@astrale-os/sdk 0.6.0-beta.17 → 0.6.0-beta.19
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 +1 -1
- package/dist/deployment/adapter/legacy/index.d.ts +2 -2
- package/dist/deployment/adapter/legacy/prepare/context.d.ts +4 -5
- package/dist/execution/identity/jwks.js +57 -12
- package/dist/platform/schema/property.d.ts +5 -0
- package/dist/tooling/cli/arguments.d.ts +1 -3
- package/dist/tooling/cli/arguments.js +5 -39
- package/dist/tooling/cli/bun.d.ts +0 -1
- package/dist/tooling/cli/bun.js +0 -7
- package/dist/tooling/cli/deploy-mode.d.ts +4 -4
- package/dist/tooling/cli/deploy-mode.js +2 -15
- package/dist/tooling/cli/help.js +3 -50
- package/dist/tooling/cli/index.d.ts +1 -2
- package/dist/tooling/cli/index.js +1 -2
- package/dist/tooling/cli/legacy/stable-target-adapter.d.ts +1 -1
- package/dist/tooling/cli/orchestrate.d.ts +0 -6
- package/dist/tooling/cli/orchestrate.js +0 -28
- package/package.json +7 -7
- package/dist/tooling/cli/legacy/development/candidate.d.ts +0 -25
- package/dist/tooling/cli/legacy/development/candidate.js +0 -170
- package/dist/tooling/cli/legacy/development/credential.d.ts +0 -2
- package/dist/tooling/cli/legacy/development/credential.js +0 -57
- package/dist/tooling/cli/legacy/development/deployment.d.ts +0 -10
- package/dist/tooling/cli/legacy/development/deployment.js +0 -20
- package/dist/tooling/cli/legacy/development/deprecation.d.ts +0 -11
- package/dist/tooling/cli/legacy/development/deprecation.js +0 -13
- package/dist/tooling/cli/legacy/development/develop.d.ts +0 -15
- package/dist/tooling/cli/legacy/development/develop.js +0 -142
- package/dist/tooling/cli/legacy/development/index.d.ts +0 -21
- package/dist/tooling/cli/legacy/development/index.js +0 -21
- package/dist/tooling/cli/legacy/development/lease.d.ts +0 -18
- package/dist/tooling/cli/legacy/development/lease.js +0 -163
- package/dist/tooling/cli/legacy/development/lifecycle.d.ts +0 -9
- package/dist/tooling/cli/legacy/development/lifecycle.js +0 -43
- package/dist/tooling/cli/legacy/development/project-imports.d.ts +0 -22
- package/dist/tooling/cli/legacy/development/project-imports.js +0 -39
- package/dist/tooling/cli/legacy/development/project-lock.d.ts +0 -16
- package/dist/tooling/cli/legacy/development/project-lock.js +0 -41
- package/dist/tooling/cli/legacy/development/rebuild.d.ts +0 -13
- package/dist/tooling/cli/legacy/development/rebuild.js +0 -58
- package/dist/tooling/cli/legacy/development/report.d.ts +0 -7
- package/dist/tooling/cli/legacy/development/report.js +0 -11
- package/dist/tooling/cli/legacy/development/secrets-file.d.ts +0 -2
- package/dist/tooling/cli/legacy/development/secrets-file.js +0 -33
- package/dist/tooling/cli/legacy/development/source-watch.d.ts +0 -14
- package/dist/tooling/cli/legacy/development/source-watch.js +0 -140
- package/dist/tooling/cli/legacy/development/sources.d.ts +0 -7
- package/dist/tooling/cli/legacy/development/sources.js +0 -48
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { mkdir, rm, 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, resolveRuntime, runtime, verifyPreflight, } from '../../../../deployment/index.js';
|
|
6
|
-
import { admitProjectModule } from '../../../../project/index.js';
|
|
7
|
-
import { loadDeclaredSecrets } from '../../dotenv.js';
|
|
8
|
-
import { selectEnvironment } from '../../project.js';
|
|
9
|
-
import { stableTargetAdapter } from '../stable-target-adapter.js';
|
|
10
|
-
import { projectImportPlugin } from './project-imports.js';
|
|
11
|
-
import { DevelopmentSources } from './sources.js';
|
|
12
|
-
/** Rebuild one complete, isolated Environment candidate from authored sources. */
|
|
13
|
-
export class DevelopmentCandidateBuilder {
|
|
14
|
-
#configPath;
|
|
15
|
-
#projectDir;
|
|
16
|
-
#environment;
|
|
17
|
-
#runtimePath;
|
|
18
|
-
#overrideSecrets;
|
|
19
|
-
#generation = 0;
|
|
20
|
-
constructor(input) {
|
|
21
|
-
this.#configPath = input.configPath;
|
|
22
|
-
this.#projectDir = input.projectDir;
|
|
23
|
-
this.#environment = input.environment;
|
|
24
|
-
this.#runtimePath = input.runtimePath;
|
|
25
|
-
this.#overrideSecrets = input.overrideSecrets;
|
|
26
|
-
}
|
|
27
|
-
async prepare(signal) {
|
|
28
|
-
throwIfAborted(signal);
|
|
29
|
-
const directory = join(this.#projectDir, '.astrale', 'development', this.#environment, 'source', String(++this.#generation));
|
|
30
|
-
await mkdir(directory, { recursive: true });
|
|
31
|
-
const bridge = join(directory, 'bridge.ts');
|
|
32
|
-
const sources = new DevelopmentSources(this.#projectDir);
|
|
33
|
-
sources.record(join(this.#projectDir, 'package.json'));
|
|
34
|
-
const configImport = moduleSpecifier(dirname(bridge), this.#configPath);
|
|
35
|
-
const runtimeImport = moduleSpecifier(dirname(bridge), resolve(dirname(this.#configPath), this.#runtimePath));
|
|
36
|
-
await writeFile(bridge, `export { default as project } from ${JSON.stringify(configImport)}\n` +
|
|
37
|
-
`export { default as runtime } from ${JSON.stringify(runtimeImport)}\n`);
|
|
38
|
-
try {
|
|
39
|
-
const bunRuntime = bun();
|
|
40
|
-
const built = await bunRuntime.build({
|
|
41
|
-
entrypoints: [bridge],
|
|
42
|
-
outdir: directory,
|
|
43
|
-
naming: 'application.mjs',
|
|
44
|
-
target: 'bun',
|
|
45
|
-
format: 'esm',
|
|
46
|
-
packages: 'bundle',
|
|
47
|
-
plugins: [projectImportPlugin(this.#projectDir, bunRuntime)],
|
|
48
|
-
splitting: false,
|
|
49
|
-
sourcemap: 'inline',
|
|
50
|
-
metafile: true,
|
|
51
|
-
throw: false,
|
|
52
|
-
});
|
|
53
|
-
throwIfAborted(signal);
|
|
54
|
-
if (!built.success) {
|
|
55
|
-
const diagnostics = built.logs.map(({ message, position }) => position === undefined || position === null
|
|
56
|
-
? message
|
|
57
|
-
: `${relative(this.#projectDir, position.file)}:${position.line}:${position.column}: ${message}`);
|
|
58
|
-
throw new Error(['Authored Domain rebuild failed.', ...diagnostics].join('\n'));
|
|
59
|
-
}
|
|
60
|
-
const output = built.outputs.find((candidate) => candidate.path.endsWith('application.mjs'));
|
|
61
|
-
if (output === undefined)
|
|
62
|
-
throw new Error('Authored Domain rebuild produced no module.');
|
|
63
|
-
const loaded = (await import(`${pathToFileURL(output.path).href}?development=${this.#generation}`));
|
|
64
|
-
if (Object.keys(loaded).some((key) => key !== 'project' && key !== 'runtime')) {
|
|
65
|
-
throw new TypeError('Development bridge produced unexpected exports.');
|
|
66
|
-
}
|
|
67
|
-
const project = admitProjectModule({ default: loaded.project });
|
|
68
|
-
if ((project.entrypoints?.runtime ?? './runtime.ts') !== this.#runtimePath) {
|
|
69
|
-
throw new Error('Runtime entrypoint changed; restart pnpm dev to apply it.');
|
|
70
|
-
}
|
|
71
|
-
const environment = selectEnvironment(project, this.#environment);
|
|
72
|
-
const resolved = await resolveRuntime(runtime(this.#runtimePath), async (path) => {
|
|
73
|
-
if (path !== this.#runtimePath) {
|
|
74
|
-
throw new Error('Runtime entrypoint changed; restart pnpm dev to apply it.');
|
|
75
|
-
}
|
|
76
|
-
return Object.freeze({ default: loaded.runtime });
|
|
77
|
-
});
|
|
78
|
-
const build = compile(project.domain);
|
|
79
|
-
admitRuntime({ runtime: build.runtime }, resolved);
|
|
80
|
-
const adapter = stableTargetAdapter(environment.deployment.adapter);
|
|
81
|
-
const parameters = environment.deployment.parameters;
|
|
82
|
-
for (const path of Object.keys(built.metafile?.inputs ?? {}))
|
|
83
|
-
sources.record(path);
|
|
84
|
-
const source = await adapter.prepare(parameters, {
|
|
85
|
-
projectDir: this.#projectDir,
|
|
86
|
-
environment: this.#environment,
|
|
87
|
-
mode: 'release',
|
|
88
|
-
recordSource: sources.record,
|
|
89
|
-
signal,
|
|
90
|
-
build,
|
|
91
|
-
runtime: resolved,
|
|
92
|
-
});
|
|
93
|
-
const artifact = verifyPreflight({ build, runtime: resolved, source });
|
|
94
|
-
const declared = this.#overrideSecrets === undefined
|
|
95
|
-
? secretsFor(adapter, parameters, this.#projectDir, resolved.runtime)
|
|
96
|
-
: { values: this.#overrideSecrets };
|
|
97
|
-
if (declared.path !== undefined)
|
|
98
|
-
sources.record(declared.path);
|
|
99
|
-
return Object.freeze({
|
|
100
|
-
adapter,
|
|
101
|
-
parameters,
|
|
102
|
-
artifact,
|
|
103
|
-
secrets: declared.values,
|
|
104
|
-
sources: sources.snapshot(),
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
finally {
|
|
108
|
-
await rm(directory, { recursive: true, force: true });
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
export async function discoverRuntimePath(configPath) {
|
|
113
|
-
const loaded = (await import(`${pathToFileURL(configPath).href}?discover=${Date.now()}`));
|
|
114
|
-
const project = admitProjectModule(loaded);
|
|
115
|
-
return project.entrypoints?.runtime ?? './runtime.ts';
|
|
116
|
-
}
|
|
117
|
-
export function sameEnvironment(current, candidate) {
|
|
118
|
-
return (candidate.adapter.name === current.adapter.name &&
|
|
119
|
-
candidate.adapter.version === current.adapter.version &&
|
|
120
|
-
candidate.artifact.build.schema.compiled.root.origin ===
|
|
121
|
-
current.artifact.build.schema.compiled.root.origin &&
|
|
122
|
-
stable(candidate.parameters) === stable(current.parameters));
|
|
123
|
-
}
|
|
124
|
-
/** Identify a rebuilt candidate that cannot change provider state. */
|
|
125
|
-
export function sameDeploymentCandidate(current, candidate) {
|
|
126
|
-
return (sameEnvironment(current, candidate) &&
|
|
127
|
-
candidate.artifact.build.schema.compiled.root.revision ===
|
|
128
|
-
current.artifact.build.schema.compiled.root.revision &&
|
|
129
|
-
candidate.artifact.digest === current.artifact.digest &&
|
|
130
|
-
stable(candidate.secrets) === stable(current.secrets));
|
|
131
|
-
}
|
|
132
|
-
function secretsFor(adapter, parameters, projectDir, selectedRuntime) {
|
|
133
|
-
const file = adapter.secretsFile?.(parameters);
|
|
134
|
-
if (file === undefined)
|
|
135
|
-
return { values: Object.freeze({}) };
|
|
136
|
-
const path = isAbsolute(file) ? file : join(projectDir, file);
|
|
137
|
-
if (Object.keys(selectedRuntime.integrations).length === 0 && !existsSync(path)) {
|
|
138
|
-
return { values: Object.freeze({}) };
|
|
139
|
-
}
|
|
140
|
-
return { values: Object.freeze(loadDeclaredSecrets(path, file)), path };
|
|
141
|
-
}
|
|
142
|
-
function bun() {
|
|
143
|
-
const value = Reflect.get(globalThis, 'Bun');
|
|
144
|
-
if (value === undefined || typeof value.build !== 'function') {
|
|
145
|
-
throw new TypeError('Domain development requires the Bun runtime.');
|
|
146
|
-
}
|
|
147
|
-
return value;
|
|
148
|
-
}
|
|
149
|
-
function moduleSpecifier(from, target) {
|
|
150
|
-
const path = relative(from, target).split(sep).join('/');
|
|
151
|
-
return path.startsWith('.') ? path : `./${path}`;
|
|
152
|
-
}
|
|
153
|
-
function stable(input) {
|
|
154
|
-
if (input === undefined)
|
|
155
|
-
return 'undefined';
|
|
156
|
-
if (input === null || typeof input !== 'object')
|
|
157
|
-
return JSON.stringify(input);
|
|
158
|
-
if (Array.isArray(input))
|
|
159
|
-
return `[${input.map(stable).join(',')}]`;
|
|
160
|
-
const record = input;
|
|
161
|
-
return `{${Object.keys(record)
|
|
162
|
-
.sort()
|
|
163
|
-
.map((key) => `${JSON.stringify(key)}:${stable(record[key])}`)
|
|
164
|
-
.join(',')}}`;
|
|
165
|
-
}
|
|
166
|
-
function throwIfAborted(signal) {
|
|
167
|
-
if (signal.aborted) {
|
|
168
|
-
throw signal.reason instanceof Error ? signal.reason : new Error('Development interrupted.');
|
|
169
|
-
}
|
|
170
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { closeSync, constants, fstatSync, openSync, readSync } from 'node:fs';
|
|
2
|
-
const MAXIMUM_CREDENTIAL_BYTES = 64 * 1024;
|
|
3
|
-
/** Admit one caller-owned credential without retaining its value outside this command. */
|
|
4
|
-
export function loadPrivateCredentialFile(path, platform = process.platform) {
|
|
5
|
-
if (platform === 'win32') {
|
|
6
|
-
throw new Error('--credential-file is unavailable on Windows until private no-reparse file admission is supported.');
|
|
7
|
-
}
|
|
8
|
-
let descriptor;
|
|
9
|
-
try {
|
|
10
|
-
descriptor = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
11
|
-
}
|
|
12
|
-
catch (cause) {
|
|
13
|
-
if (errorCode(cause) === 'ENOENT') {
|
|
14
|
-
throw new Error(`Credential file '${path}' is missing.`, { cause });
|
|
15
|
-
}
|
|
16
|
-
if (errorCode(cause) === 'ELOOP') {
|
|
17
|
-
throw new Error(`Credential file '${path}' must be a regular file and not a symlink.`, {
|
|
18
|
-
cause,
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
throw cause;
|
|
22
|
-
}
|
|
23
|
-
try {
|
|
24
|
-
const info = fstatSync(descriptor);
|
|
25
|
-
if (!info.isFile())
|
|
26
|
-
throw new Error(`Credential file '${path}' must be a regular file.`);
|
|
27
|
-
if ((info.mode & 0o077) !== 0) {
|
|
28
|
-
throw new Error(`Credential file '${path}' must not be accessible by group or other users.`);
|
|
29
|
-
}
|
|
30
|
-
if (info.size === 0 || info.size > MAXIMUM_CREDENTIAL_BYTES) {
|
|
31
|
-
throw new Error(`Credential file '${path}' must contain one bounded credential.`);
|
|
32
|
-
}
|
|
33
|
-
const bytes = Buffer.allocUnsafe(info.size + 1);
|
|
34
|
-
let offset = 0;
|
|
35
|
-
while (offset < bytes.length) {
|
|
36
|
-
const read = readSync(descriptor, bytes, offset, bytes.length - offset, null);
|
|
37
|
-
if (read === 0)
|
|
38
|
-
break;
|
|
39
|
-
offset += read;
|
|
40
|
-
}
|
|
41
|
-
if (offset !== info.size)
|
|
42
|
-
throw new Error(`Credential file '${path}' changed while read.`);
|
|
43
|
-
const credential = bytes.subarray(0, offset).toString('utf8').trim();
|
|
44
|
-
if (credential.length === 0 || /[\r\n\0]/u.test(credential)) {
|
|
45
|
-
throw new Error(`Credential file '${path}' must contain exactly one credential.`);
|
|
46
|
-
}
|
|
47
|
-
return credential;
|
|
48
|
-
}
|
|
49
|
-
finally {
|
|
50
|
-
closeSync(descriptor);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
function errorCode(input) {
|
|
54
|
-
return input !== null && typeof input === 'object' && 'code' in input
|
|
55
|
-
? String(Reflect.get(input, 'code'))
|
|
56
|
-
: undefined;
|
|
57
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { ReadyDeployResult } from '../../../../deployment/adapter/index.js';
|
|
2
|
-
import type { DevelopmentCandidate } from './candidate.js';
|
|
3
|
-
export interface DevelopmentDeploymentInput {
|
|
4
|
-
readonly projectDir: string;
|
|
5
|
-
readonly environment: string;
|
|
6
|
-
readonly identity?: string;
|
|
7
|
-
readonly credential?: string;
|
|
8
|
-
}
|
|
9
|
-
/** Commit and verify one complete remote candidate. A development deployment installs nothing. */
|
|
10
|
-
export declare function deployDevelopmentCandidate(candidate: DevelopmentCandidate, input: DevelopmentDeploymentInput, signal: AbortSignal): Promise<ReadyDeployResult>;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { verifyDeployment } from '../../../../deployment/index.js';
|
|
2
|
-
/** Commit and verify one complete remote candidate. A development deployment installs nothing. */
|
|
3
|
-
export async function deployDevelopmentCandidate(candidate, input, signal) {
|
|
4
|
-
const deployed = await candidate.adapter.deploy(candidate.parameters, {
|
|
5
|
-
projectDir: input.projectDir,
|
|
6
|
-
environment: input.environment,
|
|
7
|
-
...(input.identity === undefined ? {} : { identity: input.identity }),
|
|
8
|
-
...(input.credential === undefined ? {} : { credential: input.credential }),
|
|
9
|
-
secrets: candidate.secrets,
|
|
10
|
-
artifact: candidate.artifact,
|
|
11
|
-
signal,
|
|
12
|
-
});
|
|
13
|
-
const verified = verifyDeployment(candidate.artifact, deployed);
|
|
14
|
-
if (verified.status === 'failed') {
|
|
15
|
-
throw new Error(`Deployment failed during ${verified.phase}: ${verified.error.message}`, {
|
|
16
|
-
cause: verified.error,
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
return verified;
|
|
20
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What replaces `astrale-domain dev`, for its author: development is not a command of the
|
|
3
|
-
* deployment model. A developer, or an agent, deploys the Environment and installs the URL that
|
|
4
|
-
* deploy prints on their own instance.
|
|
5
|
-
*
|
|
6
|
-
* `--direct` sends that URL to the instance's Kernel. Without it, the CLI releases published so
|
|
7
|
-
* far route a bare URL through the Admin catalog, which only knows published entries, so a fresh
|
|
8
|
-
* deployment URL fails to install. The CLI keeps accepting `--direct` after it starts sending
|
|
9
|
-
* every URL to the Kernel, and drops the flag only after this command is removed.
|
|
10
|
-
*/
|
|
11
|
-
export declare function developmentDeprecation(environment: string): string;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What replaces `astrale-domain dev`, for its author: development is not a command of the
|
|
3
|
-
* deployment model. A developer, or an agent, deploys the Environment and installs the URL that
|
|
4
|
-
* deploy prints on their own instance.
|
|
5
|
-
*
|
|
6
|
-
* `--direct` sends that URL to the instance's Kernel. Without it, the CLI releases published so
|
|
7
|
-
* far route a bare URL through the Admin catalog, which only knows published entries, so a fresh
|
|
8
|
-
* deployment URL fails to install. The CLI keeps accepting `--direct` after it starts sending
|
|
9
|
-
* every URL to the Kernel, and drops the flag only after this command is removed.
|
|
10
|
-
*/
|
|
11
|
-
export function developmentDeprecation(environment) {
|
|
12
|
-
return `astrale-domain dev is deprecated and will be removed: run \`astrale-domain deploy ${environment}\`, then \`astrale domain install <url> --direct -i <instance>\` with the URL it prints.`;
|
|
13
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Watch one Project Environment and serialize complete remote deployment generations. Each
|
|
3
|
-
* generation replaces the Environment's stable target in place; none installs anything.
|
|
4
|
-
*
|
|
5
|
-
* @deprecated Deploy the Environment with `astrale-domain deploy`, then install the printed URL
|
|
6
|
-
* with `astrale domain install <url> --direct -i <instance>`.
|
|
7
|
-
*/
|
|
8
|
-
export declare function develop(input: {
|
|
9
|
-
readonly configPath: string;
|
|
10
|
-
readonly projectDir: string;
|
|
11
|
-
readonly environment: string;
|
|
12
|
-
readonly identity?: string;
|
|
13
|
-
readonly credentialFile?: string;
|
|
14
|
-
readonly secretsFile?: string;
|
|
15
|
-
}): Promise<number>;
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { rm, rmdir } from 'node:fs/promises';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { deprecationWarnings } from '../../deprecations.js';
|
|
4
|
-
import { error, info, warn } from '../../log.js';
|
|
5
|
-
import { DevelopmentCandidateBuilder, discoverRuntimePath, sameDeploymentCandidate, sameEnvironment, } from './candidate.js';
|
|
6
|
-
import { loadPrivateCredentialFile } from './credential.js';
|
|
7
|
-
import { deployDevelopmentCandidate } from './deployment.js';
|
|
8
|
-
import { DevelopmentLifecycle } from './lifecycle.js';
|
|
9
|
-
import { acquireProjectLock } from './project-lock.js';
|
|
10
|
-
import { LatestRebuild } from './rebuild.js';
|
|
11
|
-
import { reportDevelopmentDeployment } from './report.js';
|
|
12
|
-
import { loadPrivateSecretsFile } from './secrets-file.js';
|
|
13
|
-
import { watchSources } from './source-watch.js';
|
|
14
|
-
/**
|
|
15
|
-
* Watch one Project Environment and serialize complete remote deployment generations. Each
|
|
16
|
-
* generation replaces the Environment's stable target in place; none installs anything.
|
|
17
|
-
*
|
|
18
|
-
* @deprecated Deploy the Environment with `astrale-domain deploy`, then install the printed URL
|
|
19
|
-
* with `astrale domain install <url> --direct -i <instance>`.
|
|
20
|
-
*/
|
|
21
|
-
export async function develop(input) {
|
|
22
|
-
const lifecycle = new DevelopmentLifecycle();
|
|
23
|
-
let lock;
|
|
24
|
-
let sourceWatch;
|
|
25
|
-
let rebuild;
|
|
26
|
-
let current;
|
|
27
|
-
let failure;
|
|
28
|
-
const cleanup = [];
|
|
29
|
-
try {
|
|
30
|
-
lock = await acquireProjectLock({
|
|
31
|
-
projectRoot: input.projectDir,
|
|
32
|
-
environment: input.environment,
|
|
33
|
-
});
|
|
34
|
-
const overrideSecrets = input.secretsFile === undefined
|
|
35
|
-
? undefined
|
|
36
|
-
: Object.freeze(loadPrivateSecretsFile(input.secretsFile));
|
|
37
|
-
const credential = input.credentialFile === undefined
|
|
38
|
-
? undefined
|
|
39
|
-
: loadPrivateCredentialFile(input.credentialFile);
|
|
40
|
-
const runtimePath = await discoverRuntimePath(input.configPath);
|
|
41
|
-
const builder = new DevelopmentCandidateBuilder({
|
|
42
|
-
...input,
|
|
43
|
-
runtimePath,
|
|
44
|
-
overrideSecrets,
|
|
45
|
-
});
|
|
46
|
-
current = await builder.prepare(lifecycle.signal);
|
|
47
|
-
info(`Domain: ${current.artifact.build.schema.compiled.root.origin}`);
|
|
48
|
-
for (const warning of deprecationWarnings(current.artifact.build))
|
|
49
|
-
warn(warning);
|
|
50
|
-
const first = await deployDevelopmentCandidate(current, { ...input, ...(credential === undefined ? {} : { credential }) }, lifecycle.signal);
|
|
51
|
-
reportDevelopmentDeployment(first, current.adapter, input);
|
|
52
|
-
let restartReported = false;
|
|
53
|
-
rebuild = new LatestRebuild({
|
|
54
|
-
async prepare(_ignored, signal) {
|
|
55
|
-
info(`Rebuilding: ${input.environment}`);
|
|
56
|
-
return builder.prepare(signal);
|
|
57
|
-
},
|
|
58
|
-
async commit(candidate, signal) {
|
|
59
|
-
if (!sameEnvironment(current, candidate)) {
|
|
60
|
-
restartReported = true;
|
|
61
|
-
throw new Error('Project Environment configuration changed; restart pnpm dev to apply it.');
|
|
62
|
-
}
|
|
63
|
-
if (sameDeploymentCandidate(current, candidate)) {
|
|
64
|
-
current = candidate;
|
|
65
|
-
sourceWatch?.update(candidate.sources);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
const deployed = await deployDevelopmentCandidate(candidate, { ...input, ...(credential === undefined ? {} : { credential }) }, signal);
|
|
69
|
-
current = candidate;
|
|
70
|
-
sourceWatch?.update(candidate.sources);
|
|
71
|
-
info(`Updated: ${candidate.artifact.build.schema.compiled.root.revision}`);
|
|
72
|
-
reportDevelopmentDeployment(deployed, candidate.adapter, input);
|
|
73
|
-
},
|
|
74
|
-
async failed(cause) {
|
|
75
|
-
error(cause instanceof Error ? cause.message : String(cause));
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
sourceWatch = watchSources({
|
|
79
|
-
projectDir: input.projectDir,
|
|
80
|
-
configPath: input.configPath,
|
|
81
|
-
sources: current.sources,
|
|
82
|
-
onInvalidate: () => rebuild.invalidate(),
|
|
83
|
-
onRestartRequired: () => {
|
|
84
|
-
if (restartReported)
|
|
85
|
-
return;
|
|
86
|
-
restartReported = true;
|
|
87
|
-
error('Project Environment configuration changed; restart pnpm dev to apply it.');
|
|
88
|
-
},
|
|
89
|
-
onError: (cause) => {
|
|
90
|
-
failure = cause;
|
|
91
|
-
lifecycle.stop(cause);
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
info('Ready: watching for remote deployments');
|
|
95
|
-
// Edits made while the first build/deployment was in flight predate this watcher.
|
|
96
|
-
// Catch up once; artifact deduplication prevents an unchanged second deployment.
|
|
97
|
-
rebuild.invalidate();
|
|
98
|
-
await lifecycle.stopped;
|
|
99
|
-
}
|
|
100
|
-
catch (cause) {
|
|
101
|
-
failure = cause;
|
|
102
|
-
}
|
|
103
|
-
lifecycle.stop(failure);
|
|
104
|
-
for (const operation of [
|
|
105
|
-
() => sourceWatch?.stop(),
|
|
106
|
-
() => rebuild?.stop(failure),
|
|
107
|
-
() => rm(join(input.projectDir, '.astrale', 'development', input.environment, 'source'), {
|
|
108
|
-
recursive: true,
|
|
109
|
-
force: true,
|
|
110
|
-
}),
|
|
111
|
-
() => lock?.release(),
|
|
112
|
-
]) {
|
|
113
|
-
try {
|
|
114
|
-
await operation();
|
|
115
|
-
}
|
|
116
|
-
catch (cause) {
|
|
117
|
-
cleanup.push(cause);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
for (const directory of [
|
|
121
|
-
join(input.projectDir, '.astrale', 'development', input.environment),
|
|
122
|
-
join(input.projectDir, '.astrale', 'development'),
|
|
123
|
-
]) {
|
|
124
|
-
try {
|
|
125
|
-
await rmdir(directory);
|
|
126
|
-
}
|
|
127
|
-
catch (cause) {
|
|
128
|
-
const code = cause.code;
|
|
129
|
-
if (code !== 'ENOENT' && code !== 'ENOTEMPTY' && code !== 'EEXIST')
|
|
130
|
-
cleanup.push(cause);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
lifecycle.dispose();
|
|
134
|
-
if (failure !== undefined) {
|
|
135
|
-
if (cleanup.length > 0)
|
|
136
|
-
error(new AggregateError(cleanup, 'Development cleanup failed.').message);
|
|
137
|
-
throw failure;
|
|
138
|
-
}
|
|
139
|
-
if (cleanup.length > 0)
|
|
140
|
-
throw new AggregateError(cleanup, 'Development cleanup failed.');
|
|
141
|
-
return 0;
|
|
142
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `astrale-domain dev` (legacy, deprecated).
|
|
3
|
-
*
|
|
4
|
-
* Development is not a command of the deployment model: a developer, or an agent, iterates with
|
|
5
|
-
* `astrale-domain deploy development`, then `astrale domain install <url> --direct -i <instance>`. This
|
|
6
|
-
* folder keeps the watch loop that updates one deployment per Domain origin and Environment in
|
|
7
|
-
* place and its private file boundaries, exactly as before. Every run warns with that replacement
|
|
8
|
-
* on stderr.
|
|
9
|
-
*
|
|
10
|
-
* Short-term consumers: the `dev` scripts of the Domain packages that still deploy in place,
|
|
11
|
-
* namely the domains repository's ai-gateway, closing, grc, integrations, issues, organization and
|
|
12
|
-
* services packages, the Shell, and ui's Domain, and of the Projects create-astrale-domain
|
|
13
|
-
* scaffolds while its template still declares `dev`. Projects that pin an SDK release older than
|
|
14
|
-
* this folder never reach it.
|
|
15
|
-
*
|
|
16
|
-
* Deletion: once none of those packages runs `astrale-domain dev`, a separate breaking release
|
|
17
|
-
* deletes this folder with the `dev` command and its `--credential-file` and `--secrets-file`
|
|
18
|
-
* flags.
|
|
19
|
-
*/
|
|
20
|
-
export { develop } from './develop.js';
|
|
21
|
-
export { developmentDeprecation } from './deprecation.js';
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `astrale-domain dev` (legacy, deprecated).
|
|
3
|
-
*
|
|
4
|
-
* Development is not a command of the deployment model: a developer, or an agent, iterates with
|
|
5
|
-
* `astrale-domain deploy development`, then `astrale domain install <url> --direct -i <instance>`. This
|
|
6
|
-
* folder keeps the watch loop that updates one deployment per Domain origin and Environment in
|
|
7
|
-
* place and its private file boundaries, exactly as before. Every run warns with that replacement
|
|
8
|
-
* on stderr.
|
|
9
|
-
*
|
|
10
|
-
* Short-term consumers: the `dev` scripts of the Domain packages that still deploy in place,
|
|
11
|
-
* namely the domains repository's ai-gateway, closing, grc, integrations, issues, organization and
|
|
12
|
-
* services packages, the Shell, and ui's Domain, and of the Projects create-astrale-domain
|
|
13
|
-
* scaffolds while its template still declares `dev`. Projects that pin an SDK release older than
|
|
14
|
-
* this folder never reach it.
|
|
15
|
-
*
|
|
16
|
-
* Deletion: once none of those packages runs `astrale-domain dev`, a separate breaking release
|
|
17
|
-
* deletes this folder with the `dev` command and its `--credential-file` and `--secrets-file`
|
|
18
|
-
* flags.
|
|
19
|
-
*/
|
|
20
|
-
export { develop } from './develop.js';
|
|
21
|
-
export { developmentDeprecation } from './deprecation.js';
|
|
@@ -1,18 +0,0 @@
|
|
|
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>;
|