@strimz/sdk 0.1.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 (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/dist/browser-client-DlZg0Aae.d.cts +223 -0
  4. package/dist/browser-client-DlZg0Aae.d.ts +223 -0
  5. package/dist/browser-client.cjs +443 -0
  6. package/dist/browser-client.cjs.map +1 -0
  7. package/dist/browser-client.d.cts +4 -0
  8. package/dist/browser-client.d.ts +4 -0
  9. package/dist/browser-client.js +439 -0
  10. package/dist/browser-client.js.map +1 -0
  11. package/dist/eip712.cjs +70 -0
  12. package/dist/eip712.cjs.map +1 -0
  13. package/dist/eip712.d.cts +181 -0
  14. package/dist/eip712.d.ts +181 -0
  15. package/dist/eip712.js +65 -0
  16. package/dist/eip712.js.map +1 -0
  17. package/dist/errors.cjs +102 -0
  18. package/dist/errors.cjs.map +1 -0
  19. package/dist/errors.d.cts +56 -0
  20. package/dist/errors.d.ts +56 -0
  21. package/dist/errors.js +90 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/index.cjs +831 -0
  24. package/dist/index.cjs.map +1 -0
  25. package/dist/index.d.cts +193 -0
  26. package/dist/index.d.ts +193 -0
  27. package/dist/index.js +806 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/webhooks.cjs +54 -0
  30. package/dist/webhooks.cjs.map +1 -0
  31. package/dist/webhooks.d.cts +19 -0
  32. package/dist/webhooks.d.ts +19 -0
  33. package/dist/webhooks.js +13 -0
  34. package/dist/webhooks.js.map +1 -0
  35. package/package.json +94 -0
  36. package/src/browser-client.ts +97 -0
  37. package/src/client.ts +122 -0
  38. package/src/eip712/index.ts +25 -0
  39. package/src/eip712/permit.ts +74 -0
  40. package/src/eip712/receive-with-authorization.ts +88 -0
  41. package/src/eip712/types.ts +46 -0
  42. package/src/errors.ts +138 -0
  43. package/src/http/fetcher.ts +226 -0
  44. package/src/http/headers.ts +32 -0
  45. package/src/idempotency.ts +20 -0
  46. package/src/index.ts +77 -0
  47. package/src/pagination.ts +48 -0
  48. package/src/resources/agents.ts +64 -0
  49. package/src/resources/api-keys.ts +29 -0
  50. package/src/resources/base-resource.ts +116 -0
  51. package/src/resources/checkout.ts +32 -0
  52. package/src/resources/customers.ts +25 -0
  53. package/src/resources/invoices.ts +31 -0
  54. package/src/resources/merchants.ts +26 -0
  55. package/src/resources/payment-sessions.ts +41 -0
  56. package/src/resources/refunds.ts +36 -0
  57. package/src/resources/storefronts.ts +62 -0
  58. package/src/resources/subscription-plans.ts +32 -0
  59. package/src/resources/subscriptions.ts +37 -0
  60. package/src/resources/tokens.ts +70 -0
  61. package/src/resources/transactions.ts +20 -0
  62. package/src/resources/webhook-deliveries.ts +29 -0
  63. package/src/resources/webhook-endpoints.ts +56 -0
  64. package/src/webhooks.ts +64 -0
@@ -0,0 +1,439 @@
1
+ import { kindFromKey, modeFromKey } from '@strimz/shared-config';
2
+ import { paymentSessionSchema, subscriptionPlanSchema, tokenMetadataSchema, tokenPermitNonceSchema } from '@strimz/shared-types';
3
+ import { uuid } from '@strimz/shared-crypto';
4
+
5
+ // src/browser-client.ts
6
+
7
+ // src/errors.ts
8
+ var StrimzError = class extends Error {
9
+ code;
10
+ httpStatus;
11
+ requestId;
12
+ param;
13
+ details;
14
+ constructor(body, httpStatus) {
15
+ super(body.message);
16
+ this.name = "StrimzError";
17
+ this.code = body.code;
18
+ this.httpStatus = httpStatus;
19
+ this.requestId = body.requestId;
20
+ this.param = body.param;
21
+ this.details = body.details;
22
+ }
23
+ };
24
+ var StrimzAuthenticationError = class extends StrimzError {
25
+ constructor(body, httpStatus) {
26
+ super(body, httpStatus);
27
+ this.name = "StrimzAuthenticationError";
28
+ }
29
+ };
30
+ var StrimzPermissionError = class extends StrimzError {
31
+ constructor(body, httpStatus) {
32
+ super(body, httpStatus);
33
+ this.name = "StrimzPermissionError";
34
+ }
35
+ };
36
+ var StrimzValidationError = class extends StrimzError {
37
+ constructor(body, httpStatus) {
38
+ super(body, httpStatus);
39
+ this.name = "StrimzValidationError";
40
+ }
41
+ };
42
+ var StrimzNotFoundError = class extends StrimzError {
43
+ constructor(body, httpStatus) {
44
+ super(body, httpStatus);
45
+ this.name = "StrimzNotFoundError";
46
+ }
47
+ };
48
+ var StrimzIdempotencyError = class extends StrimzError {
49
+ constructor(body, httpStatus) {
50
+ super(body, httpStatus);
51
+ this.name = "StrimzIdempotencyError";
52
+ }
53
+ };
54
+ var StrimzRateLimitError = class extends StrimzError {
55
+ retryAfterMs;
56
+ constructor(body, httpStatus, retryAfterMs) {
57
+ super(body, httpStatus);
58
+ this.name = "StrimzRateLimitError";
59
+ this.retryAfterMs = retryAfterMs;
60
+ }
61
+ };
62
+ var StrimzNetworkError = class extends StrimzError {
63
+ cause;
64
+ constructor(message, cause) {
65
+ super({ code: "network_error", message });
66
+ this.name = "StrimzNetworkError";
67
+ this.cause = cause;
68
+ }
69
+ };
70
+ var StrimzTimeoutError = class extends StrimzError {
71
+ constructor(message) {
72
+ super({ code: "timeout", message });
73
+ this.name = "StrimzTimeoutError";
74
+ }
75
+ };
76
+ function classifyError(httpStatus, body, retryAfterMs) {
77
+ if (httpStatus === 401) return new StrimzAuthenticationError(body, httpStatus);
78
+ if (httpStatus === 403) return new StrimzPermissionError(body, httpStatus);
79
+ if (httpStatus === 404) return new StrimzNotFoundError(body, httpStatus);
80
+ if (httpStatus === 409 && body.code === "idempotency_error") {
81
+ return new StrimzIdempotencyError(body, httpStatus);
82
+ }
83
+ if (httpStatus === 422) return new StrimzValidationError(body, httpStatus);
84
+ if (httpStatus === 429) return new StrimzRateLimitError(body, httpStatus, retryAfterMs);
85
+ return new StrimzError(body, httpStatus);
86
+ }
87
+
88
+ // src/http/headers.ts
89
+ var HEADERS = {
90
+ authorization: "Authorization",
91
+ idempotencyKey: "X-Strimz-Idempotency-Key",
92
+ sdkName: "X-Strimz-Sdk",
93
+ sdkVersion: "X-Strimz-Sdk-Version",
94
+ sdkRuntime: "X-Strimz-Sdk-Runtime"
95
+ };
96
+ var SDK_NAME = "@strimz/sdk";
97
+ var SDK_VERSION = "0.0.0";
98
+ function buildBaseHeaders(apiKey, runtime) {
99
+ return {
100
+ [HEADERS.authorization]: `Bearer ${apiKey}`,
101
+ [HEADERS.sdkName]: SDK_NAME,
102
+ [HEADERS.sdkVersion]: SDK_VERSION,
103
+ [HEADERS.sdkRuntime]: runtime,
104
+ Accept: "application/json"
105
+ };
106
+ }
107
+
108
+ // src/http/fetcher.ts
109
+ var DEFAULT_TIMEOUT_MS = 3e4;
110
+ var DEFAULT_MAX_RETRIES = 3;
111
+ var DEFAULT_INITIAL_BACKOFF_MS = 250;
112
+ var Fetcher = class {
113
+ baseUrl;
114
+ baseHeaders;
115
+ timeoutMs;
116
+ maxRetries;
117
+ initialBackoffMs;
118
+ onRequest;
119
+ onResponse;
120
+ fetchImpl;
121
+ constructor(opts) {
122
+ this.baseUrl = opts.baseUrl.replace(/\/$/, "");
123
+ this.baseHeaders = opts.baseHeaders;
124
+ this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
125
+ this.maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
126
+ this.initialBackoffMs = opts.initialBackoffMs ?? DEFAULT_INITIAL_BACKOFF_MS;
127
+ this.onRequest = opts.onRequest;
128
+ this.onResponse = opts.onResponse;
129
+ this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
130
+ }
131
+ async request(spec) {
132
+ const url = this.buildUrl(spec.path, spec.query);
133
+ const idempotent = isIdempotent(spec);
134
+ const headers = { ...this.baseHeaders };
135
+ if (spec.body != null) headers["Content-Type"] = "application/json";
136
+ if (spec.idempotencyKey) headers[HEADERS.idempotencyKey] = spec.idempotencyKey;
137
+ let attempt = 0;
138
+ let lastErr;
139
+ while (attempt <= this.maxRetries) {
140
+ try {
141
+ this.onRequest?.({ method: spec.method, url, attempt });
142
+ const start = Date.now();
143
+ const res = await this.fetchWithTimeout(
144
+ url,
145
+ {
146
+ method: spec.method,
147
+ headers,
148
+ body: spec.body == null ? void 0 : JSON.stringify(spec.body)
149
+ },
150
+ spec.timeoutMs ?? this.timeoutMs
151
+ );
152
+ const ms = Date.now() - start;
153
+ this.onResponse?.({ method: spec.method, url, status: res.status, ms, attempt });
154
+ if (res.ok) {
155
+ if (res.status === 204) return void 0;
156
+ return await res.json();
157
+ }
158
+ const errorBody = await parseErrorBody(res);
159
+ const retryAfterMs = parseRetryAfter(res);
160
+ if (res.status === 429 && attempt < this.maxRetries) {
161
+ await delay(retryAfterMs ?? this.backoffFor(attempt));
162
+ attempt++;
163
+ continue;
164
+ }
165
+ if (res.status >= 500 && idempotent && attempt < this.maxRetries) {
166
+ await delay(this.backoffFor(attempt));
167
+ attempt++;
168
+ continue;
169
+ }
170
+ throw classifyError(res.status, errorBody, retryAfterMs);
171
+ } catch (err) {
172
+ if (err instanceof StrimzError) throw err;
173
+ lastErr = err;
174
+ if (!isNetworkLike(err) || attempt >= this.maxRetries) {
175
+ if (err instanceof StrimzTimeoutError) throw err;
176
+ throw new StrimzNetworkError(`Network error: ${describe(err)}`, err);
177
+ }
178
+ await delay(this.backoffFor(attempt));
179
+ attempt++;
180
+ }
181
+ }
182
+ throw new StrimzNetworkError(`Network error after ${this.maxRetries} retries`, lastErr);
183
+ }
184
+ async fetchWithTimeout(url, init, timeoutMs) {
185
+ const controller = new AbortController();
186
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
187
+ try {
188
+ return await this.fetchImpl(url, { ...init, signal: controller.signal });
189
+ } catch (err) {
190
+ if (isAbortError(err)) {
191
+ throw new StrimzTimeoutError(`Request timed out after ${timeoutMs}ms`);
192
+ }
193
+ throw err;
194
+ } finally {
195
+ clearTimeout(timer);
196
+ }
197
+ }
198
+ buildUrl(path, query) {
199
+ const base = `${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
200
+ if (!query) return base;
201
+ const usp = new URLSearchParams();
202
+ for (const [k, v] of Object.entries(query)) {
203
+ if (v == null) continue;
204
+ usp.append(k, String(v));
205
+ }
206
+ const qs = usp.toString();
207
+ return qs ? `${base}?${qs}` : base;
208
+ }
209
+ backoffFor(attempt) {
210
+ const expo = this.initialBackoffMs * Math.pow(2, attempt);
211
+ const jitter = Math.random() * this.initialBackoffMs;
212
+ return Math.min(expo + jitter, 8e3);
213
+ }
214
+ };
215
+ function isIdempotent(spec) {
216
+ if (spec.method === "GET" || spec.method === "DELETE") return true;
217
+ return spec.idempotencyKey != null;
218
+ }
219
+ async function parseErrorBody(res) {
220
+ try {
221
+ const json = await res.json();
222
+ if (typeof json === "object" && json !== null && "error" in json && json.error) {
223
+ return json.error;
224
+ }
225
+ if (typeof json === "object" && json !== null && "code" in json && "message" in json) {
226
+ return json;
227
+ }
228
+ } catch {
229
+ }
230
+ return { code: "api_error", message: `HTTP ${res.status}` };
231
+ }
232
+ function parseRetryAfter(res) {
233
+ const v = res.headers.get("Retry-After");
234
+ if (!v) return void 0;
235
+ const n = Number(v);
236
+ if (Number.isFinite(n)) return Math.max(0, n) * 1e3;
237
+ const date = Date.parse(v);
238
+ if (Number.isFinite(date)) return Math.max(0, date - Date.now());
239
+ return void 0;
240
+ }
241
+ function delay(ms) {
242
+ return new Promise((resolve) => setTimeout(resolve, ms));
243
+ }
244
+ function isAbortError(err) {
245
+ return err instanceof Error && err.name === "AbortError";
246
+ }
247
+ function isNetworkLike(err) {
248
+ if (err instanceof TypeError) return true;
249
+ if (err instanceof Error && /fetch|network|econn/i.test(err.message)) return true;
250
+ return false;
251
+ }
252
+ function describe(err) {
253
+ if (err instanceof Error) return err.message;
254
+ return String(err);
255
+ }
256
+ function generateIdempotencyKey() {
257
+ return `strimz_${uuid()}`;
258
+ }
259
+
260
+ // src/pagination.ts
261
+ var AutoPagingIterator = class {
262
+ constructor(fetchPage) {
263
+ this.fetchPage = fetchPage;
264
+ }
265
+ fetchPage;
266
+ async *[Symbol.asyncIterator]() {
267
+ let cursor = null;
268
+ let first = true;
269
+ while (first || cursor !== null) {
270
+ first = false;
271
+ const page = await this.fetchPage(cursor);
272
+ for (const item of page.data) {
273
+ yield item;
274
+ }
275
+ cursor = page.hasMore ? page.nextCursor : null;
276
+ }
277
+ }
278
+ async forEach(handler) {
279
+ for await (const item of this) {
280
+ await handler(item);
281
+ }
282
+ }
283
+ async toArray() {
284
+ const out = [];
285
+ for await (const item of this) out.push(item);
286
+ return out;
287
+ }
288
+ };
289
+
290
+ // src/resources/base-resource.ts
291
+ var BaseResource = class {
292
+ constructor(ctx) {
293
+ this.ctx = ctx;
294
+ }
295
+ ctx;
296
+ async get(path, schema, query) {
297
+ const data = await this.ctx.fetcher.request({ method: "GET", path, query });
298
+ return parse(data, schema);
299
+ }
300
+ async post(path, body, schema, options) {
301
+ const data = await this.ctx.fetcher.request({
302
+ method: "POST",
303
+ path,
304
+ body,
305
+ idempotencyKey: options?.idempotencyKey ?? generateIdempotencyKey(),
306
+ timeoutMs: options?.timeoutMs
307
+ });
308
+ return parse(data, schema);
309
+ }
310
+ async patch(path, body, schema, options) {
311
+ const data = await this.ctx.fetcher.request({
312
+ method: "PATCH",
313
+ path,
314
+ body,
315
+ idempotencyKey: options?.idempotencyKey ?? generateIdempotencyKey(),
316
+ timeoutMs: options?.timeoutMs
317
+ });
318
+ return parse(data, schema);
319
+ }
320
+ async delete(path, schema) {
321
+ const data = await this.ctx.fetcher.request({ method: "DELETE", path });
322
+ return parse(data, schema);
323
+ }
324
+ listPage(path, itemSchema, params) {
325
+ return this.ctx.fetcher.request({ method: "GET", path, query: toQuery(params) }).then((raw) => parsePage(raw, itemSchema));
326
+ }
327
+ listAuto(path, itemSchema, params) {
328
+ return new AutoPagingIterator(
329
+ (cursor) => this.listPage(path, itemSchema, { ...params, cursor })
330
+ );
331
+ }
332
+ };
333
+ function toQuery(params) {
334
+ if (!params) return {};
335
+ return params;
336
+ }
337
+ function parse(data, schema) {
338
+ return schema ? schema.parse(data) : data;
339
+ }
340
+ function parsePage(raw, itemSchema) {
341
+ const obj = raw;
342
+ const items = (obj?.data ?? []).map((d) => itemSchema.parse(d));
343
+ return {
344
+ data: items,
345
+ nextCursor: obj?.nextCursor ?? null,
346
+ hasMore: obj?.hasMore === true
347
+ };
348
+ }
349
+
350
+ // src/resources/checkout.ts
351
+ var CheckoutResource = class extends BaseResource {
352
+ /** Load a payment session by id (public — no merchant scoping). */
353
+ session(id) {
354
+ return this.get(`/v1/checkout/sessions/${encodeURIComponent(id)}`, paymentSessionSchema);
355
+ }
356
+ /** Load a subscription plan by id (public — no merchant scoping). */
357
+ plan(id) {
358
+ return this.get(`/v1/checkout/plans/${encodeURIComponent(id)}`, subscriptionPlanSchema);
359
+ }
360
+ };
361
+ var TokensResource = class extends BaseResource {
362
+ /**
363
+ * Fetch full metadata for a token. Throws via the underlying fetcher
364
+ * (404 → `StrimzNotFoundError`) if the token isn't whitelisted.
365
+ */
366
+ retrieve(address) {
367
+ return this.get(`/v1/tokens/${encodeURIComponent(address.toLowerCase())}`, tokenMetadataSchema);
368
+ }
369
+ /**
370
+ * Read an owner's current EIP-2612 permit nonce. Call this
371
+ * immediately before signing a Permit — the token contract rejects
372
+ * stale nonces, and the value advances on every successful permit.
373
+ */
374
+ permitNonce(address, owner) {
375
+ return this.get(
376
+ `/v1/tokens/${encodeURIComponent(address.toLowerCase())}/permit-nonce`,
377
+ tokenPermitNonceSchema,
378
+ { owner: owner.toLowerCase() }
379
+ );
380
+ }
381
+ };
382
+ function selectPaymentPath(meta) {
383
+ return meta.capabilities.transferAuth3009 ? "pay_with_authorization" : "approve_then_pay";
384
+ }
385
+ function selectSubscriptionPath(meta) {
386
+ return meta.capabilities.permit2612 ? "permit_and_create_subscription" : "approve_then_create_subscription";
387
+ }
388
+
389
+ // src/browser-client.ts
390
+ var DEFAULT_BASE_URL = "https://api.strimz.io";
391
+ var StrimzBrowserClient = class {
392
+ mode;
393
+ /**
394
+ * Public hosted-checkout reads — payment sessions and subscription
395
+ * plans by id. Backed by the `/v1/checkout/*` namespace on the API,
396
+ * which is intentionally unauthenticated.
397
+ */
398
+ checkout;
399
+ /** Token metadata + EIP-2612 permit nonce lookup. */
400
+ tokens;
401
+ constructor(options) {
402
+ const key = options.publishableKey;
403
+ if (!key || typeof key !== "string") {
404
+ throw new StrimzAuthenticationError(
405
+ { code: "authentication_error", message: "publishableKey is required" },
406
+ 401
407
+ );
408
+ }
409
+ if (kindFromKey(key) !== "publishable") {
410
+ throw new StrimzAuthenticationError(
411
+ {
412
+ code: "authentication_error",
413
+ message: "StrimzBrowserClient must be initialised with a publishable key (pk_test_... / pk_live_...). Never expose secret keys to a browser."
414
+ },
415
+ 401
416
+ );
417
+ }
418
+ const mode = modeFromKey(key);
419
+ if (mode == null) {
420
+ throw new StrimzAuthenticationError(
421
+ { code: "authentication_error", message: "Unrecognised API key prefix" },
422
+ 401
423
+ );
424
+ }
425
+ this.mode = mode;
426
+ const fetcher = new Fetcher({
427
+ baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
428
+ baseHeaders: buildBaseHeaders(key, "browser"),
429
+ timeoutMs: options.timeoutMs,
430
+ maxRetries: 2
431
+ });
432
+ this.checkout = new CheckoutResource({ fetcher });
433
+ this.tokens = new TokensResource({ fetcher });
434
+ }
435
+ };
436
+
437
+ export { StrimzBrowserClient, selectPaymentPath, selectSubscriptionPath };
438
+ //# sourceMappingURL=browser-client.js.map
439
+ //# sourceMappingURL=browser-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/http/headers.ts","../src/http/fetcher.ts","../src/idempotency.ts","../src/pagination.ts","../src/resources/base-resource.ts","../src/resources/checkout.ts","../src/resources/tokens.ts","../src/browser-client.ts"],"names":[],"mappings":"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","file":"browser-client.js","sourcesContent":["/**\n * Error hierarchy for the Strimz SDK.\n *\n * Every error thrown by the SDK extends `StrimzError`. The SDK never\n * resolves to `{ ok: false }` — it throws. This matches the Stripe / GitHub\n * SDK convention and keeps call sites linear.\n */\n\nexport type StrimzErrorCode =\n | 'authentication_error'\n | 'permission_denied'\n | 'invalid_request'\n | 'not_found'\n | 'idempotency_error'\n | 'rate_limited'\n | 'mode_mismatch'\n | 'merchant_not_found'\n | 'merchant_inactive'\n | 'token_not_whitelisted'\n | 'compliance_blocked'\n | 'session_expired'\n | 'session_invalid_state'\n | 'webhook_signature_invalid'\n | 'api_error'\n | 'network_error'\n | 'timeout'\n | 'parse_error'\n | 'unknown'\n\nexport interface StrimzErrorBody {\n code: StrimzErrorCode\n message: string\n param?: string\n requestId?: string\n details?: Record<string, unknown>\n}\n\nexport class StrimzError extends Error {\n public readonly code: StrimzErrorCode\n public readonly httpStatus: number | undefined\n public readonly requestId: string | undefined\n public readonly param: string | undefined\n public readonly details: Record<string, unknown> | undefined\n\n constructor(body: StrimzErrorBody, httpStatus?: number) {\n super(body.message)\n this.name = 'StrimzError'\n this.code = body.code\n this.httpStatus = httpStatus\n this.requestId = body.requestId\n this.param = body.param\n this.details = body.details\n }\n}\n\nexport class StrimzAuthenticationError extends StrimzError {\n constructor(body: StrimzErrorBody, httpStatus?: number) {\n super(body, httpStatus)\n this.name = 'StrimzAuthenticationError'\n }\n}\n\nexport class StrimzPermissionError extends StrimzError {\n constructor(body: StrimzErrorBody, httpStatus?: number) {\n super(body, httpStatus)\n this.name = 'StrimzPermissionError'\n }\n}\n\nexport class StrimzValidationError extends StrimzError {\n constructor(body: StrimzErrorBody, httpStatus?: number) {\n super(body, httpStatus)\n this.name = 'StrimzValidationError'\n }\n}\n\nexport class StrimzNotFoundError extends StrimzError {\n constructor(body: StrimzErrorBody, httpStatus?: number) {\n super(body, httpStatus)\n this.name = 'StrimzNotFoundError'\n }\n}\n\nexport class StrimzIdempotencyError extends StrimzError {\n constructor(body: StrimzErrorBody, httpStatus?: number) {\n super(body, httpStatus)\n this.name = 'StrimzIdempotencyError'\n }\n}\n\nexport class StrimzRateLimitError extends StrimzError {\n public readonly retryAfterMs: number | undefined\n constructor(body: StrimzErrorBody, httpStatus?: number, retryAfterMs?: number) {\n super(body, httpStatus)\n this.name = 'StrimzRateLimitError'\n this.retryAfterMs = retryAfterMs\n }\n}\n\nexport class StrimzNetworkError extends StrimzError {\n public override readonly cause: unknown\n constructor(message: string, cause: unknown) {\n super({ code: 'network_error', message })\n this.name = 'StrimzNetworkError'\n this.cause = cause\n }\n}\n\nexport class StrimzTimeoutError extends StrimzError {\n constructor(message: string) {\n super({ code: 'timeout', message })\n this.name = 'StrimzTimeoutError'\n }\n}\n\nexport class StrimzModeMismatchError extends StrimzError {\n constructor(message: string) {\n super({ code: 'mode_mismatch', message })\n this.name = 'StrimzModeMismatchError'\n }\n}\n\n/** Map an HTTP status + body to the right StrimzError subclass. */\nexport function classifyError(\n httpStatus: number,\n body: StrimzErrorBody,\n retryAfterMs?: number,\n): StrimzError {\n if (httpStatus === 401) return new StrimzAuthenticationError(body, httpStatus)\n if (httpStatus === 403) return new StrimzPermissionError(body, httpStatus)\n if (httpStatus === 404) return new StrimzNotFoundError(body, httpStatus)\n if (httpStatus === 409 && body.code === 'idempotency_error') {\n return new StrimzIdempotencyError(body, httpStatus)\n }\n if (httpStatus === 422) return new StrimzValidationError(body, httpStatus)\n if (httpStatus === 429) return new StrimzRateLimitError(body, httpStatus, retryAfterMs)\n return new StrimzError(body, httpStatus)\n}\n","/**\n * Strimz HTTP header conventions.\n *\n * `Authorization: Bearer <secret_key>` — primary auth.\n * `X-Strimz-Idempotency-Key` — mutating calls.\n * `X-Strimz-Sdk` — telemetry.\n * `X-Strimz-Sdk-Version` — telemetry.\n */\n\nexport const HEADERS = {\n authorization: 'Authorization',\n idempotencyKey: 'X-Strimz-Idempotency-Key',\n requestId: 'X-Strimz-Request-Id',\n sdkName: 'X-Strimz-Sdk',\n sdkVersion: 'X-Strimz-Sdk-Version',\n sdkRuntime: 'X-Strimz-Sdk-Runtime',\n} as const\n\nexport const SDK_NAME = '@strimz/sdk'\n\n/** The SDK version. Updated by the build pipeline if a version is published. */\nexport const SDK_VERSION = '0.0.0'\n\nexport function buildBaseHeaders(apiKey: string, runtime: string): Record<string, string> {\n return {\n [HEADERS.authorization]: `Bearer ${apiKey}`,\n [HEADERS.sdkName]: SDK_NAME,\n [HEADERS.sdkVersion]: SDK_VERSION,\n [HEADERS.sdkRuntime]: runtime,\n Accept: 'application/json',\n }\n}\n","/**\n * Fetch wrapper with retry, idempotency, and Strimz error parsing.\n *\n * Retries on:\n * - Network failures (TypeError on fetch).\n * - 5xx responses for idempotent methods (GET, POST with idempotency key).\n * - 429 with Retry-After.\n *\n * Does NOT retry on:\n * - 4xx other than 429 (caller's bug).\n * - 5xx for non-idempotent calls without an idempotency key.\n */\n\nimport {\n classifyError,\n StrimzError,\n StrimzNetworkError,\n StrimzTimeoutError,\n type StrimzErrorBody,\n} from '../errors.js'\nimport { HEADERS } from './headers.js'\n\nexport interface FetcherOptions {\n baseUrl: string\n baseHeaders: Record<string, string>\n /** Default timeout per attempt, milliseconds. */\n timeoutMs?: number\n /** How many retries before giving up. */\n maxRetries?: number\n /** Initial backoff in ms; doubled with jitter on each retry. */\n initialBackoffMs?: number\n /** Optional logger. */\n onRequest?: (info: { method: string; url: string; attempt: number }) => void\n onResponse?: (info: {\n method: string\n url: string\n status: number\n ms: number\n attempt: number\n }) => void\n /** Override the global fetch (for tests / Edge polyfills). */\n fetch?: typeof globalThis.fetch\n}\n\nexport interface RequestSpec {\n method: 'GET' | 'POST' | 'PATCH' | 'DELETE'\n path: string\n query?: Record<string, string | number | boolean | null | undefined>\n body?: unknown\n idempotencyKey?: string\n /** Per-call timeout override. */\n timeoutMs?: number\n}\n\nconst DEFAULT_TIMEOUT_MS = 30_000\nconst DEFAULT_MAX_RETRIES = 3\nconst DEFAULT_INITIAL_BACKOFF_MS = 250\n\nexport class Fetcher {\n private readonly baseUrl: string\n private readonly baseHeaders: Record<string, string>\n private readonly timeoutMs: number\n private readonly maxRetries: number\n private readonly initialBackoffMs: number\n private readonly onRequest: FetcherOptions['onRequest']\n private readonly onResponse: FetcherOptions['onResponse']\n private readonly fetchImpl: typeof globalThis.fetch\n\n constructor(opts: FetcherOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, '')\n this.baseHeaders = opts.baseHeaders\n this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS\n this.maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES\n this.initialBackoffMs = opts.initialBackoffMs ?? DEFAULT_INITIAL_BACKOFF_MS\n this.onRequest = opts.onRequest\n this.onResponse = opts.onResponse\n this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis)\n }\n\n async request<T>(spec: RequestSpec): Promise<T> {\n const url = this.buildUrl(spec.path, spec.query)\n const idempotent = isIdempotent(spec)\n const headers: Record<string, string> = { ...this.baseHeaders }\n if (spec.body != null) headers['Content-Type'] = 'application/json'\n if (spec.idempotencyKey) headers[HEADERS.idempotencyKey] = spec.idempotencyKey\n\n let attempt = 0\n let lastErr: unknown\n while (attempt <= this.maxRetries) {\n try {\n this.onRequest?.({ method: spec.method, url, attempt })\n const start = Date.now()\n const res = await this.fetchWithTimeout(\n url,\n {\n method: spec.method,\n headers,\n body: spec.body == null ? undefined : JSON.stringify(spec.body),\n },\n spec.timeoutMs ?? this.timeoutMs,\n )\n const ms = Date.now() - start\n this.onResponse?.({ method: spec.method, url, status: res.status, ms, attempt })\n\n if (res.ok) {\n if (res.status === 204) return undefined as T\n return (await res.json()) as T\n }\n\n const errorBody = await parseErrorBody(res)\n const retryAfterMs = parseRetryAfter(res)\n\n // 429 — back off and retry up to maxRetries.\n if (res.status === 429 && attempt < this.maxRetries) {\n await delay(retryAfterMs ?? this.backoffFor(attempt))\n attempt++\n continue\n }\n // 5xx — retry only if idempotent.\n if (res.status >= 500 && idempotent && attempt < this.maxRetries) {\n await delay(this.backoffFor(attempt))\n attempt++\n continue\n }\n\n throw classifyError(res.status, errorBody, retryAfterMs)\n } catch (err) {\n if (err instanceof StrimzError) throw err\n lastErr = err\n if (!isNetworkLike(err) || attempt >= this.maxRetries) {\n if (err instanceof StrimzTimeoutError) throw err\n throw new StrimzNetworkError(`Network error: ${describe(err)}`, err)\n }\n await delay(this.backoffFor(attempt))\n attempt++\n }\n }\n throw new StrimzNetworkError(`Network error after ${this.maxRetries} retries`, lastErr)\n }\n\n private async fetchWithTimeout(\n url: string,\n init: RequestInit,\n timeoutMs: number,\n ): Promise<Response> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n try {\n return await this.fetchImpl(url, { ...init, signal: controller.signal })\n } catch (err) {\n if (isAbortError(err)) {\n throw new StrimzTimeoutError(`Request timed out after ${timeoutMs}ms`)\n }\n throw err\n } finally {\n clearTimeout(timer)\n }\n }\n\n private buildUrl(path: string, query?: RequestSpec['query']): string {\n const base = `${this.baseUrl}${path.startsWith('/') ? path : `/${path}`}`\n if (!query) return base\n const usp = new URLSearchParams()\n for (const [k, v] of Object.entries(query)) {\n if (v == null) continue\n usp.append(k, String(v))\n }\n const qs = usp.toString()\n return qs ? `${base}?${qs}` : base\n }\n\n private backoffFor(attempt: number): number {\n const expo = this.initialBackoffMs * Math.pow(2, attempt)\n const jitter = Math.random() * this.initialBackoffMs\n return Math.min(expo + jitter, 8_000)\n }\n}\n\nfunction isIdempotent(spec: RequestSpec): boolean {\n if (spec.method === 'GET' || spec.method === 'DELETE') return true\n return spec.idempotencyKey != null\n}\n\nasync function parseErrorBody(res: Response): Promise<StrimzErrorBody> {\n try {\n const json = (await res.json()) as { error?: StrimzErrorBody } | StrimzErrorBody\n if (typeof json === 'object' && json !== null && 'error' in json && json.error) {\n return json.error\n }\n if (typeof json === 'object' && json !== null && 'code' in json && 'message' in json) {\n return json as StrimzErrorBody\n }\n } catch {\n // fall through\n }\n return { code: 'api_error', message: `HTTP ${res.status}` }\n}\n\nfunction parseRetryAfter(res: Response): number | undefined {\n const v = res.headers.get('Retry-After')\n if (!v) return undefined\n const n = Number(v)\n if (Number.isFinite(n)) return Math.max(0, n) * 1_000\n const date = Date.parse(v)\n if (Number.isFinite(date)) return Math.max(0, date - Date.now())\n return undefined\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof Error && err.name === 'AbortError'\n}\n\nfunction isNetworkLike(err: unknown): boolean {\n if (err instanceof TypeError) return true // fetch network failures\n if (err instanceof Error && /fetch|network|econn/i.test(err.message)) return true\n return false\n}\n\nfunction describe(err: unknown): string {\n if (err instanceof Error) return err.message\n return String(err)\n}\n","import { uuid } from '@strimz/shared-crypto'\n\n/**\n * Generate an idempotency key for a mutating SDK call.\n * Stripe convention: a UUID-like value with a stable prefix the merchant\n * can grep for in logs.\n */\nexport function generateIdempotencyKey(): string {\n return `strimz_${uuid()}`\n}\n\n/** RFC 4122 UUID-shaped, optionally with the strimz_ prefix. */\nconst IDEMPOTENCY_KEY_PATTERN =\n /^(strimz_)?[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/\n\nexport function isValidIdempotencyKey(key: string): boolean {\n if (typeof key !== 'string') return false\n if (key.length > 255) return false\n return IDEMPOTENCY_KEY_PATTERN.test(key)\n}\n","/**\n * Cursor-based pagination, identical shape to the API's list responses.\n */\n\nexport interface Page<T> {\n data: T[]\n nextCursor: string | null\n hasMore: boolean\n}\n\nexport interface PaginationParams {\n limit?: number\n cursor?: string | null\n}\n\n/**\n * Async-iterable wrapper that auto-paginates through every page of a list.\n *\n * for await (const tx of strimz.transactions.listAll()) { ... }\n */\nexport class AutoPagingIterator<T> implements AsyncIterable<T> {\n constructor(private readonly fetchPage: (cursor: string | null) => Promise<Page<T>>) {}\n\n async *[Symbol.asyncIterator](): AsyncIterator<T> {\n let cursor: string | null = null\n let first = true\n while (first || cursor !== null) {\n first = false\n const page: Page<T> = await this.fetchPage(cursor)\n for (const item of page.data) {\n yield item\n }\n cursor = page.hasMore ? page.nextCursor : null\n }\n }\n\n async forEach(handler: (item: T) => void | Promise<void>): Promise<void> {\n for await (const item of this) {\n await handler(item)\n }\n }\n\n async toArray(): Promise<T[]> {\n const out: T[] = []\n for await (const item of this) out.push(item)\n return out\n }\n}\n","/**\n * Base class every resource extends. Centralises endpoint plumbing so\n * resource classes are tiny declarative wrappers.\n */\n\nimport type { z } from 'zod'\nimport type { Fetcher, RequestSpec } from '../http/fetcher.js'\nimport { generateIdempotencyKey } from '../idempotency.js'\nimport { AutoPagingIterator, type Page, type PaginationParams } from '../pagination.js'\n\ntype AnySchema = z.ZodTypeAny\ntype Inferred<S extends AnySchema> = z.output<S>\n\nexport interface ResourceContext {\n fetcher: Fetcher\n}\n\nexport interface RequestOptions {\n /** Override or supply the idempotency key for a mutating call. */\n idempotencyKey?: string\n /** Per-request timeout in ms. */\n timeoutMs?: number\n}\n\nexport abstract class BaseResource {\n constructor(protected readonly ctx: ResourceContext) {}\n\n protected async get<S extends AnySchema>(\n path: string,\n schema?: S,\n query?: RequestSpec['query'],\n ): Promise<Inferred<S>> {\n const data = await this.ctx.fetcher.request<unknown>({ method: 'GET', path, query })\n return parse(data, schema)\n }\n\n protected async post<S extends AnySchema>(\n path: string,\n body: unknown,\n schema?: S,\n options?: RequestOptions,\n ): Promise<Inferred<S>> {\n const data = await this.ctx.fetcher.request<unknown>({\n method: 'POST',\n path,\n body,\n idempotencyKey: options?.idempotencyKey ?? generateIdempotencyKey(),\n timeoutMs: options?.timeoutMs,\n })\n return parse(data, schema)\n }\n\n protected async patch<S extends AnySchema>(\n path: string,\n body: unknown,\n schema?: S,\n options?: RequestOptions,\n ): Promise<Inferred<S>> {\n const data = await this.ctx.fetcher.request<unknown>({\n method: 'PATCH',\n path,\n body,\n idempotencyKey: options?.idempotencyKey ?? generateIdempotencyKey(),\n timeoutMs: options?.timeoutMs,\n })\n return parse(data, schema)\n }\n\n protected async delete<S extends AnySchema>(path: string, schema?: S): Promise<Inferred<S>> {\n const data = await this.ctx.fetcher.request<unknown>({ method: 'DELETE', path })\n return parse(data, schema)\n }\n\n protected listPage<S extends AnySchema>(\n path: string,\n itemSchema: S,\n params?: PaginationParams | Record<string, ScalarParam>,\n ): Promise<Page<Inferred<S>>> {\n return this.ctx.fetcher\n .request<unknown>({ method: 'GET', path, query: toQuery(params) })\n .then((raw) => parsePage(raw, itemSchema))\n }\n\n protected listAuto<S extends AnySchema>(\n path: string,\n itemSchema: S,\n params?: Record<string, ScalarParam>,\n ): AutoPagingIterator<Inferred<S>> {\n return new AutoPagingIterator((cursor) =>\n this.listPage(path, itemSchema, { ...params, cursor }),\n )\n }\n}\n\ntype ScalarParam = string | number | boolean | null | undefined\n\nfunction toQuery(\n params: PaginationParams | Record<string, ScalarParam> | undefined,\n): Record<string, ScalarParam> {\n if (!params) return {}\n return params as Record<string, ScalarParam>\n}\n\nfunction parse<S extends AnySchema>(data: unknown, schema?: S): Inferred<S> {\n return (schema ? schema.parse(data) : data) as Inferred<S>\n}\n\nfunction parsePage<S extends AnySchema>(raw: unknown, itemSchema: S): Page<Inferred<S>> {\n const obj = raw as { data?: unknown[]; nextCursor?: string | null; hasMore?: boolean }\n const items = (obj?.data ?? []).map((d) => itemSchema.parse(d) as Inferred<S>)\n return {\n data: items,\n nextCursor: obj?.nextCursor ?? null,\n hasMore: obj?.hasMore === true,\n }\n}\n","import {\n paymentSessionSchema,\n subscriptionPlanSchema,\n type PaymentSession,\n type SubscriptionPlan,\n} from '@strimz/shared-types'\nimport { BaseResource } from './base-resource.js'\n\n/**\n * Public hosted-checkout reads.\n *\n * Backed by the `/v1/checkout/*` namespace on the Strimz API, which\n * is intentionally unauthenticated — session and plan records are\n * what a merchant offers to payers, so a payer landing on a checkout\n * URL must be able to load the terms without holding any API key.\n *\n * Use this resource (via `StrimzBrowserClient.checkout`) from the\n * browser. The merchant-scoped `paymentSessions` / `subscriptionPlans`\n * resources on `StrimzClient` remain the right call from server-side\n * code with a secret key.\n */\nexport class CheckoutResource extends BaseResource {\n /** Load a payment session by id (public — no merchant scoping). */\n session(id: string): Promise<PaymentSession> {\n return this.get(`/v1/checkout/sessions/${encodeURIComponent(id)}`, paymentSessionSchema)\n }\n\n /** Load a subscription plan by id (public — no merchant scoping). */\n plan(id: string): Promise<SubscriptionPlan> {\n return this.get(`/v1/checkout/plans/${encodeURIComponent(id)}`, subscriptionPlanSchema)\n }\n}\n","import {\n tokenMetadataSchema,\n tokenPermitNonceSchema,\n type TokenMetadata,\n type TokenPermitNonce,\n} from '@strimz/shared-types'\nimport { BaseResource } from './base-resource.js'\n\n/**\n * Token metadata + capability lookup.\n *\n * The two endpoints are public on the API (no key required) — token\n * metadata is purely chain-derived, has no PII, and is what the\n * browser SDK consults to pick which meta-tx path to take for a\n * given token. Bundled here so consumers don't have to write the HTTP\n * fetch themselves.\n */\nexport class TokensResource extends BaseResource {\n /**\n * Fetch full metadata for a token. Throws via the underlying fetcher\n * (404 → `StrimzNotFoundError`) if the token isn't whitelisted.\n */\n retrieve(address: string): Promise<TokenMetadata> {\n return this.get(`/v1/tokens/${encodeURIComponent(address.toLowerCase())}`, tokenMetadataSchema)\n }\n\n /**\n * Read an owner's current EIP-2612 permit nonce. Call this\n * immediately before signing a Permit — the token contract rejects\n * stale nonces, and the value advances on every successful permit.\n */\n permitNonce(address: string, owner: string): Promise<TokenPermitNonce> {\n return this.get(\n `/v1/tokens/${encodeURIComponent(address.toLowerCase())}/permit-nonce`,\n tokenPermitNonceSchema,\n { owner: owner.toLowerCase() },\n )\n }\n}\n\n/**\n * Path selector — decides which meta-tx flow to take given a token's\n * capabilities and the action a merchant wants to perform.\n *\n * The choice is unambiguous in 99% of cases:\n * - One-shot pay → EIP-3009 (preferred). Falls back to\n * approve+pay if the token has neither.\n * - Subscription enrol → EIP-2612 (the only meta-tx path that\n * grants the recurring allowance subscribers\n * need). If unavailable, the merchant must\n * use the classic approve+create flow.\n *\n * Returned `path` values are strings (not enums) so future schemes\n * can extend the union without breaking existing call sites.\n */\nexport type RelayPath =\n | 'pay_with_authorization'\n | 'permit_and_create_subscription'\n | 'approve_then_pay'\n | 'approve_then_create_subscription'\n\nexport function selectPaymentPath(meta: TokenMetadata): RelayPath {\n return meta.capabilities.transferAuth3009 ? 'pay_with_authorization' : 'approve_then_pay'\n}\n\nexport function selectSubscriptionPath(meta: TokenMetadata): RelayPath {\n return meta.capabilities.permit2612\n ? 'permit_and_create_subscription'\n : 'approve_then_create_subscription'\n}\n","/**\n * StrimzBrowserClient — the publishable-key, browser-safe SDK entry point.\n *\n * Used by `@strimz/sdk-react` and any other browser code that should\n * never see a secret key. Surfaces a strict subset of resource methods —\n * only those safe to call from a browser with a `pk_test_...` or\n * `pk_live_...` key.\n */\n\nimport { kindFromKey, modeFromKey, type ApiKeyMode } from '@strimz/shared-config'\nimport { Fetcher } from './http/fetcher.js'\nimport { buildBaseHeaders } from './http/headers.js'\nimport { StrimzAuthenticationError } from './errors.js'\nimport { CheckoutResource } from './resources/checkout.js'\nimport {\n TokensResource,\n selectPaymentPath,\n selectSubscriptionPath,\n type RelayPath,\n} from './resources/tokens.js'\n\nexport interface StrimzBrowserClientOptions {\n /** Publishable key — `pk_test_...` or `pk_live_...`. */\n publishableKey: string\n /** Override the API base URL. */\n baseUrl?: string\n /** Per-request timeout in milliseconds. Default 30s. */\n timeoutMs?: number\n}\n\nconst DEFAULT_BASE_URL = 'https://api.strimz.io'\n\n/**\n * Browser-safe Strimz client.\n *\n * Designed for hosted-checkout state polling and the React component\n * family. Read-only on most resources. Refuses a secret key.\n *\n * The `tokens` resource + `selectPaymentPath` / `selectSubscriptionPath`\n * selectors are the core of the capability-detection layer: given a\n * token, the SDK asks the backend which meta-tx flows the token\n * supports, and the selectors map that to a `RelayPath` the checkout\n * UI uses to decide which typed-data to build.\n */\nexport class StrimzBrowserClient {\n public readonly mode: ApiKeyMode\n /**\n * Public hosted-checkout reads — payment sessions and subscription\n * plans by id. Backed by the `/v1/checkout/*` namespace on the API,\n * which is intentionally unauthenticated.\n */\n public readonly checkout: CheckoutResource\n /** Token metadata + EIP-2612 permit nonce lookup. */\n public readonly tokens: TokensResource\n\n constructor(options: StrimzBrowserClientOptions) {\n const key = options.publishableKey\n if (!key || typeof key !== 'string') {\n throw new StrimzAuthenticationError(\n { code: 'authentication_error', message: 'publishableKey is required' },\n 401,\n )\n }\n if (kindFromKey(key) !== 'publishable') {\n throw new StrimzAuthenticationError(\n {\n code: 'authentication_error',\n message:\n 'StrimzBrowserClient must be initialised with a publishable key (pk_test_... / pk_live_...). Never expose secret keys to a browser.',\n },\n 401,\n )\n }\n const mode = modeFromKey(key)\n if (mode == null) {\n throw new StrimzAuthenticationError(\n { code: 'authentication_error', message: 'Unrecognised API key prefix' },\n 401,\n )\n }\n this.mode = mode\n\n const fetcher = new Fetcher({\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\n baseHeaders: buildBaseHeaders(key, 'browser'),\n timeoutMs: options.timeoutMs,\n maxRetries: 2,\n })\n this.checkout = new CheckoutResource({ fetcher })\n this.tokens = new TokensResource({ fetcher })\n }\n}\n\n// Re-export the selectors + path type so consumers don't need a\n// second import: `import { StrimzBrowserClient, selectPaymentPath }\n// from '@strimz/sdk/browser'`.\nexport { selectPaymentPath, selectSubscriptionPath, type RelayPath }\n"]}
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+
3
+ // src/eip712/receive-with-authorization.ts
4
+ var RECEIVE_WITH_AUTHORIZATION_TYPES = {
5
+ ReceiveWithAuthorization: [
6
+ { name: "from", type: "address" },
7
+ { name: "to", type: "address" },
8
+ { name: "value", type: "uint256" },
9
+ { name: "validAfter", type: "uint256" },
10
+ { name: "validBefore", type: "uint256" },
11
+ { name: "nonce", type: "bytes32" }
12
+ ]
13
+ };
14
+ function buildReceiveWithAuthorizationTypedData(params) {
15
+ return {
16
+ domain: {
17
+ name: params.tokenName,
18
+ version: params.tokenVersion,
19
+ chainId: params.chainId,
20
+ verifyingContract: params.token
21
+ },
22
+ types: RECEIVE_WITH_AUTHORIZATION_TYPES,
23
+ primaryType: "ReceiveWithAuthorization",
24
+ message: {
25
+ from: params.from,
26
+ to: params.to,
27
+ value: params.value,
28
+ validAfter: params.validAfter,
29
+ validBefore: params.validBefore,
30
+ nonce: params.nonce
31
+ }
32
+ };
33
+ }
34
+
35
+ // src/eip712/permit.ts
36
+ var PERMIT_TYPES = {
37
+ Permit: [
38
+ { name: "owner", type: "address" },
39
+ { name: "spender", type: "address" },
40
+ { name: "value", type: "uint256" },
41
+ { name: "nonce", type: "uint256" },
42
+ { name: "deadline", type: "uint256" }
43
+ ]
44
+ };
45
+ function buildPermitTypedData(params) {
46
+ return {
47
+ domain: {
48
+ name: params.tokenName,
49
+ version: params.tokenVersion,
50
+ chainId: params.chainId,
51
+ verifyingContract: params.token
52
+ },
53
+ types: PERMIT_TYPES,
54
+ primaryType: "Permit",
55
+ message: {
56
+ owner: params.owner,
57
+ spender: params.spender,
58
+ value: params.value,
59
+ nonce: params.nonce,
60
+ deadline: params.deadline
61
+ }
62
+ };
63
+ }
64
+
65
+ exports.PERMIT_TYPES = PERMIT_TYPES;
66
+ exports.RECEIVE_WITH_AUTHORIZATION_TYPES = RECEIVE_WITH_AUTHORIZATION_TYPES;
67
+ exports.buildPermitTypedData = buildPermitTypedData;
68
+ exports.buildReceiveWithAuthorizationTypedData = buildReceiveWithAuthorizationTypedData;
69
+ //# sourceMappingURL=eip712.cjs.map
70
+ //# sourceMappingURL=eip712.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/eip712/receive-with-authorization.ts","../src/eip712/permit.ts"],"names":[],"mappings":";;;AA8CO,IAAM,gCAAA,GAAmC;AAAA,EAC9C,wBAAA,EAA0B;AAAA,IACxB,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAU;AAAA,IAChC,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,SAAA,EAAU;AAAA,IAC9B,EAAE,IAAA,EAAM,OAAA,EAAS,IAAA,EAAM,SAAA,EAAU;AAAA,IACjC,EAAE,IAAA,EAAM,YAAA,EAAc,IAAA,EAAM,SAAA,EAAU;AAAA,IACtC,EAAE,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,SAAA,EAAU;AAAA,IACvC,EAAE,IAAA,EAAM,OAAA,EAAS,IAAA,EAAM,SAAA;AAAU;AAErC;AAWO,SAAS,uCACd,MAAA,EAC6C;AAC7C,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ;AAAA,MACN,MAAM,MAAA,CAAO,SAAA;AAAA,MACb,SAAS,MAAA,CAAO,YAAA;AAAA,MAChB,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,mBAAmB,MAAA,CAAO;AAAA,KAC5B;AAAA,IACA,KAAA,EAAO,gCAAA;AAAA,IACP,WAAA,EAAa,0BAAA;AAAA,IACb,OAAA,EAAS;AAAA,MACP,MAAM,MAAA,CAAO,IAAA;AAAA,MACb,IAAI,MAAA,CAAO,EAAA;AAAA,MACX,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,YAAY,MAAA,CAAO,UAAA;AAAA,MACnB,aAAa,MAAA,CAAO,WAAA;AAAA,MACpB,OAAO,MAAA,CAAO;AAAA;AAChB,GACF;AACF;;;AC/CO,IAAM,YAAA,GAAe;AAAA,EAC1B,MAAA,EAAQ;AAAA,IACN,EAAE,IAAA,EAAM,OAAA,EAAS,IAAA,EAAM,SAAA,EAAU;AAAA,IACjC,EAAE,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,SAAA,EAAU;AAAA,IACnC,EAAE,IAAA,EAAM,OAAA,EAAS,IAAA,EAAM,SAAA,EAAU;AAAA,IACjC,EAAE,IAAA,EAAM,OAAA,EAAS,IAAA,EAAM,SAAA,EAAU;AAAA,IACjC,EAAE,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,SAAA;AAAU;AAExC;AAOO,SAAS,qBAAqB,MAAA,EAAiD;AACpF,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ;AAAA,MACN,MAAM,MAAA,CAAO,SAAA;AAAA,MACb,SAAS,MAAA,CAAO,YAAA;AAAA,MAChB,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,mBAAmB,MAAA,CAAO;AAAA,KAC5B;AAAA,IACA,KAAA,EAAO,YAAA;AAAA,IACP,WAAA,EAAa,QAAA;AAAA,IACb,OAAA,EAAS;AAAA,MACP,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,UAAU,MAAA,CAAO;AAAA;AACnB,GACF;AACF","file":"eip712.cjs","sourcesContent":["import type { Eip712TypedData } from './types.js'\n\n/**\n * Inputs for the EIP-3009 ReceiveWithAuthorization typed-data.\n *\n * - `chainId` is the EVM chain id (Arc Testnet = 5042002).\n * - `token` is the ERC-20 contract whose `receiveWithAuthorization` is\n * being invoked — usually USDC at `0x36...` on Arc.\n * - `tokenName` and `tokenVersion` form the EIP-712 domain. Real USDC\n * on most chains uses `name=\"USD Coin\"` and `version=\"2\"`; tests\n * use whatever the mock token reports. Always read these from the\n * token contract at runtime to avoid drift.\n * - `from` is the payer; the wallet that produces the signature must\n * match this address.\n * - `to` is the recipient of the funds — for Strimz this is the\n * StrimzPayments contract address (the contract pulls funds into\n * itself, then forwards the fee + net split).\n * - `value` is the gross amount in token base units.\n * - `validAfter` / `validBefore` are unix-second timestamps bounding\n * the signature's validity. Strimz's default checkout window is\n * 5 minutes; integrators may widen this for usage-based billing.\n * - `nonce` is a single-use 32-byte value. Generate with crypto.randomBytes\n * (server) or crypto.getRandomValues (browser). The token contract\n * tracks `(authorizer, nonce) -> used` and rejects replays.\n */\nexport interface ReceiveWithAuthorizationParams {\n chainId: number\n token: `0x${string}`\n tokenName: string\n tokenVersion: string\n from: `0x${string}`\n to: `0x${string}`\n value: bigint\n validAfter: bigint\n validBefore: bigint\n nonce: `0x${string}`\n}\n\n/**\n * EIP-712 type definition for `ReceiveWithAuthorization`. Stable —\n * shared by every EIP-3009 implementation (USDC, EURC, etc.).\n *\n * Exported so consumers can introspect or extend with sibling\n * primitive types (e.g. for x402 batched signing schemes that wrap\n * multiple authorizations in one signature).\n */\nexport const RECEIVE_WITH_AUTHORIZATION_TYPES = {\n ReceiveWithAuthorization: [\n { name: 'from', type: 'address' },\n { name: 'to', type: 'address' },\n { name: 'value', type: 'uint256' },\n { name: 'validAfter', type: 'uint256' },\n { name: 'validBefore', type: 'uint256' },\n { name: 'nonce', type: 'bytes32' },\n ],\n} as const\n\n/**\n * Build the typed-data structure for an EIP-3009\n * `ReceiveWithAuthorization` signature. Returns the canonical shape\n * compatible with viem, ethers, Privy, and Reown.\n *\n * Pass the result to `walletClient.signTypedData(typedData)` (viem)\n * or `signer._signTypedData(domain, types, message)` (ethers) — the\n * SDK does not bind to a specific signer.\n */\nexport function buildReceiveWithAuthorizationTypedData(\n params: ReceiveWithAuthorizationParams,\n): Eip712TypedData<'ReceiveWithAuthorization'> {\n return {\n domain: {\n name: params.tokenName,\n version: params.tokenVersion,\n chainId: params.chainId,\n verifyingContract: params.token,\n },\n types: RECEIVE_WITH_AUTHORIZATION_TYPES,\n primaryType: 'ReceiveWithAuthorization',\n message: {\n from: params.from,\n to: params.to,\n value: params.value,\n validAfter: params.validAfter,\n validBefore: params.validBefore,\n nonce: params.nonce,\n },\n }\n}\n","import type { Eip712TypedData } from './types.js'\n\n/**\n * Inputs for the EIP-2612 Permit typed-data.\n *\n * - `chainId`, `token`, `tokenName`, `tokenVersion` form the EIP-712\n * domain (same shape as the EIP-3009 builder).\n * - `owner` is the token holder authorising the allowance — must match\n * the signing wallet.\n * - `spender` is the contract that will pull funds — for Strimz\n * subscriptions this is the StrimzSubscriptions contract.\n * - `value` is the allowance to grant in token base units.\n * `type(uint256).max` produces an unlimited allowance and is the\n * common case for subscription enrolment.\n * - `nonce` is the owner's *current* `nonces(owner)` reading from the\n * token contract. The SDK does not fetch this — the caller is\n * expected to have just queried it. Race-free: the token rejects\n * stale nonces, so a concurrent permit on the same owner just\n * causes one to fail predictably.\n * - `deadline` is the unix-second timestamp after which the permit\n * expires. Strimz default for subscription enrolment is 24h —\n * enough headroom for a slow merchant submit pipeline without\n * leaving an indefinite signature window.\n */\nexport interface PermitParams {\n chainId: number\n token: `0x${string}`\n tokenName: string\n tokenVersion: string\n owner: `0x${string}`\n spender: `0x${string}`\n value: bigint\n nonce: bigint\n deadline: bigint\n}\n\n/**\n * EIP-712 type definition for `Permit`. Stable across every EIP-2612\n * implementation (USDC, EURC, DAI v2, etc.).\n */\nexport const PERMIT_TYPES = {\n Permit: [\n { name: 'owner', type: 'address' },\n { name: 'spender', type: 'address' },\n { name: 'value', type: 'uint256' },\n { name: 'nonce', type: 'uint256' },\n { name: 'deadline', type: 'uint256' },\n ],\n} as const\n\n/**\n * Build the typed-data structure for an EIP-2612 `Permit` signature.\n * Returns the canonical shape compatible with viem, ethers, Privy,\n * and Reown.\n */\nexport function buildPermitTypedData(params: PermitParams): Eip712TypedData<'Permit'> {\n return {\n domain: {\n name: params.tokenName,\n version: params.tokenVersion,\n chainId: params.chainId,\n verifyingContract: params.token,\n },\n types: PERMIT_TYPES,\n primaryType: 'Permit',\n message: {\n owner: params.owner,\n spender: params.spender,\n value: params.value,\n nonce: params.nonce,\n deadline: params.deadline,\n },\n }\n}\n"]}