@highstate/backend 0.9.19 → 0.9.21

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 (42) hide show
  1. package/dist/{chunk-5WVU2AK4.js → chunk-JNUJ4LTX.js} +15 -3
  2. package/dist/chunk-JNUJ4LTX.js.map +1 -0
  3. package/dist/index.js +24 -22
  4. package/dist/index.js.map +1 -1
  5. package/dist/library/package-resolution-worker.js +3 -3
  6. package/dist/library/package-resolution-worker.js.map +1 -1
  7. package/dist/library/worker/main.js.map +1 -1
  8. package/dist/shared/index.js +1 -1
  9. package/package.json +8 -5
  10. package/prisma/project/api-key.prisma +5 -0
  11. package/prisma/project/evaluation.prisma +10 -0
  12. package/prisma/project/instance.prisma +15 -18
  13. package/prisma/project/page.prisma +9 -1
  14. package/prisma/project/secret.prisma +12 -0
  15. package/prisma/project/service-account.prisma +6 -0
  16. package/prisma/project/terminal.prisma +19 -2
  17. package/prisma/project/trigger.prisma +7 -1
  18. package/prisma/project/unlock-method.prisma +14 -0
  19. package/prisma/project/worker.prisma +34 -3
  20. package/src/artifact/index.ts +1 -1
  21. package/src/business/evaluation.ts +0 -1
  22. package/src/business/secret.test.ts +11 -7
  23. package/src/business/secret.ts +4 -13
  24. package/src/library/package-resolution-worker.ts +3 -3
  25. package/src/library/worker/evaluator.ts +3 -3
  26. package/src/lock/memory.ts +1 -1
  27. package/src/orchestrator/operation-context.ts +1 -2
  28. package/src/orchestrator/operation-workset.ts +0 -1
  29. package/src/orchestrator/operation.ts +5 -0
  30. package/src/orchestrator/plan-test-builder.ts +0 -1
  31. package/src/runner/abstractions.ts +7 -0
  32. package/src/runner/artifact-env.ts +0 -1
  33. package/src/runner/local.ts +10 -1
  34. package/src/shared/models/project/api-key.ts +1 -1
  35. package/src/shared/models/project/operation.ts +13 -0
  36. package/src/shared/resolvers/graph-resolver.ts +0 -3
  37. package/src/shared/resolvers/input.ts +8 -1
  38. package/src/terminal/abstractions.ts +1 -1
  39. package/src/terminal/docker.ts +4 -4
  40. package/src/worker/docker.ts +0 -1
  41. package/src/worker/manager.ts +2 -2
  42. package/dist/chunk-5WVU2AK4.js.map +0 -1
@@ -1,7 +1,7 @@
1
- import { workerData, parentPort } from 'node:worker_threads';
2
- import { dirname } from 'node:path';
3
- import { findPackageJSON } from 'node:module';
4
1
  import { realpath } from 'node:fs/promises';
2
+ import { findPackageJSON } from 'node:module';
3
+ import { dirname } from 'node:path';
4
+ import { workerData, parentPort } from 'node:worker_threads';
5
5
  import pino from 'pino';
6
6
 
7
7
  // src/library/package-resolution-worker.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/library/package-resolution-worker.ts"],"names":[],"mappings":";;;;;;;AA8BA,IAAM,EAAE,YAAA,EAAc,QAAA,EAAS,GAAI,UAAA;AAEnC,IAAM,MAAA,GAAS,KAAK,EAAE,IAAA,EAAM,4BAA4B,KAAA,EAAO,QAAA,IAAY,UAAU,CAAA;AAErF,IAAM,UAA2B,EAAC;AAElC,KAAA,MAAW,eAAe,YAAA,EAAc;AACtC,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAAO,eAAA,CAAgB,WAAA,EAAa,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AACzD,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,SAAA,EAAY,WAAW,CAAA,WAAA,CAAa,CAAA;AAAA,IACtD;AAEA,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,IAAA,EAAM,SAAA;AAAA,MACN,WAAA;AAAA,MACA,eAAA,EAAiB,MAAM,QAAA,CAAS,OAAA,CAAQ,IAAI,CAAC;AAAA,KAC9C,CAAA;AAAA,EACH,SAAS,KAAA,EAAO;AACd,IAAA,MAAA,CAAO,KAAA,CAAM,EAAE,KAAA,EAAM,EAAG,kCAAkC,WAAW,CAAA;AAErE,IAAA,IAAI,iBAAiB,KAAA,IAAS,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,WAAW,CAAA,EAAG;AACjE,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,IAAA,EAAM,WAAA;AAAA,QACN;AAAA,OACD,CAAA;AAAA,IACH,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,IAAA,EAAM,OAAA;AAAA,QACN,WAAA;AAAA,QACA,OAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK;AAAA,OAC7D,CAAA;AAAA,IACH;AAAA,EACF;AACF;AAEA,UAAA,EAAY,WAAA,CAAY;AAAA,EACtB,IAAA,EAAM,QAAA;AAAA,EACN;AACF,CAAC,CAAA","file":"package-resolution-worker.js","sourcesContent":["import { parentPort, workerData } from \"node:worker_threads\"\nimport { dirname } from \"node:path\"\nimport { findPackageJSON } from \"node:module\"\nimport { realpath } from \"node:fs/promises\"\nimport pino, { type Level } from \"pino\"\n\nexport type PackageResolutionWorkerData = {\n packageNames: string[]\n logLevel?: Level\n}\n\nexport type PackageResult = { packageName: string } & (\n | {\n type: \"success\"\n packageRootPath: string\n }\n | {\n type: \"not-found\"\n }\n | {\n type: \"error\"\n error: string\n }\n)\n\nexport type PackageResolutionResponse = {\n type: \"result\"\n results: PackageResult[]\n}\n\nconst { packageNames, logLevel } = workerData as PackageResolutionWorkerData\n\nconst logger = pino({ name: \"source-resolution-worker\", level: logLevel ?? \"silent\" })\n\nconst results: PackageResult[] = []\n\nfor (const packageName of packageNames) {\n try {\n const path = findPackageJSON(packageName, import.meta.url)\n if (!path) {\n throw new Error(`Package \"${packageName}\" not found`)\n }\n\n results.push({\n type: \"success\",\n packageName,\n packageRootPath: await realpath(dirname(path)),\n })\n } catch (error) {\n logger.error({ error }, `failed to resolve package \"%s\"`, packageName)\n\n if (error instanceof Error && error.message.includes(\"not found\")) {\n results.push({\n type: \"not-found\",\n packageName,\n })\n } else {\n results.push({\n type: \"error\",\n packageName,\n error: error instanceof Error ? error.message : String(error),\n })\n }\n }\n}\n\nparentPort?.postMessage({\n type: \"result\",\n results,\n})\n"]}
