@fayz-ai/shop 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.
- package/README.md +18 -1
- package/dist/admin.d.ts +2 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/catalog.d.ts +1 -3
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +2 -2
- package/dist/chunk-3GERSY5F.js +526 -0
- package/dist/chunk-3GERSY5F.js.map +1 -0
- package/dist/chunk-FQPGE3YN.js +3 -0
- package/dist/{chunk-JR25TISO.js.map → chunk-FQPGE3YN.js.map} +1 -1
- package/dist/{chunk-CTKZ6O2J.js → chunk-IKNGCRUM.js} +41 -15
- package/dist/chunk-IKNGCRUM.js.map +1 -0
- package/dist/{chunk-IYQHKMLB.js → chunk-IL6GA4ER.js} +4 -4
- package/dist/chunk-IL6GA4ER.js.map +1 -0
- package/dist/chunk-KLDS7IPU.js +17 -0
- package/dist/chunk-KLDS7IPU.js.map +1 -0
- package/dist/chunk-RGTIJQJL.js +93 -0
- package/dist/chunk-RGTIJQJL.js.map +1 -0
- package/dist/{chunk-SVTCJ6HP.js → chunk-U3O2I3RM.js} +395 -27
- package/dist/chunk-U3O2I3RM.js.map +1 -0
- package/dist/chunk-XERLK5LD.js +1415 -0
- package/dist/chunk-XERLK5LD.js.map +1 -0
- package/dist/chunk-XOP6SHPB.js +142 -0
- package/dist/chunk-XOP6SHPB.js.map +1 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/{mock-catalog.d.ts → data/mock-catalog.d.ts} +21 -1
- package/dist/data/mock-catalog.d.ts.map +1 -0
- package/dist/data/mock-provider.d.ts +133 -0
- package/dist/data/mock-provider.d.ts.map +1 -0
- package/dist/data/mock.d.ts +3 -0
- package/dist/data/mock.d.ts.map +1 -0
- package/dist/data/provider.d.ts +142 -0
- package/dist/data/provider.d.ts.map +1 -0
- package/dist/data/supabase-provider.d.ts +100 -0
- package/dist/data/supabase-provider.d.ts.map +1 -0
- package/dist/data/tables.d.ts +35 -0
- package/dist/data/tables.d.ts.map +1 -0
- package/dist/data/tenant.d.ts.map +1 -0
- package/dist/entities/entity-reconcile.d.ts +32 -0
- package/dist/entities/entity-reconcile.d.ts.map +1 -0
- package/dist/entities/entity-sql.d.ts +50 -0
- package/dist/entities/entity-sql.d.ts.map +1 -0
- package/dist/entities/entity-store.d.ts +58 -0
- package/dist/entities/entity-store.d.ts.map +1 -0
- package/dist/entities/index.d.ts +11 -0
- package/dist/entities/index.d.ts.map +1 -0
- package/dist/entities/mock-entity-store.d.ts +17 -0
- package/dist/entities/mock-entity-store.d.ts.map +1 -0
- package/dist/entities/sidecar.d.ts +9 -0
- package/dist/entities/sidecar.d.ts.map +1 -0
- package/dist/entities/supabase-entity-store.d.ts +8 -0
- package/dist/entities/supabase-entity-store.d.ts.map +1 -0
- package/dist/entities.js +159 -0
- package/dist/entities.js.map +1 -0
- package/dist/index.d.ts +17 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +728 -41
- package/dist/index.js.map +1 -1
- package/dist/inventory/allocation.d.ts +98 -0
- package/dist/inventory/allocation.d.ts.map +1 -0
- package/dist/inventory/index.d.ts +13 -0
- package/dist/inventory/index.d.ts.map +1 -0
- package/dist/inventory/mock-stock-store.d.ts +89 -0
- package/dist/inventory/mock-stock-store.d.ts.map +1 -0
- package/dist/inventory/postgrest-double.d.ts +65 -0
- package/dist/inventory/postgrest-double.d.ts.map +1 -0
- package/dist/inventory/shopify-mapping.d.ts +67 -0
- package/dist/inventory/shopify-mapping.d.ts.map +1 -0
- package/dist/inventory/stock-contract.d.ts +46 -0
- package/dist/inventory/stock-contract.d.ts.map +1 -0
- package/dist/inventory/stock-store.d.ts +96 -0
- package/dist/inventory/stock-store.d.ts.map +1 -0
- package/dist/inventory/stock-types.d.ts +292 -0
- package/dist/inventory/stock-types.d.ts.map +1 -0
- package/dist/inventory/supabase-stock-store.d.ts +59 -0
- package/dist/inventory/supabase-stock-store.d.ts.map +1 -0
- package/dist/inventory/vocabulary.d.ts +86 -0
- package/dist/inventory/vocabulary.d.ts.map +1 -0
- package/dist/inventory.js +4 -0
- package/dist/inventory.js.map +1 -0
- package/dist/lib/catalog.d.ts +4 -0
- package/dist/lib/catalog.d.ts.map +1 -0
- package/dist/{commerce.d.ts → lib/commerce.d.ts} +2 -2
- package/dist/lib/commerce.d.ts.map +1 -0
- package/dist/lib/emails.d.ts +50 -0
- package/dist/lib/emails.d.ts.map +1 -0
- package/dist/lib/message-events.d.ts +4 -0
- package/dist/lib/message-events.d.ts.map +1 -0
- package/dist/lib/runtime.d.ts +5 -0
- package/dist/lib/runtime.d.ts.map +1 -0
- package/dist/mock.d.ts +1 -2
- package/dist/mock.d.ts.map +1 -1
- package/dist/mock.js +4 -2
- package/dist/provider.d.ts +1 -88
- package/dist/provider.d.ts.map +1 -1
- package/dist/rules/adapter.d.ts +36 -0
- package/dist/rules/adapter.d.ts.map +1 -0
- package/dist/rules/attributes.d.ts +64 -0
- package/dist/rules/attributes.d.ts.map +1 -0
- package/dist/rules/context.d.ts +43 -0
- package/dist/rules/context.d.ts.map +1 -0
- package/dist/rules/evaluator.d.ts +37 -0
- package/dist/rules/evaluator.d.ts.map +1 -0
- package/dist/rules/index.d.ts +13 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/prices.d.ts +25 -0
- package/dist/rules/prices.d.ts.map +1 -0
- package/dist/rules/rule-types.d.ts +160 -0
- package/dist/rules/rule-types.d.ts.map +1 -0
- package/dist/rules.js +22 -0
- package/dist/rules.js.map +1 -0
- package/dist/runtime.d.ts +1 -4
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +5 -3
- package/dist/types.d.ts +231 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +26 -20
- package/dist/chunk-CTKZ6O2J.js.map +0 -1
- package/dist/chunk-IYQHKMLB.js.map +0 -1
- package/dist/chunk-JR25TISO.js +0 -3
- package/dist/chunk-SVTCJ6HP.js.map +0 -1
- package/dist/commerce.d.ts.map +0 -1
- package/dist/mock-catalog.d.ts.map +0 -1
- package/dist/mock-provider.d.ts +0 -60
- package/dist/mock-provider.d.ts.map +0 -1
- package/dist/supabase-provider.d.ts +0 -56
- package/dist/supabase-provider.d.ts.map +0 -1
- package/dist/tables.d.ts +0 -12
- package/dist/tables.d.ts.map +0 -1
- package/dist/tenant.d.ts.map +0 -1
- package/src/catalog.ts +0 -3
- package/src/commerce.ts +0 -120
- package/src/index.ts +0 -40
- package/src/mock-catalog.ts +0 -266
- package/src/mock-provider.ts +0 -480
- package/src/mock.ts +0 -2
- package/src/provider.ts +0 -117
- package/src/runtime.ts +0 -20
- package/src/supabase-provider.ts +0 -754
- package/src/tables.ts +0 -17
- package/src/tenant.ts +0 -21
- package/src/types.ts +0 -623
- /package/dist/{tenant.d.ts → data/tenant.d.ts} +0 -0
package/src/mock-provider.ts
DELETED
|
@@ -1,480 +0,0 @@
|
|
|
1
|
-
import type { ShopProvider } from './provider'
|
|
2
|
-
import type {
|
|
3
|
-
Product, ProductImage, Category, Order, ShopCustomer, Discount, ProductEnquiry,
|
|
4
|
-
CreateProductInput, UpdateProductInput, ListProductsOptions,
|
|
5
|
-
CreateProductEnquiryInput, ListProductEnquiriesOptions,
|
|
6
|
-
CreateCategoryInput, UpdateCategoryInput,
|
|
7
|
-
CreateOrderInput, UpdateOrderInput, ListOrdersOptions, PlaceOrderInput,
|
|
8
|
-
CreateCustomerInput, UpdateCustomerInput, ListCustomersOptions, ResolveCustomerInput,
|
|
9
|
-
CreateDiscountInput, UpdateDiscountInput, ListDiscountsOptions,
|
|
10
|
-
SalesChannel, CreateSalesChannelInput, UpdateSalesChannelInput,
|
|
11
|
-
} from './types'
|
|
12
|
-
import { MOCK_PRODUCTS, MOCK_CATEGORIES, MOCK_DISCOUNTS } from './mock-catalog'
|
|
13
|
-
|
|
14
|
-
function uid() { return Math.random().toString(36).slice(2) }
|
|
15
|
-
function now() { return new Date().toISOString() }
|
|
16
|
-
|
|
17
|
-
// Orders/customers persist to localStorage so "my purchases" survives a page
|
|
18
|
-
// reload. Products/categories/discounts always reseed from the catalog —
|
|
19
|
-
// the storefront sees a deterministic catalog on every load.
|
|
20
|
-
const ORDERS_KEY = 'fayz.shop.mock.orders.v1'
|
|
21
|
-
const CUSTOMERS_KEY = 'fayz.shop.mock.customers.v1'
|
|
22
|
-
const ENQUIRIES_KEY = 'fayz.shop.mock.enquiries.v1'
|
|
23
|
-
const CHANNELS_KEY = 'fayz.shop.mock.channels.v1'
|
|
24
|
-
|
|
25
|
-
const DEFAULT_CHANNELS: SalesChannel[] = [
|
|
26
|
-
{ id: 'online-store', tenantId: 'mock', kind: 'online_store', label: 'Loja Online', url: null, enabled: true, position: 0, createdAt: now(), updatedAt: now() },
|
|
27
|
-
]
|
|
28
|
-
|
|
29
|
-
function loadStored<T>(key: string): T[] {
|
|
30
|
-
try {
|
|
31
|
-
if (typeof localStorage === 'undefined') return []
|
|
32
|
-
const raw = localStorage.getItem(key)
|
|
33
|
-
return raw ? (JSON.parse(raw) as T[]) : []
|
|
34
|
-
} catch {
|
|
35
|
-
return []
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function store<T>(key: string, value: T[]): void {
|
|
40
|
-
try {
|
|
41
|
-
if (typeof localStorage === 'undefined') return
|
|
42
|
-
localStorage.setItem(key, JSON.stringify(value))
|
|
43
|
-
} catch {
|
|
44
|
-
/* quota/serialization failures are non-fatal in mock mode */
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface MockShopSeed {
|
|
49
|
-
products?: Product[]
|
|
50
|
-
categories?: Category[]
|
|
51
|
-
discounts?: Discount[]
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export class MockShopProvider implements ShopProvider {
|
|
55
|
-
private products: Product[]
|
|
56
|
-
private categories: Category[]
|
|
57
|
-
private discounts: Discount[]
|
|
58
|
-
private orders: Order[] = loadStored<Order>(ORDERS_KEY)
|
|
59
|
-
private customers: ShopCustomer[] = loadStored<ShopCustomer>(CUSTOMERS_KEY)
|
|
60
|
-
private enquiries: ProductEnquiry[] = loadStored<ProductEnquiry>(ENQUIRIES_KEY)
|
|
61
|
-
private channels: SalesChannel[] = (() => {
|
|
62
|
-
const stored = loadStored<SalesChannel>(CHANNELS_KEY)
|
|
63
|
-
return stored.length ? stored : DEFAULT_CHANNELS.map(c => ({ ...c }))
|
|
64
|
-
})()
|
|
65
|
-
|
|
66
|
-
constructor(seed?: MockShopSeed) {
|
|
67
|
-
this.products = (seed?.products ?? MOCK_PRODUCTS).map(p => ({ ...p }))
|
|
68
|
-
this.categories = (seed?.categories ?? MOCK_CATEGORIES).map(c => ({ ...c }))
|
|
69
|
-
this.discounts = (seed?.discounts ?? MOCK_DISCOUNTS).map(d => ({ ...d }))
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Re-read before mutating: HMR can re-instantiate the provider mid-session
|
|
73
|
-
// and a stale in-memory copy must not clobber persisted records.
|
|
74
|
-
private syncOrders() { this.orders = loadStored<Order>(ORDERS_KEY) }
|
|
75
|
-
private syncCustomers() { this.customers = loadStored<ShopCustomer>(CUSTOMERS_KEY) }
|
|
76
|
-
private syncEnquiries() { this.enquiries = loadStored<ProductEnquiry>(ENQUIRIES_KEY) }
|
|
77
|
-
private syncChannels() {
|
|
78
|
-
const stored = loadStored<SalesChannel>(CHANNELS_KEY)
|
|
79
|
-
if (stored.length) this.channels = stored
|
|
80
|
-
}
|
|
81
|
-
private persistOrders() { store(ORDERS_KEY, this.orders) }
|
|
82
|
-
private persistCustomers() { store(CUSTOMERS_KEY, this.customers) }
|
|
83
|
-
private persistEnquiries() { store(ENQUIRIES_KEY, this.enquiries) }
|
|
84
|
-
private persistChannels() { store(CHANNELS_KEY, this.channels) }
|
|
85
|
-
|
|
86
|
-
// ---------------------------------------------------------------------------
|
|
87
|
-
// Products
|
|
88
|
-
// ---------------------------------------------------------------------------
|
|
89
|
-
|
|
90
|
-
async listProducts(opts?: ListProductsOptions): Promise<Product[]> {
|
|
91
|
-
let list = [...this.products]
|
|
92
|
-
if (opts?.status) list = list.filter(p => p.status === opts.status)
|
|
93
|
-
if (opts?.categoryId) list = list.filter(p => p.categoryId === opts.categoryId)
|
|
94
|
-
if (opts?.slug) list = list.filter(p => p.slug === opts.slug)
|
|
95
|
-
if (opts?.search) {
|
|
96
|
-
const q = opts.search.toLowerCase()
|
|
97
|
-
list = list.filter(p =>
|
|
98
|
-
p.name.toLowerCase().includes(q) ||
|
|
99
|
-
(p.description ?? '').toLowerCase().includes(q) ||
|
|
100
|
-
(p.sku ?? '').toLowerCase().includes(q),
|
|
101
|
-
)
|
|
102
|
-
}
|
|
103
|
-
const orderBy = opts?.orderBy ?? 'sort_order'
|
|
104
|
-
const dir = opts?.order === 'desc' ? -1 : 1
|
|
105
|
-
list.sort((a, b) => {
|
|
106
|
-
switch (orderBy) {
|
|
107
|
-
case 'name': return a.name.localeCompare(b.name) * dir
|
|
108
|
-
case 'price': return (a.price - b.price) * dir
|
|
109
|
-
case 'created_at': return a.createdAt.localeCompare(b.createdAt) * dir
|
|
110
|
-
default: return (a.sortOrder - b.sortOrder) * dir
|
|
111
|
-
}
|
|
112
|
-
})
|
|
113
|
-
const offset = opts?.offset ?? 0
|
|
114
|
-
if (offset || opts?.limit) list = list.slice(offset, opts?.limit ? offset + opts.limit : undefined)
|
|
115
|
-
return list
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async getProduct(id: string) { return this.products.find(p => p.id === id) ?? null }
|
|
119
|
-
|
|
120
|
-
async createProduct(input: CreateProductInput): Promise<Product> {
|
|
121
|
-
const p: Product = { id: uid(), tenantId: 'mock', name: input.name, slug: input.slug ?? input.name.toLowerCase().replace(/\s+/g, '-'), description: input.description ?? null, price: input.price, compareAtPrice: input.compareAtPrice ?? null, currency: input.currency ?? 'BRL', status: input.status ?? 'active', inventoryCount: input.inventoryCount ?? 0, sku: input.sku ?? null, sortOrder: input.sortOrder ?? 0, metadata: input.metadata ?? {}, images: [], categoryId: input.categoryId ?? null, categoryName: null, isPhysical: input.isPhysical ?? true, weight: input.weight ?? null, weightUnit: input.weightUnit ?? 'kg', createdAt: now(), updatedAt: now() }
|
|
122
|
-
this.products.push(p); return p
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async updateProduct(id: string, input: UpdateProductInput): Promise<Product> {
|
|
126
|
-
const i = this.products.findIndex(p => p.id === id)
|
|
127
|
-
if (i < 0) throw new Error('Product not found')
|
|
128
|
-
this.products[i] = { ...this.products[i], ...input, updatedAt: now() }
|
|
129
|
-
return this.products[i]
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async deleteProduct(id: string) { this.products = this.products.filter(p => p.id !== id) }
|
|
133
|
-
async uploadProductImage(_productId: string, _file: File): Promise<ProductImage> { throw new Error('Image upload not available in mock mode') }
|
|
134
|
-
async deleteProductImage(_imageId: string) {}
|
|
135
|
-
|
|
136
|
-
async createProductEnquiry(input: CreateProductEnquiryInput): Promise<ProductEnquiry> {
|
|
137
|
-
this.syncEnquiries()
|
|
138
|
-
const ts = now()
|
|
139
|
-
const enquiry: ProductEnquiry = {
|
|
140
|
-
id: uid(),
|
|
141
|
-
tenantId: 'mock',
|
|
142
|
-
productId: input.productId ?? null,
|
|
143
|
-
productName: input.productName,
|
|
144
|
-
productSlug: input.productSlug ?? null,
|
|
145
|
-
customerName: input.customerName,
|
|
146
|
-
customerEmail: input.customerEmail,
|
|
147
|
-
customerPhone: input.customerPhone ?? null,
|
|
148
|
-
subject: input.subject ?? null,
|
|
149
|
-
message: input.message,
|
|
150
|
-
sourceUrl: input.sourceUrl ?? null,
|
|
151
|
-
status: 'new',
|
|
152
|
-
metadata: input.metadata ?? {},
|
|
153
|
-
createdAt: ts,
|
|
154
|
-
updatedAt: ts,
|
|
155
|
-
}
|
|
156
|
-
this.enquiries.unshift(enquiry)
|
|
157
|
-
this.persistEnquiries()
|
|
158
|
-
return enquiry
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async listProductEnquiries(opts?: ListProductEnquiriesOptions): Promise<ProductEnquiry[]> {
|
|
162
|
-
this.syncEnquiries()
|
|
163
|
-
let list = [...this.enquiries]
|
|
164
|
-
if (opts?.productId) list = list.filter((e) => e.productId === opts.productId)
|
|
165
|
-
if (opts?.customerEmail) {
|
|
166
|
-
const email = opts.customerEmail.toLowerCase()
|
|
167
|
-
list = list.filter((e) => e.customerEmail.toLowerCase() === email)
|
|
168
|
-
}
|
|
169
|
-
if (opts?.status) list = list.filter((e) => e.status === opts.status)
|
|
170
|
-
list.sort((a, b) => b.createdAt.localeCompare(a.createdAt))
|
|
171
|
-
const offset = opts?.offset ?? 0
|
|
172
|
-
if (offset || opts?.limit) list = list.slice(offset, opts?.limit ? offset + opts.limit : undefined)
|
|
173
|
-
return list
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// ---------------------------------------------------------------------------
|
|
177
|
-
// Categories
|
|
178
|
-
// ---------------------------------------------------------------------------
|
|
179
|
-
|
|
180
|
-
async listCategories() { return [...this.categories].sort((a, b) => a.sortOrder - b.sortOrder) }
|
|
181
|
-
|
|
182
|
-
async createCategory(input: CreateCategoryInput): Promise<Category> {
|
|
183
|
-
const c: Category = { id: uid(), tenantId: 'mock', name: input.name, slug: input.slug ?? input.name.toLowerCase().replace(/\s+/g, '-'), description: input.description ?? null, parentId: input.parentId ?? null, sortOrder: input.sortOrder ?? 0, createdAt: now() }
|
|
184
|
-
this.categories.push(c); return c
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async updateCategory(id: string, input: UpdateCategoryInput): Promise<Category> {
|
|
188
|
-
const i = this.categories.findIndex(c => c.id === id)
|
|
189
|
-
if (i < 0) throw new Error('Category not found')
|
|
190
|
-
this.categories[i] = { ...this.categories[i], ...input }
|
|
191
|
-
return this.categories[i]
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
async deleteCategory(id: string) { this.categories = this.categories.filter(c => c.id !== id) }
|
|
195
|
-
|
|
196
|
-
// ---------------------------------------------------------------------------
|
|
197
|
-
// Orders
|
|
198
|
-
// ---------------------------------------------------------------------------
|
|
199
|
-
|
|
200
|
-
async listOrders(opts?: ListOrdersOptions): Promise<Order[]> {
|
|
201
|
-
this.syncOrders()
|
|
202
|
-
let list = [...this.orders]
|
|
203
|
-
if (opts?.status) list = list.filter(o => o.status === opts.status)
|
|
204
|
-
if (opts?.financialStatus) list = list.filter(o => o.financialStatus === opts.financialStatus)
|
|
205
|
-
if (opts?.fulfillmentStatus) list = list.filter(o => o.fulfillmentStatus === opts.fulfillmentStatus)
|
|
206
|
-
if (opts?.customerId) list = list.filter(o => o.customerId === opts.customerId)
|
|
207
|
-
if (opts?.customerEmail) {
|
|
208
|
-
const email = opts.customerEmail.toLowerCase()
|
|
209
|
-
list = list.filter(o => (o.customerEmail ?? '').toLowerCase() === email)
|
|
210
|
-
}
|
|
211
|
-
if (opts?.search) {
|
|
212
|
-
const q = opts.search.toLowerCase()
|
|
213
|
-
list = list.filter(o =>
|
|
214
|
-
(o.customerName ?? '').toLowerCase().includes(q) ||
|
|
215
|
-
(o.customerEmail ?? '').toLowerCase().includes(q) ||
|
|
216
|
-
String(o.orderNumber).includes(q),
|
|
217
|
-
)
|
|
218
|
-
}
|
|
219
|
-
list.sort((a, b) => b.createdAt.localeCompare(a.createdAt))
|
|
220
|
-
if (opts?.limit) list = list.slice(0, opts.limit)
|
|
221
|
-
return list
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
async getOrder(id: string) {
|
|
225
|
-
this.syncOrders()
|
|
226
|
-
return this.orders.find(o => o.id === id) ?? null
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
async createOrder(input: CreateOrderInput): Promise<Order> {
|
|
230
|
-
this.syncOrders()
|
|
231
|
-
const subtotal = input.items.reduce((s, i) => s + i.quantity * i.unitPrice, 0)
|
|
232
|
-
const discountTotal = input.discountTotal ?? 0
|
|
233
|
-
const shippingTotal = input.shippingTotal ?? 0
|
|
234
|
-
const total = Math.round((subtotal - discountTotal + shippingTotal) * 100) / 100
|
|
235
|
-
const orderId = uid()
|
|
236
|
-
const maxNumber = this.orders.reduce((m, o) => Math.max(m, o.orderNumber), 1000)
|
|
237
|
-
const o: Order = {
|
|
238
|
-
id: orderId,
|
|
239
|
-
tenantId: 'mock',
|
|
240
|
-
orderNumber: maxNumber + 1,
|
|
241
|
-
status: 'open',
|
|
242
|
-
financialStatus: 'pending',
|
|
243
|
-
fulfillmentStatus: 'unfulfilled',
|
|
244
|
-
currency: input.currency ?? 'BRL',
|
|
245
|
-
subtotal: Math.round(subtotal * 100) / 100,
|
|
246
|
-
taxTotal: 0,
|
|
247
|
-
discountTotal,
|
|
248
|
-
shippingTotal,
|
|
249
|
-
total,
|
|
250
|
-
customerId: input.customerId ?? null,
|
|
251
|
-
customerName: input.customerName ?? null,
|
|
252
|
-
customerEmail: input.customerEmail ?? null,
|
|
253
|
-
discountCode: input.discountCode ?? null,
|
|
254
|
-
notes: input.notes ?? null,
|
|
255
|
-
shippingAddress: null,
|
|
256
|
-
// CreateOrderInput has no payment method — that is a PlaceOrderInput
|
|
257
|
-
// concern; the mock records none rather than inventing one.
|
|
258
|
-
paymentMethodKind: null,
|
|
259
|
-
paidAt: null,
|
|
260
|
-
items: input.items.map(i => ({ id: uid(), orderId, productId: i.productId ?? null, name: i.name, sku: i.sku ?? null, quantity: i.quantity, unitPrice: i.unitPrice, total: Math.round(i.quantity * i.unitPrice * 100) / 100, imageUrl: i.imageUrl ?? null })),
|
|
261
|
-
createdAt: now(),
|
|
262
|
-
updatedAt: now(),
|
|
263
|
-
}
|
|
264
|
-
this.orders.push(o)
|
|
265
|
-
this.persistOrders()
|
|
266
|
-
return o
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
async updateOrder(id: string, input: UpdateOrderInput): Promise<Order> {
|
|
270
|
-
this.syncOrders()
|
|
271
|
-
const i = this.orders.findIndex(o => o.id === id)
|
|
272
|
-
if (i < 0) throw new Error('Order not found')
|
|
273
|
-
this.orders[i] = { ...this.orders[i], ...input, updatedAt: now() }
|
|
274
|
-
this.persistOrders()
|
|
275
|
-
return this.orders[i]
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Trusted placement (mock parity with the shop_place_order RPC): re-reads
|
|
279
|
-
// prices + stock from the catalog, validates the discount, decrements
|
|
280
|
-
// inventory. The browser-supplied prices are never used.
|
|
281
|
-
async placeOrder(input: PlaceOrderInput): Promise<Order> {
|
|
282
|
-
this.syncOrders()
|
|
283
|
-
this.syncCustomers()
|
|
284
|
-
|
|
285
|
-
// Resolve / create the customer (find-or-create by email).
|
|
286
|
-
let customerId = input.customerId ?? null
|
|
287
|
-
let customerName = input.customer?.name?.trim() || null
|
|
288
|
-
const email = input.customer?.email?.trim().toLowerCase() || null
|
|
289
|
-
if (!customerId && email) {
|
|
290
|
-
const existing = this.customers.find(c => (c.email ?? '').toLowerCase() === email)
|
|
291
|
-
if (existing) {
|
|
292
|
-
customerId = existing.id
|
|
293
|
-
customerName = customerName ?? `${existing.firstName} ${existing.lastName}`.trim()
|
|
294
|
-
} else {
|
|
295
|
-
const [first, ...rest] = (customerName ?? email).split(' ')
|
|
296
|
-
const created = await this.createCustomer({ firstName: first || email, lastName: rest.join(' '), email })
|
|
297
|
-
customerId = created.id
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Re-read price + guard stock from the catalog (never trust the client).
|
|
302
|
-
const items: CreateOrderInput['items'] = []
|
|
303
|
-
// Per-line facts for coupon scoping (productId, categoryId, line total).
|
|
304
|
-
const lineDetails: Array<{ productId: string; categoryId: string | null; lineTotal: number }> = []
|
|
305
|
-
let subtotal = 0
|
|
306
|
-
for (const line of input.items) {
|
|
307
|
-
const product = this.products.find(p => p.id === line.productId)
|
|
308
|
-
if (!product || product.status !== 'active') throw new Error(`Product unavailable: ${line.productId}`)
|
|
309
|
-
if (product.inventoryCount < line.quantity) throw new Error(`Insufficient stock for ${product.name}`)
|
|
310
|
-
const name = line.optionsLabel ? `${product.name} (${line.optionsLabel})` : product.name
|
|
311
|
-
const lineTotal = product.price * line.quantity
|
|
312
|
-
subtotal += lineTotal
|
|
313
|
-
lineDetails.push({ productId: product.id, categoryId: product.categoryId, lineTotal })
|
|
314
|
-
items.push({ productId: product.id, name, sku: product.sku ?? undefined, quantity: line.quantity, unitPrice: product.price, imageUrl: product.images[0]?.url })
|
|
315
|
-
}
|
|
316
|
-
subtotal = Math.round(subtotal * 100) / 100
|
|
317
|
-
|
|
318
|
-
// Validate + apply the discount server-side.
|
|
319
|
-
let shippingTotal = Math.max(input.shippingTotal ?? 0, 0)
|
|
320
|
-
let discountTotal = 0
|
|
321
|
-
let appliedCode: string | null = null
|
|
322
|
-
if (input.discountCode) {
|
|
323
|
-
const code = input.discountCode.trim().toLowerCase()
|
|
324
|
-
const d = this.discounts.find(x => (x.code ?? '').toLowerCase() === code)
|
|
325
|
-
const ts = now()
|
|
326
|
-
const meetsMin = !d?.minSubtotal || subtotal >= d.minSubtotal
|
|
327
|
-
const valid = !!d && d.status === 'active' && d.startsAt <= ts && (!d.endsAt || d.endsAt >= ts) && (d.usageLimit == null || d.timesUsed < d.usageLimit) && meetsMin
|
|
328
|
-
if (valid && d) {
|
|
329
|
-
appliedCode = d.code
|
|
330
|
-
// Eligible subtotal = the part of the cart the coupon is scoped to.
|
|
331
|
-
// applies_to='all' → whole subtotal (unchanged for legacy coupons).
|
|
332
|
-
let eligible = subtotal
|
|
333
|
-
if (d.appliesTo === 'products') {
|
|
334
|
-
eligible = lineDetails.filter(l => d.productIds.includes(l.productId)).reduce((s, l) => s + l.lineTotal, 0)
|
|
335
|
-
} else if (d.appliesTo === 'categories') {
|
|
336
|
-
eligible = lineDetails.filter(l => l.categoryId && d.categoryIds.includes(l.categoryId)).reduce((s, l) => s + l.lineTotal, 0)
|
|
337
|
-
}
|
|
338
|
-
eligible = Math.round(eligible * 100) / 100
|
|
339
|
-
if (d.type === 'percentage') discountTotal = Math.round(eligible * d.value) / 100
|
|
340
|
-
else if (d.type === 'fixed_amount') discountTotal = Math.min(d.value, eligible)
|
|
341
|
-
else if (d.type === 'free_shipping') shippingTotal = 0
|
|
342
|
-
// buy_x_get_y unsupported in v1: code recorded, no monetary effect
|
|
343
|
-
d.timesUsed += 1
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
discountTotal = Math.round(Math.min(Math.max(discountTotal, 0), subtotal) * 100) / 100
|
|
347
|
-
|
|
348
|
-
// Persist via createOrder (recomputes total from these trusted values).
|
|
349
|
-
const order = await this.createOrder({
|
|
350
|
-
customerId: customerId ?? undefined,
|
|
351
|
-
customerName: customerName ?? undefined,
|
|
352
|
-
customerEmail: input.customer?.email ?? undefined,
|
|
353
|
-
currency: input.currency,
|
|
354
|
-
notes: input.notes,
|
|
355
|
-
discountCode: appliedCode ?? undefined,
|
|
356
|
-
discountTotal,
|
|
357
|
-
shippingTotal,
|
|
358
|
-
items,
|
|
359
|
-
})
|
|
360
|
-
|
|
361
|
-
// Decrement inventory (in-memory; the mock catalog reseeds on reload).
|
|
362
|
-
for (const line of input.items) {
|
|
363
|
-
const product = this.products.find(p => p.id === line.productId)
|
|
364
|
-
if (product) product.inventoryCount = Math.max(0, product.inventoryCount - line.quantity)
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return order
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// ---------------------------------------------------------------------------
|
|
371
|
-
// Customers
|
|
372
|
-
// ---------------------------------------------------------------------------
|
|
373
|
-
|
|
374
|
-
async listCustomers(opts?: ListCustomersOptions) {
|
|
375
|
-
this.syncCustomers()
|
|
376
|
-
let list = [...this.customers]
|
|
377
|
-
if (opts?.search) list = list.filter(c => `${c.firstName} ${c.lastName} ${c.email}`.toLowerCase().includes(opts.search!.toLowerCase()))
|
|
378
|
-
if (opts?.limit) list = list.slice(0, opts.limit)
|
|
379
|
-
return list
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
async getCustomer(id: string) {
|
|
383
|
-
this.syncCustomers()
|
|
384
|
-
return this.customers.find(c => c.id === id) ?? null
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
async createCustomer(input: CreateCustomerInput): Promise<ShopCustomer> {
|
|
388
|
-
this.syncCustomers()
|
|
389
|
-
const c: ShopCustomer = { id: uid(), tenantId: 'mock', firstName: input.firstName, lastName: input.lastName ?? '', email: input.email ?? null, phone: input.phone ?? null, notes: input.notes ?? null, ordersCount: 0, totalSpent: 0, createdAt: now(), updatedAt: now() }
|
|
390
|
-
this.customers.push(c)
|
|
391
|
-
this.persistCustomers()
|
|
392
|
-
return c
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
async updateCustomer(id: string, input: UpdateCustomerInput): Promise<ShopCustomer> {
|
|
396
|
-
this.syncCustomers()
|
|
397
|
-
const i = this.customers.findIndex(c => c.id === id)
|
|
398
|
-
if (i < 0) throw new Error('Customer not found')
|
|
399
|
-
this.customers[i] = { ...this.customers[i], ...input, updatedAt: now() }
|
|
400
|
-
this.persistCustomers()
|
|
401
|
-
return this.customers[i]
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
async deleteCustomer(id: string) {
|
|
405
|
-
this.syncCustomers()
|
|
406
|
-
this.customers = this.customers.filter(c => c.id !== id)
|
|
407
|
-
this.persistCustomers()
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
async resolveCustomer(input: ResolveCustomerInput): Promise<ShopCustomer> {
|
|
411
|
-
this.syncCustomers()
|
|
412
|
-
const email = input.email.trim().toLowerCase()
|
|
413
|
-
const existing = this.customers.find(c => (c.email ?? '').toLowerCase() === email)
|
|
414
|
-
if (existing) return existing
|
|
415
|
-
const [first, ...rest] = (input.name?.trim() || email).split(/\s+/)
|
|
416
|
-
return this.createCustomer({ firstName: first || email, lastName: rest.join(' '), email })
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// ---------------------------------------------------------------------------
|
|
420
|
-
// Discounts
|
|
421
|
-
// ---------------------------------------------------------------------------
|
|
422
|
-
|
|
423
|
-
async listDiscounts(opts?: ListDiscountsOptions) {
|
|
424
|
-
let list = [...this.discounts]
|
|
425
|
-
if (opts?.status) list = list.filter(d => d.status === opts.status)
|
|
426
|
-
if (opts?.type) list = list.filter(d => d.type === opts.type)
|
|
427
|
-
if (opts?.search) list = list.filter(d => d.title.toLowerCase().includes(opts.search!.toLowerCase()))
|
|
428
|
-
if (opts?.limit) list = list.slice(0, opts.limit)
|
|
429
|
-
return list
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
async getDiscount(id: string) { return this.discounts.find(d => d.id === id) ?? null }
|
|
433
|
-
|
|
434
|
-
async createDiscount(input: CreateDiscountInput): Promise<Discount> {
|
|
435
|
-
const d: Discount = { id: uid(), tenantId: 'mock', title: input.title, code: input.code ?? null, type: input.type, method: input.method ?? 'code', value: input.value, usageLimit: input.usageLimit ?? null, oncePerCustomer: input.oncePerCustomer ?? false, minSubtotal: input.minSubtotal ?? null, appliesTo: input.appliesTo ?? 'all', productIds: input.productIds ?? [], categoryIds: input.categoryIds ?? [], startsAt: input.startsAt ?? now(), endsAt: input.endsAt ?? null, status: input.status ?? 'active', timesUsed: 0, createdAt: now(), updatedAt: now() }
|
|
436
|
-
this.discounts.push(d); return d
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
async updateDiscount(id: string, input: UpdateDiscountInput): Promise<Discount> {
|
|
440
|
-
const i = this.discounts.findIndex(d => d.id === id)
|
|
441
|
-
if (i < 0) throw new Error('Discount not found')
|
|
442
|
-
this.discounts[i] = { ...this.discounts[i], ...input, updatedAt: now() }
|
|
443
|
-
return this.discounts[i]
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
async deleteDiscount(id: string) { this.discounts = this.discounts.filter(d => d.id !== id) }
|
|
447
|
-
|
|
448
|
-
// ---------------------------------------------------------------------------
|
|
449
|
-
// Sales channels
|
|
450
|
-
// ---------------------------------------------------------------------------
|
|
451
|
-
|
|
452
|
-
async listSalesChannels(): Promise<SalesChannel[]> {
|
|
453
|
-
this.syncChannels()
|
|
454
|
-
return [...this.channels].sort((a, b) => a.position - b.position)
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
async createSalesChannel(input: CreateSalesChannelInput): Promise<SalesChannel> {
|
|
458
|
-
this.syncChannels()
|
|
459
|
-
const c: SalesChannel = { id: uid(), tenantId: 'mock', kind: input.kind, label: input.label, url: input.url ?? null, enabled: input.enabled ?? true, position: input.position ?? this.channels.length, createdAt: now(), updatedAt: now() }
|
|
460
|
-
this.channels.push(c); this.persistChannels(); return c
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
async updateSalesChannel(id: string, input: UpdateSalesChannelInput): Promise<SalesChannel> {
|
|
464
|
-
this.syncChannels()
|
|
465
|
-
const i = this.channels.findIndex(c => c.id === id)
|
|
466
|
-
if (i < 0) throw new Error('Sales channel not found')
|
|
467
|
-
this.channels[i] = { ...this.channels[i], ...input, updatedAt: now() }
|
|
468
|
-
this.persistChannels(); return this.channels[i]
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
async deleteSalesChannel(id: string): Promise<void> {
|
|
472
|
-
this.syncChannels()
|
|
473
|
-
this.channels = this.channels.filter(c => c.id !== id)
|
|
474
|
-
this.persistChannels()
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
export function createMockShopProvider(seed?: MockShopSeed): ShopProvider {
|
|
479
|
-
return new MockShopProvider(seed)
|
|
480
|
-
}
|
package/src/mock.ts
DELETED
package/src/provider.ts
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Product, ProductImage, Category,
|
|
3
|
-
Order, ShopCustomer, Discount, ProductEnquiry,
|
|
4
|
-
CreateProductInput, UpdateProductInput, ListProductsOptions,
|
|
5
|
-
CreateProductEnquiryInput, ListProductEnquiriesOptions,
|
|
6
|
-
CreateCategoryInput, UpdateCategoryInput,
|
|
7
|
-
CreateOrderInput, UpdateOrderInput, ListOrdersOptions, PlaceOrderInput,
|
|
8
|
-
CreateCustomerInput, UpdateCustomerInput, ListCustomersOptions, ResolveCustomerInput,
|
|
9
|
-
CustomerAddress, ShippingQuoteOption,
|
|
10
|
-
ShippingZone, CreateShippingZoneInput, UpdateShippingZoneInput,
|
|
11
|
-
CreateDiscountInput, UpdateDiscountInput, ListDiscountsOptions,
|
|
12
|
-
SalesChannel, CreateSalesChannelInput, UpdateSalesChannelInput,
|
|
13
|
-
} from './types'
|
|
14
|
-
|
|
15
|
-
export interface ShopProvider {
|
|
16
|
-
// Products
|
|
17
|
-
listProducts(options?: ListProductsOptions): Promise<Product[]>
|
|
18
|
-
getProduct(id: string): Promise<Product | null>
|
|
19
|
-
createProduct(input: CreateProductInput): Promise<Product>
|
|
20
|
-
updateProduct(id: string, input: UpdateProductInput): Promise<Product>
|
|
21
|
-
deleteProduct(id: string): Promise<void>
|
|
22
|
-
uploadProductImage(productId: string, file: File): Promise<ProductImage>
|
|
23
|
-
deleteProductImage(imageId: string): Promise<void>
|
|
24
|
-
/**
|
|
25
|
-
* Reorder a gallery or promote a photo to primary. Optional so a provider
|
|
26
|
-
* that only ever holds one image per product need not implement it.
|
|
27
|
-
*
|
|
28
|
-
* Setting `isPrimary` is exclusive: the previous primary is demoted in the
|
|
29
|
-
* same call, because two primaries make "the product photo" ambiguous
|
|
30
|
-
* everywhere it is read (card, cart line, order item, admin table).
|
|
31
|
-
*/
|
|
32
|
-
updateProductImage?(
|
|
33
|
-
imageId: string,
|
|
34
|
-
input: { isPrimary?: boolean; sortOrder?: number; altText?: string | null },
|
|
35
|
-
): Promise<ProductImage>
|
|
36
|
-
|
|
37
|
-
// Product enquiries
|
|
38
|
-
createProductEnquiry?(input: CreateProductEnquiryInput): Promise<ProductEnquiry>
|
|
39
|
-
listProductEnquiries?(options?: ListProductEnquiriesOptions): Promise<ProductEnquiry[]>
|
|
40
|
-
|
|
41
|
-
// Categories
|
|
42
|
-
listCategories(): Promise<Category[]>
|
|
43
|
-
createCategory(input: CreateCategoryInput): Promise<Category>
|
|
44
|
-
updateCategory(id: string, input: UpdateCategoryInput): Promise<Category>
|
|
45
|
-
deleteCategory(id: string): Promise<void>
|
|
46
|
-
|
|
47
|
-
// Orders
|
|
48
|
-
listOrders(options?: ListOrdersOptions): Promise<Order[]>
|
|
49
|
-
getOrder(id: string): Promise<Order | null>
|
|
50
|
-
createOrder(input: CreateOrderInput): Promise<Order>
|
|
51
|
-
updateOrder(id: string, input: UpdateOrderInput): Promise<Order>
|
|
52
|
-
/**
|
|
53
|
-
* Mock/dev payment seam: pending->paid transition via a whitelisted RPC
|
|
54
|
-
* (anon storefronts have no UPDATE grant on the orders table). Real PSPs
|
|
55
|
-
* confirm via webhook with service_role instead.
|
|
56
|
-
*/
|
|
57
|
-
confirmPayment?(id: string, reference?: string): Promise<Order | null>
|
|
58
|
-
/**
|
|
59
|
-
* Trusted order placement: the server re-reads product prices + stock,
|
|
60
|
-
* validates the discount, computes totals, and decrements inventory
|
|
61
|
-
* atomically. Storefront checkout MUST use this instead of createOrder so the
|
|
62
|
-
* browser cannot tamper with prices. createOrder remains for trusted admin entry.
|
|
63
|
-
*/
|
|
64
|
-
placeOrder(input: PlaceOrderInput): Promise<Order>
|
|
65
|
-
|
|
66
|
-
// Customers
|
|
67
|
-
listCustomers(options?: ListCustomersOptions): Promise<ShopCustomer[]>
|
|
68
|
-
getCustomer(id: string): Promise<ShopCustomer | null>
|
|
69
|
-
createCustomer(input: CreateCustomerInput): Promise<ShopCustomer>
|
|
70
|
-
updateCustomer(id: string, input: UpdateCustomerInput): Promise<ShopCustomer>
|
|
71
|
-
deleteCustomer(id: string): Promise<void>
|
|
72
|
-
/**
|
|
73
|
-
* Find-or-create the customer for a storefront shopper and (on Supabase) link
|
|
74
|
-
* it to auth.uid server-side, so order reads can be scoped to the owner by RLS.
|
|
75
|
-
* Optional: providers without it fall back to listCustomers+createCustomer.
|
|
76
|
-
*/
|
|
77
|
-
resolveCustomer?(input: ResolveCustomerInput): Promise<ShopCustomer>
|
|
78
|
-
/**
|
|
79
|
-
* The signed-in shopper's saved delivery addresses, so checkout can offer
|
|
80
|
-
* them instead of inventing a placeholder. Optional: a provider without it
|
|
81
|
-
* (or an anonymous request) yields an empty book and a blank form.
|
|
82
|
-
*/
|
|
83
|
-
listCustomerAddresses?(customerId: string): Promise<CustomerAddress[]>
|
|
84
|
-
|
|
85
|
-
// Delivery
|
|
86
|
-
/**
|
|
87
|
-
* Delivery options for a postal code at a given subtotal. An empty array
|
|
88
|
-
* means the store does not deliver there — shown before the buyer commits to
|
|
89
|
-
* a cart, which is the whole point of quoting on the product page.
|
|
90
|
-
*
|
|
91
|
-
* This is for DISPLAY. shop_place_order recomputes the freight from the same
|
|
92
|
-
* zones and ignores whatever the client sends, so a tampered quote changes
|
|
93
|
-
* what the shopper sees and nothing about what they are charged.
|
|
94
|
-
*/
|
|
95
|
-
quoteShipping?(postalCode: string, subtotal: number): Promise<ShippingQuoteOption[]>
|
|
96
|
-
|
|
97
|
-
/** Delivery zones the merchant maintains. Admin-only: the storefront reads
|
|
98
|
-
* quotes, never the ranges themselves. */
|
|
99
|
-
listShippingZones?(): Promise<ShippingZone[]>
|
|
100
|
-
createShippingZone?(input: CreateShippingZoneInput): Promise<ShippingZone>
|
|
101
|
-
updateShippingZone?(id: string, input: UpdateShippingZoneInput): Promise<ShippingZone>
|
|
102
|
-
deleteShippingZone?(id: string): Promise<void>
|
|
103
|
-
|
|
104
|
-
// Discounts
|
|
105
|
-
listDiscounts(options?: ListDiscountsOptions): Promise<Discount[]>
|
|
106
|
-
getDiscount(id: string): Promise<Discount | null>
|
|
107
|
-
createDiscount(input: CreateDiscountInput): Promise<Discount>
|
|
108
|
-
updateDiscount(id: string, input: UpdateDiscountInput): Promise<Discount>
|
|
109
|
-
deleteDiscount(id: string): Promise<void>
|
|
110
|
-
|
|
111
|
-
// Sales channels — the store's points of sale (Loja Online, WhatsApp, …).
|
|
112
|
-
// Optional: a provider without them yields no "Canais de venda" section.
|
|
113
|
-
listSalesChannels?(): Promise<SalesChannel[]>
|
|
114
|
-
createSalesChannel?(input: CreateSalesChannelInput): Promise<SalesChannel>
|
|
115
|
-
updateSalesChannel?(id: string, input: UpdateSalesChannelInput): Promise<SalesChannel>
|
|
116
|
-
deleteSalesChannel?(id: string): Promise<void>
|
|
117
|
-
}
|
package/src/runtime.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { ShopProvider } from './provider'
|
|
2
|
-
import { createMockShopProvider } from './mock-provider'
|
|
3
|
-
|
|
4
|
-
let provider: ShopProvider | null = null
|
|
5
|
-
let mockFallback: ShopProvider | null = null
|
|
6
|
-
|
|
7
|
-
export function getShopProvider(): ShopProvider {
|
|
8
|
-
if (provider) return provider
|
|
9
|
-
if (!mockFallback) mockFallback = createMockShopProvider()
|
|
10
|
-
return mockFallback
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function setShopProvider(nextProvider: ShopProvider): void {
|
|
14
|
-
provider = nextProvider
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function resetShopProvider(): void {
|
|
18
|
-
provider = null
|
|
19
|
-
mockFallback = null
|
|
20
|
-
}
|