@peac/transport-grpc 0.12.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ /**
2
+ * gRPC metadata keys, types, and helpers for PEAC transport.
3
+ *
4
+ * Extracted to a separate module to avoid circular imports between
5
+ * index.ts and a2a-carrier.ts.
6
+ */
7
+ /** gRPC metadata shape for PEAC carrier operations */
8
+ export type GrpcMetadataLike = Record<string, string | string[] | undefined>;
9
+ /**
10
+ * gRPC metadata keys for PEAC transport.
11
+ */
12
+ export declare const GrpcMetadataKeys: {
13
+ /** PEAC receipt in metadata */
14
+ readonly RECEIPT: "peac-receipt";
15
+ /** PEAC receipt type */
16
+ readonly RECEIPT_TYPE: "peac-receipt-type";
17
+ /** TAP signature */
18
+ readonly TAP_SIGNATURE: "peac-tap-signature";
19
+ /** TAP signature input */
20
+ readonly TAP_SIGNATURE_INPUT: "peac-tap-signature-input";
21
+ /** PEAC error code in trailer */
22
+ readonly ERROR_CODE: "peac-error-code";
23
+ /** Request ID for tracing */
24
+ readonly REQUEST_ID: "peac-request-id";
25
+ };
26
+ /**
27
+ * Extract PEAC receipt from gRPC metadata.
28
+ */
29
+ export declare function extractReceiptFromMetadata(metadata: GrpcMetadataLike): string | null;
30
+ /**
31
+ * Extract receipt type from gRPC metadata.
32
+ */
33
+ export declare function extractReceiptTypeFromMetadata(metadata: GrpcMetadataLike): string | null;
34
+ /**
35
+ * Add PEAC receipt to gRPC metadata.
36
+ *
37
+ * @param metadata - gRPC metadata object to modify
38
+ * @param receiptJws - Compact JWS of the signed receipt
39
+ * @param receiptType - Receipt typ value (defaults to Wire 0.2 `interaction-record+jwt`)
40
+ */
41
+ export declare function addReceiptToMetadata(metadata: Record<string, string | string[]>, receiptJws: string, receiptType?: string): void;
42
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,sDAAsD;AACtD,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;AAM7E;;GAEG;AACH,eAAO,MAAM,gBAAgB;IAC3B,+BAA+B;;IAE/B,wBAAwB;;IAExB,oBAAoB;;IAEpB,0BAA0B;;IAE1B,iCAAiC;;IAEjC,6BAA6B;;CAErB,CAAC;AAMX;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,GAAG,IAAI,CASpF;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,GAAG,IAAI,CASxF;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAC3C,UAAU,EAAE,MAAM,EAClB,WAAW,GAAE,MAAwB,GACpC,IAAI,CAGN"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@peac/transport-grpc",
3
+ "version": "0.12.6",
4
+ "description": "PEAC gRPC transport layer with carrier adapter and HTTP StatusCode parity",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "keywords": [
20
+ "peac",
21
+ "peacprotocol",
22
+ "interaction-records",
23
+ "signed-records",
24
+ "receipts",
25
+ "originary",
26
+ "transport-grpc",
27
+ "grpc",
28
+ "protobuf",
29
+ "rpc",
30
+ "carrier-adapter"
31
+ ],
32
+ "author": "PEAC Protocol Contributors",
33
+ "license": "Apache-2.0",
34
+ "dependencies": {
35
+ "@peac/kernel": "0.12.6",
36
+ "@peac/schema": "0.12.6"
37
+ },
38
+ "devDependencies": {
39
+ "tsup": "^8.5.1",
40
+ "typescript": "^5.6.2",
41
+ "vitest": "^4.0.0"
42
+ },
43
+ "bugs": {
44
+ "url": "https://github.com/peacprotocol/peac/issues"
45
+ },
46
+ "homepage": "https://github.com/peacprotocol/peac#readme",
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/peacprotocol/peac.git",
50
+ "directory": "packages/transport/grpc"
51
+ },
52
+ "scripts": {
53
+ "build": "pnpm run build:js && pnpm run build:types",
54
+ "build:js": "tsup",
55
+ "build:types": "rm -f dist/.tsbuildinfo && tsc && rm -f dist/.tsbuildinfo",
56
+ "test": "vitest run",
57
+ "test:watch": "vitest",
58
+ "clean": "rm -rf dist tsconfig.tsbuildinfo"
59
+ }
60
+ }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * gRPC CarrierAdapter for A2A transport.
3
+ *
4
+ * Implements the PEAC CarrierAdapter interface for gRPC metadata,
5
+ * enabling receipt attach/extract via gRPC metadata keys. Pure TS
6
+ * with no @grpc/grpc-js dependency; consumers bring their own gRPC.
7
+ *
8
+ * Size default: 8 KiB. gRPC metadata rides in HTTP/2 headers where
9
+ * servers commonly enforce an 8 KiB limit. For larger receipts, use
10
+ * reference mode (receipt_url) or negotiate a higher limit with the
11
+ * gRPC server configuration.
12
+ */
13
+
14
+ import { createHash } from 'node:crypto';
15
+
16
+ import type {
17
+ CarrierAdapter,
18
+ PeacEvidenceCarrier,
19
+ CarrierMeta,
20
+ CarrierValidationResult,
21
+ ReceiptRef,
22
+ } from '@peac/kernel';
23
+ import { validateCarrierConstraints } from '@peac/schema';
24
+
25
+ import { GrpcMetadataKeys, extractReceiptFromMetadata, addReceiptToMetadata } from './metadata.js';
26
+ import type { GrpcMetadataLike } from './metadata.js';
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Constants
30
+ // ---------------------------------------------------------------------------
31
+
32
+ /**
33
+ * Default maximum carrier size for gRPC metadata (8 KiB).
34
+ *
35
+ * gRPC metadata is carried in HTTP/2 headers. Official gRPC guidance
36
+ * warns that servers may limit request headers, with a common default
37
+ * of 8 KiB. This is a conservative interoperability-safe default.
38
+ * Consumers with known larger server limits can override via
39
+ * `createGrpcCarrierMeta({ max_size: ... })`.
40
+ */
41
+ export const GRPC_MAX_CARRIER_SIZE = 8_192;
42
+
43
+ /** Binary metadata key suffix per gRPC convention */
44
+ const BINARY_SUFFIX = '-bin';
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // Public API
48
+ // ---------------------------------------------------------------------------
49
+
50
+ /**
51
+ * CarrierAdapter for gRPC metadata transport.
52
+ *
53
+ * Reads and writes PEAC evidence carriers via `GrpcMetadataKeys.RECEIPT`
54
+ * and `GrpcMetadataKeys.RECEIPT_TYPE` metadata entries.
55
+ *
56
+ * `extract()` computes the real SHA-256 receipt_ref synchronously
57
+ * using Node's `crypto.createHash` (server-first package).
58
+ */
59
+ export class A2AGrpcCarrierAdapter implements CarrierAdapter<GrpcMetadataLike, GrpcMetadataLike> {
60
+ /**
61
+ * Extract PEAC evidence carrier from gRPC metadata.
62
+ *
63
+ * Computes the real SHA-256 receipt_ref from the JWS bytes using
64
+ * Node's synchronous crypto.createHash (server-first package).
65
+ * Rejects binary metadata keys (gRPC `-bin` suffix convention).
66
+ *
67
+ * @returns Extracted carrier with computed receipt_ref, or null if absent
68
+ */
69
+ extract(input: GrpcMetadataLike): { receipts: PeacEvidenceCarrier[]; meta: CarrierMeta } | null {
70
+ // Reject binary-encoded PEAC receipt metadata
71
+ const binaryReceiptKey = GrpcMetadataKeys.RECEIPT + BINARY_SUFFIX;
72
+ if (binaryReceiptKey in input) {
73
+ return null;
74
+ }
75
+
76
+ const receiptJws = extractReceiptFromMetadata(input);
77
+ if (!receiptJws) return null;
78
+
79
+ const digest = createHash('sha256').update(receiptJws).digest('hex');
80
+ const receiptRef = `sha256:${digest}` as ReceiptRef;
81
+
82
+ const carrier: PeacEvidenceCarrier = {
83
+ receipt_ref: receiptRef,
84
+ receipt_jws: receiptJws,
85
+ };
86
+
87
+ return {
88
+ receipts: [carrier],
89
+ meta: createGrpcCarrierMeta(),
90
+ };
91
+ }
92
+
93
+ attach(
94
+ output: GrpcMetadataLike,
95
+ carriers: PeacEvidenceCarrier[],
96
+ meta?: CarrierMeta
97
+ ): GrpcMetadataLike {
98
+ if (carriers.length === 0) return output;
99
+
100
+ const carrier = carriers[0];
101
+ const effectiveMeta = meta ?? createGrpcCarrierMeta();
102
+ const result = this.validateConstraints(carrier, effectiveMeta);
103
+ if (!result.valid) {
104
+ throw new Error(`Carrier constraint violation: ${result.violations.join('; ')}`);
105
+ }
106
+
107
+ if (carrier.receipt_jws) {
108
+ addReceiptToMetadata(output as Record<string, string | string[]>, carrier.receipt_jws);
109
+ }
110
+
111
+ return output;
112
+ }
113
+
114
+ validateConstraints(carrier: PeacEvidenceCarrier, meta: CarrierMeta): CarrierValidationResult {
115
+ return validateCarrierConstraints(carrier, meta);
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Create default CarrierMeta for gRPC transport.
121
+ *
122
+ * Default max_size is 8 KiB (HTTP/2 header budget). Override for
123
+ * environments with known larger server limits.
124
+ */
125
+ export function createGrpcCarrierMeta(overrides?: Partial<CarrierMeta>): CarrierMeta {
126
+ return {
127
+ transport: 'grpc',
128
+ format: 'embed',
129
+ max_size: GRPC_MAX_CARRIER_SIZE,
130
+ ...overrides,
131
+ };
132
+ }
133
+
134
+ /**
135
+ * Validate that the package's own PEAC metadata key constants are ASCII-safe
136
+ * and do not use the reserved `grpc-` prefix.
137
+ *
138
+ * This is a repo-level invariant check, not an inbound metadata validator.
139
+ * It verifies that all keys defined in `GrpcMetadataKeys` use only
140
+ * lowercase ASCII letters, digits, hyphens, and underscores per
141
+ * gRPC metadata key requirements, and that none start with the
142
+ * reserved `grpc-` prefix.
143
+ *
144
+ * @returns Array of invalid keys (empty if all valid)
145
+ */
146
+ export function validateOwnMetadataKeys(): string[] {
147
+ const ASCII_KEY_REGEX = /^[a-z0-9_-]+$/;
148
+ const RESERVED_PREFIX = 'grpc-';
149
+ const invalid: string[] = [];
150
+ for (const key of Object.values(GrpcMetadataKeys)) {
151
+ if (!ASCII_KEY_REGEX.test(key)) {
152
+ invalid.push(key);
153
+ } else if (key.startsWith(RESERVED_PREFIX)) {
154
+ invalid.push(key);
155
+ }
156
+ }
157
+ return invalid;
158
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,eAAO,MAAM,sBAAsB,EAAG,QAAiB,CAAC;AAExD;;;GAGG;AACH,eAAO,MAAM,UAAU;IACrB,cAAc;;IAEd,8BAA8B;;IAE9B,oBAAoB;;IAEpB,wCAAwC;;IAExC,kDAAkD;;IAElD,iCAAiC;;IAEjC,4BAA4B;;IAE5B,8BAA8B;;IAE9B,yBAAyB;;IAEzB,6CAA6C;;IAE7C,mCAAmC;;IAEnC,yBAAyB;;IAEzB,gCAAgC;;IAEhC,qBAAqB;;IAErB,0BAA0B;;IAE1B,gBAAgB;;IAEhB,wBAAwB;;CAEhB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAE1E;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,CAuCnE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,cAAc,GAAG,MAAM,CAuCnE;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CA2B7D,CAAC;AAEF;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAEjE;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,uBAAuB;IACvB,IAAI,EAAE,cAAc,CAAC;IACrB,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAO/F;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB;IAC3B,+BAA+B;;IAE/B,wBAAwB;;IAExB,oBAAoB;;IAEpB,0BAA0B;;IAE1B,iCAAiC;;IAEjC,6BAA6B;;CAErB,CAAC;AAEX;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GACtD,MAAM,GAAG,IAAI,CASf;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAC3C,UAAU,EAAE,MAAM,GACjB,IAAI,CAGN;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,qCAAqC;IACrC,EAAE,EAAE,OAAO,CAAC;IACZ,uBAAuB;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,mCAAmC;IACnC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,sBAAsB,CAM9E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,GAAG,sBAAsB,CAM5E;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAkBzD,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAE1D"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
package/src/index.ts ADDED
@@ -0,0 +1,313 @@
1
+ /**
2
+ * PEAC gRPC Transport Layer
3
+ *
4
+ * Provides gRPC binding for PEAC receipts with StatusCode parity to HTTP.
5
+ *
6
+ * Status code mapping follows these semantics:
7
+ * - INVALID_ARGUMENT (3): Malformed request (HTTP 400)
8
+ * - UNAUTHENTICATED (16): Authentication required (HTTP 401)
9
+ * - FAILED_PRECONDITION (9): Payment required (HTTP 402)
10
+ * - PERMISSION_DENIED (7): Not authorized (HTTP 403)
11
+ * - ABORTED (10): Conflict/replay detected (HTTP 409)
12
+ * - INTERNAL (13): Server error (HTTP 500)
13
+ *
14
+ * @packageDocumentation
15
+ */
16
+
17
+ export const GRPC_TRANSPORT_VERSION = '0.12.6' as const;
18
+
19
+ // Metadata keys, types, and helpers (shared with a2a-carrier.ts)
20
+ export {
21
+ GrpcMetadataKeys,
22
+ extractReceiptFromMetadata,
23
+ extractReceiptTypeFromMetadata,
24
+ addReceiptToMetadata,
25
+ } from './metadata.js';
26
+ export type { GrpcMetadataLike } from './metadata.js';
27
+
28
+ /**
29
+ * gRPC status codes.
30
+ * @see https://grpc.io/docs/guides/status-codes/
31
+ */
32
+ export const GrpcStatus = {
33
+ /** Success */
34
+ OK: 0,
35
+ /** Operation was cancelled */
36
+ CANCELLED: 1,
37
+ /** Unknown error */
38
+ UNKNOWN: 2,
39
+ /** Client specified invalid argument */
40
+ INVALID_ARGUMENT: 3,
41
+ /** Deadline expired before operation completed */
42
+ DEADLINE_EXCEEDED: 4,
43
+ /** Requested entity not found */
44
+ NOT_FOUND: 5,
45
+ /** Entity already exists */
46
+ ALREADY_EXISTS: 6,
47
+ /** Caller lacks permission */
48
+ PERMISSION_DENIED: 7,
49
+ /** Resource exhausted */
50
+ RESOURCE_EXHAUSTED: 8,
51
+ /** Operation rejected due to precondition */
52
+ FAILED_PRECONDITION: 9,
53
+ /** Operation aborted (conflict) */
54
+ ABORTED: 10,
55
+ /** Value out of range */
56
+ OUT_OF_RANGE: 11,
57
+ /** Operation not implemented */
58
+ UNIMPLEMENTED: 12,
59
+ /** Internal error */
60
+ INTERNAL: 13,
61
+ /** Service unavailable */
62
+ UNAVAILABLE: 14,
63
+ /** Data loss */
64
+ DATA_LOSS: 15,
65
+ /** Not authenticated */
66
+ UNAUTHENTICATED: 16,
67
+ } as const;
68
+
69
+ export type GrpcStatusCode = (typeof GrpcStatus)[keyof typeof GrpcStatus];
70
+
71
+ /**
72
+ * Map HTTP status code to gRPC status code.
73
+ *
74
+ * Mapping semantics:
75
+ * - 400 Bad Request -> INVALID_ARGUMENT (malformed)
76
+ * - 401 Unauthorized -> UNAUTHENTICATED (auth required)
77
+ * - 402 Payment Required -> FAILED_PRECONDITION (payment needed)
78
+ * - 403 Forbidden -> PERMISSION_DENIED (not authorized)
79
+ * - 409 Conflict -> ABORTED (replay detected)
80
+ * - 500 Internal Server Error -> INTERNAL
81
+ * - Other 4xx -> INVALID_ARGUMENT
82
+ * - Other 5xx -> INTERNAL
83
+ */
84
+ export function httpStatusToGrpc(httpStatus: number): GrpcStatusCode {
85
+ switch (httpStatus) {
86
+ case 200:
87
+ case 201:
88
+ case 204:
89
+ return GrpcStatus.OK;
90
+ case 400:
91
+ return GrpcStatus.INVALID_ARGUMENT;
92
+ case 401:
93
+ return GrpcStatus.UNAUTHENTICATED;
94
+ case 402:
95
+ return GrpcStatus.FAILED_PRECONDITION;
96
+ case 403:
97
+ return GrpcStatus.PERMISSION_DENIED;
98
+ case 404:
99
+ return GrpcStatus.NOT_FOUND;
100
+ case 409:
101
+ return GrpcStatus.ABORTED;
102
+ case 429:
103
+ return GrpcStatus.RESOURCE_EXHAUSTED;
104
+ case 499:
105
+ return GrpcStatus.CANCELLED;
106
+ case 500:
107
+ return GrpcStatus.INTERNAL;
108
+ case 501:
109
+ return GrpcStatus.UNIMPLEMENTED;
110
+ case 503:
111
+ return GrpcStatus.UNAVAILABLE;
112
+ case 504:
113
+ return GrpcStatus.DEADLINE_EXCEEDED;
114
+ default:
115
+ if (httpStatus >= 400 && httpStatus < 500) {
116
+ return GrpcStatus.INVALID_ARGUMENT;
117
+ }
118
+ if (httpStatus >= 500) {
119
+ return GrpcStatus.INTERNAL;
120
+ }
121
+ return GrpcStatus.OK;
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Map gRPC status code to HTTP status code.
127
+ *
128
+ * Inverse of httpStatusToGrpc for response translation.
129
+ */
130
+ export function grpcStatusToHttp(grpcStatus: GrpcStatusCode): number {
131
+ switch (grpcStatus) {
132
+ case GrpcStatus.OK:
133
+ return 200;
134
+ case GrpcStatus.CANCELLED:
135
+ return 499;
136
+ case GrpcStatus.UNKNOWN:
137
+ return 500;
138
+ case GrpcStatus.INVALID_ARGUMENT:
139
+ return 400;
140
+ case GrpcStatus.DEADLINE_EXCEEDED:
141
+ return 504;
142
+ case GrpcStatus.NOT_FOUND:
143
+ return 404;
144
+ case GrpcStatus.ALREADY_EXISTS:
145
+ return 409;
146
+ case GrpcStatus.PERMISSION_DENIED:
147
+ return 403;
148
+ case GrpcStatus.RESOURCE_EXHAUSTED:
149
+ return 429;
150
+ case GrpcStatus.FAILED_PRECONDITION:
151
+ return 402;
152
+ case GrpcStatus.ABORTED:
153
+ return 409;
154
+ case GrpcStatus.OUT_OF_RANGE:
155
+ return 400;
156
+ case GrpcStatus.UNIMPLEMENTED:
157
+ return 501;
158
+ case GrpcStatus.INTERNAL:
159
+ return 500;
160
+ case GrpcStatus.UNAVAILABLE:
161
+ return 503;
162
+ case GrpcStatus.DATA_LOSS:
163
+ return 500;
164
+ case GrpcStatus.UNAUTHENTICATED:
165
+ return 401;
166
+ default:
167
+ return 500;
168
+ }
169
+ }
170
+
171
+ /**
172
+ * PEAC error code to gRPC status mapping.
173
+ *
174
+ * Maps canonical PEAC error codes to appropriate gRPC status codes.
175
+ */
176
+ export const PEAC_ERROR_TO_GRPC: Record<string, GrpcStatusCode> = {
177
+ // 402 Payment Required -> FAILED_PRECONDITION
178
+ E_RECEIPT_MISSING: GrpcStatus.FAILED_PRECONDITION,
179
+ E_RECEIPT_INVALID: GrpcStatus.FAILED_PRECONDITION,
180
+ E_RECEIPT_EXPIRED: GrpcStatus.FAILED_PRECONDITION,
181
+
182
+ // 401 Unauthenticated -> UNAUTHENTICATED
183
+ E_TAP_SIGNATURE_MISSING: GrpcStatus.UNAUTHENTICATED,
184
+ E_TAP_SIGNATURE_INVALID: GrpcStatus.UNAUTHENTICATED,
185
+ E_TAP_TIME_INVALID: GrpcStatus.UNAUTHENTICATED,
186
+ E_TAP_KEY_NOT_FOUND: GrpcStatus.UNAUTHENTICATED,
187
+ E_TAP_REPLAY_PROTECTION_REQUIRED: GrpcStatus.UNAUTHENTICATED,
188
+
189
+ // 400 Bad Request -> INVALID_ARGUMENT
190
+ E_TAP_WINDOW_TOO_LARGE: GrpcStatus.INVALID_ARGUMENT,
191
+ E_TAP_TAG_UNKNOWN: GrpcStatus.INVALID_ARGUMENT,
192
+ E_TAP_ALGORITHM_INVALID: GrpcStatus.INVALID_ARGUMENT,
193
+
194
+ // 403 Forbidden -> PERMISSION_DENIED
195
+ E_ISSUER_NOT_ALLOWED: GrpcStatus.PERMISSION_DENIED,
196
+
197
+ // 409 Conflict -> ABORTED
198
+ E_TAP_NONCE_REPLAY: GrpcStatus.ABORTED,
199
+
200
+ // 500 Internal -> INTERNAL
201
+ E_CONFIG_ISSUER_ALLOWLIST_REQUIRED: GrpcStatus.INTERNAL,
202
+ E_INTERNAL_ERROR: GrpcStatus.INTERNAL,
203
+ };
204
+
205
+ /**
206
+ * Get gRPC status for a PEAC error code.
207
+ */
208
+ export function peacErrorToGrpc(errorCode: string): GrpcStatusCode {
209
+ return PEAC_ERROR_TO_GRPC[errorCode] ?? GrpcStatus.INTERNAL;
210
+ }
211
+
212
+ /**
213
+ * gRPC error with status code.
214
+ */
215
+ export interface GrpcError {
216
+ /** gRPC status code */
217
+ code: GrpcStatusCode;
218
+ /** Error message */
219
+ message: string;
220
+ /** PEAC error code (if applicable) */
221
+ peacCode?: string;
222
+ /** Additional error details */
223
+ details?: unknown;
224
+ }
225
+
226
+ /**
227
+ * Create a gRPC error from a PEAC error code.
228
+ */
229
+ export function createGrpcError(peacCode: string, message: string, details?: unknown): GrpcError {
230
+ return {
231
+ code: peacErrorToGrpc(peacCode),
232
+ message,
233
+ peacCode,
234
+ details,
235
+ };
236
+ }
237
+
238
+ /**
239
+ * gRPC verification result.
240
+ */
241
+ export interface GrpcVerificationResult {
242
+ /** Whether verification succeeded */
243
+ ok: boolean;
244
+ /** gRPC status code */
245
+ status: GrpcStatusCode;
246
+ /** Error if verification failed */
247
+ error?: GrpcError;
248
+ /** Receipt ID if verification succeeded */
249
+ receiptId?: string;
250
+ }
251
+
252
+ /**
253
+ * Create a successful verification result.
254
+ */
255
+ export function createSuccessResult(receiptId?: string): GrpcVerificationResult {
256
+ return {
257
+ ok: true,
258
+ status: GrpcStatus.OK,
259
+ receiptId,
260
+ };
261
+ }
262
+
263
+ /**
264
+ * Create a failed verification result.
265
+ */
266
+ export function createFailureResult(error: GrpcError): GrpcVerificationResult {
267
+ return {
268
+ ok: false,
269
+ status: error.code,
270
+ error,
271
+ };
272
+ }
273
+
274
+ /**
275
+ * Status code name mapping for debugging.
276
+ */
277
+ export const GrpcStatusName: Record<GrpcStatusCode, string> = {
278
+ [GrpcStatus.OK]: 'OK',
279
+ [GrpcStatus.CANCELLED]: 'CANCELLED',
280
+ [GrpcStatus.UNKNOWN]: 'UNKNOWN',
281
+ [GrpcStatus.INVALID_ARGUMENT]: 'INVALID_ARGUMENT',
282
+ [GrpcStatus.DEADLINE_EXCEEDED]: 'DEADLINE_EXCEEDED',
283
+ [GrpcStatus.NOT_FOUND]: 'NOT_FOUND',
284
+ [GrpcStatus.ALREADY_EXISTS]: 'ALREADY_EXISTS',
285
+ [GrpcStatus.PERMISSION_DENIED]: 'PERMISSION_DENIED',
286
+ [GrpcStatus.RESOURCE_EXHAUSTED]: 'RESOURCE_EXHAUSTED',
287
+ [GrpcStatus.FAILED_PRECONDITION]: 'FAILED_PRECONDITION',
288
+ [GrpcStatus.ABORTED]: 'ABORTED',
289
+ [GrpcStatus.OUT_OF_RANGE]: 'OUT_OF_RANGE',
290
+ [GrpcStatus.UNIMPLEMENTED]: 'UNIMPLEMENTED',
291
+ [GrpcStatus.INTERNAL]: 'INTERNAL',
292
+ [GrpcStatus.UNAVAILABLE]: 'UNAVAILABLE',
293
+ [GrpcStatus.DATA_LOSS]: 'DATA_LOSS',
294
+ [GrpcStatus.UNAUTHENTICATED]: 'UNAUTHENTICATED',
295
+ };
296
+
297
+ /**
298
+ * Get human-readable name for a gRPC status code.
299
+ */
300
+ export function getStatusName(code: GrpcStatusCode): string {
301
+ return GrpcStatusName[code] ?? 'UNKNOWN';
302
+ }
303
+
304
+ // ---------------------------------------------------------------------------
305
+ // Carrier adapter re-exports
306
+ // ---------------------------------------------------------------------------
307
+
308
+ export {
309
+ A2AGrpcCarrierAdapter,
310
+ createGrpcCarrierMeta,
311
+ validateOwnMetadataKeys,
312
+ GRPC_MAX_CARRIER_SIZE,
313
+ } from './a2a-carrier.js';
@@ -0,0 +1,85 @@
1
+ /**
2
+ * gRPC metadata keys, types, and helpers for PEAC transport.
3
+ *
4
+ * Extracted to a separate module to avoid circular imports between
5
+ * index.ts and a2a-carrier.ts.
6
+ */
7
+
8
+ import { WIRE_02_JWS_TYP } from '@peac/kernel';
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Types
12
+ // ---------------------------------------------------------------------------
13
+
14
+ /** gRPC metadata shape for PEAC carrier operations */
15
+ export type GrpcMetadataLike = Record<string, string | string[] | undefined>;
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // Constants
19
+ // ---------------------------------------------------------------------------
20
+
21
+ /**
22
+ * gRPC metadata keys for PEAC transport.
23
+ */
24
+ export const GrpcMetadataKeys = {
25
+ /** PEAC receipt in metadata */
26
+ RECEIPT: 'peac-receipt',
27
+ /** PEAC receipt type */
28
+ RECEIPT_TYPE: 'peac-receipt-type',
29
+ /** TAP signature */
30
+ TAP_SIGNATURE: 'peac-tap-signature',
31
+ /** TAP signature input */
32
+ TAP_SIGNATURE_INPUT: 'peac-tap-signature-input',
33
+ /** PEAC error code in trailer */
34
+ ERROR_CODE: 'peac-error-code',
35
+ /** Request ID for tracing */
36
+ REQUEST_ID: 'peac-request-id',
37
+ } as const;
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Helpers
41
+ // ---------------------------------------------------------------------------
42
+
43
+ /**
44
+ * Extract PEAC receipt from gRPC metadata.
45
+ */
46
+ export function extractReceiptFromMetadata(metadata: GrpcMetadataLike): string | null {
47
+ const receipt = metadata[GrpcMetadataKeys.RECEIPT];
48
+ if (typeof receipt === 'string') {
49
+ return receipt;
50
+ }
51
+ if (Array.isArray(receipt) && receipt.length > 0) {
52
+ return receipt[0];
53
+ }
54
+ return null;
55
+ }
56
+
57
+ /**
58
+ * Extract receipt type from gRPC metadata.
59
+ */
60
+ export function extractReceiptTypeFromMetadata(metadata: GrpcMetadataLike): string | null {
61
+ const typ = metadata[GrpcMetadataKeys.RECEIPT_TYPE];
62
+ if (typeof typ === 'string') {
63
+ return typ;
64
+ }
65
+ if (Array.isArray(typ) && typ.length > 0) {
66
+ return typ[0];
67
+ }
68
+ return null;
69
+ }
70
+
71
+ /**
72
+ * Add PEAC receipt to gRPC metadata.
73
+ *
74
+ * @param metadata - gRPC metadata object to modify
75
+ * @param receiptJws - Compact JWS of the signed receipt
76
+ * @param receiptType - Receipt typ value (defaults to Wire 0.2 `interaction-record+jwt`)
77
+ */
78
+ export function addReceiptToMetadata(
79
+ metadata: Record<string, string | string[]>,
80
+ receiptJws: string,
81
+ receiptType: string = WIRE_02_JWS_TYP
82
+ ): void {
83
+ metadata[GrpcMetadataKeys.RECEIPT] = receiptJws;
84
+ metadata[GrpcMetadataKeys.RECEIPT_TYPE] = receiptType;
85
+ }