@toolproof-core/lib 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/artifacts/artifacts.d.ts +1 -0
  2. package/dist/artifacts/artifacts.d.ts.map +1 -1
  3. package/dist/integrations/firebase/createRunnableStrategy.d.ts +3 -0
  4. package/dist/integrations/firebase/createRunnableStrategy.d.ts.map +1 -0
  5. package/dist/integrations/firebase/createRunnableStrategy.js +10 -0
  6. package/dist/integrations/firebase/createRunnableStrategy.js.map +1 -0
  7. package/dist/integrations/firebase/createStep.d.ts +11 -0
  8. package/dist/integrations/firebase/createStep.d.ts.map +1 -0
  9. package/dist/integrations/firebase/createStep.js +43 -0
  10. package/dist/integrations/firebase/createStep.js.map +1 -0
  11. package/dist/integrations/firebase/firebaseAdminHelpers.d.ts +6 -0
  12. package/dist/integrations/firebase/firebaseAdminHelpers.d.ts.map +1 -0
  13. package/dist/integrations/firebase/firebaseAdminHelpers.js +154 -0
  14. package/dist/integrations/firebase/firebaseAdminHelpers.js.map +1 -0
  15. package/dist/integrations/firebase/firebaseAdminInit.d.ts +4 -0
  16. package/dist/integrations/firebase/firebaseAdminInit.d.ts.map +1 -0
  17. package/{src/_lib/setup/firebaseAdminInit.ts → dist/integrations/firebase/firebaseAdminInit.js} +33 -38
  18. package/dist/integrations/firebase/firebaseAdminInit.js.map +1 -0
  19. package/dist/types/types.d.ts +3 -3
  20. package/dist/types/types.d.ts.map +1 -1
  21. package/dist/utils/creation/resourceCreation.d.ts +9 -0
  22. package/dist/utils/creation/resourceCreation.d.ts.map +1 -0
  23. package/dist/utils/creation/resourceCreation.js +62 -0
  24. package/dist/utils/creation/resourceCreation.js.map +1 -0
  25. package/dist/utils/creation/runnableStrategyCreation.d.ts +4 -0
  26. package/dist/utils/creation/runnableStrategyCreation.d.ts.map +1 -0
  27. package/dist/utils/creation/runnableStrategyCreation.js +27 -0
  28. package/dist/utils/creation/runnableStrategyCreation.js.map +1 -0
  29. package/dist/utils/creation/stepCreation.d.ts +34 -0
  30. package/dist/utils/creation/stepCreation.d.ts.map +1 -0
  31. package/dist/utils/creation/stepCreation.js +89 -0
  32. package/dist/utils/creation/stepCreation.js.map +1 -0
  33. package/package.json +12 -12
  34. package/src/integrations/firebase/createRunnableStrategy.ts +20 -0
  35. package/src/integrations/firebase/createStep.ts +71 -0
  36. package/src/{firebase → integrations/firebase}/firebaseAdminHelpers.ts +87 -49
  37. package/src/integrations/firebase/firebaseAdminInit.ts +39 -0
  38. package/src/types/types.ts +6 -6
  39. package/src/utils/{createResource.ts → creation/resourceCreation.ts} +9 -11
  40. package/src/utils/creation/runnableStrategyCreation.ts +46 -0
  41. package/src/utils/creation/stepCreation.ts +159 -0
  42. package/tsconfig.tsbuildinfo +1 -1
  43. package/src/utils/createRunnableStrategy.ts +0 -31
  44. package/src/utils/createStep.ts +0 -111
