@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
package/dist/index.js ADDED
@@ -0,0 +1,806 @@
1
+ import { kindFromKey, modeFromKey } from '@strimz/shared-config';
2
+ import { webhookEventSchema, merchantSchema, updateMerchantInputSchema, changeTierInputSchema, apiKeySchema, createApiKeyInputSchema, createApiKeyOutputSchema, customerSchema, upsertCustomerInputSchema, createPaymentSessionInputSchema, paymentSessionSchema, transactionSchema, createSubscriptionPlanInputSchema, subscriptionPlanSchema, createSubscriptionInputSchema, subscriptionSchema, cancelSubscriptionInputSchema, createRefundInputSchema, refundSchema, submitRefundSignatureInputSchema, createWebhookEndpointInputSchema, createWebhookEndpointOutputSchema, webhookEndpointSchema, webhookDeliverySchema, createInvoiceInputSchema, invoiceSchema, storefrontSchema, createStorefrontInputSchema, storefrontProductSchema, createStorefrontProductInputSchema, agentMerchantConfigSchema, updateAgentConfigInputSchema, agentActivityLogSchema, agentJobSchema, createAgentJobInputSchema, tokenMetadataSchema, tokenPermitNonceSchema } from '@strimz/shared-types';
3
+ import { uuid } from '@strimz/shared-crypto';
4
+ export { signWebhookPayload, verifyWebhookSignature } from '@strimz/shared-crypto';
5
+
6
+ // src/client.ts
7
+
8
+ // src/errors.ts
9
+ var StrimzError = class extends Error {
10
+ code;
11
+ httpStatus;
12
+ requestId;
13
+ param;
14
+ details;
15
+ constructor(body, httpStatus) {
16
+ super(body.message);
17
+ this.name = "StrimzError";
18
+ this.code = body.code;
19
+ this.httpStatus = httpStatus;
20
+ this.requestId = body.requestId;
21
+ this.param = body.param;
22
+ this.details = body.details;
23
+ }
24
+ };
25
+ var StrimzAuthenticationError = class extends StrimzError {
26
+ constructor(body, httpStatus) {
27
+ super(body, httpStatus);
28
+ this.name = "StrimzAuthenticationError";
29
+ }
30
+ };
31
+ var StrimzPermissionError = class extends StrimzError {
32
+ constructor(body, httpStatus) {
33
+ super(body, httpStatus);
34
+ this.name = "StrimzPermissionError";
35
+ }
36
+ };
37
+ var StrimzValidationError = class extends StrimzError {
38
+ constructor(body, httpStatus) {
39
+ super(body, httpStatus);
40
+ this.name = "StrimzValidationError";
41
+ }
42
+ };
43
+ var StrimzNotFoundError = class extends StrimzError {
44
+ constructor(body, httpStatus) {
45
+ super(body, httpStatus);
46
+ this.name = "StrimzNotFoundError";
47
+ }
48
+ };
49
+ var StrimzIdempotencyError = class extends StrimzError {
50
+ constructor(body, httpStatus) {
51
+ super(body, httpStatus);
52
+ this.name = "StrimzIdempotencyError";
53
+ }
54
+ };
55
+ var StrimzRateLimitError = class extends StrimzError {
56
+ retryAfterMs;
57
+ constructor(body, httpStatus, retryAfterMs) {
58
+ super(body, httpStatus);
59
+ this.name = "StrimzRateLimitError";
60
+ this.retryAfterMs = retryAfterMs;
61
+ }
62
+ };
63
+ var StrimzNetworkError = class extends StrimzError {
64
+ cause;
65
+ constructor(message, cause) {
66
+ super({ code: "network_error", message });
67
+ this.name = "StrimzNetworkError";
68
+ this.cause = cause;
69
+ }
70
+ };
71
+ var StrimzTimeoutError = class extends StrimzError {
72
+ constructor(message) {
73
+ super({ code: "timeout", message });
74
+ this.name = "StrimzTimeoutError";
75
+ }
76
+ };
77
+ var StrimzModeMismatchError = class extends StrimzError {
78
+ constructor(message) {
79
+ super({ code: "mode_mismatch", message });
80
+ this.name = "StrimzModeMismatchError";
81
+ }
82
+ };
83
+ function classifyError(httpStatus, body, retryAfterMs) {
84
+ if (httpStatus === 401) return new StrimzAuthenticationError(body, httpStatus);
85
+ if (httpStatus === 403) return new StrimzPermissionError(body, httpStatus);
86
+ if (httpStatus === 404) return new StrimzNotFoundError(body, httpStatus);
87
+ if (httpStatus === 409 && body.code === "idempotency_error") {
88
+ return new StrimzIdempotencyError(body, httpStatus);
89
+ }
90
+ if (httpStatus === 422) return new StrimzValidationError(body, httpStatus);
91
+ if (httpStatus === 429) return new StrimzRateLimitError(body, httpStatus, retryAfterMs);
92
+ return new StrimzError(body, httpStatus);
93
+ }
94
+
95
+ // src/http/headers.ts
96
+ var HEADERS = {
97
+ authorization: "Authorization",
98
+ idempotencyKey: "X-Strimz-Idempotency-Key",
99
+ sdkName: "X-Strimz-Sdk",
100
+ sdkVersion: "X-Strimz-Sdk-Version",
101
+ sdkRuntime: "X-Strimz-Sdk-Runtime"
102
+ };
103
+ var SDK_NAME = "@strimz/sdk";
104
+ var SDK_VERSION = "0.0.0";
105
+ function buildBaseHeaders(apiKey, runtime) {
106
+ return {
107
+ [HEADERS.authorization]: `Bearer ${apiKey}`,
108
+ [HEADERS.sdkName]: SDK_NAME,
109
+ [HEADERS.sdkVersion]: SDK_VERSION,
110
+ [HEADERS.sdkRuntime]: runtime,
111
+ Accept: "application/json"
112
+ };
113
+ }
114
+
115
+ // src/http/fetcher.ts
116
+ var DEFAULT_TIMEOUT_MS = 3e4;
117
+ var DEFAULT_MAX_RETRIES = 3;
118
+ var DEFAULT_INITIAL_BACKOFF_MS = 250;
119
+ var Fetcher = class {
120
+ baseUrl;
121
+ baseHeaders;
122
+ timeoutMs;
123
+ maxRetries;
124
+ initialBackoffMs;
125
+ onRequest;
126
+ onResponse;
127
+ fetchImpl;
128
+ constructor(opts) {
129
+ this.baseUrl = opts.baseUrl.replace(/\/$/, "");
130
+ this.baseHeaders = opts.baseHeaders;
131
+ this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
132
+ this.maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
133
+ this.initialBackoffMs = opts.initialBackoffMs ?? DEFAULT_INITIAL_BACKOFF_MS;
134
+ this.onRequest = opts.onRequest;
135
+ this.onResponse = opts.onResponse;
136
+ this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
137
+ }
138
+ async request(spec) {
139
+ const url = this.buildUrl(spec.path, spec.query);
140
+ const idempotent = isIdempotent(spec);
141
+ const headers = { ...this.baseHeaders };
142
+ if (spec.body != null) headers["Content-Type"] = "application/json";
143
+ if (spec.idempotencyKey) headers[HEADERS.idempotencyKey] = spec.idempotencyKey;
144
+ let attempt = 0;
145
+ let lastErr;
146
+ while (attempt <= this.maxRetries) {
147
+ try {
148
+ this.onRequest?.({ method: spec.method, url, attempt });
149
+ const start = Date.now();
150
+ const res = await this.fetchWithTimeout(
151
+ url,
152
+ {
153
+ method: spec.method,
154
+ headers,
155
+ body: spec.body == null ? void 0 : JSON.stringify(spec.body)
156
+ },
157
+ spec.timeoutMs ?? this.timeoutMs
158
+ );
159
+ const ms = Date.now() - start;
160
+ this.onResponse?.({ method: spec.method, url, status: res.status, ms, attempt });
161
+ if (res.ok) {
162
+ if (res.status === 204) return void 0;
163
+ return await res.json();
164
+ }
165
+ const errorBody = await parseErrorBody(res);
166
+ const retryAfterMs = parseRetryAfter(res);
167
+ if (res.status === 429 && attempt < this.maxRetries) {
168
+ await delay(retryAfterMs ?? this.backoffFor(attempt));
169
+ attempt++;
170
+ continue;
171
+ }
172
+ if (res.status >= 500 && idempotent && attempt < this.maxRetries) {
173
+ await delay(this.backoffFor(attempt));
174
+ attempt++;
175
+ continue;
176
+ }
177
+ throw classifyError(res.status, errorBody, retryAfterMs);
178
+ } catch (err) {
179
+ if (err instanceof StrimzError) throw err;
180
+ lastErr = err;
181
+ if (!isNetworkLike(err) || attempt >= this.maxRetries) {
182
+ if (err instanceof StrimzTimeoutError) throw err;
183
+ throw new StrimzNetworkError(`Network error: ${describe(err)}`, err);
184
+ }
185
+ await delay(this.backoffFor(attempt));
186
+ attempt++;
187
+ }
188
+ }
189
+ throw new StrimzNetworkError(`Network error after ${this.maxRetries} retries`, lastErr);
190
+ }
191
+ async fetchWithTimeout(url, init, timeoutMs) {
192
+ const controller = new AbortController();
193
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
194
+ try {
195
+ return await this.fetchImpl(url, { ...init, signal: controller.signal });
196
+ } catch (err) {
197
+ if (isAbortError(err)) {
198
+ throw new StrimzTimeoutError(`Request timed out after ${timeoutMs}ms`);
199
+ }
200
+ throw err;
201
+ } finally {
202
+ clearTimeout(timer);
203
+ }
204
+ }
205
+ buildUrl(path, query) {
206
+ const base = `${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
207
+ if (!query) return base;
208
+ const usp = new URLSearchParams();
209
+ for (const [k, v] of Object.entries(query)) {
210
+ if (v == null) continue;
211
+ usp.append(k, String(v));
212
+ }
213
+ const qs = usp.toString();
214
+ return qs ? `${base}?${qs}` : base;
215
+ }
216
+ backoffFor(attempt) {
217
+ const expo = this.initialBackoffMs * Math.pow(2, attempt);
218
+ const jitter = Math.random() * this.initialBackoffMs;
219
+ return Math.min(expo + jitter, 8e3);
220
+ }
221
+ };
222
+ function isIdempotent(spec) {
223
+ if (spec.method === "GET" || spec.method === "DELETE") return true;
224
+ return spec.idempotencyKey != null;
225
+ }
226
+ async function parseErrorBody(res) {
227
+ try {
228
+ const json = await res.json();
229
+ if (typeof json === "object" && json !== null && "error" in json && json.error) {
230
+ return json.error;
231
+ }
232
+ if (typeof json === "object" && json !== null && "code" in json && "message" in json) {
233
+ return json;
234
+ }
235
+ } catch {
236
+ }
237
+ return { code: "api_error", message: `HTTP ${res.status}` };
238
+ }
239
+ function parseRetryAfter(res) {
240
+ const v = res.headers.get("Retry-After");
241
+ if (!v) return void 0;
242
+ const n = Number(v);
243
+ if (Number.isFinite(n)) return Math.max(0, n) * 1e3;
244
+ const date = Date.parse(v);
245
+ if (Number.isFinite(date)) return Math.max(0, date - Date.now());
246
+ return void 0;
247
+ }
248
+ function delay(ms) {
249
+ return new Promise((resolve) => setTimeout(resolve, ms));
250
+ }
251
+ function isAbortError(err) {
252
+ return err instanceof Error && err.name === "AbortError";
253
+ }
254
+ function isNetworkLike(err) {
255
+ if (err instanceof TypeError) return true;
256
+ if (err instanceof Error && /fetch|network|econn/i.test(err.message)) return true;
257
+ return false;
258
+ }
259
+ function describe(err) {
260
+ if (err instanceof Error) return err.message;
261
+ return String(err);
262
+ }
263
+ function generateIdempotencyKey() {
264
+ return `strimz_${uuid()}`;
265
+ }
266
+ var IDEMPOTENCY_KEY_PATTERN = /^(strimz_)?[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
267
+ function isValidIdempotencyKey(key) {
268
+ if (typeof key !== "string") return false;
269
+ if (key.length > 255) return false;
270
+ return IDEMPOTENCY_KEY_PATTERN.test(key);
271
+ }
272
+
273
+ // src/pagination.ts
274
+ var AutoPagingIterator = class {
275
+ constructor(fetchPage) {
276
+ this.fetchPage = fetchPage;
277
+ }
278
+ fetchPage;
279
+ async *[Symbol.asyncIterator]() {
280
+ let cursor = null;
281
+ let first = true;
282
+ while (first || cursor !== null) {
283
+ first = false;
284
+ const page = await this.fetchPage(cursor);
285
+ for (const item of page.data) {
286
+ yield item;
287
+ }
288
+ cursor = page.hasMore ? page.nextCursor : null;
289
+ }
290
+ }
291
+ async forEach(handler) {
292
+ for await (const item of this) {
293
+ await handler(item);
294
+ }
295
+ }
296
+ async toArray() {
297
+ const out = [];
298
+ for await (const item of this) out.push(item);
299
+ return out;
300
+ }
301
+ };
302
+
303
+ // src/resources/base-resource.ts
304
+ var BaseResource = class {
305
+ constructor(ctx) {
306
+ this.ctx = ctx;
307
+ }
308
+ ctx;
309
+ async get(path, schema, query) {
310
+ const data = await this.ctx.fetcher.request({ method: "GET", path, query });
311
+ return parse(data, schema);
312
+ }
313
+ async post(path, body, schema, options) {
314
+ const data = await this.ctx.fetcher.request({
315
+ method: "POST",
316
+ path,
317
+ body,
318
+ idempotencyKey: options?.idempotencyKey ?? generateIdempotencyKey(),
319
+ timeoutMs: options?.timeoutMs
320
+ });
321
+ return parse(data, schema);
322
+ }
323
+ async patch(path, body, schema, options) {
324
+ const data = await this.ctx.fetcher.request({
325
+ method: "PATCH",
326
+ path,
327
+ body,
328
+ idempotencyKey: options?.idempotencyKey ?? generateIdempotencyKey(),
329
+ timeoutMs: options?.timeoutMs
330
+ });
331
+ return parse(data, schema);
332
+ }
333
+ async delete(path, schema) {
334
+ const data = await this.ctx.fetcher.request({ method: "DELETE", path });
335
+ return parse(data, schema);
336
+ }
337
+ listPage(path, itemSchema, params) {
338
+ return this.ctx.fetcher.request({ method: "GET", path, query: toQuery(params) }).then((raw) => parsePage(raw, itemSchema));
339
+ }
340
+ listAuto(path, itemSchema, params) {
341
+ return new AutoPagingIterator(
342
+ (cursor) => this.listPage(path, itemSchema, { ...params, cursor })
343
+ );
344
+ }
345
+ };
346
+ function toQuery(params) {
347
+ if (!params) return {};
348
+ return params;
349
+ }
350
+ function parse(data, schema) {
351
+ return schema ? schema.parse(data) : data;
352
+ }
353
+ function parsePage(raw, itemSchema) {
354
+ const obj = raw;
355
+ const items = (obj?.data ?? []).map((d) => itemSchema.parse(d));
356
+ return {
357
+ data: items,
358
+ nextCursor: obj?.nextCursor ?? null,
359
+ hasMore: obj?.hasMore === true
360
+ };
361
+ }
362
+
363
+ // src/resources/merchants.ts
364
+ var MerchantsResource = class extends BaseResource {
365
+ /** The merchant the API key belongs to. */
366
+ me() {
367
+ return this.get("/v1/merchants/me", merchantSchema);
368
+ }
369
+ update(input, options) {
370
+ updateMerchantInputSchema.parse(input);
371
+ return this.patch("/v1/merchants/me", input, merchantSchema, options);
372
+ }
373
+ changeTier(input, options) {
374
+ changeTierInputSchema.parse(input);
375
+ return this.post("/v1/merchants/me/tier", input, merchantSchema, options);
376
+ }
377
+ };
378
+ var ApiKeysResource = class extends BaseResource {
379
+ list(params) {
380
+ return this.listPage("/v1/api-keys", apiKeySchema, params);
381
+ }
382
+ retrieve(id) {
383
+ return this.get(`/v1/api-keys/${encodeURIComponent(id)}`, apiKeySchema);
384
+ }
385
+ create(input, options) {
386
+ createApiKeyInputSchema.parse(input);
387
+ return this.post("/v1/api-keys", input, createApiKeyOutputSchema, options);
388
+ }
389
+ revoke(id, options) {
390
+ return this.post(`/v1/api-keys/${encodeURIComponent(id)}/revoke`, {}, apiKeySchema, options);
391
+ }
392
+ };
393
+ var CustomersResource = class extends BaseResource {
394
+ retrieve(id) {
395
+ return this.get(`/v1/customers/${encodeURIComponent(id)}`, customerSchema);
396
+ }
397
+ list(params) {
398
+ return this.listPage("/v1/customers", customerSchema, params);
399
+ }
400
+ upsert(input, options) {
401
+ upsertCustomerInputSchema.parse(input);
402
+ return this.post("/v1/customers", input, customerSchema, options);
403
+ }
404
+ };
405
+ var PaymentSessionsResource = class extends BaseResource {
406
+ create(input, options) {
407
+ createPaymentSessionInputSchema.parse(input);
408
+ return this.post("/v1/payment-sessions", input, paymentSessionSchema, options);
409
+ }
410
+ retrieve(id) {
411
+ return this.get(`/v1/payment-sessions/${encodeURIComponent(id)}`, paymentSessionSchema);
412
+ }
413
+ list(params) {
414
+ return this.listPage("/v1/payment-sessions", paymentSessionSchema, params);
415
+ }
416
+ cancel(id, options) {
417
+ return this.post(
418
+ `/v1/payment-sessions/${encodeURIComponent(id)}/cancel`,
419
+ {},
420
+ paymentSessionSchema,
421
+ options
422
+ );
423
+ }
424
+ expire(id, options) {
425
+ return this.post(
426
+ `/v1/payment-sessions/${encodeURIComponent(id)}/expire`,
427
+ {},
428
+ paymentSessionSchema,
429
+ options
430
+ );
431
+ }
432
+ };
433
+ var TransactionsResource = class extends BaseResource {
434
+ retrieve(id) {
435
+ return this.get(`/v1/transactions/${encodeURIComponent(id)}`, transactionSchema);
436
+ }
437
+ list(params) {
438
+ return this.listPage("/v1/transactions", transactionSchema, params);
439
+ }
440
+ };
441
+ var SubscriptionPlansResource = class extends BaseResource {
442
+ create(input, options) {
443
+ createSubscriptionPlanInputSchema.parse(input);
444
+ return this.post("/v1/subscription-plans", input, subscriptionPlanSchema, options);
445
+ }
446
+ retrieve(id) {
447
+ return this.get(`/v1/subscription-plans/${encodeURIComponent(id)}`, subscriptionPlanSchema);
448
+ }
449
+ list(params) {
450
+ return this.listPage("/v1/subscription-plans", subscriptionPlanSchema, params);
451
+ }
452
+ archive(id, options) {
453
+ return this.post(
454
+ `/v1/subscription-plans/${encodeURIComponent(id)}/archive`,
455
+ {},
456
+ subscriptionPlanSchema,
457
+ options
458
+ );
459
+ }
460
+ };
461
+ var SubscriptionsResource = class extends BaseResource {
462
+ create(input, options) {
463
+ createSubscriptionInputSchema.parse(input);
464
+ return this.post("/v1/subscriptions", input, subscriptionSchema, options);
465
+ }
466
+ retrieve(id) {
467
+ return this.get(`/v1/subscriptions/${encodeURIComponent(id)}`, subscriptionSchema);
468
+ }
469
+ list(params) {
470
+ return this.listPage("/v1/subscriptions", subscriptionSchema, params);
471
+ }
472
+ cancel(input, options) {
473
+ cancelSubscriptionInputSchema.parse(input);
474
+ return this.post(
475
+ `/v1/subscriptions/${encodeURIComponent(input.id)}/cancel`,
476
+ input,
477
+ subscriptionSchema,
478
+ options
479
+ );
480
+ }
481
+ };
482
+ var RefundsResource = class extends BaseResource {
483
+ create(input, options) {
484
+ createRefundInputSchema.parse(input);
485
+ return this.post("/v1/refunds", input, refundSchema, options);
486
+ }
487
+ retrieve(id) {
488
+ return this.get(`/v1/refunds/${encodeURIComponent(id)}`, refundSchema);
489
+ }
490
+ list(params) {
491
+ return this.listPage("/v1/refunds", refundSchema, params);
492
+ }
493
+ /** Record the on-chain refund tx after the merchant signs from their wallet. */
494
+ submitSignature(input, options) {
495
+ submitRefundSignatureInputSchema.parse(input);
496
+ return this.post(
497
+ `/v1/refunds/${encodeURIComponent(input.id)}/signature`,
498
+ input,
499
+ refundSchema,
500
+ options
501
+ );
502
+ }
503
+ };
504
+ var WebhookEndpointsResource = class extends BaseResource {
505
+ create(input, options) {
506
+ createWebhookEndpointInputSchema.parse(input);
507
+ return this.post("/v1/webhook-endpoints", input, createWebhookEndpointOutputSchema, options);
508
+ }
509
+ retrieve(id) {
510
+ return this.get(`/v1/webhook-endpoints/${encodeURIComponent(id)}`, webhookEndpointSchema);
511
+ }
512
+ list(params) {
513
+ return this.listPage("/v1/webhook-endpoints", webhookEndpointSchema, params);
514
+ }
515
+ disable(id, options) {
516
+ return this.post(
517
+ `/v1/webhook-endpoints/${encodeURIComponent(id)}/disable`,
518
+ {},
519
+ webhookEndpointSchema,
520
+ options
521
+ );
522
+ }
523
+ enable(id, options) {
524
+ return this.post(
525
+ `/v1/webhook-endpoints/${encodeURIComponent(id)}/enable`,
526
+ {},
527
+ webhookEndpointSchema,
528
+ options
529
+ );
530
+ }
531
+ /** Rotates the signing secret. Returns the new full secret exactly once. */
532
+ rotateSecret(id, options) {
533
+ return this.post(
534
+ `/v1/webhook-endpoints/${encodeURIComponent(id)}/rotate-secret`,
535
+ {},
536
+ createWebhookEndpointOutputSchema,
537
+ options
538
+ );
539
+ }
540
+ };
541
+ var WebhookDeliveriesResource = class extends BaseResource {
542
+ retrieve(id) {
543
+ return this.get(`/v1/webhook-deliveries/${encodeURIComponent(id)}`, webhookDeliverySchema);
544
+ }
545
+ list(params) {
546
+ return this.listPage("/v1/webhook-deliveries", webhookDeliverySchema, params);
547
+ }
548
+ /** Manually replay a permanently-failed delivery. */
549
+ replay(id, options) {
550
+ return this.post(
551
+ `/v1/webhook-deliveries/${encodeURIComponent(id)}/replay`,
552
+ {},
553
+ webhookDeliverySchema,
554
+ options
555
+ );
556
+ }
557
+ };
558
+ var InvoicesResource = class extends BaseResource {
559
+ create(input, options) {
560
+ createInvoiceInputSchema.parse(input);
561
+ return this.post("/v1/invoices", input, invoiceSchema, options);
562
+ }
563
+ retrieve(id) {
564
+ return this.get(`/v1/invoices/${encodeURIComponent(id)}`, invoiceSchema);
565
+ }
566
+ list(params) {
567
+ return this.listPage("/v1/invoices", invoiceSchema, params);
568
+ }
569
+ send(id, options) {
570
+ return this.post(`/v1/invoices/${encodeURIComponent(id)}/send`, {}, invoiceSchema, options);
571
+ }
572
+ void(id, options) {
573
+ return this.post(`/v1/invoices/${encodeURIComponent(id)}/void`, {}, invoiceSchema, options);
574
+ }
575
+ };
576
+ var StorefrontsResource = class extends BaseResource {
577
+ /** Retrieve the merchant's own storefront. */
578
+ retrieve() {
579
+ return this.get("/v1/storefront", storefrontSchema);
580
+ }
581
+ upsert(input, options) {
582
+ createStorefrontInputSchema.parse(input);
583
+ return this.post("/v1/storefront", input, storefrontSchema, options);
584
+ }
585
+ publish(options) {
586
+ return this.post("/v1/storefront/publish", {}, storefrontSchema, options);
587
+ }
588
+ archive(options) {
589
+ return this.post("/v1/storefront/archive", {}, storefrontSchema, options);
590
+ }
591
+ // ----- Products -----
592
+ listProducts(params) {
593
+ return this.listPage("/v1/storefront/products", storefrontProductSchema, params);
594
+ }
595
+ createProduct(input, options) {
596
+ createStorefrontProductInputSchema.parse(input);
597
+ return this.post("/v1/storefront/products", input, storefrontProductSchema, options);
598
+ }
599
+ retrieveProduct(productId) {
600
+ return this.get(
601
+ `/v1/storefront/products/${encodeURIComponent(productId)}`,
602
+ storefrontProductSchema
603
+ );
604
+ }
605
+ archiveProduct(productId, options) {
606
+ return this.post(
607
+ `/v1/storefront/products/${encodeURIComponent(productId)}/archive`,
608
+ {},
609
+ storefrontProductSchema,
610
+ options
611
+ );
612
+ }
613
+ };
614
+ var AgentsResource = class extends BaseResource {
615
+ /** Retrieve the merchant's AutoPay Agent config. */
616
+ retrieveConfig() {
617
+ return this.get("/v1/agents/config", agentMerchantConfigSchema);
618
+ }
619
+ updateConfig(input, options) {
620
+ updateAgentConfigInputSchema.parse(input);
621
+ return this.patch("/v1/agents/config", input, agentMerchantConfigSchema, options);
622
+ }
623
+ listActivity(params) {
624
+ return this.listPage("/v1/agents/activity", agentActivityLogSchema, params);
625
+ }
626
+ // ----- ERC-8183 jobs -----
627
+ listJobs(params) {
628
+ return this.listPage("/v1/agents/jobs", agentJobSchema, params);
629
+ }
630
+ retrieveJob(id) {
631
+ return this.get(`/v1/agents/jobs/${encodeURIComponent(id)}`, agentJobSchema);
632
+ }
633
+ createJob(input, options) {
634
+ createAgentJobInputSchema.parse(input);
635
+ return this.post("/v1/agents/jobs", input, agentJobSchema, options);
636
+ }
637
+ approveJob(id, options) {
638
+ return this.post(
639
+ `/v1/agents/jobs/${encodeURIComponent(id)}/approve`,
640
+ {},
641
+ agentJobSchema,
642
+ options
643
+ );
644
+ }
645
+ };
646
+
647
+ // src/client.ts
648
+ var DEFAULT_BASE_URL = "https://api.strimz.io";
649
+ var StrimzClient = class {
650
+ /** Resolved mode — `test` or `live`. Derived from the API key prefix. */
651
+ mode;
652
+ merchants;
653
+ apiKeys;
654
+ customers;
655
+ paymentSessions;
656
+ transactions;
657
+ subscriptionPlans;
658
+ subscriptions;
659
+ refunds;
660
+ webhookEndpoints;
661
+ webhookDeliveries;
662
+ invoices;
663
+ storefronts;
664
+ agents;
665
+ constructor(options) {
666
+ if (!options.apiKey || typeof options.apiKey !== "string") {
667
+ throw new StrimzAuthenticationError(
668
+ { code: "authentication_error", message: "apiKey is required" },
669
+ 401
670
+ );
671
+ }
672
+ if (kindFromKey(options.apiKey) !== "secret") {
673
+ throw new StrimzAuthenticationError(
674
+ {
675
+ code: "authentication_error",
676
+ message: "StrimzClient requires a secret key (sk_test_... or sk_live_...). Use StrimzBrowserClient for publishable keys."
677
+ },
678
+ 401
679
+ );
680
+ }
681
+ const mode = modeFromKey(options.apiKey);
682
+ if (mode == null) {
683
+ throw new StrimzAuthenticationError(
684
+ { code: "authentication_error", message: "Unrecognised API key prefix" },
685
+ 401
686
+ );
687
+ }
688
+ this.mode = mode;
689
+ const fetcher = new Fetcher({
690
+ baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
691
+ baseHeaders: buildBaseHeaders(options.apiKey, detectRuntime()),
692
+ timeoutMs: options.timeoutMs,
693
+ maxRetries: options.maxRetries,
694
+ onRequest: options.onRequest,
695
+ onResponse: options.onResponse,
696
+ fetch: options.fetch
697
+ });
698
+ const ctx = { fetcher };
699
+ this.merchants = new MerchantsResource(ctx);
700
+ this.apiKeys = new ApiKeysResource(ctx);
701
+ this.customers = new CustomersResource(ctx);
702
+ this.paymentSessions = new PaymentSessionsResource(ctx);
703
+ this.transactions = new TransactionsResource(ctx);
704
+ this.subscriptionPlans = new SubscriptionPlansResource(ctx);
705
+ this.subscriptions = new SubscriptionsResource(ctx);
706
+ this.refunds = new RefundsResource(ctx);
707
+ this.webhookEndpoints = new WebhookEndpointsResource(ctx);
708
+ this.webhookDeliveries = new WebhookDeliveriesResource(ctx);
709
+ this.invoices = new InvoicesResource(ctx);
710
+ this.storefronts = new StorefrontsResource(ctx);
711
+ this.agents = new AgentsResource(ctx);
712
+ }
713
+ };
714
+ function detectRuntime() {
715
+ if (typeof EdgeRuntime !== "undefined") return "edge";
716
+ if (typeof process !== "undefined" && process.versions?.node)
717
+ return `node-${process.versions.node}`;
718
+ if (typeof navigator !== "undefined" && navigator.userAgent) return "browser";
719
+ return "unknown";
720
+ }
721
+ var CheckoutResource = class extends BaseResource {
722
+ /** Load a payment session by id (public — no merchant scoping). */
723
+ session(id) {
724
+ return this.get(`/v1/checkout/sessions/${encodeURIComponent(id)}`, paymentSessionSchema);
725
+ }
726
+ /** Load a subscription plan by id (public — no merchant scoping). */
727
+ plan(id) {
728
+ return this.get(`/v1/checkout/plans/${encodeURIComponent(id)}`, subscriptionPlanSchema);
729
+ }
730
+ };
731
+ var TokensResource = class extends BaseResource {
732
+ /**
733
+ * Fetch full metadata for a token. Throws via the underlying fetcher
734
+ * (404 → `StrimzNotFoundError`) if the token isn't whitelisted.
735
+ */
736
+ retrieve(address) {
737
+ return this.get(`/v1/tokens/${encodeURIComponent(address.toLowerCase())}`, tokenMetadataSchema);
738
+ }
739
+ /**
740
+ * Read an owner's current EIP-2612 permit nonce. Call this
741
+ * immediately before signing a Permit — the token contract rejects
742
+ * stale nonces, and the value advances on every successful permit.
743
+ */
744
+ permitNonce(address, owner) {
745
+ return this.get(
746
+ `/v1/tokens/${encodeURIComponent(address.toLowerCase())}/permit-nonce`,
747
+ tokenPermitNonceSchema,
748
+ { owner: owner.toLowerCase() }
749
+ );
750
+ }
751
+ };
752
+
753
+ // src/browser-client.ts
754
+ var DEFAULT_BASE_URL2 = "https://api.strimz.io";
755
+ var StrimzBrowserClient = class {
756
+ mode;
757
+ /**
758
+ * Public hosted-checkout reads — payment sessions and subscription
759
+ * plans by id. Backed by the `/v1/checkout/*` namespace on the API,
760
+ * which is intentionally unauthenticated.
761
+ */
762
+ checkout;
763
+ /** Token metadata + EIP-2612 permit nonce lookup. */
764
+ tokens;
765
+ constructor(options) {
766
+ const key = options.publishableKey;
767
+ if (!key || typeof key !== "string") {
768
+ throw new StrimzAuthenticationError(
769
+ { code: "authentication_error", message: "publishableKey is required" },
770
+ 401
771
+ );
772
+ }
773
+ if (kindFromKey(key) !== "publishable") {
774
+ throw new StrimzAuthenticationError(
775
+ {
776
+ code: "authentication_error",
777
+ message: "StrimzBrowserClient must be initialised with a publishable key (pk_test_... / pk_live_...). Never expose secret keys to a browser."
778
+ },
779
+ 401
780
+ );
781
+ }
782
+ const mode = modeFromKey(key);
783
+ if (mode == null) {
784
+ throw new StrimzAuthenticationError(
785
+ { code: "authentication_error", message: "Unrecognised API key prefix" },
786
+ 401
787
+ );
788
+ }
789
+ this.mode = mode;
790
+ const fetcher = new Fetcher({
791
+ baseUrl: options.baseUrl ?? DEFAULT_BASE_URL2,
792
+ baseHeaders: buildBaseHeaders(key, "browser"),
793
+ timeoutMs: options.timeoutMs,
794
+ maxRetries: 2
795
+ });
796
+ this.checkout = new CheckoutResource({ fetcher });
797
+ this.tokens = new TokensResource({ fetcher });
798
+ }
799
+ };
800
+ function parseWebhookEvent(rawJson) {
801
+ return webhookEventSchema.parse(JSON.parse(rawJson));
802
+ }
803
+
804
+ export { AutoPagingIterator, StrimzAuthenticationError, StrimzBrowserClient, StrimzClient, StrimzError, StrimzIdempotencyError, StrimzModeMismatchError, StrimzNetworkError, StrimzNotFoundError, StrimzPermissionError, StrimzRateLimitError, StrimzTimeoutError, StrimzValidationError, classifyError, generateIdempotencyKey, isValidIdempotencyKey, parseWebhookEvent };
805
+ //# sourceMappingURL=index.js.map
806
+ //# sourceMappingURL=index.js.map