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

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 (272) 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 +12 -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/deprecations.d.ts +9 -0
  183. package/dist/tooling/cli/deprecations.js +15 -0
  184. package/dist/tooling/cli/development/candidate.d.ts +25 -0
  185. package/dist/tooling/cli/development/candidate.js +176 -0
  186. package/dist/tooling/cli/development/deployment.d.ts +16 -0
  187. package/dist/tooling/cli/development/deployment.js +39 -0
  188. package/dist/tooling/cli/development/develop.d.ts +4 -3
  189. package/dist/tooling/cli/development/develop.js +129 -290
  190. package/dist/tooling/cli/development/lease.d.ts +18 -0
  191. package/dist/tooling/cli/development/lease.js +163 -0
  192. package/dist/tooling/cli/development/lifecycle.js +4 -0
  193. package/dist/tooling/cli/development/project-imports.d.ts +22 -0
  194. package/dist/tooling/cli/development/project-imports.js +39 -0
  195. package/dist/tooling/cli/development/project-lock.d.ts +3 -4
  196. package/dist/tooling/cli/development/project-lock.js +14 -166
  197. package/dist/tooling/cli/development/release-evidence.d.ts +4 -0
  198. package/dist/tooling/cli/development/release-evidence.js +10 -0
  199. package/dist/tooling/cli/development/report.d.ts +6 -0
  200. package/dist/tooling/cli/development/report.js +14 -0
  201. package/dist/tooling/cli/development/source-watch.js +53 -5
  202. package/dist/tooling/cli/development/sources.d.ts +7 -0
  203. package/dist/tooling/cli/development/sources.js +48 -0
  204. package/dist/tooling/cli/development/target-lock.d.ts +16 -0
  205. package/dist/tooling/cli/development/target-lock.js +68 -0
  206. package/dist/tooling/cli/development/view.d.ts +28 -0
  207. package/dist/tooling/cli/development/view.js +151 -0
  208. package/dist/tooling/cli/environment-release.d.ts +21 -0
  209. package/dist/tooling/cli/environment-release.js +46 -0
  210. package/dist/tooling/cli/evidence.d.ts +11 -0
  211. package/dist/tooling/cli/evidence.js +53 -0
  212. package/dist/tooling/cli/help.js +78 -34
  213. package/dist/tooling/cli/index.d.ts +1 -1
  214. package/dist/tooling/cli/index.js +1 -1
  215. package/dist/tooling/cli/installation/index.d.ts +2 -0
  216. package/dist/tooling/cli/installation/index.js +1 -0
  217. package/dist/tooling/cli/installation/observation.d.ts +10 -0
  218. package/dist/tooling/cli/installation/observation.js +44 -0
  219. package/dist/tooling/cli/installation/reconcile.d.ts +32 -0
  220. package/dist/tooling/cli/installation/reconcile.js +122 -0
  221. package/dist/tooling/cli/orchestrate.js +88 -45
  222. package/dist/tooling/cli/project.d.ts +17 -0
  223. package/dist/tooling/cli/project.js +18 -0
  224. package/dist/tooling/cli/test.d.ts +12 -0
  225. package/dist/tooling/cli/test.js +47 -0
  226. package/dist/tooling/cli/upgrade/index.d.ts +6 -0
  227. package/dist/tooling/cli/upgrade/index.js +115 -0
  228. package/dist/tooling/cli/upgrade/manifest.d.ts +18 -0
  229. package/dist/tooling/cli/upgrade/manifest.js +77 -0
  230. package/dist/tooling/cli/upgrade/process.d.ts +2 -0
  231. package/dist/tooling/cli/upgrade/process.js +57 -0
  232. package/dist/tooling/linter/adapters/typescript/imports.js +2 -0
  233. package/dist/tooling/linter/adapters/typescript/index.d.ts +1 -0
  234. package/dist/tooling/linter/adapters/typescript/index.js +1 -0
  235. package/dist/tooling/linter/adapters/typescript/query-collection-type.js +4 -51
  236. package/dist/tooling/linter/adapters/typescript/type-analysis.d.ts +9 -0
  237. package/dist/tooling/linter/adapters/typescript/type-analysis.js +55 -0
  238. package/dist/tooling/linter/implementations/source/callable-requirements.d.ts +28 -0
  239. package/dist/tooling/linter/implementations/source/callable-requirements.js +234 -0
  240. package/dist/tooling/linter/implementations/source/dependencies.d.ts +2 -0
  241. package/dist/tooling/linter/implementations/source/dependencies.js +219 -0
  242. package/dist/tooling/linter/implementations/source/global.js +52 -2
  243. package/dist/tooling/linter/implementations/source/mutations.js +520 -38
  244. package/dist/tooling/linter/implementations/source/providers.js +19 -164
  245. package/dist/tooling/linter/implementations/source/schema.js +454 -2
  246. package/dist/tooling/linter/implementations/source/verifiers.js +2 -0
  247. package/dist/tooling/linter/implementations/source/workflows.js +8 -35
  248. package/dist/tooling/linter/policy/generated.js +2 -2
  249. package/dist/tooling/linter/requirements/registry.js +9 -3
  250. package/dist/tooling/packaging/declarations/normalize.js +3 -38
  251. package/dist/tooling/packaging/declarations/paths.d.ts +5 -0
  252. package/dist/tooling/packaging/declarations/paths.js +38 -0
  253. package/dist/tooling/packaging/finalize.d.ts +13 -0
  254. package/dist/tooling/packaging/finalize.js +62 -0
  255. package/dist/tooling/packaging/index.d.ts +2 -0
  256. package/dist/tooling/packaging/index.js +1 -0
  257. package/dist/tooling/packaging/javascript.d.ts +3 -0
  258. package/dist/tooling/packaging/javascript.js +45 -2
  259. package/dist/tooling/packaging/packaging.d.ts +2 -5
  260. package/dist/tooling/packaging/packaging.js +6 -30
  261. package/package.json +42 -12
  262. package/CHANGELOG.md +0 -1506
  263. package/dist/deployment/adapter/development/context.d.ts +0 -18
  264. package/dist/deployment/adapter/development/index.d.ts +0 -4
  265. package/dist/deployment/adapter/development/input.d.ts +0 -6
  266. package/dist/deployment/adapter/development/placement.d.ts +0 -15
  267. package/dist/deployment/adapter/development/session.d.ts +0 -9
  268. /package/dist/{deployment/adapter/development → application/dependency}/index.js +0 -0
  269. /package/dist/{deployment/adapter/development/context.js → application/dependency/invoker.js} +0 -0
  270. /package/dist/{deployment/adapter/development/input.js → application/integration/authentication.js} +0 -0
  271. /package/dist/{deployment/adapter/development/placement.js → application/integration/authentication.typecheck.d.ts} +0 -0
  272. /package/dist/{deployment/adapter/development/session.js → application/runtime/declarations.js} +0 -0