@@ -0,0 +1,89 @@
1
+ import { CONSTANTS } from '../../artifacts/artifacts.js';
2
+ function assertNonEmpty(arr, msg) {
3
+ if (arr.length === 0) {
4
+ throw new Error(msg);
5
+ }
6
+ }
7
+ function getRoleBindings(job) {
8
+ return {
9
+ inputBindings: Object.keys(job.roles.inputDict),
10
+ outputBindings: Object.keys(job.roles.outputDict),
11
+ };
12
+ }
13
+ export function buildJobStepFromJob(job, identity) {
14
+ return {
15
+ identity,
16
+ stepKind: CONSTANTS.Enums.StepKind.job,
17
+ jobHandle: job.identity,
18
+ roleBindings: getRoleBindings(job),
19
+ };
20
+ }
21
+ export function buildLoopStepFromJobPair(whatJob, whenJob, identities) {
22
+ const what = buildJobStepFromJob(whatJob, identities.whatIdentity);
23
+ const when = buildJobStepFromJob(whenJob, identities.whenIdentity);
24
+ if (identities.stepKind === CONSTANTS.Enums.StepKind.for) {
25
+ return {
26
+ identity: identities.stepIdentity,
27
+ stepKind: CONSTANTS.Enums.StepKind.for,
28
+ case: { what, when },
29
+ };
30
+ }
31
+ return {
32
+ identity: identities.stepIdentity,
33
+ stepKind: CONSTANTS.Enums.StepKind.while,
34
+ case: { what, when },
35
+ };
36
+ }
37
+ export function buildBranchStepFromJobPairs(cases, branchIdentity, caseIdentities) {
38
+ if (cases.length !== caseIdentities.length) {
39
+ throw new Error('buildBranchStepFromJobPairs requires one identity pair per case');
40
+ }
41
+ const resolved = cases.map(({ whatJob, whenJob }, index) => {
42
+ const identities = caseIdentities[index];
43
+ if (!identities) {
44
+ throw new Error(`Missing case identities for case index ${index}`);
45
+ }
46
+ const what = buildJobStepFromJob(whatJob, identities.whatIdentity);
47
+ const when = buildJobStepFromJob(whenJob, identities.whenIdentity);
48
+ return { what, when };
49
+ });
50
+ assertNonEmpty(resolved, 'buildBranchStepFromJobPairs requires at least one case');
51
+ return {
52
+ identity: branchIdentity,
53
+ stepKind: CONSTANTS.Enums.StepKind.branch,
54
+ cases: resolved,
55
+ };
56
+ }
57
+ export function cloneForStepWithIdentities(forStep, identities) {
58
+ return {
59
+ identity: identities.stepIdentity,
60
+ stepKind: CONSTANTS.Enums.StepKind.for,
61
+ case: {
62
+ what: {
63
+ ...forStep.case.what,
64
+ identity: identities.whatIdentity,
65
+ },
66
+ when: {
67
+ ...forStep.case.when,
68
+ identity: identities.whenIdentity,
69
+ },
70
+ },
71
+ };
72
+ }
73
+ export function cloneWhileStepWithIdentities(whileStep, identities) {
74
+ return {
75
+ identity: identities.stepIdentity,
76
+ stepKind: CONSTANTS.Enums.StepKind.while,
77
+ case: {
78
+ what: {
79
+ ...whileStep.case.what,
80
+ identity: identities.whatIdentity,
81
+ },
82
+ when: {
83
+ ...whileStep.case.when,
84
+ identity: identities.whenIdentity,
85
+ },
86
+ },
87
+ };
88
+ }
89
+ //# sourceMappingURL=stepCreation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stepCreation.js","sourceRoot":"","sources":["../../../src/utils/creation/stepCreation.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolproof-core/lib",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "keywords": [],
@@ -20,16 +20,16 @@
20
20
  "import": "./dist/utils/extractData.js"
21
21
  },
22
22
  "./create-resource": {
23
- "types": "./dist/utils/createResource.d.ts",
24
- "import": "./dist/utils/createResource.js"
23
+ "types": "./dist/utils/creation/resourceCreation.d.ts",
24
+ "import": "./dist/utils/creation/resourceCreation.js"
25
25
  },
26
26
  "./create-step": {
27
- "types": "./dist/utils/createStep.d.ts",
28
- "import": "./dist/utils/createStep.js"
27
+ "types": "./dist/integrations/firebase/createStep.d.ts",
28
+ "import": "./dist/integrations/firebase/createStep.js"
29
29
  },
