@astrale-os/sdk 0.6.0-beta.18 → 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.
Files changed (46) hide show
  1. package/README.md +1 -1
  2. package/dist/deployment/adapter/legacy/index.d.ts +2 -2
  3. package/dist/deployment/adapter/legacy/prepare/context.d.ts +4 -5
  4. package/dist/tooling/cli/arguments.d.ts +1 -3
  5. package/dist/tooling/cli/arguments.js +5 -39
  6. package/dist/tooling/cli/bun.d.ts +0 -1
  7. package/dist/tooling/cli/bun.js +0 -7
  8. package/dist/tooling/cli/deploy-mode.d.ts +4 -4
  9. package/dist/tooling/cli/deploy-mode.js +2 -15
  10. package/dist/tooling/cli/help.js +3 -50
  11. package/dist/tooling/cli/index.d.ts +1 -2
  12. package/dist/tooling/cli/index.js +1 -2
  13. package/dist/tooling/cli/legacy/stable-target-adapter.d.ts +1 -1
  14. package/dist/tooling/cli/orchestrate.d.ts +0 -6
  15. package/dist/tooling/cli/orchestrate.js +0 -28
  16. package/package.json +2 -2
  17. package/dist/tooling/cli/legacy/development/candidate.d.ts +0 -25
  18. package/dist/tooling/cli/legacy/development/candidate.js +0 -170
  19. package/dist/tooling/cli/legacy/development/credential.d.ts +0 -2
  20. package/dist/tooling/cli/legacy/development/credential.js +0 -57
  21. package/dist/tooling/cli/legacy/development/deployment.d.ts +0 -10
  22. package/dist/tooling/cli/legacy/development/deployment.js +0 -20
  23. package/dist/tooling/cli/legacy/development/deprecation.d.ts +0 -11
  24. package/dist/tooling/cli/legacy/development/deprecation.js +0 -13
  25. package/dist/tooling/cli/legacy/development/develop.d.ts +0 -15
  26. package/dist/tooling/cli/legacy/development/develop.js +0 -142
  27. package/dist/tooling/cli/legacy/development/index.d.ts +0 -21
  28. package/dist/tooling/cli/legacy/development/index.js +0 -21
  29. package/dist/tooling/cli/legacy/development/lease.d.ts +0 -18
  30. package/dist/tooling/cli/legacy/development/lease.js +0 -163
  31. package/dist/tooling/cli/legacy/development/lifecycle.d.ts +0 -9
  32. package/dist/tooling/cli/legacy/development/lifecycle.js +0 -43
  33. package/dist/tooling/cli/legacy/development/project-imports.d.ts +0 -22
  34. package/dist/tooling/cli/legacy/development/project-imports.js +0 -39
  35. package/dist/tooling/cli/legacy/development/project-lock.d.ts +0 -16
  36. package/dist/tooling/cli/legacy/development/project-lock.js +0 -41
  37. package/dist/tooling/cli/legacy/development/rebuild.d.ts +0 -13
  38. package/dist/tooling/cli/legacy/development/rebuild.js +0 -58
  39. package/dist/tooling/cli/legacy/development/report.d.ts +0 -7
  40. package/dist/tooling/cli/legacy/development/report.js +0 -11
  41. package/dist/tooling/cli/legacy/development/secrets-file.d.ts +0 -2
  42. package/dist/tooling/cli/legacy/development/secrets-file.js +0 -33
  43. package/dist/tooling/cli/legacy/development/source-watch.d.ts +0 -14
  44. package/dist/tooling/cli/legacy/development/source-watch.js +0 -140
  45. package/dist/tooling/cli/legacy/development/sources.d.ts +0 -7
  46. package/dist/tooling/cli/legacy/development/sources.js +0 -48
