xoonya 1.6.0 → 1.7.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.
package/README.md CHANGED
@@ -28,6 +28,12 @@ The current `1.6.0` companion slice adds guided default proof loops on top of th
28
28
 
29
29
  This keeps `xoonya` narrow while making the intended proof path easier to inspect alongside the newer guided transaction-loop work in `xytara`.
30
30
 
31
+ The current `1.7.0` companion slice adds a lightweight transaction proof-handoff surface:
32
+
33
+ - a transaction proof-handoff center that states the expected handoff contract
34
+ - a direct handoff run path that turns transaction-side proof handoff data into a proof-native bundle
35
+ - summary helpers that make the recommended proof follow-through explicit without widening proof scope
36
+
31
37
  ## Proof Model
32
38
 
33
39
  The primary proof model is layered:
@@ -80,6 +86,7 @@ The package quickstart demonstrates:
80
86
  - canonical receipt emission
81
87
  - proof bundle construction
82
88
  - proof bundle verification
89
+ - transaction proof-handoff follow-through
83
90
 
84
91
  ## Service Quickstart
85
92
 
@@ -106,6 +113,15 @@ Environment example:
106
113
  Primary proof-model routes:
107
114
 
108
115
  - `GET /health`
116
+ - `GET /v1/proof-center`
117
+ - `GET /v1/proof-center/summary`
118
+ - `GET /v1/proof-center/default-loops`
119
+ - `GET /v1/proof-center/default-loops/summary`
120
+ - `GET /v1/proof-center/default-loop`
121
+ - `POST /v1/proof-center/default-loops/run`
122
+ - `GET /v1/proof-center/transaction-handoff`
123
+ - `GET /v1/proof-center/transaction-handoff/summary`
124
+ - `POST /v1/proof-center/transaction-handoff/run`
109
125
  - `POST /v1/events/canonicalize`
110
126
  - `POST /v1/events/hash`
111
127
  - `POST /v1/receipts/emit`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xoonya",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Deterministic proof SDK for canonical events, receipts, proof bundles, and verification.",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
package/proof_sdk.js CHANGED
@@ -877,6 +877,135 @@ function summarizeGuidedProofLoopBundle(bundle) {
877
877
  };
878
878
  }
879
879
 
