atom.io 0.45.5 → 0.46.1

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.
Files changed (31) hide show
  1. package/dist/internal/index.js +2 -7
  2. package/dist/internal/index.js.map +1 -1
  3. package/dist/react-devtools/index.d.ts.map +1 -1
  4. package/dist/realtime/index.d.ts +6 -3
  5. package/dist/realtime/index.d.ts.map +1 -1
  6. package/dist/realtime/index.js +9 -1
  7. package/dist/realtime/index.js.map +1 -1
  8. package/dist/realtime-server/index.d.ts +73 -50
  9. package/dist/realtime-server/index.d.ts.map +1 -1
  10. package/dist/realtime-server/index.js +222 -182
  11. package/dist/realtime-server/index.js.map +1 -1
  12. package/dist/realtime-testing/index.d.ts +1 -2
  13. package/dist/realtime-testing/index.d.ts.map +1 -1
  14. package/dist/realtime-testing/index.js +31 -53
  15. package/dist/realtime-testing/index.js.map +1 -1
  16. package/package.json +10 -10
  17. package/src/internal/subscribe/subscribe-to-state.ts +9 -18
  18. package/src/realtime/cast-socket.ts +1 -0
  19. package/src/realtime/shared-room-store.ts +15 -0
  20. package/src/realtime/socket-interface.ts +5 -1
  21. package/src/realtime-server/index.ts +3 -2
  22. package/src/realtime-server/ipc-sockets/custom-socket.ts +18 -2
  23. package/src/realtime-server/ipc-sockets/parent-socket.ts +1 -1
  24. package/src/realtime-server/{realtime-server-stores/provide-rooms.ts → provide-rooms.ts} +32 -57
  25. package/src/realtime-server/realtime-state-provider.ts +5 -3
  26. package/src/realtime-server/realtime-state-receiver.ts +19 -3
  27. package/src/realtime-server/server-config.ts +112 -1
  28. package/src/realtime-server/{realtime-server-stores/server-user-store.ts → server-socket-state.ts} +1 -8
  29. package/src/realtime-testing/setup-realtime-test.tsx +38 -83
  30. package/src/realtime-server/realtime-server-stores/index.ts +0 -3
  31. package/src/realtime-server/realtime-server-stores/provide-identity.ts +0 -18
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["redactorAtoms: RegularAtomFamilyToken<\n\t{\n\t\tocclude: (updates: TransactionSubEvent[]) => TransactionSubEvent[]\n\t},\n\tUserKey\n>","unacknowledgedUpdatesAtoms: RegularAtomFamilyToken<\n\tContinuitySyncTransactionUpdate[],\n\tUserKey\n>","initialPayload: Json.Serializable[]","isAvailable","socketAtoms: RegularAtomFamilyToken<Socket | null, SocketKey>","socketKeysAtom: MutableAtomToken<UList<SocketKey>>","userKeysAtom: MutableAtomToken<UList<UserKey>>","usersOfSockets: JoinToken<\n\t`user`,\n\tUserKey,\n\t`socket`,\n\tSocketKey,\n\t`1:1`\n>","selfListSelectors: PureSelectorFamilyToken<UserKey[], UserKey>","ROOMS: RoomMap","roomMeta: { count: number }","roomQueue: [string, ...Json.Array][]","forward: AllEventsListener<EventsMap>","roomKeySchema: StandardSchemaV1<Json.Array, [RoomKey]>"],"sources":["../../src/realtime-server/continuity/continuity-store.ts","../../src/realtime-server/continuity/provide-outcomes.ts","../../src/realtime-server/continuity/provide-perspectives.ts","../../src/realtime-server/continuity/provide-startup-payloads.ts","../../src/realtime-server/continuity/receive-action-requests.ts","../../src/realtime-server/continuity/track-acknowledgements.ts","../../src/realtime-server/continuity/provide-continuity.ts","../../src/realtime-server/ipc-sockets/custom-socket.ts","../../src/realtime-server/ipc-sockets/child-socket.ts","../../src/realtime-server/ipc-sockets/parent-socket.ts","../../src/realtime-server/realtime-family-provider.ts","../../src/realtime-server/realtime-mutable-family-provider.ts","../../src/realtime-server/realtime-mutable-provider.ts","../../src/realtime-server/realtime-state-provider.ts","../../src/realtime-server/realtime-server-stores/provide-identity.ts","../../src/realtime-server/realtime-server-stores/server-user-store.ts","../../src/realtime-server/realtime-server-stores/provide-rooms.ts","../../src/realtime-server/realtime-state-receiver.ts"],"sourcesContent":["import type {\n\tRegularAtomFamilyToken,\n\tTransactionOutcomeEvent,\n\tTransactionSubEvent,\n} from \"atom.io\"\nimport { atomFamily } from \"atom.io\"\nimport type { UserKey } from \"atom.io/realtime\"\n\nexport function redactTransactionUpdateContent(\n\tvisibleStateKeys: string[],\n\tupdates: TransactionSubEvent[],\n): TransactionSubEvent[] {\n\treturn updates\n\t\t.map((update): TransactionSubEvent => {\n\t\t\tswitch (update.type) {\n\t\t\t\tcase `transaction_outcome`: {\n\t\t\t\t\tconst redacted = redactTransactionUpdateContent(\n\t\t\t\t\t\tvisibleStateKeys,\n\t\t\t\t\t\tupdate.subEvents,\n\t\t\t\t\t)\n\t\t\t\t\treturn { ...update, subEvents: redacted }\n\t\t\t\t}\n\t\t\t\tcase `atom_update`:\n\t\t\t\tcase `molecule_creation`:\n\t\t\t\tcase `molecule_disposal`:\n\t\t\t\tcase `molecule_transfer`:\n\t\t\t\tcase `state_creation`:\n\t\t\t\tcase `state_disposal`:\n\t\t\t\t\treturn update\n\t\t\t}\n\t\t})\n\t\t.filter((update) => {\n\t\t\tswitch (update.type) {\n\t\t\t\tcase `atom_update`:\n\t\t\t\tcase `state_creation`:\n\t\t\t\tcase `state_disposal`:\n\t\t\t\t\treturn visibleStateKeys.includes(update.token.key)\n\t\t\t\tcase `molecule_creation`:\n\t\t\t\tcase `transaction_outcome`:\n\t\t\t\tcase `molecule_disposal`:\n\t\t\t\tcase `molecule_transfer`:\n\t\t\t\t\treturn true\n\t\t\t}\n\t\t})\n}\n\nexport const redactorAtoms: RegularAtomFamilyToken<\n\t{\n\t\tocclude: (updates: TransactionSubEvent[]) => TransactionSubEvent[]\n\t},\n\tUserKey\n> = atomFamily({\n\tkey: `redactor`,\n\tdefault: { occlude: (updates) => updates },\n})\n\nexport type ContinuitySyncTransactionUpdate = Pick<\n\tTransactionOutcomeEvent<any>,\n\t`epoch` | `id` | `output` | `subEvents` | `token`\n>\nexport const unacknowledgedUpdatesAtoms: RegularAtomFamilyToken<\n\tContinuitySyncTransactionUpdate[],\n\tUserKey\n> = atomFamily({\n\tkey: `unacknowledgedUpdates`,\n\tdefault: () => [],\n})\n","import type { Store } from \"atom.io/internal\"\nimport {\n\tfindInStore,\n\tgetFromStore,\n\tgetUpdateToken,\n\tsetIntoStore,\n\tsubscribeToTransaction,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { ContinuityToken, Socket, UserKey } from \"atom.io/realtime\"\n\nimport {\n\tredactTransactionUpdateContent,\n\tunacknowledgedUpdatesAtoms,\n} from \"./continuity-store\"\n\nexport function provideOutcomes(\n\tstore: Store,\n\tsocket: Socket,\n\tcontinuity: ContinuityToken,\n\tuserKey: UserKey,\n): () => void {\n\tconst continuityKey = continuity.key\n\tconst unsubscribeFunctions = new Set<() => void>()\n\n\tfor (const transaction of continuity.actions) {\n\t\tconst unsubscribeFromTransaction = subscribeToTransaction(\n\t\t\tstore,\n\t\t\ttransaction,\n\t\t\t`sync-continuity:${continuityKey}:${userKey}`,\n\t\t\t(outcomes) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst visibleKeys = continuity.globals\n\t\t\t\t\t\t.map((atom) => {\n\t\t\t\t\t\t\tif (atom.type === `atom`) {\n\t\t\t\t\t\t\t\treturn atom.key\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn getUpdateToken(atom).key\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.concat(\n\t\t\t\t\t\t\tcontinuity.perspectives.flatMap((perspective) => {\n\t\t\t\t\t\t\t\tconst { viewAtoms } = perspective\n\t\t\t\t\t\t\t\tconst userPerspectiveTokenState = findInStore(\n\t\t\t\t\t\t\t\t\tstore,\n\t\t\t\t\t\t\t\t\tviewAtoms,\n\t\t\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tconst visibleTokens = getFromStore(\n\t\t\t\t\t\t\t\t\tstore,\n\t\t\t\t\t\t\t\t\tuserPerspectiveTokenState,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\treturn visibleTokens.map((token) => {\n\t\t\t\t\t\t\t\t\tconst key =\n\t\t\t\t\t\t\t\t\t\ttoken.type === `mutable_atom` ? `*` + token.key : token.key\n\t\t\t\t\t\t\t\t\treturn key\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\tconst redactedUpdates = redactTransactionUpdateContent(\n\t\t\t\t\t\tvisibleKeys,\n\t\t\t\t\t\toutcomes.subEvents,\n\t\t\t\t\t)\n\t\t\t\t\tconst redactedUpdate = {\n\t\t\t\t\t\t...outcomes,\n\t\t\t\t\t\tupdates: redactedUpdates,\n\t\t\t\t\t}\n\t\t\t\t\tsetIntoStore(store, unacknowledgedUpdatesAtoms, userKey, (updates) => {\n\t\t\t\t\t\tif (redactedUpdate) {\n\t\t\t\t\t\t\tupdates.push(redactedUpdate)\n\t\t\t\t\t\t\tupdates.sort((a, b) => a.epoch - b.epoch)\n\t\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t\t`👍`,\n\t\t\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t\t\t`${userKey} unacknowledged update queue now has`,\n\t\t\t\t\t\t\t\tupdates.length,\n\t\t\t\t\t\t\t\t`items`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn updates\n\t\t\t\t\t})\n\n\t\t\t\t\tsocket.emit(\n\t\t\t\t\t\t`tx-new:${continuityKey}`,\n\t\t\t\t\t\tredactedUpdate as Json.Serializable,\n\t\t\t\t\t)\n\t\t\t\t} catch (thrown) {\n\t\t\t\t\tif (thrown instanceof Error) {\n\t\t\t\t\t\tstore.logger.error(\n\t\t\t\t\t\t\t`❌`,\n\t\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t\t`${userKey} failed to send update from transaction ${transaction.key} to ${userKey}`,\n\t\t\t\t\t\t\tthrown.message,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\t\tunsubscribeFunctions.add(unsubscribeFromTransaction)\n\t}\n\treturn () => {\n\t\tfor (const unsubscribe of unsubscribeFunctions) unsubscribe()\n\t}\n}\n","import type { Store } from \"atom.io/internal\"\nimport {\n\tfindInStore,\n\tgetFromStore,\n\tgetJsonToken,\n\tsubscribeToState,\n} from \"atom.io/internal\"\nimport type { ContinuityToken, Socket, UserKey } from \"atom.io/realtime\"\n\nexport function providePerspectives(\n\tstore: Store,\n\tsocket: Socket,\n\tcontinuity: ContinuityToken,\n\tuserKey: UserKey,\n): () => void {\n\tconst continuityKey = continuity.key\n\tconst unsubFns = new Set<() => void>()\n\tfor (const perspective of continuity.perspectives) {\n\t\tconst { viewAtoms } = perspective\n\t\tconst userViewState = findInStore(store, viewAtoms, userKey)\n\t\tconst unsubscribeFromUserView = subscribeToState(\n\t\t\tstore,\n\t\t\tuserViewState,\n\t\t\t`sync-continuity:${continuityKey}:${userKey}:perspective:${perspective.resourceAtoms.key}`,\n\t\t\t({ oldValue, newValue }) => {\n\t\t\t\tconst oldKeys = oldValue?.map((token) => token.key)\n\t\t\t\tconst newKeys = newValue.map((token) => token.key)\n\t\t\t\tconst concealed = oldValue?.filter(\n\t\t\t\t\t(token) => !newKeys.includes(token.key),\n\t\t\t\t)\n\t\t\t\tconst revealed = newValue\n\t\t\t\t\t.filter((token) => !oldKeys?.includes(token.key))\n\t\t\t\t\t.flatMap((token) => {\n\t\t\t\t\t\tconst resourceToken =\n\t\t\t\t\t\t\ttoken.type === `mutable_atom` ? getJsonToken(store, token) : token\n\t\t\t\t\t\tconst resource = getFromStore(store, resourceToken)\n\t\t\t\t\t\treturn [resourceToken, resource]\n\t\t\t\t\t})\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`👁`,\n\t\t\t\t\t`atom`,\n\t\t\t\t\tperspective.resourceAtoms.key,\n\t\t\t\t\t`${userKey} has a new perspective`,\n\t\t\t\t\t{ oldKeys, newKeys, revealed, concealed },\n\t\t\t\t)\n\t\t\t\tif (revealed.length > 0) {\n\t\t\t\t\tsocket.emit(`reveal:${continuityKey}`, revealed)\n\t\t\t\t}\n\t\t\t\tif (concealed && concealed.length > 0) {\n\t\t\t\t\tsocket.emit(`conceal:${continuityKey}`, concealed)\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\t\tunsubFns.add(unsubscribeFromUserView)\n\t}\n\treturn () => {\n\t\tfor (const unsubscribe of unsubFns) unsubscribe()\n\t}\n}\n","import type { Store } from \"atom.io/internal\"\nimport {\n\tfindInStore,\n\tgetFromStore,\n\tgetJsonToken,\n\tisRootStore,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { ContinuityToken, Socket, UserKey } from \"atom.io/realtime\"\nimport { employSocket } from \"atom.io/realtime\"\n\nexport function provideStartupPayloads(\n\tstore: Store,\n\tsocket: Socket,\n\tcontinuity: ContinuityToken,\n\tuserKey: UserKey,\n): () => void {\n\tconst continuityKey = continuity.key\n\tfunction sendInitialPayload(): void {\n\t\tconst initialPayload: Json.Serializable[] = []\n\t\tfor (const atom of continuity.globals) {\n\t\t\tconst resourceToken =\n\t\t\t\tatom.type === `mutable_atom` ? getJsonToken(store, atom) : atom\n\t\t\tconst resource = getFromStore(store, resourceToken)\n\t\t\tinitialPayload.push(resourceToken, resource)\n\t\t}\n\t\tfor (const perspective of continuity.perspectives) {\n\t\t\tconst { viewAtoms, resourceAtoms } = perspective\n\t\t\tconst userViewState = findInStore(store, viewAtoms, userKey)\n\t\t\tconst userView = getFromStore(store, userViewState)\n\t\t\tstore.logger.info(`👁`, `atom`, resourceAtoms.key, `${userKey} can see`, {\n\t\t\t\tviewAtoms,\n\t\t\t\tresourceAtoms,\n\t\t\t\tuserView,\n\t\t\t})\n\t\t\tfor (const visibleToken of userView) {\n\t\t\t\tconst resourceToken =\n\t\t\t\t\tvisibleToken.type === `mutable_atom`\n\t\t\t\t\t\t? getJsonToken(store, visibleToken)\n\t\t\t\t\t\t: visibleToken\n\t\t\t\tconst resource = getFromStore(store, resourceToken)\n\n\t\t\t\tinitialPayload.push(resourceToken, resource)\n\t\t\t}\n\t\t}\n\n\t\tconst epoch = isRootStore(store)\n\t\t\t? (store.transactionMeta.epoch.get(continuityKey) ?? null)\n\t\t\t: null\n\n\t\tsocket.emit(`continuity-init:${continuityKey}`, epoch, initialPayload)\n\t}\n\treturn employSocket(socket, `get:${continuityKey}`, sendInitialPayload)\n}\n","import type { TransactionOutcomeEvent, TransactionToken } from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { actUponStore } from \"atom.io/internal\"\nimport type { Json, JsonIO } from \"atom.io/json\"\nimport type { ContinuityToken, Socket } from \"atom.io/realtime\"\nimport { employSocket } from \"atom.io/realtime\"\n\nexport function receiveActionRequests(\n\tstore: Store,\n\tsocket: Socket,\n\tcontinuity: ContinuityToken,\n\tuserKey: string,\n): () => void {\n\tconst continuityKey = continuity.key\n\n\treturn employSocket(\n\t\tsocket,\n\t\t`tx-run:${continuityKey}`,\n\t\tfunction serveTransactionRequest(\n\t\t\ttxOutcome: Json.Serializable &\n\t\t\t\tPick<\n\t\t\t\t\tTransactionOutcomeEvent<TransactionToken<JsonIO>>,\n\t\t\t\t\t`id` | `params` | `token`\n\t\t\t\t>,\n\t\t) {\n\t\t\tstore.logger.info(`🛎️`, `continuity`, continuityKey, `received`, txOutcome)\n\t\t\tconst transactionKey = txOutcome.token.key\n\t\t\tconst updateId = txOutcome.id\n\t\t\tconst performanceKey = `tx-run:${transactionKey}:${updateId}`\n\t\t\tconst performanceKeyStart = `${performanceKey}:start`\n\t\t\tconst performanceKeyEnd = `${performanceKey}:end`\n\t\t\tperformance.mark(performanceKeyStart)\n\t\t\ttry {\n\t\t\t\tactUponStore(\n\t\t\t\t\tstore,\n\t\t\t\t\t{ type: `transaction`, key: transactionKey },\n\t\t\t\t\tupdateId,\n\t\t\t\t)(...txOutcome.params)\n\t\t\t} catch (thrown) {\n\t\t\t\tif (thrown instanceof Error) {\n\t\t\t\t\tstore.logger.error(\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`failed to run transaction ${transactionKey} from ${userKey} with update ${updateId}`,\n\t\t\t\t\t\tthrown.message,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t\tperformance.mark(performanceKeyEnd)\n\t\t\tconst metric = performance.measure(\n\t\t\t\tperformanceKey,\n\t\t\t\tperformanceKeyStart,\n\t\t\t\tperformanceKeyEnd,\n\t\t\t)\n\t\t\tstore.logger.info(\n\t\t\t\t`🚀`,\n\t\t\t\t`transaction`,\n\t\t\t\ttransactionKey,\n\t\t\t\tupdateId,\n\t\t\t\tuserKey,\n\t\t\t\tmetric.duration,\n\t\t\t)\n\t\t},\n\t)\n}\n","import type { Store } from \"atom.io/internal\"\nimport { getFromStore, setIntoStore } from \"atom.io/internal\"\nimport type { ContinuityToken, Socket, UserKey } from \"atom.io/realtime\"\nimport { employSocket } from \"atom.io/realtime\"\n\nimport { unacknowledgedUpdatesAtoms } from \"./continuity-store\"\n\nexport function trackAcknowledgements(\n\tstore: Store,\n\tsocket: Socket,\n\tcontinuity: ContinuityToken,\n\tuserKey: UserKey,\n): () => void {\n\tconst continuityKey = continuity.key\n\tconst userUnacknowledgedUpdates = getFromStore(\n\t\tstore,\n\t\tunacknowledgedUpdatesAtoms,\n\t\tuserKey,\n\t)\n\tfunction trackClientAcknowledgement(epoch: number): void {\n\t\tstore.logger.info(\n\t\t\t`👍`,\n\t\t\t`continuity`,\n\t\t\tcontinuityKey,\n\t\t\t`${userKey} acknowledged epoch ${epoch}`,\n\t\t)\n\t\tconst isUnacknowledged = userUnacknowledgedUpdates[0]?.epoch === epoch\n\t\tif (isUnacknowledged) {\n\t\t\tsetIntoStore(store, unacknowledgedUpdatesAtoms, userKey, (updates) => {\n\t\t\t\tupdates.shift()\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`${userKey} unacknowledged update queue now has`,\n\t\t\t\t\tupdates.length,\n\t\t\t\t\t`items`,\n\t\t\t\t)\n\t\t\t\treturn updates\n\t\t\t})\n\t\t}\n\t}\n\treturn employSocket(socket, `ack:${continuityKey}`, trackClientAcknowledgement)\n}\n","import { getFromStore, IMPLICIT } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { ContinuityToken, UserKey } from \"atom.io/realtime\"\n\nimport type { ServerConfig } from \"..\"\nimport { unacknowledgedUpdatesAtoms } from \"./continuity-store\"\nimport { provideOutcomes } from \"./provide-outcomes\"\nimport { providePerspectives } from \"./provide-perspectives\"\nimport { provideStartupPayloads } from \"./provide-startup-payloads\"\nimport { receiveActionRequests } from \"./receive-action-requests\"\nimport { trackAcknowledgements } from \"./track-acknowledgements\"\n\nexport type ProvideContinuity = (\n\tcontinuity: ContinuityToken,\n\tuserKey: UserKey,\n) => () => void\nexport function prepareToProvideContinuity({\n\tsocket,\n\tstore = IMPLICIT.STORE,\n}: ServerConfig): ProvideContinuity {\n\treturn function syncRealtimeContinuity(continuity, userKey) {\n\t\tconst continuityKey = continuity.key\n\n\t\tconst unacknowledgedUpdates = getFromStore(\n\t\t\tstore,\n\t\t\tunacknowledgedUpdatesAtoms,\n\t\t\tuserKey,\n\t\t)\n\t\tfor (const unacknowledgedUpdate of unacknowledgedUpdates) {\n\t\t\tsocket.emit(\n\t\t\t\t`tx-new:${continuityKey}`,\n\t\t\t\tunacknowledgedUpdate as Json.Serializable,\n\t\t\t)\n\t\t}\n\n\t\tconst subscriptions = new Set<() => void>()\n\t\tconst clearSubscriptions = () => {\n\t\t\tfor (const unsubscribe of subscriptions) unsubscribe()\n\t\t\tsubscriptions.clear()\n\t\t}\n\n\t\tsubscriptions.add(providePerspectives(store, socket, continuity, userKey))\n\t\tsubscriptions.add(provideOutcomes(store, socket, continuity, userKey))\n\t\tsubscriptions.add(provideStartupPayloads(store, socket, continuity, userKey))\n\t\tsubscriptions.add(receiveActionRequests(store, socket, continuity, userKey))\n\t\tsubscriptions.add(trackAcknowledgements(store, socket, continuity, userKey))\n\n\t\treturn clearSubscriptions\n\t}\n}\n","import type { Json, stringified } from \"atom.io/json\"\nimport type { Socket } from \"atom.io/realtime\"\n\nexport type Events = Json.Object<string, Json.Serializable[]>\n\nexport type EventPayload<\n\treceiveRelay extends Events,\n\tK extends string & keyof receiveRelay = string & keyof receiveRelay,\n> = [string, ...receiveRelay[K]]\n\nexport interface EventBuffer<\n\tE extends Events,\n\tK extends string & keyof E = string & keyof E,\n> extends Buffer {\n\ttoString(): stringified<EventPayload<E, K>>\n}\n\nexport abstract class CustomSocket<I extends Events, O extends Events>\n\timplements Socket\n{\n\tprotected listeners: Map<keyof O, Set<(...args: Json.Array) => void>>\n\tprotected globalListeners: Set<(event: string, ...args: Json.Array) => void>\n\tprotected handleEvent<K extends string & keyof I>(\n\t\t...args: EventPayload<I, K>\n\t): void {\n\t\tconst [event, ...rest] = args\n\t\tfor (const listener of this.globalListeners) {\n\t\t\tlistener(event, ...rest)\n\t\t}\n\t\tconst listeners = this.listeners.get(event)\n\t\tif (listeners) {\n\t\t\tfor (const listener of listeners) {\n\t\t\t\tlistener(...rest)\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic id = `no_id_retrieved`\n\tpublic emit: <Event extends keyof I>(\n\t\tevent: Event,\n\t\t...args: I[Event]\n\t) => CustomSocket<I, O>\n\n\tpublic constructor(\n\t\temit: <Event extends keyof I>(\n\t\t\tevent: Event,\n\t\t\t...args: I[Event]\n\t\t) => CustomSocket<I, O>,\n\t) {\n\t\tthis.emit = emit\n\t\tthis.listeners = new Map()\n\t\tthis.globalListeners = new Set()\n\t}\n\n\tpublic on<Event extends keyof O>(\n\t\tevent: Event,\n\t\tlistener: (...args: O[Event]) => void,\n\t): this {\n\t\tconst listeners = this.listeners.get(event)\n\t\tif (listeners) {\n\t\t\tlisteners.add(listener)\n\t\t} else {\n\t\t\tthis.listeners.set(event, new Set([listener]))\n\t\t}\n\t\treturn this\n\t}\n\n\tpublic onAny(listener: (event: string, ...args: Json.Array) => void): this {\n\t\tthis.globalListeners.add(listener)\n\t\treturn this\n\t}\n\n\tpublic off<Event extends keyof O>(\n\t\tevent: Event,\n\t\tlistener?: (...args: O[Event]) => void,\n\t): this {\n\t\tconst listeners = this.listeners.get(event)\n\t\tif (listeners) {\n\t\t\tif (listener) {\n\t\t\t\tlisteners.delete(listener)\n\t\t\t} else {\n\t\t\t\tthis.listeners.delete(event)\n\t\t\t}\n\t\t}\n\t\treturn this\n\t}\n\n\tpublic offAny(listener: (event: string, ...args: Json.Array) => void): this {\n\t\tthis.globalListeners.delete(listener)\n\t\treturn this\n\t}\n}\n","import type { Readable, Writable } from \"node:stream\"\n\nimport type { Json, stringified } from \"atom.io/json\"\nimport { parseJson } from \"atom.io/json\"\n\nimport type { EventBuffer, EventPayload, Events } from \"./custom-socket\"\nimport { CustomSocket } from \"./custom-socket\"\n\n/* eslint-disable no-console */\n\nexport type ChildProcess = {\n\tpid?: number | undefined\n\tstdin: Writable\n\tstdout: Readable\n\tstderr: Readable\n}\n\nexport type StderrLog = [`e` | `i` | `w`, ...Json.Array]\n\nexport class ChildSocket<\n\tI extends Events,\n\tO extends Events,\n\tP extends ChildProcess = ChildProcess,\n> extends CustomSocket<I, O> {\n\tprotected incompleteData = ``\n\tprotected unprocessedEvents: string[] = []\n\tprotected incompleteLog = ``\n\tprotected unprocessedLogs: string[] = []\n\n\tpublic id = `#####`\n\n\tpublic proc: P\n\tpublic key: string\n\tpublic logger: Pick<Console, `error` | `info` | `warn`>\n\n\tprotected handleLog(log: StderrLog): void {\n\t\tif (Array.isArray(log)) {\n\t\t\tconst [level, ...rest] = log\n\t\t\tswitch (level) {\n\t\t\t\tcase `i`:\n\t\t\t\t\tthis.logger.info(...rest)\n\t\t\t\t\tbreak\n\t\t\t\tcase `w`:\n\t\t\t\t\tthis.logger.warn(...rest)\n\t\t\t\t\tbreak\n\t\t\t\tcase `e`:\n\t\t\t\t\tthis.logger.error(...rest)\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic constructor(\n\t\tproc: P,\n\t\tkey: string,\n\t\tlogger?: Pick<Console, `error` | `info` | `warn`>,\n\t) {\n\t\tsuper((event, ...args) => {\n\t\t\tconst stringifiedEvent = JSON.stringify([event, ...args]) + `\\x03`\n\t\t\tconst errorHandler = (err: { code: string }) => {\n\t\t\t\tif (err.code === `EPIPE`) {\n\t\t\t\t\tconsole.error(`EPIPE error during write`, this.proc.stdin)\n\t\t\t\t}\n\t\t\t\tthis.proc.stdin.removeListener(`error`, errorHandler)\n\t\t\t}\n\n\t\t\tthis.proc.stdin.once(`error`, errorHandler)\n\t\t\tthis.proc.stdin.write(stringifiedEvent)\n\n\t\t\treturn this\n\t\t})\n\t\tthis.proc = proc\n\t\tthis.key = key\n\t\tthis.logger = logger ?? {\n\t\t\tinfo: (...args: unknown[]) => {\n\t\t\t\tconsole.info(this.id, this.key, ...args)\n\t\t\t},\n\t\t\twarn: (...args: unknown[]) => {\n\t\t\t\tconsole.warn(this.id, this.key, ...args)\n\t\t\t},\n\t\t\terror: (...args: unknown[]) => {\n\t\t\t\tconsole.error(this.id, this.key, ...args)\n\t\t\t},\n\t\t}\n\t\tthis.proc.stdout.on(\n\t\t\t`data`,\n\t\t\t<K extends string & keyof I>(buffer: EventBuffer<I, K>) => {\n\t\t\t\tconst chunk = buffer.toString()\n\n\t\t\t\tif (chunk === `ALIVE`) {\n\t\t\t\t\tthis.logger.info(chunk)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst pieces = chunk.split(`\\x03`)\n\t\t\t\tconst initialMaybeWellFormed = pieces[0]\n\t\t\t\tpieces[0] = this.incompleteData + initialMaybeWellFormed\n\t\t\t\tlet idx = 0\n\t\t\t\tfor (const piece of pieces) {\n\t\t\t\t\tif (piece === ``) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst jsonPiece = parseJson(piece as stringified<EventPayload<I, K>>)\n\t\t\t\t\t\tthis.handleEvent(...jsonPiece)\n\t\t\t\t\t\tthis.incompleteData = ``\n\t\t\t\t\t} catch (thrown0) {\n\t\t\t\t\t\tif (thrown0 instanceof Error) {\n\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t`❌ Malformed data received from child process`,\n\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\tpiece,\n\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\tthrown0.message,\n\t\t\t\t\t\t\t\t].join(`\\n❌\\t`),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (idx === 0) {\n\t\t\t\t\t\t\t\tthis.incompleteData = piece\n\t\t\t\t\t\t\t\tconst maybeActualJsonPiece = parseJson(\n\t\t\t\t\t\t\t\t\tinitialMaybeWellFormed as stringified<EventPayload<I, K>>,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tthis.handleEvent(...maybeActualJsonPiece)\n\t\t\t\t\t\t\t\tthis.incompleteData = ``\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.incompleteData += piece\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (thrown1) {\n\t\t\t\t\t\t\tif (thrown1 instanceof Error) {\n\t\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t`❌ Malformed data received from child process`,\n\t\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\t\tinitialMaybeWellFormed,\n\t\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\t\tthrown1.message,\n\t\t\t\t\t\t\t\t\t].join(`\\n❌\\t`),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t++idx\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\t\tthis.proc.stderr.on(`data`, (buffer: Buffer) => {\n\t\t\tconst chunk = buffer.toString()\n\t\t\tconst pieces = chunk.split(`\\x03`)\n\t\t\tconst initialMaybeWellFormed = pieces[0]\n\t\t\tpieces[0] = this.incompleteData + initialMaybeWellFormed\n\t\t\tlet idx = 0\n\t\t\tfor (const piece of pieces) {\n\t\t\t\tif (piece === ``) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst jsonPiece = parseJson(piece as stringified<StderrLog>)\n\t\t\t\t\tthis.handleLog(jsonPiece)\n\t\t\t\t\tthis.incompleteData = ``\n\t\t\t\t} catch (thrown0) {\n\t\t\t\t\tif (thrown0 instanceof Error) {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t`❌ Malformed log received from child process`,\n\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\tpiece,\n\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\tthrown0.message,\n\t\t\t\t\t\t\t].join(`\\n❌\\t`),\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (idx === 0) {\n\t\t\t\t\t\t\tthis.incompleteData = piece\n\t\t\t\t\t\t\tconst maybeActualJsonPiece = parseJson(\n\t\t\t\t\t\t\t\tinitialMaybeWellFormed as stringified<StderrLog>,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tthis.handleLog(maybeActualJsonPiece)\n\t\t\t\t\t\t\tthis.incompleteData = ``\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.incompleteData += piece\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (thrown1) {\n\t\t\t\t\t\tif (thrown1 instanceof Error) {\n\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t`❌ Malformed log received from child process...`,\n\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\tinitialMaybeWellFormed,\n\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\tthrown1.message,\n\t\t\t\t\t\t\t\t].join(`\\n❌\\t`),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t++idx\n\t\t\t}\n\t\t})\n\t\tif (proc.pid) {\n\t\t\tthis.id = proc.pid.toString()\n\t\t}\n\t}\n}\n","import type { Readable, Writable } from \"node:stream\"\n\nimport { Subject } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { parseJson, stringifyJson } from \"atom.io/json\"\nimport type { UserKey } from \"atom.io/realtime\"\nimport { UList } from \"atom.io/transceivers/u-list\"\n\nimport type { StderrLog } from \"./child-socket\"\nimport type { EventBuffer, EventPayload, Events } from \"./custom-socket\"\nimport { CustomSocket } from \"./custom-socket\"\n\nexport class SubjectSocket<\n\tI extends Events,\n\tO extends Events,\n> extends CustomSocket<I, O> {\n\tpublic in: Subject<EventPayload<I>>\n\tpublic out: Subject<EventPayload<O>>\n\tpublic id = `no_id_retrieved`\n\tpublic disposalFunctions: (() => void)[] = []\n\n\tpublic constructor(id: string) {\n\t\tsuper((...args) => {\n\t\t\tthis.out.next(args as any)\n\t\t\treturn this\n\t\t})\n\t\tthis.id = id\n\t\tthis.in = new Subject()\n\t\tthis.out = new Subject()\n\t\tthis.in.subscribe(`socket`, (event) => {\n\t\t\tthis.handleEvent(...event)\n\t\t})\n\t}\n\n\tpublic dispose(): void {\n\t\tfor (const dispose of this.disposalFunctions) {\n\t\t\tdispose()\n\t\t}\n\t}\n}\n\nexport type ParentProcess = {\n\tpid?: number | undefined\n\tstdin: Readable\n\tstdout: Writable\n\tstderr: Writable\n\texit: (code?: number) => void\n}\n\nexport class ParentSocket<\n\tI extends Events & {\n\t\t[id in string as `relay::${id}`]: [string, ...Json.Array[]]\n\t},\n\tO extends Events & {\n\t\t[id in string as `user::${id}`]: [string, ...Json.Array[]]\n\t} & {\n\t\t/* eslint-disable quotes */\n\t\t\"user-joins\": [key: UserKey]\n\t\t\"user-leaves\": [key: UserKey]\n\t\t/* eslint-enable quotes */\n\t},\n\tP extends ParentProcess = ParentProcess,\n> extends CustomSocket<I, O> {\n\tprotected incompleteData = ``\n\tprotected unprocessedEvents: string[] = []\n\tprotected relays: Map<string, SubjectSocket<any, any>>\n\tprotected relayServices: ((\n\t\tsocket: SubjectSocket<any, any>,\n\t\tuserKey: UserKey,\n\t) => (() => void) | void)[]\n\tpublic proc: P\n\n\tpublic id = `#####`\n\n\tprotected log(...args: StderrLog): void {\n\t\tthis.proc.stderr.write(\n\t\t\tstringifyJson(\n\t\t\t\targs.map((arg) =>\n\t\t\t\t\targ instanceof UList ? `{ ${arg.toJSON().join(` | `)} }` : arg,\n\t\t\t\t),\n\t\t\t) + `\\x03`,\n\t\t)\n\t}\n\tpublic logger = {\n\t\tinfo: (...args: Json.Array): void => {\n\t\t\tthis.log(`i`, ...args)\n\t\t},\n\t\twarn: (...args: Json.Array): void => {\n\t\t\tthis.log(`w`, ...args)\n\t\t},\n\t\terror: (...args: Json.Array): void => {\n\t\t\tthis.log(`e`, ...args)\n\t\t},\n\t}\n\n\tpublic constructor(proc: P) {\n\t\tsuper((event, ...args) => {\n\t\t\tconst stringifiedEvent = JSON.stringify([event, ...args])\n\t\t\tthis.proc.stdout.write(stringifiedEvent + `\\x03`)\n\t\t\treturn this\n\t\t})\n\t\tthis.proc = proc\n\t\tthis.proc.stdin.resume()\n\t\tthis.relays = new Map()\n\t\tthis.relayServices = []\n\n\t\tthis.proc.stdin.on(\n\t\t\t`data`,\n\t\t\t<K extends string & keyof I>(buffer: EventBuffer<I, K>) => {\n\t\t\t\tconst chunk = buffer.toString()\n\t\t\t\tconst pieces = chunk.split(`\\x03`)\n\t\t\t\tconst initialMaybeWellFormed = pieces[0]\n\t\t\t\tpieces[0] = this.incompleteData + initialMaybeWellFormed\n\t\t\t\tlet idx = 0\n\t\t\t\tfor (const piece of pieces) {\n\t\t\t\t\tif (piece === ``) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst jsonPiece = parseJson(piece)\n\t\t\t\t\t\tthis.logger.info(`🎰`, `received`, jsonPiece)\n\t\t\t\t\t\tthis.handleEvent(...(jsonPiece as EventPayload<I>))\n\t\t\t\t\t\tthis.incompleteData = ``\n\t\t\t\t\t} catch (thrown0) {\n\t\t\t\t\t\tif (thrown0 instanceof Error) {\n\t\t\t\t\t\t\tthis.logger.error(\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t`received malformed data from parent process:`,\n\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\tpiece,\n\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\tthrown0.message,\n\t\t\t\t\t\t\t\t].join(`\\n❌\\t`),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (idx === 0) {\n\t\t\t\t\t\t\t\tthis.incompleteData = piece\n\t\t\t\t\t\t\t\tconst maybeActualJsonPiece = parseJson(initialMaybeWellFormed)\n\t\t\t\t\t\t\t\tthis.logger.info(`🎰`, `received`, maybeActualJsonPiece)\n\t\t\t\t\t\t\t\tthis.handleEvent(...(maybeActualJsonPiece as EventPayload<I>))\n\t\t\t\t\t\t\t\tthis.incompleteData = ``\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.incompleteData += piece\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (thrown1) {\n\t\t\t\t\t\t\tif (thrown1 instanceof Error) {\n\t\t\t\t\t\t\t\tthis.logger.error(\n\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t`received malformed data from parent process:`,\n\t\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\t\tinitialMaybeWellFormed,\n\t\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\t\tthrown1.message,\n\t\t\t\t\t\t\t\t\t].join(`\\n❌\\t`),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t++idx\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\n\t\tthis.on(`exit`, () => {\n\t\t\tthis.logger.info(`🔥`, this.id, `received \"exit\"`)\n\t\t\tthis.proc.exit(0)\n\t\t})\n\n\t\tif (this.proc.pid) {\n\t\t\tthis.id = this.proc.pid?.toString()\n\t\t}\n\n\t\tthis.on(`user-joins`, (userKey: UserKey) => {\n\t\t\tthis.logger.info(`👤`, `user`, userKey, `joined`)\n\t\t\tconst relay = new SubjectSocket(userKey)\n\t\t\tthis.relays.set(userKey, relay)\n\t\t\tthis.logger.info(\n\t\t\t\t`🔗`,\n\t\t\t\t`attaching services:`,\n\t\t\t\t`[${[...this.relayServices.keys()].join(`, `)}]`,\n\t\t\t)\n\t\t\tfor (const attachRelay of this.relayServices) {\n\t\t\t\tconst cleanupRelay = attachRelay(relay, userKey)\n\t\t\t\tif (cleanupRelay) {\n\t\t\t\t\trelay.disposalFunctions.push(cleanupRelay)\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.on(userKey, (...data) => {\n\t\t\t\trelay.in.next(data)\n\t\t\t})\n\t\t\trelay.out.subscribe(`socket`, (data) => {\n\t\t\t\tthis.emit(...(data as [string, ...I[keyof I]]))\n\t\t\t})\n\t\t})\n\n\t\tthis.on(`user-leaves`, (username) => {\n\t\t\tconst relay = this.relays.get(username)\n\t\t\tthis.off(`relay:${username}`)\n\t\t\tif (relay) {\n\t\t\t\trelay.dispose()\n\t\t\t\tthis.relays.delete(username)\n\t\t\t}\n\t\t})\n\n\t\tthis.proc.stdout.write(`ALIVE`)\n\t}\n\n\tpublic receiveRelay(\n\t\tattachServices: (\n\t\t\tsocket: SubjectSocket<any, any>,\n\t\t\tuserKey: UserKey,\n\t\t) => (() => void) | void,\n\t): void {\n\t\tthis.logger.info(`🔗`, `running relay method`)\n\t\tthis.relayServices.push(attachServices)\n\t}\n}\n","import type * as AtomIO from \"atom.io\"\nimport {\n\tfindInStore,\n\tgetFromStore,\n\tIMPLICIT,\n\tsubscribeToState,\n} from \"atom.io/internal\"\nimport type { Canonical, Json, stringified } from \"atom.io/json\"\nimport { stringifyJson } from \"atom.io/json\"\nimport { employSocket } from \"atom.io/realtime\"\n\nimport type { ServerConfig } from \".\"\n\nexport type FamilyProvider = ReturnType<typeof realtimeAtomFamilyProvider>\nexport function realtimeAtomFamilyProvider({\n\tsocket,\n\tuserKey,\n\tstore = IMPLICIT.STORE,\n}: ServerConfig) {\n\treturn function familyProvider<\n\t\tJ extends Json.Serializable,\n\t\tK extends Canonical,\n\t>(\n\t\tfamily: AtomIO.RegularAtomFamilyToken<J, K>,\n\t\tindex: AtomIO.ReadableToken<Iterable<NoInfer<K>>>,\n\t): () => void {\n\t\tconst coreSubscriptions = new Set<() => void>()\n\t\tconst clearCoreSubscriptions = () => {\n\t\t\tfor (const unsub of coreSubscriptions) unsub()\n\t\t\tcoreSubscriptions.clear()\n\t\t}\n\t\tconst familyMemberSubscriptionsWanted = new Set<stringified<K>>()\n\t\tconst familyMemberSubscriptions = new Map<string, () => void>()\n\t\tconst clearFamilySubscriptions = () => {\n\t\t\tfor (const unsub of familyMemberSubscriptions.values()) unsub()\n\t\t\tfamilyMemberSubscriptions.clear()\n\t\t}\n\n\t\tconst fillUnsubRequest = (key: string) => {\n\t\t\tconst unsubUnsub = familyMemberSubscriptions.get(`${key}:unsub`)\n\t\t\tif (unsubUnsub) {\n\t\t\t\tunsubUnsub()\n\t\t\t\tfamilyMemberSubscriptions.delete(`${key}:unsub`)\n\t\t\t}\n\t\t\tconst unsub = familyMemberSubscriptions.get(key)\n\t\t\tif (unsub) {\n\t\t\t\tunsub()\n\t\t\t\tfamilyMemberSubscriptions.delete(key)\n\t\t\t}\n\t\t}\n\n\t\tconst exposeFamilyMembers = (subKey: K) => {\n\t\t\tconst token = findInStore(store, family, subKey)\n\t\t\tgetFromStore(store, token)\n\t\t\tsocket.emit(`serve:${token.key}`, getFromStore(store, token))\n\t\t\tfamilyMemberSubscriptions.set(\n\t\t\t\ttoken.key,\n\t\t\t\tsubscribeToState(\n\t\t\t\t\tstore,\n\t\t\t\t\ttoken,\n\t\t\t\t\t`expose-family:${family.key}:${socket.id}`,\n\t\t\t\t\t({ newValue }) => {\n\t\t\t\t\t\tsocket.emit(`serve:${token.key}`, newValue)\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\t\t\tfamilyMemberSubscriptions.set(\n\t\t\t\t`${token.key}:unsub`,\n\t\t\t\temploySocket(socket, `unsub:${token.key}`, () => {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`🙈`,\n\t\t\t\t\t\t`user`,\n\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t`unsubscribed from state \"${token.key}\"`,\n\t\t\t\t\t)\n\t\t\t\t\tfillUnsubRequest(token.key)\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\n\t\tconst isAvailable = (exposedSubKeys: Iterable<K>, subKey: K): boolean => {\n\t\t\tfor (const exposedSubKey of exposedSubKeys) {\n\t\t\t\tif (stringifyJson(exposedSubKey) === stringifyJson(subKey)) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\n\t\tconst start = () => {\n\t\t\tstore.logger.info(\n\t\t\t\t`👀`,\n\t\t\t\t`user`,\n\t\t\t\tuserKey,\n\t\t\t\t`can subscribe to family \"${family.key}\"`,\n\t\t\t)\n\t\t\tcoreSubscriptions.add(\n\t\t\t\temploySocket(socket, `sub:${family.key}`, (subKey: K) => {\n\t\t\t\t\tconst exposedSubKeys = getFromStore(store, index)\n\t\t\t\t\tconst shouldExpose = isAvailable(exposedSubKeys, subKey)\n\t\t\t\t\tif (shouldExpose) {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`is approved for a subscription to`,\n\t\t\t\t\t\t\tsubKey,\n\t\t\t\t\t\t\t`in family \"${family.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\texposeFamilyMembers(subKey)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`❌`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`is denied for a subscription to`,\n\t\t\t\t\t\t\tsubKey,\n\t\t\t\t\t\t\t`in family \"${family.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tfamilyMemberSubscriptionsWanted.add(stringifyJson(subKey))\n\t\t\t\t\t\tsocket.emit(`unavailable:${family.key}`, subKey)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t)\n\t\t\tcoreSubscriptions.add(\n\t\t\t\tsubscribeToState(\n\t\t\t\t\tstore,\n\t\t\t\t\tindex,\n\t\t\t\t\t`expose-family:${family.key}:${socket.id}`,\n\t\t\t\t\t({ newValue: newExposedSubKeys }) => {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`has the following keys available for family \"${family.key}\"`,\n\t\t\t\t\t\t\tnewExposedSubKeys,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tfor (const subKey of newExposedSubKeys) {\n\t\t\t\t\t\t\tif (familyMemberSubscriptionsWanted.has(stringifyJson(subKey))) {\n\t\t\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t\t\t`is retroactively approved for a subscription to`,\n\t\t\t\t\t\t\t\t\tsubKey,\n\t\t\t\t\t\t\t\t\t`in family \"${family.key}\"`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\texposeFamilyMembers(subKey)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\n\t\tstart()\n\n\t\treturn () => {\n\t\t\tclearCoreSubscriptions()\n\t\t\tclearFamilySubscriptions()\n\t\t}\n\t}\n}\n","import type * as AtomIO from \"atom.io\"\nimport type { Transceiver } from \"atom.io/internal\"\nimport {\n\tfindInStore,\n\tgetFromStore,\n\tgetJsonToken,\n\tgetUpdateToken,\n\tIMPLICIT,\n\tsubscribeToState,\n} from \"atom.io/internal\"\nimport type { Canonical, stringified } from \"atom.io/json\"\nimport { stringifyJson } from \"atom.io/json\"\nimport { employSocket } from \"atom.io/realtime\"\n\nimport type { ServerConfig } from \".\"\n\nconst isAvailable = <K extends Canonical>(\n\texposedSubKeys: Iterable<K>,\n\tsubKey: K,\n): boolean => {\n\tfor (const exposedSubKey of exposedSubKeys) {\n\t\tif (stringifyJson(exposedSubKey) === stringifyJson(subKey)) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nexport type MutableFamilyProvider = ReturnType<\n\ttypeof realtimeMutableFamilyProvider\n>\nexport function realtimeMutableFamilyProvider({\n\tsocket,\n\tuserKey,\n\tstore = IMPLICIT.STORE,\n}: ServerConfig) {\n\treturn function mutableFamilyProvider<\n\t\tT extends Transceiver<any, any, any>,\n\t\tK extends Canonical,\n\t>(\n\t\tfamily: AtomIO.MutableAtomFamilyToken<T, K>,\n\t\tindex: AtomIO.ReadableToken<Iterable<NoInfer<K>>>,\n\t): () => void {\n\t\tconst coreSubscriptions = new Set<() => void>()\n\t\tconst clearCoreSubscriptions = () => {\n\t\t\tfor (const unsub of coreSubscriptions) unsub()\n\t\t\tcoreSubscriptions.clear()\n\t\t}\n\t\tconst familyMemberSubscriptionsWanted = new Set<stringified<K>>()\n\t\tconst familyMemberSubscriptions = new Map<string, () => void>()\n\t\tconst clearFamilySubscriptions = () => {\n\t\t\tfor (const unsub of familyMemberSubscriptions.values()) unsub()\n\t\t\tfamilyMemberSubscriptions.clear()\n\t\t}\n\n\t\tconst fillUnsubRequest = (key: string) => {\n\t\t\tconst unsubUnsub = familyMemberSubscriptions.get(`${key}:unsub`)\n\t\t\tif (unsubUnsub) {\n\t\t\t\tunsubUnsub()\n\t\t\t\tfamilyMemberSubscriptions.delete(`${key}:unsub`)\n\t\t\t}\n\t\t\tconst unsub = familyMemberSubscriptions.get(key)\n\t\t\tif (unsub) {\n\t\t\t\tunsub()\n\t\t\t\tfamilyMemberSubscriptions.delete(key)\n\t\t\t}\n\t\t}\n\n\t\tconst exposeFamilyMembers = (subKey: K) => {\n\t\t\tconst token = findInStore(store, family, subKey)\n\t\t\tgetFromStore(store, token)\n\t\t\tconst jsonToken = getJsonToken(store, token)\n\t\t\tconst updateToken = getUpdateToken(token)\n\t\t\tsocket.emit(`init:${token.key}`, getFromStore(store, jsonToken))\n\t\t\tfamilyMemberSubscriptions.set(\n\t\t\t\ttoken.key,\n\t\t\t\tsubscribeToState(\n\t\t\t\t\tstore,\n\t\t\t\t\tupdateToken,\n\t\t\t\t\t`expose-family:${family.key}:${socket.id}`,\n\t\t\t\t\t({ newValue }) => {\n\t\t\t\t\t\tsocket.emit(`next:${token.key}`, newValue)\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\t\t\tfamilyMemberSubscriptions.set(\n\t\t\t\t`${token.key}:unsub`,\n\t\t\t\temploySocket(socket, `unsub:${token.key}`, () => {\n\t\t\t\t\tfillUnsubRequest(token.key)\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\n\t\tconst start = () => {\n\t\t\tstore.logger.info(\n\t\t\t\t`👀`,\n\t\t\t\t`user`,\n\t\t\t\tuserKey,\n\t\t\t\t`can subscribe to family \"${family.key}\"`,\n\t\t\t)\n\t\t\tcoreSubscriptions.add(\n\t\t\t\temploySocket(socket, `sub:${family.key}`, (subKey: K) => {\n\t\t\t\t\tconst exposedSubKeys = getFromStore(store, index)\n\t\t\t\t\tconst shouldExpose = isAvailable(exposedSubKeys, subKey)\n\t\t\t\t\tif (shouldExpose) {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`is approved for a subscription to`,\n\t\t\t\t\t\t\tsubKey,\n\t\t\t\t\t\t\t`in family \"${family.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\texposeFamilyMembers(subKey)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`❌`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`is denied for a subscription to`,\n\t\t\t\t\t\t\tsubKey,\n\t\t\t\t\t\t\t`in family \"${family.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tfamilyMemberSubscriptionsWanted.add(stringifyJson(subKey))\n\t\t\t\t\t\tsocket.emit(`unavailable:${family.key}`, subKey)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t)\n\t\t\tcoreSubscriptions.add(\n\t\t\t\tsubscribeToState(\n\t\t\t\t\tstore,\n\t\t\t\t\tindex,\n\t\t\t\t\t`expose-family:${family.key}:${socket.id}`,\n\t\t\t\t\t({ newValue: newExposedSubKeys }) => {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`has the following keys available for family \"${family.key}\"`,\n\t\t\t\t\t\t\tnewExposedSubKeys,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tfor (const subKey of newExposedSubKeys) {\n\t\t\t\t\t\t\tif (familyMemberSubscriptionsWanted.has(stringifyJson(subKey))) {\n\t\t\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t\t\t`is retroactively approved for a subscription to`,\n\t\t\t\t\t\t\t\t\tsubKey,\n\t\t\t\t\t\t\t\t\t`in family \"${family.key}\"`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\texposeFamilyMembers(subKey)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\n\t\tstart()\n\n\t\treturn () => {\n\t\t\tclearCoreSubscriptions()\n\t\t\tclearFamilySubscriptions()\n\t\t}\n\t}\n}\n","import type * as AtomIO from \"atom.io\"\nimport type { Transceiver } from \"atom.io/internal\"\nimport {\n\tgetFromStore,\n\tgetJsonToken,\n\tgetUpdateToken,\n\tIMPLICIT,\n\tsubscribeToState,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { employSocket } from \"atom.io/realtime\"\n\nimport type { ServerConfig } from \".\"\n\nexport type MutableProvider = ReturnType<typeof realtimeMutableProvider>\nexport function realtimeMutableProvider({\n\tsocket,\n\tuserKey,\n\tstore = IMPLICIT.STORE,\n}: ServerConfig) {\n\treturn function mutableProvider<\n\t\tCore extends Transceiver<any, Json.Serializable, Json.Serializable>,\n\t>(token: AtomIO.MutableAtomToken<Core>): () => void {\n\t\tconst subscriptions = new Set<() => void>()\n\t\tconst clearSubscriptions = () => {\n\t\t\tfor (const unsub of subscriptions) unsub()\n\t\t\tsubscriptions.clear()\n\t\t}\n\n\t\tconst jsonToken = getJsonToken(store, token)\n\t\tconst trackerToken = getUpdateToken(token)\n\n\t\tconst start = () => {\n\t\t\tstore.logger.info(\n\t\t\t\t`👀`,\n\t\t\t\t`user`,\n\t\t\t\tuserKey,\n\t\t\t\t`can subscribe to state \"${token.key}\"`,\n\t\t\t)\n\t\t\tsubscriptions.add(\n\t\t\t\temploySocket(socket, `sub:${token.key}`, () => {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t`user`,\n\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t`subscribes to state \"${token.key}\"`,\n\t\t\t\t\t)\n\t\t\t\t\tclearSubscriptions()\n\t\t\t\t\tsocket.emit(`init:${token.key}`, getFromStore(store, jsonToken))\n\t\t\t\t\tsubscriptions.add(\n\t\t\t\t\t\tsubscribeToState(\n\t\t\t\t\t\t\tstore,\n\t\t\t\t\t\t\ttrackerToken,\n\t\t\t\t\t\t\t`expose-single:${socket.id}`,\n\t\t\t\t\t\t\t({ newValue }) => {\n\t\t\t\t\t\t\t\tsocket.emit(`next:${token.key}`, newValue)\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\tsubscriptions.add(\n\t\t\t\t\t\temploySocket(socket, `unsub:${token.key}`, () => {\n\t\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t\t`🙈`,\n\t\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t\t`unsubscribes from state \"${token.key}\"`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tclearSubscriptions()\n\t\t\t\t\t\t\tstart()\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\n\t\tstart()\n\n\t\treturn clearSubscriptions\n\t}\n}\n","import type * as AtomIO from \"atom.io\"\nimport { getFromStore, IMPLICIT, subscribeToState } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { employSocket } from \"atom.io/realtime\"\n\nimport type { ServerConfig } from \".\"\n\nfunction isReadableToken(input: unknown): input is AtomIO.ReadableToken<any> {\n\treturn (\n\t\ttypeof input === `object` &&\n\t\tinput !== null &&\n\t\t`key` in input &&\n\t\t`type` in input\n\t)\n}\n\nexport type StateProvider = ReturnType<typeof realtimeStateProvider>\nexport function realtimeStateProvider({\n\tsocket,\n\tuserKey,\n\tstore = IMPLICIT.STORE,\n}: ServerConfig) {\n\tstore.logger.info(`🔌`, `user`, userKey, `initialized state provider`)\n\treturn function stateProvider<J extends Json.Serializable>(\n\t\tclientToken: AtomIO.WritableToken<J>,\n\t\tserverData: AtomIO.ReadableToken<NoInfer<J>> | NoInfer<J> = clientToken,\n\t): () => void {\n\t\tconst isStatic = !isReadableToken(serverData)\n\n\t\tconst subscriptions = new Set<() => void>()\n\t\tconst clearSubscriptions = () => {\n\t\t\tfor (const unsub of subscriptions) unsub()\n\t\t\tsubscriptions.clear()\n\t\t}\n\n\t\tconst start = () => {\n\t\t\tif (isStatic) {\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`👀`,\n\t\t\t\t\t`user`,\n\t\t\t\t\tuserKey,\n\t\t\t\t\t`will be served`,\n\t\t\t\t\tserverData,\n\t\t\t\t\t`as \"${clientToken.key}\"`,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`👀`,\n\t\t\t\t\t`user`,\n\t\t\t\t\tuserKey,\n\t\t\t\t\t`can subscribe to state \"${serverData.key}\" as \"${clientToken.key}\"`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tsubscriptions.add(\n\t\t\t\temploySocket(socket, `sub:${clientToken.key}`, () => {\n\t\t\t\t\tif (isStatic) {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`requests`,\n\t\t\t\t\t\t\t`\"${clientToken.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tsocket.emit(`serve:${clientToken.key}`, serverData)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`subscribes to state \"${serverData.key}\"`,\n\t\t\t\t\t\t\tclientToken === serverData\n\t\t\t\t\t\t\t\t? `directly`\n\t\t\t\t\t\t\t\t: `as \"${clientToken.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tclearSubscriptions()\n\t\t\t\t\t\tsocket.emit(\n\t\t\t\t\t\t\t`serve:${clientToken.key}`,\n\t\t\t\t\t\t\tgetFromStore(store, serverData),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tsubscriptions.add(\n\t\t\t\t\t\t\tsubscribeToState(\n\t\t\t\t\t\t\t\tstore,\n\t\t\t\t\t\t\t\tserverData,\n\t\t\t\t\t\t\t\t`expose-single:${socket.id}`,\n\t\t\t\t\t\t\t\t({ newValue }) => {\n\t\t\t\t\t\t\t\t\tsocket.emit(`serve:${clientToken.key}`, newValue)\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tsubscriptions.add(\n\t\t\t\t\t\t\temploySocket(socket, `unsub:${serverData.key}`, () => {\n\t\t\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t\t\t`🙈`,\n\t\t\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t\t\t`unsubscribes from state \"${serverData.key}\", served`,\n\t\t\t\t\t\t\t\t\tclientToken === serverData\n\t\t\t\t\t\t\t\t\t\t? `directly`\n\t\t\t\t\t\t\t\t\t\t: `as \"${clientToken.key}\"`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tclearSubscriptions()\n\t\t\t\t\t\t\t\tstart()\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\n\t\tstart()\n\n\t\treturn clearSubscriptions\n\t}\n}\n","import { IMPLICIT } from \"atom.io/internal\"\n\nimport { realtimeStateProvider } from \"../realtime-state-provider\"\nimport type { ServerConfig } from \"../server-config\"\n\nexport function provideIdentity({\n\tstore = IMPLICIT.STORE,\n\tsocket,\n\tuserKey,\n}: ServerConfig): void {\n\tconst provideState = realtimeStateProvider({ socket, store, userKey })\n\n\tconst unsub = provideState({ key: `myUserKey`, type: `atom` }, userKey)\n\n\tsocket.on(`disconnect`, () => {\n\t\tunsub()\n\t})\n}\n","import type {\n\tHierarchy,\n\tJoinToken,\n\tMutableAtomToken,\n\tPureSelectorFamilyToken,\n\tRegularAtomFamilyToken,\n} from \"atom.io\"\nimport { atomFamily, join, mutableAtom, selectorFamily } from \"atom.io\"\nimport type { RoomKey, Socket, SocketKey, UserKey } from \"atom.io/realtime\"\nimport { isSocketKey, isUserKey } from \"atom.io/realtime\"\nimport { UList } from \"atom.io/transceivers/u-list\"\n\nexport type SocketSystemHierarchy = Hierarchy<\n\t[\n\t\t{\n\t\t\tabove: `root`\n\t\t\tbelow: [UserKey, SocketKey, RoomKey]\n\t\t},\n\t]\n>\n\nexport const socketAtoms: RegularAtomFamilyToken<Socket | null, SocketKey> =\n\tatomFamily({\n\t\tkey: `sockets`,\n\t\tdefault: null,\n\t})\n\nexport const socketKeysAtom: MutableAtomToken<UList<SocketKey>> = mutableAtom({\n\tkey: `socketsIndex`,\n\tclass: UList,\n})\nexport const userKeysAtom: MutableAtomToken<UList<UserKey>> = mutableAtom({\n\tkey: `usersIndex`,\n\tclass: UList,\n})\nexport const usersOfSockets: JoinToken<\n\t`user`,\n\tUserKey,\n\t`socket`,\n\tSocketKey,\n\t`1:1`\n> = join({\n\tkey: `usersOfSockets`,\n\tbetween: [`user`, `socket`],\n\tcardinality: `1:1`,\n\tisAType: isUserKey,\n\tisBType: isSocketKey,\n})\n\nexport const selfListSelectors: PureSelectorFamilyToken<UserKey[], UserKey> =\n\tselectorFamily({\n\t\tkey: `selfList`,\n\t\tget: (userKey) => () => [userKey],\n\t})\n","import type { ChildProcessWithoutNullStreams } from \"node:child_process\"\nimport { spawn } from \"node:child_process\"\n\nimport type { RootStore } from \"atom.io/internal\"\nimport {\n\teditRelationsInStore,\n\tfindInStore,\n\tfindRelationsInStore,\n\tgetFromStore,\n\tgetInternalRelationsFromStore,\n\tIMPLICIT,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type {\n\tAllEventsListener,\n\tEventsMap,\n\tRoomKey,\n\tRoomSocketInterface,\n\tSocket,\n\tSocketGuard,\n\tSocketKey,\n\tStandardSchemaV1,\n\tTypedSocket,\n\tUserKey,\n} from \"atom.io/realtime\"\nimport {\n\tcastSocket,\n\tisRoomKey,\n\townersOfRooms,\n\troomKeysAtom,\n\tusersInRooms,\n} from \"atom.io/realtime\"\n\nimport { ChildSocket } from \"../ipc-sockets\"\nimport { realtimeMutableFamilyProvider } from \"../realtime-mutable-family-provider\"\nimport { realtimeMutableProvider } from \"../realtime-mutable-provider\"\nimport type { ServerConfig } from \"../server-config\"\nimport {\n\tselfListSelectors,\n\tsocketKeysAtom,\n\tuserKeysAtom,\n\tusersOfSockets,\n} from \"./server-user-store\"\n\nexport type RoomMap = Map<\n\tstring,\n\tChildSocket<any, any, ChildProcessWithoutNullStreams>\n>\n\ndeclare global {\n\tvar ATOM_IO_REALTIME_SERVER_ROOMS: RoomMap\n}\nexport const ROOMS: RoomMap =\n\tglobalThis.ATOM_IO_REALTIME_SERVER_ROOMS ??\n\t(globalThis.ATOM_IO_REALTIME_SERVER_ROOMS = new Map())\n\nexport const roomMeta: { count: number } = { count: 0 }\n\nexport type SpawnRoomConfig<RoomNames extends string> = {\n\tstore: RootStore\n\tsocket: Socket\n\tuserKey: UserKey\n\tresolveRoomScript: (roomName: RoomNames) => [string, string[]]\n}\nexport function spawnRoom<RoomNames extends string>({\n\tstore,\n\tsocket,\n\tuserKey,\n\tresolveRoomScript,\n}: SpawnRoomConfig<RoomNames>): (\n\troomName: RoomNames,\n) => Promise<ChildSocket<any, any>> {\n\treturn async (roomName) => {\n\t\tstore.logger.info(\n\t\t\t`📡`,\n\t\t\t`socket`,\n\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t`👤 ${userKey} spawns room ${roomName}`,\n\t\t)\n\t\tconst roomKey = `room::${roomMeta.count++}` satisfies RoomKey\n\t\tconst [command, args] = resolveRoomScript(roomName)\n\t\tconst child = await new Promise<ChildProcessWithoutNullStreams>(\n\t\t\t(resolve) => {\n\t\t\t\tconst room = spawn(command, args, { env: process.env })\n\t\t\t\tconst resolver = (data: Buffer) => {\n\t\t\t\t\tif (data.toString() === `ALIVE`) {\n\t\t\t\t\t\troom.stdout.off(`data`, resolver)\n\t\t\t\t\t\tresolve(room)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\troom.stdout.on(`data`, resolver)\n\t\t\t},\n\t\t)\n\t\tconst roomSocket = new ChildSocket(child, roomKey)\n\t\tROOMS.set(roomKey, roomSocket)\n\t\tsetIntoStore(store, roomKeysAtom, (index) => (index.add(roomKey), index))\n\n\t\teditRelationsInStore(store, ownersOfRooms, (relations) => {\n\t\t\trelations.set({ room: roomKey, user: userKey })\n\t\t})\n\n\t\troomSocket.on(`close`, () => {\n\t\t\tdestroyRoom({ store, socket, userKey })(roomKey)\n\t\t})\n\n\t\treturn roomSocket\n\t}\n}\n\nexport type ProvideEnterAndExitConfig = {\n\tstore: RootStore\n\tsocket: Socket\n\troomSocket: TypedSocket<RoomSocketInterface<any>, any>\n\tuserKey: UserKey\n}\nexport function provideEnterAndExit({\n\tstore,\n\tsocket,\n\troomSocket,\n\tuserKey,\n}: ProvideEnterAndExitConfig): (roomKey: RoomKey) => void {\n\tconst enterRoom = (roomKey: RoomKey) => {\n\t\tstore.logger.info(\n\t\t\t`📡`,\n\t\t\t`socket`,\n\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t`👤 ${userKey} enters room ${roomKey}`,\n\t\t)\n\n\t\tconst exitRoom = () => {\n\t\t\tstore.logger.info(\n\t\t\t\t`📡`,\n\t\t\t\t`socket`,\n\t\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t\t`👤 ${userKey} leaves room ${roomKey}`,\n\t\t\t)\n\t\t\tsocket.offAny(forward)\n\t\t\ttoRoom([`user-leaves`])\n\t\t\teditRelationsInStore(store, usersInRooms, (relations) => {\n\t\t\t\trelations.delete({ room: roomKey, user: userKey })\n\t\t\t})\n\t\t\troomSocket.off(`leaveRoom`, exitRoom)\n\t\t\troomSocket.on(`joinRoom`, enterRoom)\n\t\t}\n\n\t\troomSocket.on(`leaveRoom`, exitRoom)\n\t\troomSocket.off(`joinRoom`, enterRoom)\n\n\t\tconst roomQueue: [string, ...Json.Array][] = []\n\t\tconst pushToRoomQueue = (payload: [string, ...Json.Array]): void => {\n\t\t\troomQueue.push(payload)\n\t\t}\n\t\tlet toRoom = pushToRoomQueue\n\t\tconst forward: AllEventsListener<EventsMap> = (...payload) => {\n\t\t\ttoRoom(payload)\n\t\t}\n\t\tsocket.onAny(forward)\n\n\t\teditRelationsInStore(store, usersInRooms, (relations) => {\n\t\t\trelations.set({ room: roomKey, user: userKey })\n\t\t})\n\t\tconst childSocket = ROOMS.get(roomKey)\n\t\tif (!childSocket) {\n\t\t\tstore.logger.error(`❌`, `unknown`, roomKey, `no room found with this id`)\n\t\t\treturn null\n\t\t}\n\t\tchildSocket.onAny((...payload) => {\n\t\t\tsocket.emit(...payload)\n\t\t})\n\t\tchildSocket.emit(`user-joins`, userKey)\n\n\t\ttoRoom = (payload) => {\n\t\t\tchildSocket.emit(userKey, ...payload)\n\t\t}\n\t\twhile (roomQueue.length > 0) {\n\t\t\tconst payload = roomQueue.shift()\n\t\t\tif (payload) toRoom(payload)\n\t\t}\n\t}\n\troomSocket.on(`joinRoom`, enterRoom)\n\treturn enterRoom\n}\n\nexport type DestroyRoomConfig = {\n\tstore: RootStore\n\tsocket: Socket\n\tuserKey: UserKey\n}\nexport function destroyRoom({\n\tstore,\n\tsocket,\n\tuserKey,\n}: DestroyRoomConfig): (roomKey: RoomKey) => void {\n\treturn (roomKey: RoomKey) => {\n\t\tstore.logger.info(\n\t\t\t`📡`,\n\t\t\t`socket`,\n\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t`👤 ${userKey} attempts to delete room ${roomKey}`,\n\t\t)\n\t\tconst owner = getFromStore(\n\t\t\tstore,\n\t\t\tfindRelationsInStore(store, ownersOfRooms, roomKey).userKeyOfRoom,\n\t\t)\n\t\tif (owner === userKey) {\n\t\t\tstore.logger.info(\n\t\t\t\t`📡`,\n\t\t\t\t`socket`,\n\t\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t\t`👤 ${userKey} deletes room ${roomKey}`,\n\t\t\t)\n\t\t\tsetIntoStore(store, roomKeysAtom, (s) => (s.delete(roomKey), s))\n\t\t\teditRelationsInStore(store, usersInRooms, (relations) => {\n\t\t\t\trelations.delete({ room: roomKey })\n\t\t\t})\n\t\t\tconst room = ROOMS.get(roomKey)\n\t\t\tif (room) {\n\t\t\t\troom.emit(`exit`)\n\t\t\t\tROOMS.delete(roomKey)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tstore.logger.info(\n\t\t\t`📡`,\n\t\t\t`socket`,\n\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t`👤 ${userKey} failed to delete room ${roomKey}; room owner is ${owner}`,\n\t\t)\n\t}\n}\n\nexport type ProvideRoomsConfig<RoomNames extends string> = {\n\tresolveRoomScript: (path: RoomNames) => [string, string[]]\n\troomNames: RoomNames[]\n\troomTimeLimit?: number\n}\nexport function provideRooms<RoomNames extends string>({\n\tstore = IMPLICIT.STORE,\n\tsocket,\n\tresolveRoomScript,\n\troomNames,\n}: ProvideRoomsConfig<RoomNames> & ServerConfig): void {\n\tconst socketKey = `socket::${socket.id}` satisfies SocketKey\n\tconst userKey = getFromStore(\n\t\tstore,\n\t\tfindRelationsInStore(store, usersOfSockets, socketKey).userKeyOfSocket,\n\t)!\n\t// const roomSocket = socket as TypedSocket<RoomSocketInterface<RoomNames>, {}>\n\tconst roomSocket = castSocket<TypedSocket<RoomSocketInterface<RoomNames>, {}>>(\n\t\tsocket,\n\t\tcreateRoomSocketGuard(roomNames),\n\t)\n\n\tconst exposeMutable = realtimeMutableProvider({ socket, store, userKey })\n\tconst exposeMutableFamily = realtimeMutableFamilyProvider({\n\t\tsocket,\n\t\tstore,\n\t\tuserKey,\n\t})\n\n\texposeMutable(roomKeysAtom)\n\n\tconst [, usersInRoomsAtoms] = getInternalRelationsFromStore(\n\t\tstore,\n\t\tusersInRooms,\n\t\t`split`,\n\t)\n\tconst usersWhoseRoomsCanBeSeenSelector = findInStore(\n\t\tstore,\n\t\tselfListSelectors,\n\t\tuserKey,\n\t)\n\texposeMutableFamily(usersInRoomsAtoms, usersWhoseRoomsCanBeSeenSelector)\n\t// const usersOfSocketsAtoms = getInternalRelationsFromStore(\n\t// \tstore,\n\t// \tusersOfSockets,\n\t// )\n\t// exposeMutableFamily(usersOfSocketsAtoms, socketKeysAtom)\n\tconst [ownersOfRoomsAtoms] = getInternalRelationsFromStore(\n\t\tstore,\n\t\townersOfRooms,\n\t\t`split`,\n\t)\n\texposeMutableFamily(ownersOfRoomsAtoms, usersWhoseRoomsCanBeSeenSelector)\n\n\tconst enterRoom = provideEnterAndExit({ store, socket, roomSocket, userKey })\n\n\tconst userRoomSet = getFromStore(store, usersInRoomsAtoms, userKey)\n\tfor (const userRoomKey of userRoomSet) {\n\t\tenterRoom(userRoomKey)\n\t\tbreak\n\t}\n\n\troomSocket.on(\n\t\t`createRoom`,\n\t\tspawnRoom({ store, socket, userKey, resolveRoomScript }),\n\t)\n\troomSocket.on(`deleteRoom`, destroyRoom({ store, socket, userKey }))\n\tsocket.on(`disconnect`, () => {\n\t\tstore.logger.info(\n\t\t\t`📡`,\n\t\t\t`socket`,\n\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t`👤 ${userKey} disconnects`,\n\t\t)\n\t\teditRelationsInStore(store, usersOfSockets, (rel) => rel.delete(socketKey))\n\t\tsetIntoStore(store, userKeysAtom, (keys) => (keys.delete(userKey), keys))\n\t\tsetIntoStore(store, socketKeysAtom, (keys) => (keys.delete(socketKey), keys))\n\t})\n}\n\nconst roomKeySchema: StandardSchemaV1<Json.Array, [RoomKey]> = {\n\t\"~standard\": {\n\t\tversion: 1,\n\t\tvendor: `atom.io`,\n\t\tvalidate: ([maybeRoomKey]: Json.Array) => {\n\t\t\tif (typeof maybeRoomKey === `string`) {\n\t\t\t\tif (isRoomKey(maybeRoomKey)) {\n\t\t\t\t\treturn { value: [maybeRoomKey] }\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tissues: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmessage: `Room key must start with \"room::\"`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tissues: [\n\t\t\t\t\t{\n\t\t\t\t\t\tmessage: `Room key must be a string`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t}\n\t\t},\n\t},\n}\n\nfunction createRoomSocketGuard<RoomNames extends string>(\n\troomNames: RoomNames[],\n): SocketGuard<RoomSocketInterface<RoomNames>> {\n\treturn {\n\t\tcreateRoom: {\n\t\t\t\"~standard\": {\n\t\t\t\tversion: 1,\n\t\t\t\tvendor: `atom.io`,\n\t\t\t\tvalidate: ([maybeRoomName]) => {\n\t\t\t\t\tif (roomNames.includes(maybeRoomName as RoomNames)) {\n\t\t\t\t\t\treturn { value: [maybeRoomName as RoomNames] }\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tissues: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\t\t`Room name must be one of the following:\\n - ` +\n\t\t\t\t\t\t\t\t\troomNames.join(`\\n - `),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tjoinRoom: roomKeySchema,\n\t\tdeleteRoom: roomKeySchema,\n\t\tleaveRoom: {\n\t\t\t\"~standard\": {\n\t\t\t\tversion: 1,\n\t\t\t\tvendor: `atom.io`,\n\t\t\t\tvalidate: () => ({ value: [] }),\n\t\t\t},\n\t\t},\n\t}\n}\n","import type { WritableToken } from \"atom.io\"\nimport {\n\tfindInStore,\n\tgetFromStore,\n\tIMPLICIT,\n\toperateOnStore,\n\tOWN_OP,\n\tsetIntoStore,\n\tsubscribeToState,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { employSocket, mutexAtoms } from \"atom.io/realtime\"\n\nimport type { ServerConfig } from \".\"\n\nexport type StateReceiver = ReturnType<typeof realtimeStateReceiver>\nexport function realtimeStateReceiver({\n\tsocket,\n\tstore = IMPLICIT.STORE,\n}: ServerConfig) {\n\treturn function stateReceiver<S extends Json.Serializable, C extends S>(\n\t\tclientToken: WritableToken<C>,\n\t\tserverToken: WritableToken<S> = clientToken,\n\t): () => void {\n\t\tconst mutexAtom = findInStore(store, mutexAtoms, serverToken.key)\n\n\t\tconst subscriptions = new Set<() => void>()\n\t\tconst clearSubscriptions = () => {\n\t\t\tfor (const unsub of subscriptions) unsub()\n\t\t\tsubscriptions.clear()\n\t\t}\n\n\t\tconst permitPublish = () => {\n\t\t\tclearSubscriptions()\n\t\t\tsubscriptions.add(\n\t\t\t\temploySocket(socket, `pub:${clientToken.key}`, (newValue) => {\n\t\t\t\t\tsetIntoStore(store, serverToken, newValue as C)\n\t\t\t\t}),\n\t\t\t)\n\t\t\tsubscriptions.add(\n\t\t\t\temploySocket(socket, `unclaim:${clientToken.key}`, () => {\n\t\t\t\t\tsetIntoStore(store, mutexAtom, false)\n\t\t\t\t\tclearSubscriptions()\n\t\t\t\t\tstart()\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\n\t\tconst start = () => {\n\t\t\tsubscriptions.add(\n\t\t\t\temploySocket(socket, `claim:${clientToken.key}`, () => {\n\t\t\t\t\tif (getFromStore(store, mutexAtom)) {\n\t\t\t\t\t\tclearSubscriptions()\n\t\t\t\t\t\tsubscriptions.add(\n\t\t\t\t\t\t\tsubscribeToState(store, mutexAtom, socket.id!, () => {\n\t\t\t\t\t\t\t\tconst currentValue = getFromStore(store, mutexAtom)\n\t\t\t\t\t\t\t\tif (currentValue === false) {\n\t\t\t\t\t\t\t\t\toperateOnStore(OWN_OP, store, mutexAtom, true)\n\t\t\t\t\t\t\t\t\tpermitPublish()\n\t\t\t\t\t\t\t\t\tsocket.emit(`claim-result:${clientToken.key}`, true)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tsocket.emit(`claim-result:${clientToken.key}`, false)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tsetIntoStore(store, mutexAtom, true)\n\t\t\t\t\tpermitPublish()\n\t\t\t\t\tsocket.emit(`claim-result:${clientToken.key}`, true)\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\n\t\tstart()\n\n\t\treturn clearSubscriptions\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["redactorAtoms: RegularAtomFamilyToken<\n\t{\n\t\tocclude: (updates: TransactionSubEvent[]) => TransactionSubEvent[]\n\t},\n\tUserKey\n>","unacknowledgedUpdatesAtoms: RegularAtomFamilyToken<\n\tContinuitySyncTransactionUpdate[],\n\tUserKey\n>","initialPayload: Json.Serializable[]","ROOMS: RoomMap","roomMeta: { count: number }","roomQueue: [string, ...Json.Array][]","forward: AllEventsListener<EventsMap>","roomKeySchema: StandardSchemaV1<Json.Array, [RoomKey]>","isAvailable","socketAtoms: RegularAtomFamilyToken<Socket | null, SocketKey>","socketKeysAtom: MutableAtomToken<UList<SocketKey>>","userKeysAtom: MutableAtomToken<UList<UserKey>>","usersOfSockets: JoinToken<\n\t`user`,\n\tUserKey,\n\t`socket`,\n\tSocketKey,\n\t`1:1`\n>","serverConfig: ServerConfig"],"sources":["../../src/realtime-server/continuity/continuity-store.ts","../../src/realtime-server/continuity/provide-outcomes.ts","../../src/realtime-server/continuity/provide-perspectives.ts","../../src/realtime-server/continuity/provide-startup-payloads.ts","../../src/realtime-server/continuity/receive-action-requests.ts","../../src/realtime-server/continuity/track-acknowledgements.ts","../../src/realtime-server/continuity/provide-continuity.ts","../../src/realtime-server/ipc-sockets/custom-socket.ts","../../src/realtime-server/ipc-sockets/child-socket.ts","../../src/realtime-server/ipc-sockets/parent-socket.ts","../../src/realtime-server/realtime-mutable-family-provider.ts","../../src/realtime-server/realtime-mutable-provider.ts","../../src/realtime-server/provide-rooms.ts","../../src/realtime-server/realtime-family-provider.ts","../../src/realtime-server/realtime-state-provider.ts","../../src/realtime-server/realtime-state-receiver.ts","../../src/realtime-server/server-socket-state.ts","../../src/realtime-server/server-config.ts"],"sourcesContent":["import type {\n\tRegularAtomFamilyToken,\n\tTransactionOutcomeEvent,\n\tTransactionSubEvent,\n} from \"atom.io\"\nimport { atomFamily } from \"atom.io\"\nimport type { UserKey } from \"atom.io/realtime\"\n\nexport function redactTransactionUpdateContent(\n\tvisibleStateKeys: string[],\n\tupdates: TransactionSubEvent[],\n): TransactionSubEvent[] {\n\treturn updates\n\t\t.map((update): TransactionSubEvent => {\n\t\t\tswitch (update.type) {\n\t\t\t\tcase `transaction_outcome`: {\n\t\t\t\t\tconst redacted = redactTransactionUpdateContent(\n\t\t\t\t\t\tvisibleStateKeys,\n\t\t\t\t\t\tupdate.subEvents,\n\t\t\t\t\t)\n\t\t\t\t\treturn { ...update, subEvents: redacted }\n\t\t\t\t}\n\t\t\t\tcase `atom_update`:\n\t\t\t\tcase `molecule_creation`:\n\t\t\t\tcase `molecule_disposal`:\n\t\t\t\tcase `molecule_transfer`:\n\t\t\t\tcase `state_creation`:\n\t\t\t\tcase `state_disposal`:\n\t\t\t\t\treturn update\n\t\t\t}\n\t\t})\n\t\t.filter((update) => {\n\t\t\tswitch (update.type) {\n\t\t\t\tcase `atom_update`:\n\t\t\t\tcase `state_creation`:\n\t\t\t\tcase `state_disposal`:\n\t\t\t\t\treturn visibleStateKeys.includes(update.token.key)\n\t\t\t\tcase `molecule_creation`:\n\t\t\t\tcase `transaction_outcome`:\n\t\t\t\tcase `molecule_disposal`:\n\t\t\t\tcase `molecule_transfer`:\n\t\t\t\t\treturn true\n\t\t\t}\n\t\t})\n}\n\nexport const redactorAtoms: RegularAtomFamilyToken<\n\t{\n\t\tocclude: (updates: TransactionSubEvent[]) => TransactionSubEvent[]\n\t},\n\tUserKey\n> = atomFamily({\n\tkey: `redactor`,\n\tdefault: { occlude: (updates) => updates },\n})\n\nexport type ContinuitySyncTransactionUpdate = Pick<\n\tTransactionOutcomeEvent<any>,\n\t`epoch` | `id` | `output` | `subEvents` | `token`\n>\nexport const unacknowledgedUpdatesAtoms: RegularAtomFamilyToken<\n\tContinuitySyncTransactionUpdate[],\n\tUserKey\n> = atomFamily({\n\tkey: `unacknowledgedUpdates`,\n\tdefault: () => [],\n})\n","import type { Store } from \"atom.io/internal\"\nimport {\n\tfindInStore,\n\tgetFromStore,\n\tgetUpdateToken,\n\tsetIntoStore,\n\tsubscribeToTransaction,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { ContinuityToken, Socket, UserKey } from \"atom.io/realtime\"\n\nimport {\n\tredactTransactionUpdateContent,\n\tunacknowledgedUpdatesAtoms,\n} from \"./continuity-store\"\n\nexport function provideOutcomes(\n\tstore: Store,\n\tsocket: Socket,\n\tcontinuity: ContinuityToken,\n\tuserKey: UserKey,\n): () => void {\n\tconst continuityKey = continuity.key\n\tconst unsubscribeFunctions = new Set<() => void>()\n\n\tfor (const transaction of continuity.actions) {\n\t\tconst unsubscribeFromTransaction = subscribeToTransaction(\n\t\t\tstore,\n\t\t\ttransaction,\n\t\t\t`sync-continuity:${continuityKey}:${userKey}`,\n\t\t\t(outcomes) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst visibleKeys = continuity.globals\n\t\t\t\t\t\t.map((atom) => {\n\t\t\t\t\t\t\tif (atom.type === `atom`) {\n\t\t\t\t\t\t\t\treturn atom.key\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn getUpdateToken(atom).key\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.concat(\n\t\t\t\t\t\t\tcontinuity.perspectives.flatMap((perspective) => {\n\t\t\t\t\t\t\t\tconst { viewAtoms } = perspective\n\t\t\t\t\t\t\t\tconst userPerspectiveTokenState = findInStore(\n\t\t\t\t\t\t\t\t\tstore,\n\t\t\t\t\t\t\t\t\tviewAtoms,\n\t\t\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tconst visibleTokens = getFromStore(\n\t\t\t\t\t\t\t\t\tstore,\n\t\t\t\t\t\t\t\t\tuserPerspectiveTokenState,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\treturn visibleTokens.map((token) => {\n\t\t\t\t\t\t\t\t\tconst key =\n\t\t\t\t\t\t\t\t\t\ttoken.type === `mutable_atom` ? `*` + token.key : token.key\n\t\t\t\t\t\t\t\t\treturn key\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\tconst redactedUpdates = redactTransactionUpdateContent(\n\t\t\t\t\t\tvisibleKeys,\n\t\t\t\t\t\toutcomes.subEvents,\n\t\t\t\t\t)\n\t\t\t\t\tconst redactedUpdate = {\n\t\t\t\t\t\t...outcomes,\n\t\t\t\t\t\tupdates: redactedUpdates,\n\t\t\t\t\t}\n\t\t\t\t\tsetIntoStore(store, unacknowledgedUpdatesAtoms, userKey, (updates) => {\n\t\t\t\t\t\tif (redactedUpdate) {\n\t\t\t\t\t\t\tupdates.push(redactedUpdate)\n\t\t\t\t\t\t\tupdates.sort((a, b) => a.epoch - b.epoch)\n\t\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t\t`👍`,\n\t\t\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t\t\t`${userKey} unacknowledged update queue now has`,\n\t\t\t\t\t\t\t\tupdates.length,\n\t\t\t\t\t\t\t\t`items`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn updates\n\t\t\t\t\t})\n\n\t\t\t\t\tsocket.emit(\n\t\t\t\t\t\t`tx-new:${continuityKey}`,\n\t\t\t\t\t\tredactedUpdate as Json.Serializable,\n\t\t\t\t\t)\n\t\t\t\t} catch (thrown) {\n\t\t\t\t\tif (thrown instanceof Error) {\n\t\t\t\t\t\tstore.logger.error(\n\t\t\t\t\t\t\t`❌`,\n\t\t\t\t\t\t\t`continuity`,\n\t\t\t\t\t\t\tcontinuityKey,\n\t\t\t\t\t\t\t`${userKey} failed to send update from transaction ${transaction.key} to ${userKey}`,\n\t\t\t\t\t\t\tthrown.message,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\t\tunsubscribeFunctions.add(unsubscribeFromTransaction)\n\t}\n\treturn () => {\n\t\tfor (const unsubscribe of unsubscribeFunctions) unsubscribe()\n\t}\n}\n","import type { Store } from \"atom.io/internal\"\nimport {\n\tfindInStore,\n\tgetFromStore,\n\tgetJsonToken,\n\tsubscribeToState,\n} from \"atom.io/internal\"\nimport type { ContinuityToken, Socket, UserKey } from \"atom.io/realtime\"\n\nexport function providePerspectives(\n\tstore: Store,\n\tsocket: Socket,\n\tcontinuity: ContinuityToken,\n\tuserKey: UserKey,\n): () => void {\n\tconst continuityKey = continuity.key\n\tconst unsubFns = new Set<() => void>()\n\tfor (const perspective of continuity.perspectives) {\n\t\tconst { viewAtoms } = perspective\n\t\tconst userViewState = findInStore(store, viewAtoms, userKey)\n\t\tconst unsubscribeFromUserView = subscribeToState(\n\t\t\tstore,\n\t\t\tuserViewState,\n\t\t\t`sync-continuity:${continuityKey}:${userKey}:perspective:${perspective.resourceAtoms.key}`,\n\t\t\t({ oldValue, newValue }) => {\n\t\t\t\tconst oldKeys = oldValue?.map((token) => token.key)\n\t\t\t\tconst newKeys = newValue.map((token) => token.key)\n\t\t\t\tconst concealed = oldValue?.filter(\n\t\t\t\t\t(token) => !newKeys.includes(token.key),\n\t\t\t\t)\n\t\t\t\tconst revealed = newValue\n\t\t\t\t\t.filter((token) => !oldKeys?.includes(token.key))\n\t\t\t\t\t.flatMap((token) => {\n\t\t\t\t\t\tconst resourceToken =\n\t\t\t\t\t\t\ttoken.type === `mutable_atom` ? getJsonToken(store, token) : token\n\t\t\t\t\t\tconst resource = getFromStore(store, resourceToken)\n\t\t\t\t\t\treturn [resourceToken, resource]\n\t\t\t\t\t})\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`👁`,\n\t\t\t\t\t`atom`,\n\t\t\t\t\tperspective.resourceAtoms.key,\n\t\t\t\t\t`${userKey} has a new perspective`,\n\t\t\t\t\t{ oldKeys, newKeys, revealed, concealed },\n\t\t\t\t)\n\t\t\t\tif (revealed.length > 0) {\n\t\t\t\t\tsocket.emit(`reveal:${continuityKey}`, revealed)\n\t\t\t\t}\n\t\t\t\tif (concealed && concealed.length > 0) {\n\t\t\t\t\tsocket.emit(`conceal:${continuityKey}`, concealed)\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\t\tunsubFns.add(unsubscribeFromUserView)\n\t}\n\treturn () => {\n\t\tfor (const unsubscribe of unsubFns) unsubscribe()\n\t}\n}\n","import type { Store } from \"atom.io/internal\"\nimport {\n\tfindInStore,\n\tgetFromStore,\n\tgetJsonToken,\n\tisRootStore,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { ContinuityToken, Socket, UserKey } from \"atom.io/realtime\"\nimport { employSocket } from \"atom.io/realtime\"\n\nexport function provideStartupPayloads(\n\tstore: Store,\n\tsocket: Socket,\n\tcontinuity: ContinuityToken,\n\tuserKey: UserKey,\n): () => void {\n\tconst continuityKey = continuity.key\n\tfunction sendInitialPayload(): void {\n\t\tconst initialPayload: Json.Serializable[] = []\n\t\tfor (const atom of continuity.globals) {\n\t\t\tconst resourceToken =\n\t\t\t\tatom.type === `mutable_atom` ? getJsonToken(store, atom) : atom\n\t\t\tconst resource = getFromStore(store, resourceToken)\n\t\t\tinitialPayload.push(resourceToken, resource)\n\t\t}\n\t\tfor (const perspective of continuity.perspectives) {\n\t\t\tconst { viewAtoms, resourceAtoms } = perspective\n\t\t\tconst userViewState = findInStore(store, viewAtoms, userKey)\n\t\t\tconst userView = getFromStore(store, userViewState)\n\t\t\tstore.logger.info(`👁`, `atom`, resourceAtoms.key, `${userKey} can see`, {\n\t\t\t\tviewAtoms,\n\t\t\t\tresourceAtoms,\n\t\t\t\tuserView,\n\t\t\t})\n\t\t\tfor (const visibleToken of userView) {\n\t\t\t\tconst resourceToken =\n\t\t\t\t\tvisibleToken.type === `mutable_atom`\n\t\t\t\t\t\t? getJsonToken(store, visibleToken)\n\t\t\t\t\t\t: visibleToken\n\t\t\t\tconst resource = getFromStore(store, resourceToken)\n\n\t\t\t\tinitialPayload.push(resourceToken, resource)\n\t\t\t}\n\t\t}\n\n\t\tconst epoch = isRootStore(store)\n\t\t\t? (store.transactionMeta.epoch.get(continuityKey) ?? null)\n\t\t\t: null\n\n\t\tsocket.emit(`continuity-init:${continuityKey}`, epoch, initialPayload)\n\t}\n\treturn employSocket(socket, `get:${continuityKey}`, sendInitialPayload)\n}\n","import type { TransactionOutcomeEvent, TransactionToken } from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { actUponStore } from \"atom.io/internal\"\nimport type { Json, JsonIO } from \"atom.io/json\"\nimport type { ContinuityToken, Socket } from \"atom.io/realtime\"\nimport { employSocket } from \"atom.io/realtime\"\n\nexport function receiveActionRequests(\n\tstore: Store,\n\tsocket: Socket,\n\tcontinuity: ContinuityToken,\n\tuserKey: string,\n): () => void {\n\tconst continuityKey = continuity.key\n\n\treturn employSocket(\n\t\tsocket,\n\t\t`tx-run:${continuityKey}`,\n\t\tfunction serveTransactionRequest(\n\t\t\ttxOutcome: Json.Serializable &\n\t\t\t\tPick<\n\t\t\t\t\tTransactionOutcomeEvent<TransactionToken<JsonIO>>,\n\t\t\t\t\t`id` | `params` | `token`\n\t\t\t\t>,\n\t\t) {\n\t\t\tstore.logger.info(`🛎️`, `continuity`, continuityKey, `received`, txOutcome)\n\t\t\tconst transactionKey = txOutcome.token.key\n\t\t\tconst updateId = txOutcome.id\n\t\t\tconst performanceKey = `tx-run:${transactionKey}:${updateId}`\n\t\t\tconst performanceKeyStart = `${performanceKey}:start`\n\t\t\tconst performanceKeyEnd = `${performanceKey}:end`\n\t\t\tperformance.mark(performanceKeyStart)\n\t\t\ttry {\n\t\t\t\tactUponStore(\n\t\t\t\t\tstore,\n\t\t\t\t\t{ type: `transaction`, key: transactionKey },\n\t\t\t\t\tupdateId,\n\t\t\t\t)(...txOutcome.params)\n\t\t\t} catch (thrown) {\n\t\t\t\tif (thrown instanceof Error) {\n\t\t\t\t\tstore.logger.error(\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`failed to run transaction ${transactionKey} from ${userKey} with update ${updateId}`,\n\t\t\t\t\t\tthrown.message,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t\tperformance.mark(performanceKeyEnd)\n\t\t\tconst metric = performance.measure(\n\t\t\t\tperformanceKey,\n\t\t\t\tperformanceKeyStart,\n\t\t\t\tperformanceKeyEnd,\n\t\t\t)\n\t\t\tstore.logger.info(\n\t\t\t\t`🚀`,\n\t\t\t\t`transaction`,\n\t\t\t\ttransactionKey,\n\t\t\t\tupdateId,\n\t\t\t\tuserKey,\n\t\t\t\tmetric.duration,\n\t\t\t)\n\t\t},\n\t)\n}\n","import type { Store } from \"atom.io/internal\"\nimport { getFromStore, setIntoStore } from \"atom.io/internal\"\nimport type { ContinuityToken, Socket, UserKey } from \"atom.io/realtime\"\nimport { employSocket } from \"atom.io/realtime\"\n\nimport { unacknowledgedUpdatesAtoms } from \"./continuity-store\"\n\nexport function trackAcknowledgements(\n\tstore: Store,\n\tsocket: Socket,\n\tcontinuity: ContinuityToken,\n\tuserKey: UserKey,\n): () => void {\n\tconst continuityKey = continuity.key\n\tconst userUnacknowledgedUpdates = getFromStore(\n\t\tstore,\n\t\tunacknowledgedUpdatesAtoms,\n\t\tuserKey,\n\t)\n\tfunction trackClientAcknowledgement(epoch: number): void {\n\t\tstore.logger.info(\n\t\t\t`👍`,\n\t\t\t`continuity`,\n\t\t\tcontinuityKey,\n\t\t\t`${userKey} acknowledged epoch ${epoch}`,\n\t\t)\n\t\tconst isUnacknowledged = userUnacknowledgedUpdates[0]?.epoch === epoch\n\t\tif (isUnacknowledged) {\n\t\t\tsetIntoStore(store, unacknowledgedUpdatesAtoms, userKey, (updates) => {\n\t\t\t\tupdates.shift()\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`${userKey} unacknowledged update queue now has`,\n\t\t\t\t\tupdates.length,\n\t\t\t\t\t`items`,\n\t\t\t\t)\n\t\t\t\treturn updates\n\t\t\t})\n\t\t}\n\t}\n\treturn employSocket(socket, `ack:${continuityKey}`, trackClientAcknowledgement)\n}\n","import { getFromStore, IMPLICIT } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { ContinuityToken, UserKey } from \"atom.io/realtime\"\n\nimport type { ServerConfig } from \"..\"\nimport { unacknowledgedUpdatesAtoms } from \"./continuity-store\"\nimport { provideOutcomes } from \"./provide-outcomes\"\nimport { providePerspectives } from \"./provide-perspectives\"\nimport { provideStartupPayloads } from \"./provide-startup-payloads\"\nimport { receiveActionRequests } from \"./receive-action-requests\"\nimport { trackAcknowledgements } from \"./track-acknowledgements\"\n\nexport type ProvideContinuity = (\n\tcontinuity: ContinuityToken,\n\tuserKey: UserKey,\n) => () => void\nexport function prepareToProvideContinuity({\n\tsocket,\n\tstore = IMPLICIT.STORE,\n}: ServerConfig): ProvideContinuity {\n\treturn function syncRealtimeContinuity(continuity, userKey) {\n\t\tconst continuityKey = continuity.key\n\n\t\tconst unacknowledgedUpdates = getFromStore(\n\t\t\tstore,\n\t\t\tunacknowledgedUpdatesAtoms,\n\t\t\tuserKey,\n\t\t)\n\t\tfor (const unacknowledgedUpdate of unacknowledgedUpdates) {\n\t\t\tsocket.emit(\n\t\t\t\t`tx-new:${continuityKey}`,\n\t\t\t\tunacknowledgedUpdate as Json.Serializable,\n\t\t\t)\n\t\t}\n\n\t\tconst subscriptions = new Set<() => void>()\n\t\tconst clearSubscriptions = () => {\n\t\t\tfor (const unsubscribe of subscriptions) unsubscribe()\n\t\t\tsubscriptions.clear()\n\t\t}\n\n\t\tsubscriptions.add(providePerspectives(store, socket, continuity, userKey))\n\t\tsubscriptions.add(provideOutcomes(store, socket, continuity, userKey))\n\t\tsubscriptions.add(provideStartupPayloads(store, socket, continuity, userKey))\n\t\tsubscriptions.add(receiveActionRequests(store, socket, continuity, userKey))\n\t\tsubscriptions.add(trackAcknowledgements(store, socket, continuity, userKey))\n\n\t\treturn clearSubscriptions\n\t}\n}\n","import type { Json, stringified } from \"atom.io/json\"\nimport type { Socket } from \"atom.io/realtime\"\n\nexport type Events = Json.Object<string, Json.Serializable[]>\n\nexport type EventPayload<\n\treceiveRelay extends Events,\n\tK extends string & keyof receiveRelay = string & keyof receiveRelay,\n> = [string, ...receiveRelay[K]]\n\nexport interface EventBuffer<\n\tE extends Events,\n\tK extends string & keyof E = string & keyof E,\n> extends Buffer {\n\ttoString(): stringified<EventPayload<E, K>>\n}\n\nexport abstract class CustomSocket<I extends Events, O extends Events>\n\timplements Socket\n{\n\tprotected listeners: Map<keyof O, Set<(...args: Json.Array) => void>>\n\tprotected globalListeners: Set<(event: string, ...args: Json.Array) => void>\n\tprotected globalListenersOutgoing: Set<\n\t\t(event: string, ...args: Json.Array) => void\n\t>\n\tprotected handleEvent<K extends string & keyof I>(\n\t\t...args: EventPayload<I, K>\n\t): void {\n\t\tconst [event, ...rest] = args\n\t\tfor (const listener of this.globalListeners) {\n\t\t\tlistener(event, ...rest)\n\t\t}\n\t\tconst listeners = this.listeners.get(event)\n\t\tif (listeners) {\n\t\t\tfor (const listener of listeners) {\n\t\t\t\tlistener(...rest)\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic id = `no_id_retrieved`\n\tpublic emit: <Event extends string & keyof I>(\n\t\tevent: Event,\n\t\t...args: I[Event]\n\t) => CustomSocket<I, O>\n\n\tpublic constructor(\n\t\temit: <Event extends keyof I>(\n\t\t\tevent: Event,\n\t\t\t...args: I[Event]\n\t\t) => CustomSocket<I, O>,\n\t) {\n\t\tthis.emit = (...args) => {\n\t\t\tfor (const listener of this.globalListenersOutgoing) {\n\t\t\t\tlistener(...args)\n\t\t\t}\n\t\t\treturn emit(...args)\n\t\t}\n\t\tthis.listeners = new Map()\n\t\tthis.globalListeners = new Set()\n\t\tthis.globalListenersOutgoing = new Set()\n\t}\n\n\tpublic on<Event extends keyof O>(\n\t\tevent: Event,\n\t\tlistener: (...args: O[Event]) => void,\n\t): this {\n\t\tconst listeners = this.listeners.get(event)\n\t\tif (listeners) {\n\t\t\tlisteners.add(listener)\n\t\t} else {\n\t\t\tthis.listeners.set(event, new Set([listener]))\n\t\t}\n\t\treturn this\n\t}\n\n\tpublic onAny(listener: (event: string, ...args: Json.Array) => void): this {\n\t\tthis.globalListeners.add(listener)\n\t\treturn this\n\t}\n\n\tpublic onAnyOutgoing(\n\t\tlistener: (event: string, ...args: Json.Array) => void,\n\t): this {\n\t\tthis.globalListenersOutgoing.add(listener)\n\t\treturn this\n\t}\n\n\tpublic off<Event extends keyof O>(\n\t\tevent: Event,\n\t\tlistener?: (...args: O[Event]) => void,\n\t): this {\n\t\tconst listeners = this.listeners.get(event)\n\t\tif (listeners) {\n\t\t\tif (listener) {\n\t\t\t\tlisteners.delete(listener)\n\t\t\t} else {\n\t\t\t\tthis.listeners.delete(event)\n\t\t\t}\n\t\t}\n\t\treturn this\n\t}\n\n\tpublic offAny(listener: (event: string, ...args: Json.Array) => void): this {\n\t\tthis.globalListeners.delete(listener)\n\t\treturn this\n\t}\n}\n","import type { Readable, Writable } from \"node:stream\"\n\nimport type { Json, stringified } from \"atom.io/json\"\nimport { parseJson } from \"atom.io/json\"\n\nimport type { EventBuffer, EventPayload, Events } from \"./custom-socket\"\nimport { CustomSocket } from \"./custom-socket\"\n\n/* eslint-disable no-console */\n\nexport type ChildProcess = {\n\tpid?: number | undefined\n\tstdin: Writable\n\tstdout: Readable\n\tstderr: Readable\n}\n\nexport type StderrLog = [`e` | `i` | `w`, ...Json.Array]\n\nexport class ChildSocket<\n\tI extends Events,\n\tO extends Events,\n\tP extends ChildProcess = ChildProcess,\n> extends CustomSocket<I, O> {\n\tprotected incompleteData = ``\n\tprotected unprocessedEvents: string[] = []\n\tprotected incompleteLog = ``\n\tprotected unprocessedLogs: string[] = []\n\n\tpublic id = `#####`\n\n\tpublic proc: P\n\tpublic key: string\n\tpublic logger: Pick<Console, `error` | `info` | `warn`>\n\n\tprotected handleLog(log: StderrLog): void {\n\t\tif (Array.isArray(log)) {\n\t\t\tconst [level, ...rest] = log\n\t\t\tswitch (level) {\n\t\t\t\tcase `i`:\n\t\t\t\t\tthis.logger.info(...rest)\n\t\t\t\t\tbreak\n\t\t\t\tcase `w`:\n\t\t\t\t\tthis.logger.warn(...rest)\n\t\t\t\t\tbreak\n\t\t\t\tcase `e`:\n\t\t\t\t\tthis.logger.error(...rest)\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic constructor(\n\t\tproc: P,\n\t\tkey: string,\n\t\tlogger?: Pick<Console, `error` | `info` | `warn`>,\n\t) {\n\t\tsuper((event, ...args) => {\n\t\t\tconst stringifiedEvent = JSON.stringify([event, ...args]) + `\\x03`\n\t\t\tconst errorHandler = (err: { code: string }) => {\n\t\t\t\tif (err.code === `EPIPE`) {\n\t\t\t\t\tconsole.error(`EPIPE error during write`, this.proc.stdin)\n\t\t\t\t}\n\t\t\t\tthis.proc.stdin.removeListener(`error`, errorHandler)\n\t\t\t}\n\n\t\t\tthis.proc.stdin.once(`error`, errorHandler)\n\t\t\tthis.proc.stdin.write(stringifiedEvent)\n\n\t\t\treturn this\n\t\t})\n\t\tthis.proc = proc\n\t\tthis.key = key\n\t\tthis.logger = logger ?? {\n\t\t\tinfo: (...args: unknown[]) => {\n\t\t\t\tconsole.info(this.id, this.key, ...args)\n\t\t\t},\n\t\t\twarn: (...args: unknown[]) => {\n\t\t\t\tconsole.warn(this.id, this.key, ...args)\n\t\t\t},\n\t\t\terror: (...args: unknown[]) => {\n\t\t\t\tconsole.error(this.id, this.key, ...args)\n\t\t\t},\n\t\t}\n\t\tthis.proc.stdout.on(\n\t\t\t`data`,\n\t\t\t<K extends string & keyof I>(buffer: EventBuffer<I, K>) => {\n\t\t\t\tconst chunk = buffer.toString()\n\n\t\t\t\tif (chunk === `ALIVE`) {\n\t\t\t\t\tthis.logger.info(chunk)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst pieces = chunk.split(`\\x03`)\n\t\t\t\tconst initialMaybeWellFormed = pieces[0]\n\t\t\t\tpieces[0] = this.incompleteData + initialMaybeWellFormed\n\t\t\t\tlet idx = 0\n\t\t\t\tfor (const piece of pieces) {\n\t\t\t\t\tif (piece === ``) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst jsonPiece = parseJson(piece as stringified<EventPayload<I, K>>)\n\t\t\t\t\t\tthis.handleEvent(...jsonPiece)\n\t\t\t\t\t\tthis.incompleteData = ``\n\t\t\t\t\t} catch (thrown0) {\n\t\t\t\t\t\tif (thrown0 instanceof Error) {\n\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t`❌ Malformed data received from child process`,\n\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\tpiece,\n\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\tthrown0.message,\n\t\t\t\t\t\t\t\t].join(`\\n❌\\t`),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (idx === 0) {\n\t\t\t\t\t\t\t\tthis.incompleteData = piece\n\t\t\t\t\t\t\t\tconst maybeActualJsonPiece = parseJson(\n\t\t\t\t\t\t\t\t\tinitialMaybeWellFormed as stringified<EventPayload<I, K>>,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tthis.handleEvent(...maybeActualJsonPiece)\n\t\t\t\t\t\t\t\tthis.incompleteData = ``\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.incompleteData += piece\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (thrown1) {\n\t\t\t\t\t\t\tif (thrown1 instanceof Error) {\n\t\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t`❌ Malformed data received from child process`,\n\t\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\t\tinitialMaybeWellFormed,\n\t\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\t\tthrown1.message,\n\t\t\t\t\t\t\t\t\t].join(`\\n❌\\t`),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t++idx\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\t\tthis.proc.stderr.on(`data`, (buffer: Buffer) => {\n\t\t\tconst chunk = buffer.toString()\n\t\t\tconst pieces = chunk.split(`\\x03`)\n\t\t\tconst initialMaybeWellFormed = pieces[0]\n\t\t\tpieces[0] = this.incompleteData + initialMaybeWellFormed\n\t\t\tlet idx = 0\n\t\t\tfor (const piece of pieces) {\n\t\t\t\tif (piece === ``) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst jsonPiece = parseJson(piece as stringified<StderrLog>)\n\t\t\t\t\tthis.handleLog(jsonPiece)\n\t\t\t\t\tthis.incompleteData = ``\n\t\t\t\t} catch (thrown0) {\n\t\t\t\t\tif (thrown0 instanceof Error) {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t`❌ Malformed log received from child process`,\n\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\tpiece,\n\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\tthrown0.message,\n\t\t\t\t\t\t\t].join(`\\n❌\\t`),\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (idx === 0) {\n\t\t\t\t\t\t\tthis.incompleteData = piece\n\t\t\t\t\t\t\tconst maybeActualJsonPiece = parseJson(\n\t\t\t\t\t\t\t\tinitialMaybeWellFormed as stringified<StderrLog>,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tthis.handleLog(maybeActualJsonPiece)\n\t\t\t\t\t\t\tthis.incompleteData = ``\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.incompleteData += piece\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (thrown1) {\n\t\t\t\t\t\tif (thrown1 instanceof Error) {\n\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t`❌ Malformed log received from child process...`,\n\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\tinitialMaybeWellFormed,\n\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\tthrown1.message,\n\t\t\t\t\t\t\t\t].join(`\\n❌\\t`),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t++idx\n\t\t\t}\n\t\t})\n\t\tif (proc.pid) {\n\t\t\tthis.id = proc.pid.toString()\n\t\t}\n\t}\n}\n","import type { Readable, Writable } from \"node:stream\"\n\nimport { Subject } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { parseJson, stringifyJson } from \"atom.io/json\"\nimport type { UserKey } from \"atom.io/realtime\"\nimport { UList } from \"atom.io/transceivers/u-list\"\n\nimport type { StderrLog } from \"./child-socket\"\nimport type { EventBuffer, EventPayload, Events } from \"./custom-socket\"\nimport { CustomSocket } from \"./custom-socket\"\n\nexport class SubjectSocket<\n\tI extends Events,\n\tO extends Events,\n> extends CustomSocket<I, O> {\n\tpublic in: Subject<EventPayload<I>>\n\tpublic out: Subject<EventPayload<O>>\n\tpublic id = `no_id_retrieved`\n\tpublic disposalFunctions: (() => void)[] = []\n\n\tpublic constructor(id: string) {\n\t\tsuper((...args) => {\n\t\t\tthis.out.next(args as any)\n\t\t\treturn this\n\t\t})\n\t\tthis.id = id\n\t\tthis.in = new Subject()\n\t\tthis.out = new Subject()\n\t\tthis.in.subscribe(`socket`, (event) => {\n\t\t\tthis.handleEvent(...event)\n\t\t})\n\t}\n\n\tpublic dispose(): void {\n\t\tfor (const dispose of this.disposalFunctions) {\n\t\t\tdispose()\n\t\t}\n\t}\n}\n\nexport type ParentProcess = {\n\tpid?: number | undefined\n\tstdin: Readable\n\tstdout: Writable\n\tstderr: Writable\n\texit: (code?: number) => void\n}\n\nexport class ParentSocket<\n\tI extends Events & {\n\t\t[id in string as `relay::${id}`]: [string, ...Json.Array[]]\n\t},\n\tO extends Events & {\n\t\t[id in string as `user::${id}`]: [string, ...Json.Array[]]\n\t} & {\n\t\t/* eslint-disable quotes */\n\t\t\"user-joins\": [key: UserKey]\n\t\t\"user-leaves\": [key: UserKey]\n\t\t/* eslint-enable quotes */\n\t},\n\tP extends ParentProcess = ParentProcess,\n> extends CustomSocket<I, O> {\n\tprotected incompleteData = ``\n\tprotected unprocessedEvents: string[] = []\n\tprotected relays: Map<string, SubjectSocket<any, any>>\n\tprotected relayServices: ((\n\t\tsocket: SubjectSocket<any, any>,\n\t\tuserKey: UserKey,\n\t) => (() => void) | void)[]\n\tpublic proc: P\n\n\tpublic id = `#####`\n\n\tprotected log(...args: StderrLog): void {\n\t\tthis.proc.stderr.write(\n\t\t\tstringifyJson(\n\t\t\t\targs.map((arg) =>\n\t\t\t\t\targ instanceof UList ? `{ ${arg.toJSON().join(` | `)} }` : arg,\n\t\t\t\t),\n\t\t\t) + `\\x03`,\n\t\t)\n\t}\n\tpublic logger = {\n\t\tinfo: (...args: Json.Array): void => {\n\t\t\tthis.log(`i`, ...args)\n\t\t},\n\t\twarn: (...args: Json.Array): void => {\n\t\t\tthis.log(`w`, ...args)\n\t\t},\n\t\terror: (...args: Json.Array): void => {\n\t\t\tthis.log(`e`, ...args)\n\t\t},\n\t}\n\n\tpublic constructor(proc: P) {\n\t\tsuper((event, ...args) => {\n\t\t\tconst stringifiedEvent = JSON.stringify([event, ...args])\n\t\t\tthis.proc.stdout.write(stringifiedEvent + `\\x03`)\n\t\t\treturn this\n\t\t})\n\t\tthis.proc = proc\n\t\tthis.proc.stdin.resume()\n\t\tthis.relays = new Map()\n\t\tthis.relayServices = []\n\n\t\tthis.proc.stdin.on(\n\t\t\t`data`,\n\t\t\t<K extends string & keyof I>(buffer: EventBuffer<I, K>) => {\n\t\t\t\tconst chunk = buffer.toString()\n\t\t\t\tconst pieces = chunk.split(`\\x03`)\n\t\t\t\tconst initialMaybeWellFormed = pieces[0]\n\t\t\t\tpieces[0] = this.incompleteData + initialMaybeWellFormed\n\t\t\t\tlet idx = 0\n\t\t\t\tfor (const piece of pieces) {\n\t\t\t\t\tif (piece === ``) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst jsonPiece = parseJson(piece)\n\t\t\t\t\t\tthis.logger.info(`🎰`, `received`, jsonPiece)\n\t\t\t\t\t\tthis.handleEvent(...(jsonPiece as EventPayload<I>))\n\t\t\t\t\t\tthis.incompleteData = ``\n\t\t\t\t\t} catch (thrown0) {\n\t\t\t\t\t\tif (thrown0 instanceof Error) {\n\t\t\t\t\t\t\tthis.logger.error(\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t`received malformed data from parent process:`,\n\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\tpiece,\n\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\tthrown0.message,\n\t\t\t\t\t\t\t\t].join(`\\n❌\\t`),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (idx === 0) {\n\t\t\t\t\t\t\t\tthis.incompleteData = piece\n\t\t\t\t\t\t\t\tconst maybeActualJsonPiece = parseJson(initialMaybeWellFormed)\n\t\t\t\t\t\t\t\tthis.logger.info(`🎰`, `received`, maybeActualJsonPiece)\n\t\t\t\t\t\t\t\tthis.handleEvent(...(maybeActualJsonPiece as EventPayload<I>))\n\t\t\t\t\t\t\t\tthis.incompleteData = ``\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.incompleteData += piece\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (thrown1) {\n\t\t\t\t\t\t\tif (thrown1 instanceof Error) {\n\t\t\t\t\t\t\t\tthis.logger.error(\n\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t`received malformed data from parent process:`,\n\t\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\t\tinitialMaybeWellFormed,\n\t\t\t\t\t\t\t\t\t\t``,\n\t\t\t\t\t\t\t\t\t\tthrown1.message,\n\t\t\t\t\t\t\t\t\t].join(`\\n❌\\t`),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t++idx\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\n\t\tthis.on(`exit`, () => {\n\t\t\tthis.logger.info(`🔥`, this.id, `received \"exit\"`)\n\t\t\tthis.proc.exit(0)\n\t\t})\n\n\t\tif (this.proc.pid) {\n\t\t\tthis.id = this.proc.pid?.toString()\n\t\t}\n\n\t\tthis.on(`user-joins`, (userKey: UserKey) => {\n\t\t\tthis.logger.info(`👤`, `user`, userKey, `joined`)\n\t\t\tconst relay = new SubjectSocket(userKey)\n\t\t\tthis.relays.set(userKey, relay)\n\t\t\tthis.logger.info(\n\t\t\t\t`🔗`,\n\t\t\t\t`attaching services:`,\n\t\t\t\t`[${[...this.relayServices.keys()].join(`, `)}]`,\n\t\t\t)\n\t\t\tfor (const attachRelay of this.relayServices) {\n\t\t\t\tconst cleanupRelay = attachRelay(relay, userKey)\n\t\t\t\tif (cleanupRelay) {\n\t\t\t\t\trelay.disposalFunctions.push(cleanupRelay)\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.on(userKey, (...data) => {\n\t\t\t\trelay.in.next(data)\n\t\t\t})\n\t\t\trelay.out.subscribe(`socket`, (data) => {\n\t\t\t\tthis.emit(...(data as [string, ...I[string & keyof I]]))\n\t\t\t})\n\t\t})\n\n\t\tthis.on(`user-leaves`, (username) => {\n\t\t\tconst relay = this.relays.get(username)\n\t\t\tthis.off(`relay:${username}`)\n\t\t\tif (relay) {\n\t\t\t\trelay.dispose()\n\t\t\t\tthis.relays.delete(username)\n\t\t\t}\n\t\t})\n\n\t\tthis.proc.stdout.write(`ALIVE`)\n\t}\n\n\tpublic receiveRelay(\n\t\tattachServices: (\n\t\t\tsocket: SubjectSocket<any, any>,\n\t\t\tuserKey: UserKey,\n\t\t) => (() => void) | void,\n\t): void {\n\t\tthis.logger.info(`🔗`, `running relay method`)\n\t\tthis.relayServices.push(attachServices)\n\t}\n}\n","import type * as AtomIO from \"atom.io\"\nimport type { Transceiver } from \"atom.io/internal\"\nimport {\n\tfindInStore,\n\tgetFromStore,\n\tgetJsonToken,\n\tgetUpdateToken,\n\tIMPLICIT,\n\tsubscribeToState,\n} from \"atom.io/internal\"\nimport type { Canonical, stringified } from \"atom.io/json\"\nimport { stringifyJson } from \"atom.io/json\"\nimport { employSocket } from \"atom.io/realtime\"\n\nimport type { ServerConfig } from \".\"\n\nconst isAvailable = <K extends Canonical>(\n\texposedSubKeys: Iterable<K>,\n\tsubKey: K,\n): boolean => {\n\tfor (const exposedSubKey of exposedSubKeys) {\n\t\tif (stringifyJson(exposedSubKey) === stringifyJson(subKey)) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nexport type MutableFamilyProvider = ReturnType<\n\ttypeof realtimeMutableFamilyProvider\n>\nexport function realtimeMutableFamilyProvider({\n\tsocket,\n\tuserKey,\n\tstore = IMPLICIT.STORE,\n}: ServerConfig) {\n\treturn function mutableFamilyProvider<\n\t\tT extends Transceiver<any, any, any>,\n\t\tK extends Canonical,\n\t>(\n\t\tfamily: AtomIO.MutableAtomFamilyToken<T, K>,\n\t\tindex: AtomIO.ReadableToken<Iterable<NoInfer<K>>>,\n\t): () => void {\n\t\tconst coreSubscriptions = new Set<() => void>()\n\t\tconst clearCoreSubscriptions = () => {\n\t\t\tfor (const unsub of coreSubscriptions) unsub()\n\t\t\tcoreSubscriptions.clear()\n\t\t}\n\t\tconst familyMemberSubscriptionsWanted = new Set<stringified<K>>()\n\t\tconst familyMemberSubscriptions = new Map<string, () => void>()\n\t\tconst clearFamilySubscriptions = () => {\n\t\t\tfor (const unsub of familyMemberSubscriptions.values()) unsub()\n\t\t\tfamilyMemberSubscriptions.clear()\n\t\t}\n\n\t\tconst fillUnsubRequest = (key: string) => {\n\t\t\tconst unsubUnsub = familyMemberSubscriptions.get(`${key}:unsub`)\n\t\t\tif (unsubUnsub) {\n\t\t\t\tunsubUnsub()\n\t\t\t\tfamilyMemberSubscriptions.delete(`${key}:unsub`)\n\t\t\t}\n\t\t\tconst unsub = familyMemberSubscriptions.get(key)\n\t\t\tif (unsub) {\n\t\t\t\tunsub()\n\t\t\t\tfamilyMemberSubscriptions.delete(key)\n\t\t\t}\n\t\t}\n\n\t\tconst exposeFamilyMembers = (subKey: K) => {\n\t\t\tconst token = findInStore(store, family, subKey)\n\t\t\tgetFromStore(store, token)\n\t\t\tconst jsonToken = getJsonToken(store, token)\n\t\t\tconst updateToken = getUpdateToken(token)\n\t\t\tsocket.emit(`init:${token.key}`, getFromStore(store, jsonToken))\n\t\t\tfamilyMemberSubscriptions.set(\n\t\t\t\ttoken.key,\n\t\t\t\tsubscribeToState(\n\t\t\t\t\tstore,\n\t\t\t\t\tupdateToken,\n\t\t\t\t\t`expose-family:${family.key}:${socket.id}`,\n\t\t\t\t\t({ newValue }) => {\n\t\t\t\t\t\tsocket.emit(`next:${token.key}`, newValue)\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\t\t\tfamilyMemberSubscriptions.set(\n\t\t\t\t`${token.key}:unsub`,\n\t\t\t\temploySocket(socket, `unsub:${token.key}`, () => {\n\t\t\t\t\tfillUnsubRequest(token.key)\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\n\t\tconst start = () => {\n\t\t\tstore.logger.info(\n\t\t\t\t`👀`,\n\t\t\t\t`user`,\n\t\t\t\tuserKey,\n\t\t\t\t`can subscribe to family \"${family.key}\"`,\n\t\t\t)\n\t\t\tcoreSubscriptions.add(\n\t\t\t\temploySocket(socket, `sub:${family.key}`, (subKey: K) => {\n\t\t\t\t\tconst exposedSubKeys = getFromStore(store, index)\n\t\t\t\t\tconst shouldExpose = isAvailable(exposedSubKeys, subKey)\n\t\t\t\t\tif (shouldExpose) {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`is approved for a subscription to`,\n\t\t\t\t\t\t\tsubKey,\n\t\t\t\t\t\t\t`in family \"${family.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\texposeFamilyMembers(subKey)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`❌`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`is denied for a subscription to`,\n\t\t\t\t\t\t\tsubKey,\n\t\t\t\t\t\t\t`in family \"${family.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tfamilyMemberSubscriptionsWanted.add(stringifyJson(subKey))\n\t\t\t\t\t\tsocket.emit(`unavailable:${family.key}`, subKey)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t)\n\t\t\tcoreSubscriptions.add(\n\t\t\t\tsubscribeToState(\n\t\t\t\t\tstore,\n\t\t\t\t\tindex,\n\t\t\t\t\t`expose-family:${family.key}:${socket.id}`,\n\t\t\t\t\t({ newValue: newExposedSubKeys }) => {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`has the following keys available for family \"${family.key}\"`,\n\t\t\t\t\t\t\tnewExposedSubKeys,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tfor (const subKey of newExposedSubKeys) {\n\t\t\t\t\t\t\tif (familyMemberSubscriptionsWanted.has(stringifyJson(subKey))) {\n\t\t\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t\t\t`is retroactively approved for a subscription to`,\n\t\t\t\t\t\t\t\t\tsubKey,\n\t\t\t\t\t\t\t\t\t`in family \"${family.key}\"`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\texposeFamilyMembers(subKey)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\n\t\tstart()\n\n\t\treturn () => {\n\t\t\tclearCoreSubscriptions()\n\t\t\tclearFamilySubscriptions()\n\t\t}\n\t}\n}\n","import type * as AtomIO from \"atom.io\"\nimport type { Transceiver } from \"atom.io/internal\"\nimport {\n\tgetFromStore,\n\tgetJsonToken,\n\tgetUpdateToken,\n\tIMPLICIT,\n\tsubscribeToState,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { employSocket } from \"atom.io/realtime\"\n\nimport type { ServerConfig } from \".\"\n\nexport type MutableProvider = ReturnType<typeof realtimeMutableProvider>\nexport function realtimeMutableProvider({\n\tsocket,\n\tuserKey,\n\tstore = IMPLICIT.STORE,\n}: ServerConfig) {\n\treturn function mutableProvider<\n\t\tCore extends Transceiver<any, Json.Serializable, Json.Serializable>,\n\t>(token: AtomIO.MutableAtomToken<Core>): () => void {\n\t\tconst subscriptions = new Set<() => void>()\n\t\tconst clearSubscriptions = () => {\n\t\t\tfor (const unsub of subscriptions) unsub()\n\t\t\tsubscriptions.clear()\n\t\t}\n\n\t\tconst jsonToken = getJsonToken(store, token)\n\t\tconst trackerToken = getUpdateToken(token)\n\n\t\tconst start = () => {\n\t\t\tstore.logger.info(\n\t\t\t\t`👀`,\n\t\t\t\t`user`,\n\t\t\t\tuserKey,\n\t\t\t\t`can subscribe to state \"${token.key}\"`,\n\t\t\t)\n\t\t\tsubscriptions.add(\n\t\t\t\temploySocket(socket, `sub:${token.key}`, () => {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t`user`,\n\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t`subscribes to state \"${token.key}\"`,\n\t\t\t\t\t)\n\t\t\t\t\tclearSubscriptions()\n\t\t\t\t\tsocket.emit(`init:${token.key}`, getFromStore(store, jsonToken))\n\t\t\t\t\tsubscriptions.add(\n\t\t\t\t\t\tsubscribeToState(\n\t\t\t\t\t\t\tstore,\n\t\t\t\t\t\t\ttrackerToken,\n\t\t\t\t\t\t\t`expose-single:${socket.id}`,\n\t\t\t\t\t\t\t({ newValue }) => {\n\t\t\t\t\t\t\t\tsocket.emit(`next:${token.key}`, newValue)\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\tsubscriptions.add(\n\t\t\t\t\t\temploySocket(socket, `unsub:${token.key}`, () => {\n\t\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t\t`🙈`,\n\t\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t\t`unsubscribes from state \"${token.key}\"`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tclearSubscriptions()\n\t\t\t\t\t\t\tstart()\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\n\t\tstart()\n\n\t\treturn clearSubscriptions\n\t}\n}\n","import type { ChildProcessWithoutNullStreams } from \"node:child_process\"\nimport { spawn } from \"node:child_process\"\n\nimport type { RootStore } from \"atom.io/internal\"\nimport {\n\teditRelationsInStore,\n\tfindInStore,\n\tfindRelationsInStore,\n\tgetFromStore,\n\tgetInternalRelationsFromStore,\n\tIMPLICIT,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type {\n\tAllEventsListener,\n\tEventsMap,\n\tRoomKey,\n\tRoomSocketInterface,\n\tSocket,\n\tSocketGuard,\n\tStandardSchemaV1,\n\tTypedSocket,\n\tUserKey,\n} from \"atom.io/realtime\"\nimport {\n\tcastSocket,\n\tisRoomKey,\n\townersOfRooms,\n\troomKeysAtom,\n\tusersInRooms,\n\tvisibleUsersInRoomsSelector,\n} from \"atom.io/realtime\"\n\nimport { ChildSocket } from \"./ipc-sockets\"\nimport { realtimeMutableFamilyProvider } from \"./realtime-mutable-family-provider\"\nimport { realtimeMutableProvider } from \"./realtime-mutable-provider\"\nimport type { ServerConfig } from \"./server-config\"\n\nexport type RoomMap = Map<\n\tstring,\n\tChildSocket<any, any, ChildProcessWithoutNullStreams>\n>\n\ndeclare global {\n\tvar ATOM_IO_REALTIME_SERVER_ROOMS: RoomMap\n}\nexport const ROOMS: RoomMap =\n\tglobalThis.ATOM_IO_REALTIME_SERVER_ROOMS ??\n\t(globalThis.ATOM_IO_REALTIME_SERVER_ROOMS = new Map())\n\nexport const roomMeta: { count: number } = { count: 0 }\n\nexport type SpawnRoomConfig<RoomNames extends string> = {\n\tstore: RootStore\n\tsocket: Socket\n\tuserKey: UserKey\n\tresolveRoomScript: (roomName: RoomNames) => [string, string[]]\n}\nexport function spawnRoom<RoomNames extends string>({\n\tstore,\n\tsocket,\n\tuserKey,\n\tresolveRoomScript,\n}: SpawnRoomConfig<RoomNames>): (\n\troomName: RoomNames,\n) => Promise<ChildSocket<any, any>> {\n\treturn async (roomName) => {\n\t\tstore.logger.info(\n\t\t\t`📡`,\n\t\t\t`socket`,\n\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t`👤 ${userKey} spawns room ${roomName}`,\n\t\t)\n\t\tconst roomKey = `room::${roomMeta.count++}` satisfies RoomKey\n\t\tconst [command, args] = resolveRoomScript(roomName)\n\t\tconst child = await new Promise<ChildProcessWithoutNullStreams>(\n\t\t\t(resolve) => {\n\t\t\t\tconst room = spawn(command, args, { env: process.env })\n\t\t\t\tconst resolver = (data: Buffer) => {\n\t\t\t\t\tif (data.toString() === `ALIVE`) {\n\t\t\t\t\t\troom.stdout.off(`data`, resolver)\n\t\t\t\t\t\tresolve(room)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\troom.stdout.on(`data`, resolver)\n\t\t\t},\n\t\t)\n\t\tconst roomSocket = new ChildSocket(child, roomKey)\n\t\tROOMS.set(roomKey, roomSocket)\n\t\tsetIntoStore(store, roomKeysAtom, (index) => (index.add(roomKey), index))\n\n\t\teditRelationsInStore(store, ownersOfRooms, (relations) => {\n\t\t\trelations.set({ room: roomKey, user: userKey })\n\t\t})\n\n\t\troomSocket.on(`close`, () => {\n\t\t\tdestroyRoom({ store, socket, userKey })(roomKey)\n\t\t})\n\n\t\treturn roomSocket\n\t}\n}\n\nexport type ProvideEnterAndExitConfig = {\n\tstore: RootStore\n\tsocket: Socket\n\troomSocket: TypedSocket<RoomSocketInterface<any>, any>\n\tuserKey: UserKey\n}\nexport function provideEnterAndExit({\n\tstore,\n\tsocket,\n\troomSocket,\n\tuserKey,\n}: ProvideEnterAndExitConfig): (roomKey: RoomKey) => void {\n\tconst enterRoom = (roomKey: RoomKey) => {\n\t\tstore.logger.info(\n\t\t\t`📡`,\n\t\t\t`socket`,\n\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t`👤 ${userKey} enters room ${roomKey}`,\n\t\t)\n\n\t\tconst exitRoom = () => {\n\t\t\tstore.logger.info(\n\t\t\t\t`📡`,\n\t\t\t\t`socket`,\n\t\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t\t`👤 ${userKey} leaves room ${roomKey}`,\n\t\t\t)\n\t\t\tsocket.offAny(forward)\n\t\t\ttoRoom([`user-leaves`])\n\t\t\teditRelationsInStore(store, usersInRooms, (relations) => {\n\t\t\t\trelations.delete({ room: roomKey, user: userKey })\n\t\t\t})\n\t\t\troomSocket.off(`leaveRoom`, exitRoom)\n\t\t\troomSocket.on(`joinRoom`, enterRoom)\n\t\t}\n\n\t\troomSocket.on(`leaveRoom`, exitRoom)\n\t\troomSocket.off(`joinRoom`, enterRoom)\n\n\t\tconst roomQueue: [string, ...Json.Array][] = []\n\t\tconst pushToRoomQueue = (payload: [string, ...Json.Array]): void => {\n\t\t\troomQueue.push(payload)\n\t\t}\n\t\tlet toRoom = pushToRoomQueue\n\t\tconst forward: AllEventsListener<EventsMap> = (...payload) => {\n\t\t\ttoRoom(payload)\n\t\t}\n\t\tsocket.onAny(forward)\n\n\t\teditRelationsInStore(store, usersInRooms, (relations) => {\n\t\t\trelations.set({ room: roomKey, user: userKey })\n\t\t})\n\t\tconst childSocket = ROOMS.get(roomKey)\n\t\tif (!childSocket) {\n\t\t\tstore.logger.error(`❌`, `unknown`, roomKey, `no room found with this id`)\n\t\t\treturn null\n\t\t}\n\t\tchildSocket.onAny((...payload) => {\n\t\t\tsocket.emit(...payload)\n\t\t})\n\t\tchildSocket.emit(`user-joins`, userKey)\n\n\t\ttoRoom = (payload) => {\n\t\t\tchildSocket.emit(userKey, ...payload)\n\t\t}\n\t\twhile (roomQueue.length > 0) {\n\t\t\tconst payload = roomQueue.shift()\n\t\t\tif (payload) toRoom(payload)\n\t\t}\n\t}\n\troomSocket.on(`joinRoom`, enterRoom)\n\treturn enterRoom\n}\n\nexport type DestroyRoomConfig = {\n\tstore: RootStore\n\tsocket: Socket\n\tuserKey: UserKey\n}\nexport function destroyRoom({\n\tstore,\n\tsocket,\n\tuserKey,\n}: DestroyRoomConfig): (roomKey: RoomKey) => void {\n\treturn (roomKey: RoomKey) => {\n\t\tstore.logger.info(\n\t\t\t`📡`,\n\t\t\t`socket`,\n\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t`👤 ${userKey} attempts to delete room ${roomKey}`,\n\t\t)\n\t\tconst owner = getFromStore(\n\t\t\tstore,\n\t\t\tfindRelationsInStore(store, ownersOfRooms, roomKey).userKeyOfRoom,\n\t\t)\n\t\tif (owner === userKey) {\n\t\t\tstore.logger.info(\n\t\t\t\t`📡`,\n\t\t\t\t`socket`,\n\t\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t\t`👤 ${userKey} deletes room ${roomKey}`,\n\t\t\t)\n\t\t\tsetIntoStore(store, roomKeysAtom, (s) => (s.delete(roomKey), s))\n\t\t\teditRelationsInStore(store, usersInRooms, (relations) => {\n\t\t\t\trelations.delete({ room: roomKey })\n\t\t\t})\n\t\t\tconst room = ROOMS.get(roomKey)\n\t\t\tif (room) {\n\t\t\t\troom.emit(`exit`)\n\t\t\t\tROOMS.delete(roomKey)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tstore.logger.info(\n\t\t\t`📡`,\n\t\t\t`socket`,\n\t\t\tsocket.id ?? `[ID MISSING?!]`,\n\t\t\t`👤 ${userKey} failed to delete room ${roomKey}; room owner is ${owner}`,\n\t\t)\n\t}\n}\n\nexport type ProvideRoomsConfig<RoomNames extends string> = {\n\tresolveRoomScript: (path: RoomNames) => [string, string[]]\n\troomNames: RoomNames[]\n\troomTimeLimit?: number\n}\nexport function provideRooms<RoomNames extends string>({\n\tstore = IMPLICIT.STORE,\n\tsocket,\n\tresolveRoomScript,\n\troomNames,\n\tuserKey,\n}: ProvideRoomsConfig<RoomNames> & ServerConfig): () => void {\n\tconst roomSocket = castSocket<\n\t\tTypedSocket<RoomSocketInterface<RoomNames>, never>\n\t>(socket, createRoomSocketGuard(roomNames))\n\tconst exposeMutable = realtimeMutableProvider({ socket, store, userKey })\n\tconst unsubFromRoomKeys = exposeMutable(roomKeysAtom)\n\tconst usersInRoomsAtoms = getInternalRelationsFromStore(store, usersInRooms)\n\tconst [, usersInRoomsAtomsUsersOnly] = getInternalRelationsFromStore(\n\t\tstore,\n\t\tusersInRooms,\n\t\t`split`,\n\t)\n\tconst usersWhoseRoomsCanBeSeenSelector = findInStore(\n\t\tstore,\n\t\tvisibleUsersInRoomsSelector,\n\t\tuserKey,\n\t)\n\tconst ownersOfRoomsAtoms = getInternalRelationsFromStore(store, ownersOfRooms)\n\tconst exposeMutableFamily = realtimeMutableFamilyProvider({\n\t\tsocket,\n\t\tstore,\n\t\tuserKey,\n\t})\n\tconst unsubFromUsersInRooms = exposeMutableFamily(\n\t\tusersInRoomsAtoms,\n\t\tusersWhoseRoomsCanBeSeenSelector,\n\t)\n\tconst unsubFromOwnersOfRooms = exposeMutableFamily(\n\t\townersOfRoomsAtoms,\n\t\tusersWhoseRoomsCanBeSeenSelector,\n\t)\n\tconst enterRoom = provideEnterAndExit({ store, socket, roomSocket, userKey })\n\n\tconst userRoomSet = getFromStore(store, usersInRoomsAtomsUsersOnly, userKey)\n\tfor (const userRoomKey of userRoomSet) {\n\t\tenterRoom(userRoomKey)\n\t\tbreak\n\t}\n\troomSocket.on(\n\t\t`createRoom`,\n\t\tspawnRoom({ store, socket, userKey, resolveRoomScript }),\n\t)\n\troomSocket.on(`deleteRoom`, destroyRoom({ store, socket, userKey }))\n\treturn () => {\n\t\tunsubFromRoomKeys()\n\t\tunsubFromUsersInRooms()\n\t\tunsubFromOwnersOfRooms()\n\t}\n}\n\nconst roomKeySchema: StandardSchemaV1<Json.Array, [RoomKey]> = {\n\t\"~standard\": {\n\t\tversion: 1,\n\t\tvendor: `atom.io`,\n\t\tvalidate: ([maybeRoomKey]: Json.Array) => {\n\t\t\tif (typeof maybeRoomKey === `string`) {\n\t\t\t\tif (isRoomKey(maybeRoomKey)) {\n\t\t\t\t\treturn { value: [maybeRoomKey] }\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tissues: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmessage: `Room key must start with \"room::\"`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tissues: [\n\t\t\t\t\t{\n\t\t\t\t\t\tmessage: `Room key must be a string`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t}\n\t\t},\n\t},\n}\n\nfunction createRoomSocketGuard<RoomNames extends string>(\n\troomNames: RoomNames[],\n): SocketGuard<RoomSocketInterface<RoomNames>> {\n\treturn {\n\t\tcreateRoom: {\n\t\t\t\"~standard\": {\n\t\t\t\tversion: 1,\n\t\t\t\tvendor: `atom.io`,\n\t\t\t\tvalidate: ([maybeRoomName]) => {\n\t\t\t\t\tif (roomNames.includes(maybeRoomName as RoomNames)) {\n\t\t\t\t\t\treturn { value: [maybeRoomName as RoomNames] }\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tissues: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\t\t`Room name must be one of the following:\\n - ` +\n\t\t\t\t\t\t\t\t\troomNames.join(`\\n - `),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tjoinRoom: roomKeySchema,\n\t\tdeleteRoom: roomKeySchema,\n\t\tleaveRoom: {\n\t\t\t\"~standard\": {\n\t\t\t\tversion: 1,\n\t\t\t\tvendor: `atom.io`,\n\t\t\t\tvalidate: () => ({ value: [] }),\n\t\t\t},\n\t\t},\n\t}\n}\n","import type * as AtomIO from \"atom.io\"\nimport {\n\tfindInStore,\n\tgetFromStore,\n\tIMPLICIT,\n\tsubscribeToState,\n} from \"atom.io/internal\"\nimport type { Canonical, Json, stringified } from \"atom.io/json\"\nimport { stringifyJson } from \"atom.io/json\"\nimport { employSocket } from \"atom.io/realtime\"\n\nimport type { ServerConfig } from \".\"\n\nexport type FamilyProvider = ReturnType<typeof realtimeAtomFamilyProvider>\nexport function realtimeAtomFamilyProvider({\n\tsocket,\n\tuserKey,\n\tstore = IMPLICIT.STORE,\n}: ServerConfig) {\n\treturn function familyProvider<\n\t\tJ extends Json.Serializable,\n\t\tK extends Canonical,\n\t>(\n\t\tfamily: AtomIO.RegularAtomFamilyToken<J, K>,\n\t\tindex: AtomIO.ReadableToken<Iterable<NoInfer<K>>>,\n\t): () => void {\n\t\tconst coreSubscriptions = new Set<() => void>()\n\t\tconst clearCoreSubscriptions = () => {\n\t\t\tfor (const unsub of coreSubscriptions) unsub()\n\t\t\tcoreSubscriptions.clear()\n\t\t}\n\t\tconst familyMemberSubscriptionsWanted = new Set<stringified<K>>()\n\t\tconst familyMemberSubscriptions = new Map<string, () => void>()\n\t\tconst clearFamilySubscriptions = () => {\n\t\t\tfor (const unsub of familyMemberSubscriptions.values()) unsub()\n\t\t\tfamilyMemberSubscriptions.clear()\n\t\t}\n\n\t\tconst fillUnsubRequest = (key: string) => {\n\t\t\tconst unsubUnsub = familyMemberSubscriptions.get(`${key}:unsub`)\n\t\t\tif (unsubUnsub) {\n\t\t\t\tunsubUnsub()\n\t\t\t\tfamilyMemberSubscriptions.delete(`${key}:unsub`)\n\t\t\t}\n\t\t\tconst unsub = familyMemberSubscriptions.get(key)\n\t\t\tif (unsub) {\n\t\t\t\tunsub()\n\t\t\t\tfamilyMemberSubscriptions.delete(key)\n\t\t\t}\n\t\t}\n\n\t\tconst exposeFamilyMembers = (subKey: K) => {\n\t\t\tconst token = findInStore(store, family, subKey)\n\t\t\tgetFromStore(store, token)\n\t\t\tsocket.emit(`serve:${token.key}`, getFromStore(store, token))\n\t\t\tfamilyMemberSubscriptions.set(\n\t\t\t\ttoken.key,\n\t\t\t\tsubscribeToState(\n\t\t\t\t\tstore,\n\t\t\t\t\ttoken,\n\t\t\t\t\t`expose-family:${family.key}:${socket.id}`,\n\t\t\t\t\t({ newValue }) => {\n\t\t\t\t\t\tsocket.emit(`serve:${token.key}`, newValue)\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\t\t\tfamilyMemberSubscriptions.set(\n\t\t\t\t`${token.key}:unsub`,\n\t\t\t\temploySocket(socket, `unsub:${token.key}`, () => {\n\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t`🙈`,\n\t\t\t\t\t\t`user`,\n\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t`unsubscribed from state \"${token.key}\"`,\n\t\t\t\t\t)\n\t\t\t\t\tfillUnsubRequest(token.key)\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\n\t\tconst isAvailable = (exposedSubKeys: Iterable<K>, subKey: K): boolean => {\n\t\t\tfor (const exposedSubKey of exposedSubKeys) {\n\t\t\t\tif (stringifyJson(exposedSubKey) === stringifyJson(subKey)) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\n\t\tconst start = () => {\n\t\t\tstore.logger.info(\n\t\t\t\t`👀`,\n\t\t\t\t`user`,\n\t\t\t\tuserKey,\n\t\t\t\t`can subscribe to family \"${family.key}\"`,\n\t\t\t)\n\t\t\tcoreSubscriptions.add(\n\t\t\t\temploySocket(socket, `sub:${family.key}`, (subKey: K) => {\n\t\t\t\t\tconst exposedSubKeys = getFromStore(store, index)\n\t\t\t\t\tconst shouldExpose = isAvailable(exposedSubKeys, subKey)\n\t\t\t\t\tif (shouldExpose) {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`is approved for a subscription to`,\n\t\t\t\t\t\t\tsubKey,\n\t\t\t\t\t\t\t`in family \"${family.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\texposeFamilyMembers(subKey)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`❌`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`is denied for a subscription to`,\n\t\t\t\t\t\t\tsubKey,\n\t\t\t\t\t\t\t`in family \"${family.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tfamilyMemberSubscriptionsWanted.add(stringifyJson(subKey))\n\t\t\t\t\t\tsocket.emit(`unavailable:${family.key}`, subKey)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t)\n\t\t\tcoreSubscriptions.add(\n\t\t\t\tsubscribeToState(\n\t\t\t\t\tstore,\n\t\t\t\t\tindex,\n\t\t\t\t\t`expose-family:${family.key}:${socket.id}`,\n\t\t\t\t\t({ newValue: newExposedSubKeys }) => {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`has the following keys available for family \"${family.key}\"`,\n\t\t\t\t\t\t\tnewExposedSubKeys,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tfor (const subKey of newExposedSubKeys) {\n\t\t\t\t\t\t\tif (familyMemberSubscriptionsWanted.has(stringifyJson(subKey))) {\n\t\t\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t\t\t`is retroactively approved for a subscription to`,\n\t\t\t\t\t\t\t\t\tsubKey,\n\t\t\t\t\t\t\t\t\t`in family \"${family.key}\"`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\texposeFamilyMembers(subKey)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\n\t\tstart()\n\n\t\treturn () => {\n\t\t\tclearCoreSubscriptions()\n\t\t\tclearFamilySubscriptions()\n\t\t}\n\t}\n}\n","import type * as AtomIO from \"atom.io\"\nimport { getFromStore, IMPLICIT, subscribeToState } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { employSocket } from \"atom.io/realtime\"\n\nimport type { ServerConfig } from \".\"\n\nfunction isReadableToken(input: unknown): input is AtomIO.ReadableToken<any> {\n\treturn (\n\t\ttypeof input === `object` &&\n\t\tinput !== null &&\n\t\t`key` in input &&\n\t\t`type` in input\n\t)\n}\n\nexport type StateProvider = ReturnType<typeof realtimeStateProvider>\nexport function realtimeStateProvider({\n\tsocket,\n\tuserKey,\n\tstore = IMPLICIT.STORE,\n}: ServerConfig) {\n\tstore.logger.info(`🔌`, `user`, userKey, `initialized state provider`)\n\treturn function stateProvider<C extends Json.Serializable, S extends C>(\n\t\tclientToken: AtomIO.WritableToken<C>,\n\t\tserverData:\n\t\t\t| AtomIO.ReadableToken<S>\n\t\t\t| S = clientToken as AtomIO.ReadableToken<S>,\n\t): () => void {\n\t\tconst isStatic = !isReadableToken(serverData)\n\n\t\tconst subscriptions = new Set<() => void>()\n\t\tconst clearSubscriptions = () => {\n\t\t\tfor (const unsub of subscriptions) unsub()\n\t\t\tsubscriptions.clear()\n\t\t}\n\n\t\tconst start = () => {\n\t\t\tif (isStatic) {\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`👀`,\n\t\t\t\t\t`user`,\n\t\t\t\t\tuserKey,\n\t\t\t\t\t`will be served`,\n\t\t\t\t\tserverData,\n\t\t\t\t\t`as \"${clientToken.key}\"`,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tstore.logger.info(\n\t\t\t\t\t`👀`,\n\t\t\t\t\t`user`,\n\t\t\t\t\tuserKey,\n\t\t\t\t\t`can subscribe to state \"${serverData.key}\" as \"${clientToken.key}\"`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tsubscriptions.add(\n\t\t\t\temploySocket(socket, `sub:${clientToken.key}`, () => {\n\t\t\t\t\tif (isStatic) {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`requests`,\n\t\t\t\t\t\t\t`\"${clientToken.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tsocket.emit(`serve:${clientToken.key}`, serverData)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t`👀`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`subscribes to state \"${serverData.key}\"`,\n\t\t\t\t\t\t\tclientToken === serverData\n\t\t\t\t\t\t\t\t? `directly`\n\t\t\t\t\t\t\t\t: `as \"${clientToken.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tclearSubscriptions()\n\t\t\t\t\t\tsocket.emit(\n\t\t\t\t\t\t\t`serve:${clientToken.key}`,\n\t\t\t\t\t\t\tgetFromStore(store, serverData),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tsubscriptions.add(\n\t\t\t\t\t\t\tsubscribeToState(\n\t\t\t\t\t\t\t\tstore,\n\t\t\t\t\t\t\t\tserverData,\n\t\t\t\t\t\t\t\t`expose-single:${socket.id}`,\n\t\t\t\t\t\t\t\t({ newValue }) => {\n\t\t\t\t\t\t\t\t\tsocket.emit(`serve:${clientToken.key}`, newValue)\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tsubscriptions.add(\n\t\t\t\t\t\t\temploySocket(socket, `unsub:${serverData.key}`, () => {\n\t\t\t\t\t\t\t\tstore.logger.info(\n\t\t\t\t\t\t\t\t\t`🙈`,\n\t\t\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t\t\t`unsubscribes from state \"${serverData.key}\", served`,\n\t\t\t\t\t\t\t\t\tclientToken === serverData\n\t\t\t\t\t\t\t\t\t\t? `directly`\n\t\t\t\t\t\t\t\t\t\t: `as \"${clientToken.key}\"`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tclearSubscriptions()\n\t\t\t\t\t\t\t\tstart()\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\n\t\tstart()\n\n\t\treturn clearSubscriptions\n\t}\n}\n","import type { WritableToken } from \"atom.io\"\nimport {\n\tfindInStore,\n\tgetFromStore,\n\tIMPLICIT,\n\toperateOnStore,\n\tOWN_OP,\n\tsetIntoStore,\n\tsubscribeToState,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport type { SocketKey, StandardSchemaV1 } from \"atom.io/realtime\"\nimport { employSocket, mutexAtoms } from \"atom.io/realtime\"\n\nimport type { ServerConfig } from \".\"\n\nexport type StateReceiver = ReturnType<typeof realtimeStateReceiver>\nexport function realtimeStateReceiver({\n\tsocket,\n\tuserKey,\n\tstore = IMPLICIT.STORE,\n}: ServerConfig) {\n\treturn function stateReceiver<S extends Json.Serializable, C extends S>(\n\t\tschema: StandardSchemaV1<unknown, C>,\n\t\tclientToken: WritableToken<C>,\n\t\tserverToken: WritableToken<S> = clientToken,\n\t): () => void {\n\t\tconst socketKey = `socket::${socket.id}` satisfies SocketKey\n\t\tconst mutexAtom = findInStore(store, mutexAtoms, serverToken.key)\n\n\t\tconst subscriptions = new Set<() => void>()\n\t\tconst clearSubscriptions = () => {\n\t\t\tfor (const unsub of subscriptions) unsub()\n\t\t\tsubscriptions.clear()\n\t\t}\n\n\t\tconst permitPublish = () => {\n\t\t\tclearSubscriptions()\n\t\t\tsubscriptions.add(\n\t\t\t\temploySocket(socket, `pub:${clientToken.key}`, async (newValue) => {\n\t\t\t\t\tconst parsed = await schema[`~standard`].validate(newValue)\n\t\t\t\t\tif (parsed.issues) {\n\t\t\t\t\t\tstore.logger.error(\n\t\t\t\t\t\t\t`❌`,\n\t\t\t\t\t\t\t`user`,\n\t\t\t\t\t\t\tuserKey,\n\t\t\t\t\t\t\t`attempted to publish invalid value`,\n\t\t\t\t\t\t\tnewValue,\n\t\t\t\t\t\t\t`to state \"${serverToken.key}\"`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tsetIntoStore(store, serverToken, parsed.value)\n\t\t\t\t}),\n\t\t\t)\n\t\t\tsubscriptions.add(\n\t\t\t\temploySocket(socket, `unclaim:${clientToken.key}`, () => {\n\t\t\t\t\tsetIntoStore(store, mutexAtom, false)\n\t\t\t\t\tclearSubscriptions()\n\t\t\t\t\tstart()\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\n\t\tconst start = () => {\n\t\t\tsubscriptions.add(\n\t\t\t\temploySocket(socket, `claim:${clientToken.key}`, () => {\n\t\t\t\t\tif (getFromStore(store, mutexAtom)) {\n\t\t\t\t\t\tclearSubscriptions()\n\t\t\t\t\t\tsubscriptions.add(\n\t\t\t\t\t\t\tsubscribeToState(store, mutexAtom, socketKey, () => {\n\t\t\t\t\t\t\t\tconst currentValue = getFromStore(store, mutexAtom)\n\t\t\t\t\t\t\t\tif (currentValue === false) {\n\t\t\t\t\t\t\t\t\toperateOnStore(OWN_OP, store, mutexAtom, true)\n\t\t\t\t\t\t\t\t\tpermitPublish()\n\t\t\t\t\t\t\t\t\tsocket.emit(`claim-result:${clientToken.key}`, true)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tsocket.emit(`claim-result:${clientToken.key}`, false)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tsetIntoStore(store, mutexAtom, true)\n\t\t\t\t\tpermitPublish()\n\t\t\t\t\tsocket.emit(`claim-result:${clientToken.key}`, true)\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\n\t\tstart()\n\n\t\treturn clearSubscriptions\n\t}\n}\n","import type {\n\tHierarchy,\n\tJoinToken,\n\tMutableAtomToken,\n\tRegularAtomFamilyToken,\n} from \"atom.io\"\nimport { atomFamily, join, mutableAtom } from \"atom.io\"\nimport type { RoomKey, Socket, SocketKey, UserKey } from \"atom.io/realtime\"\nimport { isSocketKey, isUserKey } from \"atom.io/realtime\"\nimport { UList } from \"atom.io/transceivers/u-list\"\n\nexport type SocketSystemHierarchy = Hierarchy<\n\t[\n\t\t{\n\t\t\tabove: `root`\n\t\t\tbelow: [UserKey, SocketKey, RoomKey]\n\t\t},\n\t]\n>\n\nexport const socketAtoms: RegularAtomFamilyToken<Socket | null, SocketKey> =\n\tatomFamily({\n\t\tkey: `sockets`,\n\t\tdefault: null,\n\t})\n\nexport const socketKeysAtom: MutableAtomToken<UList<SocketKey>> = mutableAtom({\n\tkey: `socketsIndex`,\n\tclass: UList,\n})\nexport const userKeysAtom: MutableAtomToken<UList<UserKey>> = mutableAtom({\n\tkey: `usersIndex`,\n\tclass: UList,\n})\nexport const usersOfSockets: JoinToken<\n\t`user`,\n\tUserKey,\n\t`socket`,\n\tSocketKey,\n\t`1:1`\n> = join({\n\tkey: `usersOfSockets`,\n\tbetween: [`user`, `socket`],\n\tcardinality: `1:1`,\n\tisAType: isUserKey,\n\tisBType: isSocketKey,\n})\n","import type { IncomingHttpHeaders } from \"node:http\"\nimport type { ParsedUrlQuery } from \"node:querystring\"\n\nimport { Realm } from \"atom.io\"\nimport type { RootStore } from \"atom.io/internal\"\nimport {\n\teditRelationsInStore,\n\tfindInStore,\n\tfindRelationsInStore,\n\tgetFromStore,\n\tIMPLICIT,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport type { Socket, SocketKey, UserKey } from \"atom.io/realtime\"\nimport type { Server } from \"socket.io\"\n\nimport { realtimeStateProvider } from \"./realtime-state-provider\"\nimport type { SocketSystemHierarchy } from \"./server-socket-state\"\nimport {\n\tsocketAtoms,\n\tsocketKeysAtom,\n\tuserKeysAtom,\n\tusersOfSockets,\n} from \"./server-socket-state\"\n\nexport type ServerConfig = {\n\tsocket: Socket\n\tuserKey: UserKey\n\tstore?: RootStore\n}\n\n/** Socket Handshake details--taken from socket.io */\nexport type Handshake = {\n\t/** The headers sent as part of the handshake */\n\theaders: IncomingHttpHeaders\n\t/** The date of creation (as string) */\n\ttime: string\n\t/** The ip of the client */\n\taddress: string\n\t/** Whether the connection is cross-domain */\n\txdomain: boolean\n\t/** Whether the connection is secure */\n\tsecure: boolean\n\t/** The date of creation (as unix timestamp) */\n\tissued: number\n\t/** The request URL string */\n\turl: string\n\t/** The query object */\n\tquery: ParsedUrlQuery\n\t/** The auth object */\n\tauth: {\n\t\t[key: string]: any\n\t}\n}\n\nexport function realtime(\n\tserver: Server,\n\tauth: (handshake: Handshake) => Error | UserKey,\n\tonConnect: (config: ServerConfig) => () => void,\n\tstore: RootStore = IMPLICIT.STORE,\n): () => Promise<void> {\n\tconst socketRealm = new Realm<SocketSystemHierarchy>(store)\n\n\tserver\n\t\t.use((socket, next) => {\n\t\t\tconst result = auth(socket.handshake)\n\t\t\tif (result instanceof Error) {\n\t\t\t\tnext(result)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst userClaim = socketRealm.allocate(`root`, result)\n\t\t\tconst socketClaim = socketRealm.allocate(`root`, `socket::${socket.id}`)\n\t\t\tconst socketState = findInStore(store, socketAtoms, socketClaim)\n\t\t\tsetIntoStore(store, socketState, socket)\n\t\t\teditRelationsInStore(store, usersOfSockets, (relations) => {\n\t\t\t\trelations.set(userClaim, socketClaim)\n\t\t\t})\n\t\t\tsetIntoStore(store, userKeysAtom, (index) => index.add(userClaim))\n\t\t\tsetIntoStore(store, socketKeysAtom, (index) => index.add(socketClaim))\n\t\t\tnext()\n\t\t})\n\t\t.on(`connection`, (socket) => {\n\t\t\tconst socketKey = `socket::${socket.id}` satisfies SocketKey\n\t\t\tconst userKeyState = findRelationsInStore(\n\t\t\t\tstore,\n\t\t\t\tusersOfSockets,\n\t\t\t\tsocketKey,\n\t\t\t).userKeyOfSocket\n\t\t\tconst userKey = getFromStore(store, userKeyState)!\n\t\t\tconst serverConfig: ServerConfig = { store, socket, userKey }\n\t\t\tconst provideState = realtimeStateProvider(serverConfig)\n\t\t\tconst unsubFromMyUserKey = provideState(\n\t\t\t\t{ key: `myUserKey`, type: `atom` },\n\t\t\t\tuserKey,\n\t\t\t)\n\n\t\t\tconst disposeServices = onConnect(serverConfig)\n\n\t\t\tsocket.on(`disconnect`, () => {\n\t\t\t\tstore.logger.info(`📡`, `socket`, socketKey, `👤 ${userKey} disconnects`)\n\t\t\t\tdisposeServices()\n\t\t\t\tunsubFromMyUserKey()\n\t\t\t\teditRelationsInStore(store, usersOfSockets, (rel) =>\n\t\t\t\t\trel.delete(socketKey),\n\t\t\t\t)\n\t\t\t\tsetIntoStore(store, userKeysAtom, (keys) => (keys.delete(userKey), keys))\n\t\t\t\tsetIntoStore(\n\t\t\t\t\tstore,\n\t\t\t\t\tsocketKeysAtom,\n\t\t\t\t\t(keys) => (keys.delete(socketKey), keys),\n\t\t\t\t)\n\t\t\t})\n\t\t})\n\n\tconst disposeAll = async () => {\n\t\tawait server.close()\n\t}\n\treturn disposeAll\n}\n"],"mappings":"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"}
@@ -2,7 +2,6 @@ import * as AtomIO from "atom.io";
2
2
  import * as React from "react";
