@endora-commerce/contracts 0.100.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 (327) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -0
  3. package/dist/actor.d.ts +79 -0
  4. package/dist/actor.d.ts.map +1 -0
  5. package/dist/actor.js +41 -0
  6. package/dist/actor.js.map +1 -0
  7. package/dist/addresses.d.ts +134 -0
  8. package/dist/addresses.d.ts.map +1 -0
  9. package/dist/addresses.js +16 -0
  10. package/dist/addresses.js.map +1 -0
  11. package/dist/admin-actions.d.ts +367 -0
  12. package/dist/admin-actions.d.ts.map +1 -0
  13. package/dist/admin-actions.js +287 -0
  14. package/dist/admin-actions.js.map +1 -0
  15. package/dist/admin-contributions.d.ts +518 -0
  16. package/dist/admin-contributions.d.ts.map +1 -0
  17. package/dist/admin-contributions.js +495 -0
  18. package/dist/admin-contributions.js.map +1 -0
  19. package/dist/admin-i18n.d.ts +135 -0
  20. package/dist/admin-i18n.d.ts.map +1 -0
  21. package/dist/admin-i18n.js +72 -0
  22. package/dist/admin-i18n.js.map +1 -0
  23. package/dist/admin-notifications.d.ts +55 -0
  24. package/dist/admin-notifications.d.ts.map +1 -0
  25. package/dist/admin-notifications.js +16 -0
  26. package/dist/admin-notifications.js.map +1 -0
  27. package/dist/admin-roles.d.ts +125 -0
  28. package/dist/admin-roles.d.ts.map +1 -0
  29. package/dist/admin-roles.js +2 -0
  30. package/dist/admin-roles.js.map +1 -0
  31. package/dist/admin-users.d.ts +178 -0
  32. package/dist/admin-users.d.ts.map +1 -0
  33. package/dist/admin-users.js +14 -0
  34. package/dist/admin-users.js.map +1 -0
  35. package/dist/admin.d.ts +243 -0
  36. package/dist/admin.d.ts.map +1 -0
  37. package/dist/admin.js +246 -0
  38. package/dist/admin.js.map +1 -0
  39. package/dist/analytics.d.ts +123 -0
  40. package/dist/analytics.d.ts.map +1 -0
  41. package/dist/analytics.js +68 -0
  42. package/dist/analytics.js.map +1 -0
  43. package/dist/api-keys.d.ts +97 -0
  44. package/dist/api-keys.d.ts.map +1 -0
  45. package/dist/api-keys.js +64 -0
  46. package/dist/api-keys.js.map +1 -0
  47. package/dist/assets-library.d.ts +684 -0
  48. package/dist/assets-library.d.ts.map +1 -0
  49. package/dist/assets-library.js +181 -0
  50. package/dist/assets-library.js.map +1 -0
  51. package/dist/audit-logs.d.ts +141 -0
  52. package/dist/audit-logs.d.ts.map +1 -0
  53. package/dist/audit-logs.js +31 -0
  54. package/dist/audit-logs.js.map +1 -0
  55. package/dist/auth.d.ts +174 -0
  56. package/dist/auth.d.ts.map +1 -0
  57. package/dist/auth.js +27 -0
  58. package/dist/auth.js.map +1 -0
  59. package/dist/blog.d.ts +669 -0
  60. package/dist/blog.d.ts.map +1 -0
  61. package/dist/blog.js +360 -0
  62. package/dist/blog.js.map +1 -0
  63. package/dist/capabilities.d.ts +40 -0
  64. package/dist/capabilities.d.ts.map +1 -0
  65. package/dist/capabilities.js +38 -0
  66. package/dist/capabilities.js.map +1 -0
  67. package/dist/carts.d.ts +1367 -0
  68. package/dist/carts.d.ts.map +1 -0
  69. package/dist/carts.js +405 -0
  70. package/dist/carts.js.map +1 -0
  71. package/dist/catalog.d.ts +2855 -0
  72. package/dist/catalog.d.ts.map +1 -0
  73. package/dist/catalog.js +1543 -0
  74. package/dist/catalog.js.map +1 -0
  75. package/dist/cms.d.ts +872 -0
  76. package/dist/cms.d.ts.map +1 -0
  77. package/dist/cms.js +468 -0
  78. package/dist/cms.js.map +1 -0
  79. package/dist/common.d.ts +82 -0
  80. package/dist/common.d.ts.map +1 -0
  81. package/dist/common.js +72 -0
  82. package/dist/common.js.map +1 -0
  83. package/dist/comparisons.d.ts +487 -0
  84. package/dist/comparisons.d.ts.map +1 -0
  85. package/dist/comparisons.js +221 -0
  86. package/dist/comparisons.js.map +1 -0
  87. package/dist/credentials.d.ts +292 -0
  88. package/dist/credentials.d.ts.map +1 -0
  89. package/dist/credentials.js +142 -0
  90. package/dist/credentials.js.map +1 -0
  91. package/dist/credit-limits.d.ts +111 -0
  92. package/dist/credit-limits.d.ts.map +1 -0
  93. package/dist/credit-limits.js +35 -0
  94. package/dist/credit-limits.js.map +1 -0
  95. package/dist/currencies.d.ts +127 -0
  96. package/dist/currencies.d.ts.map +1 -0
  97. package/dist/currencies.js +20 -0
  98. package/dist/currencies.js.map +1 -0
  99. package/dist/custom-fields.d.ts +345 -0
  100. package/dist/custom-fields.d.ts.map +1 -0
  101. package/dist/custom-fields.js +185 -0
  102. package/dist/custom-fields.js.map +1 -0
  103. package/dist/customer-accounts.d.ts +690 -0
  104. package/dist/customer-accounts.d.ts.map +1 -0
  105. package/dist/customer-accounts.js +41 -0
  106. package/dist/customer-accounts.js.map +1 -0
  107. package/dist/customers.d.ts +305 -0
  108. package/dist/customers.d.ts.map +1 -0
  109. package/dist/customers.js +158 -0
  110. package/dist/customers.js.map +1 -0
  111. package/dist/dictionary.d.ts +580 -0
  112. package/dist/dictionary.d.ts.map +1 -0
  113. package/dist/dictionary.js +297 -0
  114. package/dist/dictionary.js.map +1 -0
  115. package/dist/email-address.d.ts +62 -0
  116. package/dist/email-address.d.ts.map +1 -0
  117. package/dist/email-address.js +64 -0
  118. package/dist/email-address.js.map +1 -0
  119. package/dist/email.d.ts +175 -0
  120. package/dist/email.d.ts.map +1 -0
  121. package/dist/email.js +45 -0
  122. package/dist/email.js.map +1 -0
  123. package/dist/envelopes.d.ts +15 -0
  124. package/dist/envelopes.d.ts.map +1 -0
  125. package/dist/envelopes.js +16 -0
  126. package/dist/envelopes.js.map +1 -0
  127. package/dist/environment-inputs.d.ts +306 -0
  128. package/dist/environment-inputs.d.ts.map +1 -0
  129. package/dist/environment-inputs.js +277 -0
  130. package/dist/environment-inputs.js.map +1 -0
  131. package/dist/erp-connector.d.ts +52 -0
  132. package/dist/erp-connector.d.ts.map +1 -0
  133. package/dist/erp-connector.js +34 -0
  134. package/dist/erp-connector.js.map +1 -0
  135. package/dist/errors.d.ts +455 -0
  136. package/dist/errors.d.ts.map +1 -0
  137. package/dist/errors.js +532 -0
  138. package/dist/errors.js.map +1 -0
  139. package/dist/google-analytics.d.ts +181 -0
  140. package/dist/google-analytics.d.ts.map +1 -0
  141. package/dist/google-analytics.js +176 -0
  142. package/dist/google-analytics.js.map +1 -0
  143. package/dist/google-tag-manager.d.ts +111 -0
  144. package/dist/google-tag-manager.d.ts.map +1 -0
  145. package/dist/google-tag-manager.js +129 -0
  146. package/dist/google-tag-manager.js.map +1 -0
  147. package/dist/i18n.d.ts +69 -0
  148. package/dist/i18n.d.ts.map +1 -0
  149. package/dist/i18n.js +59 -0
  150. package/dist/i18n.js.map +1 -0
  151. package/dist/import-export.d.ts +63 -0
  152. package/dist/import-export.d.ts.map +1 -0
  153. package/dist/import-export.js +37 -0
  154. package/dist/import-export.js.map +1 -0
  155. package/dist/index.d.ts +82 -0
  156. package/dist/index.d.ts.map +1 -0
  157. package/dist/index.js +126 -0
  158. package/dist/index.js.map +1 -0
  159. package/dist/inventory.d.ts +673 -0
  160. package/dist/inventory.d.ts.map +1 -0
  161. package/dist/inventory.js +412 -0
  162. package/dist/inventory.js.map +1 -0
  163. package/dist/invoice-ledger.d.ts +366 -0
  164. package/dist/invoice-ledger.d.ts.map +1 -0
  165. package/dist/invoice-ledger.js +114 -0
  166. package/dist/invoice-ledger.js.map +1 -0
  167. package/dist/invoices.d.ts +845 -0
  168. package/dist/invoices.d.ts.map +1 -0
  169. package/dist/invoices.js +314 -0
  170. package/dist/invoices.js.map +1 -0
  171. package/dist/kernel.d.ts +49 -0
  172. package/dist/kernel.d.ts.map +1 -0
  173. package/dist/kernel.js +19 -0
  174. package/dist/kernel.js.map +1 -0
  175. package/dist/languages.d.ts +122 -0
  176. package/dist/languages.d.ts.map +1 -0
  177. package/dist/languages.js +24 -0
  178. package/dist/languages.js.map +1 -0
  179. package/dist/linkedin-ads.d.ts +167 -0
  180. package/dist/linkedin-ads.d.ts.map +1 -0
  181. package/dist/linkedin-ads.js +156 -0
  182. package/dist/linkedin-ads.js.map +1 -0
  183. package/dist/megamenu.d.ts +556 -0
  184. package/dist/megamenu.d.ts.map +1 -0
  185. package/dist/megamenu.js +186 -0
  186. package/dist/megamenu.js.map +1 -0
  187. package/dist/meta-ads.d.ts +126 -0
  188. package/dist/meta-ads.d.ts.map +1 -0
  189. package/dist/meta-ads.js +112 -0
  190. package/dist/meta-ads.js.map +1 -0
  191. package/dist/mfa.d.ts +274 -0
  192. package/dist/mfa.d.ts.map +1 -0
  193. package/dist/mfa.js +187 -0
  194. package/dist/mfa.js.map +1 -0
  195. package/dist/modules.d.ts +1706 -0
  196. package/dist/modules.d.ts.map +1 -0
  197. package/dist/modules.js +1390 -0
  198. package/dist/modules.js.map +1 -0
  199. package/dist/newsletter.d.ts +611 -0
  200. package/dist/newsletter.d.ts.map +1 -0
  201. package/dist/newsletter.js +345 -0
  202. package/dist/newsletter.js.map +1 -0
  203. package/dist/orders.d.ts +1175 -0
  204. package/dist/orders.d.ts.map +1 -0
  205. package/dist/orders.js +630 -0
  206. package/dist/orders.js.map +1 -0
  207. package/dist/organizations.d.ts +938 -0
  208. package/dist/organizations.d.ts.map +1 -0
  209. package/dist/organizations.js +418 -0
  210. package/dist/organizations.js.map +1 -0
  211. package/dist/pagination.d.ts +21 -0
  212. package/dist/pagination.d.ts.map +1 -0
  213. package/dist/pagination.js +22 -0
  214. package/dist/pagination.js.map +1 -0
  215. package/dist/payment-methods.d.ts +472 -0
  216. package/dist/payment-methods.d.ts.map +1 -0
  217. package/dist/payment-methods.js +175 -0
  218. package/dist/payment-methods.js.map +1 -0
  219. package/dist/payment-return-url.d.ts +53 -0
  220. package/dist/payment-return-url.d.ts.map +1 -0
  221. package/dist/payment-return-url.js +35 -0
  222. package/dist/payment-return-url.js.map +1 -0
  223. package/dist/payments.d.ts +386 -0
  224. package/dist/payments.d.ts.map +1 -0
  225. package/dist/payments.js +84 -0
  226. package/dist/payments.js.map +1 -0
  227. package/dist/pim-connector.d.ts +60 -0
  228. package/dist/pim-connector.d.ts.map +1 -0
  229. package/dist/pim-connector.js +43 -0
  230. package/dist/pim-connector.js.map +1 -0
  231. package/dist/pim-field-path.d.ts +6 -0
  232. package/dist/pim-field-path.d.ts.map +1 -0
  233. package/dist/pim-field-path.js +101 -0
  234. package/dist/pim-field-path.js.map +1 -0
  235. package/dist/platform-language.d.ts +20 -0
  236. package/dist/platform-language.d.ts.map +1 -0
  237. package/dist/platform-language.js +22 -0
  238. package/dist/platform-language.js.map +1 -0
  239. package/dist/price-lists.d.ts +685 -0
  240. package/dist/price-lists.d.ts.map +1 -0
  241. package/dist/price-lists.js +330 -0
  242. package/dist/price-lists.js.map +1 -0
  243. package/dist/product-feeds.d.ts +2837 -0
  244. package/dist/product-feeds.d.ts.map +1 -0
  245. package/dist/product-feeds.js +1504 -0
  246. package/dist/product-feeds.js.map +1 -0
  247. package/dist/product-scope-overrides.d.ts +134 -0
  248. package/dist/product-scope-overrides.d.ts.map +1 -0
  249. package/dist/product-scope-overrides.js +82 -0
  250. package/dist/product-scope-overrides.js.map +1 -0
  251. package/dist/product-value-resolver.d.ts +88 -0
  252. package/dist/product-value-resolver.d.ts.map +1 -0
  253. package/dist/product-value-resolver.js +128 -0
  254. package/dist/product-value-resolver.js.map +1 -0
  255. package/dist/promotions.d.ts +678 -0
  256. package/dist/promotions.d.ts.map +1 -0
  257. package/dist/promotions.js +479 -0
  258. package/dist/promotions.js.map +1 -0
  259. package/dist/prompt-actions.d.ts +582 -0
  260. package/dist/prompt-actions.d.ts.map +1 -0
  261. package/dist/prompt-actions.js +221 -0
  262. package/dist/prompt-actions.js.map +1 -0
  263. package/dist/pwa.d.ts +293 -0
  264. package/dist/pwa.d.ts.map +1 -0
  265. package/dist/pwa.js +204 -0
  266. package/dist/pwa.js.map +1 -0
  267. package/dist/quick-order.d.ts +340 -0
  268. package/dist/quick-order.d.ts.map +1 -0
  269. package/dist/quick-order.js +177 -0
  270. package/dist/quick-order.js.map +1 -0
  271. package/dist/quote-requests.d.ts +538 -0
  272. package/dist/quote-requests.d.ts.map +1 -0
  273. package/dist/quote-requests.js +308 -0
  274. package/dist/quote-requests.js.map +1 -0
  275. package/dist/returns.d.ts +774 -0
  276. package/dist/returns.d.ts.map +1 -0
  277. package/dist/returns.js +389 -0
  278. package/dist/returns.js.map +1 -0
  279. package/dist/sales-channels.d.ts +392 -0
  280. package/dist/sales-channels.d.ts.map +1 -0
  281. package/dist/sales-channels.js +285 -0
  282. package/dist/sales-channels.js.map +1 -0
  283. package/dist/scope-notice.d.ts +60 -0
  284. package/dist/scope-notice.d.ts.map +1 -0
  285. package/dist/scope-notice.js +56 -0
  286. package/dist/scope-notice.js.map +1 -0
  287. package/dist/search.d.ts +321 -0
  288. package/dist/search.d.ts.map +1 -0
  289. package/dist/search.js +160 -0
  290. package/dist/search.js.map +1 -0
  291. package/dist/seo.d.ts +113 -0
  292. package/dist/seo.d.ts.map +1 -0
  293. package/dist/seo.js +63 -0
  294. package/dist/seo.js.map +1 -0
  295. package/dist/settings.d.ts +453 -0
  296. package/dist/settings.d.ts.map +1 -0
  297. package/dist/settings.js +337 -0
  298. package/dist/settings.js.map +1 -0
  299. package/dist/shipments.d.ts +140 -0
  300. package/dist/shipments.d.ts.map +1 -0
  301. package/dist/shipments.js +14 -0
  302. package/dist/shipments.js.map +1 -0
  303. package/dist/shipping-methods.d.ts +350 -0
  304. package/dist/shipping-methods.d.ts.map +1 -0
  305. package/dist/shipping-methods.js +99 -0
  306. package/dist/shipping-methods.js.map +1 -0
  307. package/dist/shopping-lists.d.ts +122 -0
  308. package/dist/shopping-lists.d.ts.map +1 -0
  309. package/dist/shopping-lists.js +92 -0
  310. package/dist/shopping-lists.js.map +1 -0
  311. package/dist/taxes.d.ts +106 -0
  312. package/dist/taxes.d.ts.map +1 -0
  313. package/dist/taxes.js +80 -0
  314. package/dist/taxes.js.map +1 -0
  315. package/dist/text-normalization.d.ts +199 -0
  316. package/dist/text-normalization.d.ts.map +1 -0
  317. package/dist/text-normalization.js +205 -0
  318. package/dist/text-normalization.js.map +1 -0
  319. package/dist/transactional-emails.d.ts +459 -0
  320. package/dist/transactional-emails.d.ts.map +1 -0
  321. package/dist/transactional-emails.js +212 -0
  322. package/dist/transactional-emails.js.map +1 -0
  323. package/dist/webhooks.d.ts +69 -0
  324. package/dist/webhooks.d.ts.map +1 -0
  325. package/dist/webhooks.js +53 -0
  326. package/dist/webhooks.js.map +1 -0
  327. package/package.json +46 -0
