xoonya 1.5.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 +24 -0
- package/package.json +1 -1
- package/proof_sdk.js +264 -0
- package/server.js +53 -0
package/README.md
CHANGED
|
@@ -20,6 +20,20 @@ The package and service now also expose a default proof center surface so the in
|
|
|
20
20
|
- compact compatibility helpers preserved, but not treated as the public conceptual center
|
|
21
21
|
- proof remains settlement-agnostic and workflow-agnostic by default
|
|
22
22
|
|
|
23
|
+
The current `1.6.0` companion slice adds guided default proof loops on top of that proof center:
|
|
24
|
+
|
|
25
|
+
- default proof-loop catalog and detail routes
|
|
26
|
+
- a direct proof-loop run route for the canonical proof-native path
|
|
27
|
+
- package helpers that build, verify, and summarize the proof bundle boundary in one step
|
|
28
|
+
|
|
29
|
+
This keeps `xoonya` narrow while making the intended proof path easier to inspect alongside the newer guided transaction-loop work in `xytara`.
|
|
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
|
+
|
|
23
37
|
## Proof Model
|
|
24
38
|
|
|
25
39
|
The primary proof model is layered:
|
|
@@ -72,6 +86,7 @@ The package quickstart demonstrates:
|
|
|
72
86
|
- canonical receipt emission
|
|
73
87
|
- proof bundle construction
|
|
74
88
|
- proof bundle verification
|
|
89
|
+
- transaction proof-handoff follow-through
|
|
75
90
|
|
|
76
91
|
## Service Quickstart
|
|
77
92
|
|
|
@@ -98,6 +113,15 @@ Environment example:
|
|
|
98
113
|
Primary proof-model routes:
|
|
99
114
|
|
|
100
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`
|
|
101
125
|
- `POST /v1/events/canonicalize`
|
|
102
126
|
- `POST /v1/events/hash`
|
|
103
127
|
- `POST /v1/receipts/emit`
|
package/package.json
CHANGED
package/proof_sdk.js
CHANGED
|
@@ -793,9 +793,273 @@ function summarizeDefaultProofCenter() {
|
|
|
793
793
|
};
|
|
794
794
|
}
|
|
795
795
|
|
|
796
|
+
function buildDefaultProofLoops() {
|
|
797
|
+
const center = buildDefaultProofCenter();
|
|
798
|
+
return [
|
|
799
|
+
{
|
|
800
|
+
loop_ref: "default.proof.bundle.loop",
|
|
801
|
+
title: "Default Proof Bundle Loop",
|
|
802
|
+
description: "Canonicalize an event, emit a receipt, build a proof bundle, and verify it in one proof-native path.",
|
|
803
|
+
stage_count: 5,
|
|
804
|
+
stages: ["canonicalize", "hash", "emit_receipt", "build_bundle", "verify_bundle"],
|
|
805
|
+
event_version: center.proof_model.event_version,
|
|
806
|
+
receipt_version: center.proof_model.receipt_version,
|
|
807
|
+
proof_bundle_version: center.proof_model.proof_bundle_version
|
|
808
|
+
},
|
|
809
|
+
{
|
|
810
|
+
loop_ref: "default.proof.receipt.loop",
|
|
811
|
+
title: "Default Proof Receipt Loop",
|
|
812
|
+
description: "Canonicalize an event, emit a receipt, and verify the resulting proof-native receipt path.",
|
|
813
|
+
stage_count: 4,
|
|
814
|
+
stages: ["canonicalize", "hash", "emit_receipt", "verify_receipt"],
|
|
815
|
+
event_version: center.proof_model.event_version,
|
|
816
|
+
receipt_version: center.proof_model.receipt_version,
|
|
817
|
+
proof_bundle_version: center.proof_model.proof_bundle_version
|
|
818
|
+
}
|
|
819
|
+
];
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
function buildDefaultProofLoopCatalog() {
|
|
823
|
+
const center = buildDefaultProofCenter();
|
|
824
|
+
const loops = buildDefaultProofLoops();
|
|
825
|
+
return {
|
|
826
|
+
ok: true,
|
|
827
|
+
brand: center.brand,
|
|
828
|
+
product: "default proof loops",
|
|
829
|
+
event_version: center.proof_model.event_version,
|
|
830
|
+
receipt_version: center.proof_model.receipt_version,
|
|
831
|
+
proof_bundle_version: center.proof_model.proof_bundle_version,
|
|
832
|
+
loop_count: loops.length,
|
|
833
|
+
loops
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
function summarizeDefaultProofLoops() {
|
|
838
|
+
const catalog = buildDefaultProofLoopCatalog();
|
|
839
|
+
return {
|
|
840
|
+
ok: true,
|
|
841
|
+
brand: catalog.brand,
|
|
842
|
+
product: catalog.product,
|
|
843
|
+
event_version: catalog.event_version,
|
|
844
|
+
receipt_version: catalog.receipt_version,
|
|
845
|
+
proof_bundle_version: catalog.proof_bundle_version,
|
|
846
|
+
loop_count: catalog.loop_count,
|
|
847
|
+
loop_refs: catalog.loops.map((entry) => entry && entry.loop_ref).filter(Boolean),
|
|
848
|
+
loops: catalog.loops
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
function getDefaultProofLoop(ref) {
|
|
853
|
+
const normalized = String(ref || "").trim();
|
|
854
|
+
if (!normalized) return null;
|
|
855
|
+
return buildDefaultProofLoops().find((entry) => entry && entry.loop_ref === normalized) || null;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
function summarizeGuidedProofLoopBundle(bundle) {
|
|
859
|
+
const item = bundle || {};
|
|
860
|
+
const loop = item.loop || {};
|
|
861
|
+
const canonicalEvent = item.canonical_event || {};
|
|
862
|
+
const receipt = item.receipt || {};
|
|
863
|
+
const proofBundle = item.proof_bundle || {};
|
|
864
|
+
const verification = item.bundle_verification || {};
|
|
865
|
+
const receiptVerification = item.receipt_verification || {};
|
|
866
|
+
return {
|
|
867
|
+
ok: item.ok === true,
|
|
868
|
+
loop_ref: loop.loop_ref || null,
|
|
869
|
+
stage_count: Number(loop.stage_count || 0),
|
|
870
|
+
event_version: canonicalEvent.version || null,
|
|
871
|
+
receipt_version: receipt.version || null,
|
|
872
|
+
proof_bundle_version: proofBundle.version || null,
|
|
873
|
+
receipt_id: receipt.receipt_id || null,
|
|
874
|
+
event_commitment: receipt.event_commitment || null,
|
|
875
|
+
bundle_valid: verification.valid === true,
|
|
876
|
+
receipt_valid: receiptVerification.valid === true
|
|
877
|
+
};
|
|
878
|
+
}
|
|
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
|
+
|
|
1009
|
+
function runDefaultProofLoop(loopRef, input) {
|
|
1010
|
+
const loop = getDefaultProofLoop(loopRef);
|
|
1011
|
+
if (!loop) {
|
|
1012
|
+
throw new Error("default_proof_loop_not_found");
|
|
1013
|
+
}
|
|
1014
|
+
const body = input && typeof input === "object" && !Array.isArray(input) ? input : {};
|
|
1015
|
+
const event = canonicalizeEvent(body.event || body.ceb);
|
|
1016
|
+
const receiptOptions = body.options && typeof body.options === "object" && !Array.isArray(body.options)
|
|
1017
|
+
? body.options
|
|
1018
|
+
: {};
|
|
1019
|
+
const receipt = emitReceipt(event, receiptOptions);
|
|
1020
|
+
const bundle = buildProofBundle({
|
|
1021
|
+
ceb: event,
|
|
1022
|
+
receipt,
|
|
1023
|
+
anchors: Array.isArray(body.anchors) ? body.anchors : undefined,
|
|
1024
|
+
attestations: Array.isArray(body.attestations) ? body.attestations : undefined,
|
|
1025
|
+
evidence_refs: Array.isArray(body.evidence_refs) ? body.evidence_refs : undefined,
|
|
1026
|
+
batch_refs: Array.isArray(body.batch_refs) ? body.batch_refs : undefined,
|
|
1027
|
+
metadata: body.metadata && typeof body.metadata === "object" && !Array.isArray(body.metadata) ? body.metadata : undefined
|
|
1028
|
+
});
|
|
1029
|
+
const bundleVerification = verifyProofBundle(bundle);
|
|
1030
|
+
const receiptVerification = receipt.compatibility && receipt.compatibility.legacy_receipt
|
|
1031
|
+
? verifyReceipt(
|
|
1032
|
+
receipt.compatibility.legacy_receipt.opreturn_hex,
|
|
1033
|
+
Buffer.from(canonicalize(event), "utf8")
|
|
1034
|
+
)
|
|
1035
|
+
: { valid: true, reason: null, version: CANONICAL_RECEIPT_VERSION };
|
|
1036
|
+
return {
|
|
1037
|
+
ok: true,
|
|
1038
|
+
loop,
|
|
1039
|
+
canonical_event: event,
|
|
1040
|
+
event_commitment: hashEvent(event),
|
|
1041
|
+
receipt,
|
|
1042
|
+
receipt_verification: receiptVerification,
|
|
1043
|
+
proof_bundle: bundle,
|
|
1044
|
+
bundle_verification: bundleVerification
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
|
|
796
1048
|
module.exports = {
|
|
797
1049
|
buildDefaultProofCenter,
|
|
1050
|
+
buildDefaultProofLoopCatalog,
|
|
1051
|
+
buildDefaultProofLoops,
|
|
1052
|
+
buildTransactionProofHandoffCenter,
|
|
1053
|
+
buildTransactionProofHandoffEvent,
|
|
1054
|
+
getDefaultProofLoop,
|
|
1055
|
+
canonicalizeTransactionProofHandoff,
|
|
1056
|
+
runDefaultProofLoop,
|
|
1057
|
+
runTransactionProofHandoff,
|
|
798
1058
|
summarizeDefaultProofCenter,
|
|
1059
|
+
summarizeDefaultProofLoops,
|
|
1060
|
+
summarizeGuidedProofLoopBundle,
|
|
1061
|
+
summarizeTransactionProofHandoff,
|
|
1062
|
+
summarizeTransactionProofHandoffCenter,
|
|
799
1063
|
canonicalizeEvent,
|
|
800
1064
|
hashEvent,
|
|
801
1065
|
emitReceipt,
|
package/server.js
CHANGED
|
@@ -87,6 +87,59 @@ async function routeRequest(req, res) {
|
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
if (req.method === 'GET' && url.pathname === '/v1/proof-center/default-loops') {
|
|
91
|
+
sendJson(res, 200, proofSdk.buildDefaultProofLoopCatalog());
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (req.method === 'GET' && url.pathname === '/v1/proof-center/default-loops/summary') {
|
|
96
|
+
sendJson(res, 200, proofSdk.summarizeDefaultProofLoops());
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
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
|
+
|
|
110
|
+
if (req.method === 'GET' && url.pathname === '/v1/proof-center/default-loop') {
|
|
111
|
+
const loop = proofSdk.getDefaultProofLoop(url.searchParams.get('ref'));
|
|
112
|
+
if (!loop) {
|
|
113
|
+
sendJson(res, 404, { ok: false, error: 'default_proof_loop_not_found' });
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
sendJson(res, 200, { ok: true, loop });
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (req.method === 'POST' && url.pathname === '/v1/proof-center/default-loops/run') {
|
|
121
|
+
try {
|
|
122
|
+
const body = await readJsonBody(req);
|
|
123
|
+
const loopRef = String(body.loop_ref || '').trim();
|
|
124
|
+
const result = proofSdk.runDefaultProofLoop(loopRef, body);
|
|
125
|
+
sendJson(res, 200, result);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
sendJson(res, error.message === 'default_proof_loop_not_found' ? 404 : 400, { ok: false, reason: error.message });
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
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
|
+
|
|
90
143
|
if (req.method === 'POST' && url.pathname === '/v1/receipts/verify') {
|
|
91
144
|
try {
|
|
92
145
|
const body = await readJsonBody(req);
|