@volter/live 0.5.211 → 0.5.212

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/BUNDLED_NOTICES +13 -13
  2. package/README.md +7 -11
  3. package/dist/chunk-7SZ3C4CC.js +768 -0
  4. package/dist/chunk-7SZ3C4CC.js.map +7 -0
  5. package/dist/chunk-7WKVJGHZ.js +15 -0
  6. package/dist/chunk-7WKVJGHZ.js.map +7 -0
  7. package/dist/chunk-SDIWRX5X.js +189 -0
  8. package/dist/chunk-SDIWRX5X.js.map +7 -0
  9. package/dist/chunk-USXOIBVX.js +81 -0
  10. package/dist/chunk-USXOIBVX.js.map +7 -0
  11. package/dist/chunk-Y5W77HYT.js +123 -0
  12. package/dist/chunk-Y5W77HYT.js.map +7 -0
  13. package/dist/chunk-YPAOTPIF.js +202 -0
  14. package/dist/chunk-YPAOTPIF.js.map +7 -0
  15. package/dist/client.d.ts +370 -0
  16. package/dist/client.js +9 -0
  17. package/dist/client.js.map +7 -0
  18. package/dist/discovery.d.ts +32 -0
  19. package/dist/discovery.js +19 -0
  20. package/dist/discovery.js.map +7 -0
  21. package/dist/editor-document.d.ts +12 -47
  22. package/dist/editor.d.ts +34 -181
  23. package/dist/http-transport.d.ts +6 -0
  24. package/dist/index.d.ts +1 -5
  25. package/dist/index.js +76 -1722
  26. package/dist/index.js.map +4 -4
  27. package/dist/installed-package.d.ts +6 -0
  28. package/dist/installed-package.js +7 -0
  29. package/dist/installed-package.js.map +7 -0
  30. package/dist/lazy-proxy.d.ts +11 -11
  31. package/dist/member-hints.d.ts +6 -9
  32. package/dist/product-create.d.ts +29 -0
  33. package/dist/product-create.js +13 -0
  34. package/dist/product-create.js.map +7 -0
  35. package/dist/product-locator.d.ts +100 -0
  36. package/dist/product-locator.js +25 -0
  37. package/dist/product-locator.js.map +7 -0
  38. package/dist/registry-format.d.ts +44 -0
  39. package/dist/registry-format.js +21 -0
  40. package/dist/registry-format.js.map +7 -0
  41. package/dist/session.d.ts +10 -3
  42. package/dist/singleton.d.ts +1 -13
  43. package/dist/volter-manifest.d.ts +55 -0
  44. package/dist/volter-manifest.js +9 -0
  45. package/dist/volter-manifest.js.map +7 -0
  46. package/dist/workbench-locator.d.ts +84 -0
  47. package/dist/workbench-locator.js +416 -0
  48. package/dist/workbench-locator.js.map +7 -0
  49. package/package.json +35 -3
  50. package/src/client.ts +1052 -0
  51. package/src/discovery.ts +105 -0
  52. package/src/editor-document.ts +12 -49
  53. package/src/editor.ts +45 -212
  54. package/src/http-transport.ts +19 -0
  55. package/src/index.ts +3 -7
  56. package/src/installed-package.ts +15 -0
  57. package/src/lazy-proxy.ts +11 -11
  58. package/src/member-hints.ts +8 -12
  59. package/src/product-create.ts +38 -0
  60. package/src/product-locator.ts +327 -0
  61. package/src/registry-format.ts +185 -0
  62. package/src/session.ts +38 -66
  63. package/src/singleton.ts +1 -16
  64. package/src/volter-manifest.ts +97 -0
  65. package/src/workbench-locator.ts +625 -0
  66. package/dist/tools.d.ts +0 -23
  67. package/src/tools.ts +0 -45
