xytara 1.0.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,113 @@
1
+ "use strict";
2
+
3
+ const crypto = require("crypto");
4
+ const { findTask } = require("../fixtures/catalog");
5
+
6
+ function normalizeTaskRefs(payload) {
7
+ return Array.isArray(payload.tasks) && payload.tasks.length > 0
8
+ ? payload.tasks.map((task) => String(task.task_ref || "").trim()).filter(Boolean)
9
+ : [String(payload.task_ref || "").trim()].filter(Boolean);
10
+ }
11
+
12
+ function createQuote(state, payload) {
13
+ const taskRefs = normalizeTaskRefs(payload);
14
+ const adapters = Array.from(new Set(taskRefs.flatMap((ref) => {
15
+ const task = findTask(ref);
16
+ return Array.isArray(task && task.adapters) ? task.adapters : [];
17
+ })));
18
+ const amountMinor = taskRefs.reduce((sum, ref) => {
19
+ const task = findTask(ref);
20
+ return sum + Number((task && task.public_launch_price && task.public_launch_price.amount_minor) || 0);
21
+ }, 0) || 5;
22
+ const settlementMode = payload.settlement_mode || (payload.settlement && payload.settlement.mode) || "evm_payment";
23
+ const createdAtIso = new Date().toISOString();
24
+ const ttlMs = Number.isFinite(Number(payload.quote_ttl_ms)) ? Math.max(0, Number(payload.quote_ttl_ms)) : 5 * 60 * 1000;
25
+ const quote = {
26
+ quote_id: `quote_${crypto.randomBytes(6).toString("hex")}`,
27
+ account_id: payload.account_id || "account_placeholder",
28
+ status: "quoted",
29
+ amount_minor: amountMinor,
30
+ currency: "USD_CENTS",
31
+ capabilities: taskRefs,
32
+ adapters: adapters.length > 0 ? adapters : ["http"],
33
+ settlement_adapter: settlementMode,
34
+ settlement_binding_hash: crypto.createHash("sha256").update(JSON.stringify({
35
+ taskRefs,
36
+ settlementMode,
37
+ command: payload.command || ""
38
+ })).digest("hex"),
39
+ settlement_mode: settlementMode,
40
+ settlement_preference: payload.settlement_preference || null,
41
+ payment_scheme: payload.account_id ? "exact" : "native",
42
+ task_count: taskRefs.length || 1,
43
+ task_refs: taskRefs,
44
+ created_at_iso: createdAtIso,
45
+ expires_at_iso: new Date(Date.now() + ttlMs).toISOString(),
46
+ intent: payload.command || "command.execute",
47
+ transaction_id: null,
48
+ receipt_id: null,
49
+ payment_id: null,
50
+ payment_recorded_at_iso: null,
51
+ executed_at_iso: null
52
+ };
53
+ state.quotes.set(quote.quote_id, quote);
54
+ return quote;
55
+ }
56
+
57
+ function isQuoteExpired(quote, nowMs) {
58
+ if (!quote || !quote.expires_at_iso) return false;
59
+ const expiresAtMs = Date.parse(quote.expires_at_iso);
60
+ if (!Number.isFinite(expiresAtMs)) return false;
61
+ return expiresAtMs <= (typeof nowMs === "number" ? nowMs : Date.now());
62
+ }
63
+
64
+ function refreshQuoteStatus(state, quoteId, nowMs) {
65
+ if (!quoteId || !state.quotes.has(quoteId)) return null;
66
+ const current = state.quotes.get(quoteId);
67
+ if (!current) return null;
68
+ if (current.status !== "quoted") return current;
69
+ if (!isQuoteExpired(current, nowMs)) return current;
70
+ const next = {
71
+ ...current,
72
+ status: "expired"
73
+ };
74
+ state.quotes.set(quoteId, next);
75
+ return next;
76
+ }
77
+
78
+ function hydrateQuoteStates(state, nowMs) {
79
+ for (const quoteId of Array.from(state.quotes.keys())) {
80
+ refreshQuoteStatus(state, quoteId, nowMs);
81
+ }
82
+ }
83
+
84
+ function markQuoteExecuted(state, quote, result, paymentRecord, options) {
85
+ const opts = options || {};
86
+ if (!quote || !quote.quote_id || !state.quotes.has(quote.quote_id)) return quote;
87
+ const current = state.quotes.get(quote.quote_id);
88
+ const deferredCompletion = opts.deferredCompletion === true;
89
+ const executedAtIso =
90
+ (result && result.receipt && result.receipt.created_at_iso) ||
91
+ (result && result.transaction && result.transaction.completed_at_iso) ||
92
+ new Date().toISOString();
93
+ const next = {
94
+ ...current,
95
+ status: deferredCompletion ? "accepted" : "executed",
96
+ transaction_id: result && result.transaction ? result.transaction.transaction_id || null : null,
97
+ receipt_id: result && result.receipt ? result.receipt.receipt_id || null : null,
98
+ payment_id: paymentRecord ? paymentRecord.payment_id || null : null,
99
+ payment_recorded_at_iso: paymentRecord ? paymentRecord.recorded_at_iso || current.payment_recorded_at_iso : current.payment_recorded_at_iso,
100
+ executed_at_iso: deferredCompletion ? current.executed_at_iso : executedAtIso
101
+ };
102
+ state.quotes.set(next.quote_id, next);
103
+ return next;
104
+ }
105
+
106
+ module.exports = {
107
+ createQuote,
108
+ hydrateQuoteStates,
109
+ isQuoteExpired,
110
+ markQuoteExecuted,
111
+ normalizeTaskRefs,
112
+ refreshQuoteStatus
113
+ };