@elisym/commerce 0.1.0 → 0.3.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 +11 -0
- package/dist/buyer.d.ts +921 -0
- package/dist/buyer.js +1799 -0
- package/dist/buyer.js.map +1 -0
- package/dist/chunk-DYXVY6VD.js +1464 -0
- package/dist/chunk-DYXVY6VD.js.map +1 -0
- package/dist/index.d.ts +39 -542
- package/dist/index.js +1 -1442
- package/dist/index.js.map +1 -1
- package/dist/verify-offer-BZ_a9x3L.d.ts +558 -0
- package/package.json +6 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,84 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
declare const KIND_STORE_PROFILE = 0;
|
|
7
|
-
/** Payout addresses (NIP-A3 `payto` plus the elisym `accept` extension), signed by the owner key. */
|
|
8
|
-
declare const KIND_PAYTO = 10133;
|
|
9
|
-
/**
|
|
10
|
-
* "Store key S acts for owner O", signed by the owner key. Addressable, `d` = the
|
|
11
|
-
* store pubkey.
|
|
12
|
-
*
|
|
13
|
-
* PROVISIONAL: the number is not registered yet (spec, open question 1). It is
|
|
14
|
-
* named in one place so that fixing it is a one-line change.
|
|
15
|
-
*/
|
|
16
|
-
declare const KIND_STORE_AUTH = 30490;
|
|
17
|
-
/** Product listing (NIP-99, Gamma Markets), signed by the store key. */
|
|
18
|
-
declare const KIND_PRODUCT = 30402;
|
|
19
|
-
/** Inbox relays for gift-wrapped messages (NIP-17). */
|
|
20
|
-
declare const KIND_INBOX_RELAYS = 10050;
|
|
21
|
-
/** Order message inside a gift wrap: `type` 1 order, 2 payment request, 3 status (Gamma Markets). */
|
|
22
|
-
declare const KIND_ORDER_MESSAGE = 16;
|
|
23
|
-
/** Payment receipt inside a gift wrap (Gamma Markets). */
|
|
24
|
-
declare const KIND_PAYMENT_RECEIPT = 17;
|
|
25
|
-
/** NIP-09 deletion: an `a` tag on the owner's AUTH address revokes it, like `mode` revoked. */
|
|
26
|
-
declare const KIND_DELETION = 5;
|
|
27
|
-
declare const KIND_SEAL = 13;
|
|
28
|
-
declare const KIND_GIFT_WRAP = 1059;
|
|
29
|
-
/** Opt-in tag value that lists a product in the elisym aggregator. */
|
|
30
|
-
declare const ELISYM_NETWORK_TAG = "elisym";
|
|
31
|
-
/**
|
|
32
|
-
* What a payout wallet signs to prove it belongs to the owner. The owner pubkey
|
|
33
|
-
* and the CAIP-19 id are both inside, so a proof made for one owner or one asset
|
|
34
|
-
* cannot be replayed for another.
|
|
35
|
-
*/
|
|
36
|
-
declare const PAYTO_PROOF_PREFIX = "elisym-payto:v1";
|
|
37
|
-
declare const DELIVERY_METHODS: readonly ["download", "license", "access", "webhook", "api"];
|
|
38
|
-
type DeliveryMethod = (typeof DELIVERY_METHODS)[number];
|
|
39
|
-
declare const ORDER_STATUSES: readonly ["pending", "confirmed", "completed", "cancelled"];
|
|
40
|
-
type OrderStatus = (typeof ORDER_STATUSES)[number];
|
|
41
|
-
/** Gamma Markets visibility values under which a product can be bought. */
|
|
42
|
-
declare const PURCHASABLE_VISIBILITIES: readonly ["on-sale", "pre-order"];
|
|
43
|
-
/** A payout address younger than this is flagged: the owner key may have been taken over. */
|
|
44
|
-
declare const PAYOUT_COOLDOWN_SECS: number;
|
|
45
|
-
/** How far in the future an event's `created_at` may sit before it is ignored. */
|
|
46
|
-
declare const MAX_FUTURE_SKEW_SECS: number;
|
|
47
|
-
declare const LIMITS: {
|
|
48
|
-
readonly MAX_ORDER_ID_LENGTH: 64;
|
|
49
|
-
readonly MAX_TAG_VALUE_LENGTH: 1024;
|
|
50
|
-
readonly MAX_CONTENT_LENGTH: number;
|
|
51
|
-
readonly MAX_ITEMS_PER_ORDER: 50;
|
|
52
|
-
readonly MAX_NIP05_DOCUMENT_BYTES: number;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
interface Caip19 {
|
|
56
|
-
/** The full id, exactly as written. */
|
|
57
|
-
id: string;
|
|
58
|
-
caip2: string;
|
|
59
|
-
chain: ChainConfig;
|
|
60
|
-
/** The registry coin it names, on that chain's environment. */
|
|
61
|
-
asset: Asset;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Parse a CAIP-19 id for a coin the payment registry knows: `solana:<ref>/token:<mint>`
|
|
65
|
-
* or `eip155:<id>/erc20:<lowercase contract>`. Anything else - an unknown chain,
|
|
66
|
-
* a namespace that does not fit the chain, a coin the registry does not hold -
|
|
67
|
-
* is `undefined`: an asset nothing can pay in is not an asset.
|
|
68
|
-
*/
|
|
69
|
-
declare function parseCaip19(id: string): Caip19 | undefined;
|
|
70
|
-
/**
|
|
71
|
-
* Whether a mixed-case EVM address carries a valid EIP-55 checksum. An address
|
|
72
|
-
* in one case has none to check and passes; a mixed-case one with a wrong
|
|
73
|
-
* checksum is a typo.
|
|
74
|
-
*/
|
|
75
|
-
declare function hasValidEvmChecksum(address: string): boolean;
|
|
76
|
-
/**
|
|
77
|
-
* The one canonical spelling of a payout address on a chain, or `undefined` if it
|
|
78
|
-
* is not one. EVM addresses are lowercase on the wire, so every comparison is
|
|
79
|
-
* plain equality; a virtual (TIP-1022) address is refused, as the payment rail does.
|
|
80
|
-
*/
|
|
81
|
-
declare function canonicalPayoutAddress(chain: ChainConfig, address: string): string | undefined;
|
|
1
|
+
import { O as OrderMessage } from './verify-offer-BZ_a9x3L.js';
|
|
2
|
+
export { C as Caip19, D as DELIVERY_METHODS, a as DeliveryMethod, b as DomainKeys, E as ELISYM_NETWORK_TAG, c as EndpointType, d as EvaluateOfferOptions, F as FetchLike, K as KIND_DELETION, e as KIND_GIFT_WRAP, f as KIND_INBOX_RELAYS, g as KIND_ORDER_MESSAGE, h as KIND_PAYMENT_RECEIPT, i as KIND_PAYTO, j as KIND_PRODUCT, k as KIND_SEAL, l as KIND_STORE_AUTH, m as KIND_STORE_PROFILE, L as LIMITS, M as MAX_FUTURE_SKEW_SECS, n as Money, o as ORDER_PAYMENT_REFERENCE_PREFIX, p as ORDER_STATUSES, q as OfferBundle, r as OfferRefusal, s as OfferVerification, t as OfferWarning, u as OrderItem, v as OrderRequest, w as OrderStatus, x as OrderStatusMessage, P as PAYOUT_COOLDOWN_SECS, y as PAYTO_PROOF_PREFIX, z as PURCHASABLE_VISIBILITIES, A as ParsedPayto, B as PaymentReceipt, G as PaymentRequestMessage, H as PayoutTarget, I as PaytoInput, J as PriceFrequency, N as Product, Q as ProductInput, R as ProductPointer, S as ProductPrice, T as ResolveDomainOptions, U as StoreProfile, V as StoreProfileInput, W as TrustLevel, X as VerifiedOffer, Y as VerifyOfferDeps, Z as buildOrderMessage, _ as buildPaytoEvent, $ as buildProductEvent, a0 as buildStoreProfileEvent, a1 as canonicalPayoutAddress, a2 as decodeProductNaddr, a3 as encodeProductNaddr, a4 as evaluateOffer, a5 as hasValidEvmChecksum, a6 as isOfferPayout, a7 as isOrderId, a8 as isPublicHostname, a9 as isPurchasable, aa as parseCaip19, ab as parseOrderMessage, ac as parsePayto, ad as parseProduct, ae as parseStoreProfile, af as priceInSubunits, ag as productAddress, ah as readElisymTxt, ai as readNostrJson, aj as resolveDomainKeys, ak as splitNip05, al as verifyOffer } from './verify-offer-BZ_a9x3L.js';
|
|
3
|
+
import { ChainConfig } from '@elisym/pay-core';
|
|
4
|
+
import { EventTemplate, NostrEvent } from 'nostr-tools';
|
|
5
|
+
import 'zod';
|
|
82
6
|
|
|
83
7
|
/**
|
|
84
8
|
* The exact text a payout wallet signs for an `accept` tag. A Solana wallet signs
|
|
@@ -105,102 +29,6 @@ declare function verifyPaytoProof(params: {
|
|
|
105
29
|
/** keccak256("\x19Ethereum Signed Message:\n" + len(message) + message). */
|
|
106
30
|
declare function eip191Hash(message: Uint8Array): Uint8Array;
|
|
107
31
|
|
|
108
|
-
/** The keys a merchant's domain vouches for. */
|
|
109
|
-
interface DomainKeys {
|
|
110
|
-
domain: string;
|
|
111
|
-
/**
|
|
112
|
-
* The NIP-05 name that was looked up (`_` for the domain itself). The answer
|
|
113
|
-
* vouches for that name only: a profile under another name cannot borrow it.
|
|
114
|
-
*/
|
|
115
|
-
name: string;
|
|
116
|
-
storePubkey?: string;
|
|
117
|
-
ownerPubkey?: string;
|
|
118
|
-
source: 'nostr.json' | 'dns';
|
|
119
|
-
}
|
|
120
|
-
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
121
|
-
/**
|
|
122
|
-
* A public DNS name: lowercase labels, at least two, no IP literal, no port. The
|
|
123
|
-
* domain comes from a store's own profile - attacker-controlled - so nothing
|
|
124
|
-
* else is fetched.
|
|
125
|
-
*/
|
|
126
|
-
declare function isPublicHostname(hostname: string): boolean;
|
|
127
|
-
/** Split `local@domain` (NIP-05; a bare domain means `_@domain`), lowercased, or `undefined`. */
|
|
128
|
-
declare function splitNip05(identifier: string): {
|
|
129
|
-
local: string;
|
|
130
|
-
domain: string;
|
|
131
|
-
} | undefined;
|
|
132
|
-
/** The store (under `local`) and the owner (under `owner`) a `nostr.json` names. */
|
|
133
|
-
declare function readNostrJson(document: unknown, local: string): Pick<DomainKeys, 'storePubkey' | 'ownerPubkey'>;
|
|
134
|
-
/** `v=elisym1; owner=npub1...; store=npub1...` - the DNS record for sites that cannot serve `/.well-known`. */
|
|
135
|
-
declare function readElisymTxt(record: string): Pick<DomainKeys, 'storePubkey' | 'ownerPubkey'>;
|
|
136
|
-
interface ResolveDomainOptions {
|
|
137
|
-
/**
|
|
138
|
-
* Defaults to the global `fetch`. A SERVER (resolver, merchant node) must pass
|
|
139
|
-
* a fetch that refuses private addresses: the domain comes from a store's
|
|
140
|
-
* profile, and an unguarded fetch is an SSRF.
|
|
141
|
-
*/
|
|
142
|
-
fetch?: FetchLike;
|
|
143
|
-
timeoutMs?: number;
|
|
144
|
-
dohEndpoint?: string;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* The keys `nip05` vouches for, from `/.well-known/nostr.json` and then from the
|
|
148
|
-
* `_elisym` TXT record. `undefined` when the domain answers neither - which is
|
|
149
|
-
* not the same as vouching for OTHER keys, and the caller keeps the two apart.
|
|
150
|
-
*/
|
|
151
|
-
declare function resolveDomainKeys(nip05: string, options?: ResolveDomainOptions): Promise<DomainKeys | undefined>;
|
|
152
|
-
|
|
153
|
-
/** One payout address for one asset, as the owner published it. */
|
|
154
|
-
interface PayoutTarget {
|
|
155
|
-
caip19: Caip19;
|
|
156
|
-
/** Canonical spelling (lowercase on EVM). */
|
|
157
|
-
address: string;
|
|
158
|
-
/** The wallet signed the proof message for this owner and asset, and it checks out. */
|
|
159
|
-
walletSigned: boolean;
|
|
160
|
-
}
|
|
161
|
-
interface PaytoInput {
|
|
162
|
-
/** NIP-A3 `payto` entries, e.g. `{ type: 'solana', authority: '<address>' }`. */
|
|
163
|
-
payto?: readonly {
|
|
164
|
-
type: string;
|
|
165
|
-
authority: string;
|
|
166
|
-
}[];
|
|
167
|
-
accept: readonly {
|
|
168
|
-
caip19: string;
|
|
169
|
-
address: string;
|
|
170
|
-
signature?: string;
|
|
171
|
-
}[];
|
|
172
|
-
/**
|
|
173
|
-
* The owner key that will sign the event. Required with any wallet signature:
|
|
174
|
-
* a proof made for another owner or asset is checked here, since every reader
|
|
175
|
-
* would drop that address.
|
|
176
|
-
*/
|
|
177
|
-
ownerPubkey?: string;
|
|
178
|
-
createdAt?: number;
|
|
179
|
-
}
|
|
180
|
-
/** Build the owner's kind 10133 event. The caller signs it with the OWNER key. */
|
|
181
|
-
declare function buildPaytoEvent(input: PaytoInput): EventTemplate;
|
|
182
|
-
interface ParsedPayto {
|
|
183
|
-
targets: PayoutTarget[];
|
|
184
|
-
/** `accept` entries dropped: an unknown asset, a malformed address, or a proof that fails. */
|
|
185
|
-
rejected: {
|
|
186
|
-
tag: readonly string[];
|
|
187
|
-
reason: 'unknown_asset' | 'bad_address' | 'bad_proof';
|
|
188
|
-
}[];
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* The payout targets an owner's 10133 declares, from its `accept` tags only.
|
|
192
|
-
*
|
|
193
|
-
* A bare NIP-A3 `payto` tag names no asset and no network environment, so it is
|
|
194
|
-
* shown to generic clients but never paid to by elisym: a payment always goes to
|
|
195
|
-
* an `accept` address for the exact CAIP-19 id. An `accept` tag whose wallet
|
|
196
|
-
* proof is present but wrong is DROPPED, not downgraded - a wrong proof is
|
|
197
|
-
* evidence of a mistake or of tampering, and neither is an address to pay.
|
|
198
|
-
*
|
|
199
|
-
* The caller has already checked the event's signature and that its author is
|
|
200
|
-
* the owner.
|
|
201
|
-
*/
|
|
202
|
-
declare function parsePayto(event: Pick<NostrEvent, 'pubkey' | 'tags'>): ParsedPayto;
|
|
203
|
-
|
|
204
32
|
type StoreAuthMode = 'self-host' | 'hosted' | 'revoked';
|
|
205
33
|
interface StoreAuthInput {
|
|
206
34
|
storePubkey: string;
|
|
@@ -235,254 +63,46 @@ type StoreAuthState = {
|
|
|
235
63
|
*/
|
|
236
64
|
declare function readStoreAuth(event: Pick<NostrEvent, 'kind' | 'tags'>, storePubkey: string, now?: number): StoreAuthState;
|
|
237
65
|
|
|
238
|
-
interface
|
|
239
|
-
|
|
240
|
-
about?: string;
|
|
241
|
-
picture?: string;
|
|
242
|
-
website?: string;
|
|
243
|
-
nip05?: string;
|
|
244
|
-
/** The owner pubkey the store points at (tag `owner`). One half of the two-way link. */
|
|
245
|
-
ownerPubkey?: string;
|
|
246
|
-
}
|
|
247
|
-
interface StoreProfileInput extends Omit<StoreProfile, 'ownerPubkey'> {
|
|
248
|
-
ownerPubkey: string;
|
|
249
|
-
createdAt?: number;
|
|
250
|
-
}
|
|
251
|
-
/** Build the store's kind 0. The caller signs it with the STORE key. */
|
|
252
|
-
declare function buildStoreProfileEvent(input: StoreProfileInput): EventTemplate;
|
|
253
|
-
/**
|
|
254
|
-
* Read a store's kind 0, or `undefined` when its content is not a JSON object.
|
|
255
|
-
* A field of the wrong type or past its limit is dropped on its own: other
|
|
256
|
-
* clients edit the same kind 0, and one odd field is not a missing profile.
|
|
257
|
-
*/
|
|
258
|
-
declare function parseStoreProfile(event: Pick<NostrEvent, 'content' | 'tags'>): StoreProfile | undefined;
|
|
259
|
-
|
|
260
|
-
declare const FREQUENCIES: readonly ["hour", "day", "week", "month", "year"];
|
|
261
|
-
declare const ENDPOINT_TYPES: readonly ["x402", "mpp"];
|
|
262
|
-
type PriceFrequency = (typeof FREQUENCIES)[number];
|
|
263
|
-
type EndpointType = (typeof ENDPOINT_TYPES)[number];
|
|
264
|
-
interface ProductPrice {
|
|
265
|
-
/** Decimal string, exactly as published: never a float. */
|
|
266
|
-
amount: string;
|
|
267
|
-
/** ISO 4217, e.g. `USD`. */
|
|
268
|
-
currency: string;
|
|
269
|
-
/** Subscriptions only (NIP-99). */
|
|
270
|
-
frequency?: PriceFrequency;
|
|
271
|
-
}
|
|
272
|
-
interface Product {
|
|
66
|
+
interface OrderPaymentReferenceInput {
|
|
67
|
+
/** The store the order is placed with (its store key, hex). */
|
|
273
68
|
storePubkey: string;
|
|
274
|
-
|
|
275
|
-
title: string;
|
|
276
|
-
summary?: string;
|
|
277
|
-
description: string;
|
|
278
|
-
price: ProductPrice;
|
|
279
|
-
images: string[];
|
|
280
|
-
topics: string[];
|
|
281
|
-
/** Gamma Markets visibility; absent means on sale. */
|
|
282
|
-
visibility: string;
|
|
283
|
-
delivery?: DeliveryMethod;
|
|
284
|
-
/** Opted into the elisym aggregator (`["network", "elisym"]`). */
|
|
285
|
-
listedOnElisym: boolean;
|
|
286
|
-
/** HTTP 402 entry points for agents. Never trusted on their own: a challenge must pay a 10133 address. */
|
|
287
|
-
endpoints: {
|
|
288
|
-
type: EndpointType;
|
|
289
|
-
url: string;
|
|
290
|
-
}[];
|
|
291
|
-
/** CAIP-19 ids of the assets the store accepts. Addresses come from the owner's 10133 only. */
|
|
292
|
-
accept: string[];
|
|
293
|
-
createdAt: number;
|
|
294
|
-
}
|
|
295
|
-
declare const ProductInputSchema: z.ZodObject<{
|
|
296
|
-
d: z.ZodString;
|
|
297
|
-
title: z.ZodString;
|
|
298
|
-
summary: z.ZodOptional<z.ZodString>;
|
|
299
|
-
description: z.ZodString;
|
|
300
|
-
price: z.ZodObject<{
|
|
301
|
-
amount: z.ZodString;
|
|
302
|
-
currency: z.ZodString;
|
|
303
|
-
frequency: z.ZodOptional<z.ZodEnum<["hour", "day", "week", "month", "year"]>>;
|
|
304
|
-
}, "strip", z.ZodTypeAny, {
|
|
305
|
-
amount: string;
|
|
306
|
-
currency: string;
|
|
307
|
-
frequency?: "hour" | "day" | "week" | "month" | "year" | undefined;
|
|
308
|
-
}, {
|
|
309
|
-
amount: string;
|
|
310
|
-
currency: string;
|
|
311
|
-
frequency?: "hour" | "day" | "week" | "month" | "year" | undefined;
|
|
312
|
-
}>;
|
|
313
|
-
images: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
314
|
-
topics: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
315
|
-
visibility: z.ZodDefault<z.ZodString>;
|
|
316
|
-
delivery: z.ZodOptional<z.ZodEnum<["download", "license", "access", "webhook", "api"]>>;
|
|
317
|
-
listedOnElisym: z.ZodDefault<z.ZodBoolean>;
|
|
318
|
-
endpoints: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
319
|
-
type: z.ZodEnum<["x402", "mpp"]>;
|
|
320
|
-
url: z.ZodString;
|
|
321
|
-
}, "strip", z.ZodTypeAny, {
|
|
322
|
-
type: "x402" | "mpp";
|
|
323
|
-
url: string;
|
|
324
|
-
}, {
|
|
325
|
-
type: "x402" | "mpp";
|
|
326
|
-
url: string;
|
|
327
|
-
}>, "many">>;
|
|
328
|
-
accept: z.ZodArray<z.ZodString, "many">;
|
|
329
|
-
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
330
|
-
}, "strip", z.ZodTypeAny, {
|
|
331
|
-
accept: string[];
|
|
332
|
-
d: string;
|
|
333
|
-
title: string;
|
|
334
|
-
description: string;
|
|
335
|
-
price: {
|
|
336
|
-
amount: string;
|
|
337
|
-
currency: string;
|
|
338
|
-
frequency?: "hour" | "day" | "week" | "month" | "year" | undefined;
|
|
339
|
-
};
|
|
340
|
-
images: string[];
|
|
341
|
-
topics: string[];
|
|
342
|
-
visibility: string;
|
|
343
|
-
listedOnElisym: boolean;
|
|
344
|
-
endpoints: {
|
|
345
|
-
type: "x402" | "mpp";
|
|
346
|
-
url: string;
|
|
347
|
-
}[];
|
|
348
|
-
createdAt?: number | undefined;
|
|
349
|
-
summary?: string | undefined;
|
|
350
|
-
delivery?: "download" | "license" | "access" | "webhook" | "api" | undefined;
|
|
351
|
-
}, {
|
|
352
|
-
accept: string[];
|
|
353
|
-
d: string;
|
|
354
|
-
title: string;
|
|
355
|
-
description: string;
|
|
356
|
-
price: {
|
|
357
|
-
amount: string;
|
|
358
|
-
currency: string;
|
|
359
|
-
frequency?: "hour" | "day" | "week" | "month" | "year" | undefined;
|
|
360
|
-
};
|
|
361
|
-
createdAt?: number | undefined;
|
|
362
|
-
summary?: string | undefined;
|
|
363
|
-
images?: string[] | undefined;
|
|
364
|
-
topics?: string[] | undefined;
|
|
365
|
-
visibility?: string | undefined;
|
|
366
|
-
delivery?: "download" | "license" | "access" | "webhook" | "api" | undefined;
|
|
367
|
-
listedOnElisym?: boolean | undefined;
|
|
368
|
-
endpoints?: {
|
|
369
|
-
type: "x402" | "mpp";
|
|
370
|
-
url: string;
|
|
371
|
-
}[] | undefined;
|
|
372
|
-
}>;
|
|
373
|
-
type ProductInput = z.input<typeof ProductInputSchema>;
|
|
374
|
-
/** Build a kind 30402 listing. The caller signs it with the STORE key. */
|
|
375
|
-
declare function buildProductEvent(input: ProductInput): EventTemplate;
|
|
376
|
-
/**
|
|
377
|
-
* Read a kind 30402 listing, or `undefined` when it lacks what a sale needs (a
|
|
378
|
-
* `d`, a title, a price). Unknown extras are ignored, so a plain NIP-99 listing
|
|
379
|
-
* from another client still reads - it just accepts nothing elisym can pay.
|
|
380
|
-
* The caller has checked the signature.
|
|
381
|
-
*/
|
|
382
|
-
declare function parseProduct(event: Pick<NostrEvent, 'kind' | 'pubkey' | 'tags' | 'content' | 'created_at'>): Product | undefined;
|
|
383
|
-
declare function isPurchasable(product: Pick<Product, 'visibility'>): boolean;
|
|
384
|
-
/** `30402:<store>:<d>`, the address an order's `item` tag names. */
|
|
385
|
-
declare function productAddress(product: Pick<Product, 'storePubkey' | 'd'>): string;
|
|
386
|
-
declare function encodeProductNaddr(product: Pick<Product, 'storePubkey' | 'd'>, relays?: string[]): string;
|
|
387
|
-
interface ProductPointer {
|
|
388
|
-
storePubkey: string;
|
|
389
|
-
d: string;
|
|
390
|
-
relays: string[];
|
|
391
|
-
}
|
|
392
|
-
/** Decode a product `naddr`, or `undefined` when it is not one. */
|
|
393
|
-
declare function decodeProductNaddr(naddr: string): ProductPointer | undefined;
|
|
394
|
-
/**
|
|
395
|
-
* The price in `asset` subunits. Only a one-off `USD` price paid in a USD-pegged
|
|
396
|
-
* coin at 1:1 has one; any other pairing needs a quote (quoted mode), so it is
|
|
397
|
-
* refused here rather than converted at a guessed rate.
|
|
398
|
-
*/
|
|
399
|
-
declare function priceInSubunits(price: ProductPrice, asset: Asset): bigint;
|
|
400
|
-
|
|
401
|
-
type Tags = readonly (readonly string[])[];
|
|
402
|
-
|
|
403
|
-
interface OrderItem {
|
|
404
|
-
/** `30402:<store>:<d>` */
|
|
405
|
-
product: string;
|
|
406
|
-
quantity: number;
|
|
407
|
-
}
|
|
408
|
-
interface Money {
|
|
409
|
-
/** Decimal string, never a float. */
|
|
410
|
-
amount: string;
|
|
411
|
-
currency: string;
|
|
412
|
-
}
|
|
413
|
-
/** Buyer -> store: kind 16, type 1. */
|
|
414
|
-
interface OrderRequest {
|
|
415
|
-
type: 'order';
|
|
416
|
-
storePubkey: string;
|
|
417
|
-
orderId: string;
|
|
418
|
-
items: OrderItem[];
|
|
419
|
-
total: Money;
|
|
420
|
-
email?: string;
|
|
421
|
-
}
|
|
422
|
-
/** Store -> buyer: kind 16, type 2 (quoted mode). `payload` is opaque here: the payer parses it with pay-core. */
|
|
423
|
-
interface PaymentRequestMessage {
|
|
424
|
-
type: 'payment_request';
|
|
69
|
+
/** The buyer's key, hex: the authenticated sender of the order's gift wrap. */
|
|
425
70
|
buyerPubkey: string;
|
|
71
|
+
/** Random, at least 122 bits (a UUIDv4): it is what keeps the public reference private. */
|
|
426
72
|
orderId: string;
|
|
427
|
-
total: Money;
|
|
428
|
-
options: {
|
|
429
|
-
medium: string;
|
|
430
|
-
payload: string;
|
|
431
|
-
}[];
|
|
432
73
|
}
|
|
433
|
-
/**
|
|
434
|
-
interface
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
/** Store-supplied and unchecked: show it as text, or open it only as an `https:` link. */
|
|
440
|
-
delivery?: {
|
|
441
|
-
method: DeliveryMethod;
|
|
442
|
-
value: string;
|
|
443
|
-
};
|
|
444
|
-
/** The payment the store credited: amounts in subunits of the paid asset. */
|
|
445
|
-
receipt?: {
|
|
446
|
-
medium: string;
|
|
447
|
-
tx: string;
|
|
448
|
-
amount: string;
|
|
449
|
-
fee: string;
|
|
450
|
-
};
|
|
451
|
-
refund?: {
|
|
452
|
-
tx: string;
|
|
453
|
-
amount: string;
|
|
454
|
-
};
|
|
74
|
+
/** The one value that ties a payment to one order, spelled for each rail. */
|
|
75
|
+
interface OrderPaymentReference {
|
|
76
|
+
/** Solana: the reference key the transfer carries, base58. */
|
|
77
|
+
solana: string;
|
|
78
|
+
/** Tempo: the `transferWithMemo` memo, 32 bytes of lowercase hex. */
|
|
79
|
+
tempo: string;
|
|
455
80
|
}
|
|
456
81
|
/**
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
* the authenticated sender, and the caller matches it against the role (a status
|
|
480
|
-
* must come from the store, an order from the buyer who pays).
|
|
82
|
+
* The payment reference of an order, derived from the order itself.
|
|
83
|
+
*
|
|
84
|
+
* On chain, a reference (Solana) or a memo (Tempo) is the only thing that binds
|
|
85
|
+
* a transfer to one order, and a check by transaction hash does not ask when
|
|
86
|
+
* the transfer happened. A reference the buyer merely NAMES could be copied
|
|
87
|
+
* from any transfer the payout address ever received and credit a new order
|
|
88
|
+
* with it. Derived here - a hash over the store, the buyer and the order id -
|
|
89
|
+
* it is known to both sides without the merchant being online, and no one can
|
|
90
|
+
* find an existing transfer that carries it, nor steer another buyer's payment
|
|
91
|
+
* onto their own order: the buyer key is the authenticated sender of the
|
|
92
|
+
* order, not something the payer can claim.
|
|
93
|
+
*
|
|
94
|
+
* The checkout pays under it; the merchant derives it again from the order it
|
|
95
|
+
* received and refuses a payment under any other. The merchant still claims
|
|
96
|
+
* each payment once and refuses an order id a buyer has already used. It
|
|
97
|
+
* derives with the store key that opened the gift wrap and the wrap's
|
|
98
|
+
* authenticated sender - never with keys the order's tags merely name.
|
|
99
|
+
*
|
|
100
|
+
* The reference is public on chain and a function of public keys, so the
|
|
101
|
+
* order id is what keeps it private: draw it at random, at least 122 bits (a
|
|
102
|
+
* UUIDv4). A guessable id would let anyone check whether a known buyer key -
|
|
103
|
+
* an agent's is persistent - paid a known store.
|
|
481
104
|
*/
|
|
482
|
-
declare function
|
|
483
|
-
kind: number;
|
|
484
|
-
tags: Tags;
|
|
485
|
-
}): OrderMessage | undefined;
|
|
105
|
+
declare function deriveOrderPaymentReference(input: OrderPaymentReferenceInput): OrderPaymentReference;
|
|
486
106
|
|
|
487
107
|
interface WrappedOrderMessage {
|
|
488
108
|
/** Publish to the recipient's inbox relays (kind 10050). */
|
|
@@ -517,127 +137,4 @@ interface UnwrappedOrderMessage {
|
|
|
517
137
|
*/
|
|
518
138
|
declare function unwrapOrderMessage(wrap: NostrEvent, recipientSecretKey: Uint8Array): UnwrappedOrderMessage | undefined;
|
|
519
139
|
|
|
520
|
-
|
|
521
|
-
* A: the merchant's domain names both the store and the owner.
|
|
522
|
-
* B: a hosted name (e.g. `shop@elisym.shop`) - trust in the name registrar.
|
|
523
|
-
* C: keys only - the owner is pinned on first use.
|
|
524
|
-
*/
|
|
525
|
-
type TrustLevel = 'A' | 'B' | 'C';
|
|
526
|
-
type OfferRefusal = 'bad_pointer' | 'product_missing' | 'product_not_on_sale' | 'store_profile_missing' | 'owner_unknown' | 'owner_mismatch' | 'owner_pin_mismatch' | 'domain_mismatch' | 'store_auth_missing' | 'store_auth_revoked' | 'store_auth_expired' | 'origin_mismatch' | 'payto_missing' | 'no_payout_for_accepted_assets';
|
|
527
|
-
type OfferWarning =
|
|
528
|
-
/** The profile names a domain that did not vouch for both keys; trust fell back to level C. */
|
|
529
|
-
'domain_unverified'
|
|
530
|
-
/** The page embedding the widget is not on the merchant's domain. */
|
|
531
|
-
| 'origin_mismatch'
|
|
532
|
-
/** No domain to compare the page with (levels B and C). */
|
|
533
|
-
| 'origin_unverifiable'
|
|
534
|
-
/** The newest payout event is younger than the cool-down: the owner key may be in new hands. */
|
|
535
|
-
| 'payout_recently_changed'
|
|
536
|
-
/** A payout address is not among the `knownPayouts` of earlier purchases. */
|
|
537
|
-
| 'payout_changed'
|
|
538
|
-
/** A payout address carries no wallet proof. */
|
|
539
|
-
| 'payout_unsigned'
|
|
540
|
-
/**
|
|
541
|
-
* No `pinnedOwnerPubkey` (a first purchase): nothing but this bundle names the
|
|
542
|
-
* owner, and a stolen store key can name a new one - at level A through a
|
|
543
|
-
* domain of its own. Pin the owner after paying and pass it next time.
|
|
544
|
-
*/
|
|
545
|
-
| 'owner_unpinned';
|
|
546
|
-
interface VerifiedOffer {
|
|
547
|
-
level: TrustLevel;
|
|
548
|
-
/** Levels A and B: the domain that vouches for the store. */
|
|
549
|
-
domain?: string;
|
|
550
|
-
storePubkey: string;
|
|
551
|
-
ownerPubkey: string;
|
|
552
|
-
profile: StoreProfile;
|
|
553
|
-
product: Product;
|
|
554
|
-
/** Where a payment for this offer may go: the owner's 10133 addresses for the assets the product accepts. */
|
|
555
|
-
payouts: PayoutTarget[];
|
|
556
|
-
paytoCreatedAt: number;
|
|
557
|
-
warnings: OfferWarning[];
|
|
558
|
-
}
|
|
559
|
-
type OfferVerification = {
|
|
560
|
-
ok: true;
|
|
561
|
-
offer: VerifiedOffer;
|
|
562
|
-
} | {
|
|
563
|
-
ok: false;
|
|
564
|
-
refusal: OfferRefusal;
|
|
565
|
-
message: string;
|
|
566
|
-
};
|
|
567
|
-
/**
|
|
568
|
-
* The signed events one offer rests on, as relays (or a resolver) handed them
|
|
569
|
-
* over. Nothing here is trusted: every event is checked for its signature, its
|
|
570
|
-
* author and its kind before it counts, and extras are ignored.
|
|
571
|
-
*/
|
|
572
|
-
interface OfferBundle {
|
|
573
|
-
events: readonly NostrEvent[];
|
|
574
|
-
/**
|
|
575
|
-
* What the store's `nip05` domain vouches for: keys, `'unreachable'` when it
|
|
576
|
-
* answered nothing, or absent when the profile names no domain or it was not
|
|
577
|
-
* looked up. The answer is unsigned: take it from the client's own lookup,
|
|
578
|
-
* never from a resolver.
|
|
579
|
-
*/
|
|
580
|
-
domain?: DomainKeys | 'unreachable';
|
|
581
|
-
}
|
|
582
|
-
interface EvaluateOfferOptions {
|
|
583
|
-
now?: number;
|
|
584
|
-
/** The origin of the page embedding the checkout (from `postMessage`'s `event.origin`). */
|
|
585
|
-
pageOrigin?: string;
|
|
586
|
-
/** Refuse, rather than warn, when the page is not on the merchant's domain - or its origin is not given. */
|
|
587
|
-
strictOrigin?: boolean;
|
|
588
|
-
/** Domains that issue hosted names (level B), e.g. `['elisym.shop']`. */
|
|
589
|
-
hostedDomains?: readonly string[];
|
|
590
|
-
/** The owner pinned at the first purchase from this store (TOFU). A new owner then needs a re-pin. */
|
|
591
|
-
pinnedOwnerPubkey?: string;
|
|
592
|
-
cooldownSecs?: number;
|
|
593
|
-
/**
|
|
594
|
-
* When an index (resolver, relay) first saw the newest 10133. The cool-down
|
|
595
|
-
* counts from the later of this and the event's own `created_at`, which the
|
|
596
|
-
* signer picks and can back-date.
|
|
597
|
-
*/
|
|
598
|
-
paytoFirstSeenAt?: number;
|
|
599
|
-
/**
|
|
600
|
-
* Payout addresses paid at earlier purchases from this store (TOFU). A payout
|
|
601
|
-
* outside this set is flagged `payout_changed`, however old its event claims to be.
|
|
602
|
-
* Leave it out on a first purchase: an empty list flags every address.
|
|
603
|
-
*/
|
|
604
|
-
knownPayouts?: readonly {
|
|
605
|
-
caip19: string;
|
|
606
|
-
address: string;
|
|
607
|
-
}[];
|
|
608
|
-
}
|
|
609
|
-
/**
|
|
610
|
-
* Verify an offer from its signed events (spec section 3, steps 2-7 and 9's
|
|
611
|
-
* address set). Pure: no network, so the same code runs on relay results and
|
|
612
|
-
* on a resolver bundle, and a test feeds it exactly what it needs.
|
|
613
|
-
*
|
|
614
|
-
* The protocol fee (step 8) is not read here: the payer reads it from chain with
|
|
615
|
-
* `@elisym/pay-core` when it builds the payment.
|
|
616
|
-
*/
|
|
617
|
-
declare function evaluateOffer(pointer: {
|
|
618
|
-
storePubkey: string;
|
|
619
|
-
d: string;
|
|
620
|
-
}, bundle: OfferBundle, options?: EvaluateOfferOptions): OfferVerification;
|
|
621
|
-
/**
|
|
622
|
-
* Step 9: whether a recipient named by ANY other source - a payment request, an
|
|
623
|
-
* x402 `payTo`, an MPP challenge - is one of the owner's payout addresses for
|
|
624
|
-
* that asset. Anything else must not be paid.
|
|
625
|
-
*/
|
|
626
|
-
declare function isOfferPayout(offer: VerifiedOffer, caip19: string, recipient: string): boolean;
|
|
627
|
-
interface VerifyOfferDeps extends ResolveDomainOptions {
|
|
628
|
-
/**
|
|
629
|
-
* Query relays (or a resolver). The spec asks for at least two relays so one
|
|
630
|
-
* cannot hide the newest payout event; that is this function's job, and its
|
|
631
|
-
* results are all checked again here.
|
|
632
|
-
*/
|
|
633
|
-
fetchEvents: (filters: Filter[]) => Promise<NostrEvent[]>;
|
|
634
|
-
/**
|
|
635
|
-
* Replace the domain lookup. It must be the client's OWN nostr.json / DoH
|
|
636
|
-
* lookup: the answer is unsigned, so a resolver's copy is not evidence.
|
|
637
|
-
*/
|
|
638
|
-
resolveDomain?: (nip05: string) => Promise<DomainKeys | undefined>;
|
|
639
|
-
}
|
|
640
|
-
/** Collect an offer's events from relays and verify it (spec section 3). */
|
|
641
|
-
declare function verifyOffer(naddr: string, deps: VerifyOfferDeps, options?: EvaluateOfferOptions): Promise<OfferVerification>;
|
|
642
|
-
|
|
643
|
-
export { type Caip19, DELIVERY_METHODS, type DeliveryMethod, type DomainKeys, ELISYM_NETWORK_TAG, type EndpointType, type EvaluateOfferOptions, type FetchLike, KIND_DELETION, KIND_GIFT_WRAP, KIND_INBOX_RELAYS, KIND_ORDER_MESSAGE, KIND_PAYMENT_RECEIPT, KIND_PAYTO, KIND_PRODUCT, KIND_SEAL, KIND_STORE_AUTH, KIND_STORE_PROFILE, LIMITS, MAX_FUTURE_SKEW_SECS, type Money, ORDER_STATUSES, type OfferBundle, type OfferRefusal, type OfferVerification, type OfferWarning, type OrderItem, type OrderMessage, type OrderRequest, type OrderStatus, type OrderStatusMessage, PAYOUT_COOLDOWN_SECS, PAYTO_PROOF_PREFIX, PURCHASABLE_VISIBILITIES, type ParsedPayto, type PaymentReceipt, type PaymentRequestMessage, type PayoutTarget, type PaytoInput, type PriceFrequency, type Product, type ProductInput, type ProductPointer, type ProductPrice, type ResolveDomainOptions, type StoreAuthInput, type StoreAuthMode, type StoreAuthState, type StoreProfile, type StoreProfileInput, type TrustLevel, type UnwrappedOrderMessage, type VerifiedOffer, type VerifyOfferDeps, type WrappedOrderMessage, buildOrderMessage, buildPaytoEvent, buildProductEvent, buildStoreAuthEvent, buildStoreProfileEvent, buildStoreRevocationEvent, canonicalPayoutAddress, decodeProductNaddr, eip191Hash, encodeProductNaddr, evaluateOffer, hasValidEvmChecksum, isOfferPayout, isPublicHostname, isPurchasable, parseCaip19, parseOrderMessage, parsePayto, parseProduct, parseStoreProfile, paytoProofMessage, priceInSubunits, productAddress, readElisymTxt, readNostrJson, readStoreAuth, resolveDomainKeys, splitNip05, storeAuthAddress, unwrapOrderMessage, verifyOffer, verifyPaytoProof, wrapOrderMessage };
|
|
140
|
+
export { OrderMessage, type OrderPaymentReference, type OrderPaymentReferenceInput, type StoreAuthInput, type StoreAuthMode, type StoreAuthState, type UnwrappedOrderMessage, type WrappedOrderMessage, buildStoreAuthEvent, buildStoreRevocationEvent, deriveOrderPaymentReference, eip191Hash, paytoProofMessage, readStoreAuth, storeAuthAddress, unwrapOrderMessage, verifyPaytoProof, wrapOrderMessage };
|