@dataworks-technology/data 0.1.3 → 0.1.5
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 +295 -26
- package/dist/index.cjs +273 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -4
- package/dist/index.d.ts +16 -4
- package/dist/index.js +273 -64
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@dataworks-technology/data)
|
|
4
4
|
[](./LICENSE)
|
|
5
5
|
[](https://bundlephobia.com/package/@dataworks-technology/data)
|
|
6
|
+
[](https://data-sdk-docs.dataworks.live)
|
|
6
7
|
|
|
7
8
|
Official SDK for the Dataworks Data Engine — authenticate, ingest live athlete metrics, subscribe to real-time data streams, and report errors.
|
|
8
9
|
|
|
@@ -51,7 +52,7 @@ bun add @dataworks-technology/data
|
|
|
51
52
|
```typescript
|
|
52
53
|
import { DataClient } from "@dataworks-technology/data";
|
|
53
54
|
|
|
54
|
-
const
|
|
55
|
+
const dataworks = new DataClient({
|
|
55
56
|
cognitoEndpoint: "https://cognito-idp.eu-west-1.amazonaws.com/",
|
|
56
57
|
clientId: "your-client-id",
|
|
57
58
|
ingestUrl: "https://your-ingest-endpoint.dataworks.live",
|
|
@@ -60,14 +61,14 @@ const client = new DataClient({
|
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
// Authenticate
|
|
63
|
-
await
|
|
64
|
+
await dataworks.login("username", "password");
|
|
64
65
|
|
|
65
66
|
// Ingest metrics
|
|
66
|
-
await
|
|
67
|
+
await dataworks.ingest(
|
|
67
68
|
[
|
|
68
69
|
{
|
|
69
70
|
athleteId: "athlete-1",
|
|
70
|
-
metric: "
|
|
71
|
+
metric: "heartrate_calculated",
|
|
71
72
|
value: 172,
|
|
72
73
|
timestamp: Math.floor(Date.now() / 1000),
|
|
73
74
|
},
|
|
@@ -84,7 +85,7 @@ await client.ingest(
|
|
|
84
85
|
Create a new client instance.
|
|
85
86
|
|
|
86
87
|
```typescript
|
|
87
|
-
const
|
|
88
|
+
const dataworks = new DataClient({
|
|
88
89
|
cognitoEndpoint: "https://cognito-idp.eu-west-1.amazonaws.com/",
|
|
89
90
|
clientId: "abc123",
|
|
90
91
|
ingestUrl: "https://ingest.dataworks.live",
|
|
@@ -93,37 +94,39 @@ const client = new DataClient({
|
|
|
93
94
|
});
|
|
94
95
|
```
|
|
95
96
|
|
|
96
|
-
### `
|
|
97
|
+
### `dataworks.login(username, password)`
|
|
97
98
|
|
|
98
99
|
Authenticate with Cognito. Must be called before any other operation.
|
|
99
100
|
|
|
100
101
|
```typescript
|
|
101
|
-
const result = await
|
|
102
|
+
const result = await dataworks.login("username", "password");
|
|
102
103
|
// result: { accessToken, idToken, refreshToken, tenant }
|
|
103
104
|
```
|
|
104
105
|
|
|
105
|
-
### `
|
|
106
|
+
### `dataworks.ingest(metrics, eventId, datasetDatasourceId)`
|
|
106
107
|
|
|
107
108
|
Send metric data points to the Data Engine. Invalid metrics are automatically filtered out.
|
|
108
109
|
|
|
109
110
|
```typescript
|
|
110
|
-
await
|
|
111
|
+
await dataworks.ingest(
|
|
111
112
|
[
|
|
112
|
-
{ athleteId: "1", metric: "
|
|
113
|
-
{ athleteId: "1", metric: "
|
|
113
|
+
{ athleteId: "1", metric: "heartrate_calculated", value: 172, timestamp: 1700000000 },
|
|
114
|
+
{ athleteId: "1", metric: "speed_calculated", value: 4.2, timestamp: 1700000000 },
|
|
114
115
|
],
|
|
115
116
|
"event-123",
|
|
116
117
|
"ds-456",
|
|
117
118
|
);
|
|
118
119
|
```
|
|
119
120
|
|
|
120
|
-
### `
|
|
121
|
+
### `dataworks.subscribe(channel, onEvent)`
|
|
121
122
|
|
|
122
123
|
Subscribe to real-time data events via WebSocket.
|
|
123
124
|
|
|
125
|
+
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
|
+
|
|
124
127
|
```typescript
|
|
125
|
-
const subscription =
|
|
126
|
-
"/
|
|
128
|
+
const subscription = dataworks.subscribe(
|
|
129
|
+
"dataworks/1/1/heartrate",
|
|
127
130
|
(event) => {
|
|
128
131
|
console.log("Received:", event);
|
|
129
132
|
},
|
|
@@ -133,36 +136,36 @@ const subscription = client.subscribe(
|
|
|
133
136
|
subscription.close();
|
|
134
137
|
```
|
|
135
138
|
|
|
136
|
-
### `
|
|
139
|
+
### `dataworks.reportError(error)`
|
|
137
140
|
|
|
138
141
|
Report an error to the Data Engine for monitoring and alerting.
|
|
139
142
|
|
|
140
143
|
```typescript
|
|
141
|
-
await
|
|
144
|
+
await dataworks.reportError({
|
|
142
145
|
datasetDatasourceId: "ds-456",
|
|
143
|
-
|
|
146
|
+
athleteId: "athlete-123",
|
|
144
147
|
clientId: 1,
|
|
145
148
|
errorTitle: "Sensor disconnected",
|
|
146
149
|
errorDescription: "BLE heart rate sensor lost connection at 00:42:15",
|
|
147
150
|
});
|
|
148
151
|
```
|
|
149
152
|
|
|
150
|
-
### `
|
|
153
|
+
### `dataworks.isAuthenticated`
|
|
151
154
|
|
|
152
155
|
Check if the client has valid credentials.
|
|
153
156
|
|
|
154
157
|
```typescript
|
|
155
|
-
if (
|
|
156
|
-
await
|
|
158
|
+
if (dataworks.isAuthenticated) {
|
|
159
|
+
await dataworks.ingest(metrics, eventId, dsId);
|
|
157
160
|
}
|
|
158
161
|
```
|
|
159
162
|
|
|
160
|
-
### `
|
|
163
|
+
### `dataworks.tenant`
|
|
161
164
|
|
|
162
165
|
Get the tenant from the authenticated session (or `null`).
|
|
163
166
|
|
|
164
167
|
```typescript
|
|
165
|
-
console.log(`Logged in as tenant: ${
|
|
168
|
+
console.log(`Logged in as tenant: ${dataworks.tenant}`);
|
|
166
169
|
```
|
|
167
170
|
|
|
168
171
|
## Validation Utilities
|
|
@@ -237,7 +240,7 @@ interface Metric {
|
|
|
237
240
|
|
|
238
241
|
interface ErrorReport {
|
|
239
242
|
datasetDatasourceId: string;
|
|
240
|
-
|
|
243
|
+
athleteId: string;
|
|
241
244
|
clientId: number;
|
|
242
245
|
errorTitle: string;
|
|
243
246
|
errorDescription: string;
|
|
@@ -257,13 +260,13 @@ All async methods throw on failure. Wrap calls in try/catch:
|
|
|
257
260
|
|
|
258
261
|
```typescript
|
|
259
262
|
try {
|
|
260
|
-
await
|
|
263
|
+
await dataworks.login("user", "pass");
|
|
261
264
|
} catch (err) {
|
|
262
265
|
// Authentication failed (invalid credentials, network error, etc.)
|
|
263
266
|
}
|
|
264
267
|
|
|
265
268
|
try {
|
|
266
|
-
await
|
|
269
|
+
await dataworks.ingest(metrics, eventId, dsId);
|
|
267
270
|
} catch (err) {
|
|
268
271
|
// Ingestion failed (401 expired token, 5xx server error, etc.)
|
|
269
272
|
}
|
|
@@ -278,11 +281,277 @@ Calling `ingest()`, `reportError()`, or `subscribe()` before `login()` throws im
|
|
|
278
281
|
- **TypeScript** ≥ 5.0 (optional — works with plain JavaScript too)
|
|
279
282
|
- **Browser** — compatible with any environment that has `fetch` and `WebSocket`
|
|
280
283
|
|
|
284
|
+
## Derived Metrics — Round-Trip Example
|
|
285
|
+
|
|
286
|
+
A core use case: subscribe to live metrics, apply your own calculations externally, and push **derived metrics** back into the Data Engine. This creates a feedback loop where the platform stores both raw and enriched data.
|
|
287
|
+
|
|
288
|
+
### Concept
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
Data Engine → subscribe("dataworks/{datasetDatasourceId}/{eventId}/heartrate") → Your App → calculate rolling avg → ingest("heartrate_rolling_avg_calculated") → Data Engine
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Any metric you ingest is treated the same as raw sensor data — it flows through the enrichment pipeline (avg/min/max/zones), gets stored, and is available via subscriptions and the GraphQL API.
|
|
295
|
+
|
|
296
|
+
### TypeScript Example
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
import { DataClient } from "@dataworks-technology/data";
|
|
300
|
+
|
|
301
|
+
const dataworks = new DataClient({
|
|
302
|
+
cognitoEndpoint: "https://cognito-idp.eu-west-1.amazonaws.com/",
|
|
303
|
+
clientId: "your-client-id",
|
|
304
|
+
ingestUrl: "https://your-ingest-endpoint.dataworks.live",
|
|
305
|
+
errorUrl: "https://your-error-endpoint.dataworks.live",
|
|
306
|
+
realtimeUrl: "https://your-realtime-endpoint.dataworks.live",
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
await dataworks.login("developer", "password");
|
|
310
|
+
|
|
311
|
+
// 1. Subscribe to raw heart rate data
|
|
312
|
+
const buffer: number[] = [];
|
|
313
|
+
const datasetDatasourceId = "1";
|
|
314
|
+
const eventId = "1";
|
|
315
|
+
const heartrateChannel = `dataworks/${datasetDatasourceId}/${eventId}/heartrate`;
|
|
316
|
+
|
|
317
|
+
dataworks.subscribe(heartrateChannel, (event) => {
|
|
318
|
+
// No metric guard needed here: the channel already filters to heartrate.
|
|
319
|
+
|
|
320
|
+
// 2. Calculate a rolling 3-point average
|
|
321
|
+
buffer.push(event.value);
|
|
322
|
+
if (buffer.length > 3) buffer.shift();
|
|
323
|
+
const avg = buffer.reduce((a, b) => a + b, 0) / buffer.length;
|
|
324
|
+
|
|
325
|
+
// 3. Push the derived metric back into the engine
|
|
326
|
+
dataworks.ingest(
|
|
327
|
+
[
|
|
328
|
+
{
|
|
329
|
+
athleteId: event.athleteId,
|
|
330
|
+
metric: "heartrate_rolling_avg_calculated",
|
|
331
|
+
value: Math.round(avg * 10) / 10,
|
|
332
|
+
timestamp: event.timestamp,
|
|
333
|
+
},
|
|
334
|
+
],
|
|
335
|
+
event.eventId,
|
|
336
|
+
event.datasetDatasourceId,
|
|
337
|
+
);
|
|
338
|
+
});
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Python Example (Cross-Platform)
|
|
342
|
+
|
|
343
|
+
The same flow works from any language. A full working Python demo is included at `test/demo/round-trip.py` — it proves every SDK capability end-to-end:
|
|
344
|
+
|
|
345
|
+
| Phase | What it does | SDK equivalent |
|
|
346
|
+
|-------|-------------|----------------|
|
|
347
|
+
| 1. Authenticate | Cognito USER_PASSWORD_AUTH | `dataworks.login()` |
|
|
348
|
+
| 2. Subscribe | WebSocket → AppSync Events API | `dataworks.subscribe()` |
|
|
349
|
+
| 3. Receive | Catch events on the subscriber | `onEvent` callback |
|
|
350
|
+
| 4. Calculate | Write to CSV/Google Sheets, compute rolling avg + HR zones | Your business logic |
|
|
351
|
+
| 5. Re-ingest | POST enriched metrics back to the Data Engine | `dataworks.ingest()` |
|
|
352
|
+
| 6. Report Error | Send error through the error pipeline | `dataworks.reportError()` |
|
|
353
|
+
|
|
354
|
+
#### Run the demo
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
# Install Python dependencies
|
|
358
|
+
pip install websocket-client requests
|
|
359
|
+
|
|
360
|
+
# Run from the repo root (reads test.env for credentials)
|
|
361
|
+
python test/demo/round-trip.py
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### Output
|
|
365
|
+
|
|
366
|
+
```
|
|
367
|
+
PHASE 4: WRITE DATA + CALCULATE
|
|
368
|
+
Enriched data:
|
|
369
|
+
HR=130 → avg=130.0, zone=Zone 2 (Aerobic), delta=—
|
|
370
|
+
HR=140 → avg=135.0, zone=Zone 3 (Tempo), delta=+10
|
|
371
|
+
HR=150 → avg=140.0, zone=Zone 3 (Tempo), delta=+10
|
|
372
|
+
HR=160 → avg=150.0, zone=Zone 4 (Threshold), delta=+10
|
|
373
|
+
HR=170 → avg=160.0, zone=Zone 4 (Threshold), delta=+10
|
|
374
|
+
|
|
375
|
+
PHASE 5: RE-INGEST ENRICHED METRICS
|
|
376
|
+
→ heartrate_rolling_avg=130.0
|
|
377
|
+
→ heartrate_rolling_avg=135.0
|
|
378
|
+
→ heartrate_rolling_avg=140.0
|
|
379
|
+
→ heartrate_rolling_avg=150.0
|
|
380
|
+
→ heartrate_rolling_avg=160.0
|
|
381
|
+
✓ Ingested (200)
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
The raw `heartrate` values (130–170 bpm) are transformed into `heartrate_rolling_avg_calculated` derived metrics and pushed back into the platform. These derived metrics are then available to all consumers (Console, Visual, Moments triggers) just like any other metric.
|
|
385
|
+
|
|
386
|
+
#### Google Sheets (optional)
|
|
387
|
+
|
|
388
|
+
The demo can write to Google Sheets instead of CSV — formulas compute rolling averages, HR zone classification, and deltas in the spreadsheet before re-ingesting. See `test/demo/README.md` for setup.
|
|
389
|
+
|
|
390
|
+
### Ideas for Derived Metrics
|
|
391
|
+
|
|
392
|
+
| Derived metric | Calculation | Use case |
|
|
393
|
+
|---|---|---|
|
|
394
|
+
| `heartrate_rolling_avg_calculated` | 3-point moving average | Smooth noisy sensor data |
|
|
395
|
+
| `heartrate_zone` | Zone classification (1–5) | Training load analysis |
|
|
396
|
+
| `speed_efficiency` | Speed / heart rate ratio | Fatigue detection |
|
|
397
|
+
| `power_to_weight` | Power / athlete weight | Normalised performance |
|
|
398
|
+
| `pace_delta` | Current pace − target pace | Real-time coaching alerts |
|
|
399
|
+
| `fatigue_index` | Custom formula over time window | Trigger warnings via Moments engine |
|
|
400
|
+
|
|
281
401
|
## Documentation
|
|
282
402
|
|
|
283
403
|
Full documentation with guides, examples, and detailed API reference:
|
|
284
404
|
|
|
285
|
-
**[https://data-docs.dataworks.live](https://data-docs.dataworks.live)**
|
|
405
|
+
**[https://data-sdk-docs.dataworks.live](https://data-sdk-docs.dataworks.live)**
|
|
406
|
+
|
|
407
|
+
## Development
|
|
408
|
+
|
|
409
|
+
> Internal contributors only — this section covers building, testing, and publishing the package.
|
|
410
|
+
|
|
411
|
+
This package publishes to **public npm** (`registry.npmjs.org`), not to the internal CodeArtifact registry used by `@dataworks/sdk`. The `packages/sdk/.npmrc` and `publishConfig` in `package.json` enforce this.
|
|
412
|
+
|
|
413
|
+
### Build
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
bun run build # tsup → dist/ (ESM + CJS + DTS)
|
|
417
|
+
bun run dev # tsup --watch (rebuild on save)
|
|
418
|
+
bun run test # vitest unit tests (mocked — no infra needed)
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Local Development
|
|
422
|
+
|
|
423
|
+
To test SDK changes locally before publishing:
|
|
424
|
+
|
|
425
|
+
**Option A — `npm pack` (recommended, simulates real install):**
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
# In packages/sdk/
|
|
429
|
+
bun run build
|
|
430
|
+
npm pack # creates dataworks-technology-data-0.1.4.tgz
|
|
431
|
+
|
|
432
|
+
# In your consumer project (e.g. test/demo/)
|
|
433
|
+
npm install ../../packages/sdk/dataworks-technology-data-0.1.4.tgz
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
**Option B — `bun link` (faster iteration):**
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
# In packages/sdk/
|
|
440
|
+
bun run build
|
|
441
|
+
bun link
|
|
442
|
+
|
|
443
|
+
# In your consumer project
|
|
444
|
+
bun link @dataworks-technology/data
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
**Option C — watch mode + link (live reload):**
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
# Terminal 1: packages/sdk/
|
|
451
|
+
bun run dev # rebuilds dist/ on every save
|
|
452
|
+
|
|
453
|
+
# Terminal 2: consumer project
|
|
454
|
+
bun link @dataworks-technology/data
|
|
455
|
+
npx tsx demo.ts # picks up latest build automatically
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
> **Tip:** After local testing, remember to `bun unlink` or reinstall from npm before committing.
|
|
459
|
+
|
|
460
|
+
### Publish
|
|
461
|
+
|
|
462
|
+
Login to npm first (one-time):
|
|
463
|
+
```bash
|
|
464
|
+
npm login --registry https://registry.npmjs.org/
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
Then from `packages/sdk/`:
|
|
468
|
+
```bash
|
|
469
|
+
bun run publish:patch # bump patch + publish
|
|
470
|
+
bun run publish:minor # bump minor + publish
|
|
471
|
+
bun run publish:major # bump major + publish
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### E2E Tests
|
|
475
|
+
|
|
476
|
+
The e2e test suite (`test/e2e-public-sdk.test.ts`) validates the full external developer flow against deployed infrastructure. It runs against live AWS services and proves the public SDK works end-to-end across all three stacks (Shared, Data, SDK).
|
|
477
|
+
|
|
478
|
+
#### Prerequisites
|
|
479
|
+
|
|
480
|
+
Deploy all three stacks first — `make deploy` generates `test.env` with the required env vars:
|
|
481
|
+
|
|
482
|
+
| Env var | Source | Purpose |
|
|
483
|
+
|---|---|---|
|
|
484
|
+
| `FRONTEND_CLIENT_ID` | Shared stack → Cognito | App client for USER_PASSWORD_AUTH |
|
|
485
|
+
| `API_URL` | Data stack → API Gateway | Metric ingestion endpoint |
|
|
486
|
+
| `ERROR_URL` | Data stack → API Gateway | Error reporting endpoint |
|
|
487
|
+
| `REALTIME_URL` | Data stack → AppSync Events API | WebSocket subscription endpoint |
|
|
488
|
+
| `COGNITO_BASE_DOMAIN` | Shared stack → Cognito | IDP endpoint for auth |
|
|
489
|
+
| `DEVELOPER_USERNAME` | Shared stack → Cognito | Test user in the `developer` group |
|
|
490
|
+
| `DEVELOPER_PASSWORD` | Shared stack → Cognito | Test user password |
|
|
491
|
+
|
|
492
|
+
#### Run
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
bun x vitest run test/e2e-public-sdk.test.ts
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
#### What each test proves
|
|
499
|
+
|
|
500
|
+
| # | Area | Test | What it validates | How to verify manually |
|
|
501
|
+
|---|---|---|---|---|
|
|
502
|
+
| 1 | **Login** | `should authenticate testdeveloper` | USER_PASSWORD_AUTH works with frontend client | AWS Console → Cognito → User Pool → Users → `testdeveloper` exists in `developer` group |
|
|
503
|
+
| 2 | **Login** | `should extract tenant from JWT` | `custom:tenant` claim is present in ID token | Decode the JWT at [jwt.io](https://jwt.io) — look for `custom:tenant` |
|
|
504
|
+
| 3 | **Login** | `should include resource server scopes` | Pre-token Lambda injects `dataworks.live/read` and `/write` | AWS Console → Cognito → User Pool → Lambda triggers → Pre token generation V2 is set |
|
|
505
|
+
| 4 | **Login** | `should reject invalid credentials` | Bad password returns error, not a token | Try `dataworks.login("testdeveloper", "wrong")` — should throw |
|
|
506
|
+
| 5 | **Ingest** | `should ingest valid metrics` | JWT passes API Gateway authoriser, Lambda processes payload | AWS Console → CloudWatch → Log group for the ingest Lambda — look for the metric |
|
|
507
|
+
| 6 | **Ingest** | `should filter invalid metrics` | Client-side validation drops bad metrics before sending | The `stderr` output shows `Dropping invalid metric` — local validation, no server call for bad data |
|
|
508
|
+
| 7 | **Ingest** | `should throw when not authenticated` | `ingest()` before `login()` throws immediately | Client-side guard — no network call made |
|
|
509
|
+
| 8 | **Error** | `should reach error endpoint` | Auth + API Gateway routing work (500 = Lambda ran, FK failed) | AWS Console → CloudWatch → Log group for error processor Lambda |
|
|
510
|
+
| 9 | **Error** | `should throw when not authenticated` | `reportError()` before `login()` throws immediately | Client-side guard |
|
|
511
|
+
| 10 | **Subscribe** | `should throw when not authenticated` | `subscribe()` before `login()` throws immediately | Client-side guard |
|
|
512
|
+
| 11 | **Subscribe** | `should create a subscription` | **Skipped in Node.js** (no `WebSocket` global) — see below | Use the Python verification script |
|
|
513
|
+
| 12–14 | **Validation** | `validateMetric` / `filterValidMetrics` | Static validation utilities work correctly | Pure functions — no infra dependency |
|
|
514
|
+
|
|
515
|
+
#### Verifying WebSocket subscribe (test 11)
|
|
516
|
+
|
|
517
|
+
The subscribe test is skipped in the Node.js Vitest environment because `globalThis.WebSocket` is not available. To prove subscribe works end-to-end, use the standalone Python script:
|
|
518
|
+
|
|
519
|
+
```bash
|
|
520
|
+
pip install websocket-client requests
|
|
521
|
+
python test/verify-subscribe.py
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
This script:
|
|
525
|
+
1. Authenticates via Cognito USER_PASSWORD_AUTH (same as the SDK)
|
|
526
|
+
2. Opens a WebSocket to the AppSync Events API with base64URL-encoded JWT auth subprotocols
|
|
527
|
+
3. Sends `connection_init` and receives `connection_ack` from AppSync
|
|
528
|
+
4. Sends a `subscribe` message and receives `subscribe_success`
|
|
529
|
+
5. Closes cleanly
|
|
530
|
+
|
|
531
|
+
Expected output:
|
|
532
|
+
```
|
|
533
|
+
Loading config from test.env
|
|
534
|
+
|
|
535
|
+
1. Authenticating as 'testdeveloper'...
|
|
536
|
+
✓ Login successful
|
|
537
|
+
Scopes: aws.cognito.signin.user.admin https://dataworks.live/write https://dataworks.live/read
|
|
538
|
+
Tenant: 2x9AOzBvDBgllLB0CXcCrPjK03C
|
|
539
|
+
|
|
540
|
+
2. Connecting to wss://event-api-chris-dev.dataworks.live/event/realtime...
|
|
541
|
+
Protocol: aws-appsync-event-ws (manual)
|
|
542
|
+
Received: connection_ack
|
|
543
|
+
✓ WebSocket connection established
|
|
544
|
+
|
|
545
|
+
3. Subscribing to channel '/dataworks/e2e-verify'...
|
|
546
|
+
Received: subscribe_success
|
|
547
|
+
✓ Subscribed to /dataworks/e2e-verify
|
|
548
|
+
|
|
549
|
+
4. WebSocket closed cleanly
|
|
550
|
+
|
|
551
|
+
============================================================
|
|
552
|
+
ALL CHECKS PASSED — subscribe flow works end-to-end
|
|
553
|
+
============================================================
|
|
554
|
+
```
|
|
286
555
|
|
|
287
556
|
## License
|
|
288
557
|
|