1
+ {"version":3,"sources":["../../src/library/package-resolution-worker.ts"],"names":[],"mappings":";;;;;;;AA8BA,IAAM,EAAE,YAAA,EAAc,QAAA,EAAS,GAAI,UAAA;AAEnC,IAAM,MAAA,GAAS,KAAK,EAAE,IAAA,EAAM,4BAA4B,KAAA,EAAO,QAAA,IAAY,UAAU,CAAA;AAErF,IAAM,UAA2B,EAAC;AAElC,KAAA,MAAW,eAAe,YAAA,EAAc;AACtC,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAAO,eAAA,CAAgB,WAAA,EAAa,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AACzD,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,SAAA,EAAY,WAAW,CAAA,WAAA,CAAa,CAAA;AAAA,IACtD;AAEA,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,IAAA,EAAM,SAAA;AAAA,MACN,WAAA;AAAA,MACA,eAAA,EAAiB,MAAM,QAAA,CAAS,OAAA,CAAQ,IAAI,CAAC;AAAA,KAC9C,CAAA;AAAA,EACH,SAAS,KAAA,EAAO;AACd,IAAA,MAAA,CAAO,KAAA,CAAM,EAAE,KAAA,EAAM,EAAG,kCAAkC,WAAW,CAAA;AAErE,IAAA,IAAI,iBAAiB,KAAA,IAAS,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,WAAW,CAAA,EAAG;AACjE,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,IAAA,EAAM,WAAA;AAAA,QACN;AAAA,OACD,CAAA;AAAA,IACH,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,IAAA,EAAM,OAAA;AAAA,QACN,WAAA;AAAA,QACA,OAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK;AAAA,OAC7D,CAAA;AAAA,IACH;AAAA,EACF;AACF;AAEA,UAAA,EAAY,WAAA,CAAY;AAAA,EACtB,IAAA,EAAM,QAAA;AAAA,EACN;AACF,CAAC,CAAA","file":"package-resolution-worker.js","sourcesContent":["import { realpath } from \"node:fs/promises\"\nimport { findPackageJSON } from \"node:module\"\nimport { dirname } from \"node:path\"\nimport { parentPort, workerData } from \"node:worker_threads\"\nimport pino, { type Level } from \"pino\"\n\nexport type PackageResolutionWorkerData = {\n packageNames: string[]\n logLevel?: Level\n}\n\nexport type PackageResult = { packageName: string } & (\n | {\n type: \"success\"\n packageRootPath: string\n }\n | {\n type: \"not-found\"\n }\n | {\n type: \"error\"\n error: string\n }\n)\n\nexport type PackageResolutionResponse = {\n type: \"result\"\n results: PackageResult[]\n}\n\nconst { packageNames, logLevel } = workerData as PackageResolutionWorkerData\n\nconst logger = pino({ name: \"source-resolution-worker\", level: logLevel ?? \"silent\" })\n\nconst results: PackageResult[] = []\n\nfor (const packageName of packageNames) {\n try {\n const path = findPackageJSON(packageName, import.meta.url)\n if (!path) {\n throw new Error(`Package \"${packageName}\" not found`)\n }\n\n results.push({\n type: \"success\",\n packageName,\n packageRootPath: await realpath(dirname(path)),\n })\n } catch (error) {\n logger.error({ error }, `failed to resolve package \"%s\"`, packageName)\n\n if (error instanceof Error && error.message.includes(\"not found\")) {\n results.push({\n type: \"not-found\",\n packageName,\n })\n } else {\n results.push({\n type: \"error\",\n packageName,\n error: error instanceof Error ? error.message : String(error),\n })\n }\n }\n}\n\nparentPort?.postMessage({\n type: \"result\",\n results,\n})\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/library/worker/evaluator.ts","../../../src/library/worker/loader.lite.ts","../../../src/library/worker/main.ts"],"names":["logger","error","input"],"mappings":"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","file":"main.js","sourcesContent":["import type { Logger } from \"pino\"\nimport type { ProjectEvaluationResult } from \"../abstractions\"\nimport type { ResolvedInstanceInput } from \"../../shared\"\nimport {\n getRuntimeInstances,\n InstanceNameConflictError,\n type Component,\n type InstanceModel,\n} from \"@highstate/contract\"\nimport { errorToString } from \"../../common\"\n\nexport function evaluateProject(\n logger: Logger,\n components: Readonly<Record<string, Component>>,\n allInstances: InstanceModel[],\n resolvedInputs: Record<string, Record<string, ResolvedInstanceInput[]>>,\n): ProjectEvaluationResult {\n const allInstancesMap = new Map(allInstances.map(instance => [instance.id, instance]))\n\n const instanceErrors: Record<string, unknown> = {}\n const topLevelErrors: Record<string, string> = {}\n\n const instanceOutputs = new Map<string, Record<string, unknown>>()\n\n for (const instance of allInstances) {\n try {\n evaluateInstance(instance.id)\n } catch (error) {\n if (error instanceof InstanceNameConflictError) {\n // fail the whole evaluation if there's a name conflict\n return {\n success: false,\n error: error.message,\n }\n }\n }\n }\n\n return {\n success: true,\n\n virtualInstances: getRuntimeInstances()\n .map(instance => instance.instance)\n // only include top-level composite instances and their children\n .filter(instance => instance.kind === \"composite\" || !allInstancesMap.has(instance.id)),\n\n topLevelErrors,\n }\n\n function evaluateInstance(instanceId: InstanceModel[\"id\"]): Record<string, unknown> {\n let outputs = instanceOutputs.get(instanceId)\n if (outputs) {\n return outputs\n }\n\n // do not evaluate instance if it has an error, just rethrow it\n const error = instanceErrors[instanceId]\n if (error) {\n // eslint-disable-next-line @typescript-eslint/only-throw-error\n throw error\n }\n\n const instance = allInstancesMap.get(instanceId)\n if (!instance) {\n throw new Error(`Instance not found: ${instanceId}`)\n }\n\n try {\n outputs = _evaluateInstance(instance)\n\n instanceOutputs.set(instanceId, outputs)\n return outputs\n } catch (error) {\n if (instance.kind === \"composite\" || !allInstancesMap.has(instance.id)) {\n topLevelErrors[instance.id] = errorToString(error)\n }\n\n instanceErrors[instanceId] = error\n throw error\n }\n }\n\n function _evaluateInstance(instance: InstanceModel): Record<string, unknown> {\n const inputs: Record<string, unknown> = {}\n\n logger.debug(\"evaluating instance\", { instanceId: instance.id })\n\n for (const [inputName, input] of Object.entries(resolvedInputs[instance.id] ?? {})) {\n inputs[inputName] = input.map(input => {\n const evaluated = evaluateInstance(input.input.instanceId)\n\n return evaluated[input.input.output]\n })\n }\n\n const component = components[instance.type]\n if (!component) {\n throw new Error(`Component not found: ${instance.type}, required by instance: ${instance.id}`)\n }\n\n return component({\n name: instance.name,\n args: instance.args as Record<string, never>,\n inputs: inputs as Record<string, never>,\n })\n }\n}\n","import type { Logger } from \"pino\"\nimport { type Component, isComponent } from \"@highstate/contract\"\n\nexport async function loadComponents(\n logger: Logger,\n modulePaths: string[],\n): Promise<Readonly<Record<string, Component>>> {\n const modules: Record<string, unknown> = {}\n for (const modulePath of modulePaths) {\n try {\n logger.debug({ modulePath }, \"loading module\")\n modules[modulePath] = await import(modulePath)\n\n logger.debug({ modulePath }, \"module loaded\")\n } catch (err) {\n logger.error({ modulePath, err }, \"module load failed\")\n }\n }\n\n const components: Record<string, Component> = {}\n\n await _loadLibrary(modules, components)\n logger.debug(\"library loaded with %s components\", Object.keys(components).length)\n\n return components\n}\n\nasync function _loadLibrary(value: unknown, components: Record<string, Component>): Promise<void> {\n if (isComponent(value)) {\n components[value.model.type] = value\n return\n }\n\n if (typeof value !== \"object\" || value === null) {\n return\n }\n\n if (\"_zod\" in value) {\n // this is a zod schema, we can skip it\n return\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n await _loadLibrary(item, components)\n }\n\n return\n }\n\n for (const key in value) {\n await _loadLibrary((value as Record<string, unknown>)[key], components)\n }\n}\n","import type { WorkerData } from \"./protocol\"\nimport { parentPort, workerData } from \"node:worker_threads\"\nimport { pino } from \"pino\"\nimport { errorToString } from \"../../common\"\nimport { evaluateProject } from \"./evaluator\"\nimport { loadComponents } from \"./loader.lite\"\n\nconst data = workerData as WorkerData\n\nconst logger = pino({ name: \"library-worker\" })\n\ntry {\n const library = await loadComponents(logger, data.libraryModulePaths)\n const result = evaluateProject(logger, library, data.allInstances, data.resolvedInputs)\n\n parentPort?.postMessage(result)\n} catch (error) {\n logger.error({ error }, \"failed to evaluate project\")\n\n parentPort?.postMessage({\n success: false,\n error: errorToString(error),\n })\n}\n"]}
1
+ {"version":3,"sources":["../../../src/library/worker/evaluator.ts","../../../src/library/worker/loader.lite.ts","../../../src/library/worker/main.ts"],"names":["logger","error","input"],"mappings":";;;;;;AAWO,SAAS,eAAA,CACdA,OAAAA,EACA,UAAA,EACA,YAAA,EACA,cAAA,EACyB;AACzB,EAAA,MAAM,eAAA,GAAkB,IAAI,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,CAAA,QAAA,KAAY,CAAC,QAAA,CAAS,EAAA,EAAI,QAAQ,CAAC,CAAC,CAAA;AAErF,EAAA,MAAM,iBAA0C,EAAC;AACjD,EAAA,MAAM,iBAAyC,EAAC;AAEhD,EAAA,MAAM,eAAA,uBAAsB,GAAA,EAAqC;AAEjE,EAAA,KAAA,MAAW,YAAY,YAAA,EAAc;AACnC,IAAA,IAAI;AACF,MAAA,gBAAA,CAAiB,SAAS,EAAE,CAAA;AAAA,IAC9B,SAAS,KAAA,EAAO;AACd,MAAA,IAAI,iBAAiB,yBAAA,EAA2B;AAE9C,QAAA,OAAO;AAAA,UACL,OAAA,EAAS,KAAA;AAAA,UACT,OAAO,KAAA,CAAM;AAAA,SACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,IAAA;AAAA,IAET,kBAAkB,mBAAA,EAAoB,CACnC,IAAI,CAAA,QAAA,KAAY,QAAA,CAAS,QAAQ,CAAA,CAEjC,MAAA,CAAO,CAAA,QAAA,KAAY,QAAA,CAAS,SAAS,WAAA,IAAe,CAAC,gBAAgB,GAAA,CAAI,QAAA,CAAS,EAAE,CAAC,CAAA;AAAA,IAExF;AAAA,GACF;AAEA,EAAA,SAAS,iBAAiB,UAAA,EAA0D;AAClF,IAAA,IAAI,OAAA,GAAU,eAAA,CAAgB,GAAA,CAAI,UAAU,CAAA;AAC5C,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,OAAO,OAAA;AAAA,IACT;AAGA,IAAA,MAAM,KAAA,GAAQ,eAAe,UAAU,CAAA;AACvC,IAAA,IAAI,KAAA,EAAO;AAET,MAAA,MAAM,KAAA;AAAA,IACR;AAEA,IAAA,MAAM,QAAA,GAAW,eAAA,CAAgB,GAAA,CAAI,UAAU,CAAA;AAC/C,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,oBAAA,EAAuB,UAAU,CAAA,CAAE,CAAA;AAAA,IACrD;AAEA,IAAA,IAAI;AACF,MAAA,OAAA,GAAU,kBAAkB,QAAQ,CAAA;AAEpC,MAAA,eAAA,CAAgB,GAAA,CAAI,YAAY,OAAO,CAAA;AACvC,MAAA,OAAO,OAAA;AAAA,IACT,SAASC,MAAAA,EAAO;AACd,MAAA,IAAI,QAAA,CAAS,SAAS,WAAA,IAAe,CAAC,gBAAgB,GAAA,CAAI,QAAA,CAAS,EAAE,CAAA,EAAG;AACtE,QAAA,cAAA,CAAe,QAAA,CAAS,EAAE,CAAA,GAAI,aAAA,CAAcA,MAAK,CAAA;AAAA,MACnD;AAEA,MAAA,cAAA,CAAe,UAAU,CAAA,GAAIA,MAAAA;AAC7B,MAAA,MAAMA,MAAAA;AAAA,IACR;AAAA,EACF;AAEA,EAAA,SAAS,kBAAkB,QAAA,EAAkD;AAC3E,IAAA,MAAM,SAAkC,EAAC;AAEzC,IAAAD,QAAO,KAAA,CAAM,qBAAA,EAAuB,EAAE,UAAA,EAAY,QAAA,CAAS,IAAI,CAAA;AAE/D,IAAA,KAAA,MAAW,CAAC,SAAA,EAAW,KAAK,CAAA,IAAK,MAAA,CAAO,OAAA,CAAQ,cAAA,CAAe,QAAA,CAAS,EAAE,CAAA,IAAK,EAAE,CAAA,EAAG;AAClF,MAAA,MAAA,CAAO,SAAS,CAAA,GAAI,KAAA,CAAM,GAAA,CAAI,CAAAE,MAAAA,KAAS;AACrC,QAAA,MAAM,SAAA,GAAY,gBAAA,CAAiBA,MAAAA,CAAM,KAAA,CAAM,UAAU,CAAA;AAEzD,QAAA,OAAO,SAAA,CAAUA,MAAAA,CAAM,KAAA,CAAM,MAAM,CAAA;AAAA,MACrC,CAAC,CAAA;AAAA,IACH;AAEA,IAAA,MAAM,SAAA,GAAY,UAAA,CAAW,QAAA,CAAS,IAAI,CAAA;AAC1C,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,MAAM,IAAI,MAAM,CAAA,qBAAA,EAAwB,QAAA,CAAS,IAAI,CAAA,wBAAA,EAA2B,QAAA,CAAS,EAAE,CAAA,CAAE,CAAA;AAAA,IAC/F;AAEA,IAAA,OAAO,SAAA,CAAU;AAAA,MACf,MAAM,QAAA,CAAS,IAAA;AAAA,MACf,MAAM,QAAA,CAAS,IAAA;AAAA,MACf;AAAA,KACD,CAAA;AAAA,EACH;AACF;ACvGA,eAAsB,cAAA,CACpBF,SACA,WAAA,EAC8C;AAC9C,EAAA,MAAM,UAAmC,EAAC;AAC1C,EAAA,KAAA,MAAW,cAAc,WAAA,EAAa;AACpC,IAAA,IAAI;AACF,MAAAA,OAAAA,CAAO,KAAA,CAAM,EAAE,UAAA,IAAc,gBAAgB,CAAA;AAC7C,MAAA,OAAA,CAAQ,UAAU,CAAA,GAAI,MAAM,OAAO,UAAA,CAAA;AAEnC,MAAAA,OAAAA,CAAO,KAAA,CAAM,EAAE,UAAA,IAAc,eAAe,CAAA;AAAA,IAC9C,SAAS,GAAA,EAAK;AACZ,MAAAA,QAAO,KAAA,CAAM,EAAE,UAAA,EAAY,GAAA,IAAO,oBAAoB,CAAA;AAAA,IACxD;AAAA,EACF;AAEA,EAAA,MAAM,aAAwC,EAAC;AAE/C,EAAA,MAAM,YAAA,CAAa,SAAS,UAAU,CAAA;AACtC,EAAAA,QAAO,KAAA,CAAM,mCAAA,EAAqC,OAAO,IAAA,CAAK,UAAU,EAAE,MAAM,CAAA;AAEhF,EAAA,OAAO,UAAA;AACT;AAEA,eAAe,YAAA,CAAa,OAAgB,UAAA,EAAsD;AAChG,EAAA,IAAI,WAAA,CAAY,KAAK,CAAA,EAAG;AACtB,IAAA,UAAA,CAAW,KAAA,CAAM,KAAA,CAAM,IAAI,CAAA,GAAI,KAAA;AAC/B,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,EAAM;AAC/C,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,UAAU,KAAA,EAAO;AAEnB,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAA,MAAM,YAAA,CAAa,MAAM,UAAU,CAAA;AAAA,IACrC;AAEA,IAAA;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,OAAO,KAAA,EAAO;AACvB,IAAA,MAAM,YAAA,CAAc,KAAA,CAAkC,GAAG,CAAA,EAAG,UAAU,CAAA;AAAA,EACxE;AACF;;;AC9CA,IAAM,IAAA,GAAO,UAAA;AAEb,IAAM,MAAA,GAAS,IAAA,CAAK,EAAE,IAAA,EAAM,kBAAkB,CAAA;AAE9C,IAAI;AACF,EAAA,MAAM,OAAA,GAAU,MAAM,cAAA,CAAe,MAAA,EAAQ,KAAK,kBAAkB,CAAA;AACpE,EAAA,MAAM,SAAS,eAAA,CAAgB,MAAA,EAAQ,SAAS,IAAA,CAAK,YAAA,EAAc,KAAK,cAAc,CAAA;AAEtF,EAAA,UAAA,EAAY,YAAY,MAAM,CAAA;AAChC,CAAA,CAAA,OAAS,KAAA,EAAO;AACd,EAAA,MAAA,CAAO,KAAA,CAAM,EAAE,KAAA,EAAM,EAAG,4BAA4B,CAAA;AAEpD,EAAA,UAAA,EAAY,WAAA,CAAY;AAAA,IACtB,OAAA,EAAS,KAAA;AAAA,IACT,KAAA,EAAO,cAAc,KAAK;AAAA,GAC3B,CAAA;AACH","file":"main.js","sourcesContent":["import type { Logger } from \"pino\"\nimport type { ResolvedInstanceInput } from \"../../shared\"\nimport type { ProjectEvaluationResult } from \"../abstractions\"\nimport {\n type Component,\n getRuntimeInstances,\n type InstanceModel,\n InstanceNameConflictError,\n} from \"@highstate/contract\"\nimport { errorToString } from \"../../common\"\n\nexport function evaluateProject(\n logger: Logger,\n components: Readonly<Record<string, Component>>,\n allInstances: InstanceModel[],\n resolvedInputs: Record<string, Record<string, ResolvedInstanceInput[]>>,\n): ProjectEvaluationResult {\n const allInstancesMap = new Map(allInstances.map(instance => [instance.id, instance]))\n\n const instanceErrors: Record<string, unknown> = {}\n const topLevelErrors: Record<string, string> = {}\n\n const instanceOutputs = new Map<string, Record<string, unknown>>()\n\n for (const instance of allInstances) {\n try {\n evaluateInstance(instance.id)\n } catch (error) {\n if (error instanceof InstanceNameConflictError) {\n // fail the whole evaluation if there's a name conflict\n return {\n success: false,\n error: error.message,\n }\n }\n }\n }\n\n return {\n success: true,\n\n virtualInstances: getRuntimeInstances()\n .map(instance => instance.instance)\n // only include top-level composite instances and their children\n .filter(instance => instance.kind === \"composite\" || !allInstancesMap.has(instance.id)),\n\n topLevelErrors,\n }\n\n function evaluateInstance(instanceId: InstanceModel[\"id\"]): Record<string, unknown> {\n let outputs = instanceOutputs.get(instanceId)\n if (outputs) {\n return outputs\n }\n\n // do not evaluate instance if it has an error, just rethrow it\n const error = instanceErrors[instanceId]\n if (error) {\n // eslint-disable-next-line @typescript-eslint/only-throw-error\n throw error\n }\n\n const instance = allInstancesMap.get(instanceId)\n if (!instance) {\n throw new Error(`Instance not found: ${instanceId}`)\n }\n\n try {\n outputs = _evaluateInstance(instance)\n\n instanceOutputs.set(instanceId, outputs)\n return outputs\n } catch (error) {\n if (instance.kind === \"composite\" || !allInstancesMap.has(instance.id)) {\n topLevelErrors[instance.id] = errorToString(error)\n }\n\n instanceErrors[instanceId] = error\n throw error\n }\n }\n\n function _evaluateInstance(instance: InstanceModel): Record<string, unknown> {\n const inputs: Record<string, unknown> = {}\n\n logger.debug(\"evaluating instance\", { instanceId: instance.id })\n\n for (const [inputName, input] of Object.entries(resolvedInputs[instance.id] ?? {})) {\n inputs[inputName] = input.map(input => {\n const evaluated = evaluateInstance(input.input.instanceId)\n\n return evaluated[input.input.output]\n })\n }\n\n const component = components[instance.type]\n if (!component) {\n throw new Error(`Component not found: ${instance.type}, required by instance: ${instance.id}`)\n }\n\n return component({\n name: instance.name,\n args: instance.args as Record<string, never>,\n inputs: inputs as Record<string, never>,\n })\n }\n}\n","import type { Logger } from \"pino\"\nimport { type Component, isComponent } from \"@highstate/contract\"\n\nexport async function loadComponents(\n logger: Logger,\n modulePaths: string[],\n): Promise<Readonly<Record<string, Component>>> {\n const modules: Record<string, unknown> = {}\n for (const modulePath of modulePaths) {\n try {\n logger.debug({ modulePath }, \"loading module\")\n modules[modulePath] = await import(modulePath)\n\n logger.debug({ modulePath }, \"module loaded\")\n } catch (err) {\n logger.error({ modulePath, err }, \"module load failed\")\n }\n }\n\n const components: Record<string, Component> = {}\n\n await _loadLibrary(modules, components)\n logger.debug(\"library loaded with %s components\", Object.keys(components).length)\n\n return components\n}\n\nasync function _loadLibrary(value: unknown, components: Record<string, Component>): Promise<void> {\n if (isComponent(value)) {\n components[value.model.type] = value\n return\n }\n\n if (typeof value !== \"object\" || value === null) {\n return\n }\n\n if (\"_zod\" in value) {\n // this is a zod schema, we can skip it\n return\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n await _loadLibrary(item, components)\n }\n\n return\n }\n\n for (const key in value) {\n await _loadLibrary((value as Record<string, unknown>)[key], components)\n }\n}\n","import type { WorkerData } from \"./protocol\"\nimport { parentPort, workerData } from \"node:worker_threads\"\nimport { pino } from \"pino\"\nimport { errorToString } from \"../../common\"\nimport { evaluateProject } from \"./evaluator\"\nimport { loadComponents } from \"./loader.lite\"\n\nconst data = workerData as WorkerData\n\nconst logger = pino({ name: \"library-worker\" })\n\ntry {\n const library = await loadComponents(logger, data.libraryModulePaths)\n const result = evaluateProject(logger, library, data.allInstances, data.resolvedInputs)\n\n parentPort?.postMessage(result)\n} catch (error) {\n logger.error({ error }, \"failed to evaluate project\")\n\n parentPort?.postMessage({\n success: false,\n error: errorToString(error),\n })\n}\n"]}
@@ -1,4 +1,4 @@
1
- export { AccessError, BackendError, CannotDeleteLastUnlockMethodError, GraphResolver, InputHashResolver, InputResolver, InstanceLockLostError, InstanceLockedError, InstanceNotFoundError, InstanceStateNotFoundError, InvalidInstanceKindError, MAX_WORKER_START_ATTEMPTS, OperationNotFoundError, ProjectLockedError, ProjectNotFoundError, PromiseTracker, SystemSecretNames, ValidationResolver, WorkerVersionNotFoundError, apiKeyMetaSchema, apiKeyOutputSchema, apiKeyQuerySchema, applyLibraryUpdate, artifactOutputSchema, artifactQuerySchema, backendUnlockMethodSchema, codebaseLibrary, codebaseProjectModelStorage, collectionQueryResult, collectionQuerySchema, createAsyncBatcher, databaseProjectModelStorage, diffLibraries, extractDigestFromImage, finalInstanceOperationStatuses, finalOperationStatuses, forSchema, getAllDependents, getMatchedInjectionInstanceInputs, getResolvedHubInputs, getResolvedInjectionInstanceInputs, getResolvedInstanceInputs, getResolvedInstanceOutputs, getWorkerIdentity, globalProjectSpace, hasObjectMeta, hostPulumiBackend, instanceCustomStatusInputSchema, instanceLockEventSchema, instanceLockOutputSchema, instanceStateEventSchema, int32ToBytes, isFinalOperationStatus, isInstanceDeployed, isTransientInstanceOperationStatus, isTransientOperationStatus, isVirtualGhostInstance, librarySpecSchema, operationEventSchema, operationInputSchema, operationMetaSchema, operationOptionsSchema, operationOutputSchema, operationPhaseInstanceSchema, operationPhaseSchema, operationPhaseTypeSchema, operationStatusSchema, operationTypeSchema, pageDetailsOutputSchema, pageOutputSchema, pageQuerySchema, projectInputSchema, projectModelEventSchema, projectModelStorageSpecSchema, projectOutputSchema, projectUnlockStateSchema, projectUnlockSuiteSchema, pulumiBackendSpecSchema, resolverFactories, secretOutputSchema, secretQuerySchema, serviceAccountOutputSchema, serviceAccountQuerySchema, terminalDetailsOutputSchema, terminalOutputSchema, terminalQuerySchema, terminalSessionOutputSchema, terminalStatusSchema, toApiKeyOutput, toPageOutput, toSecretOutput, toTerminalDetailsOutput, toTerminalOutput, toTerminalSessionOutput, toWorkerOutput, toWorkerVersionOutput, triggerOutputSchema, triggerQuerySchema, unlockMethodInputSchema, unlockMethodMetaSchema, unlockMethodOutputSchema, unlockMethodType, waitAll, workerOutputSchema, workerQuerySchema, workerUnitRegistrationEventSchema, workerVersionOutputSchema, workerVersionStatusSchema } from '../chunk-5WVU2AK4.js';
1
+ export { AccessError, BackendError, CannotDeleteLastUnlockMethodError, GraphResolver, InputHashResolver, InputResolver, InstanceLockLostError, InstanceLockedError, InstanceNotFoundError, InstanceStateNotFoundError, InvalidInstanceKindError, MAX_WORKER_START_ATTEMPTS, OperationNotFoundError, ProjectLockedError, ProjectNotFoundError, PromiseTracker, SystemSecretNames, ValidationResolver, WorkerVersionNotFoundError, apiKeyMetaSchema, apiKeyOutputSchema, apiKeyQuerySchema, applyLibraryUpdate, artifactOutputSchema, artifactQuerySchema, backendUnlockMethodSchema, codebaseLibrary, codebaseProjectModelStorage, collectionQueryResult, collectionQuerySchema, createAsyncBatcher, databaseProjectModelStorage, diffLibraries, extractDigestFromImage, finalInstanceOperationStatuses, finalOperationStatuses, forSchema, getAllDependents, getMatchedInjectionInstanceInputs, getResolvedHubInputs, getResolvedInjectionInstanceInputs, getResolvedInstanceInputs, getResolvedInstanceOutputs, getWorkerIdentity, globalProjectSpace, hasObjectMeta, hostPulumiBackend, instanceCustomStatusInputSchema, instanceLockEventSchema, instanceLockOutputSchema, instanceStateEventSchema, int32ToBytes, isFinalOperationStatus, isInstanceDeployed, isTransientInstanceOperationStatus, isTransientOperationStatus, isVirtualGhostInstance, librarySpecSchema, operationEventSchema, operationInputSchema, operationMetaSchema, operationOptionsSchema, operationOutputSchema, operationPhaseInstanceSchema, operationPhaseSchema, operationPhaseTypeSchema, operationStatusSchema, operationTypeSchema, pageDetailsOutputSchema, pageOutputSchema, pageQuerySchema, projectInputSchema, projectModelEventSchema, projectModelStorageSpecSchema, projectOutputSchema, projectUnlockStateSchema, projectUnlockSuiteSchema, pulumiBackendSpecSchema, resolverFactories, secretOutputSchema, secretQuerySchema, serviceAccountOutputSchema, serviceAccountQuerySchema, terminalDetailsOutputSchema, terminalOutputSchema, terminalQuerySchema, terminalSessionOutputSchema, terminalStatusSchema, toApiKeyOutput, toPageOutput, toSecretOutput, toTerminalDetailsOutput, toTerminalOutput, toTerminalSessionOutput, toWorkerOutput, toWorkerVersionOutput, triggerOutputSchema, triggerQuerySchema, unlockMethodInputSchema, unlockMethodMetaSchema, unlockMethodOutputSchema, unlockMethodType, waitAll, workerOutputSchema, workerQuerySchema, workerUnitRegistrationEventSchema, workerVersionOutputSchema, workerVersionStatusSchema } from '../chunk-JNUJ4LTX.js';
2
2
  import '../chunk-I7BWSAN6.js';
