@peac/schema 0.10.9 → 0.10.10

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 (77) hide show
  1. package/LICENSE +1 -1
  2. package/dist/attestation-receipt.cjs +127 -0
  3. package/dist/attestation-receipt.cjs.map +1 -0
  4. package/dist/attestation-receipt.mjs +113 -0
  5. package/dist/attestation-receipt.mjs.map +1 -0
  6. package/dist/attribution.cjs +249 -0
  7. package/dist/attribution.cjs.map +1 -0
  8. package/dist/attribution.mjs +227 -0
  9. package/dist/attribution.mjs.map +1 -0
  10. package/dist/dispute.d.ts.map +1 -1
  11. package/dist/index.cjs +2818 -0
  12. package/dist/index.cjs.map +1 -0
  13. package/dist/index.mjs +2577 -0
  14. package/dist/index.mjs.map +1 -0
  15. package/dist/interaction.cjs +619 -0
  16. package/dist/interaction.cjs.map +1 -0
  17. package/dist/interaction.mjs +583 -0
  18. package/dist/interaction.mjs.map +1 -0
  19. package/dist/normalize.cjs +84 -0
  20. package/dist/normalize.cjs.map +1 -0
  21. package/dist/normalize.d.ts +15 -9
  22. package/dist/normalize.d.ts.map +1 -1
  23. package/dist/normalize.mjs +82 -0
  24. package/dist/normalize.mjs.map +1 -0
  25. package/dist/receipt-parser.cjs +333 -0
  26. package/dist/receipt-parser.cjs.map +1 -0
  27. package/dist/receipt-parser.mjs +331 -0
  28. package/dist/receipt-parser.mjs.map +1 -0
  29. package/dist/workflow.cjs +321 -0
  30. package/dist/workflow.cjs.map +1 -0
  31. package/dist/workflow.mjs +292 -0
  32. package/dist/workflow.mjs.map +1 -0
  33. package/package.json +50 -6
  34. package/dist/agent-identity.js +0 -357
  35. package/dist/agent-identity.js.map +0 -1
  36. package/dist/attestation-receipt.js +0 -249
  37. package/dist/attestation-receipt.js.map +0 -1
  38. package/dist/attribution.js +0 -444
  39. package/dist/attribution.js.map +0 -1
  40. package/dist/constants.js +0 -73
  41. package/dist/constants.js.map +0 -1
  42. package/dist/control.js +0 -9
  43. package/dist/control.js.map +0 -1
  44. package/dist/dispute.js +0 -832
  45. package/dist/dispute.js.map +0 -1
  46. package/dist/envelope.js +0 -9
  47. package/dist/envelope.js.map +0 -1
  48. package/dist/errors.js +0 -116
  49. package/dist/errors.js.map +0 -1
  50. package/dist/evidence.js +0 -8
  51. package/dist/evidence.js.map +0 -1
  52. package/dist/index.js +0 -283
  53. package/dist/index.js.map +0 -1
  54. package/dist/interaction.js +0 -918
  55. package/dist/interaction.js.map +0 -1
  56. package/dist/json.js +0 -267
  57. package/dist/json.js.map +0 -1
  58. package/dist/normalize.js +0 -103
  59. package/dist/normalize.js.map +0 -1
  60. package/dist/obligations.js +0 -337
  61. package/dist/obligations.js.map +0 -1
  62. package/dist/purpose.js +0 -296
  63. package/dist/purpose.js.map +0 -1
  64. package/dist/receipt-parser.js +0 -89
  65. package/dist/receipt-parser.js.map +0 -1
  66. package/dist/schemas.js +0 -7
  67. package/dist/schemas.js.map +0 -1
  68. package/dist/subject.js +0 -9
  69. package/dist/subject.js.map +0 -1
  70. package/dist/types.js +0 -6
  71. package/dist/types.js.map +0 -1
  72. package/dist/validators.js +0 -421
  73. package/dist/validators.js.map +0 -1
  74. package/dist/version.js +0 -7
  75. package/dist/version.js.map +0 -1
  76. package/dist/workflow.js +0 -523
  77. package/dist/workflow.js.map +0 -1
