atom.io 0.41.1 → 0.42.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 (59) hide show
  1. package/dist/internal/index.d.ts +30 -47
  2. package/dist/internal/index.d.ts.map +1 -1
  3. package/dist/internal/index.js +116 -287
  4. package/dist/internal/index.js.map +1 -1
  5. package/dist/main/index.d.ts +52 -56
  6. package/dist/main/index.d.ts.map +1 -1
  7. package/dist/main/index.js +45 -8
  8. package/dist/main/index.js.map +1 -1
  9. package/dist/realtime/index.d.ts +2 -3
  10. package/dist/realtime/index.d.ts.map +1 -1
  11. package/dist/realtime/index.js +1 -1
  12. package/dist/realtime/index.js.map +1 -1
  13. package/dist/realtime-server/index.js +1 -1
  14. package/dist/realtime-server/index.js.map +1 -1
  15. package/dist/realtime-testing/index.js +1 -1
  16. package/dist/struct/index.d.ts +14 -0
  17. package/dist/struct/index.d.ts.map +1 -0
  18. package/dist/struct/index.js +35 -0
  19. package/dist/struct/index.js.map +1 -0
  20. package/dist/transceivers/o-list/index.d.ts +8 -4
  21. package/dist/transceivers/o-list/index.d.ts.map +1 -1
  22. package/dist/transceivers/o-list/index.js +2 -1
  23. package/dist/transceivers/o-list/index.js.map +1 -1
  24. package/dist/transceivers/set-rtx/index.d.ts +1 -0
  25. package/dist/transceivers/set-rtx/index.d.ts.map +1 -1
  26. package/dist/transceivers/set-rtx/index.js.map +1 -1
  27. package/dist/transceivers/u-list/index.d.ts +12 -4
  28. package/dist/transceivers/u-list/index.d.ts.map +1 -1
  29. package/dist/transceivers/u-list/index.js +34 -2
  30. package/dist/transceivers/u-list/index.js.map +1 -1
  31. package/dist/utility-types-aZkJVERa.d.ts +10 -0
  32. package/dist/utility-types-aZkJVERa.d.ts.map +1 -0
  33. package/package.json +20 -16
  34. package/src/internal/atom/create-regular-atom.ts +3 -1
  35. package/src/internal/index.ts +0 -1
  36. package/src/internal/join/create-join.ts +8 -11
  37. package/src/internal/join/edit-relations-in-store.ts +6 -8
  38. package/src/internal/join/find-relations-in-store.ts +11 -67
  39. package/src/internal/join/get-internal-relations-from-store.ts +11 -5
  40. package/src/internal/join/get-join.ts +7 -9
  41. package/src/internal/join/join-internal.ts +143 -412
  42. package/src/internal/molecule.ts +44 -25
  43. package/src/internal/mutable/create-mutable-atom.ts +15 -11
  44. package/src/internal/mutable/transceiver.ts +1 -5
  45. package/src/internal/set-state/dispatch-state-update.ts +1 -1
  46. package/src/internal/store/store.ts +16 -15
  47. package/src/internal/transaction/build-transaction.ts +1 -1
  48. package/src/main/atom.ts +15 -6
  49. package/src/main/join.ts +68 -151
  50. package/src/main/realm.ts +58 -17
  51. package/src/realtime/shared-room-store.ts +5 -15
  52. package/src/realtime-server/realtime-server-stores/server-room-external-store.ts +1 -1
  53. package/src/struct/index.ts +1 -0
  54. package/src/{internal → struct}/micro.ts +1 -1
  55. package/src/transceivers/o-list/o-list.ts +13 -9
  56. package/src/transceivers/set-rtx/set-rtx.ts +4 -0
  57. package/src/transceivers/u-list/index.ts +1 -0
  58. package/src/transceivers/u-list/u-list-disposed-key-cleanup-effect.ts +47 -0
  59. package/src/transceivers/u-list/u-list.ts +13 -9
package/src/main/join.ts CHANGED
@@ -13,39 +13,36 @@ import {
13
13
  getInternalRelationsFromStore,
14
14
  IMPLICIT,
15
15
  } from "atom.io/internal"