30
30
  "./create-runnable-strategy": {
31
- "types": "./dist/utils/createRunnableStrategy.d.ts",
32
- "import": "./dist/utils/createRunnableStrategy.js"
31
+ "types": "./dist/integrations/firebase/createRunnableStrategy.d.ts",
32
+ "import": "./dist/integrations/firebase/createRunnableStrategy.js"
33
33
  },
34
34
  "./resolve-resource-chain": {
35
35
  "types": "./dist/utils/resolveResourceChain.d.ts",
@@ -40,19 +40,19 @@
40
40
  "import": "./dist/utils/bindInputRoleToResource.js"
41
41
  },
42
42
  "./firebase-admin-init": {
43
- "types": "./dist/_lib/setup/firebaseAdminInit.d.ts",
44
- "import": "./dist/_lib/setup/firebaseAdminInit.js"
43
+ "types": "./dist/integrations/firebase/firebaseAdminInit.d.ts",
44
+ "import": "./dist/integrations/firebase/firebaseAdminInit.js"
45
45
  },
46
46
  "./firebase-admin-helpers": {
47
- "types": "./dist/firebase/firebaseAdminHelpers.d.ts",
48
- "import": "./dist/firebase/firebaseAdminHelpers.js"
47
+ "types": "./dist/integrations/firebase/firebaseAdminHelpers.d.ts",
48
+ "import": "./dist/integrations/firebase/firebaseAdminHelpers.js"
49
49
  }
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/node": "^22.0.0"
53
53
  },
54
54
  "dependencies": {
55
- "@toolproof-core/schema": "^1.0.21",
55
+ "@toolproof-core/schema": "^1.0.23",
56
56
  "firebase-admin": "^13.7.0"
57
57
  },
58
58
  "scripts": {
@@ -0,0 +1,20 @@
1
+ import type { RawStrategyJson, RunnableStrategyJson } from '@toolproof-core/schema';
2
+ import { CONSTANTS } from '../../artifacts/artifacts.js';
3
+ import {
4
+ buildRunnableStrategy,
5
+ getRunnableStrategyThreadGroups,
6
+ } from '../../utils/creation/runnableStrategyCreation.js';
7
+ import { getNewIdentity } from './firebaseAdminHelpers.js';
8
+
9
+ export function createRunnableStrategy(rawStrategy: RawStrategyJson): RunnableStrategyJson {
10
+ const threadStepGroups = getRunnableStrategyThreadGroups(rawStrategy);
11
+ const runnableStrategyIdentity = getNewIdentity(CONSTANTS.Names.RunnableStrategyIdentity);
12
+ const threadIdentities = threadStepGroups.map(() => getNewIdentity(CONSTANTS.Names.StrategyThreadIdentity));
13
+
14
+ return buildRunnableStrategy(
15
+ rawStrategy,
16
+ runnableStrategyIdentity,
17
+ threadStepGroups,
18
+ threadIdentities,
19
+ );
20
+ }
@@ -0,0 +1,71 @@
1
+ import type {
2
+ BranchStepJson,
3
+ ForStepJson,
4
+ JobJson,
5
+ JobStepJson,
6
+ WhileStepJson,
7
+ } from '@toolproof-core/schema';
8
+ import { CONSTANTS } from '../../artifacts/artifacts.js';
9
+ import {
10
+ buildBranchStepFromJobPairs,
11
+ buildJobStepFromJob,
12
+ buildLoopStepFromJobPair,
13
+ cloneForStepWithIdentities,
14
+ cloneWhileStepWithIdentities,
15
+ } from '../../utils/creation/stepCreation.js';
16
+ import { getNewStepIdentity } from './firebaseAdminHelpers.js';
17
+
18
+ export function createJobStepFromJob(job: JobJson): JobStepJson {
19
+ return buildJobStepFromJob(job, getNewStepIdentity(CONSTANTS.Enums.StepKind.job));
20
+ }
21
+
22
+ export function createLoopStepFromJobPair(
23
+ whatJob: JobJson,
24
+ whenJob: JobJson,
25
+ stepKind: typeof CONSTANTS.Enums.StepKind.for | typeof CONSTANTS.Enums.StepKind.while,
26
+ ): ForStepJson | WhileStepJson {
27
+ if (stepKind === CONSTANTS.Enums.StepKind.for) {
28
+ return buildLoopStepFromJobPair(whatJob, whenJob, {
29
+ stepKind,
30
+ stepIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.for),
31
+ whatIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.job),
32
+ whenIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.job),
33
+ });
34
+ }
35
+
36
+ return buildLoopStepFromJobPair(whatJob, whenJob, {
37
+ stepKind,
38
+ stepIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.while),
39
+ whatIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.job),
40
+ whenIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.job),
41
+ });
42
+ }
43
+
44
+ export function createBranchStepFromJobPairs(
45
+ cases: Array<{ whatJob: JobJson; whenJob: JobJson }>,
46
+ ): BranchStepJson {
47
+ return buildBranchStepFromJobPairs(
48
+ cases,
49
+ getNewStepIdentity(CONSTANTS.Enums.StepKind.branch),
50
+ cases.map(() => ({
51
+ whatIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.job),
52
+ whenIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.job),
53
+ })),
54
+ );
55
+ }
56
+
57
+ export function cloneForStep(forStep: ForStepJson): ForStepJson {
58
+ return cloneForStepWithIdentities(forStep, {
59
+ stepIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.for),
60
+ whatIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.job),
61
+ whenIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.job),
62
+ });
63
+ }
64
+
65
+ export function cloneWhileStep(whileStep: WhileStepJson): WhileStepJson {
66
+ return cloneWhileStepWithIdentities(whileStep, {
67
+ stepIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.while),
68
+ whatIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.job),
69
+ whenIdentity: getNewStepIdentity(CONSTANTS.Enums.StepKind.job),
70
+ });
71
+ }
@@ -3,14 +3,20 @@ import type {
3
3
  ResourceTypeIdentityJson,
4
4
  StepKindJson,
5
5
  } from '@toolproof-core/schema';
