@campfire-interactive/integrations-client 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.
@@ -0,0 +1,12 @@
1
+ import type { HttpTransport } from './http';
2
+ import type { ActualRow, MeasureWindow } from './types';
3
+ /** Realized actuals, keyed by canonical master-data Part id. */
4
+ export declare class ActualsResource {
5
+ private readonly http;
6
+ constructor(http: HttpTransport);
7
+ /** Actuals for the given part ids, optionally windowed by period (inclusive
8
+ * YYYYMM). partIds are chunked internally (≤100/call) so a large set never
9
+ * hits the API's 500-id / 5000-row caps. Empty in → `[]` (no network call). */
10
+ list(partIds: string[], window?: MeasureWindow): Promise<ActualRow[]>;
11
+ }
12
+ //# sourceMappingURL=actuals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actuals.d.ts","sourceRoot":"","sources":["../src/actuals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAwB,MAAM,SAAS,CAAC;AAoC9E,gEAAgE;AAChE,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,aAAa;IAEhD;;oFAEgF;IAC1E,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;CAc5E"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ActualsResource = void 0;
4
+ const internal_1 = require("./internal");
5
+ function coerce(r) {
6
+ return {
7
+ partId: r.partId,
8
+ plantCode: r.plantCode,
9
+ period: r.period,
10
+ sourceSystem: r.sourceSystem,
11
+ currency: r.currency,
12
+ actualVolume: (0, internal_1.toNum)(r.actualVolume),
13
+ revenue: (0, internal_1.toNum)(r.revenue),
14
+ usdRevenue: (0, internal_1.toNum)(r.usdRevenue),
15
+ unitCost: (0, internal_1.toNum)(r.unitCost),
16
+ oem: r.oem,
17
+ customerName: r.customerName,
18
+ programRef: r.programRef,
19
+ };
20
+ }
21
+ /** Realized actuals, keyed by canonical master-data Part id. */
22
+ class ActualsResource {
23
+ http;
24
+ constructor(http) {
25
+ this.http = http;
26
+ }
27
+ /** Actuals for the given part ids, optionally windowed by period (inclusive
28
+ * YYYYMM). partIds are chunked internally (≤100/call) so a large set never
29
+ * hits the API's 500-id / 5000-row caps. Empty in → `[]` (no network call). */
30
+ async list(partIds, window) {
31
+ const ids = (0, internal_1.dedupePartIds)(partIds);
32
+ if (ids.length === 0)
33
+ return [];
34
+ const out = [];
35
+ for (const ids100 of (0, internal_1.chunk)(ids, internal_1.MAX_PARTIDS_PER_CALL)) {
36
+ const res = await this.http.request({
37
+ method: 'GET',
38
+ path: '/v1/actuals',
39
+ query: { partId: ids100.join(','), ...(0, internal_1.windowQuery)(window) },
40
+ });
41
+ for (const r of res.data)
42
+ out.push(coerce(r));
43
+ }
44
+ return out;
45
+ }
46
+ }
47
+ exports.ActualsResource = ActualsResource;
48
+ //# sourceMappingURL=actuals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actuals.js","sourceRoot":"","sources":["../src/actuals.ts"],"names":[],"mappings":";;;AAEA,yCAA4F;AAkB5F,SAAS,MAAM,CAAC,CAAe;IAC7B,OAAO;QACL,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,YAAY,EAAE,IAAA,gBAAK,EAAC,CAAC,CAAC,YAAY,CAAC;QACnC,OAAO,EAAE,IAAA,gBAAK,EAAC,CAAC,CAAC,OAAO,CAAC;QACzB,UAAU,EAAE,IAAA,gBAAK,EAAC,CAAC,CAAC,UAAU,CAAC;QAC/B,QAAQ,EAAE,IAAA,gBAAK,EAAC,CAAC,CAAC,QAAQ,CAAC;QAC3B,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,UAAU,EAAE,CAAC,CAAC,UAAU;KACzB,CAAC;AACJ,CAAC;AAED,gEAAgE;AAChE,MAAa,eAAe;IACG;IAA7B,YAA6B,IAAmB;QAAnB,SAAI,GAAJ,IAAI,CAAe;IAAG,CAAC;IAEpD;;oFAEgF;IAChF,KAAK,CAAC,IAAI,CAAC,OAAiB,EAAE,MAAsB;QAClD,MAAM,GAAG,GAAG,IAAA,wBAAa,EAAC,OAAO,CAAC,CAAC;QACnC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAChC,MAAM,GAAG,GAAgB,EAAE,CAAC;QAC5B,KAAK,MAAM,MAAM,IAAI,IAAA,gBAAK,EAAC,GAAG,EAAE,+BAAoB,CAAC,EAAE,CAAC;YACtD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAuC;gBACxE,MAAM,EAAE,KAAK;gBACb,IAAI,EAAE,aAAa;gBACnB,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,IAAA,sBAAW,EAAC,MAAM,CAAC,EAAE;aAC5D,CAAC,CAAC;YACH,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI;gBAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AApBD,0CAoBC"}
@@ -0,0 +1,25 @@
1
+ import { ActualsResource } from './actuals';
2
+ import { EdiForecastResource } from './ediForecast';
3
+ import type { IntegrationsClientConfig } from './types';
4
+ /**
5
+ * Client for the Integrations measure data plane — the Actual/EDI read API
6
+ * (Slice 4a of the actuals/EDI ingestion). Consumers (OMSF's Part Forecast
7
+ * first) read realized actuals + forward EDI forecast through this instead of
8
+ * a hand-rolled fetch client.
9
+ *
10
+ * const integrations = new IntegrationsClient({
11
+ * baseUrl: process.env.INTEGRATIONS_BASE_URL!,
12
+ * getToken: () => getSystemTokenForTenant(tenantId, 'integrations'),
13
+ * });
14
+ * const actuals = await integrations.actuals.list(partIds, { from: 202601 });
15
+ * const edi = await integrations.ediForecast.list(partIds); // latest release
16
+ *
17
+ * Both resources chunk partIds and coerce Decimal-as-string fields to numbers,
18
+ * so a large parts book never silently truncates and the row types are honest.
19
+ */
20
+ export declare class IntegrationsClient {
21
+ readonly actuals: ActualsResource;
22
+ readonly ediForecast: EdiForecastResource;
23
+ constructor(config: IntegrationsClientConfig);
24
+ }
25
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAExD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,kBAAkB;IAC7B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,mBAAmB,CAAC;gBAE9B,MAAM,EAAE,wBAAwB;CAK7C"}
package/dist/client.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IntegrationsClient = void 0;
4
+ const http_1 = require("./http");
5
+ const actuals_1 = require("./actuals");
6
+ const ediForecast_1 = require("./ediForecast");
7
+ /**
8
+ * Client for the Integrations measure data plane — the Actual/EDI read API
9
+ * (Slice 4a of the actuals/EDI ingestion). Consumers (OMSF's Part Forecast
10
+ * first) read realized actuals + forward EDI forecast through this instead of
11
+ * a hand-rolled fetch client.
12
+ *
13
+ * const integrations = new IntegrationsClient({
14
+ * baseUrl: process.env.INTEGRATIONS_BASE_URL!,
15
+ * getToken: () => getSystemTokenForTenant(tenantId, 'integrations'),
16
+ * });
17
+ * const actuals = await integrations.actuals.list(partIds, { from: 202601 });
18
+ * const edi = await integrations.ediForecast.list(partIds); // latest release
19
+ *
20
+ * Both resources chunk partIds and coerce Decimal-as-string fields to numbers,
21
+ * so a large parts book never silently truncates and the row types are honest.
22
+ */
23
+ class IntegrationsClient {
24
+ actuals;
25
+ ediForecast;
26
+ constructor(config) {
27
+ const http = new http_1.HttpTransport(config);
28
+ this.actuals = new actuals_1.ActualsResource(http);
29
+ this.ediForecast = new ediForecast_1.EdiForecastResource(http);
30
+ }
31
+ }
32
+ exports.IntegrationsClient = IntegrationsClient;
33
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;;AAAA,iCAAuC;AACvC,uCAA4C;AAC5C,+CAAoD;AAGpD;;;;;;;;;;;;;;;GAeG;AACH,MAAa,kBAAkB;IACpB,OAAO,CAAkB;IACzB,WAAW,CAAsB;IAE1C,YAAY,MAAgC;QAC1C,MAAM,IAAI,GAAG,IAAI,oBAAa,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,IAAI,yBAAe,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,WAAW,GAAG,IAAI,iCAAmB,CAAC,IAAI,CAAC,CAAC;IACnD,CAAC;CACF;AATD,gDASC"}
@@ -0,0 +1,13 @@
1
+ import type { HttpTransport } from './http';
2
+ import type { EdiForecastRow, MeasureWindow } from './types';
3
+ /** Forward EDI forecast, keyed by canonical master-data Part id. */
4
+ export declare class EdiForecastResource {
5
+ private readonly http;
6
+ constructor(http: HttpTransport);
7
+ /** EDI forecast for the given part ids. `window.latest` defaults to `true`
8
+ * (each part's most-recent release — usually what you want); pass `false` for
9
+ * every stored release. `from`/`to` window the target period (inclusive
10
+ * YYYYMM). partIds are chunked internally (≤100/call). Empty in → `[]`. */
11
+ list(partIds: string[], window?: MeasureWindow): Promise<EdiForecastRow[]>;
12
+ }
13
+ //# sourceMappingURL=ediForecast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ediForecast.d.ts","sourceRoot":"","sources":["../src/ediForecast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAwB,MAAM,SAAS,CAAC;AAoCnF,oEAAoE;AACpE,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,aAAa;IAEhD;;;gFAG4E;IACtE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;CAgBjF"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EdiForecastResource = void 0;
4
+ const internal_1 = require("./internal");
5
+ function coerce(r) {
6
+ return {
7
+ partId: r.partId,
8
+ plantCode: r.plantCode,
9
+ basePeriod: r.basePeriod,
10
+ targetPeriod: r.targetPeriod,
11
+ sourceSystem: r.sourceSystem,
12
+ currency: r.currency,
13
+ ediVolume: (0, internal_1.toNum)(r.ediVolume),
14
+ ediPrice: (0, internal_1.toNum)(r.ediPrice),
15
+ ediRevenue: (0, internal_1.toNum)(r.ediRevenue),
16
+ oem: r.oem,
17
+ customerName: r.customerName,
18
+ programRef: r.programRef,
19
+ };
20
+ }
21
+ /** Forward EDI forecast, keyed by canonical master-data Part id. */
22
+ class EdiForecastResource {
23
+ http;
24
+ constructor(http) {
25
+ this.http = http;
26
+ }
27
+ /** EDI forecast for the given part ids. `window.latest` defaults to `true`
28
+ * (each part's most-recent release — usually what you want); pass `false` for
29
+ * every stored release. `from`/`to` window the target period (inclusive
30
+ * YYYYMM). partIds are chunked internally (≤100/call). Empty in → `[]`. */
31
+ async list(partIds, window) {
32
+ const ids = (0, internal_1.dedupePartIds)(partIds);
33
+ if (ids.length === 0)
34
+ return [];
35
+ // Default latest=true unless the caller explicitly asked for all releases.
36
+ const latest = window?.latest === false ? undefined : 'true';
37
+ const out = [];
38
+ for (const ids100 of (0, internal_1.chunk)(ids, internal_1.MAX_PARTIDS_PER_CALL)) {
39
+ const res = await this.http.request({
40
+ method: 'GET',
41
+ path: '/v1/edi-forecast',
42
+ query: { partId: ids100.join(','), latest, ...(0, internal_1.windowQuery)(window) },
43
+ });
44
+ for (const r of res.data)
45
+ out.push(coerce(r));
46
+ }
47
+ return out;
48
+ }
49
+ }
50
+ exports.EdiForecastResource = EdiForecastResource;
51
+ //# sourceMappingURL=ediForecast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ediForecast.js","sourceRoot":"","sources":["../src/ediForecast.ts"],"names":[],"mappings":";;;AAEA,yCAA4F;AAkB5F,SAAS,MAAM,CAAC,CAAoB;IAClC,OAAO;QACL,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,SAAS,EAAE,IAAA,gBAAK,EAAC,CAAC,CAAC,SAAS,CAAC;QAC7B,QAAQ,EAAE,IAAA,gBAAK,EAAC,CAAC,CAAC,QAAQ,CAAC;QAC3B,UAAU,EAAE,IAAA,gBAAK,EAAC,CAAC,CAAC,UAAU,CAAC;QAC/B,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,UAAU,EAAE,CAAC,CAAC,UAAU;KACzB,CAAC;AACJ,CAAC;AAED,oEAAoE;AACpE,MAAa,mBAAmB;IACD;IAA7B,YAA6B,IAAmB;QAAnB,SAAI,GAAJ,IAAI,CAAe;IAAG,CAAC;IAEpD;;;gFAG4E;IAC5E,KAAK,CAAC,IAAI,CAAC,OAAiB,EAAE,MAAsB;QAClD,MAAM,GAAG,GAAG,IAAA,wBAAa,EAAC,OAAO,CAAC,CAAC;QACnC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAChC,2EAA2E;QAC3E,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;QAC7D,MAAM,GAAG,GAAqB,EAAE,CAAC;QACjC,KAAK,MAAM,MAAM,IAAI,IAAA,gBAAK,EAAC,GAAG,EAAE,+BAAoB,CAAC,EAAE,CAAC;YACtD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAA4C;gBAC7E,MAAM,EAAE,KAAK;gBACb,IAAI,EAAE,kBAAkB;gBACxB,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,IAAA,sBAAW,EAAC,MAAM,CAAC,EAAE;aACpE,CAAC,CAAC;YACH,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI;gBAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAvBD,kDAuBC"}
@@ -0,0 +1,16 @@
1
+ export declare class IntegrationsError extends Error {
2
+ readonly statusCode: number;
3
+ readonly code: string;
4
+ readonly requestId: string | undefined;
5
+ constructor(message: string, statusCode: number, code: string, requestId?: string);
6
+ }
7
+ export declare class NotFoundError extends IntegrationsError {
8
+ constructor(message?: string, requestId?: string);
9
+ }
10
+ export declare class UnauthorizedError extends IntegrationsError {
11
+ constructor(message?: string, requestId?: string);
12
+ }
13
+ export declare class ForbiddenError extends IntegrationsError {
14
+ constructor(message?: string, requestId?: string);
15
+ }
16
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAKA,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;gBAE3B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;CAOlF;AAED,qBAAa,aAAc,SAAQ,iBAAiB;gBACtC,OAAO,SAAuB,EAAE,SAAS,CAAC,EAAE,MAAM;CAG/D;AAED,qBAAa,iBAAkB,SAAQ,iBAAiB;gBAC1C,OAAO,SAAiB,EAAE,SAAS,CAAC,EAAE,MAAM;CAGzD;AAED,qBAAa,cAAe,SAAQ,iBAAiB;gBACvC,OAAO,SAAc,EAAE,SAAS,CAAC,EAAE,MAAM;CAGtD"}
package/dist/errors.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ // =============================================================================
3
+ // Client-side error hierarchy — mirrors the backend's AppError shape (and the
4
+ // VI / master-data / dms clients).
5
+ // =============================================================================
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ForbiddenError = exports.UnauthorizedError = exports.NotFoundError = exports.IntegrationsError = void 0;
8
+ class IntegrationsError extends Error {
9
+ statusCode;
10
+ code;
11
+ requestId;
12
+ constructor(message, statusCode, code, requestId) {
13
+ super(message);
14
+ this.name = this.constructor.name;
15
+ this.statusCode = statusCode;
16
+ this.code = code;
17
+ this.requestId = requestId;
18
+ }
19
+ }
20
+ exports.IntegrationsError = IntegrationsError;
21
+ class NotFoundError extends IntegrationsError {
22
+ constructor(message = 'Resource not found', requestId) {
23
+ super(message, 404, 'NOT_FOUND', requestId);
24
+ }
25
+ }
26
+ exports.NotFoundError = NotFoundError;
27
+ class UnauthorizedError extends IntegrationsError {
28
+ constructor(message = 'Unauthorized', requestId) {
29
+ super(message, 401, 'UNAUTHORIZED', requestId);
30
+ }
31
+ }
32
+ exports.UnauthorizedError = UnauthorizedError;
33
+ class ForbiddenError extends IntegrationsError {
34
+ constructor(message = 'Forbidden', requestId) {
35
+ super(message, 403, 'FORBIDDEN', requestId);
36
+ }
37
+ }
38
+ exports.ForbiddenError = ForbiddenError;
39
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,8EAA8E;AAC9E,mCAAmC;AACnC,gFAAgF;;;AAEhF,MAAa,iBAAkB,SAAQ,KAAK;IACjC,UAAU,CAAS;IACnB,IAAI,CAAS;IACb,SAAS,CAAqB;IAEvC,YAAY,OAAe,EAAE,UAAkB,EAAE,IAAY,EAAE,SAAkB;QAC/E,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAClC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAZD,8CAYC;AAED,MAAa,aAAc,SAAQ,iBAAiB;IAClD,YAAY,OAAO,GAAG,oBAAoB,EAAE,SAAkB;QAC5D,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;IAC9C,CAAC;CACF;AAJD,sCAIC;AAED,MAAa,iBAAkB,SAAQ,iBAAiB;IACtD,YAAY,OAAO,GAAG,cAAc,EAAE,SAAkB;QACtD,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC;IACjD,CAAC;CACF;AAJD,8CAIC;AAED,MAAa,cAAe,SAAQ,iBAAiB;IACnD,YAAY,OAAO,GAAG,WAAW,EAAE,SAAkB;QACnD,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;IAC9C,CAAC;CACF;AAJD,wCAIC"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import type { IntegrationsClientConfig } from './types';
2
+ interface HttpRequestOptions {
3
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
4
+ path: string;
5
+ body?: unknown;
6
+ query?: Record<string, string | undefined>;
7
+ }
8
+ /** Auth-aware fetch transport. Mirrors the VI / master-data clients:
9
+ * `{ baseUrl, getToken, timeout }`, bearer injection, timeout via
10
+ * AbortController, and status→error mapping. */
11
+ export declare class HttpTransport {
12
+ private readonly baseUrl;
13
+ private readonly getToken;
14
+ private readonly timeout;
15
+ constructor(config: IntegrationsClientConfig);
16
+ request<T>(options: HttpRequestOptions): Promise<T>;
17
+ private buildUrl;
18
+ private throwForStatus;
19
+ }
20
+ export {};
21
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAKxD,UAAU,kBAAkB;IAC1B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC5C;AAED;;iDAEiD;AACjD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAC1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,wBAAwB;IAMtC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,CAAC,CAAC;IAoCzD,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,cAAc;CAyBvB"}
package/dist/http.js ADDED
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpTransport = void 0;
4
+ const errors_1 = require("./errors");
5
+ const DEFAULT_TIMEOUT = 30_000;
6
+ /** Auth-aware fetch transport. Mirrors the VI / master-data clients:
7
+ * `{ baseUrl, getToken, timeout }`, bearer injection, timeout via
8
+ * AbortController, and status→error mapping. */
9
+ class HttpTransport {
10
+ baseUrl;
11
+ getToken;
12
+ timeout;
13
+ constructor(config) {
14
+ this.baseUrl = config.baseUrl.replace(/\/+$/, '');
15
+ this.getToken = config.getToken;
16
+ this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
17
+ }
18
+ async request(options) {
19
+ const { method, path, body, query } = options;
20
+ const url = this.buildUrl(path, query);
21
+ const token = await this.getToken();
22
+ const headers = {
23
+ Authorization: `Bearer ${token}`,
24
+ 'Content-Type': 'application/json',
25
+ };
26
+ const controller = new AbortController();
27
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
28
+ let response;
29
+ try {
30
+ response = await fetch(url, {
31
+ method,
32
+ headers,
33
+ body: body !== undefined ? JSON.stringify(body) : undefined,
34
+ signal: controller.signal,
35
+ });
36
+ }
37
+ catch (error) {
38
+ if (error.name === 'AbortError') {
39
+ throw new errors_1.IntegrationsError('Request timed out', 0, 'TIMEOUT');
40
+ }
41
+ throw new errors_1.IntegrationsError(`Network error: ${error.message}`, 0, 'NETWORK_ERROR');
42
+ }
43
+ finally {
44
+ clearTimeout(timeoutId);
45
+ }
46
+ if (response.status === 204)
47
+ return undefined;
48
+ const responseBody = await response.json().catch(() => undefined);
49
+ if (!response.ok)
50
+ this.throwForStatus(response.status, responseBody);
51
+ return responseBody;
52
+ }
53
+ buildUrl(path, query) {
54
+ const url = new URL(`${this.baseUrl}${path}`);
55
+ if (query) {
56
+ for (const [key, value] of Object.entries(query)) {
57
+ if (value !== undefined)
58
+ url.searchParams.set(key, value);
59
+ }
60
+ }
61
+ return url.toString();
62
+ }
63
+ throwForStatus(status, body) {
64
+ const errorBody = body;
65
+ const rawError = errorBody?.error;
66
+ const message = typeof rawError === 'string' ? rawError : rawError?.message || `Request failed with status ${status}`;
67
+ const requestId = errorBody?.meta?.requestId;
68
+ switch (status) {
69
+ case 404:
70
+ throw new errors_1.NotFoundError(message, requestId);
71
+ case 401:
72
+ throw new errors_1.UnauthorizedError(message, requestId);
73
+ case 403:
74
+ throw new errors_1.ForbiddenError(message, requestId);
75
+ default:
76
+ throw new errors_1.IntegrationsError(message, status, typeof rawError === 'object' ? rawError?.code || 'UNKNOWN_ERROR' : 'UNKNOWN_ERROR', requestId);
77
+ }
78
+ }
79
+ }
80
+ exports.HttpTransport = HttpTransport;
81
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { IntegrationsClient } from './client';
2
+ export { MockIntegrationsClient } from './mock';
3
+ export { ActualsResource } from './actuals';
4
+ export { EdiForecastResource } from './ediForecast';
5
+ export { IntegrationsError, NotFoundError, UnauthorizedError, ForbiddenError, } from './errors';
6
+ export type { IntegrationsClientConfig, IntegrationsEnvelope, MeasureWindow, ActualRow, EdiForecastRow, } from './types';
7
+ export type { MockSeed } from './mock';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,cAAc,GACf,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,wBAAwB,EACxB,oBAAoB,EACpB,aAAa,EACb,SAAS,EACT,cAAc,GACf,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ForbiddenError = exports.UnauthorizedError = exports.NotFoundError = exports.IntegrationsError = exports.EdiForecastResource = exports.ActualsResource = exports.MockIntegrationsClient = exports.IntegrationsClient = void 0;
4
+ var client_1 = require("./client");
5
+ Object.defineProperty(exports, "IntegrationsClient", { enumerable: true, get: function () { return client_1.IntegrationsClient; } });
6
+ var mock_1 = require("./mock");
7
+ Object.defineProperty(exports, "MockIntegrationsClient", { enumerable: true, get: function () { return mock_1.MockIntegrationsClient; } });
8
+ var actuals_1 = require("./actuals");
9
+ Object.defineProperty(exports, "ActualsResource", { enumerable: true, get: function () { return actuals_1.ActualsResource; } });
10
+ var ediForecast_1 = require("./ediForecast");
11
+ Object.defineProperty(exports, "EdiForecastResource", { enumerable: true, get: function () { return ediForecast_1.EdiForecastResource; } });
12
+ var errors_1 = require("./errors");
13
+ Object.defineProperty(exports, "IntegrationsError", { enumerable: true, get: function () { return errors_1.IntegrationsError; } });
14
+ Object.defineProperty(exports, "NotFoundError", { enumerable: true, get: function () { return errors_1.NotFoundError; } });
15
+ Object.defineProperty(exports, "UnauthorizedError", { enumerable: true, get: function () { return errors_1.UnauthorizedError; } });
16
+ Object.defineProperty(exports, "ForbiddenError", { enumerable: true, get: function () { return errors_1.ForbiddenError; } });
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAA8C;AAArC,4GAAA,kBAAkB,OAAA;AAC3B,+BAAgD;AAAvC,8GAAA,sBAAsB,OAAA;AAC/B,qCAA4C;AAAnC,0GAAA,eAAe,OAAA;AACxB,6CAAoD;AAA3C,kHAAA,mBAAmB,OAAA;AAC5B,mCAKkB;AAJhB,2GAAA,iBAAiB,OAAA;AACjB,uGAAA,aAAa,OAAA;AACb,2GAAA,iBAAiB,OAAA;AACjB,wGAAA,cAAc,OAAA"}
@@ -0,0 +1,13 @@
1
+ export declare const MAX_PARTIDS_PER_CALL = 100;
2
+ /** Trim, drop blanks, de-dupe — the API does this server-side too, but doing it
3
+ * here avoids wasting a chunk on duplicates. */
4
+ export declare function dedupePartIds(ids: string[]): string[];
5
+ export declare function chunk<T>(arr: T[], size: number): T[][];
6
+ /** Fix 1: money/volume columns arrive as strings (Prisma Decimal.toJSON). Coerce
7
+ * to number so the row types are honest — a consumer must never do `"10" + "5"`. */
8
+ export declare function toNum(v: unknown): number | null;
9
+ export declare function windowQuery(window?: {
10
+ from?: number;
11
+ to?: number;
12
+ }): Record<string, string | undefined>;
13
+ //# sourceMappingURL=internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC;iDACiD;AACjD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAErD;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,EAAE,EAAE,CAItD;AAED;qFACqF;AACrF,wBAAgB,KAAK,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI/C;AAED,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAKvG"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ // Shared internals for the measure resources — the two things that make this a
3
+ // SDK and not a raw fetch: partId chunking (Fix 2) and Decimal coercion (Fix 1).
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.MAX_PARTIDS_PER_CALL = void 0;
6
+ exports.dedupePartIds = dedupePartIds;
7
+ exports.chunk = chunk;
8
+ exports.toNum = toNum;
9
+ exports.windowQuery = windowQuery;
10
+ // The read API caps at 500 partIds and 5000 result rows. EDI `latest` yields
11
+ // ~13 rows/part, so 500 parts × 13 ≈ 6,500 would silently truncate at 5,000.
12
+ // Chunking at 100/call keeps every request well under both caps.
13
+ exports.MAX_PARTIDS_PER_CALL = 100;
14
+ /** Trim, drop blanks, de-dupe — the API does this server-side too, but doing it
15
+ * here avoids wasting a chunk on duplicates. */
16
+ function dedupePartIds(ids) {
17
+ return Array.from(new Set(ids.map((s) => s.trim()).filter(Boolean)));
18
+ }
19
+ function chunk(arr, size) {
20
+ const out = [];
21
+ for (let i = 0; i < arr.length; i += size)
22
+ out.push(arr.slice(i, i + size));
23
+ return out;
24
+ }
25
+ /** Fix 1: money/volume columns arrive as strings (Prisma Decimal.toJSON). Coerce
26
+ * to number so the row types are honest — a consumer must never do `"10" + "5"`. */
27
+ function toNum(v) {
28
+ if (v == null)
29
+ return null;
30
+ const n = typeof v === 'number' ? v : Number(v);
31
+ return Number.isFinite(n) ? n : null;
32
+ }
33
+ function windowQuery(window) {
34
+ return {
35
+ from: window?.from != null ? String(window.from) : undefined,
36
+ to: window?.to != null ? String(window.to) : undefined,
37
+ };
38
+ }
39
+ //# sourceMappingURL=internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":";AAAA,+EAA+E;AAC/E,iFAAiF;;;AASjF,sCAEC;AAED,sBAIC;AAID,sBAIC;AAED,kCAKC;AA9BD,6EAA6E;AAC7E,6EAA6E;AAC7E,iEAAiE;AACpD,QAAA,oBAAoB,GAAG,GAAG,CAAC;AAExC;iDACiD;AACjD,SAAgB,aAAa,CAAC,GAAa;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,SAAgB,KAAK,CAAI,GAAQ,EAAE,IAAY;IAC7C,MAAM,GAAG,GAAU,EAAE,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI;QAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAC5E,OAAO,GAAG,CAAC;AACb,CAAC;AAED;qFACqF;AACrF,SAAgB,KAAK,CAAC,CAAU;IAC9B,IAAI,CAAC,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC3B,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC,CAAC;AAED,SAAgB,WAAW,CAAC,MAAuC;IACjE,OAAO;QACL,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QAC5D,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;KACvD,CAAC;AACJ,CAAC"}
package/dist/mock.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ import type { ActualRow, EdiForecastRow, MeasureWindow } from './types';
2
+ /** Seed data for the mock client. */
3
+ export interface MockSeed {
4
+ actuals?: ActualRow[];
5
+ ediForecast?: EdiForecastRow[];
6
+ }
7
+ /**
8
+ * In-memory stand-in mirroring the IntegrationsClient surface — for a consumer's
9
+ * tests, and for gating a page behind a mock flag before the real feed is live
10
+ * (OMSF's `partForecastLiveMeasures`). Filters seed rows by partId + window and
11
+ * applies the same latest-default as the real EDI resource.
12
+ */
13
+ export declare class MockIntegrationsClient {
14
+ private readonly _actuals;
15
+ private readonly _edi;
16
+ constructor(seed?: MockSeed);
17
+ readonly actuals: {
18
+ list: (partIds: string[], window?: MeasureWindow) => Promise<ActualRow[]>;
19
+ };
20
+ readonly ediForecast: {
21
+ list: (partIds: string[], window?: MeasureWindow) => Promise<EdiForecastRow[]>;
22
+ };
23
+ }
24
+ //# sourceMappingURL=mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExE,qCAAqC;AACrC,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;CAChC;AAED;;;;;GAKG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmB;gBAE5B,IAAI,GAAE,QAAa;IAK/B,QAAQ,CAAC,OAAO;wBACQ,MAAM,EAAE,WAAW,aAAa,KAAG,OAAO,CAAC,SAAS,EAAE,CAAC;MAS7E;IAEF,QAAQ,CAAC,WAAW;wBACI,MAAM,EAAE,WAAW,aAAa,KAAG,OAAO,CAAC,cAAc,EAAE,CAAC;MAkBlF;CACH"}
package/dist/mock.js ADDED
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MockIntegrationsClient = void 0;
4
+ /**
5
+ * In-memory stand-in mirroring the IntegrationsClient surface — for a consumer's
6
+ * tests, and for gating a page behind a mock flag before the real feed is live
7
+ * (OMSF's `partForecastLiveMeasures`). Filters seed rows by partId + window and
8
+ * applies the same latest-default as the real EDI resource.
9
+ */
10
+ class MockIntegrationsClient {
11
+ _actuals;
12
+ _edi;
13
+ constructor(seed = {}) {
14
+ this._actuals = seed.actuals ?? [];
15
+ this._edi = seed.ediForecast ?? [];
16
+ }
17
+ actuals = {
18
+ list: async (partIds, window) => {
19
+ const ids = new Set(partIds);
20
+ return this._actuals.filter((r) => ids.has(r.partId) &&
21
+ (window?.from == null || r.period >= window.from) &&
22
+ (window?.to == null || r.period <= window.to));
23
+ },
24
+ };
25
+ ediForecast = {
26
+ list: async (partIds, window) => {
27
+ const ids = new Set(partIds);
28
+ let rows = this._edi.filter((r) => ids.has(r.partId) &&
29
+ (window?.from == null || r.targetPeriod >= window.from) &&
30
+ (window?.to == null || r.targetPeriod <= window.to));
31
+ // Default latest=true: keep each part's most-recent release (max basePeriod).
32
+ if (window?.latest !== false) {
33
+ const maxBase = new Map();
34
+ for (const r of rows) {
35
+ maxBase.set(r.partId, Math.max(maxBase.get(r.partId) ?? -Infinity, r.basePeriod));
36
+ }
37
+ rows = rows.filter((r) => r.basePeriod === maxBase.get(r.partId));
38
+ }
39
+ return rows;
40
+ },
41
+ };
42
+ }
43
+ exports.MockIntegrationsClient = MockIntegrationsClient;
44
+ //# sourceMappingURL=mock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.js","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":";;;AAQA;;;;;GAKG;AACH,MAAa,sBAAsB;IAChB,QAAQ,CAAc;IACtB,IAAI,CAAmB;IAExC,YAAY,OAAiB,EAAE;QAC7B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;IACrC,CAAC;IAEQ,OAAO,GAAG;QACjB,IAAI,EAAE,KAAK,EAAE,OAAiB,EAAE,MAAsB,EAAwB,EAAE;YAC9E,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;YAC7B,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CACzB,CAAC,CAAC,EAAE,EAAE,CACJ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;gBACjB,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC;gBACjD,CAAC,MAAM,EAAE,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,EAAE,CAAC,CAChD,CAAC;QACJ,CAAC;KACF,CAAC;IAEO,WAAW,GAAG;QACrB,IAAI,EAAE,KAAK,EAAE,OAAiB,EAAE,MAAsB,EAA6B,EAAE;YACnF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;YAC7B,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CACzB,CAAC,CAAC,EAAE,EAAE,CACJ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;gBACjB,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC;gBACvD,CAAC,MAAM,EAAE,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC,YAAY,IAAI,MAAM,CAAC,EAAE,CAAC,CACtD,CAAC;YACF,8EAA8E;YAC9E,IAAI,MAAM,EAAE,MAAM,KAAK,KAAK,EAAE,CAAC;gBAC7B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;gBAC1C,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;oBACrB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;gBACpF,CAAC;gBACD,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YACpE,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC;CACH;AAzCD,wDAyCC"}
@@ -0,0 +1,60 @@
1
+ export interface IntegrationsClientConfig {
2
+ /** e.g. https://api.integrations.dev.campfiresuite.com (no trailing slash needed). */
3
+ baseUrl: string;
4
+ /** Tenant-scoped bearer. A backend passes a minted system token; the API
5
+ * checks signature + tenant only (no `aud` today), so a caller's own token works. */
6
+ getToken: () => string | Promise<string>;
7
+ /** Request timeout in milliseconds. Defaults to 30_000. */
8
+ timeout?: number;
9
+ }
10
+ export interface IntegrationsEnvelope<T> {
11
+ data: T;
12
+ meta?: {
13
+ requestId?: string;
14
+ timestamp?: string;
15
+ };
16
+ }
17
+ /** Period window for a measure read; `latest` applies to EDI only. */
18
+ export interface MeasureWindow {
19
+ /** Inclusive lower bound, YYYYMM. */
20
+ from?: number;
21
+ /** Inclusive upper bound, YYYYMM. */
22
+ to?: number;
23
+ /** EDI only — each part's most-recent release. Defaults to `true` in the SDK
24
+ * (you usually want the current forecast); pass `false` for every release.
25
+ * NB: the raw API returns all releases when the param is absent — the SDK's
26
+ * default-true is a deliberate convenience, so an SDK call and a raw curl differ. */
27
+ latest?: boolean;
28
+ }
29
+ /** Realized actuals row. Decimal fields are COERCED to numbers by the SDK (the
30
+ * API sends them as strings — Prisma Decimal.toJSON). */
31
+ export interface ActualRow {
32
+ partId: string;
33
+ plantCode: string | null;
34
+ period: number;
35
+ sourceSystem: string;
36
+ currency: string | null;
37
+ actualVolume: number | null;
38
+ revenue: number | null;
39
+ usdRevenue: number | null;
40
+ unitCost: number | null;
41
+ oem: string | null;
42
+ customerName: string | null;
43
+ programRef: string | null;
44
+ }
45
+ /** Forward EDI forecast row. Decimal fields coerced to numbers (see ActualRow). */
46
+ export interface EdiForecastRow {
47
+ partId: string;
48
+ plantCode: string | null;
49
+ basePeriod: number;
50
+ targetPeriod: number;
51
+ sourceSystem: string;
52
+ currency: string | null;
53
+ ediVolume: number | null;
54
+ ediPrice: number | null;
55
+ ediRevenue: number | null;
56
+ oem: string | null;
57
+ customerName: string | null;
58
+ programRef: string | null;
59
+ }
60
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACvC,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB;0FACsF;IACtF,QAAQ,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB,CAAC,CAAC;IACrC,IAAI,EAAE,CAAC,CAAC;IACR,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACnD;AAED,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;;;0FAGsF;IACtF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;0DAC0D;AAC1D,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,mFAAmF;AACnF,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@campfire-interactive/integrations-client",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript client for the Integrations Actual/EDI read API (the measure data plane)",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "clean": "rm -rf dist",
13
+ "test": "vitest run"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/Campfire-Interactive/packages.git"
18
+ },
19
+ "publishConfig": {
20
+ "registry": "https://registry.npmjs.org",
21
+ "access": "public"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^25.5.0",
25
+ "typescript": "^5.3.3",
26
+ "vitest": "^3.2.7"
27
+ },
28
+ "engines": {
29
+ "node": ">=18.0.0"
30
+ }
31
+ }