sinfactura-types 1.10.554 → 1.10.555

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/brands.d.ts CHANGED
@@ -1,9 +1,26 @@
1
1
  declare global {
2
- /** Write shape for brand create/update — carries the transient photo controls. */
2
+ /**
3
+ * Write shape for brand create/update — carries the transient photo controls.
4
+ *
5
+ * `name` is required on a create and optional on an update (send the diff
6
+ * plus `brandId`). An update of an unknown `brandId` is `404
7
+ * BRAND_NOT_FOUND`, never an upsert. An empty `description` or `website`
8
+ * clears it; omitting a field leaves it unchanged.
9
+ *
10
+ * A create may carry an `Idempotency-Key` header: the same key and body
11
+ * answer the same `brandId`, a changed body under that key is `422
12
+ * IDEMPOTENCY_KEY_REUSE`.
13
+ */
3
14
  type BrandUpsertInput = Partial<Brand> & PhotoUploadControls;
4
15
  interface Brand {
5
16
  storeId: string;
6
17
  brandId: string;
18
+ /**
19
+ * Display name, trimmed, 1..200 characters. Unique per store, disabled
20
+ * brands included, compared after Unicode NFKC, trimming, collapsing
21
+ * whitespace and lower-casing — accents are kept, so `Niño` and `Nino`
22
+ * are different brands.
23
+ */
7
24
  name: string;
8
25
  photoURL?: string;
9
26
  /** @deprecated Request-only upload control, never persisted or returned — use `BrandUpsertInput.photoData`. */
@@ -13,6 +30,37 @@ declare global {
13
30
  isFather: boolean;
14
31
  father?: string;
15
32
  disabled: boolean;
33
+ /**
34
+ * URL slug, unique per store: `^[a-z0-9]+(?:-[a-z0-9]+)*$`, at most 80
35
+ * characters. Minted from `name` on a create, and on an update of a row
36
+ * that has none only when that update carries `name`; suffixed `-2`,
37
+ * `-3`… on a clash; a rename never changes it. An explicit value is never
38
+ * suffixed.
39
+ */
40
+ slug?: string;
41
+ /** At most 2000 characters. */
42
+ description?: string;
43
+ /** An absolute `https:` URL without credentials, at most 2048 characters. Never fetched by the api. */
44
+ website?: string;
16
45
  }
46
+ /** Every code a `POST /brands` identity or lookup check can refuse with. */
47
+ type BrandErrorCode = 'BRAND_NOT_FOUND' | 'BRAND_NAME_TAKEN' | 'BRAND_SLUG_TAKEN' | 'INVALID_SLUG' | 'BRAND_IDENTITY_CHECK_INCOMPLETE' | 'BRAND_WRITE_CONFLICT';
48
+ /**
49
+ * The body of a refused `POST /brands`. Statuses: `BRAND_NOT_FOUND` · 404,
50
+ * `INVALID_SLUG` · 400, every other code · 409.
51
+ *
52
+ * - `BRAND_NAME_TAKEN` — another brand of the store, enabled or disabled,
53
+ * has the same name after normalization.
54
+ * - `BRAND_SLUG_TAKEN` — another brand holds the slug, or won the race for
55
+ * a minted one.
56
+ * - `BRAND_IDENTITY_CHECK_INCOMPLETE` — the store has more brands than one
57
+ * uniqueness check reads; nothing was written.
58
+ * - `BRAND_WRITE_CONFLICT` — the brand changed while it was being saved;
59
+ * nothing was written and the request is safe to retry.
60
+ */
61
+ type BrandRefusal = {
62
+ message: string;
63
+ error: BrandErrorCode;
64
+ };
17
65
  }
18
66
  export {};
@@ -1,6 +1,51 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PRODUCT_POST_ERROR_CODES = void 0;
3
+ exports.PRODUCT_POST_ERROR_CODES = exports.PRODUCT_EXPORT_ERROR_CODES = exports.PRODUCT_CATALOG_EXPORT_COLUMNS = void 0;
4
+ /**
5
+ * The CSV header of `GET /products?mode=export`, in file order.
6
+ *
7
+ * The first block uses the bulk-import row keys, so a column means the same thing
8
+ * in both directions: `prices` and `sellableOn` are JSON arrays, `barcode` is the
9
+ * primary barcode. The last block is read-only — the import ignores it:
10
+ * `productId`, `currentStock` (stock now, not an opening balance), `minStock` and
11
+ * `updatedAt` (ms epoch).
12
+ */
13
+ exports.PRODUCT_CATALOG_EXPORT_COLUMNS = [
14
+ 'sku',
15
+ 'name',
16
+ 'description',
17
+ 'categoryId',
18
+ 'brandId',
19
+ 'currency',
20
+ 'cost',
21
+ 'ivaType',
22
+ 'prices',
23
+ 'barcode',
24
+ 'limit',
25
+ 'zone',
26
+ 'isService',
27
+ 'isNew',
28
+ 'disabled',
29
+ 'sellableOn',
30
+ 'weightGrams',
31
+ 'lengthMm',
32
+ 'widthMm',
33
+ 'heightMm',
34
+ 'productId',
35
+ 'currentStock',
36
+ 'minStock',
37
+ 'updatedAt',
38
+ ];
39
+ /**
40
+ * Every refusal `GET /products?mode=export` answers, beyond the cross-cutting
41
+ * `GATING_ERROR_CODES` (the `importExport` entitlement among them):
42
+ *
43
+ * - `ADMIN_REQUIRED` · 403 — the caller is neither ADMIN nor MANAGER.
44
+ * - `ROLE_FORBIDDEN` · 403 — a print agent or an accountant.
45
+ * - `VALIDATION_FAILED` · 400 — a filter outside the grammar.
46
+ * - `INVALID_CURSOR` · 400 — a `startKey` this store did not mint.
47
+ */
48
+ exports.PRODUCT_EXPORT_ERROR_CODES = ['ADMIN_REQUIRED', 'ROLE_FORBIDDEN', 'VALIDATION_FAILED', 'INVALID_CURSOR'];
4
49
  /**
5
50
  * Every refusal `POST /products` answers on a single-product create or edit —
6
51
  * the body with no `mode`, `stacks/lambdas/products/_post.ts` behind
package/dist/product.d.ts CHANGED
@@ -13,6 +13,54 @@ declare global {
13
13
  /** Requested IDs absent, hidden, disabled or unpriceable; never unresolved reads. */
14
14
  unavailableProductIds: string[];
15
15
  }
