@ibgib/space-gib 0.0.3 → 0.0.5

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 (63) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/IMPLEMENTATION.md +9 -13
  3. package/README.md +7 -0
  4. package/dist/client/bootstrap.mjs +1 -1
  5. package/dist/client/bootstrap.mjs.map +1 -1
  6. package/dist/client/chunk-ANGVYAEK.mjs +42 -0
  7. package/dist/client/chunk-ANGVYAEK.mjs.map +7 -0
  8. package/dist/client/chunk-IRGFDQRD.mjs +1920 -0
  9. package/dist/client/chunk-IRGFDQRD.mjs.map +7 -0
  10. package/dist/client/index.html +103 -5
  11. package/dist/client/index.mjs +1 -1
  12. package/dist/client/script.mjs +1 -1
  13. package/dist/client/style.css +466 -61
  14. package/dist/respec-gib.node.mjs +5 -0
  15. package/dist/server/server.mjs +533 -233
  16. package/dist/server/server.mjs.map +2 -2
  17. package/package.json +6 -6
  18. package/src/client/AUTO-GENERATED-version.mts +1 -1
  19. package/src/client/components/identity-header/IMPLEMENTATION.md +45 -0
  20. package/src/client/components/identity-header/identity-header.css +74 -0
  21. package/src/client/components/identity-header/identity-header.html +10 -0
  22. package/src/client/components/identity-header/identity-header.mts +361 -0
  23. package/src/client/components/identity-manager/IMPLEMENTATION.md +100 -0
  24. package/src/client/components/identity-manager/identity-manager.css +467 -0
  25. package/src/client/components/identity-manager/identity-manager.html +113 -0
  26. package/src/client/components/identity-manager/identity-manager.mts +767 -0
  27. package/src/client/components/keystone-creator/keystone-creator.css +2 -76
  28. package/src/client/components/keystone-creator/keystone-creator.html +41 -26
  29. package/src/client/components/keystone-creator/keystone-creator.mts +178 -41
  30. package/src/client/dev-tools/base-tools.mts +252 -0
  31. package/src/client/dev-tools/common.mts +217 -0
  32. package/src/client/dev-tools/phase-1.mts +156 -0
  33. package/src/client/dev-tools/phase-2.mts +143 -0
  34. package/src/client/dev-tools/phase-3.mts +189 -0
  35. package/src/client/dev-tools/phase-4-1.mts +197 -0
  36. package/src/client/dev-tools/phase-4-10.mts +884 -0
  37. package/src/client/dev-tools/phase-4-2.mts +388 -0
  38. package/src/client/dev-tools/phase-4-3.mts +391 -0
  39. package/src/client/dev-tools/phase-4-4.mts +374 -0
  40. package/src/client/dev-tools/phase-4-5.mts +376 -0
  41. package/src/client/dev-tools/phase-4-6.mts +273 -0
  42. package/src/client/dev-tools/phase-4-7.mts +399 -0
  43. package/src/client/dev-tools/phase-4-8.mts +430 -0
  44. package/src/client/dev-tools/phase-4-9.mts +398 -0
  45. package/src/client/dev-tools/phase-4.mts +1302 -0
  46. package/src/client/dev-tools.mts +52 -1194
  47. package/src/client/index.html +103 -5
  48. package/src/client/style.css +466 -61
  49. package/src/client/ui/shell/space-gib-shell-constants.mts +0 -2
  50. package/src/client/ui/shell/space-gib-shell-service.mts +82 -10
  51. package/src/common/common-constants.mts +0 -0
  52. package/src/common/keystone-policies.json +40 -43
  53. package/src/common/keystone-policies.mts +3 -5
  54. package/src/server/path-helper.respec.mts +99 -94
  55. package/src/server/serve-gib/README.md +9 -0
  56. package/src/server/serve-gib/handlers/api/keystone/keystone-genesis.handler.mts +1 -1
  57. package/src/server/serve-gib/handlers/api/keystone/keystone-get.respec.mts +1 -1
  58. package/src/server/serve-gib/handlers/ws/sync-upgrade-handler-base.mts +31 -3
  59. package/src/server/serve-gib/handlers/ws/ws-helper.mts +73 -45
  60. package/dist/client/chunk-2KJC5XKE.mjs +0 -31
  61. package/dist/client/chunk-2KJC5XKE.mjs.map +0 -7
  62. package/dist/client/chunk-QNIXTRFO.mjs +0 -235
  63. package/dist/client/chunk-QNIXTRFO.mjs.map +0 -7
@@ -1,1202 +1,32 @@
1
1
  /**
2
2
  * @module client/dev-tools
3
3
  *
4
- * Wires up the Dev Tools panel button handlers for manual testing during
5
- * development. Import this from index.mts inside the DOMContentLoaded handler.
6
- *
7
- * ## intent
8
- *
9
- * Remove or gate this module once the real sync WebSocket endpoint is confirmed
10
- * working end-to-end.
4
+ * Facade entry point for Dev Tools panel button handlers.
5
+ * Imports and wires up all modular sub-file handlers under dev-tools/.
11
6
  */
12
7
 
13
- import { extractErrorMsg, getTimestamp, getUUID, } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
14
- import { Factory_V1 as factory } from '@ibgib/ts-gib/dist/V1/factory.mjs';
15
- import { ROOT } from '@ibgib/ts-gib/dist/V1/constants.mjs';
16
- import { getIbGibAddr, } from '@ibgib/ts-gib/dist/helper.mjs';
17
- import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
18
- import { KeystoneService_V1 } from '@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs';
19
- import { KeystoneIbGib_V1, KeystoneReplenishStrategy } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs';
20
- import { createManagePoolConfig } from '@ibgib/core-gib/dist/keystone/keystone-config-builder.mjs';
21
- import { KeystoneStrategyFactory } from '@ibgib/core-gib/dist/keystone/strategy/keystone-strategy-factory.mjs';
22
- import { SyncPeerWebSocketSender_V1 } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs';
23
- import { SyncSagaCoordinator } from '@ibgib/core-gib/dist/sync/sync-saga-coordinator.mjs';
24
- import { KEYSTONE_VERB_CONNECT, POOL_ID_CONNECT, POOL_ID_SYNC } from '@ibgib/core-gib/dist/keystone/keystone-constants.mjs';
25
- import { getGlobalMetaspace_waitIfNeeded } from "@ibgib/web-gib/dist/helpers.mjs";
26
- import { graphsAreEquivalent } from '@ibgib/core-gib/dist/common/other/graph-helper.mjs';
8
+ import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
27
9
 
