@toolproof-core/lib 1.0.1 → 1.0.3

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 (55) hide show
  1. package/dist/_lib/setup/firebaseAdminInit.d.ts.map +1 -0
  2. package/dist/_lib/setup/firebaseAdminInit.js.map +1 -0
  3. package/dist/artifacts/artifacts.d.ts +174 -0
  4. package/dist/artifacts/artifacts.d.ts.map +1 -0
  5. package/dist/{declarations/constants.js → artifacts/artifacts.js} +12 -11
  6. package/dist/artifacts/artifacts.js.map +1 -0
  7. package/dist/firebase/firebaseAdminHelpers.d.ts +4 -31
  8. package/dist/firebase/firebaseAdminHelpers.d.ts.map +1 -1
  9. package/dist/firebase/firebaseAdminHelpers.js +32 -27
  10. package/dist/firebase/firebaseAdminHelpers.js.map +1 -1
  11. package/dist/types/types.d.ts +9 -5
  12. package/dist/types/types.d.ts.map +1 -1
  13. package/dist/types/types.js +2 -1
  14. package/dist/types/types.js.map +1 -1
  15. package/dist/utils/creation.d.ts +4 -0
  16. package/dist/utils/creation.d.ts.map +1 -0
  17. package/dist/utils/creation.js +18 -0
  18. package/dist/utils/creation.js.map +1 -0
  19. package/dist/utils/resourceMapExtraction.d.ts +12 -0
  20. package/dist/utils/resourceMapExtraction.d.ts.map +1 -0
  21. package/dist/utils/resourceMapExtraction.js +23 -0
  22. package/dist/utils/resourceMapExtraction.js.map +1 -0
  23. package/package.json +42 -31
  24. package/src/{firebase → _lib/setup}/firebaseAdminInit.ts +38 -38
  25. package/{dist/constants/constants.js → src/artifacts/artifacts.ts} +14 -12
  26. package/src/firebase/firebaseAdminHelpers.ts +157 -189
  27. package/src/types/types.ts +25 -17
  28. package/src/utils/creation.ts +27 -0
  29. package/src/utils/resourceMapExtraction.ts +47 -0
  30. package/tsconfig.json +14 -14
  31. package/tsconfig.tsbuildinfo +1 -1
  32. package/dist/constants/constants.d.ts +0 -94
  33. package/dist/constants/constants.d.ts.map +0 -1
  34. package/dist/constants/constants.js.map +0 -1
  35. package/dist/declarations/constants.d.ts +0 -94
  36. package/dist/declarations/constants.d.ts.map +0 -1
  37. package/dist/declarations/constants.js.map +0 -1
  38. package/dist/declarations/types.d.ts +0 -10
  39. package/dist/declarations/types.d.ts.map +0 -1
  40. package/dist/declarations/types.js +0 -2
  41. package/dist/declarations/types.js.map +0 -1
  42. package/dist/declarations/typesTS.d.ts +0 -11
  43. package/dist/declarations/typesTS.d.ts.map +0 -1
  44. package/dist/declarations/typesTS.js +0 -2
  45. package/dist/declarations/typesTS.js.map +0 -1
  46. package/dist/firebase/firebaseAdminInit.d.ts.map +0 -1
  47. package/dist/firebase/firebaseAdminInit.js.map +0 -1
  48. package/dist/index.d.ts +0 -4
  49. package/dist/index.d.ts.map +0 -1
  50. package/dist/index.js +0 -4
  51. package/dist/index.js.map +0 -1
  52. package/src/constants/constants.ts +0 -39
  53. package/src/index.ts +0 -3
  54. /package/dist/{firebase → _lib/setup}/firebaseAdminInit.d.ts +0 -0
  55. /package/dist/{firebase → _lib/setup}/firebaseAdminInit.js +0 -0
