@dvmkit/sdk 0.1.0-rc.2 → 0.1.0-rc.4

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 (42) hide show
  1. package/README.md +10 -2
  2. package/dist/{revenue-reporter-GB4WKLDC.js → chunk-2ABMGUDS.js} +1 -0
  3. package/dist/chunk-2K6UXDAN.js +1557 -0
  4. package/dist/chunk-4UVRXDNY.js +21745 -0
  5. package/dist/chunk-66HGCPBU.js +25 -0
  6. package/dist/{chunk-DCNT4PJS.js → chunk-AAJNGQMC.js} +6 -258
  7. package/dist/{chunk-KQAJVVZT.js → chunk-AZBXSXQT.js} +27 -287
  8. package/dist/{chunk-H25M54MI.js → chunk-C3MTFLC6.js} +16 -0
  9. package/dist/chunk-EDU6COY2.js +1057 -0
  10. package/dist/{chunk-OJ5WFIB2.js → chunk-EXHBXA4U.js} +1 -1
  11. package/dist/chunk-F2L6KIMD.js +380 -0
  12. package/dist/{chunk-KXWROQGK.js → chunk-FUJ36YDV.js} +1 -24
  13. package/dist/chunk-GJD7PVWY.js +1090 -0
  14. package/dist/{tempo-charge-store-6GJEMNUU.js → chunk-JZWELPFH.js} +1 -0
  15. package/dist/{chunk-365P52XQ.js → chunk-LWUR4CGG.js} +2 -1
  16. package/dist/{tempo-session-store-FTEEGZXA.js → chunk-RU7SXHLO.js} +2 -1
  17. package/dist/{chunk-7IH5SG2A.js → chunk-TKA6ZP4M.js} +62 -41
  18. package/dist/chunk-TVI4V7GF.js +283 -0
  19. package/dist/{payout-reporter-4TNWRS5F.js → chunk-X3IKFWJA.js} +3 -2
  20. package/dist/chunk-XYTSDAPH.js +232 -0
  21. package/dist/{credit-ledger-RO4FGSHG.js → credit-ledger-ED6JXKVD.js} +2 -2
  22. package/dist/credit-menu-ClA1JyYW.d.ts +5076 -0
  23. package/dist/{ssrf-DZi-xJyn.d.ts → fx-ptKVFOwq.d.ts} +37 -119
  24. package/dist/index.d.ts +8 -66
  25. package/dist/index.js +11 -219
  26. package/dist/internal/index.d.ts +5896 -0
  27. package/dist/internal/index.js +6407 -0
  28. package/dist/{job-store-6gR4pZRP.d.ts → job-store-DxFqDPYq.d.ts} +1498 -12
  29. package/dist/{memory-credit-ledger-I2G64DDK.js → memory-credit-ledger-XJ5VQEVP.js} +3 -3
  30. package/dist/payout-reporter-3UB5WRCV.js +13 -0
  31. package/dist/revenue-reporter-JIKUPXOK.js +7 -0
  32. package/dist/server/index.d.ts +14 -3590
  33. package/dist/server/index.js +155 -20850
  34. package/dist/ssrf-DbFkpDv0.d.ts +118 -0
  35. package/dist/tempo-charge-store-RIFTALZK.js +8 -0
  36. package/dist/tempo-session-store-DALMRIWN.js +11 -0
  37. package/dist/testing/index.d.ts +3 -2
  38. package/dist/testing/index.js +3 -2
  39. package/dist/usd-Cha_j80I.d.ts +97 -0
  40. package/dist/x402-XXFQQAAD.js +81 -0
  41. package/package.json +6 -2
  42. package/dist/x402-35VLYFKZ.js +0 -1272
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Why `assertSafeUrl` refused this URL. Carried on `SSRFError` so callers can
3
+ * branch without string-matching `err.message` — DNS failures (NXDOMAIN, empty
4
+ * resolution), unparseable URLs, and a non-https scheme each have distinct
5
+ * recovery paths and shouldn't collapse together.
6
+ */
7
+ type SSRFReason = "invalid_url" | "insecure_scheme" | "private_address" | "dns_failed";
8
+ /**
9
+ * Thrown when an input URL points at internal infrastructure we refuse to
10
+ * fetch from inside the cluster. Carries a `reason` discriminator so the
11
+ * caller can map cleanly onto its public taxonomy instead of inspecting the
12
+ * message string.
13
+ */
14
+ declare class SSRFError extends Error {
15
+ readonly code: "ssrf_blocked";
16
+ readonly reason: SSRFReason;
17
+ constructor(reason: SSRFReason, message: string);
18
+ }
19
+ /** Pluggable DNS resolver. Defaults to `node:dns/promises` `lookup(host, { all: true })`. */
20
+ type SSRFResolver = (host: string) => Promise<{
21
+ address: string;
22
+ family: number;
23
+ }[]>;
24
+ /**
25
+ * Configurable hooks for `assertSafeUrl`. Defaults preserve the dvmkit
26
+ * baseline denylist; extra entries compose with (never replace) the defaults.
27
+ */
28
+ interface SSRFGuardOpts {
29
+ /** Custom DNS resolver — typically a test stub. */
30
+ resolver?: SSRFResolver;
31
+ /** Additional exact hostnames to deny on top of the defaults (lowercased on input). */
32
+ extraHostnamesExact?: Iterable<string>;
33
+ /**
34
+ * Additional hostname suffixes to deny on top of the defaults. Each entry
35
+ * should include the leading dot (e.g. `.example.invalid`) — the same shape
36
+ * the defaults use.
37
+ */
38
+ extraHostnameSuffixes?: Iterable<string>;
39
+ /** Additional IPv4 predicate. Returns true for an unsafe address. */
40
+ extraUnsafeIPv4?: (ipv4: string) => boolean;
41
+ /** Additional IPv6 predicate. Returns true for an unsafe address. */
42
+ extraUnsafeIPv6?: (ipv6: string) => boolean;
43
+ /**
44
+ * Underlying fetch implementation `createPinnedFetch` wraps. Defaults to
45
+ * `globalThis.fetch`. Pass an instrumented wrapper (e.g. scribe's
46
+ * `ctx.fetch` from `createInstrumentedFetch`) to keep `dvm.fetch` spans
47
+ * around outbound HEAD / GET — the dispatcher pin for every safe redirect
48
+ * hop is preserved because `init.dispatcher` flows through any thin fetch
49
+ * wrapper unchanged.
50
+ */
51
+ baseFetch?: typeof fetch;
52
+ /**
53
+ * Called after a redirect response is accepted and before the target is
54
+ * resolved or connected. Lets an outer transport refuse to replay an
55
+ * original request once its source has demonstrably responded.
56
+ */
57
+ onRedirectFollowed?: () => void;
58
+ }
59
+ /**
60
+ * Reject URLs whose host points at internal infrastructure — private /
61
+ * link-local IP ranges, the AWS / GCP metadata IP, Fly's `*.internal`
62
+ * service-discovery names, and a small denylist of obviously-internal
63
+ * hostnames. Defence-in-depth — full mitigation belongs at the egress firewall
64
+ * and at fetch-time IP pinning (`createPinnedFetch`, internal-review).
65
+ *
66
+ * Throws `SSRFError` with a `reason` discriminator so callers can branch onto
67
+ * their own typed error taxonomy.
68
+ */
69
+ declare function assertSafeUrl(url: string, opts?: SSRFGuardOpts): Promise<void>;
70
+ /**
71
+ * A `fetch`-compatible function pinned to a single pre-validated IP address.
72
+ *
73
+ * Returned by {@link createPinnedFetch}. Closes the DNS-rebinding window in
74
+ * which `assertSafeUrl` validates an address but the subsequent `fetch()`
75
+ * re-resolves DNS and lands on a different (private) address.
76
+ *
77
+ * Callers MUST `await close()` when done with the pin so undici's connection
78
+ * pool is released.
79
+ */
80
+ interface PinnedFetch {
81
+ /** Fetch whose initial request and every followed redirect are pinned to their pre-validated address sets. */
82
+ fetch: typeof fetch;
83
+ /** Primary (first) validated address of the initial URL. */
84
+ address: string;
85
+ /** IP family (4 or 6) of {@link address} (the primary). */
86
+ family: number;
87
+ /** Release the undici connection pool backing this pinned fetch. */
88
+ close(): Promise<void>;
89
+ }
90
+ /**
91
+ * Resolve the URL's host once, validate every answer against the same
92
+ * denylist `assertSafeUrl` applies, then return a `fetch` whose `connect.lookup`
93
+ * replays that frozen, pre-validated address set (see {@link buildPinnedLookup}).
94
+ * Redirects are followed manually: each target URL is independently required
95
+ * to be HTTPS, resolved once, denylist-checked, and pinned before it can be
96
+ * requested. That prevents an automatic redirect from reusing the source
97
+ * host's dispatcher for a different hostname, while keeping a redirect from
98
+ * opening a DNS-rebinding window.
99
+ *
100
+ * Throws `SSRFError` with the same `reason` discriminator as `assertSafeUrl`,
101
+ * so error-mapping paths (`mapSsrfError` in cast/scribe) work unchanged.
102
+ *
103
+ * For IP-literal URLs no dispatcher is needed, but redirects still pass
104
+ * through the same validation loop.
105
+ *
106
+ * Replaying the full validated set (not just `addresses[0]`) preserves Node's
107
+ * happy-eyeballs fallback across the answers — a host whose first address is an
108
+ * unroutable family still connects via the others — while keeping the rebind
109
+ * window closed, since every replayed address was already denylist-checked.
110
+ *
111
+ * Pass `opts.baseFetch` to wrap an instrumented fetch (e.g. scribe's
112
+ * `ctx.fetch` from `createInstrumentedFetch`) — `dvm.fetch` spans flow
113
+ * through because `init.dispatcher` is forwarded to the underlying
114
+ * `globalThis.fetch` unchanged.
115
+ */
116
+ declare function createPinnedFetch(url: string, opts?: SSRFGuardOpts): Promise<PinnedFetch>;
117
+
118
+ export { type PinnedFetch as P, SSRFError as S, type SSRFGuardOpts as a, type SSRFReason as b, type SSRFResolver as c, assertSafeUrl as d, createPinnedFetch as e };
@@ -0,0 +1,8 @@
1
+ import {
2
+ PostgresTempoChargeStore
3
+ } from "./chunk-JZWELPFH.js";
4
+ import "./chunk-YG7G4DPZ.js";
5
+ import "./chunk-S3XAHZQY.js";
6
+ export {
7
+ PostgresTempoChargeStore
8
+ };
@@ -0,0 +1,11 @@
1
+ import {
2
+ PostgresTempoSessionStore,
3
+ assertMonotonicTransition
4
+ } from "./chunk-RU7SXHLO.js";
5
+ import "./chunk-YG7G4DPZ.js";
6
+ import "./chunk-C3MTFLC6.js";
7
+ import "./chunk-S3XAHZQY.js";
8
+ export {
9
+ PostgresTempoSessionStore,
10
+ assertMonotonicTransition
11
+ };
@@ -1,9 +1,10 @@
1
- import { aX as StreamableJobStore, aY as ReceiptIssuingStore, J as JobRecord, aZ as RequestIdClaim, a_ as RequestIdClaimResult, a9 as JobReceipt, a$ as OutgoingMessage, aa as AppendOutgoingOptions, b0 as PaymentCreditDelta, b1 as VerifyAndCreditResult, b2 as JobCounters, a6 as Message, av as MessageType, K as KVStore, L as Logger, v as ResponseContent, P as PaymentContent, S as SDKJobContext } from '../job-store-6gR4pZRP.js';
1
+ import { c8 as StreamableJobStore, c9 as ReceiptIssuingStore, J as JobRecord, ca as RequestIdClaim, cb as RequestIdClaimResult, _ as JobReceipt, as as OutgoingMessage, cc as AppendOutgoingOptions, cd as PaymentCreditDelta, ce as VerifyAndCreditResult, cf as JobCounters, a2 as Message, a3 as MessageType, K as KVStore, L as Logger, v as ResponseContent, P as PaymentContent, S as SDKJobContext } from '../job-store-DxFqDPYq.js';
2
2
  import '@cashu/cashu-ts';
