atom.io 0.29.5 → 0.30.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 (44) hide show
  1. package/data/dist/index.d.ts +84 -51
  2. package/data/dist/index.js +35 -31
  3. package/data/src/join.ts +240 -134
  4. package/dist/chunk-ADMEAXYU.js +167 -0
  5. package/dist/{chunk-TCINPEYE.js → chunk-SMKF3ZNG.js} +221 -137
  6. package/dist/index.d.ts +75 -10
  7. package/dist/index.js +3 -17
  8. package/internal/dist/index.d.ts +76 -41
  9. package/internal/dist/index.js +2 -1
  10. package/internal/src/atom/dispose-atom.ts +4 -8
  11. package/internal/src/index.ts +1 -1
  12. package/internal/src/ingest-updates/ingest-creation-disposal.ts +71 -27
  13. package/internal/src/junction.ts +152 -84
  14. package/internal/src/molecule/create-molecule-family.ts +2 -2
  15. package/internal/src/molecule/dispose-molecule.ts +4 -2
  16. package/internal/src/molecule/make-molecule-in-store.ts +11 -9
  17. package/internal/src/molecule/molecule-internal.ts +12 -8
  18. package/internal/src/mutable/create-mutable-atom-family.ts +2 -2
  19. package/internal/src/mutable/get-json-family.ts +2 -2
  20. package/internal/src/store/store.ts +10 -2
  21. package/internal/src/timeline/create-timeline.ts +99 -71
  22. package/internal/src/transaction/index.ts +1 -1
  23. package/internal/src/utility-types.ts +9 -2
  24. package/json/dist/index.d.ts +3 -3
  25. package/json/dist/index.js +2 -1
  26. package/json/src/entries.ts +3 -3
  27. package/package.json +15 -15
  28. package/react-devtools/dist/index.js +9 -5
  29. package/react-devtools/src/TimelineIndex.tsx +4 -1
  30. package/react-devtools/src/Updates.tsx +18 -3
  31. package/realtime/dist/index.d.ts +1 -1
  32. package/realtime/dist/index.js +3 -1
  33. package/realtime/src/shared-room-store.ts +2 -0
  34. package/realtime-server/dist/index.d.ts +13 -4
  35. package/realtime-server/dist/index.js +4 -2
  36. package/realtime-server/src/realtime-continuity-synchronizer.ts +2 -2
  37. package/realtime-server/src/realtime-server-stores/server-user-store.ts +17 -1
  38. package/realtime-testing/dist/index.d.ts +3 -0
  39. package/realtime-testing/dist/index.js +11 -4
  40. package/realtime-testing/src/setup-realtime-test.tsx +12 -4
  41. package/src/allocate.ts +277 -0
  42. package/src/index.ts +1 -0
  43. package/src/molecule.ts +9 -5
  44. package/src/transaction.ts +22 -4
package/data/src/join.ts CHANGED
@@ -19,10 +19,9 @@ import type { seekState } from "atom.io/immortal"
19
19
  import type {
20
20
  BaseExternalStoreConfiguration,
21
21
  ExternalStoreConfiguration,
22
- JunctionEntries,
23
- JunctionSchema,
22
+ JunctionEntriesBase,
23
+ JunctionSchemaBase,
24
24
  Molecule,
25
- // RelationCardinality,
26
25
  Store,
27
26
  } from "atom.io/internal"
