@ibgib/core-gib 0.0.8 → 0.0.11

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 (154) hide show
  1. package/README.md +5 -10
  2. package/dist/assumptions.respec.d.mts +2 -0
  3. package/dist/assumptions.respec.d.mts.map +1 -0
  4. package/dist/assumptions.respec.mjs +41 -0
  5. package/dist/assumptions.respec.mjs.map +1 -0
  6. package/dist/core-constants.d.mts +0 -2
  7. package/dist/core-constants.d.mts.map +1 -1
  8. package/dist/core-constants.mjs +0 -2
  9. package/dist/core-constants.mjs.map +1 -1
  10. package/dist/core-helper.respec.d.mts +2 -0
  11. package/dist/core-helper.respec.d.mts.map +1 -0
  12. package/dist/core-helper.respec.mjs +53 -0
  13. package/dist/core-helper.respec.mjs.map +1 -0
  14. package/dist/core-types.d.mts +22 -0
  15. package/dist/core-types.d.mts.map +1 -1
  16. package/dist/respec-gib.node.d.mts +2 -0
  17. package/dist/respec-gib.node.d.mts.map +1 -0
  18. package/dist/respec-gib.node.mjs +211 -0
  19. package/dist/respec-gib.node.mjs.map +1 -0
  20. package/dist/spec-helper.node.respec.d.mts +12 -0
  21. package/dist/spec-helper.node.respec.d.mts.map +1 -0
  22. package/dist/spec-helper.node.respec.mjs +43 -0
  23. package/dist/spec-helper.node.respec.mjs.map +1 -0
  24. package/dist/witness/app/app-base-v1.d.mts +2 -2
  25. package/dist/witness/app/app-base-v1.d.mts.map +1 -1
  26. package/dist/witness/app/app-base-v1.mjs +23 -141
  27. package/dist/witness/app/app-base-v1.mjs.map +1 -1
  28. package/dist/witness/app/app-constants.d.mts +2 -0
  29. package/dist/witness/app/app-constants.d.mts.map +1 -1
  30. package/dist/witness/app/app-constants.mjs +2 -0
  31. package/dist/witness/app/app-constants.mjs.map +1 -1
  32. package/dist/witness/app/app-helper.d.mts.map +1 -1
  33. package/dist/witness/app/app-helper.mjs +2 -1
  34. package/dist/witness/app/app-helper.mjs.map +1 -1
  35. package/dist/witness/app/app-types.d.mts +2 -1
  36. package/dist/witness/app/app-types.d.mts.map +1 -1
  37. package/dist/witness/robbot/robbot-base-v1.d.mts +12 -164
  38. package/dist/witness/robbot/robbot-base-v1.d.mts.map +1 -1
  39. package/dist/witness/robbot/robbot-base-v1.mjs +41 -657
  40. package/dist/witness/robbot/robbot-base-v1.mjs.map +1 -1
  41. package/dist/witness/robbot/robbot-helper.mjs +3 -3
  42. package/dist/witness/robbot/robbot-helper.mjs.map +1 -1
  43. package/dist/witness/robbot/robbot-helper.respec.d.mts +2 -0
  44. package/dist/witness/robbot/robbot-helper.respec.d.mts.map +1 -0
  45. package/dist/witness/robbot/robbot-helper.respec.mjs +106 -0
  46. package/dist/witness/robbot/robbot-helper.respec.mjs.map +1 -0
  47. package/dist/witness/robbot/robbot-types.d.mts +6 -3
  48. package/dist/witness/robbot/robbot-types.d.mts.map +1 -1
  49. package/dist/witness/robbot/robbot-types.mjs +1 -0
  50. package/dist/witness/robbot/robbot-types.mjs.map +1 -1
  51. package/dist/witness/space/filesystem-space/filesystem-space-v1.d.mts +1 -1
  52. package/dist/witness/space/filesystem-space/filesystem-space-v1.d.mts.map +1 -1
  53. package/dist/witness/space/filesystem-space/filesystem-space-v1.respec.d.mts +2 -0
  54. package/dist/witness/space/filesystem-space/filesystem-space-v1.respec.d.mts.map +1 -0
  55. package/dist/witness/space/filesystem-space/filesystem-space-v1.respec.mjs +107 -0
  56. package/dist/witness/space/filesystem-space/filesystem-space-v1.respec.mjs.map +1 -0
  57. package/dist/witness/space/filesystem-space/node-filesystem-space-v1.d.mts.map +1 -1
  58. package/dist/witness/space/filesystem-space/node-filesystem-space-v1.mjs +1 -1
  59. package/dist/witness/space/filesystem-space/node-filesystem-space-v1.mjs.map +1 -1
  60. package/dist/witness/space/filesystem-space/node-filesystem-space-v1.node.respec.d.mts +2 -0
  61. package/dist/witness/space/filesystem-space/node-filesystem-space-v1.node.respec.d.mts.map +1 -0
  62. package/dist/witness/space/filesystem-space/node-filesystem-space-v1.node.respec.mjs +129 -0
  63. package/dist/witness/space/filesystem-space/node-filesystem-space-v1.node.respec.mjs.map +1 -0
  64. package/dist/witness/space/inner-space/inner-space-v1.respec.d.mts +2 -0
  65. package/dist/witness/space/inner-space/inner-space-v1.respec.d.mts.map +1 -0
  66. package/dist/witness/space/inner-space/inner-space-v1.respec.mjs +56 -0
  67. package/dist/witness/space/inner-space/inner-space-v1.respec.mjs.map +1 -0
  68. package/dist/witness/space/metaspace/metaspace-base.d.mts +795 -0
  69. package/dist/witness/space/metaspace/metaspace-base.d.mts.map +1 -0
  70. package/dist/witness/space/metaspace/metaspace-base.mjs +3251 -0
  71. package/dist/witness/space/metaspace/metaspace-base.mjs.map +1 -0
  72. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.d.mts +4 -0
  73. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.d.mts.map +1 -0
  74. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mjs +117 -0
  75. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mjs.map +1 -0
  76. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.d.mts +34 -0
  77. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.d.mts.map +1 -0
  78. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs +76 -0
  79. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs.map +1 -0
  80. package/dist/witness/space/metaspace/metaspace-types.d.mts +580 -0
  81. package/dist/witness/space/metaspace/metaspace-types.d.mts.map +1 -0
  82. package/dist/witness/space/metaspace/metaspace-types.mjs +6 -0
  83. package/dist/witness/space/metaspace/metaspace-types.mjs.map +1 -0
  84. package/dist/witness/space/space-helper.d.mts.map +1 -1
  85. package/dist/witness/space/space-helper.mjs +2 -1
  86. package/dist/witness/space/space-helper.mjs.map +1 -1
  87. package/dist/witness/space/{space-spec-helper.d.mts → space-respec-helper.d.mts} +15 -5
  88. package/dist/witness/space/space-respec-helper.d.mts.map +1 -0
  89. package/dist/witness/space/space-respec-helper.mjs +186 -0
  90. package/dist/witness/space/space-respec-helper.mjs.map +1 -0
  91. package/dist/witness/space/space-types.d.mts +2 -1
  92. package/dist/witness/space/space-types.d.mts.map +1 -1
  93. package/dist/witness/space/space-types.mjs.map +1 -1
  94. package/dist/witness/witness-base-v1.d.mts.map +1 -1
  95. package/dist/witness/witness-base-v1.mjs +7 -7
  96. package/dist/witness/witness-base-v1.mjs.map +1 -1
  97. package/dist/witness/witness-cmd/witness-cmd-types.d.mts +31 -0
  98. package/dist/witness/witness-cmd/witness-cmd-types.d.mts.map +1 -0
  99. package/dist/witness/witness-cmd/witness-cmd-types.mjs +2 -0
  100. package/dist/witness/witness-cmd/witness-cmd-types.mjs.map +1 -0
  101. package/dist/witness/witness-helper.d.mts +8 -0
  102. package/dist/witness/witness-helper.d.mts.map +1 -1
  103. package/dist/witness/witness-helper.mjs +30 -0
  104. package/dist/witness/witness-helper.mjs.map +1 -1
  105. package/dist/witness/witness-types.d.mts +26 -36
  106. package/dist/witness/witness-types.d.mts.map +1 -1
  107. package/dist/witness/witness-with-context/witness-with-context-base-v1.d.mts +235 -0
  108. package/dist/witness/witness-with-context/witness-with-context-base-v1.d.mts.map +1 -0
  109. package/dist/witness/witness-with-context/witness-with-context-base-v1.mjs +742 -0
  110. package/dist/witness/witness-with-context/witness-with-context-base-v1.mjs.map +1 -0
  111. package/dist/witness/witness-with-context/witness-with-context-types.d.mts +17 -0
  112. package/dist/witness/witness-with-context/witness-with-context-types.d.mts.map +1 -0
  113. package/dist/witness/witness-with-context/witness-with-context-types.mjs +2 -0
  114. package/dist/witness/witness-with-context/witness-with-context-types.mjs.map +1 -0
  115. package/package.json +12 -15
  116. package/src/{assumptions.spec.mts → assumptions.respec.mts} +11 -5
  117. package/src/core-constants.mts +0 -2
  118. package/src/core-helper.respec.mts +71 -0
  119. package/src/core-types.mts +20 -0
  120. package/src/respec-gib.node.mts +199 -0
  121. package/src/witness/app/app-base-v1.mts +19 -212
  122. package/src/witness/app/app-constants.mts +3 -0
  123. package/src/witness/app/app-helper.mts +2 -1
  124. package/src/witness/app/app-types.mts +1 -1
  125. package/src/witness/robbot/robbot-base-v1.mts +39 -690
  126. package/src/witness/robbot/robbot-helper.mts +1 -1
  127. package/src/witness/robbot/{robbot-helper.spec.mts → robbot-helper.respec.mts} +39 -33
  128. package/src/witness/robbot/robbot-types.mts +5 -3
  129. package/src/witness/space/filesystem-space/filesystem-space-v1.mts +1 -1
  130. package/src/witness/space/filesystem-space/{filesystem-space-v1.spec.mts → filesystem-space-v1.respec.mts} +17 -8
  131. package/src/witness/space/filesystem-space/node-filesystem-space-v1.mts +3 -11
  132. package/src/witness/space/filesystem-space/{node-filesystem-space-v1.node.spec.mts → node-filesystem-space-v1.node.respec.mts} +18 -14
  133. package/src/witness/space/inner-space/{inner-space-v1.spec.mts → inner-space-v1.respec.mts} +17 -8
  134. package/src/witness/space/metaspace/metaspace-base.mts +3702 -0
  135. package/src/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mts +116 -0
  136. package/src/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mts +88 -0
  137. package/src/witness/space/metaspace/metaspace-types.mts +614 -0
  138. package/src/witness/space/space-helper.mts +2 -1
  139. package/src/witness/space/{space-spec-helper.mts → space-respec-helper.mts} +76 -57
  140. package/src/witness/space/space-types.mts +2 -1
  141. package/src/witness/witness-base-v1.mts +8 -6
  142. package/src/witness/witness-cmd/witness-cmd-types.mts +38 -0
  143. package/src/witness/witness-helper.mts +31 -0
  144. package/src/witness/witness-types.mts +31 -41
  145. package/src/witness/witness-with-context/witness-with-context-base-v1.mts +809 -0
  146. package/src/witness/witness-with-context/witness-with-context-types.mts +24 -0
  147. package/tsconfig.json +1 -0
  148. package/dist/witness/space/space-spec-helper.d.mts.map +0 -1
  149. package/dist/witness/space/space-spec-helper.mjs +0 -179
  150. package/dist/witness/space/space-spec-helper.mjs.map +0 -1
  151. package/jasmine-browser.json +0 -18
  152. package/jasmine.json +0 -6
  153. package/src/core-helper.spec.mts +0 -64
  154. /package/src/{spec-helper.node.spec.mts → spec-helper.node.respec.mts} +0 -0