3
3
  //# sourceMappingURL=index.js.map
4
4
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@highstate/backend",
3
- "version": "0.9.19",
3
+ "version": "0.9.21",
4
4
  "type": "module",
5
5
  "highstate": {
6
6
  "sourceHash": {
@@ -31,7 +31,9 @@
31
31
  },
32
32
  "scripts": {
33
33
  "build": "highstate build",
34
- "typecheck": "tsc --noEmit --skipLibCheck",
34
+ "typecheck": "tsgo --noEmit --skipLibCheck",
35
+ "biome": "biome check --write --unsafe --error-on-warnings",
36
+ "biome:check": "biome check --error-on-warnings",
35
37
  "test": "vitest --run",
36
38
  "generate:project": "yarn prisma generate --schema prisma/project",
37
39
  "generate:backend": "yarn prisma generate --schema prisma/backend/postgresql && yarn prisma generate --schema prisma/backend/sqlite",
@@ -39,7 +41,7 @@
39
41
  },
40
42
  "dependencies": {
41
43
  "@aws-crypto/crc32": "^5.2.0",
42
- "@highstate/contract": "^0.9.19",
44
+ "@highstate/contract": "^0.9.21",
43
45
  "@msgpack/msgpack": "^3.1.2",
44
46
  "@napi-rs/keyring": "^1.1.8",
45
47
  "@noble/ciphers": "^1.3.0",
@@ -85,6 +87,8 @@
85
87
  }
86
88
  },
