atom.io 0.27.4 → 0.28.0

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 (134) hide show
  1. package/data/dist/index.d.ts +31 -29
  2. package/data/dist/index.js +65 -81
  3. package/data/src/dict.ts +9 -12
  4. package/data/src/join.ts +30 -33
  5. package/data/src/struct-family.ts +17 -23
  6. package/data/src/struct.ts +9 -12
  7. package/dist/{chunk-JRENM6KL.js → chunk-BX3MTH2Z.js} +482 -385
  8. package/dist/chunk-D52JNVER.js +721 -0
  9. package/dist/chunk-EUVKUTW3.js +89 -0
  10. package/dist/index.d.ts +4 -3
  11. package/dist/index.js +35 -53
  12. package/ephemeral/dist/index.js +1 -1
  13. package/ephemeral/src/find-state.ts +1 -1
  14. package/immortal/dist/index.js +2 -2
  15. package/immortal/src/seek-state.ts +2 -2
  16. package/internal/dist/index.d.ts +141 -87
  17. package/internal/dist/index.js +1 -1
  18. package/internal/src/atom/create-regular-atom.ts +3 -3
  19. package/internal/src/atom/create-standalone-atom.ts +7 -5
  20. package/internal/src/atom/dispose-atom.ts +2 -9
  21. package/internal/src/families/create-atom-family.ts +5 -5
  22. package/internal/src/families/create-readonly-selector-family.ts +20 -9
  23. package/internal/src/families/create-regular-atom-family.ts +15 -6
  24. package/internal/src/families/create-selector-family.ts +5 -5
  25. package/internal/src/families/create-writable-selector-family.ts +20 -10
  26. package/internal/src/families/dispose-from-store.ts +43 -29
  27. package/internal/src/families/find-in-store.ts +28 -18
  28. package/internal/src/families/init-family-member.ts +9 -9
  29. package/internal/src/families/seek-in-store.ts +10 -10
  30. package/internal/src/get-state/get-from-store.ts +70 -47
  31. package/internal/src/ingest-updates/ingest-atom-update.ts +1 -1
  32. package/internal/src/ingest-updates/ingest-creation-disposal.ts +15 -6
  33. package/internal/src/molecule/create-molecule-family.ts +1 -1
  34. package/internal/src/molecule/dispose-molecule.ts +7 -18
  35. package/internal/src/molecule/grow-molecule-in-store.ts +1 -1
  36. package/internal/src/molecule/make-molecule-in-store.ts +5 -5
  37. package/internal/src/mutable/create-mutable-atom-family.ts +15 -6
  38. package/internal/src/mutable/create-mutable-atom.ts +3 -3
  39. package/internal/src/mutable/get-json-token.ts +2 -2
  40. package/internal/src/mutable/tracker-family.ts +3 -3
  41. package/internal/src/mutable/tracker.ts +14 -18
  42. package/internal/src/pretty-print.ts +1 -16
  43. package/internal/src/selector/create-readonly-selector.ts +2 -2
  44. package/internal/src/selector/create-standalone-selector.ts +5 -5
  45. package/internal/src/selector/create-writable-selector.ts +2 -2
  46. package/internal/src/selector/dispose-selector.ts +2 -9
  47. package/internal/src/selector/register-selector.ts +9 -9
  48. package/internal/src/set-state/set-into-store.ts +23 -33
  49. package/internal/src/store/circular-buffer.ts +34 -0
  50. package/internal/src/store/counterfeit.ts +109 -0
  51. package/internal/src/store/deposit.ts +67 -13
  52. package/internal/src/store/index.ts +1 -0
  53. package/internal/src/store/store.ts +4 -1
  54. package/internal/src/store/withdraw.ts +15 -10
  55. package/internal/src/subscribe/index.ts +2 -0
  56. package/internal/src/subscribe/subscribe-in-store.ts +62 -0
  57. package/internal/src/timeline/time-travel.ts +1 -1
  58. package/internal/src/transaction/build-transaction.ts +7 -6
  59. package/introspection/dist/index.d.ts +84 -4
  60. package/introspection/dist/index.js +1 -413
  61. package/introspection/src/attach-atom-index.ts +5 -8
  62. package/introspection/src/attach-introspection-states.ts +7 -4
  63. package/introspection/src/attach-selector-index.ts +6 -8
  64. package/introspection/src/attach-timeline-family.ts +25 -28
  65. package/introspection/src/attach-timeline-index.ts +5 -8
  66. package/introspection/src/attach-transaction-index.ts +5 -8
  67. package/introspection/src/attach-transaction-logs.ts +21 -27
  68. package/introspection/src/attach-type-selectors.ts +26 -0
  69. package/introspection/src/differ.ts +167 -0
  70. package/introspection/src/index.ts +2 -0
  71. package/introspection/src/refinery.ts +100 -0
  72. package/json/dist/index.d.ts +31 -30
  73. package/json/dist/index.js +2 -80
  74. package/json/src/entries.ts +6 -0
  75. package/json/src/index.ts +47 -6
  76. package/json/src/select-json-family.ts +4 -4
  77. package/json/src/select-json.ts +6 -9
  78. package/package.json +17 -8
  79. package/react/dist/index.js +7 -7
  80. package/react/src/parse-state-overloads.ts +2 -2
  81. package/react/src/use-i.ts +1 -1
  82. package/react/src/use-json.ts +2 -2
  83. package/react/src/use-o.ts +2 -2
  84. package/react-devtools/dist/index.d.ts +1 -91
  85. package/react-devtools/dist/index.js +285 -414
  86. package/react-devtools/src/AtomIODevtools.tsx +2 -2
  87. package/react-devtools/src/StateEditor.tsx +20 -12
  88. package/react-devtools/src/StateIndex.tsx +8 -26
  89. package/react-devtools/src/TimelineIndex.tsx +3 -3
  90. package/react-devtools/src/TransactionIndex.tsx +6 -6
  91. package/react-devtools/src/Updates.tsx +1 -4
  92. package/react-devtools/src/index.ts +0 -71
  93. package/react-devtools/src/store.ts +51 -0
  94. package/realtime/dist/index.d.ts +7 -7
  95. package/realtime/dist/index.js +18 -22
  96. package/realtime/src/realtime-continuity.ts +27 -35
  97. package/realtime-client/dist/index.js +59 -65
  98. package/realtime-client/src/pull-atom-family-member.ts +1 -1
  99. package/realtime-client/src/pull-atom.ts +1 -1
  100. package/realtime-client/src/pull-mutable-atom-family-member.ts +3 -3
  101. package/realtime-client/src/pull-mutable-atom.ts +3 -3
  102. package/realtime-client/src/realtime-client-stores/client-main-store.ts +6 -6
  103. package/realtime-client/src/sync-continuity.ts +55 -53
  104. package/realtime-react/dist/index.js +3 -3
  105. package/realtime-react/src/use-pull-atom-family-member.ts +1 -1
  106. package/realtime-react/src/use-pull-mutable-family-member.ts +1 -1
  107. package/realtime-react/src/use-pull-selector-family-member.ts +1 -1
  108. package/realtime-server/dist/index.js +72 -36
  109. package/realtime-server/src/realtime-continuity-synchronizer.ts +57 -93
  110. package/realtime-server/src/realtime-family-provider.ts +3 -3
  111. package/realtime-server/src/realtime-mutable-family-provider.ts +5 -5
  112. package/realtime-server/src/realtime-mutable-provider.ts +2 -2
  113. package/realtime-server/src/realtime-state-provider.ts +1 -1
  114. package/realtime-server/src/realtime-state-receiver.ts +1 -1
  115. package/realtime-testing/dist/index.d.ts +2 -0
  116. package/realtime-testing/dist/index.js +57 -15
  117. package/realtime-testing/src/setup-realtime-test.tsx +66 -16
  118. package/src/atom.ts +2 -2
  119. package/src/dispose-state.ts +2 -2
  120. package/src/get-state.ts +9 -13
  121. package/src/molecule.ts +1 -1
  122. package/src/selector.ts +2 -2
  123. package/src/set-state.ts +10 -7
  124. package/src/silo.ts +29 -55
  125. package/src/subscribe.ts +3 -23
  126. package/src/timeline.ts +2 -2
  127. package/web/dist/index.d.ts +9 -0
  128. package/{dist/chunk-H6EDLPKH.js → web/dist/index.js} +5 -4
  129. package/web/package.json +13 -0
  130. package/web/src/index.ts +1 -0
  131. package/web/src/persist-sync.ts +25 -0
  132. package/dist/chunk-AK23DRMD.js +0 -21
  133. package/dist/chunk-IW6WYRS7.js +0 -140
  134. package/internal/src/families/throw-in-case-of-conflicting-family.ts +0 -18
