@astrale-os/sdk 0.5.0-beta.99 → 0.6.0-beta.0

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 (270) hide show
  1. package/README.md +165 -2
  2. package/dist/application/action/action.d.ts +7 -4
  3. package/dist/application/action/authoring.d.ts +2 -1
  4. package/dist/application/action/context.d.ts +18 -13
  5. package/dist/application/action/define.d.ts +5 -1
  6. package/dist/application/action/define.js +6 -1
  7. package/dist/application/action/index.d.ts +2 -1
  8. package/dist/application/dependency/index.d.ts +1 -0
  9. package/dist/application/dependency/invoker.d.ts +26 -0
  10. package/dist/application/error/error.d.ts +23 -0
  11. package/dist/application/error/error.js +87 -0
  12. package/dist/application/error/index.d.ts +2 -0
  13. package/dist/application/error/index.js +1 -0
  14. package/dist/application/index.d.ts +2 -2
  15. package/dist/application/integration/authentication.d.ts +10 -0
  16. package/dist/application/integration/authentication.typecheck.js +18 -0
  17. package/dist/application/integration/client.d.ts +2 -0
  18. package/dist/application/integration/client.js +19 -2
  19. package/dist/application/integration/index.d.ts +1 -0
  20. package/dist/application/integration/operation.d.ts +3 -0
  21. package/dist/application/mutation/authoring/builder.js +2 -2
  22. package/dist/application/mutation/authoring/endpoint.d.ts +3 -3
  23. package/dist/application/mutation/authoring/endpoint.js +9 -0
  24. package/dist/application/mutation/failure.js +13 -7
  25. package/dist/application/mutation/index.d.ts +1 -0
  26. package/dist/application/requirements/{profiles.d.ts → core.d.ts} +5 -3
  27. package/dist/application/requirements/{profiles.js → core.js} +6 -6
  28. package/dist/application/requirements/index.d.ts +4 -4
  29. package/dist/application/requirements/index.js +5 -5
  30. package/dist/application/requirements/requirement.d.ts +3 -2
  31. package/dist/application/runtime/authoring.d.ts +1 -0
  32. package/dist/application/runtime/callables.js +2 -2
  33. package/dist/application/runtime/declarations.d.ts +43 -0
  34. package/dist/application/runtime/define.d.ts +2 -1
  35. package/dist/application/view/index.d.ts +1 -1
  36. package/dist/application/view/route.d.ts +4 -0
  37. package/dist/application/view/route.js +5 -1
  38. package/dist/application/workflow/authoring.d.ts +1 -0
  39. package/dist/application/workflow/context.d.ts +2 -1
  40. package/dist/application/workflow/define.d.ts +5 -1
  41. package/dist/application/workflow/define.js +6 -1
  42. package/dist/application/workflow/index.d.ts +1 -0
  43. package/dist/application/workflow/runner/runner.d.ts +3 -2
  44. package/dist/application/workflow/workflow.d.ts +4 -3
  45. package/dist/deployment/adapter/adapter.d.ts +12 -7
  46. package/dist/deployment/adapter/define.d.ts +5 -2
  47. package/dist/deployment/adapter/define.js +15 -17
  48. package/dist/deployment/adapter/deploy/context.d.ts +6 -0
  49. package/dist/deployment/adapter/deploy/result.d.ts +2 -0
  50. package/dist/deployment/adapter/index.d.ts +2 -3
  51. package/dist/deployment/adapter/index.js +1 -1
  52. package/dist/deployment/adapter/prepare/context.d.ts +13 -5
  53. package/dist/deployment/authoring.d.ts +1 -1
  54. package/dist/deployment/build/compile.js +21 -19
  55. package/dist/deployment/build/frontend/compilation.d.ts +2 -1
  56. package/dist/deployment/build/frontend/compilation.js +1 -0
  57. package/dist/deployment/build/material.js +5 -5
  58. package/dist/deployment/deploy.d.ts +10 -4
  59. package/dist/deployment/deploy.js +5 -5
  60. package/dist/deployment/deployment.d.ts +8 -5
  61. package/dist/deployment/deployment.js +10 -1
  62. package/dist/deployment/index.d.ts +5 -4
  63. package/dist/deployment/index.js +3 -2
  64. package/dist/deployment/release/addressing.d.ts +6 -2
  65. package/dist/deployment/release/addressing.js +9 -4
  66. package/dist/deployment/release/publication/callables.js +1 -1
  67. package/dist/deployment/release/publication/index.d.ts +1 -1
  68. package/dist/deployment/release/publication/index.js +1 -1
  69. package/dist/deployment/release/publication/routes.js +1 -1
  70. package/dist/deployment/release/publication/seal.d.ts +0 -1
  71. package/dist/deployment/release/publication/seal.js +4 -5
  72. package/dist/deployment/release/publication/views.js +2 -1
  73. package/dist/deployment/verify/preflight/artifact.js +1 -1
  74. package/dist/deployment/verify/readiness/deployment.js +7 -3
  75. package/dist/deployment/verify/readiness/identity.js +1 -1
  76. package/dist/deployment/verify/readiness/publication.js +2 -2
  77. package/dist/execution/identity/authentication.js +0 -1
  78. package/dist/execution/identity/exchange.d.ts +1 -0
  79. package/dist/execution/identity/exchange.js +1 -1
  80. package/dist/execution/identity/jwks.js +1 -1
  81. package/dist/execution/invocation/admission/authentication.d.ts +6 -3
  82. package/dist/execution/invocation/admission/authentication.js +16 -6
  83. package/dist/execution/invocation/admission/authority.d.ts +2 -2
  84. package/dist/execution/invocation/dependency/bind.d.ts +5 -0
  85. package/dist/execution/invocation/dependency/bind.js +68 -0
  86. package/dist/execution/invocation/dependency/index.d.ts +1 -0
  87. package/dist/execution/invocation/dependency/index.js +1 -0
  88. package/dist/execution/invocation/dispatch/action.js +19 -2
  89. package/dist/execution/invocation/dispatch/context.d.ts +4 -4
  90. package/dist/execution/invocation/dispatch/context.js +29 -9
  91. package/dist/execution/invocation/dispatch/workflow.js +17 -4
  92. package/dist/execution/invocation/integration/authentication.d.ts +5 -0
  93. package/dist/execution/invocation/integration/authentication.js +53 -0
  94. package/dist/execution/invocation/integration/call.d.ts +7 -1
  95. package/dist/execution/invocation/integration/call.js +8 -3
  96. package/dist/execution/invocation/integration/clients.d.ts +2 -2
  97. package/dist/execution/invocation/integration/clients.js +2 -2
  98. package/dist/execution/invocation/lifecycle/active.js +30 -5
  99. package/dist/execution/invocation/result/errors.d.ts +1 -0
  100. package/dist/execution/invocation/result/errors.js +15 -10
  101. package/dist/execution/service/create.js +3 -1
  102. package/dist/execution/service/service.d.ts +1 -1
  103. package/dist/index.d.ts +3 -1
  104. package/dist/index.js +1 -0
  105. package/dist/platform/auth/index.d.ts +1 -1
  106. package/dist/platform/auth/index.js +0 -1
  107. package/dist/platform/graph/alias.d.ts +6 -0
  108. package/dist/platform/graph/alias.js +6 -0
  109. package/dist/platform/graph/document/index.d.ts +2 -1
  110. package/dist/platform/graph/document/index.js +2 -1
  111. package/dist/platform/graph/index.d.ts +2 -1
  112. package/dist/platform/graph/index.js +2 -1
  113. package/dist/platform/schema/class-authoring.d.ts +37 -0
  114. package/dist/platform/schema/class-authoring.js +20 -0
  115. package/dist/platform/schema/class-icon.d.ts +15 -0
  116. package/dist/platform/schema/class-icon.js +46 -0
  117. package/dist/platform/schema/error.d.ts +11 -0
  118. package/dist/platform/schema/error.js +34 -0
  119. package/dist/platform/schema/errors/index.d.ts +3 -0
  120. package/dist/platform/schema/errors/index.js +2 -0
  121. package/dist/platform/schema/icons/index.d.ts +2 -0
  122. package/dist/platform/schema/icons/index.js +2 -0
  123. package/dist/platform/schema/index.d.ts +20 -13
  124. package/dist/platform/schema/index.js +9 -4
  125. package/dist/platform/schema/kernel.d.ts +22 -0
  126. package/dist/platform/schema/kernel.js +5 -0
  127. package/dist/platform/schema/node-id.d.ts +3 -0
  128. package/dist/platform/schema/node-id.js +6 -0
  129. package/dist/platform/schema/property.d.ts +12 -0
  130. package/dist/platform/schema/property.js +3 -0
  131. package/dist/platform/schema/schema-authoring.d.ts +48 -0
  132. package/dist/platform/schema/schema-authoring.js +3 -0
  133. package/dist/platform/schema/state-property.d.ts +11 -0
  134. package/dist/platform/schema/state-property.js +3 -0
  135. package/dist/project/admit.d.ts +4 -0
  136. package/dist/project/admit.js +22 -0
  137. package/dist/project/define.d.ts +12 -0
  138. package/dist/project/define.js +106 -0
  139. package/dist/project/index.d.ts +4 -0
  140. package/dist/project/index.js +2 -0
  141. package/dist/project/project.d.ts +24 -0
  142. package/dist/project/project.js +1 -0
  143. package/dist/testing/dataset/admission.d.ts +13 -0
  144. package/dist/testing/dataset/admission.js +107 -0
  145. package/dist/testing/dataset/builder.d.ts +42 -0
  146. package/dist/testing/dataset/builder.js +127 -0
  147. package/dist/testing/dataset/codec.d.ts +6 -0
  148. package/dist/testing/dataset/codec.js +113 -0
  149. package/dist/testing/dataset/dataset.d.ts +58 -0
  150. package/dist/testing/dataset/dataset.js +2 -0
  151. package/dist/testing/dataset/define.d.ts +33 -0
  152. package/dist/testing/dataset/define.js +105 -0
  153. package/dist/testing/dataset/index.d.ts +8 -0
  154. package/dist/testing/dataset/index.js +4 -0
  155. package/dist/testing/dataset/references.d.ts +14 -0
  156. package/dist/testing/dataset/references.js +56 -0
  157. package/dist/testing/index.d.ts +9 -0
  158. package/dist/testing/index.js +5 -0
  159. package/dist/testing/load.d.ts +14 -0
  160. package/dist/testing/load.js +44 -0
  161. package/dist/testing/reference.d.ts +11 -0
  162. package/dist/testing/reference.js +19 -0
  163. package/dist/testing/tests.d.ts +12 -0
  164. package/dist/testing/tests.js +31 -0
  165. package/dist/tooling/cli/arguments.d.ts +7 -4
  166. package/dist/tooling/cli/arguments.js +82 -107
  167. package/dist/tooling/cli/astrale/authority.d.ts +5 -0
  168. package/dist/tooling/cli/astrale/authority.js +11 -0
  169. package/dist/tooling/cli/astrale/executable.d.ts +2 -0
  170. package/dist/tooling/cli/astrale/executable.js +47 -0
  171. package/dist/tooling/cli/astrale/failure.d.ts +6 -0
  172. package/dist/tooling/cli/astrale/failure.js +48 -0
  173. package/dist/tooling/cli/astrale/instance.d.ts +11 -0
  174. package/dist/tooling/cli/astrale/instance.js +52 -0
  175. package/dist/tooling/cli/astrale/process.d.ts +13 -0
  176. package/dist/tooling/cli/astrale/process.js +94 -0
  177. package/dist/tooling/cli/astrale/version.d.ts +18 -0
  178. package/dist/tooling/cli/astrale/version.js +55 -0
  179. package/dist/tooling/cli/bun.js +1 -1
  180. package/dist/tooling/cli/credential.d.ts +2 -0
  181. package/dist/tooling/cli/credential.js +57 -0
  182. package/dist/tooling/cli/development/candidate.d.ts +25 -0
  183. package/dist/tooling/cli/development/candidate.js +176 -0
  184. package/dist/tooling/cli/development/deployment.d.ts +16 -0
  185. package/dist/tooling/cli/development/deployment.js +39 -0
  186. package/dist/tooling/cli/development/develop.d.ts +4 -3
  187. package/dist/tooling/cli/development/develop.js +125 -289
  188. package/dist/tooling/cli/development/lease.d.ts +18 -0
  189. package/dist/tooling/cli/development/lease.js +163 -0
  190. package/dist/tooling/cli/development/lifecycle.js +4 -0
  191. package/dist/tooling/cli/development/project-imports.d.ts +22 -0
  192. package/dist/tooling/cli/development/project-imports.js +39 -0
  193. package/dist/tooling/cli/development/project-lock.d.ts +3 -4
  194. package/dist/tooling/cli/development/project-lock.js +14 -166
  195. package/dist/tooling/cli/development/release-evidence.d.ts +4 -0
  196. package/dist/tooling/cli/development/release-evidence.js +10 -0
  197. package/dist/tooling/cli/development/report.d.ts +6 -0
  198. package/dist/tooling/cli/development/report.js +14 -0
  199. package/dist/tooling/cli/development/source-watch.js +53 -5
  200. package/dist/tooling/cli/development/sources.d.ts +7 -0
  201. package/dist/tooling/cli/development/sources.js +48 -0
  202. package/dist/tooling/cli/development/target-lock.d.ts +16 -0
  203. package/dist/tooling/cli/development/target-lock.js +68 -0
  204. package/dist/tooling/cli/development/view.d.ts +28 -0
  205. package/dist/tooling/cli/development/view.js +151 -0
  206. package/dist/tooling/cli/environment-release.d.ts +21 -0
  207. package/dist/tooling/cli/environment-release.js +46 -0
  208. package/dist/tooling/cli/evidence.d.ts +11 -0
  209. package/dist/tooling/cli/evidence.js +53 -0
  210. package/dist/tooling/cli/help.js +78 -34
  211. package/dist/tooling/cli/index.d.ts +1 -1
  212. package/dist/tooling/cli/index.js +1 -1
  213. package/dist/tooling/cli/installation/index.d.ts +2 -0
  214. package/dist/tooling/cli/installation/index.js +1 -0
  215. package/dist/tooling/cli/installation/observation.d.ts +10 -0
  216. package/dist/tooling/cli/installation/observation.js +44 -0
  217. package/dist/tooling/cli/installation/reconcile.d.ts +32 -0
  218. package/dist/tooling/cli/installation/reconcile.js +122 -0
  219. package/dist/tooling/cli/orchestrate.js +84 -44
  220. package/dist/tooling/cli/project.d.ts +17 -0
  221. package/dist/tooling/cli/project.js +18 -0
  222. package/dist/tooling/cli/test.d.ts +12 -0
  223. package/dist/tooling/cli/test.js +47 -0
  224. package/dist/tooling/cli/upgrade/index.d.ts +6 -0
  225. package/dist/tooling/cli/upgrade/index.js +115 -0
  226. package/dist/tooling/cli/upgrade/manifest.d.ts +18 -0
  227. package/dist/tooling/cli/upgrade/manifest.js +77 -0
  228. package/dist/tooling/cli/upgrade/process.d.ts +2 -0
  229. package/dist/tooling/cli/upgrade/process.js +57 -0
  230. package/dist/tooling/linter/adapters/typescript/imports.js +2 -0
  231. package/dist/tooling/linter/adapters/typescript/index.d.ts +1 -0
  232. package/dist/tooling/linter/adapters/typescript/index.js +1 -0
  233. package/dist/tooling/linter/adapters/typescript/query-collection-type.js +4 -51
  234. package/dist/tooling/linter/adapters/typescript/type-analysis.d.ts +9 -0
  235. package/dist/tooling/linter/adapters/typescript/type-analysis.js +55 -0
  236. package/dist/tooling/linter/implementations/source/callable-requirements.d.ts +28 -0
  237. package/dist/tooling/linter/implementations/source/callable-requirements.js +234 -0
  238. package/dist/tooling/linter/implementations/source/dependencies.d.ts +2 -0
  239. package/dist/tooling/linter/implementations/source/dependencies.js +219 -0
  240. package/dist/tooling/linter/implementations/source/global.js +52 -2
  241. package/dist/tooling/linter/implementations/source/mutations.js +520 -38
  242. package/dist/tooling/linter/implementations/source/providers.js +19 -164
  243. package/dist/tooling/linter/implementations/source/schema.js +454 -2
  244. package/dist/tooling/linter/implementations/source/verifiers.js +2 -0
  245. package/dist/tooling/linter/implementations/source/workflows.js +8 -35
  246. package/dist/tooling/linter/policy/generated.js +2 -2
  247. package/dist/tooling/linter/requirements/registry.js +9 -3
  248. package/dist/tooling/packaging/declarations/normalize.js +3 -38
  249. package/dist/tooling/packaging/declarations/paths.d.ts +5 -0
  250. package/dist/tooling/packaging/declarations/paths.js +38 -0
  251. package/dist/tooling/packaging/finalize.d.ts +13 -0
  252. package/dist/tooling/packaging/finalize.js +62 -0
  253. package/dist/tooling/packaging/index.d.ts +2 -0
  254. package/dist/tooling/packaging/index.js +1 -0
  255. package/dist/tooling/packaging/javascript.d.ts +3 -0
  256. package/dist/tooling/packaging/javascript.js +45 -2
  257. package/dist/tooling/packaging/packaging.d.ts +2 -5
  258. package/dist/tooling/packaging/packaging.js +6 -30
  259. package/package.json +42 -12
  260. package/CHANGELOG.md +0 -1506
  261. package/dist/deployment/adapter/development/context.d.ts +0 -18
  262. package/dist/deployment/adapter/development/index.d.ts +0 -4
  263. package/dist/deployment/adapter/development/input.d.ts +0 -6
  264. package/dist/deployment/adapter/development/placement.d.ts +0 -15
  265. package/dist/deployment/adapter/development/session.d.ts +0 -9
  266. /package/dist/{deployment/adapter/development → application/dependency}/index.js +0 -0
  267. /package/dist/{deployment/adapter/development/context.js → application/dependency/invoker.js} +0 -0
  268. /package/dist/{deployment/adapter/development/input.js → application/integration/authentication.js} +0 -0
  269. /package/dist/{deployment/adapter/development/placement.js → application/integration/authentication.typecheck.d.ts} +0 -0
  270. /package/dist/{deployment/adapter/development/session.js → application/runtime/declarations.js} +0 -0