3
3
  import * as RT from "atom.io/realtime";
4
4
  import { RenderResult } from "@testing-library/react";
5
- import * as SocketIO from "socket.io";
6
5
  import { Socket as Socket$1 } from "socket.io-client";
7
6
 
8
7
  //#region src/realtime-testing/setup-realtime-test.d.ts
@@ -11,7 +10,7 @@ type TestSetupOptions = {
11
10
  server?: boolean;
12
11
  };
13
12
  server: (tools: {
14
- socket: SocketIO.Socket;
13
+ socket: RT.Socket;
15
14
  silo: AtomIO.Silo;
16
15
  userKey: RT.UserKey;
17
16
  enableLogging: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/realtime-testing/setup-realtime-test.tsx"],"sourcesContent":[],"mappings":";;;;;;;;KA+DY,gBAAA;;IAAZ,MAAY,CAAA,EAAA,OAAA;EAGF,CAAA;EACF,MAAA,EAAO,CAAA,KAAA,EAAA;IACJ,MAAG,EAFJ,QAAA,CAAS,MAEL;IAAA,IAAA,EADN,MAAA,CAAO,IACD;IAId,OAAY,EAJD,EAAA,CAAG,OAIF;IAGZ,aAAY,EAAA,GAAA,GAAA,IAAA;EACX,CAAA,EAAA,GAAA,CAAA,GAAA,GAAA,IAAA,CAAA,GAAA,IAAA;CAEQ;AAAoB,KANjB,8BAAA,GAAiC,gBAMhB,GAAA;EAAA,MAAA,EALpB,KAAA,CAAM,EAKc;AAI7B,CAAA;AAIY,KAXA,6BAWA,CAAA,oBAAA,MAAA,CAAA,GAVX,gBAUW,GAAA;EAAqB,OAAA,EAAA,QARxB,WAQwB,GARV,KAAA,CAAM,EAQI,EAAA;CAClB;AAGN,KARG,iBAAA,GAQH;EAAA,IAAA,EAAA,MAAA;EAET,IAAY,EARL,MAAA,CAAO,IAQF;AAKZ,CAAA;AAKY,KAhBA,kBAAA,GAAqB,iBAiBxB,GAAA;EAGT,YAAY,EAnBG,YAmBH;EAGZ,WAAY,EAAA,GAAA,GAAA,IAAA;EACX,aAAA,EAAA,GAAA,GAAA,IAAA;EACiB,MAAA,EArBT,QAqBS;CAAa;AAApB,KAnBC,yBAAA,GAmBD;EAAA,OAAA,EAAA,GAAA,GAAA,IAAA;EAGX,IAAa,EAAA,GAAA,GApBA,kBAsBV;AAiGH,CAAA;AA6Da,KAjLD,kBAAA,GAAqB,iBAkLvB,GAAA;EAeV,OAAa,EAAA,GAAA,GAhMG,OAkMgB,CAAA,IAAA,CAAA;EADQ,IAAA,EAAA,MAAA;CAA9B;AACsB,KA9LpB,eAAA,GA8LoB;EAA7B,MAAA,EA7LM,kBA6LN;EAAA,QAAA,EAAA,GAAA,GA5Lc,OA4Ld,CAAA,IAAA,CAAA;;KA1LS,6BAAA,GAAgC;UACnC;;KAEG,2DACX;WACU,OAAO,aAAa;;cAGlB,mCACH,qBACP;cAiGU,mCACH,+DAGP;cAyDU,wBACH,mCACP;cAcU,mDACH,8BAA8B,iBACrC,6BAA6B"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/realtime-testing/setup-realtime-test.tsx"],"sourcesContent":[],"mappings":";;;;;;;KAsDY,gBAAA;;IAAZ,MAAY,CAAA,EAAA,OAAA;EAGF,CAAA;EACF,MAAA,EAAO,CAAA,KAAA,EAAA;IACJ,MAAG,EAFJ,EAAA,CAAG,MAEC;IAAA,IAAA,EADN,MAAA,CAAO,IACD;IAId,OAAY,EAJD,EAAA,CAAG,OAIF;IAGZ,aAAY,EAAA,GAAA,GAAA,IAAA;EACX,CAAA,EAAA,GAAA,CAAA,GAAA,GAAA,IAAA,CAAA,GAAA,IAAA;CAEQ;AAAoB,KANjB,8BAAA,GAAiC,gBAMhB,GAAA;EAAA,MAAA,EALpB,KAAA,CAAM,EAKc;AAI7B,CAAA;AAIY,KAXA,6BAWA,CAAA,oBAAA,MAAA,CAAA,GAVX,gBAUW,GAAA;EAAqB,OAAA,EAAA,QARxB,WAQwB,GARV,KAAA,CAAM,EAQI,EAAA;CAClB;AAGN,KARG,iBAAA,GAQH;EAAA,IAAA,EAAA,MAAA;EAET,IAAY,EARL,MAAA,CAAO,IAQF;AAKZ,CAAA;AAKY,KAhBA,kBAAA,GAAqB,iBAiBxB,GAAA;EAGT,YAAY,EAnBG,YAmBH;EAGZ,WAAY,EAAA,GAAA,GAAA,IAAA;EACX,aAAA,EAAA,GAAA,GAAA,IAAA;EACiB,MAAA,EArBT,QAqBS;CAAa;AAApB,KAnBC,yBAAA,GAmBD;EAAA,OAAA,EAAA,GAAA,GAAA,IAAA;EAGX,IAAa,EAAA,GAAA,GApBA,kBAsBV;AA6DH,CAAA;AA6Da,KA7ID,kBAAA,GAAqB,iBA8IvB,GAAA;EAeV,OAAa,EAAA,GAAA,GA5JG,OA8JgB,CAAA,IAAA,CAAA;EADQ,IAAA,EAAA,MAAA;CAA9B;AACsB,KA1JpB,eAAA,GA0JoB;EAA7B,MAAA,EAzJM,kBAyJN;EAAA,QAAA,EAAA,GAAA,GAxJc,OAwJd,CAAA,IAAA,CAAA;;KAtJS,6BAAA,GAAgC;UACnC;;KAEG,2DACX;WACU,OAAO,aAAa;;cAGlB,mCACH,qBACP;cA6DU,mCACH,+DAGP;cAyDU,wBACH,mCACP;cAcU,mDACH,8BAA8B,iBACrC,6BAA6B"}
