capacity-attest 0.9.2 → 0.10.0

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,32 @@
1
+ /** The minimal shape this check needs — any object with the claim's `timestamp` field. */
2
+ export interface TimestampedClaim {
3
+ timestamp: string;
4
+ }
5
+ export type FreshnessResult = {
6
+ fresh: true;
7
+ } | {
8
+ fresh: false;
9
+ reason: "stale";
10
+ ageMs: number;
11
+ } | {
12
+ fresh: false;
13
+ reason: "timestamp_in_future";
14
+ ageMs: number;
15
+ } | {
16
+ fresh: false;
17
+ reason: "invalid_timestamp";
18
+ };
19
+ /**
20
+ * Checks a claim's own `timestamp` against `maxAgeMs`, as of `now`.
21
+ *
22
+ * Boundary is inclusive: a claim exactly `maxAgeMs` old is still fresh (`ageMs <= maxAgeMs`).
23
+ * A timestamp strictly in the future (ageMs < 0) is never "fresh" — that is not a freshness
24
+ * problem, it is a malformed-or-backdated claim, reported as its own distinct reason so a
25
+ * caller does not silently treat it as simply recent.
26
+ *
27
+ * Pure and synchronous: no network call, no state, nothing to feed with data. A timestamp
28
+ * comparison does not get "smarter" over time — it is a fixed rule, and that is deliberate:
29
+ * the whole point is that the verifier does not have to trust anything that changes.
30
+ */
31
+ export declare function checkClaimFreshness(claim: TimestampedClaim, maxAgeMs: number, now?: Date): FreshnessResult;
32
+ //# sourceMappingURL=freshness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.d.ts","sourceRoot":"","sources":["../src/freshness.ts"],"names":[],"mappings":"AAaA,0FAA0F;AAC1F,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GACf;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAElD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,IAAiB,GAAG,eAAe,CAiBtH"}
@@ -0,0 +1,39 @@
1
+ // freshness.ts — a verifier-side staleness check over the claim's own, already-signed
2
+ // `timestamp` field. Additive, same discipline as the rest of this package: no new schema
3
+ // field, no issuer-maintained registry, nothing a verifier has to trust beyond the signature
4
+ // itself. See README.md "Independently verifying a claim" for why `verifyClaim()` alone does
5
+ // NOT check this: a cryptographically valid signature says nothing about how old the claim is.
6
+ //
7
+ // Background: x402-foundation/x402 issue #2833 (imokokok, 6 Nov 2026) describes the same gap
8
+ // in a different design (a signed oracle verdict that stays byte-valid after the underlying
9
+ // venue went stale) and proposes an issuer-maintained STALE registry. This module is the
10
+ // alternative that needs no registry: every claim here already carries a mandatory timestamp
11
+ // as part of what got signed (schema.ts), so the verifier can apply its own policy without
12
+ // trusting anyone's ongoing diligence.
13
+ /**
14
+ * Checks a claim's own `timestamp` against `maxAgeMs`, as of `now`.
15
+ *
16
+ * Boundary is inclusive: a claim exactly `maxAgeMs` old is still fresh (`ageMs <= maxAgeMs`).
17
+ * A timestamp strictly in the future (ageMs < 0) is never "fresh" — that is not a freshness
18
+ * problem, it is a malformed-or-backdated claim, reported as its own distinct reason so a
19
+ * caller does not silently treat it as simply recent.
20
+ *
21
+ * Pure and synchronous: no network call, no state, nothing to feed with data. A timestamp
22
+ * comparison does not get "smarter" over time — it is a fixed rule, and that is deliberate:
23
+ * the whole point is that the verifier does not have to trust anything that changes.
24
+ */
25
+ export function checkClaimFreshness(claim, maxAgeMs, now = new Date()) {
26
+ const claimedAt = Date.parse(claim.timestamp);
27
+ if (Number.isNaN(claimedAt)) {
28
+ return { fresh: false, reason: "invalid_timestamp" };
29
+ }
30
+ const ageMs = now.getTime() - claimedAt;
31
+ if (ageMs < 0) {
32
+ return { fresh: false, reason: "timestamp_in_future", ageMs };
33
+ }
34
+ if (ageMs > maxAgeMs) {
35
+ return { fresh: false, reason: "stale", ageMs };
36
+ }
37
+ return { fresh: true };
38
+ }
39
+ //# sourceMappingURL=freshness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.js","sourceRoot":"","sources":["../src/freshness.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,0FAA0F;AAC1F,6FAA6F;AAC7F,6FAA6F;AAC7F,+FAA+F;AAC/F,EAAE;AACF,6FAA6F;AAC7F,4FAA4F;AAC5F,yFAAyF;AACzF,6FAA6F;AAC7F,2FAA2F;AAC3F,uCAAuC;AAavC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAuB,EAAE,QAAgB,EAAE,MAAY,IAAI,IAAI,EAAE;IACnG,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACvD,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC;IAExC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC;IAChE,CAAC;IAED,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;QACrB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAClD,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacity-attest",
3
- "version": "0.9.2",
3
+ "version": "0.10.0",
4
4
  "description": "MCP server for capacity-delivery attestations: after an x402 payment for compute capacity (GPU-hours, storage, API credits, bandwidth), the paying agent leaves a signed, factual claim of what was actually delivered, so other agents can check a seller's delivery history before paying. No reputation score, no judgment, no financial instrument.",
5
5
  "keywords": [
6
6
  "mcp",