atom.io 0.44.15 → 0.45.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 (61) hide show
  1. package/dist/eslint-plugin/index.js +1 -1
  2. package/dist/introspection/index.d.ts +3 -2
  3. package/dist/introspection/index.d.ts.map +1 -1
  4. package/dist/introspection/index.js.map +1 -1
  5. package/dist/json/index.d.ts +34 -20
  6. package/dist/json/index.d.ts.map +1 -1
  7. package/dist/json/index.js +40 -2
  8. package/dist/json/index.js.map +1 -1
  9. package/dist/main/index.d.ts +1 -1
  10. package/dist/main/index.d.ts.map +1 -1
  11. package/dist/react/index.d.ts +4 -4
  12. package/dist/react/index.d.ts.map +1 -1
  13. package/dist/react/index.js +13 -1
  14. package/dist/react/index.js.map +1 -1
  15. package/dist/react-devtools/index.d.ts.map +1 -1
  16. package/dist/react-devtools/index.js.map +1 -1
  17. package/dist/realtime-client/index.d.ts +1 -1
  18. package/dist/realtime-client/index.d.ts.map +1 -1
  19. package/dist/realtime-client/index.js.map +1 -1
  20. package/dist/realtime-react/index.js.map +1 -1
  21. package/dist/realtime-testing/index.js +1 -1
  22. package/dist/transceivers/o-list/index.d.ts +1 -2
  23. package/dist/transceivers/o-list/index.d.ts.map +1 -1
  24. package/dist/transceivers/o-list/index.js +23 -24
  25. package/dist/transceivers/o-list/index.js.map +1 -1
  26. package/dist/transceivers/u-list/index.d.ts +1 -2
  27. package/dist/transceivers/u-list/index.d.ts.map +1 -1
  28. package/dist/transceivers/u-list/index.js +5 -6
  29. package/dist/transceivers/u-list/index.js.map +1 -1
  30. package/package.json +4 -12
  31. package/src/introspection/attach-introspection-states.ts +1 -1
  32. package/src/introspection/attach-transaction-logs.ts +2 -2
  33. package/src/introspection/index.ts +3 -0
  34. package/src/json/canonical.ts +42 -0
  35. package/src/json/enumeration.ts +36 -0
  36. package/src/json/index.ts +3 -132
  37. package/src/json/json.ts +128 -0
  38. package/src/main/index.ts +9 -2
  39. package/src/react/use-loadable.ts +10 -5
  40. package/src/react/use-o.ts +33 -1
  41. package/src/react-devtools/TransactionIndex.tsx +1 -1
  42. package/src/react-devtools/store.ts +3 -3
  43. package/src/realtime-client/continuity/register-and-attempt-confirmed-update.ts +2 -2
  44. package/src/realtime-react/use-pull-selector-family-member.ts +0 -1
  45. package/src/transceivers/o-list/o-list.ts +27 -28
  46. package/src/transceivers/u-list/u-list.ts +7 -8
  47. package/dist/data/index.d.ts +0 -23
  48. package/dist/data/index.d.ts.map +0 -1
  49. package/dist/data/index.js +0 -63
  50. package/dist/data/index.js.map +0 -1
  51. package/dist/struct/index.d.ts +0 -14
  52. package/dist/struct/index.d.ts.map +0 -1
  53. package/dist/struct/index.js +0 -37
  54. package/dist/struct/index.js.map +0 -1
  55. package/src/data/dict.ts +0 -31
  56. package/src/data/index.ts +0 -3
  57. package/src/data/struct-family.ts +0 -53
  58. package/src/data/struct.ts +0 -54
  59. package/src/struct/index.ts +0 -1
  60. package/src/struct/micro.ts +0 -72
  61. /package/dist/{chunk-D8lmAICg.js → chunk-CKcAJnC7.js} +0 -0
@@ -1,6 +1,5 @@
1
1
  import { Subject, getUpdateToken, subscribeInStore } from "atom.io/internal";
2
- import { stringifyJson } from "atom.io/json";
3
- import { enumeration, packValue, unpackValue } from "atom.io/struct";
2
+ import { enumeration, packCanonical, stringifyJson, unpackCanonical } from "atom.io/json";
4
3
 
5
4
  //#region src/transceivers/u-list/u-list.ts
