atom.io 0.39.0 → 0.39.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 (47) hide show
  1. package/dist/data/index.js.map +1 -1
  2. package/dist/eslint-plugin/index.js +2 -1
  3. package/dist/eslint-plugin/index.js.map +1 -1
  4. package/dist/internal/index.d.ts +13 -7
  5. package/dist/internal/index.d.ts.map +1 -1
  6. package/dist/internal/index.js +34 -14
  7. package/dist/internal/index.js.map +1 -1
  8. package/dist/introspection/index.d.ts.map +1 -1
  9. package/dist/introspection/index.js.map +1 -1
  10. package/dist/json/index.d.ts.map +1 -1
  11. package/dist/json/index.js.map +1 -1
  12. package/dist/main/index.d.ts.map +1 -1
  13. package/dist/main/index.js.map +1 -1
  14. package/dist/react/index.d.ts.map +1 -1
  15. package/dist/react/index.js +43 -2
  16. package/dist/react/index.js.map +1 -1
  17. package/dist/react-devtools/index.d.ts.map +1 -1
  18. package/dist/react-devtools/index.js +4 -5
  19. package/dist/react-devtools/index.js.map +1 -1
  20. package/dist/realtime/index.d.ts.map +1 -1
  21. package/dist/realtime/index.js.map +1 -1
  22. package/dist/realtime-client/index.js.map +1 -1
  23. package/dist/realtime-react/index.js.map +1 -1
  24. package/dist/realtime-server/index.d.ts.map +1 -1
  25. package/dist/realtime-server/index.js.map +1 -1
  26. package/dist/realtime-testing/index.d.ts.map +1 -1
  27. package/dist/realtime-testing/index.js.map +1 -1
  28. package/dist/transceivers/set-rtx/index.d.ts.map +1 -1
  29. package/dist/transceivers/set-rtx/index.js.map +1 -1
  30. package/dist/web/index.js.map +1 -1
  31. package/package.json +8 -8
  32. package/src/internal/families/create-regular-atom-family.ts +3 -2
  33. package/src/internal/get-state/read-or-compute-value.ts +2 -1
  34. package/src/internal/is-fn.ts +9 -0
  35. package/src/internal/set-state/become.ts +11 -6
  36. package/src/internal/set-state/dispatch-state-update.ts +2 -1
  37. package/src/internal/set-state/operate-on-store.ts +3 -1
  38. package/src/internal/set-state/reset-atom-or-selector.ts +7 -7
  39. package/src/internal/set-state/set-atom-or-selector.ts +3 -2
  40. package/src/internal/set-state/set-atom.ts +4 -3
  41. package/src/internal/set-state/set-selector.ts +8 -7
  42. package/src/react-devtools/json-editor/editors-by-type/array-editor.tsx +1 -1
  43. package/src/react-devtools/json-editor/editors-by-type/object-editor.tsx +2 -3
  44. package/src/react-devtools/json-editor/editors-by-type/utilities/array-elements.ts +1 -1
  45. package/src/react-devtools/json-editor/editors-by-type/utilities/object-properties.ts +1 -1
  46. package/dist/use-o-DXPncKmZ.js +0 -47
  47. package/dist/use-o-DXPncKmZ.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["userKey: string | null","socket: ClientSocket"],"sources":["../../src/realtime-testing/setup-realtime-test.tsx"],"sourcesContent":["import * 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 * 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 * 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(`info`, undefined, {\n\t\tinfo: (...args) => {\n\t\t\tconsole.info(prefix, ...args)\n\t\t},\n\t\twarn: (...args) => {\n\t\t\tconsole.warn(prefix, ...args)\n\t\t},\n\t\terror: (...args) => {\n\t\t\tconsole.error(prefix, ...args)\n\t\t},\n\t})\n}\n\nexport type TestSetupOptions = {\n\tport: number\n\timmortal?: { server?: boolean }\n\tserver: (tools: {\n\t\tsocket: SocketIO.Socket\n\t\tsilo: AtomIO.Silo\n\t\tenableLogging: () => void\n\t}) => 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},\n\t\tIMPLICIT.STORE,\n\t)\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(options.port).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`, `user::${username}`)\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(\n\t\t\t\tRTS.usersOfSockets,\n\t\t\t\t(relations) => {\n\t\t\t\t\trelations.set(userClaim, socketClaim)\n\t\t\t\t},\n\t\t\t\tsilo.store,\n\t\t\t)\n\t\t\tsetIntoStore(silo.store, RTS.userIndex, (index) => index.add(userClaim))\n\t\t\tsetIntoStore(silo.store, RTS.socketIndex, (index) =>\n\t\t\t\tindex.add(socketClaim),\n\t\t\t)\n\t\t\t// console.log(`${username} connected on ${socket.id}`)\n\t\t\tnext()\n\t\t} else {\n\t\t\tnext(new Error(`Authentication error`))\n\t\t}\n\t})\n\n\tserver.on(`connection`, (socket: SocketIO.Socket) => {\n\t\tlet userKey: string | null = null\n\t\tfunction enableLogging() {\n\t\t\tconst userKeyState = findRelationsInStore(\n\t\t\t\tRTS.usersOfSockets,\n\t\t\t\t`socket::${socket.id}`,\n\t\t\t\tsilo.store,\n\t\t\t).userKeyOfSocket\n\t\t\tuserKey = getFromStore(silo.store, userKeyState)\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\toptions.server({ socket, enableLogging, silo })\n\t})\n\n\tconst dispose = async () => {\n\t\tawait server.close()\n\t\tconst roomKeys = getFromStore(silo.store, RT.roomIndex)\n\t\tfor (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}\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: `${name}-${testNumber}` },\n\t\t})\n\t\tconst silo = new AtomIO.Silo({ name, lifespan: `ephemeral` }, IMPLICIT.STORE)\n\t\tsilo.setState(RTC.myUsernameState, `${name}-${testNumber}`)\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\tprefixLogger(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":["userKey: string | null","socket: ClientSocket"],"sources":["../../src/realtime-testing/setup-realtime-test.tsx"],"sourcesContent":["import * 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 * 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 * 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(`info`, undefined, {\n\t\tinfo: (...args) => {\n\t\t\tconsole.info(prefix, ...args)\n\t\t},\n\t\twarn: (...args) => {\n\t\t\tconsole.warn(prefix, ...args)\n\t\t},\n\t\terror: (...args) => {\n\t\t\tconsole.error(prefix, ...args)\n\t\t},\n\t})\n}\n\nexport type TestSetupOptions = {\n\tport: number\n\timmortal?: { server?: boolean }\n\tserver: (tools: {\n\t\tsocket: SocketIO.Socket\n\t\tsilo: AtomIO.Silo\n\t\tenableLogging: () => void\n\t}) => 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},\n\t\tIMPLICIT.STORE,\n\t)\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(options.port).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`, `user::${username}`)\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(\n\t\t\t\tRTS.usersOfSockets,\n\t\t\t\t(relations) => {\n\t\t\t\t\trelations.set(userClaim, socketClaim)\n\t\t\t\t},\n\t\t\t\tsilo.store,\n\t\t\t)\n\t\t\tsetIntoStore(silo.store, RTS.userIndex, (index) => index.add(userClaim))\n\t\t\tsetIntoStore(silo.store, RTS.socketIndex, (index) =>\n\t\t\t\tindex.add(socketClaim),\n\t\t\t)\n\t\t\t// console.log(`${username} connected on ${socket.id}`)\n\t\t\tnext()\n\t\t} else {\n\t\t\tnext(new Error(`Authentication error`))\n\t\t}\n\t})\n\n\tserver.on(`connection`, (socket: SocketIO.Socket) => {\n\t\tlet userKey: string | null = null\n\t\tfunction enableLogging() {\n\t\t\tconst userKeyState = findRelationsInStore(\n\t\t\t\tRTS.usersOfSockets,\n\t\t\t\t`socket::${socket.id}`,\n\t\t\t\tsilo.store,\n\t\t\t).userKeyOfSocket\n\t\t\tuserKey = getFromStore(silo.store, userKeyState)\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\toptions.server({ socket, enableLogging, silo })\n\t})\n\n\tconst dispose = async () => {\n\t\tawait server.close()\n\t\tconst roomKeys = getFromStore(silo.store, RT.roomIndex)\n\t\tfor (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}\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: `${name}-${testNumber}` },\n\t\t})\n\t\tconst silo = new AtomIO.Silo({ name, lifespan: `ephemeral` }, IMPLICIT.STORE)\n\t\tsilo.setState(RTC.myUsernameState, `${name}-${testNumber}`)\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\tprefixLogger(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 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/transceivers/set-rtx/set-rtx.ts"],"sourcesContent":[],"mappings":";;;;KAKY,aAAA;AAAA,KACA,SAAA,GADA,GACe,aADf,IAAA,MAAA,EAAA;AACA,KACA,iBAAA,GADe,GAAA,MAAA,IACkB,SADlB,EAAA;AACf,UAEK,UAFL,CAAA,UAE0B,SAFO,CAAA,SAEY,WAFZ,CAEwB,CAFxB,CAAA,CAAA;EAE7C,SAAiB,KAAA,EACA,aADA,CACc,iBADd,GAAA,IAAA,CAAA;EAAA,SAAA,UAAA,EAAA,MAAA;WAAqB,QAAA,EAAA,MAAA;WAA+B,iBAAA,EAAA,MAAA;;AACpD,UAMA,UANA,CAAA,UAMqB,SANrB,CAAA,SAMwC,IAAA,CAAK,MAN7C,CAAA;SADwC,EAQ/C,CAR+C,EAAA;EAAA,KAAA,EAAA,CAShD,iBATgD,GAAA,IAAA,CAAA,EAAA;EAOzD,UAAiB,EAAA,MAAA;EAAA,QAAA,EAAA,MAAA;mBAAqB,EAAA,MAAA;;AAE7B,cAKI,MALJ,CAAA,UAKqB,SALrB,CAAA,SAMA,GANA,CAMI,CANJ,CAAA,YAQP,WARO,CAQK,UARL,CAQgB,CARhB,CAAA,EAQoB,iBARpB,EAQuC,UARvC,CAQkD,CARlD,CAAA,CAAA,EASP,OATO,CAAA;QAWK,eAbgD;EAAA,SAAA,OAAA,EAcpC,OAdoC,CAc5B,SAd4B,CAAA;EAO9D,UAAa,EAAA,MAAA;EAAA,KAAA,EAAA,CASG,iBATH,GAAA,IAAA,CAAA,EAAA;UAAiB,EAAA,MAAA;mBACjB,EAAA,MAAA;aAEY,CAAA,MAAA,CAAA,EAUI,QAVJ,CAUa,CAVb,CAAA,EAAA,UAAA,CAAA,EAAA,MAAA;WAAX,aAAA,EA2BkB,UA3BlB,CA2B6B,CA3B7B,CAAA;QAAe,CAAA,CAAA,EA6BX,UA7BW,CA6BA,CA7BA,CAAA;SAA8B,QAAA,CAAA,UAuCzB,SAvCyB,CAAA,CAAA,IAAA,EAuCR,UAvCQ,CAuCG,CAvCH,CAAA,CAAA,EAuCQ,MAvCR,CAuCe,CAvCf,CAAA;WAAX,EA+C7B,CA/C6B,CAAA,EAAA,IAAA;SAGlC,EAAA,IAAA;QACoB,CAAA,KAAA,EA6DZ,CA7DY,CAAA,EAAA,OAAA;WAAR,MAAA,EAsED,MAtEC,CAsEM,CAtEN,CAAA,GAAA,IAAA;SAuEX,MArEC,CAqEM,CArEN,CAAA,GAAA,IAAA;oBAIsB,EAkEV,SAlEU,EAAA,GAAA,IAAA;aAAT,CAAA,GAAA,EAAA,CAAA,KAAA,EAmEI,MAnEJ,CAmEW,CAnEX,CAAA,EAAA,GAAA,OAAA,CAAA,EAAA,IAAA;YAiBc,UAAA,CAAA,GAAA,EAAA,MAAA,EAAA,EAAA,EAAA,CAAA,MAAA,EAmF5B,SAnF4B,EAAA,GAAA,IAAA,CAAA,EAAA,GAAA,GAAA,IAAA;WAAX,CAAA,GAAA,EAAA,MAAA,EAAA,EAAA,EAAA,CAAA,MAAA,EAyFjB,iBAzFiB,EAAA,GAAA,IAAA,CAAA,EAAA,GAAA,GAAA,IAAA;aAEH,EA8FR,SA9FQ,CAAA,EAAA,IAAA;UAAX,MAAA;iBAUgB,CAAA,MAAA,EA6GF,iBA7GE,CAAA,EAAA,MAAA;WAA4B,EAkH3C,iBAlH2C,CAAA,EAAA,MAAA,GAAA,cAAA,GAAA,IAAA;UAAX,CAAA,MAAA,EA6J1B,SA7J0B,CAAA,EAAA,IAAA;aAAuB,EAsLrD,iBAtLqD,CAAA,EAAA,MAAA,GAAA,IAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/transceivers/set-rtx/set-rtx.ts"],"sourcesContent":[],"mappings":";;;;KAKY,aAAA;AAAA,KACA,SAAA,GADA,GACe,aADf,IAAA,MAAA,EAAA;AACA,KACA,iBAAA,GADe,GAAA,MAAA,IACkB,SADlB,EAAA;AACf,UAEK,UAFL,CAAA,UAE0B,SAFO,CAAA,SAEY,WAFZ,CAEwB,CAFxB,CAAA,CAAA;EAE7C,SAAiB,KAAA,EACA,aADA,CACc,iBADd,GAAA,IAAA,CAAA;EAAA,SAAA,UAAA,EAAA,MAAA;WAAqB,QAAA,EAAA,MAAA;WAA+B,iBAAA,EAAA,MAAA;;AACpD,UAMA,UANA,CAAA,UAMqB,SANrB,CAAA,SAMwC,IAAA,CAAK,MAN7C,CAAA;SADwC,EAQ/C,CAR+C,EAAA;UAShD;EAFT,UAAiB,EAAA,MAAA;EAAA,QAAA,EAAA,MAAA;mBAAqB,EAAA,MAAA;;AAE7B,cAKI,MALJ,CAAA,UAKqB,SALrB,CAAA,SAMA,GANA,CAMI,CANJ,CAAA,YAQP,WARO,CAQK,UARL,CAQgB,CARhB,CAAA,EAQoB,iBARpB,EAQuC,UARvC,CAQkD,CARlD,CAAA,CAAA,EASP,OATO,CAAA;QAWK,eAbgD;oBAcpC,QAAQ;EAPlC,UAAa,EAAA,MAAA;EAAA,KAAA,EAAA,CASG,iBATH,GAAA,IAAA,CAAA,EAAA;UAAiB,EAAA,MAAA;mBACjB,EAAA,MAAA;aAEY,CAAA,MAAA,CAAA,EAUI,QAVJ,CAUa,CAVb,CAAA,EAAA,UAAA,CAAA,EAAA,MAAA;WAAX,aAAA,EA2BkB,UA3BlB,CA2B6B,CA3B7B,CAAA;QAAe,CAAA,CAAA,EA6BX,UA7BW,CA6BA,CA7BA,CAAA;SAA8B,QAAA,CAAA,UAuCzB,SAvCyB,CAAA,CAAA,IAAA,EAuCR,UAvCQ,CAuCG,CAvCH,CAAA,CAAA,EAuCQ,MAvCR,CAuCe,CAvCf,CAAA;WAAX,EA+C7B,CA/C6B,CAAA,EAAA,IAAA;SAGlC,EAAA,IAAA;QACoB,CAAA,KAAA,EA6DZ,CA7DY,CAAA,EAAA,OAAA;WAAR,MAAA,EAsED,MAtEC,CAsEM,CAtEN,CAAA,GAAA,IAAA;SAuEX,MArEC,CAqEM,CArEN,CAAA,GAAA,IAAA;oBAIsB,EAkEV,SAlEU,EAAA,GAAA,IAAA;aAAT,CAAA,GAAA,EAAA,CAAA,KAAA,EAmEI,MAnEJ,CAmEW,CAnEX,CAAA,EAAA,GAAA,OAAA,CAAA,EAAA,IAAA;YAiBc,UAAA,CAAA,GAAA,EAAA,MAAA,EAAA,EAAA,EAAA,CAAA,MAAA,EAmF5B,SAnF4B,EAAA,GAAA,IAAA,CAAA,EAAA,GAAA,GAAA,IAAA;WAAX,CAAA,GAAA,EAAA,MAAA,EAAA,EAAA,EAAA,CAAA,MAAA,EAyFjB,iBAzFiB,EAAA,GAAA,IAAA,CAAA,EAAA,GAAA,GAAA,IAAA;aAEH,EA8FR,SA9FQ,CAAA,EAAA,IAAA;UAAX,MAAA;iBAUgB,CAAA,MAAA,EA6GF,iBA7GE,CAAA,EAAA,MAAA;WAA4B,EAkH3C,iBAlH2C,CAAA,EAAA,MAAA,GAAA,cAAA,GAAA,IAAA;UAAX,CAAA,MAAA,EA6J1B,SA7J0B,CAAA,EAAA,IAAA;aAAuB,EAsLrD,iBAtLqD,CAAA,EAAA,MAAA,GAAA,IAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/transceivers/set-rtx/set-rtx.ts"],"sourcesContent":["import type { Lineage, Transceiver, TransceiverMode } from \"atom.io/internal\"\nimport { Subject } from \"atom.io/internal\"\nimport type { Json, primitive } from \"atom.io/json\"\nimport { stringifyJson } from \"atom.io/json\"\n\nexport type SetUpdateType = `add` | `clear` | `del` | `tx`\nexport type SetUpdate = `${SetUpdateType}:${string}`\nexport type NumberedSetUpdate = `${number}=${SetUpdate}`\n\nexport interface SetRTXView<P extends primitive> extends ReadonlySet<P> {\n\treadonly cache: ReadonlyArray<NumberedSetUpdate | null>\n\treadonly cacheLimit: number\n\treadonly cacheIdx: number\n\treadonly cacheUpdateNumber: number\n}\n\nexport interface SetRTXJson<P extends primitive> extends Json.Object {\n\tmembers: P[]\n\tcache: (NumberedSetUpdate | null)[]\n\tcacheLimit: number\n\tcacheIdx: number\n\tcacheUpdateNumber: number\n}\nexport class SetRTX<P extends primitive>\n\textends Set<P>\n\timplements\n\t\tTransceiver<SetRTXView<P>, NumberedSetUpdate, SetRTXJson<P>>,\n\t\tLineage\n{\n\tpublic mode: TransceiverMode = `record`\n\tpublic readonly subject: Subject<SetUpdate> = new Subject<SetUpdate>()\n\tpublic cacheLimit = 0\n\tpublic cache: (NumberedSetUpdate | null)[] = []\n\tpublic cacheIdx = -1\n\tpublic cacheUpdateNumber = -1\n\n\tpublic constructor(values?: Iterable<P>, cacheLimit = 0) {\n\t\tsuper(values)\n\t\tif (values instanceof SetRTX) {\n\t\t\tthis.parent = values\n\t\t\tthis.cacheUpdateNumber = values.cacheUpdateNumber\n\t\t}\n\t\tif (cacheLimit) {\n\t\t\tthis.cacheLimit = cacheLimit\n\t\t\tthis.cache = new Array(cacheLimit)\n\t\t\tthis.subscribe(`auto cache`, (update) => {\n\t\t\t\tthis.cacheIdx++\n\t\t\t\tthis.cacheIdx %= this.cacheLimit\n\t\t\t\tthis.cache[this.cacheIdx] = update\n\t\t\t})\n\t\t}\n\t}\n\n\tpublic readonly READONLY_VIEW: SetRTXView<P> = this\n\n\tpublic toJSON(): SetRTXJson<P> {\n\t\treturn {\n\t\t\tmembers: [...this],\n\t\t\tcache: this.cache,\n\t\t\tcacheLimit: this.cacheLimit,\n\t\t\tcacheIdx: this.cacheIdx,\n\t\t\tcacheUpdateNumber: this.cacheUpdateNumber,\n\t\t}\n\t}\n\n\tpublic static fromJSON<P extends primitive>(json: SetRTXJson<P>): SetRTX<P> {\n\t\tconst set = new SetRTX<P>(json.members, json.cacheLimit)\n\t\tset.cache = json.cache\n\t\tset.cacheIdx = json.cacheIdx\n\t\tset.cacheUpdateNumber = json.cacheUpdateNumber\n\t\treturn set\n\t}\n\n\tpublic add(value: P): this {\n\t\tconst result = super.add(value)\n\t\tif (this.mode === `record`) {\n\t\t\tthis.cacheUpdateNumber++\n\t\t\tthis.emit(`add:${stringifyJson<P>(value)}`)\n\t\t}\n\t\treturn result\n\t}\n\n\tpublic clear(): void {\n\t\tconst capturedContents = this.mode === `record` ? [...this] : null\n\t\tsuper.clear()\n\t\tif (capturedContents) {\n\t\t\tthis.cacheUpdateNumber++\n\t\t\tthis.emit(`clear:${JSON.stringify(capturedContents)}`)\n\t\t}\n\t}\n\n\tpublic delete(value: P): boolean {\n\t\tconst result = super.delete(value)\n\t\tif (this.mode === `record`) {\n\t\t\tthis.cacheUpdateNumber++\n\t\t\tthis.emit(`del:${stringifyJson<P>(value)}`)\n\t\t}\n\t\treturn result\n\t}\n\n\tpublic readonly parent: SetRTX<P> | null = null\n\tpublic child: SetRTX<P> | null = null\n\tpublic transactionUpdates: SetUpdate[] | null = null\n\tpublic transaction(run: (child: SetRTX<P>) => boolean): void {\n\t\tthis.mode = `transaction`\n\t\tthis.transactionUpdates = []\n\t\tthis.child = new SetRTX(this)\n\t\tconst unsubscribe = this.child._subscribe(`transaction`, (update) => {\n\t\t\tthis.transactionUpdates?.push(update)\n\t\t})\n\t\ttry {\n\t\t\tconst shouldCommit = run(this.child)\n\t\t\tif (shouldCommit) {\n\t\t\t\tfor (const update of this.transactionUpdates) {\n\t\t\t\t\tthis.doStep(update)\n\t\t\t\t}\n\t\t\t\tthis.cacheUpdateNumber++\n\t\t\t\tthis.emit(`tx:${this.transactionUpdates.join(`;`)}`)\n\t\t\t}\n\t\t} catch (thrown) {\n\t\t\t/* eslint-disable-next-line no-console */\n\t\t\tconsole.warn(\n\t\t\t\t`Did not apply transaction to SetRTX; this error was thrown:`,\n\t\t\t\tthrown,\n\t\t\t)\n\t\t\tthrow thrown\n\t\t} finally {\n\t\t\tunsubscribe()\n\t\t\tthis.child = null\n\t\t\tthis.transactionUpdates = null\n\t\t\tthis.mode = `record`\n\t\t}\n\t}\n\n\tprotected _subscribe(\n\t\tkey: string,\n\t\tfn: (update: SetUpdate) => void,\n\t): () => void {\n\t\treturn this.subject.subscribe(key, fn)\n\t}\n\tpublic subscribe(\n\t\tkey: string,\n\t\tfn: (update: NumberedSetUpdate) => void,\n\t): () => void {\n\t\treturn this.subject.subscribe(key, (update) => {\n\t\t\tfn(`${this.cacheUpdateNumber}=${update}`)\n\t\t})\n\t}\n\n\tpublic emit(update: SetUpdate): void {\n\t\tthis.subject.next(update)\n\t}\n\n\tprivate doStep(update: SetUpdate): void {\n\t\tconst typeValueBreak = update.indexOf(`:`)\n\t\tconst type = update.substring(0, typeValueBreak) as SetUpdateType\n\t\tconst value = update.substring(typeValueBreak + 1)\n\t\tswitch (type) {\n\t\t\tcase `add`:\n\t\t\t\tthis.add(JSON.parse(value))\n\t\t\t\tbreak\n\t\t\tcase `clear`:\n\t\t\t\tthis.clear()\n\t\t\t\tbreak\n\t\t\tcase `del`:\n\t\t\t\tthis.delete(JSON.parse(value))\n\t\t\t\tbreak\n\t\t\tcase `tx`:\n\t\t\t\tfor (const subUpdate of value.split(`;`)) {\n\t\t\t\t\tthis.doStep(subUpdate as SetUpdate)\n\t\t\t\t}\n\t\t}\n\t}\n\n\tpublic getUpdateNumber(update: NumberedSetUpdate): number {\n\t\tconst breakpoint = update.indexOf(`=`)\n\t\treturn Number(update.substring(0, breakpoint))\n\t}\n\n\tpublic do(update: NumberedSetUpdate): number | `OUT_OF_RANGE` | null {\n\t\tconst breakpoint = update.indexOf(`=`)\n\t\tconst updateNumber = Number(update.substring(0, breakpoint))\n\t\tconst eventOffset = updateNumber - this.cacheUpdateNumber\n\t\tconst isFuture = eventOffset > 0\n\t\tif (isFuture) {\n\t\t\tif (eventOffset === 1) {\n\t\t\t\tthis.mode = `playback`\n\t\t\t\tconst innerUpdate = update.substring(breakpoint + 1) as SetUpdate\n\t\t\t\tthis.doStep(innerUpdate)\n\t\t\t\tthis.mode = `record`\n\t\t\t\tthis.cacheUpdateNumber = updateNumber\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.cacheUpdateNumber + 1\n\t\t}\n\t\tif (Math.abs(eventOffset) < this.cacheLimit) {\n\t\t\tconst eventIdx = this.cacheIdx + eventOffset\n\t\t\tconst cachedUpdate = this.cache[eventIdx]\n\t\t\tif (cachedUpdate === update) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tthis.mode = `playback`\n\t\t\tlet done = false\n\t\t\twhile (!done) {\n\t\t\t\tthis.cacheIdx %= this.cacheLimit\n\t\t\t\tconst u = this.cache[this.cacheIdx]\n\t\t\t\tthis.cacheIdx--\n\t\t\t\tif (!u) {\n\t\t\t\t\treturn `OUT_OF_RANGE`\n\t\t\t\t}\n\t\t\t\tthis.undo(u)\n\t\t\t\tdone = this.cacheIdx === eventIdx - 1\n\t\t\t}\n\t\t\tconst innerUpdate = update.substring(breakpoint + 1) as SetUpdate\n\t\t\tthis.doStep(innerUpdate)\n\t\t\tthis.mode = `record`\n\t\t\tthis.cacheUpdateNumber = updateNumber\n\t\t\treturn null\n\t\t}\n\t\treturn `OUT_OF_RANGE`\n\t}\n\n\tpublic undoStep(update: SetUpdate): void {\n\t\tconst breakpoint = update.indexOf(`:`)\n\t\tconst type = update.substring(0, breakpoint) as SetUpdateType\n\t\tconst value = update.substring(breakpoint + 1)\n\t\tswitch (type) {\n\t\t\tcase `add`:\n\t\t\t\tthis.delete(JSON.parse(value))\n\t\t\t\tbreak\n\t\t\tcase `del`:\n\t\t\t\tthis.add(JSON.parse(value))\n\t\t\t\tbreak\n\t\t\tcase `clear`: {\n\t\t\t\tconst values = JSON.parse(value) as P[]\n\t\t\t\tfor (const v of values) this.add(v)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase `tx`: {\n\t\t\t\tconst updates = value.split(`;`) as SetUpdate[]\n\t\t\t\tfor (let i = updates.length - 1; i >= 0; i--) {\n\t\t\t\t\tthis.undoStep(updates[i])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic undo(update: NumberedSetUpdate): number | null {\n\t\tconst breakpoint = update.indexOf(`=`)\n\t\tconst updateNumber = Number(update.substring(0, breakpoint))\n\t\tif (updateNumber === this.cacheUpdateNumber) {\n\t\t\tthis.mode = `playback`\n\t\t\tconst innerUpdate = update.substring(breakpoint + 1) as SetUpdate\n\t\t\tthis.undoStep(innerUpdate)\n\t\t\tthis.mode = `record`\n\t\t\tthis.cacheUpdateNumber--\n\t\t\treturn null\n\t\t}\n\t\treturn this.cacheUpdateNumber\n\t}\n}\n"],"mappings":";;;;AAuBA,IAAa,SAAb,MAAa,eACJ,IAIT;CACC,AAAO,OAAwB;CAC/B,AAAgB,UAA8B,IAAI;CAClD,AAAO,aAAa;CACpB,AAAO,QAAsC,EAAE;CAC/C,AAAO,WAAW;CAClB,AAAO,oBAAoB;CAE3B,AAAO,YAAY,QAAsB,aAAa,GAAG;AACxD,QAAM;AACN,MAAI,kBAAkB,QAAQ;AAC7B,QAAK,SAAS;AACd,QAAK,oBAAoB,OAAO;EAChC;AACD,MAAI,YAAY;AACf,QAAK,aAAa;AAClB,QAAK,QAAQ,IAAI,MAAM;AACvB,QAAK,UAAU,eAAe,WAAW;AACxC,SAAK;AACL,SAAK,YAAY,KAAK;AACtB,SAAK,MAAM,KAAK,YAAY;GAC5B;EACD;CACD;CAED,AAAgB,gBAA+B;CAE/C,AAAO,SAAwB;AAC9B,SAAO;GACN,SAAS,CAAC,GAAG,KAAK;GAClB,OAAO,KAAK;GACZ,YAAY,KAAK;GACjB,UAAU,KAAK;GACf,mBAAmB,KAAK;GACxB;CACD;CAED,OAAc,SAA8B,MAAgC;EAC3E,MAAM,MAAM,IAAI,OAAU,KAAK,SAAS,KAAK;AAC7C,MAAI,QAAQ,KAAK;AACjB,MAAI,WAAW,KAAK;AACpB,MAAI,oBAAoB,KAAK;AAC7B,SAAO;CACP;CAED,AAAO,IAAI,OAAgB;EAC1B,MAAM,SAAS,MAAM,IAAI;AACzB,MAAI,KAAK,SAAS,UAAU;AAC3B,QAAK;AACL,QAAK,KAAK,OAAO,cAAiB;EAClC;AACD,SAAO;CACP;CAED,AAAO,QAAc;EACpB,MAAM,mBAAmB,KAAK,SAAS,WAAW,CAAC,GAAG,KAAK,GAAG;AAC9D,QAAM;AACN,MAAI,kBAAkB;AACrB,QAAK;AACL,QAAK,KAAK,SAAS,KAAK,UAAU;EAClC;CACD;CAED,AAAO,OAAO,OAAmB;EAChC,MAAM,SAAS,MAAM,OAAO;AAC5B,MAAI,KAAK,SAAS,UAAU;AAC3B,QAAK;AACL,QAAK,KAAK,OAAO,cAAiB;EAClC;AACD,SAAO;CACP;CAED,AAAgB,SAA2B;CAC3C,AAAO,QAA0B;CACjC,AAAO,qBAAyC;CAChD,AAAO,YAAY,KAA0C;AAC5D,OAAK,OAAO;AACZ,OAAK,qBAAqB,EAAE;AAC5B,OAAK,QAAQ,IAAI,OAAO;EACxB,MAAM,cAAc,KAAK,MAAM,WAAW,gBAAgB,WAAW;AACpE,QAAK,oBAAoB,KAAK;EAC9B;AACD,MAAI;GACH,MAAM,eAAe,IAAI,KAAK;AAC9B,OAAI,cAAc;AACjB,SAAK,MAAM,UAAU,KAAK,mBACzB,MAAK,OAAO;AAEb,SAAK;AACL,SAAK,KAAK,MAAM,KAAK,mBAAmB,KAAK;GAC7C;EACD,SAAQ,QAAQ;AAEhB,WAAQ,KACP,+DACA;AAED,SAAM;EACN,UAAS;AACT;AACA,QAAK,QAAQ;AACb,QAAK,qBAAqB;AAC1B,QAAK,OAAO;EACZ;CACD;CAED,AAAU,WACT,KACA,IACa;AACb,SAAO,KAAK,QAAQ,UAAU,KAAK;CACnC;CACD,AAAO,UACN,KACA,IACa;AACb,SAAO,KAAK,QAAQ,UAAU,MAAM,WAAW;AAC9C,MAAG,GAAG,KAAK,kBAAkB,GAAG;EAChC;CACD;CAED,AAAO,KAAK,QAAyB;AACpC,OAAK,QAAQ,KAAK;CAClB;CAED,AAAQ,OAAO,QAAyB;EACvC,MAAM,iBAAiB,OAAO,QAAQ;EACtC,MAAM,OAAO,OAAO,UAAU,GAAG;EACjC,MAAM,QAAQ,OAAO,UAAU,iBAAiB;AAChD,UAAQ,MAAR;GACC,KAAK;AACJ,SAAK,IAAI,KAAK,MAAM;AACpB;GACD,KAAK;AACJ,SAAK;AACL;GACD,KAAK;AACJ,SAAK,OAAO,KAAK,MAAM;AACvB;GACD,KAAK,KACJ,MAAK,MAAM,aAAa,MAAM,MAAM,KACnC,MAAK,OAAO;EAEd;CACD;CAED,AAAO,gBAAgB,QAAmC;EACzD,MAAM,aAAa,OAAO,QAAQ;AAClC,SAAO,OAAO,OAAO,UAAU,GAAG;CAClC;CAED,AAAO,GAAG,QAA2D;EACpE,MAAM,aAAa,OAAO,QAAQ;EAClC,MAAM,eAAe,OAAO,OAAO,UAAU,GAAG;EAChD,MAAM,cAAc,eAAe,KAAK;EACxC,MAAM,WAAW,cAAc;AAC/B,MAAI,UAAU;AACb,OAAI,gBAAgB,GAAG;AACtB,SAAK,OAAO;IACZ,MAAM,cAAc,OAAO,UAAU,aAAa;AAClD,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,oBAAoB;AACzB,WAAO;GACP;AACD,UAAO,KAAK,oBAAoB;EAChC;AACD,MAAI,KAAK,IAAI,eAAe,KAAK,YAAY;GAC5C,MAAM,WAAW,KAAK,WAAW;GACjC,MAAM,eAAe,KAAK,MAAM;AAChC,OAAI,iBAAiB,OACpB,QAAO;AAER,QAAK,OAAO;GACZ,IAAI,OAAO;AACX,UAAO,CAAC,MAAM;AACb,SAAK,YAAY,KAAK;IACtB,MAAM,IAAI,KAAK,MAAM,KAAK;AAC1B,SAAK;AACL,QAAI,CAAC,EACJ,QAAO;AAER,SAAK,KAAK;AACV,WAAO,KAAK,aAAa,WAAW;GACpC;GACD,MAAM,cAAc,OAAO,UAAU,aAAa;AAClD,QAAK,OAAO;AACZ,QAAK,OAAO;AACZ,QAAK,oBAAoB;AACzB,UAAO;EACP;AACD,SAAO;CACP;CAED,AAAO,SAAS,QAAyB;EACxC,MAAM,aAAa,OAAO,QAAQ;EAClC,MAAM,OAAO,OAAO,UAAU,GAAG;EACjC,MAAM,QAAQ,OAAO,UAAU,aAAa;AAC5C,UAAQ,MAAR;GACC,KAAK;AACJ,SAAK,OAAO,KAAK,MAAM;AACvB;GACD,KAAK;AACJ,SAAK,IAAI,KAAK,MAAM;AACpB;GACD,KAAK,SAAS;IACb,MAAM,SAAS,KAAK,MAAM;AAC1B,SAAK,MAAM,KAAK,OAAQ,MAAK,IAAI;AACjC;GACA;GACD,KAAK,MAAM;IACV,MAAM,UAAU,MAAM,MAAM;AAC5B,SAAK,IAAI,IAAI,QAAQ,SAAS,GAAG,KAAK,GAAG,IACxC,MAAK,SAAS,QAAQ;GAEvB;EACD;CACD;CAED,AAAO,KAAK,QAA0C;EACrD,MAAM,aAAa,OAAO,QAAQ;EAClC,MAAM,eAAe,OAAO,OAAO,UAAU,GAAG;AAChD,MAAI,iBAAiB,KAAK,mBAAmB;AAC5C,QAAK,OAAO;GACZ,MAAM,cAAc,OAAO,UAAU,aAAa;AAClD,QAAK,SAAS;AACd,QAAK,OAAO;AACZ,QAAK;AACL,UAAO;EACP;AACD,SAAO,KAAK;CACZ;AACD"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/transceivers/set-rtx/set-rtx.ts"],"sourcesContent":["import type { Lineage, Transceiver, TransceiverMode } from \"atom.io/internal\"\nimport { Subject } from \"atom.io/internal\"\nimport type { Json, primitive } from \"atom.io/json\"\nimport { stringifyJson } from \"atom.io/json\"\n\nexport type SetUpdateType = `add` | `clear` | `del` | `tx`\nexport type SetUpdate = `${SetUpdateType}:${string}`\nexport type NumberedSetUpdate = `${number}=${SetUpdate}`\n\nexport interface SetRTXView<P extends primitive> extends ReadonlySet<P> {\n\treadonly cache: ReadonlyArray<NumberedSetUpdate | null>\n\treadonly cacheLimit: number\n\treadonly cacheIdx: number\n\treadonly cacheUpdateNumber: number\n}\n\nexport interface SetRTXJson<P extends primitive> extends Json.Object {\n\tmembers: P[]\n\tcache: (NumberedSetUpdate | null)[]\n\tcacheLimit: number\n\tcacheIdx: number\n\tcacheUpdateNumber: number\n}\nexport class SetRTX<P extends primitive>\n\textends Set<P>\n\timplements\n\t\tTransceiver<SetRTXView<P>, NumberedSetUpdate, SetRTXJson<P>>,\n\t\tLineage\n{\n\tpublic mode: TransceiverMode = `record`\n\tpublic readonly subject: Subject<SetUpdate> = new Subject<SetUpdate>()\n\tpublic cacheLimit = 0\n\tpublic cache: (NumberedSetUpdate | null)[] = []\n\tpublic cacheIdx = -1\n\tpublic cacheUpdateNumber = -1\n\n\tpublic constructor(values?: Iterable<P>, cacheLimit = 0) {\n\t\tsuper(values)\n\t\tif (values instanceof SetRTX) {\n\t\t\tthis.parent = values\n\t\t\tthis.cacheUpdateNumber = values.cacheUpdateNumber\n\t\t}\n\t\tif (cacheLimit) {\n\t\t\tthis.cacheLimit = cacheLimit\n\t\t\tthis.cache = new Array(cacheLimit)\n\t\t\tthis.subscribe(`auto cache`, (update) => {\n\t\t\t\tthis.cacheIdx++\n\t\t\t\tthis.cacheIdx %= this.cacheLimit\n\t\t\t\tthis.cache[this.cacheIdx] = update\n\t\t\t})\n\t\t}\n\t}\n\n\tpublic readonly READONLY_VIEW: SetRTXView<P> = this\n\n\tpublic toJSON(): SetRTXJson<P> {\n\t\treturn {\n\t\t\tmembers: [...this],\n\t\t\tcache: this.cache,\n\t\t\tcacheLimit: this.cacheLimit,\n\t\t\tcacheIdx: this.cacheIdx,\n\t\t\tcacheUpdateNumber: this.cacheUpdateNumber,\n\t\t}\n\t}\n\n\tpublic static fromJSON<P extends primitive>(json: SetRTXJson<P>): SetRTX<P> {\n\t\tconst set = new SetRTX<P>(json.members, json.cacheLimit)\n\t\tset.cache = json.cache\n\t\tset.cacheIdx = json.cacheIdx\n\t\tset.cacheUpdateNumber = json.cacheUpdateNumber\n\t\treturn set\n\t}\n\n\tpublic add(value: P): this {\n\t\tconst result = super.add(value)\n\t\tif (this.mode === `record`) {\n\t\t\tthis.cacheUpdateNumber++\n\t\t\tthis.emit(`add:${stringifyJson<P>(value)}`)\n\t\t}\n\t\treturn result\n\t}\n\n\tpublic clear(): void {\n\t\tconst capturedContents = this.mode === `record` ? [...this] : null\n\t\tsuper.clear()\n\t\tif (capturedContents) {\n\t\t\tthis.cacheUpdateNumber++\n\t\t\tthis.emit(`clear:${JSON.stringify(capturedContents)}`)\n\t\t}\n\t}\n\n\tpublic delete(value: P): boolean {\n\t\tconst result = super.delete(value)\n\t\tif (this.mode === `record`) {\n\t\t\tthis.cacheUpdateNumber++\n\t\t\tthis.emit(`del:${stringifyJson<P>(value)}`)\n\t\t}\n\t\treturn result\n\t}\n\n\tpublic readonly parent: SetRTX<P> | null = null\n\tpublic child: SetRTX<P> | null = null\n\tpublic transactionUpdates: SetUpdate[] | null = null\n\tpublic transaction(run: (child: SetRTX<P>) => boolean): void {\n\t\tthis.mode = `transaction`\n\t\tthis.transactionUpdates = []\n\t\tthis.child = new SetRTX(this)\n\t\tconst unsubscribe = this.child._subscribe(`transaction`, (update) => {\n\t\t\tthis.transactionUpdates?.push(update)\n\t\t})\n\t\ttry {\n\t\t\tconst shouldCommit = run(this.child)\n\t\t\tif (shouldCommit) {\n\t\t\t\tfor (const update of this.transactionUpdates) {\n\t\t\t\t\tthis.doStep(update)\n\t\t\t\t}\n\t\t\t\tthis.cacheUpdateNumber++\n\t\t\t\tthis.emit(`tx:${this.transactionUpdates.join(`;`)}`)\n\t\t\t}\n\t\t} catch (thrown) {\n\t\t\t/* eslint-disable-next-line no-console */\n\t\t\tconsole.warn(\n\t\t\t\t`Did not apply transaction to SetRTX; this error was thrown:`,\n\t\t\t\tthrown,\n\t\t\t)\n\t\t\tthrow thrown\n\t\t} finally {\n\t\t\tunsubscribe()\n\t\t\tthis.child = null\n\t\t\tthis.transactionUpdates = null\n\t\t\tthis.mode = `record`\n\t\t}\n\t}\n\n\tprotected _subscribe(\n\t\tkey: string,\n\t\tfn: (update: SetUpdate) => void,\n\t): () => void {\n\t\treturn this.subject.subscribe(key, fn)\n\t}\n\tpublic subscribe(\n\t\tkey: string,\n\t\tfn: (update: NumberedSetUpdate) => void,\n\t): () => void {\n\t\treturn this.subject.subscribe(key, (update) => {\n\t\t\tfn(`${this.cacheUpdateNumber}=${update}`)\n\t\t})\n\t}\n\n\tpublic emit(update: SetUpdate): void {\n\t\tthis.subject.next(update)\n\t}\n\n\tprivate doStep(update: SetUpdate): void {\n\t\tconst typeValueBreak = update.indexOf(`:`)\n\t\tconst type = update.substring(0, typeValueBreak) as SetUpdateType\n\t\tconst value = update.substring(typeValueBreak + 1)\n\t\tswitch (type) {\n\t\t\tcase `add`:\n\t\t\t\tthis.add(JSON.parse(value))\n\t\t\t\tbreak\n\t\t\tcase `clear`:\n\t\t\t\tthis.clear()\n\t\t\t\tbreak\n\t\t\tcase `del`:\n\t\t\t\tthis.delete(JSON.parse(value))\n\t\t\t\tbreak\n\t\t\tcase `tx`:\n\t\t\t\tfor (const subUpdate of value.split(`;`)) {\n\t\t\t\t\tthis.doStep(subUpdate as SetUpdate)\n\t\t\t\t}\n\t\t}\n\t}\n\n\tpublic getUpdateNumber(update: NumberedSetUpdate): number {\n\t\tconst breakpoint = update.indexOf(`=`)\n\t\treturn Number(update.substring(0, breakpoint))\n\t}\n\n\tpublic do(update: NumberedSetUpdate): number | `OUT_OF_RANGE` | null {\n\t\tconst breakpoint = update.indexOf(`=`)\n\t\tconst updateNumber = Number(update.substring(0, breakpoint))\n\t\tconst eventOffset = updateNumber - this.cacheUpdateNumber\n\t\tconst isFuture = eventOffset > 0\n\t\tif (isFuture) {\n\t\t\tif (eventOffset === 1) {\n\t\t\t\tthis.mode = `playback`\n\t\t\t\tconst innerUpdate = update.substring(breakpoint + 1) as SetUpdate\n\t\t\t\tthis.doStep(innerUpdate)\n\t\t\t\tthis.mode = `record`\n\t\t\t\tthis.cacheUpdateNumber = updateNumber\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.cacheUpdateNumber + 1\n\t\t}\n\t\tif (Math.abs(eventOffset) < this.cacheLimit) {\n\t\t\tconst eventIdx = this.cacheIdx + eventOffset\n\t\t\tconst cachedUpdate = this.cache[eventIdx]\n\t\t\tif (cachedUpdate === update) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tthis.mode = `playback`\n\t\t\tlet done = false\n\t\t\twhile (!done) {\n\t\t\t\tthis.cacheIdx %= this.cacheLimit\n\t\t\t\tconst u = this.cache[this.cacheIdx]\n\t\t\t\tthis.cacheIdx--\n\t\t\t\tif (!u) {\n\t\t\t\t\treturn `OUT_OF_RANGE`\n\t\t\t\t}\n\t\t\t\tthis.undo(u)\n\t\t\t\tdone = this.cacheIdx === eventIdx - 1\n\t\t\t}\n\t\t\tconst innerUpdate = update.substring(breakpoint + 1) as SetUpdate\n\t\t\tthis.doStep(innerUpdate)\n\t\t\tthis.mode = `record`\n\t\t\tthis.cacheUpdateNumber = updateNumber\n\t\t\treturn null\n\t\t}\n\t\treturn `OUT_OF_RANGE`\n\t}\n\n\tpublic undoStep(update: SetUpdate): void {\n\t\tconst breakpoint = update.indexOf(`:`)\n\t\tconst type = update.substring(0, breakpoint) as SetUpdateType\n\t\tconst value = update.substring(breakpoint + 1)\n\t\tswitch (type) {\n\t\t\tcase `add`:\n\t\t\t\tthis.delete(JSON.parse(value))\n\t\t\t\tbreak\n\t\t\tcase `del`:\n\t\t\t\tthis.add(JSON.parse(value))\n\t\t\t\tbreak\n\t\t\tcase `clear`: {\n\t\t\t\tconst values = JSON.parse(value) as P[]\n\t\t\t\tfor (const v of values) this.add(v)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase `tx`: {\n\t\t\t\tconst updates = value.split(`;`) as SetUpdate[]\n\t\t\t\tfor (let i = updates.length - 1; i >= 0; i--) {\n\t\t\t\t\tthis.undoStep(updates[i])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic undo(update: NumberedSetUpdate): number | null {\n\t\tconst breakpoint = update.indexOf(`=`)\n\t\tconst updateNumber = Number(update.substring(0, breakpoint))\n\t\tif (updateNumber === this.cacheUpdateNumber) {\n\t\t\tthis.mode = `playback`\n\t\t\tconst innerUpdate = update.substring(breakpoint + 1) as SetUpdate\n\t\t\tthis.undoStep(innerUpdate)\n\t\t\tthis.mode = `record`\n\t\t\tthis.cacheUpdateNumber--\n\t\t\treturn null\n\t\t}\n\t\treturn this.cacheUpdateNumber\n\t}\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/web/persist-sync.ts"],"sourcesContent":["import type { AtomEffect, ViewOf } from \"atom.io\"\n\nexport type StringInterface<T> = {\n\tstringify: (t: ViewOf<T>) => string\n\tparse: (s: string) => T\n}\n\nexport const persistSync =\n\t<T>(\n\t\tstorage: Storage,\n\t\t{ stringify, parse }: StringInterface<T>,\n\t\tkey: string,\n\t): AtomEffect<T> =>\n\t({ setSelf, onSet }) => {\n\t\tconst savedValue = storage.getItem(key)\n\t\tif (savedValue != null) setSelf(parse(savedValue))\n\n\t\tonSet(({ newValue }) => {\n\t\t\tif (newValue == null) {\n\t\t\t\tstorage.removeItem(key)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tstorage.setItem(key, stringify(newValue))\n\t\t})\n\t}\n"],"mappings":";AAOA,MAAa,eAEX,SACA,EAAE,WAAW,OAA2B,EACxC,SAEA,EAAE,SAAS,OAAO,KAAK;CACvB,MAAM,aAAa,QAAQ,QAAQ;AACnC,KAAI,cAAc,KAAM,SAAQ,MAAM;AAEtC,QAAO,EAAE,UAAU,KAAK;AACvB,MAAI,YAAY,MAAM;AACrB,WAAQ,WAAW;AACnB;EACA;AACD,UAAQ,QAAQ,KAAK,UAAU;CAC/B;AACD"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/web/persist-sync.ts"],"sourcesContent":["import type { AtomEffect, ViewOf } from \"atom.io\"\n\nexport type StringInterface<T> = {\n\tstringify: (t: ViewOf<T>) => string\n\tparse: (s: string) => T\n}\n\nexport const persistSync =\n\t<T>(\n\t\tstorage: Storage,\n\t\t{ stringify, parse }: StringInterface<T>,\n\t\tkey: string,\n\t): AtomEffect<T> =>\n\t({ setSelf, onSet }) => {\n\t\tconst savedValue = storage.getItem(key)\n\t\tif (savedValue != null) setSelf(parse(savedValue))\n\n\t\tonSet(({ newValue }) => {\n\t\t\tif (newValue == null) {\n\t\t\t\tstorage.removeItem(key)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tstorage.setItem(key, stringify(newValue))\n\t\t})\n\t}\n"],"mappings":";AAOA,MAAa,eAEX,SACA,EAAE,WAAW,SACb,SAEA,EAAE,SAAS,YAAY;CACvB,MAAM,aAAa,QAAQ,QAAQ;AACnC,KAAI,cAAc,KAAM,SAAQ,MAAM;AAEtC,QAAO,EAAE,eAAe;AACvB,MAAI,YAAY,MAAM;AACrB,WAAQ,WAAW;AACnB;;AAED,UAAQ,QAAQ,KAAK,UAAU"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atom.io",
