@mycadet/gateway 0.12.10 → 0.12.11
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/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
- package/node_modules/@mycadet/ces-client/src/http-credentials.ts +18 -1
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
- package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
- package/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
- package/package.json +1 -1
- package/src/__tests__/guardian-bootstrap-lookups.test.ts +4 -4
- package/src/__tests__/guardian-init-lockfile.test.ts +2 -2
- package/src/__tests__/remote-web-pairing-token.test.ts +1 -1
- package/src/auth/guardian-bootstrap.ts +1 -1
- package/src/http/routes/speech-relay-websocket.ts +2 -2
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
trimmedNonEmptyString,
|
|
11
11
|
TUNNEL_PROVIDERS,
|
|
12
12
|
type TunnelRecord,
|
|
13
|
-
|
|
13
|
+
tunnelHostForCloudHost,
|
|
14
14
|
} from "../ingress.js";
|
|
15
15
|
import {
|
|
16
16
|
buildTwilioMediaStreamUrl,
|
|
@@ -19,27 +19,27 @@ import {
|
|
|
19
19
|
resolveTwilioPublicBaseUrl,
|
|
20
20
|
} from "../twilio-ingress.js";
|
|
21
21
|
|
|
22
|
-
describe("
|
|
22
|
+
describe("tunnelHostForCloudHost", () => {
|
|
23
23
|
test("maps the prod platform host to the prod tunnel", () => {
|
|
24
|
-
expect(
|
|
24
|
+
expect(tunnelHostForCloudHost("cloud.mycadet.ai")).toBe(
|
|
25
25
|
"tunnel.mycadet.ai",
|
|
26
26
|
);
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
test("maps env-prefixed platform hosts to their env tunnel", () => {
|
|
30
|
-
expect(
|
|
30
|
+
expect(tunnelHostForCloudHost("staging-cloud.mycadet.ai")).toBe(
|
|
31
31
|
"tunnel-staging.mycadet.ai",
|
|
32
32
|
);
|
|
33
|
-
expect(
|
|
33
|
+
expect(tunnelHostForCloudHost("dev-cloud.mycadet.ai")).toBe(
|
|
34
34
|
"tunnel-dev.mycadet.ai",
|
|
35
35
|
);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
test("returns null for hosts outside the deployment convention", () => {
|
|
39
|
-
expect(
|
|
40
|
-
expect(
|
|
39
|
+
expect(tunnelHostForCloudHost("localhost")).toBeNull();
|
|
40
|
+
expect(tunnelHostForCloudHost("platform.example.com")).toBeNull();
|
|
41
41
|
expect(
|
|
42
|
-
|
|
42
|
+
tunnelHostForCloudHost("staging-cloud.mycadet.ai.evil.com"),
|
|
43
43
|
).toBeNull();
|
|
44
44
|
});
|
|
45
45
|
});
|
package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* gateway speech relay and the web live-voice client so the two ends of the
|
|
7
7
|
* cloud-speech transport can't drift.
|
|
8
8
|
*/
|
|
9
|
-
export function
|
|
9
|
+
export function tunnelHostForCloudHost(host: string): string | null {
|
|
10
10
|
if (host === "cloud.mycadet.ai") {
|
|
11
11
|
return "tunnel.mycadet.ai";
|
|
12
12
|
}
|
|
@@ -143,6 +143,19 @@ export interface CesHttpCredentialClient {
|
|
|
143
143
|
// Factory
|
|
144
144
|
// ---------------------------------------------------------------------------
|
|
145
145
|
|
|
146
|
+
function listErrorContext(
|
|
147
|
+
response: Response,
|
|
148
|
+
path: string,
|
|
149
|
+
): Record<string, unknown> {
|
|
150
|
+
const requestId = response.headers.get("x-ces-error-id");
|
|
151
|
+
return {
|
|
152
|
+
status: response.status,
|
|
153
|
+
method: "GET",
|
|
154
|
+
path,
|
|
155
|
+
...(requestId && /^[a-f0-9-]{36}$/i.test(requestId) ? { requestId } : {}),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
146
159
|
export function createCesHttpCredentialClient(
|
|
147
160
|
config: CesHttpCredentialConfig,
|
|
148
161
|
logger: CesHttpLogger,
|
|
@@ -298,7 +311,7 @@ export function createCesHttpCredentialClient(
|
|
|
298
311
|
if (!res) return { accounts: [], unreachable: true };
|
|
299
312
|
if (!res.ok) {
|
|
300
313
|
logger.warn(
|
|
301
|
-
|
|
314
|
+
listErrorContext(res, "/v1/credentials"),
|
|
302
315
|
"CES credential list returned non-OK status",
|
|
303
316
|
);
|
|
304
317
|
return { accounts: [], unreachable: true };
|
|
@@ -399,6 +412,10 @@ export function createCesHttpCredentialClient(
|
|
|
399
412
|
return { records: [], unreachable: true };
|
|
400
413
|
}
|
|
401
414
|
if (!res.ok) {
|
|
415
|
+
logger.warn(
|
|
416
|
+
listErrorContext(res, "/v1/metadata"),
|
|
417
|
+
"CES metadata list returned non-OK status",
|
|
418
|
+
);
|
|
402
419
|
return { records: [], unreachable: true };
|
|
403
420
|
}
|
|
404
421
|
const data = (await res.json()) as {
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
trimmedNonEmptyString,
|
|
11
11
|
TUNNEL_PROVIDERS,
|
|
12
12
|
type TunnelRecord,
|
|
13
|
-
|
|
13
|
+
tunnelHostForCloudHost,
|
|
14
14
|
} from "../ingress.js";
|
|
15
15
|
import {
|
|
16
16
|
buildTwilioMediaStreamUrl,
|
|
@@ -19,27 +19,27 @@ import {
|
|
|
19
19
|
resolveTwilioPublicBaseUrl,
|
|
20
20
|
} from "../twilio-ingress.js";
|
|
21
21
|
|
|
22
|
-
describe("
|
|
22
|
+
describe("tunnelHostForCloudHost", () => {
|
|
23
23
|
test("maps the prod platform host to the prod tunnel", () => {
|
|
24
|
-
expect(
|
|
24
|
+
expect(tunnelHostForCloudHost("cloud.mycadet.ai")).toBe(
|
|
25
25
|
"tunnel.mycadet.ai",
|
|
26
26
|
);
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
test("maps env-prefixed platform hosts to their env tunnel", () => {
|
|
30
|
-
expect(
|
|
30
|
+
expect(tunnelHostForCloudHost("staging-cloud.mycadet.ai")).toBe(
|
|
31
31
|
"tunnel-staging.mycadet.ai",
|
|
32
32
|
);
|
|
33
|
-
expect(
|
|
33
|
+
expect(tunnelHostForCloudHost("dev-cloud.mycadet.ai")).toBe(
|
|
34
34
|
"tunnel-dev.mycadet.ai",
|
|
35
35
|
);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
test("returns null for hosts outside the deployment convention", () => {
|
|
39
|
-
expect(
|
|
40
|
-
expect(
|
|
39
|
+
expect(tunnelHostForCloudHost("localhost")).toBeNull();
|
|
40
|
+
expect(tunnelHostForCloudHost("platform.example.com")).toBeNull();
|
|
41
41
|
expect(
|
|
42
|
-
|
|
42
|
+
tunnelHostForCloudHost("staging-cloud.mycadet.ai.evil.com"),
|
|
43
43
|
).toBeNull();
|
|
44
44
|
});
|
|
45
45
|
});
|
package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* gateway speech relay and the web live-voice client so the two ends of the
|
|
7
7
|
* cloud-speech transport can't drift.
|
|
8
8
|
*/
|
|
9
|
-
export function
|
|
9
|
+
export function tunnelHostForCloudHost(host: string): string | null {
|
|
10
10
|
if (host === "cloud.mycadet.ai") {
|
|
11
11
|
return "tunnel.mycadet.ai";
|
|
12
12
|
}
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
trimmedNonEmptyString,
|
|
11
11
|
TUNNEL_PROVIDERS,
|
|
12
12
|
type TunnelRecord,
|
|
13
|
-
|
|
13
|
+
tunnelHostForCloudHost,
|
|
14
14
|
} from "../ingress.js";
|
|
15
15
|
import {
|
|
16
16
|
buildTwilioMediaStreamUrl,
|
|
@@ -19,27 +19,27 @@ import {
|
|
|
19
19
|
resolveTwilioPublicBaseUrl,
|
|
20
20
|
} from "../twilio-ingress.js";
|
|
21
21
|
|
|
22
|
-
describe("
|
|
22
|
+
describe("tunnelHostForCloudHost", () => {
|
|
23
23
|
test("maps the prod platform host to the prod tunnel", () => {
|
|
24
|
-
expect(
|
|
24
|
+
expect(tunnelHostForCloudHost("cloud.mycadet.ai")).toBe(
|
|
25
25
|
"tunnel.mycadet.ai",
|
|
26
26
|
);
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
test("maps env-prefixed platform hosts to their env tunnel", () => {
|
|
30
|
-
expect(
|
|
30
|
+
expect(tunnelHostForCloudHost("staging-cloud.mycadet.ai")).toBe(
|
|
31
31
|
"tunnel-staging.mycadet.ai",
|
|
32
32
|
);
|
|
33
|
-
expect(
|
|
33
|
+
expect(tunnelHostForCloudHost("dev-cloud.mycadet.ai")).toBe(
|
|
34
34
|
"tunnel-dev.mycadet.ai",
|
|
35
35
|
);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
test("returns null for hosts outside the deployment convention", () => {
|
|
39
|
-
expect(
|
|
40
|
-
expect(
|
|
39
|
+
expect(tunnelHostForCloudHost("localhost")).toBeNull();
|
|
40
|
+
expect(tunnelHostForCloudHost("platform.example.com")).toBeNull();
|
|
41
41
|
expect(
|
|
42
|
-
|
|
42
|
+
tunnelHostForCloudHost("staging-cloud.mycadet.ai.evil.com"),
|
|
43
43
|
).toBeNull();
|
|
44
44
|
});
|
|
45
45
|
});
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* gateway speech relay and the web live-voice client so the two ends of the
|
|
7
7
|
* cloud-speech transport can't drift.
|
|
8
8
|
*/
|
|
9
|
-
export function
|
|
9
|
+
export function tunnelHostForCloudHost(host: string): string | null {
|
|
10
10
|
if (host === "cloud.mycadet.ai") {
|
|
11
11
|
return "tunnel.mycadet.ai";
|
|
12
12
|
}
|
package/package.json
CHANGED
|
@@ -337,7 +337,7 @@ describe("resolve-or-mint (resolveOrCreateCadetGuardian)", () => {
|
|
|
337
337
|
assistantBackend = makeAssistantBackend();
|
|
338
338
|
|
|
339
339
|
const principalId = await ensureCadetGuardianBinding();
|
|
340
|
-
expect(principalId).toMatch(/^
|
|
340
|
+
expect(principalId).toMatch(/^principal-/);
|
|
341
341
|
|
|
342
342
|
// Gateway now has the row; the assistant DB must not be read again.
|
|
343
343
|
assistantBackend = throwingBackend;
|
|
@@ -350,7 +350,7 @@ describe("resolve-or-mint (resolveOrCreateCadetGuardian)", () => {
|
|
|
350
350
|
|
|
351
351
|
const principalId = await ensureCadetGuardianBinding();
|
|
352
352
|
|
|
353
|
-
expect(principalId).toMatch(/^
|
|
353
|
+
expect(principalId).toMatch(/^principal-/);
|
|
354
354
|
const gwRows = gatewayCadetGuardians();
|
|
355
355
|
expect(gwRows).toHaveLength(1);
|
|
356
356
|
expect(gwRows[0]?.principalId).toBe(principalId);
|
|
@@ -383,7 +383,7 @@ describe("resolve-or-mint (resolveOrCreateCadetGuardian)", () => {
|
|
|
383
383
|
deviceId: "device-1",
|
|
384
384
|
});
|
|
385
385
|
|
|
386
|
-
expect(result.guardianPrincipalId).toMatch(/^
|
|
386
|
+
expect(result.guardianPrincipalId).toMatch(/^principal-/);
|
|
387
387
|
expect(result.isNew).toBe(true);
|
|
388
388
|
expect(result.mintedOverPriorEvidence).toBe(false);
|
|
389
389
|
});
|
|
@@ -606,7 +606,7 @@ describe("resolve-or-mint (resolveOrCreateCadetGuardian)", () => {
|
|
|
606
606
|
deviceId: "device-1",
|
|
607
607
|
});
|
|
608
608
|
|
|
609
|
-
expect(result.guardianPrincipalId).toMatch(/^
|
|
609
|
+
expect(result.guardianPrincipalId).toMatch(/^principal-/);
|
|
610
610
|
expect(result.isNew).toBe(true);
|
|
611
611
|
expect(result.mintedOverPriorEvidence).toBe(true);
|
|
612
612
|
expect(gatewayCadetGuardians()).toHaveLength(1);
|
|
@@ -271,7 +271,7 @@ describe("guardian/init bootstrap secret", () => {
|
|
|
271
271
|
|
|
272
272
|
expect(res.status).toBe(200);
|
|
273
273
|
const body = await res.json();
|
|
274
|
-
expect(body.guardianPrincipalId).toMatch(/^
|
|
274
|
+
expect(body.guardianPrincipalId).toMatch(/^principal-/);
|
|
275
275
|
expect(body.accessToken).toBeTruthy();
|
|
276
276
|
expect(body.refreshToken).toBeTruthy();
|
|
277
277
|
expect(body.isNew).toBe(true);
|
|
@@ -391,7 +391,7 @@ describe("guardian/init one-time-use lockfile", () => {
|
|
|
391
391
|
|
|
392
392
|
expect(res.status).toBe(200);
|
|
393
393
|
const body = await res.json();
|
|
394
|
-
expect(body.guardianPrincipalId).toMatch(/^
|
|
394
|
+
expect(body.guardianPrincipalId).toMatch(/^principal-/);
|
|
395
395
|
expect(body.accessToken).toBeTruthy();
|
|
396
396
|
expect(body.refreshToken).toBeTruthy();
|
|
397
397
|
expect(lockFileExists()).toBe(true);
|
|
@@ -622,7 +622,7 @@ describe("remote web pairing token exchange", () => {
|
|
|
622
622
|
.where(eq(contacts.role, "guardian"))
|
|
623
623
|
.all();
|
|
624
624
|
expect(gwGuardian).toHaveLength(1);
|
|
625
|
-
expect(gwGuardian[0].principalId).toMatch(/^
|
|
625
|
+
expect(gwGuardian[0].principalId).toMatch(/^principal-/);
|
|
626
626
|
});
|
|
627
627
|
|
|
628
628
|
test("gateway binding write failure fails the mint and leaves the code retryable", async () => {
|
|
@@ -1220,7 +1220,7 @@ async function resolveOrCreateCadetGuardian(options: {
|
|
|
1220
1220
|
|
|
1221
1221
|
// No gateway guardian — mint a fresh principal.
|
|
1222
1222
|
const displayName = await fetchPlatformOwnerDisplayName();
|
|
1223
|
-
const guardianPrincipalId = `
|
|
1223
|
+
const guardianPrincipalId = `principal-${uuid()}`;
|
|
1224
1224
|
await createGuardianBinding({
|
|
1225
1225
|
channel: "cadet",
|
|
1226
1226
|
externalUserId: guardianPrincipalId,
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
import type { OutgoingHttpHeaders } from "node:http";
|
|
24
24
|
|
|
25
|
-
import {
|
|
25
|
+
import { tunnelHostForCloudHost } from "@mycadet/service-contracts/ingress";
|
|
26
26
|
|
|
27
27
|
import { resolveScopeProfile } from "../../auth/scopes.js";
|
|
28
28
|
import { validateEdgeToken } from "../../auth/token-exchange.js";
|
|
@@ -163,7 +163,7 @@ function jsonError(status: number, code: string, detail: string): Response {
|
|
|
163
163
|
* shared with the web live-voice client; this wrapper adds the scheme.
|
|
164
164
|
*/
|
|
165
165
|
export function tunnelOriginForPlatformHost(host: string): string | null {
|
|
166
|
-
const tunnelHost =
|
|
166
|
+
const tunnelHost = tunnelHostForCloudHost(host);
|
|
167
167
|
return tunnelHost ? `https://${tunnelHost}` : null;
|
|
168
168
|
}
|
|
169
169
|
|