@rhinestone/deposit-modal 0.17.0 → 0.19.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.
Files changed (62) hide show
  1. package/README.md +109 -0
  2. package/dist/{DepositModalReown-6CXXGQ7X.cjs → DepositModalReown-UITYXJ6W.cjs} +17 -17
  3. package/dist/{DepositModalReown-ELDSTIME.mjs → DepositModalReown-XBNY6QCI.mjs} +4 -4
  4. package/dist/{WithdrawModal-QRMDR5T4.mjs → WithdrawModal-DY6A55OA.mjs} +3 -3
  5. package/dist/WithdrawModal-V42OK7L3.cjs +11 -0
  6. package/dist/bearer-transport-CVHNBgoV.d.cts +14 -0
  7. package/dist/bearer-transport-CVHNBgoV.d.ts +14 -0
  8. package/dist/{chunk-QMGEK623.mjs → chunk-5NWLS5BQ.mjs} +536 -225
  9. package/dist/chunk-ADEWTBSN.cjs +19 -0
  10. package/dist/{chunk-ZHX4QROC.mjs → chunk-BIL4ENC3.mjs} +1 -1
  11. package/dist/{chunk-2W4BJ5I3.cjs → chunk-EG4H7OMC.cjs} +71 -71
  12. package/dist/{chunk-QGNJFDEO.cjs → chunk-HMUGY66O.cjs} +690 -379
  13. package/dist/chunk-ISLVD5HQ.cjs +41 -0
  14. package/dist/{chunk-H66WM5AO.mjs → chunk-NITKDXHR.mjs} +388 -95
  15. package/dist/{chunk-XJMDCBHS.cjs → chunk-OCWSMLOP.cjs} +862 -569
  16. package/dist/chunk-PP4QE32S.mjs +19 -0
  17. package/dist/{chunk-JCWJ6HW7.cjs → chunk-PYOC6K24.cjs} +1 -1
  18. package/dist/{chunk-XCBDJPBD.mjs → chunk-X6N2XPTO.mjs} +1 -1
  19. package/dist/chunk-ZGHVJ2XM.mjs +41 -0
  20. package/dist/compliance.cjs +14 -0
  21. package/dist/compliance.d.cts +10 -0
  22. package/dist/compliance.d.ts +10 -0
  23. package/dist/compliance.mjs +14 -0
  24. package/dist/constants.cjs +3 -3
  25. package/dist/constants.d.cts +1 -1
  26. package/dist/constants.d.ts +1 -1
  27. package/dist/constants.mjs +3 -3
  28. package/dist/deposit.cjs +4 -4
  29. package/dist/deposit.d.cts +2 -2
  30. package/dist/deposit.d.ts +2 -2
  31. package/dist/deposit.mjs +3 -3
  32. package/dist/embed.cjs +16 -16
  33. package/dist/embed.d.cts +1 -1
  34. package/dist/embed.d.ts +1 -1
  35. package/dist/embed.mjs +8 -8
  36. package/dist/index.cjs +5 -5
  37. package/dist/index.d.cts +1 -1
  38. package/dist/index.d.ts +1 -1
  39. package/dist/index.mjs +4 -4
  40. package/dist/offramp.cjs +25 -0
  41. package/dist/offramp.d.cts +28 -0
  42. package/dist/offramp.d.ts +28 -0
  43. package/dist/offramp.mjs +25 -0
  44. package/dist/onramp.cjs +40 -0
  45. package/dist/onramp.d.cts +55 -0
  46. package/dist/onramp.d.ts +55 -0
  47. package/dist/onramp.mjs +40 -0
  48. package/dist/ramp-types-C6aUz4SZ.d.cts +43 -0
  49. package/dist/ramp-types-C6aUz4SZ.d.ts +43 -0
  50. package/dist/server.cjs +54 -2
  51. package/dist/server.d.cts +13 -1
  52. package/dist/server.d.ts +13 -1
  53. package/dist/server.mjs +52 -0
  54. package/dist/styles.css +25 -0
  55. package/dist/{types-B9SbZQIG.d.ts → types-BOxa1DE-.d.ts} +40 -4
  56. package/dist/{types-SwGGf0eH.d.cts → types-BShYNpvO.d.cts} +40 -4
  57. package/dist/withdraw.cjs +4 -4
  58. package/dist/withdraw.d.cts +2 -2
  59. package/dist/withdraw.d.ts +2 -2
  60. package/dist/withdraw.mjs +3 -3
  61. package/package.json +35 -5
  62. package/dist/WithdrawModal-QB2U756L.cjs +0 -11
