@dataworks-technology/data 0.1.9 → 0.2.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 +113 -10
- package/dist/index.cjs +143 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +116 -5
- package/dist/index.d.ts +116 -5
- package/dist/index.js +142 -31
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ You need a Dataworks developer account. Contact your Dataworks administrator to
|
|
|
28
28
|
| `errorUrl` | API Gateway endpoint for error reporting |
|
|
29
29
|
| `realtimeUrl` | AppSync Events API endpoint for subscriptions |
|
|
30
30
|
| Username + password | Your developer login credentials |
|
|
31
|
+
| `apiKey` (optional) | AppSync Events API key for subscription-only access |
|
|
31
32
|
|
|
32
33
|
## Installation
|
|
33
34
|
|
|
@@ -58,6 +59,7 @@ const dataworks = new DataClient({
|
|
|
58
59
|
ingestUrl: "https://your-ingest-endpoint.dataworks.live",
|
|
59
60
|
errorUrl: "https://your-error-endpoint.dataworks.live",
|
|
60
61
|
realtimeUrl: "https://your-realtime-endpoint.dataworks.live",
|
|
62
|
+
apiKey: "your-appsync-events-api-key", // optional
|
|
61
63
|
});
|
|
62
64
|
|
|
63
65
|
// Authenticate
|
|
@@ -94,9 +96,33 @@ const dataworks = new DataClient({
|
|
|
94
96
|
});
|
|
95
97
|
```
|
|
96
98
|
|
|
99
|
+
#### API Key Authentication (Subscription-Only)
|
|
100
|
+
|
|
101
|
+
For read-only access to real-time subscriptions without Cognito credentials:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { DataClient, SubscriptionEvent } from "@dataworks-technology/data";
|
|
105
|
+
|
|
106
|
+
const dataworks = new DataClient({
|
|
107
|
+
cognitoEndpoint: "https://cognito-idp.eu-west-1.amazonaws.com/",
|
|
108
|
+
clientId: "unused",
|
|
109
|
+
ingestUrl: "https://unused.dataworks.live",
|
|
110
|
+
errorUrl: "https://unused.dataworks.live",
|
|
111
|
+
realtimeUrl: "https://realtime.dataworks.live",
|
|
112
|
+
apiKey: "da2-xxxxxxxxxx", // AppSync Events API key
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// No login required — subscribe directly
|
|
116
|
+
const sub = dataworks.subscribe("dataworks/*", (event: SubscriptionEvent) => {
|
|
117
|
+
console.log(event.athleteId, event.metrics);
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
> **Note:** API key authentication only supports subscriptions. Ingest and error reporting require Cognito credentials. If both `apiKey` and Cognito credentials are provided, Cognito takes precedence.
|
|
122
|
+
|
|
97
123
|
### `dataworks.login(username, password)`
|
|
98
124
|
|
|
99
|
-
Authenticate with Cognito. Must be called before any other operation.
|
|
125
|
+
Authenticate with Cognito. Must be called before any other operation (unless using API key for subscriptions).
|
|
100
126
|
|
|
101
127
|
```typescript
|
|
102
128
|
const result = await dataworks.login("username", "password");
|
|
@@ -105,7 +131,7 @@ const result = await dataworks.login("username", "password");
|
|
|
105
131
|
|
|
106
132
|
### `dataworks.ingest(metrics, eventId, datasetDatasourceId)`
|
|
107
133
|
|
|
108
|
-
Send metric data points to the Data Engine. Invalid metrics are
|
|
134
|
+
Send metric data points to the Data Engine. Invalid metrics are dropped with warnings.
|
|
109
135
|
|
|
110
136
|
```typescript
|
|
111
137
|
await dataworks.ingest(
|
|
@@ -118,6 +144,21 @@ await dataworks.ingest(
|
|
|
118
144
|
);
|
|
119
145
|
```
|
|
120
146
|
|
|
147
|
+
### `dataworks.ingestWithResult(metrics, eventId, datasetDatasourceId, options?)`
|
|
148
|
+
|
|
149
|
+
Ingest with structured validation diagnostics.
|
|
150
|
+
|
|
151
|
+
- Default mode (`best-effort`): invalid metrics are dropped and valid metrics continue.
|
|
152
|
+
- Strict mode (`strict`): throws `MetricValidationError` if any metric is invalid.
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
const result = await dataworks.ingestWithResult(metrics, "event-123", "ds-456", {
|
|
156
|
+
validationMode: "best-effort",
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
console.log(result.acceptedCount, result.droppedCount, result.requestSent);
|
|
160
|
+
```
|
|
161
|
+
|
|
121
162
|
### `dataworks.subscribe(channel, onEvent, onError?)`
|
|
122
163
|
|
|
123
164
|
Subscribe to real-time data events via WebSocket.
|
|
@@ -125,13 +166,16 @@ Subscribe to real-time data events via WebSocket.
|
|
|
125
166
|
Tip: start with `dataworks/1/1/*` to inspect all metrics for a dataset-datasource/event pair, then narrow to a specific metric channel such as `dataworks/1/1/heartrate`.
|
|
126
167
|
|
|
127
168
|
```typescript
|
|
169
|
+
import { SubscriptionEvent, SubscriptionError } from "@dataworks-technology/data";
|
|
170
|
+
|
|
128
171
|
const subscription = dataworks.subscribe(
|
|
129
172
|
"dataworks/1/1/heartrate",
|
|
130
|
-
(event) => {
|
|
131
|
-
console.log("
|
|
173
|
+
(event: SubscriptionEvent) => {
|
|
174
|
+
console.log("Athlete:", event.athleteId);
|
|
175
|
+
console.log("Metrics:", event.metrics);
|
|
132
176
|
},
|
|
133
|
-
(error) => {
|
|
134
|
-
console.error("
|
|
177
|
+
(error: SubscriptionError) => {
|
|
178
|
+
console.error("Error:", error.message, "Code:", error.code);
|
|
135
179
|
},
|
|
136
180
|
);
|
|
137
181
|
|
|
@@ -139,10 +183,61 @@ const subscription = dataworks.subscribe(
|
|
|
139
183
|
subscription.close();
|
|
140
184
|
```
|
|
141
185
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
186
|
+
#### Event Type: `SubscriptionEvent`
|
|
187
|
+
|
|
188
|
+
The standard Data Engine event shape:
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
interface SubscriptionEvent {
|
|
192
|
+
name: string; // e.g. "heartrateingested"
|
|
193
|
+
timestamp: number; // Unix timestamp (milliseconds)
|
|
194
|
+
timestampSec: number; // Unix timestamp (seconds)
|
|
195
|
+
eventId: string;
|
|
196
|
+
datasetDatasourceId: string;
|
|
197
|
+
athleteId: string;
|
|
198
|
+
metrics: SubscriptionMetric[];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
interface SubscriptionMetric {
|
|
202
|
+
metric: string; // e.g. "current", "heartrate"
|
|
203
|
+
value: number | string;
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### Custom Event Types
|
|
208
|
+
|
|
209
|
+
If your channel publishes a different format, use the generic type parameter:
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
interface MyCustomEvent {
|
|
213
|
+
athleteId: string;
|
|
214
|
+
customField: number;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
dataworks.subscribe<MyCustomEvent>("custom/*", (event) => {
|
|
218
|
+
console.log(event.customField); // TypeScript knows this exists
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### Error Type: `SubscriptionError`
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
interface SubscriptionError {
|
|
226
|
+
message: string;
|
|
227
|
+
code: "CONNECTION_ERROR" | "UNAUTHORIZED" | "SUBSCRIPTION_ERROR"
|
|
228
|
+
| "PARSE_ERROR" | "RECONNECT_FAILED" | "UNKNOWN";
|
|
229
|
+
cause?: Error;
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
| Code | Description |
|
|
234
|
+
|------|-------------|
|
|
235
|
+
| `CONNECTION_ERROR` | WebSocket connection failed (network, TLS) |
|
|
236
|
+
| `UNAUTHORIZED` | Auth token expired or invalid |
|
|
237
|
+
| `SUBSCRIPTION_ERROR` | AppSync subscription error (invalid channel, server error) |
|
|
238
|
+
| `PARSE_ERROR` | Malformed message or event payload |
|
|
239
|
+
| `RECONNECT_FAILED` | Token refresh failed after auth expiry |
|
|
240
|
+
| `UNKNOWN` | Unexpected error |
|
|
146
241
|
|
|
147
242
|
### `dataworks.reportError(error)`
|
|
148
243
|
|
|
@@ -234,6 +329,10 @@ import type {
|
|
|
234
329
|
SubscriptionHandler,
|
|
235
330
|
ErrorHandler,
|
|
236
331
|
Subscription,
|
|
332
|
+
ValidationMode,
|
|
333
|
+
DroppedMetric,
|
|
334
|
+
IngestOptions,
|
|
335
|
+
IngestResult,
|
|
237
336
|
} from "@dataworks-technology/data";
|
|
238
337
|
```
|
|
239
338
|
|
|
@@ -283,6 +382,10 @@ try {
|
|
|
283
382
|
|
|
284
383
|
Calling `ingest()`, `reportError()`, or `subscribe()` before `login()` throws immediately.
|
|
285
384
|
|
|
385
|
+
Exception: `subscribe()` can run without `login()` when `apiKey` is configured. This mode is subscription-only — `ingest()` and `reportError()` still require `login()`.
|
|
386
|
+
|
|
387
|
+
When both Cognito credentials (`login(username, password)` + `clientId`) and `apiKey` are available, the SDK always uses Cognito auth for subscriptions.
|
|
388
|
+
|
|
286
389
|
## Requirements
|
|
287
390
|
|
|
288
391
|
- **Node.js** ≥ 18 (uses native `fetch`)
|
package/dist/index.cjs
CHANGED
|
@@ -31,12 +31,33 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
DataClient: () => DataClient,
|
|
34
|
+
MetricValidationError: () => MetricValidationError,
|
|
34
35
|
filterValidMetrics: () => filterValidMetrics2,
|
|
35
36
|
validateMetric: () => validateMetric2
|
|
36
37
|
});
|
|
37
38
|
module.exports = __toCommonJS(index_exports);
|
|
38
39
|
|
|
39
|
-
//
|
|
40
|
+
// ../../../Dataworks-SDK/dist/client/events-auth.js
|
|
41
|
+
var INGEST_AUTH_ERROR = "Authentication failed: username, password, and clientId are required for ingest.";
|
|
42
|
+
function resolveEventsAuth(input) {
|
|
43
|
+
const userToken = input.userToken?.trim();
|
|
44
|
+
if (userToken) {
|
|
45
|
+
return { mode: "userCredentials", token: userToken };
|
|
46
|
+
}
|
|
47
|
+
const apiKey = input.apiKey?.trim();
|
|
48
|
+
if (apiKey) {
|
|
49
|
+
return { mode: "apiKey", apiKey };
|
|
50
|
+
}
|
|
51
|
+
throw new Error(INGEST_AUTH_ERROR);
|
|
52
|
+
}
|
|
53
|
+
function buildEventsAuthHeader(resolved, host) {
|
|
54
|
+
if (resolved.mode === "userCredentials") {
|
|
55
|
+
return { Authorization: resolved.token, host };
|
|
56
|
+
}
|
|
57
|
+
return { "x-api-key": resolved.apiKey, host };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ../../../Dataworks-SDK/dist/client/subscription-manager.js
|
|
40
61
|
function createAutoRefreshingSubscription(options) {
|
|
41
62
|
const maxReconnectAttempts = options.maxReconnectAttempts ?? 1;
|
|
42
63
|
let reconnectAttempts = 0;
|
|
@@ -78,7 +99,7 @@ function createAutoRefreshingSubscription(options) {
|
|
|
78
99
|
};
|
|
79
100
|
}
|
|
80
101
|
|
|
81
|
-
//
|
|
102
|
+
// ../../../Dataworks-SDK/dist/client/validation.js
|
|
82
103
|
function validateMetric(m) {
|
|
83
104
|
if (typeof m.metric !== "string" || m.metric.trim() === "")
|
|
84
105
|
return "metric must be a non-empty string";
|
|
@@ -127,7 +148,7 @@ function getMetricValidationResult(metrics) {
|
|
|
127
148
|
return { valid, dropped };
|
|
128
149
|
}
|
|
129
150
|
|
|
130
|
-
//
|
|
151
|
+
// ../../../Dataworks-SDK/dist/client/base64url.js
|
|
131
152
|
var toBase64Url = (input) => {
|
|
132
153
|
if (typeof Buffer !== "undefined") {
|
|
133
154
|
return Buffer.from(input).toString("base64url");
|
|
@@ -142,7 +163,7 @@ var fromBase64Url = (b64url) => {
|
|
|
142
163
|
return atob(padded);
|
|
143
164
|
};
|
|
144
165
|
|
|
145
|
-
//
|
|
166
|
+
// ../../../Dataworks-SDK/dist/client/auth.js
|
|
146
167
|
async function loginWithCredentials(username, password, config) {
|
|
147
168
|
const authParams = {
|
|
148
169
|
USERNAME: username,
|
|
@@ -238,8 +259,22 @@ async function computeSecretHashAsync(username, clientId, clientSecret) {
|
|
|
238
259
|
// src/validation.ts
|
|
239
260
|
var validateMetric2 = validateMetric;
|
|
240
261
|
var filterValidMetrics2 = filterValidMetrics;
|
|
262
|
+
var getMetricValidationResult2 = getMetricValidationResult;
|
|
263
|
+
|
|
264
|
+
// src/types.ts
|
|
265
|
+
var MetricValidationError = class extends Error {
|
|
266
|
+
constructor(message, dropped) {
|
|
267
|
+
super(message);
|
|
268
|
+
this.code = "METRIC_VALIDATION_FAILED";
|
|
269
|
+
this.name = "MetricValidationError";
|
|
270
|
+
this.dropped = dropped;
|
|
271
|
+
}
|
|
272
|
+
};
|
|
241
273
|
|
|
242
274
|
// src/data-client.ts
|
|
275
|
+
function createSubscriptionError(message, code, cause) {
|
|
276
|
+
return { message, code, cause };
|
|
277
|
+
}
|
|
243
278
|
var DataClient = class {
|
|
244
279
|
constructor(config) {
|
|
245
280
|
this.credentials = null;
|
|
@@ -267,7 +302,7 @@ var DataClient = class {
|
|
|
267
302
|
}
|
|
268
303
|
/**
|
|
269
304
|
* Ingest metric data points into the Dataworks Data Engine.
|
|
270
|
-
* Validates each metric before sending — invalid metrics are
|
|
305
|
+
* Validates each metric before sending — invalid metrics are dropped with warnings.
|
|
271
306
|
*
|
|
272
307
|
* @param metrics - Array of metric data points
|
|
273
308
|
* @param eventId - Event identifier
|
|
@@ -276,12 +311,53 @@ var DataClient = class {
|
|
|
276
311
|
* @see https://data-sdk-docs.dataworks.live/ingesting-data
|
|
277
312
|
*/
|
|
278
313
|
async ingest(metrics, eventId, datasetDatasourceId) {
|
|
279
|
-
this.
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
314
|
+
await this.ingestWithResult(metrics, eventId, datasetDatasourceId);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Ingest metrics with structured validation diagnostics.
|
|
318
|
+
*
|
|
319
|
+
* By default (`validationMode: "best-effort"`), invalid metrics are dropped and
|
|
320
|
+
* valid metrics continue. In strict mode, invalid metrics cause a
|
|
321
|
+
* MetricValidationError before any network request is sent.
|
|
322
|
+
*
|
|
323
|
+
* @returns IngestResult with accepted/dropped counts and dropped reasons.
|
|
324
|
+
*/
|
|
325
|
+
async ingestWithResult(metrics, eventId, datasetDatasourceId, options = {}) {
|
|
326
|
+
this.requireIngestAuth();
|
|
327
|
+
const validationMode = options.validationMode ?? "best-effort";
|
|
328
|
+
const validation = getMetricValidationResult2(metrics);
|
|
329
|
+
const valid = validation.valid;
|
|
330
|
+
const dropped = validation.dropped.map((item) => ({
|
|
331
|
+
index: item.index,
|
|
332
|
+
reason: item.reason,
|
|
333
|
+
metric: item.metric
|
|
334
|
+
}));
|
|
335
|
+
dropped.forEach((item) => {
|
|
336
|
+
options.onDroppedMetric?.(item);
|
|
337
|
+
console.warn(
|
|
338
|
+
`[@dataworks-technology/data] Dropping invalid metric [${String(item.metric.metric)}=${String(item.metric.value)}]: ${item.reason}`
|
|
339
|
+
);
|
|
340
|
+
});
|
|
341
|
+
if (validationMode === "strict" && dropped.length > 0) {
|
|
342
|
+
throw new MetricValidationError(
|
|
343
|
+
"[@dataworks-technology/data] validation failed: one or more metrics are invalid",
|
|
344
|
+
dropped
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
if (valid.length === 0) {
|
|
348
|
+
if (options.requireAtLeastOneValidMetric) {
|
|
349
|
+
throw new MetricValidationError(
|
|
350
|
+
"[@dataworks-technology/data] validation failed: no valid metrics to ingest",
|
|
351
|
+
dropped
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
acceptedCount: 0,
|
|
356
|
+
droppedCount: dropped.length,
|
|
357
|
+
dropped,
|
|
358
|
+
requestSent: false
|
|
359
|
+
};
|
|
360
|
+
}
|
|
285
361
|
const payload = {
|
|
286
362
|
eventId,
|
|
287
363
|
datasetDatasourceId,
|
|
@@ -303,6 +379,12 @@ var DataClient = class {
|
|
|
303
379
|
`[@dataworks-technology/data] ingest failed: ${resp.status} \u2014 ${body}`
|
|
304
380
|
);
|
|
305
381
|
}
|
|
382
|
+
return {
|
|
383
|
+
acceptedCount: valid.length,
|
|
384
|
+
droppedCount: dropped.length,
|
|
385
|
+
dropped,
|
|
386
|
+
requestSent: true
|
|
387
|
+
};
|
|
306
388
|
}
|
|
307
389
|
/**
|
|
308
390
|
* Report an error to the Dataworks Data Engine.
|
|
@@ -312,7 +394,7 @@ var DataClient = class {
|
|
|
312
394
|
* @see https://data-sdk-docs.dataworks.live/error-reporting
|
|
313
395
|
*/
|
|
314
396
|
async reportError(error) {
|
|
315
|
-
this.
|
|
397
|
+
this.requireIngestAuth();
|
|
316
398
|
const resp = await this.fetchWithAutoRefresh(
|
|
317
399
|
(accessToken) => fetch(this.config.errorUrl, {
|
|
318
400
|
method: "POST",
|
|
@@ -351,7 +433,10 @@ var DataClient = class {
|
|
|
351
433
|
* @see https://data-sdk-docs.dataworks.live/real-time-subscriptions
|
|
352
434
|
*/
|
|
353
435
|
subscribe(channel, onEvent, onError) {
|
|
354
|
-
this.
|
|
436
|
+
const apiKey = this.config.apiKey?.trim();
|
|
437
|
+
if (!this.credentials && !apiKey) {
|
|
438
|
+
this.requireAuth();
|
|
439
|
+
}
|
|
355
440
|
if (typeof WebSocket === "undefined") {
|
|
356
441
|
throw new Error(
|
|
357
442
|
"[@dataworks-technology/data] WebSocket is not available. Use Node >= 22, Bun, or a browser environment. For older Node versions, install a WebSocket polyfill (e.g. ws) and assign it to globalThis.WebSocket."
|
|
@@ -365,20 +450,32 @@ var DataClient = class {
|
|
|
365
450
|
const channelPath = channel.startsWith("/") ? channel : `/${channel}`;
|
|
366
451
|
return createAutoRefreshingSubscription({
|
|
367
452
|
refreshAuth: async () => {
|
|
368
|
-
|
|
453
|
+
if (this.credentials) {
|
|
454
|
+
await this.refreshSession();
|
|
455
|
+
}
|
|
369
456
|
},
|
|
370
457
|
onReconnectError: (error) => {
|
|
371
|
-
onError?.(
|
|
458
|
+
onError?.(
|
|
459
|
+
createSubscriptionError(error.message, "RECONNECT_FAILED", error)
|
|
460
|
+
);
|
|
372
461
|
},
|
|
373
462
|
connect: ({ onUnexpectedClose }) => {
|
|
374
463
|
const url = new URL(this.config.realtimeUrl);
|
|
375
464
|
url.pathname = "/event/realtime";
|
|
376
465
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
466
|
+
if (url.host.includes(".appsync-api.")) {
|
|
467
|
+
url.host = url.host.replace(
|
|
468
|
+
".appsync-api.",
|
|
469
|
+
".appsync-realtime-api."
|
|
470
|
+
);
|
|
471
|
+
}
|
|
377
472
|
const host = new URL(this.config.realtimeUrl).host;
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
|
|
473
|
+
const resolvedAuth = resolveEventsAuth({
|
|
474
|
+
userToken: this.credentials?.accessToken,
|
|
475
|
+
apiKey: this.config.apiKey?.trim()
|
|
381
476
|
});
|
|
477
|
+
const realtimeAuthHeader = buildEventsAuthHeader(resolvedAuth, host);
|
|
478
|
+
const authPayload = JSON.stringify(realtimeAuthHeader);
|
|
382
479
|
const authHeader = toBase64Url(authPayload);
|
|
383
480
|
const ws = new WebSocket(url.toString(), [
|
|
384
481
|
"aws-appsync-event-ws",
|
|
@@ -396,8 +493,9 @@ var DataClient = class {
|
|
|
396
493
|
});
|
|
397
494
|
ws.addEventListener("error", () => {
|
|
398
495
|
onError?.(
|
|
399
|
-
|
|
400
|
-
"[@dataworks-technology/data] WebSocket connection error"
|
|
496
|
+
createSubscriptionError(
|
|
497
|
+
"[@dataworks-technology/data] WebSocket connection error",
|
|
498
|
+
"CONNECTION_ERROR"
|
|
401
499
|
)
|
|
402
500
|
);
|
|
403
501
|
});
|
|
@@ -407,8 +505,9 @@ var DataClient = class {
|
|
|
407
505
|
msg = JSON.parse(String(event.data));
|
|
408
506
|
} catch {
|
|
409
507
|
onError?.(
|
|
410
|
-
|
|
411
|
-
"[@dataworks-technology/data] Received malformed message from AppSync"
|
|
508
|
+
createSubscriptionError(
|
|
509
|
+
"[@dataworks-technology/data] Received malformed message from AppSync",
|
|
510
|
+
"PARSE_ERROR"
|
|
412
511
|
)
|
|
413
512
|
);
|
|
414
513
|
return;
|
|
@@ -419,10 +518,7 @@ var DataClient = class {
|
|
|
419
518
|
type: "subscribe",
|
|
420
519
|
id: crypto.randomUUID(),
|
|
421
520
|
channel: channelPath,
|
|
422
|
-
authorization:
|
|
423
|
-
Authorization: this.credentials.accessToken,
|
|
424
|
-
host
|
|
425
|
-
}
|
|
521
|
+
authorization: realtimeAuthHeader
|
|
426
522
|
})
|
|
427
523
|
);
|
|
428
524
|
} else if (msg.type === "data") {
|
|
@@ -432,8 +528,9 @@ var DataClient = class {
|
|
|
432
528
|
onEvent(JSON.parse(String(raw)));
|
|
433
529
|
} catch {
|
|
434
530
|
onError?.(
|
|
435
|
-
|
|
436
|
-
"[@dataworks-technology/data] Received malformed event payload from AppSync"
|
|
531
|
+
createSubscriptionError(
|
|
532
|
+
"[@dataworks-technology/data] Received malformed event payload from AppSync",
|
|
533
|
+
"PARSE_ERROR"
|
|
437
534
|
)
|
|
438
535
|
);
|
|
439
536
|
}
|
|
@@ -442,8 +539,9 @@ var DataClient = class {
|
|
|
442
539
|
const msgStr = JSON.stringify(msg);
|
|
443
540
|
if (msgStr.toLowerCase().includes("unauthor") && !unexpectedCloseHandled) {
|
|
444
541
|
onError?.(
|
|
445
|
-
|
|
446
|
-
"[@dataworks-technology/data] Unauthorized \u2014 session may have expired, attempting to reconnect"
|
|
542
|
+
createSubscriptionError(
|
|
543
|
+
"[@dataworks-technology/data] Unauthorized \u2014 session may have expired, attempting to reconnect",
|
|
544
|
+
"UNAUTHORIZED"
|
|
447
545
|
)
|
|
448
546
|
);
|
|
449
547
|
handleUnexpectedCloseOnce();
|
|
@@ -451,7 +549,10 @@ var DataClient = class {
|
|
|
451
549
|
const errors = msg.errors;
|
|
452
550
|
const errorMessage = msg.message ?? errors?.[0]?.message ?? errors?.[0]?.errorType ?? "AppSync subscription error";
|
|
453
551
|
onError?.(
|
|
454
|
-
|
|
552
|
+
createSubscriptionError(
|
|
553
|
+
`[@dataworks-technology/data] ${errorMessage}`,
|
|
554
|
+
"SUBSCRIPTION_ERROR"
|
|
555
|
+
)
|
|
455
556
|
);
|
|
456
557
|
}
|
|
457
558
|
}
|
|
@@ -486,6 +587,16 @@ var DataClient = class {
|
|
|
486
587
|
);
|
|
487
588
|
}
|
|
488
589
|
}
|
|
590
|
+
/**
|
|
591
|
+
* @internal Guard for ingest-only operations (ingest, reportError). Throws the
|
|
592
|
+
* canonical SDK ingest auth error so the message is consistent with the lower-level
|
|
593
|
+
* `@dataworks/sdk/client` HttpClient guard.
|
|
594
|
+
*/
|
|
595
|
+
requireIngestAuth() {
|
|
596
|
+
if (!this.credentials) {
|
|
597
|
+
throw new Error(`[@dataworks-technology/data] ${INGEST_AUTH_ERROR}`);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
489
600
|
async fetchWithAutoRefresh(makeRequest) {
|
|
490
601
|
this.requireAuth();
|
|
491
602
|
let response = await makeRequest(this.credentials.accessToken);
|
|
@@ -536,6 +647,7 @@ DataClient.filterValidMetrics = filterValidMetrics2;
|
|
|
536
647
|
// Annotate the CommonJS export names for ESM import in node:
|
|
537
648
|
0 && (module.exports = {
|
|
538
649
|
DataClient,
|
|
650
|
+
MetricValidationError,
|
|
539
651
|
filterValidMetrics,
|
|
540
652
|
validateMetric
|
|
541
653
|
});
|