@octonodes/cli 0.2.8 → 0.2.10

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 (69) hide show
  1. package/README.md +41 -0
  2. package/dist/apps/build.d.ts +42 -0
  3. package/dist/apps/build.d.ts.map +1 -0
  4. package/dist/apps/build.js +198 -0
  5. package/dist/apps/build.js.map +1 -0
  6. package/dist/apps/cloudflared.d.ts +2 -0
  7. package/dist/apps/cloudflared.d.ts.map +1 -0
  8. package/dist/apps/cloudflared.js +64 -0
  9. package/dist/apps/cloudflared.js.map +1 -0
  10. package/dist/apps/constants.d.ts +5 -0
  11. package/dist/apps/constants.d.ts.map +1 -0
  12. package/dist/apps/constants.js +46 -0
  13. package/dist/apps/constants.js.map +1 -0
  14. package/dist/apps/create.d.ts +7 -0
  15. package/dist/apps/create.d.ts.map +1 -0
  16. package/dist/apps/create.js +225 -0
  17. package/dist/apps/create.js.map +1 -0
  18. package/dist/apps/dev.d.ts +26 -0
  19. package/dist/apps/dev.d.ts.map +1 -0
  20. package/dist/apps/dev.js +213 -0
  21. package/dist/apps/dev.js.map +1 -0
  22. package/dist/apps/development.d.ts +8 -0
  23. package/dist/apps/development.d.ts.map +1 -0
  24. package/dist/apps/development.js +80 -0
  25. package/dist/apps/development.js.map +1 -0
  26. package/dist/apps/index.d.ts +2 -0
  27. package/dist/apps/index.d.ts.map +1 -0
  28. package/dist/apps/index.js +84 -0
  29. package/dist/apps/index.js.map +1 -0
  30. package/dist/apps/preview.d.mts +2 -0
  31. package/dist/apps/preview.d.mts.map +1 -0
  32. package/dist/apps/preview.mjs +92 -0
  33. package/dist/apps/preview.mjs.map +1 -0
  34. package/dist/apps/publish.d.ts +8 -0
  35. package/dist/apps/publish.d.ts.map +1 -0
  36. package/dist/apps/publish.js +59 -0
  37. package/dist/apps/publish.js.map +1 -0
  38. package/dist/apps/server.d.ts +19 -0
  39. package/dist/apps/server.d.ts.map +1 -0
  40. package/dist/apps/server.js +191 -0
  41. package/dist/apps/server.js.map +1 -0
  42. package/dist/apps/source.d.ts +136 -0
  43. package/dist/apps/source.d.ts.map +1 -0
  44. package/dist/apps/source.js +88 -0
  45. package/dist/apps/source.js.map +1 -0
  46. package/dist/apps/tunnel.d.ts +7 -0
  47. package/dist/apps/tunnel.d.ts.map +1 -0
  48. package/dist/apps/tunnel.js +62 -0
  49. package/dist/apps/tunnel.js.map +1 -0
  50. package/dist/apps/types.d.ts +34 -0
  51. package/dist/apps/types.d.ts.map +1 -0
  52. package/dist/apps/types.js +3 -0
  53. package/dist/apps/types.js.map +1 -0
  54. package/dist/index.js +10 -1
  55. package/dist/index.js.map +1 -1
  56. package/dist/plugins/app.d.ts +5 -0
  57. package/dist/plugins/app.d.ts.map +1 -0
  58. package/dist/plugins/app.js +59 -0
  59. package/dist/plugins/app.js.map +1 -0
  60. package/dist/plugins/artifact.d.ts.map +1 -1
  61. package/dist/plugins/artifact.js +14 -0
  62. package/dist/plugins/artifact.js.map +1 -1
  63. package/dist/plugins/build.d.ts.map +1 -1
  64. package/dist/plugins/build.js +6 -0
  65. package/dist/plugins/build.js.map +1 -1
  66. package/dist/plugins/publish.d.ts +35 -0
  67. package/dist/plugins/publish.d.ts.map +1 -1
  68. package/package.json +3 -2
  69. package/runtime/plugin-lifecycle.cjs +298 -57
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createApp = createApp;
4
+ exports.addAppExtension = addAppExtension;
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ const constants_1 = require("./constants");
8
+ const source_1 = require("./source");
9
+ const json = (value) => JSON.stringify(value, null, 2) + "\n";
10
+ function extensionCode(target) {
11
+ return `import { defineExtension, Section } from "@octonodes/ui-extensions/react";
12
+ import { getAppSession } from "@octonodes/ui-extensions";
13
+ export default defineExtension(${JSON.stringify(target)}, function Notice() {
14
+ return <Section title="Workspace notice">{getAppSession().configuration.message || "Welcome to the workspace"}</Section>;
15
+ });
16
+ `;
17
+ }
18
+ function createApp(name, version, template = "extension") {
19
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(name))
20
+ throw new Error("App name must be lowercase alphanumeric/dash");
21
+ if (!["extension", "full"].includes(template))
22
+ throw new Error("Choose --template extension or full");
23
+ const root = (0, node_path_1.resolve)(name);
24
+ (0, node_fs_1.mkdirSync)(root);
25
+ try {
26
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, "src/extensions"), { recursive: true });
27
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, "tests"));
28
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, constants_1.APP_SOURCE), json({
29
+ apiVersion: "octonode.app/v1",
30
+ id: name,
31
+ name,
32
+ version: "0.1.0",
33
+ ...(template === "full" ? { web: { entry: "src/server.ts" } } : {}),
34
+ ...(template === "extension"
35
+ ? { settings: [{ id: "message", label: "Message", defaultValue: "Welcome to the workspace" }] }
36
+ : {}),
37
+ extensions: [{ id: "notice", target: "workspace.block", entry: "src/extensions/notice.tsx" }],
38
+ }));
39
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, "src/extensions/notice.tsx"), extensionCode("workspace.block"));
40
+ if (template === "full")
41
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, "src/server.ts"), `// Export a Fetch API handler. app dev and app serve adapt it to Node HTTP.
42
+ import { connectAppServer } from "@octonodes/ui-extensions/app/server";
43
+ export default async function handle(request: Request): Promise<Response> {
44
+ const path = new URL(request.url).pathname;
45
+ if (path === "/api/context") {
46
+ const appId = process.env.OCTONODE_APP_ID;
47
+ const baseUrl = process.env.OCTONODE_API_URL;
48
+ if (!appId || !baseUrl) return new Response("App identity is not configured", { status: 503 });
49
+ try {
50
+ const token = request.headers.get("authorization")?.replace(/^Bearer /, "") ?? "";
51
+ const app = await connectAppServer(token, { appId, baseUrl });
52
+ return Response.json({ workspace: app.workspace });
53
+ } catch { return new Response("App session required", { status: 401 }); }
54
+ }
55
+ if (path === "/api/hello") return Response.json({ message: "Hello from your app backend" });
56
+ if (path !== "/") return new Response("Not found", { status: 404 });
57
+ return new Response(\`<!doctype html><html><head><meta charset="utf-8"><title>My Octonode app</title></head>
58
+ <body><h1>My Octonode app</h1><p id="message" role="status">Loading…</p>
59
+ <script>const bearer = new URLSearchParams(location.hash.slice(1)).get('octonode_session');
60
+ history.replaceState(null, '', location.pathname + location.search);
61
+ const output = document.getElementById('message');
62
+ if (!bearer) output.textContent = 'Open this app from Octonode Apps to connect your workspace.';
63
+ else fetch('/api/context', {headers:{authorization:'Bearer '+bearer}}).then(async response=>{
64
+ if(!response.ok) throw Error('Your session expired or access was revoked. Reopen this app from Octonode Apps.');
65
+ const data=await response.json(); output.textContent='Connected to '+data.workspace.kind+':'+data.workspace.id;
66
+ }).catch(error=>output.textContent=error.message);</script></body></html>\`, { headers: { "content-type": "text/html; charset=utf-8" } });
67
+ }
68
+ `);
69
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, "package.json"), json({
70
+ name,
71
+ private: true,
72
+ type: "module",
73
+ engines: { node: ">=24" },
74
+ scripts: {
75
+ dev: "octonodes app dev",
76
+ ...(template === "full" ? { start: "octonodes app serve" } : {}),
77
+ build: "tsc --noEmit && octonodes app build",
78
+ test: "npm run build && node --test tests/*.test.cjs",
79
+ },
80
+ dependencies: { "@octonodes/ui-extensions": version, react: "^19.0.0", "react-dom": "^19.0.0" },
81
+ devDependencies: {
82
+ "@octonodes/cli": version,
83
+ typescript: "5.9.3",
84
+ "@types/react": "^19.0.0",
85
+ "@types/node": "^24.0.0",
86
+ },
87
+ }));
88
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, "tsconfig.json"), json({
89
+ compilerOptions: {
90
+ target: "ES2021",
91
+ module: "ESNext",
92
+ moduleResolution: "Bundler",
93
+ jsx: "react-jsx",
94
+ strict: true,
95
+ skipLibCheck: true,
96
+ noEmit: true,
97
+ },
98
+ include: ["src/**/*.ts", "src/**/*.tsx"],
99
+ }));
100
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, ".gitignore"), "node_modules/\ndist/\n.env\n.env.*\n");
101
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, "tests/app.test.cjs"), `const { test } = require("node:test");
102
+ const assert = require("node:assert/strict");
103
+ const { readFileSync } = require("node:fs");
104
+ const { createHash } = require("node:crypto");
105
+ test("release bundles match the manifest", () => {
106
+ const root = ${JSON.stringify(`dist/apps/${name}`)};
107
+ const { plugin } = JSON.parse(readFileSync(root + "/octonode.json", "utf8"));
108
+ assert.equal(plugin.app.hosting, ${JSON.stringify(template === "full" ? "self-hosted" : "extension-only")});
109
+ assert.ok(plugin.app.extensions.length);
110
+ for (const extension of plugin.app.extensions) {
111
+ const bytes = readFileSync(${JSON.stringify(template === "full" ? `dist/web/${name}/extensions/` : `dist/apps/${name}/extensions/`)} + extension.id + ".js");
112
+ assert.equal(extension.sha256, "sha256:" + createHash("sha256").update(bytes).digest("hex"));
113
+ }
114
+ });
115
+ `);
116
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, "README.md"), `# ${name}
117
+
118
+ An Octonode app created by \`octonodes app create\`. The default contribution is a
119
+ \`workspace.block\` on workspace home. Add a page only if the app needs one.
120
+
121
+ ## Work locally
122
+
123
+ \`\`\`sh
124
+ npm install
125
+ npm test
126
+ npm run dev
127
+ \`\`\`
128
+
129
+ The CLI opens a live HTTPS preview and downloads a verified tunnel helper on first
130
+ use. No Cloudflare account or separate installation is needed. Use
131
+ \`octonodes app dev --use-localhost\` for offline UI work.
132
+ Edit \`octonode.app.json\` and \`src/extensions/notice.tsx\`. The descriptor owns
133
+ app identity, version, extension targets and entry files. Do not edit \`dist/\`.
134
+ Add a page with \`octonodes app extension add overview --target app.page\`.
135
+
136
+ ## Preview and publish in Octonode
137
+
138
+ \`\`\`sh
139
+ octonodes login
140
+ octonodes app dev --workspace user:<your-user-id>
141
+ npm test
142
+ octonodes app validate dist/apps/${name}
143
+ octonodes app publish --workspace user:<your-user-id>
144
+ \`\`\`
145
+
146
+ Use \`team:<id>\` or \`org:<id>\` if that is the publisher workspace. Studio
147
+ preview is private and expiring, with no project grants. The first publication
148
+ returns the registered app ID and revision. Install through **Studio → Apps**;
149
+ a block appears on workspace home. An administrator can change shared settings
150
+ or disable an extension-only installation. Shared settings are not secrets.
151
+
152
+ For updates, change the source version, run \`npm test\`, then publish with
153
+ \`--app-id <registered-app-id> --revision <current-revision>\`. Existing
154
+ installations stay pinned until an administrator approves an update.
155
+
156
+ ${template === "full" ? `## Host the full app
157
+
158
+ Edit \`src/server.ts\`, which default-exports a Fetch API handler. Set
159
+ \`web.applicationUrl\` in \`octonode.app.json\` to a permanent HTTPS origin
160
+ before building and publishing. Add only the \`web.requestedActions\` your
161
+ app needs. The generated \`/api/context\` route verifies an installed app
162
+ bearer through \`@octonodes/ui-extensions/app/server\`.
163
+
164
+ Publishing registers metadata but does not deploy the backend. After the first
165
+ publish returns the app ID, copy the entire \`dist/web/${name}\` directory
166
+ to a Node 24 host. Configure HTTPS, \`PORT\`, \`OCTONODE_APP_ID\` and
167
+ \`OCTONODE_API_URL\`, then run \`node start.cjs\` from that directory.
168
+ Check the public page and every hashed \`/extensions/<hash>.js\` asset
169
+ before inviting installation. Restore the previous web artifact before clean
170
+ CI builds, or retain older hash-named assets at the host for pinned installs.
171
+ The development tunnel URL is temporary and must not be published.
172
+
173
+ ` : ""}## SDK and deployment guides
174
+
175
+ - [App quickstart](https://playbook.octonodes.com/docs/apps-quickstart)
176
+ - [Configuration](https://playbook.octonodes.com/docs/apps-configuration)
177
+ - [App SDKs](https://playbook.octonodes.com/docs/apps-sdk)
178
+ - [Hosting](https://playbook.octonodes.com/docs/apps-hosting)
179
+ - [Publishing and updates](https://playbook.octonodes.com/docs/apps-publishing)
180
+ `);
181
+ return root;
182
+ }
183
+ catch (error) {
184
+ (0, node_fs_1.rmSync)(root, { recursive: true, force: true });
185
+ throw error;
186
+ }
187
+ }
188
+ function addAppExtension(directory, id, target) {
189
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(id))
190
+ throw new Error("Extension ID must be lowercase alphanumeric/dash");
191
+ if (target !== "workspace.block" && target !== "app.page")
192
+ throw new Error("Choose --target workspace.block or app.page");
193
+ const root = (0, node_path_1.resolve)(directory);
194
+ const source = (0, source_1.readAppSource)(root);
195
+ if (source.extensions.some((extension) => extension.id === id))
196
+ throw new Error("Duplicate extension ID");
197
+ const entry = `src/extensions/${id}.tsx`;
198
+ const next = { ...source, extensions: [...source.extensions, { id, target, entry }] };
199
+ (0, source_1.appManifest)(next);
200
+ for (const path of ["src", "src/extensions"]) {
201
+ const directory = (0, node_path_1.join)(root, path);
202
+ if (!(0, node_fs_1.lstatSync)(directory, { throwIfNoEntry: false }))
203
+ (0, node_fs_1.mkdirSync)(directory);
204
+ if (!(0, node_fs_1.lstatSync)(directory).isDirectory() || (0, node_fs_1.lstatSync)(directory).isSymbolicLink())
205
+ throw new Error("Unsafe extension directory");
206
+ }
207
+ const stage = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)(root, ".app-edit-"));
208
+ let created = false;
209
+ try {
210
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(stage, constants_1.APP_SOURCE), json(next));
211
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, entry), extensionCode(target), { flag: "wx" });
212
+ created = true;
213
+ (0, node_fs_1.renameSync)((0, node_path_1.join)(stage, constants_1.APP_SOURCE), (0, node_path_1.join)(root, constants_1.APP_SOURCE));
214
+ }
215
+ catch (error) {
216
+ if (created)
217
+ (0, node_fs_1.rmSync)((0, node_path_1.join)(root, entry));
218
+ throw error;
219
+ }
220
+ finally {
221
+ (0, node_fs_1.rmSync)(stage, { recursive: true, force: true });
222
+ }
223
+ return { id, target, entry };
224
+ }
225
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/apps/create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { DevOptions } from "./types";
2
+ export declare function startAppDev(directory: string, options?: DevOptions): Promise<{
3
+ server: import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>;
4
+ secret: string;
5
+ challenge: string;
6
+ listen(): Promise<number>;
7
+ setOrigin(value: string): void;
8
+ update(source: import("./types").AppSource, directory: string, backend?: (request: Request) => Response | Promise<Response>): void;
9
+ fail(message: string): void;
10
+ close: () => Promise<void>;
11
+ origin: string;
12
+ previewUrl: string;
13
+ rebuild: () => Promise<void>;
14
+ }>;
15
+ export declare function serveApp(directory: string, port: number): Promise<{
16
+ server: import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>;
17
+ secret: string;
18
+ challenge: string;
19
+ listen(): Promise<number>;
20
+ setOrigin(value: string): void;
21
+ update(source: import("./types").AppSource, directory: string, backend?: (request: Request) => Response | Promise<Response>): void;
22
+ fail(message: string): void;
23
+ close: () => Promise<void>;
24
+ port: number;
25
+ }>;
26
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/apps/dev.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe;;;;;;;;;;;;GAyJ5E;AAED,wBAAsB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;;;;;;;;;;GAmC7D"}
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startAppDev = startAppDev;
4
+ exports.serveApp = serveApp;
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ const promises_1 = require("node:timers/promises");
8
+ const node_child_process_1 = require("node:child_process");
9
+ const esbuild_1 = require("esbuild");
10
+ const build_1 = require("./build");
11
+ const source_1 = require("./source");
12
+ const server_1 = require("./server");
13
+ const cloudflared_1 = require("./cloudflared");
14
+ const tunnel_1 = require("./tunnel");
15
+ const development_1 = require("./development");
16
+ async function startAppDev(directory, options = {}) {
17
+ if (options.localhost && options.tunnelUrl)
18
+ throw new Error("Choose --use-localhost or --tunnel-url");
19
+ if (options.workspace && options.localhost)
20
+ throw new Error("Studio preview requires an HTTPS tunnel; omit --use-localhost");
21
+ const development = options.workspace
22
+ ? await (0, development_1.createDevelopmentSession)(options.workspace, options.baseUrl, options.studioUrl)
23
+ : undefined;
24
+ const root = (0, node_path_1.resolve)(directory);
25
+ let source = (0, source_1.readAppSource)(root);
26
+ const preview = await (0, esbuild_1.build)({
27
+ stdin: {
28
+ contents: `import { previewClient } from ${JSON.stringify(require.resolve("./preview.mjs"))}; previewClient();`,
29
+ resolveDir: __dirname,
30
+ },
31
+ bundle: true,
32
+ platform: "browser",
33
+ format: "iife",
34
+ write: false,
35
+ logLevel: "silent",
36
+ });
37
+ const host = (0, server_1.createAppServer)({
38
+ port: options.port ?? 0,
39
+ previewScript: preview.outputFiles[0].text,
40
+ source,
41
+ development: true,
42
+ });
43
+ let tunnel;
44
+ let watcher;
45
+ let timer;
46
+ let heartbeat;
47
+ let closed = false;
48
+ const startup = new AbortController();
49
+ let buildTask = Promise.resolve();
50
+ const close = async () => {
51
+ if (closed)
52
+ return;
53
+ closed = true;
54
+ startup.abort();
55
+ clearTimeout(timer);
56
+ watcher?.close();
57
+ clearInterval(heartbeat);
58
+ tunnel?.stop();
59
+ await host.close();
60
+ await buildTask;
61
+ await development?.close();
62
+ process.off("SIGINT", onSignal);
63
+ process.off("SIGTERM", onSignal);
64
+ };
65
+ const onSignal = () => {
66
+ void close();
67
+ };
68
+ process.once("SIGINT", onSignal);
69
+ process.once("SIGTERM", onSignal);
70
+ try {
71
+ const port = await host.listen();
72
+ const executable = !options.localhost && !options.tunnelUrl ? await (0, cloudflared_1.ensureCloudflared)(startup.signal) : undefined;
73
+ startup.signal.throwIfAborted();
74
+ const origin = options.localhost
75
+ ? `http://127.0.0.1:${port}`
76
+ : options.tunnelUrl
77
+ ? (0, tunnel_1.publicOrigin)(options.tunnelUrl)
78
+ : await (tunnel = (0, tunnel_1.startTunnel)(port, executable)).url;
79
+ host.setOrigin(origin);
80
+ if (!options.localhost) {
81
+ let reachable = false;
82
+ for (let attempt = 0; attempt < 30; attempt++) {
83
+ try {
84
+ const response = await fetch(`${origin}/_octonode/ping`, {
85
+ signal: AbortSignal.timeout(3000),
86
+ redirect: "error",
87
+ });
88
+ if (response.ok && (await response.text()) === host.challenge) {
89
+ reachable = true;
90
+ break;
91
+ }
92
+ }
93
+ catch { }
94
+ await (0, promises_1.setTimeout)(2000);
95
+ }
96
+ if (!reachable)
97
+ throw new Error("Tunnel URL does not reach this app server; check DNS or your custom tunnel's local port");
98
+ }
99
+ const rebuild = () => {
100
+ buildTask = buildTask.then(async () => {
101
+ if (closed)
102
+ return;
103
+ try {
104
+ source = (0, source_1.readAppSource)(root);
105
+ const built = await (0, build_1.buildAppProject)(root, origin.startsWith("https:") ? origin : "https://development.example");
106
+ if (closed)
107
+ return;
108
+ const web = "webDirectory" in built ? built.webDirectory : undefined;
109
+ await development?.sync(source, built, web ?? built.directory);
110
+ let backend;
111
+ if (web) {
112
+ const entry = (0, node_path_1.join)(web, "server.cjs");
113
+ delete require.cache[require.resolve(entry)];
114
+ backend = require(entry).default;
115
+ if (typeof backend !== "function")
116
+ throw new Error("web.entry must default-export a Fetch API handler");
117
+ }
118
+ host.update(source, web ?? built.directory, backend);
119
+ process.stderr.write("App rebuilt\n");
120
+ }
121
+ catch (error) {
122
+ const message = error instanceof Error ? error.message : String(error);
123
+ host.fail(message);
124
+ process.stderr.write(`Build failed: ${message}\n`);
125
+ }
126
+ });
127
+ return buildTask;
128
+ };
129
+ await rebuild();
130
+ if (development && !development.url)
131
+ throw new Error("Workspace preview could not start; see the development error above");
132
+ watcher = (0, node_fs_1.watch)(root, { recursive: true }, (_event, filename) => {
133
+ const file = String(filename ?? "").replaceAll("\\", "/");
134
+ if (file !== "octonode.app.json" && !file.startsWith("src/"))
135
+ return;
136
+ clearTimeout(timer);
137
+ timer = setTimeout(() => void rebuild(), 150);
138
+ });
139
+ tunnel?.process.on("exit", () => {
140
+ if (!closed) {
141
+ process.stderr.write("Tunnel stopped; closing app development session\n");
142
+ process.exitCode = 1;
143
+ void close();
144
+ }
145
+ });
146
+ heartbeat = development
147
+ ? setInterval(() => {
148
+ void development.sync().catch((error) => process.stderr.write(`${error.message}\n`));
149
+ }, 60_000)
150
+ : undefined;
151
+ const previewUrl = `${origin}/_octonode/#preview=${host.secret}`;
152
+ process.stdout.write(JSON.stringify({
153
+ url: origin,
154
+ previewUrl,
155
+ port,
156
+ studioUrl: development?.url,
157
+ mode: options.localhost ? "localhost" : "tunnel",
158
+ }) + "\n");
159
+ if (options.open !== false) {
160
+ const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
161
+ const openUrl = development?.url ?? previewUrl;
162
+ const args = process.platform === "win32" ? ["/c", "start", "", openUrl] : [openUrl];
163
+ const browser = (0, node_child_process_1.spawn)(command, args, { stdio: "ignore" });
164
+ browser.on("error", () => { });
165
+ browser.unref();
166
+ }
167
+ return { ...host, close, origin, previewUrl, rebuild };
168
+ }
169
+ catch (error) {
170
+ await close();
171
+ throw error;
172
+ }
173
+ }
174
+ async function serveApp(directory, port) {
175
+ if (!Number.isInteger(port) || port < 0 || port > 65535)
176
+ throw new Error("Port must be an integer from 0 to 65535");
177
+ const root = (0, node_path_1.resolve)(directory);
178
+ const web = (0, node_fs_1.existsSync)((0, node_path_1.join)(root, "octonode-web.json")) ? root : (0, node_path_1.join)(root, "dist/web", (0, source_1.readAppSource)(root).id);
179
+ const app = (0, build_1.verifyWebBuild)(web);
180
+ if (app.hosting !== "self-hosted")
181
+ throw new Error("Expected a self-hosted web build");
182
+ const backend = require((0, node_path_1.join)(web, "server.cjs")).default;
183
+ if (typeof backend !== "function")
184
+ throw new Error("web.entry must default-export a Fetch API handler");
185
+ const source = {
186
+ apiVersion: "octonode.app/v1",
187
+ id: "web",
188
+ name: "App",
189
+ version: "1.0.0",
190
+ extensions: app.extensions.map((extension) => ({
191
+ id: extension.id,
192
+ target: extension.target,
193
+ entry: `src/${extension.id}.tsx`,
194
+ })),
195
+ };
196
+ const host = (0, server_1.createAppServer)({ port, source, development: false });
197
+ const actualPort = await host.listen();
198
+ host.setOrigin(app.applicationUrl);
199
+ host.update(source, web, backend);
200
+ process.stdout.write(`Serving ${app.applicationUrl} on port ${actualPort}\n`);
201
+ const close = async () => {
202
+ process.off("SIGINT", stop);
203
+ process.off("SIGTERM", stop);
204
+ await host.close();
205
+ };
206
+ const stop = () => {
207
+ void close();
208
+ };
209
+ process.once("SIGINT", stop);
210
+ process.once("SIGTERM", stop);
211
+ return { ...host, close, port: actualPort };
212
+ }
213
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/apps/dev.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { PluginBuild } from "../plugins/types";
2
+ import type { AppSource } from "./types";
3
+ export declare function createDevelopmentSession(workspace: string, baseUrl?: string, studioUrl?: string): Promise<{
4
+ sync: (source?: AppSource, built?: PluginBuild, bundleDirectory?: string) => Promise<void>;
5
+ readonly url: string | undefined;
6
+ close(): Promise<void>;
7
+ }>;
8
+ //# sourceMappingURL=development.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"development.d.ts","sourceRoot":"","sources":["../../src/apps/development.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,MAAM,EACjB,OAAO,SAAmB,EAC1B,SAAS,SAAyB;oBAiCX,SAAS,UAAU,WAAW,oBAAoB,MAAM;;;GAyChF"}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createDevelopmentSession = createDevelopmentSession;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const sdk_1 = require("@octonodes/sdk");
7
+ const auth_1 = require("../auth");
8
+ async function createDevelopmentSession(workspace, baseUrl = sdk_1.OCTONODE_API_URL, studioUrl = "https://octonode.dev") {
9
+ const match = workspace.match(/^(user|team|org):([^:]{1,128})$/);
10
+ if (!match)
11
+ throw new Error("--workspace must be user:<id>, team:<id> or org:<id>");
12
+ const base = new URL(baseUrl);
13
+ if (base.protocol !== "https:" && !(base.protocol === "http:" && ["localhost", "127.0.0.1"].includes(base.hostname)))
14
+ throw new Error("API origin must use HTTPS");
15
+ const studio = new URL(studioUrl);
16
+ if (studio.protocol !== "https:" &&
17
+ !(studio.protocol === "http:" && ["localhost", "127.0.0.1"].includes(studio.hostname)))
18
+ throw new Error("Studio origin must use HTTPS");
19
+ if (!(await (0, auth_1.accessToken)()))
20
+ throw new Error("Run octonodes login before starting a workspace preview");
21
+ let id;
22
+ let revision = 0;
23
+ let body;
24
+ let stopped = false;
25
+ let queue = Promise.resolve();
26
+ async function request(method, payload) {
27
+ const response = await fetch(new URL(`/api/marketplace/publisher/app-development${id ? `/${id}` : ""}`, base), {
28
+ method,
29
+ headers: { authorization: `Bearer ${await (0, auth_1.accessToken)()}`, "content-type": "application/json" },
30
+ ...(payload ? { body: JSON.stringify(payload) } : {}),
31
+ signal: AbortSignal.timeout(15_000),
32
+ redirect: "error",
33
+ });
34
+ if (!response.ok)
35
+ throw new Error(`Development session ${method} failed (${response.status}); check publisher access and server migration 0023`);
36
+ return response.json();
37
+ }
38
+ const sync = (source, built, bundleDirectory) => {
39
+ const operation = queue
40
+ .catch(() => { })
41
+ .then(async () => {
42
+ if (stopped)
43
+ return;
44
+ if (source && built && bundleDirectory)
45
+ body = {
46
+ workspace: { kind: match[1], id: match[2] },
47
+ slug: source.id,
48
+ name: source.name,
49
+ version: source.version,
50
+ app: { ...built.manifest.app, requestedActions: [] },
51
+ bundles: source.extensions.map((extension) => ({
52
+ id: extension.id,
53
+ code: (0, node_fs_1.readFileSync)((0, node_path_1.join)(bundleDirectory, `extensions/${extension.id}.js`), "utf8"),
54
+ })),
55
+ };
56
+ if (!body)
57
+ return;
58
+ const result = await request("POST", { ...body, expectedRevision: revision });
59
+ id = result.id;
60
+ revision = result.revision;
61
+ process.env.OCTONODE_APP_ID = id;
62
+ process.env.OCTONODE_API_URL = base.origin;
63
+ });
64
+ queue = operation;
65
+ return operation;
66
+ };
67
+ return {
68
+ sync,
69
+ get url() {
70
+ return id ? new URL(`/studio/apps/development/${id}`, studio).href : undefined;
71
+ },
72
+ async close() {
73
+ stopped = true;
74
+ await queue.catch(() => { });
75
+ if (id)
76
+ await request("DELETE").catch((error) => process.stderr.write(`Development session cleanup failed; it expires within ten minutes: ${error.message}\n`));
77
+ },
78
+ };
79
+ }
80
+ //# sourceMappingURL=development.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"development.js","sourceRoot":"","sources":["../../src/apps/development.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function appCommand(args: string[], version: string): Promise<void>;
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/apps/index.ts"],"names":[],"mappings":"AAQA,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8E/E"}