@neo-edi/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,480 @@
1
+ // src/errors.ts
2
+ var NeoEdiError = class extends Error {
3
+ constructor(message, code, statusCode, details) {
4
+ super(message);
5
+ this.code = code;
6
+ this.statusCode = statusCode;
7
+ this.details = details;
8
+ this.name = "NeoEdiError";
9
+ }
10
+ };
11
+ var NeoEdiApiError = class extends NeoEdiError {
12
+ constructor(message, statusCode, code, details) {
13
+ super(message, code, statusCode, details);
14
+ this.statusCode = statusCode;
15
+ this.name = "NeoEdiApiError";
16
+ }
17
+ };
18
+ var NeoEdiNetworkError = class extends NeoEdiError {
19
+ constructor(message, cause) {
20
+ super(message, "NETWORK_ERROR");
21
+ this.cause = cause;
22
+ this.name = "NeoEdiNetworkError";
23
+ }
24
+ };
25
+ var NeoEdiValidationError = class extends NeoEdiError {
26
+ constructor(message, details) {
27
+ super(message, "VALIDATION_ERROR", 400, details);
28
+ this.name = "NeoEdiValidationError";
29
+ }
30
+ };
31
+
32
+ // src/http.ts
33
+ var HttpClient = class {
34
+ constructor(config) {
35
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
36
+ this.apiKey = config.apiKey;
37
+ this.timeout = config.timeout ?? 3e4;
38
+ this.defaultHeaders = {
39
+ "Content-Type": "application/json",
40
+ "X-SDK-Version": "0.1.0",
41
+ ...config.headers
42
+ };
43
+ }
44
+ async request(options) {
45
+ const url = this.buildUrl(options.path, options.query);
46
+ const headers = {
47
+ ...this.defaultHeaders,
48
+ "X-API-Key": this.apiKey,
49
+ ...options.headers
50
+ };
51
+ const controller = new AbortController();
52
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
53
+ try {
54
+ let body;
55
+ let finalHeaders = headers;
56
+ if (options.body instanceof FormData) {
57
+ body = options.body;
58
+ const { "Content-Type": _, ...restHeaders } = finalHeaders;
59
+ finalHeaders = restHeaders;
60
+ } else if (options.body) {
61
+ body = JSON.stringify(options.body);
62
+ }
63
+ const response = await fetch(url, {
64
+ method: options.method,
65
+ headers: finalHeaders,
66
+ body,
67
+ signal: controller.signal
68
+ });
69
+ clearTimeout(timeoutId);
70
+ const data = await this.parseResponse(response);
71
+ if (!response.ok) {
72
+ throw new NeoEdiApiError(
73
+ data.error || `Request failed with status ${response.status}`,
74
+ response.status,
75
+ data.code,
76
+ data.details
77
+ );
78
+ }
79
+ return data;
80
+ } catch (error) {
81
+ clearTimeout(timeoutId);
82
+ if (error instanceof NeoEdiApiError) {
83
+ throw error;
84
+ }
85
+ if (error instanceof Error) {
86
+ if (error.name === "AbortError") {
87
+ throw new NeoEdiNetworkError("Request timeout", error);
88
+ }
89
+ throw new NeoEdiNetworkError(error.message, error);
90
+ }
91
+ throw new NeoEdiNetworkError("Unknown error occurred");
92
+ }
93
+ }
94
+ buildUrl(path, query) {
95
+ const url = new URL(path, this.baseUrl);
96
+ if (query) {
97
+ Object.entries(query).forEach(([key, value]) => {
98
+ if (value !== void 0) {
99
+ url.searchParams.append(key, String(value));
100
+ }
101
+ });
102
+ }
103
+ return url.toString();
104
+ }
105
+ async parseResponse(response) {
106
+ const contentType = response.headers.get("content-type");
107
+ if (contentType?.includes("application/json")) {
108
+ try {
109
+ return await response.json();
110
+ } catch {
111
+ return { error: "Invalid JSON response" };
112
+ }
113
+ }
114
+ const text = await response.text();
115
+ return { data: text };
116
+ }
117
+ // Convenience methods
118
+ get(path, query) {
119
+ return this.request({ method: "GET", path, query });
120
+ }
121
+ post(path, body) {
122
+ return this.request({ method: "POST", path, body });
123
+ }
124
+ patch(path, body) {
125
+ return this.request({ method: "PATCH", path, body });
126
+ }
127
+ put(path, body) {
128
+ return this.request({ method: "PUT", path, body });
129
+ }
130
+ delete(path) {
131
+ return this.request({ method: "DELETE", path });
132
+ }
133
+ };
134
+
135
+ // src/resources/customers.ts
136
+ var CustomersResource = class {
137
+ constructor(http) {
138
+ this.http = http;
139
+ }
140
+ /**
141
+ * List all customers
142
+ */
143
+ async list(params) {
144
+ const response = await this.http.get(
145
+ "/api/v1/customers",
146
+ params
147
+ );
148
+ if (!response.success) {
149
+ throw new Error(response.error);
150
+ }
151
+ return response.data;
152
+ }
153
+ /**
154
+ * Get a customer by ID
155
+ */
156
+ async get(customerId) {
157
+ const response = await this.http.get(
158
+ `/api/v1/customers/${encodeURIComponent(customerId)}`
159
+ );
160
+ if (!response.success) {
161
+ throw new Error(response.error);
162
+ }
163
+ return response.data;
164
+ }
165
+ /**
166
+ * Create a new customer
167
+ */
168
+ async create(data) {
169
+ const response = await this.http.post(
170
+ "/api/v1/customers",
171
+ data
172
+ );
173
+ if (!response.success) {
174
+ throw new Error(response.error);
175
+ }
176
+ return response.data;
177
+ }
178
+ /**
179
+ * Update a customer
180
+ */
181
+ async update(customerId, data) {
182
+ const response = await this.http.patch(
183
+ `/api/v1/customers/${encodeURIComponent(customerId)}`,
184
+ data
185
+ );
186
+ if (!response.success) {
187
+ throw new Error(response.error);
188
+ }
189
+ return response.data;
190
+ }
191
+ /**
192
+ * Delete a customer
193
+ */
194
+ async delete(customerId) {
195
+ await this.http.delete(
196
+ `/api/v1/customers/${encodeURIComponent(customerId)}`
197
+ );
198
+ }
199
+ };
200
+
201
+ // src/resources/partner-customers.ts
202
+ var PartnerCustomersResource = class {
203
+ constructor(http) {
204
+ this.http = http;
205
+ }
206
+ /**
207
+ * Register customer-partner relationships
208
+ * Creates or activates relationships between a customer and multiple trading partners
209
+ */
210
+ async register(data) {
211
+ const response = await this.http.post(
212
+ "/api/v1/partner-customers",
213
+ data
214
+ );
215
+ if (!response.success) {
216
+ throw new Error(response.error);
217
+ }
218
+ return response.data;
219
+ }
220
+ };
221
+
222
+ // src/resources/mapping-templates.ts
223
+ var MappingTemplatesResource = class {
224
+ constructor(http) {
225
+ this.http = http;
226
+ }
227
+ /**
228
+ * List all mapping templates
229
+ */
230
+ async list(params) {
231
+ const response = await this.http.get(
232
+ "/api/v1/mapping-templates",
233
+ params
234
+ );
235
+ if (!response.success) {
236
+ throw new Error(response.error);
237
+ }
238
+ return response.data;
239
+ }
240
+ /**
241
+ * Get a mapping template by ID
242
+ */
243
+ async get(templateId) {
244
+ const response = await this.http.get(
245
+ `/api/v1/mapping-templates/${encodeURIComponent(templateId)}`
246
+ );
247
+ if (!response.success) {
248
+ throw new Error(response.error);
249
+ }
250
+ return response.data;
251
+ }
252
+ /**
253
+ * Create a new mapping template
254
+ */
255
+ async create(data) {
256
+ const response = await this.http.post(
257
+ "/api/v1/mapping-templates",
258
+ data
259
+ );
260
+ if (!response.success) {
261
+ throw new Error(response.error);
262
+ }
263
+ return response.data;
264
+ }
265
+ /**
266
+ * Update a mapping template
267
+ */
268
+ async update(templateId, data) {
269
+ const response = await this.http.put(
270
+ `/api/v1/mapping-templates/${encodeURIComponent(templateId)}`,
271
+ data
272
+ );
273
+ if (!response.success) {
274
+ throw new Error(response.error);
275
+ }
276
+ return response.data;
277
+ }
278
+ /**
279
+ * Delete a mapping template
280
+ */
281
+ async delete(templateId) {
282
+ await this.http.delete(
283
+ `/api/v1/mapping-templates/${encodeURIComponent(templateId)}`
284
+ );
285
+ }
286
+ };
287
+
288
+ // src/resources/ingest.ts
289
+ var IngestResource = class {
290
+ constructor(http) {
291
+ this.http = http;
292
+ }
293
+ /**
294
+ * Upload a CSV file for ingestion
295
+ *
296
+ * @example Browser
297
+ * ```typescript
298
+ * const input = document.querySelector('input[type="file"]');
299
+ * const file = input.files[0];
300
+ * await client.ingest.uploadCsv(file, options);
301
+ * ```
302
+ *
303
+ * @example Node.js
304
+ * ```typescript
305
+ * import { readFileSync } from 'fs';
306
+ * const buffer = readFileSync('data.csv');
307
+ * const blob = new Blob([buffer], { type: 'text/csv' });
308
+ * await client.ingest.uploadCsv(blob, options);
309
+ * ```
310
+ */
311
+ async uploadCsv(file, options) {
312
+ const formData = new FormData();
313
+ formData.append("file", file, "data.csv");
314
+ formData.append("partnerId", options.partnerId);
315
+ formData.append("mappingConfig", JSON.stringify(options.mappingConfig));
316
+ if (options.transformationConfig) {
317
+ formData.append(
318
+ "transformationConfig",
319
+ JSON.stringify(options.transformationConfig)
320
+ );
321
+ }
322
+ const response = await this.http.request({
323
+ method: "POST",
324
+ path: "/api/v1/ingest-csv",
325
+ body: formData
326
+ });
327
+ if (!response.success) {
328
+ throw new Error(response.error);
329
+ }
330
+ return response.data;
331
+ }
332
+ /**
333
+ * Perform a dry run of CSV ingestion (validation only)
334
+ */
335
+ async dryRun(file, options) {
336
+ const formData = new FormData();
337
+ formData.append("file", file, "data.csv");
338
+ formData.append("partnerId", options.partnerId);
339
+ formData.append("mappingConfig", JSON.stringify(options.mappingConfig));
340
+ if (options.transformationConfig) {
341
+ formData.append(
342
+ "transformationConfig",
343
+ JSON.stringify(options.transformationConfig)
344
+ );
345
+ }
346
+ const response = await this.http.request({
347
+ method: "POST",
348
+ path: "/api/v1/ingest-csv/dry-run",
349
+ body: formData
350
+ });
351
+ if (!response.success) {
352
+ throw new Error(response.error);
353
+ }
354
+ return response.data;
355
+ }
356
+ };
357
+
358
+ // src/resources/graphql.ts
359
+ var GraphQLResource = class {
360
+ constructor(http) {
361
+ this.http = http;
362
+ }
363
+ /**
364
+ * Execute a GraphQL query
365
+ */
366
+ async query(query, variables, options) {
367
+ const response = await this.http.post("/api/v1/graphql", {
368
+ query,
369
+ variables,
370
+ operationName: options?.operationName
371
+ });
372
+ if (response.errors && response.errors.length > 0) {
373
+ const errorMessage = response.errors.map((e) => e.message).join("; ");
374
+ throw new Error(`GraphQL Error: ${errorMessage}`);
375
+ }
376
+ if (!response.data) {
377
+ throw new Error("No data returned from GraphQL query");
378
+ }
379
+ return response.data;
380
+ }
381
+ /**
382
+ * Execute a GraphQL mutation
383
+ */
384
+ async mutate(mutation, variables, options) {
385
+ return this.query(mutation, variables, options);
386
+ }
387
+ };
388
+ var Queries = {
389
+ /**
390
+ * Get EDI 852 headers with filtering
391
+ */
392
+ GET_EDI_852_HEADERS: `
393
+ query GetEdi852Headers($filter: Edi852HeaderFilterInput) {
394
+ edi852Headers(filter: $filter) {
395
+ id
396
+ documentId
397
+ reportTypeCode
398
+ reportDate
399
+ vendorPartnerId
400
+ retailerPartnerId
401
+ status
402
+ totalLocations
403
+ totalItems
404
+ createdAt
405
+ }
406
+ }
407
+ `,
408
+ /**
409
+ * Get a single EDI 852 header by ID with locations
410
+ */
411
+ GET_EDI_852_HEADER_BY_ID: `
412
+ query GetEdi852HeaderById($id: ID!) {
413
+ edi852Header(id: $id) {
414
+ id
415
+ documentId
416
+ reportTypeCode
417
+ reportDate
418
+ vendorPartnerId
419
+ retailerPartnerId
420
+ status
421
+ totalLocations
422
+ totalItems
423
+ metadata
424
+ createdAt
425
+ locations {
426
+ id
427
+ locationNumber
428
+ locationName
429
+ activityDate
430
+ items {
431
+ id
432
+ upc
433
+ productDescription
434
+ quantityOnHand
435
+ quantitySold
436
+ unitCost
437
+ }
438
+ }
439
+ }
440
+ }
441
+ `,
442
+ /**
443
+ * Get trading partner execution summaries
444
+ */
445
+ GET_EXECUTION_SUMMARIES: `
446
+ query GetExecutionSummaries($partnerId: ID!) {
447
+ tradingPartnerExecutionSummaries(partnerId: $partnerId) {
448
+ tradingPartnerId
449
+ customerId
450
+ lastExecutedAt
451
+ documentCount
452
+ }
453
+ }
454
+ `
455
+ };
456
+
457
+ // src/client.ts
458
+ var NeoEdiClient = class {
459
+ constructor(config) {
460
+ this.http = new HttpClient({
461
+ baseUrl: config.baseUrl,
462
+ apiKey: config.apiKey,
463
+ timeout: config.timeout,
464
+ headers: config.headers
465
+ });
466
+ this.customers = new CustomersResource(this.http);
467
+ this.partnerCustomers = new PartnerCustomersResource(this.http);
468
+ this.mappingTemplates = new MappingTemplatesResource(this.http);
469
+ this.ingest = new IngestResource(this.http);
470
+ this.graphql = new GraphQLResource(this.http);
471
+ }
472
+ };
473
+ export {
474
+ NeoEdiApiError,
475
+ NeoEdiClient,
476
+ NeoEdiError,
477
+ NeoEdiNetworkError,
478
+ NeoEdiValidationError,
479
+ Queries
480
+ };
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@neo-edi/sdk",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript SDK for the Neo-EDI platform",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "dependencies": {
19
+ "@neo-edi/types": "0.1.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^20",
23
+ "tsup": "^8.0.0",
24
+ "typescript": "^5.0.0"
25
+ },
26
+ "peerDependencies": {
27
+ "@neo-edi/types": "0.1.0"
28
+ },
29
+ "scripts": {
30
+ "build": "tsup src/index.ts --format cjs,esm --dts",
31
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
32
+ "test": "echo 'No tests yet'"
33
+ }
34
+ }