28
27
  import {
@@ -46,7 +45,9 @@ import {
46
45
  setIntoStore,
47
46
  withdraw,
48
47
  } from "atom.io/internal"
49
- import { type Json, stringifyJson } from "atom.io/json"
48
+ import type { Refinement } from "atom.io/introspection"
49
+ import type { Json } from "atom.io/json"
50
+ import { stringifyJson } from "atom.io/json"
50
51
  import type { SetRTXJson } from "atom.io/transceivers/set-rtx"
51
52
  import { SetRTX } from "atom.io/transceivers/set-rtx"
52
53
 
@@ -56,96 +57,122 @@ function capitalize<S extends string>(string: S): Capitalize<S> {
56
57
 
57
58
  export interface JoinOptions<
58
59
  ASide extends string,
60
+ AType extends string,
59
61
  BSide extends string,
62
+ BType extends string,
60
63
  Cardinality extends `1:1` | `1:n` | `n:n`,
61
64
  Content extends Json.Object | null,
62
- > extends Json.Object,
63
- JunctionSchema<ASide, BSide>,
64
- Partial<JunctionEntries<Content>> {
65
+ > extends JunctionSchemaBase<ASide, BSide>,
66
+ Partial<JunctionEntriesBase<AType, BType, Content>> {
65
67
  readonly key: string
66
68
  readonly cardinality: Cardinality
69
+ readonly isAType: Refinement<string, AType>
70
+ readonly isBType: Refinement<string, BType>
67
71
  }
68
72
 
69
73
  export type JoinStateFamilies<
70
74
  ASide extends string,
75
+ AType extends string,
71
76
  BSide extends string,
77
+ BType extends string,
72
78
  Cardinality extends `1:1` | `1:n` | `n:n`,
73
79
  Content extends Json.Object | null,
74
80
  > = Cardinality extends `1:1`
75
81
  ? (Content extends Json.Object
76
82
  ? {
77
- readonly [AB in ASide | BSide as AB extends ASide
78
- ? `${AB}EntryOf${Capitalize<BSide>}`
79
- : `${AB}EntryOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
80
- [string, Content] | null,
81
- string
83
+ readonly [A in ASide as `${A}EntryOf${Capitalize<BSide>}`]: ReadonlySelectorFamilyToken<
84
+ [AType, Content] | null,
85
+ BType
86
+ >
87
+ } & {
88
+ readonly [B in BSide as `${B}EntryOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
89
+ [BType, Content] | null,
90
+ AType
82
91
  >
83
92
  }
84
93
  : {}) & {
85
- readonly [AB in ASide | BSide as AB extends ASide
86
- ? `${AB}KeyOf${Capitalize<BSide>}`
87
- : `${AB}KeyOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
88
- string | null,
89
- string
94
+ readonly [A in ASide as `${A}KeyOf${Capitalize<BSide>}`]: ReadonlySelectorFamilyToken<
95
+ AType | null,
96
+ BType
97
+ >
98
+ } & {
99
+ readonly [B in BSide as `${B}KeyOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
100
+ BType | null,
101
+ AType
90
102
  >
91
103
  }
92
104
  : Cardinality extends `1:n`
93
105
  ? (Content extends Json.Object
94
106
  ? {
95
107
  readonly [A in ASide as `${A}EntryOf${Capitalize<BSide>}`]: ReadonlySelectorFamilyToken<
96
- [string, Content] | null,
97
- string
108
+ [AType, Content] | null,
109
+ BType
98
110
  >
99
111
  } & {
100
112
  readonly [B in BSide as `${B}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
101
- [string, Content][],
102
- string
113
+ [BType, Content][],
114
+ AType
103
115
  >
104
116
  }
105
117
  : {}) & {
106
118
  readonly [A in ASide as `${A}KeyOf${Capitalize<BSide>}`]: ReadonlySelectorFamilyToken<
107
- string | null,
108
- string
119
+ AType | null,
120
+ BType
109
121
  >
110
122
  } & {
111
123
  readonly [B in BSide as `${B}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
112
- string[],
113
- string
124
+ BType[],
125
+ AType
114
126
  >
115
127
  }
116
128
  : Cardinality extends `n:n`
117
129
  ? (Content extends Json.Object
118
130
  ? {
119
- readonly [AB in ASide | BSide as AB extends ASide
120
- ? `${AB}EntriesOf${Capitalize<BSide>}`
121
- : `${AB}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
122
- [string, Content][],
123
- string
131
+ readonly [A in ASide as `${A}EntriesOf${Capitalize<BSide>}`]: ReadonlySelectorFamilyToken<
132
+ [AType, Content][],
133
+ BType
134
+ >
135
+ } & {
136
+ readonly [B in BSide as `${B}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
137
+ [BType, Content][],
138
+ AType
124
139
  >
125
140
  }
126
141
  : {}) & {
127
- readonly [AB in ASide | BSide as AB extends ASide
128
- ? `${AB}KeysOf${Capitalize<BSide>}`
129
- : `${AB}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
130
- string[],
131
- string
142
+ readonly [A in ASide as `${A}KeysOf${Capitalize<BSide>}`]: ReadonlySelectorFamilyToken<
143
+ AType[],
144
+ BType
145
+ >
146
+ } & {
147
+ readonly [B in BSide as `${B}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
148
+ BType[],
149
+ AType
132
150
  >
133
151
  }
134
152
  : never
135
153
 
136
154
  export class Join<
137
155
  const ASide extends string,
156
+ const AType extends string,
138
157
  const BSide extends string,
158
+ const BType extends string,
139
159
  const Cardinality extends `1:1` | `1:n` | `n:n`,
140
160
  const Content extends Json.Object | null = null,
141
161
  > {
142
- private options: JoinOptions<ASide, BSide, Cardinality, Content>
162
+ private options: JoinOptions<ASide, AType, BSide, BType, Cardinality, Content>
143
163
  private defaultContent: Content | undefined
144
164
  private toolkit: SetterToolkit & { dispose: typeof disposeState }
145
165
  public retrieve: typeof findState
146
166
  public molecules: Map<string, Molecule<any>> = new Map()
147
- public relations: Junction<ASide, BSide, Content>
148
- public states: JoinStateFamilies<ASide, BSide, Cardinality, Content>
167
+ public relations: Junction<ASide, AType, BSide, BType, Content>
168
+ public states: JoinStateFamilies<
169
+ ASide,
170
+ AType,
171
+ BSide,
172
+ BType,
173
+ Cardinality,
174
+ Content
175
+ >
149
176
  public core: {
150
177
  findRelatedKeysState: MutableAtomFamilyToken<
151
178
  SetRTX<string>,
@@ -155,7 +182,7 @@ export class Join<
155
182
  }
156
183
  public transact(
157
184
  toolkit: SetterToolkit & { dispose: typeof disposeState },
158
- run: (join: Join<ASide, BSide, Cardinality, Content>) => void,
185
+ run: (join: Join<ASide, AType, BSide, BType, Cardinality, Content>) => void,
159
186
  ): void {
160
187
  const originalToolkit = this.toolkit
161
188
  this.toolkit = toolkit
@@ -164,12 +191,17 @@ export class Join<
164
191
  }
165
192
 
166
193
  public store: Store
167
- public alternates: Map<string, Join<ASide, BSide, Cardinality, Content>>
194
+ public alternates: Map<
195
+ string,
196
+ Join<ASide, AType, BSide, BType, Cardinality, Content>
197
+ >
168
198
  public [Symbol.dispose](): void {
169
199
  this.alternates.delete(this.store.config.name)
170
200
  }
171
201
 
172
- public in(store: Store): Join<ASide, BSide, Cardinality, Content> {
202
+ public in(
203
+ store: Store,
204
+ ): Join<ASide, AType, BSide, BType, Cardinality, Content> {
173
205
  const key = store.config.name
174
206
  const alternate = this.alternates.get(key)
175
207
  if (alternate) {
@@ -182,10 +214,12 @@ export class Join<
182
214
  }
183
215
 
184
216
  public constructor(
185
- options: JoinOptions<ASide, BSide, Cardinality, Content>,
217
+ options: JoinOptions<ASide, AType, BSide, BType, Cardinality, Content>,
186
218
  defaultContent: Content | undefined,
187
219
  store: Store = IMPLICIT.STORE,
188
220
  ) {
221
+ type AnyKey = AType & BType
222
+
189
223
  this.store = store
190
224
  this.options = options
191
225
  this.defaultContent = defaultContent
@@ -202,7 +236,7 @@ export class Join<
202
236
  if (maybeToken) {
203
237
  return maybeToken
204
238
  }
205
- const molecule = this.molecules.get(stringifyJson(key))
239
+ const molecule = this.store.molecules.get(stringifyJson(key))
206
240
  if (molecule) {
207
241
  const family = withdraw(token, store)
208
242
  return growMoleculeInStore(molecule, family, store)
@@ -245,10 +279,9 @@ export class Join<
245
279
  [`join`, `relations`],
246
280
  )
247
281
  this.core = { findRelatedKeysState: relatedKeysAtoms }
248
- const getRelatedKeys: Read<(key: string) => SetRTX<string>> = (
249
- { get },
250
- key,
251
- ) => get(this.retrieve(relatedKeysAtoms, key))
282
+ const getRelatedKeys: Read<
283
+ (key: string) => SetRTX<AType> | SetRTX<BType>
284
+ > = ({ get }, key) => get(this.retrieve(relatedKeysAtoms, key) as any)
252
285
  const addRelation: Write<(a: string, b: string) => void> = (
253
286
  toolkit,
254
287
  a,
@@ -310,7 +343,7 @@ export class Join<
310
343
  nextRelationsOfA.clear()
311
344
  for (const newRelationB of newRelationsOfA) {
312
345
  const relationsOfB = getRelatedKeys(toolkit, newRelationB)
313
- const newRelationBIsAlreadyRelated = relationsOfB.has(a)
346
+ const newRelationBIsAlreadyRelated = relationsOfB.has(a as AnyKey)
314
347
  if (this.relations.cardinality === `1:n`) {
315
348
  const previousOwnersToDispose: string[] = []
316
349
  for (const previousOwner of relationsOfB) {
@@ -321,7 +354,7 @@ export class Join<
321
354
  toolkit,
322
355
  previousOwner,
323
356
  )
324
- previousOwnerRelations.delete(newRelationB)
357
+ previousOwnerRelations.delete(newRelationB as AnyKey)
325
358
  if (previousOwnerRelations.size === 0) {
326
359
  previousOwnersToDispose.push(previousOwner)
327
360
  }
@@ -336,7 +369,7 @@ export class Join<
336
369
  }
337
370
  }
338
371
  if (!newRelationBIsAlreadyRelated) {
339
- relationsOfB.add(a)
372
+ relationsOfB.add(a as AnyKey)
340
373
  }
341
374
  nextRelationsOfA.add(newRelationB)
342
375
  }
@@ -370,7 +403,7 @@ export class Join<
370
403
  }
371
404
  const has: Read<(a: string, b?: string) => boolean> = (toolkit, a, b) => {
372
405
  const aKeys = getRelatedKeys(toolkit, a)
373
- return b ? aKeys.has(b) : aKeys.size > 0
406
+ return b ? aKeys.has(b as AnyKey) : aKeys.size > 0
374
407
  }
375
408
  const baseExternalStoreConfiguration: BaseExternalStoreConfiguration = {
376
409
  getRelatedKeys: (key) => getRelatedKeys(this.toolkit, key),
@@ -404,13 +437,6 @@ export class Join<
404
437
  },
405
438
  [`join`, `content`],
406
439
  )
407
- const joinToken = {
408
- key: options.key,
409
- type: `join`,
410
- a: options.between[0],
411
- b: options.between[1],
412
- cardinality: options.cardinality,
413
- } as const satisfies JoinToken<ASide, BSide, Cardinality, Content>
414
440
  contentMolecules = createMoleculeFamily(store, {
415
441
  key: `${options.key}/content-molecules`,
416
442
  new: class ContentMolecule {
@@ -459,30 +485,35 @@ export class Join<
459
485
  externalStore =
460
486
  baseExternalStoreConfiguration as ExternalStoreConfiguration<Content>
461
487
  }
462
- const relations = new Junction<ASide, BSide, Content>(options, {
463
- externalStore,
464
- makeContentKey: (...args) => {
465
- const sorted = args.sort()
466
- const compositeKey = `${sorted[0]}:${sorted[1]}`
467
- const [m0, m1] = sorted.map((key) =>
468
- this.molecules.get(stringifyJson(key)),
469
- )
470
- if (store.config.lifespan === `immortal` && m0 && m1) {
471
- const target = newest(store)
472
- const moleculeToken = makeMoleculeInStore(
473
- target,
474
- [m0, m1],
475
- contentMolecules,
476
- compositeKey,
477
- )
478
- this.molecules.set(
479
- `"${compositeKey}"`,
480
- withdraw(moleculeToken, target),
488
+ const relations = new Junction<ASide, AType, BSide, BType, Content>(
489
+ options as any,
490
+ {
491
+ externalStore,
492
+ isAType: options.isAType,
493
+ isBType: options.isBType,
494
+ makeContentKey: (...args) => {
495
+ const sorted = args.sort()
496
+ const compositeKey = `${sorted[0]}:${sorted[1]}`
497
+ const [m0, m1] = sorted.map((key) =>
498
+ this.molecules.get(stringifyJson(key)),
481
499
  )
482
- }
483
- return compositeKey
500
+ if (store.config.lifespan === `immortal` && m0 && m1) {
501
+ const target = newest(store)
502
+ const moleculeToken = makeMoleculeInStore(
503
+ target,
504
+ [m0, m1],
505
+ contentMolecules,
506
+ compositeKey,
507
+ )
508
+ this.molecules.set(
509
+ `"${compositeKey}"`,
510
+ withdraw(moleculeToken, target),
511
+ )
512
+ }
513
+ return compositeKey
514
+ },
484
515
  },
485
- })
516
+ )
486
517
 
487
518
  const createSingleKeyStateFamily = () =>
488
519
  createReadonlySelectorFamily<string | null, string>(
@@ -530,7 +561,10 @@ export class Join<
530
561
  const relatedKeysState = this.retrieve(relatedKeysAtoms, key)
531
562
  const relatedKeys = get(relatedKeysState)
532
563
  for (const relatedKey of relatedKeys) {
533
- const contentKey = relations.makeContentKey(key, relatedKey)
564
+ const contentKey = relations.makeContentKey(
565
+ key as any,
566
+ relatedKey as any,
567
+ ) // sort XY to AB ❗
534
568
  const contentState = this.retrieve(contentAtoms, contentKey)
535
569
  const content = get(contentState)
536
570
  return [relatedKey, content]
@@ -552,7 +586,10 @@ export class Join<
552
586
  const jsonState = this.retrieve(jsonFamily, key)
553
587
  const json = get(jsonState)
554
588
  return json.members.map((relatedKey) => {
555
- const contentKey = relations.makeContentKey(key, relatedKey)
589
+ const contentKey = relations.makeContentKey(
590
+ key as any,
591
+ relatedKey as any,
592
+ ) // sort XY to AB ❗
556
593
  const contentState = this.retrieve(contentAtoms, contentKey)
557
594
  const content = get(contentState)
558
595
  return [relatedKey, content]
@@ -570,8 +607,15 @@ export class Join<
570
607
  const baseStates = {
571
608
  [stateKeyA]: findSingleRelatedKeyState,
572
609
  [stateKeyB]: findSingleRelatedKeyState,
573
- } as JoinStateFamilies<ASide, BSide, Cardinality, Content>
574
- let states: JoinStateFamilies<ASide, BSide, Cardinality, Content>
610
+ } as JoinStateFamilies<ASide, AType, BSide, BType, Cardinality, Content>
611
+ let states: JoinStateFamilies<
612
+ ASide,
613
+ AType,
614
+ BSide,
615
+ BType,
616
+ Cardinality,
617
+ Content
618
+ >
575
619
  if (defaultContent) {
576
620
  const findSingleRelatedEntryState = createSingleEntryStateFamily()
577
621
  const entriesStateKeyA = `${aSide}EntryOf${capitalize(bSide)}` as const
@@ -596,8 +640,15 @@ export class Join<
596
640
  const baseStates = {
597
641
  [stateKeyA]: findSingleRelatedKeyState,
598
642
  [stateKeyB]: findMultipleRelatedKeysState,
599
- } as JoinStateFamilies<ASide, BSide, Cardinality, Content>
600
- let states: JoinStateFamilies<ASide, BSide, Cardinality, Content>
643
+ } as JoinStateFamilies<ASide, AType, BSide, BType, Cardinality, Content>
644
+ let states: JoinStateFamilies<
645
+ ASide,
646
+ AType,
647
+ BSide,
648
+ BType,
649
+ Cardinality,
650
+ Content
651
+ >
601
652
  if (defaultContent) {
602
653
  const findSingleRelatedEntryState = createSingleEntryStateFamily()
603
654
  const findMultipleRelatedEntriesState = getMultipleEntryStateFamily()
@@ -624,8 +675,15 @@ export class Join<
624
675
  const baseStates = {
625
676
  [stateKeyA]: findMultipleRelatedKeysState,
626
677
  [stateKeyB]: findMultipleRelatedKeysState,
627
- } as JoinStateFamilies<ASide, BSide, Cardinality, Content>
628
- let states: JoinStateFamilies<ASide, BSide, Cardinality, Content>
678
+ } as JoinStateFamilies<ASide, AType, BSide, BType, Cardinality, Content>
679
+ let states: JoinStateFamilies<
680
+ ASide,
681
+ AType,
682
+ BSide,
683
+ BType,
684
+ Cardinality,
685
+ Content
686
+ >
629
687
  if (defaultContent) {
630
688
  const findMultipleRelatedEntriesState = getMultipleEntryStateFamily()
631
689
  const entriesStateKeyA = `${aSide}EntriesOf${capitalize(
@@ -651,7 +709,9 @@ export class Join<
651
709
 
652
710
  export type JoinToken<
653
711
  ASide extends string,
712
+ AType extends string,
654
713
  BSide extends string,
714
+ BType extends string,
655
715
  Cardinality extends `1:1` | `1:n` | `n:n`,
656
716
  Content extends Json.Object | null = null,
657
717
  > = {
@@ -660,41 +720,49 @@ export type JoinToken<
660
720
  cardinality: Cardinality
661
721
  a: ASide
662
722
  b: BSide
723
+ __aType?: AType
724
+ __bType?: BType
663
725
  __content?: Content
664
726
  }
665
727
 
666
728
  export function join<
667
729
  const ASide extends string,
730
+ const AType extends string,
668
731
  const BSide extends string,
732
+ const BType extends string,
669
733
  const Cardinality extends `1:1` | `1:n` | `n:n`,
670
734
  >(
671
- options: JoinOptions<ASide, BSide, Cardinality, null>,
735
+ options: JoinOptions<ASide, AType, BSide, BType, Cardinality, null>,
672
736
  defaultContent?: undefined,
673
737
  store?: Store,
674
- ): JoinToken<ASide, BSide, Cardinality, null>
738
+ ): JoinToken<ASide, AType, BSide, BType, Cardinality, null>
675
739
  export function join<
676
740
  const ASide extends string,
741
+ const AType extends string,
677
742
  const BSide extends string,
743
+ const BType extends string,
678
744
  const Cardinality extends `1:1` | `1:n` | `n:n`,
679
745
  const Content extends Json.Object,
680
746
  >(
681
- options: JoinOptions<ASide, BSide, Cardinality, Content>,
747
+ options: JoinOptions<ASide, AType, BSide, BType, Cardinality, Content>,
682
748
  defaultContent: Content,
683
749
  store?: Store,
684
- ): JoinToken<ASide, BSide, Cardinality, Content>
750
+ ): JoinToken<ASide, AType, BSide, BType, Cardinality, Content>
685
751
  export function join<
686
752
  ASide extends string,
753
+ AType extends string,
687
754
  BSide extends string,
755
+ BType extends string,
688
756
  Cardinality extends `1:1` | `1:n` | `n:n`,
689
757
  Content extends Json.Object,
690
758
  >(
691
- options: JoinOptions<ASide, BSide, Cardinality, Content>,
759
+ options: JoinOptions<ASide, AType, BSide, BType, Cardinality, Content>,
692
760
  defaultContent: Content | undefined,
693
761
  store: Store = IMPLICIT.STORE,
694
- ): JoinToken<ASide, BSide, Cardinality, Content> {
762
+ ): JoinToken<ASide, AType, BSide, BType, Cardinality, Content> {
695
763
  const joins = getJoinMap(store)
696
764
  joins.set(options.key, new Join(options, defaultContent, store))
697
- const token: JoinToken<ASide, BSide, Cardinality, Content> = {
765
+ const token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content> = {
698
766
  key: options.key,
699
767
  type: `join`,
700
768
  a: options.between[0],
@@ -705,24 +773,26 @@ export function join<
705
773
  }
706
774
 
707
775
  export function getJoinMap(
708
- store: Store & { joins?: Map<string, Join<any, any, any, any>> },
709
- ): Map<string, Join<any, any, any, any>> {
776
+ store: Store & { joins?: Map<string, Join<any, any, any, any, any, any>> },
777
+ ): Map<string, Join<any, any, any, any, any, any>> {
710
778
  if (`joins` in store && store.joins instanceof Map) {
711
779
  return store.joins
712
780
  }
713
- const joins = new Map<string, Join<any, any, any, any>>()
781
+ const joins = new Map<string, Join<any, any, any, any, any, any>>()
714
782
  store.joins = joins
715
783
  return joins
716
784
  }
717
785
  export function getJoin<
718
786
  ASide extends string,
787
+ AType extends string,
719
788
  BSide extends string,
789
+ BType extends string,
720
790
  Cardinality extends `1:1` | `1:n` | `n:n`,
721
791
  Content extends Json.Object | null,
722
792
  >(
723
- token: JoinToken<ASide, BSide, Cardinality, Content>,
793
+ token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
724
794
  store: Store,
725
- ): Join<ASide, BSide, Cardinality, Content> {
795
+ ): Join<ASide, AType, BSide, BType, Cardinality, Content> {
726
796
  const joinMap = getJoinMap(store)
727
797
  let myJoin = joinMap.get(token.key)
728
798
  if (myJoin === undefined) {
@@ -740,71 +810,99 @@ export function getJoin<
740
810
 
741
811
  export type JoinStates<
742
812
  ASide extends string,
813
+ AType extends string,
743
814
  BSide extends string,
815
+ BType extends string,
744
816
  Cardinality extends `1:1` | `1:n` | `n:n`,
745
817
  Content extends Json.Object | null,
746
818
  > = Cardinality extends `1:1`
747
819
  ? (Content extends Json.Object
748
820
  ? {
749
- readonly [AB in ASide | BSide as AB extends ASide
750
- ? `${AB}EntryOf${Capitalize<BSide>}`
751
- : `${AB}EntryOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
752
- [string, Content] | null
821
+ readonly [A in ASide as `${A}EntryOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
822
+ [AType, Content] | null,
823
+ BType
824
+ >
825
+ } & {
826
+ readonly [B in BSide as `${B}EntryOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
827
+ [BType, Content] | null,
828
+ AType
753
829
  >
754
830
  }
755
831
  : {}) & {
756
- readonly [AB in ASide | BSide as AB extends ASide
757
- ? `${AB}KeyOf${Capitalize<BSide>}`
758
- : `${AB}KeyOf${Capitalize<ASide>}`]: ReadonlySelectorToken<string | null>
832
+ readonly [A in ASide as `${A}KeyOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
833
+ AType | null,
834
+ BType
835
+ >
836
+ } & {
837
+ readonly [B in BSide as `${B}KeyOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
838
+ BType | null,
839
+ AType
840
+ >
759
841
  }
760
842
  : Cardinality extends `1:n`
761
843
  ? (Content extends Json.Object
762
844
  ? {
763
845
  readonly [A in ASide as `${A}EntryOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
764
- [string, Content] | null
846
+ [AType, Content] | null,
847
+ BType
765
848
  >
766
849
  } & {
767
850
  readonly [B in BSide as `${B}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
768
- [string, Content][]
851
+ [BType, Content][],
852
+ AType
769
853
  >
770
854
  }
771
855
  : {}) & {
772
856
  readonly [A in ASide as `${A}KeyOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
773
- string | null
857
+ AType | null,
858
+ BType
774
859
  >
775
860
  } & {
776
861
  readonly [B in BSide as `${B}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
777
- string[]
862
+ BType[],
863
+ AType
778
864
  >
779
865
  }
780
866
  : Cardinality extends `n:n`
781
867
  ? (Content extends Json.Object
782
868
  ? {
783
- readonly [AB in ASide | BSide as AB extends ASide
784
- ? `${AB}EntriesOf${Capitalize<BSide>}`
785
- : `${AB}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
786
- [string, Content][]
869
+ readonly [A in ASide as `${A}EntriesOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
870
+ [AType, Content][],
871
+ BType
872
+ >
873
+ } & {
874
+ readonly [B in BSide as `${B}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
875
+ [BType, Content][],
876
+ AType
787
877
  >
788
878
  }
789
879
  : {}) & {
790
- readonly [AB in ASide | BSide as AB extends ASide
791
- ? `${AB}KeysOf${Capitalize<BSide>}`
792
- : `${AB}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorToken<string[]>
880
+ readonly [A in ASide as `${A}KeysOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
881
+ AType[],
882
+ BType
883
+ >
884
+ } & {
885
+ readonly [B in BSide as `${B}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
886
+ BType[],
887
+ AType
888
+ >
793
889
  }
794
890
  : never
795
891
 
796
892
  export function findRelationsInStore<
797
893
  ASide extends string,
894
+ AType extends string,
798
895
  BSide extends string,
896
+ BType extends string,
799
897
  Cardinality extends `1:1` | `1:n` | `n:n`,
800
898
  Content extends Json.Object | null,
801
899
  >(
802
- token: JoinToken<ASide, BSide, Cardinality, Content>,
803
- key: string,
900
+ token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
901
+ key: AType | BType,
804
902
  store: Store,
805
- ): JoinStates<ASide, BSide, Cardinality, Content> {
903
+ ): JoinStates<ASide, AType, BSide, BType, Cardinality, Content> {
806
904
  const myJoin = getJoin(token, store)
807
- let relations: JoinStates<ASide, BSide, Cardinality, Content>
905
+ let relations: JoinStates<ASide, AType, BSide, BType, Cardinality, Content>
808
906
  switch (token.cardinality satisfies `1:1` | `1:n` | `n:n`) {
809
907
  case `1:1`: {
810
908
  const keyAB = `${token.a}KeyOf${capitalize(token.b)}`
@@ -820,7 +918,7 @@ export function findRelationsInStore<
820
918
  const state = myJoin.retrieve(familyBA, key)
821
919
  return state
822
920
  },
823
- } as JoinStates<ASide, BSide, Cardinality, Content>
921
+ } as JoinStates<ASide, AType, BSide, BType, Cardinality, Content>
824
922
  const entryAB = `${token.a}EntryOf${capitalize(token.b)}`
825
923
  if (entryAB in myJoin.states) {
826
924
  const entryBA = `${token.b}EntryOf${capitalize(token.a)}`
@@ -853,7 +951,7 @@ export function findRelationsInStore<
853
951
  const state = myJoin.retrieve(familyBA, key)
854
952
  return state
855
953
  },
856
- } as JoinStates<ASide, BSide, Cardinality, Content>
954
+ } as JoinStates<ASide, AType, BSide, BType, Cardinality, Content>
857
955
  const entryAB = `${token.a}EntryOf${capitalize(token.b)}`
858
956
  if (entryAB in myJoin.states) {
859
957
  const entriesBA = `${token.b}EntriesOf${capitalize(token.a)}`
@@ -886,7 +984,7 @@ export function findRelationsInStore<
886
984
  const state = myJoin.retrieve(familyBA, key)
887
985
  return state
888
986
  },
889
- } as JoinStates<ASide, BSide, Cardinality, Content>
987
+ } as JoinStates<ASide, AType, BSide, BType, Cardinality, Content>
890
988
  const entriesAB = `${token.a}EntriesOf${capitalize(token.b)}`
891
989
  if (entriesAB in myJoin.states) {
892
990
  const entriesBA = `${token.b}EntriesOf${capitalize(token.a)}`
@@ -910,24 +1008,28 @@ export function findRelationsInStore<
910
1008
 
911
1009
  export function findRelations<
912
1010
  ASide extends string,
1011
+ AType extends string,
913
1012
  BSide extends string,
1013
+ BType extends string,
914
1014
  Cardinality extends `1:1` | `1:n` | `n:n`,
915
1015
  Content extends Json.Object | null,
916
1016
  >(
917
- token: JoinToken<ASide, BSide, Cardinality, Content>,
918
- key: string,
919
- ): JoinStates<ASide, BSide, Cardinality, Content> {
1017
+ token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
1018
+ key: AType | BType,
1019
+ ): JoinStates<ASide, AType, BSide, BType, Cardinality, Content> {
920
1020
  return findRelationsInStore(token, key, IMPLICIT.STORE)
921
1021
  }
922
1022
 
923
1023
  export function editRelationsInStore<
924
1024
  ASide extends string,
1025
+ AType extends string,
925
1026
  BSide extends string,
1027
+ BType extends string,
926
1028
  Cardinality extends `1:1` | `1:n` | `n:n`,
927
1029
  Content extends Json.Object | null,
928
1030
  >(
929
- token: JoinToken<ASide, BSide, Cardinality, Content>,
930
- change: (relations: Junction<ASide, BSide, Content>) => void,
1031
+ token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
1032
+ change: (relations: Junction<ASide, AType, BSide, BType, Content>) => void,
931
1033
  store: Store,
932
1034
  ): void {
933
1035
  const myJoin = getJoin(token, store)
@@ -944,18 +1046,20 @@ export function editRelationsInStore<
944
1046
 
945
1047
  export function editRelations<
946
1048
  ASide extends string,
1049
+ AType extends string,
947
1050
  BSide extends string,
1051
+ BType extends string,
948
1052
  Cardinality extends `1:1` | `1:n` | `n:n`,
949
1053
  Content extends Json.Object | null,
950
1054
  >(
951
- token: JoinToken<ASide, BSide, Cardinality, Content>,
952
- change: (relations: Junction<ASide, BSide, Content>) => void,
1055
+ token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
1056
+ change: (relations: Junction<ASide, AType, BSide, BType, Content>) => void,
953
1057
  ): void {
954
1058
  editRelationsInStore(token, change, IMPLICIT.STORE)
955
1059
  }
956
1060
 
957
1061
  export function getInternalRelationsFromStore(
958
- token: JoinToken<any, any, any, any>,
1062
+ token: JoinToken<any, any, any, any, any, any>,
959
1063
  store: Store,
960
1064
  ): MutableAtomFamilyToken<SetRTX<string>, SetRTXJson<string>, string> {
961
1065
  const myJoin = getJoin(token, store)
@@ -965,11 +1069,13 @@ export function getInternalRelationsFromStore(
965
1069
 
966
1070
  export function getInternalRelations<
967
1071
  ASide extends string,
1072
+ AType extends string,
968
1073
  BSide extends string,
1074
+ BType extends string,
969
1075
  Cardinality extends `1:1` | `1:n` | `n:n`,
970
1076
  Content extends Json.Object | null,
971
1077
  >(
972
- token: JoinToken<ASide, BSide, Cardinality, Content>,
1078
+ token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
973
1079
  ): MutableAtomFamilyToken<SetRTX<string>, SetRTXJson<string>, string> {
974
1080
  return getInternalRelationsFromStore(token, IMPLICIT.STORE)
975
1081
  }