@01.software/sdk 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -83,11 +83,14 @@ __export(src_exports, {
83
83
  ApiError: () => ApiError,
84
84
  BrowserClient: () => BrowserClient,
85
85
  COLLECTIONS: () => COLLECTIONS,
86
+ CartApi: () => CartApi,
86
87
  CollectionClient: () => CollectionClient,
87
88
  CollectionQueryBuilder: () => CollectionQueryBuilder,
88
89
  ConfigError: () => ConfigError,
90
+ CustomerAuth: () => CustomerAuth,
89
91
  NetworkError: () => NetworkError,
90
92
  OrderApi: () => OrderApi,
93
+ ProductApi: () => ProductApi,
91
94
  QueryHooks: () => QueryHooks,
92
95
  RichTextContent: () => RichTextContent,
93
96
  ServerClient: () => ServerClient,
@@ -100,6 +103,7 @@ __export(src_exports, {
100
103
  createServerClient: () => createServerClient,
101
104
  createServerToken: () => createServerToken,
102
105
  createTypedWebhookHandler: () => createTypedWebhookHandler,
106
+ customerKeys: () => customerKeys,
103
107
  decodeServerToken: () => decodeServerToken,
104
108
  formatOrderName: () => formatOrderName,
105
109
  generateOrderNumber: () => generateOrderNumber,
@@ -120,119 +124,8 @@ __export(src_exports, {
120
124
  });
121
125
  module.exports = __toCommonJS(src_exports);
122
126
 
123
- // src/core/collection/query-builder.ts
124
- var CollectionQueryBuilder = class {
125
- constructor(api, collection) {
126
- this.api = api;
127
- this.collection = collection;
128
- }
129
- /**
130
- * Find documents (list query)
131
- * GET /api/{collection}
132
- * @returns Payload CMS find response with docs array and pagination
133
- */
134
- find(options) {
135
- return __async(this, null, function* () {
136
- return this.api.requestFind(
137
- `/api/${String(this.collection)}`,
138
- options
139
- );
140
- });
141
- }
142
- /**
143
- * Find document by ID
144
- * GET /api/{collection}/{id}
145
- * @returns Document object directly (no wrapper)
146
- */
147
- findById(id, options) {
148
- return __async(this, null, function* () {
149
- return this.api.requestFindById(
150
- `/api/${String(this.collection)}/${String(id)}`,
151
- options
152
- );
153
- });
154
- }
155
- /**
156
- * Create a new document
157
- * POST /api/{collection}
158
- * @returns Payload CMS mutation response with doc and message
159
- */
160
- create(data) {
161
- return __async(this, null, function* () {
162
- return this.api.requestCreate(
163
- `/api/${String(this.collection)}`,
164
- data
165
- );
166
- });
167
- }
168
- /**
169
- * Update a document by ID
170
- * PATCH /api/{collection}/{id}
171
- * @returns Payload CMS mutation response with doc and message
172
- */
173
- update(id, data) {
174
- return __async(this, null, function* () {
175
- return this.api.requestUpdate(
176
- `/api/${String(this.collection)}/${String(id)}`,
177
- data
178
- );
179
- });
180
- }
181
- /**
182
- * Count documents
183
- * GET /api/{collection}/count
184
- * @returns Count response with totalDocs
185
- */
186
- count(options) {
187
- return __async(this, null, function* () {
188
- return this.api.requestCount(
189
- `/api/${String(this.collection)}/count`,
190
- options
191
- );
192
- });
193
- }
194
- /**
195
- * Update multiple documents (bulk update)
196
- * PATCH /api/{collection}
197
- * @returns Payload CMS find response with updated docs
198
- */
199
- updateMany(where, data) {
200
- return __async(this, null, function* () {
201
- return this.api.requestUpdateMany(
202
- `/api/${String(this.collection)}`,
203
- { where, data }
204
- );
205
- });
206
- }
207
- /**
208
- * Delete a document by ID
209
- * DELETE /api/{collection}/{id}
210
- * @returns Deleted document object directly (no wrapper)
211
- */
212
- remove(id) {
213
- return __async(this, null, function* () {
214
- return this.api.requestDelete(
215
- `/api/${String(this.collection)}/${String(id)}`
216
- );
217
- });
218
- }
219
- /**
220
- * Delete multiple documents (bulk delete)
221
- * DELETE /api/{collection}
222
- * @returns Payload CMS find response with deleted docs
223
- */
224
- removeMany(where) {
225
- return __async(this, null, function* () {
226
- return this.api.requestDeleteMany(
227
- `/api/${String(this.collection)}`,
228
- { where }
229
- );
230
- });
231
- }
232
- };
233
-
234
- // src/core/collection/http-client.ts
235
- var import_qs_esm = require("qs-esm");
127
+ // src/core/internal/utils/index.ts
128
+ var import_jose = require("jose");
236
129
 
237
130
  // src/core/internal/errors/index.ts
238
131
  var SDKError = class _SDKError extends Error {
@@ -333,112 +226,6 @@ var createConfigError = (message, details, userMessage, suggestion) => new Confi
333
226
  var createTimeoutError = (message, details, userMessage, suggestion) => new TimeoutError(message, details, userMessage, suggestion);
334
227
  var createUsageLimitError = (message, usage, details, userMessage, suggestion) => new UsageLimitError(message, usage, details, userMessage, suggestion);
335
228
 
336
- // src/core/collection/http-client.ts
337
- var HttpClient = class {
338
- constructor(clientKey, secretKey, baseUrl) {
339
- if (!clientKey) {
340
- throw createValidationError("clientKey is required.");
341
- }
342
- this.clientKey = clientKey;
343
- this.secretKey = secretKey;
344
- this.baseUrl = baseUrl;
345
- this.defaultOptions = { clientKey, secretKey, baseUrl };
346
- }
347
- buildUrl(endpoint, options) {
348
- if (!options) return endpoint;
349
- const queryString = (0, import_qs_esm.stringify)(options, { addQueryPrefix: true });
350
- return queryString ? `${endpoint}${queryString}` : endpoint;
351
- }
352
- assertJsonResponse(response) {
353
- const contentType = response.headers.get("content-type");
354
- if (!(contentType == null ? void 0 : contentType.includes("application/json"))) {
355
- throw createApiError("Response is not in JSON format.", response.status, { contentType });
356
- }
357
- }
358
- /**
359
- * Parse Payload CMS find response (list query)
360
- * Returns native Payload response structure
361
- */
362
- parseFindResponse(response) {
363
- return __async(this, null, function* () {
364
- var _a, _b;
365
- const contentType = response.headers.get("content-type");
366
- try {
367
- this.assertJsonResponse(response);
368
- const jsonData = yield response.json();
369
- if (jsonData.docs === void 0) {
370
- throw createApiError("Invalid find response.", response.status, { jsonData });
371
- }
372
- return {
373
- docs: jsonData.docs,
374
- totalDocs: jsonData.totalDocs || 0,
375
- limit: jsonData.limit || 20,
376
- totalPages: jsonData.totalPages || 0,
377
- page: jsonData.page || 1,
378
- pagingCounter: jsonData.pagingCounter || 1,
379
- hasPrevPage: jsonData.hasPrevPage || false,
380
- hasNextPage: jsonData.hasNextPage || false,
381
- prevPage: (_a = jsonData.prevPage) != null ? _a : null,
382
- nextPage: (_b = jsonData.nextPage) != null ? _b : null
383
- };
384
- } catch (error) {
385
- throw createApiError("Failed to parse response.", response.status, {
386
- contentType,
387
- error: error instanceof Error ? error.message : error
388
- });
389
- }
390
- });
391
- }
392
- /**
393
- * Parse Payload CMS mutation response (create/update)
394
- * Returns native Payload response structure
395
- */
396
- parseMutationResponse(response) {
397
- return __async(this, null, function* () {
398
- const contentType = response.headers.get("content-type");
399
- try {
400
- this.assertJsonResponse(response);
401
- const jsonData = yield response.json();
402
- if (jsonData.doc === void 0) {
403
- throw createApiError("Invalid mutation response.", response.status, { jsonData });
404
- }
405
- return {
406
- message: jsonData.message || "",
407
- doc: jsonData.doc,
408
- errors: jsonData.errors
409
- };
410
- } catch (error) {
411
- throw createApiError("Failed to parse response.", response.status, {
412
- contentType,
413
- error: error instanceof Error ? error.message : error
414
- });
415
- }
416
- });
417
- }
418
- /**
419
- * Parse Payload CMS document response (findById/delete)
420
- * Returns document directly without wrapper
421
- */
422
- parseDocumentResponse(response) {
423
- return __async(this, null, function* () {
424
- const contentType = response.headers.get("content-type");
425
- try {
426
- this.assertJsonResponse(response);
427
- const jsonData = yield response.json();
428
- return jsonData;
429
- } catch (error) {
430
- throw createApiError("Failed to parse response.", response.status, {
431
- contentType,
432
- error: error instanceof Error ? error.message : error
433
- });
434
- }
435
- });
436
- }
437
- };
438
-
439
- // src/core/internal/utils/index.ts
440
- var import_jose = require("jose");
441
-
442
229
  // src/core/client/types.ts
443
230
  var API_URLS = {
444
231
  local: "http://localhost:3000",
@@ -464,6 +251,7 @@ function resolveApiUrl(config) {
464
251
  var DEFAULT_TIMEOUT = 3e4;
465
252
  var DEFAULT_RETRYABLE_STATUSES = [408, 429, 500, 502, 503, 504];
466
253
  var NON_RETRYABLE_STATUSES = [401, 403, 404, 422];
254
+ var SAFE_METHODS = ["GET", "HEAD", "OPTIONS"];
467
255
  function createServerToken(clientKey, secretKey, expiresIn = "1h") {
468
256
  return __async(this, null, function* () {
469
257
  if (!clientKey || !secretKey) {
@@ -567,6 +355,7 @@ function _fetch(url, options) {
567
355
  const _a = options || {}, {
568
356
  clientKey,
569
357
  secretKey,
358
+ customerToken,
570
359
  timeout = DEFAULT_TIMEOUT,
571
360
  baseUrl = API_URLS.production,
572
361
  debug,
@@ -574,6 +363,7 @@ function _fetch(url, options) {
574
363
  } = _a, requestInit = __objRest(_a, [
575
364
  "clientKey",
576
365
  "secretKey",
366
+ "customerToken",
577
367
  "timeout",
578
368
  "baseUrl",
579
369
  "debug",
@@ -587,6 +377,8 @@ function _fetch(url, options) {
587
377
  let authToken;
588
378
  if (secretKey && clientKey) {
589
379
  authToken = yield createServerToken(clientKey, secretKey);
380
+ } else if (customerToken) {
381
+ authToken = customerToken;
590
382
  }
591
383
  let lastError;
592
384
  for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
@@ -601,9 +393,14 @@ function _fetch(url, options) {
601
393
  if (!headers.has("Content-Type") && requestInit.body) {
602
394
  headers.set("Content-Type", "application/json");
603
395
  }
396
+ const redactedHeaders = Object.fromEntries(headers.entries());
397
+ if (redactedHeaders["authorization"]) {
398
+ const token = redactedHeaders["authorization"];
399
+ redactedHeaders["authorization"] = token.length > 15 ? `${token.slice(0, 15)}...****` : "****";
400
+ }
604
401
  debugLog(debug, "request", url, {
605
402
  method: requestInit.method || "GET",
606
- headers: Object.fromEntries(headers.entries()),
403
+ headers: redactedHeaders,
607
404
  attempt: attempt + 1
608
405
  });
609
406
  const controller = new AbortController();
@@ -647,7 +444,8 @@ function _fetch(url, options) {
647
444
  `Request failed (status: ${response.status})`,
648
445
  getErrorSuggestion(response.status)
649
446
  );
650
- if (attempt < retryConfig.maxRetries && retryConfig.retryableStatuses.includes(response.status)) {
447
+ const method = (requestInit.method || "GET").toUpperCase();
448
+ if (attempt < retryConfig.maxRetries && SAFE_METHODS.includes(method) && retryConfig.retryableStatuses.includes(response.status)) {
651
449
  lastError = error;
652
450
  const retryDelay = retryConfig.retryDelay(attempt);
653
451
  debugLog(debug, "error", `Retrying in ${retryDelay}ms...`, error);
@@ -659,6 +457,8 @@ function _fetch(url, options) {
659
457
  return response;
660
458
  } catch (error) {
661
459
  debugLog(debug, "error", url, error);
460
+ const method = (requestInit.method || "GET").toUpperCase();
461
+ const isSafe = SAFE_METHODS.includes(method);
662
462
  if (error instanceof Error && error.name === "AbortError") {
663
463
  const timeoutError = createTimeoutError(
664
464
  `Request timed out after ${timeout}ms.`,
@@ -666,7 +466,7 @@ function _fetch(url, options) {
666
466
  "The request timed out.",
667
467
  "Please check your network connection or try again later."
668
468
  );
669
- if (attempt < retryConfig.maxRetries) {
469
+ if (isSafe && attempt < retryConfig.maxRetries) {
670
470
  lastError = timeoutError;
671
471
  yield delay(retryConfig.retryDelay(attempt));
672
472
  continue;
@@ -681,7 +481,7 @@ function _fetch(url, options) {
681
481
  "Network connection failed.",
682
482
  "Please check your internet connection and try again."
683
483
  );
684
- if (attempt < retryConfig.maxRetries) {
484
+ if (isSafe && attempt < retryConfig.maxRetries) {
685
485
  lastError = networkError;
686
486
  yield delay(retryConfig.retryDelay(attempt));
687
487
  continue;
@@ -689,7 +489,7 @@ function _fetch(url, options) {
689
489
  throw networkError;
690
490
  }
691
491
  if (error instanceof NetworkError || error instanceof TimeoutError) {
692
- if (attempt < retryConfig.maxRetries && error.status && !NON_RETRYABLE_STATUSES.includes(error.status) && retryConfig.retryableStatuses.includes(error.status)) {
492
+ if (isSafe && attempt < retryConfig.maxRetries && error.status && !NON_RETRYABLE_STATUSES.includes(error.status) && retryConfig.retryableStatuses.includes(error.status)) {
693
493
  lastError = error;
694
494
  yield delay(retryConfig.retryDelay(attempt));
695
495
  continue;
@@ -703,7 +503,7 @@ function _fetch(url, options) {
703
503
  "An unknown error occurred.",
704
504
  "Please try again later."
705
505
  );
706
- if (attempt < retryConfig.maxRetries) {
506
+ if (isSafe && attempt < retryConfig.maxRetries) {
707
507
  lastError = unknownError;
708
508
  yield delay(retryConfig.retryDelay(attempt));
709
509
  continue;
@@ -711,14 +511,427 @@ function _fetch(url, options) {
711
511
  throw unknownError;
712
512
  }
713
513
  }
714
- throw lastError;
514
+ throw lastError != null ? lastError : new NetworkError("Request failed after retries");
715
515
  });
716
516
  }
717
517
 
518
+ // src/core/api/order-api.ts
519
+ var OrderApi = class {
520
+ constructor(options) {
521
+ if (!options.clientKey) {
522
+ throw createConfigError("clientKey is required for OrderApi.");
523
+ }
524
+ if (!options.secretKey) {
525
+ throw createConfigError("secretKey is required for OrderApi.");
526
+ }
527
+ this.clientKey = options.clientKey;
528
+ this.secretKey = options.secretKey;
529
+ this.baseUrl = options.baseUrl;
530
+ }
531
+ request(endpoint, body) {
532
+ return __async(this, null, function* () {
533
+ const response = yield _fetch(endpoint, {
534
+ method: "POST",
535
+ clientKey: this.clientKey,
536
+ secretKey: this.secretKey,
537
+ baseUrl: this.baseUrl,
538
+ body: JSON.stringify(body)
539
+ });
540
+ let data;
541
+ try {
542
+ data = yield response.json();
543
+ } catch (e) {
544
+ throw createApiError(
545
+ `Invalid JSON response from ${endpoint}`,
546
+ response.status,
547
+ void 0,
548
+ "Server returned an invalid response.",
549
+ "Check if the API endpoint is available."
550
+ );
551
+ }
552
+ if (data.error) {
553
+ const errorMessage = typeof data.error === "string" ? data.error : "Unknown API error";
554
+ throw createApiError(
555
+ errorMessage,
556
+ response.status,
557
+ data,
558
+ errorMessage,
559
+ "An error occurred while processing the request."
560
+ );
561
+ }
562
+ return data;
563
+ });
564
+ }
565
+ createOrder(params) {
566
+ return this.request("/api/orders/create", params);
567
+ }
568
+ updateOrder(params) {
569
+ return this.request("/api/orders/update", params);
570
+ }
571
+ getOrder(params) {
572
+ return this.request("/api/orders/get", params);
573
+ }
574
+ updateTransaction(params) {
575
+ return this.request("/api/transactions/update", params);
576
+ }
577
+ checkout(params) {
578
+ return this.request("/api/orders/checkout", params);
579
+ }
580
+ createFulfillment(params) {
581
+ return this.request("/api/orders/create-fulfillment", params);
582
+ }
583
+ returnWithRefund(params) {
584
+ return this.request("/api/returns/return-refund", params);
585
+ }
586
+ createReturn(params) {
587
+ return this.request("/api/returns/create", params);
588
+ }
589
+ updateReturn(params) {
590
+ return this.request("/api/returns/update", params);
591
+ }
592
+ };
593
+
594
+ // src/core/api/cart-api.ts
595
+ var CartApi = class {
596
+ constructor(options) {
597
+ if (!options.clientKey) {
598
+ throw createConfigError("clientKey is required for CartApi.");
599
+ }
600
+ if (!options.secretKey && !options.customerToken) {
601
+ throw createConfigError("Either secretKey or customerToken is required for CartApi.");
602
+ }
603
+ this.clientKey = options.clientKey;
604
+ this.secretKey = options.secretKey;
605
+ this.customerToken = options.customerToken;
606
+ this.baseUrl = options.baseUrl;
607
+ }
608
+ request(endpoint, body) {
609
+ return __async(this, null, function* () {
610
+ const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
611
+ const response = yield _fetch(endpoint, {
612
+ method: "POST",
613
+ clientKey: this.clientKey,
614
+ secretKey: this.secretKey,
615
+ customerToken: token != null ? token : void 0,
616
+ baseUrl: this.baseUrl,
617
+ body: JSON.stringify(body)
618
+ });
619
+ let data;
620
+ try {
621
+ data = yield response.json();
622
+ } catch (e) {
623
+ throw createApiError(
624
+ `Invalid JSON response from ${endpoint}`,
625
+ response.status,
626
+ void 0,
627
+ "Server returned an invalid response.",
628
+ "Check if the API endpoint is available."
629
+ );
630
+ }
631
+ if (data.error) {
632
+ const errorMessage = typeof data.error === "string" ? data.error : "Unknown API error";
633
+ throw createApiError(
634
+ errorMessage,
635
+ response.status,
636
+ data,
637
+ errorMessage,
638
+ "An error occurred while processing the request."
639
+ );
640
+ }
641
+ return data;
642
+ });
643
+ }
644
+ addItem(params) {
645
+ return this.request("/api/carts/add-item", params);
646
+ }
647
+ updateItem(params) {
648
+ return this.request("/api/carts/update-item", params);
649
+ }
650
+ removeItem(params) {
651
+ return this.request("/api/carts/remove-item", params);
652
+ }
653
+ };
654
+
655
+ // src/core/api/product-api.ts
656
+ var ProductApi = class {
657
+ constructor(options) {
658
+ if (!options.clientKey) {
659
+ throw createConfigError("clientKey is required for ProductApi.");
660
+ }
661
+ if (!options.secretKey) {
662
+ throw createConfigError("secretKey is required for ProductApi.");
663
+ }
664
+ this.clientKey = options.clientKey;
665
+ this.secretKey = options.secretKey;
666
+ this.baseUrl = options.baseUrl;
667
+ }
668
+ request(endpoint, body) {
669
+ return __async(this, null, function* () {
670
+ const response = yield _fetch(endpoint, {
671
+ method: "POST",
672
+ clientKey: this.clientKey,
673
+ secretKey: this.secretKey,
674
+ baseUrl: this.baseUrl,
675
+ body: JSON.stringify(body)
676
+ });
677
+ let data;
678
+ try {
679
+ data = yield response.json();
680
+ } catch (e) {
681
+ throw createApiError(
682
+ `Invalid JSON response from ${endpoint}`,
683
+ response.status,
684
+ void 0,
685
+ "Server returned an invalid response.",
686
+ "Check if the API endpoint is available."
687
+ );
688
+ }
689
+ if (data.error) {
690
+ const errorMessage = typeof data.error === "string" ? data.error : "Unknown API error";
691
+ throw createApiError(
692
+ errorMessage,
693
+ response.status,
694
+ data,
695
+ errorMessage,
696
+ "An error occurred while processing the request."
697
+ );
698
+ }
699
+ return data;
700
+ });
701
+ }
702
+ stockCheck(params) {
703
+ return this.request("/api/products/stock-check", params);
704
+ }
705
+ };
706
+
707
+ // src/core/collection/query-builder.ts
708
+ var CollectionQueryBuilder = class {
709
+ constructor(api, collection) {
710
+ this.api = api;
711
+ this.collection = collection;
712
+ }
713
+ /**
714
+ * Find documents (list query)
715
+ * GET /api/{collection}
716
+ * @returns Payload CMS find response with docs array and pagination
717
+ */
718
+ find(options) {
719
+ return __async(this, null, function* () {
720
+ return this.api.requestFind(
721
+ `/api/${String(this.collection)}`,
722
+ options
723
+ );
724
+ });
725
+ }
726
+ /**
727
+ * Find document by ID
728
+ * GET /api/{collection}/{id}
729
+ * @returns Document object directly (no wrapper)
730
+ */
731
+ findById(id, options) {
732
+ return __async(this, null, function* () {
733
+ return this.api.requestFindById(
734
+ `/api/${String(this.collection)}/${String(id)}`,
735
+ options
736
+ );
737
+ });
738
+ }
739
+ /**
740
+ * Create a new document
741
+ * POST /api/{collection}
742
+ * @returns Payload CMS mutation response with doc and message
743
+ */
744
+ create(data) {
745
+ return __async(this, null, function* () {
746
+ return this.api.requestCreate(
747
+ `/api/${String(this.collection)}`,
748
+ data
749
+ );
750
+ });
751
+ }
752
+ /**
753
+ * Update a document by ID
754
+ * PATCH /api/{collection}/{id}
755
+ * @returns Payload CMS mutation response with doc and message
756
+ */
757
+ update(id, data) {
758
+ return __async(this, null, function* () {
759
+ return this.api.requestUpdate(
760
+ `/api/${String(this.collection)}/${String(id)}`,
761
+ data
762
+ );
763
+ });
764
+ }
765
+ /**
766
+ * Count documents
767
+ * GET /api/{collection}/count
768
+ * @returns Count response with totalDocs
769
+ */
770
+ count(options) {
771
+ return __async(this, null, function* () {
772
+ return this.api.requestCount(
773
+ `/api/${String(this.collection)}/count`,
774
+ options
775
+ );
776
+ });
777
+ }
778
+ /**
779
+ * Update multiple documents (bulk update)
780
+ * PATCH /api/{collection}
781
+ * @returns Payload CMS find response with updated docs
782
+ */
783
+ updateMany(where, data) {
784
+ return __async(this, null, function* () {
785
+ return this.api.requestUpdateMany(
786
+ `/api/${String(this.collection)}`,
787
+ { where, data }
788
+ );
789
+ });
790
+ }
791
+ /**
792
+ * Delete a document by ID
793
+ * DELETE /api/{collection}/{id}
794
+ * @returns Deleted document object directly (no wrapper)
795
+ */
796
+ remove(id) {
797
+ return __async(this, null, function* () {
798
+ return this.api.requestDelete(
799
+ `/api/${String(this.collection)}/${String(id)}`
800
+ );
801
+ });
802
+ }
803
+ /**
804
+ * Delete multiple documents (bulk delete)
805
+ * DELETE /api/{collection}
806
+ * @returns Payload CMS find response with deleted docs
807
+ */
808
+ removeMany(where) {
809
+ return __async(this, null, function* () {
810
+ return this.api.requestDeleteMany(
811
+ `/api/${String(this.collection)}`,
812
+ { where }
813
+ );
814
+ });
815
+ }
816
+ };
817
+
818
+ // src/core/collection/http-client.ts
819
+ var import_qs_esm = require("qs-esm");
820
+ var HttpClient = class {
821
+ constructor(clientKey, secretKey, baseUrl, getCustomerToken) {
822
+ if (!clientKey) {
823
+ throw createValidationError("clientKey is required.");
824
+ }
825
+ this.clientKey = clientKey;
826
+ this.secretKey = secretKey;
827
+ this.baseUrl = baseUrl;
828
+ this.getCustomerToken = getCustomerToken;
829
+ }
830
+ get defaultOptions() {
831
+ var _a;
832
+ const opts = { clientKey: this.clientKey, secretKey: this.secretKey, baseUrl: this.baseUrl };
833
+ const token = (_a = this.getCustomerToken) == null ? void 0 : _a.call(this);
834
+ if (token) {
835
+ opts.customerToken = token;
836
+ }
837
+ return opts;
838
+ }
839
+ buildUrl(endpoint, options) {
840
+ if (!options) return endpoint;
841
+ const queryString = (0, import_qs_esm.stringify)(options, { addQueryPrefix: true });
842
+ return queryString ? `${endpoint}${queryString}` : endpoint;
843
+ }
844
+ assertJsonResponse(response) {
845
+ const contentType = response.headers.get("content-type");
846
+ if (!(contentType == null ? void 0 : contentType.includes("application/json"))) {
847
+ throw createApiError("Response is not in JSON format.", response.status, { contentType });
848
+ }
849
+ }
850
+ /**
851
+ * Parse Payload CMS find response (list query)
852
+ * Returns native Payload response structure
853
+ */
854
+ parseFindResponse(response) {
855
+ return __async(this, null, function* () {
856
+ var _a, _b;
857
+ const contentType = response.headers.get("content-type");
858
+ try {
859
+ this.assertJsonResponse(response);
860
+ const jsonData = yield response.json();
861
+ if (jsonData.docs === void 0) {
862
+ throw createApiError("Invalid find response.", response.status, { jsonData });
863
+ }
864
+ return {
865
+ docs: jsonData.docs,
866
+ totalDocs: jsonData.totalDocs || 0,
867
+ limit: jsonData.limit || 20,
868
+ totalPages: jsonData.totalPages || 0,
869
+ page: jsonData.page || 1,
870
+ pagingCounter: jsonData.pagingCounter || 1,
871
+ hasPrevPage: jsonData.hasPrevPage || false,
872
+ hasNextPage: jsonData.hasNextPage || false,
873
+ prevPage: (_a = jsonData.prevPage) != null ? _a : null,
874
+ nextPage: (_b = jsonData.nextPage) != null ? _b : null
875
+ };
876
+ } catch (error) {
877
+ throw createApiError("Failed to parse response.", response.status, {
878
+ contentType,
879
+ error: error instanceof Error ? error.message : error
880
+ });
881
+ }
882
+ });
883
+ }
884
+ /**
885
+ * Parse Payload CMS mutation response (create/update)
886
+ * Returns native Payload response structure
887
+ */
888
+ parseMutationResponse(response) {
889
+ return __async(this, null, function* () {
890
+ const contentType = response.headers.get("content-type");
891
+ try {
892
+ this.assertJsonResponse(response);
893
+ const jsonData = yield response.json();
894
+ if (jsonData.doc === void 0) {
895
+ throw createApiError("Invalid mutation response.", response.status, { jsonData });
896
+ }
897
+ return {
898
+ message: jsonData.message || "",
899
+ doc: jsonData.doc,
900
+ errors: jsonData.errors
901
+ };
902
+ } catch (error) {
903
+ throw createApiError("Failed to parse response.", response.status, {
904
+ contentType,
905
+ error: error instanceof Error ? error.message : error
906
+ });
907
+ }
908
+ });
909
+ }
910
+ /**
911
+ * Parse Payload CMS document response (findById/delete)
912
+ * Returns document directly without wrapper
913
+ */
914
+ parseDocumentResponse(response) {
915
+ return __async(this, null, function* () {
916
+ const contentType = response.headers.get("content-type");
917
+ try {
918
+ this.assertJsonResponse(response);
919
+ const jsonData = yield response.json();
920
+ return jsonData;
921
+ } catch (error) {
922
+ throw createApiError("Failed to parse response.", response.status, {
923
+ contentType,
924
+ error: error instanceof Error ? error.message : error
925
+ });
926
+ }
927
+ });
928
+ }
929
+ };
930
+
718
931
  // src/core/collection/collection-client.ts
719
932
  var CollectionClient = class extends HttpClient {
720
- constructor(clientKey, secretKey, baseUrl) {
721
- super(clientKey, secretKey, baseUrl);
933
+ constructor(clientKey, secretKey, baseUrl, getCustomerToken) {
934
+ super(clientKey, secretKey, baseUrl, getCustomerToken);
722
935
  }
723
936
  from(collection) {
724
937
  return new CollectionQueryBuilder(this, collection);
@@ -843,7 +1056,17 @@ var COLLECTIONS = [
843
1056
  "order-products",
844
1057
  "returns",
845
1058
  "return-products",
1059
+ "exchanges",
1060
+ "exchange-products",
1061
+ "fulfillments",
1062
+ "fulfillment-items",
846
1063
  "transactions",
1064
+ "customers",
1065
+ "customer-addresses",
1066
+ "carts",
1067
+ "cart-items",
1068
+ "discounts",
1069
+ "shipping-policies",
847
1070
  "documents",
848
1071
  "document-categories",
849
1072
  "document-images",
@@ -861,12 +1084,205 @@ var COLLECTIONS = [
861
1084
  "media"
862
1085
  ];
863
1086
 
1087
+ // src/core/customer/customer-auth.ts
1088
+ var DEFAULT_TIMEOUT2 = 15e3;
1089
+ var CustomerAuth = class {
1090
+ constructor(clientKey, baseUrl, options) {
1091
+ var _a;
1092
+ this.clientKey = clientKey;
1093
+ this.baseUrl = baseUrl;
1094
+ this.token = (_a = options == null ? void 0 : options.token) != null ? _a : null;
1095
+ this.onTokenChange = options == null ? void 0 : options.onTokenChange;
1096
+ }
1097
+ /**
1098
+ * Register a new customer account
1099
+ */
1100
+ register(data) {
1101
+ return __async(this, null, function* () {
1102
+ return this.requestJson("/api/customers/register", {
1103
+ method: "POST",
1104
+ body: JSON.stringify(data)
1105
+ });
1106
+ });
1107
+ }
1108
+ /**
1109
+ * Login with email and password. Stores the token internally.
1110
+ */
1111
+ login(data) {
1112
+ return __async(this, null, function* () {
1113
+ const result = yield this.requestJson("/api/customers/login", {
1114
+ method: "POST",
1115
+ body: JSON.stringify(data)
1116
+ });
1117
+ this.setToken(result.token);
1118
+ return result;
1119
+ });
1120
+ }
1121
+ /**
1122
+ * Refresh the current token. Requires a valid (non-expired) token.
1123
+ */
1124
+ refreshToken() {
1125
+ return __async(this, null, function* () {
1126
+ if (!this.token) throw new ApiError("Not authenticated", 401);
1127
+ const result = yield this.requestJson("/api/customers/refresh", {
1128
+ method: "POST",
1129
+ headers: { Authorization: `Bearer ${this.token}` }
1130
+ });
1131
+ this.setToken(result.token);
1132
+ return result;
1133
+ });
1134
+ }
1135
+ /**
1136
+ * Clear the stored token
1137
+ */
1138
+ logout() {
1139
+ this.setToken(null);
1140
+ }
1141
+ /**
1142
+ * Get the current authenticated customer's profile
1143
+ */
1144
+ me() {
1145
+ return __async(this, null, function* () {
1146
+ var _a;
1147
+ if (!this.token) return null;
1148
+ try {
1149
+ const data = yield this.requestJson("/api/customers/me", {
1150
+ method: "GET",
1151
+ headers: { Authorization: `Bearer ${this.token}` }
1152
+ });
1153
+ return (_a = data.customer) != null ? _a : null;
1154
+ } catch (error) {
1155
+ if (error instanceof ApiError && error.status === 401) {
1156
+ this.setToken(null);
1157
+ return null;
1158
+ }
1159
+ throw error;
1160
+ }
1161
+ });
1162
+ }
1163
+ /**
1164
+ * Request a password reset email
1165
+ */
1166
+ forgotPassword(email) {
1167
+ return __async(this, null, function* () {
1168
+ yield this.requestJson("/api/customers/forgot-password", {
1169
+ method: "POST",
1170
+ body: JSON.stringify({ email })
1171
+ });
1172
+ });
1173
+ }
1174
+ /**
1175
+ * Reset password using a token from the reset email
1176
+ */
1177
+ resetPassword(token, password) {
1178
+ return __async(this, null, function* () {
1179
+ yield this.requestJson("/api/customers/reset-password", {
1180
+ method: "POST",
1181
+ body: JSON.stringify({ token, password })
1182
+ });
1183
+ });
1184
+ }
1185
+ /**
1186
+ * Change the password of the currently authenticated customer
1187
+ */
1188
+ changePassword(currentPassword, newPassword) {
1189
+ return __async(this, null, function* () {
1190
+ if (!this.token) throw new ApiError("Not authenticated", 401);
1191
+ yield this.requestJson("/api/customers/change-password", {
1192
+ method: "POST",
1193
+ headers: { Authorization: `Bearer ${this.token}` },
1194
+ body: JSON.stringify({ currentPassword, newPassword })
1195
+ });
1196
+ });
1197
+ }
1198
+ /**
1199
+ * Verify email using the verification token
1200
+ */
1201
+ verifyEmail(token) {
1202
+ return __async(this, null, function* () {
1203
+ yield this.requestJson("/api/customers/verify-email", {
1204
+ method: "POST",
1205
+ body: JSON.stringify({ token })
1206
+ });
1207
+ });
1208
+ }
1209
+ /**
1210
+ * Get the current token (or null if not authenticated)
1211
+ */
1212
+ getToken() {
1213
+ return this.token;
1214
+ }
1215
+ /**
1216
+ * Set the token manually (e.g. from SSR)
1217
+ */
1218
+ setToken(token) {
1219
+ var _a;
1220
+ this.token = token;
1221
+ (_a = this.onTokenChange) == null ? void 0 : _a.call(this, token);
1222
+ }
1223
+ /**
1224
+ * Check if the customer is currently authenticated
1225
+ */
1226
+ isAuthenticated() {
1227
+ return this.token !== null;
1228
+ }
1229
+ /**
1230
+ * Internal: make a request with timeout and error handling.
1231
+ * Auth endpoints don't retry — failures are final.
1232
+ */
1233
+ requestJson(path, init) {
1234
+ return __async(this, null, function* () {
1235
+ const headers = new Headers(init.headers);
1236
+ headers.set("X-Client-Key", this.clientKey);
1237
+ if (!headers.has("Content-Type") && init.body) {
1238
+ headers.set("Content-Type", "application/json");
1239
+ }
1240
+ const controller = new AbortController();
1241
+ const timeoutId = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT2);
1242
+ let res;
1243
+ try {
1244
+ res = yield fetch(`${this.baseUrl}${path}`, __spreadProps(__spreadValues({}, init), {
1245
+ headers,
1246
+ signal: controller.signal
1247
+ }));
1248
+ } catch (error) {
1249
+ clearTimeout(timeoutId);
1250
+ if (error instanceof Error && error.name === "AbortError") {
1251
+ throw new TimeoutError(
1252
+ `Request timed out after ${DEFAULT_TIMEOUT2}ms`,
1253
+ { url: path, timeout: DEFAULT_TIMEOUT2 }
1254
+ );
1255
+ }
1256
+ throw new NetworkError(
1257
+ error instanceof Error ? error.message : "Network request failed",
1258
+ void 0,
1259
+ { url: path },
1260
+ "Network connection failed.",
1261
+ "Please check your internet connection and try again."
1262
+ );
1263
+ }
1264
+ clearTimeout(timeoutId);
1265
+ if (!res.ok) {
1266
+ const body = yield res.json().catch(() => ({}));
1267
+ throw new ApiError(
1268
+ body.error || `HTTP ${res.status}`,
1269
+ res.status,
1270
+ body.details,
1271
+ body.error
1272
+ );
1273
+ }
1274
+ return res.json();
1275
+ });
1276
+ }
1277
+ };
1278
+
864
1279
  // src/core/query/get-query-client.ts
865
1280
  var import_react_query = require("@tanstack/react-query");
866
1281
  function makeQueryClient() {
867
1282
  return new import_react_query.QueryClient({
868
1283
  defaultOptions: {
869
1284
  queries: {
1285
+ // SSR/RSC: server-fetched data doesn't auto-refetch; use refetch()/invalidate() to refresh
870
1286
  staleTime: Number.POSITIVE_INFINITY,
871
1287
  refetchOnWindowFocus: false
872
1288
  },
@@ -901,11 +1317,24 @@ function collectionKeys(collection) {
901
1317
  infinite: (options) => [collection, "infinite", options]
902
1318
  };
903
1319
  }
1320
+ var customerKeys = {
1321
+ all: ["customer"],
1322
+ me: () => ["customer", "me"]
1323
+ };
904
1324
  var DEFAULT_PAGE_SIZE = 20;
905
1325
  var QueryHooks = class {
906
- constructor(queryClient, collectionClient) {
1326
+ constructor(queryClient, collectionClient, customerAuth) {
907
1327
  this.queryClient = queryClient;
908
1328
  this.collectionClient = collectionClient;
1329
+ this.customerAuth = customerAuth;
1330
+ }
1331
+ ensureCustomerAuth() {
1332
+ if (!this.customerAuth) {
1333
+ throw createConfigError(
1334
+ "Customer hooks require BrowserClient. Use createBrowserClient() instead of createServerClient()."
1335
+ );
1336
+ }
1337
+ return this.customerAuth;
909
1338
  }
910
1339
  // ===== useQuery =====
911
1340
  useQuery(params, options) {
@@ -1097,6 +1526,124 @@ var QueryHooks = class {
1097
1526
  );
1098
1527
  }
1099
1528
  }
1529
+ // ===== Customer Query Hooks =====
1530
+ useCustomerMe(options) {
1531
+ var _a, _b;
1532
+ return (0, import_react_query2.useQuery)(__spreadProps(__spreadValues({
1533
+ queryKey: customerKeys.me(),
1534
+ queryFn: () => __async(this, null, function* () {
1535
+ return yield this.ensureCustomerAuth().me();
1536
+ })
1537
+ }, options), {
1538
+ enabled: ((_a = options == null ? void 0 : options.enabled) != null ? _a : true) && !!((_b = this.customerAuth) == null ? void 0 : _b.isAuthenticated())
1539
+ }));
1540
+ }
1541
+ useCustomerLogin(options) {
1542
+ return (0, import_react_query2.useMutation)({
1543
+ mutationFn: (data) => __async(this, null, function* () {
1544
+ return yield this.ensureCustomerAuth().login(data);
1545
+ }),
1546
+ onSuccess: (data) => {
1547
+ var _a;
1548
+ this.queryClient.invalidateQueries({ queryKey: customerKeys.me() });
1549
+ (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, data);
1550
+ },
1551
+ onError: options == null ? void 0 : options.onError,
1552
+ onSettled: options == null ? void 0 : options.onSettled
1553
+ });
1554
+ }
1555
+ useCustomerRegister(options) {
1556
+ return (0, import_react_query2.useMutation)({
1557
+ mutationFn: (data) => __async(this, null, function* () {
1558
+ return yield this.ensureCustomerAuth().register(data);
1559
+ }),
1560
+ onSuccess: options == null ? void 0 : options.onSuccess,
1561
+ onError: options == null ? void 0 : options.onError,
1562
+ onSettled: options == null ? void 0 : options.onSettled
1563
+ });
1564
+ }
1565
+ useCustomerLogout(options) {
1566
+ return (0, import_react_query2.useMutation)({
1567
+ mutationFn: () => __async(this, null, function* () {
1568
+ this.ensureCustomerAuth().logout();
1569
+ }),
1570
+ onSuccess: () => {
1571
+ var _a;
1572
+ this.queryClient.removeQueries({ queryKey: customerKeys.all });
1573
+ (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options);
1574
+ },
1575
+ onError: options == null ? void 0 : options.onError,
1576
+ onSettled: options == null ? void 0 : options.onSettled
1577
+ });
1578
+ }
1579
+ useCustomerForgotPassword(options) {
1580
+ return (0, import_react_query2.useMutation)({
1581
+ mutationFn: (email) => __async(this, null, function* () {
1582
+ yield this.ensureCustomerAuth().forgotPassword(email);
1583
+ }),
1584
+ onSuccess: options == null ? void 0 : options.onSuccess,
1585
+ onError: options == null ? void 0 : options.onError,
1586
+ onSettled: options == null ? void 0 : options.onSettled
1587
+ });
1588
+ }
1589
+ useCustomerResetPassword(options) {
1590
+ return (0, import_react_query2.useMutation)({
1591
+ mutationFn: (data) => __async(this, null, function* () {
1592
+ yield this.ensureCustomerAuth().resetPassword(data.token, data.password);
1593
+ }),
1594
+ onSuccess: options == null ? void 0 : options.onSuccess,
1595
+ onError: options == null ? void 0 : options.onError,
1596
+ onSettled: options == null ? void 0 : options.onSettled
1597
+ });
1598
+ }
1599
+ useCustomerVerifyEmail(options) {
1600
+ return (0, import_react_query2.useMutation)({
1601
+ mutationFn: (token) => __async(this, null, function* () {
1602
+ yield this.ensureCustomerAuth().verifyEmail(token);
1603
+ }),
1604
+ onSuccess: () => {
1605
+ var _a;
1606
+ this.queryClient.invalidateQueries({ queryKey: customerKeys.me() });
1607
+ (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options);
1608
+ },
1609
+ onError: options == null ? void 0 : options.onError,
1610
+ onSettled: options == null ? void 0 : options.onSettled
1611
+ });
1612
+ }
1613
+ useCustomerRefreshToken(options) {
1614
+ return (0, import_react_query2.useMutation)({
1615
+ mutationFn: () => __async(this, null, function* () {
1616
+ return yield this.ensureCustomerAuth().refreshToken();
1617
+ }),
1618
+ onSuccess: (data) => {
1619
+ var _a;
1620
+ this.queryClient.invalidateQueries({ queryKey: customerKeys.me() });
1621
+ (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, data);
1622
+ },
1623
+ onError: options == null ? void 0 : options.onError,
1624
+ onSettled: options == null ? void 0 : options.onSettled
1625
+ });
1626
+ }
1627
+ useCustomerChangePassword(options) {
1628
+ return (0, import_react_query2.useMutation)({
1629
+ mutationFn: (data) => __async(this, null, function* () {
1630
+ yield this.ensureCustomerAuth().changePassword(data.currentPassword, data.newPassword);
1631
+ }),
1632
+ onSuccess: options == null ? void 0 : options.onSuccess,
1633
+ onError: options == null ? void 0 : options.onError,
1634
+ onSettled: options == null ? void 0 : options.onSettled
1635
+ });
1636
+ }
1637
+ // ===== Customer Cache Utilities =====
1638
+ invalidateCustomerQueries() {
1639
+ return this.queryClient.invalidateQueries({ queryKey: customerKeys.all });
1640
+ }
1641
+ getCustomerData() {
1642
+ return this.queryClient.getQueryData(customerKeys.me());
1643
+ }
1644
+ setCustomerData(data) {
1645
+ this.queryClient.setQueryData(customerKeys.me(), data);
1646
+ }
1100
1647
  };
1101
1648
 
1102
1649
  // src/core/client/client.ts
@@ -1114,8 +1661,19 @@ var BrowserClient = class {
1114
1661
  };
1115
1662
  this.state = { metadata };
1116
1663
  this.queryClient = getQueryClient();
1117
- this.collections = new CollectionClient(this.config.clientKey, void 0, this.baseUrl);
1118
- this.query = new QueryHooks(this.queryClient, this.collections);
1664
+ this.customer = new CustomerAuth(this.config.clientKey, this.baseUrl, options.customer);
1665
+ this.cart = new CartApi({
1666
+ clientKey: this.config.clientKey,
1667
+ customerToken: () => this.customer.getToken(),
1668
+ baseUrl: this.baseUrl
1669
+ });
1670
+ this.collections = new CollectionClient(
1671
+ this.config.clientKey,
1672
+ void 0,
1673
+ this.baseUrl,
1674
+ () => this.customer.getToken()
1675
+ );
1676
+ this.query = new QueryHooks(this.queryClient, this.collections, this.customer);
1119
1677
  }
1120
1678
  from(collection) {
1121
1679
  return this.collections.from(collection);
@@ -1128,68 +1686,14 @@ function createBrowserClient(options) {
1128
1686
  return new BrowserClient(options);
1129
1687
  }
1130
1688
 
1131
- // src/core/api/order-api.ts
1132
- var OrderApi = class {
1133
- constructor(options) {
1134
- if (!options.clientKey) {
1135
- throw createConfigError("clientKey is required for OrderApi.");
1136
- }
1137
- if (!options.secretKey) {
1138
- throw createConfigError("secretKey is required for OrderApi.");
1139
- }
1140
- this.clientKey = options.clientKey;
1141
- this.secretKey = options.secretKey;
1142
- this.baseUrl = options.baseUrl;
1143
- }
1144
- request(endpoint, body) {
1145
- return __async(this, null, function* () {
1146
- const response = yield _fetch(endpoint, {
1147
- method: "POST",
1148
- clientKey: this.clientKey,
1149
- secretKey: this.secretKey,
1150
- baseUrl: this.baseUrl,
1151
- body: JSON.stringify(body)
1152
- });
1153
- let data;
1154
- try {
1155
- data = yield response.json();
1156
- } catch (e) {
1157
- throw createApiError(
1158
- `Invalid JSON response from ${endpoint}`,
1159
- response.status,
1160
- void 0,
1161
- "Server returned an invalid response.",
1162
- "Check if the API endpoint is available."
1163
- );
1164
- }
1165
- if (data.error) {
1166
- const errorMessage = typeof data.error === "string" ? data.error : "Unknown API error";
1167
- throw createApiError(
1168
- errorMessage,
1169
- response.status,
1170
- data,
1171
- errorMessage,
1172
- "An error occurred while processing the request."
1173
- );
1174
- }
1175
- return data;
1176
- });
1177
- }
1178
- createOrder(params) {
1179
- return this.request("/api/orders/create", params);
1180
- }
1181
- updateOrder(params) {
1182
- return this.request("/api/orders/update", params);
1183
- }
1184
- updateTransaction(params) {
1185
- return this.request("/api/transactions/update", params);
1186
- }
1187
- };
1188
-
1189
1689
  // src/core/client/client.server.ts
1190
1690
  var ServerClient = class {
1191
1691
  constructor(options) {
1192
- var _a;
1692
+ if (typeof window !== "undefined") {
1693
+ throw createConfigError(
1694
+ "ServerClient must not be used in a browser environment. This risks exposing your secretKey in client bundles. Use createBrowserClient() for browser code instead."
1695
+ );
1696
+ }
1193
1697
  if (!options.clientKey) {
1194
1698
  throw createConfigError("clientKey is required.");
1195
1699
  }
@@ -1200,7 +1704,7 @@ var ServerClient = class {
1200
1704
  this.baseUrl = resolveApiUrl(options);
1201
1705
  const metadata = {
1202
1706
  timestamp: Date.now(),
1203
- userAgent: typeof window !== "undefined" ? (_a = window.navigator) == null ? void 0 : _a.userAgent : "Node.js"
1707
+ userAgent: "Node.js"
1204
1708
  };
1205
1709
  this.state = { metadata };
1206
1710
  this.api = new OrderApi({
@@ -1208,6 +1712,16 @@ var ServerClient = class {
1208
1712
  secretKey: this.config.secretKey,
1209
1713
  baseUrl: this.baseUrl
1210
1714
  });
1715
+ this.cart = new CartApi({
1716
+ clientKey: this.config.clientKey,
1717
+ secretKey: this.config.secretKey,
1718
+ baseUrl: this.baseUrl
1719
+ });
1720
+ this.product = new ProductApi({
1721
+ clientKey: this.config.clientKey,
1722
+ secretKey: this.config.secretKey,
1723
+ baseUrl: this.baseUrl
1724
+ });
1211
1725
  this.collections = new CollectionClient(
1212
1726
  this.config.clientKey,
1213
1727
  this.config.secretKey,
@@ -1249,10 +1763,10 @@ function verifySignature(payload, secret, signature) {
1249
1763
  );
1250
1764
  const sig = yield crypto.subtle.sign("HMAC", key, encoder.encode(payload));
1251
1765
  const expected = Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
1252
- if (expected.length !== signature.length) return false;
1253
- let result = 0;
1254
- for (let i = 0; i < expected.length; i++) {
1255
- result |= expected.charCodeAt(i) ^ signature.charCodeAt(i);
1766
+ let result = expected.length !== signature.length ? 1 : 0;
1767
+ const len = Math.max(expected.length, signature.length);
1768
+ for (let i = 0; i < len; i++) {
1769
+ result |= (expected.charCodeAt(i) || 0) ^ (signature.charCodeAt(i) || 0);
1256
1770
  }
1257
1771
  return result === 0;
1258
1772
  });
@@ -1261,6 +1775,11 @@ function handleWebhook(request, handler, options) {
1261
1775
  return __async(this, null, function* () {
1262
1776
  try {
1263
1777
  const rawBody = yield request.text();
1778
+ if (!(options == null ? void 0 : options.secret)) {
1779
+ console.warn(
1780
+ "[@01.software/sdk] Webhook signature verification is skipped because no secret was provided. Pass { secret } to handleWebhook() to enable signature verification."
1781
+ );
1782
+ }
1264
1783
  if (options == null ? void 0 : options.secret) {
1265
1784
  const signature = request.headers.get("x-webhook-signature") || "";
1266
1785
  const valid = yield verifySignature(rawBody, options.secret, signature);
@@ -1286,10 +1805,7 @@ function handleWebhook(request, handler, options) {
1286
1805
  } catch (error) {
1287
1806
  console.error("Webhook processing error:", error);
1288
1807
  return new Response(
1289
- JSON.stringify({
1290
- error: "Internal server error",
1291
- message: error instanceof Error ? error.message : "Unknown error"
1292
- }),
1808
+ JSON.stringify({ error: "Internal server error" }),
1293
1809
  { status: 500, headers: { "Content-Type": "application/json" } }
1294
1810
  );
1295
1811
  }
@@ -1306,10 +1822,13 @@ function createTypedWebhookHandler(collection, handler) {
1306
1822
 
1307
1823
  // src/utils/order/generateOrderNumber.ts
1308
1824
  var generateOrderNumber = () => {
1825
+ var _a;
1309
1826
  const year = (/* @__PURE__ */ new Date()).getFullYear().toString().slice(-2);
1310
1827
  const month = ((/* @__PURE__ */ new Date()).getMonth() + 1).toString().padStart(2, "0");
1311
1828
  const day = (/* @__PURE__ */ new Date()).getDate().toString().padStart(2, "0");
1312
- const random = Math.floor(Math.random() * 1e6).toString().padStart(6, "0");
1829
+ const array = new Uint32Array(1);
1830
+ globalThis.crypto.getRandomValues(array);
1831
+ const random = (((_a = array[0]) != null ? _a : 0) % 1e6).toString().padStart(6, "0");
1313
1832
  return `${year}${month}${day}${random}`;
1314
1833
  };
1315
1834