@dvmkit/sdk 0.4.0-rc.1 → 0.6.0-rc.1

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.
Files changed (43) hide show
  1. package/README.md +100 -0
  2. package/dist/{chunk-TXX4GOUB.js → chunk-7ZUKL4IV.js} +1 -1
  3. package/dist/chunk-AFV77S4C.js +258 -0
  4. package/dist/{chunk-2VGWYG4P.js → chunk-B2IROPQF.js} +446 -81
  5. package/dist/chunk-BQJIFRAZ.js +36 -0
  6. package/dist/{chunk-PB4FYZET.js → chunk-EQLA4FFY.js} +54 -4
  7. package/dist/{chunk-74PUEZJ4.js → chunk-GFY5FRX3.js} +1 -1
  8. package/dist/{chunk-O3QDFPKM.js → chunk-HCLVYZUZ.js} +2 -2
  9. package/dist/{chunk-K2YX2VRA.js → chunk-HHBDBMEO.js} +170 -43
  10. package/dist/{chunk-O5AT6S5T.js → chunk-IV6Q7NRW.js} +25 -195
  11. package/dist/{chunk-W2EQGDF5.js → chunk-LE74UEV7.js} +49 -8
  12. package/dist/{chunk-CE7XEHYC.js → chunk-N5RZ5HVB.js} +1 -1
  13. package/dist/chunk-OFVV37XC.js +57 -0
  14. package/dist/{chunk-5LR6P7WN.js → chunk-OQA7IHI4.js} +133 -213
  15. package/dist/{chunk-3MHE725Z.js → chunk-PAIM66YA.js} +90 -1
  16. package/dist/{chunk-6DOGTAHA.js → chunk-QR2EF2NI.js} +9 -43
  17. package/dist/{chunk-KXZUCCEY.js → chunk-RCM3P2HE.js} +5 -56
  18. package/dist/{chunk-R4DQZFAL.js → chunk-UOCZXO2Z.js} +3 -3
  19. package/dist/content-retention-BTGSQRfP.d.ts +78 -0
  20. package/dist/{credit-menu-B8_p_vUz.d.ts → credit-menu-BAsrRu3z.d.ts} +98 -5
  21. package/dist/{fx-DuaYHvVn.d.ts → fx-BgDmyTdd.d.ts} +1 -1
  22. package/dist/index.d.ts +5 -5
  23. package/dist/index.js +4 -3
  24. package/dist/internal/caller.d.ts +90 -22
  25. package/dist/internal/caller.js +40 -40
  26. package/dist/internal/index.js +1 -1
  27. package/dist/internal/server.d.ts +8 -99
  28. package/dist/internal/server.js +15 -11
  29. package/dist/{job-store-D6Rjj5Oi.d.ts → job-store-BVeF5_Jq.d.ts} +1 -1
  30. package/dist/{lightning-backend-BaeCPmx7.d.ts → lightning-backend-40fIzz1W.d.ts} +1 -1
  31. package/dist/{postgres-consumed-credential-store-CUQJKRSL.js → postgres-consumed-credential-store-BUVCAPLS.js} +13 -0
  32. package/dist/{postgres-job-store-VLXLWXUQ.js → postgres-job-store-VHLQBJZC.js} +3 -1
  33. package/dist/server/index.d.ts +28 -10
  34. package/dist/server/index.js +24 -10
  35. package/dist/{step-cache-Bi43A0JN.d.ts → step-cache-CPdH1hei.d.ts} +3 -3
  36. package/dist/{tempo-lifecycle-OTHV757Y.js → tempo-lifecycle-ZBBLFBMH.js} +5 -4
  37. package/dist/{tempo-wallet-32JWQZKQ.js → tempo-wallet-B5XXV3YH.js} +1 -1
  38. package/dist/testing/index.d.ts +9 -2
  39. package/dist/testing/index.js +6 -3
  40. package/dist/{usd-AZPVq4eU.d.ts → usd-AWlrwlM5.d.ts} +1 -1
  41. package/dist/{x402-CEDHGZDI.js → x402-R6HPBY5D.js} +5 -4
  42. package/package.json +3 -2
  43. package/recipes/postgres/financial-export-v1.sql +137 -0
@@ -10,12 +10,12 @@ import {
10
10
  saveX402Wallet,
11
11
  tryX402Payment,
12
12
  x402WrongAssetHint
13
- } from "./chunk-W2EQGDF5.js";
14
- import "./chunk-2VGWYG4P.js";
13
+ } from "./chunk-LE74UEV7.js";
14
+ import "./chunk-B2IROPQF.js";
15
15
  import "./chunk-MZRJR2CW.js";