16
- import type { Json } from "atom.io/json"
17
- import type { SetRTX } from "atom.io/transceivers/set-rtx"
16
+ import type { UList } from "atom.io/transceivers/u-list"
18
17
 
19
18
  // biome-ignore format: intersection
20
19
  export type JoinOptions<
21
- ASide extends string,
22
- AType extends string,
23
- BSide extends string,
24
- BType extends string,
20
+ AName extends string,
21
+ A extends string,
22
+ BName extends string,
23
+ B extends string,
25
24
  Cardinality extends `1:1` | `1:n` | `n:n`,
26
- Content extends Json.Object | null,
27
25
  > =
28
26
  Flat<
29
- & JunctionSchemaBase<ASide, BSide>
27
+ & JunctionSchemaBase<AName, BName>
30
28
  & {
31
29
  /** Unique identifier of the join */
32
30
  readonly key: string
33
31
  /** How many relations are allowed in each direction? */
34
32
  readonly cardinality: Cardinality
35
33
  /** Type guard for the type of the left side */
36
- readonly isAType: Refinement<string, AType>
34
+ readonly isAType: Refinement<string, A>
37
35
  /** Type guard for the type of the right side */
38
- readonly isBType: Refinement<string, BType>
36
+ readonly isBType: Refinement<string, B>
39
37
  }
40
- > & Partial<JunctionEntriesBase<AType, BType, Content>>
38
+ > & Partial<JunctionEntriesBase<A, B, null>>
41
39
 
42
40
  export type JoinToken<
43
- ASide extends string,
44
- AType extends string,
45
- BSide extends string,
46
- BType extends string,
41
+ AName extends string,
42
+ A extends string,
43
+ BName extends string,
44
+ B extends string,
47
45
  Cardinality extends `1:1` | `1:n` | `n:n`,
48
- Content extends Json.Object | null = null,
49
46
  > = {
50
47
  /** Unique identifier of the join */
51
48
  key: string
@@ -54,15 +51,13 @@ export type JoinToken<
54
51
  /** How many relations are allowed in each direction? */
55
52
  cardinality: Cardinality
56
53
  /** Name of the join's left side */
57
- a: ASide
54
+ a: AName
58
55
  /** Name of the join's right side */
59
- b: BSide
56
+ b: BName
60
57
  /** Never present. This is a marker that preserves the type of the left side's keys */
61
- __aType?: AType
58
+ __aType?: A
62
59
  /** Never present. This is a marker that preserves the type of the right side's keys */
63
- __bType?: BType
64
- /** Never present. This is a marker that preserves the type of the data present for each relation */
65
- __content?: Content
60
+ __bType?: B
66
61
  }
67
62
 
68
63
  /**
@@ -73,136 +68,61 @@ export type JoinToken<
73
68
  * Under the hood, joins coordinate changes of multiple atoms to support that the desired relationships stay consistent.
74
69
  *
75
70
  * @param options - {@link JoinOptions}
76
- * @param defaultContent - (undefined)
77
71
  * @returns
78
72
  * A reference to the join created: a {@link JoinToken}
79
- * @overload No Content
80
73
  */
81
74
  export function join<
82
- const ASide extends string,
83
- const AType extends string,
84
- const BSide extends string,
85
- const BType extends string,
75
+ const AName extends string,
76
+ const A extends string,
77
+ const BName extends string,
78
+ const B extends string,
86
79
  const Cardinality extends `1:1` | `1:n` | `n:n`,