@@ -1,27 +1,37 @@
1
- import { existsSync } from 'node:fs';
2
- import { mkdir, rm, rmdir, writeFile } from 'node:fs/promises';
3
- import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
4
- import { pathToFileURL } from 'node:url';
5
- import { admitRuntime, compile, isDeployment, resolveRuntime, verifyPreflight, } from '../../../deployment/index.js';
6
- import { addressing, assemble } from '../../../deployment/release/index.js';
7
- import { loadDeclaredSecrets, loadPrivateSecretsFile } from '../dotenv.js';
8
- import { error, info } from '../log.js';
1
+ import { rm, rmdir } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { resolveAstraleInstanceIssuer } from '../astrale/instance.js';
4
+ import { resolveCompatibleAstrale } from '../astrale/version.js';
5
+ import { loadPrivateCredentialFile } from '../credential.js';
6
+ import { deprecationWarnings } from '../deprecations.js';
7
+ import { loadPrivateSecretsFile } from '../dotenv.js';
8
+ import { error, info, warn } from '../log.js';
9
+ import { DevelopmentCandidateBuilder, discoverRuntimePath, sameDeploymentCandidate, sameEnvironment, } from './candidate.js';
10
+ import { deployDevelopmentCandidate } from './deployment.js';
9
11
  import { DevelopmentLifecycle } from './lifecycle.js';
