@ibgib/core-gib 0.1.44 → 0.1.47

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 (31) hide show
  1. package/dist/keystone/keystone-constants.d.mts +9 -0
  2. package/dist/keystone/keystone-constants.d.mts.map +1 -1
  3. package/dist/keystone/keystone-constants.mjs +9 -0
  4. package/dist/keystone/keystone-constants.mjs.map +1 -1
  5. package/dist/keystone/keystone-helpers.d.mts +19 -0
  6. package/dist/keystone/keystone-helpers.d.mts.map +1 -1
  7. package/dist/keystone/keystone-helpers.mjs +292 -4
  8. package/dist/keystone/keystone-helpers.mjs.map +1 -1
  9. package/dist/keystone/keystone-types.d.mts +2 -0
  10. package/dist/keystone/keystone-types.d.mts.map +1 -1
  11. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  12. package/dist/sync/sync-peer/sync-peer-v1.mjs +12 -3
  13. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  14. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +0 -38
  15. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  16. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +1 -83
  17. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  18. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +24 -4
  19. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
  20. package/dist/sync/sync-saga-coordinator.d.mts +14 -2
  21. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  22. package/dist/sync/sync-saga-coordinator.mjs +128 -11
  23. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  24. package/package.json +1 -1
  25. package/src/keystone/keystone-constants.mts +9 -0
  26. package/src/keystone/keystone-helpers.mts +320 -5
  27. package/src/keystone/keystone-types.mts +4 -1
  28. package/src/sync/sync-peer/sync-peer-v1.mts +13 -3
  29. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +3 -107
  30. package/src/sync/sync-saga-context/sync-saga-context-types.mts +25 -4
  31. package/src/sync/sync-saga-coordinator.mts +159 -9
@@ -1,4 +1,5 @@
1
- import { extractErrorMsg, hash, pretty } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
1
+ import { extractErrorMsg, hash, HashAlgorithm, pretty } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
2
+ import { GIB } from "@ibgib/ts-gib/dist/V1/constants.mjs";
2
3
  import { Ib, TransformResult } from "@ibgib/ts-gib/dist/types.mjs";