880
+ function buildTransactionProofHandoffCenter() {
881
+ return {
882
+ ok: true,
883
+ brand: "xoonya",
884
+ product: "transaction proof handoff center",
885
+ supported_source_refs: [
886
+ "transaction.registry.anchor",
887
+ "transaction.runtime.consequence",
888
+ "transaction.trust.receipt",
889
+ "transaction.admission.settlement",
890
+ "transaction.job.commitment"
891
+ ],
892
+ recommended_loop: "default.proof.bundle.loop",
893
+ required_fields: ["transaction_id", "receipt_id", "proof_ref"],
894
+ optional_fields: ["source_ref", "task_refs", "delivery_count", "payment_ledger_count"]
895
+ };
896
+ }
897
+
898
+ function summarizeTransactionProofHandoffCenter() {
899
+ const center = buildTransactionProofHandoffCenter();
900
+ return {
901
+ ok: true,
902
+ brand: center.brand,
903
+ product: center.product,
904
+ source_ref_count: Array.isArray(center.supported_source_refs) ? center.supported_source_refs.length : 0,
905
+ supported_source_refs: center.supported_source_refs,
906
+ required_field_count: Array.isArray(center.required_fields) ? center.required_fields.length : 0,
907
+ required_fields: center.required_fields,
908
+ recommended_loop: center.recommended_loop
909
+ };
910
+ }
911
+
912
+ function canonicalizeTransactionProofHandoff(input) {
913
+ const body = input && typeof input === "object" && !Array.isArray(input) ? input : {};
914
+ const handoff = body.handoff_bundle && typeof body.handoff_bundle === "object" && !Array.isArray(body.handoff_bundle)
915
+ ? body.handoff_bundle
916
+ : body;
917
+ const transactionId = normalizeString(handoff.transaction_id);
918
+ const receiptId = normalizeString(handoff.receipt_id);
919
+ const proofRef = normalizeString(handoff.proof_ref);
920
+ if (!transactionId) throw new Error("handoff_bundle.transaction_id required");
921
+ if (!receiptId) throw new Error("handoff_bundle.receipt_id required");
922
+ if (!proofRef) throw new Error("handoff_bundle.proof_ref required");
923
+ const sourceRef = normalizeString(handoff.source_ref || body.source_ref || "transaction.proof_handoff");
924
+ const taskRefs = normalizeStringArray(handoff.task_refs, "handoff_bundle.task_refs") || [];
925
+ const deliveryCount = Number.isFinite(Number(handoff.delivery_count)) ? Number(handoff.delivery_count) : 0;
926
+ const paymentLedgerCount = Number.isFinite(Number(handoff.payment_ledger_count)) ? Number(handoff.payment_ledger_count) : 0;
927
+ return {
928
+ source_ref: sourceRef,
929
+ transaction_id: transactionId,
930
+ receipt_id: receiptId,
931
+ proof_ref: proofRef,
932
+ task_refs: taskRefs,
933
+ delivery_count: deliveryCount,
934
+ payment_ledger_count: paymentLedgerCount
935
+ };
936
+ }
937
+
938
+ function buildTransactionProofHandoffEvent(input) {
939
+ const handoff = canonicalizeTransactionProofHandoff(input);
940
+ const eventHash = canonicalJsonSha256Hex({
941
+ source_ref: handoff.source_ref,
942
+ transaction_id: handoff.transaction_id,
943
+ receipt_id: handoff.receipt_id,
944
+ proof_ref: handoff.proof_ref,
945
+ task_refs: handoff.task_refs,
946
+ delivery_count: handoff.delivery_count,
947
+ payment_ledger_count: handoff.payment_ledger_count
948
+ });
949
+ return canonicalizeEvent({
950
+ version: CANONICAL_EVENT_BUNDLE_VERSION,
951
+ domain_id: "xytara.transaction_handoff",
952
+ sequence: handoff.transaction_id,
953
+ actor_id: "xytara.transaction_center",
954
+ adapter_source: "xytara.proof_handoff",
955
+ event_type: `${handoff.source_ref}.proof_handoff`,
956
+ event_hash: eventHash,
957
+ semantic_slots: handoff
958
+ });
959
+ }
960
+
961
+ function runTransactionProofHandoff(input) {
962
+ const handoff = canonicalizeTransactionProofHandoff(input);
963
+ const event = buildTransactionProofHandoffEvent(input);
964
+ const options = input && input.options && typeof input.options === "object" && !Array.isArray(input.options)
965
+ ? input.options
966
+ : {};
967
+ const receipt = emitReceipt(event, options);
968
+ const proofBundle = buildProofBundle({
969
+ ceb: event,
970
+ receipt,
971
+ evidence_refs: Array.isArray(input && input.evidence_refs) ? input.evidence_refs : [handoff.proof_ref],
972
+ metadata: {
973
+ handoff_kind: "transaction_proof_handoff",
974
+ source_ref: handoff.source_ref
975
+ }
976
+ });
977
+ return {
978
+ ok: true,
979
+ handoff,
980
+ canonical_event: event,
981
+ event_commitment: hashEvent(event),
982
+ receipt,
983
+ proof_bundle: proofBundle,
984
+ bundle_verification: verifyProofBundle(proofBundle),
985
+ recommended_loop: "default.proof.bundle.loop"
986
+ };
987
+ }
988
+
989
+ function summarizeTransactionProofHandoff(bundle) {
990
+ const item = bundle && typeof bundle === "object" ? bundle : {};
991
+ const handoff = item.handoff && typeof item.handoff === "object" ? item.handoff : {};
992
+ const receipt = item.receipt && typeof item.receipt === "object" ? item.receipt : {};
993
+ const proofBundle = item.proof_bundle && typeof item.proof_bundle === "object" ? item.proof_bundle : {};
994
+ const verification = item.bundle_verification && typeof item.bundle_verification === "object" ? item.bundle_verification : {};
995
+ return {
996
+ ok: item.ok === true,
997
+ source_ref: handoff.source_ref || null,
998
+ transaction_id: handoff.transaction_id || null,
999
+ receipt_id: handoff.receipt_id || null,
1000
+ proof_ref: handoff.proof_ref || null,
1001
+ task_ref_count: Array.isArray(handoff.task_refs) ? handoff.task_refs.length : 0,
1002
+ proof_bundle_version: proofBundle.version || null,
1003
+ emitted_receipt_id: receipt.receipt_id || null,
1004
+ bundle_valid: verification.valid === true,
1005
+ recommended_loop: item.recommended_loop || null
1006
+ };
1007
+ }
1008
+
880
1009
  function runDefaultProofLoop(loopRef, input) {
881
1010
  const loop = getDefaultProofLoop(loopRef);
882
1011
  if (!loop) {
@@ -920,11 +1049,17 @@ module.exports = {
920
1049
  buildDefaultProofCenter,
921
1050
  buildDefaultProofLoopCatalog,
922
1051
  buildDefaultProofLoops,
1052
+ buildTransactionProofHandoffCenter,
1053
+ buildTransactionProofHandoffEvent,
923
1054
  getDefaultProofLoop,
1055
+ canonicalizeTransactionProofHandoff,
924
1056
  runDefaultProofLoop,
1057
+ runTransactionProofHandoff,
925
1058
  summarizeDefaultProofCenter,
926
1059
  summarizeDefaultProofLoops,
927
1060
  summarizeGuidedProofLoopBundle,
1061
+ summarizeTransactionProofHandoff,
1062
+ summarizeTransactionProofHandoffCenter,
928
1063
  canonicalizeEvent,
929
1064
  hashEvent,
930
1065
  emitReceipt,
package/server.js CHANGED
@@ -97,6 +97,16 @@ async function routeRequest(req, res) {
97
97
  return;
98
98
  }
99
99
 
100
+ if (req.method === 'GET' && url.pathname === '/v1/proof-center/transaction-handoff') {
101
+ sendJson(res, 200, proofSdk.buildTransactionProofHandoffCenter());
102
+ return;
103
+ }
104
+
105
+ if (req.method === 'GET' && url.pathname === '/v1/proof-center/transaction-handoff/summary') {
106
+ sendJson(res, 200, proofSdk.summarizeTransactionProofHandoffCenter());
107
+ return;
108
+ }
109
+
100
110
  if (req.method === 'GET' && url.pathname === '/v1/proof-center/default-loop') {
101
111
  const loop = proofSdk.getDefaultProofLoop(url.searchParams.get('ref'));
102
112
  if (!loop) {
@@ -119,6 +129,17 @@ async function routeRequest(req, res) {
119
129
  return;
120
130
  }
121
131
 
132
+ if (req.method === 'POST' && url.pathname === '/v1/proof-center/transaction-handoff/run') {
133
+ try {
134
+ const body = await readJsonBody(req);
135
+ const result = proofSdk.runTransactionProofHandoff(body);
136
+ sendJson(res, 200, result);
137
+ } catch (error) {
138
+ sendJson(res, 400, { ok: false, reason: error.message });
139
+ }
140
+ return;
141
+ }
142
+
122
143
  if (req.method === 'POST' && url.pathname === '/v1/receipts/verify') {
123
144
  try {
124
145
  const body = await readJsonBody(req);