@fayz-ai/shop 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.
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/catalog.cjs +176 -0
- package/dist/catalog.cjs.map +1 -0
- package/dist/catalog.d.ts +4 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +170 -0
- package/dist/catalog.js.map +1 -0
- package/dist/commerce.d.ts +28 -0
- package/dist/commerce.d.ts.map +1 -0
- package/dist/index.cjs +1047 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1027 -0
- package/dist/index.js.map +1 -0
- package/dist/mock-catalog.d.ts +42 -0
- package/dist/mock-catalog.d.ts.map +1 -0
- package/dist/mock-provider.d.ts +48 -0
- package/dist/mock-provider.d.ts.map +1 -0
- package/dist/mock.cjs +430 -0
- package/dist/mock.cjs.map +1 -0
- package/dist/mock.d.ts +3 -0
- package/dist/mock.d.ts.map +1 -0
- package/dist/mock.js +427 -0
- package/dist/mock.js.map +1 -0
- package/dist/provider.cjs +4 -0
- package/dist/provider.cjs.map +1 -0
- package/dist/provider.d.ts +42 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +3 -0
- package/dist/provider.js.map +1 -0
- package/dist/runtime.cjs +447 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.ts +5 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +443 -0
- package/dist/runtime.js.map +1 -0
- package/dist/supabase-provider.d.ts +33 -0
- package/dist/supabase-provider.d.ts.map +1 -0
- package/dist/tenant.d.ts +4 -0
- package/dist/tenant.d.ts.map +1 -0
- package/dist/types.cjs +4 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.ts +345 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +99 -0
- package/src/catalog.ts +3 -0
- package/src/commerce.ts +120 -0
- package/src/index.ts +34 -0
- package/src/mock-catalog.ts +258 -0
- package/src/mock-provider.ts +372 -0
- package/src/mock.ts +2 -0
- package/src/provider.ts +59 -0
- package/src/runtime.ts +20 -0
- package/src/supabase-provider.ts +499 -0
- package/src/tenant.ts +21 -0
- package/src/types.ts +401 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Product
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
export type ProductStatus = 'draft' | 'active' | 'archived'
|
|
6
|
+
|
|
7
|
+
export interface Product {
|
|
8
|
+
id: string
|
|
9
|
+
tenantId: string
|
|
10
|
+
name: string
|
|
11
|
+
slug: string
|
|
12
|
+
description: string | null
|
|
13
|
+
price: number
|
|
14
|
+
compareAtPrice: number | null
|
|
15
|
+
currency: string
|
|
16
|
+
status: ProductStatus
|
|
17
|
+
inventoryCount: number
|
|
18
|
+
sku: string | null
|
|
19
|
+
sortOrder: number
|
|
20
|
+
metadata: Record<string, unknown>
|
|
21
|
+
images: ProductImage[]
|
|
22
|
+
categoryId: string | null
|
|
23
|
+
categoryName: string | null
|
|
24
|
+
isPhysical: boolean
|
|
25
|
+
weight: number | null
|
|
26
|
+
weightUnit: string
|
|
27
|
+
createdAt: string
|
|
28
|
+
updatedAt: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ProductImage {
|
|
32
|
+
id: string
|
|
33
|
+
productId: string
|
|
34
|
+
url: string
|
|
35
|
+
altText: string | null
|
|
36
|
+
sortOrder: number
|
|
37
|
+
isPrimary: boolean
|
|
38
|
+
createdAt: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface CreateProductInput {
|
|
42
|
+
name: string
|
|
43
|
+
slug?: string
|
|
44
|
+
description?: string
|
|
45
|
+
price: number
|
|
46
|
+
compareAtPrice?: number
|
|
47
|
+
currency?: string
|
|
48
|
+
status?: ProductStatus
|
|
49
|
+
inventoryCount?: number
|
|
50
|
+
sku?: string
|
|
51
|
+
sortOrder?: number
|
|
52
|
+
metadata?: Record<string, unknown>
|
|
53
|
+
categoryId?: string
|
|
54
|
+
isPhysical?: boolean
|
|
55
|
+
weight?: number
|
|
56
|
+
weightUnit?: string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface UpdateProductInput {
|
|
60
|
+
name?: string
|
|
61
|
+
slug?: string
|
|
62
|
+
description?: string
|
|
63
|
+
price?: number
|
|
64
|
+
compareAtPrice?: number | null
|
|
65
|
+
currency?: string
|
|
66
|
+
status?: ProductStatus
|
|
67
|
+
inventoryCount?: number
|
|
68
|
+
sku?: string | null
|
|
69
|
+
sortOrder?: number
|
|
70
|
+
metadata?: Record<string, unknown>
|
|
71
|
+
categoryId?: string | null
|
|
72
|
+
isPhysical?: boolean
|
|
73
|
+
weight?: number | null
|
|
74
|
+
weightUnit?: string
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface ListProductsOptions {
|
|
78
|
+
status?: ProductStatus
|
|
79
|
+
categoryId?: string
|
|
80
|
+
search?: string
|
|
81
|
+
/** Exact-match slug lookup (storefront product-detail routing) */
|
|
82
|
+
slug?: string
|
|
83
|
+
limit?: number
|
|
84
|
+
offset?: number
|
|
85
|
+
orderBy?: 'name' | 'price' | 'created_at' | 'sort_order'
|
|
86
|
+
order?: 'asc' | 'desc'
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Category
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
export interface Category {
|
|
94
|
+
id: string
|
|
95
|
+
tenantId: string
|
|
96
|
+
name: string
|
|
97
|
+
slug: string
|
|
98
|
+
description: string | null
|
|
99
|
+
parentId: string | null
|
|
100
|
+
sortOrder: number
|
|
101
|
+
/** Showcase image (storefront category tiles). Not yet a shop_categories column. */
|
|
102
|
+
imageUrl?: string | null
|
|
103
|
+
children?: Category[]
|
|
104
|
+
createdAt: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface CreateCategoryInput {
|
|
108
|
+
name: string
|
|
109
|
+
slug?: string
|
|
110
|
+
description?: string
|
|
111
|
+
parentId?: string
|
|
112
|
+
sortOrder?: number
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface UpdateCategoryInput {
|
|
116
|
+
name?: string
|
|
117
|
+
slug?: string
|
|
118
|
+
description?: string | null
|
|
119
|
+
parentId?: string | null
|
|
120
|
+
sortOrder?: number
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// Order
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
export type OrderStatus = 'open' | 'archived' | 'cancelled'
|
|
128
|
+
export type FinancialStatus = 'pending' | 'paid' | 'partially_paid' | 'refunded' | 'partially_refunded' | 'voided'
|
|
129
|
+
export type FulfillmentStatus = 'unfulfilled' | 'partially_fulfilled' | 'fulfilled'
|
|
130
|
+
|
|
131
|
+
export interface Order {
|
|
132
|
+
id: string
|
|
133
|
+
tenantId: string
|
|
134
|
+
orderNumber: number
|
|
135
|
+
status: OrderStatus
|
|
136
|
+
financialStatus: FinancialStatus
|
|
137
|
+
fulfillmentStatus: FulfillmentStatus
|
|
138
|
+
currency: string
|
|
139
|
+
subtotal: number
|
|
140
|
+
taxTotal: number
|
|
141
|
+
discountTotal: number
|
|
142
|
+
shippingTotal: number
|
|
143
|
+
total: number
|
|
144
|
+
customerId: string | null
|
|
145
|
+
customerName: string | null
|
|
146
|
+
customerEmail: string | null
|
|
147
|
+
discountCode: string | null
|
|
148
|
+
notes: string | null
|
|
149
|
+
items: OrderItem[]
|
|
150
|
+
createdAt: string
|
|
151
|
+
updatedAt: string
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface OrderItem {
|
|
155
|
+
id: string
|
|
156
|
+
orderId: string
|
|
157
|
+
productId: string | null
|
|
158
|
+
name: string
|
|
159
|
+
sku: string | null
|
|
160
|
+
quantity: number
|
|
161
|
+
unitPrice: number
|
|
162
|
+
total: number
|
|
163
|
+
imageUrl: string | null
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface CreateOrderInput {
|
|
167
|
+
customerId?: string
|
|
168
|
+
customerName?: string
|
|
169
|
+
customerEmail?: string
|
|
170
|
+
currency?: string
|
|
171
|
+
notes?: string
|
|
172
|
+
discountCode?: string
|
|
173
|
+
discountTotal?: number
|
|
174
|
+
shippingTotal?: number
|
|
175
|
+
items: Array<{
|
|
176
|
+
productId?: string
|
|
177
|
+
name: string
|
|
178
|
+
sku?: string
|
|
179
|
+
quantity: number
|
|
180
|
+
unitPrice: number
|
|
181
|
+
imageUrl?: string
|
|
182
|
+
}>
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export interface UpdateOrderInput {
|
|
186
|
+
status?: OrderStatus
|
|
187
|
+
financialStatus?: FinancialStatus
|
|
188
|
+
fulfillmentStatus?: FulfillmentStatus
|
|
189
|
+
notes?: string
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface ListOrdersOptions {
|
|
193
|
+
status?: OrderStatus
|
|
194
|
+
financialStatus?: FinancialStatus
|
|
195
|
+
fulfillmentStatus?: FulfillmentStatus
|
|
196
|
+
customerId?: string
|
|
197
|
+
customerEmail?: string
|
|
198
|
+
search?: string
|
|
199
|
+
limit?: number
|
|
200
|
+
offset?: number
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
// Order placement (server-trust primitive)
|
|
205
|
+
// ---------------------------------------------------------------------------
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* A single line in a trusted order-placement request. Carries NO price — the
|
|
209
|
+
* server re-reads the product price from the catalog so the browser can never
|
|
210
|
+
* set what it pays.
|
|
211
|
+
*/
|
|
212
|
+
export interface PlaceOrderLine {
|
|
213
|
+
productId: string
|
|
214
|
+
quantity: number
|
|
215
|
+
/** Variant/options label appended to the stored item name (display only). */
|
|
216
|
+
optionsLabel?: string
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Input for {@link ShopProvider.placeOrder} — the only trusted path to create a
|
|
221
|
+
* storefront order. Prices, discount math, and inventory are resolved
|
|
222
|
+
* server-side; the client supplies product ids, quantities, and intent only.
|
|
223
|
+
*/
|
|
224
|
+
export interface PlaceOrderInput {
|
|
225
|
+
/** Tenant/store id. The Supabase provider falls back to the resolved shop tenant. */
|
|
226
|
+
tenantId?: string
|
|
227
|
+
/** Existing customer id (preferred when the session already resolved one). */
|
|
228
|
+
customerId?: string
|
|
229
|
+
/** Customer identity for find-or-create when {@link PlaceOrderInput.customerId} is absent. */
|
|
230
|
+
customer?: { name?: string; email?: string }
|
|
231
|
+
currency?: string
|
|
232
|
+
notes?: string
|
|
233
|
+
/** Discount code to validate + apply server-side (never trust a client total). */
|
|
234
|
+
discountCode?: string
|
|
235
|
+
/** Shipping cost from the store's shipping policy. Clamped to >= 0 server-side. */
|
|
236
|
+
shippingTotal?: number
|
|
237
|
+
items: PlaceOrderLine[]
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// Customer
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
export interface ShopCustomer {
|
|
245
|
+
id: string
|
|
246
|
+
tenantId: string
|
|
247
|
+
firstName: string
|
|
248
|
+
lastName: string
|
|
249
|
+
email: string | null
|
|
250
|
+
phone: string | null
|
|
251
|
+
notes: string | null
|
|
252
|
+
ordersCount: number
|
|
253
|
+
totalSpent: number
|
|
254
|
+
createdAt: string
|
|
255
|
+
updatedAt: string
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export interface CreateCustomerInput {
|
|
259
|
+
firstName: string
|
|
260
|
+
lastName?: string
|
|
261
|
+
email?: string
|
|
262
|
+
phone?: string
|
|
263
|
+
notes?: string
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export interface UpdateCustomerInput {
|
|
267
|
+
firstName?: string
|
|
268
|
+
lastName?: string
|
|
269
|
+
email?: string | null
|
|
270
|
+
phone?: string | null
|
|
271
|
+
notes?: string | null
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export interface ListCustomersOptions {
|
|
275
|
+
search?: string
|
|
276
|
+
limit?: number
|
|
277
|
+
offset?: number
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Input for {@link ShopProvider.resolveCustomer} — find-or-create a customer by
|
|
282
|
+
* email and (on Supabase) link it to the authenticated user (auth.uid) so
|
|
283
|
+
* "my orders" can be enforced by RLS. Runs server-side; the browser never
|
|
284
|
+
* supplies the auth id.
|
|
285
|
+
*/
|
|
286
|
+
export interface ResolveCustomerInput {
|
|
287
|
+
email: string
|
|
288
|
+
name?: string
|
|
289
|
+
/** Tenant/store id. The Supabase provider falls back to the resolved shop tenant. */
|
|
290
|
+
tenantId?: string
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ---------------------------------------------------------------------------
|
|
294
|
+
// Discount
|
|
295
|
+
// ---------------------------------------------------------------------------
|
|
296
|
+
|
|
297
|
+
export type DiscountType = 'percentage' | 'fixed_amount' | 'free_shipping' | 'buy_x_get_y'
|
|
298
|
+
export type DiscountMethod = 'code' | 'automatic'
|
|
299
|
+
export type DiscountStatus = 'active' | 'expired' | 'scheduled' | 'draft'
|
|
300
|
+
|
|
301
|
+
export interface Discount {
|
|
302
|
+
id: string
|
|
303
|
+
tenantId: string
|
|
304
|
+
title: string
|
|
305
|
+
code: string | null
|
|
306
|
+
type: DiscountType
|
|
307
|
+
method: DiscountMethod
|
|
308
|
+
value: number
|
|
309
|
+
usageLimit: number | null
|
|
310
|
+
oncePerCustomer: boolean
|
|
311
|
+
startsAt: string
|
|
312
|
+
endsAt: string | null
|
|
313
|
+
status: DiscountStatus
|
|
314
|
+
timesUsed: number
|
|
315
|
+
createdAt: string
|
|
316
|
+
updatedAt: string
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export interface CreateDiscountInput {
|
|
320
|
+
title: string
|
|
321
|
+
code?: string
|
|
322
|
+
type: DiscountType
|
|
323
|
+
method?: DiscountMethod
|
|
324
|
+
value: number
|
|
325
|
+
usageLimit?: number
|
|
326
|
+
oncePerCustomer?: boolean
|
|
327
|
+
startsAt?: string
|
|
328
|
+
endsAt?: string
|
|
329
|
+
status?: DiscountStatus
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export interface UpdateDiscountInput {
|
|
333
|
+
title?: string
|
|
334
|
+
code?: string | null
|
|
335
|
+
type?: DiscountType
|
|
336
|
+
method?: DiscountMethod
|
|
337
|
+
value?: number
|
|
338
|
+
usageLimit?: number | null
|
|
339
|
+
oncePerCustomer?: boolean
|
|
340
|
+
startsAt?: string
|
|
341
|
+
endsAt?: string | null
|
|
342
|
+
status?: DiscountStatus
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export interface ListDiscountsOptions {
|
|
346
|
+
status?: DiscountStatus
|
|
347
|
+
type?: DiscountType
|
|
348
|
+
search?: string
|
|
349
|
+
limit?: number
|
|
350
|
+
offset?: number
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ---------------------------------------------------------------------------
|
|
354
|
+
// Commerce primitives (FAY-1193) — provider-agnostic helpers for custom workflows
|
|
355
|
+
// ---------------------------------------------------------------------------
|
|
356
|
+
|
|
357
|
+
export interface DiscountValidation {
|
|
358
|
+
valid: boolean
|
|
359
|
+
code: string | null
|
|
360
|
+
type: DiscountType | null
|
|
361
|
+
/** Percentage points for 'percentage'; absolute amount for 'fixed_amount'. */
|
|
362
|
+
value: number
|
|
363
|
+
/** Machine-readable reason when invalid: not_found | expired | not_started | usage_limit | unsupported | empty */
|
|
364
|
+
reason?: string
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export interface InventoryLine {
|
|
368
|
+
productId: string
|
|
369
|
+
quantity: number
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export interface InventoryIssue {
|
|
373
|
+
productId: string
|
|
374
|
+
name: string
|
|
375
|
+
requested: number
|
|
376
|
+
available: number
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export interface InventoryCheck {
|
|
380
|
+
ok: boolean
|
|
381
|
+
issues: InventoryIssue[]
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export interface CartTotalLine {
|
|
385
|
+
productId: string
|
|
386
|
+
name: string
|
|
387
|
+
sku: string | null
|
|
388
|
+
unitPrice: number
|
|
389
|
+
quantity: number
|
|
390
|
+
lineTotal: number
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export interface CartTotals {
|
|
394
|
+
lines: CartTotalLine[]
|
|
395
|
+
subtotal: number
|
|
396
|
+
discountTotal: number
|
|
397
|
+
discountCode: string | null
|
|
398
|
+
taxTotal: number
|
|
399
|
+
shippingTotal: number
|
|
400
|
+
total: number
|
|
401
|
+
}
|