@@ -0,0 +1,583 @@
1
+ import { z } from 'zod';
2
+
3
+ // src/interaction.ts
4
+ var INTERACTION_EXTENSION_KEY = "org.peacprotocol/interaction@0.1";
5
+ var CANONICAL_DIGEST_ALGS = [
6
+ "sha-256",
7
+ // Full SHA-256
8
+ "sha-256:trunc-64k",
9
+ // First 64KB (65536 bytes)
10
+ "sha-256:trunc-1m"
11
+ // First 1MB (1048576 bytes)
12
+ ];
13
+ var DIGEST_SIZE_CONSTANTS = {
14
+ k: 1024,
15
+ // 1 KB = 1024 bytes (binary)
16
+ m: 1024 * 1024,
17
+ // 1 MB = 1048576 bytes (binary)
18
+ "trunc-64k": 65536,
19
+ // 64 * 1024
20
+ "trunc-1m": 1048576
21
+ // 1024 * 1024
22
+ };
23
+ var RESULT_STATUSES = ["ok", "error", "timeout", "canceled"];
24
+ var REDACTION_MODES = ["hash_only", "redacted", "plaintext_allowlisted"];
25
+ var POLICY_DECISIONS = ["allow", "deny", "constrained"];
26
+ var WELL_KNOWN_KINDS = [
27
+ "tool.call",
28
+ "http.request",
29
+ "fs.read",
30
+ "fs.write",
31
+ "message"
32
+ ];
33
+ var RESERVED_KIND_PREFIXES = ["peac.", "org.peacprotocol."];
34
+ var INTERACTION_LIMITS = {
35
+ /** Maximum interaction ID length */
36
+ maxInteractionIdLength: 256,
37
+ /** Maximum kind length */
38
+ maxKindLength: 128,
39
+ /** Maximum platform name length */
40
+ maxPlatformLength: 64,
41
+ /** Maximum version string length */
42
+ maxVersionLength: 64,
43
+ /** Maximum plugin ID length */
44
+ maxPluginIdLength: 128,
45
+ /** Maximum tool name length */
46
+ maxToolNameLength: 256,
47
+ /** Maximum provider length */
48
+ maxProviderLength: 128,
49
+ /** Maximum URI length */
50
+ maxUriLength: 2048,
51
+ /** Maximum method length */
52
+ maxMethodLength: 16,
53
+ /** Maximum error code length */
54
+ maxErrorCodeLength: 128,
55
+ /** Maximum payment reference length */
56
+ maxPaymentReferenceLength: 256,
57
+ /** Maximum receipt RID length */
58
+ maxReceiptRidLength: 128
59
+ };
60
+ function requiresTool(kind) {
61
+ return kind.startsWith("tool.");
62
+ }
63
+ function requiresResource(kind) {
64
+ return kind.startsWith("http.") || kind.startsWith("fs.");
65
+ }
66
+ function usesReservedPrefix(kind) {
67
+ return RESERVED_KIND_PREFIXES.some((prefix) => kind.startsWith(prefix));
68
+ }
69
+ function hasMeaningfulResource(resource) {
70
+ if (!resource) return false;
71
+ if (typeof resource.uri === "string" && resource.uri.length > 0) return true;
72
+ return false;
73
+ }
74
+ var KIND_FORMAT_PATTERN = /^[a-z][a-z0-9._:-]{0,126}[a-z0-9]$/;
75
+ var EXTENSION_KEY_PATTERN = /^([a-z0-9-]+\.)+[a-z0-9-]+\/[a-z][a-z0-9._:-]{0,126}[a-z0-9](?:@[0-9]+(?:\.[0-9]+)*)?$/;
76
+ var DIGEST_VALUE_PATTERN = /^[a-f0-9]{64}$/;
77
+ var DigestAlgSchema = z.enum(CANONICAL_DIGEST_ALGS);
78
+ var DigestSchema = z.object({
79
+ /** Algorithm: 'sha-256' (full) or 'sha-256:trunc-{size}' (truncated) */
80
+ alg: DigestAlgSchema,
81
+ /** 64 lowercase hex chars (SHA-256 output) */
82
+ value: z.string().regex(DIGEST_VALUE_PATTERN, "Must be 64 lowercase hex chars"),
83
+ /** Original byte length before any truncation (REQUIRED) */
84
+ bytes: z.number().int().nonnegative()
85
+ }).strict();
86
+ var PayloadRefSchema = z.object({
87
+ /** Content digest */
88
+ digest: DigestSchema,
89
+ /** Redaction mode */
90
+ redaction: z.enum(REDACTION_MODES)
91
+ }).strict();
92
+ var ExecutorSchema = z.object({
93
+ /** Platform identifier: 'openclaw', 'mcp', 'a2a', 'claude-code' */
94
+ platform: z.string().min(1).max(INTERACTION_LIMITS.maxPlatformLength),
95
+ /** Platform version */
96
+ version: z.string().max(INTERACTION_LIMITS.maxVersionLength).optional(),
97
+ /** Plugin that captured this */
98
+ plugin_id: z.string().max(INTERACTION_LIMITS.maxPluginIdLength).optional(),
99
+ /** Hash of plugin package (provenance) */
100
+ plugin_digest: DigestSchema.optional()
101
+ }).strict();
102
+ var ToolTargetSchema = z.object({
103
+ /** Tool name */
104
+ name: z.string().min(1).max(INTERACTION_LIMITS.maxToolNameLength),
105
+ /** Tool provider */
106
+ provider: z.string().max(INTERACTION_LIMITS.maxProviderLength).optional(),
107
+ /** Tool version */
108
+ version: z.string().max(INTERACTION_LIMITS.maxVersionLength).optional()
109
+ }).strict();
110
+ var ResourceTargetSchema = z.object({
111
+ /** Resource URI */
112
+ uri: z.string().max(INTERACTION_LIMITS.maxUriLength).optional(),
113
+ /** HTTP method or operation */
114
+ method: z.string().max(INTERACTION_LIMITS.maxMethodLength).optional()
115
+ }).strict();
116
+ var ResultSchema = z.object({
117
+ /** Result status */
118
+ status: z.enum(RESULT_STATUSES),
119
+ /** Error code (PEAC error code or namespaced) */
120
+ error_code: z.string().max(INTERACTION_LIMITS.maxErrorCodeLength).optional(),
121
+ /** Whether the operation can be retried */
122
+ retryable: z.boolean().optional()
123
+ }).strict();
124
+ var PolicyContextSchema = z.object({
125
+ /** Policy decision */
126
+ decision: z.enum(POLICY_DECISIONS),
127
+ /** Whether sandbox mode was enabled */
128
+ sandbox_enabled: z.boolean().optional(),
129
+ /** Whether elevated permissions were granted */
130
+ elevated: z.boolean().optional(),
131
+ /** Hash of effective policy document */
132
+ effective_policy_digest: DigestSchema.optional()
133
+ }).strict();
134
+ var RefsSchema = z.object({
135
+ /** Links to evidence.payment.reference */
136
+ payment_reference: z.string().max(INTERACTION_LIMITS.maxPaymentReferenceLength).optional(),
137
+ /** Correlation across receipts */
138
+ related_receipt_rid: z.string().max(INTERACTION_LIMITS.maxReceiptRidLength).optional()
139
+ }).strict();
140
+ var KindSchema = z.string().min(2).max(INTERACTION_LIMITS.maxKindLength).regex(KIND_FORMAT_PATTERN, "Invalid kind format");
141
+ var InteractionEvidenceV01BaseSchema = z.object({
142
+ /** Stable ID for idempotency/dedupe (REQUIRED) */
143
+ interaction_id: z.string().min(1).max(INTERACTION_LIMITS.maxInteractionIdLength),
144
+ /** Event kind - open string, not closed enum (REQUIRED) */
145
+ kind: KindSchema,
146
+ /** Executor identity (REQUIRED) */
147
+ executor: ExecutorSchema,
148
+ /** Tool target (when kind is tool-related) */
149
+ tool: ToolTargetSchema.optional(),
150
+ /** Resource target (when kind is http/fs-related) */
151
+ resource: ResourceTargetSchema.optional(),
152
+ /** Input payload reference */
153
+ input: PayloadRefSchema.optional(),
154
+ /** Output payload reference */
155
+ output: PayloadRefSchema.optional(),
156
+ /** Start time (RFC 3339) (REQUIRED) */
157
+ started_at: z.string().datetime(),
158
+ /** Completion time (RFC 3339) */
159
+ completed_at: z.string().datetime().optional(),
160
+ /** Duration in milliseconds (OPTIONAL, non-normative) */
161
+ duration_ms: z.number().int().nonnegative().optional(),
162
+ /** Execution outcome */
163
+ result: ResultSchema.optional(),
164
+ /** Policy context at execution */
165
+ policy: PolicyContextSchema.optional(),
166
+ /** References to related evidence */
167
+ refs: RefsSchema.optional(),
168
+ /** Platform-specific extensions (MUST be namespaced) */
169
+ extensions: z.record(z.unknown()).optional()
170
+ }).strict();
171
+ var InteractionEvidenceV01Schema = InteractionEvidenceV01BaseSchema.superRefine(
172
+ (ev, ctx) => {
173
+ if (ev.completed_at && ev.started_at) {
174
+ const startedAt = new Date(ev.started_at).getTime();
175
+ const completedAt = new Date(ev.completed_at).getTime();
176
+ if (completedAt < startedAt) {
177
+ ctx.addIssue({
178
+ code: z.ZodIssueCode.custom,
179
+ message: "completed_at must be >= started_at",
180
+ path: ["completed_at"]
181
+ });
182
+ }
183
+ }
184
+ if (ev.output && !ev.result?.status) {
185
+ ctx.addIssue({
186
+ code: z.ZodIssueCode.custom,
187
+ message: "result.status is required when output is present",
188
+ path: ["result"]
189
+ });
190
+ }
191
+ if (ev.result?.status === "error") {
192
+ const hasErrorCode = Boolean(ev.result.error_code);
193
+ const hasNonEmptyExtensions = ev.extensions !== void 0 && Object.keys(ev.extensions).length > 0;
194
+ if (!hasErrorCode && !hasNonEmptyExtensions) {
195
+ ctx.addIssue({
196
+ code: z.ZodIssueCode.custom,
197
+ message: "error_code or non-empty extensions required when status is error",
198
+ path: ["result", "error_code"]
199
+ });
200
+ }
201
+ }
202
+ if (ev.extensions) {
203
+ for (const key of Object.keys(ev.extensions)) {
204
+ if (!EXTENSION_KEY_PATTERN.test(key)) {
205
+ ctx.addIssue({
206
+ code: z.ZodIssueCode.custom,
207
+ message: `Invalid extension key format: ${key} (must be reverse-DNS/name[@version])`,
208
+ path: ["extensions", key]
209
+ });
210
+ }
211
+ }
212
+ }
213
+ if (usesReservedPrefix(ev.kind) && !WELL_KNOWN_KINDS.includes(ev.kind)) {
214
+ ctx.addIssue({
215
+ code: z.ZodIssueCode.custom,
216
+ message: `kind "${ev.kind}" uses reserved prefix`,
217
+ path: ["kind"]
218
+ });
219
+ }
220
+ if (requiresTool(ev.kind) && !ev.tool) {
221
+ ctx.addIssue({
222
+ code: z.ZodIssueCode.custom,
223
+ message: `kind "${ev.kind}" requires tool field`,
224
+ path: ["tool"]
225
+ });
226
+ }
227
+ if (requiresResource(ev.kind)) {
228
+ if (!ev.resource) {
229
+ ctx.addIssue({
230
+ code: z.ZodIssueCode.custom,
231
+ message: `kind "${ev.kind}" requires resource field`,
232
+ path: ["resource"]
233
+ });
234
+ } else if (!hasMeaningfulResource(ev.resource)) {
235
+ ctx.addIssue({
236
+ code: z.ZodIssueCode.custom,
237
+ message: `kind "${ev.kind}" requires resource.uri to be non-empty`,
238
+ path: ["resource", "uri"]
239
+ });
240
+ }
241
+ }
242
+ }
243
+ );
244
+ function validateInteractionOrdered(input) {
245
+ const errors = [];
246
+ const warnings = [];
247
+ if (typeof input !== "object" || input === null || Array.isArray(input)) {
248
+ return {
249
+ valid: false,
250
+ errors: [
251
+ {
252
+ code: "E_INTERACTION_INVALID_FORMAT",
253
+ message: "Input must be an object"
254
+ }
255
+ ],
256
+ warnings: []
257
+ };
258
+ }
259
+ const obj = input;
260
+ if (typeof obj.interaction_id !== "string" || obj.interaction_id.length === 0) {
261
+ errors.push({
262
+ code: "E_INTERACTION_MISSING_ID",
263
+ message: "interaction_id is required",
264
+ field: "interaction_id"
265
+ });
266
+ } else if (obj.interaction_id.length > INTERACTION_LIMITS.maxInteractionIdLength) {
267
+ errors.push({
268
+ code: "E_INTERACTION_INVALID_FORMAT",
269
+ message: `interaction_id exceeds max length (${INTERACTION_LIMITS.maxInteractionIdLength})`,
270
+ field: "interaction_id"
271
+ });
272
+ }
273
+ if (typeof obj.kind !== "string" || obj.kind.length === 0) {
274
+ errors.push({
275
+ code: "E_INTERACTION_MISSING_KIND",
276
+ message: "kind is required",
277
+ field: "kind"
278
+ });
279
+ } else if (obj.kind.length < 2 || obj.kind.length > INTERACTION_LIMITS.maxKindLength) {
280
+ errors.push({
281
+ code: "E_INTERACTION_INVALID_KIND_FORMAT",
282
+ message: `kind must be 2-${INTERACTION_LIMITS.maxKindLength} characters`,
283
+ field: "kind"
284
+ });
285
+ } else if (!KIND_FORMAT_PATTERN.test(obj.kind)) {
286
+ errors.push({
287
+ code: "E_INTERACTION_INVALID_KIND_FORMAT",
288
+ message: "kind must match pattern: lowercase, start with letter, end with alphanumeric",
289
+ field: "kind"
290
+ });
291
+ } else {
292
+ for (const prefix of RESERVED_KIND_PREFIXES) {
293
+ if (obj.kind.startsWith(prefix) && !WELL_KNOWN_KINDS.includes(obj.kind)) {
294
+ errors.push({
295
+ code: "E_INTERACTION_KIND_RESERVED",
296
+ message: `kind "${obj.kind}" uses reserved prefix "${prefix}"`,
297
+ field: "kind"
298
+ });
299
+ break;
300
+ }
301
+ }
302
+ if (errors.length === 0 && !WELL_KNOWN_KINDS.includes(obj.kind)) {
303
+ warnings.push({
304
+ code: "W_INTERACTION_KIND_UNREGISTERED",
305
+ message: `kind "${obj.kind}" is not in the well-known registry`,
306
+ field: "kind"
307
+ });
308
+ }
309
+ }
310
+ if (typeof obj.started_at !== "string") {
311
+ errors.push({
312
+ code: "E_INTERACTION_MISSING_STARTED_AT",
313
+ message: "started_at is required",
314
+ field: "started_at"
315
+ });
316
+ } else {
317
+ const startedAtDate = new Date(obj.started_at);
318
+ if (isNaN(startedAtDate.getTime())) {
319
+ errors.push({
320
+ code: "E_INTERACTION_MISSING_STARTED_AT",
321
+ message: "started_at must be a valid ISO 8601 datetime",
322
+ field: "started_at"
323
+ });
324
+ }
325
+ }
326
+ if (typeof obj.executor !== "object" || obj.executor === null) {
327
+ errors.push({
328
+ code: "E_INTERACTION_MISSING_EXECUTOR",
329
+ message: "executor is required",
330
+ field: "executor"
331
+ });
332
+ } else {
333
+ const executor = obj.executor;
334
+ if (typeof executor.platform !== "string" || executor.platform.length === 0) {
335
+ errors.push({
336
+ code: "E_INTERACTION_MISSING_EXECUTOR",
337
+ message: "executor.platform is required",
338
+ field: "executor.platform"
339
+ });
340
+ } else if (executor.platform.length > INTERACTION_LIMITS.maxPlatformLength) {
341
+ errors.push({
342
+ code: "E_INTERACTION_INVALID_FORMAT",
343
+ message: `executor.platform exceeds max length (${INTERACTION_LIMITS.maxPlatformLength})`,
344
+ field: "executor.platform"
345
+ });
346
+ }
347
+ }
348
+ if (errors.length > 0) {
349
+ return { valid: false, errors, warnings };
350
+ }
351
+ const validateDigest = (digest, fieldPath) => {
352
+ const digestErrors = [];
353
+ if (typeof digest !== "object" || digest === null) {
354
+ digestErrors.push({
355
+ code: "E_INTERACTION_INVALID_DIGEST",
356
+ message: "digest must be an object",
357
+ field: fieldPath
358
+ });
359
+ return { errors: digestErrors, valid: false };
360
+ }
361
+ const d = digest;
362
+ if (!CANONICAL_DIGEST_ALGS.includes(d.alg)) {
363
+ digestErrors.push({
364
+ code: "E_INTERACTION_INVALID_DIGEST_ALG",
365
+ message: `digest.alg must be one of: ${CANONICAL_DIGEST_ALGS.join(", ")}`,
366
+ field: `${fieldPath}.alg`
367
+ });
368
+ }
369
+ if (typeof d.value !== "string" || !DIGEST_VALUE_PATTERN.test(d.value)) {
370
+ digestErrors.push({
371
+ code: "E_INTERACTION_INVALID_DIGEST",
372
+ message: "digest.value must be 64 lowercase hex chars",
373
+ field: `${fieldPath}.value`
374
+ });
375
+ }
376
+ if (typeof d.bytes !== "number" || !Number.isInteger(d.bytes) || d.bytes < 0) {
377
+ digestErrors.push({
378
+ code: "E_INTERACTION_INVALID_DIGEST",
379
+ message: "digest.bytes must be a non-negative integer",
380
+ field: `${fieldPath}.bytes`
381
+ });
382
+ }
383
+ return { errors: digestErrors, valid: digestErrors.length === 0 };
384
+ };
385
+ if (obj.input !== void 0) {
386
+ const inputObj = obj.input;
387
+ if (inputObj.digest !== void 0) {
388
+ const result = validateDigest(inputObj.digest, "input.digest");
389
+ errors.push(...result.errors);
390
+ }
391
+ }
392
+ if (obj.output !== void 0) {
393
+ const outputObj = obj.output;
394
+ if (outputObj.digest !== void 0) {
395
+ const result = validateDigest(outputObj.digest, "output.digest");
396
+ errors.push(...result.errors);
397
+ }
398
+ }
399
+ if (typeof obj.completed_at === "string" && typeof obj.started_at === "string") {
400
+ const startedAt = new Date(obj.started_at).getTime();
401
+ const completedAt = new Date(obj.completed_at).getTime();
402
+ if (!isNaN(startedAt) && !isNaN(completedAt) && completedAt < startedAt) {
403
+ errors.push({
404
+ code: "E_INTERACTION_INVALID_TIMING",
405
+ message: "completed_at must be >= started_at",
406
+ field: "completed_at"
407
+ });
408
+ }
409
+ }
410
+ if (obj.output !== void 0) {
411
+ const result = obj.result;
412
+ if (!result?.status) {
413
+ errors.push({
414
+ code: "E_INTERACTION_MISSING_RESULT",
415
+ message: "result.status is required when output is present",
416
+ field: "result"
417
+ });
418
+ }
419
+ }
420
+ if (obj.result !== void 0) {
421
+ const result = obj.result;
422
+ if (result.status === "error") {
423
+ const hasErrorCode = Boolean(result.error_code);
424
+ const hasNonEmptyExtensions = obj.extensions !== void 0 && typeof obj.extensions === "object" && obj.extensions !== null && Object.keys(obj.extensions).length > 0;
425
+ if (!hasErrorCode && !hasNonEmptyExtensions) {
426
+ errors.push({
427
+ code: "E_INTERACTION_MISSING_ERROR_DETAIL",
428
+ message: "error_code or non-empty extensions required when result.status is error",
429
+ field: "result.error_code"
430
+ });
431
+ }
432
+ }
433
+ }
434
+ if (obj.extensions !== void 0) {
435
+ if (typeof obj.extensions !== "object" || obj.extensions === null) {
436
+ errors.push({
437
+ code: "E_INTERACTION_INVALID_FORMAT",
438
+ message: "extensions must be an object",
439
+ field: "extensions"
440
+ });
441
+ } else {
442
+ for (const key of Object.keys(obj.extensions)) {
443
+ if (!EXTENSION_KEY_PATTERN.test(key)) {
444
+ errors.push({
445
+ code: "E_INTERACTION_INVALID_EXTENSION_KEY",
446
+ message: `Invalid extension key format: "${key}" (must be reverse-DNS/name[@version])`,
447
+ field: `extensions.${key}`
448
+ });
449
+ }
450
+ }
451
+ }
452
+ }
453
+ const kind = obj.kind;
454
+ const hasTool = obj.tool !== void 0;
455
+ const hasResource = obj.resource !== void 0;
456
+ if (requiresTool(kind) && !hasTool) {
457
+ errors.push({
458
+ code: "E_INTERACTION_MISSING_TARGET",
459
+ message: `kind "${kind}" requires tool field`,
460
+ field: "tool"
461
+ });
462
+ }
463
+ if (requiresResource(kind)) {
464
+ if (!hasResource) {
465
+ errors.push({
466
+ code: "E_INTERACTION_MISSING_TARGET",
467
+ message: `kind "${kind}" requires resource field`,
468
+ field: "resource"
469
+ });
470
+ } else if (!hasMeaningfulResource(obj.resource)) {
471
+ errors.push({
472
+ code: "E_INTERACTION_MISSING_TARGET",
473
+ message: `kind "${kind}" requires resource.uri to be non-empty`,
474
+ field: "resource.uri"
475
+ });
476
+ }
477
+ }
478
+ if (!hasTool && !hasResource && errors.length === 0) {
479
+ warnings.push({
480
+ code: "W_INTERACTION_MISSING_TARGET",
481
+ message: "Neither tool nor resource field is present",
482
+ field: "tool"
483
+ });
484
+ }
485
+ if (errors.length > 0) {
486
+ return { valid: false, errors, warnings };
487
+ }
488
+ const zodResult = InteractionEvidenceV01Schema.safeParse(input);
489
+ if (!zodResult.success) {
490
+ return {
491
+ valid: false,
492
+ errors: [
493
+ {
494
+ code: "E_INTERACTION_INVALID_FORMAT",
495
+ message: zodResult.error.issues[0]?.message || "Schema validation failed",
496
+ field: zodResult.error.issues[0]?.path.join(".")
497
+ }
498
+ ],
499
+ warnings
500
+ };
501
+ }
502
+ return { valid: true, value: zodResult.data, warnings };
503
+ }
504
+ function validateInteraction(input) {
505
+ const result = validateInteractionOrdered(input);
506
+ if (result.valid) {
507
+ return { valid: true };
508
+ }
509
+ const firstError = result.errors[0];
510
+ return {
511
+ valid: false,
512
+ error_code: firstError?.code,
513
+ error_field: firstError?.field
514
+ };
515
+ }
516
+ function validateInteractionEvidence(evidence) {
517
+ return InteractionEvidenceV01Schema.parse(evidence);
518
+ }
519
+ function isValidInteractionEvidence(evidence) {
520
+ return InteractionEvidenceV01Schema.safeParse(evidence).success;
521
+ }
522
+ function isWellKnownKind(kind) {
523
+ return WELL_KNOWN_KINDS.includes(kind);
524
+ }
525
+ function isReservedKindPrefix(kind) {
526
+ return RESERVED_KIND_PREFIXES.some((prefix) => kind.startsWith(prefix));
527
+ }
528
+ function isDigestTruncated(digest) {
529
+ return digest.alg.startsWith("sha-256:trunc-");
530
+ }
531
+ function getInteraction(receipt) {
532
+ return receipt.evidence?.extensions?.[INTERACTION_EXTENSION_KEY];
533
+ }
534
+ function setInteraction(receipt, interaction) {
535
+ if (!receipt.evidence) {
536
+ receipt.evidence = {};
537
+ }
538
+ if (!receipt.evidence.extensions) {
539
+ receipt.evidence.extensions = {};
540
+ }
541
+ receipt.evidence.extensions[INTERACTION_EXTENSION_KEY] = interaction;
542
+ }
543
+ function hasInteraction(receipt) {
544
+ return receipt.evidence?.extensions?.[INTERACTION_EXTENSION_KEY] !== void 0;
545
+ }
546
+ function createReceiptView(envelope) {
547
+ const interaction = getInteraction(envelope);
548
+ const workflow = envelope.auth?.extensions?.["org.peacprotocol/workflow"];
549
+ return {
550
+ envelope,
551
+ interaction,
552
+ interactions: interaction ? [interaction] : [],
553
+ workflow
554
+ };
555
+ }
556
+ function createInteractionEvidence(params) {
557
+ const evidence = {
558
+ interaction_id: params.interaction_id,
559
+ kind: params.kind,
560
+ executor: {
561
+ platform: params.executor.platform,
562
+ ...params.executor.version && { version: params.executor.version },
563
+ ...params.executor.plugin_id && { plugin_id: params.executor.plugin_id },
564
+ ...params.executor.plugin_digest && { plugin_digest: params.executor.plugin_digest }
565
+ },
566
+ ...params.tool && { tool: params.tool },
567
+ ...params.resource && { resource: params.resource },
568
+ ...params.input && { input: params.input },
569
+ ...params.output && { output: params.output },
570
+ started_at: params.started_at,
571
+ ...params.completed_at && { completed_at: params.completed_at },
572
+ ...params.duration_ms !== void 0 && { duration_ms: params.duration_ms },
573
+ ...params.result && { result: params.result },
574
+ ...params.policy && { policy: params.policy },
575
+ ...params.refs && { refs: params.refs },
576
+ ...params.extensions && { extensions: params.extensions }
577
+ };
578
+ return validateInteractionEvidence(evidence);
579
+ }
580
+
581
+ export { CANONICAL_DIGEST_ALGS, DIGEST_SIZE_CONSTANTS, DIGEST_VALUE_PATTERN, DigestAlgSchema, DigestSchema, EXTENSION_KEY_PATTERN, ExecutorSchema, INTERACTION_EXTENSION_KEY, INTERACTION_LIMITS, InteractionEvidenceV01Schema, KIND_FORMAT_PATTERN, KindSchema, POLICY_DECISIONS, PayloadRefSchema, PolicyContextSchema, REDACTION_MODES, RESERVED_KIND_PREFIXES, RESULT_STATUSES, RefsSchema, ResourceTargetSchema, ResultSchema, ToolTargetSchema, WELL_KNOWN_KINDS, createInteractionEvidence, createReceiptView, getInteraction, hasInteraction, isDigestTruncated, isReservedKindPrefix, isValidInteractionEvidence, isWellKnownKind, setInteraction, validateInteraction, validateInteractionEvidence, validateInteractionOrdered };
582
+ //# sourceMappingURL=interaction.mjs.map
583
+ //# sourceMappingURL=interaction.mjs.map