@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.
@@ -10,7 +10,7 @@ import {
10
10
  trimmedNonEmptyString,
11
11
  TUNNEL_PROVIDERS,
12
12
  type TunnelRecord,
13
- tunnelHostForPlatformHost,
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("tunnelHostForPlatformHost", () => {
22
+ describe("tunnelHostForCloudHost", () => {
23
23
  test("maps the prod platform host to the prod tunnel", () => {
24
- expect(tunnelHostForPlatformHost("cloud.mycadet.ai")).toBe(
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(tunnelHostForPlatformHost("staging-cloud.mycadet.ai")).toBe(
30
+ expect(tunnelHostForCloudHost("staging-cloud.mycadet.ai")).toBe(
31
31
  "tunnel-staging.mycadet.ai",
32
32
  );
33
- expect(tunnelHostForPlatformHost("dev-cloud.mycadet.ai")).toBe(
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(tunnelHostForPlatformHost("localhost")).toBeNull();
40
- expect(tunnelHostForPlatformHost("platform.example.com")).toBeNull();
39
+ expect(tunnelHostForCloudHost("localhost")).toBeNull();
40
+ expect(tunnelHostForCloudHost("platform.example.com")).toBeNull();
41
41
  expect(
42
- tunnelHostForPlatformHost("staging-cloud.mycadet.ai.evil.com"),
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 tunnelHostForPlatformHost(host: string): string | null {
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
- { status: res.status },
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
- tunnelHostForPlatformHost,
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("tunnelHostForPlatformHost", () => {
22
+ describe("tunnelHostForCloudHost", () => {
23
23
  test("maps the prod platform host to the prod tunnel", () => {
24
- expect(tunnelHostForPlatformHost("cloud.mycadet.ai")).toBe(
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(tunnelHostForPlatformHost("staging-cloud.mycadet.ai")).toBe(
30
+ expect(tunnelHostForCloudHost("staging-cloud.mycadet.ai")).toBe(
31
31
  "tunnel-staging.mycadet.ai",
32
32
  );
33
- expect(tunnelHostForPlatformHost("dev-cloud.mycadet.ai")).toBe(
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(tunnelHostForPlatformHost("localhost")).toBeNull();
40
- expect(tunnelHostForPlatformHost("platform.example.com")).toBeNull();
39
+ expect(tunnelHostForCloudHost("localhost")).toBeNull();
40
+ expect(tunnelHostForCloudHost("platform.example.com")).toBeNull();
41
41
  expect(
42
- tunnelHostForPlatformHost("staging-cloud.mycadet.ai.evil.com"),
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 tunnelHostForPlatformHost(host: string): string | null {
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
- tunnelHostForPlatformHost,
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("tunnelHostForPlatformHost", () => {
22
+ describe("tunnelHostForCloudHost", () => {
23
23
  test("maps the prod platform host to the prod tunnel", () => {
24
- expect(tunnelHostForPlatformHost("cloud.mycadet.ai")).toBe(
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(tunnelHostForPlatformHost("staging-cloud.mycadet.ai")).toBe(
30
+ expect(tunnelHostForCloudHost("staging-cloud.mycadet.ai")).toBe(
31
31
  "tunnel-staging.mycadet.ai",
32
32
  );
33
- expect(tunnelHostForPlatformHost("dev-cloud.mycadet.ai")).toBe(
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(tunnelHostForPlatformHost("localhost")).toBeNull();
40
- expect(tunnelHostForPlatformHost("platform.example.com")).toBeNull();
39
+ expect(tunnelHostForCloudHost("localhost")).toBeNull();
40
+ expect(tunnelHostForCloudHost("platform.example.com")).toBeNull();
41
41
  expect(
42
- tunnelHostForPlatformHost("staging-cloud.mycadet.ai.evil.com"),
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 tunnelHostForPlatformHost(host: string): string | null {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mycadet/gateway",
3
- "version": "0.12.10",
3
+ "version": "0.12.11",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -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(/^cadet-principal-/);
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(/^cadet-principal-/);
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(/^cadet-principal-/);
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(/^cadet-principal-/);
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(/^cadet-principal-/);
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(/^cadet-principal-/);
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(/^cadet-principal-/);
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 = `cadet-principal-${uuid()}`;
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 { tunnelHostForPlatformHost } from "@mycadet/service-contracts/ingress";
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 = tunnelHostForPlatformHost(host);
166
+ const tunnelHost = tunnelHostForCloudHost(host);
167
167
  return tunnelHost ? `https://${tunnelHost}` : null;
168
168
  }
169
169