87
80
  >(
88
- options: JoinOptions<ASide, AType, BSide, BType, Cardinality, null>,
89
- defaultContent?: undefined,
90
- ): JoinToken<ASide, AType, BSide, BType, Cardinality, null>
91
- /**
92
- * Create a join, an interface for managing relations between two sets of keys.
93
- *
94
- * Use joins when it is important to view relationships from either side.
95
- *
96
- * Under the hood, joins coordinate changes of multiple atoms to support that the desired relationships stay consistent.
97
- *
98
- * @param options - {@link JoinOptions}
99
- * @param defaultContent - The default value for the content of each relation
100
- * @returns
101
- * A reference to the join created: a {@link JoinToken}
102
- * @overload With Content
103
- */
104
- export function join<
105
- const ASide extends string,
106
- const AType extends string,
107
- const BSide extends string,
108
- const BType extends string,
109
- const Cardinality extends `1:1` | `1:n` | `n:n`,
110
- const Content extends Json.Object,
111
- >(
112
- options: JoinOptions<ASide, AType, BSide, BType, Cardinality, Content>,
113
- defaultContent: Content,
114
- ): JoinToken<ASide, AType, BSide, BType, Cardinality, Content>
115
- export function join<
116
- ASide extends string,
117
- AType extends string,
118
- BSide extends string,
119
- BType extends string,
120
- Cardinality extends `1:1` | `1:n` | `n:n`,
121
- Content extends Json.Object,
122
- >(
123
- options: JoinOptions<ASide, AType, BSide, BType, Cardinality, Content>,
124
- defaultContent: Content | undefined,
125
- ): JoinToken<ASide, AType, BSide, BType, Cardinality, Content> {
126
- return createJoin(IMPLICIT.STORE, options, defaultContent)
81
+ options: JoinOptions<AName, A, BName, B, Cardinality>,
82
+ ): JoinToken<AName, A, BName, B, Cardinality> {
83
+ return createJoin(IMPLICIT.STORE, options)
127
84
  }
128
85
 
129
86
  export type JoinStates<
130
- ASide extends string,
131
- AType extends string,
132
- BSide extends string,
133
- BType extends string,
87
+ AName extends string,
88
+ A extends string,
89
+ BName extends string,
90
+ B extends string,
134
91
  Cardinality extends `1:1` | `1:n` | `n:n`,
135
- Content extends Json.Object | null,
136
92
  > = Cardinality extends `1:1`
