@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
@@ -1,27 +1,36 @@
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';
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 { loadPrivateSecretsFile } from '../dotenv.js';
8
7
  import { error, info } from '../log.js';
8
+ import { DevelopmentCandidateBuilder, discoverRuntimePath, sameDeploymentCandidate, sameEnvironment, } from './candidate.js';
9
+ import { deployDevelopmentCandidate } from './deployment.js';
9
10
  import { DevelopmentLifecycle } from './lifecycle.js';
10
11
  import { acquireProjectLock } from './project-lock.js';
11
12
  import { LatestRebuild } from './rebuild.js';
12
- import { DevelopmentSessionFileError, DevelopmentSessionFileWriter } from './session-file.js';
13
+ import { developmentReleaseEvidence } from './release-evidence.js';
14
+ import { reportDevelopmentDeployment } from './report.js';
15
+ import { DevelopmentSessionFileWriter } from './session-file.js';
13
16
  import { watchSources } from './source-watch.js';
14
- /** Run one complete provider-neutral development session until interruption. */
17
+ import { acquireDevelopmentTargetLock } from './target-lock.js';
18
+ import { DevelopmentView } from './view.js';
19
+ /** Watch one Project Environment and serialize complete remote deployment generations. */
15
20
  export async function develop(input) {
16
21
  const lifecycle = new DevelopmentLifecycle();
17
22
  let sessionFile;
18
23
  let lock;
19
- let session;
24
+ let targetLock;
25
+ let view;
26
+ let installationExecutable;
27
+ let installationIssuer;
20
28
  let sourceWatch;
21
29
  let rebuild;
30
+ let current;
31
+ let lastEvidence;
22
32
  let failure;
23
- let failed = false;
24
- let watcherFailure;
33
+ const cleanup = [];
25
34
  try {
26
35
  if (input.sessionFile !== undefined) {
27
36
  sessionFile = await DevelopmentSessionFileWriter.create(input.sessionFile);
@@ -33,103 +42,108 @@ export async function develop(input) {
33
42
  const overrideSecrets = input.secretsFile === undefined
34
43
  ? undefined
35
44
  : Object.freeze(loadPrivateSecretsFile(input.secretsFile));
45
+ const credential = input.credentialFile === undefined
46
+ ? undefined
47
+ : loadPrivateCredentialFile(input.credentialFile);
36
48
  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
- },
49
+ const builder = new DevelopmentCandidateBuilder({
50
+ ...input,
51
+ runtimePath,
52
+ overrideSecrets,
75
53
  });
54
+ current = await builder.prepare(lifecycle.signal);
55
+ if (credential !== undefined && current.installation?.identity !== undefined) {
56
+ throw new TypeError('--credential-file cannot be combined with the Environment installation identity.');
57
+ }
58
+ if (sessionFile !== undefined && (current.installation === undefined || input.deployOnly)) {
59
+ throw new TypeError('--session-file requires an Environment installation that is active for this development session.');
60
+ }
61
+ info(`Domain: ${current.artifact.build.schema.compiled.root.origin}`);
62
+ if (current.installation !== undefined && !input.deployOnly) {
63
+ installationExecutable = await resolveCompatibleAstrale({
64
+ projectDir: input.projectDir,
65
+ signal: lifecycle.signal,
66
+ });
67
+ installationIssuer = await resolveAstraleInstanceIssuer({
68
+ executable: installationExecutable,
69
+ projectDir: input.projectDir,
70
+ instance: current.installation.instance,
71
+ signal: lifecycle.signal,
72
+ });
73
+ targetLock = await acquireDevelopmentTargetLock({
74
+ issuer: installationIssuer,
75
+ origin: current.artifact.build.schema.compiled.root.origin,
76
+ });
77
+ view = new DevelopmentView({
78
+ executable: installationExecutable,
79
+ projectDir: input.projectDir,
80
+ instance: current.installation.instance,
81
+ ...(credential === undefined
82
+ ? { identity: input.identity ?? current.installation.identity }
83
+ : { credential }),
84
+ });
85
+ if (current.artifact.build.frontend !== undefined)
86
+ await view.prepare(lifecycle.signal);
87
+ }
88
+ const first = await deployDevelopmentCandidate(current, { ...input, credential, installationExecutable }, lifecycle.signal);
89
+ lastEvidence =
90
+ first.installation === undefined ? undefined : developmentReleaseEvidence(first.installation);
91
+ await sessionFile?.transition('ready', lastEvidence);
92
+ reportDevelopmentDeployment(first.deployment, first.installation, current.adapter, input);
93
+ await refreshView(view, first.deployment.release, lifecycle.signal);
94
+ let restartReported = false;
76
95
  rebuild = new LatestRebuild({
77
96
  async prepare(_ignored, signal) {
78
- rebuildActive = true;
79
- await publishSessionPhase();
97
+ info(`Rebuilding: ${input.environment}`);
98
+ if (lastEvidence !== undefined)
99
+ await sessionFile?.transition('updating', lastEvidence);
80
100
  return builder.prepare(signal);
81
101
  },
82
- async commit(candidate) {
83
- if (candidate.adapter.name !== adapter.name ||
84
- candidate.adapter.version !== adapter.version ||
85
- stable(candidate.parameters) !== stable(parameters)) {
102
+ async commit(candidate, signal) {
103
+ if (!sameEnvironment(current, candidate)) {
86
104
  restartReported = true;
87
- throw new Error('Adapter configuration changed; restart pnpm dev to apply it.');
105
+ throw new Error('Project Environment configuration changed; restart pnpm dev to apply it.');
88
106
  }
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();
107
+ if (sameDeploymentCandidate(current, candidate)) {
108
+ current = candidate;
109
+ await sessionFile?.transition('ready', lastEvidence);
103
110
  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;
111
+ return;
114
112
  }
115
- finally {
116
- updatePrevious = undefined;
113
+ if (installationIssuer !== undefined && candidate.installation !== undefined) {
114
+ await resolveAstraleInstanceIssuer({
115
+ executable: installationExecutable,
116
+ projectDir: input.projectDir,
117
+ instance: candidate.installation.instance,
118
+ expectedIssuer: installationIssuer,
119
+ signal,
120
+ });
117
121
  }
122
+ if (candidate.artifact.build.frontend !== undefined)
123
+ await view?.prepare(signal);
124
+ const deployed = await deployDevelopmentCandidate(candidate, { ...input, credential, installationExecutable }, signal);
125
+ current = candidate;
126
+ lastEvidence =
127
+ deployed.installation === undefined
128
+ ? undefined
129
+ : developmentReleaseEvidence(deployed.installation);
130
+ await sessionFile?.transition('ready', lastEvidence);
131
+ sourceWatch?.update(candidate.sources);
132
+ info(`Updated: ${candidate.artifact.build.schema.compiled.root.revision}`);
133
+ reportDevelopmentDeployment(deployed.deployment, deployed.installation, candidate.adapter, input);
134
+ await refreshView(view, deployed.deployment.release, signal);
118
135
  },
119
136
  async failed(cause) {
120
- rebuildActive = false;
121
- if (cause instanceof DevelopmentSessionFileError) {
122
- watcherFailure = cause;
123
- lifecycle.stop(cause);
124
- return;
125
- }
126
137
  error(cause instanceof Error ? cause.message : String(cause));
138
+ if (lastEvidence === undefined)
139
+ return;
127
140
  try {
128
- await publishSessionPhase();
141
+ await sessionFile?.transition('recovering', lastEvidence);
129
142
  }
130
143
  catch (sessionCause) {
131
- watcherFailure = sessionCause;
132
- lifecycle.stop(sessionCause);
144
+ const terminal = new AggregateError([cause, sessionCause], 'Development rebuild failed and session evidence could not be recovered.');
145
+ failure ??= terminal;
146
+ lifecycle.stop(terminal);
133
147
  }
134
148
  },
135
149
  });
@@ -142,46 +156,38 @@ export async function develop(input) {
142
156
  if (restartReported)
143
157
  return;
144
158
  restartReported = true;
145
- error('Adapter configuration changed; restart pnpm dev to apply it.');
159
+ error('Project Environment configuration changed; restart pnpm dev to apply it.');
146
160
  },
147
161
  onError: (cause) => {
148
- watcherFailure = cause;
162
+ failure = cause;
149
163
  lifecycle.stop(cause);
150
164
  },
151
165
  });
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;
166
+ info('Ready: watching for remote deployments');
167
+ // Edits made while the first build/deployment was in flight predate this watcher.
168
+ // Catch up once; artifact deduplication prevents an unchanged second deployment.
169
+ rebuild.invalidate();
170
+ await lifecycle.stopped;
163
171
  }
164
172
  catch (cause) {
165
- failed = true;
166
173
  failure = cause;
167
174
  }
168
175
  lifecycle.stop(failure);
169
- const cleanup = [];
170
176
  try {
171
- await sessionFile?.transition('stopping');
177
+ await sessionFile?.transition('stopping', lastEvidence);
172
178
  }
173
179
  catch (cause) {
174
- failed = true;
175
180
  failure ??= cause;
176
181
  }
177
182
  for (const operation of [
178
183
  () => sourceWatch?.stop(),
179
184
  () => rebuild?.stop(failure),
180
- () => session?.stop(),
185
+ () => view?.close(AbortSignal.timeout(30_000)),
181
186
  () => rm(join(input.projectDir, '.astrale', 'development', input.environment, 'source'), {
182
187
  recursive: true,
183
188
  force: true,
184
189
  }),
190
+ () => targetLock?.release(),
185
191
  () => lock?.release(),
186
192
  ]) {
187
193
  try {
@@ -205,13 +211,13 @@ export async function develop(input) {
205
211
  }
206
212
  }
207
213
  try {
208
- await sessionFile?.transition(failed || cleanup.length > 0 ? 'failed' : 'stopped');
214
+ await sessionFile?.transition(failure === undefined && cleanup.length === 0 ? 'stopped' : 'failed');
209
215
  }
210
216
  catch (cause) {
211
217
  cleanup.push(cause);
212
218
  }
213
219
  lifecycle.dispose();
214
- if (failed) {
220
+ if (failure !== undefined) {
215
221
  if (cleanup.length > 0)
216
222
  error(new AggregateError(cleanup, 'Development cleanup failed.').message);
217
223
  throw failure;
@@ -220,185 +226,15 @@ export async function develop(input) {
220
226
  throw new AggregateError(cleanup, 'Development cleanup failed.');
221
227
  return 0;
222
228
  }
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;
229
+ async function refreshView(view, release, signal) {
230
+ if (view === undefined)
231
+ return;
239
232
  try {
240
- matches = artifacts.some((artifact) => evidenceMatches(artifact, evidence));
233
+ const pageUrl = await view.refresh(release, signal);
234
+ if (pageUrl !== undefined)
235
+ info(`View: ${pageUrl}`);
241
236
  }
242
237
  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.');
238
+ error(`View unavailable: ${cause instanceof Error ? cause.message : String(cause)}`);
403
239
  }
404
240
  }
@@ -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>;