6
- import type { IdentityName, IdentityStringByIdentityName, StepIdentityStringByStepKind, ResourcesByTypeDict } 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
-
6
+ import type {
7
+ IdentityName,
8
+ IdentityStringByIdentityName,
9
+ ResourcesByTypeDict,
10
+ StepIdentityStringByStepKind,
11
+ } from '../../types/types.js';
12
+ import { CONSTANTS, MAPPINGS } from '../../artifacts/artifacts.js';
13
+ import { dbAdmin, storageAdmin } from './firebaseAdminInit.js';
11
14
 
12
15
  function capitalizeFirst(value: string): string {
13
- if (!value) return value;
16
+ if (!value) {
17
+ return value;
18
+ }
19
+
14
20
  return value.charAt(0).toUpperCase() + value.slice(1);
15
21
  }
16
22
 
@@ -21,35 +27,43 @@ export function getNewIdentity<K extends IdentityName>(identityName: K): Identit
21
27
  .doc(identityName)
22
28
  .collection(CONSTANTS.Persistence.Collections.members)
23
29
  .doc();
30
+
24
31
  return (prefix + docRef.id) as IdentityStringByIdentityName<K>;
25
32
  }
26
33
 
27
34
  export function getNewStepIdentity<K extends StepKindJson>(stepKind: K): StepIdentityStringByStepKind<K> {
28
35
  const identityName = `${capitalizeFirst(stepKind)}StepIdentity` as IdentityName;
36
+
29
37
  if (!(identityName in MAPPINGS.IdentityNameToIdentityPrefix)) {
30
38
  throw new Error(`No IdentityNameToIdentityPrefix entry for derived step identity name: ${identityName}`);
31
39
  }
40
+
32
41
  return getNewIdentity(identityName) as StepIdentityStringByStepKind<K>;
33
42
  }
