@unifiedcommerce/core 0.1.0 → 0.2.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 (245) hide show
  1. package/dist/auth/setup.d.ts.map +1 -1
  2. package/dist/auth/setup.js +8 -3
  3. package/dist/config/types.d.ts +3 -1
  4. package/dist/config/types.d.ts.map +1 -1
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1 -0
  8. package/dist/interfaces/mcp/server.d.ts +3 -5
  9. package/dist/interfaces/mcp/server.d.ts.map +1 -1
  10. package/dist/interfaces/mcp/server.js +25 -510
  11. package/dist/interfaces/mcp/tool-builder.d.ts +120 -0
  12. package/dist/interfaces/mcp/tool-builder.d.ts.map +1 -0
  13. package/dist/interfaces/mcp/tool-builder.js +224 -0
  14. package/dist/interfaces/mcp/tools/analytics.d.ts +42 -0
  15. package/dist/interfaces/mcp/tools/analytics.d.ts.map +1 -0
  16. package/dist/interfaces/mcp/tools/analytics.js +70 -0
  17. package/dist/interfaces/mcp/tools/cart.d.ts +14 -0
  18. package/dist/interfaces/mcp/tools/cart.d.ts.map +1 -0
  19. package/dist/interfaces/mcp/tools/cart.js +47 -0
  20. package/dist/interfaces/mcp/tools/catalog.d.ts +53 -0
  21. package/dist/interfaces/mcp/tools/catalog.d.ts.map +1 -0
  22. package/dist/interfaces/mcp/tools/catalog.js +284 -0
  23. package/dist/interfaces/mcp/tools/index.d.ts +3 -0
  24. package/dist/interfaces/mcp/tools/index.d.ts.map +1 -0
  25. package/dist/interfaces/mcp/tools/index.js +20 -0
  26. package/dist/interfaces/mcp/tools/inventory.d.ts +27 -0
  27. package/dist/interfaces/mcp/tools/inventory.d.ts.map +1 -0
  28. package/dist/interfaces/mcp/tools/inventory.js +143 -0
  29. package/dist/interfaces/mcp/tools/orders.d.ts +18 -0
  30. package/dist/interfaces/mcp/tools/orders.d.ts.map +1 -0
  31. package/dist/interfaces/mcp/tools/orders.js +82 -0
  32. package/dist/interfaces/mcp/tools/pricing.d.ts +29 -0
  33. package/dist/interfaces/mcp/tools/pricing.d.ts.map +1 -0
  34. package/dist/interfaces/mcp/tools/pricing.js +90 -0
  35. package/dist/interfaces/mcp/tools/promotions.d.ts +44 -0
  36. package/dist/interfaces/mcp/tools/promotions.d.ts.map +1 -0
  37. package/dist/interfaces/mcp/tools/promotions.js +109 -0
  38. package/dist/interfaces/mcp/tools/registry.d.ts +32 -0
  39. package/dist/interfaces/mcp/tools/registry.d.ts.map +1 -0
  40. package/dist/interfaces/mcp/tools/registry.js +55 -0
  41. package/dist/interfaces/mcp/tools/search.d.ts +14 -0
  42. package/dist/interfaces/mcp/tools/search.d.ts.map +1 -0
  43. package/dist/interfaces/mcp/tools/search.js +39 -0
  44. package/dist/interfaces/mcp/tools/webhooks.d.ts +15 -0
  45. package/dist/interfaces/mcp/tools/webhooks.d.ts.map +1 -0
  46. package/dist/interfaces/mcp/tools/webhooks.js +48 -0
  47. package/dist/interfaces/mcp/transport.d.ts +17 -2
  48. package/dist/interfaces/mcp/transport.d.ts.map +1 -1
  49. package/dist/interfaces/mcp/transport.js +91 -44
  50. package/dist/interfaces/rest/router.d.ts.map +1 -1
  51. package/dist/interfaces/rest/routes/checkout.d.ts.map +1 -1
  52. package/dist/interfaces/rest/routes/checkout.js +1 -1
  53. package/dist/interfaces/rest/routes/promotions.d.ts.map +1 -1
  54. package/dist/interfaces/rest/routes/promotions.js +3 -2
  55. package/dist/kernel/database/adapter.d.ts +8 -0
  56. package/dist/kernel/database/adapter.d.ts.map +1 -1
  57. package/dist/kernel/factory/repository-factory.d.ts.map +1 -1
  58. package/dist/kernel/factory/repository-factory.js +3 -1
  59. package/dist/kernel/local-api.d.ts.map +1 -1
  60. package/dist/kernel/local-api.js +2 -0
  61. package/dist/kernel/plugin/manifest.d.ts +3 -3
  62. package/dist/kernel/plugin/manifest.d.ts.map +1 -1
  63. package/dist/kernel/plugin/manifest.js +36 -7
  64. package/dist/runtime/kernel.d.ts +1 -2
  65. package/dist/runtime/kernel.d.ts.map +1 -1
  66. package/dist/runtime/kernel.js +16 -8
  67. package/dist/runtime/server.d.ts.map +1 -1
  68. package/dist/runtime/server.js +8 -3
  69. package/dist/test-utils/create-pglite-adapter.d.ts.map +1 -1
  70. package/dist/test-utils/create-pglite-adapter.js +7 -6
  71. package/dist/tsconfig.tsbuildinfo +1 -0
  72. package/package.json +2 -2
  73. package/src/adapters/console-email.ts +0 -43
  74. package/src/auth/access.ts +0 -187
  75. package/src/auth/auth-schema.ts +0 -139
  76. package/src/auth/middleware.ts +0 -161
  77. package/src/auth/org.ts +0 -41
  78. package/src/auth/permissions.ts +0 -28
  79. package/src/auth/setup.ts +0 -169
  80. package/src/auth/system-actor.ts +0 -19
  81. package/src/auth/types.ts +0 -10
  82. package/src/config/defaults.ts +0 -82
  83. package/src/config/define-config.ts +0 -53
  84. package/src/config/types.ts +0 -299
  85. package/src/generated/plugin-capabilities.d.ts +0 -20
  86. package/src/generated/plugin-manifest.ts +0 -23
  87. package/src/generated/plugin-repositories.d.ts +0 -20
  88. package/src/hooks/checkout-completion.ts +0 -262
  89. package/src/hooks/checkout.ts +0 -677
  90. package/src/hooks/order-emails.ts +0 -62
  91. package/src/index.ts +0 -214
  92. package/src/interfaces/mcp/agent-prompt.ts +0 -174
  93. package/src/interfaces/mcp/context-enrichment.ts +0 -177
  94. package/src/interfaces/mcp/server.ts +0 -617
  95. package/src/interfaces/mcp/transport.ts +0 -68
  96. package/src/interfaces/rest/customer-portal.ts +0 -299
  97. package/src/interfaces/rest/index.ts +0 -74
  98. package/src/interfaces/rest/router.ts +0 -334
  99. package/src/interfaces/rest/routes/admin-jobs.ts +0 -58
  100. package/src/interfaces/rest/routes/audit.ts +0 -50
  101. package/src/interfaces/rest/routes/carts.ts +0 -89
  102. package/src/interfaces/rest/routes/catalog.ts +0 -493
  103. package/src/interfaces/rest/routes/checkout.ts +0 -283
  104. package/src/interfaces/rest/routes/inventory.ts +0 -70
  105. package/src/interfaces/rest/routes/media.ts +0 -86
  106. package/src/interfaces/rest/routes/orders.ts +0 -78
  107. package/src/interfaces/rest/routes/payments.ts +0 -60
  108. package/src/interfaces/rest/routes/pricing.ts +0 -57
  109. package/src/interfaces/rest/routes/promotions.ts +0 -92
  110. package/src/interfaces/rest/routes/search.ts +0 -71
  111. package/src/interfaces/rest/routes/webhooks.ts +0 -46
  112. package/src/interfaces/rest/schemas/admin-jobs.ts +0 -40
  113. package/src/interfaces/rest/schemas/audit.ts +0 -46
  114. package/src/interfaces/rest/schemas/carts.ts +0 -125
  115. package/src/interfaces/rest/schemas/catalog.ts +0 -450
  116. package/src/interfaces/rest/schemas/checkout.ts +0 -66
  117. package/src/interfaces/rest/schemas/customer-portal.ts +0 -195
  118. package/src/interfaces/rest/schemas/inventory.ts +0 -138
  119. package/src/interfaces/rest/schemas/media.ts +0 -75
  120. package/src/interfaces/rest/schemas/orders.ts +0 -104
  121. package/src/interfaces/rest/schemas/pricing.ts +0 -80
  122. package/src/interfaces/rest/schemas/promotions.ts +0 -110
  123. package/src/interfaces/rest/schemas/responses.ts +0 -85
  124. package/src/interfaces/rest/schemas/search.ts +0 -58
  125. package/src/interfaces/rest/schemas/shared.ts +0 -62
  126. package/src/interfaces/rest/schemas/webhooks.ts +0 -68
  127. package/src/interfaces/rest/utils.ts +0 -104
  128. package/src/interfaces/rest/webhook-router.ts +0 -50
  129. package/src/kernel/compensation/executor.ts +0 -61
  130. package/src/kernel/compensation/types.ts +0 -26
  131. package/src/kernel/database/adapter.ts +0 -13
  132. package/src/kernel/database/drizzle-db.ts +0 -56
  133. package/src/kernel/database/migrate.ts +0 -76
  134. package/src/kernel/database/plugin-types.ts +0 -34
  135. package/src/kernel/database/schema.ts +0 -49
  136. package/src/kernel/database/scoped-db.ts +0 -68
  137. package/src/kernel/database/tx-context.ts +0 -46
  138. package/src/kernel/error-mapper.ts +0 -15
  139. package/src/kernel/errors.ts +0 -89
  140. package/src/kernel/factory/repository-factory.ts +0 -242
  141. package/src/kernel/hooks/create-context.ts +0 -43
  142. package/src/kernel/hooks/executor.ts +0 -88
  143. package/src/kernel/hooks/registry.ts +0 -74
  144. package/src/kernel/hooks/types.ts +0 -52
  145. package/src/kernel/http-error.ts +0 -44
  146. package/src/kernel/jobs/adapter.ts +0 -36
  147. package/src/kernel/jobs/drizzle-adapter.ts +0 -58
  148. package/src/kernel/jobs/runner.ts +0 -153
  149. package/src/kernel/jobs/schema.ts +0 -46
  150. package/src/kernel/jobs/types.ts +0 -30
  151. package/src/kernel/local-api.ts +0 -185
  152. package/src/kernel/plugin/manifest.ts +0 -253
  153. package/src/kernel/query/executor.ts +0 -184
  154. package/src/kernel/query/registry.ts +0 -46
  155. package/src/kernel/result.ts +0 -33
  156. package/src/kernel/schema/extra-columns.ts +0 -37
  157. package/src/kernel/service-registry.ts +0 -76
  158. package/src/kernel/service-timing.ts +0 -89
  159. package/src/kernel/state-machine/machine.ts +0 -101
  160. package/src/modules/analytics/drizzle-adapter.ts +0 -426
  161. package/src/modules/analytics/hooks.ts +0 -11
  162. package/src/modules/analytics/models.ts +0 -125
  163. package/src/modules/analytics/repository/index.ts +0 -6
  164. package/src/modules/analytics/service.ts +0 -245
  165. package/src/modules/analytics/types.ts +0 -180
  166. package/src/modules/audit/hooks.ts +0 -78
  167. package/src/modules/audit/schema.ts +0 -33
  168. package/src/modules/audit/service.ts +0 -151
  169. package/src/modules/cart/access.ts +0 -27
  170. package/src/modules/cart/matcher.ts +0 -26
  171. package/src/modules/cart/repository/index.ts +0 -234
  172. package/src/modules/cart/schema.ts +0 -42
  173. package/src/modules/cart/schemas.ts +0 -38
  174. package/src/modules/cart/service.ts +0 -541
  175. package/src/modules/catalog/repository/index.ts +0 -772
  176. package/src/modules/catalog/schema.ts +0 -203
  177. package/src/modules/catalog/schemas.ts +0 -104
  178. package/src/modules/catalog/service.ts +0 -1544
  179. package/src/modules/customers/repository/index.ts +0 -327
  180. package/src/modules/customers/schema.ts +0 -64
  181. package/src/modules/customers/service.ts +0 -171
  182. package/src/modules/fulfillment/repository/index.ts +0 -426
  183. package/src/modules/fulfillment/schema.ts +0 -101
  184. package/src/modules/fulfillment/service.ts +0 -555
  185. package/src/modules/fulfillment/types.ts +0 -59
  186. package/src/modules/inventory/repository/index.ts +0 -509
  187. package/src/modules/inventory/schema.ts +0 -94
  188. package/src/modules/inventory/schemas.ts +0 -38
  189. package/src/modules/inventory/service.ts +0 -490
  190. package/src/modules/media/adapter.ts +0 -17
  191. package/src/modules/media/repository/index.ts +0 -274
  192. package/src/modules/media/schema.ts +0 -41
  193. package/src/modules/media/service.ts +0 -151
  194. package/src/modules/orders/repository/index.ts +0 -287
  195. package/src/modules/orders/schema.ts +0 -66
  196. package/src/modules/orders/service.ts +0 -619
  197. package/src/modules/orders/stale-order-cleanup.ts +0 -76
  198. package/src/modules/organization/service.ts +0 -191
  199. package/src/modules/payments/adapter.ts +0 -47
  200. package/src/modules/payments/repository/index.ts +0 -6
  201. package/src/modules/payments/service.ts +0 -107
  202. package/src/modules/pricing/repository/index.ts +0 -291
  203. package/src/modules/pricing/schema.ts +0 -71
  204. package/src/modules/pricing/schemas.ts +0 -38
  205. package/src/modules/pricing/service.ts +0 -494
  206. package/src/modules/promotions/repository/index.ts +0 -325
  207. package/src/modules/promotions/schema.ts +0 -62
  208. package/src/modules/promotions/schemas.ts +0 -38
  209. package/src/modules/promotions/service.ts +0 -598
  210. package/src/modules/search/adapter.ts +0 -57
  211. package/src/modules/search/hooks.ts +0 -12
  212. package/src/modules/search/repository/index.ts +0 -6
  213. package/src/modules/search/service.ts +0 -315
  214. package/src/modules/shipping/calculator.ts +0 -188
  215. package/src/modules/shipping/repository/index.ts +0 -6
  216. package/src/modules/shipping/service.ts +0 -51
  217. package/src/modules/tax/adapter.ts +0 -60
  218. package/src/modules/tax/repository/index.ts +0 -6
  219. package/src/modules/tax/service.ts +0 -53
  220. package/src/modules/webhooks/hook.ts +0 -34
  221. package/src/modules/webhooks/repository/index.ts +0 -278
  222. package/src/modules/webhooks/schema.ts +0 -56
  223. package/src/modules/webhooks/service.ts +0 -117
  224. package/src/modules/webhooks/signing.ts +0 -6
  225. package/src/modules/webhooks/ssrf-guard.ts +0 -71
  226. package/src/modules/webhooks/tasks.ts +0 -52
  227. package/src/modules/webhooks/worker.ts +0 -134
  228. package/src/runtime/commerce.ts +0 -145
  229. package/src/runtime/kernel.ts +0 -419
  230. package/src/runtime/logger.ts +0 -36
  231. package/src/runtime/server.ts +0 -349
  232. package/src/runtime/shutdown.ts +0 -43
  233. package/src/test-utils/create-pglite-adapter.ts +0 -129
  234. package/src/test-utils/create-plugin-test-app.ts +0 -128
  235. package/src/test-utils/create-repository-test-harness.ts +0 -16
  236. package/src/test-utils/create-test-config.ts +0 -190
  237. package/src/test-utils/create-test-kernel.ts +0 -7
  238. package/src/test-utils/create-test-plugin-context.ts +0 -75
  239. package/src/test-utils/rest-api-test-utils.ts +0 -265
  240. package/src/test-utils/test-actors.ts +0 -62
  241. package/src/test-utils/typed-hooks.ts +0 -54
  242. package/src/types/commerce-types.ts +0 -34
  243. package/src/utils/id.ts +0 -3
  244. package/src/utils/logger.ts +0 -18
  245. package/src/utils/pagination.ts +0 -22
