@vorim/sdk 3.5.0 → 3.6.1

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.
Files changed (62) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/_runtime-gate-DZQTkw4J.d.cts +11 -0
  3. package/dist/_runtime-gate-DZQTkw4J.d.ts +11 -0
  4. package/dist/index.cjs +13 -8
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.cts +6 -233
  7. package/dist/index.d.ts +6 -233
  8. package/dist/index.js +13 -8
  9. package/dist/index.js.map +1 -1
  10. package/dist/integrations/anthropic.cjs +54 -5
  11. package/dist/integrations/anthropic.cjs.map +1 -1
  12. package/dist/integrations/anthropic.d.cts +30 -1
  13. package/dist/integrations/anthropic.d.ts +30 -1
  14. package/dist/integrations/anthropic.js +54 -5
  15. package/dist/integrations/anthropic.js.map +1 -1
  16. package/dist/integrations/crewai.d.cts +2 -1
  17. package/dist/integrations/crewai.d.ts +2 -1
  18. package/dist/integrations/langchain.cjs +12 -14
  19. package/dist/integrations/langchain.cjs.map +1 -1
  20. package/dist/integrations/langchain.d.cts +9 -1
  21. package/dist/integrations/langchain.d.ts +9 -1
  22. package/dist/integrations/langchain.js +12 -14
  23. package/dist/integrations/langchain.js.map +1 -1
  24. package/dist/integrations/langgraph.cjs +200 -0
  25. package/dist/integrations/langgraph.cjs.map +1 -0
  26. package/dist/integrations/langgraph.d.cts +20 -0
  27. package/dist/integrations/langgraph.d.ts +20 -0
  28. package/dist/integrations/langgraph.js +162 -0
  29. package/dist/integrations/langgraph.js.map +1 -0
  30. package/dist/integrations/llamaindex.cjs +3 -4
  31. package/dist/integrations/llamaindex.cjs.map +1 -1
  32. package/dist/integrations/llamaindex.d.cts +2 -1
  33. package/dist/integrations/llamaindex.d.ts +2 -1
  34. package/dist/integrations/llamaindex.js +3 -4
  35. package/dist/integrations/llamaindex.js.map +1 -1
  36. package/dist/integrations/openai.cjs +66 -11
  37. package/dist/integrations/openai.cjs.map +1 -1
  38. package/dist/integrations/openai.d.cts +37 -1
  39. package/dist/integrations/openai.d.ts +37 -1
  40. package/dist/integrations/openai.js +66 -11
  41. package/dist/integrations/openai.js.map +1 -1
  42. package/dist/integrations/siem.cjs +128 -0
  43. package/dist/integrations/siem.cjs.map +1 -0
  44. package/dist/integrations/siem.d.cts +57 -0
  45. package/dist/integrations/siem.d.ts +57 -0
  46. package/dist/integrations/siem.js +102 -0
  47. package/dist/integrations/siem.js.map +1 -0
  48. package/dist/integrations/stripe-acp.cjs +179 -0
  49. package/dist/integrations/stripe-acp.cjs.map +1 -0
  50. package/dist/integrations/stripe-acp.d.cts +69 -0
  51. package/dist/integrations/stripe-acp.d.ts +69 -0
  52. package/dist/integrations/stripe-acp.js +153 -0
  53. package/dist/integrations/stripe-acp.js.map +1 -0
  54. package/dist/integrations/vercel-ai.cjs +252 -0
  55. package/dist/integrations/vercel-ai.cjs.map +1 -0
  56. package/dist/integrations/vercel-ai.d.cts +67 -0
  57. package/dist/integrations/vercel-ai.d.ts +67 -0
  58. package/dist/integrations/vercel-ai.js +214 -0
  59. package/dist/integrations/vercel-ai.js.map +1 -0
  60. package/dist/types-B22WnXEW.d.cts +234 -0
  61. package/dist/types-B22WnXEW.d.ts +234 -0
  62. package/package.json +41 -1
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/integrations/siem.ts
21
+ var siem_exports = {};
22
+ __export(siem_exports, {
23
+ auditEventToOtel: () => auditEventToOtel,
24
+ createSiemForwarder: () => createSiemForwarder
25
+ });
26
+ module.exports = __toCommonJS(siem_exports);
27
+ var SEVERITY = {
28
+ success: { text: "INFO", num: 9 },
29
+ denied: { text: "WARN", num: 13 },
30
+ error: { text: "ERROR", num: 17 }
31
+ };
32
+ function attr(key, value) {
33
+ if (value === void 0 || value === null) return null;
34
+ if (typeof value === "number") return { key, value: { intValue: value } };
35
+ if (typeof value === "boolean") return { key, value: { boolValue: value } };
36
+ return { key, value: { stringValue: String(value) } };
37
+ }
38
+ function resolveTimestampMs(timestamp) {
39
+ if (!timestamp) return Date.now();
40
+ const ms = Date.parse(timestamp);
41
+ return Number.isNaN(ms) ? Date.now() : ms;
42
+ }
43
+ function auditEventToOtel(event, service = "vorim") {
44
+ const sev = SEVERITY[event.result] ?? SEVERITY.success;
45
+ const tsMs = resolveTimestampMs(event.timestamp);
46
+ const eventType = event.event_type || "unknown";
47
+ const action = event.action || "unknown";
48
+ const result = event.result || "unknown";
49
+ const attrs = [
50
+ attr("service.name", service),
51
+ attr("vorim.agent_id", event.agent_id),
52
+ attr("vorim.event_type", event.event_type),
53
+ attr("vorim.action", event.action),
54
+ attr("vorim.resource", event.resource),
55
+ attr("vorim.permission", event.permission),
56
+ attr("vorim.result", event.result),
57
+ attr("vorim.latency_ms", event.latency_ms),
58
+ attr("vorim.error_code", event.error_code),
59
+ attr("vorim.decision_id", event.decision_id),
60
+ attr("vorim.signature", event.signature ? "present" : "absent")
61
+ ].filter(Boolean);
62
+ return {
63
+ timeUnixNano: String(BigInt(Math.floor(tsMs)) * 1000000n),
64
+ severityText: sev.text,
65
+ severityNumber: sev.num,
66
+ body: { stringValue: `${eventType} ${action} \u2192 ${result}` },
67
+ attributes: attrs
68
+ };
69
+ }
70
+ function buildPayload(sink, events, service) {
71
+ if (sink === "splunk-hec") {
72
+ return events.map((e) => JSON.stringify({
73
+ time: resolveTimestampMs(e.timestamp) / 1e3,
74
+ source: "vorim",
75
+ sourcetype: "vorim:audit",
76
+ event: { ...e, service }
77
+ })).join("\n");
78
+ }
79
+ if (sink === "elasticsearch") {
80
+ return events.flatMap((e) => [JSON.stringify({ index: {} }), JSON.stringify({ ...e, service, "@timestamp": new Date(resolveTimestampMs(e.timestamp)).toISOString() })]).join("\n") + "\n";
81
+ }
82
+ return JSON.stringify({
83
+ resourceLogs: [{
84
+ resource: { attributes: [{ key: "service.name", value: { stringValue: service } }] },
85
+ scopeLogs: [{
86
+ scope: { name: "@vorim/sdk" },
87
+ logRecords: events.map((e) => auditEventToOtel(e, service))
88
+ }]
89
+ }]
90
+ });
91
+ }
92
+ function createSiemForwarder(config) {
93
+ const service = config.service ?? "vorim";
94
+ const timeoutMs = config.timeoutMs ?? 1e4;
95
+ const doFetch = config.fetchImpl ?? fetch;
96
+ const contentType = config.sink === "otlp-http" ? "application/json" : "application/json";
97
+ async function send(events) {
98
+ if (events.length === 0) return;
99
+ const body = buildPayload(config.sink, events, service);
100
+ const headers = { "Content-Type": contentType, ...config.headers ?? {} };
101
+ if (config.token) {
102
+ if (!headers.Authorization) {
103
+ headers.Authorization = config.sink === "splunk-hec" ? `Splunk ${config.token}` : config.sink === "elasticsearch" ? `ApiKey ${config.token}` : `Bearer ${config.token}`;
104
+ }
105
+ }
106
+ const controller = new AbortController();
107
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
108
+ try {
109
+ const res = await doFetch(config.endpoint, { method: "POST", headers, body, signal: controller.signal });
110
+ if (!res.ok) {
111
+ const text = await res.text().catch(() => "");
112
+ throw new Error(`SIEM forward failed: ${res.status} ${text.slice(0, 200)}`);
113
+ }
114
+ } finally {
115
+ clearTimeout(timer);
116
+ }
117
+ }
118
+ return {
119
+ forward: (event) => send([event]),
120
+ forwardBatch: (events) => send(events)
121
+ };
122
+ }
123
+ // Annotate the CommonJS export names for ESM import in node:
124
+ 0 && (module.exports = {
125
+ auditEventToOtel,
126
+ createSiemForwarder
127
+ });
128
+ //# sourceMappingURL=siem.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/integrations/siem.ts"],"sourcesContent":["// ============================================================================\n// VORIM SDK — SIEM Forwarder (OpenTelemetry / Splunk / Elastic)\n//\n// Forward Vorim's signed audit events into the tools your security team\n// already runs. This module is dependency-light: it maps an audit event to a\n// standard OpenTelemetry LogRecord and ships it over HTTP to one of three\n// sinks — an OTLP/HTTP collector, Splunk HEC, or Elasticsearch — so you do\n// not need to pull in the @opentelemetry/* packages to get audit into a SIEM.\n//\n// It is a transform + sink, not a poller: feed it the events you already\n// have (from emit(), a Vorim webhook, or an audit query) and it forwards them.\n//\n// Usage:\n// import { createSiemForwarder } from '@vorim/sdk/integrations/siem';\n//\n// const siem = createSiemForwarder({\n// sink: 'splunk-hec',\n// endpoint: 'https://splunk.example.com:8088/services/collector',\n// token: process.env.SPLUNK_HEC_TOKEN,\n// service: 'vorim-agents',\n// });\n//\n// // forward one event (e.g. inside a Vorim webhook handler)\n// await siem.forward(auditEvent);\n// // or a batch\n// await siem.forwardBatch(events);\n// ============================================================================\n\nimport type { AuditEventInput } from '../types.js';\n\nexport type SiemSink = 'otlp-http' | 'splunk-hec' | 'elasticsearch';\n\nexport interface SiemForwarderConfig {\n /** Which SIEM sink to ship to. */\n sink: SiemSink;\n /**\n * HTTP endpoint:\n * - otlp-http: your OTel collector's logs endpoint (…/v1/logs)\n * - splunk-hec: the HEC collector URL (…/services/collector)\n * - elasticsearch: the index/_bulk or _doc URL (…/vorim-audit/_doc)\n */\n endpoint: string;\n /** Auth token. Splunk HEC: the HEC token. Elastic: an API key. OTLP: bearer. */\n token?: string;\n /** Extra HTTP headers (e.g. an Authorization scheme the sink expects). */\n headers?: Record<string, string>;\n /** service.name attribute on emitted records. @default 'vorim' */\n service?: string;\n /** Request timeout in ms. @default 10000 */\n timeoutMs?: number;\n /** Custom fetch (for testing / non-global-fetch runtimes). */\n fetchImpl?: typeof fetch;\n}\n\n/** An OpenTelemetry LogRecord (JSON form) — the lingua franca for SIEM ingest. */\nexport interface OtelLogRecord {\n timeUnixNano: string;\n severityText: 'INFO' | 'WARN' | 'ERROR';\n severityNumber: number;\n body: { stringValue: string };\n attributes: { key: string; value: { stringValue?: string; intValue?: number; boolValue?: boolean } }[];\n}\n\nconst SEVERITY: Record<string, { text: OtelLogRecord['severityText']; num: number }> = {\n success: { text: 'INFO', num: 9 },\n denied: { text: 'WARN', num: 13 },\n error: { text: 'ERROR', num: 17 },\n};\n\nfunction attr(key: string, value: string | number | boolean | undefined): OtelLogRecord['attributes'][number] | null {\n if (value === undefined || value === null) return null;\n if (typeof value === 'number') return { key, value: { intValue: value } };\n if (typeof value === 'boolean') return { key, value: { boolValue: value } };\n return { key, value: { stringValue: String(value) } };\n}\n\n/**\n * Resolve an event timestamp to epoch-millis, tolerating a missing or malformed\n * `timestamp`. An unparseable ISO string (e.g. `'2026-13-32'`) would otherwise\n * yield NaN — which crashes the OTLP path (`BigInt(NaN)` throws) and serialises\n * to a null/garbage timestamp on the Splunk/ES paths. We fall back to now().\n */\nfunction resolveTimestampMs(timestamp?: string): number {\n if (!timestamp) return Date.now();\n const ms = Date.parse(timestamp);\n return Number.isNaN(ms) ? Date.now() : ms;\n}\n\n/** Map a Vorim audit event to an OTel LogRecord. Exported for testing. */\nexport function auditEventToOtel(event: AuditEventInput & { timestamp?: string; decision_id?: string }, service = 'vorim'): OtelLogRecord {\n const sev = SEVERITY[event.result] ?? SEVERITY.success;\n const tsMs = resolveTimestampMs(event.timestamp);\n // Guard the body against missing required fields (a direct SDK caller can\n // bypass the type checker); the HTTP API path is already Zod-validated.\n const eventType = event.event_type || 'unknown';\n const action = event.action || 'unknown';\n const result = event.result || 'unknown';\n const attrs = [\n attr('service.name', service),\n attr('vorim.agent_id', event.agent_id),\n attr('vorim.event_type', event.event_type),\n attr('vorim.action', event.action),\n attr('vorim.resource', event.resource),\n attr('vorim.permission', event.permission),\n attr('vorim.result', event.result),\n attr('vorim.latency_ms', event.latency_ms),\n attr('vorim.error_code', event.error_code),\n attr('vorim.decision_id', (event as any).decision_id),\n attr('vorim.signature', event.signature ? 'present' : 'absent'),\n ].filter(Boolean) as OtelLogRecord['attributes'];\n\n return {\n timeUnixNano: String(BigInt(Math.floor(tsMs)) * 1_000_000n),\n severityText: sev.text,\n severityNumber: sev.num,\n body: { stringValue: `${eventType} ${action} → ${result}` },\n attributes: attrs,\n };\n}\n\n/** Build the request body for a given sink from a batch of audit events. */\nfunction buildPayload(sink: SiemSink, events: any[], service: string): string {\n if (sink === 'splunk-hec') {\n // One HEC envelope per event (newline-delimited JSON).\n return events\n .map((e) => JSON.stringify({\n time: resolveTimestampMs(e.timestamp) / 1000,\n source: 'vorim',\n sourcetype: 'vorim:audit',\n event: { ...e, service },\n }))\n .join('\\n');\n }\n if (sink === 'elasticsearch') {\n // Bulk NDJSON: action line + doc line per event.\n return events\n .flatMap((e) => [JSON.stringify({ index: {} }), JSON.stringify({ ...e, service, '@timestamp': new Date(resolveTimestampMs(e.timestamp)).toISOString() })])\n .join('\\n') + '\\n';\n }\n // otlp-http: a single OTLP logs payload with one scope, many records.\n return JSON.stringify({\n resourceLogs: [{\n resource: { attributes: [{ key: 'service.name', value: { stringValue: service } }] },\n scopeLogs: [{\n scope: { name: '@vorim/sdk' },\n logRecords: events.map((e) => auditEventToOtel(e, service)),\n }],\n }],\n });\n}\n\nexport interface SiemForwarder {\n forward(event: AuditEventInput): Promise<void>;\n forwardBatch(events: AuditEventInput[]): Promise<void>;\n}\n\n/**\n * Create a SIEM forwarder. Errors are surfaced (the caller decides whether a\n * SIEM outage should block) — wrap in try/catch if you want fire-and-forget.\n */\nexport function createSiemForwarder(config: SiemForwarderConfig): SiemForwarder {\n const service = config.service ?? 'vorim';\n const timeoutMs = config.timeoutMs ?? 10_000;\n const doFetch = config.fetchImpl ?? fetch;\n\n const contentType = config.sink === 'otlp-http' ? 'application/json' : 'application/json';\n\n async function send(events: AuditEventInput[]): Promise<void> {\n if (events.length === 0) return;\n const body = buildPayload(config.sink, events, service);\n\n const headers: Record<string, string> = { 'Content-Type': contentType, ...(config.headers ?? {}) };\n if (config.token) {\n // Splunk HEC uses \"Authorization: Splunk <token>\"; Elastic uses \"ApiKey\";\n // OTLP collectors typically take a bearer. Default to bearer unless the\n // caller overrode Authorization via `headers`.\n if (!headers.Authorization) {\n headers.Authorization =\n config.sink === 'splunk-hec' ? `Splunk ${config.token}`\n : config.sink === 'elasticsearch' ? `ApiKey ${config.token}`\n : `Bearer ${config.token}`;\n }\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const res = await doFetch(config.endpoint, { method: 'POST', headers, body, signal: controller.signal });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`SIEM forward failed: ${res.status} ${text.slice(0, 200)}`);\n }\n } finally {\n clearTimeout(timer);\n }\n }\n\n return {\n forward: (event) => send([event]),\n forwardBatch: (events) => send(events),\n };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,57 @@
1
+ import { a as AuditEventInput } from '../types-B22WnXEW.cjs';
2
+
3
+ type SiemSink = 'otlp-http' | 'splunk-hec' | 'elasticsearch';
4
+ interface SiemForwarderConfig {
5
+ /** Which SIEM sink to ship to. */
6
+ sink: SiemSink;
7
+ /**
8
+ * HTTP endpoint:
9
+ * - otlp-http: your OTel collector's logs endpoint (…/v1/logs)
10
+ * - splunk-hec: the HEC collector URL (…/services/collector)
11
+ * - elasticsearch: the index/_bulk or _doc URL (…/vorim-audit/_doc)
12
+ */
13
+ endpoint: string;
14
+ /** Auth token. Splunk HEC: the HEC token. Elastic: an API key. OTLP: bearer. */
15
+ token?: string;
16
+ /** Extra HTTP headers (e.g. an Authorization scheme the sink expects). */
17
+ headers?: Record<string, string>;
18
+ /** service.name attribute on emitted records. @default 'vorim' */
19
+ service?: string;
20
+ /** Request timeout in ms. @default 10000 */
21
+ timeoutMs?: number;
22
+ /** Custom fetch (for testing / non-global-fetch runtimes). */
23
+ fetchImpl?: typeof fetch;
24
+ }
25
+ /** An OpenTelemetry LogRecord (JSON form) — the lingua franca for SIEM ingest. */
26
+ interface OtelLogRecord {
27
+ timeUnixNano: string;
28
+ severityText: 'INFO' | 'WARN' | 'ERROR';
29
+ severityNumber: number;
30
+ body: {
31
+ stringValue: string;
32
+ };
33
+ attributes: {
34
+ key: string;
35
+ value: {
36
+ stringValue?: string;
37
+ intValue?: number;
38
+ boolValue?: boolean;
39
+ };
40
+ }[];
41
+ }
42
+ /** Map a Vorim audit event to an OTel LogRecord. Exported for testing. */
43
+ declare function auditEventToOtel(event: AuditEventInput & {
44
+ timestamp?: string;
45
+ decision_id?: string;
46
+ }, service?: string): OtelLogRecord;
47
+ interface SiemForwarder {
48
+ forward(event: AuditEventInput): Promise<void>;
49
+ forwardBatch(events: AuditEventInput[]): Promise<void>;
50
+ }
51
+ /**
52
+ * Create a SIEM forwarder. Errors are surfaced (the caller decides whether a
53
+ * SIEM outage should block) — wrap in try/catch if you want fire-and-forget.
54
+ */
55
+ declare function createSiemForwarder(config: SiemForwarderConfig): SiemForwarder;
56
+
57
+ export { type OtelLogRecord, type SiemForwarder, type SiemForwarderConfig, type SiemSink, auditEventToOtel, createSiemForwarder };
@@ -0,0 +1,57 @@
1
+ import { a as AuditEventInput } from '../types-B22WnXEW.js';
2
+
3
+ type SiemSink = 'otlp-http' | 'splunk-hec' | 'elasticsearch';
4
+ interface SiemForwarderConfig {
5
+ /** Which SIEM sink to ship to. */
6
+ sink: SiemSink;
7
+ /**
8
+ * HTTP endpoint:
9
+ * - otlp-http: your OTel collector's logs endpoint (…/v1/logs)
10
+ * - splunk-hec: the HEC collector URL (…/services/collector)
11
+ * - elasticsearch: the index/_bulk or _doc URL (…/vorim-audit/_doc)
12
+ */
13
+ endpoint: string;
14
+ /** Auth token. Splunk HEC: the HEC token. Elastic: an API key. OTLP: bearer. */
15
+ token?: string;
16
+ /** Extra HTTP headers (e.g. an Authorization scheme the sink expects). */
17
+ headers?: Record<string, string>;
18
+ /** service.name attribute on emitted records. @default 'vorim' */
19
+ service?: string;
20
+ /** Request timeout in ms. @default 10000 */
21
+ timeoutMs?: number;
22
+ /** Custom fetch (for testing / non-global-fetch runtimes). */
23
+ fetchImpl?: typeof fetch;
24
+ }
25
+ /** An OpenTelemetry LogRecord (JSON form) — the lingua franca for SIEM ingest. */
26
+ interface OtelLogRecord {
27
+ timeUnixNano: string;
28
+ severityText: 'INFO' | 'WARN' | 'ERROR';
29
+ severityNumber: number;
30
+ body: {
31
+ stringValue: string;
32
+ };
33
+ attributes: {
34
+ key: string;
35
+ value: {
36
+ stringValue?: string;
37
+ intValue?: number;
38
+ boolValue?: boolean;
39
+ };
40
+ }[];
41
+ }
42
+ /** Map a Vorim audit event to an OTel LogRecord. Exported for testing. */
43
+ declare function auditEventToOtel(event: AuditEventInput & {
44
+ timestamp?: string;
45
+ decision_id?: string;
46
+ }, service?: string): OtelLogRecord;
47
+ interface SiemForwarder {
48
+ forward(event: AuditEventInput): Promise<void>;
49
+ forwardBatch(events: AuditEventInput[]): Promise<void>;
50
+ }
51
+ /**
52
+ * Create a SIEM forwarder. Errors are surfaced (the caller decides whether a
53
+ * SIEM outage should block) — wrap in try/catch if you want fire-and-forget.
54
+ */
55
+ declare function createSiemForwarder(config: SiemForwarderConfig): SiemForwarder;
56
+
57
+ export { type OtelLogRecord, type SiemForwarder, type SiemForwarderConfig, type SiemSink, auditEventToOtel, createSiemForwarder };
@@ -0,0 +1,102 @@
1
+ // src/integrations/siem.ts
2
+ var SEVERITY = {
3
+ success: { text: "INFO", num: 9 },
4
+ denied: { text: "WARN", num: 13 },
5
+ error: { text: "ERROR", num: 17 }
6
+ };
7
+ function attr(key, value) {
8
+ if (value === void 0 || value === null) return null;
9
+ if (typeof value === "number") return { key, value: { intValue: value } };
10
+ if (typeof value === "boolean") return { key, value: { boolValue: value } };
11
+ return { key, value: { stringValue: String(value) } };
12
+ }
13
+ function resolveTimestampMs(timestamp) {
14
+ if (!timestamp) return Date.now();
15
+ const ms = Date.parse(timestamp);
16
+ return Number.isNaN(ms) ? Date.now() : ms;
17
+ }
18
+ function auditEventToOtel(event, service = "vorim") {
19
+ const sev = SEVERITY[event.result] ?? SEVERITY.success;
20
+ const tsMs = resolveTimestampMs(event.timestamp);
21
+ const eventType = event.event_type || "unknown";
22
+ const action = event.action || "unknown";
23
+ const result = event.result || "unknown";
24
+ const attrs = [
25
+ attr("service.name", service),
26
+ attr("vorim.agent_id", event.agent_id),
27
+ attr("vorim.event_type", event.event_type),
28
+ attr("vorim.action", event.action),
29
+ attr("vorim.resource", event.resource),
30
+ attr("vorim.permission", event.permission),
31
+ attr("vorim.result", event.result),
32
+ attr("vorim.latency_ms", event.latency_ms),
33
+ attr("vorim.error_code", event.error_code),
34
+ attr("vorim.decision_id", event.decision_id),
35
+ attr("vorim.signature", event.signature ? "present" : "absent")
36
+ ].filter(Boolean);
37
+ return {
38
+ timeUnixNano: String(BigInt(Math.floor(tsMs)) * 1000000n),
39
+ severityText: sev.text,
40
+ severityNumber: sev.num,
41
+ body: { stringValue: `${eventType} ${action} \u2192 ${result}` },
42
+ attributes: attrs
43
+ };
44
+ }
45
+ function buildPayload(sink, events, service) {
46
+ if (sink === "splunk-hec") {
47
+ return events.map((e) => JSON.stringify({
48
+ time: resolveTimestampMs(e.timestamp) / 1e3,
49
+ source: "vorim",
50
+ sourcetype: "vorim:audit",
51
+ event: { ...e, service }
52
+ })).join("\n");
53
+ }
54
+ if (sink === "elasticsearch") {
55
+ return events.flatMap((e) => [JSON.stringify({ index: {} }), JSON.stringify({ ...e, service, "@timestamp": new Date(resolveTimestampMs(e.timestamp)).toISOString() })]).join("\n") + "\n";
56
+ }
57
+ return JSON.stringify({
58
+ resourceLogs: [{
59
+ resource: { attributes: [{ key: "service.name", value: { stringValue: service } }] },
60
+ scopeLogs: [{
61
+ scope: { name: "@vorim/sdk" },
62
+ logRecords: events.map((e) => auditEventToOtel(e, service))
63
+ }]
64
+ }]
65
+ });
66
+ }
67
+ function createSiemForwarder(config) {
68
+ const service = config.service ?? "vorim";
69
+ const timeoutMs = config.timeoutMs ?? 1e4;
70
+ const doFetch = config.fetchImpl ?? fetch;
71
+ const contentType = config.sink === "otlp-http" ? "application/json" : "application/json";
72
+ async function send(events) {
73
+ if (events.length === 0) return;
74
+ const body = buildPayload(config.sink, events, service);
75
+ const headers = { "Content-Type": contentType, ...config.headers ?? {} };
76
+ if (config.token) {
77
+ if (!headers.Authorization) {
78
+ headers.Authorization = config.sink === "splunk-hec" ? `Splunk ${config.token}` : config.sink === "elasticsearch" ? `ApiKey ${config.token}` : `Bearer ${config.token}`;
79
+ }
80
+ }
81
+ const controller = new AbortController();
82
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
83
+ try {
84
+ const res = await doFetch(config.endpoint, { method: "POST", headers, body, signal: controller.signal });
85
+ if (!res.ok) {
86
+ const text = await res.text().catch(() => "");
87
+ throw new Error(`SIEM forward failed: ${res.status} ${text.slice(0, 200)}`);
88
+ }
89
+ } finally {
90
+ clearTimeout(timer);
91
+ }
92
+ }
93
+ return {
94
+ forward: (event) => send([event]),
95
+ forwardBatch: (events) => send(events)
96
+ };
97
+ }
98
+ export {
99
+ auditEventToOtel,
100
+ createSiemForwarder
101
+ };
102
+ //# sourceMappingURL=siem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/integrations/siem.ts"],"sourcesContent":["// ============================================================================\n// VORIM SDK — SIEM Forwarder (OpenTelemetry / Splunk / Elastic)\n//\n// Forward Vorim's signed audit events into the tools your security team\n// already runs. This module is dependency-light: it maps an audit event to a\n// standard OpenTelemetry LogRecord and ships it over HTTP to one of three\n// sinks — an OTLP/HTTP collector, Splunk HEC, or Elasticsearch — so you do\n// not need to pull in the @opentelemetry/* packages to get audit into a SIEM.\n//\n// It is a transform + sink, not a poller: feed it the events you already\n// have (from emit(), a Vorim webhook, or an audit query) and it forwards them.\n//\n// Usage:\n// import { createSiemForwarder } from '@vorim/sdk/integrations/siem';\n//\n// const siem = createSiemForwarder({\n// sink: 'splunk-hec',\n// endpoint: 'https://splunk.example.com:8088/services/collector',\n// token: process.env.SPLUNK_HEC_TOKEN,\n// service: 'vorim-agents',\n// });\n//\n// // forward one event (e.g. inside a Vorim webhook handler)\n// await siem.forward(auditEvent);\n// // or a batch\n// await siem.forwardBatch(events);\n// ============================================================================\n\nimport type { AuditEventInput } from '../types.js';\n\nexport type SiemSink = 'otlp-http' | 'splunk-hec' | 'elasticsearch';\n\nexport interface SiemForwarderConfig {\n /** Which SIEM sink to ship to. */\n sink: SiemSink;\n /**\n * HTTP endpoint:\n * - otlp-http: your OTel collector's logs endpoint (…/v1/logs)\n * - splunk-hec: the HEC collector URL (…/services/collector)\n * - elasticsearch: the index/_bulk or _doc URL (…/vorim-audit/_doc)\n */\n endpoint: string;\n /** Auth token. Splunk HEC: the HEC token. Elastic: an API key. OTLP: bearer. */\n token?: string;\n /** Extra HTTP headers (e.g. an Authorization scheme the sink expects). */\n headers?: Record<string, string>;\n /** service.name attribute on emitted records. @default 'vorim' */\n service?: string;\n /** Request timeout in ms. @default 10000 */\n timeoutMs?: number;\n /** Custom fetch (for testing / non-global-fetch runtimes). */\n fetchImpl?: typeof fetch;\n}\n\n/** An OpenTelemetry LogRecord (JSON form) — the lingua franca for SIEM ingest. */\nexport interface OtelLogRecord {\n timeUnixNano: string;\n severityText: 'INFO' | 'WARN' | 'ERROR';\n severityNumber: number;\n body: { stringValue: string };\n attributes: { key: string; value: { stringValue?: string; intValue?: number; boolValue?: boolean } }[];\n}\n\nconst SEVERITY: Record<string, { text: OtelLogRecord['severityText']; num: number }> = {\n success: { text: 'INFO', num: 9 },\n denied: { text: 'WARN', num: 13 },\n error: { text: 'ERROR', num: 17 },\n};\n\nfunction attr(key: string, value: string | number | boolean | undefined): OtelLogRecord['attributes'][number] | null {\n if (value === undefined || value === null) return null;\n if (typeof value === 'number') return { key, value: { intValue: value } };\n if (typeof value === 'boolean') return { key, value: { boolValue: value } };\n return { key, value: { stringValue: String(value) } };\n}\n\n/**\n * Resolve an event timestamp to epoch-millis, tolerating a missing or malformed\n * `timestamp`. An unparseable ISO string (e.g. `'2026-13-32'`) would otherwise\n * yield NaN — which crashes the OTLP path (`BigInt(NaN)` throws) and serialises\n * to a null/garbage timestamp on the Splunk/ES paths. We fall back to now().\n */\nfunction resolveTimestampMs(timestamp?: string): number {\n if (!timestamp) return Date.now();\n const ms = Date.parse(timestamp);\n return Number.isNaN(ms) ? Date.now() : ms;\n}\n\n/** Map a Vorim audit event to an OTel LogRecord. Exported for testing. */\nexport function auditEventToOtel(event: AuditEventInput & { timestamp?: string; decision_id?: string }, service = 'vorim'): OtelLogRecord {\n const sev = SEVERITY[event.result] ?? SEVERITY.success;\n const tsMs = resolveTimestampMs(event.timestamp);\n // Guard the body against missing required fields (a direct SDK caller can\n // bypass the type checker); the HTTP API path is already Zod-validated.\n const eventType = event.event_type || 'unknown';\n const action = event.action || 'unknown';\n const result = event.result || 'unknown';\n const attrs = [\n attr('service.name', service),\n attr('vorim.agent_id', event.agent_id),\n attr('vorim.event_type', event.event_type),\n attr('vorim.action', event.action),\n attr('vorim.resource', event.resource),\n attr('vorim.permission', event.permission),\n attr('vorim.result', event.result),\n attr('vorim.latency_ms', event.latency_ms),\n attr('vorim.error_code', event.error_code),\n attr('vorim.decision_id', (event as any).decision_id),\n attr('vorim.signature', event.signature ? 'present' : 'absent'),\n ].filter(Boolean) as OtelLogRecord['attributes'];\n\n return {\n timeUnixNano: String(BigInt(Math.floor(tsMs)) * 1_000_000n),\n severityText: sev.text,\n severityNumber: sev.num,\n body: { stringValue: `${eventType} ${action} → ${result}` },\n attributes: attrs,\n };\n}\n\n/** Build the request body for a given sink from a batch of audit events. */\nfunction buildPayload(sink: SiemSink, events: any[], service: string): string {\n if (sink === 'splunk-hec') {\n // One HEC envelope per event (newline-delimited JSON).\n return events\n .map((e) => JSON.stringify({\n time: resolveTimestampMs(e.timestamp) / 1000,\n source: 'vorim',\n sourcetype: 'vorim:audit',\n event: { ...e, service },\n }))\n .join('\\n');\n }\n if (sink === 'elasticsearch') {\n // Bulk NDJSON: action line + doc line per event.\n return events\n .flatMap((e) => [JSON.stringify({ index: {} }), JSON.stringify({ ...e, service, '@timestamp': new Date(resolveTimestampMs(e.timestamp)).toISOString() })])\n .join('\\n') + '\\n';\n }\n // otlp-http: a single OTLP logs payload with one scope, many records.\n return JSON.stringify({\n resourceLogs: [{\n resource: { attributes: [{ key: 'service.name', value: { stringValue: service } }] },\n scopeLogs: [{\n scope: { name: '@vorim/sdk' },\n logRecords: events.map((e) => auditEventToOtel(e, service)),\n }],\n }],\n });\n}\n\nexport interface SiemForwarder {\n forward(event: AuditEventInput): Promise<void>;\n forwardBatch(events: AuditEventInput[]): Promise<void>;\n}\n\n/**\n * Create a SIEM forwarder. Errors are surfaced (the caller decides whether a\n * SIEM outage should block) — wrap in try/catch if you want fire-and-forget.\n */\nexport function createSiemForwarder(config: SiemForwarderConfig): SiemForwarder {\n const service = config.service ?? 'vorim';\n const timeoutMs = config.timeoutMs ?? 10_000;\n const doFetch = config.fetchImpl ?? fetch;\n\n const contentType = config.sink === 'otlp-http' ? 'application/json' : 'application/json';\n\n async function send(events: AuditEventInput[]): Promise<void> {\n if (events.length === 0) return;\n const body = buildPayload(config.sink, events, service);\n\n const headers: Record<string, string> = { 'Content-Type': contentType, ...(config.headers ?? {}) };\n if (config.token) {\n // Splunk HEC uses \"Authorization: Splunk <token>\"; Elastic uses \"ApiKey\";\n // OTLP collectors typically take a bearer. Default to bearer unless the\n // caller overrode Authorization via `headers`.\n if (!headers.Authorization) {\n headers.Authorization =\n config.sink === 'splunk-hec' ? `Splunk ${config.token}`\n : config.sink === 'elasticsearch' ? `ApiKey ${config.token}`\n : `Bearer ${config.token}`;\n }\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const res = await doFetch(config.endpoint, { method: 'POST', headers, body, signal: controller.signal });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`SIEM forward failed: ${res.status} ${text.slice(0, 200)}`);\n }\n } finally {\n clearTimeout(timer);\n }\n }\n\n return {\n forward: (event) => send([event]),\n forwardBatch: (events) => send(events),\n };\n}\n"],"mappings":";AA+DA,IAAM,WAAiF;AAAA,EACrF,SAAS,EAAE,MAAM,QAAQ,KAAK,EAAE;AAAA,EAChC,QAAQ,EAAE,MAAM,QAAQ,KAAK,GAAG;AAAA,EAChC,OAAO,EAAE,MAAM,SAAS,KAAK,GAAG;AAClC;AAEA,SAAS,KAAK,KAAa,OAA0F;AACnH,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO,EAAE,KAAK,OAAO,EAAE,UAAU,MAAM,EAAE;AACxE,MAAI,OAAO,UAAU,UAAW,QAAO,EAAE,KAAK,OAAO,EAAE,WAAW,MAAM,EAAE;AAC1E,SAAO,EAAE,KAAK,OAAO,EAAE,aAAa,OAAO,KAAK,EAAE,EAAE;AACtD;AAQA,SAAS,mBAAmB,WAA4B;AACtD,MAAI,CAAC,UAAW,QAAO,KAAK,IAAI;AAChC,QAAM,KAAK,KAAK,MAAM,SAAS;AAC/B,SAAO,OAAO,MAAM,EAAE,IAAI,KAAK,IAAI,IAAI;AACzC;AAGO,SAAS,iBAAiB,OAAuE,UAAU,SAAwB;AACxI,QAAM,MAAM,SAAS,MAAM,MAAM,KAAK,SAAS;AAC/C,QAAM,OAAO,mBAAmB,MAAM,SAAS;AAG/C,QAAM,YAAY,MAAM,cAAc;AACtC,QAAM,SAAS,MAAM,UAAU;AAC/B,QAAM,SAAS,MAAM,UAAU;AAC/B,QAAM,QAAQ;AAAA,IACZ,KAAK,gBAAgB,OAAO;AAAA,IAC5B,KAAK,kBAAkB,MAAM,QAAQ;AAAA,IACrC,KAAK,oBAAoB,MAAM,UAAU;AAAA,IACzC,KAAK,gBAAgB,MAAM,MAAM;AAAA,IACjC,KAAK,kBAAkB,MAAM,QAAQ;AAAA,IACrC,KAAK,oBAAoB,MAAM,UAAU;AAAA,IACzC,KAAK,gBAAgB,MAAM,MAAM;AAAA,IACjC,KAAK,oBAAoB,MAAM,UAAU;AAAA,IACzC,KAAK,oBAAoB,MAAM,UAAU;AAAA,IACzC,KAAK,qBAAsB,MAAc,WAAW;AAAA,IACpD,KAAK,mBAAmB,MAAM,YAAY,YAAY,QAAQ;AAAA,EAChE,EAAE,OAAO,OAAO;AAEhB,SAAO;AAAA,IACL,cAAc,OAAO,OAAO,KAAK,MAAM,IAAI,CAAC,IAAI,QAAU;AAAA,IAC1D,cAAc,IAAI;AAAA,IAClB,gBAAgB,IAAI;AAAA,IACpB,MAAM,EAAE,aAAa,GAAG,SAAS,IAAI,MAAM,WAAM,MAAM,GAAG;AAAA,IAC1D,YAAY;AAAA,EACd;AACF;AAGA,SAAS,aAAa,MAAgB,QAAe,SAAyB;AAC5E,MAAI,SAAS,cAAc;AAEzB,WAAO,OACJ,IAAI,CAAC,MAAM,KAAK,UAAU;AAAA,MACzB,MAAM,mBAAmB,EAAE,SAAS,IAAI;AAAA,MACxC,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,OAAO,EAAE,GAAG,GAAG,QAAQ;AAAA,IACzB,CAAC,CAAC,EACD,KAAK,IAAI;AAAA,EACd;AACA,MAAI,SAAS,iBAAiB;AAE5B,WAAO,OACJ,QAAQ,CAAC,MAAM,CAAC,KAAK,UAAU,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,KAAK,UAAU,EAAE,GAAG,GAAG,SAAS,cAAc,IAAI,KAAK,mBAAmB,EAAE,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EACxJ,KAAK,IAAI,IAAI;AAAA,EAClB;AAEA,SAAO,KAAK,UAAU;AAAA,IACpB,cAAc,CAAC;AAAA,MACb,UAAU,EAAE,YAAY,CAAC,EAAE,KAAK,gBAAgB,OAAO,EAAE,aAAa,QAAQ,EAAE,CAAC,EAAE;AAAA,MACnF,WAAW,CAAC;AAAA,QACV,OAAO,EAAE,MAAM,aAAa;AAAA,QAC5B,YAAY,OAAO,IAAI,CAAC,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAAA,MAC5D,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;AAWO,SAAS,oBAAoB,QAA4C;AAC9E,QAAM,UAAU,OAAO,WAAW;AAClC,QAAM,YAAY,OAAO,aAAa;AACtC,QAAM,UAAU,OAAO,aAAa;AAEpC,QAAM,cAAc,OAAO,SAAS,cAAc,qBAAqB;AAEvE,iBAAe,KAAK,QAA0C;AAC5D,QAAI,OAAO,WAAW,EAAG;AACzB,UAAM,OAAO,aAAa,OAAO,MAAM,QAAQ,OAAO;AAEtD,UAAM,UAAkC,EAAE,gBAAgB,aAAa,GAAI,OAAO,WAAW,CAAC,EAAG;AACjG,QAAI,OAAO,OAAO;AAIhB,UAAI,CAAC,QAAQ,eAAe;AAC1B,gBAAQ,gBACN,OAAO,SAAS,eAAe,UAAU,OAAO,KAAK,KACnD,OAAO,SAAS,kBAAkB,UAAU,OAAO,KAAK,KACxD,UAAU,OAAO,KAAK;AAAA,MAC5B;AAAA,IACF;AAEA,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAC5D,QAAI;AACF,YAAM,MAAM,MAAM,QAAQ,OAAO,UAAU,EAAE,QAAQ,QAAQ,SAAS,MAAM,QAAQ,WAAW,OAAO,CAAC;AACvG,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,cAAM,IAAI,MAAM,wBAAwB,IAAI,MAAM,IAAI,KAAK,MAAM,GAAG,GAAG,CAAC,EAAE;AAAA,MAC5E;AAAA,IACF,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS,CAAC,UAAU,KAAK,CAAC,KAAK,CAAC;AAAA,IAChC,cAAc,CAAC,WAAW,KAAK,MAAM;AAAA,EACvC;AACF;","names":[]}
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/integrations/stripe-acp.ts
21
+ var stripe_acp_exports = {};
22
+ __export(stripe_acp_exports, {
23
+ VorimACP: () => VorimACP,
24
+ createVorimACP: () => createVorimACP
25
+ });
26
+ module.exports = __toCommonJS(stripe_acp_exports);
27
+ var VorimACP = class {
28
+ sdk;
29
+ minTrustScore;
30
+ requiredScope;
31
+ constructor(sdk, config) {
32
+ this.sdk = sdk;
33
+ this.minTrustScore = config?.minTrustScore ?? 50;
34
+ this.requiredScope = config?.requiredScope ?? "agent:transact";
35
+ }
36
+ /**
37
+ * Verify an agent is authorized to initiate a checkout.
38
+ */
39
+ async authorizeCheckout(req) {
40
+ const threshold = req.minTrustScore ?? this.minTrustScore;
41
+ try {
42
+ const perm = await this.sdk.check(req.agentId, this.requiredScope);
43
+ if (!perm.allowed) {
44
+ await this.logEvent(req.agentId, "checkout.authorize", "denied", req, { reason: `Missing ${this.requiredScope}` });
45
+ return {
46
+ authorized: false,
47
+ agentId: req.agentId,
48
+ trustScore: 0,
49
+ status: "unknown",
50
+ reason: `Agent does not have ${this.requiredScope} permission`,
51
+ scopeVerified: false
52
+ };
53
+ }
54
+ } catch (e) {
55
+ await this.logEvent(req.agentId, "checkout.authorize", "denied", req, { reason: e.message });
56
+ return {
57
+ authorized: false,
58
+ agentId: req.agentId,
59
+ trustScore: 0,
60
+ status: "unknown",
61
+ reason: `Permission check failed: ${e.message}`,
62
+ scopeVerified: false
63
+ };
64
+ }
65
+ let score = 0;
66
+ let status = "unknown";
67
+ try {
68
+ const trust = await this.sdk.verify(req.agentId);
69
+ score = trust.trust_score ?? 0;
70
+ status = trust.status ?? "unknown";
71
+ } catch {
72
+ }
73
+ if (status !== "active") {
74
+ await this.logEvent(req.agentId, "checkout.authorize", "denied", req, { reason: `Status: ${status}` });
75
+ return {
76
+ authorized: false,
77
+ agentId: req.agentId,
78
+ trustScore: score,
79
+ status,
80
+ reason: `Agent is ${status}, not active`,
81
+ scopeVerified: true
82
+ };
83
+ }
84
+ if (score < threshold) {
85
+ await this.logEvent(req.agentId, "checkout.authorize", "denied", req, { reason: `Score ${score} < ${threshold}` });
86
+ return {
87
+ authorized: false,
88
+ agentId: req.agentId,
89
+ trustScore: score,
90
+ status,
91
+ reason: `Trust score ${score} is below minimum ${threshold}`,
92
+ scopeVerified: true
93
+ };
94
+ }
95
+ await this.logEvent(req.agentId, "checkout.authorize", "success", req, { trust_score: score });
96
+ return {
97
+ authorized: true,
98
+ agentId: req.agentId,
99
+ trustScore: score,
100
+ status,
101
+ scopeVerified: true
102
+ };
103
+ }
104
+ /**
105
+ * Log a checkout lifecycle event.
106
+ */
107
+ async logCheckoutCreated(agentId, checkoutId, seller, amount) {
108
+ await this.logEvent(agentId, "checkout.created", "success", { agentId, seller, amount }, { checkout_id: checkoutId });
109
+ }
110
+ async logCheckoutCompleted(agentId, checkoutId, seller, amount) {
111
+ await this.logEvent(agentId, "checkout.completed", "success", { agentId, seller, amount }, { checkout_id: checkoutId });
112
+ }
113
+ async logCheckoutCanceled(agentId, checkoutId, reason) {
114
+ await this.logEvent(agentId, "checkout.canceled", "success", { agentId }, { checkout_id: checkoutId, cancel_reason: reason });
115
+ }
116
+ /**
117
+ * Express/Connect middleware that requires transact permission.
118
+ */
119
+ middleware(options) {
120
+ const header = options?.agentIdHeader ?? "x-vorim-agent-id";
121
+ const threshold = options?.minTrustScore ?? this.minTrustScore;
122
+ return async (req, res, next) => {
123
+ const agentId = req.headers?.[header] || req.headers?.[header.toLowerCase()] || "";
124
+ if (!agentId) {
125
+ res.status(401).json({
126
+ error: { code: "MISSING_AGENT_ID", message: `Agent ID required in ${header} header` }
127
+ });
128
+ return;
129
+ }
130
+ const auth = await this.authorizeCheckout({
131
+ agentId,
132
+ seller: req.body?.seller || "",
133
+ amount: req.body?.amount || 0,
134
+ currency: req.body?.currency || "usd",
135
+ minTrustScore: threshold
136
+ });
137
+ if (!auth.authorized) {
138
+ res.status(403).json({
139
+ error: {
140
+ code: "UNAUTHORIZED_AGENT",
141
+ message: auth.reason || "Agent not authorized for transactions",
142
+ trust_score: auth.trustScore,
143
+ status: auth.status
144
+ }
145
+ });
146
+ return;
147
+ }
148
+ req.vorimAuthorization = auth;
149
+ next();
150
+ };
151
+ }
152
+ async logEvent(agentId, action, result, req, metadata) {
153
+ try {
154
+ await this.sdk.emit({
155
+ agent_id: agentId,
156
+ event_type: "api_request",
157
+ action,
158
+ result,
159
+ resource: req?.seller || "",
160
+ metadata: {
161
+ seller: req?.seller || "",
162
+ amount: req?.amount || 0,
163
+ currency: req?.currency || "",
164
+ ...metadata
165
+ }
166
+ });
167
+ } catch {
168
+ }
169
+ }
170
+ };
171
+ function createVorimACP(sdk, config) {
172
+ return new VorimACP(sdk, config);
173
+ }
174
+ // Annotate the CommonJS export names for ESM import in node:
175
+ 0 && (module.exports = {
176
+ VorimACP,
177
+ createVorimACP
178
+ });
179
+ //# sourceMappingURL=stripe-acp.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/integrations/stripe-acp.ts"],"sourcesContent":["// ============================================================================\n// Vorim AI — Stripe Agentic Commerce Protocol (ACP) Integration\n//\n// Adds agent identity verification and permission checking before agents can\n// initiate payments via Stripe ACP. Ensures only authorized agents with the\n// 'transact' permission scope can create checkouts and complete purchases.\n//\n// Usage:\n// import { createVorimACP } from '@vorim/sdk/integrations/stripe-acp';\n//\n// const acp = createVorimACP({ apiKey: 'agid_sk_...', minTrustScore: 60 });\n//\n// // Before creating a Stripe ACP checkout\n// const auth = await acp.authorizeCheckout({\n// agentId: 'agid_abc123',\n// seller: 'acme-store',\n// amount: 9999,\n// currency: 'usd',\n// });\n//\n// if (auth.authorized) {\n// // Proceed with Stripe checkout\n// }\n//\n// // Express middleware\n// app.post('/checkouts', acp.middleware(), (req, res) => {\n// // Only reached if agent has transact permission + trust score passes\n// });\n// ============================================================================\n\nimport type { VorimSDK } from '../index.js';\n\nexport interface ACPConfig {\n apiKey: string;\n baseUrl?: string;\n minTrustScore?: number;\n requiredScope?: string;\n}\n\nexport interface CheckoutAuthorizationRequest {\n agentId: string;\n seller?: string;\n amount?: number;\n currency?: string;\n minTrustScore?: number;\n}\n\nexport interface CheckoutAuthorization {\n authorized: boolean;\n agentId: string;\n trustScore: number;\n status: string;\n reason?: string;\n scopeVerified: boolean;\n}\n\nexport class VorimACP {\n private sdk: VorimSDK;\n private minTrustScore: number;\n private requiredScope: string;\n\n constructor(sdk: VorimSDK, config?: Partial<ACPConfig>) {\n this.sdk = sdk;\n this.minTrustScore = config?.minTrustScore ?? 50;\n this.requiredScope = config?.requiredScope ?? 'agent:transact';\n }\n\n /**\n * Verify an agent is authorized to initiate a checkout.\n */\n async authorizeCheckout(req: CheckoutAuthorizationRequest): Promise<CheckoutAuthorization> {\n const threshold = req.minTrustScore ?? this.minTrustScore;\n\n // Check transact permission\n try {\n const perm = await this.sdk.check(req.agentId, this.requiredScope as any);\n if (!(perm as any).allowed) {\n await this.logEvent(req.agentId, 'checkout.authorize', 'denied', req, { reason: `Missing ${this.requiredScope}` });\n return {\n authorized: false,\n agentId: req.agentId,\n trustScore: 0,\n status: 'unknown',\n reason: `Agent does not have ${this.requiredScope} permission`,\n scopeVerified: false,\n };\n }\n } catch (e: any) {\n await this.logEvent(req.agentId, 'checkout.authorize', 'denied', req, { reason: e.message });\n return {\n authorized: false,\n agentId: req.agentId,\n trustScore: 0,\n status: 'unknown',\n reason: `Permission check failed: ${e.message}`,\n scopeVerified: false,\n };\n }\n\n // Verify trust score\n let score = 0;\n let status = 'unknown';\n try {\n const trust = await this.sdk.verify(req.agentId);\n score = (trust as any).trust_score ?? 0;\n status = (trust as any).status ?? 'unknown';\n } catch {\n // Trust verification failed\n }\n\n if (status !== 'active') {\n await this.logEvent(req.agentId, 'checkout.authorize', 'denied', req, { reason: `Status: ${status}` });\n return {\n authorized: false,\n agentId: req.agentId,\n trustScore: score,\n status,\n reason: `Agent is ${status}, not active`,\n scopeVerified: true,\n };\n }\n\n if (score < threshold) {\n await this.logEvent(req.agentId, 'checkout.authorize', 'denied', req, { reason: `Score ${score} < ${threshold}` });\n return {\n authorized: false,\n agentId: req.agentId,\n trustScore: score,\n status,\n reason: `Trust score ${score} is below minimum ${threshold}`,\n scopeVerified: true,\n };\n }\n\n await this.logEvent(req.agentId, 'checkout.authorize', 'success', req, { trust_score: score });\n\n return {\n authorized: true,\n agentId: req.agentId,\n trustScore: score,\n status,\n scopeVerified: true,\n };\n }\n\n /**\n * Log a checkout lifecycle event.\n */\n async logCheckoutCreated(agentId: string, checkoutId: string, seller?: string, amount?: number): Promise<void> {\n await this.logEvent(agentId, 'checkout.created', 'success', { agentId, seller, amount }, { checkout_id: checkoutId });\n }\n\n async logCheckoutCompleted(agentId: string, checkoutId: string, seller?: string, amount?: number): Promise<void> {\n await this.logEvent(agentId, 'checkout.completed', 'success', { agentId, seller, amount }, { checkout_id: checkoutId });\n }\n\n async logCheckoutCanceled(agentId: string, checkoutId: string, reason?: string): Promise<void> {\n await this.logEvent(agentId, 'checkout.canceled', 'success', { agentId }, { checkout_id: checkoutId, cancel_reason: reason });\n }\n\n /**\n * Express/Connect middleware that requires transact permission.\n */\n middleware(options?: { agentIdHeader?: string; minTrustScore?: number }) {\n const header = options?.agentIdHeader ?? 'x-vorim-agent-id';\n const threshold = options?.minTrustScore ?? this.minTrustScore;\n\n return async (req: any, res: any, next: any) => {\n const agentId = req.headers?.[header] || req.headers?.[header.toLowerCase()] || '';\n\n if (!agentId) {\n res.status(401).json({\n error: { code: 'MISSING_AGENT_ID', message: `Agent ID required in ${header} header` },\n });\n return;\n }\n\n const auth = await this.authorizeCheckout({\n agentId,\n seller: req.body?.seller || '',\n amount: req.body?.amount || 0,\n currency: req.body?.currency || 'usd',\n minTrustScore: threshold,\n });\n\n if (!auth.authorized) {\n res.status(403).json({\n error: {\n code: 'UNAUTHORIZED_AGENT',\n message: auth.reason || 'Agent not authorized for transactions',\n trust_score: auth.trustScore,\n status: auth.status,\n },\n });\n return;\n }\n\n req.vorimAuthorization = auth;\n next();\n };\n }\n\n private async logEvent(\n agentId: string,\n action: string,\n result: 'success' | 'denied' | 'error',\n req?: any,\n metadata?: Record<string, any>,\n ): Promise<void> {\n try {\n // Use the canonical audit-event contract: event_type from the\n // AuditEventType enum ('api_request' for a payment authorization) and\n // `result` (not the non-existent `outcome`) from the AuditResult enum.\n await this.sdk.emit({\n agent_id: agentId,\n event_type: 'api_request',\n action,\n result,\n resource: req?.seller || '',\n metadata: {\n seller: req?.seller || '',\n amount: req?.amount || 0,\n currency: req?.currency || '',\n ...metadata,\n },\n });\n } catch {\n // Don't block commerce flow\n }\n }\n}\n\n/**\n * Create a VorimACP instance.\n *\n * @example\n * ```typescript\n * import createVorim from '@vorim/sdk';\n * import { createVorimACP } from '@vorim/sdk/integrations/stripe-acp';\n *\n * const vorim = createVorim({ apiKey: 'agid_sk_...' });\n * const acp = createVorimACP(vorim, { minTrustScore: 70 });\n *\n * // Verify before checkout\n * const auth = await acp.authorizeCheckout({ agentId: 'agid_abc123', seller: 'shop', amount: 4999 });\n *\n * // Express middleware\n * app.post('/checkouts', acp.middleware(), createCheckoutHandler);\n * ```\n */\nexport function createVorimACP(sdk: VorimSDK, config?: Partial<ACPConfig>): VorimACP {\n return new VorimACP(sdk, config);\n}\n"],"mappings":"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","names":[]}