@highstate/backend 0.9.15 → 0.9.16

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 (144) hide show
  1. package/dist/chunk-RCB4AFGD.js +159 -0
  2. package/dist/chunk-RCB4AFGD.js.map +1 -0
  3. package/dist/chunk-WHALQHEZ.js +2017 -0
  4. package/dist/chunk-WHALQHEZ.js.map +1 -0
  5. package/dist/highstate.manifest.json +3 -3
  6. package/dist/index.js +6158 -2178
  7. package/dist/index.js.map +1 -1
  8. package/dist/library/worker/main.js +47 -155
  9. package/dist/library/worker/main.js.map +1 -1
  10. package/dist/shared/index.js +159 -41
  11. package/package.json +25 -7
  12. package/src/artifact/abstractions.ts +46 -0
  13. package/src/artifact/encryption.ts +69 -0
  14. package/src/artifact/factory.ts +36 -0
  15. package/src/artifact/index.ts +3 -0
  16. package/src/artifact/local.ts +142 -0
  17. package/src/business/api-key.ts +65 -0
  18. package/src/business/artifact.ts +288 -0
  19. package/src/business/backend-unlock.ts +10 -0
  20. package/src/business/index.ts +9 -0
  21. package/src/business/instance-lock.ts +124 -0
  22. package/src/business/instance-state.ts +292 -0
  23. package/src/business/operation.ts +251 -0
  24. package/src/business/project-unlock.ts +242 -0
  25. package/src/business/secret.ts +187 -0
  26. package/src/business/worker.ts +161 -0
  27. package/src/common/index.ts +2 -1
  28. package/src/common/performance.ts +44 -0
  29. package/src/common/tree.ts +33 -0
  30. package/src/common/utils.ts +40 -1
  31. package/src/config.ts +14 -10
  32. package/src/hotstate/abstractions.ts +48 -0
  33. package/src/hotstate/factory.ts +17 -0
  34. package/src/{secret → hotstate}/index.ts +1 -0
  35. package/src/hotstate/manager.ts +192 -0
  36. package/src/hotstate/memory.ts +100 -0
  37. package/src/hotstate/validation.ts +101 -0
  38. package/src/index.ts +2 -1
  39. package/src/library/abstractions.ts +10 -23
  40. package/src/library/factory.ts +2 -2
  41. package/src/library/local.ts +89 -102
  42. package/src/library/worker/evaluator.ts +9 -42
  43. package/src/library/worker/loader.lite.ts +41 -0
  44. package/src/library/worker/main.ts +14 -65
  45. package/src/library/worker/protocol.ts +8 -24
  46. package/src/lock/abstractions.ts +6 -0
  47. package/src/lock/factory.ts +15 -0
  48. package/src/{workspace → lock}/index.ts +1 -0
  49. package/src/lock/manager.ts +82 -0
  50. package/src/lock/memory.ts +19 -0
  51. package/src/orchestrator/manager.ts +129 -82
  52. package/src/orchestrator/operation-workset.ts +168 -77
  53. package/src/orchestrator/operation.ts +967 -284
  54. package/src/project/abstractions.ts +20 -7
  55. package/src/project/factory.ts +1 -1
  56. package/src/project/index.ts +0 -1
  57. package/src/project/local.ts +73 -17
  58. package/src/project/manager.ts +272 -131
  59. package/src/pubsub/abstractions.ts +13 -0
  60. package/src/pubsub/factory.ts +19 -0
  61. package/src/pubsub/index.ts +3 -0
  62. package/src/pubsub/local.ts +36 -0
  63. package/src/pubsub/manager.ts +100 -0
  64. package/src/pubsub/validation.ts +33 -0
  65. package/src/runner/abstractions.ts +135 -68
  66. package/src/runner/artifact-env.ts +160 -0
  67. package/src/runner/factory.ts +20 -5
  68. package/src/runner/force-abort.ts +117 -0
  69. package/src/runner/local.ts +281 -371
  70. package/src/{common → runner}/pulumi.ts +86 -37
  71. package/src/services.ts +193 -35
  72. package/src/shared/index.ts +3 -11
  73. package/src/shared/models/backend/index.ts +3 -0
  74. package/src/shared/models/backend/project.ts +63 -0
  75. package/src/shared/models/backend/unlock-method.ts +20 -0
  76. package/src/shared/models/base.ts +151 -0
  77. package/src/shared/models/errors.ts +5 -0
  78. package/src/shared/models/index.ts +4 -0
  79. package/src/shared/models/project/api-key.ts +62 -0
  80. package/src/shared/models/project/artifact.ts +113 -0
  81. package/src/shared/models/project/component.ts +45 -0
  82. package/src/shared/models/project/index.ts +14 -0
  83. package/src/shared/{project.ts → models/project/instance.ts} +12 -0
  84. package/src/shared/models/project/lock.ts +91 -0
  85. package/src/shared/{operation.ts → models/project/operation.ts} +28 -7
  86. package/src/shared/models/project/page.ts +57 -0
  87. package/src/shared/models/project/secret.ts +112 -0
  88. package/src/shared/models/project/service-account.ts +22 -0
  89. package/src/shared/models/project/state.ts +432 -0
  90. package/src/shared/models/project/terminal.ts +99 -0
  91. package/src/shared/models/project/trigger.ts +56 -0
  92. package/src/shared/models/project/unlock-method.ts +31 -0
  93. package/src/shared/models/project/worker.ts +105 -0
  94. package/src/shared/resolvers/graph-resolver.ts +28 -0
  95. package/src/shared/resolvers/index.ts +5 -0
  96. package/src/shared/resolvers/input-hash.ts +53 -15
  97. package/src/shared/resolvers/input.ts +1 -9
  98. package/src/shared/resolvers/registry.ts +3 -2
  99. package/src/shared/resolvers/state.ts +2 -2
  100. package/src/shared/resolvers/validation.ts +61 -20
  101. package/src/shared/{async-batcher.ts → utils/async-batcher.ts} +13 -1
  102. package/src/shared/utils/hash.ts +6 -0
  103. package/src/shared/utils/index.ts +3 -0
  104. package/src/shared/utils/promise-tracker.ts +23 -0
  105. package/src/state/abstractions.ts +330 -101
  106. package/src/state/encryption.ts +59 -0
  107. package/src/state/factory.ts +3 -5
  108. package/src/state/index.ts +3 -0
  109. package/src/state/keyring.ts +22 -0
  110. package/src/state/local/backend.ts +299 -0
  111. package/src/state/local/collection.ts +342 -0
  112. package/src/state/local/index.ts +2 -0
  113. package/src/state/manager.ts +804 -18
  114. package/src/state/repository/index.ts +2 -0
  115. package/src/state/repository/repository.index.ts +193 -0
  116. package/src/state/repository/repository.ts +458 -0
  117. package/src/terminal/{shared.ts → abstractions.ts} +3 -3
  118. package/src/terminal/docker.ts +18 -14
  119. package/src/terminal/factory.ts +3 -3
  120. package/src/terminal/index.ts +1 -1
  121. package/src/terminal/manager.ts +131 -79
  122. package/src/terminal/run.sh.ts +21 -11
  123. package/src/worker/abstractions.ts +42 -0
  124. package/src/worker/docker.ts +83 -0
  125. package/src/worker/factory.ts +20 -0
  126. package/src/worker/index.ts +3 -0
  127. package/src/worker/manager.ts +139 -0
  128. package/dist/chunk-KTGKNSKM.js +0 -979
  129. package/dist/chunk-KTGKNSKM.js.map +0 -1
  130. package/dist/chunk-WXDYCRTT.js +0 -234
  131. package/dist/chunk-WXDYCRTT.js.map +0 -1
  132. package/src/library/worker/loader.ts +0 -114
  133. package/src/preferences/shared.ts +0 -1
  134. package/src/project/lock.ts +0 -39
  135. package/src/secret/abstractions.ts +0 -59
  136. package/src/secret/factory.ts +0 -22
  137. package/src/secret/local.ts +0 -152
  138. package/src/shared/state.ts +0 -247
  139. package/src/shared/terminal.ts +0 -14
  140. package/src/state/local.ts +0 -612
  141. package/src/workspace/abstractions.ts +0 -41
  142. package/src/workspace/factory.ts +0 -14
  143. package/src/workspace/local.ts +0 -54
  144. /package/src/shared/{library.ts → models/backend/library.ts} +0 -0