6
5
  const SET_UPDATE_ENUM = enumeration([
@@ -87,19 +86,19 @@ var UList = class UList extends Set {
87
86
  }
88
87
  static packUpdate(update) {
89
88
  const head = SET_UPDATE_ENUM[update.type] + `\u001F`;
90
- if (update.type === `clear`) return head + update.values.map(packValue).join(`\u001E`);
91
- return head + packValue(update.value);
89
+ if (update.type === `clear`) return head + update.values.map(packCanonical).join(`\u001E`);
90
+ return head + packCanonical(update.value);
92
91
  }
93
92
  static unpackUpdate(packed) {
94
93
  const [type, tail] = packed.split(`\u001F`);
95
94
  const head = SET_UPDATE_ENUM[type];
96
95
  if (head === `clear`) return {
97
96
  type: `clear`,
98
- values: tail.split(`\u001E`).map(unpackValue)
97
+ values: tail.split(`\u001E`).map(unpackCanonical)
99
98
  };
100
99
  return {
101
100
  type: head,
102
- value: unpackValue(tail)
101
+ value: unpackCanonical(tail)
103
102
  };
104
103
  }
105
104
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["SET_UPDATE_ENUM: Enumeration<[`add`, `delete`, `clear`]>","uListDisposedKeyCleanupEffect: AtomEffect<UList<primitive>>"],"sources":["../../../src/transceivers/u-list/u-list.ts","../../../src/transceivers/u-list/u-list-disposed-key-cleanup-effect.ts"],"sourcesContent":["import type { Fn, Transceiver, TransceiverMode } from \"atom.io/internal\"\nimport { Subject } from \"atom.io/internal\"\nimport type { primitive } from \"atom.io/json\"\nimport type { Enumeration } from \"atom.io/struct\"\nimport { enumeration, packValue, unpackValue } from \"atom.io/struct\"\n\nexport type SetMutations = Exclude<\n\tkeyof Set<any>,\n\tsymbol | keyof ReadonlySet<any>\n>\nexport type SetUpdate<P extends primitive> =\n\t| {\n\t\t\ttype: `add` | `delete`\n\t\t\tvalue: P\n\t }\n\t| {\n\t\t\ttype: `clear`\n\t\t\tvalues: P[]\n\t }\nexport type UListUpdateType = SetUpdate<any>[`type`]\ntrue satisfies SetMutations extends UListUpdateType\n\t? true\n\t: Exclude<SetMutations, UListUpdateType>\n\nexport type PackedSetUpdate<P extends primitive> = string & {\n\tupdate?: SetUpdate<P>\n}\n\nexport const SET_UPDATE_ENUM: Enumeration<[`add`, `delete`, `clear`]> =\n\tenumeration([`add`, `delete`, `clear`] as const)\n\nexport type SetMutationHandler = { [K in UListUpdateType]: Fn }\n\nexport type UListView<P extends primitive> = ReadonlySet<P> & {\n\tsubscribe: (\n\t\tkey: string,\n\t\tfn: (update: PackedSetUpdate<P>) => void,\n\t) => () => void\n}\n\nexport class UList<P extends primitive>\n\textends Set<P>\n\timplements\n\t\tTransceiver<UListView<P>, PackedSetUpdate<P>, ReadonlyArray<P>>,\n\t\tSetMutationHandler\n{\n\tpublic mode: TransceiverMode = `record`\n\tpublic readonly subject: Subject<PackedSetUpdate<P>> = new Subject()\n\n\tpublic constructor(values?: Iterable<P>) {\n\t\tsuper(values)\n\t\tif (values instanceof UList) {\n\t\t}\n\t}\n\n\tpublic readonly READONLY_VIEW: UListView<P> = this\n\n\tpublic toJSON(): ReadonlyArray<P> {\n\t\treturn [...this]\n\t}\n\n\tpublic static fromJSON<P extends primitive>(json: ReadonlyArray<P>): UList<P> {\n\t\treturn new UList<P>(json)\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.emit({ type: `add`, 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.emit({ type: `clear`, values: 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.emit({ type: `delete`, value })\n\t\t}\n\t\treturn result\n\t}\n\n\tpublic subscribe(\n\t\tkey: string,\n\t\tfn: (update: PackedSetUpdate<P>) => void,\n\t): () => void {\n\t\treturn this.subject.subscribe(key, fn)\n\t}\n\n\tpublic emit(update: SetUpdate<P>): void {\n\t\tthis.subject.next(UList.packUpdate(update))\n\t}\n\n\tpublic do(packed: PackedSetUpdate<P>): null {\n\t\tthis.mode = `playback`\n\t\tconst update = UList.unpackUpdate(packed)\n\t\tswitch (update.type) {\n\t\t\tcase `add`:\n\t\t\t\tthis.add(update.value)\n\t\t\t\tbreak\n\t\t\tcase `delete`:\n\t\t\t\tthis.delete(update.value)\n\t\t\t\tbreak\n\t\t\tcase `clear`:\n\t\t\t\tthis.clear()\n\t\t}\n\t\tthis.mode = `record`\n\t\treturn null\n\t}\n\n\tpublic undo(packed: PackedSetUpdate<P>): number | null {\n\t\tconst update = UList.unpackUpdate(packed)\n\t\tthis.mode = `playback`\n\t\tswitch (update.type) {\n\t\t\tcase `add`:\n\t\t\t\tthis.delete(update.value)\n\t\t\t\tbreak\n\t\t\tcase `delete`:\n\t\t\t\tthis.add(update.value)\n\t\t\t\tbreak\n\t\t\tcase `clear`: {\n\t\t\t\tconst values = update.values\n\t\t\t\tfor (const v of values) this.add(v)\n\t\t\t}\n\t\t}\n\t\tthis.mode = `record`\n\t\treturn null\n\t}\n\n\tpublic static packUpdate<P extends primitive>(\n\t\tupdate: SetUpdate<P>,\n\t): PackedSetUpdate<P> {\n\t\tconst head = SET_UPDATE_ENUM[update.type] + `\\u001F`\n\t\tif (update.type === `clear`) {\n\t\t\treturn head + update.values.map(packValue).join(`\\u001E`)\n\t\t}\n\t\treturn head + packValue(update.value)\n\t}\n\tpublic static unpackUpdate<P extends primitive>(\n\t\tpacked: PackedSetUpdate<P>,\n\t): SetUpdate<P> {\n\t\tconst [type, tail] = packed.split(`\\u001F`) as [0 | 1 | 2, string]\n\t\tconst head = SET_UPDATE_ENUM[type]\n\t\tif (head === `clear`) {\n\t\t\tconst values = tail.split(`\\u001E`).map(unpackValue) as P[]\n\t\t\treturn { type: `clear`, values }\n\t\t}\n\t\treturn { type: head, value: unpackValue(tail) as P }\n\t}\n}\n","import type { AtomEffect } from \"atom.io\"\nimport { getUpdateToken, subscribeInStore } from \"atom.io/internal\"\nimport { type primitive, stringifyJson } from \"atom.io/json\"\n\nimport { UList } from \"./u-list\"\n\nexport const uListDisposedKeyCleanupEffect: AtomEffect<UList<primitive>> = ({\n\ttoken,\n\tsetSelf,\n\tstore,\n}) => {\n\tconst disposalSubscriptions = new Map<primitive, () => void>()\n\tconst updateToken = getUpdateToken(token)\n\tsubscribeInStore(\n\t\tstore,\n\t\tupdateToken,\n\t\tfunction setAutoDeletionTriggers({ newValue }) {\n\t\t\tconst unpacked = UList.unpackUpdate(newValue)\n\t\t\tswitch (unpacked.type) {\n\t\t\t\tcase `add`:\n\t\t\t\t\t{\n\t\t\t\t\t\tconst molecule = store.molecules.get(stringifyJson(unpacked.value))\n\t\t\t\t\t\tif (molecule) {\n\t\t\t\t\t\t\tdisposalSubscriptions.set(\n\t\t\t\t\t\t\t\tunpacked.value,\n\t\t\t\t\t\t\t\tmolecule.subject.subscribe(token.key, () => {\n\t\t\t\t\t\t\t\t\tsetSelf((self) => {\n\t\t\t\t\t\t\t\t\t\tself.delete(unpacked.value)\n\t\t\t\t\t\t\t\t\t\treturn self\n\t\t\t\t\t\t\t\t\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\tbreak\n\t\t\t\tcase `delete`:\n\t\t\t\t\tdisposalSubscriptions.get(unpacked.value)?.()\n\t\t\t\t\tdisposalSubscriptions.delete(unpacked.value)\n\t\t\t\t\tbreak\n\t\t\t\tcase `clear`:\n\t\t\t\t\tfor (const unsub of disposalSubscriptions.values()) unsub()\n\t\t\t\t\tdisposalSubscriptions.clear()\n\t\t\t}\n\t\t},\n\t\t`set-auto-deletion-triggers`,\n\t)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["SET_UPDATE_ENUM: Enumeration<[`add`, `delete`, `clear`]>","uListDisposedKeyCleanupEffect: AtomEffect<UList<primitive>>"],"sources":["../../../src/transceivers/u-list/u-list.ts","../../../src/transceivers/u-list/u-list-disposed-key-cleanup-effect.ts"],"sourcesContent":["import type { Fn, Transceiver, TransceiverMode } from \"atom.io/internal\"\nimport { Subject } from \"atom.io/internal\"\nimport type { Enumeration, packed, primitive } from \"atom.io/json\"\nimport { enumeration, packCanonical, unpackCanonical } from \"atom.io/json\"\n\nexport type SetMutations = Exclude<\n\tkeyof Set<any>,\n\tsymbol | keyof ReadonlySet<any>\n>\nexport type SetUpdate<P extends primitive> =\n\t| {\n\t\t\ttype: `add` | `delete`\n\t\t\tvalue: P\n\t }\n\t| {\n\t\t\ttype: `clear`\n\t\t\tvalues: P[]\n\t }\nexport type UListUpdateType = SetUpdate<any>[`type`]\ntrue satisfies SetMutations extends UListUpdateType\n\t? true\n\t: Exclude<SetMutations, UListUpdateType>\n\nexport type PackedSetUpdate<P extends primitive> = string & {\n\tupdate?: SetUpdate<P>\n}\n\nexport const SET_UPDATE_ENUM: Enumeration<[`add`, `delete`, `clear`]> =\n\tenumeration([`add`, `delete`, `clear`] as const)\n\nexport type SetMutationHandler = { [K in UListUpdateType]: Fn }\n\nexport type UListView<P extends primitive> = ReadonlySet<P> & {\n\tsubscribe: (\n\t\tkey: string,\n\t\tfn: (update: PackedSetUpdate<P>) => void,\n\t) => () => void\n}\n\nexport class UList<P extends primitive>\n\textends Set<P>\n\timplements\n\t\tTransceiver<UListView<P>, PackedSetUpdate<P>, ReadonlyArray<P>>,\n\t\tSetMutationHandler\n{\n\tpublic mode: TransceiverMode = `record`\n\tpublic readonly subject: Subject<PackedSetUpdate<P>> = new Subject()\n\n\tpublic constructor(values?: Iterable<P>) {\n\t\tsuper(values)\n\t\tif (values instanceof UList) {\n\t\t}\n\t}\n\n\tpublic readonly READONLY_VIEW: UListView<P> = this\n\n\tpublic toJSON(): ReadonlyArray<P> {\n\t\treturn [...this]\n\t}\n\n\tpublic static fromJSON<P extends primitive>(json: ReadonlyArray<P>): UList<P> {\n\t\treturn new UList<P>(json)\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.emit({ type: `add`, 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.emit({ type: `clear`, values: 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.emit({ type: `delete`, value })\n\t\t}\n\t\treturn result\n\t}\n\n\tpublic subscribe(\n\t\tkey: string,\n\t\tfn: (update: PackedSetUpdate<P>) => void,\n\t): () => void {\n\t\treturn this.subject.subscribe(key, fn)\n\t}\n\n\tpublic emit(update: SetUpdate<P>): void {\n\t\tthis.subject.next(UList.packUpdate(update))\n\t}\n\n\tpublic do(packed: PackedSetUpdate<P>): null {\n\t\tthis.mode = `playback`\n\t\tconst update = UList.unpackUpdate(packed)\n\t\tswitch (update.type) {\n\t\t\tcase `add`:\n\t\t\t\tthis.add(update.value)\n\t\t\t\tbreak\n\t\t\tcase `delete`:\n\t\t\t\tthis.delete(update.value)\n\t\t\t\tbreak\n\t\t\tcase `clear`:\n\t\t\t\tthis.clear()\n\t\t}\n\t\tthis.mode = `record`\n\t\treturn null\n\t}\n\n\tpublic undo(packed: PackedSetUpdate<P>): number | null {\n\t\tconst update = UList.unpackUpdate(packed)\n\t\tthis.mode = `playback`\n\t\tswitch (update.type) {\n\t\t\tcase `add`:\n\t\t\t\tthis.delete(update.value)\n\t\t\t\tbreak\n\t\t\tcase `delete`:\n\t\t\t\tthis.add(update.value)\n\t\t\t\tbreak\n\t\t\tcase `clear`: {\n\t\t\t\tconst values = update.values\n\t\t\t\tfor (const v of values) this.add(v)\n\t\t\t}\n\t\t}\n\t\tthis.mode = `record`\n\t\treturn null\n\t}\n\n\tpublic static packUpdate<P extends primitive>(\n\t\tupdate: SetUpdate<P>,\n\t): PackedSetUpdate<P> {\n\t\tconst head = SET_UPDATE_ENUM[update.type] + `\\u001F`\n\t\tif (update.type === `clear`) {\n\t\t\treturn head + update.values.map(packCanonical).join(`\\u001E`)\n\t\t}\n\t\treturn head + packCanonical(update.value)\n\t}\n\tpublic static unpackUpdate<P extends primitive>(\n\t\tpacked: PackedSetUpdate<P>,\n\t): SetUpdate<P> {\n\t\tconst [type, tail] = packed.split(`\\u001F`) as [0 | 1 | 2, packed<P>]\n\t\tconst head = SET_UPDATE_ENUM[type]\n\t\tif (head === `clear`) {\n\t\t\tconst values = tail.split(`\\u001E`).map<P>(unpackCanonical)\n\t\t\treturn { type: `clear`, values }\n\t\t}\n\t\treturn { type: head, value: unpackCanonical(tail) }\n\t}\n}\n","import type { AtomEffect } from \"atom.io\"\nimport { getUpdateToken, subscribeInStore } from \"atom.io/internal\"\nimport { type primitive, stringifyJson } from \"atom.io/json\"\n\nimport { UList } from \"./u-list\"\n\nexport const uListDisposedKeyCleanupEffect: AtomEffect<UList<primitive>> = ({\n\ttoken,\n\tsetSelf,\n\tstore,\n}) => {\n\tconst disposalSubscriptions = new Map<primitive, () => void>()\n\tconst updateToken = getUpdateToken(token)\n\tsubscribeInStore(\n\t\tstore,\n\t\tupdateToken,\n\t\tfunction setAutoDeletionTriggers({ newValue }) {\n\t\t\tconst unpacked = UList.unpackUpdate(newValue)\n\t\t\tswitch (unpacked.type) {\n\t\t\t\tcase `add`:\n\t\t\t\t\t{\n\t\t\t\t\t\tconst molecule = store.molecules.get(stringifyJson(unpacked.value))\n\t\t\t\t\t\tif (molecule) {\n\t\t\t\t\t\t\tdisposalSubscriptions.set(\n\t\t\t\t\t\t\t\tunpacked.value,\n\t\t\t\t\t\t\t\tmolecule.subject.subscribe(token.key, () => {\n\t\t\t\t\t\t\t\t\tsetSelf((self) => {\n\t\t\t\t\t\t\t\t\t\tself.delete(unpacked.value)\n\t\t\t\t\t\t\t\t\t\treturn self\n\t\t\t\t\t\t\t\t\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\tbreak\n\t\t\t\tcase `delete`:\n\t\t\t\t\tdisposalSubscriptions.get(unpacked.value)?.()\n\t\t\t\t\tdisposalSubscriptions.delete(unpacked.value)\n\t\t\t\t\tbreak\n\t\t\t\tcase `clear`:\n\t\t\t\t\tfor (const unsub of disposalSubscriptions.values()) unsub()\n\t\t\t\t\tdisposalSubscriptions.clear()\n\t\t\t}\n\t\t},\n\t\t`set-auto-deletion-triggers`,\n\t)\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atom.io",
3
- "version": "0.44.15",
3
+ "version": "0.45.1",
4
4
  "description": "Composable and testable reactive data library.",
5
5
  "homepage": "https://atom.io.fyi",
6
6
  "sideEffects": false,
@@ -72,7 +72,7 @@
72
72
  "@typescript-eslint/parser": "8.47.0",
73
73
  "@typescript-eslint/rule-tester": "8.47.0",
74
74
  "@typescript-eslint/utils": "8.47.0",
75
- "@typescript/native-preview": "7.0.0-dev.20251129.1",
75
+ "@typescript/native-preview": "7.0.0-dev.20251130.1",
76
76
  "@vitest/coverage-v8": "4.0.14",
77
77
  "@vitest/ui": "4.0.14",
78
78
  "arktype": "2.1.27",
@@ -97,8 +97,8 @@
97
97
  "vite": "7.2.4",
98
98
  "vite-tsconfig-paths": "5.1.4",
99
99
  "vitest": "4.0.14",
100
- "break-check": "0.6.23",
101
- "takua": "0.1.1"
100
+ "takua": "0.1.1",
101
+ "break-check": "0.6.24"
102
102
  },
103
103
  "main": "./dist/main/index.js",
104
104
  "files": [
@@ -111,10 +111,6 @@
111
111
  "import": "./dist/main/index.js",
112
112
  "types": "./dist/main/index.d.ts"
113
113
  },
114
- "./data": {
115
- "import": "./dist/data/index.js",
116
- "types": "./dist/data/index.d.ts"
117
- },
118
114
  "./eslint-plugin": {
119
115
  "import": "./dist/eslint-plugin/index.js",
120
116
  "types": "./dist/eslint-plugin/index.d.ts"
@@ -162,10 +158,6 @@
162
158
  "import": "./dist/realtime-testing/index.js",
163
159
  "types": "./dist/realtime-testing/index.d.ts"
164
160
  },
165
- "./struct": {
166
- "import": "./dist/struct/index.js",
167
- "types": "./dist/struct/index.d.ts"
168
- },
169
161
  "./transceivers/o-list": {
170
162
  "import": "./dist/transceivers/o-list/index.js",
171
163
  "types": "./dist/transceivers/o-list/index.d.ts"
@@ -22,7 +22,7 @@ export type IntrospectionStates = {
22
22
  selectorIndex: AtomToken<SelectorTokenIndex>
23
23
  transactionIndex: AtomToken<TransactionToken<Fn>[]>
24
24
  transactionLogSelectors: ReadonlyPureSelectorFamilyToken<
25
- TransactionOutcomeEvent<TransactionToken<Fn>>[],
25
+ readonly TransactionOutcomeEvent<TransactionToken<Fn>>[],
26
26
  string
27
27
  >
28
28
  timelineIndex: AtomToken<TimelineToken<any>[]>
@@ -9,7 +9,7 @@ import { createRegularAtomFamily, createSelectorFamily } from "atom.io/internal"
9
9
  export const attachTransactionLogs = (
10
10
  store: RootStore,
11
11
  ): ReadonlyPureSelectorFamilyToken<
12
- TransactionOutcomeEvent<TransactionToken<any>>[],
12
+ readonly TransactionOutcomeEvent<TransactionToken<any>>[],
13
13
  string
14
14
  > => {
15
15
  const transactionUpdateLogAtoms = createRegularAtomFamily<
@@ -31,7 +31,7 @@ export const attachTransactionLogs = (
31
31
  ],
32
32
  })
33
33
  const findTransactionUpdateLogState = createSelectorFamily<
34
- TransactionOutcomeEvent<TransactionToken<any>>[],
34
+ readonly TransactionOutcomeEvent<TransactionToken<any>>[],
35
35
  string,
36
36
  never
37
37
  >(store, {
@@ -11,5 +11,8 @@ export type FamilyNode<Token extends ReadableToken<unknown, any, any>> = {
11
11
  familyMembers: Map<string, Token>
12
12
  }
13
13
 
14
+ export type ReadonlyTokenIndex<Token extends ReadableToken<unknown, any, any>> =
15
+ ReadonlyMap<string, FamilyNode<Token> | Token>
16
+
14
17
  export type WritableTokenIndex<Token extends ReadableToken<unknown, any, any>> =
15
18
  Map<string, FamilyNode<Token> | Token>
@@ -0,0 +1,42 @@
1
+ import type { primitive } from "./json"
2
+
3
+ /** Only Canonical values should be used for keys because they always serialize to the same string */
4
+ export type Canonical = primitive | ReadonlyArray<Canonical>
5
+
6
+ export type packed<C extends Canonical> = string & { __canonical?: C }
7
+
8
+ const BOOL = `\u0001`
9
+ const NULL = `\u0002`
10
+ const STRING = `\u0003`
11
+ const NUMBER = `\u0004`
12
+ export const packCanonical = <C extends Canonical>(
13
+ value: Canonical,
14
+ ): packed<C> => {
15
+ if (value === null) return NULL
16
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
17
+ switch (typeof value) {
18
+ case `string`:
19
+ return STRING + value
20
+ case `number`:
21
+ return NUMBER + value
22
+ case `boolean`:
23
+ return BOOL + +value
24
+ case `object`: // array
25
+ return JSON.stringify(value)
26
+ }
27
+ }
28
+ export const unpackCanonical = <C extends Canonical>(value: packed<C>): C => {
29
+ const type = value[0] as `[` | `\u0001` | `\u0002` | `\u0003` | `\u0004`
30
+ switch (type) {
31
+ case STRING:
32
+ return value.slice(1) as C
33
+ case NUMBER:
34
+ return +value.slice(1) as C
35
+ case BOOL:
36
+ return (value.slice(1) === `1`) as C
37
+ case NULL:
38
+ return null as C
39
+ case `[`:
40
+ return JSON.parse(value)
41
+ }
42
+ }
@@ -0,0 +1,36 @@
1
+ import type { Flat } from "atom.io/internal"
2
+
3
+ export type IndexOf<
4
+ T extends readonly unknown[],
5
+ E,
6
+ A extends unknown[] = [],
7
+ > = T extends readonly [infer Head, ...infer Tail]
8
+ ? (<U>() => U extends Head ? 1 : 2) extends <U>() => U extends E ? 1 : 2
9
+ ? A[`length`]
10
+ : IndexOf<Tail, E, [...A, unknown]>
11
+ : never
12
+
13
+ export type Flip<T extends Record<string, number | string>> = {
14
+ [K in keyof T as T[K]]: K
15
+ }
16
+
17
+ export type TwoWay<T extends Record<string, number | string>> = Flip<T> & T
18
+
19
+ export type Enumeration<T extends readonly string[]> = Flat<
20
+ TwoWay<{
21
+ [K in T[number]]: IndexOf<T, K>
22
+ }>
23
+ >
24
+
25
+ export function enumeration<T extends readonly string[]>(
26
+ values: T,
27
+ ): Enumeration<T> {
28
+ const result: Record<any, any> = {}
29
+ let i = 0
30
+ for (const value of values) {
31
+ result[value] = i
32
+ result[i] = value
33
+ ++i
34
+ }
35
+ return result as Enumeration<T>
36
+ }
package/src/json/index.ts CHANGED
@@ -1,133 +1,4 @@
1
- import type { ViewOf } from "atom.io"
2
-
1
+ export * from "./canonical"
3
2
  export * from "./entries"
4
-
5
- export type primitive = boolean | number | string | null
6
-
7
- export namespace Json {
8
- export namespace Tree {
9
- // eslint-disable-next-line @typescript-eslint/no-shadow
10
- export type Array<Element = unknown> = ReadonlyArray<Element>
11
- // eslint-disable-next-line @typescript-eslint/no-shadow
12
- export type Object<K extends string = string, V = unknown> = Record<K, V>
13
- export type Fork = Array | Object
14
- export type Leaf = primitive
15
- export type Node = Fork | Leaf
16
- }
17
-
18
- /** A value can survive being {@link JSON.stringify}-ed and {@link JSON.parse}-d fully intact */
19
- export type Serializable =
20
- | primitive
21
- | Readonly<{ [key: string]: Serializable }>
22
- | ReadonlyArray<Serializable>
23
-
24
- export type Object<
25
- Key extends string = string,
26
- Value extends Serializable = Serializable,
27
- > = Record<Key, Value>
28
-
29
- export type Array<Element extends Serializable = Serializable> =
30
- ReadonlyArray<Element>
31
- }
32
-
33
- /** A generic that retains the type information of a {@link Json.Serializable} value while in string form */
34
- // biome-ignore format: long silly ternary
35
- export type stringified<J extends Json.Serializable> = (
36
- J extends string
37
- ? `"${J}"`
38
- : J extends number
39
- ? `${J}`
40
- : J extends true
41
- ? `true`
42
- : J extends false
43
- ? `false`
44
- : J extends boolean
45
- ? `false` | `true`
46
- : J extends null
47
- ? `null`
48
- : J extends []
49
- ? `[]`
50
- : J extends [infer Element extends Json.Serializable]
51
- ? `[${stringified<Element>}]`
52
- : J extends [
53
- infer Element1 extends Json.Serializable,
54
- infer Element2 extends Json.Serializable,
55
- ]
56
- ? `[${stringified<Element1>}, ${stringified<Element2>}]`
57
- : J extends [
58
- infer Element1 extends Json.Serializable,
59
- infer Element2 extends Json.Serializable,
60
- infer Element3 extends Json.Serializable,
61
- ]
62
- ? `[${stringified<Element1>}, ${stringified<Element2>}, ${stringified<Element3>}]`
63
- : J extends any[]
64
- ? `[${string}]` & { __json?: J }
65
- : string & { __json?: J }
66
- )
67
-
68
- /** Type-safe wrapper for {@link JSON.parse} */
69
- export function parseJson<J extends Json.Serializable>(str: stringified<J>): J
70
- /** Type-safe wrapper for {@link JSON.parse} */
71
- export function parseJson(str: string): Json.Serializable
72
- export function parseJson(str: string): Json.Serializable {
73
- return JSON.parse(str)
74
- }
75
-
76
- /** Type-safe wrapper for {@link JSON.stringify} */
77
- export const stringifyJson = <J extends Json.Serializable>(
78
- json: J,
79
- ): stringified<J> => JSON.stringify(json) as stringified<J>
80
-
81
- /** Only Canonical values should be used for keys because they always serialize to the same string */
82
- export type Canonical = primitive | ReadonlyArray<Canonical>
83
-
84
- /** A function whose parameters and return value are {@link Json.Serializable} */
85
- export type JsonIO = (...params: Json.Serializable[]) => Json.Serializable | void
86
-
87
- export type JsonInterface<T, J extends Json.Serializable = Json.Serializable> = {
88
- toJson: (t: ViewOf<T>) => J
89
- fromJson: (json: J) => T
90
- }
91
-
92
- const JSON_PROTOTYPES = [
93
- Array.prototype,
94
- Boolean.prototype,
95
- Number.prototype,
96
- Object.prototype,
97
- String.prototype,
98
- ] as const
99
- export const isJson = (input: unknown): input is Json.Tree.Node => {
100
- if (input === null) return true
101
- if (input === undefined) return false
102
- const prototype = Object.getPrototypeOf(input)
103
- return JSON_PROTOTYPES.includes(prototype)
104
- }
105
-
106
- export const JSON_TYPE_NAMES = [
107
- `array`,
108
- `boolean`,
109
- `null`,
110
- `number`,
111
- `object`,
112
- `string`,
113
- ] as const
114
-
115
- export type JsonTypeName = (typeof JSON_TYPE_NAMES)[number]
116
-
117
- export interface JsonTypes extends Record<JsonTypeName, Json.Serializable> {
118
- array: Json.Array
119
- boolean: boolean
120
- null: null
121
- number: number
122
- object: Json.Object
123
- string: string
124
- }
125
-
126
- export const JSON_DEFAULTS: JsonTypes = {
127
- array: [],
128
- boolean: false,
129
- null: null,
130
- number: 0,
131
- object: {},
132
- string: ``,
133
- }
3
+ export * from "./enumeration"
4
+ export * from "./json"
@@ -0,0 +1,128 @@
1
+ import type { ViewOf } from "atom.io"
2
+
3
+ export type primitive = boolean | number | string | null
4
+
5
+ export namespace Json {
6
+ export namespace Tree {
7
+ // eslint-disable-next-line @typescript-eslint/no-shadow
8
+ export type Array<Element = unknown> = ReadonlyArray<Element>
9
+ // eslint-disable-next-line @typescript-eslint/no-shadow
10
+ export type Object<K extends string = string, V = unknown> = Record<K, V>
11
+ export type Fork = Array | Object
12
+ export type Leaf = primitive
13
+ export type Node = Fork | Leaf
14
+ }
15
+
16
+ /** A value can survive being {@link JSON.stringify}-ed and {@link JSON.parse}-d fully intact */
17
+ export type Serializable =
18
+ | primitive
19
+ | Readonly<{ [key: string]: Serializable }>
20
+ | ReadonlyArray<Serializable>
21
+
22
+ export type Object<
23
+ Key extends string = string,
24
+ Value extends Serializable = Serializable,
25
+ > = Record<Key, Value>
26
+
27
+ export type Array<Element extends Serializable = Serializable> =
28
+ ReadonlyArray<Element>
29
+ }
30
+
31
+ /** A generic that retains the type information of a {@link Json.Serializable} value while in string form */
32
+ // biome-ignore format: long silly ternary
33
+ export type stringified<J extends Json.Serializable> = (
34
+ J extends string
35
+ ? `"${J}"`
36
+ : J extends number
37
+ ? `${J}`
38
+ : J extends true
39
+ ? `true`
40
+ : J extends false
41
+ ? `false`
42
+ : J extends boolean
43
+ ? `false` | `true`
44
+ : J extends null
45
+ ? `null`
46
+ : J extends []
47
+ ? `[]`
48
+ : J extends [infer Element extends Json.Serializable]
49
+ ? `[${stringified<Element>}]`
50
+ : J extends [
51
+ infer Element1 extends Json.Serializable,
52
+ infer Element2 extends Json.Serializable,
53
+ ]
54
+ ? `[${stringified<Element1>}, ${stringified<Element2>}]`
55
+ : J extends [
56
+ infer Element1 extends Json.Serializable,
57
+ infer Element2 extends Json.Serializable,
58
+ infer Element3 extends Json.Serializable,
59
+ ]
60
+ ? `[${stringified<Element1>}, ${stringified<Element2>}, ${stringified<Element3>}]`
61
+ : J extends any[]
62
+ ? `[${string}]` & { __json?: J }
63
+ : string & { __json?: J }
64
+ )
65
+
66
+ /** Type-safe wrapper for {@link JSON.parse} */
67
+ export function parseJson<J extends Json.Serializable>(str: stringified<J>): J
68
+ /** Type-safe wrapper for {@link JSON.parse} */
69
+ export function parseJson(str: string): Json.Serializable
70
+ export function parseJson(str: string): Json.Serializable {
71
+ return JSON.parse(str)
72
+ }
73
+
74
+ /** Type-safe wrapper for {@link JSON.stringify} */
75
+ export const stringifyJson = <J extends Json.Serializable>(
76
+ json: J,
77
+ ): stringified<J> => JSON.stringify(json) as stringified<J>
78
+
79
+ /** A function whose parameters and return value are {@link Json.Serializable} */
80
+ export type JsonIO = (...params: Json.Serializable[]) => Json.Serializable | void
81
+
82
+ export type JsonInterface<T, J extends Json.Serializable = Json.Serializable> = {
83
+ toJson: (t: ViewOf<T>) => J
84
+ fromJson: (json: J) => T
85
+ }
86
+
87
+ const JSON_PROTOTYPES = [
88
+ Array.prototype,
89
+ Boolean.prototype,
90
+ Number.prototype,
91
+ Object.prototype,
92
+ String.prototype,
93
+ ] as const
94
+ export const isJson = (input: unknown): input is Json.Tree.Node => {
95
+ if (input === null) return true
96
+ if (input === undefined) return false
97
+ const prototype = Object.getPrototypeOf(input)
98
+ return JSON_PROTOTYPES.includes(prototype)
99
+ }
100
+
101
+ export const JSON_TYPE_NAMES = [
102
+ `array`,
103
+ `boolean`,
104
+ `null`,
105
+ `number`,
106
+ `object`,
107
+ `string`,
108
+ ] as const
109
+
110
+ export type JsonTypeName = (typeof JSON_TYPE_NAMES)[number]
111
+
112
+ export interface JsonTypes extends Record<JsonTypeName, Json.Serializable> {
113
+ array: Json.Array
114
+ boolean: boolean
115
+ null: null
116
+ number: number
117
+ object: Json.Object
118
+ string: string
119
+ }
120
+
121
+ export const JSON_DEFAULTS: JsonTypes = {
122
+ array: [],
123
+ boolean: false,
124
+ null: null,
125
+ number: 0,
126
+ object: {},
127
+ string: ``,
128
+ }
package/src/main/index.ts CHANGED
@@ -15,7 +15,6 @@ export * from "./timeline"
15
15
  export type * from "./tokens"
16
16
  export * from "./transaction"
17
17
  export * from "./validators"
18
-
19
18
  /**
20
19
  * Loadable is used to type atoms or selectors that may at some point be initialized to or set to a {@link Promise}.
21
20
  *
@@ -25,4 +24,12 @@ export * from "./validators"
25
24
  */
26
25
  export type Loadable<T> = Promise<T> | T
27
26
 
28
- export type ViewOf<T> = T extends { READONLY_VIEW: infer View } ? View : T
27
+ export type ViewOf<T> = T extends { READONLY_VIEW: infer View }
28
+ ? View
29
+ : T extends Array<any>
30
+ ? readonly [...T]
31
+ : T extends Set<infer U>
32
+ ? ReadonlySet<ViewOf<U>>
33
+ : T extends Map<infer K, infer V>
34
+ ? ReadonlyMap<ViewOf<K>, ViewOf<V>>
35
+ : T
@@ -1,5 +1,10 @@
1
1
  /** biome-ignore-all lint/correctness/useHookAtTopLevel: params are used in an invariant way */
2
- import type { Loadable, ReadableFamilyToken, ReadableToken } from "atom.io"
2
+ import type {
3
+ Loadable,
4
+ ReadableFamilyToken,
5
+ ReadableToken,
6
+ ViewOf,
7
+ } from "atom.io"
3
8
  import { findInStore, type ReadableState, withdraw } from "atom.io/internal"
4
9
  import type { Canonical } from "atom.io/json"
5
10
  import { StoreContext, useO } from "atom.io/react"
@@ -7,23 +12,23 @@ import { useContext, useRef } from "react"
7
12
 
8
13
  export function useLoadable<T, E>(
9
14
  token: ReadableToken<Loadable<T>, any, E>,
10
- ): `LOADING` | { loading: boolean; value: E | T }
15
+ ): `LOADING` | { loading: boolean; value: ViewOf<E | T> }
11
16
 
12
17
  export function useLoadable<T, K extends Canonical, E>(
13
18
  token: ReadableFamilyToken<Loadable<T>, K, E>,
14
19
  key: NoInfer<K>,
15
- ): `LOADING` | { loading: boolean; value: E | T }
20
+ ): `LOADING` | { loading: boolean; value: ViewOf<E | T> }
16
21
 
17
22
  export function useLoadable<T, F extends T, E>(
18
23
  token: ReadableToken<Loadable<T>, any, E>,
19
24
  fallback: F,
20
- ): { loading: boolean; value: T; error?: E }
25
+ ): { loading: boolean; value: ViewOf<T>; error?: E }
21
26
 
22
27
  export function useLoadable<T, K extends Canonical, F extends T, E>(
23
28
  token: ReadableFamilyToken<Loadable<T>, K, E>,
24
29
  key: NoInfer<K>,
25
30
  fallback: F,
26
- ): { loading: boolean; value: T; error?: E }
31
+ ): { loading: boolean; value: ViewOf<T>; error?: E }
27
32
 
28
33
  export function useLoadable(
29
34
  ...params:
@@ -1,7 +1,16 @@
1
+ /** biome-ignore-all lint/correctness/useHookAtTopLevel: depends on the type of atom, which shouldn't change */
1
2
  import type { ReadableFamilyToken, ReadableToken, ViewOf } from "atom.io"
2
3
  import { getFromStore, subscribeToState } from "atom.io/internal"
3
4
  import type { Canonical } from "atom.io/json"
4
- import { useCallback, useContext, useId, useSyncExternalStore } from "react"
5
+ import { useSingleEffect } from "atom.io/realtime-react"
6
+ import {
7
+ useCallback,
8
+ useContext,
9
+ useId,
10
+ useRef,
11
+ useState,
12
+ useSyncExternalStore,
13
+ } from "react"
5
14
 
6
15
  import { parseStateOverloads } from "./parse-state-overloads"
7
16
  import { StoreContext } from "./store-context"
@@ -23,6 +32,29 @@ export function useO<T, K extends Canonical, E = never>(
23
32
  const store = useContext(StoreContext)
24
33
  const token = parseStateOverloads(store, ...params)
25
34
  const id = useId()
35
+
36
+ if (
37
+ token.type === `mutable_atom` ||
38
+ token.type === `readonly_held_selector` ||
39
+ token.type === `writable_held_selector`
40
+ ) {
41
+ const [, dispatch] = useState<number>(0)
42
+ const valueRef = useRef<ViewOf<E | T>>(getFromStore(store, token))
43
+ useSingleEffect(() => {
44
+ const unsub = subscribeToState<T, E>(
45
+ store,
46
+ token,
47
+ `use-o:${id}`,
48
+ ({ newValue }) => {
49
+ valueRef.current = newValue
50
+ dispatch((c) => c + 1)
51
+ },
52
+ )
53
+ return unsub
54
+ }, [token.key])
55
+ return valueRef.current
56
+ }
57
+
26
58
  const sub = useCallback(
27
59
  (dispatch: () => void) =>
28
60
  subscribeToState<T, E>(store, token, `use-o:${id}`, dispatch),
@@ -16,7 +16,7 @@ export const TransactionLog: FC<{
16
16
  token: TransactionToken<Fn>
17
17
  isOpenState: RegularAtomToken<boolean>
18
18
  logState: ReadonlyPureSelectorToken<
19
- TransactionOutcomeEvent<TransactionToken<Fn>>[]
19
+ readonly TransactionOutcomeEvent<TransactionToken<Fn>>[]
20
20
  >
21
21
  }> = ({ token, isOpenState, logState }) => {
22
22
  const log = useO(logState)
@@ -13,7 +13,7 @@ import {
13
13
  } from "atom.io/internal"
14
14
  import type {
15
15
  IntrospectionStates,
16
- WritableTokenIndex,
16
+ ReadonlyTokenIndex,
17
17
  } from "atom.io/introspection"
18
18
  import { attachIntrospectionStates, isPlainObject } from "atom.io/introspection"
19
19
  import { storageSync } from "atom.io/web"
@@ -131,8 +131,8 @@ export function attachDevtoolsStates(
131
131
  do: ({ get, set }, path, current) => {
132
132
  const currentView = get(devtoolsViewSelectionAtom)
133
133
  let states:
134
- | WritableTokenIndex<AtomToken<unknown, any, any>>
135
- | WritableTokenIndex<SelectorToken<unknown, any, any>>
134
+ | ReadonlyTokenIndex<AtomToken<unknown, any, any>>
135
+ | ReadonlyTokenIndex<SelectorToken<unknown, any, any>>
136
136
  switch (currentView) {
137
137
  case `atoms`:
138
138
  states = get(introspectionStates.atomIndex)
@@ -18,10 +18,10 @@ export const useRegisterAndAttemptConfirmedUpdate =
18
18
  store: RootStore,
19
19
  continuityKey: string,
20
20
  socket: Socket,
21
- optimisticUpdates: AtomIO.TransactionOutcomeEvent<
21
+ optimisticUpdates: readonly AtomIO.TransactionOutcomeEvent<
22
22
  AtomIO.TransactionToken<Fn>
23
23
  >[],
24
- confirmedUpdates: AtomIO.TransactionOutcomeEvent<
24
+ confirmedUpdates: readonly AtomIO.TransactionOutcomeEvent<
25
25
  AtomIO.TransactionToken<Fn>
26
26
  >[],
27
27
  ) =>
@@ -16,6 +16,5 @@ export function usePullSelectorFamilyMember<T, K extends Canonical>(
16
16
  useRealtimeService(`pull:${token.key}`, (socket) =>
17
17
  RTC.pullSelectorFamilyMember(store, socket, familyToken, key),
18
18
  )
19
-
20
19
  return useO(token)
21
20
  }