@peac/audit 0.12.11 → 0.12.13

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.
@@ -85,4 +85,51 @@ export interface CreateCommerceBundleOptions {
85
85
  /** Optional creation timestamp (for deterministic output; defaults to now) */
86
86
  created_at?: string;
87
87
  }
88
+ /**
89
+ * Input record accepted by `groupByLifecycle`.
90
+ *
91
+ * Observational-only shape: callers provide the fields necessary for
92
+ * grouping without passing the full signed record. `session_ref` is the
93
+ * value the grouper keys on; records with the same `session_ref` end up
94
+ * in the same `LifecycleBundle`.
95
+ */
96
+ export interface LifecycleInputRecord {
97
+ /** Session or transaction identifier shared across a lifecycle. */
98
+ session_ref: string;
99
+ /**
100
+ * Observed commerce event name, per the upstream attestation. An
101
+ * empty, missing, null, or non-string value routes the record to the
102
+ * `unclassified` bucket; no event is synthesized.
103
+ */
104
+ commerce_event?: string | null;
105
+ /** Issued-at time (RFC 3339 string or unix seconds). */
106
+ iat: string | number;
107
+ /** SHA-256 hash of the JWS (used for deterministic tie-breaking). */
108
+ receipt_ref: string;
109
+ /** Optional opaque passthrough so callers can carry the full record. */
110
+ data?: Record<string, unknown>;
111
+ }
112
+ /**
113
+ * Reserved bucket name for records whose `commerce_event` is absent,
114
+ * null, empty, or not a string. No lifecycle semantics are inferred;
115
+ * `unclassified` preserves the record as observed and never promotes
116
+ * it into an interpreted bucket.
117
+ */
118
+ export declare const UNCLASSIFIED_LIFECYCLE_BUCKET: "unclassified";
119
+ /**
120
+ * One session's records grouped by the event name each record carries,
121
+ * observational only. `buckets` keys are the literal `commerce_event`
122
+ * values the upstream attested (or `'unclassified'` for records with
123
+ * no event). Buckets with zero records are omitted.
124
+ */
125
+ export interface LifecycleBundle {
126
+ /** Session or transaction identifier shared by every record in the bundle. */
127
+ session_ref: string;
128
+ /** Per-event record lists, keyed by the upstream event name. */
129
+ buckets: Record<string, LifecycleInputRecord[]>;
130
+ /** Total number of records in the bundle (sum across buckets). */
131
+ record_count: number;
132
+ /** Bundle format version (same experimental constant as commerce bundles). */
133
+ version: typeof COMMERCE_BUNDLE_VERSION;
134
+ }
88
135
  //# sourceMappingURL=commerce-bundle-types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"commerce-bundle-types.d.ts","sourceRoot":"","sources":["../src/commerce-bundle-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,4BAA4B;AAC5B,eAAO,MAAM,uBAAuB,EAAG,uCAAgD,CAAC;AAExF,yDAAyD;AACzD,MAAM,WAAW,gBAAgB;IAC/B,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,sDAAsD;AACtD,MAAM,WAAW,aAAa;IAC5B,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,kDAAkD;AAClD,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,yDAAyD;AACzD,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,gBAAgB,EAAE,cAAc,EAAE,CAAC;IACnC,6CAA6C;IAC7C,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,6BAA6B;IAC7B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,2CAA2C;IAC3C,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,+BAA+B;AAC/B,MAAM,WAAW,sBAAsB;IACrC,qDAAqD;IACrD,OAAO,EAAE,OAAO,uBAAuB,CAAC;IACxC,8CAA8C;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,2CAA2C;IAC3C,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;IACtC,mCAAmC;IACnC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,0CAA0C;IAC1C,OAAO,EAAE,eAAe,CAAC;IACzB,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,sDAAsD;AACtD,MAAM,WAAW,2BAA2B;IAC1C,8CAA8C;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;IAC3B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
1
+ {"version":3,"file":"commerce-bundle-types.d.ts","sourceRoot":"","sources":["../src/commerce-bundle-types.ts"],"names":[],"mappings":"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"}
@@ -9,7 +9,7 @@
9
9
  * derived when same currency, same semantic stage, and an explicit
10
10
  * authoritative-winner rule is documented and tested.
11
11
  */