10
12
  import { acquireProjectLock } from './project-lock.js';
11
13
  import { LatestRebuild } from './rebuild.js';
12
- import { DevelopmentSessionFileError, DevelopmentSessionFileWriter } from './session-file.js';
14
+ import { developmentReleaseEvidence } from './release-evidence.js';
15
+ import { reportDevelopmentDeployment } from './report.js';
16
+ import { DevelopmentSessionFileWriter } from './session-file.js';
13
17
  import { watchSources } from './source-watch.js';
14
- /** Run one complete provider-neutral development session until interruption. */
18
+ import { acquireDevelopmentTargetLock } from './target-lock.js';
19
+ import { DevelopmentView } from './view.js';
20
+ /** Watch one Project Environment and serialize complete remote deployment generations. */
15
21
  export async function develop(input) {
16
22
  const lifecycle = new DevelopmentLifecycle();
17
23
  let sessionFile;
18
24
  let lock;
19
- let session;
25
+ let targetLock;
26
+ let view;
27
+ let installationExecutable;
28
+ let installationIssuer;
20
29
  let sourceWatch;
21
30
  let rebuild;
31
+ let current;
32
+ let lastEvidence;
22
33
  let failure;
23
- let failed = false;
24
- let watcherFailure;
34
+ const cleanup = [];
25
35
  try {
26
36
  if (input.sessionFile !== undefined) {
27
37
  sessionFile = await DevelopmentSessionFileWriter.create(input.sessionFile);
@@ -33,103 +43,110 @@ export async function develop(input) {
33
43
  const overrideSecrets = input.secretsFile === undefined
34
44
  ? undefined
35
45
  : Object.freeze(loadPrivateSecretsFile(input.secretsFile));
46
+ const credential = input.credentialFile === undefined
47
+ ? undefined
48
+ : loadPrivateCredentialFile(input.credentialFile);
36
49
  const runtimePath = await discoverRuntimePath(input.configPath);
37
- const builder = new ProjectBuilder({ ...input, runtimePath, overrideSecrets });
38
- let current = await builder.prepare(lifecycle.signal);
39
- let sessionEvidence;
40
- let placementReady = false;
41
- let rebuildActive = false;
42
- let updatePrevious;
43
- let placementSequence = 0;
44
- const publishSessionPhase = async () => {
45
- if (sessionFile === undefined || sessionEvidence === undefined)
46
- return;
47
- await sessionFile.transition(placementReady ? (rebuildActive ? 'updating' : 'ready') : 'recovering', sessionEvidence);
48
- };
49
- const adapter = current.adapter;
50
- const parameters = current.parameters;
51
- let restartReported = false;
52
- info(`Domain: ${current.artifact.build.schema.compiled.root.origin}`);
53
- session = await adapter.develop(parameters, {
54
- projectDir: input.projectDir,
55
- environment: input.environment,
56
- artifact: current.artifact,
57
- secrets: current.secrets,
58
- overrides: input.overrides,
59
- signal: lifecycle.signal,
60
- async onRecovering() {
61
- placementReady = false;
62
- await publishSessionPhase();
63
- },
64
- async onPlacement(placement) {
65
- if (sessionFile !== undefined) {
66
- sessionEvidence = coherentSessionEvidence(updatePrevious === undefined ? [current.artifact] : [current.artifact, updatePrevious], placement);
67
- placementReady = true;
68
- placementSequence += 1;
69
- await publishSessionPhase();
70
- }
71
- info(`Public: ${placement.releaseUrl}`);
72
- if (placement.localUrl !== undefined)
73
- info(`Runtime: ${placement.localUrl}`);
74
- },
50
+ const builder = new DevelopmentCandidateBuilder({
51
+ ...input,
52
+ runtimePath,
53
+ overrideSecrets,
75
54
  });
55
+ current = await builder.prepare(lifecycle.signal);
56
+ if (credential !== undefined && current.installation?.identity !== undefined) {
57
+ throw new TypeError('--credential-file cannot be combined with the Environment installation identity.');
58
+ }
59
+ if (sessionFile !== undefined && (current.installation === undefined || input.deployOnly)) {
60
+ throw new TypeError('--session-file requires an Environment installation that is active for this development session.');
61
+ }
62
+ info(`Domain: ${current.artifact.build.schema.compiled.root.origin}`);
63
+ for (const warning of deprecationWarnings(current.artifact.build))
64
+ warn(warning);
65
+ if (current.installation !== undefined && !input.deployOnly) {
66
+ installationExecutable = await resolveCompatibleAstrale({
67
+ projectDir: input.projectDir,
68
+ signal: lifecycle.signal,
69
+ });
70
+ installationIssuer = await resolveAstraleInstanceIssuer({
71
+ executable: installationExecutable,
72
+ projectDir: input.projectDir,
73
+ instance: current.installation.instance,
74
+ signal: lifecycle.signal,
75
+ });
76
+ targetLock = await acquireDevelopmentTargetLock({
77
+ issuer: installationIssuer,
78
+ origin: current.artifact.build.schema.compiled.root.origin,
79
+ });
80
+ view = new DevelopmentView({
81
+ executable: installationExecutable,
82
+ projectDir: input.projectDir,
83
+ instance: current.installation.instance,
84
+ ...(credential === undefined
85
+ ? { identity: input.identity ?? current.installation.identity }
86
+ : { credential }),
87
+ });
88
+ if (current.artifact.build.frontend !== undefined)
89
+ await view.prepare(lifecycle.signal);
90
+ }
91
+ const first = await deployDevelopmentCandidate(current, { ...input, credential, installationExecutable }, lifecycle.signal);
92
+ lastEvidence =
93
+ first.installation === undefined ? undefined : developmentReleaseEvidence(first.installation);
94
+ await sessionFile?.transition('ready', lastEvidence);
95
+ reportDevelopmentDeployment(first.deployment, first.installation, current.adapter, input);
96
+ await refreshView(view, first.deployment.release, lifecycle.signal);
97
+ let restartReported = false;
76
98
  rebuild = new LatestRebuild({
77
99
  async prepare(_ignored, signal) {
78
- rebuildActive = true;
79
- await publishSessionPhase();
100
+ info(`Rebuilding: ${input.environment}`);
101
+ if (lastEvidence !== undefined)
102
+ await sessionFile?.transition('updating', lastEvidence);
80
103
  return builder.prepare(signal);
81
104
  },
82
- async commit(candidate) {
83
- if (candidate.adapter.name !== adapter.name ||
84
- candidate.adapter.version !== adapter.version ||
85
- stable(candidate.parameters) !== stable(parameters)) {
105
+ async commit(candidate, signal) {
106
+ if (!sameEnvironment(current, candidate)) {
86
107
  restartReported = true;
87
- throw new Error('Adapter configuration changed; restart pnpm dev to apply it.');
108
+ throw new Error('Project Environment configuration changed; restart pnpm dev to apply it.');
88
109
  }
89
- const previous = current;
90
- const beforePlacement = placementSequence;
91
- updatePrevious = previous.artifact;
92
- current = candidate;
93
- try {
94
- await session.update({ artifact: candidate.artifact, secrets: candidate.secrets });
95
- if (sessionFile !== undefined) {
96
- if (placementSequence === beforePlacement || sessionEvidence === undefined) {
97
- throw new DevelopmentSessionFileError('SESSION_FILE_EVIDENCE_INCOHERENT', 'Development adapter completed an update without reporting installed Release evidence.');
98
- }
99
- assertEvidenceMatches(candidate.artifact, sessionEvidence);
100
- }
101
- rebuildActive = false;
102
- await publishSessionPhase();
110
+ if (sameDeploymentCandidate(current, candidate)) {
111
+ current = candidate;
112
+ await sessionFile?.transition('ready', lastEvidence);
103
113
  sourceWatch?.update(candidate.sources);
104
- info(`Updated ${candidate.artifact.build.schema.compiled.root.revision}.`);
105
- }
106
- catch (cause) {
107
- current = previous;
108
- if (sessionFile !== undefined &&
109
- sessionEvidence !== undefined &&
110
- !evidenceMatches(previous.artifact, sessionEvidence)) {
111
- throw new DevelopmentSessionFileError('SESSION_FILE_EVIDENCE_INCOHERENT', 'Development adapter rejected an update without restoring prior installed Release evidence.', { cause });
112
- }
113
- throw cause;
114
+ return;
114
115
  }
115
- finally {
116
- updatePrevious = undefined;
116
+ if (installationIssuer !== undefined && candidate.installation !== undefined) {
117
+ await resolveAstraleInstanceIssuer({
118
+ executable: installationExecutable,
119
+ projectDir: input.projectDir,
120
+ instance: candidate.installation.instance,
121
+ expectedIssuer: installationIssuer,
122
+ signal,
123
+ });
117
124
  }
125
+ if (candidate.artifact.build.frontend !== undefined)
126
+ await view?.prepare(signal);
127
+ const deployed = await deployDevelopmentCandidate(candidate, { ...input, credential, installationExecutable }, signal);
128
+ current = candidate;
129
+ lastEvidence =
130
+ deployed.installation === undefined
131
+ ? undefined
132
+ : developmentReleaseEvidence(deployed.installation);
133
+ await sessionFile?.transition('ready', lastEvidence);
134
+ sourceWatch?.update(candidate.sources);
135
+ info(`Updated: ${candidate.artifact.build.schema.compiled.root.revision}`);
136
+ reportDevelopmentDeployment(deployed.deployment, deployed.installation, candidate.adapter, input);
137
+ await refreshView(view, deployed.deployment.release, signal);
118
138
  },
119
139
  async failed(cause) {
120
- rebuildActive = false;
121
- if (cause instanceof DevelopmentSessionFileError) {
122
- watcherFailure = cause;
123
- lifecycle.stop(cause);
124
- return;
125
- }
126
140
  error(cause instanceof Error ? cause.message : String(cause));
141
+ if (lastEvidence === undefined)
142
+ return;
127
143
  try {
128
- await publishSessionPhase();
144
+ await sessionFile?.transition('recovering', lastEvidence);
129
145
  }
130
146
  catch (sessionCause) {
131
- watcherFailure = sessionCause;
132
- lifecycle.stop(sessionCause);
147
+ const terminal = new AggregateError([cause, sessionCause], 'Development rebuild failed and session evidence could not be recovered.');
148
+ failure ??= terminal;
149
+ lifecycle.stop(terminal);
133
150
  }
134
151
  },
135
152
  });
@@ -142,46 +159,38 @@ export async function develop(input) {
142
159
  if (restartReported)
143
160
  return;
144
161
  restartReported = true;
145
- error('Adapter configuration changed; restart pnpm dev to apply it.');
162
+ error('Project Environment configuration changed; restart pnpm dev to apply it.');
146
163
  },
147
164
  onError: (cause) => {
148
- watcherFailure = cause;
165
+ failure = cause;
149
166
  lifecycle.stop(cause);
150
167
  },
151
168
  });
152
- const placement = session.current();
153
- info(`Ready: watching for changes (${placement.releaseUrl}).`);
154
- const completed = await Promise.race([
155
- session.finished.then(() => 'session'),
156
- lifecycle.stopped.then(() => 'signal'),
157
- ]);
158
- if (completed === 'session' && !lifecycle.signal.aborted) {
159
- throw new Error('Development provider stopped unexpectedly.');
160
- }
161
- if (watcherFailure !== undefined)
162
- throw watcherFailure;
169
+ info('Ready: watching for remote deployments');
170
+ // Edits made while the first build/deployment was in flight predate this watcher.
171
+ // Catch up once; artifact deduplication prevents an unchanged second deployment.
172
+ rebuild.invalidate();
173
+ await lifecycle.stopped;
163
174
  }
164
175
  catch (cause) {
165
- failed = true;
166
176
  failure = cause;
167
177
  }
168
178
  lifecycle.stop(failure);
169
- const cleanup = [];
170
179
  try {
171
- await sessionFile?.transition('stopping');
180
+ await sessionFile?.transition('stopping', lastEvidence);
172
181
  }
173
182
  catch (cause) {
174
- failed = true;
175
183
  failure ??= cause;
176
184
  }
177
185
  for (const operation of [
178
186
  () => sourceWatch?.stop(),
179
187
  () => rebuild?.stop(failure),
180
- () => session?.stop(),
188
+ () => view?.close(AbortSignal.timeout(30_000)),
181
189
  () => rm(join(input.projectDir, '.astrale', 'development', input.environment, 'source'), {
182
190
  recursive: true,
183
191
  force: true,
184
192
  }),
193
+ () => targetLock?.release(),
185
194
  () => lock?.release(),
186
195
  ]) {
187
196
  try {
@@ -205,13 +214,13 @@ export async function develop(input) {
205
214
  }
206
215
  }
207
216
  try {
208
- await sessionFile?.transition(failed || cleanup.length > 0 ? 'failed' : 'stopped');
217
+ await sessionFile?.transition(failure === undefined && cleanup.length === 0 ? 'stopped' : 'failed');
209
218
  }
210
219
  catch (cause) {
211
220
  cleanup.push(cause);
212
221
  }
213
222
  lifecycle.dispose();
214
- if (failed) {
223
+ if (failure !== undefined) {
215
224
  if (cleanup.length > 0)
216
225
  error(new AggregateError(cleanup, 'Development cleanup failed.').message);
217
226
  throw failure;
@@ -220,185 +229,15 @@ export async function develop(input) {
220
229
  throw new AggregateError(cleanup, 'Development cleanup failed.');
221
230
  return 0;
222
231
  }
223
- function coherentSessionEvidence(artifacts, placement) {
224
- const evidence = placement.installedRelease;
225
- if (evidence === undefined) {
226
- throw new DevelopmentSessionFileError('SESSION_FILE_EVIDENCE_INCOHERENT', '--session-file requires an adapter that reports exact installed Release evidence.');
227
- }
228
- let issuer;
229
- try {
230
- issuer = new URL(placement.releaseUrl).origin;
231
- }
232
- catch (cause) {
233
- throw new DevelopmentSessionFileError('SESSION_FILE_EVIDENCE_INCOHERENT', 'Development adapter reported an invalid Release URL.', { cause });
234
- }
235
- if (placement.releaseUrl !== issuer) {
236
- throw new DevelopmentSessionFileError('SESSION_FILE_EVIDENCE_INCOHERENT', 'Development adapter reported a non-canonical Release URL.');
237
- }
238
- let matches = false;
232
+ async function refreshView(view, release, signal) {
233
+ if (view === undefined)
234
+ return;
239
235
  try {
240
- matches = artifacts.some((artifact) => evidenceMatches(artifact, evidence));
236
+ const pageUrl = await view.refresh(release, signal);
237
+ if (pageUrl !== undefined)
238
+ info(`View: ${pageUrl}`);
241
239
  }
242
240
  catch (cause) {
243
- throw new DevelopmentSessionFileError('SESSION_FILE_EVIDENCE_INCOHERENT', 'Development adapter reported invalid installed Release evidence.', { cause });
244
- }
245
- if (evidence.issuer !== issuer || !matches) {
246
- throw new DevelopmentSessionFileError('SESSION_FILE_EVIDENCE_INCOHERENT', 'Development adapter installed Release evidence does not match the current artifact and placement.');
247
- }
248
- return evidence;
249
- }
250
- function assertEvidenceMatches(artifact, evidence) {
251
- if (!evidenceMatches(artifact, evidence)) {
252
- throw new DevelopmentSessionFileError('SESSION_FILE_EVIDENCE_INCOHERENT', 'Development adapter installed Release evidence does not match the committed artifact.');
253
- }
254
- }
255
- function evidenceMatches(artifact, evidence) {
256
- const root = artifact.build.schema.compiled.root;
257
- const release = assemble(artifact.build, addressing(evidence.issuer));
258
- return (evidence.origin === root.origin &&
259
- evidence.revision === root.revision &&
260
- evidence.etag === release.publication.etag);
261
- }
262
- class ProjectBuilder {
263
- #configPath;
264
- #projectDir;
265
- #environment;
266
- #runtimePath;
267
- #overrideSecrets;
268
- #generation = 0;
269
- constructor(input) {
270
- this.#configPath = input.configPath;
271
- this.#projectDir = input.projectDir;
272
- this.#environment = input.environment;
273
- this.#runtimePath = input.runtimePath;
274
- this.#overrideSecrets = input.overrideSecrets;
275
- }
276
- async prepare(signal) {
277
- throwIfAborted(signal);
278
- const directory = join(this.#projectDir, '.astrale', 'development', this.#environment, 'source', String(++this.#generation));
279
- await mkdir(directory, { recursive: true });
280
- const bridge = join(directory, 'bridge.ts');
281
- const configImport = moduleSpecifier(dirname(bridge), this.#configPath);
282
- const runtimeImport = moduleSpecifier(dirname(bridge), resolve(dirname(this.#configPath), this.#runtimePath));
283
- await writeFile(bridge, `export { default as deployment } from ${JSON.stringify(configImport)}\n` +
284
- `export { default as runtime } from ${JSON.stringify(runtimeImport)}\n`);
285
- try {
286
- const built = await bun().build({
287
- entrypoints: [bridge],
288
- outdir: directory,
289
- naming: 'application.mjs',
290
- target: 'bun',
291
- format: 'esm',
292
- packages: 'external',
293
- splitting: false,
294
- sourcemap: 'inline',
295
- metafile: true,
296
- });
297
- throwIfAborted(signal);
298
- const output = built.outputs.find((candidate) => candidate.path.endsWith('application.mjs'));
299
- if (output === undefined)
300
- throw new Error('Authored Application rebuild produced no module.');
301
- const loaded = (await import(`${pathToFileURL(output.path).href}?development=${this.#generation}`));
302
- if (Object.keys(loaded).some((key) => key !== 'deployment' && key !== 'runtime')) {
303
- throw new TypeError('Development bridge produced unexpected exports.');
304
- }
305
- const deployment = loaded.deployment;
306
- if (!isDeployment(deployment)) {
307
- throw new TypeError('astrale.config.ts default export must be created by deploy().');
308
- }
309
- const admitted = deployment;
310
- const resolved = await resolveRuntime(admitted.entrypoint, async (path) => {
311
- if (path !== this.#runtimePath) {
312
- throw new Error('Runtime entrypoint changed; restart pnpm dev to apply it.');
313
- }
314
- return Object.freeze({ default: loaded.runtime });
315
- });
316
- const build = compile(admitted.application);
317
- admitRuntime({ runtime: build.runtime }, resolved);
318
- const adapter = admitted.adapter;
319
- const parameters = adapter.parameters(this.#environment);
320
- const source = await adapter.prepare(parameters, {
321
- projectDir: this.#projectDir,
322
- environment: this.#environment,
323
- mode: 'development',
324
- build,
325
- runtime: resolved,
326
- });
327
- const artifact = verifyPreflight({ build, runtime: resolved, source });
328
- const declared = this.#overrideSecrets === undefined
329
- ? secretsFor(adapter, parameters, this.#projectDir, resolved.runtime)
330
- : { values: this.#overrideSecrets };
331
- const sources = new Set();
332
- for (const path of Object.keys(built.metafile?.inputs ?? {})) {
333
- const absolute = isAbsolute(path) ? path : resolve(this.#projectDir, path);
334
- if (!absolute.startsWith(`${resolve(this.#projectDir)}${sep}`))
335
- continue;
336
- if (absolute.includes(`${sep}.astrale${sep}`))
337
- continue;
338
- sources.add(absolute);
339
- }
340
- if (declared.path !== undefined)
341
- sources.add(declared.path);
342
- return Object.freeze({
343
- adapter,
344
- parameters,
345
- artifact,
346
- secrets: declared.values,
347
- sources,
348
- });
349
- }
350
- finally {
351
- await rm(directory, { recursive: true, force: true });
352
- }
353
- }
354
- }
355
- async function discoverRuntimePath(configPath) {
356
- const loaded = (await import(`${pathToFileURL(configPath).href}?discover=${Date.now()}`));
357
- if (Object.keys(loaded).length !== 1 || !Object.hasOwn(loaded, 'default')) {
358
- throw new TypeError('astrale.config.ts must export exactly one default Deployment.');
359
- }
360
- if (!isDeployment(loaded.default)) {
361
- throw new TypeError('Default export must be created by deploy().');
362
- }
363
- return loaded.default.entrypoint.path;
364
- }
365
- function secretsFor(adapter, parameters, projectDir, runtime) {
366
- const file = adapter.secretsFile?.(parameters);
367
- if (file === undefined)
368
- return { values: Object.freeze({}) };
369
- const path = isAbsolute(file) ? file : join(projectDir, file);
370
- // An Integration-free Runtime has no Providers and therefore no author-owned
371
- // environment secrets. Adapter-owned secrets, such as the signing identity,
372
- // are resolved separately by the adapter and must not make this file required.
373
- if (Object.keys(runtime.integrations).length === 0 && !existsSync(path)) {
374
- return { values: Object.freeze({}) };
375
- }
376
- return { values: Object.freeze(loadDeclaredSecrets(path, file)), path };
377
- }
378
- function bun() {
379
- const value = Reflect.get(globalThis, 'Bun');
380
- if (value === undefined || typeof value.build !== 'function') {
381
- throw new TypeError('Domain development requires the Bun runtime.');
382
- }
383
- return value;
384
- }
385
- function moduleSpecifier(from, target) {
386
- const path = relative(from, target).split(sep).join('/');
387
- return path.startsWith('.') ? path : `./${path}`;
388
- }
389
- function stable(input) {
390
- if (input === null || typeof input !== 'object')
391
- return JSON.stringify(input);
392
- if (Array.isArray(input))
393
- return `[${input.map(stable).join(',')}]`;
394
- const record = input;
395
- return `{${Object.keys(record)
396
- .sort()
397
- .map((key) => `${JSON.stringify(key)}:${stable(record[key])}`)
398
- .join(',')}}`;
399
- }
400
- function throwIfAborted(signal) {
401
- if (signal.aborted) {
402
- throw signal.reason instanceof Error ? signal.reason : new Error('Development interrupted.');
241
+ error(`View unavailable: ${cause instanceof Error ? cause.message : String(cause)}`);
403
242
  }
404
243
  }
@@ -0,0 +1,18 @@
1
+ export declare class DevelopmentLeaseError extends Error {
2
+ readonly code: 'DEVELOPMENT_LEASE_LOCKED' | 'DEVELOPMENT_LEASE_LOST';
3
+ readonly name = "DevelopmentLeaseError";
4
+ constructor(code: 'DEVELOPMENT_LEASE_LOCKED' | 'DEVELOPMENT_LEASE_LOST', message: string, options?: ErrorOptions);
5
+ }
6
+ export interface DevelopmentLease {
7
+ readonly path: string;
8
+ readonly recovered: boolean;
9
+ release(): Promise<void>;
10
+ }
11
+ /** One fail-closed filesystem lease engine for every local development coordinate. */
12
+ export declare function acquireDevelopmentLease(input: {
13
+ readonly directory: string;
14
+ readonly coordinate: string;
15
+ readonly pid?: number;
16
+ readonly sessionId?: string;
17
+ readonly processAlive?: (pid: number) => boolean;
18
+ }): Promise<DevelopmentLease>;