28
- import { GLOBAL_LOG_A_LOT } from './constants.mjs';
10
+ import { devLog, debugState, lc } from './dev-tools/common.mjs';
29
11
  import {
30
- SESSION_KEYSTONE_POLICY, getConnectChallenge, getSpaceGibPoolConfig
31
- } from "../common/keystone-policies.mjs";
32
- import { SpaceGibApiBridge } from './api/space-gib-api-bridge.mjs';
33
- import { SyncConflictStrategy } from '@ibgib/core-gib/dist/sync/sync-constants.mjs';
34
-
35
- const logalot = GLOBAL_LOG_A_LOT
36
- const lc = '[dev-tools]';
37
-
38
- interface DebugState {
39
- domainI?: KeystoneIbGib_V1;
40
- domainIMasterSecret?: string;
41
- targetX?: IbGib_V1;
42
- sessionS?: KeystoneIbGib_V1;
43
- sessionSecret?: string;
44
- senderPeer?: SyncPeerWebSocketSender_V1;
45
- sagaId?: string;
46
- }
47
-
48
- export const debugState: DebugState = {};
49
- (window as any).ibgibDebugState = debugState;
50
-
51
- // ---------------------------------------------------------------------------
52
- // Dev panel log helper
53
- // ---------------------------------------------------------------------------
54
-
55
- export function devLog(msg: string): void {
56
- const logEl = document.getElementById('dev-panel-log') as HTMLPreElement | null;
57
- if (!logEl) { return; }
58
- const timestamp = new Date().toISOString().slice(11, 23); // HH:MM:SS.mmm
59
- logEl.textContent = `[${timestamp}] ${msg}\n` + logEl.textContent;
60
- }
61
-
62
- // ---------------------------------------------------------------------------
63
- // Test WebSocket button
64
- // ---------------------------------------------------------------------------
65
-
66
- let _ws: WebSocket | null = null;
67
-
68
- function initWsTestButton(): void {
69
- const lc_fn = `${lc}[initWsTestButton]`;
70
- const btn = document.getElementById('btn-test-ws') as HTMLButtonElement | null;
71
- if (!btn) {
72
- console.warn(`${lc_fn} btn-test-ws not found — skipping`);
73
- return;
74
- }
75
-
76
- btn.addEventListener('click', () => {
77
- try {
78
- if (_ws && _ws.readyState === WebSocket.OPEN) {
79
- // Already connected — send a test ping instead
80
- _ws.send(JSON.stringify({ ping: 'hello from client', ts: Date.now() }));
81
- devLog('→ sent ping on existing connection');
82
- return;
83
- }
84
-
85
- // Build the WebSocket URL from the current origin (wss:// if https://)
86
- const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
87
- const wsUrl = `${protocol}//${location.host}/api/debug/ws-echo`;
88
- devLog(`→ connecting to ${wsUrl}`);
89
-
90
- _ws = new WebSocket(wsUrl);
91
-
92
- _ws.addEventListener('open', () => {
93
- devLog('✓ WebSocket connected');
94
- btn.textContent = 'Send WS Ping';
95
- });
96
-
97
- _ws.addEventListener('message', (ev) => {
98
- devLog(`← ${ev.data}`);
99
- });
100
-
101
- _ws.addEventListener('close', (ev) => {
102
- devLog(`✗ WebSocket closed (code ${ev.code})`);
103
- btn.textContent = 'Test WebSocket';
104
- _ws = null;
105
- });
106
-
107
- _ws.addEventListener('error', (ev) => {
108
- devLog(`✗ WebSocket error — check console`);
109
- console.error(`${lc_fn} WebSocket error`, ev);
110
- });
111
-
112
- } catch (error) {
113
- devLog(`✗ ${extractErrorMsg(error)}`);
114
- console.error(`${lc_fn} ${extractErrorMsg(error)}`);
115
- }
116
- });
117
- }
118
-
119
- // ---------------------------------------------------------------------------
120
- // Print Dev State button
121
- // ---------------------------------------------------------------------------
122
-
123
- function initPrintStateButton(): void {
124
- const btn = document.getElementById('btn-print-dev-state') as HTMLButtonElement | null;
125
- if (!btn) { return; }
126
- btn.addEventListener('click', () => {
127
- devLog(`Printing debug state to console...`);
128
- console.dir(debugState);
129
- });
130
- }
131
-
132
- // ---------------------------------------------------------------------------
133
- // Create Domain Keystone (I) button
134
- // ---------------------------------------------------------------------------
135
-
136
- function initCreateDomainKeystoneButton(): void {
137
- const lc_fn = `${lc}[initCreateDomainKeystoneButton]`;
138
- const btn = document.getElementById('btn-create-domain-keystone') as HTMLButtonElement | null;
139
- if (!btn) { return; }
140
-
141
- btn.addEventListener('click', async () => {
142
- try {
143
- btn.disabled = true;
144
- devLog('Generating dummy Domain Keystone (I)...');
145
-
146
- const metaspace = await getGlobalMetaspace_waitIfNeeded();
147
- const space = await metaspace.getLocalUserSpace({});
148
- if (!space) { throw new Error("No default space found in metaspace."); }
149
-
150
- const masterSecret = 'password'; // Hardcoded for debug as requested
151
- const keystoneService = new KeystoneService_V1();
152
-
153
- const domainI = await keystoneService.genesis({
154
- masterSecret,
155
- configs: [
156
- createManagePoolConfig({
157
- id: 'default',
158
- salt: await getUUID(),
159
- replenishStrategy: KeystoneReplenishStrategy.topUp,
160
- }),
161
- ],
162
- metaspace,
163
- space,
164
- frameDetails: { client: 'space-gib-web-dev', timestamp: getTimestamp() }
165
- });
166
-
167
- const iAddr = getIbGibAddr({ ibGib: domainI });
168
- devLog(`✓ Local genesis complete: ${iAddr}`);
169
-
170
- debugState.domainI = domainI;
171
- debugState.domainIMasterSecret = masterSecret;
172
-
173
- // Post to server
174
- devLog(`Posting genesis keystone to server...`);
175
- const apiBridge = new SpaceGibApiBridge();
176
- const resSync = await apiBridge.postGenesisKeystone(domainI);
177
- if (!resSync.success) {
178
- devLog(`✗ Server rejected genesis keystone: ${resSync.message}`);
179
- btn.disabled = false;
180
- return;
181
- }
182
-
183
- devLog(`✓ Server accepted Domain Keystone (I)`);
184
- btn.textContent = '✓ Domain Keystone Created';
185
-
186
- // Enable next step
187
- const nextBtn = document.getElementById('btn-create-test-ibgib') as HTMLButtonElement;
188
- if (nextBtn) { nextBtn.disabled = false; }
189
-
190
- } catch (error) {
191
- devLog(`✗ ${extractErrorMsg(error)}`);
192
- console.error(`${lc_fn} ${extractErrorMsg(error)}`);
193
- btn.disabled = false;
194
- }
195
- });
196
- }
197
-
198
- // ---------------------------------------------------------------------------
199
- // Create Test IbGib button
200
- // ---------------------------------------------------------------------------
201
-
202
- function initCreateTestIbGibButton(): void {
203
- const lc_fn = `${lc}[initCreateTestIbGibButton]`;
204
- const btn = document.getElementById('btn-create-test-ibgib') as HTMLButtonElement | null;
205
- if (!btn) {
206
- console.warn(`${lc_fn} btn-create-test-ibgib not found — skipping`);
207
- return;
208
- }
209
-
210
- btn.addEventListener('click', async () => {
211
- try {
212
- devLog('Generating dummy X^Xtjp ibgib...');
213
- const resX = await factory.firstGen({
214
- parentIbGib: ROOT,
215
- ib: 'test data',
216
- data: { hello: 'world', random: Math.random() },
217
- dna: true,
218
- nCounter: true,
219
- tjp: { uuid: true, timestamp: true }
220
- });
221
- const xIbGib = resX.newIbGib;
222
- const xAddr = getIbGibAddr({ ibGib: xIbGib });
223
-
224
- debugState.targetX = xIbGib;
225
- devLog(`✓ Created X: ${xAddr}`);
226
- btn.textContent = '✓ Test IbGib (X) Created';
227
-
228
- // Enable next step
229
- const nextBtn = document.getElementById('btn-create-session-keystone') as HTMLButtonElement;
230
- if (nextBtn) { nextBtn.disabled = false; }
231
- } catch (error) {
232
- devLog(`✗ ${extractErrorMsg(error)}`);
233
- console.error(`${lc_fn} ${extractErrorMsg(error)}`);
234
- }
235
- });
236
- }
237
-
238
- // ---------------------------------------------------------------------------
239
- // Create Session Keystone (S^Stjp) button
240
- // ---------------------------------------------------------------------------
241
-
242
- function initCreateSessionKeystoneButton(): void {
243
- const lc_fn = `${lc}[initCreateSessionKeystoneButton]`;
244
- const btn = document.getElementById('btn-create-session-keystone') as HTMLButtonElement | null;
245
- if (!btn) {
246
- console.warn(`${lc_fn} btn-create-session-keystone not found — skipping`);
247
- return;
248
- }
249
-
250
- btn.addEventListener('click', async () => {
251
- try {
252
- devLog('Generating Session Keystone (S^Stjp)...');
253
-
254
- const domainI = debugState.domainI;
255
- const targetX = debugState.targetX;
256
-
257
- if (!domainI) { devLog('⚠ No domain keystone (I) found in state. Please Create Domain Keystone first.'); return; }
258
- if (!targetX) { devLog('⚠ No target ibgib (X) found in state. Please Create Test IbGib first.'); return; }
259
-
260
- const metaspace = await getGlobalMetaspace_waitIfNeeded();
261
- const space = await metaspace.getLocalUserSpace({});
262
- if (!space) { throw new Error("No default space found in metaspace."); }
263
-
264
- const sessionSecret = 'ephemeral-' + Math.random().toString();
265
- const keystoneService = new KeystoneService_V1();
266
-
267
- console.warn(`${lc}[NAG] placeholder genesis keystone config right now (W: 69b108687cf8bec0f9a8e148bcca8d26)`);
268
- const sIbGib = await keystoneService.genesis({
269
- masterSecret: sessionSecret,
270
- configs: [
271
- {
272
- id: SESSION_KEYSTONE_POLICY.DEFAULT_POOL.ID,
273
- salt: await getUUID(),
274
- type: SESSION_KEYSTONE_POLICY.COMMON.TYPE,
275
- algo: SESSION_KEYSTONE_POLICY.COMMON.ALGO,
276
- rounds: SESSION_KEYSTONE_POLICY.COMMON.ROUNDS,
277
- behavior: {
278
- size: SESSION_KEYSTONE_POLICY.DEFAULT_POOL.SIZE,
279
- replenish: SESSION_KEYSTONE_POLICY.COMMON.REPLENISH,
280
- selectSequentially: SESSION_KEYSTONE_POLICY.DEFAULT_POOL.SELECT_SEQUENTIALLY,
281
- selectRandomly: SESSION_KEYSTONE_POLICY.DEFAULT_POOL.SELECT_RANDOMLY,
282
- targetBindingChars: SESSION_KEYSTONE_POLICY.DEFAULT_POOL.TARGET_BINDING_CHARS,
283
- },
284
- allowedVerbs: [],
285
- },
286
- {
287
- id: SESSION_KEYSTONE_POLICY.CONNECT_POOL.ID,
288
- salt: await getUUID(),
289
- type: SESSION_KEYSTONE_POLICY.COMMON.TYPE,
290
- algo: SESSION_KEYSTONE_POLICY.COMMON.ALGO,
291
- rounds: SESSION_KEYSTONE_POLICY.COMMON.ROUNDS,
292
- behavior: {
293
- size: SESSION_KEYSTONE_POLICY.CONNECT_POOL.SIZE,
294
- replenish: SESSION_KEYSTONE_POLICY.COMMON.REPLENISH,
295
- selectSequentially: SESSION_KEYSTONE_POLICY.CONNECT_POOL.SELECT_SEQUENTIALLY,
296
- selectRandomly: SESSION_KEYSTONE_POLICY.CONNECT_POOL.SELECT_RANDOMLY,
297
- targetBindingChars: SESSION_KEYSTONE_POLICY.CONNECT_POOL.TARGET_BINDING_CHARS,
298
- },
299
- allowedVerbs: [SESSION_KEYSTONE_POLICY.CONNECT_POOL.VERB],
300
- }
301
- ],
302
- metaspace,
303
- space,
304
- frameDetails: {
305
- client: 'space-gib-web-session',
306
- target_I: domainI ? getIbGibAddr({ ibGib: domainI }) : undefined,
307
- target_X: targetX ? getIbGibAddr({ ibGib: targetX }) : undefined,
308
- }
309
- });
310
-
311
- const sAddr = getIbGibAddr({ ibGib: sIbGib });
312
- debugState.sessionS = sIbGib;
313
- debugState.sessionSecret = sessionSecret;
314
-
315
- devLog(`✓ Created Session Keystone: ${sAddr}`);
316
- btn.textContent = '✓ Session Keystone Created';
317
-
318
- // Enable next step
319
- const nextBtn = document.getElementById('btn-evolve-domain-keystone') as HTMLButtonElement;
320
- if (nextBtn) { nextBtn.disabled = false; }
321
- } catch (error) {
322
- devLog(`✗ ${extractErrorMsg(error)}`);
323
- console.error(`${lc_fn} ${extractErrorMsg(error)}`);
324
- }
325
- });
326
- }
327
-
328
- // ---------------------------------------------------------------------------
329
- // Evolve Domain Keystone (I^I1) button
330
- // ---------------------------------------------------------------------------
331
-
332
- function initEvolveDomainKeystoneButton(): void {
333
- const lc_fn = `${lc}[initEvolveDomainKeystoneButton]`;
334
- const btn = document.getElementById('btn-evolve-domain-keystone') as HTMLButtonElement | null;
335
- if (!btn) {
336
- console.warn(`${lc_fn} btn-evolve-domain-keystone not found — skipping`);
337
- return;
338
- }
339
-
340
- btn.addEventListener('click', async () => {
341
- try {
342
- btn.disabled = true;
343
- devLog('Evolving Domain Keystone (I^I1) with sync claim...');
344
-
345
- const domainI = debugState.domainI;
346
- const masterSecret = debugState.domainIMasterSecret;
347
- const sessionS = debugState.sessionS;
348
-
349
- if (!domainI || !masterSecret) { devLog('⚠ No domain keystone (I) found. Please Create Domain Keystone first.'); return; }
350
- if (!sessionS) { devLog('⚠ No session keystone (S) found. Please Create Session Keystone first.'); return; }
351
-
352
- const metaspace = await getGlobalMetaspace_waitIfNeeded();
353
- const space = await metaspace.getLocalUserSpace({});
354
- if (!space) { throw new Error("No default space found in metaspace."); }
355
-
356
- const keystoneService = new KeystoneService_V1();
357
- const sAddr = getIbGibAddr({ ibGib: sessionS });
358
-
359
- devLog('Solving challenges to authorize sync...');
360
- const evolvedI = await keystoneService.sign({
361
- latestKeystone: domainI,
362
- masterSecret,
363
- claim: {
364
- target: sAddr,
365
- verb: 'sync'
366
- },
367
- metaspace,
368
- space
369
- });
370
-
371
- const evolvedAddr = getIbGibAddr({ ibGib: evolvedI });
372
- devLog(`✓ Local evolution complete: ${evolvedAddr}`);
373
-
374
- // Update state with new tip
375
- debugState.domainI = evolvedI;
376
-
377
- devLog('Posting evolution to server...');
378
- const apiBridge = new SpaceGibApiBridge();
379
- // We pass the domain address (from the original TJP) and the session keystone
380
- const domainAddr = getIbGibAddr({ ibGib: domainI });
381
- const resSync = await apiBridge.putEvolveKeystone(domainAddr, evolvedI, [sessionS]);
382
-
383
- if (!resSync.success) {
384
- devLog(`✗ Server rejected evolution: ${resSync.message}`);
385
- btn.disabled = false;
386
- return;
387
- }
388
-
389
- devLog('✓ Server accepted Domain Keystone evolution!');
390
- btn.textContent = '✓ Domain Keystone Evolved';
391
-
392
- // Enable next step
393
- const nextBtn = document.getElementById('btn-perform-sync') as HTMLButtonElement;
394
- if (nextBtn) { nextBtn.disabled = false; }
395
-
396
- } catch (error) {
397
- devLog(`✗ ${extractErrorMsg(error)}`);
398
- console.error(`${lc_fn} ${extractErrorMsg(error)}`);
399
- btn.disabled = false;
400
- }
401
- });
402
- }
403
-
404
- // ---------------------------------------------------------------------------
405
- // Perform Sync Connect (S) button
406
- // ---------------------------------------------------------------------------
407
-
408
- function initPerformSyncButton(): void {
409
- const lc_fn = `${lc}[initPerformSyncButton]`;
410
- const btn = document.getElementById('btn-perform-sync') as HTMLButtonElement | null;
411
- if (!btn) { return; }
412
-
413
- btn.addEventListener('click', async () => {
414
- try {
415
- debugger; // walk through sync
416
- btn.disabled = true;
417
- devLog('Initiating Sync Connect via WebSocket...');
418
-
419
- const sessionS = debugState.sessionS;
420
- const sessionSecret = debugState.sessionSecret;
421
- const domainI = debugState.domainI;
422
-
423
- if (!sessionS || !sessionSecret || !domainI) {
424
- devLog('⚠ Incomplete state. Please complete steps 1-4.');
425
- btn.disabled = false;
426
- return;
427
- }
428
-
429
- const metaspace = await getGlobalMetaspace_waitIfNeeded();
430
- const space = await metaspace.getLocalUserSpace({});
431
- if (!space) { throw new Error("No space."); }
432
-
433
- devLog('Pre-solving upfront picket-fence challenge...');
434
- const connectPool = (sessionS.data?.challengePools ?? []).find(p => p.id === SESSION_KEYSTONE_POLICY.CONNECT_POOL.ID);
435
- if (!connectPool) {
436
- throw new Error(`Session keystone missing "${SESSION_KEYSTONE_POLICY.CONNECT_POOL.ID}" pool`);
437
- }
438
-
439
- const { challengeId } = getConnectChallenge(sessionS);
440
- const strategy = KeystoneStrategyFactory.create({ config: connectPool.config });
441
- const poolSecret = await strategy.derivePoolSecret({ masterSecret: sessionSecret });
442
- const solution = await strategy.generateSolution({
443
- poolSecret,
444
- poolId: SESSION_KEYSTONE_POLICY.CONNECT_POOL.ID,
445
- challengeId
446
- });
447
-
448
- const sAddr = getIbGibAddr({ ibGib: sessionS });
449
- const domainAddr = getIbGibAddr({ ibGib: domainI });
450
- const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
451
- const wsUrl = `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}` +
452
- `?sAddr=${encodeURIComponent(sAddr)}` +
453
- `&solution=${solution.value}`;
454
-
455
- devLog(`→ connecting to ${wsUrl}`);
456
- const ws = new WebSocket(wsUrl);
457
-
458
- ws.addEventListener('open', () => {
459
- devLog('✓ WebSocket connected. Waiting for server challenge...');
460
- });
461
-
462
- ws.addEventListener('message', async (ev) => {
463
- try {
464
- const msg = JSON.parse(ev.data);
465
- devLog(`← received: ${msg.type ?? 'message'}`);
466
-
467
- if (msg.type === 'auth-challenge-init') {
468
- devLog('→ sending auth-init with sAddr...');
469
- ws.send(JSON.stringify({
470
- type: 'auth-init',
471
- sAddr: getIbGibAddr({ ibGib: sessionS })
472
- }));
473
- } else if (msg.type === 'auth-challenge') {
474
- const { challengeUuid, demandedIds } = msg;
475
- devLog(`→ server demanded ${demandedIds.length} ids. Signing connect proof...`);
476
-
477
- const keystoneService = new KeystoneService_V1();
478
- const proofFrame = await keystoneService.sign({
479
- latestKeystone: sessionS,
480
- masterSecret: sessionSecret,
481
- poolId: POOL_ID_CONNECT,
482
- requiredChallengeIds: demandedIds,
483
- claim: {
484
- verb: KEYSTONE_VERB_CONNECT,
485
- target: challengeUuid
486
- },
487
- metaspace,
488
- space
489
- });
490
-
491
- devLog('→ sending auth-proof...');
492
- ws.send(JSON.stringify({
493
- type: 'auth-proof',
494
- proofFrame
495
- }));
496
- } else if (msg.type === 'auth-ok') {
497
- devLog('✓ Connect SUCCESS! Sync session authorized.');
498
- btn.textContent = '✓ Sync Authorized';
499
- } else if (msg.type === 'auth-fail') {
500
- devLog(`✗ Connect FAILED: ${msg.message}`);
501
- btn.disabled = false;
502
- }
503
- } catch (error) {
504
- devLog(`✗ Message handler error: ${extractErrorMsg(error)}`);
505
- console.error(`${lc_fn} Message handler error:`, error);
506
- btn.disabled = false;
507
- }
508
- });
509
-
510
- ws.addEventListener('close', (ev) => {
511
- devLog(`✗ WebSocket closed (code ${ev.code})`);
512
- btn.disabled = false;
513
- });
514
-
515
- ws.addEventListener('error', () => {
516
- devLog(`✗ WebSocket error — check server`);
517
- btn.disabled = false;
518
- });
519
-
520
- } catch (error) {
521
- devLog(`✗ ${extractErrorMsg(error)}`);
522
- console.error(`${lc_fn} ${extractErrorMsg(error)}`);
523
- btn.disabled = false;
524
- }
525
- });
526
- }
527
-
528
- // ---------------------------------------------------------------------------
529
- // Phase 1B: Standardized Setup / Sync / Check testing loop
530
- // ---------------------------------------------------------------------------
531
-
532
- interface PhaseSetupOptions {
533
- phaseText: '1B' | '2B' | '3B';
534
- btnId: string;
535
- nextBtnId: string;
536
- masterSecret: string;
537
- syncSalt: string;
538
- manageSalt: string;
539
- ib: string;
540
- data: any;
541
- }
542
-
543
- async function performPhaseSetup(opts: PhaseSetupOptions): Promise<void> {
544
- const lc_fn = `${lc}[performPhaseSetup(${opts.phaseText})]`;
545
- const btn = document.getElementById(opts.btnId) as HTMLButtonElement | null;
546
- if (!btn) { return; }
547
-
548
- try {
549
- btn.disabled = true;
550
- devLog(`${opts.phaseText} Setup: Generating Alice's long-lived Domain Keystone (I) and Target (X)...`);
551
-
552
- const metaspace = await getGlobalMetaspace_waitIfNeeded();
553
- const space = await metaspace.getLocalUserSpace({});
554
- if (!space) { throw new Error("No default space found in metaspace."); }
555
-
556
- const keystoneService = new KeystoneService_V1();
557
-
558
- // 1. Create Genesis Domain Keystone (I^Itjp) in local space
559
- const domainI = await keystoneService.genesis({
560
- masterSecret: opts.masterSecret,
561
- configs: [
562
- getSpaceGibPoolConfig('sync', opts.syncSalt),
563
- getSpaceGibPoolConfig('manage', opts.manageSalt),
564
- ],
565
- metaspace,
566
- space,
567
- frameDetails: { client: 'space-gib-web-dev', timestamp: getTimestamp() }
568
- });
569
-
570
- debugState.domainI = domainI;
571
- debugState.domainIMasterSecret = opts.masterSecret;
572
-
573
- devLog(`${opts.phaseText} Setup: ✓ Domain Keystone (I) created locally: ${getIbGibAddr({ ibGib: domainI })}`);
574
- devLog(`${opts.phaseText} Setup: Starting postGenesisKeystone...`);
575
-
576
- // 2. Post Genesis Domain Keystone to receiver/server
577
- const apiBridge = new SpaceGibApiBridge();
578
- const resGenesis = await apiBridge.postGenesisKeystone(domainI);
579
- if (resGenesis.success) {
580
- devLog(`${opts.phaseText} Setup: ✓ Domain Keystone registered and stored on receiver (server).`);
581
- } else {
582
- devLog(`${opts.phaseText} Setup: X postGenesisKeystone failed: ${resGenesis.message}.`);
583
- throw new Error(`${opts.phaseText} Setup: Server rejected genesis domain keystone: ${resGenesis.message}`);
584
- }
585
-
586
- // 3. Create Test IbGib (X) locally
587
- const resX = await factory.firstGen({
588
- parentIbGib: ROOT,
589
- ib: opts.ib,
590
- data: opts.data,
591
- dna: true,
592
- nCounter: true,
593
- tjp: { uuid: true, timestamp: true }
594
- });
595
- const xIbGib = resX.newIbGib;
596
-
597
- // Persist target X to local space so coordinator can build the sync history
598
- await metaspace.persistTransformResult({ resTransform: resX, space });
599
- await metaspace.registerNewIbGib({ ibGib: xIbGib });
600
-
601
- debugState.targetX = xIbGib;
602
- devLog(`${opts.phaseText} Setup: ✓ Target (X) created and persisted locally: ${getIbGibAddr({ ibGib: xIbGib })}`);
603
-
604
- devLog(`✓ ${opts.phaseText} Setup Complete! Ready for ${opts.phaseText} Sync.`);
605
- btn.textContent = `✓ ${opts.phaseText} Setup Complete`;
606
-
607
- // Enable next button in the phase flow
608
- const syncBtn = document.getElementById(opts.nextBtnId) as HTMLButtonElement | null;
609
- if (syncBtn) { syncBtn.disabled = false; }
610
-
611
- } catch (error) {
612
- devLog(`✗ ${opts.phaseText} Setup FAILED: ${extractErrorMsg(error)}`);
613
- console.error(`${lc_fn} ${opts.phaseText} Setup error:`, error);
614
- btn.disabled = false;
615
- }
616
- }
617
-
618
- interface PhaseSyncOptions {
619
- phaseText: '1B' | '2B' | '3B';
620
- btnId: string;
621
- nextBtnId: string;
622
- expectSyncFailure?: boolean;
623
- failureMessageSuffix?: string;
624
- }
625
-
626
- async function performPhaseSync(opts: PhaseSyncOptions): Promise<void> {
627
- const lc_fn = `${lc}[performPhaseSync(${opts.phaseText})]`;
628
- const btn = document.getElementById(opts.btnId) as HTMLButtonElement | null;
629
- if (!btn) { return; }
630
-
631
- try {
632
- btn.disabled = true;
633
- devLog(`${opts.phaseText} Sync: Executing senderCoordinator.sync(...) using WebSocket Peer...`);
634
-
635
- const domainI = debugState.domainI;
636
- const targetX = debugState.targetX;
637
- if (!domainI || !targetX) {
638
- devLog(`⚠ ${opts.phaseText} Sync: Missing setup state. Please run Setup first.`);
639
- btn.disabled = false;
640
- return;
641
- }
642
-
643
- const domainAddr = getIbGibAddr({ ibGib: domainI });
644
- const metaspace = await getGlobalMetaspace_waitIfNeeded();
645
- const space = await metaspace.getLocalUserSpace({});
646
- if (!space) { throw new Error("No default space."); }
647
-
648
- const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
649
- const senderPeer = new SyncPeerWebSocketSender_V1({
650
- classname: 'SyncPeerWebSocketSender_V1',
651
- httpEvolveUrl: `${location.protocol}//${location.host}/api/keystone/evolve/${encodeURIComponent(domainAddr)}`,
652
- wsUrl: `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}`
653
- });
654
-
655
- const coordinator = new SyncSagaCoordinator();
656
- const sagaId = await getUUID();
657
- debugState.sagaId = sagaId;
658
- debugState.senderPeer = senderPeer;
659
-
660
- await senderPeer.initializeOpts({
661
- localMetaspace: metaspace,
662
- localSpace: space,
663
- senderIdentity: domainI,
664
- fnSenderSecret: async () => debugState.domainIMasterSecret!,
665
- sagaId,
666
- sessionConnectPoolConfig: SESSION_KEYSTONE_POLICY.CONNECT_POOL as any,
667
- sessionSyncPoolConfig: SESSION_KEYSTONE_POLICY.DEFAULT_POOL as any,
668
- targetAddrs: [domainAddr]
669
- });
670
-
671
- try {
672
- const syncSaga = await coordinator.sync({
673
- domainIbGibs: [targetX],
674
- senderIdentity: domainI,
675
- fnSenderSecret: async () => debugState.domainIMasterSecret!,
676
- peer: senderPeer,
677
- localSpace: space,
678
- metaspace,
679
- conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
680
- });
681
- await syncSaga.done;
682
- } catch (err) {
683
- if (opts.expectSyncFailure) {
684
- devLog(`${opts.phaseText} Sync: Coordinator sync executed (${opts.failureMessageSuffix ?? 'errors expected'}): ${extractErrorMsg(err)}`);
685
- } else {
686
- throw err;
687
- }
688
- }
689
-
690
- devLog(`✓ ${opts.phaseText} Sync Execution Complete! Ready for State Checks.`);
691
- btn.textContent = `✓ ${opts.phaseText} Sync Run`;
692
-
693
- const checkBtn = document.getElementById(opts.nextBtnId) as HTMLButtonElement | null;
694
- if (checkBtn) { checkBtn.disabled = false; }
695
-
696
- } catch (error) {
697
- devLog(`✗ ${opts.phaseText} Sync FAILED: ${extractErrorMsg(error)}`);
698
- console.error(`${lc_fn} ${opts.phaseText} Sync error:`, error);
699
- btn.disabled = false;
700
- }
701
- }
702
-
703
- function init1bSetupButton(): void {
704
- const btn = document.getElementById('btn-1b-setup') as HTMLButtonElement | null;
705
- if (!btn) { return; }
706
- btn.addEventListener('click', () => {
707
- performPhaseSetup({
708
- phaseText: '1B',
709
- btnId: 'btn-1b-setup',
710
- nextBtnId: 'btn-1b-sync',
711
- masterSecret: 'test-sender-secret-phase1',
712
- syncSalt: 'senderidentitysyncsaltphase1',
713
- manageSalt: 'senderidentitymanagesaltphase1',
714
- ib: 'test data',
715
- data: { hello: 'world', random: Math.random() }
716
- });
717
- });
718
- }
719
-
720
- function init1bSyncButton(): void {
721
- const btn = document.getElementById('btn-1b-sync') as HTMLButtonElement | null;
722
- if (!btn) { return; }
723
- btn.addEventListener('click', () => {
724
- performPhaseSync({
725
- phaseText: '1B',
726
- btnId: 'btn-1b-sync',
727
- nextBtnId: 'btn-1b-check',
728
- expectSyncFailure: true,
729
- failureMessageSuffix: 'establish phase successfully run; connection/sync errors expected in 1B'
730
- });
731
- });
732
- }
733
-
734
- function init1bCheckButton(): void {
735
- const lc_fn = `${lc}[init1bCheckButton]`;
736
- const btn = document.getElementById('btn-1b-check') as HTMLButtonElement | null;
737
- if (!btn) { return; }
738
-
739
- btn.addEventListener('click', async () => {
740
- try {
741
- devLog('1B Check: Asserting cryptographic and durable state expectations from respec...');
742
-
743
- debugger; // allow for walkthrough 1B check
744
- const metaspace = await getGlobalMetaspace_waitIfNeeded();
745
- const space = await metaspace.getLocalUserSpace({});
746
- if (!space) { throw new Error("No default space."); }
747
-
748
- const domainI = debugState.domainI!;
749
- const targetX = debugState.targetX!;
750
- const xAddr = getIbGibAddr({ ibGib: targetX });
751
-
752
- // 1. Resolve evolved sender identity I1 locally
753
- const newSenderIdentityAddr = await metaspace.getLatestAddr({
754
- addr: getIbGibAddr({ ibGib: domainI }),
755
- space
756
- });
757
-
758
- if (!newSenderIdentityAddr) {
759
- devLog('✗ Check: Evolved domain keystone tip I1 NOT found in local space!');
760
- return;
761
- }
762
- devLog(`✓ Check: Evolved Domain Keystone (I1) created and stored locally.`);
763
-
764
- const getRes = await metaspace.get({ addrs: [newSenderIdentityAddr], space });
765
- const newSenderIdentity = getRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
766
-
767
- if (!newSenderIdentity) {
768
- devLog('✗ Check: Failed to load I1 from local space.');
769
- return;
770
- }
771
-
772
- const syncProof = newSenderIdentity.data?.proofs?.find(p => p.claim?.verb === 'sync');
773
- if (!syncProof) {
774
- devLog('✗ Check: I1 is missing sync-verb claim proof!');
775
- } else {
776
- devLog('✓ Check: I1 contains valid sync-verb claim proof.');
777
- }
778
-
779
- const sessionIdentityTjpAddr = syncProof?.claim?.target;
780
- if (!sessionIdentityTjpAddr) {
781
- devLog('✗ Check: I1 sync claim does not target a session keystone.');
782
- return;
783
- }
784
- devLog(`✓ Check: Sync claim targets session keystone: ${sessionIdentityTjpAddr}`);
785
-
786
- // 2. Load Session Keystone (S) locally
787
- const sRes = await metaspace.get({ addrs: [sessionIdentityTjpAddr], space });
788
- const sessionIdentity = sRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
789
-
790
- if (!sessionIdentity) {
791
- devLog('✗ Check: Session Keystone (S) NOT found in local space.');
792
- return;
793
- }
794
- devLog('✓ Check: Session Keystone (S) successfully created locally.');
795
-
796
- const sPools = sessionIdentity.data?.challengePools ?? [];
797
- const hasConnectPool = sPools.some(p => p.id === POOL_ID_CONNECT);
798
- const hasSyncPool = sPools.some(p => p.id === POOL_ID_SYNC);
799
-
800
- if (hasConnectPool && hasSyncPool) {
801
- devLog('✓ Check: S contains both connect and sync challenge pools.');
802
- } else {
803
- devLog(`✗ Check: S is missing challenge pools! (connect: ${hasConnectPool}, sync: ${hasSyncPool})`);
804
- }
805
-
806
- // we don't check this yet until sync ping pong
807
- // const targetAddrs = sessionIdentity.data?.frameDetails?.targetAddrs ?? [];
808
- // if (targetAddrs.includes(xAddr)) {
809
- // devLog('✓ Check: S is securely bound to target domain X in frameDetails.');
810
- // } else {
811
- // devLog('✗ Check: S is not bound to target domain X!');
812
- // }
813
-
814
- // #region 3. Verify Server-Side (receiver) registrations via GET REST API
815
- devLog('Check: Verifying registrations on server (receiver metaspace)...');
816
- const apiBridge = new SpaceGibApiBridge();
817
-
818
- // Check if I, evolved I1 and session S exist on server
819
- let hasI = false;
820
- let hasI1 = false;
821
- let hasS = false;
822
-
823
- const domainAddr = getIbGibAddr({ ibGib: domainI });
824
- const resGetDomainIGraphFromServer = await apiBridge.getKeystoneGraph(domainAddr);
825
- if (resGetDomainIGraphFromServer.success && resGetDomainIGraphFromServer.graph) {
826
- const domainGraph = resGetDomainIGraphFromServer.graph;
827
- hasI = domainGraph[domainAddr] !== undefined;
828
- hasI1 = domainGraph[newSenderIdentityAddr] !== undefined;
829
- } else {
830
- devLog(`✗ Check Server: Failed to fetch keystone graph from server: ${resGetDomainIGraphFromServer.message}`);
831
- }
832
-
833
- const resGetSessionSFromServer = await apiBridge.getIbGib(domainAddr, sessionIdentityTjpAddr);
834
- if (resGetSessionSFromServer.success && resGetSessionSFromServer.ibGib) {
835
- hasS = true;
836
- } else {
837
- devLog(`✗ Check Server: Failed to fetch session keystone from server: ${resGetSessionSFromServer.message}`);
838
- }
839
-
840
- if (hasI) { devLog('✓ Check Server: Genesis Domain Keystone (I) registered on server.'); }
841
- else devLog('✗ Check Server: Genesis Domain Keystone (I) missing on server!');
842
- if (hasI1) { devLog('✓ Check Server: Evolved Domain Keystone (I1) accepted and stored on server.'); }
843
- else devLog('✗ Check Server: Evolved Domain Keystone (I1) missing on server!');
844
- if (hasS) { devLog('✓ Check Server: Session Keystone (S) accepted and stored on server.'); }
845
- else devLog('✗ Check Server: Session Keystone (S) missing on server!');
846
- if (hasI && hasI1 && hasS) {
847
- devLog('🎉 ALL PHASE 1B ESTABLISH CHECKS PASSED FLAWLESSLY! ✓');
848
- btn.textContent = '✓ 1B All Passed';
849
-
850
- const btn2bSetup = document.getElementById('btn-2b-setup') as HTMLButtonElement | null;
851
- if (btn2bSetup) { btn2bSetup.disabled = false; }
852
- }
853
-
854
- // #endregion 3. Verify Server-Side (receiver) registrations via GET REST API
855
-
856
- } catch (error) {
857
- devLog(`✗ 1B Check FAILED: ${extractErrorMsg(error)}`);
858
- console.error(`${lc_fn} 1B Check error:`, error);
859
- }
860
- });
861
- }
862
-
863
- // ---------------------------------------------------------------------------
864
- // Phase 2B Implementation
865
- // ---------------------------------------------------------------------------
866
-
867
- function init2bSetupButton(): void {
868
- const btn = document.getElementById('btn-2b-setup') as HTMLButtonElement | null;
869
- if (!btn) { return; }
870
- btn.addEventListener('click', () => {
871
- performPhaseSetup({
872
- phaseText: '2B',
873
- btnId: 'btn-2b-setup',
874
- nextBtnId: 'btn-2b-sync',
875
- masterSecret: 'test-sender-secret-phase2',
876
- syncSalt: 'senderidentitysyncsaltphase2',
877
- manageSalt: 'senderidentitymanagesaltphase2',
878
- ib: 'test data',
879
- data: { hello: 'world2', random: Math.random() }
880
- });
881
- });
882
- }
883
-
884
- function init2bSyncButton(): void {
885
- const btn = document.getElementById('btn-2b-sync') as HTMLButtonElement | null;
886
- if (!btn) { return; }
887
- btn.addEventListener('click', () => {
888
- performPhaseSync({
889
- phaseText: '2B',
890
- btnId: 'btn-2b-sync',
891
- nextBtnId: 'btn-2b-check',
892
- expectSyncFailure: true,
893
- failureMessageSuffix: 'connect phase successfully run; subsequent sync errors expected in 2B'
894
- });
895
- });
896
- }
897
-
898
- function init2bCheckButton(): void {
899
- const lc_fn = `${lc}[init2bCheckButton]`;
900
- const btn = document.getElementById('btn-2b-check') as HTMLButtonElement | null;
901
- if (!btn) { return; }
902
-
903
- btn.addEventListener('click', async () => {
904
- try {
905
- debugger; // allow for walkthrough 2B check
906
- devLog('2B Check: Asserting cryptographic and WebSocket state expectations...');
907
-
908
- const metaspace = await getGlobalMetaspace_waitIfNeeded();
909
- const space = await metaspace.getLocalUserSpace({});
910
- if (!space) { throw new Error("No default space."); }
911
-
912
- const domainI = debugState.domainI!;
913
- const targetX = debugState.targetX!;
914
- const xAddr = getIbGibAddr({ ibGib: targetX });
915
-
916
- // 1. Resolve evolved sender identity I1 locally
917
- const domainAddr = getIbGibAddr({ ibGib: domainI });
918
- const newSenderIdentityAddr = await metaspace.getLatestAddr({
919
- addr: domainAddr,
920
- space
921
- });
922
-
923
- if (!newSenderIdentityAddr) {
924
- devLog('✗ Check: Evolved domain keystone tip I1 NOT found in local space!');
925
- return;
926
- }
927
- devLog(`✓ Check: Evolved Domain Keystone (I1) created and stored locally.`);
928
-
929
- const getRes = await metaspace.get({ addrs: [newSenderIdentityAddr], space });
930
- const newSenderIdentity = getRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
931
-
932
- if (!newSenderIdentity) {
933
- devLog('✗ Check: Failed to load I1 from local space.');
934
- return;
935
- }
936
-
937
- const syncProof = newSenderIdentity.data?.proofs?.find(p => p.claim?.verb === 'sync');
938
- const sessionIdentityTjpAddr = syncProof?.claim?.target;
939
- if (!sessionIdentityTjpAddr) {
940
- devLog('✗ Check: I1 sync claim does not target a session keystone.');
941
- return;
942
- }
943
- devLog(`✓ Check: Sync claim targets session keystone: ${sessionIdentityTjpAddr}`);
944
-
945
- // 2. Load Session Keystone (S) locally and get latest tip
946
- const latestSessionSAddr = await metaspace.getLatestAddr({
947
- addr: sessionIdentityTjpAddr,
948
- space
949
- });
950
- if (!latestSessionSAddr) {
951
- devLog('✗ Check: Latest Session Keystone (S) NOT found in local space.');
952
- return;
953
- }
954
- devLog(`✓ Check: Found latest session keystone (S) locally.`);
955
-
956
- const sRes = await metaspace.get({ addrs: [latestSessionSAddr], space });
957
- const sessionIdentity = sRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
958
-
959
- if (!sessionIdentity) {
960
- devLog('✗ Check: Failed to load latest Session Keystone (S).');
961
- return;
962
- }
963
-
964
- // Verify S contains connect and sync pools
965
- const sPools = sessionIdentity.data?.challengePools ?? [];
966
- const connectPool = sPools.find(p => p.id === POOL_ID_CONNECT);
967
- const syncPool = sPools.find(p => p.id === POOL_ID_SYNC);
968
-
969
- if (connectPool && syncPool) {
970
- devLog('✓ Check: S contains both connect and sync challenge pools.');
971
- } else {
972
- devLog(`✗ Check: S is missing challenge pools! (connect: ${!!connectPool}, sync: ${!!syncPool})`);
973
- return;
974
- }
975
-
976
- // Verify S was successfully evolved (depleted connect pool)
977
- const remainingChallenges = Object.keys(connectPool.challenges).length;
978
- if (remainingChallenges === 0) {
979
- devLog('✓ Check: S connect pool successfully depleted (0 challenges remaining).');
980
- } else {
981
- devLog(`✗ Check: S connect pool not depleted! (${remainingChallenges} challenges remaining)`);
982
- return;
983
- }
984
-
985
- // we don't check this yet until sync ping pong
986
- // const targetAddrs = sessionIdentity.data?.frameDetails?.targetAddrs ?? [];
987
- // if (targetAddrs.includes(xAddr)) {
988
- // devLog('✓ Check: S is securely bound to target domain X in frameDetails.');
989
- // } else {
990
- // devLog('✗ Check: S is not bound to target domain X!');
991
- // }
992
-
993
- // 3. Verify WebSocket Connection is open and active
994
- if (debugState.senderPeer && debugState.senderPeer.isSocketOpen) {
995
- devLog('✓ Check: WebSocket connection is active and OPEN.');
996
- } else {
997
- devLog('✗ Check: WebSocket connection is NOT open or peer is missing!');
998
- return;
999
- }
1000
-
1001
- devLog('🎉 ALL PHASE 2B CONNECT CHECKS PASSED FLAWLESSLY! ✓');
1002
- btn.textContent = '✓ 2B All Passed';
1003
-
1004
- // Enable Phase 3B setup
1005
- const p3SetupBtn = document.getElementById('btn-3b-setup') as HTMLButtonElement | null;
1006
- if (p3SetupBtn) { p3SetupBtn.disabled = false; }
1007
-
1008
- } catch (error) {
1009
- devLog(`✗ 2B Check FAILED: ${extractErrorMsg(error)}`);
1010
- console.error(`${lc_fn} 2B Check error:`, error);
1011
- }
1012
- });
1013
- }
1014
-
1015
- function init3bSetupButton(): void {
1016
- const btn = document.getElementById('btn-3b-setup') as HTMLButtonElement | null;
1017
- if (!btn) { return; }
1018
- btn.addEventListener('click', () => {
1019
- performPhaseSetup({
1020
- phaseText: '3B',
1021
- btnId: 'btn-3b-setup',
1022
- nextBtnId: 'btn-3b-sync',
1023
- masterSecret: 'test-sender-secret-phase3',
1024
- syncSalt: 'senderidentitysyncsaltphase3',
1025
- manageSalt: 'senderidentitymanagesaltphase3',
1026
- ib: 'test data 3b',
1027
- data: { hello: 'world3', random: Math.random() }
1028
- });
1029
- });
1030
- }
1031
-
1032
- function init3bSyncButton(): void {
1033
- const btn = document.getElementById('btn-3b-sync') as HTMLButtonElement | null;
1034
- if (!btn) { return; }
1035
- btn.addEventListener('click', () => {
1036
- performPhaseSync({
1037
- phaseText: '3B',
1038
- btnId: 'btn-3b-sync',
1039
- nextBtnId: 'btn-3b-check'
1040
- });
1041
- });
1042
- }
1043
-
1044
- function init3bCheckButton(): void {
1045
- const lc_fn = `${lc}[init3bCheckButton]`;
1046
- const btn = document.getElementById('btn-3b-check') as HTMLButtonElement | null;
1047
- if (!btn) { return; }
1048
-
1049
- btn.addEventListener('click', async () => {
1050
- try {
1051
- debugger; // allow for walkthrough 3B check
1052
- devLog('3B Check: Asserting cryptographic and WebSocket state expectations...');
1053
-
1054
- const metaspace = await getGlobalMetaspace_waitIfNeeded();
1055
- const space = await metaspace.getLocalUserSpace({});
1056
- if (!space) { throw new Error("No default space."); }
1057
-
1058
- const domainI = debugState.domainI!;
1059
- const targetX = debugState.targetX!;
1060
- const xAddr = getIbGibAddr({ ibGib: targetX });
1061
- const domainAddr = getIbGibAddr({ ibGib: domainI });
1062
-
1063
- // 1. Assert Target X exists locally (with evolved timeline) and get latest local graph
1064
- const latestLocalXAddr = await metaspace.getLatestAddr({
1065
- addr: xAddr,
1066
- space
1067
- });
1068
- if (!latestLocalXAddr) {
1069
- devLog('✗ Check: Evolved target X NOT found in local space!');
1070
- return;
1071
- }
1072
- devLog(`✓ Check: Evolved target X found locally at: ${latestLocalXAddr}`);
1073
-
1074
- const localXGraph = await metaspace.getDependencyGraph({
1075
- ibGibAddr: latestLocalXAddr,
1076
- space
1077
- });
1078
- if (!localXGraph || Object.keys(localXGraph).length === 0) {
1079
- devLog('✗ Check: Failed to load target X dependency graph locally.');
1080
- return;
1081
- }
1082
- devLog(`✓ Check: Target X local graph loaded (${Object.keys(localXGraph).length} nodes).`);
1083
-
1084
- // 2. Fetch server's Target X graph via API bridge
1085
- const apiBridge = new SpaceGibApiBridge();
1086
- const serverGetRes = await apiBridge.getIbGibGraph(domainAddr, xAddr, true);
1087
- if (!serverGetRes.success || !serverGetRes.graph) {
1088
- devLog(`✗ Check: Failed to fetch target X graph from server: ${serverGetRes.message}`);
1089
- return;
1090
- }
1091
- const serverXGraph = serverGetRes.graph;
1092
- devLog(`✓ Check: Target X server graph loaded (${Object.keys(serverXGraph).length} nodes).`);
1093
-
1094
- // 3. Verify graphs are equivalent using graphsAreEquivalent
1095
- const equal = graphsAreEquivalent({ graphA: localXGraph, graphB: serverXGraph });
1096
- if (equal) {
1097
- devLog('✓ Check: Target X dependency graphs are equivalent on client and server.');
1098
- } else {
1099
- devLog('✗ Check: Target X dependency graphs mismatch between client and server!');
1100
- return;
1101
- }
1102
-
1103
- // 4. Assert evolved sender identity I1 exists locally and on server
1104
- const latestLocalIAddr = await metaspace.getLatestAddr({
1105
- addr: domainAddr,
1106
- space
1107
- });
1108
- if (!latestLocalIAddr) {
1109
- devLog('✗ Check: Evolved domain keystone tip I1 NOT found in local space!');
1110
- return;
1111
- }
1112
- devLog(`✓ Check: Evolved Domain Keystone (I1) exists locally.`);
1113
-
1114
- const getRes = await metaspace.get({ addrs: [latestLocalIAddr], space });
1115
- const localI = getRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
1116
- if (!localI) {
1117
- devLog('✗ Check: Failed to load I1 from local space.');
1118
- return;
1119
- }
1120
-
1121
- const syncProof = localI.data?.proofs?.find(p => p.claim?.verb === 'sync');
1122
- const sessionIdentityTjpAddr = syncProof?.claim?.target;
1123
- if (!sessionIdentityTjpAddr) {
1124
- devLog('✗ Check: I1 sync claim does not target a session keystone.');
1125
- return;
1126
- }
1127
-
1128
- const serverIGetRes = await apiBridge.getIbGib(domainAddr, latestLocalIAddr);
1129
- if (!serverIGetRes.success || !serverIGetRes.ibGib) {
1130
- devLog(`✗ Check: Evolved Domain Keystone (I1) NOT found on server!`);
1131
- return;
1132
- }
1133
- devLog(`✓ Check: Evolved Domain Keystone (I1) exists on server.`);
1134
-
1135
- // 5. Assert session identity S tip exists locally and on server
1136
- const latestLocalSAddr = await metaspace.getLatestAddr({
1137
- addr: sessionIdentityTjpAddr,
1138
- space
1139
- });
1140
- if (!latestLocalSAddr) {
1141
- devLog('✗ Check: Latest Session Keystone (S) NOT found in local space.');
1142
- return;
1143
- }
1144
- devLog(`✓ Check: Found latest session keystone (S) locally: ${latestLocalSAddr}`);
1145
-
1146
- const localSRes = await metaspace.get({ addrs: [latestLocalSAddr], space });
1147
- const sessionS = localSRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
1148
- if (!sessionS) {
1149
- devLog('✗ Check: Failed to load latest Session Keystone (S) locally.');
1150
- return;
1151
- }
1152
-
1153
- // Verify S evolved to correct n (n === 3 or 4)
1154
- const n = sessionS.data?.n;
1155
- devLog(`✓ Check: S tip evolved to n = ${n}.`);
1156
- if (n !== 3 && n !== 4) {
1157
- devLog(`⚠ Check: Expected S to evolve to n = 3 or 4, got n = ${n}. Continuing anyway...`);
1158
- }
1159
-
1160
- const serverSGetRes = await apiBridge.getIbGib(domainAddr, latestLocalSAddr);
1161
- if (!serverSGetRes.success || !serverSGetRes.ibGib) {
1162
- devLog(`✗ Check: Latest Session Keystone (S) NOT found on server!`);
1163
- return;
1164
- }
1165
- devLog(`✓ Check: Latest Session Keystone (S) exists on server.`);
1166
-
1167
- // 6. Assert S graph is identical on client and server
1168
- const localSGraph = await metaspace.getDependencyGraph({
1169
- ibGibAddr: latestLocalSAddr,
1170
- space
1171
- });
1172
- const serverSGetGraphRes = await apiBridge.getIbGibGraph(domainAddr, sessionIdentityTjpAddr, true);
1173
- if (!serverSGetGraphRes.success || !serverSGetGraphRes.graph) {
1174
- devLog(`✗ Check: Failed to fetch session S graph from server: ${serverSGetGraphRes.message}`);
1175
- return;
1176
- }
1177
- const serverSGraph = serverSGetGraphRes.graph;
1178
-
1179
- const sGraphsEqual = graphsAreEquivalent({ graphA: localSGraph, graphB: serverSGraph });
1180
- if (sGraphsEqual) {
1181
- devLog('✓ Check: Session Keystone (S) dependency graphs are equivalent on client and server.');
1182
- } else {
1183
- devLog('✗ Check: Session Keystone (S) dependency graphs mismatch between client and server!');
1184
- return;
1185
- }
1186
-
1187
- devLog('🎉 ALL PHASE 3B TRANSACTION SYNC CHECKS PASSED FLAWLESSLY! ✓');
1188
- btn.textContent = '✓ 3B All Passed';
1189
-
1190
- } catch (error) {
1191
- devLog(`✗ 3B Check FAILED: ${extractErrorMsg(error)}`);
1192
- console.error(`${lc_fn} 3B Check error:`, error);
1193
- }
1194
- });
1195
- }
1196
-
1197
- // ---------------------------------------------------------------------------
1198
- // Dev Tools UI Init
1199
- // ---------------------------------------------------------------------------
12
+ initWsTestButton, initPrintStateButton, initCreateDomainKeystoneButton,
13
+ initCreateTestIbGibButton, initCreateSessionKeystoneButton
14
+ } from './dev-tools/base-tools.mjs';
15
+ import { init1bSetupButton, init1bSyncButton, init1bCheckButton } from './dev-tools/phase-1.mjs';
16
+ import { init2bSetupButton, init2bSyncButton, init2bCheckButton } from './dev-tools/phase-2.mjs';
17
+ import { init3bSetupButton, init3bSyncButton, init3bCheckButton } from './dev-tools/phase-3.mjs';
18
+ import { init4_1bSetupButton, init4_1bSyncButton, init4_1bCheckButton } from './dev-tools/phase-4-1.mjs';
19
+ import { init4_2bSetupButton, init4_2bSyncButton, init4_2bCheckButton } from './dev-tools/phase-4-2.mjs';
20
+ import { init4_3bSetupButton, init4_3bSyncButton, init4_3bCheckButton } from './dev-tools/phase-4-3.mjs';
21
+ import { init4_4bSetupButton, init4_4bSyncButton, init4_4bCheckButton } from './dev-tools/phase-4-4.mjs';
22
+ import { init4_5bSetupButton, init4_5bSyncButton, init4_5bCheckButton } from './dev-tools/phase-4-5.mjs';
23
+ import { init4_6bSetupButton, init4_6bSyncButton, init4_6bCheckButton } from './dev-tools/phase-4-6.mjs';
24
+ import { init4_7bSetupButton, init4_7bSyncButton, init4_7bCheckButton } from './dev-tools/phase-4-7.mjs';
25
+ import { init4_8bSetupButton, init4_8bSyncButton, init4_8bCheckButton } from './dev-tools/phase-4-8.mjs';
26
+ import { init4_9bSetupButton, init4_9bSyncButton, init4_9bCheckButton } from './dev-tools/phase-4-9.mjs';
27
+ import { init4_10bSetupButton, init4_10bSyncButton, init4_10bCheckButton } from './dev-tools/phase-4-10.mjs';
28
+
29
+ export { devLog, debugState };
1200
30
 