3
4
  import { getIbAndGib, getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
4
5
  import { validateIbGibIntrinsically } from "@ibgib/ts-gib/dist/V1/validate-helper.mjs";
@@ -7,12 +8,23 @@ import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
7
8
  import { getGib } from "@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs";
8
9
 
9
10
  import { GLOBAL_LOG_A_LOT } from "../core-constants.mjs";
10
- import { KEYSTONE_ATOM } from "./keystone-constants.mjs";
11
- import { KeystoneData_V1, KeystoneIbGib_V1, KeystoneIb_V1, KeystoneChallengePool, DeterministicResult, KeystoneProof, KeystonePoolConfig, KeystoneReplenishStrategy, KEYSTONE_REPLENISH_STRATEGY_VALID_VALUES, KeystoneClaim, KeystoneSolution } from "./keystone-types.mjs";
11
+ import { KEYSTONE_ATOM, KEYSTONE_HASH_MAX_ROUNDS, KEYSTONE_POOL_ID_REGEXP, KEYSTONE_SALT_REGEXP } from "./keystone-constants.mjs";
12
+ import {
13
+ KeystoneData_V1, KeystoneIbGib_V1, KeystoneIb_V1, KeystoneChallengePool,
14
+ DeterministicResult, KeystoneProof, KeystonePoolConfig,
15
+ KeystoneReplenishStrategy, KEYSTONE_REPLENISH_STRATEGY_VALID_VALUES,
16
+ KeystoneClaim, KeystoneSolution,
17
+ KeystoneChallengeType,
18
+ KEYSTONE_CHALLENGE_TYPE_VALID_VALUES,
19
+ KeystonePoolConfig_HashV1,
20
+ } from "./keystone-types.mjs";
12
21
  import { MetaspaceService } from "../witness/space/metaspace/metaspace-types.mjs";
13
22
  import { IbGibSpaceAny } from "../witness/space/space-base-v1.mjs";
14
23
  import { KeystoneStrategyFactory } from "./strategy/keystone-strategy-factory.mjs";
15
- import { GIB } from "@ibgib/ts-gib/dist/V1/constants.mjs";
24
+ import { getDependencyGraph } from "../common/other/graph-helper.mjs";
25
+ import { getIbGibsFromCache_fallbackToSpaces, getTimelinesGroupedByTjp, splitPerTjpAndOrDna } from "../common/other/ibgib-helper.mjs";
26
+ import { IbGib_V1, IbGibData_V1, IbGibRel8ns_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
27
+ import { getLatestAddrs } from "../witness/space/space-helper.mjs";
16
28
 
17
29
  const logalot = GLOBAL_LOG_A_LOT;
18
30
 
@@ -512,6 +524,156 @@ export async function solveAndReplenish({
512
524
  }
513
525
  }
514
526
 
527
+ export async function validateChallengePool_typeHashRevealV1({ pool }: {
528
+ pool: KeystoneChallengePool;
529
+ }): Promise<string[]> {
530
+ const lc = `[${validateChallengePool_typeHashRevealV1.name}]`;
531
+ try {
532
+ if (logalot) { console.log(`${lc} starting... (I: e2ffd568b698cc12d8c5e838d73ae726)`); }
533
+
534
+ if (!pool.config) { throw new Error(`(UNEXPECTED) pool.configy falsy? (E: fcde88fe20e8004a58d7e445436bf526)`); }
535
+ if (pool.config.type !== KeystoneChallengeType.hash_reveal_v1) {
536
+ throw new Error(`(UNEXPECTED) pool.config.type !== KeystoneChallengeType.hash_reveal_v1? (E: e205f8872909c37168a624a9df778c26)`);
537
+ }
538
+
539
+ const errors: string[] = [];
540
+
541
+ const { algo, rounds, salt, } = pool.config as KeystonePoolConfig_HashV1;
542
+
543
+ const validAlgos: HashAlgorithm[] = [HashAlgorithm.sha_256];
544
+ if (algo) {
545
+ if (!validAlgos.includes(algo)) {
546
+ errors.push(`${lc} invalid hash algorithm (${algo}). Must be one of ${validAlgos}. (E: a22399ca3a68e63ffcc7507699be5826)`);
547
+ }
548
+ } else {
549
+ errors.push(`${lc} algorithm required. (E: 8cd6bfb0590862b9bae24d98d2cf3826)`)
550
+ }
551
+
552
+ if (rounds && typeof rounds === 'number' && Number.isInteger(rounds)) {
553
+ if (rounds > KEYSTONE_HASH_MAX_ROUNDS) {
554
+ errors.push(`${lc} rounds too high. max rounds: ${KEYSTONE_HASH_MAX_ROUNDS} (E: 31ce082f7fd88d6b58ef08a816458826)`);
555
+ }
556
+ } else {
557
+ errors.push(`${lc} invalid rounds (${rounds}). must be positive integer. (E: 73c643ccda78afaf28d52a6871a9e826)`);
558
+ }
559
+
560
+ if (salt && typeof salt === 'string') {
561
+ // no limits on this? sanity check?
562
+ if (!KEYSTONE_SALT_REGEXP.test(salt)) {
563
+ errors.push(`${lc} invalid salt (${salt.substring(0, 99)}). Must match regexp ${KEYSTONE_SALT_REGEXP}`);
564
+ }
565
+ } else {
566
+ errors.push(`${lc} invalid salt (${salt}). must be truthy string value. (E: 564a4844ec88fc1988197ce89c381426)`);
567
+ }
568
+
569
+ return errors;
570
+
571
+ } catch (error) {
572
+ console.error(`${lc} ${extractErrorMsg(error)}`);
573
+ throw error;
574
+ } finally {
575
+ if (logalot) { console.log(`${lc} complete.`); }
576
+ }
577
+ }
578
+
579
+ export async function validateChallengePool({ pool }: {
580
+ pool: KeystoneChallengePool;
581
+ }): Promise<string[]> {
582
+ const lc = `[${validateChallengePool.name}]`;
583
+ try {
584
+ if (logalot) { console.log(`${lc} starting... (I: 1a0eafc158a83d1ba8fc019d5c979a26)`); }
585
+ const errors: string[] = [];
586
+
587
+ if (pool.config) {
588
+ // first validate common to all pools, regardless of type...
589
+ if (pool.config.id) {
590
+ if (!KEYSTONE_POOL_ID_REGEXP.test(pool.config.id)) {
591
+ // not 100% that this is needed but hey
592
+ errors.push(`${lc} pool.config.id is not formatted correctly. must pass regexp: ${KEYSTONE_POOL_ID_REGEXP.source}`);
593
+ }
594
+ } else {
595
+ errors.push(`${lc} pool.config.id falsy (E: 31d7943d95f877326d5f4ea14463d626)`);
596
+ }
597
+
598
+ if (pool.config.behavior) {
599
+ const { size } = pool.config.behavior;
600
+ if (!size || size === 0) {
601
+ errors.push(`${lc} invalid pool.config.behavior.size (${size}). Must be positive integer. (E: b221e36ec102bdc944552248ce8fe626)`)
602
+ }
603
+ // todo: more behavior checks
604
+ } else {
605
+ errors.push(`${lc} pool.config.behavior falsy (E: bede081c066c39732eefe2f92e296326)`)
606
+ }
607
+
608
+ // ...then do type-specific validation
609
+ const poolType = pool.config.type;
610
+ switch (poolType) {
611
+ case KeystoneChallengeType.hash_reveal_v1:
612
+ const errorsHashRevealV1 = await validateChallengePool_typeHashRevealV1({ pool });
613
+ errorsHashRevealV1.forEach(x => errors.push(x));
614
+ break;
615
+ default:
616
+ throw new Error(`(UNEXPECTED) unknown pool.config.type (${poolType})? We only implement the following at this time: ${KEYSTONE_CHALLENGE_TYPE_VALID_VALUES} (E: cce5285cf7580b8bc82172488eba2826)`);
617
+ }
618
+ } else {
619
+ errors.push(`${lc} pool.config falsy. (E: 8d05c875a1d2c58018a5eaf803977d26)`);
620
+ }
621
+
622
+ return errors;
623
+ } catch (error) {
624
+ console.error(`${lc} ${extractErrorMsg(error)}`);
625
+ throw error;
626
+ } finally {
627
+ if (logalot) { console.log(`${lc} complete.`); }
628
+ }
629
+ }
630
+
631
+
632
+ export async function validateGenesisKeystone({
633
+ keystoneIbGib
634
+ }: {
635
+ keystoneIbGib: KeystoneIbGib_V1;
636
+ }): Promise<string[]> {
637
+ const lc = `[${validateGenesisKeystone.name}]`;
638
+ try {
639
+ if (logalot) { console.log(`${lc} starting... (I: ec6ba82ec848b5ac3d8953e89d8d9826)`); }
640
+
641
+ const errors: string[] = [];
642
+
643
+ const { data, rel8ns } = keystoneIbGib;
644
+
645
+ // no proofs/solutions yet
646
+ if (data.proofs && data.proofs.length > 0) {
647
+ errors.push(`${lc} proofs already exist on genesis keystone. (E: 7a5e15f20918f1bbd8ffb62857dcd526)`);
648
+ }
649
+
650
+ for (const pool of data.challengePools) {
651
+ // validate each pool intrinsically (config, sanity)
652
+ const poolErrors = await validateChallengePool({ pool });
653
+ poolErrors.forEach(x => errors.push(x));
654
+
655
+ // additionally ensure each pool has challenges. This is only on
656
+ // this genesis keystone, as it is valid to have pool without
657
+ // challenges after revocation
658
+ if (!pool.challenges || Object.keys(pool.challenges).length === 0) {
659
+ errors.push(`${lc} invalid pool (${pool.id}). pool.challenges is falsy/empty. (E: 8cd16a5416ae62a058342828be465b26)`);
660
+ }
661
+ }
662
+
663
+ // not stated as revoked already
664
+ if (!!data.revocationInfo) {
665
+ errors.push(`${lc} genesis keystone already has revocationInfo. (E: e11408d0c558d0fa948efbce611ec826)`);
666
+ }
667
+
668
+ return errors;
669
+ } catch (error) {
670
+ console.error(`${lc} ${extractErrorMsg(error)}`);
671
+ throw error;
672
+ } finally {
673
+ if (logalot) { console.log(`${lc} complete.`); }
674
+ }
675
+ }
676
+
515
677
  /**
516
678
  * Validates the transition from Prev -> Curr.
517
679
  * Enforces Cryptography AND Behavioral Policy.
@@ -782,4 +944,157 @@ export async function createKeystoneIbGibImpl({
782
944
  } finally {
783
945
  if (logalot) { console.log(`${lc} complete.`); }
784
946
  }
785
- }
947
+ }
948
+
949
+ export async function validateKeystoneGraph({
950
+ keystoneIbGib,
951
+ getLatest,
952
+ invalidIfMoreRecentKeystoneFoundInSpace,
953
+ space,
954
+ }: {
955
+ keystoneIbGib: KeystoneIbGib_V1,
956
+ /**
957
+ * if true, then this will get the latest keystone known in the incoming
958
+ * {@link keystoneIbGib} timeline, as found in {@link space}.
959
+ */
960
+ getLatest: boolean,
961
+ invalidIfMoreRecentKeystoneFoundInSpace: boolean,
962
+ space: IbGibSpaceAny,
963
+ }): Promise<string[]> {
964
+ const lc = `[${validateKeystoneGraph.name}]`;
965
+ try {
966
+ if (logalot) { console.log(`${lc} starting... (I: 22e1ca1d5a08a3f90b7fe9da95df7b26)`); }
967
+
968
+ // maybe too defensive but...
969
+ if (!keystoneIbGib) { throw new Error(`(UNEXPECTED) keystoneIbGib falsy? (E: 26482871d529fff6e8899c5d8a6c3826)`); }
970
+
971
+ // #region leaving off here
972
+ // asdf
973
+ // just implemented validate keystone graph. incorporate this into the
974
+ // context ibgib, which now has the session ibgib as part of it. each
975
+ // step in ping pong should validate the entire keystone graph
976
+
977
+ // #endregion leaving off here
978
+ const errors: string[] = [];
979
+
980
+ // first, get the latest if that is the case...
981
+ if (getLatest) {
982
+ const keystoneAddr = getIbGibAddr({ ibGib: keystoneIbGib });
983
+ const resGetLatestAddrs = await getLatestAddrs({
984
+ ibGibs: [keystoneIbGib],
985
+ space,
986
+ });
987
+ if (!resGetLatestAddrs.data) { throw new Error(`(UNEXPECTED) resGetLatestAddrs.data falsy? (E: 3a23b3b420a8da1928219ca8d47b2126)`); }
988
+ if (!resGetLatestAddrs.data.latestAddrsMap) { throw new Error(`(UNEXPECTED) resGetLatestAddrs.data.latestAddrsMap falsy? (E: 93f1180598fb65a4b8d36e08d6c50426)`); }
989
+
990
+ const { latestAddrsMap } = resGetLatestAddrs.data;
991
+ if (Object.keys(latestAddrsMap).length === 0) {
992
+ throw new Error(`(UNEXPECTED) latestAddrsMap truthy but empty? (E: 7142f8f7625b9186281d08251e407826)`);
993
+ }
994
+
995
+ const latestAddr = latestAddrsMap[keystoneAddr];
996
+ if (latestAddr) {
997
+ if (latestAddr !== keystoneAddr) {
998
+ if (invalidIfMoreRecentKeystoneFoundInSpace) {
999
+ errors.push(`${lc} more recent keystone (${latestAddr}) found than the one passed in (${keystoneAddr}) in space (${space.ib}). (E: 64bf48de9448ee5c7528bf03bed2a826)`);
1000
+ } else {
1001
+ // get the latest ibgib and point the incoming ref to that
1002
+ const [latestKeystoneIbGib] = await getIbGibsFromCache_fallbackToSpaces({
1003
+ addrs: [latestAddr],
1004
+ space,
1005
+ });
1006
+ keystoneIbGib = latestKeystoneIbGib as KeystoneIbGib_V1;
1007
+ }
1008
+ } else {
1009
+ // the incoming ibgib **is** the latest keystone, so nothing more to be done.
1010
+ if (logalot) { console.log(`${lc} incoming keystone (${keystoneAddr}) is the latest in the space (${space.ib}) (I: 8ffbd8d6cbc8a461e5e7f1084bd22a26)`); }
1011
+ }
1012
+ } else {
1013
+ // keystone not found in space?
1014
+ console.warn(`${lc} keystoneIbGib (${keystoneAddr}) not found in space (${space.ib}). I don't know what the implications of this are. (W: 258c88742448db34a585669484771826)`)
1015
+ }
1016
+ }
1017
+
1018
+ const dependencyGraph = await getDependencyGraph({
1019
+ ibGib: keystoneIbGib,
1020
+ space,
1021
+ });
1022
+
1023
+ const depIbGibs = Object.values(dependencyGraph);
1024
+ const { mapWithTjp_NoDna, mapWithTjp_YesDna, mapWithoutTjps, } =
1025
+ splitPerTjpAndOrDna({ ibGibs: depIbGibs });
1026
+
1027
+
1028
+ // there should be no DNA
1029
+ if (Object.keys(mapWithTjp_YesDna).length > 0) {
1030
+ errors.push(`${lc} DNA found. Keystones should NOT have DNA. (E: a3ec7827c4284cdea61c2372c0615826)`);
1031
+ }
1032
+
1033
+ // is there a tjp? I think there is, so mapWithoutTjps should also be
1034
+ // empty
1035
+ if (Object.keys(mapWithoutTjps).length > 0) {
1036
+ errors.push(`${lc} Non-tjp ibgibs found? Keystones are expected to have tjps. (E: a3ec7827c4284cdea61c2372c0615826)`);
1037
+ }
1038
+
1039
+ if (Object.keys(mapWithTjp_NoDna).length > 0) {
1040
+ // happy path here. These should be the keystone ibgibs. we will put
1041
+ // them in order, then do validation on the transitions. We will
1042
+ // also check other graph-scoped integrity of keystones (like do
1043
+ // certain properties match among ALL keystones, etc.)
1044
+
1045
+ const keystoneIbGibs_unordered = Object.values(mapWithTjp_NoDna);
1046
+
1047
+ const orderedKeystonesMap = getTimelinesGroupedByTjp({ ibGibs: keystoneIbGibs_unordered });
1048
+ const keys = Object.keys(orderedKeystonesMap);
1049
+ if (keys.length === 0) {
1050
+ throw new Error(`(UNEXPECTED) orderedKeystonesMap empty? (E: d437b80bef58e83a034b28af46278726)`);
1051
+ } else if (keys.length > 0) {
1052
+ // keys.length > 0
1053
+ throw new Error(`(UNEXPECTED) more than one timeline in keystone graph? ATOW (02/19/2026) we are expecting only a single timeline. (E: 66085b14e3887a59c872afd240511f26)`);
1054
+ }
1055
+ // happy path: exactly one timeline
1056
+ const keystoneTjpAddr = keys[0];
1057
+ const keystoneIbGibs_ordered = orderedKeystonesMap[keystoneTjpAddr] as KeystoneIbGib_V1[];
1058
+
1059
+ if (keystoneIbGibs_ordered.length === 0) { throw new Error(`(UNEXPECTED) empty keystoneIbGibs_ordered? (E: 4a6b085aa8a76828a8d65367e7e56526)`); }
1060
+
1061
+ const genesisErrors = await validateGenesisKeystone({
1062
+ keystoneIbGib: keystoneIbGibs_ordered[0]
1063
+ });
1064
+ genesisErrors.forEach(x => errors.push(x));
1065
+
1066
+ if (keystoneIbGibs_ordered.length === 1) {
1067
+ // only the genesis keystone, which has already been done.
1068
+ } else {
1069
+ // more than 1 keystone, so validate the transitions
1070
+ for (let i = 0; i < keystoneIbGibs_ordered.length - 1; i++) {
1071
+ const prevIbGib = keystoneIbGibs_ordered[i];
1072
+ const currentIbGib = keystoneIbGibs_ordered[i + 1];
1073
+ const transitionErrors = await validateKeystoneTransition({
1074
+ prevIbGib, currentIbGib
1075
+ });
1076
+ if (transitionErrors.length > 0) {
1077
+ errors.push(`${lc} keystone has ${transitionErrors.length} transition errors. i: ${i}. prevIbGib addr: ${getIbGibAddr({ ibGib: prevIbGib })}. currentIbGib addr: ${getIbGibAddr({ ibGib: currentIbGib })}. (E: 3ac17be916141d0c286ca5a87bb1b426)`);
1078
+ transitionErrors.forEach(x => errors.push(x));
1079
+ }
1080
+
1081
+ break; // stop after the first found transition error
1082
+ }
1083
+ }
1084
+ } else {
1085
+ // one of the other errors regarding mapWithTjp_YesDna or
1086
+ // mapWithoutTjps will exist at this point, so we don't need to add
1087
+ // any more errors.
1088
+ if (errors.length === 0) { throw new Error(`(UNEXPECTED) mapWithTjp_NoDna empty (which is an error) but errors.length === 0? If we get here, we expect one of the other errors to have been populated. (E: 7bca2866b6f8fca318923de8c88e8826)`); }
1089
+ }
1090
+
1091
+ return errors;
1092
+
1093
+ } catch (error) {
1094
+ console.error(`${lc} ${extractErrorMsg(error)}`);
1095
+ throw error;
1096
+ } finally {
1097
+ if (logalot) { console.log(`${lc} complete.`); }
1098
+ }
1099
+ }
1100
+
@@ -336,7 +336,10 @@ export interface KeystoneRel8ns_V1 extends IbGibRel8ns_V1 {
336
336
  // Specific hard-links for composite keystones go here later.
337
337
  }
