@toolproof-core/lib 1.0.34 → 1.0.37

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 (114) hide show
  1. package/dist/integrations/firebase/firebaseAdminHelpers.d.ts +3 -10
  2. package/dist/integrations/firebase/firebaseAdminHelpers.js +43 -148
  3. package/dist/integrations/firebase/firebaseAdminInit.d.ts +0 -1
  4. package/dist/integrations/firebase/firebaseAdminInit.js +0 -1
  5. package/dist/lookups/lookups.d.ts +214 -0
  6. package/dist/lookups/lookups.js +33 -0
  7. package/dist/types/types.d.ts +15 -15
  8. package/dist/types/types.js +2 -3
  9. package/dist/utils/cosmosDataExtraction.d.ts +5 -0
  10. package/dist/utils/cosmosDataExtraction.js +15 -0
  11. package/dist/utils/identifierGeneration.d.ts +2 -0
  12. package/dist/utils/identifierGeneration.js +5 -0
  13. package/dist/utils/mutableStrategyOverlay.d.ts +55 -0
  14. package/dist/utils/mutableStrategyOverlay.js +115 -0
  15. package/dist/utils/resourceCreation.d.ts +11 -0
  16. package/dist/utils/resourceCreation.js +32 -0
  17. package/dist/utils/stepCreation.d.ts +9 -0
  18. package/dist/utils/stepCreation.js +79 -0
  19. package/dist/utils/stepParallelization.d.ts +2 -0
  20. package/dist/utils/{parallelizeSteps.js → stepParallelization.js} +40 -55
  21. package/dist/utils/strategyAssembly.d.ts +3 -0
  22. package/dist/utils/strategyAssembly.js +6 -0
  23. package/dist/utils/strategyCanonicalization.d.ts +4 -0
  24. package/dist/utils/strategyCanonicalization.js +215 -0
  25. package/dist/utils/strategyExtraction.d.ts +17 -0
  26. package/dist/utils/strategyExtraction.js +88 -0
  27. package/dist/utils/strategyStateResolution.d.ts +17 -0
  28. package/dist/utils/strategyStateResolution.js +27 -0
  29. package/dist/utils/strategyThreading.d.ts +2 -0
  30. package/dist/utils/strategyThreading.js +10 -0
  31. package/dist/utils/toolStepPaths.d.ts +2 -0
  32. package/dist/utils/toolStepPaths.js +21 -0
  33. package/package.json +43 -23
  34. package/src/integrations/firebase/firebaseAdminHelpers.ts +57 -180
  35. package/src/lookups/lookups.ts +35 -0
  36. package/src/types/types.ts +16 -13
  37. package/src/utils/cosmosDataExtraction.ts +25 -0
  38. package/src/utils/identifierGeneration.ts +12 -0
  39. package/src/utils/mutableStrategyOverlay.ts +286 -0
  40. package/src/utils/resourceCreation.ts +87 -0
  41. package/src/utils/stepCreation.ts +114 -0
  42. package/src/utils/stepParallelization.ts +181 -0
  43. package/src/utils/strategyAssembly.ts +14 -0
  44. package/src/utils/strategyCanonicalization.ts +294 -0
  45. package/src/utils/strategyExtraction.ts +150 -0
  46. package/src/utils/strategyStateResolution.ts +57 -0
  47. package/src/utils/strategyThreading.ts +27 -0
  48. package/src/utils/toolStepPaths.ts +34 -0
  49. package/tsconfig.tsbuildinfo +1 -1
  50. package/dist/artifacts/artifacts.d.ts +0 -175
  51. package/dist/artifacts/artifacts.d.ts.map +0 -1
  52. package/dist/artifacts/artifacts.js +0 -48
  53. package/dist/artifacts/artifacts.js.map +0 -1
  54. package/dist/integrations/firebase/createStep.d.ts +0 -11
  55. package/dist/integrations/firebase/createStep.d.ts.map +0 -1
  56. package/dist/integrations/firebase/createStep.js +0 -43
  57. package/dist/integrations/firebase/createStep.js.map +0 -1
  58. package/dist/integrations/firebase/createThreadedStrategy.d.ts +0 -3
  59. package/dist/integrations/firebase/createThreadedStrategy.d.ts.map +0 -1
  60. package/dist/integrations/firebase/createThreadedStrategy.js +0 -9
  61. package/dist/integrations/firebase/createThreadedStrategy.js.map +0 -1
  62. package/dist/integrations/firebase/firebaseAdminHelpers.d.ts.map +0 -1
  63. package/dist/integrations/firebase/firebaseAdminHelpers.js.map +0 -1
  64. package/dist/integrations/firebase/firebaseAdminInit.d.ts.map +0 -1
  65. package/dist/integrations/firebase/firebaseAdminInit.js.map +0 -1
  66. package/dist/types/types.d.ts.map +0 -1
  67. package/dist/types/types.js.map +0 -1
  68. package/dist/utils/bindInputRoleToResource.d.ts +0 -6
  69. package/dist/utils/bindInputRoleToResource.d.ts.map +0 -1
  70. package/dist/utils/bindInputRoleToResource.js +0 -25
  71. package/dist/utils/bindInputRoleToResource.js.map +0 -1
  72. package/dist/utils/creation/resourceCreation.d.ts +0 -21
  73. package/dist/utils/creation/resourceCreation.d.ts.map +0 -1
  74. package/dist/utils/creation/resourceCreation.js +0 -66
  75. package/dist/utils/creation/resourceCreation.js.map +0 -1
  76. package/dist/utils/creation/stepCreation.d.ts +0 -51
  77. package/dist/utils/creation/stepCreation.d.ts.map +0 -1
  78. package/dist/utils/creation/stepCreation.js +0 -90
  79. package/dist/utils/creation/stepCreation.js.map +0 -1
  80. package/dist/utils/creation/threadedStrategyCreation.d.ts +0 -19
  81. package/dist/utils/creation/threadedStrategyCreation.d.ts.map +0 -1
  82. package/dist/utils/creation/threadedStrategyCreation.js +0 -17
  83. package/dist/utils/creation/threadedStrategyCreation.js.map +0 -1
  84. package/dist/utils/extractData.d.ts +0 -13
  85. package/dist/utils/extractData.d.ts.map +0 -1
  86. package/dist/utils/extractData.js +0 -74
  87. package/dist/utils/extractData.js.map +0 -1
  88. package/dist/utils/parallelizeSteps.d.ts +0 -4
  89. package/dist/utils/parallelizeSteps.d.ts.map +0 -1
  90. package/dist/utils/parallelizeSteps.js.map +0 -1
  91. package/dist/utils/resolveResourceChain.d.ts +0 -19
  92. package/dist/utils/resolveResourceChain.d.ts.map +0 -1
  93. package/dist/utils/resolveResourceChain.js +0 -31
  94. package/dist/utils/resolveResourceChain.js.map +0 -1
  95. package/dist/utils/roleSpec.d.ts +0 -17
  96. package/dist/utils/roleSpec.d.ts.map +0 -1
  97. package/dist/utils/roleSpec.js +0 -58
  98. package/dist/utils/roleSpec.js.map +0 -1
  99. package/dist/utils/strategyState.d.ts +0 -8
  100. package/dist/utils/strategyState.d.ts.map +0 -1
  101. package/dist/utils/strategyState.js +0 -29
  102. package/dist/utils/strategyState.js.map +0 -1
  103. package/src/artifacts/artifacts.ts +0 -49
  104. package/src/integrations/firebase/createStep.ts +0 -71
  105. package/src/integrations/firebase/createThreadedStrategy.ts +0 -19
  106. package/src/utils/bindInputRoleToResource.ts +0 -54
  107. package/src/utils/creation/resourceCreation.ts +0 -121
  108. package/src/utils/creation/stepCreation.ts +0 -165
  109. package/src/utils/creation/threadedStrategyCreation.ts +0 -42
  110. package/src/utils/extractData.ts +0 -129
  111. package/src/utils/parallelizeSteps.ts +0 -187
  112. package/src/utils/resolveResourceChain.ts +0 -52
  113. package/src/utils/roleSpec.ts +0 -84
  114. package/src/utils/strategyState.ts +0 -57