@@ -1,10 +1,11 @@
1
- import { IMPLICIT, clearStore, editRelationsInStore, findInStore, findRelationsInStore, getFromStore, setIntoStore } from "atom.io/internal";
1
+ import { IMPLICIT, clearStore } from "atom.io/internal";
2
2
  import * as AtomIO from "atom.io";
3
3
  import { toEntries } from "atom.io/json";
4
4
  import { UList } from "atom.io/transceivers/u-list";
5
5
  import "react";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  import * as AR from "atom.io/react";
8
+ import * as RT from "atom.io/realtime";
8
9
  import { ChildProcess } from "node:child_process";
9
10
  import * as http from "node:http";
10
11
  import { prettyDOM, render } from "@testing-library/react";
@@ -40,65 +41,42 @@ const setupRealtimeTestServer = (options) => {
40
41
  lifespan: options.immortal?.server ? `immortal` : `ephemeral`,
41
42
  isProduction: false
42
43
  }, IMPLICIT.STORE);
43
- const socketRealm = new AtomIO.Realm(silo.store);
44
44
  const httpServer = http.createServer((_, res) => res.end(`Hello World!`));
45
45
  const address = httpServer.listen().address();
46
46
  const port = typeof address === `string` ? null : address === null ? null : address.port;
47
47
  if (port === null) throw new Error(`Could not determine port for test server`);