34
43
 
35
44
  export async function listResources(
36
- resourceTypeHandles: ResourceTypeIdentityJson[]
45
+ resourceTypeHandles: ResourceTypeIdentityJson[],
37
46
  ): Promise<ResourcesByTypeDict> {
38
- const bucket_resources = storageAdmin.bucket(CONSTANTS.Persistence.Buckets.tp_resources);
39
- const bucket_strategies = storageAdmin.bucket(CONSTANTS.Persistence.Buckets.tp_strategies);
47
+ const bucketResources = storageAdmin.bucket(CONSTANTS.Persistence.Buckets.tp_resources);
48
+ const bucketStrategies = storageAdmin.bucket(CONSTANTS.Persistence.Buckets.tp_strategies);
40
49
 
41
- async function fetchFilesUnder(resourceTypeHandle: ResourceTypeIdentityJson): Promise<Array<{ data: unknown; meta: any; name: string }>> {
50
+ async function fetchFilesUnder(
51
+ resourceTypeHandle: ResourceTypeIdentityJson,
52
+ ): Promise<Array<{ data: unknown; meta: any; name: string }>> {
42
53
  const bucket = resourceTypeHandle === CONSTANTS.Cosmos.TYPE_RunnableStrategy
43
- ? bucket_strategies
44
- : bucket_resources;
54
+ ? bucketStrategies
55
+ : bucketResources;
45
56
  const prefix = `${resourceTypeHandle}/`;
46
57
  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;
58
+ const files = found.filter((file) => {
59
+ const name = file.name || '';
60
+ return !!name && !name.endsWith('/');
51
61
  });
52
- if (!files.length) return [];
62
+
63
+ if (!files.length) {
64
+ return [];
65
+ }
66
+
53
67
  const items = await Promise.all(files.map(async (file) => {
54
68
  try {
55
69
  const [buf] = await file.download();
@@ -60,6 +74,7 @@ export async function listResources(
60
74
  return null as unknown as { data: unknown; meta: any; name: string };
61
75
  }
62
76
  }));
77
+
63
78
  return items.filter(Boolean) as Array<{ data: unknown; meta: any; name: string }>;
64
79
  }
65
80
 
@@ -68,47 +83,70 @@ export async function listResources(
68
83
  const rows = await fetchFilesUnder(resourceTypeHandle);
69
84
  const items: ResourceJson[] = rows.map(({ data, meta, name }) => {
70
85
  const flat = meta?.metadata ?? {};
71
- // Reconstruct nested object from flattened keys (dot and array index notation)
72
86
  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; }
87
+
88
+ for (const [key, valueRaw] of Object.entries(flat)) {
89
+ if (typeof valueRaw !== 'string') {
90
+ continue;
91
+ }
92
+
93
+ const valueString = valueRaw.trim();
94
+ let value: any = valueString;
95
+
96
+ if ((valueString.startsWith('{') && valueString.endsWith('}')) || (valueString.startsWith('[') && valueString.endsWith(']'))) {
97
+ try {
98
+ value = JSON.parse(valueString);
99
+ } catch {
100
+ value = valueString;
101
+ }
80
102
  }
81
- // Split by '.' while preserving array indices
82
- const segments = k.split('.');
103
+
104
+ const segments = key.split('.');
83
105
  let cursor = root;
84
- for (const [i, seg] of segments.entries()) {
85
- const arrIdxMatch = seg.match(/^(.*)\[(\d+)\]$/);
106
+
107
+ for (const [index, segment] of segments.entries()) {
108
+ const arrIdxMatch = segment.match(/^(.*)\[(\d+)\]$/);
109
+
86
110
  if (arrIdxMatch) {
87
111
  const base = arrIdxMatch[1];
88
112
  const idxStr = arrIdxMatch[2];
89
- if (base === undefined || idxStr === undefined) continue;
113
+
114
+ if (base === undefined || idxStr === undefined) {
115
+ continue;
116
+ }
117
+
90
118
  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) {
119
+
120
+ if (!cursor[base] || !Array.isArray(cursor[base])) {
121
+ cursor[base] = [];
122
+ }
123
+
124
+ while (cursor[base].length <= idx) {
125
+ cursor[base].push(undefined);
126
+ }
127
+
128
+ if (index === segments.length - 1) {
95
129
  cursor[base][idx] = value;
96
130
  } else {
97
- if (!cursor[base][idx]) cursor[base][idx] = {};
131
+ if (!cursor[base][idx]) {
132
+ cursor[base][idx] = {};
133
+ }
98
134
  cursor = cursor[base][idx];
99
135
  }
100
136
  } else {
101
- if (i === segments.length - 1) {
102
- cursor[seg] = value;
137
+ if (index === segments.length - 1) {
138
+ cursor[segment] = value;
103
139
  } else {
104
- if (!cursor[seg] || typeof cursor[seg] !== 'object') cursor[seg] = {};
105
- cursor = cursor[seg];
140
+ if (!cursor[segment] || typeof cursor[segment] !== 'object') {
141
+ cursor[segment] = {};
142
+ }
143
+ cursor = cursor[segment];
106
144
  }
107
145
  }
108
146
  }
109
147
  }
148
+
110
149
  const identity = root.identity;
111
- // const resourceTypeHandle = root.resourceTypeHandle; // we already have this
112
150
  const resourceRoleHandle = root.creationContext.resourceRoleHandle;
113
151
  const jobStepHandle = root.creationContext.jobStepHandle;
114
152
  const resourceShellKind = root.resourceShellKind;
@@ -116,7 +154,7 @@ export async function listResources(
116
154
  const version = typeof versionRaw === 'number'
117
155
  ? versionRaw
118
156
  : parseInt(String(versionRaw ?? ''), 10);
119
- const path = root.path;
157
+ const resourcePath = root.path;
120
158
  const timestamp = root.timestamp;
121
159
 
122
160
  const missing = [
@@ -126,11 +164,11 @@ export async function listResources(
126
164
  ['resourceShellKind', resourceShellKind],
127
165
  ['version', Number.isFinite(version) ? String(version) : ''],
128
166
  ['timestamp', timestamp],
129
- ['path', path],
130
- ].filter(([_, v]) => typeof v !== 'string' || (v as string).length === 0) as Array<[string, string | undefined]>;
167
+ ['path', resourcePath],
168
+ ].filter(([_, value]) => typeof value !== 'string' || (value as string).length === 0) as Array<[string, string | undefined]>;
131
169
 
132
170
  if (missing.length) {
133
- const keys = missing.map(([k]) => k).join(', ');
171
+ const keys = missing.map(([key]) => key).join(', ');
134
172
  throw new Error(`Missing required metadata keys [${keys}] for resource file: ${name}`);
135
173
  }
136
174
 
@@ -144,14 +182,14 @@ export async function listResources(
144
182
  resourceShellKind,
145
183
  version,
146
184
  timestamp: timestamp as string,
147
- path: path as string,
185
+ path: resourcePath as string,
148
186
  nucleus: data as any,
149
187
  } as unknown as ResourceJson;
150
188
  });
189
+
151
190
  return [resourceTypeHandle, items] as const;
152
- })
191
+ }),
153
192
  );
154
- return Object.fromEntries(entries) as ResourcesByTypeDict;
155
- }
156
-
157
193
 