12
- import type { CommerceEvidenceBundle, CommerceSummary, CreateCommerceBundleOptions, ProtocolEvidence, TimelineEntry } from './commerce-bundle-types.js';
12
+ import type { CommerceEvidenceBundle, CommerceSummary, CreateCommerceBundleOptions, LifecycleBundle, LifecycleInputRecord, ProtocolEvidence, TimelineEntry } from './commerce-bundle-types.js';
13
13
  /**
14
14
  * Create a new commerce evidence bundle.
15
15
  */
@@ -44,4 +44,27 @@ export declare function computeCommerceSummary(evidence: ProtocolEvidence[]): Co
44
44
  * Arrays are preserved in-order. No nested fields are omitted.
45
45
  */
46
46
  export declare function serializeCommerceBundle(bundle: CommerceEvidenceBundle): string;
47
+ /**
48
+ * Group records by their session identifier and then by the literal
49
+ * `commerce_event` value each record carries.
50
+ *
51
+ * Observational only. The returned `buckets` map keys are the exact
52
+ * event names attested by the upstream; no lifecycle semantics are
53
+ * inferred. Records with a missing, null, empty, or non-string
54
+ * `commerce_event` are routed to the reserved
55
+ * `UNCLASSIFIED_LIFECYCLE_BUCKET` key. Combinations of records in the
56
+ * same session never synthesize a new bucket name; there is no
57
+ * `settled`, `completed`, or `finalized` outcome derived from record
58
+ * pairs.
59
+ *
60
+ * Deterministic ordering:
61
+ * - Within each bucket: primary sort by `iat` ascending, tie-break by
62
+ * `receipt_ref` lex ascending.
63
+ * - Across the returned array: `session_ref` lex ascending.
64
+ *
65
+ * @experimental The API shape may change before the `-experimental`
66
+ * suffix is removed. Callers should pin the `COMMERCE_BUNDLE_VERSION`
67
+ * constant when persisting the result.
68
+ */
69
+ export declare function groupByLifecycle(records: LifecycleInputRecord[]): LifecycleBundle[];
47
70
  //# sourceMappingURL=commerce-bundle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"commerce-bundle.d.ts","sourceRoot":"","sources":["../src/commerce-bundle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,sBAAsB,EACtB,eAAe,EACf,2BAA2B,EAE3B,gBAAgB,EAChB,aAAa,EACd,MAAM,4BAA4B,CAAC;AAGpC;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,2BAA2B,GACnC,sBAAsB,CAiBxB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,sBAAsB,EAC9B,QAAQ,EAAE,gBAAgB,GACzB,sBAAsB,CAQxB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,sBAAsB,EAC9B,KAAK,EAAE,aAAa,GACnB,sBAAsB,CAKxB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,sBAAsB,EAC9B,UAAU,EAAE,MAAM,GACjB,sBAAsB,CAKxB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,eAAe,CA8CpF;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAE9E"}