87
89
  "devDependencies": {
90
+ "@biomejs/biome": "2.2.0",
91
+ "@typescript/native-preview": "^7.0.0-dev.20250920.1",
88
92
  "classic-level": "^3.0.0",
89
93
  "highstate-cli-bootstrap": "patch:@highstate/cli@npm%3A0.9.16#~/.yarn/patches/@highstate-cli-npm-0.9.16-e03b564691.patch",
90
94
  "pino-pretty": "^13.0.0",
@@ -92,8 +96,7 @@
92
96
  "rollup": "^4.28.1",
93
97
  "ts-markdown-builder": "^0.4.1",
94
98
  "type-fest": "^4.41.0",
95
- "typescript": "^5.7.2",
96
99
  "vitest": "^3.2.4"
97
100
  },
98
- "gitHead": "e77d292335556c6e5b6275acda1a3d1609d786a1"
101
+ "gitHead": "390ff15c0e0076822a682f9d4e19260942a8d6c2"
99
102
  }
@@ -1,3 +1,8 @@
1
+ /// The API key provides authentication tokens for accessing the platform API.
2
+ ///
3
+ /// Each API key impersonates a service account, inheriting its permissions and access scope.
4
+ /// Keys are automatically created for worker versions and can be manually created for
5
+ /// external integrations. The token is a 32-byte random hex string that can be regenerated.
1
6
  model ApiKey {
2
7
  /// The CUIDv2 of the API key.
3
8
  id String @id @default(cuid(2))
@@ -7,6 +7,16 @@ enum InstanceEvaluationStatus {
7
7
  error
8
8
  }
9
9
 
10
+ /// The evaluation state tracks the result of evaluating composite instances to produce virtual instances.
11
+ ///
12
+ /// Composite instances are template components that generate other instances (virtual instances) when evaluated.
13
+ /// The evaluation process executes the composite's create function with resolved inputs to produce a tree
14
+ /// of child instances. These virtual instances exist in the source "virtual" state and can be units
15
+ /// (mapping to Pulumi resources) or other composites (producing more virtual instances recursively).
16
+ ///
17
+ /// Evaluation happens automatically after project unlock and library reloads to keep virtual instances
18
+ /// synchronized with their composite definitions. Evaluation state persists the produced instance model
19
+ /// and tracks success/error status with descriptive messages showing the instance tree or error details.
10
20
  model InstanceEvaluationState {
11
21
  /// The ID of the state of the instance.
12
22
  stateId String @id
@@ -1,28 +1,28 @@
1
1
  enum InstanceStatus {
2
2
  /// The instance is exists in the model (resident or virtual), but not yet deployed or was completely destroyed.
3
3
  ///
4
- /// "attempted", "deployed" and "failed" instances cannot be transitioned back to "undeployed" after
4
+ /// "partial", "deployed" and "failed" instances can be transitioned back to "undeployed" after
5
5
  /// successful "destroy" operation.
6
6
  undeployed
7
7
 
8
- /// The instance was tryied to be initially deployed.
8
+ /// The instance is partially deployed (attempted, but not yet successful).
9
9
  ///
10
10
  /// Normally, this status is very short-lived, and here to indicate that the instance
11
11
  /// cannot be safely deleted from the the model until it will be completely destroyed.
12
- attempted
12
+ partial
13
13
 
14
14
  /// The initial deployment of the instance was successful.
15
15
  ///
16
16
  /// The transition of "deployed -> failed" is not possible, so consequent failed operations
17
17
  /// will not affect this status.
18
18
  ///
19
- /// Like "attempted", that instance cannot be safely deleted from the model until it will be completely destroyed.
19
+ /// Like "partial", that instance cannot be safely deleted from the model until it will be completely destroyed.
20
20
  deployed
21
21
 
22
22
  /// The initial deployment of the instance failed.
23
23
  /// It can still be transitioned to "deployed" by a successful operation
24
24
  ///
25
- /// Like "attempted", that instance cannot be safely deleted from the model until it will be completely destroyed.
25
+ /// Like "partial", that instance cannot be safely deleted from the model until it will be completely destroyed.
26
26
  failed
27
27
  }
28
28
 
@@ -60,21 +60,16 @@ model InstanceState {
60
60
  /// The 32-bit nonce used to invalidate the input hash when secrets are updated.
61
61
  inputHashNonce Int?
62
62
 
63
- /// The status fields produced by the last operation.
64
- ///
65
- /// [InstanceStatusFields]
66
- statusFields Json?
67
-
68
63
  /// The calculated instance CRC32 input hash at the moment of last operation completion.
69
64
  ///
70
65
  /// This hash covers:
71
66
  /// - the instance's configuration (name, args, secret hashes);
72
- /// - tWorkerVersionponent definition hash;
67
+ /// - component definition hash;
73
68
  /// - the unit's source hash (if applicable);
74
69
  /// - the input hashes and output hashes of all input instances.
75
70
  inputHash Int?
76
71
 
77
- /// The CRC32 of the output produced by the instance at the moment of last operation completion.
72
+ /// The CRC32 of the SHA256 of the output produced by the instance at the moment of last operation completion.
78
73
  ///
79
74
  /// Does not depend on anything except the instance's output.
80
75
  outputHash Int?
@@ -96,12 +91,6 @@ model InstanceState {
96
91
  /// [InstanceArtifactIds]
97
92
  exportedArtifactIds Json?
98
93
 
99
- /// The count of Pulumi resources currently managed by this instance.
100
- currentResourceCount Int?
101
-
102
- /// The message describing the current state of the instance.
103
- message String?
104
-
105
94
  /// The snapshot of the instance model at the moment of last non-preview operation start.
106
95
  ///
107
96
  /// Null if the instance was never operated on.
@@ -116,6 +105,14 @@ model InstanceState {
116
105
  /// [InstanceResolvedInputs]
117
106
  resolvedInputs Json?
118
107
 
108
+ /// The count of Pulumi resources currently managed by this instance.
109
+ currentResourceCount Int?
110
+
111
+ /// The status fields produced by the last operation.
112
+ ///
113
+ /// [InstanceStatusFields]
114
+ statusFields Json?
115
+
119
116
  /// The parent instance.
120
117
  parent InstanceState? @relation("InstanceHierarchy", fields: [parentId], references: [id])
121
118
 
@@ -1,3 +1,9 @@
1
+ /// The page provides custom UI content for instances and service accounts.
2
+ ///
3
+ /// Pages can be created by units to display instance-specific information or by service accounts.
4
+ /// The content consists of blocks that support markdown text, QR codes with optional content display,
5
+ /// and file attachments (inline or artifact references). Instance pages are explicitly deleted
6
+ /// when instances are destroyed.
1
7
  model Page {
2
8
  /// The CUIDv2 of the page.
3
9
  id String @id @default(cuid(2))
@@ -17,7 +23,9 @@ model Page {
17
23
  /// The ID of the service account that owns this page.
18
24
  serviceAccountId String?
19
25
 
20
- /// The content of the page managed by the backend.
26
+ /// The content of the page as an array of blocks.
27
+ ///
28
+ /// Supports markdown, QR codes, and file blocks.
21
29
  ///
22
30
  /// [PageContent]
23
31
  content Json
@@ -1,3 +1,15 @@
1
+ /// The secret stores sensitive configuration values for instances, service accounts, and system components.
2
+ ///
3
+ /// Secrets can be instance-owned (for unit configuration), service account-owned, or system-level
4
+ /// (like Pulumi passwords).
5
+ ///
6
+ /// Secrets persist through normal destroy (recreate) operations
7
+ /// and are only deleted when explicitly forgetting instance state with the deleteSecrets flag or when manually deleted.
8
+ ///
9
+ /// Secret updates invalidate instance input hashes via inputHashNonce, triggering re-execution
10
+ /// during operations. But the content of the secrets itself do not contribute to the input hash.
11
+ ///
12
+ /// System secrets like Pulumi passwords are created on-demand and persist for the whole project lifetime.
1
13
  model Secret {
2
14
  /// The CUIDv2 of the secret.
3
15
  id String @id @default(cuid(2))
@@ -1,3 +1,9 @@
1
+ /// The service account represents an identity for non-human actors in the system.
2
+ ///
3
+ /// Service accounts are automatically created for workers and can be manually created
4
+ /// for external integrations. They define the access scope for resources like artifacts,
5
+ /// secrets, terminals, and pages. Multiple API keys can impersonate the same service account,
6
+ /// allowing different authentication tokens to share the same permissions.
1
7
  model ServiceAccount {
2
8
  /// The CUIDv2 of the service account.
3
9
  id String @id @default(cuid(2))
@@ -1,11 +1,20 @@
1
+ /// The terminal status indicates whether a terminal can accept new connections.
1
2
  enum TerminalStatus {
2
3
  /// The terminal is currently active and can create new sessions.
3
4
  active
4
5
 
5
- /// The instance was destroyed and the tertminal is no longer available, but here for historical purposes.
6
+ /// The instance was destroyed and the terminal is no longer available, but here for historical purposes.
6
7
  unavailable
7
8
  }
8
9
 
10
+ /// The terminal provides interactive shell access to infrastructure resources.
11
+ ///
12
+ /// Terminals can be created by units (owned by instances) or by service accounts.
13
+ /// Each terminal maintains a specification for creating containers that power the terminal,
14
+ /// including image, command, environment, and mounted files.
15
+ ///
16
+ /// Instance-owned terminals are marked unavailable when the instance is destroyed, preserving session history.
17
+ /// Service account terminals persist independently.
9
18
  model Terminal {
10
19
  /// The CUIDv2 of the terminal.
11
20
  id String @id @default(cuid(2))
@@ -18,7 +27,9 @@ model Terminal {
18
27
  /// The status of the terminal.
19
28
  status TerminalStatus @default(active)
20
29
 
21
- /// The specification of the terminal managed by the backend.
30
+ /// The specification for creating the container that powers this terminal.
31
+ ///
32
+ /// Includes image, command, working directory, environment variables, and files.
22
33
  ///
23
34
  /// [TerminalSpec]
24
35
  spec Json
@@ -55,6 +66,9 @@ model Terminal {
55
66
  @@unique([stateId, name]) // the name is unique within the instance
56
67
  }
57
68
 
69
+ /// The terminal session represents a single interactive connection to a terminal.
70
+ ///
71
+ /// Each session tracks when it started and finished. All session output is preserved in logs.
58
72
  model TerminalSession {
59
73
  /// The CUIDv2 of the terminal session.
60
74
  id String @id @default(cuid(2))
@@ -75,6 +89,9 @@ model TerminalSession {
75
89
  logs TerminalSessionLog[]
76
90
  }
77
91
 
92
+ /// The terminal session log captures all input and output from a terminal session.
93
+ ///
94
+ /// Logs are stored with ULID identifiers for timestamp ordering.
78
95
  model TerminalSessionLog {
79
96
  /// The ULID of the session log. Also used to extract the timestamp.
80
97
  id String @id
@@ -1,3 +1,9 @@
1
+ /// The trigger defines automated actions that execute in response to specific events.
2
+ ///
3
+ /// Triggers are created by units to perform actions at defined points in the instance lifecycle
4
+ /// or on schedule. The spec field determines the trigger type and behavior - currently supporting
5
+ /// before-destroy triggers, with planned support for additional types like cron scheduling.
6
+ /// Triggers are deleted along with their instance.
1
7
  model Trigger {
2
8
  /// The CUIDv2 of the trigger.
3
9
  id String @id @default(cuid(2))
@@ -13,7 +19,7 @@ model Trigger {
13
19
  /// The name of the trigger within the instance.
14
20
  name String
15
21
 
16
- /// The specification of the trigger describing its behavior and configuration.
22
+ /// The specification of the trigger describing its type and behavior.
17
23
  ///
18
24
  /// [TriggerSpec]
19
25
  spec Json
@@ -1,3 +1,4 @@
1
+ /// The unlock method type determines how users authenticate to decrypt project databases.
1
2
  enum UnlockMethodType {
2
3
  /// The password is used to unlock the project.
3
4
  password
@@ -6,6 +7,19 @@ enum UnlockMethodType {
6
7
  passkey
7
8
  }
8
9
 
10
+ /// The unlock method enables decryption of project databases through user authentication.
11
+ ///
12
+ /// Each project database is encrypted with a master key, which is then encrypted for each
13
+ /// unlock method's recipient using AGE encryption. Users authenticate (password or passkey)
14
+ /// to decrypt their specific AGE identity, which then decrypts the master key.
15
+ ///
16
+ /// Multiple unlock methods can exist per project, allowing different authentication paths
17
+ /// to the same encrypted database. When unlock methods are added/removed, the master key
18
+ /// is re-encrypted for the new set of recipients.
19
+ ///
20
+ /// The encryptedIdentity contains the AGE identity encrypted with the user's authentication
21
+ /// method (password-derived key or WebAuthn), while the recipient is the public key
22
+ /// corresponding to that identity.
9
23
  model UnlockMethod {
10
24
  /// The CUIDv2 of the unlock method.
11
25
  id String @id @default(cuid(2))
@@ -1,8 +1,18 @@
1
+ /// The worker represents a containerized application that extends unit capabilities beyond Pulumi execution.
2
+ ///
3
+ /// Workers enable units to perform runtime operations after Pulumi program completion,
4
+ /// such as attaching custom statuses, monitoring resources, or triggering unit reconfigurations.
5
+ /// Since Pulumi programs cannot affect instances after execution, workers bypass this limitation
6
+ /// by providing persistent runtime behavior.
7
+ ///
8
+ /// The worker identity (fully qualified image name) indicates the same publisher/party and services as natural authentication mechanism.
9
+ /// All versions of a worker share the same service account, meaning they operate over
10
+ /// the same resources and have the same access scope within the platform.
1
11
  model Worker {
2
12
  /// The CUIDv2 of the worker.
3
13
  id String @id @default(cuid(2))
4
14
 
5
- /// The ID of the worker.
15
+ /// The identity of the worker derived from the container image.
6
16
  ///
7
17
  /// This is the fully qualified image name without the tag or digest.
8
18
  /// The format is `{<registry>/}[<namespace>/]<name>`.
@@ -43,6 +53,15 @@ enum WorkerVersionStatus {
43
53
  error
44
54
  }
45
55
 
56
+ /// The worker version represents a specific container image digest of a worker.
57
+ ///
58
+ /// Each version corresponds to an immutable container image identified by its SHA256 digest.
59
+ /// Versions are automatically created when units reference new image digests and deleted
60
+ /// when no longer referenced by any unit registrations.
61
+ ///
62
+ /// Each version has its own API key for isolation, but all versions of a worker
63
+ /// share the same service account and thus the same access scope within the platform.
64
+ /// The runtime starts containers when registrations exist and stops them when removed.
46
65
  model WorkerVersion {
47
66
  /// The CUIDv2 of the worker version.
48
67
  id String @id @default(cuid(2))
@@ -90,11 +109,19 @@ model WorkerVersion {
90
109
  logs WorkerVersionLog[]
91
110
  }
92
111
 
112
+ /// The worker unit registration tracks which unit instances require specific worker versions.
113
+ ///
114
+ /// Units declare worker dependencies through their outputs, creating registrations that
115
+ /// trigger the runtime to start corresponding worker containers. Each registration
116
+ /// includes parameters passed to the worker for unit-specific configuration.
117
+ ///
118
+ /// Registrations are managed during operation execution - created when units declare workers
119
+ /// and removed when units are destroyed. Worker versions without registrations are garbage collected.
93
120
  model WorkerUnitRegistration {
94
121
  /// The ID of the state of the unit instance requesting the registration.
95
122
  stateId String
96
123
 
97
- /// The name of the workor within the instance.
124
+ /// The name of the worker within the instance.
98
125
  name String
99
126
 
100
127
  /// The parameters of the registration passed by the unit.
@@ -120,6 +147,10 @@ model WorkerUnitRegistration {
120
147
  @@id([stateId, name]) // the registration is identified by the instance and name
121
148
  }
122
149
 
150
+ /// The worker version log captures output from running worker containers.
151
+ ///
152
+ /// Logs include both worker-generated output and system messages from the runtime.
153
+ /// The ULID identifier provides timestamp ordering. Logs are deleted with the worker version.
123
154
  model WorkerVersionLog {
124
155
  /// The ULID of the worker log. Also used to extract the timestamp.
125
156
  id String @id @default(ulid())
@@ -129,7 +160,7 @@ model WorkerVersionLog {
129
160
 
130
161
  /// The log content.
131
162
  content String
132
-
163
+
133
164
  /// Whether this log is a system/runtime message (vs worker output).
134
165
  isSystem Boolean @default(false)
135
166
 
@@ -1,3 +1,3 @@
1
+ export * from "../business/artifact"
1
2
  export * from "./abstractions"
2
3
  export * from "./factory"
3
- export * from "../business/artifact"
@@ -164,7 +164,6 @@ export class ProjectEvaluationSubsystem {
164
164
  // 2. convert EvaluatedInstance[] to InstanceEvaluationStateUncheckedCreateInput[]
165
165
  const states: InstanceEvaluationStateUncheckedCreateInput[] = evaluatedInstances.map(ei => {
166
166
  return {
167
- // biome-ignore lint/style/noNonNullAssertion: we ensure this is always set
168
167
  stateId: instanceIdToStateMap.get(ei.instanceId)!.id,
169
168
  status: ei.status,
170
169
  message: ei.message,
@@ -186,7 +186,7 @@ describe("updateInstanceSecrets", () => {
186
186
  )
187
187
 
188
188
  secretTest(
189
- "deletes all secrets when called with empty object",
189
+ "preserves existing secrets when called with empty object",
190
190
  async ({ secretService, projectDatabase, project, createInstanceState, expect }) => {
191
191
  // arrange
192
192
  const instance = await createInstanceState(project.id)
@@ -218,12 +218,12 @@ describe("updateInstanceSecrets", () => {
218
218
  const secrets = await projectDatabase.secret.findMany({
219
219
  where: { stateId: instance.id },
220
220
  })
221
- expect(secrets).toHaveLength(0)
221
+ expect(secrets).toHaveLength(2)
222
222
  },
223
223
  )
224
224
 
225
225
  secretTest(
226
- "handles mixed create, update, and delete operations",
226
+ "handles mixed create and update operations while preserving existing secrets",
227
227
  async ({ secretService, projectDatabase, project, createInstanceState, expect }) => {
228
228
  // arrange
229
229
  const instance = await createInstanceState(project.id)
@@ -241,9 +241,9 @@ describe("updateInstanceSecrets", () => {
241
241
  {
242
242
  id: createId(),
243
243
  stateId: instance.id,
244
- name: "to-delete",
245
- meta: { title: "To Delete" },
246
- content: "delete-me",
244
+ name: "to-preserve",
245
+ meta: { title: "To Preserve" },
246
+ content: "preserve-me",
247
247
  },
248
248
  ],
249
249
  })
@@ -261,7 +261,7 @@ describe("updateInstanceSecrets", () => {
261
261
  where: { stateId: instance.id },
262
262
  orderBy: { name: "asc" },
263
263
  })
264
- expect(secrets).toHaveLength(2)
264
+ expect(secrets).toHaveLength(3)
265
265
 
266
266
  expect(secrets[0].name).toBe("existing-key")
267
267
  expect(secrets[0].content).toBe("updated-value")
@@ -278,6 +278,10 @@ describe("updateInstanceSecrets", () => {
278
278
  description: "Newly generated access token for service authentication",
279
279
  icon: "mdi:shield-key",
280
280
  })
281
+
282
+ expect(secrets[2].name).toBe("to-preserve")
283
+ expect(secrets[2].content).toBe("preserve-me")
284
+ expect(secrets[2].meta).toEqual({ title: "To Preserve" })
281
285
  },
282
286
  )
283
287
 
@@ -3,7 +3,7 @@ import type { DatabaseManager, ProjectTransaction } from "../database"
3
3
  import type { LibraryBackend } from "../library"
4
4
  import type { PubSubManager } from "../pubsub"
5
5
  import { randomBytes } from "node:crypto"
6
- import { isUnitModel, parseInstanceId, type CommonObjectMeta } from "@highstate/contract"
6
+ import { type CommonObjectMeta, isUnitModel, parseInstanceId } from "@highstate/contract"
7
7
  import {
8
8
  InstanceStateNotFoundError,
9
9
  InvalidInstanceKindError,
@@ -26,7 +26,7 @@ export class SecretService {
26
26
  * @param tx The database transaction to use.
27
27
  * @param libraryId The ID of the library containing the component.
28
28
  * @param stateId The ID of the instance state.
29
- * @param secretValues The secrets to create or update. Missing secrets will be deleted.
29
+ * @param secretValues The secrets to create or update. Existing secrets not in this update are preserved.
30
30
  * @returns The list of secret names that were updated or created.
31
31
  */
32
32
  async updateInstanceSecretsCore(
@@ -97,25 +97,16 @@ export class SecretService {
97
97
  })
98
98
  }
99
99
 
100
- // delete secrets that are no longer provided
101
- const providedSecretNames = Object.keys(secretValues)
102
- await tx.secret.deleteMany({
103
- where: {
104
- stateId,
105
- name: { notIn: providedSecretNames },
106
- },
107
- })
108
-
109
100
  return Object.keys(secretValues)
110
101
  }
111
102
 
112
103
  /**
113
- * Updates secrets for a specific instance, handling both creation/updates and deletions.
104
+ * Updates secrets for a specific instance, handling creation and updates.
114
105
  * Only works with unit instances.
115
106
  *
116
107
  * @param projectId The project ID containing the instance.
117
108
  * @param stateId The ID of the instance state.
118
- * @param secretValues The secrets to create or update. Missing secrets will be deleted.
109
+ * @param secretValues The secrets to create or update. Existing secrets not in this update are preserved.
119
110
  */
120
111
  async updateInstanceSecrets(
121
112
  projectId: string,
@@ -1,7 +1,7 @@
1
- import { parentPort, workerData } from "node:worker_threads"
2
- import { dirname } from "node:path"
3
- import { findPackageJSON } from "node:module"
4
1
  import { realpath } from "node:fs/promises"
2
+ import { findPackageJSON } from "node:module"
3
+ import { dirname } from "node:path"
4
+ import { parentPort, workerData } from "node:worker_threads"
5
5
  import pino, { type Level } from "pino"
6
6
 
7
7
  export type PackageResolutionWorkerData = {
@@ -1,11 +1,11 @@
1
1
  import type { Logger } from "pino"
2
- import type { ProjectEvaluationResult } from "../abstractions"
3
2
  import type { ResolvedInstanceInput } from "../../shared"
3
+ import type { ProjectEvaluationResult } from "../abstractions"
4
4
  import {
5
- getRuntimeInstances,
6
- InstanceNameConflictError,
7
5
  type Component,
6
+ getRuntimeInstances,
8
7
  type InstanceModel,
8
+ InstanceNameConflictError,
9
9
  } from "@highstate/contract"
10
10
  import { errorToString } from "../../common"
11
11
 
@@ -1,5 +1,5 @@
1
- import type { LockBackend } from "./abstractions"
2
1
  import type { BetterLock as BetterLockType } from "better-lock/dist/better_lock"
2
+ import type { LockBackend } from "./abstractions"
3
3
  import { BetterLock } from "better-lock"
4
4
 
5
5
  export class MemoryLockBackend implements LockBackend {