194
+ return Object.fromEntries(entries) as ResourcesByTypeDict;
195
+ }
@@ -0,0 +1,39 @@
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
+ function resolveCredential() {
8
+ const jsonString = process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON;
9
+ const envPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;
10
+ const localKeyPath = path.join(process.cwd(), 'gcp-key.json');
11
+
12
+ try {
13
+ if (jsonString) {
14
+ return cert(JSON.parse(jsonString));
15
+ }
16
+
17
+ if (envPath && existsSync(envPath)) {
18
+ return cert(JSON.parse(readFileSync(envPath, 'utf8')));
19
+ }
20
+
21
+ if (existsSync(localKeyPath)) {
22
+ return cert(JSON.parse(readFileSync(localKeyPath, 'utf8')));
23
+ }
24
+ } catch {
25
+ return applicationDefault();
26
+ }
27
+
28
+ return applicationDefault();
29
+ }
30
+
31
+ const app = getApps().length ? getApp() : initializeApp({
32
+ credential: resolveCredential(),
33
+ projectId: 'toolproof-563fe',
34
+ });
35
+
36
+ const dbAdmin = getFirestore(app);
37
+ const storageAdmin = getStorage(app);
38
+
39
+ export { dbAdmin, storageAdmin };
@@ -1,7 +1,7 @@
1
1
  import type {
2
- StepKindJson,
3
- ResourceJson,
4
- ResourceTypeIdentityJson,
2
+ StepKindJson,
3
+ ResourceJson,
4
+ ResourceTypeIdentityJson,
5
5
  } from '@toolproof-core/schema';
