@unifiedcommerce/core 0.0.4 → 0.1.1

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 (179) hide show
  1. package/dist/auth/auth-schema.d.ts +92 -0
  2. package/dist/auth/auth-schema.d.ts.map +1 -1
  3. package/dist/auth/auth-schema.js +7 -0
  4. package/dist/auth/setup.d.ts.map +1 -1
  5. package/dist/auth/setup.js +3 -1
  6. package/package.json +1 -2
  7. package/src/adapters/console-email.ts +0 -43
  8. package/src/auth/access.ts +0 -187
  9. package/src/auth/auth-schema.ts +0 -131
  10. package/src/auth/middleware.ts +0 -161
  11. package/src/auth/org.ts +0 -41
  12. package/src/auth/permissions.ts +0 -28
  13. package/src/auth/setup.ts +0 -165
  14. package/src/auth/system-actor.ts +0 -19
  15. package/src/auth/types.ts +0 -10
  16. package/src/config/defaults.ts +0 -82
  17. package/src/config/define-config.ts +0 -53
  18. package/src/config/types.ts +0 -299
  19. package/src/generated/plugin-capabilities.d.ts +0 -20
  20. package/src/generated/plugin-manifest.ts +0 -23
  21. package/src/generated/plugin-repositories.d.ts +0 -20
  22. package/src/hooks/checkout-completion.ts +0 -262
  23. package/src/hooks/checkout.ts +0 -677
  24. package/src/hooks/order-emails.ts +0 -62
  25. package/src/index.ts +0 -214
  26. package/src/interfaces/mcp/agent-prompt.ts +0 -174
  27. package/src/interfaces/mcp/context-enrichment.ts +0 -177
  28. package/src/interfaces/mcp/server.ts +0 -617
  29. package/src/interfaces/mcp/transport.ts +0 -68
  30. package/src/interfaces/rest/customer-portal.ts +0 -299
  31. package/src/interfaces/rest/index.ts +0 -74
  32. package/src/interfaces/rest/router.ts +0 -334
  33. package/src/interfaces/rest/routes/admin-jobs.ts +0 -58
  34. package/src/interfaces/rest/routes/audit.ts +0 -50
  35. package/src/interfaces/rest/routes/carts.ts +0 -89
  36. package/src/interfaces/rest/routes/catalog.ts +0 -493
  37. package/src/interfaces/rest/routes/checkout.ts +0 -283
  38. package/src/interfaces/rest/routes/inventory.ts +0 -70
  39. package/src/interfaces/rest/routes/media.ts +0 -86
  40. package/src/interfaces/rest/routes/orders.ts +0 -78
  41. package/src/interfaces/rest/routes/payments.ts +0 -60
  42. package/src/interfaces/rest/routes/pricing.ts +0 -57
  43. package/src/interfaces/rest/routes/promotions.ts +0 -92
  44. package/src/interfaces/rest/routes/search.ts +0 -71
  45. package/src/interfaces/rest/routes/webhooks.ts +0 -46
  46. package/src/interfaces/rest/schemas/admin-jobs.ts +0 -40
  47. package/src/interfaces/rest/schemas/audit.ts +0 -46
  48. package/src/interfaces/rest/schemas/carts.ts +0 -125
  49. package/src/interfaces/rest/schemas/catalog.ts +0 -450
  50. package/src/interfaces/rest/schemas/checkout.ts +0 -66
  51. package/src/interfaces/rest/schemas/customer-portal.ts +0 -195
  52. package/src/interfaces/rest/schemas/inventory.ts +0 -138
  53. package/src/interfaces/rest/schemas/media.ts +0 -75
  54. package/src/interfaces/rest/schemas/orders.ts +0 -104
  55. package/src/interfaces/rest/schemas/pricing.ts +0 -80
  56. package/src/interfaces/rest/schemas/promotions.ts +0 -110
  57. package/src/interfaces/rest/schemas/responses.ts +0 -85
  58. package/src/interfaces/rest/schemas/search.ts +0 -58
  59. package/src/interfaces/rest/schemas/shared.ts +0 -62
  60. package/src/interfaces/rest/schemas/webhooks.ts +0 -68
  61. package/src/interfaces/rest/utils.ts +0 -104
  62. package/src/interfaces/rest/webhook-router.ts +0 -50
  63. package/src/kernel/compensation/executor.ts +0 -61
  64. package/src/kernel/compensation/types.ts +0 -26
  65. package/src/kernel/database/adapter.ts +0 -13
  66. package/src/kernel/database/drizzle-db.ts +0 -56
  67. package/src/kernel/database/migrate.ts +0 -76
  68. package/src/kernel/database/plugin-types.ts +0 -34
  69. package/src/kernel/database/schema.ts +0 -49
  70. package/src/kernel/database/scoped-db.ts +0 -68
  71. package/src/kernel/database/tx-context.ts +0 -46
  72. package/src/kernel/error-mapper.ts +0 -15
  73. package/src/kernel/errors.ts +0 -89
  74. package/src/kernel/factory/repository-factory.ts +0 -242
  75. package/src/kernel/hooks/create-context.ts +0 -43
  76. package/src/kernel/hooks/executor.ts +0 -88
  77. package/src/kernel/hooks/registry.ts +0 -74
  78. package/src/kernel/hooks/types.ts +0 -52
  79. package/src/kernel/http-error.ts +0 -44
  80. package/src/kernel/jobs/adapter.ts +0 -36
  81. package/src/kernel/jobs/drizzle-adapter.ts +0 -58
  82. package/src/kernel/jobs/runner.ts +0 -153
  83. package/src/kernel/jobs/schema.ts +0 -46
  84. package/src/kernel/jobs/types.ts +0 -30
  85. package/src/kernel/local-api.ts +0 -185
  86. package/src/kernel/plugin/manifest.ts +0 -253
  87. package/src/kernel/query/executor.ts +0 -184
  88. package/src/kernel/query/registry.ts +0 -46
  89. package/src/kernel/result.ts +0 -33
  90. package/src/kernel/schema/extra-columns.ts +0 -37
  91. package/src/kernel/service-registry.ts +0 -76
  92. package/src/kernel/service-timing.ts +0 -89
  93. package/src/kernel/state-machine/machine.ts +0 -101
  94. package/src/modules/analytics/drizzle-adapter.ts +0 -426
  95. package/src/modules/analytics/hooks.ts +0 -11
  96. package/src/modules/analytics/models.ts +0 -125
  97. package/src/modules/analytics/repository/index.ts +0 -6
  98. package/src/modules/analytics/service.ts +0 -245
  99. package/src/modules/analytics/types.ts +0 -180
  100. package/src/modules/audit/hooks.ts +0 -78
  101. package/src/modules/audit/schema.ts +0 -33
  102. package/src/modules/audit/service.ts +0 -151
  103. package/src/modules/cart/access.ts +0 -27
  104. package/src/modules/cart/matcher.ts +0 -26
  105. package/src/modules/cart/repository/index.ts +0 -234
  106. package/src/modules/cart/schema.ts +0 -42
  107. package/src/modules/cart/schemas.ts +0 -38
  108. package/src/modules/cart/service.ts +0 -541
  109. package/src/modules/catalog/repository/index.ts +0 -772
  110. package/src/modules/catalog/schema.ts +0 -203
  111. package/src/modules/catalog/schemas.ts +0 -104
  112. package/src/modules/catalog/service.ts +0 -1544
  113. package/src/modules/customers/repository/index.ts +0 -327
  114. package/src/modules/customers/schema.ts +0 -64
  115. package/src/modules/customers/service.ts +0 -171
  116. package/src/modules/fulfillment/repository/index.ts +0 -426
  117. package/src/modules/fulfillment/schema.ts +0 -101
  118. package/src/modules/fulfillment/service.ts +0 -555
  119. package/src/modules/fulfillment/types.ts +0 -59
  120. package/src/modules/inventory/repository/index.ts +0 -509
  121. package/src/modules/inventory/schema.ts +0 -94
  122. package/src/modules/inventory/schemas.ts +0 -38
  123. package/src/modules/inventory/service.ts +0 -490
  124. package/src/modules/media/adapter.ts +0 -17
  125. package/src/modules/media/repository/index.ts +0 -274
  126. package/src/modules/media/schema.ts +0 -41
  127. package/src/modules/media/service.ts +0 -151
  128. package/src/modules/orders/repository/index.ts +0 -287
  129. package/src/modules/orders/schema.ts +0 -66
  130. package/src/modules/orders/service.ts +0 -619
  131. package/src/modules/orders/stale-order-cleanup.ts +0 -76
  132. package/src/modules/organization/service.ts +0 -191
  133. package/src/modules/payments/adapter.ts +0 -47
  134. package/src/modules/payments/repository/index.ts +0 -6
  135. package/src/modules/payments/service.ts +0 -107
  136. package/src/modules/pricing/repository/index.ts +0 -291
  137. package/src/modules/pricing/schema.ts +0 -71
  138. package/src/modules/pricing/schemas.ts +0 -38
  139. package/src/modules/pricing/service.ts +0 -494
  140. package/src/modules/promotions/repository/index.ts +0 -325
  141. package/src/modules/promotions/schema.ts +0 -62
  142. package/src/modules/promotions/schemas.ts +0 -38
  143. package/src/modules/promotions/service.ts +0 -598
  144. package/src/modules/search/adapter.ts +0 -57
  145. package/src/modules/search/hooks.ts +0 -12
  146. package/src/modules/search/repository/index.ts +0 -6
  147. package/src/modules/search/service.ts +0 -315
  148. package/src/modules/shipping/calculator.ts +0 -188
  149. package/src/modules/shipping/repository/index.ts +0 -6
  150. package/src/modules/shipping/service.ts +0 -51
  151. package/src/modules/tax/adapter.ts +0 -60
  152. package/src/modules/tax/repository/index.ts +0 -6
  153. package/src/modules/tax/service.ts +0 -53
  154. package/src/modules/webhooks/hook.ts +0 -34
  155. package/src/modules/webhooks/repository/index.ts +0 -278
  156. package/src/modules/webhooks/schema.ts +0 -56
  157. package/src/modules/webhooks/service.ts +0 -117
  158. package/src/modules/webhooks/signing.ts +0 -6
  159. package/src/modules/webhooks/ssrf-guard.ts +0 -71
  160. package/src/modules/webhooks/tasks.ts +0 -52
  161. package/src/modules/webhooks/worker.ts +0 -134
  162. package/src/runtime/commerce.ts +0 -145
  163. package/src/runtime/kernel.ts +0 -419
  164. package/src/runtime/logger.ts +0 -36
  165. package/src/runtime/server.ts +0 -349
  166. package/src/runtime/shutdown.ts +0 -43
  167. package/src/test-utils/create-pglite-adapter.ts +0 -129
  168. package/src/test-utils/create-plugin-test-app.ts +0 -128
  169. package/src/test-utils/create-repository-test-harness.ts +0 -16
  170. package/src/test-utils/create-test-config.ts +0 -190
  171. package/src/test-utils/create-test-kernel.ts +0 -7
  172. package/src/test-utils/create-test-plugin-context.ts +0 -75
  173. package/src/test-utils/rest-api-test-utils.ts +0 -265
  174. package/src/test-utils/test-actors.ts +0 -62
  175. package/src/test-utils/typed-hooks.ts +0 -54
  176. package/src/types/commerce-types.ts +0 -34
  177. package/src/utils/id.ts +0 -3
  178. package/src/utils/logger.ts +0 -18
  179. 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
- }