@fayz-ai/shop 0.10.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.
Files changed (63) hide show
  1. package/dist/{chunk-IL6GA4ER.js → chunk-2WACO2TG.js} +3 -3
  2. package/dist/{chunk-IL6GA4ER.js.map → chunk-2WACO2TG.js.map} +1 -1
  3. package/dist/{chunk-RGTIJQJL.js → chunk-6BO2TMZ5.js} +3 -3
  4. package/dist/{chunk-RGTIJQJL.js.map → chunk-6BO2TMZ5.js.map} +1 -1
  5. package/dist/{chunk-XOP6SHPB.js → chunk-NWW3WJ7Y.js} +4 -10
  6. package/dist/chunk-NWW3WJ7Y.js.map +1 -0
  7. package/dist/{chunk-XERLK5LD.js → chunk-STRNMFC4.js} +28 -5
  8. package/dist/chunk-STRNMFC4.js.map +1 -0
  9. package/dist/{chunk-U3O2I3RM.js → chunk-U6HV3LVP.js} +385 -23
  10. package/dist/chunk-U6HV3LVP.js.map +1 -0
  11. package/dist/data/customer-search.d.ts +3 -0
  12. package/dist/data/customer-search.d.ts.map +1 -0
  13. package/dist/data/functions.d.ts +9 -0
  14. package/dist/data/functions.d.ts.map +1 -0
  15. package/dist/data/media.d.ts +37 -0
  16. package/dist/data/media.d.ts.map +1 -0
  17. package/dist/data/mock-provider.d.ts +40 -8
  18. package/dist/data/mock-provider.d.ts.map +1 -1
  19. package/dist/data/provider.d.ts +200 -7
  20. package/dist/data/provider.d.ts.map +1 -1
  21. package/dist/data/supabase-provider.d.ts +113 -5
  22. package/dist/data/supabase-provider.d.ts.map +1 -1
  23. package/dist/data/tables.d.ts +3 -0
  24. package/dist/data/tables.d.ts.map +1 -1
  25. package/dist/entities/index.d.ts +0 -1
  26. package/dist/entities/index.d.ts.map +1 -1
  27. package/dist/entities.js +2 -2
  28. package/dist/index.d.ts +14 -5
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +891 -60
  31. package/dist/index.js.map +1 -1
  32. package/dist/inventory/index.d.ts +2 -2
  33. package/dist/inventory/index.d.ts.map +1 -1
  34. package/dist/inventory/stock-types.d.ts +60 -1
  35. package/dist/inventory/stock-types.d.ts.map +1 -1
  36. package/dist/inventory/supabase-stock-store.d.ts +1 -0
  37. package/dist/inventory/supabase-stock-store.d.ts.map +1 -1
  38. package/dist/inventory.js +1 -1
  39. package/dist/lib/commerce.d.ts.map +1 -1
  40. package/dist/lib/document.d.ts +13 -0
  41. package/dist/lib/document.d.ts.map +1 -0
  42. package/dist/lib/variant-matrix.d.ts +120 -0
  43. package/dist/lib/variant-matrix.d.ts.map +1 -0
  44. package/dist/mock.js +2 -2
  45. package/dist/providers/checkout.d.ts +129 -0
  46. package/dist/providers/checkout.d.ts.map +1 -0
  47. package/dist/providers/index.d.ts +5 -0
  48. package/dist/providers/index.d.ts.map +1 -0
  49. package/dist/providers/shipping.d.ts +43 -0
  50. package/dist/providers/shipping.d.ts.map +1 -0
  51. package/dist/providers.js +70 -0
  52. package/dist/providers.js.map +1 -0
  53. package/dist/runtime.js +3 -3
  54. package/dist/shipping/label-provider.d.ts +43 -0
  55. package/dist/shipping/label-provider.d.ts.map +1 -0
  56. package/dist/types.d.ts +457 -0
  57. package/dist/types.d.ts.map +1 -1
  58. package/package.json +8 -4
  59. package/dist/chunk-U3O2I3RM.js.map +0 -1
  60. package/dist/chunk-XERLK5LD.js.map +0 -1
  61. package/dist/chunk-XOP6SHPB.js.map +0 -1
  62. package/dist/entities/sidecar.d.ts +0 -9
  63. package/dist/entities/sidecar.d.ts.map +0 -1
