@netnodeag/kraftwerk 0.76.0 → 0.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -27
- package/dist/cli/cloud.d.ts +2 -0
- package/dist/cli/cloud.js +262 -0
- package/dist/cli/daemon.js +9 -0
- package/dist/cli/doctor.js +16 -8
- package/dist/cli/init.js +2 -2
- package/dist/cli/kraftwerk.js +4 -0
- package/dist/client/routes.d.ts +4 -0
- package/dist/client/routes.js +4 -0
- package/dist/config.d.ts +15 -28
- package/dist/config.js +5 -19
- package/dist/core/cloud.d.ts +115 -0
- package/dist/core/cloud.js +94 -0
- package/dist/server/api/cloud.d.ts +72 -0
- package/dist/server/api/cloud.js +38 -0
- package/dist/server/api/devices.d.ts +8 -8
- package/dist/server/api/index.d.ts +88 -10
- package/dist/server/api/index.js +2 -0
- package/dist/server/api/workspace.d.ts +16 -1
- package/dist/server/api/workspace.js +2 -1
- package/dist/server/cloud.d.ts +65 -33
- package/dist/server/cloud.js +207 -188
- package/dist/server/hub-context.d.ts +1 -1
- package/dist/server/hub-context.js +3 -3
- package/dist/server/relay.d.ts +13 -0
- package/dist/server/relay.js +29 -1
- package/dist/server/server.d.ts +3 -2
- package/dist/server/server.js +6 -6
- package/package.json +1 -1
- package/schema/kraftwerk.schema.json +4 -4
- package/web/dist/assets/{dist-T1sNLC62.js → dist-BGHweZKi.js} +1 -1
- package/web/dist/assets/{dist-DFXmaDc5.js → dist-BVPxOqcx.js} +1 -1
- package/web/dist/assets/{dist-BYkcY-Vl.js → dist-CCNyRSAA.js} +1 -1
- package/web/dist/assets/{dist-flnLXEzU.js → dist-CXoAMU1b.js} +1 -1
- package/web/dist/assets/{dist-l7foWlFx.js → dist-DCFREMXk.js} +1 -1
- package/web/dist/assets/{dist-BQpWYkxm.js → dist-DT2Tjvwx.js} +1 -1
- package/web/dist/assets/{dist-BwIca_Uj.js → dist-DdA5PoVJ.js} +1 -1
- package/web/dist/assets/{dist-fgB7OEJy.js → dist-DoD3qX1P.js} +1 -1
- package/web/dist/assets/{dist-vuciRCSz.js → dist-FFA4-S6d.js} +1 -1
- package/web/dist/assets/{dist-BTVP-6On.js → dist-yGx0qYbw.js} +1 -1
- package/web/dist/assets/dist-zjUUP5a9.js +1 -0
- package/web/dist/assets/{editor-C6Ok8NPo.js → editor-CyWapLQr.js} +3 -3
- package/web/dist/assets/{index-z4tpCCzk.js → index-CNXcNoKJ.js} +4 -4
- package/web/dist/index.html +1 -1
- package/web/dist/assets/dist-BURf1l-A.js +0 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kraftwerk cloud, machine side: the settings and the wire contract the
|
|
3
|
+
* daemon's machine client (server/cloud.ts) and the CLI (`kraftwerk cloud`,
|
|
4
|
+
* `login`, `logout`) share.
|
|
5
|
+
*
|
|
6
|
+
* The daemon registers this MACHINE once; the workspaces it serves ride
|
|
7
|
+
* along as children of that record. The machine's id is its relay id (the
|
|
8
|
+
* hash of the X25519 key in ~/.kraftwerk/relay.json) and the proof is the
|
|
9
|
+
* relay secret — the key cannot sign. Nothing here opens the relay link.
|
|
10
|
+
*
|
|
11
|
+
* ~/.kraftwerk/cloud.json — the machine's switch and the cloud's origin:
|
|
12
|
+
*
|
|
13
|
+
* { "enabled": false, "url": "https://cloud.example.com" }
|
|
14
|
+
*
|
|
15
|
+
* `enabled` absent = on. The origin: KRAFTWERK_CLOUD_URL (env) wins, then
|
|
16
|
+
* cloud.json `url`, then a kraftwerk.yml `cloud.url` of an open workspace
|
|
17
|
+
* (deprecated, one release), then the default. KRAFTWERK_CLOUD_URL=off
|
|
18
|
+
* turns the cloud off for the process (what tests and CI set). kraftwerk.yml
|
|
19
|
+
* `cloud.enabled: false` is a per-workspace veto: that workspace is left out
|
|
20
|
+
* of the machine's reports.
|
|
21
|
+
*
|
|
22
|
+
* The contract (all POST, JSON):
|
|
23
|
+
*
|
|
24
|
+
* /api/machines/register {id, key, secret, name, handle, hostname?, platform?, version, interval?, workspaces}
|
|
25
|
+
* → {ok, interval, claimCode|null, account|null} (403: wrong secret)
|
|
26
|
+
* /api/machines/heartbeat {id, secret, version?, workspaces?} → {ok, interval, account, claimCode}
|
|
27
|
+
* /api/machines/goodbye {id, secret}
|
|
28
|
+
* /api/machines/unlink {id, secret} → {ok, claimCode}
|
|
29
|
+
*
|
|
30
|
+
* workspaces: [{id?: "ws_…", name, slug, root?}] — `root` only once the
|
|
31
|
+
* machine is claimed (account set): an unclaimed machine tells the cloud no
|
|
32
|
+
* paths.
|
|
33
|
+
*/
|
|
34
|
+
export interface CloudFile {
|
|
35
|
+
enabled?: boolean;
|
|
36
|
+
url?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Where the effective origin came from. */
|
|
39
|
+
export type CloudUrlSource = "env" | "cloud.json" | "kraftwerk.yml" | "default";
|
|
40
|
+
export interface MachineCloud {
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
url: string;
|
|
43
|
+
source: CloudUrlSource;
|
|
44
|
+
/** Why it is off, when it is. */
|
|
45
|
+
reason?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface MachineWorkspace {
|
|
48
|
+
id?: string;
|
|
49
|
+
name: string;
|
|
50
|
+
slug: string;
|
|
51
|
+
root?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface Credentials {
|
|
54
|
+
id: string;
|
|
55
|
+
key: string;
|
|
56
|
+
secret: string;
|
|
57
|
+
}
|
|
58
|
+
export interface RegisterResponse {
|
|
59
|
+
ok: boolean;
|
|
60
|
+
interval: number;
|
|
61
|
+
claimCode: string | null;
|
|
62
|
+
account: string | null;
|
|
63
|
+
}
|
|
64
|
+
export interface HeartbeatResponse {
|
|
65
|
+
ok: boolean;
|
|
66
|
+
interval: number;
|
|
67
|
+
account: string | null;
|
|
68
|
+
claimCode: string | null;
|
|
69
|
+
}
|
|
70
|
+
export interface UnlinkResponse {
|
|
71
|
+
ok: boolean;
|
|
72
|
+
claimCode: string | null;
|
|
73
|
+
}
|
|
74
|
+
export declare const cloudFilePath: () => string;
|
|
75
|
+
/** The retired per-workspace identities (before machines): deleted at the daemon's start. */
|
|
76
|
+
export declare const retiredCloudDir: () => string;
|
|
77
|
+
export declare function readCloudFile(): Promise<CloudFile>;
|
|
78
|
+
/** Merge a change into cloud.json (a `url: undefined` leaves the URL as it is). */
|
|
79
|
+
export declare function writeCloudFile(change: CloudFile): Promise<CloudFile>;
|
|
80
|
+
/** Whether the environment turned the cloud off for this process. */
|
|
81
|
+
export declare const envCloudOff: () => boolean;
|
|
82
|
+
/**
|
|
83
|
+
* The machine's effective cloud. `ymlUrls`: `cloud.url` of open workspaces
|
|
84
|
+
* (deprecated) — used only when neither the environment nor cloud.json names
|
|
85
|
+
* an origin.
|
|
86
|
+
*/
|
|
87
|
+
export declare function machineCloud(ymlUrls?: string[]): Promise<MachineCloud>;
|
|
88
|
+
export declare const claimUrlFor: (url: string, code: string | null | undefined) => string | null;
|
|
89
|
+
export declare const GOODBYE_TIMEOUT_MS = 800;
|
|
90
|
+
/** A refused or failed call; `status` is the HTTP status (0: no answer). */
|
|
91
|
+
export declare class CloudError extends Error {
|
|
92
|
+
readonly status: number;
|
|
93
|
+
constructor(message: string, status: number);
|
|
94
|
+
}
|
|
95
|
+
/** The cloud no longer knows this machine (its data was reset): registering again fixes it. */
|
|
96
|
+
export declare const unknownMachine: (err: unknown) => boolean;
|
|
97
|
+
export declare function cloudPost<T>(base: string, route: string, body: unknown, opts?: {
|
|
98
|
+
version?: string;
|
|
99
|
+
timeout?: number;
|
|
100
|
+
}): Promise<T>;
|
|
101
|
+
/** What register says about the machine besides its credentials. */
|
|
102
|
+
export interface MachineHello {
|
|
103
|
+
name: string;
|
|
104
|
+
handle: string;
|
|
105
|
+
hostname: string;
|
|
106
|
+
platform: string;
|
|
107
|
+
version: string;
|
|
108
|
+
}
|
|
109
|
+
export declare const machineRegister: (base: string, creds: Credentials, hello: MachineHello, workspaces: MachineWorkspace[]) => Promise<RegisterResponse>;
|
|
110
|
+
export declare const machineHeartbeat: (base: string, creds: Credentials, extra: {
|
|
111
|
+
version?: string;
|
|
112
|
+
workspaces?: MachineWorkspace[];
|
|
113
|
+
}) => Promise<HeartbeatResponse>;
|
|
114
|
+
export declare const machineGoodbye: (base: string, creds: Credentials, version?: string) => Promise<unknown>;
|
|
115
|
+
export declare const machineUnlink: (base: string, creds: Credentials, version?: string) => Promise<UnlinkResponse>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { promises as fs } from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { CLOUD_DEFAULT_URL } from "../config.js";
|
|
6
|
+
// Resolved on every use, not at import: a test swaps HOME after some module already imported this one.
|
|
7
|
+
const kwHome = () => path.join(os.homedir(), ".kraftwerk");
|
|
8
|
+
export const cloudFilePath = () => path.join(kwHome(), "cloud.json");
|
|
9
|
+
/** The retired per-workspace identities (before machines): deleted at the daemon's start. */
|
|
10
|
+
export const retiredCloudDir = () => path.join(kwHome(), "cloud");
|
|
11
|
+
export async function readCloudFile() {
|
|
12
|
+
try {
|
|
13
|
+
const raw = JSON.parse(await fs.readFile(cloudFilePath(), "utf8"));
|
|
14
|
+
return {
|
|
15
|
+
...(typeof raw.enabled === "boolean" ? { enabled: raw.enabled } : {}),
|
|
16
|
+
...(typeof raw.url === "string" && raw.url ? { url: raw.url.replace(/\/+$/, "") } : {}),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** Merge a change into cloud.json (a `url: undefined` leaves the URL as it is). */
|
|
24
|
+
export async function writeCloudFile(change) {
|
|
25
|
+
const cur = await readCloudFile();
|
|
26
|
+
const next = { ...cur, ...(change.enabled !== undefined ? { enabled: change.enabled } : {}), ...(change.url ? { url: change.url.replace(/\/+$/, "") } : {}) };
|
|
27
|
+
const file = cloudFilePath();
|
|
28
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
29
|
+
const tmp = `${file}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
|
|
30
|
+
await fs.writeFile(tmp, JSON.stringify(next, null, 2) + "\n");
|
|
31
|
+
await fs.rename(tmp, file);
|
|
32
|
+
return next;
|
|
33
|
+
}
|
|
34
|
+
/** Whether the environment turned the cloud off for this process. */
|
|
35
|
+
export const envCloudOff = () => process.env.KRAFTWERK_CLOUD_URL?.trim().toLowerCase() === "off";
|
|
36
|
+
/**
|
|
37
|
+
* The machine's effective cloud. `ymlUrls`: `cloud.url` of open workspaces
|
|
38
|
+
* (deprecated) — used only when neither the environment nor cloud.json names
|
|
39
|
+
* an origin.
|
|
40
|
+
*/
|
|
41
|
+
export async function machineCloud(ymlUrls = []) {
|
|
42
|
+
const file = await readCloudFile();
|
|
43
|
+
const env = process.env.KRAFTWERK_CLOUD_URL?.trim();
|
|
44
|
+
const [url, source] = env && !envCloudOff() ? [env, "env"] : file.url ? [file.url, "cloud.json"] : ymlUrls[0] ? [ymlUrls[0], "kraftwerk.yml"] : [CLOUD_DEFAULT_URL, "default"];
|
|
45
|
+
const base = { url: url.replace(/\/+$/, ""), source };
|
|
46
|
+
if (envCloudOff())
|
|
47
|
+
return { ...base, enabled: false, reason: "KRAFTWERK_CLOUD_URL=off" };
|
|
48
|
+
if (file.enabled === false)
|
|
49
|
+
return { ...base, enabled: false, reason: "turned off for this machine (`kraftwerk cloud on` turns it on)" };
|
|
50
|
+
return { ...base, enabled: true };
|
|
51
|
+
}
|
|
52
|
+
export const claimUrlFor = (url, code) => (code ? `${url}/claim/${encodeURIComponent(code)}` : null);
|
|
53
|
+
const REQUEST_TIMEOUT_MS = 8_000;
|
|
54
|
+
export const GOODBYE_TIMEOUT_MS = 800;
|
|
55
|
+
/** A refused or failed call; `status` is the HTTP status (0: no answer). */
|
|
56
|
+
export class CloudError extends Error {
|
|
57
|
+
status;
|
|
58
|
+
constructor(message, status) {
|
|
59
|
+
super(message);
|
|
60
|
+
this.status = status;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** The cloud no longer knows this machine (its data was reset): registering again fixes it. */
|
|
64
|
+
export const unknownMachine = (err) => err instanceof CloudError && (err.status === 404 || /unknown machine|not registered/i.test(err.message));
|
|
65
|
+
export async function cloudPost(base, route, body, opts = {}) {
|
|
66
|
+
const url = `${base}${route}`;
|
|
67
|
+
let r;
|
|
68
|
+
try {
|
|
69
|
+
r = await fetch(url, {
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: { "content-type": "application/json", "user-agent": `kraftwerk/${opts.version ?? "dev"}` },
|
|
72
|
+
body: JSON.stringify(body),
|
|
73
|
+
signal: AbortSignal.timeout(opts.timeout ?? REQUEST_TIMEOUT_MS),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
throw new CloudError(err.message, 0);
|
|
78
|
+
}
|
|
79
|
+
const text = await r.text();
|
|
80
|
+
let data;
|
|
81
|
+
try {
|
|
82
|
+
data = text ? JSON.parse(text) : {};
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
throw new CloudError(`${r.status} from ${url}: not JSON`, r.status);
|
|
86
|
+
}
|
|
87
|
+
if (!r.ok)
|
|
88
|
+
throw new CloudError(data.error ?? `${r.status} from ${url}`, r.status);
|
|
89
|
+
return data;
|
|
90
|
+
}
|
|
91
|
+
export const machineRegister = (base, creds, hello, workspaces) => cloudPost(base, "/api/machines/register", { ...creds, ...hello, workspaces }, { version: hello.version });
|
|
92
|
+
export const machineHeartbeat = (base, creds, extra) => cloudPost(base, "/api/machines/heartbeat", { id: creds.id, secret: creds.secret, ...extra }, { version: extra.version });
|
|
93
|
+
export const machineGoodbye = (base, creds, version) => cloudPost(base, "/api/machines/goodbye", { id: creds.id, secret: creds.secret }, { version, timeout: GOODBYE_TIMEOUT_MS });
|
|
94
|
+
export const machineUnlink = (base, creds, version) => cloudPost(base, "/api/machines/unlink", { id: creds.id, secret: creds.secret }, { version });
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* The machine in the kraftwerk cloud (server/cloud.ts): its record, turning
|
|
4
|
+
* it on or off, a round now, releasing the claim. What `kraftwerk cloud`,
|
|
5
|
+
* `login` and `logout` ask the running daemon; a standalone server answers
|
|
6
|
+
* "off" (only the daemon registers). This machine only: the claim code
|
|
7
|
+
* claims the machine.
|
|
8
|
+
*/
|
|
9
|
+
export declare const cloudRoutes: (import("./router.js").Route<"cloud.set", {
|
|
10
|
+
daemon: boolean;
|
|
11
|
+
url: string;
|
|
12
|
+
state: import("../cloud.js").CloudState;
|
|
13
|
+
reason?: string;
|
|
14
|
+
source?: import("../../core/cloud.js").CloudUrlSource;
|
|
15
|
+
error?: string;
|
|
16
|
+
id?: string;
|
|
17
|
+
machine?: string;
|
|
18
|
+
account?: string | null;
|
|
19
|
+
interval?: number;
|
|
20
|
+
lastSeen?: string;
|
|
21
|
+
claimCode?: string | null;
|
|
22
|
+
claimUrl?: string | null;
|
|
23
|
+
workspaces?: number;
|
|
24
|
+
}, "/api/cloud", z.ZodObject<{
|
|
25
|
+
enabled: z.ZodBoolean;
|
|
26
|
+
url: z.ZodOptional<z.ZodString>;
|
|
27
|
+
}, z.core.$strip>> | import("./router.js").Route<"cloud.status", {
|
|
28
|
+
daemon: boolean;
|
|
29
|
+
url: string;
|
|
30
|
+
state: import("../cloud.js").CloudState;
|
|
31
|
+
reason?: string;
|
|
32
|
+
source?: import("../../core/cloud.js").CloudUrlSource;
|
|
33
|
+
error?: string;
|
|
34
|
+
id?: string;
|
|
35
|
+
machine?: string;
|
|
36
|
+
account?: string | null;
|
|
37
|
+
interval?: number;
|
|
38
|
+
lastSeen?: string;
|
|
39
|
+
claimCode?: string | null;
|
|
40
|
+
claimUrl?: string | null;
|
|
41
|
+
workspaces?: number;
|
|
42
|
+
}, "/api/cloud", undefined> | import("./router.js").Route<"cloud.sync", {
|
|
43
|
+
daemon: boolean;
|
|
44
|
+
url: string;
|
|
45
|
+
state: import("../cloud.js").CloudState;
|
|
46
|
+
reason?: string;
|
|
47
|
+
source?: import("../../core/cloud.js").CloudUrlSource;
|
|
48
|
+
error?: string;
|
|
49
|
+
id?: string;
|
|
50
|
+
machine?: string;
|
|
51
|
+
account?: string | null;
|
|
52
|
+
interval?: number;
|
|
53
|
+
lastSeen?: string;
|
|
54
|
+
claimCode?: string | null;
|
|
55
|
+
claimUrl?: string | null;
|
|
56
|
+
workspaces?: number;
|
|
57
|
+
}, "/api/cloud/sync", undefined> | import("./router.js").Route<"cloud.unlink", {
|
|
58
|
+
daemon: boolean;
|
|
59
|
+
url: string;
|
|
60
|
+
state: import("../cloud.js").CloudState;
|
|
61
|
+
reason?: string;
|
|
62
|
+
source?: import("../../core/cloud.js").CloudUrlSource;
|
|
63
|
+
error?: string;
|
|
64
|
+
id?: string;
|
|
65
|
+
machine?: string;
|
|
66
|
+
account?: string | null;
|
|
67
|
+
interval?: number;
|
|
68
|
+
lastSeen?: string;
|
|
69
|
+
claimCode?: string | null;
|
|
70
|
+
claimUrl?: string | null;
|
|
71
|
+
workspaces?: number;
|
|
72
|
+
}, "/api/cloud/unlink", undefined>)[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { writeCloudFile } from "../../core/cloud.js";
|
|
3
|
+
import { applyMachineCloud, cloudStatus, syncMachineCloud, unlinkMachineCloud } from "../cloud.js";
|
|
4
|
+
import { currentHub } from "../hub-context.js";
|
|
5
|
+
import { route } from "./router.js";
|
|
6
|
+
/**
|
|
7
|
+
* The machine in the kraftwerk cloud (server/cloud.ts): its record, turning
|
|
8
|
+
* it on or off, a round now, releasing the claim. What `kraftwerk cloud`,
|
|
9
|
+
* `login` and `logout` ask the running daemon; a standalone server answers
|
|
10
|
+
* "off" (only the daemon registers). This machine only: the claim code
|
|
11
|
+
* claims the machine.
|
|
12
|
+
*/
|
|
13
|
+
export const cloudRoutes = [
|
|
14
|
+
route({ name: "cloud.status", method: "GET", path: "/api/cloud", summary: "the machine's cloud record: state, claim code, account, last heartbeat", access: "local" }, async () => ({
|
|
15
|
+
daemon: currentHub().daemon === true,
|
|
16
|
+
...cloudStatus(),
|
|
17
|
+
})),
|
|
18
|
+
route({
|
|
19
|
+
name: "cloud.set",
|
|
20
|
+
method: "POST",
|
|
21
|
+
path: "/api/cloud",
|
|
22
|
+
summary: "turn the machine's cloud on or off {enabled, url?} (~/.kraftwerk/cloud.json); off says goodbye",
|
|
23
|
+
access: "local",
|
|
24
|
+
body: z.object({ enabled: z.boolean(), url: z.string().url().optional() }),
|
|
25
|
+
}, async (c) => {
|
|
26
|
+
const { enabled, url } = await c.body();
|
|
27
|
+
await writeCloudFile({ enabled, url });
|
|
28
|
+
return { daemon: currentHub().daemon === true, ...(await applyMachineCloud()) };
|
|
29
|
+
}),
|
|
30
|
+
route({ name: "cloud.sync", method: "POST", path: "/api/cloud/sync", summary: "register or heartbeat now; answers the record (a claim made in the cloud shows here)", access: "local" }, async () => ({
|
|
31
|
+
daemon: currentHub().daemon === true,
|
|
32
|
+
...(await syncMachineCloud()),
|
|
33
|
+
})),
|
|
34
|
+
route({ name: "cloud.unlink", method: "POST", path: "/api/cloud/unlink", summary: "release the machine from its account; the cloud hands out a fresh claim code", access: "local", errors: 400 }, async () => ({
|
|
35
|
+
daemon: currentHub().daemon === true,
|
|
36
|
+
...(await unlinkMachineCloud()),
|
|
37
|
+
})),
|
|
38
|
+
];
|
|
@@ -16,16 +16,16 @@ export declare const deviceRoutes: (import("./router.js").Route<"devices.code",
|
|
|
16
16
|
code: z.ZodString;
|
|
17
17
|
name: z.ZodDefault<z.ZodString>;
|
|
18
18
|
}, z.core.$strip>> | import("./router.js").Route<"devices.relay", {
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
url: string | null;
|
|
21
|
+
fingerprint: string | null;
|
|
22
|
+
daemon: boolean;
|
|
19
23
|
state: import("../relay.js").RelayState;
|
|
20
24
|
id?: string;
|
|
21
25
|
key?: string;
|
|
22
26
|
error?: string;
|
|
23
27
|
clients: number;
|
|
24
28
|
since?: string;
|
|
25
|
-
enabled: boolean;
|
|
26
|
-
url: string | null;
|
|
27
|
-
fingerprint: string | null;
|
|
28
|
-
daemon: boolean;
|
|
29
29
|
}, "/api/devices/relay", undefined> | import("./router.js").Route<"devices.revoke", {
|
|
30
30
|
ok: boolean;
|
|
31
31
|
}, "/api/devices/:id", undefined> | import("./router.js").Route<"devices.self", {
|
|
@@ -41,16 +41,16 @@ export declare const deviceRoutes: (import("./router.js").Route<"devices.code",
|
|
|
41
41
|
}>;
|
|
42
42
|
key: z.ZodString;
|
|
43
43
|
}, z.core.$strip>> | import("./router.js").Route<"devices.setRelay", {
|
|
44
|
+
enabled: boolean;
|
|
45
|
+
url: string;
|
|
46
|
+
fingerprint: string;
|
|
47
|
+
daemon: boolean;
|
|
44
48
|
state: import("../relay.js").RelayState;
|
|
45
49
|
id?: string;
|
|
46
50
|
key?: string;
|
|
47
51
|
error?: string;
|
|
48
52
|
clients: number;
|
|
49
53
|
since?: string;
|
|
50
|
-
enabled: boolean;
|
|
51
|
-
url: string;
|
|
52
|
-
fingerprint: string;
|
|
53
|
-
daemon: boolean;
|
|
54
54
|
}, "/api/devices/relay", z.ZodObject<{
|
|
55
55
|
enabled: z.ZodBoolean;
|
|
56
56
|
url: z.ZodOptional<z.ZodString>;
|
|
@@ -291,7 +291,70 @@ export declare const routes: (Route<"agents.addJournal", {
|
|
|
291
291
|
ok: true;
|
|
292
292
|
}, "/api/chats/:id/task-stop", z.ZodObject<{
|
|
293
293
|
taskId: z.ZodDefault<z.ZodString>;
|
|
294
|
-
}, z.core.$strip>> | Route<"
|
|
294
|
+
}, z.core.$strip>> | Route<"cloud.set", {
|
|
295
|
+
daemon: boolean;
|
|
296
|
+
url: string;
|
|
297
|
+
state: import("../cloud.js").CloudState;
|
|
298
|
+
reason?: string;
|
|
299
|
+
source?: import("../../core/cloud.js").CloudUrlSource;
|
|
300
|
+
error?: string;
|
|
301
|
+
id?: string;
|
|
302
|
+
machine?: string;
|
|
303
|
+
account?: string | null;
|
|
304
|
+
interval?: number;
|
|
305
|
+
lastSeen?: string;
|
|
306
|
+
claimCode?: string | null;
|
|
307
|
+
claimUrl?: string | null;
|
|
308
|
+
workspaces?: number;
|
|
309
|
+
}, "/api/cloud", z.ZodObject<{
|
|
310
|
+
enabled: z.ZodBoolean;
|
|
311
|
+
url: z.ZodOptional<z.ZodString>;
|
|
312
|
+
}, z.core.$strip>> | Route<"cloud.status", {
|
|
313
|
+
daemon: boolean;
|
|
314
|
+
url: string;
|
|
315
|
+
state: import("../cloud.js").CloudState;
|
|
316
|
+
reason?: string;
|
|
317
|
+
source?: import("../../core/cloud.js").CloudUrlSource;
|
|
318
|
+
error?: string;
|
|
319
|
+
id?: string;
|
|
320
|
+
machine?: string;
|
|
321
|
+
account?: string | null;
|
|
322
|
+
interval?: number;
|
|
323
|
+
lastSeen?: string;
|
|
324
|
+
claimCode?: string | null;
|
|
325
|
+
claimUrl?: string | null;
|
|
326
|
+
workspaces?: number;
|
|
327
|
+
}, "/api/cloud", undefined> | Route<"cloud.sync", {
|
|
328
|
+
daemon: boolean;
|
|
329
|
+
url: string;
|
|
330
|
+
state: import("../cloud.js").CloudState;
|
|
331
|
+
reason?: string;
|
|
332
|
+
source?: import("../../core/cloud.js").CloudUrlSource;
|
|
333
|
+
error?: string;
|
|
334
|
+
id?: string;
|
|
335
|
+
machine?: string;
|
|
336
|
+
account?: string | null;
|
|
337
|
+
interval?: number;
|
|
338
|
+
lastSeen?: string;
|
|
339
|
+
claimCode?: string | null;
|
|
340
|
+
claimUrl?: string | null;
|
|
341
|
+
workspaces?: number;
|
|
342
|
+
}, "/api/cloud/sync", undefined> | Route<"cloud.unlink", {
|
|
343
|
+
daemon: boolean;
|
|
344
|
+
url: string;
|
|
345
|
+
state: import("../cloud.js").CloudState;
|
|
346
|
+
reason?: string;
|
|
347
|
+
source?: import("../../core/cloud.js").CloudUrlSource;
|
|
348
|
+
error?: string;
|
|
349
|
+
id?: string;
|
|
350
|
+
machine?: string;
|
|
351
|
+
account?: string | null;
|
|
352
|
+
interval?: number;
|
|
353
|
+
lastSeen?: string;
|
|
354
|
+
claimCode?: string | null;
|
|
355
|
+
claimUrl?: string | null;
|
|
356
|
+
workspaces?: number;
|
|
357
|
+
}, "/api/cloud/unlink", undefined> | Route<"devices.code", {
|
|
295
358
|
code: string;
|
|
296
359
|
expiresAt: string;
|
|
297
360
|
urls: string[];
|
|
@@ -307,16 +370,16 @@ export declare const routes: (Route<"agents.addJournal", {
|
|
|
307
370
|
code: z.ZodString;
|
|
308
371
|
name: z.ZodDefault<z.ZodString>;
|
|
309
372
|
}, z.core.$strip>> | Route<"devices.relay", {
|
|
373
|
+
enabled: boolean;
|
|
374
|
+
url: string | null;
|
|
375
|
+
fingerprint: string | null;
|
|
376
|
+
daemon: boolean;
|
|
310
377
|
state: import("../relay.js").RelayState;
|
|
311
378
|
id?: string;
|
|
312
379
|
key?: string;
|
|
313
380
|
error?: string;
|
|
314
381
|
clients: number;
|
|
315
382
|
since?: string;
|
|
316
|
-
enabled: boolean;
|
|
317
|
-
url: string | null;
|
|
318
|
-
fingerprint: string | null;
|
|
319
|
-
daemon: boolean;
|
|
320
383
|
}, "/api/devices/relay", undefined> | Route<"devices.revoke", {
|
|
321
384
|
ok: boolean;
|
|
322
385
|
}, "/api/devices/:id", undefined> | Route<"devices.self", {
|
|
@@ -332,16 +395,16 @@ export declare const routes: (Route<"agents.addJournal", {
|
|
|
332
395
|
}>;
|
|
333
396
|
key: z.ZodString;
|
|
334
397
|
}, z.core.$strip>> | Route<"devices.setRelay", {
|
|
398
|
+
enabled: boolean;
|
|
399
|
+
url: string;
|
|
400
|
+
fingerprint: string;
|
|
401
|
+
daemon: boolean;
|
|
335
402
|
state: import("../relay.js").RelayState;
|
|
336
403
|
id?: string;
|
|
337
404
|
key?: string;
|
|
338
405
|
error?: string;
|
|
339
406
|
clients: number;
|
|
340
407
|
since?: string;
|
|
341
|
-
enabled: boolean;
|
|
342
|
-
url: string;
|
|
343
|
-
fingerprint: string;
|
|
344
|
-
daemon: boolean;
|
|
345
408
|
}, "/api/devices/relay", z.ZodObject<{
|
|
346
409
|
enabled: z.ZodBoolean;
|
|
347
410
|
url: z.ZodOptional<z.ZodString>;
|
|
@@ -439,7 +502,22 @@ export declare const routes: (Route<"agents.addJournal", {
|
|
|
439
502
|
vibeables: boolean;
|
|
440
503
|
projects: boolean;
|
|
441
504
|
publicUrl: string;
|
|
442
|
-
cloud:
|
|
505
|
+
cloud: {
|
|
506
|
+
included: boolean;
|
|
507
|
+
url: string;
|
|
508
|
+
state: import("../cloud.js").CloudState;
|
|
509
|
+
reason?: string;
|
|
510
|
+
source?: import("../../core/cloud.js").CloudUrlSource;
|
|
511
|
+
error?: string;
|
|
512
|
+
id?: string;
|
|
513
|
+
machine?: string;
|
|
514
|
+
account?: string | null;
|
|
515
|
+
interval?: number;
|
|
516
|
+
lastSeen?: string;
|
|
517
|
+
claimCode?: string | null;
|
|
518
|
+
claimUrl?: string | null;
|
|
519
|
+
workspaces?: number;
|
|
520
|
+
};
|
|
443
521
|
switcher: import("../../config.js").SwitcherEntry[];
|
|
444
522
|
}, "/api/meta", undefined> | Route<"notifications.clear", {
|
|
445
523
|
ok: boolean;
|
package/dist/server/api/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { agentRoutes } from "./agents.js";
|
|
|
3
3
|
import { attentionRoutes } from "./attention.js";
|
|
4
4
|
import { channelRoutes } from "./channels.js";
|
|
5
5
|
import { chatRoutes } from "./chats.js";
|
|
6
|
+
import { cloudRoutes } from "./cloud.js";
|
|
6
7
|
import { deviceRoutes } from "./devices.js";
|
|
7
8
|
import { hubRoutes } from "./hub.js";
|
|
8
9
|
import { fileRoutes } from "./files.js";
|
|
@@ -35,6 +36,7 @@ const domainRoutes = [
|
|
|
35
36
|
...gitRoutes,
|
|
36
37
|
...vibeableRoutes,
|
|
37
38
|
...deviceRoutes,
|
|
39
|
+
...cloudRoutes,
|
|
38
40
|
...hubRoutes,
|
|
39
41
|
];
|
|
40
42
|
const protocolRoute = route({ name: "protocol.get", method: "GET", path: "/api/protocol", summary: "the protocol version and every route", access: "public" }, async () => ({
|
|
@@ -35,7 +35,22 @@ export declare const workspaceRoutes: (import("./router.js").Route<"identity.get
|
|
|
35
35
|
projects: boolean;
|
|
36
36
|
/** @deprecated Always "": the Cloudflare Tunnel that set it was removed in 0.65. Removed with protocol 2. */
|
|
37
37
|
publicUrl: string;
|
|
38
|
-
cloud:
|
|
38
|
+
cloud: {
|
|
39
|
+
included: boolean;
|
|
40
|
+
url: string;
|
|
41
|
+
state: import("../cloud.js").CloudState;
|
|
42
|
+
reason?: string;
|
|
43
|
+
source?: import("../../core/cloud.js").CloudUrlSource;
|
|
44
|
+
error?: string;
|
|
45
|
+
id?: string;
|
|
46
|
+
machine?: string;
|
|
47
|
+
account?: string | null;
|
|
48
|
+
interval?: number;
|
|
49
|
+
lastSeen?: string;
|
|
50
|
+
claimCode?: string | null;
|
|
51
|
+
claimUrl?: string | null;
|
|
52
|
+
workspaces?: number;
|
|
53
|
+
};
|
|
39
54
|
switcher: import("../../config.js").SwitcherEntry[];
|
|
40
55
|
}, "/api/meta", undefined> | import("./router.js").Route<"search.agents", {
|
|
41
56
|
workspaces: (import("../../core/search.js").WorkspaceAgents & {
|
|
@@ -105,7 +105,8 @@ export const workspaceRoutes = [
|
|
|
105
105
|
projects: (ws?.config.projects && ws.config.projects.enabled !== false) === true,
|
|
106
106
|
/** @deprecated Always "": the Cloudflare Tunnel that set it was removed in 0.65. Removed with protocol 2. */
|
|
107
107
|
publicUrl: "",
|
|
108
|
-
cloud
|
|
108
|
+
// The machine's cloud record (only the daemon registers one); `included`: this workspace rides along (no cloud.enabled: false veto).
|
|
109
|
+
cloud: { ...cloudStatus(), included: ws?.config.cloud?.enabled !== false },
|
|
109
110
|
switcher,
|
|
110
111
|
};
|
|
111
112
|
}),
|