@porulle/core 0.9.0 → 0.10.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 (103) hide show
  1. package/dist/config/defaults.js +1 -1
  2. package/dist/config/types.d.ts +4 -3
  3. package/dist/config/types.d.ts.map +1 -1
  4. package/dist/generated/plugin-manifest.d.ts +3 -0
  5. package/dist/generated/plugin-manifest.d.ts.map +1 -1
  6. package/dist/generated/plugin-manifest.js +1 -0
  7. package/dist/index.d.ts +5 -2
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +2 -0
  10. package/dist/interfaces/rest/router.d.ts.map +1 -1
  11. package/dist/interfaces/rest/router.js +2 -0
  12. package/dist/interfaces/rest/routes/checkout.d.ts.map +1 -1
  13. package/dist/interfaces/rest/routes/checkout.js +1 -0
  14. package/dist/interfaces/rest/schemas/catalog.d.ts +391 -0
  15. package/dist/interfaces/rest/schemas/catalog.d.ts.map +1 -1
  16. package/dist/interfaces/rest/schemas/responses.d.ts +51 -0
  17. package/dist/interfaces/rest/schemas/responses.d.ts.map +1 -1
  18. package/dist/interfaces/rest/schemas/search.d.ts +17 -0
  19. package/dist/interfaces/rest/schemas/search.d.ts.map +1 -1
  20. package/dist/kernel/database/scoped-db.d.ts.map +1 -1
  21. package/dist/kernel/database/scoped-db.js +21 -23
  22. package/dist/kernel/errors.d.ts +12 -0
  23. package/dist/kernel/errors.d.ts.map +1 -1
  24. package/dist/kernel/errors.js +16 -0
  25. package/dist/kernel/jobs/adapter.d.ts +27 -8
  26. package/dist/kernel/jobs/adapter.d.ts.map +1 -1
  27. package/dist/kernel/jobs/adapter.js +1 -2
  28. package/dist/kernel/jobs/drizzle-adapter.d.ts +13 -3
  29. package/dist/kernel/jobs/drizzle-adapter.d.ts.map +1 -1
  30. package/dist/kernel/jobs/drizzle-adapter.js +46 -5
  31. package/dist/kernel/jobs/runner.d.ts +2 -1
  32. package/dist/kernel/jobs/runner.d.ts.map +1 -1
  33. package/dist/kernel/jobs/runner.js +100 -15
  34. package/dist/kernel/jobs/types.d.ts +13 -0
  35. package/dist/kernel/jobs/types.d.ts.map +1 -1
  36. package/dist/kernel/plugin/manifest.d.ts +2 -0
  37. package/dist/kernel/plugin/manifest.d.ts.map +1 -1
  38. package/dist/kernel/plugin/manifest.js +9 -0
  39. package/dist/modules/catalog/entity-service.d.ts +1 -0
  40. package/dist/modules/catalog/entity-service.d.ts.map +1 -1
  41. package/dist/modules/catalog/entity-service.js +15 -1
  42. package/dist/modules/catalog/repository/index.d.ts +2 -2
  43. package/dist/modules/catalog/repository/index.d.ts.map +1 -1
  44. package/dist/modules/catalog/repository/index.js +9 -1
  45. package/dist/modules/catalog/schema.d.ts +51 -0
  46. package/dist/modules/catalog/schema.d.ts.map +1 -1
  47. package/dist/modules/catalog/schema.js +12 -1
  48. package/dist/modules/catalog/schemas.d.ts +3 -1
  49. package/dist/modules/catalog/schemas.d.ts.map +1 -1
  50. package/dist/modules/channels/adapter.d.ts +117 -0
  51. package/dist/modules/channels/adapter.d.ts.map +1 -0
  52. package/dist/modules/channels/adapter.js +3 -0
  53. package/dist/modules/inventory/repository/index.js +4 -4
  54. package/dist/modules/inventory/service.d.ts.map +1 -1
  55. package/dist/modules/inventory/service.js +7 -3
  56. package/dist/modules/orders/service.d.ts.map +1 -1
  57. package/dist/modules/orders/service.js +7 -4
  58. package/dist/modules/orders/stale-order-cleanup.d.ts.map +1 -1
  59. package/dist/modules/orders/stale-order-cleanup.js +25 -16
  60. package/dist/modules/promotions/repository/index.d.ts +1 -1
  61. package/dist/modules/promotions/repository/index.d.ts.map +1 -1
  62. package/dist/modules/promotions/repository/index.js +6 -3
  63. package/dist/modules/promotions/service.d.ts +1 -0
  64. package/dist/modules/promotions/service.d.ts.map +1 -1
  65. package/dist/modules/promotions/service.js +1 -1
  66. package/dist/modules/webhooks/repository/index.d.ts +1 -1
  67. package/dist/modules/webhooks/repository/index.d.ts.map +1 -1
  68. package/dist/modules/webhooks/repository/index.js +16 -10
  69. package/dist/runtime/kernel.d.ts.map +1 -1
  70. package/dist/runtime/kernel.js +14 -2
  71. package/dist/runtime/server.d.ts +1 -4
  72. package/dist/runtime/server.d.ts.map +1 -1
  73. package/dist/runtime/server.js +16 -34
  74. package/package.json +1 -1
  75. package/src/config/defaults.ts +1 -1
  76. package/src/config/types.ts +7 -3
  77. package/src/generated/plugin-capabilities.d.ts +1 -0
  78. package/src/generated/plugin-manifest.ts +1 -0
  79. package/src/generated/plugin-repositories.d.ts +1 -0
  80. package/src/index.ts +31 -1
  81. package/src/interfaces/rest/router.ts +2 -0
  82. package/src/interfaces/rest/routes/checkout.ts +1 -0
  83. package/src/kernel/database/scoped-db.ts +25 -26
  84. package/src/kernel/errors.ts +20 -0
  85. package/src/kernel/jobs/adapter.ts +39 -8
  86. package/src/kernel/jobs/drizzle-adapter.ts +72 -9
  87. package/src/kernel/jobs/runner.ts +194 -72
  88. package/src/kernel/jobs/types.ts +25 -0
  89. package/src/kernel/plugin/manifest.ts +12 -0
  90. package/src/modules/catalog/entity-service.ts +9 -1
  91. package/src/modules/catalog/repository/index.ts +13 -3
  92. package/src/modules/catalog/schema.ts +33 -18
  93. package/src/modules/catalog/schemas.ts +3 -1
  94. package/src/modules/channels/adapter.ts +139 -0
  95. package/src/modules/inventory/repository/index.ts +4 -4
  96. package/src/modules/inventory/service.ts +12 -2
  97. package/src/modules/orders/service.ts +8 -12
  98. package/src/modules/orders/stale-order-cleanup.ts +35 -24
  99. package/src/modules/promotions/repository/index.ts +6 -2
  100. package/src/modules/promotions/service.ts +2 -0
  101. package/src/modules/webhooks/repository/index.ts +16 -14
  102. package/src/runtime/kernel.ts +16 -2
  103. package/src/runtime/server.ts +22 -42
