@agentcash/telemetry 0.3.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/README.md +128 -0
- package/dist/builder.d.mts +58 -0
- package/dist/builder.d.ts +58 -0
- package/dist/builder.js +218 -0
- package/dist/builder.js.map +1 -0
- package/dist/builder.mjs +218 -0
- package/dist/builder.mjs.map +1 -0
- package/dist/chunk-FJ3YM6KO.js +55 -0
- package/dist/chunk-FJ3YM6KO.js.map +1 -0
- package/dist/chunk-GE7VBMQP.js +149 -0
- package/dist/chunk-GE7VBMQP.js.map +1 -0
- package/dist/chunk-JVLKV7CX.mjs +55 -0
- package/dist/chunk-JVLKV7CX.mjs.map +1 -0
- package/dist/chunk-O2PCP6KV.mjs +60 -0
- package/dist/chunk-O2PCP6KV.mjs.map +1 -0
- package/dist/chunk-P63MLKU3.js +60 -0
- package/dist/chunk-P63MLKU3.js.map +1 -0
- package/dist/chunk-VOY67KA4.mjs +149 -0
- package/dist/chunk-VOY67KA4.mjs.map +1 -0
- package/dist/index.d.mts +59 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +14 -0
- package/dist/index.mjs.map +1 -0
- package/dist/router-plugin.d.mts +109 -0
- package/dist/router-plugin.d.ts +109 -0
- package/dist/router-plugin.js +99 -0
- package/dist/router-plugin.js.map +1 -0
- package/dist/router-plugin.mjs +99 -0
- package/dist/router-plugin.mjs.map +1 -0
- package/dist/siwx.d.mts +29 -0
- package/dist/siwx.d.ts +29 -0
- package/dist/siwx.js +99 -0
- package/dist/siwx.js.map +1 -0
- package/dist/siwx.mjs +99 -0
- package/dist/siwx.mjs.map +1 -0
- package/dist/types-Bl8IwXin.d.mts +57 -0
- package/dist/types-Bl8IwXin.d.ts +57 -0
- package/package.json +88 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
var _chunkP63MLKU3js = require('./chunk-P63MLKU3.js');
|
|
6
|
+
|
|
7
|
+
// src/router-plugin.ts
|
|
8
|
+
function createTelemetryPlugin(config) {
|
|
9
|
+
_chunkP63MLKU3js.initClickhouse.call(void 0, config.clickhouse);
|
|
10
|
+
if (config.verify) {
|
|
11
|
+
_chunkP63MLKU3js.pingClickhouse.call(void 0, );
|
|
12
|
+
}
|
|
13
|
+
const log = _nullishCoalesce(config.console, () => ( false));
|
|
14
|
+
return {
|
|
15
|
+
onRequest(meta) {
|
|
16
|
+
const ctx = {
|
|
17
|
+
requestId: meta.requestId,
|
|
18
|
+
route: meta.route,
|
|
19
|
+
walletAddress: meta.walletAddress,
|
|
20
|
+
clientId: meta.clientId,
|
|
21
|
+
sessionId: meta.sessionId,
|
|
22
|
+
verifiedWallet: null,
|
|
23
|
+
setVerifiedWallet(address) {
|
|
24
|
+
ctx.verifiedWallet = address;
|
|
25
|
+
},
|
|
26
|
+
_meta: meta
|
|
27
|
+
};
|
|
28
|
+
return ctx;
|
|
29
|
+
},
|
|
30
|
+
onPaymentVerified(ctx, payment) {
|
|
31
|
+
ctx._payment = payment;
|
|
32
|
+
if (log) {
|
|
33
|
+
console.log(`[telemetry] VERIFIED ${payment.protocol} ${payment.payer} ${payment.amount}`);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
onPaymentSettled(ctx, settlement) {
|
|
37
|
+
ctx._settlement = settlement;
|
|
38
|
+
if (log) {
|
|
39
|
+
console.log(`[telemetry] SETTLED ${settlement.protocol} tx=${settlement.transaction}`);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
onResponse(ctx, response) {
|
|
43
|
+
const tCtx = ctx;
|
|
44
|
+
const meta = tCtx._meta;
|
|
45
|
+
if (log) {
|
|
46
|
+
const wallet = ctx.verifiedWallet ? ` wallet=${ctx.verifiedWallet}` : "";
|
|
47
|
+
console.log(
|
|
48
|
+
`[telemetry] ${meta.route} \u2192 ${response.statusCode} (${response.duration}ms)${wallet}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
const row = {
|
|
52
|
+
id: meta.requestId,
|
|
53
|
+
x_wallet_address: _nullishCoalesce(_optionalChain([meta, 'access', _ => _.walletAddress, 'optionalAccess', _2 => _2.toLowerCase, 'call', _3 => _3()]), () => ( null)),
|
|
54
|
+
x_client_id: meta.clientId,
|
|
55
|
+
session_id: meta.sessionId,
|
|
56
|
+
verified_wallet_address: _nullishCoalesce(_optionalChain([ctx, 'access', _4 => _4.verifiedWallet, 'optionalAccess', _5 => _5.toLowerCase, 'call', _6 => _6()]), () => ( null)),
|
|
57
|
+
method: meta.method,
|
|
58
|
+
route: meta.route,
|
|
59
|
+
origin: meta.origin,
|
|
60
|
+
referer: meta.referer,
|
|
61
|
+
request_content_type: meta.contentType,
|
|
62
|
+
request_headers: JSON.stringify(meta.headers),
|
|
63
|
+
request_body: null,
|
|
64
|
+
status_code: response.statusCode,
|
|
65
|
+
status_text: response.statusText,
|
|
66
|
+
duration: response.duration,
|
|
67
|
+
response_content_type: response.contentType,
|
|
68
|
+
response_headers: JSON.stringify(response.headers),
|
|
69
|
+
response_body: null,
|
|
70
|
+
created_at: /* @__PURE__ */ new Date()
|
|
71
|
+
};
|
|
72
|
+
_chunkP63MLKU3js.insertInvocation.call(void 0, row);
|
|
73
|
+
},
|
|
74
|
+
onError(ctx, error) {
|
|
75
|
+
if (log) {
|
|
76
|
+
console.error(`[telemetry] ERROR ${error.status}: ${error.message}`);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
onAlert(ctx, alert) {
|
|
80
|
+
if (log) {
|
|
81
|
+
const logFn = alert.level === "critical" || alert.level === "error" ? console.error : alert.level === "warn" ? console.warn : console.log;
|
|
82
|
+
logFn(
|
|
83
|
+
`[telemetry] ${alert.level.toUpperCase()} ${alert.route}: ${alert.message}`,
|
|
84
|
+
_nullishCoalesce(alert.meta, () => ( ""))
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
onProviderQuota(ctx, event) {
|
|
89
|
+
if (log) {
|
|
90
|
+
const logFn = event.level === "critical" ? console.error : event.level === "warn" ? console.warn : console.log;
|
|
91
|
+
logFn(`[telemetry] QUOTA ${event.level.toUpperCase()} ${event.provider}: ${event.message}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
exports.createTelemetryPlugin = createTelemetryPlugin;
|
|
99
|
+
//# sourceMappingURL=router-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/samragsdale/Documents/Code/merit-systems/agentcash-telemetry/dist/router-plugin.js","../src/router-plugin.ts"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACF,sDAA4B;AAC5B;AACA;ACmIO,SAAS,qBAAA,CAAsB,MAAA,EAA6C;AAEjF,EAAA,6CAAA,MAAe,CAAO,UAAU,CAAA;AAChC,EAAA,GAAA,CAAI,MAAA,CAAO,MAAA,EAAQ;AACjB,IAAA,6CAAA,CAAe;AAAA,EACjB;AAEA,EAAA,MAAM,IAAA,mBAAM,MAAA,CAAO,OAAA,UAAW,OAAA;AAE9B,EAAA,OAAO;AAAA,IACL,SAAA,CAAU,IAAA,EAAkC;AAC1C,MAAA,MAAM,IAAA,EAA8B;AAAA,QAClC,SAAA,EAAW,IAAA,CAAK,SAAA;AAAA,QAChB,KAAA,EAAO,IAAA,CAAK,KAAA;AAAA,QACZ,aAAA,EAAe,IAAA,CAAK,aAAA;AAAA,QACpB,QAAA,EAAU,IAAA,CAAK,QAAA;AAAA,QACf,SAAA,EAAW,IAAA,CAAK,SAAA;AAAA,QAChB,cAAA,EAAgB,IAAA;AAAA,QAChB,iBAAA,CAAkB,OAAA,EAAiB;AACjC,UAAA,GAAA,CAAI,eAAA,EAAiB,OAAA;AAAA,QACvB,CAAA;AAAA,QACA,KAAA,EAAO;AAAA,MACT,CAAA;AACA,MAAA,OAAO,GAAA;AAAA,IACT,CAAA;AAAA,IAEA,iBAAA,CAAkB,GAAA,EAAoB,OAAA,EAAuB;AAC3D,MAAC,GAAA,CAA+B,SAAA,EAAW,OAAA;AAC3C,MAAA,GAAA,CAAI,GAAA,EAAK;AACP,QAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,qBAAA,EAAwB,OAAA,CAAQ,QAAQ,CAAA,CAAA,EAAI,OAAA,CAAQ,KAAK,CAAA,CAAA,EAAI,OAAA,CAAQ,MAAM,CAAA,CAAA;AACzF,MAAA;AACF,IAAA;AAEkE,IAAA;AAClB,MAAA;AACrC,MAAA;AAC8E,QAAA;AACvF,MAAA;AACF,IAAA;AAEuD,IAAA;AACxC,MAAA;AACK,MAAA;AAET,MAAA;AAC+D,QAAA;AAC9D,QAAA;AACwE,UAAA;AAChF,QAAA;AACF,MAAA;AAEmC,MAAA;AACxB,QAAA;AAC8C,QAAA;AACrC,QAAA;AACD,QAAA;AAC6C,QAAA;AAEjD,QAAA;AACD,QAAA;AACC,QAAA;AACC,QAAA;AACa,QAAA;AACiB,QAAA;AAC9B,QAAA;AAEQ,QAAA;AACA,QAAA;AACH,QAAA;AACa,QAAA;AACiB,QAAA;AAClC,QAAA;AAEM,QAAA;AACvB,MAAA;AAEoB,MAAA;AACtB,IAAA;AAE+C,IAAA;AACpC,MAAA;AAC4D,QAAA;AACrE,MAAA;AACF,IAAA;AAE+C,IAAA;AACpC,MAAA;AAID,QAAA;AAGN,QAAA;AAC2E,UAAA;AAC3D,2BAAA;AAChB,QAAA;AACF,MAAA;AACF,IAAA;AAE+D,IAAA;AACpD,MAAA;AAKC,QAAA;AAEgF,QAAA;AAC1F,MAAA;AACF,IAAA;AACF,EAAA;AACF;AD1JgG;AACA;AACA","file":"/Users/samragsdale/Documents/Code/merit-systems/agentcash-telemetry/dist/router-plugin.js","sourcesContent":[null,"/**\n * RouterPlugin adapter for @agentcash/router.\n *\n * Bridges the router's plugin hooks into ClickHouse telemetry.\n * Uses the same mcp_resource_invocations table as the legacy withTelemetry wrapper.\n *\n * Usage:\n * import { createRouter } from '@agentcash/router';\n * import { createTelemetryPlugin } from '@agentcash/telemetry/plugin';\n *\n * const router = createRouter({\n * payeeAddress: '...',\n * plugin: createTelemetryPlugin({\n * clickhouse: {\n * url: process.env.TELEM_CLICKHOUSE_URL ?? 'http://localhost:8123',\n * database: process.env.TELEM_CLICKHOUSE_DATABASE,\n * username: process.env.TELEM_CLICKHOUSE_USERNAME,\n * password: process.env.TELEM_CLICKHOUSE_PASSWORD,\n * },\n * }),\n * });\n */\n\nimport { initClickhouse, pingClickhouse, insertInvocation } from './clickhouse';\nimport type { McpResourceInvocation, TelemetryConfig } from './types';\n\n// ---------------------------------------------------------------------------\n// Minimal RouterPlugin types (inlined to avoid depending on @agentcash/router\n// at runtime — the router passes these shapes, we just consume them)\n// ---------------------------------------------------------------------------\n\ninterface RequestMeta {\n requestId: string;\n method: string;\n route: string;\n origin: string;\n referer: string | null;\n walletAddress: string | null;\n clientId: string | null;\n sessionId: string | null;\n contentType: string | null;\n headers: Record<string, string>;\n startTime: number;\n}\n\ninterface PluginContext {\n readonly requestId: string;\n readonly route: string;\n readonly walletAddress: string | null;\n readonly clientId: string | null;\n readonly sessionId: string | null;\n verifiedWallet: string | null;\n setVerifiedWallet(address: string): void;\n}\n\ninterface PaymentEvent {\n protocol: 'x402' | 'mpp';\n payer: string;\n amount: string;\n network: string;\n}\n\ninterface SettlementEvent {\n protocol: 'x402' | 'mpp';\n payer: string;\n transaction: string;\n network: string;\n}\n\ninterface ResponseMeta {\n statusCode: number;\n statusText: string;\n duration: number;\n contentType: string | null;\n headers: Record<string, string>;\n}\n\ninterface ErrorEvent {\n status: number;\n message: string;\n settled: boolean;\n}\n\ninterface AlertEvent {\n level: string;\n message: string;\n route: string;\n meta?: Record<string, unknown>;\n}\n\ninterface ProviderQuotaEvent {\n provider: string;\n route: string;\n remaining: number | null;\n limit: number | null;\n level: string;\n overage: string;\n message: string;\n}\n\n/** RouterPlugin interface — must match @agentcash/router's RouterPlugin */\ninterface RouterPlugin {\n init?(config: { origin?: string }): void | Promise<void>;\n onRequest?(meta: RequestMeta): PluginContext;\n onPaymentVerified?(ctx: PluginContext, payment: PaymentEvent): void;\n onPaymentSettled?(ctx: PluginContext, settlement: SettlementEvent): void;\n onResponse?(ctx: PluginContext, response: ResponseMeta): void;\n onError?(ctx: PluginContext, error: ErrorEvent): void;\n onAlert?(ctx: PluginContext, alert: AlertEvent): void;\n onProviderQuota?(ctx: PluginContext, event: ProviderQuotaEvent): void;\n}\n\n// ---------------------------------------------------------------------------\n// Extended context — carries request metadata through the lifecycle\n// ---------------------------------------------------------------------------\n\ninterface TelemetryPluginContext extends PluginContext {\n /** Stored from onRequest for use in onResponse */\n _meta: RequestMeta;\n /** Payment info captured between verify and response */\n _payment?: PaymentEvent;\n /** Settlement info captured between settle and response */\n _settlement?: SettlementEvent;\n}\n\n// ---------------------------------------------------------------------------\n// Plugin factory\n// ---------------------------------------------------------------------------\n\nexport interface TelemetryPluginConfig {\n clickhouse: TelemetryConfig['clickhouse'];\n /** If true, pings ClickHouse on init. */\n verify?: boolean;\n /** Console logging for dev. Default: false. */\n console?: boolean;\n}\n\nexport function createTelemetryPlugin(config: TelemetryPluginConfig): RouterPlugin {\n // Initialize ClickHouse synchronously (connection happens on first query)\n initClickhouse(config.clickhouse);\n if (config.verify) {\n pingClickhouse();\n }\n\n const log = config.console ?? false;\n\n return {\n onRequest(meta: RequestMeta): PluginContext {\n const ctx: TelemetryPluginContext = {\n requestId: meta.requestId,\n route: meta.route,\n walletAddress: meta.walletAddress,\n clientId: meta.clientId,\n sessionId: meta.sessionId,\n verifiedWallet: null,\n setVerifiedWallet(address: string) {\n ctx.verifiedWallet = address;\n },\n _meta: meta,\n };\n return ctx as PluginContext;\n },\n\n onPaymentVerified(ctx: PluginContext, payment: PaymentEvent) {\n (ctx as TelemetryPluginContext)._payment = payment;\n if (log) {\n console.log(`[telemetry] VERIFIED ${payment.protocol} ${payment.payer} ${payment.amount}`);\n }\n },\n\n onPaymentSettled(ctx: PluginContext, settlement: SettlementEvent) {\n (ctx as TelemetryPluginContext)._settlement = settlement;\n if (log) {\n console.log(`[telemetry] SETTLED ${settlement.protocol} tx=${settlement.transaction}`);\n }\n },\n\n onResponse(ctx: PluginContext, response: ResponseMeta) {\n const tCtx = ctx as TelemetryPluginContext;\n const meta = tCtx._meta;\n\n if (log) {\n const wallet = ctx.verifiedWallet ? ` wallet=${ctx.verifiedWallet}` : '';\n console.log(\n `[telemetry] ${meta.route} → ${response.statusCode} (${response.duration}ms)${wallet}`,\n );\n }\n\n const row: McpResourceInvocation = {\n id: meta.requestId,\n x_wallet_address: meta.walletAddress?.toLowerCase() ?? null,\n x_client_id: meta.clientId,\n session_id: meta.sessionId,\n verified_wallet_address: ctx.verifiedWallet?.toLowerCase() ?? null,\n\n method: meta.method,\n route: meta.route,\n origin: meta.origin,\n referer: meta.referer,\n request_content_type: meta.contentType,\n request_headers: JSON.stringify(meta.headers),\n request_body: null,\n\n status_code: response.statusCode,\n status_text: response.statusText,\n duration: response.duration,\n response_content_type: response.contentType,\n response_headers: JSON.stringify(response.headers),\n response_body: null,\n\n created_at: new Date(),\n };\n\n insertInvocation(row);\n },\n\n onError(ctx: PluginContext, error: ErrorEvent) {\n if (log) {\n console.error(`[telemetry] ERROR ${error.status}: ${error.message}`);\n }\n },\n\n onAlert(ctx: PluginContext, alert: AlertEvent) {\n if (log) {\n const logFn =\n alert.level === 'critical' || alert.level === 'error'\n ? console.error\n : alert.level === 'warn'\n ? console.warn\n : console.log;\n logFn(\n `[telemetry] ${alert.level.toUpperCase()} ${alert.route}: ${alert.message}`,\n alert.meta ?? '',\n );\n }\n },\n\n onProviderQuota(ctx: PluginContext, event: ProviderQuotaEvent) {\n if (log) {\n const logFn =\n event.level === 'critical'\n ? console.error\n : event.level === 'warn'\n ? console.warn\n : console.log;\n logFn(`[telemetry] QUOTA ${event.level.toUpperCase()} ${event.provider}: ${event.message}`);\n }\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
initClickhouse,
|
|
3
|
+
insertInvocation,
|
|
4
|
+
pingClickhouse
|
|
5
|
+
} from "./chunk-O2PCP6KV.mjs";
|
|
6
|
+
|
|
7
|
+
// src/router-plugin.ts
|
|
8
|
+
function createTelemetryPlugin(config) {
|
|
9
|
+
initClickhouse(config.clickhouse);
|
|
10
|
+
if (config.verify) {
|
|
11
|
+
pingClickhouse();
|
|
12
|
+
}
|
|
13
|
+
const log = config.console ?? false;
|
|
14
|
+
return {
|
|
15
|
+
onRequest(meta) {
|
|
16
|
+
const ctx = {
|
|
17
|
+
requestId: meta.requestId,
|
|
18
|
+
route: meta.route,
|
|
19
|
+
walletAddress: meta.walletAddress,
|
|
20
|
+
clientId: meta.clientId,
|
|
21
|
+
sessionId: meta.sessionId,
|
|
22
|
+
verifiedWallet: null,
|
|
23
|
+
setVerifiedWallet(address) {
|
|
24
|
+
ctx.verifiedWallet = address;
|
|
25
|
+
},
|
|
26
|
+
_meta: meta
|
|
27
|
+
};
|
|
28
|
+
return ctx;
|
|
29
|
+
},
|
|
30
|
+
onPaymentVerified(ctx, payment) {
|
|
31
|
+
ctx._payment = payment;
|
|
32
|
+
if (log) {
|
|
33
|
+
console.log(`[telemetry] VERIFIED ${payment.protocol} ${payment.payer} ${payment.amount}`);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
onPaymentSettled(ctx, settlement) {
|
|
37
|
+
ctx._settlement = settlement;
|
|
38
|
+
if (log) {
|
|
39
|
+
console.log(`[telemetry] SETTLED ${settlement.protocol} tx=${settlement.transaction}`);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
onResponse(ctx, response) {
|
|
43
|
+
const tCtx = ctx;
|
|
44
|
+
const meta = tCtx._meta;
|
|
45
|
+
if (log) {
|
|
46
|
+
const wallet = ctx.verifiedWallet ? ` wallet=${ctx.verifiedWallet}` : "";
|
|
47
|
+
console.log(
|
|
48
|
+
`[telemetry] ${meta.route} \u2192 ${response.statusCode} (${response.duration}ms)${wallet}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
const row = {
|
|
52
|
+
id: meta.requestId,
|
|
53
|
+
x_wallet_address: meta.walletAddress?.toLowerCase() ?? null,
|
|
54
|
+
x_client_id: meta.clientId,
|
|
55
|
+
session_id: meta.sessionId,
|
|
56
|
+
verified_wallet_address: ctx.verifiedWallet?.toLowerCase() ?? null,
|
|
57
|
+
method: meta.method,
|
|
58
|
+
route: meta.route,
|
|
59
|
+
origin: meta.origin,
|
|
60
|
+
referer: meta.referer,
|
|
61
|
+
request_content_type: meta.contentType,
|
|
62
|
+
request_headers: JSON.stringify(meta.headers),
|
|
63
|
+
request_body: null,
|
|
64
|
+
status_code: response.statusCode,
|
|
65
|
+
status_text: response.statusText,
|
|
66
|
+
duration: response.duration,
|
|
67
|
+
response_content_type: response.contentType,
|
|
68
|
+
response_headers: JSON.stringify(response.headers),
|
|
69
|
+
response_body: null,
|
|
70
|
+
created_at: /* @__PURE__ */ new Date()
|
|
71
|
+
};
|
|
72
|
+
insertInvocation(row);
|
|
73
|
+
},
|
|
74
|
+
onError(ctx, error) {
|
|
75
|
+
if (log) {
|
|
76
|
+
console.error(`[telemetry] ERROR ${error.status}: ${error.message}`);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
onAlert(ctx, alert) {
|
|
80
|
+
if (log) {
|
|
81
|
+
const logFn = alert.level === "critical" || alert.level === "error" ? console.error : alert.level === "warn" ? console.warn : console.log;
|
|
82
|
+
logFn(
|
|
83
|
+
`[telemetry] ${alert.level.toUpperCase()} ${alert.route}: ${alert.message}`,
|
|
84
|
+
alert.meta ?? ""
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
onProviderQuota(ctx, event) {
|
|
89
|
+
if (log) {
|
|
90
|
+
const logFn = event.level === "critical" ? console.error : event.level === "warn" ? console.warn : console.log;
|
|
91
|
+
logFn(`[telemetry] QUOTA ${event.level.toUpperCase()} ${event.provider}: ${event.message}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export {
|
|
97
|
+
createTelemetryPlugin
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=router-plugin.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/router-plugin.ts"],"sourcesContent":["/**\n * RouterPlugin adapter for @agentcash/router.\n *\n * Bridges the router's plugin hooks into ClickHouse telemetry.\n * Uses the same mcp_resource_invocations table as the legacy withTelemetry wrapper.\n *\n * Usage:\n * import { createRouter } from '@agentcash/router';\n * import { createTelemetryPlugin } from '@agentcash/telemetry/plugin';\n *\n * const router = createRouter({\n * payeeAddress: '...',\n * plugin: createTelemetryPlugin({\n * clickhouse: {\n * url: process.env.TELEM_CLICKHOUSE_URL ?? 'http://localhost:8123',\n * database: process.env.TELEM_CLICKHOUSE_DATABASE,\n * username: process.env.TELEM_CLICKHOUSE_USERNAME,\n * password: process.env.TELEM_CLICKHOUSE_PASSWORD,\n * },\n * }),\n * });\n */\n\nimport { initClickhouse, pingClickhouse, insertInvocation } from './clickhouse';\nimport type { McpResourceInvocation, TelemetryConfig } from './types';\n\n// ---------------------------------------------------------------------------\n// Minimal RouterPlugin types (inlined to avoid depending on @agentcash/router\n// at runtime — the router passes these shapes, we just consume them)\n// ---------------------------------------------------------------------------\n\ninterface RequestMeta {\n requestId: string;\n method: string;\n route: string;\n origin: string;\n referer: string | null;\n walletAddress: string | null;\n clientId: string | null;\n sessionId: string | null;\n contentType: string | null;\n headers: Record<string, string>;\n startTime: number;\n}\n\ninterface PluginContext {\n readonly requestId: string;\n readonly route: string;\n readonly walletAddress: string | null;\n readonly clientId: string | null;\n readonly sessionId: string | null;\n verifiedWallet: string | null;\n setVerifiedWallet(address: string): void;\n}\n\ninterface PaymentEvent {\n protocol: 'x402' | 'mpp';\n payer: string;\n amount: string;\n network: string;\n}\n\ninterface SettlementEvent {\n protocol: 'x402' | 'mpp';\n payer: string;\n transaction: string;\n network: string;\n}\n\ninterface ResponseMeta {\n statusCode: number;\n statusText: string;\n duration: number;\n contentType: string | null;\n headers: Record<string, string>;\n}\n\ninterface ErrorEvent {\n status: number;\n message: string;\n settled: boolean;\n}\n\ninterface AlertEvent {\n level: string;\n message: string;\n route: string;\n meta?: Record<string, unknown>;\n}\n\ninterface ProviderQuotaEvent {\n provider: string;\n route: string;\n remaining: number | null;\n limit: number | null;\n level: string;\n overage: string;\n message: string;\n}\n\n/** RouterPlugin interface — must match @agentcash/router's RouterPlugin */\ninterface RouterPlugin {\n init?(config: { origin?: string }): void | Promise<void>;\n onRequest?(meta: RequestMeta): PluginContext;\n onPaymentVerified?(ctx: PluginContext, payment: PaymentEvent): void;\n onPaymentSettled?(ctx: PluginContext, settlement: SettlementEvent): void;\n onResponse?(ctx: PluginContext, response: ResponseMeta): void;\n onError?(ctx: PluginContext, error: ErrorEvent): void;\n onAlert?(ctx: PluginContext, alert: AlertEvent): void;\n onProviderQuota?(ctx: PluginContext, event: ProviderQuotaEvent): void;\n}\n\n// ---------------------------------------------------------------------------\n// Extended context — carries request metadata through the lifecycle\n// ---------------------------------------------------------------------------\n\ninterface TelemetryPluginContext extends PluginContext {\n /** Stored from onRequest for use in onResponse */\n _meta: RequestMeta;\n /** Payment info captured between verify and response */\n _payment?: PaymentEvent;\n /** Settlement info captured between settle and response */\n _settlement?: SettlementEvent;\n}\n\n// ---------------------------------------------------------------------------\n// Plugin factory\n// ---------------------------------------------------------------------------\n\nexport interface TelemetryPluginConfig {\n clickhouse: TelemetryConfig['clickhouse'];\n /** If true, pings ClickHouse on init. */\n verify?: boolean;\n /** Console logging for dev. Default: false. */\n console?: boolean;\n}\n\nexport function createTelemetryPlugin(config: TelemetryPluginConfig): RouterPlugin {\n // Initialize ClickHouse synchronously (connection happens on first query)\n initClickhouse(config.clickhouse);\n if (config.verify) {\n pingClickhouse();\n }\n\n const log = config.console ?? false;\n\n return {\n onRequest(meta: RequestMeta): PluginContext {\n const ctx: TelemetryPluginContext = {\n requestId: meta.requestId,\n route: meta.route,\n walletAddress: meta.walletAddress,\n clientId: meta.clientId,\n sessionId: meta.sessionId,\n verifiedWallet: null,\n setVerifiedWallet(address: string) {\n ctx.verifiedWallet = address;\n },\n _meta: meta,\n };\n return ctx as PluginContext;\n },\n\n onPaymentVerified(ctx: PluginContext, payment: PaymentEvent) {\n (ctx as TelemetryPluginContext)._payment = payment;\n if (log) {\n console.log(`[telemetry] VERIFIED ${payment.protocol} ${payment.payer} ${payment.amount}`);\n }\n },\n\n onPaymentSettled(ctx: PluginContext, settlement: SettlementEvent) {\n (ctx as TelemetryPluginContext)._settlement = settlement;\n if (log) {\n console.log(`[telemetry] SETTLED ${settlement.protocol} tx=${settlement.transaction}`);\n }\n },\n\n onResponse(ctx: PluginContext, response: ResponseMeta) {\n const tCtx = ctx as TelemetryPluginContext;\n const meta = tCtx._meta;\n\n if (log) {\n const wallet = ctx.verifiedWallet ? ` wallet=${ctx.verifiedWallet}` : '';\n console.log(\n `[telemetry] ${meta.route} → ${response.statusCode} (${response.duration}ms)${wallet}`,\n );\n }\n\n const row: McpResourceInvocation = {\n id: meta.requestId,\n x_wallet_address: meta.walletAddress?.toLowerCase() ?? null,\n x_client_id: meta.clientId,\n session_id: meta.sessionId,\n verified_wallet_address: ctx.verifiedWallet?.toLowerCase() ?? null,\n\n method: meta.method,\n route: meta.route,\n origin: meta.origin,\n referer: meta.referer,\n request_content_type: meta.contentType,\n request_headers: JSON.stringify(meta.headers),\n request_body: null,\n\n status_code: response.statusCode,\n status_text: response.statusText,\n duration: response.duration,\n response_content_type: response.contentType,\n response_headers: JSON.stringify(response.headers),\n response_body: null,\n\n created_at: new Date(),\n };\n\n insertInvocation(row);\n },\n\n onError(ctx: PluginContext, error: ErrorEvent) {\n if (log) {\n console.error(`[telemetry] ERROR ${error.status}: ${error.message}`);\n }\n },\n\n onAlert(ctx: PluginContext, alert: AlertEvent) {\n if (log) {\n const logFn =\n alert.level === 'critical' || alert.level === 'error'\n ? console.error\n : alert.level === 'warn'\n ? console.warn\n : console.log;\n logFn(\n `[telemetry] ${alert.level.toUpperCase()} ${alert.route}: ${alert.message}`,\n alert.meta ?? '',\n );\n }\n },\n\n onProviderQuota(ctx: PluginContext, event: ProviderQuotaEvent) {\n if (log) {\n const logFn =\n event.level === 'critical'\n ? console.error\n : event.level === 'warn'\n ? console.warn\n : console.log;\n logFn(`[telemetry] QUOTA ${event.level.toUpperCase()} ${event.provider}: ${event.message}`);\n }\n },\n };\n}\n"],"mappings":";;;;;;;AAyIO,SAAS,sBAAsB,QAA6C;AAEjF,iBAAe,OAAO,UAAU;AAChC,MAAI,OAAO,QAAQ;AACjB,mBAAe;AAAA,EACjB;AAEA,QAAM,MAAM,OAAO,WAAW;AAE9B,SAAO;AAAA,IACL,UAAU,MAAkC;AAC1C,YAAM,MAA8B;AAAA,QAClC,WAAW,KAAK;AAAA,QAChB,OAAO,KAAK;AAAA,QACZ,eAAe,KAAK;AAAA,QACpB,UAAU,KAAK;AAAA,QACf,WAAW,KAAK;AAAA,QAChB,gBAAgB;AAAA,QAChB,kBAAkB,SAAiB;AACjC,cAAI,iBAAiB;AAAA,QACvB;AAAA,QACA,OAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IAEA,kBAAkB,KAAoB,SAAuB;AAC3D,MAAC,IAA+B,WAAW;AAC3C,UAAI,KAAK;AACP,gBAAQ,IAAI,wBAAwB,QAAQ,QAAQ,IAAI,QAAQ,KAAK,IAAI,QAAQ,MAAM,EAAE;AAAA,MAC3F;AAAA,IACF;AAAA,IAEA,iBAAiB,KAAoB,YAA6B;AAChE,MAAC,IAA+B,cAAc;AAC9C,UAAI,KAAK;AACP,gBAAQ,IAAI,uBAAuB,WAAW,QAAQ,OAAO,WAAW,WAAW,EAAE;AAAA,MACvF;AAAA,IACF;AAAA,IAEA,WAAW,KAAoB,UAAwB;AACrD,YAAM,OAAO;AACb,YAAM,OAAO,KAAK;AAElB,UAAI,KAAK;AACP,cAAM,SAAS,IAAI,iBAAiB,WAAW,IAAI,cAAc,KAAK;AACtE,gBAAQ;AAAA,UACN,eAAe,KAAK,KAAK,WAAM,SAAS,UAAU,KAAK,SAAS,QAAQ,MAAM,MAAM;AAAA,QACtF;AAAA,MACF;AAEA,YAAM,MAA6B;AAAA,QACjC,IAAI,KAAK;AAAA,QACT,kBAAkB,KAAK,eAAe,YAAY,KAAK;AAAA,QACvD,aAAa,KAAK;AAAA,QAClB,YAAY,KAAK;AAAA,QACjB,yBAAyB,IAAI,gBAAgB,YAAY,KAAK;AAAA,QAE9D,QAAQ,KAAK;AAAA,QACb,OAAO,KAAK;AAAA,QACZ,QAAQ,KAAK;AAAA,QACb,SAAS,KAAK;AAAA,QACd,sBAAsB,KAAK;AAAA,QAC3B,iBAAiB,KAAK,UAAU,KAAK,OAAO;AAAA,QAC5C,cAAc;AAAA,QAEd,aAAa,SAAS;AAAA,QACtB,aAAa,SAAS;AAAA,QACtB,UAAU,SAAS;AAAA,QACnB,uBAAuB,SAAS;AAAA,QAChC,kBAAkB,KAAK,UAAU,SAAS,OAAO;AAAA,QACjD,eAAe;AAAA,QAEf,YAAY,oBAAI,KAAK;AAAA,MACvB;AAEA,uBAAiB,GAAG;AAAA,IACtB;AAAA,IAEA,QAAQ,KAAoB,OAAmB;AAC7C,UAAI,KAAK;AACP,gBAAQ,MAAM,qBAAqB,MAAM,MAAM,KAAK,MAAM,OAAO,EAAE;AAAA,MACrE;AAAA,IACF;AAAA,IAEA,QAAQ,KAAoB,OAAmB;AAC7C,UAAI,KAAK;AACP,cAAM,QACJ,MAAM,UAAU,cAAc,MAAM,UAAU,UAC1C,QAAQ,QACR,MAAM,UAAU,SACd,QAAQ,OACR,QAAQ;AAChB;AAAA,UACE,eAAe,MAAM,MAAM,YAAY,CAAC,IAAI,MAAM,KAAK,KAAK,MAAM,OAAO;AAAA,UACzE,MAAM,QAAQ;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,IAEA,gBAAgB,KAAoB,OAA2B;AAC7D,UAAI,KAAK;AACP,cAAM,QACJ,MAAM,UAAU,aACZ,QAAQ,QACR,MAAM,UAAU,SACd,QAAQ,OACR,QAAQ;AAChB,cAAM,qBAAqB,MAAM,MAAM,YAAY,CAAC,IAAI,MAAM,QAAQ,KAAK,MAAM,OAAO,EAAE;AAAA,MAC5F;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
package/dist/siwx.d.mts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { a as TelemetryContext } from './types-Bl8IwXin.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SIWX telemetry wrapper — composes SIWX verification with telemetry.
|
|
6
|
+
* One-liner for routes that need wallet auth + telemetry.
|
|
7
|
+
*
|
|
8
|
+
* Delegates SIWX verification to @x402/extensions/sign-in-with-x.
|
|
9
|
+
* This package does NOT implement SIWX itself.
|
|
10
|
+
*
|
|
11
|
+
* Import from '@agentcash/telemetry/siwx'.
|
|
12
|
+
* Requires peer dep: @x402/extensions
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
interface SiwxTelemetryContext extends Omit<TelemetryContext, 'verifiedWallet'> {
|
|
16
|
+
/** Verified wallet address from SIWX authentication */
|
|
17
|
+
verifiedWallet: string;
|
|
18
|
+
}
|
|
19
|
+
type SiwxHandler = (request: NextRequest, ctx: SiwxTelemetryContext) => Promise<NextResponse>;
|
|
20
|
+
/**
|
|
21
|
+
* Wrap a Next.js route handler with SIWX verification + telemetry.
|
|
22
|
+
*
|
|
23
|
+
* Verifies the SIGN-IN-WITH-X header and sets the verified wallet automatically.
|
|
24
|
+
* If no SIWX header is present, returns a 402 with SIWX challenge.
|
|
25
|
+
* If verification fails, returns a 402 (matching x402 protocol convention).
|
|
26
|
+
*/
|
|
27
|
+
declare function withSiwxTelemetry(handler: SiwxHandler): (request: NextRequest) => Promise<NextResponse>;
|
|
28
|
+
|
|
29
|
+
export { type SiwxTelemetryContext, withSiwxTelemetry };
|
package/dist/siwx.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { a as TelemetryContext } from './types-Bl8IwXin.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SIWX telemetry wrapper — composes SIWX verification with telemetry.
|
|
6
|
+
* One-liner for routes that need wallet auth + telemetry.
|
|
7
|
+
*
|
|
8
|
+
* Delegates SIWX verification to @x402/extensions/sign-in-with-x.
|
|
9
|
+
* This package does NOT implement SIWX itself.
|
|
10
|
+
*
|
|
11
|
+
* Import from '@agentcash/telemetry/siwx'.
|
|
12
|
+
* Requires peer dep: @x402/extensions
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
interface SiwxTelemetryContext extends Omit<TelemetryContext, 'verifiedWallet'> {
|
|
16
|
+
/** Verified wallet address from SIWX authentication */
|
|
17
|
+
verifiedWallet: string;
|
|
18
|
+
}
|
|
19
|
+
type SiwxHandler = (request: NextRequest, ctx: SiwxTelemetryContext) => Promise<NextResponse>;
|
|
20
|
+
/**
|
|
21
|
+
* Wrap a Next.js route handler with SIWX verification + telemetry.
|
|
22
|
+
*
|
|
23
|
+
* Verifies the SIGN-IN-WITH-X header and sets the verified wallet automatically.
|
|
24
|
+
* If no SIWX header is present, returns a 402 with SIWX challenge.
|
|
25
|
+
* If verification fails, returns a 402 (matching x402 protocol convention).
|
|
26
|
+
*/
|
|
27
|
+
declare function withSiwxTelemetry(handler: SiwxHandler): (request: NextRequest) => Promise<NextResponse>;
|
|
28
|
+
|
|
29
|
+
export { type SiwxTelemetryContext, withSiwxTelemetry };
|
package/dist/siwx.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
|
|
2
|
+
|
|
3
|
+
var _chunkFJ3YM6KOjs = require('./chunk-FJ3YM6KO.js');
|
|
4
|
+
require('./chunk-GE7VBMQP.js');
|
|
5
|
+
require('./chunk-P63MLKU3.js');
|
|
6
|
+
|
|
7
|
+
// src/siwx.ts
|
|
8
|
+
var _server = require('next/server');
|
|
9
|
+
var _crypto = require('crypto');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
var _signinwithx = require('@x402/extensions/sign-in-with-x');
|
|
16
|
+
var _http = require('@x402/core/http');
|
|
17
|
+
function withSiwxTelemetry(handler) {
|
|
18
|
+
return _chunkFJ3YM6KOjs.withTelemetry.call(void 0, async (request, ctx) => {
|
|
19
|
+
const header = _nullishCoalesce(request.headers.get("SIGN-IN-WITH-X"), () => ( request.headers.get("sign-in-with-x")));
|
|
20
|
+
if (!header) {
|
|
21
|
+
return buildSiwxChallengeResponse(request);
|
|
22
|
+
}
|
|
23
|
+
const payload = _signinwithx.parseSIWxHeader.call(void 0, header);
|
|
24
|
+
const validation = await _signinwithx.validateSIWxMessage.call(void 0, payload, request.url);
|
|
25
|
+
if (!validation.valid) {
|
|
26
|
+
return _server.NextResponse.json(
|
|
27
|
+
{ success: false, error: `SIWX validation failed: ${validation.error}` },
|
|
28
|
+
{ status: 402 }
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
const verification = await _signinwithx.verifySIWxSignature.call(void 0, payload);
|
|
32
|
+
if (!verification.valid || !verification.address) {
|
|
33
|
+
return _server.NextResponse.json(
|
|
34
|
+
{ success: false, error: "SIWX signature verification failed" },
|
|
35
|
+
{ status: 402 }
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
const walletAddress = verification.address.toLowerCase();
|
|
39
|
+
ctx.setVerifiedWallet(walletAddress);
|
|
40
|
+
return handler(request, {
|
|
41
|
+
...ctx,
|
|
42
|
+
verifiedWallet: walletAddress
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function buildSiwxChallengeResponse(request) {
|
|
47
|
+
const url = new URL(request.url);
|
|
48
|
+
const nonce = _crypto.randomBytes.call(void 0, 16).toString("hex");
|
|
49
|
+
const issuedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
50
|
+
const expirationTime = new Date(Date.now() + 3e5).toISOString();
|
|
51
|
+
const paymentRequired = {
|
|
52
|
+
x402Version: 2,
|
|
53
|
+
error: "SIWX authentication required",
|
|
54
|
+
resource: {
|
|
55
|
+
url: request.url,
|
|
56
|
+
description: "SIWX-protected endpoint",
|
|
57
|
+
mimeType: "application/json"
|
|
58
|
+
},
|
|
59
|
+
accepts: [
|
|
60
|
+
{
|
|
61
|
+
scheme: "exact",
|
|
62
|
+
network: "eip155:8453",
|
|
63
|
+
asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
64
|
+
amount: "0",
|
|
65
|
+
payTo: "0x0000000000000000000000000000000000000000",
|
|
66
|
+
maxTimeoutSeconds: 300,
|
|
67
|
+
extra: {}
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
extensions: {
|
|
71
|
+
"sign-in-with-x": {
|
|
72
|
+
info: {
|
|
73
|
+
domain: url.hostname,
|
|
74
|
+
uri: request.url,
|
|
75
|
+
version: "1",
|
|
76
|
+
nonce,
|
|
77
|
+
issuedAt,
|
|
78
|
+
expirationTime,
|
|
79
|
+
statement: "Sign in to verify your wallet identity",
|
|
80
|
+
resources: [request.url]
|
|
81
|
+
},
|
|
82
|
+
supportedChains: [{ chainId: "eip155:8453", type: "eip191" }],
|
|
83
|
+
schema: _signinwithx.buildSIWxSchema.call(void 0, )
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const encoded = _http.encodePaymentRequiredHeader.call(void 0, paymentRequired);
|
|
88
|
+
return new (0, _server.NextResponse)(JSON.stringify(paymentRequired), {
|
|
89
|
+
status: 402,
|
|
90
|
+
headers: {
|
|
91
|
+
"Content-Type": "application/json",
|
|
92
|
+
"PAYMENT-REQUIRED": encoded
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
exports.withSiwxTelemetry = withSiwxTelemetry;
|
|
99
|
+
//# sourceMappingURL=siwx.js.map
|
package/dist/siwx.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/samragsdale/Documents/Code/merit-systems/agentcash-telemetry/dist/siwx.js","../src/siwx.ts"],"names":[],"mappings":"AAAA;AACE;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B;AACA;ACKA,qCAA+C;AAC/C,gCAA4B;AAC5B;AACE;AACA;AACA;AACA;AAAA,8DACK;AACP,uCAA4C;AAoBrC,SAAS,iBAAA,CAAkB,OAAA,EAAsB;AACtD,EAAA,OAAO,4CAAA,MAAc,CAAO,OAAA,EAAsB,GAAA,EAAA,GAA0B;AAC1E,IAAA,MAAM,OAAA,mBAAS,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,gBAAgB,CAAA,UAAK,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,gBAAgB,GAAA;AAE5F,IAAA,GAAA,CAAI,CAAC,MAAA,EAAQ;AACX,MAAA,OAAO,0BAAA,CAA2B,OAAO,CAAA;AAAA,IAC3C;AAEA,IAAA,MAAM,QAAA,EAAU,0CAAA,MAAsB,CAAA;AAEtC,IAAA,MAAM,WAAA,EAAa,MAAM,8CAAA,OAAoB,EAAS,OAAA,CAAQ,GAAG,CAAA;AACjE,IAAA,GAAA,CAAI,CAAC,UAAA,CAAW,KAAA,EAAO;AACrB,MAAA,OAAO,oBAAA,CAAa,IAAA;AAAA,QAClB,EAAE,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,CAAA,wBAAA,EAA2B,UAAA,CAAW,KAAK,CAAA,EAAA;AACtD,QAAA;AAChB,MAAA;AACF,IAAA;AAEsD,IAAA;AACJ,IAAA;AAC5B,MAAA;AAC4C,QAAA;AAChD,QAAA;AAChB,MAAA;AACF,IAAA;AAEuD,IAAA;AACpB,IAAA;AAEX,IAAA;AACnB,MAAA;AACa,MAAA;AACO,IAAA;AAC1B,EAAA;AACH;AAKwE;AACvC,EAAA;AACa,EAAA;AACJ,EAAA;AAC0B,EAAA;AAE1C,EAAA;AACT,IAAA;AACN,IAAA;AACG,IAAA;AACK,MAAA;AACA,MAAA;AACH,MAAA;AACZ,IAAA;AACS,IAAA;AACP,MAAA;AACU,QAAA;AACC,QAAA;AACF,QAAA;AACC,QAAA;AACD,QAAA;AACY,QAAA;AACX,QAAA;AACV,MAAA;AACF,IAAA;AACY,IAAA;AACQ,MAAA;AACV,QAAA;AACQ,UAAA;AACC,UAAA;AACJ,UAAA;AACT,UAAA;AACA,UAAA;AACA,UAAA;AACW,UAAA;AACY,UAAA;AACzB,QAAA;AAC4D,QAAA;AACpC,QAAA;AAC1B,MAAA;AACF,IAAA;AACF,EAAA;AAE2D,EAAA;AAEF,EAAA;AAC/C,IAAA;AACC,IAAA;AACS,MAAA;AACI,MAAA;AACtB,IAAA;AACD,EAAA;AACH;ADnC6E;AACA;AACA","file":"/Users/samragsdale/Documents/Code/merit-systems/agentcash-telemetry/dist/siwx.js","sourcesContent":[null,"/**\n * SIWX telemetry wrapper — composes SIWX verification with telemetry.\n * One-liner for routes that need wallet auth + telemetry.\n *\n * Delegates SIWX verification to @x402/extensions/sign-in-with-x.\n * This package does NOT implement SIWX itself.\n *\n * Import from '@agentcash/telemetry/siwx'.\n * Requires peer dep: @x402/extensions\n */\n\nimport { type NextRequest, NextResponse } from 'next/server';\nimport { randomBytes } from 'crypto';\nimport {\n parseSIWxHeader,\n validateSIWxMessage,\n verifySIWxSignature,\n buildSIWxSchema,\n} from '@x402/extensions/sign-in-with-x';\nimport { encodePaymentRequiredHeader } from '@x402/core/http';\nimport type { TelemetryContext } from './types';\nimport { withTelemetry } from './telemetry';\n\nexport type { SiwxTelemetryContext };\n\ninterface SiwxTelemetryContext extends Omit<TelemetryContext, 'verifiedWallet'> {\n /** Verified wallet address from SIWX authentication */\n verifiedWallet: string;\n}\n\ntype SiwxHandler = (request: NextRequest, ctx: SiwxTelemetryContext) => Promise<NextResponse>;\n\n/**\n * Wrap a Next.js route handler with SIWX verification + telemetry.\n *\n * Verifies the SIGN-IN-WITH-X header and sets the verified wallet automatically.\n * If no SIWX header is present, returns a 402 with SIWX challenge.\n * If verification fails, returns a 402 (matching x402 protocol convention).\n */\nexport function withSiwxTelemetry(handler: SiwxHandler) {\n return withTelemetry(async (request: NextRequest, ctx: TelemetryContext) => {\n const header = request.headers.get('SIGN-IN-WITH-X') ?? request.headers.get('sign-in-with-x');\n\n if (!header) {\n return buildSiwxChallengeResponse(request);\n }\n\n const payload = parseSIWxHeader(header);\n\n const validation = await validateSIWxMessage(payload, request.url);\n if (!validation.valid) {\n return NextResponse.json(\n { success: false, error: `SIWX validation failed: ${validation.error}` },\n { status: 402 },\n );\n }\n\n const verification = await verifySIWxSignature(payload);\n if (!verification.valid || !verification.address) {\n return NextResponse.json(\n { success: false, error: 'SIWX signature verification failed' },\n { status: 402 },\n );\n }\n\n const walletAddress = verification.address.toLowerCase();\n ctx.setVerifiedWallet(walletAddress);\n\n return handler(request, {\n ...ctx,\n verifiedWallet: walletAddress,\n } as SiwxTelemetryContext);\n });\n}\n\n/**\n * Build a 402 response with SIWX challenge.\n */\nfunction buildSiwxChallengeResponse(request: NextRequest): NextResponse {\n const url = new URL(request.url);\n const nonce = randomBytes(16).toString('hex');\n const issuedAt = new Date().toISOString();\n const expirationTime = new Date(Date.now() + 300_000).toISOString();\n\n const paymentRequired = {\n x402Version: 2,\n error: 'SIWX authentication required',\n resource: {\n url: request.url,\n description: 'SIWX-protected endpoint',\n mimeType: 'application/json',\n },\n accepts: [\n {\n scheme: 'exact' as const,\n network: 'eip155:8453' as const,\n asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n amount: '0',\n payTo: '0x0000000000000000000000000000000000000000',\n maxTimeoutSeconds: 300,\n extra: {},\n },\n ],\n extensions: {\n 'sign-in-with-x': {\n info: {\n domain: url.hostname,\n uri: request.url,\n version: '1',\n nonce,\n issuedAt,\n expirationTime,\n statement: 'Sign in to verify your wallet identity',\n resources: [request.url],\n },\n supportedChains: [{ chainId: 'eip155:8453', type: 'eip191' }],\n schema: buildSIWxSchema(),\n },\n },\n };\n\n const encoded = encodePaymentRequiredHeader(paymentRequired);\n\n return new NextResponse(JSON.stringify(paymentRequired), {\n status: 402,\n headers: {\n 'Content-Type': 'application/json',\n 'PAYMENT-REQUIRED': encoded,\n },\n });\n}\n"]}
|
package/dist/siwx.mjs
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
withTelemetry
|
|
3
|
+
} from "./chunk-JVLKV7CX.mjs";
|
|
4
|
+
import "./chunk-VOY67KA4.mjs";
|
|
5
|
+
import "./chunk-O2PCP6KV.mjs";
|
|
6
|
+
|
|
7
|
+
// src/siwx.ts
|
|
8
|
+
import { NextResponse } from "next/server";
|
|
9
|
+
import { randomBytes } from "crypto";
|
|
10
|
+
import {
|
|
11
|
+
parseSIWxHeader,
|
|
12
|
+
validateSIWxMessage,
|
|
13
|
+
verifySIWxSignature,
|
|
14
|
+
buildSIWxSchema
|
|
15
|
+
} from "@x402/extensions/sign-in-with-x";
|
|
16
|
+
import { encodePaymentRequiredHeader } from "@x402/core/http";
|
|
17
|
+
function withSiwxTelemetry(handler) {
|
|
18
|
+
return withTelemetry(async (request, ctx) => {
|
|
19
|
+
const header = request.headers.get("SIGN-IN-WITH-X") ?? request.headers.get("sign-in-with-x");
|
|
20
|
+
if (!header) {
|
|
21
|
+
return buildSiwxChallengeResponse(request);
|
|
22
|
+
}
|
|
23
|
+
const payload = parseSIWxHeader(header);
|
|
24
|
+
const validation = await validateSIWxMessage(payload, request.url);
|
|
25
|
+
if (!validation.valid) {
|
|
26
|
+
return NextResponse.json(
|
|
27
|
+
{ success: false, error: `SIWX validation failed: ${validation.error}` },
|
|
28
|
+
{ status: 402 }
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
const verification = await verifySIWxSignature(payload);
|
|
32
|
+
if (!verification.valid || !verification.address) {
|
|
33
|
+
return NextResponse.json(
|
|
34
|
+
{ success: false, error: "SIWX signature verification failed" },
|
|
35
|
+
{ status: 402 }
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
const walletAddress = verification.address.toLowerCase();
|
|
39
|
+
ctx.setVerifiedWallet(walletAddress);
|
|
40
|
+
return handler(request, {
|
|
41
|
+
...ctx,
|
|
42
|
+
verifiedWallet: walletAddress
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function buildSiwxChallengeResponse(request) {
|
|
47
|
+
const url = new URL(request.url);
|
|
48
|
+
const nonce = randomBytes(16).toString("hex");
|
|
49
|
+
const issuedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
50
|
+
const expirationTime = new Date(Date.now() + 3e5).toISOString();
|
|
51
|
+
const paymentRequired = {
|
|
52
|
+
x402Version: 2,
|
|
53
|
+
error: "SIWX authentication required",
|
|
54
|
+
resource: {
|
|
55
|
+
url: request.url,
|
|
56
|
+
description: "SIWX-protected endpoint",
|
|
57
|
+
mimeType: "application/json"
|
|
58
|
+
},
|
|
59
|
+
accepts: [
|
|
60
|
+
{
|
|
61
|
+
scheme: "exact",
|
|
62
|
+
network: "eip155:8453",
|
|
63
|
+
asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
64
|
+
amount: "0",
|
|
65
|
+
payTo: "0x0000000000000000000000000000000000000000",
|
|
66
|
+
maxTimeoutSeconds: 300,
|
|
67
|
+
extra: {}
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
extensions: {
|
|
71
|
+
"sign-in-with-x": {
|
|
72
|
+
info: {
|
|
73
|
+
domain: url.hostname,
|
|
74
|
+
uri: request.url,
|
|
75
|
+
version: "1",
|
|
76
|
+
nonce,
|
|
77
|
+
issuedAt,
|
|
78
|
+
expirationTime,
|
|
79
|
+
statement: "Sign in to verify your wallet identity",
|
|
80
|
+
resources: [request.url]
|
|
81
|
+
},
|
|
82
|
+
supportedChains: [{ chainId: "eip155:8453", type: "eip191" }],
|
|
83
|
+
schema: buildSIWxSchema()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const encoded = encodePaymentRequiredHeader(paymentRequired);
|
|
88
|
+
return new NextResponse(JSON.stringify(paymentRequired), {
|
|
89
|
+
status: 402,
|
|
90
|
+
headers: {
|
|
91
|
+
"Content-Type": "application/json",
|
|
92
|
+
"PAYMENT-REQUIRED": encoded
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
export {
|
|
97
|
+
withSiwxTelemetry
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=siwx.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/siwx.ts"],"sourcesContent":["/**\n * SIWX telemetry wrapper — composes SIWX verification with telemetry.\n * One-liner for routes that need wallet auth + telemetry.\n *\n * Delegates SIWX verification to @x402/extensions/sign-in-with-x.\n * This package does NOT implement SIWX itself.\n *\n * Import from '@agentcash/telemetry/siwx'.\n * Requires peer dep: @x402/extensions\n */\n\nimport { type NextRequest, NextResponse } from 'next/server';\nimport { randomBytes } from 'crypto';\nimport {\n parseSIWxHeader,\n validateSIWxMessage,\n verifySIWxSignature,\n buildSIWxSchema,\n} from '@x402/extensions/sign-in-with-x';\nimport { encodePaymentRequiredHeader } from '@x402/core/http';\nimport type { TelemetryContext } from './types';\nimport { withTelemetry } from './telemetry';\n\nexport type { SiwxTelemetryContext };\n\ninterface SiwxTelemetryContext extends Omit<TelemetryContext, 'verifiedWallet'> {\n /** Verified wallet address from SIWX authentication */\n verifiedWallet: string;\n}\n\ntype SiwxHandler = (request: NextRequest, ctx: SiwxTelemetryContext) => Promise<NextResponse>;\n\n/**\n * Wrap a Next.js route handler with SIWX verification + telemetry.\n *\n * Verifies the SIGN-IN-WITH-X header and sets the verified wallet automatically.\n * If no SIWX header is present, returns a 402 with SIWX challenge.\n * If verification fails, returns a 402 (matching x402 protocol convention).\n */\nexport function withSiwxTelemetry(handler: SiwxHandler) {\n return withTelemetry(async (request: NextRequest, ctx: TelemetryContext) => {\n const header = request.headers.get('SIGN-IN-WITH-X') ?? request.headers.get('sign-in-with-x');\n\n if (!header) {\n return buildSiwxChallengeResponse(request);\n }\n\n const payload = parseSIWxHeader(header);\n\n const validation = await validateSIWxMessage(payload, request.url);\n if (!validation.valid) {\n return NextResponse.json(\n { success: false, error: `SIWX validation failed: ${validation.error}` },\n { status: 402 },\n );\n }\n\n const verification = await verifySIWxSignature(payload);\n if (!verification.valid || !verification.address) {\n return NextResponse.json(\n { success: false, error: 'SIWX signature verification failed' },\n { status: 402 },\n );\n }\n\n const walletAddress = verification.address.toLowerCase();\n ctx.setVerifiedWallet(walletAddress);\n\n return handler(request, {\n ...ctx,\n verifiedWallet: walletAddress,\n } as SiwxTelemetryContext);\n });\n}\n\n/**\n * Build a 402 response with SIWX challenge.\n */\nfunction buildSiwxChallengeResponse(request: NextRequest): NextResponse {\n const url = new URL(request.url);\n const nonce = randomBytes(16).toString('hex');\n const issuedAt = new Date().toISOString();\n const expirationTime = new Date(Date.now() + 300_000).toISOString();\n\n const paymentRequired = {\n x402Version: 2,\n error: 'SIWX authentication required',\n resource: {\n url: request.url,\n description: 'SIWX-protected endpoint',\n mimeType: 'application/json',\n },\n accepts: [\n {\n scheme: 'exact' as const,\n network: 'eip155:8453' as const,\n asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n amount: '0',\n payTo: '0x0000000000000000000000000000000000000000',\n maxTimeoutSeconds: 300,\n extra: {},\n },\n ],\n extensions: {\n 'sign-in-with-x': {\n info: {\n domain: url.hostname,\n uri: request.url,\n version: '1',\n nonce,\n issuedAt,\n expirationTime,\n statement: 'Sign in to verify your wallet identity',\n resources: [request.url],\n },\n supportedChains: [{ chainId: 'eip155:8453', type: 'eip191' }],\n schema: buildSIWxSchema(),\n },\n },\n };\n\n const encoded = encodePaymentRequiredHeader(paymentRequired);\n\n return new NextResponse(JSON.stringify(paymentRequired), {\n status: 402,\n headers: {\n 'Content-Type': 'application/json',\n 'PAYMENT-REQUIRED': encoded,\n },\n });\n}\n"],"mappings":";;;;;;;AAWA,SAA2B,oBAAoB;AAC/C,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,mCAAmC;AAoBrC,SAAS,kBAAkB,SAAsB;AACtD,SAAO,cAAc,OAAO,SAAsB,QAA0B;AAC1E,UAAM,SAAS,QAAQ,QAAQ,IAAI,gBAAgB,KAAK,QAAQ,QAAQ,IAAI,gBAAgB;AAE5F,QAAI,CAAC,QAAQ;AACX,aAAO,2BAA2B,OAAO;AAAA,IAC3C;AAEA,UAAM,UAAU,gBAAgB,MAAM;AAEtC,UAAM,aAAa,MAAM,oBAAoB,SAAS,QAAQ,GAAG;AACjE,QAAI,CAAC,WAAW,OAAO;AACrB,aAAO,aAAa;AAAA,QAClB,EAAE,SAAS,OAAO,OAAO,2BAA2B,WAAW,KAAK,GAAG;AAAA,QACvE,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,eAAe,MAAM,oBAAoB,OAAO;AACtD,QAAI,CAAC,aAAa,SAAS,CAAC,aAAa,SAAS;AAChD,aAAO,aAAa;AAAA,QAClB,EAAE,SAAS,OAAO,OAAO,qCAAqC;AAAA,QAC9D,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,gBAAgB,aAAa,QAAQ,YAAY;AACvD,QAAI,kBAAkB,aAAa;AAEnC,WAAO,QAAQ,SAAS;AAAA,MACtB,GAAG;AAAA,MACH,gBAAgB;AAAA,IAClB,CAAyB;AAAA,EAC3B,CAAC;AACH;AAKA,SAAS,2BAA2B,SAAoC;AACtE,QAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,QAAM,QAAQ,YAAY,EAAE,EAAE,SAAS,KAAK;AAC5C,QAAM,YAAW,oBAAI,KAAK,GAAE,YAAY;AACxC,QAAM,iBAAiB,IAAI,KAAK,KAAK,IAAI,IAAI,GAAO,EAAE,YAAY;AAElE,QAAM,kBAAkB;AAAA,IACtB,aAAa;AAAA,IACb,OAAO;AAAA,IACP,UAAU;AAAA,MACR,KAAK,QAAQ;AAAA,MACb,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,mBAAmB;AAAA,QACnB,OAAO,CAAC;AAAA,MACV;AAAA,IACF;AAAA,IACA,YAAY;AAAA,MACV,kBAAkB;AAAA,QAChB,MAAM;AAAA,UACJ,QAAQ,IAAI;AAAA,UACZ,KAAK,QAAQ;AAAA,UACb,SAAS;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,WAAW,CAAC,QAAQ,GAAG;AAAA,QACzB;AAAA,QACA,iBAAiB,CAAC,EAAE,SAAS,eAAe,MAAM,SAAS,CAAC;AAAA,QAC5D,QAAQ,gBAAgB;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,4BAA4B,eAAe;AAE3D,SAAO,IAAI,aAAa,KAAK,UAAU,eAAe,GAAG;AAAA,IACvD,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,oBAAoB;AAAA,IACtB;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClickHouse row type for mcp_resource_invocations table.
|
|
3
|
+
* This is the real contract — not the DDL.
|
|
4
|
+
*/
|
|
5
|
+
interface McpResourceInvocation {
|
|
6
|
+
id: string;
|
|
7
|
+
x_wallet_address: string | null;
|
|
8
|
+
x_client_id: string | null;
|
|
9
|
+
session_id: string | null;
|
|
10
|
+
verified_wallet_address: string | null;
|
|
11
|
+
method: string;
|
|
12
|
+
route: string;
|
|
13
|
+
origin: string;
|
|
14
|
+
referer: string | null;
|
|
15
|
+
request_content_type: string | null;
|
|
16
|
+
request_headers: string | null;
|
|
17
|
+
request_body: string | null;
|
|
18
|
+
status_code: number;
|
|
19
|
+
status_text: string;
|
|
20
|
+
duration: number;
|
|
21
|
+
response_content_type: string | null;
|
|
22
|
+
response_headers: string | null;
|
|
23
|
+
response_body: string | null;
|
|
24
|
+
created_at: Date;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Telemetry context passed to handler functions.
|
|
28
|
+
*/
|
|
29
|
+
interface TelemetryContext {
|
|
30
|
+
/** Wallet address from X-Wallet-Address header (lowercased) */
|
|
31
|
+
walletAddress: string | null;
|
|
32
|
+
/** Client ID from X-Client-ID header */
|
|
33
|
+
clientId: string | null;
|
|
34
|
+
/** Session ID from X-Session-ID header */
|
|
35
|
+
sessionId: string | null;
|
|
36
|
+
/** Verified wallet address (auto-extracted from x402 payment, or set manually) */
|
|
37
|
+
verifiedWallet: string | null;
|
|
38
|
+
/** Manually set the verified wallet address (for SIWX, API-key, or other auth) */
|
|
39
|
+
setVerifiedWallet: (address: string) => void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* ClickHouse connection config for initTelemetry.
|
|
43
|
+
*/
|
|
44
|
+
interface TelemetryConfig {
|
|
45
|
+
clickhouse: {
|
|
46
|
+
url: string;
|
|
47
|
+
database?: string;
|
|
48
|
+
username?: string;
|
|
49
|
+
password?: string;
|
|
50
|
+
};
|
|
51
|
+
/** Server's own origin URL (e.g., 'https://enrichx402.com'). Auto-detected from request if not set. */
|
|
52
|
+
origin?: string;
|
|
53
|
+
/** If true, pings ClickHouse on init and logs the result. Never throws or blocks. */
|
|
54
|
+
verify?: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type { McpResourceInvocation as M, TelemetryConfig as T, TelemetryContext as a };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClickHouse row type for mcp_resource_invocations table.
|
|
3
|
+
* This is the real contract — not the DDL.
|
|
4
|
+
*/
|
|
5
|
+
interface McpResourceInvocation {
|
|
6
|
+
id: string;
|
|
7
|
+
x_wallet_address: string | null;
|
|
8
|
+
x_client_id: string | null;
|
|
9
|
+
session_id: string | null;
|
|
10
|
+
verified_wallet_address: string | null;
|
|
11
|
+
method: string;
|
|
12
|
+
route: string;
|
|
13
|
+
origin: string;
|
|
14
|
+
referer: string | null;
|
|
15
|
+
request_content_type: string | null;
|
|
16
|
+
request_headers: string | null;
|
|
17
|
+
request_body: string | null;
|
|
18
|
+
status_code: number;
|
|
19
|
+
status_text: string;
|
|
20
|
+
duration: number;
|
|
21
|
+
response_content_type: string | null;
|
|
22
|
+
response_headers: string | null;
|
|
23
|
+
response_body: string | null;
|
|
24
|
+
created_at: Date;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Telemetry context passed to handler functions.
|
|
28
|
+
*/
|
|
29
|
+
interface TelemetryContext {
|
|
30
|
+
/** Wallet address from X-Wallet-Address header (lowercased) */
|
|
31
|
+
walletAddress: string | null;
|
|
32
|
+
/** Client ID from X-Client-ID header */
|
|
33
|
+
clientId: string | null;
|
|
34
|
+
/** Session ID from X-Session-ID header */
|
|
35
|
+
sessionId: string | null;
|
|
36
|
+
/** Verified wallet address (auto-extracted from x402 payment, or set manually) */
|
|
37
|
+
verifiedWallet: string | null;
|
|
38
|
+
/** Manually set the verified wallet address (for SIWX, API-key, or other auth) */
|
|
39
|
+
setVerifiedWallet: (address: string) => void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* ClickHouse connection config for initTelemetry.
|
|
43
|
+
*/
|
|
44
|
+
interface TelemetryConfig {
|
|
45
|
+
clickhouse: {
|
|
46
|
+
url: string;
|
|
47
|
+
database?: string;
|
|
48
|
+
username?: string;
|
|
49
|
+
password?: string;
|
|
50
|
+
};
|
|
51
|
+
/** Server's own origin URL (e.g., 'https://enrichx402.com'). Auto-detected from request if not set. */
|
|
52
|
+
origin?: string;
|
|
53
|
+
/** If true, pings ClickHouse on init and logs the result. Never throws or blocks. */
|
|
54
|
+
verify?: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type { McpResourceInvocation as M, TelemetryConfig as T, TelemetryContext as a };
|