@ibgib/core-gib 0.1.57 → 0.1.59

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 (162) hide show
  1. package/dist/keystone/keystone-config-builder.d.mts +12 -1
  2. package/dist/keystone/keystone-config-builder.d.mts.map +1 -1
  3. package/dist/keystone/keystone-config-builder.mjs +58 -4
  4. package/dist/keystone/keystone-config-builder.mjs.map +1 -1
  5. package/dist/keystone/keystone-constants.d.mts +40 -5
  6. package/dist/keystone/keystone-constants.d.mts.map +1 -1
  7. package/dist/keystone/keystone-constants.mjs +39 -5
  8. package/dist/keystone/keystone-constants.mjs.map +1 -1
  9. package/dist/keystone/keystone-helpers.d.mts +11 -1
  10. package/dist/keystone/keystone-helpers.d.mts.map +1 -1
  11. package/dist/keystone/keystone-helpers.mjs +37 -1
  12. package/dist/keystone/keystone-helpers.mjs.map +1 -1
  13. package/dist/keystone/keystone-policy-types.d.mts +23 -0
  14. package/dist/keystone/keystone-policy-types.d.mts.map +1 -0
  15. package/dist/keystone/keystone-policy-types.mjs +2 -0
  16. package/dist/keystone/keystone-policy-types.mjs.map +1 -0
  17. package/dist/sync/graft-info/graft-info-helpers.respec.mjs +8 -8
  18. package/dist/sync/graft-info/graft-info-helpers.respec.mjs.map +1 -1
  19. package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs +22 -22
  20. package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs.map +1 -1
  21. package/dist/sync/sync-conflict-basic-divergence.respec.mjs +3 -3
  22. package/dist/sync/sync-conflict-basic-divergence.respec.mjs.map +1 -1
  23. package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs +6 -6
  24. package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs.map +1 -1
  25. package/dist/sync/sync-conflict-text-merge.respec.mjs +26 -26
  26. package/dist/sync/sync-conflict-text-merge.respec.mjs.map +1 -1
  27. package/dist/sync/sync-helpers.d.mts +19 -0
  28. package/dist/sync/sync-helpers.d.mts.map +1 -1
  29. package/dist/sync/sync-helpers.mjs +51 -1
  30. package/dist/sync/sync-helpers.mjs.map +1 -1
  31. package/dist/sync/sync-innerspace-constants.respec.mjs +2 -2
  32. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  33. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +2 -2
  34. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  35. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +4 -4
  36. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
  37. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +2 -2
  38. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
  39. package/dist/sync/sync-innerspace-partial-update.respec.mjs +3 -3
  40. package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
  41. package/dist/sync/sync-innerspace.respec.mjs +4 -4
  42. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  43. package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.d.mts +5 -0
  44. package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.d.mts.map +1 -1
  45. package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mjs +24 -2
  46. package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mjs.map +1 -1
  47. package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.d.mts +5 -0
  48. package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.d.mts.map +1 -1
  49. package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.mjs +21 -3
  50. package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.mjs.map +1 -1
  51. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.d.mts +1 -1
  52. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +13 -1
  53. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
  54. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +40 -10
  55. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
  56. package/dist/sync/sync-peer/sync-peer-types.d.mts +81 -1
  57. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
  58. package/dist/sync/sync-peer/sync-peer-v1.d.mts +37 -3
  59. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  60. package/dist/sync/sync-peer/sync-peer-v1.mjs +163 -23
  61. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  62. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-constants.d.mts +46 -0
  63. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-constants.d.mts.map +1 -0
  64. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-constants.mjs +45 -0
  65. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-constants.mjs.map +1 -0
  66. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.d.mts +30 -0
  67. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.d.mts.map +1 -0
  68. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.mjs +2 -0
  69. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.mjs.map +1 -0
  70. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.d.mts +68 -0
  71. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.d.mts.map +1 -0
  72. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs +324 -0
  73. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs.map +1 -0
  74. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts +85 -0
  75. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts.map +1 -0
  76. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs +332 -0
  77. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs.map +1 -0
  78. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-types.d.mts +29 -0
  79. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-types.d.mts.map +1 -0
  80. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-types.mjs +2 -0
  81. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-types.mjs.map +1 -0
  82. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.d.mts +44 -0
  83. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.d.mts.map +1 -0
  84. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs +303 -0
  85. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs.map +1 -0
  86. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +22 -5
  87. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  88. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +223 -27
  89. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  90. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +9 -0
  91. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
  92. package/dist/sync/sync-saga-coordinator.d.mts +41 -2
  93. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  94. package/dist/sync/sync-saga-coordinator.mjs +110 -11
  95. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  96. package/dist/sync/sync-types.d.mts +24 -0
  97. package/dist/sync/sync-types.d.mts.map +1 -1
  98. package/dist/sync/sync-types.mjs +0 -1
  99. package/dist/sync/sync-types.mjs.map +1 -1
  100. package/dist/sync/sync-withid.connect.respec.d.mts +12 -0
  101. package/dist/sync/sync-withid.connect.respec.d.mts.map +1 -0
  102. package/dist/sync/sync-withid.connect.respec.mjs +205 -0
  103. package/dist/sync/sync-withid.connect.respec.mjs.map +1 -0
  104. package/dist/sync/sync-withid.establish.respec.d.mts +19 -0
  105. package/dist/sync/sync-withid.establish.respec.d.mts.map +1 -0
  106. package/dist/sync/sync-withid.establish.respec.mjs +322 -0
  107. package/dist/sync/sync-withid.establish.respec.mjs.map +1 -0
  108. package/dist/sync/sync-withid.pingpong.respec.d.mts +11 -0
  109. package/dist/sync/sync-withid.pingpong.respec.d.mts.map +1 -0
  110. package/dist/sync/sync-withid.pingpong.respec.mjs +131 -0
  111. package/dist/sync/sync-withid.pingpong.respec.mjs.map +1 -0
  112. package/dist/witness/space/inner-space/inner-space-v1.d.mts.map +1 -1
  113. package/dist/witness/space/inner-space/inner-space-v1.mjs +1 -1
  114. package/dist/witness/space/inner-space/inner-space-v1.mjs.map +1 -1
  115. package/package.json +4 -4
  116. package/src/keystone/keystone-config-builder.mts +73 -4
  117. package/src/keystone/keystone-constants.mts +42 -6
  118. package/src/keystone/keystone-helpers.mts +44 -2
  119. package/src/keystone/keystone-policy-types.mts +25 -0
  120. package/src/keystone/keystone-policy.schema.json +51 -0
  121. package/src/keystone/keystone-service-v1.mts +3 -3
  122. package/src/sync/docs/architecture.md +20 -0
  123. package/src/sync/docs/ping_pong_plan.md +147 -0
  124. package/src/sync/docs/security.md +207 -3
  125. package/src/sync/graft-info/graft-info-helpers.respec.mts +7 -7
  126. package/src/sync/sync-conflict-adv-multitimelines.respec.mts +21 -21
  127. package/src/sync/sync-conflict-basic-divergence.respec.mts +2 -2
  128. package/src/sync/sync-conflict-basic-multitimelines.respec.mts +5 -5
  129. package/src/sync/sync-conflict-text-merge.respec.mts +25 -25
  130. package/src/sync/sync-helpers.mts +51 -1
  131. package/src/sync/sync-innerspace-constants.respec.mts +1 -1
  132. package/src/sync/sync-innerspace-deep-updates.respec.mts +1 -1
  133. package/src/sync/sync-innerspace-dest-ahead.respec.mts +3 -3
  134. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +1 -1
  135. package/src/sync/sync-innerspace-partial-update.respec.mts +2 -2
  136. package/src/sync/sync-innerspace.respec.mts +3 -3
  137. package/src/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mts +26 -2
  138. package/src/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.mts +23 -3
  139. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.mts +1 -1
  140. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +47 -13
  141. package/src/sync/sync-peer/sync-peer-types.mts +87 -1
  142. package/src/sync/sync-peer/sync-peer-v1.mts +171 -32
  143. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-constants.mts +68 -0
  144. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.mts +36 -0
  145. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mts +385 -0
  146. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mts +388 -0
  147. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-types.mts +35 -0
  148. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mts +345 -0
  149. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +223 -34
  150. package/src/sync/sync-saga-context/sync-saga-context-types.mts +9 -0
  151. package/src/sync/sync-saga-coordinator.mts +162 -6
  152. package/src/sync/sync-types.mts +28 -4
  153. package/src/sync/sync-withid.connect.respec.mts +243 -0
  154. package/src/sync/sync-withid.establish.respec.mts +361 -0
  155. package/src/sync/sync-withid.pingpong.respec.mts +161 -0
  156. package/src/sync/unused-identity-backup.mts.md +1 -1
  157. package/src/witness/space/inner-space/inner-space-v1.mts +4 -5
  158. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts +0 -2
  159. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts.map +0 -1
  160. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs +0 -310
  161. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs.map +0 -1
  162. package/src/sync/sync-innerspace-dest-ahead-withid.respec.mts +0 -364