@@ -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>;
@@ -1,163 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- import { mkdir, open, readFile, unlink } from 'node:fs/promises';
3
- import { join } from 'node:path';
4
- const LOCK_VERSION = 1;
5
- export class DevelopmentLeaseError extends Error {
6
- code;
7
- name = 'DevelopmentLeaseError';
8
- constructor(code, message, options) {
9
- super(message, options);
10
- this.code = code;
11
- }
12
- }
13
- /** One fail-closed filesystem lease engine for every local development coordinate. */
14
- export async function acquireDevelopmentLease(input) {
15
- const path = join(input.directory, 'session.lock');
16
- const recovery = `${path}.reclaim`;
17
- const sessionId = input.sessionId ?? randomUUID();
18
- const alive = input.processAlive ?? processAlive;
19
- const owner = Object.freeze({
20
- version: LOCK_VERSION,
21
- pid: input.pid ?? process.pid,
22
- sessionId,
23
- coordinate: input.coordinate,
24
- acquiredAt: new Date().toISOString(),
25
- });
26
- await mkdir(input.directory, { recursive: true, mode: 0o700 });
27
- try {
28
- await create(path, owner);
29
- return handle(path, input.coordinate, owner, false);
30
- }
31
- catch (cause) {
32
- if (errorCode(cause) !== 'EEXIST')
33
- throw cause;
34
- }
35
- let recoveryHandle;
36
- try {
37
- recoveryHandle = await open(recovery, 'wx', 0o600);
38
- await recoveryHandle.writeFile(`${sessionId}\n`, 'utf8');
39
- await recoveryHandle.sync();
40
- }
41
- catch (cause) {
42
- if (errorCode(cause) === 'EEXIST')
43
- throw locked(input.coordinate);
44
- throw cause;
45
- }
46
- finally {
47
- await recoveryHandle?.close();
48
- }
49
- try {
50
- const observed = await readOwner(path, input.coordinate);
51
- if (observed === undefined || alive(observed.pid))
52
- throw locked(input.coordinate, observed);
53
- const current = await readOwner(path, input.coordinate);
54
- if (!sameOwner(current, observed) || alive(observed.pid)) {
55
- throw locked(input.coordinate, current);
56
- }
57
- await unlink(path);
58
- try {
59
- await create(path, owner);
60
- }
61
- catch (cause) {
62
- if (errorCode(cause) === 'EEXIST')
63
- throw locked(input.coordinate);
64
- throw cause;
65
- }
66
- return handle(path, input.coordinate, owner, true);
67
- }
68
- finally {
69
- await unlink(recovery).catch((cause) => {
70
- if (errorCode(cause) !== 'ENOENT')
71
- throw cause;
72
- });
73
- }
74
- }
75
- function handle(path, coordinate, owner, recovered) {
76
- let released = false;
77
- return Object.freeze({
78
- path,
79
- recovered,
80
- async release() {
81
- if (released)
82
- return;
83
- const current = await readOwner(path, coordinate);
84
- if (!sameOwner(current, owner)) {
85
- throw new DevelopmentLeaseError('DEVELOPMENT_LEASE_LOST', `Development lease ownership changed for ${coordinate}; refusing to remove it.`);
86
- }
87
- await unlink(path);
88
- released = true;
89
- },
90
- });
91
- }
92
- async function create(path, owner) {
93
- const file = await open(path, 'wx', 0o600);
94
- try {
95
- await file.writeFile(`${JSON.stringify(owner)}\n`, 'utf8');
96
- await file.sync();
97
- }
98
- catch (cause) {
99
- await file.close();
100
- await unlink(path).catch(() => undefined);
101
- throw cause;
102
- }
103
- await file.close();
104
- }
105
- async function readOwner(path, coordinate) {
106
- let text;
107
- try {
108
- text = await readFile(path, 'utf8');
109
- }
110
- catch (cause) {
111
- if (errorCode(cause) === 'ENOENT')
112
- return undefined;
113
- throw cause;
114
- }
115
- let value;
116
- try {
117
- value = JSON.parse(text);
118
- }
119
- catch (cause) {
120
- throw locked(coordinate, undefined, cause);
121
- }
122
- if (!isOwner(value) || value.coordinate !== coordinate)
123
- throw locked(coordinate);
124
- return value;
125
- }
126
- function isOwner(input) {
127
- if (input === null || typeof input !== 'object' || Array.isArray(input))
128
- return false;
129
- const owner = input;
130
- return (Reflect.ownKeys(owner).every((key) => ['version', 'pid', 'sessionId', 'coordinate', 'acquiredAt'].includes(String(key))) &&
131
- owner.version === LOCK_VERSION &&
132
- Number.isSafeInteger(owner.pid) &&
133
- (owner.pid ?? 0) > 0 &&
134
- typeof owner.sessionId === 'string' &&
135
- owner.sessionId.length > 0 &&
136
- typeof owner.coordinate === 'string' &&
137
- owner.coordinate.length > 0 &&
138
- typeof owner.acquiredAt === 'string');
139
- }
140
- function sameOwner(left, right) {
141
- return (left?.version === right.version &&
142
- left.pid === right.pid &&
143
- left.sessionId === right.sessionId &&
144
- left.coordinate === right.coordinate);
145
- }
146
- function locked(coordinate, owner, cause) {
147
- const detail = owner === undefined ? '' : ` by PID ${owner.pid} (session ${owner.sessionId})`;
148
- return new DevelopmentLeaseError('DEVELOPMENT_LEASE_LOCKED', `Development coordinate ${coordinate} is already locked${detail}.`, cause === undefined ? undefined : { cause });
149
- }
150
- function processAlive(pid) {
151
- try {
152
- process.kill(pid, 0);
153
- return true;
154
- }
155
- catch (cause) {
156
- return errorCode(cause) !== 'ESRCH';
157
- }
158
- }
159
- function errorCode(input) {
160
- return input !== null && typeof input === 'object' && 'code' in input
161
- ? String(Reflect.get(input, 'code'))
162
- : undefined;
163
- }
@@ -1,9 +0,0 @@
1
- /** Own process signals for exactly one foreground development command. */
2
- export declare class DevelopmentLifecycle {
3
- #private;
4
- constructor();
5
- get signal(): AbortSignal;
6
- get stopped(): Promise<void>;
7
- stop(reason?: unknown): void;
8
- dispose(): void;
9
- }
@@ -1,43 +0,0 @@
1
- /** Own process signals for exactly one foreground development command. */
2
- export class DevelopmentLifecycle {
3
- #controller = new AbortController();
4
- #stopped;
5
- #resolveStopped;
6
- #disposed = false;
7
- constructor() {
8
- let resolveStopped;
9
- this.#stopped = new Promise((resolve) => {
10
- resolveStopped = resolve;
11
- });
12
- this.#resolveStopped = resolveStopped;
13
- // Keep handlers installed throughout cleanup. This covers direct Bun
14
- // invocation and any duplicate signal forwarding by an older launcher:
15
- // repeated interrupts remain idempotent stop requests instead of reverting
16
- // to the runtime's immediate default termination.
17
- process.on('SIGINT', this.#interrupt);
18
- process.on('SIGTERM', this.#interrupt);
19
- // The terminal's session leader can exit before asynchronous cleanup finishes.
20
- // Its hangup must request the same stop, not terminate the remaining View owner.
21
- process.on('SIGHUP', this.#interrupt);
22
- }
23
- get signal() {
24
- return this.#controller.signal;
25
- }
26
- get stopped() {
27
- return this.#stopped;
28
- }
29
- stop(reason = new Error('Development interrupted.')) {
30
- if (!this.#controller.signal.aborted)
31
- this.#controller.abort(reason);
32
- this.#resolveStopped();
33
- }
34
- dispose() {
35
- if (this.#disposed)
36
- return;
37
- this.#disposed = true;
38
- process.off('SIGINT', this.#interrupt);
39
- process.off('SIGTERM', this.#interrupt);
40
- process.off('SIGHUP', this.#interrupt);
41
- }
42
- #interrupt = () => this.stop();
43
- }
@@ -1,22 +0,0 @@
1
- interface ProjectImportResolver {
2
- resolveSync(specifier: string, importer: string): string;
3
- }
4
- interface ProjectImportResolution {
5
- readonly path: string;
6
- readonly external?: boolean;
7
- }
8
- interface ProjectImportBuilder {
9
- onResolve(options: {
10
- readonly filter: RegExp;
11
- }, resolve: (input: {
12
- readonly path: string;
13
- readonly importer: string;
14
- }) => ProjectImportResolution | undefined): void;
15
- }
16
- export interface ProjectImportPlugin {
17
- readonly name: string;
18
- setup(builder: ProjectImportBuilder): void;
19
- }
20
- /** Bundle project-local bare imports while leaving actual dependencies external. */
21
- export declare function projectImportPlugin(projectDir: string, resolver: ProjectImportResolver): ProjectImportPlugin;
22
- export {};
@@ -1,39 +0,0 @@
1
- import { realpathSync } from 'node:fs';
2
- import { isAbsolute, relative, resolve, sep } from 'node:path';
3
- /** Bundle project-local bare imports while leaving actual dependencies external. */
4
- export function projectImportPlugin(projectDir, resolver) {
5
- return Object.freeze({
6
- name: 'astrale-project-imports',
7
- setup(builder) {
8
- builder.onResolve({ filter: /^[^./]/u }, (input) => {
9
- let path;
10
- try {
11
- path = resolver.resolveSync(input.path, input.importer);
12
- }
13
- catch {
14
- return Object.freeze({ path: input.path, external: true });
15
- }
16
- return projectLocal(projectDir, path)
17
- ? Object.freeze({ path })
18
- : Object.freeze({ path: input.path, external: true });
19
- });
20
- },
21
- });
22
- }
23
- function projectLocal(projectDir, path) {
24
- if (!isAbsolute(path))
25
- return false;
26
- const local = relative(canonical(projectDir), canonical(path));
27
- return (local !== '..' &&
28
- !local.startsWith(`..${sep}`) &&
29
- !isAbsolute(local) &&
30
- !local.split(sep).includes('node_modules'));
31
- }
32
- function canonical(path) {
33
- try {
34
- return realpathSync.native(path);
35
- }
36
- catch {
37
- return resolve(path);
38
- }
39
- }
@@ -1,16 +0,0 @@
1
- import type { DevelopmentLease } from './lease.js';
2
- export declare class ProjectLockError extends Error {
3
- readonly code: 'INVALID_ENVIRONMENT' | 'PROJECT_ENVIRONMENT_LOCKED';
4
- readonly name = "ProjectLockError";
5
- constructor(code: 'INVALID_ENVIRONMENT' | 'PROJECT_ENVIRONMENT_LOCKED', message: string, options?: ErrorOptions);
6
- }
7
- export interface ProjectLock extends DevelopmentLease {
8
- }
9
- /** Exclude concurrent writers of one checkout's generated Environment state. */
10
- export declare function acquireProjectLock(input: {
11
- readonly projectRoot: string;
12
- readonly environment: string;
13
- readonly pid?: number;
14
- readonly sessionId?: string;
15
- readonly processAlive?: (pid: number) => boolean;
16
- }): Promise<ProjectLock>;