···11+// This isn't a real property, but it prevents T being compatible with Shadow<T>.
22+declare const IsShadow: unique symbol;
33+44+export type Shadow<T> = T & { [IsShadow]: true };
55+66+export const castAsShadow = <T>(value: T): Shadow<T> => {
77+ return value as any as Shadow<T>;
88+};
99+1010+export interface PostCacheFindOptions {
1111+ uri?: string;
1212+ rootUri?: string;
1313+ includeQuote?: boolean;
1414+}
···11+export const focusBroadcast = new BroadcastChannel('focus');
+10
src/globals/events.ts
···11+import { EventEmitter } from '@mary/events';
22+33+export const globalEvents = new EventEmitter<{
44+ // Current session has expired
55+ sessionexpired(): void;
66+ // User has published a post
77+ postpublished(): void;
88+ // User tried navigating to the same main page they're already in
99+ softreset(): void;
1010+}>();
···11+import { onCleanup } from 'solid-js';
22+33+type UnknownFunction = (...args: any[]) => any;
44+55+type InferEventType<TTarget> = TTarget extends {
66+ // we infer from 2 overloads which are super common for event targets in the DOM lib
77+ // we "prioritize" the first one as the first one is always more specific
88+ addEventListener(type: infer P, ...args: any): void;
99+ // we can ignore the second one as it's usually just a fallback that allows bare `string` here
1010+ // we use `infer P2` over `any` as we really don't care about this type value
1111+ // and we don't want to accidentally fail a type assignability check, remember that `any` isn't assignable to `never`
1212+ addEventListener(type: infer P2, ...args: any): void;
1313+}
1414+ ? P & string
1515+ : never;
1616+1717+type InferEvent<TTarget, TType extends string> = `on${TType}` extends keyof TTarget
1818+ ? Parameters<Extract<TTarget[`on${TType}`], UnknownFunction>>[0]
1919+ : Event;
2020+2121+// For listener objects, the handleEvent function has the object as the `this` binding
2222+type ListenerObject<TEvent extends Event> = {
2323+ handleEvent(this: ListenerObject<TEvent>, event: TEvent): void;
2424+};
2525+2626+// event listeners can be an object or a function
2727+export type Listener<TTarget extends EventTarget, TType extends string> =
2828+ | ListenerObject<InferEvent<TTarget, TType>>
2929+ | { (this: TTarget, ev: InferEvent<TTarget, TType>): void };
3030+3131+export const createEventListener = <
3232+ TTarget extends EventTarget,
3333+ TType extends InferEventType<TTarget> | (string & {}),
3434+>(
3535+ target: TTarget,
3636+ type: TType,
3737+ listener: Listener<TTarget, TType>,
3838+ options?: boolean | AddEventListenerOptions,
3939+) => {
4040+ onCleanup(target.removeEventListener.bind(target, type, listener, options));
4141+ target.addEventListener(type, listener, options);
4242+};