@ibgib/web-gib 0.0.28 → 0.0.30
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/dist/AUTO-GENERATED-version.d.mts +1 -1
- package/dist/AUTO-GENERATED-version.mjs +1 -1
- package/dist/app-bootstrap/bootstrap.d.mts +90 -0
- package/dist/app-bootstrap/bootstrap.d.mts.map +1 -0
- package/dist/app-bootstrap/bootstrap.mjs +404 -0
- package/dist/app-bootstrap/bootstrap.mjs.map +1 -0
- package/dist/app-bootstrap/init-orchestration.d.mts +75 -0
- package/dist/app-bootstrap/init-orchestration.d.mts.map +1 -0
- package/dist/app-bootstrap/init-orchestration.mjs +211 -0
- package/dist/app-bootstrap/init-orchestration.mjs.map +1 -0
- package/dist/app-bootstrap/types.d.mts +163 -0
- package/dist/app-bootstrap/types.d.mts.map +1 -0
- package/dist/app-bootstrap/types.mjs +15 -0
- package/dist/app-bootstrap/types.mjs.map +1 -0
- package/dist/constants.d.mts +10 -0
- package/dist/constants.d.mts.map +1 -1
- package/dist/constants.mjs +10 -0
- package/dist/constants.mjs.map +1 -1
- package/dist/helpers.d.mts +0 -7
- package/dist/helpers.d.mts.map +1 -1
- package/dist/helpers.mjs +0 -25
- package/dist/helpers.mjs.map +1 -1
- package/dist/index.d.mts +16 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +15 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/AUTO-GENERATED-version.mts +1 -1
- package/src/app-bootstrap/bootstrap.mts +570 -0
- package/src/app-bootstrap/init-orchestration.mts +244 -0
- package/src/app-bootstrap/types.mts +190 -0
- package/src/constants.mts +10 -0
- package/src/helpers.mts +1 -23
- package/src/index.mts +28 -2
- package/tools/auto-generated-agent-skills/skills/ibgib-create-app-core/SKILL.md +7 -7
- package/tools/auto-generated-agent-skills/skills/ibgib-create-app-core/templates/types.mts.template +0 -3
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @ibgib/web-gib
|
|
3
|
+
*
|
|
4
|
+
* Front Door: Streamlined App Bootstrapping
|
|
5
|
+
*/
|
|
6
|
+
export { bootstrapIbGibApp } from "./app-bootstrap/bootstrap.mjs";
|
|
7
|
+
export { initIbGibStorage, dynamicallyLoadBootstrapScript, getComponentCtorArg } from "./app-bootstrap/init-orchestration.mjs";
|
|
8
|
+
/**
|
|
9
|
+
* Toolbox: Library Internals
|
|
10
|
+
* (Only export what's necessary for advanced users)
|
|
11
|
+
*/
|
|
12
|
+
export * from "./constants.mjs";
|
|
13
|
+
export * from "./types.mjs";
|
|
14
|
+
export * from "./helpers.web.mjs";
|
|
15
|
+
export * from "./helpers.mjs";
|
|
3
16
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.mts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.mts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACH,iBAAiB,EACpB,MAAM,+BAA+B,CAAC;AAOvC,OAAO,EACH,gBAAgB,EAChB,8BAA8B,EAC9B,mBAAmB,EACtB,MAAM,wCAAwC,CAAC;AAEhD;;;GAGG;AACH,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ibgib/web-gib",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.30",
|
|
4
4
|
"description": "Framework for creating agentic ibGib web apps. Contains plumbing for ibgib components, agentic framework (currently only Gemini implemented), web-based IndexedDB storage substrate, and more.",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module bootstrap
|
|
3
|
+
*
|
|
4
|
+
* Shared bootstrap entry point for ibgib-based web apps.
|
|
5
|
+
* Collapses the metaspace, globalThis, and shell-init boilerplate.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
clone, extractErrorMsg, getTimestamp, getUUID, pickRandom_Letters,
|
|
10
|
+
} from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
11
|
+
import { RCLIArgInfo, RCLIParamInfo } from "@ibgib/helper-gib/dist/rcli/rcli-types.mjs";
|
|
12
|
+
import { buildArgInfos } from "@ibgib/helper-gib/dist/rcli/rcli-helper.mjs";
|
|
13
|
+
import { IbGibAddr, TransformResult } from "@ibgib/ts-gib/dist/types.mjs";
|
|
14
|
+
import { getIbAndGib, getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
|
|
15
|
+
import { Factory_V1 as factory } from "@ibgib/ts-gib/dist/V1/factory.mjs";
|
|
16
|
+
import { Rel8n } from "@ibgib/ts-gib/dist/V1/types.mjs";
|
|
17
|
+
import { IbGibAppAny, AppBase_V1 } from "@ibgib/core-gib/dist/witness/app/app-base-v1.mjs";
|
|
18
|
+
import { getFromSpace } from "@ibgib/core-gib/dist/witness/space/space-helper.mjs";
|
|
19
|
+
import { createNewApp, getAppIb, getInfoFromAppIb } from "@ibgib/core-gib/dist/witness/app/app-helper.mjs";
|
|
20
|
+
import { MetaspaceService } from "@ibgib/core-gib/dist/witness/space/metaspace/metaspace-types.mjs";
|
|
21
|
+
import { IbGibSpaceAny } from "@ibgib/core-gib/dist/witness/space/space-base-v1.mjs";
|
|
22
|
+
import { APP_REL8N_NAME } from '@ibgib/core-gib/dist/witness/app/app-constants.mjs';
|
|
23
|
+
import { TAG_REL8N_NAME } from "@ibgib/core-gib/dist/common/tag/tag-constants.mjs";
|
|
24
|
+
import { TagIbGib_V1 } from "@ibgib/core-gib/dist/common/tag/tag-types.mjs";
|
|
25
|
+
import { SPACE_NAME_REGEXP } from "@ibgib/core-gib/dist/witness/space/space-constants.mjs";
|
|
26
|
+
import { SpecialIbGibType } from "@ibgib/core-gib/dist/common/other/other-types.mjs";
|
|
27
|
+
|
|
28
|
+
import { alertUser, promptForSecret, promptForText } from "../helpers.web.mjs";
|
|
29
|
+
import { Metaspace_Webspace } from "../witness/space/metaspace/metaspace-webspace/metaspace-webspace.mjs";
|
|
30
|
+
import { LiveProxyIbGib } from "../witness/live-proxy-ibgib/live-proxy-ibgib-one-file.mjs";
|
|
31
|
+
import { storageGet } from "../storage/storage-helpers.web.mjs";
|
|
32
|
+
import { getIbGibGlobalThis_IbGib } from "../helpers.mjs";
|
|
33
|
+
|
|
34
|
+
import {
|
|
35
|
+
IbGibAmbientContextConfig,
|
|
36
|
+
IbGibGlobalThis_IbGibApp,
|
|
37
|
+
IbGibIdentityContext,
|
|
38
|
+
RequestCommentData_V1,
|
|
39
|
+
RequestCommentIbGib_V1,
|
|
40
|
+
} from "./types.mjs";
|
|
41
|
+
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Options
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
export interface TagConfig {
|
|
47
|
+
text: string;
|
|
48
|
+
icon: string;
|
|
49
|
+
description: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface BootstrapIbGibAppOptions<TApp extends AppBase_V1<any, any, any, any, any, any, any, any>> {
|
|
53
|
+
/** Application context configuration (IndexedDB names, etc.) */
|
|
54
|
+
config: IbGibAmbientContextConfig;
|
|
55
|
+
|
|
56
|
+
/** Accessor for the application's typed globalThis slot */
|
|
57
|
+
getGlobalThis: (config?: IbGibAmbientContextConfig) => IbGibGlobalThis_IbGibApp;
|
|
58
|
+
|
|
59
|
+
/** The main application witness class */
|
|
60
|
+
AppClass: new (data?: any, rel8ns?: any) => TApp;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Default data used when generating the very first version of this app.
|
|
64
|
+
* Only applied if `fnGetOrCreateApp` is omitted.
|
|
65
|
+
*/
|
|
66
|
+
defaultAppData: any;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Optional. Provide an array of parameters the application supports.
|
|
70
|
+
*/
|
|
71
|
+
paramInfos?: RCLIParamInfo[];
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Optional. Provide initial args for bootstrap.
|
|
75
|
+
* Defaults to `['--interactive']`.
|
|
76
|
+
*/
|
|
77
|
+
getOpeningArgs?: () => Promise<string[]>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Optional. RCLI argument validation hook.
|
|
81
|
+
*/
|
|
82
|
+
validateArgInfos?: (opts: { argInfos: RCLIArgInfo[] }) => string | undefined;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Optional. Hook called before initializing the app, but after metaspace is ready.
|
|
86
|
+
* Can be used to check environment, space state, etc.
|
|
87
|
+
*/
|
|
88
|
+
onBeforeCreate?: (metaspace: MetaspaceService, space: IbGibSpaceAny) => Promise<void>;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Optional. Hook called immediately after the application witness is loaded or created.
|
|
92
|
+
* A good place to execute migrations before returning the 'ready' app.
|
|
93
|
+
*/
|
|
94
|
+
onAppLoaded?: (app: TApp, isNew: boolean) => Promise<TApp>;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Nuclear escape hatch. Provide this to replace the entire app get-or-create flow.
|
|
98
|
+
* If provided, `onBeforeCreate`, `onAppLoaded`, and `defaultAppData` are ignored.
|
|
99
|
+
*/
|
|
100
|
+
fnGetOrCreateApp?: (metaspace: MetaspaceService, space: IbGibSpaceAny) => Promise<TApp>;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Optional. Hook called to initialize identity context (e.g., keystone based auth).
|
|
104
|
+
*/
|
|
105
|
+
resolveIdentity?: (metaspace: MetaspaceService) => Promise<IbGibIdentityContext | undefined>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Optional. The point at which the application logic dictates its readiness to UI components.
|
|
109
|
+
* Typically this executes `getAppShellSvc().onEngineReady()`.
|
|
110
|
+
*/
|
|
111
|
+
onReady?: (app: TApp) => void | Promise<void>;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Tags verified to exist in the global user space at startup.
|
|
115
|
+
*/
|
|
116
|
+
ensureTags?: TagConfig[];
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The key prefix used for allocating new spaces (e.g. `test_app_space`).
|
|
120
|
+
*/
|
|
121
|
+
localSpaceNamePrefix?: string;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Optional hook to register AI agent function tracking and deprecations.
|
|
125
|
+
*/
|
|
126
|
+
registerAgentFunctionInfos?: () => void;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Main Flow
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
export async function bootstrapIbGibApp<TApp extends AppBase_V1<any, any, any, any, any, any, any, any>>(
|
|
134
|
+
opts: BootstrapIbGibAppOptions<TApp>
|
|
135
|
+
): Promise<void> {
|
|
136
|
+
const lc = `[${bootstrapIbGibApp.name}]`;
|
|
137
|
+
const logalot = true; // Use a general log flag or derive from config
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
if (logalot) { console.log(`${lc} starting...`); }
|
|
141
|
+
|
|
142
|
+
const ibGibGlobalThis = opts.getGlobalThis(opts.config);
|
|
143
|
+
|
|
144
|
+
if (ibGibGlobalThis.bootstrapStarted) {
|
|
145
|
+
if (ibGibGlobalThis.bootstrapPromise) {
|
|
146
|
+
console.warn(`${lc} already bootstrapping — awaiting that promise.`);
|
|
147
|
+
} else {
|
|
148
|
+
throw new Error(`(UNEXPECTED) bootstrapStarted but bootstrapPromise is falsy?`);
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
ibGibGlobalThis.bootstrapStarted = true;
|
|
152
|
+
ibGibGlobalThis.bootstrapPromise = new Promise<void>(async (resolve, reject) => {
|
|
153
|
+
try {
|
|
154
|
+
const args = opts.getOpeningArgs
|
|
155
|
+
? await opts.getOpeningArgs()
|
|
156
|
+
: ['--interactive'];
|
|
157
|
+
|
|
158
|
+
const paramInfos = opts.paramInfos ?? [{ name: 'interactive', isFlag: true, argTypeName: 'boolean' }];
|
|
159
|
+
|
|
160
|
+
const paramInfosErrors = validateParamInfos({ paramInfos });
|
|
161
|
+
if (paramInfosErrors.length > 0) {
|
|
162
|
+
throw new Error(`(UNEXPECTED) invalid PARAM_INFOS: ${paramInfosErrors.join('|')}`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const argInfos = buildArgInfos({ args, paramInfos, logalot });
|
|
166
|
+
|
|
167
|
+
if (opts.validateArgInfos) {
|
|
168
|
+
const validationErrors = opts.validateArgInfos({ argInfos });
|
|
169
|
+
if (validationErrors) {
|
|
170
|
+
throw new Error(`Arg validation errors: ${validationErrors}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
await execFromArgs({ opts, args, argInfos, logalot });
|
|
175
|
+
resolve();
|
|
176
|
+
} catch (error) {
|
|
177
|
+
reject(error);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
await ibGibGlobalThis.bootstrapPromise;
|
|
183
|
+
|
|
184
|
+
// Execute onReady securely outside the promise resolution to prevent deadlock
|
|
185
|
+
// when getComponentInstance is used by shell service.
|
|
186
|
+
if (opts.onReady) {
|
|
187
|
+
|
|
188
|
+
// Re-fetch the loaded app wrapper dynamically
|
|
189
|
+
const getApp = () => ((ibGibGlobalThis as any).appInstance as TApp) || null;
|
|
190
|
+
await opts.onReady(getApp());
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
} catch (error) {
|
|
194
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
195
|
+
throw error;
|
|
196
|
+
} finally {
|
|
197
|
+
if (logalot) { console.log(`\n${lc} complete.`); }
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function execFromArgs<TApp extends AppBase_V1<any, any, any, any, any, any, any, any>>({
|
|
202
|
+
opts, args, argInfos, logalot,
|
|
203
|
+
}: {
|
|
204
|
+
opts: BootstrapIbGibAppOptions<TApp>,
|
|
205
|
+
args: string[],
|
|
206
|
+
argInfos: RCLIArgInfo[],
|
|
207
|
+
logalot: boolean
|
|
208
|
+
}): Promise<void> {
|
|
209
|
+
const lc = `[${execFromArgs.name}]`;
|
|
210
|
+
try {
|
|
211
|
+
if (logalot) { console.log(`${lc} starting...`); }
|
|
212
|
+
|
|
213
|
+
const metaspace = await initMetaspace({ opts, logalot });
|
|
214
|
+
|
|
215
|
+
const ibgibGlobalThis_core = getIbGibGlobalThis_IbGib();
|
|
216
|
+
ibgibGlobalThis_core.metaspace = metaspace;
|
|
217
|
+
|
|
218
|
+
const ibgibGlobalThis = opts.getGlobalThis(opts.config);
|
|
219
|
+
ibgibGlobalThis.metaspace = metaspace;
|
|
220
|
+
|
|
221
|
+
if (opts.ensureTags) {
|
|
222
|
+
await ensureTagsExist({ metaspace, tags: opts.ensureTags, logalot });
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (opts.registerAgentFunctionInfos) {
|
|
226
|
+
opts.registerAgentFunctionInfos();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const resRequestCommentIbGib = await createRequestCommentIbGib_Common({
|
|
230
|
+
args, interpretedArgInfos: argInfos,
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
await metaspace.persistTransformResult({ resTransform: resRequestCommentIbGib });
|
|
234
|
+
ibgibGlobalThis.initialCommentIbGib = resRequestCommentIbGib.newIbGib;
|
|
235
|
+
|
|
236
|
+
const proxy = new LiveProxyIbGib();
|
|
237
|
+
await proxy.initialized;
|
|
238
|
+
proxy.setWrappedIbGib({ ibGib: resRequestCommentIbGib.newIbGib });
|
|
239
|
+
ibgibGlobalThis.initialCommentIbGibProxy = proxy;
|
|
240
|
+
|
|
241
|
+
if (opts.resolveIdentity) {
|
|
242
|
+
ibgibGlobalThis.identity = await opts.resolveIdentity(metaspace);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
await execInteractive({ opts, resRequestCommentIbGib, metaspace, logalot });
|
|
246
|
+
|
|
247
|
+
} catch (error) {
|
|
248
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
249
|
+
throw error;
|
|
250
|
+
} finally {
|
|
251
|
+
if (logalot) { console.log(`\n${lc} complete.`); }
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async function initMetaspace<TApp extends AppBase_V1<any, any, any, any, any, any, any, any>>({
|
|
256
|
+
opts, logalot
|
|
257
|
+
}: {
|
|
258
|
+
opts: BootstrapIbGibAppOptions<TApp>,
|
|
259
|
+
logalot: boolean
|
|
260
|
+
}): Promise<MetaspaceService> {
|
|
261
|
+
const lc = `[${initMetaspace.name}]`;
|
|
262
|
+
try {
|
|
263
|
+
if (logalot) { console.log(`${lc} starting...`); }
|
|
264
|
+
|
|
265
|
+
let metaspace = new Metaspace_Webspace(/*cacheSvc*/undefined);
|
|
266
|
+
|
|
267
|
+
const localSpaceNameKey = opts.localSpaceNamePrefix
|
|
268
|
+
? `${opts.localSpaceNamePrefix}_local_space_name`
|
|
269
|
+
: `local_space_name`;
|
|
270
|
+
|
|
271
|
+
const existingLocalSpaceName = await storageGet({
|
|
272
|
+
dbName: opts.config.dbName,
|
|
273
|
+
storeName: opts.config.storeName,
|
|
274
|
+
key: localSpaceNameKey,
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
const prefix = opts.localSpaceNamePrefix ?? 'app_space';
|
|
278
|
+
const spaceName = existingLocalSpaceName
|
|
279
|
+
? undefined
|
|
280
|
+
: await generateLocalSpaceName(prefix);
|
|
281
|
+
|
|
282
|
+
await metaspace.initialize({
|
|
283
|
+
spaceName,
|
|
284
|
+
metaspaceFactory: undefined,
|
|
285
|
+
getFnAlert: () => ({ title, msg }) => alertUser({ title, msg }),
|
|
286
|
+
getFnPrompt: () => ({ title, msg }) => promptForText({ title, msg, confirm: false }),
|
|
287
|
+
getFnPromptPassword: () => () => promptForSecret({ confirm: true }),
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return metaspace;
|
|
291
|
+
} catch (error) {
|
|
292
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
293
|
+
throw error;
|
|
294
|
+
} finally {
|
|
295
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async function generateLocalSpaceName(prefix: string): Promise<string> {
|
|
300
|
+
const name = prefix + '_' + pickRandom_Letters({ count: 12 });
|
|
301
|
+
if (!SPACE_NAME_REGEXP.test(name)) {
|
|
302
|
+
throw new Error(`(UNEXPECTED) generated space name (${name}) failed regexp`);
|
|
303
|
+
}
|
|
304
|
+
return name;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async function execInteractive<TApp extends AppBase_V1<any, any, any, any, any, any, any, any>>({
|
|
308
|
+
opts, resRequestCommentIbGib, metaspace, logalot
|
|
309
|
+
}: {
|
|
310
|
+
opts: BootstrapIbGibAppOptions<TApp>,
|
|
311
|
+
resRequestCommentIbGib: TransformResult<RequestCommentIbGib_V1>,
|
|
312
|
+
metaspace: MetaspaceService,
|
|
313
|
+
logalot: boolean
|
|
314
|
+
}): Promise<void> {
|
|
315
|
+
const lc = `[${execInteractive.name}]`;
|
|
316
|
+
try {
|
|
317
|
+
if (logalot) { console.log(`${lc} starting...`); }
|
|
318
|
+
|
|
319
|
+
const localUserSpace = await metaspace.getLocalUserSpace({ lock: false });
|
|
320
|
+
if (!localUserSpace) {
|
|
321
|
+
throw new Error(`(UNEXPECTED) localUserSpace falsy?`);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const app = opts.fnGetOrCreateApp
|
|
325
|
+
? await opts.fnGetOrCreateApp(metaspace, localUserSpace)
|
|
326
|
+
: await defaultGetOrCreateApp({
|
|
327
|
+
AppClass: opts.AppClass,
|
|
328
|
+
defaultAppData: opts.defaultAppData,
|
|
329
|
+
onBeforeCreate: opts.onBeforeCreate,
|
|
330
|
+
onAppLoaded: opts.onAppLoaded,
|
|
331
|
+
metaspace,
|
|
332
|
+
space: localUserSpace,
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// Track the app so `onReady` can access it cleanly
|
|
336
|
+
const ibgibGlobalThis = opts.getGlobalThis(opts.config);
|
|
337
|
+
(ibgibGlobalThis as any).appInstance = app;
|
|
338
|
+
|
|
339
|
+
app.metaspace = metaspace;
|
|
340
|
+
await app.witness(resRequestCommentIbGib.newIbGib);
|
|
341
|
+
} catch (error) {
|
|
342
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
343
|
+
throw error;
|
|
344
|
+
} finally {
|
|
345
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
async function defaultGetOrCreateApp<TApp extends AppBase_V1<any, any, any, any, any, any, any, any>>({
|
|
350
|
+
AppClass,
|
|
351
|
+
defaultAppData,
|
|
352
|
+
onBeforeCreate,
|
|
353
|
+
onAppLoaded,
|
|
354
|
+
metaspace,
|
|
355
|
+
space,
|
|
356
|
+
}: {
|
|
357
|
+
AppClass: new (data?: any, rel8ns?: any) => TApp,
|
|
358
|
+
defaultAppData: any,
|
|
359
|
+
onBeforeCreate?: (metaspace: MetaspaceService, space: IbGibSpaceAny) => Promise<void>,
|
|
360
|
+
onAppLoaded?: (app: TApp, isNew: boolean) => Promise<TApp>,
|
|
361
|
+
metaspace: MetaspaceService,
|
|
362
|
+
space: IbGibSpaceAny,
|
|
363
|
+
}): Promise<TApp> {
|
|
364
|
+
const lc = `[${defaultGetOrCreateApp.name}]`;
|
|
365
|
+
const logalot = true;
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
if (logalot) { console.log(`${lc} starting...`); }
|
|
369
|
+
|
|
370
|
+
let appsIbGib = await metaspace.getSpecialIbGib({
|
|
371
|
+
type: SpecialIbGibType.apps,
|
|
372
|
+
initialize: false, lock: false, space,
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
if (!appsIbGib) { throw new Error(`(UNEXPECTED) no apps index ibgib`); }
|
|
376
|
+
if (!appsIbGib.rel8ns) { throw new Error(`(UNEXPECTED) appsIbGib.rel8ns falsy`); }
|
|
377
|
+
|
|
378
|
+
const appAddrs = (appsIbGib.rel8ns[APP_REL8N_NAME] ?? [] as IbGibAddr[])
|
|
379
|
+
.filter(addr => {
|
|
380
|
+
const { ib } = getIbAndGib({ ibGibAddr: addr });
|
|
381
|
+
return getInfoFromAppIb({ appIb: ib }).appClassname === AppClass.name;
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
let app: TApp;
|
|
385
|
+
let appAddr: IbGibAddr;
|
|
386
|
+
let isNew = false;
|
|
387
|
+
|
|
388
|
+
if (appAddrs.length === 0) {
|
|
389
|
+
isNew = true;
|
|
390
|
+
if (onBeforeCreate) {
|
|
391
|
+
await onBeforeCreate(metaspace, space);
|
|
392
|
+
}
|
|
393
|
+
app = await createAndSaveNewApp({ AppClass, defaultAppData, metaspace, space });
|
|
394
|
+
appAddr = getIbGibAddr({ ibGib: app });
|
|
395
|
+
} else if (appAddrs.length === 1) {
|
|
396
|
+
appAddr = appAddrs[0];
|
|
397
|
+
} else {
|
|
398
|
+
const list = appAddrs
|
|
399
|
+
.map(a => getIbAndGib({ ibGibAddr: a }).ib)
|
|
400
|
+
.map((ib, idx) => `\n${idx}) ${ib}`);
|
|
401
|
+
|
|
402
|
+
let idx: number | undefined;
|
|
403
|
+
let retry = false;
|
|
404
|
+
do {
|
|
405
|
+
const response = await promptForText({
|
|
406
|
+
title: 'Which App?',
|
|
407
|
+
msg: `${retry ? 'huh? ' : ''}Multiple apps found. Which one?${list}`,
|
|
408
|
+
});
|
|
409
|
+
const parsed = Number.parseInt(response);
|
|
410
|
+
retry = Number.isNaN(parsed) || parsed >= appAddrs.length;
|
|
411
|
+
if (!retry) { idx = parsed; }
|
|
412
|
+
} while (retry);
|
|
413
|
+
appAddr = appAddrs[idx!];
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const resGet = await getFromSpace({ addr: appAddr, space });
|
|
417
|
+
if (resGet.success && resGet.ibGibs?.length === 1) {
|
|
418
|
+
app = resGet.ibGibs[0] as TApp;
|
|
419
|
+
} else {
|
|
420
|
+
throw new Error(`Couldn't get app (${appAddr}).`);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (!app.witness) {
|
|
424
|
+
const witness = new AppClass(undefined, undefined);
|
|
425
|
+
await witness.loadIbGibDto(app);
|
|
426
|
+
app = witness;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (onAppLoaded) {
|
|
430
|
+
app = await onAppLoaded(app, isNew);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return app;
|
|
434
|
+
} catch (error) {
|
|
435
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
436
|
+
throw error;
|
|
437
|
+
} finally {
|
|
438
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async function createAndSaveNewApp<TApp extends AppBase_V1<any, any, any, any, any, any, any, any>>({
|
|
443
|
+
AppClass,
|
|
444
|
+
defaultAppData,
|
|
445
|
+
metaspace,
|
|
446
|
+
space,
|
|
447
|
+
}: {
|
|
448
|
+
AppClass: new (data?: any, rel8ns?: any) => TApp,
|
|
449
|
+
defaultAppData: any,
|
|
450
|
+
metaspace: MetaspaceService,
|
|
451
|
+
space: IbGibSpaceAny
|
|
452
|
+
}): Promise<TApp> {
|
|
453
|
+
const lc = `[${createAndSaveNewApp.name}]`;
|
|
454
|
+
const logalot = true;
|
|
455
|
+
|
|
456
|
+
try {
|
|
457
|
+
if (logalot) { console.log(`${lc} starting...`); }
|
|
458
|
+
|
|
459
|
+
const fnPromptApp = (() => {
|
|
460
|
+
return async () => {
|
|
461
|
+
const name = `${AppClass.name}_${pickRandom_Letters({ count: 8 })}`;
|
|
462
|
+
const data = clone(defaultAppData);
|
|
463
|
+
data.name = name;
|
|
464
|
+
data.uuid = await getUUID();
|
|
465
|
+
const rel8ns = undefined; // App templates usually have DEFAULT_APP_REL8NS as undefined
|
|
466
|
+
|
|
467
|
+
const { classname } = data;
|
|
468
|
+
const ib = getAppIb({ appData: data, classname });
|
|
469
|
+
return await factory.firstGen({
|
|
470
|
+
ib,
|
|
471
|
+
parentIbGib: factory.primitive({ ib: `app ${classname}` }),
|
|
472
|
+
data, rel8ns,
|
|
473
|
+
dna: true,
|
|
474
|
+
linkedRel8ns: [Rel8n.ancestor, Rel8n.past],
|
|
475
|
+
nCounter: true,
|
|
476
|
+
tjp: { timestamp: true },
|
|
477
|
+
}) as TransformResult<IbGibAppAny>;
|
|
478
|
+
};
|
|
479
|
+
})();
|
|
480
|
+
|
|
481
|
+
const app = await createNewApp({
|
|
482
|
+
fnPromptApp,
|
|
483
|
+
space,
|
|
484
|
+
ibgibs: metaspace,
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
if (!app) { throw new Error(`Failed to create app (falsy).`); }
|
|
488
|
+
if (app?.data?.classname !== AppClass.name) {
|
|
489
|
+
throw new Error(`(UNEXPECTED) wrong app classname.`);
|
|
490
|
+
}
|
|
491
|
+
return app as TApp;
|
|
492
|
+
} catch (error) {
|
|
493
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
494
|
+
throw error;
|
|
495
|
+
} finally {
|
|
496
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
async function ensureTagsExist({
|
|
501
|
+
metaspace, tags, logalot
|
|
502
|
+
}: {
|
|
503
|
+
metaspace: MetaspaceService,
|
|
504
|
+
tags: TagConfig[],
|
|
505
|
+
logalot: boolean
|
|
506
|
+
}): Promise<void> {
|
|
507
|
+
const lc = `[${ensureTagsExist.name}]`;
|
|
508
|
+
try {
|
|
509
|
+
if (logalot) { console.log(`${lc} starting...`); }
|
|
510
|
+
const tagIbGibs = await metaspace.getSpecialRel8dIbGibs({
|
|
511
|
+
type: "tags", rel8nName: TAG_REL8N_NAME,
|
|
512
|
+
}) as TagIbGib_V1[];
|
|
513
|
+
|
|
514
|
+
for (const tag of tags) {
|
|
515
|
+
if (!tagIbGibs.some(x => x.data?.text === tag.text)) {
|
|
516
|
+
await metaspace.createTagIbGib({
|
|
517
|
+
text: tag.text,
|
|
518
|
+
icon: tag.icon,
|
|
519
|
+
description: tag.description,
|
|
520
|
+
space: undefined,
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
} catch (error) {
|
|
525
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
526
|
+
throw error;
|
|
527
|
+
} finally {
|
|
528
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
export async function createRequestCommentIbGib_Common({
|
|
533
|
+
args, interpretedArgInfos,
|
|
534
|
+
}: {
|
|
535
|
+
args: string[],
|
|
536
|
+
interpretedArgInfos: RCLIArgInfo[],
|
|
537
|
+
}): Promise<TransformResult<RequestCommentIbGib_V1>> {
|
|
538
|
+
const text = args.join(' ');
|
|
539
|
+
const data: RequestCommentData_V1 = {
|
|
540
|
+
uuid: await getUUID(),
|
|
541
|
+
text,
|
|
542
|
+
args,
|
|
543
|
+
interpretedArgInfos,
|
|
544
|
+
textTimestamp: getTimestamp(),
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
return await factory.firstGen({
|
|
548
|
+
parentIbGib: factory.primitive({ ib: 'comment' }),
|
|
549
|
+
ib: `comment ${text.substring(0, 32).replace(/ /g, '_')}`,
|
|
550
|
+
data,
|
|
551
|
+
dna: true,
|
|
552
|
+
tjp: { uuid: true, timestamp: true },
|
|
553
|
+
nCounter: true,
|
|
554
|
+
}) as TransformResult<RequestCommentIbGib_V1>;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
export function validateParamInfos({ paramInfos }: { paramInfos: RCLIParamInfo[] }): string[] {
|
|
558
|
+
const errors: string[] = [];
|
|
559
|
+
const identifiers: string[] = [];
|
|
560
|
+
paramInfos.forEach(p => {
|
|
561
|
+
const names = [p.name, ...(p.synonyms ?? [])];
|
|
562
|
+
names.forEach(name => {
|
|
563
|
+
if (identifiers.includes(name.toLowerCase())) {
|
|
564
|
+
errors.push(`Duplicate identifier found: ${name}`);
|
|
565
|
+
}
|
|
566
|
+
identifiers.push(name.toLowerCase());
|
|
567
|
+
});
|
|
568
|
+
});
|
|
569
|
+
return errors;
|
|
570
|
+
}
|