@umec/admin 0.1.0-alpha.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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/dist/access.d.ts +7 -0
  3. package/dist/access.js +9 -0
  4. package/dist/access.js.map +1 -0
  5. package/dist/carriers.d.ts +9 -0
  6. package/dist/carriers.js +13 -0
  7. package/dist/carriers.js.map +1 -0
  8. package/dist/catalog/index.d.ts +27 -0
  9. package/dist/catalog/index.js +21 -0
  10. package/dist/catalog/index.js.map +1 -0
  11. package/dist/chunk-4DR4K72B.js +24 -0
  12. package/dist/chunk-4DR4K72B.js.map +1 -0
  13. package/dist/chunk-E7ATMICY.js +51 -0
  14. package/dist/chunk-E7ATMICY.js.map +1 -0
  15. package/dist/chunk-G3O62WUE.js +57 -0
  16. package/dist/chunk-G3O62WUE.js.map +1 -0
  17. package/dist/chunk-ODK4R57S.js +131 -0
  18. package/dist/chunk-ODK4R57S.js.map +1 -0
  19. package/dist/chunk-RK7FIONL.js +27 -0
  20. package/dist/chunk-RK7FIONL.js.map +1 -0
  21. package/dist/chunk-STQU4LQU.js +402 -0
  22. package/dist/chunk-STQU4LQU.js.map +1 -0
  23. package/dist/chunk-TIK7KC4O.js +210 -0
  24. package/dist/chunk-TIK7KC4O.js.map +1 -0
  25. package/dist/chunk-TKJ6KSXM.js +23 -0
  26. package/dist/chunk-TKJ6KSXM.js.map +1 -0
  27. package/dist/chunk-VUT3UCCR.js +200 -0
  28. package/dist/chunk-VUT3UCCR.js.map +1 -0
  29. package/dist/chunk-W2O6EQWT.js +57 -0
  30. package/dist/chunk-W2O6EQWT.js.map +1 -0
  31. package/dist/chunk-ZEA6G75Z.js +129 -0
  32. package/dist/chunk-ZEA6G75Z.js.map +1 -0
  33. package/dist/csv.d.ts +4 -0
  34. package/dist/csv.js +9 -0
  35. package/dist/csv.js.map +1 -0
  36. package/dist/http.d.ts +17 -0
  37. package/dist/http.js +17 -0
  38. package/dist/http.js.map +1 -0
  39. package/dist/index.d.ts +16 -0
  40. package/dist/index.js +141 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/inventory/index.d.ts +27 -0
  43. package/dist/inventory/index.js +21 -0
  44. package/dist/inventory/index.js.map +1 -0
  45. package/dist/offers.d.ts +10 -0
  46. package/dist/offers.js +9 -0
  47. package/dist/offers.js.map +1 -0
  48. package/dist/orders/index.d.ts +49 -0
  49. package/dist/orders/index.js +34 -0
  50. package/dist/orders/index.js.map +1 -0
  51. package/dist/product-fields.d.ts +12 -0
  52. package/dist/product-fields.js +14 -0
  53. package/dist/product-fields.js.map +1 -0
  54. package/dist/products.d.ts +48 -0
  55. package/dist/products.js +27 -0
  56. package/dist/products.js.map +1 -0
  57. package/dist/unshipped-alert.d.ts +19 -0
  58. package/dist/unshipped-alert.js +12 -0
  59. package/dist/unshipped-alert.js.map +1 -0
  60. package/package.json +86 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/catalog/create-product.ts","../src/catalog/discontinue-product.ts","../src/catalog/page.ts","../src/catalog/update-product.ts"],"sourcesContent":["import { createProduct, writeAuditLog } from \"@umec/core/db\";\nimport { getServerEnv } from \"@umec/core/env\";\nimport { authenticateAdmin } from \"../access.js\";\nimport { jsonError, jsonOk, readJsonObject, type AdminApiHandler } from \"../http.js\";\nimport { isFieldError, parseCreateProductFields, parseSku } from \"../product-fields.js\";\n\nexport function createCreateProductHandler(): AdminApiHandler {\n return async ({ request }) => {\n const auth = await authenticateAdmin(request);\n if (auth instanceof Response) return auth;\n\n const payload = await readJsonObject(request);\n if (payload instanceof Response) return payload;\n\n const sku = parseSku(payload.sku);\n if (isFieldError(sku)) return jsonError(sku.error, 400);\n\n const fields = parseCreateProductFields(payload);\n if (isFieldError(fields)) return jsonError(fields.error, 400);\n\n const { DB: db } = getServerEnv();\n if (!db) return jsonError(\"DB not available\", 503);\n\n try {\n const result = await createProduct(db, sku, fields, auth.email);\n if (result === \"conflict\") return jsonError(\"SKU already exists\", 409);\n } catch (error) {\n console.error(\"[create-product] insert failed:\", error);\n return jsonError(\"Failed to create product\", 500);\n }\n\n console.log(\n JSON.stringify({\n type: \"admin.audit\",\n action: \"create-product\",\n actor: auth.email,\n targetId: sku,\n }),\n );\n\n await writeAuditLog(db, {\n entityType: \"product\",\n entityId: sku,\n action: \"create-product\",\n adminEmail: auth.email,\n actor: \"human\",\n detail: {\n name: fields.name,\n price: fields.price,\n shipping_units: fields.shippingUnits,\n active: fields.active,\n },\n });\n\n return jsonOk({\n ok: true,\n sku,\n name: fields.name,\n price: fields.price,\n active: fields.active,\n });\n };\n}\n","import { discontinueProduct, writeAuditLog } from \"@umec/core/db\";\nimport { getServerEnv } from \"@umec/core/env\";\nimport { authenticateAdmin } from \"../access.js\";\nimport { jsonError, jsonOk, readJsonObject, type AdminApiHandler } from \"../http.js\";\nimport { isFieldError, parseSku } from \"../product-fields.js\";\n\nexport function createDiscontinueProductHandler(): AdminApiHandler {\n return async ({ request }) => {\n const auth = await authenticateAdmin(request);\n if (auth instanceof Response) return auth;\n\n const payload = await readJsonObject(request);\n if (payload instanceof Response) return payload;\n\n const sku = parseSku(payload.sku);\n if (isFieldError(sku)) return jsonError(sku.error, 400);\n\n const { DB: db } = getServerEnv();\n if (!db) return jsonError(\"DB not available\", 503);\n\n const result = await discontinueProduct(db, sku, auth.email);\n if (result === \"not_found\") return jsonError(\"SKU not found\", 404);\n\n if (result === \"already_inactive\") {\n return jsonOk({ ok: true, sku, active: 0 });\n }\n\n console.log(\n JSON.stringify({\n type: \"admin.audit\",\n action: \"discontinue-product\",\n actor: auth.email,\n targetId: sku,\n }),\n );\n\n await writeAuditLog(db, {\n entityType: \"product\",\n entityId: sku,\n action: \"discontinue-product\",\n adminEmail: auth.email,\n actor: \"human\",\n detail: { before: { active: 1 }, after: { active: 0 } },\n });\n\n return jsonOk({ ok: true, sku, active: 0 });\n };\n}\n","import type { InventoryRow } from \"@umec/core/db\";\nimport { getServerEnv } from \"@umec/core/env\";\nimport { requireAdminAuth } from \"../access.js\";\nimport { listProductRows, parseImagesJson, type ProductRow } from \"../products.js\";\n\nexport type ProductListRow = ProductRow & { stock: InventoryRow[\"stock\"] | null };\n\nexport type CatalogAdminPageData = {\n products: ProductListRow[];\n dbNotice: string;\n};\n\nexport type CatalogAdminPageLoad = { response: Response } | CatalogAdminPageData;\n\nexport function formatYen(value: number) {\n return new Intl.NumberFormat(\"ja-JP\", {\n style: \"currency\",\n currency: \"JPY\",\n maximumFractionDigits: 0,\n }).format(value);\n}\n\nexport function imagesText(row: ProductRow) {\n return parseImagesJson(row.images_json).join(\"\\n\");\n}\n\nexport async function loadCatalogAdminPage(request: Request): Promise<CatalogAdminPageLoad> {\n const denied = await requireAdminAuth(request);\n if (denied) return { response: denied };\n\n const { DB: db } = getServerEnv();\n let products: ProductListRow[] = [];\n let dbNotice = \"\";\n\n if (db) {\n try {\n const rows = await listProductRows(db, { includeInactive: true });\n const stockResult = await db\n .prepare(\"SELECT sku, stock FROM inventory\")\n .all<Pick<InventoryRow, \"sku\" | \"stock\">>();\n const stockMap = new Map<string, number>(\n (stockResult.results ?? []).map((row: Pick<InventoryRow, \"sku\" | \"stock\">) => [row.sku, row.stock]),\n );\n products = rows.map((row) => ({ ...row, stock: stockMap.get(row.sku) ?? null }));\n } catch (error) {\n console.error(\"[admin/products] query failed:\", error);\n dbNotice = \"Products could not be loaded.\";\n }\n } else {\n dbNotice = \"DB binding is not available.\";\n }\n\n return { products, dbNotice };\n}\n","import { updateProduct, writeAuditLog } from \"@umec/core/db\";\nimport { getServerEnv } from \"@umec/core/env\";\nimport { authenticateAdmin } from \"../access.js\";\nimport { jsonError, jsonOk, readJsonObject, type AdminApiHandler } from \"../http.js\";\nimport { isFieldError, parseSku, parseUpdateProductFields } from \"../product-fields.js\";\n\nexport function createUpdateProductHandler(): AdminApiHandler {\n return async ({ request }) => {\n const auth = await authenticateAdmin(request);\n if (auth instanceof Response) return auth;\n\n const payload = await readJsonObject(request);\n if (payload instanceof Response) return payload;\n\n const sku = parseSku(payload.sku);\n if (isFieldError(sku)) return jsonError(sku.error, 400);\n\n const fields = parseUpdateProductFields(payload);\n if (isFieldError(fields)) return jsonError(fields.error, 400);\n\n const { DB: db } = getServerEnv();\n if (!db) return jsonError(\"DB not available\", 503);\n\n const { result, before, after } = await updateProduct(db, sku, fields, auth.email);\n if (result === \"not_found\" || !before || !after) return jsonError(\"SKU not found\", 404);\n\n console.log(\n JSON.stringify({\n type: \"admin.audit\",\n action: \"update-product\",\n actor: auth.email,\n targetId: sku,\n }),\n );\n\n await writeAuditLog(db, {\n entityType: \"product\",\n entityId: sku,\n action: \"update-product\",\n adminEmail: auth.email,\n actor: \"human\",\n detail: {\n before: {\n name: before.name,\n price: before.price,\n active: before.active,\n },\n after: {\n name: after.name,\n price: after.price,\n active: after.active,\n },\n },\n });\n\n return jsonOk({\n ok: true,\n sku,\n name: after.name,\n price: after.price,\n active: after.active,\n });\n };\n}\n"],"mappings":"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","names":["writeAuditLog","getServerEnv","getServerEnv","writeAuditLog","getServerEnv","getServerEnv","writeAuditLog","getServerEnv","getServerEnv","writeAuditLog"]}
