@ibgib/space-gib 0.0.2 → 0.0.4

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 (67) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/IMPLEMENTATION.md +9 -13
  3. package/dist/client/bootstrap.mjs +1 -1
  4. package/dist/client/bootstrap.mjs.map +1 -1
  5. package/dist/client/chunk-NCXKCVYS.mjs +42 -0
  6. package/dist/client/chunk-NCXKCVYS.mjs.map +7 -0
  7. package/dist/client/chunk-ZUEU37Z5.mjs +1920 -0
  8. package/dist/client/chunk-ZUEU37Z5.mjs.map +7 -0
  9. package/dist/client/index.html +108 -8
  10. package/dist/client/index.mjs +1 -1
  11. package/dist/client/script.mjs +1 -1
  12. package/dist/client/style.css +466 -61
  13. package/dist/respec-gib.node.mjs +5 -0
  14. package/dist/server/server.mjs +815 -316
  15. package/dist/server/server.mjs.map +4 -4
  16. package/package.json +6 -6
  17. package/src/client/AUTO-GENERATED-version.mts +1 -1
  18. package/src/client/api/space-gib-api-bridge.mts +35 -0
  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 +55 -1096
  47. package/src/client/index.html +108 -8
  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 +4 -6
  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-evolve.handler.mts +1 -1
  57. package/src/server/serve-gib/handlers/api/keystone/keystone-genesis.handler.mts +1 -1
  58. package/src/server/serve-gib/handlers/api/keystone/keystone-get.respec.mts +4 -4
  59. package/src/server/serve-gib/handlers/api/keystone/keystone-post.handler.mts +1 -1
  60. package/src/server/serve-gib/handlers/ws/sync-upgrade-handler-base.mts +37 -5
  61. package/src/server/serve-gib/handlers/ws/ws-helper.mts +73 -45
  62. package/dist/client/chunk-BL2SGXS4.mjs +0 -18994
  63. package/dist/client/chunk-RDTAT5G4.mjs +0 -235
  64. package/dist/client/chunk-RDTAT5G4.mjs.map +0 -7
  65. package/dist/client/chunk-RE7XSMHH.mjs +0 -31
  66. package/dist/client/chunk-RE7XSMHH.mjs.map +0 -7
  67. package/dist/client/chunk-YUSGN3J4.mjs +0 -23119