@@ -0,0 +1,88 @@
1
+ import { CONSTANTS } from '../lookups/lookups.js';
2
+ export function getInputRoleSpecEntriesFromTool(tool) {
3
+ return Object.entries(tool.roleSpec.inputRoleValueByName);
4
+ }
5
+ export function getOutputRoleSpecEntriesFromTool(tool) {
6
+ return Object.entries(tool.roleSpec.outputRoleValueByName);
7
+ }
8
+ export function getInputRoleNamesFromTool(tool) {
9
+ return getInputRoleSpecEntriesFromTool(tool).map(([roleName]) => roleName);
10
+ }
11
+ export function getOutputRoleNamesFromTool(tool) {
12
+ return getOutputRoleSpecEntriesFromTool(tool).map(([roleName]) => roleName);
13
+ }
14
+ export function extractResourceTypeHandleFromRoleValue(roleValue) {
15
+ const typeRef = roleValue.typeRef;
16
+ if ('resourceTypeHandle' in typeRef) {
17
+ return typeRef.resourceTypeHandle;
18
+ }
19
+ return null;
20
+ }
21
+ export function extractToolStepsFromStrategy(strategy) {
22
+ const toolSteps = [];
23
+ const visitStep = (step) => {
24
+ switch (step.stepKind) {
25
+ case 'tool': {
26
+ toolSteps.push(step);
27
+ return;
28
+ }
29
+ case 'branch': {
30
+ for (const conditional of step.cases) {
31
+ toolSteps.push(conditional.when, conditional.what);
32
+ }
33
+ return;
34
+ }
35
+ case 'while':
36
+ case 'for': {
37
+ toolSteps.push(step.case.when, step.case.what);
38
+ return;
39
+ }
40
+ default: {
41
+ const _exhaustive = step;
42
+ return _exhaustive;
43
+ }
44
+ }
45
+ };
46
+ for (const threadSteps of strategy.stepsByThreadIndex) {
47
+ for (const step of threadSteps) {
48
+ visitStep(step);
49
+ }
50
+ }
51
+ return toolSteps;
52
+ }
53
+ export function extractToolsFromStrategy(strategy, toolMap) {
54
+ const toolSteps = extractToolStepsFromStrategy(strategy);
55
+ const toolHandles = new Set();
56
+ const tools = [];
57
+ for (const toolStep of toolSteps) {
58
+ toolHandles.add(toolStep.toolHandle);
59
+ }
60
+ for (const toolHandle of toolHandles) {
61
+ const tool = toolMap.get(toolHandle);
62
+ if (!tool) {
63
+ throw new Error(`Tool with handle '${toolHandle}' not found in toolMap.`);
64
+ }
65
+ tools.push(tool);
66
+ }
67
+ return tools;
68
+ }
69
+ function extractRoleSpecByDirectionFromTool(tool) {
70
+ return {
71
+ inputRoleValueByName: new Map(getInputRoleSpecEntriesFromTool(tool)),
72
+ outputRoleValueByName: new Map(getOutputRoleSpecEntriesFromTool(tool)),
73
+ };
74
+ }
75
+ export function extractRoleSpecByDirectionByToolHandleFromStrategy(strategy, toolMap) {
76
+ const roleSpecByDirectionByToolHandle = new Map();
77
+ for (const tool of extractToolsFromStrategy(strategy, toolMap)) {
78
+ roleSpecByDirectionByToolHandle.set(tool.handle, extractRoleSpecByDirectionFromTool(tool));
79
+ }
80
+ return roleSpecByDirectionByToolHandle;
81
+ }
82
+ export function extractSingleBranchableOutputResourceTypeHandle(tool) {
83
+ const outputRoleSpecEntries = getOutputRoleSpecEntriesFromTool(tool).filter(([roleName]) => roleName !== CONSTANTS.Cosmos.ErrorOutputRoleName);
84
+ if (!outputRoleSpecEntries[0] || outputRoleSpecEntries.length !== 1) {
85
+ throw new Error(`Tool ${tool.handle} must have exactly one branchable output resource type to be branchable/loopable`);
86
+ }
87
+ return extractResourceTypeHandleFromRoleValue(outputRoleSpecEntries[0][1]);
88
+ }
@@ -0,0 +1,17 @@
1
+ import type { MutableInputResource, MutableExternalInputPotential, MutableStrategyState, MutableToolStepKey, MutableToolStepRoleAddress } from './mutableStrategyOverlay.js';
2
+ export type ResolveResult<TKey extends string = MutableToolStepKey> = {
3
+ status: 'inputResource';
4
+ entry: MutableInputResource;
5
+ path: MutableToolStepRoleAddress<TKey>[];
6
+ } | {
7
+ status: 'externalInputPotential';
8
+ entry: MutableExternalInputPotential;
9
+ path: MutableToolStepRoleAddress<TKey>[];
10
+ } | {
11
+ status: 'unresolved';
12
+ reason: 'not-found' | 'cycle' | 'depth-exceeded';
13
+ path: MutableToolStepRoleAddress<TKey>[];
14
+ };
15
+ export declare function resolveStrategyStateChain<TKey extends string, TStrategyState extends MutableStrategyState<TKey>>(strategyState: TStrategyState, start: MutableToolStepRoleAddress<TKey>, opts?: {
16
+ maxDepth?: number;
17
+ }): ResolveResult<TKey>;
@@ -0,0 +1,27 @@
1
+ import { getStrategyStateInputEntry } from './mutableStrategyOverlay.js';
2
+ export function resolveStrategyStateChain(strategyState, start, opts) {
3
+ const maxDepth = opts?.maxDepth ?? 50;
4
+ const visited = new Set();
5
+ const path = [];
6
+ let current = start;
7
+ for (let depth = 0; depth <= maxDepth; depth++) {
8
+ path.push(current);
9
+ const visitKey = `${current.toolStepKey}::${current.roleName}`;
10
+ if (visited.has(visitKey)) {
11
+ return { status: 'unresolved', reason: 'cycle', path };
12
+ }
13
+ visited.add(visitKey);
14
+ const entry = getStrategyStateInputEntry(strategyState, current);
15
+ if (!entry) {
16
+ return { status: 'unresolved', reason: 'not-found', path };
17
+ }
18
+ if (entry.strategyStateInputKind === 'inputResource') {
19
+ return { status: 'inputResource', entry, path };
20
+ }
21
+ if (entry.strategyStateInputKind === 'externalInputPotential') {
22
+ return { status: 'externalInputPotential', entry, path };
23
+ }
24
+ current = entry.toolStepRoleAddress;
25
+ }
26
+ return { status: 'unresolved', reason: 'depth-exceeded', path };
27
+ }
@@ -0,0 +1,2 @@
1
+ import type { MutableStrategy, MutableStep, MutableStrategyState, MutableToolStepKey } from './mutableStrategyOverlay.js';
2
+ export declare function toExecutionMutableStrategy<TKey extends string = MutableToolStepKey, TStep extends MutableStep<TKey> = MutableStep<TKey>, TState extends MutableStrategyState<TKey> = MutableStrategyState<TKey>>(mutableStrategy: MutableStrategy<TKey, TStep, TState>): MutableStrategy<TKey, TStep, TState>;
@@ -0,0 +1,10 @@
1
+ import { getIndependentThreads } from './stepParallelization.js';
2
+ import { getAuthoringSteps as getAuthoringThreadSteps } from './mutableStrategyOverlay.js';
3
+ export function toExecutionMutableStrategy(mutableStrategy) {
4
+ const authoringSteps = getAuthoringThreadSteps(mutableStrategy);
5
+ const stepsByThreadIndex = getIndependentThreads(authoringSteps, mutableStrategy.strategyState);
6
+ return {
7
+ ...mutableStrategy,
8
+ stepsByThreadIndex: stepsByThreadIndex,
9
+ };
10
+ }
@@ -0,0 +1,2 @@
1
+ import type { ToolStepPath, ToolStepPathSpec } from '@toolproof-core/genesis';
2
+ export declare function toToolStepPath(spec: ToolStepPathSpec): ToolStepPath;
@@ -0,0 +1,21 @@
1
+ function getToolStepPathSuffix(spec) {
2
+ if (spec.toolStepPathSlot === 'self') {
3
+ return '/self';
4
+ }
5
+ if (spec.toolStepPathSlot === 'cases/when' || spec.toolStepPathSlot === 'cases/what') {
6
+ if (typeof spec.caseIndex !== 'number') {
7
+ throw new Error('Expected caseIndex for branch tool-step path construction');
8
+ }
9
+ return `/cases/${spec.caseIndex}/${spec.toolStepPathSlot === 'cases/when' ? 'when' : 'what'}`;
10
+ }
11
+ if (spec.toolStepPathSlot === 'case/when') {
12
+ return '/case/when';
13
+ }
14
+ if (spec.toolStepPathSlot === 'case/what') {
15
+ return '/case/what';
16
+ }
17
+ throw new Error(`Unsupported tool-step path slot '${String(spec.toolStepPathSlot)}'`);
18
+ }
19
+ export function toToolStepPath(spec) {
20
+ return `/threads/${spec.threadIndex}/steps/${spec.stepIndex}${getToolStepPathSuffix(spec)}`;
21
+ }
package/package.json CHANGED
@@ -1,43 +1,63 @@
1
1
  {
2
2
  "name": "@toolproof-core/lib",
3
- "version": "1.0.34",
3
+ "version": "1.0.37",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "keywords": [],
7
7
  "author": "",
8
8
  "license": "ISC",
9
9
  "exports": {
10
- "./artifacts": {
11
- "types": "./dist/artifacts/artifacts.d.ts",
12
- "import": "./dist/artifacts/artifacts.js"
10
+ "./lookups": {
11
+ "types": "./dist/lookups/lookups.d.ts",
12
+ "import": "./dist/lookups/lookups.js"
13
13
  },
14
14
  "./types": {
15
15
  "types": "./dist/types/types.d.ts",
16
16
  "import": "./dist/types/types.js"
17
17
  },
18
- "./extract-data": {
19
- "types": "./dist/utils/extractData.d.ts",
20
- "import": "./dist/utils/extractData.js"
18
+ "./identifier-generation": {
19
+ "types": "./dist/utils/identifierGeneration.d.ts",
20
+ "import": "./dist/utils/identifierGeneration.js"
21
21
  },
22
- "./create-resource": {
23
- "types": "./dist/utils/creation/resourceCreation.d.ts",
24
- "import": "./dist/utils/creation/resourceCreation.js"
22
+ "./strategy-assembly": {
23
+ "types": "./dist/utils/strategyAssembly.d.ts",
24
+ "import": "./dist/utils/strategyAssembly.js"
25
25
  },
26
- "./create-step": {
27
- "types": "./dist/integrations/firebase/createStep.d.ts",
28
- "import": "./dist/integrations/firebase/createStep.js"
26
+ "./cosmos-data-extraction": {
27
+ "types": "./dist/utils/cosmosDataExtraction.d.ts",
28
+ "import": "./dist/utils/cosmosDataExtraction.js"
29
29
  },
30
- "./create-threaded-strategy": {
31
- "types": "./dist/integrations/firebase/createThreadedStrategy.d.ts",
32
- "import": "./dist/integrations/firebase/createThreadedStrategy.js"
30
+ "./strategy-extraction": {
31
+ "types": "./dist/utils/strategyExtraction.d.ts",
32
+ "import": "./dist/utils/strategyExtraction.js"
33
33
  },
34
- "./resolve-resource-chain": {
35
- "types": "./dist/utils/resolveResourceChain.d.ts",
36
- "import": "./dist/utils/resolveResourceChain.js"
34
+ "./resource-creation": {
35
+ "types": "./dist/utils/resourceCreation.d.ts",
36
+ "import": "./dist/utils/resourceCreation.js"
37
37
  },
38
- "./bind-input-role-to-resource": {
39
- "types": "./dist/utils/bindInputRoleToResource.d.ts",
40
- "import": "./dist/utils/bindInputRoleToResource.js"
38
+ "./step-creation": {
39
+ "types": "./dist/utils/stepCreation.d.ts",
40
+ "import": "./dist/utils/stepCreation.js"
41
+ },
42
+ "./tool-step-paths": {
43
+ "types": "./dist/utils/toolStepPaths.d.ts",
44
+ "import": "./dist/utils/toolStepPaths.js"
45
+ },
46
+ "./strategy-state-resolution": {
47
+ "types": "./dist/utils/strategyStateResolution.d.ts",
48
+ "import": "./dist/utils/strategyStateResolution.js"
49
+ },
50
+ "./mutable-strategy-overlay": {
51
+ "types": "./dist/utils/mutableStrategyOverlay.d.ts",
52
+ "import": "./dist/utils/mutableStrategyOverlay.js"
53
+ },
54
+ "./strategy-threading": {
55
+ "types": "./dist/utils/strategyThreading.d.ts",
56
+ "import": "./dist/utils/strategyThreading.js"
57
+ },
58
+ "./strategy-canonicalization": {
59
+ "types": "./dist/utils/strategyCanonicalization.d.ts",
60
+ "import": "./dist/utils/strategyCanonicalization.js"
41
61
  },
42
62
  "./firebase-admin-init": {
43
63
  "types": "./dist/integrations/firebase/firebaseAdminInit.d.ts",
@@ -52,7 +72,7 @@
52
72
  "@types/node": "^22.0.0"
53
73
  },
54
74
  "dependencies": {
55
- "@toolproof-core/schema": "^1.0.46",
75
+ "@toolproof-core/genesis": "^1.0.58",
56
76
  "firebase-admin": "^13.7.0"
57
77
  },
58
78
  "scripts": {
@@ -1,203 +1,80 @@
1
1
  import type {
2
- CreationContext,
3
2
  Resource,
4
- ResourceProvenance,
5
- ResourceTypeId,
6
- StepKind,
7
- } from '@toolproof-core/schema';
3
+ ResourcePointer,
4
+ ResourceTypeHandle,
5
+ TimestampedResource,
6
+ } from '@toolproof-core/genesis';
8
7
  import type {
9
- IdName,
10
- IdStringByIdName,
11
8
  ResourcesByType,
12
9
  } from '../../types/types.js';
13
- import { CONSTANTS, MAPPINGS } from '../../artifacts/artifacts.js';
10
+ import { CONSTANTS } from '../../lookups/lookups.js';
14
11
  import { dbAdmin, storageAdmin } from './firebaseAdminInit.js';
15
12
 
16
- type StepIdStringByStepKind<K extends StepKind> = string & { readonly __stepKind?: K };
17
-
18
- function capitalizeFirst(value: string): string {
19
- if (!value) {
20
- return value;
21
- }
22
-
23
- return value.charAt(0).toUpperCase() + value.slice(1);
24
- }
25
-
26
- export function getNewId<K extends IdName>(idName: K): IdStringByIdName<K> {
27
- const prefix = MAPPINGS.IdNameToIdPrefix[idName];
28
- const docRef = dbAdmin
29
- .collection(CONSTANTS.Persistence.Collections.resources)
30
- .doc(idName)
31
- .collection(CONSTANTS.Persistence.Collections.members)
32
- .doc();
33
-
34
- return (prefix + docRef.id) as IdStringByIdName<K>;
35
- }
36
-
37
- export function getNewStepId<K extends StepKind>(stepKind: K): StepIdStringByStepKind<K> {
38
- const idName = `${capitalizeFirst(stepKind)}StepId` as IdName;
39
-
40
- if (!(idName in MAPPINGS.IdNameToIdPrefix)) {
41
- throw new Error(`No IdNameToIdPrefix entry for derived step id name: ${idName}`);
42
- }
43
-
44
- return getNewId(idName) as StepIdStringByStepKind<K>;
45
- }
46
13
 
47
14
  export async function listResources(
48
- resourceTypeIds: ResourceTypeId[],
15
+ resourceTypeHandles: ResourceTypeHandle[],
49
16
  ): Promise<ResourcesByType> {
50
- const bucketResources = storageAdmin.bucket(CONSTANTS.Persistence.Buckets.tp_resources);
51
- const bucketStrategies = storageAdmin.bucket(CONSTANTS.Persistence.Buckets.tp_strategies);
17
+ const resourcesBucket = storageAdmin.bucket(CONSTANTS.Persistence.Buckets.tp_resources);
18
+ const strategiesBucket = storageAdmin.bucket(CONSTANTS.Persistence.Buckets.tp_strategies);
19
+
20
+ async function fetchTimestampedMetadataUnder(
21
+ resourceTypeHandle: ResourceTypeHandle,
22
+ ): Promise<ResourcePointer[]> {
23
+ const snapshot = await dbAdmin
24
+ .collection(CONSTANTS.Persistence.Collections.resources)
25
+ .doc(resourceTypeHandle)
26
+ .collection(CONSTANTS.Persistence.Collections.members)
27
+ .get();
28
+
29
+ return snapshot.docs.map((doc) => {
30
+ const data = doc.data() as Partial<TimestampedResource>;
31
+ if (
32
+ typeof data.id !== 'string' ||
33
+ typeof data.resourceTypeHandle !== 'string' ||
34
+ !data.provenance ||
35
+ typeof data.provenance !== 'object' ||
36
+ typeof data.provenance.provenanceKind !== 'string'
37
+ ) {
38
+ throw new Error(`Invalid TimestampedResource document for ${resourceTypeHandle}/${doc.id}`);
39
+ }
52
40
 
53
- async function fetchFilesUnder(
54
- resourceTypeId: ResourceTypeId,
55
- ): Promise<Array<{ data: unknown; meta: any; name: string }>> {
56
- const bucket = resourceTypeId === CONSTANTS.Cosmos.TYPE_ThreadedStrategy
57
- ? bucketStrategies
58
- : bucketResources;
59
- const prefix = `${resourceTypeId}/`;
60
- const [found] = await bucket.getFiles({ prefix });
61
- const files = found.filter((file) => {
62
- const name = file.name || '';
63
- return !!name && !name.endsWith('/');
41
+ return {
42
+ id: data.id,
43
+ resourceTypeHandle: data.resourceTypeHandle,
44
+ provenance: data.provenance,
45
+ } as ResourcePointer;
64
46
  });
47
+ }
65
48
 
66
- if (!files.length) {
67
- return [];
49
+ async function fetchProjection(
50
+ resourceTypeHandle: ResourceTypeHandle,
51
+ resourceId: ResourcePointer['id'],
52
+ ): Promise<unknown> {
53
+ const bucket = resourceTypeHandle === CONSTANTS.Handles.ResourceTypes.TYPE_Strategy
54
+ ? strategiesBucket
55
+ : resourcesBucket;
56
+ const file = bucket.file(`${resourceTypeHandle}/${resourceId}`);
57
+ const [exists] = await file.exists();
58
+ if (!exists) {
59
+ throw new Error(`Missing projection blob for ${resourceTypeHandle}/${resourceId}`);
68
60
  }
69
61
 
70
- const items = await Promise.all(files.map(async (file) => {
71
- try {
72
- const [buf] = await file.download();
73
- const meta = file.metadata || (await file.getMetadata())[0];
74
- const data = JSON.parse(buf.toString('utf8')) as unknown;
75
- return { data, meta, name: file.name };
76
- } catch {
77
- return null as unknown as { data: unknown; meta: any; name: string };
78
- }
79
- }));
80
-
81
- return items.filter(Boolean) as Array<{ data: unknown; meta: any; name: string }>;
62
+ const [buf] = await file.download();
63
+ return JSON.parse(buf.toString('utf8')) as unknown;
82
64
  }
83
65
 
84
66
  const entries = await Promise.all(
85
- resourceTypeIds.map(async (resourceTypeId) => {
86
- const rows = await fetchFilesUnder(resourceTypeId);
87
- const items: Resource[] = rows.map(({ data, meta, name }) => {
88
- const flat = meta?.metadata ?? {};
89
- const root: any = {};
90
-
91
- for (const [key, valueRaw] of Object.entries(flat)) {
92
- if (typeof valueRaw !== 'string') {
93
- continue;
94
- }
95
-
96
- const valueString = valueRaw.trim();
97
- let value: any = valueString;
98
-
99
- if ((valueString.startsWith('{') && valueString.endsWith('}')) || (valueString.startsWith('[') && valueString.endsWith(']'))) {
100
- try {
101
- value = JSON.parse(valueString);
102
- } catch {
103
- value = valueString;
104
- }
105
- }
106
-
107
- const segments = key.split('.');
108
- let cursor = root;
109
-
110
- for (const [index, segment] of segments.entries()) {
111
- const arrIdxMatch = segment.match(/^(.*)\[(\d+)\]$/);
112
-
113
- if (arrIdxMatch) {
114
- const base = arrIdxMatch[1];
115
- const idxStr = arrIdxMatch[2];
116
-
117
- if (base === undefined || idxStr === undefined) {
118
- continue;
119
- }
120
-
121
- const idx = parseInt(idxStr, 10);
122
-
123
- if (!cursor[base] || !Array.isArray(cursor[base])) {
124
- cursor[base] = [];
125
- }
126
-
127
- while (cursor[base].length <= idx) {
128
- cursor[base].push(undefined);
129
- }
130
-
131
- if (index === segments.length - 1) {
132
- cursor[base][idx] = value;
133
- } else {
134
- if (!cursor[base][idx]) {
135
- cursor[base][idx] = {};
136
- }
137
- cursor = cursor[base][idx];
138
- }
139
- } else {
140
- if (index === segments.length - 1) {
141
- cursor[segment] = value;
142
- } else {
143
- if (!cursor[segment] || typeof cursor[segment] !== 'object') {
144
- cursor[segment] = {};
145
- }
146
- cursor = cursor[segment];
147
- }
148
- }
149
- }
150
- }
151
-
152
- const id = root.id;
153
- const provenance = root.provenance as ResourceProvenance | undefined;
154
- const versionRaw = root.version;
155
- const version = typeof versionRaw === 'number'
156
- ? versionRaw
157
- : parseInt(String(versionRaw ?? ''), 10);
158
- const resourcePath = root.path;
159
- const timestamp = root.timestamp;
160
-
161
- const missing = [
162
- ['id', id],
163
- ['version', Number.isFinite(version) ? String(version) : ''],
164
- ['timestamp', timestamp],
165
- ['path', resourcePath],
166
- ].filter(([_, value]) => typeof value !== 'string' || (value as string).length === 0) as Array<[string, string | undefined]>;
167
-
168
- if (missing.length) {
169
- const keys = missing.map(([key]) => key).join(', ');
170
- throw new Error(`Missing required metadata keys [${keys}] for resource file: ${name}`);
171
- }
172
-
173
- if (!provenance || typeof provenance !== 'object' || typeof provenance.resourceProvenanceKind !== 'string') {
174
- throw new Error(`Missing required metadata key [provenance] for resource file: ${name}`);
175
- }
176
-
177
- if (provenance.resourceProvenanceKind === 'strategy') {
178
- const creationContext = (provenance as { creationContext?: CreationContext }).creationContext;
179
- if (
180
- !creationContext ||
181
- typeof creationContext !== 'object' ||
182
- typeof creationContext.roleName !== 'string' ||
183
- typeof creationContext.toolStepPath !== 'string'
184
- ) {
185
- throw new Error(`Missing required strategy provenance creationContext for resource file: ${name}`);
186
- }
187
- }
188
-
67
+ resourceTypeHandles.map(async (resourceTypeHandle) => {
68
+ const pointers = await fetchTimestampedMetadataUnder(resourceTypeHandle);
69
+ const items: Resource[] = await Promise.all(pointers.map(async (resourcePointer) => {
70
+ const projection = await fetchProjection(resourceTypeHandle, resourcePointer.id);
189
71
  return {
190
- id,
191
- resourceTypeId,
192
- provenance,
193
- version,
194
- timestamp: timestamp as string,
195
- path: resourcePath as string,
196
- nucleus: data as any,
197
- } as unknown as Resource;
198
- });
72
+ ...resourcePointer,
73
+ projection,
74
+ };
75
+ }));
199
76
 
200
- return [resourceTypeId, items] as const;
77
+ return [resourceTypeHandle, items] as const;
201
78
  }),
202
79
  );
203
80
 
@@ -0,0 +1,35 @@
1
+ import { CONSTANTS as _CONSTANTS, MAPPINGS as _MAPPINGS } from '@toolproof-core/genesis';
2
+
3
+ export const CONSTANTS = {
4
+ ..._CONSTANTS,
5
+ Persistence: {
6
+ Buckets: {
7
+ tp_resources: 'tp-resources' as const,
8
+ tp_strategies: 'tp-strategies' as const,
9
+ },
10
+ Collections: {
11
+ resources: 'resources' as const,
12
+ members: 'members' as const,
13
+ },
14
+ },
15
+ Engine: {
16
+ Graphs: {
17
+ GraphRunStrategy: 'GraphRunStrategy' as const,
18
+ GraphBuildStrategy: 'GraphBuildStrategy' as const,
19
+ },
20
+ },
21
+ Cosmos: {
22
+ ErrorOutputRoleName: 'ErrorOutput' as const,
23
+ }
24
+ } as const;
25
+
26
+ export const MAPPINGS = {
27
+ ..._MAPPINGS,
28
+ IdentifierNameToPrefix: {
29
+ ..._MAPPINGS.IdentifierNameToPrefix,
30
+ ToolStepKey: 'TOOL_STEP-',
31
+ BranchStepKey: 'BRANCH_STEP-',
32
+ WhileStepKey: 'WHILE_STEP-',
33
+ ForStepKey: 'FOR_STEP-',
34
+ },
35
+ } as const;
@@ -1,30 +1,33 @@
1
1
  import type {
2
- StepKind,
3
2
  Resource,
4
- ResourceTypeId,
5
- } from '@toolproof-core/schema';
6
- import { CONSTANTS } from '../artifacts/artifacts.js';
7
- import { MAPPINGS } from '../artifacts/artifacts.js';
3
+ ResourceTypeHandle,
4
+ } from '@toolproof-core/genesis/types';
5
+ import { CONSTANTS } from '../lookups/lookups.js';
6
+ import { MAPPINGS } from '../lookups/lookups.js';
8
7
 
9
- export type Bucket = typeof CONSTANTS.Persistence.Buckets.tp_resources;
8
+ export type Bucket = keyof typeof CONSTANTS.Persistence.Buckets;
10
9
 
11
10
  export type Collection = keyof typeof CONSTANTS.Persistence.Collections;
12
11
 
13
12
  export type SchemaLike = Record<string, unknown>;
14
13
 
15
- export type ResourcesByType = Record<ResourceTypeId, Resource[]>;
14
+ export type ResourcesByType = Record<ResourceTypeHandle, Resource[]>;
16
15
 
17
- export type IdName = keyof typeof MAPPINGS.IdNameToIdPrefix;
16
+ export type IdentifierName = keyof typeof MAPPINGS.IdentifierNameToPrefix;
18
17
 
19
- export type IdStringByIdName<K extends IdName> = `${(typeof MAPPINGS.IdNameToIdPrefix)[K]}${string}`;
18
+ export type IdentifierStringByName<K extends IdentifierName> = `${(typeof MAPPINGS.IdentifierNameToPrefix)[K]}${string}`;
20
19
 
21
- export type StepIdStringByStepKind<K extends StepKind> = string & { readonly __stepKind?: K };
20
+ export type ItemKey = string;
22
21
 
23
- export interface NucleusBaseSmall<T extends string = string> {
24
- id: T;
22
+ export type BaseItem = {
23
+ itemKey: ItemKey;
25
24
  }
26
25
 
27
- export interface NucleusBaseLarge<T extends string = string> extends NucleusBaseSmall<T> {
26
+ export type DocumentedBaseItem = BaseItem & { // ATTENTION: reuse ontology concept
28
27
  name: string;
29
28
  description: string;
29
+ }
30
+
31
+ export type Item = DocumentedBaseItem & {
32
+ label: string;
30
33
  }
@@ -0,0 +1,25 @@
1
+ import type { Resource, TimestampedResource } from '@toolproof-core/genesis';
2
+
3
+
4
+ export function timestampedResourceToResource(timestampedResource: TimestampedResource): Resource {
5
+ const { timestamp: _timestamp, ...resource } = timestampedResource;
6
+ return resource;
7
+ }
8
+
9
+ export function extractProjectionMapByHandle<TKey extends string, TProjection extends { handle: TKey }>(
10
+ resources: Resource[] | undefined,
11
+ ): Map<TKey, TProjection> {
12
+ const map = new Map<TKey, TProjection>();
13
+
14
+ for (const resource of resources ?? []) {
15
+ const projection = resource.projection as (TProjection & { handle?: TKey }) | null;
16
+
17
+ if (!projection || typeof projection !== 'object' || !projection.handle) {
18
+ continue;
19
+ }
20
+
21
+ map.set(projection.handle, projection);
22
+ }
23
+
24
+ return map;
25
+ }
@@ -0,0 +1,12 @@
1
+ import type {
2
+ IdentifierName,
3
+ IdentifierStringByName,
4
+ } from '../types/types.js';
5
+ import { MAPPINGS } from '../lookups/lookups.js';
6
+
7
+ export function generateIdentifier<K extends IdentifierName>(identifierName: K): IdentifierStringByName<K> {
8
+ const prefix = MAPPINGS.IdentifierNameToPrefix[identifierName];
9
+
10
+
11
+ return (prefix + crypto.randomUUID()) as IdentifierStringByName<K>;
12
+ }