@nyte-ai/host 0.0.18 → 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +66 -0
- package/dist/chunks/{canvas-preview-5hxat7hh.js → canvas-preview-11nadadc.js} +8 -6
- package/dist/chunks/{canvas-preview-rp6fz0w5.js → canvas-preview-2jwbe14k.js} +5 -5
- package/dist/chunks/{canvas-preview-m02v4yy6.js → canvas-preview-55s0y68g.js} +3 -2
- package/dist/chunks/{canvas-preview-xn10d4f8.js → canvas-preview-5ekjx6sw.js} +9 -4
- package/dist/chunks/{canvas-preview-75db60xy.js → canvas-preview-8xc0vn7v.js} +5 -4
- package/dist/chunks/{canvas-preview-zn2d0k9d.js → canvas-preview-af86jz8t.js} +14 -6
- package/dist/chunks/{canvas-preview-d9wwhbtz.js → canvas-preview-aq5j4p25.js} +1 -1
- package/dist/chunks/{canvas-preview-j1tnf51w.js → canvas-preview-b2v8wfnz.js} +1 -1
- package/dist/chunks/canvas-preview-befkjea2.js +60 -0
- package/dist/chunks/canvas-preview-bxnqt8cd.js +103 -0
- package/dist/chunks/{canvas-preview-vax9ne4e.js → canvas-preview-cawy6vbz.js} +22 -11
- package/dist/chunks/{canvas-preview-senpjwep.js → canvas-preview-crmzxxt8.js} +3 -3
- package/dist/chunks/{canvas-preview-ymgz0937.js → canvas-preview-drctegz4.js} +8 -4
- package/dist/chunks/{canvas-preview-yrfz2ak6.js → canvas-preview-e3vnkkc5.js} +6 -6
- package/dist/chunks/canvas-preview-ec2mt7es.js +108 -0
- package/dist/chunks/{canvas-preview-1ta3avah.js → canvas-preview-fxa0rfb0.js} +10 -5
- package/dist/chunks/{canvas-preview-8xgt67ka.js → canvas-preview-g5fkjs34.js} +1 -1
- package/dist/chunks/{canvas-preview-g3qj3y3k.js → canvas-preview-jeddjex8.js} +13 -3
- package/dist/chunks/{canvas-preview-0nrnbt76.js → canvas-preview-k1yg4fgp.js} +199 -125
- package/dist/chunks/canvas-preview-kp75gb63.js +141 -0
- package/dist/chunks/{canvas-preview-ewgspmsd.js → canvas-preview-n2a35zv5.js} +1 -1
- package/dist/chunks/{canvas-preview-h8hshnff.js → canvas-preview-pkzqg96v.js} +1 -1
- package/dist/chunks/{canvas-preview-evh92ywd.js → canvas-preview-tnqe7k0b.js} +15 -10
- package/dist/chunks/{canvas-preview-ehf3vp31.js → canvas-preview-vm9zdp2t.js} +45 -58
- package/dist/chunks/{canvas-preview-76fwvd6e.js → canvas-preview-w54ymtb3.js} +1 -1
- package/dist/chunks/canvas-preview-y5y6ghaw.js +125 -0
- package/dist/chunks/{canvas-preview-98aj5p34.js → canvas-preview-ycepb05s.js} +1 -1
- package/dist/src/canvas-preview.js +7 -3
- package/dist/src/deploy/cloudflare/worker.js +1 -1
- package/dist/src/deploy/vercel/server/routes/[...].js +2 -2
- package/dist/src/deploy/vercel/server/utils/host.js +1 -1
- package/dist/src/deploy/vercel/server/workflows/drive.js +3 -3
- package/dist/src/images/exif.d.ts +1 -0
- package/dist/src/images/exif.js +6 -0
- package/dist/src/images/node.d.ts +37 -0
- package/dist/src/images/node.js +12 -0
- package/dist/src/images/photon.d.ts +3 -0
- package/dist/src/images/photon.js +7 -0
- package/dist/src/images/worker.d.ts +1 -0
- package/dist/src/images/worker.js +23 -0
- package/dist/src/index.d.ts +0 -1
- package/dist/src/index.js +23 -22
- package/dist/src/listen-fetch.js +3 -3
- package/dist/src/listen.js +4 -4
- package/dist/src/local/command.d.ts +5 -0
- package/dist/src/local/command.js +6 -2
- package/dist/src/local/files.js +2 -2
- package/dist/src/local/git-watch.d.ts +1 -1
- package/dist/src/local/git-watch.js +1 -1
- package/dist/src/local/git.js +3 -3
- package/dist/src/local/github.js +2 -2
- package/dist/src/local/jobs.d.ts +1 -1
- package/dist/src/local/jobs.js +2 -1
- package/dist/src/local/provider.js +9 -9
- package/dist/src/local/snapshots.js +2 -2
- package/dist/src/local/worktrees.js +2 -2
- package/dist/src/mcp/connect.d.ts +0 -13
- package/dist/src/mcp/connect.js +1 -1
- package/dist/src/mcp/hub.js +2 -2
- package/dist/src/open.d.ts +2 -30
- package/dist/src/open.js +20 -18
- package/dist/src/serve/binding.js +1 -1
- package/dist/src/serve/handler.js +2 -2
- package/dist/src/sqlite.d.ts +2 -1
- package/dist/src/sqlite.js +4 -3
- package/dist/src/store-usage.js +4 -1
- package/dist/src/usage-history.d.ts +54 -0
- package/dist/src/usage-history.js +14 -0
- package/dist/src/usage-service.d.ts +2 -1
- package/dist/src/usage-service.js +7 -3
- package/dist/src/usage-worker.js +8 -4
- package/dist/src/usage.d.ts +150 -27
- package/dist/src/usage.js +12 -2
- package/package.json +16 -8
- package/src/canvas-preview.ts +4 -3
- package/src/images/exif.ts +69 -0
- package/src/images/node.ts +163 -0
- package/src/images/photon.ts +141 -0
- package/src/images/worker.ts +29 -0
- package/src/index.ts +19 -1
- package/src/local/command.ts +64 -12
- package/src/local/files.ts +8 -3
- package/src/local/git-watch.ts +16 -6
- package/src/local/git.ts +7 -2
- package/src/local/github.ts +3 -4
- package/src/local/jobs.ts +55 -69
- package/src/local/snapshots.ts +4 -2
- package/src/local/worktrees.ts +4 -4
- package/src/mcp/connect.ts +1 -14
- package/src/open.ts +16 -36
- package/src/serve/binding.ts +4 -3
- package/src/sqlite.ts +33 -8
- package/src/store-usage.ts +5 -2
- package/src/usage-history.ts +219 -0
- package/src/usage-service.ts +12 -3
- package/src/usage.ts +251 -176
- package/dist/chunks/canvas-preview-a3yw0j70.js +0 -72
- package/dist/chunks/canvas-preview-azg56359.js +0 -68
- package/dist/src/store-owner.d.ts +0 -15
- package/dist/src/store-owner.js +0 -9
- package/src/store-owner.ts +0 -98
|
@@ -18,13 +18,11 @@ import {
|
|
|
18
18
|
sessionIndexChanges2,
|
|
19
19
|
sqlSessionIndex2
|
|
20
20
|
} from "./canvas-preview-0cmbkp2j.js";
|
|
21
|
-
import {
|
|
22
|
-
claimStore2
|
|
23
|
-
} from "./canvas-preview-a3yw0j70.js";
|
|
24
21
|
|
|
25
22
|
// src/sqlite.ts
|
|
26
23
|
import { mkdirSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
27
24
|
import { dirname, join } from "node:path";
|
|
25
|
+
import process from "node:process";
|
|
28
26
|
import { DatabaseSync } from "node:sqlite";
|
|
29
27
|
import { asSeq } from "@nyte-ai/schema";
|
|
30
28
|
import { dev } from "@nyte-ai/core";
|
|
@@ -43,14 +41,15 @@ import {
|
|
|
43
41
|
var BUSY_TIMEOUT_MS = 5000;
|
|
44
42
|
var BACKUPS_KEPT = 3;
|
|
45
43
|
var PUT_BODY = "INSERT INTO objects (id, body) VALUES (?, ?) ON CONFLICT (id) DO UPDATE SET body = excluded.body WHERE objects.body IS NULL";
|
|
44
|
+
function storePath2(home) {
|
|
45
|
+
return process.env["NYTE_DB"] ?? join(home, ".nyte", "nyte.db");
|
|
46
|
+
}
|
|
46
47
|
function sqliteStore2(input) {
|
|
47
48
|
let database = null;
|
|
48
49
|
let opening = null;
|
|
49
50
|
let closing = null;
|
|
50
51
|
let workers = null;
|
|
51
|
-
let release = null;
|
|
52
52
|
const open = async () => {
|
|
53
|
-
const claim = "path" in input ? claimStore2(input.path) : null;
|
|
54
53
|
let created;
|
|
55
54
|
try {
|
|
56
55
|
created = new DatabaseSync("path" in input ? input.path : ":memory:", {
|
|
@@ -65,11 +64,9 @@ function sqliteStore2(input) {
|
|
|
65
64
|
created.exec("PRAGMA optimize = 0x10012");
|
|
66
65
|
} catch (error) {
|
|
67
66
|
created?.close();
|
|
68
|
-
claim?.();
|
|
69
67
|
throw error;
|
|
70
68
|
}
|
|
71
69
|
database = created;
|
|
72
|
-
release = claim;
|
|
73
70
|
workers = "path" in input ? sqliteWorkers2(created, input.path) : null;
|
|
74
71
|
return connect(created, workers);
|
|
75
72
|
};
|
|
@@ -91,10 +88,8 @@ function sqliteStore2(input) {
|
|
|
91
88
|
});
|
|
92
89
|
await workers?.close();
|
|
93
90
|
database?.close();
|
|
94
|
-
release?.();
|
|
95
91
|
workers = null;
|
|
96
92
|
database = null;
|
|
97
|
-
release = null;
|
|
98
93
|
opening = null;
|
|
99
94
|
})().finally(() => {
|
|
100
95
|
closing = null;
|
|
@@ -219,6 +214,7 @@ function connect(database, workers) {
|
|
|
219
214
|
const listRange = database.prepare("SELECT name, target, revision FROM refs WHERE name >= ? AND name < ? ORDER BY name");
|
|
220
215
|
const putRef = database.prepare("INSERT INTO refs (name, target, revision) VALUES (?, ?, ?) ON CONFLICT (name) DO UPDATE SET target = excluded.target, revision = excluded.revision");
|
|
221
216
|
const deleteRef = database.prepare("DELETE FROM refs WHERE name = ?");
|
|
217
|
+
const audit = auditing(database);
|
|
222
218
|
const append = database.prepare("INSERT INTO log (session, seq, at, event) VALUES (?, ?, ?, ?)");
|
|
223
219
|
const readLog = database.prepare("SELECT seq, at, event FROM log WHERE session = ? AND seq > ? ORDER BY seq LIMIT ?");
|
|
224
220
|
const readTail = database.prepare("SELECT MAX(seq) AS tail FROM log WHERE session = ?");
|
|
@@ -295,12 +291,15 @@ function connect(database, workers) {
|
|
|
295
291
|
};
|
|
296
292
|
}
|
|
297
293
|
const touched = new Map;
|
|
294
|
+
const current = new Map([...before].map(([name, row]) => [name, row?.revision ?? null]));
|
|
298
295
|
const revisions = updates.map((update) => {
|
|
299
296
|
const revision = mintRevision2();
|
|
300
297
|
if (update.target === null)
|
|
301
298
|
deleteRef.run(update.name);
|
|
302
299
|
else
|
|
303
300
|
putRef.run(update.name, update.target, revision);
|
|
301
|
+
audit?.run(Date.now(), process.pid, fenceNames([update]).find((name) => name.startsWith("processes/")) ?? null, update.name, current.get(update.name) ?? null, update.target === null ? null : revision, update.target);
|
|
302
|
+
current.set(update.name, update.target === null ? null : revision);
|
|
304
303
|
updateSessionIndex(database, update.name, update.target, revision);
|
|
305
304
|
const session = parseSessionRef(update.name);
|
|
306
305
|
if (session !== null)
|
|
@@ -354,6 +353,12 @@ function connect(database, workers) {
|
|
|
354
353
|
}
|
|
355
354
|
};
|
|
356
355
|
}
|
|
356
|
+
function auditing(database) {
|
|
357
|
+
if (process.env.NYTE_STORE_AUDIT !== "1")
|
|
358
|
+
return null;
|
|
359
|
+
database.exec("CREATE TABLE IF NOT EXISTS store_audit (id INTEGER PRIMARY KEY, at INTEGER NOT NULL, pid INTEGER NOT NULL, writer TEXT, name TEXT NOT NULL, before TEXT, after TEXT, target TEXT)");
|
|
360
|
+
return database.prepare("INSERT INTO store_audit (at, pid, writer, name, before, after, target) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
|
361
|
+
}
|
|
357
362
|
function updateSessionIndex(database, name, target, revision) {
|
|
358
363
|
if (sessionIndexRef(name) === null)
|
|
359
364
|
return;
|
|
@@ -366,4 +371,4 @@ function write(database, statement, ...params) {
|
|
|
366
371
|
return (size > 64 * 1024 ? database.prepare(statement.sourceSQL) : statement).run(...params);
|
|
367
372
|
}
|
|
368
373
|
|
|
369
|
-
export { sqliteStore2 };
|
|
374
|
+
export { storePath2, sqliteStore2 };
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
run2,
|
|
3
|
+
spawnCommand2,
|
|
4
|
+
killTree2,
|
|
5
|
+
findExecutable2
|
|
6
|
+
} from "./canvas-preview-bxnqt8cd.js";
|
|
7
|
+
|
|
1
8
|
// src/local/jobs.ts
|
|
2
9
|
import { spawn } from "node:child_process";
|
|
3
10
|
import { createRequire } from "node:module";
|
|
4
|
-
import { resolve } from "node:path";
|
|
11
|
+
import { basename, resolve } from "node:path";
|
|
5
12
|
import { asId, SdkError } from "@nyte-ai/schema";
|
|
6
13
|
import {
|
|
7
14
|
processEnvironment,
|
|
@@ -16,11 +23,7 @@ var PAUSE_BYTES = 256 * 1024;
|
|
|
16
23
|
var RESUME_BYTES = 64 * 1024;
|
|
17
24
|
var STOP_GRACE_MS = 2000;
|
|
18
25
|
var CLOSE_GRACE_MS = 2000;
|
|
19
|
-
var QUIET_MS = 300;
|
|
20
26
|
var DONE = { done: true, value: undefined };
|
|
21
|
-
var ESC = "\x1B";
|
|
22
|
-
var BEL = "\x07";
|
|
23
|
-
var PROMPT_MARKER = new RegExp(`${ESC}\\]133;([ABCD])`, "g");
|
|
24
27
|
var loaded;
|
|
25
28
|
function localExec2(root, options) {
|
|
26
29
|
const readers = new Set;
|
|
@@ -106,7 +109,7 @@ function localExec2(root, options) {
|
|
|
106
109
|
return { kind: "not-pty" };
|
|
107
110
|
return finished === null && driver.resize(size) ? { kind: "resized" } : { kind: "missing" };
|
|
108
111
|
},
|
|
109
|
-
idle: async () => finished
|
|
112
|
+
idle: async () => driver.pty && (finished !== null || driver.idle()),
|
|
110
113
|
stop: async () => ({ kind: "settled", outcome: await stop() }),
|
|
111
114
|
settled: (request) => waitEnd(ended, request),
|
|
112
115
|
close,
|
|
@@ -116,16 +119,16 @@ function localExec2(root, options) {
|
|
|
116
119
|
};
|
|
117
120
|
}
|
|
118
121
|
async function pipe(command, options, log, finish) {
|
|
119
|
-
const
|
|
122
|
+
const windows = process.platform === "win32";
|
|
120
123
|
const [file, ...args] = typeof command === "string" ? [command] : command;
|
|
121
124
|
const settings = {
|
|
122
125
|
cwd: options.cwd,
|
|
123
126
|
env: options.env,
|
|
124
|
-
detached:
|
|
127
|
+
detached: !windows,
|
|
125
128
|
stdio: "pipe",
|
|
126
129
|
windowsHide: true
|
|
127
130
|
};
|
|
128
|
-
const child = typeof command === "string" ? spawn(command, { ...settings, shell: true }) :
|
|
131
|
+
const child = typeof command === "string" ? spawn(command, { ...settings, shell: true }) : spawnCommand2(windows ? await findExecutable2(file ?? "") ?? file ?? "" : file ?? "", args, settings);
|
|
129
132
|
await new Promise((started, failed) => {
|
|
130
133
|
child.once("spawn", started);
|
|
131
134
|
child.once("error", (error) => failed(new SdkError("unavailable", `Cannot start ${file ?? ""}: ${error.message}`)));
|
|
@@ -146,12 +149,13 @@ async function pipe(command, options, log, finish) {
|
|
|
146
149
|
child.stdin?.on("error", () => {
|
|
147
150
|
return;
|
|
148
151
|
});
|
|
149
|
-
|
|
152
|
+
let killed = false;
|
|
153
|
+
child.on("close", (code) => finish(killed ? null : code));
|
|
150
154
|
child.on("exit", (code) => {
|
|
151
155
|
setTimeout(() => {
|
|
152
156
|
child.stdout?.destroy();
|
|
153
157
|
child.stderr?.destroy();
|
|
154
|
-
finish(code);
|
|
158
|
+
finish(killed ? null : code);
|
|
155
159
|
}, CLOSE_GRACE_MS).unref();
|
|
156
160
|
});
|
|
157
161
|
return {
|
|
@@ -165,8 +169,13 @@ async function pipe(command, options, log, finish) {
|
|
|
165
169
|
resize: () => false,
|
|
166
170
|
idle: () => false,
|
|
167
171
|
kill(signal) {
|
|
172
|
+
if (windows) {
|
|
173
|
+
killed = true;
|
|
174
|
+
killTree2(child, signal);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
168
177
|
try {
|
|
169
|
-
if (
|
|
178
|
+
if (child.pid !== undefined)
|
|
170
179
|
process.kill(-child.pid, signal);
|
|
171
180
|
else
|
|
172
181
|
child.kill(signal);
|
|
@@ -200,21 +209,7 @@ async function terminal(command, options, log, finish) {
|
|
|
200
209
|
throw new SdkError("unavailable", `Cannot start ${file ?? shell} in a pty: ${error instanceof Error ? error.message : String(error)}`);
|
|
201
210
|
}
|
|
202
211
|
const encoder = new TextEncoder;
|
|
203
|
-
|
|
204
|
-
let line = "";
|
|
205
|
-
let quietSince = 0;
|
|
206
|
-
term.onData((text) => {
|
|
207
|
-
log.push(encoder.encode(text));
|
|
208
|
-
quietSince = Date.now();
|
|
209
|
-
marker = lastMarker(text) ?? marker;
|
|
210
|
-
const plain = withoutEscapes(text);
|
|
211
|
-
const broken = plain.lastIndexOf(`
|
|
212
|
-
`);
|
|
213
|
-
line = (broken < 0 ? line + plain : plain.slice(broken + 1)).slice(-1024);
|
|
214
|
-
const returned = line.replace(/\r+$/, "").lastIndexOf("\r");
|
|
215
|
-
if (returned >= 0)
|
|
216
|
-
line = line.slice(returned + 1);
|
|
217
|
-
});
|
|
212
|
+
term.onData((text) => log.push(encoder.encode(text)));
|
|
218
213
|
term.onExit(({ exitCode, signal }) => finish(signal ? null : exitCode));
|
|
219
214
|
log.throttle({ pause: () => term.pause(), resume: () => term.resume() });
|
|
220
215
|
return {
|
|
@@ -226,10 +221,29 @@ async function terminal(command, options, log, finish) {
|
|
|
226
221
|
term.resize(size.columns, size.rows);
|
|
227
222
|
return true;
|
|
228
223
|
},
|
|
229
|
-
idle() {
|
|
230
|
-
if (
|
|
231
|
-
return
|
|
232
|
-
|
|
224
|
+
async idle() {
|
|
225
|
+
if (typeof command === "string" || command.length !== 0)
|
|
226
|
+
return false;
|
|
227
|
+
const result = await run2(windows ? "powershell.exe" : "ps", windows ? [
|
|
228
|
+
"-NoProfile",
|
|
229
|
+
"-NonInteractive",
|
|
230
|
+
"-Command",
|
|
231
|
+
`Get-CimInstance Win32_Process -Filter "ParentProcessId = ${term.pid} AND Name != 'conhost.exe' AND Name != 'OpenConsole.exe'" | Select-Object -ExpandProperty ProcessId`
|
|
232
|
+
] : ["-A", "-o", "pid=,ppid=,stat=,comm="], { cwd: options.cwd, timeoutMs: 1500 });
|
|
233
|
+
if (result.code !== 0)
|
|
234
|
+
throw new SdkError("unavailable", "Cannot inspect terminal processes");
|
|
235
|
+
const processes = result.stdout.toString("utf8").trim();
|
|
236
|
+
if (windows)
|
|
237
|
+
return processes === "";
|
|
238
|
+
return !processes.split(`
|
|
239
|
+
`).some((line) => {
|
|
240
|
+
const [pid, parent, state, ...name] = line.trim().split(/\s+/);
|
|
241
|
+
if (state?.startsWith("Z"))
|
|
242
|
+
return false;
|
|
243
|
+
if (Number(parent) === term.pid)
|
|
244
|
+
return true;
|
|
245
|
+
return Number(pid) === term.pid && basename(name.join(" ")).replace(/^-/, "") !== basename(shell);
|
|
246
|
+
});
|
|
233
247
|
},
|
|
234
248
|
kill(signal) {
|
|
235
249
|
try {
|
|
@@ -238,33 +252,6 @@ async function terminal(command, options, log, finish) {
|
|
|
238
252
|
}
|
|
239
253
|
};
|
|
240
254
|
}
|
|
241
|
-
function lastMarker(text) {
|
|
242
|
-
return Array.from(text.matchAll(PROMPT_MARKER), (match) => match[1]).at(-1) ?? null;
|
|
243
|
-
}
|
|
244
|
-
function withoutEscapes(text) {
|
|
245
|
-
let plain = "";
|
|
246
|
-
let at = 0;
|
|
247
|
-
while (at < text.length) {
|
|
248
|
-
const char = text[at] ?? "";
|
|
249
|
-
if (char !== ESC) {
|
|
250
|
-
plain += char;
|
|
251
|
-
at += 1;
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
const kind = text[at + 1] ?? "";
|
|
255
|
-
at += 2;
|
|
256
|
-
if (kind === "[") {
|
|
257
|
-
while (at < text.length && !/[@-~]/.test(text[at] ?? ""))
|
|
258
|
-
at += 1;
|
|
259
|
-
at += 1;
|
|
260
|
-
} else if (kind === "]") {
|
|
261
|
-
while (at < text.length && text[at] !== BEL && !(text[at] === ESC && text[at + 1] === "\\"))
|
|
262
|
-
at += 1;
|
|
263
|
-
at += text[at] === BEL ? 1 : 2;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
return plain;
|
|
267
|
-
}
|
|
268
255
|
function loadPty() {
|
|
269
256
|
if (loaded === undefined)
|
|
270
257
|
loaded = ptyFrom(() => createRequire(import.meta.url)("@lydell/node-pty"));
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {
|
|
2
|
+
photonImages2
|
|
3
|
+
} from "./canvas-preview-ec2mt7es.js";
|
|
4
|
+
|
|
5
|
+
// src/images/node.ts
|
|
6
|
+
import { readFile } from "node:fs/promises";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { Worker } from "node:worker_threads";
|
|
9
|
+
import { Type } from "typebox";
|
|
10
|
+
import { Value } from "typebox/value";
|
|
11
|
+
var size = Type.Object({ width: Type.Number(), height: Type.Number() });
|
|
12
|
+
var prepareReply2 = Type.Union([
|
|
13
|
+
Type.Object({ id: Type.Integer(), result: Type.Null() }),
|
|
14
|
+
Type.Object({
|
|
15
|
+
id: Type.Integer(),
|
|
16
|
+
result: Type.Object({
|
|
17
|
+
data: Type.String(),
|
|
18
|
+
mimeType: Type.String(),
|
|
19
|
+
resized: Type.Optional(Type.Object({ from: size, to: size }))
|
|
20
|
+
})
|
|
21
|
+
}),
|
|
22
|
+
Type.Object({ id: Type.Integer(), error: Type.String() })
|
|
23
|
+
]);
|
|
24
|
+
var IDLE_MS = 30000;
|
|
25
|
+
function nodeImages2(options = {}) {
|
|
26
|
+
const worker = options.worker ?? new URL(import.meta.url.endsWith(".ts") ? "./worker.ts" : "./worker.js", import.meta.url);
|
|
27
|
+
let wasm;
|
|
28
|
+
const loadWasm = () => wasm ??= readFile(options.wasm ?? resolvePhotonWasmPath2());
|
|
29
|
+
let thread;
|
|
30
|
+
let inProcess;
|
|
31
|
+
return {
|
|
32
|
+
async prepare(bytes, mimeType, limits) {
|
|
33
|
+
if (inProcess !== undefined)
|
|
34
|
+
return inProcess.prepare(bytes, mimeType, limits);
|
|
35
|
+
const module = await loadWasm();
|
|
36
|
+
try {
|
|
37
|
+
thread ??= new PhotonThread(worker, module, (ended) => {
|
|
38
|
+
if (thread === ended)
|
|
39
|
+
thread = undefined;
|
|
40
|
+
});
|
|
41
|
+
return await thread.prepare(bytes, mimeType, limits);
|
|
42
|
+
} catch (cause) {
|
|
43
|
+
if (!(cause instanceof WorkerUnavailable))
|
|
44
|
+
throw cause;
|
|
45
|
+
inProcess ??= photonImages2(module);
|
|
46
|
+
return inProcess.prepare(bytes, mimeType, limits);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function resolvePhotonWasmPath2() {
|
|
52
|
+
return fileURLToPath(import.meta.resolve("@silvia-odwyer/photon/photon_rs_bg.wasm"));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class WorkerUnavailable extends Error {
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class PhotonThread {
|
|
59
|
+
#worker;
|
|
60
|
+
#pending = new Map;
|
|
61
|
+
#onExit;
|
|
62
|
+
#nextId = 0;
|
|
63
|
+
#idle;
|
|
64
|
+
#started = false;
|
|
65
|
+
constructor(entry, wasm, onExit) {
|
|
66
|
+
this.#onExit = onExit;
|
|
67
|
+
try {
|
|
68
|
+
this.#worker = new Worker(entry, { workerData: wasm });
|
|
69
|
+
} catch (cause) {
|
|
70
|
+
throw new WorkerUnavailable("The image worker cannot start", { cause });
|
|
71
|
+
}
|
|
72
|
+
this.#worker.on("message", (reply) => {
|
|
73
|
+
if (!Value.Check(prepareReply2, reply)) {
|
|
74
|
+
this.#fail(new Error("Malformed image worker reply"));
|
|
75
|
+
this.#worker.terminate();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.#started = true;
|
|
79
|
+
const request = this.#pending.get(reply.id);
|
|
80
|
+
if (request === undefined)
|
|
81
|
+
return;
|
|
82
|
+
this.#pending.delete(reply.id);
|
|
83
|
+
if ("error" in reply)
|
|
84
|
+
request.reject(new Error(reply.error));
|
|
85
|
+
else
|
|
86
|
+
request.resolve(reply.result ?? undefined);
|
|
87
|
+
this.#settled();
|
|
88
|
+
});
|
|
89
|
+
this.#worker.on("error", (cause) => this.#fail(cause));
|
|
90
|
+
this.#worker.on("exit", (code) => this.#fail(new Error(`The image worker exited with code ${String(code)}`)));
|
|
91
|
+
}
|
|
92
|
+
prepare(bytes, mimeType, limits) {
|
|
93
|
+
const id = this.#nextId++;
|
|
94
|
+
const request = Promise.withResolvers();
|
|
95
|
+
this.#pending.set(id, request);
|
|
96
|
+
clearTimeout(this.#idle);
|
|
97
|
+
this.#idle = undefined;
|
|
98
|
+
this.#worker.ref();
|
|
99
|
+
const copy = bytes.slice();
|
|
100
|
+
this.#worker.postMessage({ id, bytes: copy, mimeType, limits }, [
|
|
101
|
+
copy.buffer
|
|
102
|
+
]);
|
|
103
|
+
return request.promise;
|
|
104
|
+
}
|
|
105
|
+
#settled() {
|
|
106
|
+
if (this.#pending.size > 0)
|
|
107
|
+
return;
|
|
108
|
+
this.#worker.unref();
|
|
109
|
+
this.#idle = setTimeout(() => {
|
|
110
|
+
this.#onExit(this);
|
|
111
|
+
this.#worker.terminate();
|
|
112
|
+
}, IDLE_MS);
|
|
113
|
+
this.#idle.unref();
|
|
114
|
+
}
|
|
115
|
+
#fail(cause) {
|
|
116
|
+
const failure = this.#started ? cause : new WorkerUnavailable("The image worker cannot start", { cause });
|
|
117
|
+
for (const request of this.#pending.values())
|
|
118
|
+
request.reject(failure);
|
|
119
|
+
this.#pending.clear();
|
|
120
|
+
clearTimeout(this.#idle);
|
|
121
|
+
this.#onExit(this);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export { prepareReply2, nodeImages2, resolvePhotonWasmPath2 };
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
killTree2
|
|
3
|
+
} from "../chunks/canvas-preview-bxnqt8cd.js";
|
|
4
|
+
|
|
1
5
|
// src/canvas-preview.ts
|
|
2
6
|
import { spawn } from "node:child_process";
|
|
3
7
|
import { existsSync, readdirSync } from "node:fs";
|
|
@@ -192,12 +196,12 @@ function stop(child) {
|
|
|
192
196
|
if (child.exitCode !== null || child.signalCode !== null)
|
|
193
197
|
return Promise.resolve();
|
|
194
198
|
return new Promise((resolve) => {
|
|
195
|
-
const kill = setTimeout(() => child
|
|
199
|
+
const kill = setTimeout(() => killTree2(child, "SIGKILL"), 2000);
|
|
196
200
|
child.once("exit", () => {
|
|
197
201
|
clearTimeout(kill);
|
|
198
202
|
resolve();
|
|
199
203
|
});
|
|
200
|
-
child
|
|
204
|
+
killTree2(child, "SIGTERM");
|
|
201
205
|
});
|
|
202
206
|
}
|
|
203
207
|
function chromiumCanvasPreview(shell, executable = findChromium) {
|
|
@@ -257,7 +261,7 @@ function chromiumCanvasPreview(shell, executable = findChromium) {
|
|
|
257
261
|
}
|
|
258
262
|
} finally {
|
|
259
263
|
await stop(child);
|
|
260
|
-
await rm(profile, { recursive: true, force: true });
|
|
264
|
+
await rm(profile, { recursive: true, force: true, maxRetries: 10 });
|
|
261
265
|
}
|
|
262
266
|
};
|
|
263
267
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import"../../../../../chunks/canvas-preview-2zdyh9ny.js";
|
|
2
2
|
import {
|
|
3
3
|
vercelHost2
|
|
4
|
-
} from "../../../../../chunks/canvas-preview-
|
|
4
|
+
} from "../../../../../chunks/canvas-preview-n2a35zv5.js";
|
|
5
5
|
import"../../../../../chunks/canvas-preview-65xqjw7f.js";
|
|
6
6
|
import {
|
|
7
7
|
dispatchHead2
|
|
8
|
-
} from "../../../../../chunks/canvas-preview-
|
|
8
|
+
} from "../../../../../chunks/canvas-preview-b2v8wfnz.js";
|
|
9
9
|
|
|
10
10
|
// src/deploy/vercel/server/routes/[...].ts
|
|
11
11
|
import { defineHandler } from "nitro/h3";
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
dispatchHead2,
|
|
3
3
|
driveHead2,
|
|
4
4
|
advanceHead2
|
|
5
|
-
} from "../../../../../chunks/canvas-preview-
|
|
6
|
-
import"../../../../../chunks/canvas-preview-
|
|
7
|
-
import"../../../../../chunks/canvas-preview-ewgspmsd.js";
|
|
5
|
+
} from "../../../../../chunks/canvas-preview-b2v8wfnz.js";
|
|
6
|
+
import"../../../../../chunks/canvas-preview-n2a35zv5.js";
|
|
8
7
|
import"../../../../../chunks/canvas-preview-2zdyh9ny.js";
|
|
8
|
+
import"../../../../../chunks/canvas-preview-65xqjw7f.js";
|
|
9
9
|
export {
|
|
10
10
|
advanceHead2 as advanceHead,
|
|
11
11
|
dispatchHead2 as dispatchHead,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function exifOrientation(bytes: Uint8Array): number;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ImageLimits, ImageProcessor } from "@nyte-ai/core";
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
export interface NodeImagesOptions {
|
|
4
|
+
readonly worker?: string | URL;
|
|
5
|
+
readonly wasm?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface PrepareRequest {
|
|
8
|
+
readonly id: number;
|
|
9
|
+
readonly bytes: Uint8Array;
|
|
10
|
+
readonly mimeType: string;
|
|
11
|
+
readonly limits: ImageLimits;
|
|
12
|
+
}
|
|
13
|
+
export declare const prepareReply: Type.TUnion<[Type.TObject<{
|
|
14
|
+
id: Type.TInteger;
|
|
15
|
+
result: Type.TNull;
|
|
16
|
+
}>, Type.TObject<{
|
|
17
|
+
id: Type.TInteger;
|
|
18
|
+
result: Type.TObject<{
|
|
19
|
+
data: Type.TString;
|
|
20
|
+
mimeType: Type.TString;
|
|
21
|
+
resized: Type.TOptional<Type.TObject<{
|
|
22
|
+
from: Type.TObject<{
|
|
23
|
+
width: Type.TNumber;
|
|
24
|
+
height: Type.TNumber;
|
|
25
|
+
}>;
|
|
26
|
+
to: Type.TObject<{
|
|
27
|
+
width: Type.TNumber;
|
|
28
|
+
height: Type.TNumber;
|
|
29
|
+
}>;
|
|
30
|
+
}>>;
|
|
31
|
+
}>;
|
|
32
|
+
}>, Type.TObject<{
|
|
33
|
+
id: Type.TInteger;
|
|
34
|
+
error: Type.TString;
|
|
35
|
+
}>]>;
|
|
36
|
+
export declare function nodeImages(options?: NodeImagesOptions): ImageProcessor;
|
|
37
|
+
export declare function resolvePhotonWasmPath(): string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
prepareReply2,
|
|
3
|
+
nodeImages2,
|
|
4
|
+
resolvePhotonWasmPath2
|
|
5
|
+
} from "../../chunks/canvas-preview-y5y6ghaw.js";
|
|
6
|
+
import"../../chunks/canvas-preview-ec2mt7es.js";
|
|
7
|
+
import"../../chunks/canvas-preview-befkjea2.js";
|
|
8
|
+
export {
|
|
9
|
+
nodeImages2 as nodeImages,
|
|
10
|
+
prepareReply2 as prepareReply,
|
|
11
|
+
resolvePhotonWasmPath2 as resolvePhotonWasmPath
|
|
12
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import"../../chunks/canvas-preview-befkjea2.js";
|
|
2
|
+
import {
|
|
3
|
+
photonImages2
|
|
4
|
+
} from "../../chunks/canvas-preview-ec2mt7es.js";
|
|
5
|
+
|
|
6
|
+
// src/images/worker.ts
|
|
7
|
+
import { parentPort, workerData } from "node:worker_threads";
|
|
8
|
+
var port = parentPort;
|
|
9
|
+
if (port === null)
|
|
10
|
+
throw new Error("The image worker needs a parent thread");
|
|
11
|
+
var wasm = workerData;
|
|
12
|
+
if (!(wasm instanceof Uint8Array))
|
|
13
|
+
throw new Error("The image worker needs Photon's WebAssembly");
|
|
14
|
+
var images = photonImages2(wasm);
|
|
15
|
+
port.on("message", (request) => {
|
|
16
|
+
images.prepare(request.bytes, request.mimeType, request.limits).then((result) => port.postMessage({
|
|
17
|
+
id: request.id,
|
|
18
|
+
result: result ?? null
|
|
19
|
+
}), (cause) => port.postMessage({
|
|
20
|
+
id: request.id,
|
|
21
|
+
error: cause instanceof Error ? cause.message : String(cause)
|
|
22
|
+
}));
|
|
23
|
+
});
|
package/dist/src/index.d.ts
CHANGED