@@ -0,0 +1,32 @@
1
+ import type { InstallationTarget } from '../../../deployment/adapter/index.js';
2
+ import type { Release } from '../../../deployment/release/index.js';
3
+ import type { AstraleProcessResult } from '../astrale/process.js';
4
+ export interface InstallationEvidence {
5
+ readonly status: 'unchanged' | 'installed' | 'upgraded';
6
+ readonly instance: string;
7
+ readonly origin: string;
8
+ readonly issuer: string;
9
+ readonly revision: string;
10
+ readonly generation: string;
11
+ readonly etag: string;
12
+ }
13
+ export type AstraleCommandResult = AstraleProcessResult;
14
+ export interface InstallationDependencies {
15
+ run(input: {
16
+ readonly executable: string;
17
+ readonly args: readonly string[];
18
+ readonly projectDir: string;
19
+ readonly signal: AbortSignal;
20
+ readonly timeoutMs: number;
21
+ }): Promise<AstraleCommandResult>;
22
+ }
23
+ /** Reconcile one observed Release without ever replacing a different issuer. */
24
+ export declare function reconcileInstallation(input: {
25
+ readonly projectDir: string;
26
+ readonly target: InstallationTarget;
27
+ readonly executable: string;
28
+ readonly identity?: string;
29
+ readonly credential?: string;
30
+ readonly release: Release;
31
+ readonly signal: AbortSignal;
32
+ }, dependencies?: InstallationDependencies): Promise<InstallationEvidence>;
@@ -0,0 +1,122 @@
1
+ import { astraleAuthorityArguments } from '../astrale/authority.js';
2
+ import { AstraleCliError, isDomainNotInstalledFailure, astraleFailure } from '../astrale/failure.js';
3
+ import { runAstrale } from '../astrale/process.js';
4
+ import { canonicalIssuer, decodeInstallationObservation } from './observation.js';
5
+ /** Reconcile one observed Release without ever replacing a different issuer. */
6
+ export async function reconcileInstallation(input, dependencies = {
7
+ run: runAstrale,
8
+ }) {
9
+ const origin = input.release.publication.origin;
10
+ const revision = input.release.publication.schema.revision;
11
+ const issuer = canonicalIssuer(input.release.addressing.issuer);
12
+ const etag = input.release.publication.etag;
13
+ const identity = input.identity ?? input.target.identity;
14
+ const authority = astraleAuthorityArguments({
15
+ ...(identity === undefined ? {} : { identity }),
16
+ ...(input.credential === undefined ? {} : { credential: input.credential }),
17
+ });
18
+ const executable = input.executable;
19
+ const before = await observe(input, origin, authority, executable, dependencies);
20
+ if (before !== undefined) {
21
+ assertIdentity(before, { origin, issuer });
22
+ if (before.revision === revision && before.etag === etag) {
23
+ return evidence('unchanged', input.target.instance, before);
24
+ }
25
+ }
26
+ let installationFailure;
27
+ try {
28
+ const installed = await dependencies.run({
29
+ executable,
30
+ projectDir: input.projectDir,
31
+ signal: input.signal,
32
+ timeoutMs: 250_000,
33
+ args: [
34
+ '--ci',
35
+ '--no-prompt',
36
+ 'domain',
37
+ 'install',
38
+ input.release.addressing.publicUrl,
39
+ '--direct',
40
+ '--allow-identity-override',
41
+ '-i',
42
+ input.target.instance,
43
+ '--json',
44
+ '--timeout',
45
+ '240000',
46
+ ...authority,
47
+ ],
48
+ });
49
+ if (installed.code !== 0)
50
+ installationFailure = astraleFailure('domain install', installed);
51
+ }
52
+ catch (cause) {
53
+ installationFailure = cause;
54
+ }
55
+ let after;
56
+ try {
57
+ after = await observe(input, origin, authority, executable, dependencies);
58
+ }
59
+ catch (cause) {
60
+ throw installationError(installationFailure === undefined ? [cause] : [installationFailure, cause], 'Domain installation outcome is unknown because reconciliation failed.');
61
+ }
62
+ if (installationFailure !== undefined && after === undefined) {
63
+ throw installationError([installationFailure], 'Domain installation failed and no installed Release was observed.');
64
+ }
65
+ if (after === undefined)
66
+ throw new TypeError('Installed Domain was absent after installation.');
67
+ try {
68
+ assertIdentity(after, { origin, issuer });
69
+ if (after.revision !== revision || after.etag !== etag) {
70
+ throw new TypeError('Installed Domain evidence differs from the deployed Release.');
71
+ }
72
+ }
73
+ catch (cause) {
74
+ if (installationFailure === undefined)
75
+ throw cause;
76
+ throw installationError([installationFailure, cause], 'Domain installation failed with a different observed Release.');
77
+ }
78
+ return evidence(before === undefined ? 'installed' : 'upgraded', input.target.instance, after);
79
+ }
80
+ function installationError(causes, message) {
81
+ const diagnostics = causes
82
+ .filter((cause) => cause instanceof AstraleCliError)
83
+ .map((cause) => cause.message);
84
+ return new AggregateError(causes, [message, ...diagnostics].join(' '));
85
+ }
86
+ async function observe(input, origin, authority, executable, dependencies) {
87
+ const result = await dependencies.run({
88
+ executable,
89
+ projectDir: input.projectDir,
90
+ signal: input.signal,
91
+ timeoutMs: 70_000,
92
+ args: [
93
+ '--ci',
94
+ '--no-prompt',
95
+ 'introspect',
96
+ origin,
97
+ '-i',
98
+ input.target.instance,
99
+ '--json',
100
+ '--timeout',
101
+ '60000',
102
+ ...authority,
103
+ ],
104
+ });
105
+ if (result.code !== 0) {
106
+ if (isDomainNotInstalledFailure(result.stderr))
107
+ return undefined;
108
+ throw astraleFailure(`introspect ${origin}`, result);
109
+ }
110
+ return decodeInstallationObservation(result.stdout);
111
+ }
112
+ function assertIdentity(observed, expected) {
113
+ if (observed.origin !== expected.origin) {
114
+ throw new TypeError('Installed Domain evidence has a different origin.');
115
+ }
116
+ if (observed.issuer !== expected.issuer) {
117
+ throw new TypeError(`Installed Domain issuer ${observed.issuer} differs from deployment issuer ${expected.issuer}; refusing replacement.`);
118
+ }
119
+ }
120
+ function evidence(status, instance, observed) {
121
+ return Object.freeze({ status, instance, ...observed });
122
+ }
@@ -1,14 +1,17 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { dirname, isAbsolute, join, resolve } from 'node:path';
3
- import { pathToFileURL } from 'node:url';
4
- import { admitRuntime, compile, isDeployment, resolveRuntime, verifyDeployment, verifyPreflight, } from '../../deployment/index.js';
3
+ import { admitRuntime, compile, resolveRuntime, verifyDeployment, verifyPreflight, } from '../../deployment/index.js';
5
4
  import { packageDomain } from '../packaging/index.js';