16
+ /** Anonymous Web GET /products related read; the tenant comes from the public store context. */
17
+ interface PublicRelatedProductsInput {
18
+ mode: 'related';
19
+ /** Canonical id of the product page the suggestions are for. */
20
+ productId: string;
21
+ }
22
+ /**
23
+ * The computed associations for one product, resolved at read time against the
24
+ * public projection: at most 10 products, in the model's ranked order, each
25
+ * visible, enabled, priceable and sellable on the storefront.
26
+ *
27
+ * ⚠️ `data: []` covers both "no model computed yet" and "every suggestion is
28
+ * currently not offered"; the distinction and every figure stay on the
29
+ * operator `GET /products?mode=associations`. An anchor that is not offered
30
+ * answers 404 `PRODUCT_NOT_FOUND`; an incomplete read 503
31
+ * `PRODUCT_LOOKUP_INCOMPLETE`, never a partial list.
32
+ */
33
+ interface PublicRelatedProductsResponse {
34
+ message: string;
35
+ /** Current public price/projection and online stock, best suggestion first. */
36
+ data: Partial<Product>[];
37
+ }
38
+ /**
39
+ * Anonymous Web GET /products composed discovery; the tenant comes from the
40
+ * public store context. Every filter is optional and they AND-compose.
41
+ */
42
+ interface PublicProductDiscoverInput {
43
+ mode: 'discover';
44
+ /** Free text, ≤100 chars; every token must appear in the product's search term. */
45
+ search?: string;
46
+ /** Exact primary category; descendants are not included. */
47
+ categoryId?: string;
48
+ brandId?: string;
49
+ /** Only products with a promo window open now. */
50
+ inOffer?: 'true';
51
+ /** Only products the online stock authority can sell now; services always pass. */
52
+ inStock?: 'true';
53
+ /** The previous response's `LastEvaluatedKey`, under the SAME filters; else 400 INVALID_CURSOR. */
54
+ startKey?: string;
55
+ }
56
+ /** One page of a discovery walk; `data` can be empty while `LastEvaluatedKey` is set. */
57
+ interface PublicProductDiscoverResponse {
58
+ message: string;
59
+ /** Public price/projection and online stock, in index order. */
60
+ data: Partial<Product>[];
61
+ /** Present while rows remain; absent means the walk is complete. */
62
+ LastEvaluatedKey?: string;
63
+ }
16
64
  /** Write shape for product create/update — carries the transient picture-removal control. */