@@ -0,0 +1,26 @@
1
+ import type { ReadonlySelectorFamilyToken } from "atom.io"
2
+ import type { Store } from "atom.io/internal"
3
+ import { createReadonlySelectorFamily, IMPLICIT } from "atom.io/internal"
4
+
5
+ import { discoverType } from "./refinery"
6
+
7
+ export const attachTypeSelectors = (
8
+ store: Store = IMPLICIT.STORE,
9
+ ): ReadonlySelectorFamilyToken<string, string> => {
10
+ const typeSelectors = createReadonlySelectorFamily<string, string>(store, {
11
+ key: `👁‍🗨 State Type`,
12
+ get:
13
+ (token) =>
14
+ ({ get }) => {
15
+ let state: unknown
16
+ try {
17
+ state = get(token as any)
18
+ } catch (error) {
19
+ return `error`
20
+ }
21
+ const typeOfState = discoverType(state)
22
+ return typeOfState
23
+ },
24
+ })
25
+ return typeSelectors
26
+ }
@@ -0,0 +1,167 @@
1
+ import { sprawl } from "anvl/object"
2
+ import type { Json } from "atom.io/json"
3
+
4
+ import type { Refinery, Supported } from "./refinery"
5
+ import { discoverType, jsonTreeRefinery, primitiveRefinery } from "./refinery"
6
+
7
+ export function diffNumber(a: number, b: number): Delta {
8
+ const sign = a < b ? `+` : `-`
9
+ return {
10
+ summary: `${sign}${Math.abs(a - b)} (${a} → ${b})`,
11
+ }
12
+ }
13
+
14
+ export function diffString(a: string, b: string): Delta {
15
+ const sign = a.length < b.length ? `+` : `-`
16
+ return {
17
+ summary: `${sign}${Math.abs(a.length - b.length)} ("${a}" → "${b}")`,
18
+ }
19
+ }
20
+
21
+ export function diffBoolean(a: boolean, b: boolean): Delta {
22
+ return {
23
+ summary: `${a} → ${b}`,
24
+ }
25
+ }
26
+
27
+ export function diffObject(
28
+ a: Json.Tree.Object,
29
+ b: Json.Tree.Object,
30
+ recurse: Diff<unknown>,
31
+ ): Delta {
32
+ let summary = ``
33
+ const added: Delta[`added`] = []
34
+ const removed: Delta[`removed`] = []
35
+ const changed: Delta[`changed`] = []
36
+
37
+ sprawl(a, (path, nodeA) => {
38
+ let key: string
39
+ for (key of path) {
40
+ const nodeB = b[key]
41
+ if (nodeB === undefined) {
42
+ removed.push([key, JSON.stringify(nodeA)])
43
+ } else {
44
+ const delta = recurse(nodeA, nodeB)
45
+ if (delta.summary !== `No Change`) {
46
+ changed.push([key, delta])
47
+ }
48
+ }
49
+ }
50
+ })
51
+
52
+ sprawl(b, (path, nodeB) => {
53
+ let key: string
54
+ for (key of path) {
55
+ const nodeA = a[key]
56
+ if (nodeA === undefined) {
57
+ added.push([key, JSON.stringify(nodeB)])
58
+ }
59
+ }
60
+ })
61
+
62
+ summary = `~${changed.length} +${added.length} -${removed.length}`
63
+
64
+ return {
65
+ summary,
66
+ added,
67
+ removed,
68
+ changed,
69
+ }
70
+ }
71
+
72
+ export function diffArray(
73
+ a: Json.Tree.Array,
74
+ b: Json.Tree.Array,
75
+ recurse: Diff<unknown>,
76
+ ): Delta {
77
+ return diffObject(a as any, b as any, recurse)
78
+ }
79
+
80
+ type Delta = {
81
+ summary: string
82
+ added?: [path: string, addedStringifiedValue: string][]
83
+ removed?: [path: string, removedStringifiedValue: string][]
84
+ changed?: [path: string, delta: Delta][]
85
+ }
86
+
87
+ type Diff<T> = (a: T, b: T) => Delta
88
+ type DiffTree<T> = (a: T, b: T, recurse: Differ<any, any>[`diff`]) => Delta
89
+
90
+ export class Differ<
91
+ Leaf extends Record<string, any>,
92
+ Tree extends Record<string, any>,
93
+ > {
94
+ public leafRefinery: Refinery<Leaf>
95
+ public treeRefinery: Refinery<Tree>
96
+ public leafDiffers: { [KL in keyof Leaf]: Diff<Supported<Leaf[KL]>> }
97
+ public treeDiffers: { [KT in keyof Tree]: DiffTree<Supported<Tree[KT]>> }
98
+
99
+ public constructor(
100
+ leafRefinery: Refinery<Leaf>,
101
+ treeRefinery: Refinery<Tree>,
102
+ diffFunctions: {
103
+ [KT in keyof Tree]: DiffTree<Supported<Tree[KT]>>
104
+ } & { [KL in keyof Leaf]: Diff<Supported<Leaf[KL]>> },
105
+ ) {
106
+ this.leafRefinery = leafRefinery
107
+ this.treeRefinery = treeRefinery
108
+ this.leafDiffers = {} as any
109
+ this.treeDiffers = {} as any
110
+ for (const key of Object.keys(leafRefinery.supported)) {
111
+ const diffFunction = diffFunctions[key]
112
+ this.leafDiffers[key as keyof Leaf] = diffFunction
113
+ }
114
+ for (const key of Object.keys(treeRefinery.supported)) {
115
+ const diffFunction = diffFunctions[key]
116
+ this.treeDiffers[key as keyof Tree] = diffFunction
117
+ }
118
+ }
119
+
120
+ public diff(a: unknown, b: unknown): Delta {
121
+ if (a === b) {
122
+ return { summary: `No Change` }
123
+ }
124
+
125
+ const aRefined = this.leafRefinery.refine(a) ?? this.treeRefinery.refine(a)
126
+ const bRefined = this.leafRefinery.refine(b) ?? this.treeRefinery.refine(b)
127
+
128
+ if (aRefined !== null && bRefined !== null) {
129
+ if (aRefined.type === bRefined.type) {
130
+ if (aRefined.type in this.leafDiffers) {
131
+ const delta = this.leafDiffers[aRefined.type](
132
+ aRefined.data,
133
+ bRefined.data,
134
+ )
135
+ return delta
136
+ }
137
+ if (aRefined.type in this.treeDiffers) {
138
+ const delta = this.treeDiffers[aRefined.type](
139
+ aRefined.data,
140
+ bRefined.data,
141
+ (x, y) => this.diff(x, y),
142
+ )
143
+ return delta
144
+ }
145
+ }
146
+ }
147
+ const typeA = discoverType(a)
148
+ const typeB = discoverType(b)
149
+ if (typeA === typeB) {
150
+ return {
151
+ summary: `${typeA} → ${typeB}`,
152
+ }
153
+ }
154
+ return {
155
+ summary: `Type change: ${typeA} → ${typeB}`,
156
+ }
157
+ }
158
+ }
159
+
160
+ export const prettyJson = new Differ(primitiveRefinery, jsonTreeRefinery, {
161
+ number: diffNumber,
162
+ string: diffString,
163
+ boolean: diffBoolean,
164
+ null: () => ({ summary: `No Change` }),
165
+ object: diffObject,
166
+ array: diffArray,
167
+ })
@@ -2,6 +2,8 @@ import type { ReadableToken } from "atom.io"
2
2
 
