@revealui/mcp 0.1.11 → 0.2.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/LICENSE.commercial +90 -0
- package/README.md +5 -13
- package/dist/adapters/db.d.ts +16 -7
- package/dist/adapters/db.d.ts.map +1 -1
- package/dist/adapters/db.js +6 -24
- package/dist/adapters/db.js.map +1 -1
- package/dist/client.d.ts +307 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +492 -0
- package/dist/client.js.map +1 -0
- package/dist/hypervisor.d.ts +18 -0
- package/dist/hypervisor.d.ts.map +1 -1
- package/dist/hypervisor.js +83 -4
- package/dist/hypervisor.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/metering.d.ts +59 -0
- package/dist/metering.d.ts.map +1 -0
- package/dist/metering.js +25 -0
- package/dist/metering.js.map +1 -0
- package/dist/oauth.d.ts +171 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +292 -0
- package/dist/oauth.js.map +1 -0
- package/dist/remote-client.d.ts +86 -0
- package/dist/remote-client.d.ts.map +1 -0
- package/dist/remote-client.js +130 -0
- package/dist/remote-client.js.map +1 -0
- package/dist/servers/adapter.d.ts.map +1 -1
- package/dist/servers/adapter.js +4 -0
- package/dist/servers/adapter.js.map +1 -1
- package/dist/servers/factories/revealui-content.d.ts +85 -0
- package/dist/servers/factories/revealui-content.d.ts.map +1 -0
- package/dist/servers/factories/revealui-content.js +471 -0
- package/dist/servers/factories/revealui-content.js.map +1 -0
- package/dist/servers/revealui-content.d.ts +12 -18
- package/dist/servers/revealui-content.d.ts.map +1 -1
- package/dist/servers/revealui-content.js +14 -220
- package/dist/servers/revealui-content.js.map +1 -1
- package/dist/servers/revealui-memory.d.ts +24 -0
- package/dist/servers/revealui-memory.d.ts.map +1 -0
- package/dist/servers/revealui-memory.js +339 -0
- package/dist/servers/revealui-memory.js.map +1 -0
- package/dist/streamable-http.d.ts +72 -0
- package/dist/streamable-http.d.ts.map +1 -0
- package/dist/streamable-http.js +120 -0
- package/dist/streamable-http.js.map +1 -0
- package/package.json +21 -8
- package/dist/stores/postgres-idempotency.d.ts +0 -32
- package/dist/stores/postgres-idempotency.d.ts.map +0 -1
- package/dist/stores/postgres-idempotency.js +0 -63
- package/dist/stores/postgres-idempotency.js.map +0 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streamable HTTP server helper for `@revealui/mcp` (Stage 1 PR-1.1).
|
|
3
|
+
*
|
|
4
|
+
* Wraps `@modelcontextprotocol/sdk`'s `StreamableHTTPServerTransport` with
|
|
5
|
+
* session routing: one `MCP Server` + transport pair per concurrent client,
|
|
6
|
+
* identified by the `Mcp-Session-Id` header. Initialize requests without a
|
|
7
|
+
* session header allocate a new server via `createServer()`; subsequent
|
|
8
|
+
* requests route to the matching session.
|
|
9
|
+
*
|
|
10
|
+
* Returns a Node `(req, res) => Promise<void>` handler suitable for use with
|
|
11
|
+
* `http.createServer`, Express, Fastify, or any framework that exposes the
|
|
12
|
+
* raw Node request/response pair. A Web-Standard (Request → Response)
|
|
13
|
+
* variant can layer on top later — the session-routing logic is independent
|
|
14
|
+
* of the concrete transport flavour.
|
|
15
|
+
*
|
|
16
|
+
* The SDK's `StreamableHTTPServerTransport` is a one-session-per-instance
|
|
17
|
+
* primitive (see the `this.sessionId` field in its implementation). That's
|
|
18
|
+
* why we maintain an external `Map<sessionId, { server, transport }>` and
|
|
19
|
+
* not rely on a single transport to multiplex.
|
|
20
|
+
*/
|
|
21
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
22
|
+
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
23
|
+
export type StreamableHttpHandlerOptions = {
|
|
24
|
+
/**
|
|
25
|
+
* Called once per new session — returns a fresh `Server` instance to
|
|
26
|
+
* connect to the session's transport. Keep this function pure; do not
|
|
27
|
+
* share Server instances across sessions.
|
|
28
|
+
*/
|
|
29
|
+
createServer: () => Server | Promise<Server>;
|
|
30
|
+
/** Generate session IDs. Default: `crypto.randomUUID()`. */
|
|
31
|
+
sessionIdGenerator?: () => string;
|
|
32
|
+
/** Called when a new session is initialized. */
|
|
33
|
+
onSessionInitialized?: (sessionId: string) => void | Promise<void>;
|
|
34
|
+
/** Called when a session is terminated (DELETE or transport close). */
|
|
35
|
+
onSessionClosed?: (sessionId: string) => void | Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Allowed `Origin` headers for DNS rebinding protection. If set, requests
|
|
38
|
+
* with other origins are rejected. Mirrors the SDK's option.
|
|
39
|
+
*/
|
|
40
|
+
allowedOrigins?: string[];
|
|
41
|
+
/**
|
|
42
|
+
* Allowed `Host` headers for DNS rebinding protection. If set, requests
|
|
43
|
+
* with other hosts are rejected.
|
|
44
|
+
*/
|
|
45
|
+
allowedHosts?: string[];
|
|
46
|
+
/**
|
|
47
|
+
* If true, responses are raw JSON instead of SSE streams. Useful for
|
|
48
|
+
* deployments that can't hold open long-lived connections (many
|
|
49
|
+
* serverless request/response platforms). Default: false.
|
|
50
|
+
*/
|
|
51
|
+
enableJsonResponse?: boolean;
|
|
52
|
+
};
|
|
53
|
+
export type StreamableHttpHandler = (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Build a Node HTTP request handler that routes MCP Streamable HTTP traffic
|
|
56
|
+
* to per-session `Server` + `Transport` pairs, allocating new sessions on
|
|
57
|
+
* InitializeRequest and reusing them on follow-up requests via the
|
|
58
|
+
* `Mcp-Session-Id` header.
|
|
59
|
+
*
|
|
60
|
+
* ```ts
|
|
61
|
+
* import { createServer as createHttpServer } from 'node:http';
|
|
62
|
+
* import { createNodeStreamableHttpHandler } from '@revealui/mcp/streamable-http';
|
|
63
|
+
*
|
|
64
|
+
* const mcpHandler = createNodeStreamableHttpHandler({
|
|
65
|
+
* createServer: () => makeMyMcpServer(),
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* createHttpServer(mcpHandler).listen(3000);
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function createNodeStreamableHttpHandler(options: StreamableHttpHandlerOptions): StreamableHttpHandler;
|
|
72
|
+
//# sourceMappingURL=streamable-http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamable-http.d.ts","sourceRoot":"","sources":["../src/streamable-http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAWxE,MAAM,MAAM,4BAA4B,GAAG;IACzC;;;;OAIG;IACH,YAAY,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7C,4DAA4D;IAC5D,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;IAElC,gDAAgD;IAChD,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnE,uEAAuE;IACvE,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9D;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAWjG;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,4BAA4B,GACpC,qBAAqB,CAqDvB"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streamable HTTP server helper for `@revealui/mcp` (Stage 1 PR-1.1).
|
|
3
|
+
*
|
|
4
|
+
* Wraps `@modelcontextprotocol/sdk`'s `StreamableHTTPServerTransport` with
|
|
5
|
+
* session routing: one `MCP Server` + transport pair per concurrent client,
|
|
6
|
+
* identified by the `Mcp-Session-Id` header. Initialize requests without a
|
|
7
|
+
* session header allocate a new server via `createServer()`; subsequent
|
|
8
|
+
* requests route to the matching session.
|
|
9
|
+
*
|
|
10
|
+
* Returns a Node `(req, res) => Promise<void>` handler suitable for use with
|
|
11
|
+
* `http.createServer`, Express, Fastify, or any framework that exposes the
|
|
12
|
+
* raw Node request/response pair. A Web-Standard (Request → Response)
|
|
13
|
+
* variant can layer on top later — the session-routing logic is independent
|
|
14
|
+
* of the concrete transport flavour.
|
|
15
|
+
*
|
|
16
|
+
* The SDK's `StreamableHTTPServerTransport` is a one-session-per-instance
|
|
17
|
+
* primitive (see the `this.sessionId` field in its implementation). That's
|
|
18
|
+
* why we maintain an external `Map<sessionId, { server, transport }>` and
|
|
19
|
+
* not rely on a single transport to multiplex.
|
|
20
|
+
*/
|
|
21
|
+
import { randomUUID } from 'node:crypto';
|
|
22
|
+
import { StreamableHTTPServerTransport, } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
23
|
+
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Handler factory
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
/**
|
|
28
|
+
* Build a Node HTTP request handler that routes MCP Streamable HTTP traffic
|
|
29
|
+
* to per-session `Server` + `Transport` pairs, allocating new sessions on
|
|
30
|
+
* InitializeRequest and reusing them on follow-up requests via the
|
|
31
|
+
* `Mcp-Session-Id` header.
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { createServer as createHttpServer } from 'node:http';
|
|
35
|
+
* import { createNodeStreamableHttpHandler } from '@revealui/mcp/streamable-http';
|
|
36
|
+
*
|
|
37
|
+
* const mcpHandler = createNodeStreamableHttpHandler({
|
|
38
|
+
* createServer: () => makeMyMcpServer(),
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* createHttpServer(mcpHandler).listen(3000);
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function createNodeStreamableHttpHandler(options) {
|
|
45
|
+
const sessions = new Map();
|
|
46
|
+
const generateSessionId = options.sessionIdGenerator ?? (() => randomUUID());
|
|
47
|
+
return async function mcpStreamableHttpHandler(req, res) {
|
|
48
|
+
const body = req.method === 'POST' ? await readJsonBody(req) : undefined;
|
|
49
|
+
const rawSession = req.headers['mcp-session-id'];
|
|
50
|
+
const sessionId = typeof rawSession === 'string' ? rawSession : undefined;
|
|
51
|
+
// Existing session — delegate to its transport.
|
|
52
|
+
if (sessionId) {
|
|
53
|
+
const entry = sessions.get(sessionId);
|
|
54
|
+
if (entry) {
|
|
55
|
+
await entry.transport.handleRequest(req, res, body);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Known-bad session header — let the transport produce the 404.
|
|
59
|
+
// Fall through to fresh-session handling, which will reject
|
|
60
|
+
// non-init requests.
|
|
61
|
+
}
|
|
62
|
+
// No session header: only an Initialize request may start a new session.
|
|
63
|
+
if (!sessionId && req.method === 'POST' && isInitializeRequest(body)) {
|
|
64
|
+
await handleNewSession(body);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
sendJsonError(res, 400, sessionId ? 'Unknown session ID' : 'Session ID required');
|
|
68
|
+
return;
|
|
69
|
+
async function handleNewSession(parsedBody) {
|
|
70
|
+
const server = await options.createServer();
|
|
71
|
+
const transportOptions = {
|
|
72
|
+
sessionIdGenerator: generateSessionId,
|
|
73
|
+
enableJsonResponse: options.enableJsonResponse,
|
|
74
|
+
allowedHosts: options.allowedHosts,
|
|
75
|
+
allowedOrigins: options.allowedOrigins,
|
|
76
|
+
onsessioninitialized: async (id) => {
|
|
77
|
+
sessions.set(id, { server, transport });
|
|
78
|
+
await options.onSessionInitialized?.(id);
|
|
79
|
+
},
|
|
80
|
+
onsessionclosed: async (id) => {
|
|
81
|
+
sessions.delete(id);
|
|
82
|
+
await options.onSessionClosed?.(id);
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
const transport = new StreamableHTTPServerTransport(transportOptions);
|
|
86
|
+
await server.connect(transport);
|
|
87
|
+
await transport.handleRequest(req, res, parsedBody);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Helpers
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
async function readJsonBody(req) {
|
|
95
|
+
const chunks = [];
|
|
96
|
+
for await (const chunk of req) {
|
|
97
|
+
chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
|
|
98
|
+
}
|
|
99
|
+
if (chunks.length === 0)
|
|
100
|
+
return undefined;
|
|
101
|
+
const raw = Buffer.concat(chunks).toString('utf8');
|
|
102
|
+
if (!raw)
|
|
103
|
+
return undefined;
|
|
104
|
+
try {
|
|
105
|
+
return JSON.parse(raw);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function sendJsonError(res, status, message) {
|
|
112
|
+
res.statusCode = status;
|
|
113
|
+
res.setHeader('content-type', 'application/json');
|
|
114
|
+
res.end(JSON.stringify({
|
|
115
|
+
jsonrpc: '2.0',
|
|
116
|
+
error: { code: -32000, message },
|
|
117
|
+
id: null,
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=streamable-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamable-http.js","sourceRoot":"","sources":["../src/streamable-http.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revealui/mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Model Context Protocol
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Model Context Protocol framework — MCP server hypervisor, adapter pattern, tool discovery, and adapters for Stripe, Supabase, and Vercel.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/RevealUIStudio/revealui.git",
|
|
@@ -14,13 +14,14 @@
|
|
|
14
14
|
"jose": "^6.2.2",
|
|
15
15
|
"@revealui/config": "0.4.0",
|
|
16
16
|
"@revealui/contracts": "1.4.0",
|
|
17
|
-
"@revealui/core": "0.6.0"
|
|
17
|
+
"@revealui/core": "0.6.0",
|
|
18
|
+
"@revealui/security": "0.3.0"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
21
|
"@electric-sql/pglite": "^0.4.4",
|
|
21
22
|
"pg": "^8.20.0",
|
|
22
|
-
"typescript": "^6.0.
|
|
23
|
-
"vitest": "^4.1.
|
|
23
|
+
"typescript": "^6.0.3",
|
|
24
|
+
"vitest": "^4.1.5"
|
|
24
25
|
},
|
|
25
26
|
"engines": {
|
|
26
27
|
"node": ">=24.13.0"
|
|
@@ -66,9 +67,21 @@
|
|
|
66
67
|
"types": "./dist/auth.d.ts",
|
|
67
68
|
"import": "./dist/auth.js"
|
|
68
69
|
},
|
|
69
|
-
"./
|
|
70
|
-
"types": "./dist/
|
|
71
|
-
"import": "./dist/
|
|
70
|
+
"./streamable-http": {
|
|
71
|
+
"types": "./dist/streamable-http.d.ts",
|
|
72
|
+
"import": "./dist/streamable-http.js"
|
|
73
|
+
},
|
|
74
|
+
"./oauth": {
|
|
75
|
+
"types": "./dist/oauth.d.ts",
|
|
76
|
+
"import": "./dist/oauth.js"
|
|
77
|
+
},
|
|
78
|
+
"./client": {
|
|
79
|
+
"types": "./dist/client.d.ts",
|
|
80
|
+
"import": "./dist/client.js"
|
|
81
|
+
},
|
|
82
|
+
"./remote-client": {
|
|
83
|
+
"types": "./dist/remote-client.d.ts",
|
|
84
|
+
"import": "./dist/remote-client.js"
|
|
72
85
|
}
|
|
73
86
|
},
|
|
74
87
|
"files": [
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Postgres-backed Idempotency Store
|
|
3
|
-
*
|
|
4
|
-
* Persistent implementation of the {@link IdempotencyStore} interface
|
|
5
|
-
* using a PostgreSQL table. Stores MCP responses keyed by idempotency
|
|
6
|
-
* key with automatic TTL expiration via a `expires_at` column.
|
|
7
|
-
*
|
|
8
|
-
* Table schema (auto-created on first use):
|
|
9
|
-
* mcp_idempotency_cache (
|
|
10
|
-
* key TEXT PRIMARY KEY,
|
|
11
|
-
* response JSONB NOT NULL,
|
|
12
|
-
* expires_at TIMESTAMPTZ NOT NULL
|
|
13
|
-
* )
|
|
14
|
-
*/
|
|
15
|
-
import type { IdempotencyStore } from '../servers/adapter.js';
|
|
16
|
-
interface PgClient {
|
|
17
|
-
query(text: string, values?: unknown[]): Promise<{
|
|
18
|
-
rows: Record<string, unknown>[];
|
|
19
|
-
}>;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Create a Postgres-backed idempotency store.
|
|
23
|
-
*
|
|
24
|
-
* @param client - Any object with a `.query(text, values?)` method
|
|
25
|
-
* (e.g. `pg.Pool`, `pg.Client`, `@neondatabase/serverless` pool).
|
|
26
|
-
* @param opts - Optional configuration
|
|
27
|
-
*/
|
|
28
|
-
export declare function createPostgresIdempotencyStore(client: PgClient, opts?: {
|
|
29
|
-
ensureTable?: boolean;
|
|
30
|
-
}): IdempotencyStore;
|
|
31
|
-
export {};
|
|
32
|
-
//# sourceMappingURL=postgres-idempotency.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-idempotency.d.ts","sourceRoot":"","sources":["../../src/stores/postgres-idempotency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAe,MAAM,uBAAuB,CAAC;AAE3E,UAAU,QAAQ;IAChB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;KAAE,CAAC,CAAC;CACvF;AAYD;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,QAAQ,EAChB,IAAI,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GAC/B,gBAAgB,CAwClB"}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Postgres-backed Idempotency Store
|
|
3
|
-
*
|
|
4
|
-
* Persistent implementation of the {@link IdempotencyStore} interface
|
|
5
|
-
* using a PostgreSQL table. Stores MCP responses keyed by idempotency
|
|
6
|
-
* key with automatic TTL expiration via a `expires_at` column.
|
|
7
|
-
*
|
|
8
|
-
* Table schema (auto-created on first use):
|
|
9
|
-
* mcp_idempotency_cache (
|
|
10
|
-
* key TEXT PRIMARY KEY,
|
|
11
|
-
* response JSONB NOT NULL,
|
|
12
|
-
* expires_at TIMESTAMPTZ NOT NULL
|
|
13
|
-
* )
|
|
14
|
-
*/
|
|
15
|
-
const TABLE = 'mcp_idempotency_cache';
|
|
16
|
-
const CREATE_TABLE_SQL = `
|
|
17
|
-
CREATE TABLE IF NOT EXISTS ${TABLE} (
|
|
18
|
-
key TEXT PRIMARY KEY,
|
|
19
|
-
response JSONB NOT NULL,
|
|
20
|
-
expires_at TIMESTAMPTZ NOT NULL
|
|
21
|
-
);
|
|
22
|
-
`;
|
|
23
|
-
/**
|
|
24
|
-
* Create a Postgres-backed idempotency store.
|
|
25
|
-
*
|
|
26
|
-
* @param client - Any object with a `.query(text, values?)` method
|
|
27
|
-
* (e.g. `pg.Pool`, `pg.Client`, `@neondatabase/serverless` pool).
|
|
28
|
-
* @param opts - Optional configuration
|
|
29
|
-
*/
|
|
30
|
-
export function createPostgresIdempotencyStore(client, opts) {
|
|
31
|
-
let tableEnsured = opts?.ensureTable === false;
|
|
32
|
-
async function ensureTable() {
|
|
33
|
-
if (tableEnsured)
|
|
34
|
-
return;
|
|
35
|
-
await client.query(CREATE_TABLE_SQL);
|
|
36
|
-
tableEnsured = true;
|
|
37
|
-
}
|
|
38
|
-
return {
|
|
39
|
-
async get(key) {
|
|
40
|
-
await ensureTable();
|
|
41
|
-
const { rows } = await client.query(`SELECT response, expires_at FROM ${TABLE} WHERE key = $1 AND expires_at > NOW()`, [key]);
|
|
42
|
-
const row = rows[0];
|
|
43
|
-
if (!row)
|
|
44
|
-
return null;
|
|
45
|
-
return {
|
|
46
|
-
response: row.response,
|
|
47
|
-
expiresAt: new Date(row.expires_at).getTime(),
|
|
48
|
-
};
|
|
49
|
-
},
|
|
50
|
-
async set(key, response, ttlMs) {
|
|
51
|
-
await ensureTable();
|
|
52
|
-
const expiresAt = new Date(Date.now() + ttlMs).toISOString();
|
|
53
|
-
await client.query(`INSERT INTO ${TABLE} (key, response, expires_at)
|
|
54
|
-
VALUES ($1, $2, $3)
|
|
55
|
-
ON CONFLICT (key) DO UPDATE SET response = $2, expires_at = $3`, [key, JSON.stringify(response), expiresAt]);
|
|
56
|
-
},
|
|
57
|
-
async delete(key) {
|
|
58
|
-
await ensureTable();
|
|
59
|
-
await client.query(`DELETE FROM ${TABLE} WHERE key = $1`, [key]);
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
//# sourceMappingURL=postgres-idempotency.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-idempotency.js","sourceRoot":"","sources":["../../src/stores/postgres-idempotency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH,MAAM,KAAK,GAAG,uBAAuB,CAAC;AAEtC,MAAM,gBAAgB,GAAG;+BACM,KAAK;;;;;CAKnC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,8BAA8B,CAC5C,MAAgB,EAChB,IAAgC;IAEhC,IAAI,YAAY,GAAG,IAAI,EAAE,WAAW,KAAK,KAAK,CAAC;IAE/C,KAAK,UAAU,WAAW;QACxB,IAAI,YAAY;YAAE,OAAO;QACzB,MAAM,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACrC,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,OAAO;QACL,KAAK,CAAC,GAAG,CAAC,GAAW;YACnB,MAAM,WAAW,EAAE,CAAC;YACpB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CACjC,oCAAoC,KAAK,wCAAwC,EACjF,CAAC,GAAG,CAAC,CACN,CAAC;YACF,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAC;YACtB,OAAO;gBACL,QAAQ,EAAE,GAAG,CAAC,QAAuB;gBACrC,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,UAAoB,CAAC,CAAC,OAAO,EAAE;aACxD,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,QAAqB,EAAE,KAAa;YACzD,MAAM,WAAW,EAAE,CAAC;YACpB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;YAC7D,MAAM,MAAM,CAAC,KAAK,CAChB,eAAe,KAAK;;wEAE4C,EAChE,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,CAC3C,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,GAAW;YACtB,MAAM,WAAW,EAAE,CAAC;YACpB,MAAM,MAAM,CAAC,KAAK,CAAC,eAAe,KAAK,iBAAiB,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACnE,CAAC;KACF,CAAC;AACJ,CAAC"}
|