@use-stall/core 0.0.1 → 0.0.2

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 ADDED
@@ -0,0 +1,562 @@
1
+ # Stall Universal Connector SDK
2
+
3
+ A universal, type-safe SDK for integrating multiple commerce connectors (WooCommerce, Shopify, Medusa, etc.) with a unified interface. The SDK enables seamless communication with various data sources while maintaining a consistent API across all connectors.
4
+
5
+ ## Overview
6
+
7
+ The Stall SDK provides a plugin-based architecture that allows you to:
8
+
9
+ - **Load connector plugins** dynamically from a public connector URL
10
+ - **Standardize operations** across different commerce platforms
11
+ - **Work with unified types** for orders, products, customers, and more
12
+ - **Handle authentication** transparently across different auth methods
13
+ - **Manage errors** consistently with detailed error codes and messages
14
+
15
+ ## Architecture
16
+
17
+ ```
18
+ ┌─────────────────────────────────────┐
19
+ │ Your Application │
20
+ └──────────────┬──────────────────────┘
21
+
22
+ ┌──────────────▼──────────────────────┐
23
+ │ StallSDK (Main Entry) │
24
+ │ - Firebase-style initialization │
25
+ │ - Service management │
26
+ └──────────────┬──────────────────────┘
27
+
28
+ ┌──────┴──────┐
29
+ │ │
30
+ ┌───────▼─────┐ ┌────▼──────────┐
31
+ │ Orders │ │ Products │
32
+ │ Service │ │ Service │
33
+ └───────┬─────┘ └────┬──────────┘
34
+ │ │
35
+ └──────┬──────┘
36
+
37
+ ┌─────────▼──────────┐
38
+ │ Plugin Manager │
39
+ │ - Lifecycle │
40
+ │ - Verification │
41
+ └─────────┬──────────┘
42
+
43
+ ┌─────────▼──────────┐
44
+ │ Connector Loader │
45
+ │ - Public URL │
46
+ │ - Caching │
47
+ └─────────┬──────────┘
48
+
49
+ ┌─────────▼──────────┐
50
+ │ Plugin Instance │
51
+ │ (WooCommerce, │
52
+ │ Shopify, etc.) │
53
+ └────────────────────┘
54
+ ```
55
+
56
+ ## Installation
57
+
58
+ The SDK is part of `@use-stall/core`. Install it with:
59
+
60
+ ```bash
61
+ npm install @use-stall/core
62
+ # or
63
+ bun install @use-stall/core
64
+ ```
65
+
66
+ ## Quick Start
67
+
68
+ ### Basic Usage
69
+
70
+ ```typescript
71
+ import { StallSDK } from '@use-stall/core';
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
105
+
106
+ ```typescript
107
+ import { StallSDK } from '@use-stall/core';
108
+
109
+ // Initialize with public connector URL
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(),
116
+ configuration: {
117
+ endpoint: 'https://myshop.com',
118
+ token: process.env.WOOCOMMERCE_TOKEN,
119
+ },
120
+ options: {
121
+ logLevel: 'info',
122
+ cachePlugins: true,
123
+ // connectorUrl is optional, defaults to https://connectors.myapp.xyz
124
+ },
125
+ });
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
+ ```
141
+
142
+ ## Services
143
+
144
+ ### Orders Service
145
+
146
+ ```typescript
147
+ // Create an order
148
+ const result = await stall.orders.createOrder(unifiedOrder);
149
+
150
+ // Get an order
151
+ const result = await stall.orders.getOrder('order_id');
152
+
153
+ // Update an order
154
+ const result = await stall.orders.updateOrder('order_id', { status: 'completed' });
155
+
156
+ // Delete/cancel an order
157
+ const result = await stall.orders.deleteOrder('order_id');
158
+
159
+ // List orders
160
+ const result = await stall.orders.listOrders({ limit: 20, offset: 0 });
161
+
162
+ // Create a refund
163
+ const result = await stall.orders.createRefund('order_id', refundData);
164
+
165
+ // Get a refund
166
+ const result = await stall.orders.getRefund('refund_id');
167
+
168
+ // List refunds
169
+ const result = await stall.orders.listRefunds('order_id');
170
+ ```
171
+
172
+ ### Products Service
173
+
174
+ ```typescript
175
+ // Create a product
176
+ const result = await stall.products.createProduct(unifiedProduct);
177
+
178
+ // Get a product
179
+ const result = await stall.products.getProduct('product_id');
180
+
181
+ // Update a product
182
+ const result = await stall.products.updateProduct('product_id', { price: 199.99 });
183
+
184
+ // Delete a product
185
+ const result = await stall.products.deleteProduct('product_id');
186
+
187
+ // List products
188
+ const result = await stall.products.listProducts({
189
+ limit: 50,
190
+ category: 'electronics'
191
+ });
192
+ ```
193
+
194
+ ## Types
195
+
196
+ ### Unified Types
197
+
198
+ The SDK uses unified types from `@use-stall/types`:
199
+
200
+ ```typescript
201
+ import type {
202
+ UnifiedOrderType,
203
+ UnifiedProductType,
204
+ UnifiedOrderRefundType,
205
+ ConnectorConfigurationType,
206
+ } from '@use-stall/core';
207
+ ```
208
+
209
+ ### Response Format
210
+
211
+ All operations return a standardized response:
212
+
213
+ ```typescript
214
+ interface ConnectorResponse<T> {
215
+ success: boolean;
216
+ data?: T;
217
+ error?: {
218
+ code: string;
219
+ message: string;
220
+ details?: Record<string, any>;
221
+ };
222
+ metadata?: {
223
+ timestamp: number;
224
+ connector_id: string;
225
+ operation: string;
226
+ request_id: string;
227
+ };
228
+ }
229
+ ```
230
+
231
+ ## Error Handling
232
+
233
+ The SDK provides comprehensive error handling with specific error codes:
234
+
235
+ ```typescript
236
+ import { StallConnectorError, ErrorCodes } from '@use-stall/core';
237
+
238
+ try {
239
+ const result = await stall.orders.createOrder(order);
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
+ }
260
+ ```
261
+
262
+ ### Error Codes
263
+
264
+ - **Configuration Errors**: `INVALID_CONFIGURATION`, `MISSING_CREDENTIALS`, `INVALID_CREDENTIALS`
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`
271
+
272
+ ## Creating Custom Connector Plugins
273
+
274
+ Connector plugins implement the `IConnectorPlugin` interface:
275
+
276
+ ```typescript
277
+ import type { IConnectorPlugin, ConnectorResponse, ConnectorPluginConfig } from '@use-stall/core';
278
+ import type { UnifiedOrderType, UnifiedProductType } from '@use-stall/types';
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
+ };
346
+
347
+ products = {
348
+ // Similar implementation for products
349
+ };
350
+
351
+ customers = {
352
+ // Similar implementation for customers
353
+ };
354
+
355
+ inventory = {
356
+ // Similar implementation for inventory
357
+ };
358
+
359
+ refunds = {
360
+ // Similar implementation for refunds
361
+ };
362
+
363
+ payments = {
364
+ // Similar implementation for payments
365
+ };
366
+ }
367
+ ```
368
+
369
+ ## Logging
370
+
371
+ The SDK includes built-in logging. Control the log level during initialization:
372
+
373
+ ```typescript
374
+ const stall = await StallSDK.initialize({
375
+ // ... config
376
+ options: {
377
+ logLevel: 'debug', // 'debug' | 'info' | 'warn' | 'error'
378
+ },
379
+ });
380
+ ```
381
+
382
+ You can also use the logger directly:
383
+
384
+ ```typescript
385
+ import { createLogger } from '@use-stall/core';
386
+
387
+ const logger = createLogger('MyApp', 'info');
388
+ logger.info('Application started');
389
+ logger.debug('Debug information');
390
+ logger.warn('Warning message');
391
+ logger.error('Error occurred', error);
392
+ ```
393
+
394
+ ## Configuration
395
+
396
+ ### ConnectorConfigurationType
397
+
398
+ ```typescript
399
+ interface ConnectorConfigurationType {
400
+ id: string;
401
+ integration_id: string;
402
+ created_at: number;
403
+ updated_at: number;
404
+ configuration: {
405
+ endpoint: string;
406
+ username?: string;
407
+ password?: string;
408
+ token?: string;
409
+ api_key_header?: string;
410
+ api_key_value?: string;
411
+ [key: string]: any;
412
+ };
413
+ }
414
+ ```
415
+
416
+ ### StallSDKOptions
417
+
418
+ Extends `ConnectorConfigurationType` from `@use-stall/types`:
419
+
420
+ ```typescript
421
+ interface StallSDKOptions extends ConnectorConfigurationType {
422
+ // Inherits: id, integration_id, created_at, updated_at, configuration
423
+
424
+ options?: {
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
+ };
452
+ }
453
+ ```
454
+
455
+ ## Best Practices
456
+
457
+ 1. **Always check the response**: Every SDK operation returns a `ConnectorResponse` that includes a `success` flag.
458
+
459
+ ```typescript
460
+ const result = await stall.orders.createOrder(order);
461
+ if (result.success) {
462
+ // Handle success
463
+ } else {
464
+ // Handle error
465
+ console.error(result.error?.code, result.error?.message);
466
+ }
467
+ ```
468
+
469
+ 2. **Use TypeScript types**: Leverage the unified types to ensure type safety.
470
+
471
+ ```typescript
472
+ import type { UnifiedOrderType } from '@use-stall/core';
473
+
474
+ const order: UnifiedOrderType = {
475
+ id: 'order_123',
476
+ // ... other required fields
477
+ };
478
+ ```
479
+
480
+ 3. **Handle module support checking**: Not all connectors support all modules.
481
+
482
+ ```typescript
483
+ if (stall.isModuleSupported('inventory')) {
484
+ // Safe to use inventory operations
485
+ }
486
+ ```
487
+
488
+ 4. **Verify connection on startup**: Always verify the connector is properly configured.
489
+
490
+ ```typescript
491
+ const isConnected = await stall.verify();
492
+ if (!isConnected) {
493
+ throw new Error('Failed to connect to connector');
494
+ }
495
+ ```
496
+
497
+ 5. **Cache plugins when appropriate**: For better performance, enable plugin caching.
498
+
499
+ ```typescript
500
+ options: {
501
+ cachePlugins: true, // Default: true
502
+ }
503
+ ```
504
+
505
+ ## Development with Mock Plugin
506
+
507
+ For local development and testing, use the `MockConnectorPlugin`:
508
+
509
+ ```typescript
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
+ );
522
+ ```
523
+
524
+ ## Environment Variables
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
531
+
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
+ ```
537
+
538
+ Example usage:
539
+
540
+ ```typescript
541
+ const stall = await StallSDK.initialize({
542
+ id: 'config_123',
543
+ integration_id: 'woocommerce',
544
+ created_at: Date.now(),
545
+ updated_at: Date.now(),
546
+ configuration: {
547
+ endpoint: 'https://myshop.com',
548
+ token: process.env.WOOCOMMERCE_TOKEN,
549
+ },
550
+ options: {
551
+ connectorUrl: process.env.CONNECTOR_URL || 'https://connectors.myapp.xyz',
552
+ },
553
+ });
554
+ ```
555
+
556
+ ## License
557
+
558
+ MIT
559
+
560
+ ## Support
561
+
562
+ For issues, questions, or contributions, please visit the Stall GitHub repository.