3
3
  export * from "./attach-introspection-states"
4
4
  export * from "./auditor"
5
+ export * from "./differ"
6
+ export * from "./refinery"
5
7
 
6
8
  export type FamilyNode<Token extends ReadableToken<unknown>> = {
7
9
  key: string
@@ -0,0 +1,100 @@
1
+ import type { Flat } from "atom.io/internal"
2
+ import type { Json } from "atom.io/json"
3
+
4
+ export type Refinement<A, B extends A> = (a: A) => a is B
5
+
6
+ export type ClassSignature = abstract new (...args: any) => any
7
+
8
+ export type RefinementStrategy = ClassSignature | Refinement<unknown, any>
9
+
10
+ export type Supported<Refine extends RefinementStrategy> =
11
+ Refine extends Refinement<unknown, infer T>
12
+ ? T
13
+ : Refine extends ClassSignature
14
+ ? InstanceType<Refine>
15
+ : never
16
+
17
+ export type RefinementSupport = Record<string, RefinementStrategy>
18
+
19
+ export class Refinery<SupportedTypes extends RefinementSupport> {
20
+ public supported: SupportedTypes
21
+
22
+ public constructor(supported: SupportedTypes) {
23
+ this.supported = supported
24
+ }
25
+
26
+ public refine<T>(input: T):
27
+ | Flat<{
28
+ [K in keyof SupportedTypes]: T extends Supported<SupportedTypes[K]>
29
+ ? {
30
+ type: K
31
+ data: Supported<SupportedTypes[K]>
32
+ }
33
+ : Supported<SupportedTypes[K]> extends T
34
+ ? {
35
+ type: K
36
+ data: Supported<SupportedTypes[K]>
37
+ }
38
+ : never
39
+ }>[keyof SupportedTypes]
40
+ | (T extends Supported<SupportedTypes[keyof SupportedTypes]>
41
+ ? never
42
+ : null) {
43
+ for (const [key, refiner] of Object.entries(this.supported)) {
44
+ try {
45
+ if (
46
+ // @ts-expect-error that's the point
47
+ refiner(input) === true &&
48
+ refiner !== Boolean
49
+ ) {
50
+ return { type: key, data: input } as any
51
+ }
52
+ } catch (_) {
53
+ try {
54
+ if (input instanceof refiner) {
55
+ return { type: key, data: input } as any
56
+ }
57
+ } catch (__) {}
58
+ }
59
+ }
60
+ return null as any
61
+ }
62
+ }
63
+
64
+ export const primitiveRefinery = new Refinery({
65
+ number: (input: unknown): input is number => typeof input === `number`,
66
+ string: (input: unknown): input is string => typeof input === `string`,
67
+ boolean: (input: unknown): input is boolean => typeof input === `boolean`,
68
+ null: (input: unknown): input is null => input === null,
69
+ })
70
+
71
+ export const jsonTreeRefinery = new Refinery({
72
+ object: (input: unknown): input is Json.Tree.Object => {
73
+ if (!input) {
74
+ return false
75
+ }
76
+ const prototype = Object.getPrototypeOf(input)
77
+ return prototype === Object.prototype
78
+ },
79
+ array: (input: unknown): input is Json.Tree.Array => Array.isArray(input),
80
+ })
81
+
82
+ export const jsonRefinery = new Refinery({
83
+ ...primitiveRefinery.supported,
84
+ ...jsonTreeRefinery.supported,
85
+ })
86
+
87
+ export type JsonType = keyof typeof jsonRefinery.supported
88
+
89
+ export const discoverType = (
90
+ input: unknown,
91
+ ): JsonType | `Map` | `Set` | `undefined` | (string & {}) => {
92
+ if (input === undefined) {
93
+ return `undefined`
94
+ }
95
+ const refined = jsonRefinery.refine(input)
96
+ if (refined) {
97
+ return refined.type
98
+ }
99
+ return Object.getPrototypeOf(input).constructor.name
100
+ }
@@ -1,31 +1,6 @@
1
1
  import { Range, Flat, Store, Transceiver } from 'atom.io/internal';
2
2
  import * as AtomIO from 'atom.io';
3
3
 
4
- type JsonInterface<T, J extends Serializable = Serializable> = {
5
- toJson: (t: T) => J;
6
- fromJson: (json: J) => T;
7
- };
8
-
9
- type primitive = boolean | number | string | null;
10
-
11
- type Serializable = primitive | Readonly<{
12
- [key: string]: Serializable;
13
- }> | ReadonlyArray<Serializable>;
14
- type Object$1<Key extends string = string, Value extends Serializable = Serializable> = Record<Key, Value>;
15
- type Array<Element extends Serializable = Serializable> = ReadonlyArray<Element>;
16
-
17
- type json_Array<Element extends Serializable = Serializable> = Array<Element>;
18
- type json_Serializable = Serializable;
19
- declare namespace json {
20
- export type { json_Array as Array, Object$1 as Object, json_Serializable as Serializable };
21
- }
22
-
23
- declare const parseJson: <S extends stringified<Serializable>>(str: S | string) => S extends stringified<infer J> ? J : Serializable;
24
- type stringified<J extends Serializable> = string & {
25
- __json: J;
26
- };
27
- declare const stringifyJson: <J extends Serializable>(json: J) => stringified<J>;
28
-
29
4
  type Entries<K extends keyof any = keyof any, V = any> = [K, V][];
30
5
  type KeyOfEntries<E extends Entries> = E extends [infer K, any][] ? K : never;
31
6
  type ValueOfEntry<E extends Entries, K extends KeyOfEntries<E>> = {
@@ -35,13 +10,39 @@ type FromEntries<E extends Entries> = Flat<{
35
10
  [K in KeyOfEntries<E>]: ValueOfEntry<E, K>;
36
11
  }>;
37
12
  declare function fromEntries<E extends Entries>(entries: E): FromEntries<E>;
13
+ declare function toEntries<T extends object>(obj: T): Entries<keyof T, T[keyof T]>;
38
14
 
39
- declare const selectJson: <T, J extends Serializable>(atom: AtomIO.AtomToken<T>, transform: JsonInterface<T, J>, store?: Store) => AtomIO.WritableSelectorToken<J>;
15
+ declare const selectJson: <T, J extends Json.Serializable>(atom: AtomIO.AtomToken<T>, transform: JsonInterface<T, J>, store?: Store) => AtomIO.WritableSelectorToken<J>;
40
16
 
41
- declare function selectJsonFamily<T extends Transceiver<any>, J extends Serializable, K extends Canonical>(atomFamilyToken: AtomIO.MutableAtomFamilyToken<T, J, K>, transform: JsonInterface<T, J>, store: Store): AtomIO.WritableSelectorFamilyToken<J, K>;
42
- declare function selectJsonFamily<T, J extends Serializable, K extends Canonical>(atomFamilyToken: AtomIO.RegularAtomFamilyToken<T, K>, transform: JsonInterface<T, J>, store: Store): AtomIO.WritableSelectorFamilyToken<J, K>;
17
+ declare function selectJsonFamily<T extends Transceiver<any>, J extends Json.Serializable, K extends Canonical>(atomFamilyToken: AtomIO.MutableAtomFamilyToken<T, J, K>, transform: JsonInterface<T, J>, store: Store): AtomIO.WritableSelectorFamilyToken<J, K>;
18
+ declare function selectJsonFamily<T, J extends Json.Serializable, K extends Canonical>(atomFamilyToken: AtomIO.RegularAtomFamilyToken<T, K>, transform: JsonInterface<T, J>, store: Store): AtomIO.WritableSelectorFamilyToken<J, K>;
43
19
 
20
+ type primitive = boolean | number | string | null;
21
+ declare namespace Json {
22
+ namespace Tree {
23
+ type Array<Element = unknown> = ReadonlyArray<Element>;
24
+ type Object<K extends string = string, V = unknown> = Record<K, V>;
25
+ type Fork = Array | Object;
26
+ type Leaf = primitive;
27
+ type Node = Fork | Leaf;
28
+ }
29
+ type Serializable = primitive | Readonly<{
30
+ [key: string]: Serializable;
31
+ }> | ReadonlyArray<Serializable>;
32
+ type Object<Key extends string = string, Value extends Serializable = Serializable> = Record<Key, Value>;
33
+ type Array<Element extends Serializable = Serializable> = ReadonlyArray<Element>;
34
+ }
35
+ type stringified<J extends Json.Serializable> = string & {
36
+ __json: J;
37
+ };
38
+ declare const parseJson: <S extends stringified<Json.Serializable>>(str: S | string) => S extends stringified<infer J> ? J : Json.Serializable;
39
+ declare const stringifyJson: <J extends Json.Serializable>(json: J) => stringified<J>;
44
40
  type Canonical = primitive | ReadonlyArray<Canonical>;
45
- type JsonIO = (...params: Serializable[]) => Serializable | void;
41
+ type JsonIO = (...params: Json.Serializable[]) => Json.Serializable | void;
42
+ type JsonInterface<T, J extends Json.Serializable = Json.Serializable> = {
43
+ toJson: (t: T) => J;
44
+ fromJson: (json: J) => T;
45
+ };
46
+ declare const isJson: (input: unknown) => input is Json.Tree.Node;
46
47
 
47
- export { type Canonical, type Entries, type FromEntries, json as Json, type JsonIO, type JsonInterface, type KeyOfEntries, type ValueOfEntry, fromEntries, parseJson, type primitive, selectJson, selectJsonFamily, type stringified, stringifyJson };
48
+ export { type Canonical, type Entries, type FromEntries, Json, type JsonIO, type JsonInterface, type KeyOfEntries, type ValueOfEntry, fromEntries, isJson, parseJson, type primitive, selectJson, selectJsonFamily, type stringified, stringifyJson, toEntries };
@@ -1,82 +1,4 @@
1
- import { stringifyJson, parseJson } from '../../dist/chunk-AK23DRMD.js';
2
- export { parseJson, stringifyJson } from '../../dist/chunk-AK23DRMD.js';
3
- import { createWritableSelectorFamily } from '../../dist/chunk-JRENM6KL.js';
1
+ export { fromEntries, isJson, parseJson, selectJson, selectJsonFamily, stringifyJson, toEntries } from '../../dist/chunk-EUVKUTW3.js';
2
+ import '../../dist/chunk-BX3MTH2Z.js';
4
3
  import '../../dist/chunk-IBTHB2PI.js';
5
4
  import '../../dist/chunk-XWL6SNVU.js';
6
- import { createStandaloneSelector, IMPLICIT, growMoleculeInStore, initFamilyMemberInStore, withdraw, seekInStore } from 'atom.io/internal';
7
-
8
- // json/src/entries.ts
9
- function fromEntries(entries) {
10
- return Object.fromEntries(entries);
11
- }
12
- var selectJson = (atom, transform, store = IMPLICIT.STORE) => {
13
- return createStandaloneSelector(
14
- {
15
- key: `${atom.key}:JSON`,
16
- get: ({ get }) => transform.toJson(get(atom)),
17
- set: ({ set }, newValue) => {
18
- set(atom, transform.fromJson(newValue));
19
- }
20
- },
21
- store
22
- );
23
- };
24
- function selectJsonFamily(atomFamilyToken, transform, store = IMPLICIT.STORE) {
25
- const jsonFamily = createWritableSelectorFamily(
26
- {
27
- key: `${atomFamilyToken.key}:JSON`,
28
- get: (key) => ({ seek, get }) => {
29
- const existingState = seek(atomFamilyToken, key);
30
- if (existingState) {
31
- return transform.toJson(get(existingState));
32
- }
33
- const stringKey = stringifyJson(key);
34
- const molecule = store.molecules.get(stringKey);
35
- if (molecule) {
36
- const atom = growMoleculeInStore(molecule, atomFamilyToken, store);
37
- return transform.toJson(get(atom));
38
- }
39
- if (store.config.lifespan === `immortal`) {
40
- throw new Error(`No molecule found for key "${stringKey}"`);
41
- }
42
- const newToken = initFamilyMemberInStore(atomFamilyToken, key, store);
43
- return transform.toJson(get(newToken));
44
- },
45
- set: (key) => ({ seek, set }, newValue) => {
46
- const existingState = seek(atomFamilyToken, key);
47
- if (existingState) {
48
- set(existingState, transform.fromJson(newValue));
49
- } else {
50
- const stringKey = stringifyJson(key);
51
- const molecule = store.molecules.get(stringKey);
52
- if (molecule) {
53
- const atom = growMoleculeInStore(molecule, atomFamilyToken, store);
54
- set(atom, transform.fromJson(newValue));
55
- } else {
56
- if (store.config.lifespan === `immortal`) {
57
- throw new Error(`No molecule found for key "${stringKey}"`);
58
- }
59
- set(
60
- initFamilyMemberInStore(atomFamilyToken, key, store),
61
- transform.fromJson(newValue)
62
- );
63
- }
64
- }
65
- }
66
- },
67
- store,
68
- [`mutable`, `json`]
69
- );
70
- const atomFamily = withdraw(atomFamilyToken, store);
71
- atomFamily.subject.subscribe(
72
- `store=${store.config.name}::json-selector-family`,
73
- (event) => {
74
- if (event.token.family) {
75
- seekInStore(jsonFamily, parseJson(event.token.family.subKey), store);
76
- }
77
- }
78
- );
79
- return jsonFamily;
80
- }
81
-
82
- export { fromEntries, selectJson, selectJsonFamily };
@@ -17,3 +17,9 @@ export type FromEntries<E extends Entries> = Flat<{
17
17
  export function fromEntries<E extends Entries>(entries: E): FromEntries<E> {
18
18
  return Object.fromEntries(entries) as FromEntries<E>
19
19
  }
20
+
21
+ export function toEntries<T extends object>(
22
+ obj: T,
23
+ ): Entries<keyof T, T[keyof T]> {
24
+ return Object.entries(obj) as Entries<keyof T, T[keyof T]>
25
+ }
package/json/src/index.ts CHANGED
@@ -1,14 +1,55 @@
1
- import type { Json, JsonInterface, stringified } from "~/packages/anvl/src/json"
2
- import { parseJson, stringifyJson } from "~/packages/anvl/src/json"
3
- import type { primitive } from "~/packages/anvl/src/primitive"
4
-
5
1
  export * from "./entries"
6
2
  export * from "./select-json"
7
3
  export * from "./select-json-family"
8
4
 
9
- export type { Json, JsonInterface, primitive, stringified }
10
- export { parseJson, stringifyJson }
5
+ export type primitive = boolean | number | string | null
6
+
7
+ export namespace Json {
8
+ export namespace Tree {
9
+ export type Array<Element = unknown> = ReadonlyArray<Element>
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
+ export type Serializable =
17
+ | primitive
18
+ | Readonly<{ [key: string]: Serializable }>
19
+ | ReadonlyArray<Serializable>
20
+
21
+ export type Object<
22
+ Key extends string = string,
23
+ Value extends Serializable = Serializable,
24
+ > = Record<Key, Value>
25
+
26
+ export type Array<Element extends Serializable = Serializable> =
27
+ ReadonlyArray<Element>
28
+ }
29
+
30
+ export type stringified<J extends Json.Serializable> = string & { __json: J }
31
+
32
+ export const parseJson = <S extends stringified<Json.Serializable>>(
33
+ str: S | string,
34
+ ): S extends stringified<infer J> ? J : Json.Serializable => JSON.parse(str)
35
+
36
+ export const stringifyJson = <J extends Json.Serializable>(
37
+ json: J,
38
+ ): stringified<J> => JSON.stringify(json) as stringified<J>
11
39
 
12
40
  export type Canonical = primitive | ReadonlyArray<Canonical>
13
41
 
14
42
  export type JsonIO = (...params: Json.Serializable[]) => Json.Serializable | void
43
+
44
+ export type JsonInterface<T, J extends Json.Serializable = Json.Serializable> = {
45
+ toJson: (t: T) => J
46
+ fromJson: (json: J) => T
47
+ }
48
+
49
+ const JSON_PROTOTYPES = [Array, Boolean, Number, Object, String] as const
50
+ export const isJson = (input: unknown): input is Json.Tree.Node => {
51
+ if (input === null) return true
52
+ if (input === undefined) return false
53
+ const prototype = Object.getPrototypeOf(input)
54
+ return JSON_PROTOTYPES.includes(prototype)
55
+ }
@@ -42,6 +42,7 @@ export function selectJsonFamily<
42
42
  store: Store = IMPLICIT.STORE,
43
43
  ): AtomIO.WritableSelectorFamilyToken<J, K> {
44
44
  const jsonFamily = createWritableSelectorFamily<J, K>(
45
+ store,
45
46
  {
46
47
  key: `${atomFamilyToken.key}:JSON`,
47
48
  get:
@@ -60,7 +61,7 @@ export function selectJsonFamily<
60
61
  if (store.config.lifespan === `immortal`) {
61
62
  throw new Error(`No molecule found for key "${stringKey}"`)
62
63
  }
63
- const newToken = initFamilyMemberInStore(atomFamilyToken, key, store)
64
+ const newToken = initFamilyMemberInStore(store, atomFamilyToken, key)
64
65
  return transform.toJson(get(newToken))
65
66
  },
66
67
  set:
@@ -80,14 +81,13 @@ export function selectJsonFamily<
80
81
  throw new Error(`No molecule found for key "${stringKey}"`)
81
82
  }
82
83
  set(
83
- initFamilyMemberInStore(atomFamilyToken, key, store),
84
+ initFamilyMemberInStore(store, atomFamilyToken, key),
84
85
  transform.fromJson(newValue),
85
86
  )
86
87
  }
87
88
  }
88
89
  },
89
90
  },