137
- ? (Content extends Json.Object
138
- ? {
139
- readonly [A in ASide as `${A}EntryOf${Capitalize<BSide>}`]: ReadonlyPureSelectorToken<
140
- [AType, Content] | null,
141
- BType
142
- >
143
- } & {
144
- readonly [B in BSide as `${B}EntryOf${Capitalize<ASide>}`]: ReadonlyPureSelectorToken<
145
- [BType, Content] | null,
146
- AType
147
- >
148
- }
149
- : {}) & {
150
- readonly [A in ASide as `${A}KeyOf${Capitalize<BSide>}`]: ReadonlyPureSelectorToken<
151
- AType | null,
152
- BType
93
+ ? {
94
+ readonly [N in AName as `${N}KeyOf${Capitalize<BName>}`]: ReadonlyPureSelectorToken<
95
+ A | null,
96
+ B
153
97
  >
154
98
  } & {
155
- readonly [B in BSide as `${B}KeyOf${Capitalize<ASide>}`]: ReadonlyPureSelectorToken<
156
- BType | null,
157
- AType
99
+ readonly [N in BName as `${N}KeyOf${Capitalize<AName>}`]: ReadonlyPureSelectorToken<
100
+ B | null,
101
+ A
158
102
  >
159
103
  }
160
104
  : Cardinality extends `1:n`
161
- ? (Content extends Json.Object
162
- ? {
163
- readonly [A in ASide as `${A}EntryOf${Capitalize<BSide>}`]: ReadonlyPureSelectorToken<
164
- [AType, Content] | null,
165
- BType
166
- >
167
- } & {
168
- readonly [B in BSide as `${B}EntriesOf${Capitalize<ASide>}`]: ReadonlyPureSelectorToken<
169
- [BType, Content][],
170
- AType
171
- >
172
- }
173
- : {}) & {
174
- readonly [A in ASide as `${A}KeyOf${Capitalize<BSide>}`]: ReadonlyPureSelectorToken<
175
- AType | null,
176
- BType
105
+ ? {
106
+ readonly [N in AName as `${N}KeyOf${Capitalize<BName>}`]: ReadonlyPureSelectorToken<
107
+ A | null,
108
+ B
177
109
  >
178
110
  } & {
179
- readonly [B in BSide as `${B}KeysOf${Capitalize<ASide>}`]: ReadonlyPureSelectorToken<
180
- BType[],
181
- AType
111
+ readonly [N in BName as `${N}KeysOf${Capitalize<AName>}`]: ReadonlyPureSelectorToken<
112
+ B[],
113
+ A
182
114
  >
183
115
  }
184
116
  : Cardinality extends `n:n`
185
- ? (Content extends Json.Object
186
- ? {
187
- readonly [A in ASide as `${A}EntriesOf${Capitalize<BSide>}`]: ReadonlyPureSelectorToken<
188
- [AType, Content][],
189
- BType
190
- >
191
- } & {
192
- readonly [B in BSide as `${B}EntriesOf${Capitalize<ASide>}`]: ReadonlyPureSelectorToken<
193
- [BType, Content][],
194
- AType
195
- >
196
- }
197
- : {}) & {
198
- readonly [A in ASide as `${A}KeysOf${Capitalize<BSide>}`]: ReadonlyPureSelectorToken<
199
- AType[],
200
- BType
117
+ ? {
118
+ readonly [N in AName as `${N}KeysOf${Capitalize<BName>}`]: ReadonlyPureSelectorToken<
119
+ A[],
120
+ B
201
121
  >
202
122
  } & {
203
- readonly [B in BSide as `${B}KeysOf${Capitalize<ASide>}`]: ReadonlyPureSelectorToken<
204
- BType[],
205
- AType
123
+ readonly [N in BName as `${N}KeysOf${Capitalize<AName>}`]: ReadonlyPureSelectorToken<
124
+ B[],
125
+ A
206
126
  >
207
127
  }
208
128
  : never
@@ -216,16 +136,15 @@ export type JoinStates<
216
136
  * @overload Default
217
137
  */
218
138
  export function findRelations<
219
- ASide extends string,
220
- AType extends string,
221
- BSide extends string,
222
- BType extends string,
139
+ AName extends string,
140
+ A extends string,
141
+ BName extends string,
142
+ B extends string,
223
143
  Cardinality extends `1:1` | `1:n` | `n:n`,
224
- Content extends Json.Object | null,
225
144
  >(
226
- token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
227
- key: AType | BType,
228
- ): JoinStates<ASide, AType, BSide, BType, Cardinality, Content> {
145
+ token: JoinToken<AName, A, BName, B, Cardinality>,
146
+ key: A | B,
147
+ ): JoinStates<AName, A, BName, B, Cardinality> {
229
148
  return findRelationsInStore(token, key, IMPLICIT.STORE)
230
149
  }
231
150
 
@@ -235,15 +154,14 @@ export function findRelations<
235
154
  * @param change - A function that takes a {@link Junction} interface to edit the relations
236
155
  */
237
156
  export function editRelations<
238
- ASide extends string,
239
- AType extends string,
240
- BSide extends string,
241
- BType extends string,
157
+ AName extends string,
158
+ A extends string,
159
+ BName extends string,
160
+ B extends string,
242
161
  Cardinality extends `1:1` | `1:n` | `n:n`,
243
- Content extends Json.Object | null,
244
162
  >(
245
- token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
246
- change: (relations: Junction<ASide, AType, BSide, BType, Content>) => void,
163
+ token: JoinToken<AName, A, BName, B, Cardinality>,
164
+ change: (relations: Junction<AName, A, BName, B>) => void,
247
165
  ): void {
248
166
  editRelationsInStore(token, change, IMPLICIT.STORE)
249
167
  }
@@ -254,14 +172,13 @@ export function editRelations<
254
172
  * A {@link MutableAtomFamilyToken} to access the internal relations
255
173
  */
256
174
  export function getInternalRelations<
257
- ASide extends string,
258
- AType extends string,
259
- BSide extends string,
260
- BType extends string,
175
+ AName extends string,
176
+ A extends string,
177
+ BName extends string,
178
+ B extends string,
261
179
  Cardinality extends `1:1` | `1:n` | `n:n`,
262
- Content extends Json.Object | null,
263
180
  >(
264
- token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
265
- ): MutableAtomFamilyToken<SetRTX<string>, string> {
181
+ token: JoinToken<AName, A, BName, B, Cardinality>,
182
+ ): MutableAtomFamilyToken<UList<A> | UList<B>, string> {
266
183
  return getInternalRelationsFromStore(token, IMPLICIT.STORE)
267
184
  }
package/src/main/realm.ts CHANGED
@@ -14,16 +14,20 @@ import type { Canonical } from "atom.io/json"
14
14
 
15
15
  import type { TransactionToken } from "./tokens"
16
16
 
17
- export const $claim: unique symbol = Symbol.for(`claim`)
18
- export type Claim<K extends Canonical> = K & { [$claim]?: true }
17
+ export const $validatedKey: unique symbol = Symbol.for(`claim`)
18
+ export type ValidKey<K extends Canonical> = K & { [$validatedKey]?: true }
19
+
20
+ export function simpleCompound(a: string, b: string): string {
21
+ return [a, b].sort().join(`\u001F`)
22
+ }
19
23
 
20
24
  export class Realm<H extends Hierarchy> {
21
25
  public store: RootStore
22
- public deallocateTX: TransactionToken<(claim: Claim<Vassal<H>>) => void>
26
+ public deallocateTX: TransactionToken<(claim: ValidKey<Vassal<H>>) => void>
23
27
  public claimTX: TransactionToken<
24
28
  <V extends Exclude<Vassal<H>, CompoundTypedKey>, A extends Above<V, H>>(
25
29
  newProvenance: A,
26
- claim: Claim<V>,
30
+ claim: ValidKey<V>,
27
31
  exclusive?: `exclusive`,
28
32
  ) => void
29
33
  >
@@ -42,13 +46,13 @@ export class Realm<H extends Hierarchy> {
42
46
  * @param key - A unique identifier for the new subject
43
47
  * @param attachmentStyle - The attachment style of new subject to its owner(s). `any` means that if any owners remain, the subject will be retained. `all` means that the subject be retained only if all owners remain .
44
48
  * @returns
45
- * The subject's key, given status as a true {@link Claim}
49
+ * The subject's key, given status as a true {@link ValidKey}
46
50
  */
47
51
  public allocate<V extends Vassal<H>, A extends Above<V, H>>(
48
52
  provenance: A,
49
53
  key: V,
50
54
  attachmentStyle?: `all` | `any`,
51
- ): Claim<V> {
55
+ ): ValidKey<V> {
52
56
  return allocateIntoStore<H, V, A>(
53
57
  this.store,
54
58
  provenance,
@@ -62,7 +66,7 @@ export class Realm<H extends Hierarchy> {
62
66
  * @param reagentA - the left reagent of the compound
63
67
  * @param reagentB - the right reagent of the compound
64
68
  * @returns
65
- * The compound's key, given status as a true {@link Claim}
69
+ * The compound's key, given status as a {@link ValidKey}
66
70
  */
67
71
  public fuse<
68
72
  C extends CompoundFrom<H>,
@@ -73,14 +77,14 @@ export class Realm<H extends Hierarchy> {
73
77
  type: T,
74
78
  reagentA: SingularTypedKey<A>,
75
79
  reagentB: SingularTypedKey<B>,
76
- ): Claim<CompoundTypedKey<T, A, B>> {
80
+ ): ValidKey<CompoundTypedKey<T, A, B>> {
77
81
  return fuseWithinStore<H, C, T, A, B>(this.store, type, reagentA, reagentB)
78
82
  }
79
83
  /**
80
84
  * Remove a subject from the realm
81
85
  * @param claim - The subject to be deallocated
82
86
  */
83
- public deallocate<V extends Vassal<H>>(claim: Claim<V>): void {
87
+ public deallocate<V extends Vassal<H>>(claim: ValidKey<V>): void {
84
88
  actUponStore(this.store, this.deallocateTX, arbitrary())(claim)
85
89
  }
86
90
  /**
@@ -89,12 +93,12 @@ export class Realm<H extends Hierarchy> {
89
93
  * @param claim - The subject to be claimed
90
94
  * @param exclusive - Whether the subjects previous owners should be detached from it
91
95
  * @returns
92
- * The subject's key, given status as a true {@link Claim}
96
+ * The subject's key, given status as a true {@link ValidKey}
93
97
  */
94
98
  public claim<
95
99
  V extends Exclude<Vassal<H>, CompoundTypedKey>,
96
100
  A extends Above<V, H>,
97
- >(newProvenance: A, claim: Claim<V>, exclusive?: `exclusive`): void {
101
+ >(newProvenance: A, claim: ValidKey<V>, exclusive?: `exclusive`): void {
98
102
  actUponStore(this.store, this.claimTX, arbitrary())(
99
103
  newProvenance,
100
104
  claim,
@@ -157,22 +161,59 @@ export class Anarchy {
157
161
  ): void {
158
162
  claimWithinStore<any, any, any>(this.store, newProvenance, key, exclusive)
159
163
  }
164
+ /**
165
+ * Fuse two reagents into a compound
166
+ * @param type - the name of the compound that is being fused
167
+ * @param reagentA - the left reagent of the compound
168
+ * @param reagentB - the right reagent of the compound
169
+ * @returns
170
+ * The compound's key, given status as a {@link ValidKey}
171
+ */
172
+ public fuse<T extends string, A extends string, B extends string>(
173
+ type: T,
174
+ reagentA: SingularTypedKey<A>,
175
+ reagentB: SingularTypedKey<B>,
176
+ ): ValidKey<CompoundTypedKey<T, A, B>> {
177
+ return fuseWithinStore<any, any, T, A, B>(
178
+ this.store,
179
+ type,
180
+ reagentA,
181
+ reagentB,
182
+ )
183
+ }
184
+ }
185
+
186
+ export function decomposeCompound(
187
+ compound: Canonical,
188
+ ): [type: string, a: string, b: string] | null {
189
+ if ((typeof compound === `string`) === false) {
190
+ return null
191
+ }
192
+ const [typeTag, components] = compound.split(`==`)
193
+ if (!components) {
194
+ return null
195
+ }
196
+ const type = typeTag.slice(4)
197
+ const [a, b] = components.split(`++`)
198
+ if (type && a && b) {
199
+ return [type, a, b]
200
+ }
201
+ return null
160
202
  }
161
203
 
162
- export const T$ = `T$`
163
- export type T$ = typeof T$
204
+ export type T$ = `T$`
164
205
  export type TypeTag<T extends string> = `${T$}--${T}`
165
206
  export type SingularTypedKey<T extends string = string> = `${T}::${string}`
166
207
  export type CompoundTypedKey<
208
+ T extends string = string,
167
209
  A extends string = string,
168
210
  B extends string = string,
169
- C extends string = string,
170
- > = `${TypeTag<A>}==${SingularTypedKey<B>}++${SingularTypedKey<C>}`
211
+ > = `${TypeTag<T>}==${SingularTypedKey<A>}++${SingularTypedKey<B>}`
171
212
  export type TypedKey<
213
+ T extends string = string,
172
214
  A extends string = string,
173
215
  B extends string = string,
174
- C extends string = string,
175
- > = CompoundTypedKey<A, B, C> | SingularTypedKey<A>
216
+ > = CompoundTypedKey<T, A, B> | SingularTypedKey<T>
176
217
  type Scope = SingularTypedKey[]
177
218
  type MutualFealty = {
178
219
  above: Scope
@@ -4,7 +4,6 @@ import type {
4
4
  ReadonlyPureSelectorFamilyToken,
5
5
  } from "atom.io"
6
6
  import { getInternalRelations, join, mutableAtom, selectorFamily } from "atom.io"
7
- import type { SetRTX } from "atom.io/transceivers/set-rtx"
8
7
  import { UList } from "atom.io/transceivers/u-list"
9
8
 
10
9
  export const usersInThisRoomIndex: MutableAtomToken<UList<string>> = mutableAtom<
@@ -27,28 +26,19 @@ export type UserInRoomMeta = {
27
26
  export const DEFAULT_USER_IN_ROOM_META: UserInRoomMeta = {
28
27
  enteredAtEpoch: 0,
29
28
  }
30
- export const usersInRooms: JoinToken<
31
- `room`,
32
- string,
33
- `user`,
34
- string,
35
- `1:n`,
36
- UserInRoomMeta
37
- > = join(
38
- {
29
+ export const usersInRooms: JoinToken<`room`, string, `user`, string, `1:n`> =
30
+ join({
39
31
  key: `usersInRooms`,
40
32
  between: [`room`, `user`],
41
33
  cardinality: `1:n`,
42
34
  isAType: (input): input is string => typeof input === `string`,
43
35
  isBType: (input): input is string => typeof input === `string`,
44
- },
45
- DEFAULT_USER_IN_ROOM_META,
46
- )
36
+ })
47
37
 
48
38
  export const usersInMyRoomView: ReadonlyPureSelectorFamilyToken<
49
- MutableAtomToken<SetRTX<string>>[],
39
+ MutableAtomToken<UList<string>>[],
50
40
  string
51
- > = selectorFamily<MutableAtomToken<SetRTX<string>>[], string>({
41
+ > = selectorFamily<MutableAtomToken<UList<string>>[], string>({
52
42
  key: `usersInMyRoomView`,
53
43
  get:
54
44
  (myUsername) =>
@@ -43,7 +43,7 @@ export const joinRoomTX: TransactionToken<
43
43
  editRelationsInStore(
44
44
  usersInRooms,
45
45
  (relations) => {
46
- relations.set({ room: roomId, user: userId }, meta)
46
+ relations.set({ room: roomId, user: userId })
47
47
  },
48
48
  tools.env().store,
49
49
  )
@@ -0,0 +1 @@
1
+ export * from "./micro"
@@ -1,6 +1,6 @@
1
1
  import type { primitive } from "atom.io/json"
2
2
 
3
- import type { Flat } from "./utility-types"
3
+ import type { Flat } from "../internal/utility-types"
4
4
 
5
5
  export type IndexOf<
6
6
  T extends readonly unknown[],
@@ -1,11 +1,8 @@
1
- import type {
2
- Enumeration,
3
- Fn,
4
- Transceiver,
5
- TransceiverMode,
6
- } from "atom.io/internal"
7
- import { enumeration, packValue, Subject, unpackValue } from "atom.io/internal"
1
+ import type { Fn, Transceiver, TransceiverMode } from "atom.io/internal"
2
+ import { Subject } from "atom.io/internal"
8
3
  import type { primitive } from "atom.io/json"
4
+ import type { Enumeration } from "atom.io/struct"
5
+ import { enumeration, packValue, unpackValue } from "atom.io/struct"
9
6
 
10
7
  export type ArrayMutations = Exclude<keyof Array<any>, keyof ReadonlyArray<any>>
11
8
  export type ArrayUpdate<P extends primitive> =
@@ -99,16 +96,23 @@ export type ArrayMutationHandler = {
99
96
  [K in Exclude<OListUpdateType, `extend` | `set` | `truncate`>]: Fn
100
97
  }
101
98
 
99
+ export type OListView<P extends primitive> = ReadonlyArray<P> & {
100
+ subscribe: (
101
+ key: string,
102
+ fn: (update: PackedArrayUpdate<P>) => void,
103
+ ) => () => void
104
+ }
105
+
102
106
  export class OList<P extends primitive>
103
107
  extends Array<P>
104
108
  implements
105
- Transceiver<ReadonlyArray<P>, PackedArrayUpdate<P>, ReadonlyArray<P>>,
109
+ Transceiver<OListView<P>, PackedArrayUpdate<P>, ReadonlyArray<P>>,
106
110
  ArrayMutationHandler
107
111
  {
108
112
  public mode: TransceiverMode = `record`
109
113
  public readonly subject: Subject<PackedArrayUpdate<P>> = new Subject()
110
114
 
111
- public readonly READONLY_VIEW: ReadonlyArray<P> = this
115
+ public readonly READONLY_VIEW: OListView<P> = this
112
116
 
113
117
  public constructor(arrayLength?: number)
114
118
  public constructor(...items: P[])
@@ -12,6 +12,10 @@ export interface SetRTXView<P extends primitive> extends ReadonlySet<P> {
12
12
  readonly cacheLimit: number
13
13
  readonly cacheIdx: number
14
14
  readonly cacheUpdateNumber: number
15
+ readonly subscribe: (
16
+ key: string,
17
+ fn: (update: NumberedSetUpdateString) => void,
18
+ ) => () => void
15
19
  }
16
20
 
17
21
  export interface SetRTXJson<P extends primitive> extends Json.Object {
@@ -1 +1,2 @@
1
1
  export * from "./u-list"
2
+ export * from "./u-list-disposed-key-cleanup-effect"
@@ -0,0 +1,47 @@
1
+ import type { AtomEffect } from "atom.io"
2
+ import { getUpdateToken, subscribeInStore } from "atom.io/internal"
3
+ import { type primitive, stringifyJson } from "atom.io/json"
4
+
5
+ import { UList } from "./u-list"
6
+
7
+ export const uListDisposedKeyCleanupEffect: AtomEffect<UList<primitive>> = ({
8
+ token,
9
+ setSelf,
10
+ store,
11
+ }) => {
12
+ const disposalSubscriptions = new Map<primitive, () => void>()
13
+ const updateToken = getUpdateToken(token)
14
+ subscribeInStore(
15
+ store,
16
+ updateToken,
17
+ function setAutoDeletionTriggers({ newValue }) {
18
+ const unpacked = UList.unpackUpdate(newValue)
19
+ switch (unpacked.type) {
20
+ case `add`:
21
+ {
22
+ const molecule = store.molecules.get(stringifyJson(unpacked.value))
23
+ if (molecule) {
24
+ disposalSubscriptions.set(
25
+ unpacked.value,
26
+ molecule.subject.subscribe(token.key, () => {
27
+ setSelf((self) => {
28
+ self.delete(unpacked.value)
29
+ return self
30
+ })
31
+ }),
32
+ )
33
+ }
34
+ }
35
+ break
36
+ case `delete`:
37
+ disposalSubscriptions.get(unpacked.value)?.()
38
+ disposalSubscriptions.delete(unpacked.value)
39
+ break
40
+ case `clear`:
41
+ for (const unsub of disposalSubscriptions.values()) unsub()
42
+ disposalSubscriptions.clear()
43
+ }
44
+ },
45
+ `set-auto-deletion-triggers`,
46
+ )
47
+ }
@@ -1,11 +1,8 @@
1
- import type {
2
- Enumeration,
3
- Fn,
4
- Transceiver,
5
- TransceiverMode,
6
- } from "atom.io/internal"
7
- import { enumeration, packValue, Subject, unpackValue } from "atom.io/internal"
1
+ import type { Fn, Transceiver, TransceiverMode } from "atom.io/internal"
2
+ import { Subject } from "atom.io/internal"
8
3
  import type { primitive } from "atom.io/json"
4
+ import type { Enumeration } from "atom.io/struct"
5
+ import { enumeration, packValue, unpackValue } from "atom.io/struct"
9
6
 
10
7
  export type SetMutations = Exclude<
11
8
  keyof Set<any>,
@@ -34,10 +31,17 @@ export const SET_UPDATE_ENUM: Enumeration<[`add`, `delete`, `clear`]> =
34
31
 
35
32
  export type SetMutationHandler = { [K in UListUpdateType]: Fn }
36
33
 
34
+ export type UListView<P extends primitive> = ReadonlySet<P> & {
35
+ subscribe: (
36
+ key: string,
37
+ fn: (update: PackedSetUpdate<P>) => void,
38
+ ) => () => void
39
+ }
40
+
37
41
  export class UList<P extends primitive>
38
42
  extends Set<P>
39
43
  implements
40
- Transceiver<ReadonlySet<P>, PackedSetUpdate<P>, ReadonlyArray<P>>,
44
+ Transceiver<UListView<P>, PackedSetUpdate<P>, ReadonlyArray<P>>,
41
45
  SetMutationHandler
42
46
  {
43
47
  public mode: TransceiverMode = `record`
@@ -49,7 +53,7 @@ export class UList<P extends primitive>
49
53
  }
50
54
  }
51
55
 
52
- public readonly READONLY_VIEW: ReadonlySet<P> = this
56
+ public readonly READONLY_VIEW: UListView<P> = this
53
57
 
54
58
  public toJSON(): ReadonlyArray<P> {
55
59
  return [...this]