@mycadet/gateway 0.12.7 → 0.12.9

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.
Files changed (179) hide show
  1. package/README.md +3 -3
  2. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/package.json +2 -2
  3. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/{platform-credential.ts → cloud-credential.ts} +9 -9
  4. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
  5. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
  6. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
  7. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
  8. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
  9. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
  10. package/node_modules/@mycadet/ces-client/package.json +1 -1
  11. package/node_modules/@mycadet/ces-client/src/__tests__/ces-client.test.ts +14 -14
  12. package/node_modules/@mycadet/ces-client/src/rpc-client.ts +1 -1
  13. package/node_modules/@mycadet/environments/src/seeds.ts +6 -6
  14. package/node_modules/@mycadet/environments/src/shell.test.ts +1 -1
  15. package/node_modules/@mycadet/environments/src/types.ts +6 -6
  16. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/package.json +2 -2
  17. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/{platform-credential.ts → cloud-credential.ts} +9 -9
  18. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
  19. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
  20. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
  21. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
  22. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
  23. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
  24. package/node_modules/@mycadet/gateway-client/src/binding-strength-contract.ts +5 -5
  25. package/node_modules/@mycadet/gateway-client/src/gateway-ipc-contracts.ts +1 -1
  26. package/node_modules/@mycadet/gateway-client/src/inbound-contract.ts +2 -2
  27. package/node_modules/@mycadet/gateway-client/src/outbound-contract.ts +1 -1
  28. package/node_modules/@mycadet/service-contracts/package.json +2 -2
  29. package/node_modules/@mycadet/service-contracts/src/{platform-credential.ts → cloud-credential.ts} +9 -9
  30. package/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
  31. package/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
  32. package/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
  33. package/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
  34. package/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
  35. package/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
  36. package/openapi.json +17 -17
  37. package/package.json +1 -1
  38. package/scripts/generate-openapi.ts +1 -1
  39. package/src/__tests__/actor-token-revocation.test.ts +0 -1
  40. package/src/__tests__/{backup-worker-platform-mode.test.ts → backup-worker-cloud-mode.test.ts} +4 -4
  41. package/src/__tests__/channel-verification-session-proxy.test.ts +0 -1
  42. package/src/__tests__/{platform-identity.test.ts → cloud-identity.test.ts} +72 -86
  43. package/src/__tests__/config.test.ts +0 -24
  44. package/src/__tests__/contacts-control-plane-proxy.test.ts +0 -1
  45. package/src/__tests__/credential-requests.test.ts +6 -6
  46. package/src/__tests__/{credential-watcher-managed-bootstrap.test.ts → credential-watcher-cloud-bootstrap.test.ts} +1 -1
  47. package/src/__tests__/edge-auth.test.ts +18 -18
  48. package/src/__tests__/edge-guardian-auth.test.ts +10 -10
  49. package/src/__tests__/guardian-init-lockfile.test.ts +6 -8
  50. package/src/__tests__/guardian-pin.test.ts +8 -8
  51. package/src/__tests__/handle-inbound-admission.test.ts +0 -1
  52. package/src/__tests__/handle-inbound-app-context.test.ts +0 -1
  53. package/src/__tests__/handle-inbound-invite-intercept.test.ts +0 -1
  54. package/src/__tests__/handle-inbound-trust-verdict.test.ts +0 -1
  55. package/src/__tests__/inbound-contact-seed.test.ts +1 -1
  56. package/src/__tests__/live-voice-websocket.test.ts +12 -12
  57. package/src/__tests__/load-guards.test.ts +0 -1
  58. package/src/__tests__/migration-teleport-gcs-proxy.test.ts +0 -1
  59. package/src/__tests__/oauth-callback.test.ts +0 -1
  60. package/src/__tests__/remote-feature-flag-sync.test.ts +35 -45
  61. package/src/__tests__/resolve-assistant.test.ts +0 -1
  62. package/src/__tests__/route-schema-guard.test.ts +4 -1
  63. package/src/__tests__/runtime-client.test.ts +1 -2
  64. package/src/__tests__/runtime-health-proxy.test.ts +0 -1
  65. package/src/__tests__/runtime-proxy-auth.test.ts +3 -2
  66. package/src/__tests__/runtime-proxy-device-stamp.test.ts +0 -1
  67. package/src/__tests__/runtime-proxy-error-body.test.ts +0 -1
  68. package/src/__tests__/runtime-proxy.test.ts +0 -1
  69. package/src/__tests__/runtime-stream-test-utils.ts +0 -1
  70. package/src/__tests__/shared-invite-registration.test.ts +15 -32
  71. package/src/__tests__/slack-control-plane-proxy.test.ts +0 -1
  72. package/src/__tests__/slack-display-name.test.ts +0 -1
  73. package/src/__tests__/slack-normalize.test.ts +0 -1
  74. package/src/__tests__/slack-reaction-normalize.test.ts +0 -1
  75. package/src/__tests__/slack-socket-mode-catchup.test.ts +0 -1
  76. package/src/__tests__/slack-socket-mode-group-dm.test.ts +0 -1
  77. package/src/__tests__/slack-socket-mode-liveness.test.ts +0 -1
  78. package/src/__tests__/slack-socket-mode-outbound-root.test.ts +0 -1
  79. package/src/__tests__/slack-socket-mode-thread-tracking.test.ts +0 -1
  80. package/src/__tests__/speech-relay-websocket.test.ts +16 -14
  81. package/src/__tests__/stt-stream-websocket.test.ts +5 -5
  82. package/src/__tests__/telegram-control-plane-proxy.test.ts +0 -1
  83. package/src/__tests__/telegram-webhook-drop-visibility.test.ts +0 -1
  84. package/src/__tests__/telegram-webhook-handler.test.ts +0 -1
  85. package/src/__tests__/telegram-webhook-manager.test.ts +79 -80
  86. package/src/__tests__/twilio-media-websocket.test.ts +0 -1
  87. package/src/__tests__/twilio-webhooks.test.ts +6 -7
  88. package/src/__tests__/whatsapp-download.test.ts +0 -1
  89. package/src/__tests__/whatsapp-webhook.test.ts +0 -1
  90. package/src/attachments/ingest.test.ts +0 -1
  91. package/src/auth/guardian-bootstrap.ts +16 -15
  92. package/src/auth/scopes.ts +1 -1
  93. package/src/auth-fallback-reporter.ts +1 -1
  94. package/src/backup/backup-worker.ts +2 -2
  95. package/src/channels/inbound-event.ts +3 -3
  96. package/src/channels/ingress-inbound-vendors.test.ts +2 -2
  97. package/src/channels/ingress-inbound.ts +1 -1
  98. package/src/channels/ingress-verification.test.ts +2 -2
  99. package/src/channels/ingress-verification.ts +4 -4
  100. package/src/channels/plugin-ingress-approvals.test.ts +1 -1
  101. package/src/channels/plugin-ingress-approvals.ts +1 -1
  102. package/src/channels/plugin-ingress.test.ts +3 -3
  103. package/src/channels/plugin-ingress.ts +3 -3
  104. package/src/channels/room-admission.ts +2 -2
  105. package/src/cli/contacts.ts +3 -1
  106. package/src/cli/index.ts +1 -1
  107. package/src/{platform-identity.ts → cloud-identity.ts} +60 -68
  108. package/src/cloud-url.ts +25 -0
  109. package/src/{platform-user-id.ts → cloud-user-id.ts} +4 -4
  110. package/src/config.ts +2 -4
  111. package/src/credential-reader.ts +2 -2
  112. package/src/db/assistant-db-proxy.ts +1 -1
  113. package/src/discord/forward.ts +1 -1
  114. package/src/email/normalize.ts +4 -4
  115. package/src/email/register-callback.test.ts +27 -34
  116. package/src/email/register-callback.ts +21 -26
  117. package/src/feature-flag-registry.json +5 -5
  118. package/src/feature-flag-remote-store.ts +2 -2
  119. package/src/feature-flag-resolver.ts +5 -5
  120. package/src/http/cadet-signature.ts +1 -1
  121. package/src/http/edge-forwarded-header.ts +1 -1
  122. package/src/http/loopback-guard.ts +1 -1
  123. package/src/http/middleware/auth.ts +22 -22
  124. package/src/http/router.ts +1 -1
  125. package/src/http/routes/auto-approve-thresholds-routes.ts +1 -1
  126. package/src/http/routes/cadet-identity.ts +2 -2
  127. package/src/http/routes/channel-admission-policy-routes.ts +2 -2
  128. package/src/http/routes/channel-ingress-routes.ts +3 -3
  129. package/src/http/routes/channel-ingress.test.ts +13 -2
  130. package/src/http/routes/channel-permission-overrides-routes.ts +3 -3
  131. package/src/http/routes/channel-verification-session-proxy.ts +8 -22
  132. package/src/http/routes/{platform-push-proxy.test.ts → cloud-push-proxy.test.ts} +21 -22
  133. package/src/http/routes/{platform-push-proxy.ts → cloud-push-proxy.ts} +13 -14
  134. package/src/http/routes/contacts-control-plane-proxy.ts +3 -3
  135. package/src/http/routes/contacts-control-plane-routes.ts +5 -5
  136. package/src/http/routes/email-webhook.test.ts +2 -3
  137. package/src/http/routes/email-webhook.ts +4 -4
  138. package/src/http/routes/feature-flags.ts +1 -1
  139. package/src/http/routes/guardian-channel-create.ts +3 -3
  140. package/src/http/routes/guardian-pin.ts +9 -9
  141. package/src/http/routes/inbound-register.ts +2 -2
  142. package/src/http/routes/ingress-domains.test.ts +129 -0
  143. package/src/http/routes/ingress-domains.ts +73 -0
  144. package/src/http/routes/live-voice-websocket.ts +2 -2
  145. package/src/http/routes/log-export.test.ts +0 -1
  146. package/src/http/routes/log-tail.test.ts +0 -1
  147. package/src/http/routes/migration-proxy.ts +1 -1
  148. package/src/http/routes/plugin-webhook-websocket.test.ts +3 -3
  149. package/src/http/routes/plugin-webhook.test.ts +9 -8
  150. package/src/http/routes/plugin-webhook.ts +1 -1
  151. package/src/http/routes/speech-relay-websocket.ts +8 -11
  152. package/src/http/routes/stt-stream-websocket.ts +1 -1
  153. package/src/http/routes/telegram-webhook.test.ts +0 -1
  154. package/src/http/routes/trust-rules-routes.ts +2 -2
  155. package/src/http/routes/twilio-voice-verify-callback.ts +3 -3
  156. package/src/http/routes/twilio-voice-webhook.test.ts +3 -4
  157. package/src/http/routes/twilio-voice-webhook.ts +3 -3
  158. package/src/http/routes/whatsapp-webhook.test.ts +0 -1
  159. package/src/index.ts +57 -56
  160. package/src/ipc/credential-request-handlers.ts +4 -4
  161. package/src/ipc/debug-export-handlers.test.ts +0 -1
  162. package/src/ipc/log-tail-handlers.test.ts +0 -1
  163. package/src/ipc/risk-classification-handlers.test.ts +4 -4
  164. package/src/ipc/risk-classification-handlers.ts +2 -2
  165. package/src/remote-feature-flag-sync.ts +17 -19
  166. package/src/risk/command-registry/commands/assistant.ts +2 -2
  167. package/src/risk/skill-risk-classifier.test.ts +24 -24
  168. package/src/risk/skill-risk-classifier.ts +10 -10
  169. package/src/runtime/client.ts +17 -17
  170. package/src/schema.ts +29 -29
  171. package/src/telegram/send.test.ts +0 -1
  172. package/src/telegram/webhook-manager.ts +33 -38
  173. package/src/tunnel/allowed-paths.test.ts +3 -3
  174. package/src/tunnel/allowed-paths.ts +1 -1
  175. package/src/tunnel/client.test.ts +20 -21
  176. package/src/tunnel/client.ts +16 -17
  177. package/src/verification/shared-invite-registration.ts +22 -17
  178. package/src/version.ts +1 -1
  179. package/src/platform-url.ts +0 -24
