@toolproof-core/lib 1.0.3 → 1.0.5
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/artifacts/artifacts.d.ts +4 -3
- package/dist/artifacts/artifacts.d.ts.map +1 -1
- package/dist/firebase/firebaseAdminHelpers.d.ts +2 -2
- package/dist/firebase/firebaseAdminHelpers.d.ts.map +1 -1
- package/dist/firebase/firebaseAdminHelpers.js.map +1 -1
- package/dist/shared.d.ts +33 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +67 -0
- package/dist/shared.js.map +1 -0
- package/dist/types/types.d.ts +2 -5
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js.map +1 -1
- package/dist/utils/extractFrom.d.ts +5 -0
- package/dist/utils/extractFrom.d.ts.map +1 -0
- package/dist/utils/extractFrom.js +72 -0
- package/dist/utils/extractFrom.js.map +1 -0
- package/dist/utils/extractFromCosmosData.d.ts +9 -0
- package/dist/utils/extractFromCosmosData.d.ts.map +1 -0
- package/dist/utils/extractFromCosmosData.js +20 -0
- package/dist/utils/extractFromCosmosData.js.map +1 -0
- package/dist/utils/extractFromResourceDict.d.ts +12 -0
- package/dist/utils/extractFromResourceDict.d.ts.map +1 -0
- package/dist/utils/extractFromResourceDict.js +23 -0
- package/dist/utils/extractFromResourceDict.js.map +1 -0
- package/dist/utils/extractFromResourceMap.d.ts +12 -0
- package/dist/utils/extractFromResourceMap.d.ts.map +1 -0
- package/dist/utils/extractFromResourceMap.js +23 -0
- package/dist/utils/extractFromResourceMap.js.map +1 -0
- package/dist/utils/extractFromResourcesByResourceTypeHandle.d.ts +8 -0
- package/dist/utils/extractFromResourcesByResourceTypeHandle.d.ts.map +1 -0
- package/dist/utils/extractFromResourcesByResourceTypeHandle.js +31 -0
- package/dist/utils/extractFromResourcesByResourceTypeHandle.js.map +1 -0
- package/dist/utils/extractFromStrategy.d.ts +5 -0
- package/dist/utils/extractFromStrategy.d.ts.map +1 -0
- package/dist/utils/extractFromStrategy.js +72 -0
- package/dist/utils/extractFromStrategy.js.map +1 -0
- package/dist/utils/extraction.d.ts +12 -0
- package/dist/utils/extraction.d.ts.map +1 -0
- package/dist/utils/extraction.js +27 -0
- package/dist/utils/extraction.js.map +1 -0
- package/dist/utils/generateFrom.d.ts +4 -0
- package/dist/utils/generateFrom.d.ts.map +1 -0
- package/dist/utils/generateFrom.js +18 -0
- package/dist/utils/generateFrom.js.map +1 -0
- package/dist/utils/generateFromTo.d.ts +4 -0
- package/dist/utils/generateFromTo.d.ts.map +1 -0
- package/dist/utils/generateFromTo.js +18 -0
- package/dist/utils/generateFromTo.js.map +1 -0
- package/dist/utils/parallelization.d.ts +3 -0
- package/dist/utils/parallelization.d.ts.map +1 -0
- package/dist/utils/parallelization.js +136 -0
- package/dist/utils/parallelization.js.map +1 -0
- package/dist/utils/resourceChain.d.ts +22 -0
- package/dist/utils/resourceChain.d.ts.map +1 -0
- package/dist/utils/resourceChain.js +38 -0
- package/dist/utils/resourceChain.js.map +1 -0
- package/dist/utils/roleResourceBinding.d.ts +5 -0
- package/dist/utils/roleResourceBinding.d.ts.map +1 -0
- package/dist/utils/roleResourceBinding.js +74 -0
- package/dist/utils/roleResourceBinding.js.map +1 -0
- package/dist/utils/runnableStrategyCreation.d.ts +8 -0
- package/dist/utils/runnableStrategyCreation.d.ts.map +1 -0
- package/dist/utils/runnableStrategyCreation.js +24 -0
- package/dist/utils/runnableStrategyCreation.js.map +1 -0
- package/dist/utils/stepCreation.d.ts +10 -0
- package/dist/utils/stepCreation.d.ts.map +1 -0
- package/dist/utils/stepCreation.js +80 -0
- package/dist/utils/stepCreation.js.map +1 -0
- package/package.json +48 -41
- package/src/_lib/setup/firebaseAdminInit.ts +38 -38
- package/src/artifacts/artifacts.ts +40 -40
- package/src/firebase/firebaseAdminHelpers.ts +157 -157
- package/src/shared.ts +126 -0
- package/src/types/types.ts +20 -24
- package/src/utils/extractFrom.ts +93 -0
- package/src/utils/extractFromResourcesByResourceTypeHandle.ts +55 -0
- package/src/utils/{creation.ts → generateFrom.ts} +26 -26
- package/src/utils/parallelization.ts +177 -0
- package/src/utils/resourceChain.ts +66 -0
- package/src/utils/roleResourceBinding.ts +109 -0
- package/src/utils/runnableStrategyCreation.ts +47 -0
- package/src/utils/stepCreation.ts +112 -0
- package/tsconfig.json +14 -14
- package/tsconfig.tsbuildinfo +1 -1
- package/src/utils/resourceMapExtraction.ts +0 -47
package/package.json
CHANGED
|
@@ -1,47 +1,54 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
"name": "@toolproof-core/lib",
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"keywords": [],
|
|
7
|
+
"author": "",
|
|
8
|
+
"license": "ISC",
|
|
9
|
+
"exports": {
|
|
10
|
+
"./artifacts": {
|
|
11
|
+
"types": "./dist/artifacts/artifacts.d.ts",
|
|
12
|
+
"import": "./dist/artifacts/artifacts.js"
|
|
13
13
|
},
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"import": "./dist/artifacts/artifacts.js"
|
|
18
|
-
},
|
|
19
|
-
"./types": {
|
|
20
|
-
"types": "./dist/types/types.d.ts",
|
|
21
|
-
"import": "./dist/types/types.js"
|
|
22
|
-
},
|
|
23
|
-
"./resource-map-extraction": {
|
|
24
|
-
"types": "./dist/utils/resourceMapExtraction.d.ts",
|
|
25
|
-
"import": "./dist/utils/resourceMapExtraction.js"
|
|
26
|
-
},
|
|
27
|
-
"./creation": {
|
|
28
|
-
"types": "./dist/utils/creation.d.ts",
|
|
29
|
-
"import": "./dist/utils/creation.js"
|
|
30
|
-
},
|
|
31
|
-
"./firebase-admin-init": {
|
|
32
|
-
"types": "./dist/_lib/setup/firebaseAdminInit.d.ts",
|
|
33
|
-
"import": "./dist/_lib/setup/firebaseAdminInit.js"
|
|
34
|
-
},
|
|
35
|
-
"./firebase-admin-helpers": {
|
|
36
|
-
"types": "./dist/firebase/firebaseAdminHelpers.d.ts",
|
|
37
|
-
"import": "./dist/firebase/firebaseAdminHelpers.js"
|
|
38
|
-
}
|
|
14
|
+
"./types": {
|
|
15
|
+
"types": "./dist/types/types.d.ts",
|
|
16
|
+
"import": "./dist/types/types.js"
|
|
39
17
|
},
|
|
40
|
-
"
|
|
41
|
-
|
|
18
|
+
"./extract-from": {
|
|
19
|
+
"types": "./dist/utils/extractFrom.d.ts",
|
|
20
|
+
"import": "./dist/utils/extractFrom.js"
|
|
42
21
|
},
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
22
|
+
"./extract-from-resources-by-resource-type-handle": {
|
|
23
|
+
"types": "./dist/utils/extractFromResourcesByResourceTypeHandle.d.ts",
|
|
24
|
+
"import": "./dist/utils/extractFromResourcesByResourceTypeHandle.js"
|
|
25
|
+
},
|
|
26
|
+
"./generate-from": {
|
|
27
|
+
"types": "./dist/utils/generateFrom.d.ts",
|
|
28
|
+
"import": "./dist/utils/generateFrom.js"
|
|
29
|
+
},
|
|
30
|
+
"./firebase-admin-init": {
|
|
31
|
+
"types": "./dist/_lib/setup/firebaseAdminInit.d.ts",
|
|
32
|
+
"import": "./dist/_lib/setup/firebaseAdminInit.js"
|
|
33
|
+
},
|
|
34
|
+
"./firebase-admin-helpers": {
|
|
35
|
+
"types": "./dist/firebase/firebaseAdminHelpers.d.ts",
|
|
36
|
+
"import": "./dist/firebase/firebaseAdminHelpers.js"
|
|
37
|
+
},
|
|
38
|
+
"./shared": {
|
|
39
|
+
"types": "./dist/shared.d.ts",
|
|
40
|
+
"import": "./dist/shared.js"
|
|
46
41
|
}
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.0.0"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@toolproof-core/schema": "^1.0.11",
|
|
48
|
+
"firebase-admin": "^13.7.0"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
52
|
+
"build": "tsc -b"
|
|
53
|
+
}
|
|
47
54
|
}
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import { getApp, getApps, initializeApp, applicationDefault, cert } from 'firebase-admin/app';
|
|
2
|
-
import { getFirestore } from 'firebase-admin/firestore';
|
|
3
|
-
import { getStorage } from 'firebase-admin/storage';
|
|
4
|
-
import { existsSync, readFileSync } from 'fs';
|
|
5
|
-
import path from 'path';
|
|
6
|
-
|
|
7
|
-
// Resolve credentials: prefer GOOGLE_APPLICATION_CREDENTIALS, fallback to local gcp-key.json, else ADC
|
|
8
|
-
function resolveCredential() {
|
|
9
|
-
const jsonString = process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON;
|
|
10
|
-
const envPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
11
|
-
const localKeyPath = path.join(process.cwd(), 'gcp-key.json');
|
|
12
|
-
try {
|
|
13
|
-
if (jsonString) {
|
|
14
|
-
const json = JSON.parse(jsonString);
|
|
15
|
-
return cert(json);
|
|
16
|
-
}
|
|
17
|
-
if (envPath && existsSync(envPath)) {
|
|
18
|
-
const json = JSON.parse(readFileSync(envPath, 'utf8'));
|
|
19
|
-
return cert(json);
|
|
20
|
-
}
|
|
21
|
-
if (existsSync(localKeyPath)) {
|
|
22
|
-
const json = JSON.parse(readFileSync(localKeyPath, 'utf8'));
|
|
23
|
-
return cert(json);
|
|
24
|
-
}
|
|
25
|
-
} catch {
|
|
26
|
-
// fall through to ADC
|
|
27
|
-
}
|
|
28
|
-
return applicationDefault();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const app = getApps().length ? getApp() : initializeApp({
|
|
32
|
-
credential: resolveCredential(),
|
|
33
|
-
projectId: "toolproof-563fe",
|
|
34
|
-
});
|
|
35
|
-
const dbAdmin = getFirestore(app);
|
|
36
|
-
const storageAdmin = getStorage(app);
|
|
37
|
-
|
|
38
|
-
export { dbAdmin, storageAdmin };
|
|
1
|
+
import { getApp, getApps, initializeApp, applicationDefault, cert } from 'firebase-admin/app';
|
|
2
|
+
import { getFirestore } from 'firebase-admin/firestore';
|
|
3
|
+
import { getStorage } from 'firebase-admin/storage';
|
|
4
|
+
import { existsSync, readFileSync } from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
|
|
7
|
+
// Resolve credentials: prefer GOOGLE_APPLICATION_CREDENTIALS, fallback to local gcp-key.json, else ADC
|
|
8
|
+
function resolveCredential() {
|
|
9
|
+
const jsonString = process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON;
|
|
10
|
+
const envPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
11
|
+
const localKeyPath = path.join(process.cwd(), 'gcp-key.json');
|
|
12
|
+
try {
|
|
13
|
+
if (jsonString) {
|
|
14
|
+
const json = JSON.parse(jsonString);
|
|
15
|
+
return cert(json);
|
|
16
|
+
}
|
|
17
|
+
if (envPath && existsSync(envPath)) {
|
|
18
|
+
const json = JSON.parse(readFileSync(envPath, 'utf8'));
|
|
19
|
+
return cert(json);
|
|
20
|
+
}
|
|
21
|
+
if (existsSync(localKeyPath)) {
|
|
22
|
+
const json = JSON.parse(readFileSync(localKeyPath, 'utf8'));
|
|
23
|
+
return cert(json);
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
// fall through to ADC
|
|
27
|
+
}
|
|
28
|
+
return applicationDefault();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const app = getApps().length ? getApp() : initializeApp({
|
|
32
|
+
credential: resolveCredential(),
|
|
33
|
+
projectId: "toolproof-563fe",
|
|
34
|
+
});
|
|
35
|
+
const dbAdmin = getFirestore(app);
|
|
36
|
+
const storageAdmin = getStorage(app);
|
|
37
|
+
|
|
38
|
+
export { dbAdmin, storageAdmin };
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import { CONSTANTS as _CONSTANTS, MAPPINGS as _MAPPINGS } from "@toolproof-core/schema";
|
|
2
|
-
|
|
3
|
-
export const CONSTANTS = {
|
|
4
|
-
..._CONSTANTS,
|
|
5
|
-
Persistence: {
|
|
6
|
-
Buckets: {
|
|
7
|
-
tp_resources: 'tp-resources',
|
|
8
|
-
tp_strategies: 'tp-strategies',
|
|
9
|
-
},
|
|
10
|
-
Collections: {
|
|
11
|
-
resources: 'resources',
|
|
12
|
-
members: 'members',
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
Engine: {
|
|
16
|
-
Graphs: {
|
|
17
|
-
GraphRunStrategy: 'GraphRunStrategy',
|
|
18
|
-
GraphBuildStrategy: 'GraphBuildStrategy',
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
Cosmos: {
|
|
22
|
-
TYPE_Boolean: 'TYPE-Boolean',
|
|
23
|
-
TYPE_Natural: 'TYPE-Natural',
|
|
24
|
-
TYPE_ResourceType: 'TYPE-ResourceType',
|
|
25
|
-
TYPE_Job: 'TYPE-Job',
|
|
26
|
-
TYPE_Error: 'TYPE-Error',
|
|
27
|
-
TYPE_RawStrategy: 'TYPE-RawStrategy',
|
|
28
|
-
TYPE_RunnableStrategy: 'TYPE-RunnableStrategy',
|
|
29
|
-
TYPE_StrategyRun: 'TYPE-StrategyRun',
|
|
30
|
-
ROLE_Manual: 'ROLE-Manual',
|
|
31
|
-
ROLE_ErrorOutput: 'ROLE-ErrorOutput',
|
|
32
|
-
ROLE_LessThanSource: 'ROLE-LessThanSource',
|
|
33
|
-
ROLE_LessThanTarget: 'ROLE-LessThanTarget',
|
|
34
|
-
ROLE_LessThanDecision: 'ROLE-LessThanDecision',
|
|
35
|
-
JOB_LessThan: 'JOB-LessThan',
|
|
36
|
-
}
|
|
37
|
-
} as const;
|
|
38
|
-
|
|
39
|
-
export const MAPPINGS = {
|
|
40
|
-
..._MAPPINGS,
|
|
1
|
+
import { CONSTANTS as _CONSTANTS, MAPPINGS as _MAPPINGS } from "@toolproof-core/schema";
|
|
2
|
+
|
|
3
|
+
export const CONSTANTS = {
|
|
4
|
+
..._CONSTANTS,
|
|
5
|
+
Persistence: {
|
|
6
|
+
Buckets: {
|
|
7
|
+
tp_resources: 'tp-resources',
|
|
8
|
+
tp_strategies: 'tp-strategies',
|
|
9
|
+
},
|
|
10
|
+
Collections: {
|
|
11
|
+
resources: 'resources',
|
|
12
|
+
members: 'members',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
Engine: {
|
|
16
|
+
Graphs: {
|
|
17
|
+
GraphRunStrategy: 'GraphRunStrategy',
|
|
18
|
+
GraphBuildStrategy: 'GraphBuildStrategy',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
Cosmos: {
|
|
22
|
+
TYPE_Boolean: 'TYPE-Boolean',
|
|
23
|
+
TYPE_Natural: 'TYPE-Natural',
|
|
24
|
+
TYPE_ResourceType: 'TYPE-ResourceType',
|
|
25
|
+
TYPE_Job: 'TYPE-Job',
|
|
26
|
+
TYPE_Error: 'TYPE-Error',
|
|
27
|
+
TYPE_RawStrategy: 'TYPE-RawStrategy',
|
|
28
|
+
TYPE_RunnableStrategy: 'TYPE-RunnableStrategy',
|
|
29
|
+
TYPE_StrategyRun: 'TYPE-StrategyRun',
|
|
30
|
+
ROLE_Manual: 'ROLE-Manual',
|
|
31
|
+
ROLE_ErrorOutput: 'ROLE-ErrorOutput',
|
|
32
|
+
ROLE_LessThanSource: 'ROLE-LessThanSource',
|
|
33
|
+
ROLE_LessThanTarget: 'ROLE-LessThanTarget',
|
|
34
|
+
ROLE_LessThanDecision: 'ROLE-LessThanDecision',
|
|
35
|
+
JOB_LessThan: 'JOB-LessThan',
|
|
36
|
+
}
|
|
37
|
+
} as const;
|
|
38
|
+
|
|
39
|
+
export const MAPPINGS = {
|
|
40
|
+
..._MAPPINGS,
|
|
41
41
|
} as const;
|
|
@@ -1,157 +1,157 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ResourceJson,
|
|
3
|
-
ResourceTypeIdentityJson,
|
|
4
|
-
StepKindJson,
|
|
5
|
-
} from '@toolproof-core/schema';
|
|
6
|
-
import type { IdentityName, IdentityStringByIdentityName, StepIdentityStringByStepKind,
|
|
7
|
-
import { CONSTANTS } from '../artifacts/artifacts.js';
|
|
8
|
-
import { MAPPINGS } from '../artifacts/artifacts.js';
|
|
9
|
-
import { dbAdmin, storageAdmin } from "../_lib/setup/firebaseAdminInit.js";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
function capitalizeFirst(value: string): string {
|
|
13
|
-
if (!value) return value;
|
|
14
|
-
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function getNewIdentity<K extends IdentityName>(identityName: K): IdentityStringByIdentityName<K> {
|
|
18
|
-
const prefix = MAPPINGS.IdentityNameToIdentityPrefix[identityName];
|
|
19
|
-
const docRef = dbAdmin
|
|
20
|
-
.collection(CONSTANTS.Persistence.Collections.resources)
|
|
21
|
-
.doc(identityName)
|
|
22
|
-
.collection(CONSTANTS.Persistence.Collections.members)
|
|
23
|
-
.doc();
|
|
24
|
-
return (prefix + docRef.id) as IdentityStringByIdentityName<K>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function getNewStepIdentity<K extends StepKindJson>(stepKind: K): StepIdentityStringByStepKind<K> {
|
|
28
|
-
const identityName = `${capitalizeFirst(stepKind)}StepIdentity` as IdentityName;
|
|
29
|
-
if (!(identityName in MAPPINGS.IdentityNameToIdentityPrefix)) {
|
|
30
|
-
throw new Error(`No IdentityNameToIdentityPrefix entry for derived step identity name: ${identityName}`);
|
|
31
|
-
}
|
|
32
|
-
return getNewIdentity(identityName) as StepIdentityStringByStepKind<K>;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export async function listResources(
|
|
36
|
-
resourceTypeHandles: ResourceTypeIdentityJson[]
|
|
37
|
-
): Promise<
|
|
38
|
-
const bucket_resources = storageAdmin.bucket(CONSTANTS.Persistence.Buckets.tp_resources);
|
|
39
|
-
const bucket_strategies = storageAdmin.bucket(CONSTANTS.Persistence.Buckets.tp_strategies);
|
|
40
|
-
|
|
41
|
-
async function fetchFilesUnder(resourceTypeHandle: ResourceTypeIdentityJson): Promise<Array<{ data: unknown; meta: any; name: string }>> {
|
|
42
|
-
const bucket = resourceTypeHandle === CONSTANTS.Cosmos.TYPE_RunnableStrategy
|
|
43
|
-
? bucket_strategies
|
|
44
|
-
: bucket_resources;
|
|
45
|
-
const prefix = `${resourceTypeHandle}/`;
|
|
46
|
-
const [found] = await bucket.getFiles({ prefix });
|
|
47
|
-
const files = found.filter(f => {
|
|
48
|
-
const name = f.name || '';
|
|
49
|
-
if (!name || name.endsWith('/')) return false;
|
|
50
|
-
return true;
|
|
51
|
-
});
|
|
52
|
-
if (!files.length) return [];
|
|
53
|
-
const items = await Promise.all(files.map(async (file) => {
|
|
54
|
-
try {
|
|
55
|
-
const [buf] = await file.download();
|
|
56
|
-
const meta = file.metadata || (await file.getMetadata())[0];
|
|
57
|
-
const data = JSON.parse(buf.toString('utf8')) as unknown;
|
|
58
|
-
return { data, meta, name: file.name };
|
|
59
|
-
} catch {
|
|
60
|
-
return null as unknown as { data: unknown; meta: any; name: string };
|
|
61
|
-
}
|
|
62
|
-
}));
|
|
63
|
-
return items.filter(Boolean) as Array<{ data: unknown; meta: any; name: string }>;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const entries = await Promise.all(
|
|
67
|
-
resourceTypeHandles.map(async (resourceTypeHandle) => {
|
|
68
|
-
const rows = await fetchFilesUnder(resourceTypeHandle);
|
|
69
|
-
const items: ResourceJson[] = rows.map(({ data, meta, name }) => {
|
|
70
|
-
const flat = meta?.metadata ?? {};
|
|
71
|
-
// Reconstruct nested object from flattened keys (dot and array index notation)
|
|
72
|
-
const root: any = {};
|
|
73
|
-
for (const [k, vRaw] of Object.entries(flat)) {
|
|
74
|
-
if (typeof vRaw !== 'string') continue; // GCS should store only strings
|
|
75
|
-
const vStr = vRaw.trim();
|
|
76
|
-
// Attempt JSON parse for non-simple primitives
|
|
77
|
-
let value: any = vStr;
|
|
78
|
-
if ((vStr.startsWith('{') && vStr.endsWith('}')) || (vStr.startsWith('[') && vStr.endsWith(']'))) {
|
|
79
|
-
try { value = JSON.parse(vStr); } catch { value = vStr; }
|
|
80
|
-
}
|
|
81
|
-
// Split by '.' while preserving array indices
|
|
82
|
-
const segments = k.split('.');
|
|
83
|
-
let cursor = root;
|
|
84
|
-
for (const [i, seg] of segments.entries()) {
|
|
85
|
-
const arrIdxMatch = seg.match(/^(.*)\[(\d+)\]$/);
|
|
86
|
-
if (arrIdxMatch) {
|
|
87
|
-
const base = arrIdxMatch[1];
|
|
88
|
-
const idxStr = arrIdxMatch[2];
|
|
89
|
-
if (base === undefined || idxStr === undefined) continue;
|
|
90
|
-
const idx = parseInt(idxStr, 10);
|
|
91
|
-
if (!cursor[base]) cursor[base] = [];
|
|
92
|
-
if (!Array.isArray(cursor[base])) cursor[base] = [];
|
|
93
|
-
while (cursor[base].length <= idx) cursor[base].push(undefined);
|
|
94
|
-
if (i === segments.length - 1) {
|
|
95
|
-
cursor[base][idx] = value;
|
|
96
|
-
} else {
|
|
97
|
-
if (!cursor[base][idx]) cursor[base][idx] = {};
|
|
98
|
-
cursor = cursor[base][idx];
|
|
99
|
-
}
|
|
100
|
-
} else {
|
|
101
|
-
if (i === segments.length - 1) {
|
|
102
|
-
cursor[seg] = value;
|
|
103
|
-
} else {
|
|
104
|
-
if (!cursor[seg] || typeof cursor[seg] !== 'object') cursor[seg] = {};
|
|
105
|
-
cursor = cursor[seg];
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
const identity = root.identity;
|
|
111
|
-
// const resourceTypeHandle = root.resourceTypeHandle; // we already have this
|
|
112
|
-
const resourceRoleHandle = root.creationContext.resourceRoleHandle;
|
|
113
|
-
const jobStepHandle = root.creationContext.jobStepHandle;
|
|
114
|
-
const resourceShellKind = root.resourceShellKind;
|
|
115
|
-
const versionRaw = root.version;
|
|
116
|
-
const version = typeof versionRaw === 'number'
|
|
117
|
-
? versionRaw
|
|
118
|
-
: parseInt(String(versionRaw ?? ''), 10);
|
|
119
|
-
const path = root.path;
|
|
120
|
-
const timestamp = root.timestamp;
|
|
121
|
-
|
|
122
|
-
const missing = [
|
|
123
|
-
['identity', identity],
|
|
124
|
-
['resourceRoleHandle', resourceRoleHandle],
|
|
125
|
-
['jobStepHandle', jobStepHandle],
|
|
126
|
-
['resourceShellKind', resourceShellKind],
|
|
127
|
-
['version', Number.isFinite(version) ? String(version) : ''],
|
|
128
|
-
['timestamp', timestamp],
|
|
129
|
-
['path', path],
|
|
130
|
-
].filter(([_, v]) => typeof v !== 'string' || (v as string).length === 0) as Array<[string, string | undefined]>;
|
|
131
|
-
|
|
132
|
-
if (missing.length) {
|
|
133
|
-
const keys = missing.map(([k]) => k).join(', ');
|
|
134
|
-
throw new Error(`Missing required metadata keys [${keys}] for resource file: ${name}`);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
identity,
|
|
139
|
-
resourceTypeHandle,
|
|
140
|
-
creationContext: {
|
|
141
|
-
resourceRoleHandle,
|
|
142
|
-
jobStepHandle,
|
|
143
|
-
},
|
|
144
|
-
resourceShellKind,
|
|
145
|
-
version,
|
|
146
|
-
timestamp: timestamp as string,
|
|
147
|
-
path: path as string,
|
|
148
|
-
nucleus: data as any,
|
|
149
|
-
} as unknown as ResourceJson;
|
|
150
|
-
});
|
|
151
|
-
return [resourceTypeHandle, items] as const;
|
|
152
|
-
})
|
|
153
|
-
);
|
|
154
|
-
return Object.fromEntries(entries) as
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
1
|
+
import type {
|
|
2
|
+
ResourceJson,
|
|
3
|
+
ResourceTypeIdentityJson,
|
|
4
|
+
StepKindJson,
|
|
5
|
+
} from '@toolproof-core/schema';
|
|
6
|
+
import type { IdentityName, IdentityStringByIdentityName, StepIdentityStringByStepKind, ResourcesByResourceTypeHandle } from '../types/types.js';
|
|
7
|
+
import { CONSTANTS } from '../artifacts/artifacts.js';
|
|
8
|
+
import { MAPPINGS } from '../artifacts/artifacts.js';
|
|
9
|
+
import { dbAdmin, storageAdmin } from "../_lib/setup/firebaseAdminInit.js";
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
function capitalizeFirst(value: string): string {
|
|
13
|
+
if (!value) return value;
|
|
14
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getNewIdentity<K extends IdentityName>(identityName: K): IdentityStringByIdentityName<K> {
|
|
18
|
+
const prefix = MAPPINGS.IdentityNameToIdentityPrefix[identityName];
|
|
19
|
+
const docRef = dbAdmin
|
|
20
|
+
.collection(CONSTANTS.Persistence.Collections.resources)
|
|
21
|
+
.doc(identityName)
|
|
22
|
+
.collection(CONSTANTS.Persistence.Collections.members)
|
|
23
|
+
.doc();
|
|
24
|
+
return (prefix + docRef.id) as IdentityStringByIdentityName<K>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getNewStepIdentity<K extends StepKindJson>(stepKind: K): StepIdentityStringByStepKind<K> {
|
|
28
|
+
const identityName = `${capitalizeFirst(stepKind)}StepIdentity` as IdentityName;
|
|
29
|
+
if (!(identityName in MAPPINGS.IdentityNameToIdentityPrefix)) {
|
|
30
|
+
throw new Error(`No IdentityNameToIdentityPrefix entry for derived step identity name: ${identityName}`);
|
|
31
|
+
}
|
|
32
|
+
return getNewIdentity(identityName) as StepIdentityStringByStepKind<K>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function listResources(
|
|
36
|
+
resourceTypeHandles: ResourceTypeIdentityJson[]
|
|
37
|
+
): Promise<ResourcesByResourceTypeHandle> {
|
|
38
|
+
const bucket_resources = storageAdmin.bucket(CONSTANTS.Persistence.Buckets.tp_resources);
|
|
39
|
+
const bucket_strategies = storageAdmin.bucket(CONSTANTS.Persistence.Buckets.tp_strategies);
|
|
40
|
+
|
|
41
|
+
async function fetchFilesUnder(resourceTypeHandle: ResourceTypeIdentityJson): Promise<Array<{ data: unknown; meta: any; name: string }>> {
|
|
42
|
+
const bucket = resourceTypeHandle === CONSTANTS.Cosmos.TYPE_RunnableStrategy
|
|
43
|
+
? bucket_strategies
|
|
44
|
+
: bucket_resources;
|
|
45
|
+
const prefix = `${resourceTypeHandle}/`;
|
|
46
|
+
const [found] = await bucket.getFiles({ prefix });
|
|
47
|
+
const files = found.filter(f => {
|
|
48
|
+
const name = f.name || '';
|
|
49
|
+
if (!name || name.endsWith('/')) return false;
|
|
50
|
+
return true;
|
|
51
|
+
});
|
|
52
|
+
if (!files.length) return [];
|
|
53
|
+
const items = await Promise.all(files.map(async (file) => {
|
|
54
|
+
try {
|
|
55
|
+
const [buf] = await file.download();
|
|
56
|
+
const meta = file.metadata || (await file.getMetadata())[0];
|
|
57
|
+
const data = JSON.parse(buf.toString('utf8')) as unknown;
|
|
58
|
+
return { data, meta, name: file.name };
|
|
59
|
+
} catch {
|
|
60
|
+
return null as unknown as { data: unknown; meta: any; name: string };
|
|
61
|
+
}
|
|
62
|
+
}));
|
|
63
|
+
return items.filter(Boolean) as Array<{ data: unknown; meta: any; name: string }>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const entries = await Promise.all(
|
|
67
|
+
resourceTypeHandles.map(async (resourceTypeHandle) => {
|
|
68
|
+
const rows = await fetchFilesUnder(resourceTypeHandle);
|
|
69
|
+
const items: ResourceJson[] = rows.map(({ data, meta, name }) => {
|
|
70
|
+
const flat = meta?.metadata ?? {};
|
|
71
|
+
// Reconstruct nested object from flattened keys (dot and array index notation)
|
|
72
|
+
const root: any = {};
|
|
73
|
+
for (const [k, vRaw] of Object.entries(flat)) {
|
|
74
|
+
if (typeof vRaw !== 'string') continue; // GCS should store only strings
|
|
75
|
+
const vStr = vRaw.trim();
|
|
76
|
+
// Attempt JSON parse for non-simple primitives
|
|
77
|
+
let value: any = vStr;
|
|
78
|
+
if ((vStr.startsWith('{') && vStr.endsWith('}')) || (vStr.startsWith('[') && vStr.endsWith(']'))) {
|
|
79
|
+
try { value = JSON.parse(vStr); } catch { value = vStr; }
|
|
80
|
+
}
|
|
81
|
+
// Split by '.' while preserving array indices
|
|
82
|
+
const segments = k.split('.');
|
|
83
|
+
let cursor = root;
|
|
84
|
+
for (const [i, seg] of segments.entries()) {
|
|
85
|
+
const arrIdxMatch = seg.match(/^(.*)\[(\d+)\]$/);
|
|
86
|
+
if (arrIdxMatch) {
|
|
87
|
+
const base = arrIdxMatch[1];
|
|
88
|
+
const idxStr = arrIdxMatch[2];
|
|
89
|
+
if (base === undefined || idxStr === undefined) continue;
|
|
90
|
+
const idx = parseInt(idxStr, 10);
|
|
91
|
+
if (!cursor[base]) cursor[base] = [];
|
|
92
|
+
if (!Array.isArray(cursor[base])) cursor[base] = [];
|
|
93
|
+
while (cursor[base].length <= idx) cursor[base].push(undefined);
|
|
94
|
+
if (i === segments.length - 1) {
|
|
95
|
+
cursor[base][idx] = value;
|
|
96
|
+
} else {
|
|
97
|
+
if (!cursor[base][idx]) cursor[base][idx] = {};
|
|
98
|
+
cursor = cursor[base][idx];
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
if (i === segments.length - 1) {
|
|
102
|
+
cursor[seg] = value;
|
|
103
|
+
} else {
|
|
104
|
+
if (!cursor[seg] || typeof cursor[seg] !== 'object') cursor[seg] = {};
|
|
105
|
+
cursor = cursor[seg];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const identity = root.identity;
|
|
111
|
+
// const resourceTypeHandle = root.resourceTypeHandle; // we already have this
|
|
112
|
+
const resourceRoleHandle = root.creationContext.resourceRoleHandle;
|
|
113
|
+
const jobStepHandle = root.creationContext.jobStepHandle;
|
|
114
|
+
const resourceShellKind = root.resourceShellKind;
|
|
115
|
+
const versionRaw = root.version;
|
|
116
|
+
const version = typeof versionRaw === 'number'
|
|
117
|
+
? versionRaw
|
|
118
|
+
: parseInt(String(versionRaw ?? ''), 10);
|
|
119
|
+
const path = root.path;
|
|
120
|
+
const timestamp = root.timestamp;
|
|
121
|
+
|
|
122
|
+
const missing = [
|
|
123
|
+
['identity', identity],
|
|
124
|
+
['resourceRoleHandle', resourceRoleHandle],
|
|
125
|
+
['jobStepHandle', jobStepHandle],
|
|
126
|
+
['resourceShellKind', resourceShellKind],
|
|
127
|
+
['version', Number.isFinite(version) ? String(version) : ''],
|
|
128
|
+
['timestamp', timestamp],
|
|
129
|
+
['path', path],
|
|
130
|
+
].filter(([_, v]) => typeof v !== 'string' || (v as string).length === 0) as Array<[string, string | undefined]>;
|
|
131
|
+
|
|
132
|
+
if (missing.length) {
|
|
133
|
+
const keys = missing.map(([k]) => k).join(', ');
|
|
134
|
+
throw new Error(`Missing required metadata keys [${keys}] for resource file: ${name}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
identity,
|
|
139
|
+
resourceTypeHandle,
|
|
140
|
+
creationContext: {
|
|
141
|
+
resourceRoleHandle,
|
|
142
|
+
jobStepHandle,
|
|
143
|
+
},
|
|
144
|
+
resourceShellKind,
|
|
145
|
+
version,
|
|
146
|
+
timestamp: timestamp as string,
|
|
147
|
+
path: path as string,
|
|
148
|
+
nucleus: data as any,
|
|
149
|
+
} as unknown as ResourceJson;
|
|
150
|
+
});
|
|
151
|
+
return [resourceTypeHandle, items] as const;
|
|
152
|
+
})
|
|
153
|
+
);
|
|
154
|
+
return Object.fromEntries(entries) as ResourcesByResourceTypeHandle;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|