@volter/live 0.5.212 → 0.5.213
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/BUNDLED_NOTICES +4 -4
- package/README.md +4 -1
- package/dist/asset-library.d.ts +98 -0
- package/dist/asset-library.js +7 -0
- package/dist/asset-library.js.map +7 -0
- package/dist/chunk-B2HUWFTT.js +25 -0
- package/dist/chunk-B2HUWFTT.js.map +7 -0
- package/dist/{chunk-7SZ3C4CC.js → chunk-IZJOOON2.js} +45 -8
- package/dist/chunk-IZJOOON2.js.map +7 -0
- package/dist/{chunk-Y5W77HYT.js → chunk-JDOIPALX.js} +38 -3
- package/dist/chunk-JDOIPALX.js.map +7 -0
- package/dist/{chunk-YPAOTPIF.js → chunk-JFAHP5CC.js} +19 -3
- package/dist/chunk-JFAHP5CC.js.map +7 -0
- package/dist/{chunk-SDIWRX5X.js → chunk-PC56TDHV.js} +5 -5
- package/dist/chunk-PC56TDHV.js.map +7 -0
- package/dist/{chunk-USXOIBVX.js → chunk-WIAH4XZE.js} +5 -4
- package/dist/chunk-WIAH4XZE.js.map +7 -0
- package/dist/client.d.ts +10 -4
- package/dist/client.js +2 -1
- package/dist/discovery.js +2 -2
- package/dist/editor.d.ts +11 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +18 -51
- package/dist/index.js.map +3 -3
- package/dist/product-locator.d.ts +2 -2
- package/dist/product-locator.js +2 -2
- package/dist/registry-format.d.ts +31 -3
- package/dist/registry-format.js +13 -3
- package/dist/session.d.ts +4 -15
- package/dist/volter-manifest.js +1 -1
- package/dist/workbench-locator.js +2 -2
- package/package.json +7 -3
- package/src/asset-library.ts +104 -0
- package/src/client.ts +48 -7
- package/src/discovery.ts +2 -2
- package/src/editor.ts +11 -3
- package/src/index.ts +2 -1
- package/src/product-locator.ts +2 -2
- package/src/registry-format.ts +68 -5
- package/src/session.ts +6 -86
- package/dist/chunk-7SZ3C4CC.js.map +0 -7
- package/dist/chunk-SDIWRX5X.js.map +0 -7
- package/dist/chunk-USXOIBVX.js.map +0 -7
- package/dist/chunk-Y5W77HYT.js.map +0 -7
- package/dist/chunk-YPAOTPIF.js.map +0 -7
|
@@ -54,14 +54,22 @@ function readUtility(value) {
|
|
|
54
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
55
|
return { declaration: { id, title: title.trim() }, module };
|
|
56
56
|
}
|
|
57
|
+
function readStatusItem(value) {
|
|
58
|
+
const { id, name, alignment, priority, module } = record(value) ?? {};
|
|
59
|
+
if (typeof id !== "string" || id === "" || typeof name !== "string" || name.trim() === "" || typeof module !== "string") return "an entry is { id, name, alignment, priority?, module }, with a non-empty id, name and module";
|
|
60
|
+
if (alignment !== "left" && alignment !== "right") return `${id}'s alignment is 'left' or 'right'`;
|
|
61
|
+
if (priority !== void 0 && (typeof priority !== "number" || !Number.isFinite(priority))) return `${id}'s priority is a number`;
|
|
62
|
+
return { declaration: { id, name: name.trim(), alignment, priority: priority ?? 0 }, module };
|
|
63
|
+
}
|
|
57
64
|
function readVolterContributions(declared) {
|
|
58
65
|
const entries = [];
|
|
59
66
|
const editors = [];
|
|
60
67
|
const utilities = [];
|
|
68
|
+
const statusItems = [];
|
|
61
69
|
const events = [];
|
|
62
70
|
const errors = [];
|
|
63
71
|
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."] };
|
|
72
|
+
if (kinds === null) return { entries, editors, utilities, statusItems, events, errors: ["`contributes.volter` must be an object of kinds, each a list of ./-relative modules."] };
|
|
65
73
|
const listed = [];
|
|
66
74
|
for (const [key, list] of Object.entries(kinds)) {
|
|
67
75
|
if (key === "page" || DECLARATION_KEYS.has(key)) continue;
|
|
@@ -99,6 +107,14 @@ function readVolterContributions(declared) {
|
|
|
99
107
|
utilities.push(view.declaration);
|
|
100
108
|
entries.push({ key, entry: view.module, declared: view.declaration });
|
|
101
109
|
events.push(`onView:${view.declaration.id}`);
|
|
110
|
+
} else if (key === "views.statusbar") {
|
|
111
|
+
const item = readStatusItem(entry);
|
|
112
|
+
if (typeof item === "string") {
|
|
113
|
+
refuse(item);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
statusItems.push(item.declaration);
|
|
117
|
+
entries.push({ key, entry: item.module, statusItem: item.declaration });
|
|
102
118
|
} else if (key === "finders") {
|
|
103
119
|
const finder = readFinder(entry);
|
|
104
120
|
if (typeof finder === "string") {
|
|
@@ -140,7 +156,7 @@ function readVolterContributions(declared) {
|
|
|
140
156
|
}
|
|
141
157
|
}
|
|
142
158
|
}
|
|
143
|
-
return { entries, editors, utilities, events, errors };
|
|
159
|
+
return { entries, editors, utilities, statusItems, events, errors };
|
|
144
160
|
}
|
|
145
161
|
function readPageEntry(name, page) {
|
|
146
162
|
if (page === void 0) return { entry: null };
|
|
@@ -199,4 +215,4 @@ export {
|
|
|
199
215
|
readVolterManifest,
|
|
200
216
|
declaredContributions
|
|
201
217
|
};
|
|
202
|
-
//# sourceMappingURL=chunk-
|
|
218
|
+
//# sourceMappingURL=chunk-JFAHP5CC.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/**\n * One status-bar item a package declares under `contributes.volter.views.statusbar`: `{ id, name, alignment, priority,\n * module }`, the fields of Code-OSS's `contributes.statusBarItems` (`api/browser/statusBarExtensionPoint.ts`), whose\n * `text` and `command` a page-rendered item replaces with its `module`. The workbench adds its `IStatusbarService` entry\n * from this before any of the package's code loads (`workbench/src/volterStatus.ts`); the module's default export\n * fills it once the package activates.\n */\nexport interface VolterStatusItemDeclaration {\n /** Unique within the package, as Code-OSS's item `id` is. */\n readonly id: string;\n /** What a person calls it: the status bar's own `Hide <name>` menu and the entry's aria label. */\n readonly name: string;\n readonly alignment: 'left' | 'right';\n /** Code-OSS's priority: a higher value is further left, on either side. */\n readonly priority: number;\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, a status-bar item's or a finder's own statement. */\nexport interface VolterContribution {\n readonly key: string;\n readonly entry: string;\n readonly declared?: VolterUtilityDeclaration;\n readonly statusItem?: VolterStatusItemDeclaration;\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 status-bar items. */\n readonly statusItems: readonly VolterStatusItemDeclaration[];\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/** One `contributes.volter.views.statusbar` entry, read. */\nfunction readStatusItem(value: unknown): { readonly declaration: VolterStatusItemDeclaration; readonly module: string } | string {\n const { id, name, alignment, priority, module } = record(value) ?? {};\n if (typeof id !== 'string' || id === '' || typeof name !== 'string' || name.trim() === '' || typeof module !== 'string') return 'an entry is { id, name, alignment, priority?, module }, with a non-empty id, name and module';\n if (alignment !== 'left' && alignment !== 'right') return `${id}'s alignment is 'left' or 'right'`;\n if (priority !== undefined && (typeof priority !== 'number' || !Number.isFinite(priority))) return `${id}'s priority is a number`;\n return { declaration: { id, name: name.trim(), alignment, priority: priority ?? 0 }, 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 statusItems: VolterStatusItemDeclaration[] = [];\n const events: string[] = [];\n const errors: string[] = [];\n const kinds = record(declared);\n if (kinds === null) return { entries, editors, utilities, statusItems, 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 === 'views.statusbar') {\n // A status-bar item implies no activation event, as Code-OSS's `statusBarItems` implies none: its entry stands\n // from the manifest, and its module fills it once the package activates on another event.\n const item = readStatusItem(entry);\n if (typeof item === 'string') { refuse(item); continue; }\n statusItems.push(item.declaration);\n entries.push({ key, entry: item.module, statusItem: item.declaration });\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, statusItems, 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
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
installedPackageDir
|
|
3
|
-
} from "./chunk-7WKVJGHZ.js";
|
|
4
1
|
import {
|
|
5
2
|
declaredContributions,
|
|
6
3
|
readVolterManifest
|
|
7
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JFAHP5CC.js";
|
|
5
|
+
import {
|
|
6
|
+
installedPackageDir
|
|
7
|
+
} from "./chunk-7WKVJGHZ.js";
|
|
8
8
|
|
|
9
9
|
// src/product-locator.ts
|
|
10
10
|
import { existsSync } from "node:fs";
|
|
@@ -186,4 +186,4 @@ export {
|
|
|
186
186
|
declaredProducts,
|
|
187
187
|
resolveProductForProject
|
|
188
188
|
};
|
|
189
|
-
//# sourceMappingURL=chunk-
|
|
189
|
+
//# sourceMappingURL=chunk-PC56TDHV.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/product-locator.ts"],
|
|
4
|
+
"sourcesContent": ["\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { installedPackageDir } from './installed-package';\nimport { declaredContributions, type ProductDeclaration, readVolterManifest } from './volter-manifest';\n\n\nexport const PRODUCT_DECLARATION_KEY = 'contributes.volter.product';\n\n/** Light or dark \u2014 the two the workbench's own `ColorScheme` has plain names\n * for, and the only two a product needs to state (a high-contrast scheme is a\n * person's accessibility choice, never a product's declaration). */\nexport type ProductColorTheme = 'dark' | 'light';\n\n\nexport interface ProductWorkbench {\n /** The GitHub Release tag on `volter-ai/code-oss`. */\n readonly release: string;\n /** The sha256 of that release's tarball asset, hex. */\n readonly tarballSha256: string;\n}\n\n/** A product package, as everything outside it needs to know it. */\nexport interface ProductIdentity {\n\n readonly name: string;\n /** Its version, reported beside the workbench by the editor's `status` command. */\n readonly version: string;\n\n readonly command: string;\n /** The name a person sees \u2014 `contributes.volter.product.displayName`. */\n readonly displayName: string;\n /**\n * `contributes.volter.product.upgrade: true` \u2014 its command has `upgrade [version]`\n * (the product CLI's own), so a pinned-engine refusal\n * may tell a person to run it. Optional: a product that says nothing has none.\n */\n readonly upgrade?: boolean;\n /**\n * `contributes.volter.product.adapterRequired: true` \u2014 a project this product opens must have its own\n * adapter module (`editor/volter.adapter.ts`), because the product's layout and document\n * finders are declared there and the native default shows none of them. Such a product refuses\n * a project without one. Optional: a product that says nothing opens it on the native default.\n */\n readonly adapterRequired?: boolean;\n /** Its package root, absolute. */\n readonly dir: string;\n /**\n * Its ONE source entry, package-relative and POSIX (`./src/index.ts`). That\n * entry IS the product's frame entry: it composes and re-exports `mountVolter`,\n * which is the name the fork's contribution reads off the served module.\n */\n readonly entry: string;\n /**\n * The packages this product mounts, in order \u2014 `contributes.volter.product.composes`. The ONE statement of\n * the composition: the session reads it here for the packages it installs and serves, the catalog and the\n * serving doors.\n */\n readonly composes: readonly string[];\n\n readonly colorTheme: ProductColorTheme;\n /** WHICH WORKBENCH THIS PRODUCT IS \u2014 see {@link ProductWorkbench}. */\n readonly workbench: ProductWorkbench | null;\n /**\n * The ONE LINE that installs this product and starts a project in it \u2014\n * `contributes.volter.product.install` (`npx <name> create my-project`). A limited view quotes\n * it wherever it cannot do what the local editor does (its agent answers with it, and every\n * route it does not carry names it), so it is a declaration read without running the product.\n * An undeclared one is `npx <name> create my-project`, which is what every product's `create`\n * verb accepts.\n */\n readonly install: string;\n}\n\n/** What a project without a product is told to add: the declaration this module reads, naming no package. */\nexport const PRODUCT_DECLARATION_HINT =\n `a product package as a dev dependency: one whose package.json declares \\`${PRODUCT_DECLARATION_KEY}\\``;\n\nconst PRODUCT_COLOR_THEMES: readonly ProductColorTheme[] = ['dark', 'light'];\n\n/**\n * Read one product package's declaration, or `null` when the manifest is not a\n * product's. Throws when it declares `contributes.volter.product` and the declaration is\n * unusable \u2014 a half-written product must be named, never skipped.\n */\nexport function readProductManifest(packageDir: string): ProductIdentity | null {\n const manifestPath = join(packageDir, 'package.json');\n const manifest = readVolterManifest(manifestPath);\n const declared = manifest?.product;\n if (manifest === null || declared === undefined) return null;\n const entry = declared.entry;\n if (typeof entry !== 'string' || !entry.startsWith('./'))\n throw new Error(\n `${manifestPath} declares ${PRODUCT_DECLARATION_KEY} but its \"entry\" is ` +\n `${JSON.stringify(entry)}. It must be a ./-relative module \u2014 the product's ONE source ` +\n 'entry, which is also its frame entry (e.g. \"./src/index.ts\").',\n );\n const resolved = join(packageDir, entry);\n if (!existsSync(resolved))\n throw new Error(\n `${manifestPath} declares ${PRODUCT_DECLARATION_KEY}.entry ${JSON.stringify(entry)}, ` +\n `which does not exist (${resolved}).`,\n );\n const colorTheme = declared.colorTheme;\n // REQUIRED, like `entry`, and for the same reason: a product that does not\n // say which way round it paints gets the workbench's web default, which is\n // LIGHT, and its cover is white until its real theme loads. There is no\n // defensible default to invent here \u2014 a dark product and a light product are\n // both ordinary \u2014 so an unstated one is named rather than guessed.\n if (typeof colorTheme !== 'string' || !PRODUCT_COLOR_THEMES.includes(colorTheme as never))\n throw new Error(\n `${manifestPath} declares ${PRODUCT_DECLARATION_KEY} but its \"colorTheme\" is ` +\n `${JSON.stringify(colorTheme)}. It must be ${PRODUCT_COLOR_THEMES.map((one) =>\n JSON.stringify(one),\n ).join(' or ')} \u2014 which way round this product paints, read before any of its code ` +\n \"runs so the workbench's first frame is already the product's own background.\",\n );\n // REQUIRED, for the same reason as `entry`: the kit names verbs in every\n // message it writes, and there is no command to name but the product's own.\n const composes = productComposes(manifestPath, declared);\n const bin = manifest.bin;\n const commands = bin !== null && typeof bin === 'object' ? Object.keys(bin) : [];\n if (commands.length !== 1)\n throw new Error(\n `${manifestPath} declares ${PRODUCT_DECLARATION_KEY} but its \"bin\" names ` +\n `${commands.length === 0 ? 'no command' : `${commands.length} commands`}. A product has ` +\n 'exactly one command \u2014 the one every session message tells a person to run.',\n );\n const displayName = declared.displayName;\n if (typeof displayName !== 'string' || displayName.trim() === '')\n throw new Error(\n `${manifestPath} declares ${PRODUCT_DECLARATION_KEY} but its \"displayName\" is ` +\n `${JSON.stringify(displayName)}. It must be the name a person sees (e.g. \"Volter Editor\").`,\n );\n const name = manifest.name ?? packageDir;\n const install = declared.install;\n if (install !== undefined && (typeof install !== 'string' || install.trim() === ''))\n throw new Error(\n `${manifestPath} declares ${PRODUCT_DECLARATION_KEY} but its \"install\" is ` +\n `${JSON.stringify(install)}. It is the one line that installs this product and starts a ` +\n `project (e.g. \"npx ${name} create my-project\"), or absent.`,\n );\n return {\n name,\n version: manifest.version ?? 'unknown',\n command: commands[0]!,\n displayName,\n upgrade: declared.upgrade === true,\n adapterRequired: declared.adapterRequired === true,\n dir: packageDir,\n entry,\n composes,\n colorTheme: colorTheme as ProductColorTheme,\n // A private source product may use an explicitly selected matching checkout.\n // Public packages must always carry a downloadable, checksummed workbench.\n workbench: manifest.private && declared.workbench === undefined\n ? null : readProductWorkbench(manifestPath, declared.workbench),\n install: typeof install === 'string' ? install.trim() : `npx ${name} create my-project`,\n };\n}\n\n/** A product declaration's `composes`, checked: the packages it mounts, by name, in order. The\n * build's composition module and the session read it through this one check. */\nexport function productComposes(manifestPath: string, declared: ProductDeclaration): string[] {\n const composes = declared.composes;\n if (!Array.isArray(composes) || composes.some((name) => typeof name !== 'string' || name === ''))\n throw new Error(\n `${manifestPath} declares ${PRODUCT_DECLARATION_KEY} but its \"composes\" is ` +\n `${JSON.stringify(composes)}. It must list the packages this product mounts, by name ` +\n '(e.g. [\"<package>\"]); each is a dependency of the product package.',\n );\n return composes as string[];\n}\n\n/** The sha256 a release pins its tarball with, as `BUILD.json` writes it. */\nconst SHA256_HEX = /^[0-9a-f]{64}$/;\n\n/**\n * REQUIRED, like `entry` and `colorTheme`, and for the sharpest reason of all\n * three of them: a product that does not say which workbench it is cannot be INSTALLED\n * \u2014 `npx @volter/<product> create <name>` on a machine with nothing else on it\n * has no other way to find the bytes it runs in, and the person is left writing\n * a path to a directory they would have to build first. There is no default to\n * invent (the tag names a fork commit nobody can guess), so an unstated one is\n * named rather than guessed.\n */\nfunction readProductWorkbench(manifestPath: string, declared: unknown): ProductWorkbench {\n const example =\n ' \"contributes\": { \"volter\": { \"product\": { \"workbench\": { \"release\": \"<product>-<fork sha 12>-<platform>\", ' +\n '\"tarballSha256\": \"<64 hex>\" } } } }\\n' +\n '`node scripts/workbench/build-release.mjs --publish --out <release dir>` cuts the release ' +\n 'and prints exactly that block.';\n if (typeof declared !== 'object' || declared === null || Array.isArray(declared))\n throw new Error(\n `${manifestPath} declares ${PRODUCT_DECLARATION_KEY} but its \"workbench\" is ` +\n `${JSON.stringify(declared)}. A product IS the Code-OSS workbench it was compiled into, ` +\n `so it names the published release those bytes are:\\n${example}`,\n );\n const platforms = declared as Record<string, unknown>;\n if (!('release' in platforms) && !('tarballSha256' in platforms)) {\n const machine = `${process.platform}-${process.arch}`;\n const declaredHere = platforms[machine];\n if (declaredHere === undefined)\n throw new Error(\n `${manifestPath}'s ${PRODUCT_DECLARATION_KEY}.workbench declares releases for ` +\n `${Object.keys(platforms).join(', ') || 'no platform'} and this machine is ${machine}. A ` +\n \"Code-OSS server package carries its own platform's node binary and native modules, so \" +\n `there is nothing this product can run in here until a ${machine} release is cut:\\n` +\n ` node scripts/workbench/build-release.mjs --product <id> --platform ${machine} --checkout <fork dir> --publish`,\n );\n return readPlatformWorkbench(manifestPath, declaredHere, example);\n }\n return readPlatformWorkbench(manifestPath, declared, example);\n}\n\nfunction readPlatformWorkbench(manifestPath: string, declared: unknown, example: string): ProductWorkbench {\n if (typeof declared !== 'object' || declared === null || Array.isArray(declared))\n throw new Error(\n `${manifestPath}'s ${PRODUCT_DECLARATION_KEY}.workbench names ${JSON.stringify(declared)} ` +\n `for this platform, which is not a release:\\n${example}`,\n );\n const record = declared as Record<string, unknown>;\n const extra = Object.keys(record).filter((key) => key !== 'release' && key !== 'tarballSha256');\n if (extra.length > 0)\n throw new Error(\n `${manifestPath}'s ${PRODUCT_DECLARATION_KEY}.workbench carries ` +\n `${extra.map((key) => `\"${key}\"`).join(', ')}, which this declaration has no meaning for. ` +\n `It names the release and the pin, and nothing else:\\n${example}`,\n );\n const release = record['release'];\n if (typeof release !== 'string' || release.trim() === '')\n throw new Error(\n `${manifestPath}'s ${PRODUCT_DECLARATION_KEY}.workbench names no \"release\" \u2014 the GitHub ` +\n `Release tag its workbench was published under:\\n${example}`,\n );\n const tarballSha256 = record['tarballSha256'];\n if (typeof tarballSha256 !== 'string' || !SHA256_HEX.test(tarballSha256))\n throw new Error(\n `${manifestPath}'s ${PRODUCT_DECLARATION_KEY}.workbench has tarballSha256 ` +\n `${JSON.stringify(tarballSha256)}, which is not 64 hex characters. It is the PIN \u2014 the ` +\n 'hash the downloaded tarball is checked against before a byte of it is extracted, so it ' +\n `is never approximate:\\n${example}`,\n );\n return { release, tarballSha256 };\n}\n\n/**\n * A product's SHORT id \u2014 `@<scope>/<name>` \u2192 `<name>`.\n *\n * It is the product's own `product({ id })`, the directory its workbench half\n * lives in (`packages/<id>/workbench`), the `--product` flag the overlay and the\n * release build take, and what a release records in `BUILD.json`. One derivation\n * rather than four literals: the package name is the only place the product is\n * NAMED, and everything else is that name's last segment.\n */\nexport function workbenchProductId(packageName: string): string {\n return packageName.split('/').pop() ?? packageName;\n}\n\n/** A product's entry as a path relative to `fromDir`, POSIX \u2014 the spelling a\n * Vite manifest key and a dev-server URL both use. */\nexport function productEntryPath(product: ProductIdentity, fromDir: string): string {\n const absolute = join(product.dir, product.entry);\n const prefix = fromDir.endsWith('/') ? fromDir : `${fromDir}/`;\n const relative = absolute.startsWith(prefix) ? absolute.slice(prefix.length) : absolute;\n return relative.split('\\\\').join('/');\n}\n\n/** Every `@volter/*` this project declares, in either section, sorted. */\nfunction declaredVolterPackages(projectRoot: string): string[] {\n const manifest = readVolterManifest(join(projectRoot, 'package.json'));\n return (manifest?.dependencyNames ?? []).filter((name) => name.startsWith('@volter/')).sort();\n}\n\n/**\n * The packages `product` mounts that are installed and contribute: its `contributes.volter.product.composes`,\n * each resolved from the product's own directory and kept when its manifest declares\n * a `contributes.volter` object (its serving half, `contributes.volter.serving`, may be all a package contributes).\n */\nexport function productComposedPackages(product: ProductIdentity): string[] {\n return product.composes.filter((name) => {\n const dir = installedPackageDir(product.dir, name);\n if (dir === null) return false;\n const manifest = readVolterManifest(join(dir, 'package.json'));\n return declaredContributions(manifest) !== null;\n });\n}\n\n/** The products this project declares AND resolves, in declaration order. */\nexport function declaredProducts(projectRoot: string): ProductIdentity[] {\n const found: ProductIdentity[] = [];\n for (const name of declaredVolterPackages(projectRoot)) {\n const dir = installedPackageDir(projectRoot, name);\n if (dir === null) continue;\n const product = readProductManifest(dir);\n if (product !== null) found.push(product);\n }\n return found;\n}\n\n/**\n * THE product this project opens in, or a throw naming what is wrong.\n *\n * The refusals are the whole point: a project with none and a project with two\n * are both states a person can be in, and neither has an answer this code may\n * invent.\n */\nexport function resolveProductForProject(projectRoot: string): ProductIdentity {\n const products = declaredProducts(projectRoot);\n if (products.length === 1) return products[0] as ProductIdentity;\n if (products.length === 0)\n throw new Error(\n `${projectRoot} declares no editor product, so there is no editor to open it in.\\n` +\n 'The installed product supplies the editor,\\n' +\n 'and which one runs is what the project installed, never a flag.\\n' +\n `For THIS folder, install ${PRODUCT_DECLARATION_HINT},\\n` +\n \"then run that product's `edit` command again. For a NEW project, the product's own `create` verb makes it.\",\n );\n throw new Error(\n `${projectRoot} declares ${products.length} editor products \u2014 ` +\n `${products.map((product) => product.name).join(' and ')}.\\n` +\n 'One page runs one product, and nothing here may choose between them. Remove the one you\\n' +\n 'are not building with:\\n' +\n products.map((product) => ` npm uninstall ${product.name}`).join('\\n'),\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readLiveRegisteredSessions,
|
|
3
|
-
servedProjectAnswer
|
|
4
|
-
|
|
3
|
+
servedProjectAnswer,
|
|
4
|
+
sessionFetch
|
|
5
|
+
} from "./chunk-JDOIPALX.js";
|
|
5
6
|
|
|
6
7
|
// src/discovery.ts
|
|
7
8
|
var EDITOR_SESSION_DISCOVERY_TIMEOUT_MS = 2e3;
|
|
@@ -28,7 +29,7 @@ function withTimeout(promise, ms, label) {
|
|
|
28
29
|
});
|
|
29
30
|
}
|
|
30
31
|
async function fetchJson(url, timeoutMs) {
|
|
31
|
-
const res = await
|
|
32
|
+
const res = await sessionFetch(url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
32
33
|
if (!res.ok) throw new Error(`GET /__editor/project returned HTTP ${res.status}`);
|
|
33
34
|
return await res.json();
|
|
34
35
|
}
|
|
@@ -78,4 +79,4 @@ export {
|
|
|
78
79
|
withTimeout,
|
|
79
80
|
HttpSessionDiscovery
|
|
80
81
|
};
|
|
81
|
-
//# sourceMappingURL=chunk-
|
|
82
|
+
//# sourceMappingURL=chunk-WIAH4XZE.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/discovery.ts"],
|
|
4
|
+
"sourcesContent": ["/** Registered-session discovery; never selects another project's session. */\nimport { readLiveRegisteredSessions, servedProjectAnswer, sessionFetch } from './registry-format.js';\nexport { servedProjectAnswer } from './registry-format.js';\n\nexport const EDITOR_SESSION_DISCOVERY_TIMEOUT_MS = 2000;\n\nexport const EDITOR_PROBE_TIMEOUT_MS = 1500;\n\nexport class EditorTimeoutError extends Error {\n constructor(label: string, ms: number) {\n super(`${label} timed out after ${ms}ms`);\n this.name = 'EditorTimeoutError';\n }\n}\n\nexport function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {\n return new Promise<T>((resolvePromise, reject) => {\n const timer = setTimeout(() => reject(new EditorTimeoutError(label, ms)), ms);\n promise.then(\n (v) => {\n clearTimeout(timer);\n resolvePromise(v);\n },\n (err) => {\n clearTimeout(timer);\n reject(err instanceof Error ? err : new Error(String(err)));\n },\n );\n });\n}\n\nexport interface EditorSessionInfo {\n /** The port this session's dev server is bound to. */\n port: number;\n /** Canonical project root path currently open, or null when none. */\n project: string | null;\n /** Dev-server process id, when known from the local session registry (null for an unregistered server the caller only probed by port). */\n pid: number | null;\n /** Exact explicitly targeted editor origin/base URL, including protocol and host. */\n url?: string;\n /**\n * Why this server cannot DESCRIBE the `project` it is serving \u2014 its\n * manifest's own parse/validation failure, naming the failing key. `null`\n * when the project reads fine, and `undefined` from a probe that did not ask\n * See {@link servedProjectAnswer}: a session in\n * this state is still THIS project's session, and callers must report the\n * reason rather than treat it as no session at all.\n */\n manifestError?: string | null;\n}\n\nasync function fetchJson(url: string, timeoutMs: number): Promise<unknown> {\n const res = await sessionFetch(url, { signal: AbortSignal.timeout(timeoutMs) });\n if (!res.ok) throw new Error(`GET /__editor/project returned HTTP ${res.status}`);\n return await res.json();\n}\n\nfunction baseUrl(session: EditorSessionInfo): string {\n return session.url ?? `http://127.0.0.1:${session.port}`;\n}\n\nexport interface SessionListingTransport { listSessions(timeoutMs: number): Promise<EditorSessionInfo[]>; }\nexport class HttpSessionDiscovery implements SessionListingTransport {\n async listSessions(timeoutMs: number): Promise<EditorSessionInfo[]> {\n const registered = readLiveRegisteredSessions();\n const perProbeTimeout = Math.min(EDITOR_PROBE_TIMEOUT_MS, Math.max(200, timeoutMs));\n const failures: string[] = [];\n const probes = await Promise.all(\n registered.map(async (s) => {\n try {\n const body = await fetchJson(\n `${baseUrl({ port: s.port, project: null, pid: s.pid })}/__editor/project`,\n perProbeTimeout,\n );\n const served = servedProjectAnswer(body);\n const info: EditorSessionInfo = {\n port: s.port,\n project: served.path,\n pid: s.pid,\n manifestError: served.manifestError,\n };\n return info;\n } catch (error) {\n // Name the step that did not answer, not a guess at why: an aborted fetch here means\n // the server took the request to /__editor/project and sent nothing back in time.\n const timedOut = (error as { name?: string } | null)?.name === 'TimeoutError';\n const detail = timedOut\n ? `GET /__editor/project sent no answer within ${perProbeTimeout} ms (pid ${s.pid})`\n : error instanceof Error ? `${error.name}: ${error.message}` : String(error);\n failures.push(`port ${s.port}: ${detail}`);\n return undefined;\n }\n }),\n );\n const sessions = probes.filter((p): p is EditorSessionInfo => p !== undefined);\n // A readable registry with registered live processes is not an empty\n // registry just because every HTTP discovery request failed. Keep any\n // verified sessions usable, but refuse an entirely unanswered inventory\n // rather than telling the caller to launch a second editor.\n if (registered.length > 0 && sessions.length === 0) {\n throw new Error(`Registered editor sessions could not be inspected: ${failures.join('; ')}`);\n }\n return sessions;\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;AAIO,IAAM,sCAAsC;AAE5C,IAAM,0BAA0B;AAEhC,IAAM,qBAAN,cAAiC,MAAM;AAAA,EAC5C,YAAY,OAAe,IAAY;AACrC,UAAM,GAAG,KAAK,oBAAoB,EAAE,IAAI;AACxC,SAAK,OAAO;AAAA,EACd;AACF;AAEO,SAAS,YAAe,SAAqB,IAAY,OAA2B;AACzF,SAAO,IAAI,QAAW,CAAC,gBAAgB,WAAW;AAChD,UAAM,QAAQ,WAAW,MAAM,OAAO,IAAI,mBAAmB,OAAO,EAAE,CAAC,GAAG,EAAE;AAC5E,YAAQ;AAAA,MACN,CAAC,MAAM;AACL,qBAAa,KAAK;AAClB,uBAAe,CAAC;AAAA,MAClB;AAAA,MACA,CAAC,QAAQ;AACP,qBAAa,KAAK;AAClB,eAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,MAC5D;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAsBA,eAAe,UAAU,KAAa,WAAqC;AACzE,QAAM,MAAM,MAAM,aAAa,KAAK,EAAE,QAAQ,YAAY,QAAQ,SAAS,EAAE,CAAC;AAC9E,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,uCAAuC,IAAI,MAAM,EAAE;AAChF,SAAO,MAAM,IAAI,KAAK;AACxB;AAEA,SAAS,QAAQ,SAAoC;AACnD,SAAO,QAAQ,OAAO,oBAAoB,QAAQ,IAAI;AACxD;AAGO,IAAM,uBAAN,MAA8D;AAAA,EACnE,MAAM,aAAa,WAAiD;AAClE,UAAM,aAAa,2BAA2B;AAC9C,UAAM,kBAAkB,KAAK,IAAI,yBAAyB,KAAK,IAAI,KAAK,SAAS,CAAC;AAClF,UAAM,WAAqB,CAAC;AAC5B,UAAM,SAAS,MAAM,QAAQ;AAAA,MAC3B,WAAW,IAAI,OAAO,MAAM;AAC1B,YAAI;AACF,gBAAM,OAAO,MAAM;AAAA,YACjB,GAAG,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,MAAM,KAAK,EAAE,IAAI,CAAC,CAAC;AAAA,YACvD;AAAA,UACF;AACA,gBAAM,SAAS,oBAAoB,IAAI;AACvC,gBAAM,OAA0B;AAAA,YAC9B,MAAM,EAAE;AAAA,YACR,SAAS,OAAO;AAAA,YAChB,KAAK,EAAE;AAAA,YACP,eAAe,OAAO;AAAA,UACxB;AACA,iBAAO;AAAA,QACT,SAAS,OAAO;AAGd,gBAAM,WAAY,OAAoC,SAAS;AAC/D,gBAAM,SAAS,WACX,+CAA+C,eAAe,YAAY,EAAE,GAAG,MAC/E,iBAAiB,QAAQ,GAAG,MAAM,IAAI,KAAK,MAAM,OAAO,KAAK,OAAO,KAAK;AAC7E,mBAAS,KAAK,QAAQ,EAAE,IAAI,KAAK,MAAM,EAAE;AACzC,iBAAO;AAAA,QACT;AAAA,MACF,CAAC;AAAA,IACH;AACA,UAAM,WAAW,OAAO,OAAO,CAAC,MAA8B,MAAM,MAAS;AAK7E,QAAI,WAAW,SAAS,KAAK,SAAS,WAAW,GAAG;AAClD,YAAM,IAAI,MAAM,sDAAsD,SAAS,KAAK,IAAI,CAAC,EAAE;AAAA,IAC7F;AACA,WAAO;AAAA,EACT;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/client.d.ts
CHANGED
|
@@ -139,10 +139,13 @@ export declare class EditorClient {
|
|
|
139
139
|
toggleCommandPalette(): Promise<void>;
|
|
140
140
|
toggleConsole(): Promise<void>;
|
|
141
141
|
/** Switch the editor's NAMED WORKSPACE — the task-named layout memory
|
|
142
|
-
* (`design`/`animate`/`look`, or one a package contributes).
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
setWorkspace(workspace: EditorWorkspaceName): Promise<
|
|
142
|
+
* (`design`/`animate`/`look`, or one a package contributes). Answers the workspace now active and whether its dock
|
|
143
|
+
* had rebuilt within the command's wait (`applied`): when it had, a following capture photographs the arrangement
|
|
144
|
+
* that was asked for. */
|
|
145
|
+
setWorkspace(workspace: EditorWorkspaceName): Promise<{
|
|
146
|
+
readonly workspace: EditorWorkspaceName;
|
|
147
|
+
readonly applied: boolean;
|
|
148
|
+
}>;
|
|
146
149
|
/** Choose a STYLE (`volter.style`) — its material, icon set and type, and the colour theme it
|
|
147
150
|
* was drawn with (`classic`/`glass`/`maya`/`substance`, or one a package the project or
|
|
148
151
|
* product composes carries). */
|
|
@@ -321,6 +324,9 @@ export declare class EditorClient {
|
|
|
321
324
|
}): Promise<ProjectInfo>;
|
|
322
325
|
openProject(path: string): Promise<void>;
|
|
323
326
|
getProject(): Promise<ProjectInfo | null>;
|
|
327
|
+
/** One `/__editor/asset-library/<route>` request, for `editor.assetLibrary` (`asset-library.ts`): a GET's fields as
|
|
328
|
+
* its query, a POST's as its JSON body. A refusal throws the route's own error. */
|
|
329
|
+
assetLibraryRequest<T>(method: 'GET' | 'POST', route: string, fields: object): Promise<T>;
|
|
324
330
|
listRecentProjects(): Promise<RecentProject[]>;
|
|
325
331
|
/**
|
|
326
332
|
* The document table the host resolved — every scene, prefab, page, model,
|
package/dist/client.js
CHANGED
package/dist/discovery.js
CHANGED
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
EditorTimeoutError,
|
|
5
5
|
HttpSessionDiscovery,
|
|
6
6
|
withTimeout
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-WIAH4XZE.js";
|
|
8
8
|
import {
|
|
9
9
|
servedProjectAnswer
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-JDOIPALX.js";
|
|
11
11
|
export {
|
|
12
12
|
EDITOR_PROBE_TIMEOUT_MS,
|
|
13
13
|
EDITOR_SESSION_DISCOVERY_TIMEOUT_MS,
|
package/dist/editor.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Modeling executes in the editor tab; this client owns no model state. */
|
|
3
3
|
import type { ActiveDocumentCapture, AssetKind, AssetPreviewCapture, AssetPreviewOptions, AssetPreviewShotSetDefinition, AssetPreviewSource, CaptureDimensions, DocumentLookOutcome, StageFrameCostReading, EditorChromeCapture, EditorChromeCaptureOptions, EditorState, EditorView, EditorWorkspaceName, InspectedFieldWrite, InspectedHierarchy, InspectedInspection, LabeledShotSetCapture, PresentedEditorView, ShadingMode, StructureOp, StructureOpOptions, StructureOpResult, ViewPreset, ViewportCapture } from '@volter/sdk';
|
|
4
4
|
import type { EditorClient, HistoryStep, OpenedDocument } from './client.js';
|
|
5
|
+
import { LiveAssetLibrary } from './asset-library.js';
|
|
5
6
|
import { LiveEditorDocument } from './editor-document.js';
|
|
6
7
|
/** A panel `showPanel` can focus: the console, the build surface, or any key
|
|
7
8
|
* the editor's own static-panel registry holds (`hierarchy`, `asset-library`,
|
|
@@ -20,6 +21,9 @@ export declare class LiveEditor {
|
|
|
20
21
|
* such as header, shelf, rail, outliner, utility and area. Targets outside the scope are refused.
|
|
21
22
|
* See `@volter/sdk`'s editor-document-probe for scope and gesture contracts. */
|
|
22
23
|
readonly document: LiveEditorDocument;
|
|
24
|
+
/** The asset library: search a source, list an asset's files, download one into the project with its license
|
|
25
|
+
* recorded (`asset-library.ts`). */
|
|
26
|
+
readonly assetLibrary: LiveAssetLibrary;
|
|
23
27
|
constructor(client: EditorClient);
|
|
24
28
|
/** A verb a composed package contributes (`<package>-<verb>`), waited on for its own row's budget. */
|
|
25
29
|
contributedVerb<T extends object = Record<string, unknown>>(type: string, fields?: Record<string, unknown>): Promise<T>;
|
|
@@ -125,7 +129,10 @@ export declare class LiveEditor {
|
|
|
125
129
|
readonly quality?: 'full' | 'navigation';
|
|
126
130
|
}): Promise<StageFrameCostReading>;
|
|
127
131
|
view(preset: ViewPreset): Promise<void>;
|
|
128
|
-
workspace(id: EditorWorkspaceName): Promise<
|
|
132
|
+
workspace(id: EditorWorkspaceName): Promise<{
|
|
133
|
+
readonly workspace: EditorWorkspaceName;
|
|
134
|
+
readonly applied: boolean;
|
|
135
|
+
}>;
|
|
129
136
|
/**
|
|
130
137
|
* Apply a STYLE BUNDLE by id — the chrome's palette, material and icon set in
|
|
131
138
|
* one gesture, the session door beside
|
|
@@ -279,7 +286,9 @@ export declare class LiveEditor {
|
|
|
279
286
|
* seam to report, not a removal that failed.
|
|
280
287
|
*/
|
|
281
288
|
removeField(path: string): Promise<InspectedFieldWrite>;
|
|
282
|
-
/** Open a document by its adapter-declared id, through its registered owner.
|
|
289
|
+
/** Open a document by its adapter-declared id, through its registered owner. An id the adapter would list for a
|
|
290
|
+
* file not written yet (a new model, `model:prefabs/coin/coin.blend`) opens as that new document, written by its
|
|
291
|
+
* first save. */
|
|
283
292
|
open(id: string): Promise<OpenedDocument>;
|
|
284
293
|
/** Undo / redo one project transaction, through the session's own history
|
|
285
294
|
* queue — the same one the keyboard shortcut drives. */
|
package/dist/index.d.ts
CHANGED
|
@@ -2,10 +2,11 @@ import { LiveEditor } from './editor.js';
|
|
|
2
2
|
import { type ResolvedSession, type SessionResolutionDeps } from './session.js';
|
|
3
3
|
export { LiveEditor, inferAssetKind, type PanelName } from './editor.js';
|
|
4
4
|
export { LiveEditorDocument } from './editor-document.js';
|
|
5
|
+
export type { AssetDownloadRequest, AssetDownloadResult, AssetFileOption, AssetSearchQuery, OnlineAsset } from './asset-library.js';
|
|
5
6
|
export type { DocumentGestureOptions, DocumentKeyOptions, DocumentPasteOptions } from './editor-document.js';
|
|
6
7
|
export { editorMemberHint, withEditorMemberHints } from './member-hints.js';
|
|
7
8
|
export { resolveSession, findProjectRootFrom, NO_SESSION_FOR_PROJECT, SESSION_MANIFEST_UNREADABLE } from './session.js';
|
|
8
|
-
export type { ResolvedSession, SessionResolutionDeps, SessionListingTransport
|
|
9
|
+
export type { ResolvedSession, SessionResolutionDeps, SessionListingTransport } from './session.js';
|
|
9
10
|
export type { ActiveDocumentCapture, EditorView, PresentedEditorView } from '@volter/sdk';
|
|
10
11
|
export interface LiveBindings {
|
|
11
12
|
editor: LiveEditor;
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EditorClient
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IZJOOON2.js";
|
|
4
|
+
import {
|
|
5
|
+
LiveAssetLibrary
|
|
6
|
+
} from "./chunk-B2HUWFTT.js";
|
|
4
7
|
import {
|
|
5
8
|
EDITOR_SESSION_DISCOVERY_TIMEOUT_MS,
|
|
6
9
|
HttpSessionDiscovery,
|
|
7
10
|
withTimeout
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import
|
|
10
|
-
servedProjectAnswer
|
|
11
|
-
} from "./chunk-Y5W77HYT.js";
|
|
11
|
+
} from "./chunk-WIAH4XZE.js";
|
|
12
|
+
import "./chunk-JDOIPALX.js";
|
|
12
13
|
import {
|
|
13
14
|
resolveProductForProject
|
|
14
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-PC56TDHV.js";
|
|
16
|
+
import "./chunk-JFAHP5CC.js";
|
|
15
17
|
import "./chunk-7WKVJGHZ.js";
|
|
16
|
-
import "./chunk-YPAOTPIF.js";
|
|
17
18
|
|
|
18
19
|
// src/editor-document.ts
|
|
19
20
|
var LiveEditorDocument = class {
|
|
@@ -198,9 +199,13 @@ var LiveEditor = class {
|
|
|
198
199
|
* such as header, shelf, rail, outliner, utility and area. Targets outside the scope are refused.
|
|
199
200
|
* See `@volter/sdk`'s editor-document-probe for scope and gesture contracts. */
|
|
200
201
|
document;
|
|
202
|
+
/** The asset library: search a source, list an asset's files, download one into the project with its license
|
|
203
|
+
* recorded (`asset-library.ts`). */
|
|
204
|
+
assetLibrary;
|
|
201
205
|
constructor(client) {
|
|
202
206
|
this.#client = client;
|
|
203
207
|
this.document = new LiveEditorDocument(client);
|
|
208
|
+
this.assetLibrary = new LiveAssetLibrary(client);
|
|
204
209
|
}
|
|
205
210
|
/** A verb a composed package contributes (`<package>-<verb>`), waited on for its own row's budget. */
|
|
206
211
|
async contributedVerb(type, fields = {}) {
|
|
@@ -322,7 +327,7 @@ var LiveEditor = class {
|
|
|
322
327
|
await this.#client.viewPreset(preset);
|
|
323
328
|
}
|
|
324
329
|
async workspace(id) {
|
|
325
|
-
|
|
330
|
+
return this.#client.setWorkspace(id);
|
|
326
331
|
}
|
|
327
332
|
/**
|
|
328
333
|
* Apply a STYLE BUNDLE by id — the chrome's palette, material and icon set in
|
|
@@ -533,7 +538,9 @@ var LiveEditor = class {
|
|
|
533
538
|
async removeField(path) {
|
|
534
539
|
return this.#client.removeInspectionField(path);
|
|
535
540
|
}
|
|
536
|
-
/** Open a document by its adapter-declared id, through its registered owner.
|
|
541
|
+
/** Open a document by its adapter-declared id, through its registered owner. An id the adapter would list for a
|
|
542
|
+
* file not written yet (a new model, `model:prefabs/coin/coin.blend`) opens as that new document, written by its
|
|
543
|
+
* first save. */
|
|
537
544
|
async open(id) {
|
|
538
545
|
return this.#client.open(id);
|
|
539
546
|
}
|
|
@@ -598,8 +605,8 @@ function lazyChainProxy(resolveRoot, path = [], hint) {
|
|
|
598
605
|
}
|
|
599
606
|
|
|
600
607
|
// src/session.ts
|
|
601
|
-
import { existsSync,
|
|
602
|
-
import { dirname,
|
|
608
|
+
import { existsSync, realpathSync, statSync } from "node:fs";
|
|
609
|
+
import { dirname, resolve } from "node:path";
|
|
603
610
|
|
|
604
611
|
// ../project/src/manifest/locate.ts
|
|
605
612
|
import { join } from "node:path";
|
|
@@ -640,32 +647,6 @@ function sameDirectory(a, b) {
|
|
|
640
647
|
}
|
|
641
648
|
var NO_SESSION_FOR_PROJECT = "VOLTER_NO_SESSION_FOR_PROJECT";
|
|
642
649
|
var SESSION_MANIFEST_UNREADABLE = "VOLTER_SESSION_MANIFEST_UNREADABLE";
|
|
643
|
-
function readProjectSession(projectRoot) {
|
|
644
|
-
try {
|
|
645
|
-
const value = JSON.parse(
|
|
646
|
-
readFileSync(join2(projectRoot, ".volter", "session.json"), "utf8")
|
|
647
|
-
);
|
|
648
|
-
if (typeof value !== "object" || value === null) return null;
|
|
649
|
-
const hint = value;
|
|
650
|
-
if (typeof hint["port"] !== "number" || !Number.isInteger(hint["port"]) || hint["port"] <= 0 || typeof hint["pid"] !== "number" || typeof hint["url"] !== "string" || typeof hint["startedAt"] !== "string") {
|
|
651
|
-
return null;
|
|
652
|
-
}
|
|
653
|
-
return hint;
|
|
654
|
-
} catch {
|
|
655
|
-
return null;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
async function probeServedProject(port) {
|
|
659
|
-
try {
|
|
660
|
-
const response = await fetch(`http://127.0.0.1:${port}/__editor/project`, {
|
|
661
|
-
signal: AbortSignal.timeout(EDITOR_SESSION_DISCOVERY_TIMEOUT_MS)
|
|
662
|
-
});
|
|
663
|
-
if (!response.ok) return void 0;
|
|
664
|
-
return servedProjectAnswer(await response.json());
|
|
665
|
-
} catch {
|
|
666
|
-
return void 0;
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
650
|
function manifestRefusal(projectRoot, manifestError, port) {
|
|
670
651
|
return Object.assign(
|
|
671
652
|
new Error(
|
|
@@ -706,20 +687,6 @@ async function resolveSession(projectDir = process.cwd(), deps = {}) {
|
|
|
706
687
|
`@volter/live: no volter.project.json found in ${projectDir} or any parent directory \u2014 is this a project?`
|
|
707
688
|
);
|
|
708
689
|
}
|
|
709
|
-
const localHint = (deps.readProjectSession ?? readProjectSession)(projectRoot);
|
|
710
|
-
if (localHint) {
|
|
711
|
-
if (deps.verifyProjectSession) {
|
|
712
|
-
if (await deps.verifyProjectSession(localHint, projectRoot)) {
|
|
713
|
-
return { port: localHint.port, projectRoot };
|
|
714
|
-
}
|
|
715
|
-
} else {
|
|
716
|
-
const served = await probeServedProject(localHint.port);
|
|
717
|
-
if (served?.path != null && canonicalPath(served.path) === canonicalPath(projectRoot)) {
|
|
718
|
-
if (served.manifestError !== null) throw manifestRefusal(projectRoot, served.manifestError, localHint.port);
|
|
719
|
-
return { port: localHint.port, projectRoot };
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
690
|
let sessions;
|
|
724
691
|
let discoveryFailure = null;
|
|
725
692
|
try {
|