package/dist/runtime.js CHANGED
@@ -1,7 +1,7 @@
1
- export { getShopProvider, resetShopProvider, setShopProvider } from './chunk-IL6GA4ER.js';
2
- import './chunk-U3O2I3RM.js';
1
+ export { getShopProvider, resetShopProvider, setShopProvider } from './chunk-2WACO2TG.js';
2
+ import './chunk-U6HV3LVP.js';
3
3
  import './chunk-IKNGCRUM.js';
4
- import './chunk-XOP6SHPB.js';
4
+ import './chunk-NWW3WJ7Y.js';
5
5
  import './chunk-3GERSY5F.js';
6
6
  //# sourceMappingURL=runtime.js.map
7
7
  //# sourceMappingURL=runtime.js.map
@@ -0,0 +1,43 @@
1
+ import type { ShippingLabel, ShippingLabelOption } from '../types';
2
+ export interface ShippingLabelProvider {
3
+ /** Connector slug — the id `plg_connections.connector_id` carries. */
4
+ id: string;
5
+ /** How the merchant knows them ("Melhor Envio"). Shown in the panel. */
6
+ label: string;
7
+ /** Services and prices for one order. Free, repeatable, spends nothing. */
8
+ quote(orderId: string): Promise<{
9
+ options: ShippingLabelOption[];
10
+ label: ShippingLabel | null;
11
+ }>;
12
+ /** SPENDS the merchant's balance. Idempotent per order by contract. */
13
+ buy(orderId: string, serviceId: number): Promise<ShippingLabel>;
14
+ /** The label PDF, as many times as the merchant needs it. */
15
+ print(orderId: string): Promise<string | null>;
16
+ /** What the carrier says now. */
17
+ track(orderId: string): Promise<ShippingLabel['tracking']>;
18
+ }
19
+ export declare function registerShippingLabelProvider(provider: ShippingLabelProvider): void;
20
+ export declare function listShippingLabelProviders(): ShippingLabelProvider[];
21
+ /** Test seam — the registry is module state, and a test that registers a fake
22
+ * must not leak it into the next one. */
23
+ export declare function resetShippingLabelProviders(): void;
24
+ export interface ResolveShippingLabelOptions {
25
+ /** Connector ids the store has ACTIVE, in the order the panel lists them. */
26
+ connected: readonly string[];
27
+ /**
28
+ * The merchant's explicit choice, when they made one.
29
+ *
30
+ * `''` (empty, not undefined) is a decision too — "I print labels myself" —
31
+ * and it must beat every connected carrier, exactly as the payment provider
32
+ * setting treats "confirmo à mão".
33
+ */
34
+ preferred?: string | null;
35
+ }
36
+ /**
37
+ * Which carrier issues this store's labels — or nobody.
38
+ *
39
+ * Null is a first-class answer and the common one: most stores dispatch by hand,
40
+ * and the panel must show them the manual path without a dead button beside it.
41
+ */
42
+ export declare function resolveShippingLabelProvider(options: ResolveShippingLabelOptions): ShippingLabelProvider | null;
43
+ //# sourceMappingURL=label-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"label-provider.d.ts","sourceRoot":"","sources":["../../src/shipping/label-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAiBlE,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,EAAE,EAAE,MAAM,CAAA;IACV,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAA;IACb,2EAA2E;IAC3E,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC;QAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAA;KAAE,CAAC,CAAA;IAChG,uEAAuE;IACvE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;IAC/D,6DAA6D;IAC7D,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAC9C,iCAAiC;IACjC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAA;CAC3D;AAID,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAEnF;AAED,wBAAgB,0BAA0B,IAAI,qBAAqB,EAAE,CAEpE;AAED;0CAC0C;AAC1C,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AAED,MAAM,WAAW,2BAA2B;IAC1C,6EAA6E;IAC7E,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,2BAA2B,GACnC,qBAAqB,GAAG,IAAI,CAkB9B"}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,13 @@
1
1
  export type ProductStatus = 'draft' | 'active' | 'archived';
