@chaindaddy/js 0.3.3 → 0.3.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.
- package/dist/api.d.ts +197 -17
- package/dist/cd.js +2 -2
- package/dist/cd.js.sri +1 -1
- package/dist/checkout.d.ts +5 -1
- package/dist/checkout.js +1 -0
- package/dist/index.js +2 -1
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -987,16 +987,18 @@ export interface paths {
|
|
|
987
987
|
* goes are the item's own, exactly as when it is bought on chaindaddy.io: a session changes none of them.
|
|
988
988
|
*
|
|
989
989
|
* `successUrl` and `cancelUrl` must be `https` pages on one of the coin's verified sites, or a subdomain of
|
|
990
|
-
* one (400 `RETURN_URL_NOT_VERIFIED`, which lists the sites that pass).
|
|
991
|
-
*
|
|
990
|
+
* one (400 `RETURN_URL_NOT_VERIFIED`, which lists the sites that pass). A test store's key
|
|
991
|
+
* (`cd_iap_test_…`) may also use `http://localhost` or `http://127.0.0.1`, on any port: test mode works on
|
|
992
|
+
* localhost, live needs a verified site. The wallet that opened the store must have signed the Seller
|
|
993
|
+
* Terms (403 `SELLER_TERMS_REQUIRED`).
|
|
992
994
|
*
|
|
993
995
|
* An item of an app installed on the coin's page (its `sku` starts with `app.`) is sold through a session
|
|
994
996
|
* only when the app's developer has allowed that item to be sold outside the app; otherwise the call answers
|
|
995
997
|
* 409 `APP_ITEM_NOT_SOLD_HERE`, with a `reason`. The sale pays the same wallets as inside the app: the page,
|
|
996
998
|
* the fee and the developer's share. Such a session takes at most the app's per-order quantity.
|
|
997
999
|
*
|
|
998
|
-
*
|
|
999
|
-
* and the header `Idempotent-Replayed: true`.
|
|
1000
|
+
* An `Idempotency-Key` is required. A retry of the same request returns the session it opened, with
|
|
1001
|
+
* status 200 and the header `Idempotent-Replayed: true`.
|
|
1000
1002
|
*
|
|
1001
1003
|
* Learn that the session was paid from the `iap.order.confirmed` webhook (its payload carries
|
|
1002
1004
|
* `checkoutSessionId`), or by reading the session. Never from the buyer arriving on `successUrl`.
|
|
@@ -1054,12 +1056,13 @@ export interface paths {
|
|
|
1054
1056
|
* needs no credential (the session id in the buyer's link is enough) and never carries the session's
|
|
1055
1057
|
* `metadata` or `clientReferenceId`. The answer is never cached.
|
|
1056
1058
|
*
|
|
1057
|
-
* When the item belongs to an app installed on the coin's page, `sku` names the app (`appId`) and
|
|
1058
|
-
*
|
|
1059
|
-
* `metadata`.
|
|
1059
|
+
* When the item belongs to an app installed on the coin's page, `sku` names the app (`appId`) and the
|
|
1060
|
+
* share of the price its developer gets (`appBps`, basis points of the price after the fee), and carries
|
|
1061
|
+
* nothing else of the app's: no `appTermsVersion`, `appItemKey` or `appRole`, and an empty `metadata`.
|
|
1060
1062
|
*
|
|
1061
1063
|
* Pass `origin` to learn whether a page on that origin may open this checkout in a popup
|
|
1062
|
-
* (`openerAllowed`): it must be `https` on one of the coin's verified sites.
|
|
1064
|
+
* (`openerAllowed`): it must be `https` on one of the coin's verified sites. A test store's session
|
|
1065
|
+
* (`livemode: false`) may also be opened from `http://localhost` or `http://127.0.0.1`, on any port.
|
|
1063
1066
|
*
|
|
1064
1067
|
* `returnAllowed` says whether the buyer may still be sent to `successUrl` and `cancelUrl`. It is checked
|
|
1065
1068
|
* again on every read, so a coin whose site stopped being verified after the session was opened no longer
|
|
@@ -1074,6 +1077,48 @@ export interface paths {
|
|
|
1074
1077
|
patch?: never;
|
|
1075
1078
|
trace?: never;
|
|
1076
1079
|
};
|
|
1080
|
+
"/api/v2/iap/checkout/sessions/{sessionId}/test-pay": {
|
|
1081
|
+
parameters: {
|
|
1082
|
+
query?: never;
|
|
1083
|
+
header?: never;
|
|
1084
|
+
path: {
|
|
1085
|
+
/** @description The checkout session's id, `cs_` followed by 48 hex characters */
|
|
1086
|
+
sessionId: components["parameters"]["IapCheckoutSessionId"];
|
|
1087
|
+
};
|
|
1088
|
+
cookie?: never;
|
|
1089
|
+
};
|
|
1090
|
+
get?: never;
|
|
1091
|
+
put?: never;
|
|
1092
|
+
/**
|
|
1093
|
+
* Complete a test checkout session
|
|
1094
|
+
* @description Completes a test store's checkout session from your own server or terminal, with no buyer signed in
|
|
1095
|
+
* and no wallet: the whole loop (open a session, pay it, get the webhook, read it `complete`) with
|
|
1096
|
+
* nothing but a test store's key. It makes the session's order for `wallet` and pays it as
|
|
1097
|
+
* `POST /api/v2/iap/orders/{orderId}/test-pay` does: the items are granted, the receipt is signed and the
|
|
1098
|
+
* test store's webhook gets `iap.order.confirmed` with `checkoutSessionId` and `"livemode": false`. No
|
|
1099
|
+
* chain is read or written and no money moves. A pay page left open on the session notices within a
|
|
1100
|
+
* few seconds and takes the buyer back.
|
|
1101
|
+
*
|
|
1102
|
+
* Call it with a key of the session's test store (`cd_iap_test_…`, scope `orders:write`). `wallet` is the
|
|
1103
|
+
* wallet the test items go to: required unless the session names one, and then it must be that wallet
|
|
1104
|
+
* (403 `CHECKOUT_SESSION_WALLET`). The answer is the session as `GET` returns it: `status: complete`,
|
|
1105
|
+
* the order and its receipt.
|
|
1106
|
+
*
|
|
1107
|
+
* `Idempotency-Key` is required. A retry of the same request returns the same order, with the header
|
|
1108
|
+
* `Idempotent-Replayed: true`; the key used for a different session or wallet is a 422.
|
|
1109
|
+
*
|
|
1110
|
+
* Test stores only. A live store's session is only ever paid by the buyer on chaindaddy.io: a live
|
|
1111
|
+
* store's key gets 409 `LIVE_ORDER` and nothing is created. A key of any other store gets 404. An item
|
|
1112
|
+
* of an installed app cannot be bought with a store key (403 `SESSION_REQUIRED`); pay that session on
|
|
1113
|
+
* its page. Guide: https://docs.chaindaddy.io/developer/take-payments-on-your-site#test-mode
|
|
1114
|
+
*/
|
|
1115
|
+
post: operations["testPayIapCheckoutSession"];
|
|
1116
|
+
delete?: never;
|
|
1117
|
+
options?: never;
|
|
1118
|
+
head?: never;
|
|
1119
|
+
patch?: never;
|
|
1120
|
+
trace?: never;
|
|
1121
|
+
};
|
|
1077
1122
|
"/api/v2/webhooks": {
|
|
1078
1123
|
parameters: {
|
|
1079
1124
|
query?: never;
|
|
@@ -2228,7 +2273,8 @@ export interface components {
|
|
|
2228
2273
|
/** @description Whether a page on the `origin` passed may open this checkout in a popup. False when no `origin` is passed */
|
|
2229
2274
|
openerAllowed?: boolean;
|
|
2230
2275
|
/**
|
|
2231
|
-
* @description Whether `successUrl` and `cancelUrl` are both still on the coin's verified sites, as of this read
|
|
2276
|
+
* @description Whether `successUrl` and `cancelUrl` are both still on the coin's verified sites, as of this read
|
|
2277
|
+
* (for a test store's session, a URL on `http://localhost` or `http://127.0.0.1` also counts).
|
|
2232
2278
|
* When false the buyer is not sent to either
|
|
2233
2279
|
*/
|
|
2234
2280
|
returnAllowed?: boolean;
|
|
@@ -2805,7 +2851,7 @@ export interface components {
|
|
|
2805
2851
|
"application/json": components["schemas"]["IapError"];
|
|
2806
2852
|
};
|
|
2807
2853
|
};
|
|
2808
|
-
/** @description
|
|
2854
|
+
/** @description `AUTHENTICATION_REQUIRED`: no credential at all. Sign in, or send the credential the operation names */
|
|
2809
2855
|
IapUnauthorized: {
|
|
2810
2856
|
headers: {
|
|
2811
2857
|
[name: string]: unknown;
|
|
@@ -2813,8 +2859,8 @@ export interface components {
|
|
|
2813
2859
|
content: {
|
|
2814
2860
|
/**
|
|
2815
2861
|
* @example {
|
|
2816
|
-
* "error": "
|
|
2817
|
-
* "code": "
|
|
2862
|
+
* "error": "authentication required",
|
|
2863
|
+
* "code": "AUTHENTICATION_REQUIRED"
|
|
2818
2864
|
* }
|
|
2819
2865
|
*/
|
|
2820
2866
|
"application/json": components["schemas"]["IapError"];
|
|
@@ -4873,7 +4919,8 @@ export interface operations {
|
|
|
4873
4919
|
appAccountToken?: string;
|
|
4874
4920
|
/**
|
|
4875
4921
|
* @description The checkout session the buyer is paying. A buyer's session only: a store key gets 403
|
|
4876
|
-
* `SESSION_REQUIRED
|
|
4922
|
+
* `SESSION_REQUIRED` (a test store's key completes its own test session with
|
|
4923
|
+
* `POST /api/v2/iap/checkout/sessions/{sessionId}/test-pay` instead). 409 `CHECKOUT_SESSION_EXPIRED` or `CHECKOUT_SESSION_COMPLETE` when the
|
|
4877
4924
|
* session can no longer be paid; 403 `CHECKOUT_SESSION_WALLET` when it names another wallet.
|
|
4878
4925
|
* A session takes one buyer at a time: 409 `CHECKOUT_SESSION_IN_USE` while another wallet has
|
|
4879
4926
|
* an order for it that can still be paid, or is paid and being confirmed
|
|
@@ -5106,7 +5153,9 @@ export interface operations {
|
|
|
5106
5153
|
}[];
|
|
5107
5154
|
/**
|
|
5108
5155
|
* Format: uri
|
|
5109
|
-
* @description Where the buyer returns after paying. `https`, on one of the coin's verified sites
|
|
5156
|
+
* @description Where the buyer returns after paying. `https`, on one of the coin's verified sites or a
|
|
5157
|
+
* subdomain of one. With a test store's key it may also be `http://localhost` or
|
|
5158
|
+
* `http://127.0.0.1`, on any port
|
|
5110
5159
|
*/
|
|
5111
5160
|
successUrl: string;
|
|
5112
5161
|
/**
|
|
@@ -5154,8 +5203,10 @@ export interface operations {
|
|
|
5154
5203
|
};
|
|
5155
5204
|
};
|
|
5156
5205
|
/**
|
|
5157
|
-
* @description `INVALID_REQUEST`, `IDEMPOTENCY_KEY_REQUIRED`,
|
|
5158
|
-
*
|
|
5206
|
+
* @description `INVALID_REQUEST`, `IDEMPOTENCY_KEY_REQUIRED`, `IDEMPOTENCY_KEY_INVALID` (a key longer than 255
|
|
5207
|
+
* characters), or `RETURN_URL_NOT_VERIFIED`: a return URL is not an
|
|
5208
|
+
* `https` page on one of the coin's verified sites (nor, with a test store's key, `http://localhost` or
|
|
5209
|
+
* `http://127.0.0.1`). A live store's key is always refused a localhost URL
|
|
5159
5210
|
*/
|
|
5160
5211
|
400: {
|
|
5161
5212
|
headers: {
|
|
@@ -5289,7 +5340,7 @@ export interface operations {
|
|
|
5289
5340
|
getIapPublicCheckoutSession: {
|
|
5290
5341
|
parameters: {
|
|
5291
5342
|
query?: {
|
|
5292
|
-
/** @description The origin of the page that opened the checkout, e.g. `https://example.com` */
|
|
5343
|
+
/** @description The origin of the page that opened the checkout, e.g. `https://example.com` (or `http://localhost:3000` for a test store's session) */
|
|
5293
5344
|
origin?: string;
|
|
5294
5345
|
};
|
|
5295
5346
|
header?: never;
|
|
@@ -5324,6 +5375,135 @@ export interface operations {
|
|
|
5324
5375
|
};
|
|
5325
5376
|
};
|
|
5326
5377
|
};
|
|
5378
|
+
testPayIapCheckoutSession: {
|
|
5379
|
+
parameters: {
|
|
5380
|
+
query?: never;
|
|
5381
|
+
header: {
|
|
5382
|
+
/**
|
|
5383
|
+
* @description Required: a call without it answers 400 `IDEMPOTENCY_KEY_REQUIRED`. Send one value per attempt (a UUID,
|
|
5384
|
+
* or an id of your own such as `cart-8842-attempt-1`), up to 255 characters. Retrying with the same key
|
|
5385
|
+
* and the same request returns the first result and never sells, grants or consumes twice.
|
|
5386
|
+
*/
|
|
5387
|
+
"Idempotency-Key": components["parameters"]["IdempotencyKeyRequired"];
|
|
5388
|
+
};
|
|
5389
|
+
path: {
|
|
5390
|
+
/** @description The checkout session's id, `cs_` followed by 48 hex characters */
|
|
5391
|
+
sessionId: components["parameters"]["IapCheckoutSessionId"];
|
|
5392
|
+
};
|
|
5393
|
+
cookie?: never;
|
|
5394
|
+
};
|
|
5395
|
+
requestBody?: {
|
|
5396
|
+
content: {
|
|
5397
|
+
/**
|
|
5398
|
+
* @example {
|
|
5399
|
+
* "wallet": "0x00000000000000000000000000000000000000d4"
|
|
5400
|
+
* }
|
|
5401
|
+
*/
|
|
5402
|
+
"application/json": {
|
|
5403
|
+
/**
|
|
5404
|
+
* @description The wallet the test items go to: an address on the store's chain. Required unless the
|
|
5405
|
+
* session names a wallet; when it does, leave this out or send the same wallet
|
|
5406
|
+
*/
|
|
5407
|
+
wallet?: string;
|
|
5408
|
+
};
|
|
5409
|
+
};
|
|
5410
|
+
};
|
|
5411
|
+
responses: {
|
|
5412
|
+
/** @description The session, complete, with the order that paid it and its receipt */
|
|
5413
|
+
200: {
|
|
5414
|
+
headers: {
|
|
5415
|
+
/** @description Present, and `true`, on a retry of a request already made under this `Idempotency-Key` */
|
|
5416
|
+
"Idempotent-Replayed"?: "true";
|
|
5417
|
+
[name: string]: unknown;
|
|
5418
|
+
};
|
|
5419
|
+
content: {
|
|
5420
|
+
"application/json": components["schemas"]["IapCheckoutSession"];
|
|
5421
|
+
};
|
|
5422
|
+
};
|
|
5423
|
+
/**
|
|
5424
|
+
* @description `IDEMPOTENCY_KEY_REQUIRED`, or `INVALID_REQUEST`: no `wallet` and the session names none, a `wallet`
|
|
5425
|
+
* that is not an address on the store's chain, or a body that is not the JSON above
|
|
5426
|
+
*/
|
|
5427
|
+
400: {
|
|
5428
|
+
headers: {
|
|
5429
|
+
[name: string]: unknown;
|
|
5430
|
+
};
|
|
5431
|
+
content: {
|
|
5432
|
+
"application/json": components["schemas"]["IapError"];
|
|
5433
|
+
};
|
|
5434
|
+
};
|
|
5435
|
+
/**
|
|
5436
|
+
* @description `AUTHENTICATION_REQUIRED`: no credential at all; send the test store's key as
|
|
5437
|
+
* `Authorization: Bearer cd_iap_test_…`. `INVALID_STORE_KEY`: the key is unknown or revoked
|
|
5438
|
+
*/
|
|
5439
|
+
401: {
|
|
5440
|
+
headers: {
|
|
5441
|
+
[name: string]: unknown;
|
|
5442
|
+
};
|
|
5443
|
+
content: {
|
|
5444
|
+
"application/json": components["schemas"]["IapError"];
|
|
5445
|
+
};
|
|
5446
|
+
};
|
|
5447
|
+
/**
|
|
5448
|
+
* @description `STORE_KEY_REQUIRED`: called with a signed-in session instead of a store key. `SCOPE_REQUIRED`: the
|
|
5449
|
+
* key lacks `orders:write`. `CHECKOUT_SESSION_WALLET`: the session names another wallet.
|
|
5450
|
+
* `IAP_PLAN_REQUIRED` or `STORE_NOT_LIVE`: the store's plan lapsed or the store is paused.
|
|
5451
|
+
* `SESSION_REQUIRED`: the session's item belongs to an installed app
|
|
5452
|
+
*/
|
|
5453
|
+
403: {
|
|
5454
|
+
headers: {
|
|
5455
|
+
[name: string]: unknown;
|
|
5456
|
+
};
|
|
5457
|
+
content: {
|
|
5458
|
+
"application/json": components["schemas"]["IapError"];
|
|
5459
|
+
};
|
|
5460
|
+
};
|
|
5461
|
+
/**
|
|
5462
|
+
* @description `NOT_FOUND`: no such session, or it belongs to another store. `TEST_MODE_DISABLED`: test stores are
|
|
5463
|
+
* not available here. `CHECKOUT_SESSIONS_DISABLED`: checkout sessions are not switched on here
|
|
5464
|
+
*/
|
|
5465
|
+
404: {
|
|
5466
|
+
headers: {
|
|
5467
|
+
[name: string]: unknown;
|
|
5468
|
+
};
|
|
5469
|
+
content: {
|
|
5470
|
+
"application/json": components["schemas"]["IapError"];
|
|
5471
|
+
};
|
|
5472
|
+
};
|
|
5473
|
+
/**
|
|
5474
|
+
* @description `LIVE_ORDER`: the session belongs to a live store. `CHECKOUT_SESSION_COMPLETE`: it is already paid.
|
|
5475
|
+
* `CHECKOUT_SESSION_EXPIRED`: it expired; open a new one. `CHECKOUT_SESSION_IN_USE`: another wallet
|
|
5476
|
+
* has an unpaid order for it; use that wallet, or wait a few minutes past that order's deadline.
|
|
5477
|
+
* `ORDER_EXPIRED`: the order this `Idempotency-Key` made has lapsed; use a new key
|
|
5478
|
+
*/
|
|
5479
|
+
409: {
|
|
5480
|
+
headers: {
|
|
5481
|
+
[name: string]: unknown;
|
|
5482
|
+
};
|
|
5483
|
+
content: {
|
|
5484
|
+
/**
|
|
5485
|
+
* @example {
|
|
5486
|
+
* "error": "this is a live checkout session: it is paid by the buyer on chaindaddy.io, and test-pay pays a test store's sessions only",
|
|
5487
|
+
* "code": "LIVE_ORDER"
|
|
5488
|
+
* }
|
|
5489
|
+
*/
|
|
5490
|
+
"application/json": components["schemas"]["IapError"];
|
|
5491
|
+
};
|
|
5492
|
+
};
|
|
5493
|
+
/**
|
|
5494
|
+
* @description `IDEMPOTENCY_KEY_REUSED`: this `Idempotency-Key` already made an order for a different session or
|
|
5495
|
+
* wallet. Nothing is returned or created; use a new key
|
|
5496
|
+
*/
|
|
5497
|
+
422: {
|
|
5498
|
+
headers: {
|
|
5499
|
+
[name: string]: unknown;
|
|
5500
|
+
};
|
|
5501
|
+
content: {
|
|
5502
|
+
"application/json": components["schemas"]["IapError"];
|
|
5503
|
+
};
|
|
5504
|
+
};
|
|
5505
|
+
};
|
|
5506
|
+
};
|
|
5327
5507
|
listWebhooks: {
|
|
5328
5508
|
parameters: {
|
|
5329
5509
|
query?: never;
|
package/dist/cd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";(()=>{var R="0.3.
|
|
1
|
+
"use strict";(()=>{var R="0.3.4";function C(t){let e="";for(let i of t)e+=String.fromCharCode(i);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function w(){return C(crypto.getRandomValues(new Uint8Array(32)))}function T(t,e,i,o,r){let u=n=>{if(n&&typeof n=="object"&&n.type===t)try{i(n)}catch{}},l=n=>{n.origin===e&&(!r||n.source===r)&&u(n.data)};window.addEventListener("message",l);let a=null;if(o&&typeof BroadcastChannel=="function"&&e===location.origin)try{a=new BroadcastChannel(o),a.onmessage=n=>u(n.data)}catch{a=null}return()=>{window.removeEventListener("message",l),a?.close()}}var y={get(t){try{return sessionStorage.getItem(t)}catch{return null}},set(t,e){try{sessionStorage.setItem(t,e)}catch{}},remove(t){try{sessionStorage.removeItem(t)}catch{}}};var F="https://api.chaindaddy.io",G={"https://api.chaindaddy.io":"https://chaindaddy.io/_oauth/authorize","https://staging-api.chaindaddy.io":"https://staging.chaindaddy.io/_oauth/authorize"},b="cd-signin",U="cd:signin",v="cd.signin",_=300;async function K(t){let e=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t));return C(new Uint8Array(e))}function W(t="openid"){let e=t.split(/\s+/).filter(Boolean);return(e.includes("openid")?e:["openid",...e]).join(" ")}async function Y(t,e,i){let o=new URLSearchParams({response_type:"code",client_id:e.clientId,redirect_uri:e.redirectUri,scope:W(t.scope),state:e.state,nonce:e.nonce,code_challenge:await K(e.verifier),code_challenge_method:"S256"});return t.claims&&o.set("claims",typeof t.claims=="string"?t.claims:JSON.stringify(t.claims)),`${i}?${o}`}function A(t,e){return{code:e,codeVerifier:t.verifier,state:t.state,nonce:t.nonce,issuer:t.issuer,clientId:t.clientId,redirectUri:t.redirectUri}}var m;function k(t){let e=(t.issuer??F).replace(/\/$/,""),i=t.authorizeUrl??G[e];if(!i)return Promise.reject(new Error("authorizeUrl is required for this issuer"));if(!t.clientId||!t.redirectUri)return Promise.reject(new Error("clientId and redirectUri are required"));if(m&&!m.popup.closed)return m.popup.focus(),m.waiting;let o={state:w(),nonce:w(),verifier:w(),issuer:e,clientId:t.clientId,redirectUri:t.redirectUri};y.set(v,JSON.stringify(o));let r=window.open("",b,"popup,width=480,height=720"),u=(async()=>{let l=await Y(t,o,i);if(!r)return location.assign(l),null;r.location.href=l;let a=new URL(t.redirectUri,location.href).origin;return new Promise((n,c)=>{let s,d=()=>{g(),clearInterval(h),clearTimeout(s)},g=T(U,a,p=>{p.state===o.state&&(d(),y.remove(v),typeof p.error=="string"&&p.error?c(new Error(p.error)):p.iss!==e?c(new Error("the answer came from another issuer")):typeof p.code!="string"||!p.code?c(new Error("the answer carried no code")):n(A(o,p.code)))},b,r),h=setInterval(()=>{r.closed&&(clearInterval(h),s=setTimeout(()=>{d(),c(new Error("closed"))},_))},_);t.signal?.addEventListener("abort",()=>{d(),c(new Error("aborted"))})})})();if(r){m={popup:r,waiting:u};let l=()=>{m&&m.popup===r&&(m=void 0)};u.then(l,l)}return u}async function L(){let t=new URLSearchParams(location.search),e={type:U,code:t.get("code"),state:t.get("state"),iss:t.get("iss"),error:t.get("error")};if(window.name===b){try{window.opener?.postMessage(e,location.origin)}catch{}try{let r=new BroadcastChannel(b);r.postMessage(e),r.close()}catch{}return window.close(),null}let i=y.get(v);y.remove(v);let o=i?JSON.parse(i):null;if(!o||e.state!==o.state)throw new Error("the sign-in state does not match: start again");if(e.error)throw new Error(e.error);if(e.iss!==o.issuer)throw new Error("the answer came from another issuer");if(!e.code)throw new Error("the answer carried no code");return A(o,e.code)}async function M(t){let e=await fetch(`${t.issuer}/api/v2/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:t.code,redirect_uri:t.redirectUri,client_id:t.clientId,code_verifier:t.codeVerifier})}),i=await e.json();if(!e.ok)throw new Error(`${i.error??e.status}: ${i.error_description??""}`.trim());return i}var J='<svg viewBox="0 0 24 24" fill="#FFD700" width="20" height="20" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><path d="M5 16L3 5l5.5 5L12 4l3.5 6L21 5l-2 11H5z" stroke="#B8860B" stroke-width="0.5"/><path d="M5 18h14v2H5v-2z" stroke="#B8860B" stroke-width="0.5"/></svg>',X=`
|
|
2
2
|
:host { display: inline-block; }
|
|
3
3
|
button { display: inline-flex; align-items: center; justify-content: center; gap: 10px; box-sizing: border-box;
|
|
4
4
|
min-height: 40px; padding: 0 16px; border-radius: 10px; font: 600 15px/1 system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
@@ -19,4 +19,4 @@ button { box-sizing: border-box; min-height: 40px; padding: 0 16px; border-radiu
|
|
|
19
19
|
font: 600 15px/1 system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
20
20
|
border: 1px solid var(--cd-border, #d0d5dd); background: var(--cd-accent, #f59e0b); color: var(--cd-text, #101828); }
|
|
21
21
|
button:focus-visible { outline: 2px solid var(--cd-accent, #f59e0b); outline-offset: 2px; }
|
|
22
|
-
`;function D(t={}){try{if(typeof customElements>"u"||typeof HTMLElement>"u")return;let e=t.origin===E?E:O;class i extends HTMLElement{constructor(){super(...arguments);this.kind="app";this.frame=null;this.onMessage=n=>this.receive(n)}connectedCallback(){try{this.shadowRoot||this.attachShadow({mode:"open"}),this.mount()}catch{this.unavailable()}}disconnectedCallback(){try{window.removeEventListener("message",this.onMessage),clearTimeout(this.timer),this.watch?.disconnect()}catch{}}attributeChangedCallback(){try{this.isConnected&&this.shadowRoot&&this.mount()}catch{this.unavailable()}}src(){let n=(this.getAttribute("crown")??"").trim(),c=(this.getAttribute("chain")??"").trim(),s=(this.getAttribute("app")??"").trim();if(!/^[0-9]{1,18}$/.test(n)||!c||this.kind==="app"&&!s)return null;let d=new URLSearchParams({crown:n,chain:c});return this.kind==="app"?d.set("app",s):d.set("kind","coin"),d.set("mode",this.mode()),d.set("v","1"),`${e}/v1/frame?${d.toString()}`}mode(){let n=this.getAttribute("mode");if(n==="light"||n==="dark")return n;try{return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}catch{return"light"}}mount(){let n=this.shadowRoot;window.removeEventListener("message",this.onMessage),clearTimeout(this.timer),this.watch?.disconnect(),this.removeAttribute("data-cd-ready"),this.removeAttribute("data-cd-unavailable");let c=this.src();if(!c){n.innerHTML="<slot></slot>",this.frame=null;return}n.innerHTML=`<style>${et}</style><slot></slot>`;let s=document.createElement("iframe");s.setAttribute("referrerpolicy","strict-origin-when-cross-origin"),s.setAttribute("allow","clipboard-write; fullscreen"),s.setAttribute("title",this.kind==="coin"?"Coin on Chain Daddy":"App on Chain Daddy"),n.appendChild(s),this.frame=s,window.addEventListener("message",this.onMessage);let d=()=>{s.src=c,this.timer=setTimeout(()=>{this.hasAttribute("data-cd-ready")||this.unavailable()},8e3)};if(typeof IntersectionObserver>"u")return d();this.watch=new IntersectionObserver(g=>{g.some(h=>h.isIntersecting)&&(this.watch?.disconnect(),d())},{rootMargin:Q}),this.watch.observe(this)}why(){try{let n=new URL(this.frame.src).searchParams,c=n.get("app");n.delete("mode"),n.delete("v"),fetch(`https://${e===E?"staging-api":"api"}.chaindaddy.io/api/v2/embed/status?${n}`,{credentials:"omit"}).then(s=>s.json()).then(s=>{let d=s.embeddable?s.interactive?"not a verified site of the coin":"not https, or the app did not start":s.reason;console.info(`[Chain Daddy] cd-${this.kind} ${c??""} cannot show here: ${d}. ${Z}`)}).catch(()=>{})}catch{}}receive(n){try{if(n.origin!==e||!this.frame||!n.source||n.source!==this.frame.contentWindow)return;let c=n.data;if(!c||typeof c!="object")return;if(c.type==="cd:ready")clearTimeout(this.timer),this.removeAttribute("data-cd-unavailable"),this.setAttribute("data-cd-ready",""),this.sendTheme(),this.dispatchEvent(new CustomEvent("cd:ready"));else if(c.type==="cd:resize"){let s=Number(c.height);Number.isFinite(s)&&(this.frame.style.height=`${Math.max(1,Math.min(4e3,Math.ceil(s)))}px`)}else c.type==="cd:unavailable"&&this.unavailable()}catch{}}sendTheme(){let n={},c=getComputedStyle(this);for(let s of tt){let d=c.getPropertyValue(s).trim();d&&(n[s]=d)}this.frame?.contentWindow?.postMessage({type:"cd:theme",tokens:n},e)}unavailable(){try{if(clearTimeout(this.timer),this.removeAttribute("data-cd-ready"),this.hasAttribute("data-cd-unavailable"))return;this.setAttribute("data-cd-unavailable",""),this.dispatchEvent(new CustomEvent("cd:unavailable")),this.why()}catch{}}}i.observedAttributes=["crown","chain","app","mode"];class o extends i{}class r extends i{constructor(){super(...arguments);this.kind="coin"}}class u extends HTMLElement{connectedCallback(){try{let a=this.querySelector("a[href]"),n=a?new URL(a.getAttribute("href")??"",document.baseURI):null;if(!n||n.protocol!=="https:")return;let c=this.shadowRoot??this.attachShadow({mode:"open"});c.innerHTML=`<style>${nt}</style><button type="button" part="button"></button>`;let s=c.querySelector("button");s.textContent=(a.textContent??"").trim()||"Buy on Chain Daddy",s.addEventListener("click",()=>{try{window.open(n.toString(),"cd-buy","popup,width=460,height=760")||window.location.assign(n.toString())}catch{}})}catch{}}}for(let[l,a]of[["cd-app",o],["cd-coin",r],["cd-buy",u]])customElements.get(l)||customElements.define(l,a)}catch{}}var it=["https://chaindaddy.io","https://staging.chaindaddy.io"],H=()=>"cd-checkout-"+w(),N="popup,width=480,height=820",B=300,rt=7;function I(t){if(typeof t!="string")return null;let e;try{e=new URL(t)}catch{return null}let i=/^\/_pay\/([\w-]+)$/.exec(e.pathname);return i&&it.includes(e.origin)&&!e.username&&!e.password?{href:e.origin+e.pathname,origin:e.origin,id:i[1]}:null}function x(t,e){if(typeof t!="string")return null;let i;try{i=new URL(t,location.href)}catch{return null}if(!/^https?:$/.test(i.protocol)||i.username||i.password)return null;let o=u=>{let l=u.split("=")[0];try{return decodeURIComponent(l.replace(/\+/g," "))}catch{return l}},r=i.search.slice(1).split("&").filter(u=>u&&o(u)!=="session_id");return r.push("session_id="+encodeURIComponent(e)),i.origin+i.pathname+"?"+r.join("&")+i.hash}var f;function z(t,e,i){return new Promise(o=>{let r=!1,u=0,l,a=d=>{clearInterval(s),clearTimeout(l),window.removeEventListener("message",n),i&&d.status==="completed"&&location.assign(i),o(d)},n=d=>{if(d.origin!==e.origin||d.source!==t)return;let g=d.data;if(!g||typeof g!="object")return;g.type==="cd:checkout.ready"&&(r=!0);let h=g.session;if(!(!h||typeof h!="object"||h.id!==e.id)){if(g.type==="cd:checkout.cancelled")a({status:"cancelled",session:{id:e.id}});else if(g.type==="cd:checkout.completed"&&(h.status==="complete"||h.status==="paid")){let p={id:e.id,status:h.status};typeof h.orderId=="string"&&/^[\w-]{1,128}$/.test(h.orderId)&&(p.orderId=h.orderId),a({status:"completed",session:p})}}},c=()=>{try{t.postMessage({type:"cd:checkout.hello"},e.origin)}catch{}},s=setInterval(()=>{t.closed?(clearInterval(s),l=setTimeout(()=>a({status:"closed"}),B)):(!r||++u%rt===0)&&c()},B);window.addEventListener("message",n),c()})}function S(t){let e=()=>new Error("checkout: url is not a Chain Daddy checkout session link"),i=(r,u,l)=>{f={popup:r,result:u,href:l};let a=()=>{f&&f.popup===r&&(f=void 0)};return u.then(a,a),u},o=r=>(location.assign(r.href),{status:"redirected"});try{let{url:r,successUrl:u}=t;if(u&&!x(u,""))throw new Error("checkout: successUrl is not a web address");let l=s=>u?x(u,s.id):null,a=typeof r=="function"?null:I(r);if(typeof r!="function"&&!a)throw e();if(f&&!f.popup.closed&&(!a||f.href===a.href))return f.popup.focus(),f.result;if(a){let s=window.open(a.href,H(),N);return s?i(s,z(s,a,l(a)),a.href):Promise.resolve(o(a))}let n=window.open("",H(),N),c=new Promise(s=>s(r())).then(s=>{let d=I(s);if(!d)throw n?.close(),e();return n?(n.location.href=d.href,z(n,d,l(d))):o(d)},s=>{throw n?.close(),s});return n?i(n,c):c}catch(r){return Promise.reject(r)}}var j=!1,q;function V(){j||typeof document>"u"||(j=!0,document.addEventListener("click",t=>{let e=t.target instanceof Element?t.target.closest("[data-cd-checkout]"):null;if(!e||t.defaultPrevented||t.button||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)return;let i=e.getAttribute("data-cd-checkout")||e.href,o=e.getAttribute("data-cd-success");if(!I(i)||o&&!x(o,""))return;t.preventDefault();let r=S({url:i,successUrl:o});r!==q&&(q=r,r.then(u=>void e.dispatchEvent(new CustomEvent("cd:checkout",{detail:u,bubbles:!0})),()=>{}))}))}var st={version:R,signIn:k,handleCallback:L,exchangeCode:M,checkout:S};window.ChainDaddy=Object.assign(window.ChainDaddy??{},st);P();D({origin:$(document.currentScript?.src)});V();})();
|
|
22
|
+
`;function D(t={}){try{if(typeof customElements>"u"||typeof HTMLElement>"u")return;let e=t.origin===E?E:O;class i extends HTMLElement{constructor(){super(...arguments);this.kind="app";this.frame=null;this.onMessage=n=>this.receive(n)}connectedCallback(){try{this.shadowRoot||this.attachShadow({mode:"open"}),this.mount()}catch{this.unavailable()}}disconnectedCallback(){try{window.removeEventListener("message",this.onMessage),clearTimeout(this.timer),this.watch?.disconnect()}catch{}}attributeChangedCallback(){try{this.isConnected&&this.shadowRoot&&this.mount()}catch{this.unavailable()}}src(){let n=(this.getAttribute("crown")??"").trim(),c=(this.getAttribute("chain")??"").trim(),s=(this.getAttribute("app")??"").trim();if(!/^[0-9]{1,18}$/.test(n)||!c||this.kind==="app"&&!s)return null;let d=new URLSearchParams({crown:n,chain:c});return this.kind==="app"?d.set("app",s):d.set("kind","coin"),d.set("mode",this.mode()),d.set("v","1"),`${e}/v1/frame?${d.toString()}`}mode(){let n=this.getAttribute("mode");if(n==="light"||n==="dark")return n;try{return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}catch{return"light"}}mount(){let n=this.shadowRoot;window.removeEventListener("message",this.onMessage),clearTimeout(this.timer),this.watch?.disconnect(),this.removeAttribute("data-cd-ready"),this.removeAttribute("data-cd-unavailable");let c=this.src();if(!c){n.innerHTML="<slot></slot>",this.frame=null;return}n.innerHTML=`<style>${et}</style><slot></slot>`;let s=document.createElement("iframe");s.setAttribute("referrerpolicy","strict-origin-when-cross-origin"),s.setAttribute("allow","clipboard-write; fullscreen"),s.setAttribute("title",this.kind==="coin"?"Coin on Chain Daddy":"App on Chain Daddy"),n.appendChild(s),this.frame=s,window.addEventListener("message",this.onMessage);let d=()=>{s.src=c,this.timer=setTimeout(()=>{this.hasAttribute("data-cd-ready")||this.unavailable()},8e3)};if(typeof IntersectionObserver>"u")return d();this.watch=new IntersectionObserver(g=>{g.some(h=>h.isIntersecting)&&(this.watch?.disconnect(),d())},{rootMargin:Q}),this.watch.observe(this)}why(){try{let n=new URL(this.frame.src).searchParams,c=n.get("app");n.delete("mode"),n.delete("v"),fetch(`https://${e===E?"staging-api":"api"}.chaindaddy.io/api/v2/embed/status?${n}`,{credentials:"omit"}).then(s=>s.json()).then(s=>{let d=s.embeddable?s.interactive?"not a verified site of the coin":"not https, or the app did not start":s.reason;console.info(`[Chain Daddy] cd-${this.kind} ${c??""} cannot show here: ${d}. ${Z}`)}).catch(()=>{})}catch{}}receive(n){try{if(n.origin!==e||!this.frame||!n.source||n.source!==this.frame.contentWindow)return;let c=n.data;if(!c||typeof c!="object")return;if(c.type==="cd:ready")clearTimeout(this.timer),this.removeAttribute("data-cd-unavailable"),this.setAttribute("data-cd-ready",""),this.sendTheme(),this.dispatchEvent(new CustomEvent("cd:ready"));else if(c.type==="cd:resize"){let s=Number(c.height);Number.isFinite(s)&&(this.frame.style.height=`${Math.max(1,Math.min(4e3,Math.ceil(s)))}px`)}else c.type==="cd:unavailable"&&this.unavailable()}catch{}}sendTheme(){let n={},c=getComputedStyle(this);for(let s of tt){let d=c.getPropertyValue(s).trim();d&&(n[s]=d)}this.frame?.contentWindow?.postMessage({type:"cd:theme",tokens:n},e)}unavailable(){try{if(clearTimeout(this.timer),this.removeAttribute("data-cd-ready"),this.hasAttribute("data-cd-unavailable"))return;this.setAttribute("data-cd-unavailable",""),this.dispatchEvent(new CustomEvent("cd:unavailable")),this.why()}catch{}}}i.observedAttributes=["crown","chain","app","mode"];class o extends i{}class r extends i{constructor(){super(...arguments);this.kind="coin"}}class u extends HTMLElement{connectedCallback(){try{let a=this.querySelector("a[href]"),n=a?new URL(a.getAttribute("href")??"",document.baseURI):null;if(!n||n.protocol!=="https:")return;let c=this.shadowRoot??this.attachShadow({mode:"open"});c.innerHTML=`<style>${nt}</style><button type="button" part="button"></button>`;let s=c.querySelector("button");s.textContent=(a.textContent??"").trim()||"Buy on Chain Daddy",s.addEventListener("click",()=>{try{window.open(n.toString(),"cd-buy","popup,width=460,height=760")||window.location.assign(n.toString())}catch{}})}catch{}}}for(let[l,a]of[["cd-app",o],["cd-coin",r],["cd-buy",u]])customElements.get(l)||customElements.define(l,a)}catch{}}var it=["https://chaindaddy.io","https://staging.chaindaddy.io"],H=()=>"cd-checkout-"+w(),N="popup,width=480,height=820",B=300,rt=7;function I(t){if(typeof t!="string")return null;let e;try{e=new URL(t)}catch{return null}let i=/^\/_pay\/([\w-]+)$/.exec(e.pathname);return i&&it.includes(e.origin)&&!e.username&&!e.password?{href:e.origin+e.pathname,origin:e.origin,id:i[1]}:null}function x(t,e){if(typeof t!="string")return null;let i;try{i=new URL(t,location.href)}catch{return null}if(!/^https?:$/.test(i.protocol)||i.username||i.password)return null;let o=u=>{let l=u.split("=")[0];try{return decodeURIComponent(l.replace(/\+/g," "))}catch{return l}},r=i.search.slice(1).split("&").filter(u=>u&&o(u)!=="session_id");return r.push("session_id="+encodeURIComponent(e)),i.origin+i.pathname+"?"+r.join("&")+i.hash}var f;function z(t,e,i){return new Promise(o=>{let r=!1,u=0,l,a=d=>{clearInterval(s),clearTimeout(l),window.removeEventListener("message",n),i&&d.status==="completed"&&location.assign(i),o(d)},n=d=>{if(d.origin!==e.origin||d.source!==t)return;let g=d.data;if(!g||typeof g!="object")return;g.type==="cd:checkout.ready"&&(r=!0);let h=g.session;if(!(!h||typeof h!="object"||h.id!==e.id)){if(g.type==="cd:checkout.cancelled")a({status:"cancelled",session:{id:e.id}});else if(g.type==="cd:checkout.completed"&&(h.status==="complete"||h.status==="paid")){let p={id:e.id,status:h.status};typeof h.orderId=="string"&&/^[\w-]{1,128}$/.test(h.orderId)&&(p.orderId=h.orderId),typeof h.livemode=="boolean"&&(p.livemode=h.livemode),a({status:"completed",session:p})}}},c=()=>{try{t.postMessage({type:"cd:checkout.hello"},e.origin)}catch{}},s=setInterval(()=>{t.closed?(clearInterval(s),l=setTimeout(()=>a({status:"closed"}),B)):(!r||++u%rt===0)&&c()},B);window.addEventListener("message",n),c()})}function S(t){let e=()=>new Error("checkout: url is not a Chain Daddy checkout session link"),i=(r,u,l)=>{f={popup:r,result:u,href:l};let a=()=>{f&&f.popup===r&&(f=void 0)};return u.then(a,a),u},o=r=>(location.assign(r.href),{status:"redirected"});try{let{url:r,successUrl:u}=t;if(u&&!x(u,""))throw new Error("checkout: successUrl is not a web address");let l=s=>u?x(u,s.id):null,a=typeof r=="function"?null:I(r);if(typeof r!="function"&&!a)throw e();if(f&&!f.popup.closed&&(!a||f.href===a.href))return f.popup.focus(),f.result;if(a){let s=window.open(a.href,H(),N);return s?i(s,z(s,a,l(a)),a.href):Promise.resolve(o(a))}let n=window.open("",H(),N),c=new Promise(s=>s(r())).then(s=>{let d=I(s);if(!d)throw n?.close(),e();return n?(n.location.href=d.href,z(n,d,l(d))):o(d)},s=>{throw n?.close(),s});return n?i(n,c):c}catch(r){return Promise.reject(r)}}var j=!1,q;function V(){j||typeof document>"u"||(j=!0,document.addEventListener("click",t=>{let e=t.target instanceof Element?t.target.closest("[data-cd-checkout]"):null;if(!e||t.defaultPrevented||t.button||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)return;let i=e.getAttribute("data-cd-checkout")||e.href,o=e.getAttribute("data-cd-success");if(!I(i)||o&&!x(o,""))return;t.preventDefault();let r=S({url:i,successUrl:o});r!==q&&(q=r,r.then(u=>void e.dispatchEvent(new CustomEvent("cd:checkout",{detail:u,bubbles:!0})),()=>{}))}))}var st={version:R,signIn:k,handleCallback:L,exchangeCode:M,checkout:S};window.ChainDaddy=Object.assign(window.ChainDaddy??{},st);P();D({origin:$(document.currentScript?.src)});V();})();
|
package/dist/cd.js.sri
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
sha384-
|
|
1
|
+
sha384-Skwsv/FQCtenMYT3zex2SCnlERwJPOsytod8T05hRGAb8yUoTlD/nF2tx+0d590b
|
package/dist/checkout.d.ts
CHANGED
|
@@ -13,13 +13,17 @@ export interface CheckoutOptions {
|
|
|
13
13
|
successUrl?: string | null;
|
|
14
14
|
}
|
|
15
15
|
export type CheckoutResult =
|
|
16
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* The buyer paid. `session.status` is "complete" (confirmed) or "paid" (sent, still confirming).
|
|
18
|
+
* `session.livemode` is false for a test store's session, where nothing was charged.
|
|
19
|
+
*/
|
|
17
20
|
{
|
|
18
21
|
status: 'completed';
|
|
19
22
|
session: {
|
|
20
23
|
id: string;
|
|
21
24
|
status: 'complete' | 'paid';
|
|
22
25
|
orderId?: string;
|
|
26
|
+
livemode?: boolean;
|
|
23
27
|
};
|
|
24
28
|
}
|
|
25
29
|
/** The buyer left the checkout without paying. */
|
package/dist/checkout.js
CHANGED
|
@@ -70,6 +70,7 @@ function wait(popup, target, success) {
|
|
|
70
70
|
else if (data.type === "cd:checkout.completed" && (s.status === "complete" || s.status === "paid")) {
|
|
71
71
|
const session = { id: target.id, status: s.status };
|
|
72
72
|
if (typeof s.orderId === "string" && /^[\w-]{1,128}$/.test(s.orderId)) session.orderId = s.orderId;
|
|
73
|
+
if (typeof s.livemode === "boolean") session.livemode = s.livemode;
|
|
73
74
|
done({ status: "completed", session });
|
|
74
75
|
}
|
|
75
76
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/core.ts
|
|
2
|
-
var VERSION = true ? "0.3.
|
|
2
|
+
var VERSION = true ? "0.3.4" : "0.0.0";
|
|
3
3
|
function b64url(bytes) {
|
|
4
4
|
let s = "";
|
|
5
5
|
for (const b of bytes) s += String.fromCharCode(b);
|
|
@@ -522,6 +522,7 @@ function wait(popup, target, success) {
|
|
|
522
522
|
else if (data.type === "cd:checkout.completed" && (s.status === "complete" || s.status === "paid")) {
|
|
523
523
|
const session = { id: target.id, status: s.status };
|
|
524
524
|
if (typeof s.orderId === "string" && /^[\w-]{1,128}$/.test(s.orderId)) session.orderId = s.orderId;
|
|
525
|
+
if (typeof s.livemode === "boolean") session.livemode = s.livemode;
|
|
525
526
|
done({ status: "completed", session });
|
|
526
527
|
}
|
|
527
528
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chaindaddy/js",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Chain Daddy for any website: Sign in with Chain Daddy (a popup and a button), a coin's apps on its own site (<cd-app>), checkout for a coin's store in a popup, and a server-side check that a store order was paid on chain",
|
|
5
5
|
"homepage": "https://docs.chaindaddy.io/developer/javascript-sdk",
|
|
6
6
|
"repository": {
|