@@ -0,0 +1,3251 @@
1
+ import { ReplaySubject, } from 'rxjs';
2
+ import { concatMap, } from 'rxjs/operators';
3
+ import { delay, getUUID, groupBy, pretty } from '@ibgib/helper-gib';
4
+ import { encrypt, decrypt, } from '@ibgib/encrypt-gib';
5
+ import { GIB, GIB_DELIMITER, } from '@ibgib/ts-gib/dist/V1/index.mjs';
6
+ import { getIbGibAddr, } from '@ibgib/ts-gib';
7
+ import { Factory_V1 as factory } from '@ibgib/ts-gib/dist/V1/index.mjs';
8
+ import { getGib, getGibInfo, isPrimitive } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
9
+ import { StatusCode, } from '../../../witness/space/outer-space/outer-space-types.mjs';
10
+ import { getTimelinesGroupedByTjp, hasTjp } from '../../../common/other/ibgib-helper.mjs';
11
+ // import {
12
+ // getFnPrompt, getFnAlert, getFnPromptPassword
13
+ // } from '../../../common/prompt-functions.mjs';
14
+ import { getValidatedBootstrapIbGib, getLocalSpace, execInSpaceWithLocking, updateBootstrapIbGib, getSpaceArgMetadata, createTagIbGibAndSundry, getConfigAddr, setConfigAddr, setCurrentRoot, rel8ToCurrentRoot, rel8ToSpecialIbGib, registerNewIbGib, persistTransformResult, getFromSpace, putInSpace, deleteFromSpace, getLatestAddrs, getTjpIbGib, getSpecialIbGib, getSpecialRel8dIbGibs, /*createRobbotIbGib, */ trash, archive, parseSpaceIb, } from '../../../witness/space/space-helper.mjs';
15
+ import { getDependencyGraph } from '../../../common/other/graph-helper.mjs';
16
+ import { createNewRobbot, validateCommonRobbotIbGib } from '../../../witness/robbot/robbot-helper.mjs';
17
+ import { createNewApp, documentLocationIsAtWelcomePage } from '../../../witness/app/app-helper.mjs';
18
+ import { BOOTSTRAP_DATA_KNOWN_SPACE_IDS_KEY, BOOTSTRAP_IBGIB_ADDR } from '../../../witness/space/bootstrap/bootstrap-constants.mjs';
19
+ import { DEFAULT_MAX_RETRIES_GET_DEPENDENCY_GRAPH_OUTERSPACE, DEFAULT_MS_BETWEEN_RETRIES_GET_DEPENDENCY_GRAPH_OUTERSPACE, DEFAULT_SECONDS_VALID_LOCAL, SYNC_SPACE_REL8N_NAME } from '../../../witness/space/space-constants.mjs';
20
+ import { DEFAULT_ENCRYPTION_HASH_ALGORITHM, DEFAULT_ENCRYPTION_INITIAL_RECURSIONS, DEFAULT_ENCRYPTION_RECURSIONS_PER_HASH, DEFAULT_ENCRYPTION_SALT_STRATEGY, ENCRYPTION_REL8N_NAME, SECRET_REL8N_NAME } from '../../../common/encrypt/encrypt-constants.mjs';
21
+ import { ROBBOT_REL8N_NAME } from '../../../witness/robbot/robbot-constants.mjs';
22
+ import { APP_REL8N_NAME } from '../../../witness/app/app-constants.mjs';
23
+ import { AUTOSYNC_ALWAYS_REL8N_NAME } from '../../../common/other/other-constants.mjs';
24
+ import { GLOBAL_LOG_A_LOT, GLOBAL_TIMER_NAME } from '../../../core-constants.mjs';
25
+ const logalot = GLOBAL_LOG_A_LOT || true;
26
+ /**
27
+ * All-purpose mega service (todo: which we'll need to break up!) to interact
28
+ * with ibgibs at the app/device level.
29
+ *
30
+ * This works with the local app user space.
31
+ *
32
+ * ## regarding special ibgibs
33
+ *
34
+ * Special ibgibs' behaviors are what hold in other apps configuration data.
35
+ * Of course the difference is that most special ibgibs can leverage the "on-chain"
36
+ * functionality of "regular" ibgibs.
37
+ *
38
+ * There are a couple meta ibgibs (which I also call "special"):
39
+ * * roots^gib
40
+ * * tracks other special root^gib ibgibs, which are like local app-level indexes.
41
+ * * tags^gib
42
+ * * tracks other special tag^gib ibgibs, which you can apply to any ibgib
43
+ * * latest^gib
44
+ * * tracks mappings between tjp -> latest ib^gib address
45
+ * * ephemeral (deletes past rel8ns and past ibGib frames)
46
+ * * ...
47
+ *
48
+ * ## regarding latest ibgibs
49
+ *
50
+ * The tjp (temporal junction point) defines atow the beginning of an ibGib
51
+ * timeline. it's like the birthday for an ibGib. (Or you can think if it as
52
+ * the id for the stream of ibgib frames in a given timeline.)
53
+ *
54
+ * The latest ibGib in that timeline is also special, because it's often what
55
+ * you want to work with.
56
+ *
57
+ * So ideally, when an ibgib, A, has a tjp A1, and it is updated to A2, A3, An
58
+ * via `mut8` and/or `rel8` transforms, that ibgib creates a single timeline.
59
+ * This service attempts to track the relationship between that starting tjp
60
+ * address and its corresponding latest frame in that timeline, i.e., A1 -> An.
61
+ *
62
+ * ### mapping persistence implementation details
63
+ *
64
+ * The latest ibGib service is backed by a special ibgib that maintains the
65
+ * mapping index. It does this by rel8-ing that special backing ibgib via the
66
+ * tjp pointer, e.g. [special latest ibgib^XXX000].rel8ns[A^TJP123] ===
67
+ * [A^N12345] . It does this via the ib^gib content address pointer, so this
68
+ * becomes a mapping from A^TJP123 to A^N12345.
69
+ *
70
+ * This backing ibGib is special (even for special ibGibs) in that:
71
+ * * it does not relate itself with the current root of the application
72
+ * * it does not maintain references to its past (i.e. rel8ns['past'] === [])
73
+ * * it DELETES its previous incarnation from the files service
74
+ *
75
+ * In other words, this service is meant to be as ephemeral as possible. I am
76
+ * keeping it as an ibGib and not some other data format (like straight in
77
+ * storage/some other db) because I've found this is often useful and what I end
78
+ * up doing anyway to leverage other ibgib behavior. For example, in the future
79
+ * it may be good to take snapshots, which is a simple copy operation of the
80
+ * file persistence.
81
+ *
82
+ * ### current naive implementation notes
83
+ *
84
+ * questions:
85
+ * * What do we want to do if we can't locate an ibGib record?
86
+ * * How/when do we want to alert the user/our own code that we've found
87
+ * multiple timelines for an ibGib with a tjp (usually a thing we want to
88
+ * avoid)?
89
+ * * Who do we want to notify when new ibGibs arrive?
90
+ * * How often do we want to check external sources for latest?
91
+ * * When do we get to merging ibGib timelines?
92
+ *
93
+ * This is behavior that is somewhat taken care of, e.g. in git, with the HEAD
94
+ * pointer for a repo. But we're talking about here basically as a metarepo or
95
+ * "repo of repos", and unlike git, we don't want our HEAD metadata living "off
96
+ * chain" (outside of the DLT itself that it's modifying). So eventually, what
97
+ * we want is just like what we want with ALL ibGibs: perspective. From "the
98
+ * app"'s perspective, the latest is mapped. But really, apps can't view slices
99
+ * of ibGib graphs in all sorts of interesting ways and still be productive &
100
+ * beneficial to the ecosystem as a whole.
101
+ */
102
+ export class MetaspaceBase {
103
+ get initialized() { return this._initialized; }
104
+ get initializing() { return this._initializing; }
105
+ /**
106
+ * gets the current local user space
107
+ */
108
+ async getLocalUserSpace({ lock = true, localSpaceId, }) {
109
+ const lc = `${this.lc}[${this.getLocalUserSpace.name}]`;
110
+ try {
111
+ if (logalot) {
112
+ console.log(`${lc} starting...`);
113
+ }
114
+ debugger;
115
+ // if we're not explicit with skipLock, go by platform
116
+ // we only need to lock when doing the web, because we could
117
+ // have multiple tabs open.
118
+ lock ?? (lock = true);
119
+ // if (lock === undefined) {
120
+ // if (!this._platform) { this._platform = Capacitor.getPlatform(); }
121
+ // if (logalot) { console.log(`${this.lc} platform: ${this._platform}`); }
122
+ // lock = this._platform === 'web';
123
+ // }
124
+ const bootstrapIbGib = await getValidatedBootstrapIbGib({ zeroSpace: this.zeroSpace }) ?? undefined;
125
+ const localSpace = await getLocalSpace({
126
+ zeroSpace: this.zeroSpace,
127
+ bootstrapIbGib,
128
+ lock,
129
+ callerInstanceId: this.instanceId,
130
+ localSpaceId,
131
+ fnDtoToSpace: (spaceDto) => this.metaspaceFactory.fnDtoToSpace(spaceDto),
132
+ localSpaceCacheSvc: this.cacheSvc,
133
+ });
134
+ return localSpace;
135
+ }
136
+ catch (error) {
137
+ console.error(`${lc} ${error.message}`);
138
+ throw error;
139
+ }
140
+ finally {
141
+ if (logalot) {
142
+ console.log(`${lc} complete.`);
143
+ }
144
+ }
145
+ }
146
+ /**
147
+ * gets all local user spaces known in bootstrap ibgib, according to
148
+ * spaceIds property
149
+ *
150
+ * (`bootstrapIbGib.data[BOOTSTRAP_DATA_KNOWN_SPACE_IDS_KEY]` atow)
151
+ *
152
+ * ## example bootstrap ibgib atow
153
+ *
154
+ ```json
155
+ {
156
+ "ib":"bootstrap",
157
+ "gib":"gib",
158
+ "data":{
159
+ "defaultSpaceId":"d455d9a72807617634ccbf1e532b71037c45762f824ec85fcd9a4c2275562f33",
160
+ "spaceIds":["d455d9a72807617634ccbf1e532b71037c45762f824ec85fcd9a4c2275562f33"]
161
+ },
162
+ "rel8ns":{
163
+ "d455d9a72807617634ccbf1e532b71037c45762f824ec85fcd9a4c2275562f33":[
164
+ "witness space IonicSpace_V1 oij d455d9a72807617634ccbf1e532b71037c45762f824ec85fcd9a4c2275562f33^B336251655E8C56B38E9E86F20E0E42E6C153785F1A0A798ADE6916E71CF055B"
165
+ ]
166
+ }
167
+ }
168
+ ```
169
+ *
170
+ * so this enumerates `data.spaceIds` and gets the corresponding addrs in the `rel8ns`.
171
+ * it then gets the space ibgibs themselves via the local zero space.
172
+ *
173
+ * @returns array of known local user spaces
174
+ *
175
+ * @throws if no local user spaces found (there should be at least one atow i think)
176
+ */
177
+ async getLocalUserSpaces({ lock = true, }) {
178
+ const lc = `${this.lc}[${this.getLocalUserSpaces.name}]`;
179
+ try {
180
+ if (logalot) {
181
+ console.log(`${lc} starting...`);
182
+ }
183
+ const localSpaces = [];
184
+ // if we're not explicit with skipLock, go by platform
185
+ // we only need to lock when doing the web, because we could
186
+ // have multiple tabs open.
187
+ lock ?? (lock = true);
188
+ // if (lock === undefined) {
189
+ // if (!this._platform) { this._platform = Capacitor.getPlatform(); }
190
+ // if (logalot) { console.log(`${this.lc} platform: ${this._platform}`); }
191
+ // lock = this._platform === 'web';
192
+ // }
193
+ const bootstrapIbGib = await getValidatedBootstrapIbGib({ zeroSpace: this.zeroSpace });
194
+ // #region validate bootstrapIbGib
195
+ if (!bootstrapIbGib) {
196
+ throw new Error(`(UNEXPECTED) bootstrapIbGib falsy (E: fff2de921a3ee56a1d70e4ac320e4122)`);
197
+ }
198
+ if (!bootstrapIbGib.data) {
199
+ throw new Error(`(UNEXPECTED) bootstrapIbGib data falsy (E: 7f9d08050f214078b2f85dd2ed47e005)`);
200
+ }
201
+ if (!bootstrapIbGib.data[BOOTSTRAP_DATA_KNOWN_SPACE_IDS_KEY]) {
202
+ throw new Error(`(UNEXPECTED) bootstrapIbGib data invalid. data[${BOOTSTRAP_DATA_KNOWN_SPACE_IDS_KEY}] falsy (E: 37614e2e8f914d6ab7c605cf064a80d2)`);
203
+ }
204
+ if (bootstrapIbGib.data[BOOTSTRAP_DATA_KNOWN_SPACE_IDS_KEY].length === 0) {
205
+ throw new Error(`(UNEXPECTED) bootstrapIbGib data invalid. data[${BOOTSTRAP_DATA_KNOWN_SPACE_IDS_KEY}] length === 0 (E: d57691d17e6b4d7ea3a8fed36c0f47e5)`);
206
+ }
207
+ // #endregion validate bootstrapIbGib
208
+ const localSpaceIds = bootstrapIbGib.data[BOOTSTRAP_DATA_KNOWN_SPACE_IDS_KEY];
209
+ for (let i = 0; i < localSpaceIds.length; i++) {
210
+ const localSpaceId = localSpaceIds[i];
211
+ if (!localSpaceId) {
212
+ throw new Error(`(UNEXPECTED) localSpaceId falsy (E: 582c520897f5355d642229eae122ac22)`);
213
+ }
214
+ const localSpace = await getLocalSpace({
215
+ zeroSpace: this.zeroSpace,
216
+ bootstrapIbGib,
217
+ lock,
218
+ localSpaceId,
219
+ callerInstanceId: this.instanceId,
220
+ fnDtoToSpace: (spaceDto) => this.metaspaceFactory.fnDtoToSpace(spaceDto),
221
+ // fnDtoToSpace: (spaceDto: IbGib_V1) => {
222
+ // return Promise.resolve(
223
+ // NodeFilesystemSpace_V1.createFromDto(spaceDto as IbGib_V1<NodeFilesystemSpaceData_V1, NodeFilesystemSpaceRel8ns_V1>)
224
+ // );
225
+ // },
226
+ localSpaceCacheSvc: this.cacheSvc,
227
+ });
228
+ localSpaces.push(localSpace);
229
+ }
230
+ return localSpaces;
231
+ }
232
+ catch (error) {
233
+ console.error(`${lc} ${error.message}`);
234
+ throw error;
235
+ }
236
+ finally {
237
+ if (logalot) {
238
+ console.log(`${lc} complete.`);
239
+ }
240
+ }
241
+ }
242
+ /**
243
+ * should only syncIbGibs when not already syncing.
244
+ */
245
+ get syncing() {
246
+ return this._syncing;
247
+ }
248
+ getUUIDSync() {
249
+ const lc = `${this.lc}[${this.getUUIDSync.name}]`;
250
+ try {
251
+ if (logalot) {
252
+ console.log(`${lc} starting...`);
253
+ }
254
+ const id = this._precalculatedIds.pop();
255
+ if (!id) {
256
+ throw new Error(`no precalculated ids? (E: 14915489b21d031ee9ca695737ac6923)`);
257
+ }
258
+ if (this._precalculatedIds.length < 100) {
259
+ this.precalculateSomeUUIDsPlease(); // spins off
260
+ // only a race condition if we're consuming sync ids
261
+ // in a tight loop...
262
+ }
263
+ return id;
264
+ }
265
+ catch (error) {
266
+ console.error(`${lc} ${error.message}`);
267
+ throw error;
268
+ }
269
+ finally {
270
+ if (logalot) {
271
+ console.log(`${lc} complete.`);
272
+ }
273
+ }
274
+ }
275
+ async precalculateSomeUUIDsPlease() {
276
+ const lc = `${this.lc}[${this.precalculateSomeUUIDsPlease.name}]`;
277
+ try {
278
+ if (logalot) {
279
+ console.log(`${lc} starting...`);
280
+ }
281
+ const ids = [];
282
+ for (let i = 0; i < 500; i++) {
283
+ const id = await getUUID();
284
+ ids.push(id);
285
+ }
286
+ this._precalculatedIds = ids;
287
+ }
288
+ catch (error) {
289
+ console.error(`${lc} ${error.message}`);
290
+ throw error;
291
+ }
292
+ finally {
293
+ if (logalot) {
294
+ console.log(`${lc} complete.`);
295
+ }
296
+ }
297
+ }
298
+ constructor(cacheSvc) {
299
+ this.cacheSvc = cacheSvc;
300
+ // we won't get an object back, only a DTO ibGib essentially
301
+ this.lc = `[${MetaspaceBase.name}]`;
302
+ this.instanceId = (new Date()).toUTCString();
303
+ this._initialized = false;
304
+ this._initializedSubj = new ReplaySubject();
305
+ this.initialized$ = this._initializedSubj.asObservable();
306
+ this._initializing = false;
307
+ this._latestSubj = new ReplaySubject();
308
+ this.latestObs = this._latestSubj.asObservable();
309
+ // {
310
+ // const lc = `${this.lc}[get zeroSpace]`;
311
+ // if (!this._zeroSpace) { throw new Error(`this._zeroSpace falsy. should have been created on this.initialize (E: e723177fd2a74e25eb25e2299dfa4d23)`); }
312
+ // return this._zeroSpace;
313
+ // }
314
+ // protected _localUserSpaceCurrentRoot: IbGib_V1<RootData> | undefined;
315
+ /**
316
+ * Just to prevent plaintext passwords from just sitting in memory,
317
+ * this is a slight layer of indirection for caching.
318
+ */
319
+ this.passwordCache = {};
320
+ // protected fnPromptSecret: (space: IbGibSpaceAny) => Promise<IbGib_V1 | undefined>;
321
+ // protected fnPromptEncryption: (space: IbGibSpaceAny) => Promise<IbGib_V1 | undefined>;
322
+ // protected fnPromptOuterSpace: (space: IbGibSpaceAny) => Promise<IbGib_V1 | undefined>;
323
+ // protected fnPromptUpdatePic: (space: IbGibSpaceAny, picIbGib: PicIbGib_V1) => Promise<UpdatePicPromptResult | undefined>;
324
+ // protected fnPromptUpdateComment: (space: IbGibSpaceAny, commentIbGib: CommentIbGib_V1) => Promise<UpdateCommentPromptResult | undefined>;
325
+ // fnPromptRobbot: ((space: IbGibSpaceAny, ibGib: RobbotIbGib_V1) => Promise<RobbotPromptResult | undefined>) | undefined = undefined;
326
+ // fnPromptApp: ((space: IbGibSpaceAny, ibGib: AppIbGib_V1) => Promise<AppPromptResult | undefined>) | undefined = undefined;
327
+ this._syncing = false;
328
+ this.sagaInfoMap = {};
329
+ /**
330
+ * unique set of tjp addresses that will auto sync to sync spaces.
331
+ */
332
+ this._alwaysAutosyncTjpAddrsCache = new Set();
333
+ // /**
334
+ // * Cached platform value via `Capacitor.getPlatform()`.
335
+ // */
336
+ // protected _platform: string;
337
+ /**
338
+ * Hmm, hacky way of tracking if we're prompt the user for something.
339
+ * We don't want to prompt while we're already prompting, and this
340
+ * is a straight-forward approach.
341
+ *
342
+ * @see {@link getPasswordForSecrets}
343
+ */
344
+ this.isPrompting = false;
345
+ // #region sync uuids
346
+ /**
347
+ * getUUID is async. there are many times we want a throwaway id
348
+ * synchronously. So we'll prepopulate them here.
349
+ */
350
+ this._precalculatedIds = [];
351
+ // #endregion sync uuids
352
+ this.metaspaceFactory = {};
353
+ this.fnUpdateBootstrap = async (newSpace) => {
354
+ const space = await this.getLocalUserSpace({});
355
+ await updateBootstrapIbGib({ space: newSpace, zeroSpace: this.zeroSpace });
356
+ };
357
+ this.fnBroadcast = (info) => {
358
+ // if (!getIbAndGib({ibGibAddr: info.latestAddr}).gib?.includes('.')) {
359
+ // need to know why tjp's continue to get published as the latest addrs
360
+ // }
361
+ // this._latestSubj.next({tjpAddr, latestAddr: ibGibAddr, latestIbGib: ibGib});
362
+ // let gib = getIbAndGib({ibGibAddr: info.latestAddr}).gib;
363
+ this._latestSubj.next(info);
364
+ };
365
+ const lc = `${this.lc}[ctor]`;
366
+ if (logalot) {
367
+ console.log(`${lc}${GLOBAL_TIMER_NAME}`);
368
+ console.timeLog(GLOBAL_TIMER_NAME);
369
+ }
370
+ console.log(`${lc} created.`);
371
+ }
372
+ async initializeMetaspaceFactory({ metaspaceFactory }) {
373
+ const lc = `[${this.initializeMetaspaceFactory.name}]`;
374
+ try {
375
+ if (logalot) {
376
+ console.log(`${lc} starting... (I: 0b84dfb68c1e89e0af880d4461fe4b23)`);
377
+ }
378
+ this.metaspaceFactory = metaspaceFactory;
379
+ }
380
+ catch (error) {
381
+ console.error(`${lc} ${error.message}`);
382
+ throw error;
383
+ }
384
+ finally {
385
+ if (logalot) {
386
+ console.log(`${lc} complete.`);
387
+ }
388
+ }
389
+ }
390
+ async initialize({ spaceName, metaspaceFactory, getFnAlert, getFnPrompt, getFnPromptPassword, }) {
391
+ const lc = `${this.lc}[${this.initialize.name}]`;
392
+ try {
393
+ this.instanceId = await getUUID();
394
+ if (!getFnAlert) {
395
+ throw new Error(`getFnAlert required (E: c7ded289d9b6265b6d1294988faba923)`);
396
+ }
397
+ if (!getFnPrompt) {
398
+ throw new Error(`getFnPrompt required (E: cce7733db0abbf9a41fa45b6b9bf9523)`);
399
+ }
400
+ if (!getFnPromptPassword) {
401
+ throw new Error(`getFnPromptPassword required (E: cadae9f5df9a7c310e76b63cb6afb623)`);
402
+ }
403
+ this.getFnAlert = getFnAlert;
404
+ this.getFnPrompt = getFnPrompt;
405
+ this.getFnPromptPassword = getFnPromptPassword;
406
+ let timerName = `${lc}[timer]`;
407
+ if (logalot) {
408
+ timerName = lc + '[timer 71cbfa]';
409
+ console.log(`${lc} starting timer ${timerName}`);
410
+ console.time(timerName);
411
+ }
412
+ await this.precalculateSomeUUIDsPlease();
413
+ if (logalot) {
414
+ console.timeLog(timerName);
415
+ }
416
+ await this.initializeMetaspaceFactory({ metaspaceFactory: metaspaceFactory ?? (metaspaceFactory = {}) });
417
+ // local space(s)
418
+ await this.initializeLocalSpaces({ spaceName });
419
+ if (logalot) {
420
+ console.timeLog(timerName);
421
+ }
422
+ // flexibility for descending classes
423
+ await this.initializeSpecialIbGibs_required({ timerName });
424
+ await this.initializeSpecialIbGibs_outerspaces({ timerName });
425
+ await this.initializeSpecialIbGibs_other({ timerName });
426
+ if (logalot) {
427
+ console.timeEnd(timerName);
428
+ console.log(`${lc} timer ${timerName} complete.`);
429
+ }
430
+ this._initialized = true;
431
+ this._initializedSubj.next();
432
+ // always log when this is initialized (not just logalot)
433
+ console.log(`${lc} initialized (I: e3b3a9652c09445cb055013166ff089c)`);
434
+ }
435
+ catch (error) {
436
+ console.error(`${lc} ${error.message}`);
437
+ throw error;
438
+ }
439
+ }
440
+ async initializeSpecialIbGibs_required({ timerName }) {
441
+ const lc = `[${this.initializeSpecialIbGibs_required.name}]`;
442
+ try {
443
+ if (logalot) {
444
+ console.log(`${lc} starting... (I: 8cb7f63d766ab38885dc63d8da9cd323)`);
445
+ }
446
+ await this.getSpecialIbGib({ type: "latest", initialize: true });
447
+ if (logalot) {
448
+ console.timeLog(timerName);
449
+ }
450
+ await this.getSpecialIbGib({ type: "roots", initialize: true });
451
+ if (logalot) {
452
+ console.timeLog(timerName);
453
+ }
454
+ await this.getSpecialIbGib({ type: "tags", initialize: true });
455
+ if (logalot) {
456
+ console.timeLog(timerName);
457
+ }
458
+ await this.getSpecialIbGib({ type: "robbots", initialize: true });
459
+ if (logalot) {
460
+ console.timeLog(timerName);
461
+ }
462
+ await this.getSpecialIbGib({ type: "apps", initialize: true });
463
+ if (logalot) {
464
+ console.timeLog(timerName);
465
+ }
466
+ await this.getSpecialIbGib({ type: "secrets", initialize: true });
467
+ if (logalot) {
468
+ console.timeLog(timerName);
469
+ }
470
+ }
471
+ catch (error) {
472
+ console.error(`${lc} ${error.message}`);
473
+ throw error;
474
+ }
475
+ finally {
476
+ if (logalot) {
477
+ console.log(`${lc} complete.`);
478
+ }
479
+ }
480
+ }
481
+ async initializeSpecialIbGibs_outerspaces({ timerName }) {
482
+ const lc = `[${this.initializeSpecialIbGibs_outerspaces.name}]`;
483
+ try {
484
+ if (logalot) {
485
+ console.log(`${lc} starting... (I: 4f5ca25899384ceabd65e30cdf58f889)`);
486
+ }
487
+ await this.getSpecialIbGib({ type: "encryptions", initialize: true });
488
+ if (logalot) {
489
+ console.timeLog(timerName);
490
+ }
491
+ await this.getSpecialIbGib({ type: "outerspaces", initialize: true });
492
+ if (logalot) {
493
+ console.timeLog(timerName);
494
+ }
495
+ await this.getSpecialIbGib({ type: "autosyncs", initialize: true });
496
+ if (logalot) {
497
+ console.timeLog(timerName);
498
+ }
499
+ await this.loadAutoSyncs();
500
+ }
501
+ catch (error) {
502
+ console.error(`${lc} ${error.message}`);
503
+ throw error;
504
+ }
505
+ finally {
506
+ if (logalot) {
507
+ console.log(`${lc} complete.`);
508
+ }
509
+ }
510
+ }
511
+ async initializeSpecialIbGibs_other({ timerName }) {
512
+ const lc = `[${this.initializeSpecialIbGibs_other.name}]`;
513
+ try {
514
+ if (logalot) {
515
+ console.log(`${lc} starting... (I: 3cad0b16f5dac3686929dd1923ee3623)`);
516
+ }
517
+ }
518
+ catch (error) {
519
+ console.error(`${lc} ${error.message}`);
520
+ throw error;
521
+ }
522
+ finally {
523
+ if (logalot) {
524
+ console.log(`${lc} complete.`);
525
+ }
526
+ }
527
+ }
528
+ /**
529
+ * Make sure we have a bootstrapped space. This is like a node...kinda in peer
530
+ * to peer systems.
531
+ *
532
+ * For all intents and purposes here to begin with, I'm using this initially
533
+ * as where to put the settings ibGib that will contain pointers for this app, be it an
534
+ * ionic android/web app or a browser extension. This is because the initial
535
+ * intent of doing the spaces, besides it being necessary for the distributed
536
+ * nature of the architecture, is to obviate the use of ionic Storage.
537
+ * That is currently where we are storing things like the pointers to special
538
+ * ibGibs like tags^ibgib, roots ibgibs, etc.
539
+ */
540
+ async initializeLocalSpaces({ spaceName, }) {
541
+ const lc = `${this.lc}[${this.initializeLocalSpaces.name}]`;
542
+ try {
543
+ if (logalot) {
544
+ console.log(`${lc} starting...`);
545
+ }
546
+ // we're going to use the default space first to find/load the actual user's space (if it exists)
547
+ let zeroSpace = this.zeroSpace;
548
+ if (!zeroSpace.gib) {
549
+ zeroSpace.gib = await getGib({ ibGib: zeroSpace, hasTjp: false });
550
+ }
551
+ if (logalot) {
552
+ console.log(`${lc} getting bootstrap ibgib (I: a4ad1cfd5c6f895e879d9e6a5f607b22)`);
553
+ }
554
+ // first call without locking, because we just want to see if it exists.
555
+ // note that because of race conditions, this may be out of date though.
556
+ const bootstrapAddr = BOOTSTRAP_IBGIB_ADDR;
557
+ let bootstrapIbGib = await getValidatedBootstrapIbGib({ zeroSpace });
558
+ if (bootstrapIbGib) {
559
+ // re-get it using locking to ensure we've gotten the correct one.
560
+ if (logalot) {
561
+ console.log(`${lc} getting bootstrap ibgib with locking from zero space...`);
562
+ }
563
+ bootstrapIbGib = await execInSpaceWithLocking({
564
+ space: zeroSpace,
565
+ scope: bootstrapAddr,
566
+ secondsValid: DEFAULT_SECONDS_VALID_LOCAL,
567
+ fn: async () => {
568
+ const bootstrapIbGib = await getValidatedBootstrapIbGib({ zeroSpace });
569
+ if (!bootstrapIbGib) {
570
+ throw new Error(`failed to get validated bootstrapIbGib (E: a4318a8183c3d8979981c29bd4ecb223)`);
571
+ }
572
+ return bootstrapIbGib;
573
+ },
574
+ callerInstanceId: this.instanceId,
575
+ });
576
+ if (logalot) {
577
+ console.log(`${lc} got bootstrap ibgib with locking from zero space.`);
578
+ }
579
+ }
580
+ else {
581
+ if (logalot) {
582
+ console.log(`${lc} getting from default space...not found. bootstrap space not found.`);
583
+ }
584
+ // bootstrap space ibgib not found, so first run probably for user.
585
+ // so create a new bootstrapGib and user space
586
+ await this.createLocalSpaceAndUpdateBootstrap({
587
+ zeroSpace,
588
+ allowCancel: false,
589
+ createBootstrap: true,
590
+ spaceName,
591
+ });
592
+ }
593
+ }
594
+ catch (error) {
595
+ if (logalot) {
596
+ console.log(`${lc} getting from default space...not found. bootstrap space not found.`);
597
+ }
598
+ console.error(`${lc} ${error.message}`);
599
+ throw error;
600
+ }
601
+ finally {
602
+ if (logalot) {
603
+ console.log(`${lc} complete.`);
604
+ }
605
+ }
606
+ }
607
+ // #region create functions
608
+ /**
609
+ * wrapping dispatch factory function for creating local spaces. If a factory
610
+ * functionis provided, will use that. If not, then will use
611
+ * this.fnDefaultLocalSpaceFactory function. Ifthat is also falsy, then this
612
+ * will default to the NodeFSSpace factory function
613
+ * `fnCreateNewLocalSpace_NodeFSSpace`.
614
+ *
615
+ * @returns newly created local space, or undefined if there was a problem.
616
+ */
617
+ createNewLocalSpace({ opts, fnLocalSpaceFactory, }) {
618
+ const lc = `[${this.createNewLocalSpace.name}]`;
619
+ try {
620
+ if (logalot) {
621
+ console.log(`${lc} starting... (I: ac652df9d652459d98832be8483544d1)`);
622
+ }
623
+ if (!opts) {
624
+ throw new Error(`opts required (E: f1d50207b35c96985ba6c2e1a18a4e23)`);
625
+ }
626
+ fnLocalSpaceFactory ?? (fnLocalSpaceFactory = this.metaspaceFactory.fnDefaultLocalSpaceFactory);
627
+ if (!fnLocalSpaceFactory) {
628
+ throw new Error(`neither fnLocalSpaceFactory nor this.fnDefaultLocalSpaceFactory provided (E: 5142df9dbae63fd0ffef8165782dc423)`);
629
+ }
630
+ return fnLocalSpaceFactory(opts);
631
+ }
632
+ catch (error) {
633
+ console.error(`${lc} ${error.message}`);
634
+ throw error;
635
+ }
636
+ finally {
637
+ if (logalot) {
638
+ console.log(`${lc} complete.`);
639
+ }
640
+ }
641
+ }
642
+ async createLocalSpaceAndUpdateBootstrap({ zeroSpace, allowCancel, createBootstrap, spaceName, }) {
643
+ const lc = `${this.lc}[${this.createLocalSpaceAndUpdateBootstrap.name}]`;
644
+ try {
645
+ let newLocalSpace;
646
+ if (allowCancel) {
647
+ newLocalSpace = await this.createNewLocalSpace({
648
+ opts: {
649
+ allowCancel, spaceName, logalot, getFnPrompt: this.getFnPrompt,
650
+ },
651
+ });
652
+ if (!newLocalSpace) {
653
+ // cancelled
654
+ return undefined; /* <<<< returns early */
655
+ }
656
+ }
657
+ else {
658
+ // can't cancel (probably first run of app)
659
+ do {
660
+ newLocalSpace = await this.createNewLocalSpace({
661
+ opts: {
662
+ allowCancel, spaceName, logalot,
663
+ getFnPrompt: this.getFnPrompt,
664
+ }
665
+ });
666
+ } while (!newLocalSpace);
667
+ }
668
+ // create bootstrap if needed
669
+ if (createBootstrap) {
670
+ if (logalot) {
671
+ console.log(`${lc} creating new bootstrap ibgib (I: ecc58dd4af21a0c69a16b3d71dad9c22)`);
672
+ }
673
+ await updateBootstrapIbGib({
674
+ space: newLocalSpace,
675
+ zeroSpace,
676
+ setSpaceAsDefault: true,
677
+ createIfNotFound: true,
678
+ });
679
+ }
680
+ /** put arg used in both put calls to zero space and new local space. */
681
+ const argPutUserSpace = await zeroSpace.argy({
682
+ ibMetadata: getSpaceArgMetadata({ space: newLocalSpace }),
683
+ argData: {
684
+ cmd: 'put',
685
+ isMeta: true,
686
+ ibGibAddrs: [getIbGibAddr({ ibGib: newLocalSpace })],
687
+ },
688
+ ibGibs: [newLocalSpace],
689
+ });
690
+ // save the localSpace in default space
691
+ if (logalot) {
692
+ console.log(`${lc} save the localSpace in default zero space (I: 1b34fb9f548042ab9d9ae0619377e370)`);
693
+ }
694
+ const resZeroSpace = await zeroSpace.witness(argPutUserSpace);
695
+ if (resZeroSpace?.data?.success) {
696
+ if (logalot) {
697
+ console.log(`${lc} default zero space witnessed the user space (I: b6314ea887d34609904db3bb76ae2f9b)`);
698
+ }
699
+ }
700
+ else {
701
+ throw new Error(`${resZeroSpace?.data?.errors?.join('|') || "There was a problem with zeroSpace witnessing the new localSpace (E: b952e888a4954cc5b671034b8384e750)"}`);
702
+ }
703
+ // save the localSpace in its own space(?)
704
+ if (logalot) {
705
+ console.log(`${lc} save the new localSpace in its own space (I: e1f520f2cc614b1fa9c1ebd1c4dd6957)`);
706
+ }
707
+ const resPutUserSpaceInUserSpace = await newLocalSpace.witness(argPutUserSpace);
708
+ if (resPutUserSpaceInUserSpace?.data?.success) {
709
+ // we now have saved the localSpace ibgib "in" its own space.
710
+ // but atow, this does NOT change the space's gib hash, so no
711
+ // need to update the space
712
+ if (logalot) {
713
+ console.log(`${lc} user space witnessed itself`);
714
+ }
715
+ }
716
+ else {
717
+ throw new Error(`${resPutUserSpaceInUserSpace?.data?.errors?.join('|') || "There was a problem with localSpace witnessing itself. (E: 33d4b1ffcca64160afe67046531958b5)"}`);
718
+ }
719
+ // update the bootstrap ibgib to point to the new local space
720
+ await updateBootstrapIbGib({
721
+ space: newLocalSpace,
722
+ zeroSpace: this.zeroSpace,
723
+ });
724
+ return newLocalSpace;
725
+ }
726
+ catch (error) {
727
+ console.error(`${lc} ${error.message}`);
728
+ const alert = this.getFnAlert();
729
+ alert({ title: 'failed', msg: `failed to initialize the local space. error: ${error.message}` });
730
+ throw error;
731
+ }
732
+ }
733
+ async createTagIbGib({ text, icon, description, space, }) {
734
+ const lc = `${this.lc}[${this.createTagIbGib.name}]`;
735
+ try {
736
+ space = space ?? await this.getLocalUserSpace({});
737
+ if (!space) {
738
+ throw new Error(`space falsy and localUserSpace not initialized (E: 18f846b645124210a2ff1611641a8daf)`);
739
+ }
740
+ return createTagIbGibAndSundry({
741
+ text,
742
+ icon,
743
+ description,
744
+ space,
745
+ zeroSpace: this.zeroSpace,
746
+ fnBroadcast: (x) => this.fnBroadcast(x),
747
+ fnUpdateBootstrap: (x) => this.fnUpdateBootstrap(x),
748
+ });
749
+ }
750
+ catch (error) {
751
+ console.error(`${lc} ${error.message}`);
752
+ throw error;
753
+ }
754
+ }
755
+ async trash({ ibGib_Context, rel8nName_Context, addr, space, }) {
756
+ const lc = `${this.lc}[${this.trash.name}]`;
757
+ try {
758
+ if (logalot) {
759
+ console.log(`${lc} starting... (I: 4cf73be6e3294124a78a4a45368bfbcc)`);
760
+ }
761
+ if (!ibGib_Context) {
762
+ throw new Error(`ibGib_Context required (E: 09dd5e5a9f784953a42d70b1827ba442)`);
763
+ }
764
+ if (!rel8nName_Context) {
765
+ throw new Error(`rel8nName_Context required (E: cb6edaaac586773b08fd18855fc11322)`);
766
+ }
767
+ if (!addr) {
768
+ throw new Error(`addr required (E: 14f27805749c499098cebc0b1b11bc57)`);
769
+ }
770
+ space = space ?? await this.getLocalUserSpace({});
771
+ if (!space) {
772
+ throw new Error(`space falsy and localUserSpace not initialized (E: f81574e3437a4b88acd044b2abdc1ae4)`);
773
+ }
774
+ await trash({
775
+ ibGib_Context,
776
+ rel8nName_Context,
777
+ addr,
778
+ space,
779
+ zeroSpace: this.zeroSpace,
780
+ fnBroadcast: (x) => this.fnBroadcast(x),
781
+ fnUpdateBootstrap: (x) => this.fnUpdateBootstrap(x),
782
+ });
783
+ // Toast.show({ text: `trashed '${addr.slice(0, 32)}...'`, duration: "long" }); // spins off...
784
+ }
785
+ catch (error) {
786
+ console.error(`${lc} ${error.message}`);
787
+ throw error;
788
+ }
789
+ finally {
790
+ if (logalot) {
791
+ console.log(`${lc} complete.`);
792
+ }
793
+ }
794
+ }
795
+ async archive({ ibGib_Context, rel8nName_Context, addr, space, }) {
796
+ const lc = `${this.lc}[${this.archive.name}]`;
797
+ try {
798
+ if (logalot) {
799
+ console.log(`${lc} starting... (I: 785b44dbb7b048cb8c210a907b73b4c8)`);
800
+ }
801
+ if (!ibGib_Context) {
802
+ throw new Error(`ibGib_Context required (E: dc277b47aa4f42118ad14bfc817bf1d5)`);
803
+ }
804
+ if (!rel8nName_Context) {
805
+ throw new Error(`rel8nName_Context required (E: 87bd7ffa820645e9bdfb17fc726249ba)`);
806
+ }
807
+ if (!addr) {
808
+ throw new Error(`addr required (E: f6ce4e1325c84aa9b3da31c5b9dcc787)`);
809
+ }
810
+ space = space ?? await this.getLocalUserSpace({});
811
+ if (!space) {
812
+ throw new Error(`space falsy and localUserSpace not initialized (E: d6e0b1618eec400e820de6ac37491d39)`);
813
+ }
814
+ await archive({
815
+ ibGib_Context,
816
+ rel8nName_Context,
817
+ addr,
818
+ space,
819
+ zeroSpace: this.zeroSpace,
820
+ fnBroadcast: (x) => this.fnBroadcast(x),
821
+ fnUpdateBootstrap: (x) => this.fnUpdateBootstrap(x),
822
+ });
823
+ // Toast.show({ text: `archived '${addr.slice(0, 32)}...'`, duration: "long" }); // spins off...
824
+ if (logalot) {
825
+ console.log(`${lc} archived '${addr.slice(0, 32)}...' (I: 767b06c8cadd58c618924f0cd98a1723)`);
826
+ }
827
+ }
828
+ catch (error) {
829
+ console.error(`${lc} ${error.message}`);
830
+ throw error;
831
+ }
832
+ finally {
833
+ if (logalot) {
834
+ console.log(`${lc} complete.`);
835
+ }
836
+ }
837
+ }
838
+ // #endregion
839
+ /**
840
+ * Gets a config addr from the current space via the given key
841
+ * as the space's rel8n name.
842
+ *
843
+ * For example, for `key = tags`, a space may look like:
844
+ *
845
+ * ```json
846
+ * {
847
+ * ib: space xyz,
848
+ * gib: e89ff8a1c4954db28432007615a78952,
849
+ * rel8ns: {
850
+ * past: [space xyz^21cb29cc353f45a491d2b49ff2f130db],
851
+ * ancestor: [space^gib],
852
+ * tags: [tags^99b388355f8f4a979ca30ba284d3a686], // <<< rel8n with name specified by key
853
+ * }
854
+ * }
855
+ * ```
856
+ *
857
+ * @param key config key
858
+ * @returns addr in config if exists, else undefined
859
+ */
860
+ async getConfigAddr({ key, space, }) {
861
+ const lc = `${this.lc}[${this.getConfigAddr.name}](${key})`;
862
+ try {
863
+ if (logalot) {
864
+ console.log(`${lc} getting...`);
865
+ }
866
+ space = space ?? await this.getLocalUserSpace({});
867
+ if (!space) {
868
+ throw new Error(`space falsy and could not get local space. (E: b6e7fcc09c6244b99b2e6e6ece398db0)`);
869
+ }
870
+ return getConfigAddr({ key, space });
871
+ }
872
+ catch (error) {
873
+ console.error(`${lc} ${error.message}`);
874
+ return undefined;
875
+ }
876
+ }
877
+ /**
878
+ * Takes the given `key`, which should be unique in the given space (or
879
+ * zerospace), and uses that to persist the given `addr` in that space.
880
+ *
881
+ * # notes
882
+ *
883
+ * configuration is stored in "special" ibgibs, and so we need only to persist
884
+ * the address of that configuration.
885
+ */
886
+ async setConfigAddr({ key, addr, space, }) {
887
+ const lc = `${this.lc}[${this.setConfigAddr.name}]`;
888
+ try {
889
+ space = space ?? await this.getLocalUserSpace({});
890
+ if (!space) {
891
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: 2149c59ebd584a118304dd54656aa800)`);
892
+ }
893
+ return await setConfigAddr({
894
+ key, addr, space, zeroSpace: this.zeroSpace,
895
+ fnUpdateBootstrap: (x) => this.fnUpdateBootstrap(x),
896
+ });
897
+ }
898
+ catch (error) {
899
+ console.error(`${lc} ${error.message}`);
900
+ throw error;
901
+ }
902
+ }
903
+ async getCurrentRoot({ space, }) {
904
+ const lc = `${this.lc}[${this.getCurrentRoot.name}]`;
905
+ try {
906
+ space = space ?? await this.getLocalUserSpace({});
907
+ if (!space) {
908
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: 1f4dc5e9560341a993bf0b28accd75fe)`);
909
+ }
910
+ while (this.initializing) {
911
+ if (logalot) {
912
+ console.log(`${lc} hacky wait while initializing ibgibs service (I: 5fd759510e584cb69b232259b891cca1)`);
913
+ }
914
+ await delay(100);
915
+ }
916
+ const roots = await this.getSpecialIbGib({ type: "roots", space });
917
+ if (!roots) {
918
+ throw new Error(`Roots not initialized. (E: e7712dc3d183487e98cd44a2b4324bc2)`);
919
+ }
920
+ if (!roots.rel8ns) {
921
+ throw new Error(`Roots not initialized properly. No rel8ns. (E: 689f47f5d1da4a868d1c1ddd2ff13e17)`);
922
+ }
923
+ if (!roots.rel8ns.current) {
924
+ throw new Error(`Roots not initialized properly. No current root. (E: 962acd3f60474a329bfbd7682c003916)`);
925
+ }
926
+ if (roots.rel8ns.current.length === 0) {
927
+ throw new Error(`Invalid Roots: empty current root rel8n. (E: fbdc13c157514efa86ade1bf9a38bbd6)`);
928
+ }
929
+ if (roots.rel8ns.current.length > 1) {
930
+ throw new Error(`Invalid Roots: multiple current roots selected. (E: 370fe6e3920a4a1299f879e6fcbbc448)`);
931
+ }
932
+ const currentRootAddr = roots.rel8ns.current[0];
933
+ const resCurrentRoot = await this.get({ addr: currentRootAddr, isMeta: true, space });
934
+ if (resCurrentRoot.ibGibs?.length === 1) {
935
+ return resCurrentRoot.ibGibs[0];
936
+ }
937
+ else {
938
+ throw new Error(`could not get current root. addr: ${currentRootAddr} (E: 69de35c5f71e45a1a5d83228e136642b)`);
939
+ }
940
+ }
941
+ catch (error) {
942
+ console.error(`${lc} ${error.message}`);
943
+ return undefined;
944
+ }
945
+ }
946
+ async setCurrentRoot({ root, space, }) {
947
+ const lc = `${this.lc}[${this.setCurrentRoot.name}]`;
948
+ try {
949
+ if (!root) {
950
+ throw new Error(`root required.`);
951
+ }
952
+ space = space ?? await this.getLocalUserSpace({});
953
+ if (!space) {
954
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: 222a3f5b39fc47ccb2a4aa3ddcd49969)`);
955
+ }
956
+ return setCurrentRoot({
957
+ root,
958
+ space,
959
+ zeroSpace: this.zeroSpace,
960
+ fnBroadcast: (x) => this.fnBroadcast(x),
961
+ fnUpdateBootstrap: (x) => this.fnUpdateBootstrap(x),
962
+ });
963
+ // how to let others know roots has changed?
964
+ }
965
+ catch (error) {
966
+ console.error(`${lc} ${error.message}`);
967
+ throw error;
968
+ }
969
+ }
970
+ /**
971
+ * Every tjp should be related to one of the roots in a space.
972
+ *
973
+ * You should NOT relate every ibgib frame of a given ibGib.
974
+ */
975
+ async rel8ToCurrentRoot({ ibGib, linked, rel8nName, space, }) {
976
+ const lc = `${this.lc}[${this.rel8ToCurrentRoot.name}]`;
977
+ try {
978
+ space = space ?? await this.getLocalUserSpace({});
979
+ if (!space) {
980
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: cbc4e519414a405eab7fe470eadbf8f0)`);
981
+ }
982
+ return rel8ToCurrentRoot({
983
+ ibGib,
984
+ linked,
985
+ rel8nName,
986
+ space,
987
+ zeroSpace: this.zeroSpace,
988
+ fnBroadcast: (x) => this.fnBroadcast(x),
989
+ fnUpdateBootstrap: (x) => this.fnUpdateBootstrap(x),
990
+ });
991
+ }
992
+ catch (error) {
993
+ console.error(`${lc} ${error.message}`);
994
+ return;
995
+ }
996
+ }
997
+ /**
998
+ * rel8s given ibgibs to special ibgib.
999
+ * @see {@link rel8ToSpecialIbGib}
1000
+ * @returns new special ibgib addr
1001
+ */
1002
+ async rel8ToSpecialIbGib({ type, rel8nName, ibGibsToRel8, ibGibsToUnRel8, linked, severPast, deletePreviousSpecialIbGib, space, }) {
1003
+ const lc = `${this.lc}[${this.rel8ToSpecialIbGib.name}](type:${type},rel8nName:${rel8nName})`;
1004
+ try {
1005
+ space = space ?? await this.getLocalUserSpace({});
1006
+ if (!space) {
1007
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: af863928bbc945549ffc4dcca830a70a)`);
1008
+ }
1009
+ return rel8ToSpecialIbGib({
1010
+ type,
1011
+ rel8nName,
1012
+ ibGibsToRel8,
1013
+ ibGibsToUnRel8,
1014
+ linked,
1015
+ severPast,
1016
+ deletePreviousSpecialIbGib,
1017
+ space,
1018
+ zeroSpace: this.zeroSpace,
1019
+ fnUpdateBootstrap: (x) => this.fnUpdateBootstrap(x),
1020
+ fnBroadcast: (x) => this.fnBroadcast(x),
1021
+ });
1022
+ }
1023
+ catch (error) {
1024
+ console.error(`${lc} ${error.message}`);
1025
+ throw error;
1026
+ }
1027
+ }
1028
+ /**
1029
+ * Used for tracking tjpAddr -> latest ibGibAddr.
1030
+ *
1031
+ * Call this when you create a new ibGib.
1032
+ *
1033
+ * Need to put this in another service at some point, but crunch crunch
1034
+ * like pacman's lunch.
1035
+ */
1036
+ async registerNewIbGib({ ibGib, space, }) {
1037
+ let lc = `${this.lc}[${this.registerNewIbGib.name}]`;
1038
+ try {
1039
+ const ibGibAddr = getIbGibAddr({ ibGib });
1040
+ lc = `${lc}[${ibGibAddr}]`;
1041
+ space = space ?? await this.getLocalUserSpace({});
1042
+ if (!space) {
1043
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: d7e6d609a784449087cbaf1bbfb6b0c2)`);
1044
+ }
1045
+ if (logalot) {
1046
+ console.log(`${lc} starting...`);
1047
+ }
1048
+ return registerNewIbGib({
1049
+ ibGib,
1050
+ space,
1051
+ zeroSpace: this.zeroSpace,
1052
+ fnBroadcast: (x) => this.fnBroadcast(x),
1053
+ fnUpdateBootstrap: (x) => this.fnUpdateBootstrap(x),
1054
+ });
1055
+ }
1056
+ catch (error) {
1057
+ console.error(`${lc} ${error.message}`);
1058
+ throw error;
1059
+ }
1060
+ finally {
1061
+ if (logalot) {
1062
+ console.log(`${lc} complete.`);
1063
+ }
1064
+ }
1065
+ }
1066
+ /**
1067
+ * Will trigger a latest info event to be fired.
1068
+ * @param param0
1069
+ */
1070
+ async pingLatest_Local({ ibGib, tjpIbGib, space, useCache, }) {
1071
+ let lc = `${this.lc}[${this.pingLatest_Local.name}]`;
1072
+ if (logalot) {
1073
+ console.log(`${lc} starting...`);
1074
+ }
1075
+ try {
1076
+ if (!ibGib) {
1077
+ if (logalot) {
1078
+ console.log(`${lc} ibGib falsy.`);
1079
+ }
1080
+ return; /* <<<< returns early */
1081
+ }
1082
+ if (isPrimitive({ ibGib })) {
1083
+ console.warn(`${lc} tried to ping latest for primitive. returning early... (W: 06c50cfe028cc04cca67e97a48e6fe22)`);
1084
+ return; /* <<<< returns early */
1085
+ }
1086
+ if (ibGib.ib.startsWith(`witness space IonicSpace_V1`)) {
1087
+ // pinging a local user space, which for better or worse, does not
1088
+ // have a tjp (nor is it kept up to date via the latest index).
1089
+ // I can't remember, but I think there was a reason for the last bit,
1090
+ // but I probably should have given it a tjp. Anyway, the latest
1091
+ // "index" for local spaces is in the bootstrap. (Also the space is
1092
+ // not necessarily contained in the passed in `space` arg.)
1093
+ const { spaceId } = parseSpaceIb({ spaceIb: ibGib.ib });
1094
+ const latestSpace = await this.getLocalUserSpace({ localSpaceId: spaceId });
1095
+ // if (latestSpace.gib !== ibGib.gib) { // leavin this in for now. delete after awhile of normal operation. see https://github.com/wraiford/ibgib/commit/2247235a6f25945000fef419c08d5518ba2cfb48
1096
+ this._latestSubj.next({
1097
+ latestIbGib: latestSpace,
1098
+ latestAddr: getIbGibAddr({ ibGib: latestSpace }),
1099
+ tjpAddr: `${ibGib.ib}^gib`
1100
+ });
1101
+ // }
1102
+ return; /* <<<< returns early */
1103
+ }
1104
+ space = space ?? await this.getLocalUserSpace({});
1105
+ if (!space) {
1106
+ console.warn(`${lc} space falsy and localUserSpace not initialized. (W: e6708e58618947a6b66f6a49406cbf35)`);
1107
+ return;
1108
+ }
1109
+ let latestIbGib;
1110
+ let ibGibAddr = getIbGibAddr({ ibGib });
1111
+ let tjpAddr;
1112
+ // if (!latestIbGib || !latestAddr) {
1113
+ // not found in cache or caller didn't allow using the cache
1114
+ let latestAddr = await this.getLatestAddr({ ibGib, tjp: tjpIbGib, space }) ?? ibGibAddr;
1115
+ // get the tjp for the rel8nName mapping, and also for some checking logic
1116
+ if (!tjpIbGib) {
1117
+ tjpIbGib = await this.getTjpIbGib({ ibGib, space });
1118
+ if (!tjpIbGib) {
1119
+ console.warn(`${lc} tjp not found for ${ibGibAddr}? Should at least just be the ibGib's address itself. (W: 15d9c6daca7e442e968af36b4c18b8f7)`);
1120
+ tjpIbGib = ibGib;
1121
+ }
1122
+ }
1123
+ tjpAddr = getIbGibAddr({ ibGib: tjpIbGib });
1124
+ if (latestAddr === ibGibAddr) {
1125
+ if (logalot) {
1126
+ console.log(`${lc} latestAddr === ibGibAddr (I: f38042421fcc3d148a26ed56651c2522)`);
1127
+ }
1128
+ latestIbGib = ibGib;
1129
+ }
1130
+ else {
1131
+ if (logalot) {
1132
+ console.log(`${lc} later version found. ibGibAddr: ${ibGibAddr}\nlatestAddr: ${latestAddr} (I: 53cabd1643df7d43635af642e4c90922)`);
1133
+ }
1134
+ let resLatestIbGib = await this.get({ addr: latestAddr, space });
1135
+ if (!resLatestIbGib.success || resLatestIbGib.ibGibs?.length !== 1) {
1136
+ throw new Error(`latest not found (E: bc54e433573a5a89c6436dc6a3b60922)`);
1137
+ }
1138
+ latestIbGib = resLatestIbGib.ibGibs[0];
1139
+ // if (useCache) {
1140
+ // // we tried to use cache but it wasn't there, so put it for the next time.
1141
+ // if (logalot) { console.log(`${lc} putting in getLatest cache (I: 5f264edf03940a0f7e72252fd6fe0d22)`); }
1142
+ // console.log(`${lc} putting in getLatest cache (I: 5f264edf03940a0f7e72252fd6fe0d22)`);
1143
+ // setTimeout(async () => {
1144
+ // await this.latestCacheSvc.put({
1145
+ // addr: latestAddr,
1146
+ // ibGib: latestIbGib,
1147
+ // tjpAddr,
1148
+ // tjpIbGib: tjpIbGib,
1149
+ // });
1150
+ // }, Math.ceil(Math.random() * 10000));
1151
+ // }
1152
+ }
1153
+ // }
1154
+ if (latestIbGib && latestAddr && tjpAddr) {
1155
+ this._latestSubj.next({
1156
+ latestIbGib,
1157
+ latestAddr,
1158
+ tjpAddr
1159
+ });
1160
+ }
1161
+ else {
1162
+ debugger;
1163
+ throw new Error(`(UNEXPECTED) latestIbGib, latestAddr and tjpAddr should all be truthy. (E: 20e71fa1a72c45deb1dc5083903a8622)`);
1164
+ }
1165
+ }
1166
+ catch (error) {
1167
+ console.error(`${lc} ${error.message}`);
1168
+ }
1169
+ finally {
1170
+ if (logalot) {
1171
+ console.log(`${lc} complete.`);
1172
+ }
1173
+ }
1174
+ }
1175
+ // #region space facade (e.g. get, getLatest___, put, etc.)
1176
+ /**
1177
+ * Convenience function for persisting a transform result, which has
1178
+ * a newIbGib and optionally intermediate ibGibs and/or dnas.
1179
+ *
1180
+ * it persists these ibgibs into the given space, else the current space.
1181
+ */
1182
+ async persistTransformResult({ resTransform, isMeta, force, space, }) {
1183
+ const lc = `${this.lc}[${this.persistTransformResult.name}]`;
1184
+ try {
1185
+ space = space ?? await this.getLocalUserSpace({});
1186
+ if (!space) {
1187
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: f8b3d06006874b479240eb45f4015628)`);
1188
+ }
1189
+ return persistTransformResult({
1190
+ resTransform,
1191
+ isMeta,
1192
+ force,
1193
+ space,
1194
+ });
1195
+ }
1196
+ catch (error) {
1197
+ console.error(`${lc} ${error.message}`);
1198
+ throw error;
1199
+ }
1200
+ }
1201
+ /**
1202
+ * Wrapper for retrieving ibgib from a given space, else the current space.
1203
+ */
1204
+ async get({ addr, addrs, isMeta, isDna, space, }) {
1205
+ let lc = `${this.lc}[${this.get.name}]`;
1206
+ try {
1207
+ space = space ?? await this.getLocalUserSpace({});
1208
+ if (!space) {
1209
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: 86ccdcf3417a45b4a3a8c280fb9a6df7)`);
1210
+ }
1211
+ return getFromSpace({ addr, addrs, isMeta, isDna, space });
1212
+ }
1213
+ catch (error) {
1214
+ console.error(`${lc} ${error.message}`);
1215
+ return Promise.resolve({ errorMsg: error.message });
1216
+ }
1217
+ }
1218
+ /**
1219
+ * Wrapper for saving ibgib in a given space, else the current space.
1220
+ */
1221
+ async put({ ibGib, ibGibs, isMeta, isDna, force, space, }) {
1222
+ const lc = `${this.lc}[${this.put.name}]`;
1223
+ try {
1224
+ space = space ?? await this.getLocalUserSpace({});
1225
+ if (!space) {
1226
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: a00eebe0e3d348d09fda62a6be486b6c)`);
1227
+ }
1228
+ return putInSpace({ ibGib, ibGibs, isMeta, isDna, force, space });
1229
+ }
1230
+ catch (error) {
1231
+ console.error(`${lc} ${error.message}`);
1232
+ return Promise.resolve({ errorMsg: error.message });
1233
+ }
1234
+ }
1235
+ /**
1236
+ * Wrapper for removing ibgib from the a given space, else the current space.
1237
+ */
1238
+ async delete({ addr, isMeta, isDna, space, }) {
1239
+ const lc = `${this.lc}[${this.delete.name}]`;
1240
+ try {
1241
+ space = space ?? await this.getLocalUserSpace({});
1242
+ if (!space) {
1243
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: b4250b0045dc40629447f2cbd162faaa)`);
1244
+ }
1245
+ return deleteFromSpace({ addr, isMeta, isDna, space });
1246
+ }
1247
+ catch (error) {
1248
+ console.error(`${lc} ${error.message}`);
1249
+ return Promise.resolve({ errorMsg: error.message });
1250
+ }
1251
+ }
1252
+ /**
1253
+ * Wrapper for `getDependencyGraph` fn in `helper/space.ts`, but using
1254
+ * `this.localUserSpace` as default space.
1255
+ *
1256
+ * (refactoring!)
1257
+ *
1258
+ * ## note on space
1259
+ *
1260
+ * pass in `null` for space if you want to
1261
+ *
1262
+ * ## warning
1263
+ *
1264
+ * This does not (YET) have a flag that gets the latest ibgibs for the graph.
1265
+ * It only climbs the current graph, which may not cover all ibgibs when you
1266
+ * deal with ibGibs with tjps (timelines). We're going to eventually
1267
+ * combat this with auto-updating our rel8ns, but for now we're just going
1268
+ * to earmark this for the future.
1269
+ *
1270
+ * todo: auto-update or better
1271
+ *
1272
+ * @returns map of addr => ibGib
1273
+ */
1274
+ async getDependencyGraph(opts) {
1275
+ const lc = `${this.lc}[${this.getDependencyGraph.name}]`;
1276
+ try {
1277
+ opts.space = opts.space ?? await this.getLocalUserSpace({}) ?? null;
1278
+ if (!opts.space) {
1279
+ throw new Error(`(UNEXPECTED) space falsy and localUserSpace not initialized (?) (E: e2a35a23d12d48ebadcfd4f1a396d6c1)`);
1280
+ }
1281
+ return getDependencyGraph(opts);
1282
+ }
1283
+ catch (error) {
1284
+ console.error(`${lc} ${error.message}`);
1285
+ throw error;
1286
+ }
1287
+ }
1288
+ /**
1289
+ * Wrapper for getting the latest addr in the given space.
1290
+ *
1291
+ * ## warnings
1292
+ *
1293
+ * * This was written early and makes many assumptions.
1294
+ * * Meant to work with Ionic space atow.
1295
+ *
1296
+ * @returns latest addr in a given space (or localUserSpace)
1297
+ */
1298
+ async getLatestAddr({ ibGib, addr, tjpAddr, tjp, space, }) {
1299
+ let lc = `${this.lc}[${this.getLatestAddr.name}]`;
1300
+ if (logalot) {
1301
+ console.log(`${lc} starting...`);
1302
+ }
1303
+ try {
1304
+ if (!ibGib && !tjp && !tjpAddr) {
1305
+ throw new Error(`ibGib && tjp && tjpAddr falsy (E: fe725654342c4d80a33219160b5d81d3)`);
1306
+ }
1307
+ space = space ?? await this.getLocalUserSpace({});
1308
+ if (!space) {
1309
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: fd01bb85e91f4c54bfe8b35714d48a38)`);
1310
+ }
1311
+ const resGetLatest = await getLatestAddrs({
1312
+ ibGibs: ibGib ? [ibGib] : undefined,
1313
+ addrs: addr ? [addr] : undefined,
1314
+ tjpAddrs: tjpAddr ? [tjpAddr] : undefined,
1315
+ tjps: tjp ? [tjp] : undefined,
1316
+ space,
1317
+ });
1318
+ if (!resGetLatest) {
1319
+ throw new Error(`resGetLatest falsy (E: 3851bbe4427ae11771f222234e8c6622)`);
1320
+ }
1321
+ if (!resGetLatest.data) {
1322
+ throw new Error(`invalid resGetLatest: data falsy (E: 134e0f1f65edc69c6951c32e00a4bb22)`);
1323
+ }
1324
+ if (resGetLatest.data.success) {
1325
+ if (resGetLatest.data.addrs?.length === 1) {
1326
+ return resGetLatest.data.addrs[0];
1327
+ }
1328
+ else if (resGetLatest.data.addrsNotFound?.length === 1) {
1329
+ return undefined;
1330
+ }
1331
+ else if (resGetLatest.data.addrsErrored?.length === 1) {
1332
+ const emsg = resGetLatest.data.errors?.join('|') ?? "[unspecified error(s)] (E: 24f338036aa84ac99e3c39a660207222)";
1333
+ throw new Error(`resGetLatest had error(s): ${emsg}`);
1334
+ }
1335
+ else {
1336
+ throw new Error(`unknown error, invalid resGetLatest: ${pretty(resGetLatest)} (E: 6aa5aa225ebf49b588664370cb8feb22)`);
1337
+ }
1338
+ }
1339
+ else {
1340
+ const emsg = resGetLatest.data.errors?.join('|') ?? "[unspecified error(s)] (E: dcd6dcd6ec052fd112a4d48f1afa2922)";
1341
+ throw new Error(`resGetLatest had error(s): ${emsg}`);
1342
+ }
1343
+ }
1344
+ catch (error) {
1345
+ console.error(`${lc} ${error.message}`);
1346
+ throw error;
1347
+ }
1348
+ finally {
1349
+ if (logalot) {
1350
+ console.log(`${lc} complete.`);
1351
+ }
1352
+ }
1353
+ }
1354
+ /**
1355
+ * Gets the tjpIbGib for the given `ibGib` in the given `space`.
1356
+ * atow, naive must be true.
1357
+ *
1358
+ *
1359
+ *
1360
+ * @returns tjpIbGib for the given `ibGib`
1361
+ */
1362
+ async getTjpIbGib({ ibGib, naive = true, space, }) {
1363
+ const lc = `${this.lc}[${this.getTjpIbGib.name}]`;
1364
+ try {
1365
+ space = space ?? await this.getLocalUserSpace({});
1366
+ if (!space) {
1367
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: 0ec806bd2c5641c4844a3698c922e1f6)`);
1368
+ }
1369
+ if (!space) {
1370
+ console.warn(`${lc} space falsy and localUserSpace not initialized.`);
1371
+ return ibGib;
1372
+ }
1373
+ return getTjpIbGib({ ibGib, naive, space });
1374
+ }
1375
+ catch (error) {
1376
+ console.error(`${lc} ${error.message}`);
1377
+ throw error;
1378
+ }
1379
+ }
1380
+ /**
1381
+ * Gets one of the app's special ibGibs, e.g., TagsIbGib.
1382
+ *
1383
+ * When initializing tags, this will generate some boilerplate tags.
1384
+ * I'm going to be doing roots here also, and who knows what else, but each
1385
+ * one will have its own initialize specifics.
1386
+ *
1387
+ * @param initialize initialize (i.e. create) ONLY IF IbGib not found. Used for initializing app (first run).
1388
+ *
1389
+ * @see {@link createSpecial}
1390
+ * @see {@link createTags}
1391
+ */
1392
+ async getSpecialIbGib({ type, initialize, space, lock, }) {
1393
+ const lc = `${this.lc}[${this.getSpecialIbGib.name}]`;
1394
+ try {
1395
+ space = space ?? await this.getLocalUserSpace({ lock });
1396
+ if (!space) {
1397
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: e08e85d8422e479f9d101194fd26cbda)`);
1398
+ }
1399
+ while (this.initializing) {
1400
+ if (logalot) {
1401
+ console.log(`${lc} hacky wait while initializing ibgibs service (I: 497d4becb94f4515a2ec389630420d6c)`);
1402
+ }
1403
+ await delay(100);
1404
+ }
1405
+ // debugger;
1406
+ return getSpecialIbGib({
1407
+ type,
1408
+ initialize,
1409
+ space,
1410
+ zeroSpace: this.zeroSpace,
1411
+ fnUpdateBootstrap: (x) => this.fnUpdateBootstrap(x),
1412
+ fnBroadcast: (x) => this.fnBroadcast(x),
1413
+ fnGetInitializing: () => { return this._initializing; },
1414
+ fnSetInitializing: (value) => { this._initializing = value; }
1415
+ });
1416
+ }
1417
+ catch (error) {
1418
+ console.error(`${lc} ${error.message}`);
1419
+ return null;
1420
+ }
1421
+ }
1422
+ async getSpecialRel8dIbGibs({ type, rel8nName, space, }) {
1423
+ const lc = `${this.lc}[${this.getSpecialRel8dIbGibs.name}]`;
1424
+ try {
1425
+ space = space ?? await this.getLocalUserSpace({});
1426
+ if (!space) {
1427
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: 476c7d7c68f34197b740be5df09238a2)`);
1428
+ }
1429
+ return getSpecialRel8dIbGibs({ type, rel8nName, space });
1430
+ }
1431
+ catch (error) {
1432
+ console.error(`${lc} ${error.message}`);
1433
+ throw error;
1434
+ }
1435
+ }
1436
+ // #endregion space facade (e.g. get, getLatest___, put, etc.)
1437
+ /**
1438
+ * Feels klugy.
1439
+ */
1440
+ async getPasswordForSecrets({ secretIbGibs, fnPromptPassword, dontPrompt, checkCacheFirst, cacheAfter, }) {
1441
+ const lc = `${this.lc}[${this.getPasswordForSecrets.name}]`;
1442
+ /** Flag that we'll check in finally clause */
1443
+ let erroredDueToPromptTimeout = false;
1444
+ try {
1445
+ let tries = 0;
1446
+ while (this.isPrompting) {
1447
+ if (logalot) {
1448
+ console.log(`${lc} hacky wait while already prompting (I: 852007c8549d42c096defe0105b5e2e6)`);
1449
+ }
1450
+ await delay(100);
1451
+ tries++;
1452
+ if (tries > 1000) {
1453
+ erroredDueToPromptTimeout = true;
1454
+ throw new Error(`attempted to prompt for user password, but already prompting for quite awhile now. (E: 8bd4dc907422dd95862b2038ffe2b822)`);
1455
+ }
1456
+ }
1457
+ // used if we `checkCacheFirst` AND/OR if we `cacheAfter`
1458
+ const secretsCacheKey = secretIbGibs.map(ibGib => getIbGibAddr({ ibGib })).join('');
1459
+ if (checkCacheFirst) {
1460
+ const cachedPassword = await this.getCachedSecretPassword({ cacheKey: secretsCacheKey });
1461
+ if (cachedPassword) {
1462
+ // do NOT log the actual cachedPassword!!
1463
+ if (logalot) {
1464
+ console.log(`${lc} using cachedPassword.`);
1465
+ }
1466
+ return cachedPassword;
1467
+ }
1468
+ }
1469
+ if (dontPrompt) {
1470
+ return null; /* <<<< returns early */
1471
+ }
1472
+ // build prompt message
1473
+ this.isPrompting = true;
1474
+ let secretInfos = [];
1475
+ for (let i = 0; i < secretIbGibs.length; i++) {
1476
+ const secretIbGib = secretIbGibs[i];
1477
+ if (!secretIbGib.data) {
1478
+ throw new Error(`invalid secretIbGib. data falsy.`);
1479
+ }
1480
+ if (secretIbGib.data.type === 'password') {
1481
+ const secretInfo = secretIbGib.data;
1482
+ secretInfos.push(secretInfo);
1483
+ }
1484
+ else {
1485
+ throw new Error(`Only password secrets are implemented atm.`);
1486
+ }
1487
+ }
1488
+ const separator = '-------------';
1489
+ const secretInfosMsgBlock = secretInfos.map(secretInfo => {
1490
+ return `name: ${secretInfo.name}
1491
+ description: ${secretInfo.description}
1492
+ hint: ${secretInfo.hint}`;
1493
+ }).join('\n' + separator + '\n');
1494
+ // prompt user
1495
+ const title = `Gimme a password.`;
1496
+ const msg = `Enter the password corresponding to the following secret(s):\n
1497
+ ${separator}\n\n
1498
+ ${secretInfosMsgBlock}
1499
+ `;
1500
+ let password = await fnPromptPassword(title, msg);
1501
+ // cache if applicable
1502
+ if (password && cacheAfter) {
1503
+ await this.setCachedSecretPassword({
1504
+ cacheKey: secretsCacheKey,
1505
+ secretPassword: password,
1506
+ });
1507
+ }
1508
+ // we're done
1509
+ return password;
1510
+ }
1511
+ catch (error) {
1512
+ console.error(`${lc} ${error.message}`);
1513
+ throw error;
1514
+ }
1515
+ finally {
1516
+ if (!erroredDueToPromptTimeout) {
1517
+ // if we errored due to prompt timeout, then some other call to this
1518
+ // function is prompting and we don't want to turn off their flag.
1519
+ this.isPrompting = false;
1520
+ }
1521
+ }
1522
+ }
1523
+ async getCiphertextIbGib({ plaintext, password, encryptionIbGib, confirm, persist, ibRoot, publicIbMetadata, publicMetadata, }) {
1524
+ const lc = `${this.lc}[${this.getCiphertextIbGib.name}]`;
1525
+ try {
1526
+ const encryptionInfo = encryptionIbGib.data;
1527
+ if (encryptionInfo?.method !== 'encrypt-gib (weak)') {
1528
+ throw new Error('only encrypt-gib is implemented.');
1529
+ }
1530
+ const info = encryptionInfo;
1531
+ const resEncrypt = await encrypt({
1532
+ dataToEncrypt: plaintext,
1533
+ secret: password,
1534
+ initialRecursions: info.initialRecursions,
1535
+ recursionsPerHash: info.recursionsPerHash,
1536
+ salt: info.salt,
1537
+ saltStrategy: info.saltStrategy,
1538
+ hashAlgorithm: info.hashAlgorithm,
1539
+ encryptedDataDelimiter: info.encryptedDataDelimiter,
1540
+ confirm,
1541
+ });
1542
+ if (resEncrypt.warnings?.length ?? 0 > 0) {
1543
+ console.warn(`${lc} warnings: ${resEncrypt.warnings.join('\n')}`);
1544
+ }
1545
+ if (resEncrypt.errors?.length ?? 0 > 0) {
1546
+ throw new Error(resEncrypt.errors.join('\n'));
1547
+ }
1548
+ if (!resEncrypt.encryptedData) {
1549
+ throw new Error(`encryptedData is falsy`);
1550
+ }
1551
+ const data = { ciphertext: resEncrypt.encryptedData, };
1552
+ if (publicMetadata) {
1553
+ data.metadata = publicMetadata;
1554
+ }
1555
+ const rel8ns = {
1556
+ encryption: [getIbGibAddr({ ibGib: encryptionIbGib })],
1557
+ };
1558
+ const resCiphertext = (await factory.firstGen({
1559
+ parentIbGib: factory.primitive({ ib: ibRoot || 'ciphertext' }),
1560
+ ib: publicIbMetadata ?
1561
+ `${ibRoot || 'ciphertext'} ${publicIbMetadata}` :
1562
+ `${ibRoot || 'ciphertext'}`,
1563
+ data,
1564
+ rel8ns,
1565
+ dna: false,
1566
+ tjp: { uuid: true, timestamp: true },
1567
+ nCounter: true,
1568
+ }));
1569
+ if (!resCiphertext.newIbGib) {
1570
+ throw new Error('Error creating ciphertext ibgib.');
1571
+ }
1572
+ if (persist) {
1573
+ await this.persistTransformResult({ resTransform: resCiphertext });
1574
+ }
1575
+ return resCiphertext;
1576
+ }
1577
+ catch (error) {
1578
+ console.error(`${lc} ${error.message}`);
1579
+ throw error;
1580
+ }
1581
+ }
1582
+ /**
1583
+ * Brings together a ciphertext and secretIbGibs to decrypt
1584
+ * the `ciphertextIbGib.data.ciphertext`
1585
+ * @returns plaintext string of `ciphertextIbGib.data.ciphertext`
1586
+ */
1587
+ async getPlaintextString({ ciphertextIbGib, secretIbGibs, fnPromptPassword, dontPrompt, space, }) {
1588
+ const lc = `${this.lc}[${this.getPlaintextString.name}]`;
1589
+ try {
1590
+ // validate
1591
+ if ((secretIbGibs || []).length === 0) {
1592
+ throw new Error(`secretIbGibs required.`);
1593
+ }
1594
+ if (!ciphertextIbGib.data) {
1595
+ throw new Error(`ciphertextIbGib.data falsy (E: 598fc6473149e240a7d6916ecf642323)`);
1596
+ }
1597
+ if (!ciphertextIbGib.data.ciphertext) {
1598
+ throw new Error(`ciphertextIbGib.data.ciphertext falsy (E: 0e764a71ec214132a5a528f17f495a7c)`);
1599
+ }
1600
+ if (!ciphertextIbGib.rel8ns?.encryption) {
1601
+ throw new Error(`ciphertextIbGib.rel8ns.encryption falsy`);
1602
+ }
1603
+ if (ciphertextIbGib.rel8ns.encryption.length !== 1) {
1604
+ throw new Error(`ciphertextIbGib.rel8ns!.encryption!.length !== 1`);
1605
+ }
1606
+ // get corresponding encryption ibgib for encryption settings
1607
+ const encryptionAddr = ciphertextIbGib.rel8ns.encryption[0];
1608
+ const resEncryption = await this.get({ addr: encryptionAddr, space });
1609
+ if (!resEncryption.success) {
1610
+ throw new Error(`get encryption failed`);
1611
+ }
1612
+ if ((resEncryption.ibGibs || []).length !== 1) {
1613
+ throw new Error(`get encryption retrieved non-1 length (eesh)`);
1614
+ }
1615
+ const encryptionIbGib = resEncryption.ibGibs[0];
1616
+ if (!encryptionIbGib.data) {
1617
+ throw new Error('encryptionIbGib.data falsy');
1618
+ }
1619
+ // prompt user for the password
1620
+ const password = await this.getPasswordForSecrets({
1621
+ secretIbGibs,
1622
+ fnPromptPassword,
1623
+ dontPrompt,
1624
+ checkCacheFirst: true,
1625
+ cacheAfter: true,
1626
+ });
1627
+ // we're about the decrypt, but maybe the data doesn't have everything.
1628
+ // So WARN for any defaults we're using.
1629
+ if (!encryptionIbGib.data.initialRecursions) {
1630
+ console.warn(`${lc} using default initialRecursions`);
1631
+ }
1632
+ if (!encryptionIbGib.data.recursionsPerHash) {
1633
+ console.warn(`${lc} using default recursionsPerHash`);
1634
+ }
1635
+ if (!encryptionIbGib.data.saltStrategy) {
1636
+ console.warn(`${lc} using default saltStrategy`);
1637
+ }
1638
+ if (!encryptionIbGib.data.hashAlgorithm) {
1639
+ console.warn(`${lc} using default hashAlgorithm`);
1640
+ }
1641
+ // do actual decryption
1642
+ if (logalot) {
1643
+ console.log(`${lc} starting decrypt...`);
1644
+ }
1645
+ const timerName = 'sync_log decrypt';
1646
+ console.time(timerName);
1647
+ console.timeLog(timerName, 'decrypting...');
1648
+ const resDecrypt = await decrypt({
1649
+ encryptedData: ciphertextIbGib.data.ciphertext,
1650
+ secret: password ?? '',
1651
+ initialRecursions: encryptionIbGib.data.initialRecursions || DEFAULT_ENCRYPTION_INITIAL_RECURSIONS,
1652
+ recursionsPerHash: encryptionIbGib.data.recursionsPerHash || DEFAULT_ENCRYPTION_RECURSIONS_PER_HASH,
1653
+ salt: encryptionIbGib.data.salt,
1654
+ saltStrategy: encryptionIbGib.data.saltStrategy || DEFAULT_ENCRYPTION_SALT_STRATEGY,
1655
+ hashAlgorithm: encryptionIbGib.data.hashAlgorithm || DEFAULT_ENCRYPTION_HASH_ALGORITHM,
1656
+ encryptedDataDelimiter: encryptionIbGib.data.encryptedDataDelimiter,
1657
+ });
1658
+ console.timeLog(timerName, 'decrypting complete.');
1659
+ console.timeEnd(timerName);
1660
+ if (logalot) {
1661
+ console.log(`${lc} decrypt complete.`);
1662
+ }
1663
+ if (resDecrypt.errors?.length ?? 0 > 0) {
1664
+ throw new Error(resDecrypt.errors.join('|'));
1665
+ }
1666
+ if (!resDecrypt.decryptedData) {
1667
+ throw new Error(`(UNEXPECTED) resDecrypt has no errors but resDecrypt.decryptedData falsy? (E: 06e73992fb02e45e3c18db33f9a61b23)`);
1668
+ }
1669
+ // we're done
1670
+ return resDecrypt.decryptedData;
1671
+ }
1672
+ catch (error) {
1673
+ console.error(`${lc} ${error.message}`);
1674
+ throw error;
1675
+ }
1676
+ }
1677
+ async unwrapEncryptedSyncSpace({ encryptedSpace, fnPromptPassword, dontPrompt, space, fnSpaceFactory, }) {
1678
+ const lc = `${this.lc}[${this.unwrapEncryptedSyncSpace.name}]`;
1679
+ try {
1680
+ // validation
1681
+ if (!space) {
1682
+ throw new Error(`space required (E: d4d3eaa2d7b9143cf1173b8ae6344c23)`);
1683
+ }
1684
+ if (!encryptedSpace.rel8ns?.ciphertext) {
1685
+ throw new Error(`encryptedSpace is not a ciphertext`);
1686
+ }
1687
+ if (encryptedSpace.rel8ns.ciphertext.length !== 1) {
1688
+ throw new Error(`only 1 ciphertext rel8n allowed...`);
1689
+ }
1690
+ // get ciphertext ibgib
1691
+ const ciphertextAddr = encryptedSpace.rel8ns.ciphertext[0];
1692
+ const resCiphertext = await this.get({ addr: ciphertextAddr, space });
1693
+ if (!resCiphertext.success) {
1694
+ throw new Error(`get ciphertext failed`);
1695
+ }
1696
+ if ((resCiphertext.ibGibs || []).length !== 1) {
1697
+ throw new Error(`get ciphertext retrieved non-1 length (eesh)`);
1698
+ }
1699
+ const ciphertextIbGib = resCiphertext.ibGibs[0];
1700
+ // get secrets associated with enciphered space
1701
+ if (!encryptedSpace.rel8ns?.secret) {
1702
+ throw new Error('!encryptionIbGib.rel8ns?.secret');
1703
+ }
1704
+ const secretAddrs = encryptedSpace.rel8ns.secret;
1705
+ const localUserSpace = await this.getLocalUserSpace({});
1706
+ if (!localUserSpace) {
1707
+ throw new Error(`(UNEXPECTED) could not get localUserSpace? (E: 3c5687a15b3b58e3dcf1eca4f5fe5723)`);
1708
+ }
1709
+ const argGetSecrets = await localUserSpace.argy({
1710
+ argData: { ibGibAddrs: secretAddrs, cmd: 'get', }
1711
+ });
1712
+ const resSecrets = await localUserSpace.witness(argGetSecrets);
1713
+ if (!resSecrets.data?.success || (resSecrets.ibGibs || []).length === 0) {
1714
+ throw new Error(`couldn't get secret ibgibs`);
1715
+ }
1716
+ const secretIbGibs = resSecrets.ibGibs.concat();
1717
+ // get plaintext now that we have the ciphertext ibgib and secret ibgib(s)
1718
+ const plaintextString = await this.getPlaintextString({
1719
+ ciphertextIbGib: ciphertextIbGib,
1720
+ fnPromptPassword,
1721
+ dontPrompt,
1722
+ secretIbGibs,
1723
+ space,
1724
+ });
1725
+ const syncSpaceData = JSON.parse(plaintextString);
1726
+ if (syncSpaceData.type !== 'sync') {
1727
+ throw new Error(`syncSpaceData.type !== 'sync'...this is the only one implemented right now`);
1728
+ }
1729
+ if (syncSpaceData.subtype !== 'aws-dynamodb') {
1730
+ throw new Error(`syncSpaceData.subtype !== 'aws-dynamodb'...only one right now dude`);
1731
+ }
1732
+ // this is the original aws only implementation. I've just added (untested)
1733
+ // a quick factory function where the consumer would do the following code.
1734
+ const unwrappedSpace = await fnSpaceFactory(syncSpaceData);
1735
+ return unwrappedSpace;
1736
+ // so we have a syncspace data (only aws-dynamodb space right now).
1737
+ // load this data into a space class with behavior (not just the dto).
1738
+ // const awsSpace = new AWSDynamoSpace_V1(syncSpaceData, null);
1739
+ // awsSpace.gib = await getGib({ ibGib: awsSpace, hasTjp: false });
1740
+ // if (logalot) { console.log(`awsSpace.gib: ${awsSpace.gib}`); }
1741
+ // return awsSpace;
1742
+ }
1743
+ catch (error) {
1744
+ console.error(`${lc} ${error.message}`);
1745
+ throw error;
1746
+ }
1747
+ }
1748
+ /**
1749
+ * Caching user password secret in memory only.
1750
+ *
1751
+ * Just to prevent plaintext passwords from just sitting in memory,
1752
+ * this is a slight layer of indirection for caching
1753
+ *
1754
+ * @returns user password
1755
+ */
1756
+ async getCachedSecretPassword({ cacheKey, }) {
1757
+ const lc = `${this.lc}[${this.getCachedSecretPassword.name}]`;
1758
+ try {
1759
+ if (!cacheKey) {
1760
+ throw new Error(`secretAddr required`);
1761
+ }
1762
+ let entry = this.passwordCache[cacheKey];
1763
+ if (!entry) {
1764
+ if (logalot) {
1765
+ console.log(`${lc} secretAddr not cached: ${cacheKey}`);
1766
+ }
1767
+ return undefined;
1768
+ }
1769
+ // settings must match, but I'm feeling lazy on DRYing
1770
+ if (logalot) {
1771
+ console.log(`${lc} starting decrypt...`);
1772
+ }
1773
+ let resDecrypt = await decrypt({
1774
+ encryptedData: entry.encryptedPassword,
1775
+ secret: entry.tempMetaPassword,
1776
+ initialRecursions: 10000,
1777
+ recursionsPerHash: 5,
1778
+ salt: entry.salt,
1779
+ saltStrategy: 'appendPerHash',
1780
+ hashAlgorithm: 'SHA-512',
1781
+ });
1782
+ if (logalot) {
1783
+ console.log(`${lc} decrypt complete.`);
1784
+ }
1785
+ if (!resDecrypt.decryptedData) {
1786
+ throw new Error(`resDecrypt.decryptedData falsy`);
1787
+ }
1788
+ return resDecrypt.decryptedData;
1789
+ }
1790
+ catch (error) {
1791
+ console.error(`${lc} ${error.message}`);
1792
+ return undefined;
1793
+ }
1794
+ }
1795
+ async setCachedSecretPassword({ cacheKey, secretPassword, force, }) {
1796
+ const lc = `${this.lc}[${this.getCachedSecretPassword.name}]`;
1797
+ try {
1798
+ if (!cacheKey) {
1799
+ throw new Error(`secretAddr required`);
1800
+ }
1801
+ if (this.passwordCache[cacheKey]) {
1802
+ if (force) {
1803
+ if (logalot) {
1804
+ console.log(`already cached, but force is true: ${cacheKey}`);
1805
+ }
1806
+ delete this.passwordCache[cacheKey];
1807
+ }
1808
+ else {
1809
+ if (logalot) {
1810
+ console.log(`already cached: ${cacheKey}`);
1811
+ }
1812
+ return undefined;
1813
+ }
1814
+ }
1815
+ const tempMetaPassword = await getUUID(256);
1816
+ const salt = await getUUID();
1817
+ // settings must match, but I'm feeling lazy on DRYing
1818
+ let resEncrypt = await encrypt({
1819
+ dataToEncrypt: secretPassword,
1820
+ secret: tempMetaPassword,
1821
+ initialRecursions: 10000,
1822
+ recursionsPerHash: 5,
1823
+ salt: salt,
1824
+ saltStrategy: 'appendPerHash',
1825
+ hashAlgorithm: 'SHA-512',
1826
+ });
1827
+ if (!resEncrypt.encryptedData) {
1828
+ throw new Error(`resEncrypt.encryptedData falsy`);
1829
+ }
1830
+ const encryptedPassword = resEncrypt.encryptedData;
1831
+ let entry = { tempMetaPassword, salt, encryptedPassword, };
1832
+ this.passwordCache[cacheKey] = entry;
1833
+ if (logalot) {
1834
+ console.log(`${lc} entry added for ${cacheKey}.`);
1835
+ }
1836
+ }
1837
+ catch (error) {
1838
+ console.error(`${lc} ${error.message}`);
1839
+ return undefined;
1840
+ }
1841
+ }
1842
+ /**
1843
+ * If we don't have outerspaces/cloud endpoints, we'll do that here.
1844
+ *
1845
+ * @returns true if creation was successfully created, else false.
1846
+ */
1847
+ async _createOuterspaceAndRequiredIbGibs({ space, fnPromptSecret, fnPromptEncryption, fnPromptOuterSpace, }) {
1848
+ const lc = `${this.lc}[${this._createOuterspaceAndRequiredIbGibs.name}]`;
1849
+ try {
1850
+ const createdSecret = await this._createSecret({ space, fnPromptSecret });
1851
+ if (logalot) {
1852
+ console.log(`${lc} createdSecret: ${createdSecret} (I: 9fc011d8ecb1e10c86c86025be4d5c22)`);
1853
+ }
1854
+ if (!createdSecret) {
1855
+ return false;
1856
+ } // <<<< returns early
1857
+ const createdEncryption = await this._createEncryption({ space, fnPromptEncryption });
1858
+ if (logalot) {
1859
+ console.log(`${lc} createdEncryption: ${createdEncryption} (I: 6796bbeb7338471e965cf1806d0dea9c)`);
1860
+ }
1861
+ if (!createdEncryption) {
1862
+ return false;
1863
+ } // <<<< returns early
1864
+ const createdOuterspace = await this._createOuterspace({ space, fnPromptOuterSpace });
1865
+ if (logalot) {
1866
+ console.log(`${lc} createdOuterspace: ${createdOuterspace} (I: 6796bbeb7338471e965cf1806d0dea9c)`);
1867
+ }
1868
+ return createdOuterspace;
1869
+ }
1870
+ catch (error) {
1871
+ console.error(`${lc} ${error.message}`);
1872
+ return false;
1873
+ }
1874
+ }
1875
+ async _createSecret({ space, fnPromptSecret, }) {
1876
+ const lc = `${this.lc}[${this._createSecret.name}]`;
1877
+ try {
1878
+ if (logalot) {
1879
+ console.log(`${lc} starting...`);
1880
+ }
1881
+ const alert = this.getFnAlert();
1882
+ let secretIbGibs = await this.getSpecialRel8dIbGibs({
1883
+ type: "secrets",
1884
+ rel8nName: SECRET_REL8N_NAME,
1885
+ space,
1886
+ });
1887
+ if (secretIbGibs.length === 0) {
1888
+ await alert({
1889
+ title: 'first create some stuff...',
1890
+ msg: "First we'll need to do a couple things, like create a secret password, an encryption setting, and a cloud endpoint.",
1891
+ });
1892
+ }
1893
+ while (secretIbGibs.length === 0) {
1894
+ let secretIbGib = await fnPromptSecret(space);
1895
+ if (secretIbGib === undefined) {
1896
+ await alert({ title: 'cancelled', msg: 'Cancelled.' });
1897
+ return false;
1898
+ }
1899
+ await this.registerNewIbGib({ ibGib: secretIbGib, });
1900
+ await this.rel8ToSpecialIbGib({
1901
+ type: "secrets",
1902
+ rel8nName: SECRET_REL8N_NAME,
1903
+ ibGibsToRel8: [secretIbGib],
1904
+ space,
1905
+ });
1906
+ secretIbGibs = await this.getSpecialRel8dIbGibs({
1907
+ type: "secrets",
1908
+ rel8nName: SECRET_REL8N_NAME,
1909
+ space,
1910
+ });
1911
+ }
1912
+ return true;
1913
+ }
1914
+ catch (error) {
1915
+ console.error(`${lc} ${error.message}`);
1916
+ throw error;
1917
+ }
1918
+ finally {
1919
+ if (logalot) {
1920
+ console.log(`${lc} complete.`);
1921
+ }
1922
+ }
1923
+ }
1924
+ async _createEncryption({ space, fnPromptEncryption, }) {
1925
+ const lc = `${this.lc}[${this._createEncryption.name}]`;
1926
+ try {
1927
+ if (logalot) {
1928
+ console.log(`${lc} starting...`);
1929
+ }
1930
+ const alert = this.getFnAlert();
1931
+ let encryptionIbGibs = await this.getSpecialRel8dIbGibs({
1932
+ type: "encryptions",
1933
+ rel8nName: ENCRYPTION_REL8N_NAME,
1934
+ space,
1935
+ });
1936
+ if (encryptionIbGibs.length === 0) {
1937
+ await alert({
1938
+ title: 'next create an encryption...',
1939
+ msg: "Now we need to create an encryption setting. If you don't know what this is, just fill in the requirements and leave the others as defaults.",
1940
+ });
1941
+ }
1942
+ while (encryptionIbGibs.length === 0) {
1943
+ let encryptionIbGib = await fnPromptEncryption(space);
1944
+ if (encryptionIbGib === undefined) {
1945
+ await this.getFnAlert()({ title: 'cancelled', msg: 'Cancelled.' });
1946
+ return false;
1947
+ }
1948
+ await this.registerNewIbGib({ ibGib: encryptionIbGib, space });
1949
+ await this.rel8ToSpecialIbGib({
1950
+ type: "encryptions",
1951
+ rel8nName: ENCRYPTION_REL8N_NAME,
1952
+ ibGibsToRel8: [encryptionIbGib],
1953
+ space,
1954
+ });
1955
+ encryptionIbGibs = await this.getSpecialRel8dIbGibs({
1956
+ type: "encryptions",
1957
+ rel8nName: ENCRYPTION_REL8N_NAME,
1958
+ space,
1959
+ });
1960
+ }
1961
+ return true;
1962
+ }
1963
+ catch (error) {
1964
+ console.error(`${lc} ${error.message}`);
1965
+ throw error;
1966
+ }
1967
+ finally {
1968
+ if (logalot) {
1969
+ console.log(`${lc} complete.`);
1970
+ }
1971
+ }
1972
+ }
1973
+ async _createOuterspace({ space, fnPromptOuterSpace, }) {
1974
+ const lc = `${this.lc}[${this._createOuterspace.name}]`;
1975
+ try {
1976
+ const alert = this.getFnAlert();
1977
+ let outerspaceIbGibs = await this.getSpecialRel8dIbGibs({
1978
+ type: "outerspaces",
1979
+ rel8nName: SYNC_SPACE_REL8N_NAME,
1980
+ space,
1981
+ });
1982
+ if (outerspaceIbGibs.length === 0) {
1983
+ await alert({
1984
+ title: 'Now to outerspace...',
1985
+ msg: `Great! Now we can create an outerspace ibgib, which is like a connection from this local space to other spaces (like the cloud).`,
1986
+ });
1987
+ }
1988
+ while (outerspaceIbGibs.length === 0) {
1989
+ let outerspaceIbGib = await fnPromptOuterSpace(space);
1990
+ if (outerspaceIbGib === undefined) {
1991
+ break;
1992
+ }
1993
+ await this.registerNewIbGib({ ibGib: outerspaceIbGib, space });
1994
+ await this.rel8ToSpecialIbGib({
1995
+ type: "outerspaces",
1996
+ rel8nName: SYNC_SPACE_REL8N_NAME,
1997
+ ibGibsToRel8: [outerspaceIbGib],
1998
+ space,
1999
+ });
2000
+ await alert({
2001
+ title: 'Good job',
2002
+ msg: `Great! Now we can use this space to synchronize & import ibgibs.`,
2003
+ });
2004
+ outerspaceIbGibs = await this.getSpecialRel8dIbGibs({
2005
+ type: "outerspaces",
2006
+ rel8nName: SYNC_SPACE_REL8N_NAME,
2007
+ space,
2008
+ });
2009
+ }
2010
+ if (outerspaceIbGibs.length > 0) {
2011
+ return true;
2012
+ }
2013
+ else {
2014
+ await alert({ title: 'cancelled', msg: 'Cancelled.' });
2015
+ return false;
2016
+ }
2017
+ }
2018
+ catch (error) {
2019
+ console.log(`${lc} ${error.message}`);
2020
+ throw error;
2021
+ }
2022
+ }
2023
+ async getAppSyncSpaces({ unwrapEncrypted, createIfNone, dontPrompt, space, fnSpaceFactory, fnPromptSecret, fnPromptEncryption, fnPromptOuterSpace, }) {
2024
+ const lc = `${this.lc}[${this.getAppSyncSpaces.name}]`;
2025
+ try {
2026
+ // I don't want this pinging the user if we're on the welcome page.
2027
+ dontPrompt = dontPrompt ?? documentLocationIsAtWelcomePage();
2028
+ space = space ?? await this.getLocalUserSpace({});
2029
+ if (!space) {
2030
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: bf09346708ba4d6e9a1389bd1b66d500)`);
2031
+ }
2032
+ // get existing
2033
+ let appSyncSpaces = await this.getSpecialRel8dIbGibs({
2034
+ type: "outerspaces",
2035
+ rel8nName: SYNC_SPACE_REL8N_NAME,
2036
+ space,
2037
+ });
2038
+ // create if applicable
2039
+ if (appSyncSpaces.length === 0 && createIfNone) {
2040
+ const createdReqs = await this._createOuterspaceAndRequiredIbGibs({
2041
+ space,
2042
+ fnPromptSecret,
2043
+ fnPromptEncryption,
2044
+ fnPromptOuterSpace,
2045
+ });
2046
+ if (createdReqs) {
2047
+ appSyncSpaces = await this.getSpecialRel8dIbGibs({
2048
+ type: "outerspaces",
2049
+ rel8nName: SYNC_SPACE_REL8N_NAME,
2050
+ space,
2051
+ });
2052
+ }
2053
+ }
2054
+ // unwrap if requested
2055
+ let resSpaces = [];
2056
+ if (unwrapEncrypted) {
2057
+ for (let i = 0; i < appSyncSpaces.length; i++) {
2058
+ let syncSpace = appSyncSpaces[i];
2059
+ if (syncSpace.rel8ns) {
2060
+ if (syncSpace.rel8ns.ciphertext) {
2061
+ syncSpace = await this.unwrapEncryptedSyncSpace({
2062
+ encryptedSpace: syncSpace,
2063
+ fnPromptPassword: this.getFnPromptPassword(),
2064
+ dontPrompt,
2065
+ space,
2066
+ fnSpaceFactory,
2067
+ });
2068
+ }
2069
+ resSpaces.push(syncSpace);
2070
+ }
2071
+ else {
2072
+ }
2073
+ }
2074
+ }
2075
+ else {
2076
+ // still (probably) encrypted
2077
+ resSpaces = appSyncSpaces;
2078
+ }
2079
+ return resSpaces;
2080
+ }
2081
+ catch (error) {
2082
+ console.error(`${lc} ${error.message}`);
2083
+ return [];
2084
+ }
2085
+ }
2086
+ // async createRobbotIbGib({
2087
+ // robbotData,
2088
+ // space,
2089
+ // }: {
2090
+ // robbotData: RobbotData_V1,
2091
+ // space?: IbGibSpaceAny,
2092
+ // }): Promise<{ newRobbotIbGib: RobbotIbGib_V1, newRobbotsAddr: string }> {
2093
+ // const lc = `${this.lc}[${this.createRobbotIbGib.name}]`;
2094
+ // try {
2095
+ // space = space ?? await this.getLocalUserSpace({});
2096
+ // if (!space) { throw new Error(`space falsy and localUserSpace not initialized (E: 33ea7f4633484afa984225d037478ac4)`); }
2097
+ // return createRobbotIbGib({
2098
+ // robbotData,
2099
+ // space,
2100
+ // zeroSpace: this.zeroSpace,
2101
+ // fnBroadcast: (x) => this.fnBroadcast(x),
2102
+ // fnUpdateBootstrap: (x) => this.fnUpdateBootstrap(x),
2103
+ // });
2104
+ // } catch (error) {
2105
+ // console.error(`${lc} ${error.message}`);
2106
+ // throw error;
2107
+ // }
2108
+ // }
2109
+ async getAppRobbotIbGibs({ createIfNone, space, }) {
2110
+ const lc = `${this.lc}[${this.getAppRobbotIbGibs.name}]`;
2111
+ try {
2112
+ space = space ?? await this.getLocalUserSpace({});
2113
+ if (!space) {
2114
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: bf09346708ba4d6e9a1389bd1b66d500)`);
2115
+ }
2116
+ // get existing. Note that these are not the robbot witnesses, but only
2117
+ // the robbot ibgib (dtos). They do not have a `witness` function on them
2118
+ // at this point.
2119
+ let appRobbots_MaybeOutOfDate = await this.getSpecialRel8dIbGibs({
2120
+ type: "robbots",
2121
+ rel8nName: ROBBOT_REL8N_NAME,
2122
+ space,
2123
+ });
2124
+ let appRobbots = [];
2125
+ for (let i = 0; i < appRobbots_MaybeOutOfDate.length; i++) {
2126
+ let robbotIbGib = appRobbots_MaybeOutOfDate[i];
2127
+ let robbotAddr = getIbGibAddr({ ibGib: robbotIbGib });
2128
+ const latestAddr = await this.getLatestAddr({ ibGib: robbotIbGib });
2129
+ if (latestAddr && latestAddr !== robbotAddr) {
2130
+ // robbot has a newer ibgib in its timeline
2131
+ let resGet = await this.get({ addr: latestAddr });
2132
+ if (!resGet || !resGet?.success || (resGet?.ibGibs ?? []).length === 0) {
2133
+ throw new Error(`could not get newer robbot ibgib (E: 15fa346c8ac17edb96e4b0870104c122)`);
2134
+ }
2135
+ robbotIbGib = resGet.ibGibs[0];
2136
+ robbotAddr = getIbGibAddr({ ibGib: robbotIbGib });
2137
+ }
2138
+ const errors = await validateCommonRobbotIbGib({ robbotIbGib });
2139
+ if ((errors ?? []).length === 0) {
2140
+ // only add if robbot doesn't have validation errors
2141
+ appRobbots.push(robbotIbGib);
2142
+ }
2143
+ else {
2144
+ console.error(`${lc} robbot ibGib (${robbotAddr}) has validation errors: ${errors}`);
2145
+ }
2146
+ }
2147
+ // create if applicable
2148
+ if (appRobbots.length === 0 && createIfNone) {
2149
+ console.error(`${lc} creating new robbot but should be not casting this on next line in src code. (E: 3252c5917e11421dbc1c26b280b8aeef)`);
2150
+ let robbot = await createNewRobbot({ ibgibs: this, space });
2151
+ if (robbot) {
2152
+ appRobbots = await this.getSpecialRel8dIbGibs({
2153
+ type: "robbots",
2154
+ rel8nName: ROBBOT_REL8N_NAME,
2155
+ space,
2156
+ });
2157
+ }
2158
+ }
2159
+ return appRobbots;
2160
+ }
2161
+ catch (error) {
2162
+ console.error(`${lc} ${error.message}`);
2163
+ return [];
2164
+ }
2165
+ }
2166
+ async getAppAppIbGibs({ createIfNone, space, }) {
2167
+ const lc = `${this.lc}[${this.getAppAppIbGibs.name}]`;
2168
+ try {
2169
+ space = space ?? await this.getLocalUserSpace({});
2170
+ if (!space) {
2171
+ throw new Error(`space falsy and localUserSpace not initialized (?) (E: a5aec4d94f764c6a964179bbb743b577)`);
2172
+ }
2173
+ // get existing. Note that these are not the app witnesses, but only
2174
+ // the app ibgib (dtos). They do not have a `witness` function on them
2175
+ // at this point.
2176
+ let appApps_MaybeOutOfDate = await this.getSpecialRel8dIbGibs({
2177
+ type: "apps",
2178
+ rel8nName: APP_REL8N_NAME,
2179
+ space,
2180
+ });
2181
+ let appApps = [];
2182
+ for (let i = 0; i < appApps_MaybeOutOfDate.length; i++) {
2183
+ const appIbGib = appApps_MaybeOutOfDate[i];
2184
+ const appAddr = getIbGibAddr({ ibGib: appIbGib });
2185
+ const latestAddr = await this.getLatestAddr({ ibGib: appIbGib });
2186
+ if (latestAddr && latestAddr !== appAddr) {
2187
+ // app has a newer ibgib in its timeline
2188
+ let resGet = await this.get({ addr: latestAddr });
2189
+ if (!resGet || !resGet?.success || (resGet?.ibGibs ?? []).length === 0) {
2190
+ throw new Error(`could not get newer app ibgib (E: de6a77634b1e4e16914ef110bb263d7c)`);
2191
+ }
2192
+ appApps.push(resGet.ibGibs[0]);
2193
+ }
2194
+ else {
2195
+ appApps.push(appIbGib);
2196
+ }
2197
+ }
2198
+ // create if applicable
2199
+ if (appApps.length === 0 && createIfNone) {
2200
+ console.error(`${lc} creating new app but should be not casting this on next line in src code. (E: 3252c5917e11421dbc1c26b280b8aeef)`);
2201
+ let app = await createNewApp({ ibgibs: this, space });
2202
+ if (app) {
2203
+ appApps = await this.getSpecialRel8dIbGibs({
2204
+ type: "apps",
2205
+ rel8nName: APP_REL8N_NAME,
2206
+ space,
2207
+ });
2208
+ }
2209
+ }
2210
+ return appApps;
2211
+ }
2212
+ catch (error) {
2213
+ console.error(`${lc} ${error.message}`);
2214
+ return [];
2215
+ }
2216
+ }
2217
+ async syncIbGibs({ dependencyGraphIbGibs,
2218
+ // confirm,
2219
+ watch, fnPreSyncProgress, fnSpaceFactory, fnPromptSecret, fnPromptEncryption, fnPromptOuterSpace, }) {
2220
+ const lc = `${this.lc}[${this.syncIbGibs.name}]`;
2221
+ // map of saga infos across all spaces
2222
+ // const sagaInfoMap: { [spaceGib: string]: SyncSagaInfo } = {};
2223
+ try {
2224
+ if (this.syncing) {
2225
+ console.warn(`already syncing. (E: dfa3ad58e97f4b18b4e4d7dc252208fb)`);
2226
+ return;
2227
+ }
2228
+ if (Object.values(this.sagaInfoMap).length > 0) {
2229
+ throw new Error(`this._syncing is false but sagaInfoMap not cleaned up(?). (E: bb69c808877c4931b5481585043c18e7)(UNEXPECTED)`);
2230
+ }
2231
+ this._syncing = true;
2232
+ // have to make sagaId and syncStatus$ early to enable timeLog calls
2233
+ const sagaId = (await getUUID()).slice(0, 24);
2234
+ const syncStatus$ = new ReplaySubject();
2235
+ const syncTimelogName = `sync_log ${sagaId}`;
2236
+ console.time(syncTimelogName);
2237
+ console.timeLog(syncTimelogName, 'start');
2238
+ this.subSagaSyncTimeLog = syncStatus$.subscribe({
2239
+ next: (status) => {
2240
+ if (status.data?.statusCode === StatusCode.completed) {
2241
+ console.timeLog(syncTimelogName, 'StatusCode.complete');
2242
+ }
2243
+ },
2244
+ error: (_) => {
2245
+ console.timeEnd(syncTimelogName);
2246
+ this.subSagaSyncTimeLog?.unsubscribe();
2247
+ },
2248
+ complete: () => {
2249
+ console.timeEnd(syncTimelogName);
2250
+ this.subSagaSyncTimeLog?.unsubscribe();
2251
+ }
2252
+ });
2253
+ // #region validate
2254
+ if (logalot) {
2255
+ console.log(`${lc} starting...`);
2256
+ }
2257
+ if (!dependencyGraphIbGibs || dependencyGraphIbGibs.length === 0) {
2258
+ throw new Error(`ibGibs required. (E: 404c36475fb84fc285a23a67c0b8fcb2)`);
2259
+ }
2260
+ // #endregion
2261
+ const localUserSpace = await this.getLocalUserSpace({});
2262
+ if (!localUserSpace?.data) {
2263
+ throw new Error(`localUserSpace?.data falsy (E: e7ff57e4d529cde903619078ee9b6e23)`);
2264
+ }
2265
+ if (!localUserSpace.gib) {
2266
+ throw new Error(`localUserSpace.gib falsy (E: 884d86d20e7a4468b3c8b2c3ab7dba7e)`);
2267
+ }
2268
+ // #region get sync spaces and build participant infos
2269
+ if (logalot) {
2270
+ console.log(`${lc} get sync spaces (returns if none)`);
2271
+ }
2272
+ console.timeLog(syncTimelogName, 'getAppSyncSpaces starting (unwrapEncrypted is true) starting...');
2273
+ if (fnPreSyncProgress) {
2274
+ fnPreSyncProgress('getting app sync spaces... (I: aa2e8f32ab26457bad703218aa7fb47d)');
2275
+ }
2276
+ const appSyncSpaces = await this.getAppSyncSpaces({
2277
+ unwrapEncrypted: true,
2278
+ createIfNone: true,
2279
+ space: localUserSpace,
2280
+ fnSpaceFactory,
2281
+ fnPromptSecret,
2282
+ fnPromptEncryption,
2283
+ fnPromptOuterSpace,
2284
+ });
2285
+ if (fnPreSyncProgress) {
2286
+ fnPreSyncProgress('build complete. (I: 391a9aa7749d45b1aecf9a0010d9937f)');
2287
+ }
2288
+ console.timeLog(syncTimelogName, 'getAppSyncSpaces starting (unwrapEncrypted is true) complete.');
2289
+ if (appSyncSpaces.length === 0) {
2290
+ const msg = `Can't sync without sync spaces...wrong password? Cancelling. Restart app to retry password (I know it sucks!...just me coding this thing right now)`;
2291
+ if (logalot) {
2292
+ console.log(`${lc} ${msg}`);
2293
+ }
2294
+ ;
2295
+ const fnAlert = this.getFnAlert();
2296
+ await fnAlert({ title: "Cancelled", msg });
2297
+ this._syncing = false;
2298
+ console.timeLog(syncTimelogName, 'cancelled');
2299
+ console.timeEnd(syncTimelogName);
2300
+ return;
2301
+ }
2302
+ // const localUserSpace = await this.getLocalUserSpace({});
2303
+ const participants = [
2304
+ // local user space is the src
2305
+ { id: localUserSpace.data.uuid, gib: localUserSpace.gib, s_d: 'src', },
2306
+ // each sync space is a destination
2307
+ ...appSyncSpaces.map(s => {
2308
+ if (!s.data) {
2309
+ throw new Error(`space.data required. (E: 3c192771e84445a4b6476d5193b07e9d)`);
2310
+ }
2311
+ if (!s.data.uuid) {
2312
+ throw new Error(`space.data.uuid required. (E: d27e9998227840f99d45a3ed245f3196)`);
2313
+ }
2314
+ if (!s.gib) {
2315
+ throw new Error(`space.gib required. (E: db73aceb2f8445d8964ae49b59957072)`);
2316
+ }
2317
+ return { id: s.data.uuid, gib: s.gib, s_d: 'dest', };
2318
+ }),
2319
+ ];
2320
+ // #endregion
2321
+ // if (fnPreSyncProgress) { fnPreSyncProgress('building dependency graph... (I: ae178a39c2594557b6d0489b02336ecd)'); }
2322
+ // get **ALL** ibgibs that we'll need to put/merge
2323
+ // const allIbGibsToSync: { [addr: string]: IbGib_V1 } = {};
2324
+ // dependencyGraphIbGibs.forEach(x => { allIbGibsToSync[getIbGibAddr({ ibGib: x })] = x });
2325
+ // await this._getAllIbGibsToSyncFromGraph({ dependencyGraphIbGibs, space: localUserSpace });
2326
+ // _NOW_ we can finally put/merge into sync spaces.
2327
+ // this returns to us the most recent versions which we can update
2328
+ // our local timelines if we so choose (which we will).
2329
+ // NOTE: we won't worry about what if different sync spaces have different
2330
+ // versions atm. We're just going to do this assuming sync spaces
2331
+ // are nice and coordinated (which they aren't).
2332
+ if (logalot) {
2333
+ console.log(`${lc} syncing to spaces in parallel...`);
2334
+ }
2335
+ const multiSpaceOpId = await getUUID();
2336
+ const allSagaInfos = [];
2337
+ const startSyncPromises = appSyncSpaces.map(async (syncSpace) => {
2338
+ // create the info that will track progress over entire sync saga
2339
+ const sagaInfo = await this._createNewSyncSagaInfo({
2340
+ multiSpaceOpId,
2341
+ allIbGibsToSync: dependencyGraphIbGibs,
2342
+ syncSpace,
2343
+ participants,
2344
+ sagaId,
2345
+ syncStatus$,
2346
+ });
2347
+ this.sagaInfoMap[sagaInfo.sagaId] = sagaInfo;
2348
+ allSagaInfos.push(sagaInfo);
2349
+ try {
2350
+ // _startSync creates a status observable that can keep us up to date
2351
+ // on the status updates throughout the sync saga. We can handle
2352
+ // updating our own local space based on those status updates.
2353
+ // await this._startSync({syncSagaInfo: sagaInfo, confirm});
2354
+ // await this._startSync({ syncSagaInfo: sagaInfo, watch, syncTimelogName });
2355
+ // taking out watch for now
2356
+ await this._startSync({ syncSagaInfo: sagaInfo, watch: false, syncTimelogName });
2357
+ }
2358
+ catch (error) {
2359
+ // if this throws, then that is unexpected. The above result should
2360
+ // always be returned, and if it's errored then it should indicate as
2361
+ // such.
2362
+ console.error(`${lc} (UNEXPECTED) ${error.message}`);
2363
+ throw error;
2364
+ }
2365
+ });
2366
+ // await just the initial starting of each space's sync operation. when
2367
+ // this promise is awaited, the sync operation is not done, only the
2368
+ // starting of all sync sagas across all spaces.
2369
+ console.timeLog(syncTimelogName, 'awaiting all startSyncPromises starting...');
2370
+ await Promise.all(startSyncPromises);
2371
+ console.timeLog(syncTimelogName, 'awaiting all startSyncPromises complete.');
2372
+ // at this point, all spaces have prepared and are going. the sync saga
2373
+ // info attached to each arg/result ibgib has the observable syncStatus$
2374
+ // that will produce the status updates which can be interpreted &
2375
+ // responded to.
2376
+ await this._handleSagaUpdates();
2377
+ return allSagaInfos;
2378
+ }
2379
+ catch (error) {
2380
+ console.error(`${lc} ${error.message}`);
2381
+ this.finalizeAllSyncSagas_NoThrow({ error });
2382
+ throw error;
2383
+ }
2384
+ finally {
2385
+ if (logalot) {
2386
+ console.log(`${lc} complete.`);
2387
+ }
2388
+ }
2389
+ }
2390
+ finalizeSyncSaga({ sagaInfo, error, }) {
2391
+ const lc = `${this.lc}[${this.finalizeSyncSaga.name}]`;
2392
+ try {
2393
+ if (logalot) {
2394
+ console.log(`${lc} starting...`);
2395
+ }
2396
+ if (sagaInfo.complete) {
2397
+ return;
2398
+ }
2399
+ if (!sagaInfo.syncStatus$.closed) {
2400
+ if (error) {
2401
+ const emsg = typeof (error) === 'string' ? error : error.message ??
2402
+ `${lc} something went wrong (E: d7db873d9e8b4f14b5b490cadd9730f4)`;
2403
+ console.error(emsg);
2404
+ sagaInfo.syncStatus$.error(emsg);
2405
+ }
2406
+ sagaInfo.syncStatus$.complete();
2407
+ }
2408
+ // I think $.complete() closes subscriptions, but to be double sure...
2409
+ (sagaInfo.syncStatusSubscriptions ?? [])
2410
+ .filter(sub => sub && !sub.closed)
2411
+ .forEach(sub => { sub.unsubscribe(); });
2412
+ if (logalot) {
2413
+ console.log(`${lc} setting sagaInfo.complete to true (I: 85c34469cdac404782c2024ad6b6fbd1)`);
2414
+ }
2415
+ sagaInfo.complete = true;
2416
+ this._updateSagaInfoMapAndIsSyncingFlag();
2417
+ if (logalot) {
2418
+ console.log(`${lc} complete.`);
2419
+ }
2420
+ }
2421
+ catch (err) {
2422
+ console.error(`${lc} ${err.message}`);
2423
+ if (logalot) {
2424
+ console.log(`${lc} setting sagaInfo.complete to true (I: 23de6ef45eaf47a1918038dce3da7d78)`);
2425
+ }
2426
+ sagaInfo.complete = true;
2427
+ throw err;
2428
+ }
2429
+ finally {
2430
+ if (logalot) {
2431
+ console.log(`${lc} complete.`);
2432
+ }
2433
+ }
2434
+ }
2435
+ finalizeAllSyncSagas_NoThrow({ error, }) {
2436
+ const lc = `${this.lc}[${this.finalizeAllSyncSagas_NoThrow.name}]`;
2437
+ try {
2438
+ const syncSagaInfos_NotComplete = Object.values(this.sagaInfoMap).filter(x => !x.complete);
2439
+ for (let i = 0; i < syncSagaInfos_NotComplete.length; i++) {
2440
+ const sagaInfo = syncSagaInfos_NotComplete[i];
2441
+ this.finalizeSyncSaga({ sagaInfo, error });
2442
+ }
2443
+ }
2444
+ catch (error) {
2445
+ console.error(`${lc}(UNEXPECTED) ${error.message}`);
2446
+ // caller expects does NOT rethrow!
2447
+ }
2448
+ finally {
2449
+ this._updateSagaInfoMapAndIsSyncingFlag();
2450
+ }
2451
+ }
2452
+ _updateSagaInfoMapAndIsSyncingFlag() {
2453
+ const lc = `${this.lc}[${this._updateSagaInfoMapAndIsSyncingFlag.name}]`;
2454
+ try {
2455
+ if (logalot) {
2456
+ console.log(`${lc} starting...`);
2457
+ }
2458
+ const sagaInfoKeys = Object.keys(this.sagaInfoMap || {});
2459
+ if (sagaInfoKeys.length === 0) {
2460
+ this.sagaInfoMap = {};
2461
+ if (this._syncing) {
2462
+ this._syncing = false;
2463
+ }
2464
+ return; /* <<<< returns early */
2465
+ }
2466
+ const sagaInfos = Object.values(this.sagaInfoMap);
2467
+ if (sagaInfos.every(info => info.complete)) {
2468
+ if (logalot) {
2469
+ console.log(`${lc} all sagaInfos are complete. finalizing sync. (I: f6d94deb5509e6b2e5371b9bfc007422)`);
2470
+ }
2471
+ this.sagaInfoMap = {};
2472
+ this._syncing = false;
2473
+ if (logalot) {
2474
+ console.log(`${lc} this._syncing is now false.`);
2475
+ }
2476
+ }
2477
+ }
2478
+ catch (error) {
2479
+ console.error(`${lc} ${error.message}`);
2480
+ throw error;
2481
+ }
2482
+ finally {
2483
+ if (logalot) {
2484
+ console.log(`${lc} complete.`);
2485
+ }
2486
+ }
2487
+ }
2488
+ async _createNewSyncSagaInfo({ multiSpaceOpId, allIbGibsToSync, syncSpace, participants, sagaId, syncStatus$, }) {
2489
+ const lc = `${this.lc}[${this._createNewSyncSagaInfo.name}]`;
2490
+ try {
2491
+ if (!multiSpaceOpId) {
2492
+ throw new Error(`multiSpaceOpId required. (E: a7e228dbd63948d784a67ddbb342e4f7)`);
2493
+ }
2494
+ if (!syncSpace.data) {
2495
+ throw new Error(`syncSpace.data required. (E: 1c44334cf4545de147ef2dc675406a23)`);
2496
+ }
2497
+ // do the addrs outside of info initializer
2498
+ const syncAddrs_All = allIbGibsToSync.map(x => getIbGibAddr({ ibGib: x }));
2499
+ const syncAddrs_All_WithTjps = allIbGibsToSync
2500
+ .filter(x => hasTjp({ ibGib: x }))
2501
+ .map(x => getIbGibAddr({ ibGib: x }));
2502
+ const syncAddrs_All_AreTjps = allIbGibsToSync
2503
+ .filter(x => x.gib !== GIB && x.data?.isTjp === true)
2504
+ .map(x => getIbGibAddr({ ibGib: x }));
2505
+ const syncAddrs_All_WithoutTjps = syncAddrs_All.filter(addr => !syncAddrs_All_WithTjps.includes(addr));
2506
+ // do the info initializer
2507
+ const syncSagaInfo = {
2508
+ multiSpaceOpId,
2509
+ outerSpace: syncSpace,
2510
+ // spaceGib: syncSpace.gib,
2511
+ spaceId: syncSpace.data.uuid,
2512
+ sagaId,
2513
+ participants,
2514
+ witnessFnArgsAndResults$: new ReplaySubject(),
2515
+ // syncStatus$: new ReplaySubject<SyncStatusIbGib>(),
2516
+ syncStatus$,
2517
+ syncStatusSubscriptions: [],
2518
+ syncIbGibs_All: allIbGibsToSync,
2519
+ syncAddrs_All,
2520
+ syncAddrs_All_AreTjps,
2521
+ syncAddrs_All_WithTjps,
2522
+ syncAddrs_All_WithoutTjps,
2523
+ syncAddrs_Skipped: [],
2524
+ syncAddrs_ToDo: [],
2525
+ syncAddrs_InProgress: [],
2526
+ syncAddrs_Failed: [],
2527
+ };
2528
+ const syncTimelogName = `sync_log ${syncSagaInfo.sagaId}`;
2529
+ // console.time(syncTimelogName);
2530
+ console.timeLog(syncTimelogName);
2531
+ // return it
2532
+ return syncSagaInfo;
2533
+ }
2534
+ catch (error) {
2535
+ console.error(`${lc} ${error.message}`);
2536
+ throw error;
2537
+ }
2538
+ }
2539
+ /**
2540
+ * this {@link IbGibsService} acts as the local app space intermediary,
2541
+ * a broker between the local space and the sync space(s). So this
2542
+ * function's job is to coordinate sending the given ibgibs
2543
+ * to a single sync space and return the observable (subject)
2544
+ * corresponding to the multi-step sync process.
2545
+ *
2546
+ * The caller will be responsible for coordinating among sync
2547
+ * space results and handling updates to local space ibgib's,
2548
+ * such as rebasing/updating/etc.
2549
+ *
2550
+ * @returns
2551
+ */
2552
+ async _startSync({ syncSagaInfo, watch,
2553
+ // confirm,
2554
+ syncTimelogName, }) {
2555
+ const lc = `${this.lc}[${this._startSync.name}]`;
2556
+ try {
2557
+ const { multiSpaceOpId, participants, sagaId, outerSpace: syncSpace, syncIbGibs_All, syncAddrs_All, syncAddrs_All_WithTjps: syncAddrs_All_Tjps, syncAddrs_All_WithoutTjps: syncAddrs_All_NonTjps, } = syncSagaInfo;
2558
+ // first we want to get the ball rolling
2559
+ // we will get back an ibGib that we can use to track the progress of the
2560
+ // entire operation wrt this space.
2561
+ console.timeLog(syncTimelogName, `getLocalUserSpace starting...`);
2562
+ const localUserSpace = await this.getLocalUserSpace({});
2563
+ if (!localUserSpace) {
2564
+ throw new Error(`localUserSpace required (E: e01fc13ce7c5a802b50aa0f9b2c13a23)`);
2565
+ }
2566
+ if (!localUserSpace.data) {
2567
+ throw new Error(`localUserSpace.data required (E: e01fc13ce7c5a802b50aa0f9b2c13a23)`);
2568
+ }
2569
+ console.timeLog(syncTimelogName, `getLocalUserSpace complete.`);
2570
+ const argStartSync = await syncSpace.argy({
2571
+ argData: {
2572
+ // cmd: 'put', cmdModifiers: watch ? ['sync', 'watch'] : ['sync'],
2573
+ cmd: 'put', cmdModifiers: ['sync'],
2574
+ sagaId,
2575
+ participants,
2576
+ ibGibAddrs: syncAddrs_All,
2577
+ ibGibAddrs_All_Tjps: syncAddrs_All_Tjps,
2578
+ ibGibAddrs_All_NonTjps: syncAddrs_All_NonTjps,
2579
+ },
2580
+ ibGibs: syncIbGibs_All,
2581
+ ibMetadata: `sync src ${localUserSpace.data.name} srcId ${localUserSpace.data.uuid}`,
2582
+ });
2583
+ argStartSync.syncSagaInfo = syncSagaInfo;
2584
+ // atow we only have one cycle. in the future, I think we will be having the possibility
2585
+ // of multiple cycles, which is why I have this structured as an observable
2586
+ // and not hard-coding a single arg/result in the saga info.
2587
+ syncSagaInfo.witnessFnArgsAndResults$.next(argStartSync);
2588
+ console.timeLog(syncTimelogName, `syncSpace witness starting...`);
2589
+ const resStartSync = await syncSpace.witness(argStartSync);
2590
+ console.timeLog(syncTimelogName, `syncSpace witness complete.`);
2591
+ if (!resStartSync.data?.statusTjpAddr) {
2592
+ throw new Error(`resStartSync.data.statusTjpAddr is falsy. sagaId: ${sagaId} (E: 727b5cc1a0254497bc6e06e9c6760564)`);
2593
+ }
2594
+ syncSagaInfo.witnessFnArgsAndResults$.next(resStartSync);
2595
+ // in our return, we can check for updates since our last communication.
2596
+ // if (Object.keys(resStartSync.data.watchTjpUpdateMap ?? {}).length > 0) {
2597
+ // if (logalot) { console.log(`${lc} resStartSync.data.watchTjpUpdateMap: ${pretty(resStartSync.data.watchTjpUpdateMap)}`); }
2598
+ // console.timeLog(syncTimelogName, `handleWatchTjpUpdates starting...`);
2599
+ // await this.handleWatchTjpUpdates({
2600
+ // outerSpace: syncSpace,
2601
+ // updates: resStartSync.data.watchTjpUpdateMap,
2602
+ // localUserSpace,
2603
+ // });
2604
+ // console.timeLog(syncTimelogName, `handleWatchTjpUpdates complete.`);
2605
+ // }
2606
+ // most of our handling will be in subscription to syncStatus$ updates.
2607
+ return resStartSync;
2608
+ }
2609
+ catch (error) {
2610
+ console.error(`${lc} ${error.message}`);
2611
+ throw error;
2612
+ }
2613
+ }
2614
+ /**
2615
+ * Coming in to this function, we have results from one or more
2616
+ * sync spaces. Here are the combinations of expected outcomes:
2617
+ *
2618
+ * 1. All success, each returns the exact same new ib^gib address(es).
2619
+ * 2. All success, but different spaces return different ib^gib address(es).
2620
+ * 3. Some success, which returns exact same new ib^gib, some error.
2621
+ * 4. Some success, more than one ib^gib address(es), some error.
2622
+ * 5. All error.
2623
+ *
2624
+ * For the first naive implementation, we will always be optimistic,
2625
+ * assuming that errors will be resolved with enough attempts. This
2626
+ * is closely related to our initial optimistic strategy of
2627
+ * "access is authorization" + "unordered dna equivalence". These
2628
+ * strategies mean that we are simply, optimistically, and
2629
+ * naively applying incoming dna transforms to ibgib timelines.
2630
+ * So failure should only result from a failure at the communication
2631
+ * layer, assuming non-adversarial conditions.
2632
+ *
2633
+ * ## future
2634
+ *
2635
+ * The handling of this should absolutely be generalized to the
2636
+ * requirements for interspatial relationships. This is the language
2637
+ * that must be implemented to deal with this in a dynamic fashion.
2638
+ *
2639
+ * This does not equate to only "ad hoc" in the sense of untested/untried.
2640
+ * This means that we have an "on-chain", public linked requirement
2641
+ * for consensus as opposed to a hard-coded consensus as is defined
2642
+ * in this function.
2643
+ *
2644
+ * It is in this generalization that byzantine resolution can be
2645
+ * achieved through whichever mechanism is correct for the use case.
2646
+ */
2647
+ async _handleSagaUpdates() {
2648
+ const lc = `${this.lc}[${this._handleSagaUpdates.name}]`;
2649
+ try {
2650
+ // at this point in execution, each space has returned the result ibgib
2651
+ // which has a syncStatus$ observable.
2652
+ const infos = Object.values(this.sagaInfoMap);
2653
+ for (let i = 0; i < infos.length; i++) {
2654
+ const sagaInfo = infos[i];
2655
+ let sub = sagaInfo.syncStatus$
2656
+ .pipe(concatMap(async (status) => {
2657
+ if (logalot) {
2658
+ console.log(`${lc}(sagaId: ${sagaInfo.sagaId}) status received. ${status?.data?.statusCode ?? 'no status'}`);
2659
+ }
2660
+ await this._handleSyncStatusIbGib({ status, sagaInfo });
2661
+ return status;
2662
+ })).subscribe({
2663
+ next: (status) => {
2664
+ if (logalot) {
2665
+ console.log(`${lc}(sagaId: ${sagaInfo.sagaId}) subscribe next triggered. status: ${status?.data?.statusCode} (I: 41e1f61e5e1b422ead1d72a1c92c7d51)`);
2666
+ }
2667
+ },
2668
+ error: async (error) => {
2669
+ const emsg = `${lc}(sagaId: ${sagaInfo.sagaId}) syncStatus$.error: ${error}`;
2670
+ console.error(emsg);
2671
+ // await this.getFnAlert!()({title: 'couldnt this.syncIbGibs...', msg: emsg});
2672
+ this.finalizeSyncSaga({ sagaInfo, error: emsg });
2673
+ },
2674
+ complete: () => {
2675
+ if (logalot) {
2676
+ console.log(`${lc}(sagaId: ${sagaInfo.sagaId}) syncStatus$.complete.`);
2677
+ }
2678
+ }
2679
+ });
2680
+ // if (sagaInfo.syncStatusSubscriptions) { sagaInfo.syncStatusSubscriptions.push(sub); }
2681
+ if (!sagaInfo.syncStatusSubscriptions) {
2682
+ throw new Error(`sagaInfo.syncStatusSubscriptions array falsy? (E: f6d834beaa164c6ea1073d35b9fecd01)`);
2683
+ }
2684
+ sagaInfo.syncStatusSubscriptions.push(sub);
2685
+ }
2686
+ }
2687
+ catch (error) {
2688
+ console.error(`${lc} ${error.message}`);
2689
+ throw error;
2690
+ }
2691
+ }
2692
+ async _handleSyncStatusIbGib({ status, sagaInfo, }) {
2693
+ const lc = `${this.lc}[${this._handleSyncStatusIbGib.name}]`;
2694
+ try {
2695
+ if (logalot) {
2696
+ console.log(`${lc} starting...`);
2697
+ }
2698
+ // #region validate
2699
+ if (!status) {
2700
+ throw new Error(`falsy status. (E: 8da370a9f3df48a98cc08f1cccf5f2dc)`);
2701
+ }
2702
+ if (!status.data) {
2703
+ throw new Error(`falsy status.data. (E: 996d458c5cde4622ba1ed54c7e188815)`);
2704
+ }
2705
+ if (!status.data.statusCode) {
2706
+ throw new Error(`falsy status.data.statusCode (E: 7f2bec6b9dd0484eb7ef97966e6dd027)`);
2707
+ }
2708
+ // #endregion validate
2709
+ let resStoreStatusLocally = await this.put({ ibGibs: status.statusIbGibGraph, isMeta: true });
2710
+ if (!resStoreStatusLocally.success) {
2711
+ // just log for now...the saving is supposed to the the log in the first place.
2712
+ console.error(`${lc}(UNEXPECTED) couldn't save status graph locally? sagaId: ${sagaInfo.sagaId} (E: b472101897824195b96b658c441dfb55)`);
2713
+ }
2714
+ const statusCode = status.data.statusCode;
2715
+ if (logalot) {
2716
+ console.log(`${lc} status update received. statusCode: ${statusCode}. sagaId: ${sagaInfo.sagaId}. spaceId: ${sagaInfo.spaceId}`);
2717
+ }
2718
+ switch (statusCode) {
2719
+ case StatusCode.started:
2720
+ // nothing to do on start? hmm...
2721
+ break;
2722
+ case StatusCode.inserted:
2723
+ // await this.handleSyncComplete_Inserted({sagaInfo, status});
2724
+ // nothing further to do? hmm...
2725
+ break;
2726
+ case StatusCode.updated:
2727
+ // await this.handleSyncComplete_Updated({sagaInfo, status});
2728
+ // nothing further to do? hmm...
2729
+ break;
2730
+ case StatusCode.merged_dna:
2731
+ await this.handleSyncStatus_Merged({ status });
2732
+ break;
2733
+ case StatusCode.merged_state:
2734
+ await this.handleSyncStatus_Merged({ status });
2735
+ break;
2736
+ case StatusCode.already_synced:
2737
+ // await this.handleSyncComplete_AlreadySynced({sagaInfo, status});
2738
+ // nothing further to do? hmm...
2739
+ break;
2740
+ case StatusCode.completed:
2741
+ await this.handleSyncStatus_Complete({ sagaInfo });
2742
+ break;
2743
+ case StatusCode.undefined:
2744
+ // atow undefined is used in primitive status parentage
2745
+ throw new Error(`statusCode is "undefined". Maybe published a primitive? sagaId: ${sagaInfo.sagaId} (E: c98376f35b194adf9bf12ff9259a2569)`);
2746
+ default:
2747
+ // ?
2748
+ throw new Error(`(UNEXPECTED) unknown status.data.statusCode (${status.data.statusCode}). sagaId: ${sagaInfo.sagaId} (E: e4872abfc1ae4c27905793ca0f937a9b)`);
2749
+ }
2750
+ if (logalot) {
2751
+ console.log(`${lc} complete.`);
2752
+ }
2753
+ }
2754
+ catch (error) {
2755
+ const emsg = `${lc} ${error.message}`;
2756
+ console.error(emsg);
2757
+ sagaInfo.syncStatus$.error(emsg);
2758
+ }
2759
+ }
2760
+ ;
2761
+ async handleSyncStatus_Merged({ status, }) {
2762
+ const lc = `${this.lc}[${this.handleSyncStatus_Merged.name}]`;
2763
+ try {
2764
+ if (logalot) {
2765
+ console.log(`${lc} starting...`);
2766
+ }
2767
+ // #region validate
2768
+ // not necessarily the case, if we only have changes on the store side, we apply no dna and create no side effects
2769
+ if ((status.createdIbGibs ?? []).length === 0 &&
2770
+ (status.storeOnlyIbGibs ?? []).length === 0) {
2771
+ throw new Error('status.createdIbGibs and/or status.storeOnlyIbGibs required when merging. (E: d118bde47fb9434fa95d747f8e4f6b33)');
2772
+ }
2773
+ if (Object.keys(status.ibGibsMergeMap ?? {}).length === 0) {
2774
+ throw new Error('status.ibGibsMergeMap required when merging. (E: 0f06238e5535408f8980e0f9f82cf564)');
2775
+ }
2776
+ // #endregion validate
2777
+ if (logalot) {
2778
+ console.log(`${lc} validated.`);
2779
+ }
2780
+ // first, we will store the newly created ibgibs in the local space. Then
2781
+ // we want to rebase our local timeline to point to the new one. I believe
2782
+ // we can do this simply by registering the latest created ibgib which
2783
+ // will record it as the local latest ibgib in the tjp timeline. It may be
2784
+ // best to somehow tag the rebased ibgib, which would enable us to
2785
+ // optionally see this later without modifying the ibgib timeline by a
2786
+ // mut8 or rel8 function directly on the now-vestigial/abandoned timeline.
2787
+ /**
2788
+ * groups the incoming `ibGibsToRegister` by tjp and registers each latest.
2789
+ *
2790
+ * @param ibGibsToRegister will call `registerNewIbGib` on the lastest in each timeline
2791
+ */
2792
+ const registerLatestInTimelines = async (ibGibsToRegister) => {
2793
+ const timelines = getTimelinesGroupedByTjp({ ibGibs: ibGibsToRegister });
2794
+ for (let i = 0; i < Object.keys(timelines).length; i++) {
2795
+ const tjpAddr = Object.keys(timelines)[i];
2796
+ const timeline = timelines[tjpAddr];
2797
+ const latestIbGibInTimeline = timeline[timeline.length - 1];
2798
+ // registerNewIbGib is idempotent if already registered as latest
2799
+ await this.registerNewIbGib({ ibGib: latestIbGibInTimeline });
2800
+ }
2801
+ };
2802
+ // first, we will store the newly created ibgibs (if any) in the local space.
2803
+ // created ibgibs may not exist if only the sync space branch has changed.
2804
+ // meanwhile, we must collect all ibgib timelines (with tjps) to register
2805
+ if (status.createdIbGibs?.length ?? 0 > 0) {
2806
+ if (logalot) {
2807
+ console.log(`${lc} putting createdIbGibs (${status.createdIbGibs.length}): ${status.createdIbGibs.map(x => getIbGibAddr({ ibGib: x })).join('\n')}.`);
2808
+ }
2809
+ const resPutCreated = await this.put({ ibGibs: status.createdIbGibs });
2810
+ if (!resPutCreated.success) {
2811
+ throw new Error(`Couldn't save created ibGibs locally? (E: f8bc91259c5043d589cd2e7ad2220c1f)`);
2812
+ }
2813
+ if (status.storeOnlyIbGibs) {
2814
+ await registerLatestInTimelines(status.storeOnlyIbGibs);
2815
+ }
2816
+ }
2817
+ else {
2818
+ if (logalot) {
2819
+ console.log(`${lc} no createdIbGibs`);
2820
+ }
2821
+ }
2822
+ if (status.storeOnlyIbGibs?.length ?? 0 > 0) {
2823
+ if (logalot) {
2824
+ console.log(`${lc} putting storeOnlyIbGibs (${status.storeOnlyIbGibs.length}): ${status.storeOnlyIbGibs.map(x => getIbGibAddr({ ibGib: x })).join('\n')}.`);
2825
+ }
2826
+ console.warn(`${lc} putting storeOnlyIbGibs (${status.storeOnlyIbGibs.length}): ${status.storeOnlyIbGibs.map(x => getIbGibAddr({ ibGib: x })).join('\n')}.`);
2827
+ const resPutStoreOnly = await this.put({ ibGibs: status.storeOnlyIbGibs });
2828
+ if (!resPutStoreOnly.success) {
2829
+ throw new Error(`Couldn't save storeonly ibGibs locally? (E: c5ab044718ab42bba27f5852149b7ddc)`);
2830
+ }
2831
+ await registerLatestInTimelines(status.storeOnlyIbGibs);
2832
+ }
2833
+ else {
2834
+ if (logalot) {
2835
+ console.log(`${lc} no storeOnlyIbGibs`);
2836
+ }
2837
+ }
2838
+ // download any dependency ibgibs from the new latest ibgib that we don't have already.
2839
+ // register the new latest ibgib.
2840
+ // merge map goes from old latest addr -> latest ibGib that was the result of the merge.
2841
+ let newLatestIbGibs = Object.values(status.ibGibsMergeMap ?? {});
2842
+ for (let i = 0; i < newLatestIbGibs.length; i++) {
2843
+ const latestIbGib = newLatestIbGibs[i];
2844
+ if (logalot) {
2845
+ console.log(`${lc} registering latestIbGib in localUserSpace: ${getIbGibAddr({ ibGib: latestIbGib })}`);
2846
+ }
2847
+ await this.registerNewIbGib({ ibGib: latestIbGib });
2848
+ }
2849
+ if (logalot) {
2850
+ console.log(`${lc} complete.`);
2851
+ }
2852
+ }
2853
+ catch (error) {
2854
+ console.error(`${lc} ${error.message}`);
2855
+ throw error;
2856
+ }
2857
+ }
2858
+ async handleSyncStatus_Complete({ sagaInfo, }) {
2859
+ const lc = `${this.lc}[${this.handleSyncStatus_Complete.name}]`;
2860
+ try {
2861
+ // cleanup just this saga, which corresponds to a single sync space.
2862
+ this.finalizeSyncSaga({ sagaInfo });
2863
+ // if this is the last saga across all spaces, clean up the rest.
2864
+ const allSagaInfos = Object.values(this.sagaInfoMap);
2865
+ if (allSagaInfos.every(x => x.complete)) {
2866
+ this.finalizeAllSyncSagas_NoThrow({});
2867
+ }
2868
+ }
2869
+ catch (error) {
2870
+ console.error(`${lc} ${error.message}`);
2871
+ this.finalizeAllSyncSagas_NoThrow({ error });
2872
+ }
2873
+ }
2874
+ /**
2875
+ * Searches through timelines and gets every single one of them
2876
+ * in the local space. (ideally)
2877
+ *
2878
+ * ## notes
2879
+ *
2880
+ * So if you pass in an ibgib with a reference to old ibgibs that
2881
+ * have not been updated to the latest, this will get those latest.
2882
+ *
2883
+ * @returns all ibgibs related to given ibgibs
2884
+ */
2885
+ // protected async _getAllIbGibsToSyncFromGraph({
2886
+ // ibGibs,
2887
+ // dependencyGraphIbGibs,
2888
+ // space,
2889
+ // }: {
2890
+ // ibGibs: IbGib_V1[],
2891
+ // dependencyGraphIbGibs: IbGib_V1[],
2892
+ // space: IbGibSpaceAny,
2893
+ // }): Promise<IbGib_V1[]> {
2894
+ // const lc = `${this.lc}[${this._getAllIbGibsToSyncFromGraph.name}]`;
2895
+ // try {
2896
+ // if (dependencyGraphIbGibs?.length > 0) {
2897
+ // // already have the dependecy graph
2898
+ // }
2899
+ // // need to get the ibgibs with tjps,
2900
+ // // then filter these to just the latest of given dependency graph ibgibs
2901
+ // // then get the latest for each of these in the local space.
2902
+ // let latestIbGibsWithTjps = await this._getLatestIbGibsWithTjps({ ibGibs: dependencyGraphIbGibs });
2903
+ // if (latestIbGibsWithTjps.length === 0) {
2904
+ // // we have no ibgib timelines, so the incoming dependency graph is complete.
2905
+ // return dependencyGraphIbGibs;
2906
+ // }
2907
+ // // An issue arises that each time we get updates to tjp ibgibs, then there is the
2908
+ // // possibility of having additional tjps that weren't in the original graph.
2909
+ // // So we need to call multiple times until we get the same number in as out.
2910
+ // let latestIbGibsWithTjps_CHECK = await this._getLatestIbGibsWithTjps({ ibGibs: latestIbGibsWithTjps });
2911
+ // while (latestIbGibsWithTjps_CHECK.length > latestIbGibsWithTjps.length) {
2912
+ // console.warn(`${lc} another tjp found. calling getLatestIbGibsWithTjps again to check for more. (W: 9735c4194d1243269d4fe4a4ed93cf59)`);
2913
+ // latestIbGibsWithTjps = latestIbGibsWithTjps_CHECK;
2914
+ // latestIbGibsWithTjps_CHECK = await this._getLatestIbGibsWithTjps({ ibGibs: latestIbGibsWithTjps });
2915
+ // }
2916
+ // // at this point, we have all of the latest tjp ibgibs, but not their
2917
+ // // dependency graphs. We need to get all dependencies from these and
2918
+ // // combine them with our given dependency graph.
2919
+ // // we're going to translate the given dependencyGraphIbGibs that we already have to
2920
+ // // a map that `getDependencyGraph` understands so we don't waste time re-getting them.
2921
+ // let allIbGibsToMergeMap: { [addr: string]: IbGib_V1 } = {};
2922
+ // dependencyGraphIbGibs.forEach(x => { allIbGibsToMergeMap[getIbGibAddr(x)] = x; });
2923
+ // // now we can combine both these latest ibGibs with the incoming ibgibs
2924
+ // for (let i = 0; i < latestIbGibsWithTjps.length; i++) {
2925
+ // const latestIbGibWithTjp = latestIbGibsWithTjps[i];
2926
+ // // anything that we have in the incoming dependency
2927
+ // // graph already has been fully traversed, so we put this in `gotten`
2928
+ // allIbGibsToMergeMap = await this.getDependencyGraph({
2929
+ // ibGib: latestIbGibWithTjp,
2930
+ // live: true,
2931
+ // gotten: allIbGibsToMergeMap,
2932
+ // maxRetries: DEFAULT_MAX_RETRIES_GET_DEPENDENCY_GRAPH_OUTERSPACE,
2933
+ // msBetweenRetries: DEFAULT_MS_BETWEEN_RETRIES_GET_DEPENDENCY_GRAPH_OUTERSPACE,
2934
+ // space,
2935
+ // });
2936
+ // }
2937
+ // const allIbGibsToMerge = Object.values(allIbGibsToMergeMap);
2938
+ // return allIbGibsToMerge;
2939
+ // } catch (error) {
2940
+ // console.error(`${lc} ${error.message}`);
2941
+ // throw error;
2942
+ // }
2943
+ // }
2944
+ async _getLatestIbGibsWithTjps({ ibGibs, warnIfMultipleLocalTimelines, }) {
2945
+ const lc = `${this.lc}[${this._getLatestIbGibsWithTjps.name}]`;
2946
+ try {
2947
+ const result = [];
2948
+ const ibGibsWithTjp_Ungrouped = ibGibs.filter(x => x.data?.isTjp || (x.rel8ns?.tjp?.length ?? 0) > 0 || x.gib?.includes(GIB_DELIMITER));
2949
+ // group them by tjp
2950
+ const ibGibsWithTjp_GroupedByTjpGib = groupBy({ items: ibGibsWithTjp_Ungrouped, keyFn: x => getGibInfo({ gib: x.gib }).tjpGib ?? '' });
2951
+ const tjpGibs = Object.keys(ibGibsWithTjp_GroupedByTjpGib);
2952
+ for (let i = 0; i < tjpGibs.length; i++) {
2953
+ const group = ibGibsWithTjp_GroupedByTjpGib[tjpGibs[i]];
2954
+ if (warnIfMultipleLocalTimelines) {
2955
+ // quick check to warn if we have multiple n's for a tjpGib (multi-timeline)
2956
+ let nCounts = {};
2957
+ for (const ibGibFrame of group) {
2958
+ let n = ibGibFrame.data?.isTjp ? -1 : (ibGibFrame.data?.n ?? -2);
2959
+ if (n === -2) {
2960
+ throw new Error(`ibGibFrame.data.n is undefined. We're only working with those with n right now!`);
2961
+ }
2962
+ nCounts[n] = (nCounts[n] ?? 0) + 1;
2963
+ }
2964
+ if (Object.values(nCounts).some(count => count > 1)) {
2965
+ console.warn(`${lc} we have multiple local timelines.`);
2966
+ }
2967
+ }
2968
+ // sort by n (ascending) and then grab the latest one
2969
+ const latestIbGibInGroup = group.sort((a, b) => (a.data?.n ?? -1) > (b.data?.n ?? -1) ? 1 : -1)[group.length - 1];
2970
+ result.push(latestIbGibInGroup);
2971
+ }
2972
+ // we're done
2973
+ return result;
2974
+ }
2975
+ catch (error) {
2976
+ console.error(`${lc} ${error.message}`);
2977
+ throw error;
2978
+ }
2979
+ }
2980
+ async handleWatchTjpUpdates({ updates, outerSpace, localUserSpace, }) {
2981
+ const lc = `${this.lc}[${this.handleWatchTjpUpdates.name}]`;
2982
+ if (logalot) {
2983
+ console.log(`${lc} starting...`);
2984
+ }
2985
+ try {
2986
+ if (!outerSpace.data) {
2987
+ throw new Error(`outerSpace.data falsy (E: b5fde89e87bef9b8b6ce38e24be4a823)`);
2988
+ }
2989
+ /**
2990
+ * compile list of addrs we have locally for all updates, so we don't try
2991
+ * to download them from outer space unnecessarily.
2992
+ */
2993
+ const latestAddrsLocallyWithUpdate = [];
2994
+ const tjpAddrs = Object.keys(updates);
2995
+ const latestAddrs_Store = Object.values(updates);
2996
+ for (let i = 0; i < tjpAddrs.length; i++) {
2997
+ const tjpAddr = tjpAddrs[i];
2998
+ if (logalot) {
2999
+ console.log(`${lc} tjpAddr: ${tjpAddr}`);
3000
+ }
3001
+ const latestAddrLocally = await this.getLatestAddr({ tjpAddr }) ?? tjpAddr;
3002
+ if (!latestAddrs_Store.includes(latestAddrLocally) &&
3003
+ !latestAddrsLocallyWithUpdate.includes(latestAddrLocally)) {
3004
+ latestAddrsLocallyWithUpdate.push(latestAddrLocally);
3005
+ }
3006
+ }
3007
+ if (latestAddrsLocallyWithUpdate.length === 0) {
3008
+ if (logalot) {
3009
+ console.log(`${lc} latestAddrsLocallyWithUpdate.length === 0. We already had all of the updates locally perhaps. Returning early. (I: 844193c515084d0ebc348349f1ac41f4)`);
3010
+ }
3011
+ return; /* <<<< returns early */
3012
+ }
3013
+ /**
3014
+ * LOCAL dependencies for latest LOCAL addrs for all tjpAddrs in updates.
3015
+ */
3016
+ const localDependencyGraphs = await this.getDependencyGraph({
3017
+ ibGibAddrs: latestAddrsLocallyWithUpdate,
3018
+ live: true,
3019
+ maxRetries: DEFAULT_MAX_RETRIES_GET_DEPENDENCY_GRAPH_OUTERSPACE,
3020
+ msBetweenRetries: DEFAULT_MS_BETWEEN_RETRIES_GET_DEPENDENCY_GRAPH_OUTERSPACE,
3021
+ space: localUserSpace,
3022
+ });
3023
+ /** all addrs we already have locally */
3024
+ const addrsAlreadyStoredLocally = Object.keys(localDependencyGraphs);
3025
+ // get dependency graph from outer space, skipping all addrs in local already
3026
+ const newerAddrsFromOuterSpace = Object.values(updates);
3027
+ const newerIbGibDependencyGraphFromOuterSpace = await getDependencyGraph({
3028
+ ibGibAddrs: newerAddrsFromOuterSpace,
3029
+ live: false,
3030
+ skipAddrs: addrsAlreadyStoredLocally,
3031
+ space: outerSpace,
3032
+ });
3033
+ const newerIbGibsFromOuterSpace = Object.values(newerIbGibDependencyGraphFromOuterSpace);
3034
+ if (logalot) {
3035
+ console.log(`${lc} got ${newerIbGibsFromOuterSpace.length} ibGibs from outerspace`);
3036
+ }
3037
+ // save locally
3038
+ if (logalot) {
3039
+ console.log(`${lc} saving new ibgibs from outerspace in local space...`);
3040
+ }
3041
+ if (newerIbGibsFromOuterSpace.length > 0) {
3042
+ await this.put({ ibGibs: newerIbGibsFromOuterSpace });
3043
+ // register the newest tjp ibGibs locally
3044
+ if (logalot) {
3045
+ console.log(`${lc} registering "new" updated tjp ibgibs locally...`);
3046
+ }
3047
+ for (let i = 0; i < tjpAddrs.length; i++) {
3048
+ const tjpAddr = tjpAddrs[i];
3049
+ const updatedAddr = updates[tjpAddr];
3050
+ if (!addrsAlreadyStoredLocally.includes(updatedAddr)) {
3051
+ const updatedIbGib = newerIbGibDependencyGraphFromOuterSpace[updatedAddr];
3052
+ if (!updatedIbGib) {
3053
+ throw new Error(`did not get updatedIbGib (${updatedAddr}) from outerspace (${outerSpace.data.uuid}) (E: 818de70f5b444a3ba198ba6480a15b04)`);
3054
+ }
3055
+ await this.registerNewIbGib({ ibGib: updatedIbGib });
3056
+ }
3057
+ }
3058
+ }
3059
+ }
3060
+ catch (error) {
3061
+ console.error(`${lc} ${error.message}`);
3062
+ // does not rethrow
3063
+ }
3064
+ finally {
3065
+ if (logalot) {
3066
+ console.log(`${lc} complete.`);
3067
+ }
3068
+ }
3069
+ }
3070
+ // #endregion syncIbGibs related
3071
+ // #region autosync
3072
+ async enableAutosync({ tjpIbGibs, }) {
3073
+ const lc = `${this.lc}[${this.enableAutosync.name}]`;
3074
+ try {
3075
+ if (logalot) {
3076
+ console.log(`${lc} starting...`);
3077
+ }
3078
+ if ((tjpIbGibs ?? []).length === 0) {
3079
+ throw new Error(`tjps required. (E: 3e3bb6ef1a3d483795440e0efcef8e04)`);
3080
+ }
3081
+ // validate tjps
3082
+ if (tjpIbGibs.some(tjp => !tjp.data?.isTjp)) {
3083
+ const wonkyTjpAddrs = tjpIbGibs
3084
+ .filter(tjp => !tjp.data?.isTjp)
3085
+ .map(x => getIbGibAddr({ ibGib: x }));
3086
+ console.warn(`${lc} unrelating tjp whose data.isTjp is false. tjpAddrs: ${wonkyTjpAddrs.join('|')} (W: 03b3d7a94e6d4ccaace3df4657a82322)`);
3087
+ }
3088
+ // we'll use addrs to compare to cache and autosync special ibgib
3089
+ let tjpAddrs = tjpIbGibs.map(tjp => getIbGibAddr({ ibGib: tjp }));
3090
+ // if we're already autosyncing all tjps, warn and return early check
3091
+ // locally since this is very fast/cheap
3092
+ let notAlreadySyncingTjpAddrs = tjpAddrs.filter(tjpAddr => !this._alwaysAutosyncTjpAddrsCache.has(tjpAddr));
3093
+ if (notAlreadySyncingTjpAddrs.length === 0) {
3094
+ console.warn(`${lc} all tjpAddrs already auto syncing. tjpAddrs: ${tjpAddrs.join('\n')} (W: 7fbe51c8187840efa1b259417053bd22)`);
3095
+ return; /* <<<< returns early */
3096
+ }
3097
+ // ...and double check in autosyncs itself, more expensive though
3098
+ const autosyncsIbGib = await this.getSpecialIbGib({ type: "autosyncs" });
3099
+ if (!autosyncsIbGib?.rel8ns) {
3100
+ throw new Error(`autosyncsIbGib?.rel8ns falsy (E: 963313139e919c09aade8b8c412d7b23)`);
3101
+ }
3102
+ const alreadySyncing = autosyncsIbGib.rel8ns[AUTOSYNC_ALWAYS_REL8N_NAME] ?? [];
3103
+ notAlreadySyncingTjpAddrs = tjpAddrs.filter(tjpAddr => !alreadySyncing.includes(tjpAddr));
3104
+ if (notAlreadySyncingTjpAddrs.length === 0) {
3105
+ console.error(`${lc} (UNEXPECTED) all tjpAddrs already auto syncing per special ibgib. Proceeding without throwing here, but this means that the cache is out of sync with the special ibgib also. tjpAddrs: ${tjpAddrs.join('\n')} (E: 574e163118f043fa8c50cfd575e62122)`);
3106
+ return; /* <<<< returns early */
3107
+ }
3108
+ // map back from tjp addrs to the tjp ibgibs
3109
+ const notAlreadySyncingTjps = notAlreadySyncingTjpAddrs.map(tjpAddr => {
3110
+ return tjpIbGibs.filter(tjp => getIbGibAddr({ ibGib: tjp }) === tjpAddr)[0];
3111
+ });
3112
+ // execute rel8 transform and plumbing
3113
+ await this.rel8ToSpecialIbGib({
3114
+ type: 'autosyncs',
3115
+ ibGibsToRel8: notAlreadySyncingTjps,
3116
+ rel8nName: AUTOSYNC_ALWAYS_REL8N_NAME,
3117
+ });
3118
+ // add to cache and we're done
3119
+ notAlreadySyncingTjpAddrs.forEach(tjpAddr => {
3120
+ this._alwaysAutosyncTjpAddrsCache.add(tjpAddr);
3121
+ });
3122
+ }
3123
+ catch (error) {
3124
+ console.error(`${lc} ${error.message}`);
3125
+ throw error;
3126
+ }
3127
+ finally {
3128
+ if (logalot) {
3129
+ console.log(`${lc} complete.`);
3130
+ }
3131
+ }
3132
+ }
3133
+ async disableAutosync({ tjpIbGibs, }) {
3134
+ const lc = `${this.lc}[${this.disableAutosync.name}]`;
3135
+ try {
3136
+ if (logalot) {
3137
+ console.log(`${lc} starting...`);
3138
+ }
3139
+ if ((tjpIbGibs ?? []).length === 0) {
3140
+ throw new Error(`tjps required. (E: 7b7e34e20b5848b882e14ff8b6c53622)`);
3141
+ }
3142
+ if (tjpIbGibs.some(tjp => !tjp.data?.isTjp)) {
3143
+ const wonkyTjpAddrs = tjpIbGibs
3144
+ .filter(tjp => !tjp.data?.isTjp)
3145
+ .map(x => getIbGibAddr({ ibGib: x }));
3146
+ console.warn(`${lc} unrelating tjp whose data.isTjp is false. tjpAddrs: ${wonkyTjpAddrs.join('|')} (W: 7babdf67dda54a2a9905c6c45ef36522)`);
3147
+ }
3148
+ let tjpAddrs = tjpIbGibs.map(tjp => getIbGibAddr({ ibGib: tjp }));
3149
+ // if we're already autosyncing this tjp, warn and return early
3150
+ // check locally...
3151
+ // ...and double check in autosyncs itself.
3152
+ const autosyncsIbGib = await this.getSpecialIbGib({ type: "autosyncs" });
3153
+ if (!autosyncsIbGib?.rel8ns) {
3154
+ throw new Error(`(UNEXPECTED) invalid autosyncIbGibs. rel8ns falsy. (E: 5f6211c8a41896003db8bfc40230af22)`);
3155
+ }
3156
+ const alreadySyncing = autosyncsIbGib.rel8ns[AUTOSYNC_ALWAYS_REL8N_NAME] ?? [];
3157
+ const tjpAddrsToRemove = [];
3158
+ tjpAddrs.forEach(tjpAddr => {
3159
+ if (alreadySyncing.includes(tjpAddr)) {
3160
+ if (logalot) {
3161
+ console.log(`${lc} disabling autosync for ${tjpAddr} (I: 63087804e6c436143971e5039b5e5e22)`);
3162
+ }
3163
+ tjpAddrsToRemove.push(tjpAddr);
3164
+ }
3165
+ else {
3166
+ if (logalot) {
3167
+ console.log(`${lc} already NOT auto syncing ${tjpAddr} (I: 88e00fea009964cd2bab4cc580aa2922)`);
3168
+ }
3169
+ }
3170
+ });
3171
+ if (tjpAddrsToRemove.length === 0) {
3172
+ console.warn(`${lc} tried to disable autosync for tjpAddrs but none were valid. returning early. (W: f9bdda90d906471aa56804d76b6e9522)`);
3173
+ return; /* <<<< returns early */
3174
+ }
3175
+ const uniqueTjpAddrsToRemove = Array.from(new Set(tjpAddrsToRemove));
3176
+ const tjpsToRemove = uniqueTjpAddrsToRemove.map(tjpAddr => {
3177
+ return tjpIbGibs.filter(tjp => getIbGibAddr({ ibGib: tjp }) === tjpAddr)[0];
3178
+ });
3179
+ // execute rel8 transform and plumbing
3180
+ await this.rel8ToSpecialIbGib({
3181
+ type: 'autosyncs',
3182
+ ibGibsToUnRel8: tjpsToRemove,
3183
+ rel8nName: AUTOSYNC_ALWAYS_REL8N_NAME,
3184
+ });
3185
+ // remove from cache and we're done
3186
+ uniqueTjpAddrsToRemove.forEach(tjpAddr => {
3187
+ this._alwaysAutosyncTjpAddrsCache.delete(tjpAddr);
3188
+ });
3189
+ }
3190
+ catch (error) {
3191
+ console.error(`${lc} ${error.message}`);
3192
+ throw error;
3193
+ }
3194
+ finally {
3195
+ if (logalot) {
3196
+ console.log(`${lc} complete.`);
3197
+ }
3198
+ }
3199
+ }
3200
+ async loadAutoSyncs() {
3201
+ const lc = `${this.lc}[${this.loadAutoSyncs.name}]`;
3202
+ try {
3203
+ if (logalot) {
3204
+ console.log(`${lc} starting...`);
3205
+ }
3206
+ const autosyncsIbGib = await this.getSpecialIbGib({ type: "autosyncs" });
3207
+ if (!autosyncsIbGib?.rel8ns) {
3208
+ throw new Error(`autosyncsIbGib?.rel8ns falsy (E: 3fdcdf40f33c41ed9b7a01a079a8fd71)`);
3209
+ }
3210
+ if (autosyncsIbGib.rel8ns) {
3211
+ this._alwaysAutosyncTjpAddrsCache =
3212
+ new Set(autosyncsIbGib.rel8ns[AUTOSYNC_ALWAYS_REL8N_NAME]);
3213
+ }
3214
+ }
3215
+ catch (error) {
3216
+ console.error(`${lc} ${error.message}`);
3217
+ throw error;
3218
+ }
3219
+ finally {
3220
+ if (logalot) {
3221
+ console.log(`${lc} complete.`);
3222
+ }
3223
+ }
3224
+ }
3225
+ /**
3226
+ * checks to see if autosync is enabled for a given `tjp`.
3227
+ *
3228
+ * NOTE: this only checks cache atm.
3229
+ *
3230
+ * @returns true if autosync is enabled for the given tjp, else false
3231
+ */
3232
+ autosyncIsEnabled({ tjp, }) {
3233
+ const lc = `${this.lc}[${this.autosyncIsEnabled.name}]`;
3234
+ try {
3235
+ if (logalot) {
3236
+ console.log(`${lc} starting...`);
3237
+ }
3238
+ return this._alwaysAutosyncTjpAddrsCache.has(getIbGibAddr({ ibGib: tjp }));
3239
+ }
3240
+ catch (error) {
3241
+ console.error(`${lc} ${error.message}`);
3242
+ throw error;
3243
+ }
3244
+ finally {
3245
+ if (logalot) {
3246
+ console.log(`${lc} complete.`);
3247
+ }
3248
+ }
3249
+ }
3250
+ }
3251
+ //# sourceMappingURL=metaspace-base.mjs.map