@nebulr-group/bridge-auth-core 0.4.0-beta.0 → 0.4.0-beta.10
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/auth-service.d.ts +11 -0
- package/dist/auth-service.d.ts.map +1 -1
- package/dist/auth-service.js +20 -0
- package/dist/auth-service.js.map +1 -1
- package/dist/backend/index.d.ts +12 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +12 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/jwks-service.d.ts +119 -0
- package/dist/backend/jwks-service.d.ts.map +1 -0
- package/dist/backend/jwks-service.js +216 -0
- package/dist/backend/jwks-service.js.map +1 -0
- package/dist/backend/types.d.ts +119 -0
- package/dist/backend/types.d.ts.map +1 -0
- package/dist/backend/types.js +37 -0
- package/dist/backend/types.js.map +1 -0
- package/dist/billing/quota-store.d.ts +20 -0
- package/dist/billing/quota-store.d.ts.map +1 -1
- package/dist/billing/quota-store.js +15 -0
- package/dist/billing/quota-store.js.map +1 -1
- package/dist/bridge-auth.d.ts +93 -2
- package/dist/bridge-auth.d.ts.map +1 -1
- package/dist/bridge-auth.js +178 -5
- package/dist/bridge-auth.js.map +1 -1
- package/dist/direct-auth.d.ts +5 -1
- package/dist/direct-auth.d.ts.map +1 -1
- package/dist/direct-auth.js +29 -19
- package/dist/direct-auth.js.map +1 -1
- package/dist/flags/realtime.d.ts +35 -0
- package/dist/flags/realtime.d.ts.map +1 -1
- package/dist/flags/realtime.js +285 -10
- package/dist/flags/realtime.js.map +1 -1
- package/dist/http.d.ts +4 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +33 -11
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/management-types.d.ts +17 -0
- package/dist/management-types.d.ts.map +1 -1
- package/dist/sso-popup.d.ts.map +1 -1
- package/dist/sso-popup.js +11 -4
- package/dist/sso-popup.js.map +1 -1
- package/dist/types.d.ts +52 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/usage/index.d.ts +1 -1
- package/dist/usage/index.d.ts.map +1 -1
- package/dist/usage/index.js +1 -1
- package/dist/usage/index.js.map +1 -1
- package/dist/usage/storage/index.d.ts +0 -1
- package/dist/usage/storage/index.d.ts.map +1 -1
- package/dist/usage/storage/index.js +44 -9
- package/dist/usage/storage/index.js.map +1 -1
- package/dist/usage/storage/node-fs-storage.d.ts.map +1 -1
- package/dist/usage/storage/node-fs-storage.js +22 -7
- package/dist/usage/storage/node-fs-storage.js.map +1 -1
- package/dist/usage/usage-reporter.d.ts +1 -0
- package/dist/usage/usage-reporter.d.ts.map +1 -1
- package/dist/usage/usage-reporter.js +24 -3
- package/dist/usage/usage-reporter.js.map +1 -1
- package/package.json +16 -4
package/dist/direct-auth.js
CHANGED
|
@@ -7,49 +7,49 @@ export class DirectAuthService {
|
|
|
7
7
|
this.logger = logger;
|
|
8
8
|
}
|
|
9
9
|
async getCredentialsConfig(email) {
|
|
10
|
-
const url = `${this.config.authBaseUrl}/
|
|
10
|
+
const url = `${this.config.authBaseUrl}/credentialsConfig`;
|
|
11
11
|
return httpFetch(url, {
|
|
12
12
|
method: 'POST',
|
|
13
13
|
body: { username: email, mode: 'sdk', appId: this.config.appId },
|
|
14
14
|
}, this.logger);
|
|
15
15
|
}
|
|
16
16
|
async authenticate(email, password) {
|
|
17
|
-
const url = `${this.config.authBaseUrl}/
|
|
17
|
+
const url = `${this.config.authBaseUrl}/authenticate`;
|
|
18
18
|
return httpFetch(url, {
|
|
19
19
|
method: 'POST',
|
|
20
20
|
body: { username: email, password, mode: 'sdk', appId: this.config.appId },
|
|
21
21
|
}, this.logger);
|
|
22
22
|
}
|
|
23
23
|
async commitMfaCode(mfaCode, session) {
|
|
24
|
-
const url = `${this.config.authBaseUrl}/
|
|
24
|
+
const url = `${this.config.authBaseUrl}/commitMfaCode`;
|
|
25
25
|
return httpFetch(url, {
|
|
26
26
|
method: 'POST',
|
|
27
27
|
body: { mfaCode, session, mode: 'sdk', appId: this.config.appId },
|
|
28
28
|
}, this.logger);
|
|
29
29
|
}
|
|
30
30
|
async resendMfaCode(session) {
|
|
31
|
-
const url = `${this.config.authBaseUrl}/
|
|
31
|
+
const url = `${this.config.authBaseUrl}/resendMfaCode`;
|
|
32
32
|
return httpFetch(url, {
|
|
33
33
|
method: 'POST',
|
|
34
34
|
body: { session, mode: 'sdk', appId: this.config.appId },
|
|
35
35
|
}, this.logger);
|
|
36
36
|
}
|
|
37
37
|
async startMfaUserSetup(phoneNumber, session) {
|
|
38
|
-
const url = `${this.config.authBaseUrl}/
|
|
38
|
+
const url = `${this.config.authBaseUrl}/startMfaUserSetup`;
|
|
39
39
|
return httpFetch(url, {
|
|
40
40
|
method: 'POST',
|
|
41
41
|
body: { phoneNumber, session, mode: 'sdk', appId: this.config.appId },
|
|
42
42
|
}, this.logger);
|
|
43
43
|
}
|
|
44
44
|
async finishMfaUserSetup(mfaCode, session) {
|
|
45
|
-
const url = `${this.config.authBaseUrl}/
|
|
45
|
+
const url = `${this.config.authBaseUrl}/finishMfaUserSetup`;
|
|
46
46
|
return httpFetch(url, {
|
|
47
47
|
method: 'POST',
|
|
48
48
|
body: { mfaCode, session, mode: 'sdk', appId: this.config.appId },
|
|
49
49
|
}, this.logger);
|
|
50
50
|
}
|
|
51
51
|
async resetUserMfaSetup(backupCode, session) {
|
|
52
|
-
const url = `${this.config.authBaseUrl}/
|
|
52
|
+
const url = `${this.config.authBaseUrl}/resetUserMfaSetup`;
|
|
53
53
|
return httpFetch(url, {
|
|
54
54
|
method: 'POST',
|
|
55
55
|
body: { backupCode, session, mode: 'sdk', appId: this.config.appId },
|
|
@@ -94,23 +94,33 @@ export class DirectAuthService {
|
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
96
|
// --- Signup ---
|
|
97
|
-
async signup(email, firstName, lastName) {
|
|
98
|
-
const url = `${this.config.authBaseUrl}/
|
|
97
|
+
async signup(email, firstName, lastName, options) {
|
|
98
|
+
const url = `${this.config.authBaseUrl}/signup`;
|
|
99
99
|
return httpFetch(url, {
|
|
100
100
|
method: 'POST',
|
|
101
|
-
body: {
|
|
101
|
+
body: {
|
|
102
|
+
email,
|
|
103
|
+
firstName,
|
|
104
|
+
lastName,
|
|
105
|
+
appId: this.config.appId,
|
|
106
|
+
mode: 'sdk',
|
|
107
|
+
// TBP-36 — plan-specific signup links apply the plan at tenant creation.
|
|
108
|
+
...(options?.plan ? { plan: options.plan } : {}),
|
|
109
|
+
...(options?.currency ? { currency: options.currency } : {}),
|
|
110
|
+
...(options?.recurrenceInterval ? { recurrenceInterval: options.recurrenceInterval } : {}),
|
|
111
|
+
},
|
|
102
112
|
}, this.logger);
|
|
103
113
|
}
|
|
104
114
|
// --- Magic link ---
|
|
105
115
|
async sendMagicLink(email) {
|
|
106
|
-
const url = `${this.config.authBaseUrl}/
|
|
116
|
+
const url = `${this.config.authBaseUrl}/magic-link`;
|
|
107
117
|
return httpFetch(url, {
|
|
108
118
|
method: 'POST',
|
|
109
119
|
body: { username: email, mode: 'sdk', appId: this.config.appId },
|
|
110
120
|
}, this.logger);
|
|
111
121
|
}
|
|
112
122
|
async authenticateWithMagicLinkToken(token) {
|
|
113
|
-
const url = `${this.config.authBaseUrl}/
|
|
123
|
+
const url = `${this.config.authBaseUrl}/magic-link/authenticate`;
|
|
114
124
|
return httpFetch(url, {
|
|
115
125
|
method: 'POST',
|
|
116
126
|
body: { token },
|
|
@@ -118,7 +128,7 @@ export class DirectAuthService {
|
|
|
118
128
|
}
|
|
119
129
|
// --- Password reset ---
|
|
120
130
|
async sendResetPasswordLink(email) {
|
|
121
|
-
const url = `${this.config.apiBaseUrl}/auth/
|
|
131
|
+
const url = `${this.config.apiBaseUrl}/auth/password`;
|
|
122
132
|
await httpFetch(url, {
|
|
123
133
|
method: 'POST',
|
|
124
134
|
body: { username: email },
|
|
@@ -126,7 +136,7 @@ export class DirectAuthService {
|
|
|
126
136
|
}, this.logger);
|
|
127
137
|
}
|
|
128
138
|
async updatePassword(token, password) {
|
|
129
|
-
const url = `${this.config.apiBaseUrl}/auth/
|
|
139
|
+
const url = `${this.config.apiBaseUrl}/auth/password`;
|
|
130
140
|
await httpFetch(url, {
|
|
131
141
|
method: 'PUT',
|
|
132
142
|
body: { token, password },
|
|
@@ -135,14 +145,14 @@ export class DirectAuthService {
|
|
|
135
145
|
}
|
|
136
146
|
// --- Passkeys: authentication ---
|
|
137
147
|
async passkeysAuthenticationOptions() {
|
|
138
|
-
const url = `${this.config.authBaseUrl}/
|
|
148
|
+
const url = `${this.config.authBaseUrl}/passkeys/authentication-options`;
|
|
139
149
|
return httpFetch(url, {
|
|
140
150
|
method: 'GET',
|
|
141
151
|
headers: { 'x-app-id': this.config.appId },
|
|
142
152
|
}, this.logger);
|
|
143
153
|
}
|
|
144
154
|
async passkeysAuthenticate(response) {
|
|
145
|
-
const url = `${this.config.authBaseUrl}/
|
|
155
|
+
const url = `${this.config.authBaseUrl}/passkeys/verify-authentication`;
|
|
146
156
|
return httpFetch(url, {
|
|
147
157
|
method: 'POST',
|
|
148
158
|
body: { ...response, mode: 'sdk', appId: this.config.appId },
|
|
@@ -150,21 +160,21 @@ export class DirectAuthService {
|
|
|
150
160
|
}
|
|
151
161
|
// --- Passkeys: registration ---
|
|
152
162
|
async requestPasskeySetupLink(email) {
|
|
153
|
-
const url = `${this.config.authBaseUrl}/
|
|
163
|
+
const url = `${this.config.authBaseUrl}/passkeys/request-setup-link`;
|
|
154
164
|
return httpFetch(url, {
|
|
155
165
|
method: 'POST',
|
|
156
166
|
body: { username: email, appId: this.config.appId },
|
|
157
167
|
}, this.logger);
|
|
158
168
|
}
|
|
159
169
|
async getPasskeyRegistrationOptions(token) {
|
|
160
|
-
const url = `${this.config.authBaseUrl}/
|
|
170
|
+
const url = `${this.config.authBaseUrl}/passkeys/registration-options?passkeySetupToken=${encodeURIComponent(token)}`;
|
|
161
171
|
return httpFetch(url, {
|
|
162
172
|
method: 'GET',
|
|
163
173
|
headers: { 'x-app-id': this.config.appId },
|
|
164
174
|
}, this.logger);
|
|
165
175
|
}
|
|
166
176
|
async verifyPasskeyRegistration(credential, token) {
|
|
167
|
-
const url = `${this.config.authBaseUrl}/
|
|
177
|
+
const url = `${this.config.authBaseUrl}/passkeys/verify-registration?passkeySetupToken=${encodeURIComponent(token)}`;
|
|
168
178
|
return httpFetch(url, {
|
|
169
179
|
method: 'POST',
|
|
170
180
|
body: { ...credential, appId: this.config.appId },
|
package/dist/direct-auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"direct-auth.js","sourceRoot":"","sources":["../src/direct-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAyBtC,MAAM,OAAO,iBAAiB;IAET;IACA;IAFnB,YACmB,MAAsB,EACtB,MAAc;QADd,WAAM,GAAN,MAAM,CAAgB;QACtB,WAAM,GAAN,MAAM,CAAQ;IAC9B,CAAC;IAEJ,KAAK,CAAC,oBAAoB,CAAC,KAAa;QACtC,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,
|
|
1
|
+
{"version":3,"file":"direct-auth.js","sourceRoot":"","sources":["../src/direct-auth.ts"],"names":[],"mappings":"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"}
|
package/dist/flags/realtime.d.ts
CHANGED
|
@@ -124,6 +124,16 @@ export interface QuotaUpdatedMessage {
|
|
|
124
124
|
* `'metered'` in that case.
|
|
125
125
|
*/
|
|
126
126
|
policy?: 'hard' | 'metered';
|
|
127
|
+
/**
|
|
128
|
+
* TBP-275 — metered overage context. Optional (absent for hard quotas and
|
|
129
|
+
* older servers). `unitAmount` + `currency` describe the per-unit price;
|
|
130
|
+
* `overageEstimate` is the server-computed estimated cost this period;
|
|
131
|
+
* `overcap` is true once usage passed the included allotment.
|
|
132
|
+
*/
|
|
133
|
+
unitAmount?: number;
|
|
134
|
+
currency?: string;
|
|
135
|
+
overageEstimate?: number;
|
|
136
|
+
overcap?: boolean;
|
|
127
137
|
}
|
|
128
138
|
/**
|
|
129
139
|
* Billing 2.0 US-12 — wholesale entitlement snapshot push. The bridge-api
|
|
@@ -322,6 +332,31 @@ export declare class RealtimeClient {
|
|
|
322
332
|
private fetchServerConfig;
|
|
323
333
|
private authorize;
|
|
324
334
|
private openWebSocket;
|
|
335
|
+
/**
|
|
336
|
+
* TBP-148 — AppSync Events transport.
|
|
337
|
+
*
|
|
338
|
+
* Wire protocol (AWS public spec for AppSync Events, distinct from the older
|
|
339
|
+
* AppSync GraphQL `graphql-ws` subscriptions):
|
|
340
|
+
* - WebSocket to `wss://<endpoint>/event/realtime` (path appended if the
|
|
341
|
+
* endpoint from /realtime/config doesn't already include it — stage
|
|
342
|
+
* CFN output is the bare host today; the spec test uses the full URL).
|
|
343
|
+
* - Subprotocols: `['aws-appsync-event-ws', 'header-<base64url-json>']`.
|
|
344
|
+
* The `header-…` token carries auth, since browsers can't set arbitrary
|
|
345
|
+
* HTTP headers on a WebSocket.
|
|
346
|
+
* - After open: `{type:'connection_init'}` → server replies
|
|
347
|
+
* `{type:'connection_ack', connectionTimeoutMs}` → then one
|
|
348
|
+
* `{type:'subscribe', id, channel, authorization}` per channel.
|
|
349
|
+
* - Data: `{type:'data', id, event:'<json-string>'}` — `event` is a string
|
|
350
|
+
* (matches `appsync-events.adapter.ts:90` JSON.stringify).
|
|
351
|
+
* - Keepalive: server sends `{type:'ka'}` (silently ignored).
|
|
352
|
+
* - Channel wire format: `<ns>/<id>` (colon-to-slash; mirrors
|
|
353
|
+
* `appsync-events.adapter.ts:87` and `appsync-authorizer.handler.ts:59`).
|
|
354
|
+
*
|
|
355
|
+
* Anonymous flow: `getAuthToken()` returns undefined → Authorization sent as
|
|
356
|
+
* empty string. The Lambda authorizer accepts that only for `app:<appId>`
|
|
357
|
+
* channels whose origin matches the app's allowedOrigins (demo path).
|
|
358
|
+
*/
|
|
359
|
+
private openAppSyncWebSocket;
|
|
325
360
|
private handleMessage;
|
|
326
361
|
private scheduleReconnect;
|
|
327
362
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../src/flags/realtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../src/flags/realtime.ts"],"names":[],"mappings":"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"}
|
package/dist/flags/realtime.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
// SDK realtime client (TBP-150).
|
|
2
2
|
//
|
|
3
3
|
// Auto-discovers the workspace's pub/sub protocol from `GET /realtime/config`
|
|
4
|
-
// (TBP-147), authorizes via `POST /realtime/authorize` (TBP-151
|
|
5
|
-
//
|
|
4
|
+
// (TBP-147), authorizes via `POST /realtime/authorize` (TBP-151 — Centrifugo
|
|
5
|
+
// path only; AppSync uses a Lambda authorizer server-side), and connects to
|
|
6
|
+
// receive live flag updates + per-user identity changes.
|
|
6
7
|
//
|
|
7
8
|
// Two protocols, one shape:
|
|
8
|
-
// - `centrifugo`: WebSocket to a Centrifugo server using a signed connect token
|
|
9
|
-
// - `appsync`:
|
|
9
|
+
// - `centrifugo`: WebSocket to a Centrifugo server using a signed connect token.
|
|
10
|
+
// - `appsync`: WebSocket to AWS AppSync Events (TBP-148). Client carries
|
|
11
|
+
// its Bridge JWT directly in the `header-…` subprotocol; the
|
|
12
|
+
// Lambda authorizer makes per-channel decisions server-side
|
|
13
|
+
// (no `/realtime/authorize` round-trip).
|
|
10
14
|
//
|
|
11
15
|
// `noop` server-side → realtime is disabled; the SDK falls back to periodic
|
|
12
16
|
// poll or simply doesn't get live updates.
|
|
@@ -226,14 +230,22 @@ export class RealtimeClient {
|
|
|
226
230
|
this.state = 'closed';
|
|
227
231
|
return;
|
|
228
232
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
233
|
+
const channels = this.channelsToSubscribe();
|
|
234
|
+
if (serverConfig.kind === 'appsync') {
|
|
235
|
+
// AppSync uses a Lambda authorizer for per-channel auth — no client-side
|
|
236
|
+
// /realtime/authorize round-trip. The Bridge JWT is carried in the
|
|
237
|
+
// subprotocol negotiation; the Lambda decides allow/deny per channel.
|
|
238
|
+
this.openAppSyncWebSocket(serverConfig.endpoint, channels);
|
|
232
239
|
return;
|
|
233
240
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
241
|
+
if (serverConfig.kind === 'centrifugo') {
|
|
242
|
+
const auth = await this.authorize(channels);
|
|
243
|
+
this.openWebSocket(serverConfig.endpoint, auth);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
// Unknown protocol — close cleanly so consumers don't get stuck in
|
|
247
|
+
// 'connecting'. New transports must be added explicitly here.
|
|
248
|
+
this.state = 'closed';
|
|
237
249
|
}
|
|
238
250
|
catch {
|
|
239
251
|
this.state = 'closed';
|
|
@@ -376,6 +388,168 @@ export class RealtimeClient {
|
|
|
376
388
|
// Let onclose handle reconnect — errors are noisy but not actionable.
|
|
377
389
|
};
|
|
378
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* TBP-148 — AppSync Events transport.
|
|
393
|
+
*
|
|
394
|
+
* Wire protocol (AWS public spec for AppSync Events, distinct from the older
|
|
395
|
+
* AppSync GraphQL `graphql-ws` subscriptions):
|
|
396
|
+
* - WebSocket to `wss://<endpoint>/event/realtime` (path appended if the
|
|
397
|
+
* endpoint from /realtime/config doesn't already include it — stage
|
|
398
|
+
* CFN output is the bare host today; the spec test uses the full URL).
|
|
399
|
+
* - Subprotocols: `['aws-appsync-event-ws', 'header-<base64url-json>']`.
|
|
400
|
+
* The `header-…` token carries auth, since browsers can't set arbitrary
|
|
401
|
+
* HTTP headers on a WebSocket.
|
|
402
|
+
* - After open: `{type:'connection_init'}` → server replies
|
|
403
|
+
* `{type:'connection_ack', connectionTimeoutMs}` → then one
|
|
404
|
+
* `{type:'subscribe', id, channel, authorization}` per channel.
|
|
405
|
+
* - Data: `{type:'data', id, event:'<json-string>'}` — `event` is a string
|
|
406
|
+
* (matches `appsync-events.adapter.ts:90` JSON.stringify).
|
|
407
|
+
* - Keepalive: server sends `{type:'ka'}` (silently ignored).
|
|
408
|
+
* - Channel wire format: `<ns>/<id>` (colon-to-slash; mirrors
|
|
409
|
+
* `appsync-events.adapter.ts:87` and `appsync-authorizer.handler.ts:59`).
|
|
410
|
+
*
|
|
411
|
+
* Anonymous flow: `getAuthToken()` returns undefined → Authorization sent as
|
|
412
|
+
* empty string. The Lambda authorizer accepts that only for `app:<appId>`
|
|
413
|
+
* channels whose origin matches the app's allowedOrigins (demo path).
|
|
414
|
+
*/
|
|
415
|
+
openAppSyncWebSocket(endpoint, channels) {
|
|
416
|
+
const { url, httpHost } = normalizeAppSyncEndpoint(endpoint);
|
|
417
|
+
// AWS spec: the auth header's `host` field refers to the HTTP endpoint
|
|
418
|
+
// even when the wss:// call is made against the realtime endpoint. The
|
|
419
|
+
// server-side validation uses this to verify the connection — sending
|
|
420
|
+
// the realtime host instead produces a silent close 1000 right after
|
|
421
|
+
// the WS upgrade succeeds.
|
|
422
|
+
const authHeader = buildAppSyncAuthHeader(this.cfg.getAuthToken?.(), httpHost);
|
|
423
|
+
const headerProtocol = `header-${base64urlEncode(JSON.stringify(authHeader))}`;
|
|
424
|
+
const ws = this.cfg.websocketFactory(url, [APPSYNC_WS_PROTOCOL, headerProtocol]);
|
|
425
|
+
this.ws = ws;
|
|
426
|
+
ws.onopen = () => {
|
|
427
|
+
if (this.ws !== ws)
|
|
428
|
+
return;
|
|
429
|
+
// `state` stays 'connecting' until connection_ack lands — premature
|
|
430
|
+
// transition would let the client miss server-side rejects (auth
|
|
431
|
+
// failure surfaces as a quick close right after open).
|
|
432
|
+
try {
|
|
433
|
+
ws.send(JSON.stringify({ type: 'connection_init' }));
|
|
434
|
+
}
|
|
435
|
+
catch {
|
|
436
|
+
// onclose will fire on a broken socket; no further work here.
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
ws.onmessage = (ev) => {
|
|
440
|
+
if (this.ws !== ws)
|
|
441
|
+
return;
|
|
442
|
+
let frame;
|
|
443
|
+
try {
|
|
444
|
+
frame = typeof ev.data === 'string' ? JSON.parse(ev.data) : ev.data;
|
|
445
|
+
}
|
|
446
|
+
catch {
|
|
447
|
+
return; // malformed — ignore
|
|
448
|
+
}
|
|
449
|
+
if (!frame || typeof frame !== 'object')
|
|
450
|
+
return;
|
|
451
|
+
const type = typeof frame.type === 'string' ? frame.type : '';
|
|
452
|
+
switch (type) {
|
|
453
|
+
case 'connection_ack': {
|
|
454
|
+
// Handshake complete — open the gate for app traffic.
|
|
455
|
+
this.state = 'open';
|
|
456
|
+
this.reconnectDelayMs = this.cfg.reconnectBaseMs;
|
|
457
|
+
for (const channel of channels) {
|
|
458
|
+
try {
|
|
459
|
+
ws.send(JSON.stringify({
|
|
460
|
+
type: 'subscribe',
|
|
461
|
+
id: appSyncSubscriptionId(),
|
|
462
|
+
channel: appSyncChannelToWire(channel),
|
|
463
|
+
authorization: authHeader,
|
|
464
|
+
}));
|
|
465
|
+
}
|
|
466
|
+
catch {
|
|
467
|
+
// ignore — onclose will pick up a broken socket.
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
try {
|
|
471
|
+
this.onOpenHook?.();
|
|
472
|
+
}
|
|
473
|
+
catch {
|
|
474
|
+
// hook errors must not break the connection.
|
|
475
|
+
}
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
case 'ka':
|
|
479
|
+
// Keepalive — server-initiated, no client response required.
|
|
480
|
+
break;
|
|
481
|
+
case 'data': {
|
|
482
|
+
// Per AWS spec, the `event` field is an **array of stringified JSON
|
|
483
|
+
// values** (publish accepts `events: [...]`; data delivers `event:
|
|
484
|
+
// [...]`). The backend currently publishes one entry per frame
|
|
485
|
+
// (`events: [JSON.stringify(payload)]`), but the wire shape is an
|
|
486
|
+
// array either way — iterate, decode each, dispatch independently.
|
|
487
|
+
const rawList = Array.isArray(frame.event)
|
|
488
|
+
? frame.event
|
|
489
|
+
: typeof frame.event === 'string'
|
|
490
|
+
? [frame.event]
|
|
491
|
+
: [];
|
|
492
|
+
for (const raw of rawList) {
|
|
493
|
+
if (typeof raw !== 'string')
|
|
494
|
+
continue;
|
|
495
|
+
let payload;
|
|
496
|
+
try {
|
|
497
|
+
payload = JSON.parse(raw);
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
if (payload &&
|
|
503
|
+
typeof payload === 'object' &&
|
|
504
|
+
typeof payload.kind === 'string') {
|
|
505
|
+
try {
|
|
506
|
+
this.handleMessage(payload);
|
|
507
|
+
}
|
|
508
|
+
catch {
|
|
509
|
+
// hook errors are isolated per-handler in handleMessage.
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
break;
|
|
514
|
+
}
|
|
515
|
+
case 'subscribe_success':
|
|
516
|
+
// Per-channel ack — no action required, server now streams data.
|
|
517
|
+
break;
|
|
518
|
+
case 'connection_error':
|
|
519
|
+
case 'subscribe_error':
|
|
520
|
+
case 'error':
|
|
521
|
+
// Server-side reject — close cleanly so onclose triggers reconnect.
|
|
522
|
+
// We intentionally don't surface the error message: the next
|
|
523
|
+
// connect's authorize will succeed or fail with the same signal.
|
|
524
|
+
try {
|
|
525
|
+
ws.close(1011, `appsync:${type}`);
|
|
526
|
+
}
|
|
527
|
+
catch {
|
|
528
|
+
// ignore
|
|
529
|
+
}
|
|
530
|
+
break;
|
|
531
|
+
default:
|
|
532
|
+
// Unknown frame type — ignore. Forward-compatible with future
|
|
533
|
+
// protocol additions (e.g. `keepalive`, `pong`, …).
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
ws.onclose = () => {
|
|
538
|
+
if (this.ws !== ws)
|
|
539
|
+
return;
|
|
540
|
+
this.state = 'closed';
|
|
541
|
+
try {
|
|
542
|
+
this.onCloseHook?.();
|
|
543
|
+
}
|
|
544
|
+
catch {
|
|
545
|
+
// hook errors must not block reconnect scheduling.
|
|
546
|
+
}
|
|
547
|
+
this.scheduleReconnect();
|
|
548
|
+
};
|
|
549
|
+
ws.onerror = () => {
|
|
550
|
+
// Let onclose handle reconnect — errors are noisy but not actionable.
|
|
551
|
+
};
|
|
552
|
+
}
|
|
379
553
|
handleMessage(msg) {
|
|
380
554
|
switch (msg.kind) {
|
|
381
555
|
case 'flag.updated':
|
|
@@ -501,4 +675,105 @@ function parseMessage(raw) {
|
|
|
501
675
|
return null;
|
|
502
676
|
return data;
|
|
503
677
|
}
|
|
678
|
+
// ── AppSync Events helpers (TBP-148) ─────────────────────────────────────────
|
|
679
|
+
/** Subprotocol identifier for AppSync Events realtime channels. */
|
|
680
|
+
const APPSYNC_WS_PROTOCOL = 'aws-appsync-event-ws';
|
|
681
|
+
/**
|
|
682
|
+
* Normalize the realtime endpoint to a full `wss://…/event/realtime` URL and
|
|
683
|
+
* compute the matching HTTP host (needed in the auth header — AppSync
|
|
684
|
+
* server-side validation uses the HTTP host, NOT the realtime host).
|
|
685
|
+
*
|
|
686
|
+
* Stage's CFN output currently surfaces a bare host (`<id>.appsync-realtime-api.<region>.amazonaws.com`),
|
|
687
|
+
* while the backend spec tests use the fully-qualified `wss://…/event/realtime`.
|
|
688
|
+
* Both must work — this normalizer accepts either.
|
|
689
|
+
*
|
|
690
|
+
* HTTP-host derivation: AWS uses two parallel domains for AppSync Events:
|
|
691
|
+
* wss://<id>.appsync-realtime-api.<region>.amazonaws.com/event/realtime
|
|
692
|
+
* https://<id>.appsync-api.<region>.amazonaws.com/event
|
|
693
|
+
* The HTTP host is the realtime host with `appsync-realtime-api` swapped for
|
|
694
|
+
* `appsync-api`. Custom domains skip the suffix entirely (host == http host).
|
|
695
|
+
*/
|
|
696
|
+
function normalizeAppSyncEndpoint(endpoint) {
|
|
697
|
+
let raw = endpoint.trim();
|
|
698
|
+
if (!raw.startsWith('ws://') && !raw.startsWith('wss://')) {
|
|
699
|
+
raw = `wss://${raw}`;
|
|
700
|
+
}
|
|
701
|
+
raw = raw.replace(/\/+$/, '');
|
|
702
|
+
if (!/\/event\/realtime$/.test(raw)) {
|
|
703
|
+
raw = `${raw}/event/realtime`;
|
|
704
|
+
}
|
|
705
|
+
let realtimeHost = '';
|
|
706
|
+
try {
|
|
707
|
+
realtimeHost = new URL(raw).host;
|
|
708
|
+
}
|
|
709
|
+
catch {
|
|
710
|
+
realtimeHost = endpoint.replace(/^wss?:\/\//, '').split('/')[0] ?? '';
|
|
711
|
+
}
|
|
712
|
+
// Swap the realtime suffix → http suffix. If the host doesn't match the
|
|
713
|
+
// standard AppSync naming (e.g. custom domain), pass it through unchanged
|
|
714
|
+
// — the same host serves both endpoints on custom domains.
|
|
715
|
+
const httpHost = realtimeHost.replace('.appsync-realtime-api.', '.appsync-api.');
|
|
716
|
+
return { url: raw, httpHost };
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Build the AppSync Events auth header carried in the `header-…` subprotocol
|
|
720
|
+
* token. Anonymous sessions send Authorization: '' — the Lambda authorizer
|
|
721
|
+
* accepts that only for `app:<appId>` channels with a passing origin check.
|
|
722
|
+
*/
|
|
723
|
+
function buildAppSyncAuthHeader(token, host) {
|
|
724
|
+
return {
|
|
725
|
+
Authorization: token ? `Bearer ${token}` : '',
|
|
726
|
+
host,
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Base64url-encode a UTF-8 string. AppSync Events expects the `header-…`
|
|
731
|
+
* subprotocol token to be base64url (no padding). Uses `btoa` when available
|
|
732
|
+
* (every modern browser + Node ≥16 globalThis); falls back to a manual encode
|
|
733
|
+
* for the rare environment where it isn't.
|
|
734
|
+
*/
|
|
735
|
+
function base64urlEncode(input) {
|
|
736
|
+
let b64;
|
|
737
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
738
|
+
const g = globalThis;
|
|
739
|
+
if (typeof g.btoa === 'function') {
|
|
740
|
+
// btoa wants binary string; encode UTF-8 → bytes first so non-ASCII JWTs
|
|
741
|
+
// survive (rare but legal — JWT header/claims can be unicode).
|
|
742
|
+
const utf8 = unescape(encodeURIComponent(input));
|
|
743
|
+
b64 = g.btoa(utf8);
|
|
744
|
+
}
|
|
745
|
+
else if (typeof g.Buffer?.from === 'function') {
|
|
746
|
+
b64 = g.Buffer.from(input, 'utf-8').toString('base64');
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
// No encoder available — return the raw input. Will fail the handshake,
|
|
750
|
+
// but loudly (Lambda authorizer rejects), which is preferable to silent
|
|
751
|
+
// corruption.
|
|
752
|
+
return input;
|
|
753
|
+
}
|
|
754
|
+
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Translate internal channel name (`<ns>:<id>`) to the AppSync wire form
|
|
758
|
+
* (`<ns>/<id>`). Mirrors the publish side at
|
|
759
|
+
* `microservices/shared/realtime/adapters/appsync-events.adapter.ts:87`
|
|
760
|
+
* and the Lambda authorizer's normalizer at
|
|
761
|
+
* `microservices/shared/realtime/appsync-authorizer.handler.ts:59`.
|
|
762
|
+
*/
|
|
763
|
+
function appSyncChannelToWire(internal) {
|
|
764
|
+
return internal.replace(':', '/');
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Stable per-subscribe identifier. Prefer `crypto.randomUUID()` (ES2022,
|
|
768
|
+
* available in every supported runtime — browser globals + Node ≥19); fall
|
|
769
|
+
* back to a Math.random-based id for the rare environment where it isn't.
|
|
770
|
+
*/
|
|
771
|
+
function appSyncSubscriptionId() {
|
|
772
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
773
|
+
const g = globalThis;
|
|
774
|
+
if (g.crypto?.randomUUID) {
|
|
775
|
+
return g.crypto.randomUUID();
|
|
776
|
+
}
|
|
777
|
+
return `sub-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
778
|
+
}
|
|
504
779
|
//# sourceMappingURL=realtime.js.map
|