@peac/schema 0.10.9 → 0.10.11
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/LICENSE +1 -1
- package/dist/attestation-receipt.cjs +127 -0
- package/dist/attestation-receipt.cjs.map +1 -0
- package/dist/attestation-receipt.mjs +113 -0
- package/dist/attestation-receipt.mjs.map +1 -0
- package/dist/attribution.cjs +249 -0
- package/dist/attribution.cjs.map +1 -0
- package/dist/attribution.mjs +227 -0
- package/dist/attribution.mjs.map +1 -0
- package/dist/dispute.d.ts.map +1 -1
- package/dist/index.cjs +2818 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +2577 -0
- package/dist/index.mjs.map +1 -0
- package/dist/interaction.cjs +619 -0
- package/dist/interaction.cjs.map +1 -0
- package/dist/interaction.mjs +583 -0
- package/dist/interaction.mjs.map +1 -0
- package/dist/normalize.cjs +84 -0
- package/dist/normalize.cjs.map +1 -0
- package/dist/normalize.d.ts +15 -9
- package/dist/normalize.d.ts.map +1 -1
- package/dist/normalize.mjs +82 -0
- package/dist/normalize.mjs.map +1 -0
- package/dist/receipt-parser.cjs +333 -0
- package/dist/receipt-parser.cjs.map +1 -0
- package/dist/receipt-parser.mjs +331 -0
- package/dist/receipt-parser.mjs.map +1 -0
- package/dist/workflow.cjs +321 -0
- package/dist/workflow.cjs.map +1 -0
- package/dist/workflow.mjs +292 -0
- package/dist/workflow.mjs.map +1 -0
- package/package.json +50 -6
- package/dist/agent-identity.js +0 -357
- package/dist/agent-identity.js.map +0 -1
- package/dist/attestation-receipt.js +0 -249
- package/dist/attestation-receipt.js.map +0 -1
- package/dist/attribution.js +0 -444
- package/dist/attribution.js.map +0 -1
- package/dist/constants.js +0 -73
- package/dist/constants.js.map +0 -1
- package/dist/control.js +0 -9
- package/dist/control.js.map +0 -1
- package/dist/dispute.js +0 -832
- package/dist/dispute.js.map +0 -1
- package/dist/envelope.js +0 -9
- package/dist/envelope.js.map +0 -1
- package/dist/errors.js +0 -116
- package/dist/errors.js.map +0 -1
- package/dist/evidence.js +0 -8
- package/dist/evidence.js.map +0 -1
- package/dist/index.js +0 -283
- package/dist/index.js.map +0 -1
- package/dist/interaction.js +0 -918
- package/dist/interaction.js.map +0 -1
- package/dist/json.js +0 -267
- package/dist/json.js.map +0 -1
- package/dist/normalize.js +0 -103
- package/dist/normalize.js.map +0 -1
- package/dist/obligations.js +0 -337
- package/dist/obligations.js.map +0 -1
- package/dist/purpose.js +0 -296
- package/dist/purpose.js.map +0 -1
- package/dist/receipt-parser.js +0 -89
- package/dist/receipt-parser.js.map +0 -1
- package/dist/schemas.js +0 -7
- package/dist/schemas.js.map +0 -1
- package/dist/subject.js +0 -9
- package/dist/subject.js.map +0 -1
- package/dist/types.js +0 -6
- package/dist/types.js.map +0 -1
- package/dist/validators.js +0 -421
- package/dist/validators.js.map +0 -1
- package/dist/version.js +0 -7
- package/dist/version.js.map +0 -1
- package/dist/workflow.js +0 -523
- package/dist/workflow.js.map +0 -1
package/dist/dispute.js
DELETED
|
@@ -1,832 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DisputeAttestationSchema = exports.DISPUTE_TYPE = exports.DisputeEvidenceSchema = exports.DocumentRefSchema = exports.DisputeContactSchema = exports.ContactMethodSchema = exports.DisputeResolutionSchema = exports.RemediationSchema = exports.REMEDIATION_TYPES = exports.RemediationTypeSchema = exports.DISPUTE_OUTCOMES = exports.DisputeOutcomeSchema = exports.DISPUTE_TRANSITIONS = exports.TERMINAL_STATES = exports.DISPUTE_STATES = exports.DisputeStateSchema = exports.DisputeGroundsSchema = exports.DISPUTE_GROUNDS_CODES = exports.DisputeGroundsCodeSchema = exports.DISPUTE_TARGET_TYPES = exports.DisputeTargetTypeSchema = exports.DISPUTE_TYPES = exports.DisputeTypeSchema = exports.DisputeIdSchema = exports.DISPUTE_LIMITS = void 0;
|
|
4
|
-
exports.canTransitionTo = canTransitionTo;
|
|
5
|
-
exports.isTerminalState = isTerminalState;
|
|
6
|
-
exports.getValidTransitions = getValidTransitions;
|
|
7
|
-
exports.validateDisputeAttestation = validateDisputeAttestation;
|
|
8
|
-
exports.isValidDisputeAttestation = isValidDisputeAttestation;
|
|
9
|
-
exports.isDisputeAttestation = isDisputeAttestation;
|
|
10
|
-
exports.validateDisputeResolution = validateDisputeResolution;
|
|
11
|
-
exports.validateDisputeContact = validateDisputeContact;
|
|
12
|
-
exports.createDisputeAttestation = createDisputeAttestation;
|
|
13
|
-
exports.transitionDisputeState = transitionDisputeState;
|
|
14
|
-
exports.isDisputeExpired = isDisputeExpired;
|
|
15
|
-
exports.isDisputeNotYetValid = isDisputeNotYetValid;
|
|
16
|
-
/**
|
|
17
|
-
* Dispute Attestation Types and Validators (v0.9.27+)
|
|
18
|
-
*
|
|
19
|
-
* Provides formal mechanism for contesting PEAC receipts, attributions,
|
|
20
|
-
* and identity claims with lifecycle state management.
|
|
21
|
-
*
|
|
22
|
-
* @see docs/specs/DISPUTE.md for normative specification
|
|
23
|
-
*/
|
|
24
|
-
const zod_1 = require("zod");
|
|
25
|
-
const attribution_1 = require("./attribution");
|
|
26
|
-
// =============================================================================
|
|
27
|
-
// DISPUTE LIMITS (v0.9.27+)
|
|
28
|
-
// =============================================================================
|
|
29
|
-
/**
|
|
30
|
-
* Dispute limits for DoS protection and validation.
|
|
31
|
-
*
|
|
32
|
-
* These are implementation safety limits, not protocol constraints.
|
|
33
|
-
*/
|
|
34
|
-
exports.DISPUTE_LIMITS = {
|
|
35
|
-
/** Maximum grounds per dispute */
|
|
36
|
-
maxGrounds: 10,
|
|
37
|
-
/** Maximum supporting receipts */
|
|
38
|
-
maxSupportingReceipts: 50,
|
|
39
|
-
/** Maximum supporting attributions */
|
|
40
|
-
maxSupportingAttributions: 50,
|
|
41
|
-
/** Maximum supporting documents */
|
|
42
|
-
maxSupportingDocuments: 20,
|
|
43
|
-
/** Maximum description length in chars */
|
|
44
|
-
maxDescriptionLength: 4000,
|
|
45
|
-
/** Maximum details length per ground in chars */
|
|
46
|
-
maxGroundDetailsLength: 1000,
|
|
47
|
-
/** Maximum rationale length in chars */
|
|
48
|
-
maxRationaleLength: 4000,
|
|
49
|
-
/** Maximum remediation details length in chars */
|
|
50
|
-
maxRemediationDetailsLength: 4000,
|
|
51
|
-
/** Minimum description for 'other' dispute type */
|
|
52
|
-
minOtherDescriptionLength: 50,
|
|
53
|
-
};
|
|
54
|
-
// =============================================================================
|
|
55
|
-
// ULID VALIDATION (v0.9.27+)
|
|
56
|
-
// =============================================================================
|
|
57
|
-
/**
|
|
58
|
-
* ULID format regex: 26 characters, Crockford Base32, UPPERCASE ONLY.
|
|
59
|
-
*
|
|
60
|
-
* ULIDs are time-ordered, globally unique identifiers that are URL-safe.
|
|
61
|
-
* Format: 10 characters timestamp + 16 characters randomness
|
|
62
|
-
*
|
|
63
|
-
* CASE SENSITIVITY DECISION (v0.9.27):
|
|
64
|
-
* While the ULID spec allows case-insensitive decoding (lowercase is valid),
|
|
65
|
-
* PEAC enforces UPPERCASE as the canonical form for dispute IDs. This ensures:
|
|
66
|
-
* 1. Consistent string comparison without normalization
|
|
67
|
-
* 2. Predictable indexing and lookup in storage systems
|
|
68
|
-
* 3. Deterministic hash computation for audit trails
|
|
69
|
-
*
|
|
70
|
-
* Implementations generating ULIDs MUST use uppercase encoding.
|
|
71
|
-
* Implementations receiving ULIDs MAY normalize to uppercase before validation
|
|
72
|
-
* if interoperating with systems that produce lowercase, but SHOULD warn.
|
|
73
|
-
*
|
|
74
|
-
* @see https://github.com/ulid/spec
|
|
75
|
-
*/
|
|
76
|
-
const ULID_REGEX = /^[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
77
|
-
/**
|
|
78
|
-
* Dispute ID schema using ULID format.
|
|
79
|
-
*
|
|
80
|
-
* @example "01ARZ3NDEKTSV4RRFFQ69G5FAV"
|
|
81
|
-
*/
|
|
82
|
-
exports.DisputeIdSchema = zod_1.z.string().regex(ULID_REGEX, 'Invalid ULID format');
|
|
83
|
-
// =============================================================================
|
|
84
|
-
// DISPUTE TYPES (v0.9.27+)
|
|
85
|
-
// =============================================================================
|
|
86
|
-
/**
|
|
87
|
-
* Type of dispute being filed.
|
|
88
|
-
*
|
|
89
|
-
* - 'unauthorized_access': Content accessed without valid receipt
|
|
90
|
-
* - 'attribution_missing': Used content without attribution
|
|
91
|
-
* - 'attribution_incorrect': Attribution exists but is wrong
|
|
92
|
-
* - 'receipt_invalid': Receipt was fraudulently issued
|
|
93
|
-
* - 'identity_spoofed': Agent identity was impersonated
|
|
94
|
-
* - 'purpose_mismatch': Declared purpose doesn't match actual use
|
|
95
|
-
* - 'policy_violation': Terms/policy violated despite receipt
|
|
96
|
-
* - 'other': Catch-all (requires description >= 50 chars)
|
|
97
|
-
*/
|
|
98
|
-
exports.DisputeTypeSchema = zod_1.z.enum([
|
|
99
|
-
'unauthorized_access',
|
|
100
|
-
'attribution_missing',
|
|
101
|
-
'attribution_incorrect',
|
|
102
|
-
'receipt_invalid',
|
|
103
|
-
'identity_spoofed',
|
|
104
|
-
'purpose_mismatch',
|
|
105
|
-
'policy_violation',
|
|
106
|
-
'other',
|
|
107
|
-
]);
|
|
108
|
-
/**
|
|
109
|
-
* Array of valid dispute types for runtime checks.
|
|
110
|
-
*/
|
|
111
|
-
exports.DISPUTE_TYPES = [
|
|
112
|
-
'unauthorized_access',
|
|
113
|
-
'attribution_missing',
|
|
114
|
-
'attribution_incorrect',
|
|
115
|
-
'receipt_invalid',
|
|
116
|
-
'identity_spoofed',
|
|
117
|
-
'purpose_mismatch',
|
|
118
|
-
'policy_violation',
|
|
119
|
-
'other',
|
|
120
|
-
];
|
|
121
|
-
// =============================================================================
|
|
122
|
-
// DISPUTE TARGET TYPES (v0.9.27+)
|
|
123
|
-
// =============================================================================
|
|
124
|
-
/**
|
|
125
|
-
* Type of entity being disputed.
|
|
126
|
-
*
|
|
127
|
-
* - 'receipt': A PEAC receipt
|
|
128
|
-
* - 'attribution': An attribution attestation
|
|
129
|
-
* - 'identity': An agent identity attestation
|
|
130
|
-
* - 'policy': A policy decision or enforcement
|
|
131
|
-
*/
|
|
132
|
-
exports.DisputeTargetTypeSchema = zod_1.z.enum(['receipt', 'attribution', 'identity', 'policy']);
|
|
133
|
-
/**
|
|
134
|
-
* Array of valid target types for runtime checks.
|
|
135
|
-
*/
|
|
136
|
-
exports.DISPUTE_TARGET_TYPES = ['receipt', 'attribution', 'identity', 'policy'];
|
|
137
|
-
// =============================================================================
|
|
138
|
-
// DISPUTE GROUNDS (v0.9.27+)
|
|
139
|
-
// =============================================================================
|
|
140
|
-
/**
|
|
141
|
-
* Specific grounds for the dispute.
|
|
142
|
-
*
|
|
143
|
-
* Evidence-based:
|
|
144
|
-
* - 'missing_receipt': No receipt exists for access
|
|
145
|
-
* - 'expired_receipt': Receipt was expired at time of use
|
|
146
|
-
* - 'forged_receipt': Receipt signature invalid or tampered
|
|
147
|
-
* - 'receipt_not_applicable': Receipt doesn't cover the resource
|
|
148
|
-
*
|
|
149
|
-
* Attribution-based:
|
|
150
|
-
* - 'content_not_used': Content was not actually used
|
|
151
|
-
* - 'source_misidentified': Wrong source attributed
|
|
152
|
-
* - 'usage_type_wrong': RAG claimed but was training, etc.
|
|
153
|
-
* - 'weight_inaccurate': Attribution weight is incorrect
|
|
154
|
-
*
|
|
155
|
-
* Identity-based:
|
|
156
|
-
* - 'agent_impersonation': Agent ID was spoofed
|
|
157
|
-
* - 'key_compromise': Signing key was compromised
|
|
158
|
-
* - 'delegation_invalid': Delegation chain is broken
|
|
159
|
-
*
|
|
160
|
-
* Policy-based:
|
|
161
|
-
* - 'purpose_exceeded': Used beyond declared purpose
|
|
162
|
-
* - 'terms_violated': Specific terms were violated
|
|
163
|
-
* - 'rate_limit_exceeded': Exceeded rate limits
|
|
164
|
-
*/
|
|
165
|
-
exports.DisputeGroundsCodeSchema = zod_1.z.enum([
|
|
166
|
-
// Evidence-based
|
|
167
|
-
'missing_receipt',
|
|
168
|
-
'expired_receipt',
|
|
169
|
-
'forged_receipt',
|
|
170
|
-
'receipt_not_applicable',
|
|
171
|
-
// Attribution-based
|
|
172
|
-
'content_not_used',
|
|
173
|
-
'source_misidentified',
|
|
174
|
-
'usage_type_wrong',
|
|
175
|
-
'weight_inaccurate',
|
|
176
|
-
// Identity-based
|
|
177
|
-
'agent_impersonation',
|
|
178
|
-
'key_compromise',
|
|
179
|
-
'delegation_invalid',
|
|
180
|
-
// Policy-based
|
|
181
|
-
'purpose_exceeded',
|
|
182
|
-
'terms_violated',
|
|
183
|
-
'rate_limit_exceeded',
|
|
184
|
-
]);
|
|
185
|
-
/**
|
|
186
|
-
* Array of valid grounds codes for runtime checks.
|
|
187
|
-
*/
|
|
188
|
-
exports.DISPUTE_GROUNDS_CODES = [
|
|
189
|
-
'missing_receipt',
|
|
190
|
-
'expired_receipt',
|
|
191
|
-
'forged_receipt',
|
|
192
|
-
'receipt_not_applicable',
|
|
193
|
-
'content_not_used',
|
|
194
|
-
'source_misidentified',
|
|
195
|
-
'usage_type_wrong',
|
|
196
|
-
'weight_inaccurate',
|
|
197
|
-
'agent_impersonation',
|
|
198
|
-
'key_compromise',
|
|
199
|
-
'delegation_invalid',
|
|
200
|
-
'purpose_exceeded',
|
|
201
|
-
'terms_violated',
|
|
202
|
-
'rate_limit_exceeded',
|
|
203
|
-
];
|
|
204
|
-
/**
|
|
205
|
-
* Individual dispute ground with supporting evidence reference.
|
|
206
|
-
*/
|
|
207
|
-
exports.DisputeGroundsSchema = zod_1.z
|
|
208
|
-
.object({
|
|
209
|
-
/** Specific code for this ground (REQUIRED) */
|
|
210
|
-
code: exports.DisputeGroundsCodeSchema,
|
|
211
|
-
/** Reference to supporting evidence (OPTIONAL) */
|
|
212
|
-
evidence_ref: zod_1.z.string().max(2048).optional(),
|
|
213
|
-
/** Additional context for this ground (OPTIONAL) */
|
|
214
|
-
details: zod_1.z.string().max(exports.DISPUTE_LIMITS.maxGroundDetailsLength).optional(),
|
|
215
|
-
})
|
|
216
|
-
.strict();
|
|
217
|
-
// =============================================================================
|
|
218
|
-
// DISPUTE LIFECYCLE STATES (v0.9.27+)
|
|
219
|
-
// =============================================================================
|
|
220
|
-
/**
|
|
221
|
-
* Dispute lifecycle states.
|
|
222
|
-
*
|
|
223
|
-
* State flow:
|
|
224
|
-
* ```
|
|
225
|
-
* FILED -> ACKNOWLEDGED -> UNDER_REVIEW -> RESOLVED
|
|
226
|
-
* | | |
|
|
227
|
-
* +-> REJECTED +-> ESCALATED +-> APPEALED
|
|
228
|
-
* |
|
|
229
|
-
* +-> FINAL
|
|
230
|
-
* ```
|
|
231
|
-
*
|
|
232
|
-
* Terminal states (REQUIRE resolution): resolved, rejected, final
|
|
233
|
-
* Non-terminal states: filed, acknowledged, under_review, escalated, appealed
|
|
234
|
-
*/
|
|
235
|
-
exports.DisputeStateSchema = zod_1.z.enum([
|
|
236
|
-
'filed',
|
|
237
|
-
'acknowledged',
|
|
238
|
-
'under_review',
|
|
239
|
-
'escalated',
|
|
240
|
-
'resolved',
|
|
241
|
-
'rejected',
|
|
242
|
-
'appealed',
|
|
243
|
-
'final',
|
|
244
|
-
]);
|
|
245
|
-
/**
|
|
246
|
-
* Array of valid dispute states for runtime checks.
|
|
247
|
-
*/
|
|
248
|
-
exports.DISPUTE_STATES = [
|
|
249
|
-
'filed',
|
|
250
|
-
'acknowledged',
|
|
251
|
-
'under_review',
|
|
252
|
-
'escalated',
|
|
253
|
-
'resolved',
|
|
254
|
-
'rejected',
|
|
255
|
-
'appealed',
|
|
256
|
-
'final',
|
|
257
|
-
];
|
|
258
|
-
/**
|
|
259
|
-
* Terminal states that REQUIRE a resolution field.
|
|
260
|
-
*/
|
|
261
|
-
exports.TERMINAL_STATES = ['resolved', 'rejected', 'final'];
|
|
262
|
-
/**
|
|
263
|
-
* Canonical state transition table for dispute lifecycle.
|
|
264
|
-
*
|
|
265
|
-
* This is the SINGLE SOURCE OF TRUTH for valid transitions.
|
|
266
|
-
* Do not duplicate elsewhere - reference this constant.
|
|
267
|
-
*/
|
|
268
|
-
exports.DISPUTE_TRANSITIONS = {
|
|
269
|
-
filed: ['acknowledged', 'rejected'],
|
|
270
|
-
acknowledged: ['under_review', 'rejected'],
|
|
271
|
-
under_review: ['resolved', 'escalated'],
|
|
272
|
-
escalated: ['resolved'],
|
|
273
|
-
resolved: ['appealed', 'final'],
|
|
274
|
-
rejected: ['appealed', 'final'],
|
|
275
|
-
appealed: ['under_review', 'final'],
|
|
276
|
-
final: [], // Terminal - no transitions out
|
|
277
|
-
};
|
|
278
|
-
/**
|
|
279
|
-
* Check if a state transition is valid.
|
|
280
|
-
*
|
|
281
|
-
* @param current - Current dispute state
|
|
282
|
-
* @param next - Proposed next state
|
|
283
|
-
* @returns True if the transition is valid
|
|
284
|
-
*/
|
|
285
|
-
function canTransitionTo(current, next) {
|
|
286
|
-
return exports.DISPUTE_TRANSITIONS[current].includes(next);
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Check if a state is terminal (requires resolution).
|
|
290
|
-
*
|
|
291
|
-
* @param state - Dispute state to check
|
|
292
|
-
* @returns True if the state is terminal
|
|
293
|
-
*/
|
|
294
|
-
function isTerminalState(state) {
|
|
295
|
-
return exports.TERMINAL_STATES.includes(state);
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Get valid next states from current state.
|
|
299
|
-
*
|
|
300
|
-
* @param current - Current dispute state
|
|
301
|
-
* @returns Array of valid next states
|
|
302
|
-
*/
|
|
303
|
-
function getValidTransitions(current) {
|
|
304
|
-
return exports.DISPUTE_TRANSITIONS[current];
|
|
305
|
-
}
|
|
306
|
-
// =============================================================================
|
|
307
|
-
// DISPUTE OUTCOME AND RESOLUTION (v0.9.27+)
|
|
308
|
-
// =============================================================================
|
|
309
|
-
/**
|
|
310
|
-
* Outcome of a resolved dispute.
|
|
311
|
-
*
|
|
312
|
-
* - 'upheld': Dispute was valid, in favor of filer
|
|
313
|
-
* - 'dismissed': Dispute invalid or without merit
|
|
314
|
-
* - 'partially_upheld': Some grounds upheld, others dismissed
|
|
315
|
-
* - 'settled': Parties reached agreement
|
|
316
|
-
*/
|
|
317
|
-
exports.DisputeOutcomeSchema = zod_1.z.enum(['upheld', 'dismissed', 'partially_upheld', 'settled']);
|
|
318
|
-
/**
|
|
319
|
-
* Array of valid outcomes for runtime checks.
|
|
320
|
-
*/
|
|
321
|
-
exports.DISPUTE_OUTCOMES = ['upheld', 'dismissed', 'partially_upheld', 'settled'];
|
|
322
|
-
/**
|
|
323
|
-
* Type of remediation action taken.
|
|
324
|
-
*
|
|
325
|
-
* - 'attribution_corrected': Attribution was fixed
|
|
326
|
-
* - 'receipt_revoked': Receipt was revoked
|
|
327
|
-
* - 'access_restored': Access was restored
|
|
328
|
-
* - 'compensation': Financial compensation provided
|
|
329
|
-
* - 'policy_updated': Policy was updated
|
|
330
|
-
* - 'no_action': No action required
|
|
331
|
-
* - 'other': Other remediation
|
|
332
|
-
*/
|
|
333
|
-
exports.RemediationTypeSchema = zod_1.z.enum([
|
|
334
|
-
'attribution_corrected',
|
|
335
|
-
'receipt_revoked',
|
|
336
|
-
'access_restored',
|
|
337
|
-
'compensation',
|
|
338
|
-
'policy_updated',
|
|
339
|
-
'no_action',
|
|
340
|
-
'other',
|
|
341
|
-
]);
|
|
342
|
-
/**
|
|
343
|
-
* Array of valid remediation types for runtime checks.
|
|
344
|
-
*/
|
|
345
|
-
exports.REMEDIATION_TYPES = [
|
|
346
|
-
'attribution_corrected',
|
|
347
|
-
'receipt_revoked',
|
|
348
|
-
'access_restored',
|
|
349
|
-
'compensation',
|
|
350
|
-
'policy_updated',
|
|
351
|
-
'no_action',
|
|
352
|
-
'other',
|
|
353
|
-
];
|
|
354
|
-
/**
|
|
355
|
-
* Remediation action taken to address the dispute.
|
|
356
|
-
*/
|
|
357
|
-
exports.RemediationSchema = zod_1.z
|
|
358
|
-
.object({
|
|
359
|
-
/** Type of remediation (REQUIRED) */
|
|
360
|
-
type: exports.RemediationTypeSchema,
|
|
361
|
-
/** Details of the remediation action (REQUIRED) */
|
|
362
|
-
details: zod_1.z.string().min(1).max(exports.DISPUTE_LIMITS.maxRemediationDetailsLength),
|
|
363
|
-
/** Deadline for completing remediation (OPTIONAL) */
|
|
364
|
-
deadline: zod_1.z.string().datetime().optional(),
|
|
365
|
-
})
|
|
366
|
-
.strict();
|
|
367
|
-
/**
|
|
368
|
-
* Resolution of a dispute.
|
|
369
|
-
*
|
|
370
|
-
* Required for terminal states (resolved, rejected, final).
|
|
371
|
-
*/
|
|
372
|
-
exports.DisputeResolutionSchema = zod_1.z
|
|
373
|
-
.object({
|
|
374
|
-
/** Outcome of the dispute (REQUIRED) */
|
|
375
|
-
outcome: exports.DisputeOutcomeSchema,
|
|
376
|
-
/** When the decision was made (REQUIRED) */
|
|
377
|
-
decided_at: zod_1.z.string().datetime(),
|
|
378
|
-
/** Who made the decision (REQUIRED) */
|
|
379
|
-
decided_by: zod_1.z.string().min(1).max(2048),
|
|
380
|
-
/** Explanation of the decision (REQUIRED) */
|
|
381
|
-
rationale: zod_1.z.string().min(1).max(exports.DISPUTE_LIMITS.maxRationaleLength),
|
|
382
|
-
/** Remediation action if applicable (OPTIONAL) */
|
|
383
|
-
remediation: exports.RemediationSchema.optional(),
|
|
384
|
-
})
|
|
385
|
-
.strict();
|
|
386
|
-
// =============================================================================
|
|
387
|
-
// DISPUTE CONTACT (v0.9.27+)
|
|
388
|
-
// =============================================================================
|
|
389
|
-
/**
|
|
390
|
-
* Contact method for dispute resolution.
|
|
391
|
-
*
|
|
392
|
-
* - 'email': Email address
|
|
393
|
-
* - 'url': URL (webhook, contact form)
|
|
394
|
-
* - 'did': Decentralized identifier
|
|
395
|
-
*/
|
|
396
|
-
exports.ContactMethodSchema = zod_1.z.enum(['email', 'url', 'did']);
|
|
397
|
-
/**
|
|
398
|
-
* Contact information for dispute communication.
|
|
399
|
-
*
|
|
400
|
-
* Validated based on method type.
|
|
401
|
-
*/
|
|
402
|
-
exports.DisputeContactSchema = zod_1.z
|
|
403
|
-
.object({
|
|
404
|
-
/** Contact method (REQUIRED) */
|
|
405
|
-
method: exports.ContactMethodSchema,
|
|
406
|
-
/** Contact value (REQUIRED) */
|
|
407
|
-
value: zod_1.z.string().min(1).max(2048),
|
|
408
|
-
})
|
|
409
|
-
.strict()
|
|
410
|
-
.superRefine((contact, ctx) => {
|
|
411
|
-
if (contact.method === 'email') {
|
|
412
|
-
// Basic email validation (RFC 5322 simplified)
|
|
413
|
-
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
414
|
-
if (!emailRegex.test(contact.value)) {
|
|
415
|
-
ctx.addIssue({
|
|
416
|
-
code: zod_1.z.ZodIssueCode.custom,
|
|
417
|
-
message: 'Invalid email format',
|
|
418
|
-
path: ['value'],
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
else if (contact.method === 'did') {
|
|
423
|
-
// DID must start with did:
|
|
424
|
-
if (!contact.value.startsWith('did:')) {
|
|
425
|
-
ctx.addIssue({
|
|
426
|
-
code: zod_1.z.ZodIssueCode.custom,
|
|
427
|
-
message: 'DID must start with "did:"',
|
|
428
|
-
path: ['value'],
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
else if (contact.method === 'url') {
|
|
433
|
-
// URL validation
|
|
434
|
-
try {
|
|
435
|
-
new URL(contact.value);
|
|
436
|
-
}
|
|
437
|
-
catch {
|
|
438
|
-
ctx.addIssue({
|
|
439
|
-
code: zod_1.z.ZodIssueCode.custom,
|
|
440
|
-
message: 'Invalid URL format',
|
|
441
|
-
path: ['value'],
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
});
|
|
446
|
-
// =============================================================================
|
|
447
|
-
// DOCUMENT REFERENCE (v0.9.27+)
|
|
448
|
-
// =============================================================================
|
|
449
|
-
/**
|
|
450
|
-
* Reference to an external document supporting the dispute.
|
|
451
|
-
*/
|
|
452
|
-
exports.DocumentRefSchema = zod_1.z
|
|
453
|
-
.object({
|
|
454
|
-
/** URI of the document (REQUIRED) */
|
|
455
|
-
uri: zod_1.z.string().url().max(2048),
|
|
456
|
-
/** Content hash for integrity verification (OPTIONAL) */
|
|
457
|
-
content_hash: attribution_1.ContentHashSchema.optional(),
|
|
458
|
-
/** Brief description of the document (OPTIONAL) */
|
|
459
|
-
description: zod_1.z.string().max(500).optional(),
|
|
460
|
-
})
|
|
461
|
-
.strict();
|
|
462
|
-
// =============================================================================
|
|
463
|
-
// DISPUTE EVIDENCE (v0.9.27+)
|
|
464
|
-
// =============================================================================
|
|
465
|
-
/**
|
|
466
|
-
* Base evidence schema without invariants.
|
|
467
|
-
*/
|
|
468
|
-
const DisputeEvidenceBaseSchema = zod_1.z
|
|
469
|
-
.object({
|
|
470
|
-
/** Type of dispute (REQUIRED) */
|
|
471
|
-
dispute_type: exports.DisputeTypeSchema,
|
|
472
|
-
/** Reference to disputed target: jti:{id}, URL, or URN (REQUIRED) */
|
|
473
|
-
target_ref: zod_1.z.string().min(1).max(2048),
|
|
474
|
-
/** Type of target being disputed (REQUIRED) */
|
|
475
|
-
target_type: exports.DisputeTargetTypeSchema,
|
|
476
|
-
/** Grounds for the dispute (REQUIRED, at least 1) */
|
|
477
|
-
grounds: zod_1.z.array(exports.DisputeGroundsSchema).min(1).max(exports.DISPUTE_LIMITS.maxGrounds),
|
|
478
|
-
/** Human-readable description (REQUIRED) */
|
|
479
|
-
description: zod_1.z.string().min(1).max(exports.DISPUTE_LIMITS.maxDescriptionLength),
|
|
480
|
-
/** Receipt references supporting the claim (OPTIONAL) */
|
|
481
|
-
supporting_receipts: zod_1.z
|
|
482
|
-
.array(zod_1.z.string().max(2048))
|
|
483
|
-
.max(exports.DISPUTE_LIMITS.maxSupportingReceipts)
|
|
484
|
-
.optional(),
|
|
485
|
-
/** Attribution references supporting the claim (OPTIONAL) */
|
|
486
|
-
supporting_attributions: zod_1.z
|
|
487
|
-
.array(zod_1.z.string().max(2048))
|
|
488
|
-
.max(exports.DISPUTE_LIMITS.maxSupportingAttributions)
|
|
489
|
-
.optional(),
|
|
490
|
-
/** External document references (OPTIONAL) */
|
|
491
|
-
supporting_documents: zod_1.z
|
|
492
|
-
.array(exports.DocumentRefSchema)
|
|
493
|
-
.max(exports.DISPUTE_LIMITS.maxSupportingDocuments)
|
|
494
|
-
.optional(),
|
|
495
|
-
/** Contact for dispute resolution (OPTIONAL) */
|
|
496
|
-
contact: exports.DisputeContactSchema.optional(),
|
|
497
|
-
/** Current lifecycle state (REQUIRED) */
|
|
498
|
-
state: exports.DisputeStateSchema,
|
|
499
|
-
/** When state was last changed (OPTIONAL) */
|
|
500
|
-
state_changed_at: zod_1.z.string().datetime().optional(),
|
|
501
|
-
/** Reason for state change (OPTIONAL) */
|
|
502
|
-
state_reason: zod_1.z.string().max(1000).optional(),
|
|
503
|
-
/** Resolution details (REQUIRED for terminal states) */
|
|
504
|
-
resolution: exports.DisputeResolutionSchema.optional(),
|
|
505
|
-
/** Advisory: filing window used by issuer in days (OPTIONAL, informative only) */
|
|
506
|
-
window_hint_days: zod_1.z.number().int().positive().max(365).optional(),
|
|
507
|
-
})
|
|
508
|
-
.strict();
|
|
509
|
-
/**
|
|
510
|
-
* Dispute evidence with cross-field invariants enforced via superRefine.
|
|
511
|
-
*
|
|
512
|
-
* Invariants:
|
|
513
|
-
* 1. Terminal states (resolved, rejected, final) REQUIRE resolution
|
|
514
|
-
* 2. Resolution is ONLY valid for terminal states
|
|
515
|
-
* 3. Dispute type 'other' requires description >= 50 characters
|
|
516
|
-
*/
|
|
517
|
-
exports.DisputeEvidenceSchema = DisputeEvidenceBaseSchema.superRefine((evidence, ctx) => {
|
|
518
|
-
const terminalStates = ['resolved', 'rejected', 'final'];
|
|
519
|
-
// Invariant 1: Terminal states REQUIRE resolution
|
|
520
|
-
if (terminalStates.includes(evidence.state) && !evidence.resolution) {
|
|
521
|
-
ctx.addIssue({
|
|
522
|
-
code: zod_1.z.ZodIssueCode.custom,
|
|
523
|
-
message: `Resolution is required when state is "${evidence.state}"`,
|
|
524
|
-
path: ['resolution'],
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
// Invariant 2: Resolution REQUIRES terminal state
|
|
528
|
-
if (evidence.resolution && !terminalStates.includes(evidence.state)) {
|
|
529
|
-
ctx.addIssue({
|
|
530
|
-
code: zod_1.z.ZodIssueCode.custom,
|
|
531
|
-
message: `Resolution is only valid for terminal states (resolved, rejected, final), not "${evidence.state}"`,
|
|
532
|
-
path: ['state'],
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
// Invariant 3: 'other' dispute type requires meaningful description
|
|
536
|
-
if (evidence.dispute_type === 'other' &&
|
|
537
|
-
evidence.description.length < exports.DISPUTE_LIMITS.minOtherDescriptionLength) {
|
|
538
|
-
ctx.addIssue({
|
|
539
|
-
code: zod_1.z.ZodIssueCode.custom,
|
|
540
|
-
message: `Dispute type "other" requires description of at least ${exports.DISPUTE_LIMITS.minOtherDescriptionLength} characters`,
|
|
541
|
-
path: ['description'],
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
});
|
|
545
|
-
// =============================================================================
|
|
546
|
-
// DISPUTE ATTESTATION (v0.9.27+)
|
|
547
|
-
// =============================================================================
|
|
548
|
-
/**
|
|
549
|
-
* Attestation type literal for disputes.
|
|
550
|
-
*/
|
|
551
|
-
exports.DISPUTE_TYPE = 'peac/dispute';
|
|
552
|
-
/**
|
|
553
|
-
* DisputeAttestation - formal mechanism for contesting PEAC claims.
|
|
554
|
-
*
|
|
555
|
-
* This attestation provides a standardized way to dispute receipts,
|
|
556
|
-
* attributions, identity claims, or policy decisions.
|
|
557
|
-
*
|
|
558
|
-
* @example
|
|
559
|
-
* ```typescript
|
|
560
|
-
* const dispute: DisputeAttestation = {
|
|
561
|
-
* type: 'peac/dispute',
|
|
562
|
-
* issuer: 'https://publisher.example.com',
|
|
563
|
-
* issued_at: '2026-01-06T12:00:00Z',
|
|
564
|
-
* ref: '01ARZ3NDEKTSV4RRFFQ69G5FAV',
|
|
565
|
-
* evidence: {
|
|
566
|
-
* dispute_type: 'unauthorized_access',
|
|
567
|
-
* target_ref: 'jti:01H5KPT9QZA123456789VWXYZG',
|
|
568
|
-
* target_type: 'receipt',
|
|
569
|
-
* grounds: [{ code: 'missing_receipt' }],
|
|
570
|
-
* description: 'Content was accessed without a valid receipt.',
|
|
571
|
-
* state: 'filed',
|
|
572
|
-
* },
|
|
573
|
-
* };
|
|
574
|
-
* ```
|
|
575
|
-
*/
|
|
576
|
-
exports.DisputeAttestationSchema = zod_1.z
|
|
577
|
-
.object({
|
|
578
|
-
/** Attestation type (MUST be 'peac/dispute') */
|
|
579
|
-
type: zod_1.z.literal(exports.DISPUTE_TYPE),
|
|
580
|
-
/** Party filing the dispute (REQUIRED) */
|
|
581
|
-
issuer: zod_1.z.string().min(1).max(2048),
|
|
582
|
-
/** When the dispute was filed (REQUIRED) */
|
|
583
|
-
issued_at: zod_1.z.string().datetime(),
|
|
584
|
-
/** When the dispute expires (OPTIONAL) */
|
|
585
|
-
expires_at: zod_1.z.string().datetime().optional(),
|
|
586
|
-
/** Unique dispute reference in ULID format (REQUIRED) */
|
|
587
|
-
ref: exports.DisputeIdSchema,
|
|
588
|
-
/** Dispute evidence and state */
|
|
589
|
-
evidence: exports.DisputeEvidenceSchema,
|
|
590
|
-
})
|
|
591
|
-
.strict();
|
|
592
|
-
// =============================================================================
|
|
593
|
-
// VALIDATION HELPERS (v0.9.27+)
|
|
594
|
-
// =============================================================================
|
|
595
|
-
/**
|
|
596
|
-
* Validate a DisputeAttestation.
|
|
597
|
-
*
|
|
598
|
-
* @param data - Unknown data to validate
|
|
599
|
-
* @returns Result with validated attestation or error message
|
|
600
|
-
*
|
|
601
|
-
* @example
|
|
602
|
-
* ```typescript
|
|
603
|
-
* const result = validateDisputeAttestation(data);
|
|
604
|
-
* if (result.ok) {
|
|
605
|
-
* console.log('Dispute ref:', result.value.ref);
|
|
606
|
-
* } else {
|
|
607
|
-
* console.error('Validation error:', result.error);
|
|
608
|
-
* }
|
|
609
|
-
* ```
|
|
610
|
-
*/
|
|
611
|
-
function validateDisputeAttestation(data) {
|
|
612
|
-
const result = exports.DisputeAttestationSchema.safeParse(data);
|
|
613
|
-
if (result.success) {
|
|
614
|
-
return { ok: true, value: result.data };
|
|
615
|
-
}
|
|
616
|
-
return { ok: false, error: result.error.message };
|
|
617
|
-
}
|
|
618
|
-
/**
|
|
619
|
-
* Check if an object is a valid DisputeAttestation.
|
|
620
|
-
*
|
|
621
|
-
* @param data - Unknown data to check
|
|
622
|
-
* @returns True if valid
|
|
623
|
-
*/
|
|
624
|
-
function isValidDisputeAttestation(data) {
|
|
625
|
-
return exports.DisputeAttestationSchema.safeParse(data).success;
|
|
626
|
-
}
|
|
627
|
-
/**
|
|
628
|
-
* Check if an object has the dispute attestation type.
|
|
629
|
-
*
|
|
630
|
-
* @param attestation - Object with a type field
|
|
631
|
-
* @returns True if type is 'peac/dispute'
|
|
632
|
-
*/
|
|
633
|
-
function isDisputeAttestation(attestation) {
|
|
634
|
-
return attestation.type === exports.DISPUTE_TYPE;
|
|
635
|
-
}
|
|
636
|
-
/**
|
|
637
|
-
* Validate a DisputeResolution.
|
|
638
|
-
*
|
|
639
|
-
* @param data - Unknown data to validate
|
|
640
|
-
* @returns Result with validated resolution or error message
|
|
641
|
-
*/
|
|
642
|
-
function validateDisputeResolution(data) {
|
|
643
|
-
const result = exports.DisputeResolutionSchema.safeParse(data);
|
|
644
|
-
if (result.success) {
|
|
645
|
-
return { ok: true, value: result.data };
|
|
646
|
-
}
|
|
647
|
-
return { ok: false, error: result.error.message };
|
|
648
|
-
}
|
|
649
|
-
/**
|
|
650
|
-
* Validate a DisputeContact.
|
|
651
|
-
*
|
|
652
|
-
* @param data - Unknown data to validate
|
|
653
|
-
* @returns Result with validated contact or error message
|
|
654
|
-
*/
|
|
655
|
-
function validateDisputeContact(data) {
|
|
656
|
-
const result = exports.DisputeContactSchema.safeParse(data);
|
|
657
|
-
if (result.success) {
|
|
658
|
-
return { ok: true, value: result.data };
|
|
659
|
-
}
|
|
660
|
-
return { ok: false, error: result.error.message };
|
|
661
|
-
}
|
|
662
|
-
/**
|
|
663
|
-
* Create a DisputeAttestation with current timestamp and 'filed' state.
|
|
664
|
-
*
|
|
665
|
-
* @param params - Attestation parameters
|
|
666
|
-
* @returns A valid DisputeAttestation in 'filed' state
|
|
667
|
-
*
|
|
668
|
-
* @example
|
|
669
|
-
* ```typescript
|
|
670
|
-
* const dispute = createDisputeAttestation({
|
|
671
|
-
* issuer: 'https://publisher.example.com',
|
|
672
|
-
* ref: '01ARZ3NDEKTSV4RRFFQ69G5FAV',
|
|
673
|
-
* dispute_type: 'unauthorized_access',
|
|
674
|
-
* target_ref: 'jti:01H5KPT9QZA123456789VWXYZG',
|
|
675
|
-
* target_type: 'receipt',
|
|
676
|
-
* grounds: [{ code: 'missing_receipt' }],
|
|
677
|
-
* description: 'Content was accessed without a valid receipt.',
|
|
678
|
-
* });
|
|
679
|
-
* ```
|
|
680
|
-
*/
|
|
681
|
-
function createDisputeAttestation(params) {
|
|
682
|
-
const now = new Date().toISOString();
|
|
683
|
-
const evidence = {
|
|
684
|
-
dispute_type: params.dispute_type,
|
|
685
|
-
target_ref: params.target_ref,
|
|
686
|
-
target_type: params.target_type,
|
|
687
|
-
grounds: params.grounds,
|
|
688
|
-
description: params.description,
|
|
689
|
-
state: 'filed',
|
|
690
|
-
};
|
|
691
|
-
if (params.contact) {
|
|
692
|
-
evidence.contact = params.contact;
|
|
693
|
-
}
|
|
694
|
-
if (params.supporting_receipts) {
|
|
695
|
-
evidence.supporting_receipts = params.supporting_receipts;
|
|
696
|
-
}
|
|
697
|
-
if (params.supporting_attributions) {
|
|
698
|
-
evidence.supporting_attributions = params.supporting_attributions;
|
|
699
|
-
}
|
|
700
|
-
if (params.supporting_documents) {
|
|
701
|
-
evidence.supporting_documents = params.supporting_documents;
|
|
702
|
-
}
|
|
703
|
-
if (params.window_hint_days !== undefined) {
|
|
704
|
-
evidence.window_hint_days = params.window_hint_days;
|
|
705
|
-
}
|
|
706
|
-
const attestation = {
|
|
707
|
-
type: exports.DISPUTE_TYPE,
|
|
708
|
-
issuer: params.issuer,
|
|
709
|
-
issued_at: now,
|
|
710
|
-
ref: params.ref,
|
|
711
|
-
evidence,
|
|
712
|
-
};
|
|
713
|
-
if (params.expires_at) {
|
|
714
|
-
attestation.expires_at = params.expires_at;
|
|
715
|
-
}
|
|
716
|
-
return attestation;
|
|
717
|
-
}
|
|
718
|
-
/**
|
|
719
|
-
* Transition a dispute to a new state.
|
|
720
|
-
*
|
|
721
|
-
* @param dispute - Current dispute attestation
|
|
722
|
-
* @param newState - Target state
|
|
723
|
-
* @param reason - Reason for transition (optional)
|
|
724
|
-
* @param resolution - Resolution details (required for terminal states)
|
|
725
|
-
* @returns Updated dispute attestation or error
|
|
726
|
-
*
|
|
727
|
-
* @example
|
|
728
|
-
* ```typescript
|
|
729
|
-
* // Acknowledge a filed dispute
|
|
730
|
-
* const acknowledged = transitionDisputeState(
|
|
731
|
-
* dispute,
|
|
732
|
-
* 'acknowledged',
|
|
733
|
-
* 'Dispute received and under review'
|
|
734
|
-
* );
|
|
735
|
-
*
|
|
736
|
-
* // Resolve a dispute (terminal state requires resolution)
|
|
737
|
-
* const resolved = transitionDisputeState(
|
|
738
|
-
* dispute,
|
|
739
|
-
* 'resolved',
|
|
740
|
-
* 'Investigation complete',
|
|
741
|
-
* {
|
|
742
|
-
* outcome: 'upheld',
|
|
743
|
-
* decided_at: new Date().toISOString(),
|
|
744
|
-
* decided_by: 'https://platform.example.com',
|
|
745
|
-
* rationale: 'Evidence supports the claim.',
|
|
746
|
-
* }
|
|
747
|
-
* );
|
|
748
|
-
* ```
|
|
749
|
-
*/
|
|
750
|
-
function transitionDisputeState(dispute, newState, reason, resolution) {
|
|
751
|
-
const currentState = dispute.evidence.state;
|
|
752
|
-
// Check if transition is valid
|
|
753
|
-
if (!canTransitionTo(currentState, newState)) {
|
|
754
|
-
return {
|
|
755
|
-
ok: false,
|
|
756
|
-
error: `Invalid transition from "${currentState}" to "${newState}". Valid transitions: ${exports.DISPUTE_TRANSITIONS[currentState].join(', ') || 'none'}`,
|
|
757
|
-
code: 'INVALID_TRANSITION',
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
// Check resolution requirements
|
|
761
|
-
const isTargetTerminal = isTerminalState(newState);
|
|
762
|
-
if (isTargetTerminal && !resolution) {
|
|
763
|
-
return {
|
|
764
|
-
ok: false,
|
|
765
|
-
error: `Resolution is required when transitioning to terminal state "${newState}"`,
|
|
766
|
-
code: 'RESOLUTION_REQUIRED',
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
if (!isTargetTerminal && resolution) {
|
|
770
|
-
return {
|
|
771
|
-
ok: false,
|
|
772
|
-
error: `Resolution is not allowed for non-terminal state "${newState}"`,
|
|
773
|
-
code: 'RESOLUTION_NOT_ALLOWED',
|
|
774
|
-
};
|
|
775
|
-
}
|
|
776
|
-
// Create updated dispute
|
|
777
|
-
const now = new Date().toISOString();
|
|
778
|
-
// Destructure to separate resolution from other evidence fields
|
|
779
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
780
|
-
const { resolution: _existingResolution, ...evidenceWithoutResolution } = dispute.evidence;
|
|
781
|
-
// Build updated evidence: start without resolution, add back only if terminal
|
|
782
|
-
const updatedEvidence = {
|
|
783
|
-
...evidenceWithoutResolution,
|
|
784
|
-
state: newState,
|
|
785
|
-
state_changed_at: now,
|
|
786
|
-
};
|
|
787
|
-
if (reason) {
|
|
788
|
-
updatedEvidence.state_reason = reason;
|
|
789
|
-
}
|
|
790
|
-
// Only add resolution for terminal states
|
|
791
|
-
if (isTargetTerminal && resolution) {
|
|
792
|
-
updatedEvidence.resolution = resolution;
|
|
793
|
-
}
|
|
794
|
-
return {
|
|
795
|
-
ok: true,
|
|
796
|
-
value: {
|
|
797
|
-
...dispute,
|
|
798
|
-
evidence: updatedEvidence,
|
|
799
|
-
},
|
|
800
|
-
};
|
|
801
|
-
}
|
|
802
|
-
// =============================================================================
|
|
803
|
-
// TIME VALIDATION HELPERS (v0.9.27+)
|
|
804
|
-
// =============================================================================
|
|
805
|
-
/**
|
|
806
|
-
* Check if a dispute attestation is expired.
|
|
807
|
-
*
|
|
808
|
-
* @param attestation - The attestation to check
|
|
809
|
-
* @param clockSkew - Clock skew tolerance in milliseconds (default: 30000)
|
|
810
|
-
* @returns True if expired
|
|
811
|
-
*/
|
|
812
|
-
function isDisputeExpired(attestation, clockSkew = 30000) {
|
|
813
|
-
if (!attestation.expires_at) {
|
|
814
|
-
return false; // No expiry = never expires
|
|
815
|
-
}
|
|
816
|
-
const expiresAt = new Date(attestation.expires_at).getTime();
|
|
817
|
-
const now = Date.now();
|
|
818
|
-
return expiresAt < now - clockSkew;
|
|
819
|
-
}
|
|
820
|
-
/**
|
|
821
|
-
* Check if a dispute attestation is not yet valid (issued_at in future).
|
|
822
|
-
*
|
|
823
|
-
* @param attestation - The attestation to check
|
|
824
|
-
* @param clockSkew - Clock skew tolerance in milliseconds (default: 30000)
|
|
825
|
-
* @returns True if not yet valid
|
|
826
|
-
*/
|
|
827
|
-
function isDisputeNotYetValid(attestation, clockSkew = 30000) {
|
|
828
|
-
const issuedAt = new Date(attestation.issued_at).getTime();
|
|
829
|
-
const now = Date.now();
|
|
830
|
-
return issuedAt > now + clockSkew;
|
|
831
|
-
}
|
|
832
|
-
//# sourceMappingURL=dispute.js.map
|