@@ -1,772 +0,0 @@
1
- import { eq, and, inArray, type SQL } from "drizzle-orm";
2
- import type { TxContext } from "../../../kernel/database/tx-context.js";
3
- import type {
4
- DrizzleDatabase,
5
- DbOrTx,
6
- } from "../../../kernel/database/drizzle-db.js";
7
- import {
8
- sellableEntities,
9
- sellableAttributes,
10
- sellableCustomFields,
11
- categories,
12
- entityCategories,
13
- brands,
14
- entityBrands,
15
- optionTypes,
16
- optionValues,
17
- variants,
18
- variantOptionValues,
19
- } from "../schema.js";
20
-
21
- // Infer types from Drizzle schema
22
- export type SellableEntity = typeof sellableEntities.$inferSelect;
23
- export type SellableEntityInsert = typeof sellableEntities.$inferInsert;
24
- export type SellableAttribute = typeof sellableAttributes.$inferSelect;
25
- export type SellableAttributeInsert = typeof sellableAttributes.$inferInsert;
26
- export type SellableCustomField = typeof sellableCustomFields.$inferSelect;
27
- export type SellableCustomFieldInsert =
28
- typeof sellableCustomFields.$inferInsert;
29
- export type Category = typeof categories.$inferSelect;
30
- export type CategoryInsert = typeof categories.$inferInsert;
31
- export type EntityCategory = typeof entityCategories.$inferSelect;
32
- export type EntityCategoryInsert = typeof entityCategories.$inferInsert;
33
- export type Brand = typeof brands.$inferSelect;
34
- export type BrandInsert = typeof brands.$inferInsert;
35
- export type EntityBrand = typeof entityBrands.$inferSelect;
36
- export type EntityBrandInsert = typeof entityBrands.$inferInsert;
37
- export type OptionType = typeof optionTypes.$inferSelect;
38
- export type OptionTypeInsert = typeof optionTypes.$inferInsert;
39
- export type OptionValue = typeof optionValues.$inferSelect;
40
- export type OptionValueInsert = typeof optionValues.$inferInsert;
41
- export type Variant = typeof variants.$inferSelect;
42
- export type VariantInsert = typeof variants.$inferInsert;
43
- export type VariantOptionValue = typeof variantOptionValues.$inferSelect;
44
- export type VariantOptionValueInsert = typeof variantOptionValues.$inferInsert;
45
-
46
- /**
47
- * CatalogRepository provides type-safe database operations for catalog entities.
48
- *
49
- * This repository uses Drizzle ORM with PostgresJsDatabase for full type inference.
50
- * Transaction context is passed through TxContext when needed for transactional writes.
51
- *
52
- * All methods support an optional TxContext parameter for transaction participation.
53
- * When ctx is provided, operations run within that transaction; otherwise they use the main db.
54
- */
55
- export class CatalogRepository {
56
- constructor(private readonly db: DrizzleDatabase) {}
57
-
58
- /**
59
- * Returns the appropriate database context - either a transaction or the main db.
60
- * Both DrizzleDatabase and DrizzleTx have the same query builder interface.
61
- */
62
- private getDb(ctx?: TxContext): DbOrTx {
63
- return (ctx?.tx as DbOrTx | undefined) ?? this.db;
64
- }
65
-
66
- // ─────────────────────────────────────────────────────────────────────────────
67
- // Sellable Entities
68
- // ─────────────────────────────────────────────────────────────────────────────
69
-
70
- async findEntityById(
71
- id: string,
72
- ctx?: TxContext,
73
- ): Promise<SellableEntity | undefined> {
74
- const db = this.getDb(ctx);
75
- const rows = await db
76
- .select()
77
- .from(sellableEntities)
78
- .where(eq(sellableEntities.id, id));
79
- return rows[0];
80
- }
81
-
82
- async findEntityBySlug(
83
- orgId: string,
84
- slug: string,
85
- ctx?: TxContext,
86
- ): Promise<SellableEntity | undefined> {
87
- const db = this.getDb(ctx);
88
- const rows = await db
89
- .select()
90
- .from(sellableEntities)
91
- .where(
92
- and(
93
- eq(sellableEntities.organizationId, orgId),
94
- eq(sellableEntities.slug, slug),
95
- ),
96
- );
97
- return rows[0];
98
- }
99
-
100
- async findEntities(
101
- orgId: string,
102
- filter?: {
103
- type?: string;
104
- status?: string;
105
- ids?: string[];
106
- },
107
- ctx?: TxContext,
108
- ): Promise<SellableEntity[]> {
109
- const db = this.getDb(ctx);
110
- const conditions: SQL[] = [eq(sellableEntities.organizationId, orgId)];
111
-
112
- if (filter?.type) {
113
- conditions.push(eq(sellableEntities.type, filter.type));
114
- }
115
- if (filter?.status) {
116
- conditions.push(
117
- eq(sellableEntities.status, filter.status as SellableEntity["status"]),
118
- );
119
- }
120
- if (filter?.ids && filter.ids.length > 0) {
121
- conditions.push(inArray(sellableEntities.id, filter.ids));
122
- }
123
-
124
- return db
125
- .select()
126
- .from(sellableEntities)
127
- .where(conditions.length === 1 ? conditions[0] : and(...conditions));
128
- }
129
-
130
- async createEntity(
131
- data: SellableEntityInsert,
132
- ctx?: TxContext,
133
- ): Promise<SellableEntity> {
134
- const db = this.getDb(ctx);
135
- const rows = await db.insert(sellableEntities).values(data).returning();
136
- return rows[0]!;
137
- }
138
-
139
- async updateEntity(
140
- id: string,
141
- data: Partial<Omit<SellableEntityInsert, "id">>,
142
- ctx?: TxContext,
143
- ): Promise<SellableEntity | undefined> {
144
- const db = this.getDb(ctx);
145
- const rows = await db
146
- .update(sellableEntities)
147
- .set({ ...data, updatedAt: new Date() })
148
- .where(eq(sellableEntities.id, id))
149
- .returning();
150
- return rows[0];
151
- }
152
-
153
- async deleteEntity(id: string, ctx?: TxContext): Promise<boolean> {
154
- const db = this.getDb(ctx);
155
- const result = await db
156
- .delete(sellableEntities)
157
- .where(eq(sellableEntities.id, id))
158
- .returning();
159
- return result.length > 0;
160
- }
161
-
162
- // ─────────────────────────────────────────────────────────────────────────────
163
- // Sellable Attributes
164
- // ─────────────────────────────────────────────────────────────────────────────
165
-
166
- async findAttributesByEntityId(
167
- entityId: string,
168
- ctx?: TxContext,
169
- ): Promise<SellableAttribute[]> {
170
- const db = this.getDb(ctx);
171
- return db
172
- .select()
173
- .from(sellableAttributes)
174
- .where(eq(sellableAttributes.entityId, entityId));
175
- }
176
-
177
- async findAttributeByLocale(
178
- entityId: string,
179
- locale: string,
180
- ctx?: TxContext,
181
- ): Promise<SellableAttribute | undefined> {
182
- const db = this.getDb(ctx);
183
- const rows = await db
184
- .select()
185
- .from(sellableAttributes)
186
- .where(
187
- and(
188
- eq(sellableAttributes.entityId, entityId),
189
- eq(sellableAttributes.locale, locale),
190
- ),
191
- );
192
- return rows[0];
193
- }
194
-
195
- async createAttribute(
196
- data: SellableAttributeInsert,
197
- ctx?: TxContext,
198
- ): Promise<SellableAttribute> {
199
- const db = this.getDb(ctx);
200
- const rows = await db.insert(sellableAttributes).values(data).returning();
201
- return rows[0]!;
202
- }
203
-
204
- async updateAttribute(
205
- id: string,
206
- data: Partial<Omit<SellableAttributeInsert, "id">>,
207
- ctx?: TxContext,
208
- ): Promise<SellableAttribute | undefined> {
209
- const db = this.getDb(ctx);
210
- const rows = await db
211
- .update(sellableAttributes)
212
- .set(data)
213
- .where(eq(sellableAttributes.id, id))
214
- .returning();
215
- return rows[0];
216
- }
217
-
218
- async upsertAttribute(
219
- entityId: string,
220
- locale: string,
221
- data: Omit<SellableAttributeInsert, "entityId" | "locale">,
222
- ctx?: TxContext,
223
- ): Promise<SellableAttribute> {
224
- const existing = await this.findAttributeByLocale(entityId, locale, ctx);
225
- if (existing) {
226
- const updated = await this.updateAttribute(existing.id, data, ctx);
227
- return updated!;
228
- }
229
- return this.createAttribute({ ...data, entityId, locale }, ctx);
230
- }
231
-
232
- async deleteAttributesByEntityId(
233
- entityId: string,
234
- ctx?: TxContext,
235
- ): Promise<void> {
236
- const db = this.getDb(ctx);
237
- await db
238
- .delete(sellableAttributes)
239
- .where(eq(sellableAttributes.entityId, entityId));
240
- }
241
-
242
- // ─────────────────────────────────────────────────────────────────────────────
243
- // Custom Fields
244
- // ─────────────────────────────────────────────────────────────────────────────
245
-
246
- async findCustomFieldsByEntityId(
247
- entityId: string,
248
- ctx?: TxContext,
249
- ): Promise<SellableCustomField[]> {
250
- const db = this.getDb(ctx);
251
- return db
252
- .select()
253
- .from(sellableCustomFields)
254
- .where(eq(sellableCustomFields.entityId, entityId));
255
- }
256
-
257
- async createCustomField(
258
- data: SellableCustomFieldInsert,
259
- ctx?: TxContext,
260
- ): Promise<SellableCustomField> {
261
- const db = this.getDb(ctx);
262
- const rows = await db.insert(sellableCustomFields).values(data).returning();
263
- return rows[0]!;
264
- }
265
-
266
- async deleteCustomFieldsByEntityId(
267
- entityId: string,
268
- ctx?: TxContext,
269
- ): Promise<void> {
270
- const db = this.getDb(ctx);
271
- await db
272
- .delete(sellableCustomFields)
273
- .where(eq(sellableCustomFields.entityId, entityId));
274
- }
275
-
276
- // ─────────────────────────────────────────────────────────────────────────────
277
- // Categories
278
- // ─────────────────────────────────────────────────────────────────────────────
279
-
280
- async findCategoryById(
281
- id: string,
282
- ctx?: TxContext,
283
- ): Promise<Category | undefined> {
284
- const db = this.getDb(ctx);
285
- const rows = await db
286
- .select()
287
- .from(categories)
288
- .where(eq(categories.id, id));
289
- return rows[0];
290
- }
291
-
292
- async findCategoryBySlug(
293
- orgId: string,
294
- slug: string,
295
- ctx?: TxContext,
296
- ): Promise<Category | undefined> {
297
- const db = this.getDb(ctx);
298
- const rows = await db
299
- .select()
300
- .from(categories)
301
- .where(
302
- and(
303
- eq(categories.organizationId, orgId),
304
- eq(categories.slug, slug),
305
- ),
306
- );
307
- return rows[0];
308
- }
309
-
310
- async findAllCategories(
311
- orgId: string,
312
- ctx?: TxContext,
313
- ): Promise<Category[]> {
314
- const db = this.getDb(ctx);
315
- return db
316
- .select()
317
- .from(categories)
318
- .where(eq(categories.organizationId, orgId));
319
- }
320
-
321
- async createCategory(
322
- data: CategoryInsert,
323
- ctx?: TxContext,
324
- ): Promise<Category> {
325
- const db = this.getDb(ctx);
326
- const rows = await db.insert(categories).values(data).returning();
327
- return rows[0]!;
328
- }
329
-
330
- async updateCategory(
331
- id: string,
332
- data: Partial<Omit<CategoryInsert, "id">>,
333
- ctx?: TxContext,
334
- ): Promise<Category | undefined> {
335
- const db = this.getDb(ctx);
336
- const rows = await db
337
- .update(categories)
338
- .set(data)
339
- .where(eq(categories.id, id))
340
- .returning();
341
- return rows[0];
342
- }
343
-
344
- async deleteCategory(id: string, ctx?: TxContext): Promise<boolean> {
345
- const db = this.getDb(ctx);
346
- const result = await db
347
- .delete(categories)
348
- .where(eq(categories.id, id))
349
- .returning();
350
- return result.length > 0;
351
- }
352
-
353
- // ─────────────────────────────────────────────────────────────────────────────
354
- // Entity Categories (Join Table)
355
- // ─────────────────────────────────────────────────────────────────────────────
356
-
357
- async findEntityCategories(
358
- entityId: string,
359
- ctx?: TxContext,
360
- ): Promise<EntityCategory[]> {
361
- const db = this.getDb(ctx);
362
- return db
363
- .select()
364
- .from(entityCategories)
365
- .where(eq(entityCategories.entityId, entityId));
366
- }
367
-
368
- async findEntitiesByCategory(
369
- categoryId: string,
370
- ctx?: TxContext,
371
- ): Promise<string[]> {
372
- const db = this.getDb(ctx);
373
- const rows = await db
374
- .select()
375
- .from(entityCategories)
376
- .where(eq(entityCategories.categoryId, categoryId));
377
- return rows.map((r) => r.entityId);
378
- }
379
-
380
- async addEntityToCategory(
381
- entityId: string,
382
- categoryId: string,
383
- sortOrder = 0,
384
- ctx?: TxContext,
385
- ): Promise<void> {
386
- const db = this.getDb(ctx);
387
- await db
388
- .insert(entityCategories)
389
- .values({ entityId, categoryId, sortOrder })
390
- .onConflictDoNothing();
391
- }
392
-
393
- async removeEntityFromCategory(
394
- entityId: string,
395
- categoryId: string,
396
- ctx?: TxContext,
397
- ): Promise<boolean> {
398
- const db = this.getDb(ctx);
399
- const result = await db
400
- .delete(entityCategories)
401
- .where(
402
- and(
403
- eq(entityCategories.entityId, entityId),
404
- eq(entityCategories.categoryId, categoryId),
405
- ),
406
- )
407
- .returning();
408
- return result.length > 0;
409
- }
410
-
411
- async deleteEntityCategoriesByEntityId(
412
- entityId: string,
413
- ctx?: TxContext,
414
- ): Promise<void> {
415
- const db = this.getDb(ctx);
416
- await db
417
- .delete(entityCategories)
418
- .where(eq(entityCategories.entityId, entityId));
419
- }
420
-
421
- async deleteEntityCategoriesByCategoryId(
422
- categoryId: string,
423
- ctx?: TxContext,
424
- ): Promise<void> {
425
- const db = this.getDb(ctx);
426
- await db
427
- .delete(entityCategories)
428
- .where(eq(entityCategories.categoryId, categoryId));
429
- }
430
-
431
- // ─────────────────────────────────────────────────────────────────────────────
432
- // Brands
433
- // ─────────────────────────────────────────────────────────────────────────────
434
-
435
- async findBrandById(id: string, ctx?: TxContext): Promise<Brand | undefined> {
436
- const db = this.getDb(ctx);
437
- const rows = await db.select().from(brands).where(eq(brands.id, id));
438
- return rows[0];
439
- }
440
-
441
- async findBrandBySlug(
442
- orgId: string,
443
- slug: string,
444
- ctx?: TxContext,
445
- ): Promise<Brand | undefined> {
446
- const db = this.getDb(ctx);
447
- const rows = await db
448
- .select()
449
- .from(brands)
450
- .where(
451
- and(
452
- eq(brands.organizationId, orgId),
453
- eq(brands.slug, slug),
454
- ),
455
- );
456
- return rows[0];
457
- }
458
-
459
- async findAllBrands(orgId: string, ctx?: TxContext): Promise<Brand[]> {
460
- const db = this.getDb(ctx);
461
- return db
462
- .select()
463
- .from(brands)
464
- .where(eq(brands.organizationId, orgId));
465
- }
466
-
467
- async createBrand(data: BrandInsert, ctx?: TxContext): Promise<Brand> {
468
- const db = this.getDb(ctx);
469
- const rows = await db.insert(brands).values(data).returning();
470
- return rows[0]!;
471
- }
472
-
473
- async updateBrand(
474
- id: string,
475
- data: Partial<Omit<BrandInsert, "id">>,
476
- ctx?: TxContext,
477
- ): Promise<Brand | undefined> {
478
- const db = this.getDb(ctx);
479
- const rows = await db
480
- .update(brands)
481
- .set(data)
482
- .where(eq(brands.id, id))
483
- .returning();
484
- return rows[0];
485
- }
486
-
487
- async deleteBrand(id: string, ctx?: TxContext): Promise<boolean> {
488
- const db = this.getDb(ctx);
489
- const result = await db.delete(brands).where(eq(brands.id, id)).returning();
490
- return result.length > 0;
491
- }
492
-
493
- // ─────────────────────────────────────────────────────────────────────────────
494
- // Entity Brands (Join Table)
495
- // ─────────────────────────────────────────────────────────────────────────────
496
-
497
- async findEntityBrands(
498
- entityId: string,
499
- ctx?: TxContext,
500
- ): Promise<EntityBrand[]> {
501
- const db = this.getDb(ctx);
502
- return db
503
- .select()
504
- .from(entityBrands)
505
- .where(eq(entityBrands.entityId, entityId));
506
- }
507
-
508
- async addEntityToBrand(
509
- entityId: string,
510
- brandId: string,
511
- sortOrder = 0,
512
- ctx?: TxContext,
513
- ): Promise<void> {
514
- const db = this.getDb(ctx);
515
- await db
516
- .insert(entityBrands)
517
- .values({ entityId, brandId, sortOrder })
518
- .onConflictDoNothing();
519
- }
520
-
521
- async removeEntityFromBrand(
522
- entityId: string,
523
- brandId: string,
524
- ctx?: TxContext,
525
- ): Promise<boolean> {
526
- const db = this.getDb(ctx);
527
- const result = await db
528
- .delete(entityBrands)
529
- .where(
530
- and(
531
- eq(entityBrands.entityId, entityId),
532
- eq(entityBrands.brandId, brandId),
533
- ),
534
- )
535
- .returning();
536
- return result.length > 0;
537
- }
538
-
539
- async deleteEntityBrandsByEntityId(
540
- entityId: string,
541
- ctx?: TxContext,
542
- ): Promise<void> {
543
- const db = this.getDb(ctx);
544
- await db.delete(entityBrands).where(eq(entityBrands.entityId, entityId));
545
- }
546
-
547
- async deleteEntityBrandsByBrandId(
548
- brandId: string,
549
- ctx?: TxContext,
550
- ): Promise<void> {
551
- const db = this.getDb(ctx);
552
- await db.delete(entityBrands).where(eq(entityBrands.brandId, brandId));
553
- }
554
-
555
- // ─────────────────────────────────────────────────────────────────────────────
556
- // Option Types
557
- // ─────────────────────────────────────────────────────────────────────────────
558
-
559
- async findOptionTypesByEntityId(
560
- entityId: string,
561
- ctx?: TxContext,
562
- ): Promise<OptionType[]> {
563
- const db = this.getDb(ctx);
564
- return db
565
- .select()
566
- .from(optionTypes)
567
- .where(eq(optionTypes.entityId, entityId));
568
- }
569
-
570
- async findOptionTypeById(
571
- id: string,
572
- ctx?: TxContext,
573
- ): Promise<OptionType | undefined> {
574
- const db = this.getDb(ctx);
575
- const rows = await db
576
- .select()
577
- .from(optionTypes)
578
- .where(eq(optionTypes.id, id));
579
- return rows[0];
580
- }
581
-
582
- async createOptionType(
583
- data: OptionTypeInsert,
584
- ctx?: TxContext,
585
- ): Promise<OptionType> {
586
- const db = this.getDb(ctx);
587
- const rows = await db.insert(optionTypes).values(data).returning();
588
- return rows[0]!;
589
- }
590
-
591
- async deleteOptionTypesByEntityId(
592
- entityId: string,
593
- ctx?: TxContext,
594
- ): Promise<void> {
595
- const db = this.getDb(ctx);
596
- await db.delete(optionTypes).where(eq(optionTypes.entityId, entityId));
597
- }
598
-
599
- // ─────────────────────────────────────────────────────────────────────────────
600
- // Option Values
601
- // ─────────────────────────────────────────────────────────────────────────────
602
-
603
- async findOptionValuesByTypeId(
604
- optionTypeId: string,
605
- ctx?: TxContext,
606
- ): Promise<OptionValue[]> {
607
- const db = this.getDb(ctx);
608
- return db
609
- .select()
610
- .from(optionValues)
611
- .where(eq(optionValues.optionTypeId, optionTypeId));
612
- }
613
-
614
- async findOptionValueById(
615
- id: string,
616
- ctx?: TxContext,
617
- ): Promise<OptionValue | undefined> {
618
- const db = this.getDb(ctx);
619
- const rows = await db
620
- .select()
621
- .from(optionValues)
622
- .where(eq(optionValues.id, id));
623
- return rows[0];
624
- }
625
-
626
- async findOptionValuesByIds(
627
- ids: string[],
628
- ctx?: TxContext,
629
- ): Promise<OptionValue[]> {
630
- if (ids.length === 0) return [];
631
- const db = this.getDb(ctx);
632
- return db.select().from(optionValues).where(inArray(optionValues.id, ids));
633
- }
634
-
635
- async createOptionValue(
636
- data: OptionValueInsert,
637
- ctx?: TxContext,
638
- ): Promise<OptionValue> {
639
- const db = this.getDb(ctx);
640
- const rows = await db.insert(optionValues).values(data).returning();
641
- return rows[0]!;
642
- }
643
-
644
- async deleteOptionValuesByTypeId(
645
- optionTypeId: string,
646
- ctx?: TxContext,
647
- ): Promise<void> {
648
- const db = this.getDb(ctx);
649
- await db
650
- .delete(optionValues)
651
- .where(eq(optionValues.optionTypeId, optionTypeId));
652
- }
653
-
654
- // ─────────────────────────────────────────────────────────────────────────────
655
- // Variants
656
- // ─────────────────────────────────────────────────────────────────────────────
657
-
658
- async findVariantsByEntityId(
659
- entityId: string,
660
- ctx?: TxContext,
661
- ): Promise<Variant[]> {
662
- const db = this.getDb(ctx);
663
- return db.select().from(variants).where(eq(variants.entityId, entityId));
664
- }
665
-
666
- async findVariantById(
667
- id: string,
668
- ctx?: TxContext,
669
- ): Promise<Variant | undefined> {
670
- const db = this.getDb(ctx);
671
- const rows = await db.select().from(variants).where(eq(variants.id, id));
672
- return rows[0];
673
- }
674
-
675
- async findVariantBySku(
676
- sku: string,
677
- ctx?: TxContext,
678
- ): Promise<Variant | undefined> {
679
- const db = this.getDb(ctx);
680
- const rows = await db.select().from(variants).where(eq(variants.sku, sku));
681
- return rows[0];
682
- }
683
-
684
- async findVariantByBarcode(
685
- barcode: string,
686
- ctx?: TxContext,
687
- ): Promise<Variant | undefined> {
688
- const db = this.getDb(ctx);
689
- const rows = await db
690
- .select()
691
- .from(variants)
692
- .where(eq(variants.barcode, barcode));
693
- return rows[0];
694
- }
695
-
696
- async createVariant(data: VariantInsert, ctx?: TxContext): Promise<Variant> {
697
- const db = this.getDb(ctx);
698
- const rows = await db.insert(variants).values(data).returning();
699
- return rows[0]!;
700
- }
701
-
702
- async updateVariant(
703
- id: string,
704
- data: Partial<Omit<VariantInsert, "id">>,
705
- ctx?: TxContext,
706
- ): Promise<Variant | undefined> {
707
- const db = this.getDb(ctx);
708
- const rows = await db
709
- .update(variants)
710
- .set(data)
711
- .where(eq(variants.id, id))
712
- .returning();
713
- return rows[0];
714
- }
715
-
716
- async deleteVariantsByEntityId(
717
- entityId: string,
718
- ctx?: TxContext,
719
- ): Promise<void> {
720
- const db = this.getDb(ctx);
721
- await db.delete(variants).where(eq(variants.entityId, entityId));
722
- }
723
-
724
- // ─────────────────────────────────────────────────────────────────────────────
725
- // Variant Option Values (Join Table)
726
- // ─────────────────────────────────────────────────────────────────────────────
727
-
728
- async findVariantOptionValues(
729
- variantId: string,
730
- ctx?: TxContext,
731
- ): Promise<VariantOptionValue[]> {
732
- const db = this.getDb(ctx);
733
- return db
734
- .select()
735
- .from(variantOptionValues)
736
- .where(eq(variantOptionValues.variantId, variantId));
737
- }
738
-
739
- async createVariantOptionValues(
740
- data: VariantOptionValueInsert[],
741
- ctx?: TxContext,
742
- ): Promise<void> {
743
- if (data.length === 0) return;
744
- const db = this.getDb(ctx);
745
- await db.insert(variantOptionValues).values(data).onConflictDoNothing();
746
- }
747
-
748
- async deleteVariantOptionValuesByVariantId(
749
- variantId: string,
750
- ctx?: TxContext,
751
- ): Promise<void> {
752
- const db = this.getDb(ctx);
753
- await db
754
- .delete(variantOptionValues)
755
- .where(eq(variantOptionValues.variantId, variantId));
756
- }
757
-
758
- async deleteVariantOptionValuesByEntityId(
759
- entityId: string,
760
- ctx?: TxContext,
761
- ): Promise<void> {
762
- const db = this.getDb(ctx);
763
- // Get all variant IDs for this entity first
764
- const entityVariants = await this.findVariantsByEntityId(entityId, ctx);
765
- const variantIds = entityVariants.map((v) => v.id);
766
- if (variantIds.length > 0) {
767
- await db
768
- .delete(variantOptionValues)
769
- .where(inArray(variantOptionValues.variantId, variantIds));
770
- }
771
- }
772
- }