@parlor/cli 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +19 -2
- package/dist/agent-host-process.d.ts +22 -0
- package/dist/agent-host-process.d.ts.map +1 -0
- package/dist/agent-host-process.js +35 -0
- package/dist/agent-host-process.js.map +1 -0
- package/dist/chat-warning.d.ts +8 -0
- package/dist/chat-warning.d.ts.map +1 -0
- package/dist/chat-warning.js +13 -0
- package/dist/chat-warning.js.map +1 -0
- package/dist/cloudflare/loader.d.ts +4 -0
- package/dist/cloudflare/loader.d.ts.map +1 -0
- package/dist/cloudflare/loader.js +11 -0
- package/dist/cloudflare/loader.js.map +1 -0
- package/dist/cloudflare/platform.d.ts +16 -0
- package/dist/cloudflare/platform.d.ts.map +1 -0
- package/dist/cloudflare/platform.js +52 -0
- package/dist/cloudflare/platform.js.map +1 -0
- package/dist/cloudflare/prepare.d.ts +9 -0
- package/dist/cloudflare/prepare.d.ts.map +1 -0
- package/dist/cloudflare/prepare.js +29 -0
- package/dist/cloudflare/prepare.js.map +1 -0
- package/dist/cloudflare/workers.d.ts +12 -0
- package/dist/cloudflare/workers.d.ts.map +1 -0
- package/dist/cloudflare/workers.js +18 -0
- package/dist/cloudflare/workers.js.map +1 -0
- package/dist/cloudflare/wrangler.d.ts +4 -0
- package/dist/cloudflare/wrangler.d.ts.map +1 -0
- package/dist/cloudflare/wrangler.js +16 -0
- package/dist/cloudflare/wrangler.js.map +1 -0
- package/dist/commands/add.d.ts +32 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +79 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/build.d.ts +12 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +27 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/db.d.ts +12 -0
- package/dist/commands/db.d.ts.map +1 -0
- package/dist/commands/db.js +131 -0
- package/dist/commands/db.js.map +1 -0
- package/dist/commands/deploy.d.ts +8 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +45 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/dev.d.ts +22 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +85 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/typegen.d.ts +2 -0
- package/dist/commands/typegen.d.ts.map +1 -0
- package/dist/commands/typegen.js +13 -0
- package/dist/commands/typegen.js.map +1 -0
- package/dist/desktop-target.d.ts +4 -0
- package/dist/desktop-target.d.ts.map +1 -0
- package/dist/desktop-target.js +45 -0
- package/dist/desktop-target.js.map +1 -0
- package/dist/dev-session.d.ts +16 -0
- package/dist/dev-session.d.ts.map +1 -0
- package/dist/dev-session.js +66 -0
- package/dist/dev-session.js.map +1 -0
- package/dist/errors.d.ts +4 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +4 -0
- package/dist/errors.js.map +1 -0
- package/dist/handlers.d.ts +3 -0
- package/dist/handlers.d.ts.map +1 -0
- package/dist/handlers.js +12 -0
- package/dist/handlers.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +37 -0
- package/dist/main.js.map +1 -0
- package/dist/mobile-target.d.ts +5 -0
- package/dist/mobile-target.d.ts.map +1 -0
- package/dist/mobile-target.js +40 -0
- package/dist/mobile-target.js.map +1 -0
- package/dist/ports.d.ts +14 -0
- package/dist/ports.d.ts.map +1 -0
- package/dist/ports.js +45 -0
- package/dist/ports.js.map +1 -0
- package/dist/serve-entry.d.ts +2 -0
- package/dist/serve-entry.d.ts.map +1 -0
- package/dist/serve-entry.js +35 -0
- package/dist/serve-entry.js.map +1 -0
- package/dist/server-process.d.ts +14 -0
- package/dist/server-process.d.ts.map +1 -0
- package/dist/server-process.js +75 -0
- package/dist/server-process.js.map +1 -0
- package/dist/serverless-warning.d.ts +4 -0
- package/dist/serverless-warning.d.ts.map +1 -0
- package/dist/serverless-warning.js +6 -0
- package/dist/serverless-warning.js.map +1 -0
- package/dist/shutdown.d.ts +6 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +22 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/targets.d.ts +27 -0
- package/dist/targets.d.ts.map +1 -0
- package/dist/targets.js +31 -0
- package/dist/targets.js.map +1 -0
- package/dist/web-target.d.ts +6 -0
- package/dist/web-target.d.ts.map +1 -0
- package/dist/web-target.js +50 -0
- package/dist/web-target.js.map +1 -0
- package/package.json +60 -3
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { generatedDir, loadParlorConfig } from "@parlor/config";
|
|
5
|
+
import { createDatabase } from "@parlor/data";
|
|
6
|
+
import { defineCommand } from "citty";
|
|
7
|
+
import { CliError } from "../errors.js";
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
/** `name` replaces drizzle-kit's random suffix, so a generated migration has a stable file name. */
|
|
10
|
+
export function drizzleKitArgs(schema, migrations, name) {
|
|
11
|
+
return [
|
|
12
|
+
"generate",
|
|
13
|
+
"--dialect",
|
|
14
|
+
"postgresql",
|
|
15
|
+
"--schema",
|
|
16
|
+
schema,
|
|
17
|
+
"--out",
|
|
18
|
+
migrations,
|
|
19
|
+
...(name === undefined ? [] : ["--name", name]),
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
const STACK_FRAME = /^\s+at \S/m;
|
|
23
|
+
const KILL_GRACE_MS = 2000;
|
|
24
|
+
const PARENT_SIGNALS = ["SIGINT", "SIGTERM"];
|
|
25
|
+
export function runDrizzleKit(args, cwd, options = {}) {
|
|
26
|
+
const { stdout = "inherit", stderr = process.stderr, signal, timeoutMs } = options;
|
|
27
|
+
const command = `drizzle-kit ${args[0]}`;
|
|
28
|
+
const bin = join(dirname(require.resolve("drizzle-kit")), "bin.cjs");
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
if (signal?.aborted) {
|
|
31
|
+
reject(new CliError(`${command} aborted`));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const child = spawn(process.execPath, [bin, ...args], {
|
|
35
|
+
cwd,
|
|
36
|
+
env: { ...process.env, NODE_NO_WARNINGS: "1" },
|
|
37
|
+
// the rename prompt needs a TTY; without one stdin would only keep the child waiting
|
|
38
|
+
stdio: [process.stdin.isTTY ? "inherit" : "ignore", stdout, "pipe"],
|
|
39
|
+
});
|
|
40
|
+
let stderrText = "";
|
|
41
|
+
let stopReason;
|
|
42
|
+
let parentSignal;
|
|
43
|
+
let killTimer;
|
|
44
|
+
const stop = (reason) => {
|
|
45
|
+
if (stopReason)
|
|
46
|
+
return;
|
|
47
|
+
stopReason = reason;
|
|
48
|
+
child.kill("SIGTERM");
|
|
49
|
+
killTimer = setTimeout(() => child.kill("SIGKILL"), KILL_GRACE_MS);
|
|
50
|
+
};
|
|
51
|
+
const onAbort = () => stop(new CliError(`${command} aborted`));
|
|
52
|
+
const onParentExit = () => {
|
|
53
|
+
child.kill("SIGKILL");
|
|
54
|
+
};
|
|
55
|
+
const onParentSignal = (name) => {
|
|
56
|
+
parentSignal = name;
|
|
57
|
+
stop(new CliError(`${command} interrupted by ${name}`));
|
|
58
|
+
};
|
|
59
|
+
const timeoutTimer = timeoutMs === undefined
|
|
60
|
+
? undefined
|
|
61
|
+
: setTimeout(() => stop(new CliError(`${command} timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
62
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
63
|
+
process.once("exit", onParentExit);
|
|
64
|
+
for (const name of PARENT_SIGNALS)
|
|
65
|
+
process.on(name, onParentSignal);
|
|
66
|
+
const release = () => {
|
|
67
|
+
clearTimeout(timeoutTimer);
|
|
68
|
+
clearTimeout(killTimer);
|
|
69
|
+
signal?.removeEventListener("abort", onAbort);
|
|
70
|
+
process.removeListener("exit", onParentExit);
|
|
71
|
+
for (const name of PARENT_SIGNALS)
|
|
72
|
+
process.removeListener(name, onParentSignal);
|
|
73
|
+
};
|
|
74
|
+
child.stderr.on("data", (chunk) => {
|
|
75
|
+
stderrText += chunk.toString();
|
|
76
|
+
stderr.write(chunk);
|
|
77
|
+
});
|
|
78
|
+
child.once("error", (error) => {
|
|
79
|
+
release();
|
|
80
|
+
reject(error);
|
|
81
|
+
});
|
|
82
|
+
child.once("close", (code) => {
|
|
83
|
+
release();
|
|
84
|
+
if (stopReason)
|
|
85
|
+
reject(stopReason);
|
|
86
|
+
else if (code !== 0)
|
|
87
|
+
reject(new CliError(`${command} failed with exit code ${code}`));
|
|
88
|
+
// drizzle-kit catches its own errors, prints the Error to stderr and still exits 0
|
|
89
|
+
else if (STACK_FRAME.test(stderrText))
|
|
90
|
+
reject(new CliError(`${command} failed`));
|
|
91
|
+
else
|
|
92
|
+
resolve();
|
|
93
|
+
if (parentSignal)
|
|
94
|
+
process.kill(process.pid, parentSignal);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const generate = defineCommand({
|
|
99
|
+
meta: { name: "generate", description: "Generate a SQL migration from the schema" },
|
|
100
|
+
args: {
|
|
101
|
+
name: {
|
|
102
|
+
type: "string",
|
|
103
|
+
description: "Name of the migration file instead of a random one",
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
async run({ args }) {
|
|
107
|
+
const { config, rootDir } = await loadParlorConfig();
|
|
108
|
+
await runDrizzleKit(drizzleKitArgs(config.database.schema, config.database.migrations, args.name), rootDir);
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
const migrate = defineCommand({
|
|
112
|
+
meta: { name: "migrate", description: "Apply pending migrations to the database" },
|
|
113
|
+
async run() {
|
|
114
|
+
const { config, rootDir } = await loadParlorConfig();
|
|
115
|
+
const database = await createDatabase({
|
|
116
|
+
dataDir: join(generatedDir(rootDir), "pglite"),
|
|
117
|
+
});
|
|
118
|
+
try {
|
|
119
|
+
await database.migrate(join(rootDir, config.database.migrations));
|
|
120
|
+
console.log(`migrations applied with ${database.driver}`);
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
await database.close();
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
export const db = defineCommand({
|
|
128
|
+
meta: { name: "db", description: "Database migrations" },
|
|
129
|
+
subCommands: { generate, migrate },
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/commands/db.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport type { Writable } from \"node:stream\";\n\nimport { generatedDir, loadParlorConfig } from \"@parlor/config\";\nimport { createDatabase } from \"@parlor/data\";\nimport { defineCommand } from \"citty\";\n\nimport { CliError } from \"../errors.js\";\n\nconst require = createRequire(import.meta.url);\n\n/** `name` replaces drizzle-kit's random suffix, so a generated migration has a stable file name. */\nexport function drizzleKitArgs(\n schema: string,\n migrations: string,\n name?: string,\n): string[] {\n return [\n \"generate\",\n \"--dialect\",\n \"postgresql\",\n \"--schema\",\n schema,\n \"--out\",\n migrations,\n ...(name === undefined ? [] : [\"--name\", name]),\n ];\n}\n\nconst STACK_FRAME = /^\\s+at \\S/m;\n\nconst KILL_GRACE_MS = 2000;\nconst PARENT_SIGNALS = [\"SIGINT\", \"SIGTERM\"] as const;\n\nexport interface DrizzleKitOptions {\n readonly stdout?: \"inherit\" | \"ignore\";\n readonly stderr?: Writable;\n readonly signal?: AbortSignal;\n readonly timeoutMs?: number;\n}\n\nexport function runDrizzleKit(\n args: readonly string[],\n cwd: string,\n options: DrizzleKitOptions = {},\n): Promise<void> {\n const { stdout = \"inherit\", stderr = process.stderr, signal, timeoutMs } = options;\n const command = `drizzle-kit ${args[0]}`;\n const bin = join(dirname(require.resolve(\"drizzle-kit\")), \"bin.cjs\");\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new CliError(`${command} aborted`));\n return;\n }\n const child = spawn(process.execPath, [bin, ...args], {\n cwd,\n env: { ...process.env, NODE_NO_WARNINGS: \"1\" },\n // the rename prompt needs a TTY; without one stdin would only keep the child waiting\n stdio: [process.stdin.isTTY ? \"inherit\" : \"ignore\", stdout, \"pipe\"],\n });\n let stderrText = \"\";\n let stopReason: CliError | undefined;\n let parentSignal: NodeJS.Signals | undefined;\n let killTimer: NodeJS.Timeout | undefined;\n\n const stop = (reason: CliError) => {\n if (stopReason) return;\n stopReason = reason;\n child.kill(\"SIGTERM\");\n killTimer = setTimeout(() => child.kill(\"SIGKILL\"), KILL_GRACE_MS);\n };\n const onAbort = () => stop(new CliError(`${command} aborted`));\n const onParentExit = () => {\n child.kill(\"SIGKILL\");\n };\n const onParentSignal = (name: NodeJS.Signals) => {\n parentSignal = name;\n stop(new CliError(`${command} interrupted by ${name}`));\n };\n const timeoutTimer =\n timeoutMs === undefined\n ? undefined\n : setTimeout(\n () => stop(new CliError(`${command} timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n process.once(\"exit\", onParentExit);\n for (const name of PARENT_SIGNALS) process.on(name, onParentSignal);\n const release = () => {\n clearTimeout(timeoutTimer);\n clearTimeout(killTimer);\n signal?.removeEventListener(\"abort\", onAbort);\n process.removeListener(\"exit\", onParentExit);\n for (const name of PARENT_SIGNALS) process.removeListener(name, onParentSignal);\n };\n\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderrText += chunk.toString();\n stderr.write(chunk);\n });\n child.once(\"error\", (error) => {\n release();\n reject(error);\n });\n child.once(\"close\", (code) => {\n release();\n if (stopReason) reject(stopReason);\n else if (code !== 0)\n reject(new CliError(`${command} failed with exit code ${code}`));\n // drizzle-kit catches its own errors, prints the Error to stderr and still exits 0\n else if (STACK_FRAME.test(stderrText)) reject(new CliError(`${command} failed`));\n else resolve();\n if (parentSignal) process.kill(process.pid, parentSignal);\n });\n });\n}\n\nconst generate = defineCommand({\n meta: { name: \"generate\", description: \"Generate a SQL migration from the schema\" },\n args: {\n name: {\n type: \"string\",\n description: \"Name of the migration file instead of a random one\",\n },\n },\n async run({ args }) {\n const { config, rootDir } = await loadParlorConfig();\n await runDrizzleKit(\n drizzleKitArgs(config.database.schema, config.database.migrations, args.name),\n rootDir,\n );\n },\n});\n\nconst migrate = defineCommand({\n meta: { name: \"migrate\", description: \"Apply pending migrations to the database\" },\n async run() {\n const { config, rootDir } = await loadParlorConfig();\n const database = await createDatabase({\n dataDir: join(generatedDir(rootDir), \"pglite\"),\n });\n try {\n await database.migrate(join(rootDir, config.database.migrations));\n console.log(`migrations applied with ${database.driver}`);\n } finally {\n await database.close();\n }\n },\n});\n\nexport const db = defineCommand({\n meta: { name: \"db\", description: \"Database migrations\" },\n subCommands: { generate, migrate },\n});\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function runNitroDeploy(hostRoot: string, preset: string): Promise<void>;
|
|
2
|
+
export declare const deploy: import("citty").CommandDef<{
|
|
3
|
+
readonly preset: {
|
|
4
|
+
readonly type: "string";
|
|
5
|
+
readonly description: "Deploy preset: node-server, vercel, netlify, …";
|
|
6
|
+
};
|
|
7
|
+
}>;
|
|
8
|
+
//# sourceMappingURL=deploy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAaA,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc9E;AAED,eAAO,MAAM,MAAM;;;;;EAuBjB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { loadParlorConfig } from "@parlor/config";
|
|
4
|
+
import { nitroPresetFor } from "@parlor/host";
|
|
5
|
+
import { defineCommand } from "citty";
|
|
6
|
+
import { warnChatWithoutAuth } from "../chat-warning.js";
|
|
7
|
+
import { CliError } from "../errors.js";
|
|
8
|
+
import { buildWebAndServer } from "../web-target.js";
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
export function runNitroDeploy(hostRoot, preset) {
|
|
11
|
+
const bin = require.resolve("nitro/cli");
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const child = spawn(process.execPath, [bin, "deploy", "--prebuilt", "--preset", preset, "--dir", hostRoot], { stdio: "inherit" });
|
|
14
|
+
child.once("error", reject);
|
|
15
|
+
child.once("exit", (code) => {
|
|
16
|
+
if (code === 0)
|
|
17
|
+
resolve();
|
|
18
|
+
else
|
|
19
|
+
reject(new CliError(`nitro deploy exited with code ${code}`));
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export const deploy = defineCommand({
|
|
24
|
+
meta: {
|
|
25
|
+
name: "deploy",
|
|
26
|
+
description: "Build the app and deploy the server to its preset",
|
|
27
|
+
},
|
|
28
|
+
args: {
|
|
29
|
+
preset: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "Deploy preset: node-server, vercel, netlify, …",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
async run({ args }) {
|
|
35
|
+
const loaded = await loadParlorConfig();
|
|
36
|
+
await warnChatWithoutAuth(loaded);
|
|
37
|
+
const result = await buildWebAndServer(loaded, { preset: args.preset });
|
|
38
|
+
if (result.preset === "node-server") {
|
|
39
|
+
console.log(`node-server has no remote to deploy to. Run: node ${result.outputDir}/server/index.mjs`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
await runNitroDeploy(result.rootDir, nitroPresetFor(result.preset));
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=deploy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,MAAc;IAC7D,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACzC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CACjB,OAAO,CAAC,QAAQ,EAChB,CAAC,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EACpE,EAAE,KAAK,EAAE,SAAS,EAAE,CACrB,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC1B,IAAI,IAAI,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;;gBACrB,MAAM,CAAC,IAAI,QAAQ,CAAC,iCAAiC,IAAI,EAAE,CAAC,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,aAAa,CAAC;IAClC,IAAI,EAAE;QACJ,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,mDAAmD;KACjE;IACD,IAAI,EAAE;QACJ,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,gDAAgD;SAC9D;KACF;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QAChB,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;QACxC,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACxE,IAAI,MAAM,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,CACT,qDAAqD,MAAM,CAAC,SAAS,mBAAmB,CACzF,CAAC;YACF,OAAO;QACT,CAAC;QACD,MAAM,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACtE,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { createRequire } from \"node:module\";\n\nimport { loadParlorConfig } from \"@parlor/config\";\nimport { nitroPresetFor } from \"@parlor/host\";\nimport { defineCommand } from \"citty\";\n\nimport { warnChatWithoutAuth } from \"../chat-warning.js\";\nimport { CliError } from \"../errors.js\";\nimport { buildWebAndServer } from \"../web-target.js\";\n\nconst require = createRequire(import.meta.url);\n\nexport function runNitroDeploy(hostRoot: string, preset: string): Promise<void> {\n const bin = require.resolve(\"nitro/cli\");\n return new Promise((resolve, reject) => {\n const child = spawn(\n process.execPath,\n [bin, \"deploy\", \"--prebuilt\", \"--preset\", preset, \"--dir\", hostRoot],\n { stdio: \"inherit\" },\n );\n child.once(\"error\", reject);\n child.once(\"exit\", (code) => {\n if (code === 0) resolve();\n else reject(new CliError(`nitro deploy exited with code ${code}`));\n });\n });\n}\n\nexport const deploy = defineCommand({\n meta: {\n name: \"deploy\",\n description: \"Build the app and deploy the server to its preset\",\n },\n args: {\n preset: {\n type: \"string\",\n description: \"Deploy preset: node-server, vercel, netlify, …\",\n },\n },\n async run({ args }) {\n const loaded = await loadParlorConfig();\n await warnChatWithoutAuth(loaded);\n const result = await buildWebAndServer(loaded, { preset: args.preset });\n if (result.preset === \"node-server\") {\n console.log(\n `node-server has no remote to deploy to. Run: node ${result.outputDir}/server/index.mjs`,\n );\n return;\n }\n await runNitroDeploy(result.rootDir, nitroPresetFor(result.preset));\n },\n});\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare function parsePort(value: unknown): number | undefined;
|
|
2
|
+
export declare const dev: import("citty").CommandDef<{
|
|
3
|
+
readonly target: {
|
|
4
|
+
readonly type: "string";
|
|
5
|
+
readonly description: "web | ios | android | mac | windows | linux, or several joined by commas (web,mac) to run them against one server";
|
|
6
|
+
readonly default: "web";
|
|
7
|
+
};
|
|
8
|
+
readonly port: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly description: "Override web.port from parlor.config.ts; a busy port moves to the next free one";
|
|
11
|
+
};
|
|
12
|
+
readonly device: {
|
|
13
|
+
readonly type: "string";
|
|
14
|
+
readonly description: "Simulator or device name for ios and android";
|
|
15
|
+
};
|
|
16
|
+
readonly "agent-host": {
|
|
17
|
+
readonly type: "boolean";
|
|
18
|
+
readonly default: true;
|
|
19
|
+
readonly description: "Serve the chat with this computer's agents (--no-agent-host to skip)";
|
|
20
|
+
};
|
|
21
|
+
}>;
|
|
22
|
+
//# sourceMappingURL=dev.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAcA,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAO5D;AAED,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;EAuEd,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { loadParlorConfig } from "@parlor/config";
|
|
2
|
+
import { inspectServerEntry } from "@parlor/scaffold";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
import { startDevAgentHost } from "../agent-host-process.js";
|
|
5
|
+
import { prepareCloudflareDev } from "../cloudflare/prepare.js";
|
|
6
|
+
import { claimDevSession } from "../dev-session.js";
|
|
7
|
+
import { CliError } from "../errors.js";
|
|
8
|
+
import { handlers } from "../handlers.js";
|
|
9
|
+
import { resolveDevPorts } from "../ports.js";
|
|
10
|
+
import { startServerProcess, untilListening } from "../server-process.js";
|
|
11
|
+
import { onShutdown } from "../shutdown.js";
|
|
12
|
+
import { parseTargets, resolveHandler } from "../targets.js";
|
|
13
|
+
export function parsePort(value) {
|
|
14
|
+
if (value === undefined)
|
|
15
|
+
return undefined;
|
|
16
|
+
const port = Number(value);
|
|
17
|
+
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
18
|
+
throw new CliError(`Invalid --port "${String(value)}"`);
|
|
19
|
+
}
|
|
20
|
+
return port;
|
|
21
|
+
}
|
|
22
|
+
export const dev = defineCommand({
|
|
23
|
+
meta: { name: "dev", description: "Run the app in development mode" },
|
|
24
|
+
args: {
|
|
25
|
+
target: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "web | ios | android | mac | windows | linux, or several joined by commas (web,mac) to run them against one server",
|
|
28
|
+
default: "web",
|
|
29
|
+
},
|
|
30
|
+
port: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "Override web.port from parlor.config.ts; a busy port moves to the next free one",
|
|
33
|
+
},
|
|
34
|
+
device: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "Simulator or device name for ios and android",
|
|
37
|
+
},
|
|
38
|
+
"agent-host": {
|
|
39
|
+
type: "boolean",
|
|
40
|
+
default: true,
|
|
41
|
+
description: "Serve the chat with this computer's agents (--no-agent-host to skip)",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
async run({ args }) {
|
|
45
|
+
const targets = parseTargets(args.target);
|
|
46
|
+
const targetHandlers = targets.map((target) => resolveHandler(handlers, target));
|
|
47
|
+
for (const handler of targetHandlers)
|
|
48
|
+
handler.assertHost?.();
|
|
49
|
+
const configured = await loadParlorConfig();
|
|
50
|
+
const cloudflare = await prepareCloudflareDev(configured);
|
|
51
|
+
const port = parsePort(args.port);
|
|
52
|
+
const session = claimDevSession(configured.rootDir, targets);
|
|
53
|
+
onShutdown(() => session.release());
|
|
54
|
+
const ports = await resolveDevPorts({
|
|
55
|
+
server: configured.config.server.port,
|
|
56
|
+
web: port ?? configured.config.web.port,
|
|
57
|
+
targets: targets.length,
|
|
58
|
+
});
|
|
59
|
+
const frontends = ports.web.map((web) => `http://localhost:${web}`);
|
|
60
|
+
session.update(frontends);
|
|
61
|
+
const main = Math.max(targets.indexOf("web"), 0);
|
|
62
|
+
const appOrigin = frontends[main];
|
|
63
|
+
const loadedFor = (web) => ({
|
|
64
|
+
...configured,
|
|
65
|
+
config: {
|
|
66
|
+
...configured.config,
|
|
67
|
+
server: { ...configured.config.server, port: ports.server },
|
|
68
|
+
web: { ...configured.config.web, port: web },
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
const shared = loadedFor(ports.web[main]);
|
|
72
|
+
const server = await inspectServerEntry(shared.rootDir, shared.config.server.entry);
|
|
73
|
+
const serverProcess = startServerProcess(shared, [appOrigin, ...frontends.filter((origin) => origin !== appOrigin)], cloudflare);
|
|
74
|
+
await untilListening(serverProcess, ports.server);
|
|
75
|
+
startDevAgentHost(shared, {
|
|
76
|
+
enabled: args["agent-host"],
|
|
77
|
+
serverHasAuth: server.auth === "installed",
|
|
78
|
+
});
|
|
79
|
+
await Promise.all(targetHandlers.map((handler, index) => handler.dev(loadedFor(ports.web[index]), {
|
|
80
|
+
device: args.device,
|
|
81
|
+
appOrigin: index === main ? undefined : appOrigin,
|
|
82
|
+
})));
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=dev.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"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","sourcesContent":["import { loadParlorConfig } from \"@parlor/config\";\nimport { inspectServerEntry } from \"@parlor/scaffold\";\nimport { defineCommand } from \"citty\";\n\nimport { startDevAgentHost } from \"../agent-host-process.js\";\nimport { prepareCloudflareDev } from \"../cloudflare/prepare.js\";\nimport { claimDevSession } from \"../dev-session.js\";\nimport { CliError } from \"../errors.js\";\nimport { handlers } from \"../handlers.js\";\nimport { resolveDevPorts } from \"../ports.js\";\nimport { startServerProcess, untilListening } from \"../server-process.js\";\nimport { onShutdown } from \"../shutdown.js\";\nimport { parseTargets, resolveHandler } from \"../targets.js\";\n\nexport function parsePort(value: unknown): number | undefined {\n if (value === undefined) return undefined;\n const port = Number(value);\n if (!Number.isInteger(port) || port <= 0 || port > 65535) {\n throw new CliError(`Invalid --port \"${String(value)}\"`);\n }\n return port;\n}\n\nexport const dev = defineCommand({\n meta: { name: \"dev\", description: \"Run the app in development mode\" },\n args: {\n target: {\n type: \"string\",\n description:\n \"web | ios | android | mac | windows | linux, or several joined by commas (web,mac) to run them against one server\",\n default: \"web\",\n },\n port: {\n type: \"string\",\n description:\n \"Override web.port from parlor.config.ts; a busy port moves to the next free one\",\n },\n device: {\n type: \"string\",\n description: \"Simulator or device name for ios and android\",\n },\n \"agent-host\": {\n type: \"boolean\",\n default: true,\n description: \"Serve the chat with this computer's agents (--no-agent-host to skip)\",\n },\n },\n async run({ args }) {\n const targets = parseTargets(args.target);\n const targetHandlers = targets.map((target) => resolveHandler(handlers, target));\n for (const handler of targetHandlers) handler.assertHost?.();\n const configured = await loadParlorConfig();\n const cloudflare = await prepareCloudflareDev(configured);\n const port = parsePort(args.port);\n const session = claimDevSession(configured.rootDir, targets);\n onShutdown(() => session.release());\n const ports = await resolveDevPorts({\n server: configured.config.server.port,\n web: port ?? configured.config.web.port,\n targets: targets.length,\n });\n const frontends = ports.web.map((web) => `http://localhost:${web}`);\n session.update(frontends);\n const main = Math.max(targets.indexOf(\"web\"), 0);\n const appOrigin = frontends[main]!;\n const loadedFor = (web: number) => ({\n ...configured,\n config: {\n ...configured.config,\n server: { ...configured.config.server, port: ports.server },\n web: { ...configured.config.web, port: web },\n },\n });\n const shared = loadedFor(ports.web[main]!);\n const server = await inspectServerEntry(shared.rootDir, shared.config.server.entry);\n const serverProcess = startServerProcess(\n shared,\n [appOrigin, ...frontends.filter((origin) => origin !== appOrigin)],\n cloudflare,\n );\n await untilListening(serverProcess, ports.server);\n startDevAgentHost(shared, {\n enabled: args[\"agent-host\"],\n serverHasAuth: server.auth === \"installed\",\n });\n await Promise.all(\n targetHandlers.map((handler, index) =>\n handler.dev(loadedFor(ports.web[index]!), {\n device: args.device,\n appOrigin: index === main ? undefined : appOrigin,\n }),\n ),\n );\n },\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typegen.d.ts","sourceRoot":"","sources":["../../src/commands/typegen.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,OAAO,qDASlB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { loadParlorConfig } from "@parlor/config";
|
|
2
|
+
import { generateRouteTree } from "@parlor/shell-web";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
export const typegen = defineCommand({
|
|
5
|
+
meta: {
|
|
6
|
+
name: "typegen",
|
|
7
|
+
description: "Generate the route tree from src/routes, as parlor dev does, without Vite",
|
|
8
|
+
},
|
|
9
|
+
async run() {
|
|
10
|
+
await generateRouteTree(await loadParlorConfig());
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=typegen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typegen.js","sourceRoot":"","sources":["../../src/commands/typegen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEtC,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC;IACnC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,WAAW,EACT,2EAA2E;KAC9E;IACD,KAAK,CAAC,GAAG;QACP,MAAM,iBAAiB,CAAC,MAAM,gBAAgB,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { loadParlorConfig } from \"@parlor/config\";\nimport { generateRouteTree } from \"@parlor/shell-web\";\nimport { defineCommand } from \"citty\";\n\nexport const typegen = defineCommand({\n meta: {\n name: \"typegen\",\n description:\n \"Generate the route tree from src/routes, as parlor dev does, without Vite\",\n },\n async run() {\n await generateRouteTree(await loadParlorConfig());\n },\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop-target.d.ts","sourceRoot":"","sources":["../src/desktop-target.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAQ1D,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAM,CAAC,QAA2B,QAQ7C;AAYD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAmB3D"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { buildDesktop, startDesktopDev, TauriCliError } from "@parlor/shell-desktop";
|
|
2
|
+
import { CliError } from "./errors.js";
|
|
3
|
+
import { onShutdown } from "./shutdown.js";
|
|
4
|
+
const HOST_TARGET = {
|
|
5
|
+
darwin: "mac",
|
|
6
|
+
win32: "windows",
|
|
7
|
+
linux: "linux",
|
|
8
|
+
};
|
|
9
|
+
export function assertHostMatches(target, platform = process.platform) {
|
|
10
|
+
const host = HOST_TARGET[platform];
|
|
11
|
+
if (host !== target) {
|
|
12
|
+
throw new CliError(`Target "${target}" can only be built on its own operating system. This machine builds "${host ?? "nothing"}".`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async function surfaceTauriErrors(run) {
|
|
16
|
+
try {
|
|
17
|
+
return await run();
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error instanceof TauriCliError)
|
|
21
|
+
throw new CliError(error.message, { cause: error });
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function desktopTarget(target) {
|
|
26
|
+
return {
|
|
27
|
+
assertHost: () => assertHostMatches(target),
|
|
28
|
+
async dev(loaded, options) {
|
|
29
|
+
await surfaceTauriErrors(async () => {
|
|
30
|
+
const controller = new AbortController();
|
|
31
|
+
onShutdown(() => controller.abort());
|
|
32
|
+
await startDesktopDev(loaded, {
|
|
33
|
+
signal: controller.signal,
|
|
34
|
+
appOrigin: options.appOrigin,
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
async build(loaded, _options) {
|
|
39
|
+
assertHostMatches(target);
|
|
40
|
+
const bundleDir = await surfaceTauriErrors(() => buildDesktop(loaded));
|
|
41
|
+
console.log(`desktop bundles written to ${bundleDir}`);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=desktop-target.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop-target.js","sourceRoot":"","sources":["../src/desktop-target.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAErF,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,MAAM,WAAW,GAA6C;IAC5D,MAAM,EAAE,KAAK;IACb,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,OAAO;CACf,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAC/B,MAAc,EACd,QAAQ,GAAoB,OAAO,CAAC,QAAQ;IAE5C,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,QAAQ,CAChB,WAAW,MAAM,yEAAyE,IAAI,IAAI,SAAS,IAAI,CAChH,CAAC;IACJ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAI,GAAqB;IACxD,IAAI,CAAC;QACH,OAAO,MAAM,GAAG,EAAE,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,aAAa;YAChC,MAAM,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QACtD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,OAAO;QACL,UAAU,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC;QAC3C,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO;YACvB,MAAM,kBAAkB,CAAC,KAAK,IAAI,EAAE;gBAClC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;gBACzC,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;gBACrC,MAAM,eAAe,CAAC,MAAM,EAAE;oBAC5B,MAAM,EAAE,UAAU,CAAC,MAAM;oBACzB,SAAS,EAAE,OAAO,CAAC,SAAS;iBAC7B,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ;YAC1B,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC1B,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;YACvE,OAAO,CAAC,GAAG,CAAC,8BAA8B,SAAS,EAAE,CAAC,CAAC;QACzD,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { buildDesktop, startDesktopDev, TauriCliError } from \"@parlor/shell-desktop\";\n\nimport { CliError } from \"./errors.js\";\nimport { onShutdown } from \"./shutdown.js\";\nimport type { Target, TargetHandler } from \"./targets.js\";\n\nconst HOST_TARGET: Partial<Record<NodeJS.Platform, Target>> = {\n darwin: \"mac\",\n win32: \"windows\",\n linux: \"linux\",\n};\n\nexport function assertHostMatches(\n target: Target,\n platform: NodeJS.Platform = process.platform,\n) {\n const host = HOST_TARGET[platform];\n if (host !== target) {\n throw new CliError(\n `Target \"${target}\" can only be built on its own operating system. This machine builds \"${host ?? \"nothing\"}\".`,\n );\n }\n}\n\nasync function surfaceTauriErrors<T>(run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (error) {\n if (error instanceof TauriCliError)\n throw new CliError(error.message, { cause: error });\n throw error;\n }\n}\n\nexport function desktopTarget(target: Target): TargetHandler {\n return {\n assertHost: () => assertHostMatches(target),\n async dev(loaded, options) {\n await surfaceTauriErrors(async () => {\n const controller = new AbortController();\n onShutdown(() => controller.abort());\n await startDesktopDev(loaded, {\n signal: controller.signal,\n appOrigin: options.appOrigin,\n });\n });\n },\n async build(loaded, _options) {\n assertHostMatches(target);\n const bundleDir = await surfaceTauriErrors(() => buildDesktop(loaded));\n console.log(`desktop bundles written to ${bundleDir}`);\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface DevSession {
|
|
2
|
+
readonly pid: number;
|
|
3
|
+
readonly targets: readonly string[];
|
|
4
|
+
readonly urls: readonly string[];
|
|
5
|
+
}
|
|
6
|
+
export declare const DEV_SESSION_FILE = "dev.json";
|
|
7
|
+
/**
|
|
8
|
+
* Claims the run's generated directory for this `parlor dev`, so a second one cannot open the
|
|
9
|
+
* same database; a claim whose process is gone is stale. `update` records the URLs once the
|
|
10
|
+
* ports are known.
|
|
11
|
+
*/
|
|
12
|
+
export declare function claimDevSession(rootDir: string, targets: readonly string[], pid?: number): {
|
|
13
|
+
update(urls: readonly string[]): void;
|
|
14
|
+
release(): void;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=dev-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-session.d.ts","sourceRoot":"","sources":["../src/dev-session.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAED,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAgC3C;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,GAAG,GAAE,MAAoB,GACxB;IAAE,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IAAC,OAAO,IAAI,IAAI,CAAA;CAAE,CAwB5D"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { closeSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync, writeSync, } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { GENERATED_DIR_ENV, generatedDir } from "@parlor/config";
|
|
4
|
+
import { CliError } from "./errors.js";
|
|
5
|
+
export const DEV_SESSION_FILE = "dev.json";
|
|
6
|
+
function alive(pid) {
|
|
7
|
+
try {
|
|
8
|
+
process.kill(pid, 0);
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
return error.code === "EPERM";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function read(path) {
|
|
16
|
+
try {
|
|
17
|
+
const session = JSON.parse(readFileSync(path, "utf8"));
|
|
18
|
+
return typeof session.pid === "number"
|
|
19
|
+
? { pid: session.pid, targets: session.targets ?? [], urls: session.urls ?? [] }
|
|
20
|
+
: undefined;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function running(owner) {
|
|
27
|
+
const targets = owner.targets.length > 0 ? owner.targets : ["web"];
|
|
28
|
+
const where = targets
|
|
29
|
+
.map((target, index) => owner.urls[index] ? `${target} at ${owner.urls[index]}` : target)
|
|
30
|
+
.join(", ");
|
|
31
|
+
return `parlor dev is already running for this project (${where}, pid ${owner.pid}). A second one would open the same database. Stop it first, run every target from one: parlor dev --target web,mac, or give the second its own directory: ${GENERATED_DIR_ENV}=.parlor/second parlor dev.`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Claims the run's generated directory for this `parlor dev`, so a second one cannot open the
|
|
35
|
+
* same database; a claim whose process is gone is stale. `update` records the URLs once the
|
|
36
|
+
* ports are known.
|
|
37
|
+
*/
|
|
38
|
+
export function claimDevSession(rootDir, targets, pid = process.pid) {
|
|
39
|
+
const path = join(generatedDir(rootDir), DEV_SESSION_FILE);
|
|
40
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
41
|
+
const write = (urls) => JSON.stringify({ pid, targets, urls });
|
|
42
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
43
|
+
try {
|
|
44
|
+
const fd = openSync(path, "wx");
|
|
45
|
+
writeSync(fd, write([]));
|
|
46
|
+
closeSync(fd);
|
|
47
|
+
return {
|
|
48
|
+
update: (urls) => writeFileSync(path, write(urls)),
|
|
49
|
+
release: () => {
|
|
50
|
+
if (read(path)?.pid === pid)
|
|
51
|
+
rmSync(path, { force: true });
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error.code !== "EEXIST")
|
|
57
|
+
throw error;
|
|
58
|
+
const owner = read(path);
|
|
59
|
+
if (owner && owner.pid !== pid && alive(owner.pid))
|
|
60
|
+
throw new CliError(running(owner));
|
|
61
|
+
rmSync(path, { force: true });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
throw new CliError(`Could not claim ${path} for parlor dev.`);
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=dev-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-session.js","sourceRoot":"","sources":["../src/dev-session.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n closeSync,\n mkdirSync,\n openSync,\n readFileSync,\n rmSync,\n writeFileSync,\n writeSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nimport { GENERATED_DIR_ENV, generatedDir } from \"@parlor/config\";\n\nimport { CliError } from \"./errors.js\";\n\nexport interface DevSession {\n readonly pid: number;\n readonly targets: readonly string[];\n readonly urls: readonly string[];\n}\n\nexport const DEV_SESSION_FILE = \"dev.json\";\n\nfunction alive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n\nfunction read(path: string): DevSession | undefined {\n try {\n const session = JSON.parse(readFileSync(path, \"utf8\")) as Partial<DevSession>;\n return typeof session.pid === \"number\"\n ? { pid: session.pid, targets: session.targets ?? [], urls: session.urls ?? [] }\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction running(owner: DevSession): string {\n const targets = owner.targets.length > 0 ? owner.targets : [\"web\"];\n const where = targets\n .map((target, index) =>\n owner.urls[index] ? `${target} at ${owner.urls[index]}` : target,\n )\n .join(\", \");\n return `parlor dev is already running for this project (${where}, pid ${owner.pid}). A second one would open the same database. Stop it first, run every target from one: parlor dev --target web,mac, or give the second its own directory: ${GENERATED_DIR_ENV}=.parlor/second parlor dev.`;\n}\n\n/**\n * Claims the run's generated directory for this `parlor dev`, so a second one cannot open the\n * same database; a claim whose process is gone is stale. `update` records the URLs once the\n * ports are known.\n */\nexport function claimDevSession(\n rootDir: string,\n targets: readonly string[],\n pid: number = process.pid,\n): { update(urls: readonly string[]): void; release(): void } {\n const path = join(generatedDir(rootDir), DEV_SESSION_FILE);\n mkdirSync(dirname(path), { recursive: true });\n const write = (urls: readonly string[]) => JSON.stringify({ pid, targets, urls });\n for (let attempt = 0; attempt < 2; attempt += 1) {\n try {\n const fd = openSync(path, \"wx\");\n writeSync(fd, write([]));\n closeSync(fd);\n return {\n update: (urls) => writeFileSync(path, write(urls)),\n release: () => {\n if (read(path)?.pid === pid) rmSync(path, { force: true });\n },\n };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n const owner = read(path);\n if (owner && owner.pid !== pid && alive(owner.pid))\n throw new CliError(running(owner));\n rmSync(path, { force: true });\n }\n }\n throw new CliError(`Could not claim ${path} for parlor dev.`);\n}\n"]}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAkB,IAAI,EAAE,MAAM,CAAc;CAC7C"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAS,SAAQ,KAAK;IACf,IAAI,GAAW,UAAU,CAAC;CAC7C","sourcesContent":["export class CliError extends Error {\n override readonly name: string = \"CliError\";\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG1D,eAAO,MAAM,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAO3D,CAAC"}
|
package/dist/handlers.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { desktopTarget } from "./desktop-target.js";
|
|
2
|
+
import { mobileTarget } from "./mobile-target.js";
|
|
3
|
+
import { webTarget } from "./web-target.js";
|
|
4
|
+
export const handlers = {
|
|
5
|
+
web: webTarget,
|
|
6
|
+
ios: mobileTarget("ios"),
|
|
7
|
+
android: mobileTarget("android"),
|
|
8
|
+
mac: desktopTarget("mac"),
|
|
9
|
+
windows: desktopTarget("windows"),
|
|
10
|
+
linux: desktopTarget("linux"),
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,CAAC,MAAM,QAAQ,GAA2C;IAC9D,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,YAAY,CAAC,KAAK,CAAC;IACxB,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC;IAChC,GAAG,EAAE,aAAa,CAAC,KAAK,CAAC;IACzB,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC;IACjC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC;CAC9B,CAAC","sourcesContent":["import { desktopTarget } from \"./desktop-target.js\";\nimport { mobileTarget } from \"./mobile-target.js\";\nimport type { Target, TargetHandler } from \"./targets.js\";\nimport { webTarget } from \"./web-target.js\";\n\nexport const handlers: Partial<Record<Target, TargetHandler>> = {\n web: webTarget,\n ios: mobileTarget(\"ios\"),\n android: mobileTarget(\"android\"),\n mac: desktopTarget(\"mac\"),\n windows: desktopTarget(\"windows\"),\n linux: desktopTarget(\"linux\"),\n};\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,cAAc,EACd,KAAK,MAAM,EACX,WAAW,EACX,KAAK,aAAa,EAClB,OAAO,GACR,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,cAAc,EAEd,WAAW,EAEX,OAAO,GACR,MAAM,cAAc,CAAC","sourcesContent":["export {\n parseTarget,\n resolveHandler,\n type Target,\n TargetError,\n type TargetHandler,\n TARGETS,\n} from \"./targets.js\";\n"]}
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
|