@@ -0,0 +1,23 @@
1
+ // src/csv.ts
2
+ function csvEscape(value) {
3
+ if (value == null) return "";
4
+ const text = String(value);
5
+ if (/[",\r\n]/.test(text)) {
6
+ return `"${text.replaceAll('"', '""')}"`;
7
+ }
8
+ return text;
9
+ }
10
+ function toCsv(headers, rows) {
11
+ const lines = [
12
+ headers.map(csvEscape).join(","),
13
+ ...rows.map((row) => row.map(csvEscape).join(","))
14
+ ];
15
+ return `${lines.join("\r\n")}\r
16
+ `;
17
+ }
18
+
19
+ export {
20
+ csvEscape,
21
+ toCsv
22
+ };
23
+ //# sourceMappingURL=chunk-TKJ6KSXM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/csv.ts"],"sourcesContent":["export function csvEscape(value: unknown): string {\n if (value == null) return \"\";\n const text = String(value);\n if (/[\",\\r\\n]/.test(text)) {\n return `\"${text.replaceAll('\"', '\"\"')}\"`;\n }\n return text;\n}\n\nexport function toCsv(headers: string[], rows: unknown[][]): string {\n const lines = [\n headers.map(csvEscape).join(\",\"),\n ...rows.map((row) => row.map(csvEscape).join(\",\")),\n ];\n return `${lines.join(\"\\r\\n\")}\\r\\n`;\n}\n"],"mappings":";AAAO,SAAS,UAAU,OAAwB;AAChD,MAAI,SAAS,KAAM,QAAO;AAC1B,QAAM,OAAO,OAAO,KAAK;AACzB,MAAI,WAAW,KAAK,IAAI,GAAG;AACzB,WAAO,IAAI,KAAK,WAAW,KAAK,IAAI,CAAC;AAAA,EACvC;AACA,SAAO;AACT;AAEO,SAAS,MAAM,SAAmB,MAA2B;AAClE,QAAM,QAAQ;AAAA,IACZ,QAAQ,IAAI,SAAS,EAAE,KAAK,GAAG;AAAA,IAC/B,GAAG,KAAK,IAAI,CAAC,QAAQ,IAAI,IAAI,SAAS,EAAE,KAAK,GAAG,CAAC;AAAA,EACnD;AACA,SAAO,GAAG,MAAM,KAAK,MAAM,CAAC;AAAA;AAC9B;","names":[]}
@@ -0,0 +1,200 @@
1
+ import {
2
+ authenticateAdmin,
3
+ requireAdminAuth
4
+ } from "./chunk-W2O6EQWT.js";
5
+ import {
6
+ csvAttachment,
7
+ jsonError,
8
+ jsonOk,
9
+ readJsonObject
10
+ } from "./chunk-E7ATMICY.js";
11
+ import {
12
+ toCsv
13
+ } from "./chunk-TKJ6KSXM.js";
14
+ import {
15
+ loadProductNamesFromDb
16
+ } from "./chunk-ZEA6G75Z.js";
17
+
18
+ // src/inventory/adjust-stock.ts
19
+ import { adjustStock, getStock, MAX_STOCK_DELTA, writeAuditLog } from "@umec/core/db";
20
+ import { getServerEnv } from "@umec/core/env";
21
+ function createAdjustStockHandler() {
22
+ return async ({ request }) => {
23
+ const auth = await authenticateAdmin(request);
24
+ if (auth instanceof Response) return auth;
25
+ const payload = await readJsonObject(request);
26
+ if (payload instanceof Response) return payload;
27
+ const { sku, delta, reason } = payload;
28
+ if (typeof sku !== "string" || sku.trim() === "") return jsonError("Invalid sku", 400);
29
+ if (typeof delta !== "number" || !Number.isInteger(delta) || delta === 0) {
30
+ return jsonError("Invalid delta", 400);
31
+ }
32
+ if (Math.abs(delta) > MAX_STOCK_DELTA) {
33
+ return jsonError(`delta must be between -${MAX_STOCK_DELTA} and ${MAX_STOCK_DELTA}`, 400);
34
+ }
35
+ if (typeof reason !== "string" || reason.trim() === "") {
36
+ return jsonError("reason is required", 400);
37
+ }
38
+ const { DB: db } = getServerEnv();
39
+ if (!db) return jsonError("DB not available", 503);
40
+ const current = (await getStock(db, [sku])).get(sku);
41
+ if (current === void 0) return jsonError("SKU not found", 404);
42
+ const result = await adjustStock(db, sku, delta);
43
+ if (result === "not_found") return jsonError("SKU not found", 404);
44
+ if (result === "insufficient") return jsonError("Insufficient stock", 409);
45
+ const after = current + delta;
46
+ console.log(
47
+ JSON.stringify({
48
+ type: "admin.audit",
49
+ action: "adjust-stock",
50
+ actor: auth.email,
51
+ targetId: sku,
52
+ delta,
53
+ reason: reason.trim()
54
+ })
55
+ );
56
+ await writeAuditLog(db, {
57
+ entityType: "inventory",
58
+ entityId: sku,
59
+ action: "adjust-stock",
60
+ delta,
61
+ reason: reason.trim(),
62
+ adminEmail: auth.email,
63
+ actor: "human",
64
+ detail: { before: current, after }
65
+ });
66
+ return jsonOk({ ok: true, sku, stock: after, delta });
67
+ };
68
+ }
69
+
70
+ // src/inventory/export.ts
71
+ import { getServerEnv as getServerEnv2 } from "@umec/core/env";
72
+ function createInventoryExportHandler() {
73
+ return async ({ request }) => {
74
+ const auth = await authenticateAdmin(request);
75
+ if (auth instanceof Response) return auth;
76
+ const { DB: db } = getServerEnv2();
77
+ if (!db) return jsonError("DB not available", 503);
78
+ const result = await db.prepare(
79
+ `SELECT inventory.sku AS sku,
80
+ inventory.stock AS stock,
81
+ inventory.updated_at AS updated_at,
82
+ products.name AS name,
83
+ products.low_stock_threshold AS low_stock_threshold
84
+ FROM inventory
85
+ LEFT JOIN products ON products.sku = inventory.sku
86
+ ORDER BY inventory.sku ASC`
87
+ ).all();
88
+ const csv = toCsv(
89
+ ["sku", "name", "stock", "low_stock_threshold", "updated_at"],
90
+ (result.results ?? []).map((row) => [
91
+ row.sku,
92
+ row.name ?? "",
93
+ row.stock,
94
+ row.low_stock_threshold ?? "",
95
+ row.updated_at ?? ""
96
+ ])
97
+ );
98
+ return csvAttachment("inventory.csv", csv);
99
+ };
100
+ }
101
+
102
+ // src/inventory/page.ts
103
+ import { listAuditLog } from "@umec/core/db";
104
+ import { getServerEnv as getServerEnv3 } from "@umec/core/env";
105
+ function formatInventoryDate(value) {
106
+ if (value == null || value === "" || value === 0) return "-";
107
+ const timestamp = typeof value === "string" ? Number(value) : value;
108
+ if (!Number.isFinite(timestamp)) return "-";
109
+ return new Intl.DateTimeFormat("ja-JP", {
110
+ dateStyle: "medium",
111
+ timeStyle: "short",
112
+ timeZone: "Asia/Tokyo"
113
+ }).format(new Date(timestamp));
114
+ }
115
+ function isLowStock(item) {
116
+ return item.low_stock_threshold != null && item.stock <= item.low_stock_threshold;
117
+ }
118
+ async function loadInventoryAdminPage(request) {
119
+ const denied = await requireAdminAuth(request);
120
+ if (denied) return { response: denied };
121
+ const { DB: db } = getServerEnv3();
122
+ let inventory = [];
123
+ let history = [];
124
+ let names = {};
125
+ let dbNotice = "";
126
+ if (db) {
127
+ try {
128
+ const result = await db.prepare(
129
+ `SELECT inventory.sku AS sku,
130
+ inventory.stock AS stock,
131
+ inventory.updated_at AS updated_at,
132
+ products.name AS name,
133
+ products.low_stock_threshold AS low_stock_threshold
134
+ FROM inventory
135
+ LEFT JOIN products ON products.sku = inventory.sku
136
+ ORDER BY inventory.sku ASC`
137
+ ).all();
138
+ inventory = result.results ?? [];
139
+ history = await listAuditLog(db, { entityType: "inventory", limit: 30 });
140
+ names = await loadProductNamesFromDb(db);
141
+ } catch (error) {
142
+ console.error("[admin/inventory] inventory query failed:", error);
143
+ dbNotice = "Inventory could not be loaded.";
144
+ }
145
+ } else {
146
+ dbNotice = "DB binding is not available.";
147
+ }
148
+ return { inventory, history, names, dbNotice };
149
+ }
150
+
151
+ // src/inventory/set-stock.ts
152
+ import { getStock as getStock2, setStock, writeAuditLog as writeAuditLog2 } from "@umec/core/db";
153
+ import { getServerEnv as getServerEnv4 } from "@umec/core/env";
154
+ function createSetStockHandler() {
155
+ return async ({ request }) => {
156
+ const auth = await authenticateAdmin(request);
157
+ if (auth instanceof Response) return auth;
158
+ const payload = await readJsonObject(request);
159
+ if (payload instanceof Response) return payload;
160
+ const { sku, stock } = payload;
161
+ if (typeof sku !== "string") return jsonError("Invalid sku", 400);
162
+ if (typeof stock !== "number" || !Number.isInteger(stock) || stock < 0) {
163
+ return jsonError("Invalid stock", 400);
164
+ }
165
+ const { DB: db } = getServerEnv4();
166
+ if (!db) return jsonError("DB not available", 503);
167
+ const current = (await getStock2(db, [sku])).get(sku);
168
+ if (current === void 0) return jsonError("SKU not found", 404);
169
+ const result = await setStock(db, sku, stock);
170
+ if (result === "not_found") return jsonError("SKU not found", 404);
171
+ console.log(
172
+ JSON.stringify({
173
+ type: "admin.audit",
174
+ action: "set-stock",
175
+ actor: auth.email,
176
+ targetId: sku,
177
+ stock
178
+ })
179
+ );
180
+ await writeAuditLog2(db, {
181
+ entityType: "inventory",
182
+ entityId: sku,
183
+ action: "set-stock",
184
+ adminEmail: auth.email,
185
+ actor: "human",
186
+ detail: { before: current, after: stock }
187
+ });
188
+ return jsonOk({ ok: true });
189
+ };
190
+ }
191
+
192
+ export {
193
+ createAdjustStockHandler,
194
+ createInventoryExportHandler,
195
+ formatInventoryDate,
196
+ isLowStock,
197
+ loadInventoryAdminPage,
198
+ createSetStockHandler
199
+ };
200
+ //# sourceMappingURL=chunk-VUT3UCCR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/inventory/adjust-stock.ts","../src/inventory/export.ts","../src/inventory/page.ts","../src/inventory/set-stock.ts"],"sourcesContent":["import { adjustStock, getStock, MAX_STOCK_DELTA, writeAuditLog } from \"@umec/core/db\";\nimport { getServerEnv } from \"@umec/core/env\";\nimport { authenticateAdmin } from \"../access.js\";\nimport { jsonError, jsonOk, readJsonObject, type AdminApiHandler } from \"../http.js\";\n\nexport function createAdjustStockHandler(): AdminApiHandler {\n return async ({ request }) => {\n const auth = await authenticateAdmin(request);\n if (auth instanceof Response) return auth;\n\n const payload = await readJsonObject(request);\n if (payload instanceof Response) return payload;\n\n const { sku, delta, reason } = payload;\n if (typeof sku !== \"string\" || sku.trim() === \"\") return jsonError(\"Invalid sku\", 400);\n if (typeof delta !== \"number\" || !Number.isInteger(delta) || delta === 0) {\n return jsonError(\"Invalid delta\", 400);\n }\n if (Math.abs(delta) > MAX_STOCK_DELTA) {\n return jsonError(`delta must be between -${MAX_STOCK_DELTA} and ${MAX_STOCK_DELTA}`, 400);\n }\n if (typeof reason !== \"string\" || reason.trim() === \"\") {\n return jsonError(\"reason is required\", 400);\n }\n\n const { DB: db } = getServerEnv();\n if (!db) return jsonError(\"DB not available\", 503);\n\n const current = (await getStock(db, [sku])).get(sku);\n if (current === undefined) return jsonError(\"SKU not found\", 404);\n\n const result = await adjustStock(db, sku, delta);\n if (result === \"not_found\") return jsonError(\"SKU not found\", 404);\n if (result === \"insufficient\") return jsonError(\"Insufficient stock\", 409);\n\n const after = current + delta;\n\n console.log(\n JSON.stringify({\n type: \"admin.audit\",\n action: \"adjust-stock\",\n actor: auth.email,\n targetId: sku,\n delta,\n reason: reason.trim(),\n }),\n );\n\n await writeAuditLog(db, {\n entityType: \"inventory\",\n entityId: sku,\n action: \"adjust-stock\",\n delta,\n reason: reason.trim(),\n adminEmail: auth.email,\n actor: \"human\",\n detail: { before: current, after },\n });\n\n return jsonOk({ ok: true, sku, stock: after, delta });\n };\n}\n","import type { InventoryRow } from \"@umec/core/db\";\nimport { getServerEnv } from \"@umec/core/env\";\nimport { authenticateAdmin } from \"../access.js\";\nimport { csvAttachment, jsonError, type AdminApiHandler } from \"../http.js\";\nimport { toCsv } from \"../csv.js\";\n\ntype InventoryExportRow = Pick<InventoryRow, \"sku\" | \"stock\" | \"updated_at\"> & {\n name: string | null;\n low_stock_threshold: number | null;\n};\n\nexport function createInventoryExportHandler(): AdminApiHandler {\n return async ({ request }) => {\n const auth = await authenticateAdmin(request);\n if (auth instanceof Response) return auth;\n\n const { DB: db } = getServerEnv();\n if (!db) return jsonError(\"DB not available\", 503);\n\n const result = await db\n .prepare(\n `SELECT inventory.sku AS sku,\n inventory.stock AS stock,\n inventory.updated_at AS updated_at,\n products.name AS name,\n products.low_stock_threshold AS low_stock_threshold\n FROM inventory\n LEFT JOIN products ON products.sku = inventory.sku\n ORDER BY inventory.sku ASC`,\n )\n .all<InventoryExportRow>();\n\n const csv = toCsv(\n [\"sku\", \"name\", \"stock\", \"low_stock_threshold\", \"updated_at\"],\n (result.results ?? []).map((row: InventoryExportRow) => [\n row.sku,\n row.name ?? \"\",\n row.stock,\n row.low_stock_threshold ?? \"\",\n row.updated_at ?? \"\",\n ]),\n );\n\n return csvAttachment(\"inventory.csv\", csv);\n };\n}\n","import { listAuditLog, type InventoryRow } from \"@umec/core/db\";\nimport { getServerEnv } from \"@umec/core/env\";\nimport { requireAdminAuth } from \"../access.js\";\nimport { loadProductNamesFromDb } from \"../products.js\";\n\nexport type InventoryListRow = InventoryRow & {\n name: string | null;\n low_stock_threshold: number | null;\n};\n\nexport type InventoryAdminPageData = {\n inventory: InventoryListRow[];\n history: Awaited<ReturnType<typeof listAuditLog>>;\n names: Record<string, string>;\n dbNotice: string;\n};\n\nexport type InventoryAdminPageLoad = { response: Response } | InventoryAdminPageData;\n\nexport function formatInventoryDate(value: number | string | null) {\n if (value == null || value === \"\" || value === 0) return \"-\";\n const timestamp = typeof value === \"string\" ? Number(value) : value;\n if (!Number.isFinite(timestamp)) return \"-\";\n\n return new Intl.DateTimeFormat(\"ja-JP\", {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n timeZone: \"Asia/Tokyo\",\n }).format(new Date(timestamp));\n}\n\nexport function isLowStock(item: InventoryListRow) {\n return item.low_stock_threshold != null && item.stock <= item.low_stock_threshold;\n}\n\nexport async function loadInventoryAdminPage(request: Request): Promise<InventoryAdminPageLoad> {\n const denied = await requireAdminAuth(request);\n if (denied) return { response: denied };\n\n const { DB: db } = getServerEnv();\n let inventory: InventoryListRow[] = [];\n let history: Awaited<ReturnType<typeof listAuditLog>> = [];\n let names: Record<string, string> = {};\n let dbNotice = \"\";\n\n if (db) {\n try {\n const result = await db\n .prepare(\n `SELECT inventory.sku AS sku,\n inventory.stock AS stock,\n inventory.updated_at AS updated_at,\n products.name AS name,\n products.low_stock_threshold AS low_stock_threshold\n FROM inventory\n LEFT JOIN products ON products.sku = inventory.sku\n ORDER BY inventory.sku ASC`,\n )\n .all<InventoryListRow>();\n inventory = result.results ?? [];\n history = await listAuditLog(db, { entityType: \"inventory\", limit: 30 });\n names = await loadProductNamesFromDb(db);\n } catch (error) {\n console.error(\"[admin/inventory] inventory query failed:\", error);\n dbNotice = \"Inventory could not be loaded.\";\n }\n } else {\n dbNotice = \"DB binding is not available.\";\n }\n\n return { inventory, history, names, dbNotice };\n}\n","import { getStock, setStock, writeAuditLog } from \"@umec/core/db\";\nimport { getServerEnv } from \"@umec/core/env\";\nimport { authenticateAdmin } from \"../access.js\";\nimport { jsonError, jsonOk, readJsonObject, type AdminApiHandler } from \"../http.js\";\n\nexport function createSetStockHandler(): AdminApiHandler {\n return async ({ request }) => {\n const auth = await authenticateAdmin(request);\n if (auth instanceof Response) return auth;\n\n const payload = await readJsonObject(request);\n if (payload instanceof Response) return payload;\n\n const { sku, stock } = payload;\n if (typeof sku !== \"string\") return jsonError(\"Invalid sku\", 400);\n if (typeof stock !== \"number\" || !Number.isInteger(stock) || stock < 0) {\n return jsonError(\"Invalid stock\", 400);\n }\n\n const { DB: db } = getServerEnv();\n if (!db) return jsonError(\"DB not available\", 503);\n\n const current = (await getStock(db, [sku])).get(sku);\n if (current === undefined) return jsonError(\"SKU not found\", 404);\n\n const result = await setStock(db, sku, stock);\n if (result === \"not_found\") return jsonError(\"SKU not found\", 404);\n\n console.log(\n JSON.stringify({\n type: \"admin.audit\",\n action: \"set-stock\",\n actor: auth.email,\n targetId: sku,\n stock,\n }),\n );\n\n await writeAuditLog(db, {\n entityType: \"inventory\",\n entityId: sku,\n action: \"set-stock\",\n adminEmail: auth.email,\n actor: \"human\",\n detail: { before: current, after: stock },\n });\n\n return jsonOk({ ok: true });\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA,SAAS,aAAa,UAAU,iBAAiB,qBAAqB;AACtE,SAAS,oBAAoB;AAItB,SAAS,2BAA4C;AAC1D,SAAO,OAAO,EAAE,QAAQ,MAAM;AAC5B,UAAM,OAAO,MAAM,kBAAkB,OAAO;AAC5C,QAAI,gBAAgB,SAAU,QAAO;AAErC,UAAM,UAAU,MAAM,eAAe,OAAO;AAC5C,QAAI,mBAAmB,SAAU,QAAO;AAExC,UAAM,EAAE,KAAK,OAAO,OAAO,IAAI;AAC/B,QAAI,OAAO,QAAQ,YAAY,IAAI,KAAK,MAAM,GAAI,QAAO,UAAU,eAAe,GAAG;AACrF,QAAI,OAAO,UAAU,YAAY,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,GAAG;AACxE,aAAO,UAAU,iBAAiB,GAAG;AAAA,IACvC;AACA,QAAI,KAAK,IAAI,KAAK,IAAI,iBAAiB;AACrC,aAAO,UAAU,0BAA0B,eAAe,QAAQ,eAAe,IAAI,GAAG;AAAA,IAC1F;AACA,QAAI,OAAO,WAAW,YAAY,OAAO,KAAK,MAAM,IAAI;AACtD,aAAO,UAAU,sBAAsB,GAAG;AAAA,IAC5C;AAEA,UAAM,EAAE,IAAI,GAAG,IAAI,aAAa;AAChC,QAAI,CAAC,GAAI,QAAO,UAAU,oBAAoB,GAAG;AAEjD,UAAM,WAAW,MAAM,SAAS,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG;AACnD,QAAI,YAAY,OAAW,QAAO,UAAU,iBAAiB,GAAG;AAEhE,UAAM,SAAS,MAAM,YAAY,IAAI,KAAK,KAAK;AAC/C,QAAI,WAAW,YAAa,QAAO,UAAU,iBAAiB,GAAG;AACjE,QAAI,WAAW,eAAgB,QAAO,UAAU,sBAAsB,GAAG;AAEzE,UAAM,QAAQ,UAAU;AAExB,YAAQ;AAAA,MACN,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,OAAO,KAAK;AAAA,QACZ,UAAU;AAAA,QACV;AAAA,QACA,QAAQ,OAAO,KAAK;AAAA,MACtB,CAAC;AAAA,IACH;AAEA,UAAM,cAAc,IAAI;AAAA,MACtB,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,QAAQ;AAAA,MACR;AAAA,MACA,QAAQ,OAAO,KAAK;AAAA,MACpB,YAAY,KAAK;AAAA,MACjB,OAAO;AAAA,MACP,QAAQ,EAAE,QAAQ,SAAS,MAAM;AAAA,IACnC,CAAC;AAED,WAAO,OAAO,EAAE,IAAI,MAAM,KAAK,OAAO,OAAO,MAAM,CAAC;AAAA,EACtD;AACF;;;AC5DA,SAAS,gBAAAA,qBAAoB;AAUtB,SAAS,+BAAgD;AAC9D,SAAO,OAAO,EAAE,QAAQ,MAAM;AAC5B,UAAM,OAAO,MAAM,kBAAkB,OAAO;AAC5C,QAAI,gBAAgB,SAAU,QAAO;AAErC,UAAM,EAAE,IAAI,GAAG,IAAIC,cAAa;AAChC,QAAI,CAAC,GAAI,QAAO,UAAU,oBAAoB,GAAG;AAEjD,UAAM,SAAS,MAAM,GAClB;AAAA,MACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQF,EACC,IAAwB;AAE3B,UAAM,MAAM;AAAA,MACV,CAAC,OAAO,QAAQ,SAAS,uBAAuB,YAAY;AAAA,OAC3D,OAAO,WAAW,CAAC,GAAG,IAAI,CAAC,QAA4B;AAAA,QACtD,IAAI;AAAA,QACJ,IAAI,QAAQ;AAAA,QACZ,IAAI;AAAA,QACJ,IAAI,uBAAuB;AAAA,QAC3B,IAAI,cAAc;AAAA,MACpB,CAAC;AAAA,IACH;AAEA,WAAO,cAAc,iBAAiB,GAAG;AAAA,EAC3C;AACF;;;AC7CA,SAAS,oBAAuC;AAChD,SAAS,gBAAAC,qBAAoB;AAkBtB,SAAS,oBAAoB,OAA+B;AACjE,MAAI,SAAS,QAAQ,UAAU,MAAM,UAAU,EAAG,QAAO;AACzD,QAAM,YAAY,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI;AAC9D,MAAI,CAAC,OAAO,SAAS,SAAS,EAAG,QAAO;AAExC,SAAO,IAAI,KAAK,eAAe,SAAS;AAAA,IACtC,WAAW;AAAA,IACX,WAAW;AAAA,IACX,UAAU;AAAA,EACZ,CAAC,EAAE,OAAO,IAAI,KAAK,SAAS,CAAC;AAC/B;AAEO,SAAS,WAAW,MAAwB;AACjD,SAAO,KAAK,uBAAuB,QAAQ,KAAK,SAAS,KAAK;AAChE;AAEA,eAAsB,uBAAuB,SAAmD;AAC9F,QAAM,SAAS,MAAM,iBAAiB,OAAO;AAC7C,MAAI,OAAQ,QAAO,EAAE,UAAU,OAAO;AAEtC,QAAM,EAAE,IAAI,GAAG,IAAIC,cAAa;AAChC,MAAI,YAAgC,CAAC;AACrC,MAAI,UAAoD,CAAC;AACzD,MAAI,QAAgC,CAAC;AACrC,MAAI,WAAW;AAEf,MAAI,IAAI;AACN,QAAI;AACF,YAAM,SAAS,MAAM,GAClB;AAAA,QACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQF,EACC,IAAsB;AACzB,kBAAY,OAAO,WAAW,CAAC;AAC/B,gBAAU,MAAM,aAAa,IAAI,EAAE,YAAY,aAAa,OAAO,GAAG,CAAC;AACvE,cAAQ,MAAM,uBAAuB,EAAE;AAAA,IACzC,SAAS,OAAO;AACd,cAAQ,MAAM,6CAA6C,KAAK;AAChE,iBAAW;AAAA,IACb;AAAA,EACF,OAAO;AACL,eAAW;AAAA,EACb;AAEA,SAAO,EAAE,WAAW,SAAS,OAAO,SAAS;AAC/C;;;ACvEA,SAAS,YAAAC,WAAU,UAAU,iBAAAC,sBAAqB;AAClD,SAAS,gBAAAC,qBAAoB;AAItB,SAAS,wBAAyC;AACvD,SAAO,OAAO,EAAE,QAAQ,MAAM;AAC5B,UAAM,OAAO,MAAM,kBAAkB,OAAO;AAC5C,QAAI,gBAAgB,SAAU,QAAO;AAErC,UAAM,UAAU,MAAM,eAAe,OAAO;AAC5C,QAAI,mBAAmB,SAAU,QAAO;AAExC,UAAM,EAAE,KAAK,MAAM,IAAI;AACvB,QAAI,OAAO,QAAQ,SAAU,QAAO,UAAU,eAAe,GAAG;AAChE,QAAI,OAAO,UAAU,YAAY,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GAAG;AACtE,aAAO,UAAU,iBAAiB,GAAG;AAAA,IACvC;AAEA,UAAM,EAAE,IAAI,GAAG,IAAIC,cAAa;AAChC,QAAI,CAAC,GAAI,QAAO,UAAU,oBAAoB,GAAG;AAEjD,UAAM,WAAW,MAAMC,UAAS,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG;AACnD,QAAI,YAAY,OAAW,QAAO,UAAU,iBAAiB,GAAG;AAEhE,UAAM,SAAS,MAAM,SAAS,IAAI,KAAK,KAAK;AAC5C,QAAI,WAAW,YAAa,QAAO,UAAU,iBAAiB,GAAG;AAEjE,YAAQ;AAAA,MACN,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,OAAO,KAAK;AAAA,QACZ,UAAU;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAMC,eAAc,IAAI;AAAA,MACtB,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,YAAY,KAAK;AAAA,MACjB,OAAO;AAAA,MACP,QAAQ,EAAE,QAAQ,SAAS,OAAO,MAAM;AAAA,IAC1C,CAAC;AAED,WAAO,OAAO,EAAE,IAAI,KAAK,CAAC;AAAA,EAC5B;AACF;","names":["getServerEnv","getServerEnv","getServerEnv","getServerEnv","getStock","writeAuditLog","getServerEnv","getServerEnv","getStock","writeAuditLog"]}
@@ -0,0 +1,57 @@
1
+ // src/access.ts
2
+ import { createAccessGuard } from "@umec/core/access";
3
+ import { getServerEnv } from "@umec/core/env";
4
+ var cachedConfig = null;
5
+ var cachedGuard = null;
6
+ function jsonError(error, status) {
7
+ return new Response(JSON.stringify({ error }), {
8
+ status,
9
+ headers: {
10
+ "Content-Type": "application/json",
11
+ "Cache-Control": "no-store"
12
+ }
13
+ });
14
+ }
15
+ function forbidden() {
16
+ return new Response("Forbidden", {
17
+ status: 403,
18
+ headers: { "Cache-Control": "no-store" }
19
+ });
20
+ }
21
+ function getAccessGuard(teamDomain, aud) {
22
+ if (cachedGuard && cachedConfig?.teamDomain === teamDomain && cachedConfig.aud === aud) {
23
+ return cachedGuard;
24
+ }
25
+ cachedConfig = { teamDomain, aud };
26
+ cachedGuard = createAccessGuard({ teamDomain, aud });
27
+ return cachedGuard;
28
+ }
29
+ function emailFromPayload(payload) {
30
+ const email = "email" in payload ? payload.email : void 0;
31
+ return typeof email === "string" ? email.trim() : "";
32
+ }
33
+ async function authenticateAdmin(request) {
34
+ const { ACCESS_TEAM_DOMAIN: teamDomain, ACCESS_AUD: aud } = getServerEnv();
35
+ if (!teamDomain || !aud) {
36
+ return jsonError("Access not configured", 503);
37
+ }
38
+ const result = await getAccessGuard(teamDomain, aud)(request);
39
+ if (!result.ok) {
40
+ return forbidden();
41
+ }
42
+ const email = emailFromPayload(result.payload);
43
+ if (!email) {
44
+ return forbidden();
45
+ }
46
+ return { email };
47
+ }
48
+ async function requireAdminAuth(request) {
49
+ const result = await authenticateAdmin(request);
50
+ return result instanceof Response ? result : null;
51
+ }
52
+
53
+ export {
54
+ authenticateAdmin,
55
+ requireAdminAuth
56
+ };
57
+ //# sourceMappingURL=chunk-W2O6EQWT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/access.ts"],"sourcesContent":["import { createAccessGuard } from \"@umec/core/access\";\nimport { getServerEnv } from \"@umec/core/env\";\n\nexport type AdminIdentity = {\n email: string;\n};\n\ntype AdminAccessGuard = ReturnType<typeof createAccessGuard>;\n\nlet cachedConfig: { teamDomain: string; aud: string } | null = null;\nlet cachedGuard: AdminAccessGuard | null = null;\n\nfunction jsonError(error: string, status: number) {\n return new Response(JSON.stringify({ error }), {\n status,\n headers: {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": \"no-store\",\n },\n });\n}\n\nfunction forbidden() {\n return new Response(\"Forbidden\", {\n status: 403,\n headers: { \"Cache-Control\": \"no-store\" },\n });\n}\n\nfunction getAccessGuard(teamDomain: string, aud: string) {\n if (\n cachedGuard &&\n cachedConfig?.teamDomain === teamDomain &&\n cachedConfig.aud === aud\n ) {\n return cachedGuard;\n }\n\n cachedConfig = { teamDomain, aud };\n cachedGuard = createAccessGuard({ teamDomain, aud });\n return cachedGuard;\n}\n\nfunction emailFromPayload(payload: { email?: unknown } | Record<string, unknown>): string {\n const email = \"email\" in payload ? payload.email : undefined;\n return typeof email === \"string\" ? email.trim() : \"\";\n}\n\nexport async function authenticateAdmin(\n request: Request,\n): Promise<AdminIdentity | Response> {\n const { ACCESS_TEAM_DOMAIN: teamDomain, ACCESS_AUD: aud } = getServerEnv();\n\n if (!teamDomain || !aud) {\n return jsonError(\"Access not configured\", 503);\n }\n\n const result = await getAccessGuard(teamDomain, aud)(request);\n if (!result.ok) {\n return forbidden();\n }\n\n const email = emailFromPayload(result.payload);\n if (!email) {\n return forbidden();\n }\n\n return { email };\n}\n\nexport async function requireAdminAuth(request: Request): Promise<Response | null> {\n const result = await authenticateAdmin(request);\n return result instanceof Response ? result : null;\n}\n"],"mappings":";AAAA,SAAS,yBAAyB;AAClC,SAAS,oBAAoB;AAQ7B,IAAI,eAA2D;AAC/D,IAAI,cAAuC;AAE3C,SAAS,UAAU,OAAe,QAAgB;AAChD,SAAO,IAAI,SAAS,KAAK,UAAU,EAAE,MAAM,CAAC,GAAG;AAAA,IAC7C;AAAA,IACA,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,IACnB;AAAA,EACF,CAAC;AACH;AAEA,SAAS,YAAY;AACnB,SAAO,IAAI,SAAS,aAAa;AAAA,IAC/B,QAAQ;AAAA,IACR,SAAS,EAAE,iBAAiB,WAAW;AAAA,EACzC,CAAC;AACH;AAEA,SAAS,eAAe,YAAoB,KAAa;AACvD,MACE,eACA,cAAc,eAAe,cAC7B,aAAa,QAAQ,KACrB;AACA,WAAO;AAAA,EACT;AAEA,iBAAe,EAAE,YAAY,IAAI;AACjC,gBAAc,kBAAkB,EAAE,YAAY,IAAI,CAAC;AACnD,SAAO;AACT;AAEA,SAAS,iBAAiB,SAAgE;AACxF,QAAM,QAAQ,WAAW,UAAU,QAAQ,QAAQ;AACnD,SAAO,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;AACpD;AAEA,eAAsB,kBACpB,SACmC;AACnC,QAAM,EAAE,oBAAoB,YAAY,YAAY,IAAI,IAAI,aAAa;AAEzE,MAAI,CAAC,cAAc,CAAC,KAAK;AACvB,WAAO,UAAU,yBAAyB,GAAG;AAAA,EAC/C;AAEA,QAAM,SAAS,MAAM,eAAe,YAAY,GAAG,EAAE,OAAO;AAC5D,MAAI,CAAC,OAAO,IAAI;AACd,WAAO,UAAU;AAAA,EACnB;AAEA,QAAM,QAAQ,iBAAiB,OAAO,OAAO;AAC7C,MAAI,CAAC,OAAO;AACV,WAAO,UAAU;AAAA,EACnB;AAEA,SAAO,EAAE,MAAM;AACjB;AAEA,eAAsB,iBAAiB,SAA4C;AACjF,QAAM,SAAS,MAAM,kBAAkB,OAAO;AAC9C,SAAO,kBAAkB,WAAW,SAAS;AAC/C;","names":[]}
@@ -0,0 +1,129 @@
1
+ // src/products.ts
2
+ import { listProductRows } from "@umec/core/db";
3
+ import { getProductRow, listProductRows as listProductRows2 } from "@umec/core/db";
4
+ var SKU_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
5
+ var GTIN_PATTERN = /^(?:\d{8}|\d{12}|\d{13}|\d{14})$/;
6
+ function isValidSku(value) {
7
+ return typeof value === "string" && SKU_PATTERN.test(value);
8
+ }
9
+ function isValidGtin(value) {
10
+ return GTIN_PATTERN.test(value);
11
+ }
12
+ function parseImagesJson(value) {
13
+ if (!value) return [];
14
+ try {
15
+ const parsed = JSON.parse(value);
16
+ if (!Array.isArray(parsed)) return [];
17
+ return parsed.filter((item) => typeof item === "string" && item.trim() !== "");
18
+ } catch {
19
+ return [];
20
+ }
21
+ }
22
+ function parseProductImages(value) {
23
+ if (value === void 0 || value === null || value === "") return [];
24
+ if (typeof value === "string") {
25
+ const trimmed = value.trim();
26
+ if (!trimmed) return [];
27
+ try {
28
+ const parsed = JSON.parse(trimmed);
29
+ return parseProductImages(parsed);
30
+ } catch {
31
+ return trimmed.split(/[\n,]/).map((item) => item.trim()).filter(Boolean);
32
+ }
33
+ }
34
+ if (!Array.isArray(value)) return { error: "Invalid images" };
35
+ if (!value.every((item) => typeof item === "string")) return { error: "Invalid images" };
36
+ return value.map((item) => item.trim()).filter(Boolean);
37
+ }
38
+ function rowToStorefrontProduct(row) {
39
+ return {
40
+ sku: row.sku,
41
+ name: row.name,
42
+ description: row.description ?? "",
43
+ price: row.price,
44
+ shippingUnits: row.shipping_units,
45
+ images: parseImagesJson(row.images_json),
46
+ active: row.active === 1,
47
+ gtin: row.gtin,
48
+ category: row.category,
49
+ lowStockThreshold: row.low_stock_threshold
50
+ };
51
+ }
52
+ function toCheckoutProduct(product) {
53
+ return {
54
+ name: product.name,
55
+ price: product.price,
56
+ description: product.description || void 0,
57
+ active: product.active,
58
+ shippingUnits: product.shippingUnits,
59
+ images: product.images.length > 0 ? product.images : void 0
60
+ };
61
+ }
62
+ function catalogFromConfig(config) {
63
+ const PRODUCTS = Object.entries(config.products).map(([sku, product]) => ({
64
+ sku,
65
+ ...product,
66
+ description: product.description ?? "",
67
+ images: product.images ?? []
68
+ })).filter((product) => product.active);
69
+ const PRODUCTS_MAP = Object.fromEntries(PRODUCTS.map((product) => [product.sku, product]));
70
+ return { PRODUCTS, PRODUCTS_MAP };
71
+ }
72
+ async function loadProductNamesFromDb(db) {
73
+ const rows = await listProductRows(db, { includeInactive: true });
74
+ return Object.fromEntries(rows.map((row) => [row.sku, row.name]));
75
+ }
76
+ function createProductLoader(config) {
77
+ function storefrontProductsFromConfig() {
78
+ return Object.entries(config.products).map(([sku, product]) => ({
79
+ sku,
80
+ name: product.name,
81
+ description: product.description ?? "",
82
+ price: product.price,
83
+ shippingUnits: product.shippingUnits,
84
+ images: product.images ?? [],
85
+ active: product.active,
86
+ gtin: null,
87
+ category: null,
88
+ lowStockThreshold: null
89
+ })).filter((product) => product.active);
90
+ }
91
+ async function loadStorefrontProducts(db) {
92
+ if (!db) return storefrontProductsFromConfig();
93
+ const rows = await listProductRows(db, { includeInactive: false });
94
+ return rows.map(rowToStorefrontProduct);
95
+ }
96
+ async function loadCheckoutProducts(db) {
97
+ const products = await loadStorefrontProducts(db);
98
+ return Object.fromEntries(products.map((product) => [product.sku, toCheckoutProduct(product)]));
99
+ }
100
+ async function loadProductNames(db) {
101
+ if (!db) {
102
+ return Object.fromEntries(
103
+ Object.entries(config.products).map(([sku, product]) => [sku, product.name])
104
+ );
105
+ }
106
+ return loadProductNamesFromDb(db);
107
+ }
108
+ return {
109
+ storefrontProductsFromConfig,
110
+ loadStorefrontProducts,
111
+ loadCheckoutProducts,
112
+ loadProductNames
113
+ };
114
+ }
115
+
116
+ export {
117
+ isValidSku,
118
+ isValidGtin,
119
+ parseImagesJson,
120
+ parseProductImages,
121
+ rowToStorefrontProduct,
122
+ toCheckoutProduct,
123
+ catalogFromConfig,
124
+ loadProductNamesFromDb,
125
+ createProductLoader,
126
+ getProductRow,
127
+ listProductRows2 as listProductRows
128
+ };
129
+ //# sourceMappingURL=chunk-ZEA6G75Z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/products.ts"],"sourcesContent":["import type { CheckoutProductsMap } from \"@umec/core/checkout\";\nimport type { UmecProduct } from \"@umec/core/config\";\nimport { listProductRows, type ProductsRow, type ShopDatabase } from \"@umec/core/db\";\n\nexport type { ProductsRow };\nexport type ProductRow = ProductsRow;\nexport { getProductRow, listProductRows } from \"@umec/core/db\";\n\nexport type StorefrontProduct = {\n sku: string;\n name: string;\n description: string;\n price: number;\n shippingUnits: number;\n images: string[];\n active: boolean;\n gtin: string | null;\n category: string | null;\n lowStockThreshold: number | null;\n};\n\nexport type ConfigProduct = Omit<UmecProduct, \"description\" | \"images\"> & {\n sku: string;\n description: string;\n images: string[];\n};\n\nexport type ProductLoaderConfig = {\n products: Record<string, UmecProduct>;\n};\n\nconst SKU_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;\nconst GTIN_PATTERN = /^(?:\\d{8}|\\d{12}|\\d{13}|\\d{14})$/;\n\nexport function isValidSku(value: unknown): value is string {\n return typeof value === \"string\" && SKU_PATTERN.test(value);\n}\n\nexport function isValidGtin(value: string): boolean {\n return GTIN_PATTERN.test(value);\n}\n\nexport function parseImagesJson(value: string | null | undefined): string[] {\n if (!value) return [];\n try {\n const parsed: unknown = JSON.parse(value);\n if (!Array.isArray(parsed)) return [];\n return parsed.filter((item): item is string => typeof item === \"string\" && item.trim() !== \"\");\n } catch {\n return [];\n }\n}\n\nexport function parseProductImages(value: unknown): string[] | { error: string } {\n if (value === undefined || value === null || value === \"\") return [];\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (!trimmed) return [];\n try {\n const parsed: unknown = JSON.parse(trimmed);\n return parseProductImages(parsed);\n } catch {\n return trimmed\n .split(/[\\n,]/)\n .map((item) => item.trim())\n .filter(Boolean);\n }\n }\n if (!Array.isArray(value)) return { error: \"Invalid images\" };\n if (!value.every((item) => typeof item === \"string\")) return { error: \"Invalid images\" };\n return value.map((item) => item.trim()).filter(Boolean);\n}\n\nexport function rowToStorefrontProduct(row: ProductsRow): StorefrontProduct {\n return {\n sku: row.sku,\n name: row.name,\n description: row.description ?? \"\",\n price: row.price,\n shippingUnits: row.shipping_units,\n images: parseImagesJson(row.images_json),\n active: row.active === 1,\n gtin: row.gtin,\n category: row.category,\n lowStockThreshold: row.low_stock_threshold,\n };\n}\n\nexport function toCheckoutProduct(product: StorefrontProduct): UmecProduct {\n return {\n name: product.name,\n price: product.price,\n description: product.description || undefined,\n active: product.active,\n shippingUnits: product.shippingUnits,\n images: product.images.length > 0 ? product.images : undefined,\n };\n}\n\nexport function catalogFromConfig(config: ProductLoaderConfig): {\n PRODUCTS: ConfigProduct[];\n PRODUCTS_MAP: Record<string, ConfigProduct>;\n} {\n const PRODUCTS = Object.entries(config.products)\n .map(([sku, product]) => ({\n sku,\n ...product,\n description: product.description ?? \"\",\n images: product.images ?? [],\n }))\n .filter((product) => product.active);\n const PRODUCTS_MAP = Object.fromEntries(PRODUCTS.map((product) => [product.sku, product]));\n return { PRODUCTS, PRODUCTS_MAP };\n}\n\nexport async function loadProductNamesFromDb(db: ShopDatabase): Promise<Record<string, string>> {\n const rows = await listProductRows(db, { includeInactive: true });\n return Object.fromEntries(rows.map((row) => [row.sku, row.name]));\n}\n\nexport function createProductLoader(config: ProductLoaderConfig) {\n function storefrontProductsFromConfig(): StorefrontProduct[] {\n return Object.entries(config.products)\n .map(([sku, product]) => ({\n sku,\n name: product.name,\n description: product.description ?? \"\",\n price: product.price,\n shippingUnits: product.shippingUnits,\n images: product.images ?? [],\n active: product.active,\n gtin: null,\n category: null,\n lowStockThreshold: null,\n }))\n .filter((product) => product.active);\n }\n\n async function loadStorefrontProducts(db: ShopDatabase | undefined): Promise<StorefrontProduct[]> {\n if (!db) return storefrontProductsFromConfig();\n const rows = await listProductRows(db, { includeInactive: false });\n return rows.map(rowToStorefrontProduct);\n }\n\n async function loadCheckoutProducts(db: ShopDatabase | undefined): Promise<CheckoutProductsMap> {\n const products = await loadStorefrontProducts(db);\n return Object.fromEntries(products.map((product) => [product.sku, toCheckoutProduct(product)]));\n }\n\n async function loadProductNames(db: ShopDatabase | undefined): Promise<Record<string, string>> {\n if (!db) {\n return Object.fromEntries(\n Object.entries(config.products).map(([sku, product]) => [sku, product.name]),\n );\n }\n\n return loadProductNamesFromDb(db);\n }\n\n return {\n storefrontProductsFromConfig,\n loadStorefrontProducts,\n loadCheckoutProducts,\n loadProductNames,\n };\n}\n"],"mappings":"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","names":["listProductRows"]}
package/dist/csv.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ declare function csvEscape(value: unknown): string;
2
+ declare function toCsv(headers: string[], rows: unknown[][]): string;
3
+
4
+ export { csvEscape, toCsv };
package/dist/csv.js ADDED
@@ -0,0 +1,9 @@
1
+ import {
2
+ csvEscape,
3
+ toCsv
4
+ } from "./chunk-TKJ6KSXM.js";
5
+ export {
6
+ csvEscape,
7
+ toCsv
8
+ };
9
+ //# sourceMappingURL=csv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/http.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ type AdminApiHandler = (context: {
2
+ request: Request;
3
+ }) => Promise<Response>;
4
+ declare const NO_STORE_JSON: {
5
+ readonly "Content-Type": "application/json";
6
+ readonly "Cache-Control": "no-store";
7
+ };
8
+ declare const NO_STORE_CSV: {
9
+ readonly "Content-Type": "text/csv; charset=utf-8";
10
+ readonly "Cache-Control": "no-store";
11
+ };
12
+ declare function jsonError(error: string, status: number): Response;
13
+ declare function jsonOk(body?: unknown, status?: number): Response;
14
+ declare function readJsonObject(request: Request): Promise<Record<string, unknown> | Response>;
15
+ declare function csvAttachment(filename: string, body: string): Response;
16
+
17
+ export { type AdminApiHandler, NO_STORE_CSV, NO_STORE_JSON, csvAttachment, jsonError, jsonOk, readJsonObject };
package/dist/http.js ADDED
@@ -0,0 +1,17 @@
1
+ import {
2
+ NO_STORE_CSV,
3
+ NO_STORE_JSON,
4
+ csvAttachment,
5
+ jsonError,
6
+ jsonOk,
7
+ readJsonObject
8
+ } from "./chunk-E7ATMICY.js";
9
+ export {
10
+ NO_STORE_CSV,
11
+ NO_STORE_JSON,
12
+ csvAttachment,
13
+ jsonError,
14
+ jsonOk,
15
+ readJsonObject
16
+ };
17
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,16 @@
1
+ export { AdminIdentity, authenticateAdmin, requireAdminAuth } from './access.js';
2
+ export { CARRIERS, CARRIER_LABELS, Carrier, isCarrier, parseOptionalCarrier } from './carriers.js';
3
+ export { CatalogAdminPageData, CatalogAdminPageLoad, ProductListRow, createCreateProductHandler, createDiscontinueProductHandler, createUpdateProductHandler, formatYen as formatCatalogYen, imagesText, loadCatalogAdminPage } from './catalog/index.js';
4
+ export { csvEscape, toCsv } from './csv.js';
5
+ export { AdminApiHandler, NO_STORE_CSV, NO_STORE_JSON, csvAttachment, jsonError, jsonOk, readJsonObject } from './http.js';
6
+ export { InventoryAdminPageData, InventoryAdminPageLoad, InventoryListRow, createAdjustStockHandler, createInventoryExportHandler, createSetStockHandler, formatInventoryDate, isLowStock, loadInventoryAdminPage } from './inventory/index.js';
7
+ export { SAMPLE_FREE_SHIPPING_OFFER_SLUG, createResolveCheckoutOffer } from './offers.js';
8
+ export { CheckoutItem, MAX_BULK_SHIP, OrdersAdminPageData, OrdersAdminPageLoad, ShippingAddress, carrierLabel, createMarkShippedBulkHandler, createMarkShippedHandler, createOrdersExportHandler, createUpdateTrackingHandler, formatCustomFields, formatOrderAddress, formatOrderDate, formatOrderItems, formatYen, loadOrdersAdminPage } from './orders/index.js';
9
+ export { FieldError, isFieldError, parseCreateProductFields, parseSku, parseUpdateProductFields } from './product-fields.js';
10
+ export { ConfigProduct, ProductLoaderConfig, ProductRow, StorefrontProduct, catalogFromConfig, createProductLoader, isValidGtin, isValidSku, loadProductNamesFromDb, parseImagesJson, parseProductImages, rowToStorefrontProduct, toCheckoutProduct } from './products.js';
11
+ export { AlertEnv, DEFAULT_ALERT_DAYS_THRESHOLD, UnshippedAlertConfig, createUnshippedAlerter, parseAlertDaysThreshold } from './unshipped-alert.js';
12
+ export { ProductWriteFields, ProductsRow, getProductRow, listProductRows } from '@umec/core/db';
13
+ import '@umec/core/checkout';
14
+ import '@umec/core/config';
15
+ import '@umec/core/notify';
16
+ import '@umec/core/env';