3
3
  import 'mppx';
4
- import 'hono';
5
4
  import '@x402/core/server';
6
5
  import '@x402/evm/batch-settlement/server';
6
+ import 'hono';
7
+ import 'viem';
7
8
  import 'pg';
8
9
  import '@x402/core/types';
9
10
  import 'zod';
@@ -4,8 +4,9 @@ import {
4
4
  MemoryKVStore,
5
5
  createInstrumentedFetch,
6
6
  createNoopLogger
7
- } from "../chunk-7IH5SG2A.js";
8
- import "../chunk-KXWROQGK.js";
7
+ } from "../chunk-TKA6ZP4M.js";
8
+ import "../chunk-66HGCPBU.js";
9
+ import "../chunk-FUJ36YDV.js";
9
10
 
10
11
  // src/sdk/testing/test-context.ts
11
12
  function createTestContext(opts) {
@@ -0,0 +1,97 @@
1
+ import { C as Currency } from './job-store-DxFqDPYq.js';
2
+
3
+ /**
4
+ * Thrown by `fiatToSatsCeil` / `satsToFiat` when the supplied `ratePerBtc` is
5
+ * non-finite or non-positive. Surfaces a misconfigured fx fetcher loudly
6
+ * instead of silently producing a 0-sats charge or a 0-fiat display string —
7
+ * a silent 0 lost real money in internal-review slice-04. Callers obtain a valid rate
8
+ * from the SDK's fx fetcher (which raises `FxRateUnavailableError` on
9
+ * upstream failure); this error is the defence-in-depth backstop for any
10
+ * caller that constructs a rate by other means.
11
+ */
12
+ declare class InvalidFxRateError extends Error {
13
+ readonly code = "invalid_fx_rate";
14
+ readonly ratePerBtc: unknown;
15
+ constructor(ratePerBtc: unknown);
16
+ }
17
+ /**
18
+ * Convert a fiat amount to integer sats at the supplied fiat-per-BTC rate.
19
+ * Rounds **up** so the operator never overcharges the caller (caller-friendly
20
+ * rounding). Negative or non-finite amounts collapse to 0 (a $0 charge is
21
+ * well-defined). A non-finite or non-positive `ratePerBtc` raises
22
+ * `InvalidFxRateError` — a silent 0 would mask a misconfigured fetcher into
23
+ * shipping a free charge. The math is currency-agnostic — `ratePerBtc` is the
24
+ * number of units of *some* fiat per 1 BTC; the caller looks the right rate
25
+ * out of an `FxRateSnapshot`.
26
+ */
27
+ declare function fiatToSatsCeil(amount: number, ratePerBtc: number): number;
28
+ /**
29
+ * Convert integer sats back to a fiat amount at the supplied fiat-per-BTC
30
+ * rate. A non-finite or non-positive `ratePerBtc` raises
31
+ * `InvalidFxRateError` — the silent `0` would land in display strings and
32
+ * mislead callers about the value at hand.
33
+ */
34
+ declare function satsToFiat(sats: number, ratePerBtc: number): number;
35
+ /**
36
+ * Thrown when a builder-declared USD price literal is malformed (internal-review).
37
+ * Carries the offending value and the config field it came from so
38
+ * `configureDVM`'s boot check can surface both without re-deriving them.
39
+ */
40
+ declare class InvalidUsdPriceError extends Error {
41
+ readonly field: string;
42
+ readonly value: unknown;
43
+ readonly code = "invalid_usd_price";
44
+ constructor(field: string, value: unknown, detail: string);
45
+ }
46
+ /**
47
+ * Parse a builder-declared USD price literal (`"$0.05"`) into a bare USD
48
+ * number. The single parser for every price surface — capability `price`,
49
+ * `credit.min`/`credit.max`, the `/v1/info` pricing ceiling, and the ledger's
50
+ * fiat denomination — so those surfaces cannot drift on what they accept.
51
+ *
52
+ * Strict by construction on both format and precision:
53
+ *
54
+ * - The grammar is `$` followed by a decimal number, so `"$1abc"` (which every
55
+ * ad-hoc `parseFloat(v.slice(1))` used to accept as 1) is rejected.
56
+ * - The amount must be expressible at {@link roundUsd}'s four decimal places,
57
+ * which is the precision **every** advertisement surface carries — `/v1/info`
58
+ * pricing ceilings, `/v1/quote` upfronts, the isolate tier's re-emit. A price
59
+ * finer than that advertises as a different number than it charges, and one
60
+ * below `$0.0001` advertises as `$0` while still gating the job: advertised
61
+ * paid, apparently free, which is the shape internal-review exists to close.
62
+ *
63
+ * The floor is deliberately 100× coarser than the credit ledger's micro-unit.
64
+ * The ledger could denominate `$0.000001`; no surface a caller reads can
65
+ * express it, so blessing it here would only move the incoherence downstream.
66
+ */
67
+ declare function parseUsdPrice(value: string, field: string): number;
68
+ /**
69
+ * Round a USD value to 4 decimal places (matches scribe's stored display
70
+ * precision). This is the **storage / accounting** precision — preserves
71
+ * sub-cent amounts so a `$0.0150` per-minute rate doesn't collapse to
72
+ * `$0.02` before it ever reaches a multiplier. See {@link formatUsd} for the
73
+ * human-render precision, which deliberately truncates at the cent boundary
74
+ * for amounts ≥ $0.01.
75
+ */
76
+ declare function roundUsd(usd: number): number;
77
+ /**
78
+ * Format a USD amount with adaptive precision so sub-cent amounts don't
79
+ * render as `$0.00`. The 2dp/4dp boundary at $0.01 is **human-render**
80
+ * precision and is intentionally coarser than {@link roundUsd}'s storage
81
+ * precision: a value like `0.015` keeps four decimals through `roundUsd`
82
+ * (storage / multiplier inputs) but renders as `$0.02` here (human display).
83
+ * Don't try to unify the two — they serve different surfaces.
84
+ */
85
+ declare function formatUsd(usd: number): string;
86
+ /**
87
+ * Format a fiat amount with currency-aware symbol, precision, and ISO code.
88
+ * Used by the CLI to render payment-request `fiat_amount` envelopes ("$0.05
89
+ * USD", "€0.05 EUR", "¥5 JPY"). Precision is adaptive: JPY has no sub-yen
90
+ * denomination so renders as 0 decimals, every other currency uses 2 decimals
91
+ * at or above 0.01 and 4 below so sub-cent figures don't collapse to 0.00.
92
+ * Unknown currencies (anything not in {@link FIAT_SYMBOLS}) render with the
93
+ * uppercased ISO code and no leading symbol.
94
+ */
95
+ declare function formatFiat(amount: number, currency: Currency): string;
96
+
97
+ export { InvalidFxRateError as I, formatFiat as a, formatUsd as b, InvalidUsdPriceError as c, fiatToSatsCeil as f, parseUsdPrice as p, roundUsd as r, satsToFiat as s };
@@ -0,0 +1,81 @@
1
+ import {
2
+ connectedX402Payer,
3
+ ensureAddress,
4
+ generateX402PrivateKey,
5
+ getX402Balance,
6
+ loadX402Wallet,
7
+ removeX402Wallet,
8
+ repinX402WalletNetwork,
9
+ resolveX402Asset,
10
+ saveX402Wallet,
11
+ tryX402Payment,
12
+ verifyX402Payment,
13
+ x402WrongAssetHint
14
+ } from "./chunk-GJD7PVWY.js";
15
+ import "./chunk-2K6UXDAN.js";
16
+ import {
17
+ X402_DEFAULT_FACILITATOR,
18
+ X402_DEFAULT_NETWORK,
19
+ X402_NETWORKS,
20
+ X402_V1_VERSION,
21
+ X402_VERSION,
22
+ assertSupportedX402Network,
23
+ buildPaymentRequiredV2,
24
+ buildPaymentRequirements,
25
+ caip2ToX402Network,
26
+ chainIdFromCaip2,
27
+ decodePayment,
28
+ decodePaymentRequiredHeader,
29
+ encodePayment,
30
+ encodePaymentRequiredHeader,
31
+ encodeSettleResponseHeader,
32
+ exactEvmAuthorization,
33
+ paymentRequiredV2FromV1,
34
+ usdcContractByCaip2,
35
+ x402NetworkByCaip2,
36
+ x402NetworkLabel,
37
+ x402NetworkListForCopy,
38
+ x402NetworkToCaip2,
39
+ x402SupportedNetworksHint
40
+ } from "./chunk-AAJNGQMC.js";
41
+ import "./chunk-F2L6KIMD.js";
42
+ import "./chunk-66HGCPBU.js";
43
+ import "./chunk-FUJ36YDV.js";
44
+ import "./chunk-AT6V3SY7.js";
45
+ export {
46
+ X402_DEFAULT_FACILITATOR,
47
+ X402_DEFAULT_NETWORK,
48
+ X402_NETWORKS,
49
+ X402_V1_VERSION,
50
+ X402_VERSION,
51
+ assertSupportedX402Network,
52
+ buildPaymentRequiredV2,
53
+ buildPaymentRequirements,
54
+ caip2ToX402Network,
55
+ chainIdFromCaip2,
56
+ connectedX402Payer,
57
+ decodePayment,
58
+ decodePaymentRequiredHeader,
59
+ encodePayment,
60
+ encodePaymentRequiredHeader,
61
+ encodeSettleResponseHeader,
62
+ ensureAddress,
63
+ exactEvmAuthorization,
64
+ generateX402PrivateKey,
65
+ getX402Balance,
66
+ loadX402Wallet,
67
+ paymentRequiredV2FromV1,
68
+ removeX402Wallet,
69
+ repinX402WalletNetwork,
70
+ resolveX402Asset,
71
+ saveX402Wallet,
72
+ tryX402Payment,
73
+ usdcContractByCaip2,
74
+ verifyX402Payment,
75
+ x402NetworkByCaip2,
76
+ x402NetworkLabel,
77
+ x402NetworkListForCopy,
78
+ x402NetworkToCaip2,
79
+ x402SupportedNetworksHint,
80
+ x402WrongAssetHint
81
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dvmkit/sdk",
3
- "version": "0.1.0-rc.2",
3
+ "version": "0.1.0-rc.4",
4
4
  "description": "SDK for building accountless, pay-per-use Digital Vending Machines",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -27,6 +27,10 @@
27
27
  "./server": {
28
28
  "types": "./dist/server/index.d.ts",
29
29
  "import": "./dist/server/index.js"
30
+ },
31
+ "./internal": {
32
+ "types": "./dist/internal/index.d.ts",
33
+ "import": "./dist/internal/index.js"
30
34
  }
31
35
  },
32
36
  "files": [
@@ -37,7 +41,7 @@
37
41
  "node": ">=22"
38
42
  },
39
43
  "scripts": {
40
- "build": "tsup --config tsup.config.ts && node scripts/prune-sdk-dist.mjs",
44
+ "build": "NODE_OPTIONS=--max-old-space-size=6144 tsup --config tsup.config.ts && node scripts/prune-sdk-dist.mjs",
41
45
  "check:api": "node scripts/check-api-surface.mjs",
42
46
  "check:consumer": "node scripts/consumer-smoke.mjs",
43
47
  "check:package": "node scripts/package-smoke.mjs",