@porulle/plugin-marketplace 0.63.0 → 0.65.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 (57) hide show
  1. package/README.md +11 -59
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +3 -11
  4. package/dist/routes/b2b.d.ts +1 -3
  5. package/dist/routes/b2b.d.ts.map +1 -1
  6. package/dist/routes/b2b.js +2 -70
  7. package/dist/routes/sub-orders.js +3 -3
  8. package/dist/routes/vendor-portal.js +6 -6
  9. package/dist/schema.d.ts +0 -194
  10. package/dist/schema.d.ts.map +1 -1
  11. package/dist/schema.js +0 -14
  12. package/dist/schemas/b2b.d.ts +0 -986
  13. package/dist/schemas/b2b.d.ts.map +1 -1
  14. package/dist/schemas/b2b.js +1 -184
  15. package/dist/schemas/commission.d.ts +0 -495
  16. package/dist/schemas/commission.d.ts.map +1 -1
  17. package/dist/schemas/commission.js +1 -78
  18. package/dist/schemas/disputes-returns-reviews.d.ts +0 -1354
  19. package/dist/schemas/disputes-returns-reviews.d.ts.map +1 -1
  20. package/dist/schemas/disputes-returns-reviews.js +1 -208
  21. package/dist/schemas/sub-orders.d.ts +0 -290
  22. package/dist/schemas/sub-orders.d.ts.map +1 -1
  23. package/dist/schemas/sub-orders.js +1 -59
  24. package/dist/schemas/vendor-portal.d.ts +0 -1755
  25. package/dist/schemas/vendor-portal.d.ts.map +1 -1
  26. package/dist/schemas/vendor-portal.js +1 -247
  27. package/dist/schemas/vendors.d.ts +0 -1321
  28. package/dist/schemas/vendors.d.ts.map +1 -1
  29. package/dist/schemas/vendors.js +1 -205
  30. package/dist/services/sub-order.d.ts +1 -31
  31. package/dist/services/sub-order.d.ts.map +1 -1
  32. package/dist/services/sub-order.js +14 -22
  33. package/dist/types.d.ts +0 -17
  34. package/dist/types.d.ts.map +1 -1
  35. package/dist/types.js +0 -4
  36. package/package.json +4 -4
  37. package/src/index.ts +3 -11
  38. package/src/routes/b2b.ts +1 -76
  39. package/src/routes/sub-orders.ts +3 -3
  40. package/src/routes/vendor-portal.ts +6 -6
  41. package/src/schema.ts +0 -16
  42. package/src/schemas/b2b.ts +1 -208
  43. package/src/schemas/commission.ts +1 -86
  44. package/src/schemas/disputes-returns-reviews.ts +1 -225
  45. package/src/schemas/sub-orders.ts +1 -65
  46. package/src/schemas/vendor-portal.ts +1 -269
  47. package/src/schemas/vendors.ts +1 -222
  48. package/src/services/sub-order.ts +16 -18
  49. package/src/types.ts +0 -28
  50. package/dist/schemas/payouts.d.ts +0 -375
  51. package/dist/schemas/payouts.d.ts.map +0 -1
  52. package/dist/schemas/payouts.js +0 -78
  53. package/dist/services/contract-price.d.ts +0 -64
  54. package/dist/services/contract-price.d.ts.map +0 -1
  55. package/dist/services/contract-price.js +0 -57
  56. package/src/schemas/payouts.ts +0 -90
  57. package/src/services/contract-price.ts +0 -80
@@ -1,4 +1,4 @@
1
- import { router } from "@porulle/core";
1
+ import { router, CommerceNotFoundError } from "@porulle/core";
2
2
  import type { PluginRouteRegistration } from "@porulle/core";
3
3
  import type { z } from "@hono/zod-openapi";
4
4
  import type { SubOrderService } from "../services/sub-order.js";