@@ -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,23 +1,24 @@
1
- import { CONSTANTS as CONSTANTS_ } from "@toolproof-core/schema";
1
+ import { CONSTANTS as _CONSTANTS, MAPPINGS as _MAPPINGS } from "@toolproof-core/schema";
2
+
2
3
  export const CONSTANTS = {
3
- ...CONSTANTS_,
4
- PERSISTENCE: {
5
- BUCKETS: {
4
+ ..._CONSTANTS,
5
+ Persistence: {
6
+ Buckets: {
6
7
  tp_resources: 'tp-resources',
7
8
  tp_strategies: 'tp-strategies',
8
9
  },
9
- COLLECTIONS: {
10
+ Collections: {
10
11
  resources: 'resources',
11
12
  members: 'members',
12
13
  },
13
14
  },
14
- ENGINE: {
15
- GRAPHS: {
15
+ Engine: {
16
+ Graphs: {
16
17
  GraphRunStrategy: 'GraphRunStrategy',
17
18
  GraphBuildStrategy: 'GraphBuildStrategy',
18
19
  },
19
20
  },
20
- COSMOS: {
21
+ Cosmos: {
21
22
  TYPE_Boolean: 'TYPE-Boolean',
22
23
  TYPE_Natural: 'TYPE-Natural',
23
24
  TYPE_ResourceType: 'TYPE-ResourceType',
@@ -32,8 +33,9 @@ export const CONSTANTS = {
32
33
  ROLE_LessThanTarget: 'ROLE-LessThanTarget',
33
34
  ROLE_LessThanDecision: 'ROLE-LessThanDecision',
34
35
  JOB_LessThan: 'JOB-LessThan',
35
- BOOLEAN_false: 'RESOURCE-qadnfFGjZsjpqLI0Du1d',
36
- BOOLEAN_true: 'RESOURCE-iZX1cxZ9ImJRzty9Ob4G',
37
36
  }
38
- };
39
- //# sourceMappingURL=constants.js.map
37
+ } as const;
38
+
39
+ export const MAPPINGS = {
40
+ ..._MAPPINGS,
41
+ } as const;
@@ -1,189 +1,157 @@
1
- import type {
2
- BranchStepIdentityJson,
3
- ForStepIdentityJson,
4
- GoalIdentityJson,
5
- JobIdentityJson,
6
- JobStepIdentityJson,
7
- ResourceJson,
8
- ResourceIdentityJson,
9
- ResourceRoleIdentityJson,
10
- ResourceTypeIdentityJson,
11
- RunnableStrategyIdentityJson,
12
- StrategyRunIdentityJson,
13
- StrategyThreadIdentityJson,
14
- WhileStepIdentityJson,
15
- } from '@toolproof-core/schema';
16
- import type { ResourceMap, IdentityPrefix } from '../types/types.js';
17
- import { CONSTANTS } from '../constants/constants.js';
18
- import { dbAdmin, storageAdmin } from "./firebaseAdminInit.js";
19
-
20
- export type StepKind = keyof typeof CONSTANTS.ENUMS.StepKind;
21
-
22
- const STEP_KIND_TO_IDENTITY_PREFIX_KEY = {
23
- job: 'JobStepIdentity',
24
- branch: 'BranchStepIdentity',
25
- while: 'WhileStepIdentity',
26
- for: 'ForStepIdentity',
27
- } as const;
28
-
29
- type StepIdentityPrefixKey = (typeof STEP_KIND_TO_IDENTITY_PREFIX_KEY)[StepKind];
30
-
31
- type IdentityJsonByPrefixKey = {
32
- ResourceTypeIdentity: ResourceTypeIdentityJson;
33
- ResourceRoleIdentity: ResourceRoleIdentityJson;
34
- ResourceIdentity: ResourceIdentityJson;
35
- JobIdentity: JobIdentityJson;
36
- JobStepIdentity: JobStepIdentityJson;
37
- BranchStepIdentity: BranchStepIdentityJson;
38
- WhileStepIdentity: WhileStepIdentityJson;
39
- ForStepIdentity: ForStepIdentityJson;
40
- StrategyThreadIdentity: StrategyThreadIdentityJson;
41
- RunnableStrategyIdentity: RunnableStrategyIdentityJson;
42
- StrategyRunIdentity: StrategyRunIdentityJson;
43
- GoalIdentity: GoalIdentityJson;
44
- };
45
-
46
- export type NewIdentity<T extends IdentityPrefix = IdentityPrefix> =
47
- T extends keyof IdentityJsonByPrefixKey
48
- ? IdentityJsonByPrefixKey[T]
49
- : `${(typeof CONSTANTS.IDENTIFIABLES.PREFIXES)[T]}${string}`;
50
-
51
- export function getNewIdentity<T extends IdentityPrefix>(identifiable: T): NewIdentity<T> {
52
- const prefix = CONSTANTS.IDENTIFIABLES.PREFIXES[identifiable];
53
- const docRef = dbAdmin
54
- .collection(CONSTANTS.PERSISTENCE.COLLECTIONS.resources)
55
- .doc(identifiable)
56
- .collection(CONSTANTS.PERSISTENCE.COLLECTIONS.members)
57
- .doc();
58
- return (prefix + docRef.id) as NewIdentity<T>;
59
- }
60
-
61
- export function getNewStepIdentityPrefix<K extends StepKind>(kind: K): (typeof CONSTANTS.IDENTIFIABLES.PREFIXES)[StepIdentityPrefixKey] {
62
- const key = STEP_KIND_TO_IDENTITY_PREFIX_KEY[kind];
63
- return CONSTANTS.IDENTIFIABLES.PREFIXES[key];
64
- }
65
-
66
- type StepIdentityForKind<K extends StepKind> = IdentityJsonByPrefixKey[(typeof STEP_KIND_TO_IDENTITY_PREFIX_KEY)[K]];
67
-
68
- export async function getNewStepIdentity<K extends StepKind>(kind: K): Promise<StepIdentityForKind<K>> {
69
- const key = STEP_KIND_TO_IDENTITY_PREFIX_KEY[kind];
70
- return getNewIdentity(key) as StepIdentityForKind<K>;
71
- }
72
-
73
- export async function listResources(
74
- resourceTypeHandles: ResourceTypeIdentityJson[]
75
- ): Promise<ResourceMap> {
76
- const bucket_resources = storageAdmin.bucket(CONSTANTS.PERSISTENCE.BUCKETS.tp_resources);
77
- const bucket_strategies = storageAdmin.bucket(CONSTANTS.PERSISTENCE.BUCKETS.tp_strategies);
78
-
79
- async function fetchFilesUnder(resourceTypeHandle: ResourceTypeIdentityJson): Promise<Array<{ data: unknown; meta: any; name: string }>> {
80
- const bucket = resourceTypeHandle === CONSTANTS.COSMOS.TYPE_RunnableStrategy
81
- ? bucket_strategies
82
- : bucket_resources;
83
- const prefix = `${resourceTypeHandle}/`;
84
- const [found] = await bucket.getFiles({ prefix });
85
- const files = found.filter(f => {
86
- const name = f.name || '';
87
- if (!name || name.endsWith('/')) return false;
88
- return true;
89
- });
90
- if (!files.length) return [];
91
- const items = await Promise.all(files.map(async (file) => {
92
- try {
93
- const [buf] = await file.download();
94
- const meta = file.metadata || (await file.getMetadata())[0];
95
- const data = JSON.parse(buf.toString('utf8')) as unknown;
96
- return { data, meta, name: file.name };
97
- } catch {
98
- return null as unknown as { data: unknown; meta: any; name: string };
99
- }
100
- }));
101
- return items.filter(Boolean) as Array<{ data: unknown; meta: any; name: string }>;
102
- }
103
-
104
- const entries = await Promise.all(
105
- resourceTypeHandles.map(async (resourceTypeHandle) => {
106
- const rows = await fetchFilesUnder(resourceTypeHandle);
107
- const items: ResourceJson[] = rows.map(({ data, meta, name }) => {
108
- const flat = meta?.metadata ?? {};
109
- // Reconstruct nested object from flattened keys (dot and array index notation)
110
- const root: any = {};
111
- for (const [k, vRaw] of Object.entries(flat)) {
112
- if (typeof vRaw !== 'string') continue; // GCS should store only strings
113
- const vStr = vRaw.trim();
114
- // Attempt JSON parse for non-simple primitives
115
- let value: any = vStr;
116
- if ((vStr.startsWith('{') && vStr.endsWith('}')) || (vStr.startsWith('[') && vStr.endsWith(']'))) {
117
- try { value = JSON.parse(vStr); } catch { value = vStr; }
118
- }
119
- // Split by '.' while preserving array indices
120
- const segments = k.split('.');
121
- let cursor = root;
122
- for (const [i, seg] of segments.entries()) {
123
- const arrIdxMatch = seg.match(/^(.*)\[(\d+)\]$/);
124
- if (arrIdxMatch) {
125
- const base = arrIdxMatch[1];
126
- const idxStr = arrIdxMatch[2];
127
- if (base === undefined || idxStr === undefined) continue;
128
- const idx = parseInt(idxStr, 10);
129
- if (!cursor[base]) cursor[base] = [];
130
- if (!Array.isArray(cursor[base])) cursor[base] = [];
131
- while (cursor[base].length <= idx) cursor[base].push(undefined);
132
- if (i === segments.length - 1) {
133
- cursor[base][idx] = value;
134
- } else {
135
- if (!cursor[base][idx]) cursor[base][idx] = {};
136
- cursor = cursor[base][idx];
137
- }
138
- } else {
139
- if (i === segments.length - 1) {
140
- cursor[seg] = value;
141
- } else {
142
- if (!cursor[seg] || typeof cursor[seg] !== 'object') cursor[seg] = {};
143
- cursor = cursor[seg];
144
- }
145
- }
146
- }
147
- }
148
- const identity = root.identity;
149
- // const resourceTypeHandle = root.resourceTypeHandle; // we already have this
150
- const resourceRoleHandle = root.creationContext.resourceRoleHandle;
151
- const jobStepHandle = root.creationContext.jobStepHandle;
152
- const stepKind = root.stepKind;
153
- const path = root.path;
154
- const timestamp = root.timestamp;
155
-
156
- const missing = [
157
- ['identity', identity],
158
- ['resourceRoleHandle', resourceRoleHandle],
159
- ['jobStepHandle', jobStepHandle],
160
- ['stepKind', stepKind],
161
- ['timestamp', timestamp],
162
- ['path', path],
163
- ].filter(([_, v]) => typeof v !== 'string' || (v as string).length === 0) as Array<[string, string | undefined]>;
164
-
165
- if (missing.length) {
166
- const keys = missing.map(([k]) => k).join(', ');
167
- throw new Error(`Missing required metadata keys [${keys}] for resource file: ${name}`);
168
- }
169
-
170
- return {
171
- identity,
172
- resourceTypeHandle,
173
- creationContext: {
174
- resourceRoleHandle,
175
- jobStepHandle,
176
- },
177
- stepKind: stepKind as string,
178
- path: path as string,
179
- timestamp: timestamp as string,
180
- nucleus: data as any,
181
- } as unknown as ResourceJson;
182
- });
183
- return [resourceTypeHandle, items] as const;
184
- })
185
- );
186
- return Object.fromEntries(entries) as ResourceMap;
187
- }
188
-
189
-
1
+ import type {
2
+ ResourceJson,
3
+ ResourceTypeIdentityJson,
4
+ StepKindJson,
5
+ } from '@toolproof-core/schema';
6
+ import type { IdentityName, IdentityStringByIdentityName, StepIdentityStringByStepKind, ResourceMap } 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<ResourceMap> {
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 ResourceMap;
155
+ }
156
+
157
+
@@ -1,17 +1,25 @@
1
- import type {
2
- ResourceJson,
3
- ResourceRoleIdentityJson,
4
- ResourceRoleValueJson,
5
- ResourceTypeIdentityJson,
6
- } from '@toolproof-core/schema';
7
- import { CONSTANTS } from '../constants/constants.js';
8
-
9
- export type BucketConst = typeof CONSTANTS.PERSISTENCE.BUCKETS.tp_resources;
10
-
11
- export type CollectionConst = keyof typeof CONSTANTS.PERSISTENCE.COLLECTIONS;
12
-
13
- export type IdentityPrefix = keyof typeof CONSTANTS.IDENTIFIABLES.PREFIXES;
14
-
15
- export type Role = { identity: ResourceRoleIdentityJson } & ResourceRoleValueJson;
16
-
17
- export type ResourceMap = Record<ResourceTypeIdentityJson, ResourceJson[]>;
1
+ import type {
2
+ StepKindJson,
3
+ ResourceJson,
4
+ ResourceRoleIdentityJson,
5
+ ResourceRoleValueJson,
6
+ ResourceTypeIdentityJson,
7
+ } from '@toolproof-core/schema';
8
+ import { CONSTANTS } from '../artifacts/artifacts.js';
9
+ import { MAPPINGS } from '../artifacts/artifacts.js';
10
+
11
+ export type Bucket = typeof CONSTANTS.Persistence.Buckets.tp_resources;
12
+
13
+ export type Collection = keyof typeof CONSTANTS.Persistence.Collections;
14
+
15
+ export type SchemaLike = Record<string, unknown>;
16
+
17
+ export type Role = { identity: ResourceRoleIdentityJson } & ResourceRoleValueJson;
18
+
19
+ export type ResourceMap = Record<ResourceTypeIdentityJson, ResourceJson[]>;
20
+
21
+ export type IdentityName = keyof typeof MAPPINGS.IdentityNameToIdentityPrefix;
22
+
23
+ export type IdentityStringByIdentityName<K extends IdentityName> = `${(typeof MAPPINGS.IdentityNameToIdentityPrefix)[K]}${string}`;
24
+
25
+ export type StepIdentityStringByStepKind<K extends StepKindJson> = `${(typeof MAPPINGS.StepKindToStepIdentityPrefix)[K]}${string}`;
@@ -0,0 +1,27 @@
1
+ import type { ResourceIdentityJson, ResourceTypeIdentityJson, ResourceJson, ResourceOutputPotentialJson } from '@toolproof-core/schema';
2
+
3
+
4
+ export function generatePath(resourceTypeHandle: ResourceTypeIdentityJson, identity: ResourceIdentityJson): string {
5
+ return `${resourceTypeHandle}/${identity}.json`;
6
+ }
7
+
8
+ export function fromOutputPotentialToMaterialized(
9
+ outputPotential: ResourceOutputPotentialJson,
10
+ nucleus: unknown,
11
+ timestamp?: string
12
+ ): ResourceJson {
13
+ const { identity, resourceTypeHandle, creationContext } = outputPotential;
14
+
15
+ const path = generatePath(resourceTypeHandle, identity);
16
+
17
+ return {
18
+ identity,
19
+ resourceTypeHandle,
20
+ creationContext,
21
+ resourceShellKind: 'materialized',
22
+ version: 1,
23
+ timestamp: timestamp ?? new Date().toISOString(), // Preserve original timestamp when copying
24
+ path,
25
+ nucleus,
26
+ };
27
+ }
@@ -0,0 +1,47 @@
1
+ import type {
2
+ ResourceIdentityJson,
3
+ ResourceTypeIdentityJson,
4
+ ResourceJson,
5
+ } from '@toolproof-core/schema';
6
+ import type { ResourceMap } from '../types/types.js';
7
+
8
+
9
+ export function extractResourcesByType<TResource extends ResourceJson = ResourceJson>(
10
+ resourceMap: ResourceMap,
11
+ resourceTypeHandle: ResourceTypeIdentityJson
12
+ ): Record<ResourceIdentityJson, TResource> {
13
+ const resources = (resourceMap[resourceTypeHandle] ?? []) as TResource[];
14
+ const result: Record<ResourceIdentityJson, TResource> = {} as Record<ResourceIdentityJson, TResource>;
15
+
16
+ for (const resource of resources) {
17
+ result[resource.identity] = resource;
18
+ }
19
+
20
+ return result;
21
+ }
22
+
23
+ /**
24
+
25
+ */
26
+ export function extractNucleusMap<
27
+ TKey extends string = string,
28
+ TNucleus extends { identity: string | number | boolean } = { identity: string | number | boolean },
29
+ TResource extends ResourceJson = ResourceJson
30
+ >(
31
+ resourceMap: ResourceMap,
32
+ resourceTypeHandle: ResourceTypeIdentityJson,
33
+ ): Map<TKey, TNucleus> {
34
+ const resources = extractResourcesByType<TResource>(resourceMap, resourceTypeHandle);
35
+ const out = new Map<TKey, TNucleus>();
36
+
37
+ for (const resource of Object.values(resources)) {
38
+ const data = (resource as any).nucleus as unknown;
39
+
40
+ const value = data as TNucleus;
41
+ const key = String(value.identity) as TKey;
42
+
43
+ out.set(key, value);
44
+ }
45
+
46
+ return out;
47
+ }
package/tsconfig.json CHANGED
@@ -1,15 +1,15 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "rootDir": "./src",
5
- "outDir": "./dist",
6
- "types": ["node"]
7
- },
8
- "include": [
9
- "src"
10
- ],
11
- "exclude": [
12
- "dist",
13
- "node_modules"
14
- ]
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": "./src",
5
+ "outDir": "./dist",
6
+ "types": ["node"]
7
+ },
8
+ "include": [
9
+ "src"
10
+ ],
11
+ "exclude": [
12
+ "dist",
13
+ "node_modules"
14
+ ]
15
15
  }
@@ -1 +1 @@
1
- {"root":["./src/index.ts","./src/constants/constants.ts","./src/firebase/firebaseadminhelpers.ts","./src/firebase/firebaseadmininit.ts","./src/types/types.ts"],"version":"5.9.3"}
1
+ {"root":["./src/_lib/setup/firebaseAdminInit.ts","./src/artifacts/artifacts.ts","./src/firebase/firebaseAdminHelpers.ts","./src/types/types.ts","./src/utils/creation.ts","./src/utils/resourceMapExtraction.ts"],"version":"5.9.3"}