17
65
  type ProductUpsertInput = Partial<Product> & {
18
66
  /** Request-only: pictures to delete; the BE removes them from storage and from `pictures[]`. */
@@ -745,7 +793,78 @@ declare global {
745
793
  /** Ranked and truncated server-side. May be shorter than the ids requested. */
746
794
  data: ProductAssociations[];
747
795
  }
796
+ /**
797
+ * `GET /products?mode=export` — the filters it accepts, with the operator
798
+ * listing's (`GET /products`) meaning: an absent `disabled` means enabled-only,
799
+ * `all` adds the disabled rows, `true` is only those. Any other listing parameter
800
+ * is refused 400 `VALIDATION_FAILED` rather than ignored. ADMIN or MANAGER,
801
+ * behind the `importExport` entitlement.
802
+ */
803
+ interface ProductCatalogExportQuery {
804
+ mode: 'export';
805
+ categoryId?: string;
806
+ brandId?: string;
807
+ search?: string;
808
+ disabled?: 'true' | 'false' | 'all';
809
+ stock?: 'out' | 'low';
810
+ inOffer?: 'true' | 'false';
811
+ /** `nextStartKey` from an incomplete export, to export the rest. */
812
+ startKey?: string;
813
+ }
814
+ /**
815
+ * One export: a `;`-separated UTF-8 CSV (with BOM), stored privately and handed
816
+ * out as a short-lived download link. The header row is
817
+ * {@link PRODUCT_CATALOG_EXPORT_COLUMNS}; an empty cell means the field is absent,
818
+ * never zero. A text cell starting with `=`, `+`, `-`, `@`, tab, CR or `'` is
819
+ * written with one extra leading `'` so a spreadsheet opens it as text; stripping
820
+ * one leading `'` from such a cell restores it exactly. Numbers use `.` as the
821
+ * decimal separator and are never prefixed.
822
+ */
823
+ interface ProductCatalogExport {
824
+ /** Presigned GET; valid until `expiresAt`. Ask for a new export after that. */
825
+ url: string;
826
+ fileName: string;
827
+ /** ms epoch. */
828
+ expiresAt: number;
829
+ /** ms epoch the rows were read at. */
830
+ generatedAt: number;
831
+ rowCount: number;
832
+ /**
833
+ * `false` when the read stopped before the end of the selection. The file then
834
+ * holds only the rows before the stop, its name ends in `-parcial`, and
835
+ * `nextStartKey` exports the rest.
836
+ */
837
+ complete: boolean;
838
+ nextStartKey?: string;
839
+ columns: ProductCatalogExportColumn[];
840
+ }
841
+ interface ProductCatalogExportResponse {
842
+ message: string;
843
+ data: ProductCatalogExport;
844
+ }
845
+ type ProductCatalogExportColumn = (typeof PRODUCT_CATALOG_EXPORT_COLUMNS)[number];
748
846
  }