3
- "version": "0.39.0",
3
+ "version": "0.39.1",
4
4
  "description": "Composable and testable reactive data library.",
5
5
  "homepage": "https://atom.io.fyi",
6
6
  "sideEffects": false,
@@ -65,21 +65,21 @@
65
65
  "@storybook/addon-onboarding": "9.1.3",
66
66
  "@storybook/react-vite": "9.1.3",
67
67
  "@testing-library/react": "16.3.0",
68
- "@types/bun": "npm:bun-types@1.2.20",
68
+ "@types/bun": "npm:bun-types@1.2.21",
69
69
  "@types/eslint": "9.6.1",
70
70
  "@types/estree": "1.0.8",
71
71
  "@types/http-proxy": "1.17.16",
72
72
  "@types/npmlog": "7.0.0",
73
73
  "@types/react": "19.1.11",
74
74
  "@types/tmp": "0.2.6",
75
- "@typescript-eslint/parser": "8.40.0",
76
- "@typescript-eslint/rule-tester": "8.40.0",
77
- "@typescript-eslint/utils": "8.40.0",
75
+ "@typescript-eslint/parser": "8.41.0",
76
+ "@typescript-eslint/rule-tester": "8.41.0",
77
+ "@typescript-eslint/utils": "8.41.0",
78
78
  "@vitest/coverage-v8": "3.2.4",