1201
31
  /**
1202
32
  * Call once inside DOMContentLoaded to wire up all dev-tool buttons.
@@ -1209,8 +39,6 @@ export function initDevTools(): void {
1209
39
  initWsTestButton();
1210
40
  initCreateTestIbGibButton();
1211
41
  initCreateSessionKeystoneButton();
1212
- initEvolveDomainKeystoneButton();
1213
- initPerformSyncButton();
1214
42
  init1bSetupButton();
1215
43
  init1bSyncButton();
1216
44
  init1bCheckButton();
@@ -1220,6 +48,36 @@ export function initDevTools(): void {
1220
48
  init3bSetupButton();
1221
49
  init3bSyncButton();
1222
50
  init3bCheckButton();
51
+ init4_1bSetupButton();
52
+ init4_1bSyncButton();
53
+ init4_1bCheckButton();
54
+ init4_2bSetupButton();
55
+ init4_2bSyncButton();
56
+ init4_2bCheckButton();
57
+ init4_3bSetupButton();
58
+ init4_3bSyncButton();
59
+ init4_3bCheckButton();
60
+ init4_4bSetupButton();
61
+ init4_4bSyncButton();
62
+ init4_4bCheckButton();
63
+ init4_5bSetupButton();
64
+ init4_5bSyncButton();
65
+ init4_5bCheckButton();
66
+ init4_6bSetupButton();
67
+ init4_6bSyncButton();
68
+ init4_6bCheckButton();
69
+ init4_7bSetupButton();
70
+ init4_7bSyncButton();
71
+ init4_7bCheckButton();
72
+ init4_8bSetupButton();
73
+ init4_8bSyncButton();
74
+ init4_8bCheckButton();
75
+ init4_9bSetupButton();
76
+ init4_9bSyncButton();
77
+ init4_9bCheckButton();
78
+ init4_10bSetupButton();
79
+ init4_10bSyncButton();
80
+ init4_10bCheckButton();
1223
81
  } catch (error) {
1224
82
  console.error(`${lc_fn} ${extractErrorMsg(error)}`);
1225
83
  }