@asteby/storefront 0.9.0 → 0.11.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.
package/dist/mock.cjs CHANGED
@@ -44,6 +44,949 @@ function resolveAvailability(source, options = {}) {
44
44
  };
45
45
  }
46
46
 
47
+ // src/mock/region-mx.seed.ts
48
+ var SEED_MX_CSF = {
49
+ "kind": "MX:csf",
50
+ "country_code": "MX",
51
+ "label": "Constancia de situaci\xF3n fiscal",
52
+ "help": "Es el PDF que te da el SAT con tu RFC, tu nombre o raz\xF3n social, tu r\xE9gimen y tu c\xF3digo postal fiscal. Lo leemos en tu dispositivo para llenar tus datos de facturaci\xF3n.",
53
+ "obtain_url": "https://www.sat.gob.mx/portal/public/tramites/constancia-de-situacion-fiscal",
54
+ "accept": [
55
+ "application/pdf"
56
+ ],
57
+ "max_bytes": 5242880,
58
+ "max_pages": 6,
59
+ "engine": "rules@1",
60
+ "rules": {
61
+ "version": 1,
62
+ "normalize": [
63
+ "nbsp",
64
+ "collapse_ws"
65
+ ],
66
+ "labels": [
67
+ "RFC",
68
+ "CURP",
69
+ "Nombre \\(s\\)",
70
+ "Nombre",
71
+ "Primer Apellido",
72
+ "Segundo Apellido",
73
+ "Denominaci[\xF3o]n\\s*/\\s*Raz[\xF3o]n Social",
74
+ "R[\xE9e]gimen de capital",
75
+ "Nombre Comercial",
76
+ "Fecha (?:de )?inicio de operaciones",
77
+ "Fecha de constituci[\xF3o]n",
78
+ "Estatus en el padr[\xF3o]n",
79
+ "Fecha de [\xFAu]ltimo cambio de estado",
80
+ "Datos del domicilio registrado",
81
+ "C[\xF3o]digo Postal",
82
+ "Tipo de Vialidad",
83
+ "Nombre de Vialidad",
84
+ "N[\xFAu]mero Exterior",
85
+ "N[\xFAu]mero Interior",
86
+ "Nombre de la Colonia",
87
+ "Nombre de la Localidad",
88
+ "Nombre del Municipio o Demarcaci[\xF3o]n Territorial",
89
+ "Nombre de la Entidad Federativa",
90
+ "Entre Calle",
91
+ "Y Calle",
92
+ "Actividades Econ[\xF3o]micas",
93
+ "Reg[\xEDi]menes",
94
+ "Obligaciones",
95
+ "Correo Electr[\xF3o]nico"
96
+ ],
97
+ "qr_canonical": "https://siat.sat.gob.mx/app/qr/faces/pages/mobile/validadorqr.jsf?D1=10&D2=1&D3={document_id}_{tax_id}",
98
+ "fields": [
99
+ {
100
+ "key": "tax_id",
101
+ "required": true,
102
+ "strategies": [
103
+ {
104
+ "strategy": "labeled_lines",
105
+ "label": "RFC",
106
+ "upper": true,
107
+ "capture": {
108
+ "pattern": "(?:^|[^A-Z0-9\xD1&])([A-Z\xD1&]{3,4}[0-9]{6}[A-Z0-9]{3})(?:[^A-Z0-9\xD1&]|$)",
109
+ "flags": "i",
110
+ "group": 1
111
+ }
112
+ },
113
+ {
114
+ "strategy": "regex",
115
+ "pattern": "(?:^|[^A-Z0-9\xD1&])([A-Z\xD1&]{3,4}[0-9]{6}[A-Z0-9]{3})(?:[^A-Z0-9\xD1&]|$)",
116
+ "flags": "i",
117
+ "group": 1,
118
+ "upper": true
119
+ },
120
+ {
121
+ "strategy": "qr_param",
122
+ "param": "D3",
123
+ "split": "_",
124
+ "parts": 2,
125
+ "match": "^[A-Z\xD1&]{3,4}[0-9]{6}[A-Z0-9]{3}$"
126
+ },
127
+ {
128
+ "strategy": "qr_param",
129
+ "scan": "(?:D3)?([0-9]{11})[^A-Z0-9\xD1&]{0,3}([A-Z\xD1&]{3,4}[0-9]{6}[A-Z0-9]{3})(?:[^A-Z0-9]|$)",
130
+ "flags": "i",
131
+ "group": 2
132
+ }
133
+ ]
134
+ },
135
+ {
136
+ "key": "legal_name",
137
+ "required": true,
138
+ "strategies": [
139
+ {
140
+ "strategy": "labeled_lines",
141
+ "label": "Denominaci[\xF3o]n\\s*/\\s*Raz[\xF3o]n Social"
142
+ },
143
+ {
144
+ "strategy": "concat_labeled",
145
+ "labels": [
146
+ "Nombre \\(s\\)",
147
+ "Primer Apellido",
148
+ "Segundo Apellido"
149
+ ],
150
+ "separator": " "
151
+ }
152
+ ]
153
+ },
154
+ {
155
+ "key": "postal_code",
156
+ "required": true,
157
+ "strategies": [
158
+ {
159
+ "strategy": "labeled_lines",
160
+ "label": "C[\xF3o]digo Postal",
161
+ "capture": {
162
+ "pattern": "\\b([0-9]{5})\\b",
163
+ "group": 1
164
+ }
165
+ }
166
+ ]
167
+ },
168
+ {
169
+ "key": "tax_regime",
170
+ "required": true,
171
+ "multiple": true,
172
+ "strategies": [
173
+ {
174
+ "strategy": "catalog_phrases",
175
+ "catalog": "fiscal_regime",
176
+ "start": "Reg[\xEDi]menes\\s*:?",
177
+ "end": "Obligaciones\\s*:"
178
+ }
179
+ ]
180
+ },
181
+ {
182
+ "key": "document_id",
183
+ "strategies": [
184
+ {
185
+ "strategy": "regex",
186
+ "pattern": "id\\s*CIF\\s*:?\\s*([0-9]{6,})",
187
+ "flags": "i",
188
+ "group": 1
189
+ },
190
+ {
191
+ "strategy": "qr_param",
192
+ "param": "D3",
193
+ "split": "_",
194
+ "parts": 2,
195
+ "match": "^[0-9]+$"
196
+ },
197
+ {
198
+ "strategy": "qr_param",
199
+ "scan": "(?:D3)?([0-9]{11})[^A-Z0-9\xD1&]{0,3}([A-Z\xD1&]{3,4}[0-9]{6}[A-Z0-9]{3})(?:[^A-Z0-9]|$)",
200
+ "flags": "i",
201
+ "group": 1
202
+ }
203
+ ]
204
+ },
205
+ {
206
+ "key": "issued_on",
207
+ "strategies": [
208
+ {
209
+ "strategy": "date",
210
+ "order": "dmy",
211
+ "pattern": "Fecha\\s+de\\s+Emisi[\xF3o]n\\s*:?[^0-9]*?([0-9]{1,2})\\s+DE\\s+([A-Za-z\xC1\xC9\xCD\xD3\xDA\xD1\xE1\xE9\xED\xF3\xFA\xF1]+)\\s+DE\\s+([0-9]{4})",
212
+ "flags": "i",
213
+ "months": [
214
+ "enero",
215
+ "febrero",
216
+ "marzo",
217
+ "abril",
218
+ "mayo",
219
+ "junio",
220
+ "julio",
221
+ "agosto",
222
+ "septiembre",
223
+ "octubre",
224
+ "noviembre",
225
+ "diciembre"
226
+ ]
227
+ }
228
+ ]
229
+ }
230
+ ]
231
+ },
232
+ "verify_kind": "qr_validator",
233
+ "freshness_days": 90,
234
+ "discard_fields": [
235
+ "curp",
236
+ "street",
237
+ "exterior_number",
238
+ "neighborhood",
239
+ "activities"
240
+ ]
241
+ };
242
+ var SEED_MX_REGIMES = [
243
+ {
244
+ "code": "601",
245
+ "label": "General de Ley Personas Morales",
246
+ "person_types": [
247
+ "company"
248
+ ],
249
+ "match_phrases": [
250
+ "general de ley personas morales"
251
+ ]
252
+ },
253
+ {
254
+ "code": "603",
255
+ "label": "Personas Morales con Fines no Lucrativos",
256
+ "person_types": [
257
+ "company"
258
+ ],
259
+ "match_phrases": [
260
+ "fines no lucrativos"
261
+ ]
262
+ },
263
+ {
264
+ "code": "605",
265
+ "label": "Sueldos y Salarios e Ingresos Asimilados a Salarios",
266
+ "person_types": [
267
+ "individual"
268
+ ],
269
+ "match_phrases": [
270
+ "sueldos y salarios"
271
+ ]
272
+ },
273
+ {
274
+ "code": "606",
275
+ "label": "Arrendamiento",
276
+ "person_types": [
277
+ "individual"
278
+ ],
279
+ "match_phrases": [
280
+ "arrendamiento"
281
+ ]
282
+ },
283
+ {
284
+ "code": "607",
285
+ "label": "R\xE9gimen de Enajenaci\xF3n o Adquisici\xF3n de Bienes",
286
+ "person_types": [
287
+ "individual"
288
+ ],
289
+ "match_phrases": [
290
+ "enajenacion o adquisicion de bienes"
291
+ ]
292
+ },
293
+ {
294
+ "code": "608",
295
+ "label": "Dem\xE1s ingresos",
296
+ "person_types": [
297
+ "individual"
298
+ ],
299
+ "match_phrases": [
300
+ "demas ingresos"
301
+ ]
302
+ },
303
+ {
304
+ "code": "610",
305
+ "label": "Residentes en el Extranjero sin Establecimiento Permanente en M\xE9xico",
306
+ "person_types": [
307
+ "individual",
308
+ "company"
309
+ ],
310
+ "match_phrases": [
311
+ "residentes en el extranjero"
312
+ ]
313
+ },
314
+ {
315
+ "code": "611",
316
+ "label": "Ingresos por Dividendos (socios y accionistas)",
317
+ "person_types": [
318
+ "individual"
319
+ ],
320
+ "match_phrases": [
321
+ "dividendos"
322
+ ]
323
+ },
324
+ {
325
+ "code": "612",
326
+ "label": "Personas F\xEDsicas con Actividades Empresariales y Profesionales",
327
+ "person_types": [
328
+ "individual"
329
+ ],
330
+ "match_phrases": [
331
+ "actividades empresariales y profesionales"
332
+ ]
333
+ },
334
+ {
335
+ "code": "614",
336
+ "label": "Ingresos por intereses",
337
+ "person_types": [
338
+ "individual"
339
+ ],
340
+ "match_phrases": [
341
+ "ingresos por intereses"
342
+ ]
343
+ },
344
+ {
345
+ "code": "615",
346
+ "label": "R\xE9gimen de los ingresos por obtenci\xF3n de premios",
347
+ "person_types": [
348
+ "individual"
349
+ ],
350
+ "match_phrases": [
351
+ "premios"
352
+ ]
353
+ },
354
+ {
355
+ "code": "616",
356
+ "label": "Sin obligaciones fiscales",
357
+ "person_types": [
358
+ "individual"
359
+ ],
360
+ "match_phrases": [
361
+ "sin obligaciones fiscales"
362
+ ]
363
+ },
364
+ {
365
+ "code": "620",
366
+ "label": "Sociedades Cooperativas de Producci\xF3n que optan por diferir sus ingresos",
367
+ "person_types": [
368
+ "company"
369
+ ],
370
+ "match_phrases": [
371
+ "sociedades cooperativas de produccion"
372
+ ]
373
+ },
374
+ {
375
+ "code": "621",
376
+ "label": "Incorporaci\xF3n Fiscal",
377
+ "person_types": [
378
+ "individual"
379
+ ],
380
+ "match_phrases": [
381
+ "incorporacion fiscal"
382
+ ]
383
+ },
384
+ {
385
+ "code": "622",
386
+ "label": "Actividades Agr\xEDcolas, Ganaderas, Silv\xEDcolas y Pesqueras",
387
+ "person_types": [
388
+ "company"
389
+ ],
390
+ "match_phrases": [
391
+ "actividades agricolas"
392
+ ]
393
+ },
394
+ {
395
+ "code": "623",
396
+ "label": "Opcional para Grupos de Sociedades",
397
+ "person_types": [
398
+ "company"
399
+ ],
400
+ "match_phrases": [
401
+ "opcional para grupos de sociedades"
402
+ ]
403
+ },
404
+ {
405
+ "code": "624",
406
+ "label": "Coordinados",
407
+ "person_types": [
408
+ "company"
409
+ ],
410
+ "match_phrases": [
411
+ "coordinados"
412
+ ]
413
+ },
414
+ {
415
+ "code": "625",
416
+ "label": "R\xE9gimen de las Actividades Empresariales con ingresos a trav\xE9s de Plataformas Tecnol\xF3gicas",
417
+ "person_types": [
418
+ "individual"
419
+ ],
420
+ "match_phrases": [
421
+ "plataformas tecnologicas"
422
+ ]
423
+ },
424
+ {
425
+ "code": "626",
426
+ "label": "R\xE9gimen Simplificado de Confianza",
427
+ "person_types": [
428
+ "individual",
429
+ "company"
430
+ ],
431
+ "match_phrases": [
432
+ "simplificado de confianza"
433
+ ]
434
+ }
435
+ ];
436
+ var SEED_MX_INVOICE_USES = [
437
+ {
438
+ "code": "G01",
439
+ "label": "Adquisici\xF3n de mercanc\xEDas",
440
+ "person_types": [
441
+ "individual",
442
+ "company"
443
+ ],
444
+ "allowed_regimes": [
445
+ "601",
446
+ "603",
447
+ "606",
448
+ "612",
449
+ "620",
450
+ "621",
451
+ "622",
452
+ "623",
453
+ "624",
454
+ "625",
455
+ "626"
456
+ ]
457
+ },
458
+ {
459
+ "code": "G03",
460
+ "label": "Gastos en general",
461
+ "person_types": [
462
+ "individual",
463
+ "company"
464
+ ],
465
+ "allowed_regimes": [
466
+ "601",
467
+ "603",
468
+ "606",
469
+ "612",
470
+ "620",
471
+ "621",
472
+ "622",
473
+ "623",
474
+ "624",
475
+ "625",
476
+ "626"
477
+ ]
478
+ },
479
+ {
480
+ "code": "I01",
481
+ "label": "Construcciones",
482
+ "person_types": [
483
+ "individual",
484
+ "company"
485
+ ],
486
+ "allowed_regimes": [
487
+ "601",
488
+ "603",
489
+ "606",
490
+ "612",
491
+ "620",
492
+ "621",
493
+ "622",
494
+ "623",
495
+ "624",
496
+ "625",
497
+ "626"
498
+ ]
499
+ },
500
+ {
501
+ "code": "I02",
502
+ "label": "Mobiliario y equipo de oficina por inversiones",
503
+ "person_types": [
504
+ "individual",
505
+ "company"
506
+ ],
507
+ "allowed_regimes": [
508
+ "601",
509
+ "603",
510
+ "606",
511
+ "612",
512
+ "620",
513
+ "621",
514
+ "622",
515
+ "623",
516
+ "624",
517
+ "625",
518
+ "626"
519
+ ]
520
+ },
521
+ {
522
+ "code": "I03",
523
+ "label": "Equipo de transporte",
524
+ "person_types": [
525
+ "individual",
526
+ "company"
527
+ ],
528
+ "allowed_regimes": [
529
+ "601",
530
+ "603",
531
+ "606",
532
+ "612",
533
+ "620",
534
+ "621",
535
+ "622",
536
+ "623",
537
+ "624",
538
+ "625",
539
+ "626"
540
+ ]
541
+ },
542
+ {
543
+ "code": "I04",
544
+ "label": "Equipo de c\xF3mputo y accesorios",
545
+ "person_types": [
546
+ "individual",
547
+ "company"
548
+ ],
549
+ "allowed_regimes": [
550
+ "601",
551
+ "603",
552
+ "606",
553
+ "612",
554
+ "620",
555
+ "621",
556
+ "622",
557
+ "623",
558
+ "624",
559
+ "625",
560
+ "626"
561
+ ]
562
+ },
563
+ {
564
+ "code": "I05",
565
+ "label": "Dados, troqueles, moldes, matrices y herramental",
566
+ "person_types": [
567
+ "individual",
568
+ "company"
569
+ ],
570
+ "allowed_regimes": [
571
+ "601",
572
+ "603",
573
+ "606",
574
+ "612",
575
+ "620",
576
+ "621",
577
+ "622",
578
+ "623",
579
+ "624",
580
+ "625",
581
+ "626"
582
+ ]
583
+ },
584
+ {
585
+ "code": "I06",
586
+ "label": "Comunicaciones telef\xF3nicas",
587
+ "person_types": [
588
+ "individual",
589
+ "company"
590
+ ],
591
+ "allowed_regimes": [
592
+ "601",
593
+ "603",
594
+ "606",
595
+ "612",
596
+ "620",
597
+ "621",
598
+ "622",
599
+ "623",
600
+ "624",
601
+ "625",
602
+ "626"
603
+ ]
604
+ },
605
+ {
606
+ "code": "I07",
607
+ "label": "Comunicaciones satelitales",
608
+ "person_types": [
609
+ "individual",
610
+ "company"
611
+ ],
612
+ "allowed_regimes": [
613
+ "601",
614
+ "603",
615
+ "606",
616
+ "612",
617
+ "620",
618
+ "621",
619
+ "622",
620
+ "623",
621
+ "624",
622
+ "625",
623
+ "626"
624
+ ]
625
+ },
626
+ {
627
+ "code": "I08",
628
+ "label": "Otra maquinaria y equipo",
629
+ "person_types": [
630
+ "individual",
631
+ "company"
632
+ ],
633
+ "allowed_regimes": [
634
+ "601",
635
+ "603",
636
+ "606",
637
+ "612",
638
+ "620",
639
+ "621",
640
+ "622",
641
+ "623",
642
+ "624",
643
+ "625",
644
+ "626"
645
+ ]
646
+ },
647
+ {
648
+ "code": "D01",
649
+ "label": "Honorarios m\xE9dicos, dentales y gastos hospitalarios",
650
+ "person_types": [
651
+ "individual"
652
+ ],
653
+ "allowed_regimes": [
654
+ "605",
655
+ "606",
656
+ "607",
657
+ "608",
658
+ "611",
659
+ "612",
660
+ "614",
661
+ "615",
662
+ "625"
663
+ ]
664
+ },
665
+ {
666
+ "code": "D02",
667
+ "label": "Gastos m\xE9dicos por incapacidad o discapacidad",
668
+ "person_types": [
669
+ "individual"
670
+ ],
671
+ "allowed_regimes": [
672
+ "605",
673
+ "606",
674
+ "607",
675
+ "608",
676
+ "611",
677
+ "612",
678
+ "614",
679
+ "615",
680
+ "625"
681
+ ]
682
+ },
683
+ {
684
+ "code": "D03",
685
+ "label": "Gastos funerales",
686
+ "person_types": [
687
+ "individual"
688
+ ],
689
+ "allowed_regimes": [
690
+ "605",
691
+ "606",
692
+ "607",
693
+ "608",
694
+ "611",
695
+ "612",
696
+ "614",
697
+ "615",
698
+ "625"
699
+ ]
700
+ },
701
+ {
702
+ "code": "D04",
703
+ "label": "Donativos",
704
+ "person_types": [
705
+ "individual"
706
+ ],
707
+ "allowed_regimes": [
708
+ "605",
709
+ "606",
710
+ "607",
711
+ "608",
712
+ "611",
713
+ "612",
714
+ "614",
715
+ "615",
716
+ "625"
717
+ ]
718
+ },
719
+ {
720
+ "code": "D05",
721
+ "label": "Intereses reales efectivamente pagados por cr\xE9ditos hipotecarios (casa habitaci\xF3n)",
722
+ "person_types": [
723
+ "individual"
724
+ ],
725
+ "allowed_regimes": [
726
+ "605",
727
+ "606",
728
+ "607",
729
+ "608",
730
+ "611",
731
+ "612",
732
+ "614",
733
+ "615",
734
+ "625"
735
+ ]
736
+ },
737
+ {
738
+ "code": "D06",
739
+ "label": "Aportaciones voluntarias al SAR",
740
+ "person_types": [
741
+ "individual"
742
+ ],
743
+ "allowed_regimes": [
744
+ "605",
745
+ "606",
746
+ "607",
747
+ "608",
748
+ "611",
749
+ "612",
750
+ "614",
751
+ "615",
752
+ "625"
753
+ ]
754
+ },
755
+ {
756
+ "code": "D07",
757
+ "label": "Primas por seguros de gastos m\xE9dicos",
758
+ "person_types": [
759
+ "individual"
760
+ ],
761
+ "allowed_regimes": [
762
+ "605",
763
+ "606",
764
+ "607",
765
+ "608",
766
+ "611",
767
+ "612",
768
+ "614",
769
+ "615",
770
+ "625"
771
+ ]
772
+ },
773
+ {
774
+ "code": "D08",
775
+ "label": "Gastos de transportaci\xF3n escolar obligatoria",
776
+ "person_types": [
777
+ "individual"
778
+ ],
779
+ "allowed_regimes": [
780
+ "605",
781
+ "606",
782
+ "607",
783
+ "608",
784
+ "611",
785
+ "612",
786
+ "614",
787
+ "615",
788
+ "625"
789
+ ]
790
+ },
791
+ {
792
+ "code": "D09",
793
+ "label": "Dep\xF3sitos en cuentas para el ahorro, primas que tengan como base planes de pensiones",
794
+ "person_types": [
795
+ "individual"
796
+ ],
797
+ "allowed_regimes": [
798
+ "605",
799
+ "606",
800
+ "607",
801
+ "608",
802
+ "611",
803
+ "612",
804
+ "614",
805
+ "615",
806
+ "625"
807
+ ]
808
+ },
809
+ {
810
+ "code": "D10",
811
+ "label": "Pagos por servicios educativos (colegiaturas)",
812
+ "person_types": [
813
+ "individual"
814
+ ],
815
+ "allowed_regimes": [
816
+ "605",
817
+ "606",
818
+ "607",
819
+ "608",
820
+ "611",
821
+ "612",
822
+ "614",
823
+ "615",
824
+ "625"
825
+ ]
826
+ },
827
+ {
828
+ "code": "S01",
829
+ "label": "Sin efectos fiscales",
830
+ "person_types": [
831
+ "individual",
832
+ "company"
833
+ ],
834
+ "allowed_regimes": [
835
+ "601",
836
+ "603",
837
+ "605",
838
+ "606",
839
+ "607",
840
+ "608",
841
+ "610",
842
+ "611",
843
+ "612",
844
+ "614",
845
+ "615",
846
+ "616",
847
+ "620",
848
+ "621",
849
+ "622",
850
+ "623",
851
+ "624",
852
+ "625",
853
+ "626"
854
+ ]
855
+ }
856
+ ];
857
+ var SEED_MX_PAYMENT_METHODS = [
858
+ {
859
+ "code": "card",
860
+ "label": "Tarjeta de cr\xE9dito o d\xE9bito",
861
+ "description": "Visa, Mastercard y American Express. Pago seguro procesado por tu pasarela.",
862
+ "kind": "card",
863
+ "flow": "inline",
864
+ "providers": [
865
+ "mercadopago",
866
+ "stripe"
867
+ ],
868
+ "installments": null,
869
+ "min_amount": null,
870
+ "max_amount": null,
871
+ "icon": "CreditCard",
872
+ "fiscal_payment_form": "04,28"
873
+ },
874
+ {
875
+ "code": "mercadopago",
876
+ "label": "Mercado Pago",
877
+ "description": "Paga con tu cuenta de Mercado Pago: saldo, tarjetas guardadas o meses.",
878
+ "kind": "wallet",
879
+ "flow": "redirect",
880
+ "providers": [
881
+ "mercadopago"
882
+ ],
883
+ "installments": null,
884
+ "min_amount": null,
885
+ "max_amount": null,
886
+ "icon": "Wallet",
887
+ "fiscal_payment_form": "06,04,28"
888
+ },
889
+ {
890
+ "code": "oxxo",
891
+ "label": "Efectivo en OXXO",
892
+ "description": "Recibe una referencia y paga en cualquier tienda OXXO. Confirmamos tu pedido cuando se acredita el pago.",
893
+ "kind": "cash_voucher",
894
+ "flow": "voucher",
895
+ "providers": [
896
+ "mercadopago",
897
+ "stripe"
898
+ ],
899
+ "installments": null,
900
+ "min_amount": null,
901
+ "max_amount": null,
902
+ "expires_hours": 72,
903
+ "icon": "Store",
904
+ "fiscal_payment_form": "01"
905
+ },
906
+ {
907
+ "code": "spei",
908
+ "label": "Transferencia SPEI",
909
+ "description": "Paga desde la app de tu banco con una CLABE \xFAnica para tu pedido; se confirma en minutos.",
910
+ "kind": "bank_transfer",
911
+ "flow": "instructions",
912
+ "providers": [
913
+ "mercadopago",
914
+ "stripe"
915
+ ],
916
+ "installments": null,
917
+ "min_amount": null,
918
+ "max_amount": null,
919
+ "expires_hours": 24,
920
+ "icon": "Landmark",
921
+ "fiscal_payment_form": "03"
922
+ }
923
+ ];
924
+ var SEED_MX_FISCAL_ID_PATTERN = "^[A-Z\xD1&]{3,4}[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])[A-Z0-9]{2}[0-9A]$";
925
+ var SEED_MX_GENERIC_IDS = ["XAXX010101000", "XEXX010101000"];
926
+
927
+ // src/mock/region.ts
928
+ var MOCK_IDENTITY_DOCUMENT_MX_CSF = SEED_MX_CSF;
929
+ var MOCK_CSF_RULES = SEED_MX_CSF.rules;
930
+ var MOCK_FISCAL_ID_MX = {
931
+ kind: "mx_rfc",
932
+ label: "RFC",
933
+ pattern: SEED_MX_FISCAL_ID_PATTERN,
934
+ generic_ids: SEED_MX_GENERIC_IDS,
935
+ regimes: SEED_MX_REGIMES,
936
+ invoice_uses: SEED_MX_INVOICE_USES,
937
+ documents: [SEED_MX_CSF]
938
+ };
939
+ var MOCK_REGION_MX = {
940
+ country_code: "MX",
941
+ name: "M\xE9xico",
942
+ locale: { default: "es-MX", available: ["es-MX", "en-US"], current: "es-MX" },
943
+ timezone: "America/Mexico_City",
944
+ currency: { code: "MXN", symbol: "$", symbol_position: "before", minor_units: 2 },
945
+ formats: { date: "dd/MM/yyyy", measurement: "metric" },
946
+ tax: { prices_include_tax: true, label: "IVA", price_label: "IVA incluido", show_breakdown: true, default_category: "standard", categories: ["standard"] },
947
+ address: { postal_code: { pattern: "^[0-9]{5}$", example: "06600" } },
948
+ fiscal_id: MOCK_FISCAL_ID_MX,
949
+ payment_methods: SEED_MX_PAYMENT_METHODS
950
+ };
951
+ function mockPersonType(taxId) {
952
+ if (taxId.length === 13) return "individual";
953
+ if (taxId.length === 12) return "company";
954
+ return null;
955
+ }
956
+ function validateInvoiceRequest(region, input, prefix = "invoice") {
957
+ const text = (...v) => v.map((x) => typeof x === "string" ? x.trim() : "").find(Boolean) ?? "";
958
+ const fid = region?.fiscal_id;
959
+ const taxId = text(input.tax_id, input.rfc).toUpperCase();
960
+ const name = text(input.legal_name, input.razon_social);
961
+ const regime = text(input.tax_regime, input.regimen);
962
+ const use = text(input.use, input.uso_cfdi);
963
+ const postal = text(input.postal_code, input.cp);
964
+ const bad = (field, message) => ({ field: `${prefix}.${field}`, message });
965
+ if (!taxId) return bad("tax_id", "The tax id is required");
966
+ if (fid?.pattern && !fid.generic_ids.includes(taxId) && !new RegExp(fid.pattern).test(taxId)) return bad("tax_id", `Not a valid ${fid.kind}`);
967
+ if (!name) return bad("legal_name", "The legal name is required");
968
+ if (!regime) return bad("tax_regime", "The tax regime is required");
969
+ const entry = fid?.regimes.find((r) => r.code === regime);
970
+ if (fid && !entry) return bad("tax_regime", `Unknown tax regime ${regime}`);
971
+ const person = fid?.generic_ids.includes(taxId) ? null : mockPersonType(taxId);
972
+ if (entry && person && entry.person_types.length > 0 && !entry.person_types.includes(person)) {
973
+ return bad("tax_regime", `The regime ${regime} does not apply to this ${fid.kind}`);
974
+ }
975
+ const postalPattern = region?.address?.postal_code?.pattern;
976
+ if (!postal || postalPattern && !new RegExp(postalPattern).test(postal)) return bad("postal_code", "Not a valid postal code");
977
+ if (!use) return bad("use", "The invoice use is required");
978
+ const useEntry = fid?.invoice_uses.find((u) => u.code === use);
979
+ if (fid && !useEntry) return bad("use", `Unknown invoice use ${use}`);
980
+ if (useEntry?.allowed_regimes && useEntry.allowed_regimes.length > 0 && !useEntry.allowed_regimes.includes(regime)) {
981
+ return bad("use", `The regime ${regime} does not admit the use ${use}`);
982
+ }
983
+ return null;
984
+ }
985
+ function maskTaxId(taxId) {
986
+ const v = taxId.trim();
987
+ return v.length <= 4 ? "*".repeat(v.length) : `${v.slice(0, 2)}${"*".repeat(v.length - 5)}${v.slice(-3)}`;
988
+ }
989
+
47
990
  // src/mock/seed.ts
