@vorionsys/proof-plane 0.1.0 → 0.1.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.
package/README.md ADDED
@@ -0,0 +1,174 @@
1
+ # @vorionsys/proof-plane
2
+
3
+ Immutable audit trail for AI agent operations. Provides hash-chained, cryptographically signed event logging for compliance, debugging, and trust verification.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @vorionsys/proof-plane
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { createProofPlane, createInMemoryEventStore } from '@vorionsys/proof-plane';
15
+
16
+ const store = createInMemoryEventStore();
17
+ const proofPlane = createProofPlane({
18
+ signedBy: 'my-service',
19
+ store,
20
+ });
21
+
22
+ // Log events
23
+ await proofPlane.logIntentReceived(intent);
24
+ await proofPlane.logDecisionMade(decision);
25
+
26
+ // Query events by correlation ID
27
+ const trace = await proofPlane.getTrace(correlationId);
28
+
29
+ // Verify hash chain integrity
30
+ const verification = await proofPlane.verifyChain();
31
+ console.log(verification.valid); // true
32
+ ```
33
+
34
+ ## Features
35
+
36
+ - **Hash-Chained Events**: Every event links to the previous via SHA-256, forming a tamper-evident chain
37
+ - **Cryptographic Signatures**: Ed25519 event signing with key pair generation and batch verification
38
+ - **Pluggable Storage**: Abstract `ProofEventStore` interface - bring your own database
39
+ - **Event Emitter**: Typed event system with batch emit support
40
+ - **Trace Queries**: Retrieve full event traces by correlation ID
41
+ - **Chain Verification**: Verify integrity of the entire hash chain with detailed reports
42
+ - **API Routes**: Pre-built Express/Fastify route handlers for proof endpoints
43
+
44
+ ## Subpath Imports
45
+
46
+ ```typescript
47
+ // Core proof plane
48
+ import { createProofPlane, ProofPlane } from '@vorionsys/proof-plane';
49
+
50
+ // Event stores
51
+ import { InMemoryEventStore } from '@vorionsys/proof-plane/events';
52
+
53
+ // Proof plane internals
54
+ import { ProofPlane } from '@vorionsys/proof-plane/proof-plane';
55
+
56
+ // API route handlers
57
+ import { createProofRoutes } from '@vorionsys/proof-plane/api';
58
+ ```
59
+
60
+ ## API Reference
61
+
62
+ ### ProofPlane
63
+
64
+ ```typescript
65
+ const plane = createProofPlane({
66
+ signedBy: 'service-name', // Identifier for the signing service
67
+ store: eventStore, // ProofEventStore implementation
68
+ });
69
+
70
+ // Log lifecycle events
71
+ await plane.logIntentReceived(intent);
72
+ await plane.logDecisionMade(decision);
73
+
74
+ // Query
75
+ const trace = await plane.getTrace(correlationId);
76
+ const events = await plane.queryEvents({ limit: 100, offset: 0 });
77
+
78
+ // Verify chain
79
+ const result = await plane.verifyChain();
80
+ // { valid: boolean, checkedCount: number, errors: string[] }
81
+ ```
82
+
83
+ ### Hash Chain
84
+
85
+ ```typescript
86
+ import {
87
+ sha256,
88
+ computeEventHash,
89
+ verifyEventHash,
90
+ verifyChain,
91
+ verifyChainWithDetails,
92
+ } from '@vorionsys/proof-plane';
93
+
94
+ const hash = sha256(data);
95
+ const eventHash = computeEventHash(event);
96
+ const isValid = verifyEventHash(event);
97
+ const chainResult = verifyChainWithDetails(events);
98
+ ```
99
+
100
+ ### Event Signatures
101
+
102
+ ```typescript
103
+ import {
104
+ generateSigningKeyPair,
105
+ signEvent,
106
+ verifyEventSignature,
107
+ EventSigningService,
108
+ } from '@vorionsys/proof-plane';
109
+
110
+ // Generate keys
111
+ const keyPair = await generateSigningKeyPair();
112
+
113
+ // Sign an event
114
+ const signature = await signEvent(event, keyPair.privateKey);
115
+
116
+ // Verify
117
+ const isValid = await verifyEventSignature(event, signature, keyPair.publicKey);
118
+
119
+ // Or use the service
120
+ const signer = createSigningService({ keyPair });
121
+ const signed = await signer.sign(event);
122
+ ```
123
+
124
+ ### Event Store
125
+
126
+ Implement the `ProofEventStore` interface for custom storage:
127
+
128
+ ```typescript
129
+ import type { ProofEventStore, EventQueryOptions } from '@vorionsys/proof-plane';
130
+
131
+ class MyEventStore implements ProofEventStore {
132
+ async append(event) { /* ... */ }
133
+ async getByCorrelationId(id) { /* ... */ }
134
+ async query(options: EventQueryOptions) { /* ... */ }
135
+ async getStats() { /* ... */ }
136
+ async getChain(options) { /* ... */ }
137
+ }
138
+ ```
139
+
140
+ ### API Routes
141
+
142
+ ```typescript
143
+ import { createProofRoutes, registerProofRoutes } from '@vorionsys/proof-plane';
144
+
145
+ // Fastify
146
+ registerProofRoutes(fastifyApp, { store });
147
+
148
+ // Express
149
+ import { createProofExpressRouter } from '@vorionsys/proof-plane';
150
+ app.use('/proof', createProofExpressRouter({ store }));
151
+ ```
152
+
153
+ ## TypeScript
154
+
155
+ ```typescript
156
+ import type {
157
+ ProofPlaneConfig,
158
+ ProofPlaneLogger,
159
+ ProofEventStore,
160
+ EventQueryOptions,
161
+ EventQueryResult,
162
+ EventStats,
163
+ EventEmitterConfig,
164
+ EventListener,
165
+ EmitResult,
166
+ ChainVerificationResult,
167
+ SigningKeyPair,
168
+ SignatureVerificationResult,
169
+ } from '@vorionsys/proof-plane';
170
+ ```
171
+
172
+ ## License
173
+
174
+ MIT
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Proof Plane API Module
3
+ *
4
+ * Provides REST API routes for the Vorion audit system.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ export { createProofRoutes, registerProofRoutes, createProofExpressRouter, type ProofRoute, } from './routes.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,UAAU,GAChB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Proof Plane API Module
3
+ *
4
+ * Provides REST API routes for the Vorion audit system.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ export { createProofRoutes, registerProofRoutes, createProofExpressRouter, } from './routes.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,GAEzB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Proof Plane API Routes
3
+ *
4
+ * Provides REST API endpoints for the Vorion audit system:
5
+ * - POST /proof - Submit a proof event
6
+ * - GET /proof/:id - Retrieve proof event by ID
7
+ * - GET /proof/verify/:id - Verify a single proof event
8
+ * - GET /proof/chain/:correlationId - Get event trace by correlation ID
9
+ * - POST /proof/chain/verify - Verify chain integrity
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ import { z } from 'zod';
14
+ import type { ProofPlane } from '../proof-plane/proof-plane.js';
15
+ /**
16
+ * Route handler context - generic interface for Fastify-like frameworks
17
+ */
18
+ interface RouteContext {
19
+ request: {
20
+ params?: unknown;
21
+ query?: unknown;
22
+ body?: unknown;
23
+ id?: string;
24
+ };
25
+ reply: {
26
+ status(code: number): RouteContext['reply'];
27
+ send(data: unknown): void;
28
+ };
29
+ }
30
+ /**
31
+ * Route definition for registration
32
+ */
33
+ export interface ProofRoute {
34
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
35
+ path: string;
36
+ handler: (ctx: RouteContext, proofPlane: ProofPlane) => Promise<void>;
37
+ schema?: {
38
+ params?: z.ZodSchema;
39
+ query?: z.ZodSchema;
40
+ body?: z.ZodSchema;
41
+ };
42
+ }
43
+ /**
44
+ * Define all proof API routes
45
+ */
46
+ export declare function createProofRoutes(proofPlane: ProofPlane): ProofRoute[];
47
+ /**
48
+ * Fastify plugin registration helper
49
+ *
50
+ * Usage with Fastify:
51
+ * ```typescript
52
+ * import Fastify from 'fastify';
53
+ * import { createProofPlane } from '@vorionsys/proof-plane';
54
+ * import { registerProofRoutes } from '@vorionsys/proof-plane/api';
55
+ *
56
+ * const app = Fastify();
57
+ * const proofPlane = createProofPlane({ signedBy: 'my-service' });
58
+ *
59
+ * await app.register(async (instance) => {
60
+ * registerProofRoutes(instance, proofPlane);
61
+ * }, { prefix: '/v1' });
62
+ * ```
63
+ */
64
+ export declare function registerProofRoutes(fastify: {
65
+ get: (path: string, handler: (request: any, reply: any) => Promise<void>) => void;
66
+ post: (path: string, handler: (request: any, reply: any) => Promise<void>) => void;
67
+ }, proofPlane: ProofPlane): void;
68
+ /**
69
+ * Express middleware adapter
70
+ *
71
+ * Usage with Express:
72
+ * ```typescript
73
+ * import express from 'express';
74
+ * import { createProofPlane } from '@vorionsys/proof-plane';
75
+ * import { createProofExpressRouter } from '@vorionsys/proof-plane/api';
76
+ *
77
+ * const app = express();
78
+ * const proofPlane = createProofPlane({ signedBy: 'my-service' });
79
+ *
80
+ * app.use('/v1', createProofExpressRouter(proofPlane));
81
+ * ```
82
+ */
83
+ export declare function createProofExpressRouter(proofPlane: ProofPlane): {
84
+ routes: ProofRoute[];
85
+ handler: (req: any, res: any, next: any) => Promise<void>;
86
+ };
87
+ export {};
88
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAiEhE;;GAEG;AACH,UAAU,YAAY;IACpB,OAAO,EAAE;QACP,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,EAAE,CAAC,EAAE,MAAM,CAAC;KACb,CAAC;IACF,KAAK,EAAE;QACL,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;KAC3B,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;QACrB,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;QACpB,IAAI,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;KACpB,CAAC;CACH;AA4BD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,EAAE,CAuPtE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE;IACP,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;IAClF,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;CACpF,EACD,UAAU,EAAE,UAAU,GACrB,IAAI,CA0CN;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,UAAU,GAAG;IAChE,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D,CA+CA"}
@@ -0,0 +1,399 @@
1
+ /**
2
+ * Proof Plane API Routes
3
+ *
4
+ * Provides REST API endpoints for the Vorion audit system:
5
+ * - POST /proof - Submit a proof event
6
+ * - GET /proof/:id - Retrieve proof event by ID
7
+ * - GET /proof/verify/:id - Verify a single proof event
8
+ * - GET /proof/chain/:correlationId - Get event trace by correlation ID
9
+ * - POST /proof/chain/verify - Verify chain integrity
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ import { z } from 'zod';
14
+ import { ProofEventType } from '@vorionsys/contracts';
15
+ /**
16
+ * Zod schema for proof event submission
17
+ */
18
+ const submitProofSchema = z.object({
19
+ eventType: z.nativeEnum(ProofEventType),
20
+ correlationId: z.string().uuid(),
21
+ agentId: z.string().uuid().optional(),
22
+ payload: z.record(z.unknown()),
23
+ });
24
+ /**
25
+ * Zod schema for event ID parameter
26
+ */
27
+ const eventIdParamsSchema = z.object({
28
+ id: z.string().uuid(),
29
+ });
30
+ /**
31
+ * Zod schema for correlation ID parameter
32
+ */
33
+ const correlationIdParamsSchema = z.object({
34
+ correlationId: z.string().uuid(),
35
+ });
36
+ /**
37
+ * Zod schema for chain verification request
38
+ */
39
+ const verifyChainBodySchema = z.object({
40
+ fromEventId: z.string().uuid().optional(),
41
+ limit: z.number().int().min(1).max(10000).optional(),
42
+ });
43
+ /**
44
+ * Zod schema for query options
45
+ */
46
+ const queryOptionsSchema = z.object({
47
+ limit: z.coerce.number().int().min(1).max(1000).optional(),
48
+ offset: z.coerce.number().int().min(0).optional(),
49
+ });
50
+ /**
51
+ * Create success response
52
+ */
53
+ function success(data, requestId) {
54
+ return {
55
+ data,
56
+ meta: {
57
+ requestId,
58
+ timestamp: new Date().toISOString(),
59
+ },
60
+ };
61
+ }
62
+ /**
63
+ * Create error response
64
+ */
65
+ function error(code, message, details) {
66
+ return {
67
+ error: {
68
+ code,
69
+ message,
70
+ details,
71
+ },
72
+ };
73
+ }
74
+ /**
75
+ * Define all proof API routes
76
+ */
77
+ export function createProofRoutes(proofPlane) {
78
+ return [
79
+ // POST /proof - Submit a new proof event
80
+ {
81
+ method: 'POST',
82
+ path: '/proof',
83
+ schema: { body: submitProofSchema },
84
+ handler: async (ctx) => {
85
+ const body = submitProofSchema.parse(ctx.request.body ?? {});
86
+ try {
87
+ const result = await proofPlane.logEvent(body.eventType, body.correlationId, body.payload, body.agentId);
88
+ ctx.reply.status(201).send(success({
89
+ eventId: result.event.eventId,
90
+ eventType: result.event.eventType,
91
+ correlationId: result.event.correlationId,
92
+ eventHash: result.event.eventHash,
93
+ previousHash: result.event.previousHash,
94
+ occurredAt: result.event.occurredAt,
95
+ recordedAt: result.event.recordedAt,
96
+ }, ctx.request.id));
97
+ }
98
+ catch (err) {
99
+ ctx.reply.status(500).send(error('EMIT_FAILED', 'Failed to emit proof event', {
100
+ message: err instanceof Error ? err.message : String(err),
101
+ }));
102
+ }
103
+ },
104
+ },
105
+ // GET /proof/:id - Get proof event by ID
106
+ {
107
+ method: 'GET',
108
+ path: '/proof/:id',
109
+ schema: { params: eventIdParamsSchema },
110
+ handler: async (ctx) => {
111
+ const params = eventIdParamsSchema.parse(ctx.request.params ?? {});
112
+ const event = await proofPlane.getEvent(params.id);
113
+ if (!event) {
114
+ ctx.reply.status(404).send(error('EVENT_NOT_FOUND', `Proof event ${params.id} not found`));
115
+ return;
116
+ }
117
+ ctx.reply.status(200).send(success(event, ctx.request.id));
118
+ },
119
+ },
120
+ // GET /proof/verify/:id - Verify a single proof event
121
+ {
122
+ method: 'GET',
123
+ path: '/proof/verify/:id',
124
+ schema: { params: eventIdParamsSchema },
125
+ handler: async (ctx) => {
126
+ const params = eventIdParamsSchema.parse(ctx.request.params ?? {});
127
+ const event = await proofPlane.getEvent(params.id);
128
+ if (!event) {
129
+ ctx.reply.status(404).send(error('EVENT_NOT_FOUND', `Proof event ${params.id} not found`));
130
+ return;
131
+ }
132
+ // Verify hash integrity
133
+ const { computeEventHash } = await import('../events/hash-chain.js');
134
+ const computedHash = await computeEventHash(event);
135
+ const hashValid = computedHash === event.eventHash;
136
+ // Verify signature if present
137
+ let signatureResult = null;
138
+ if (event.signature && proofPlane.isSignatureVerificationEnabled()) {
139
+ signatureResult = await proofPlane.verifyEventSignature(event);
140
+ }
141
+ ctx.reply.status(200).send(success({
142
+ eventId: event.eventId,
143
+ verification: {
144
+ hashValid,
145
+ computedHash,
146
+ storedHash: event.eventHash,
147
+ signatureValid: signatureResult?.valid ?? null,
148
+ signatureError: signatureResult?.error,
149
+ signer: signatureResult?.signer,
150
+ verifiedAt: new Date().toISOString(),
151
+ },
152
+ }, ctx.request.id));
153
+ },
154
+ },
155
+ // GET /proof/chain/:correlationId - Get event trace by correlation ID
156
+ {
157
+ method: 'GET',
158
+ path: '/proof/chain/:correlationId',
159
+ schema: {
160
+ params: correlationIdParamsSchema,
161
+ query: queryOptionsSchema,
162
+ },
163
+ handler: async (ctx) => {
164
+ const params = correlationIdParamsSchema.parse(ctx.request.params ?? {});
165
+ const query = queryOptionsSchema.parse(ctx.request.query ?? {});
166
+ const events = await proofPlane.getTrace(params.correlationId);
167
+ if (events.length === 0) {
168
+ ctx.reply.status(404).send(error('TRACE_NOT_FOUND', `No events found for correlation ${params.correlationId}`));
169
+ return;
170
+ }
171
+ // Apply pagination
172
+ const offset = query.offset ?? 0;
173
+ const limit = query.limit ?? 100;
174
+ const paginatedEvents = events.slice(offset, offset + limit);
175
+ ctx.reply.status(200).send(success({
176
+ correlationId: params.correlationId,
177
+ events: paginatedEvents,
178
+ total: events.length,
179
+ pagination: {
180
+ offset,
181
+ limit,
182
+ hasMore: offset + limit < events.length,
183
+ },
184
+ }, ctx.request.id));
185
+ },
186
+ },
187
+ // POST /proof/chain/verify - Verify chain integrity
188
+ {
189
+ method: 'POST',
190
+ path: '/proof/chain/verify',
191
+ schema: { body: verifyChainBodySchema },
192
+ handler: async (ctx) => {
193
+ const body = verifyChainBodySchema.parse(ctx.request.body ?? {});
194
+ const chainResult = await proofPlane.verifyChain(body.fromEventId, body.limit);
195
+ // Optionally verify signatures
196
+ let signaturesResult = null;
197
+ if (proofPlane.isSignatureVerificationEnabled()) {
198
+ const fullResult = await proofPlane.verifyChainAndSignatures(body.fromEventId, body.limit);
199
+ signaturesResult = fullResult.signatures;
200
+ }
201
+ ctx.reply.status(200).send(success({
202
+ chain: {
203
+ valid: chainResult.valid,
204
+ verifiedCount: chainResult.verifiedCount,
205
+ totalEvents: chainResult.totalEvents,
206
+ firstEventId: chainResult.firstEventId,
207
+ lastEventId: chainResult.lastEventId,
208
+ brokenAtEventId: chainResult.brokenAtEventId,
209
+ brokenAtIndex: chainResult.brokenAtIndex,
210
+ error: chainResult.error,
211
+ },
212
+ signatures: signaturesResult
213
+ ? {
214
+ totalEvents: signaturesResult.totalEvents,
215
+ validCount: signaturesResult.validCount,
216
+ invalidCount: signaturesResult.invalidCount,
217
+ unsignedCount: signaturesResult.unsignedCount,
218
+ success: signaturesResult.success,
219
+ }
220
+ : null,
221
+ fullyVerified: chainResult.valid && (signaturesResult?.success ?? true),
222
+ verifiedAt: new Date().toISOString(),
223
+ }, ctx.request.id));
224
+ },
225
+ },
226
+ // GET /proof/stats - Get event statistics
227
+ {
228
+ method: 'GET',
229
+ path: '/proof/stats',
230
+ handler: async (ctx) => {
231
+ const stats = await proofPlane.getStats();
232
+ ctx.reply.status(200).send(success({
233
+ totalEvents: stats.totalEvents,
234
+ eventsByType: stats.byType,
235
+ eventsByAgent: stats.byAgent,
236
+ oldestEvent: stats.oldestEvent,
237
+ newestEvent: stats.newestEvent,
238
+ shadowModeStats: stats.byShadowMode,
239
+ }, ctx.request.id));
240
+ },
241
+ },
242
+ // GET /proof/latest - Get most recent event
243
+ {
244
+ method: 'GET',
245
+ path: '/proof/latest',
246
+ handler: async (ctx) => {
247
+ const event = await proofPlane.getLatestEvent();
248
+ if (!event) {
249
+ ctx.reply.status(404).send(error('NO_EVENTS', 'No proof events recorded yet'));
250
+ return;
251
+ }
252
+ ctx.reply.status(200).send(success(event, ctx.request.id));
253
+ },
254
+ },
255
+ ];
256
+ }
257
+ /**
258
+ * Fastify plugin registration helper
259
+ *
260
+ * Usage with Fastify:
261
+ * ```typescript
262
+ * import Fastify from 'fastify';
263
+ * import { createProofPlane } from '@vorionsys/proof-plane';
264
+ * import { registerProofRoutes } from '@vorionsys/proof-plane/api';
265
+ *
266
+ * const app = Fastify();
267
+ * const proofPlane = createProofPlane({ signedBy: 'my-service' });
268
+ *
269
+ * await app.register(async (instance) => {
270
+ * registerProofRoutes(instance, proofPlane);
271
+ * }, { prefix: '/v1' });
272
+ * ```
273
+ */
274
+ export function registerProofRoutes(fastify, proofPlane) {
275
+ const routes = createProofRoutes(proofPlane);
276
+ for (const route of routes) {
277
+ const handler = async (request, reply) => {
278
+ const ctx = {
279
+ request: {
280
+ params: request.params,
281
+ query: request.query,
282
+ body: request.body,
283
+ id: request.id,
284
+ },
285
+ reply: {
286
+ status(code) {
287
+ reply.status(code);
288
+ return this;
289
+ },
290
+ send(data) {
291
+ reply.send(data);
292
+ },
293
+ },
294
+ };
295
+ try {
296
+ await route.handler(ctx, proofPlane);
297
+ }
298
+ catch (err) {
299
+ if (err instanceof z.ZodError) {
300
+ reply.status(400).send(error('VALIDATION_ERROR', 'Request validation failed', err.errors));
301
+ return;
302
+ }
303
+ throw err;
304
+ }
305
+ };
306
+ if (route.method === 'GET') {
307
+ fastify.get(route.path, handler);
308
+ }
309
+ else if (route.method === 'POST') {
310
+ fastify.post(route.path, handler);
311
+ }
312
+ }
313
+ }
314
+ /**
315
+ * Express middleware adapter
316
+ *
317
+ * Usage with Express:
318
+ * ```typescript
319
+ * import express from 'express';
320
+ * import { createProofPlane } from '@vorionsys/proof-plane';
321
+ * import { createProofExpressRouter } from '@vorionsys/proof-plane/api';
322
+ *
323
+ * const app = express();
324
+ * const proofPlane = createProofPlane({ signedBy: 'my-service' });
325
+ *
326
+ * app.use('/v1', createProofExpressRouter(proofPlane));
327
+ * ```
328
+ */
329
+ export function createProofExpressRouter(proofPlane) {
330
+ const routes = createProofRoutes(proofPlane);
331
+ const handler = async (req, res, next) => {
332
+ const matchedRoute = routes.find((r) => r.method === req.method &&
333
+ matchPath(r.path, req.path));
334
+ if (!matchedRoute) {
335
+ next();
336
+ return;
337
+ }
338
+ const ctx = {
339
+ request: {
340
+ params: extractParams(matchedRoute.path, req.path),
341
+ query: req.query,
342
+ body: req.body,
343
+ id: req.headers['x-request-id'],
344
+ },
345
+ reply: {
346
+ status(code) {
347
+ res.status(code);
348
+ return this;
349
+ },
350
+ send(data) {
351
+ res.json(data);
352
+ },
353
+ },
354
+ };
355
+ try {
356
+ await matchedRoute.handler(ctx, proofPlane);
357
+ }
358
+ catch (err) {
359
+ if (err instanceof z.ZodError) {
360
+ res.status(400).json(error('VALIDATION_ERROR', 'Request validation failed', err.errors));
361
+ return;
362
+ }
363
+ next(err);
364
+ }
365
+ };
366
+ return { routes, handler };
367
+ }
368
+ /**
369
+ * Simple path matching for Express adapter
370
+ */
371
+ function matchPath(pattern, path) {
372
+ const patternParts = pattern.split('/');
373
+ const pathParts = path.split('/');
374
+ if (patternParts.length !== pathParts.length) {
375
+ return false;
376
+ }
377
+ return patternParts.every((part, i) => {
378
+ if (part.startsWith(':')) {
379
+ return true; // Parameter matches anything
380
+ }
381
+ return part === pathParts[i];
382
+ });
383
+ }
384
+ /**
385
+ * Extract parameters from path
386
+ */
387
+ function extractParams(pattern, path) {
388
+ const params = {};
389
+ const patternParts = pattern.split('/');
390
+ const pathParts = path.split('/');
391
+ patternParts.forEach((part, i) => {
392
+ if (part.startsWith(':')) {
393
+ const paramName = part.slice(1);
394
+ params[paramName] = pathParts[i];
395
+ }
396
+ });
397
+ return params;
398
+ }
399
+ //# sourceMappingURL=routes.js.map