6
6
  import { CONSTANTS } from '../artifacts/artifacts.js';
7
7
  import { MAPPINGS } from '../artifacts/artifacts.js';
@@ -20,11 +20,11 @@ export type IdentityStringByIdentityName<K extends IdentityName> = `${(typeof MA
20
20
 
21
21
  export type StepIdentityStringByStepKind<K extends StepKindJson> = `${(typeof MAPPINGS.StepKindToStepIdentityPrefix)[K]}${string}`;
22
22
 
23
- export interface NucleusBaseSmall {
24
- identity: string;
23
+ export interface NucleusBaseSmall<T extends string = string> {
24
+ identity: T;
25
25
  }
26
26
 
27
- export interface NucleusBaseLarge extends NucleusBaseSmall {
27
+ export interface NucleusBaseLarge<T extends string = string> extends NucleusBaseSmall<T> {
28
28
  name: string;
29
29
  description: string;
30
30
  }
@@ -7,8 +7,7 @@ import type {
7
7
  ResourceOutputPotentialJson,
8
8
  ResourceTypeIdentityJson,
9
9
  } from '@toolproof-core/schema';
10
- import { CONSTANTS } from '../artifacts/artifacts.js';
11
-
10
+ import { CONSTANTS } from '../../artifacts/artifacts.js';
12
11
 
13
12
  export function generatePath(resourceTypeHandle: ResourceTypeIdentityJson, identity: ResourceIdentityJson): string {
14
13
  return `${resourceTypeHandle}/${identity}.json`;
@@ -17,10 +16,9 @@ export function generatePath(resourceTypeHandle: ResourceTypeIdentityJson, ident
17
16
  export function createMaterializedFromOutputPotential(
18
17
  outputPotential: ResourceOutputPotentialJson,
19
18
  nucleus: unknown,
20
- timestamp?: string
19
+ timestamp?: string,
21
20
  ): ResourceJson {
22
21
  const { identity, resourceTypeHandle, creationContext } = outputPotential;
23
-
24
22
  const path = generatePath(resourceTypeHandle, identity);
25
23
 
26
24
  return {
@@ -29,7 +27,7 @@ export function createMaterializedFromOutputPotential(
29
27
  creationContext,
30
28
  resourceShellKind: CONSTANTS.Enums.ResourceShellKind.materialized,
31
29
  version: 1,
32
- timestamp: timestamp ?? new Date().toISOString(), // Preserve original timestamp when copying
30
+ timestamp: timestamp ?? new Date().toISOString(),
33
31
  path,
34
32
  nucleus,
35
33
  };
@@ -38,10 +36,9 @@ export function createMaterializedFromOutputPotential(
38
36
  export function createMaterializedFromInputPotential(
39
37
  inputPotential: ResourceInputPotentialJson,
40
38
  nucleus: unknown,
41
- timestamp?: string
39
+ timestamp?: string,
42
40
  ): ResourceJson {
43
41
  const { identity, resourceTypeHandle, creationContext } = inputPotential;
44
-
45
42
  const path = generatePath(resourceTypeHandle, identity);
46
43
 
47
44
  return {
@@ -59,17 +56,18 @@ export function createMaterializedFromInputPotential(
59
56
  export function createMaterializedFromPotential(
60
57
  potential: ResourceInputPotentialJson | ResourceOutputPotentialJson,
61
58
  nucleus: unknown,
62
- timestamp?: string
59
+ timestamp?: string,
63
60
  ): ResourceJson {
64
61
  if (potential.resourceShellKind === CONSTANTS.Enums.ResourceShellKind.inputPotential) {
65
62
  return createMaterializedFromInputPotential(potential, nucleus, timestamp);
66
63
  }
64
+
67
65
  return createMaterializedFromOutputPotential(potential, nucleus, timestamp);
68
66
  }
69
67
 
70
68
  export function createMissing(
71
69
  identity: ResourceIdentityJson,
72
- resourceTypeHandle: ResourceTypeIdentityJson
70
+ resourceTypeHandle: ResourceTypeIdentityJson,
73
71
  ): ResourceMissingJson {
74
72
  return {
75
73
  identity,
@@ -81,7 +79,7 @@ export function createMissing(
81
79
  export function createInputPotential(
82
80
  identity: ResourceIdentityJson,
83
81
  resourceTypeHandle: ResourceTypeIdentityJson,
84
- creationContext: CreationContextJson
82
+ creationContext: CreationContextJson,
85
83
  ): ResourceInputPotentialJson {
86
84
  return {
87
85
  identity,
@@ -94,7 +92,7 @@ export function createInputPotential(
94
92
  export function createOutputPotential(
95
93
  identity: ResourceIdentityJson,
96
94
  resourceTypeHandle: ResourceTypeIdentityJson,
97
- creationContext: CreationContextJson
95
+ creationContext: CreationContextJson,
98
96
  ): ResourceOutputPotentialJson {
99
97
  return {
100
98
  identity,
@@ -0,0 +1,46 @@
1
+ import type {
2
+ RawStrategyJson,
3
+ RunnableStrategyIdentityJson,
4
+ RunnableStrategyJson,
5
+ StepJson,
6
+ StrategyThreadDictJson,
7
+ StrategyThreadIdentityJson,
8
+ } from '@toolproof-core/schema';
9
+ import { CONSTANTS } from '../../artifacts/artifacts.js';
10
+ import { getIndependentThreads } from '../parallelizeSteps.js';
11
+
12
+ export function getRunnableStrategyThreadGroups(rawStrategy: RawStrategyJson): StepJson[][] {
13
+ return getIndependentThreads(rawStrategy.steps, rawStrategy.strategyState);
14
+ }
15
+
16
+ export function buildRunnableStrategy(
17
+ rawStrategy: RawStrategyJson,
18
+ runnableStrategyIdentity: RunnableStrategyIdentityJson,
19
+ threadStepGroups: StepJson[][],
20
+ threadIdentities: StrategyThreadIdentityJson[],
21
+ ): RunnableStrategyJson {
22
+ if (threadStepGroups.length !== threadIdentities.length) {
23
+ throw new Error('buildRunnableStrategy requires one thread identity per thread group');
24
+ }
25
+
26
+ const strategyThreadDict: StrategyThreadDictJson = {};
27
+
28
+ for (const [index, group] of threadStepGroups.entries()) {
29
+ const threadIdentity = threadIdentities[index];
30
+
31
+ if (!threadIdentity) {
32
+ throw new Error(`Missing thread identity for thread group index ${index}`);
33
+ }
34
+
35
+ strategyThreadDict[threadIdentity] = group;
36
+ }
37
+
38
+ return {
39
+ identity: runnableStrategyIdentity,
40
+ runnableStrategyContext: {
41
+ status: CONSTANTS.Enums.RunnableStrategyStatus.pending,
42
+ },
43
+ strategyThreadDict,
44
+ strategyState: rawStrategy.strategyState,
45
+ };
46
+ }