16
16
  import {
17
17
  verifyX402Payment
18
- } from "./chunk-TXX4GOUB.js";
18
+ } from "./chunk-7ZUKL4IV.js";
19
19
  import "./chunk-PLG4XER6.js";
20
20
  import {
21
21
  X402_DEFAULT_FACILITATOR,
@@ -36,8 +36,9 @@ import {
36
36
  usdcContractByCaip2,
37
37
  x402NetworkToCaip2
38
38
  } from "./chunk-IWQHUSMO.js";
39
- import "./chunk-3MHE725Z.js";
39
+ import "./chunk-PAIM66YA.js";
40
40
  import "./chunk-CZULM42S.js";
41
+ import "./chunk-OFVV37XC.js";
41
42
  import "./chunk-66HGCPBU.js";
42
43
  import "./chunk-FUJ36YDV.js";
43
44
  import "./chunk-AT6V3SY7.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dvmkit/sdk",
3
- "version": "0.4.0-rc.1",
3
+ "version": "0.6.0-rc.1",
4
4
  "description": "SDK for building accountless, pay-per-use Digital Vending Machines",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -36,7 +36,8 @@
36
36
  },
37
37
  "files": [
38
38
  "dist",
39
- "NOTICE"
39
+ "NOTICE",
40
+ "recipes"
40
41
  ],