90
- store,
91
91
  [`mutable`, `json`],
92
92
  )
93
93
  const atomFamily = withdraw(atomFamilyToken, store)
@@ -95,7 +95,7 @@ export function selectJsonFamily<
95
95
  `store=${store.config.name}::json-selector-family`,
96
96
  (event) => {
97
97
  if (event.token.family) {
98
- seekInStore(jsonFamily, parseJson(event.token.family.subKey) as K, store)
98
+ seekInStore(store, jsonFamily, parseJson(event.token.family.subKey) as K)
99
99
  }
100
100
  },
101
101
  )
@@ -9,14 +9,11 @@ export const selectJson = <T, J extends Json.Serializable>(
9
9
  transform: JsonInterface<T, J>,
10
10
  store: Store = IMPLICIT.STORE,
11
11
  ): AtomIO.WritableSelectorToken<J> => {
12
- return createStandaloneSelector(
13
- {
14
- key: `${atom.key}:JSON`,
15
- get: ({ get }) => transform.toJson(get(atom)),
16
- set: ({ set }, newValue) => {
17
- set(atom, transform.fromJson(newValue))
18
- },
12
+ return createStandaloneSelector(store, {
13
+ key: `${atom.key}:JSON`,
14
+ get: ({ get }) => transform.toJson(get(atom)),
15
+ set: ({ set }, newValue) => {
16
+ set(atom, transform.fromJson(newValue))
19
17
  },
20
- store,
21
- )
18
+ })
22
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atom.io",
3
- "version": "0.27.4",
3
+ "version": "0.28.0",
4
4
  "description": "Composable and testable reactive data library.",
5
5
  "homepage": "https://atom.io.fyi",
6
6
  "sideEffects": false,
@@ -57,18 +57,18 @@
57
57
  "@types/estree": "1.0.5",
58
58
  "@types/http-proxy": "1.17.15",
59
59
  "@types/npmlog": "7.0.0",
60
- "@types/react": "18.3.3",
60
+ "@types/react": "18.3.4",
61
61
  "@types/tmp": "0.2.6",
62
- "@typescript-eslint/parser": "8.1.0",
63
- "@typescript-eslint/rule-tester": "8.1.0",
62
+ "@typescript-eslint/parser": "8.2.0",
63
+ "@typescript-eslint/rule-tester": "8.2.0",
64
64
  "@vitest/coverage-v8": "2.0.5",
65
65
  "@vitest/ui": "2.0.5",
66
66
  "concurrently": "8.2.2",
67
67
  "drizzle-kit": "0.24.0",
68
68
  "drizzle-orm": "0.33.0",
69
69
  "eslint": "9.9.0",
70
- "framer-motion": "11.3.28",
71
- "happy-dom": "14.12.3",
70
+ "framer-motion": "11.3.29",
71
+ "happy-dom": "15.0.0",
72
72
  "http-proxy": "1.18.1",
73
73
  "npmlog": "7.0.1",
74
74
  "postgres": "3.4.4",
@@ -82,7 +82,7 @@
82
82
  "tsup": "8.2.4",
83
83
  "tsx": "4.17.0",
84
84
  "typescript": "5.5.4",
85
- "vite": "5.4.1",
85
+ "vite": "5.4.2",
86
86
  "vite-tsconfig-paths": "5.0.1",
87
87
  "vitest": "2.0.5"
88
88
  },
@@ -135,7 +135,10 @@
135
135
  "realtime-testing/src",
136
136
  "transceivers/set-rtx/dist",
137
137
  "transceivers/set-rtx/package.json",
138
- "transceivers/set-rtx/src"
138
+ "transceivers/set-rtx/src",
139
+ "web/dist",
140
+ "web/package.json",
141
+ "web/src"
139
142
  ],
140
143
  "exports": {
141
144
  "./package.json": "./package.json",
@@ -217,6 +220,11 @@
217
220
  "./transceivers/set-rtx": {
218
221
  "import": "./transceivers/set-rtx/dist/index.js",
219
222
  "types": "./transceivers/set-rtx/dist/index.d.ts"
223
+ },
224
+ "./web/package.json": "./web/package.json",
225
+ "./web": {
226
+ "import": "./web/dist/index.js",
227
+ "types": "./web/dist/index.d.ts"
220
228
  }
221
229
  },
222
230
  "scripts": {
@@ -240,6 +248,7 @@
240
248
  "build:realtime-server": "cd realtime-server && tsup",
241
249
  "build:realtime-testing": "cd realtime-testing && tsup",
242
250
  "build:transceivers:set-rtx": "cd transceivers/set-rtx && tsup",
251
+ "build:web": "cd web && tsup",
243
252
  "lint:biome": "biome check -- .",
244
253
  "lint:eslint": "eslint --flag unstable_ts_config -- .",
245
254
  "lint:eslint:build": "bun run build:main",