@parlor/core 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/action.d.ts +5 -3
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +1 -0
- package/dist/action.js.map +1 -1
- package/dist/confirmation.d.ts +21 -0
- package/dist/confirmation.d.ts.map +1 -0
- package/dist/confirmation.js +11 -0
- package/dist/confirmation.js.map +1 -0
- package/dist/ids.d.ts +2 -1
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/principal.d.ts +23 -3
- package/dist/principal.d.ts.map +1 -1
- package/dist/principal.js +9 -4
- package/dist/principal.js.map +1 -1
- package/dist/registry/invoke.d.ts +5 -0
- package/dist/registry/invoke.d.ts.map +1 -1
- package/dist/registry/invoke.js +16 -7
- package/dist/registry/invoke.js.map +1 -1
- package/package.json +1 -1
package/dist/action.d.ts
CHANGED
|
@@ -59,9 +59,11 @@ export interface ActionConfig<TInput extends z.ZodType, TOutput> {
|
|
|
59
59
|
readonly notifies?: "scope" | "user" | undefined;
|
|
60
60
|
/**
|
|
61
61
|
* Ask the user to approve each call from an agent (source `mcp` or `agent`) in the app
|
|
62
|
-
* before it runs. Calls from the app's own UI and plain HTTP never ask
|
|
63
|
-
*
|
|
64
|
-
*
|
|
62
|
+
* before it runs. Calls from the app's own UI and plain HTTP never ask, and a call with an
|
|
63
|
+
* API key is refused, as nobody can approve for it. The server's `confirmation` policy can
|
|
64
|
+
* change both. With an enforcing auth provider the source comes from the caller's
|
|
65
|
+
* credential, so this is a boundary; without one it stays a UX guard over a
|
|
66
|
+
* self-declared header.
|
|
65
67
|
*/
|
|
66
68
|
readonly confirm?: boolean | undefined;
|
|
67
69
|
/**
|
package/dist/action.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,gBAAgB,CAAC;AAE/D,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAE3D,MAAM,WAAW,YAAY;CAAG;AAEhC,MAAM,MAAM,cAAc,GAAG,YAAY,SAAS;IAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,OAAO,CAAC;AAEtF,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CAC5C;AAED,MAAM,WAAW,YAAY,CAAC,GAAG,GAAG,OAAO;IACzC;;;OAGG;IACH,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,IAAI,GAAG,CAAC;IACZ,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,CAAC,CACL,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EAClC,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrB,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACxC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAC3C,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;AAC/C,MAAM,MAAM,QAAQ,CAAC,MAAM,IAAI,SAAS,SAAS,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,SAAS,GAAG,EAAE,CAAC,CAAC;AAE1F,MAAM,WAAW,YAAY,CAAC,MAAM,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO;IAC7D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,CAAC;IACnD;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IACjD
|
|
1
|
+
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"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"}
|
package/dist/action.js
CHANGED
package/dist/action.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action.js","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"action.js","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AAyFA,MAAM,OAAO,GAAkB,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AAYvD,MAAM,UAAU,YAAY,CAC1B,MAAqC;IAErC,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAiB;IAC1C,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,iBAAiB,GAA8B,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AAE/E,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,MAAoB;IACvE,OAAO,MAAM,CAAC,OAAO,KAAK,IAAI,IAAI,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,cAAc,GAAG;IACrB,SAAS,EAAE,MAAM;IACjB,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,MAAM;CAC2C,CAAC;AAEzD,MAAM,UAAU,iBAAiB,CAAC,SAAoB;IACpD,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,IAAI,SAAS,CAAC,IAAI;QAAE,OAAO,OAAO,CAAC;IACjE,OAAO,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAiB,EAAE,SAAkB;IAClE,OAAO,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC;AAC7C,CAAC","sourcesContent":["import type { z } from \"zod\";\n\nimport type { Principal, PrincipalKind } from \"./principal.js\";\n\nexport type ActionSource = \"ui\" | \"agent\" | \"http\" | \"mcp\";\n\nexport interface DataRegister {}\n\nexport type ParlorDatabase = DataRegister extends { database: infer D } ? D : unknown;\n\nexport type Unlisten = () => Promise<void>;\n\nexport interface ListenOptions {\n /**\n * The connection behind this listener dropped. It is gone for good, and notifications\n * sent until a new `listen` call succeeds are lost, so a listener must listen again and\n * reload whatever it derived from them.\n */\n readonly onLost?: (() => void) | undefined;\n}\n\nexport interface DataProvider<TDb = unknown> {\n /**\n * Work deferred to the server's first request, such as migrations on runtimes that allow\n * no I/O while the app loads. The server awaits it before anything else touches the data.\n */\n prepare?(): Promise<void>;\n read(): TDb;\n transaction<T>(run: (tx: TDb) => Promise<T>): Promise<T>;\n listen?(\n channel: string,\n handler: (payload: string) => void,\n options?: ListenOptions,\n ): Promise<Unlisten>;\n close?(): Promise<void>;\n}\n\nexport interface ActionContext {\n readonly scope: string;\n readonly source: ActionSource;\n readonly principal: Principal;\n readonly db: ParlorDatabase;\n readonly signal?: AbortSignal | undefined;\n /**\n * The HTTP request that made the call, whichever surface it came through; undefined for\n * an in-process call. For what the request carries besides identity, such as a cookie\n * the app set; who is calling is `principal`.\n */\n readonly request?: Request | undefined;\n}\n\nexport interface TableLike {\n readonly _: { readonly name: string };\n}\n\nexport type TagSource = string | TableLike;\nexport type Tag = readonly (string | number)[];\nexport type ReadTags<TInput> = readonly TagSource[] | ((input: TInput) => readonly Tag[]);\n\nexport interface ActionConfig<TInput extends z.ZodType, TOutput> {\n readonly description: string;\n readonly input: TInput;\n readonly reads?: ReadTags<z.output<TInput>> | undefined;\n readonly writes?: readonly TagSource[] | undefined;\n /**\n * Whose clients its `writes` wake: everyone in the scope (the default), or only the\n * caller's own user, with their tabs and computers, when the scope is shared.\n */\n readonly notifies?: \"scope\" | \"user\" | undefined;\n /**\n * Ask the user to approve each call from an agent (source `mcp` or `agent`) in the app\n * before it runs. Calls from the app's own UI and plain HTTP never ask, and a call with an\n * API key is refused, as nobody can approve for it. The server's `confirmation` policy can\n * change both. With an enforcing auth provider the source comes from the caller's\n * credential, so this is a boundary; without one it stays a UX guard over a\n * self-declared header.\n */\n readonly confirm?: boolean | undefined;\n /**\n * Callable without signing in. Only read when the server has an enforcing auth provider,\n * which otherwise answers an anonymous caller with `unauthenticated`.\n */\n readonly public?: boolean | undefined;\n readonly run: (\n input: z.output<TInput>,\n ctx: ActionContext,\n ) => Promise<TOutput> | TOutput;\n}\n\nconst kAction: unique symbol = Symbol.for(\"fw.action\");\n\nexport interface ActionDefinition<\n TInput extends z.ZodType = z.ZodType,\n TOutput = unknown,\n> extends ActionConfig<TInput, TOutput> {\n readonly [kAction]: true;\n}\n\nexport type AnyAction = ActionDefinition<z.ZodType, unknown>;\nexport type ActionMap = Record<string, AnyAction>;\n\nexport function defineAction<TInput extends z.ZodType, TOutput>(\n config: ActionConfig<TInput, TOutput>,\n): ActionDefinition<TInput, TOutput> {\n return { ...config, [kAction]: true };\n}\n\nexport function isAction(value: unknown): value is AnyAction {\n return typeof value === \"object\" && value !== null && kAction in value;\n}\n\nexport function isMutating(action: AnyAction): boolean {\n return (action.writes?.length ?? 0) > 0;\n}\n\nconst CONFIRMED_SOURCES: ReadonlySet<ActionSource> = new Set([\"mcp\", \"agent\"]);\n\nexport function needsConfirmation(action: AnyAction, source: ActionSource): boolean {\n return action.confirm === true && CONFIRMED_SOURCES.has(source);\n}\n\nconst SOURCE_BY_KIND = {\n anonymous: \"http\",\n user: \"ui\",\n agent: \"mcp\",\n host: \"http\",\n key: \"http\",\n} as const satisfies Record<PrincipalKind, ActionSource>;\n\nexport function sourceOfPrincipal(principal: Principal): ActionSource {\n if (principal.kind === \"agent\" && principal.turn) return \"agent\";\n return SOURCE_BY_KIND[principal.kind];\n}\n\nexport function needsPrincipal(action: AnyAction, enforcing: boolean): boolean {\n return enforcing && action.public !== true;\n}\n\nexport type ActionInput<A> =\n A extends ActionDefinition<infer I, unknown> ? z.input<I> : never;\nexport type ActionOutput<A> = A extends ActionDefinition<z.ZodType, infer O> ? O : never;\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ActionSource, type AnyAction } from "./action.js";
|
|
2
|
+
import type { Principal } from "./principal.js";
|
|
3
|
+
/**
|
|
4
|
+
* What happens to a call before `run`: `ask` waits for the user to approve it in the app,
|
|
5
|
+
* `proceed` runs it, and `refuse` fails it with `confirmation_unavailable` at once.
|
|
6
|
+
*/
|
|
7
|
+
export type ConfirmationDecision = "ask" | "proceed" | "refuse";
|
|
8
|
+
export interface ConfirmationCall {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly action: AnyAction;
|
|
11
|
+
readonly principal: Principal;
|
|
12
|
+
readonly source: ActionSource;
|
|
13
|
+
}
|
|
14
|
+
/** Decides, once per call after its input is valid, whether someone must approve it first. */
|
|
15
|
+
export type ConfirmationPolicy = (call: ConfirmationCall) => ConfirmationDecision;
|
|
16
|
+
/**
|
|
17
|
+
* Asks before an agent's call to a `confirm: true` action and refuses a key's call to one,
|
|
18
|
+
* since nobody can approve for a key. Everything else proceeds.
|
|
19
|
+
*/
|
|
20
|
+
export declare const defaultConfirmationPolicy: ConfirmationPolicy;
|
|
21
|
+
//# sourceMappingURL=confirmation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirmation.d.ts","sourceRoot":"","sources":["../src/confirmation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAqB,MAAM,aAAa,CAAC;AACnF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEhE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;CAC/B;AAED,8FAA8F;AAC9F,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,gBAAgB,KAAK,oBAAoB,CAAC;AAElF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,kBAOvC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { needsConfirmation } from "./action.js";
|
|
2
|
+
/**
|
|
3
|
+
* Asks before an agent's call to a `confirm: true` action and refuses a key's call to one,
|
|
4
|
+
* since nobody can approve for a key. Everything else proceeds.
|
|
5
|
+
*/
|
|
6
|
+
export const defaultConfirmationPolicy = ({ action, principal, source, }) => {
|
|
7
|
+
if (action.confirm === true && principal.kind === "key")
|
|
8
|
+
return "refuse";
|
|
9
|
+
return needsConfirmation(action, source) ? "ask" : "proceed";
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=confirmation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirmation.js","sourceRoot":"","sources":["../src/confirmation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqC,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAmBnF;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAuB,CAAC,EAC5D,MAAM,EACN,SAAS,EACT,MAAM,GACP,EAAE,EAAE;IACH,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI,IAAI,SAAS,CAAC,IAAI,KAAK,KAAK;QAAE,OAAO,QAAQ,CAAC;IACzE,OAAO,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/D,CAAC,CAAC","sourcesContent":["import { type ActionSource, type AnyAction, needsConfirmation } from \"./action.js\";\nimport type { Principal } from \"./principal.js\";\n\n/**\n * What happens to a call before `run`: `ask` waits for the user to approve it in the app,\n * `proceed` runs it, and `refuse` fails it with `confirmation_unavailable` at once.\n */\nexport type ConfirmationDecision = \"ask\" | \"proceed\" | \"refuse\";\n\nexport interface ConfirmationCall {\n readonly name: string;\n readonly action: AnyAction;\n readonly principal: Principal;\n readonly source: ActionSource;\n}\n\n/** Decides, once per call after its input is valid, whether someone must approve it first. */\nexport type ConfirmationPolicy = (call: ConfirmationCall) => ConfirmationDecision;\n\n/**\n * Asks before an agent's call to a `confirm: true` action and refuses a key's call to one,\n * since nobody can approve for a key. Everything else proceeds.\n */\nexport const defaultConfirmationPolicy: ConfirmationPolicy = ({\n action,\n principal,\n source,\n}) => {\n if (action.confirm === true && principal.kind === \"key\") return \"refuse\";\n return needsConfirmation(action, source) ? \"ask\" : \"proceed\";\n};\n"]}
|
package/dist/ids.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
declare const idKind: unique symbol;
|
|
2
|
-
export type IdKind = "user" | "device" | "grant" | "host" | "thread" | "turn" | "item";
|
|
2
|
+
export type IdKind = "user" | "device" | "grant" | "host" | "thread" | "turn" | "item" | "key";
|
|
3
3
|
export type Id<K extends IdKind> = string & {
|
|
4
4
|
readonly [idKind]: K;
|
|
5
5
|
};
|
|
@@ -10,6 +10,7 @@ export type HostId = Id<"host">;
|
|
|
10
10
|
export type ThreadId = Id<"thread">;
|
|
11
11
|
export type TurnId = Id<"turn">;
|
|
12
12
|
export type ItemId = Id<"item">;
|
|
13
|
+
export type KeyId = Id<"key">;
|
|
13
14
|
/**
|
|
14
15
|
* Names a string as an id. Only boundary code calls it: a verified token's claims, a
|
|
15
16
|
* database row, a request body after validation.
|
package/dist/ids.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,MAAM,EAAE,OAAO,MAAM,CAAC;AAEpC,MAAM,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,MAAM,EAAE,OAAO,MAAM,CAAC;AAEpC,MAAM,MAAM,MAAM,GACd,MAAM,GACN,QAAQ,GACR,OAAO,GACP,MAAM,GACN,QAAQ,GACR,MAAM,GACN,MAAM,GACN,KAAK,CAAC;AAEV,MAAM,MAAM,EAAE,CAAC,CAAC,SAAS,MAAM,IAAI,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC;AAErE,MAAM,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;AAChC,MAAM,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC;AACpC,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC;AAClC,MAAM,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;AAChC,MAAM,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC;AACpC,MAAM,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;AAChC,MAAM,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;AAChC,MAAM,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;AAE9B;;;GAGG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,CAErE"}
|
package/dist/ids.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAuBA;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAmB,KAAQ,EAAE,KAAa;IAC5D,OAAO,KAAc,CAAC;AACxB,CAAC","sourcesContent":["declare const idKind: unique symbol;\n\nexport type IdKind =\n | \"user\"\n | \"device\"\n | \"grant\"\n | \"host\"\n | \"thread\"\n | \"turn\"\n | \"item\"\n | \"key\";\n\nexport type Id<K extends IdKind> = string & { readonly [idKind]: K };\n\nexport type UserId = Id<\"user\">;\nexport type DeviceId = Id<\"device\">;\nexport type GrantId = Id<\"grant\">;\nexport type HostId = Id<\"host\">;\nexport type ThreadId = Id<\"thread\">;\nexport type TurnId = Id<\"turn\">;\nexport type ItemId = Id<\"item\">;\nexport type KeyId = Id<\"key\">;\n\n/**\n * Names a string as an id. Only boundary code calls it: a verified token's claims, a\n * database row, a request body after validation.\n */\nexport function asId<K extends IdKind>(_kind: K, value: string): Id<K> {\n return value as Id<K>;\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { type ActionConfig, type ActionContext, type ActionDefinition, type ActionInput, type ActionMap, type ActionOutput, type ActionSource, type AnyAction, type DataProvider, type DataRegister, type Unlisten, defineAction, isAction, isMutating, type ListenOptions, needsConfirmation, needsPrincipal, type ParlorDatabase, type ReadTags, sourceOfPrincipal, type TableLike, type Tag, type TagSource, } from "./action.js";
|
|
2
|
+
export { type ConfirmationCall, type ConfirmationDecision, type ConfirmationPolicy, defaultConfirmationPolicy, } from "./confirmation.js";
|
|
2
3
|
export { decodeReadRequests, encodeReadRequests, MAX_REFRESHED_READS, type ReadRequest, REFRESH_HEADER, type RefreshedRead, } from "./refresh.js";
|
|
3
4
|
export { ACTION_ERROR_CODES, ActionError, type ActionErrorBody, type ActionErrorCode, } from "./errors.js";
|
|
4
|
-
export { asId, type DeviceId, type GrantId, type HostId, type Id, type IdKind, type ItemId, type ThreadId, type TurnId, type UserId, } from "./ids.js";
|
|
5
|
-
export { ANONYMOUS, type AgentIdentity, type AgentPrincipal, type AnonymousPrincipal, type AuthenticatedPrincipal, DEV_USER_ID, type HostPrincipal, isAuthenticated, type Principal, type PrincipalKind, type TurnBinding, type UserPrincipal, userOf, } from "./principal.js";
|
|
5
|
+
export { asId, type DeviceId, type GrantId, type HostId, type Id, type IdKind, type ItemId, type KeyId, type ThreadId, type TurnId, type UserId, } from "./ids.js";
|
|
6
|
+
export { ANONYMOUS, type AgentIdentity, type AgentPrincipal, type AnonymousPrincipal, type AuthenticatedPrincipal, DEV_USER_ID, hasUser, type HostPrincipal, isAuthenticated, type KeyPrincipal, type Principal, type PrincipalKind, type TurnBinding, type UserPrincipal, userOf, } from "./principal.js";
|
|
6
7
|
export { SHELL_ORIGINS } from "./shell-origins.js";
|
|
7
8
|
export { readTagsFor, tableName, tagsOverlap, writeTagsFor } from "./tags.js";
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,KAAK,aAAa,EAClB,iBAAiB,EACjB,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,iBAAiB,EACjB,KAAK,SAAS,EACd,KAAK,GAAG,EACR,KAAK,SAAS,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,WAAW,EAChB,cAAc,EACd,KAAK,aAAa,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,IAAI,EACJ,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,MAAM,EACX,KAAK,EAAE,EACP,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,MAAM,GACZ,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,SAAS,EACT,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,WAAW,EACX,KAAK,aAAa,EAClB,eAAe,EACf,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,MAAM,GACP,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,KAAK,aAAa,EAClB,iBAAiB,EACjB,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,iBAAiB,EACjB,KAAK,SAAS,EACd,KAAK,GAAG,EACR,KAAK,SAAS,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,WAAW,EAChB,cAAc,EACd,KAAK,aAAa,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,IAAI,EACJ,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,MAAM,EACX,KAAK,EAAE,EACP,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,MAAM,GACZ,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,SAAS,EACT,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,WAAW,EACX,OAAO,EACP,KAAK,aAAa,EAClB,eAAe,EACf,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,MAAM,GACP,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { defineAction, isAction, isMutating, needsConfirmation, needsPrincipal, sourceOfPrincipal, } from "./action.js";
|
|
2
|
+
export { defaultConfirmationPolicy, } from "./confirmation.js";
|
|
2
3
|
export { decodeReadRequests, encodeReadRequests, MAX_REFRESHED_READS, REFRESH_HEADER, } from "./refresh.js";
|
|
3
4
|
export { ACTION_ERROR_CODES, ActionError, } from "./errors.js";
|
|
4
5
|
export { asId, } from "./ids.js";
|
|
5
|
-
export { ANONYMOUS, DEV_USER_ID, isAuthenticated, userOf, } from "./principal.js";
|
|
6
|
+
export { ANONYMOUS, DEV_USER_ID, hasUser, isAuthenticated, userOf, } from "./principal.js";
|
|
6
7
|
export { SHELL_ORIGINS } from "./shell-origins.js";
|
|
7
8
|
export { readTagsFor, tableName, tagsOverlap, writeTagsFor } from "./tags.js";
|
|
8
9
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAYL,YAAY,EACZ,QAAQ,EACR,UAAU,EAEV,iBAAiB,EACjB,cAAc,EAGd,iBAAiB,GAIlB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EAEnB,cAAc,GAEf,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,WAAW,GAGZ,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,IAAI,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAYL,YAAY,EACZ,QAAQ,EACR,UAAU,EAEV,iBAAiB,EACjB,cAAc,EAGd,iBAAiB,GAIlB,MAAM,aAAa,CAAC;AACrB,OAAO,EAIL,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EAEnB,cAAc,GAEf,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,WAAW,GAGZ,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,IAAI,GAWL,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,SAAS,EAKT,WAAW,EACX,OAAO,EAEP,eAAe,EAMf,MAAM,GACP,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC","sourcesContent":["export {\n type ActionConfig,\n type ActionContext,\n type ActionDefinition,\n type ActionInput,\n type ActionMap,\n type ActionOutput,\n type ActionSource,\n type AnyAction,\n type DataProvider,\n type DataRegister,\n type Unlisten,\n defineAction,\n isAction,\n isMutating,\n type ListenOptions,\n needsConfirmation,\n needsPrincipal,\n type ParlorDatabase,\n type ReadTags,\n sourceOfPrincipal,\n type TableLike,\n type Tag,\n type TagSource,\n} from \"./action.js\";\nexport {\n type ConfirmationCall,\n type ConfirmationDecision,\n type ConfirmationPolicy,\n defaultConfirmationPolicy,\n} from \"./confirmation.js\";\nexport {\n decodeReadRequests,\n encodeReadRequests,\n MAX_REFRESHED_READS,\n type ReadRequest,\n REFRESH_HEADER,\n type RefreshedRead,\n} from \"./refresh.js\";\nexport {\n ACTION_ERROR_CODES,\n ActionError,\n type ActionErrorBody,\n type ActionErrorCode,\n} from \"./errors.js\";\nexport {\n asId,\n type DeviceId,\n type GrantId,\n type HostId,\n type Id,\n type IdKind,\n type ItemId,\n type KeyId,\n type ThreadId,\n type TurnId,\n type UserId,\n} from \"./ids.js\";\nexport {\n ANONYMOUS,\n type AgentIdentity,\n type AgentPrincipal,\n type AnonymousPrincipal,\n type AuthenticatedPrincipal,\n DEV_USER_ID,\n hasUser,\n type HostPrincipal,\n isAuthenticated,\n type KeyPrincipal,\n type Principal,\n type PrincipalKind,\n type TurnBinding,\n type UserPrincipal,\n userOf,\n} from \"./principal.js\";\nexport { SHELL_ORIGINS } from \"./shell-origins.js\";\nexport { readTagsFor, tableName, tagsOverlap, writeTagsFor } from \"./tags.js\";\n"]}
|
package/dist/principal.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { type DeviceId, type GrantId, type HostId, type ThreadId, type TurnId, type UserId } from "./ids.js";
|
|
1
|
+
import { type DeviceId, type GrantId, type HostId, type KeyId, type ThreadId, type TurnId, type UserId } from "./ids.js";
|
|
2
2
|
/**
|
|
3
3
|
* Who is calling, resolved once per request from its credential by the server's auth
|
|
4
4
|
* provider. Never built from a header: `x-parlor-source` and `x-parlor-client` are
|
|
5
5
|
* routing hints at most.
|
|
6
6
|
*/
|
|
7
|
-
export type Principal = AnonymousPrincipal | UserPrincipal | AgentPrincipal | HostPrincipal;
|
|
7
|
+
export type Principal = AnonymousPrincipal | UserPrincipal | AgentPrincipal | HostPrincipal | KeyPrincipal;
|
|
8
8
|
export type PrincipalKind = Principal["kind"];
|
|
9
9
|
export interface AnonymousPrincipal {
|
|
10
10
|
readonly kind: "anonymous";
|
|
@@ -34,6 +34,20 @@ export interface HostPrincipal {
|
|
|
34
34
|
readonly grantId: GrantId;
|
|
35
35
|
readonly hostId: HostId;
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* A program holding an API key the app issued, bound to one scope. No person stands behind
|
|
39
|
+
* its calls: it has no user, nobody can approve for it, and it reaches no screen.
|
|
40
|
+
*/
|
|
41
|
+
export interface KeyPrincipal {
|
|
42
|
+
readonly kind: "key";
|
|
43
|
+
readonly keyId: KeyId;
|
|
44
|
+
/** The only scope it acts in; the server refuses a scope resolver that answers another. */
|
|
45
|
+
readonly scope: string;
|
|
46
|
+
/** How audit records and approvals name it, such as `API key "CI exporter"`. */
|
|
47
|
+
readonly name: string;
|
|
48
|
+
/** The app's own claims, such as a role. The framework never reads them. */
|
|
49
|
+
readonly claims: Readonly<Record<string, string | boolean>>;
|
|
50
|
+
}
|
|
37
51
|
/** `verified` is false when the name is the MCP client's self-declared `clientInfo.name`. */
|
|
38
52
|
export interface AgentIdentity {
|
|
39
53
|
readonly name: string;
|
|
@@ -45,13 +59,19 @@ export interface TurnBinding {
|
|
|
45
59
|
readonly hostId: HostId;
|
|
46
60
|
readonly clientId: string;
|
|
47
61
|
}
|
|
48
|
-
|
|
62
|
+
/** A signed-in principal backed by a user: everything but anonymous and a key. */
|
|
63
|
+
export type AuthenticatedPrincipal = UserPrincipal | AgentPrincipal | HostPrincipal;
|
|
49
64
|
export declare const ANONYMOUS: AnonymousPrincipal;
|
|
50
65
|
/**
|
|
51
66
|
* Who everyone is when no provider tells people apart: the anonymous browser and the
|
|
52
67
|
* `parlor dev` host and turns. Equal to the default scope, so they share one audience.
|
|
53
68
|
*/
|
|
54
69
|
export declare const DEV_USER_ID: UserId;
|
|
70
|
+
export declare function hasUser(principal: Principal): principal is AuthenticatedPrincipal;
|
|
71
|
+
/**
|
|
72
|
+
* @deprecated Use `hasUser`, or `principal.kind !== "anonymous"` to include a key. Same as
|
|
73
|
+
* `hasUser`: false for a key, which is signed in but has no user.
|
|
74
|
+
*/
|
|
55
75
|
export declare function isAuthenticated(principal: Principal): principal is AuthenticatedPrincipal;
|
|
56
76
|
export declare function userOf(principal: Principal | undefined): UserId | undefined;
|
|
57
77
|
//# sourceMappingURL=principal.d.ts.map
|
package/dist/principal.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principal.d.ts","sourceRoot":"","sources":["../src/principal.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,MAAM,EACZ,MAAM,UAAU,CAAC;AAElB;;;;GAIG;AACH,MAAM,MAAM,SAAS,GACjB,kBAAkB,GAClB,aAAa,GACb,cAAc,GACd,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"principal.d.ts","sourceRoot":"","sources":["../src/principal.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,MAAM,EACX,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,MAAM,EACZ,MAAM,UAAU,CAAC;AAElB;;;;GAIG;AACH,MAAM,MAAM,SAAS,GACjB,kBAAkB,GAClB,aAAa,GACb,cAAc,GACd,aAAa,GACb,YAAY,CAAC;AAEjB,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;AAE9C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;CAC5B;AAED,6DAA6D;AAC7D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC1C;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CACzC;AAED,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,2FAA2F;IAC3F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;CAC7D;AAED,6FAA6F;AAC7F,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,kFAAkF;AAClF,MAAM,MAAM,sBAAsB,GAAG,aAAa,GAAG,cAAc,GAAG,aAAa,CAAC;AAEpF,eAAO,MAAM,SAAS,EAAE,kBAA0C,CAAC;AAEnE;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,MAAgC,CAAC;AAE3D,wBAAgB,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,IAAI,sBAAsB,CAIjF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,SAAS,GACnB,SAAS,IAAI,sBAAsB,CAErC;AAED,wBAAgB,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAE3E"}
|
package/dist/principal.js
CHANGED
|
@@ -5,12 +5,17 @@ export const ANONYMOUS = { kind: "anonymous" };
|
|
|
5
5
|
* `parlor dev` host and turns. Equal to the default scope, so they share one audience.
|
|
6
6
|
*/
|
|
7
7
|
export const DEV_USER_ID = asId("user", "default");
|
|
8
|
+
export function hasUser(principal) {
|
|
9
|
+
return (principal.kind === "user" || principal.kind === "agent" || principal.kind === "host");
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Use `hasUser`, or `principal.kind !== "anonymous"` to include a key. Same as
|
|
13
|
+
* `hasUser`: false for a key, which is signed in but has no user.
|
|
14
|
+
*/
|
|
8
15
|
export function isAuthenticated(principal) {
|
|
9
|
-
return principal
|
|
16
|
+
return hasUser(principal);
|
|
10
17
|
}
|
|
11
18
|
export function userOf(principal) {
|
|
12
|
-
|
|
13
|
-
return undefined;
|
|
14
|
-
return principal.kind === "anonymous" ? undefined : principal.userId;
|
|
19
|
+
return principal !== undefined && hasUser(principal) ? principal.userId : undefined;
|
|
15
20
|
}
|
|
16
21
|
//# sourceMappingURL=principal.js.map
|
package/dist/principal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principal.js","sourceRoot":"","sources":["../src/principal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,
|
|
1
|
+
{"version":3,"file":"principal.js","sourceRoot":"","sources":["../src/principal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,GAQL,MAAM,UAAU,CAAC;AA+ElB,MAAM,CAAC,MAAM,SAAS,GAAuB,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAEnE;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAW,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAE3D,MAAM,UAAU,OAAO,CAAC,SAAoB;IAC1C,OAAO,CACL,SAAS,CAAC,IAAI,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,CACrF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,SAAoB;IAEpB,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,SAAgC;IACrD,OAAO,SAAS,KAAK,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACtF,CAAC","sourcesContent":["import {\n asId,\n type DeviceId,\n type GrantId,\n type HostId,\n type KeyId,\n type ThreadId,\n type TurnId,\n type UserId,\n} from \"./ids.js\";\n\n/**\n * Who is calling, resolved once per request from its credential by the server's auth\n * provider. Never built from a header: `x-parlor-source` and `x-parlor-client` are\n * routing hints at most.\n */\nexport type Principal =\n | AnonymousPrincipal\n | UserPrincipal\n | AgentPrincipal\n | HostPrincipal\n | KeyPrincipal;\n\nexport type PrincipalKind = Principal[\"kind\"];\n\nexport interface AnonymousPrincipal {\n readonly kind: \"anonymous\";\n}\n\n/** A person in the app's own UI: a session on one device. */\nexport interface UserPrincipal {\n readonly kind: \"user\";\n readonly userId: UserId;\n readonly sessionId: string;\n readonly deviceId?: DeviceId | undefined;\n}\n\n/**\n * An agent acting for a user. `turn` is set only for an inline agent inside a chat turn;\n * an external MCP client has none.\n */\nexport interface AgentPrincipal {\n readonly kind: \"agent\";\n readonly userId: UserId;\n readonly grantId: GrantId;\n readonly agent: AgentIdentity;\n readonly turn?: TurnBinding | undefined;\n}\n\n/** A user's computer running Parlor Host, holding a grant for one app. */\nexport interface HostPrincipal {\n readonly kind: \"host\";\n readonly userId: UserId;\n readonly grantId: GrantId;\n readonly hostId: HostId;\n}\n\n/**\n * A program holding an API key the app issued, bound to one scope. No person stands behind\n * its calls: it has no user, nobody can approve for it, and it reaches no screen.\n */\nexport interface KeyPrincipal {\n readonly kind: \"key\";\n readonly keyId: KeyId;\n /** The only scope it acts in; the server refuses a scope resolver that answers another. */\n readonly scope: string;\n /** How audit records and approvals name it, such as `API key \"CI exporter\"`. */\n readonly name: string;\n /** The app's own claims, such as a role. The framework never reads them. */\n readonly claims: Readonly<Record<string, string | boolean>>;\n}\n\n/** `verified` is false when the name is the MCP client's self-declared `clientInfo.name`. */\nexport interface AgentIdentity {\n readonly name: string;\n readonly verified: boolean;\n}\n\nexport interface TurnBinding {\n readonly threadId: ThreadId;\n readonly turnId: TurnId;\n readonly hostId: HostId;\n readonly clientId: string;\n}\n\n/** A signed-in principal backed by a user: everything but anonymous and a key. */\nexport type AuthenticatedPrincipal = UserPrincipal | AgentPrincipal | HostPrincipal;\n\nexport const ANONYMOUS: AnonymousPrincipal = { kind: \"anonymous\" };\n\n/**\n * Who everyone is when no provider tells people apart: the anonymous browser and the\n * `parlor dev` host and turns. Equal to the default scope, so they share one audience.\n */\nexport const DEV_USER_ID: UserId = asId(\"user\", \"default\");\n\nexport function hasUser(principal: Principal): principal is AuthenticatedPrincipal {\n return (\n principal.kind === \"user\" || principal.kind === \"agent\" || principal.kind === \"host\"\n );\n}\n\n/**\n * @deprecated Use `hasUser`, or `principal.kind !== \"anonymous\"` to include a key. Same as\n * `hasUser`: false for a key, which is signed in but has no user.\n */\nexport function isAuthenticated(\n principal: Principal,\n): principal is AuthenticatedPrincipal {\n return hasUser(principal);\n}\n\nexport function userOf(principal: Principal | undefined): UserId | undefined {\n return principal !== undefined && hasUser(principal) ? principal.userId : undefined;\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ActionContext, AnyAction, DataProvider, Tag } from "../action.js";
|
|
2
|
+
import { type ConfirmationPolicy } from "../confirmation.js";
|
|
2
3
|
import { type Principal } from "../principal.js";
|
|
3
4
|
import type { ActionRegistry } from "./registry.js";
|
|
4
5
|
/** A caller that names no principal is anonymous: missing identity never widens access. */
|
|
@@ -22,6 +23,10 @@ export interface InvokeOptions {
|
|
|
22
23
|
readonly data?: DataProvider | undefined;
|
|
23
24
|
readonly onWrite?: ((event: WriteEvent) => Promise<void>) | undefined;
|
|
24
25
|
readonly confirm?: ((call: PreparedCall) => Promise<void>) | undefined;
|
|
26
|
+
/** Whether a call is asked about, run or refused before `run`; `defaultConfirmationPolicy` when absent. */
|
|
27
|
+
readonly confirmation?: ConfirmationPolicy | undefined;
|
|
28
|
+
/** Called when the policy runs a call the default policy would have asked about or refused. */
|
|
29
|
+
readonly onWaived?: (() => void) | undefined;
|
|
25
30
|
/** An enforcing auth provider is installed: non-public actions refuse anonymous callers. */
|
|
26
31
|
readonly enforcing?: boolean | undefined;
|
|
27
32
|
/** Called once, right before `run`: every earlier refusal leaves it uncalled. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../../src/registry/invoke.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../../src/registry/invoke.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEhF,OAAO,EAAE,KAAK,kBAAkB,EAA6B,MAAM,oBAAoB,CAAC;AAExF,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,2FAA2F;AAC3F,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG;IACpE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CAC5C,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;IACvE,2GAA2G;IAC3G,QAAQ,CAAC,YAAY,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACvD,+FAA+F;IAC/F,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAC7C,4FAA4F;IAC5F,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACzC,iFAAiF;IACjF,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC;CACxB;AAED,wBAAsB,YAAY,CAChC,QAAQ,EAAE,cAAc,EACxB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,GAAG,EAAE,aAAa,EAClB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA+DvB"}
|
package/dist/registry/invoke.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { isMutating,
|
|
1
|
+
import { isMutating, needsPrincipal } from "../action.js";
|
|
2
|
+
import { defaultConfirmationPolicy } from "../confirmation.js";
|
|
2
3
|
import { ActionError } from "../errors.js";
|
|
3
4
|
import { ANONYMOUS } from "../principal.js";
|
|
4
5
|
import { readTagsFor, writeTagsFor } from "../tags.js";
|
|
@@ -18,12 +19,20 @@ export async function invokeAction(registry, name, rawInput, ctx, options = {})
|
|
|
18
19
|
});
|
|
19
20
|
}
|
|
20
21
|
const input = parsed.data;
|
|
21
|
-
const { data, onWrite, confirm } = options;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
const { data, onWrite, confirm, confirmation = defaultConfirmationPolicy } = options;
|
|
23
|
+
const call = { name, action, principal, source: ctx.source };
|
|
24
|
+
switch (confirmation(call)) {
|
|
25
|
+
case "proceed":
|
|
26
|
+
if (defaultConfirmationPolicy(call) !== "proceed")
|
|
27
|
+
options.onWaived?.();
|
|
28
|
+
break;
|
|
29
|
+
case "refuse":
|
|
30
|
+
throw new ActionError("confirmation_unavailable", `"${name}" needs a person's approval, and nobody can give it for this caller. Ask the user to do it in the app themselves.`);
|
|
31
|
+
case "ask":
|
|
32
|
+
if (!confirm) {
|
|
33
|
+
throw new ActionError("confirmation_unavailable", `"${name}" needs the user's approval, but nothing here can ask for it.`);
|
|
34
|
+
}
|
|
35
|
+
await confirm({ action, name, input, ctx: { ...ctx, principal } });
|
|
27
36
|
}
|
|
28
37
|
const reads = readTagsFor(action, input);
|
|
29
38
|
if (!data) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoke.js","sourceRoot":"","sources":["../../src/registry/invoke.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"invoke.js","sourceRoot":"","sources":["../../src/registry/invoke.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ActionContext, AnyAction, DataProvider, Tag } from \"../action.js\";\nimport { isMutating, needsPrincipal } from \"../action.js\";\nimport { type ConfirmationPolicy, defaultConfirmationPolicy } from \"../confirmation.js\";\nimport { ActionError } from \"../errors.js\";\nimport { ANONYMOUS, type Principal } from \"../principal.js\";\nimport { readTagsFor, writeTagsFor } from \"../tags.js\";\nimport type { ActionRegistry } from \"./registry.js\";\n\n/** A caller that names no principal is anonymous: missing identity never widens access. */\nexport type InvokeContext = Omit<ActionContext, \"db\" | \"principal\"> & {\n readonly principal?: Principal | undefined;\n};\n\nexport interface WriteEvent {\n readonly action: AnyAction;\n readonly name: string;\n readonly tags: Tag[];\n readonly ctx: InvokeContext;\n readonly tx: unknown;\n}\n\nexport interface PreparedCall {\n readonly action: AnyAction;\n readonly name: string;\n readonly input: unknown;\n readonly ctx: InvokeContext;\n}\n\nexport interface InvokeOptions {\n readonly data?: DataProvider | undefined;\n readonly onWrite?: ((event: WriteEvent) => Promise<void>) | undefined;\n readonly confirm?: ((call: PreparedCall) => Promise<void>) | undefined;\n /** Whether a call is asked about, run or refused before `run`; `defaultConfirmationPolicy` when absent. */\n readonly confirmation?: ConfirmationPolicy | undefined;\n /** Called when the policy runs a call the default policy would have asked about or refused. */\n readonly onWaived?: (() => void) | undefined;\n /** An enforcing auth provider is installed: non-public actions refuse anonymous callers. */\n readonly enforcing?: boolean | undefined;\n /** Called once, right before `run`: every earlier refusal leaves it uncalled. */\n readonly onRun?: (() => void) | undefined;\n}\n\nexport interface InvokeResult {\n readonly data: unknown;\n readonly reads: Tag[];\n readonly writes: Tag[];\n}\n\nexport async function invokeAction(\n registry: ActionRegistry,\n name: string,\n rawInput: unknown,\n ctx: InvokeContext,\n options: InvokeOptions = {},\n): Promise<InvokeResult> {\n const action = registry.get(name);\n if (!action) throw new ActionError(\"not_found\", `Unknown action \"${name}\"`);\n const principal = ctx.principal ?? ANONYMOUS;\n if (\n principal.kind === \"anonymous\" &&\n needsPrincipal(action, options.enforcing === true)\n ) {\n throw new ActionError(\"unauthenticated\", `Sign in to call \"${name}\".`);\n }\n\n const parsed = await action.input.safeParseAsync(rawInput ?? {});\n if (!parsed.success) {\n throw new ActionError(\"invalid_input\", `Invalid input for \"${name}\"`, {\n issues: parsed.error.issues,\n });\n }\n const input = parsed.data;\n const { data, onWrite, confirm, confirmation = defaultConfirmationPolicy } = options;\n const call = { name, action, principal, source: ctx.source };\n switch (confirmation(call)) {\n case \"proceed\":\n if (defaultConfirmationPolicy(call) !== \"proceed\") options.onWaived?.();\n break;\n case \"refuse\":\n throw new ActionError(\n \"confirmation_unavailable\",\n `\"${name}\" needs a person's approval, and nobody can give it for this caller. Ask the user to do it in the app themselves.`,\n );\n case \"ask\":\n if (!confirm) {\n throw new ActionError(\n \"confirmation_unavailable\",\n `\"${name}\" needs the user's approval, but nothing here can ask for it.`,\n );\n }\n await confirm({ action, name, input, ctx: { ...ctx, principal } });\n }\n const reads = readTagsFor(action, input);\n\n if (!data) {\n options.onRun?.();\n const result = await action.run(input, { ...ctx, principal, db: undefined as never });\n return { data: result, reads, writes: writeTagsFor(action, result) };\n }\n\n if (!isMutating(action)) {\n options.onRun?.();\n const result = await action.run(input, {\n ...ctx,\n principal,\n db: data.read() as never,\n });\n return { data: result, reads, writes: [] };\n }\n\n return data.transaction(async (tx) => {\n options.onRun?.();\n const result = await action.run(input, { ...ctx, principal, db: tx as never });\n const writes = writeTagsFor(action, result);\n await onWrite?.({ action, name, tags: writes, ctx, tx });\n return { data: result, reads, writes };\n });\n}\n"]}
|