41
42
  "engines": {
42
43
  "node": ">=22"
@@ -0,0 +1,137 @@
1
+ -- Run with psql -X -q -t -A -v ON_ERROR_STOP=1 -f financial-export-v1.sql > financial-evidence.json
2
+ -- The transaction gives every table one consistent snapshot. Optional rail tables
3
+ -- absent from this service are empty arrays. Keep this file with the export.
4
+ -- Receipts are signed over every field. Reject unsupported shapes instead of
5
+ -- removing signed extensions and silently producing unverifiable evidence.
6
+ CREATE OR REPLACE FUNCTION pg_temp.receipt_v1(value jsonb) RETURNS jsonb LANGUAGE plpgsql IMMUTABLE AS $$
7
+ DECLARE allowed text[]; nested_allowed text[]; item record; nested_item record;
8
+ BEGIN
9
+ IF value IS NULL OR value = 'null'::jsonb THEN RETURN value; END IF;
10
+ IF jsonb_typeof(value) <> 'object' OR value->'v' IS DISTINCT FROM '1'::jsonb THEN
11
+ RAISE EXCEPTION 'financial export v1: unsupported receipt version or shape';
12
+ END IF;
13
+ CASE value->>'kind'
14
+ WHEN 'credit_funding' THEN allowed := ARRAY['v','kind','credit_id','fund_id','funded_micro','balance_after_micro','ledger_seq','issued_at','caller_pubkey','dvm_id','dvm','receipt_pubkey','signature'];
15
+ WHEN 'credit_drain' THEN allowed := ARRAY['v','kind','credit_id','drain_id','event','method','amount_micro','balance_after_micro','ledger_seq','issued_at','caller_pubkey','dvm_id','dvm','receipt_pubkey','signature'];
16
+ ELSE
17
+ IF value ? 'kind' THEN RAISE EXCEPTION 'financial export v1: unsupported receipt kind'; END IF;
18
+ allowed := ARRAY['v','job_id','dvm_id','dvm','capability','outcome','reason','ended_by','seq','issued_at','requester_pubkey','result_hash','receipt_pubkey','signature','paid','timing','credit'];
19
+ END CASE;
20
+ FOR item IN SELECT key,val FROM jsonb_each(value) AS e(key,val) LOOP
21
+ IF NOT item.key = ANY(allowed) THEN
22
+ RAISE EXCEPTION 'financial export v1: unsupported signed receipt extension';
23
+ END IF;
24
+ IF item.key = ANY(ARRAY['paid','timing','credit']) THEN
25
+ IF jsonb_typeof(item.val) <> 'object' THEN
26
+ RAISE EXCEPTION 'financial export v1: unsupported receipt block';
27
+ END IF;
28
+ nested_allowed := CASE item.key
29
+ WHEN 'paid' THEN ARRAY['msats','rail','native_amount','native_asset','tx_hash','mint']
30
+ WHEN 'timing' THEN ARRAY['accepted_at_ms','terminal_at_ms','caller_wait_ms']
31
+ WHEN 'credit' THEN ARRAY['credit_id','draw_id','amount','balance_after','ledger_seq'] END;
32
+ FOR nested_item IN SELECT key,val FROM jsonb_each(item.val) AS n(key,val) LOOP
33
+ IF NOT nested_item.key = ANY(nested_allowed) OR jsonb_typeof(nested_item.val) = ANY(ARRAY['object','array']) THEN
34
+ RAISE EXCEPTION 'financial export v1: unsupported signed receipt block extension';
35
+ END IF;
36
+ END LOOP;
37
+ ELSIF jsonb_typeof(item.val) = ANY(ARRAY['object','array']) THEN
38
+ RAISE EXCEPTION 'financial export v1: unsupported receipt field shape';
39
+ END IF;
40
+ END LOOP;
41
+ RETURN value;
42
+ END
43
+ $$;
44
+ -- Unsigned evidence uses explicit scalar projections. Objects/arrays in scalar
45
+ -- positions are excluded, including inside the supported nested financial blocks.
46
+ CREATE OR REPLACE FUNCTION pg_temp.scalars_v1(value jsonb, strings text[], numbers text[], booleans text[] DEFAULT ARRAY[]::text[]) RETURNS jsonb LANGUAGE sql IMMUTABLE AS $$
47
+ SELECT CASE WHEN jsonb_typeof(value) <> 'object' THEN NULL ELSE
48
+ (SELECT COALESCE(jsonb_object_agg(key,val), '{}'::jsonb) FROM jsonb_each(value) AS e(key,val)
49
+ WHERE (key=ANY(strings) AND jsonb_typeof(val) IN ('string','null'))
50
+ OR (key=ANY(numbers) AND (jsonb_typeof(val) IN ('number','null') OR (jsonb_typeof(val)='string' AND val #>> '{}' ~ '^-?[0-9]+$')))
51
+ OR (key=ANY(booleans) AND jsonb_typeof(val) IN ('boolean','null'))) END
52
+ $$;
53
+ CREATE OR REPLACE FUNCTION pg_temp.settlement_v1(value jsonb) RETURNS jsonb LANGUAGE sql IMMUTABLE AS $$
54
+ SELECT pg_temp.scalars_v1(value,
55
+ ARRAY['tx_hash','transaction','channel_id','network','repair_kind','payer'],
56
+ ARRAY['settledAmount','settled_amount','amount','refunded_native','debited_native','surplus_native'], ARRAY['success','repaired'])
57
+ $$;
58
+ CREATE OR REPLACE FUNCTION pg_temp.fulfilment_v1(value jsonb) RETURNS jsonb LANGUAGE sql IMMUTABLE AS $$
59
+ SELECT pg_temp.scalars_v1(value, ARRAY['source','mintUrl','quoteId'], ARRAY['faceSats','reserveSats','invoiceMsats','routingFeeMsats'])
60
+ $$;
61
+ CREATE OR REPLACE FUNCTION pg_temp.lot_debits_v1(value jsonb) RETURNS jsonb LANGUAGE sql IMMUTABLE AS $$
62
+ SELECT CASE WHEN jsonb_typeof(value) <> 'array' THEN NULL ELSE
63
+ (SELECT COALESCE(jsonb_agg(pg_temp.scalars_v1(item, ARRAY['lotId'], ARRAY['micro','sats'])), '[]'::jsonb)
64
+ FROM jsonb_array_elements(value) item WHERE jsonb_typeof(item)='object') END
65
+ $$;
66
+ CREATE OR REPLACE FUNCTION pg_temp.effect_v1(value jsonb) RETURNS jsonb LANGUAGE sql IMMUTABLE AS $$
67
+ SELECT pg_temp.scalars_v1(value, ARRAY['callerId','dvmId','jobId'],
68
+ ARRAY['requiredMsats','paidMsats','fundedMicro','nativeAmount','topUpCapMicro'], ARRAY['drawBasis','askSatisfied','midJob'])
69
+ || jsonb_strip_nulls(jsonb_build_object(
70
+ 'priceFiat', pg_temp.scalars_v1(value->'priceFiat', ARRAY['currency'], ARRAY['amountMicro']),
71
+ 'fundOnly', pg_temp.scalars_v1(value->'fundOnly', ARRAY['creditId','fundId'], ARRAY[]::text[]),
72
+ 'topUp', pg_temp.scalars_v1(value->'topUp', ARRAY['creditId','drawId'], ARRAY[]::text[]),
73
+ 'creditEnvelope', pg_temp.scalars_v1(value->'creditEnvelope', ARRAY['creditId','drawId'], ARRAY[]::text[])))
74
+ $$;
75
+ CREATE OR REPLACE FUNCTION pg_temp.channel_config_v1(value jsonb) RETURNS jsonb LANGUAGE sql IMMUTABLE AS $$
76
+ SELECT pg_temp.scalars_v1(value, ARRAY['payer','payerAuthorizer','receiver','receiverAuthorizer'], ARRAY['withdrawDelay'])
77
+ || CASE WHEN value->>'token' ~ '^0x[0-9a-fA-F]{40}$' THEN jsonb_build_object('token',value->'token') ELSE '{}'::jsonb END
78
+ $$;
79
+ CREATE OR REPLACE FUNCTION pg_temp.tempo_state_v1(value jsonb) RETURNS jsonb LANGUAGE plpgsql IMMUTABLE AS $$
80
+ DECLARE state jsonb; amounts jsonb;
81
+ BEGIN
82
+ IF value IS NULL OR value='null'::jsonb THEN RETURN NULL; END IF;
83
+ IF jsonb_typeof(value)<>'string' THEN RETURN NULL; END IF;
84
+ BEGIN state := (value #>> '{}')::jsonb;
85
+ EXCEPTION WHEN OTHERS THEN RAISE EXCEPTION 'financial export v1: unsupported Tempo state'; END;
86
+ IF jsonb_typeof(state)<>'object' THEN RETURN NULL; END IF;
87
+ -- Normalize the store's tagged bigints without retaining vouchers or signatures.
88
+ SELECT COALESCE(jsonb_object_agg(key, regexp_replace(val #>> '{}', '#__bigint$', '')), '{}'::jsonb) INTO amounts
89
+ FROM jsonb_each(state) AS e(key,val)
90
+ WHERE key=ANY(ARRAY['deposit','spent','settledOnChain','highestVoucherAmount','closeRequestedAt'])
91
+ AND jsonb_typeof(val) IN ('number','string') AND val #>> '{}' ~ '^[0-9]+(#__bigint)?$';
92
+ RETURN pg_temp.scalars_v1(state, ARRAY['channelId','escrowContract','payee','payer'], ARRAY['chainId','units'], ARRAY['finalized']) || amounts
93
+ || CASE WHEN state->>'token' ~ '^0x[0-9a-fA-F]{40}$' THEN jsonb_build_object('token',state->'token') ELSE '{}'::jsonb END;
94
+ END
95
+ $$;
96
+ CREATE OR REPLACE FUNCTION pg_temp.financial_rows_v1(table_name text, columns text[]) RETURNS jsonb LANGUAGE plpgsql AS $$
97
+ DECLARE result jsonb;
98
+ BEGIN
99
+ IF to_regclass(table_name) IS NULL THEN RETURN '[]'::jsonb; END IF;
100
+ EXECUTE format('SELECT COALESCE(jsonb_agg(projected ORDER BY projected::text), ''[]''::jsonb) FROM (
101
+ SELECT (SELECT COALESCE(jsonb_object_agg(key,
102
+ CASE WHEN key=ANY(ARRAY[''sent_ref'',''settle_response'']) THEN pg_temp.settlement_v1(value)
103
+ WHEN key=''fulfilment'' THEN pg_temp.fulfilment_v1(value)
104
+ WHEN key=''lot_debits'' THEN pg_temp.lot_debits_v1(value)
105
+ WHEN key=''state_json'' THEN pg_temp.tempo_state_v1(value)
106
+ WHEN key=''channel_config'' THEN pg_temp.channel_config_v1(value)
107
+ WHEN key=''effect'' THEN pg_temp.effect_v1(value)
108
+ WHEN key=''receipt'' THEN pg_temp.receipt_v1(value)
109
+ WHEN key=''receipts'' THEN (SELECT COALESCE(jsonb_agg(pg_temp.receipt_v1(r)), ''[]''::jsonb) FROM jsonb_array_elements(value) r)
110
+ ELSE CASE WHEN jsonb_typeof(value) NOT IN (''object'',''array'') THEN value ELSE NULL END END), ''{}''::jsonb)
111
+ FROM jsonb_each(to_jsonb(t)) WHERE key=ANY($1)) projected FROM %I t) rows', table_name)
112
+ INTO result USING columns;
113
+ RETURN result;
114
+ END
115
+ $$;
116
+ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY;
117
+ SELECT jsonb_build_object(
118
+ 'format', 'dvmkit-financial-evidence', 'version', 1,
119
+ 'jobs', pg_temp.financial_rows_v1('jobs', ARRAY['id','dvm_id','request_id','requester_pubkey','capability','status','created_at','last_activity_at','terminal_at_ms','ended_by','receipt','receipt_seq','paid_msats','payment_rail','payment_tx_hash','payment_transaction_hash','native_amount','native_asset','credit_id','draw_id','cost_amount_micro','cost_currency']),
120
+ 'credits', pg_temp.financial_rows_v1('credits', ARRAY['credit_id','caller_pubkey','currency','balance_micro','expiry_ms','status','last_ledger_seq','created_at','rail','native_asset','funding_ref','tempo_channel_id','x402_channel_id','msats_remaining','native_remaining']),
121
+ 'fundings', pg_temp.financial_rows_v1('credit_fundings', ARRAY['credit_id','fund_id','caller_pubkey','amount_micro','rail','created_at','balance_after_micro','ledger_seq','receipt']),
122
+ 'funding_lots', pg_temp.financial_rows_v1('credit_funding_lots', ARRAY['lot_id','credit_id','rail','sats_funded','credited_micro','remaining_micro','funding_ref','created_at']),
123
+ 'draws', pg_temp.financial_rows_v1('credit_draws', ARRAY['credit_id','draw_id','job_id','amount_micro','ledger_seq','status','balance_after_micro','created_at','resolved_at','draw_msats','allocated_msats','draw_native','grown_micro']),
124
+ 'drains', pg_temp.financial_rows_v1('credit_drains', ARRAY['credit_id','drain_id','method','amount_micro','balance_after_micro','drained_msats','drained_native','owed_sats','ledger_seq','status','receipts','sent_ref','fulfilment','lot_debits','created_at','parked_at','picked_up_at','sent_at','released_at','written_off_at']),
125
+ 'invoices', pg_temp.financial_rows_v1('credit_invoices', ARRAY['credit_id','fund_id','caller_pubkey','currency','amount_micro','amount_msats','payment_hash','status','expires_at','created_at','settled_at','reconciled_credit_id','reconciled_fund_id','resolved_at']),
126
+ 'expiry_releases', pg_temp.financial_rows_v1('credit_expiry_releases', ARRAY['credit_id','release_id','caller_pubkey','currency','rail','amount_micro','expiry_ms','released_at','reversed_at']),
127
+ 'tempo_channels', pg_temp.financial_rows_v1('mpp_tempo_channels', ARRAY['channel_key','state_json','updated_at']),
128
+ 'tempo_channel_tombstones', pg_temp.financial_rows_v1('mpp_tempo_channel_tombstones', ARRAY['channel_key','state_json','deleted_at_ms']),
129
+ 'tempo_close_intents', pg_temp.financial_rows_v1('mpp_tempo_close_intents', ARRAY['channel_id','drain_id','reference','forecast_pending','updated_at']),
130
+ 'x402_channels', pg_temp.financial_rows_v1('x402_batch_channels', ARRAY['channel_id','channel_config','charged_cumulative_amount','signed_max_claimable','balance','total_claimed','withdraw_requested_at','refund_nonce','onchain_synced_at','last_request_timestamp']),
131
+ 'x402_channel_tombstones', pg_temp.financial_rows_v1('x402_batch_channel_tombstones', ARRAY['channel_id','charged_cumulative_amount','signed_max_claimable','refund_nonce','deleted_at_ms']),
132
+ 'x402_batch_settlements', pg_temp.financial_rows_v1('x402_batch_settlements', ARRAY['settlement_id','channel_id','operation','effect_id','payment_id','status','submission_block','settle_response','created_at','updated_at','resolved_at']),
133
+ 'x402_exact_settlements', pg_temp.financial_rows_v1('x402_exact_settlement_intents', ARRAY['dvm_id','intent_id','network','asset','authorizer','recipient','value','status','effect','submission_block','transaction','settle_response','last_outcome','created_at','updated_at','resolved_at']),
134
+ 'tempo_losses', pg_temp.financial_rows_v1('tempo_credit_losses', ARRAY['credit_id','channel_id','caller_pubkey','currency','former_balance_micro','settled_on_chain_native','highest_voucher_native','consumed_service_micro','consumed_native','observed_at']),
135
+ 'x402_losses', pg_temp.financial_rows_v1('x402_credit_losses', ARRAY['credit_id','channel_id','caller_pubkey','currency','former_balance_micro','channel_balance_native','total_claimed_native','consumed_service_micro','observed_at'])
136
+ );
137
+ ROLLBACK;