@use-stall/core 0.0.2 → 0.0.3
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 +345 -430
- package/dist/index.d.mts +690 -657
- package/dist/index.d.ts +690 -657
- package/dist/index.js +2084 -1247
- package/dist/index.mjs +2056 -1239
- package/package.json +3 -2
- package/bun.lock +0 -211
package/README.md
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
# Stall
|
|
1
|
+
# Stall Core SDK
|
|
2
2
|
|
|
3
|
-
A universal, type-safe SDK for integrating multiple commerce connectors (WooCommerce, Shopify, Medusa, etc.) with a unified interface. The SDK
|
|
3
|
+
A universal, type-safe, adapter-based SDK for integrating multiple e-commerce connectors (WooCommerce, Shopify, Medusa, etc.) with a unified interface. The SDK uses a dynamic adapter architecture with IndexedDB caching for optimal performance.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
The Stall SDK provides
|
|
7
|
+
The Stall Core SDK provides an adapter-based architecture that allows you to:
|
|
8
8
|
|
|
9
|
-
- **Load connector
|
|
10
|
-
- **Standardize operations** across different commerce platforms
|
|
11
|
-
- **Work with unified types** for
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
9
|
+
- **Load connector adapters dynamically** from a remote URL with automatic caching
|
|
10
|
+
- **Standardize operations** across different e-commerce platforms
|
|
11
|
+
- **Work with unified types** for products, orders, customers, inventory, and more
|
|
12
|
+
- **Implement CRUD + bulk operations** with a consistent API
|
|
13
|
+
- **Handle errors gracefully** with try-catch wrapped operations
|
|
14
|
+
- **Cache adapter modules** in IndexedDB with TTL-based invalidation
|
|
14
15
|
|
|
15
16
|
## Architecture
|
|
16
17
|
|
|
@@ -19,544 +20,458 @@ The Stall SDK provides a plugin-based architecture that allows you to:
|
|
|
19
20
|
│ Your Application │
|
|
20
21
|
└──────────────┬──────────────────────┘
|
|
21
22
|
│
|
|
22
|
-
|
|
23
|
-
│
|
|
24
|
-
│
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
┌───────▼──────────────────┐
|
|
24
|
+
│ initializeStallCore()
|
|
25
|
+
│ Returns: CoreConfig
|
|
26
|
+
└───────┬──────────────────┘
|
|
27
|
+
│
|
|
28
|
+
┌──────────▼──────────┐
|
|
29
|
+
│ Service Layer │
|
|
30
|
+
├─────────────────────┤
|
|
31
|
+
│ - products │
|
|
32
|
+
│ - orders │
|
|
33
|
+
│ - customers │
|
|
34
|
+
│ - variants │
|
|
35
|
+
│ - inventory_levels │
|
|
36
|
+
│ - promotions │
|
|
37
|
+
│ - refunds │
|
|
38
|
+
│ - payments │
|
|
39
|
+
│ - tax_regions │
|
|
40
|
+
│ - locations │
|
|
41
|
+
│ - fulfillments │
|
|
42
|
+
│ - ... and more │
|
|
43
|
+
└──────────┬──────────┘
|
|
36
44
|
│
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
┌──────────▼──────────────────┐
|
|
46
|
+
│ Adapter Module (Cached) │
|
|
47
|
+
│ ┌───────────────────────┐ │
|
|
48
|
+
│ │ - Products module │ │
|
|
49
|
+
│ │ - Orders module │ │
|
|
50
|
+
│ │ - Customers module │ │
|
|
51
|
+
│ │ - All modules │ │
|
|
52
|
+
│ └───────────────────────┘ │
|
|
53
|
+
│ │
|
|
54
|
+
│ Storage: IndexedDB + Dexie │
|
|
55
|
+
│ TTL: 4 hours (configurable)│
|
|
56
|
+
└──────────┬──────────────────┘
|
|
42
57
|
│
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
└─────────┬──────────┘
|
|
58
|
+
┌──────────▼──────────────────┐
|
|
59
|
+
│ Connector Loader │
|
|
60
|
+
│ (Dynamic Module Import) │
|
|
61
|
+
└──────────┬──────────────────┘
|
|
48
62
|
│
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
63
|
+
┌──────────▼──────────────────┐
|
|
64
|
+
│ Commerce Platform API │
|
|
65
|
+
│ (WooCommerce, Shopify, │
|
|
66
|
+
│ Medusa,Google Sheets etc.) │
|
|
67
|
+
└─────────────────────────────┘
|
|
54
68
|
```
|
|
55
69
|
|
|
56
70
|
## Installation
|
|
57
71
|
|
|
58
|
-
The SDK is part of `@use-stall/core`. Install it with:
|
|
59
|
-
|
|
60
72
|
```bash
|
|
61
|
-
npm install @use-stall/core
|
|
62
|
-
# or
|
|
63
73
|
bun install @use-stall/core
|
|
64
74
|
```
|
|
65
75
|
|
|
66
76
|
## Quick Start
|
|
67
77
|
|
|
68
|
-
###
|
|
78
|
+
### Initialize the SDK
|
|
69
79
|
|
|
70
80
|
```typescript
|
|
71
|
-
import {
|
|
72
|
-
import { MockConnectorPlugin } from '@use-stall/core';
|
|
73
|
-
|
|
74
|
-
// Initialize the SDK with a mock connector for testing
|
|
75
|
-
const stall = await StallSDK.initializeWithPlugin(
|
|
76
|
-
{
|
|
77
|
-
id: 'config_123',
|
|
78
|
-
integration_id: 'mock',
|
|
79
|
-
created_at: Date.now(),
|
|
80
|
-
updated_at: Date.now(),
|
|
81
|
-
configuration: {
|
|
82
|
-
endpoint: 'https://example.com/api',
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
new MockConnectorPlugin()
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
// Create an order
|
|
89
|
-
const orderResult = await stall.orders.createOrder({
|
|
90
|
-
id: 'order_123',
|
|
91
|
-
order_number: 'ORD-001',
|
|
92
|
-
status: 'pending',
|
|
93
|
-
total: 99.99,
|
|
94
|
-
// ... other order fields
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
if (orderResult.success) {
|
|
98
|
-
console.log('Order created:', orderResult.data);
|
|
99
|
-
} else {
|
|
100
|
-
console.error('Failed to create order:', orderResult.error);
|
|
101
|
-
}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
### Remote Plugin Loading from Public URL
|
|
81
|
+
import { initializeStallCore, products, orders, customers } from '@use-stall/core';
|
|
105
82
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// Default: https://connectors.myapp.xyz/{integration_id}/index.js
|
|
111
|
-
const stall = await StallSDK.initialize({
|
|
112
|
-
id: 'config_123',
|
|
113
|
-
integration_id: 'woocommerce',
|
|
114
|
-
created_at: Date.now(),
|
|
115
|
-
updated_at: Date.now(),
|
|
83
|
+
// Initialize with connector configuration
|
|
84
|
+
const stall = initializeStallCore({
|
|
85
|
+
connector_url: 'https://connectors.myapp.xyz/woocommerce',
|
|
86
|
+
version: '1.0.0',
|
|
116
87
|
configuration: {
|
|
117
88
|
endpoint: 'https://myshop.com',
|
|
118
89
|
token: process.env.WOOCOMMERCE_TOKEN,
|
|
119
90
|
},
|
|
120
|
-
options: {
|
|
121
|
-
logLevel: 'info',
|
|
122
|
-
cachePlugins: true,
|
|
123
|
-
// connectorUrl is optional, defaults to https://connectors.myapp.xyz
|
|
124
|
-
},
|
|
125
91
|
});
|
|
126
|
-
|
|
127
|
-
// Verify connection
|
|
128
|
-
const isConnected = await stall.verify();
|
|
129
|
-
console.log('Connected:', isConnected);
|
|
130
|
-
|
|
131
|
-
// Get metadata
|
|
132
|
-
const metadata = stall.getMetadata();
|
|
133
|
-
console.log('Connector:', metadata.name, metadata.version);
|
|
134
|
-
|
|
135
|
-
// List products
|
|
136
|
-
const products = await stall.products.listProducts({ limit: 10 });
|
|
137
|
-
if (products.success) {
|
|
138
|
-
console.log('Products:', products.data);
|
|
139
|
-
}
|
|
140
92
|
```
|
|
141
93
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
### Orders Service
|
|
94
|
+
### Use Any Service
|
|
145
95
|
|
|
146
96
|
```typescript
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const
|
|
97
|
+
try {
|
|
98
|
+
// Products
|
|
99
|
+
const productList = await products.list({ sdk: stall, query: 'laptop' });
|
|
100
|
+
const product = await products.retrieve({ sdk: stall, id: 'prod_123' });
|
|
101
|
+
const newProduct = await products.create({
|
|
102
|
+
sdk: stall,
|
|
103
|
+
data: { name: 'New Product', price: 99.99 }
|
|
104
|
+
});
|
|
105
|
+
const updated = await products.update({
|
|
106
|
+
sdk: stall,
|
|
107
|
+
id: 'prod_123',
|
|
108
|
+
data: { price: 89.99 }
|
|
109
|
+
});
|
|
110
|
+
await products.delete({ sdk: stall, id: 'prod_123' });
|
|
111
|
+
|
|
112
|
+
// Bulk operations
|
|
113
|
+
const created = await products.bulk_create({
|
|
114
|
+
sdk: stall,
|
|
115
|
+
data: [{ name: 'Product 1' }, { name: 'Product 2' }]
|
|
116
|
+
});
|
|
117
|
+
const updated = await products.bulk_update({
|
|
118
|
+
sdk: stall,
|
|
119
|
+
data: [
|
|
120
|
+
{ id: 'prod_1', data: { name: 'Updated 1' } },
|
|
121
|
+
{ id: 'prod_2', data: { name: 'Updated 2' } },
|
|
122
|
+
]
|
|
123
|
+
});
|
|
124
|
+
await products.bulk_delete({ sdk: stall, ids: ['prod_1', 'prod_2'] });
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error('Operation failed:', error);
|
|
127
|
+
}
|
|
128
|
+
```
|
|
152
129
|
|
|
153
|
-
|
|
154
|
-
const result = await stall.orders.updateOrder('order_id', { status: 'completed' });
|
|
130
|
+
## Available Services
|
|
155
131
|
|
|
156
|
-
|
|
157
|
-
const result = await stall.orders.deleteOrder('order_id');
|
|
132
|
+
### Core CRUD Operations
|
|
158
133
|
|
|
159
|
-
|
|
160
|
-
const result = await stall.orders.listOrders({ limit: 20, offset: 0 });
|
|
134
|
+
Each service module provides 8 standard operations:
|
|
161
135
|
|
|
162
|
-
|
|
163
|
-
|
|
136
|
+
- **list(props)** - Get array of items with query search
|
|
137
|
+
- **retrieve(props)** - Get single item by ID
|
|
138
|
+
- **create(props)** - Create new item
|
|
139
|
+
- **update(props)** - Update existing item
|
|
140
|
+
- **delete(props)** - Delete item by ID
|
|
141
|
+
- **bulk_create(props)** - Create multiple items
|
|
142
|
+
- **bulk_update(props)** - Update multiple items
|
|
143
|
+
- **bulk_delete(props)** - Delete multiple items
|
|
164
144
|
|
|
165
|
-
|
|
166
|
-
const result = await stall.orders.getRefund('refund_id');
|
|
145
|
+
### Inventory & Catalog
|
|
167
146
|
|
|
168
|
-
|
|
169
|
-
|
|
147
|
+
```typescript
|
|
148
|
+
// Products
|
|
149
|
+
const productList = await products.list({ sdk: stall, query: 'laptop' });
|
|
150
|
+
const product = await products.retrieve({ sdk: stall, id: 'prod_123' });
|
|
151
|
+
const newProduct = await products.create({ sdk: stall, data: { name: 'New Product' } });
|
|
152
|
+
const updated = await products.update({ sdk: stall, id: 'prod_123', data: { price: 99.99 } });
|
|
153
|
+
await products.delete({ sdk: stall, id: 'prod_123' });
|
|
154
|
+
const bulkProducts = await products.bulk_create({ sdk: stall, data: [...] });
|
|
155
|
+
const updatedBulk = await products.bulk_update({ sdk: stall, data: [...] });
|
|
156
|
+
await products.bulk_delete({ sdk: stall, ids: ['prod_1', 'prod_2'] });
|
|
157
|
+
|
|
158
|
+
// Variants
|
|
159
|
+
const variantList = await variants.list({ sdk: stall, query: 'color-red' });
|
|
160
|
+
const variant = await variants.retrieve({ sdk: stall, id: 'var_123' });
|
|
161
|
+
|
|
162
|
+
// Categories
|
|
163
|
+
const categoryList = await categories.list({ sdk: stall, query: 'electronics' });
|
|
164
|
+
const category = await categories.retrieve({ sdk: stall, id: 'cat_123' });
|
|
165
|
+
|
|
166
|
+
// Collections
|
|
167
|
+
const collectionList = await collections.list({ sdk: stall, query: 'featured' });
|
|
168
|
+
const collection = await collections.retrieve({ sdk: stall, id: 'coll_123' });
|
|
169
|
+
const newCollection = await collections.create({ sdk: stall, data: { title: 'Summer Sale' } });
|
|
170
|
+
|
|
171
|
+
// Inventory Levels
|
|
172
|
+
const inventoryList = await inventory_levels.list({ sdk: stall, query: 'low' });
|
|
173
|
+
const inventory = await inventory_levels.retrieve({ sdk: stall, id: 'inv_123' });
|
|
174
|
+
const newInventory = await inventory_levels.create({ sdk: stall, data: { quantity: 100 } });
|
|
175
|
+
const updatedInventory = await inventory_levels.update({ sdk: stall, id: 'inv_123', data: { quantity: 150 } });
|
|
176
|
+
await inventory_levels.delete({ sdk: stall, id: 'inv_123' });
|
|
177
|
+
const bulkInventory = await inventory_levels.bulk_create({ sdk: stall, data: [...] });
|
|
178
|
+
const updatedBulkInventory = await inventory_levels.bulk_update({ sdk: stall, data: [...] });
|
|
179
|
+
await inventory_levels.bulk_delete({ sdk: stall, ids: ['inv_1', 'inv_2'] });
|
|
170
180
|
```
|
|
171
181
|
|
|
172
|
-
###
|
|
182
|
+
### Order Management
|
|
173
183
|
|
|
174
184
|
```typescript
|
|
175
|
-
//
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
185
|
+
// Orders
|
|
186
|
+
const orderList = await orders.list({ sdk: stall, query: 'pending' });
|
|
187
|
+
const order = await orders.retrieve({ sdk: stall, id: 'order_123' });
|
|
188
|
+
const newOrder = await orders.create({ sdk: stall, data: { customer_id: 'cust_123' } });
|
|
189
|
+
const updatedOrder = await orders.update({ sdk: stall, id: 'order_123', data: { status: 'shipped' } });
|
|
190
|
+
await orders.delete({ sdk: stall, id: 'order_123' });
|
|
191
|
+
|
|
192
|
+
// Order Notes
|
|
193
|
+
const noteList = await order_notes.list({ sdk: stall, query: 'urgent' });
|
|
194
|
+
const note = await order_notes.retrieve({ sdk: stall, id: 'note_123' });
|
|
195
|
+
const newNote = await order_notes.create({ sdk: stall, data: { text: 'Handle with care' } });
|
|
196
|
+
|
|
197
|
+
// Refunds
|
|
198
|
+
const refundList = await refunds.list({ sdk: stall, query: 'pending' });
|
|
199
|
+
const refund = await refunds.retrieve({ sdk: stall, id: 'ref_123' });
|
|
200
|
+
const newRefund = await refunds.create({ sdk: stall, data: { amount: 99.99 } });
|
|
201
|
+
```
|
|
183
202
|
|
|
184
|
-
|
|
185
|
-
const result = await stall.products.deleteProduct('product_id');
|
|
203
|
+
### Customer Management
|
|
186
204
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
});
|
|
205
|
+
```typescript
|
|
206
|
+
// Customers
|
|
207
|
+
const customers_list = await customers.list({ sdk: stall, query: 'john' });
|
|
208
|
+
const customer = await customers.retrieve({ sdk: stall, id: 'cust_123' });
|
|
209
|
+
const newCustomer = await customers.create({ sdk: stall, data: { email: 'john@example.com' } });
|
|
210
|
+
const updatedCustomer = await customers.update({ sdk: stall, id: 'cust_123', data: { phone: '+1234567890' } });
|
|
211
|
+
await customers.delete({ sdk: stall, id: 'cust_123' });
|
|
192
212
|
```
|
|
193
213
|
|
|
194
|
-
|
|
214
|
+
### Promotions
|
|
195
215
|
|
|
196
|
-
|
|
216
|
+
```typescript
|
|
217
|
+
// Promotions
|
|
218
|
+
const promotionList = await promotions.list({ sdk: stall, query: 'active' });
|
|
219
|
+
const promotion = await promotions.retrieve({ sdk: stall, id: 'promo_123' });
|
|
220
|
+
const newPromotion = await promotions.create({ sdk: stall, data: { code: 'SUMMER20' } });
|
|
221
|
+
```
|
|
197
222
|
|
|
198
|
-
|
|
223
|
+
### Payment Management
|
|
199
224
|
|
|
200
225
|
```typescript
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
226
|
+
// Payment Providers
|
|
227
|
+
const providerList = await payment_providers.list({ sdk: stall, query: 'stripe' });
|
|
228
|
+
const provider = await payment_providers.retrieve({ sdk: stall, id: 'pay_prov_123' });
|
|
229
|
+
const newProvider = await payment_providers.create({ sdk: stall, data: { name: 'PayPal' } });
|
|
230
|
+
const updatedProvider = await payment_providers.update({ sdk: stall, id: 'pay_prov_123', data: { status: 'active' } });
|
|
231
|
+
await payment_providers.delete({ sdk: stall, id: 'pay_prov_123' });
|
|
232
|
+
|
|
233
|
+
// Payments
|
|
234
|
+
const paymentList = await payments.list({ sdk: stall, query: 'successful' });
|
|
235
|
+
const payment = await payments.retrieve({ sdk: stall, id: 'pay_123' });
|
|
236
|
+
const newPayment = await payments.create({ sdk: stall, data: { amount: 199.99 } });
|
|
207
237
|
```
|
|
208
238
|
|
|
209
|
-
###
|
|
210
|
-
|
|
211
|
-
All operations return a standardized response:
|
|
239
|
+
### Tax & Location
|
|
212
240
|
|
|
213
241
|
```typescript
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
242
|
+
// Tax Regions
|
|
243
|
+
const taxRegionList = await tax_regions.list({ sdk: stall, query: 'US' });
|
|
244
|
+
const taxRegion = await tax_regions.retrieve({ sdk: stall, id: 'tax_reg_123' });
|
|
245
|
+
const newTaxRegion = await tax_regions.create({ sdk: stall, data: { country: 'US' } });
|
|
246
|
+
|
|
247
|
+
// Tax Rates
|
|
248
|
+
const taxRateList = await tax_rates.list({ sdk: stall, query: 'standard' });
|
|
249
|
+
const taxRate = await tax_rates.retrieve({ sdk: stall, id: 'tax_rate_123' });
|
|
250
|
+
const newTaxRate = await tax_rates.create({ sdk: stall, data: { rate: 0.1 } });
|
|
251
|
+
|
|
252
|
+
// Locations
|
|
253
|
+
const locationList = await locations.list({ sdk: stall, query: 'warehouse' });
|
|
254
|
+
const location = await locations.retrieve({ sdk: stall, id: 'loc_123' });
|
|
255
|
+
const newLocation = await locations.create({ sdk: stall, data: { name: 'Main Warehouse' } });
|
|
229
256
|
```
|
|
230
257
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
The SDK provides comprehensive error handling with specific error codes:
|
|
258
|
+
### Fulfillment
|
|
234
259
|
|
|
235
260
|
```typescript
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if (!result.success) {
|
|
241
|
-
switch (result.error?.code) {
|
|
242
|
-
case ErrorCodes.INVALID_CREDENTIALS:
|
|
243
|
-
console.error('Invalid connector credentials');
|
|
244
|
-
break;
|
|
245
|
-
case ErrorCodes.RATE_LIMITED:
|
|
246
|
-
console.error('Rate limit exceeded');
|
|
247
|
-
break;
|
|
248
|
-
case ErrorCodes.OPERATION_TIMEOUT:
|
|
249
|
-
console.error('Operation timed out');
|
|
250
|
-
break;
|
|
251
|
-
default:
|
|
252
|
-
console.error('Operation failed:', result.error?.message);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
} catch (error) {
|
|
256
|
-
if (error instanceof StallConnectorError) {
|
|
257
|
-
console.error('Connector error:', error.code, error.message);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
261
|
+
// Fulfillments
|
|
262
|
+
const fulfillmentList = await fulfillments.list({ sdk: stall, query: 'pending' });
|
|
263
|
+
const fulfillment = await fulfillments.retrieve({ sdk: stall, id: 'ful_123' });
|
|
264
|
+
const newFulfillment = await fulfillments.create({ sdk: stall, data: { order_id: 'order_123' } });
|
|
260
265
|
```
|
|
261
266
|
|
|
262
|
-
|
|
267
|
+
## Adapter Architecture
|
|
263
268
|
|
|
264
|
-
|
|
265
|
-
- **Plugin Errors**: `PLUGIN_LOAD_FAILED`, `PLUGIN_NOT_FOUND`
|
|
266
|
-
- **Operation Errors**: `OPERATION_FAILED`, `OPERATION_TIMEOUT`, `OPERATION_NOT_SUPPORTED`
|
|
267
|
-
- **Network Errors**: `NETWORK_ERROR`, `REQUEST_FAILED`, `RATE_LIMITED`
|
|
268
|
-
- **Validation Errors**: `VALIDATION_FAILED`, `INVALID_DATA`, `MISSING_REQUIRED_FIELD`
|
|
269
|
-
- **Auth Errors**: `UNAUTHORIZED`, `FORBIDDEN`, `TOKEN_EXPIRED`
|
|
270
|
-
- **Server Errors**: `INTERNAL_ERROR`, `SERVICE_UNAVAILABLE`
|
|
269
|
+
### How It Works
|
|
271
270
|
|
|
272
|
-
|
|
271
|
+
1. **Initialization**: `initializeStallCore()` creates a `CoreConfig` object with your connector settings
|
|
272
|
+
2. **Adapter Loading**: First service call triggers `sdk.adapter()` which:
|
|
273
|
+
- Checks IndexedDB cache for existing adapter module
|
|
274
|
+
- If cache exists and valid (TTL not expired): returns cached module
|
|
275
|
+
- If cache missing or expired: fetches fresh module from connector URL
|
|
276
|
+
- Stores module in IndexedDB with timestamp
|
|
277
|
+
3. **Module Execution**: Adapter module is imported dynamically and executes the requested operation
|
|
278
|
+
4. **Caching**: Subsequent calls reuse the cached module (up to 4 hours by default)
|
|
273
279
|
|
|
274
|
-
|
|
280
|
+
### Cache Behavior
|
|
275
281
|
|
|
276
282
|
```typescript
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
export class MyConnectorPlugin implements IConnectorPlugin {
|
|
281
|
-
metadata = {
|
|
282
|
-
id: 'my-connector',
|
|
283
|
-
name: 'My Connector',
|
|
284
|
-
version: '1.0.0',
|
|
285
|
-
description: 'My custom connector',
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
async initialize(config: ConnectorPluginConfig): Promise<void> {
|
|
289
|
-
// Initialize your connector with the provided configuration
|
|
290
|
-
this.endpoint = config.configuration.endpoint;
|
|
291
|
-
this.token = config.configuration.token;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
async verify(): Promise<ConnectorResponse<boolean>> {
|
|
295
|
-
// Verify the connector can connect to the external service
|
|
296
|
-
try {
|
|
297
|
-
await this.makeRequest('GET', '/status');
|
|
298
|
-
return { success: true, data: true };
|
|
299
|
-
} catch (error) {
|
|
300
|
-
return {
|
|
301
|
-
success: false,
|
|
302
|
-
error: { code: 'CONNECTION_FAILED', message: error.message },
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
getSupportedModules(): string[] {
|
|
308
|
-
return ['orders', 'products', 'customers', 'inventory'];
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
orders = {
|
|
312
|
-
create: async (order: UnifiedOrderType): Promise<ConnectorResponse<any>> => {
|
|
313
|
-
// Map from unified format to connector-specific format
|
|
314
|
-
const connectorOrder = this.mapOrderToConnectorFormat(order);
|
|
315
|
-
|
|
316
|
-
try {
|
|
317
|
-
const response = await this.makeRequest('POST', '/orders', connectorOrder);
|
|
318
|
-
return {
|
|
319
|
-
success: true,
|
|
320
|
-
data: this.mapOrderToUnifiedFormat(response),
|
|
321
|
-
};
|
|
322
|
-
} catch (error) {
|
|
323
|
-
return {
|
|
324
|
-
success: false,
|
|
325
|
-
error: { code: 'CREATE_FAILED', message: error.message },
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
},
|
|
329
|
-
|
|
330
|
-
get: async (orderId: string): Promise<ConnectorResponse<any>> => {
|
|
331
|
-
// Implementation
|
|
332
|
-
},
|
|
333
|
-
|
|
334
|
-
update: async (orderId: string, order: Partial<UnifiedOrderType>) => {
|
|
335
|
-
// Implementation
|
|
336
|
-
},
|
|
337
|
-
|
|
338
|
-
delete: async (orderId: string) => {
|
|
339
|
-
// Implementation
|
|
340
|
-
},
|
|
341
|
-
|
|
342
|
-
list: async (options?: any) => {
|
|
343
|
-
// Implementation
|
|
344
|
-
},
|
|
345
|
-
};
|
|
283
|
+
// First call - fetches from URL
|
|
284
|
+
const products1 = await products.list({ sdk: stall, query: 'laptop' });
|
|
346
285
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
customers = {
|
|
352
|
-
// Similar implementation for customers
|
|
353
|
-
};
|
|
286
|
+
// Subsequent calls within TTL - uses cache
|
|
287
|
+
const products2 = await products.list({ sdk: stall, query: 'shoes' });
|
|
288
|
+
const products3 = await products.list({ sdk: stall, query: 'hats' });
|
|
354
289
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
};
|
|
358
|
-
|
|
359
|
-
refunds = {
|
|
360
|
-
// Similar implementation for refunds
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
payments = {
|
|
364
|
-
// Similar implementation for payments
|
|
365
|
-
};
|
|
366
|
-
}
|
|
290
|
+
// Force refresh
|
|
291
|
+
await stall.refreshAdapter(); // Clears cache, fetches fresh module
|
|
367
292
|
```
|
|
368
293
|
|
|
369
|
-
##
|
|
294
|
+
## Error Handling
|
|
370
295
|
|
|
371
|
-
|
|
296
|
+
All service methods are wrapped in try-catch blocks and propagate errors:
|
|
372
297
|
|
|
373
298
|
```typescript
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
});
|
|
299
|
+
try {
|
|
300
|
+
const product = await products.retrieve({ sdk: stall, id: 'invalid_id' });
|
|
301
|
+
} catch (error) {
|
|
302
|
+
console.error('Failed to retrieve product:', error.message);
|
|
303
|
+
}
|
|
380
304
|
```
|
|
381
305
|
|
|
382
|
-
|
|
306
|
+
## Type Safety
|
|
383
307
|
|
|
384
|
-
|
|
385
|
-
import { createLogger } from '@use-stall/core';
|
|
308
|
+
All services use TypeScript types from `@use-stall/types`:
|
|
386
309
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
310
|
+
```typescript
|
|
311
|
+
import type {
|
|
312
|
+
UnifiedProductType,
|
|
313
|
+
UnifiedOrderType,
|
|
314
|
+
UnifiedCustomerType,
|
|
315
|
+
UnifiedVariantsType,
|
|
316
|
+
UnifiedInventoryLevelType,
|
|
317
|
+
UnifiedCollectionType,
|
|
318
|
+
UnifiedCategoryType,
|
|
319
|
+
UnifiedPromotion,
|
|
320
|
+
UnifiedOrderNote,
|
|
321
|
+
UnifiedOrderRefundType,
|
|
322
|
+
UnifiedPaymentProviderType,
|
|
323
|
+
UnifiedPaymentCollectionType,
|
|
324
|
+
UnifiedTaxRegionType,
|
|
325
|
+
UnifiedTaxRateType,
|
|
326
|
+
UnifiedLocationType,
|
|
327
|
+
UnifiedFulfillmentType,
|
|
328
|
+
} from '@use-stall/types';
|
|
392
329
|
```
|
|
393
330
|
|
|
394
331
|
## Configuration
|
|
395
332
|
|
|
396
|
-
###
|
|
333
|
+
### StallCoreConfigOptions
|
|
397
334
|
|
|
398
335
|
```typescript
|
|
399
|
-
interface
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
updated_at: number;
|
|
404
|
-
configuration: {
|
|
336
|
+
interface StallCoreConfigOptions {
|
|
337
|
+
connector_url: string; // URL to fetch adapter module from
|
|
338
|
+
version: string; // SDK/adapter version
|
|
339
|
+
configuration: { // Connector-specific credentials
|
|
405
340
|
endpoint: string;
|
|
341
|
+
token?: string;
|
|
406
342
|
username?: string;
|
|
407
343
|
password?: string;
|
|
408
|
-
|
|
409
|
-
api_key_header?: string;
|
|
410
|
-
api_key_value?: string;
|
|
344
|
+
api_key?: string;
|
|
411
345
|
[key: string]: any;
|
|
412
346
|
};
|
|
413
347
|
}
|
|
414
348
|
```
|
|
415
349
|
|
|
416
|
-
###
|
|
417
|
-
|
|
418
|
-
Extends `ConnectorConfigurationType` from `@use-stall/types`:
|
|
350
|
+
### CoreConfig (Returned from initialization)
|
|
419
351
|
|
|
420
352
|
```typescript
|
|
421
|
-
interface
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
timeout?: number;
|
|
426
|
-
retries?: number;
|
|
427
|
-
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
428
|
-
cachePlugins?: boolean;
|
|
429
|
-
connectorUrl?: string; // Base URL for public connector plugins
|
|
430
|
-
// Default: https://connectors.myapp.xyz
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
### ConnectorConfigurationType
|
|
436
|
-
|
|
437
|
-
```typescript
|
|
438
|
-
interface ConnectorConfigurationType {
|
|
439
|
-
id: string; // Configuration ID
|
|
440
|
-
integration_id: string; // Integration type (woocommerce, shopify, etc.)
|
|
441
|
-
created_at: number; // Timestamp
|
|
442
|
-
updated_at: number; // Timestamp
|
|
443
|
-
configuration: {
|
|
444
|
-
endpoint: string; // Platform API endpoint
|
|
445
|
-
username?: string; // Basic auth username
|
|
446
|
-
password?: string; // Basic auth password
|
|
447
|
-
token?: string; // Bearer token
|
|
448
|
-
api_key_header?: string; // API key header name
|
|
449
|
-
api_key_value?: string; // API key value
|
|
450
|
-
[key: string]: any; // Custom fields
|
|
451
|
-
};
|
|
353
|
+
interface CoreConfig {
|
|
354
|
+
options: StallCoreConfigOptions;
|
|
355
|
+
adapter: () => Promise<AdapterModuleType>; // Get or fetch adapter
|
|
356
|
+
refreshAdapter: () => Promise<AdapterModuleType>; // Force refresh
|
|
452
357
|
}
|
|
453
358
|
```
|
|
454
359
|
|
|
455
360
|
## Best Practices
|
|
456
361
|
|
|
457
|
-
1. **
|
|
362
|
+
1. **Initialize once**: Create the SDK instance once and reuse it
|
|
458
363
|
|
|
459
364
|
```typescript
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
// Handle success
|
|
463
|
-
} else {
|
|
464
|
-
// Handle error
|
|
465
|
-
console.error(result.error?.code, result.error?.message);
|
|
466
|
-
}
|
|
365
|
+
const stall = initializeStallCore({ ... });
|
|
366
|
+
// Use stall across your application
|
|
467
367
|
```
|
|
468
368
|
|
|
469
|
-
2. **Use
|
|
369
|
+
2. **Use the service imports**: Import services from the main package
|
|
470
370
|
|
|
471
371
|
```typescript
|
|
472
|
-
import
|
|
473
|
-
|
|
474
|
-
const order: UnifiedOrderType = {
|
|
475
|
-
id: 'order_123',
|
|
476
|
-
// ... other required fields
|
|
477
|
-
};
|
|
372
|
+
import { products, orders, customers } from '@use-stall/core';
|
|
478
373
|
```
|
|
479
374
|
|
|
480
|
-
3. **Handle
|
|
375
|
+
3. **Handle errors properly**: Always wrap calls in try-catch
|
|
481
376
|
|
|
482
377
|
```typescript
|
|
483
|
-
|
|
484
|
-
|
|
378
|
+
try {
|
|
379
|
+
const result = await products.list({ sdk: stall, query: 'search' });
|
|
380
|
+
} catch (error) {
|
|
381
|
+
// Handle error
|
|
485
382
|
}
|
|
486
383
|
```
|
|
487
384
|
|
|
488
|
-
4. **
|
|
385
|
+
4. **Leverage bulk operations**: For multiple operations, use bulk methods
|
|
489
386
|
|
|
490
387
|
```typescript
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
388
|
+
// Better than multiple create() calls
|
|
389
|
+
const items = await products.bulk_create({
|
|
390
|
+
sdk: stall,
|
|
391
|
+
data: [
|
|
392
|
+
{ name: 'Product 1' },
|
|
393
|
+
{ name: 'Product 2' },
|
|
394
|
+
{ name: 'Product 3' },
|
|
395
|
+
]
|
|
396
|
+
});
|
|
495
397
|
```
|
|
496
398
|
|
|
497
|
-
5. **
|
|
399
|
+
5. **Type your data**: Use TypeScript types for safety
|
|
498
400
|
|
|
499
401
|
```typescript
|
|
500
|
-
|
|
501
|
-
cachePlugins: true, // Default: true
|
|
502
|
-
}
|
|
503
|
-
```
|
|
402
|
+
import type { UnifiedProductType } from '@use-stall/types';
|
|
504
403
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
404
|
+
const product: UnifiedProductType = {
|
|
405
|
+
id: 'prod_123',
|
|
406
|
+
name: 'My Product',
|
|
407
|
+
// ... other fields
|
|
408
|
+
};
|
|
508
409
|
|
|
509
|
-
|
|
510
|
-
import { MockConnectorPlugin, StallSDK } from '@use-stall/core';
|
|
511
|
-
|
|
512
|
-
const mockStall = await StallSDK.initializeWithPlugin(
|
|
513
|
-
{
|
|
514
|
-
id: 'config_test',
|
|
515
|
-
integration_id: 'mock',
|
|
516
|
-
created_at: Date.now(),
|
|
517
|
-
updated_at: Date.now(),
|
|
518
|
-
configuration: { /* ... */ },
|
|
519
|
-
},
|
|
520
|
-
new MockConnectorPlugin()
|
|
521
|
-
);
|
|
410
|
+
await products.create({ sdk: stall, data: product });
|
|
522
411
|
```
|
|
523
412
|
|
|
524
|
-
##
|
|
525
|
-
|
|
526
|
-
Recommended environment variables for production:
|
|
527
|
-
|
|
528
|
-
```bash
|
|
529
|
-
# Connector URL (optional, defaults to https://connectors.myapp.xyz)
|
|
530
|
-
CONNECTOR_URL=https://connectors.myapp.xyz
|
|
413
|
+
## File Structure
|
|
531
414
|
|
|
532
|
-
# Connector-specific credentials (these go in the configuration object)
|
|
533
|
-
WOOCOMMERCE_TOKEN=your_token
|
|
534
|
-
SHOPIFY_TOKEN=your_token
|
|
535
|
-
MEDUSA_API_KEY=your_api_key
|
|
536
415
|
```
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
416
|
+
core/src/
|
|
417
|
+
├── core/
|
|
418
|
+
│ ├── init.ts (Initialization logic)
|
|
419
|
+
│ └── sdk.ts (Main exports + documentation)
|
|
420
|
+
├── services/ (Service modules - one per entity)
|
|
421
|
+
│ ├── products.service.ts
|
|
422
|
+
│ ├── orders.service.ts
|
|
423
|
+
│ ├── customers.service.ts
|
|
424
|
+
│ ├── collections.service.ts
|
|
425
|
+
│ ├── categories.service.ts
|
|
426
|
+
│ ├── variants.service.ts
|
|
427
|
+
│ ├── inventory-levels.service.ts
|
|
428
|
+
│ ├── promotions.service.ts
|
|
429
|
+
│ ├── order-notes.service.ts
|
|
430
|
+
│ ├── refunds.service.ts
|
|
431
|
+
│ ├── payment-providers.service.ts
|
|
432
|
+
│ ├── payments.service.ts
|
|
433
|
+
│ ├── tax-regions.service.ts
|
|
434
|
+
│ ├── tax-rates.service.ts
|
|
435
|
+
│ ├── locations.service.ts
|
|
436
|
+
│ └── fulfillments.service.ts
|
|
437
|
+
├── types/
|
|
438
|
+
│ └── core.d.ts (TypeScript definitions)
|
|
439
|
+
├── db/
|
|
440
|
+
│ ├── db.ts (Dexie database setup)
|
|
441
|
+
│ ├── schema.ts (Database schema)
|
|
442
|
+
│ └── helpers.ts (Database helpers)
|
|
443
|
+
└── index.ts (Main entry point)
|
|
554
444
|
```
|
|
555
445
|
|
|
556
|
-
##
|
|
557
|
-
|
|
558
|
-
|
|
446
|
+
## Service Summary
|
|
447
|
+
|
|
448
|
+
| Service | Purpose | Operations |
|
|
449
|
+
|---------|---------|-----------|
|
|
450
|
+
| `products` | Product management | CRUD + bulk |
|
|
451
|
+
| `variants` | Product variants | CRUD + bulk |
|
|
452
|
+
| `categories` | Product categories | CRUD + bulk |
|
|
453
|
+
| `collections` | Product collections | CRUD + bulk |
|
|
454
|
+
| `inventory_levels` | Inventory tracking | CRUD + bulk |
|
|
455
|
+
| `orders` | Order management | CRUD + bulk |
|
|
456
|
+
| `order_notes` | Order comments/notes | CRUD + bulk |
|
|
457
|
+
| `refunds` | Refund management | CRUD + bulk |
|
|
458
|
+
| `customers` | Customer management | CRUD + bulk |
|
|
459
|
+
| `promotions` | Promotions/discounts | CRUD + bulk |
|
|
460
|
+
| `payment_providers` | Payment providers | CRUD + bulk |
|
|
461
|
+
| `payments` | Payment transactions | CRUD + bulk |
|
|
462
|
+
| `tax_regions` | Tax configuration | CRUD + bulk |
|
|
463
|
+
| `tax_rates` | Tax rates | CRUD + bulk |
|
|
464
|
+
| `locations` | Store locations | CRUD + bulk |
|
|
465
|
+
| `fulfillments` | Order fulfillment | CRUD + bulk |
|
|
466
|
+
|
|
467
|
+
## Development
|
|
468
|
+
|
|
469
|
+
Built with Bun and TypeScript. The SDK uses:
|
|
470
|
+
|
|
471
|
+
- **Dexie.js** for IndexedDB management
|
|
472
|
+
- **@use-stall/types** for unified type definitions
|
|
473
|
+
- **TypeScript** for type safety
|
|
559
474
|
|
|
560
|
-
##
|
|
475
|
+
## License
|
|
561
476
|
|
|
562
|
-
|
|
477
|
+
MIT
|