48
- const server = new SocketIO.Server(httpServer).use((socket, next) => {
49
- const { token, username } = socket.handshake.auth;
50
- if (token === `test` && socket.id) {
51
- const userClaim = socketRealm.allocate(`root`, username);
52
- const socketClaim = socketRealm.allocate(`root`, `socket::${socket.id}`);
53
- const socketState = findInStore(silo.store, RTS.socketAtoms, socketClaim);
54
- setIntoStore(silo.store, socketState, socket);
55
- editRelationsInStore(silo.store, RTS.usersOfSockets, (relations) => {
56
- relations.set(userClaim, socketClaim);
57
- });
58
- setIntoStore(silo.store, RTS.userKeysAtom, (index) => index.add(userClaim));
59
- setIntoStore(silo.store, RTS.socketKeysAtom, (index) => index.add(socketClaim));
60
- next();
61
- } else next(/* @__PURE__ */ new Error(`Authentication error`));
62
- });
63
- const socketServices = /* @__PURE__ */ new Set();
64
- const disposeAllSocketServices = () => {
65
- for (const disposeService of socketServices) disposeService();
66
- };
67
- server.on(`connection`, (socket) => {
68
- const userKeyState = findRelationsInStore(silo.store, RTS.usersOfSockets, `socket::${socket.id}`).userKeyOfSocket;
69
- const userKey = getFromStore(silo.store, userKeyState);
70
- function enableLogging() {
71
- prefixLogger(silo.store, `server`);
72
- socket.onAny((event, ...args) => {
73
- console.log(`🛰 `, userKey, event, ...args);
74
- });
75
- socket.onAnyOutgoing((event, ...args) => {
76
- console.log(`🛰 >>`, userKey, event, ...args);
77
- });
78
- socket.on(`disconnect`, () => {
79
- console.log(`${userKey} disconnected`);
80
- });
81
- }
82
- const disposeServices = options.server({
83
- socket,
84
- enableLogging,
85
- silo,
86
- userKey
87
- });
88
- if (disposeServices) {
89
- socketServices.add(disposeServices);
90
- socket.on(`disconnect`, disposeServices);
91
- }
92
- });
93
- const dispose = async () => {
94
- disposeAllSocketServices();
95
- await server.close();
96
- silo.store.valueMap.clear();
97
- };
48
+ const server = new SocketIO.Server(httpServer);
98
49
  return {
99
50
  name: `SERVER`,
100
51
  silo,
101
- dispose,
52
+ dispose: RTS.realtime(server, (handshake) => {
53
+ const { token, username } = handshake.auth;
54
+ if (RT.isUserKey(username) && token === `test`) return username;
55
+ return /* @__PURE__ */ new Error(`Authentication error`);
56
+ }, (config) => {
57
+ const { socket, userKey } = config;
58
+ function enableLogging() {
59
+ prefixLogger(silo.store, `server`);
60
+ socket.onAny((event, ...args) => {
61
+ console.log(`🛰 `, userKey, event, ...args);
62
+ });
63
+ socket.onAnyOutgoing((event, ...args) => {
64
+ console.log(`🛰 >>`, userKey, event, ...args);
65
+ });
66
+ socket.on(`disconnect`, () => {
67
+ console.log(`${userKey} disconnected`);
68
+ });
69
+ }
70
+ const disposeServices = options.server({
71
+ socket: config.socket,
72
+ userKey: config.userKey,
73
+ enableLogging,
74
+ silo
75
+ });
76
+ return () => {
77
+ disposeServices?.();
78
+ };
79
+ }, silo.store),
102
80
  port
103
81
  };
