@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.
- package/README.md +5 -10
- package/dist/assumptions.respec.d.mts +2 -0
- package/dist/assumptions.respec.d.mts.map +1 -0
- package/dist/assumptions.respec.mjs +41 -0
- package/dist/assumptions.respec.mjs.map +1 -0
- package/dist/core-constants.d.mts +0 -2
- package/dist/core-constants.d.mts.map +1 -1
- package/dist/core-constants.mjs +0 -2
- package/dist/core-constants.mjs.map +1 -1
- package/dist/core-helper.respec.d.mts +2 -0
- package/dist/core-helper.respec.d.mts.map +1 -0
- package/dist/core-helper.respec.mjs +53 -0
- package/dist/core-helper.respec.mjs.map +1 -0
- package/dist/core-types.d.mts +22 -0
- package/dist/core-types.d.mts.map +1 -1
- package/dist/respec-gib.node.d.mts +2 -0
- package/dist/respec-gib.node.d.mts.map +1 -0
- package/dist/respec-gib.node.mjs +211 -0
- package/dist/respec-gib.node.mjs.map +1 -0
- package/dist/spec-helper.node.respec.d.mts +12 -0
- package/dist/spec-helper.node.respec.d.mts.map +1 -0
- package/dist/spec-helper.node.respec.mjs +43 -0
- package/dist/spec-helper.node.respec.mjs.map +1 -0
- package/dist/witness/app/app-base-v1.d.mts +2 -2
- package/dist/witness/app/app-base-v1.d.mts.map +1 -1
- package/dist/witness/app/app-base-v1.mjs +23 -141
- package/dist/witness/app/app-base-v1.mjs.map +1 -1
- package/dist/witness/app/app-constants.d.mts +2 -0
- package/dist/witness/app/app-constants.d.mts.map +1 -1
- package/dist/witness/app/app-constants.mjs +2 -0
- package/dist/witness/app/app-constants.mjs.map +1 -1
- package/dist/witness/app/app-helper.d.mts.map +1 -1
- package/dist/witness/app/app-helper.mjs +2 -1
- package/dist/witness/app/app-helper.mjs.map +1 -1
- package/dist/witness/app/app-types.d.mts +2 -1
- package/dist/witness/app/app-types.d.mts.map +1 -1
- package/dist/witness/robbot/robbot-base-v1.d.mts +12 -164
- package/dist/witness/robbot/robbot-base-v1.d.mts.map +1 -1
- package/dist/witness/robbot/robbot-base-v1.mjs +41 -657
- package/dist/witness/robbot/robbot-base-v1.mjs.map +1 -1
- package/dist/witness/robbot/robbot-helper.mjs +3 -3
- package/dist/witness/robbot/robbot-helper.mjs.map +1 -1
- package/dist/witness/robbot/robbot-helper.respec.d.mts +2 -0
- package/dist/witness/robbot/robbot-helper.respec.d.mts.map +1 -0
- package/dist/witness/robbot/robbot-helper.respec.mjs +106 -0
- package/dist/witness/robbot/robbot-helper.respec.mjs.map +1 -0
- package/dist/witness/robbot/robbot-types.d.mts +6 -3
- package/dist/witness/robbot/robbot-types.d.mts.map +1 -1
- package/dist/witness/robbot/robbot-types.mjs +1 -0
- package/dist/witness/robbot/robbot-types.mjs.map +1 -1
- package/dist/witness/space/filesystem-space/filesystem-space-v1.d.mts +1 -1
- package/dist/witness/space/filesystem-space/filesystem-space-v1.d.mts.map +1 -1
- package/dist/witness/space/filesystem-space/filesystem-space-v1.respec.d.mts +2 -0
- package/dist/witness/space/filesystem-space/filesystem-space-v1.respec.d.mts.map +1 -0
- package/dist/witness/space/filesystem-space/filesystem-space-v1.respec.mjs +107 -0
- package/dist/witness/space/filesystem-space/filesystem-space-v1.respec.mjs.map +1 -0
- package/dist/witness/space/filesystem-space/node-filesystem-space-v1.d.mts.map +1 -1
- package/dist/witness/space/filesystem-space/node-filesystem-space-v1.mjs +1 -1
- package/dist/witness/space/filesystem-space/node-filesystem-space-v1.mjs.map +1 -1
- package/dist/witness/space/filesystem-space/node-filesystem-space-v1.node.respec.d.mts +2 -0
- package/dist/witness/space/filesystem-space/node-filesystem-space-v1.node.respec.d.mts.map +1 -0
- package/dist/witness/space/filesystem-space/node-filesystem-space-v1.node.respec.mjs +129 -0
- package/dist/witness/space/filesystem-space/node-filesystem-space-v1.node.respec.mjs.map +1 -0
- package/dist/witness/space/inner-space/inner-space-v1.respec.d.mts +2 -0
- package/dist/witness/space/inner-space/inner-space-v1.respec.d.mts.map +1 -0
- package/dist/witness/space/inner-space/inner-space-v1.respec.mjs +56 -0
- package/dist/witness/space/inner-space/inner-space-v1.respec.mjs.map +1 -0
- package/dist/witness/space/metaspace/metaspace-base.d.mts +795 -0
- package/dist/witness/space/metaspace/metaspace-base.d.mts.map +1 -0
- package/dist/witness/space/metaspace/metaspace-base.mjs +3251 -0
- package/dist/witness/space/metaspace/metaspace-base.mjs.map +1 -0
- package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.d.mts +4 -0
- package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.d.mts.map +1 -0
- package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mjs +117 -0
- package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mjs.map +1 -0
- package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.d.mts +34 -0
- package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.d.mts.map +1 -0
- package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs +76 -0
- package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs.map +1 -0
- package/dist/witness/space/metaspace/metaspace-types.d.mts +580 -0
- package/dist/witness/space/metaspace/metaspace-types.d.mts.map +1 -0
- package/dist/witness/space/metaspace/metaspace-types.mjs +6 -0
- package/dist/witness/space/metaspace/metaspace-types.mjs.map +1 -0
- package/dist/witness/space/space-helper.d.mts.map +1 -1
- package/dist/witness/space/space-helper.mjs +2 -1
- package/dist/witness/space/space-helper.mjs.map +1 -1
- package/dist/witness/space/{space-spec-helper.d.mts → space-respec-helper.d.mts} +15 -5
- package/dist/witness/space/space-respec-helper.d.mts.map +1 -0
- package/dist/witness/space/space-respec-helper.mjs +186 -0
- package/dist/witness/space/space-respec-helper.mjs.map +1 -0
- package/dist/witness/space/space-types.d.mts +2 -1
- package/dist/witness/space/space-types.d.mts.map +1 -1
- package/dist/witness/space/space-types.mjs.map +1 -1
- package/dist/witness/witness-base-v1.d.mts.map +1 -1
- package/dist/witness/witness-base-v1.mjs +7 -7
- package/dist/witness/witness-base-v1.mjs.map +1 -1
- package/dist/witness/witness-cmd/witness-cmd-types.d.mts +31 -0
- package/dist/witness/witness-cmd/witness-cmd-types.d.mts.map +1 -0
- package/dist/witness/witness-cmd/witness-cmd-types.mjs +2 -0
- package/dist/witness/witness-cmd/witness-cmd-types.mjs.map +1 -0
- package/dist/witness/witness-helper.d.mts +8 -0
- package/dist/witness/witness-helper.d.mts.map +1 -1
- package/dist/witness/witness-helper.mjs +30 -0
- package/dist/witness/witness-helper.mjs.map +1 -1
- package/dist/witness/witness-types.d.mts +26 -36
- package/dist/witness/witness-types.d.mts.map +1 -1
- package/dist/witness/witness-with-context/witness-with-context-base-v1.d.mts +235 -0
- package/dist/witness/witness-with-context/witness-with-context-base-v1.d.mts.map +1 -0
- package/dist/witness/witness-with-context/witness-with-context-base-v1.mjs +742 -0
- package/dist/witness/witness-with-context/witness-with-context-base-v1.mjs.map +1 -0
- package/dist/witness/witness-with-context/witness-with-context-types.d.mts +17 -0
- package/dist/witness/witness-with-context/witness-with-context-types.d.mts.map +1 -0
- package/dist/witness/witness-with-context/witness-with-context-types.mjs +2 -0
- package/dist/witness/witness-with-context/witness-with-context-types.mjs.map +1 -0
- package/package.json +12 -15
- package/src/{assumptions.spec.mts → assumptions.respec.mts} +11 -5
- package/src/core-constants.mts +0 -2
- package/src/core-helper.respec.mts +71 -0
- package/src/core-types.mts +20 -0
- package/src/respec-gib.node.mts +199 -0
- package/src/witness/app/app-base-v1.mts +19 -212
- package/src/witness/app/app-constants.mts +3 -0
- package/src/witness/app/app-helper.mts +2 -1
- package/src/witness/app/app-types.mts +1 -1
- package/src/witness/robbot/robbot-base-v1.mts +39 -690
- package/src/witness/robbot/robbot-helper.mts +1 -1
- package/src/witness/robbot/{robbot-helper.spec.mts → robbot-helper.respec.mts} +39 -33
- package/src/witness/robbot/robbot-types.mts +5 -3
- package/src/witness/space/filesystem-space/filesystem-space-v1.mts +1 -1
- package/src/witness/space/filesystem-space/{filesystem-space-v1.spec.mts → filesystem-space-v1.respec.mts} +17 -8
- package/src/witness/space/filesystem-space/node-filesystem-space-v1.mts +3 -11
- package/src/witness/space/filesystem-space/{node-filesystem-space-v1.node.spec.mts → node-filesystem-space-v1.node.respec.mts} +18 -14
- package/src/witness/space/inner-space/{inner-space-v1.spec.mts → inner-space-v1.respec.mts} +17 -8
- package/src/witness/space/metaspace/metaspace-base.mts +3702 -0
- package/src/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mts +116 -0
- package/src/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mts +88 -0
- package/src/witness/space/metaspace/metaspace-types.mts +614 -0
- package/src/witness/space/space-helper.mts +2 -1
- package/src/witness/space/{space-spec-helper.mts → space-respec-helper.mts} +76 -57
- package/src/witness/space/space-types.mts +2 -1
- package/src/witness/witness-base-v1.mts +8 -6
- package/src/witness/witness-cmd/witness-cmd-types.mts +38 -0
- package/src/witness/witness-helper.mts +31 -0
- package/src/witness/witness-types.mts +31 -41
- package/src/witness/witness-with-context/witness-with-context-base-v1.mts +809 -0
- package/src/witness/witness-with-context/witness-with-context-types.mts +24 -0
- package/tsconfig.json +1 -0
- package/dist/witness/space/space-spec-helper.d.mts.map +0 -1
- package/dist/witness/space/space-spec-helper.mjs +0 -179
- package/dist/witness/space/space-spec-helper.mjs.map +0 -1
- package/jasmine-browser.json +0 -18
- package/jasmine.json +0 -6
- package/src/core-helper.spec.mts +0 -64
- /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
|