@emseepea/server 0.19.0 → 0.20.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.
@@ -0,0 +1,66 @@
1
+ import { z } from "zod";
2
+ declare const proposalSchema: z.ZodObject<{
3
+ principalId: z.ZodString;
4
+ scopeId: z.ZodString;
5
+ tool: z.ZodString;
6
+ input: z.ZodJSONSchema;
7
+ effect: z.ZodJSONSchema;
8
+ formSchema: z.ZodJSONSchema;
9
+ }, z.core.$strict>;
10
+ export type ExternalApprovalProposal = z.infer<typeof proposalSchema>;
11
+ declare const recordSchema: z.ZodObject<{
12
+ capsuleDigest: z.ZodString;
13
+ expiresAt: z.ZodNumber;
14
+ state: z.ZodEnum<{
15
+ pending: "pending";
16
+ approved: "approved";
17
+ cancelled: "cancelled";
18
+ consumed: "consumed";
19
+ }>;
20
+ }, z.core.$strict>;
21
+ export type ExternalApprovalRecord = Readonly<z.infer<typeof recordSchema>>;
22
+ /** CAS must compare the entire expected record atomically across all instances. */
23
+ export interface ExternalApprovalStore {
24
+ load(key: string): Promise<ExternalApprovalRecord | null>;
25
+ compareAndSwap(key: string, expected: ExternalApprovalRecord | null, replacement: ExternalApprovalRecord): Promise<boolean>;
26
+ }
27
+ export interface ExternalApprovalOptions {
28
+ readonly key: Uint8Array;
29
+ readonly store: ExternalApprovalStore;
30
+ readonly lifetimeMs: number;
31
+ readonly maxCapsuleBytes: number;
32
+ readonly now?: () => number;
33
+ }
34
+ declare const VERIFIED_EXTERNAL_APPROVAL: unique symbol;
35
+ export type ExternalApprovalOutcome = {
36
+ readonly status: "missing" | "pending" | "cancelled" | "expired" | "used";
37
+ } | {
38
+ readonly status: "approved";
39
+ readonly [VERIFIED_EXTERNAL_APPROVAL]: true;
40
+ };
41
+ /**
42
+ * An opt-in primitive, not an HTTP route or effect executor. Page adapters must
43
+ * supply the authenticated principal, enforce CSRF, and keep the capsule in a
44
+ * URL fragment or POST body, never a server-visible URL query or application log.
45
+ * Applications must recheck permissions/freshness and retain effect idempotency.
46
+ */
47
+ export declare function createExternalApprovalBroker(options: ExternalApprovalOptions): Readonly<{
48
+ prepare(value: ExternalApprovalProposal): Promise<{
49
+ capsule: string;
50
+ expiresAt: number;
51
+ }>;
52
+ review(token: string, principalId: string): Promise<{
53
+ principalId: string;
54
+ scopeId: string;
55
+ tool: string;
56
+ input: z.core.util.JSONType;
57
+ effect: z.core.util.JSONType;
58
+ formSchema: z.core.util.JSONType;
59
+ }>;
60
+ decide(token: string, principalId: string, decision: "approve" | "cancel"): Promise<{
61
+ readonly status: "approved" | "cancelled";
62
+ }>;
63
+ consume(value: ExternalApprovalProposal): Promise<ExternalApprovalOutcome>;
64
+ }>;
65
+ export {};
66
+ //# sourceMappingURL=external-approval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-approval.d.ts","sourceRoot":"","sources":["../src/external-approval.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,QAAA,MAAM,cAAc;;;;;;;kBAOlB,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtE,QAAA,MAAM,YAAY;;;;;;;;;kBAIhB,CAAC;AACH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC;AAE5E,mFAAmF;AACnF,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC;IAC1D,cAAc,CACZ,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,sBAAsB,GAAG,IAAI,EACvC,WAAW,EAAE,sBAAsB,GAClC,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED,OAAO,CAAC,MAAM,0BAA0B,EAAE,OAAO,MAAM,CAAC;AACxD,MAAM,MAAM,uBAAuB,GAC/B;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,CAAA;CAAE,GAC7E;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,CAAC,0BAA0B,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AA0BjF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,uBAAuB;mBAwFpD,wBAAwB;;;;kBAezB,MAAM,eAAe,MAAM;;;;;;;;kBAK3B,MAAM,eAAe,MAAM,YAAY,SAAS,GAAG,QAAQ;;;mBAS1D,wBAAwB,GAAG,OAAO,CAAC,uBAAuB,CAAC;GAanF"}
@@ -0,0 +1,215 @@
1
+ import { createCipheriv, createDecipheriv, createHmac, randomBytes } from "node:crypto";
2
+ import { z } from "zod";
3
+ const proposalSchema = z.strictObject({
4
+ principalId: z.string().min(1).max(512),
5
+ scopeId: z.string().min(1).max(512),
6
+ tool: z.string().min(1).max(128),
7
+ input: z.json(),
8
+ effect: z.json(),
9
+ formSchema: z.json(),
10
+ });
11
+ const recordSchema = z.strictObject({
12
+ capsuleDigest: z.string().regex(/^[a-f0-9]{64}$/),
13
+ expiresAt: z.number().int().positive(),
14
+ state: z.enum(["pending", "approved", "cancelled", "consumed"]),
15
+ });
16
+ const capsuleSchema = z.strictObject({
17
+ version: z.literal(1),
18
+ issuedAt: z.number().int().nonnegative(),
19
+ expiresAt: z.number().int().positive(),
20
+ nonce: z.string().regex(/^[a-f0-9]{32}$/),
21
+ proposal: proposalSchema,
22
+ });
23
+ const aad = Buffer.from("emseepea.external-approval.v1");
24
+ function invalid() {
25
+ throw new Error("External approval is unavailable or invalid");
26
+ }
27
+ function canonical(value, depth = 0) {
28
+ if (depth > 32)
29
+ invalid();
30
+ if (value === null || typeof value === "string" || typeof value === "boolean")
31
+ return JSON.stringify(value);
32
+ if (typeof value === "number" && Number.isFinite(value))
33
+ return JSON.stringify(value);
34
+ if (Array.isArray(value))
35
+ return `[${value.map((item) => canonical(item, depth + 1)).join(",")}]`;
36
+ if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype) {
37
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonical(value[key], depth + 1)}`).join(",")}}`;
38
+ }
39
+ return invalid();
40
+ }
41
+ /**
42
+ * An opt-in primitive, not an HTTP route or effect executor. Page adapters must
43
+ * supply the authenticated principal, enforce CSRF, and keep the capsule in a
44
+ * URL fragment or POST body, never a server-visible URL query or application log.
45
+ * Applications must recheck permissions/freshness and retain effect idempotency.
46
+ */
47
+ export function createExternalApprovalBroker(options) {
48
+ const { key: configuredKey, store, lifetimeMs, maxCapsuleBytes, now: configuredClock } = options;
49
+ if (!(configuredKey instanceof Uint8Array) || configuredKey.byteLength !== 32 ||
50
+ !Number.isSafeInteger(lifetimeMs) || lifetimeMs <= 0 || lifetimeMs > 3_600_000 ||
51
+ !Number.isSafeInteger(maxCapsuleBytes) || maxCapsuleBytes <= 0 || maxCapsuleBytes > 131_072 ||
52
+ (configuredClock !== undefined && typeof configuredClock !== "function") ||
53
+ typeof store?.load !== "function" || typeof store?.compareAndSwap !== "function") {
54
+ throw new TypeError("External approval requires a 32-byte key, atomic store and bounded lifetime/size");
55
+ }
56
+ const key = Buffer.from(configuredKey);
57
+ const now = configuredClock ?? Date.now;
58
+ const timestamp = () => {
59
+ const value = now();
60
+ if (!Number.isSafeInteger(value) || value < 0)
61
+ invalid();
62
+ return value;
63
+ };
64
+ const digest = (domain, value) => createHmac("sha256", key).update(`${domain}\0${value}`).digest("hex");
65
+ const checkedProposal = (value) => {
66
+ // Bound nesting before recursive JSON schema validation, and freeze the
67
+ // serialized proposal before any asynchronous store operation.
68
+ const encoded = canonical(value);
69
+ if (Buffer.byteLength(encoded) > maxCapsuleBytes)
70
+ invalid();
71
+ const result = proposalSchema.safeParse(JSON.parse(encoded));
72
+ if (!result.success)
73
+ invalid();
74
+ return result.data;
75
+ };
76
+ const recordFor = async (id) => {
77
+ let value;
78
+ try {
79
+ value = await store.load(id);
80
+ }
81
+ catch {
82
+ return invalid();
83
+ }
84
+ if (value === null)
85
+ return null;
86
+ const result = recordSchema.safeParse(value);
87
+ if (!result.success)
88
+ invalid();
89
+ return result.data;
90
+ };
91
+ const transition = async (id, expected, next) => {
92
+ try {
93
+ const success = await store.compareAndSwap(id, expected, next);
94
+ if (typeof success !== "boolean")
95
+ invalid();
96
+ return success;
97
+ }
98
+ catch {
99
+ return invalid();
100
+ }
101
+ };
102
+ const proposalId = (value) => digest("proposal", canonical(value));
103
+ const seal = (value) => {
104
+ const iv = randomBytes(12);
105
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
106
+ cipher.setAAD(aad);
107
+ const ciphertext = Buffer.concat([cipher.update(JSON.stringify(value), "utf8"), cipher.final()]);
108
+ const token = `1.${iv.toString("base64url")}.${ciphertext.toString("base64url")}.${cipher.getAuthTag().toString("base64url")}`;
109
+ if (Buffer.byteLength(token) > maxCapsuleBytes)
110
+ invalid();
111
+ return token;
112
+ };
113
+ const open = (token, principalId) => {
114
+ try {
115
+ if (typeof token !== "string" || Buffer.byteLength(token) > maxCapsuleBytes)
116
+ invalid();
117
+ const parts = token.split(".");
118
+ if (parts.length !== 4 || parts[0] !== "1")
119
+ invalid();
120
+ const decode = (value) => {
121
+ const bytes = Buffer.from(value, "base64url");
122
+ if (bytes.toString("base64url") !== value)
123
+ invalid();
124
+ return bytes;
125
+ };
126
+ const iv = decode(parts[1]);
127
+ const ciphertext = decode(parts[2]);
128
+ const tag = decode(parts[3]);
129
+ if (iv.byteLength !== 12 || tag.byteLength !== 16)
130
+ invalid();
131
+ const decipher = createDecipheriv("aes-256-gcm", key, iv);
132
+ decipher.setAAD(aad);
133
+ decipher.setAuthTag(tag);
134
+ const text = Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
135
+ const parsed = JSON.parse(text);
136
+ canonical(parsed);
137
+ const capsule = capsuleSchema.parse(parsed);
138
+ const at = timestamp();
139
+ if (capsule.proposal.principalId !== principalId || capsule.issuedAt > at ||
140
+ capsule.expiresAt <= at || capsule.expiresAt - capsule.issuedAt !== lifetimeMs)
141
+ invalid();
142
+ return capsule;
143
+ }
144
+ catch {
145
+ return invalid();
146
+ }
147
+ };
148
+ const current = async (token, principalId) => {
149
+ const capsule = open(token, principalId);
150
+ const id = proposalId(capsule.proposal);
151
+ const record = await recordFor(id);
152
+ if (!record || record.capsuleDigest !== digest("capsule", token) ||
153
+ record.expiresAt !== capsule.expiresAt || record.expiresAt <= timestamp())
154
+ invalid();
155
+ return { capsule, id, record };
156
+ };
157
+ return Object.freeze({
158
+ async prepare(value) {
159
+ const proposal = checkedProposal(value);
160
+ const id = proposalId(proposal);
161
+ const expected = await recordFor(id);
162
+ const at = timestamp();
163
+ // An active request (including cancellation/consumption) is terminal for
164
+ // this proposal. Restart explicitly after expiry; never silently renew it.
165
+ if (expected && expected.expiresAt > at)
166
+ invalid();
167
+ const expiresAt = at + lifetimeMs;
168
+ if (!Number.isSafeInteger(expiresAt))
169
+ invalid();
170
+ const capsule = seal({ version: 1, issuedAt: at, expiresAt, nonce: randomBytes(16).toString("hex"), proposal });
171
+ const record = { capsuleDigest: digest("capsule", capsule), expiresAt, state: "pending" };
172
+ if (!await transition(id, expected, record))
173
+ invalid();
174
+ return { capsule, expiresAt };
175
+ },
176
+ async review(token, principalId) {
177
+ const { capsule, record } = await current(token, principalId);
178
+ if (record.state !== "pending")
179
+ invalid();
180
+ return capsule.proposal;
181
+ },
182
+ async decide(token, principalId, decision) {
183
+ if (decision !== "approve" && decision !== "cancel")
184
+ invalid();
185
+ const { id, record } = await current(token, principalId);
186
+ if (record.state !== "pending")
187
+ invalid();
188
+ const state = decision === "approve" ? "approved" : "cancelled";
189
+ if (!await transition(id, record, { ...record, state }))
190
+ invalid();
191
+ if (record.expiresAt <= timestamp())
192
+ invalid();
193
+ return { status: state };
194
+ },
195
+ async consume(value) {
196
+ const proposal = checkedProposal(value);
197
+ const id = proposalId(proposal);
198
+ const record = await recordFor(id);
199
+ if (!record)
200
+ return { status: "missing" };
201
+ if (record.expiresAt <= timestamp())
202
+ return { status: "expired" };
203
+ if (record.state === "pending" || record.state === "cancelled")
204
+ return { status: record.state };
205
+ if (record.state === "consumed")
206
+ return { status: "used" };
207
+ if (!await transition(id, record, { ...record, state: "consumed" }))
208
+ return { status: "used" };
209
+ if (record.expiresAt <= timestamp())
210
+ return { status: "expired" };
211
+ return { status: "approved" };
212
+ },
213
+ });
214
+ }
215
+ //# sourceMappingURL=external-approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-approval.js","sourceRoot":"","sources":["../src/external-approval.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emseepea/server",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "Fastify-first framework for Model Context Protocol 2026-07-28 servers over Streamable HTTP",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -27,6 +27,10 @@
27
27
  "./http": {
28
28
  "types": "./dist/http.d.ts",
29
29
  "import": "./dist/http.js"
30
+ },
31
+ "./external-approval": {
32
+ "types": "./dist/external-approval.d.ts",
33
+ "import": "./dist/external-approval.js"
30
34
  }
31
35
  },
32
36
  "files": [
@@ -44,7 +48,7 @@
44
48
  "@modelcontextprotocol/fastify": "2.0.0",
45
49
  "@modelcontextprotocol/node": "2.0.0",
46
50
  "@modelcontextprotocol/server": "2.0.0",
47
- "fastify": "5.12.1",
51
+ "fastify": "5.12.5",
48
52
  "zod": "4.4.3"
49
53
  },
50
54
  "engines": {