847
+ /**
848
+ * The CSV header of `GET /products?mode=export`, in file order.
849
+ *
850
+ * The first block uses the bulk-import row keys, so a column means the same thing
851
+ * in both directions: `prices` and `sellableOn` are JSON arrays, `barcode` is the
852
+ * primary barcode. The last block is read-only — the import ignores it:
853
+ * `productId`, `currentStock` (stock now, not an opening balance), `minStock` and
854
+ * `updatedAt` (ms epoch).
855
+ */
856
+ export declare const PRODUCT_CATALOG_EXPORT_COLUMNS: readonly ["sku", "name", "description", "categoryId", "brandId", "currency", "cost", "ivaType", "prices", "barcode", "limit", "zone", "isService", "isNew", "disabled", "sellableOn", "weightGrams", "lengthMm", "widthMm", "heightMm", "productId", "currentStock", "minStock", "updatedAt"];
857
+ /**
858
+ * Every refusal `GET /products?mode=export` answers, beyond the cross-cutting
859
+ * `GATING_ERROR_CODES` (the `importExport` entitlement among them):
860
+ *
861
+ * - `ADMIN_REQUIRED` · 403 — the caller is neither ADMIN nor MANAGER.
862
+ * - `ROLE_FORBIDDEN` · 403 — a print agent or an accountant.
863
+ * - `VALIDATION_FAILED` · 400 — a filter outside the grammar.
864
+ * - `INVALID_CURSOR` · 400 — a `startKey` this store did not mint.
865
+ */
866
+ export declare const PRODUCT_EXPORT_ERROR_CODES: readonly ["ADMIN_REQUIRED", "ROLE_FORBIDDEN", "VALIDATION_FAILED", "INVALID_CURSOR"];
867
+ export type ProductExportErrorCode = (typeof PRODUCT_EXPORT_ERROR_CODES)[number];
749
868
  /**
750
869
  * Every refusal `POST /products` answers on a single-product create or edit —
751
870
  * the body with no `mode`, `stacks/lambdas/products/_post.ts` behind
package/dist/product.js CHANGED
@@ -1,3 +1,48 @@
1
+ /**
2
+ * The CSV header of `GET /products?mode=export`, in file order.
3
+ *
4
+ * The first block uses the bulk-import row keys, so a column means the same thing
5
+ * in both directions: `prices` and `sellableOn` are JSON arrays, `barcode` is the
6
+ * primary barcode. The last block is read-only — the import ignores it:
7
+ * `productId`, `currentStock` (stock now, not an opening balance), `minStock` and
8
+ * `updatedAt` (ms epoch).
9
+ */
10
+ export const PRODUCT_CATALOG_EXPORT_COLUMNS = [
11
+ 'sku',
12
+ 'name',
13
+ 'description',
14
+ 'categoryId',
15
+ 'brandId',
16
+ 'currency',
17
+ 'cost',
18
+ 'ivaType',
19
+ 'prices',
20
+ 'barcode',
21
+ 'limit',
22
+ 'zone',
23
+ 'isService',
24
+ 'isNew',
25
+ 'disabled',
26
+ 'sellableOn',
27
+ 'weightGrams',
28
+ 'lengthMm',
29
+ 'widthMm',
30
+ 'heightMm',
31
+ 'productId',
32
+ 'currentStock',
33
+ 'minStock',
34
+ 'updatedAt',
35
+ ];
36
+ /**
37
+ * Every refusal `GET /products?mode=export` answers, beyond the cross-cutting
38
+ * `GATING_ERROR_CODES` (the `importExport` entitlement among them):
39
+ *
40
+ * - `ADMIN_REQUIRED` · 403 — the caller is neither ADMIN nor MANAGER.
41
+ * - `ROLE_FORBIDDEN` · 403 — a print agent or an accountant.
42
+ * - `VALIDATION_FAILED` · 400 — a filter outside the grammar.
43
+ * - `INVALID_CURSOR` · 400 — a `startKey` this store did not mint.
44
+ */
45
+ export const PRODUCT_EXPORT_ERROR_CODES = ['ADMIN_REQUIRED', 'ROLE_FORBIDDEN', 'VALIDATION_FAILED', 'INVALID_CURSOR'];
1
46
  /**
2
47
  * Every refusal `POST /products` answers on a single-product create or edit —
3
48
  * the body with no `mode`, `stacks/lambdas/products/_post.ts` behind
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sinfactura-types",
3
- "version": "1.10.554",
3
+ "version": "1.10.555",
4
4
  "description": "Shared wire and entity contracts for the SINFACTURA platform.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",