@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
package/dist/native.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HOME_ENTITY_LIMIT, HOME_KINDS, HOME_PAGE_LIMIT, parseHomeContribution, parseHomeEntity, parseHomeProjection, parseHomeSnapshot } from "./src/schemas/home.mjs";
|
|
2
|
-
import { defineActivityGroup, defineChannelFile,
|
|
2
|
+
import { defineActivityGroup, defineChannelFile, defineFileLinks, defineFill, defineNativeTemplate, defineSelectionAxis, defineSessionChannel, defineSettingsSection, defineSlotFile, defineTab, defineToolRenderer, defineUserMessageAction, defineWebLifecycle, defineWebPlugin } from "./src/extensions/webPlugin.mjs";
|
|
3
3
|
import { defineGlobalStore } from "./src/web/models/globalStore.mjs";
|
|
4
4
|
import { defineSessionStore } from "./src/web/models/sessionStore.mjs";
|
|
5
5
|
import { defineWorkspaceStore } from "./src/web/models/workspaceStore.mjs";
|
|
@@ -9,4 +9,4 @@ import { sessionApiAddress, sessionApiPath } from "./src/web/services/apiRoutes/
|
|
|
9
9
|
import { nativeApiTransport } from "./src/web/services/nativeApiTransport/index.mjs";
|
|
10
10
|
import { parseNativeTemplate } from "./src/web/schemas/template.mjs";
|
|
11
11
|
import { NATIVE_HOST_MODULES, NATIVE_HOST_MODULE_IDS, NATIVE_UNISTYLES_COMPONENTS, NATIVE_UNISTYLES_COMPONENT_PREFIX } from "./src/constants/nativeHost.mjs";
|
|
12
|
-
export { HOME_ENTITY_LIMIT, HOME_KINDS, HOME_PAGE_LIMIT, NATIVE_HOST_MODULES, NATIVE_HOST_MODULE_IDS, NATIVE_UNISTYLES_COMPONENTS, NATIVE_UNISTYLES_COMPONENT_PREFIX, apiResponse, createApiClient, defineActivityGroup, defineApiRoutes, defineChannelFile,
|
|
12
|
+
export { HOME_ENTITY_LIMIT, HOME_KINDS, HOME_PAGE_LIMIT, NATIVE_HOST_MODULES, NATIVE_HOST_MODULE_IDS, NATIVE_UNISTYLES_COMPONENTS, NATIVE_UNISTYLES_COMPONENT_PREFIX, apiResponse, createApiClient, defineActivityGroup, defineApiRoutes, defineChannelFile, defineFileLinks, defineFill, defineGlobalStore, defineWebPlugin as defineNativePlugin, defineNativeTemplate, defineSelectionAxis, defineSessionChannel, defineSessionStore, defineSettingsSection, defineSlotFile, defineTab, defineToolRenderer, defineUserMessageAction, defineWebLifecycle, defineWorkspaceStore, nativeApiTransport, parseHomeContribution, parseHomeEntity, parseHomeProjection, parseHomeSnapshot, parseNativeTemplate, sessionApiAddress, sessionApiPath, toolResultText, toolResultTextLines };
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
|
|
2
3
|
const require_serverTelemetry = require("./serverTelemetry.cjs");
|
|
3
4
|
const require_index = require("./src/services/sessionFiles/index.cjs");
|
|
4
5
|
const require_packageApi = require("./src/schemas/packageApi.cjs");
|
|
5
6
|
require("./packageApi.cjs");
|
|
6
|
-
const
|
|
7
|
+
const require_sessionFiles = require("./src/constants/sessionFiles.cjs");
|
|
8
|
+
const require_accessibleFile = require("./src/services/fileAccess/accessibleFile.cjs");
|
|
9
|
+
const require_index$1 = require("./src/services/fileAccess/index.cjs");
|
|
10
|
+
const require_index$2 = require("./src/services/serverHost/index.cjs");
|
|
7
11
|
const require_serverScope = require("./src/server/serverScope.cjs");
|
|
8
12
|
require("./serverPlugin.cjs");
|
|
9
|
-
const require_index$
|
|
13
|
+
const require_index$3 = require("./src/services/traceContext/index.cjs");
|
|
14
|
+
let node_path = require("node:path");
|
|
15
|
+
node_path = require_runtime.__toESM(node_path, 1);
|
|
10
16
|
//#region src/server/packageApiServer.ts
|
|
11
17
|
/**
|
|
12
18
|
* A body that keeps streaming well after its headers went out is worth its own span. A fast
|
|
@@ -49,6 +55,25 @@ function responseWithCompletion(response, complete) {
|
|
|
49
55
|
});
|
|
50
56
|
return new Response(body, response);
|
|
51
57
|
}
|
|
58
|
+
/** Reads files under the session's open folders; the hub's session `/file` route forwards here. */
|
|
59
|
+
function sessionFilesApi(fileAccess, cwd) {
|
|
60
|
+
return {
|
|
61
|
+
basePath: require_sessionFiles.SESSION_FILES_API,
|
|
62
|
+
start: () => ({
|
|
63
|
+
fetch: (request) => {
|
|
64
|
+
if (request.method !== "GET") return Response.json({ error: "Method not allowed." }, { status: 405 });
|
|
65
|
+
return require_accessibleFile.readAccessibleFile({
|
|
66
|
+
roots: fileAccess.roots(),
|
|
67
|
+
cwd,
|
|
68
|
+
path: new URL(request.url).searchParams.get("path"),
|
|
69
|
+
...request.headers.get("range") === null ? {} : { range: request.headers.get("range") },
|
|
70
|
+
...request.headers.get("if-match") === null ? {} : { expectedVersion: request.headers.get("if-match") }
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
close: () => void 0
|
|
74
|
+
})
|
|
75
|
+
};
|
|
76
|
+
}
|
|
52
77
|
/** Installs session packages and dispatches authenticated package API calls in-process. */
|
|
53
78
|
async function serveSessionApis(options) {
|
|
54
79
|
if (options.environment === void 0) throw new Error("Session package API server requires an admitted environment.");
|
|
@@ -109,20 +134,30 @@ async function serveSessionApis(options) {
|
|
|
109
134
|
...communication === void 0 ? {} : { sessionCommunication: communication },
|
|
110
135
|
onNotice: options.onNotice
|
|
111
136
|
};
|
|
112
|
-
const host = require_index$
|
|
137
|
+
const host = require_index$2.createPoServerHost({
|
|
113
138
|
scope: "session",
|
|
114
139
|
context,
|
|
115
140
|
mountChannel: options.mountChannel,
|
|
116
141
|
...options.pluginRegistry === void 0 ? {} : { pluginRegistry: options.pluginRegistry }
|
|
117
142
|
});
|
|
143
|
+
const fileAccess = require_index$1.createFileAccess();
|
|
144
|
+
for (const directory of [
|
|
145
|
+
options.cwd,
|
|
146
|
+
options.workspaceRoot,
|
|
147
|
+
options.environment[require_index.PO_SESSION_TEMP_DIR]
|
|
148
|
+
]) if (directory !== void 0 && node_path.default.isAbsolute(directory)) fileAccess.register(directory);
|
|
118
149
|
let scope;
|
|
119
150
|
try {
|
|
151
|
+
host.registerApi(sessionFilesApi(fileAccess, options.cwd));
|
|
120
152
|
for (const api of options.apis) host.registerApi(api);
|
|
121
153
|
scope = await require_serverScope.PoServerScope.open("session", options.parentScope);
|
|
122
154
|
await scope.serve({
|
|
123
155
|
host,
|
|
124
156
|
platform: options.platform
|
|
125
157
|
});
|
|
158
|
+
await scope.root.plugin((root) => {
|
|
159
|
+
root.provide(require_index$1.PO_FILE_ACCESS_SERVICE, fileAccess);
|
|
160
|
+
});
|
|
126
161
|
await options.preparePackages?.(scope.root);
|
|
127
162
|
const installed = await scope.install(packages, {
|
|
128
163
|
onNotice: options.onNotice,
|
|
@@ -164,7 +199,7 @@ async function serveSessionApis(options) {
|
|
|
164
199
|
if (handler === void 0) return Response.json({ error: `No API '${basePath}' in this session.` }, { status: 404 });
|
|
165
200
|
url.pathname = slash === -1 ? "/" : rest.slice(slash);
|
|
166
201
|
const startedAt = performance.now();
|
|
167
|
-
const parent = require_index$
|
|
202
|
+
const parent = require_index$3.validatedTraceContext(request.headers.get("traceparent"));
|
|
168
203
|
let childContext;
|
|
169
204
|
let response;
|
|
170
205
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageApiServer.cjs","names":["prepareSessionEnvironment","createPoServerHost","PoServerScope","PO_API_ROUTE_PREFIX","validatedTraceContext"],"sources":["../src/server/packageApiServer.ts"],"sourcesContent":["import type { PoTraceContext } from '@agimon-ai/po-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport type { PoDirectEventBus, PoHubSessionPromptOptions, PoHubSessionService } from '../exports/hubChannel';\nimport { PO_API_ROUTE_PREFIX, type PoApi, type PoApiContext } from '../exports/packageApi';\nimport type { PoPlatform } from '../exports/platform';\nimport type { PoPluginRegistry } from '../exports/pluginProtocol';\nimport {\n createPoServerHost,\n type CreatePoServerHostOptions,\n type LoadedServerPackage,\n type PoServerPlugin,\n PoServerScope,\n} from '../exports/serverPlugin';\nimport { observe, type ServerTelemetry } from '../services/serverTelemetry';\nimport { prepareSessionEnvironment } from '../services/sessionFiles';\nimport { validatedTraceContext } from '../services/traceContext';\n\n/**\n * A body that keeps streaming well after its headers went out is worth its own span. A fast\n * one is not: the request span already carries the duration and outcome, so emitting a second\n * span per call made package API traffic 99.65% of all spans recorded in a two hour sample.\n */\nexport const COMPLETION_SPAN_MIN_DURATION_MS = 1000;\n\nexport interface PackageApiServerOptions {\n sessionId: string;\n workspaceId?: string;\n workspaceRoot?: string;\n sessionContext?: PoApiContext['sessionContext'];\n homeDirectory?: string;\n mountChannel?: CreatePoServerHostOptions['mountChannel'];\n cwd: string;\n /** Admitted environment for APIs serving this session. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n /** Lifecycle-owned direct events shared with the hub. */\n readonly directEvents: PoDirectEventBus;\n readonly computerUse?: PoApiContext['computerUse'];\n /** Bound to this session's id and cwd by the host. */\n readonly shareFile?: PoApiContext['shareFile'];\n readonly mediaArbitration?: PoApiContext['mediaArbitration'];\n readonly executionBudget?: PoApiContext['executionBudget'];\n readonly editPresence?: PoApiContext['editPresence'];\n readonly peerAgents?: PoApiContext['peerAgents'];\n readonly requestApi?: PoApiContext['requestApi'];\n /** Publishes this session's activity line through the hub; bound to this session only. */\n readonly publishActivity?: PoApiContext['publishActivity'];\n internalToken?: string;\n hubToken?: string;\n /** Shared exact-scope dispatch table, so session packages can mount plugin methods. */\n pluginRegistry?: PoPluginRegistry;\n sessionService?: PoHubSessionService;\n apis: readonly PoApi[];\n /** Server packages to install; each registers its own APIs through the host. */\n packages?: readonly (PoServerPlugin | LoadedServerPackage)[];\n /** Publishes the session's own services into its scope root before any package installs. */\n preparePackages?: (root: Context) => void | Promise<void>;\n /** The hub's workspace or global scope; the session's own scope opens below it and closes with it. */\n parentScope?: PoServerScope;\n /** Host capabilities for the session scope root, injected by the composition root. */\n platform: PoPlatform;\n activatePackages?: (installedPackages: readonly string[]) => Promise<void>;\n canDispatch?: () => boolean;\n telemetry?: ServerTelemetry;\n onNotice: (message: string) => void;\n}\n\nexport interface PackageApiServer {\n /** Dispatches an already-authenticated request without crossing a transport boundary. */\n readonly request: (request: Request) => Promise<Response>;\n close(): Promise<void>;\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction responseWithCompletion(response: Response, complete: () => void): Response {\n if (response.body === null) {\n complete();\n return response;\n }\n const reader = response.body.getReader();\n let completed = false;\n const finish = (): void => {\n if (completed) return;\n completed = true;\n complete();\n };\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const result = await reader.read();\n if (result.done) {\n finish();\n controller.close();\n } else controller.enqueue(result.value);\n } catch (error) {\n finish();\n controller.error(error);\n }\n },\n async cancel(reason) {\n finish();\n await reader.cancel(reason);\n },\n });\n return new Response(body, response);\n}\n\n/** Installs session packages and dispatches authenticated package API calls in-process. */\nexport async function serveSessionApis(options: PackageApiServerOptions): Promise<PackageApiServer> {\n if (options.environment === undefined)\n throw new Error('Session package API server requires an admitted environment.');\n if (options.directEvents === undefined) throw new Error('Session package API server requires direct events.');\n options = { ...options, environment: await prepareSessionEnvironment(options) };\n const packages = options.packages ?? [];\n // Without a level above it, a session that mounts nothing has nothing to route.\n const routesNothing = (): boolean => !options.preparePackages && options.parentScope === undefined;\n if (options.apis.length === 0 && packages.length === 0 && routesNothing()) {\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n\n const owningSessionService = options.sessionService;\n const communication = owningSessionService?.bindCommunication?.(options.sessionId);\n const ownedReadExecutionState = owningSessionService?.readExecutionState?.bind(owningSessionService);\n const ownedPrompt = owningSessionService?.prompt?.bind(owningSessionService);\n const ownedAbort = owningSessionService?.abort?.bind(owningSessionService);\n const ownedSteer = owningSessionService?.steer?.bind(owningSessionService);\n const ownedRelease = owningSessionService?.release?.bind(owningSessionService);\n const exposedSessionService: PoHubSessionService | undefined =\n owningSessionService === undefined\n ? undefined\n : {\n create: (request) => owningSessionService.create(request),\n close: (sessionId) => owningSessionService.close(sessionId),\n isLive: (sessionId) => owningSessionService.isLive(sessionId),\n ...(ownedReadExecutionState === undefined\n ? {}\n : {\n readExecutionState: (sessionId: string) =>\n ownedReadExecutionState(sessionId, { parentSessionId: options.sessionId }),\n }),\n // A session may drive only the children it started, never its parent or a sibling.\n ...(ownedPrompt === undefined\n ? {}\n : {\n prompt: (sessionId: string, text: string, promptOptions?: PoHubSessionPromptOptions) =>\n ownedPrompt(sessionId, text, {\n ...(promptOptions?.signal === undefined ? {} : { signal: promptOptions.signal }),\n parentSessionId: options.sessionId,\n }),\n }),\n ...(ownedAbort === undefined\n ? {}\n : {\n abort: (sessionId: string) => ownedAbort(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(ownedSteer === undefined\n ? {}\n : {\n steer: (sessionId: string, message: string) =>\n ownedSteer(sessionId, message, { parentSessionId: options.sessionId }),\n }),\n ...(ownedRelease === undefined\n ? {}\n : {\n release: (sessionId: string) => ownedRelease(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(owningSessionService.canCommunicate === undefined\n ? {}\n : {\n canCommunicate: (sourceSessionId: string, targetSessionId: string) =>\n owningSessionService.canCommunicate?.(sourceSessionId, targetSessionId) === true,\n }),\n };\n const context: PoApiContext = {\n scope: 'session',\n sessionId: options.sessionId,\n workspaceId: options.workspaceId,\n workspaceRoot: options.workspaceRoot,\n ...(options.sessionContext === undefined ? {} : { sessionContext: options.sessionContext }),\n homeDirectory: options.homeDirectory ?? options.platform.homeDirectory,\n sessionStorage: options.platform.sessions,\n cwd: options.cwd,\n environment: options.environment,\n directEvents: options.directEvents,\n ...(options.computerUse === undefined ? {} : { computerUse: options.computerUse }),\n ...(options.shareFile === undefined ? {} : { shareFile: options.shareFile }),\n ...(options.mediaArbitration === undefined ? {} : { mediaArbitration: options.mediaArbitration }),\n ...(options.executionBudget === undefined ? {} : { executionBudget: options.executionBudget }),\n ...(options.editPresence === undefined ? {} : { editPresence: options.editPresence }),\n ...(options.peerAgents === undefined ? {} : { peerAgents: options.peerAgents }),\n ...(options.requestApi === undefined ? {} : { requestApi: options.requestApi }),\n ...(options.publishActivity === undefined ? {} : { publishActivity: options.publishActivity }),\n ...(options.internalToken === undefined ? {} : { internalToken: options.internalToken }),\n ...(options.hubToken === undefined ? {} : { hubToken: options.hubToken }),\n ...(exposedSessionService === undefined ? {} : { sessionService: exposedSessionService }),\n ...(communication === undefined ? {} : { sessionCommunication: communication }),\n onNotice: options.onNotice,\n };\n const host = createPoServerHost({\n scope: 'session',\n context,\n mountChannel: options.mountChannel,\n ...(options.pluginRegistry === undefined ? {} : { pluginRegistry: options.pluginRegistry }),\n });\n let scope: PoServerScope | undefined;\n try {\n for (const api of options.apis) host.registerApi(api);\n // The session's own level of the server IoC tree; it closes with the hub level it opens below.\n scope = await PoServerScope.open('session', options.parentScope);\n await scope.serve({ host, platform: options.platform });\n await options.preparePackages?.(scope.root);\n const installed = await scope.install(packages, {\n onNotice: options.onNotice,\n onPackageSettled: (report) => {\n if (!options.telemetry) return;\n observe(\n options.telemetry.recordEvent('po_server.package_install', {\n 'package.name': report.packageName,\n 'package.outcome': report.outcome,\n duration_ms: report.durationMs,\n scope: 'session',\n }),\n options.onNotice,\n );\n },\n });\n await options.activatePackages?.(installed);\n } catch (error) {\n await scope?.dispose();\n communication?.close();\n host.dispose();\n throw error;\n }\n if (host.mounted().length === 0 && routesNothing()) {\n await scope.dispose();\n communication?.close();\n host.dispose();\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n const sessionScope = scope;\n\n const dispatch = async (request: Request): Promise<Response> => {\n if (options.canDispatch?.() === false)\n return Response.json({ error: 'Session selection is not ready.' }, { status: 503 });\n const url = new URL(request.url);\n if (!url.pathname.startsWith(`${PO_API_ROUTE_PREFIX}/`))\n return Response.json({ error: 'Not found.' }, { status: 404 });\n const rest = url.pathname.slice(PO_API_ROUTE_PREFIX.length + 1);\n const slash = rest.indexOf('/');\n const basePath = slash === -1 ? rest : rest.slice(0, slash);\n // The session's own API, else the nearest level above it that serves one.\n const handler = sessionScope.apiHandler(basePath);\n if (handler === undefined)\n return Response.json({ error: `No API '${basePath}' in this session.` }, { status: 404 });\n url.pathname = slash === -1 ? '/' : rest.slice(slash);\n const startedAt = performance.now();\n const parent = validatedTraceContext(request.headers.get('traceparent'));\n let childContext: PoTraceContext | undefined;\n let response: Response;\n try {\n const invoke = async (context?: PoTraceContext): Promise<Response> => {\n if (options.canDispatch?.() === false || sessionScope.apiHandler(basePath) !== handler) {\n return Response.json({ error: 'Session selection changed before dispatch.' }, { status: 503 });\n }\n childContext = context;\n return handler.fetch(new Request(url, request));\n };\n response = options.telemetry\n ? await options.telemetry.runInSpan(\n 'po_server.package_api.request',\n { api: basePath, method: request.method },\n invoke,\n parent,\n )\n : await invoke();\n } catch (error) {\n if (request.signal.aborted) return new Response(null, { status: 499 });\n options.onNotice(`package API '${basePath}' failed on ${url.pathname} (${describeError(error)})`);\n response = Response.json({ error: `The '${basePath}' API failed.` }, { status: 500 });\n }\n return responseWithCompletion(response, () => {\n if (!options.telemetry) return;\n const durationMs = Math.round(performance.now() - startedAt);\n // Keep this span only where it says something the request span cannot: a failing status,\n // or a body that took real time to flush after the headers were sent.\n if (response.status < 400 && durationMs < COMPLETION_SPAN_MIN_DURATION_MS) return;\n observe(\n options.telemetry.runInSpan(\n 'po_server.package_api.complete',\n {\n api: basePath,\n method: request.method,\n status_code: response.status,\n duration_ms: durationMs,\n },\n async () => undefined,\n childContext ?? parent,\n ),\n options.onNotice,\n );\n });\n };\n let closePromise: Promise<void> | undefined;\n\n return {\n request: dispatch,\n close: () => {\n closePromise ??= (async () => {\n await scope.dispose();\n communication?.close();\n host.dispose();\n })();\n return closePromise;\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"packageApiServer.cjs","names":["SESSION_FILES_API","readAccessibleFile","prepareSessionEnvironment","createPoServerHost","createFileAccess","PO_SESSION_TEMP_DIR","path","PoServerScope","PO_FILE_ACCESS_SERVICE","PO_API_ROUTE_PREFIX","validatedTraceContext"],"sources":["../src/server/packageApiServer.ts"],"sourcesContent":["import path from 'node:path';\n\nimport type { PoTraceContext } from '@agimon-ai/po-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { SESSION_FILES_API } from '../constants/sessionFiles';\nimport type { PoDirectEventBus, PoHubSessionPromptOptions, PoHubSessionService } from '../exports/hubChannel';\nimport { PO_API_ROUTE_PREFIX, type PoApi, type PoApiContext } from '../exports/packageApi';\nimport type { PoPlatform } from '../exports/platform';\nimport type { PoPluginRegistry } from '../exports/pluginProtocol';\nimport {\n createPoServerHost,\n type CreatePoServerHostOptions,\n type LoadedServerPackage,\n type PoServerPlugin,\n PoServerScope,\n} from '../exports/serverPlugin';\nimport {\n createFileAccess,\n PO_FILE_ACCESS_SERVICE,\n type PoFileAccess,\n readAccessibleFile,\n} from '../services/fileAccess';\nimport { observe, type ServerTelemetry } from '../services/serverTelemetry';\nimport { PO_SESSION_TEMP_DIR, prepareSessionEnvironment } from '../services/sessionFiles';\nimport { validatedTraceContext } from '../services/traceContext';\n\n/**\n * A body that keeps streaming well after its headers went out is worth its own span. A fast\n * one is not: the request span already carries the duration and outcome, so emitting a second\n * span per call made package API traffic 99.65% of all spans recorded in a two hour sample.\n */\nexport const COMPLETION_SPAN_MIN_DURATION_MS = 1000;\n\nexport interface PackageApiServerOptions {\n sessionId: string;\n workspaceId?: string;\n workspaceRoot?: string;\n sessionContext?: PoApiContext['sessionContext'];\n homeDirectory?: string;\n mountChannel?: CreatePoServerHostOptions['mountChannel'];\n cwd: string;\n /** Admitted environment for APIs serving this session. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n /** Lifecycle-owned direct events shared with the hub. */\n readonly directEvents: PoDirectEventBus;\n readonly computerUse?: PoApiContext['computerUse'];\n /** Bound to this session's id and cwd by the host. */\n readonly shareFile?: PoApiContext['shareFile'];\n readonly mediaArbitration?: PoApiContext['mediaArbitration'];\n readonly executionBudget?: PoApiContext['executionBudget'];\n readonly editPresence?: PoApiContext['editPresence'];\n readonly peerAgents?: PoApiContext['peerAgents'];\n readonly requestApi?: PoApiContext['requestApi'];\n /** Publishes this session's activity line through the hub; bound to this session only. */\n readonly publishActivity?: PoApiContext['publishActivity'];\n internalToken?: string;\n hubToken?: string;\n /** Shared exact-scope dispatch table, so session packages can mount plugin methods. */\n pluginRegistry?: PoPluginRegistry;\n sessionService?: PoHubSessionService;\n apis: readonly PoApi[];\n /** Server packages to install; each registers its own APIs through the host. */\n packages?: readonly (PoServerPlugin | LoadedServerPackage)[];\n /** Publishes the session's own services into its scope root before any package installs. */\n preparePackages?: (root: Context) => void | Promise<void>;\n /** The hub's workspace or global scope; the session's own scope opens below it and closes with it. */\n parentScope?: PoServerScope;\n /** Host capabilities for the session scope root, injected by the composition root. */\n platform: PoPlatform;\n activatePackages?: (installedPackages: readonly string[]) => Promise<void>;\n canDispatch?: () => boolean;\n telemetry?: ServerTelemetry;\n onNotice: (message: string) => void;\n}\n\nexport interface PackageApiServer {\n /** Dispatches an already-authenticated request without crossing a transport boundary. */\n readonly request: (request: Request) => Promise<Response>;\n close(): Promise<void>;\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction responseWithCompletion(response: Response, complete: () => void): Response {\n if (response.body === null) {\n complete();\n return response;\n }\n const reader = response.body.getReader();\n let completed = false;\n const finish = (): void => {\n if (completed) return;\n completed = true;\n complete();\n };\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const result = await reader.read();\n if (result.done) {\n finish();\n controller.close();\n } else controller.enqueue(result.value);\n } catch (error) {\n finish();\n controller.error(error);\n }\n },\n async cancel(reason) {\n finish();\n await reader.cancel(reason);\n },\n });\n return new Response(body, response);\n}\n\n/** Reads files under the session's open folders; the hub's session `/file` route forwards here. */\nfunction sessionFilesApi(fileAccess: PoFileAccess, cwd: string): PoApi {\n return {\n basePath: SESSION_FILES_API,\n start: () => ({\n fetch: (request) => {\n if (request.method !== 'GET') return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n return readAccessibleFile({\n roots: fileAccess.roots(),\n cwd,\n path: new URL(request.url).searchParams.get('path'),\n ...(request.headers.get('range') === null ? {} : { range: request.headers.get('range')! }),\n ...(request.headers.get('if-match') === null ? {} : { expectedVersion: request.headers.get('if-match')! }),\n });\n },\n close: () => undefined,\n }),\n };\n}\n/** Installs session packages and dispatches authenticated package API calls in-process. */\nexport async function serveSessionApis(options: PackageApiServerOptions): Promise<PackageApiServer> {\n if (options.environment === undefined)\n throw new Error('Session package API server requires an admitted environment.');\n if (options.directEvents === undefined) throw new Error('Session package API server requires direct events.');\n options = { ...options, environment: await prepareSessionEnvironment(options) };\n const packages = options.packages ?? [];\n // Without a level above it, a session that mounts nothing has nothing to route.\n const routesNothing = (): boolean => !options.preparePackages && options.parentScope === undefined;\n if (options.apis.length === 0 && packages.length === 0 && routesNothing()) {\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n\n const owningSessionService = options.sessionService;\n const communication = owningSessionService?.bindCommunication?.(options.sessionId);\n const ownedReadExecutionState = owningSessionService?.readExecutionState?.bind(owningSessionService);\n const ownedPrompt = owningSessionService?.prompt?.bind(owningSessionService);\n const ownedAbort = owningSessionService?.abort?.bind(owningSessionService);\n const ownedSteer = owningSessionService?.steer?.bind(owningSessionService);\n const ownedRelease = owningSessionService?.release?.bind(owningSessionService);\n const exposedSessionService: PoHubSessionService | undefined =\n owningSessionService === undefined\n ? undefined\n : {\n create: (request) => owningSessionService.create(request),\n close: (sessionId) => owningSessionService.close(sessionId),\n isLive: (sessionId) => owningSessionService.isLive(sessionId),\n ...(ownedReadExecutionState === undefined\n ? {}\n : {\n readExecutionState: (sessionId: string) =>\n ownedReadExecutionState(sessionId, { parentSessionId: options.sessionId }),\n }),\n // A session may drive only the children it started, never its parent or a sibling.\n ...(ownedPrompt === undefined\n ? {}\n : {\n prompt: (sessionId: string, text: string, promptOptions?: PoHubSessionPromptOptions) =>\n ownedPrompt(sessionId, text, {\n ...(promptOptions?.signal === undefined ? {} : { signal: promptOptions.signal }),\n parentSessionId: options.sessionId,\n }),\n }),\n ...(ownedAbort === undefined\n ? {}\n : {\n abort: (sessionId: string) => ownedAbort(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(ownedSteer === undefined\n ? {}\n : {\n steer: (sessionId: string, message: string) =>\n ownedSteer(sessionId, message, { parentSessionId: options.sessionId }),\n }),\n ...(ownedRelease === undefined\n ? {}\n : {\n release: (sessionId: string) => ownedRelease(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(owningSessionService.canCommunicate === undefined\n ? {}\n : {\n canCommunicate: (sourceSessionId: string, targetSessionId: string) =>\n owningSessionService.canCommunicate?.(sourceSessionId, targetSessionId) === true,\n }),\n };\n const context: PoApiContext = {\n scope: 'session',\n sessionId: options.sessionId,\n workspaceId: options.workspaceId,\n workspaceRoot: options.workspaceRoot,\n ...(options.sessionContext === undefined ? {} : { sessionContext: options.sessionContext }),\n homeDirectory: options.homeDirectory ?? options.platform.homeDirectory,\n sessionStorage: options.platform.sessions,\n cwd: options.cwd,\n environment: options.environment,\n directEvents: options.directEvents,\n ...(options.computerUse === undefined ? {} : { computerUse: options.computerUse }),\n ...(options.shareFile === undefined ? {} : { shareFile: options.shareFile }),\n ...(options.mediaArbitration === undefined ? {} : { mediaArbitration: options.mediaArbitration }),\n ...(options.executionBudget === undefined ? {} : { executionBudget: options.executionBudget }),\n ...(options.editPresence === undefined ? {} : { editPresence: options.editPresence }),\n ...(options.peerAgents === undefined ? {} : { peerAgents: options.peerAgents }),\n ...(options.requestApi === undefined ? {} : { requestApi: options.requestApi }),\n ...(options.publishActivity === undefined ? {} : { publishActivity: options.publishActivity }),\n ...(options.internalToken === undefined ? {} : { internalToken: options.internalToken }),\n ...(options.hubToken === undefined ? {} : { hubToken: options.hubToken }),\n ...(exposedSessionService === undefined ? {} : { sessionService: exposedSessionService }),\n ...(communication === undefined ? {} : { sessionCommunication: communication }),\n onNotice: options.onNotice,\n };\n const host = createPoServerHost({\n scope: 'session',\n context,\n mountChannel: options.mountChannel,\n ...(options.pluginRegistry === undefined ? {} : { pluginRegistry: options.pluginRegistry }),\n });\n // The session's own folder, its workspace and its temp folder; extensions open their own beside these.\n const fileAccess = createFileAccess();\n for (const directory of [options.cwd, options.workspaceRoot, options.environment[PO_SESSION_TEMP_DIR]])\n if (directory !== undefined && path.isAbsolute(directory)) fileAccess.register(directory);\n let scope: PoServerScope | undefined;\n try {\n // Registered first, so no package can claim the host's own base path.\n host.registerApi(sessionFilesApi(fileAccess, options.cwd));\n for (const api of options.apis) host.registerApi(api);\n // The session's own level of the server IoC tree; it closes with the hub level it opens below.\n scope = await PoServerScope.open('session', options.parentScope);\n await scope.serve({ host, platform: options.platform });\n await scope.root.plugin((root) => {\n root.provide(PO_FILE_ACCESS_SERVICE, fileAccess);\n });\n await options.preparePackages?.(scope.root);\n const installed = await scope.install(packages, {\n onNotice: options.onNotice,\n onPackageSettled: (report) => {\n if (!options.telemetry) return;\n observe(\n options.telemetry.recordEvent('po_server.package_install', {\n 'package.name': report.packageName,\n 'package.outcome': report.outcome,\n duration_ms: report.durationMs,\n scope: 'session',\n }),\n options.onNotice,\n );\n },\n });\n await options.activatePackages?.(installed);\n } catch (error) {\n await scope?.dispose();\n communication?.close();\n host.dispose();\n throw error;\n }\n if (host.mounted().length === 0 && routesNothing()) {\n await scope.dispose();\n communication?.close();\n host.dispose();\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n const sessionScope = scope;\n\n const dispatch = async (request: Request): Promise<Response> => {\n if (options.canDispatch?.() === false)\n return Response.json({ error: 'Session selection is not ready.' }, { status: 503 });\n const url = new URL(request.url);\n if (!url.pathname.startsWith(`${PO_API_ROUTE_PREFIX}/`))\n return Response.json({ error: 'Not found.' }, { status: 404 });\n const rest = url.pathname.slice(PO_API_ROUTE_PREFIX.length + 1);\n const slash = rest.indexOf('/');\n const basePath = slash === -1 ? rest : rest.slice(0, slash);\n // The session's own API, else the nearest level above it that serves one.\n const handler = sessionScope.apiHandler(basePath);\n if (handler === undefined)\n return Response.json({ error: `No API '${basePath}' in this session.` }, { status: 404 });\n url.pathname = slash === -1 ? '/' : rest.slice(slash);\n const startedAt = performance.now();\n const parent = validatedTraceContext(request.headers.get('traceparent'));\n let childContext: PoTraceContext | undefined;\n let response: Response;\n try {\n const invoke = async (context?: PoTraceContext): Promise<Response> => {\n if (options.canDispatch?.() === false || sessionScope.apiHandler(basePath) !== handler) {\n return Response.json({ error: 'Session selection changed before dispatch.' }, { status: 503 });\n }\n childContext = context;\n return handler.fetch(new Request(url, request));\n };\n response = options.telemetry\n ? await options.telemetry.runInSpan(\n 'po_server.package_api.request',\n { api: basePath, method: request.method },\n invoke,\n parent,\n )\n : await invoke();\n } catch (error) {\n if (request.signal.aborted) return new Response(null, { status: 499 });\n options.onNotice(`package API '${basePath}' failed on ${url.pathname} (${describeError(error)})`);\n response = Response.json({ error: `The '${basePath}' API failed.` }, { status: 500 });\n }\n return responseWithCompletion(response, () => {\n if (!options.telemetry) return;\n const durationMs = Math.round(performance.now() - startedAt);\n // Keep this span only where it says something the request span cannot: a failing status,\n // or a body that took real time to flush after the headers were sent.\n if (response.status < 400 && durationMs < COMPLETION_SPAN_MIN_DURATION_MS) return;\n observe(\n options.telemetry.runInSpan(\n 'po_server.package_api.complete',\n {\n api: basePath,\n method: request.method,\n status_code: response.status,\n duration_ms: durationMs,\n },\n async () => undefined,\n childContext ?? parent,\n ),\n options.onNotice,\n );\n });\n };\n let closePromise: Promise<void> | undefined;\n\n return {\n request: dispatch,\n close: () => {\n closePromise ??= (async () => {\n await scope.dispose();\n communication?.close();\n host.dispose();\n })();\n return closePromise;\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageApiServer.d.mts","names":[],"sources":["../src/server/packageApiServer.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"packageApiServer.d.mts","names":[],"sources":["../src/server/packageApiServer.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;qBAgCa;iBAEI;EACf;EACA;EACA;EACA,iBAAiB;EACjB;EACA,eAAe;EACf;;WAES,aAAa,SAAS;;WAEtB,cAAc;WACd,cAAc;;WAEd,YAAY;WACZ,mBAAmB;WACnB,kBAAkB;WAClB,eAAe;WACf,aAAa;WACb,aAAa;;WAEb,kBAAkB;EAC3B;EACA;;EAEA,iBAAiB;EACjB,iBAAiB;EACjB,eAAe;;EAEf,qBAAqB,iBAAiB;;EAEtC,mBAAmB,MAAM,mBAAmB;;EAE5C,cAAc;;EAEd,UAAU;EACV,oBAAoB,yCAAyC;EAC7D;EACA,YAAY;EACZ,WAAW;;iBAGI;;WAEN,UAAU,SAAS,YAAY,QAAQ;EAChD,SAAS;;;wBA4DW,iBAAiB,SAAS,0BAA0B,QAAQ"}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { observe } from "./serverTelemetry.mjs";
|
|
2
|
-
import { prepareSessionEnvironment } from "./src/services/sessionFiles/index.mjs";
|
|
2
|
+
import { PO_SESSION_TEMP_DIR, prepareSessionEnvironment } from "./src/services/sessionFiles/index.mjs";
|
|
3
3
|
import { PO_API_ROUTE_PREFIX } from "./src/schemas/packageApi.mjs";
|
|
4
4
|
import "./packageApi.mjs";
|
|
5
|
+
import { SESSION_FILES_API } from "./src/constants/sessionFiles.mjs";
|
|
6
|
+
import { readAccessibleFile } from "./src/services/fileAccess/accessibleFile.mjs";
|
|
7
|
+
import { PO_FILE_ACCESS_SERVICE, createFileAccess } from "./src/services/fileAccess/index.mjs";
|
|
5
8
|
import { createPoServerHost } from "./src/services/serverHost/index.mjs";
|
|
6
9
|
import { PoServerScope } from "./src/server/serverScope.mjs";
|
|
7
10
|
import "./serverPlugin.mjs";
|
|
8
11
|
import { validatedTraceContext } from "./src/services/traceContext/index.mjs";
|
|
12
|
+
import path from "node:path";
|
|
9
13
|
//#region src/server/packageApiServer.ts
|
|
10
14
|
/**
|
|
11
15
|
* A body that keeps streaming well after its headers went out is worth its own span. A fast
|
|
@@ -48,6 +52,25 @@ function responseWithCompletion(response, complete) {
|
|
|
48
52
|
});
|
|
49
53
|
return new Response(body, response);
|
|
50
54
|
}
|
|
55
|
+
/** Reads files under the session's open folders; the hub's session `/file` route forwards here. */
|
|
56
|
+
function sessionFilesApi(fileAccess, cwd) {
|
|
57
|
+
return {
|
|
58
|
+
basePath: SESSION_FILES_API,
|
|
59
|
+
start: () => ({
|
|
60
|
+
fetch: (request) => {
|
|
61
|
+
if (request.method !== "GET") return Response.json({ error: "Method not allowed." }, { status: 405 });
|
|
62
|
+
return readAccessibleFile({
|
|
63
|
+
roots: fileAccess.roots(),
|
|
64
|
+
cwd,
|
|
65
|
+
path: new URL(request.url).searchParams.get("path"),
|
|
66
|
+
...request.headers.get("range") === null ? {} : { range: request.headers.get("range") },
|
|
67
|
+
...request.headers.get("if-match") === null ? {} : { expectedVersion: request.headers.get("if-match") }
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
close: () => void 0
|
|
71
|
+
})
|
|
72
|
+
};
|
|
73
|
+
}
|
|
51
74
|
/** Installs session packages and dispatches authenticated package API calls in-process. */
|
|
52
75
|
async function serveSessionApis(options) {
|
|
53
76
|
if (options.environment === void 0) throw new Error("Session package API server requires an admitted environment.");
|
|
@@ -114,14 +137,24 @@ async function serveSessionApis(options) {
|
|
|
114
137
|
mountChannel: options.mountChannel,
|
|
115
138
|
...options.pluginRegistry === void 0 ? {} : { pluginRegistry: options.pluginRegistry }
|
|
116
139
|
});
|
|
140
|
+
const fileAccess = createFileAccess();
|
|
141
|
+
for (const directory of [
|
|
142
|
+
options.cwd,
|
|
143
|
+
options.workspaceRoot,
|
|
144
|
+
options.environment[PO_SESSION_TEMP_DIR]
|
|
145
|
+
]) if (directory !== void 0 && path.isAbsolute(directory)) fileAccess.register(directory);
|
|
117
146
|
let scope;
|
|
118
147
|
try {
|
|
148
|
+
host.registerApi(sessionFilesApi(fileAccess, options.cwd));
|
|
119
149
|
for (const api of options.apis) host.registerApi(api);
|
|
120
150
|
scope = await PoServerScope.open("session", options.parentScope);
|
|
121
151
|
await scope.serve({
|
|
122
152
|
host,
|
|
123
153
|
platform: options.platform
|
|
124
154
|
});
|
|
155
|
+
await scope.root.plugin((root) => {
|
|
156
|
+
root.provide(PO_FILE_ACCESS_SERVICE, fileAccess);
|
|
157
|
+
});
|
|
125
158
|
await options.preparePackages?.(scope.root);
|
|
126
159
|
const installed = await scope.install(packages, {
|
|
127
160
|
onNotice: options.onNotice,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageApiServer.mjs","names":[],"sources":["../src/server/packageApiServer.ts"],"sourcesContent":["import type { PoTraceContext } from '@agimon-ai/po-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport type { PoDirectEventBus, PoHubSessionPromptOptions, PoHubSessionService } from '../exports/hubChannel';\nimport { PO_API_ROUTE_PREFIX, type PoApi, type PoApiContext } from '../exports/packageApi';\nimport type { PoPlatform } from '../exports/platform';\nimport type { PoPluginRegistry } from '../exports/pluginProtocol';\nimport {\n createPoServerHost,\n type CreatePoServerHostOptions,\n type LoadedServerPackage,\n type PoServerPlugin,\n PoServerScope,\n} from '../exports/serverPlugin';\nimport { observe, type ServerTelemetry } from '../services/serverTelemetry';\nimport { prepareSessionEnvironment } from '../services/sessionFiles';\nimport { validatedTraceContext } from '../services/traceContext';\n\n/**\n * A body that keeps streaming well after its headers went out is worth its own span. A fast\n * one is not: the request span already carries the duration and outcome, so emitting a second\n * span per call made package API traffic 99.65% of all spans recorded in a two hour sample.\n */\nexport const COMPLETION_SPAN_MIN_DURATION_MS = 1000;\n\nexport interface PackageApiServerOptions {\n sessionId: string;\n workspaceId?: string;\n workspaceRoot?: string;\n sessionContext?: PoApiContext['sessionContext'];\n homeDirectory?: string;\n mountChannel?: CreatePoServerHostOptions['mountChannel'];\n cwd: string;\n /** Admitted environment for APIs serving this session. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n /** Lifecycle-owned direct events shared with the hub. */\n readonly directEvents: PoDirectEventBus;\n readonly computerUse?: PoApiContext['computerUse'];\n /** Bound to this session's id and cwd by the host. */\n readonly shareFile?: PoApiContext['shareFile'];\n readonly mediaArbitration?: PoApiContext['mediaArbitration'];\n readonly executionBudget?: PoApiContext['executionBudget'];\n readonly editPresence?: PoApiContext['editPresence'];\n readonly peerAgents?: PoApiContext['peerAgents'];\n readonly requestApi?: PoApiContext['requestApi'];\n /** Publishes this session's activity line through the hub; bound to this session only. */\n readonly publishActivity?: PoApiContext['publishActivity'];\n internalToken?: string;\n hubToken?: string;\n /** Shared exact-scope dispatch table, so session packages can mount plugin methods. */\n pluginRegistry?: PoPluginRegistry;\n sessionService?: PoHubSessionService;\n apis: readonly PoApi[];\n /** Server packages to install; each registers its own APIs through the host. */\n packages?: readonly (PoServerPlugin | LoadedServerPackage)[];\n /** Publishes the session's own services into its scope root before any package installs. */\n preparePackages?: (root: Context) => void | Promise<void>;\n /** The hub's workspace or global scope; the session's own scope opens below it and closes with it. */\n parentScope?: PoServerScope;\n /** Host capabilities for the session scope root, injected by the composition root. */\n platform: PoPlatform;\n activatePackages?: (installedPackages: readonly string[]) => Promise<void>;\n canDispatch?: () => boolean;\n telemetry?: ServerTelemetry;\n onNotice: (message: string) => void;\n}\n\nexport interface PackageApiServer {\n /** Dispatches an already-authenticated request without crossing a transport boundary. */\n readonly request: (request: Request) => Promise<Response>;\n close(): Promise<void>;\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction responseWithCompletion(response: Response, complete: () => void): Response {\n if (response.body === null) {\n complete();\n return response;\n }\n const reader = response.body.getReader();\n let completed = false;\n const finish = (): void => {\n if (completed) return;\n completed = true;\n complete();\n };\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const result = await reader.read();\n if (result.done) {\n finish();\n controller.close();\n } else controller.enqueue(result.value);\n } catch (error) {\n finish();\n controller.error(error);\n }\n },\n async cancel(reason) {\n finish();\n await reader.cancel(reason);\n },\n });\n return new Response(body, response);\n}\n\n/** Installs session packages and dispatches authenticated package API calls in-process. */\nexport async function serveSessionApis(options: PackageApiServerOptions): Promise<PackageApiServer> {\n if (options.environment === undefined)\n throw new Error('Session package API server requires an admitted environment.');\n if (options.directEvents === undefined) throw new Error('Session package API server requires direct events.');\n options = { ...options, environment: await prepareSessionEnvironment(options) };\n const packages = options.packages ?? [];\n // Without a level above it, a session that mounts nothing has nothing to route.\n const routesNothing = (): boolean => !options.preparePackages && options.parentScope === undefined;\n if (options.apis.length === 0 && packages.length === 0 && routesNothing()) {\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n\n const owningSessionService = options.sessionService;\n const communication = owningSessionService?.bindCommunication?.(options.sessionId);\n const ownedReadExecutionState = owningSessionService?.readExecutionState?.bind(owningSessionService);\n const ownedPrompt = owningSessionService?.prompt?.bind(owningSessionService);\n const ownedAbort = owningSessionService?.abort?.bind(owningSessionService);\n const ownedSteer = owningSessionService?.steer?.bind(owningSessionService);\n const ownedRelease = owningSessionService?.release?.bind(owningSessionService);\n const exposedSessionService: PoHubSessionService | undefined =\n owningSessionService === undefined\n ? undefined\n : {\n create: (request) => owningSessionService.create(request),\n close: (sessionId) => owningSessionService.close(sessionId),\n isLive: (sessionId) => owningSessionService.isLive(sessionId),\n ...(ownedReadExecutionState === undefined\n ? {}\n : {\n readExecutionState: (sessionId: string) =>\n ownedReadExecutionState(sessionId, { parentSessionId: options.sessionId }),\n }),\n // A session may drive only the children it started, never its parent or a sibling.\n ...(ownedPrompt === undefined\n ? {}\n : {\n prompt: (sessionId: string, text: string, promptOptions?: PoHubSessionPromptOptions) =>\n ownedPrompt(sessionId, text, {\n ...(promptOptions?.signal === undefined ? {} : { signal: promptOptions.signal }),\n parentSessionId: options.sessionId,\n }),\n }),\n ...(ownedAbort === undefined\n ? {}\n : {\n abort: (sessionId: string) => ownedAbort(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(ownedSteer === undefined\n ? {}\n : {\n steer: (sessionId: string, message: string) =>\n ownedSteer(sessionId, message, { parentSessionId: options.sessionId }),\n }),\n ...(ownedRelease === undefined\n ? {}\n : {\n release: (sessionId: string) => ownedRelease(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(owningSessionService.canCommunicate === undefined\n ? {}\n : {\n canCommunicate: (sourceSessionId: string, targetSessionId: string) =>\n owningSessionService.canCommunicate?.(sourceSessionId, targetSessionId) === true,\n }),\n };\n const context: PoApiContext = {\n scope: 'session',\n sessionId: options.sessionId,\n workspaceId: options.workspaceId,\n workspaceRoot: options.workspaceRoot,\n ...(options.sessionContext === undefined ? {} : { sessionContext: options.sessionContext }),\n homeDirectory: options.homeDirectory ?? options.platform.homeDirectory,\n sessionStorage: options.platform.sessions,\n cwd: options.cwd,\n environment: options.environment,\n directEvents: options.directEvents,\n ...(options.computerUse === undefined ? {} : { computerUse: options.computerUse }),\n ...(options.shareFile === undefined ? {} : { shareFile: options.shareFile }),\n ...(options.mediaArbitration === undefined ? {} : { mediaArbitration: options.mediaArbitration }),\n ...(options.executionBudget === undefined ? {} : { executionBudget: options.executionBudget }),\n ...(options.editPresence === undefined ? {} : { editPresence: options.editPresence }),\n ...(options.peerAgents === undefined ? {} : { peerAgents: options.peerAgents }),\n ...(options.requestApi === undefined ? {} : { requestApi: options.requestApi }),\n ...(options.publishActivity === undefined ? {} : { publishActivity: options.publishActivity }),\n ...(options.internalToken === undefined ? {} : { internalToken: options.internalToken }),\n ...(options.hubToken === undefined ? {} : { hubToken: options.hubToken }),\n ...(exposedSessionService === undefined ? {} : { sessionService: exposedSessionService }),\n ...(communication === undefined ? {} : { sessionCommunication: communication }),\n onNotice: options.onNotice,\n };\n const host = createPoServerHost({\n scope: 'session',\n context,\n mountChannel: options.mountChannel,\n ...(options.pluginRegistry === undefined ? {} : { pluginRegistry: options.pluginRegistry }),\n });\n let scope: PoServerScope | undefined;\n try {\n for (const api of options.apis) host.registerApi(api);\n // The session's own level of the server IoC tree; it closes with the hub level it opens below.\n scope = await PoServerScope.open('session', options.parentScope);\n await scope.serve({ host, platform: options.platform });\n await options.preparePackages?.(scope.root);\n const installed = await scope.install(packages, {\n onNotice: options.onNotice,\n onPackageSettled: (report) => {\n if (!options.telemetry) return;\n observe(\n options.telemetry.recordEvent('po_server.package_install', {\n 'package.name': report.packageName,\n 'package.outcome': report.outcome,\n duration_ms: report.durationMs,\n scope: 'session',\n }),\n options.onNotice,\n );\n },\n });\n await options.activatePackages?.(installed);\n } catch (error) {\n await scope?.dispose();\n communication?.close();\n host.dispose();\n throw error;\n }\n if (host.mounted().length === 0 && routesNothing()) {\n await scope.dispose();\n communication?.close();\n host.dispose();\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n const sessionScope = scope;\n\n const dispatch = async (request: Request): Promise<Response> => {\n if (options.canDispatch?.() === false)\n return Response.json({ error: 'Session selection is not ready.' }, { status: 503 });\n const url = new URL(request.url);\n if (!url.pathname.startsWith(`${PO_API_ROUTE_PREFIX}/`))\n return Response.json({ error: 'Not found.' }, { status: 404 });\n const rest = url.pathname.slice(PO_API_ROUTE_PREFIX.length + 1);\n const slash = rest.indexOf('/');\n const basePath = slash === -1 ? rest : rest.slice(0, slash);\n // The session's own API, else the nearest level above it that serves one.\n const handler = sessionScope.apiHandler(basePath);\n if (handler === undefined)\n return Response.json({ error: `No API '${basePath}' in this session.` }, { status: 404 });\n url.pathname = slash === -1 ? '/' : rest.slice(slash);\n const startedAt = performance.now();\n const parent = validatedTraceContext(request.headers.get('traceparent'));\n let childContext: PoTraceContext | undefined;\n let response: Response;\n try {\n const invoke = async (context?: PoTraceContext): Promise<Response> => {\n if (options.canDispatch?.() === false || sessionScope.apiHandler(basePath) !== handler) {\n return Response.json({ error: 'Session selection changed before dispatch.' }, { status: 503 });\n }\n childContext = context;\n return handler.fetch(new Request(url, request));\n };\n response = options.telemetry\n ? await options.telemetry.runInSpan(\n 'po_server.package_api.request',\n { api: basePath, method: request.method },\n invoke,\n parent,\n )\n : await invoke();\n } catch (error) {\n if (request.signal.aborted) return new Response(null, { status: 499 });\n options.onNotice(`package API '${basePath}' failed on ${url.pathname} (${describeError(error)})`);\n response = Response.json({ error: `The '${basePath}' API failed.` }, { status: 500 });\n }\n return responseWithCompletion(response, () => {\n if (!options.telemetry) return;\n const durationMs = Math.round(performance.now() - startedAt);\n // Keep this span only where it says something the request span cannot: a failing status,\n // or a body that took real time to flush after the headers were sent.\n if (response.status < 400 && durationMs < COMPLETION_SPAN_MIN_DURATION_MS) return;\n observe(\n options.telemetry.runInSpan(\n 'po_server.package_api.complete',\n {\n api: basePath,\n method: request.method,\n status_code: response.status,\n duration_ms: durationMs,\n },\n async () => undefined,\n childContext ?? parent,\n ),\n options.onNotice,\n );\n });\n };\n let closePromise: Promise<void> | undefined;\n\n return {\n request: dispatch,\n close: () => {\n closePromise ??= (async () => {\n await scope.dispose();\n communication?.close();\n host.dispose();\n })();\n return closePromise;\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"packageApiServer.mjs","names":[],"sources":["../src/server/packageApiServer.ts"],"sourcesContent":["import path from 'node:path';\n\nimport type { PoTraceContext } from '@agimon-ai/po-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { SESSION_FILES_API } from '../constants/sessionFiles';\nimport type { PoDirectEventBus, PoHubSessionPromptOptions, PoHubSessionService } from '../exports/hubChannel';\nimport { PO_API_ROUTE_PREFIX, type PoApi, type PoApiContext } from '../exports/packageApi';\nimport type { PoPlatform } from '../exports/platform';\nimport type { PoPluginRegistry } from '../exports/pluginProtocol';\nimport {\n createPoServerHost,\n type CreatePoServerHostOptions,\n type LoadedServerPackage,\n type PoServerPlugin,\n PoServerScope,\n} from '../exports/serverPlugin';\nimport {\n createFileAccess,\n PO_FILE_ACCESS_SERVICE,\n type PoFileAccess,\n readAccessibleFile,\n} from '../services/fileAccess';\nimport { observe, type ServerTelemetry } from '../services/serverTelemetry';\nimport { PO_SESSION_TEMP_DIR, prepareSessionEnvironment } from '../services/sessionFiles';\nimport { validatedTraceContext } from '../services/traceContext';\n\n/**\n * A body that keeps streaming well after its headers went out is worth its own span. A fast\n * one is not: the request span already carries the duration and outcome, so emitting a second\n * span per call made package API traffic 99.65% of all spans recorded in a two hour sample.\n */\nexport const COMPLETION_SPAN_MIN_DURATION_MS = 1000;\n\nexport interface PackageApiServerOptions {\n sessionId: string;\n workspaceId?: string;\n workspaceRoot?: string;\n sessionContext?: PoApiContext['sessionContext'];\n homeDirectory?: string;\n mountChannel?: CreatePoServerHostOptions['mountChannel'];\n cwd: string;\n /** Admitted environment for APIs serving this session. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n /** Lifecycle-owned direct events shared with the hub. */\n readonly directEvents: PoDirectEventBus;\n readonly computerUse?: PoApiContext['computerUse'];\n /** Bound to this session's id and cwd by the host. */\n readonly shareFile?: PoApiContext['shareFile'];\n readonly mediaArbitration?: PoApiContext['mediaArbitration'];\n readonly executionBudget?: PoApiContext['executionBudget'];\n readonly editPresence?: PoApiContext['editPresence'];\n readonly peerAgents?: PoApiContext['peerAgents'];\n readonly requestApi?: PoApiContext['requestApi'];\n /** Publishes this session's activity line through the hub; bound to this session only. */\n readonly publishActivity?: PoApiContext['publishActivity'];\n internalToken?: string;\n hubToken?: string;\n /** Shared exact-scope dispatch table, so session packages can mount plugin methods. */\n pluginRegistry?: PoPluginRegistry;\n sessionService?: PoHubSessionService;\n apis: readonly PoApi[];\n /** Server packages to install; each registers its own APIs through the host. */\n packages?: readonly (PoServerPlugin | LoadedServerPackage)[];\n /** Publishes the session's own services into its scope root before any package installs. */\n preparePackages?: (root: Context) => void | Promise<void>;\n /** The hub's workspace or global scope; the session's own scope opens below it and closes with it. */\n parentScope?: PoServerScope;\n /** Host capabilities for the session scope root, injected by the composition root. */\n platform: PoPlatform;\n activatePackages?: (installedPackages: readonly string[]) => Promise<void>;\n canDispatch?: () => boolean;\n telemetry?: ServerTelemetry;\n onNotice: (message: string) => void;\n}\n\nexport interface PackageApiServer {\n /** Dispatches an already-authenticated request without crossing a transport boundary. */\n readonly request: (request: Request) => Promise<Response>;\n close(): Promise<void>;\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction responseWithCompletion(response: Response, complete: () => void): Response {\n if (response.body === null) {\n complete();\n return response;\n }\n const reader = response.body.getReader();\n let completed = false;\n const finish = (): void => {\n if (completed) return;\n completed = true;\n complete();\n };\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const result = await reader.read();\n if (result.done) {\n finish();\n controller.close();\n } else controller.enqueue(result.value);\n } catch (error) {\n finish();\n controller.error(error);\n }\n },\n async cancel(reason) {\n finish();\n await reader.cancel(reason);\n },\n });\n return new Response(body, response);\n}\n\n/** Reads files under the session's open folders; the hub's session `/file` route forwards here. */\nfunction sessionFilesApi(fileAccess: PoFileAccess, cwd: string): PoApi {\n return {\n basePath: SESSION_FILES_API,\n start: () => ({\n fetch: (request) => {\n if (request.method !== 'GET') return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n return readAccessibleFile({\n roots: fileAccess.roots(),\n cwd,\n path: new URL(request.url).searchParams.get('path'),\n ...(request.headers.get('range') === null ? {} : { range: request.headers.get('range')! }),\n ...(request.headers.get('if-match') === null ? {} : { expectedVersion: request.headers.get('if-match')! }),\n });\n },\n close: () => undefined,\n }),\n };\n}\n/** Installs session packages and dispatches authenticated package API calls in-process. */\nexport async function serveSessionApis(options: PackageApiServerOptions): Promise<PackageApiServer> {\n if (options.environment === undefined)\n throw new Error('Session package API server requires an admitted environment.');\n if (options.directEvents === undefined) throw new Error('Session package API server requires direct events.');\n options = { ...options, environment: await prepareSessionEnvironment(options) };\n const packages = options.packages ?? [];\n // Without a level above it, a session that mounts nothing has nothing to route.\n const routesNothing = (): boolean => !options.preparePackages && options.parentScope === undefined;\n if (options.apis.length === 0 && packages.length === 0 && routesNothing()) {\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n\n const owningSessionService = options.sessionService;\n const communication = owningSessionService?.bindCommunication?.(options.sessionId);\n const ownedReadExecutionState = owningSessionService?.readExecutionState?.bind(owningSessionService);\n const ownedPrompt = owningSessionService?.prompt?.bind(owningSessionService);\n const ownedAbort = owningSessionService?.abort?.bind(owningSessionService);\n const ownedSteer = owningSessionService?.steer?.bind(owningSessionService);\n const ownedRelease = owningSessionService?.release?.bind(owningSessionService);\n const exposedSessionService: PoHubSessionService | undefined =\n owningSessionService === undefined\n ? undefined\n : {\n create: (request) => owningSessionService.create(request),\n close: (sessionId) => owningSessionService.close(sessionId),\n isLive: (sessionId) => owningSessionService.isLive(sessionId),\n ...(ownedReadExecutionState === undefined\n ? {}\n : {\n readExecutionState: (sessionId: string) =>\n ownedReadExecutionState(sessionId, { parentSessionId: options.sessionId }),\n }),\n // A session may drive only the children it started, never its parent or a sibling.\n ...(ownedPrompt === undefined\n ? {}\n : {\n prompt: (sessionId: string, text: string, promptOptions?: PoHubSessionPromptOptions) =>\n ownedPrompt(sessionId, text, {\n ...(promptOptions?.signal === undefined ? {} : { signal: promptOptions.signal }),\n parentSessionId: options.sessionId,\n }),\n }),\n ...(ownedAbort === undefined\n ? {}\n : {\n abort: (sessionId: string) => ownedAbort(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(ownedSteer === undefined\n ? {}\n : {\n steer: (sessionId: string, message: string) =>\n ownedSteer(sessionId, message, { parentSessionId: options.sessionId }),\n }),\n ...(ownedRelease === undefined\n ? {}\n : {\n release: (sessionId: string) => ownedRelease(sessionId, { parentSessionId: options.sessionId }),\n }),\n ...(owningSessionService.canCommunicate === undefined\n ? {}\n : {\n canCommunicate: (sourceSessionId: string, targetSessionId: string) =>\n owningSessionService.canCommunicate?.(sourceSessionId, targetSessionId) === true,\n }),\n };\n const context: PoApiContext = {\n scope: 'session',\n sessionId: options.sessionId,\n workspaceId: options.workspaceId,\n workspaceRoot: options.workspaceRoot,\n ...(options.sessionContext === undefined ? {} : { sessionContext: options.sessionContext }),\n homeDirectory: options.homeDirectory ?? options.platform.homeDirectory,\n sessionStorage: options.platform.sessions,\n cwd: options.cwd,\n environment: options.environment,\n directEvents: options.directEvents,\n ...(options.computerUse === undefined ? {} : { computerUse: options.computerUse }),\n ...(options.shareFile === undefined ? {} : { shareFile: options.shareFile }),\n ...(options.mediaArbitration === undefined ? {} : { mediaArbitration: options.mediaArbitration }),\n ...(options.executionBudget === undefined ? {} : { executionBudget: options.executionBudget }),\n ...(options.editPresence === undefined ? {} : { editPresence: options.editPresence }),\n ...(options.peerAgents === undefined ? {} : { peerAgents: options.peerAgents }),\n ...(options.requestApi === undefined ? {} : { requestApi: options.requestApi }),\n ...(options.publishActivity === undefined ? {} : { publishActivity: options.publishActivity }),\n ...(options.internalToken === undefined ? {} : { internalToken: options.internalToken }),\n ...(options.hubToken === undefined ? {} : { hubToken: options.hubToken }),\n ...(exposedSessionService === undefined ? {} : { sessionService: exposedSessionService }),\n ...(communication === undefined ? {} : { sessionCommunication: communication }),\n onNotice: options.onNotice,\n };\n const host = createPoServerHost({\n scope: 'session',\n context,\n mountChannel: options.mountChannel,\n ...(options.pluginRegistry === undefined ? {} : { pluginRegistry: options.pluginRegistry }),\n });\n // The session's own folder, its workspace and its temp folder; extensions open their own beside these.\n const fileAccess = createFileAccess();\n for (const directory of [options.cwd, options.workspaceRoot, options.environment[PO_SESSION_TEMP_DIR]])\n if (directory !== undefined && path.isAbsolute(directory)) fileAccess.register(directory);\n let scope: PoServerScope | undefined;\n try {\n // Registered first, so no package can claim the host's own base path.\n host.registerApi(sessionFilesApi(fileAccess, options.cwd));\n for (const api of options.apis) host.registerApi(api);\n // The session's own level of the server IoC tree; it closes with the hub level it opens below.\n scope = await PoServerScope.open('session', options.parentScope);\n await scope.serve({ host, platform: options.platform });\n await scope.root.plugin((root) => {\n root.provide(PO_FILE_ACCESS_SERVICE, fileAccess);\n });\n await options.preparePackages?.(scope.root);\n const installed = await scope.install(packages, {\n onNotice: options.onNotice,\n onPackageSettled: (report) => {\n if (!options.telemetry) return;\n observe(\n options.telemetry.recordEvent('po_server.package_install', {\n 'package.name': report.packageName,\n 'package.outcome': report.outcome,\n duration_ms: report.durationMs,\n scope: 'session',\n }),\n options.onNotice,\n );\n },\n });\n await options.activatePackages?.(installed);\n } catch (error) {\n await scope?.dispose();\n communication?.close();\n host.dispose();\n throw error;\n }\n if (host.mounted().length === 0 && routesNothing()) {\n await scope.dispose();\n communication?.close();\n host.dispose();\n return {\n request: async () => Response.json({ error: 'No package APIs are mounted.' }, { status: 404 }),\n close: () => Promise.resolve(),\n };\n }\n const sessionScope = scope;\n\n const dispatch = async (request: Request): Promise<Response> => {\n if (options.canDispatch?.() === false)\n return Response.json({ error: 'Session selection is not ready.' }, { status: 503 });\n const url = new URL(request.url);\n if (!url.pathname.startsWith(`${PO_API_ROUTE_PREFIX}/`))\n return Response.json({ error: 'Not found.' }, { status: 404 });\n const rest = url.pathname.slice(PO_API_ROUTE_PREFIX.length + 1);\n const slash = rest.indexOf('/');\n const basePath = slash === -1 ? rest : rest.slice(0, slash);\n // The session's own API, else the nearest level above it that serves one.\n const handler = sessionScope.apiHandler(basePath);\n if (handler === undefined)\n return Response.json({ error: `No API '${basePath}' in this session.` }, { status: 404 });\n url.pathname = slash === -1 ? '/' : rest.slice(slash);\n const startedAt = performance.now();\n const parent = validatedTraceContext(request.headers.get('traceparent'));\n let childContext: PoTraceContext | undefined;\n let response: Response;\n try {\n const invoke = async (context?: PoTraceContext): Promise<Response> => {\n if (options.canDispatch?.() === false || sessionScope.apiHandler(basePath) !== handler) {\n return Response.json({ error: 'Session selection changed before dispatch.' }, { status: 503 });\n }\n childContext = context;\n return handler.fetch(new Request(url, request));\n };\n response = options.telemetry\n ? await options.telemetry.runInSpan(\n 'po_server.package_api.request',\n { api: basePath, method: request.method },\n invoke,\n parent,\n )\n : await invoke();\n } catch (error) {\n if (request.signal.aborted) return new Response(null, { status: 499 });\n options.onNotice(`package API '${basePath}' failed on ${url.pathname} (${describeError(error)})`);\n response = Response.json({ error: `The '${basePath}' API failed.` }, { status: 500 });\n }\n return responseWithCompletion(response, () => {\n if (!options.telemetry) return;\n const durationMs = Math.round(performance.now() - startedAt);\n // Keep this span only where it says something the request span cannot: a failing status,\n // or a body that took real time to flush after the headers were sent.\n if (response.status < 400 && durationMs < COMPLETION_SPAN_MIN_DURATION_MS) return;\n observe(\n options.telemetry.runInSpan(\n 'po_server.package_api.complete',\n {\n api: basePath,\n method: request.method,\n status_code: response.status,\n duration_ms: durationMs,\n },\n async () => undefined,\n childContext ?? parent,\n ),\n options.onNotice,\n );\n });\n };\n let closePromise: Promise<void> | undefined;\n\n return {\n request: dispatch,\n close: () => {\n closePromise ??= (async () => {\n await scope.dispose();\n communication?.close();\n host.dispose();\n })();\n return closePromise;\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/platform.cjs
CHANGED
|
@@ -6,6 +6,7 @@ const require_docs = require("./src/services/durableSession/docs.cjs");
|
|
|
6
6
|
const require_index$3 = require("./src/services/durableSession/index.cjs");
|
|
7
7
|
const require_index$4 = require("./src/services/sessionFiles/index.cjs");
|
|
8
8
|
const require_platform = require("./src/schemas/platform.cjs");
|
|
9
|
+
const require_index$5 = require("./src/services/fileAccess/index.cjs");
|
|
9
10
|
let _earendil_works_pi_durable_env = require("@earendil-works/pi-durable/env");
|
|
10
11
|
let dist_interop_chordContext_mjs = require("../dist/interop/chordContext.mjs");
|
|
11
12
|
Object.defineProperty(exports, "BACKGROUND_CONTEXT", {
|
|
@@ -26,6 +27,7 @@ Object.defineProperty(exports, "FileError", {
|
|
|
26
27
|
return _earendil_works_pi_durable_env.FileError;
|
|
27
28
|
}
|
|
28
29
|
});
|
|
30
|
+
exports.PO_FILE_ACCESS_SERVICE = require_index$5.PO_FILE_ACCESS_SERVICE;
|
|
29
31
|
exports.PO_FS_SERVICE = require_platform.PO_FS_SERVICE;
|
|
30
32
|
exports.PO_SESSION_FILES_SERVICE = require_index$4.PO_SESSION_FILES_SERVICE;
|
|
31
33
|
exports.PO_SESSION_STORAGE_SERVICE = require_platform.PO_SESSION_STORAGE_SERVICE;
|
|
@@ -44,6 +46,7 @@ Object.defineProperty(exports, "getOrThrow", {
|
|
|
44
46
|
exports.initializeSessionIdentity = require_index$3.initializeSessionIdentity;
|
|
45
47
|
exports.nodeHost = require_index$1.nodeHost;
|
|
46
48
|
exports.pathExists = require_index.pathExists;
|
|
49
|
+
exports.readPoFileAccess = require_index$5.readPoFileAccess;
|
|
47
50
|
exports.readPoFs = require_platform.readPoFs;
|
|
48
51
|
exports.readSessionFileDirectories = require_index$4.readSessionFileDirectories;
|
|
49
52
|
exports.readTextIfExists = require_index.readTextIfExists;
|
package/dist/platform.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PO_FS_SERVICE, PO_SESSION_STORAGE_SERVICE, PO_SHELL_SERVICE, PO_SQLITE_SERVICE, PoPlatform, PoSessionStorage, PoSessionStorageRequest, PoSessionStorageService, PoSqliteService, PoStoredSession, readPoFs, requirePoFs, requirePoShell, requirePoSqlite } from "./src/schemas/platform.mjs";
|
|
2
2
|
import { PO_SESSION_FILES_SERVICE, PO_SESSION_TEMP_DIR, PoSessionFileDirectories, PoSessionFiles, SessionTempDirectoryOptions, readSessionFileDirectories, removeSessionFiles, sessionTempDirectory } from "./src/services/sessionFiles/index.mjs";
|
|
3
|
+
import { PO_FILE_ACCESS_SERVICE, PoFileAccess, readPoFileAccess } from "./src/services/fileAccess/index.mjs";
|
|
3
4
|
import { SerialRunner, SerialTask, createSerialRunner } from "./src/services/serialRunner/index.mjs";
|
|
4
5
|
import { initializeSessionIdentity } from "./src/services/durableSession/index.mjs";
|
|
5
6
|
import { SessionIdentityDoc, SessionMetadataDoc } from "./src/services/durableSession/docs.mjs";
|
|
@@ -7,4 +8,4 @@ import { nodeHost } from "./src/services/nodeHost/index.mjs";
|
|
|
7
8
|
import { pathExists, readTextIfExists, removePath, writeFileAtomic } from "./src/services/platformFiles/index.mjs";
|
|
8
9
|
import { ExecutionEnv, ExecutionError, FileError, FileSystem, Result, Shell, getOrThrow } from "@earendil-works/pi-durable/env";
|
|
9
10
|
import { BACKGROUND_CONTEXT, withAbortSignal } from "@earendil-works/chord/context";
|
|
10
|
-
export { BACKGROUND_CONTEXT, type ExecutionEnv, ExecutionError, FileError, type FileSystem, PO_FS_SERVICE, PO_SESSION_FILES_SERVICE, PO_SESSION_STORAGE_SERVICE, PO_SESSION_TEMP_DIR, PO_SHELL_SERVICE, PO_SQLITE_SERVICE, type PoPlatform, type PoSessionFileDirectories, type PoSessionFiles, type PoSessionStorage, type PoSessionStorageRequest, type PoSessionStorageService, type PoSqliteService, type PoStoredSession, type Result, type SerialRunner, type SerialTask, SessionIdentityDoc, SessionMetadataDoc, type SessionTempDirectoryOptions, type Shell, createSerialRunner, getOrThrow, initializeSessionIdentity, nodeHost, pathExists, readPoFs, readSessionFileDirectories, readTextIfExists, removePath, removeSessionFiles, requirePoFs, requirePoShell, requirePoSqlite, sessionTempDirectory, withAbortSignal, writeFileAtomic };
|
|
11
|
+
export { BACKGROUND_CONTEXT, type ExecutionEnv, ExecutionError, FileError, type FileSystem, PO_FILE_ACCESS_SERVICE, PO_FS_SERVICE, PO_SESSION_FILES_SERVICE, PO_SESSION_STORAGE_SERVICE, PO_SESSION_TEMP_DIR, PO_SHELL_SERVICE, PO_SQLITE_SERVICE, type PoFileAccess, type PoPlatform, type PoSessionFileDirectories, type PoSessionFiles, type PoSessionStorage, type PoSessionStorageRequest, type PoSessionStorageService, type PoSqliteService, type PoStoredSession, type Result, type SerialRunner, type SerialTask, SessionIdentityDoc, SessionMetadataDoc, type SessionTempDirectoryOptions, type Shell, createSerialRunner, getOrThrow, initializeSessionIdentity, nodeHost, pathExists, readPoFileAccess, readPoFs, readSessionFileDirectories, readTextIfExists, removePath, removeSessionFiles, requirePoFs, requirePoShell, requirePoSqlite, sessionTempDirectory, withAbortSignal, writeFileAtomic };
|
package/dist/platform.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { SessionIdentityDoc, SessionMetadataDoc } from "./src/services/durableSe
|
|
|
5
5
|
import { initializeSessionIdentity } from "./src/services/durableSession/index.mjs";
|
|
6
6
|
import { PO_SESSION_FILES_SERVICE, PO_SESSION_TEMP_DIR, readSessionFileDirectories, removeSessionFiles, sessionTempDirectory } from "./src/services/sessionFiles/index.mjs";
|
|
7
7
|
import { PO_FS_SERVICE, PO_SESSION_STORAGE_SERVICE, PO_SHELL_SERVICE, PO_SQLITE_SERVICE, readPoFs, requirePoFs, requirePoShell, requirePoSqlite } from "./src/schemas/platform.mjs";
|
|
8
|
+
import { PO_FILE_ACCESS_SERVICE, readPoFileAccess } from "./src/services/fileAccess/index.mjs";
|
|
8
9
|
import { ExecutionError, FileError, getOrThrow } from "@earendil-works/pi-durable/env";
|
|
9
10
|
import { BACKGROUND_CONTEXT, withAbortSignal } from "@earendil-works/chord/context";
|
|
10
|
-
export { BACKGROUND_CONTEXT, ExecutionError, FileError, PO_FS_SERVICE, PO_SESSION_FILES_SERVICE, PO_SESSION_STORAGE_SERVICE, PO_SESSION_TEMP_DIR, PO_SHELL_SERVICE, PO_SQLITE_SERVICE, SessionIdentityDoc, SessionMetadataDoc, createSerialRunner, getOrThrow, initializeSessionIdentity, nodeHost, pathExists, readPoFs, readSessionFileDirectories, readTextIfExists, removePath, removeSessionFiles, requirePoFs, requirePoShell, requirePoSqlite, sessionTempDirectory, withAbortSignal, writeFileAtomic };
|
|
11
|
+
export { BACKGROUND_CONTEXT, ExecutionError, FileError, PO_FILE_ACCESS_SERVICE, PO_FS_SERVICE, PO_SESSION_FILES_SERVICE, PO_SESSION_STORAGE_SERVICE, PO_SESSION_TEMP_DIR, PO_SHELL_SERVICE, PO_SQLITE_SERVICE, SessionIdentityDoc, SessionMetadataDoc, createSerialRunner, getOrThrow, initializeSessionIdentity, nodeHost, pathExists, readPoFileAccess, readPoFs, readSessionFileDirectories, readTextIfExists, removePath, removeSessionFiles, requirePoFs, requirePoShell, requirePoSqlite, sessionTempDirectory, withAbortSignal, writeFileAtomic };
|
|
@@ -19,8 +19,11 @@ const SESSION_FILE_CONTENT_TYPES = {
|
|
|
19
19
|
};
|
|
20
20
|
/** The fallback media type for a session file whose extension is not listed above. */
|
|
21
21
|
const SESSION_FILE_DEFAULT_CONTENT_TYPE = "application/octet-stream";
|
|
22
|
+
/** The session host's own API that reads files under the session's open folders. */
|
|
23
|
+
const SESSION_FILES_API = "session-files";
|
|
22
24
|
//#endregion
|
|
23
25
|
exports.MAX_SESSION_FILE_BYTES = MAX_SESSION_FILE_BYTES;
|
|
26
|
+
exports.SESSION_FILES_API = SESSION_FILES_API;
|
|
24
27
|
exports.SESSION_FILE_CONTENT_TYPES = SESSION_FILE_CONTENT_TYPES;
|
|
25
28
|
exports.SESSION_FILE_DEFAULT_CONTENT_TYPE = SESSION_FILE_DEFAULT_CONTENT_TYPE;
|
|
26
29
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionFiles.cjs","names":[],"sources":["../../../src/constants/sessionFiles.ts"],"sourcesContent":["/** Largest session file the host reads into a response or publishes at a share link. */\nexport const MAX_SESSION_FILE_BYTES = 25 * 1024 * 1024;\n\n/** Media types for session files a browser may render; anything else is served as bytes. */\nexport const SESSION_FILE_CONTENT_TYPES: Readonly<Record<string, string>> = {\n '.avif': 'image/avif',\n '.bmp': 'image/bmp',\n '.gif': 'image/gif',\n '.jpeg': 'image/jpeg',\n '.jpg': 'image/jpeg',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.m4v': 'video/mp4',\n '.mov': 'video/quicktime',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.pdf': 'application/pdf',\n};\n\n/** The fallback media type for a session file whose extension is not listed above. */\nexport const SESSION_FILE_DEFAULT_CONTENT_TYPE = 'application/octet-stream';\n"],"mappings":";;AACA,MAAa,yBAAyB;;AAGtC,MAAa,6BAA+D;CAC1E,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;AACV;;AAGA,MAAa,oCAAoC"}
|
|
1
|
+
{"version":3,"file":"sessionFiles.cjs","names":[],"sources":["../../../src/constants/sessionFiles.ts"],"sourcesContent":["/** Largest session file the host reads into a response or publishes at a share link. */\nexport const MAX_SESSION_FILE_BYTES = 25 * 1024 * 1024;\n\n/** Media types for session files a browser may render; anything else is served as bytes. */\nexport const SESSION_FILE_CONTENT_TYPES: Readonly<Record<string, string>> = {\n '.avif': 'image/avif',\n '.bmp': 'image/bmp',\n '.gif': 'image/gif',\n '.jpeg': 'image/jpeg',\n '.jpg': 'image/jpeg',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.m4v': 'video/mp4',\n '.mov': 'video/quicktime',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.pdf': 'application/pdf',\n};\n\n/** The fallback media type for a session file whose extension is not listed above. */\nexport const SESSION_FILE_DEFAULT_CONTENT_TYPE = 'application/octet-stream';\n\n/** The session host's own API that reads files under the session's open folders. */\nexport const SESSION_FILES_API = 'session-files';\n"],"mappings":";;AACA,MAAa,yBAAyB;;AAGtC,MAAa,6BAA+D;CAC1E,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;AACV;;AAGA,MAAa,oCAAoC;;AAGjD,MAAa,oBAAoB"}
|
|
@@ -19,7 +19,9 @@ const SESSION_FILE_CONTENT_TYPES = {
|
|
|
19
19
|
};
|
|
20
20
|
/** The fallback media type for a session file whose extension is not listed above. */
|
|
21
21
|
const SESSION_FILE_DEFAULT_CONTENT_TYPE = "application/octet-stream";
|
|
22
|
+
/** The session host's own API that reads files under the session's open folders. */
|
|
23
|
+
const SESSION_FILES_API = "session-files";
|
|
22
24
|
//#endregion
|
|
23
|
-
export { MAX_SESSION_FILE_BYTES, SESSION_FILE_CONTENT_TYPES, SESSION_FILE_DEFAULT_CONTENT_TYPE };
|
|
25
|
+
export { MAX_SESSION_FILE_BYTES, SESSION_FILES_API, SESSION_FILE_CONTENT_TYPES, SESSION_FILE_DEFAULT_CONTENT_TYPE };
|
|
24
26
|
|
|
25
27
|
//# sourceMappingURL=sessionFiles.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionFiles.mjs","names":[],"sources":["../../../src/constants/sessionFiles.ts"],"sourcesContent":["/** Largest session file the host reads into a response or publishes at a share link. */\nexport const MAX_SESSION_FILE_BYTES = 25 * 1024 * 1024;\n\n/** Media types for session files a browser may render; anything else is served as bytes. */\nexport const SESSION_FILE_CONTENT_TYPES: Readonly<Record<string, string>> = {\n '.avif': 'image/avif',\n '.bmp': 'image/bmp',\n '.gif': 'image/gif',\n '.jpeg': 'image/jpeg',\n '.jpg': 'image/jpeg',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.m4v': 'video/mp4',\n '.mov': 'video/quicktime',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.pdf': 'application/pdf',\n};\n\n/** The fallback media type for a session file whose extension is not listed above. */\nexport const SESSION_FILE_DEFAULT_CONTENT_TYPE = 'application/octet-stream';\n"],"mappings":";;AACA,MAAa,yBAAyB;;AAGtC,MAAa,6BAA+D;CAC1E,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;AACV;;AAGA,MAAa,oCAAoC"}
|
|
1
|
+
{"version":3,"file":"sessionFiles.mjs","names":[],"sources":["../../../src/constants/sessionFiles.ts"],"sourcesContent":["/** Largest session file the host reads into a response or publishes at a share link. */\nexport const MAX_SESSION_FILE_BYTES = 25 * 1024 * 1024;\n\n/** Media types for session files a browser may render; anything else is served as bytes. */\nexport const SESSION_FILE_CONTENT_TYPES: Readonly<Record<string, string>> = {\n '.avif': 'image/avif',\n '.bmp': 'image/bmp',\n '.gif': 'image/gif',\n '.jpeg': 'image/jpeg',\n '.jpg': 'image/jpeg',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.m4v': 'video/mp4',\n '.mov': 'video/quicktime',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.pdf': 'application/pdf',\n};\n\n/** The fallback media type for a session file whose extension is not listed above. */\nexport const SESSION_FILE_DEFAULT_CONTENT_TYPE = 'application/octet-stream';\n\n/** The session host's own API that reads files under the session's open folders. */\nexport const SESSION_FILES_API = 'session-files';\n"],"mappings":";;AACA,MAAa,yBAAyB;;AAGtC,MAAa,6BAA+D;CAC1E,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;AACV;;AAGA,MAAa,oCAAoC;;AAGjD,MAAa,oBAAoB"}
|
|
@@ -88,6 +88,14 @@ const NativeCompositionSchema = typebox.Type.Object({
|
|
|
88
88
|
channels: Strings,
|
|
89
89
|
plugins: Strings
|
|
90
90
|
});
|
|
91
|
+
/** One platform's signed over-the-air app bundle; `fingerprint` names the binaries it runs on. */
|
|
92
|
+
const NativeAppSchema = typebox.Type.Object({
|
|
93
|
+
id: Text,
|
|
94
|
+
revision: NumberValue,
|
|
95
|
+
manifestUrl: Text,
|
|
96
|
+
rawAssetBaseUrl: Text,
|
|
97
|
+
fingerprint: Text
|
|
98
|
+
});
|
|
91
99
|
/** A configured template id and the mount whose compositions offer it. */
|
|
92
100
|
const TemplateDecisionSchema = typebox.Type.Object({
|
|
93
101
|
id: Optional(Text),
|
|
@@ -202,6 +210,8 @@ host("health", "/api/health", "GET", typebox.Type.Object({
|
|
|
202
210
|
})) }), host("compositions", "/api/compositions", "GET", typebox.Type.Object({
|
|
203
211
|
global: Optional(WebCompositionSchema),
|
|
204
212
|
nativeGlobal: Optional(NativeCompositionSchema),
|
|
213
|
+
/** App bundles by platform, which a phone loads only when its own fingerprint matches. */
|
|
214
|
+
nativeApp: Optional(typebox.Type.Record(Text, NativeAppSchema)),
|
|
205
215
|
publicKey: Optional(Text),
|
|
206
216
|
shell: Optional(typebox.Type.Object({
|
|
207
217
|
publicKey: Text,
|