@nyte-ai/host 0.0.0-stage → 0.0.18
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 +6 -2
- package/THIRD-PARTY-NOTICES.md +800 -0
- package/dist/chunks/canvas-preview-0cmbkp2j.js +65 -0
- package/dist/chunks/canvas-preview-0nq75h9k.js +7 -0
- package/dist/chunks/canvas-preview-0nrnbt76.js +497 -0
- package/dist/chunks/canvas-preview-1sq7z9jq.js +17 -0
- package/dist/chunks/canvas-preview-1ta3avah.js +56 -0
- package/dist/chunks/canvas-preview-2zdyh9ny.js +26 -0
- package/dist/chunks/canvas-preview-31w7xm8z.js +34 -0
- package/dist/chunks/canvas-preview-4b6sayhg.js +295 -0
- package/dist/chunks/canvas-preview-4e0pxa32.js +63 -0
- package/dist/chunks/canvas-preview-518dh8by.js +169 -0
- package/dist/chunks/canvas-preview-5hxat7hh.js +239 -0
- package/dist/chunks/canvas-preview-5mex725c.js +14 -0
- package/dist/chunks/canvas-preview-5z63am63.js +295 -0
- package/dist/chunks/canvas-preview-65xqjw7f.js +20 -0
- package/dist/chunks/canvas-preview-69fkk9yn.js +95 -0
- package/dist/chunks/canvas-preview-75db60xy.js +457 -0
- package/dist/chunks/canvas-preview-76fwvd6e.js +272 -0
- package/dist/chunks/canvas-preview-8xgt67ka.js +598 -0
- package/dist/chunks/canvas-preview-98aj5p34.js +176 -0
- package/dist/chunks/canvas-preview-9aqczacs.js +73 -0
- package/dist/chunks/canvas-preview-a3yw0j70.js +72 -0
- package/dist/chunks/canvas-preview-azg56359.js +68 -0
- package/dist/chunks/canvas-preview-d9wwhbtz.js +240 -0
- package/dist/chunks/canvas-preview-ehf3vp31.js +411 -0
- package/dist/chunks/canvas-preview-evh92ywd.js +369 -0
- package/dist/chunks/canvas-preview-ewgspmsd.js +81 -0
- package/dist/chunks/canvas-preview-g3qj3y3k.js +156 -0
- package/dist/chunks/canvas-preview-h8hshnff.js +63 -0
- package/dist/chunks/canvas-preview-j1tnf51w.js +36 -0
- package/dist/chunks/canvas-preview-kdqgrstc.js +194 -0
- package/dist/chunks/canvas-preview-kn7kvbfj.js +12 -0
- package/dist/chunks/canvas-preview-m02v4yy6.js +386 -0
- package/dist/chunks/canvas-preview-mgcx2b2p.js +271 -0
- package/dist/chunks/canvas-preview-rp4x6y1h.js +144 -0
- package/dist/chunks/canvas-preview-rp6fz0w5.js +130 -0
- package/dist/chunks/canvas-preview-s94ebwf5.js +112 -0
- package/dist/chunks/canvas-preview-senpjwep.js +518 -0
- package/dist/chunks/canvas-preview-skzwvw4d.js +23 -0
- package/dist/chunks/canvas-preview-srgfpdmf.js +60 -0
- package/dist/chunks/canvas-preview-tjhabynd.js +252 -0
- package/dist/chunks/canvas-preview-vaatfznm.js +189 -0
- package/dist/chunks/canvas-preview-vax9ne4e.js +341 -0
- package/dist/chunks/canvas-preview-wg80rbc2.js +46 -0
- package/dist/chunks/canvas-preview-xn10d4f8.js +608 -0
- package/dist/chunks/canvas-preview-yjz0f7n4.js +50 -0
- package/dist/chunks/canvas-preview-ymgz0937.js +587 -0
- package/dist/chunks/canvas-preview-yrfz2ak6.js +134 -0
- package/dist/chunks/canvas-preview-zaaj99wd.js +244 -0
- package/dist/chunks/canvas-preview-zn2d0k9d.js +133 -0
- package/dist/src/canvas-preview.d.ts +29 -0
- package/dist/src/canvas-preview.js +267 -0
- package/dist/src/credentials.d.ts +44 -0
- package/dist/src/credentials.js +10 -0
- package/dist/src/deploy/cloudflare/worker.d.ts +50 -0
- package/dist/src/deploy/cloudflare/worker.js +196 -0
- package/dist/src/deploy/vercel/nitro.config.d.ts +2 -0
- package/dist/src/deploy/vercel/nitro.config.js +30 -0
- package/dist/src/deploy/vercel/server/routes/[...].d.ts +2 -0
- package/dist/src/deploy/vercel/server/routes/[...].js +18 -0
- package/dist/src/deploy/vercel/server/utils/host.d.ts +13 -0
- package/dist/src/deploy/vercel/server/utils/host.js +7 -0
- package/dist/src/deploy/vercel/server/utils/repair.d.ts +1 -0
- package/dist/src/deploy/vercel/server/utils/repair.js +6 -0
- package/dist/src/deploy/vercel/server/utils/step.d.ts +10 -0
- package/dist/src/deploy/vercel/server/utils/step.js +6 -0
- package/dist/src/deploy/vercel/server/workflows/drive.d.ts +14 -0
- package/dist/src/deploy/vercel/server/workflows/drive.js +13 -0
- package/dist/src/durable-object.d.ts +14 -0
- package/dist/src/durable-object.js +231 -0
- package/dist/src/hash.d.ts +1 -0
- package/dist/src/hash.js +6 -0
- package/dist/src/identity-key.d.ts +11 -0
- package/dist/src/identity-key.js +9 -0
- package/dist/src/identity.d.ts +12 -0
- package/dist/src/identity.js +6 -0
- package/dist/src/index.d.ts +21 -0
- package/dist/src/index.js +120 -0
- package/dist/src/key-file.d.ts +1 -0
- package/dist/src/key-file.js +7 -0
- package/dist/src/listen-fetch.d.ts +8 -0
- package/dist/src/listen-fetch.js +9 -0
- package/dist/src/listen.d.ts +4 -0
- package/dist/src/listen.js +10 -0
- package/dist/src/local/command.d.ts +15 -0
- package/dist/src/local/command.js +8 -0
- package/dist/src/local/feed.d.ts +7 -0
- package/dist/src/local/feed.js +6 -0
- package/dist/src/local/files.d.ts +18 -0
- package/dist/src/local/files.js +13 -0
- package/dist/src/local/git-watch.d.ts +15 -0
- package/dist/src/local/git-watch.js +7 -0
- package/dist/src/local/git.d.ts +5 -0
- package/dist/src/local/git.js +13 -0
- package/dist/src/local/github.d.ts +30 -0
- package/dist/src/local/github.js +9 -0
- package/dist/src/local/identity.d.ts +3 -0
- package/dist/src/local/identity.js +7 -0
- package/dist/src/local/jobs.d.ts +7 -0
- package/dist/src/local/jobs.js +6 -0
- package/dist/src/local/legacy-trust.d.ts +10 -0
- package/dist/src/local/legacy-trust.js +6 -0
- package/dist/src/local/patch.d.ts +16 -0
- package/dist/src/local/patch.js +17 -0
- package/dist/src/local/provider.d.ts +11 -0
- package/dist/src/local/provider.js +20 -0
- package/dist/src/local/snapshots.d.ts +7 -0
- package/dist/src/local/snapshots.js +11 -0
- package/dist/src/local/text.d.ts +1 -0
- package/dist/src/local/text.js +6 -0
- package/dist/src/local/tree.d.ts +50 -0
- package/dist/src/local/tree.js +16 -0
- package/dist/src/local/workspace-migration.d.ts +2 -0
- package/dist/src/local/workspace-migration.js +7 -0
- package/dist/src/local/worktrees.d.ts +46 -0
- package/dist/src/local/worktrees.js +14 -0
- package/dist/src/mcp/config.d.ts +75 -0
- package/dist/src/mcp/config.js +12 -0
- package/dist/src/mcp/connect.d.ts +28 -0
- package/dist/src/mcp/connect.js +9 -0
- package/dist/src/mcp/hub.d.ts +19 -0
- package/dist/src/mcp/hub.js +11 -0
- package/dist/src/mcp/oauth.d.ts +46 -0
- package/dist/src/mcp/oauth.js +12 -0
- package/dist/src/mcp/tools.d.ts +29 -0
- package/dist/src/mcp/tools.js +12 -0
- package/dist/src/open.d.ts +42 -0
- package/dist/src/open.js +44 -0
- package/dist/src/plugins/loader.d.ts +21 -0
- package/dist/src/plugins/loader.js +11 -0
- package/dist/src/postgres.d.ts +19 -0
- package/dist/src/postgres.js +8 -0
- package/dist/src/providers.d.ts +16 -0
- package/dist/src/providers.js +112 -0
- package/dist/src/secrets.d.ts +12 -0
- package/dist/src/secrets.js +8 -0
- package/dist/src/serve/binding.d.ts +39 -0
- package/dist/src/serve/binding.js +6 -0
- package/dist/src/serve/handler.d.ts +15 -0
- package/dist/src/serve/handler.js +8 -0
- package/dist/src/serve/stream-server.d.ts +6 -0
- package/dist/src/serve/stream-server.js +6 -0
- package/dist/src/session-index.d.ts +11 -0
- package/dist/src/session-index.js +11 -0
- package/dist/src/shell-env.d.ts +14 -0
- package/dist/src/shell-env.js +108 -0
- package/dist/src/sqlite-workers.d.ts +6 -0
- package/dist/src/sqlite-workers.js +6 -0
- package/dist/src/sqlite.d.ts +7 -0
- package/dist/src/sqlite.js +10 -0
- package/dist/src/store-owner.d.ts +15 -0
- package/dist/src/store-owner.js +9 -0
- package/dist/src/store-rows.d.ts +13 -0
- package/dist/src/store-rows.js +26 -0
- package/dist/src/store-usage.d.ts +25 -0
- package/dist/src/store-usage.js +16 -0
- package/dist/src/usage-scan.d.ts +24 -0
- package/dist/src/usage-scan.js +65 -0
- package/dist/src/usage-service.d.ts +22 -0
- package/dist/src/usage-service.js +12 -0
- package/dist/src/usage-summary.d.ts +9 -0
- package/dist/src/usage-summary.js +16 -0
- package/dist/src/usage-types.d.ts +86 -0
- package/dist/src/usage-types.js +0 -0
- package/dist/src/usage-worker.d.ts +1 -0
- package/dist/src/usage-worker.js +25 -0
- package/dist/src/usage.d.ts +72 -0
- package/dist/src/usage.js +13 -0
- package/package.json +132 -3
- package/src/canvas-preview.ts +402 -0
- package/src/credentials.ts +294 -0
- package/src/deploy/cloudflare/README.md +3 -0
- package/src/deploy/cloudflare/worker.ts +306 -0
- package/src/deploy/cloudflare/wrangler.jsonc +12 -0
- package/src/deploy/vercel/README.md +3 -0
- package/src/deploy/vercel/nitro.config.ts +29 -0
- package/src/deploy/vercel/server/routes/[...].ts +10 -0
- package/src/deploy/vercel/server/utils/host.ts +104 -0
- package/src/deploy/vercel/server/utils/repair.ts +35 -0
- package/src/deploy/vercel/server/utils/step.ts +25 -0
- package/src/deploy/vercel/server/workflows/drive.ts +46 -0
- package/src/deploy/vercel/tsconfig.json +9 -0
- package/src/deploy/vercel/types/bun.d.ts +2 -0
- package/src/durable-object.ts +386 -0
- package/src/hash.ts +5 -0
- package/src/identity-key.ts +20 -0
- package/src/identity.ts +66 -0
- package/src/index.ts +21 -0
- package/src/key-file.ts +53 -0
- package/src/listen-fetch.ts +409 -0
- package/src/listen.ts +228 -0
- package/src/local/command.ts +109 -0
- package/src/local/feed.ts +70 -0
- package/src/local/files.ts +812 -0
- package/src/local/git-watch.ts +189 -0
- package/src/local/git.ts +914 -0
- package/src/local/github.ts +692 -0
- package/src/local/identity.ts +21 -0
- package/src/local/jobs.ts +587 -0
- package/src/local/legacy-trust.ts +105 -0
- package/src/local/patch.ts +334 -0
- package/src/local/provider.ts +184 -0
- package/src/local/snapshots.ts +776 -0
- package/src/local/text.ts +9 -0
- package/src/local/tree.ts +398 -0
- package/src/local/workspace-migration.ts +95 -0
- package/src/local/worktrees.ts +239 -0
- package/src/mcp/config.ts +330 -0
- package/src/mcp/connect.ts +105 -0
- package/src/mcp/hub.ts +836 -0
- package/src/mcp/oauth.ts +436 -0
- package/src/mcp/tools.ts +333 -0
- package/src/open.ts +469 -0
- package/src/plugins/loader.ts +186 -0
- package/src/postgres.ts +492 -0
- package/src/providers.ts +135 -0
- package/src/secrets.ts +31 -0
- package/src/serve/binding.ts +628 -0
- package/src/serve/handler.ts +362 -0
- package/src/serve/stream-server.ts +176 -0
- package/src/session-index.ts +99 -0
- package/src/shell-env.ts +153 -0
- package/src/sqlite-workers.ts +283 -0
- package/src/sqlite.ts +528 -0
- package/src/store-owner.ts +98 -0
- package/src/store-rows.ts +110 -0
- package/src/store-usage.ts +344 -0
- package/src/usage-scan.ts +81 -0
- package/src/usage-service.ts +73 -0
- package/src/usage-summary.ts +79 -0
- package/src/usage-types.ts +87 -0
- package/src/usage-worker.ts +24 -0
- package/src/usage.ts +701 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
// src/local/tree.ts
|
|
2
|
+
import { watch } from "node:fs";
|
|
3
|
+
import { lstat, readFile, readdir } from "node:fs/promises";
|
|
4
|
+
import { basename, dirname, join, sep } from "node:path";
|
|
5
|
+
import ignore from "ignore";
|
|
6
|
+
var WALK_LIMIT2 = 50000;
|
|
7
|
+
var WALK_PAGE = 500;
|
|
8
|
+
function createIgnores2(root) {
|
|
9
|
+
const rules = new Map;
|
|
10
|
+
const loadRules = (directory) => {
|
|
11
|
+
const known = rules.get(directory);
|
|
12
|
+
if (known !== undefined)
|
|
13
|
+
return known;
|
|
14
|
+
const sources = [join(root, directory, ".gitignore")];
|
|
15
|
+
if (directory === "")
|
|
16
|
+
sources.push(join(root, ".git", "info", "exclude"));
|
|
17
|
+
const loaded = Promise.all(sources.map((source) => readFile(source, "utf8").catch(() => null))).then((texts) => {
|
|
18
|
+
const found = texts.filter((text) => text !== null);
|
|
19
|
+
return found.length === 0 ? null : found.reduce((matcher, text) => matcher.add(text), ignore());
|
|
20
|
+
});
|
|
21
|
+
rules.set(directory, loaded);
|
|
22
|
+
return loaded;
|
|
23
|
+
};
|
|
24
|
+
const matches = async (path, directory) => {
|
|
25
|
+
const segments = path.split("/");
|
|
26
|
+
if (segments.includes(".git"))
|
|
27
|
+
return true;
|
|
28
|
+
let result = false;
|
|
29
|
+
for (let depth = 0;depth < segments.length; depth += 1) {
|
|
30
|
+
const matcher = await loadRules(segments.slice(0, depth).join("/"));
|
|
31
|
+
if (matcher === null)
|
|
32
|
+
continue;
|
|
33
|
+
const relative = segments.slice(depth).join("/") + (directory ? "/" : "");
|
|
34
|
+
if (!ignore.isPathValid(relative.replace(/\/$/, "")))
|
|
35
|
+
continue;
|
|
36
|
+
const test = matcher.test(relative);
|
|
37
|
+
if (test.ignored)
|
|
38
|
+
result = true;
|
|
39
|
+
else if (test.unignored)
|
|
40
|
+
result = false;
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
matches,
|
|
46
|
+
async ignored(path, directory) {
|
|
47
|
+
const segments = path.split("/");
|
|
48
|
+
for (let depth = 1;depth < segments.length; depth += 1)
|
|
49
|
+
if (await matches(segments.slice(0, depth).join("/"), true))
|
|
50
|
+
return true;
|
|
51
|
+
return matches(path, directory);
|
|
52
|
+
},
|
|
53
|
+
forget(directory) {
|
|
54
|
+
rules.delete(directory);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async function* walkTree2(root, options) {
|
|
59
|
+
const ignores = options.ignores ?? createIgnores2(root);
|
|
60
|
+
const limit = options.limit ?? WALK_LIMIT2;
|
|
61
|
+
const size = options.page ?? WALK_PAGE;
|
|
62
|
+
const queue = [trimSlashes(options.directory ?? "")];
|
|
63
|
+
let page = [];
|
|
64
|
+
let count = 0;
|
|
65
|
+
let denied = false;
|
|
66
|
+
for (let next = queue.shift();next !== undefined; next = queue.shift()) {
|
|
67
|
+
const directory = next;
|
|
68
|
+
const listed = await readdir(join(root, directory), { withFileTypes: true }).catch((error) => {
|
|
69
|
+
if (readErrorCode2(error) === "EACCES" || readErrorCode2(error) === "EPERM")
|
|
70
|
+
denied = true;
|
|
71
|
+
return null;
|
|
72
|
+
});
|
|
73
|
+
if (listed === null)
|
|
74
|
+
continue;
|
|
75
|
+
listed.sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
|
|
76
|
+
const entries = await Promise.all(listed.map(async (dirent) => {
|
|
77
|
+
const path = directory === "" ? dirent.name : `${directory}/${dirent.name}`;
|
|
78
|
+
const kind = dirent.isSymbolicLink() ? "symlink" : dirent.isDirectory() ? "directory" : dirent.isFile() ? "file" : null;
|
|
79
|
+
if (kind === null || dirent.name === ".git")
|
|
80
|
+
return null;
|
|
81
|
+
if (options.ignored === "exclude" && await ignores.matches(path, kind === "directory"))
|
|
82
|
+
return null;
|
|
83
|
+
if (kind === "directory")
|
|
84
|
+
return { path, kind, size: null };
|
|
85
|
+
const stats = await lstat(join(root, path)).catch(() => null);
|
|
86
|
+
return stats === null ? null : { path, kind, size: stats.size };
|
|
87
|
+
}));
|
|
88
|
+
for (const entry of entries) {
|
|
89
|
+
if (entry === null)
|
|
90
|
+
continue;
|
|
91
|
+
page.push(entry);
|
|
92
|
+
count += 1;
|
|
93
|
+
if (entry.kind === "directory")
|
|
94
|
+
queue.push(entry.path);
|
|
95
|
+
if (count >= limit) {
|
|
96
|
+
yield { kind: "entries", entries: page };
|
|
97
|
+
yield { kind: "incomplete", reason: "limit" };
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (page.length >= size) {
|
|
101
|
+
yield { kind: "entries", entries: page };
|
|
102
|
+
page = [];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (page.length > 0)
|
|
107
|
+
yield { kind: "entries", entries: page };
|
|
108
|
+
yield denied ? { kind: "incomplete", reason: "permission" } : { kind: "complete" };
|
|
109
|
+
}
|
|
110
|
+
function watchTree2(root, options, changed) {
|
|
111
|
+
let pending = new Set;
|
|
112
|
+
let timer = null;
|
|
113
|
+
let polling = null;
|
|
114
|
+
let watcher = null;
|
|
115
|
+
let fellBack = false;
|
|
116
|
+
let stopped = false;
|
|
117
|
+
const flush = () => {
|
|
118
|
+
timer = null;
|
|
119
|
+
const paths = pending;
|
|
120
|
+
pending = new Set;
|
|
121
|
+
if (!stopped && paths.size > 0)
|
|
122
|
+
changed(paths);
|
|
123
|
+
};
|
|
124
|
+
const note = (path) => {
|
|
125
|
+
pending.add(path);
|
|
126
|
+
timer ??= setTimeout(flush, options.delay);
|
|
127
|
+
};
|
|
128
|
+
const poll = (every) => {
|
|
129
|
+
let known = null;
|
|
130
|
+
const tick = async () => {
|
|
131
|
+
const seen = new Map;
|
|
132
|
+
for await (const frame of walkTree2(root, { ignored: "include" }))
|
|
133
|
+
if (frame.kind === "entries")
|
|
134
|
+
for (const entry of frame.entries) {
|
|
135
|
+
const stats = await lstat(join(root, entry.path)).catch(() => null);
|
|
136
|
+
seen.set(entry.path, stats === null ? "" : `${stats.size}:${stats.mtimeMs}`);
|
|
137
|
+
}
|
|
138
|
+
if (known !== null) {
|
|
139
|
+
for (const [path, stamp] of seen)
|
|
140
|
+
if (known.get(path) !== stamp)
|
|
141
|
+
note(path);
|
|
142
|
+
for (const path of known.keys())
|
|
143
|
+
if (!seen.has(path))
|
|
144
|
+
note(path);
|
|
145
|
+
}
|
|
146
|
+
known = seen;
|
|
147
|
+
};
|
|
148
|
+
const again = () => {
|
|
149
|
+
if (stopped)
|
|
150
|
+
return;
|
|
151
|
+
polling = setTimeout(() => {
|
|
152
|
+
tick().then(again, again);
|
|
153
|
+
}, every);
|
|
154
|
+
};
|
|
155
|
+
tick().then(again, again);
|
|
156
|
+
};
|
|
157
|
+
const fallback = () => {
|
|
158
|
+
watcher?.close();
|
|
159
|
+
watcher = null;
|
|
160
|
+
if (stopped || fellBack)
|
|
161
|
+
return;
|
|
162
|
+
fellBack = true;
|
|
163
|
+
options.unwatched?.();
|
|
164
|
+
if (options.poll !== null)
|
|
165
|
+
poll(options.poll);
|
|
166
|
+
};
|
|
167
|
+
try {
|
|
168
|
+
watcher = watch(root, { recursive: true }, (_event, filename) => note(filename === null ? "" : filename.split(sep).join("/")));
|
|
169
|
+
watcher.on("error", fallback);
|
|
170
|
+
} catch {
|
|
171
|
+
fallback();
|
|
172
|
+
}
|
|
173
|
+
return () => {
|
|
174
|
+
stopped = true;
|
|
175
|
+
watcher?.close();
|
|
176
|
+
if (timer !== null)
|
|
177
|
+
clearTimeout(timer);
|
|
178
|
+
if (polling !== null)
|
|
179
|
+
clearTimeout(polling);
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function watchPath2(target, options, changed) {
|
|
183
|
+
let pending = new Set;
|
|
184
|
+
let timer = null;
|
|
185
|
+
let watchers = [];
|
|
186
|
+
let generation = 0;
|
|
187
|
+
let moved = false;
|
|
188
|
+
let stopped = false;
|
|
189
|
+
const flush = () => {
|
|
190
|
+
timer = null;
|
|
191
|
+
const paths = pending;
|
|
192
|
+
pending = new Set;
|
|
193
|
+
if (stopped)
|
|
194
|
+
return;
|
|
195
|
+
if (moved) {
|
|
196
|
+
moved = false;
|
|
197
|
+
arm();
|
|
198
|
+
}
|
|
199
|
+
if (paths.size > 0)
|
|
200
|
+
changed(paths);
|
|
201
|
+
};
|
|
202
|
+
const note = (path, replaced) => {
|
|
203
|
+
pending.add(path);
|
|
204
|
+
moved ||= replaced;
|
|
205
|
+
timer ??= setTimeout(flush, options.delay);
|
|
206
|
+
};
|
|
207
|
+
const listen = (at, recursive, heard) => {
|
|
208
|
+
try {
|
|
209
|
+
const watcher = watch(at, { recursive, persistent: false }, (event, name) => heard(event, name === null ? null : name.split(sep).join("/")));
|
|
210
|
+
watcher.on("error", () => note("", true));
|
|
211
|
+
watchers.push(watcher);
|
|
212
|
+
} catch {}
|
|
213
|
+
};
|
|
214
|
+
const arm = async () => {
|
|
215
|
+
generation += 1;
|
|
216
|
+
const armed = generation;
|
|
217
|
+
for (const watcher of watchers)
|
|
218
|
+
watcher.close();
|
|
219
|
+
watchers = [];
|
|
220
|
+
let existing = target;
|
|
221
|
+
let missing = null;
|
|
222
|
+
let stats = await lstat(existing).catch(() => null);
|
|
223
|
+
while (stats === null) {
|
|
224
|
+
const parent = dirname(existing);
|
|
225
|
+
if (parent === existing)
|
|
226
|
+
return;
|
|
227
|
+
missing = basename(existing);
|
|
228
|
+
existing = parent;
|
|
229
|
+
stats = await lstat(existing).catch(() => null);
|
|
230
|
+
}
|
|
231
|
+
if (stopped || armed !== generation)
|
|
232
|
+
return;
|
|
233
|
+
if (missing !== null) {
|
|
234
|
+
const awaited = missing;
|
|
235
|
+
if (stats.isDirectory())
|
|
236
|
+
listen(existing, false, (_event, name) => {
|
|
237
|
+
if (name === null || name === awaited)
|
|
238
|
+
note("", true);
|
|
239
|
+
});
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (!stats.isDirectory()) {
|
|
243
|
+
listen(target, false, (event) => note("", event === "rename"));
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const own = basename(target);
|
|
247
|
+
listen(target, true, (_event, name) => note(name ?? "", false));
|
|
248
|
+
listen(dirname(target), false, (event, name) => {
|
|
249
|
+
if (name === null || name === own)
|
|
250
|
+
note("", event === "rename");
|
|
251
|
+
});
|
|
252
|
+
};
|
|
253
|
+
arm();
|
|
254
|
+
return () => {
|
|
255
|
+
stopped = true;
|
|
256
|
+
generation += 1;
|
|
257
|
+
for (const watcher of watchers)
|
|
258
|
+
watcher.close();
|
|
259
|
+
watchers = [];
|
|
260
|
+
if (timer !== null)
|
|
261
|
+
clearTimeout(timer);
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function readErrorCode2(error) {
|
|
265
|
+
return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : null;
|
|
266
|
+
}
|
|
267
|
+
function trimSlashes(path) {
|
|
268
|
+
return path.replace(/\\/g, "/").replace(/^\.?\/+|\/+$/g, "").replace(/^\.$/, "");
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export { WALK_LIMIT2, createIgnores2, walkTree2, watchTree2, watchPath2, readErrorCode2 };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// src/serve/stream-server.ts
|
|
2
|
+
import { deflateSync } from "fflate";
|
|
3
|
+
import { SdkError } from "@nyte-ai/schema";
|
|
4
|
+
import { CHANNEL_HEADER, asSdkError, encodeError, streamBuffer } from "@nyte-ai/protocol";
|
|
5
|
+
var encoder = new TextEncoder;
|
|
6
|
+
var CHUNK_BYTES = 48 * 1024;
|
|
7
|
+
var DEFLATE_MIN_BYTES = 16 * 1024;
|
|
8
|
+
function createStreamChannels2() {
|
|
9
|
+
const channels = new Map;
|
|
10
|
+
const owned = (id, connection) => {
|
|
11
|
+
const channel = channels.get(id);
|
|
12
|
+
if (channel === undefined)
|
|
13
|
+
throw new SdkError("unavailable", "The stream channel is closed.");
|
|
14
|
+
if (channel.connection !== connection)
|
|
15
|
+
throw new SdkError("denied", "The stream channel belongs to another connection.");
|
|
16
|
+
return channel;
|
|
17
|
+
};
|
|
18
|
+
return {
|
|
19
|
+
open(connection, signal, deflate) {
|
|
20
|
+
const id = crypto.randomUUID();
|
|
21
|
+
const controller = new AbortController;
|
|
22
|
+
const streams = new Map;
|
|
23
|
+
let timer;
|
|
24
|
+
const finish = () => {
|
|
25
|
+
if (controller.signal.aborted)
|
|
26
|
+
return;
|
|
27
|
+
controller.abort();
|
|
28
|
+
channels.delete(id);
|
|
29
|
+
clearInterval(timer);
|
|
30
|
+
signal.removeEventListener("abort", aborted);
|
|
31
|
+
for (const stream of streams.values())
|
|
32
|
+
stream.abort();
|
|
33
|
+
streams.clear();
|
|
34
|
+
};
|
|
35
|
+
const buffer = streamBuffer(finish);
|
|
36
|
+
const fail = (error) => {
|
|
37
|
+
if (controller.signal.aborted)
|
|
38
|
+
return;
|
|
39
|
+
buffer.end(encoder.encode(`event: error
|
|
40
|
+
data: ${JSON.stringify(encodeError(error))}
|
|
41
|
+
|
|
42
|
+
`));
|
|
43
|
+
finish();
|
|
44
|
+
};
|
|
45
|
+
const aborted = () => {
|
|
46
|
+
fail(signal.reason instanceof SdkError ? signal.reason : new SdkError("unavailable", "The stream channel disconnected."));
|
|
47
|
+
};
|
|
48
|
+
channels.set(id, {
|
|
49
|
+
connection,
|
|
50
|
+
signal: controller.signal,
|
|
51
|
+
deflate,
|
|
52
|
+
streams,
|
|
53
|
+
push: (frame, signal) => buffer.write(encoder.encode(`data: ${JSON.stringify(frame)}
|
|
54
|
+
|
|
55
|
+
`), signal)
|
|
56
|
+
});
|
|
57
|
+
buffer.push(encoder.encode(`: connected
|
|
58
|
+
|
|
59
|
+
`));
|
|
60
|
+
timer = setInterval(() => {
|
|
61
|
+
buffer.push(encoder.encode(`: ping
|
|
62
|
+
|
|
63
|
+
`));
|
|
64
|
+
}, 15000);
|
|
65
|
+
if (signal.aborted)
|
|
66
|
+
aborted();
|
|
67
|
+
else
|
|
68
|
+
signal.addEventListener("abort", aborted, { once: true });
|
|
69
|
+
return new Response(buffer.body, {
|
|
70
|
+
headers: {
|
|
71
|
+
"Content-Type": "text/event-stream",
|
|
72
|
+
"Cache-Control": "no-cache",
|
|
73
|
+
[CHANNEL_HEADER]: id
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
async start(connection, channelId, streamId, request, serve) {
|
|
78
|
+
const channel = owned(channelId, connection);
|
|
79
|
+
if (channel.streams.has(streamId))
|
|
80
|
+
throw new SdkError("invalid", "The stream identifier is already in use.");
|
|
81
|
+
const controller = new AbortController;
|
|
82
|
+
channel.streams.set(streamId, controller);
|
|
83
|
+
const abortSetup = () => controller.abort(request.reason);
|
|
84
|
+
request.addEventListener("abort", abortSetup, { once: true });
|
|
85
|
+
const signal = AbortSignal.any([controller.signal, channel.signal]);
|
|
86
|
+
(async () => {
|
|
87
|
+
let reader;
|
|
88
|
+
const cancel = () => {
|
|
89
|
+
reader?.cancel().catch(() => {
|
|
90
|
+
return;
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
signal.addEventListener("abort", cancel, { once: true });
|
|
94
|
+
try {
|
|
95
|
+
if (request.aborted)
|
|
96
|
+
abortSetup();
|
|
97
|
+
signal.throwIfAborted();
|
|
98
|
+
const response = await serve(signal);
|
|
99
|
+
reader = response.body?.getReader();
|
|
100
|
+
request.removeEventListener("abort", abortSetup);
|
|
101
|
+
if (signal.aborted)
|
|
102
|
+
return;
|
|
103
|
+
if (reader !== undefined)
|
|
104
|
+
for (;; ) {
|
|
105
|
+
const next = await reader.read();
|
|
106
|
+
if (signal.aborted || next.done)
|
|
107
|
+
break;
|
|
108
|
+
for (let start = 0;start < next.value.byteLength; start += CHUNK_BYTES) {
|
|
109
|
+
if (signal.aborted)
|
|
110
|
+
break;
|
|
111
|
+
const chunk = next.value.subarray(start, start + CHUNK_BYTES);
|
|
112
|
+
await channel.push(channel.deflate && chunk.byteLength >= DEFLATE_MIN_BYTES ? {
|
|
113
|
+
kind: "deflated",
|
|
114
|
+
stream: streamId,
|
|
115
|
+
data: deflateSync(chunk, { level: 1 }).toBase64()
|
|
116
|
+
} : { kind: "chunk", stream: streamId, data: chunk.toBase64() }, signal);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!signal.aborted)
|
|
120
|
+
await channel.push({ kind: "end", stream: streamId }, signal);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (!signal.aborted)
|
|
123
|
+
await channel.push({
|
|
124
|
+
kind: "error",
|
|
125
|
+
stream: streamId,
|
|
126
|
+
error: JSON.stringify(encodeError(asSdkError(error)))
|
|
127
|
+
}, signal);
|
|
128
|
+
} finally {
|
|
129
|
+
request.removeEventListener("abort", abortSetup);
|
|
130
|
+
signal.removeEventListener("abort", cancel);
|
|
131
|
+
channel.streams.delete(streamId);
|
|
132
|
+
controller.abort();
|
|
133
|
+
cancel();
|
|
134
|
+
}
|
|
135
|
+
})();
|
|
136
|
+
return new Response(null, { status: 202 });
|
|
137
|
+
},
|
|
138
|
+
cancel(connection, channelId, streamId) {
|
|
139
|
+
owned(channelId, connection).streams.get(streamId)?.abort();
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export { createStreamChannels2 };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sha2562
|
|
3
|
+
} from "./canvas-preview-0nq75h9k.js";
|
|
4
|
+
import {
|
|
5
|
+
run2
|
|
6
|
+
} from "./canvas-preview-azg56359.js";
|
|
7
|
+
|
|
8
|
+
// src/local/worktrees.ts
|
|
9
|
+
import { randomUUID } from "node:crypto";
|
|
10
|
+
import { copyFile, mkdir, realpath, rm, stat } from "node:fs/promises";
|
|
11
|
+
import { homedir, tmpdir } from "node:os";
|
|
12
|
+
import { basename, dirname, join } from "node:path";
|
|
13
|
+
import { SdkError } from "@nyte-ai/schema";
|
|
14
|
+
var ENV = { GIT_TERMINAL_PROMPT: "0", LC_ALL: "C" };
|
|
15
|
+
function gitCommand(binary = "git") {
|
|
16
|
+
return async (cwd, args, env) => {
|
|
17
|
+
const ran = await run2(binary, ["-c", "core.quotepath=off", ...args], {
|
|
18
|
+
cwd,
|
|
19
|
+
env: { ...ENV, ...env }
|
|
20
|
+
});
|
|
21
|
+
if (ran.code !== 0)
|
|
22
|
+
throw new SdkError("unavailable", ran.stderr.trim() || `git ${args[0] ?? ""} failed.`);
|
|
23
|
+
return ran.stdout.toString("utf8");
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async function listWorktrees2(cwd, options) {
|
|
27
|
+
const out = await gitCommand(options?.git)(cwd, ["worktree", "list", "--porcelain", "-z"]);
|
|
28
|
+
return out.split("\x00\x00").flatMap((record) => {
|
|
29
|
+
const fields = record.split("\x00");
|
|
30
|
+
const path = fields.find((field) => field.startsWith("worktree "))?.slice(9);
|
|
31
|
+
const branch = fields.find((field) => field.startsWith("branch refs/heads/"))?.slice(18);
|
|
32
|
+
return path === undefined ? [] : [{ path, branch: branch ?? null }];
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async function addWorktree2(cwd, input, options) {
|
|
36
|
+
await gitCommand(options?.git)(cwd, input.from === undefined ? ["worktree", "add", input.path, input.branch] : ["worktree", "add", "-b", input.branch, input.path, input.from]);
|
|
37
|
+
}
|
|
38
|
+
async function hasBranch2(cwd, name, options) {
|
|
39
|
+
return gitCommand(options?.git)(cwd, ["show-ref", "--verify", "--quiet", `refs/heads/${name}`]).then(() => true).catch(() => false);
|
|
40
|
+
}
|
|
41
|
+
function localWorktrees2(options) {
|
|
42
|
+
const git = gitCommand(options?.git);
|
|
43
|
+
const folders = join(options?.home ?? homedir(), ".nyte", "worktrees");
|
|
44
|
+
const commitAt = (cwd, revision) => git(cwd, ["rev-parse", "--verify", "--quiet", `${revision}^{commit}`]).then((out) => out.trim(), () => null);
|
|
45
|
+
const workingTree = async (repo) => {
|
|
46
|
+
const index = join(tmpdir(), `nyte-worktree-index-${randomUUID()}`);
|
|
47
|
+
const indexEnv = { GIT_INDEX_FILE: index };
|
|
48
|
+
try {
|
|
49
|
+
await copyFile(join(repo.gitDir, "index"), index).catch(() => {
|
|
50
|
+
return;
|
|
51
|
+
});
|
|
52
|
+
await git(repo.root, ["add", "-A", "--", "."], indexEnv);
|
|
53
|
+
return (await git(repo.root, ["write-tree"], indexEnv)).trim();
|
|
54
|
+
} finally {
|
|
55
|
+
await rm(index, { force: true });
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
async create(env, input) {
|
|
60
|
+
const repo = await readRepository(git, env.cwd);
|
|
61
|
+
if (repo === null)
|
|
62
|
+
throw new SdkError("unavailable", `${env.cwd} is not in a git repository, so it cannot have a worktree.`);
|
|
63
|
+
const head = await commitAt(repo.root, "HEAD");
|
|
64
|
+
if (head === null)
|
|
65
|
+
throw new SdkError("unavailable", `${repo.root} has no commits yet, so a worktree has nothing to branch from.`);
|
|
66
|
+
const slug = worktreeSlug(input.name, input.title);
|
|
67
|
+
const branch = `nyte/${slug}`;
|
|
68
|
+
const below = (root) => ({
|
|
69
|
+
kind: "local",
|
|
70
|
+
path: repo.prefix === "" ? root : join(root, repo.prefix).replace(/\/+$/u, "")
|
|
71
|
+
});
|
|
72
|
+
const listed = (await listWorktrees2(repo.root, options)).find((worktree) => worktree.branch === branch);
|
|
73
|
+
if (listed !== undefined)
|
|
74
|
+
return {
|
|
75
|
+
target: below(listed.path),
|
|
76
|
+
branch,
|
|
77
|
+
base: await commitAt(repo.root, `refs/heads/${branch}`) ?? head
|
|
78
|
+
};
|
|
79
|
+
const folder = join(folders, basename(repo.root), slug);
|
|
80
|
+
const branched = await hasBranch2(repo.root, branch, options);
|
|
81
|
+
const base = branched ? await commitAt(repo.root, `refs/heads/${branch}`) ?? head : head;
|
|
82
|
+
const tree = await workingTree(repo);
|
|
83
|
+
await mkdir(dirname(folder), { recursive: true });
|
|
84
|
+
await addWorktree2(repo.root, branched ? { path: folder, branch } : { path: folder, branch, from: head }, options);
|
|
85
|
+
if (tree !== (await git(folder, ["rev-parse", "HEAD^{tree}"])).trim()) {
|
|
86
|
+
await git(folder, ["read-tree", "-m", "-u", "HEAD", tree]);
|
|
87
|
+
await git(folder, ["reset", "-q"]);
|
|
88
|
+
}
|
|
89
|
+
return { target: below(await realpath(folder)), branch, base };
|
|
90
|
+
},
|
|
91
|
+
async remove(worktree) {
|
|
92
|
+
const path = "path" in worktree.target ? worktree.target.path : null;
|
|
93
|
+
if (path === null || await stat(path).catch(() => null) === null)
|
|
94
|
+
return { folder: "removed", branch: "kept" };
|
|
95
|
+
const [root = path, common = ""] = (await git(path, [
|
|
96
|
+
"rev-parse",
|
|
97
|
+
"--show-toplevel",
|
|
98
|
+
"--path-format=absolute",
|
|
99
|
+
"--git-common-dir"
|
|
100
|
+
])).split(`
|
|
101
|
+
`);
|
|
102
|
+
const status = await git(root, ["status", "--porcelain", "--ignored", "-z"]);
|
|
103
|
+
if (status.split("\x00").some((entry) => entry !== "" && !(entry.startsWith("!! ") && entry.endsWith("/"))))
|
|
104
|
+
return { folder: "kept", branch: "kept" };
|
|
105
|
+
await git(common, ["worktree", "remove", root]);
|
|
106
|
+
if (await commitAt(common, `refs/heads/${worktree.branch}`) !== worktree.base)
|
|
107
|
+
return { folder: "removed", branch: "kept" };
|
|
108
|
+
await git(common, ["branch", "-D", worktree.branch]);
|
|
109
|
+
return { folder: "removed", branch: "deleted" };
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
async function readRepository(git, cwd) {
|
|
114
|
+
const out = await git(cwd, [
|
|
115
|
+
"rev-parse",
|
|
116
|
+
"--show-toplevel",
|
|
117
|
+
"--absolute-git-dir",
|
|
118
|
+
"--show-prefix"
|
|
119
|
+
]).catch(() => null);
|
|
120
|
+
const [root, gitDir, prefix = ""] = out?.split(`
|
|
121
|
+
`) ?? [];
|
|
122
|
+
return root === undefined || gitDir === undefined || root === "" ? null : { root, gitDir, prefix };
|
|
123
|
+
}
|
|
124
|
+
function worktreeSlug(name, title) {
|
|
125
|
+
const words = (title ?? "").toLowerCase().replace(/[^a-z0-9]+/gu, "-").slice(0, 40).replace(/^-+|-+$/gu, "");
|
|
126
|
+
const key = sha2562(name).slice(0, 8);
|
|
127
|
+
return words === "" ? key : `${words}-${key}`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export { listWorktrees2, addWorktree2, hasBranch2, localWorktrees2 };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readErrorCode2
|
|
3
|
+
} from "./canvas-preview-mgcx2b2p.js";
|
|
4
|
+
|
|
5
|
+
// src/plugins/loader.ts
|
|
6
|
+
import { readdir, realpath, stat } from "node:fs/promises";
|
|
7
|
+
import { isAbsolute, join, relative } from "node:path";
|
|
8
|
+
import { pathToFileURL } from "node:url";
|
|
9
|
+
import { SdkError } from "@nyte-ai/schema";
|
|
10
|
+
import { dev } from "@nyte-ai/core";
|
|
11
|
+
var EXTENSIONS = [".ts", ".mts", ".js", ".mjs"];
|
|
12
|
+
async function loadPluginFiles2(dir) {
|
|
13
|
+
return loadAll(await pluginFilesIn(dir));
|
|
14
|
+
}
|
|
15
|
+
async function loadPluginDirectory2(dir) {
|
|
16
|
+
return importEach(await pluginFilesIn(dir));
|
|
17
|
+
}
|
|
18
|
+
function pluginLoader2(dirs) {
|
|
19
|
+
return async (paths) => {
|
|
20
|
+
const roots = (await Promise.all(dirs.map((dir) => realpath(dir).catch(() => null)))).filter((root) => root !== null);
|
|
21
|
+
const files = await Promise.all(paths.map(async (path) => {
|
|
22
|
+
const real = await realpath(path).catch(() => null);
|
|
23
|
+
if (real === null)
|
|
24
|
+
throw new SdkError("invalid", `No plugin file is at ${path}.`);
|
|
25
|
+
if (!roots.some((root) => inside(root, real)))
|
|
26
|
+
throw new SdkError("denied", `${path} is not in a plugin directory this host loads.`);
|
|
27
|
+
return real;
|
|
28
|
+
}));
|
|
29
|
+
return (await loadAll(files)).map((loaded) => loaded.plugin);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async function loadAll(files) {
|
|
33
|
+
const { loaded, failed } = await importEach(files);
|
|
34
|
+
const issues = failed.map((entry) => entry.issue);
|
|
35
|
+
if (issues.length > 0)
|
|
36
|
+
throw new SdkError("invalid", `${issues.length === 1 ? "A plugin file" : `${issues.length} plugin files`} did not load: ${failed.map((entry) => `${entry.path}: ${entry.issue.message}`).join("; ")}`, { issues });
|
|
37
|
+
return loaded;
|
|
38
|
+
}
|
|
39
|
+
async function importEach(files) {
|
|
40
|
+
const loaded = [];
|
|
41
|
+
const failed = [];
|
|
42
|
+
for (const path of files) {
|
|
43
|
+
const outcome = await importPlugin(path);
|
|
44
|
+
dev("plugins", "file", { path, outcome: "plugin" in outcome ? "loaded" : "failed" });
|
|
45
|
+
if ("plugin" in outcome)
|
|
46
|
+
loaded.push({ plugin: outcome.plugin, path });
|
|
47
|
+
else
|
|
48
|
+
failed.push({
|
|
49
|
+
path,
|
|
50
|
+
issue: {
|
|
51
|
+
severity: "error",
|
|
52
|
+
path: [path],
|
|
53
|
+
message: outcome.reason,
|
|
54
|
+
source: { plugin: path, file: path }
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return { loaded, failed };
|
|
59
|
+
}
|
|
60
|
+
async function pluginFilesIn(dir) {
|
|
61
|
+
const entries = await readdir(dir, { withFileTypes: true }).catch((error) => {
|
|
62
|
+
if (readErrorCode2(error) === "ENOENT" || readErrorCode2(error) === "ENOTDIR")
|
|
63
|
+
return [];
|
|
64
|
+
throw error;
|
|
65
|
+
});
|
|
66
|
+
return (await Promise.all(entries.sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0).map(async (entry) => {
|
|
67
|
+
const path = join(dir, entry.name);
|
|
68
|
+
if (entry.isFile())
|
|
69
|
+
return EXTENSIONS.some((extension) => entry.name.endsWith(extension)) ? [path] : [];
|
|
70
|
+
if (!entry.isDirectory())
|
|
71
|
+
return [];
|
|
72
|
+
for (const extension of EXTENSIONS) {
|
|
73
|
+
const index = join(path, `index${extension}`);
|
|
74
|
+
if ((await stat(index).catch(() => null))?.isFile() === true)
|
|
75
|
+
return [index];
|
|
76
|
+
}
|
|
77
|
+
return [];
|
|
78
|
+
}))).flat();
|
|
79
|
+
}
|
|
80
|
+
async function importPlugin(path) {
|
|
81
|
+
try {
|
|
82
|
+
const stats = await stat(path);
|
|
83
|
+
const url = pathToFileURL(path);
|
|
84
|
+
url.searchParams.set("nyte", `${stats.mtimeMs}-${stats.size}`);
|
|
85
|
+
const imported = await import(url.href);
|
|
86
|
+
const exported = typeof imported === "object" && imported !== null && "default" in imported ? imported.default : undefined;
|
|
87
|
+
return fitsCorePlugin(exported) ? { plugin: exported } : { reason: "Its default export is not a core plugin (an object with a string id)." };
|
|
88
|
+
} catch (error) {
|
|
89
|
+
return { reason: error instanceof Error ? error.message : String(error) };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function fitsCorePlugin(value) {
|
|
93
|
+
if (typeof value !== "object" || value === null || !("id" in value) || typeof value.id !== "string")
|
|
94
|
+
return false;
|
|
95
|
+
const object = (field) => field === undefined || typeof field === "object" && field !== null;
|
|
96
|
+
if ("contribute" in value && !object(value.contribute))
|
|
97
|
+
return false;
|
|
98
|
+
if ("hooks" in value && !object(value.hooks))
|
|
99
|
+
return false;
|
|
100
|
+
if ("activate" in value && value.activate !== undefined && typeof value.activate !== "function")
|
|
101
|
+
return false;
|
|
102
|
+
if (!("environment" in value) || value.environment === undefined)
|
|
103
|
+
return true;
|
|
104
|
+
const environment = value.environment;
|
|
105
|
+
return typeof environment === "object" && environment !== null && "kind" in environment && typeof environment.kind === "string" && "inspect" in environment && typeof environment.inspect === "function" && "attach" in environment && typeof environment.attach === "function";
|
|
106
|
+
}
|
|
107
|
+
function inside(root, path) {
|
|
108
|
+
const within = relative(root, path);
|
|
109
|
+
return within !== "" && !within.startsWith("..") && !isAbsolute(within);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export { loadPluginFiles2, loadPluginDirectory2, pluginLoader2 };
|