338
338
 
339
- export interface KeystoneIbGib_V1 extends IbGib_V1<KeystoneData_V1, KeystoneRel8ns_V1> { }
339
+ export interface KeystoneIbGib_V1 extends IbGib_V1<KeystoneData_V1, KeystoneRel8ns_V1> {
340
+ data: KeystoneData_V1;
341
+ rel8ns: KeystoneRel8ns_V1;
342
+ }
340
343
 
341
344
  export interface DeterministicResult {
342
345
  /**
@@ -133,13 +133,23 @@ export abstract class SyncPeer_V1<TInitializeOpts extends InitializeSyncPeerOpts
133
133
 
134
134
  if (!this.opts) { throw new Error(`(UNEXPECTED) this.opts falsy? Concrete class should have initialized sender opts by now. (E: 0b9e28287318fdf8bf9f5a6886a24826)`); }
135
135
 
136
- // NOTE: There are two basic types of peers:
137
- // * local-only (peer)
136
+ // #region leaving off here
137
+ // NOTES: the context ibgib now has a reference to the signed
138
+ // keystone. the signed keystone targets the context ibgib, and the
139
+ // context ibgib itself points to the previous frame of the
140
+ // keystone. I've started on creating a validateKeystone function,
141
+ // whcih I need to at least add the validate transitions to. I
142
+ // _think_ I need to also fill in some authentication here in this
143
+ // peer at the very least, then I can move on to other layers.
144
+ // #endregion leaving off here
145
+
146
+ // NOTE: There are three basic types of peers:
147
+ // * local-only
138
148
  // * this peer is both sender/receiver peer
139
149
  // * for local merges and relatively fast spaces
140
150
  // * proxy to remote space
141
151
  // * this peer is both sender/receiver peer
142
- // * works directly with remote/outerspaces
152
+ // * works directly with remote/outerspaces via API calls
143
153
  // * Less efficient over-the-wire xfer due to chatiness
144
154
  // * symmetric node sender/receiver peers
145
155
  // * separate sender/receiver classes
@@ -20,33 +20,12 @@ import { IbGibSpaceAny } from '../../witness/space/space-base-v1.mjs';
20
20
  import { putInSpace, registerNewIbGib } from '../../witness/space/space-helper.mjs';
21
21
  import { SyncIbGib_V1 } from '../sync-types.mjs';
22
22
  import { validateSyncSagaFrame } from '../sync-helpers.mjs';
23
+ import { validateKeystoneGraph, validateKeystoneTransition } from '../../keystone/keystone-helpers.mjs';
24
+ import { KeystoneService_V1 } from '../../keystone/keystone-service-v1.mjs';
25
+ import { KeystoneIbGib_V1 } from '../../keystone/keystone-types.mjs';
23
26
 
24
27
  const logalot = GLOBAL_LOG_A_LOT;
25
28
 
26
- /**
27
- * Options for creating a SyncSagaContext ibgib.
28
- */
29
- export interface CreateSyncSagaContextOptions {
30
- /**
31
- * The main saga frame (Init, Ack, etc.).
32
- */
33
- sagaFrame: SyncIbGib_V1;
34
- /**
35
- * Session identity keystones.
36
- */
37
- sessionKeystones?: IbGib_V1[];
38
- /**
39
- * Domain payload ibgibs when the sync saga frame includes actual domain
40
- * payloads to send, e.g., in a Delta frame.
41
- */
42
- payloadIbGibsDomain?: IbGib_V1[];
43
- /**
44
- * we persist the context in the local/sender space (relative to our
45
- * execution POV) right when we create it.
46
- */
47
- localSpace: IbGibSpaceAny;
48
- }
49
-
50
29
  /**
51
30
  * Constructs the standard 'ib' string for a Sync Saga Context stone.
52
31
  */
@@ -117,89 +96,6 @@ export async function parseSyncSagaContextIb({
117
96
  }
118
97
  }
119
98
 
120
- /**
121
- * Creates new SyncSagaContext stone. Puts/registers in {@link localSpace}
122
- * immediately after creation.
123
- *
124
- * @returns The context ibGib.
125
- *
126
- * ## notes
127
- *
128
- * the other ibgibs that are related to this context stone should already be
129
- * put/registered in {@link localSpace}.
130
- */
131
- export async function createSyncSagaContext({
132
- sagaFrame,
133
- sessionKeystones,
134
- payloadIbGibsDomain,
135
- localSpace,
136
- }: CreateSyncSagaContextOptions): Promise<SyncSagaContextIbGib_V1> {
137
- const lc = `[${createSyncSagaContext.name}]`;
138
- try {
139
- if (logalot) { console.log(`${lc} starting... (I: 6b87bee313e811d1d2fc90e87fbec826)`); }
140
-
141
- if (!sagaFrame.data) { throw new Error(`(UNEXPECTED) sagaFrame.data falsy? (E: 04c49b4cccba6842a8b52e4c6f570726)`); }
142
- if (!sagaFrame.data.n && sagaFrame.data.n !== 0) { throw new Error(`(UNEXPECTED) sagaFrame.data.n falsy and not 0? (E: 45b508da64a8b28428b11765d684b826)`); }
143
-
144
- const date = new Date();
145
- const timestamp = getTimestamp(date);
146
- const timestampMs = date.getMilliseconds();
147
-
148
- const data: SyncSagaContextData_V1 = {
149
- timestamp,
150
- timestampMs,
151
- sagaN: sagaFrame.data.n,
152
- };
153
-
154
- // Domain Payloads
155
- const payloadAddrsDomain = payloadIbGibsDomain ?
156
- payloadIbGibsDomain?.map(x => getIbGibAddr({ ibGib: x })) :
157
- undefined;
158
- if (payloadAddrsDomain && payloadAddrsDomain.length > 0) {
159
- data[SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN] = payloadAddrsDomain;
160
- }
161
-
162
- // rel8ns should always have saga frame, sometimes have keystone
163
- const rel8ns: SyncSagaContextRel8ns_V1 = {
164
- sagaFrame: [getIbGibAddr({ ibGib: sagaFrame })],
165
- };
166
- if (sessionKeystones && sessionKeystones.length > 0) {
167
- rel8ns.sessionKeystone = sessionKeystones.map(x => getIbGibAddr({ ibGib: x }));
168
- }
169
-
170
- // Generate standard ib
171
- const ib = await getSyncSagaContextIb({ data });
172
-
173
- const contextIbGib = await Factory_V1.stone<SyncSagaContextData_V1, SyncSagaContextRel8ns_V1>({
174
- parentPrimitiveIb: SYNC_SAGA_CONTEXT_ATOM,
175
- ib,
176
- data,
177
- rel8ns,
178
- }) as SyncSagaContextIbGib_V1;
179
-
180
- // put/register immediately. Note that contextIbGib at this point is
181
- // pure DTO, i.e., only ib, gib, data, rel8ns props.
182
- await putInSpace({ ibGib: contextIbGib, space: localSpace, });
183
- await registerNewIbGib({
184
- ibGib: contextIbGib,
185
- space: localSpace,
186
- fnBroadcast: undefined,
187
- });
188
-
189
- // Attach actual ibgibs for transport (not pure DTO now)
190
- contextIbGib.sagaFrame = sagaFrame;
191
- if (payloadIbGibsDomain && payloadIbGibsDomain.length > 0) {
192
- contextIbGib.payloadIbGibsDomain = payloadIbGibsDomain;
193
- }
194
-
195
- return contextIbGib;
196
- } catch (error) {
197
- console.error(`${lc} ${extractErrorMsg(error)}`);
198
- throw error;
199
- } finally {
200
- if (logalot) { console.log(`${lc} complete.`); }
201
- }
202
- }
203
99
 
204
100
  /**
205
101
  * Validates ONLY the {@link context} ibgib itself and saga frame/msg stone(s)
@@ -8,6 +8,7 @@ import { IbGibData_V1, IbGibRel8ns_V1, IbGib_V1 } from '@ibgib/ts-gib/dist/V1/ty
8
8
  import { SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN } from '../sync-constants.mjs';
9
9
  import { SyncIbGib_V1 } from '../sync-types.mjs';
10
10
  import { SYNC_SAGA_CONTEXT_ATOM } from './sync-saga-context-constants.mjs';
11
+ import { KeystoneIbGib_V1 } from '../../keystone/keystone-types.mjs';
11
12
 
12
13
  export interface SyncSagaContextIb_V1 {
13
14
  atom: typeof SYNC_SAGA_CONTEXT_ATOM;
@@ -49,13 +50,21 @@ export interface SyncSagaContextRel8ns_V1 extends IbGibRel8ns_V1 {
49
50
  sagaFrame: IbGibAddr[];
50
51
 
51
52
  /**
52
- * The Ephemeral Session Keystone Identity used for this saga.
53
- * Required for validating the saga frame signature.
53
+ * The Ephemeral Session Keystone Identity used for this saga. Required for
54
+ * validating the saga frame and this context.
55
+ *
56
+ * WARNING!!!: THIS DOES NOT POINT TO THE CURRENT SESSION KEYSTONE IN
57
+ * {@link SyncSagaContextIbGib_V1.signedSessionKeystone}. This points to the
58
+ * PREVIOUS FRAME (immediate past) of that frame. That session keystone
59
+ * signs with THIS context's frame as its target, so it is logically
60
+ * impossible because the hash would be different.
54
61
  *
55
62
  * ## notes
56
63
  *
57
- * This will be different for the sender and receiver, yes? hmm...
58
- * I think I need to put "sender" or "receiver" in the session keystone ib.
64
+ * ATOW (02/18/2026), this is a single address that will have a primary pool
65
+ * for the sender and a delegated pool for the receiver.
66
+ *
67
+ * @see {@link SyncSagaContextIbGib_V1.signedSessionKeystone}
59
68
  */
60
69
  sessionKeystone?: IbGibAddr[];
61
70
  }
@@ -79,4 +88,16 @@ export interface SyncSagaContextIbGib_V1 extends IbGib_V1<SyncSagaContextData_V1
79
88
  * This frame's addr should be {@link SyncSagaContextRel8ns_V1.sagaFrame}.
80
89
  */
81
90
  sagaFrame: SyncIbGib_V1;
91
+
92
+ /**
93
+ * If session keystone is in play, then this will be populated with that
94
+ * keystone. This session keystone will point to the this context ibgib,
95
+ * BUT, this context ibgib will point to the **PREVIOUS** frame of the
96
+ * keystone.
97
+ *
98
+ * So in order to verify this context ibgib, we must verify the keystone
99
+ * points to this context ibgib AND that this context ibgib points to the
100
+ * previous frame of the keystone.
101
+ */
102
+ signedSessionKeystone?: KeystoneIbGib_V1;
82
103
  }