@@ -0,0 +1,159 @@
1
+ // src/common/utils.ts
2
+ import { z } from "zod";
3
+ async function runWithRetryOnError(runner, tryHandleError, maxRetries = 1) {
4
+ let lastError;
5
+ for (let i = 0; i < maxRetries + 1; i++) {
6
+ try {
7
+ return await runner();
8
+ } catch (e) {
9
+ lastError = e;
10
+ if (await tryHandleError(e)) {
11
+ continue;
12
+ }
13
+ throw e;
14
+ }
15
+ }
16
+ throw lastError;
17
+ }
18
+ var AbortError = class extends Error {
19
+ constructor(options) {
20
+ super("Operation aborted", options);
21
+ }
22
+ };
23
+ function isAbortError(error) {
24
+ return error instanceof Error && error.name === "AbortError";
25
+ }
26
+ var abortMessagePatterns = [
27
+ "Operation aborted",
28
+ "This operation was aborted",
29
+ "Command was killed with SIGINT"
30
+ ];
31
+ function isAbortErrorLike(error) {
32
+ if (isAbortError(error)) {
33
+ return true;
34
+ }
35
+ if (error instanceof Error) {
36
+ return abortMessagePatterns.some((pattern) => error.message.includes(pattern));
37
+ }
38
+ if (typeof error === "string") {
39
+ return abortMessagePatterns.some((pattern) => error.includes(pattern));
40
+ }
41
+ return false;
42
+ }
43
+ var stringArrayType = z.string().transform((args) => args.split(",").map((arg) => arg.trim()));
44
+ function errorToString(error) {
45
+ if (error instanceof Error) {
46
+ return error.stack || error.message;
47
+ }
48
+ return JSON.stringify(error);
49
+ }
50
+ function valueToString(value) {
51
+ if (typeof value === "string") {
52
+ return value;
53
+ }
54
+ return JSON.stringify(value);
55
+ }
56
+ function stringToValue(value) {
57
+ try {
58
+ return JSON.parse(value);
59
+ } catch {
60
+ return value;
61
+ }
62
+ }
63
+ function waitForAbort(signal) {
64
+ return new Promise((resolve) => {
65
+ if (signal.aborted) {
66
+ resolve();
67
+ return;
68
+ }
69
+ signal.addEventListener("abort", () => resolve(), { once: true });
70
+ });
71
+ }
72
+
73
+ // src/common/local.ts
74
+ import { basename } from "node:path";
75
+ import { findWorkspaceDir, readPackageJSON } from "pkg-types";
76
+ async function resolveMainLocalProject(projectPath, projectName) {
77
+ if (!projectPath) {
78
+ projectPath = await findWorkspaceDir();
79
+ }
80
+ if (!projectName) {
81
+ const packageJson = await readPackageJSON(projectPath);
82
+ projectName = packageJson.name;
83
+ }
84
+ if (!projectName) {
85
+ projectName = basename(projectPath);
86
+ }
87
+ return [projectPath, projectName];
88
+ }
89
+
90
+ // src/common/tree.ts
91
+ function renderTree(node) {
92
+ const lines = [];
93
+ function renderNode(node2, prefix = "", isLast = true) {
94
+ lines.push(prefix + (isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ") + node2.text);
95
+ const childPrefix = prefix + (isLast ? " " : "\u2502 ");
96
+ node2.children.forEach((child, index) => {
97
+ const isLastChild = index === node2.children.length - 1;
98
+ renderNode(child, childPrefix, isLastChild);
99
+ });
100
+ }
101
+ lines.push(node.text);
102
+ node.children.forEach((child, index) => {
103
+ const isLastChild = index === node.children.length - 1;
104
+ renderNode(child, "", isLastChild);
105
+ });
106
+ return lines.join("\n");
107
+ }
108
+
109
+ // src/common/performance.ts
110
+ var PerformanceLogger = class _PerformanceLogger {
111
+ constructor(logger) {
112
+ this.logger = logger;
113
+ this.start = Date.now();
114
+ this.last = this.start;
115
+ this.logger.child({});
116
+ }
117
+ start;
118
+ last;
119
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
120
+ log(message, ...args) {
121
+ const now = Date.now();
122
+ const diff = now - this.last;
123
+ const absDiff = now - this.start;
124
+ this.last = now;
125
+ this.logger.debug(
126
+ {
127
+ message,
128
+ diff: _PerformanceLogger.msToHumanReadable(diff),
129
+ absDiff: _PerformanceLogger.msToHumanReadable(absDiff)
130
+ },
131
+ message,
132
+ ...args
133
+ );
134
+ }
135
+ static msToHumanReadable(ms) {
136
+ const seconds = Math.floor(ms / 1e3);
137
+ const msPart = ms % 1e3;
138
+ if (seconds > 0) {
139
+ return `${seconds}s ${msPart}ms`;
140
+ } else {
141
+ return `${msPart}ms`;
142
+ }
143
+ }
144
+ };
145
+
146
+ export {
147
+ runWithRetryOnError,
148
+ AbortError,
149
+ isAbortErrorLike,
150
+ stringArrayType,
151
+ errorToString,
152
+ valueToString,
153
+ stringToValue,
154
+ waitForAbort,
155
+ resolveMainLocalProject,
156
+ renderTree,
157
+ PerformanceLogger
158
+ };
159
+ //# sourceMappingURL=chunk-RCB4AFGD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/common/utils.ts","../src/common/local.ts","../src/common/tree.ts","../src/common/performance.ts"],"sourcesContent":["import { z } from \"zod\"\n\nexport async function runWithRetryOnError<T>(\n runner: () => T | Promise<T>,\n tryHandleError: (error: unknown) => boolean | Promise<boolean>,\n maxRetries: number = 1,\n): Promise<T> {\n let lastError: unknown\n\n for (let i = 0; i < maxRetries + 1; i++) {\n try {\n return await runner()\n } catch (e) {\n lastError = e\n\n if (await tryHandleError(e)) {\n continue\n }\n\n throw e\n }\n }\n\n throw lastError\n}\n\nexport class AbortError extends Error {\n constructor(options?: ErrorOptions) {\n super(\"Operation aborted\", options)\n }\n}\n\nexport function isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === \"AbortError\"\n}\n\nconst abortMessagePatterns = [\n \"Operation aborted\",\n \"This operation was aborted\",\n \"Command was killed with SIGINT\",\n]\n\nexport function isAbortErrorLike(error: unknown): boolean {\n if (isAbortError(error)) {\n return true\n }\n\n if (error instanceof Error) {\n return abortMessagePatterns.some(pattern => error.message.includes(pattern))\n }\n\n if (typeof error === \"string\") {\n return abortMessagePatterns.some(pattern => error.includes(pattern))\n }\n\n return false\n}\n\nexport function tryWrapAbortErrorLike(error: unknown): unknown {\n if (isAbortErrorLike(error)) {\n return new AbortError({ cause: error })\n }\n\n return error\n}\n\nexport const stringArrayType = z.string().transform(args => args.split(\",\").map(arg => arg.trim()))\n\nexport function errorToString(error: unknown): string {\n if (error instanceof Error) {\n return error.stack || error.message\n }\n\n return JSON.stringify(error)\n}\n\nexport function valueToString(value: unknown): string {\n if (typeof value === \"string\") {\n return value\n }\n\n return JSON.stringify(value)\n}\n\nexport function stringToValue(value: string): unknown {\n try {\n return JSON.parse(value)\n } catch {\n return value\n }\n}\n\nexport function waitForAbort(signal: AbortSignal): Promise<void> {\n return new Promise(resolve => {\n if (signal.aborted) {\n resolve()\n return\n }\n\n signal.addEventListener(\"abort\", () => resolve(), { once: true })\n })\n}\n","import { basename } from \"node:path\"\nimport { findWorkspaceDir, readPackageJSON } from \"pkg-types\"\n\nexport async function resolveMainLocalProject(\n projectPath?: string,\n projectName?: string,\n): Promise<[projecPath: string, projectName: string]> {\n if (!projectPath) {\n projectPath = await findWorkspaceDir()\n }\n\n if (!projectName) {\n const packageJson = await readPackageJSON(projectPath)\n projectName = packageJson.name\n }\n\n if (!projectName) {\n projectName = basename(projectPath)\n }\n\n return [projectPath, projectName]\n}\n","export type TreeNode = {\n text: string\n children: TreeNode[]\n}\n\n/**\n * Renders a tree structure similar to the Linux tree command output.\n * Uses box-drawing characters to create visual hierarchy.\n */\nexport function renderTree(node: TreeNode): string {\n const lines: string[] = []\n\n function renderNode(node: TreeNode, prefix: string = \"\", isLast: boolean = true): void {\n // Add current node\n lines.push(prefix + (isLast ? \"└── \" : \"├── \") + node.text)\n\n // Add children\n const childPrefix = prefix + (isLast ? \" \" : \"│ \")\n node.children.forEach((child, index) => {\n const isLastChild = index === node.children.length - 1\n renderNode(child, childPrefix, isLastChild)\n })\n }\n\n // Start with root node (no prefix)\n lines.push(node.text)\n node.children.forEach((child, index) => {\n const isLastChild = index === node.children.length - 1\n renderNode(child, \"\", isLastChild)\n })\n\n return lines.join(\"\\n\")\n}\n","import type { Logger } from \"pino\"\n\nexport class PerformanceLogger {\n private readonly start: number\n private last: number\n\n constructor(private readonly logger: Logger) {\n this.start = Date.now()\n this.last = this.start\n\n this.logger.child({})\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n log(message: string, ...args: any[]): void {\n const now = Date.now()\n const diff = now - this.last\n const absDiff = now - this.start\n\n this.last = now\n\n this.logger.debug(\n {\n message,\n diff: PerformanceLogger.msToHumanReadable(diff),\n absDiff: PerformanceLogger.msToHumanReadable(absDiff),\n },\n message,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n ...args,\n )\n }\n\n private static msToHumanReadable(ms: number): string {\n const seconds = Math.floor(ms / 1000)\n const msPart = ms % 1000\n\n if (seconds > 0) {\n return `${seconds}s ${msPart}ms`\n } else {\n return `${msPart}ms`\n }\n }\n}\n"],"mappings":"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","names":["node"]}