@@ -3,12 +3,14 @@
3
3
  */
4
4
 
5
5
  import { IbGibData_V1, IbGibRel8ns_V1, IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
6
+ import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
6
7
 
7
8
  import { SubjectWitness } from '../../common/pubsub/subject/subject-types.mjs';
8
9
  import { SyncSagaContextData_V1, SyncSagaContextIbGib_V1, SyncSagaContextRel8ns_V1 } from '../sync-saga-context/sync-saga-context-types.mjs';
9
10
  import { Witness_V1 } from '../../witness/witness-types.mjs';
10
11
  import { IbGibSpaceAny } from '../../witness/space/space-base-v1.mjs';
11
12
  import { MetaspaceService } from '../../witness/space/metaspace/metaspace-types.mjs';
13
+ import { KeystoneIbGib_V1, KeystonePoolConfig } from '../../keystone/keystone-types.mjs';
12
14
 
13
15
  /**
14
16
  * Data for the SyncPeer witness.
@@ -36,13 +38,29 @@ export interface SyncPeerIbGib_V1 extends IbGib_V1<SyncPeerData_V1, SyncPeerRel8
36
38
  * opts used in `connect(opts)`
37
39
  */
38
40
  export interface ConnectSyncPeerOpts {
41
+ /**
42
+ * TODO: sagaId is now also on {@link InitializeSyncPeerOpts} since a peer
43
+ * is scoped to a single sync saga. Evaluate whether this duplicate is still
44
+ * needed when implementing the connect phase (Phase 2).
45
+ */
39
46
  sagaId: string;
40
47
  }
41
48
 
42
49
  /**
43
- * base initialization opts
50
+ * base initialization opts.
51
+ *
52
+ * A sync peer is scoped to exactly one sync saga. A new peer instance must be
53
+ * created for each `sync(...)` call. Reusing a peer across multiple sagas is
54
+ * not supported and would compromise the identity security model.
44
55
  */
45
56
  export interface InitializeSyncPeerOpts {
57
+ /**
58
+ * Unique id for the sync saga this peer is servicing.
59
+ * Generated by `SyncSagaCoordinator.sync()` and passed here so that
60
+ * `establishSessionIdentity` can derive the session secret via
61
+ * `KDF(senderSecret, sagaId)`.
62
+ */
63
+ sagaId?: string;
46
64
  /**
47
65
  * reference to the local metaspace
48
66
  */
@@ -62,6 +80,44 @@ export interface InitializeSyncPeerOpts {
62
80
  * received/created throughout the transaction until commit.
63
81
  */
64
82
  localTempSpace?: IbGibSpaceAny;
83
+ /**
84
+ * The sender's long-lived Domain Keystone (I) — Alice's identity.
85
+ * Optional; if omitted the sync runs without identity (anonymous).
86
+ * Must be the current tip frame of I's timeline.
87
+ *
88
+ * Both {@link senderIdentity} and {@link fnSenderSecret} must be provided
89
+ * together or omitted together.
90
+ */
91
+ senderIdentity?: KeystoneIbGib_V1;
92
+ /**
93
+ * Returns the plaintext secret corresponding to {@link senderIdentity}.
94
+ * Wrapped in a function to avoid holding the secret in memory longer than needed.
95
+ *
96
+ * Both {@link senderIdentity} and {@link fnSenderSecret} must be provided
97
+ * together or omitted together.
98
+ */
99
+ fnSenderSecret?: () => Promise<string>;
100
+ /**
101
+ * Pool config for the session keystone's transport connect handshake pool.
102
+ * Required when {@link senderIdentity} is provided.
103
+ *
104
+ * @see {@link POOL_ID_CONNECT}
105
+ */
106
+ sessionConnectPoolConfig?: KeystonePoolConfig;
107
+ /**
108
+ * Pool config for the session keystone's per-turn signing pool (`sync`).
109
+ * Required when {@link senderIdentity} is provided.
110
+ *
111
+ * @see {@link POOL_ID_SYNC}
112
+ */
113
+ sessionSyncPoolConfig?: KeystonePoolConfig;
114
+ /**
115
+ * Addresses of the synced domains (ibgibs).
116
+ * Used during `establishSessionIdentity` to bind the session keystone (S)
117
+ * strictly to these domains, preventing S from acting as a "blank check"
118
+ * for unauthorized domains.
119
+ */
120
+ targetAddrs?: string[];
65
121
  }
66
122
 
67
123
  /**
@@ -107,6 +163,26 @@ export interface SyncPeerWitness<TInitializeOpts extends InitializeSyncPeerOpts
107
163
  */
108
164
  payloadIbGibsDomainReceived$: SubjectWitness<IbGib_V1>;
109
165
 
166
+ currentSessionIdentity: KeystoneIbGib_V1 | undefined;
167
+ /**
168
+ * convenience getter for {@link currentSessionIdentity}
169
+ */
170
+ get currentSessionIdentityAddr(): IbGibAddr | undefined;
171
+
172
+ /**
173
+ * Pre-connect phase: creates the session keystone (S) locally, evolves
174
+ * `senderIdentity` (I → I1) with a `sync` claim targeting S, and posts
175
+ * both to the receiver's domain registry.
176
+ *
177
+ * Must be called before `connect()`. No-op if `senderIdentity` was not
178
+ * provided in {@link InitializeSyncPeerOpts}.
179
+ *
180
+ * @returns The session keystone genesis (S^Stjp). The coordinator holds
181
+ * this reference for the remainder of the saga. The name `newSenderIdentity`
182
+ * (I1) is intentionally scoped only within this method to avoid confusion.
183
+ */
184
+ establishSessionIdentity(): Promise<void>;
185
+
110
186
  /**
111
187
  * Establishes the connection context.
112
188
  *
@@ -115,4 +191,14 @@ export interface SyncPeerWitness<TInitializeOpts extends InitializeSyncPeerOpts
115
191
  * @param opts Connection options, including the sagaId for the upcoming sync saga.
116
192
  */
117
193
  connect(opts?: { sagaId?: string }): Promise<void>;
194
+
195
+ // /**
196
+ // * Returns the sender's long-lived primary/domain identity.
197
+ // */
198
+ // getSenderIdentity(): KeystoneIbGib_V1 | undefined;
199
+
200
+ /**
201
+ * Evolves the session identity (S_n -> S_n+1) and signs targeting contextAddr.
202
+ */
203
+ signContext(opts: { contextAddr: IbGibAddr }): Promise<KeystoneIbGib_V1 | undefined>;
118
204
  }
@@ -7,11 +7,8 @@
7
7
  import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
8
8
  import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
9
9
  import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
10
- import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
11
- import { validateIbGibIntrinsically } from '@ibgib/ts-gib/dist/V1/validate-helper.mjs';
12
10
 
13
11
  import { GLOBAL_LOG_A_LOT } from '../../core-constants.mjs';
14
- import { SYNC_MSG_REL8N_NAME, SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN } from '../sync-constants.mjs';
15
12
  import { SubjectWitness } from '../../common/pubsub/subject/subject-types.mjs';
16
13
  import { SyncSagaContextIbGib_V1 } from '../sync-saga-context/sync-saga-context-types.mjs';
17
14
  import {
@@ -19,16 +16,18 @@ import {
19
16
  SyncPeerRel8ns_V1, SyncPeerWitness
20
17
  } from './sync-peer-types.mjs';
21
18
  import { LightWitnessBase_V1 } from '../../witness/light-witness-base-v1.mjs';
22
- import { IbGibSpaceAny } from '../../witness/space/space-base-v1.mjs';
23
19
  import { newupSubject } from '../../common/pubsub/subject/subject-helper.mjs';
24
- import { authenticateContext, authorizeContext, validateContextAndSagaFrame } from '../sync-saga-context/sync-saga-context-helpers.mjs';
20
+ import { authenticateContextIntrinsically, validateContextAndSagaFrame } from '../sync-saga-context/sync-saga-context-helpers.mjs';
25
21
  import { getFromSpace } from '../../witness/space/space-helper.mjs';
26
- import { getFullSyncSagaHistory } from '../sync-helpers.mjs';
27
- import { SyncSagaFrameDependencyGraph } from '../sync-types.mjs';
22
+ import { getFullSyncSagaHistory, deriveSessionSecret } from '../sync-helpers.mjs';
23
+ import { SessionGenesisFrameDetails, SyncSagaFrameDependencyGraph } from '../sync-types.mjs';
24
+ import { KeystoneService_V1 } from '../../keystone/keystone-service-v1.mjs';
25
+ import { KeystoneIbGib_V1 } from '../../keystone/keystone-types.mjs';
26
+ import { KEYSTONE_VERB_SYNC, } from '../../keystone/keystone-constants.mjs';
27
+ import { getTjpAddr } from '../../common/other/ibgib-helper.mjs';
28
+ import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
28
29
 
29
30
  const logalot = GLOBAL_LOG_A_LOT;
30
- const logalotControlDomain = false;
31
- const lcControlDomain = '[ControlDomain]';
32
31
 
33
32
 
34
33
  /**
@@ -51,6 +50,54 @@ export abstract class SyncPeer_V1<
51
50
 
52
51
  public opts: TInitializeOpts | undefined;
53
52
  public payloadIbGibsDomainReceived$!: SubjectWitness<IbGib_V1>;
53
+ public currentSessionIdentity: KeystoneIbGib_V1 | undefined;
54
+ public get currentSessionIdentityAddr(): IbGibAddr | undefined {
55
+ return this.currentSessionIdentity ?
56
+ getIbGibAddr({ ibGib: this.currentSessionIdentity }) :
57
+ undefined;
58
+ }
59
+
60
+ // public getSenderIdentity(): KeystoneIbGib_V1 | undefined {
61
+ // return this.opts?.senderIdentity;
62
+ // }
63
+
64
+ public async signContext({
65
+ contextAddr,
66
+ }: {
67
+ contextAddr: IbGibAddr;
68
+ }): Promise<KeystoneIbGib_V1 | undefined> {
69
+ const lc = `${this.lc}[${this.signContext.name}]`;
70
+ try {
71
+ if (!this.currentSessionIdentity) {
72
+ return undefined;
73
+ }
74
+ if (!this.opts) { throw new Error(`opts not initialized. (E: bcf5978aed789b0ebcbdc51971ebe826)`); }
75
+ const { fnSenderSecret, sagaId, localMetaspace, localSpace } = this.opts;
76
+ if (!fnSenderSecret) { throw new Error(`fnSenderSecret not initialized. (E: 207fd292a2e8c53c05fd0a74a4ae6d26)`); }
77
+ if (!sagaId) { throw new Error(`sagaId not initialized. (E: f2e35cc13ed873b638116188119d1826)`); }
78
+
79
+ const senderSecret = await fnSenderSecret();
80
+ const sessionSecret = await deriveSessionSecret({ senderSecret, sagaId });
81
+
82
+ const keystoneSvc = new KeystoneService_V1();
83
+ const evolved = await keystoneSvc.sign({
84
+ latestKeystone: this.currentSessionIdentity,
85
+ masterSecret: sessionSecret,
86
+ claim: {
87
+ verb: KEYSTONE_VERB_SYNC,
88
+ target: contextAddr,
89
+ },
90
+ metaspace: localMetaspace,
91
+ space: localSpace,
92
+ });
93
+
94
+ this.currentSessionIdentity = evolved;
95
+ return evolved;
96
+ } catch (error) {
97
+ console.error(`${lc} ${extractErrorMsg(error)}`);
98
+ throw error;
99
+ }
100
+ }
54
101
 
55
102
  get classname(): string {
56
103
  if (!this.data) { throw new Error(`(UNEXPECTED) this.data falsy? (E: 1ab1841e9338b54f3aa615fa37024826)`); }
@@ -107,6 +154,108 @@ export abstract class SyncPeer_V1<
107
154
  */
108
155
  protected abstract connectImpl(opts: TConnectOpts): Promise<void>;
109
156
 
157
+ /**
158
+ * Pre-connect phase: establishes session identity.
159
+ *
160
+ * Shared base implementation:
161
+ * 1. Derives `sessionSecret = KDF(senderSecret, sagaId)`.
162
+ * 2. Creates session keystone genesis S (connect + sync pools) in `localSpace`.
163
+ * 3. Evolves `senderIdentity` → `newSenderIdentity` (I1) with a `sync`
164
+ * claim targeting S^Stjp, stored in `localSpace`.
165
+ * 4. Delegates posting of both keystones to the receiver via the abstract
166
+ * hook {@link postEstablishToReceiver} (peer-specific transport).
167
+ *
168
+ * Returns `undefined` (no-op) if no `senderIdentity` was provided in opts.
169
+ *
170
+ * @returns The session keystone genesis (S^Stjp) so the coordinator can
171
+ * hold a reference for subsequent per-turn signing. The name
172
+ * `newSenderIdentity` (I1) is scoped only within this method.
173
+ */
174
+ public async establishSessionIdentity(): Promise<void> {
175
+ const lc = `${this.lc}[${this.establishSessionIdentity.name}]`;
176
+ try {
177
+ if (logalot) { console.log(`${lc} starting... (I: f2a1b3c4d5e6f7a8b9c0d1e2f3a4b526)`); }
178
+
179
+ if (!this.opts) { throw new Error(`(UNEXPECTED) this.opts falsy? Call initializeOpts first. (E: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c526)`); }
180
+
181
+ const { senderIdentity, fnSenderSecret, sagaId, localMetaspace, localSpace } = this.opts;
182
+
183
+ // No identity provided — anonymous sync, nothing to establish.
184
+ if (!senderIdentity || !fnSenderSecret) {
185
+ if (logalot) { console.log(`${lc} no senderIdentity/fnSenderSecret — skipping establish (I: f29348a77d1542326d14043ea4b69126)`); }
186
+ return undefined;
187
+ }
188
+ const senderIdentityAddr = getIbGibAddr({ ibGib: senderIdentity });
189
+ const senderIdentityTjpAddr = getTjpAddr({ ibGib: senderIdentity });
190
+ if (!senderIdentityTjpAddr) { throw new Error(`(UNEXPECTED) senderIdentityTjpAddr falsy? (E: d5d8c3ab25a83a2c127904fe96de1526)`); }
191
+
192
+ if (!sagaId) { throw new Error(`(UNEXPECTED) sagaId falsy? Must be set in initializeOpts before calling establishSessionIdentity. (E: c6ba389d51b8af07d82458f875cf9826)`); }
193
+
194
+ const senderSecret = await fnSenderSecret();
195
+ if (!senderSecret) { throw new Error(`senderSecret falsy. senderSecret required. (E: 1a8b0298bf78cbdf284b7988983b9826)`); }
196
+ const sessionSecret = await deriveSessionSecret({ senderSecret, sagaId });
197
+
198
+ const keystoneSvc = new KeystoneService_V1();
199
+
200
+ // Step 1: Create S genesis in localSpace.
201
+ // Pool configs must be provided via opts (set by coordinator before calling establish).
202
+ if (!this.opts.sessionConnectPoolConfig) { throw new Error(`(UNEXPECTED) opts.sessionConnectPoolConfig falsy? (E: 3351fd566eb8bbd2f821bb08c4419826)`); }
203
+ if (!this.opts.sessionSyncPoolConfig) { throw new Error(`(UNEXPECTED) opts.sessionSyncPoolConfig falsy? (E: dbffa810d9e7ff6079088deb5b8e7826)`); }
204
+
205
+ // session genesis keystone should have soft links to both
206
+ // targetAddrs and the sender identity that spawned it.
207
+ const frameDetails: SessionGenesisFrameDetails = {
208
+ senderIdentityAddr,
209
+ senderIdentityTjpAddr,
210
+ }
211
+ if (this.opts.targetAddrs) {
212
+ frameDetails.targetAddrs = this.opts.targetAddrs
213
+ }
214
+ const sessionIdentity = await keystoneSvc.genesis({
215
+ masterSecret: sessionSecret,
216
+ configs: [this.opts.sessionConnectPoolConfig, this.opts.sessionSyncPoolConfig],
217
+ frameDetails,
218
+ metaspace: localMetaspace,
219
+ space: localSpace,
220
+ });
221
+ const sessionIdentityAddr = getIbGibAddr({ ibGib: sessionIdentity });
222
+
223
+ // Step 2: Evolve senderIdentity → newSenderIdentity (I1) with sync claim.
224
+ const newSenderIdentity = await keystoneSvc.sign({
225
+ latestKeystone: senderIdentity,
226
+ masterSecret: senderSecret,
227
+ claim: {
228
+ verb: KEYSTONE_VERB_SYNC,
229
+ target: sessionIdentityAddr,
230
+ },
231
+ metaspace: localMetaspace,
232
+ space: localSpace,
233
+ });
234
+
235
+ // Step 3: Post both to the receiver (peer-specific).
236
+ await this.postEstablishToReceiver({ newSenderIdentity, sessionIdentity });
237
+
238
+ this.currentSessionIdentity = sessionIdentity;
239
+ } catch (error) {
240
+ console.error(`${lc} ${extractErrorMsg(error)}`);
241
+ throw error;
242
+ } finally {
243
+ if (logalot) { console.log(`${lc} complete.`); }
244
+ }
245
+ }
246
+
247
+ /**
248
+ * Peer-specific hook: transmits `newSenderIdentity` (I1) and
249
+ * `sessionIdentity` (S) to the receiver's domain registry.
250
+ *
251
+ * - **Innerspace**: puts both into `receiverMetaspace` / `receiverSpace`.
252
+ * - **WebSocket**: HTTP POST to the domain provider's keystone endpoint.
253
+ */
254
+ protected abstract postEstablishToReceiver(opts: {
255
+ newSenderIdentity: KeystoneIbGib_V1;
256
+ sessionIdentity: KeystoneIbGib_V1;
257
+ }): Promise<void>;
258
+
110
259
  /**
111
260
  * base implementation just sets the opts property.
112
261
  *
@@ -164,16 +313,12 @@ export abstract class SyncPeer_V1<
164
313
  // }
165
314
  // }
166
315
 
167
-
168
-
169
- protected async authenticateValidateAuthorize({
316
+ protected async authenticateAndValidate({
170
317
  context,
171
- fullSagaHistory,
172
318
  }: {
173
319
  context: SyncSagaContextIbGib_V1,
174
- fullSagaHistory: SyncSagaFrameDependencyGraph[],
175
320
  }): Promise<void> {
176
- const lc = `${this.lc}[${this.authenticateValidateAuthorize.name}]`;
321
+ const lc = `${this.lc}[${this.authenticateAndValidate.name}]`;
177
322
  try {
178
323
  if (logalot) { console.log(`${lc} starting... (I: add238055cd84a222c5b8c89913af526)`); }
179
324
 
@@ -181,7 +326,8 @@ export abstract class SyncPeer_V1<
181
326
  const { localSpace } = this.opts;
182
327
 
183
328
  // first authenticate, because invalid authn is a non-starter
184
- const authenticationErrors = await authenticateContext({
329
+ // (already validated intrinsically)
330
+ const authenticationErrors = await authenticateContextIntrinsically({
185
331
  context,
186
332
  space: localSpace,
187
333
  });
@@ -195,12 +341,6 @@ export abstract class SyncPeer_V1<
195
341
  if (validationErrors.length > 0) {
196
342
  throw new Error(`invalid context received. validationErrors: ${validationErrors} (E: 8b34c875c968af29bc433138e57a7826)`);
197
343
  }
198
- // we have a valid authentication that points to a valid context,
199
- // but what exactly is authorized ?
200
- const authorizationErrors = await authorizeContext({ context, fullSagaHistory });
201
- if (authorizationErrors.length > 0) {
202
- throw new Error(`invalid context authorization. authorizationErrors: ${authorizationErrors} (E: 8ddc284a758cf10ba829334c1babb826)`);
203
- }
204
344
  } catch (error) {
205
345
  console.error(`${lc} ${extractErrorMsg(error)}`);
206
346
  throw error;
@@ -268,14 +408,12 @@ export abstract class SyncPeer_V1<
268
408
  // this is not just happening on the client, but this peer may be
269
409
  // the one receiving the context as well.
270
410
 
271
- const sagaHistory_beforeSend = await getFullSyncSagaHistory({
272
- sagaIbGib: context.sagaFrame,
273
- space: this.opts.localSpace
274
- });
411
+ // const sagaHistory_beforeSend = await getFullSyncSagaHistory({
412
+ // sagaIbGib: context.sagaFrame,
413
+ // space: this.opts.localSpace
414
+ // });
275
415
 
276
- await this.authenticateValidateAuthorize({
277
- context, fullSagaHistory: sagaHistory_beforeSend,
278
- });
416
+ await this.authenticateAndValidate({ context });
279
417
 
280
418
  // at this point, we have a valid, authenticated, authorized context
281
419
 
@@ -296,9 +434,10 @@ export abstract class SyncPeer_V1<
296
434
  space: this.opts.localSpace
297
435
  });
298
436
 
299
- await this.authenticateValidateAuthorize({
300
- context, fullSagaHistory: sagaHistory_afterSend,
301
- });
437
+ // NOTE: I think this is the wrong place for this, as we must do this in the peer **before** storing any control ibgibs. This needs to be done in the continueSync I _think_ (not sure yet)
438
+ // await this.authenticateValidateAuthorize({
439
+ // context, fullSagaHistory: sagaHistory_afterSend,
440
+ // });
302
441
 
303
442
  return response;
304
443
  } else {
@@ -0,0 +1,68 @@
1
+ // #region SyncWebSocketMsgType enum
2
+
3
+ export const SYNC_WEB_SOCKET_MSG_TYPE_AUTH_CHALLENGE_INIT = 'auth-challenge-init';
4
+ export const SYNC_WEB_SOCKET_MSG_TYPE_AUTH_INIT = 'auth-init';
5
+ export const SYNC_WEB_SOCKET_MSG_TYPE_AUTH_CHALLENGE = 'auth-challenge';
6
+ export const SYNC_WEB_SOCKET_MSG_TYPE_AUTH_PROOF = 'auth-proof';
7
+ export const SYNC_WEB_SOCKET_MSG_TYPE_AUTH_OK = 'auth-ok';
8
+ export const SYNC_WEB_SOCKET_MSG_TYPE_AUTH_FAIL = 'auth-fail';
9
+ export const SYNC_WEB_SOCKET_MSG_TYPE_SYNC_FRAME = 'sync-frame';
10
+ export const SYNC_WEB_SOCKET_MSG_TYPE_SYNC_FRAME_RESPONSE = 'sync-frame-response';
11
+ export const SYNC_WEB_SOCKET_MSG_TYPE_SYNC_FRAME_AUTHENTICATED = 'sync-frame-authenticated';
12
+ export const SYNC_WEB_SOCKET_MSG_TYPE_SYNC_FRAME_RESPONSE_AUTHENTICATED = 'sync-frame-response-authenticated';
13
+ export const SYNC_WEB_SOCKET_MSG_TYPE_DOMAIN_PAYLOAD = 'domain-payload';
14
+ export const SYNC_WEB_SOCKET_MSG_TYPE_SYNC_ERROR = 'sync-error';
15
+
16
+ /**
17
+ * Message types transmitted over the stateful WebSocket connection
18
+ * during a sync saga session handshake and execution.
19
+ */
20
+ export type SyncWebSocketMsgType =
21
+ | typeof SYNC_WEB_SOCKET_MSG_TYPE_AUTH_CHALLENGE_INIT
22
+ | typeof SYNC_WEB_SOCKET_MSG_TYPE_AUTH_INIT
23
+ | typeof SYNC_WEB_SOCKET_MSG_TYPE_AUTH_CHALLENGE
24
+ | typeof SYNC_WEB_SOCKET_MSG_TYPE_AUTH_PROOF
25
+ | typeof SYNC_WEB_SOCKET_MSG_TYPE_AUTH_OK
26
+ | typeof SYNC_WEB_SOCKET_MSG_TYPE_AUTH_FAIL
27
+ | typeof SYNC_WEB_SOCKET_MSG_TYPE_SYNC_FRAME
28
+ | typeof SYNC_WEB_SOCKET_MSG_TYPE_SYNC_FRAME_RESPONSE
29
+ | typeof SYNC_WEB_SOCKET_MSG_TYPE_SYNC_FRAME_AUTHENTICATED
30
+ | typeof SYNC_WEB_SOCKET_MSG_TYPE_SYNC_FRAME_RESPONSE_AUTHENTICATED
31
+ | typeof SYNC_WEB_SOCKET_MSG_TYPE_DOMAIN_PAYLOAD
32
+ | typeof SYNC_WEB_SOCKET_MSG_TYPE_SYNC_ERROR
33
+ ;
34
+
35
+ export const SyncWebSocketMsgType = {
36
+ /** Sent by server/receiver to trigger connection authentication. */
37
+ auth_challenge_init: SYNC_WEB_SOCKET_MSG_TYPE_AUTH_CHALLENGE_INIT,
38
+ /** Sent by client/sender to start the authentication handshake with the target session address. */
39
+ auth_init: SYNC_WEB_SOCKET_MSG_TYPE_AUTH_INIT,
40
+ /** Sent by server/receiver with dynamic connect challenges to be solved. */
41
+ auth_challenge: SYNC_WEB_SOCKET_MSG_TYPE_AUTH_CHALLENGE,
42
+ /** Sent by client/sender with proof of session keystone evolution solving challenges. */
43
+ auth_proof: SYNC_WEB_SOCKET_MSG_TYPE_AUTH_PROOF,
44
+ /** Sent by server/receiver signaling successful challenge resolution and upgrade to active sync. */
45
+ auth_ok: SYNC_WEB_SOCKET_MSG_TYPE_AUTH_OK,
46
+ /** Sent when authentication fails. */
47
+ auth_fail: SYNC_WEB_SOCKET_MSG_TYPE_AUTH_FAIL,
48
+ /** Sent by client/sender to transmit the next sync transaction context without payload ibgibs. */
49
+ sync_frame: SYNC_WEB_SOCKET_MSG_TYPE_SYNC_FRAME,
50
+ /** Sent by server/receiver responding with the next sync transaction context. */
51
+ sync_frame_response: SYNC_WEB_SOCKET_MSG_TYPE_SYNC_FRAME_RESPONSE,
52
+ /** Sent by server/receiver after context is validated/authenticated to signal payload transmission. */
53
+ sync_frame_authenticated: SYNC_WEB_SOCKET_MSG_TYPE_SYNC_FRAME_AUTHENTICATED,
54
+ /** Sent by client/sender after response context is validated/authenticated to signal payload transmission. */
55
+ sync_frame_response_authenticated: SYNC_WEB_SOCKET_MSG_TYPE_SYNC_FRAME_RESPONSE_AUTHENTICATED,
56
+ /** Sent to stream a single domain payload ibgib. */
57
+ domain_payload: SYNC_WEB_SOCKET_MSG_TYPE_DOMAIN_PAYLOAD,
58
+ /** Sent when a sync runtime execution error occurs. */
59
+ sync_error: SYNC_WEB_SOCKET_MSG_TYPE_SYNC_ERROR,
60
+ } satisfies { readonly [key: string]: SyncWebSocketMsgType };
61
+
62
+ export const SYNC_WEB_SOCKET_MSG_TYPE_VALID_VALUES: SyncWebSocketMsgType[] = Object.values(SyncWebSocketMsgType);
63
+
64
+ export function isSyncWebSocketMsgType(value: any): value is SyncWebSocketMsgType {
65
+ return SYNC_WEB_SOCKET_MSG_TYPE_VALID_VALUES.includes(value);
66
+ }
67
+
68
+ // #endregion SyncWebSocketMsgType enum
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @module sync-peer-websocket-receiver-types
3
+ */
4
+ import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
5
+ import {
6
+ SyncPeerData_V1, SyncPeerRel8ns_V1, SyncPeerWitness,
7
+ InitializeSyncPeerOpts, ConnectSyncPeerOpts
8
+ } from '../../sync-peer-types.mjs';
9
+ import { SyncSagaCoordinator } from '../../../sync-saga-coordinator.mjs';
10
+
11
+ /**
12
+ * Data for the SyncPeerWebSocketReceiver witness.
13
+ */
14
+ export interface SyncPeerWebSocketReceiverData_V1 extends SyncPeerData_V1 {
15
+ }
16
+
17
+ /**
18
+ * Relations for the SyncPeerWebSocketReceiver witness.
19
+ */
20
+ export interface SyncPeerWebSocketReceiverRel8ns_V1 extends SyncPeerRel8ns_V1 {
21
+ }
22
+
23
+ /**
24
+ * The SyncPeerWebSocketReceiver witness IbGib.
25
+ */
26
+ export interface SyncPeerWebSocketReceiverIbGib_V1 extends IbGib_V1<SyncPeerWebSocketReceiverData_V1, SyncPeerWebSocketReceiverRel8ns_V1> { }
27
+
28
+ export interface ConnectSyncPeerWebSocketReceiverOpts extends ConnectSyncPeerOpts {
29
+ }
30
+
31
+ export interface InitializeSyncPeerWebSocketReceiverOpts extends InitializeSyncPeerOpts {
32
+ /**
33
+ * The local SyncSagaCoordinator instance running on the receiver/server.
34
+ */
35
+ localCoordinator: SyncSagaCoordinator;
36
+ }