@aglyn/plugins-commerce 1.0.0-beta.221 → 1.0.0-beta.222

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 (125) hide show
  1. package/README.md +4 -2
  2. package/package.json +14 -13
  3. package/src/lib/components/console/catalog-organization-card.component.js +9 -0
  4. package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
  5. package/src/lib/components/console/discounts-card.component.js +8 -0
  6. package/src/lib/components/console/discounts-card.component.js.map +1 -1
  7. package/src/lib/components/console/gift-cards-card.component.js +8 -0
  8. package/src/lib/components/console/gift-cards-card.component.js.map +1 -1
  9. package/src/lib/components/console/host-coupons-card.component.js +8 -0
  10. package/src/lib/components/console/host-coupons-card.component.js.map +1 -1
  11. package/src/lib/components/console/host-orders-card.component.js +34 -70
  12. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  13. package/src/lib/components/console/product-zones.d.ts +7 -6
  14. package/src/lib/components/console/product-zones.js +5 -4
  15. package/src/lib/components/console/product-zones.js.map +1 -1
  16. package/src/lib/components/console/products-hub-card.component.js +86 -284
  17. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  18. package/src/lib/declarations.console-server.d.ts +38 -0
  19. package/src/lib/declarations.console-server.js +67 -0
  20. package/src/lib/declarations.console-server.js.map +1 -0
  21. package/src/lib/model/commerce-gift-cards.d.ts +26 -0
  22. package/src/lib/model/commerce-gift-cards.js +42 -0
  23. package/src/lib/model/commerce-gift-cards.js.map +1 -1
  24. package/src/lib/model/commerce-orders.d.ts +0 -57
  25. package/src/lib/model/commerce-orders.js +0 -80
  26. package/src/lib/model/commerce-orders.js.map +1 -1
  27. package/src/lib/model/index.d.ts +0 -1
  28. package/src/lib/model/index.js +0 -1
  29. package/src/lib/model/index.js.map +1 -1
  30. package/src/lib/plugin.js +5 -0
  31. package/src/lib/plugin.js.map +1 -1
  32. package/src/lib/server/api-v1/openapi.d.ts +27 -0
  33. package/src/lib/server/api-v1/openapi.js +219 -0
  34. package/src/lib/server/api-v1/openapi.js.map +1 -0
  35. package/src/lib/server/api-v1/orders-and-products.d.ts +19 -0
  36. package/src/lib/server/api-v1/orders-and-products.js +419 -0
  37. package/src/lib/server/api-v1/orders-and-products.js.map +1 -0
  38. package/src/lib/server/billing-webhook.js +10 -13
  39. package/src/lib/server/billing-webhook.js.map +1 -1
  40. package/src/lib/server/download.js +4 -1
  41. package/src/lib/server/download.js.map +1 -1
  42. package/src/lib/server/fulfill-order.d.ts +52 -11
  43. package/src/lib/server/fulfill-order.js +6 -9
  44. package/src/lib/server/fulfill-order.js.map +1 -1
  45. package/src/lib/server/gift-card-issue.d.ts +57 -0
  46. package/src/lib/server/gift-card-issue.js +155 -0
  47. package/src/lib/server/gift-card-issue.js.map +1 -0
  48. package/src/lib/server/gift-cards.js +25 -84
  49. package/src/lib/server/gift-cards.js.map +1 -1
  50. package/src/lib/server/membership-register.js +9 -8
  51. package/src/lib/server/membership-register.js.map +1 -1
  52. package/src/lib/server/newsletter.js +7 -5
  53. package/src/lib/server/newsletter.js.map +1 -1
  54. package/src/lib/server/paid-media-delivery.d.ts +21 -0
  55. package/src/lib/server/paid-media-delivery.js +23 -5
  56. package/src/lib/server/paid-media-delivery.js.map +1 -1
  57. package/src/lib/server/paid-media-serve-count.d.ts +28 -0
  58. package/src/lib/server/paid-media-serve-count.js +46 -0
  59. package/src/lib/server/paid-media-serve-count.js.map +1 -0
  60. package/src/lib/server/person-eraser.d.ts +45 -0
  61. package/src/lib/server/person-eraser.js +57 -0
  62. package/src/lib/server/person-eraser.js.map +1 -0
  63. package/src/lib/server/refund.js +15 -15
  64. package/src/lib/server/refund.js.map +1 -1
  65. package/src/lib/server/restock-flag.d.ts +2 -2
  66. package/src/lib/server/restock-flag.js +1 -1
  67. package/src/lib/server/restock-flag.js.map +1 -1
  68. package/src/lib/server/stream.js +4 -1
  69. package/src/lib/server/stream.js.map +1 -1
  70. package/src/lib/server.js +5 -21
  71. package/src/lib/server.js.map +1 -1
  72. package/src/lib/testing/stand-in-person-records.d.ts +43 -0
  73. package/src/lib/testing/stand-in-person-records.js +63 -0
  74. package/src/lib/testing/stand-in-person-records.js.map +1 -0
  75. package/src/lib/transfer/gift-card-confirm-step.component.d.ts +22 -0
  76. package/src/lib/transfer/gift-card-confirm-step.component.js +259 -0
  77. package/src/lib/transfer/gift-card-confirm-step.component.js.map +1 -0
  78. package/src/lib/transfer/gift-cards-plan.d.ts +29 -0
  79. package/src/lib/transfer/gift-cards-plan.js +40 -0
  80. package/src/lib/transfer/gift-cards-plan.js.map +1 -0
  81. package/src/lib/transfer/gift-cards.server.d.ts +34 -0
  82. package/src/lib/transfer/gift-cards.server.js +296 -0
  83. package/src/lib/transfer/gift-cards.server.js.map +1 -0
  84. package/src/lib/transfer/list-filter.d.ts +29 -0
  85. package/src/lib/transfer/list-filter.js +112 -0
  86. package/src/lib/transfer/list-filter.js.map +1 -0
  87. package/src/lib/transfer/product-import-results.d.ts +29 -0
  88. package/src/lib/transfer/product-import-results.js +49 -0
  89. package/src/lib/transfer/product-import-results.js.map +1 -0
  90. package/src/lib/transfer/product-import-step.component.d.ts +30 -0
  91. package/src/lib/transfer/product-import-step.component.js +99 -0
  92. package/src/lib/transfer/product-import-step.component.js.map +1 -0
  93. package/src/lib/transfer/product-transfer.d.ts +211 -0
  94. package/src/lib/transfer/product-transfer.js +1594 -0
  95. package/src/lib/transfer/product-transfer.js.map +1 -0
  96. package/src/lib/transfer/products.server.d.ts +44 -0
  97. package/src/lib/transfer/products.server.js +550 -0
  98. package/src/lib/transfer/products.server.js.map +1 -0
  99. package/src/lib/transfer/records-transfer.d.ts +182 -0
  100. package/src/lib/transfer/records-transfer.js +1153 -0
  101. package/src/lib/transfer/records-transfer.js.map +1 -0
  102. package/src/lib/transfer/records.server.d.ts +68 -0
  103. package/src/lib/transfer/records.server.js +455 -0
  104. package/src/lib/transfer/records.server.js.map +1 -0
  105. package/src/lib/transfer/register-transfer-resources.d.ts +17 -0
  106. package/src/lib/transfer/register-transfer-resources.js +171 -0
  107. package/src/lib/transfer/register-transfer-resources.js.map +1 -0
  108. package/src/lib/transfer/register-transfer-ui.d.ts +23 -0
  109. package/src/lib/transfer/register-transfer-ui.js +78 -0
  110. package/src/lib/transfer/register-transfer-ui.js.map +1 -0
  111. package/src/lib/transfer/server-common.d.ts +76 -0
  112. package/src/lib/transfer/server-common.js +165 -0
  113. package/src/lib/transfer/server-common.js.map +1 -0
  114. package/src/lib/transfer/transfer-header-actions.component.d.ts +39 -0
  115. package/src/lib/transfer/transfer-header-actions.component.js +79 -0
  116. package/src/lib/transfer/transfer-header-actions.component.js.map +1 -0
  117. package/src/lib/transfer/transfer-keys.d.ts +31 -0
  118. package/src/lib/transfer/transfer-keys.js +56 -0
  119. package/src/lib/transfer/transfer-keys.js.map +1 -0
  120. package/src/lib/model/commerce-io.d.ts +0 -36
  121. package/src/lib/model/commerce-io.js +0 -245
  122. package/src/lib/model/commerce-io.js.map +0 -1
  123. package/src/lib/server/contact-refund.d.ts +0 -117
  124. package/src/lib/server/contact-refund.js +0 -196
  125. package/src/lib/server/contact-refund.js.map +0 -1
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type MaybeTokenSource } from '@aglyn/shared-util-http/authorized-token';
18
+ export interface PendingProductImport {
19
+ orgId: string;
20
+ jobId: string;
21
+ /** The options the `productImport` zone set, by key. */
22
+ options: Record<string, boolean>;
23
+ }
24
+ /** Files the import a site's wizard is running, with its options. */
25
+ export declare function rememberProductImport(hostId: string, entry: PendingProductImport): void;
26
+ /** The import the site's wizard last ran, once: the hub takes it when the wizard closes. */
27
+ export declare function takeProductImport(hostId: string): PendingProductImport | null;
28
+ /** The products an applied import created, from the job's results (`api/transfer/status`). */
29
+ export declare function createdProductIds(user: MaybeTokenSource, entry: PendingProductImport): Promise<string[]>;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
17
+ const pending = new Map();
18
+ /** Files the import a site's wizard is running, with its options. */ export function rememberProductImport(hostId, entry) {
19
+ pending.set(hostId, entry);
20
+ }
21
+ /** The import the site's wizard last ran, once: the hub takes it when the wizard closes. */ export function takeProductImport(hostId) {
22
+ var _pending_get;
23
+ const entry = (_pending_get = pending.get(hostId)) != null ? _pending_get : null;
24
+ pending.delete(hostId);
25
+ return entry;
26
+ }
27
+ /** The products an applied import created, from the job's results (`api/transfer/status`). */ export async function createdProductIds(user, entry) {
28
+ var _ref;
29
+ const response = await authorizedFetch(user, '/api/transfer/status', {
30
+ method: 'POST',
31
+ headers: {
32
+ 'Content-Type': 'application/json'
33
+ },
34
+ body: JSON.stringify({
35
+ orgId: entry.orgId,
36
+ jobId: entry.jobId,
37
+ include: 'results'
38
+ })
39
+ });
40
+ if (!response.ok) return [];
41
+ const status = await response.json().catch(()=>null);
42
+ const ids = [];
43
+ for (const row of (_ref = status == null ? void 0 : status.rows) != null ? _ref : []){
44
+ if (row.outcome === 'created' && row.recordId && !ids.includes(row.recordId)) ids.push(row.recordId);
45
+ }
46
+ return ids;
47
+ }
48
+
49
+ //# sourceMappingURL=product-import-results.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/transfer/product-import-results.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { authorizedFetch, type MaybeTokenSource } from '@aglyn/shared-util-http/authorized-token'\nimport type { TransferStatusResponse } from '@aglyn/aglyn/data-transfer'\n\n/*\n * WHAT A PRODUCT IMPORT LEFT FOR THE PRODUCTS HUB (AGL-3531).\n *\n * The `productImport` zone's options are set in the wizard's own step\n * (`ProductImportOptionsStep`) and the hub hands them to the `productsHub`\n * zone with the products the import CREATED — the AI copy option starts a\n * copy job for exactly those. The step files the job here; the hub takes it\n * when the wizard closes on its results and reads the created ids from the\n * job's results. Module state is enough: the step and the hub share one tab.\n */\n\nexport interface PendingProductImport {\n orgId: string\n jobId: string\n /** The options the `productImport` zone set, by key. */\n options: Record<string, boolean>\n}\n\nconst pending = new Map<string, PendingProductImport>()\n\n/** Files the import a site's wizard is running, with its options. */\nexport function rememberProductImport(hostId: string, entry: PendingProductImport): void {\n pending.set(hostId, entry)\n}\n\n/** The import the site's wizard last ran, once: the hub takes it when the wizard closes. */\nexport function takeProductImport(hostId: string): PendingProductImport | null {\n const entry = pending.get(hostId) ?? null\n pending.delete(hostId)\n return entry\n}\n\n/** The products an applied import created, from the job's results (`api/transfer/status`). */\nexport async function createdProductIds(user: MaybeTokenSource, entry: PendingProductImport): Promise<string[]> {\n const response = await authorizedFetch(user, '/api/transfer/status', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ orgId: entry.orgId, jobId: entry.jobId, include: 'results' }),\n })\n if (!response.ok) return []\n const status = (await response.json().catch(() => null)) as TransferStatusResponse | null\n const ids: string[] = []\n for (const row of status?.rows ?? []) {\n if (row.outcome === 'created' && row.recordId && !ids.includes(row.recordId)) ids.push(row.recordId)\n }\n return ids\n}\n"],"names":["authorizedFetch","pending","Map","rememberProductImport","hostId","entry","set","takeProductImport","get","delete","createdProductIds","user","response","method","headers","body","JSON","stringify","orgId","jobId","include","ok","status","json","catch","ids","row","rows","outcome","recordId","includes","push"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,eAAe,QAA+B,2CAA0C;AAqBjG,MAAMC,UAAU,IAAIC;AAEpB,mEAAmE,GACnE,OAAO,SAASC,sBAAsBC,MAAc,EAAEC,KAA2B;IAC/EJ,QAAQK,GAAG,CAACF,QAAQC;AACtB;AAEA,0FAA0F,GAC1F,OAAO,SAASE,kBAAkBH,MAAc;QAChCH;IAAd,MAAMI,SAAQJ,eAAAA,QAAQO,GAAG,CAACJ,mBAAZH,eAAuB;IACrCA,QAAQQ,MAAM,CAACL;IACf,OAAOC;AACT;AAEA,4FAA4F,GAC5F,OAAO,eAAeK,kBAAkBC,IAAsB,EAAEN,KAA2B;;IACzF,MAAMO,WAAW,MAAMZ,gBAAgBW,MAAM,wBAAwB;QACnEE,QAAQ;QACRC,SAAS;YAAE,gBAAgB;QAAmB;QAC9CC,MAAMC,KAAKC,SAAS,CAAC;YAAEC,OAAOb,MAAMa,KAAK;YAAEC,OAAOd,MAAMc,KAAK;YAAEC,SAAS;QAAU;IACpF;IACA,IAAI,CAACR,SAASS,EAAE,EAAE,OAAO,EAAE;IAC3B,MAAMC,SAAU,MAAMV,SAASW,IAAI,GAAGC,KAAK,CAAC,IAAM;IAClD,MAAMC,MAAgB,EAAE;IACxB,KAAK,MAAMC,eAAOJ,0BAAAA,OAAQK,IAAI,mBAAI,EAAE,CAAE;QACpC,IAAID,IAAIE,OAAO,KAAK,aAAaF,IAAIG,QAAQ,IAAI,CAACJ,IAAIK,QAAQ,CAACJ,IAAIG,QAAQ,GAAGJ,IAAIM,IAAI,CAACL,IAAIG,QAAQ;IACrG;IACA,OAAOJ;AACT"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { TransferWizardStepProps } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources';
18
+ /**
19
+ * The product import wizard's After import step (AGL-3531): the
20
+ * `productImport` zone, where another plugin offers what happens to the
21
+ * products once they land — the AI plugin's "write descriptions as they
22
+ * land". The options are filed with the job for the products hub, which
23
+ * hands them to `productsHub` with the ids the import created. Nothing here
24
+ * blocks the import: with no widget the step says so and lets it go on.
25
+ */
26
+ export declare function ProductImportOptionsStep(props: TransferWizardStepProps): import("react").JSX.Element;
27
+ export declare namespace ProductImportOptionsStep {
28
+ var displayName: string;
29
+ }
30
+ export default ProductImportOptionsStep;
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { _ as _extends } from "@swc/helpers/_/_extends";
18
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
+ import { useConsoleWidgetSlot } from "@aglyn/aglyn/app-utils/console-widget-slot-context";
20
+ import { useFirestore } from "@aglyn/tenant-feature-instance";
21
+ import { Stack, Typography } from "@mui/material";
22
+ import { doc, getDoc } from "firebase/firestore";
23
+ import { useCallback, useEffect, useState } from "react";
24
+ import { PRODUCT_IMPORT_ZONE } from "../components/console/product-zones.js";
25
+ import { rememberProductImport } from "./product-import-results.js";
26
+ /**
27
+ * The product import wizard's After import step (AGL-3531): the
28
+ * `productImport` zone, where another plugin offers what happens to the
29
+ * products once they land — the AI plugin's "write descriptions as they
30
+ * land". The options are filed with the job for the products hub, which
31
+ * hands them to `productsHub` with the ids the import created. Nothing here
32
+ * blocks the import: with no widget the step says so and lets it go on.
33
+ */ export function ProductImportOptionsStep(props) {
34
+ const { orgId, hostId, jobId, value, setValue, setComplete } = props;
35
+ const firestore = useFirestore();
36
+ const WidgetSlot = useConsoleWidgetSlot();
37
+ const options = value && typeof value === 'object' ? value : {};
38
+ const [count, setCount] = useState(0);
39
+ useEffect(()=>setComplete(true), [
40
+ setComplete
41
+ ]);
42
+ // How many products the dry run creates, from the job the wizard listens to.
43
+ useEffect(()=>{
44
+ if (!jobId || !orgId) return;
45
+ let live = true;
46
+ getDoc(doc(firestore, 'orgs', orgId, 'transferJobs', jobId)).then((snapshot)=>{
47
+ var _snapshot_get;
48
+ const creates = Number((_snapshot_get = snapshot.get('summary.create')) != null ? _snapshot_get : 0);
49
+ if (live) setCount(Number.isFinite(creates) ? creates : 0);
50
+ }).catch(()=>undefined);
51
+ return ()=>{
52
+ live = false;
53
+ };
54
+ }, [
55
+ firestore,
56
+ orgId,
57
+ jobId
58
+ ]);
59
+ useEffect(()=>{
60
+ if (hostId && jobId && orgId) rememberProductImport(hostId, {
61
+ orgId,
62
+ jobId,
63
+ options
64
+ });
65
+ }, [
66
+ hostId,
67
+ jobId,
68
+ orgId,
69
+ options
70
+ ]);
71
+ const setOption = useCallback((key, on)=>setValue(_extends({}, options, {
72
+ [key]: on
73
+ })), [
74
+ options,
75
+ setValue
76
+ ]);
77
+ return /*#__PURE__*/ _jsxs(Stack, {
78
+ spacing: 1,
79
+ children: [
80
+ /*#__PURE__*/ _jsx(Typography, {
81
+ variant: "body2",
82
+ color: "text.secondary",
83
+ children: 'What happens to the new products once they land.'
84
+ }),
85
+ WidgetSlot && hostId ? /*#__PURE__*/ _jsx(WidgetSlot, {
86
+ slot: PRODUCT_IMPORT_ZONE.id,
87
+ hostId: hostId,
88
+ orgId: orgId,
89
+ count: count,
90
+ options: options,
91
+ setOption: setOption
92
+ }) : null
93
+ ]
94
+ });
95
+ }
96
+ ProductImportOptionsStep.displayName = 'ProductImportOptionsStep';
97
+ export default ProductImportOptionsStep;
98
+
99
+ //# sourceMappingURL=product-import-step.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/transfer/product-import-step.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { useConsoleWidgetSlot } from '@aglyn/aglyn/app-utils/console-widget-slot-context'\nimport type { TransferWizardStepProps } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { Stack, Typography } from '@mui/material'\nimport { doc, getDoc } from 'firebase/firestore'\nimport { useCallback, useEffect, useState } from 'react'\nimport { PRODUCT_IMPORT_ZONE } from '../components/console/product-zones'\nimport { rememberProductImport } from './product-import-results'\n\n/**\n * The product import wizard's After import step (AGL-3531): the\n * `productImport` zone, where another plugin offers what happens to the\n * products once they land — the AI plugin's \"write descriptions as they\n * land\". The options are filed with the job for the products hub, which\n * hands them to `productsHub` with the ids the import created. Nothing here\n * blocks the import: with no widget the step says so and lets it go on.\n */\nexport function ProductImportOptionsStep(props: TransferWizardStepProps) {\n const { orgId, hostId, jobId, value, setValue, setComplete } = props\n const firestore = useFirestore()\n const WidgetSlot = useConsoleWidgetSlot()\n const options = (value && typeof value === 'object' ? value : {}) as Record<string, boolean>\n const [count, setCount] = useState(0)\n\n useEffect(() => setComplete(true), [setComplete])\n\n // How many products the dry run creates, from the job the wizard listens to.\n useEffect(() => {\n if (!jobId || !orgId) return\n let live = true\n getDoc(doc(firestore, 'orgs', orgId, 'transferJobs', jobId))\n .then((snapshot) => {\n const creates = Number(snapshot.get('summary.create') ?? 0)\n if (live) setCount(Number.isFinite(creates) ? creates : 0)\n })\n .catch(() => undefined)\n return () => {\n live = false\n }\n }, [firestore, orgId, jobId])\n\n useEffect(() => {\n if (hostId && jobId && orgId) rememberProductImport(hostId, { orgId, jobId, options })\n }, [hostId, jobId, orgId, options])\n\n const setOption = useCallback(\n (key: string, on: boolean) => setValue({ ...options, [key]: on }),\n [options, setValue],\n )\n\n return (\n <Stack spacing={1}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'What happens to the new products once they land.'}\n </Typography>\n {WidgetSlot && hostId ? (\n <WidgetSlot\n slot={PRODUCT_IMPORT_ZONE.id}\n hostId={hostId}\n orgId={orgId}\n count={count}\n options={options}\n setOption={setOption}\n />\n ) : null}\n </Stack>\n )\n}\nProductImportOptionsStep.displayName = 'ProductImportOptionsStep'\n\nexport default ProductImportOptionsStep\n"],"names":["useConsoleWidgetSlot","useFirestore","Stack","Typography","doc","getDoc","useCallback","useEffect","useState","PRODUCT_IMPORT_ZONE","rememberProductImport","ProductImportOptionsStep","props","orgId","hostId","jobId","value","setValue","setComplete","firestore","WidgetSlot","options","count","setCount","live","then","snapshot","creates","Number","get","isFinite","catch","undefined","setOption","key","on","spacing","variant","color","slot","id","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;AAEA,SAASA,oBAAoB,QAAQ,qDAAoD;AAEzF,SAASC,YAAY,QAAQ,iCAAgC;AAC7D,SAASC,KAAK,EAAEC,UAAU,QAAQ,gBAAe;AACjD,SAASC,GAAG,EAAEC,MAAM,QAAQ,qBAAoB;AAChD,SAASC,WAAW,EAAEC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AACxD,SAASC,mBAAmB,QAAQ,yCAAqC;AACzE,SAASC,qBAAqB,QAAQ,8BAA0B;AAEhE;;;;;;;CAOC,GACD,OAAO,SAASC,yBAAyBC,KAA8B;IACrE,MAAM,EAAEC,KAAK,EAAEC,MAAM,EAAEC,KAAK,EAAEC,KAAK,EAAEC,QAAQ,EAAEC,WAAW,EAAE,GAAGN;IAC/D,MAAMO,YAAYlB;IAClB,MAAMmB,aAAapB;IACnB,MAAMqB,UAAWL,SAAS,OAAOA,UAAU,WAAWA,QAAQ,CAAC;IAC/D,MAAM,CAACM,OAAOC,SAAS,GAAGf,SAAS;IAEnCD,UAAU,IAAMW,YAAY,OAAO;QAACA;KAAY;IAEhD,6EAA6E;IAC7EX,UAAU;QACR,IAAI,CAACQ,SAAS,CAACF,OAAO;QACtB,IAAIW,OAAO;QACXnB,OAAOD,IAAIe,WAAW,QAAQN,OAAO,gBAAgBE,QAClDU,IAAI,CAAC,CAACC;gBACkBA;YAAvB,MAAMC,UAAUC,QAAOF,gBAAAA,SAASG,GAAG,CAAC,6BAAbH,gBAAkC;YACzD,IAAIF,MAAMD,SAASK,OAAOE,QAAQ,CAACH,WAAWA,UAAU;QAC1D,GACCI,KAAK,CAAC,IAAMC;QACf,OAAO;YACLR,OAAO;QACT;IACF,GAAG;QAACL;QAAWN;QAAOE;KAAM;IAE5BR,UAAU;QACR,IAAIO,UAAUC,SAASF,OAAOH,sBAAsBI,QAAQ;YAAED;YAAOE;YAAOM;QAAQ;IACtF,GAAG;QAACP;QAAQC;QAAOF;QAAOQ;KAAQ;IAElC,MAAMY,YAAY3B,YAChB,CAAC4B,KAAaC,KAAgBlB,SAAS,aAAKI;YAAS,CAACa,IAAI,EAAEC;aAC5D;QAACd;QAASJ;KAAS;IAGrB,qBACE,MAACf;QAAMkC,SAAS;;0BACd,KAACjC;gBAAWkC,SAAQ;gBAAQC,OAAM;0BAC/B;;YAEFlB,cAAcN,uBACb,KAACM;gBACCmB,MAAM9B,oBAAoB+B,EAAE;gBAC5B1B,QAAQA;gBACRD,OAAOA;gBACPS,OAAOA;gBACPD,SAASA;gBACTY,WAAWA;iBAEX;;;AAGV;AACAtB,yBAAyB8B,WAAW,GAAG;AAEvC,eAAe9B,yBAAwB"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type BuildTransferPlanInput, type MatchKeySpec, type PlannedTransferRow, type TransferAliasDictionary, type TransferField, type TransferFieldGroup, type TransferLockedRule, type TransferPlan, type TransferPlanRow, type TransferResourcePreset } from '@aglyn/aglyn/data-transfer';
18
+ import type { PicklistSpec } from '@aglyn/aglyn/app-utils/picklists';
19
+ import { type HostProduct, type ProductOption, type ProductVariant } from '../model/commerce';
20
+ /** The field ids, as the catalog and every file name them. */
21
+ export declare const PRODUCT_FIELD: {
22
+ readonly handle: "handle";
23
+ readonly title: "title";
24
+ readonly description: "description";
25
+ readonly kind: "type";
26
+ readonly status: "status";
27
+ readonly published: "published";
28
+ readonly tags: "tags";
29
+ readonly categories: "categories";
30
+ readonly option1Name: "option1Name";
31
+ readonly option2Name: "option2Name";
32
+ readonly option3Name: "option3Name";
33
+ readonly image: "image";
34
+ readonly seoTitle: "seoTitle";
35
+ readonly seoDescription: "seoDescription";
36
+ readonly taxExempt: "taxExempt";
37
+ readonly oversellPolicy: "oversellPolicy";
38
+ readonly lowStockThreshold: "lowStockThreshold";
39
+ readonly option1Value: "option1Value";
40
+ readonly option2Value: "option2Value";
41
+ readonly option3Value: "option3Value";
42
+ readonly sku: "sku";
43
+ readonly barcode: "barcode";
44
+ readonly price: "price";
45
+ readonly compareAtPrice: "compareAtPrice";
46
+ readonly inventory: "inventory";
47
+ readonly weightGrams: "weightGrams";
48
+ readonly variantImage: "variantImage";
49
+ readonly priceFrom: "priceFrom";
50
+ readonly totalInventory: "totalInventory";
51
+ readonly soldOut: "soldOut";
52
+ readonly variantCount: "variantCount";
53
+ readonly createdAt: "createdAt";
54
+ readonly updatedAt: "updatedAt";
55
+ };
56
+ /** The picklists the product fields name. */
57
+ export declare const PRODUCT_KIND_PICKLIST = "commerce.productKind";
58
+ export declare const PRODUCT_STATUS_PICKLIST = "commerce.productStatus";
59
+ export declare const PRODUCT_OVERSELL_PICKLIST = "commerce.oversellPolicy";
60
+ export declare const PRODUCT_CATEGORY_PICKLIST = "commerce.categories";
61
+ /** The fixed lists products name, by picklist id. */
62
+ export declare const PRODUCT_FIXED_PICKLISTS: Readonly<Record<string, PicklistSpec>>;
63
+ /** The id a label of a fixed list names, by label or id in any case; `null` for none. */
64
+ export declare function fixedListId(picklistId: string, value: unknown): string | null;
65
+ export declare const PRODUCT_TRANSFER_GROUPS: readonly TransferFieldGroup[];
66
+ /** The fields a product's first row carries: the product's own. */
67
+ export declare const PRODUCT_LEVEL_FIELDS: readonly string[];
68
+ /** The fields every row carries for its own variant. */
69
+ export declare const VARIANT_LEVEL_FIELDS: readonly string[];
70
+ /** Every writable product field, in picker order. */
71
+ export declare const PRODUCT_STANDARD_FIELDS: readonly TransferField[];
72
+ export declare const PRODUCT_DERIVED_FIELDS: readonly TransferField[];
73
+ export declare const PRODUCT_SYSTEM_FIELDS: readonly TransferField[];
74
+ /** Handle, then SKU, then the Aglyn ID. */
75
+ export declare const PRODUCT_MATCH_KEYS: readonly MatchKeySpec[];
76
+ /**
77
+ * A product's handle and its option names are changed in the product editor,
78
+ * never by a file: the handle is the product's address, and renaming an
79
+ * option moves every variant. A file gives a new product both, and names an
80
+ * option a product does not have yet.
81
+ */
82
+ export declare const PRODUCT_LOCKED_RULES: readonly TransferLockedRule[];
83
+ /** Shopify's product CSV columns, by the field each one means. */
84
+ export declare const SHOPIFY_PRODUCT_COLUMNS: Readonly<Record<string, string>>;
85
+ /** Shopify's export headers, so its file maps column for column. */
86
+ export declare const PRODUCT_ALIAS_DICTIONARIES: readonly TransferAliasDictionary[];
87
+ /**
88
+ * The Shopify preset: Shopify's product CSV columns, in Shopify's order and
89
+ * under Shopify's names. Status is left out — Shopify reads it in lowercase
90
+ * and Published says the same thing — and so is the kind, which Shopify's
91
+ * "Type" does not mean.
92
+ */
93
+ export declare const SHOPIFY_PRODUCT_PRESET: TransferResourcePreset;
94
+ /** Where a product's record keeps its variants, apart from its fields. */
95
+ export declare const PRODUCT_VARIANT_ORDER = "$variants";
96
+ /** The record key one variant's values live under. */
97
+ export declare function productVariantKey(variantId: string): string;
98
+ /** A variant's values, as a file names them. */
99
+ export type VariantRecord = Record<string, unknown> & {
100
+ /** Its stock is kept per location. */
101
+ $byLocation?: boolean;
102
+ };
103
+ /** A product as a stored document, the way every reader lifts one. */
104
+ type StoredProduct = Partial<HostProduct> & {
105
+ createdAt?: unknown;
106
+ updatedAt?: unknown;
107
+ createdAtMs?: number;
108
+ updatedAtMs?: number;
109
+ };
110
+ /** One variant as a file names it. */
111
+ export declare function variantRecord(variant: ProductVariant, options: readonly ProductOption[]): VariantRecord;
112
+ /**
113
+ * A product as one record: its fields by field id, and its variants under
114
+ * {@link productVariantKey} in the order {@link PRODUCT_VARIANT_ORDER} lists
115
+ * them. The lookup answers this shape, so the dry run's before → after and
116
+ * undo's "edited since" both read a product the way a file names it.
117
+ */
118
+ export declare function productRecord(stored: StoredProduct, categoryNames?: ReadonlyMap<string, string>): Record<string, unknown>;
119
+ /**
120
+ * A product's rows in a file, holding only `fieldIds`: one per variant (and
121
+ * per image past the variants), the product's own fields on the first, the
122
+ * handle and the ID on every one.
123
+ */
124
+ export declare function productExportRows(id: string, stored: StoredProduct, fieldIds: readonly string[], categoryNames?: ReadonlyMap<string, string>): Array<Record<string, unknown>>;
125
+ /** How many rows {@link productExportRows} writes for a product. */
126
+ export declare function productExportRowCount(stored: Pick<StoredProduct, 'variants' | 'mediaUrls' | 'imageUrl'>): number;
127
+ /** What a planned product row carries for the apply. */
128
+ export interface ProductRowPlan {
129
+ /** The product the row writes: its id, or the id a new one is created under. */
130
+ productId: string;
131
+ /** The file row carrying the product's own fields. */
132
+ leader: number;
133
+ /**
134
+ * `create` makes the product (its leader); `part` is a row folded into a
135
+ * product the leader creates; `update` writes this row's changes into an
136
+ * existing product.
137
+ */
138
+ role: 'create' | 'part' | 'update';
139
+ /** The variant this row writes, when it writes one. */
140
+ variant?: {
141
+ id: string;
142
+ isNew: boolean;
143
+ };
144
+ /** On a new product's leader: the whole document's parts. */
145
+ create?: {
146
+ slug: string;
147
+ values: Record<string, unknown>;
148
+ variants: Array<{
149
+ id: string;
150
+ values: Record<string, unknown>;
151
+ }>;
152
+ };
153
+ /** Why the product this row belongs to cannot be stored, when it cannot. */
154
+ problem?: string;
155
+ }
156
+ /** A planned row with what the apply needs. */
157
+ export type ProductPlannedRow = PlannedTransferRow & {
158
+ commerce?: ProductRowPlan;
159
+ };
160
+ export interface ProductPlanContext {
161
+ /** A new product's id. */
162
+ newProductId(): string;
163
+ /** A new variant's id, unique within its product. */
164
+ newVariantId(): string;
165
+ /** Whether a slug is held by a product already (deleted ones included). */
166
+ slugTaken?(slug: string): boolean;
167
+ /** How many products the site may still create; unbounded when absent. */
168
+ maxCreates?: number;
169
+ }
170
+ /** The tags a cell names, in their own case. */
171
+ export declare function productTagList(value: unknown): string[];
172
+ /**
173
+ * A product's document from its record values (see {@link productRecord}),
174
+ * for checking what a plan would store with the model's own rules.
175
+ */
176
+ export declare function productFromRecord(values: Readonly<Record<string, unknown>>, variants: ReadonlyArray<{
177
+ id: string;
178
+ values: Readonly<Record<string, unknown>>;
179
+ }>): HostProduct;
180
+ /** One variant of a document from its record values. */
181
+ export declare function variantFromRecord(id: string, values: Readonly<Record<string, unknown>>, optionNames: readonly (string | null | undefined)[]): ProductVariant;
182
+ /**
183
+ * The products resource's plan: the core's plan per product and per variant,
184
+ * folded back into one verdict per file row (see the block header).
185
+ */
186
+ export declare function planProductTransfer(input: BuildTransferPlanInput, context: ProductPlanContext): TransferPlan;
187
+ /** The handles a plan may create products under, for the server to ask which are taken. */
188
+ export declare function productPlanHandles(rows: readonly TransferPlanRow[]): string[];
189
+ /** Category names → ids, for the categories a row names. */
190
+ export type CategoryIdsOf = (names: readonly string[]) => string[];
191
+ /** A product with one planned row's changes written into it — the product's own on its first row, and the row's variant. */
192
+ export declare function applyProductRow(current: HostProduct, changes: {
193
+ product?: Readonly<Record<string, unknown>>;
194
+ variant?: {
195
+ id: string;
196
+ isNew: boolean;
197
+ values: Readonly<Record<string, unknown>>;
198
+ };
199
+ }, categoryIdsOf: CategoryIdsOf): HostProduct;
200
+ /** A new product's document from its leader's plan, before the platform's stamps. */
201
+ export declare function createProductDocument(create: NonNullable<ProductRowPlan['create']>, categoryIdsOf: CategoryIdsOf): HostProduct;
202
+ /** The values one planned row changes, split into the product's and its variant's. */
203
+ export declare function productRowChanges(row: ProductPlannedRow): {
204
+ product: Record<string, unknown>;
205
+ variant?: {
206
+ id: string;
207
+ isNew: boolean;
208
+ values: Record<string, unknown>;
209
+ };
210
+ };
211
+ export {};