2
+ /**
3
+ * A handling requirement declared on a product (0048).
4
+ *
5
+ * This is a DECLARATION, not a guarantee: it is what travels to whoever carries
6
+ * the parcel — a carrier's refrigerated service, a motoboy, or the merchant's
7
+ * own car. What RESTRICTS who may carry it is the product's shipping profile
8
+ * (0049), not this list — this one only travels.
9
+ */
10
+ export type HandlingRequirement = 'refrigerated' | 'frozen' | 'fragile';
2
11
  export interface Product {
3
12
  id: string;
4
13
  tenantId: string;
@@ -16,9 +25,41 @@ export interface Product {
16
25
  images: ProductImage[];
17
26
  categoryId: string | null;
18
27
  categoryName: string | null;
28
+ /** False keeps the product out of the freight calculation entirely (0001,
29
+ * finally read in FAY-1407). */
19
30
  isPhysical: boolean;
20
31
  weight: number | null;
32
+ /** The unit `weight` is in. Honoured by the packing code — it is not
33
+ * decoration, and a catalogue in grams quoted as kg is a thousandfold error. */
21
34
  weightUnit: string;
35
+ /** Centimetres (0044b/0046). Null is "not measured", which degrades the cart
36
+ * to the store's default package rather than inventing a size. */
37
+ heightCm?: number | null;
38
+ widthCm?: number | null;
39
+ lengthCm?: number | null;
40
+ /**
41
+ * Em que embalagem da loja este produto vai (0047). NULL = a padrão da
42
+ * loja, que é o estado de todo produto no dia da aplicação. Aponta para
43
+ * plg_shop_packages; a medida está lá, não aqui.
44
+ */
45
+ packageId?: string | null;
46
+ /**
47
+ * What the box needs from whoever carries it (0048). Empty is "nothing
48
+ * declared", which is how every catalogue starts.
49
+ *
50
+ * On the PRODUCT and not the variant on purpose: needing cold is a property of
51
+ * what is inside, and a chocolate melts in all three sizes. Weight and
52
+ * dimensions live on the variant because those genuinely differ.
53
+ *
54
+ * Optional and not `HandlingRequirement[]`: eleven apps build Product literals
55
+ * from source, and a required field on a shared interface makes a declaration
56
+ * nobody asked for into a build break in every one of them. The live provider
57
+ * always returns an array, so a reader may treat `undefined` as empty.
58
+ */
59
+ handling?: HandlingRequirement[];
60
+ /** Which delivery profile ships this product (0049). Undefined = the general
61
+ * one, which is every product nobody has moved. */
62
+ shippingProfileId?: string | null;
22
63
  createdAt: string;
23
64
  updatedAt: string;
24
65
  /**
@@ -62,12 +103,56 @@ export interface ProductVariant {
62
103
  status: 'active' | 'archived';
63
104
  /** Variant-specific photo; null falls back to the product's primary image. */
64
105
  imageId: string | null;
106
+ /**
107
+ * 0037's placeholder sellable unit for a product that declares no axes. MUST
108
+ * BE INVISIBLE to the merchant — no row in the variant grid, no options label.
109
+ */
110
+ isDefaultVariant?: boolean;
111
+ /**
112
+ * Shipping measurements (0046). Null inherits the product's, exactly like
113
+ * `price` — a camiseta P and a GG do not occupy the same box, and a
114
+ * catalogue where every size weighs the same is measured once, on the
115
+ * product, and never again.
116
+ */
117
+ weight?: number | null;
118
+ weightUnit?: string | null;
119
+ heightCm?: number | null;
120
+ widthCm?: number | null;
121
+ lengthCm?: number | null;
65
122
  }
66
123
  /** What ShopProvider.getProductVariants answers for one product. */
67
124
  export interface ProductVariantSet {
68
125
  options: ProductOption[];
69
126
  variants: ProductVariant[];
70
127
  }
128
+ /** One axis as the admin submits it. Order of `values` is the picker's order. */
129
+ export interface ProductOptionInput {
130
+ name: string;
131
+ values: string[];
132
+ }
133
+ /**
134
+ * The variant fields the admin owns. `inventoryCount` is deliberately ABSENT:
135
+ * since 0034 stock is a ledger and since 0036 `inventory_count` is its mirror,
136
+ * so a write here would be a second truth. Stock moves through
137
+ * ShopProvider.setVariantStock, which appends a movement.
138
+ */
139
+ export interface UpdateProductVariantInput {
140
+ sku?: string | null;
141
+ price?: number | null;
142
+ compareAtPrice?: number | null;
143
+ position?: number;
144
+ status?: 'active' | 'archived';
145
+ imageId?: string | null;
146
+ weight?: number | null;
147
+ weightUnit?: string | null;
148
+ heightCm?: number | null;
149
+ widthCm?: number | null;
150
+ lengthCm?: number | null;
151
+ }
152
+ export interface CreateProductVariantInput extends UpdateProductVariantInput {
153
+ /** The combination this variant IS. Empty is refused — that shape is 0037's. */
154
+ options: Record<string, string>;
155
+ }
71
156
  export interface ProductImage {
72
157
  id: string;
73
158
  productId: string;
@@ -93,6 +178,12 @@ export interface CreateProductInput {
93
178
  isPhysical?: boolean;
94
179
  weight?: number;
95
180
  weightUnit?: string;
181
+ heightCm?: number | null;
182
+ widthCm?: number | null;
183
+ lengthCm?: number | null;
184
+ packageId?: string | null;
185
+ handling?: HandlingRequirement[];
186
+ shippingProfileId?: string | null;
96
187
  }
97
188
  export interface UpdateProductInput {
98
189
  name?: string;
@@ -110,6 +201,12 @@ export interface UpdateProductInput {
110
201
  isPhysical?: boolean;
111
202
  weight?: number | null;
112
203
  weightUnit?: string;
204
+ heightCm?: number | null;
205
+ widthCm?: number | null;
206
+ lengthCm?: number | null;
207
+ packageId?: string | null;
208
+ handling?: HandlingRequirement[];
209
+ shippingProfileId?: string | null;
113
210
  }
114
211
  export interface ListProductsOptions {
115
212
  status?: ProductStatus;
@@ -213,9 +310,25 @@ export interface Order {
213
310
  paymentMethodKind: PaymentMethodKind | null;
214
311
  paidAt: string | null;
215
312
  items: OrderItem[];
313
+ /**
314
+ * What the buyer needs to follow the box (0052). Only `getOrder` fills it —
315
+ * on a list, `[]` means "not asked for" as much as "nothing shipped".
316
+ */
317
+ shipments?: OrderShipment[];
216
318
  createdAt: string;
217
319
  updatedAt: string;
218
320
  }
321
+ /** One non-cancelled shipment, as the buyer's own window returns it. */
322
+ export interface OrderShipment {
323
+ id: string;
324
+ status: string;
325
+ carrier: string | null;
326
+ trackingCode: string | null;
327
+ trackingUrl: string | null;
328
+ shippedAt: string | null;
329
+ estimatedDeliveryAt: string | null;
330
+ deliveredAt: string | null;
331
+ }
219
332
  export interface OrderItem {
220
333
  id: string;
221
334
  orderId: string;
@@ -298,8 +411,125 @@ export interface ShippingAddressInput {
298
411
  recipient?: string;
299
412
  phone?: string;
300
413
  label?: string;
414
+ /**
415
+ * CPF/CNPJ of whoever is buying — digits only. It is NOT part of the address:
416
+ * it travels here because shop_place_order cannot grow a parameter without a
417
+ * DROP, and 0050's BEFORE INSERT trigger lifts it into
418
+ * plg_shop_orders.customer_document and removes it from the stored jsonb.
419
+ * Read the column, never this field.
420
+ */
421
+ document?: string;
301
422
  }
302
423
  export type PaymentMethodKind = 'pix' | 'credit_card' | 'debit_card' | 'boleto' | 'cash' | 'other';
424
+ export interface CreateFulfillmentInput {
425
+ orderId: string;
426
+ /** Free text: the merchant's own courier is as valid as a named carrier. */
427
+ carrier?: string;
428
+ /** With one, the shipment is already in transit; without, it is picking. */
429
+ trackingCode?: string;
430
+ locationId?: string;
431
+ notes?: string;
432
+ /** Partial shipment. Omitted means everything still outstanding. */
433
+ items?: Array<{
434
+ orderItemId: string;
435
+ quantity: number;
436
+ }>;
437
+ }
438
+ export interface ShipFulfillmentInput {
439
+ trackingCode?: string;
440
+ trackingUrl?: string;
441
+ carrier?: string;
442
+ }
443
+ /**
444
+ * O carrinho congelado enquanto o comprador paga.
445
+ *
446
+ * Existe porque o pedido passou a nascer DEPOIS do pagamento. Entre "escolhi
447
+ * pagar" e "paguei" não há pedido nenhum — há esta sessão, com os preços que o
448
+ * SERVIDOR recalculou, e é dela que o pedido é criado quando o dinheiro entra.
449
+ */
450
+ export interface CheckoutSessionInput {
451
+ items: Array<{
452
+ productId: string;
453
+ variantId?: string | null;
454
+ quantity: number;
455
+ optionsLabel?: string | null;
456
+ }>;
457
+ customer: {
458
+ name?: string | null;
459
+ email: string;
460
+ };
461
+ shippingAddress?: ShippingAddressInput;
462
+ discountCode?: string | null;
463
+ paymentMethod?: PaymentMethodKind;
464
+ }
465
+ export interface CheckoutSession {
466
+ sessionId: string;
467
+ /** Recalculado no servidor. O navegador exibe; nunca decide. */
468
+ total: number;
469
+ charge: PaymentCharge | null;
470
+ state: 'open' | 'paid' | 'failed' | 'expired';
471
+ }
472
+ /** `orderId` só aparece quando o pagamento entrou — é ele que prova a compra. */
473
+ export interface CheckoutSettlement {
474
+ /** `pending` is what the acquirer answers while the buyer still has the QR
475
+ * code open — the ordinary case, and the one a caller must never read as a
476
+ * refusal. Only `failed`, `expired` and `cancelled` end the wait. */
477
+ state: 'open' | 'pending' | 'paid' | 'failed' | 'expired' | 'cancelled' | 'unknown';
478
+ orderId?: string | null;
479
+ reason?: string | null;
480
+ }
481
+ /** A carrier label, from quote to tracking. `labelUrl` is a PDF the merchant prints. */
482
+ export interface ShippingLabelOption {
483
+ serviceId: number;
484
+ name: string;
485
+ carrier: string;
486
+ price: number;
487
+ etaMinDays?: number | null;
488
+ etaMaxDays?: number | null;
489
+ }
490
+ /** A carrier drop-off point, as a settings screen lists it. */
491
+ export interface ShippingAgency {
492
+ id: string;
493
+ name: string;
494
+ city: string;
495
+ state: string;
496
+ address: string;
497
+ /** Carrier service ids this one accepts — a choice that hides them is a
498
+ * choice the merchant discovers is wrong at the first dispatch. */
499
+ services: string[];
500
+ }
501
+ export interface ShippingLabel {
502
+ labelId: string;
503
+ labelUrl?: string | null;
504
+ status?: string | null;
505
+ tracking?: {
506
+ code: string | null;
507
+ status: string | null;
508
+ url: string | null;
509
+ } | null;
510
+ }
511
+ /** What a connected acquirer can be asked to open. Card waits for hosted fields. */
512
+ export type PaymentChargeMethod = 'pix';
513
+ /**
514
+ * A charge the buyer can act on. `qrcodeBase64` is a bare base64 PNG — no
515
+ * `data:` prefix — because that is how the provider returns it.
516
+ */
517
+ export interface PaymentCharge {
518
+ emv: string;
519
+ qrcodeBase64: string | null;
520
+ expiresAt: string;
521
+ }
522
+ /**
523
+ * `unopened` is not an error: the page may ask for the state before the charge
524
+ * call has returned. `failed` is the provider's final no.
525
+ */
526
+ export interface PaymentChargeResult {
527
+ state: 'pending' | 'paid' | 'refunded' | 'failed' | 'unopened';
528
+ orderId: string;
529
+ reference?: string | null;
530
+ charge?: PaymentCharge | null;
531
+ providerStatus?: string | null;
532
+ }
303
533
  /**
304
534
  * A range of postal codes the store delivers to, with its own price and ETA.
305
535
  *
@@ -321,9 +551,208 @@ export interface ShippingZone {
321
551
  etaMaxDays?: number | null;
322
552
  active: boolean;
323
553
  sortOrder: number;
554
+ /**
555
+ * A zone the store REFUSES (0048) — "não entrego aqui", by any means.
556
+ *
557
+ * It beats every other zone covering the same postcode and it beats a carrier
558
+ * quote, because the refusal is about the store and not about who carries the
559
+ * parcel. Enforced server-side on the order, so a direct POST cannot get
560
+ * around it. `rate` and the ETA are ignored on an excluded zone.
561
+ *
562
+ * Not-cadastrar is a different thing: a broad zone covering a whole region
563
+ * already accepts the street the merchant wants to avoid, and there was no way
564
+ * to carve an exception out of it.
565
+ */
566
+ excluded: boolean;
567
+ /** Which profile owns this range (0049). Undefined = the general profile. */
568
+ profileId?: string | null;
324
569
  }
325
570
  export type CreateShippingZoneInput = Omit<ShippingZone, 'id' | 'tenantId'>;
326
571
  export type UpdateShippingZoneInput = Partial<CreateShippingZoneInput>;
572
+ export type ShippingPackageKind = 'box' | 'envelope' | 'soft';
573
+ /**
574
+ * A box the store actually owns (plg_shop_packages, 0046).
575
+ *
576
+ * The freight engine picks the SMALLEST of these the cart fits in and adds
577
+ * `emptyWeightGrams` to what the carrier weighs. Before this cadastro existed
578
+ * the box was a constant in the edge function — 4×16×20cm for every store —
579
+ * and the difference between the quote and the label came out of the
580
+ * merchant's margin.
581
+ *
582
+ * `isDefault` is the box a cart falls back to when some item has no
583
+ * measurements. That fallback used to be the constant; it is data now.
584
+ */
585
+ export interface ShippingPackage {
586
+ id: string;
587
+ tenantId: string;
588
+ name: string;
589
+ kind: ShippingPackageKind;
590
+ heightCm: number;
591
+ widthCm: number;
592
+ lengthCm: number;
593
+ /** Grams, because that is how a merchant reads a carton's own weight. */
594
+ emptyWeightGrams: number;
595
+ isDefault: boolean;
596
+ active: boolean;
597
+ }
598
+ export type CreateShippingPackageInput = Omit<ShippingPackage, 'id' | 'tenantId'>;
599
+ export type UpdateShippingPackageInput = Partial<CreateShippingPackageInput>;
600
+ /**
601
+ * A named group of products with its own delivery zones (0049).
602
+ *
603
+ * The general mechanism behind "estes produtos vão de outro jeito", copied from
604
+ * Shopify's shipping profiles: refrigerated, fragile, oversized and made-to-order
605
+ * are all the same shape — a set of products the store ships differently — and
606
+ * modelling them one column at a time is how a settings screen ends up with four
607
+ * radios that each answer one merchant's question.
608
+ *
609
+ * INHERITANCE is by NULL on both ends: a product with no profile uses the
610
+ * general one, and a zone with no profile belongs to the general one. That is
611
+ * what lets this ship without migrating a single existing product or zone.
612
+ */
613
+ export interface ShippingProfile {
614
+ id: string;
615
+ tenantId: string;
616
+ name: string;
617
+ /**
618
+ * Whether a freight gateway may quote for the products in this profile.
619
+ *
620
+ * Undefined inherits `StoreSettings.carrierQuotes`. `false` is what replaces
621
+ * the old cold-chain policy: these products leave only through the zones the
622
+ * store declared itself. In a cart that mixes profiles the most restrictive one
623
+ * wins — otherwise "these do not go by truck" would be undone by adding a mug.
624
+ */
625
+ carrierQuotes?: boolean;
626
+ /** The general profile, so the screen has somewhere to hang unprofiled zones. */
627
+ isDefault: boolean;
628
+ }
629
+ export type CreateShippingProfileInput = Omit<ShippingProfile, 'id' | 'tenantId'>;
630
+ export type UpdateShippingProfileInput = Partial<CreateShippingProfileInput>;
631
+ /**
632
+ * The store-wide delivery fallback (public.shipping_settings, 0015).
633
+ *
634
+ * A zone always wins over this. It is what a store charges for an address no
635
+ * zone covers — and for a store that has declared no zone at all, which is how
636
+ * most start. A tenant with no row at all charges nothing, which is the safe
637
+ * default: inventing a freight nobody configured is worse than free delivery.
638
+ */
639
+ export interface ShippingSettings {
640
+ flatRate: number;
641
+ /** Subtotal (after discount) at or above which delivery is free. */
642
+ freeAbove?: number | null;
643
+ currency: string;
644
+ }
645
+ export type UpdateShippingSettingsInput = Partial<ShippingSettings>;
646
+ /**
647
+ * Per-field checkout policy. Keyed by the form field the storefront renders.
648
+ *
649
+ * A record rather than columns because the SET OF FIELDS is the variable part:
650
+ * a store selling downloads has no use for a district, and the next storefront
651
+ * will want one nobody has thought of. `visible: false` implies not required —
652
+ * a field nobody can see cannot be filled in.
653
+ */
654
+ export type CheckoutFieldKey = 'name' | 'email' | 'phone' | 'document' | 'street' | 'number' | 'complement' | 'district' | 'city' | 'state' | 'postalCode';
655
+ export interface CheckoutFieldPolicy {
656
+ visible?: boolean;
657
+ required?: boolean;
658
+ }
659
+ /**
660
+ * The store's commercial policy — what plg_shop_settings holds (0044b).
661
+ *
662
+ * Every field is OPTIONAL and `undefined` means NOT DECIDED, which is a
663
+ * different thing from a false or an empty list: not-decided keeps whatever the
664
+ * app declared in its StorefrontConfig, while `paymentMethods: []` would be a
665
+ * merchant who accepts nothing. That distinction is what lets this ship to eight
666
+ * live storefronts without changing any of them on deploy day.
667
+ *
668
+ * Two of these are enforced SERVER-SIDE by a trigger (`paymentMethods`,
669
+ * `guestCheckout`); the rest are read by the storefront. The docs on each say
670
+ * which, because "the checkbox is off" and "the server refuses" are promises of
671
+ * very different strength.
672
+ */
673
+ export interface StoreSettings {
674
+ /** Vitrine display. Undefined = the app's own currency/locale. */
675
+ currency?: string;
676
+ locale?: string;
677
+ showOutOfStock?: boolean;
678
+ /** Admin-side: makes SKU mandatory on the product form. Not a storefront rule. */
679
+ requireSku?: boolean;
680
+ /** ERP ownership of stock (0029). 'external' means a connector owns the numbers. */
681
+ stockOwnership?: 'internal' | 'external';
682
+ /** What the checkout may offer. ENFORCED: an order naming a method outside
683
+ * this list is refused by the server, not merely hidden by the form. */
684
+ paymentMethods?: PaymentMethodKind[];
685
+ /** Which connected gateway charges, when more than one is connected. The id of
686
+ * a ConnectorDefinition ('appmax'), never a credential. */
687
+ paymentProvider?: string;
688
+ /** ENFORCED: a storefront order with no account-linked customer is refused
689
+ * when this is explicitly false. */
690
+ guestCheckout?: boolean;
691
+ /** Storefront-side only — confirming an e-mail is a fact about the auth
692
+ * provider, not about the order, so the server does not police it. */
693
+ requireConfirmedEmail?: boolean;
694
+ marketingOptIn?: boolean;
695
+ discountsEnabled?: boolean;
696
+ checkoutFields?: Partial<Record<CheckoutFieldKey, CheckoutFieldPolicy>>;
697
+ /** 'never' — every shipment is created by hand. 'on_payment' — one is created
698
+ * when the payment is confirmed. 'always' — when the order is placed. */
699
+ autoFulfill?: 'never' | 'on_payment' | 'always';
700
+ notifyNewOrder?: boolean;
701
+ notifyLowStock?: boolean;
702
+ /**
703
+ * A declaração que viaja com o pedido — para você, para o motoboy, e na
704
+ * observação da etiqueta. Nunca mostrada ao comprador.
705
+ *
706
+ * Onde ficou a política de frio: num PERFIL DE ENTREGA (0049). "Refrigerado só
707
+ * sai no meu carro" é uma frase sobre logística, e uma coluna de três valores
708
+ * só respondia por temperatura — a loja seguinte pede o mesmo para frágil, para
709
+ * volumoso, para sob encomenda. Um perfil atende os quatro sem código novo.
710
+ */
711
+ /**
712
+ * Whether a freight GATEWAY may quote for this store (0048).
713
+ *
714
+ * Melhor Envio is not a carrier — it is a gateway that brings Correios,
715
+ * Jadlog, Loggi and others behind one connection. So the store's question is
716
+ * not "which carrier" but WHO CALCULATES: the merchant, from her zones, or a
717
+ * gateway, from the shopper's postcode.
718
+ *
719
+ * `false` = the merchant calculates, and no gateway is asked even if one is
720
+ * connected. Undefined = not decided, which behaves as today (ask if
721
+ * connected). It has to be storable rather than inferred from "no connection":
722
+ * the day someone connects a gateway in this app, a store that dispatches by
723
+ * hand would start receiving carrier prices it never chose — and 0044b makes a
724
+ * gateway quote WIN over the zones when it answers.
725
+ */
726
+ carrierQuotes?: boolean;
727
+ /**
728
+ * The note that travels with the parcel ("caixa térmica com gelo, entregar em
729
+ * até 24h"). Admin-side and carrier-side only — never shown to the shopper,
730
+ * which is why `shop_store_settings()` does not return it.
731
+ */
732
+ handlingNote?: string;
733
+ }
734
+ export type UpdateStoreSettingsInput = Partial<StoreSettings>;
735
+ /**
736
+ * The answer to "does this store deliver to this postcode?" (0048,
737
+ * `shop_delivery_check`), asked with the address and BEFORE the card.
738
+ *
739
+ * Two separate facts, because they are not the same question:
740
+ * · `refused` — an exclusion zone covers it. A no from the store, true even
741
+ * where a carrier would happily deliver.
742
+ * · `ownZone` — a zone of the store's own covers it. What tells "our car"
743
+ * from "a gateway", and what a shipping profile with the gateway off (0049)
744
+ * narrows a product to.
745
+ *
746
+ * Deliberately NOT "is there freight": that is `quoteShipping`, which also
747
+ * consults a carrier. Answering both here would tell every carrier-only store
748
+ * that it does not deliver anywhere.
749
+ */
750
+ export interface DeliveryCheck {
751
+ refused: boolean;
752
+ /** The exclusion zone's name, so the shopper reads a reason and not an error. */
753
+ refusedZone?: string | null;
754
+ ownZone: boolean;
755
+ }
327
756
  /**
328
757
  * One delivery option for a postal code, as quoted by shop_quote_shipping.
329
758
  *
@@ -413,6 +842,10 @@ export interface ShopCustomer {
413
842
  lastName: string;
414
843
  email: string | null;
415
844
  phone: string | null;
845
+ /** CPF/CNPJ, digits only. The person's, not the order's — an invoice issued
846
+ * months later needs the document that was valid on the day it is issued,
847
+ * and the order keeps its own frozen copy for that. */
848
+ document?: string | null;
416
849
  notes: string | null;
417
850
  ordersCount: number;
418
851
  totalSpent: number;
@@ -424,6 +857,7 @@ export interface CreateCustomerInput {
424
857
  lastName?: string;
425
858
  email?: string;
426
859
  phone?: string;
860
+ document?: string;
427
861
  notes?: string;
428
862
  }
429
863
  export interface UpdateCustomerInput {
@@ -431,6 +865,7 @@ export interface UpdateCustomerInput {
431
865
  lastName?: string;
432
866
  email?: string | null;
433
867
  phone?: string | null;
868
+ document?: string | null;
434
869
  notes?: string | null;
435
870
  }
436
871
  export interface ListCustomersOptions {
@@ -749,6 +1184,26 @@ export interface UpdateGiftCardInput {
749
1184
  note?: string | null;
750
1185
  }
751
1186
  export type MediaFileKind = 'image' | 'video' | 'document';
1187
+ /**
1188
+ * The record a file hangs off.
1189
+ *
1190
+ * Without this a media library is a wall of anonymous thumbnails: a merchant can
1191
+ * see that a photo is bad and has nowhere to go to replace it. Only products own
1192
+ * files today; the shape is a discriminated union so a collection or a category
1193
+ * can join without changing the screens that read it.
1194
+ */
1195
+ export interface MediaFileReference {
1196
+ type: 'product';
1197
+ /** The record's id — what the admin route is built from. */
1198
+ id: string;
1199
+ /** The record's name, for the card's link. */
1200
+ label: string;
1201
+ /** The attachment row (plg_shop_product_images.id). Deleting a file from the
1202
+ * library targets this: detaching it IS the deletion. */
1203
+ attachmentId: string;
1204
+ /** True for the photo the storefront leads with. */
1205
+ isCover?: boolean;
1206
+ }
752
1207
  export interface MediaFile {
753
1208
  /** Storage path relative to the bucket — the stable identity. */
754
1209
  id: string;
@@ -760,5 +1215,7 @@ export interface MediaFile {
760
1215
  /** Upper-cased extension, for the card's type caption (WEBP, MP4…). */
761
1216
  extension: string;
762
1217
  createdAt: string;
1218
+ /** Absent for files uploaded straight to the library, which belong to nothing. */
1219
+ reference?: MediaFileReference;
763
1220
  }
764
1221
  //# sourceMappingURL=types.d.ts.map