atom.io 0.46.11 → 0.46.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/eslint-plugin/index.js +1 -1
- package/dist/eslint-plugin/index.js.map +1 -1
- package/dist/react-devtools/index.js +24 -5
- package/dist/react-devtools/index.js.map +1 -1
- package/dist/realtime/index.js +1 -1
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime-client/index.js +21 -12
- package/dist/realtime-client/index.js.map +1 -1
- package/package.json +10 -10
- package/src/eslint-plugin/rules/exact-catch-types.ts +1 -1
- package/src/react-devtools/StateIndex.tsx +8 -1
- package/src/react-devtools/json-editor/editors-by-type/non-json.tsx +17 -10
- package/src/react-devtools/json-editor/json-editor-internal.tsx +8 -1
- package/src/realtime/shared-room-store.ts +1 -1
- package/src/realtime-client/create-subscriber.ts +22 -14
- package/src/realtime-client/pull-selector-roots.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["mutexAtoms: AtomFamilyToken<boolean, Canonical>","roomKeysAtom: MutableAtomToken<UList<RoomKey>>","DEFAULT_USER_IN_ROOM_META: UserInRoomMeta","usersInRooms: JoinToken<`room`, RoomKey, `user`, UserKey, `1:n`>","visibleUsersInRoomsSelector: PureSelectorFamilyToken<\n\t[self: UserKey, ...RoomKey[]],\n\tUserKey\n>","visibilityFromRoomSelector: PureSelectorFamilyToken<\n\t[self: RoomKey, ...UserKey[]],\n\tRoomKey\n>","mutualUsersSelector: ReadonlyPureSelectorFamilyToken<\n\tUserKey[],\n\tUserKey\n>","ownersOfRooms: JoinToken<`user`, UserKey, `room`, RoomKey, `1:n`>"],"sources":["../../src/realtime/cast-socket.ts","../../src/realtime/employ-socket.ts","../../src/realtime/mutex-store.ts","../../src/realtime/realtime-continuity.ts","../../src/realtime/realtime-key-types.ts","../../src/realtime/shared-room-store.ts"],"sourcesContent":["import type { Loadable } from \"atom.io\"\nimport type { Json } from \"atom.io/json\"\n\nimport type { EventsMap, Socket, TypedSocket } from \"./socket-interface\"\nimport type { StandardSchemaV1 } from \"./standard-schema\"\n\nexport type SocketListeners<T extends TypedSocket> =\n\tT extends TypedSocket<infer ListenEvents> ? ListenEvents : never\n\nexport type SocketGuard<L extends EventsMap> = {\n\t[K in keyof L]: StandardSchemaV1<Json.Array, Parameters<L[K]>>\n}\n\nexport type Loaded<L extends Loadable<any>> =\n\tL extends Loadable<infer T> ? T : never\n\nfunction onLoad<L extends Loadable<any>>(\n\tloadable: L,\n\tfn: (loaded: Loaded<L>) => any,\n): void {\n\tif (loadable instanceof Promise) {\n\t\tvoid loadable.then(fn)\n\t} else {\n\t\tfn(loadable as Loaded<L>)\n\t}\n}\n\nexport function castSocket<T extends TypedSocket>(\n\tsocket: Socket,\n\tguard: SocketGuard<SocketListeners<T>> | `TRUST`,\n\tlogError?: (error: unknown) => void,\n): T {\n\tif (guard === `TRUST`) {\n\t\treturn socket as T\n\t}\n\tconst guardedSocket: Socket = {\n\t\tid: socket.id,\n\t\ton: (event, listener) => {\n\t\t\tconst schema = guard[event] as StandardSchemaV1<Json.Array, Json.Array>\n\t\t\tsocket.on(event, (...args) => {\n\t\t\t\tconst loadableResult = schema[`~standard`].validate(args)\n\t\t\t\tonLoad(loadableResult, (result) => {\n\t\t\t\t\tif (result.issues) {\n\t\t\t\t\t\tlogError?.(result.issues)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlistener(...result.value)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t},\n\t\tonAny: (listener) => {\n\t\t\tsocket.onAny((event, ...args) => {\n\t\t\t\tconst schema = guard[event] as StandardSchemaV1<unknown, Json.Array>\n\t\t\t\tconst loadableResult = schema[`~standard`].validate(args)\n\t\t\t\tonLoad(loadableResult, (result) => {\n\t\t\t\t\tif (result.issues) {\n\t\t\t\t\t\tlogError?.(result.issues)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlistener(event, ...result.value)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t},\n\t\tonAnyOutgoing: socket.onAnyOutgoing.bind(socket),\n\t\toff: socket.off.bind(socket),\n\t\toffAny: socket.offAny.bind(socket),\n\t\temit: socket.emit.bind(socket),\n\t}\n\treturn guardedSocket as T\n}\n","import type { EventsMap, Socket, TypedSocket } from \"atom.io/realtime\"\nimport type { Events } from \"atom.io/realtime-server\"\n\nexport function employSocket<I extends EventsMap, K extends string & keyof I>(\n\tsocket: TypedSocket<I, any>,\n\tevent: K,\n\thandleEvent: (...data: Parameters<I[K]>) => void,\n): () => void\nexport function employSocket<I extends Events, K extends string & keyof I>(\n\tsocket: Socket,\n\tevent: K,\n\thandleEvent: (...data: I[K]) => void,\n): () => void\nexport function employSocket<I extends Events, K extends string & keyof I>(\n\tsocket: Socket | TypedSocket<any, any>,\n\tevent: K,\n\thandleEvent: (...data: I[K]) => void,\n): () => void {\n\tsocket.on(event, handleEvent)\n\tconst retireSocket = () => {\n\t\tsocket.off(event, handleEvent)\n\t}\n\treturn retireSocket\n}\n","import type { AtomFamilyToken } from \"atom.io\"\nimport { atomFamily } from \"atom.io\"\nimport type { Canonical } from \"atom.io/json\"\n\nexport const mutexAtoms: AtomFamilyToken<boolean, Canonical> = atomFamily({\n\tkey: `mutex`,\n\tdefault: false,\n})\n","import type {\n\tAtomFamilyToken,\n\tAtomToken,\n\tReadableFamilyToken,\n\tReadableToken,\n\tTokenType,\n\tTransactionToken,\n} from \"atom.io\"\nimport {\n\tassignTransactionToContinuity,\n\tIMPLICIT,\n\tsetEpochNumberOfContinuity,\n} from \"atom.io/internal\"\nimport type { Canonical, Json, JsonIO } from \"atom.io/json\"\n\nimport type { UserKey } from \"./realtime-key-types\"\n\n/* eslint-disable no-console */\n\nexport class InvariantMap<K, V> extends Map<K, V> implements ReadonlyMap<K, V> {\n\tpublic set(key: K, value: V): this {\n\t\tif (this.has(key)) {\n\t\t\tconsole.warn(`Tried to set a key that already exists in an InvariantMap`, {\n\t\t\t\tkey,\n\t\t\t\tvalue,\n\t\t\t})\n\t\t\treturn this\n\t\t}\n\t\treturn super.set(key, value)\n\t}\n}\n\nexport type PerspectiveToken<F extends AtomFamilyToken<any>> = {\n\ttype: `realtime_perspective`\n\tresourceAtoms: F\n\tviewAtoms: ReadableFamilyToken<ReadableToken<TokenType<F>>[], UserKey>\n}\n\nexport type ContinuityToken = {\n\treadonly type: `continuity`\n\treadonly key: string\n\treadonly globals: AtomToken<any>[]\n\treadonly actions: (Json.Serializable & TransactionToken<JsonIO>)[]\n\treadonly perspectives: PerspectiveToken<AtomFamilyToken<any, Canonical>>[]\n}\n\nexport class SyncGroup {\n\tpublic type = `continuity` as const\n\n\tprotected globals: AtomToken<any>[] = []\n\tprotected actions: TransactionToken<any>[] = []\n\tprotected perspectives: PerspectiveToken<any>[] = []\n\tprotected readonly key: string\n\n\tprotected constructor(key: string) {\n\t\tthis.key = key\n\t}\n\n\tpublic static existing: InvariantMap<string, ContinuityToken> =\n\t\tnew InvariantMap()\n\tpublic static create(\n\t\tkey: string,\n\t\tbuilder: (group: SyncGroup) => SyncGroup,\n\t): ContinuityToken {\n\t\tconst group = new SyncGroup(key)\n\t\tconst { type, globals, actions, perspectives } = builder(group)\n\t\tconst token = { type, key, globals, actions, perspectives }\n\t\tSyncGroup.existing.set(key, token)\n\t\treturn token\n\t}\n\n\tpublic add(...atoms: AtomToken<any>[]): SyncGroup\n\tpublic add(...args: TransactionToken<any>[]): SyncGroup\n\tpublic add<\n\t\tF extends AtomFamilyToken<any>,\n\t\tT extends F extends AtomFamilyToken<infer U> ? U : never,\n\t>(\n\t\tfamily: AtomFamilyToken<T, any>,\n\t\tindex: ReadableFamilyToken<Iterable<AtomToken<T>>, string>,\n\t): SyncGroup\n\tpublic add(\n\t\t...args:\n\t\t\t| readonly AtomToken<any>[]\n\t\t\t| readonly TransactionToken<any>[]\n\t\t\t| [AtomFamilyToken<any, any>, ReadableFamilyToken<Iterable<any>, string>]\n\t): this {\n\t\tconst zeroth = args[0]\n\t\tswitch (zeroth.type) {\n\t\t\tcase `atom`:\n\t\t\tcase `mutable_atom`:\n\t\t\t\tthis.globals.push(...(args as AtomToken<any>[]))\n\t\t\t\tbreak\n\t\t\tcase `transaction`:\n\t\t\t\tthis.actions.push(...(args as TransactionToken<any>[]))\n\t\t\t\tbreak\n\t\t\tcase `atom_family`:\n\t\t\tcase `mutable_atom_family`:\n\t\t\t\t{\n\t\t\t\t\tconst [family, index] = args as [\n\t\t\t\t\t\tAtomFamilyToken<any, any>,\n\t\t\t\t\t\tReadableFamilyToken<ReadableToken<any>[], UserKey>,\n\t\t\t\t\t]\n\t\t\t\t\tthis.perspectives.push({\n\t\t\t\t\t\ttype: `realtime_perspective`,\n\t\t\t\t\t\tresourceAtoms: family,\n\t\t\t\t\t\tviewAtoms: index,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn this\n\t}\n}\n\nexport type ContinuityOptions = {\n\tkey: string\n\tconfig: (group: SyncGroup) => SyncGroup\n}\n\nexport function continuity(options: ContinuityOptions): ContinuityToken {\n\tconst { key, config } = options\n\tconst token = SyncGroup.create(key, config)\n\tconst { actions } = token\n\tfor (const action of actions) {\n\t\tassignTransactionToContinuity(IMPLICIT.STORE, key, action.key)\n\t}\n\tsetEpochNumberOfContinuity(IMPLICIT.STORE, key, -1)\n\treturn token\n}\n\n// const counterStates = atomFamily<number, { c: string }>({\n// \tkey: `counter`,\n// \tdefault: 0,\n// })\n// const counterIndices = atomFamily<{ c: string }[], string>({\n// \tkey: `counterIndex`,\n// \tdefault: [],\n// })\n// const nameStates = atomFamily<number, { n: string }>({\n// \tkey: `name`,\n// \tdefault: 0,\n// })\n// const nameIndices = atomFamily<{ n: string }[], string>({\n// \tkey: `nameIndex`,\n// \tdefault: [],\n// })\n\n// const counterContinuity = continuity({\n// \tkey: `counter`,\n// \tconfig: (group) =>\n// \t\tgroup\n// \t\t\t.add(counterStates, counterIndices)\n// \t\t\t.add(nameStates, nameIndices)\n// \t\t\t.add(nameStates, nameIndices)\n// \t\t\t.add(nameStates, nameIndices),\n// })\n","export type SocketKey = `socket::${string}`\nexport const isSocketKey = (key: string): key is SocketKey =>\n\tkey.startsWith(`socket::`)\n\nexport type UserKey = `user::${string}`\nexport const isUserKey = (key: string): key is UserKey =>\n\tkey.startsWith(`user::`)\n\nexport type RoomKey = `room::${string}`\nexport const isRoomKey = (key: string): key is RoomKey =>\n\tkey.startsWith(`room::`)\n","import type {\n\tJoinToken,\n\tMutableAtomToken,\n\tPureSelectorFamilyToken,\n\tReadonlyPureSelectorFamilyToken,\n} from \"atom.io\"\nimport { getInternalRelations, join, mutableAtom, selectorFamily } from \"atom.io\"\nimport { UList } from \"atom.io/transceivers/u-list\"\n\nimport {\n\tisRoomKey,\n\tisUserKey,\n\ttype RoomKey,\n\ttype UserKey,\n} from \"./realtime-key-types\"\n\nexport type RoomSocketInterface<RoomNames extends string> = {\n\tcreateRoom: (roomName: RoomNames) => void\n\tjoinRoom: (roomKey: RoomKey) => void\n\tdeleteRoom: (roomKey: RoomKey) => void\n\tleaveRoom: () => void\n\t// [leaveRoom: `leaveRoom:${string}`]: () => void\n}\n\nexport const roomKeysAtom: MutableAtomToken<UList<RoomKey>> = mutableAtom({\n\tkey: `roomKeys`,\n\tclass: UList,\n})\n\nexport type UserInRoomMeta = {\n\tenteredAtEpoch: number\n}\nexport const DEFAULT_USER_IN_ROOM_META: UserInRoomMeta = {\n\tenteredAtEpoch: 0,\n}\nexport const usersInRooms: JoinToken<`room`, RoomKey, `user`, UserKey, `1:n`> =\n\tjoin({\n\t\tkey: `usersInRooms`,\n\t\tbetween: [`room`, `user`],\n\t\tcardinality: `1:n`,\n\t\tisAType: isRoomKey,\n\t\tisBType: isUserKey,\n\t})\n\nexport const visibleUsersInRoomsSelector: PureSelectorFamilyToken<\n\t[self: UserKey, ...RoomKey[]],\n\tUserKey\n> = selectorFamily({\n\tkey: `visibleUsersInRooms`,\n\tget:\n\t\t(userKey) =>\n\t\t({ get }) => {\n\t\t\tconst [, roomsOfUsersAtoms] = getInternalRelations(usersInRooms, `split`)\n\t\t\tconst rooms = get(roomsOfUsersAtoms, userKey)\n\t\t\treturn [userKey, ...rooms]\n\t\t},\n})\n\nexport const visibilityFromRoomSelector: PureSelectorFamilyToken<\n\t[self: RoomKey, ...UserKey[]],\n\tRoomKey\n> = selectorFamily({\n\tkey: `visibilityFromRoom`,\n\tget:\n\t\t(roomKey) =>\n\t\t({ get }) => {\n\t\t\tconst [usersOfRoomsAtoms] = getInternalRelations(usersInRooms, `split`)\n\t\t\tconst users = get(usersOfRoomsAtoms, roomKey)\n\t\t\treturn [roomKey, ...users]\n\t\t},\n})\n\nexport const mutualUsersSelector: ReadonlyPureSelectorFamilyToken<\n\tUserKey[],\n\tUserKey\n> = selectorFamily({\n\tkey: `mutualUsers`,\n\tget:\n\t\t(userKey) =>\n\t\t({ get }) => {\n\t\t\tconst [usersOfRoomsAtoms, roomsOfUsersAtoms] = getInternalRelations(\n\t\t\t\tusersInRooms,\n\t\t\t\t`split`,\n\t\t\t)\n\t\t\tconst rooms = get(roomsOfUsersAtoms, userKey)\n\t\t\tfor (const room of rooms) {\n\t\t\t\tconst users = get(usersOfRoomsAtoms, room)\n\t\t\t\treturn [...users]\n\t\t\t}\n\t\t\treturn []\n\t\t},\n})\n\nexport const ownersOfRooms: JoinToken<`user`, UserKey, `room`, RoomKey, `1:n`> =\n\tjoin({\n\t\tkey: `ownersOfRooms`,\n\t\tbetween: [`user`, `room`],\n\t\tcardinality: `1:n`,\n\t\tisAType: isUserKey,\n\t\tisBType: isRoomKey,\n\t})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["mutexAtoms: AtomFamilyToken<boolean, Canonical>","roomKeysAtom: MutableAtomToken<UList<RoomKey>>","DEFAULT_USER_IN_ROOM_META: UserInRoomMeta","usersInRooms: JoinToken<`room`, RoomKey, `user`, UserKey, `1:n`>","visibleUsersInRoomsSelector: PureSelectorFamilyToken<\n\t[self: UserKey, ...RoomKey[]],\n\tUserKey\n>","visibilityFromRoomSelector: PureSelectorFamilyToken<\n\t[self: RoomKey, ...UserKey[]],\n\tRoomKey\n>","mutualUsersSelector: ReadonlyPureSelectorFamilyToken<\n\tUserKey[],\n\tUserKey\n>","ownersOfRooms: JoinToken<`user`, UserKey, `room`, RoomKey, `1:n`>"],"sources":["../../src/realtime/cast-socket.ts","../../src/realtime/employ-socket.ts","../../src/realtime/mutex-store.ts","../../src/realtime/realtime-continuity.ts","../../src/realtime/realtime-key-types.ts","../../src/realtime/shared-room-store.ts"],"sourcesContent":["import type { Loadable } from \"atom.io\"\nimport type { Json } from \"atom.io/json\"\n\nimport type { EventsMap, Socket, TypedSocket } from \"./socket-interface\"\nimport type { StandardSchemaV1 } from \"./standard-schema\"\n\nexport type SocketListeners<T extends TypedSocket> =\n\tT extends TypedSocket<infer ListenEvents> ? ListenEvents : never\n\nexport type SocketGuard<L extends EventsMap> = {\n\t[K in keyof L]: StandardSchemaV1<Json.Array, Parameters<L[K]>>\n}\n\nexport type Loaded<L extends Loadable<any>> =\n\tL extends Loadable<infer T> ? T : never\n\nfunction onLoad<L extends Loadable<any>>(\n\tloadable: L,\n\tfn: (loaded: Loaded<L>) => any,\n): void {\n\tif (loadable instanceof Promise) {\n\t\tvoid loadable.then(fn)\n\t} else {\n\t\tfn(loadable as Loaded<L>)\n\t}\n}\n\nexport function castSocket<T extends TypedSocket>(\n\tsocket: Socket,\n\tguard: SocketGuard<SocketListeners<T>> | `TRUST`,\n\tlogError?: (error: unknown) => void,\n): T {\n\tif (guard === `TRUST`) {\n\t\treturn socket as T\n\t}\n\tconst guardedSocket: Socket = {\n\t\tid: socket.id,\n\t\ton: (event, listener) => {\n\t\t\tconst schema = guard[event] as StandardSchemaV1<Json.Array, Json.Array>\n\t\t\tsocket.on(event, (...args) => {\n\t\t\t\tconst loadableResult = schema[`~standard`].validate(args)\n\t\t\t\tonLoad(loadableResult, (result) => {\n\t\t\t\t\tif (result.issues) {\n\t\t\t\t\t\tlogError?.(result.issues)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlistener(...result.value)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t},\n\t\tonAny: (listener) => {\n\t\t\tsocket.onAny((event, ...args) => {\n\t\t\t\tconst schema = guard[event] as StandardSchemaV1<unknown, Json.Array>\n\t\t\t\tconst loadableResult = schema[`~standard`].validate(args)\n\t\t\t\tonLoad(loadableResult, (result) => {\n\t\t\t\t\tif (result.issues) {\n\t\t\t\t\t\tlogError?.(result.issues)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlistener(event, ...result.value)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t},\n\t\tonAnyOutgoing: socket.onAnyOutgoing.bind(socket),\n\t\toff: socket.off.bind(socket),\n\t\toffAny: socket.offAny.bind(socket),\n\t\temit: socket.emit.bind(socket),\n\t}\n\treturn guardedSocket as T\n}\n","import type { EventsMap, Socket, TypedSocket } from \"atom.io/realtime\"\nimport type { Events } from \"atom.io/realtime-server\"\n\nexport function employSocket<I extends EventsMap, K extends string & keyof I>(\n\tsocket: TypedSocket<I, any>,\n\tevent: K,\n\thandleEvent: (...data: Parameters<I[K]>) => void,\n): () => void\nexport function employSocket<I extends Events, K extends string & keyof I>(\n\tsocket: Socket,\n\tevent: K,\n\thandleEvent: (...data: I[K]) => void,\n): () => void\nexport function employSocket<I extends Events, K extends string & keyof I>(\n\tsocket: Socket | TypedSocket<any, any>,\n\tevent: K,\n\thandleEvent: (...data: I[K]) => void,\n): () => void {\n\tsocket.on(event, handleEvent)\n\tconst retireSocket = () => {\n\t\tsocket.off(event, handleEvent)\n\t}\n\treturn retireSocket\n}\n","import type { AtomFamilyToken } from \"atom.io\"\nimport { atomFamily } from \"atom.io\"\nimport type { Canonical } from \"atom.io/json\"\n\nexport const mutexAtoms: AtomFamilyToken<boolean, Canonical> = atomFamily({\n\tkey: `mutex`,\n\tdefault: false,\n})\n","import type {\n\tAtomFamilyToken,\n\tAtomToken,\n\tReadableFamilyToken,\n\tReadableToken,\n\tTokenType,\n\tTransactionToken,\n} from \"atom.io\"\nimport {\n\tassignTransactionToContinuity,\n\tIMPLICIT,\n\tsetEpochNumberOfContinuity,\n} from \"atom.io/internal\"\nimport type { Canonical, Json, JsonIO } from \"atom.io/json\"\n\nimport type { UserKey } from \"./realtime-key-types\"\n\n/* eslint-disable no-console */\n\nexport class InvariantMap<K, V> extends Map<K, V> implements ReadonlyMap<K, V> {\n\tpublic set(key: K, value: V): this {\n\t\tif (this.has(key)) {\n\t\t\tconsole.warn(`Tried to set a key that already exists in an InvariantMap`, {\n\t\t\t\tkey,\n\t\t\t\tvalue,\n\t\t\t})\n\t\t\treturn this\n\t\t}\n\t\treturn super.set(key, value)\n\t}\n}\n\nexport type PerspectiveToken<F extends AtomFamilyToken<any>> = {\n\ttype: `realtime_perspective`\n\tresourceAtoms: F\n\tviewAtoms: ReadableFamilyToken<ReadableToken<TokenType<F>>[], UserKey>\n}\n\nexport type ContinuityToken = {\n\treadonly type: `continuity`\n\treadonly key: string\n\treadonly globals: AtomToken<any>[]\n\treadonly actions: (Json.Serializable & TransactionToken<JsonIO>)[]\n\treadonly perspectives: PerspectiveToken<AtomFamilyToken<any, Canonical>>[]\n}\n\nexport class SyncGroup {\n\tpublic type = `continuity` as const\n\n\tprotected globals: AtomToken<any>[] = []\n\tprotected actions: TransactionToken<any>[] = []\n\tprotected perspectives: PerspectiveToken<any>[] = []\n\tprotected readonly key: string\n\n\tprotected constructor(key: string) {\n\t\tthis.key = key\n\t}\n\n\tpublic static existing: InvariantMap<string, ContinuityToken> =\n\t\tnew InvariantMap()\n\tpublic static create(\n\t\tkey: string,\n\t\tbuilder: (group: SyncGroup) => SyncGroup,\n\t): ContinuityToken {\n\t\tconst group = new SyncGroup(key)\n\t\tconst { type, globals, actions, perspectives } = builder(group)\n\t\tconst token = { type, key, globals, actions, perspectives }\n\t\tSyncGroup.existing.set(key, token)\n\t\treturn token\n\t}\n\n\tpublic add(...atoms: AtomToken<any>[]): SyncGroup\n\tpublic add(...args: TransactionToken<any>[]): SyncGroup\n\tpublic add<\n\t\tF extends AtomFamilyToken<any>,\n\t\tT extends F extends AtomFamilyToken<infer U> ? U : never,\n\t>(\n\t\tfamily: AtomFamilyToken<T, any>,\n\t\tindex: ReadableFamilyToken<Iterable<AtomToken<T>>, string>,\n\t): SyncGroup\n\tpublic add(\n\t\t...args:\n\t\t\t| readonly AtomToken<any>[]\n\t\t\t| readonly TransactionToken<any>[]\n\t\t\t| [AtomFamilyToken<any, any>, ReadableFamilyToken<Iterable<any>, string>]\n\t): this {\n\t\tconst zeroth = args[0]\n\t\tswitch (zeroth.type) {\n\t\t\tcase `atom`:\n\t\t\tcase `mutable_atom`:\n\t\t\t\tthis.globals.push(...(args as AtomToken<any>[]))\n\t\t\t\tbreak\n\t\t\tcase `transaction`:\n\t\t\t\tthis.actions.push(...(args as TransactionToken<any>[]))\n\t\t\t\tbreak\n\t\t\tcase `atom_family`:\n\t\t\tcase `mutable_atom_family`:\n\t\t\t\t{\n\t\t\t\t\tconst [family, index] = args as [\n\t\t\t\t\t\tAtomFamilyToken<any, any>,\n\t\t\t\t\t\tReadableFamilyToken<ReadableToken<any>[], UserKey>,\n\t\t\t\t\t]\n\t\t\t\t\tthis.perspectives.push({\n\t\t\t\t\t\ttype: `realtime_perspective`,\n\t\t\t\t\t\tresourceAtoms: family,\n\t\t\t\t\t\tviewAtoms: index,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn this\n\t}\n}\n\nexport type ContinuityOptions = {\n\tkey: string\n\tconfig: (group: SyncGroup) => SyncGroup\n}\n\nexport function continuity(options: ContinuityOptions): ContinuityToken {\n\tconst { key, config } = options\n\tconst token = SyncGroup.create(key, config)\n\tconst { actions } = token\n\tfor (const action of actions) {\n\t\tassignTransactionToContinuity(IMPLICIT.STORE, key, action.key)\n\t}\n\tsetEpochNumberOfContinuity(IMPLICIT.STORE, key, -1)\n\treturn token\n}\n\n// const counterStates = atomFamily<number, { c: string }>({\n// \tkey: `counter`,\n// \tdefault: 0,\n// })\n// const counterIndices = atomFamily<{ c: string }[], string>({\n// \tkey: `counterIndex`,\n// \tdefault: [],\n// })\n// const nameStates = atomFamily<number, { n: string }>({\n// \tkey: `name`,\n// \tdefault: 0,\n// })\n// const nameIndices = atomFamily<{ n: string }[], string>({\n// \tkey: `nameIndex`,\n// \tdefault: [],\n// })\n\n// const counterContinuity = continuity({\n// \tkey: `counter`,\n// \tconfig: (group) =>\n// \t\tgroup\n// \t\t\t.add(counterStates, counterIndices)\n// \t\t\t.add(nameStates, nameIndices)\n// \t\t\t.add(nameStates, nameIndices)\n// \t\t\t.add(nameStates, nameIndices),\n// })\n","export type SocketKey = `socket::${string}`\nexport const isSocketKey = (key: string): key is SocketKey =>\n\tkey.startsWith(`socket::`)\n\nexport type UserKey = `user::${string}`\nexport const isUserKey = (key: string): key is UserKey =>\n\tkey.startsWith(`user::`)\n\nexport type RoomKey = `room::${string}`\nexport const isRoomKey = (key: string): key is RoomKey =>\n\tkey.startsWith(`room::`)\n","import type {\n\tJoinToken,\n\tMutableAtomToken,\n\tPureSelectorFamilyToken,\n\tReadonlyPureSelectorFamilyToken,\n} from \"atom.io\"\nimport { getInternalRelations, join, mutableAtom, selectorFamily } from \"atom.io\"\nimport { UList } from \"atom.io/transceivers/u-list\"\n\nimport {\n\tisRoomKey,\n\tisUserKey,\n\ttype RoomKey,\n\ttype UserKey,\n} from \"./realtime-key-types\"\n\nexport type RoomSocketInterface<RoomNames extends string> = {\n\tcreateRoom: (roomName: RoomNames) => void\n\tjoinRoom: (roomKey: RoomKey) => void\n\tdeleteRoom: (roomKey: RoomKey) => void\n\tleaveRoom: () => void\n\t// [leaveRoom: `leaveRoom:${string}`]: () => void\n}\n\nexport const roomKeysAtom: MutableAtomToken<UList<RoomKey>> = mutableAtom({\n\tkey: `roomKeys`,\n\tclass: UList,\n})\n\nexport type UserInRoomMeta = {\n\tenteredAtEpoch: number\n}\nexport const DEFAULT_USER_IN_ROOM_META: UserInRoomMeta = {\n\tenteredAtEpoch: 0,\n}\nexport const usersInRooms: JoinToken<`room`, RoomKey, `user`, UserKey, `1:n`> =\n\tjoin({\n\t\tkey: `usersInRooms`,\n\t\tbetween: [`room`, `user`],\n\t\tcardinality: `1:n`,\n\t\tisAType: isRoomKey,\n\t\tisBType: isUserKey,\n\t})\n\nexport const visibleUsersInRoomsSelector: PureSelectorFamilyToken<\n\t[self: UserKey, ...RoomKey[]],\n\tUserKey\n> = selectorFamily({\n\tkey: `visibleUsersInRooms`,\n\tget:\n\t\t(userKey) =>\n\t\t({ get }) => {\n\t\t\tconst [, roomsOfUsersAtoms] = getInternalRelations(usersInRooms, `split`)\n\t\t\tconst rooms = get(roomsOfUsersAtoms, userKey)\n\t\t\treturn [userKey, ...rooms]\n\t\t},\n})\n\nexport const visibilityFromRoomSelector: PureSelectorFamilyToken<\n\t[self: RoomKey, ...UserKey[]],\n\tRoomKey\n> = selectorFamily({\n\tkey: `visibilityFromRoom`,\n\tget:\n\t\t(roomKey) =>\n\t\t({ get }) => {\n\t\t\tconst [usersOfRoomsAtoms] = getInternalRelations(usersInRooms, `split`)\n\t\t\tconst users = get(usersOfRoomsAtoms, roomKey)\n\t\t\treturn [roomKey, ...users]\n\t\t},\n})\n\nexport const mutualUsersSelector: ReadonlyPureSelectorFamilyToken<\n\tUserKey[],\n\tUserKey\n> = selectorFamily({\n\tkey: `mutualUsers`,\n\tget:\n\t\t(userKey) =>\n\t\t({ get }) => {\n\t\t\tconst [usersOfRoomsAtoms, roomsOfUsersAtoms] = getInternalRelations(\n\t\t\t\tusersInRooms,\n\t\t\t\t`split`,\n\t\t\t)\n\t\t\tconst rooms = get(roomsOfUsersAtoms, userKey)\n\t\t\tfor (const room of rooms) {\n\t\t\t\tconst users = get(usersOfRoomsAtoms, room)\n\t\t\t\treturn [...users]\n\t\t\t}\n\t\t\treturn [userKey]\n\t\t},\n})\n\nexport const ownersOfRooms: JoinToken<`user`, UserKey, `room`, RoomKey, `1:n`> =\n\tjoin({\n\t\tkey: `ownersOfRooms`,\n\t\tbetween: [`user`, `room`],\n\t\tcardinality: `1:n`,\n\t\tisAType: isUserKey,\n\t\tisBType: isRoomKey,\n\t})\n"],"mappings":"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"}
|
|
@@ -174,23 +174,31 @@ function createSubscriber(socket, key, open) {
|
|
|
174
174
|
socketIds.set(socket, socket.id);
|
|
175
175
|
subscriptions.delete(socket);
|
|
176
176
|
}
|
|
177
|
-
const
|
|
178
|
-
let
|
|
179
|
-
if (
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
const subMap = getSubMap(socket);
|
|
178
|
+
let sub = subMap.get(key);
|
|
179
|
+
if (sub) {
|
|
180
|
+
sub.timer.use(new Promise(() => {}));
|
|
181
|
+
sub.refcount++;
|
|
182
|
+
} else {
|
|
183
|
+
sub = {
|
|
184
|
+
refcount: 1,
|
|
185
|
+
timer: new Future(() => {})
|
|
186
|
+
};
|
|
187
|
+
subMap.set(key, sub);
|
|
183
188
|
const close = open(key);
|
|
184
|
-
timer.then(() => {
|
|
189
|
+
sub.timer.then(() => {
|
|
185
190
|
close();
|
|
186
|
-
|
|
191
|
+
subMap.delete(key);
|
|
187
192
|
});
|
|
188
193
|
}
|
|
189
194
|
return () => {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
195
|
+
sub.refcount--;
|
|
196
|
+
if (sub.refcount === 0) {
|
|
197
|
+
const timeout = new Promise((resolve) => {
|
|
198
|
+
setTimeout(resolve, 50);
|
|
199
|
+
});
|
|
200
|
+
sub.timer.use(timeout);
|
|
201
|
+
}
|
|
194
202
|
};
|
|
195
203
|
}
|
|
196
204
|
|
|
@@ -309,6 +317,7 @@ function pullSelectorRoots(store, socket, selectorToken) {
|
|
|
309
317
|
start();
|
|
310
318
|
return () => {
|
|
311
319
|
for (const [, unsub] of atomSubscriptions) unsub();
|
|
320
|
+
atomSubscriptions.clear();
|
|
312
321
|
unsubFromSelector();
|
|
313
322
|
};
|
|
314
323
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["mySocketKeyAtom: RegularAtomToken<SocketKey | undefined>","myUserKeyAtom: RegularAtomToken<UserKey | null>","myRoomKeySelector: ReadonlyPureSelectorToken<RoomKey | null>","optimisticUpdateQueueAtom: AtomIO.RegularAtomToken<\n\tAtomIO.TransactionOutcomeEvent<any>[]\n>","confirmedUpdateQueueAtom: AtomIO.RegularAtomToken<\n\tAtomIO.TransactionOutcomeEvent<any>[]\n>","continuityEpoch: number | undefined","k: any","v: any","subscriptions: WeakMap<Socket, Map<string, Future<void>>>","socketIds: WeakMap<Socket, string | undefined>","atom","k: any","v: any"],"sources":["../../src/realtime-client/realtime-client-stores/client-main-store.ts","../../src/realtime-client/realtime-client-stores/client-sync-store.ts","../../src/realtime-client/continuity/register-and-attempt-confirmed-update.ts","../../src/realtime-client/continuity/use-conceal-state.ts","../../src/realtime-client/continuity/use-reveal-state.ts","../../src/realtime-client/create-subscriber.ts","../../src/realtime-client/pull-atom.ts","../../src/realtime-client/pull-atom-family-member.ts","../../src/realtime-client/pull-mutable-atom.ts","../../src/realtime-client/pull-mutable-atom-family-member.ts","../../src/realtime-client/pull-selector-roots.ts","../../src/realtime-client/pull-selector.ts","../../src/realtime-client/pull-selector-family-member.ts","../../src/realtime-client/push-state.ts","../../src/realtime-client/sync-continuity.ts"],"sourcesContent":["import type { ReadonlyPureSelectorToken, RegularAtomToken } from \"atom.io\"\nimport { atom, getInternalRelations, selector } from \"atom.io\"\nimport type { RoomKey, SocketKey, UserKey } from \"atom.io/realtime\"\nimport { usersInRooms } from \"atom.io/realtime\"\n\nexport const mySocketKeyAtom: RegularAtomToken<SocketKey | undefined> = atom({\n\tkey: `mySocketKey`,\n\tdefault: undefined,\n})\n\nexport const myUserKeyAtom: RegularAtomToken<UserKey | null> = atom({\n\tkey: `myUserKey`,\n\tdefault: null,\n\teffects: [\n\t\t(userKey) => {\n\t\t\tif (typeof window !== `undefined`) {\n\t\t\t\tvoid import(`atom.io/web`).then(({ storageSync }) => {\n\t\t\t\t\tstorageSync(globalThis.localStorage, JSON, `myUserKey`)(userKey)\n\t\t\t\t})\n\t\t\t}\n\t\t},\n\t],\n})\n\nexport const myRoomKeySelector: ReadonlyPureSelectorToken<RoomKey | null> =\n\tselector({\n\t\tkey: `myRoomKey`,\n\t\tget: ({ get }) => {\n\t\t\tif (\n\t\t\t\t`process` in globalThis &&\n\t\t\t\t`env` in process &&\n\t\t\t\t`REALTIME_ROOM_KEY` in process.env\n\t\t\t) {\n\t\t\t\t// if a room running server-side wants its own key, this is where it lives\n\t\t\t\treturn process.env[`REALTIME_ROOM_KEY`] as RoomKey\n\t\t\t}\n\t\t\tconst myUserKey = get(myUserKeyAtom)\n\t\t\tif (!myUserKey) return null\n\t\t\tconst [, usersInRoomsAtoms] = getInternalRelations(usersInRooms, `split`)\n\t\t\tconst roomKeys = get(usersInRoomsAtoms, myUserKey)\n\t\t\tfor (const roomKey of roomKeys) return roomKey\n\t\t\treturn null\n\t\t},\n\t})\n","import * as AtomIO from \"atom.io\"\n\nexport const optimisticUpdateQueueAtom: AtomIO.RegularAtomToken<\n\tAtomIO.TransactionOutcomeEvent<any>[]\n> = AtomIO.atom<AtomIO.TransactionOutcomeEvent<any>[]>({\n\tkey: `optimisticUpdateQueue`,\n\tdefault: () => [],\n})\n\nexport const confirmedUpdateQueueAtom: AtomIO.RegularAtomToken<\n\tAtomIO.TransactionOutcomeEvent<any>[]\n> = AtomIO.atom<AtomIO.TransactionOutcomeEvent<any>[]>({\n\tkey: `confirmedUpdateQueue`,\n\tdefault: () => [],\n})\n","import type * as AtomIO from \"atom.io\"\nimport type { Fn, RootStore } from \"atom.io/internal\"\nimport {\n\tactUponStore,\n\tgetEpochNumberOfContinuity,\n\tingestTransactionOutcomeEvent,\n\tsetEpochNumberOfContinuity,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { Socket } from \"atom.io/realtime\"\n\nimport {\n\tconfirmedUpdateQueueAtom,\n\toptimisticUpdateQueueAtom,\n} from \"../realtime-client-stores\"\n\nexport const useRegisterAndAttemptConfirmedUpdate =\n\t(\n\t\tstore: RootStore,\n\t\tcontinuityKey: string,\n\t\tsocket: Socket,\n\t\toptimisticUpdates: readonly AtomIO.TransactionOutcomeEvent<\n\t\t\tAtomIO.TransactionToken<Fn>\n\t\t>[],\n\t\tconfirmedUpdates: readonly AtomIO.TransactionOutcomeEvent<\n\t\t\tAtomIO.TransactionToken<Fn>\n\t\t>[],\n\t) =>\n\t(\n\t\tconfirmed: AtomIO.TransactionOutcomeEvent<AtomIO.TransactionToken<Fn>> &\n\t\t\tJson.Serializable,\n\t): void => {\n\t\tfunction reconcileEpoch(\n\t\t\toptimisticUpdate: AtomIO.TransactionOutcomeEvent<\n\t\t\t\tAtomIO.TransactionToken<Fn>\n\t\t\t>,\n\t\t\tconfirmedUpdate: AtomIO.TransactionOutcomeEvent<\n\t\t\t\tAtomIO.TransactionToken<Fn>\n\t\t\t>,\n\t\t): void {\n\t\t\tstore.logger.info(\n\t\t\t\t`🧑⚖️`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`reconciling updates`,\n\t\t\t)\n\t\t\tsetIntoStore(store, optimisticUpdateQueueAtom, (queue) => {\n\t\t\t\tqueue.shift()\n\t\t\t\treturn queue\n\t\t\t})\n\t\t\tif (optimisticUpdate.id === confirmedUpdate.id) {\n\t\t\t\tconst clientResult = JSON.stringify(optimisticUpdate.subEvents)\n\t\t\t\tconst serverResult = JSON.stringify(confirmedUpdate.subEvents)\n\t\t\t\tif (clientResult === serverResult) {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`✅`,\n\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t`results for ${optimisticUpdate.id} match between client and server`,\n\t\t\t\t\t)\n\t\t\t\t\tsocket.emit(`ack:${continuityKey}`, confirmedUpdate.epoch)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// id mismatch\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`❌`,\n\t\t\t\t\t`continuity`,\n\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t`thought update #${confirmedUpdate.epoch} was ${optimisticUpdate.token.key}:${optimisticUpdate.id}, but it was actually ${confirmedUpdate.token.key}:${confirmedUpdate.id}`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tstore.logger.info(\n\t\t\t\t`🧑⚖️`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`updates do not match`,\n\t\t\t\toptimisticUpdate,\n\t\t\t\tconfirmedUpdate,\n\t\t\t)\n\t\t\tconst reversedOptimisticUpdates = optimisticUpdates.toReversed()\n\t\t\tfor (const subsequentOptimistic of reversedOptimisticUpdates) {\n\t\t\t\tingestTransactionOutcomeEvent(store, subsequentOptimistic, `oldValue`)\n\t\t\t}\n\t\t\tstore.logger.info(\n\t\t\t\t`⏪`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`undid optimistic updates:`,\n\t\t\t\treversedOptimisticUpdates,\n\t\t\t)\n\t\t\tingestTransactionOutcomeEvent(store, optimisticUpdate, `oldValue`)\n\t\t\tstore.logger.info(\n\t\t\t\t`⏪`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`undid zeroth optimistic update`,\n\t\t\t\toptimisticUpdate,\n\t\t\t)\n\t\t\tingestTransactionOutcomeEvent(store, confirmedUpdate, `newValue`)\n\t\t\tstore.logger.info(\n\t\t\t\t`⏩`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`applied confirmed update`,\n\t\t\t\tconfirmedUpdate,\n\t\t\t)\n\t\t\tsocket.emit(`ack:${continuityKey}`, confirmedUpdate.epoch)\n\n\t\t\tfor (const subsequentOptimistic of optimisticUpdates) {\n\t\t\t\tconst token = {\n\t\t\t\t\ttype: `transaction`,\n\t\t\t\t\tkey: subsequentOptimistic.token.key,\n\t\t\t\t} as const\n\t\t\t\tconst { id, params } = subsequentOptimistic\n\t\t\t\tactUponStore(store, token, id)(...params)\n\t\t\t}\n\t\t\tstore.logger.info(\n\t\t\t\t`⏩`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`reapplied subsequent optimistic updates:`,\n\t\t\t\toptimisticUpdates,\n\t\t\t)\n\t\t}\n\n\t\tstore.logger.info(\n\t\t\t`🧑⚖️`,\n\t\t\t`continuity`,\n\t\t\tcontinuityKey,\n\t\t\t`integrating confirmed update`,\n\t\t\t{ confirmedUpdate: confirmed, confirmedUpdates, optimisticUpdates },\n\t\t)\n\t\tconst zerothOptimisticUpdate = optimisticUpdates[0]\n\t\tif (zerothOptimisticUpdate) {\n\t\t\tstore.logger.info(\n\t\t\t\t`🧑⚖️`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`has optimistic updates to reconcile`,\n\t\t\t)\n\t\t\tif (confirmed.epoch === zerothOptimisticUpdate.epoch) {\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`🧑⚖️`,\n\t\t\t\t\t`continuity`,\n\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t`epoch of confirmed update #${confirmed.epoch} matches zeroth optimistic update`,\n\t\t\t\t)\n\t\t\t\treconcileEpoch(zerothOptimisticUpdate, confirmed)\n\t\t\t\tfor (const nextConfirmed of confirmedUpdates) {\n\t\t\t\t\tconst nextOptimistic = optimisticUpdates[0]\n\t\t\t\t\tif (nextConfirmed.epoch === nextOptimistic?.epoch) {\n\t\t\t\t\t\treconcileEpoch(nextOptimistic, nextConfirmed)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// epoch mismatch\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`🧑⚖️`,\n\t\t\t\t\t`continuity`,\n\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t`epoch of confirmed update #${confirmed.epoch} does not match zeroth optimistic update #${zerothOptimisticUpdate.epoch}`,\n\t\t\t\t)\n\t\t\t\tconst confirmedUpdateIsAlreadyEnqueued = confirmedUpdates.some(\n\t\t\t\t\t(update) => update.epoch === confirmed.epoch,\n\t\t\t\t)\n\t\t\t\tif (!confirmedUpdateIsAlreadyEnqueued) {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`👈`,\n\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t`pushing confirmed update to queue`,\n\t\t\t\t\t\tconfirmed,\n\t\t\t\t\t)\n\t\t\t\t\tsetIntoStore(store, confirmedUpdateQueueAtom, (queue) => {\n\t\t\t\t\t\tqueue.push(confirmed)\n\t\t\t\t\t\tqueue.sort((a, b) => a.epoch - b.epoch)\n\t\t\t\t\t\treturn queue\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tstore.logger.info(\n\t\t\t\t`🧑⚖️`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`has no optimistic updates to deal with`,\n\t\t\t)\n\t\t\tlet continuityEpoch: number | undefined\n\t\t\tcontinuityEpoch = getEpochNumberOfContinuity(store, continuityKey)\n\n\t\t\tif (continuityEpoch === confirmed.epoch - 1) {\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`✅`,\n\t\t\t\t\t`continuity`,\n\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t`integrating update #${confirmed.epoch} (${confirmed.token.key} ${confirmed.id})`,\n\t\t\t\t)\n\t\t\t\tingestTransactionOutcomeEvent(store, confirmed, `newValue`)\n\t\t\t\tsocket.emit(`ack:${continuityKey}`, confirmed.epoch)\n\t\t\t\tsetEpochNumberOfContinuity(store, continuityKey, confirmed.epoch)\n\t\t\t} else if (continuityEpoch !== undefined) {\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`🧑⚖️`,\n\t\t\t\t\t`continuity`,\n\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t`received update #${confirmed.epoch} but still waiting for update #${\n\t\t\t\t\t\tcontinuityEpoch + 1\n\t\t\t\t\t}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tclientEpoch: continuityEpoch,\n\t\t\t\t\t\tserverEpoch: confirmed.epoch,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tconst confirmedUpdateIsAlreadyEnqueued = confirmedUpdates.some(\n\t\t\t\t\t(update) => update.epoch === confirmed.epoch,\n\t\t\t\t)\n\t\t\t\tif (confirmedUpdateIsAlreadyEnqueued) {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`👍`,\n\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t`confirmed update #${confirmed.epoch} is already enqueued`,\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`👈`,\n\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t`pushing confirmed update #${confirmed.epoch} to queue`,\n\t\t\t\t\t)\n\t\t\t\t\tsetIntoStore(store, confirmedUpdateQueueAtom, (queue) => {\n\t\t\t\t\t\tqueue.push(confirmed)\n\t\t\t\t\t\tqueue.sort((a, b) => a.epoch - b.epoch)\n\t\t\t\t\t\treturn queue\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n","import type { AtomToken } from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { disposeAtom } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\n\nexport function useConcealState(store: Store) {\n\treturn (concealed: AtomToken<Json.Serializable>[]): void => {\n\t\tfor (const token of concealed) {\n\t\t\tdisposeAtom(store, token)\n\t\t}\n\t}\n}\n","import { setIntoStore, type Store } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\n\nexport function useRevealState(store: Store) {\n\treturn (revealed: Json.Array): void => {\n\t\tlet i = 0\n\t\tlet k: any\n\t\tlet v: any\n\t\tfor (const x of revealed) {\n\t\t\tif (i % 2 === 0) {\n\t\t\t\tk = x\n\t\t\t} else {\n\t\t\t\tv = x\n\t\t\t\tsetIntoStore(store, k, v)\n\t\t\t}\n\t\t\ti++\n\t\t}\n\t}\n}\n","import { Future } from \"atom.io/internal\"\nimport type { Socket } from \"atom.io/realtime\"\n\nconst subscriptions: WeakMap<Socket, Map<string, Future<void>>> = new WeakMap()\nconst socketIds: WeakMap<Socket, string | undefined> = new WeakMap()\n\nfunction getSubMap(socket: Socket): Map<string, Future<void>> {\n\tlet subMap = subscriptions.get(socket)\n\tif (subMap === undefined) {\n\t\tsubMap = new Map()\n\t\tsubscriptions.set(socket, subMap)\n\t}\n\treturn subMap\n}\n\nexport function createSubscriber<K extends string>(\n\tsocket: Socket,\n\tkey: K,\n\topen: (key: K) => () => void,\n): () => void {\n\tconst knownSocketId = socketIds.get(socket)\n\tif (knownSocketId !== socket.id) {\n\t\tsocketIds.set(socket, socket.id)\n\t\tsubscriptions.delete(socket)\n\t}\n\tconst unsubTimers = getSubMap(socket)\n\tlet timer = unsubTimers.get(key)\n\tif (timer) {\n\t\ttimer.use(new Promise<void>(() => {}))\n\t} else {\n\t\ttimer = new Future<void>(() => {})\n\t\tunsubTimers.set(key, timer)\n\t\tconst close = open(key)\n\t\tvoid timer.then(() => {\n\t\t\tclose()\n\t\t\tunsubTimers.delete(key)\n\t\t})\n\t}\n\treturn () => {\n\t\tconst timeout = new Promise<void>((resolve) => {\n\t\t\tsetTimeout(resolve, 25)\n\t\t})\n\t\ttimer.use(timeout)\n\t}\n}\n","import type * as AtomIO from \"atom.io\"\nimport { setIntoStore, type Store } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { employSocket, type Socket } from \"atom.io/realtime\"\n\nimport { createSubscriber } from \"./create-subscriber\"\n\nexport function pullAtom<J extends Json.Serializable>(\n\tstore: Store,\n\tsocket: Socket,\n\ttoken: AtomIO.RegularAtomToken<J, any, any>,\n): () => void {\n\treturn createSubscriber(socket, token.key, (key) => {\n\t\tconst stopWatching = employSocket(socket, `serve:${key}`, (data: J) => {\n\t\t\tsetIntoStore(store, token, data)\n\t\t})\n\t\tsocket.emit(`sub:${token.key}`)\n\t\treturn () => {\n\t\t\tsocket.emit(`unsub:${key}`)\n\t\t\tstopWatching()\n\t\t}\n\t})\n}\n","import type * as AtomIO from \"atom.io\"\nimport { findInStore, setIntoStore, type Store } from \"atom.io/internal\"\nimport type { Canonical, Json } from \"atom.io/json\"\nimport { employSocket, type Socket } from \"atom.io/realtime\"\n\nimport { createSubscriber } from \"./create-subscriber\"\n\nexport function pullAtomFamilyMember<\n\tJ extends Json.Serializable,\n\tK extends Canonical,\n>(\n\tstore: Store,\n\tsocket: Socket,\n\tfamily: AtomIO.AtomFamilyToken<J, K, any>,\n\tkey: NoInfer<K>,\n): () => void {\n\tconst token = findInStore(store, family, key)\n\treturn createSubscriber(socket, token.key, () => {\n\t\tconst stopWatching = employSocket(\n\t\t\tsocket,\n\t\t\t`serve:${token.key}`,\n\t\t\t(data: J) => {\n\t\t\t\tsetIntoStore(store, token, data)\n\t\t\t},\n\t\t)\n\t\tsocket.emit(`sub:${family.key}`, key)\n\t\treturn () => {\n\t\t\tsocket.emit(`unsub:${token.key}`)\n\t\t\tstopWatching()\n\t\t}\n\t})\n}\n","import type * as AtomIO from \"atom.io\"\nimport type { AsJSON, SignalFrom, Store, Transceiver } from \"atom.io/internal\"\nimport { getJsonToken, getUpdateToken, setIntoStore } from \"atom.io/internal\"\nimport { employSocket, type Socket } from \"atom.io/realtime\"\n\nimport { createSubscriber } from \"./create-subscriber\"\n\nexport function pullMutableAtom<T extends Transceiver<any, any, any>>(\n\tstore: Store,\n\tsocket: Socket,\n\ttoken: AtomIO.MutableAtomToken<T>,\n): () => void {\n\tconst jsonToken = getJsonToken(store, token)\n\tconst updateToken = getUpdateToken(token)\n\treturn createSubscriber(socket, token.key, () => {\n\t\tconst stopWatchingForInit = employSocket(\n\t\t\tsocket,\n\t\t\t`init:${token.key}`,\n\t\t\t(data: AsJSON<T>) => {\n\t\t\t\tsetIntoStore(store, jsonToken, data)\n\t\t\t},\n\t\t)\n\t\tconst stopWatchingForUpdate = employSocket(\n\t\t\tsocket,\n\t\t\t`next:${token.key}`,\n\t\t\t(data: SignalFrom<T>) => {\n\t\t\t\tsetIntoStore(store, updateToken, data)\n\t\t\t},\n\t\t)\n\t\tsocket.emit(`sub:${token.key}`)\n\t\treturn () => {\n\t\t\tsocket.emit(`unsub:${token.key}`)\n\t\t\tstopWatchingForInit()\n\t\t\tstopWatchingForUpdate()\n\t\t}\n\t})\n}\n","import type * as AtomIO from \"atom.io\"\nimport type { AsJSON, SignalFrom, Store, Transceiver } from \"atom.io/internal\"\nimport {\n\tfindInStore,\n\tgetJsonToken,\n\tgetUpdateToken,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport { employSocket, type Socket } from \"atom.io/realtime\"\n\nimport { createSubscriber } from \"./create-subscriber\"\n\nexport function pullMutableAtomFamilyMember<\n\tT extends Transceiver<any, any, any>,\n\tK extends Canonical,\n>(\n\tstore: Store,\n\tsocket: Socket,\n\tfamily: AtomIO.MutableAtomFamilyToken<T, K>,\n\tkey: NoInfer<K>,\n): () => void {\n\tconst token = findInStore(store, family, key)\n\tconst jsonToken = getJsonToken(store, token)\n\tconst trackerToken = getUpdateToken(token)\n\treturn createSubscriber(socket, token.key, () => {\n\t\tconst stopWatchingForInit = employSocket(\n\t\t\tsocket,\n\t\t\t`init:${token.key}`,\n\t\t\t(data: AsJSON<T>) => {\n\t\t\t\tsetIntoStore(store, jsonToken, data)\n\t\t\t},\n\t\t)\n\t\tconst stopWatchingForUpdate = employSocket(\n\t\t\tsocket,\n\t\t\t`next:${token.key}`,\n\t\t\t(data: SignalFrom<T>) => {\n\t\t\t\tsetIntoStore(store, trackerToken, data)\n\t\t\t},\n\t\t)\n\t\tsocket.emit(`sub:${family.key}`, key)\n\t\treturn () => {\n\t\t\tsocket.emit(`unsub:${token.key}`)\n\t\t\tstopWatchingForInit()\n\t\t\tstopWatchingForUpdate()\n\t\t}\n\t})\n}\n","import type { AtomToken, SelectorToken } from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { getFamilyOfToken, subscribeToState } from \"atom.io/internal\"\nimport { parseJson } from \"atom.io/json\"\nimport type { Socket } from \"atom.io/realtime\"\n\nimport { pullAtom } from \"./pull-atom\"\nimport { pullAtomFamilyMember } from \"./pull-atom-family-member\"\nimport { pullMutableAtom } from \"./pull-mutable-atom\"\nimport { pullMutableAtomFamilyMember } from \"./pull-mutable-atom-family-member\"\n\nexport function pullSelectorRoots(\n\tstore: Store,\n\tsocket: Socket,\n\tselectorToken: SelectorToken<any>,\n): () => void {\n\tconst atomSubscriptions = new Map<string, () => void>()\n\n\tconst start = () => {\n\t\tconst atomKeys = store.selectorAtoms.getRelatedKeys(selectorToken.key)\n\t\tif (atomKeys) {\n\t\t\tfor (const [atomKey, unsub] of atomSubscriptions) {\n\t\t\t\tif (!atomKeys.has(atomKey)) {\n\t\t\t\t\tunsub()\n\t\t\t\t\tatomSubscriptions.delete(atomKey)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const atomKey of atomKeys) {\n\t\t\t\tif (atomSubscriptions.has(atomKey)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst atom = store.atoms.get(atomKey) as AtomToken<any, any>\n\t\t\t\tswitch (atom.type) {\n\t\t\t\t\tcase `atom`: {\n\t\t\t\t\t\tif (atom.family) {\n\t\t\t\t\t\t\tconst { subKey: serializedSubKey } = atom.family\n\t\t\t\t\t\t\tconst subKey = parseJson(serializedSubKey)\n\t\t\t\t\t\t\tconst family = getFamilyOfToken(store, atom)\n\t\t\t\t\t\t\tatomSubscriptions.set(\n\t\t\t\t\t\t\t\tatomKey,\n\t\t\t\t\t\t\t\tpullAtomFamilyMember(store, socket, family, subKey),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tatomSubscriptions.set(atomKey, pullAtom(store, socket, atom))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase `mutable_atom`: {\n\t\t\t\t\t\tif (atom.family) {\n\t\t\t\t\t\t\tconst { subKey: serializedSubKey } = atom.family\n\t\t\t\t\t\t\tconst subKey = parseJson(serializedSubKey)\n\t\t\t\t\t\t\tconst family = getFamilyOfToken(store, atom)\n\t\t\t\t\t\t\tatomSubscriptions.set(\n\t\t\t\t\t\t\t\tatomKey,\n\t\t\t\t\t\t\t\tpullMutableAtomFamilyMember(store, socket, family, subKey),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tatomSubscriptions.set(\n\t\t\t\t\t\t\t\tatomKey,\n\t\t\t\t\t\t\t\tpullMutableAtom(store, socket, atom),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tconst unsubFromSelector = subscribeToState(\n\t\tstore,\n\t\tselectorToken,\n\t\t`pull-watches-dependencies`,\n\t\t() => {\n\t\t\tstart()\n\t\t},\n\t)\n\n\tstart()\n\n\treturn () => {\n\t\tfor (const [, unsub] of atomSubscriptions) unsub()\n\t\tunsubFromSelector()\n\t}\n}\n","import type * as AtomIO from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport type { Socket } from \"atom.io/realtime\"\n\nimport { pullSelectorRoots } from \"./pull-selector-roots\"\n\nexport function pullSelector<T>(\n\tstore: Store,\n\tsocket: Socket,\n\ttoken: AtomIO.SelectorToken<T>,\n): () => void {\n\treturn pullSelectorRoots(store, socket, token)\n}\n","import type * as AtomIO from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { findInStore } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport type { Socket } from \"atom.io/realtime\"\n\nimport { pullSelectorRoots } from \"./pull-selector-roots\"\n\nexport function pullSelectorFamilyMember<T, K extends Canonical>(\n\tstore: Store,\n\tsocket: Socket,\n\tfamilyToken: AtomIO.SelectorFamilyToken<T, K>,\n\tkey: NoInfer<K>,\n): () => void {\n\tconst token = findInStore(store, familyToken, key)\n\treturn pullSelectorRoots(store, socket, token)\n}\n","import type { WritableToken } from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { setIntoStore, subscribeToState } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { Socket } from \"atom.io/realtime\"\nimport { employSocket, mutexAtoms } from \"atom.io/realtime\"\n\nimport { createSubscriber } from \"./create-subscriber\"\n\nexport function pushState<J extends Json.Serializable>(\n\tstore: Store,\n\tsocket: Socket,\n\ttoken: WritableToken<J>,\n): () => void {\n\treturn createSubscriber(socket, `push:${token.key}`, () => {\n\t\tlet stopWatching = employSocket(\n\t\t\tsocket,\n\t\t\t`claim-result:${token.key}`,\n\t\t\t(success: boolean) => {\n\t\t\t\tif (!success) return\n\t\t\t\tstopWatching()\n\t\t\t\tsetIntoStore(store, mutexAtoms, token.key, true)\n\t\t\t\tstopWatching = subscribeToState(store, token, `push`, ({ newValue }) => {\n\t\t\t\t\tsocket.emit(`pub:${token.key}`, newValue)\n\t\t\t\t})\n\t\t\t},\n\t\t)\n\n\t\tsocket.emit(`claim:${token.key}`)\n\n\t\treturn () => {\n\t\t\tsocket.emit(`unclaim:${token.key}`)\n\t\t\tstopWatching()\n\t\t}\n\t})\n}\n","import type { RootStore } from \"atom.io/internal\"\nimport {\n\tassignTransactionToContinuity,\n\tgetFromStore,\n\tgetJsonToken,\n\tsetEpochNumberOfContinuity,\n\tsetIntoStore,\n\tsubscribeToTransaction,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { ContinuityToken, Socket } from \"atom.io/realtime\"\n\nimport { useRegisterAndAttemptConfirmedUpdate } from \"./continuity/register-and-attempt-confirmed-update\"\nimport { useConcealState } from \"./continuity/use-conceal-state\"\nimport { useRevealState } from \"./continuity/use-reveal-state\"\nimport {\n\tconfirmedUpdateQueueAtom,\n\toptimisticUpdateQueueAtom,\n} from \"./realtime-client-stores\"\n\nexport function syncContinuity(\n\tstore: RootStore,\n\tsocket: Socket,\n\tcontinuity: ContinuityToken,\n): () => void {\n\tconst continuityKey = continuity.key\n\tconst optimisticUpdates = getFromStore(store, optimisticUpdateQueueAtom)\n\tconst confirmedUpdates = getFromStore(store, confirmedUpdateQueueAtom)\n\n\tconst initializeContinuity = (epoch: number, payload: Json.Array) => {\n\t\tsocket.off(`continuity-init:${continuityKey}`, initializeContinuity)\n\t\tlet i = 0\n\t\tlet k: any\n\t\tlet v: any\n\t\tfor (const x of payload) {\n\t\t\tif (i % 2 === 0) {\n\t\t\t\tk = x\n\t\t\t} else {\n\t\t\t\tv = x\n\t\t\t\tif (`type` in k && k.type === `mutable_atom`) {\n\t\t\t\t\tk = getJsonToken(store, k)\n\t\t\t\t}\n\t\t\t\tsetIntoStore(store, k, v)\n\t\t\t}\n\t\t\ti++\n\t\t}\n\t\tsetEpochNumberOfContinuity(store, continuityKey, epoch)\n\t}\n\tsocket.off(`continuity-init:${continuityKey}`)\n\tsocket.on(`continuity-init:${continuityKey}`, initializeContinuity)\n\n\tconst registerAndAttemptConfirmedUpdate = useRegisterAndAttemptConfirmedUpdate(\n\t\tstore,\n\t\tcontinuityKey,\n\t\tsocket,\n\t\toptimisticUpdates,\n\t\tconfirmedUpdates,\n\t)\n\tsocket.off(`tx-new:${continuityKey}`)\n\tsocket.on(`tx-new:${continuityKey}`, registerAndAttemptConfirmedUpdate)\n\n\tconst unsubscribeFunctions = continuity.actions.map((transaction) => {\n\t\tassignTransactionToContinuity(store, continuityKey, transaction.key)\n\t\tconst unsubscribeFromTransactionUpdates = subscribeToTransaction(\n\t\t\tstore,\n\t\t\ttransaction,\n\t\t\t`tx-run:${continuityKey}`,\n\t\t\t(clientUpdate) => {\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`🤞`,\n\t\t\t\t\t`continuity`,\n\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t`enqueuing optimistic update`,\n\t\t\t\t)\n\t\t\t\tconst optimisticUpdateIndex = optimisticUpdates.findIndex(\n\t\t\t\t\t(update) => update.id === clientUpdate.id,\n\t\t\t\t)\n\t\t\t\tif (optimisticUpdateIndex === -1) {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`🤞`,\n\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t`enqueuing new optimistic update`,\n\t\t\t\t\t)\n\t\t\t\t\tsetIntoStore(store, optimisticUpdateQueueAtom, (queue) => {\n\t\t\t\t\t\tqueue.push(clientUpdate)\n\t\t\t\t\t\tqueue.sort((a, b) => a.epoch - b.epoch)\n\t\t\t\t\t\treturn queue\n\t\t\t\t\t})\n\t\t\t\t} else {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`🤞`,\n\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t`replacing existing optimistic update at index ${optimisticUpdateIndex}`,\n\t\t\t\t\t)\n\t\t\t\t\tsetIntoStore(store, optimisticUpdateQueueAtom, (queue) => {\n\t\t\t\t\t\tqueue[optimisticUpdateIndex] = clientUpdate\n\t\t\t\t\t\treturn queue\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tsocket.emit(`tx-run:${continuityKey}`, {\n\t\t\t\t\tid: clientUpdate.id,\n\t\t\t\t\ttoken: transaction,\n\t\t\t\t\tparams: clientUpdate.params,\n\t\t\t\t})\n\t\t\t},\n\t\t)\n\t\treturn unsubscribeFromTransactionUpdates\n\t})\n\n\tconst revealState = useRevealState(store)\n\tconst concealState = useConcealState(store)\n\tsocket.on(`reveal:${continuityKey}`, revealState)\n\tsocket.on(`conceal:${continuityKey}`, concealState)\n\n\tsocket.emit(`get:${continuityKey}`)\n\treturn () => {\n\t\tsocket.off(`continuity-init:${continuityKey}`)\n\t\tsocket.off(`tx-new:${continuityKey}`)\n\t\tfor (const unsubscribe of unsubscribeFunctions) unsubscribe()\n\t\t// socket.emit(`unsub:${continuityKey}`)\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["mySocketKeyAtom: RegularAtomToken<SocketKey | undefined>","myUserKeyAtom: RegularAtomToken<UserKey | null>","myRoomKeySelector: ReadonlyPureSelectorToken<RoomKey | null>","optimisticUpdateQueueAtom: AtomIO.RegularAtomToken<\n\tAtomIO.TransactionOutcomeEvent<any>[]\n>","confirmedUpdateQueueAtom: AtomIO.RegularAtomToken<\n\tAtomIO.TransactionOutcomeEvent<any>[]\n>","continuityEpoch: number | undefined","k: any","v: any","subscriptions: WeakMap<Socket, Map<string, SubData>>","socketIds: WeakMap<Socket, string | undefined>","atom","k: any","v: any"],"sources":["../../src/realtime-client/realtime-client-stores/client-main-store.ts","../../src/realtime-client/realtime-client-stores/client-sync-store.ts","../../src/realtime-client/continuity/register-and-attempt-confirmed-update.ts","../../src/realtime-client/continuity/use-conceal-state.ts","../../src/realtime-client/continuity/use-reveal-state.ts","../../src/realtime-client/create-subscriber.ts","../../src/realtime-client/pull-atom.ts","../../src/realtime-client/pull-atom-family-member.ts","../../src/realtime-client/pull-mutable-atom.ts","../../src/realtime-client/pull-mutable-atom-family-member.ts","../../src/realtime-client/pull-selector-roots.ts","../../src/realtime-client/pull-selector.ts","../../src/realtime-client/pull-selector-family-member.ts","../../src/realtime-client/push-state.ts","../../src/realtime-client/sync-continuity.ts"],"sourcesContent":["import type { ReadonlyPureSelectorToken, RegularAtomToken } from \"atom.io\"\nimport { atom, getInternalRelations, selector } from \"atom.io\"\nimport type { RoomKey, SocketKey, UserKey } from \"atom.io/realtime\"\nimport { usersInRooms } from \"atom.io/realtime\"\n\nexport const mySocketKeyAtom: RegularAtomToken<SocketKey | undefined> = atom({\n\tkey: `mySocketKey`,\n\tdefault: undefined,\n})\n\nexport const myUserKeyAtom: RegularAtomToken<UserKey | null> = atom({\n\tkey: `myUserKey`,\n\tdefault: null,\n\teffects: [\n\t\t(userKey) => {\n\t\t\tif (typeof window !== `undefined`) {\n\t\t\t\tvoid import(`atom.io/web`).then(({ storageSync }) => {\n\t\t\t\t\tstorageSync(globalThis.localStorage, JSON, `myUserKey`)(userKey)\n\t\t\t\t})\n\t\t\t}\n\t\t},\n\t],\n})\n\nexport const myRoomKeySelector: ReadonlyPureSelectorToken<RoomKey | null> =\n\tselector({\n\t\tkey: `myRoomKey`,\n\t\tget: ({ get }) => {\n\t\t\tif (\n\t\t\t\t`process` in globalThis &&\n\t\t\t\t`env` in process &&\n\t\t\t\t`REALTIME_ROOM_KEY` in process.env\n\t\t\t) {\n\t\t\t\t// if a room running server-side wants its own key, this is where it lives\n\t\t\t\treturn process.env[`REALTIME_ROOM_KEY`] as RoomKey\n\t\t\t}\n\t\t\tconst myUserKey = get(myUserKeyAtom)\n\t\t\tif (!myUserKey) return null\n\t\t\tconst [, usersInRoomsAtoms] = getInternalRelations(usersInRooms, `split`)\n\t\t\tconst roomKeys = get(usersInRoomsAtoms, myUserKey)\n\t\t\tfor (const roomKey of roomKeys) return roomKey\n\t\t\treturn null\n\t\t},\n\t})\n","import * as AtomIO from \"atom.io\"\n\nexport const optimisticUpdateQueueAtom: AtomIO.RegularAtomToken<\n\tAtomIO.TransactionOutcomeEvent<any>[]\n> = AtomIO.atom<AtomIO.TransactionOutcomeEvent<any>[]>({\n\tkey: `optimisticUpdateQueue`,\n\tdefault: () => [],\n})\n\nexport const confirmedUpdateQueueAtom: AtomIO.RegularAtomToken<\n\tAtomIO.TransactionOutcomeEvent<any>[]\n> = AtomIO.atom<AtomIO.TransactionOutcomeEvent<any>[]>({\n\tkey: `confirmedUpdateQueue`,\n\tdefault: () => [],\n})\n","import type * as AtomIO from \"atom.io\"\nimport type { Fn, RootStore } from \"atom.io/internal\"\nimport {\n\tactUponStore,\n\tgetEpochNumberOfContinuity,\n\tingestTransactionOutcomeEvent,\n\tsetEpochNumberOfContinuity,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { Socket } from \"atom.io/realtime\"\n\nimport {\n\tconfirmedUpdateQueueAtom,\n\toptimisticUpdateQueueAtom,\n} from \"../realtime-client-stores\"\n\nexport const useRegisterAndAttemptConfirmedUpdate =\n\t(\n\t\tstore: RootStore,\n\t\tcontinuityKey: string,\n\t\tsocket: Socket,\n\t\toptimisticUpdates: readonly AtomIO.TransactionOutcomeEvent<\n\t\t\tAtomIO.TransactionToken<Fn>\n\t\t>[],\n\t\tconfirmedUpdates: readonly AtomIO.TransactionOutcomeEvent<\n\t\t\tAtomIO.TransactionToken<Fn>\n\t\t>[],\n\t) =>\n\t(\n\t\tconfirmed: AtomIO.TransactionOutcomeEvent<AtomIO.TransactionToken<Fn>> &\n\t\t\tJson.Serializable,\n\t): void => {\n\t\tfunction reconcileEpoch(\n\t\t\toptimisticUpdate: AtomIO.TransactionOutcomeEvent<\n\t\t\t\tAtomIO.TransactionToken<Fn>\n\t\t\t>,\n\t\t\tconfirmedUpdate: AtomIO.TransactionOutcomeEvent<\n\t\t\t\tAtomIO.TransactionToken<Fn>\n\t\t\t>,\n\t\t): void {\n\t\t\tstore.logger.info(\n\t\t\t\t`🧑⚖️`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`reconciling updates`,\n\t\t\t)\n\t\t\tsetIntoStore(store, optimisticUpdateQueueAtom, (queue) => {\n\t\t\t\tqueue.shift()\n\t\t\t\treturn queue\n\t\t\t})\n\t\t\tif (optimisticUpdate.id === confirmedUpdate.id) {\n\t\t\t\tconst clientResult = JSON.stringify(optimisticUpdate.subEvents)\n\t\t\t\tconst serverResult = JSON.stringify(confirmedUpdate.subEvents)\n\t\t\t\tif (clientResult === serverResult) {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`✅`,\n\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t`results for ${optimisticUpdate.id} match between client and server`,\n\t\t\t\t\t)\n\t\t\t\t\tsocket.emit(`ack:${continuityKey}`, confirmedUpdate.epoch)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// id mismatch\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`❌`,\n\t\t\t\t\t`continuity`,\n\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t`thought update #${confirmedUpdate.epoch} was ${optimisticUpdate.token.key}:${optimisticUpdate.id}, but it was actually ${confirmedUpdate.token.key}:${confirmedUpdate.id}`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tstore.logger.info(\n\t\t\t\t`🧑⚖️`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`updates do not match`,\n\t\t\t\toptimisticUpdate,\n\t\t\t\tconfirmedUpdate,\n\t\t\t)\n\t\t\tconst reversedOptimisticUpdates = optimisticUpdates.toReversed()\n\t\t\tfor (const subsequentOptimistic of reversedOptimisticUpdates) {\n\t\t\t\tingestTransactionOutcomeEvent(store, subsequentOptimistic, `oldValue`)\n\t\t\t}\n\t\t\tstore.logger.info(\n\t\t\t\t`⏪`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`undid optimistic updates:`,\n\t\t\t\treversedOptimisticUpdates,\n\t\t\t)\n\t\t\tingestTransactionOutcomeEvent(store, optimisticUpdate, `oldValue`)\n\t\t\tstore.logger.info(\n\t\t\t\t`⏪`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`undid zeroth optimistic update`,\n\t\t\t\toptimisticUpdate,\n\t\t\t)\n\t\t\tingestTransactionOutcomeEvent(store, confirmedUpdate, `newValue`)\n\t\t\tstore.logger.info(\n\t\t\t\t`⏩`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`applied confirmed update`,\n\t\t\t\tconfirmedUpdate,\n\t\t\t)\n\t\t\tsocket.emit(`ack:${continuityKey}`, confirmedUpdate.epoch)\n\n\t\t\tfor (const subsequentOptimistic of optimisticUpdates) {\n\t\t\t\tconst token = {\n\t\t\t\t\ttype: `transaction`,\n\t\t\t\t\tkey: subsequentOptimistic.token.key,\n\t\t\t\t} as const\n\t\t\t\tconst { id, params } = subsequentOptimistic\n\t\t\t\tactUponStore(store, token, id)(...params)\n\t\t\t}\n\t\t\tstore.logger.info(\n\t\t\t\t`⏩`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`reapplied subsequent optimistic updates:`,\n\t\t\t\toptimisticUpdates,\n\t\t\t)\n\t\t}\n\n\t\tstore.logger.info(\n\t\t\t`🧑⚖️`,\n\t\t\t`continuity`,\n\t\t\tcontinuityKey,\n\t\t\t`integrating confirmed update`,\n\t\t\t{ confirmedUpdate: confirmed, confirmedUpdates, optimisticUpdates },\n\t\t)\n\t\tconst zerothOptimisticUpdate = optimisticUpdates[0]\n\t\tif (zerothOptimisticUpdate) {\n\t\t\tstore.logger.info(\n\t\t\t\t`🧑⚖️`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`has optimistic updates to reconcile`,\n\t\t\t)\n\t\t\tif (confirmed.epoch === zerothOptimisticUpdate.epoch) {\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`🧑⚖️`,\n\t\t\t\t\t`continuity`,\n\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t`epoch of confirmed update #${confirmed.epoch} matches zeroth optimistic update`,\n\t\t\t\t)\n\t\t\t\treconcileEpoch(zerothOptimisticUpdate, confirmed)\n\t\t\t\tfor (const nextConfirmed of confirmedUpdates) {\n\t\t\t\t\tconst nextOptimistic = optimisticUpdates[0]\n\t\t\t\t\tif (nextConfirmed.epoch === nextOptimistic?.epoch) {\n\t\t\t\t\t\treconcileEpoch(nextOptimistic, nextConfirmed)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// epoch mismatch\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`🧑⚖️`,\n\t\t\t\t\t`continuity`,\n\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t`epoch of confirmed update #${confirmed.epoch} does not match zeroth optimistic update #${zerothOptimisticUpdate.epoch}`,\n\t\t\t\t)\n\t\t\t\tconst confirmedUpdateIsAlreadyEnqueued = confirmedUpdates.some(\n\t\t\t\t\t(update) => update.epoch === confirmed.epoch,\n\t\t\t\t)\n\t\t\t\tif (!confirmedUpdateIsAlreadyEnqueued) {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`👈`,\n\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t`pushing confirmed update to queue`,\n\t\t\t\t\t\tconfirmed,\n\t\t\t\t\t)\n\t\t\t\t\tsetIntoStore(store, confirmedUpdateQueueAtom, (queue) => {\n\t\t\t\t\t\tqueue.push(confirmed)\n\t\t\t\t\t\tqueue.sort((a, b) => a.epoch - b.epoch)\n\t\t\t\t\t\treturn queue\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tstore.logger.info(\n\t\t\t\t`🧑⚖️`,\n\t\t\t\t`continuity`,\n\t\t\t\tcontinuityKey,\n\t\t\t\t`has no optimistic updates to deal with`,\n\t\t\t)\n\t\t\tlet continuityEpoch: number | undefined\n\t\t\tcontinuityEpoch = getEpochNumberOfContinuity(store, continuityKey)\n\n\t\t\tif (continuityEpoch === confirmed.epoch - 1) {\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`✅`,\n\t\t\t\t\t`continuity`,\n\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t`integrating update #${confirmed.epoch} (${confirmed.token.key} ${confirmed.id})`,\n\t\t\t\t)\n\t\t\t\tingestTransactionOutcomeEvent(store, confirmed, `newValue`)\n\t\t\t\tsocket.emit(`ack:${continuityKey}`, confirmed.epoch)\n\t\t\t\tsetEpochNumberOfContinuity(store, continuityKey, confirmed.epoch)\n\t\t\t} else if (continuityEpoch !== undefined) {\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`🧑⚖️`,\n\t\t\t\t\t`continuity`,\n\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t`received update #${confirmed.epoch} but still waiting for update #${\n\t\t\t\t\t\tcontinuityEpoch + 1\n\t\t\t\t\t}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tclientEpoch: continuityEpoch,\n\t\t\t\t\t\tserverEpoch: confirmed.epoch,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tconst confirmedUpdateIsAlreadyEnqueued = confirmedUpdates.some(\n\t\t\t\t\t(update) => update.epoch === confirmed.epoch,\n\t\t\t\t)\n\t\t\t\tif (confirmedUpdateIsAlreadyEnqueued) {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`👍`,\n\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t`confirmed update #${confirmed.epoch} is already enqueued`,\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`👈`,\n\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t`pushing confirmed update #${confirmed.epoch} to queue`,\n\t\t\t\t\t)\n\t\t\t\t\tsetIntoStore(store, confirmedUpdateQueueAtom, (queue) => {\n\t\t\t\t\t\tqueue.push(confirmed)\n\t\t\t\t\t\tqueue.sort((a, b) => a.epoch - b.epoch)\n\t\t\t\t\t\treturn queue\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n","import type { AtomToken } from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { disposeAtom } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\n\nexport function useConcealState(store: Store) {\n\treturn (concealed: AtomToken<Json.Serializable>[]): void => {\n\t\tfor (const token of concealed) {\n\t\t\tdisposeAtom(store, token)\n\t\t}\n\t}\n}\n","import { setIntoStore, type Store } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\n\nexport function useRevealState(store: Store) {\n\treturn (revealed: Json.Array): void => {\n\t\tlet i = 0\n\t\tlet k: any\n\t\tlet v: any\n\t\tfor (const x of revealed) {\n\t\t\tif (i % 2 === 0) {\n\t\t\t\tk = x\n\t\t\t} else {\n\t\t\t\tv = x\n\t\t\t\tsetIntoStore(store, k, v)\n\t\t\t}\n\t\t\ti++\n\t\t}\n\t}\n}\n","import { Future } from \"atom.io/internal\"\nimport type { Socket } from \"atom.io/realtime\"\n\ntype SubData = { refcount: number; timer: Future<void> }\n\nconst subscriptions: WeakMap<Socket, Map<string, SubData>> = new WeakMap()\nconst socketIds: WeakMap<Socket, string | undefined> = new WeakMap()\n\nfunction getSubMap(socket: Socket): Map<string, SubData> {\n\tlet subMap = subscriptions.get(socket)\n\tif (subMap === undefined) {\n\t\tsubMap = new Map()\n\t\tsubscriptions.set(socket, subMap)\n\t}\n\treturn subMap\n}\n\nexport function createSubscriber<K extends string>(\n\tsocket: Socket,\n\tkey: K,\n\topen: (key: K) => () => void,\n): () => void {\n\tconst knownSocketId = socketIds.get(socket)\n\tif (knownSocketId !== socket.id) {\n\t\tsocketIds.set(socket, socket.id)\n\t\tsubscriptions.delete(socket)\n\t}\n\tconst subMap = getSubMap(socket)\n\tlet sub = subMap.get(key)\n\n\tif (sub) {\n\t\tsub.timer.use(new Promise<void>(() => {}))\n\t\tsub.refcount++\n\t} else {\n\t\tsub = { refcount: 1, timer: new Future<void>(() => {}) }\n\t\tsubMap.set(key, sub)\n\t\tconst close = open(key)\n\t\tvoid sub.timer.then(() => {\n\t\t\tclose()\n\t\t\tsubMap.delete(key)\n\t\t})\n\t}\n\treturn () => {\n\t\tsub.refcount--\n\n\t\tif (sub.refcount === 0) {\n\t\t\tconst timeout = new Promise<void>((resolve) => {\n\t\t\t\tsetTimeout(resolve, 50)\n\t\t\t})\n\t\t\tsub.timer.use(timeout)\n\t\t}\n\t}\n}\n","import type * as AtomIO from \"atom.io\"\nimport { setIntoStore, type Store } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { employSocket, type Socket } from \"atom.io/realtime\"\n\nimport { createSubscriber } from \"./create-subscriber\"\n\nexport function pullAtom<J extends Json.Serializable>(\n\tstore: Store,\n\tsocket: Socket,\n\ttoken: AtomIO.RegularAtomToken<J, any, any>,\n): () => void {\n\treturn createSubscriber(socket, token.key, (key) => {\n\t\tconst stopWatching = employSocket(socket, `serve:${key}`, (data: J) => {\n\t\t\tsetIntoStore(store, token, data)\n\t\t})\n\t\tsocket.emit(`sub:${token.key}`)\n\t\treturn () => {\n\t\t\tsocket.emit(`unsub:${key}`)\n\t\t\tstopWatching()\n\t\t}\n\t})\n}\n","import type * as AtomIO from \"atom.io\"\nimport { findInStore, setIntoStore, type Store } from \"atom.io/internal\"\nimport type { Canonical, Json } from \"atom.io/json\"\nimport { employSocket, type Socket } from \"atom.io/realtime\"\n\nimport { createSubscriber } from \"./create-subscriber\"\n\nexport function pullAtomFamilyMember<\n\tJ extends Json.Serializable,\n\tK extends Canonical,\n>(\n\tstore: Store,\n\tsocket: Socket,\n\tfamily: AtomIO.AtomFamilyToken<J, K, any>,\n\tkey: NoInfer<K>,\n): () => void {\n\tconst token = findInStore(store, family, key)\n\treturn createSubscriber(socket, token.key, () => {\n\t\tconst stopWatching = employSocket(\n\t\t\tsocket,\n\t\t\t`serve:${token.key}`,\n\t\t\t(data: J) => {\n\t\t\t\tsetIntoStore(store, token, data)\n\t\t\t},\n\t\t)\n\t\tsocket.emit(`sub:${family.key}`, key)\n\t\treturn () => {\n\t\t\tsocket.emit(`unsub:${token.key}`)\n\t\t\tstopWatching()\n\t\t}\n\t})\n}\n","import type * as AtomIO from \"atom.io\"\nimport type { AsJSON, SignalFrom, Store, Transceiver } from \"atom.io/internal\"\nimport { getJsonToken, getUpdateToken, setIntoStore } from \"atom.io/internal\"\nimport { employSocket, type Socket } from \"atom.io/realtime\"\n\nimport { createSubscriber } from \"./create-subscriber\"\n\nexport function pullMutableAtom<T extends Transceiver<any, any, any>>(\n\tstore: Store,\n\tsocket: Socket,\n\ttoken: AtomIO.MutableAtomToken<T>,\n): () => void {\n\tconst jsonToken = getJsonToken(store, token)\n\tconst updateToken = getUpdateToken(token)\n\treturn createSubscriber(socket, token.key, () => {\n\t\tconst stopWatchingForInit = employSocket(\n\t\t\tsocket,\n\t\t\t`init:${token.key}`,\n\t\t\t(data: AsJSON<T>) => {\n\t\t\t\tsetIntoStore(store, jsonToken, data)\n\t\t\t},\n\t\t)\n\t\tconst stopWatchingForUpdate = employSocket(\n\t\t\tsocket,\n\t\t\t`next:${token.key}`,\n\t\t\t(data: SignalFrom<T>) => {\n\t\t\t\tsetIntoStore(store, updateToken, data)\n\t\t\t},\n\t\t)\n\t\tsocket.emit(`sub:${token.key}`)\n\t\treturn () => {\n\t\t\tsocket.emit(`unsub:${token.key}`)\n\t\t\tstopWatchingForInit()\n\t\t\tstopWatchingForUpdate()\n\t\t}\n\t})\n}\n","import type * as AtomIO from \"atom.io\"\nimport type { AsJSON, SignalFrom, Store, Transceiver } from \"atom.io/internal\"\nimport {\n\tfindInStore,\n\tgetJsonToken,\n\tgetUpdateToken,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport { employSocket, type Socket } from \"atom.io/realtime\"\n\nimport { createSubscriber } from \"./create-subscriber\"\n\nexport function pullMutableAtomFamilyMember<\n\tT extends Transceiver<any, any, any>,\n\tK extends Canonical,\n>(\n\tstore: Store,\n\tsocket: Socket,\n\tfamily: AtomIO.MutableAtomFamilyToken<T, K>,\n\tkey: NoInfer<K>,\n): () => void {\n\tconst token = findInStore(store, family, key)\n\tconst jsonToken = getJsonToken(store, token)\n\tconst trackerToken = getUpdateToken(token)\n\treturn createSubscriber(socket, token.key, () => {\n\t\tconst stopWatchingForInit = employSocket(\n\t\t\tsocket,\n\t\t\t`init:${token.key}`,\n\t\t\t(data: AsJSON<T>) => {\n\t\t\t\tsetIntoStore(store, jsonToken, data)\n\t\t\t},\n\t\t)\n\t\tconst stopWatchingForUpdate = employSocket(\n\t\t\tsocket,\n\t\t\t`next:${token.key}`,\n\t\t\t(data: SignalFrom<T>) => {\n\t\t\t\tsetIntoStore(store, trackerToken, data)\n\t\t\t},\n\t\t)\n\t\tsocket.emit(`sub:${family.key}`, key)\n\t\treturn () => {\n\t\t\tsocket.emit(`unsub:${token.key}`)\n\t\t\tstopWatchingForInit()\n\t\t\tstopWatchingForUpdate()\n\t\t}\n\t})\n}\n","import type { AtomToken, SelectorToken } from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { getFamilyOfToken, subscribeToState } from \"atom.io/internal\"\nimport { parseJson } from \"atom.io/json\"\nimport type { Socket } from \"atom.io/realtime\"\n\nimport { pullAtom } from \"./pull-atom\"\nimport { pullAtomFamilyMember } from \"./pull-atom-family-member\"\nimport { pullMutableAtom } from \"./pull-mutable-atom\"\nimport { pullMutableAtomFamilyMember } from \"./pull-mutable-atom-family-member\"\n\nexport function pullSelectorRoots(\n\tstore: Store,\n\tsocket: Socket,\n\tselectorToken: SelectorToken<any>,\n): () => void {\n\tconst atomSubscriptions = new Map<string, () => void>()\n\n\tconst start = () => {\n\t\tconst atomKeys = store.selectorAtoms.getRelatedKeys(selectorToken.key)\n\t\tif (atomKeys) {\n\t\t\tfor (const [atomKey, unsub] of atomSubscriptions) {\n\t\t\t\tif (!atomKeys.has(atomKey)) {\n\t\t\t\t\tunsub()\n\t\t\t\t\tatomSubscriptions.delete(atomKey)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const atomKey of atomKeys) {\n\t\t\t\tif (atomSubscriptions.has(atomKey)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst atom = store.atoms.get(atomKey) as AtomToken<any, any>\n\t\t\t\tswitch (atom.type) {\n\t\t\t\t\tcase `atom`: {\n\t\t\t\t\t\tif (atom.family) {\n\t\t\t\t\t\t\tconst { subKey: serializedSubKey } = atom.family\n\t\t\t\t\t\t\tconst subKey = parseJson(serializedSubKey)\n\t\t\t\t\t\t\tconst family = getFamilyOfToken(store, atom)\n\t\t\t\t\t\t\tatomSubscriptions.set(\n\t\t\t\t\t\t\t\tatomKey,\n\t\t\t\t\t\t\t\tpullAtomFamilyMember(store, socket, family, subKey),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tatomSubscriptions.set(atomKey, pullAtom(store, socket, atom))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase `mutable_atom`: {\n\t\t\t\t\t\tif (atom.family) {\n\t\t\t\t\t\t\tconst { subKey: serializedSubKey } = atom.family\n\t\t\t\t\t\t\tconst subKey = parseJson(serializedSubKey)\n\t\t\t\t\t\t\tconst family = getFamilyOfToken(store, atom)\n\t\t\t\t\t\t\tatomSubscriptions.set(\n\t\t\t\t\t\t\t\tatomKey,\n\t\t\t\t\t\t\t\tpullMutableAtomFamilyMember(store, socket, family, subKey),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tatomSubscriptions.set(\n\t\t\t\t\t\t\t\tatomKey,\n\t\t\t\t\t\t\t\tpullMutableAtom(store, socket, atom),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tconst unsubFromSelector = subscribeToState(\n\t\tstore,\n\t\tselectorToken,\n\t\t`pull-watches-dependencies`,\n\t\t() => {\n\t\t\tstart()\n\t\t},\n\t)\n\n\tstart()\n\n\treturn () => {\n\t\tfor (const [, unsub] of atomSubscriptions) unsub()\n\t\tatomSubscriptions.clear()\n\t\tunsubFromSelector()\n\t}\n}\n","import type * as AtomIO from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport type { Socket } from \"atom.io/realtime\"\n\nimport { pullSelectorRoots } from \"./pull-selector-roots\"\n\nexport function pullSelector<T>(\n\tstore: Store,\n\tsocket: Socket,\n\ttoken: AtomIO.SelectorToken<T>,\n): () => void {\n\treturn pullSelectorRoots(store, socket, token)\n}\n","import type * as AtomIO from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { findInStore } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport type { Socket } from \"atom.io/realtime\"\n\nimport { pullSelectorRoots } from \"./pull-selector-roots\"\n\nexport function pullSelectorFamilyMember<T, K extends Canonical>(\n\tstore: Store,\n\tsocket: Socket,\n\tfamilyToken: AtomIO.SelectorFamilyToken<T, K>,\n\tkey: NoInfer<K>,\n): () => void {\n\tconst token = findInStore(store, familyToken, key)\n\treturn pullSelectorRoots(store, socket, token)\n}\n","import type { WritableToken } from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { setIntoStore, subscribeToState } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { Socket } from \"atom.io/realtime\"\nimport { employSocket, mutexAtoms } from \"atom.io/realtime\"\n\nimport { createSubscriber } from \"./create-subscriber\"\n\nexport function pushState<J extends Json.Serializable>(\n\tstore: Store,\n\tsocket: Socket,\n\ttoken: WritableToken<J>,\n): () => void {\n\treturn createSubscriber(socket, `push:${token.key}`, () => {\n\t\tlet stopWatching = employSocket(\n\t\t\tsocket,\n\t\t\t`claim-result:${token.key}`,\n\t\t\t(success: boolean) => {\n\t\t\t\tif (!success) return\n\t\t\t\tstopWatching()\n\t\t\t\tsetIntoStore(store, mutexAtoms, token.key, true)\n\t\t\t\tstopWatching = subscribeToState(store, token, `push`, ({ newValue }) => {\n\t\t\t\t\tsocket.emit(`pub:${token.key}`, newValue)\n\t\t\t\t})\n\t\t\t},\n\t\t)\n\n\t\tsocket.emit(`claim:${token.key}`)\n\n\t\treturn () => {\n\t\t\tsocket.emit(`unclaim:${token.key}`)\n\t\t\tstopWatching()\n\t\t}\n\t})\n}\n","import type { RootStore } from \"atom.io/internal\"\nimport {\n\tassignTransactionToContinuity,\n\tgetFromStore,\n\tgetJsonToken,\n\tsetEpochNumberOfContinuity,\n\tsetIntoStore,\n\tsubscribeToTransaction,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { ContinuityToken, Socket } from \"atom.io/realtime\"\n\nimport { useRegisterAndAttemptConfirmedUpdate } from \"./continuity/register-and-attempt-confirmed-update\"\nimport { useConcealState } from \"./continuity/use-conceal-state\"\nimport { useRevealState } from \"./continuity/use-reveal-state\"\nimport {\n\tconfirmedUpdateQueueAtom,\n\toptimisticUpdateQueueAtom,\n} from \"./realtime-client-stores\"\n\nexport function syncContinuity(\n\tstore: RootStore,\n\tsocket: Socket,\n\tcontinuity: ContinuityToken,\n): () => void {\n\tconst continuityKey = continuity.key\n\tconst optimisticUpdates = getFromStore(store, optimisticUpdateQueueAtom)\n\tconst confirmedUpdates = getFromStore(store, confirmedUpdateQueueAtom)\n\n\tconst initializeContinuity = (epoch: number, payload: Json.Array) => {\n\t\tsocket.off(`continuity-init:${continuityKey}`, initializeContinuity)\n\t\tlet i = 0\n\t\tlet k: any\n\t\tlet v: any\n\t\tfor (const x of payload) {\n\t\t\tif (i % 2 === 0) {\n\t\t\t\tk = x\n\t\t\t} else {\n\t\t\t\tv = x\n\t\t\t\tif (`type` in k && k.type === `mutable_atom`) {\n\t\t\t\t\tk = getJsonToken(store, k)\n\t\t\t\t}\n\t\t\t\tsetIntoStore(store, k, v)\n\t\t\t}\n\t\t\ti++\n\t\t}\n\t\tsetEpochNumberOfContinuity(store, continuityKey, epoch)\n\t}\n\tsocket.off(`continuity-init:${continuityKey}`)\n\tsocket.on(`continuity-init:${continuityKey}`, initializeContinuity)\n\n\tconst registerAndAttemptConfirmedUpdate = useRegisterAndAttemptConfirmedUpdate(\n\t\tstore,\n\t\tcontinuityKey,\n\t\tsocket,\n\t\toptimisticUpdates,\n\t\tconfirmedUpdates,\n\t)\n\tsocket.off(`tx-new:${continuityKey}`)\n\tsocket.on(`tx-new:${continuityKey}`, registerAndAttemptConfirmedUpdate)\n\n\tconst unsubscribeFunctions = continuity.actions.map((transaction) => {\n\t\tassignTransactionToContinuity(store, continuityKey, transaction.key)\n\t\tconst unsubscribeFromTransactionUpdates = subscribeToTransaction(\n\t\t\tstore,\n\t\t\ttransaction,\n\t\t\t`tx-run:${continuityKey}`,\n\t\t\t(clientUpdate) => {\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`🤞`,\n\t\t\t\t\t`continuity`,\n\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t`enqueuing optimistic update`,\n\t\t\t\t)\n\t\t\t\tconst optimisticUpdateIndex = optimisticUpdates.findIndex(\n\t\t\t\t\t(update) => update.id === clientUpdate.id,\n\t\t\t\t)\n\t\t\t\tif (optimisticUpdateIndex === -1) {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`🤞`,\n\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t`enqueuing new optimistic update`,\n\t\t\t\t\t)\n\t\t\t\t\tsetIntoStore(store, optimisticUpdateQueueAtom, (queue) => {\n\t\t\t\t\t\tqueue.push(clientUpdate)\n\t\t\t\t\t\tqueue.sort((a, b) => a.epoch - b.epoch)\n\t\t\t\t\t\treturn queue\n\t\t\t\t\t})\n\t\t\t\t} else {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`🤞`,\n\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t`replacing existing optimistic update at index ${optimisticUpdateIndex}`,\n\t\t\t\t\t)\n\t\t\t\t\tsetIntoStore(store, optimisticUpdateQueueAtom, (queue) => {\n\t\t\t\t\t\tqueue[optimisticUpdateIndex] = clientUpdate\n\t\t\t\t\t\treturn queue\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tsocket.emit(`tx-run:${continuityKey}`, {\n\t\t\t\t\tid: clientUpdate.id,\n\t\t\t\t\ttoken: transaction,\n\t\t\t\t\tparams: clientUpdate.params,\n\t\t\t\t})\n\t\t\t},\n\t\t)\n\t\treturn unsubscribeFromTransactionUpdates\n\t})\n\n\tconst revealState = useRevealState(store)\n\tconst concealState = useConcealState(store)\n\tsocket.on(`reveal:${continuityKey}`, revealState)\n\tsocket.on(`conceal:${continuityKey}`, concealState)\n\n\tsocket.emit(`get:${continuityKey}`)\n\treturn () => {\n\t\tsocket.off(`continuity-init:${continuityKey}`)\n\t\tsocket.off(`tx-new:${continuityKey}`)\n\t\tfor (const unsubscribe of unsubscribeFunctions) unsubscribe()\n\t\t// socket.emit(`unsub:${continuityKey}`)\n\t}\n}\n"],"mappings":";;;;;;;AAKA,MAAaA,kBAA2D,KAAK;CAC5E,KAAK;CACL,SAAS;CACT,CAAC;AAEF,MAAaC,gBAAkD,KAAK;CACnE,KAAK;CACL,SAAS;CACT,SAAS,EACP,YAAY;AACZ,MAAI,OAAO,WAAW,YACrB,CAAK,OAAO,eAAe,MAAM,EAAE,kBAAkB;AACpD,eAAY,WAAW,cAAc,MAAM,YAAY,CAAC,QAAQ;IAC/D;GAGJ;CACD,CAAC;AAEF,MAAaC,oBACZ,SAAS;CACR,KAAK;CACL,MAAM,EAAE,UAAU;AACjB,MACC,aAAa,cACb,SAAS,WACT,uBAAuB,QAAQ,IAG/B,QAAO,QAAQ,IAAI;EAEpB,MAAM,YAAY,IAAI,cAAc;AACpC,MAAI,CAAC,UAAW,QAAO;EACvB,MAAM,GAAG,qBAAqB,qBAAqB,cAAc,QAAQ;EACzE,MAAM,WAAW,IAAI,mBAAmB,UAAU;AAClD,OAAK,MAAM,WAAW,SAAU,QAAO;AACvC,SAAO;;CAER,CAAC;;;;ACzCH,MAAaC,4BAET,OAAO,KAA4C;CACtD,KAAK;CACL,eAAe,EAAE;CACjB,CAAC;AAEF,MAAaC,2BAET,OAAO,KAA4C;CACtD,KAAK;CACL,eAAe,EAAE;CACjB,CAAC;;;;ACGF,MAAa,wCAEX,OACA,eACA,QACA,mBAGA,sBAKA,cAEU;CACV,SAAS,eACR,kBAGA,iBAGO;AACP,QAAM,OAAO,KACZ,SACA,cACA,eACA,sBACA;AACD,eAAa,OAAO,4BAA4B,UAAU;AACzD,SAAM,OAAO;AACb,UAAO;IACN;AACF,MAAI,iBAAiB,OAAO,gBAAgB,IAG3C;OAFqB,KAAK,UAAU,iBAAiB,UAAU,KAC1C,KAAK,UAAU,gBAAgB,UAAU,EAC3B;AAClC,UAAM,OAAO,KACZ,KACA,cACA,eACA,eAAe,iBAAiB,GAAG,kCACnC;AACD,WAAO,KAAK,OAAO,iBAAiB,gBAAgB,MAAM;AAC1D;;QAID,OAAM,OAAO,KACZ,KACA,cACA,eACA,mBAAmB,gBAAgB,MAAM,OAAO,iBAAiB,MAAM,IAAI,GAAG,iBAAiB,GAAG,wBAAwB,gBAAgB,MAAM,IAAI,GAAG,gBAAgB,KACvK;AAEF,QAAM,OAAO,KACZ,SACA,cACA,eACA,wBACA,kBACA,gBACA;EACD,MAAM,4BAA4B,kBAAkB,YAAY;AAChE,OAAK,MAAM,wBAAwB,0BAClC,+BAA8B,OAAO,sBAAsB,WAAW;AAEvE,QAAM,OAAO,KACZ,KACA,cACA,eACA,6BACA,0BACA;AACD,gCAA8B,OAAO,kBAAkB,WAAW;AAClE,QAAM,OAAO,KACZ,KACA,cACA,eACA,kCACA,iBACA;AACD,gCAA8B,OAAO,iBAAiB,WAAW;AACjE,QAAM,OAAO,KACZ,KACA,cACA,eACA,4BACA,gBACA;AACD,SAAO,KAAK,OAAO,iBAAiB,gBAAgB,MAAM;AAE1D,OAAK,MAAM,wBAAwB,mBAAmB;GACrD,MAAM,QAAQ;IACb,MAAM;IACN,KAAK,qBAAqB,MAAM;IAChC;GACD,MAAM,EAAE,IAAI,WAAW;AACvB,gBAAa,OAAO,OAAO,GAAG,CAAC,GAAG,OAAO;;AAE1C,QAAM,OAAO,KACZ,KACA,cACA,eACA,4CACA,kBACA;;AAGF,OAAM,OAAO,KACZ,SACA,cACA,eACA,gCACA;EAAE,iBAAiB;EAAW;EAAkB;EAAmB,CACnE;CACD,MAAM,yBAAyB,kBAAkB;AACjD,KAAI,wBAAwB;AAC3B,QAAM,OAAO,KACZ,SACA,cACA,eACA,sCACA;AACD,MAAI,UAAU,UAAU,uBAAuB,OAAO;AACrD,SAAM,OAAO,KACZ,SACA,cACA,eACA,8BAA8B,UAAU,MAAM,mCAC9C;AACD,kBAAe,wBAAwB,UAAU;AACjD,QAAK,MAAM,iBAAiB,kBAAkB;IAC7C,MAAM,iBAAiB,kBAAkB;AACzC,QAAI,cAAc,UAAU,gBAAgB,MAC3C,gBAAe,gBAAgB,cAAc;QAE7C;;SAGI;AAEN,SAAM,OAAO,KACZ,SACA,cACA,eACA,8BAA8B,UAAU,MAAM,4CAA4C,uBAAuB,QACjH;AAID,OAAI,CAHqC,iBAAiB,MACxD,WAAW,OAAO,UAAU,UAAU,MACvC,EACsC;AACtC,UAAM,OAAO,KACZ,MACA,cACA,eACA,qCACA,UACA;AACD,iBAAa,OAAO,2BAA2B,UAAU;AACxD,WAAM,KAAK,UAAU;AACrB,WAAM,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;AACvC,YAAO;MACN;;;QAGE;AACN,QAAM,OAAO,KACZ,SACA,cACA,eACA,yCACA;EACD,IAAIC;AACJ,oBAAkB,2BAA2B,OAAO,cAAc;AAElE,MAAI,oBAAoB,UAAU,QAAQ,GAAG;AAC5C,SAAM,OAAO,KACZ,KACA,cACA,eACA,uBAAuB,UAAU,MAAM,IAAI,UAAU,MAAM,IAAI,GAAG,UAAU,GAAG,GAC/E;AACD,iCAA8B,OAAO,WAAW,WAAW;AAC3D,UAAO,KAAK,OAAO,iBAAiB,UAAU,MAAM;AACpD,8BAA2B,OAAO,eAAe,UAAU,MAAM;aACvD,oBAAoB,QAAW;AACzC,SAAM,OAAO,KACZ,SACA,cACA,eACA,oBAAoB,UAAU,MAAM,iCACnC,kBAAkB,KAEnB;IACC,aAAa;IACb,aAAa,UAAU;IACvB,CACD;AAID,OAHyC,iBAAiB,MACxD,WAAW,OAAO,UAAU,UAAU,MACvC,CAEA,OAAM,OAAO,KACZ,MACA,cACA,eACA,qBAAqB,UAAU,MAAM,sBACrC;QACK;AACN,UAAM,OAAO,KACZ,MACA,cACA,eACA,6BAA6B,UAAU,MAAM,WAC7C;AACD,iBAAa,OAAO,2BAA2B,UAAU;AACxD,WAAM,KAAK,UAAU;AACrB,WAAM,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;AACvC,YAAO;MACN;;;;;;;;ACzOP,SAAgB,gBAAgB,OAAc;AAC7C,SAAQ,cAAoD;AAC3D,OAAK,MAAM,SAAS,UACnB,aAAY,OAAO,MAAM;;;;;;ACL5B,SAAgB,eAAe,OAAc;AAC5C,SAAQ,aAA+B;EACtC,IAAI,IAAI;EACR,IAAIC;EACJ,IAAIC;AACJ,OAAK,MAAM,KAAK,UAAU;AACzB,OAAI,IAAI,MAAM,EACb,KAAI;QACE;AACN,QAAI;AACJ,iBAAa,OAAO,GAAG,EAAE;;AAE1B;;;;;;;ACVH,MAAMC,gCAAuD,IAAI,SAAS;AAC1E,MAAMC,4BAAiD,IAAI,SAAS;AAEpE,SAAS,UAAU,QAAsC;CACxD,IAAI,SAAS,cAAc,IAAI,OAAO;AACtC,KAAI,WAAW,QAAW;AACzB,2BAAS,IAAI,KAAK;AAClB,gBAAc,IAAI,QAAQ,OAAO;;AAElC,QAAO;;AAGR,SAAgB,iBACf,QACA,KACA,MACa;AAEb,KADsB,UAAU,IAAI,OAAO,KACrB,OAAO,IAAI;AAChC,YAAU,IAAI,QAAQ,OAAO,GAAG;AAChC,gBAAc,OAAO,OAAO;;CAE7B,MAAM,SAAS,UAAU,OAAO;CAChC,IAAI,MAAM,OAAO,IAAI,IAAI;AAEzB,KAAI,KAAK;AACR,MAAI,MAAM,IAAI,IAAI,cAAoB,GAAG,CAAC;AAC1C,MAAI;QACE;AACN,QAAM;GAAE,UAAU;GAAG,OAAO,IAAI,aAAmB,GAAG;GAAE;AACxD,SAAO,IAAI,KAAK,IAAI;EACpB,MAAM,QAAQ,KAAK,IAAI;AACvB,EAAK,IAAI,MAAM,WAAW;AACzB,UAAO;AACP,UAAO,OAAO,IAAI;IACjB;;AAEH,cAAa;AACZ,MAAI;AAEJ,MAAI,IAAI,aAAa,GAAG;GACvB,MAAM,UAAU,IAAI,SAAe,YAAY;AAC9C,eAAW,SAAS,GAAG;KACtB;AACF,OAAI,MAAM,IAAI,QAAQ;;;;;;;AC1CzB,SAAgB,SACf,OACA,QACA,OACa;AACb,QAAO,iBAAiB,QAAQ,MAAM,MAAM,QAAQ;EACnD,MAAM,eAAe,aAAa,QAAQ,SAAS,QAAQ,SAAY;AACtE,gBAAa,OAAO,OAAO,KAAK;IAC/B;AACF,SAAO,KAAK,OAAO,MAAM,MAAM;AAC/B,eAAa;AACZ,UAAO,KAAK,SAAS,MAAM;AAC3B,iBAAc;;GAEd;;;;;ACdH,SAAgB,qBAIf,OACA,QACA,QACA,KACa;CACb,MAAM,QAAQ,YAAY,OAAO,QAAQ,IAAI;AAC7C,QAAO,iBAAiB,QAAQ,MAAM,WAAW;EAChD,MAAM,eAAe,aACpB,QACA,SAAS,MAAM,QACd,SAAY;AACZ,gBAAa,OAAO,OAAO,KAAK;IAEjC;AACD,SAAO,KAAK,OAAO,OAAO,OAAO,IAAI;AACrC,eAAa;AACZ,UAAO,KAAK,SAAS,MAAM,MAAM;AACjC,iBAAc;;GAEd;;;;;ACvBH,SAAgB,gBACf,OACA,QACA,OACa;CACb,MAAM,YAAY,aAAa,OAAO,MAAM;CAC5C,MAAM,cAAc,eAAe,MAAM;AACzC,QAAO,iBAAiB,QAAQ,MAAM,WAAW;EAChD,MAAM,sBAAsB,aAC3B,QACA,QAAQ,MAAM,QACb,SAAoB;AACpB,gBAAa,OAAO,WAAW,KAAK;IAErC;EACD,MAAM,wBAAwB,aAC7B,QACA,QAAQ,MAAM,QACb,SAAwB;AACxB,gBAAa,OAAO,aAAa,KAAK;IAEvC;AACD,SAAO,KAAK,OAAO,MAAM,MAAM;AAC/B,eAAa;AACZ,UAAO,KAAK,SAAS,MAAM,MAAM;AACjC,wBAAqB;AACrB,0BAAuB;;GAEvB;;;;;ACtBH,SAAgB,4BAIf,OACA,QACA,QACA,KACa;CACb,MAAM,QAAQ,YAAY,OAAO,QAAQ,IAAI;CAC7C,MAAM,YAAY,aAAa,OAAO,MAAM;CAC5C,MAAM,eAAe,eAAe,MAAM;AAC1C,QAAO,iBAAiB,QAAQ,MAAM,WAAW;EAChD,MAAM,sBAAsB,aAC3B,QACA,QAAQ,MAAM,QACb,SAAoB;AACpB,gBAAa,OAAO,WAAW,KAAK;IAErC;EACD,MAAM,wBAAwB,aAC7B,QACA,QAAQ,MAAM,QACb,SAAwB;AACxB,gBAAa,OAAO,cAAc,KAAK;IAExC;AACD,SAAO,KAAK,OAAO,OAAO,OAAO,IAAI;AACrC,eAAa;AACZ,UAAO,KAAK,SAAS,MAAM,MAAM;AACjC,wBAAqB;AACrB,0BAAuB;;GAEvB;;;;;ACnCH,SAAgB,kBACf,OACA,QACA,eACa;CACb,MAAM,oCAAoB,IAAI,KAAyB;CAEvD,MAAM,cAAc;EACnB,MAAM,WAAW,MAAM,cAAc,eAAe,cAAc,IAAI;AACtE,MAAI,UAAU;AACb,QAAK,MAAM,CAAC,SAAS,UAAU,kBAC9B,KAAI,CAAC,SAAS,IAAI,QAAQ,EAAE;AAC3B,WAAO;AACP,sBAAkB,OAAO,QAAQ;;AAInC,QAAK,MAAM,WAAW,UAAU;AAC/B,QAAI,kBAAkB,IAAI,QAAQ,CACjC;IAED,MAAMC,SAAO,MAAM,MAAM,IAAI,QAAQ;AACrC,YAAQA,OAAK,MAAb;KACC,KAAK;AACJ,UAAIA,OAAK,QAAQ;OAChB,MAAM,EAAE,QAAQ,qBAAqBA,OAAK;OAC1C,MAAM,SAAS,UAAU,iBAAiB;OAC1C,MAAM,SAAS,iBAAiB,OAAOA,OAAK;AAC5C,yBAAkB,IACjB,SACA,qBAAqB,OAAO,QAAQ,QAAQ,OAAO,CACnD;YAED,mBAAkB,IAAI,SAAS,SAAS,OAAO,QAAQA,OAAK,CAAC;AAE9D;KAED,KAAK;AACJ,UAAIA,OAAK,QAAQ;OAChB,MAAM,EAAE,QAAQ,qBAAqBA,OAAK;OAC1C,MAAM,SAAS,UAAU,iBAAiB;OAC1C,MAAM,SAAS,iBAAiB,OAAOA,OAAK;AAC5C,yBAAkB,IACjB,SACA,4BAA4B,OAAO,QAAQ,QAAQ,OAAO,CAC1D;YAED,mBAAkB,IACjB,SACA,gBAAgB,OAAO,QAAQA,OAAK,CACpC;AAEF;;;;;CAOL,MAAM,oBAAoB,iBACzB,OACA,eACA,mCACM;AACL,SAAO;GAER;AAED,QAAO;AAEP,cAAa;AACZ,OAAK,MAAM,GAAG,UAAU,kBAAmB,QAAO;AAClD,oBAAkB,OAAO;AACzB,qBAAmB;;;;;;AC9ErB,SAAgB,aACf,OACA,QACA,OACa;AACb,QAAO,kBAAkB,OAAO,QAAQ,MAAM;;;;;ACH/C,SAAgB,yBACf,OACA,QACA,aACA,KACa;AAEb,QAAO,kBAAkB,OAAO,QADlB,YAAY,OAAO,aAAa,IAAI,CACJ;;;;;ACN/C,SAAgB,UACf,OACA,QACA,OACa;AACb,QAAO,iBAAiB,QAAQ,QAAQ,MAAM,aAAa;EAC1D,IAAI,eAAe,aAClB,QACA,gBAAgB,MAAM,QACrB,YAAqB;AACrB,OAAI,CAAC,QAAS;AACd,iBAAc;AACd,gBAAa,OAAO,YAAY,MAAM,KAAK,KAAK;AAChD,kBAAe,iBAAiB,OAAO,OAAO,SAAS,EAAE,eAAe;AACvE,WAAO,KAAK,OAAO,MAAM,OAAO,SAAS;KACxC;IAEH;AAED,SAAO,KAAK,SAAS,MAAM,MAAM;AAEjC,eAAa;AACZ,UAAO,KAAK,WAAW,MAAM,MAAM;AACnC,iBAAc;;GAEd;;;;;ACdH,SAAgB,eACf,OACA,QACA,YACa;CACb,MAAM,gBAAgB,WAAW;CACjC,MAAM,oBAAoB,aAAa,OAAO,0BAA0B;CACxE,MAAM,mBAAmB,aAAa,OAAO,yBAAyB;CAEtE,MAAM,wBAAwB,OAAe,YAAwB;AACpE,SAAO,IAAI,mBAAmB,iBAAiB,qBAAqB;EACpE,IAAI,IAAI;EACR,IAAIC;EACJ,IAAIC;AACJ,OAAK,MAAM,KAAK,SAAS;AACxB,OAAI,IAAI,MAAM,EACb,KAAI;QACE;AACN,QAAI;AACJ,QAAI,UAAU,KAAK,EAAE,SAAS,eAC7B,KAAI,aAAa,OAAO,EAAE;AAE3B,iBAAa,OAAO,GAAG,EAAE;;AAE1B;;AAED,6BAA2B,OAAO,eAAe,MAAM;;AAExD,QAAO,IAAI,mBAAmB,gBAAgB;AAC9C,QAAO,GAAG,mBAAmB,iBAAiB,qBAAqB;CAEnE,MAAM,oCAAoC,qCACzC,OACA,eACA,QACA,mBACA,iBACA;AACD,QAAO,IAAI,UAAU,gBAAgB;AACrC,QAAO,GAAG,UAAU,iBAAiB,kCAAkC;CAEvE,MAAM,uBAAuB,WAAW,QAAQ,KAAK,gBAAgB;AACpE,gCAA8B,OAAO,eAAe,YAAY,IAAI;AA8CpE,SA7C0C,uBACzC,OACA,aACA,UAAU,kBACT,iBAAiB;AACjB,SAAM,OAAO,KACZ,MACA,cACA,eACA,8BACA;GACD,MAAM,wBAAwB,kBAAkB,WAC9C,WAAW,OAAO,OAAO,aAAa,GACvC;AACD,OAAI,0BAA0B,IAAI;AACjC,UAAM,OAAO,KACZ,MACA,cACA,eACA,kCACA;AACD,iBAAa,OAAO,4BAA4B,UAAU;AACzD,WAAM,KAAK,aAAa;AACxB,WAAM,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;AACvC,YAAO;MACN;UACI;AACN,UAAM,OAAO,KACZ,MACA,cACA,eACA,iDAAiD,wBACjD;AACD,iBAAa,OAAO,4BAA4B,UAAU;AACzD,WAAM,yBAAyB;AAC/B,YAAO;MACN;;AAEH,UAAO,KAAK,UAAU,iBAAiB;IACtC,IAAI,aAAa;IACjB,OAAO;IACP,QAAQ,aAAa;IACrB,CAAC;IAEH;GAEA;CAEF,MAAM,cAAc,eAAe,MAAM;CACzC,MAAM,eAAe,gBAAgB,MAAM;AAC3C,QAAO,GAAG,UAAU,iBAAiB,YAAY;AACjD,QAAO,GAAG,WAAW,iBAAiB,aAAa;AAEnD,QAAO,KAAK,OAAO,gBAAgB;AACnC,cAAa;AACZ,SAAO,IAAI,mBAAmB,gBAAgB;AAC9C,SAAO,IAAI,UAAU,gBAAgB;AACrC,OAAK,MAAM,eAAe,qBAAsB,cAAa"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atom.io",
|
|
3
|
-
"version": "0.46.
|
|
3
|
+
"version": "0.46.13",
|
|
4
4
|
"description": "Composable and testable reactive data library.",
|
|
5
5
|
"homepage": "https://atom.io.fyi",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -60,9 +60,9 @@
|
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@storybook/addon-docs": "10.1.
|
|
64
|
-
"@storybook/addon-onboarding": "10.1.
|
|
65
|
-
"@storybook/react-vite": "10.1.
|
|
63
|
+
"@storybook/addon-docs": "10.1.11",
|
|
64
|
+
"@storybook/addon-onboarding": "10.1.11",
|
|
65
|
+
"@storybook/react-vite": "10.1.11",
|
|
66
66
|
"@testing-library/react": "16.3.1",
|
|
67
67
|
"@types/eslint": "9.6.1",
|
|
68
68
|
"@types/estree": "1.0.8",
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
"@types/node": "25.0.3",
|
|
71
71
|
"@types/react": "19.2.7",
|
|
72
72
|
"@types/tmp": "0.2.6",
|
|
73
|
-
"@typescript-eslint/parser": "8.
|
|
74
|
-
"@typescript-eslint/rule-tester": "8.
|
|
75
|
-
"@typescript-eslint/utils": "8.
|
|
76
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
73
|
+
"@typescript-eslint/parser": "8.51.0",
|
|
74
|
+
"@typescript-eslint/rule-tester": "8.51.0",
|
|
75
|
+
"@typescript-eslint/utils": "8.51.0",
|
|
76
|
+
"@typescript/native-preview": "7.0.0-dev.20251230.1",
|
|
77
77
|
"@vitest/coverage-v8": "4.0.16",
|
|
78
78
|
"@vitest/ui": "4.0.16",
|
|
79
79
|
"arktype": "2.1.29",
|
|
@@ -92,9 +92,9 @@
|
|
|
92
92
|
"recoverage": "0.1.13",
|
|
93
93
|
"socket.io": "4.8.3",
|
|
94
94
|
"socket.io-client": "4.8.3",
|
|
95
|
-
"storybook": "10.1.
|
|
95
|
+
"storybook": "10.1.11",
|
|
96
96
|
"tmp": "0.2.5",
|
|
97
|
-
"tsdown": "0.18.
|
|
97
|
+
"tsdown": "0.18.4",
|
|
98
98
|
"vite": "7.3.0",
|
|
99
99
|
"vite-tsconfig-paths": "6.0.3",
|
|
100
100
|
"vitest": "4.0.16",
|
|
@@ -192,7 +192,7 @@ export const exactCatchTypes: ESLintUtils.RuleModule<
|
|
|
192
192
|
|
|
193
193
|
// Iterate over each constructor reference in the 'catch' array
|
|
194
194
|
for (const element of catchArray.elements) {
|
|
195
|
-
if (
|
|
195
|
+
if (element?.type !== AST_NODE_TYPES.Identifier) {
|
|
196
196
|
// Only check simple identifier references (e.g., [ClientError])
|
|
197
197
|
continue
|
|
198
198
|
}
|
|
@@ -44,6 +44,13 @@ export const StateIndexLeafNode: FC<{
|
|
|
44
44
|
|
|
45
45
|
const path = node.family ? [node.family.key, node.family.subKey] : [node.key]
|
|
46
46
|
|
|
47
|
+
let stringified: string
|
|
48
|
+
try {
|
|
49
|
+
stringified = JSON.stringify(state)
|
|
50
|
+
} catch (_) {
|
|
51
|
+
stringified = `?`
|
|
52
|
+
}
|
|
53
|
+
|
|
47
54
|
return (
|
|
48
55
|
<>
|
|
49
56
|
<header>
|
|
@@ -72,7 +79,7 @@ export const StateIndexLeafNode: FC<{
|
|
|
72
79
|
{isPrimitive ? (
|
|
73
80
|
<StoreEditor token={node} />
|
|
74
81
|
) : (
|
|
75
|
-
<div className="json_viewer">{
|
|
82
|
+
<div className="json_viewer">{stringified}</div>
|
|
76
83
|
)}
|
|
77
84
|
{dispose ? (
|
|
78
85
|
<DEFAULT_JSON_EDITOR_COMPONENTS.Button
|
|
@@ -5,18 +5,25 @@ export const NonJsonEditor: React.FC<JsonEditorProps<never>> = ({
|
|
|
5
5
|
data,
|
|
6
6
|
testid,
|
|
7
7
|
}) => {
|
|
8
|
-
|
|
8
|
+
if (data === undefined) {
|
|
9
|
+
return (
|
|
10
|
+
<ElasticInput
|
|
11
|
+
disabled
|
|
12
|
+
value="undefined"
|
|
13
|
+
data-testid={`${testid}-undefined`}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
let stringified: string
|
|
18
|
+
try {
|
|
19
|
+
stringified = JSON.stringify(data)
|
|
20
|
+
} catch (_) {
|
|
21
|
+
stringified = `?`
|
|
22
|
+
}
|
|
23
|
+
return (
|
|
9
24
|
<ElasticInput
|
|
10
25
|
disabled
|
|
11
|
-
value=
|
|
12
|
-
data-testid={`${testid}-undefined`}
|
|
13
|
-
/>
|
|
14
|
-
) : (
|
|
15
|
-
<ElasticInput
|
|
16
|
-
disabled
|
|
17
|
-
value={
|
|
18
|
-
Object.getPrototypeOf(data).constructor.name + ` ` + JSON.stringify(data)
|
|
19
|
-
}
|
|
26
|
+
value={Object.getPrototypeOf(data).constructor.name + ` ` + stringified}
|
|
20
27
|
data-testid={`${testid}-non-json-${Object.getPrototypeOf(data).constructor.name}`}
|
|
21
28
|
/>
|
|
22
29
|
)
|
|
@@ -69,6 +69,13 @@ export const JsonEditor_INTERNAL = <T,>({
|
|
|
69
69
|
const dataIsTree = refined.type === `array` || refined.type === `object`
|
|
70
70
|
const dataIsExpandable = dataIsTree && isOpen !== undefined && setIsOpen
|
|
71
71
|
|
|
72
|
+
let stringified: string
|
|
73
|
+
try {
|
|
74
|
+
stringified = JSON.stringify(data)
|
|
75
|
+
} catch (_) {
|
|
76
|
+
stringified = `?`
|
|
77
|
+
}
|
|
78
|
+
|
|
72
79
|
return isHidden(path) ? null : (
|
|
73
80
|
<Components.ErrorBoundary>
|
|
74
81
|
<Components.EditorWrapper
|
|
@@ -105,7 +112,7 @@ export const JsonEditor_INTERNAL = <T,>({
|
|
|
105
112
|
{dataIsTree ? (
|
|
106
113
|
<>
|
|
107
114
|
{isOpen !== undefined && setIsOpen ? (
|
|
108
|
-
<span className="json_viewer">{
|
|
115
|
+
<span className="json_viewer">{stringified}</span>
|
|
109
116
|
) : null}
|
|
110
117
|
{recast ? (
|
|
111
118
|
<select
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Future } from "atom.io/internal"
|
|
2
2
|
import type { Socket } from "atom.io/realtime"
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
type SubData = { refcount: number; timer: Future<void> }
|
|
5
|
+
|
|
6
|
+
const subscriptions: WeakMap<Socket, Map<string, SubData>> = new WeakMap()
|
|
5
7
|
const socketIds: WeakMap<Socket, string | undefined> = new WeakMap()
|
|
6
8
|
|
|
7
|
-
function getSubMap(socket: Socket): Map<string,
|
|
9
|
+
function getSubMap(socket: Socket): Map<string, SubData> {
|
|
8
10
|
let subMap = subscriptions.get(socket)
|
|
9
11
|
if (subMap === undefined) {
|
|
10
12
|
subMap = new Map()
|
|
@@ -23,23 +25,29 @@ export function createSubscriber<K extends string>(
|
|
|
23
25
|
socketIds.set(socket, socket.id)
|
|
24
26
|
subscriptions.delete(socket)
|
|
25
27
|
}
|
|
26
|
-
const
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const subMap = getSubMap(socket)
|
|
29
|
+
let sub = subMap.get(key)
|
|
30
|
+
|
|
31
|
+
if (sub) {
|
|
32
|
+
sub.timer.use(new Promise<void>(() => {}))
|
|
33
|
+
sub.refcount++
|
|
30
34
|
} else {
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
sub = { refcount: 1, timer: new Future<void>(() => {}) }
|
|
36
|
+
subMap.set(key, sub)
|
|
33
37
|
const close = open(key)
|
|
34
|
-
void timer.then(() => {
|
|
38
|
+
void sub.timer.then(() => {
|
|
35
39
|
close()
|
|
36
|
-
|
|
40
|
+
subMap.delete(key)
|
|
37
41
|
})
|
|
38
42
|
}
|
|
39
43
|
return () => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
sub.refcount--
|
|
45
|
+
|
|
46
|
+
if (sub.refcount === 0) {
|
|
47
|
+
const timeout = new Promise<void>((resolve) => {
|
|
48
|
+
setTimeout(resolve, 50)
|
|
49
|
+
})
|
|
50
|
+
sub.timer.use(timeout)
|
|
51
|
+
}
|
|
44
52
|
}
|
|
45
53
|
}
|