@@ -0,0 +1,388 @@
1
+ import { extractErrorMsg, getUUID, getTimestamp } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
2
+ import { Factory_V1 as factory } from '@ibgib/ts-gib/dist/V1/factory.mjs';
3
+ import { ROOT } from '@ibgib/ts-gib/dist/V1/constants.mjs';
4
+ import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
5
+ import { KeystoneIbGib_V1 } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs';
6
+ import { KeystoneService_V1 } from '@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs';
7
+ import { getGlobalMetaspace_waitIfNeeded } from "@ibgib/web-gib/dist/helpers.mjs";
8
+ import { mut8Timeline } from '@ibgib/core-gib/dist/timeline/timeline-api.mjs';
9
+ import { graphsAreEquivalent } from '@ibgib/core-gib/dist/common/other/graph-helper.mjs';
10
+ import { SyncPeerWebSocketSender_V1 } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs';
11
+ import { SyncSagaCoordinator } from '@ibgib/core-gib/dist/sync/sync-saga-coordinator.mjs';
12
+ import { SyncConflictStrategy } from '@ibgib/core-gib/dist/sync/sync-constants.mjs';
13
+ import { SESSION_KEYSTONE_POLICY, getSpaceGibPoolConfig } from "../../common/keystone-policies.mjs";
14
+ import { SpaceGibApiBridge } from '../api/space-gib-api-bridge.mjs';
15
+
16
+ import { debugState, devLog, lc, performPhaseSetup } from './common.mjs';
17
+
18
+ export function init4_2bSetupButton(): void {
19
+ const btn = document.getElementById('btn-4-2b-setup') as HTMLButtonElement | null;
20
+ if (!btn) { return; }
21
+ btn.addEventListener('click', () => {
22
+ performPhaseSetup({
23
+ phaseText: '4.2B',
24
+ btnId: 'btn-4-2b-setup',
25
+ nextBtnId: 'btn-4-2b-sync',
26
+ masterSecret: 'test-sender-secret-phase4-2',
27
+ syncSalt: 'senderidentitysyncsaltphase4-2',
28
+ manageSalt: 'senderidentitymanagesaltphase4-2',
29
+ ib: 'dummy target 4.2b',
30
+ data: { hello: 'dummy' }
31
+ });
32
+ });
33
+ }
34
+
35
+ async function performPhaseSync4_2b(): Promise<void> {
36
+ const lc_fn = `${lc}[performPhaseSync4_2b]`;
37
+ const btn = document.getElementById('btn-4-2b-sync') as HTMLButtonElement | null;
38
+ if (!btn) { return; }
39
+
40
+ try {
41
+ btn.disabled = true;
42
+ devLog(`4.2B Sync: Creating Constants and executing three-pass WebSocket Sync...`);
43
+
44
+ const domainI = debugState.domainI;
45
+ if (!domainI) {
46
+ devLog(`⚠ 4.2B Sync: Missing setup state. Please run Setup first.`);
47
+ btn.disabled = false;
48
+ return;
49
+ }
50
+
51
+ const domainAddr = getIbGibAddr({ ibGib: domainI });
52
+ const metaspace = await getGlobalMetaspace_waitIfNeeded();
53
+ const space = await metaspace.getLocalUserSpace({});
54
+ if (!space) { throw new Error("No default space."); }
55
+
56
+ // 1. Create Constant C1 locally
57
+ const c1 = await factory.constant({
58
+ parentPrimitiveIb: 'root',
59
+ ib: 'constant_c1_' + (await getUUID()).slice(0, 8),
60
+ data: { some: 'data_4_2b', random: Math.random() },
61
+ });
62
+ const addrC1 = getIbGibAddr({ ibGib: c1 });
63
+ await metaspace.put({ ibGib: c1, space });
64
+ await metaspace.registerNewIbGib({ ibGib: c1 });
65
+ debugState.targetC1 = c1;
66
+ devLog(`4.2B Sync: ✓ Constant C1 created: ${addrC1}`);
67
+
68
+ // --- Sync 1: C1 First Pass ---
69
+ devLog(`4.2B Sync: Starting Pass 1 (Sync C1)...`);
70
+ const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
71
+ let senderPeer = new SyncPeerWebSocketSender_V1({
72
+ classname: 'SyncPeerWebSocketSender_V1',
73
+ httpEvolveUrl: `${location.protocol}//${location.host}/api/keystone/evolve/${encodeURIComponent(domainAddr)}`,
74
+ wsUrl: `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}`
75
+ });
76
+
77
+ let coordinator = new SyncSagaCoordinator();
78
+ let sagaId = await getUUID();
79
+ debugState.sagaId = sagaId;
80
+ debugState.senderPeer = senderPeer;
81
+
82
+ await senderPeer.initializeOpts({
83
+ localMetaspace: metaspace,
84
+ localSpace: space,
85
+ senderIdentity: domainI,
86
+ fnSenderSecret: async () => debugState.domainIMasterSecret!,
87
+ sagaId,
88
+ sessionConnectPoolConfig: SESSION_KEYSTONE_POLICY.CONNECT_POOL as any,
89
+ sessionSyncPoolConfig: SESSION_KEYSTONE_POLICY.DEFAULT_POOL as any,
90
+ targetAddrs: [domainAddr]
91
+ });
92
+
93
+ let syncSaga = await coordinator.sync({
94
+ domainIbGibs: [c1],
95
+ senderIdentity: domainI,
96
+ fnSenderSecret: async () => debugState.domainIMasterSecret!,
97
+ peer: senderPeer,
98
+ localSpace: space,
99
+ metaspace,
100
+ conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
101
+ });
102
+ await syncSaga.done;
103
+ devLog(`4.2B Sync: ✓ Pass 1 Complete.`);
104
+
105
+ const latestSenderAddr1 = await metaspace.getLatestAddr({
106
+ addr: getIbGibAddr({ ibGib: domainI }),
107
+ space,
108
+ });
109
+ const resGetLatestI1 = await metaspace.get({ addrs: [latestSenderAddr1!], space });
110
+ const senderIdentityEvolved1 = resGetLatestI1.ibGibs![0] as KeystoneIbGib_V1;
111
+
112
+ // --- Sync 2: C1 Second Pass (Idempotent check) ---
113
+ devLog(`4.2B Sync: Starting Pass 2 (Sync C1 - Idempotent)...`);
114
+ senderPeer = new SyncPeerWebSocketSender_V1({
115
+ classname: 'SyncPeerWebSocketSender_V1',
116
+ httpEvolveUrl: `${location.protocol}//${location.host}/api/keystone/evolve/${encodeURIComponent(domainAddr)}`,
117
+ wsUrl: `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}`
118
+ });
119
+ coordinator = new SyncSagaCoordinator();
120
+ sagaId = await getUUID();
121
+ debugState.sagaId = sagaId;
122
+ debugState.senderPeer = senderPeer;
123
+
124
+ await senderPeer.initializeOpts({
125
+ localMetaspace: metaspace,
126
+ localSpace: space,
127
+ senderIdentity: senderIdentityEvolved1,
128
+ fnSenderSecret: async () => debugState.domainIMasterSecret!,
129
+ sagaId,
130
+ sessionConnectPoolConfig: SESSION_KEYSTONE_POLICY.CONNECT_POOL as any,
131
+ sessionSyncPoolConfig: SESSION_KEYSTONE_POLICY.DEFAULT_POOL as any,
132
+ targetAddrs: [domainAddr]
133
+ });
134
+
135
+ syncSaga = await coordinator.sync({
136
+ domainIbGibs: [c1],
137
+ senderIdentity: senderIdentityEvolved1,
138
+ fnSenderSecret: async () => debugState.domainIMasterSecret!,
139
+ peer: senderPeer,
140
+ localSpace: space,
141
+ metaspace,
142
+ conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
143
+ });
144
+ await syncSaga.done;
145
+ devLog(`4.2B Sync: ✓ Pass 2 Complete.`);
146
+
147
+ const latestSenderAddr2 = await metaspace.getLatestAddr({
148
+ addr: getIbGibAddr({ ibGib: domainI }),
149
+ space,
150
+ });
151
+ const resGetLatestI2 = await metaspace.get({ addrs: [latestSenderAddr2!], space });
152
+ const senderIdentityEvolved2 = resGetLatestI2.ibGibs![0] as KeystoneIbGib_V1;
153
+
154
+ // 2. Create Constant C2 locally linking to C1
155
+ const c2 = await factory.constant({
156
+ ib: 'constant_c2_' + (await getUUID()).slice(0, 8),
157
+ parentPrimitiveIb: 'root',
158
+ rel8ns: {
159
+ link: [addrC1],
160
+ },
161
+ });
162
+ const addrC2 = getIbGibAddr({ ibGib: c2 });
163
+ await metaspace.put({ ibGib: c2, space });
164
+ await metaspace.registerNewIbGib({ ibGib: c2 });
165
+ debugState.targetC2 = c2;
166
+ devLog(`4.2B Sync: ✓ Constant C2 created linking to C1: ${addrC2}`);
167
+
168
+ // --- Sync 3: C2 Pass ---
169
+ devLog(`4.2B Sync: Starting Pass 3 (Sync C2)...`);
170
+ senderPeer = new SyncPeerWebSocketSender_V1({
171
+ classname: 'SyncPeerWebSocketSender_V1',
172
+ httpEvolveUrl: `${location.protocol}//${location.host}/api/keystone/evolve/${encodeURIComponent(domainAddr)}`,
173
+ wsUrl: `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}`
174
+ });
175
+ coordinator = new SyncSagaCoordinator();
176
+ sagaId = await getUUID();
177
+ debugState.sagaId = sagaId;
178
+ debugState.senderPeer = senderPeer;
179
+
180
+ await senderPeer.initializeOpts({
181
+ localMetaspace: metaspace,
182
+ localSpace: space,
183
+ senderIdentity: senderIdentityEvolved2,
184
+ fnSenderSecret: async () => debugState.domainIMasterSecret!,
185
+ sagaId,
186
+ sessionConnectPoolConfig: SESSION_KEYSTONE_POLICY.CONNECT_POOL as any,
187
+ sessionSyncPoolConfig: SESSION_KEYSTONE_POLICY.DEFAULT_POOL as any,
188
+ targetAddrs: [domainAddr]
189
+ });
190
+
191
+ syncSaga = await coordinator.sync({
192
+ domainIbGibs: [c2],
193
+ senderIdentity: senderIdentityEvolved2,
194
+ fnSenderSecret: async () => debugState.domainIMasterSecret!,
195
+ peer: senderPeer,
196
+ localSpace: space,
197
+ metaspace,
198
+ conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
199
+ });
200
+ await syncSaga.done;
201
+ devLog(`4.2B Sync: ✓ Pass 3 Complete.`);
202
+
203
+ devLog(`✓ 4.2B Sync Sequence Complete! Ready for State Checks.`);
204
+ btn.textContent = `✓ 4.2B Sync Run`;
205
+
206
+ const checkBtn = document.getElementById('btn-4-2b-check') as HTMLButtonElement | null;
207
+ if (checkBtn) { checkBtn.disabled = false; }
208
+
209
+ } catch (error) {
210
+ devLog(`✗ 4.2B Sync FAILED: ${extractErrorMsg(error)}`);
211
+ console.error(`${lc_fn} 4.2B Sync error:`, error);
212
+ btn.disabled = false;
213
+ }
214
+ }
215
+
216
+ export function init4_2bSyncButton(): void {
217
+ const btn = document.getElementById('btn-4-2b-sync') as HTMLButtonElement | null;
218
+ if (!btn) { return; }
219
+ btn.addEventListener('click', () => {
220
+ performPhaseSync4_2b();
221
+ });
222
+ }
223
+
224
+ export function init4_2bCheckButton(): void {
225
+ const lc_fn = `${lc}[init4_2bCheckButton]`;
226
+ const btn = document.getElementById('btn-4-2b-check') as HTMLButtonElement | null;
227
+ if (!btn) { return; }
228
+
229
+ btn.addEventListener('click', async () => {
230
+ try {
231
+ devLog('4.2B Check: Asserting cryptographic and WebSocket state expectations...');
232
+
233
+ const metaspace = await getGlobalMetaspace_waitIfNeeded();
234
+ const space = await metaspace.getLocalUserSpace({});
235
+ if (!space) { throw new Error("No default space."); }
236
+
237
+ const domainI = debugState.domainI!;
238
+ const targetC1 = debugState.targetC1!;
239
+ const targetC2 = debugState.targetC2!;
240
+ const c1Addr = getIbGibAddr({ ibGib: targetC1 });
241
+ const c2Addr = getIbGibAddr({ ibGib: targetC2 });
242
+ const domainAddr = getIbGibAddr({ ibGib: domainI });
243
+
244
+ // 1. Verify C1 and C2 exist locally
245
+ const localC1Res = await metaspace.get({ addrs: [c1Addr], space });
246
+ const localC2Res = await metaspace.get({ addrs: [c2Addr], space });
247
+ if (!localC1Res.success || !localC1Res.ibGibs?.[0]) {
248
+ devLog('✗ Check: Constant C1 NOT found locally.');
249
+ return;
250
+ }
251
+ if (!localC2Res.success || !localC2Res.ibGibs?.[0]) {
252
+ devLog('✗ Check: Constant C2 NOT found locally.');
253
+ return;
254
+ }
255
+ devLog(`✓ Check: Constants C1 and C2 exist locally.`);
256
+
257
+ // 2. Fetch server's graphs for C1 and C2
258
+ const apiBridge = new SpaceGibApiBridge();
259
+ const serverC1Res = await apiBridge.getIbGib(domainAddr, c1Addr);
260
+ const serverC2Res = await apiBridge.getIbGib(domainAddr, c2Addr);
261
+ if (!serverC1Res.success || !serverC1Res.ibGib) {
262
+ devLog(`✗ Check: Constant C1 NOT found on server: ${serverC1Res.message}`);
263
+ return;
264
+ }
265
+ if (!serverC2Res.success || !serverC2Res.ibGib) {
266
+ devLog(`✗ Check: Constant C2 NOT found on server: ${serverC2Res.message}`);
267
+ return;
268
+ }
269
+ devLog(`✓ Check: Constants C1 and C2 exist on server.`);
270
+
271
+ const localC2Graph = await metaspace.getDependencyGraph({
272
+ ibGibAddr: c2Addr,
273
+ space
274
+ });
275
+ const serverC2GetGraphRes = await apiBridge.getIbGibGraph(domainAddr, c2Addr, true);
276
+ if (!serverC2GetGraphRes.success || !serverC2GetGraphRes.graph) {
277
+ devLog(`✗ Check: Failed to fetch C2 graph from server: ${serverC2GetGraphRes.message}`);
278
+ return;
279
+ }
280
+ const serverC2Graph = serverC2GetGraphRes.graph;
281
+
282
+ const c2GraphsEqual = graphsAreEquivalent({ graphA: localC2Graph, graphB: serverC2Graph });
283
+ if (c2GraphsEqual) {
284
+ devLog('✓ Check: C2 dependency graphs are equivalent on client and server.');
285
+ } else {
286
+ devLog('✗ Check: C2 dependency graphs mismatch between client and server!');
287
+ return;
288
+ }
289
+
290
+ // 3. Verify evolved sender identity I exists locally and on server, n = 3
291
+ const latestLocalIAddr = await metaspace.getLatestAddr({
292
+ addr: domainAddr,
293
+ space
294
+ });
295
+ if (!latestLocalIAddr) {
296
+ devLog('✗ Check: Evolved domain keystone tip I3 NOT found in local space!');
297
+ return;
298
+ }
299
+ const localIRes = await metaspace.get({ addrs: [latestLocalIAddr], space });
300
+ const localI = localIRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
301
+ if (!localI) {
302
+ devLog('✗ Check: Failed to load evolved I from local space.');
303
+ return;
304
+ }
305
+ devLog(`✓ Check: Evolved Domain Keystone exists locally: ${latestLocalIAddr}`);
306
+
307
+ const nI = localI.data?.n;
308
+ devLog(`✓ Check: Evolved I tip is at n = ${nI}.`);
309
+ if (nI !== 3) {
310
+ devLog(`✗ Check: Expected I to evolve to n = 3, got n = ${nI}.`);
311
+ return;
312
+ }
313
+
314
+ const serverIGetRes = await apiBridge.getIbGib(domainAddr, latestLocalIAddr);
315
+ if (!serverIGetRes.success || !serverIGetRes.ibGib) {
316
+ devLog(`✗ Check: Evolved Domain Keystone tip NOT found on server!`);
317
+ return;
318
+ }
319
+ devLog(`✓ Check: Evolved Domain Keystone tip exists on server.`);
320
+
321
+ // 4. Verify session identity S tip exists locally and on server
322
+ const syncProof = localI.data?.proofs?.find(p => p.claim?.verb === 'sync');
323
+ const sessionIdentityTjpAddr = syncProof?.claim?.target;
324
+ if (!sessionIdentityTjpAddr) {
325
+ devLog('✗ Check: Evolved I sync claim does not target a session keystone.');
326
+ return;
327
+ }
328
+
329
+ const latestLocalSAddr = await metaspace.getLatestAddr({
330
+ addr: sessionIdentityTjpAddr,
331
+ space
332
+ });
333
+ if (!latestLocalSAddr) {
334
+ devLog('✗ Check: Latest Session Keystone (S) NOT found in local space.');
335
+ return;
336
+ }
337
+ devLog(`✓ Check: Found latest session keystone (S) locally: ${latestLocalSAddr}`);
338
+
339
+ const localSRes = await metaspace.get({ addrs: [latestLocalSAddr], space });
340
+ const sessionS = localSRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
341
+ if (!sessionS) {
342
+ devLog('✗ Check: Failed to load latest Session Keystone (S) locally.');
343
+ return;
344
+ }
345
+
346
+ const nS = sessionS.data?.n;
347
+ devLog(`✓ Check: Latest session S tip evolved to n = ${nS}.`);
348
+ if (nS !== 3) {
349
+ devLog(`✗ Check: Expected latest session S to evolve to n = 3, got n = ${nS}.`);
350
+ return;
351
+ }
352
+
353
+ const serverSGetRes = await apiBridge.getIbGib(domainAddr, latestLocalSAddr);
354
+ if (!serverSGetRes.success || !serverSGetRes.ibGib) {
355
+ devLog(`✗ Check: Latest Session Keystone (S) NOT found on server!`);
356
+ return;
357
+ }
358
+ devLog(`✓ Check: Latest Session Keystone (S) exists on server.`);
359
+
360
+ // 5. Assert S graph is identical on client and server
361
+ const localSGraph = await metaspace.getDependencyGraph({
362
+ ibGibAddr: latestLocalSAddr,
363
+ space
364
+ });
365
+ const serverSGetGraphRes = await apiBridge.getIbGibGraph(domainAddr, sessionIdentityTjpAddr, true);
366
+ if (!serverSGetGraphRes.success || !serverSGetGraphRes.graph) {
367
+ devLog(`✗ Check: Failed to fetch session S graph from server: ${serverSGetGraphRes.message}`);
368
+ return;
369
+ }
370
+ const serverSGraph = serverSGetGraphRes.graph;
371
+
372
+ const sGraphsEqual = graphsAreEquivalent({ graphA: localSGraph, graphB: serverSGraph });
373
+ if (sGraphsEqual) {
374
+ devLog('✓ Check: Session Keystone (S) dependency graphs are equivalent on client and server.');
375
+ } else {
376
+ devLog('✗ Check: Session Keystone (S) dependency graphs mismatch between client and server!');
377
+ return;
378
+ }
379
+
380
+ devLog('🎉 ALL PHASE 4.2B TRANSACTION SYNC CHECKS PASSED FLAWLESSLY! ✓');
381
+ btn.textContent = '✓ 4.2B All Passed';
382
+
383
+ } catch (error) {
384
+ devLog(`✗ 4.2B Check FAILED: ${extractErrorMsg(error)}`);
385
+ console.error(`${lc_fn} 4.2B Check error:`, error);
386
+ }
387
+ });
388
+ }