48
991
  var MOCK_IMAGE_URL = (seed, width = 800, height = 800) => `https://picsum.photos/seed/${encodeURIComponent(seed)}/${width}/${height}`;
49
992
  var MOCK_CURRENCY = "MXN";
@@ -382,17 +1325,19 @@ function buildCustomers() {
382
1325
 
383
1326
  // src/mock/index.ts
384
1327
  var HttpError = class extends Error {
385
- constructor(status, code, message, field, details) {
1328
+ constructor(status, code, message, field, details, requiredScopes) {
386
1329
  super(message);
387
1330
  this.status = status;
388
1331
  this.code = code;
389
1332
  this.field = field;
390
1333
  this.details = details;
1334
+ this.requiredScopes = requiredScopes;
391
1335
  }
392
1336
  status;
393
1337
  code;
394
1338
  field;
395
1339
  details;
1340
+ requiredScopes;
396
1341
  };
397
1342
  var PUBLIC_CACHE = "public, max-age=60, stale-while-revalidate=600";
398
1343
  var PRIVATE_CACHE = "private, no-store";
@@ -438,6 +1383,31 @@ function createMockStorefront(options = {}) {
438
1383
  const currency = options.currency ?? MOCK_CURRENCY;
439
1384
  const imageUrl = options.imageUrl ?? MOCK_IMAGE_URL;
440
1385
  const otpCode = options.otpCode ?? "000000";
1386
+ const capabilities = {
1387
+ password: true,
1388
+ email_verification: true,
1389
+ otp_channels: ["email"],
1390
+ invoicing: {
1391
+ available: true,
1392
+ countries: ["MX"],
1393
+ checkout: "optional",
1394
+ post_purchase: true,
1395
+ window_days: 30,
1396
+ identity_documents: ["MX:csf"],
1397
+ online_verify: false
1398
+ },
1399
+ ...options.customerCapabilities
1400
+ };
1401
+ const missingScopes = options.missingScopes ?? [];
1402
+ if (missingScopes.includes("customer:write")) {
1403
+ capabilities.password = false;
1404
+ capabilities.unavailable_reason = "missing_scope";
1405
+ capabilities.missing_scopes = ["customer:write"];
1406
+ }
1407
+ const region = options.region === void 0 ? MOCK_REGION_MX : options.region;
1408
+ const maxLoginAttempts = options.maxLoginAttempts ?? 5;
1409
+ const MIN_PASSWORD = 10;
1410
+ const MAX_PASSWORD = 128;
441
1411
  const discountCodes = Object.fromEntries(
442
1412
  Object.entries(options.discountCodes ?? { BIENVENIDA10: 10 }).map(([k, v]) => [k.toUpperCase(), v])
443
1413
  );
@@ -470,11 +1440,15 @@ function createMockStorefront(options = {}) {
470
1440
  }
471
1441
  ],
472
1442
  otps: /* @__PURE__ */ new Map(),
1443
+ passwords: /* @__PURE__ */ new Map(),
1444
+ pendingRegistrations: /* @__PURE__ */ new Map(),
1445
+ loginFailures: /* @__PURE__ */ new Map(),
473
1446
  sessions: /* @__PURE__ */ new Map(),
474
1447
  idempotency: /* @__PURE__ */ new Map(),
475
1448
  checkouts: /* @__PURE__ */ new Map(),
476
1449
  payments: /* @__PURE__ */ new Map(),
477
1450
  restock: /* @__PURE__ */ new Set(),
1451
+ invoices: /* @__PURE__ */ new Map(),
478
1452
  seq: 0
479
1453
  };
480
1454
  }