1
+ {"version":3,"file":"commerce-bundle.d.ts","sourceRoot":"","sources":["../src/commerce-bundle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,sBAAsB,EACtB,eAAe,EACf,2BAA2B,EAC3B,eAAe,EACf,oBAAoB,EAEpB,gBAAgB,EAChB,aAAa,EACd,MAAM,4BAA4B,CAAC;AAGpC;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,2BAA2B,GACnC,sBAAsB,CAiBxB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,sBAAsB,EAC9B,QAAQ,EAAE,gBAAgB,GACzB,sBAAsB,CAQxB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,sBAAsB,EAC9B,KAAK,EAAE,aAAa,GACnB,sBAAsB,CAKxB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,sBAAsB,EAC9B,UAAU,EAAE,MAAM,GACjB,sBAAsB,CAKxB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,eAAe,CA8CpF;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAE9E;AA+CD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,eAAe,EAAE,CAgCnF"}
package/dist/index.cjs CHANGED
@@ -1550,6 +1550,7 @@ function formatReportText(report) {
1550
1550
 
1551
1551
  // src/commerce-bundle-types.ts
1552
1552
  var COMMERCE_BUNDLE_VERSION = "peac.commerce-bundle/0.1-experimental";
1553
+ var UNCLASSIFIED_LIFECYCLE_BUCKET = "unclassified";
1553
1554
 
1554
1555
  // src/commerce-bundle.ts
1555
1556
  function createCommerceEvidenceBundle(options) {
@@ -1644,6 +1645,60 @@ function sortTimeline(entries) {
1644
1645
  (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
1645
1646
  );
1646
1647
  }
1648
+ function groupByLifecycle(records) {
1649
+ const bySession = /* @__PURE__ */ new Map();
1650
+ for (const rec of records) {
1651
+ const list = bySession.get(rec.session_ref);
1652
+ if (list) list.push(rec);
1653
+ else bySession.set(rec.session_ref, [rec]);
1654
+ }
1655
+ const bundles = [];
1656
+ for (const [session_ref, rs] of bySession) {
1657
+ const buckets = {};
1658
+ for (const rec of rs) {
1659
+ const key = resolveBucketKey(rec.commerce_event);
1660
+ const list = buckets[key];
1661
+ if (list) list.push(rec);
1662
+ else buckets[key] = [rec];
1663
+ }
1664
+ for (const key of Object.keys(buckets)) {
1665
+ buckets[key] = [...buckets[key]].sort(compareLifecycleRecords);
1666
+ }
1667
+ bundles.push({
1668
+ session_ref,
1669
+ buckets,
1670
+ record_count: rs.length,
1671
+ version: COMMERCE_BUNDLE_VERSION
1672
+ });
1673
+ }
1674
+ bundles.sort(
1675
+ (a, b) => a.session_ref < b.session_ref ? -1 : a.session_ref > b.session_ref ? 1 : 0
1676
+ );
1677
+ return bundles;
1678
+ }
1679
+ function resolveBucketKey(event) {
1680
+ if (typeof event !== "string") return UNCLASSIFIED_LIFECYCLE_BUCKET;
1681
+ const trimmed = event.trim();
1682
+ if (trimmed === "") return UNCLASSIFIED_LIFECYCLE_BUCKET;
1683
+ return trimmed;
1684
+ }
1685
+ function compareLifecycleRecords(a, b) {
1686
+ const aTs = normalizeIat(a.iat);
1687
+ const bTs = normalizeIat(b.iat);
1688
+ if (aTs < bTs) return -1;
1689
+ if (aTs > bTs) return 1;
1690
+ if (a.receipt_ref < b.receipt_ref) return -1;
1691
+ if (a.receipt_ref > b.receipt_ref) return 1;
1692
+ return 0;
1693
+ }
1694
+ function normalizeIat(iat) {
1695
+ if (typeof iat === "number") return iat;
1696
+ const asNumber = Number(iat);
1697
+ if (!Number.isNaN(asNumber)) return asNumber;
1698
+ const parsed = Date.parse(iat);
1699
+ if (!Number.isNaN(parsed)) return parsed;
1700
+ return 0;
1701
+ }
1647
1702
 
1648
1703
  // src/index.ts
1649
1704
  var AUDIT_PACKAGE_VERSION = "0.9.27";
@@ -1656,6 +1711,7 @@ exports.BUNDLE_VERSION = BUNDLE_VERSION;
1656
1711
  exports.COMMERCE_BUNDLE_VERSION = COMMERCE_BUNDLE_VERSION;
1657
1712
  exports.DISPUTE_BUNDLE_VERSION = DISPUTE_BUNDLE_VERSION;
1658
1713
  exports.DISPUTE_BUNDLE_VERSION_v2 = BUNDLE_VERSION2;
1714
+ exports.UNCLASSIFIED_LIFECYCLE_BUCKET = UNCLASSIFIED_LIFECYCLE_BUCKET;
1659
1715
  exports.VERIFICATION_REPORT_VERSION = VERIFICATION_REPORT_VERSION;
1660
1716
  exports.addProtocolEvidence = addProtocolEvidence;
1661
1717
  exports.addReceiptRef = addReceiptRef;
@@ -1677,6 +1733,7 @@ exports.formatReportText = formatReportText;
1677
1733
  exports.generateAuditId = generateAuditId;
1678
1734
  exports.generateBundleSummary = generateBundleSummary;
1679
1735
  exports.getBundleContentHash = getBundleContentHash;
1736
+ exports.groupByLifecycle = groupByLifecycle;
1680
1737
  exports.isValidAuditEntry = isValidAuditEntry;
1681
1738
  exports.isValidTraceContext = isValidTraceContext;
1682
1739
  exports.isValidUlid = isValidUlid;