79
79
  "@vitest/ui": "3.2.4",
80
- "concurrently": "9.2.0",
80
+ "concurrently": "9.2.1",
81
81
  "drizzle-kit": "0.31.4",
82
- "drizzle-orm": "0.44.4",
82
+ "drizzle-orm": "0.44.5",
83
83
  "eslint": "9.34.0",
84
84
  "happy-dom": "18.0.1",
85
85
  "http-proxy": "1.18.1",
@@ -96,7 +96,7 @@
96
96
  "socket.io-client": "4.8.1",
97
97
  "storybook": "9.1.3",
98
98
  "tmp": "0.2.5",
99
- "tsdown": "0.14.1",
99
+ "tsdown": "0.14.2",
100
100
  "typescript": "5.9.2",
101
101
  "vite": "7.1.3",
102
102
  "vite-tsconfig-paths": "5.1.4",
@@ -12,6 +12,7 @@ import { stringifyJson } from "atom.io/json"
12
12
 
13
13
  import type { RegularAtomFamily } from ".."
14
14
  import { createRegularAtom } from "../atom"
15
+ import { isFn } from "../is-fn"
15
16
  import { newest } from "../lineage"
16
17
  import type { Store } from "../store"
17
18
  import { Subject } from "../subject"
@@ -47,7 +48,7 @@ export function createRegularAtomFamily<T, K extends Canonical>(
47
48
  const def = options.default
48
49
  const individualOptions: RegularAtomOptions<T> = {
49
50
  key: fullKey,
50
- default: def instanceof Function ? () => def(key) : def,
51
+ default: isFn(def) ? () => def(key) : def,
51
52
  }
52
53
  if (options.effects) {
53
54
  individualOptions.effects = options.effects(key)
@@ -67,7 +68,7 @@ export function createRegularAtomFamily<T, K extends Canonical>(
67
68
  }) satisfies RegularAtomFamily<T, K>
68
69
 
69
70
  store.families.set(options.key, atomFamily)
70
- if (options.default instanceof Function === false) {
71
+ if (isFn(options.default) === false) {
71
72
  store.defaults.set(options.key, options.default)
72
73
  }
73
74
  return familyToken
@@ -2,6 +2,7 @@ import type { ViewOf } from "atom.io"
2
2
 
3
3
  import type { ReadableState } from ".."
4
4
  import { readFromCache, writeToCache } from "../caching"
5
+ import { isFn } from "../is-fn"
5
6
  import type { Store } from "../store"
6
7
 
7
8
  export function readOrComputeValue<T>(
@@ -33,7 +34,7 @@ export function readOrComputeValue<T>(
33
34
  return state.getFrom(target)
34
35
  case `atom`: {
35
36
  let def: T
36
- if (state.default instanceof Function) {
37
+ if (isFn(state.default)) {
37
38
  def = state.default()
38
39
  target.logger.info(`✨`, state.type, key, `computed default`, def)
39
40
  } else {
@@ -0,0 +1,9 @@
1
+ import type { Fn } from "./utility-types"
2
+
3
+ const NON_CTOR_FN_REGEX =
4
+ /^\[object (?:Async|Generator|AsyncGenerator)?Function\]$/
5
+
6
+ export function isFn(input: unknown): input is Fn {
7
+ const protoString = Object.prototype.toString.call(input)
8
+ return NON_CTOR_FN_REGEX.test(protoString)
9
+ }
@@ -1,8 +1,13 @@
1
+ import { isFn } from "../is-fn"
2
+
1
3
  export type Modify<T> = (thing: T) => T
2
4
 
3
- export const become =
4
- <T>(nextVersionOfThing: Modify<T> | T) =>
5
- (originalThing: T): T =>
6
- nextVersionOfThing instanceof Function
7
- ? nextVersionOfThing(originalThing)
8
- : nextVersionOfThing
5
+ export function become<T>(
6
+ nextVersionOfThing: Modify<T> | T,
7
+ originalThing: T,
8
+ ): T {
9
+ if (isFn(nextVersionOfThing)) {
10
+ return nextVersionOfThing(originalThing)
11
+ }
12
+ return nextVersionOfThing
13
+ }
@@ -15,11 +15,12 @@ import type { OpenOperation } from "../operation"
15
15
  import { deposit, type Store } from "../store"
16
16
  import { isChildStore, isRootStore } from "../transaction"
17
17
  import { evictDownstreamFromAtom } from "./evict-downstream"
18
+ import type { ProtoUpdate } from "./operate-on-store"
18
19
 
19
20
  export function dispatchOrDeferStateUpdate<T>(
20
21
  target: Store & { operation: OpenOperation<any> },
21
22
  state: WritableState<T>,
22
- [oldValue, newValue]: [T, T],
23
+ { oldValue, newValue }: ProtoUpdate<T>,
23
24
  stateIsNewlyCreated: boolean,
24
25
  family?: WritableFamily<T, any>,
25
26
  ): void {
@@ -13,6 +13,8 @@ import { resetAtomOrSelector } from "./reset-atom-or-selector"
13
13
  import { RESET_STATE } from "./reset-in-store"
14
14
  import { setAtomOrSelector } from "./set-atom-or-selector"
15
15
 
16
+ export type ProtoUpdate<T> = { oldValue: T; newValue: T }
17
+
16
18
  export const OWN_OP: unique symbol = Symbol(`OWN_OP`)
17
19
  export const JOIN_OP: unique symbol = Symbol(`JOIN_OP`)
18
20
 
@@ -114,7 +116,7 @@ export function operateOnStore<T, New extends T>(
114
116
  }
115
117
 
116
118
  const state = withdraw(target, token)
117
- let protoUpdate: [T, T]
119
+ let protoUpdate: ProtoUpdate<T>
118
120
  if (value === RESET_STATE) {
119
121
  protoUpdate = resetAtomOrSelector(target, state)
120
122
  } else {
@@ -1,20 +1,20 @@
1
1
  import type { Atom, OpenOperation, Store, WritableState } from ".."
2
2
  import { traceRootSelectorAtoms } from ".."
3
+ import { isFn } from "../is-fn"
3
4
  import { dispatchOrDeferStateUpdate } from "./dispatch-state-update"
5
+ import type { ProtoUpdate } from "./operate-on-store"
4
6
  import { setAtom } from "./set-atom"
5
7
 
6
8
  function resetAtom<T>(
7
9
  target: Store & { operation: OpenOperation },
8
10
  atom: Atom<T>,
9
- ): [oldValue: T, newValue: T] {
11
+ ): ProtoUpdate<T> {
10
12
  switch (atom.type) {
11
13
  case `mutable_atom`:
12
14
  return setAtom(target, atom, new atom.class())
13
15
  case `atom`: {
14
16
  let def = atom.default
15
- if (def instanceof Function) {
16
- def = def()
17
- }
17
+ if (isFn(def)) def = def()
18
18
  return setAtom(target, atom, def)
19
19
  }
20
20
  }
@@ -23,8 +23,8 @@ function resetAtom<T>(
23
23
  export function resetAtomOrSelector<T>(
24
24
  target: Store & { operation: OpenOperation },
25
25
  state: WritableState<T>,
26
- ): [oldValue: T, newValue: T] {
27
- let protoUpdate: [T, T]
26
+ ): ProtoUpdate<T> {
27
+ let protoUpdate: ProtoUpdate<T>
28
28
  switch (state.type) {
29
29
  case `atom`:
30
30
  case `mutable_atom`:
@@ -40,7 +40,7 @@ export function resetAtomOrSelector<T>(
40
40
  dispatchOrDeferStateUpdate(target, state, rootProtoUpdate, false)
41
41
  }
42
42
  const newValue = state.getFrom(target)
43
- protoUpdate = [oldValue, newValue]
43
+ protoUpdate = { oldValue, newValue }
44
44
  }
45
45
  break
46
46
  }
@@ -1,6 +1,7 @@
1
1
  import type { WritableState } from ".."
2
2
  import type { OpenOperation } from "../operation"
3
3
  import type { Store } from "../store"
4
+ import type { ProtoUpdate } from "./operate-on-store"
4
5
  import { setAtom } from "./set-atom"
5
6
  import { setSelector } from "./set-selector"
6
7
 
@@ -8,8 +9,8 @@ export const setAtomOrSelector = <T>(
8
9
  target: Store & { operation: OpenOperation },
9
10
  state: WritableState<T>,
10
11
  value: T | ((oldValue: T) => T),
11
- ): [oldValue: T, newValue: T] => {
12
- let protoUpdate: [T, T]
12
+ ): ProtoUpdate<T> => {
13
+ let protoUpdate: ProtoUpdate<T>
13
14
  switch (state.type) {
14
15
  case `atom`:
15
16
  case `mutable_atom`:
@@ -4,17 +4,18 @@ import { readOrComputeValue } from "../get-state/read-or-compute-value"
4
4
  import { markDone } from "../operation"
5
5
  import { become } from "./become"
6
6
  import { evictDownstreamFromAtom } from "./evict-downstream"
7
+ import type { ProtoUpdate } from "./operate-on-store"
7
8
 
8
9
  export const setAtom = <T>(
9
10
  target: Store & { operation: OpenOperation<any> },
10
11
  atom: Atom<T>,
11
12
  next: T | ((oldValue: T) => T),
12
- ): [oldValue: T, newValue: T] => {
13
+ ): ProtoUpdate<T> => {
13
14
  const oldValue = readOrComputeValue(target, atom, `mut`)
14
- let newValue = become(next)(oldValue)
15
+ let newValue = become(next, oldValue)
15
16
  target.logger.info(`⭐`, `atom`, atom.key, `setting value`, newValue)
16
17
  newValue = writeToCache(target, atom, newValue)
17
18
  markDone(target, atom.key)
18
19
  evictDownstreamFromAtom(target, atom)
19
- return [oldValue, newValue]
20
+ return { oldValue, newValue }
20
21
  }
@@ -1,14 +1,15 @@
1
- import type { WritableSelector } from ".."
1
+ import { readOrComputeValue, type WritableSelector } from ".."
2
2
  import { writeToCache } from "../caching"
3
3
  import { markDone, type OpenOperation } from "../operation"
4
4
  import type { Store } from "../store"
5
5
  import { become } from "./become"
6
+ import type { ProtoUpdate } from "./operate-on-store"
6
7
 
7
8
  export function setSelector<T>(
8
9
  target: Store & { operation: OpenOperation<any> },
9
10
  selector: WritableSelector<T>,
10
11
  next: T | ((oldValue: T) => T),
11
- ): [oldValue: T, newValue: T] {
12
+ ): ProtoUpdate<T> {
12
13
  let oldValue: T
13
14
  let newValue: T
14
15
  let constant: T
@@ -17,13 +18,13 @@ export function setSelector<T>(
17
18
 
18
19
  switch (selector.type) {
19
20
  case `writable_pure_selector`:
20
- oldValue = selector.getFrom(target)
21
- newValue = become(next)(oldValue)
22
- writeToCache(target, selector, newValue)
21
+ oldValue = readOrComputeValue(target, selector, `mut`)
22
+ newValue = become(next, oldValue)
23
+ newValue = writeToCache(target, selector, newValue)
23
24
  break
24
25
  case `writable_held_selector`:
25
26
  constant = selector.const
26
- become(next)(constant)
27
+ become(next, constant)
27
28
  oldValue = constant
28
29
  newValue = constant
29
30
  }
@@ -31,5 +32,5 @@ export function setSelector<T>(
31
32
  target.logger.info(`⭐`, type, key, `setting to`, newValue)
32
33
  markDone(target, key)
33
34
  selector.setSelf(newValue)
34
- return [oldValue, newValue]
35
+ return { oldValue, newValue }
35
36
  }
@@ -3,9 +3,9 @@ import { findInStore } from "atom.io/internal"
3
3
  import type { Json, JsonTypes } from "atom.io/json"
4
4
  import { JSON_DEFAULTS } from "atom.io/json"
5
5
  import { useI, useO } from "atom.io/react"
6
- import { DevtoolsContext } from "atom.io/react-devtools/store"
7
6
  import { type ReactElement, useContext } from "react"
8
7
 
8
+ import { DevtoolsContext } from "../../store"
9
9
  import type { JsonEditorComponents, SetterOrUpdater } from ".."
10
10
  import type { JsonEditorProps_INTERNAL } from "../json-editor-internal"
11
11
  import { JsonEditor_INTERNAL } from "../json-editor-internal"
@@ -1,13 +1,12 @@
1
1
  import type { RegularAtomToken } from "atom.io"
2
2
  import { findInStore } from "atom.io/internal"
3
3
  import type { Json, JsonTypes } from "atom.io/json"
4
- import { useI } from "atom.io/react/use-i"
5
- import { useO } from "atom.io/react/use-o"
6
- import { DevtoolsContext } from "atom.io/react-devtools/store"
4
+ import { useI, useO } from "atom.io/react"
7
5
  import type { FC, ReactElement } from "react"
8
6
  import { useContext, useRef } from "react"
9
7
 
10
8
  import { ElasticInput } from "../../elastic-input"
9
+ import { DevtoolsContext } from "../../store"
11
10
  import type { SetterOrUpdater } from ".."
12
11
  import type { JsonEditorComponents } from "../default-components"
13
12
  import type { JsonEditorProps_INTERNAL } from "../json-editor-internal"
@@ -10,7 +10,7 @@ export const makeElementSetters = <T extends Json.Tree.Array>(
10
10
  data.map((value, index) => (newValue) => {
11
11
  set((): T => {
12
12
  const newData = [...data]
13
- newData[index] = become(newValue)(value)
13
+ newData[index] = become(newValue, value)
14
14
  return newData as unknown as T
15
15
  })
16
16
  })
@@ -14,7 +14,7 @@ export const makePropertySetters = <T extends Json.Tree.Object>(
14
14
  toEntries(data).map(([key, value]) => [
15
15
  key,
16
16
  (newValue: unknown) => {
17
- set({ ...data, [key]: become(newValue)(value) })
17
+ set({ ...data, [key]: become(newValue, value) })
18
18
  },
19
19
  ]),
20
20
  )
@@ -1,47 +0,0 @@
1
- import { IMPLICIT, findInStore, getFromStore, setIntoStore, subscribeToState } from "atom.io/internal";
2
- import * as React$1 from "react";
3
- import { jsx } from "react/jsx-runtime";
4
-
5
- //#region src/react/store-context.tsx
6
- const StoreContext = React$1.createContext(IMPLICIT.STORE);
7
- const StoreProvider = ({ children, store = IMPLICIT.STORE }) => /* @__PURE__ */ jsx(StoreContext.Provider, {
8
- value: store,
9
- children
10
- });
11
-
12
- //#endregion
13
- //#region src/react/parse-state-overloads.ts
14
- function parseStateOverloads(store, ...rest) {
15
- let token;
16
- if (rest.length === 2) {
17
- const family = rest[0];
18
- const key = rest[1];
19
- token = findInStore(store, family, key);
20
- } else token = rest[0];
21
- return token;
22
- }
23
-
24
- //#endregion
25
- //#region src/react/use-i.ts
26
- function useI(...params) {
27
- const store = React$1.useContext(StoreContext);
28
- const token = parseStateOverloads(store, ...params);
29
- const setter = React$1.useRef(null);
30
- setter.current ??= (next) => {
31
- setIntoStore(store, token, next);
32
- };
33
- return setter.current;
34
- }
35
-
36
- //#endregion
37
- //#region src/react/use-o.ts
38
- function useO(...params) {
39
- const store = React$1.useContext(StoreContext);
40
- const token = parseStateOverloads(store, ...params);
41
- const id = React$1.useId();
42
- return React$1.useSyncExternalStore((dispatch) => subscribeToState(store, token, `use-o:${id}`, dispatch), () => getFromStore(store, token), () => getFromStore(store, token));
43
- }
44
-
45
- //#endregion
46
- export { StoreContext, StoreProvider, useI, useO };
47
- //# sourceMappingURL=use-o-DXPncKmZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-o-DXPncKmZ.js","names":["StoreContext: React.Context<Store>","React","StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: Store\n}>","token: ReadableToken<any>","React","setter: React.RefObject<\n\t\t(<New extends T>(next: New | ((old: T) => New)) => void) | null\n\t>","React"],"sources":["../src/react/store-context.tsx","../src/react/parse-state-overloads.ts","../src/react/use-i.ts","../src/react/use-o.ts"],"sourcesContent":["import type { Store } from \"atom.io/internal\"\nimport { IMPLICIT } from \"atom.io/internal\"\nimport * as React from \"react\"\n\nexport const StoreContext: React.Context<Store> = React.createContext(\n\tIMPLICIT.STORE,\n)\n\nexport const StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: Store\n}> = ({ children, store = IMPLICIT.STORE }) => (\n\t<StoreContext.Provider value={store}>{children}</StoreContext.Provider>\n)\n","import type {\n\tReadableFamilyToken,\n\tReadableToken,\n\tWritableFamilyToken,\n\tWritableToken,\n} from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { findInStore } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\n\nexport function parseStateOverloads<T, K extends Canonical>(\n\tstore: Store,\n\t...rest: [WritableFamilyToken<T, K>, K] | [WritableToken<T>]\n): WritableToken<T>\n\nexport function parseStateOverloads<T, K extends Canonical>(\n\tstore: Store,\n\t...rest: [ReadableFamilyToken<T, K>, K] | [ReadableToken<T>]\n): ReadableToken<T>\n\nexport function parseStateOverloads<T, K extends Canonical>(\n\tstore: Store,\n\t...rest: [ReadableFamilyToken<T, K>, K] | [ReadableToken<T>]\n): ReadableToken<T> {\n\tlet token: ReadableToken<any>\n\tif (rest.length === 2) {\n\t\tconst family = rest[0]\n\t\tconst key = rest[1]\n\n\t\ttoken = findInStore(store, family, key)\n\t} else {\n\t\ttoken = rest[0]\n\t}\n\treturn token\n}\n","import type { WritableFamilyToken, WritableToken } from \"atom.io\"\nimport { setIntoStore } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport * as React from \"react\"\n\nimport { parseStateOverloads } from \"./parse-state-overloads\"\nimport { StoreContext } from \"./store-context\"\n\nexport function useI<T>(\n\ttoken: WritableToken<T>,\n): <New extends T>(next: New | ((old: T) => New)) => void\n\nexport function useI<T, K extends Canonical>(\n\ttoken: WritableFamilyToken<T, K>,\n\tkey: K,\n): <New extends T>(next: New | ((old: T) => New)) => void\n\nexport function useI<T, K extends Canonical>(\n\t...params: [WritableFamilyToken<T, K>, K] | [WritableToken<T>]\n): <New extends T>(next: New | ((old: T) => New)) => void {\n\tconst store = React.useContext(StoreContext)\n\tconst token = parseStateOverloads(store, ...params)\n\tconst setter: React.RefObject<\n\t\t(<New extends T>(next: New | ((old: T) => New)) => void) | null\n\t> = React.useRef(null)\n\tsetter.current ??= (next) => {\n\t\tsetIntoStore(store, token, next)\n\t}\n\treturn setter.current\n}\n","import type { ReadableFamilyToken, ReadableToken } from \"atom.io\"\nimport { getFromStore, subscribeToState } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport * as React from \"react\"\n\nimport { parseStateOverloads } from \"./parse-state-overloads\"\nimport { StoreContext } from \"./store-context\"\n\nexport function useO<T>(token: ReadableToken<T>): T\n\nexport function useO<T, K extends Canonical>(\n\ttoken: ReadableFamilyToken<T, K>,\n\tkey: K,\n): T\n\nexport function useO<T, K extends Canonical>(\n\t...params: [ReadableFamilyToken<T, K>, K] | [ReadableToken<T>]\n): T {\n\tconst store = React.useContext(StoreContext)\n\tconst token = parseStateOverloads(store, ...params)\n\tconst id = React.useId()\n\treturn React.useSyncExternalStore<T>(\n\t\t(dispatch) => subscribeToState(store, token, `use-o:${id}`, dispatch),\n\t\t() => getFromStore(store, token),\n\t\t() => getFromStore(store, token),\n\t)\n}\n"],"mappings":";;;;;AAIA,MAAaA,eAAqCC,QAAM,cACvD,SAAS;AAGV,MAAaC,iBAGP,EAAE,UAAU,QAAQ,SAAS,OAAO,KACzC,oBAAC,aAAa;CAAS,OAAO;CAAQ;;;;;ACQvC,SAAgB,oBACf,OACA,GAAG,MACgB;CACnB,IAAIC;AACJ,KAAI,KAAK,WAAW,GAAG;EACtB,MAAM,SAAS,KAAK;EACpB,MAAM,MAAM,KAAK;AAEjB,UAAQ,YAAY,OAAO,QAAQ;CACnC,MACA,SAAQ,KAAK;AAEd,QAAO;AACP;;;;ACjBD,SAAgB,KACf,GAAG,QACsD;CACzD,MAAM,QAAQC,QAAM,WAAW;CAC/B,MAAM,QAAQ,oBAAoB,OAAO,GAAG;CAC5C,MAAMC,SAEFD,QAAM,OAAO;AACjB,QAAO,aAAa,SAAS;AAC5B,eAAa,OAAO,OAAO;CAC3B;AACD,QAAO,OAAO;AACd;;;;ACdD,SAAgB,KACf,GAAG,QACC;CACJ,MAAM,QAAQE,QAAM,WAAW;CAC/B,MAAM,QAAQ,oBAAoB,OAAO,GAAG;CAC5C,MAAM,KAAKA,QAAM;AACjB,QAAOA,QAAM,sBACX,aAAa,iBAAiB,OAAO,OAAO,SAAS,MAAM,iBACtD,aAAa,OAAO,cACpB,aAAa,OAAO;AAE3B"}