@@ -737,9 +1711,39 @@ function createMockStorefront(options = {}) {
737
1711
  tax_included: true
738
1712
  },
739
1713
  note: cart.note,
1714
+ invoice: cart.invoice ? cartInvoiceOf(cart.invoice) : null,
740
1715
  updated_at: cart.updated_at
741
1716
  };
742
1717
  }
1718
+ function cartInvoiceOf(inv) {
1719
+ const taxId = typeof inv.tax_id === "string" ? inv.tax_id : typeof inv.rfc === "string" ? inv.rfc : "";
1720
+ const name = typeof inv.legal_name === "string" ? inv.legal_name : typeof inv.razon_social === "string" ? inv.razon_social : null;
1721
+ return {
1722
+ requested: true,
1723
+ tax_id_masked: taxId ? maskTaxId(taxId) : null,
1724
+ legal_name: name,
1725
+ country_code: inv.country_code ?? region?.country_code ?? null,
1726
+ document_kind: inv.document?.kind ?? null
1727
+ };
1728
+ }
1729
+ function parseInvoice(raw, prefix = "invoice") {
1730
+ if (raw === null || raw === void 0) return null;
1731
+ if (typeof raw !== "object" || Array.isArray(raw)) throw new HttpError(400, "validation", "invoice must be an object", prefix);
1732
+ const inv = raw;
1733
+ if (inv.requested === false) return null;
1734
+ const problem = validateInvoiceRequest(region, inv, prefix);
1735
+ if (problem) throw new HttpError(422, "invalid_state", problem.message, problem.field);
1736
+ return inv;
1737
+ }
1738
+ const orderInvoice = (order) => {
1739
+ const entry = state.invoices.get(order.id);
1740
+ const paid = order.status !== "pending_payment";
1741
+ if (entry) {
1742
+ const stage = entry.stage === "awaiting_payment" && paid ? "queued" : entry.stage;
1743
+ return { stage, requested: true, status: stage === "issued" ? "issued" : "requested", action: stage === "awaiting_payment" ? "wait" : "none", can_request: false, url: null, xml_url: null };
1744
+ }
1745
+ return paid ? { status: "not_requested", stage: "not_requested", requested: false, action: "request", can_request: true, blocked_reason: null } : { status: "not_requested", stage: "not_requested", requested: false, action: "none", can_request: false, blocked_reason: "awaiting_payment" };
1746
+ };
743
1747
  function requireCustomer(headers) {
744
1748
  const token = headers.get("x-customer-token");
745
1749
  const id = token ? state.sessions.get(token) : void 0;
@@ -754,6 +1758,39 @@ function createMockStorefront(options = {}) {
754
1758
  if (email && !/^[^@\s]+@[^@\s]+$/.test(email)) throw new HttpError(400, "validation", "Invalid email", "email");
755
1759
  return email ? `email:${email}` : `phone:${phone}`;
756
1760
  }
1761
+ function emailOf(body) {
1762
+ const email = typeof body.email === "string" ? body.email.trim().toLowerCase() : "";
1763
+ if (!email || !/^[^@\s]+@[^@\s]+$/.test(email)) throw new HttpError(400, "validation", "Invalid email", "email");
1764
+ return email;
1765
+ }
1766
+ function passwordOf(body, field = "password") {
1767
+ const value = body[field];
1768
+ if (typeof value !== "string" || value.length < MIN_PASSWORD || value.length > MAX_PASSWORD) {
1769
+ throw new HttpError(400, "validation", `${field} must be ${MIN_PASSWORD}-${MAX_PASSWORD} characters`, field);
1770
+ }
1771
+ return value;
1772
+ }
1773
+ function requirePasswordEnabled() {
1774
+ if (!capabilities.password) throw new HttpError(403, "forbidden", "Password accounts are disabled for this store");
1775
+ }
1776
+ function sessionFor(email, extra = {}) {
1777
+ let customer = state.customers.find((c) => c.email === email);
1778
+ if (!customer) {
1779
+ customer = {
1780
+ id: nextId("cus"),
1781
+ email,
1782
+ phone: null,
1783
+ first_name: extra.first_name ?? null,
1784
+ last_name: extra.last_name ?? null,
1785
+ default_address_id: null,
1786
+ created_at: now()
1787
+ };
1788
+ state.customers.push(customer);
1789
+ }
1790
+ const token = `ct_${customer.id}_${Math.random().toString(36).slice(2)}`;
1791
+ state.sessions.set(token, customer.id);
1792
+ return { token, expires_at: new Date(Date.now() + 30 * 864e5).toISOString(), customer };
1793
+ }
757
1794
  function validateAddress(body, partial = false) {
758
1795
  const required = ["address1", "city", "zip", "country_code"];
759
1796
  if (!partial) {
@@ -779,6 +1816,10 @@ function createMockStorefront(options = {}) {
779
1816
  return value;
780
1817
  };
781
1818
  route("GET", "/shop", "catalog:read", () => ({ body: state.shop, cache: "public" }));
1819
+ route("GET", "/region", "catalog:read", () => {
1820
+ if (!region) throw new HttpError(404, "not_found", "No region configured");
1821
+ return { body: region, cache: "public" };
1822
+ });
782
1823
  route("GET", "/products", "catalog:read", ({ search }) => ({ body: listProducts(search), cache: "public" }));
783
1824
  route("GET", "/products/:handle", "catalog:read", ({ params }) => ({
784
1825
  body: requireNode(state.products.find((p) => p.handle === params[0]), `Product ${params[0]}`),
@@ -835,6 +1876,8 @@ function createMockStorefront(options = {}) {
835
1876
  shipping_address: null,
836
1877
  delivery: { method: null, rate_id: null, branch_id: null },
837
1878
  note: null,
1879
+ invoice: null,
1880
+ checkedOut: false,
838
1881
  updated_at: now()
839
1882
  };
840
1883
  if (body.lines !== void 0) addLines(cart, validateLines(body.lines));
@@ -931,6 +1974,13 @@ function createMockStorefront(options = {}) {
931
1974
  cart.updated_at = now();
932
1975
  return { body: renderCart(cart), cache: "private" };
933
1976
  });
1977
+ route("PUT", "/carts/:id/invoice", "cart:write", ({ params, body }) => {
1978
+ const cart = getCartRecord(params[0]);
1979
+ if (cart.checkedOut) throw new HttpError(409, "already_checked_out", "The cart is already an order");
1980
+ cart.invoice = parseInvoice(body);
1981
+ cart.updated_at = now();
1982
+ return { body: renderCart(cart), cache: "private" };
1983
+ });
934
1984
  route("PUT", "/carts/:id/note", "cart:write", ({ params, body }) => {
935
1985
  const cart = getCartRecord(params[0]);
936
1986
  const raw = body.note;
@@ -981,6 +2031,7 @@ function createMockStorefront(options = {}) {
981
2031
  }
982
2032
  if (typeof body.payment_method !== "string" || !body.payment_method) throw new HttpError(400, "validation", "payment_method is required", "payment_method");
983
2033
  if (typeof body.return_url !== "string" || !body.return_url) throw new HttpError(400, "validation", "return_url is required", "return_url");
2034
+ const invoice = body.invoice !== void 0 ? parseInvoice(body.invoice) : record.invoice;
984
2035
  checkStock(record.lines.map((l, i) => ({ variant: findVariant(l.variant_id).variant, quantity: l.quantity, lineId: l.id, field: `lines[${i}].quantity` })));
985
2036
  for (const l of record.lines) {
986
2037
  const v = findVariant(l.variant_id).variant;
@@ -1025,6 +2076,8 @@ function createMockStorefront(options = {}) {
1025
2076
  }
1026
2077
  };
1027
2078
  state.checkouts.set(checkoutId, result);
2079
+ record.checkedOut = true;
2080
+ if (invoice) state.invoices.set(orderId, { stage: "awaiting_payment", request: invoice });
1028
2081
  if (key) state.idempotency.set(`${params[0]}:${key}`, { status: 201, body: result });
1029
2082
  return { status: 201, body: result, cache: "private" };
1030
2083
  });
@@ -1118,6 +2171,8 @@ function createMockStorefront(options = {}) {
1118
2171
  } else {
1119
2172
  payment = { provider: "mock", status: "paid" };
1120
2173
  found.checkout.status = "paid";
2174
+ const order = state.orders.find((o) => o.id === found.checkout.external_order_id);
2175
+ if (order) order.status = "paid";
1121
2176
  }
1122
2177
  payment.outcome = payment.status === "paid" ? "approved" : payment.status === "failed" ? "rejected" : payment.action?.type === "challenge" ? "challenge" : "pending";
1123
2178
  const result = { attempt: { n: st.attempts }, payment, checkout: found.checkout, attempts_left: attemptsLeft };
@@ -1169,8 +2224,106 @@ function createMockStorefront(options = {}) {
1169
2224
  cache: "private"
1170
2225
  };
1171
2226
  });
1172
- route("GET", "/customer", "customer:read", ({ headers }) => ({ body: requireCustomer(headers), cache: "private" }));
1173
- const stripOrder = ({ customer_id: _c, ...o }) => o;
2227
+ route("GET", "/customer/capabilities", "customer:read", () => ({ body: capabilities, cache: "private" }));
2228
+ route("POST", "/customer/register", "customer:write", ({ body }) => {
2229
+ requirePasswordEnabled();
2230
+ const email = emailOf(body);
2231
+ const password = passwordOf(body);
2232
+ const text = (v) => typeof v === "string" && v.trim() ? v.trim() : null;
2233
+ const first_name = text(body.first_name);
2234
+ const last_name = text(body.last_name);
2235
+ if (state.passwords.has(email)) throw new HttpError(409, "conflict", "An account with this email already exists", "email");
2236
+ if (capabilities.email_verification) {
2237
+ state.pendingRegistrations.set(email, { password, first_name, last_name });
2238
+ state.otps.set(`email:${email}`, otpCode);
2239
+ return { status: 202, body: { status: "verification_required" }, cache: "private" };
2240
+ }
2241
+ state.passwords.set(email, password);
2242
+ return { status: 201, body: sessionFor(email, { first_name, last_name }), cache: "private" };
2243
+ });
2244
+ route("POST", "/customer/register/verify", "customer:write", ({ body }) => {
2245
+ requirePasswordEnabled();
2246
+ const email = emailOf(body);
2247
+ const pending = state.pendingRegistrations.get(email);
2248
+ if (!pending || typeof body.code !== "string" || state.otps.get(`email:${email}`) !== body.code) {
2249
+ throw new HttpError(401, "unauthorized", "Invalid or expired code", "code");
2250
+ }
2251
+ state.pendingRegistrations.delete(email);
2252
+ state.otps.delete(`email:${email}`);
2253
+ state.passwords.set(email, pending.password);
2254
+ return { status: 201, body: sessionFor(email, pending), cache: "private" };
2255
+ });
2256
+ route("POST", "/customer/login", "customer:write", ({ body }) => {
2257
+ requirePasswordEnabled();
2258
+ const email = emailOf(body);
2259
+ if ((state.loginFailures.get(email) ?? 0) >= maxLoginAttempts) {
2260
+ throw new HttpError(429, "rate_limited", "Too many failed attempts, try again later");
2261
+ }
2262
+ const stored = state.passwords.get(email);
2263
+ if (stored === void 0 || typeof body.password !== "string" || body.password !== stored) {
2264
+ state.loginFailures.set(email, (state.loginFailures.get(email) ?? 0) + 1);
2265
+ throw new HttpError(401, "unauthorized", "Invalid email or password");
2266
+ }
2267
+ state.loginFailures.delete(email);
2268
+ return { status: 201, body: sessionFor(email), cache: "private" };
2269
+ });
2270
+ route("PUT", "/customer/password", "customer:write", ({ headers, body }) => {
2271
+ requirePasswordEnabled();
2272
+ const customer = requireCustomer(headers);
2273
+ const password = passwordOf(body);
2274
+ const email = customer.email;
2275
+ if (!email) throw new HttpError(422, "invalid_state", "The account has no email", "email");
2276
+ const current = state.passwords.get(email);
2277
+ if (current !== void 0 && body.current_password !== current) {
2278
+ throw new HttpError(401, "unauthorized", "current_password is missing or wrong", "current_password");
2279
+ }
2280
+ state.passwords.set(email, password);
2281
+ return { status: 204 };
2282
+ });
2283
+ route("POST", "/customer/password/reset", "customer:write", ({ body }) => {
2284
+ requirePasswordEnabled();
2285
+ const email = emailOf(body);
2286
+ const password = passwordOf(body);
2287
+ if (typeof body.code !== "string" || state.otps.get(`email:${email}`) !== body.code || !state.customers.some((c) => c.email === email)) {
2288
+ throw new HttpError(401, "unauthorized", "Invalid or expired code", "code");
2289
+ }
2290
+ state.otps.delete(`email:${email}`);
2291
+ state.passwords.set(email, password);
2292
+ state.loginFailures.delete(email);
2293
+ return { status: 204 };
2294
+ });
2295
+ const publicCustomer = (c) => {
2296
+ if (!c.fiscal?.document) return c;
2297
+ const { sha256: _sha, ...document } = c.fiscal.document;
2298
+ return { ...c, fiscal: { ...c.fiscal, document } };
2299
+ };
2300
+ route("GET", "/customer", "customer:read", ({ headers }) => ({ body: publicCustomer(requireCustomer(headers)), cache: "private" }));
2301
+ route("PATCH", "/customer", "customer:write", ({ headers, body }) => {
2302
+ const c = requireCustomer(headers);
2303
+ const text = (v) => typeof v === "string" && v.trim() ? v.trim() : null;
2304
+ if ("first_name" in body) c.first_name = text(body.first_name);
2305
+ if ("last_name" in body) c.last_name = text(body.last_name);
2306
+ if ("phone" in body) c.phone = text(body.phone);
2307
+ if ("fiscal" in body) {
2308
+ if (body.fiscal === null) c.fiscal = null;
2309
+ else {
2310
+ const fiscal = parseInvoice({ ...body.fiscal, requested: true }, "fiscal");
2311
+ const fid = {
2312
+ country_code: String(fiscal.country_code ?? region?.country_code ?? ""),
2313
+ tax_id: String(fiscal.tax_id ?? fiscal.rfc).toUpperCase(),
2314
+ legal_name: String(fiscal.legal_name ?? fiscal.razon_social),
2315
+ tax_regime: String(fiscal.tax_regime ?? fiscal.regimen),
2316
+ postal_code: String(fiscal.postal_code ?? fiscal.cp),
2317
+ invoice_use: String(fiscal.use ?? fiscal.uso_cfdi ?? "") || null,
2318
+ document: fiscal.document ?? null,
2319
+ verification: { status: "reviewed", checked_at: now() }
2320
+ };
2321
+ c.fiscal = fid;
2322
+ }
2323
+ }
2324
+ return { body: publicCustomer(c), cache: "private" };
2325
+ });
2326
+ const stripOrder = ({ customer_id: _c, ...o }) => ({ ...o, invoice: orderInvoice(o) });
1174
2327
  route("GET", "/customer/orders", "orders:read", ({ headers, search }) => {
1175
2328
  const c = requireCustomer(headers);
1176
2329
  const orders = state.orders.filter((o) => o.customer_id === c.id).sort((a, b) => b.created_at.localeCompare(a.created_at)).map(stripOrder);
@@ -1186,9 +2339,16 @@ function createMockStorefront(options = {}) {
1186
2339
  if (!Array.isArray(body.lines) || body.lines.length === 0) throw new HttpError(400, "validation", "lines are required", "lines");
1187
2340
  return { status: 201, body: { id: nextId("ret"), order_id: order.id, status: "requested" }, cache: "private" };
1188
2341
  });
1189
- route("POST", "/customer/orders/:id/invoice", "customer:write", ({ headers, params }) => {
1190
- findOrder(headers, params[0]);
1191
- return { status: 202, body: { status: "requested", url: null }, cache: "private" };
2342
+ route("POST", "/customer/orders/:id/invoice", "customer:write", ({ headers, params, body }) => {
2343
+ const order = findOrder(headers, params[0]);
2344
+ const existing = state.invoices.get(order.id);
2345
+ if (existing && existing.stage !== "awaiting_payment") {
2346
+ return { status: existing.stage === "issued" ? 200 : 202, body: { status: existing.stage === "issued" ? "issued" : "requested", url: null, stage: existing.stage, invoice: orderInvoice(order) }, cache: "private" };
2347
+ }
2348
+ const request = parseInvoice({ ...body, requested: true }, "invoice");
2349
+ if (order.status === "pending_payment") throw new HttpError(409, "awaiting_payment", "The order is not paid yet");
2350
+ state.invoices.set(order.id, { stage: "queued", request });
2351
+ return { status: 202, body: { status: "requested", url: null, stage: "queued", invoice: orderInvoice(order) }, cache: "private" };
1192
2352
  });
1193
2353
  route("GET", "/customer/addresses", "customer:read", ({ headers }) => {
1194
2354
  const c = requireCustomer(headers);
@@ -1243,9 +2403,11 @@ function createMockStorefront(options = {}) {
1243
2403
  }));
1244
2404
  function scopesFor(token) {
1245
2405
  if (!token) return null;
1246
- if (token.startsWith("pk_")) return /* @__PURE__ */ new Set(["catalog:read", "content:read", "cart:write"]);
1247
- if (token.startsWith("sk_")) return /* @__PURE__ */ new Set(["catalog:read", "content:read", "cart:write", "checkout:write", "customer:read", "customer:write", "orders:read"]);
1248
- return null;
2406
+ let all;
2407
+ if (token.startsWith("pk_")) all = ["catalog:read", "content:read", "cart:write"];
2408
+ else if (token.startsWith("sk_")) all = ["catalog:read", "content:read", "cart:write", "checkout:write", "customer:read", "customer:write", "orders:read"];
2409
+ else return null;
2410
+ return new Set(all.filter((sc) => !missingScopes.includes(sc)));
1249
2411
  }
1250
2412
  function json(status, body, headers = {}) {
1251
2413
  return new Response(status === 204 || body === void 0 ? null : JSON.stringify(body), {
@@ -1256,12 +2418,18 @@ function createMockStorefront(options = {}) {
1256
2418
  function errorResponse(err) {
1257
2419
  return json(
1258
2420
  err.status,
1259
- { error: { code: err.code, message: err.message, ...err.field ? { field: err.field } : {}, ...err.details !== void 0 ? { details: err.details } : {} } },
2421
+ { error: { code: err.code, message: err.message, ...err.field ? { field: err.field } : {}, ...err.details !== void 0 ? { details: err.details } : {}, ...err.requiredScopes ? { required_scopes: err.requiredScopes } : {} } },
1260
2422
  { "Cache-Control": PRIVATE_CACHE }
1261
2423
  );
1262
2424
  }
1263
2425
  async function handle(request) {
1264
2426
  const url = new URL(request.url);
2427
+ if (/\/_token\/?$/.test(url.pathname)) {
2428
+ const tok = request.headers.get("authorization")?.match(/^Bearer\s+(.+)$/i)?.[1] ?? null;
2429
+ const granted = scopesFor(tok);
2430
+ if (!tok || !granted) return errorResponse(new HttpError(401, "unauthorized", "Missing or invalid storefront token"));
2431
+ return json(200, { kind: tok.startsWith("pk_") ? "publishable" : "secret", environment: "sandbox", scopes: [...granted], missing_scopes: missingScopes, connection_id: "conn_mock", expires_at: null }, { "Cache-Control": PRIVATE_CACHE });
2432
+ }
1265
2433
  const idx = url.pathname.indexOf("/storefront/");
1266
2434
  if (idx < 0) return errorResponse(new HttpError(404, "not_found", `No route for ${url.pathname}`));
1267
2435
  const path = url.pathname.slice(idx + "/storefront".length).replace(/\/+$/, "") || "/";
@@ -1274,7 +2442,9 @@ function createMockStorefront(options = {}) {
1274
2442
  const token = auth?.match(/^Bearer\s+(.+)$/i)?.[1] ?? null;
1275
2443
  const scopes = scopesFor(token);
1276
2444
  if (!scopes) return errorResponse(new HttpError(401, "unauthorized", "Missing or invalid storefront token"));
1277
- if (enforceScopes && !scopes.has(r.scope)) return errorResponse(new HttpError(403, "forbidden", `Token lacks scope ${r.scope}`));
2445
+ if ((enforceScopes || missingScopes.length > 0) && !scopes.has(r.scope)) {
2446
+ return errorResponse(new HttpError(403, "insufficient_scope", `Token lacks scope ${r.scope}`, void 0, void 0, [r.scope]));
2447
+ }
1278
2448
  let body = {};
1279
2449
  if (method !== "GET" && method !== "DELETE") {
1280
2450
  const text = await request.text();
@@ -1329,10 +2499,14 @@ function createMockStorefront(options = {}) {
1329
2499
  };
1330
2500
  }
1331
2501
 
2502
+ exports.MOCK_CSF_RULES = MOCK_CSF_RULES;
1332
2503
  exports.MOCK_CURRENCY = MOCK_CURRENCY;
1333
2504
  exports.MOCK_CUSTOMER_EMAIL = MOCK_CUSTOMER_EMAIL;
2505
+ exports.MOCK_FISCAL_ID_MX = MOCK_FISCAL_ID_MX;
2506
+ exports.MOCK_IDENTITY_DOCUMENT_MX_CSF = MOCK_IDENTITY_DOCUMENT_MX_CSF;
1334
2507
  exports.MOCK_IMAGE_URL = MOCK_IMAGE_URL;
1335
2508
  exports.MOCK_POSTAL_CENTROIDS = MOCK_POSTAL_CENTROIDS;
2509
+ exports.MOCK_REGION_MX = MOCK_REGION_MX;
1336
2510
  exports.createMockStorefront = createMockStorefront;
1337
2511
  //# sourceMappingURL=mock.cjs.map
1338
2512
  //# sourceMappingURL=mock.cjs.map