@@ -36,25 +36,34 @@ export const staleOrderCleanupTask = {
36
36
  async handler({ input, ctx }) {
37
37
  const thresholdHours = input.thresholdHours ?? 48;
38
38
  const cutoff = new Date(Date.now() - thresholdHours * 60 * 60 * 1000);
39
- // Find stale pending orders
40
- const staleOrders = await ctx.db
41
- .select()
42
- .from(orders)
43
- .where(and(eq(orders.status, "pending"), lt(orders.placedAt, cutoff)));
44
39
  const cancelledIds = [];
45
40
  // Cancel each stale order via the service (triggers inventory release + payment refund)
46
41
  const orderService = ctx.services.orders;
47
- for (const order of staleOrders) {
48
- try {
49
- await orderService.cancel(order.id, systemActorForOrg(order.organizationId), `Auto-cancelled: pending for >${thresholdHours}h`);
50
- cancelledIds.push(order.id);
51
- ctx.logger.info(`Stale order ${order.orderNumber} auto-cancelled`, {
52
- orderId: order.id,
53
- placedAt: order.placedAt,
54
- });
55
- }
56
- catch (error) {
57
- ctx.logger.error(`Failed to cancel stale order ${order.orderNumber}`, { error });
42
+ // This is a cross-org system sweep, but the row reads stay org-scoped: first
43
+ // enumerate the orgs that have stale orders (id-only projection), then read
44
+ // each org's stale orders under an explicit organizationId predicate. No
45
+ // query returns another tenant's order rows.
46
+ const staleOrgs = await ctx.db
47
+ .selectDistinct({ organizationId: orders.organizationId })
48
+ .from(orders)
49
+ .where(and(eq(orders.status, "pending"), lt(orders.placedAt, cutoff)));
50
+ for (const { organizationId } of staleOrgs) {
51
+ const staleOrders = await ctx.db
52
+ .select()
53
+ .from(orders)
54
+ .where(and(eq(orders.organizationId, organizationId), eq(orders.status, "pending"), lt(orders.placedAt, cutoff)));
55
+ for (const order of staleOrders) {
56
+ try {
57
+ await orderService.cancel(order.id, systemActorForOrg(order.organizationId), `Auto-cancelled: pending for >${thresholdHours}h`);
58
+ cancelledIds.push(order.id);
59
+ ctx.logger.info(`Stale order ${order.orderNumber} auto-cancelled`, {
60
+ orderId: order.id,
61
+ placedAt: order.placedAt,
62
+ });
63
+ }
64
+ catch (error) {
65
+ ctx.logger.error(`Failed to cancel stale order ${order.orderNumber}`, { error });
66
+ }
58
67
  }
59
68
  }
60
69
  return {
@@ -28,7 +28,7 @@ export declare class PromotionsRepository {
28
28
  findUsageById(id: string, ctx?: TxContext): Promise<PromotionUsage | undefined>;
29
29
  findUsagesByPromotionId(promotionId: string, ctx?: TxContext): Promise<PromotionUsage[]>;
30
30
  findUsagesByCustomerId(customerId: string, ctx?: TxContext): Promise<PromotionUsage[]>;
31
- createUsage(data: PromotionUsageInsert, ctx?: TxContext): Promise<PromotionUsage>;
31
+ createUsage(data: PromotionUsageInsert, orgId: string, ctx?: TxContext): Promise<PromotionUsage>;
32
32
  countUsages(promotionId: string, ctx?: TxContext): Promise<number>;
33
33
  countUsagesByCustomer(promotionId: string, customerId: string, ctx?: TxContext): Promise<number>;
34
34
  isUsageLimitReached(orgId: string, promotionId: string, ctx?: TxContext): Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/promotions/repository/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/promotions/repository/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG3D,MAAM,MAAM,SAAS,GAAG,OAAO,UAAU,CAAC,YAAY,CAAC;AACvD,MAAM,MAAM,eAAe,GAAG,OAAO,UAAU,CAAC,YAAY,CAAC;AAC7D,MAAM,MAAM,cAAc,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AACjE,MAAM,MAAM,oBAAoB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AAEvE;;;;;GAKG;AACH,qBAAa,oBAAoB;IACnB,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,eAAe;IAEhD,OAAO,CAAC,KAAK;IAQP,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IASpF,UAAU,CACd,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAc3B,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAS7D,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAkBhE,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAmBnE,MAAM,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IAMlE,MAAM,CACV,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,EAC1C,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAU3B,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IASrD,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAIrE,UAAU,CACd,EAAE,EAAE,MAAM,EACV,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAQ3B,aAAa,CACjB,EAAE,EAAE,MAAM,EACV,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAShC,uBAAuB,CAC3B,WAAW,EAAE,MAAM,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,cAAc,EAAE,CAAC;IAQtB,sBAAsB,CAC1B,UAAU,EAAE,MAAM,EAClB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,cAAc,EAAE,CAAC;IAQtB,WAAW,CACf,IAAI,EAAE,oBAAoB,EAC1B,KAAK,EAAE,MAAM,EACb,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,cAAc,CAAC;IA0CpB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IASlE,qBAAqB,CACzB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC;IAkBZ,mBAAmB,CACvB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,OAAO,CAAC;IASb,2BAA2B,CAC/B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,OAAO,CAAC;IAab,gBAAgB,CACpB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAiChD"}
@@ -112,16 +112,19 @@ export class PromotionsRepository {
112
112
  .from(promotionUsages)
113
113
  .where(eq(promotionUsages.customerId, customerId));
114
114
  }
115
- async createUsage(data, ctx) {
115
+ async createUsage(data, orgId, ctx) {
116
116
  const db = this.getDb(ctx);
117
117
  // Atomic guard: use INSERT ... SELECT WHERE count < limit to prevent
118
118
  // race conditions between concurrent checkouts using the same coupon.
119
119
  // A plain count-then-insert has a TOCTOU gap; this single statement
120
120
  // ensures the insert only succeeds if the limit has not been reached.
121
+ // Both reads are scoped by organizationId: these are raw/lock queries that
122
+ // bypass the scoped-db proxy, so a promotionId from another tenant must
123
+ // resolve to no row rather than reading/locking a foreign promotion.
121
124
  const promo = await db
122
125
  .select({ usageLimitTotal: promotions.usageLimitTotal })
123
126
  .from(promotions)
124
- .where(eq(promotions.id, data.promotionId));
127
+ .where(and(eq(promotions.id, data.promotionId), eq(promotions.organizationId, orgId)));
125
128
  const limit = promo[0]?.usageLimitTotal;
126
129
  if (limit != null) {
127
130
  // Atomic guard: lock the promotion row and check usage count in the
@@ -131,7 +134,7 @@ export class PromotionsRepository {
131
134
  // SELECT ... FOR UPDATE acquires a row-level lock that serializes
132
135
  // concurrent callers. If the caller is already inside a transaction
133
136
  // (ctx.tx), the lock is held until that transaction commits.
134
- await db.execute(sql `SELECT id FROM promotions WHERE id = ${data.promotionId} FOR UPDATE`);
137
+ await db.execute(sql `SELECT id FROM promotions WHERE id = ${data.promotionId} AND organization_id = ${orgId} FOR UPDATE`);
135
138
  const currentCount = await this.countUsages(data.promotionId, ctx);
136
139
  if (currentCount >= limit) {
137
140
  throw new Error(`Promotion usage limit reached (${currentCount}/${limit})`);
@@ -85,6 +85,7 @@ export declare class PromotionService {
85
85
  applyPromotions(context: PromotionEvaluationContext, ctx?: TxContext): Promise<Result<PromotionApplicationResult>>;
86
86
  recordUsage(input: {
87
87
  promotions: AppliedPromotion[];
88
+ organizationId: string;
88
89
  customerId?: string;
89
90
  orderId?: string;
90
91
  }, ctx?: TxContext): Promise<Result<PromotionUsage[]>>;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/promotions/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/promotions/service.ts"],"names":[],"mappings":"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"}
@@ -302,7 +302,7 @@ export class PromotionService {
302
302
  promotionId: applied.promotionId,
303
303
  customerId: input.customerId ?? null,
304
304
  orderId: input.orderId ?? null,
305
- }, ctx);
305
+ }, input.organizationId, ctx);
306
306
  usages.push(usage);
307
307
  }
308
308
  return Ok(usages);
@@ -29,7 +29,7 @@ export declare class WebhooksRepository {
29
29
  limit?: number;
30
30
  }, ctx?: TxContext): Promise<WebhookDelivery[]>;
31
31
  findPendingDeliveries(ctx?: TxContext): Promise<WebhookDelivery[]>;
32
- findFailedDeliveries(endpointId?: string, ctx?: TxContext): Promise<WebhookDelivery[]>;
32
+ findFailedDeliveries(orgId: string, endpointId?: string, ctx?: TxContext): Promise<WebhookDelivery[]>;
33
33
  createDelivery(data: WebhookDeliveryInsert, ctx?: TxContext): Promise<WebhookDelivery>;
34
34
  updateDelivery(id: string, data: Partial<Omit<WebhookDeliveryInsert, "id">>, ctx?: TxContext): Promise<WebhookDelivery | undefined>;
35
35
  markDelivered(id: string, statusCode: number, ctx?: TxContext): Promise<WebhookDelivery | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/webhooks/repository/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/webhooks/repository/index.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { eq, and, lte, isNull, or, desc, sql } from "drizzle-orm";
1
+ import { eq, and, lte, isNull, or, desc, sql, inArray } from "drizzle-orm";
2
2
  import { webhookEndpoints, webhookDeliveries } from "../schema.js";
3
3
  /**
4
4
  * WebhooksRepository provides type-safe database operations for webhooks.
@@ -113,19 +113,25 @@ export class WebhooksRepository {
113
113
  .where(and(isNull(webhookDeliveries.deliveredAt), isNull(webhookDeliveries.failedAt), or(isNull(webhookDeliveries.nextRetryAt), lte(webhookDeliveries.nextRetryAt, now))))
114
114
  .orderBy(webhookDeliveries.createdAt);
115
115
  }
116
- async findFailedDeliveries(endpointId, ctx) {
116
+ async findFailedDeliveries(orgId, endpointId, ctx) {
117
117
  const db = this.getDb(ctx);
118
- if (endpointId) {
119
- return db
120
- .select()
121
- .from(webhookDeliveries)
122
- .where(and(eq(webhookDeliveries.endpointId, endpointId), sql `${webhookDeliveries.failedAt} IS NOT NULL`))
123
- .orderBy(desc(webhookDeliveries.failedAt));
124
- }
118
+ // webhook_deliveries has no organizationId column — org lives on the parent
119
+ // endpoint. Scope failed deliveries to endpoints owned by orgId so this can
120
+ // never read another tenant's deliveries.
121
+ const orgEndpointIds = db
122
+ .select({ id: webhookEndpoints.id })
123
+ .from(webhookEndpoints)
124
+ .where(eq(webhookEndpoints.organizationId, orgId));
125
+ const conditions = [
126
+ sql `${webhookDeliveries.failedAt} IS NOT NULL`,
127
+ inArray(webhookDeliveries.endpointId, orgEndpointIds),
128
+ ];
129
+ if (endpointId)
130
+ conditions.push(eq(webhookDeliveries.endpointId, endpointId));
125
131
  return db
126
132
  .select()
127
133
  .from(webhookDeliveries)
128
- .where(sql `${webhookDeliveries.failedAt} IS NOT NULL`)
134
+ .where(and(...conditions))
129
135
  .orderBy(desc(webhookDeliveries.failedAt));
130
136
  }
131
137
  async createDelivery(data, ctx) {
@@ -1 +1 @@
1
- {"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../../src/runtime/kernel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAoBzD,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,sBAAsB,EAC5B,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,8BAA8B,GAC/B,MAAM,qBAAqB,CAAC;AAE7B,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CA6H3D"}
1
+ {"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../../src/runtime/kernel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAqBzD,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,sBAAsB,EAC5B,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,8BAA8B,GAC/B,MAAM,qBAAqB,CAAC;AAE7B,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CA0I3D"}
@@ -44,8 +44,20 @@ export function createKernel(config) {
44
44
  serviceContainer.database = database;
45
45
  const db = database.db;
46
46
  const jobsTaskMap = new Map((config.jobs?.tasks ?? []).map((t) => [t.slug, t]));
47
- const jobsAdapter = new DrizzleJobsAdapter(db, jobsTaskMap);
48
- serviceContainer.jobs = jobsAdapter;
47
+ const jobsEngine = config.jobs?.adapter ?? new DrizzleJobsAdapter(db);
48
+ const jobLogger = {
49
+ info: (message, data) => logger.info(message, data),
50
+ warn: (message, data) => logger.warn(message, data),
51
+ error: (message, data) => logger.error(message, data),
52
+ };
53
+ jobsEngine.register({
54
+ tasks: jobsTaskMap,
55
+ context: { logger: jobLogger, db, services: serviceContainer },
56
+ ...(config.jobs?.processingOrder !== undefined
57
+ ? { processingOrder: config.jobs.processingOrder }
58
+ : {}),
59
+ });
60
+ serviceContainer.jobs = jobsEngine;
49
61
  const topoGraph = kernelModulesForTopoSort();
50
62
  const order = topoSortModules(topoGraph);
51
63
  const moduleKeys = Object.keys(KERNEL_ALL_MODULES);
@@ -32,10 +32,7 @@ export declare function createServer(config: CommerceConfig): Promise<{
32
32
  kernel: import("./kernel-types.js").Kernel;
33
33
  logger: Logger;
34
34
  commerce: CommerceInstance;
35
- runJobs: (queue?: string, limit?: number) => Promise<{
36
- processed: number;
37
- failed: number;
38
- }>;
35
+ runJobs: (queue?: string, limit?: number) => Promise<import("../kernel/jobs/adapter.js").RunJobsResult>;
39
36
  }>;
40
37
  export {};
41
38
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/runtime/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAQhD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAOzD,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAItE,KAAK,SAAS,GAAG;IACf,SAAS,EAAE;QACT,IAAI,EAAE,YAAY,CAAC;QACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAMvC;AAeD;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,cAAc;;;;;sBAuXxB,MAAM,UAAU,MAAM;;;;GAgFtD"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/runtime/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAQhD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAOzD,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAItE,KAAK,SAAS,GAAG;IACf,SAAS,EAAE;QACT,IAAI,EAAE,YAAY,CAAC;QACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAMvC;AAeD;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,cAAc;;;;;sBAyVxB,MAAM,UAAU,MAAM;GA2FtD"}
@@ -345,41 +345,15 @@ export async function createServer(config) {
345
345
  // 1. autorun: in-process polling (long-running servers)
346
346
  // 2. GET /api/jobs/run: cron endpoint (serverless — Vercel, Cloudflare)
347
347
  // 3. runPendingJobs() export (custom worker process)
348
- const { runPendingJobs } = await import("../kernel/jobs/runner.js");
349
- const { runStaleJobReaper, getJobReapThresholdMs, getJobsReaperIntervalMs } = await import("../kernel/jobs/reaper.js");
350
- const taskMap = new Map();
351
- for (const task of config.jobs?.tasks ?? []) {
352
- const t = task;
353
- taskMap.set(t.slug ?? t.name ?? "", task);
354
- }
355
- const jobLogger = {
356
- info: (msg, data) => logger.info(data != null ? { data } : {}, msg),
357
- warn: (msg, data) => logger.warn(data != null ? { data } : {}, msg),
358
- error: (msg, data) => logger.error(data != null ? { data } : {}, msg),
359
- };
360
- let lastStaleJobReaperAt = 0;
361
- const maybeRunStaleJobReaper = async () => {
362
- const interval = getJobsReaperIntervalMs();
363
- const now = Date.now();
364
- if (now - lastStaleJobReaperAt < interval)
365
- return;
366
- lastStaleJobReaperAt = now;
367
- try {
368
- await runStaleJobReaper(kernel.database.db, getJobReapThresholdMs(), jobLogger);
369
- }
370
- catch (err) {
371
- logger.error({ err }, "Stale job reaper failed");
372
- }
373
- };
348
+ const jobsEngine = kernel.services
349
+ .jobs;
374
350
  const runJobs = async (queue, limit) => {
375
- await maybeRunStaleJobReaper();
376
- return runPendingJobs({
377
- db: kernel.database.db,
378
- tasks: taskMap,
351
+ if (jobsEngine.execution.mode !== "pull") {
352
+ throw new Error("The configured push execution engine is driven by its native runtime and cannot be polled with runJobs().");
353
+ }
354
+ return jobsEngine.execution.run({
379
355
  queue: queue ?? "default",
380
356
  limit: limit ?? 10,
381
- logger: jobLogger,
382
- services: kernel.services,
383
357
  });
384
358
  };
385
359
  // Strategy 1: Built-in cron endpoint for serverless deployments.
@@ -405,6 +379,9 @@ export async function createServer(config) {
405
379
  // Strategy 2: In-process polling for long-running servers (ECS, Cloud Run, Docker).
406
380
  // Enable via config.jobs.autorun.enabled = true
407
381
  if (config.jobs?.autorun?.enabled) {
382
+ if (jobsEngine.execution.mode !== "pull") {
383
+ throw new Error("jobs.autorun is only valid for pull execution engines. Serve the configured push engine through its native runtime.");
384
+ }
408
385
  const intervalMs = config.jobs.autorun.intervalMs ?? 10_000;
409
386
  const jobInterval = setInterval(async () => {
410
387
  try {
@@ -420,8 +397,13 @@ export async function createServer(config) {
420
397
  logger.info({ intervalMs }, "Job queue autorun started (in-process polling)");
421
398
  }
422
399
  else {
423
- logger.info("Job queue autorun disabled. Use GET /api/jobs/run for serverless cron, " +
424
- "or set config.jobs.autorun.enabled = true for in-process polling.");
400
+ if (jobsEngine.execution.mode === "push") {
401
+ logger.info("Push job engine registered. Serve it through its native runtime.");
402
+ }
403
+ else {
404
+ logger.info("Job queue autorun disabled. Use GET /api/jobs/run for serverless cron, " +
405
+ "or set config.jobs.autorun.enabled = true for in-process polling.");
406
+ }
425
407
  }
426
408
  const dispatchFetch = app.fetch.bind(app);
427
409
  app.fetch = ((input, env, executionCtx) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@porulle/core",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -17,7 +17,7 @@ export const defaultConfig: Partial<CommerceConfig> = {
17
17
  },
18
18
  roles: {
19
19
  owner: { permissions: ["*:*"] },
20
- admin: { permissions: ["*:*", "compensation:admin"] },
20
+ admin: { permissions: ["*:*", "catalog:sync", "compensation:admin"] },
21
21
  manager: {
22
22
  permissions: [
23
23
  "catalog:create",
@@ -8,8 +8,11 @@ import type { AuthInstance } from "../auth/setup.js";
8
8
  import type { DatabaseAdapter } from "../kernel/database/adapter.js";
9
9
  import type { TaxAdapter } from "../modules/tax/adapter.js";
10
10
  import type { SearchAdapter } from "../modules/search/adapter.js";
11
- import type { JobsAdapter } from "../kernel/jobs/adapter.js";
12
- import type { TaskDefinition } from "../kernel/jobs/types.js";
11
+ import type { ExecutionEngine } from "../kernel/jobs/adapter.js";
12
+ import type {
13
+ JobProcessingOrder,
14
+ TaskDefinition,
15
+ } from "../kernel/jobs/types.js";
13
16
 
14
17
  export interface RoleDefinition {
15
18
  permissions: string[];
@@ -353,8 +356,9 @@ export interface CommerceConfig {
353
356
  analytics?: AnalyticsConfig;
354
357
  search?: SearchConfig;
355
358
  jobs?: {
356
- adapter?: JobsAdapter;
359
+ adapter?: ExecutionEngine;
357
360
  tasks?: TaskDefinition[];
361
+ processingOrder?: JobProcessingOrder;
358
362
  autorun?: {
359
363
  enabled: boolean;
360
364
  intervalMs?: number;
@@ -3,6 +3,7 @@
3
3
 
4
4
  export interface PluginCapabilityRegistryShape {
5
5
  "appointments": Record<string, unknown>;
6
+ "channel-connector": Record<string, unknown>;
6
7
  "gift-cards": Record<string, unknown>;
7
8
  "layaway": Record<string, unknown>;
8
9
  "loyalty": Record<string, unknown>;
@@ -4,6 +4,7 @@
4
4
 
5
5
  export const resolvedPluginManifest = [
6
6
  { id: "appointments", directory: "plugin-appointments" },
7
+ { id: "channel-connector", directory: "plugin-channel-connector" },
7
8
  { id: "gift-cards", directory: "plugin-gift-cards" },
8
9
  { id: "layaway", directory: "plugin-layaway" },
9
10
  { id: "loyalty", directory: "plugin-loyalty" },
@@ -3,6 +3,7 @@
3
3
 
4
4
  export interface PluginRepositoryRegistryShape {
5
5
  "appointments": Record<string, unknown>;
6
+ "channel-connector": Record<string, unknown>;
6
7
  "gift-cards": Record<string, unknown>;
7
8
  "layaway": Record<string, unknown>;
8
9
  "loyalty": Record<string, unknown>;
package/src/index.ts CHANGED
@@ -32,6 +32,7 @@ export type { Kernel } from "./runtime/kernel.js";
32
32
 
33
33
  export type { Actor } from "./auth/types.js";
34
34
  export { resolveOrgId, ensureDefaultOrg, DEFAULT_ORG_ID } from "./auth/org.js";
35
+ export { createSystemActor } from "./auth/system-actor.js";
35
36
  export { OrganizationService } from "./modules/organization/service.js";
36
37
  export { createScopedDb } from "./kernel/database/scoped-db.js";
37
38
  export type { ScopedOrganizationId } from "./kernel/database/scoped-db.js";
@@ -61,7 +62,15 @@ export type {
61
62
  export { runBeforeHooks, runAfterHooks } from "./kernel/hooks/executor.js";
62
63
  export { createHookContext } from "./kernel/hooks/create-context.js";
63
64
  export type { CreateHookContextArgs } from "./kernel/hooks/create-context.js";
64
- export type { JobsAdapter, EnqueueOptions } from "./kernel/jobs/adapter.js";
65
+ export type {
66
+ JobsAdapter,
67
+ EnqueueOptions,
68
+ ExecutionDriver,
69
+ ExecutionEngine,
70
+ ExecutionEngineSetup,
71
+ RunJobsOptions,
72
+ RunJobsResult,
73
+ } from "./kernel/jobs/adapter.js";
65
74
  export { NullJobsAdapter } from "./kernel/jobs/adapter.js";
66
75
  export { DrizzleJobsAdapter } from "./kernel/jobs/drizzle-adapter.js";
67
76
  export { runPendingJobs } from "./kernel/jobs/runner.js";
@@ -71,6 +80,9 @@ export type {
71
80
  TaskContext,
72
81
  TaskJobMeta,
73
82
  TaskRetryConfig,
83
+ JobProcessingOrder,
84
+ JobProcessingOrderField,
85
+ JobProcessingOrderRecord,
74
86
  } from "./kernel/jobs/types.js";
75
87
  export { BUILTIN_JOB_TASK_SLUGS } from "./kernel/jobs/types.js";
76
88
  export {
@@ -127,6 +139,24 @@ export type {
127
139
  PaymentRefund,
128
140
  PaymentWebhookEvent,
129
141
  } from "./modules/payments/adapter.js";
142
+ export { defineChannelConnector } from "./modules/channels/adapter.js";
143
+ export type {
144
+ ChannelCatalogItem,
145
+ ChannelCatalogPage,
146
+ ChannelCatalogVariant,
147
+ ChannelConnector,
148
+ ChannelConnectorCapabilities,
149
+ ChannelInventoryLevel,
150
+ ChannelOrderLine,
151
+ ChannelOrderSlice,
152
+ ChannelConnectorError,
153
+ ChannelOrderStatus,
154
+ ChannelPushOrderResult,
155
+ ChannelRefundResult,
156
+ ChannelReservation,
157
+ ChannelStore,
158
+ ChannelWebhookEvent,
159
+ } from "./modules/channels/adapter.js";
130
160
  export type { StorageAdapter } from "./modules/media/adapter.js";
131
161
  export { noopStorageAdapter } from "./modules/media/noop-adapter.js";
132
162
  export type {
@@ -240,6 +240,8 @@ class RouteChain {
240
240
 
241
241
  const result = await fn(handlerCtx);
242
242
 
243
+ if (result instanceof Response) return result;
244
+
243
245
  if (result === undefined || result === null) {
244
246
  return ctx.json({ data: null }, successStatus);
245
247
  }
@@ -286,6 +286,7 @@ export function checkoutRoutes(kernel: Kernel) {
286
286
  if (order.ok && (processed.appliedPromotions?.length ?? 0) > 0) {
287
287
  await kernel.services.promotions.recordUsage({
288
288
  promotions: processed.appliedPromotions ?? [],
289
+ organizationId: order.value.organizationId,
289
290
  orderId: order.value.id,
290
291
  ...(customerUuid !== undefined
291
292
  ? { customerId: customerUuid }
@@ -32,25 +32,23 @@ function tableHasOrganizationId(table: unknown): boolean {
32
32
  }
33
33
 
34
34
  /**
35
- * Pre-apply the org predicate to a WHERE-able builder (UPDATE/DELETE) and wrap
36
- * its `.where()` so a caller-supplied condition is AND-ed with the org filter
37
- * rather than replacing it. Pre-applying `orgEq` immediately means a builder
38
- * executed with NO caller `.where()` (e.g. `update(t).set(...)`) is still
39
- * constrained to the orgit can never touch another tenant's rows.
35
+ * Wrap a WHERE-able Drizzle builder so every `.where()` call AND-s `orgEq` in
36
+ * AND re-wraps its result. Re-wrapping is what makes a chained
37
+ * `.where(a).where(b)` safe: Drizzle's second `.where()` REPLACES the first, so
38
+ * without re-wrapping the chained call would reach the raw builder and execute
39
+ * with only the caller's condition dropping the org predicate and leaking
40
+ * across tenants. Every link in the chain re-injects `orgEq`.
40
41
  */
41
- function scopeWhereBuilder(
42
- builder: { where: (c: SQL | undefined) => unknown },
43
- orgEq: SQL,
44
- ): unknown {
45
- const scoped = builder.where(orgEq);
46
- return new Proxy(scoped as Record<string, unknown>, {
42
+ function wrapWhereable(builder: unknown, orgEq: SQL): unknown {
43
+ return new Proxy(builder as Record<string, unknown>, {
47
44
  get(st, sp, sr) {
48
45
  const sv = Reflect.get(st, sp, sr);
49
46
  if (sp === "where" && typeof sv === "function") {
50
47
  return (condition?: unknown, ...wRest: unknown[]) => {
51
48
  const c = condition as SQL | undefined;
52
49
  const merged = c ? and(orgEq, c) : orgEq;
53
- return (sv as (...a: unknown[]) => unknown).call(st, merged, ...wRest);
50
+ const next = (sv as (...a: unknown[]) => unknown).call(st, merged, ...wRest);
51
+ return wrapWhereable(next, orgEq);
54
52
  };
55
53
  }
56
54
  return typeof sv === "function" ? sv.bind(st) : sv;
@@ -58,6 +56,20 @@ function scopeWhereBuilder(
58
56
  });
59
57
  }
60
58
 
59
+ /**
60
+ * Pre-apply the org predicate to a WHERE-able builder (UPDATE/DELETE) and wrap
61
+ * its `.where()` so a caller-supplied condition is AND-ed with the org filter
62
+ * rather than replacing it. Pre-applying `orgEq` immediately means a builder
63
+ * executed with NO caller `.where()` (e.g. `update(t).set(...)`) is still
64
+ * constrained to the org — it can never touch another tenant's rows.
65
+ */
66
+ function scopeWhereBuilder(
67
+ builder: { where: (c: SQL | undefined) => unknown },
68
+ orgEq: SQL,
69
+ ): unknown {
70
+ return wrapWhereable(builder.where(orgEq), orgEq);
71
+ }
72
+
61
73
  export function createScopedDb<TDb>(rawDb: TDb, orgSource: ScopedOrganizationId): TDb {
62
74
  if (!rawDb || typeof rawDb !== "object") return rawDb;
63
75
 
@@ -112,20 +124,7 @@ export function createScopedDb<TDb>(rawDb: TDb, orgSource: ScopedOrganizationId)
112
124
 
113
125
  const orgEq = eq(orgCol, resolveOrganizationId(orgSource));
114
126
  const inner = chain as { where: (c: SQL | undefined) => unknown };
115
- const scoped = inner.where(orgEq);
116
- return new Proxy(scoped as Record<string, unknown>, {
117
- get(st, sp, sr) {
118
- const sv = Reflect.get(st, sp, sr);
119
- if (sp === "where" && typeof sv === "function") {
120
- return (condition?: unknown, ...wRest: unknown[]) => {
121
- const c = condition as SQL | undefined;
122
- const merged = c ? and(orgEq, c) : orgEq;
123
- return sv.call(st, merged, ...wRest);
124
- };
125
- }
126
- return typeof sv === "function" ? sv.bind(st) : sv;
127
- },
128
- });
127
+ return wrapWhereable(inner.where(orgEq), orgEq);
129
128
  };
130
129
  }
131
130
  return typeof sbVal === "function" ? sbVal.bind(sbTarget) : sbVal;
@@ -32,6 +32,26 @@ export class CommerceValidationError extends Error implements CommerceError {
32
32
  }
33
33
  }
34
34
 
35
+ /** Canonical message for a missing inventory record — the single source used by
36
+ * the inventory repository and mapped to the typed error below. */
37
+ export const INVENTORY_RECORD_NOT_FOUND_MESSAGE =
38
+ "No inventory record found for this entity.";
39
+
40
+ /** Raised when an inventory reserve/release targets an entity with no inventory
41
+ * record. Consumers (e.g. order status transitions that tolerate a missing
42
+ * record) discriminate on `code === "INVENTORY_RECORD_NOT_FOUND"`, never the
43
+ * message string. */
44
+ export class CommerceInventoryRecordNotFoundError extends Error implements CommerceError {
45
+ code = "INVENTORY_RECORD_NOT_FOUND" as const;
46
+ constructor(
47
+ message: string = INVENTORY_RECORD_NOT_FOUND_MESSAGE,
48
+ public details?: unknown,
49
+ ) {
50
+ super(message);
51
+ this.name = "CommerceInventoryRecordNotFoundError";
52
+ }
53
+ }
54
+
35
55
  export class CommerceForbiddenError extends Error implements CommerceError {
36
56
  code = "FORBIDDEN" as const;
37
57
  constructor(