@@ -29,7 +29,7 @@ export function buildSubOrderRoutes(services: {
29
29
  .permission("marketplace:admin")
30
30
  .handler(async ({ params }) => {
31
31
  const subOrder = await services.subOrder.getById(params.id!);
32
- if (!subOrder) throw new Error("Sub-order not found");
32
+ if (!subOrder) throw new CommerceNotFoundError("Sub-order not found.");
33
33
  return subOrder;
34
34
  });
35
35
 
@@ -41,7 +41,7 @@ export function buildSubOrderRoutes(services: {
41
41
  .handler(async ({ params, input }) => {
42
42
  const body = input as z.infer<typeof UpdateSubOrderStatusBodySchema>;
43
43
  const subOrder = await services.subOrder.getById(params.id!);
44
- if (!subOrder) throw new Error("Sub-order not found");
44
+ if (!subOrder) throw new CommerceNotFoundError("Sub-order not found.");
45
45
 
46
46
  // Use cancel() for cancelled status to trigger side effects
47
47
  // (inventory release + ledger reversal)
@@ -1,4 +1,4 @@
1
- import { router } from "@porulle/core";
1
+ import { router, CommerceNotFoundError } from "@porulle/core";
2
2
  import type { PluginRouteRegistration } from "@porulle/core";
3
3
  import type { z } from "@hono/zod-openapi";
4
4
  import type { VendorService } from "../services/vendor.js";
@@ -113,7 +113,7 @@ export function buildVendorPortalRoutes(services: {
113
113
  .handler(async ({ actor, params }) => {
114
114
  const vendorId = requireVendorId(actor);
115
115
  const subOrder = await services.subOrder.getById(params.subOrderId!);
116
- if (!subOrder) throw new Error("Sub-order not found");
116
+ if (!subOrder) throw new CommerceNotFoundError("Sub-order not found.");
117
117
  if (subOrder.vendorId !== vendorId) throw new Error("Forbidden");
118
118
  return subOrder;
119
119
  });
@@ -125,7 +125,7 @@ export function buildVendorPortalRoutes(services: {
125
125
  .handler(async ({ actor, params }) => {
126
126
  const vendorId = requireVendorId(actor);
127
127
  const subOrder = await services.subOrder.getById(params.subOrderId!);
128
- if (!subOrder) throw new Error("Sub-order not found");
128
+ if (!subOrder) throw new CommerceNotFoundError("Sub-order not found.");
129
129
  if (subOrder.vendorId !== vendorId) throw new Error("Forbidden");
130
130
  return services.subOrder.confirm(params.subOrderId!);
131
131
  });
@@ -139,7 +139,7 @@ export function buildVendorPortalRoutes(services: {
139
139
  const vendorId = requireVendorId(actor);
140
140
  const body = input as z.infer<typeof ShipSubOrderBodySchema>;
141
141
  const subOrder = await services.subOrder.getById(params.subOrderId!);
142
- if (!subOrder) throw new Error("Sub-order not found");
142
+ if (!subOrder) throw new CommerceNotFoundError("Sub-order not found.");
143
143
  if (subOrder.vendorId !== vendorId) throw new Error("Forbidden");
144
144
  return services.subOrder.ship(params.subOrderId!, {
145
145
  trackingNumber: body.trackingNumber,
@@ -154,7 +154,7 @@ export function buildVendorPortalRoutes(services: {
154
154
  .handler(async ({ actor, params }) => {
155
155
  const vendorId = requireVendorId(actor);
156
156
  const subOrder = await services.subOrder.getById(params.subOrderId!);
157
- if (!subOrder) throw new Error("Sub-order not found");
157
+ if (!subOrder) throw new CommerceNotFoundError("Sub-order not found.");
158
158
  if (subOrder.vendorId !== vendorId) throw new Error("Forbidden");
159
159
  return services.subOrder.deliver(params.subOrderId!);
160
160
  });
@@ -168,7 +168,7 @@ export function buildVendorPortalRoutes(services: {
168
168
  const vendorId = requireVendorId(actor);
169
169
  const body = input as z.infer<typeof CancelSubOrderBodySchema>;
170
170
  const subOrder = await services.subOrder.getById(params.subOrderId!);
171
- if (!subOrder) throw new Error("Sub-order not found");
171
+ if (!subOrder) throw new CommerceNotFoundError("Sub-order not found.");
172
172
  if (subOrder.vendorId !== vendorId) throw new Error("Forbidden");
173
173
  return services.subOrder.cancel(params.subOrderId!, body.reason);
174
174
  });
package/src/schema.ts CHANGED
@@ -242,19 +242,3 @@ export const rfqResponses = pgTable("marketplace_rfq_responses", {
242
242
  status: text("status").notNull().default("submitted"),
243
243
  createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
244
244
  });
245
-
246
- // ─── Contract Prices (B2B) ───────────────────────────────────────────────────
247
-
248
- export const contractPrices = pgTable("marketplace_contract_prices", {
249
- id: uuid("id").defaultRandom().primaryKey(),
250
- vendorId: uuid("vendor_id").notNull().references(() => vendors.id, { onDelete: "cascade" }),
251
- buyerId: uuid("buyer_id").notNull(),
252
- entityId: uuid("entity_id").notNull(),
253
- variantId: uuid("variant_id"),
254
- priceCents: integer("price_cents").notNull(),
255
- minQuantity: integer("min_quantity").notNull().default(1),
256
- currency: text("currency").notNull().default("USD"),
257
- validFrom: timestamp("valid_from", { withTimezone: true }),
258
- validUntil: timestamp("valid_until", { withTimezone: true }),
259
- createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
260
- });
@@ -1,25 +1,4 @@
1
- import { z, createRoute } from "@hono/zod-openapi";
2
-
3
- const ErrorSchema = z.object({
4
- error: z.object({
5
- code: z.string(),
6
- message: z.string(),
7
- }),
8
- });
9
-
10
- const errorResponses = {
11
- 401: { content: { "application/json": { schema: ErrorSchema } }, description: "Authentication required." },
12
- 403: { content: { "application/json": { schema: ErrorSchema } }, description: "Insufficient permissions." },
13
- 404: { content: { "application/json": { schema: ErrorSchema } }, description: "Not found." },
14
- 422: { content: { "application/json": { schema: ErrorSchema } }, description: "Validation error." },
15
- 500: { content: { "application/json": { schema: ErrorSchema } }, description: "Server error." },
16
- } as const;
17
-
18
- const DataResponseSchema = z.object({ data: z.any() });
19
-
20
- // ═══════════════════════════════════════════════════════════════════════════════
21
- // RFQ (Request for Quote)
22
- // ═══════════════════════════════════════════════════════════════════════════════
1
+ import { z } from "@hono/zod-openapi";
23
2
 
24
3
  // ─── Create RFQ ─────────────────────────────────────────────────────────────
25
4
 
@@ -35,20 +14,6 @@ export const CreateRFQBodySchema = z.object({
35
14
  metadata: z.record(z.string(), z.unknown()).optional(),
36
15
  }).openapi("CreateRFQRequest");
37
16
 
38
- export const createRFQRoute = createRoute({
39
- method: "post",
40
- path: "/api/marketplace/rfq",
41
- tags: ["Marketplace - B2B"],
42
- summary: "Create a Request for Quote",
43
- request: {
44
- body: { content: { "application/json": { schema: CreateRFQBodySchema } }, required: true },
45
- },
46
- responses: {
47
- 201: { content: { "application/json": { schema: DataResponseSchema } }, description: "RFQ created." },
48
- ...errorResponses,
49
- },
50
- });
51
-
52
17
  // ─── Respond to RFQ ─────────────────────────────────────────────────────────
53
18
 
54
19
  export const RespondRFQBodySchema = z.object({
@@ -59,180 +24,8 @@ export const RespondRFQBodySchema = z.object({
59
24
  notes: z.string().optional(),
60
25
  }).openapi("RespondRFQRequest");
61
26
 
62
- export const respondRFQRoute = createRoute({
63
- method: "post",
64
- path: "/api/marketplace/rfq/{id}/respond",
65
- tags: ["Marketplace - B2B"],
66
- summary: "Submit a vendor response to an RFQ",
67
- request: {
68
- params: z.object({ id: z.string() }),
69
- body: { content: { "application/json": { schema: RespondRFQBodySchema } }, required: true },
70
- },
71
- responses: {
72
- 201: { content: { "application/json": { schema: DataResponseSchema } }, description: "RFQ response submitted." },
73
- ...errorResponses,
74
- },
75
- });
76
-
77
27
  // ─── Award RFQ ──────────────────────────────────────────────────────────────
78
28
 
79
29
  export const AwardRFQBodySchema = z.object({
80
30
  vendorId: z.string().min(1).openapi({ example: "vendor_abc" }),
81
31
  }).openapi("AwardRFQRequest");
82
-
83
- export const awardRFQRoute = createRoute({
84
- method: "post",
85
- path: "/api/marketplace/rfq/{id}/award",
86
- tags: ["Marketplace - B2B"],
87
- summary: "Award an RFQ to a vendor",
88
- request: {
89
- params: z.object({ id: z.string() }),
90
- body: { content: { "application/json": { schema: AwardRFQBodySchema } }, required: true },
91
- },
92
- responses: {
93
- 200: { content: { "application/json": { schema: DataResponseSchema } }, description: "RFQ awarded." },
94
- ...errorResponses,
95
- },
96
- });
97
-
98
- // ═══════════════════════════════════════════════════════════════════════════════
99
- // CONTRACT PRICES
100
- // ═══════════════════════════════════════════════════════════════════════════════
101
-
102
- // ─── Create Contract Price ──────────────────────────────────────────────────
103
-
104
- export const CreateContractPriceBodySchema = z.object({
105
- vendorId: z.string().min(1).openapi({ example: "vendor_abc" }),
106
- buyerId: z.string().min(1).openapi({ example: "buyer_xyz" }),
107
- entityId: z.string().min(1).openapi({ example: "product_001" }),
108
- variantId: z.string().optional(),
109
- priceCents: z.number().int().openapi({ example: 7500 }),
110
- minQuantity: z.number().int().optional().openapi({ example: 100 }),
111
- currency: z.string().optional().openapi({ example: "USD" }),
112
- validFrom: z.string().optional().openapi({ example: "2026-01-01T00:00:00Z", description: "ISO 8601 date string" }),
113
- validUntil: z.string().optional().openapi({ example: "2026-12-31T23:59:59Z", description: "ISO 8601 date string" }),
114
- }).openapi("CreateContractPriceRequest");
115
-
116
- export const createContractPriceRoute = createRoute({
117
- method: "post",
118
- path: "/api/marketplace/contract-prices",
119
- tags: ["Marketplace - B2B"],
120
- summary: "Create a contract price",
121
- request: {
122
- body: { content: { "application/json": { schema: CreateContractPriceBodySchema } }, required: true },
123
- },
124
- responses: {
125
- 201: { content: { "application/json": { schema: DataResponseSchema } }, description: "Contract price created." },
126
- ...errorResponses,
127
- },
128
- });
129
-
130
- // ─── Update Contract Price ──────────────────────────────────────────────────
131
-
132
- export const UpdateContractPriceBodySchema = z.object({
133
- priceCents: z.number().int().optional().openapi({ example: 7000 }),
134
- minQuantity: z.number().int().optional(),
135
- validFrom: z.string().nullable().optional().openapi({ description: "ISO 8601 date string or null to clear" }),
136
- validUntil: z.string().nullable().optional().openapi({ description: "ISO 8601 date string or null to clear" }),
137
- }).openapi("UpdateContractPriceRequest");
138
-
139
- export const updateContractPriceRoute = createRoute({
140
- method: "patch",
141
- path: "/api/marketplace/contract-prices/{id}",
142
- tags: ["Marketplace - B2B"],
143
- summary: "Update a contract price",
144
- request: {
145
- params: z.object({ id: z.string() }),
146
- body: { content: { "application/json": { schema: UpdateContractPriceBodySchema } }, required: true },
147
- },
148
- responses: {
149
- 200: { content: { "application/json": { schema: DataResponseSchema } }, description: "Contract price updated." },
150
- ...errorResponses,
151
- },
152
- });
153
-
154
- // ─── List RFQs ──────────────────────────────────────────────────────────────
155
-
156
- export const listRFQsRoute = createRoute({
157
- method: "get",
158
- path: "/api/marketplace/rfq",
159
- tags: ["Marketplace - B2B"],
160
- summary: "List Requests for Quote",
161
- request: {
162
- query: z.object({
163
- status: z.string().optional(),
164
- categorySlug: z.string().optional(),
165
- }),
166
- },
167
- responses: {
168
- 200: { content: { "application/json": { schema: DataResponseSchema } }, description: "Success" },
169
- ...errorResponses,
170
- },
171
- });
172
-
173
- // ─── Get RFQ ────────────────────────────────────────────────────────────────
174
-
175
- export const getRFQRoute = createRoute({
176
- method: "get",
177
- path: "/api/marketplace/rfq/{id}",
178
- tags: ["Marketplace - B2B"],
179
- summary: "Get RFQ detail",
180
- request: {
181
- params: z.object({ id: z.string() }),
182
- },
183
- responses: {
184
- 200: { content: { "application/json": { schema: DataResponseSchema } }, description: "Success" },
185
- ...errorResponses,
186
- },
187
- });
188
-
189
- // ─── Close RFQ ──────────────────────────────────────────────────────────────
190
-
191
- export const closeRFQRoute = createRoute({
192
- method: "post",
193
- path: "/api/marketplace/rfq/{id}/close",
194
- tags: ["Marketplace - B2B"],
195
- summary: "Close an RFQ",
196
- request: {
197
- params: z.object({ id: z.string() }),
198
- },
199
- responses: {
200
- 200: { content: { "application/json": { schema: DataResponseSchema } }, description: "RFQ closed." },
201
- ...errorResponses,
202
- },
203
- });
204
-
205
- // ─── List Contract Prices ───────────────────────────────────────────────────
206
-
207
- export const listContractPricesRoute = createRoute({
208
- method: "get",
209
- path: "/api/marketplace/contract-prices",
210
- tags: ["Marketplace - B2B"],
211
- summary: "List contract prices",
212
- request: {
213
- query: z.object({
214
- vendorId: z.string().optional(),
215
- buyerId: z.string().optional(),
216
- }),
217
- },
218
- responses: {
219
- 200: { content: { "application/json": { schema: DataResponseSchema } }, description: "Success" },
220
- ...errorResponses,
221
- },
222
- });
223
-
224
- // ─── Delete Contract Price ──────────────────────────────────────────────────
225
-
226
- export const deleteContractPriceRoute = createRoute({
227
- method: "delete",
228
- path: "/api/marketplace/contract-prices/{id}",
229
- tags: ["Marketplace - B2B"],
230
- summary: "Delete a contract price",
231
- request: {
232
- params: z.object({ id: z.string() }),
233
- },
234
- responses: {
235
- 200: { content: { "application/json": { schema: DataResponseSchema } }, description: "Contract price deleted." },
236
- ...errorResponses,
237
- },
238
- });
@@ -1,21 +1,4 @@
1
- import { z, createRoute } from "@hono/zod-openapi";
2
-
3
- const ErrorSchema = z.object({
4
- error: z.object({
5
- code: z.string(),
6
- message: z.string(),
7
- }),
8
- });
9
-
10
- const errorResponses = {
11
- 401: { content: { "application/json": { schema: ErrorSchema } }, description: "Authentication required." },
12
- 403: { content: { "application/json": { schema: ErrorSchema } }, description: "Insufficient permissions." },
13
- 404: { content: { "application/json": { schema: ErrorSchema } }, description: "Not found." },
14
- 422: { content: { "application/json": { schema: ErrorSchema } }, description: "Validation error." },
15
- 500: { content: { "application/json": { schema: ErrorSchema } }, description: "Server error." },
16
- } as const;
17
-
18
- const CommissionResponseSchema = z.object({ data: z.any() });
1
+ import { z } from "@hono/zod-openapi";
19
2
 
20
3
  // ─── Create Commission Rule ──────────────────────────────────────────────────
21
4
 
@@ -33,20 +16,6 @@ export const CreateCommissionRuleBodySchema = z.object({
33
16
  priority: z.number().int().optional(),
34
17
  }).openapi("CreateCommissionRuleRequest");
35
18
 
36
- export const createCommissionRuleRoute = createRoute({
37
- method: "post",
38
- path: "/api/marketplace/commission-rules",
39
- tags: ["Marketplace - Commission"],
40
- summary: "Create a commission rule",
41
- request: {
42
- body: { content: { "application/json": { schema: CreateCommissionRuleBodySchema } }, required: true },
43
- },
44
- responses: {
45
- 201: { content: { "application/json": { schema: CommissionResponseSchema } }, description: "Commission rule created." },
46
- ...errorResponses,
47
- },
48
- });
49
-
50
19
  // ─── Update Commission Rule ──────────────────────────────────────────────────
51
20
 
52
21
  export const UpdateCommissionRuleBodySchema = z.object({
@@ -62,21 +31,6 @@ export const UpdateCommissionRuleBodySchema = z.object({
62
31
  isActive: z.boolean().optional(),
63
32
  }).openapi("UpdateCommissionRuleRequest");
64
33
 
65
- export const updateCommissionRuleRoute = createRoute({
66
- method: "patch",
67
- path: "/api/marketplace/commission-rules/{id}",
68
- tags: ["Marketplace - Commission"],
69
- summary: "Update a commission rule",
70
- request: {
71
- params: z.object({ id: z.uuid() }),
72
- body: { content: { "application/json": { schema: UpdateCommissionRuleBodySchema } }, required: true },
73
- },
74
- responses: {
75
- 200: { content: { "application/json": { schema: CommissionResponseSchema } }, description: "Commission rule updated." },
76
- ...errorResponses,
77
- },
78
- });
79
-
80
34
  // ─── Preview Commission Rate ─────────────────────────────────────────────────
81
35
 
82
36
  export const PreviewCommissionBodySchema = z.object({
@@ -85,45 +39,6 @@ export const PreviewCommissionBodySchema = z.object({
85
39
  volumeCents: z.number().int().optional().openapi({ example: 100000, description: "Order volume in cents" }),
86
40
  }).openapi("PreviewCommissionRequest");
87
41
 
88
- export const previewCommissionRoute = createRoute({
89
- method: "post",
90
- path: "/api/marketplace/commission-rules/preview",
91
- tags: ["Marketplace - Commission"],
92
- summary: "Preview the commission rate for a vendor",
93
- request: {
94
- body: { content: { "application/json": { schema: PreviewCommissionBodySchema } }, required: true },
95
- },
96
- responses: {
97
- 200: { content: { "application/json": { schema: CommissionResponseSchema } }, description: "Commission rate preview." },
98
- ...errorResponses,
99
- },
100
- });
101
-
102
42
  // ─── List Commission Rules ──────────────────────────────────────────────────
103
43
 
104
- export const listCommissionRulesRoute = createRoute({
105
- method: "get",
106
- path: "/api/marketplace/commission-rules",
107
- tags: ["Marketplace - Commission"],
108
- summary: "List all commission rules",
109
- responses: {
110
- 200: { content: { "application/json": { schema: CommissionResponseSchema } }, description: "Success" },
111
- ...errorResponses,
112
- },
113
- });
114
-
115
44
  // ─── Delete Commission Rule ─────────────────────────────────────────────────
116
-
117
- export const deleteCommissionRuleRoute = createRoute({
118
- method: "delete",
119
- path: "/api/marketplace/commission-rules/{id}",
120
- tags: ["Marketplace - Commission"],
121
- summary: "Delete a commission rule",
122
- request: {
123
- params: z.object({ id: z.uuid() }),
124
- },
125
- responses: {
126
- 200: { content: { "application/json": { schema: CommissionResponseSchema } }, description: "Commission rule deleted." },
127
- ...errorResponses,
128
- },
129
- });