@agimon-ai/po-core 0.0.0-alpha.21 → 0.0.0-alpha.23
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/dist/apiContracts.cjs +10 -0
- package/dist/apiContracts.cjs.map +1 -1
- package/dist/apiContracts.mjs +10 -0
- package/dist/apiContracts.mjs.map +1 -1
- package/dist/headlessServer.cjs +12 -84
- package/dist/headlessServer.cjs.map +1 -1
- package/dist/headlessServer.d.mts.map +1 -1
- package/dist/headlessServer.mjs +13 -85
- package/dist/headlessServer.mjs.map +1 -1
- package/dist/mcpProjection.cjs +1 -0
- package/dist/mcpProjection.d.mts +2 -2
- package/dist/mcpProjection.mjs +1 -1
- package/dist/native.cjs +0 -1
- package/dist/native.d.mts +3 -3
- package/dist/native.mjs +2 -2
- package/dist/packageApiServer.cjs +39 -4
- package/dist/packageApiServer.cjs.map +1 -1
- package/dist/packageApiServer.d.mts.map +1 -1
- package/dist/packageApiServer.mjs +34 -1
- package/dist/packageApiServer.mjs.map +1 -1
- package/dist/platform.cjs +3 -0
- package/dist/platform.d.mts +2 -1
- package/dist/platform.mjs +2 -1
- package/dist/src/constants/sessionFiles.cjs +3 -0
- package/dist/src/constants/sessionFiles.cjs.map +1 -1
- package/dist/src/constants/sessionFiles.mjs +3 -1
- package/dist/src/constants/sessionFiles.mjs.map +1 -1
- package/dist/src/schemas/httpApiContracts.cjs +10 -0
- package/dist/src/schemas/httpApiContracts.cjs.map +1 -1
- package/dist/src/schemas/httpApiContracts.d.mts.map +1 -1
- package/dist/src/schemas/httpApiContracts.mjs +10 -0
- package/dist/src/schemas/httpApiContracts.mjs.map +1 -1
- package/dist/src/schemas/mcpProjection.cjs +11 -1
- package/dist/src/schemas/mcpProjection.cjs.map +1 -1
- package/dist/src/schemas/mcpProjection.d.mts +8 -3
- package/dist/src/schemas/mcpProjection.d.mts.map +1 -1
- package/dist/src/schemas/mcpProjection.mjs +11 -2
- package/dist/src/schemas/mcpProjection.mjs.map +1 -1
- package/dist/src/schemas/mcpSession.d.mts +1 -1
- package/dist/src/services/fileAccess/accessibleFile.cjs +101 -0
- package/dist/src/services/fileAccess/accessibleFile.cjs.map +1 -0
- package/dist/src/services/fileAccess/accessibleFile.mjs +98 -0
- package/dist/src/services/fileAccess/accessibleFile.mjs.map +1 -0
- package/dist/src/services/fileAccess/index.cjs +34 -0
- package/dist/src/services/fileAccess/index.cjs.map +1 -0
- package/dist/src/services/fileAccess/index.d.mts +22 -0
- package/dist/src/services/fileAccess/index.d.mts.map +1 -0
- package/dist/src/services/fileAccess/index.mjs +29 -0
- package/dist/src/services/fileAccess/index.mjs.map +1 -0
- package/dist/src/web/types/webPlugin.d.mts +13 -0
- package/dist/src/web/types/webPlugin.d.mts.map +1 -1
- package/dist/web.d.mts +2 -2
- package/dist/webCompositions.cjs +43 -2
- package/dist/webCompositions.cjs.map +1 -1
- package/dist/webCompositions.d.mts +22 -0
- package/dist/webCompositions.d.mts.map +1 -1
- package/dist/webCompositions.mjs +43 -2
- package/dist/webCompositions.mjs.map +1 -1
- package/package.json +4 -4
|
@@ -37,6 +37,22 @@ export interface GlobalNativeBuild {
|
|
|
37
37
|
/** Directory holding exactly `/composition.js`. */
|
|
38
38
|
pluginsDirectory: string;
|
|
39
39
|
}
|
|
40
|
+
/** One platform's over-the-air app bundle that `po sync` exported from a source checkout. */
|
|
41
|
+
export interface NativeAppBuild {
|
|
42
|
+
key: string;
|
|
43
|
+
/** Directory holding `/app.json`, the `/bundle/` parts and the bundle's assets. */
|
|
44
|
+
directory: string;
|
|
45
|
+
/** Native fingerprint of the binaries the bundle runs on. */
|
|
46
|
+
fingerprint: string;
|
|
47
|
+
}
|
|
48
|
+
/** A published app bundle as `/api/compositions` offers it to phones. */
|
|
49
|
+
export interface PoNativeApp {
|
|
50
|
+
id: string;
|
|
51
|
+
revision: number;
|
|
52
|
+
manifestUrl: string;
|
|
53
|
+
rawAssetBaseUrl: string;
|
|
54
|
+
fingerprint: string;
|
|
55
|
+
}
|
|
40
56
|
/**
|
|
41
57
|
* The stylesheets of exactly the given slots, each loaded once: the stylesheets their code
|
|
42
58
|
* imports first, then each slot's own stylesheet in slot order.
|
|
@@ -66,6 +82,12 @@ export declare function createWebCompositions(stateDirectory: string, onNotice:
|
|
|
66
82
|
publishNative(mount: PoApiMount, build: GlobalNativeBuild, channels: readonly string[], pluginIds: readonly string[]): PoNativeComposition;
|
|
67
83
|
getNative: (mount: PoApiMount) => PoNativeComposition | undefined;
|
|
68
84
|
removeNative: (mount: PoApiMount) => void;
|
|
85
|
+
/**
|
|
86
|
+
* Publishes one platform's app bundle under the `app` profile, so it can never be served or
|
|
87
|
+
* verified as a composition. A new key releases the previous bundle; a failure leaves it serving.
|
|
88
|
+
*/
|
|
89
|
+
publishApp(platform: string, build: NativeAppBuild): void;
|
|
90
|
+
apps: () => Record<string, PoNativeApp>;
|
|
69
91
|
/**
|
|
70
92
|
* Signs `po/host-channel-key/v1` with the shell publication's signer, the key the pairing QR pins
|
|
71
93
|
* as `s`. Undefined until the shell is published.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webCompositions.d.mts","names":[],"sources":["../src/services/webCompositions/index.ts"],"mappings":";;;;iBAWiB;EACf;;EAEA;EACA;EACA;;EAEA;;EAEA;;EAEA;;;iBAIe;;EAEf;;EAEA;;EAEA;;EAEA,kBAAkB;;EAElB,cAAc,SAAS;;EAEvB;;;iBAIe;;EAEf;;EAEA;;;;;;
|
|
1
|
+
{"version":3,"file":"webCompositions.d.mts","names":[],"sources":["../src/services/webCompositions/index.ts"],"mappings":";;;;iBAWiB;EACf;;EAEA;EACA;EACA;;EAEA;;EAEA;;EAEA;;;iBAIe;;EAEf;;EAEA;;EAEA;;EAEA,kBAAkB;;EAElB,cAAc,SAAS;;EAEvB;;;iBAIe;;EAEf;;EAEA;;;iBAIe;EACf;;EAEA;;EAEA;;;iBAIe;EACf;EACA;EACA;EACA;EACA;;;;;;wBA4Bc,gBAAgB,OAAO,gBAAgB;;wBAQvC,gBAAgB,OAAO,gBAAgB;;;;;;;wBAkBvC,sBAAsB,wBAAwB,WAAW;EAuBrE,aAAY,OAAQ;EAIpB;;;;EAEA,QAAO,OACE,YAAU,OACV,gBAAc,6BACM,2BAE1B;EA6BH,MAAG,OAAU,eAAU;EACvB,SAAM,OAAU;;;;;EAShB,cAAa,OACJ,YAAU,OACV,mBAAiB,6BACG,+BAE1B;EAsBH,YAAS,OAAU,eAAU;EAC7B,eAAY,OAAU;;;;;EAStB,WAAU,kBAAiB,OAAS;EAiBpC,YAAU,eAAe;;;;;EAKzB,aAAU;EAEV;EACM,QAAO,SAAU,UAAU,QAAQ;EA6CzC"}
|
package/dist/webCompositions.mjs
CHANGED
|
@@ -6,6 +6,19 @@ import path from "node:path";
|
|
|
6
6
|
import { NATIVE_ENTRY_PATH } from "@agimon-ai/po-web-security";
|
|
7
7
|
//#region src/services/webCompositions/index.ts
|
|
8
8
|
const absolute = (file) => file.startsWith("/") ? file : `/${file}`;
|
|
9
|
+
/**
|
|
10
|
+
* The file a signed manifest path names below `root`. Manifest segments are percent-encoded
|
|
11
|
+
* (`@` and `+` in pnpm paths); the decoded file must still resolve inside `root`.
|
|
12
|
+
*/
|
|
13
|
+
function assetFile(root, assetPath) {
|
|
14
|
+
try {
|
|
15
|
+
const base = path.resolve(root);
|
|
16
|
+
const file = path.resolve(base, ...assetPath.slice(1).split("/").map(decodeURIComponent));
|
|
17
|
+
return file.startsWith(`${base}${path.sep}`) && !file.includes("\0") ? file : void 0;
|
|
18
|
+
} catch {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
9
22
|
/** The build's plugin copies for exactly the given slots, in slot order. */
|
|
10
23
|
function slotPlugins(build, slots) {
|
|
11
24
|
return slots.flatMap((slot) => build.plugins.filter((plugin) => plugin.slot === slot));
|
|
@@ -36,6 +49,7 @@ function createWebCompositions(stateDirectory, onNotice) {
|
|
|
36
49
|
let shell;
|
|
37
50
|
const mounts = /* @__PURE__ */ new Map();
|
|
38
51
|
const nativeMounts = /* @__PURE__ */ new Map();
|
|
52
|
+
const apps = /* @__PURE__ */ new Map();
|
|
39
53
|
const references = /* @__PURE__ */ new Map();
|
|
40
54
|
const keyOf = (mount) => mount.scope === "global" ? "global" : mount.scope === "workspace" ? `workspace:${mount.workspaceId}` : `session:${mount.sessionId}`;
|
|
41
55
|
const release = (id) => {
|
|
@@ -121,6 +135,28 @@ function createWebCompositions(stateDirectory, onNotice) {
|
|
|
121
135
|
if (previous) release(previous.id);
|
|
122
136
|
},
|
|
123
137
|
/**
|
|
138
|
+
* Publishes one platform's app bundle under the `app` profile, so it can never be served or
|
|
139
|
+
* verified as a composition. A new key releases the previous bundle; a failure leaves it serving.
|
|
140
|
+
*/
|
|
141
|
+
publishApp(platform, build) {
|
|
142
|
+
const id = sha256(`app:${platform}:${build.key}`);
|
|
143
|
+
const previous = apps.get(platform);
|
|
144
|
+
if (previous?.id === id) return;
|
|
145
|
+
const published = publication.publish(id, build.directory, "app");
|
|
146
|
+
if (!published) return;
|
|
147
|
+
const revision = published.signed.manifest.revision;
|
|
148
|
+
const base = `/api/web-plugins/${id}/${String(revision)}`;
|
|
149
|
+
apps.set(platform, {
|
|
150
|
+
id,
|
|
151
|
+
revision,
|
|
152
|
+
manifestUrl: `${base}/manifest`,
|
|
153
|
+
rawAssetBaseUrl: `${base}/assets`,
|
|
154
|
+
fingerprint: build.fingerprint
|
|
155
|
+
});
|
|
156
|
+
if (previous !== void 0) publication.release(previous.id);
|
|
157
|
+
},
|
|
158
|
+
apps: () => Object.fromEntries(apps),
|
|
159
|
+
/**
|
|
124
160
|
* Signs `po/host-channel-key/v1` with the shell publication's signer, the key the pairing QR pins
|
|
125
161
|
* as `s`. Undefined until the shell is published.
|
|
126
162
|
*/
|
|
@@ -138,7 +174,9 @@ function createWebCompositions(stateDirectory, onNotice) {
|
|
|
138
174
|
if (!shell || Number(shellAsset[1]) !== shell.signed.manifest.revision) return new Response(null, { status: 404 });
|
|
139
175
|
const asset = shell.signed.manifest.assets.find((entry) => entry.path === shellAsset[2]);
|
|
140
176
|
if (!asset) return new Response(null, { status: 404 });
|
|
141
|
-
const
|
|
177
|
+
const file = assetFile(shell.assetsDir, asset.path);
|
|
178
|
+
if (!file) return new Response(null, { status: 404 });
|
|
179
|
+
const bytes = await fs.promises.readFile(file);
|
|
142
180
|
return new Response(request.method === "HEAD" ? null : bytes, { headers: {
|
|
143
181
|
"content-type": asset.contentType,
|
|
144
182
|
"x-content-type-options": "nosniff"
|
|
@@ -153,7 +191,9 @@ function createWebCompositions(stateDirectory, onNotice) {
|
|
|
153
191
|
const assetPath = match[3].slice(6);
|
|
154
192
|
const asset = bundle.signed.manifest.assets.find((candidate) => candidate.path === assetPath);
|
|
155
193
|
if (!asset) return Response.json({ error: "Plugin asset not found." }, { status: 404 });
|
|
156
|
-
const
|
|
194
|
+
const file = assetFile(bundle.assetsDir, asset.path);
|
|
195
|
+
if (!file) return Response.json({ error: "Plugin asset not found." }, { status: 404 });
|
|
196
|
+
const bytes = await fs.promises.readFile(file);
|
|
157
197
|
return new Response(request.method === "HEAD" ? null : bytes, { headers: {
|
|
158
198
|
"content-type": asset.contentType,
|
|
159
199
|
"cache-control": "private, max-age=31536000, immutable",
|
|
@@ -163,6 +203,7 @@ function createWebCompositions(stateDirectory, onNotice) {
|
|
|
163
203
|
close() {
|
|
164
204
|
mounts.clear();
|
|
165
205
|
nativeMounts.clear();
|
|
206
|
+
apps.clear();
|
|
166
207
|
references.clear();
|
|
167
208
|
publication.close();
|
|
168
209
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webCompositions.mjs","names":[],"sources":["../src/services/webCompositions/index.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { NATIVE_ENTRY_PATH } from '@agimon-ai/po-web-security';\n\nimport { HOST_CHANNEL_KEY_TAG } from '../../constants/remote';\nimport type { PoApiMount, PoNativeComposition, PoWebComposition } from '../../exports/packageApi';\nimport { createPluginBundlePublication, type PublishedBundle } from '../bundlePublication';\n\n/** One plugin copy in a global web build: its slot entry and the files that entry can load. */\nexport interface GlobalWebBuildPlugin {\n pluginId: string;\n /** The copy's identity: the pluginId for a host plugin, else the pluginId plus a package hash. */\n slot: string;\n packageDir: string;\n isHost: boolean;\n /** The slot entry module below `pluginsDirectory`. */\n entry: string;\n /** Every file below `pluginsDirectory` the entry reaches through static and dynamic imports, plus its stylesheet. */\n files: readonly string[];\n /** The stylesheets of the entry's static import closure. */\n css: readonly string[];\n}\n\n/** One global web build: the shell, the shared plugin composition, and one stylesheet per plugin copy. */\nexport interface GlobalWebBuild {\n /** Content key of the build; equal keys hold identical bytes. */\n key: string;\n /** Signed cockpit shell directory. */\n webDirectory: string;\n /** Shared plugin composition directory, published once for every mount. */\n pluginsDirectory: string;\n /** Every plugin copy in the build, in build order. */\n plugins: readonly GlobalWebBuildPlugin[];\n /** Content-hashed stylesheet paths below `pluginsDirectory`, keyed by slot. */\n pluginStyles: Readonly<Record<string, string>>;\n /** Stylesheet a mount without plugin styles still loads, for the host shell and fallback template. */\n baseStyle?: string;\n}\n\n/** One global native build: a single signed CommonJS composition shared by every mount. */\nexport interface GlobalNativeBuild {\n /** Content key of the build; equal keys hold identical bytes. */\n key: string;\n /** Directory holding exactly `/composition.js`. */\n pluginsDirectory: string;\n}\n\nconst absolute = (file: string): string => (file.startsWith('/') ? file : `/${file}`);\n\n/** The build's plugin copies for exactly the given slots, in slot order. */\nfunction slotPlugins(build: GlobalWebBuild, slots: readonly string[]): GlobalWebBuildPlugin[] {\n return slots.flatMap((slot) => build.plugins.filter((plugin) => plugin.slot === slot));\n}\n\n/**\n * The stylesheets of exactly the given slots, each loaded once: the stylesheets their code\n * imports first, then each slot's own stylesheet in slot order.\n */\nexport function mountStylePaths(build: GlobalWebBuild, slots: readonly string[]): string[] {\n const paths = slots.map((slot) => build.pluginStyles[slot]).filter((style) => style !== undefined);\n if (paths.length === 0 && build.baseStyle !== undefined) paths.push(build.baseStyle);\n const imported = slotPlugins(build, slots).flatMap((plugin) => plugin.css);\n return [...new Set([...imported, ...paths].map(absolute))];\n}\n\n/** Every file the given slots can load: their reachable files and static stylesheets, each once. */\nexport function mountAssetPaths(build: GlobalWebBuild, slots: readonly string[]): string[] {\n return [\n ...new Set(\n slotPlugins(build, slots)\n .flatMap((plugin) => [...plugin.files, ...plugin.css])\n .map(absolute),\n ),\n ];\n}\n\nconst sha256 = (value: string): string => crypto.createHash('sha256').update(value).digest('hex');\n\n/**\n * Signs the global build once and hands each mount a composition naming its own plugins.\n *\n * Every mount of one build shares a publication id, so the bytes are counted per mount and\n * released only when the last mount leaves or moves to another build.\n */\nexport function createWebCompositions(stateDirectory: string, onNotice: (message: string) => void) {\n const publication = createPluginBundlePublication(stateDirectory, onNotice);\n let shell: PublishedBundle | undefined;\n const mounts = new Map<string, PoWebComposition>();\n const nativeMounts = new Map<string, PoNativeComposition>();\n const references = new Map<string, number>();\n const keyOf = (mount: PoApiMount): string =>\n mount.scope === 'global'\n ? 'global'\n : mount.scope === 'workspace'\n ? `workspace:${mount.workspaceId}`\n : `session:${mount.sessionId}`;\n const release = (id: string): void => {\n const count = (references.get(id) ?? 0) - 1;\n if (count > 0) {\n references.set(id, count);\n return;\n }\n references.delete(id);\n publication.release(id);\n };\n return {\n publishShell(build: GlobalWebBuild): void {\n shell = publication.publish(sha256(`shell:${build.key}`), build.webDirectory);\n if (!shell) throw new Error('Could not publish the global web shell.');\n },\n shellTrust: () =>\n shell === undefined ? undefined : { publicKey: shell.signed.publicKey, revision: shell.signed.manifest.revision },\n publish(\n mount: PoApiMount,\n build: GlobalWebBuild,\n channels: readonly string[],\n slots: readonly string[],\n ): PoWebComposition | undefined {\n const id = sha256(`plugins:${build.key}`);\n const published = publication.publish(id, build.pluginsDirectory);\n if (!published) throw new Error(`Could not publish ${keyOf(mount)} web composition.`);\n const previous = mounts.get(keyOf(mount));\n if (previous?.id !== id) references.set(id, (references.get(id) ?? 0) + 1);\n const revision = published.signed.manifest.revision;\n const base = `/api/web-plugins/${id}/${String(revision)}`;\n const signedPaths = new Set(published.signed.manifest.assets.map((asset) => asset.path));\n const composition: PoWebComposition = {\n id,\n scope: mount.scope,\n revision,\n manifestUrl: `${base}/manifest`,\n rawAssetBaseUrl: `${base}/assets`,\n verifiedAssetBaseUrl: `/verified-plugins/${id}/${String(revision)}`,\n pluginEntries: slotPlugins(build, slots).map((plugin): [string, string] => [\n plugin.slot,\n absolute(plugin.entry),\n ]),\n assetPaths: mountAssetPaths(build, slots).filter((file) => signedPaths.has(file)),\n stylePaths: mountStylePaths(build, slots).filter((style) => signedPaths.has(style)),\n channels: [...channels],\n plugins: [...slots],\n };\n mounts.set(keyOf(mount), composition);\n if (previous !== undefined && previous.id !== id) release(previous.id);\n return composition;\n },\n get: (mount: PoApiMount) => mounts.get(keyOf(mount)),\n remove: (mount: PoApiMount) => {\n const previous = mounts.get(keyOf(mount));\n mounts.delete(keyOf(mount));\n if (previous) release(previous.id);\n },\n /**\n * Publishes the native composition for one mount. Signed under the `native` profile, so it can\n * never be served or verified as a web bundle. Shares reference counting with web publications.\n */\n publishNative(\n mount: PoApiMount,\n build: GlobalNativeBuild,\n channels: readonly string[],\n pluginIds: readonly string[],\n ): PoNativeComposition {\n const id = sha256(`native:${build.key}`);\n const published = publication.publish(id, build.pluginsDirectory, 'native');\n if (!published) throw new Error(`Could not publish ${keyOf(mount)} native composition.`);\n const previous = nativeMounts.get(keyOf(mount));\n if (previous?.id !== id) references.set(id, (references.get(id) ?? 0) + 1);\n const revision = published.signed.manifest.revision;\n const base = `/api/web-plugins/${id}/${String(revision)}`;\n const composition: PoNativeComposition = {\n id,\n scope: mount.scope,\n revision,\n manifestUrl: `${base}/manifest`,\n rawAssetBaseUrl: `${base}/assets`,\n entryPath: NATIVE_ENTRY_PATH,\n channels: [...channels],\n plugins: [...pluginIds],\n };\n nativeMounts.set(keyOf(mount), composition);\n if (previous !== undefined && previous.id !== id) release(previous.id);\n return composition;\n },\n getNative: (mount: PoApiMount) => nativeMounts.get(keyOf(mount)),\n removeNative: (mount: PoApiMount) => {\n const previous = nativeMounts.get(keyOf(mount));\n nativeMounts.delete(keyOf(mount));\n if (previous) release(previous.id);\n },\n /**\n * Signs `po/host-channel-key/v1` with the shell publication's signer, the key the pairing QR pins\n * as `s`. Undefined until the shell is published.\n */\n attestHost: (fields: readonly string[]): string | undefined =>\n shell === undefined ? undefined : publication.attest(HOST_CHANNEL_KEY_TAG, fields),\n publicKey: () => publication.publicKey(),\n async request(request: Request): Promise<Response | undefined> {\n const url = new URL(request.url);\n if (\n (url.pathname === '/bundle-manifest.json' || url.pathname.startsWith('/bundle-assets/')) &&\n request.method !== 'GET' &&\n request.method !== 'HEAD'\n )\n return new Response(null, { status: 405 });\n if (url.pathname === '/bundle-manifest.json') {\n if (!shell) return new Response(null, { status: 404 });\n return Response.json(shell.signed);\n }\n const shellAsset = /^\\/bundle-assets\\/(\\d+)(\\/.*)$/u.exec(url.pathname);\n if (shellAsset) {\n if (!shell || Number(shellAsset[1]) !== shell.signed.manifest.revision)\n return new Response(null, { status: 404 });\n const asset = shell.signed.manifest.assets.find((entry) => entry.path === shellAsset[2]);\n if (!asset) return new Response(null, { status: 404 });\n const bytes = await fs.promises.readFile(path.join(shell.assetsDir, asset.path));\n return new Response(request.method === 'HEAD' ? null : bytes, {\n headers: { 'content-type': asset.contentType, 'x-content-type-options': 'nosniff' },\n });\n }\n const match = /^\\/api\\/web-plugins\\/([a-f0-9]{64})\\/(\\d+)\\/(manifest|assets(?:\\/.*)?)$/u.exec(url.pathname);\n if (!match) return undefined;\n if (request.method !== 'GET' && request.method !== 'HEAD') return new Response(null, { status: 405 });\n const bundle = publication.get(match[1], Number(match[2]));\n if (!bundle) return Response.json({ error: 'Plugin generation not found.' }, { status: 404 });\n if (match[3] === 'manifest') return Response.json(bundle.signed);\n const assetPath = match[3].slice('assets'.length);\n const asset = bundle.signed.manifest.assets.find((candidate) => candidate.path === assetPath);\n if (!asset) return Response.json({ error: 'Plugin asset not found.' }, { status: 404 });\n const bytes = await fs.promises.readFile(path.join(bundle.assetsDir, asset.path));\n return new Response(request.method === 'HEAD' ? null : bytes, {\n headers: {\n 'content-type': asset.contentType,\n 'cache-control': 'private, max-age=31536000, immutable',\n 'x-content-type-options': 'nosniff',\n },\n });\n },\n close() {\n mounts.clear();\n nativeMounts.clear();\n references.clear();\n publication.close();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"webCompositions.mjs","names":[],"sources":["../src/services/webCompositions/index.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { NATIVE_ENTRY_PATH } from '@agimon-ai/po-web-security';\n\nimport { HOST_CHANNEL_KEY_TAG } from '../../constants/remote';\nimport type { PoApiMount, PoNativeComposition, PoWebComposition } from '../../exports/packageApi';\nimport { createPluginBundlePublication, type PublishedBundle } from '../bundlePublication';\n\n/** One plugin copy in a global web build: its slot entry and the files that entry can load. */\nexport interface GlobalWebBuildPlugin {\n pluginId: string;\n /** The copy's identity: the pluginId for a host plugin, else the pluginId plus a package hash. */\n slot: string;\n packageDir: string;\n isHost: boolean;\n /** The slot entry module below `pluginsDirectory`. */\n entry: string;\n /** Every file below `pluginsDirectory` the entry reaches through static and dynamic imports, plus its stylesheet. */\n files: readonly string[];\n /** The stylesheets of the entry's static import closure. */\n css: readonly string[];\n}\n\n/** One global web build: the shell, the shared plugin composition, and one stylesheet per plugin copy. */\nexport interface GlobalWebBuild {\n /** Content key of the build; equal keys hold identical bytes. */\n key: string;\n /** Signed cockpit shell directory. */\n webDirectory: string;\n /** Shared plugin composition directory, published once for every mount. */\n pluginsDirectory: string;\n /** Every plugin copy in the build, in build order. */\n plugins: readonly GlobalWebBuildPlugin[];\n /** Content-hashed stylesheet paths below `pluginsDirectory`, keyed by slot. */\n pluginStyles: Readonly<Record<string, string>>;\n /** Stylesheet a mount without plugin styles still loads, for the host shell and fallback template. */\n baseStyle?: string;\n}\n\n/** One global native build: a single signed CommonJS composition shared by every mount. */\nexport interface GlobalNativeBuild {\n /** Content key of the build; equal keys hold identical bytes. */\n key: string;\n /** Directory holding exactly `/composition.js`. */\n pluginsDirectory: string;\n}\n\n/** One platform's over-the-air app bundle that `po sync` exported from a source checkout. */\nexport interface NativeAppBuild {\n key: string;\n /** Directory holding `/app.json`, the `/bundle/` parts and the bundle's assets. */\n directory: string;\n /** Native fingerprint of the binaries the bundle runs on. */\n fingerprint: string;\n}\n\n/** A published app bundle as `/api/compositions` offers it to phones. */\nexport interface PoNativeApp {\n id: string;\n revision: number;\n manifestUrl: string;\n rawAssetBaseUrl: string;\n fingerprint: string;\n}\n\nconst absolute = (file: string): string => (file.startsWith('/') ? file : `/${file}`);\n\n/**\n * The file a signed manifest path names below `root`. Manifest segments are percent-encoded\n * (`@` and `+` in pnpm paths); the decoded file must still resolve inside `root`.\n */\nfunction assetFile(root: string, assetPath: string): string | undefined {\n try {\n const base = path.resolve(root);\n const file = path.resolve(base, ...assetPath.slice(1).split('/').map(decodeURIComponent));\n return file.startsWith(`${base}${path.sep}`) && !file.includes('\\0') ? file : undefined;\n } catch {\n return undefined; // A malformed escape names no file.\n }\n}\n\n/** The build's plugin copies for exactly the given slots, in slot order. */\nfunction slotPlugins(build: GlobalWebBuild, slots: readonly string[]): GlobalWebBuildPlugin[] {\n return slots.flatMap((slot) => build.plugins.filter((plugin) => plugin.slot === slot));\n}\n\n/**\n * The stylesheets of exactly the given slots, each loaded once: the stylesheets their code\n * imports first, then each slot's own stylesheet in slot order.\n */\nexport function mountStylePaths(build: GlobalWebBuild, slots: readonly string[]): string[] {\n const paths = slots.map((slot) => build.pluginStyles[slot]).filter((style) => style !== undefined);\n if (paths.length === 0 && build.baseStyle !== undefined) paths.push(build.baseStyle);\n const imported = slotPlugins(build, slots).flatMap((plugin) => plugin.css);\n return [...new Set([...imported, ...paths].map(absolute))];\n}\n\n/** Every file the given slots can load: their reachable files and static stylesheets, each once. */\nexport function mountAssetPaths(build: GlobalWebBuild, slots: readonly string[]): string[] {\n return [\n ...new Set(\n slotPlugins(build, slots)\n .flatMap((plugin) => [...plugin.files, ...plugin.css])\n .map(absolute),\n ),\n ];\n}\n\nconst sha256 = (value: string): string => crypto.createHash('sha256').update(value).digest('hex');\n\n/**\n * Signs the global build once and hands each mount a composition naming its own plugins.\n *\n * Every mount of one build shares a publication id, so the bytes are counted per mount and\n * released only when the last mount leaves or moves to another build.\n */\nexport function createWebCompositions(stateDirectory: string, onNotice: (message: string) => void) {\n const publication = createPluginBundlePublication(stateDirectory, onNotice);\n let shell: PublishedBundle | undefined;\n const mounts = new Map<string, PoWebComposition>();\n const nativeMounts = new Map<string, PoNativeComposition>();\n const apps = new Map<string, PoNativeApp>();\n const references = new Map<string, number>();\n const keyOf = (mount: PoApiMount): string =>\n mount.scope === 'global'\n ? 'global'\n : mount.scope === 'workspace'\n ? `workspace:${mount.workspaceId}`\n : `session:${mount.sessionId}`;\n const release = (id: string): void => {\n const count = (references.get(id) ?? 0) - 1;\n if (count > 0) {\n references.set(id, count);\n return;\n }\n references.delete(id);\n publication.release(id);\n };\n return {\n publishShell(build: GlobalWebBuild): void {\n shell = publication.publish(sha256(`shell:${build.key}`), build.webDirectory);\n if (!shell) throw new Error('Could not publish the global web shell.');\n },\n shellTrust: () =>\n shell === undefined ? undefined : { publicKey: shell.signed.publicKey, revision: shell.signed.manifest.revision },\n publish(\n mount: PoApiMount,\n build: GlobalWebBuild,\n channels: readonly string[],\n slots: readonly string[],\n ): PoWebComposition | undefined {\n const id = sha256(`plugins:${build.key}`);\n const published = publication.publish(id, build.pluginsDirectory);\n if (!published) throw new Error(`Could not publish ${keyOf(mount)} web composition.`);\n const previous = mounts.get(keyOf(mount));\n if (previous?.id !== id) references.set(id, (references.get(id) ?? 0) + 1);\n const revision = published.signed.manifest.revision;\n const base = `/api/web-plugins/${id}/${String(revision)}`;\n const signedPaths = new Set(published.signed.manifest.assets.map((asset) => asset.path));\n const composition: PoWebComposition = {\n id,\n scope: mount.scope,\n revision,\n manifestUrl: `${base}/manifest`,\n rawAssetBaseUrl: `${base}/assets`,\n verifiedAssetBaseUrl: `/verified-plugins/${id}/${String(revision)}`,\n pluginEntries: slotPlugins(build, slots).map((plugin): [string, string] => [\n plugin.slot,\n absolute(plugin.entry),\n ]),\n assetPaths: mountAssetPaths(build, slots).filter((file) => signedPaths.has(file)),\n stylePaths: mountStylePaths(build, slots).filter((style) => signedPaths.has(style)),\n channels: [...channels],\n plugins: [...slots],\n };\n mounts.set(keyOf(mount), composition);\n if (previous !== undefined && previous.id !== id) release(previous.id);\n return composition;\n },\n get: (mount: PoApiMount) => mounts.get(keyOf(mount)),\n remove: (mount: PoApiMount) => {\n const previous = mounts.get(keyOf(mount));\n mounts.delete(keyOf(mount));\n if (previous) release(previous.id);\n },\n /**\n * Publishes the native composition for one mount. Signed under the `native` profile, so it can\n * never be served or verified as a web bundle. Shares reference counting with web publications.\n */\n publishNative(\n mount: PoApiMount,\n build: GlobalNativeBuild,\n channels: readonly string[],\n pluginIds: readonly string[],\n ): PoNativeComposition {\n const id = sha256(`native:${build.key}`);\n const published = publication.publish(id, build.pluginsDirectory, 'native');\n if (!published) throw new Error(`Could not publish ${keyOf(mount)} native composition.`);\n const previous = nativeMounts.get(keyOf(mount));\n if (previous?.id !== id) references.set(id, (references.get(id) ?? 0) + 1);\n const revision = published.signed.manifest.revision;\n const base = `/api/web-plugins/${id}/${String(revision)}`;\n const composition: PoNativeComposition = {\n id,\n scope: mount.scope,\n revision,\n manifestUrl: `${base}/manifest`,\n rawAssetBaseUrl: `${base}/assets`,\n entryPath: NATIVE_ENTRY_PATH,\n channels: [...channels],\n plugins: [...pluginIds],\n };\n nativeMounts.set(keyOf(mount), composition);\n if (previous !== undefined && previous.id !== id) release(previous.id);\n return composition;\n },\n getNative: (mount: PoApiMount) => nativeMounts.get(keyOf(mount)),\n removeNative: (mount: PoApiMount) => {\n const previous = nativeMounts.get(keyOf(mount));\n nativeMounts.delete(keyOf(mount));\n if (previous) release(previous.id);\n },\n /**\n * Publishes one platform's app bundle under the `app` profile, so it can never be served or\n * verified as a composition. A new key releases the previous bundle; a failure leaves it serving.\n */\n publishApp(platform: string, build: NativeAppBuild): void {\n const id = sha256(`app:${platform}:${build.key}`);\n const previous = apps.get(platform);\n if (previous?.id === id) return;\n const published = publication.publish(id, build.directory, 'app');\n if (!published) return;\n const revision = published.signed.manifest.revision;\n const base = `/api/web-plugins/${id}/${String(revision)}`;\n apps.set(platform, {\n id,\n revision,\n manifestUrl: `${base}/manifest`,\n rawAssetBaseUrl: `${base}/assets`,\n fingerprint: build.fingerprint,\n });\n if (previous !== undefined) publication.release(previous.id);\n },\n apps: (): Record<string, PoNativeApp> => Object.fromEntries(apps),\n /**\n * Signs `po/host-channel-key/v1` with the shell publication's signer, the key the pairing QR pins\n * as `s`. Undefined until the shell is published.\n */\n attestHost: (fields: readonly string[]): string | undefined =>\n shell === undefined ? undefined : publication.attest(HOST_CHANNEL_KEY_TAG, fields),\n publicKey: () => publication.publicKey(),\n async request(request: Request): Promise<Response | undefined> {\n const url = new URL(request.url);\n if (\n (url.pathname === '/bundle-manifest.json' || url.pathname.startsWith('/bundle-assets/')) &&\n request.method !== 'GET' &&\n request.method !== 'HEAD'\n )\n return new Response(null, { status: 405 });\n if (url.pathname === '/bundle-manifest.json') {\n if (!shell) return new Response(null, { status: 404 });\n return Response.json(shell.signed);\n }\n const shellAsset = /^\\/bundle-assets\\/(\\d+)(\\/.*)$/u.exec(url.pathname);\n if (shellAsset) {\n if (!shell || Number(shellAsset[1]) !== shell.signed.manifest.revision)\n return new Response(null, { status: 404 });\n const asset = shell.signed.manifest.assets.find((entry) => entry.path === shellAsset[2]);\n if (!asset) return new Response(null, { status: 404 });\n const file = assetFile(shell.assetsDir, asset.path);\n if (!file) return new Response(null, { status: 404 });\n const bytes = await fs.promises.readFile(file);\n return new Response(request.method === 'HEAD' ? null : bytes, {\n headers: { 'content-type': asset.contentType, 'x-content-type-options': 'nosniff' },\n });\n }\n const match = /^\\/api\\/web-plugins\\/([a-f0-9]{64})\\/(\\d+)\\/(manifest|assets(?:\\/.*)?)$/u.exec(url.pathname);\n if (!match) return undefined;\n if (request.method !== 'GET' && request.method !== 'HEAD') return new Response(null, { status: 405 });\n const bundle = publication.get(match[1], Number(match[2]));\n if (!bundle) return Response.json({ error: 'Plugin generation not found.' }, { status: 404 });\n if (match[3] === 'manifest') return Response.json(bundle.signed);\n const assetPath = match[3].slice('assets'.length);\n const asset = bundle.signed.manifest.assets.find((candidate) => candidate.path === assetPath);\n if (!asset) return Response.json({ error: 'Plugin asset not found.' }, { status: 404 });\n const file = assetFile(bundle.assetsDir, asset.path);\n if (!file) return Response.json({ error: 'Plugin asset not found.' }, { status: 404 });\n const bytes = await fs.promises.readFile(file);\n return new Response(request.method === 'HEAD' ? null : bytes, {\n headers: {\n 'content-type': asset.contentType,\n 'cache-control': 'private, max-age=31536000, immutable',\n 'x-content-type-options': 'nosniff',\n },\n });\n },\n close() {\n mounts.clear();\n nativeMounts.clear();\n apps.clear();\n references.clear();\n publication.close();\n },\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/po-core",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.23",
|
|
4
4
|
"description": "Po runtime systems and reusable core services.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -529,8 +529,8 @@
|
|
|
529
529
|
"registry": "https://registry.npmjs.org/"
|
|
530
530
|
},
|
|
531
531
|
"dependencies": {
|
|
532
|
-
"@agimon-ai/po-telemetry": "0.0.0-alpha.
|
|
533
|
-
"@agimon-ai/po-web-security": "0.0.0-alpha.
|
|
532
|
+
"@agimon-ai/po-telemetry": "0.0.0-alpha.23",
|
|
533
|
+
"@agimon-ai/po-web-security": "0.0.0-alpha.23",
|
|
534
534
|
"@deepseek-ai/cordis": "4.0.5",
|
|
535
535
|
"@earendil-works/chord": "1.3.0",
|
|
536
536
|
"@earendil-works/pi-agent-core": "1.3.0",
|
|
@@ -553,7 +553,7 @@
|
|
|
553
553
|
"yaml": "2.9.1"
|
|
554
554
|
},
|
|
555
555
|
"devDependencies": {
|
|
556
|
-
"@agimon-ai/vibe-lint-plugin-po-core": "0.0.0-alpha.
|
|
556
|
+
"@agimon-ai/vibe-lint-plugin-po-core": "0.0.0-alpha.23",
|
|
557
557
|
"@apidevtools/swagger-parser": "^13.1.0",
|
|
558
558
|
"@asyncapi/parser": "^3.6.4",
|
|
559
559
|
"@earendil-works/pi-ai": "1.3.0",
|