@@ -0,0 +1,123 @@
1
+ // src/registry-format.ts
2
+ import {
3
+ mkdirSync,
4
+ readdirSync,
5
+ readFileSync,
6
+ realpathSync,
7
+ unlinkSync,
8
+ writeFileSync
9
+ } from "node:fs";
10
+ import { homedir } from "node:os";
11
+ import { join, resolve } from "node:path";
12
+ import { setTimeout as delay } from "node:timers/promises";
13
+ var EDITOR_SESSIONS_REGISTRY_FILE = join(homedir(), ".volter", "editor-sessions.json");
14
+ function isEditorSessionEntry(v) {
15
+ if (typeof v !== "object" || v === null) return false;
16
+ const s = v;
17
+ const optionalIdentity = (value) => value === void 0 || value === null || typeof value === "string";
18
+ return (typeof s["project"] === "string" || s["project"] === null) && typeof s["port"] === "number" && typeof s["pid"] === "number" && typeof s["startedAt"] === "string" && optionalIdentity(s["sessionId"]) && optionalIdentity(s["controlSecret"]) && optionalIdentity(s["repositoryId"]) && optionalIdentity(s["worktreeId"]) && optionalIdentity(s["worktreeRoot"]) && optionalIdentity(s["projectRelativePath"]) && optionalIdentity(s["branch"]) && optionalIdentity(s["headCommit"]) && optionalIdentity(s["baseCommit"]);
19
+ }
20
+ function normalizeEditorSessionEntry(session) {
21
+ return {
22
+ ...session,
23
+ sessionId: session.sessionId ?? null,
24
+ controlSecret: session.controlSecret ?? null,
25
+ repositoryId: session.repositoryId ?? null,
26
+ worktreeId: session.worktreeId ?? null,
27
+ worktreeRoot: session.worktreeRoot ?? null,
28
+ projectRelativePath: session.projectRelativePath ?? null,
29
+ branch: session.branch ?? null,
30
+ headCommit: session.headCommit ?? null,
31
+ baseCommit: session.baseCommit ?? null
32
+ };
33
+ }
34
+ function pidAlive(pid) {
35
+ try {
36
+ process.kill(pid, 0);
37
+ return true;
38
+ } catch (error) {
39
+ return error.code === "EPERM";
40
+ }
41
+ }
42
+ function readLiveRegisteredSessions() {
43
+ try {
44
+ const raw = JSON.parse(readFileSync(EDITOR_SESSIONS_REGISTRY_FILE, "utf8"));
45
+ return Array.isArray(raw) ? raw.filter(isEditorSessionEntry).map(normalizeEditorSessionEntry).filter((s) => pidAlive(s.pid)) : [];
46
+ } catch {
47
+ return [];
48
+ }
49
+ }
50
+ function announceEditorLaunch(project) {
51
+ const directory = join(project, ".volter", "editor-launches");
52
+ mkdirSync(directory, { recursive: true });
53
+ const file = join(directory, `${process.pid}.json`);
54
+ writeFileSync(file, JSON.stringify({ pid: process.pid }));
55
+ const clear = () => {
56
+ process.removeListener("exit", clear);
57
+ try {
58
+ unlinkSync(file);
59
+ } catch {
60
+ }
61
+ };
62
+ process.once("exit", clear);
63
+ return clear;
64
+ }
65
+ function hasPendingEditorLaunch(project) {
66
+ const directory = join(project, ".volter", "editor-launches");
67
+ try {
68
+ return readdirSync(directory).some((name) => {
69
+ if (!/^\d+\.json$/.test(name)) return false;
70
+ const pid = Number(name.slice(0, -5));
71
+ return pid !== process.pid && pidAlive(pid);
72
+ });
73
+ } catch {
74
+ return false;
75
+ }
76
+ }
77
+ async function waitForPendingEditorLaunch(project) {
78
+ const canon = canonicalizeProjectPath(project);
79
+ const ready = () => readLiveRegisteredSessions().some(
80
+ (session) => session.project !== null && canonicalizeProjectPath(session.project) === canon
81
+ );
82
+ if (ready() || !hasPendingEditorLaunch(canon)) return;
83
+ const deadline = Date.now() + 18e4;
84
+ while (!ready()) {
85
+ if (!hasPendingEditorLaunch(canon)) {
86
+ if (ready()) return;
87
+ throw new Error(`The editor launch for ${canon} ended before registering a session.`);
88
+ }
89
+ if (Date.now() >= deadline) {
90
+ throw new Error(
91
+ `The editor launch for ${canon} is still running but has not registered within 180s.`
92
+ );
93
+ }
94
+ await delay(100);
95
+ }
96
+ }
97
+ function servedProjectAnswer(body) {
98
+ const b = body;
99
+ return {
100
+ path: b.project?.path ?? b.serving?.path ?? null,
101
+ manifestError: b.project ? null : b.serving?.error ?? null
102
+ };
103
+ }
104
+ function canonicalizeProjectPath(p) {
105
+ const absolute = resolve(p);
106
+ try {
107
+ return realpathSync(absolute);
108
+ } catch {
109
+ return absolute;
110
+ }
111
+ }
112
+
113
+ export {
114
+ EDITOR_SESSIONS_REGISTRY_FILE,
115
+ isEditorSessionEntry,
116
+ normalizeEditorSessionEntry,
117
+ pidAlive,
118
+ readLiveRegisteredSessions,
119
+ announceEditorLaunch,
120
+ waitForPendingEditorLaunch,
121
+ servedProjectAnswer
122
+ };
123
+ //# sourceMappingURL=chunk-Y5W77HYT.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/registry-format.ts"],
4
+ "sourcesContent": ["/**\n * Shared editor-session registry format: entry shape, guards, path,\n * liveness-filtered reads, served-project parsing and pending launches.\n * The server\u2019s session-registry module owns writes to this format.\n */\n\nimport {\n mkdirSync,\n readdirSync,\n readFileSync,\n realpathSync,\n unlinkSync,\n writeFileSync,\n} from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { setTimeout as delay } from 'node:timers/promises';\n\n/** One registry entry, exactly as the server's write half records it. */\nexport interface EditorSessionEntry {\n /** Canonical project root currently open, or null when none. */\n project: string | null;\n port: number;\n /** PID of the dev-server process. */\n pid: number;\n /** ISO timestamp of server start. */\n startedAt: string;\n sessionId: string | null;\n /** Private loopback control credential \u2014 never returned by an editor HTTP\n * route; exists only in this user-private registry. */\n controlSecret?: string | null;\n repositoryId: string | null;\n worktreeId: string | null;\n worktreeRoot: string | null;\n projectRelativePath: string | null;\n branch: string | null;\n headCommit: string | null;\n baseCommit: string | null;\n}\n\nexport const EDITOR_SESSIONS_REGISTRY_FILE = join(homedir(), '.volter', 'editor-sessions.json');\n\nexport function isEditorSessionEntry(v: unknown): v is EditorSessionEntry {\n if (typeof v !== 'object' || v === null) return false;\n const s = v as Record<string, unknown>;\n const optionalIdentity = (value: unknown) =>\n value === undefined || value === null || typeof value === 'string';\n return (\n (typeof s['project'] === 'string' || s['project'] === null) &&\n typeof s['port'] === 'number' &&\n typeof s['pid'] === 'number' &&\n typeof s['startedAt'] === 'string' &&\n optionalIdentity(s['sessionId']) &&\n optionalIdentity(s['controlSecret']) &&\n optionalIdentity(s['repositoryId']) &&\n optionalIdentity(s['worktreeId']) &&\n optionalIdentity(s['worktreeRoot']) &&\n optionalIdentity(s['projectRelativePath']) &&\n optionalIdentity(s['branch']) &&\n optionalIdentity(s['headCommit']) &&\n optionalIdentity(s['baseCommit'])\n );\n}\n\nexport function normalizeEditorSessionEntry(session: EditorSessionEntry): EditorSessionEntry {\n return {\n ...session,\n sessionId: session.sessionId ?? null,\n controlSecret: session.controlSecret ?? null,\n repositoryId: session.repositoryId ?? null,\n worktreeId: session.worktreeId ?? null,\n worktreeRoot: session.worktreeRoot ?? null,\n projectRelativePath: session.projectRelativePath ?? null,\n branch: session.branch ?? null,\n headCommit: session.headCommit ?? null,\n baseCommit: session.baseCommit ?? null,\n };\n}\n\n/** Whether pid exists. Signal 0's EPERM means it exists but this caller cannot signal it. */\nexport function pidAlive(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\n/** The registry's live entries \u2014 shape-validated and PID-liveness-filtered. */\nexport function readLiveRegisteredSessions(): EditorSessionEntry[] {\n try {\n const raw: unknown = JSON.parse(readFileSync(EDITOR_SESSIONS_REGISTRY_FILE, 'utf8'));\n return Array.isArray(raw)\n ? raw\n .filter(isEditorSessionEntry)\n .map(normalizeEditorSessionEntry)\n .filter((s) => pidAlive(s.pid))\n : [];\n } catch {\n return [];\n }\n}\n\n/** Announce a launch before the server can register. Each launcher owns its file. */\nexport function announceEditorLaunch(project: string): () => void {\n const directory = join(project, '.volter', 'editor-launches');\n mkdirSync(directory, { recursive: true });\n const file = join(directory, `${process.pid}.json`);\n writeFileSync(file, JSON.stringify({ pid: process.pid }));\n const clear = () => {\n process.removeListener('exit', clear);\n try {\n unlinkSync(file);\n } catch {\n // Already cleared when the server became ready.\n }\n };\n process.once('exit', clear);\n return clear;\n}\n\nfunction hasPendingEditorLaunch(project: string): boolean {\n const directory = join(project, '.volter', 'editor-launches');\n try {\n return readdirSync(directory).some((name) => {\n if (!/^\\d+\\.json$/.test(name)) return false;\n const pid = Number(name.slice(0, -5));\n return pid !== process.pid && pidAlive(pid);\n });\n } catch {\n return false;\n }\n}\n\n/** Wait only for an observed live launcher, never for a missing editor. */\nexport async function waitForPendingEditorLaunch(project: string): Promise<void> {\n const canon = canonicalizeProjectPath(project);\n const ready = () =>\n readLiveRegisteredSessions().some(\n (session) => session.project !== null && canonicalizeProjectPath(session.project) === canon,\n );\n if (ready() || !hasPendingEditorLaunch(canon)) return;\n const deadline = Date.now() + 180_000;\n while (!ready()) {\n if (!hasPendingEditorLaunch(canon)) {\n // The launcher clears its announcement only after registration.\n if (ready()) return;\n throw new Error(`The editor launch for ${canon} ended before registering a session.`);\n }\n if (Date.now() >= deadline) {\n throw new Error(\n `The editor launch for ${canon} is still running but has not registered within 180s.`,\n );\n }\n await delay(100);\n }\n}\n\n/** Read the project identity reported by /__editor/project. A serving path\n * identifies an open project even when its manifest cannot be parsed or\n * validated; project: null alone denotes no described project. */\nexport function servedProjectAnswer(body: unknown): {\n path: string | null;\n manifestError: string | null;\n} {\n const b = body as {\n project?: { path?: string } | null;\n serving?: { path?: string; error?: string } | null;\n };\n return {\n path: b.project?.path ?? b.serving?.path ?? null,\n manifestError: b.project ? null : (b.serving?.error ?? null),\n };\n}\n\n/** Canonical (realpathed when possible) absolute form of a project path. */\nfunction canonicalizeProjectPath(p: string): string {\n const absolute = resolve(p);\n try {\n return realpathSync(absolute);\n } catch {\n return absolute;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,202 @@
1
+ // src/volter-manifest.ts
2
+ import { readFileSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+
5
+ // ../sdk/src/volter-contributions.ts
6
+ var DECLARATION_KEYS = /* @__PURE__ */ new Set(["product", "serving", "viewRoutes", "projectAdapters"]);
7
+ function record(value) {
8
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
9
+ }
10
+ function contributionIdFromPath(entry) {
11
+ return (entry.split(/[\\/]/).pop() ?? entry).replace(/\.[jt]sx?$/, "");
12
+ }
13
+ function readEditor(value) {
14
+ const editor = record(value);
15
+ if (editor === null) return "an entry is not an object";
16
+ const { viewType, displayName, document, selector, priority, kind, views, assetRoute } = editor;
17
+ if (document !== void 0 && typeof document !== "string") return "a document is a ./-relative module";
18
+ if (kind !== void 0 && (typeof kind !== "string" || kind === "")) return "a kind is a non-empty string";
19
+ if (views !== void 0 && (kind === void 0 || !Array.isArray(views) || views.some((view) => typeof view !== "string"))) return "views are a kind's list of view document ids";
20
+ if (assetRoute !== void 0 && (typeof assetRoute !== "string" || assetRoute === "")) return "an assetRoute is a non-empty string";
21
+ if (document === void 0 && kind === void 0 && assetRoute === void 0) return "an entry names a document, a kind or an assetRoute";
22
+ const read = {
23
+ ...document === void 0 ? {} : { document },
24
+ ...kind === void 0 ? {} : { kind },
25
+ ...views === void 0 ? {} : { views },
26
+ ...assetRoute === void 0 ? {} : { assetRoute }
27
+ };
28
+ if (viewType === void 0 && displayName === void 0 && selector === void 0 && priority === void 0) return read;
29
+ if (typeof viewType !== "string" || typeof displayName !== "string" || typeof document !== "string") return "a file editor needs a viewType, a displayName and a document module";
30
+ const filenamePatterns = Array.isArray(selector) ? selector.map((item) => record(item)?.["filenamePattern"]) : [];
31
+ if (filenamePatterns.length === 0 || filenamePatterns.some((pattern) => typeof pattern !== "string")) return `${viewType}'s selector must list its { filenamePattern }s`;
32
+ if (priority !== void 0 && priority !== "default" && priority !== "option") return `${viewType}'s priority is 'default' or 'option'`;
33
+ return { ...read, declaration: { viewType, displayName, filenamePatterns, priority: priority ?? "default" } };
34
+ }
35
+ function readService(value) {
36
+ if (typeof value === "string") return { module: value };
37
+ const { module, sourceAnalyzer, designTimeMount } = record(value) ?? {};
38
+ if (typeof module !== "string" || [sourceAnalyzer, designTimeMount].some((id) => id !== void 0 && (typeof id !== "string" || id === ""))) {
39
+ return "an entry is a ./-relative module, or { module, sourceAnalyzer?, designTimeMount? }";
40
+ }
41
+ return {
42
+ module,
43
+ ...typeof sourceAnalyzer === "string" ? { sourceAnalyzer } : {},
44
+ ...typeof designTimeMount === "string" ? { designTimeMount } : {}
45
+ };
46
+ }
47
+ function readFinder(value) {
48
+ const { name, module } = record(value) ?? {};
49
+ if (typeof name !== "string" || name === "" || typeof module !== "string") return "an entry is { name, module }, each a non-empty string";
50
+ return { name, module };
51
+ }
52
+ function readUtility(value) {
53
+ const { id, title, module } = record(value) ?? {};
54
+ if (typeof id !== "string" || id === "" || typeof title !== "string" || title.trim() === "" || typeof module !== "string") return "an entry is { id, title, module }, each a non-empty string";
55
+ return { declaration: { id, title: title.trim() }, module };
56
+ }
57
+ function readVolterContributions(declared) {
58
+ const entries = [];
59
+ const editors = [];
60
+ const utilities = [];
61
+ const events = [];
62
+ const errors = [];
63
+ const kinds = record(declared);
64
+ if (kinds === null) return { entries, editors, utilities, events, errors: ["`contributes.volter` must be an object of kinds, each a list of ./-relative modules."] };
65
+ const listed = [];
66
+ for (const [key, list] of Object.entries(kinds)) {
67
+ if (key === "page" || DECLARATION_KEYS.has(key)) continue;
68
+ if (key === "activationEvents") {
69
+ if (!Array.isArray(list) || list.some((event) => typeof event !== "string")) errors.push("`contributes.volter.activationEvents` must be a list of activation events.");
70
+ else events.push(...list);
71
+ continue;
72
+ }
73
+ if (key !== "views") {
74
+ listed.push([key, list]);
75
+ continue;
76
+ }
77
+ const containers = record(list);
78
+ if (containers === null) {
79
+ errors.push("`contributes.volter.views` must be an object of containers: `panel`, `statusbar`.");
80
+ continue;
81
+ }
82
+ for (const [container, views] of Object.entries(containers)) listed.push([`views.${container}`, views]);
83
+ }
84
+ for (const [key, list] of listed) {
85
+ if (!Array.isArray(list)) {
86
+ errors.push(`\`contributes.volter.${key}\` must be a list.`);
87
+ continue;
88
+ }
89
+ for (const entry of list) {
90
+ const refuse = (why) => {
91
+ errors.push(`\`contributes.volter.${key}\`: ${why}.`);
92
+ };
93
+ if (key === "views.panel") {
94
+ const view = readUtility(entry);
95
+ if (typeof view === "string") {
96
+ refuse(view);
97
+ continue;
98
+ }
99
+ utilities.push(view.declaration);
100
+ entries.push({ key, entry: view.module, declared: view.declaration });
101
+ events.push(`onView:${view.declaration.id}`);
102
+ } else if (key === "finders") {
103
+ const finder = readFinder(entry);
104
+ if (typeof finder === "string") {
105
+ refuse(finder);
106
+ continue;
107
+ }
108
+ entries.push({ key, entry: finder.module, finder: finder.name });
109
+ events.push(`onFinder:${finder.name}`);
110
+ } else if (key === "services") {
111
+ const service = readService(entry);
112
+ if (typeof service === "string") {
113
+ refuse(service);
114
+ continue;
115
+ }
116
+ entries.push({ key, entry: service.module });
117
+ if (service.sourceAnalyzer !== void 0) events.push(`onSourceAnalysis:${service.sourceAnalyzer}`);
118
+ if (service.designTimeMount !== void 0) events.push(`onDesignTimeMount:${service.designTimeMount}`);
119
+ } else if (key === "editors") {
120
+ const editor = readEditor(entry);
121
+ if (typeof editor === "string") {
122
+ refuse(editor);
123
+ continue;
124
+ }
125
+ if (editor.declaration) {
126
+ editors.push(editor.declaration);
127
+ events.push(`onCustomEditor:${editor.declaration.viewType}`);
128
+ }
129
+ if (editor.document !== void 0) {
130
+ entries.push({ key, entry: editor.document });
131
+ events.push(`onDocument:${contributionIdFromPath(editor.document)}`);
132
+ }
133
+ if (editor.kind !== void 0) events.push(`onDocument:${editor.kind}`);
134
+ for (const view of editor.views ?? []) events.push(`onDocument:${view}`);
135
+ if (editor.assetRoute !== void 0) events.push(`onAssetViewer:${editor.assetRoute}`);
136
+ } else if (typeof entry !== "string") {
137
+ refuse(`${JSON.stringify(entry)} is not a ./-relative module`);
138
+ } else {
139
+ entries.push({ key, entry });
140
+ }
141
+ }
142
+ }
143
+ return { entries, editors, utilities, events, errors };
144
+ }
145
+ function readPageEntry(name, page) {
146
+ if (page === void 0) return { entry: null };
147
+ const listed = Array.isArray(page) ? page : null;
148
+ if (listed === null || listed.length > 1 || listed.length === 1 && (typeof listed[0] !== "string" || !listed[0].startsWith("./") || listed[0].includes(".."))) {
149
+ return {
150
+ malformed: `${name}'s package.json#contributes.volter.page is ${JSON.stringify(page)}: it lists one page entry, a ./-relative module without parent traversal that exports activate(context).`
151
+ };
152
+ }
153
+ return { entry: listed[0] ?? null };
154
+ }
155
+
156
+ // src/volter-manifest.ts
157
+ function readVolterManifest(path) {
158
+ let json;
159
+ try {
160
+ json = JSON.parse(readFileSync(path, "utf8"));
161
+ } catch {
162
+ return null;
163
+ }
164
+ if (json === null || typeof json !== "object" || Array.isArray(json)) return null;
165
+ const record2 = json;
166
+ const names = (key) => {
167
+ const section = record2[key];
168
+ return section !== null && typeof section === "object" ? Object.keys(section) : [];
169
+ };
170
+ const contributes = record2["contributes"];
171
+ const contributions = contributes !== null && typeof contributes === "object" ? contributes["volter"] : void 0;
172
+ const declared = contributions !== null && typeof contributions === "object" ? contributions : {};
173
+ const product = declared["product"];
174
+ return {
175
+ path,
176
+ dir: dirname(path),
177
+ name: typeof record2["name"] === "string" ? record2["name"] : null,
178
+ version: typeof record2["version"] === "string" ? record2["version"] : null,
179
+ private: record2["private"] === true,
180
+ bin: record2["bin"],
181
+ dependencyNames: [.../* @__PURE__ */ new Set([...names("dependencies"), ...names("devDependencies"), ...names("optionalDependencies")])],
182
+ contributions,
183
+ languageModelTools: contributes !== null && typeof contributes === "object" ? contributes["languageModelTools"] : void 0,
184
+ product: product !== null && typeof product === "object" && !Array.isArray(product) ? product : void 0
185
+ };
186
+ }
187
+ function declaredContributions(manifest) {
188
+ const declared = manifest?.contributions;
189
+ if (declared === null || typeof declared !== "object" || Array.isArray(declared)) return null;
190
+ const { entries, errors } = readVolterContributions(declared);
191
+ const page = readPageEntry(manifest?.name ?? manifest?.path ?? "", declared["page"]);
192
+ return {
193
+ modules: [...entries.map(({ entry }) => entry), ..."entry" in page && page.entry !== null ? [page.entry] : []],
194
+ errors: "malformed" in page ? [...errors, page.malformed] : errors
195
+ };
196
+ }
197
+
198
+ export {
199
+ readVolterManifest,
200
+ declaredContributions
201
+ };
202
+ //# sourceMappingURL=chunk-YPAOTPIF.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/volter-manifest.ts", "../../sdk/src/volter-contributions.ts"],
4
+ "sourcesContent": ["import { readFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport { readPageEntry, readVolterContributions } from '@volter/sdk/volter-contributions';\n\n/**\n * THE NODE READER of a package's `package.json` as Volter reads it: its name, its dependency\n * names and its `contributes.volter` declarations, which `@volter/sdk/volter-contributions` reads as the workbench and\n * the page read them. The build's product plugin, the session's catalog and\n * serving doors, the shared-React scope and the pre-bundle crawl all read a package here, so a\n * declaration means one thing everywhere it is read.\n *\n * It parses and does no policy. What an unusable declaration costs is the caller's to say: a\n * product build refuses it, the catalog reports it as a load error, a scope decision treats it\n * as no declaration. {@link declaredContributions} is the one test of \"this package contributes\".\n */\nexport interface VolterManifest {\n /** The `package.json`, absolute. */\n readonly path: string;\n /** Its package's directory. */\n readonly dir: string;\n readonly name: string | null;\n readonly version: string | null;\n readonly private: boolean;\n readonly bin: unknown;\n /** Every name in `dependencies`, `devDependencies` and `optionalDependencies`, in that order,\n * each once. */\n readonly dependencyNames: readonly string[];\n /** `package.json#contributes.volter`, unchecked: the package's contribution modules, an object\n * keyed by kind, and its declarations (`serving`, `viewRoutes`, `product`). It is where Code-OSS's extension\n * service reads them too, through the kit's `volter` extension point. */\n readonly contributions: unknown;\n /** `package.json#contributes.languageModelTools`, unchecked: the agent tools Code-OSS registers from it. */\n readonly languageModelTools: unknown;\n /** `package.json#contributes.volter.product`, a product's declaration, read and checked by `product-locator.ts`;\n * `undefined` when the package declares none or it is not an object. */\n readonly product: ProductDeclaration | undefined;\n}\n\n/** `package.json#contributes.volter.product`, as declared and unchecked. */\nexport interface ProductDeclaration {\n readonly entry?: unknown;\n readonly composes?: unknown;\n readonly colorTheme?: unknown;\n readonly workbench?: unknown;\n readonly displayName?: unknown;\n readonly install?: unknown;\n readonly upgrade?: unknown;\n readonly adapterRequired?: unknown;\n}\n\n/** `path`'s manifest, or `null` when there is no file there or it is not a JSON object. */\nexport function readVolterManifest(path: string): VolterManifest | null {\n let json: unknown;\n try {\n json = JSON.parse(readFileSync(path, 'utf8'));\n } catch {\n return null;\n }\n if (json === null || typeof json !== 'object' || Array.isArray(json)) return null;\n const record = json as Record<string, unknown>;\n const names = (key: string): string[] => {\n const section = record[key];\n return section !== null && typeof section === 'object' ? Object.keys(section) : [];\n };\n const contributes = record['contributes'];\n const contributions = contributes !== null && typeof contributes === 'object' ? (contributes as Record<string, unknown>)['volter'] : undefined;\n const declared = contributions !== null && typeof contributions === 'object' ? (contributions as Record<string, unknown>) : {};\n const product = declared['product'];\n return {\n path,\n dir: dirname(path),\n name: typeof record['name'] === 'string' ? record['name'] : null,\n version: typeof record['version'] === 'string' ? record['version'] : null,\n private: record['private'] === true,\n bin: record['bin'],\n dependencyNames: [...new Set([...names('dependencies'), ...names('devDependencies'), ...names('optionalDependencies')])],\n contributions,\n languageModelTools: contributes !== null && typeof contributes === 'object' ? (contributes as Record<string, unknown>)['languageModelTools'] : undefined,\n product: product !== null && typeof product === 'object' && !Array.isArray(product) ? (product as ProductDeclaration) : undefined,\n };\n}\n\n/**\n * The package's declared modules, each contribution's and its page half's, with why any entry is refused; `null` when\n * it declares none (an absent `contributes.volter`, or one that is not an object). A package with the object, even an\n * empty one, is a contributing package: its modules are editor-tree code.\n */\nexport function declaredContributions(manifest: VolterManifest | null): { readonly modules: readonly string[]; readonly errors: readonly string[] } | null {\n const declared = manifest?.contributions;\n if (declared === null || typeof declared !== 'object' || Array.isArray(declared)) return null;\n const { entries, errors } = readVolterContributions(declared);\n const page = readPageEntry(manifest?.name ?? manifest?.path ?? '', (declared as Record<string, unknown>)['page']);\n return {\n modules: [...entries.map(({ entry }) => entry), ...('entry' in page && page.entry !== null ? [page.entry] : [])],\n errors: 'malformed' in page ? [...errors, page.malformed] : errors,\n };\n}\n", "/**\n * THE ONE READER of a package's `contributes.volter`: what each key declares, the modules it names, and the activation\n * events its contributions imply. The workbench's `volter` extension point (`workbench/src/volterExtensions.ts`, through\n * the copy the overlay writes beside it, `volterGeneratedContributions.ts`), the page's activation (editor-core's `page-activation.ts`) and\n * Node's manifest reader (`@volter/live/volter-manifest`) all read a package here, so a declaration means one thing\n * everywhere it is read.\n *\n * It imports nothing: the workbench half is compiled inside the Code-OSS fork, which resolves no package, so\n * `scripts/workbench/overlay.mjs` copies this file into it at every overlay.\n *\n * The keys are an EDITOR's (`editors`), a VIEW's by container (`views.panel`, `views.statusbar`), an INSPECTOR's, a LOOK's,\n * a FINDER's and a SERVICE's. `page` is the package's page half, and `product`, `serving`, `viewRoutes` and\n * `projectAdapters` are declarations read in Node ({@link DECLARATION_KEYS}); none of them is a contribution kind.\n *\n * `activationEvents` is Code-OSS's top-level key, stated here by a package whose only code is its page half: Code-OSS\n * refuses an extension that lists top-level `activationEvents` without a `main` or `browser` entry\n * (`extensionValidator.ts`'s `validateExtensionManifest`), so such a package lists its explicit events under\n * `contributes.volter` instead, and they join the ones its contributions imply.\n */\n\n/** The `contributes.volter` keys that are declarations, not contribution kinds: the product's declaration (`product`,\n * `@volter/live/product-locator`), the server half (`serving`, editor-core's `server/session-product.ts`), the\n * limited view's module (`viewRoutes`) and the adapters a package supplies for projects like a kind it knows\n * (`projectAdapters`, editor-core's `server/session-product.ts`). */\nconst DECLARATION_KEYS: ReadonlySet<string> = new Set(['product', 'serving', 'viewRoutes', 'projectAdapters']);\n\n/**\n * One editor a package declares under `contributes.volter.editors` with the files it opens (Code-OSS's `selector` and\n * `priority`, as `contributes.notebooks` states them). Code-OSS's `customEditors` is not used: it means a webview editor.\n */\nexport interface VolterEditorDeclaration {\n /** The editor's id in the resolver (`volter.<integration>.model`). */\n readonly viewType: string;\n /** What \"Reopen Editor With\u2026\" lists. */\n readonly displayName: string;\n readonly filenamePatterns: readonly string[];\n readonly priority: 'default' | 'option';\n}\n\n/**\n * One panel view a package declares under `contributes.volter.views.panel`: `{ id, title, module }`, as an editor states\n * its `viewType` and `displayName`. The workbench registers its panel view from this before any of the package's code\n * loads, and the view's first showing is the package's `onView:<id>`.\n */\nexport interface VolterUtilityDeclaration {\n readonly id: string;\n readonly title: string;\n}\n\n/** One contribution module a package declares: the key it is listed under (`views.panel` for a panel view), its\n * `./`-relative module, and a panel view's or a finder's own statement. */\nexport interface VolterContribution {\n readonly key: string;\n readonly entry: string;\n readonly declared?: VolterUtilityDeclaration;\n readonly finder?: string;\n}\n\n/** A package's `contributes.volter`, read. */\ninterface VolterContributions {\n /** Each contribution module, in declaration order; a refused entry is left out. */\n readonly entries: readonly VolterContribution[];\n /** The file editors, for the workbench's editor resolver. */\n readonly editors: readonly VolterEditorDeclaration[];\n /** The panel views. */\n readonly utilities: readonly VolterUtilityDeclaration[];\n /** The activation events the contributions imply ({@link activationEvents}). */\n readonly events: readonly string[];\n /** Why each refused entry is refused, as `contributes.volter.<key>: <why>.` */\n readonly errors: readonly string[];\n}\n\nfunction record(value: unknown): Record<string, unknown> | null {\n return value !== null && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : null;\n}\n\n/** A declared list's string entries. */\nfunction strings(list: unknown): string[] {\n return Array.isArray(list) ? list.filter((entry): entry is string => typeof entry === 'string') : [];\n}\n\n/** A contribution module's id, its base name without its extension: `contributions/timeline.document.tsx` is\n * `timeline.document`. An editor's `document` implies `onDocument:<id>`, and the loader records a module by it. */\nexport function contributionIdFromPath(entry: string): string {\n return (entry.split(/[\\\\/]/).pop() ?? entry).replace(/\\.[jt]sx?$/, '');\n}\n\n/** One `contributes.volter.editors` entry, read. */\ninterface ReadEditor {\n readonly declaration?: VolterEditorDeclaration;\n /** The document module the page loads; absent for a kind or an asset route the package registers in code. */\n readonly document?: string;\n readonly kind?: string;\n readonly views?: readonly string[];\n readonly assetRoute?: string;\n}\n\nfunction readEditor(value: unknown): ReadEditor | string {\n const editor = record(value);\n if (editor === null) return 'an entry is not an object';\n const { viewType, displayName, document, selector, priority, kind, views, assetRoute } = editor;\n if (document !== undefined && typeof document !== 'string') return 'a document is a ./-relative module';\n if (kind !== undefined && (typeof kind !== 'string' || kind === '')) return 'a kind is a non-empty string';\n if (views !== undefined && (kind === undefined || !Array.isArray(views) || views.some((view) => typeof view !== 'string'))) return \"views are a kind's list of view document ids\";\n if (assetRoute !== undefined && (typeof assetRoute !== 'string' || assetRoute === '')) return 'an assetRoute is a non-empty string';\n if (document === undefined && kind === undefined && assetRoute === undefined) return 'an entry names a document, a kind or an assetRoute';\n const read = {\n ...(document === undefined ? {} : { document }),\n ...(kind === undefined ? {} : { kind }),\n ...(views === undefined ? {} : { views: views as string[] }),\n ...(assetRoute === undefined ? {} : { assetRoute }),\n };\n if (viewType === undefined && displayName === undefined && selector === undefined && priority === undefined) return read;\n if (typeof viewType !== 'string' || typeof displayName !== 'string' || typeof document !== 'string') return 'a file editor needs a viewType, a displayName and a document module';\n const filenamePatterns = Array.isArray(selector) ? selector.map((item) => record(item)?.['filenamePattern']) : [];\n if (filenamePatterns.length === 0 || filenamePatterns.some((pattern) => typeof pattern !== 'string')) return `${viewType}'s selector must list its { filenamePattern }s`;\n if (priority !== undefined && priority !== 'default' && priority !== 'option') return `${viewType}'s priority is 'default' or 'option'`;\n return { ...read, declaration: { viewType, displayName, filenamePatterns: filenamePatterns as string[], priority: priority ?? 'default' } };\n}\n\n/** One `contributes.volter.services` entry, read: a module, or `{ module, sourceAnalyzer?, designTimeMount? }`. */\nfunction readService(value: unknown): { readonly module: string; readonly sourceAnalyzer?: string; readonly designTimeMount?: string } | string {\n if (typeof value === 'string') return { module: value };\n const { module, sourceAnalyzer, designTimeMount } = record(value) ?? {};\n if (typeof module !== 'string' || [sourceAnalyzer, designTimeMount].some((id) => id !== undefined && (typeof id !== 'string' || id === ''))) {\n return 'an entry is a ./-relative module, or { module, sourceAnalyzer?, designTimeMount? }';\n }\n return {\n module,\n ...(typeof sourceAnalyzer === 'string' ? { sourceAnalyzer } : {}),\n ...(typeof designTimeMount === 'string' ? { designTimeMount } : {}),\n };\n}\n\n/** One `contributes.volter.finders` entry, read. */\nfunction readFinder(value: unknown): { readonly name: string; readonly module: string } | string {\n const { name, module } = record(value) ?? {};\n if (typeof name !== 'string' || name === '' || typeof module !== 'string') return 'an entry is { name, module }, each a non-empty string';\n return { name, module };\n}\n\n/** One `contributes.volter.views.panel` entry, read. */\nfunction readUtility(value: unknown): { readonly declaration: VolterUtilityDeclaration; readonly module: string } | string {\n const { id, title, module } = record(value) ?? {};\n if (typeof id !== 'string' || id === '' || typeof title !== 'string' || title.trim() === '' || typeof module !== 'string') return 'an entry is { id, title, module }, each a non-empty string';\n return { declaration: { id, title: title.trim() }, module };\n}\n\n/**\n * Read a package's `contributes.volter` (`declared`, unchecked). Each key is a list; the views are keyed by container,\n * as Code-OSS's `contributes.views` is. An entry that is refused is left out and named in `errors`.\n *\n * The implied activation events are Code-OSS's for an extension's contributions (`ImplicitActivationEvents`), carried\n * the same way by Volter's:\n * - for each `editors` entry, `onCustomEditor:<viewType>`, `onDocument:<id>` for its `document` (the module's base\n * name), `onDocument:<kind>` and `onDocument:<view>` for its `kind` and `views`, and `onAssetViewer:<route>` for its\n * `assetRoute`;\n * - `onView:<id>` for each `views.panel` entry;\n * - `onFinder:<name>` for each `finders` entry;\n * - for each `services` entry, `onSourceAnalysis:<id>` and `onDesignTimeMount:<medium>`;\n * - and each event `activationEvents` lists.\n */\nexport function readVolterContributions(declared: unknown): VolterContributions {\n const entries: VolterContribution[] = [];\n const editors: VolterEditorDeclaration[] = [];\n const utilities: VolterUtilityDeclaration[] = [];\n const events: string[] = [];\n const errors: string[] = [];\n const kinds = record(declared);\n if (kinds === null) return { entries, editors, utilities, events, errors: ['`contributes.volter` must be an object of kinds, each a list of ./-relative modules.'] };\n const listed: [string, unknown][] = [];\n for (const [key, list] of Object.entries(kinds)) {\n if (key === 'page' || DECLARATION_KEYS.has(key)) continue;\n if (key === 'activationEvents') {\n if (!Array.isArray(list) || list.some((event) => typeof event !== 'string')) errors.push('`contributes.volter.activationEvents` must be a list of activation events.');\n else events.push(...(list as string[]));\n continue;\n }\n if (key !== 'views') { listed.push([key, list]); continue; }\n const containers = record(list);\n if (containers === null) { errors.push('`contributes.volter.views` must be an object of containers: `panel`, `statusbar`.'); continue; }\n for (const [container, views] of Object.entries(containers)) listed.push([`views.${container}`, views]);\n }\n for (const [key, list] of listed) {\n if (!Array.isArray(list)) { errors.push(`\\`contributes.volter.${key}\\` must be a list.`); continue; }\n for (const entry of list) {\n const refuse = (why: string): void => { errors.push(`\\`contributes.volter.${key}\\`: ${why}.`); };\n if (key === 'views.panel') {\n const view = readUtility(entry);\n if (typeof view === 'string') { refuse(view); continue; }\n utilities.push(view.declaration);\n entries.push({ key, entry: view.module, declared: view.declaration });\n events.push(`onView:${view.declaration.id}`);\n } else if (key === 'finders') {\n const finder = readFinder(entry);\n if (typeof finder === 'string') { refuse(finder); continue; }\n entries.push({ key, entry: finder.module, finder: finder.name });\n events.push(`onFinder:${finder.name}`);\n } else if (key === 'services') {\n const service = readService(entry);\n if (typeof service === 'string') { refuse(service); continue; }\n entries.push({ key, entry: service.module });\n if (service.sourceAnalyzer !== undefined) events.push(`onSourceAnalysis:${service.sourceAnalyzer}`);\n if (service.designTimeMount !== undefined) events.push(`onDesignTimeMount:${service.designTimeMount}`);\n } else if (key === 'editors') {\n // An editor's document module is a document contribution like any other; a kind or an asset route the package\n // registers in code names no module, and implies its activation events alone.\n const editor = readEditor(entry);\n if (typeof editor === 'string') { refuse(editor); continue; }\n if (editor.declaration) { editors.push(editor.declaration); events.push(`onCustomEditor:${editor.declaration.viewType}`); }\n if (editor.document !== undefined) { entries.push({ key, entry: editor.document }); events.push(`onDocument:${contributionIdFromPath(editor.document)}`); }\n if (editor.kind !== undefined) events.push(`onDocument:${editor.kind}`);\n for (const view of editor.views ?? []) events.push(`onDocument:${view}`);\n if (editor.assetRoute !== undefined) events.push(`onAssetViewer:${editor.assetRoute}`);\n } else if (typeof entry !== 'string') {\n refuse(`${JSON.stringify(entry)} is not a ./-relative module`);\n } else {\n entries.push({ key, entry });\n }\n }\n }\n return { entries, editors, utilities, events, errors };\n}\n\n/** `contributes[key]`, unchecked. */\nfunction contributed(packageJSON: Readonly<Record<string, unknown>>, key: string): unknown {\n return record(packageJSON['contributes'])?.[key];\n}\n\n/** The commands a package declares (`contributes.commands`), by id. */\nfunction commandIds(packageJSON: Readonly<Record<string, unknown>>): string[] {\n const commands = contributed(packageJSON, 'commands');\n return (Array.isArray(commands) ? commands : []).flatMap((command) => {\n const id = record(command)?.['command'];\n return typeof id === 'string' ? [id] : [];\n });\n}\n\n/**\n * A package's activation events, as Code-OSS forms an extension's: the explicit ones it lists in its top-level\n * `activationEvents`, `onCommand:<id>` for each `contributes.commands` entry, and the ones its `contributes.volter`\n * implies ({@link readVolterContributions}). One list governs the package's page half and its extension-host half, as\n * one Code-OSS extension's `main` and `browser` entries share theirs.\n */\nexport function activationEvents(packageJSON: Readonly<Record<string, unknown>>): readonly string[] {\n return [\n ...strings(packageJSON['activationEvents']),\n ...commandIds(packageJSON).map((id) => `onCommand:${id}`),\n ...readVolterContributions(contributed(packageJSON, 'volter') ?? {}).events,\n ];\n}\n\n/**\n * The commands a package's page half answers: those it declares (`contributes.commands`), less, in a package with an\n * extension-host half (`main` or `browser`), the ones its `activationEvents` name (`onCommand:<id>`), which that half\n * registers.\n */\nexport function pageCommandIds(packageJSON: Readonly<Record<string, unknown>>): string[] {\n const hosted = packageJSON['main'] !== undefined || packageJSON['browser'] !== undefined;\n const hostCommands = new Set(hosted ? strings(packageJSON['activationEvents']) : []);\n return commandIds(packageJSON).filter((id) => !hostCommands.has(`onCommand:${id}`));\n}\n\n/** `contributes.volter.page`, checked: one `./`-relative module, or none. */\nexport function readPageEntry(name: string, page: unknown): { readonly entry: string | null } | { readonly malformed: string } {\n if (page === undefined) return { entry: null };\n const listed = Array.isArray(page) ? page : null;\n if (listed === null || listed.length > 1 || (listed.length === 1 && (typeof listed[0] !== 'string' || !listed[0].startsWith('./') || listed[0].includes('..')))) {\n return {\n malformed:\n `${name}'s package.json#contributes.volter.page is ${JSON.stringify(page)}: it lists one page entry, ` +\n 'a ./-relative module without parent traversal that exports activate(context).',\n };\n }\n return { entry: (listed[0] as string | undefined) ?? null };\n}\n\n/** A declaration's one module (`serving`, `viewRoutes`: a one-entry list), unchecked; `undefined` when the package\n * declares none and `null` when the declaration is not a one-entry list. */\nexport function declaredModule(declared: unknown, key: 'serving' | 'viewRoutes'): unknown {\n const listed = record(declared)?.[key];\n if (listed === undefined) return undefined;\n return Array.isArray(listed) && listed.length === 1 ? listed[0] : null;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["record"]
7
+ }