@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 +562 -0
- package/bun.lock +211 -0
- package/dist/index.d.mts +672 -3
- package/dist/index.d.ts +672 -3
- package/dist/index.js +1289 -9
- package/dist/index.mjs +1282 -7
- package/package.json +13 -12
- package/.README.md +0 -4
package/dist/index.js
CHANGED
|
@@ -20,20 +20,1300 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
BaseService: () => BaseService,
|
|
24
|
+
ConnectorLoader: () => ConnectorLoader,
|
|
25
|
+
ErrorCodes: () => ErrorCodes,
|
|
26
|
+
Logger: () => Logger,
|
|
27
|
+
MockConnectorPlugin: () => MockConnectorPlugin,
|
|
28
|
+
OrdersService: () => OrdersService,
|
|
29
|
+
PluginManager: () => PluginManager,
|
|
30
|
+
ProductsService: () => ProductsService,
|
|
31
|
+
StallConnectorError: () => StallConnectorError,
|
|
32
|
+
StallCore: () => StallCore,
|
|
33
|
+
createErrorResponse: () => createErrorResponse,
|
|
34
|
+
createLogger: () => createLogger,
|
|
35
|
+
generateRequestId: () => generateRequestId,
|
|
36
|
+
handleConnectorError: () => handleConnectorError
|
|
25
37
|
});
|
|
26
38
|
module.exports = __toCommonJS(index_exports);
|
|
27
39
|
|
|
28
|
-
// src/
|
|
29
|
-
var
|
|
30
|
-
|
|
40
|
+
// src/utils/logger.ts
|
|
41
|
+
var Logger = class {
|
|
42
|
+
level;
|
|
43
|
+
context;
|
|
44
|
+
constructor(context = "Stall", level = "info") {
|
|
45
|
+
this.context = context;
|
|
46
|
+
this.level = level;
|
|
47
|
+
}
|
|
48
|
+
shouldLog(level) {
|
|
49
|
+
const levels = {
|
|
50
|
+
debug: 0,
|
|
51
|
+
info: 1,
|
|
52
|
+
warn: 2,
|
|
53
|
+
error: 3
|
|
54
|
+
};
|
|
55
|
+
return levels[level] >= levels[this.level];
|
|
56
|
+
}
|
|
57
|
+
format(level, message, data) {
|
|
58
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
59
|
+
const prefix = `[${timestamp}] [${this.context}] [${level.toUpperCase()}]`;
|
|
60
|
+
if (data) {
|
|
61
|
+
return `${prefix} ${message} ${JSON.stringify(data)}`;
|
|
62
|
+
}
|
|
63
|
+
return `${prefix} ${message}`;
|
|
64
|
+
}
|
|
65
|
+
debug(message, data) {
|
|
66
|
+
if (this.shouldLog("debug")) {
|
|
67
|
+
console.debug(this.format("debug", message, data));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
info(message, data) {
|
|
71
|
+
if (this.shouldLog("info")) {
|
|
72
|
+
console.info(this.format("info", message, data));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
warn(message, data) {
|
|
76
|
+
if (this.shouldLog("warn")) {
|
|
77
|
+
console.warn(this.format("warn", message, data));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
error(message, error) {
|
|
81
|
+
if (this.shouldLog("error")) {
|
|
82
|
+
const data = error instanceof Error ? { message: error.message, stack: error.stack } : error;
|
|
83
|
+
console.error(this.format("error", message, data));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
setLevel(level) {
|
|
87
|
+
this.level = level;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
function createLogger(context = "Stall", level = "info") {
|
|
91
|
+
return new Logger(context, level);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/utils/error-handler.ts
|
|
95
|
+
var StallConnectorError = class extends Error {
|
|
96
|
+
code;
|
|
97
|
+
details;
|
|
98
|
+
statusCode;
|
|
99
|
+
constructor(message, code, statusCode, details) {
|
|
100
|
+
super(message);
|
|
101
|
+
this.name = "StallConnectorError";
|
|
102
|
+
this.code = code;
|
|
103
|
+
this.statusCode = statusCode;
|
|
104
|
+
this.details = details;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var ErrorCodes = {
|
|
108
|
+
// Initialization errors
|
|
109
|
+
INVALID_CONFIGURATION: "INVALID_CONFIGURATION",
|
|
110
|
+
MISSING_CREDENTIALS: "MISSING_CREDENTIALS",
|
|
111
|
+
INVALID_CREDENTIALS: "INVALID_CREDENTIALS",
|
|
112
|
+
PLUGIN_LOAD_FAILED: "PLUGIN_LOAD_FAILED",
|
|
113
|
+
PLUGIN_NOT_FOUND: "PLUGIN_NOT_FOUND",
|
|
114
|
+
// Operation errors
|
|
115
|
+
OPERATION_FAILED: "OPERATION_FAILED",
|
|
116
|
+
OPERATION_TIMEOUT: "OPERATION_TIMEOUT",
|
|
117
|
+
OPERATION_NOT_SUPPORTED: "OPERATION_NOT_SUPPORTED",
|
|
118
|
+
// Network errors
|
|
119
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
120
|
+
REQUEST_FAILED: "REQUEST_FAILED",
|
|
121
|
+
RATE_LIMITED: "RATE_LIMITED",
|
|
122
|
+
// Validation errors
|
|
123
|
+
VALIDATION_FAILED: "VALIDATION_FAILED",
|
|
124
|
+
INVALID_DATA: "INVALID_DATA",
|
|
125
|
+
MISSING_REQUIRED_FIELD: "MISSING_REQUIRED_FIELD",
|
|
126
|
+
// Authentication errors
|
|
127
|
+
UNAUTHORIZED: "UNAUTHORIZED",
|
|
128
|
+
FORBIDDEN: "FORBIDDEN",
|
|
129
|
+
TOKEN_EXPIRED: "TOKEN_EXPIRED",
|
|
130
|
+
// Server errors
|
|
131
|
+
INTERNAL_ERROR: "INTERNAL_ERROR",
|
|
132
|
+
SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE"
|
|
133
|
+
};
|
|
134
|
+
function handleConnectorError(error, context) {
|
|
135
|
+
if (error instanceof StallConnectorError) {
|
|
136
|
+
return error;
|
|
137
|
+
}
|
|
138
|
+
if (error?.response) {
|
|
139
|
+
const statusCode = error.response.status;
|
|
140
|
+
const data = error.response.data || error.response.body;
|
|
141
|
+
let code = ErrorCodes.REQUEST_FAILED;
|
|
142
|
+
if (statusCode === 401) code = ErrorCodes.UNAUTHORIZED;
|
|
143
|
+
else if (statusCode === 403) code = ErrorCodes.FORBIDDEN;
|
|
144
|
+
else if (statusCode === 429) code = ErrorCodes.RATE_LIMITED;
|
|
145
|
+
else if (statusCode >= 500) code = ErrorCodes.INTERNAL_ERROR;
|
|
146
|
+
return new StallConnectorError(
|
|
147
|
+
`${context}: ${data?.message || error.message}`,
|
|
148
|
+
code,
|
|
149
|
+
statusCode,
|
|
150
|
+
data
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
if (error?.code === "ECONNABORTED" || error?.message?.includes("timeout")) {
|
|
154
|
+
return new StallConnectorError(
|
|
155
|
+
`${context}: Operation timed out`,
|
|
156
|
+
ErrorCodes.OPERATION_TIMEOUT
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
if (error?.code === "ECONNREFUSED" || error?.code === "ENOTFOUND" || error?.message?.includes("network")) {
|
|
160
|
+
return new StallConnectorError(
|
|
161
|
+
`${context}: Network error - ${error.message}`,
|
|
162
|
+
ErrorCodes.NETWORK_ERROR
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
if (error?.name === "ValidationError") {
|
|
166
|
+
return new StallConnectorError(
|
|
167
|
+
`${context}: Validation failed - ${error.message}`,
|
|
168
|
+
ErrorCodes.VALIDATION_FAILED,
|
|
169
|
+
400,
|
|
170
|
+
error.details
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
return new StallConnectorError(
|
|
174
|
+
`${context}: ${error.message || "Unknown error"}`,
|
|
175
|
+
ErrorCodes.OPERATION_FAILED,
|
|
176
|
+
void 0,
|
|
177
|
+
error
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
function createErrorResponse(error, operation, connectorId) {
|
|
181
|
+
const isStallError = error instanceof StallConnectorError;
|
|
182
|
+
return {
|
|
183
|
+
success: false,
|
|
184
|
+
error: {
|
|
185
|
+
code: isStallError ? error.code : ErrorCodes.OPERATION_FAILED,
|
|
186
|
+
message: error.message,
|
|
187
|
+
details: isStallError ? error.details : void 0
|
|
188
|
+
},
|
|
189
|
+
metadata: {
|
|
190
|
+
connector_id: connectorId,
|
|
191
|
+
operation,
|
|
192
|
+
timestamp: Date.now(),
|
|
193
|
+
request_id: generateRequestId()
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function generateRequestId() {
|
|
198
|
+
return `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/core/connector-loader.ts
|
|
202
|
+
var ConnectorLoader = class {
|
|
203
|
+
logger;
|
|
204
|
+
connectorUrl;
|
|
205
|
+
cache = /* @__PURE__ */ new Map();
|
|
206
|
+
cacheTtl;
|
|
207
|
+
constructor(options) {
|
|
208
|
+
this.logger = new Logger("ConnectorLoader");
|
|
209
|
+
this.connectorUrl = options.connectorUrl;
|
|
210
|
+
this.cacheTtl = options.cacheTtl || 60 * 60 * 1e3;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Load a connector plugin from public URL
|
|
214
|
+
* URL pattern: {connectorUrl}/{integrationId}/index.js
|
|
215
|
+
*/
|
|
216
|
+
async loadConnector(integrationId) {
|
|
217
|
+
const cacheKey = integrationId;
|
|
218
|
+
if (this.cache.has(cacheKey)) {
|
|
219
|
+
this.logger.debug(`Loaded ${integrationId} from cache`);
|
|
220
|
+
return this.cache.get(cacheKey);
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
this.logger.info(`Loading connector plugin: ${integrationId}`);
|
|
224
|
+
const url = this.buildConnectorUrl(integrationId);
|
|
225
|
+
this.logger.debug(`Fetching from: ${url}`);
|
|
226
|
+
const response = await fetch(url);
|
|
227
|
+
if (!response.ok) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`Failed to fetch connector: ${response.statusText} (${response.status})`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
const code = await response.text();
|
|
233
|
+
const plugin = await this.instantiatePlugin(code, integrationId);
|
|
234
|
+
this.logger.info(`Successfully loaded ${integrationId}`);
|
|
235
|
+
this.cache.set(cacheKey, plugin);
|
|
236
|
+
return plugin;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
this.logger.error(
|
|
239
|
+
`Failed to load connector ${integrationId}`,
|
|
240
|
+
error
|
|
241
|
+
);
|
|
242
|
+
throw new StallConnectorError(
|
|
243
|
+
`Failed to load connector plugin: ${integrationId}`,
|
|
244
|
+
ErrorCodes.PLUGIN_LOAD_FAILED,
|
|
245
|
+
void 0,
|
|
246
|
+
{ originalError: error.message }
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Instantiate a plugin from code
|
|
252
|
+
*/
|
|
253
|
+
async instantiatePlugin(code, integrationId) {
|
|
254
|
+
try {
|
|
255
|
+
const moduleExports = {};
|
|
256
|
+
const module2 = { exports: moduleExports };
|
|
257
|
+
const fn = new Function(
|
|
258
|
+
"module",
|
|
259
|
+
"exports",
|
|
260
|
+
"require",
|
|
261
|
+
code + "\nreturn module.exports;"
|
|
262
|
+
);
|
|
263
|
+
const pluginModule = fn(
|
|
264
|
+
module2,
|
|
265
|
+
moduleExports,
|
|
266
|
+
this.createRequireProxy()
|
|
267
|
+
);
|
|
268
|
+
const PluginClass = pluginModule.default || pluginModule.Plugin;
|
|
269
|
+
if (!PluginClass) {
|
|
270
|
+
throw new Error("Plugin module does not export a default or Plugin");
|
|
271
|
+
}
|
|
272
|
+
const instance = new PluginClass();
|
|
273
|
+
if (!this.validatePlugin(instance)) {
|
|
274
|
+
throw new Error("Plugin does not implement IConnectorPlugin interface");
|
|
275
|
+
}
|
|
276
|
+
return instance;
|
|
277
|
+
} catch (error) {
|
|
278
|
+
throw new StallConnectorError(
|
|
279
|
+
`Failed to instantiate plugin: ${integrationId}`,
|
|
280
|
+
ErrorCodes.PLUGIN_LOAD_FAILED,
|
|
281
|
+
void 0,
|
|
282
|
+
{ originalError: error.message }
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Validate that an object implements IConnectorPlugin
|
|
288
|
+
*/
|
|
289
|
+
validatePlugin(plugin) {
|
|
290
|
+
const requiredMethods = ["initialize", "verify", "getSupportedModules"];
|
|
291
|
+
const requiredModules = ["orders", "products", "customers", "inventory"];
|
|
292
|
+
for (const method of requiredMethods) {
|
|
293
|
+
if (typeof plugin[method] !== "function") {
|
|
294
|
+
this.logger.warn(`Plugin missing method: ${method}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
for (const module2 of requiredModules) {
|
|
298
|
+
if (typeof plugin[module2] !== "object") {
|
|
299
|
+
this.logger.warn(`Plugin missing module: ${module2}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Build the connector plugin URL
|
|
306
|
+
* Pattern: {connectorUrl}/{integrationId}/index.js
|
|
307
|
+
*/
|
|
308
|
+
buildConnectorUrl(integrationId) {
|
|
309
|
+
const baseUrl = this.connectorUrl.endsWith("/") ? this.connectorUrl.slice(0, -1) : this.connectorUrl;
|
|
310
|
+
return `${baseUrl}/${integrationId}/index.js`;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Create a proxy for require() in loaded plugins
|
|
314
|
+
*/
|
|
315
|
+
createRequireProxy() {
|
|
316
|
+
return (id) => {
|
|
317
|
+
if (id === "@use-stall/types") {
|
|
318
|
+
return require("@use-stall/types");
|
|
319
|
+
}
|
|
320
|
+
if (id === "node:crypto" || id === "crypto") {
|
|
321
|
+
return require("crypto");
|
|
322
|
+
}
|
|
323
|
+
this.logger.warn(`Attempted to require unsupported module: ${id}`);
|
|
324
|
+
return {};
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Clear the cache
|
|
329
|
+
*/
|
|
330
|
+
clearCache() {
|
|
331
|
+
this.cache.clear();
|
|
332
|
+
this.logger.info("Plugin cache cleared");
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Remove a specific plugin from cache
|
|
336
|
+
*/
|
|
337
|
+
removeCacheEntry(integrationId) {
|
|
338
|
+
this.cache.delete(integrationId);
|
|
339
|
+
this.logger.info(`Removed ${integrationId} from cache`);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
// src/core/plugin-manager.ts
|
|
344
|
+
var PluginManager = class {
|
|
345
|
+
plugin = null;
|
|
346
|
+
logger;
|
|
347
|
+
connectorLoader = null;
|
|
348
|
+
initialized = false;
|
|
349
|
+
constructor(logLevel = "info") {
|
|
350
|
+
this.logger = new Logger("PluginManager", logLevel);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Initialize the plugin manager with a plugin
|
|
354
|
+
*/
|
|
355
|
+
async initialize(plugin, options) {
|
|
356
|
+
try {
|
|
357
|
+
if (!plugin) {
|
|
358
|
+
const connectorUrl = options.options?.connectorUrl || "https://connectors.myapp.xyz";
|
|
359
|
+
this.connectorLoader = new ConnectorLoader({
|
|
360
|
+
connectorUrl,
|
|
361
|
+
cache: options.options?.cachePlugins !== false
|
|
362
|
+
});
|
|
363
|
+
plugin = await this.connectorLoader.loadConnector(
|
|
364
|
+
options.integration_id
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
if (!plugin) {
|
|
368
|
+
throw new StallConnectorError(
|
|
369
|
+
"Failed to load connector plugin",
|
|
370
|
+
ErrorCodes.PLUGIN_NOT_FOUND
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
this.plugin = plugin;
|
|
374
|
+
const pluginConfig = {
|
|
375
|
+
connectorId: options.id,
|
|
376
|
+
integrationId: options.integration_id,
|
|
377
|
+
organizationId: options.id,
|
|
378
|
+
// Use the config id as org context
|
|
379
|
+
configuration: options.configuration,
|
|
380
|
+
options: options.options
|
|
381
|
+
};
|
|
382
|
+
await this.plugin.initialize(pluginConfig);
|
|
383
|
+
this.logger.info(
|
|
384
|
+
`Plugin initialized: ${this.plugin.metadata.name}@${this.plugin.metadata.version}`
|
|
385
|
+
);
|
|
386
|
+
this.initialized = true;
|
|
387
|
+
} catch (error) {
|
|
388
|
+
this.logger.error("Failed to initialize plugin manager", error);
|
|
389
|
+
throw error;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Get the loaded plugin
|
|
394
|
+
*/
|
|
395
|
+
getPlugin() {
|
|
396
|
+
if (!this.plugin) {
|
|
397
|
+
throw new StallConnectorError(
|
|
398
|
+
"Plugin not initialized",
|
|
399
|
+
ErrorCodes.INVALID_CONFIGURATION
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
return this.plugin;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Check if plugin is initialized
|
|
406
|
+
*/
|
|
407
|
+
isInitialized() {
|
|
408
|
+
return this.initialized && this.plugin !== null;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Verify the plugin configuration
|
|
412
|
+
*/
|
|
413
|
+
async verify() {
|
|
414
|
+
if (!this.isInitialized()) {
|
|
415
|
+
throw new StallConnectorError(
|
|
416
|
+
"Plugin not initialized",
|
|
417
|
+
ErrorCodes.INVALID_CONFIGURATION
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
const result = await this.plugin.verify();
|
|
421
|
+
return result.success && result.data === true;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Get metadata about the loaded plugin
|
|
425
|
+
*/
|
|
426
|
+
getMetadata() {
|
|
427
|
+
if (!this.plugin) {
|
|
428
|
+
throw new StallConnectorError(
|
|
429
|
+
"Plugin not initialized",
|
|
430
|
+
ErrorCodes.INVALID_CONFIGURATION
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
id: this.plugin.metadata.id,
|
|
435
|
+
name: this.plugin.metadata.name,
|
|
436
|
+
version: this.plugin.metadata.version,
|
|
437
|
+
description: this.plugin.metadata.description,
|
|
438
|
+
supportedModules: this.plugin.getSupportedModules()
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Check if a module is supported
|
|
443
|
+
*/
|
|
444
|
+
isModuleSupported(module2) {
|
|
445
|
+
if (!this.plugin) return false;
|
|
446
|
+
return this.plugin.getSupportedModules().includes(module2);
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Clear plugin cache (if using remote loading)
|
|
450
|
+
*/
|
|
451
|
+
clearCache() {
|
|
452
|
+
if (this.connectorLoader) {
|
|
453
|
+
this.connectorLoader.clearCache();
|
|
454
|
+
this.logger.info("Plugin cache cleared");
|
|
455
|
+
}
|
|
456
|
+
}
|
|
31
457
|
};
|
|
32
|
-
|
|
33
|
-
|
|
458
|
+
|
|
459
|
+
// src/services/base.service.ts
|
|
460
|
+
var BaseService = class {
|
|
461
|
+
logger;
|
|
462
|
+
pluginManager;
|
|
463
|
+
connectorId;
|
|
464
|
+
constructor(pluginManager, connectorId, serviceName) {
|
|
465
|
+
this.pluginManager = pluginManager;
|
|
466
|
+
this.connectorId = connectorId;
|
|
467
|
+
this.logger = new Logger(serviceName);
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Wrap a connector operation with error handling and logging
|
|
471
|
+
*/
|
|
472
|
+
async executeOperation(operation, fn) {
|
|
473
|
+
const requestId = generateRequestId();
|
|
474
|
+
const startTime = Date.now();
|
|
475
|
+
try {
|
|
476
|
+
this.logger.debug(`[${requestId}] Starting operation: ${operation}`);
|
|
477
|
+
const result = await fn();
|
|
478
|
+
const duration = Date.now() - startTime;
|
|
479
|
+
this.logger.info(
|
|
480
|
+
`[${requestId}] Operation completed: ${operation} (${duration}ms)`,
|
|
481
|
+
{ success: result.success }
|
|
482
|
+
);
|
|
483
|
+
return {
|
|
484
|
+
...result,
|
|
485
|
+
metadata: {
|
|
486
|
+
...result.metadata,
|
|
487
|
+
connector_id: this.connectorId,
|
|
488
|
+
operation,
|
|
489
|
+
timestamp: Date.now(),
|
|
490
|
+
request_id: requestId
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
} catch (error) {
|
|
494
|
+
const duration = Date.now() - startTime;
|
|
495
|
+
this.logger.error(
|
|
496
|
+
`[${requestId}] Operation failed: ${operation} (${duration}ms)`,
|
|
497
|
+
error
|
|
498
|
+
);
|
|
499
|
+
return createErrorResponse(
|
|
500
|
+
error,
|
|
501
|
+
operation,
|
|
502
|
+
this.connectorId
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Check if a module is supported
|
|
508
|
+
*/
|
|
509
|
+
isModuleSupported(module2) {
|
|
510
|
+
return this.pluginManager.isModuleSupported(module2);
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Get the plugin instance
|
|
514
|
+
*/
|
|
515
|
+
getPlugin() {
|
|
516
|
+
return this.pluginManager.getPlugin();
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Verify plugin is ready
|
|
520
|
+
*/
|
|
521
|
+
ensurePluginInitialized() {
|
|
522
|
+
if (!this.pluginManager.isInitialized()) {
|
|
523
|
+
throw new StallConnectorError(
|
|
524
|
+
"Plugin not initialized",
|
|
525
|
+
ErrorCodes.INVALID_CONFIGURATION
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
// src/services/orders.service.ts
|
|
532
|
+
var OrdersService = class extends BaseService {
|
|
533
|
+
constructor(pluginManager, connectorId) {
|
|
534
|
+
super(pluginManager, connectorId, "OrdersService");
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Create a new order
|
|
538
|
+
*/
|
|
539
|
+
async createOrder(order) {
|
|
540
|
+
return this.executeOperation("orders.create", async () => {
|
|
541
|
+
this.ensurePluginInitialized();
|
|
542
|
+
if (!this.isModuleSupported("orders")) {
|
|
543
|
+
return {
|
|
544
|
+
success: false,
|
|
545
|
+
error: {
|
|
546
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
547
|
+
message: "Orders module is not supported by this connector"
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
const plugin = this.getPlugin();
|
|
552
|
+
return plugin.orders.create(order);
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Get an order by ID
|
|
557
|
+
*/
|
|
558
|
+
async getOrder(orderId) {
|
|
559
|
+
return this.executeOperation("orders.get", async () => {
|
|
560
|
+
this.ensurePluginInitialized();
|
|
561
|
+
if (!this.isModuleSupported("orders")) {
|
|
562
|
+
return {
|
|
563
|
+
success: false,
|
|
564
|
+
error: {
|
|
565
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
566
|
+
message: "Orders module is not supported by this connector"
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
const plugin = this.getPlugin();
|
|
571
|
+
return plugin.orders.get(orderId);
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Update an existing order
|
|
576
|
+
*/
|
|
577
|
+
async updateOrder(orderId, order) {
|
|
578
|
+
return this.executeOperation("orders.update", async () => {
|
|
579
|
+
this.ensurePluginInitialized();
|
|
580
|
+
if (!this.isModuleSupported("orders")) {
|
|
581
|
+
return {
|
|
582
|
+
success: false,
|
|
583
|
+
error: {
|
|
584
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
585
|
+
message: "Orders module is not supported by this connector"
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
const plugin = this.getPlugin();
|
|
590
|
+
return plugin.orders.update(orderId, order);
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Delete/cancel an order
|
|
595
|
+
*/
|
|
596
|
+
async deleteOrder(orderId) {
|
|
597
|
+
return this.executeOperation("orders.delete", async () => {
|
|
598
|
+
this.ensurePluginInitialized();
|
|
599
|
+
if (!this.isModuleSupported("orders")) {
|
|
600
|
+
return {
|
|
601
|
+
success: false,
|
|
602
|
+
error: {
|
|
603
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
604
|
+
message: "Orders module is not supported by this connector"
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
const plugin = this.getPlugin();
|
|
609
|
+
return plugin.orders.delete(orderId);
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* List orders with optional filtering
|
|
614
|
+
*/
|
|
615
|
+
async listOrders(options) {
|
|
616
|
+
return this.executeOperation("orders.list", async () => {
|
|
617
|
+
this.ensurePluginInitialized();
|
|
618
|
+
if (!this.isModuleSupported("orders")) {
|
|
619
|
+
return {
|
|
620
|
+
success: false,
|
|
621
|
+
error: {
|
|
622
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
623
|
+
message: "Orders module is not supported by this connector"
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
const plugin = this.getPlugin();
|
|
628
|
+
return plugin.orders.list(options);
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Create a refund for an order
|
|
633
|
+
*/
|
|
634
|
+
async createRefund(orderId, refund) {
|
|
635
|
+
return this.executeOperation("refunds.create", async () => {
|
|
636
|
+
this.ensurePluginInitialized();
|
|
637
|
+
if (!this.isModuleSupported("orders")) {
|
|
638
|
+
return {
|
|
639
|
+
success: false,
|
|
640
|
+
error: {
|
|
641
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
642
|
+
message: "Orders module is not supported by this connector"
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
const plugin = this.getPlugin();
|
|
647
|
+
return plugin.refunds.create(orderId, refund);
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Get a refund by ID
|
|
652
|
+
*/
|
|
653
|
+
async getRefund(refundId) {
|
|
654
|
+
return this.executeOperation("refunds.get", async () => {
|
|
655
|
+
this.ensurePluginInitialized();
|
|
656
|
+
if (!this.isModuleSupported("orders")) {
|
|
657
|
+
return {
|
|
658
|
+
success: false,
|
|
659
|
+
error: {
|
|
660
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
661
|
+
message: "Orders module is not supported by this connector"
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
const plugin = this.getPlugin();
|
|
666
|
+
return plugin.refunds.get(refundId);
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* List refunds for an order
|
|
671
|
+
*/
|
|
672
|
+
async listRefunds(orderId, options) {
|
|
673
|
+
return this.executeOperation("refunds.list", async () => {
|
|
674
|
+
this.ensurePluginInitialized();
|
|
675
|
+
if (!this.isModuleSupported("orders")) {
|
|
676
|
+
return {
|
|
677
|
+
success: false,
|
|
678
|
+
error: {
|
|
679
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
680
|
+
message: "Orders module is not supported by this connector"
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
const plugin = this.getPlugin();
|
|
685
|
+
return plugin.refunds.list(orderId, options);
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
// src/services/products.service.ts
|
|
691
|
+
var ProductsService = class extends BaseService {
|
|
692
|
+
constructor(pluginManager, connectorId) {
|
|
693
|
+
super(pluginManager, connectorId, "ProductsService");
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Create a new product
|
|
697
|
+
*/
|
|
698
|
+
async createProduct(product) {
|
|
699
|
+
return this.executeOperation("products.create", async () => {
|
|
700
|
+
this.ensurePluginInitialized();
|
|
701
|
+
if (!this.isModuleSupported("products")) {
|
|
702
|
+
return {
|
|
703
|
+
success: false,
|
|
704
|
+
error: {
|
|
705
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
706
|
+
message: "Products module is not supported by this connector"
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
const plugin = this.getPlugin();
|
|
711
|
+
return plugin.products.create(product);
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Get a product by ID
|
|
716
|
+
*/
|
|
717
|
+
async getProduct(productId) {
|
|
718
|
+
return this.executeOperation("products.get", async () => {
|
|
719
|
+
this.ensurePluginInitialized();
|
|
720
|
+
if (!this.isModuleSupported("products")) {
|
|
721
|
+
return {
|
|
722
|
+
success: false,
|
|
723
|
+
error: {
|
|
724
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
725
|
+
message: "Products module is not supported by this connector"
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
const plugin = this.getPlugin();
|
|
730
|
+
return plugin.products.get(productId);
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Update an existing product
|
|
735
|
+
*/
|
|
736
|
+
async updateProduct(productId, product) {
|
|
737
|
+
return this.executeOperation("products.update", async () => {
|
|
738
|
+
this.ensurePluginInitialized();
|
|
739
|
+
if (!this.isModuleSupported("products")) {
|
|
740
|
+
return {
|
|
741
|
+
success: false,
|
|
742
|
+
error: {
|
|
743
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
744
|
+
message: "Products module is not supported by this connector"
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
const plugin = this.getPlugin();
|
|
749
|
+
return plugin.products.update(productId, product);
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Delete a product
|
|
754
|
+
*/
|
|
755
|
+
async deleteProduct(productId) {
|
|
756
|
+
return this.executeOperation("products.delete", async () => {
|
|
757
|
+
this.ensurePluginInitialized();
|
|
758
|
+
if (!this.isModuleSupported("products")) {
|
|
759
|
+
return {
|
|
760
|
+
success: false,
|
|
761
|
+
error: {
|
|
762
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
763
|
+
message: "Products module is not supported by this connector"
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
const plugin = this.getPlugin();
|
|
768
|
+
return plugin.products.delete(productId);
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* List products with optional filtering
|
|
773
|
+
*/
|
|
774
|
+
async listProducts(options) {
|
|
775
|
+
return this.executeOperation("products.list", async () => {
|
|
776
|
+
this.ensurePluginInitialized();
|
|
777
|
+
if (!this.isModuleSupported("products")) {
|
|
778
|
+
return {
|
|
779
|
+
success: false,
|
|
780
|
+
error: {
|
|
781
|
+
code: "MODULE_NOT_SUPPORTED",
|
|
782
|
+
message: "Products module is not supported by this connector"
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
const plugin = this.getPlugin();
|
|
787
|
+
return plugin.products.list(options);
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
};
|
|
791
|
+
|
|
792
|
+
// src/core/sdk.ts
|
|
793
|
+
var StallCore = class _StallCore {
|
|
794
|
+
pluginManager;
|
|
795
|
+
logger;
|
|
796
|
+
options;
|
|
797
|
+
// Service instances
|
|
798
|
+
orders;
|
|
799
|
+
products;
|
|
800
|
+
constructor(options) {
|
|
801
|
+
this.options = options;
|
|
802
|
+
const logLevel = options.options?.logLevel || "info";
|
|
803
|
+
this.logger = new Logger("StallSDK", logLevel);
|
|
804
|
+
this.pluginManager = new PluginManager(logLevel);
|
|
805
|
+
this.orders = new OrdersService(this.pluginManager, options.id);
|
|
806
|
+
this.products = new ProductsService(this.pluginManager, options.id);
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Firebase-style initialization with automatic plugin loading
|
|
810
|
+
* Loads connector from public URL: {connectorUrl}/{integration_id}/index.js
|
|
811
|
+
* Default URL: https://connectors.myapp.xyz
|
|
812
|
+
*/
|
|
813
|
+
static async initialize(options) {
|
|
814
|
+
const sdk = new _StallCore(options);
|
|
815
|
+
try {
|
|
816
|
+
await sdk.pluginManager.initialize(null, options);
|
|
817
|
+
sdk.logger.info("StallSDK initialized successfully");
|
|
818
|
+
} catch (error) {
|
|
819
|
+
sdk.logger.error("Failed to initialize StallSDK", error);
|
|
820
|
+
throw error;
|
|
821
|
+
}
|
|
822
|
+
return sdk;
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Initialize with a provided plugin instance (for testing/custom plugins)
|
|
826
|
+
* Useful for mock plugins or custom implementations
|
|
827
|
+
*/
|
|
828
|
+
static async initializeWithPlugin(options, plugin) {
|
|
829
|
+
const sdk = new _StallCore(options);
|
|
830
|
+
try {
|
|
831
|
+
await sdk.pluginManager.initialize(plugin, options);
|
|
832
|
+
sdk.logger.info("StallSDK initialized with custom plugin");
|
|
833
|
+
} catch (error) {
|
|
834
|
+
sdk.logger.error("Failed to initialize StallSDK", error);
|
|
835
|
+
throw error;
|
|
836
|
+
}
|
|
837
|
+
return sdk;
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Get plugin metadata
|
|
841
|
+
*/
|
|
842
|
+
getMetadata() {
|
|
843
|
+
return this.pluginManager.getMetadata();
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Verify the connector configuration
|
|
847
|
+
*/
|
|
848
|
+
async verify() {
|
|
849
|
+
return this.pluginManager.verify();
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Check if a module is supported
|
|
853
|
+
*/
|
|
854
|
+
isModuleSupported(module2) {
|
|
855
|
+
return this.pluginManager.isModuleSupported(module2);
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Check if SDK is initialized
|
|
859
|
+
*/
|
|
860
|
+
isInitialized() {
|
|
861
|
+
return this.pluginManager.isInitialized();
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Clear plugin cache
|
|
865
|
+
*/
|
|
866
|
+
clearCache() {
|
|
867
|
+
this.pluginManager.clearCache();
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Get the underlying plugin instance
|
|
871
|
+
*/
|
|
872
|
+
getPlugin() {
|
|
873
|
+
return this.pluginManager.getPlugin();
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Get SDK configuration
|
|
877
|
+
*/
|
|
878
|
+
getConfiguration() {
|
|
879
|
+
return {
|
|
880
|
+
id: this.options.id,
|
|
881
|
+
integration_id: this.options.integration_id,
|
|
882
|
+
created_at: this.options.created_at,
|
|
883
|
+
updated_at: this.options.updated_at
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
// src/plugins/mock-connector.plugin.ts
|
|
889
|
+
var MockConnectorPlugin = class {
|
|
890
|
+
metadata = {
|
|
891
|
+
id: "mock",
|
|
892
|
+
name: "Mock Connector",
|
|
893
|
+
version: "1.0.0",
|
|
894
|
+
description: "Mock connector for development and testing purposes"
|
|
895
|
+
};
|
|
896
|
+
config = null;
|
|
897
|
+
initialized = false;
|
|
898
|
+
async initialize(config) {
|
|
899
|
+
this.config = config;
|
|
900
|
+
this.initialized = true;
|
|
901
|
+
console.log(`Mock connector initialized for: ${config.integrationId}`);
|
|
902
|
+
}
|
|
903
|
+
async verify() {
|
|
904
|
+
if (!this.initialized) {
|
|
905
|
+
return {
|
|
906
|
+
success: false,
|
|
907
|
+
error: {
|
|
908
|
+
code: "NOT_INITIALIZED",
|
|
909
|
+
message: "Plugin not initialized"
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
return {
|
|
914
|
+
success: true,
|
|
915
|
+
data: true,
|
|
916
|
+
metadata: {
|
|
917
|
+
connector_id: this.config?.connectorId || "mock",
|
|
918
|
+
operation: "verify",
|
|
919
|
+
timestamp: Date.now(),
|
|
920
|
+
request_id: `req_${Date.now()}`
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
getSupportedModules() {
|
|
925
|
+
return ["orders", "products", "customers", "inventory", "refunds", "payments"];
|
|
926
|
+
}
|
|
927
|
+
orders = {
|
|
928
|
+
create: async (order) => ({
|
|
929
|
+
success: true,
|
|
930
|
+
data: {
|
|
931
|
+
...order,
|
|
932
|
+
id: `mock_order_${Date.now()}`,
|
|
933
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
934
|
+
},
|
|
935
|
+
metadata: {
|
|
936
|
+
connector_id: this.config?.connectorId || "mock",
|
|
937
|
+
operation: "orders.create",
|
|
938
|
+
timestamp: Date.now(),
|
|
939
|
+
request_id: `req_${Date.now()}`
|
|
940
|
+
}
|
|
941
|
+
}),
|
|
942
|
+
get: async (orderId) => ({
|
|
943
|
+
success: true,
|
|
944
|
+
data: {
|
|
945
|
+
id: orderId,
|
|
946
|
+
order_number: `ORD-${orderId}`,
|
|
947
|
+
status: "completed",
|
|
948
|
+
total: 100
|
|
949
|
+
},
|
|
950
|
+
metadata: {
|
|
951
|
+
connector_id: this.config?.connectorId || "mock",
|
|
952
|
+
operation: "orders.get",
|
|
953
|
+
timestamp: Date.now(),
|
|
954
|
+
request_id: `req_${Date.now()}`
|
|
955
|
+
}
|
|
956
|
+
}),
|
|
957
|
+
update: async (orderId, order) => ({
|
|
958
|
+
success: true,
|
|
959
|
+
data: {
|
|
960
|
+
id: orderId,
|
|
961
|
+
...order,
|
|
962
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
963
|
+
},
|
|
964
|
+
metadata: {
|
|
965
|
+
connector_id: this.config?.connectorId || "mock",
|
|
966
|
+
operation: "orders.update",
|
|
967
|
+
timestamp: Date.now(),
|
|
968
|
+
request_id: `req_${Date.now()}`
|
|
969
|
+
}
|
|
970
|
+
}),
|
|
971
|
+
delete: async (orderId) => ({
|
|
972
|
+
success: true,
|
|
973
|
+
data: null,
|
|
974
|
+
metadata: {
|
|
975
|
+
connector_id: this.config?.connectorId || "mock",
|
|
976
|
+
operation: "orders.delete",
|
|
977
|
+
timestamp: Date.now(),
|
|
978
|
+
request_id: `req_${Date.now()}`
|
|
979
|
+
}
|
|
980
|
+
}),
|
|
981
|
+
list: async (options) => {
|
|
982
|
+
const limit = options?.limit || 10;
|
|
983
|
+
const orders = Array.from({ length: limit }, (_, i) => ({
|
|
984
|
+
id: `mock_order_${i}`,
|
|
985
|
+
order_number: `ORD-${i}`,
|
|
986
|
+
status: "completed",
|
|
987
|
+
total: (i + 1) * 100
|
|
988
|
+
}));
|
|
989
|
+
return {
|
|
990
|
+
success: true,
|
|
991
|
+
data: orders,
|
|
992
|
+
metadata: {
|
|
993
|
+
connector_id: this.config?.connectorId || "mock",
|
|
994
|
+
operation: "orders.list",
|
|
995
|
+
timestamp: Date.now(),
|
|
996
|
+
request_id: `req_${Date.now()}`
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
products = {
|
|
1002
|
+
create: async (product) => ({
|
|
1003
|
+
success: true,
|
|
1004
|
+
data: {
|
|
1005
|
+
...product,
|
|
1006
|
+
id: `mock_product_${Date.now()}`,
|
|
1007
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1008
|
+
},
|
|
1009
|
+
metadata: {
|
|
1010
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1011
|
+
operation: "products.create",
|
|
1012
|
+
timestamp: Date.now(),
|
|
1013
|
+
request_id: `req_${Date.now()}`
|
|
1014
|
+
}
|
|
1015
|
+
}),
|
|
1016
|
+
get: async (productId) => ({
|
|
1017
|
+
success: true,
|
|
1018
|
+
data: {
|
|
1019
|
+
id: productId,
|
|
1020
|
+
title: "Mock Product",
|
|
1021
|
+
price: 99.99,
|
|
1022
|
+
sku: `MOCK-${productId}`
|
|
1023
|
+
},
|
|
1024
|
+
metadata: {
|
|
1025
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1026
|
+
operation: "products.get",
|
|
1027
|
+
timestamp: Date.now(),
|
|
1028
|
+
request_id: `req_${Date.now()}`
|
|
1029
|
+
}
|
|
1030
|
+
}),
|
|
1031
|
+
update: async (productId, product) => ({
|
|
1032
|
+
success: true,
|
|
1033
|
+
data: {
|
|
1034
|
+
id: productId,
|
|
1035
|
+
...product,
|
|
1036
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1037
|
+
},
|
|
1038
|
+
metadata: {
|
|
1039
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1040
|
+
operation: "products.update",
|
|
1041
|
+
timestamp: Date.now(),
|
|
1042
|
+
request_id: `req_${Date.now()}`
|
|
1043
|
+
}
|
|
1044
|
+
}),
|
|
1045
|
+
delete: async (productId) => ({
|
|
1046
|
+
success: true,
|
|
1047
|
+
data: null,
|
|
1048
|
+
metadata: {
|
|
1049
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1050
|
+
operation: "products.delete",
|
|
1051
|
+
timestamp: Date.now(),
|
|
1052
|
+
request_id: `req_${Date.now()}`
|
|
1053
|
+
}
|
|
1054
|
+
}),
|
|
1055
|
+
list: async (options) => {
|
|
1056
|
+
const limit = options?.limit || 10;
|
|
1057
|
+
const products = Array.from({ length: limit }, (_, i) => ({
|
|
1058
|
+
id: `mock_product_${i}`,
|
|
1059
|
+
title: `Mock Product ${i}`,
|
|
1060
|
+
price: (i + 1) * 10,
|
|
1061
|
+
sku: `MOCK-${i}`
|
|
1062
|
+
}));
|
|
1063
|
+
return {
|
|
1064
|
+
success: true,
|
|
1065
|
+
data: products,
|
|
1066
|
+
metadata: {
|
|
1067
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1068
|
+
operation: "products.list",
|
|
1069
|
+
timestamp: Date.now(),
|
|
1070
|
+
request_id: `req_${Date.now()}`
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
customers = {
|
|
1076
|
+
create: async (customer) => ({
|
|
1077
|
+
success: true,
|
|
1078
|
+
data: {
|
|
1079
|
+
...customer,
|
|
1080
|
+
id: `mock_customer_${Date.now()}`,
|
|
1081
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1082
|
+
},
|
|
1083
|
+
metadata: {
|
|
1084
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1085
|
+
operation: "customers.create",
|
|
1086
|
+
timestamp: Date.now(),
|
|
1087
|
+
request_id: `req_${Date.now()}`
|
|
1088
|
+
}
|
|
1089
|
+
}),
|
|
1090
|
+
get: async (customerId) => ({
|
|
1091
|
+
success: true,
|
|
1092
|
+
data: {
|
|
1093
|
+
id: customerId,
|
|
1094
|
+
email: "customer@example.com",
|
|
1095
|
+
name: "Mock Customer"
|
|
1096
|
+
},
|
|
1097
|
+
metadata: {
|
|
1098
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1099
|
+
operation: "customers.get",
|
|
1100
|
+
timestamp: Date.now(),
|
|
1101
|
+
request_id: `req_${Date.now()}`
|
|
1102
|
+
}
|
|
1103
|
+
}),
|
|
1104
|
+
update: async (customerId, customer) => ({
|
|
1105
|
+
success: true,
|
|
1106
|
+
data: {
|
|
1107
|
+
id: customerId,
|
|
1108
|
+
...customer,
|
|
1109
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1110
|
+
},
|
|
1111
|
+
metadata: {
|
|
1112
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1113
|
+
operation: "customers.update",
|
|
1114
|
+
timestamp: Date.now(),
|
|
1115
|
+
request_id: `req_${Date.now()}`
|
|
1116
|
+
}
|
|
1117
|
+
}),
|
|
1118
|
+
delete: async (customerId) => ({
|
|
1119
|
+
success: true,
|
|
1120
|
+
data: null,
|
|
1121
|
+
metadata: {
|
|
1122
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1123
|
+
operation: "customers.delete",
|
|
1124
|
+
timestamp: Date.now(),
|
|
1125
|
+
request_id: `req_${Date.now()}`
|
|
1126
|
+
}
|
|
1127
|
+
}),
|
|
1128
|
+
list: async (options) => {
|
|
1129
|
+
const limit = options?.limit || 10;
|
|
1130
|
+
const customers = Array.from({ length: limit }, (_, i) => ({
|
|
1131
|
+
id: `mock_customer_${i}`,
|
|
1132
|
+
email: `customer${i}@example.com`,
|
|
1133
|
+
name: `Customer ${i}`
|
|
1134
|
+
}));
|
|
1135
|
+
return {
|
|
1136
|
+
success: true,
|
|
1137
|
+
data: customers,
|
|
1138
|
+
metadata: {
|
|
1139
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1140
|
+
operation: "customers.list",
|
|
1141
|
+
timestamp: Date.now(),
|
|
1142
|
+
request_id: `req_${Date.now()}`
|
|
1143
|
+
}
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
};
|
|
1147
|
+
inventory = {
|
|
1148
|
+
get: async (productId, variantId) => ({
|
|
1149
|
+
success: true,
|
|
1150
|
+
data: {
|
|
1151
|
+
product_id: productId,
|
|
1152
|
+
variant_id: variantId,
|
|
1153
|
+
in_stock: 100,
|
|
1154
|
+
committed: 0,
|
|
1155
|
+
on_hand: 100
|
|
1156
|
+
},
|
|
1157
|
+
metadata: {
|
|
1158
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1159
|
+
operation: "inventory.get",
|
|
1160
|
+
timestamp: Date.now(),
|
|
1161
|
+
request_id: `req_${Date.now()}`
|
|
1162
|
+
}
|
|
1163
|
+
}),
|
|
1164
|
+
update: async (productId, inventory, variantId) => ({
|
|
1165
|
+
success: true,
|
|
1166
|
+
data: {
|
|
1167
|
+
product_id: productId,
|
|
1168
|
+
variant_id: variantId,
|
|
1169
|
+
...inventory,
|
|
1170
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1171
|
+
},
|
|
1172
|
+
metadata: {
|
|
1173
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1174
|
+
operation: "inventory.update",
|
|
1175
|
+
timestamp: Date.now(),
|
|
1176
|
+
request_id: `req_${Date.now()}`
|
|
1177
|
+
}
|
|
1178
|
+
}),
|
|
1179
|
+
list: async (options) => {
|
|
1180
|
+
const limit = options?.limit || 10;
|
|
1181
|
+
const inventoryItems = Array.from({ length: limit }, (_, i) => ({
|
|
1182
|
+
product_id: `mock_product_${i}`,
|
|
1183
|
+
in_stock: (i + 1) * 10,
|
|
1184
|
+
committed: 0,
|
|
1185
|
+
on_hand: (i + 1) * 10
|
|
1186
|
+
}));
|
|
1187
|
+
return {
|
|
1188
|
+
success: true,
|
|
1189
|
+
data: inventoryItems,
|
|
1190
|
+
metadata: {
|
|
1191
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1192
|
+
operation: "inventory.list",
|
|
1193
|
+
timestamp: Date.now(),
|
|
1194
|
+
request_id: `req_${Date.now()}`
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
};
|
|
1199
|
+
refunds = {
|
|
1200
|
+
create: async (orderId, refund) => ({
|
|
1201
|
+
success: true,
|
|
1202
|
+
data: {
|
|
1203
|
+
...refund,
|
|
1204
|
+
id: `mock_refund_${Date.now()}`,
|
|
1205
|
+
order_id: orderId,
|
|
1206
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1207
|
+
},
|
|
1208
|
+
metadata: {
|
|
1209
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1210
|
+
operation: "refunds.create",
|
|
1211
|
+
timestamp: Date.now(),
|
|
1212
|
+
request_id: `req_${Date.now()}`
|
|
1213
|
+
}
|
|
1214
|
+
}),
|
|
1215
|
+
get: async (refundId) => ({
|
|
1216
|
+
success: true,
|
|
1217
|
+
data: {
|
|
1218
|
+
id: refundId,
|
|
1219
|
+
amount: 100,
|
|
1220
|
+
reason: "Customer request",
|
|
1221
|
+
status: "completed"
|
|
1222
|
+
},
|
|
1223
|
+
metadata: {
|
|
1224
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1225
|
+
operation: "refunds.get",
|
|
1226
|
+
timestamp: Date.now(),
|
|
1227
|
+
request_id: `req_${Date.now()}`
|
|
1228
|
+
}
|
|
1229
|
+
}),
|
|
1230
|
+
list: async (orderId, options) => {
|
|
1231
|
+
const limit = options?.limit || 10;
|
|
1232
|
+
const refunds = Array.from({ length: limit }, (_, i) => ({
|
|
1233
|
+
id: `mock_refund_${i}`,
|
|
1234
|
+
order_id: orderId,
|
|
1235
|
+
amount: (i + 1) * 10,
|
|
1236
|
+
reason: "Customer request",
|
|
1237
|
+
status: "completed"
|
|
1238
|
+
}));
|
|
1239
|
+
return {
|
|
1240
|
+
success: true,
|
|
1241
|
+
data: refunds,
|
|
1242
|
+
metadata: {
|
|
1243
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1244
|
+
operation: "refunds.list",
|
|
1245
|
+
timestamp: Date.now(),
|
|
1246
|
+
request_id: `req_${Date.now()}`
|
|
1247
|
+
}
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
payments = {
|
|
1252
|
+
create: async (payment) => ({
|
|
1253
|
+
success: true,
|
|
1254
|
+
data: {
|
|
1255
|
+
...payment,
|
|
1256
|
+
id: `mock_payment_${Date.now()}`,
|
|
1257
|
+
status: "successful",
|
|
1258
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1259
|
+
},
|
|
1260
|
+
metadata: {
|
|
1261
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1262
|
+
operation: "payments.create",
|
|
1263
|
+
timestamp: Date.now(),
|
|
1264
|
+
request_id: `req_${Date.now()}`
|
|
1265
|
+
}
|
|
1266
|
+
}),
|
|
1267
|
+
get: async (paymentId) => ({
|
|
1268
|
+
success: true,
|
|
1269
|
+
data: {
|
|
1270
|
+
id: paymentId,
|
|
1271
|
+
amount: 100,
|
|
1272
|
+
status: "successful",
|
|
1273
|
+
method: "card"
|
|
1274
|
+
},
|
|
1275
|
+
metadata: {
|
|
1276
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1277
|
+
operation: "payments.get",
|
|
1278
|
+
timestamp: Date.now(),
|
|
1279
|
+
request_id: `req_${Date.now()}`
|
|
1280
|
+
}
|
|
1281
|
+
}),
|
|
1282
|
+
list: async (options) => {
|
|
1283
|
+
const limit = options?.limit || 10;
|
|
1284
|
+
const payments = Array.from({ length: limit }, (_, i) => ({
|
|
1285
|
+
id: `mock_payment_${i}`,
|
|
1286
|
+
amount: (i + 1) * 100,
|
|
1287
|
+
status: "successful",
|
|
1288
|
+
method: "card"
|
|
1289
|
+
}));
|
|
1290
|
+
return {
|
|
1291
|
+
success: true,
|
|
1292
|
+
data: payments,
|
|
1293
|
+
metadata: {
|
|
1294
|
+
connector_id: this.config?.connectorId || "mock",
|
|
1295
|
+
operation: "payments.list",
|
|
1296
|
+
timestamp: Date.now(),
|
|
1297
|
+
request_id: `req_${Date.now()}`
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
};
|
|
34
1302
|
};
|
|
35
1303
|
// Annotate the CommonJS export names for ESM import in node:
|
|
36
1304
|
0 && (module.exports = {
|
|
37
|
-
|
|
38
|
-
|
|
1305
|
+
BaseService,
|
|
1306
|
+
ConnectorLoader,
|
|
1307
|
+
ErrorCodes,
|
|
1308
|
+
Logger,
|
|
1309
|
+
MockConnectorPlugin,
|
|
1310
|
+
OrdersService,
|
|
1311
|
+
PluginManager,
|
|
1312
|
+
ProductsService,
|
|
1313
|
+
StallConnectorError,
|
|
1314
|
+
StallCore,
|
|
1315
|
+
createErrorResponse,
|
|
1316
|
+
createLogger,
|
|
1317
|
+
generateRequestId,
|
|
1318
|
+
handleConnectorError
|
|
39
1319
|
});
|