@@ -7,13 +7,13 @@ import { credentialKey } from "../credential-key.js";
7
7
  import { registerWebhookIngressRoute } from "../db/webhook-ingress-route-store.js";
8
8
  import { fetchImpl } from "../fetch.js";
9
9
  import {
10
- arePlatformFeaturesEnabled,
10
+ areCloudFeaturesEnabled,
11
11
  isFeatureFlagEnabled,
12
- isPlatformMode,
12
+ isCloudServedBuild,
13
13
  } from "../feature-flag-resolver.js";
14
14
  import { callTelegramApi } from "./api.js";
15
15
  import { getLogger } from "../logger.js";
16
- import { resolvePlatformAssistantIdOrUndefined } from "../platform-identity.js";
16
+ import { resolveCloudAssistantIdOrUndefined } from "../cloud-identity.js";
17
17
 
18
18
  const log = getLogger("webhook-manager");
19
19
  const TELEGRAM_CALLBACK_PATH = "webhooks/telegram";
@@ -46,26 +46,21 @@ interface PlatformCallbackRouteResponse {
46
46
  async function registerManagedTelegramCallbackRoute(
47
47
  caches?: WebhookManagerCaches,
48
48
  ): Promise<string | undefined> {
49
- if (!arePlatformFeaturesEnabled()) {
49
+ if (!areCloudFeaturesEnabled()) {
50
50
  log.debug(
51
51
  "Platform features disabled — skipping managed Telegram callback registration",
52
52
  );
53
53
  return undefined;
54
54
  }
55
55
 
56
- const [platformBaseUrlRaw, assistantApiKeyRaw] = caches?.credentials
57
- ? await Promise.all([
58
- caches.credentials.get(credentialKey("cadet", "platform_base_url")),
59
- caches.credentials.get(credentialKey("cadet", "assistant_api_key")),
60
- ])
61
- : [undefined, undefined];
62
-
63
- // Fall back to env vars when managed pod credentials are not yet cached,
64
- // matching the daemon's resolvePlatformCallbackRegistrationContext().
65
- const platformBaseUrl = (
66
- platformBaseUrlRaw?.trim() ||
67
- process.env.CADET_PLATFORM_URL?.trim() ||
68
- ""
56
+ const assistantApiKeyRaw = caches?.credentials
57
+ ? await caches.credentials.get(credentialKey("cadet", "assistant_api_key"))
58
+ : undefined;
59
+
60
+ // The base URL resolves from the environment only — the credential store
61
+ // never carries it.
62
+ const cloudBaseUrl = (
63
+ process.env.CADET_CLOUD_URL?.trim() || ""
69
64
  ).replace(/\/+$/, "");
70
65
 
71
66
  const assistantCredential =
@@ -73,12 +68,12 @@ async function registerManagedTelegramCallbackRoute(
73
68
  process.env.ASSISTANT_API_KEY?.trim() ||
74
69
  undefined;
75
70
 
76
- const assistantId = await resolvePlatformAssistantIdOrUndefined();
71
+ const assistantId = await resolveCloudAssistantIdOrUndefined();
77
72
 
78
- if (!platformBaseUrl || !assistantCredential || !assistantId) {
73
+ if (!cloudBaseUrl || !assistantCredential || !assistantId) {
79
74
  log.debug(
80
75
  {
81
- hasPlatformBaseUrl: !!platformBaseUrl,
76
+ hasPlatformBaseUrl: !!cloudBaseUrl,
82
77
  hasApiKey: !!assistantCredential,
83
78
  hasAssistantId: !!assistantId,
84
79
  },
@@ -104,8 +99,8 @@ async function registerManagedTelegramCallbackRoute(
104
99
  log.debug("Could not resolve Telegram bot username for source_identifier");
105
100
  }
106
101
 
107
- // Self-hosted assistants send their public ingress URL so the platform
108
- // can register a callback that points at this gateway. Platform pods may
102
+ // Self-hosted assistants send their public ingress URL so the cloud
103
+ // can register a callback that points at this gateway. Cloud pods may
109
104
  // also include it; Django ignores a client-provided base for those.
110
105
  const ingressUrl = readIngressBaseUrl(caches);
111
106
 
@@ -122,7 +117,7 @@ async function registerManagedTelegramCallbackRoute(
122
117
  }
123
118
 
124
119
  const response = await fetchImpl(
125
- `${platformBaseUrl}/v1/internal/gateway/callback-routes/register/`,
120
+ `${cloudBaseUrl}/v1/internal/gateway/callback-routes/register/`,
126
121
  {
127
122
  method: "POST",
128
123
  headers: {
@@ -177,7 +172,7 @@ function readIngressBaseUrl(caches?: WebhookManagerCaches): string | undefined {
177
172
  * path is unclaimed would register a webhook that every delivery bounces off.
178
173
  *
179
174
  * Returns undefined when the tunnel has published no URL yet or the claim
180
- * fails, which leaves the caller on the managed callback route.
175
+ * fails, which leaves the caller on the cloud callback route.
181
176
  */
182
177
  function resolveTunnelTelegramWebhookUrl(
183
178
  caches?: WebhookManagerCaches,
@@ -195,7 +190,7 @@ function resolveTunnelTelegramWebhookUrl(
195
190
  } catch (err) {
196
191
  log.error(
197
192
  { err },
198
- "Could not claim the Telegram webhook path in the ingress registry; falling back to the managed callback route",
193
+ "Could not claim the Telegram webhook path in the ingress registry; falling back to the cloud callback route",
199
194
  );
200
195
  return undefined;
201
196
  }
@@ -213,33 +208,33 @@ async function resolveExpectedTelegramWebhookUrl(
213
208
  // resolver declines makes setup report success while setWebhook never runs
214
209
  // (LUM-2899).
215
210
  //
216
- // 1. Platform pods (`IS_PLATFORM`) with `tunnel-webhooks` off always use
217
- // the managed callback route and never consult ingress at all. A pod's
211
+ // 1. Cloud pods (`IS_CLOUD`) with `tunnel-webhooks` off always use
212
+ // the cloud callback route and never consult ingress at all. A pod's
218
213
  // `ingress.publicBaseUrl` is written by the Tunnel client, not by
219
214
  // a user, and that address is only live while the tunnel is:
220
215
  // `clearManagedPublicBaseUrl` wipes the key when the tunnel drops, but
221
216
  // Telegram keeps delivering to whatever was last registered, so a pod
222
217
  // that resolved through the address alone would be pointed at a dead
223
- // one. The platform callback route is the pod's stable inbound address.
218
+ // one. The cloud callback route is the pod's stable inbound address.
224
219
  // 2. With the flag on, a pod points Telegram at its published Tunnel URL
225
220
  // and claims that path in the ingress registry first, so the tunnel
226
221
  // edge and the bridge both admit it. A pod with no published URL, or a
227
- // claim that fails, still falls back to the managed callback route.
222
+ // claim that fails, still falls back to the cloud callback route.
228
223
  // Both the tunnel publishing a URL and the flag flipping re-run this
229
224
  // reconciliation, so a pod moves between the two addresses in either
230
225
  // direction without a restart.
231
226
  // 3. An explicit `ingress.enabled: false` is a decision not to accept
232
227
  // inbound webhooks at all; it precedes both tiers below and actively
233
228
  // deregisters, so `reconcileTelegramWebhook` handles it before calling
234
- // this resolver. Platform pods are exempt (see the comment there).
229
+ // this resolver. Cloud pods are exempt (see the comment there).
235
230
  // 4. A configured public ingress URL wins (a self-hosted tunnel, or the
236
231
  // Tunnel-published URL while the tunnel is registered).
237
232
  // 5. Platform-connected local assistants holding cadet credentials fall
238
- // back to a managed platform callback route.
233
+ // back to a cloud platform callback route.
239
234
  // `registerManagedTelegramCallbackRoute` self-gates on platform
240
235
  // features and credential presence, so a gateway with no platform
241
236
  // context resolves to undefined and reconciliation skips.
242
- if (isPlatformMode()) {
237
+ if (isCloudServedBuild()) {
243
238
  if (isFeatureFlagEnabled("tunnel-webhooks")) {
244
239
  const tunnelUrl = resolveTunnelTelegramWebhookUrl(caches);
245
240
  if (tunnelUrl) {
@@ -269,7 +264,7 @@ let reconcileDrain: Promise<void> | undefined;
269
264
  * resolves depends on config that moves underneath it. A Tunnel rules refresh
270
265
  * clears `ingress.publicBaseUrl` and republishes it moments later, and each
271
266
  * write fires a config change. Run concurrently, the clear-time reconciliation
272
- * resolves the managed callback route while the republish-time one resolves
267
+ * resolves the cloud callback route while the republish-time one resolves
273
268
  * Tunnel, and whichever setWebhook lands last decides where Telegram delivers.
274
269
  * A stale winner leaves the pod on the fallback address until some later
275
270
  * trigger happens to correct it.
@@ -375,13 +370,13 @@ async function reconcileTelegramWebhookNow(
375
370
  // idempotent, and pending updates are deliberately kept so re-enabling
376
371
  // ingress does not lose queued messages.
377
372
  //
378
- // Platform pods are exempt: `hasWebhookRoutingConfigured` resolves the
379
- // IS_PLATFORM tier ahead of the explicit-disable check because a pod has no
373
+ // Cloud pods are exempt: `hasWebhookRoutingConfigured` resolves the
374
+ // IS_CLOUD tier ahead of the explicit-disable check because a pod has no
380
375
  // self-owned ingress to disable, so honoring a stray flag here would delete
381
376
  // the pod's only delivery path while the daemon still reports the channel
382
377
  // as configured (the LUM-2899 divergence in mirror image).
383
378
  if (
384
- !isPlatformMode() &&
379
+ !isCloudServedBuild() &&
385
380
  caches?.configFile?.getBoolean("ingress", "enabled") === false
386
381
  ) {
387
382
  await callTelegramApi("deleteWebhook", {}, apiOpts);
@@ -399,8 +394,8 @@ async function reconcileTelegramWebhookNow(
399
394
  try {
400
395
  expectedUrl = await resolveExpectedTelegramWebhookUrl(caches);
401
396
  } catch (err) {
402
- // Managed callback route registration failed — this is a platform-side
403
- // issue. Do not suggest ngrok or other tunnel options; they are not
397
+ // Managed callback route registration failed — this is a cloud-side
398
+ // issue. Do not suggest third-party tunnel options; they are not
404
399
  // usable in containerized deployments.
405
400
  const detail = err instanceof Error ? err.message : String(err);
406
401
  log.error(
@@ -28,7 +28,7 @@ beforeEach(() => {
28
28
  });
29
29
 
30
30
  describe("TUNNEL_ALLOWED_PATHS", () => {
31
- it("matches the platform-side header name (must stay in sync with mycadet-platform RegistrationAllowedPathsHeader)", () => {
31
+ it("matches the cloud-side header name (must stay in sync with mycadet-platform RegistrationAllowedPathsHeader)", () => {
32
32
  expect(TUNNEL_ALLOWED_PATHS_HEADER).toBe("X-Cadet-Tunnel-Allowed-Paths");
33
33
  });
34
34
 
@@ -57,7 +57,7 @@ describe("TUNNEL_ALLOWED_PATHS", () => {
57
57
  for (const pattern of patterns) {
58
58
  expect(() => new RegExp(pattern)).not.toThrow();
59
59
  // RE2-incompatible features that should never appear: lookahead,
60
- // lookbehind, backreferences. A simple guard is enough — the platform
60
+ // lookbehind, backreferences. A simple guard is enough — the cloud
61
61
  // side will reject anything Go's regexp.Compile can't parse.
62
62
  expect(pattern).not.toMatch(/\(\?[=!<]/); // lookaround
63
63
  expect(pattern).not.toMatch(/\\[1-9]/); // backreferences
@@ -85,7 +85,7 @@ describe("TUNNEL_ALLOWED_PATHS", () => {
85
85
  "/v1/audio/some-uuid.mp3": true,
86
86
  "/v1/live-voice": true,
87
87
  "/v1/stt/stream": true,
88
- // Watch sessions on a managed assistant ride the tunnel, the same shape
88
+ // Watch sessions on a cloud assistant ride the tunnel, the same shape
89
89
  // as live voice: tunnel validates the browser's minted token on this path
90
90
  // and injects the attested caller, and the gateway's handler admits only
91
91
  // the guardian on it. Self-hosted assistants bypass tunnel entirely.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Tunnel path allowlist sent to Tunnel on the WS upgrade request via the
3
3
  * {@link TUNNEL_ALLOWED_PATHS_HEADER} HTTP header. Tunnel parses the JSON-encoded
4
- * regex array on the platform side
4
+ * regex array on the cloud side
5
5
  * ({@link
6
6
  * https://github.com/vargasjr-dev/mycadet-platform/blob/main/tunnel/internal/tunnel/protocol.go
7
7
  * `RegistrationAllowedPathsHeader`})
@@ -81,8 +81,8 @@ const {
81
81
  } = await import("./allowed-paths.js");
82
82
  const { TunnelClient, createTunnelClient, enablePublicIngress } =
83
83
  await import("./client.js");
84
- const { applyPlatformIdentityIds, _resetPlatformIdentityForTests } =
85
- await import("../platform-identity.js");
84
+ const { applyCloudIdentityIds, _resetCloudIdentityForTests } =
85
+ await import("../cloud-identity.js");
86
86
 
87
87
  const WS_OPEN = WebSocket.OPEN;
88
88
  const WS_CLOSED = WebSocket.CLOSED;
@@ -91,7 +91,7 @@ function makeCredentials(values: Record<string, string | undefined>) {
91
91
  const assistantId =
92
92
  values[credentialKey("cadet", "platform_assistant_id")]?.trim();
93
93
  if (assistantId) {
94
- applyPlatformIdentityIds({
94
+ applyCloudIdentityIds({
95
95
  assistantId,
96
96
  organizationId: "",
97
97
  userId: "",
@@ -178,7 +178,6 @@ function makeConfig(overrides: Partial<GatewayConfig> = {}): GatewayConfig {
178
178
  runtimeMaxRetries: 0,
179
179
  runtimeProxyRequireAuth: true,
180
180
  runtimeTimeoutMs: 1,
181
- shutdownDrainMs: 1,
182
181
  trustProxy: false,
183
182
  ...overrides,
184
183
  };
@@ -270,10 +269,10 @@ async function flushPromises(): Promise<void> {
270
269
  }
271
270
 
272
271
  const originalAssistantApiKey = process.env.ASSISTANT_API_KEY;
273
- const originalPlatformUrl = process.env.CADET_PLATFORM_URL;
274
- const originalPlatformAssistantId = process.env.PLATFORM_ASSISTANT_ID;
275
- const originalPlatformOrgId = process.env.PLATFORM_ORGANIZATION_ID;
276
- const originalPlatformUserId = process.env.PLATFORM_USER_ID;
272
+ const originalCloudUrl = process.env.CADET_CLOUD_URL;
273
+ const originalCloudAssistantId = process.env.CLOUD_ASSISTANT_ID;
274
+ const originalCloudOrgId = process.env.CLOUD_ORGANIZATION_ID;
275
+ const originalCloudUserId = process.env.CLOUD_USER_ID;
277
276
 
278
277
  function restoreEnv(name: string, value: string | undefined): void {
279
278
  if (value === undefined) {
@@ -291,21 +290,21 @@ beforeEach(() => {
291
290
  webhookRouteReads = 0;
292
291
  fetchImplFn = async () => new Response("not found", { status: 404 });
293
292
  delete process.env.ASSISTANT_API_KEY;
294
- delete process.env.CADET_PLATFORM_URL;
295
- delete process.env.PLATFORM_ASSISTANT_ID;
296
- delete process.env.PLATFORM_ORGANIZATION_ID;
297
- delete process.env.PLATFORM_USER_ID;
298
- _resetPlatformIdentityForTests();
293
+ delete process.env.CADET_CLOUD_URL;
294
+ delete process.env.CLOUD_ASSISTANT_ID;
295
+ delete process.env.CLOUD_ORGANIZATION_ID;
296
+ delete process.env.CLOUD_USER_ID;
297
+ _resetCloudIdentityForTests();
299
298
  });
300
299
 
301
300
  afterEach(() => {
302
301
  rmSync(workspaceDir, { recursive: true, force: true });
303
302
  restoreEnv("ASSISTANT_API_KEY", originalAssistantApiKey);
304
- restoreEnv("CADET_PLATFORM_URL", originalPlatformUrl);
305
- restoreEnv("PLATFORM_ASSISTANT_ID", originalPlatformAssistantId);
306
- restoreEnv("PLATFORM_ORGANIZATION_ID", originalPlatformOrgId);
307
- restoreEnv("PLATFORM_USER_ID", originalPlatformUserId);
308
- _resetPlatformIdentityForTests();
303
+ restoreEnv("CADET_CLOUD_URL", originalCloudUrl);
304
+ restoreEnv("CLOUD_ASSISTANT_ID", originalCloudAssistantId);
305
+ restoreEnv("CLOUD_ORGANIZATION_ID", originalCloudOrgId);
306
+ restoreEnv("CLOUD_USER_ID", originalCloudUserId);
307
+ _resetCloudIdentityForTests();
309
308
  });
310
309
 
311
310
  describe("enablePublicIngress", () => {
@@ -368,7 +367,7 @@ describe("TunnelClient", () => {
368
367
  await client.stop();
369
368
  });
370
369
 
371
- test("opens a socket and registers when the platform assistant ID is missing", async () => {
370
+ test("opens a socket and registers when the cloud assistant ID is missing", async () => {
372
371
  const sockets: FakeWebSocket[] = [];
373
372
  const reconnectDelays: number[] = [];
374
373
  writeConfig({
@@ -629,7 +628,7 @@ describe("TunnelClient", () => {
629
628
  test("awaits validate before rejecting a mismatched registration", async () => {
630
629
  const sockets: FakeWebSocket[] = [];
631
630
  process.env.ASSISTANT_API_KEY = "api-key-123";
632
- process.env.CADET_PLATFORM_URL = "https://platform.example.com";
631
+ process.env.CADET_CLOUD_URL = "https://test-cloud.mycadet.ai";
633
632
  fetchImplFn = async () =>
634
633
  new Response(
635
634
  JSON.stringify({
@@ -785,7 +784,7 @@ describe("TunnelClient", () => {
785
784
  resolveFirstApiKeyRead = resolve;
786
785
  });
787
786
  let useFreshCredentials = false;
788
- applyPlatformIdentityIds({
787
+ applyCloudIdentityIds({
789
788
  assistantId: "asst-123",
790
789
  organizationId: "",
791
790
  userId: "",
@@ -9,9 +9,9 @@ import { credentialKey } from "../credential-key.js";
9
9
  import { mutateConfigFile } from "../config-file-utils.js";
10
10
  import { getLogger } from "../logger.js";
11
11
  import {
12
- ensurePlatformIdentityIds,
13
- peekPlatformAssistantId,
14
- } from "../platform-identity.js";
12
+ ensureCloudIdentityIds,
13
+ peekCloudAssistantId,
14
+ } from "../cloud-identity.js";
15
15
  import { ExponentialBackoff } from "../util/exponential-backoff.js";
16
16
  import { listWebhookIngressRoutes } from "../db/webhook-ingress-route-store.js";
17
17
  import {
@@ -33,6 +33,7 @@ import {
33
33
  TUNNEL_BINARY_WEBSOCKET_HEADER,
34
34
  } from "./binary-websocket.js";
35
35
  import { TunnelWebSocketBridge } from "./websocket-bridge.js";
36
+ import { getIsCloud } from "../cloud-url.js";
36
37
 
37
38
  const log = getLogger("tunnel-client");
38
39
 
@@ -335,8 +336,8 @@ export class TunnelClient {
335
336
  this.scheduleReconnect();
336
337
  return;
337
338
  }
338
- await ensurePlatformIdentityIds();
339
- const expectedAssistantId = peekPlatformAssistantId();
339
+ await ensureCloudIdentityIds();
340
+ const expectedAssistantId = peekCloudAssistantId();
340
341
 
341
342
  let registerUrl: string;
342
343
  try {
@@ -360,7 +361,7 @@ export class TunnelClient {
360
361
  // Declares the path allowlist Tunnel enforces for inbound proxied
361
362
  // traffic on this tunnel. Read per attempt so a reconnect picks up
362
363
  // webhook routes registered since the last one. See
363
- // ./allowed-paths.ts for the route inventory and the platform-side
364
+ // ./allowed-paths.ts for the route inventory and the cloud-side
364
365
  // enforcement (ATL-402).
365
366
  [TUNNEL_ALLOWED_PATHS_HEADER]: buildTunnelAllowedPathsHeaderValue(
366
367
  () => this.readRegisteredWebhookPaths(),
@@ -435,7 +436,7 @@ export class TunnelClient {
435
436
  private async handleMessage(
436
437
  data: unknown,
437
438
  originWs: WebSocket,
438
- platformAssistantId: string | undefined,
439
+ cloudAssistantId: string | undefined,
439
440
  ): Promise<void> {
440
441
  if (this.ws !== originWs || !this.running) return;
441
442
 
@@ -458,7 +459,7 @@ export class TunnelClient {
458
459
 
459
460
  switch (frame.type) {
460
461
  case TUNNEL_FRAME_TYPES.registered:
461
- await this.handleRegisteredFrame(frame, originWs, platformAssistantId);
462
+ await this.handleRegisteredFrame(frame, originWs, cloudAssistantId);
462
463
  return;
463
464
  case TUNNEL_FRAME_TYPES.httpRequest:
464
465
  await this.handleHttpRequestFrame(frame, originWs);
@@ -479,12 +480,12 @@ export class TunnelClient {
479
480
  private async handleRegisteredFrame(
480
481
  frame: TunnelRegisteredFrame,
481
482
  originWs: WebSocket,
482
- platformAssistantId: string | undefined,
483
+ cloudAssistantId: string | undefined,
483
484
  ): Promise<void> {
484
- if (platformAssistantId && frame.assistant_id !== platformAssistantId) {
485
+ if (cloudAssistantId && frame.assistant_id !== cloudAssistantId) {
485
486
  log.error(
486
487
  {
487
- expectedAssistantId: platformAssistantId,
488
+ expectedAssistantId: cloudAssistantId,
488
489
  receivedAssistantId: frame.assistant_id,
489
490
  },
490
491
  "Tunnel registered assistant ID mismatch",
@@ -793,12 +794,10 @@ export function createTunnelClient(
793
794
  },
794
795
  ): TunnelClient | undefined {
795
796
  if (!config.tunnelBaseUrl) {
796
- const isPlatform =
797
- process.env.IS_PLATFORM?.trim().toLowerCase() === "true" ||
798
- process.env.IS_PLATFORM?.trim() === "1";
799
- if (isPlatform) {
797
+ const isCloud = getIsCloud();
798
+ if (isCloud) {
800
799
  log.warn(
801
- "TUNNEL_BASE_URL is not configured on a platform pod — the assistant tunnel will not be established and inbound webhook delivery will fail",
800
+ "TUNNEL_BASE_URL is not configured on a cloud pod — the assistant tunnel will not be established and inbound webhook delivery will fail",
802
801
  );
803
802
  }
804
803
  void clearManagedPublicBaseUrl(deps.configFile).catch((err) => {
@@ -845,7 +844,7 @@ async function mutateGatewayConfigFile(
845
844
 
846
845
  const TUNNEL_MANAGED_BY = "tunnel";
847
846
 
848
- async function writeManagedPublicBaseUrl(
847
+ export async function writeManagedPublicBaseUrl(
849
848
  publicUrl: string,
850
849
  configFile: ConfigFileCache,
851
850
  ): Promise<void> {
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Registers a `cadet-shared` invite with the platform, which routes the
3
- * invitee's redemption back to this assistant. The platform receives only the
2
+ * Registers a `cadet-shared` invite with the cloud, which routes the
3
+ * invitee's redemption back to this assistant. The cloud receives only the
4
4
  * link-token hash and the invite's expiry, never the token itself.
5
5
  */
6
6
 
@@ -10,7 +10,7 @@ import { credentialKey } from "../credential-key.js";
10
10
  import { readCredentialResult } from "../credential-reader.js";
11
11
  import { fetchImpl } from "../fetch.js";
12
12
  import {
13
- arePlatformFeaturesEnabled,
13
+ areCloudFeaturesEnabled,
14
14
  isFeatureFlagEnabled,
15
15
  } from "../feature-flag-resolver.js";
16
16
  import { getLogger } from "../logger.js";
@@ -26,9 +26,9 @@ const REGISTRATION_TIMEOUT_MS = 10_000;
26
26
  export type SharedInviteRegistrationResult =
27
27
  /** Registered, or nothing to register for this invite or gateway. */
28
28
  | { status: "registered" | "skipped" }
29
- /** The platform already holds this hash. */
29
+ /** The cloud already holds this hash. */
30
30
  | { status: "duplicate" }
31
- /** The platform refused another outstanding invite. */
31
+ /** The cloud refused another outstanding invite. */
32
32
  | { status: "limit_reached" }
33
33
  /** The credential store could not be read. */
34
34
  | { status: "unavailable" }
@@ -39,8 +39,8 @@ export type SharedInviteRegistrationResult =
39
39
  * Store value when present, else the environment fallback. `unreachable` is
40
40
  * set only when the store could not be read and no fallback exists.
41
41
  */
42
- async function readPlatformCredential(
43
- field: "platform_base_url" | "assistant_api_key",
42
+ async function readCloudCredential(
43
+ field: "assistant_api_key",
44
44
  envName: string,
45
45
  ): Promise<{ value: string; unreachable: boolean }> {
46
46
  const stored = await readCredentialResult(credentialKey("cadet", field));
@@ -49,7 +49,7 @@ async function readPlatformCredential(
49
49
  }
50
50
 
51
51
  /**
52
- * Register the invite's link-token hash and expiry with the platform.
52
+ * Register the invite's link-token hash and expiry with the cloud.
53
53
  *
54
54
  * Skipped for any channel other than `cadet-shared`, while the
55
55
  * trusted-contacts flag is off, when platform features are disabled, and when
@@ -63,28 +63,33 @@ export async function registerSharedInvite(params: {
63
63
  if (
64
64
  params.sourceChannel !== SHARED_INVITE_CHANNEL ||
65
65
  !isFeatureFlagEnabled(TRUSTED_CONTACTS_FLAG) ||
66
- !arePlatformFeaturesEnabled()
66
+ !areCloudFeaturesEnabled()
67
67
  ) {
68
68
  return { status: "skipped" };
69
69
  }
70
70
 
71
- const [baseUrl, apiKey] = await Promise.all([
72
- readPlatformCredential("platform_base_url", "CADET_PLATFORM_URL"),
73
- readPlatformCredential("assistant_api_key", "ASSISTANT_API_KEY"),
71
+ const [cloudBaseUrl, apiKey] = await Promise.all([
72
+ Promise.resolve(
73
+ (process.env.CADET_CLOUD_URL?.trim() || "").replace(/\/+$/, ""),
74
+ ),
75
+ readCloudCredential("assistant_api_key", "ASSISTANT_API_KEY"),
74
76
  ]);
75
- if (baseUrl.unreachable || apiKey.unreachable) {
77
+ if (apiKey.unreachable) {
76
78
  log.warn("Shared invite registration: credential store unreachable");
77
79
  return { status: "unavailable" };
78
80
  }
79
- if (!baseUrl.value || !apiKey.value) {
81
+ if (!cloudBaseUrl || !apiKey.value) {
80
82
  log.debug(
81
- { hasPlatformBaseUrl: !!baseUrl.value, hasApiKey: !!apiKey.value },
83
+ {
84
+ hasPlatformBaseUrl: !!cloudBaseUrl,
85
+ hasApiKey: !!apiKey.value,
86
+ },
82
87
  "Shared invite registration skipped: no cloud credentials",
83
88
  );
84
89
  return { status: "skipped" };
85
90
  }
86
91
 
87
- const url = `${baseUrl.value.replace(/\/+$/, "")}${SHARED_INVITE_REGISTRATION_PATH}`;
92
+ const url = `${cloudBaseUrl}${SHARED_INVITE_REGISTRATION_PATH}`;
88
93
  let response: Response;
89
94
  try {
90
95
  response = await fetchImpl(url, {
@@ -109,7 +114,7 @@ export async function registerSharedInvite(params: {
109
114
  }
110
115
  log.warn(
111
116
  { status: response.status },
112
- "Shared invite registration refused by the platform",
117
+ "Shared invite registration refused by the cloud",
113
118
  );
114
119
  if (response.status === 409) {
115
120
  return { status: "duplicate" };
package/src/version.ts CHANGED
@@ -28,7 +28,7 @@ export const APP_VERSION: string = resolveVersion();
28
28
 
29
29
  /**
30
30
  * Header name for the assistant version returned in every gateway response.
31
- * Allows the platform to trace which build handled a request.
31
+ * Allows the cloud to trace which build handled a request.
32
32
  */
33
33
  export const VERSION_HEADER_NAME = "X-Cadet-Assistant-Version";
34
34
 
@@ -1,24 +0,0 @@
1
- import type { CredentialCache } from "./credential-cache.js";
2
- import { credentialKey } from "./credential-key.js";
3
-
4
- /**
5
- * Resolve the platform base URL from the credential cache, falling back to
6
- * the `CADET_PLATFORM_URL` environment variable. Returns `undefined` when
7
- * neither source provides a value.
8
- *
9
- * The returned URL is trimmed and has any trailing slashes removed so callers
10
- * can safely append path segments.
11
- */
12
- export async function getPlatformBaseUrl(
13
- credentials: CredentialCache,
14
- ): Promise<string | undefined> {
15
- const raw = await credentials.get(
16
- credentialKey("cadet", "platform_base_url"),
17
- );
18
- const url = (
19
- raw?.trim() ||
20
- process.env.CADET_PLATFORM_URL?.trim() ||
21
- ""
22
- ).replace(/\/+$/, "");
23
- return url || undefined;
24
- }