@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.
- package/README.md +165 -2
- package/dist/application/action/action.d.ts +7 -4
- package/dist/application/action/authoring.d.ts +2 -1
- package/dist/application/action/context.d.ts +18 -13
- package/dist/application/action/define.d.ts +5 -1
- package/dist/application/action/define.js +6 -1
- package/dist/application/action/index.d.ts +2 -1
- package/dist/application/dependency/index.d.ts +1 -0
- package/dist/application/dependency/invoker.d.ts +26 -0
- package/dist/application/error/error.d.ts +23 -0
- package/dist/application/error/error.js +87 -0
- package/dist/application/error/index.d.ts +2 -0
- package/dist/application/error/index.js +1 -0
- package/dist/application/index.d.ts +2 -2
- package/dist/application/integration/authentication.d.ts +10 -0
- package/dist/application/integration/authentication.typecheck.js +18 -0
- package/dist/application/integration/client.d.ts +2 -0
- package/dist/application/integration/client.js +19 -2
- package/dist/application/integration/index.d.ts +1 -0
- package/dist/application/integration/operation.d.ts +3 -0
- package/dist/application/mutation/authoring/builder.js +2 -2
- package/dist/application/mutation/authoring/endpoint.d.ts +3 -3
- package/dist/application/mutation/authoring/endpoint.js +9 -0
- package/dist/application/mutation/failure.js +13 -7
- package/dist/application/mutation/index.d.ts +1 -0
- package/dist/application/requirements/{profiles.d.ts → core.d.ts} +5 -3
- package/dist/application/requirements/{profiles.js → core.js} +6 -6
- package/dist/application/requirements/index.d.ts +4 -4
- package/dist/application/requirements/index.js +5 -5
- package/dist/application/requirements/requirement.d.ts +3 -2
- package/dist/application/runtime/authoring.d.ts +1 -0
- package/dist/application/runtime/callables.js +2 -2
- package/dist/application/runtime/declarations.d.ts +43 -0
- package/dist/application/runtime/define.d.ts +2 -1
- package/dist/application/view/index.d.ts +1 -1
- package/dist/application/view/route.d.ts +4 -0
- package/dist/application/view/route.js +5 -1
- package/dist/application/workflow/authoring.d.ts +1 -0
- package/dist/application/workflow/context.d.ts +2 -1
- package/dist/application/workflow/define.d.ts +5 -1
- package/dist/application/workflow/define.js +6 -1
- package/dist/application/workflow/index.d.ts +1 -0
- package/dist/application/workflow/runner/runner.d.ts +3 -2
- package/dist/application/workflow/workflow.d.ts +4 -3
- package/dist/deployment/adapter/adapter.d.ts +12 -7
- package/dist/deployment/adapter/define.d.ts +5 -2
- package/dist/deployment/adapter/define.js +15 -17
- package/dist/deployment/adapter/deploy/context.d.ts +6 -0
- package/dist/deployment/adapter/deploy/result.d.ts +2 -0
- package/dist/deployment/adapter/index.d.ts +2 -3
- package/dist/deployment/adapter/index.js +1 -1
- package/dist/deployment/adapter/prepare/context.d.ts +13 -5
- package/dist/deployment/authoring.d.ts +1 -1
- package/dist/deployment/build/compile.js +21 -19
- package/dist/deployment/build/frontend/compilation.d.ts +2 -1
- package/dist/deployment/build/frontend/compilation.js +1 -0
- package/dist/deployment/build/material.js +5 -5
- package/dist/deployment/deploy.d.ts +10 -4
- package/dist/deployment/deploy.js +5 -5
- package/dist/deployment/deployment.d.ts +8 -5
- package/dist/deployment/deployment.js +10 -1
- package/dist/deployment/index.d.ts +5 -4
- package/dist/deployment/index.js +3 -2
- package/dist/deployment/release/addressing.d.ts +6 -2
- package/dist/deployment/release/addressing.js +9 -4
- package/dist/deployment/release/publication/callables.js +1 -1
- package/dist/deployment/release/publication/index.d.ts +1 -1
- package/dist/deployment/release/publication/index.js +1 -1
- package/dist/deployment/release/publication/routes.js +1 -1
- package/dist/deployment/release/publication/seal.d.ts +0 -1
- package/dist/deployment/release/publication/seal.js +4 -5
- package/dist/deployment/release/publication/views.js +2 -1
- package/dist/deployment/verify/preflight/artifact.js +1 -1
- package/dist/deployment/verify/readiness/deployment.js +7 -3
- package/dist/deployment/verify/readiness/identity.js +1 -1
- package/dist/deployment/verify/readiness/publication.js +2 -2
- package/dist/execution/identity/authentication.js +0 -1
- package/dist/execution/identity/exchange.d.ts +1 -0
- package/dist/execution/identity/exchange.js +1 -1
- package/dist/execution/identity/jwks.js +1 -1
- package/dist/execution/invocation/admission/authentication.d.ts +6 -3
- package/dist/execution/invocation/admission/authentication.js +16 -6
- package/dist/execution/invocation/admission/authority.d.ts +2 -2
- package/dist/execution/invocation/dependency/bind.d.ts +5 -0
- package/dist/execution/invocation/dependency/bind.js +68 -0
- package/dist/execution/invocation/dependency/index.d.ts +1 -0
- package/dist/execution/invocation/dependency/index.js +1 -0
- package/dist/execution/invocation/dispatch/action.js +19 -2
- package/dist/execution/invocation/dispatch/context.d.ts +4 -4
- package/dist/execution/invocation/dispatch/context.js +29 -9
- package/dist/execution/invocation/dispatch/workflow.js +17 -4
- package/dist/execution/invocation/integration/authentication.d.ts +5 -0
- package/dist/execution/invocation/integration/authentication.js +53 -0
- package/dist/execution/invocation/integration/call.d.ts +7 -1
- package/dist/execution/invocation/integration/call.js +8 -3
- package/dist/execution/invocation/integration/clients.d.ts +2 -2
- package/dist/execution/invocation/integration/clients.js +2 -2
- package/dist/execution/invocation/lifecycle/active.js +30 -5
- package/dist/execution/invocation/result/errors.d.ts +1 -0
- package/dist/execution/invocation/result/errors.js +15 -10
- package/dist/execution/service/create.js +3 -1
- package/dist/execution/service/service.d.ts +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/platform/auth/index.d.ts +1 -1
- package/dist/platform/auth/index.js +0 -1
- package/dist/platform/graph/alias.d.ts +6 -0
- package/dist/platform/graph/alias.js +6 -0
- package/dist/platform/graph/document/index.d.ts +2 -1
- package/dist/platform/graph/document/index.js +2 -1
- package/dist/platform/graph/index.d.ts +2 -1
- package/dist/platform/graph/index.js +2 -1
- package/dist/platform/schema/class-authoring.d.ts +37 -0
- package/dist/platform/schema/class-authoring.js +20 -0
- package/dist/platform/schema/class-icon.d.ts +15 -0
- package/dist/platform/schema/class-icon.js +46 -0
- package/dist/platform/schema/error.d.ts +11 -0
- package/dist/platform/schema/error.js +34 -0
- package/dist/platform/schema/errors/index.d.ts +3 -0
- package/dist/platform/schema/errors/index.js +2 -0
- package/dist/platform/schema/icons/index.d.ts +2 -0
- package/dist/platform/schema/icons/index.js +2 -0
- package/dist/platform/schema/index.d.ts +20 -13
- package/dist/platform/schema/index.js +9 -4
- package/dist/platform/schema/kernel.d.ts +22 -0
- package/dist/platform/schema/kernel.js +5 -0
- package/dist/platform/schema/node-id.d.ts +3 -0
- package/dist/platform/schema/node-id.js +6 -0
- package/dist/platform/schema/property.d.ts +12 -0
- package/dist/platform/schema/property.js +3 -0
- package/dist/platform/schema/schema-authoring.d.ts +48 -0
- package/dist/platform/schema/schema-authoring.js +3 -0
- package/dist/platform/schema/state-property.d.ts +11 -0
- package/dist/platform/schema/state-property.js +3 -0
- package/dist/project/admit.d.ts +4 -0
- package/dist/project/admit.js +22 -0
- package/dist/project/define.d.ts +12 -0
- package/dist/project/define.js +106 -0
- package/dist/project/index.d.ts +4 -0
- package/dist/project/index.js +2 -0
- package/dist/project/project.d.ts +24 -0
- package/dist/project/project.js +1 -0
- package/dist/testing/dataset/admission.d.ts +13 -0
- package/dist/testing/dataset/admission.js +107 -0
- package/dist/testing/dataset/builder.d.ts +42 -0
- package/dist/testing/dataset/builder.js +127 -0
- package/dist/testing/dataset/codec.d.ts +6 -0
- package/dist/testing/dataset/codec.js +113 -0
- package/dist/testing/dataset/dataset.d.ts +58 -0
- package/dist/testing/dataset/dataset.js +2 -0
- package/dist/testing/dataset/define.d.ts +33 -0
- package/dist/testing/dataset/define.js +105 -0
- package/dist/testing/dataset/index.d.ts +8 -0
- package/dist/testing/dataset/index.js +4 -0
- package/dist/testing/dataset/references.d.ts +14 -0
- package/dist/testing/dataset/references.js +56 -0
- package/dist/testing/index.d.ts +9 -0
- package/dist/testing/index.js +5 -0
- package/dist/testing/load.d.ts +14 -0
- package/dist/testing/load.js +44 -0
- package/dist/testing/reference.d.ts +11 -0
- package/dist/testing/reference.js +19 -0
- package/dist/testing/tests.d.ts +12 -0
- package/dist/testing/tests.js +31 -0
- package/dist/tooling/cli/arguments.d.ts +7 -4
- package/dist/tooling/cli/arguments.js +82 -107
- package/dist/tooling/cli/astrale/authority.d.ts +5 -0
- package/dist/tooling/cli/astrale/authority.js +11 -0
- package/dist/tooling/cli/astrale/executable.d.ts +2 -0
- package/dist/tooling/cli/astrale/executable.js +47 -0
- package/dist/tooling/cli/astrale/failure.d.ts +6 -0
- package/dist/tooling/cli/astrale/failure.js +48 -0
- package/dist/tooling/cli/astrale/instance.d.ts +11 -0
- package/dist/tooling/cli/astrale/instance.js +52 -0
- package/dist/tooling/cli/astrale/process.d.ts +13 -0
- package/dist/tooling/cli/astrale/process.js +94 -0
- package/dist/tooling/cli/astrale/version.d.ts +18 -0
- package/dist/tooling/cli/astrale/version.js +55 -0
- package/dist/tooling/cli/bun.js +1 -1
- package/dist/tooling/cli/credential.d.ts +2 -0
- package/dist/tooling/cli/credential.js +57 -0
- package/dist/tooling/cli/development/candidate.d.ts +25 -0
- package/dist/tooling/cli/development/candidate.js +176 -0
- package/dist/tooling/cli/development/deployment.d.ts +16 -0
- package/dist/tooling/cli/development/deployment.js +39 -0
- package/dist/tooling/cli/development/develop.d.ts +4 -3
- package/dist/tooling/cli/development/develop.js +125 -289
- package/dist/tooling/cli/development/lease.d.ts +18 -0
- package/dist/tooling/cli/development/lease.js +163 -0
- package/dist/tooling/cli/development/lifecycle.js +4 -0
- package/dist/tooling/cli/development/project-imports.d.ts +22 -0
- package/dist/tooling/cli/development/project-imports.js +39 -0
- package/dist/tooling/cli/development/project-lock.d.ts +3 -4
- package/dist/tooling/cli/development/project-lock.js +14 -166
- package/dist/tooling/cli/development/release-evidence.d.ts +4 -0
- package/dist/tooling/cli/development/release-evidence.js +10 -0
- package/dist/tooling/cli/development/report.d.ts +6 -0
- package/dist/tooling/cli/development/report.js +14 -0
- package/dist/tooling/cli/development/source-watch.js +53 -5
- package/dist/tooling/cli/development/sources.d.ts +7 -0
- package/dist/tooling/cli/development/sources.js +48 -0
- package/dist/tooling/cli/development/target-lock.d.ts +16 -0
- package/dist/tooling/cli/development/target-lock.js +68 -0
- package/dist/tooling/cli/development/view.d.ts +28 -0
- package/dist/tooling/cli/development/view.js +151 -0
- package/dist/tooling/cli/environment-release.d.ts +21 -0
- package/dist/tooling/cli/environment-release.js +46 -0
- package/dist/tooling/cli/evidence.d.ts +11 -0
- package/dist/tooling/cli/evidence.js +53 -0
- package/dist/tooling/cli/help.js +78 -34
- package/dist/tooling/cli/index.d.ts +1 -1
- package/dist/tooling/cli/index.js +1 -1
- package/dist/tooling/cli/installation/index.d.ts +2 -0
- package/dist/tooling/cli/installation/index.js +1 -0
- package/dist/tooling/cli/installation/observation.d.ts +10 -0
- package/dist/tooling/cli/installation/observation.js +44 -0
- package/dist/tooling/cli/installation/reconcile.d.ts +32 -0
- package/dist/tooling/cli/installation/reconcile.js +122 -0
- package/dist/tooling/cli/orchestrate.js +84 -44
- package/dist/tooling/cli/project.d.ts +17 -0
- package/dist/tooling/cli/project.js +18 -0
- package/dist/tooling/cli/test.d.ts +12 -0
- package/dist/tooling/cli/test.js +47 -0
- package/dist/tooling/cli/upgrade/index.d.ts +6 -0
- package/dist/tooling/cli/upgrade/index.js +115 -0
- package/dist/tooling/cli/upgrade/manifest.d.ts +18 -0
- package/dist/tooling/cli/upgrade/manifest.js +77 -0
- package/dist/tooling/cli/upgrade/process.d.ts +2 -0
- package/dist/tooling/cli/upgrade/process.js +57 -0
- package/dist/tooling/linter/adapters/typescript/imports.js +2 -0
- package/dist/tooling/linter/adapters/typescript/index.d.ts +1 -0
- package/dist/tooling/linter/adapters/typescript/index.js +1 -0
- package/dist/tooling/linter/adapters/typescript/query-collection-type.js +4 -51
- package/dist/tooling/linter/adapters/typescript/type-analysis.d.ts +9 -0
- package/dist/tooling/linter/adapters/typescript/type-analysis.js +55 -0
- package/dist/tooling/linter/implementations/source/callable-requirements.d.ts +28 -0
- package/dist/tooling/linter/implementations/source/callable-requirements.js +234 -0
- package/dist/tooling/linter/implementations/source/dependencies.d.ts +2 -0
- package/dist/tooling/linter/implementations/source/dependencies.js +219 -0
- package/dist/tooling/linter/implementations/source/global.js +52 -2
- package/dist/tooling/linter/implementations/source/mutations.js +520 -38
- package/dist/tooling/linter/implementations/source/providers.js +19 -164
- package/dist/tooling/linter/implementations/source/schema.js +454 -2
- package/dist/tooling/linter/implementations/source/verifiers.js +2 -0
- package/dist/tooling/linter/implementations/source/workflows.js +8 -35
- package/dist/tooling/linter/policy/generated.js +2 -2
- package/dist/tooling/linter/requirements/registry.js +9 -3
- package/dist/tooling/packaging/declarations/normalize.js +3 -38
- package/dist/tooling/packaging/declarations/paths.d.ts +5 -0
- package/dist/tooling/packaging/declarations/paths.js +38 -0
- package/dist/tooling/packaging/finalize.d.ts +13 -0
- package/dist/tooling/packaging/finalize.js +62 -0
- package/dist/tooling/packaging/index.d.ts +2 -0
- package/dist/tooling/packaging/index.js +1 -0
- package/dist/tooling/packaging/javascript.d.ts +3 -0
- package/dist/tooling/packaging/javascript.js +45 -2
- package/dist/tooling/packaging/packaging.d.ts +2 -5
- package/dist/tooling/packaging/packaging.js +6 -30
- package/package.json +42 -12
- package/CHANGELOG.md +0 -1506
- package/dist/deployment/adapter/development/context.d.ts +0 -18
- package/dist/deployment/adapter/development/index.d.ts +0 -4
- package/dist/deployment/adapter/development/input.d.ts +0 -6
- package/dist/deployment/adapter/development/placement.d.ts +0 -15
- package/dist/deployment/adapter/development/session.d.ts +0 -9
- /package/dist/{deployment/adapter/development → application/dependency}/index.js +0 -0
- /package/dist/{deployment/adapter/development/context.js → application/dependency/invoker.js} +0 -0
- /package/dist/{deployment/adapter/development/input.js → application/integration/authentication.js} +0 -0
- /package/dist/{deployment/adapter/development/placement.js → application/integration/authentication.typecheck.d.ts} +0 -0
- /package/dist/{deployment/adapter/development/session.js → application/runtime/declarations.js} +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { mkdir, rmdir } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { acquireDevelopmentLease, DevelopmentLeaseError } from './lease.js';
|
|
6
|
+
export class DevelopmentTargetLockError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
name = 'DevelopmentTargetLockError';
|
|
9
|
+
constructor(code, message, options) {
|
|
10
|
+
super(message, options);
|
|
11
|
+
this.code = code;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** Exclude local sessions targeting one installed Domain across separate checkouts. */
|
|
15
|
+
export async function acquireDevelopmentTargetLock(input, dependencies = {}) {
|
|
16
|
+
const coordinate = `${input.issuer}#${input.origin}`;
|
|
17
|
+
const root = dependencies.root ?? join(tmpdir(), 'astrale-domain-development-targets');
|
|
18
|
+
const key = createHash('sha256')
|
|
19
|
+
.update(input.issuer)
|
|
20
|
+
.update('\0')
|
|
21
|
+
.update(input.origin)
|
|
22
|
+
.digest('hex');
|
|
23
|
+
const directory = join(root, key);
|
|
24
|
+
await mkdir(root, { recursive: true, mode: 0o700 });
|
|
25
|
+
let lease;
|
|
26
|
+
try {
|
|
27
|
+
lease = await acquireDevelopmentLease({
|
|
28
|
+
directory,
|
|
29
|
+
coordinate,
|
|
30
|
+
...(dependencies.pid === undefined ? {} : { pid: dependencies.pid }),
|
|
31
|
+
...(dependencies.sessionId === undefined ? {} : { sessionId: dependencies.sessionId }),
|
|
32
|
+
...(dependencies.processAlive === undefined
|
|
33
|
+
? {}
|
|
34
|
+
: { processAlive: dependencies.processAlive }),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (cause) {
|
|
38
|
+
if (cause instanceof DevelopmentLeaseError) {
|
|
39
|
+
throw new DevelopmentTargetLockError('DEVELOPMENT_TARGET_LOCKED', cause.message, { cause });
|
|
40
|
+
}
|
|
41
|
+
throw cause;
|
|
42
|
+
}
|
|
43
|
+
return Object.freeze({
|
|
44
|
+
...lease,
|
|
45
|
+
async release() {
|
|
46
|
+
try {
|
|
47
|
+
await lease.release();
|
|
48
|
+
}
|
|
49
|
+
catch (cause) {
|
|
50
|
+
if (cause instanceof DevelopmentLeaseError) {
|
|
51
|
+
throw new DevelopmentTargetLockError('DEVELOPMENT_TARGET_LOCK_LOST', cause.message, {
|
|
52
|
+
cause,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
throw cause;
|
|
56
|
+
}
|
|
57
|
+
await rmdir(directory).catch(ignoreNonEmpty);
|
|
58
|
+
await rmdir(root).catch(ignoreNonEmpty);
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function ignoreNonEmpty(cause) {
|
|
63
|
+
const code = cause !== null && typeof cause === 'object' && 'code' in cause
|
|
64
|
+
? String(Reflect.get(cause, 'code'))
|
|
65
|
+
: undefined;
|
|
66
|
+
if (!['ENOENT', 'ENOTEMPTY', 'EEXIST'].includes(code ?? ''))
|
|
67
|
+
throw cause;
|
|
68
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Release } from '../../../deployment/release/index.js';
|
|
2
|
+
import type { AstraleProcessResult } from '../astrale/process.js';
|
|
3
|
+
export interface DevelopmentViewDependencies {
|
|
4
|
+
run(input: {
|
|
5
|
+
readonly executable: string;
|
|
6
|
+
readonly args: readonly string[];
|
|
7
|
+
readonly projectDir: string;
|
|
8
|
+
readonly signal: AbortSignal;
|
|
9
|
+
readonly timeoutMs: number;
|
|
10
|
+
}): Promise<AstraleProcessResult>;
|
|
11
|
+
}
|
|
12
|
+
/** Keep one browser tab alive across successful remote deployments. */
|
|
13
|
+
export declare class DevelopmentView {
|
|
14
|
+
#private;
|
|
15
|
+
constructor(input: {
|
|
16
|
+
readonly executable: string;
|
|
17
|
+
readonly projectDir: string;
|
|
18
|
+
readonly instance: string;
|
|
19
|
+
readonly identity?: string;
|
|
20
|
+
readonly credential?: string;
|
|
21
|
+
readonly dependencies?: DevelopmentViewDependencies;
|
|
22
|
+
});
|
|
23
|
+
/** Require in-place refresh before publishing anything that depends on this CLI feature. */
|
|
24
|
+
prepare(signal: AbortSignal): Promise<void>;
|
|
25
|
+
/** Called after each committed deployment; the development loop owns candidate deduplication. */
|
|
26
|
+
refresh(release: Release, signal: AbortSignal): Promise<string | undefined>;
|
|
27
|
+
close(signal: AbortSignal): Promise<void>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { astraleAuthorityArguments } from '../astrale/authority.js';
|
|
2
|
+
import { runAstrale } from '../astrale/process.js';
|
|
3
|
+
/** Keep one browser tab alive across successful remote deployments. */
|
|
4
|
+
export class DevelopmentView {
|
|
5
|
+
#executable;
|
|
6
|
+
#projectDir;
|
|
7
|
+
#instance;
|
|
8
|
+
#authority;
|
|
9
|
+
#dependencies;
|
|
10
|
+
#current;
|
|
11
|
+
#prepared = false;
|
|
12
|
+
constructor(input) {
|
|
13
|
+
this.#executable = input.executable;
|
|
14
|
+
this.#projectDir = input.projectDir;
|
|
15
|
+
this.#instance = input.instance;
|
|
16
|
+
this.#authority = astraleAuthorityArguments({
|
|
17
|
+
...(input.identity === undefined ? {} : { identity: input.identity }),
|
|
18
|
+
...(input.credential === undefined ? {} : { credential: input.credential }),
|
|
19
|
+
});
|
|
20
|
+
this.#dependencies = input.dependencies ?? { run: runAstrale };
|
|
21
|
+
}
|
|
22
|
+
/** Require in-place refresh before publishing anything that depends on this CLI feature. */
|
|
23
|
+
async prepare(signal) {
|
|
24
|
+
if (this.#prepared)
|
|
25
|
+
return;
|
|
26
|
+
const result = await this.#dependencies.run({
|
|
27
|
+
executable: this.#executable,
|
|
28
|
+
projectDir: this.#projectDir,
|
|
29
|
+
signal,
|
|
30
|
+
timeoutMs: 10_000,
|
|
31
|
+
args: ['view', '--help'],
|
|
32
|
+
});
|
|
33
|
+
if (result.code !== 0 || !result.stdout.includes('--refresh <id>')) {
|
|
34
|
+
throw new Error('This Astrale CLI cannot refresh development Views. Run astrale update before pnpm dev.');
|
|
35
|
+
}
|
|
36
|
+
this.#prepared = true;
|
|
37
|
+
}
|
|
38
|
+
/** Called after each committed deployment; the development loop owns candidate deduplication. */
|
|
39
|
+
async refresh(release, signal) {
|
|
40
|
+
const frontend = release.build.frontend;
|
|
41
|
+
if (frontend === undefined) {
|
|
42
|
+
await this.close(AbortSignal.timeout(30_000));
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const path = `/:${frontend.entrypoint.origin}:view.${frontend.entrypoint.name}`;
|
|
46
|
+
const previous = this.#current;
|
|
47
|
+
if (previous?.path === path) {
|
|
48
|
+
const refreshed = await this.#dependencies.run({
|
|
49
|
+
executable: this.#executable,
|
|
50
|
+
projectDir: this.#projectDir,
|
|
51
|
+
signal,
|
|
52
|
+
timeoutMs: 60_000,
|
|
53
|
+
args: ['--ci', '--no-prompt', 'view', '--refresh', previous.id, '--json'],
|
|
54
|
+
});
|
|
55
|
+
if (refreshed.code !== 0)
|
|
56
|
+
throw new Error('Astrale CLI could not refresh the development View.');
|
|
57
|
+
return previous.pageUrl;
|
|
58
|
+
}
|
|
59
|
+
const next = await this.#open(path, signal);
|
|
60
|
+
if (previous !== undefined) {
|
|
61
|
+
try {
|
|
62
|
+
await this.#close(previous.id, AbortSignal.timeout(30_000));
|
|
63
|
+
}
|
|
64
|
+
catch (cause) {
|
|
65
|
+
try {
|
|
66
|
+
await this.#close(next.id, AbortSignal.timeout(30_000));
|
|
67
|
+
}
|
|
68
|
+
catch (rollback) {
|
|
69
|
+
throw new AggregateError([cause, rollback], 'Astrale View replacement and rollback cleanup failed.');
|
|
70
|
+
}
|
|
71
|
+
throw cause;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
this.#current = next;
|
|
75
|
+
return next.pageUrl;
|
|
76
|
+
}
|
|
77
|
+
async close(signal) {
|
|
78
|
+
const current = this.#current;
|
|
79
|
+
if (current === undefined)
|
|
80
|
+
return;
|
|
81
|
+
await this.#close(current.id, signal);
|
|
82
|
+
if (this.#current === current) {
|
|
83
|
+
this.#current = undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async #open(path, signal) {
|
|
87
|
+
const result = await this.#dependencies.run({
|
|
88
|
+
executable: this.#executable,
|
|
89
|
+
projectDir: this.#projectDir,
|
|
90
|
+
signal,
|
|
91
|
+
timeoutMs: 60_000,
|
|
92
|
+
args: [
|
|
93
|
+
'--ci',
|
|
94
|
+
'--no-prompt',
|
|
95
|
+
'view',
|
|
96
|
+
path,
|
|
97
|
+
'--browser',
|
|
98
|
+
'--instance',
|
|
99
|
+
this.#instance,
|
|
100
|
+
'--json',
|
|
101
|
+
...this.#authority,
|
|
102
|
+
],
|
|
103
|
+
});
|
|
104
|
+
if (result.code !== 0)
|
|
105
|
+
throw new Error('Astrale CLI could not open the development View.');
|
|
106
|
+
return { ...decodeOpenedView(result.stdout), path };
|
|
107
|
+
}
|
|
108
|
+
async #close(id, signal) {
|
|
109
|
+
const result = await this.#dependencies.run({
|
|
110
|
+
executable: this.#executable,
|
|
111
|
+
projectDir: this.#projectDir,
|
|
112
|
+
signal,
|
|
113
|
+
timeoutMs: 30_000,
|
|
114
|
+
args: ['--ci', '--no-prompt', 'view', '--close', id, '--json'],
|
|
115
|
+
});
|
|
116
|
+
if (result.code !== 0)
|
|
117
|
+
throw new Error('Astrale CLI could not close the development View.');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function decodeOpenedView(input) {
|
|
121
|
+
let value;
|
|
122
|
+
try {
|
|
123
|
+
value = JSON.parse(input);
|
|
124
|
+
}
|
|
125
|
+
catch (cause) {
|
|
126
|
+
throw new TypeError('Astrale View output is invalid.', { cause });
|
|
127
|
+
}
|
|
128
|
+
const session = record(value) ? value.session : undefined;
|
|
129
|
+
const id = record(session) ? session.id : undefined;
|
|
130
|
+
const pageUrl = record(session) ? session.pageUrl : undefined;
|
|
131
|
+
if (typeof id !== 'string' || id.length === 0 || !webUrl(pageUrl)) {
|
|
132
|
+
throw new TypeError('Astrale View output is invalid.');
|
|
133
|
+
}
|
|
134
|
+
return Object.freeze({ id, pageUrl });
|
|
135
|
+
}
|
|
136
|
+
function webUrl(input) {
|
|
137
|
+
if (typeof input !== 'string' || input.length === 0 || input.length > 2_048)
|
|
138
|
+
return false;
|
|
139
|
+
try {
|
|
140
|
+
const value = new URL(input);
|
|
141
|
+
return ((value.protocol === 'http:' || value.protocol === 'https:') &&
|
|
142
|
+
value.username === '' &&
|
|
143
|
+
value.password === '');
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function record(input) {
|
|
150
|
+
return input !== null && typeof input === 'object' && !Array.isArray(input);
|
|
151
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Adapter, InstallationTarget, ReadyDeployResult } from '../../deployment/adapter/index.js';
|
|
2
|
+
import type { InstallationEvidence } from './installation/index.js';
|
|
3
|
+
import { writeDeploymentEvidence } from './evidence.js';
|
|
4
|
+
import { reconcileInstallation } from './installation/index.js';
|
|
5
|
+
export interface EnvironmentReleaseDependencies {
|
|
6
|
+
readonly writeEvidence: typeof writeDeploymentEvidence;
|
|
7
|
+
readonly reconcileInstallation: typeof reconcileInstallation;
|
|
8
|
+
}
|
|
9
|
+
/** Retain verified provider evidence and reconcile one optional durable Kernel installation. */
|
|
10
|
+
export declare function reconcileEnvironmentRelease(input: {
|
|
11
|
+
readonly projectDir: string;
|
|
12
|
+
readonly environment: string;
|
|
13
|
+
readonly adapter: Adapter<object>;
|
|
14
|
+
readonly deployment: ReadyDeployResult;
|
|
15
|
+
readonly installation?: InstallationTarget;
|
|
16
|
+
readonly deployOnly: boolean;
|
|
17
|
+
readonly identity?: string;
|
|
18
|
+
readonly credential?: string;
|
|
19
|
+
readonly installationExecutable?: string;
|
|
20
|
+
readonly signal: AbortSignal;
|
|
21
|
+
}, dependencies?: EnvironmentReleaseDependencies): Promise<InstallationEvidence | undefined>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { writeDeploymentEvidence } from './evidence.js';
|
|
2
|
+
import { reconcileInstallation } from './installation/index.js';
|
|
3
|
+
/** Retain verified provider evidence and reconcile one optional durable Kernel installation. */
|
|
4
|
+
export async function reconcileEnvironmentRelease(input, dependencies = {
|
|
5
|
+
writeEvidence: writeDeploymentEvidence,
|
|
6
|
+
reconcileInstallation,
|
|
7
|
+
}) {
|
|
8
|
+
try {
|
|
9
|
+
await dependencies.writeEvidence({
|
|
10
|
+
projectDir: input.projectDir,
|
|
11
|
+
environment: input.environment,
|
|
12
|
+
adapter: input.adapter,
|
|
13
|
+
deployment: input.deployment,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
catch (cause) {
|
|
17
|
+
throw new TypeError(`Domain ${input.deployment.release.publication.origin} remains deployed, but its local evidence could not be saved. Kernel installation was not attempted.`, { cause });
|
|
18
|
+
}
|
|
19
|
+
if (input.installation === undefined || input.deployOnly)
|
|
20
|
+
return undefined;
|
|
21
|
+
if (input.installationExecutable === undefined) {
|
|
22
|
+
throw new TypeError('A compatible Astrale CLI must be pinned before deploying an installed Environment.');
|
|
23
|
+
}
|
|
24
|
+
const installation = await dependencies.reconcileInstallation({
|
|
25
|
+
projectDir: input.projectDir,
|
|
26
|
+
target: input.installation,
|
|
27
|
+
executable: input.installationExecutable,
|
|
28
|
+
...(input.identity === undefined ? {} : { identity: input.identity }),
|
|
29
|
+
...(input.credential === undefined ? {} : { credential: input.credential }),
|
|
30
|
+
release: input.deployment.release,
|
|
31
|
+
signal: input.signal,
|
|
32
|
+
});
|
|
33
|
+
try {
|
|
34
|
+
await dependencies.writeEvidence({
|
|
35
|
+
projectDir: input.projectDir,
|
|
36
|
+
environment: input.environment,
|
|
37
|
+
adapter: input.adapter,
|
|
38
|
+
deployment: input.deployment,
|
|
39
|
+
installation,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch (cause) {
|
|
43
|
+
throw new TypeError(`Domain ${installation.origin} remains installed on ${installation.instance}, but its local evidence could not be saved. The installation was not rolled back.`, { cause });
|
|
44
|
+
}
|
|
45
|
+
return installation;
|
|
46
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Adapter, ReadyDeployResult } from '../../deployment/adapter/index.js';
|
|
2
|
+
import type { InstallationEvidence } from './installation/index.js';
|
|
3
|
+
export declare const DEPLOYMENT_EVIDENCE_VERSION: 1;
|
|
4
|
+
/** Persist one non-secret, non-authoritative continuity observation atomically. */
|
|
5
|
+
export declare function writeDeploymentEvidence(input: {
|
|
6
|
+
readonly projectDir: string;
|
|
7
|
+
readonly environment: string;
|
|
8
|
+
readonly adapter: Adapter<object>;
|
|
9
|
+
readonly deployment: ReadyDeployResult;
|
|
10
|
+
readonly installation?: InstallationEvidence;
|
|
11
|
+
}): Promise<string>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdir, rename, unlink, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
export const DEPLOYMENT_EVIDENCE_VERSION = 1;
|
|
5
|
+
/** Persist one non-secret, non-authoritative continuity observation atomically. */
|
|
6
|
+
export async function writeDeploymentEvidence(input) {
|
|
7
|
+
const directory = join(input.projectDir, '.astrale', 'environments', input.environment);
|
|
8
|
+
const path = join(directory, 'deployment.json');
|
|
9
|
+
await mkdir(directory, { recursive: true });
|
|
10
|
+
const provider = input.deployment.progress.provider.evidence;
|
|
11
|
+
const value = Object.freeze({
|
|
12
|
+
version: DEPLOYMENT_EVIDENCE_VERSION,
|
|
13
|
+
environment: input.environment,
|
|
14
|
+
adapter: Object.freeze({ name: input.adapter.name, version: input.adapter.version }),
|
|
15
|
+
deployment: Object.freeze({
|
|
16
|
+
provider: provider.provider,
|
|
17
|
+
id: provider.deployment,
|
|
18
|
+
artifact: provider.artifact,
|
|
19
|
+
issuer: input.deployment.release.addressing.issuer,
|
|
20
|
+
publicUrl: input.deployment.release.addressing.publicUrl,
|
|
21
|
+
origin: input.deployment.release.publication.origin,
|
|
22
|
+
revision: input.deployment.release.publication.schema.revision,
|
|
23
|
+
etag: input.deployment.release.publication.etag,
|
|
24
|
+
readiness: 'ready',
|
|
25
|
+
...(provider.preflight === undefined ? {} : { preflight: provider.preflight }),
|
|
26
|
+
}),
|
|
27
|
+
...(input.installation === undefined
|
|
28
|
+
? {}
|
|
29
|
+
: {
|
|
30
|
+
installation: Object.freeze({
|
|
31
|
+
instance: input.installation.instance,
|
|
32
|
+
origin: input.installation.origin,
|
|
33
|
+
issuer: input.installation.issuer,
|
|
34
|
+
revision: input.installation.revision,
|
|
35
|
+
etag: input.installation.etag,
|
|
36
|
+
generation: input.installation.generation,
|
|
37
|
+
status: input.installation.status,
|
|
38
|
+
}),
|
|
39
|
+
}),
|
|
40
|
+
});
|
|
41
|
+
const staging = join(directory, `.deployment-${randomUUID()}.json`);
|
|
42
|
+
await writeFile(staging, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600, flag: 'wx' });
|
|
43
|
+
try {
|
|
44
|
+
await rename(staging, path);
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
await unlink(staging).catch((cause) => {
|
|
48
|
+
if (cause.code !== 'ENOENT')
|
|
49
|
+
throw cause;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return path;
|
|
53
|
+
}
|
package/dist/tooling/cli/help.js
CHANGED
|
@@ -12,17 +12,19 @@ export function helpText(command) {
|
|
|
12
12
|
export const ERROR_USAGE = `Usage: astrale-domain <command> [options]
|
|
13
13
|
Run "astrale-domain --help" for available commands.
|
|
14
14
|
`;
|
|
15
|
-
const GLOBAL_HELP = `Build, develop, deploy, lint, and package Astrale Domains.
|
|
15
|
+
const GLOBAL_HELP = `Build, develop, deploy, test, lint, and package Astrale Domains.
|
|
16
16
|
|
|
17
17
|
Usage:
|
|
18
18
|
astrale-domain <command> [options]
|
|
19
19
|
|
|
20
20
|
Commands:
|
|
21
|
-
dev [environment]
|
|
21
|
+
dev [environment] Remotely deploy and watch one Project Environment.
|
|
22
22
|
build Build and verify without deploying.
|
|
23
|
-
deploy <environment> Deploy
|
|
23
|
+
deploy <environment> Deploy and optionally install one Environment.
|
|
24
|
+
test Run Project tests, optionally against one Environment.
|
|
24
25
|
lint Check Domain source and architecture.
|
|
25
26
|
package Prepare public declarations for publication.
|
|
27
|
+
upgrade Update Astrale dependencies through pnpm (default: beta).
|
|
26
28
|
|
|
27
29
|
Options:
|
|
28
30
|
-h, --help Show help.
|
|
@@ -30,51 +32,73 @@ Options:
|
|
|
30
32
|
Run "astrale-domain <command> --help" for command-specific help.
|
|
31
33
|
`;
|
|
32
34
|
const COMMAND_HELP = Object.freeze({
|
|
33
|
-
|
|
35
|
+
upgrade: `Update existing Astrale dependencies in a pnpm project or workspace.
|
|
36
|
+
|
|
37
|
+
Usage:
|
|
38
|
+
astrale-domain upgrade [--channel <tag>] [--check]
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
--channel <tag> Registry dist-tag to select (default: beta).
|
|
42
|
+
--check Show changes without modifying project files or installing.
|
|
43
|
+
-h, --help Show help for upgrade.
|
|
44
|
+
|
|
45
|
+
Behavior:
|
|
46
|
+
Updates dependencies, devDependencies, and optionalDependencies under @astrale-os/
|
|
47
|
+
and @astrale-domains/, including the workspace root. Writes exact versions and
|
|
48
|
+
runs pnpm install once. The selected tag is authoritative, even if older than
|
|
49
|
+
the current version. Installation is synchronized even when versions are unchanged,
|
|
50
|
+
so retrying can finish a previously failed install. Packages without that tag remain
|
|
51
|
+
unchanged with a warning.
|
|
52
|
+
Local links, catalogs, aliases, peers, and overrides are not rewritten.
|
|
53
|
+
Does not load astrale.config.ts, require Bun, run project checks, commit, or deploy.
|
|
54
|
+
Stop development watchers before upgrading. Review changes and run your project's
|
|
55
|
+
checks afterwards. Failed installations leave local changes available for repair.
|
|
56
|
+
For an older SDK without this command: pnpm dlx @astrale-os/sdk@beta upgrade.
|
|
57
|
+
`,
|
|
58
|
+
dev: `Build, verify, remotely deploy, and watch one Project Environment.
|
|
34
59
|
|
|
35
60
|
Usage:
|
|
36
61
|
astrale-domain dev [environment] [options]
|
|
37
62
|
|
|
38
63
|
Arguments:
|
|
39
|
-
environment
|
|
64
|
+
environment Project Environment name; defaults to development.
|
|
40
65
|
|
|
41
66
|
Options:
|
|
42
67
|
--environment <name> Select the environment without a positional argument.
|
|
43
|
-
--
|
|
44
|
-
--
|
|
45
|
-
from --port or adapter configuration.
|
|
68
|
+
--deploy-only Suppress this run's configured Kernel installation.
|
|
69
|
+
--as <identity> Select the Astrale identity for Services and installation calls.
|
|
46
70
|
--session-file <path> Write one retained DevelopmentSessionFileV1 snapshot at an
|
|
47
71
|
absolute path in a caller-owned private directory.
|
|
48
72
|
--credential-file <path>
|
|
49
|
-
Use one private operator credential for
|
|
50
|
-
calls without exposing it in
|
|
73
|
+
Use one private operator credential for provider and Kernel
|
|
74
|
+
calls without exposing it in Project configuration.
|
|
51
75
|
--secrets-file <path> Load one private, absolute secrets file for this development
|
|
52
76
|
session instead of the adapter-declared secrets file.
|
|
53
77
|
-h, --help Show help for dev.
|
|
54
78
|
|
|
55
79
|
Behavior:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
require restarting the command.
|
|
80
|
+
The selected Environment must exist; no other Environment is chosen as a fallback.
|
|
81
|
+
Builds and verifies the Application, Runtime, frontend, and adapter artifact, then
|
|
82
|
+
deploys it through the selected Environment. It never starts a local Worker,
|
|
83
|
+
Vite server, or tunnel. Imported source changes produce serialized remote updates;
|
|
84
|
+
configuration changes require restarting the command.
|
|
85
|
+
A shared direct-provider target additionally requires an external single-writer
|
|
86
|
+
boundary such as a CI/CD concurrency group.
|
|
61
87
|
The session file is machine-readable and authoritative when requested; human
|
|
62
88
|
stdout/stderr remains diagnostic. It requires an adapter that reports exact
|
|
63
|
-
installed Release evidence
|
|
64
|
-
|
|
65
|
-
|
|
89
|
+
installed Release evidence, so it is rejected for an Environment without an
|
|
90
|
+
installation and when --deploy-only suppresses installation.
|
|
91
|
+
A credential file is admitted and read once. Its value is passed only to the
|
|
92
|
+
deployment adapter, configured Kernel installation, and default View; it never
|
|
93
|
+
enters Domain Runtime secrets, diagnostics, deployment evidence, or the session
|
|
94
|
+
file. It is currently unavailable on Windows because private no-reparse file
|
|
95
|
+
admission is absent.
|
|
66
96
|
A secrets-file override is read once, passed to the Domain runtime as secrets,
|
|
67
97
|
never mutates the authored project, and is not watched for later changes. It is
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
it owns no public ingress or Kernel installation.
|
|
73
|
-
astrale Also owns a Quick Tunnel when no public host is configured,
|
|
74
|
-
reconciles each verified Release on the configured or
|
|
75
|
-
CLI-active instance, and starts a local View host when
|
|
76
|
-
a View is declared. The installation remains after the
|
|
77
|
-
development session stops.
|
|
98
|
+
also unavailable on Windows because private no-reparse admission is absent.
|
|
99
|
+
|
|
100
|
+
Stopping the watcher stops only local build orchestration. The remote deployment
|
|
101
|
+
and optional Kernel installation remain available.
|
|
78
102
|
`,
|
|
79
103
|
build: `Build and verify a Domain without deploying it.
|
|
80
104
|
|
|
@@ -85,9 +109,9 @@ Options:
|
|
|
85
109
|
-h, --help Show help for build.
|
|
86
110
|
|
|
87
111
|
Behavior:
|
|
88
|
-
Compiles the Application and
|
|
89
|
-
the
|
|
90
|
-
the Domain.
|
|
112
|
+
Compiles the Application and verifies that the conventional or configured Runtime
|
|
113
|
+
module exports the exact Runtime owned by it. It does not select an Environment,
|
|
114
|
+
load secrets, deploy, or install the Domain.
|
|
91
115
|
`,
|
|
92
116
|
deploy: `Build, verify, and deploy a Domain through its configured adapter.
|
|
93
117
|
|
|
@@ -100,12 +124,32 @@ Arguments:
|
|
|
100
124
|
|
|
101
125
|
Options:
|
|
102
126
|
--environment <name> Select the environment without a positional argument.
|
|
127
|
+
--deploy-only Suppress this run's configured Kernel installation.
|
|
128
|
+
--as <identity> Select the Astrale identity for Services and installation calls.
|
|
103
129
|
-h, --help Show help for deploy.
|
|
104
130
|
|
|
105
131
|
Behavior:
|
|
106
|
-
Builds and verifies the
|
|
107
|
-
|
|
108
|
-
|
|
132
|
+
Builds and verifies the Application, Runtime, and provider artifact, loads declared
|
|
133
|
+
secrets, and invokes the selected adapter. It then verifies the resulting Release.
|
|
134
|
+
When the Environment declares installation, reconciles it after provider readiness.
|
|
135
|
+
An Environment without installation performs zero Kernel calls.
|
|
136
|
+
`,
|
|
137
|
+
test: `Run Project tests locally or against one selected Environment.
|
|
138
|
+
|
|
139
|
+
Usage:
|
|
140
|
+
astrale-domain test [options]
|
|
141
|
+
|
|
142
|
+
Options:
|
|
143
|
+
--environment <name> Select the committed Project Environment exposed to tests as
|
|
144
|
+
ASTRALE_PROJECT_ENVIRONMENT.
|
|
145
|
+
--suite <name> Select a named Vitest project from vitest.config.ts.
|
|
146
|
+
-h, --help Show help for test.
|
|
147
|
+
|
|
148
|
+
Behavior:
|
|
149
|
+
Without an Environment, runs the Project-local Vitest suite once. With an
|
|
150
|
+
Environment, first validates the name against astrale.config.ts, then exposes
|
|
151
|
+
that exact name to the selected suite. Test definitions remain Project-level;
|
|
152
|
+
environments never duplicate or override them.
|
|
109
153
|
`,
|
|
110
154
|
lint: `Check Domain source and architecture.
|
|
111
155
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@astrale-os/sdk/cli` — the `astrale-domain` CLI
|
|
3
|
-
* (dev | build | deploy | lint | package), explicit dotenv boundary, and admitted
|
|
3
|
+
* (dev | build | deploy | test | lint | package), explicit dotenv boundary, and admitted
|
|
4
4
|
* development-session file representation.
|
|
5
5
|
*
|
|
6
6
|
* Node-only: the CLI imports `node:fs`/`node:module`/`node:url` and runs under
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@astrale-os/sdk/cli` — the `astrale-domain` CLI
|
|
3
|
-
* (dev | build | deploy | lint | package), explicit dotenv boundary, and admitted
|
|
3
|
+
* (dev | build | deploy | test | lint | package), explicit dotenv boundary, and admitted
|
|
4
4
|
* development-session file representation.
|
|
5
5
|
*
|
|
6
6
|
* Node-only: the CLI imports `node:fs`/`node:module`/`node:url` and runs under
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { reconcileInstallation } from './reconcile.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface InstallationObservation {
|
|
2
|
+
readonly origin: string;
|
|
3
|
+
readonly revision: string;
|
|
4
|
+
readonly issuer: string;
|
|
5
|
+
readonly generation: string;
|
|
6
|
+
readonly etag: string;
|
|
7
|
+
}
|
|
8
|
+
/** Admit exact installed Release evidence returned by Kernel introspection. */
|
|
9
|
+
export declare function decodeInstallationObservation(input: string): InstallationObservation;
|
|
10
|
+
export declare function canonicalIssuer(input: string): string;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Admit exact installed Release evidence returned by Kernel introspection. */
|
|
2
|
+
export function decodeInstallationObservation(input) {
|
|
3
|
+
let decoded;
|
|
4
|
+
try {
|
|
5
|
+
decoded = JSON.parse(input);
|
|
6
|
+
}
|
|
7
|
+
catch (cause) {
|
|
8
|
+
throw new TypeError('Astrale introspection did not return one JSON value.', { cause });
|
|
9
|
+
}
|
|
10
|
+
const root = record(decoded);
|
|
11
|
+
const publication = record(root.publication);
|
|
12
|
+
const identity = record(publication.identity);
|
|
13
|
+
if (typeof root.origin !== 'string' ||
|
|
14
|
+
typeof root.revision !== 'string' ||
|
|
15
|
+
typeof root.generation !== 'string' ||
|
|
16
|
+
!/^sha256:[0-9a-f]{64}$/u.test(root.generation) ||
|
|
17
|
+
publication.origin !== root.origin ||
|
|
18
|
+
publication.revision !== root.revision ||
|
|
19
|
+
typeof identity.issuer !== 'string' ||
|
|
20
|
+
typeof publication.etag !== 'string' ||
|
|
21
|
+
!/^sha256:[0-9a-f]{64}$/u.test(publication.etag)) {
|
|
22
|
+
throw new TypeError('Astrale introspection returned invalid installed Domain evidence.');
|
|
23
|
+
}
|
|
24
|
+
return Object.freeze({
|
|
25
|
+
origin: root.origin,
|
|
26
|
+
revision: root.revision,
|
|
27
|
+
issuer: canonicalIssuer(identity.issuer),
|
|
28
|
+
generation: root.generation,
|
|
29
|
+
etag: publication.etag,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export function canonicalIssuer(input) {
|
|
33
|
+
const url = new URL(input);
|
|
34
|
+
if (url.href !== url.origin && url.href !== `${url.origin}/`) {
|
|
35
|
+
throw new TypeError('Release issuer must be one canonical origin.');
|
|
36
|
+
}
|
|
37
|
+
return url.origin;
|
|
38
|
+
}
|
|
39
|
+
function record(input) {
|
|
40
|
+
if (input === null || typeof input !== 'object' || Array.isArray(input)) {
|
|
41
|
+
throw new TypeError('Astrale introspection returned invalid installed Domain evidence.');
|
|
42
|
+
}
|
|
43
|
+
return input;
|
|
44
|
+
}
|