@@ -0,0 +1,25 @@
1
+ import {
2
+ rampQuery,
3
+ rampResourceId
4
+ } from "./chunk-PP4QE32S.mjs";
5
+ import {
6
+ ScopedRequestError,
7
+ createBearerTransport
8
+ } from "./chunk-ZGHVJ2XM.mjs";
9
+ import "./chunk-X6N2XPTO.mjs";
10
+
11
+ // src/core/offramp-service.ts
12
+ function createOfframpService(options) {
13
+ const request = createBearerTransport(options);
14
+ return {
15
+ createSession: (body) => request("/offramp/noah/sessions", body),
16
+ getSession: (id) => request(`/offramp/noah/sessions/${rampResourceId(id)}`),
17
+ getOptions: (intent) => request(`/offramp/noah/options?${rampQuery(intent)}`),
18
+ listPayments: (page = {}) => request(`/offramp/noah/payments?${rampQuery(page)}`),
19
+ getPayment: (id) => request(`/offramp/noah/payments/${rampResourceId(id)}`)
20
+ };
21
+ }
22
+ export {
23
+ ScopedRequestError,
24
+ createOfframpService
25
+ };
@@ -0,0 +1,40 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+ var _chunkADEWTBSNcjs = require('./chunk-ADEWTBSN.cjs');
5
+
6
+
7
+
8
+ var _chunkISLVD5HQcjs = require('./chunk-ISLVD5HQ.cjs');
9
+ require('./chunk-PYOC6K24.cjs');
10
+
11
+ // src/core/onramp-service.ts
12
+ function createOnrampService(options) {
13
+ const request = _chunkISLVD5HQcjs.createBearerTransport.call(void 0, options);
14
+ return {
15
+ createSetup: (body) => request("/onramp/noah/setup", body),
16
+ getSetup: (id) => request(`/onramp/noah/setup/${_chunkADEWTBSNcjs.rampResourceId.call(void 0, id)}`),
17
+ getOptions: (intent) => request(`/onramp/noah/options?${_chunkADEWTBSNcjs.rampQuery.call(void 0, intent)}`),
18
+ listAccounts: (page = {}) => request(
19
+ `/onramp/noah/accounts?${_chunkADEWTBSNcjs.rampQuery.call(void 0, page)}`
20
+ ),
21
+ getAccount: (id) => request(`/onramp/noah/accounts/${_chunkADEWTBSNcjs.rampResourceId.call(void 0, id)}`),
22
+ /**
23
+ * Mint a hosted address for the customer to read their account number or
24
+ * international account number from. A POST because minting one is a
25
+ * provider write; the coordinates themselves never cross this API.
26
+ */
27
+ getAccountDetails: (id) => request(
28
+ `/onramp/noah/accounts/${_chunkADEWTBSNcjs.rampResourceId.call(void 0, id)}/details`,
29
+ {}
30
+ ),
31
+ listPayments: (page = {}) => request(
32
+ `/onramp/noah/payments?${_chunkADEWTBSNcjs.rampQuery.call(void 0, page)}`
33
+ ),
34
+ getPayment: (id) => request(`/onramp/noah/payments/${_chunkADEWTBSNcjs.rampResourceId.call(void 0, id)}`)
35
+ };
36
+ }
37
+
38
+
39
+
40
+ exports.ScopedRequestError = _chunkISLVD5HQcjs.ScopedRequestError; exports.createOnrampService = createOnrampService;
@@ -0,0 +1,55 @@
1
+ import { C as CustomerSessionOptions } from './bearer-transport-CVHNBgoV.cjs';
2
+ export { a as CustomerSession, S as ScopedRequestError } from './bearer-transport-CVHNBgoV.cjs';
3
+ import { f as RampCurrency, H as HostedNextAction, B as BankIntent, R as RampPayment, P as PaymentLegStatus, a as PaymentReturnStatus, c as RampPage, d as RampOption, e as RampPagination } from './ramp-types-C6aUz4SZ.cjs';
4
+
5
+ interface OnrampSetupRequest extends BankIntent {
6
+ purpose: "account_setup";
7
+ }
8
+ interface OnrampOptionsRequest extends BankIntent {
9
+ /** Decimal fiat major units sent; the actual transfer determines payment amount. */
10
+ amount?: string;
11
+ }
12
+ interface OnrampPayment extends RampPayment {
13
+ bankReceipt: PaymentLegStatus;
14
+ conversion: PaymentLegStatus;
15
+ cryptoDelivery: PaymentLegStatus;
16
+ refund: PaymentReturnStatus;
17
+ adjustment: PaymentReturnStatus;
18
+ }
19
+ interface OnrampAccount {
20
+ id: string;
21
+ currency: RampCurrency;
22
+ paymentMethod: "bank_transfer";
23
+ status: "pending" | "active" | "disabled";
24
+ }
25
+ /**
26
+ * The result of one account setup. Unlike an offramp session it carries no
27
+ * status and no expiry: the call either configured the account named here, or
28
+ * it failed. There is nothing to poll and nothing that lapses.
29
+ */
30
+ interface OnrampSetup {
31
+ id: string;
32
+ account: OnrampAccount;
33
+ }
34
+ /** Where the customer reads their own bank coordinates; never returned here. */
35
+ interface OnrampAccountDetails {
36
+ nextAction: HostedNextAction;
37
+ }
38
+ /** No requests until an onramp method is called. */
39
+ declare function createOnrampService(options: CustomerSessionOptions): {
40
+ createSetup: (body: OnrampSetupRequest) => Promise<OnrampSetup>;
41
+ getSetup: (id: string) => Promise<OnrampSetup>;
42
+ getOptions: (intent: OnrampOptionsRequest) => Promise<RampPage<RampOption>>;
43
+ listAccounts: (page?: RampPagination) => Promise<RampPage<OnrampAccount>>;
44
+ getAccount: (id: string) => Promise<OnrampAccount>;
45
+ /**
46
+ * Mint a hosted address for the customer to read their account number or
47
+ * international account number from. A POST because minting one is a
48
+ * provider write; the coordinates themselves never cross this API.
49
+ */
50
+ getAccountDetails: (id: string) => Promise<OnrampAccountDetails>;
51
+ listPayments: (page?: RampPagination) => Promise<RampPage<OnrampPayment>>;
52
+ getPayment: (id: string) => Promise<OnrampPayment>;
53
+ };
54
+
55
+ export { CustomerSessionOptions, HostedNextAction, type OnrampAccount, type OnrampAccountDetails, type OnrampOptionsRequest, type OnrampPayment, type OnrampSetup, type OnrampSetupRequest, PaymentLegStatus, PaymentReturnStatus, RampCurrency, RampOption, RampPage, RampPagination, createOnrampService };
@@ -0,0 +1,55 @@
1
+ import { C as CustomerSessionOptions } from './bearer-transport-CVHNBgoV.js';
2
+ export { a as CustomerSession, S as ScopedRequestError } from './bearer-transport-CVHNBgoV.js';
3
+ import { f as RampCurrency, H as HostedNextAction, B as BankIntent, R as RampPayment, P as PaymentLegStatus, a as PaymentReturnStatus, c as RampPage, d as RampOption, e as RampPagination } from './ramp-types-C6aUz4SZ.js';
4
+
5
+ interface OnrampSetupRequest extends BankIntent {
6
+ purpose: "account_setup";
7
+ }
8
+ interface OnrampOptionsRequest extends BankIntent {
9
+ /** Decimal fiat major units sent; the actual transfer determines payment amount. */
10
+ amount?: string;
11
+ }
12
+ interface OnrampPayment extends RampPayment {
13
+ bankReceipt: PaymentLegStatus;
14
+ conversion: PaymentLegStatus;
15
+ cryptoDelivery: PaymentLegStatus;
16
+ refund: PaymentReturnStatus;
17
+ adjustment: PaymentReturnStatus;
18
+ }
19
+ interface OnrampAccount {
20
+ id: string;
21
+ currency: RampCurrency;
22
+ paymentMethod: "bank_transfer";
23
+ status: "pending" | "active" | "disabled";
24
+ }
25
+ /**
26
+ * The result of one account setup. Unlike an offramp session it carries no
27
+ * status and no expiry: the call either configured the account named here, or
28
+ * it failed. There is nothing to poll and nothing that lapses.
29
+ */
30
+ interface OnrampSetup {
31
+ id: string;
32
+ account: OnrampAccount;
33
+ }
34
+ /** Where the customer reads their own bank coordinates; never returned here. */
35
+ interface OnrampAccountDetails {
36
+ nextAction: HostedNextAction;
37
+ }
38
+ /** No requests until an onramp method is called. */
39
+ declare function createOnrampService(options: CustomerSessionOptions): {
40
+ createSetup: (body: OnrampSetupRequest) => Promise<OnrampSetup>;
41
+ getSetup: (id: string) => Promise<OnrampSetup>;
42
+ getOptions: (intent: OnrampOptionsRequest) => Promise<RampPage<RampOption>>;
43
+ listAccounts: (page?: RampPagination) => Promise<RampPage<OnrampAccount>>;
44
+ getAccount: (id: string) => Promise<OnrampAccount>;
45
+ /**
46
+ * Mint a hosted address for the customer to read their account number or
47
+ * international account number from. A POST because minting one is a
48
+ * provider write; the coordinates themselves never cross this API.
49
+ */
50
+ getAccountDetails: (id: string) => Promise<OnrampAccountDetails>;
51
+ listPayments: (page?: RampPagination) => Promise<RampPage<OnrampPayment>>;
52
+ getPayment: (id: string) => Promise<OnrampPayment>;
53
+ };
54
+
55
+ export { CustomerSessionOptions, HostedNextAction, type OnrampAccount, type OnrampAccountDetails, type OnrampOptionsRequest, type OnrampPayment, type OnrampSetup, type OnrampSetupRequest, PaymentLegStatus, PaymentReturnStatus, RampCurrency, RampOption, RampPage, RampPagination, createOnrampService };
@@ -0,0 +1,40 @@
1
+ import {
2
+ rampQuery,
3
+ rampResourceId
4
+ } from "./chunk-PP4QE32S.mjs";
5
+ import {
6
+ ScopedRequestError,
7
+ createBearerTransport
8
+ } from "./chunk-ZGHVJ2XM.mjs";
9
+ import "./chunk-X6N2XPTO.mjs";
10
+
11
+ // src/core/onramp-service.ts
12
+ function createOnrampService(options) {
13
+ const request = createBearerTransport(options);
14
+ return {
15
+ createSetup: (body) => request("/onramp/noah/setup", body),
16
+ getSetup: (id) => request(`/onramp/noah/setup/${rampResourceId(id)}`),
17
+ getOptions: (intent) => request(`/onramp/noah/options?${rampQuery(intent)}`),
18
+ listAccounts: (page = {}) => request(
19
+ `/onramp/noah/accounts?${rampQuery(page)}`
20
+ ),
21
+ getAccount: (id) => request(`/onramp/noah/accounts/${rampResourceId(id)}`),
22
+ /**
23
+ * Mint a hosted address for the customer to read their account number or
24
+ * international account number from. A POST because minting one is a
25
+ * provider write; the coordinates themselves never cross this API.
26
+ */
27
+ getAccountDetails: (id) => request(
28
+ `/onramp/noah/accounts/${rampResourceId(id)}/details`,
29
+ {}
30
+ ),
31
+ listPayments: (page = {}) => request(
32
+ `/onramp/noah/payments?${rampQuery(page)}`
33
+ ),
34
+ getPayment: (id) => request(`/onramp/noah/payments/${rampResourceId(id)}`)
35
+ };
36
+ }
37
+ export {
38
+ ScopedRequestError,
39
+ createOnrampService
40
+ };
@@ -0,0 +1,43 @@
1
+ type RampCurrency = "EUR" | "USD";
2
+ interface BankIntent {
3
+ country: string;
4
+ currency: RampCurrency;
5
+ paymentMethod: "bank_transfer";
6
+ optionId?: string;
7
+ }
8
+ interface HostedNextAction {
9
+ type: "hosted";
10
+ url: string;
11
+ presentation: "iframe";
12
+ }
13
+ interface RampSession {
14
+ id: string;
15
+ /** Interaction completion never proves settlement. */
16
+ status: "pending" | "completed" | "expired" | "failed";
17
+ expiresAt: string;
18
+ nextAction?: HostedNextAction;
19
+ }
20
+ interface RampOption {
21
+ optionId: string;
22
+ currency: RampCurrency;
23
+ paymentMethod: "bank_transfer";
24
+ }
25
+ type PaymentLegStatus = "not_started" | "pending" | "on_hold" | "processing" | "submitted" | "completed" | "failed";
26
+ type PaymentReturnStatus = "none" | "pending" | "processing" | "completed" | "failed";
27
+ interface RampPayment {
28
+ id: string;
29
+ amount: string;
30
+ currency: RampCurrency;
31
+ createdAt: string;
32
+ updatedAt: string;
33
+ }
34
+ interface RampPage<T> {
35
+ items: T[];
36
+ nextCursor?: string;
37
+ }
38
+ interface RampPagination {
39
+ cursor?: string;
40
+ limit?: number;
41
+ }
42
+
43
+ export type { BankIntent as B, HostedNextAction as H, PaymentLegStatus as P, RampPayment as R, PaymentReturnStatus as a, RampSession as b, RampPage as c, RampOption as d, RampPagination as e, RampCurrency as f };
@@ -0,0 +1,43 @@
1
+ type RampCurrency = "EUR" | "USD";
2
+ interface BankIntent {
3
+ country: string;
4
+ currency: RampCurrency;
5
+ paymentMethod: "bank_transfer";
6
+ optionId?: string;
7
+ }
8
+ interface HostedNextAction {
9
+ type: "hosted";
10
+ url: string;
11
+ presentation: "iframe";
12
+ }
13
+ interface RampSession {
14
+ id: string;
15
+ /** Interaction completion never proves settlement. */
16
+ status: "pending" | "completed" | "expired" | "failed";
17
+ expiresAt: string;
18
+ nextAction?: HostedNextAction;
19
+ }
20
+ interface RampOption {
21
+ optionId: string;
22
+ currency: RampCurrency;
23
+ paymentMethod: "bank_transfer";
24
+ }
25
+ type PaymentLegStatus = "not_started" | "pending" | "on_hold" | "processing" | "submitted" | "completed" | "failed";
26
+ type PaymentReturnStatus = "none" | "pending" | "processing" | "completed" | "failed";
27
+ interface RampPayment {
28
+ id: string;
29
+ amount: string;
30
+ currency: RampCurrency;
31
+ createdAt: string;
32
+ updatedAt: string;
33
+ }
34
+ interface RampPage<T> {
35
+ items: T[];
36
+ nextCursor?: string;
37
+ }
38
+ interface RampPagination {
39
+ cursor?: string;
40
+ limit?: number;
41
+ }
42
+
43
+ export type { BankIntent as B, HostedNextAction as H, PaymentLegStatus as P, RampPayment as R, PaymentReturnStatus as a, RampSession as b, RampPage as c, RampOption as d, RampPagination as e, RampCurrency as f };
package/dist/server.cjs CHANGED
@@ -1,5 +1,56 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/server.ts
2
2
  var DEFAULT_PROCESSOR_URL = "https://v1.orchestrator.rhinestone.dev/deposit-processor";
