@parlor/server 0.3.3 → 0.4.0
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/access.d.ts +3 -3
- package/dist/access.d.ts.map +1 -1
- package/dist/access.js +4 -4
- package/dist/access.js.map +1 -1
- package/dist/actions.d.ts +6 -1
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +21 -8
- package/dist/actions.js.map +1 -1
- package/dist/auth.d.ts +20 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +3 -1
- package/dist/auth.js.map +1 -1
- package/dist/caller.d.ts +3 -1
- package/dist/caller.d.ts.map +1 -1
- package/dist/caller.js +12 -5
- package/dist/caller.js.map +1 -1
- package/dist/create-server.d.ts +16 -1
- package/dist/create-server.d.ts.map +1 -1
- package/dist/create-server.js +28 -10
- package/dist/create-server.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +8 -3
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +38 -18
- package/dist/mcp.js.map +1 -1
- package/dist/plugin.d.ts +7 -3
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js.map +1 -1
- package/dist/scope.d.ts +4 -1
- package/dist/scope.d.ts.map +1 -1
- package/dist/scope.js +1 -1
- package/dist/scope.js.map +1 -1
- package/dist/visibility.d.ts +16 -0
- package/dist/visibility.d.ts.map +1 -0
- package/dist/visibility.js +32 -0
- package/dist/visibility.js.map +1 -0
- package/package.json +5 -5
package/dist/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CLIENT_INFO_META_KEY,\n type CallToolResult,\n createMcpHandler as createSdkHandler,\n type McpHttpHandler,\n type McpRequestContext,\n McpServer,\n type ServerContext,\n type StandardSchemaWithJSON,\n} from \"@modelcontextprotocol/server\";\nimport type { AgentOrigin, UiError } from \"@parlor/agent-ui\";\nimport { type AgentUi, UI_MANIFEST_RESOURCE, UiFailure } from \"@parlor/agent-ui/server\";\nimport {\n ActionError,\n type ActionErrorCode,\n type ActionMap,\n type AnyAction,\n isMutating,\n} from \"@parlor/core\";\nimport type { ActionRegistry } from \"@parlor/core/registry\";\n\nimport type { ActionRunner } from \"./actions.js\";\nimport type { CallerResolver } from \"./caller.js\";\nimport { McpCalls } from \"./mcp-calls.js\";\n\nexport interface McpOptions<T extends ActionMap> {\n readonly actions: ActionRegistry<T>;\n readonly runner: ActionRunner;\n readonly name?: string | undefined;\n readonly version?: string | undefined;\n /**\n * Which app these tools belong to, told to every MCP client, so an agent connected to\n * several Parlor apps keeps them apart.\n */\n readonly app?:\n | { readonly name: string; readonly description?: string | undefined }\n | undefined;\n readonly agentUi?: AgentUi | undefined;\n readonly callers?: CallerResolver | undefined;\n}\n\n/** The public origin first, then the one `parlor dev` serves the app on, then the request's. */\nfunction appOrigin(request: Request | undefined): string | undefined {\n const configured = process.env.PARLOR_ORIGIN || process.env.PARLOR_WEB_ORIGIN;\n if (configured) return new URL(configured).origin;\n return request ? new URL(request.url).origin : undefined;\n}\n\nexport function appIdentity(\n app: McpOptions<ActionMap>[\"app\"],\n origin: string | undefined,\n): string {\n const where = origin ? ` at ${origin}` : \"\";\n const what = app?.description ? ` ${app.description.trim()}` : \"\";\n const who = app ? app.name : \"this app\";\n return `These tools belong to ${who}${where}.${what} They act only on ${who}, as the signed-in user; any other app's tools are a separate server.`;\n}\n\nfunction toolResult(result: unknown): CallToolResult {\n const text = result === undefined ? \"ok\" : JSON.stringify(result, null, 2);\n return {\n content: [{ type: \"text\", text }],\n ...(result !== null && typeof result === \"object\" && !Array.isArray(result)\n ? { structuredContent: result as Record<string, unknown> }\n : {}),\n };\n}\n\ninterface ToolErrorBody {\n readonly code: UiError[\"code\"] | ActionErrorCode;\n readonly message: string;\n readonly issues?:\n | readonly { readonly path: string; readonly message: string }[]\n | undefined;\n}\n\nfunction errorBodyOf(error: unknown): ToolErrorBody {\n if (error instanceof UiFailure) return error.error;\n if (error instanceof ActionError) {\n return {\n code: error.code,\n message: error.message,\n ...(error.issues\n ? {\n issues: error.issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n })),\n }\n : {}),\n };\n }\n return { code: \"internal\", message: \"Internal error\" };\n}\n\nfunction toolError(error: unknown): CallToolResult {\n return {\n isError: true,\n content: [\n { type: \"text\", text: JSON.stringify({ error: errorBodyOf(error) }, null, 2) },\n ],\n };\n}\n\n/**\n * The SDK answers bad arguments in plain text before the handler runs. A schema that lists\n * as the original but accepts anything leaves the check to the handler, which fails in the\n * one error body.\n */\nfunction unvalidated(schema: StandardSchemaWithJSON): StandardSchemaWithJSON {\n return { \"~standard\": { ...schema[\"~standard\"], validate: (value) => ({ value }) } };\n}\n\nfunction actionDescription(action: AnyAction): string {\n return action.confirm\n ? `${action.description} When an agent calls it, the user must approve it in the app first; the call waits for that answer and fails with declined, confirmation_timeout or confirmation_unavailable without running.`\n : action.description;\n}\n\nexport const PROGRESS_INTERVAL_MS = 10_000;\n\nasync function verifiedOrigin(\n callers: CallerResolver | undefined,\n request: Request | undefined,\n ctx: ServerContext,\n): Promise<AgentOrigin> {\n const caller = callers && request ? await callers(request) : undefined;\n const principal = caller?.principal;\n if (principal?.kind === \"agent\" && principal.turn) {\n return { via: \"agent\", name: principal.agent.name };\n }\n if (principal?.kind === \"agent\" && principal.agent.verified) {\n return { via: \"mcp\", name: principal.agent.name };\n }\n return originOf(ctx);\n}\n\nasync function turnClientOf(\n callers: CallerResolver | undefined,\n request: Request | undefined,\n): Promise<{ readonly clientId: string } | undefined> {\n const principal = callers && request ? (await callers(request)).principal : undefined;\n return principal?.kind === \"agent\" && principal.turn\n ? { clientId: principal.turn.clientId }\n : undefined;\n}\n\nexport function originOf(ctx: ServerContext): AgentOrigin {\n const envelope: Readonly<Record<string, unknown>> | undefined = ctx.mcpReq.envelope;\n const info = envelope?.[CLIENT_INFO_META_KEY];\n const name =\n typeof info === \"object\" && info !== null\n ? (info as { name?: unknown }).name\n : undefined;\n return typeof name === \"string\" && name !== \"\" ? { via: \"mcp\", name } : { via: \"mcp\" };\n}\n\nexport async function withProgress<T>(\n ctx: ServerContext,\n work: () => Promise<T>,\n intervalMs: number = PROGRESS_INTERVAL_MS,\n): Promise<T> {\n const progressToken = ctx.mcpReq._meta?.progressToken;\n if (progressToken === undefined) return work();\n let progress = 0;\n const timer = setInterval(() => {\n ctx.mcpReq\n .notify({\n method: \"notifications/progress\",\n params: {\n progressToken,\n progress: ++progress,\n message: \"Waiting for the user to approve in the app\",\n },\n })\n .catch(() => {});\n }, intervalMs);\n try {\n return await work();\n } finally {\n clearInterval(timer);\n }\n}\n\nexport function createMcpHandler<T extends ActionMap>(\n options: McpOptions<T>,\n): McpHttpHandler {\n const {\n actions,\n runner,\n agentUi,\n callers,\n app,\n name = app?.name ?? \"parlor\",\n version = \"0.0.0\",\n } = options;\n\n const calls = new McpCalls();\n\n const inCall = <R>(\n ctx: McpRequestContext,\n toolCtx: ServerContext,\n work: (signal: AbortSignal) => Promise<R>,\n ): Promise<R> =>\n calls.run(\n ctx.requestInfo,\n toolCtx.mcpReq.id,\n [...(ctx.requestInfo ? [ctx.requestInfo.signal] : []), toolCtx.mcpReq.signal],\n work,\n );\n\n const factory = (ctx: McpRequestContext) => {\n const instructions = [\n appIdentity(app, appOrigin(ctx.requestInfo)),\n agentUi?.instructions(\"mcp\"),\n ]\n .filter(Boolean)\n .join(\"\\n\\n\");\n const server = new McpServer(\n { name, version, ...(app ? { title: app.name } : {}) },\n { instructions },\n );\n server.server.setNotificationHandler(\"notifications/cancelled\", (notification) => {\n const { requestId, reason } = notification.params;\n if (ctx.requestInfo && requestId !== undefined)\n calls.cancel(ctx.requestInfo, requestId, reason);\n });\n for (const actionName of actions.names()) {\n const action = actions.get(actionName);\n if (!action) continue;\n server.registerTool(\n actionName,\n {\n description: actionDescription(action),\n inputSchema: unvalidated(action.input),\n annotations: { readOnlyHint: !isMutating(action) },\n },\n async (args, toolCtx) => {\n try {\n const origin = await verifiedOrigin(callers, ctx.requestInfo, toolCtx);\n const result = await inCall(ctx, toolCtx, (signal) => {\n const run = () =>\n runner.run(actionName, args, ctx.requestInfo, \"mcp\", { signal, origin });\n return action.confirm ? withProgress(toolCtx, run) : run();\n });\n return toolResult(result.data);\n } catch (error) {\n return toolError(error);\n }\n },\n );\n }\n const uiTools = agentUi?.tools(\"mcp\") ?? [];\n const uiManifest = uiTools.length > 0 ? agentUi?.manifest() : undefined;\n if (uiManifest) {\n server.registerResource(\n \"ui-manifest\",\n UI_MANIFEST_RESOURCE,\n {\n description:\n \"The app's pages and the views they show, with full JSON schemas for each view's value.\",\n mimeType: \"application/json\",\n },\n (uri) => ({\n contents: [\n {\n uri: uri.href,\n mimeType: \"application/json\",\n text: JSON.stringify(uiManifest, null, 2),\n },\n ],\n }),\n );\n }\n for (const tool of uiTools) {\n server.registerTool(\n tool.name,\n {\n description: tool.description,\n inputSchema: unvalidated(tool.input),\n annotations: { readOnlyHint: tool.readOnly },\n },\n async (args, toolCtx) => {\n try {\n const input = tool.input.safeParse(args);\n if (!input.success) {\n throw new ActionError(\"invalid_input\", `Invalid input for \"${tool.name}\"`, {\n issues: input.error.issues,\n });\n }\n return toolResult(\n await inCall(ctx, toolCtx, async (signal) =>\n tool.run(\n input.data,\n await agentUi!.contextFor(\n ctx.requestInfo,\n await verifiedOrigin(callers, ctx.requestInfo, toolCtx),\n signal,\n await turnClientOf(callers, ctx.requestInfo),\n ),\n ),\n ),\n );\n } catch (error) {\n if (!(error instanceof UiFailure))\n console.error(\"[parlor] UI tool failed:\", error);\n return toolError(error);\n }\n },\n );\n }\n return server;\n };\n\n return createSdkHandler(factory);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CLIENT_INFO_META_KEY,\n type CallToolResult,\n createMcpHandler as createSdkHandler,\n type McpHttpHandler,\n type McpRequestContext,\n McpServer,\n type ServerContext,\n type StandardSchemaWithJSON,\n} from \"@modelcontextprotocol/server\";\nimport type { AgentOrigin, UiError } from \"@parlor/agent-ui\";\nimport { type AgentUi, UI_MANIFEST_RESOURCE, UiFailure } from \"@parlor/agent-ui/server\";\nimport {\n ActionError,\n type ActionErrorCode,\n type ActionMap,\n ANONYMOUS,\n type AnyAction,\n type ConfirmationDecision,\n type ConfirmationPolicy,\n defaultConfirmationPolicy,\n isMutating,\n type Principal,\n} from \"@parlor/core\";\nimport type { ActionRegistry } from \"@parlor/core/registry\";\n\nimport type { ActionRunner } from \"./actions.js\";\nimport { type CallerResolver, sourceFor } from \"./caller.js\";\nimport { McpCalls } from \"./mcp-calls.js\";\nimport type { RegistryResolver } from \"./visibility.js\";\n\nexport interface McpOptions<T extends ActionMap> {\n readonly actions: ActionRegistry<T>;\n readonly runner: ActionRunner;\n readonly name?: string | undefined;\n readonly version?: string | undefined;\n /**\n * Which app these tools belong to, told to every MCP client, so an agent connected to\n * several Parlor apps keeps them apart.\n */\n readonly app?:\n | { readonly name: string; readonly description?: string | undefined }\n | undefined;\n readonly agentUi?: AgentUi | undefined;\n readonly callers?: CallerResolver | undefined;\n /** The server's confirmation policy, so each tool says what a call from this caller meets. */\n readonly confirmation?: ConfirmationPolicy | undefined;\n /** The actions a request may see; defaults to all of `actions`. */\n readonly registryFor?: RegistryResolver | undefined;\n}\n\n/** The public origin first, then the one `parlor dev` serves the app on, then the request's. */\nfunction appOrigin(request: Request | undefined): string | undefined {\n const configured = process.env.PARLOR_ORIGIN || process.env.PARLOR_WEB_ORIGIN;\n if (configured) return new URL(configured).origin;\n return request ? new URL(request.url).origin : undefined;\n}\n\nexport function appIdentity(\n app: McpOptions<ActionMap>[\"app\"],\n origin: string | undefined,\n principal: Principal = ANONYMOUS,\n): string {\n const where = origin ? ` at ${origin}` : \"\";\n const what = app?.description ? ` ${app.description.trim()}` : \"\";\n const who = app ? app.name : \"this app\";\n const actor = principal.kind === \"key\" ? principal.name : \"the signed-in user\";\n return `These tools belong to ${who}${where}.${what} They act only on ${who}, as ${actor}; any other app's tools are a separate server.`;\n}\n\nfunction toolResult(result: unknown): CallToolResult {\n const text = result === undefined ? \"ok\" : JSON.stringify(result, null, 2);\n return {\n content: [{ type: \"text\", text }],\n ...(result !== null && typeof result === \"object\" && !Array.isArray(result)\n ? { structuredContent: result as Record<string, unknown> }\n : {}),\n };\n}\n\ninterface ToolErrorBody {\n readonly code: UiError[\"code\"] | ActionErrorCode;\n readonly message: string;\n readonly issues?:\n | readonly { readonly path: string; readonly message: string }[]\n | undefined;\n}\n\nfunction errorBodyOf(error: unknown): ToolErrorBody {\n if (error instanceof UiFailure) return error.error;\n if (error instanceof ActionError) {\n return {\n code: error.code,\n message: error.message,\n ...(error.issues\n ? {\n issues: error.issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n })),\n }\n : {}),\n };\n }\n return { code: \"internal\", message: \"Internal error\" };\n}\n\nfunction toolError(error: unknown): CallToolResult {\n return {\n isError: true,\n content: [\n { type: \"text\", text: JSON.stringify({ error: errorBodyOf(error) }, null, 2) },\n ],\n };\n}\n\n/**\n * The SDK answers bad arguments in plain text before the handler runs. A schema that lists\n * as the original but accepts anything leaves the check to the handler, which fails in the\n * one error body.\n */\nfunction unvalidated(schema: StandardSchemaWithJSON): StandardSchemaWithJSON {\n return { \"~standard\": { ...schema[\"~standard\"], validate: (value) => ({ value }) } };\n}\n\nfunction actionDescription(action: AnyAction, decision: ConfirmationDecision): string {\n switch (decision) {\n case \"ask\":\n return `${action.description} When an agent calls it, the user must approve it in the app first; the call waits for that answer and fails with declined, confirmation_timeout or confirmation_unavailable without running.`;\n case \"refuse\":\n return `${action.description} It needs a person's approval, which nobody can give for this caller, so a call fails with confirmation_unavailable without running.`;\n case \"proceed\":\n return action.description;\n }\n}\n\nexport const PROGRESS_INTERVAL_MS = 10_000;\n\nasync function verifiedOrigin(\n callers: CallerResolver | undefined,\n request: Request | undefined,\n ctx: ServerContext,\n): Promise<AgentOrigin> {\n const caller = callers && request ? await callers(request) : undefined;\n const principal = caller?.principal;\n if (principal?.kind === \"agent\" && principal.turn) {\n return { via: \"agent\", name: principal.agent.name };\n }\n if (principal?.kind === \"agent\" && principal.agent.verified) {\n return { via: \"mcp\", name: principal.agent.name };\n }\n if (principal?.kind === \"key\") return { via: \"mcp\", name: principal.name };\n return originOf(ctx);\n}\n\nasync function turnClientOf(\n callers: CallerResolver | undefined,\n request: Request | undefined,\n): Promise<{ readonly clientId: string } | undefined> {\n const principal = callers && request ? (await callers(request)).principal : undefined;\n return principal?.kind === \"agent\" && principal.turn\n ? { clientId: principal.turn.clientId }\n : undefined;\n}\n\nexport function originOf(ctx: ServerContext): AgentOrigin {\n const envelope: Readonly<Record<string, unknown>> | undefined = ctx.mcpReq.envelope;\n const info = envelope?.[CLIENT_INFO_META_KEY];\n const name =\n typeof info === \"object\" && info !== null\n ? (info as { name?: unknown }).name\n : undefined;\n return typeof name === \"string\" && name !== \"\" ? { via: \"mcp\", name } : { via: \"mcp\" };\n}\n\nexport async function withProgress<T>(\n ctx: ServerContext,\n work: () => Promise<T>,\n intervalMs: number = PROGRESS_INTERVAL_MS,\n): Promise<T> {\n const progressToken = ctx.mcpReq._meta?.progressToken;\n if (progressToken === undefined) return work();\n let progress = 0;\n const timer = setInterval(() => {\n ctx.mcpReq\n .notify({\n method: \"notifications/progress\",\n params: {\n progressToken,\n progress: ++progress,\n message: \"Waiting for the user to approve in the app\",\n },\n })\n .catch(() => {});\n }, intervalMs);\n try {\n return await work();\n } finally {\n clearInterval(timer);\n }\n}\n\nexport function createMcpHandler<T extends ActionMap>(\n options: McpOptions<T>,\n): McpHttpHandler {\n const {\n runner,\n agentUi,\n callers,\n confirmation = defaultConfirmationPolicy,\n registryFor = () => Promise.resolve(options.actions),\n app,\n name = app?.name ?? \"parlor\",\n version = \"0.0.0\",\n } = options;\n\n const calls = new McpCalls();\n\n const inCall = <R>(\n ctx: McpRequestContext,\n toolCtx: ServerContext,\n work: (signal: AbortSignal) => Promise<R>,\n ): Promise<R> =>\n calls.run(\n ctx.requestInfo,\n toolCtx.mcpReq.id,\n [...(ctx.requestInfo ? [ctx.requestInfo.signal] : []), toolCtx.mcpReq.signal],\n work,\n );\n\n const factory = async (ctx: McpRequestContext) => {\n const caller =\n callers && ctx.requestInfo ? await callers(ctx.requestInfo) : undefined;\n const principal = caller?.principal ?? ANONYMOUS;\n const source = caller\n ? sourceFor(\"mcp\", caller, callers?.enforcing === true, \"mcp\")\n : \"mcp\";\n const screen = principal.kind === \"key\" ? undefined : agentUi;\n const registry = await registryFor(ctx.requestInfo);\n const instructions = [\n appIdentity(app, appOrigin(ctx.requestInfo), principal),\n screen?.instructions(\"mcp\"),\n ]\n .filter(Boolean)\n .join(\"\\n\\n\");\n const server = new McpServer(\n { name, version, ...(app ? { title: app.name } : {}) },\n { instructions },\n );\n server.server.setNotificationHandler(\"notifications/cancelled\", (notification) => {\n const { requestId, reason } = notification.params;\n if (ctx.requestInfo && requestId !== undefined)\n calls.cancel(ctx.requestInfo, requestId, reason);\n });\n for (const actionName of registry.names()) {\n const action = registry.get(actionName);\n if (!action) continue;\n server.registerTool(\n actionName,\n {\n description: actionDescription(\n action,\n confirmation({ name: actionName, action, principal, source }),\n ),\n inputSchema: unvalidated(action.input),\n annotations: { readOnlyHint: !isMutating(action) },\n },\n async (args, toolCtx) => {\n try {\n const origin = await verifiedOrigin(callers, ctx.requestInfo, toolCtx);\n const result = await inCall(ctx, toolCtx, (signal) => {\n const run = () =>\n runner.run(actionName, args, ctx.requestInfo, \"mcp\", {\n signal,\n origin,\n surface: \"mcp\",\n });\n return action.confirm ? withProgress(toolCtx, run) : run();\n });\n return toolResult(result.data);\n } catch (error) {\n return toolError(error);\n }\n },\n );\n }\n const uiTools = screen?.tools(\"mcp\") ?? [];\n const uiManifest = uiTools.length > 0 ? screen?.manifest() : undefined;\n if (uiManifest) {\n server.registerResource(\n \"ui-manifest\",\n UI_MANIFEST_RESOURCE,\n {\n description:\n \"The app's pages and the views they show, with full JSON schemas for each view's value.\",\n mimeType: \"application/json\",\n },\n (uri) => ({\n contents: [\n {\n uri: uri.href,\n mimeType: \"application/json\",\n text: JSON.stringify(uiManifest, null, 2),\n },\n ],\n }),\n );\n }\n for (const tool of uiTools) {\n server.registerTool(\n tool.name,\n {\n description: tool.description,\n inputSchema: unvalidated(tool.input),\n annotations: { readOnlyHint: tool.readOnly },\n },\n async (args, toolCtx) => {\n try {\n const input = tool.input.safeParse(args);\n if (!input.success) {\n throw new ActionError(\"invalid_input\", `Invalid input for \"${tool.name}\"`, {\n issues: input.error.issues,\n });\n }\n return toolResult(\n await inCall(ctx, toolCtx, async (signal) =>\n tool.run(\n input.data,\n await screen!.contextFor(\n ctx.requestInfo,\n await verifiedOrigin(callers, ctx.requestInfo, toolCtx),\n signal,\n await turnClientOf(callers, ctx.requestInfo),\n ),\n ),\n ),\n );\n } catch (error) {\n if (!(error instanceof UiFailure))\n console.error(\"[parlor] UI tool failed:\", error);\n return toolError(error);\n }\n },\n );\n }\n return server;\n };\n\n return createSdkHandler(factory);\n}\n"]}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ActionErrorCode, ActionSource,
|
|
1
|
+
import type { ActionErrorCode, ActionSource, DataProvider, Principal, PrincipalKind, Tag } from "@parlor/core";
|
|
2
2
|
import type { ActionRegistry } from "@parlor/core/registry";
|
|
3
3
|
import type { ServerChannel } from "@parlor/sync";
|
|
4
4
|
import type { CallerOf } from "./access.js";
|
|
@@ -57,8 +57,12 @@ export interface ActionAudit {
|
|
|
57
57
|
readonly outcome: "ok" | "cancelled" | ActionErrorCode;
|
|
58
58
|
readonly confirmation?: ConfirmationAnswer | undefined;
|
|
59
59
|
}
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
/**
|
|
61
|
+
* How a call's confirmation went. `waived` means the server's confirmation policy ran a call
|
|
62
|
+
* that the default would have asked the user about.
|
|
63
|
+
*/
|
|
64
|
+
export type ConfirmationAnswer = "approved" | "declined" | "timeout" | "unavailable" | "waived";
|
|
65
|
+
type SignedInKind = Exclude<PrincipalKind, "anonymous">;
|
|
62
66
|
/**
|
|
63
67
|
* A plain route with no transaction or sync event. `access` decides who may call it and
|
|
64
68
|
* types the caller its handler receives. An anonymous caller is admitted only when `access`
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAoHA,+EAA+E;AAC/E,MAAM,UAAU,WAAW,CACzB,KAAqB;IAErB,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import type {\n ActionErrorCode,\n ActionSource,\n DataProvider,\n Principal,\n PrincipalKind,\n Tag,\n} from \"@parlor/core\";\nimport type { ActionRegistry } from \"@parlor/core/registry\";\nimport type { ServerChannel } from \"@parlor/sync\";\n\nimport type { CallerOf } from \"./access.js\";\nimport type { AuthProvider } from \"./auth.js\";\nimport type { Caller } from \"./caller.js\";\n\n/**\n * A framework feature the app installs with `createServer({ plugins })`. It owns the\n * tables prefixed `parlor_<name>_`, every path under `/_parlor/<name>/`, and the paths its\n * absolute routes declare.\n */\nexport interface ServerPlugin {\n readonly name: string;\n readonly migrations?: readonly Migration[] | undefined;\n setup(host: PluginHost): PluginRuntime;\n}\n\n/** Applied once per database in list order. An applied id must never change. */\nexport interface Migration {\n readonly id: `${string}/${number}_${string}`;\n readonly sql: string;\n}\n\nexport interface PluginRuntime {\n /**\n * Served at `POST /_parlor/<plugin>/actions/<action>` through the same runner as the app's\n * actions, but never listed on MCP and never callable by an agent.\n */\n readonly actions?: ActionRegistry | undefined;\n readonly channel?: ServerChannel | undefined;\n readonly routes?: readonly AnyPluginRoute[] | undefined;\n /** Called once per action call on every surface after it settles, whatever the outcome. */\n audit?(record: ActionAudit): void;\n /**\n * Starts the plugin's background work, such as timers. Called once, when the server is\n * ready for its first request: some runtimes allow no timers while the app loads.\n */\n start?(): void;\n /**\n * Who may use the plugin. Everyone else gets `forbidden` from its actions and signed-in\n * routes and never joins its channel. Absent admits whoever those surfaces admit.\n */\n allows?(caller: PluginCaller): boolean | Promise<boolean>;\n /** Runs before `close()` awaits in-flight requests, so it must end what it holds open. */\n close?(): void | Promise<void>;\n}\n\n/** Who is asking: enough to look the user up, with no request to read. */\nexport type PluginCaller = Pick<Caller, \"principal\" | \"scope\">;\n\nexport interface ActionAudit {\n readonly at: number;\n readonly action: string;\n readonly principal: Principal;\n readonly source: ActionSource;\n readonly scope: string;\n /** SHA-256 of the input as received; the input itself is not kept. */\n readonly inputDigest: string;\n /** `ran` once `run` started; `refused` when the call stopped before it. */\n readonly stage: \"refused\" | \"ran\";\n readonly outcome: \"ok\" | \"cancelled\" | ActionErrorCode;\n readonly confirmation?: ConfirmationAnswer | undefined;\n}\n\n/**\n * How a call's confirmation went. `waived` means the server's confirmation policy ran a call\n * that the default would have asked the user about.\n */\nexport type ConfirmationAnswer =\n | \"approved\"\n | \"declined\"\n | \"timeout\"\n | \"unavailable\"\n | \"waived\";\n\ntype SignedInKind = Exclude<PrincipalKind, \"anonymous\">;\n\n/**\n * A plain route with no transaction or sync event. `access` decides who may call it and\n * types the caller its handler receives. An anonymous caller is admitted only when `access`\n * lists it and no enforcing auth provider is installed.\n */\nexport interface PluginRoute<K extends SignedInKind | \"anonymous\"> {\n readonly method: \"GET\" | \"POST\";\n readonly path: `/${string}`;\n /**\n * Serves `path` as is from the origin root instead of under `/_parlor/<plugin>/`, for URLs\n * fixed outside the app, such as a payment provider's webhook. The path must be static.\n */\n readonly absolute?: boolean | undefined;\n readonly access: readonly K[];\n handle(request: Request, caller: CallerOf<K>): Promise<Response>;\n}\n\n/** Callable by anyone, signed in or not: sign-in pages, OAuth endpoints. */\nexport interface PublicPluginRoute {\n readonly method: \"GET\" | \"POST\";\n /** Absolute when it starts with `/.well-known/`. */\n readonly path: `/${string}`;\n /** See `PluginRoute.absolute`. */\n readonly absolute?: boolean | undefined;\n readonly access: \"public\";\n handle(request: Request): Promise<Response>;\n}\n\nexport type AnyPluginRoute = PluginRoute<SignedInKind | \"anonymous\"> | PublicPluginRoute;\n\n/** Infers `K` from `access`, so the handler's caller type follows the list. */\nexport function pluginRoute<const K extends SignedInKind | \"anonymous\">(\n route: PluginRoute<K>,\n): PluginRoute<K> {\n return route;\n}\n\nexport interface PluginHost {\n readonly basePath: string;\n readonly database: DataProvider | undefined;\n /** The installed auth provider, for plugins that mint or look up credentials (chat). */\n readonly auth?: AuthProvider | undefined;\n /** `createServer` got an `auth` key whose value is undefined: a sign-in setup that failed to configure. */\n readonly authMisconfigured?: boolean;\n callerOf(request: Request): Promise<Caller>;\n /**\n * Whether the installed plugin `name` admits `caller`, for a plugin that serves another\n * one (auth pairs computers for chat). True when it is not installed or has no policy.\n */\n allows?(plugin: string, caller: PluginCaller): Promise<boolean>;\n /**\n * Resolves once the database holds every plugin's tables. Work a plugin starts on its own,\n * such as a timer, waits for it; request handlers need not, as the server awaits it first.\n */\n ready?(): Promise<void>;\n /**\n * Records a sync event for writes made outside an action's transaction, such as through\n * a library that holds its own connection. With `tx`, the event commits with that\n * transaction instead of its own. Does nothing when sync is off.\n */\n announce(scope: string, tags: readonly Tag[], tx?: unknown): Promise<void>;\n}\n"]}
|
package/dist/scope.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { type Principal } from "@parlor/core";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* The tenant a request belongs to. Called once per request. For a key it must answer the
|
|
4
|
+
* key's own scope, or the request is refused.
|
|
5
|
+
*/
|
|
3
6
|
export type ScopeResolver = (request: Request, principal: Principal) => string | Promise<string>;
|
|
4
7
|
export declare const DEFAULT_SCOPE = "default";
|
|
5
8
|
export declare const defaultScope: ScopeResolver;
|
package/dist/scope.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAU,MAAM,cAAc,CAAC;AAEtD
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAU,MAAM,cAAc,CAAC;AAEtD;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,KACjB,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAE9B,eAAO,MAAM,aAAa,YAAY,CAAC;AAEvC,eAAO,MAAM,YAAY,EAAE,aACwD,CAAC"}
|
package/dist/scope.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { userOf } from "@parlor/core";
|
|
2
2
|
export const DEFAULT_SCOPE = "default";
|
|
3
|
-
export const defaultScope = (_request, principal) => userOf(principal) ?? DEFAULT_SCOPE;
|
|
3
|
+
export const defaultScope = (_request, principal) => principal.kind === "key" ? principal.scope : (userOf(principal) ?? DEFAULT_SCOPE);
|
|
4
4
|
//# sourceMappingURL=scope.js.map
|
package/dist/scope.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,MAAM,EAAE,MAAM,cAAc,CAAC;AAWtD,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAC;AAEvC,MAAM,CAAC,MAAM,YAAY,GAAkB,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,CACjE,SAAS,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,aAAa,CAAC,CAAC","sourcesContent":["import { type Principal, userOf } from \"@parlor/core\";\n\n/**\n * The tenant a request belongs to. Called once per request. For a key it must answer the\n * key's own scope, or the request is refused.\n */\nexport type ScopeResolver = (\n request: Request,\n principal: Principal,\n) => string | Promise<string>;\n\nexport const DEFAULT_SCOPE = \"default\";\n\nexport const defaultScope: ScopeResolver = (_request, principal) =>\n principal.kind === \"key\" ? principal.scope : (userOf(principal) ?? DEFAULT_SCOPE);\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AnyAction } from "@parlor/core";
|
|
2
|
+
import type { ActionRegistry } from "@parlor/core/registry";
|
|
3
|
+
import type { Caller, CallerResolver } from "./caller.js";
|
|
4
|
+
/** Whether the caller a test was made for may see and call `name`. */
|
|
5
|
+
export type VisibleTest = (name: string, action: AnyAction) => boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Decides, once per request, which of the app's actions `caller` may see and call. It
|
|
8
|
+
* returns a synchronous test so lookups, such as a membership role, run once per request.
|
|
9
|
+
*/
|
|
10
|
+
export type ActionVisibility = (caller: Caller, request: Request) => VisibleTest | Promise<VisibleTest>;
|
|
11
|
+
/** The registry a request sees: every surface reads actions through it, never around it. */
|
|
12
|
+
export type RegistryResolver = (request: Request | undefined) => Promise<ActionRegistry>;
|
|
13
|
+
export declare function visibleRegistry(registry: ActionRegistry, test: VisibleTest): ActionRegistry;
|
|
14
|
+
/** Resolves `visible` at most once per request; without it every request sees `registry`. */
|
|
15
|
+
export declare function createRegistryResolver(registry: ActionRegistry, visible: ActionVisibility | undefined, callers: CallerResolver): RegistryResolver;
|
|
16
|
+
//# sourceMappingURL=visibility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visibility.d.ts","sourceRoot":"","sources":["../src/visibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE1D,sEAAsE;AACtE,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC;AAEvE;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,KACb,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;AAExC,4FAA4F;AAC5F,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAEzF,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,cAAc,EACxB,IAAI,EAAE,WAAW,GAChB,cAAc,CAchB;AAED,6FAA6F;AAC7F,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,OAAO,EAAE,cAAc,GACtB,gBAAgB,CAclB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function visibleRegistry(registry, test) {
|
|
2
|
+
const actions = {};
|
|
3
|
+
for (const name of registry.names()) {
|
|
4
|
+
const action = registry.get(name);
|
|
5
|
+
if (action && test(name, action))
|
|
6
|
+
actions[name] = action;
|
|
7
|
+
}
|
|
8
|
+
const names = Object.keys(actions);
|
|
9
|
+
return {
|
|
10
|
+
actions,
|
|
11
|
+
get: (name) => (Object.hasOwn(actions, name) ? actions[name] : undefined),
|
|
12
|
+
names: () => [...names],
|
|
13
|
+
describe: () => registry.describe().filter(({ name }) => Object.hasOwn(actions, name)),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** Resolves `visible` at most once per request; without it every request sees `registry`. */
|
|
17
|
+
export function createRegistryResolver(registry, visible, callers) {
|
|
18
|
+
if (!visible)
|
|
19
|
+
return () => Promise.resolve(registry);
|
|
20
|
+
const views = new WeakMap();
|
|
21
|
+
return (request) => {
|
|
22
|
+
if (!request)
|
|
23
|
+
return Promise.resolve(registry);
|
|
24
|
+
let view = views.get(request);
|
|
25
|
+
if (!view) {
|
|
26
|
+
view = callers(request).then(async (caller) => visibleRegistry(registry, await visible(caller, request)));
|
|
27
|
+
views.set(request, view);
|
|
28
|
+
}
|
|
29
|
+
return view;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=visibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visibility.js","sourceRoot":"","sources":["../src/visibility.ts"],"names":[],"mappings":"AAoBA,MAAM,UAAU,eAAe,CAC7B,QAAwB,EACxB,IAAiB;IAEjB,MAAM,OAAO,GAAc,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;IAC3D,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnC,OAAO;QACL,OAAO;QACP,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC;QACvB,QAAQ,EAAE,GAAG,EAAE,CACb,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;KACzE,CAAC;AACJ,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,sBAAsB,CACpC,QAAwB,EACxB,OAAqC,EACrC,OAAuB;IAEvB,IAAI,CAAC,OAAO;QAAE,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,IAAI,OAAO,EAAoC,CAAC;IAC9D,OAAO,CAAC,OAAO,EAAE,EAAE;QACjB,IAAI,CAAC,OAAO;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAC5C,eAAe,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAC1D,CAAC;YACF,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { ActionMap, AnyAction } from \"@parlor/core\";\nimport type { ActionRegistry } from \"@parlor/core/registry\";\n\nimport type { Caller, CallerResolver } from \"./caller.js\";\n\n/** Whether the caller a test was made for may see and call `name`. */\nexport type VisibleTest = (name: string, action: AnyAction) => boolean;\n\n/**\n * Decides, once per request, which of the app's actions `caller` may see and call. It\n * returns a synchronous test so lookups, such as a membership role, run once per request.\n */\nexport type ActionVisibility = (\n caller: Caller,\n request: Request,\n) => VisibleTest | Promise<VisibleTest>;\n\n/** The registry a request sees: every surface reads actions through it, never around it. */\nexport type RegistryResolver = (request: Request | undefined) => Promise<ActionRegistry>;\n\nexport function visibleRegistry(\n registry: ActionRegistry,\n test: VisibleTest,\n): ActionRegistry {\n const actions: ActionMap = {};\n for (const name of registry.names()) {\n const action = registry.get(name);\n if (action && test(name, action)) actions[name] = action;\n }\n const names = Object.keys(actions);\n return {\n actions,\n get: (name) => (Object.hasOwn(actions, name) ? actions[name] : undefined),\n names: () => [...names],\n describe: () =>\n registry.describe().filter(({ name }) => Object.hasOwn(actions, name)),\n };\n}\n\n/** Resolves `visible` at most once per request; without it every request sees `registry`. */\nexport function createRegistryResolver(\n registry: ActionRegistry,\n visible: ActionVisibility | undefined,\n callers: CallerResolver,\n): RegistryResolver {\n if (!visible) return () => Promise.resolve(registry);\n const views = new WeakMap<Request, Promise<ActionRegistry>>();\n return (request) => {\n if (!request) return Promise.resolve(registry);\n let view = views.get(request);\n if (!view) {\n view = callers(request).then(async (caller) =>\n visibleRegistry(registry, await visible(caller, request)),\n );\n views.set(request, view);\n }\n return view;\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parlor/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"homepage": "https://cychien.github.io/parlor",
|
|
5
5
|
"bugs": "https://github.com/cychien/parlor/issues",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"drizzle-orm": "^0.45.4",
|
|
25
25
|
"h3": "^2.0.1",
|
|
26
26
|
"zod": "^4.6.5",
|
|
27
|
-
"@parlor/
|
|
28
|
-
"@parlor/
|
|
29
|
-
"@parlor/
|
|
27
|
+
"@parlor/agent-ui": "0.4.0",
|
|
28
|
+
"@parlor/core": "0.4.0",
|
|
29
|
+
"@parlor/sync": "0.4.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@modelcontextprotocol/client": "^2.3.1",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"srvx": "^1.0.5",
|
|
35
35
|
"typescript": "^7.0.2",
|
|
36
36
|
"vitest": "^5.0.3",
|
|
37
|
-
"@parlor/data": "0.
|
|
37
|
+
"@parlor/data": "0.4.0"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "tsc -p tsconfig.json",
|