@amalgm/apps 0.1.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/PURPOSE.md +98 -0
- package/README.md +61 -0
- package/dist/apps.d.ts +58 -0
- package/dist/apps.js +274 -0
- package/dist/apps.js.map +1 -0
- package/dist/bin/apps.d.ts +2 -0
- package/dist/bin/apps.js +6 -0
- package/dist/bin/apps.js.map +1 -0
- package/dist/bin/mcp.d.ts +2 -0
- package/dist/bin/mcp.js +15 -0
- package/dist/bin/mcp.js.map +1 -0
- package/dist/boundaries.d.ts +11 -0
- package/dist/boundaries.js +55 -0
- package/dist/boundaries.js.map +1 -0
- package/dist/changes.d.ts +14 -0
- package/dist/changes.js +23 -0
- package/dist/changes.js.map +1 -0
- package/dist/cli.d.ts +24 -0
- package/dist/cli.js +138 -0
- package/dist/cli.js.map +1 -0
- package/dist/command.d.ts +3 -0
- package/dist/command.js +40 -0
- package/dist/command.js.map +1 -0
- package/dist/faults.d.ts +21 -0
- package/dist/faults.js +59 -0
- package/dist/faults.js.map +1 -0
- package/dist/generations.d.ts +28 -0
- package/dist/generations.js +83 -0
- package/dist/generations.js.map +1 -0
- package/dist/health.d.ts +35 -0
- package/dist/health.js +116 -0
- package/dist/health.js.map +1 -0
- package/dist/identity.d.ts +10 -0
- package/dist/identity.js +59 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/lease.d.ts +30 -0
- package/dist/lease.js +82 -0
- package/dist/lease.js.map +1 -0
- package/dist/logs.d.ts +11 -0
- package/dist/logs.js +40 -0
- package/dist/logs.js.map +1 -0
- package/dist/manifest.d.ts +6 -0
- package/dist/manifest.js +105 -0
- package/dist/manifest.js.map +1 -0
- package/dist/mcp-server.d.ts +3 -0
- package/dist/mcp-server.js +65 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mcp.d.ts +4 -0
- package/dist/mcp.js +171 -0
- package/dist/mcp.js.map +1 -0
- package/dist/operations.d.ts +10 -0
- package/dist/operations.js +31 -0
- package/dist/operations.js.map +1 -0
- package/dist/ownership.d.ts +11 -0
- package/dist/ownership.js +75 -0
- package/dist/ownership.js.map +1 -0
- package/dist/package.d.ts +20 -0
- package/dist/package.js +204 -0
- package/dist/package.js.map +1 -0
- package/dist/presentation.d.ts +9 -0
- package/dist/presentation.js +63 -0
- package/dist/presentation.js.map +1 -0
- package/dist/process.d.ts +10 -0
- package/dist/process.js +68 -0
- package/dist/process.js.map +1 -0
- package/dist/reconciler.d.ts +27 -0
- package/dist/reconciler.js +103 -0
- package/dist/reconciler.js.map +1 -0
- package/dist/releases.d.ts +26 -0
- package/dist/releases.js +108 -0
- package/dist/releases.js.map +1 -0
- package/dist/restarts.d.ts +40 -0
- package/dist/restarts.js +137 -0
- package/dist/restarts.js.map +1 -0
- package/dist/runtime.d.ts +19 -0
- package/dist/runtime.js +57 -0
- package/dist/runtime.js.map +1 -0
- package/dist/schema.d.ts +3 -0
- package/dist/schema.js +80 -0
- package/dist/schema.js.map +1 -0
- package/dist/source-import.d.ts +4 -0
- package/dist/source-import.js +77 -0
- package/dist/source-import.js.map +1 -0
- package/dist/store.d.ts +29 -0
- package/dist/store.js +221 -0
- package/dist/store.js.map +1 -0
- package/dist/supervisor.d.ts +29 -0
- package/dist/supervisor.js +279 -0
- package/dist/supervisor.js.map +1 -0
- package/dist/types.d.ts +264 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/docs/ENGINE_INTEGRATION.md +68 -0
- package/docs/SUPERVISION.md +73 -0
- package/package.json +59 -0
package/PURPOSE.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Amalgm Apps
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Amalgm Apps lets a user turn any runnable project into a locally owned,
|
|
6
|
+
versioned application that Amalgm can build, keep alive, and route. It serves
|
|
7
|
+
users who want deployment operations without surrendering their source,
|
|
8
|
+
runtime, or data to a remote hosting platform. When the system is healthy, an
|
|
9
|
+
app keeps one stable identity while every deployment names an immutable
|
|
10
|
+
release, failed deployments leave the last working release recoverable, and
|
|
11
|
+
rollback means activating known bytes rather than rebuilding history.
|
|
12
|
+
|
|
13
|
+
Amalgm Engine is the composition root for the complete Amalgm runtime. This
|
|
14
|
+
repository owns the Apps product and its supervisor. Engine may run that
|
|
15
|
+
product beside independently supervised Events, Realtime, and other products;
|
|
16
|
+
it supplies identity, transport, and UI composition but does not absorb their
|
|
17
|
+
domain supervisors or maintain a second app lifecycle implementation.
|
|
18
|
+
|
|
19
|
+
## Primitives
|
|
20
|
+
|
|
21
|
+
- An **app** is a stable local identity with a user-controlled name, route,
|
|
22
|
+
port, and desired running state.
|
|
23
|
+
- A **release** is one immutable, content-addressed package and its completed
|
|
24
|
+
build output.
|
|
25
|
+
- A **deployment** is an immutable record that activates one release for one
|
|
26
|
+
app.
|
|
27
|
+
- A **process generation** is one supervised execution attempt for a
|
|
28
|
+
deployment.
|
|
29
|
+
- The **Apps supervisor** is the sole lifecycle authority for apps in one
|
|
30
|
+
Apps state directory.
|
|
31
|
+
- A **product-service supervisor** is an optional outer Engine concern that
|
|
32
|
+
observes whether the Apps product is available; it never supervises
|
|
33
|
+
individual apps.
|
|
34
|
+
- The **data directory** is stable writable storage for an app across
|
|
35
|
+
deployments; release and deployment files are not persistent data.
|
|
36
|
+
|
|
37
|
+
## Axioms
|
|
38
|
+
|
|
39
|
+
1. App identity, app ref, public URL, and port survive deploys, rollbacks, and
|
|
40
|
+
renames.
|
|
41
|
+
2. A release is identified by its normalized manifest and selected source
|
|
42
|
+
bytes; an existing release is never rebuilt or mutated.
|
|
43
|
+
3. A deployment activates exactly one release, and activation history is
|
|
44
|
+
append-only.
|
|
45
|
+
4. Rollback creates a new deployment of an existing release; it never changes
|
|
46
|
+
or deletes history.
|
|
47
|
+
5. Registration and deploy finish validation and build before stopping the
|
|
48
|
+
active process.
|
|
49
|
+
6. Activation requires the new process to survive its startup grace period;
|
|
50
|
+
failure before that boundary restores the previous runnable deployment
|
|
51
|
+
whenever one exists.
|
|
52
|
+
7. The app name belongs to the stable app. The manifest seeds it during
|
|
53
|
+
registration; only rename changes it afterward.
|
|
54
|
+
8. Process state changes only through the supervisor, and route eligibility
|
|
55
|
+
is derived from desired state, process state, health, and DNS connection.
|
|
56
|
+
9. App code receives a stable data directory explicitly; writes made inside a
|
|
57
|
+
deployment directory never become part of a release or a later deploy.
|
|
58
|
+
10. The SDK owns behavior. CLI, MCP, HTTP, and Engine integrations only adapt
|
|
59
|
+
that public service.
|
|
60
|
+
11. Apps stores tool identifiers as opaque references and never edits Toolbox,
|
|
61
|
+
Agents, or another product. Any workflow spanning products has an explicit
|
|
62
|
+
product owner and never lives in a Core adapter.
|
|
63
|
+
12. The app-side health lease is optional, inert outside Amalgm, and can never
|
|
64
|
+
crash or keep the hosted app alive by itself.
|
|
65
|
+
13. The Apps supervisor belongs to this product in standalone and composed
|
|
66
|
+
deployments; exactly one active Apps supervisor owns a state directory.
|
|
67
|
+
14. Engine composes product supervisors side by side. It may supervise the
|
|
68
|
+
Apps product as one service, but it never reaches through that boundary to
|
|
69
|
+
start, stop, adopt, or restart an individual app process.
|
|
70
|
+
15. Supervisor state is scoped to its fault domain: an app failure changes
|
|
71
|
+
Apps state, an Apps-service failure changes Apps availability, and neither
|
|
72
|
+
is represented as failure of an unrelated product.
|
|
73
|
+
16. Every lifecycle mutation is serialized per app, and one operating-system
|
|
74
|
+
owner guards every writable state directory.
|
|
75
|
+
17. Crash restart budgets are derived from durable process-generation history;
|
|
76
|
+
restarting the Apps service never resets an app's budget.
|
|
77
|
+
18. A crash restart reuses the active deployment directory without copying,
|
|
78
|
+
rebuilding, or mutating it.
|
|
79
|
+
19. Embedder callbacks, child events, and supervision timers are fault
|
|
80
|
+
boundaries: failures are reported, routes fail closed, and no callback can
|
|
81
|
+
escape into the owning daemon.
|
|
82
|
+
20. TypeScript under `src/` is the product source of truth. JavaScript and
|
|
83
|
+
declarations under `dist/` are generated together and are never edited by
|
|
84
|
+
hand or maintained as a parallel contract.
|
|
85
|
+
21. An awaited lifecycle mutation resolves only after its ordered embedder
|
|
86
|
+
change notifications settle; observer failures are reported and contained.
|
|
87
|
+
|
|
88
|
+
## Predictable behavior
|
|
89
|
+
|
|
90
|
+
Equal source and manifest content produces the same release id, even when
|
|
91
|
+
deployed twice. Deploying changed content creates a new release and
|
|
92
|
+
deployment. Rolling back selects an earlier successful release and appends a
|
|
93
|
+
new deployment. Renaming changes only the app record. If validation or build
|
|
94
|
+
fails, the running deployment is untouched. If the new process cannot start,
|
|
95
|
+
the deployment is marked failed and the previous deployment is reactivated.
|
|
96
|
+
When composed into Engine, the same Apps supervisor makes those decisions.
|
|
97
|
+
Engine sees the Apps product as available, degraded, or unavailable and can
|
|
98
|
+
restart that product independently without becoming a second app supervisor.
|
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# @amalgm/apps
|
|
2
|
+
|
|
3
|
+
Register, deploy, roll back, rename, and supervise local-first applications.
|
|
4
|
+
The complete behavioral contract is in [PURPOSE.md](./PURPOSE.md).
|
|
5
|
+
|
|
6
|
+
An app can use any language or framework. Its only integration is a small
|
|
7
|
+
`amalgm.app.json` manifest describing how to build, start, and package it.
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"schemaVersion": 1,
|
|
12
|
+
"name": "Accounts dashboard",
|
|
13
|
+
"buildCommand": "npm ci && npm run build",
|
|
14
|
+
"startCommand": "npm start",
|
|
15
|
+
"package": {
|
|
16
|
+
"include": ["package*.json", "src/**", "public/**"],
|
|
17
|
+
"exclude": ["**/*.test.js"]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
amalgm-apps register ./accounts
|
|
24
|
+
amalgm-apps deploy <app-id>
|
|
25
|
+
amalgm-apps versions <app-id>
|
|
26
|
+
amalgm-apps rollback <app-id>
|
|
27
|
+
amalgm-apps rename <app-id> "Accounts"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The SDK, CLI, and MCP tools call the same `Apps` service. Releases and
|
|
31
|
+
deployment history live under `~/.amalgm/users/<scope>/apps` by default
|
|
32
|
+
(the kernel's scoped layout; `AMALGM_APPS_DIR` and `AMALGM_DIR` still
|
|
33
|
+
override). Hosted apps receive
|
|
34
|
+
`AMALGM_APP_DATA_DIR`, a stable writable directory that survives deployments.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { Apps } from '@amalgm/apps';
|
|
38
|
+
|
|
39
|
+
const apps = new Apps();
|
|
40
|
+
const app = await apps.register({ cwd: './accounts' });
|
|
41
|
+
await apps.deploy(app.id);
|
|
42
|
+
await apps.rollback(app.id);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The SDK, supervisor, CLI, MCP server, lease, and tests are authored in
|
|
46
|
+
TypeScript. `npm run build` emits the CommonJS runtime and declarations into
|
|
47
|
+
`dist/`; generated output is not a second source tree.
|
|
48
|
+
|
|
49
|
+
Engine supplies runtime identity, route publication, and state notifications
|
|
50
|
+
through constructor callbacks; it does not replace product behavior. The
|
|
51
|
+
ownership and generated-source boundary are described in
|
|
52
|
+
[docs/ENGINE_INTEGRATION.md](./docs/ENGINE_INTEGRATION.md). Supervisor
|
|
53
|
+
ownership and the shared composition pattern for Apps, Events, and Realtime
|
|
54
|
+
are defined in [docs/SUPERVISION.md](./docs/SUPERVISION.md).
|
|
55
|
+
|
|
56
|
+
## Verify
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
npm install
|
|
60
|
+
npm run verify
|
|
61
|
+
```
|
package/dist/apps.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Changes } from './changes.js';
|
|
2
|
+
import { defaultStateDir } from './identity.js';
|
|
3
|
+
import type { Faults } from './faults.js';
|
|
4
|
+
import type { Health } from './health.js';
|
|
5
|
+
import type { Operations } from './operations.js';
|
|
6
|
+
import type { Ownership } from './ownership.js';
|
|
7
|
+
import type { Releases } from './releases.js';
|
|
8
|
+
import type { Store } from './store.js';
|
|
9
|
+
import type { Supervisor } from './supervisor.js';
|
|
10
|
+
import type { AppRecord, AppsOptions, AppView, CloseOptions, Deployment, DeployInput, ExistingAppInput, PackageInspection, PackedPackage, ReadyOptions, RegisterInput, Release, RollbackInput } from './types.js';
|
|
11
|
+
declare class Apps {
|
|
12
|
+
readonly options: AppsOptions;
|
|
13
|
+
readonly stateDir: string;
|
|
14
|
+
readonly domain: string;
|
|
15
|
+
readonly portMin: number;
|
|
16
|
+
readonly portMax: number;
|
|
17
|
+
routeQueue: Promise<unknown>;
|
|
18
|
+
readonly changes: Changes;
|
|
19
|
+
readonly faults: Faults;
|
|
20
|
+
readonly health: Health;
|
|
21
|
+
readonly operations: Operations;
|
|
22
|
+
readonly ownership: Ownership;
|
|
23
|
+
readonly releases: Releases;
|
|
24
|
+
readonly store: Store;
|
|
25
|
+
readonly supervisor: Supervisor;
|
|
26
|
+
constructor(options?: AppsOptions);
|
|
27
|
+
environment(app: AppRecord): NodeJS.ProcessEnv;
|
|
28
|
+
changed(app: AppRecord | {
|
|
29
|
+
id: string;
|
|
30
|
+
deleted: true;
|
|
31
|
+
}): void;
|
|
32
|
+
publishRoutes(reason?: string): Promise<unknown>;
|
|
33
|
+
view(app: AppRecord | null): AppView | null;
|
|
34
|
+
get(appId: string): AppView | null;
|
|
35
|
+
list(): AppView[];
|
|
36
|
+
validate(cwd: string): PackageInspection;
|
|
37
|
+
pack(cwd: string): PackedPackage;
|
|
38
|
+
register(input: RegisterInput): Promise<AppView>;
|
|
39
|
+
importExisting(input: ExistingAppInput): Promise<AppView>;
|
|
40
|
+
deploy(appId: string, input?: DeployInput): Promise<AppView>;
|
|
41
|
+
rollback(appId: string, input?: RollbackInput): Promise<AppView>;
|
|
42
|
+
activate(app: AppRecord, release: Release, reason: string): Promise<AppRecord>;
|
|
43
|
+
rename(appId: string, name: string): Promise<AppView>;
|
|
44
|
+
versions(appId: string): Release[];
|
|
45
|
+
deployments(appId: string): Deployment[];
|
|
46
|
+
start(appId: string): Promise<AppView>;
|
|
47
|
+
stop(appId: string): Promise<AppView>;
|
|
48
|
+
connectDns(appId: string): Promise<AppView>;
|
|
49
|
+
disconnectDns(appId: string): Promise<AppView>;
|
|
50
|
+
ready(appId: string, options?: ReadyOptions): unknown;
|
|
51
|
+
heartbeat(appId: string): unknown;
|
|
52
|
+
routes(): import('./types.js').AppRoute[];
|
|
53
|
+
delete(appId: string): Promise<AppView>;
|
|
54
|
+
removeAppFiles(appId: string): void;
|
|
55
|
+
boot(): Promise<PromiseSettledResult<AppView | null>[]>;
|
|
56
|
+
close(options?: CloseOptions): Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
export { Apps, defaultStateDir };
|
package/dist/apps.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { errorMessage, invoke } from './boundaries.js';
|
|
5
|
+
import { Changes } from './changes.js';
|
|
6
|
+
import { allocatePort, allocateRef, assertAppRef, defaultStateDir } from './identity.js';
|
|
7
|
+
import { importExisting } from './source-import.js';
|
|
8
|
+
import { inspectPackage, packPackage } from './package.js';
|
|
9
|
+
import { appEnvironment, appView, eligibleRoutes, queueRoutes, } from './presentation.js';
|
|
10
|
+
import { createRuntime } from './runtime.js';
|
|
11
|
+
class Apps {
|
|
12
|
+
options;
|
|
13
|
+
stateDir;
|
|
14
|
+
domain;
|
|
15
|
+
portMin;
|
|
16
|
+
portMax;
|
|
17
|
+
routeQueue;
|
|
18
|
+
changes;
|
|
19
|
+
faults;
|
|
20
|
+
health;
|
|
21
|
+
operations;
|
|
22
|
+
ownership;
|
|
23
|
+
releases;
|
|
24
|
+
store;
|
|
25
|
+
supervisor;
|
|
26
|
+
constructor(options = {}) {
|
|
27
|
+
this.options = options;
|
|
28
|
+
this.stateDir = path.resolve(options.stateDir || defaultStateDir(options.env));
|
|
29
|
+
this.domain = options.domain || 'apps.amalgm.ai';
|
|
30
|
+
this.portMin = options.portMin || 9100;
|
|
31
|
+
this.portMax = options.portMax || 9199;
|
|
32
|
+
this.routeQueue = Promise.resolve();
|
|
33
|
+
this.changes = new Changes(options, () => this.publishRoutes('state-change'));
|
|
34
|
+
const runtime = createRuntime(this, options);
|
|
35
|
+
this.faults = runtime.faults;
|
|
36
|
+
this.health = runtime.health;
|
|
37
|
+
this.operations = runtime.operations;
|
|
38
|
+
this.ownership = runtime.ownership;
|
|
39
|
+
this.releases = runtime.releases;
|
|
40
|
+
this.store = runtime.store;
|
|
41
|
+
this.supervisor = runtime.supervisor;
|
|
42
|
+
}
|
|
43
|
+
environment(app) {
|
|
44
|
+
return invoke(() => appEnvironment(this.options, app), [], this.options.onError, `Environment callback failed for ${app.id}`);
|
|
45
|
+
}
|
|
46
|
+
changed(app) { this.changes.publish(app); }
|
|
47
|
+
publishRoutes(reason = 'manual') {
|
|
48
|
+
return queueRoutes(this, reason);
|
|
49
|
+
}
|
|
50
|
+
view(app) {
|
|
51
|
+
return appView(this, app);
|
|
52
|
+
}
|
|
53
|
+
get(appId) {
|
|
54
|
+
return this.view(this.store.getApp(appId));
|
|
55
|
+
}
|
|
56
|
+
list() {
|
|
57
|
+
return this.store.listApps().map((app) => this.view(app));
|
|
58
|
+
}
|
|
59
|
+
validate(cwd) {
|
|
60
|
+
return inspectPackage(cwd);
|
|
61
|
+
}
|
|
62
|
+
pack(cwd) {
|
|
63
|
+
return packPackage(cwd);
|
|
64
|
+
}
|
|
65
|
+
async register(input) {
|
|
66
|
+
if (typeof input.cwd !== 'string' || !input.cwd.trim())
|
|
67
|
+
throw new Error('cwd is required');
|
|
68
|
+
const cwd = path.resolve(input.cwd);
|
|
69
|
+
const inspected = inspectPackage(cwd);
|
|
70
|
+
const id = input.id || `app-${crypto.randomUUID()}`;
|
|
71
|
+
return this.operations.run(id, 'register', async () => {
|
|
72
|
+
const appRef = assertAppRef(allocateRef(this.store));
|
|
73
|
+
const now = new Date().toISOString();
|
|
74
|
+
let app = this.store.createApp({
|
|
75
|
+
id,
|
|
76
|
+
name: inspected.manifest.name,
|
|
77
|
+
description: inspected.manifest.description,
|
|
78
|
+
appRef,
|
|
79
|
+
publicUrl: `https://${appRef}.${this.domain}/`,
|
|
80
|
+
port: allocatePort(this.store, input.port, this.portMin, this.portMax),
|
|
81
|
+
sourceDir: cwd,
|
|
82
|
+
dataDir: path.join(this.stateDir, 'data', id),
|
|
83
|
+
desiredState: 'running',
|
|
84
|
+
status: 'registered',
|
|
85
|
+
dnsConnected: input.connectDns !== false && input.connect_dns !== false,
|
|
86
|
+
autostart: input.autostart !== false,
|
|
87
|
+
keepAlive: input.keepAlive !== false && input.keep_alive !== false,
|
|
88
|
+
createdAt: now,
|
|
89
|
+
updatedAt: now,
|
|
90
|
+
});
|
|
91
|
+
try {
|
|
92
|
+
const release = await this.releases.prepare(app, cwd);
|
|
93
|
+
app = await this.activate(app, release, 'register');
|
|
94
|
+
return this.view(app);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
this.store.deleteApp(id);
|
|
98
|
+
this.removeAppFiles(id);
|
|
99
|
+
throw new Error(`App registration failed: ${errorMessage(error)}`);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async importExisting(input) {
|
|
104
|
+
return this.operations.run(input?.id || 'source-import', 'import', () => importExisting(this, input));
|
|
105
|
+
}
|
|
106
|
+
async deploy(appId, input = {}) {
|
|
107
|
+
return this.operations.run(appId, 'deploy', async () => {
|
|
108
|
+
const app = this.store.getApp(appId);
|
|
109
|
+
if (!app)
|
|
110
|
+
throw new Error(`App not found: ${appId}`);
|
|
111
|
+
const cwd = path.resolve(input.cwd || app.sourceDir);
|
|
112
|
+
const release = await this.releases.prepare(app, cwd);
|
|
113
|
+
const deployed = await this.activate(app, release, 'deploy');
|
|
114
|
+
this.store.updateApp(appId, { sourceDir: cwd });
|
|
115
|
+
return this.get(deployed.id);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async rollback(appId, input = {}) {
|
|
119
|
+
return this.operations.run(appId, 'rollback', async () => {
|
|
120
|
+
const app = this.store.getApp(appId);
|
|
121
|
+
if (!app)
|
|
122
|
+
throw new Error(`App not found: ${appId}`);
|
|
123
|
+
let release;
|
|
124
|
+
if (input.releaseId || input.versionId) {
|
|
125
|
+
release = this.store.getRelease((input.releaseId || input.versionId));
|
|
126
|
+
if (!release || release.appId !== appId)
|
|
127
|
+
throw new Error('Release does not belong to this app');
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const previous = this.store.previousDeployment(appId, app.activeReleaseId);
|
|
131
|
+
release = previous ? this.store.getRelease(previous.releaseId) : null;
|
|
132
|
+
}
|
|
133
|
+
if (!release)
|
|
134
|
+
throw new Error('No earlier release is available');
|
|
135
|
+
if (release.id === app.activeReleaseId)
|
|
136
|
+
throw new Error('Release is already active');
|
|
137
|
+
return this.view(await this.activate(app, release, 'rollback'));
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
async activate(app, release, reason) {
|
|
141
|
+
const previous = app.activeDeploymentId
|
|
142
|
+
? this.store.getDeployment(app.activeDeploymentId)
|
|
143
|
+
: null;
|
|
144
|
+
const deployment = await this.releases.createDeployment(app, release, reason);
|
|
145
|
+
if (previous)
|
|
146
|
+
await this.supervisor.stop(app.id, { preserveDesiredState: true });
|
|
147
|
+
this.health.forget(app.id);
|
|
148
|
+
this.store.activate(app.id, deployment.id);
|
|
149
|
+
try {
|
|
150
|
+
const activated = await this.supervisor.start(app.id);
|
|
151
|
+
if (previous)
|
|
152
|
+
this.releases.removeDeployment(previous);
|
|
153
|
+
return activated;
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
this.store.failDeployment(deployment.id, errorMessage(error));
|
|
157
|
+
this.releases.removeDeployment(deployment);
|
|
158
|
+
if (previous) {
|
|
159
|
+
this.store.activate(app.id, previous.id);
|
|
160
|
+
try {
|
|
161
|
+
await this.supervisor.start(app.id);
|
|
162
|
+
}
|
|
163
|
+
catch (restoreError) {
|
|
164
|
+
this.store.updateApp(app.id, {
|
|
165
|
+
status: 'error',
|
|
166
|
+
error: `Activation failed: ${errorMessage(error)}; restore failed: ${errorMessage(restoreError)}`,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
throw new Error(`Activation failed: ${errorMessage(error)}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async rename(appId, name) {
|
|
174
|
+
return this.operations.run(appId, 'rename', async () => {
|
|
175
|
+
const value = typeof name === 'string' ? name.trim() : '';
|
|
176
|
+
if (!value)
|
|
177
|
+
throw new Error('name must be a non-empty string');
|
|
178
|
+
if (!this.store.getApp(appId))
|
|
179
|
+
throw new Error(`App not found: ${appId}`);
|
|
180
|
+
const app = this.store.updateApp(appId, { name: value });
|
|
181
|
+
this.changed(app);
|
|
182
|
+
return this.view(app);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
versions(appId) {
|
|
186
|
+
if (!this.store.getApp(appId))
|
|
187
|
+
throw new Error(`App not found: ${appId}`);
|
|
188
|
+
return this.store.listReleases(appId);
|
|
189
|
+
}
|
|
190
|
+
deployments(appId) {
|
|
191
|
+
if (!this.store.getApp(appId))
|
|
192
|
+
throw new Error(`App not found: ${appId}`);
|
|
193
|
+
return this.store.listDeployments(appId);
|
|
194
|
+
}
|
|
195
|
+
async start(appId) {
|
|
196
|
+
return this.operations.run(appId, 'start', async () => this.view(await this.supervisor.start(appId)));
|
|
197
|
+
}
|
|
198
|
+
async stop(appId) {
|
|
199
|
+
return this.operations.run(appId, 'stop', async () => {
|
|
200
|
+
this.health.forget(appId);
|
|
201
|
+
return this.view(await this.supervisor.stop(appId));
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
async connectDns(appId) {
|
|
205
|
+
return this.operations.run(appId, 'connect-dns', async () => {
|
|
206
|
+
if (!this.store.getApp(appId))
|
|
207
|
+
throw new Error(`App not found: ${appId}`);
|
|
208
|
+
const app = this.store.updateApp(appId, { dnsConnected: true });
|
|
209
|
+
this.changed(app);
|
|
210
|
+
return this.view(app);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
async disconnectDns(appId) {
|
|
214
|
+
return this.operations.run(appId, 'disconnect-dns', async () => {
|
|
215
|
+
if (!this.store.getApp(appId))
|
|
216
|
+
throw new Error(`App not found: ${appId}`);
|
|
217
|
+
const app = this.store.updateApp(appId, { dnsConnected: false });
|
|
218
|
+
this.changed(app);
|
|
219
|
+
return this.view(app);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
ready(appId, options) {
|
|
223
|
+
return this.health.ready(appId, options);
|
|
224
|
+
}
|
|
225
|
+
heartbeat(appId) {
|
|
226
|
+
return this.health.heartbeat(appId);
|
|
227
|
+
}
|
|
228
|
+
routes() {
|
|
229
|
+
return eligibleRoutes(this);
|
|
230
|
+
}
|
|
231
|
+
async delete(appId) {
|
|
232
|
+
return this.operations.run(appId, 'delete', async () => {
|
|
233
|
+
const app = this.store.getApp(appId);
|
|
234
|
+
if (!app)
|
|
235
|
+
throw new Error(`App not found: ${appId}`);
|
|
236
|
+
await this.supervisor.stop(appId);
|
|
237
|
+
this.health.forget(appId);
|
|
238
|
+
this.store.deleteApp(appId);
|
|
239
|
+
this.removeAppFiles(appId);
|
|
240
|
+
this.changed({ id: appId, deleted: true });
|
|
241
|
+
return this.view(app);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
removeAppFiles(appId) {
|
|
245
|
+
for (const directory of ['data', 'deployments', 'releases']) {
|
|
246
|
+
fs.rmSync(path.join(this.stateDir, directory, appId), { recursive: true, force: true });
|
|
247
|
+
}
|
|
248
|
+
const log = this.supervisor.logPath(appId);
|
|
249
|
+
fs.rmSync(log, { force: true });
|
|
250
|
+
fs.rmSync(`${log}.1`, { force: true });
|
|
251
|
+
}
|
|
252
|
+
async boot() {
|
|
253
|
+
await this.ownership.acquire();
|
|
254
|
+
this.health.start();
|
|
255
|
+
const results = await this.supervisor.boot();
|
|
256
|
+
await this.changes.settle();
|
|
257
|
+
await this.publishRoutes('boot');
|
|
258
|
+
return results.map((result) => (result.status === 'fulfilled'
|
|
259
|
+
? { ...result, value: this.view(result.value) }
|
|
260
|
+
: result));
|
|
261
|
+
}
|
|
262
|
+
async close(options = {}) {
|
|
263
|
+
this.health.close();
|
|
264
|
+
if (options.stopProcesses)
|
|
265
|
+
await this.supervisor.close();
|
|
266
|
+
else
|
|
267
|
+
this.supervisor.detach();
|
|
268
|
+
await this.changes.settle();
|
|
269
|
+
this.store.close();
|
|
270
|
+
await this.ownership.release();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
export { Apps, defaultStateDir };
|
|
274
|
+
//# sourceMappingURL=apps.js.map
|
package/dist/apps.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apps.js","sourceRoot":"","sources":["../src/apps.ts"],"names":[],"mappings":"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"}
|
package/dist/bin/apps.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apps.js","sourceRoot":"","sources":["../../src/bin/apps.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;IAC1C,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC1B,CAAC,CAAC,CAAC"}
|
package/dist/bin/mcp.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { errorMessage } from '../boundaries.js';
|
|
3
|
+
import { createMcpServer } from '../mcp-server.js';
|
|
4
|
+
const server = createMcpServer();
|
|
5
|
+
server.start().catch((error) => {
|
|
6
|
+
console.error(errorMessage(error));
|
|
7
|
+
process.exitCode = 1;
|
|
8
|
+
});
|
|
9
|
+
async function shutdown() {
|
|
10
|
+
await server.apps.close();
|
|
11
|
+
process.exit();
|
|
12
|
+
}
|
|
13
|
+
process.once('SIGINT', shutdown);
|
|
14
|
+
process.once('SIGTERM', shutdown);
|
|
15
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/bin/mcp.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;AACjC,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC7B,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IACnC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC;AAEH,KAAK,UAAU,QAAQ;IACrB,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1B,OAAO,CAAC,IAAI,EAAE,CAAC;AACjB,CAAC;AAED,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACjC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type ErrorObserver = ((error: Error) => unknown) | undefined | null;
|
|
2
|
+
declare function errorMessage(error: unknown): string;
|
|
3
|
+
declare function errorCode(error: unknown): unknown;
|
|
4
|
+
declare function contextual(error: unknown, context: string): Error & {
|
|
5
|
+
code?: unknown;
|
|
6
|
+
};
|
|
7
|
+
declare function report(onError: ErrorObserver, error: unknown, context: string): void;
|
|
8
|
+
declare function observe<TArgs extends unknown[], TResult>(callback: ((...args: TArgs) => TResult) | undefined, args: TArgs, onError: ErrorObserver, context: string): Promise<TResult | undefined>;
|
|
9
|
+
declare function invoke<TArgs extends unknown[], TResult>(callback: (...args: TArgs) => TResult, args: TArgs, onError: ErrorObserver, context: string): TResult;
|
|
10
|
+
declare function invokeAsync<TArgs extends unknown[], TResult>(callback: (...args: TArgs) => TResult | Promise<TResult>, args: TArgs, onError: ErrorObserver, context: string): Promise<TResult>;
|
|
11
|
+
export { contextual, errorCode, errorMessage, invoke, invokeAsync, observe, report };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
function errorMessage(error) {
|
|
3
|
+
return error instanceof Error ? error.message : String(error);
|
|
4
|
+
}
|
|
5
|
+
function errorCode(error) {
|
|
6
|
+
return error && typeof error === 'object' && 'code' in error ? error.code : undefined;
|
|
7
|
+
}
|
|
8
|
+
function contextual(error, context) {
|
|
9
|
+
const cause = error instanceof Error ? error : new Error(String(error));
|
|
10
|
+
const wrapped = new Error(`${context}: ${cause.message}`, { cause });
|
|
11
|
+
wrapped.code = cause.code;
|
|
12
|
+
return wrapped;
|
|
13
|
+
}
|
|
14
|
+
function report(onError, error, context) {
|
|
15
|
+
if (typeof onError !== 'function')
|
|
16
|
+
return;
|
|
17
|
+
const failure = contextual(error, context);
|
|
18
|
+
try {
|
|
19
|
+
Promise.resolve(onError(failure)).catch(() => undefined);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Error reporting is a terminal boundary and must never recurse.
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function observe(callback, args, onError, context) {
|
|
26
|
+
if (typeof callback !== 'function')
|
|
27
|
+
return undefined;
|
|
28
|
+
try {
|
|
29
|
+
return await callback(...args);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
report(onError, error, context);
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function invoke(callback, args, onError, context) {
|
|
37
|
+
try {
|
|
38
|
+
return callback(...args);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
report(onError, error, context);
|
|
42
|
+
throw contextual(error, context);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function invokeAsync(callback, args, onError, context) {
|
|
46
|
+
try {
|
|
47
|
+
return await callback(...args);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
report(onError, error, context);
|
|
51
|
+
throw contextual(error, context);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export { contextual, errorCode, errorMessage, invoke, invokeAsync, observe, report };
|
|
55
|
+
//# sourceMappingURL=boundaries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundaries.js","sourceRoot":"","sources":["../src/boundaries.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAIb,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACxF,CAAC;AAED,SAAS,UAAU,CAAC,KAAc,EAAE,OAAe;IACjD,MAAM,KAAK,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACxE,MAAM,OAAO,GAA+B,IAAI,KAAK,CAAC,GAAG,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACjG,OAAO,CAAC,IAAI,GAAI,KAAoC,CAAC,IAAI,CAAC;IAC1D,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,MAAM,CAAC,OAAsB,EAAE,KAAc,EAAE,OAAe;IACrE,IAAI,OAAO,OAAO,KAAK,UAAU;QAAE,OAAO;IAC1C,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;IACnE,CAAC;AACH,CAAC;AAED,KAAK,UAAU,OAAO,CACpB,QAAmD,EACnD,IAAW,EACX,OAAsB,EACtB,OAAe;IAEf,IAAI,OAAO,QAAQ,KAAK,UAAU;QAAE,OAAO,SAAS,CAAC;IACrD,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAChC,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CACb,QAAqC,EACrC,IAAW,EACX,OAAsB,EACtB,OAAe;IAEf,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAChC,MAAM,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,QAAwD,EACxD,IAAW,EACX,OAAsB,EACtB,OAAe;IAEf,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAChC,MAAM,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;AACH,CAAC;AAED,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AppRecord, AppsOptions } from './types.js';
|
|
2
|
+
type AppChange = AppRecord | {
|
|
3
|
+
id: string;
|
|
4
|
+
deleted: true;
|
|
5
|
+
};
|
|
6
|
+
declare class Changes {
|
|
7
|
+
private readonly options;
|
|
8
|
+
private readonly publishRoutes;
|
|
9
|
+
private queue;
|
|
10
|
+
constructor(options: AppsOptions, publishRoutes: () => Promise<unknown>);
|
|
11
|
+
publish(change: AppChange): void;
|
|
12
|
+
settle(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export { Changes };
|