104
82
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["socket: ClientSocket"],"sources":["../../src/realtime-testing/setup-realtime-test.tsx"],"sourcesContent":["import { ChildProcess } from \"node:child_process\"\nimport * as http from \"node:http\"\n\nimport type { RenderResult } from \"@testing-library/react\"\nimport { prettyDOM, render } from \"@testing-library/react\"\nimport * as AtomIO from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport {\n\tclearStore,\n\teditRelationsInStore,\n\tfindInStore,\n\tfindRelationsInStore,\n\tgetFromStore,\n\tIMPLICIT,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport { toEntries } from \"atom.io/json\"\nimport * as AR from \"atom.io/react\"\nimport type * as RT from \"atom.io/realtime\"\nimport * as RTC from \"atom.io/realtime-client\"\nimport * as RTR from \"atom.io/realtime-react\"\nimport * as RTS from \"atom.io/realtime-server\"\nimport { UList } from \"atom.io/transceivers/u-list\"\nimport * as Happy from \"happy-dom\"\nimport * as React from \"react\"\nimport * as SocketIO from \"socket.io\"\nimport type { Socket as ClientSocket } from \"socket.io-client\"\nimport { io } from \"socket.io-client\"\n\nlet testNumber = 0\n\n/* eslint-disable no-console */\n\nfunction prefixLogger(store: Store, prefix: string) {\n\tstore.loggers[0] = new AtomIO.AtomIOLogger(\n\t\t`info`,\n\t\t(...params) => {\n\t\t\tlet idx = 0\n\t\t\tfor (const param of params) {\n\t\t\t\tif (param instanceof SocketIO.Socket) {\n\t\t\t\t\tparams[idx] = `Socket:${param.id}`\n\t\t\t\t}\n\t\t\t\tif (param instanceof RTS.ChildSocket) {\n\t\t\t\t\tparams[idx] = `ChildSocket:${param.id}`\n\t\t\t\t}\n\t\t\t\tif (param instanceof ChildProcess) {\n\t\t\t\t\tparams[idx] = `ChildProcess:${param.pid}`\n\t\t\t\t}\n\t\t\t\tif (param instanceof UList) {\n\t\t\t\t\tparams[idx] = `UList(${param.size}) {${[...param].join(`, `)}}`\n\t\t\t\t}\n\t\t\t\tidx++\n\t\t\t}\n\t\t\treturn params\n\t\t},\n\t\t{\n\t\t\tinfo: AtomIO.simpleLog(`info`, prefix),\n\t\t\twarn: AtomIO.simpleLog(`warn`, prefix),\n\t\t\terror: AtomIO.simpleLog(`error`, prefix),\n\t\t},\n\t)\n}\n\nexport type TestSetupOptions = {\n\timmortal?: { server?: boolean }\n\tserver: (tools: {\n\t\tsocket: SocketIO.Socket\n\t\tsilo: AtomIO.Silo\n\t\tuserKey: RT.UserKey\n\t\tenableLogging: () => void\n\t}) => (() => void) | void\n}\nexport type TestSetupOptions__SingleClient = TestSetupOptions & {\n\tclient: React.FC\n}\nexport type TestSetupOptions__MultiClient<ClientNames extends string> =\n\tTestSetupOptions & {\n\t\tclients: {\n\t\t\t[K in ClientNames]: React.FC\n\t\t}\n\t}\n\nexport type RealtimeTestTools = {\n\tname: string\n\tsilo: AtomIO.Silo\n}\nexport type RealtimeTestClient = RealtimeTestTools & {\n\trenderResult: RenderResult\n\tprettyPrint: () => void\n\tenableLogging: () => void\n\tsocket: ClientSocket\n}\nexport type RealtimeTestClientBuilder = {\n\tdispose: () => void\n\tinit: () => RealtimeTestClient\n}\n\nexport type RealtimeTestServer = RealtimeTestTools & {\n\tdispose: () => Promise<void>\n\tport: number\n}\n\nexport type RealtimeTestAPI = {\n\tserver: RealtimeTestServer\n\tteardown: () => Promise<void>\n}\nexport type RealtimeTestAPI__SingleClient = RealtimeTestAPI & {\n\tclient: RealtimeTestClientBuilder\n}\nexport type RealtimeTestAPI__MultiClient<ClientNames extends string> =\n\tRealtimeTestAPI & {\n\t\tclients: Record<ClientNames, RealtimeTestClientBuilder>\n\t}\n\nexport const setupRealtimeTestServer = (\n\toptions: TestSetupOptions,\n): RealtimeTestServer => {\n\t++testNumber\n\tconst silo = new AtomIO.Silo(\n\t\t{\n\t\t\tname: `SERVER-${testNumber}`,\n\t\t\tlifespan: options.immortal?.server ? `immortal` : `ephemeral`,\n\t\t\tisProduction: false,\n\t\t},\n\t\tIMPLICIT.STORE,\n\t)\n\t// prefixLogger(silo.store, `server`)\n\tconst socketRealm = new AtomIO.Realm<RTS.SocketSystemHierarchy>(silo.store)\n\n\tconst httpServer = http.createServer((_, res) => res.end(`Hello World!`))\n\tconst address = httpServer.listen().address()\n\tconst port =\n\t\ttypeof address === `string` ? null : address === null ? null : address.port\n\tif (port === null) throw new Error(`Could not determine port for test server`)\n\n\tconst server = new SocketIO.Server(httpServer).use((socket, next) => {\n\t\tconst { token, username } = socket.handshake.auth\n\t\tif (token === `test` && socket.id) {\n\t\t\tconst userClaim = socketRealm.allocate(`root`, username as RT.UserKey)\n\t\t\tconst socketClaim = socketRealm.allocate(`root`, `socket::${socket.id}`)\n\t\t\tconst socketState = findInStore(silo.store, RTS.socketAtoms, socketClaim)\n\t\t\tsetIntoStore(silo.store, socketState, socket)\n\t\t\teditRelationsInStore(silo.store, RTS.usersOfSockets, (relations) => {\n\t\t\t\trelations.set(userClaim, socketClaim)\n\t\t\t})\n\t\t\tsetIntoStore(silo.store, RTS.userKeysAtom, (index) => index.add(userClaim))\n\t\t\tsetIntoStore(silo.store, RTS.socketKeysAtom, (index) =>\n\t\t\t\tindex.add(socketClaim),\n\t\t\t)\n\t\t\tnext()\n\t\t} else {\n\t\t\tnext(new Error(`Authentication error`))\n\t\t}\n\t})\n\n\tconst socketServices = new Set<() => void>()\n\tconst disposeAllSocketServices = () => {\n\t\tfor (const disposeService of socketServices) disposeService()\n\t}\n\n\tserver.on(`connection`, (socket: SocketIO.Socket) => {\n\t\tconst userKeyState = findRelationsInStore(\n\t\t\tsilo.store,\n\t\t\tRTS.usersOfSockets,\n\t\t\t`socket::${socket.id}`,\n\t\t).userKeyOfSocket\n\t\tconst userKey = getFromStore(silo.store, userKeyState)!\n\t\tfunction enableLogging() {\n\t\t\tprefixLogger(silo.store, `server`)\n\t\t\tsocket.onAny((event, ...args) => {\n\t\t\t\tconsole.log(`🛰 `, userKey, event, ...args)\n\t\t\t})\n\t\t\tsocket.onAnyOutgoing((event, ...args) => {\n\t\t\t\tconsole.log(`🛰 >>`, userKey, event, ...args)\n\t\t\t})\n\t\t\tsocket.on(`disconnect`, () => {\n\t\t\t\tconsole.log(`${userKey} disconnected`)\n\t\t\t})\n\t\t}\n\t\tconst disposeServices = options.server({\n\t\t\tsocket,\n\t\t\tenableLogging,\n\t\t\tsilo,\n\t\t\tuserKey,\n\t\t})\n\t\tif (disposeServices) {\n\t\t\tsocketServices.add(disposeServices)\n\t\t\tsocket.on(`disconnect`, disposeServices)\n\t\t}\n\t})\n\n\tconst dispose = async () => {\n\t\tdisposeAllSocketServices()\n\t\tawait server.close()\n\n\t\t// const roomKeys = getFromStore(silo.store, RT.roomIndex)\n\t\t// for (const roomKey of roomKeys) {\n\t\t// \tconst roomState = findInStore(silo.store, RTS.roomSelectors, roomKey)\n\t\t// \tconst room = getFromStore(silo.store, roomState)\n\t\t// \tif (room && !(room instanceof Promise)) {\n\t\t// \t\troom.process.kill()\n\t\t// \t}\n\t\t// } // ❗ POSSIBLY STILL NEEDED\n\t\tsilo.store.valueMap.clear()\n\t}\n\n\treturn {\n\t\tname: `SERVER`,\n\t\tsilo,\n\t\tdispose,\n\t\tport,\n\t}\n}\nexport const setupRealtimeTestClient = (\n\toptions: TestSetupOptions__SingleClient,\n\tname: string,\n\tport: number,\n): RealtimeTestClientBuilder => {\n\tconst testClient = { dispose: () => {} }\n\tconst init = () => {\n\t\tconst socket: ClientSocket = io(`http://localhost:${port}/`, {\n\t\t\tauth: { token: `test`, username: `user::${name}-${testNumber}` },\n\t\t})\n\t\tconst silo = new AtomIO.Silo(\n\t\t\t{ name, lifespan: `ephemeral`, isProduction: false },\n\t\t\tIMPLICIT.STORE,\n\t\t)\n\n\t\tconst { document } = new Happy.Window()\n\t\tdocument.body.innerHTML = `<div id=\"app\"></div>`\n\t\tconst renderResult = render(\n\t\t\t<AR.StoreProvider store={silo.store}>\n\t\t\t\t<RTR.RealtimeProvider socket={socket}>\n\t\t\t\t\t<options.client />\n\t\t\t\t</RTR.RealtimeProvider>\n\t\t\t</AR.StoreProvider>,\n\t\t\t{\n\t\t\t\tcontainer: document.querySelector(`#app`) as unknown as HTMLElement,\n\t\t\t},\n\t\t)\n\n\t\tconst prettyPrint = () => {\n\t\t\tconsole.log(prettyDOM(renderResult.container))\n\t\t}\n\n\t\tconst enableLogging = () => {\n\t\t\t// prefixLogger(silo.store, name)\n\t\t\tsocket.onAny((event, ...args) => {\n\t\t\t\tconsole.log(`📡 `, name, event, ...args)\n\t\t\t})\n\t\t\tsocket.onAnyOutgoing((event, ...args) => {\n\t\t\t\tconsole.log(`📡 >>`, name, event, ...args)\n\t\t\t})\n\t\t}\n\n\t\tconst dispose = () => {\n\t\t\trenderResult.unmount()\n\t\t\tsocket.disconnect()\n\t\t\tclearStore(silo.store)\n\t\t}\n\t\ttestClient.dispose = dispose\n\n\t\treturn {\n\t\t\tname,\n\t\t\tsilo,\n\t\t\tsocket,\n\t\t\trenderResult,\n\t\t\tprettyPrint,\n\t\t\tenableLogging,\n\t\t}\n\t}\n\treturn Object.assign(testClient, { init })\n}\n\nexport const singleClient = (\n\toptions: TestSetupOptions__SingleClient,\n): RealtimeTestAPI__SingleClient => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst client = setupRealtimeTestClient(options, `CLIENT`, server.port)\n\n\treturn {\n\t\tclient,\n\t\tserver,\n\t\tteardown: async () => {\n\t\t\tawait server.dispose()\n\t\t\tclient.dispose()\n\t\t},\n\t}\n}\n\nexport const multiClient = <ClientNames extends string>(\n\toptions: TestSetupOptions__MultiClient<ClientNames>,\n): RealtimeTestAPI__MultiClient<ClientNames> => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst clients = toEntries(options.clients).reduce(\n\t\t(clientRecord, [name, client]) => {\n\t\t\tclientRecord[name] = setupRealtimeTestClient(\n\t\t\t\t{ ...options, client },\n\t\t\t\tname,\n\t\t\t\tserver.port,\n\t\t\t)\n\t\t\treturn clientRecord\n\t\t},\n\t\t{} as Record<ClientNames, RealtimeTestClientBuilder>,\n\t)\n\n\treturn {\n\t\tclients,\n\t\tserver,\n\t\tteardown: async () => {\n\t\t\tawait server.dispose()\n\t\t\tfor (const [, client] of toEntries(clients)) {\n\t\t\t\tclient.dispose()\n\t\t\t}\n\t\t},\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["socket: ClientSocket"],"sources":["../../src/realtime-testing/setup-realtime-test.tsx"],"sourcesContent":["import { ChildProcess } from \"node:child_process\"\nimport * as http from \"node:http\"\n\nimport type { RenderResult } from \"@testing-library/react\"\nimport { prettyDOM, render } from \"@testing-library/react\"\nimport * as AtomIO from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { clearStore, IMPLICIT } from \"atom.io/internal\"\nimport { toEntries } from \"atom.io/json\"\nimport * as AR from \"atom.io/react\"\nimport * as RT from \"atom.io/realtime\"\nimport * as RTR from \"atom.io/realtime-react\"\nimport * as RTS from \"atom.io/realtime-server\"\nimport { UList } from \"atom.io/transceivers/u-list\"\nimport * as Happy from \"happy-dom\"\nimport * as React from \"react\"\nimport * as SocketIO from \"socket.io\"\nimport type { Socket as ClientSocket } from \"socket.io-client\"\nimport { io } from \"socket.io-client\"\n\nlet testNumber = 0\n\n/* eslint-disable no-console */\n\nfunction prefixLogger(store: Store, prefix: string) {\n\tstore.loggers[0] = new AtomIO.AtomIOLogger(\n\t\t`info`,\n\t\t(...params) => {\n\t\t\tlet idx = 0\n\t\t\tfor (const param of params) {\n\t\t\t\tif (param instanceof SocketIO.Socket) {\n\t\t\t\t\tparams[idx] = `Socket:${param.id}`\n\t\t\t\t}\n\t\t\t\tif (param instanceof RTS.ChildSocket) {\n\t\t\t\t\tparams[idx] = `ChildSocket:${param.id}`\n\t\t\t\t}\n\t\t\t\tif (param instanceof ChildProcess) {\n\t\t\t\t\tparams[idx] = `ChildProcess:${param.pid}`\n\t\t\t\t}\n\t\t\t\tif (param instanceof UList) {\n\t\t\t\t\tparams[idx] = `UList(${param.size}) {${[...param].join(`, `)}}`\n\t\t\t\t}\n\t\t\t\tidx++\n\t\t\t}\n\t\t\treturn params\n\t\t},\n\t\t{\n\t\t\tinfo: AtomIO.simpleLog(`info`, prefix),\n\t\t\twarn: AtomIO.simpleLog(`warn`, prefix),\n\t\t\terror: AtomIO.simpleLog(`error`, prefix),\n\t\t},\n\t)\n}\n\nexport type TestSetupOptions = {\n\timmortal?: { server?: boolean }\n\tserver: (tools: {\n\t\tsocket: RT.Socket\n\t\tsilo: AtomIO.Silo\n\t\tuserKey: RT.UserKey\n\t\tenableLogging: () => void\n\t}) => (() => void) | void\n}\nexport type TestSetupOptions__SingleClient = TestSetupOptions & {\n\tclient: React.FC\n}\nexport type TestSetupOptions__MultiClient<ClientNames extends string> =\n\tTestSetupOptions & {\n\t\tclients: {\n\t\t\t[K in ClientNames]: React.FC\n\t\t}\n\t}\n\nexport type RealtimeTestTools = {\n\tname: string\n\tsilo: AtomIO.Silo\n}\nexport type RealtimeTestClient = RealtimeTestTools & {\n\trenderResult: RenderResult\n\tprettyPrint: () => void\n\tenableLogging: () => void\n\tsocket: ClientSocket\n}\nexport type RealtimeTestClientBuilder = {\n\tdispose: () => void\n\tinit: () => RealtimeTestClient\n}\n\nexport type RealtimeTestServer = RealtimeTestTools & {\n\tdispose: () => Promise<void>\n\tport: number\n}\n\nexport type RealtimeTestAPI = {\n\tserver: RealtimeTestServer\n\tteardown: () => Promise<void>\n}\nexport type RealtimeTestAPI__SingleClient = RealtimeTestAPI & {\n\tclient: RealtimeTestClientBuilder\n}\nexport type RealtimeTestAPI__MultiClient<ClientNames extends string> =\n\tRealtimeTestAPI & {\n\t\tclients: Record<ClientNames, RealtimeTestClientBuilder>\n\t}\n\nexport const setupRealtimeTestServer = (\n\toptions: TestSetupOptions,\n): RealtimeTestServer => {\n\t++testNumber\n\tconst silo = new AtomIO.Silo(\n\t\t{\n\t\t\tname: `SERVER-${testNumber}`,\n\t\t\tlifespan: options.immortal?.server ? `immortal` : `ephemeral`,\n\t\t\tisProduction: false,\n\t\t},\n\t\tIMPLICIT.STORE,\n\t)\n\n\tconst httpServer = http.createServer((_, res) => res.end(`Hello World!`))\n\tconst address = httpServer.listen().address()\n\tconst port =\n\t\ttypeof address === `string` ? null : address === null ? null : address.port\n\tif (port === null) throw new Error(`Could not determine port for test server`)\n\n\tconst server = new SocketIO.Server(httpServer)\n\tconst dispose = RTS.realtime(\n\t\tserver,\n\t\t(handshake) => {\n\t\t\tconst { token, username } = handshake.auth\n\t\t\tif (RT.isUserKey(username) && token === `test`) {\n\t\t\t\treturn username\n\t\t\t}\n\t\t\treturn new Error(`Authentication error`)\n\t\t},\n\t\t(config) => {\n\t\t\tconst { socket, userKey } = config\n\t\t\tfunction enableLogging() {\n\t\t\t\tprefixLogger(silo.store, `server`)\n\t\t\t\tsocket.onAny((event, ...args) => {\n\t\t\t\t\tconsole.log(`🛰 `, userKey, event, ...args)\n\t\t\t\t})\n\t\t\t\tsocket.onAnyOutgoing((event, ...args) => {\n\t\t\t\t\tconsole.log(`🛰 >>`, userKey, event, ...args)\n\t\t\t\t})\n\t\t\t\tsocket.on(`disconnect`, () => {\n\t\t\t\t\tconsole.log(`${userKey} disconnected`)\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst disposeServices = options.server({\n\t\t\t\tsocket: config.socket,\n\t\t\t\tuserKey: config.userKey,\n\t\t\t\tenableLogging,\n\t\t\t\tsilo,\n\t\t\t})\n\t\t\treturn () => {\n\t\t\t\tdisposeServices?.()\n\t\t\t}\n\t\t},\n\t\tsilo.store,\n\t)\n\n\treturn {\n\t\tname: `SERVER`,\n\t\tsilo,\n\t\tdispose,\n\t\tport,\n\t}\n}\nexport const setupRealtimeTestClient = (\n\toptions: TestSetupOptions__SingleClient,\n\tname: string,\n\tport: number,\n): RealtimeTestClientBuilder => {\n\tconst testClient = { dispose: () => {} }\n\tconst init = () => {\n\t\tconst socket: ClientSocket = io(`http://localhost:${port}/`, {\n\t\t\tauth: { token: `test`, username: `user::${name}-${testNumber}` },\n\t\t})\n\t\tconst silo = new AtomIO.Silo(\n\t\t\t{ name, lifespan: `ephemeral`, isProduction: false },\n\t\t\tIMPLICIT.STORE,\n\t\t)\n\n\t\tconst { document } = new Happy.Window()\n\t\tdocument.body.innerHTML = `<div id=\"app\"></div>`\n\t\tconst renderResult = render(\n\t\t\t<AR.StoreProvider store={silo.store}>\n\t\t\t\t<RTR.RealtimeProvider socket={socket}>\n\t\t\t\t\t<options.client />\n\t\t\t\t</RTR.RealtimeProvider>\n\t\t\t</AR.StoreProvider>,\n\t\t\t{\n\t\t\t\tcontainer: document.querySelector(`#app`) as unknown as HTMLElement,\n\t\t\t},\n\t\t)\n\n\t\tconst prettyPrint = () => {\n\t\t\tconsole.log(prettyDOM(renderResult.container))\n\t\t}\n\n\t\tconst enableLogging = () => {\n\t\t\t// prefixLogger(silo.store, name)\n\t\t\tsocket.onAny((event, ...args) => {\n\t\t\t\tconsole.log(`📡 `, name, event, ...args)\n\t\t\t})\n\t\t\tsocket.onAnyOutgoing((event, ...args) => {\n\t\t\t\tconsole.log(`📡 >>`, name, event, ...args)\n\t\t\t})\n\t\t}\n\n\t\tconst dispose = () => {\n\t\t\trenderResult.unmount()\n\t\t\tsocket.disconnect()\n\t\t\tclearStore(silo.store)\n\t\t}\n\t\ttestClient.dispose = dispose\n\n\t\treturn {\n\t\t\tname,\n\t\t\tsilo,\n\t\t\tsocket,\n\t\t\trenderResult,\n\t\t\tprettyPrint,\n\t\t\tenableLogging,\n\t\t}\n\t}\n\treturn Object.assign(testClient, { init })\n}\n\nexport const singleClient = (\n\toptions: TestSetupOptions__SingleClient,\n): RealtimeTestAPI__SingleClient => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst client = setupRealtimeTestClient(options, `CLIENT`, server.port)\n\n\treturn {\n\t\tclient,\n\t\tserver,\n\t\tteardown: async () => {\n\t\t\tawait server.dispose()\n\t\t\tclient.dispose()\n\t\t},\n\t}\n}\n\nexport const multiClient = <ClientNames extends string>(\n\toptions: TestSetupOptions__MultiClient<ClientNames>,\n): RealtimeTestAPI__MultiClient<ClientNames> => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst clients = toEntries(options.clients).reduce(\n\t\t(clientRecord, [name, client]) => {\n\t\t\tclientRecord[name] = setupRealtimeTestClient(\n\t\t\t\t{ ...options, client },\n\t\t\t\tname,\n\t\t\t\tserver.port,\n\t\t\t)\n\t\t\treturn clientRecord\n\t\t},\n\t\t{} as Record<ClientNames, RealtimeTestClientBuilder>,\n\t)\n\n\treturn {\n\t\tclients,\n\t\tserver,\n\t\tteardown: async () => {\n\t\t\tawait server.dispose()\n\t\t\tfor (const [, client] of toEntries(clients)) {\n\t\t\t\tclient.dispose()\n\t\t\t}\n\t\t},\n\t}\n}\n"],"mappings":"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"}