6
5
  import { parseArgs } from './arguments.js';
6
+ import { resolveCompatibleAstrale } from './astrale/version.js';
7
7
  import { BunRequiredError } from './bun.js';
8
8
  import { develop } from './development/develop.js';
9
9
  import { loadDeclaredSecrets } from './dotenv.js';
10
+ import { reconcileEnvironmentRelease } from './environment-release.js';
10
11
  import { ERROR_USAGE, helpRequest, helpText } from './help.js';
11
12
  import { error, info } from './log.js';
13
+ import { importModule, loadProject, runtimeEntrypoint, selectEnvironment } from './project.js';
14
+ import { executeTests } from './test.js';
12
15
  const CONFIG_NAMES = ['astrale.config.ts', 'astrale.config.js', 'astrale.config.mjs'];
13
16
  export async function run(argv) {
14
17
  const requestedHelp = helpRequest(argv);
@@ -26,11 +29,23 @@ export async function run(argv) {
26
29
  }
27
30
  if (parsed.command === 'lint')
28
31
  return lint(parsed);
32
+ if (parsed.command === 'upgrade') {
33
+ const { upgrade } = await import('./upgrade/index.js');
34
+ await upgrade({
35
+ cwd: process.cwd(),
36
+ channel: parsed.channel ?? 'beta',
37
+ check: parsed.check ?? false,
38
+ });
39
+ return 0;
40
+ }
29
41
  if (parsed.command === 'package') {
30
42
  const result = await packageDomain({ projectDir: process.cwd() });
31
43
  info(`Packaged ${result.declarations} public declarations (${result.replacements} references normalized).`);
32
44
  return 0;
33
45
  }
46
+ if (parsed.command === 'test' && parsed.env === '') {
47
+ return executeTests(parsed.suite === undefined ? {} : { suite: parsed.suite });
48
+ }
34
49
  if (!process.versions.bun) {
35
50
  throw new BunRequiredError();
36
51
  }
@@ -43,46 +58,86 @@ export async function run(argv) {
43
58
  if (parsed.command === 'dev') {
44
59
  return executeDevelopmentCommand(parsed, { configPath, projectDir });
45
60
  }
46
- const deployment = await loadDeployment(configPath);
47
- const adapter = deployment.adapter;
48
- const build = compile(deployment.application);
49
- const resolved = await resolveRuntime(deployment.entrypoint, (path) => importModule(resolve(dirname(configPath), path)));
61
+ const project = await loadProject(configPath);
62
+ if (parsed.command === 'test') {
63
+ selectEnvironment(project, parsed.env);
64
+ return executeTests({
65
+ environment: parsed.env,
66
+ ...(parsed.suite === undefined ? {} : { suite: parsed.suite }),
67
+ });
68
+ }
69
+ const build = compile(project.application);
70
+ const resolved = await resolveRuntime(runtimeEntrypoint(project), (path) => importModule(resolve(dirname(configPath), path)));
50
71
  admitRuntime({ runtime: build.runtime }, resolved);
51
- const parameters = adapter.parameters(parsed.env);
52
- const source = await adapter.prepare(parameters, {
53
- projectDir,
54
- environment: parsed.env,
55
- mode: 'release',
56
- build,
57
- runtime: resolved,
58
- });
59
- const artifact = verifyPreflight({ build, runtime: resolved, source });
60
72
  if (parsed.command === 'build') {
61
- info(`Built ${build.schema.compiled.root.origin} (${artifact.digest}).`);
73
+ info(`Built ${build.schema.compiled.root.origin} (${build.schema.compiled.root.revision}).`);
62
74
  return 0;
63
75
  }
64
- const secrets = secretsFor(adapter, parameters, projectDir, resolved.runtime);
76
+ const environment = selectEnvironment(project, parsed.env);
77
+ const adapter = environment.deployment.adapter;
78
+ const parameters = environment.deployment.parameters;
65
79
  const lifecycle = deploymentLifecycle();
66
- let deployed;
67
80
  try {
68
- deployed = await adapter.deploy(parameters, {
81
+ const source = await adapter.prepare(parameters, {
82
+ projectDir,
83
+ environment: parsed.env,
84
+ ...(environment.installation === undefined ? {} : { installation: environment.installation }),
85
+ mode: 'release',
86
+ signal: lifecycle.signal,
87
+ build,
88
+ runtime: resolved,
89
+ });
90
+ const artifact = verifyPreflight({ build, runtime: resolved, source });
91
+ const secrets = secretsFor(adapter, parameters, projectDir, resolved.runtime);
92
+ const installationExecutable = environment.installation === undefined || parsed.deployOnly
93
+ ? undefined
94
+ : await resolveCompatibleAstrale({ projectDir, signal: lifecycle.signal });
95
+ const deployed = await adapter.deploy(parameters, {
69
96
  projectDir,
70
97
  environment: parsed.env,
98
+ ...(environment.installation === undefined ? {} : { installation: environment.installation }),
99
+ ...(parsed.identity === undefined ? {} : { identity: parsed.identity }),
71
100
  secrets,
72
101
  artifact,
73
102
  signal: lifecycle.signal,
74
103
  });
104
+ const result = verifyDeployment(artifact, deployed);
105
+ if (result.status === 'failed') {
106
+ error(`Deployment failed during ${result.phase}: ${result.error.message}`);
107
+ return 1;
108
+ }
109
+ info(`Domain: ${result.release.publication.origin}`);
110
+ info(`Environment: ${parsed.env}`);
111
+ info(`Adapter: ${adapter.name}@${adapter.version}`);
112
+ info(`Deployment: ${result.progress.provider.evidence.deployment}`);
113
+ if (result.progress.provider.evidence.preflight !== undefined) {
114
+ info(`Preflight: ${result.progress.provider.evidence.preflight}; public readiness verified`);
115
+ }
116
+ info(`Public: ${result.release.addressing.publicUrl}`);
117
+ info(`Publication: ${result.release.publication.schema.revision} · ${result.release.publication.etag}`);
118
+ const installed = await reconcileEnvironmentRelease({
119
+ projectDir,
120
+ environment: parsed.env,
121
+ adapter,
122
+ deployment: result,
123
+ ...(environment.installation === undefined ? {} : { installation: environment.installation }),
124
+ deployOnly: parsed.deployOnly ?? false,
125
+ ...(installationExecutable === undefined ? {} : { installationExecutable }),
126
+ ...(parsed.identity === undefined ? {} : { identity: parsed.identity }),
127
+ signal: lifecycle.signal,
128
+ });
129
+ if (installed === undefined) {
130
+ info('Installation: skipped');
131
+ }
132
+ else {
133
+ info(`Installation: ${installed.instance} · ${installed.status}`);
134
+ }
135
+ info('Ready: deployment verified');
136
+ return 0;
75
137
  }
76
138
  finally {
77
139
  lifecycle.dispose();
78
140
  }
79
- const result = verifyDeployment(artifact, deployed);
80
- if (result.status === 'failed') {
81
- error(`Deployment failed during ${result.phase}: ${result.error.message}`);
82
- return 1;
83
- }
84
- info(`Ready: ${result.release.addressing.issuer}`);
85
- return 0;
86
141
  }
87
142
  export function executeDevelopmentCommand(parsed, input, execute = develop) {
88
143
  if (parsed.command !== 'dev')
@@ -91,11 +146,9 @@ export function executeDevelopmentCommand(parsed, input, execute = develop) {
91
146
  configPath: input.configPath,
92
147
  projectDir: input.projectDir,
93
148
  environment: parsed.env,
94
- overrides: Object.freeze({
95
- ...(parsed.host === undefined ? {} : { publicUrl: parsed.host }),
96
- ...(parsed.port === undefined ? {} : { localPort: parsed.port }),
97
- ...(parsed.credentialFile === undefined ? {} : { credentialFile: parsed.credentialFile }),
98
- }),
149
+ deployOnly: parsed.deployOnly ?? false,
150
+ ...(parsed.identity === undefined ? {} : { identity: parsed.identity }),
151
+ ...(parsed.credentialFile === undefined ? {} : { credentialFile: parsed.credentialFile }),
99
152
  ...(parsed.sessionFile === undefined ? {} : { sessionFile: parsed.sessionFile }),
100
153
  ...(parsed.secretsFile === undefined ? {} : { secretsFile: parsed.secretsFile }),
101
154
  });
@@ -131,19 +184,6 @@ function secretsFor(adapter, parameters, projectDir, runtime) {
131
184
  }
132
185
  return Object.freeze(loadDeclaredSecrets(path, file));
133
186
  }
134
- async function loadDeployment(path) {
135
- const loaded = (await importModule(path));
136
- if (Object.keys(loaded).length !== 1 || !Object.hasOwn(loaded, 'default')) {
137
- throw new TypeError('astrale.config.ts must export exactly one default Deployment.');
138
- }
139
- const deployment = loaded.default;
140
- if (!isDeployment(deployment))
141
- throw new TypeError('Default export must be created by deploy().');
142
- return deployment;
143
- }
144
- function importModule(path) {
145
- return import(`${pathToFileURL(path).href}?sdk=${Date.now()}`);
146
- }
147
187
  function findConfig(projectDir) {
148
188
  return CONFIG_NAMES.map((name) => join(projectDir, name)).find(existsSync);
149
189
  }
@@ -0,0 +1,17 @@
1
+ import type { Application } from '../../application/index.js';
2
+ import type { Requirements } from '../../application/requirements/index.js';
3
+ import type { Routes } from '../../application/routes/index.js';
4
+ import type { Runtime } from '../../application/runtime/index.js';
5
+ import type { Frontend } from '../../application/view/index.js';
6
+ import type { Deployment } from '../../deployment/index.js';
7
+ import type { schema } from '../../platform/schema/index.js';
8
+ import type { Project, ProjectEnvironment } from '../../project/index.js';
9
+ import type { Tests } from '../../testing/index.js';
10
+ export type LoadedApplication = Application<schema.DomainSchema, Runtime, Frontend<schema.DomainSchema> | undefined, Routes | undefined, Requirements | undefined>;
11
+ export type LoadedDeployment = Deployment<object>;
12
+ export type LoadedEnvironment = ProjectEnvironment<LoadedDeployment>;
13
+ export type LoadedProject = Project<LoadedApplication, Readonly<Record<string, LoadedEnvironment>>, Tests | undefined>;
14
+ export declare function loadProject(path: string): Promise<LoadedProject>;
15
+ export declare function selectEnvironment(project: LoadedProject, name: string): LoadedEnvironment;
16
+ export declare function runtimeEntrypoint(project: LoadedProject): import("../../deployment/index.js").RuntimeReference;
17
+ export declare function importModule(path: string): Promise<unknown>;
@@ -0,0 +1,18 @@
1
+ import { pathToFileURL } from 'node:url';
2
+ import { runtime } from '../../deployment/index.js';
3
+ import { admitProjectModule } from '../../project/index.js';
4
+ export async function loadProject(path) {
5
+ return admitProjectModule(await importModule(path));
6
+ }
7
+ export function selectEnvironment(project, name) {
8
+ if (Object.hasOwn(project.environments, name))
9
+ return project.environments[name];
10
+ const known = Object.keys(project.environments).sort();
11
+ throw new TypeError(`Project has no Environment ${name}; known Environments: ${known.join(', ') || '(none)'}.`);
12
+ }
13
+ export function runtimeEntrypoint(project) {
14
+ return runtime(project.entrypoints?.runtime ?? './runtime.ts');
15
+ }
16
+ export function importModule(path) {
17
+ return import(`${pathToFileURL(path).href}?sdk=${Date.now()}`);
18
+ }
@@ -0,0 +1,12 @@
1
+ import { spawn } from 'node:child_process';
2
+ export interface TestExecution {
3
+ readonly environment?: string;
4
+ readonly suite?: string;
5
+ }
6
+ interface TestRunner {
7
+ readonly executable: string;
8
+ readonly arguments: readonly string[];
9
+ }
10
+ /** Run the Project's ordinary test runner, optionally targeting one observed Environment. */
11
+ export declare function executeTests(input: TestExecution, start?: typeof spawn, runner?: TestRunner): Promise<number>;
12
+ export {};
@@ -0,0 +1,47 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { createRequire } from 'node:module';
3
+ import { dirname, isAbsolute, join, resolve } from 'node:path';
4
+ /** Run the Project's ordinary test runner, optionally targeting one observed Environment. */
5
+ export function executeTests(input, start = spawn, runner = projectVitest()) {
6
+ const arguments_ = ['run', '--config', 'vitest.config.ts'];
7
+ if (input.suite !== undefined)
8
+ arguments_.push('--project', input.suite);
9
+ const environment = { ...process.env };
10
+ if (input.environment === undefined)
11
+ delete environment.ASTRALE_PROJECT_ENVIRONMENT;
12
+ else
13
+ environment.ASTRALE_PROJECT_ENVIRONMENT = input.environment;
14
+ return new Promise((resolve, reject) => {
15
+ const child = start(runner.executable, [...runner.arguments, ...arguments_], {
16
+ stdio: 'inherit',
17
+ env: environment,
18
+ });
19
+ child.once('error', reject);
20
+ child.once('close', (code, signal) => {
21
+ if (signal !== null) {
22
+ reject(new Error(`Project tests stopped by ${signal}.`));
23
+ }
24
+ else {
25
+ resolve(code ?? 1);
26
+ }
27
+ });
28
+ });
29
+ }
30
+ function projectVitest() {
31
+ const projectRequire = createRequire(join(process.cwd(), 'package.json'));
32
+ const manifestPath = projectRequire.resolve('vitest/package.json');
33
+ const manifest = projectRequire(manifestPath);
34
+ const relative = typeof manifest.bin === 'string' ? manifest.bin : manifest.bin?.vitest;
35
+ if (relative === undefined ||
36
+ relative.length === 0 ||
37
+ isAbsolute(relative) ||
38
+ relative.split(/[\\/]/u).includes('..')) {
39
+ throw new TypeError('Project Vitest package has no contained executable.');
40
+ }
41
+ return Object.freeze({
42
+ executable: process.versions.bun === undefined
43
+ ? process.execPath
44
+ : (process.env.npm_node_execpath ?? 'node'),
45
+ arguments: Object.freeze([resolve(dirname(manifestPath), relative)]),
46
+ });
47
+ }
@@ -0,0 +1,6 @@
1
+ export interface UpgradeOptions {
2
+ readonly cwd: string;
3
+ readonly channel: string;
4
+ readonly check: boolean;
5
+ }
6
+ export declare function upgrade(options: UpgradeOptions): Promise<void>;
@@ -0,0 +1,115 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readFile, realpath, writeFile } from 'node:fs/promises';
3
+ import { isAbsolute, join, relative } from 'node:path';
4
+ import { failureMessage } from '../failure.js';
5
+ import { projectRoot, readManifest, record, registryDependency, updatedManifest, } from './manifest.js';
6
+ import { runPnpm } from './process.js';
7
+ export async function upgrade(options) {
8
+ const root = await realpath(projectRoot(options.cwd));
9
+ const rootManifest = await readManifest(root);
10
+ const rootValue = JSON.parse(rootManifest.source);
11
+ const manager = record(rootValue) ? rootValue.packageManager : undefined;
12
+ if (manager !== undefined
13
+ ? typeof manager !== 'string' || !manager.startsWith('pnpm@')
14
+ : !existsSync(join(root, 'pnpm-workspace.yaml')) && !existsSync(join(root, 'pnpm-lock.yaml'))) {
15
+ throw new Error('Upgrade currently supports pnpm projects only. Declare packageManager: "pnpm@<version>" in package.json.');
16
+ }
17
+ const directories = new Set([root]);
18
+ if (existsSync(join(root, 'pnpm-workspace.yaml'))) {
19
+ const inventory = JSON.parse(await runPnpm(root, [
20
+ '--recursive',
21
+ '--include-workspace-root',
22
+ 'list',
23
+ '--depth',
24
+ '-1',
25
+ '--json',
26
+ ]));
27
+ if (!Array.isArray(inventory))
28
+ throw new Error('Invalid pnpm workspace inventory.');
29
+ for (const entry of inventory) {
30
+ if (!record(entry) || typeof entry.path !== 'string' || !isAbsolute(entry.path))
31
+ throw new Error('Invalid pnpm workspace path.');
32
+ const directory = await realpath(entry.path);
33
+ const offset = relative(root, directory);
34
+ if (offset === '..' ||
35
+ offset.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`) ||
36
+ isAbsolute(offset)) {
37
+ throw new Error(`Workspace package is outside ${root}: ${entry.path}.`);
38
+ }
39
+ directories.add(directory);
40
+ }
41
+ }
42
+ const manifests = await Promise.all([...directories].sort().map(readManifest));
43
+ const names = new Set();
44
+ const skipped = new Set();
45
+ for (const manifest of manifests) {
46
+ for (const dependency of manifest.dependencies) {
47
+ if (registryDependency(dependency.value))
48
+ names.add(dependency.name);
49
+ else
50
+ skipped.add(`${dependency.name}: ${dependency.value} (left unchanged)`);
51
+ }
52
+ }
53
+ const versions = new Map();
54
+ const queue = [...names].sort();
55
+ // Resolve the complete plan before writing. Each package's tag is observed once.
56
+ for (let offset = 0; offset < queue.length; offset += 4) {
57
+ await Promise.all(queue.slice(offset, offset + 4).map(async (name) => {
58
+ const tags = JSON.parse(await runPnpm(root, ['view', name, 'dist-tags', '--json']));
59
+ if (!record(tags))
60
+ throw new Error(`Invalid registry dist-tags for ${name}.`);
61
+ const version = tags[options.channel];
62
+ if (version === undefined)
63
+ skipped.add(`${name}: no ${options.channel} tag (left unchanged)`);
64
+ else if (typeof version !== 'string' ||
65
+ !/^\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?$/u.test(version)) {
66
+ throw new Error(`Invalid ${options.channel} version for ${name}.`);
67
+ }
68
+ else
69
+ versions.set(name, version);
70
+ }));
71
+ }
72
+ process.stdout.write(`Astrale upgrade · ${options.channel}\nWorkspace: ${root}\n`);
73
+ for (const warning of [...skipped].sort())
74
+ process.stdout.write(`Skipped: ${warning}\n`);
75
+ const changes = manifests
76
+ .map((manifest) => ({ manifest, source: updatedManifest(manifest, versions) }))
77
+ .filter(({ manifest, source }) => manifest.source !== source);
78
+ for (const { manifest } of changes) {
79
+ for (const dependency of manifest.dependencies) {
80
+ const next = registryDependency(dependency.value) ? versions.get(dependency.name) : undefined;
81
+ if (next !== undefined && next !== dependency.value)
82
+ process.stdout.write(`${relative(root, manifest.path)} · ${dependency.name}: ${dependency.value} → ${next}\n`);
83
+ }
84
+ }
85
+ if (changes.length === 0) {
86
+ process.stdout.write('No dependency changes.\n');
87
+ }
88
+ if (options.check) {
89
+ process.stdout.write('Check only: no project files changed; nothing installed.\n');
90
+ return;
91
+ }
92
+ if (versions.size === 0) {
93
+ process.stdout.write('No matching registry versions; nothing installed.\n');
94
+ return;
95
+ }
96
+ for (const { manifest } of changes) {
97
+ if ((await readFile(manifest.path, 'utf8')) !== manifest.source)
98
+ throw new Error(`Manifest changed during upgrade: ${manifest.path}. Retry against the current files.`);
99
+ }
100
+ for (const { manifest, source } of changes)
101
+ await writeFile(manifest.path, source);
102
+ try {
103
+ await runPnpm(root, ['install', '--no-frozen-lockfile'], true);
104
+ }
105
+ catch (cause) {
106
+ throw new Error(`${failureMessage(cause)}\nDependency installation failed. Local changes remain; repair and run pnpm install. Nothing committed or deployed.`, { cause });
107
+ }
108
+ process.stdout.write("Dependencies installed. Run your project's typecheck, lint, tests, and build before deploying. Nothing committed or deployed.\n");
109
+ if (changes.some(({ manifest }) => manifest.dependencies.some(({ name, value }) => name === '@astrale-domains/shell' &&
110
+ registryDependency(value) &&
111
+ versions.has(name) &&
112
+ versions.get(name) !== value))) {
113
+ process.stdout.write('Shell changed: verify the installed Shell revision before deploying dependent Domains.\n');
114
+ }
115
+ }
@@ -0,0 +1,18 @@
1
+ export interface Dependency {
2
+ readonly name: string;
3
+ readonly value: string;
4
+ readonly start: number;
5
+ readonly end: number;
6
+ }
7
+ export interface Manifest {
8
+ readonly path: string;
9
+ readonly source: string;
10
+ readonly dependencies: readonly Dependency[];
11
+ }
12
+ export declare function record(value: unknown): value is Record<string, unknown>;
13
+ /** Find a declared workspace without escaping an enclosing repository. */
14
+ export declare function projectRoot(cwd: string): string;
15
+ export declare function readManifest(directory: string): Promise<Manifest>;
16
+ export declare function registryDependency(value: string): boolean;
17
+ /** Replace only dependency value tokens; preserve formatting and all unrelated content. */
18
+ export declare function updatedManifest(manifest: Manifest, versions: ReadonlyMap<string, string>): string;
@@ -0,0 +1,77 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import ts from 'typescript';
5
+ const SECTIONS = new Set(['dependencies', 'devDependencies', 'optionalDependencies']);
6
+ export function record(value) {
7
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
8
+ }
9
+ /** Find a declared workspace without escaping an enclosing repository. */
10
+ export function projectRoot(cwd) {
11
+ let directory = resolve(cwd);
12
+ let nearest;
13
+ for (;;) {
14
+ if (existsSync(join(directory, 'pnpm-workspace.yaml')))
15
+ return directory;
16
+ if (nearest === undefined && existsSync(join(directory, 'package.json')))
17
+ nearest = directory;
18
+ if (existsSync(join(directory, '.git')) || dirname(directory) === directory)
19
+ break;
20
+ directory = dirname(directory);
21
+ }
22
+ if (nearest === undefined)
23
+ throw new Error(`No package.json found from ${cwd}.`);
24
+ return nearest;
25
+ }
26
+ export async function readManifest(directory) {
27
+ const path = join(directory, 'package.json');
28
+ const source = await readFile(path, 'utf8');
29
+ const value = JSON.parse(source);
30
+ if (!record(value))
31
+ throw new Error(`Invalid package manifest: ${path}.`);
32
+ const tree = ts.parseJsonText(path, source);
33
+ const statement = tree.statements[0];
34
+ if (!statement ||
35
+ !ts.isExpressionStatement(statement) ||
36
+ !ts.isObjectLiteralExpression(statement.expression)) {
37
+ throw new Error(`Invalid package manifest: ${path}.`);
38
+ }
39
+ const dependencies = [];
40
+ for (const section of statement.expression.properties) {
41
+ if (!ts.isPropertyAssignment(section) || !SECTIONS.has(section.name.getText(tree).slice(1, -1)))
42
+ continue;
43
+ if (!ts.isObjectLiteralExpression(section.initializer))
44
+ throw new Error(`Invalid dependency section in ${path}.`);
45
+ for (const property of section.initializer.properties) {
46
+ if (!ts.isPropertyAssignment(property) || !ts.isStringLiteral(property.name))
47
+ continue;
48
+ const name = property.name.text;
49
+ if (!name.startsWith('@astrale-os/') && !name.startsWith('@astrale-domains/'))
50
+ continue;
51
+ if (!ts.isStringLiteral(property.initializer))
52
+ throw new Error(`Invalid dependency ${name} in ${path}.`);
53
+ dependencies.push({
54
+ name,
55
+ value: property.initializer.text,
56
+ start: property.initializer.getStart(tree),
57
+ end: property.initializer.end,
58
+ });
59
+ }
60
+ }
61
+ return { path, source, dependencies };
62
+ }
63
+ export function registryDependency(value) {
64
+ return value.length > 0 && !/[:/\\#]/u.test(value) && !value.endsWith('.tgz');
65
+ }
66
+ /** Replace only dependency value tokens; preserve formatting and all unrelated content. */
67
+ export function updatedManifest(manifest, versions) {
68
+ let result = manifest.source;
69
+ for (const dependency of [...manifest.dependencies].reverse()) {
70
+ const version = registryDependency(dependency.value) ? versions.get(dependency.name) : undefined;
71
+ if (version !== undefined && version !== dependency.value) {
72
+ result =
73
+ result.slice(0, dependency.start) + JSON.stringify(version) + result.slice(dependency.end);
74
+ }
75
+ }
76
+ return result;
77
+ }
@@ -0,0 +1,2 @@
1
+ /** pnpm owns registry configuration, installation policy, and lockfile resolution. */
2
+ export declare function runPnpm(cwd: string, args: readonly string[], install?: boolean): Promise<string>;