@@ -0,0 +1,285 @@
1
+ // Sales Channels module — feature 005 contract surface.
2
+ // Single file with logical sections (matching the convention used by every
3
+ // other module in @endora-commerce/contracts):
4
+ // (1) Identity primitives (channel code, summary, detail).
5
+ // (2) Resolver middleware contract (header / query schemas).
6
+ // (3) Admin HTTP request/response schemas (list / detail / create / edit
7
+ // / lifecycle).
8
+ // (4) Membership endpoints (the bidirectional channel-side / entity-side
9
+ // routes; one shape, used by all 10 entity types).
10
+ // (5) Storefront / public read-only schemas.
11
+ // (6) Audit-action constants — free-form action strings written through
12
+ // the existing AuditLogService.
13
+ // (7) Attribution registry — the contribution seam that answers "who still
14
+ // points at this channel?" before a delete (feature 075, D-87).
15
+ // See specs/005-sales-channels/contracts/sales-channels-005.contract.md
16
+ // for the prose contract and the error-code references in `errors.ts`.
17
+ import { z } from 'zod';
18
+ import { isoDateTimeSchema, uuidSchema } from './common.js';
19
+ // ---------------------------------------------------------------------------
20
+ // (1) Identity primitives
21
+ // ---------------------------------------------------------------------------
22
+ /**
23
+ * Machine-friendly Sales Channel code. Lower-case, starts with a letter,
24
+ * may contain digits, hyphens, and underscores. Stored as `varchar(32)`
25
+ * (foundation 001).
26
+ */
27
+ export const SalesChannelCodeSchema = z
28
+ .string()
29
+ .min(1)
30
+ .max(32)
31
+ .regex(/^[a-z][a-z0-9_-]*$/, 'sales channel code must be lowercase machine-friendly');
32
+ /** i18n display name keyed by language code, e.g. `{ en: 'Default' }`. */
33
+ export const SalesChannelNameSchema = z
34
+ .record(z.string(), z.string())
35
+ .refine((o) => Object.keys(o).length > 0, 'name must include at least one locale');
36
+ /** Short summary returned in list views. */
37
+ export const SalesChannelSummarySchema = z.object({
38
+ id: uuidSchema,
39
+ code: SalesChannelCodeSchema,
40
+ name: SalesChannelNameSchema,
41
+ active: z.boolean(),
42
+ systemDefault: z.boolean(),
43
+ defaultLanguage: z.string(),
44
+ defaultCurrency: z.string(),
45
+ themeCode: z.string().nullable(),
46
+ logoAssetId: uuidSchema.nullable(),
47
+ version: z.number().int().positive(),
48
+ createdAt: isoDateTimeSchema,
49
+ updatedAt: isoDateTimeSchema,
50
+ });
51
+ /** Full detail returned by the admin GET-by-code endpoint. */
52
+ export const SalesChannelDetailSchema = SalesChannelSummarySchema.extend({
53
+ languages: z.array(z.string()).min(1),
54
+ currencies: z.array(z.string()).min(1),
55
+ /** Resolved through the assets module on response; nullable when no logo set. */
56
+ logoUrl: z.string().url().nullable(),
57
+ });
58
+ // ---------------------------------------------------------------------------
59
+ // (2) Resolver middleware contract
60
+ // ---------------------------------------------------------------------------
61
+ /** `X-Sales-Channel: <code>` header schema. */
62
+ export const SalesChannelHeaderSchema = z.object({
63
+ 'x-sales-channel': SalesChannelCodeSchema.optional(),
64
+ });
65
+ /**
66
+ * `?salesChannel=<code>` query parameter schema. Used by storefront SSR
67
+ * paths and link-shareable previews; ignored on `/api/v1/admin/*` paths
68
+ * by the resolver middleware to prevent cross-channel admin bleed.
69
+ */
70
+ export const SalesChannelQuerySchema = z.object({
71
+ salesChannel: SalesChannelCodeSchema.optional(),
72
+ });
73
+ // ---------------------------------------------------------------------------
74
+ // (3) Admin HTTP request/response schemas
75
+ // ---------------------------------------------------------------------------
76
+ const themeCodeRe = /^[a-z][a-z0-9_-]*$/;
77
+ /** Body shape for POST /api/v1/admin/sales-channels. */
78
+ export const SalesChannelCreateBodySchema = z
79
+ .object({
80
+ code: SalesChannelCodeSchema,
81
+ name: SalesChannelNameSchema,
82
+ logoAssetId: uuidSchema.nullable().optional(),
83
+ themeCode: z
84
+ .string()
85
+ .regex(themeCodeRe, 'theme code must be lowercase machine-friendly')
86
+ .nullable()
87
+ .optional(),
88
+ languages: z.array(z.string()).min(1),
89
+ defaultLanguage: z.string(),
90
+ currencies: z.array(z.string()).min(1),
91
+ defaultCurrency: z.string(),
92
+ active: z.boolean().optional().default(true),
93
+ })
94
+ .superRefine((v, ctx) => {
95
+ if (!v.languages.includes(v.defaultLanguage)) {
96
+ ctx.addIssue({
97
+ code: 'custom',
98
+ path: ['defaultLanguage'],
99
+ message: 'defaultLanguage must be one of languages',
100
+ });
101
+ }
102
+ if (!v.currencies.includes(v.defaultCurrency)) {
103
+ ctx.addIssue({
104
+ code: 'custom',
105
+ path: ['defaultCurrency'],
106
+ message: 'defaultCurrency must be one of currencies',
107
+ });
108
+ }
109
+ });
110
+ /**
111
+ * Body shape for PATCH /api/v1/admin/sales-channels/{code}. Every field optional.
112
+ *
113
+ * `code` is accepted only when it repeats the channel's current code: a channel's
114
+ * code is written once, at creation, and is immutable afterwards — on every
115
+ * channel, not only the system default. A code is an identity other systems hold
116
+ * onto (`SALES_CHANNEL_HOST_MAP`, cached storefront responses, integration
117
+ * configuration), so changing it renames something those systems cannot follow.
118
+ * A different value is refused with 422 `SALES_CHANNEL_CODE_IMMUTABLE`; the field
119
+ * stays in the shape so the refusal is explicit rather than a silently stripped
120
+ * property that answers 200 and changes nothing. A mistyped code is fixed by
121
+ * creating the channel again under the right code and deleting the old one —
122
+ * for the default channel, after moving the flag off it with `set-default`.
123
+ * The `name` stays freely editable.
124
+ */
125
+ export const SalesChannelUpdateBodySchema = z
126
+ .object({
127
+ code: SalesChannelCodeSchema.optional(),
128
+ name: SalesChannelNameSchema.optional(),
129
+ logoAssetId: uuidSchema.nullable().optional(),
130
+ themeCode: z.string().regex(themeCodeRe).nullable().optional(),
131
+ languages: z.array(z.string()).min(1).optional(),
132
+ defaultLanguage: z.string().optional(),
133
+ currencies: z.array(z.string()).min(1).optional(),
134
+ defaultCurrency: z.string().optional(),
135
+ active: z.boolean().optional(),
136
+ })
137
+ .superRefine((v, ctx) => {
138
+ if (v.defaultLanguage !== undefined && v.languages && !v.languages.includes(v.defaultLanguage)) {
139
+ ctx.addIssue({
140
+ code: 'custom',
141
+ path: ['defaultLanguage'],
142
+ message: 'defaultLanguage must be one of languages',
143
+ });
144
+ }
145
+ if (v.defaultCurrency !== undefined && v.currencies && !v.currencies.includes(v.defaultCurrency)) {
146
+ ctx.addIssue({
147
+ code: 'custom',
148
+ path: ['defaultCurrency'],
149
+ message: 'defaultCurrency must be one of currencies',
150
+ });
151
+ }
152
+ });
153
+ /**
154
+ * Body shape for POST /api/v1/admin/sales-channels/{code}/set-default.
155
+ *
156
+ * The target is the path parameter, so the body carries nothing today. It is
157
+ * declared rather than omitted because the endpoint is a state transition, not a
158
+ * patch: an operator's client sends `{}` and any later option (a reason, a
159
+ * scheduled cut-over) lands here instead of on the query string.
160
+ */
161
+ export const SalesChannelSetDefaultBodySchema = z.object({});
162
+ /**
163
+ * Response shape for POST /api/v1/admin/sales-channels/{code}/set-default.
164
+ *
165
+ * `changed` is false when the target already held the flag — promoting the
166
+ * current default is a no-op success, not an error, so a double-click and a
167
+ * retried request both answer 200 with the same body. `previousDefaultCode` is
168
+ * the code that held the flag before the call, which on the no-op path is the
169
+ * target's own code; it names the channel a subsequent `set-default` would move
170
+ * the flag back to.
171
+ */
172
+ export const SalesChannelSetDefaultResponseSchema = z.object({
173
+ channel: SalesChannelDetailSchema,
174
+ previousDefaultCode: SalesChannelCodeSchema.nullable(),
175
+ changed: z.boolean(),
176
+ });
177
+ /** Response shape for GET /api/v1/admin/sales-channels (paginated list). */
178
+ export const SalesChannelListResponseSchema = z.object({
179
+ items: z.array(SalesChannelSummarySchema),
180
+ page: z.number().int().nonnegative(),
181
+ pageSize: z.number().int().positive(),
182
+ total: z.number().int().nonnegative(),
183
+ });
184
+ // ---------------------------------------------------------------------------
185
+ // (4) Membership endpoints (bidirectional)
186
+ // ---------------------------------------------------------------------------
187
+ /** Channel-scoped entity types tracked by the M:N membership service. */
188
+ export const ChannelMemberEntityTypeSchema = z.enum([
189
+ 'product',
190
+ 'category',
191
+ 'payment-method',
192
+ 'delivery-method',
193
+ 'organization',
194
+ 'tax',
195
+ 'customer',
196
+ 'promotion',
197
+ 'cms-page',
198
+ ]);
199
+ /** `GET /api/v1/admin/sales-channels/{code}/{entityType}` — list members. */
200
+ export const ChannelMembershipListResponseSchema = z.object({
201
+ channels: z.array(SalesChannelSummarySchema),
202
+ });
203
+ /** `GET /api/v1/admin/{entityType}/{id}/sales-channels` — list channels of an entity. */
204
+ export const EntityMembershipListResponseSchema = z.object({
205
+ entityType: ChannelMemberEntityTypeSchema,
206
+ entityId: uuidSchema,
207
+ channels: z.array(SalesChannelSummarySchema),
208
+ });
209
+ // ---------------------------------------------------------------------------
210
+ // (5) Storefront / public read-only
211
+ // ---------------------------------------------------------------------------
212
+ /**
213
+ * `GET /api/v1/storefront/sales-channel` — what the storefront app fetches
214
+ * on first paint to know its theme / language / currency.
215
+ *
216
+ * Deliberately drops `id`, `active`, `systemDefault`, and `version`
217
+ * (admin-only fields).
218
+ */
219
+ export const PublicSalesChannelSchema = z.object({
220
+ code: SalesChannelCodeSchema,
221
+ name: SalesChannelNameSchema,
222
+ defaultLanguage: z.string(),
223
+ defaultCurrency: z.string(),
224
+ languages: z.array(z.string()),
225
+ currencies: z.array(z.string()),
226
+ themeCode: z.string().nullable(),
227
+ logoUrl: z.string().url().nullable(),
228
+ });
229
+ /** Response envelope of `GET /api/v1/storefront/sales-channel`. */
230
+ export const PublicSalesChannelResponseSchema = z.object({
231
+ data: PublicSalesChannelSchema,
232
+ });
233
+ /**
234
+ * **The platform no longer holds a list of storefront themes** — owner ruling
235
+ * D-199, implemented by `specs/102-storefront-theme-discovery/`.
236
+ *
237
+ * `STOREFRONT_THEME_CODES`, `StorefrontThemeCodeSchema`, `StorefrontThemeCode`,
238
+ * `DEFAULT_STOREFRONT_THEME_CODE` and `isStorefrontThemeCode` used to live here
239
+ * and are gone. A theme is a token set a **third party** may publish as an
240
+ * ordinary npm package, so no set this repository can compile is the whole set:
241
+ * the answer belongs to the storefront instance that has the packages
242
+ * installed, and it is generated in that instance's own tree
243
+ * (`storefront/lib/theme/`).
244
+ *
245
+ * The **write** schemas above are unchanged and must stay so. They have never
246
+ * used the enum: `themeCodeRe` is the whole validation, and a backend that
247
+ * refused a code it has never heard of would make the field unusable for
248
+ * exactly the deployments it exists for. `PublicSalesChannelSchema.themeCode`
249
+ * is likewise unchanged — the wire shape gains and loses nothing.
250
+ *
251
+ * What an unknown code does is the storefront's answer and is unchanged too:
252
+ * it renders the instance's default rather than blank, reports the code once
253
+ * per process, marks the document with `data-theme-requested`, never writes the
254
+ * value back and never guesses at a near match. See
255
+ * `specs/102-storefront-theme-discovery/contracts/theme-package.md` for what a
256
+ * theme author ships, and `contracts/instance-theme-registry.md` for how an
257
+ * instance discovers its own.
258
+ */
259
+ // ---------------------------------------------------------------------------
260
+ // (6) Audit-action constants
261
+ // ---------------------------------------------------------------------------
262
+ /**
263
+ * Action strings written by `SalesChannelsService` / `SalesChannelMembershipService`
264
+ * through the existing `AuditLogService.record({ action, ... })`. They are
265
+ * free-form strings (the audit log uses `action: string`, not an enum)
266
+ * but every consumer should use these constants so a typo can't drift.
267
+ */
268
+ export const SALES_CHANNEL_AUDIT_ACTIONS = {
269
+ IDENTITY_CHANGED: 'sales_channel.identity.changed',
270
+ MEMBERSHIP_CHANGED: 'sales_channel.membership.changed',
271
+ LIFECYCLE_CHANGED: 'sales_channel.lifecycle.changed',
272
+ };
273
+ export const SalesChannelAuditActionSchema = z.enum([
274
+ SALES_CHANNEL_AUDIT_ACTIONS.IDENTITY_CHANGED,
275
+ SALES_CHANNEL_AUDIT_ACTIONS.MEMBERSHIP_CHANGED,
276
+ SALES_CHANNEL_AUDIT_ACTIONS.LIFECYCLE_CHANGED,
277
+ ]);
278
+ export const SalesChannelLifecycleOpSchema = z.enum([
279
+ 'deactivated',
280
+ 'activated',
281
+ 'deleted',
282
+ 'system-default-promoted',
283
+ ]);
284
+ export const SalesChannelMembershipOpSchema = z.enum(['add', 'remove']);
285
+ //# sourceMappingURL=sales-channels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sales-channels.js","sourceRoot":"","sources":["../src/sales-channels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Why a listing came back empty, when "empty" and "nothing exists" are not the
4
+ * same statement (feature 087, owner decision of 2026-08-29).
5
+ *
6
+ * `customerFilterCond`'s `allowed-set` arm refuses **every** row of a
7
+ * `@CustomerScoped` table that carries no `organization_id`, because no row in
8
+ * such a table is inside a scoped actor's authority (FR-011). The refusal is
9
+ * correct. What is not correct is the silence: the client receives `[]`, which
10
+ * is indistinguishable from "there is nothing here", and an operator reading it
11
+ * concludes something false about the **data** rather than something true about
12
+ * their own reach.
13
+ *
14
+ * So the server says which of the two it meant. The notice is **derived** —
15
+ * the filter records that it emitted the refusing predicate, and the host's
16
+ * request hook puts the code on the response envelope — so no route sets a flag
17
+ * and no screen has to be remembered. It stops being emitted, everywhere at
18
+ * once and with no edit, on the day a table gains its column and the same arm
19
+ * starts granting.
20
+ *
21
+ * It is a *notice*, never an error: the response is a 200 with a truthful body.
22
+ */
23
+ export declare const SCOPE_NOTICE_CODES: {
24
+ /**
25
+ * The records this surface lists carry no organization at all yet, so a
26
+ * viewer confined to a set of organizations can be shown none of them. The
27
+ * operator-facing sentences live in the `core` i18n bundle under
28
+ * `scopeNotice.organizationAttributionPending.*`.
29
+ */
30
+ readonly ORGANIZATION_ATTRIBUTION_PENDING: "ORGANIZATION_ATTRIBUTION_PENDING";
31
+ };
32
+ export declare const scopeNoticeCodeSchema: z.ZodEnum<{
33
+ ORGANIZATION_ATTRIBUTION_PENDING: "ORGANIZATION_ATTRIBUTION_PENDING";
34
+ }>;
35
+ export type ScopeNoticeCode = z.infer<typeof scopeNoticeCodeSchema>;
36
+ /**
37
+ * The envelope slot the notice occupies: `meta.scopeNotice`, on any successful
38
+ * response. `meta` is the one place the three surfaces this covers could share
39
+ * — their bodies are `{ data, meta }`, `{ data }` and a bare page object — and
40
+ * the key is absent rather than null when there is nothing to say.
41
+ */
42
+ export declare const scopeNoticeMetaSchema: z.ZodObject<{
43
+ scopeNotice: z.ZodOptional<z.ZodEnum<{
44
+ ORGANIZATION_ATTRIBUTION_PENDING: "ORGANIZATION_ATTRIBUTION_PENDING";
45
+ }>>;
46
+ }, z.core.$strip>;
47
+ export type ScopeNoticeMeta = z.infer<typeof scopeNoticeMetaSchema>;
48
+ /** The envelope shape a client reads the notice out of. */
49
+ export interface ScopeNoticeEnvelope {
50
+ readonly meta?: {
51
+ readonly scopeNotice?: ScopeNoticeCode;
52
+ } | undefined;
53
+ }
54
+ /**
55
+ * Read the notice off any response body, or `null` when the body carries none.
56
+ * Written here rather than per client so that "what a notice looks like on the
57
+ * wire" has one definition on both sides of the boundary.
58
+ */
59
+ export declare function scopeNoticeOf(response: unknown): ScopeNoticeCode | null;
60
+ //# sourceMappingURL=scope-notice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-notice.d.ts","sourceRoot":"","sources":["../src/scope-notice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,kBAAkB;IAC7B;;;;;OAKG;;CAEK,CAAC;AAEX,eAAO,MAAM,qBAAqB;;EAA+C,CAAC;AAClF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB;;;;iBAEhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,2DAA2D;AAC3D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,eAAe,CAAA;KAAE,GAAG,SAAS,CAAC;CACxE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAMvE"}
@@ -0,0 +1,56 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Why a listing came back empty, when "empty" and "nothing exists" are not the
4
+ * same statement (feature 087, owner decision of 2026-08-29).
5
+ *
6
+ * `customerFilterCond`'s `allowed-set` arm refuses **every** row of a
7
+ * `@CustomerScoped` table that carries no `organization_id`, because no row in
8
+ * such a table is inside a scoped actor's authority (FR-011). The refusal is
9
+ * correct. What is not correct is the silence: the client receives `[]`, which
10
+ * is indistinguishable from "there is nothing here", and an operator reading it
11
+ * concludes something false about the **data** rather than something true about
12
+ * their own reach.
13
+ *
14
+ * So the server says which of the two it meant. The notice is **derived** —
15
+ * the filter records that it emitted the refusing predicate, and the host's
16
+ * request hook puts the code on the response envelope — so no route sets a flag
17
+ * and no screen has to be remembered. It stops being emitted, everywhere at
18
+ * once and with no edit, on the day a table gains its column and the same arm
19
+ * starts granting.
20
+ *
21
+ * It is a *notice*, never an error: the response is a 200 with a truthful body.
22
+ */
23
+ export const SCOPE_NOTICE_CODES = {
24
+ /**
25
+ * The records this surface lists carry no organization at all yet, so a
26
+ * viewer confined to a set of organizations can be shown none of them. The
27
+ * operator-facing sentences live in the `core` i18n bundle under
28
+ * `scopeNotice.organizationAttributionPending.*`.
29
+ */
30
+ ORGANIZATION_ATTRIBUTION_PENDING: 'ORGANIZATION_ATTRIBUTION_PENDING',
31
+ };
32
+ export const scopeNoticeCodeSchema = z.enum(['ORGANIZATION_ATTRIBUTION_PENDING']);
33
+ /**
34
+ * The envelope slot the notice occupies: `meta.scopeNotice`, on any successful
35
+ * response. `meta` is the one place the three surfaces this covers could share
36
+ * — their bodies are `{ data, meta }`, `{ data }` and a bare page object — and
37
+ * the key is absent rather than null when there is nothing to say.
38
+ */
39
+ export const scopeNoticeMetaSchema = z.object({
40
+ scopeNotice: scopeNoticeCodeSchema.optional(),
41
+ });
42
+ /**
43
+ * Read the notice off any response body, or `null` when the body carries none.
44
+ * Written here rather than per client so that "what a notice looks like on the
45
+ * wire" has one definition on both sides of the boundary.
46
+ */
47
+ export function scopeNoticeOf(response) {
48
+ if (typeof response !== 'object' || response === null)
49
+ return null;
50
+ const meta = response.meta;
51
+ if (typeof meta !== 'object' || meta === null)
52
+ return null;
53
+ const code = meta.scopeNotice;
54
+ return scopeNoticeCodeSchema.safeParse(code).success ? code : null;
55
+ }
56
+ //# sourceMappingURL=scope-notice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-notice.js","sourceRoot":"","sources":["../src/scope-notice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC;;;;;OAKG;IACH,gCAAgC,EAAE,kCAAkC;CAC5D,CAAC;AAEX,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC;AAGlF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,WAAW,EAAE,qBAAqB,CAAC,QAAQ,EAAE;CAC9C,CAAC,CAAC;AAQH;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,QAAiB;IAC7C,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnE,MAAM,IAAI,GAAI,QAA+B,CAAC,IAAI,CAAC;IACnD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC3D,MAAM,IAAI,GAAI,IAAkC,CAAC,WAAW,CAAC;IAC7D,OAAO,qBAAqB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAE,IAAwB,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1F,CAAC"}