3
+ function createCustomerSessionHandler(options) {
4
+ const url = `${(_nullishCoalesce(options.processorUrl, () => ( DEFAULT_PROCESSOR_URL))).replace(
5
+ /\/$/,
6
+ ""
7
+ )}/compliance/sessions`;
8
+ const responseHeaders = {
9
+ "Content-Type": "application/json",
10
+ "Cache-Control": "no-store"
11
+ };
12
+ const error = (status, message) => new Response(JSON.stringify({ error: message }), {
13
+ status,
14
+ headers: responseHeaders
15
+ });
16
+ return async (request) => {
17
+ if (request.method !== "POST") return error(405, "Method not allowed");
18
+ try {
19
+ const identity = await options.authorize(request);
20
+ if (!identity) return error(401, "Unauthorized");
21
+ const upstream = await fetch(url, {
22
+ method: "POST",
23
+ headers: {
24
+ "Content-Type": "application/json",
25
+ "x-api-key": options.apiKey
26
+ },
27
+ body: JSON.stringify({
28
+ externalCustomerId: identity.externalCustomerId,
29
+ ...identity.smartAccount ? { smartAccount: identity.smartAccount } : {}
30
+ }),
31
+ cache: "no-store",
32
+ redirect: "manual",
33
+ signal: AbortSignal.timeout(15e3)
34
+ });
35
+ if (!upstream.ok)
36
+ return error(
37
+ upstream.status >= 400 && upstream.status < 500 ? upstream.status : 502,
38
+ "Customer session unavailable"
39
+ );
40
+ const value = await upstream.json();
41
+ if (!value || typeof value !== "object")
42
+ return error(502, "Invalid customer session");
43
+ const { token, expiresAt } = value;
44
+ if (typeof token !== "string" || !token || /\s/.test(token) || typeof expiresAt !== "string" || !Number.isFinite(Date.parse(expiresAt)) || Date.parse(expiresAt) <= Date.now() || Date.parse(expiresAt) > Date.now() + 15 * 6e4)
45
+ return error(502, "Invalid customer session");
46
+ return new Response(JSON.stringify({ token, expiresAt }), {
47
+ headers: responseHeaders
48
+ });
49
+ } catch (e) {
50
+ return error(502, "Customer session unavailable");
51
+ }
52
+ };
53
+ }
3
54
  function jsonError(message, status) {
4
55
  return new Response(JSON.stringify({ error: message }), {
5
56
  status,
@@ -79,7 +130,7 @@ function createRefundHandler(options) {
79
130
  let body_;
80
131
  try {
81
132
  body_ = JSON.parse(text);
82
- } catch (e) {
133
+ } catch (e2) {
83
134
  return new Response(text, {
84
135
  status: upstream.status,
85
136
  headers: { "Content-Type": "application/json" }
@@ -93,4 +144,5 @@ function createRefundHandler(options) {
93
144
  }
94
145
 
95
146
 
96
- exports.createRefundHandler = createRefundHandler;
147
+
148
+ exports.createCustomerSessionHandler = createCustomerSessionHandler; exports.createRefundHandler = createRefundHandler;
package/dist/server.d.cts CHANGED
@@ -8,6 +8,18 @@
8
8
  * Whether a deposit belongs to a given user is something only your app knows,
9
9
  * so that one decision is yours (`authorize`) and everything else is here.
10
10
  */
11
+ interface CustomerSessionAuthorization {
12
+ externalCustomerId: string;
13
+ smartAccount?: string;
14
+ }
15
+ interface CreateCustomerSessionHandlerOptions {
16
+ apiKey: string;
17
+ processorUrl?: string;
18
+ /** Authenticate and enforce your CSRF policy. Derive identity server-side, never from the request body. */
19
+ authorize: (request: Request) => CustomerSessionAuthorization | null | Promise<CustomerSessionAuthorization | null>;
20
+ }
21
+ /** Server-only token minting endpoint. Never mount this on an unauthenticated proxy. */
22
+ declare function createCustomerSessionHandler(options: CreateCustomerSessionHandlerOptions): (request: Request) => Promise<Response>;
11
23
  /** Body your own UI POSTs to your endpoint. Never trusted on its own. */
12
24
  interface RefundRequestBody {
13
25
  chain: string;
@@ -62,4 +74,4 @@ interface CreateRefundHandlerOptions {
62
74
  */
63
75
  declare function createRefundHandler(options: CreateRefundHandlerOptions): (request: Request) => Promise<Response>;
64
76
 
65
- export { type CreateRefundHandlerOptions, type RefundAuthorization, createRefundHandler };
77
+ export { type CreateCustomerSessionHandlerOptions, type CreateRefundHandlerOptions, type CustomerSessionAuthorization, type RefundAuthorization, createCustomerSessionHandler, createRefundHandler };
package/dist/server.d.ts CHANGED
@@ -8,6 +8,18 @@
8
8
  * Whether a deposit belongs to a given user is something only your app knows,
9
9
  * so that one decision is yours (`authorize`) and everything else is here.
10
10
  */
11
+ interface CustomerSessionAuthorization {
12
+ externalCustomerId: string;
13
+ smartAccount?: string;
14
+ }
15
+ interface CreateCustomerSessionHandlerOptions {
16
+ apiKey: string;
17
+ processorUrl?: string;
18
+ /** Authenticate and enforce your CSRF policy. Derive identity server-side, never from the request body. */
19
+ authorize: (request: Request) => CustomerSessionAuthorization | null | Promise<CustomerSessionAuthorization | null>;
20
+ }
21
+ /** Server-only token minting endpoint. Never mount this on an unauthenticated proxy. */
22
+ declare function createCustomerSessionHandler(options: CreateCustomerSessionHandlerOptions): (request: Request) => Promise<Response>;
11
23
  /** Body your own UI POSTs to your endpoint. Never trusted on its own. */
12
24
  interface RefundRequestBody {
13
25
  chain: string;
@@ -62,4 +74,4 @@ interface CreateRefundHandlerOptions {
62
74
  */
63
75
  declare function createRefundHandler(options: CreateRefundHandlerOptions): (request: Request) => Promise<Response>;
64
76
 
65
- export { type CreateRefundHandlerOptions, type RefundAuthorization, createRefundHandler };
77
+ export { type CreateCustomerSessionHandlerOptions, type CreateRefundHandlerOptions, type CustomerSessionAuthorization, type RefundAuthorization, createCustomerSessionHandler, createRefundHandler };
package/dist/server.mjs CHANGED
@@ -1,5 +1,56 @@
1
1
  // src/server.ts
2
2
  var DEFAULT_PROCESSOR_URL = "https://v1.orchestrator.rhinestone.dev/deposit-processor";
3
+ function createCustomerSessionHandler(options) {
4
+ const url = `${(options.processorUrl ?? DEFAULT_PROCESSOR_URL).replace(
5
+ /\/$/,
6
+ ""
7
+ )}/compliance/sessions`;
8
+ const responseHeaders = {
9
+ "Content-Type": "application/json",
10
+ "Cache-Control": "no-store"
11
+ };
12
+ const error = (status, message) => new Response(JSON.stringify({ error: message }), {
13
+ status,
14
+ headers: responseHeaders
15
+ });
16
+ return async (request) => {
17
+ if (request.method !== "POST") return error(405, "Method not allowed");
18
+ try {
19
+ const identity = await options.authorize(request);
20
+ if (!identity) return error(401, "Unauthorized");
21
+ const upstream = await fetch(url, {
22
+ method: "POST",
23
+ headers: {
24
+ "Content-Type": "application/json",
25
+ "x-api-key": options.apiKey
26
+ },
27
+ body: JSON.stringify({
28
+ externalCustomerId: identity.externalCustomerId,
29
+ ...identity.smartAccount ? { smartAccount: identity.smartAccount } : {}
30
+ }),
31
+ cache: "no-store",
32
+ redirect: "manual",
33
+ signal: AbortSignal.timeout(15e3)
34
+ });
35
+ if (!upstream.ok)
36
+ return error(
37
+ upstream.status >= 400 && upstream.status < 500 ? upstream.status : 502,
38
+ "Customer session unavailable"
39
+ );
40
+ const value = await upstream.json();
41
+ if (!value || typeof value !== "object")
42
+ return error(502, "Invalid customer session");
43
+ const { token, expiresAt } = value;
44
+ if (typeof token !== "string" || !token || /\s/.test(token) || typeof expiresAt !== "string" || !Number.isFinite(Date.parse(expiresAt)) || Date.parse(expiresAt) <= Date.now() || Date.parse(expiresAt) > Date.now() + 15 * 6e4)
45
+ return error(502, "Invalid customer session");
46
+ return new Response(JSON.stringify({ token, expiresAt }), {
47
+ headers: responseHeaders
48
+ });
49
+ } catch {
50
+ return error(502, "Customer session unavailable");
51
+ }
52
+ };
53
+ }
3
54
  function jsonError(message, status) {
4
55
  return new Response(JSON.stringify({ error: message }), {
5
56
  status,
@@ -92,5 +143,6 @@ function createRefundHandler(options) {
92
143
  };
93
144
  }
94
145
  export {
146
+ createCustomerSessionHandler,
95
147
  createRefundHandler
96
148
  };
package/dist/styles.css CHANGED
@@ -2176,6 +2176,18 @@
2176
2176
  font-feature-settings: "tnum";
2177
2177
  }
2178
2178
 
2179
+ /* Payment mode's price. Same weight as the input it replaces, but sized down:
2180
+ a token amount carries more digits than a USD figure and must not wrap. */
2181
+ .rs-amount-fixed {
2182
+ width: 100%;
2183
+ font-size: 40px;
2184
+ font-weight: 700;
2185
+ line-height: 1.1;
2186
+ color: var(--rs-foreground);
2187
+ font-feature-settings: "tnum";
2188
+ overflow-wrap: anywhere;
2189
+ }
2190
+
2179
2191
  .rs-amount-prefix {
2180
2192
  flex: none;
2181
2193
  user-select: none;
@@ -3491,6 +3503,19 @@
3491
3503
  height: 190px;
3492
3504
  }
3493
3505
 
3506
+ /* Sits above the address and outranks it: the amount is the instruction the
3507
+ payer has to get right, the address is what the QR already carries. */
3508
+ .rs-deposit-address-amount {
3509
+ width: 100%;
3510
+ padding: 0 16px 4px;
3511
+ font-size: 15px;
3512
+ font-weight: 600;
3513
+ line-height: normal;
3514
+ color: var(--rs-foreground);
3515
+ text-align: center;
3516
+ font-feature-settings: "tnum";
3517
+ }
3518
+
3494
3519
  .rs-deposit-address-value {
3495
3520
  width: 100%;
3496
3521
  padding: 0 16px 12px;
@@ -87,8 +87,9 @@ type RecoveryErrorCode = "DEPOSIT_NOT_RECOVERABLE" | "RECOVERY_UNSUPPORTED" | "S
87
87
  /**
88
88
  * How a `GET /deposits` row reads on screen, and which rows are on screen at
89
89
  * all. Shared rather than private to the history panel: the header's status dot
90
- * derives from the same rows the panel lists, and a second copy of either
91
- * answer would let the badge and the list disagree.
90
+ * derives from the same rows the panel lists, the arrival expectation inside a
91
+ * row is gated on the same statuses, and a second copy of any of those answers
92
+ * would let the badge, the list and the arrival line disagree.
92
93
  */
93
94
  type HistoryStatus = "pending" | "processing" | "completed" | "failed" | "refunded" | "spam";
94
95
 
@@ -198,6 +199,32 @@ interface FiatMethodsConfig {
198
199
  "bank-transfer"?: boolean;
199
200
  "apple-pay"?: boolean;
200
201
  }
202
+ /**
203
+ * Turns the modal into a checkout for one order: the amount is the merchant's
204
+ * price rather than the payer's choice, and the account is the order's rather
205
+ * than the recipient's.
206
+ *
207
+ * Every funding method stays available, and only the wallet path can hold a
208
+ * payer to the amount — a QR, exchange or card payer can still send the wrong
209
+ * one. Reconcile what arrives; `destinationAmount` on the `complete` lifecycle
210
+ * event is the delivered figure.
211
+ */
212
+ interface PaymentConfig {
213
+ /**
214
+ * The order's account salt, as the merchant's server registered it. Both sides
215
+ * must pass the same 32 bytes: the address is derived from it, so a different
216
+ * salt is a different account and the payment lands somewhere the merchant is
217
+ * not watching. It replaces the (recipient, target) derivation entirely, which
218
+ * is what lets one recipient hold many orders.
219
+ */
220
+ salt: Hex;
221
+ /**
222
+ * Required destination amount, in base units of `targetToken`. NOT a USD
223
+ * figure — the amount screen's own input is USD, and this is deliberately not
224
+ * that, since it is the quantity the merchant must receive.
225
+ */
226
+ amount: string;
227
+ }
201
228
  interface DepositModalProps {
202
229
  /**
203
230
  * A wallet the host app already has connected. Pass this to reuse the user's
@@ -226,6 +253,8 @@ interface DepositModalProps {
226
253
  */
227
254
  defaultAmount?: string;
228
255
  recipient: Address | string;
256
+ /** Renders the modal as a checkout for one order. See {@link PaymentConfig}. */
257
+ payment?: PaymentConfig;
229
258
  /**
230
259
  * The user's current in-app balance, in USD, as the consuming app displays
231
260
  * it. When provided, the amount screen shows a "Balance after deposit" row
@@ -486,6 +515,13 @@ type DepositLifecycleEvent = {
486
515
  destinationTxHash?: string;
487
516
  /** Source-token base units (e.g. "1100000" for 1.10 USDC). */
488
517
  amount: string;
518
+ /**
519
+ * What actually arrived, in `targetToken` base units, once the bridge
520
+ * reports it — the only field that answers "was the invoice paid in
521
+ * full?". `amount` is the source side and says nothing about delivery.
522
+ * Absent until the completing event carries a destination leg.
523
+ */
524
+ destinationAmount?: string;
489
525
  sourceChain: ChainId | "unknown";
490
526
  sourceToken?: string;
491
527
  /**
@@ -893,7 +929,7 @@ type WithdrawAnalyticsEvent = WithdrawAnalyticsEventPayload & AnalyticsEventEnve
893
929
  */
894
930
  type ClaimAnalyticsStep = "lookup" | "select" | "review" | "submit";
895
931
  /** Every reason has a call site in the claim flow; none is aspirational. */
896
- type ClaimAnalyticsFailureReason = RoutableAnalyticsReason<"lookup_transaction_hash_invalid" | "lookup_failed" | "lookup_no_deposits_found" | "lookup_no_eligible_deposits" | "refund_destination_invalid" | "recovery_deposit_data_incomplete" | "signature_rejected" | "signature_invalid" | "recovery_deposit_not_recoverable" | "recovery_unsupported" | "signature_verification_unavailable" | "refund_reconciliation_required" | "refund_failed" | "refund_service_unreachable" | "modal_close_refused_in_flight">;
932
+ type ClaimAnalyticsFailureReason = RoutableAnalyticsReason<"lookup_transaction_hash_invalid" | "lookup_failed" | "lookup_no_deposits_found" | "lookup_no_eligible_deposits" | "refund_destination_invalid" | "refund_destination_is_deposit_address" | "recovery_deposit_data_incomplete" | "signature_rejected" | "signature_invalid" | "recovery_deposit_not_recoverable" | "recovery_unsupported" | "signature_verification_unavailable" | "refund_reconciliation_required" | "refund_failed" | "refund_service_unreachable" | "modal_close_refused_in_flight">;
897
933
  type ClaimAnalyticsAbandonmentReason = "back" | "modal_close";
898
934
  type ClaimAnalyticsCloseSource = "header_button" | "escape" | "overlay" | "host_controlled" | "success_done" | "failure_cancel"
899
935
  /** The labelled control back to the history list a recovery was started from. */
@@ -1016,4 +1052,4 @@ interface AnalyticsIngestFailureEvent {
1016
1052
  }
1017
1053
  type ModalAnalyticsEvent = DepositAnalyticsEvent | WithdrawAnalyticsEvent | ClaimAnalyticsEvent | AnalyticsIngestFailureEvent;
1018
1054
 
1019
- export type { OutputTokenRule as $, AnalyticsEventEnvelope as A, DepositAnalyticsStep as B, ChainId as C, DepositAnalyticsAbandonmentReason as D, DepositAnalyticsTransferStep as E, DepositAnalyticsUiOutcome as F, DepositAnalyticsWalletStep as G, DepositAssetMigrationMethodIdentifiers as H, DepositCompleteEventData as I, DepositExchangeConnectMethodIdentifiers as J, DepositFailedEventData as K, DepositFiatOnrampMethodIdentifiers as L, DepositFundingMethod as M, DepositLifecycleEvent as N, DepositModalProps as O, DepositModalTheme as P, DepositModalUIConfig as Q, DepositSubmittedEventData as R, DepositTransferHandoffIdentifiers as S, DepositWalletIntegration as T, DepositWalletMethodIdentifiers as U, ErrorEventData as V, FiatMethodsConfig as W, HistoryAnalyticsBadge as X, HistoryClaimEntrySource as Y, HistoryStatus as Z, ModalAnalyticsEvent as _, AnalyticsIngestFailureEvent as a, RecoveryErrorCode as a0, RpcUrlMap as a1, SignRecovery as a2, SignRecoveryPayload as a3, WithdrawAnalyticsAbandonmentReason as a4, WithdrawAnalyticsCloseSource as a5, WithdrawAnalyticsEvent as a6, WithdrawAnalyticsEventPayload as a7, WithdrawAnalyticsFailureReason as a8, WithdrawAnalyticsSessionProperties as a9, WithdrawAnalyticsStep as aa, WithdrawAnalyticsUiOutcome as ab, WithdrawCompleteEventData as ac, WithdrawFailedEventData as ad, WithdrawLifecycleEvent as ae, WithdrawModalProps as af, WithdrawSubmittedEventData as ag, WithdrawTransferRequest as ah, AnalyticsIngestFailureReason as b, AnalyticsReasonFamily as c, AssetMigrationsConfig as d, AssetOption as e, ClaimAnalyticsAbandonmentReason as f, ClaimAnalyticsCloseSource as g, ClaimAnalyticsCorrelation as h, ClaimAnalyticsEntrySource as i, ClaimAnalyticsEvent as j, ClaimAnalyticsEventPayload as k, ClaimAnalyticsFailureReason as l, ClaimAnalyticsSessionProperties as m, ClaimAnalyticsStep as n, ClaimAnalyticsUiOutcome as o, ConnectedEventData as p, DepositAnalyticsCloseSource as q, DepositAnalyticsCorrelator as r, DepositAnalyticsEvent as s, DepositAnalyticsEventPayload as t, DepositAnalyticsExchangeStep as u, DepositAnalyticsFailureReason as v, DepositAnalyticsFiatStep as w, DepositAnalyticsMigrationStep as x, DepositAnalyticsSessionProperties as y, DepositAnalyticsSharedStep as z };
1055
+ export type { OutputTokenRule as $, AnalyticsEventEnvelope as A, DepositAnalyticsStep as B, ChainId as C, DepositAnalyticsAbandonmentReason as D, DepositAnalyticsTransferStep as E, DepositAnalyticsUiOutcome as F, DepositAnalyticsWalletStep as G, DepositAssetMigrationMethodIdentifiers as H, DepositCompleteEventData as I, DepositExchangeConnectMethodIdentifiers as J, DepositFailedEventData as K, DepositFiatOnrampMethodIdentifiers as L, DepositFundingMethod as M, DepositLifecycleEvent as N, DepositModalProps as O, DepositModalTheme as P, DepositModalUIConfig as Q, DepositSubmittedEventData as R, DepositTransferHandoffIdentifiers as S, DepositWalletIntegration as T, DepositWalletMethodIdentifiers as U, ErrorEventData as V, FiatMethodsConfig as W, HistoryAnalyticsBadge as X, HistoryClaimEntrySource as Y, HistoryStatus as Z, ModalAnalyticsEvent as _, AnalyticsIngestFailureEvent as a, PaymentConfig as a0, RecoveryErrorCode as a1, RpcUrlMap as a2, SignRecovery as a3, SignRecoveryPayload as a4, WithdrawAnalyticsAbandonmentReason as a5, WithdrawAnalyticsCloseSource as a6, WithdrawAnalyticsEvent as a7, WithdrawAnalyticsEventPayload as a8, WithdrawAnalyticsFailureReason as a9, WithdrawAnalyticsSessionProperties as aa, WithdrawAnalyticsStep as ab, WithdrawAnalyticsUiOutcome as ac, WithdrawCompleteEventData as ad, WithdrawFailedEventData as ae, WithdrawLifecycleEvent as af, WithdrawModalProps as ag, WithdrawSubmittedEventData as ah, WithdrawTransferRequest as ai, AnalyticsIngestFailureReason as b, AnalyticsReasonFamily as c, AssetMigrationsConfig as d, AssetOption as e, ClaimAnalyticsAbandonmentReason as f, ClaimAnalyticsCloseSource as g, ClaimAnalyticsCorrelation as h, ClaimAnalyticsEntrySource as i, ClaimAnalyticsEvent as j, ClaimAnalyticsEventPayload as k, ClaimAnalyticsFailureReason as l, ClaimAnalyticsSessionProperties as m, ClaimAnalyticsStep as n, ClaimAnalyticsUiOutcome as o, ConnectedEventData as p, DepositAnalyticsCloseSource as q, DepositAnalyticsCorrelator as r, DepositAnalyticsEvent as s, DepositAnalyticsEventPayload as t, DepositAnalyticsExchangeStep as u, DepositAnalyticsFailureReason as v, DepositAnalyticsFiatStep as w, DepositAnalyticsMigrationStep as x, DepositAnalyticsSessionProperties as y, DepositAnalyticsSharedStep as z };