@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
@@ -8,9 +8,9 @@ import {
8
8
  resetMockFetch,
9
9
  } from "../__tests__/mock-fetch.js";
10
10
  import {
11
- applyPlatformIdentityIds,
12
- _resetPlatformIdentityForTests,
13
- } from "../platform-identity.js";
11
+ applyCloudIdentityIds,
12
+ _resetCloudIdentityForTests,
13
+ } from "../cloud-identity.js";
14
14
  import {
15
15
  registerEmailCallbackRoute,
16
16
  EMAIL_CALLBACK_PATH,
@@ -18,9 +18,9 @@ import {
18
18
 
19
19
  afterEach(() => {
20
20
  resetMockFetch();
21
- delete process.env.CADET_PLATFORM_URL;
21
+ delete process.env.CADET_CLOUD_URL;
22
22
  delete process.env.ASSISTANT_API_KEY;
23
- _resetPlatformIdentityForTests();
23
+ _resetCloudIdentityForTests();
24
24
  });
25
25
 
26
26
  function makeConfigFile(
@@ -34,29 +34,22 @@ function makeConfigFile(
34
34
  }
35
35
 
36
36
  function makeCaches(opts: {
37
- platformBaseUrl?: string;
37
+ cloudBaseUrl?: string;
38
38
  assistantApiKey?: string;
39
- platformAssistantId?: string;
39
+ cloudAssistantId?: string;
40
40
  ingressUrl?: string;
41
41
  }): { credentials: CredentialCache; configFile?: ConfigFileCache } {
42
42
  const store = new Map<string, string>();
43
- if (opts.platformBaseUrl)
44
- store.set(
45
- credentialKey("cadet", "platform_base_url"),
46
- opts.platformBaseUrl,
47
- );
43
+ if (opts.cloudBaseUrl)
44
+ process.env.CADET_CLOUD_URL = opts.cloudBaseUrl;
48
45
  if (opts.assistantApiKey)
49
46
  store.set(
50
47
  credentialKey("cadet", "assistant_api_key"),
51
48
  opts.assistantApiKey,
52
49
  );
53
- if (opts.platformAssistantId) {
54
- store.set(
55
- credentialKey("cadet", "platform_assistant_id"),
56
- opts.platformAssistantId,
57
- );
58
- applyPlatformIdentityIds({
59
- assistantId: opts.platformAssistantId,
50
+ if (opts.cloudAssistantId) {
51
+ applyCloudIdentityIds({
52
+ assistantId: opts.cloudAssistantId,
60
53
  organizationId: "org-abc",
61
54
  userId: "user-123",
62
55
  });
@@ -95,13 +88,13 @@ describe("registerEmailCallbackRoute", () => {
95
88
 
96
89
  test("registers callback route with platform via credential cache", async () => {
97
90
  const caches = makeCaches({
98
- platformBaseUrl: "https://platform.example.com",
91
+ cloudBaseUrl: "https://test-cloud.mycadet.ai",
99
92
  assistantApiKey: "test-api-key",
100
- platformAssistantId: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
93
+ cloudAssistantId: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
101
94
  });
102
95
 
103
96
  const callbackUrl =
104
- "https://platform.example.com/v1/gateway/callbacks/aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee/webhooks/email/";
97
+ "https://test-cloud.mycadet.ai/v1/gateway/callbacks/aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee/webhooks/email/";
105
98
 
106
99
  mockFetch(
107
100
  "callback-routes/register",
@@ -130,7 +123,7 @@ describe("registerEmailCallbackRoute", () => {
130
123
  });
131
124
 
132
125
  test("uses env assistant key with credential cache for assistant ID", async () => {
133
- process.env.CADET_PLATFORM_URL = "https://env-platform.example.com";
126
+ process.env.CADET_CLOUD_URL = "https://env-platform.example.com";
134
127
  process.env.ASSISTANT_API_KEY = "env-key";
135
128
 
136
129
  const callbackUrl =
@@ -146,7 +139,7 @@ describe("registerEmailCallbackRoute", () => {
146
139
  );
147
140
 
148
141
  const caches = makeCaches({
149
- platformAssistantId: "11111111-2222-3333-4444-555555555555",
142
+ cloudAssistantId: "11111111-2222-3333-4444-555555555555",
150
143
  });
151
144
 
152
145
  const result = await registerEmailCallbackRoute(caches);
@@ -161,9 +154,9 @@ describe("registerEmailCallbackRoute", () => {
161
154
 
162
155
  test("throws on non-ok response", async () => {
163
156
  const caches = makeCaches({
164
- platformBaseUrl: "https://platform.example.com",
157
+ cloudBaseUrl: "https://test-cloud.mycadet.ai",
165
158
  assistantApiKey: "test-api-key",
166
- platformAssistantId: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
159
+ cloudAssistantId: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
167
160
  });
168
161
 
169
162
  mockFetch(
@@ -179,9 +172,9 @@ describe("registerEmailCallbackRoute", () => {
179
172
 
180
173
  test("throws when response has no callback_url", async () => {
181
174
  const caches = makeCaches({
182
- platformBaseUrl: "https://platform.example.com",
175
+ cloudBaseUrl: "https://test-cloud.mycadet.ai",
183
176
  assistantApiKey: "test-api-key",
184
- platformAssistantId: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
177
+ cloudAssistantId: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
185
178
  });
186
179
 
187
180
  mockFetch(
@@ -200,9 +193,9 @@ describe("registerEmailCallbackRoute", () => {
200
193
 
201
194
  test("sends callback_base_url when ingress URL is configured (self-hosted)", async () => {
202
195
  const caches = makeCaches({
203
- platformBaseUrl: "https://platform.example.com",
196
+ cloudBaseUrl: "https://test-cloud.mycadet.ai",
204
197
  assistantApiKey: "vak_selfhosted",
205
- platformAssistantId: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
198
+ cloudAssistantId: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
206
199
  ingressUrl: "https://my-assistant.example.com",
207
200
  });
208
201
 
@@ -233,15 +226,15 @@ describe("registerEmailCallbackRoute", () => {
233
226
  });
234
227
  });
235
228
 
236
- test("omits callback_base_url when no ingress URL is configured (platform-managed)", async () => {
229
+ test("omits callback_base_url when no ingress URL is configured (cloud-managed)", async () => {
237
230
  const caches = makeCaches({
238
- platformBaseUrl: "https://platform.example.com",
231
+ cloudBaseUrl: "https://test-cloud.mycadet.ai",
239
232
  assistantApiKey: "vak_managed",
240
- platformAssistantId: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
233
+ cloudAssistantId: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
241
234
  });
242
235
 
243
236
  const callbackUrl =
244
- "https://platform.example.com/v1/gateway/callbacks/aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee/webhooks/email/";
237
+ "https://test-cloud.mycadet.ai/v1/gateway/callbacks/aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee/webhooks/email/";
245
238
 
246
239
  mockFetch(
247
240
  "callback-routes/register",
@@ -2,14 +2,14 @@ import type { ConfigFileCache } from "../config-file-cache.js";
2
2
  import type { CredentialCache } from "../credential-cache.js";
3
3
  import { credentialKey } from "../credential-key.js";
4
4
  import { fetchImpl } from "../fetch.js";
5
- import { arePlatformFeaturesEnabled } from "../feature-flag-resolver.js";
5
+ import { areCloudFeaturesEnabled } from "../feature-flag-resolver.js";
6
6
  import { getLogger } from "../logger.js";
7
- import { resolvePlatformAssistantIdOrUndefined } from "../platform-identity.js";
7
+ import { resolveCloudAssistantIdOrUndefined } from "../cloud-identity.js";
8
8
 
9
9
  const log = getLogger("email-callback");
10
10
 
11
11
  /**
12
- * The callback path registered with the platform for inbound email webhooks.
12
+ * The callback path registered with the cloud for inbound email webhooks.
13
13
  * Must match the gateway route path in index.ts ("/webhooks/email").
14
14
  */
15
15
  export const EMAIL_CALLBACK_PATH = "webhooks/email";
@@ -26,39 +26,34 @@ interface PlatformCallbackRouteResponse {
26
26
  * Follows the same pattern as Telegram's managed callback route registration
27
27
  * in `telegram/webhook-manager.ts`. Requires cloud credentials (base URL,
28
28
  * assistant API key, assistant ID). The base URL can fall back to
29
- * `CADET_PLATFORM_URL`; the key can fall back to `ASSISTANT_API_KEY`.
29
+ * `CADET_CLOUD_URL`; the key can fall back to `ASSISTANT_API_KEY`.
30
30
  *
31
31
  * Self-hosted assistants with a configured ``ingress.publicBaseUrl`` send
32
32
  * their own base URL so the callback route points directly at the gateway
33
- * rather than through the platform proxy.
33
+ * rather than through the cloud proxy.
34
34
  *
35
- * Returns the platform-assigned callback URL on success, or `undefined` if
35
+ * Returns the cloud-assigned callback URL on success, or `undefined` if
36
36
  * credentials are not available.
37
37
  */
38
38
  export async function registerEmailCallbackRoute(caches?: {
39
39
  credentials?: CredentialCache;
40
40
  configFile?: ConfigFileCache;
41
41
  }): Promise<string | undefined> {
42
- if (!arePlatformFeaturesEnabled()) {
42
+ if (!areCloudFeaturesEnabled()) {
43
43
  log.debug(
44
44
  "Platform features disabled — skipping email callback registration",
45
45
  );
46
46
  return undefined;
47
47
  }
48
48
 
49
- const [platformBaseUrlRaw, assistantApiKeyRaw] = caches?.credentials
50
- ? await Promise.all([
51
- caches.credentials.get(credentialKey("cadet", "platform_base_url")),
52
- caches.credentials.get(credentialKey("cadet", "assistant_api_key")),
53
- ])
54
- : [undefined, undefined];
55
-
56
- // Fall back to env vars when managed pod credentials are not yet cached,
57
- // matching the daemon's resolvePlatformCallbackRegistrationContext().
58
- const platformBaseUrl = (
59
- platformBaseUrlRaw?.trim() ||
60
- process.env.CADET_PLATFORM_URL?.trim() ||
61
- ""
49
+ const assistantApiKeyRaw = caches?.credentials
50
+ ? await caches.credentials.get(credentialKey("cadet", "assistant_api_key"))
51
+ : undefined;
52
+
53
+ // The base URL resolves from the environment only — the credential store
54
+ // never carries it.
55
+ const cloudBaseUrl = (
56
+ process.env.CADET_CLOUD_URL?.trim() || ""
62
57
  ).replace(/\/+$/, "");
63
58
 
64
59
  const assistantCredential =
@@ -66,12 +61,12 @@ export async function registerEmailCallbackRoute(caches?: {
66
61
  process.env.ASSISTANT_API_KEY?.trim() ||
67
62
  undefined;
68
63
 
69
- const assistantId = await resolvePlatformAssistantIdOrUndefined();
64
+ const assistantId = await resolveCloudAssistantIdOrUndefined();
70
65
 
71
- if (!platformBaseUrl || !assistantCredential || !assistantId) {
66
+ if (!cloudBaseUrl || !assistantCredential || !assistantId) {
72
67
  log.debug(
73
68
  {
74
- hasPlatformBaseUrl: !!platformBaseUrl,
69
+ hasPlatformBaseUrl: !!cloudBaseUrl,
75
70
  hasApiKey: !!assistantCredential,
76
71
  hasAssistantId: !!assistantId,
77
72
  },
@@ -80,9 +75,9 @@ export async function registerEmailCallbackRoute(caches?: {
80
75
  return undefined;
81
76
  }
82
77
 
83
- // Self-hosted assistants send their public ingress URL so the platform
78
+ // Self-hosted assistants send their public ingress URL so the cloud
84
79
  // registers a callback pointing directly at the gateway rather than
85
- // routing through the platform proxy (matching Telegram's two-tier
80
+ // routing through the cloud proxy (matching Telegram's two-tier
86
81
  // pattern in telegram/webhook-manager.ts).
87
82
  const ingressUrl = caches?.configFile
88
83
  ?.getString("ingress", "publicBaseUrl")
@@ -106,7 +101,7 @@ export async function registerEmailCallbackRoute(caches?: {
106
101
  }
107
102
 
108
103
  const response = await fetchImpl(
109
- `${platformBaseUrl}/v1/internal/gateway/callback-routes/register/`,
104
+ `${cloudBaseUrl}/v1/internal/gateway/callback-routes/register/`,
110
105
  {
111
106
  method: "POST",
112
107
  headers: {
@@ -82,7 +82,7 @@
82
82
  "scope": "client",
83
83
  "key": "multi-platform-assistant",
84
84
  "label": "Multi-Platform Assistant Switcher",
85
- "description": "Enable the menu-bar assistant switcher for managing multiple platform-hosted assistants (new/switch/retire)",
85
+ "description": "Enable the menu-bar assistant switcher for managing multiple cloud-hosted assistants (new/switch/retire)",
86
86
  "defaultEnabled": false
87
87
  },
88
88
  {
@@ -138,7 +138,7 @@
138
138
  "scope": "client",
139
139
  "key": "fork-from-message",
140
140
  "label": "Internal Thread Actions (legacy key)",
141
- "description": "Legacy key for `internal-thread-actions`. The client grants the internal thread affordances when either key is enabled, so the platform may serve the gate under either name. Declared here so the flag mapper keeps the value instead of dropping it as undeclared.",
141
+ "description": "Legacy key for `internal-thread-actions`. The client grants the internal thread affordances when either key is enabled, so the cloud may serve the gate under either name. Declared here so the flag mapper keeps the value instead of dropping it as undeclared.",
142
142
  "defaultEnabled": false
143
143
  },
144
144
  {
@@ -378,7 +378,7 @@
378
378
  "scope": "client",
379
379
  "key": "push-avatar-sender",
380
380
  "label": "Push Avatar Sender",
381
- "description": "Native notifications show the assistant's avatar as the icon with the assistant's name on line one. Same key the platform reads for APNs/FCM sender blocks.",
381
+ "description": "Native notifications show the assistant's avatar as the icon with the assistant's name on line one. Same key the cloud reads for APNs/FCM sender blocks.",
382
382
  "defaultEnabled": false
383
383
  },
384
384
  {
@@ -450,7 +450,7 @@
450
450
  "scope": "assistant",
451
451
  "key": "tunnel-webhooks",
452
452
  "label": "Tunnel Webhooks",
453
- "description": "Platform pods resolve webhook callback URLs from the Tunnel-published ingress URL instead of registering platform callback routes. Falls back to platform callback registration while no tunnel URL is published.",
453
+ "description": "Cloud pods resolve webhook callback URLs from the Tunnel-published ingress URL instead of registering platform callback routes. Falls back to platform callback registration while no tunnel URL is published.",
454
454
  "defaultEnabled": false
455
455
  },
456
456
  {
@@ -483,7 +483,7 @@
483
483
  "scope": "assistant",
484
484
  "key": "assistant-desktop",
485
485
  "label": "Virtual desktop",
486
- "description": "Streams an interactive virtual desktop from a platform-hosted, containerized assistant over /v1/desktop/stream. Requires platform hosting; self-hosted assistants are excluded. Off: the virtual desktop is hidden. On: the chat header offers its viewer and controls.",
486
+ "description": "Streams an interactive virtual desktop from a cloud-hosted, containerized assistant over /v1/desktop/stream. Requires platform hosting; self-hosted assistants are excluded. Off: the virtual desktop is hidden. On: the chat header offers its viewer and controls.",
487
487
  "defaultEnabled": false
488
488
  },
489
489
  {
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Gateway-side remote feature flag store — file-backed persistence of
3
- * feature flag values pushed from the platform.
3
+ * feature flag values pushed from the cloud.
4
4
  *
5
5
  * Mirrors the feature-flag-store.ts pattern: file path resolution via
6
6
  * getGatewaySecurityDir(), atomic writes (temp file + rename), 0o600
7
7
  * permissions, and module-level caching with manual invalidation.
8
8
  *
9
9
  * Unlike the local override store, writes replace the *entire* value map at
10
- * once (the platform pushes a complete snapshot) and immediately update the
10
+ * once (the cloud pushes a complete snapshot) and immediately update the
11
11
  * in-memory cache so no file watcher is needed.
12
12
  */
13
13
 
@@ -40,13 +40,13 @@ export function isFeatureFlagEnabled(key: string): boolean {
40
40
  return !!getFeatureFlagValue(key);
41
41
  }
42
42
 
43
- export function isPlatformMode(): boolean {
44
- const v = process.env.IS_PLATFORM?.trim().toLowerCase();
43
+ export function isCloudServedBuild(): boolean {
44
+ const v = process.env.IS_CLOUD?.trim().toLowerCase();
45
45
  return v === "true" || v === "1";
46
46
  }
47
47
 
48
- export function arePlatformFeaturesEnabled(): boolean {
49
- if (isPlatformMode()) return true;
50
- const v = process.env.CADET_DISABLE_PLATFORM?.trim().toLowerCase();
48
+ export function areCloudFeaturesEnabled(): boolean {
49
+ if (isCloudServedBuild()) return true;
50
+ const v = process.env.CADET_DISABLE_CLOUD?.trim().toLowerCase();
51
51
  return !(v === "true" || v === "1");
52
52
  }
@@ -2,7 +2,7 @@
2
2
  * Verification for the `Cadet-Signature` header.
3
3
  *
4
4
  * The signer computes `HMAC-SHA256(secret, rawBody)` and sends it as
5
- * `Cadet-Signature: sha256=<hex-digest>`. The scheme is the platform's, but
5
+ * `Cadet-Signature: sha256=<hex-digest>`. The scheme is the cloud's, but
6
6
  * nothing about it is platform-specific — plugin webhook routes verify the
7
7
  * same header against the plugin's own secret.
8
8
  */
@@ -13,7 +13,7 @@
13
13
  * Loopback-only endpoints (`/v1/guardian/init`, `/v1/pair`) treat its presence
14
14
  * as proof that the request did NOT arrive directly from a local loopback
15
15
  * client: it was forwarded by the edge proxy, possibly from a remote browser
16
- * over a tunnel (e.g. ngrok). Because every hop in that chain is loopback
16
+ * over a tunnel (e.g. a third-party tunnel). Because every hop in that chain is loopback
17
17
  * (browser → tunnel agent → nginx@127.0.0.1 → gateway@127.0.0.1), the raw TCP
18
18
  * peer is 127.0.0.1 and a peer-IP loopback check alone would misclassify the
19
19
  * caller as local. This marker is the reliable signal instead — and crucially
@@ -91,7 +91,7 @@ export function enforceLoopbackOnly(
91
91
  return errorResponse("FORBIDDEN", "endpoint is local-only", 403);
92
92
  }
93
93
 
94
- // The self-hosted nginx edge (e.g. the SPA over an ngrok tunnel) sets this
94
+ // The self-hosted nginx edge (e.g. the SPA over a tunnel) sets this
95
95
  // marker unconditionally; it cannot be spoofed or stripped by the client.
96
96
  if (requestArrivedViaEdgeProxy(req)) {
97
97
  auditDeny(req, clientIp, auditTag, "edge_proxy_forwarded");
@@ -13,7 +13,7 @@ import { AuthFallbackCountTracker } from "../../auth-fallback-count-tracker.js";
13
13
  import { AuthFallbackLogThrottle } from "../../auth-fallback-log-throttle.js";
14
14
  import type { AuthRateLimiter } from "../../auth-rate-limiter.js";
15
15
  import { getLogger } from "../../logger.js";
16
- import { readStoredPlatformUserId } from "../../platform-user-id.js";
16
+ import { readStoredCloudUserId } from "../../cloud-user-id.js";
17
17
  import { isLoopbackPeer } from "../../util/is-loopback-address.js";
18
18
  import { requestArrivedViaEdgeProxy } from "../edge-forwarded-header.js";
19
19
 
@@ -34,34 +34,34 @@ export const loopbackFallbackCountTracker = new AuthFallbackCountTracker();
34
34
  type GetClientIp = () => string;
35
35
 
36
36
  // ---------------------------------------------------------------------------
37
- // Platform-managed auth bypass — DISABLE_HTTP_AUTH + IS_PLATFORM
37
+ // Platform-managed auth bypass — DISABLE_HTTP_AUTH + IS_CLOUD
38
38
  // ---------------------------------------------------------------------------
39
39
  //
40
40
  // Both flags must be set together to disable JWT validation. DISABLE_HTTP_AUTH
41
41
  // alone is insufficient — it closes the accidental misconfig case where the
42
- // flag gets set on a non-platform deployment (e.g. a leaked dev env var on a
43
- // public host). When the bypass IS active, the platform vembda sidecar is
42
+ // flag gets set on a non-cloud deployment (e.g. a leaked dev env var on a
43
+ // public host). When the bypass IS active, the cloud vembda sidecar is
44
44
  // expected to forward `X-Cadet-User-Id`; the gateway cross-checks that
45
45
  // against the bound platform user id. This means reaching the gateway
46
46
  // sidecar's port directly (without going through vembda) still requires
47
- // knowing the bound user id. The platform header alone is not a free-pass.
47
+ // knowing the bound user id. The cloud header alone is not a free-pass.
48
48
 
49
49
  /** True when DISABLE_HTTP_AUTH=true. */
50
50
  export function isHttpAuthDisabled(): boolean {
51
51
  return process.env.DISABLE_HTTP_AUTH?.trim().toLowerCase() === "true";
52
52
  }
53
53
 
54
- /** True when IS_PLATFORM is set (vembda-managed deployment). */
54
+ /** True when IS_CLOUD is set (vembda-managed deployment). */
55
55
  function isPlatformManaged(): boolean {
56
- const v = process.env.IS_PLATFORM?.trim();
56
+ const v = process.env.IS_CLOUD?.trim();
57
57
  return v === "1" || v?.toLowerCase() === "true";
58
58
  }
59
59
 
60
60
  /**
61
- * True when the platform-managed auth bypass is in effect — both flags set.
61
+ * True when the cloud-managed auth bypass is in effect — both flags set.
62
62
  * Either alone leaves JWT validation in place.
63
63
  */
64
- function isPlatformAuthBypassActive(): boolean {
64
+ function isCloudAuthBypassActive(): boolean {
65
65
  return isHttpAuthDisabled() && isPlatformManaged();
66
66
  }
67
67
 
@@ -75,14 +75,14 @@ export function logAuthBypassState(): void {
75
75
  }
76
76
  if (isPlatformManaged()) {
77
77
  log.info(
78
- "DISABLE_HTTP_AUTH + IS_PLATFORM both set: JWT validation bypassed; " +
78
+ "DISABLE_HTTP_AUTH + IS_CLOUD both set: JWT validation bypassed; " +
79
79
  "X-Cadet-User-Id is cross-checked against the bound platform user id",
80
80
  );
81
81
  } else {
82
82
  log.warn(
83
- "DISABLE_HTTP_AUTH is set but IS_PLATFORM is NOT — bypass is INACTIVE. " +
84
- "JWT validation runs as normal. Set IS_PLATFORM=true to opt into the " +
85
- "platform-managed auth model.",
83
+ "DISABLE_HTTP_AUTH is set but IS_CLOUD is NOT — bypass is INACTIVE. " +
84
+ "JWT validation runs as normal. Set IS_CLOUD=true to opt into the " +
85
+ "cloud-managed auth model.",
86
86
  );
87
87
  }
88
88
  }
@@ -94,14 +94,14 @@ export function logAuthBypassState(): void {
94
94
  * clients. Each fallback endpoint and failure kind logs once per cooldown
95
95
  * window (see `loopbackFallbackLogThrottle`) so callers still missing or
96
96
  * failing auth are visible during rollout without per-request log noise. The
97
- * platform-managed bypass is checked first, so this fallback only applies in
97
+ * cloud-managed bypass is checked first, so this fallback only applies in
98
98
  * default mode.
99
99
  *
100
100
  * - `requireEdgeAuth` — validates a JWT bearer token (aud=cadet-gateway)
101
101
  * OR (when bypass is active) cross-checks X-Cadet-User-Id against the
102
102
  * bound platform user id.
103
103
  * - `requireEdgeAuthWithScope` — same, plus a scope-profile check on the
104
- * decoded JWT. Under the platform bypass, scope is enforced upstream by
104
+ * decoded JWT. Under the cloud bypass, scope is enforced upstream by
105
105
  * vembda; the gateway only verifies the cross-checked user id.
106
106
  * - `requireEdgeGuardianAuth` — same pattern, additionally requires the
107
107
  * authenticated principal to match the bound guardian.
@@ -117,7 +117,7 @@ export function createAuthMiddleware(
117
117
  ) {
118
118
  /**
119
119
  * Cross-check `X-Cadet-User-Id` against the bound platform user id.
120
- * Used by all three guards under the platform-managed bypass. Returns
120
+ * Used by all three guards under the cloud-managed bypass. Returns
121
121
  * null on success, or a 4xx/5xx Response.
122
122
  */
123
123
  async function requirePlatformUserHeader(
@@ -134,7 +134,7 @@ export function createAuthMiddleware(
134
134
  let storedUserId: string | undefined;
135
135
  let unreachable = false;
136
136
  try {
137
- const result = await readStoredPlatformUserId();
137
+ const result = await readStoredCloudUserId();
138
138
  storedUserId = result.userId;
139
139
  unreachable = result.unreachable;
140
140
  } catch (err) {
@@ -177,7 +177,7 @@ export function createAuthMiddleware(
177
177
  req: Request,
178
178
  server?: Server<unknown>,
179
179
  ): Promise<Response | null> {
180
- if (isPlatformAuthBypassActive()) {
180
+ if (isCloudAuthBypassActive()) {
181
181
  return requirePlatformUserHeader(req);
182
182
  }
183
183
  const hasAuthHeader = hasAuthorizationHeader(req);
@@ -194,7 +194,7 @@ export function createAuthMiddleware(
194
194
  /**
195
195
  * Validate a JWT bearer token and check that its scope profile includes the
196
196
  * required scope. Loopback peers fall back when auth is missing, malformed,
197
- * invalid, or under-scoped. Under the platform bypass, scope is enforced
197
+ * invalid, or under-scoped. Under the cloud bypass, scope is enforced
198
198
  * upstream by vembda — the gateway only confirms the user id.
199
199
  */
200
200
  async function requireEdgeAuthWithScope(
@@ -202,7 +202,7 @@ export function createAuthMiddleware(
202
202
  scope: Scope,
203
203
  server?: Server<unknown>,
204
204
  ): Promise<Response | null> {
205
- if (isPlatformAuthBypassActive()) {
205
+ if (isCloudAuthBypassActive()) {
206
206
  return requirePlatformUserHeader(req);
207
207
  }
208
208
  const hasAuthHeader = hasAuthorizationHeader(req);
@@ -233,7 +233,7 @@ export function createAuthMiddleware(
233
233
  *
234
234
  * Two auth modes:
235
235
  *
236
- * 1. Platform-managed (DISABLE_HTTP_AUTH + IS_PLATFORM): caller's identity
236
+ * 1. Platform-managed (DISABLE_HTTP_AUTH + IS_CLOUD): caller's identity
237
237
  * is asserted via X-Cadet-User-Id cross-checked against the bound
238
238
  * platform user id.
239
239
  * 2. Default: validate the edge JWT, require an actor principal, assert it
@@ -246,7 +246,7 @@ export function createAuthMiddleware(
246
246
  req: Request,
247
247
  server?: Server<unknown>,
248
248
  ): Promise<Response | null> {
249
- if (isPlatformAuthBypassActive()) {
249
+ if (isCloudAuthBypassActive()) {
250
250
  return requirePlatformUserHeader(req);
251
251
  }
252
252
  return requireEdgeGuardianAuthByActorPrincipal(req, server);
@@ -22,7 +22,7 @@ export type GetRawPeerIp = () => string;
22
22
  * - "edge-guardian" — caller must be the bound cadet guardian. In the default
23
23
  * path, edge JWT is validated and the caller's actor
24
24
  * principal must match the guardian's principal id.
25
- * When DISABLE_HTTP_AUTH=true (platform-managed), the
25
+ * When DISABLE_HTTP_AUTH=true (cloud-managed), the
26
26
  * caller is asserted via X-Cadet-User-Id forwarded by
27
27
  * vembda, cross-referenced with the bound platform
28
28
  * user id.
@@ -55,7 +55,7 @@ export const ROUTES: GatewayRouteDefinition[] = [
55
55
  operationId: "conversationThresholdGet",
56
56
  summary: "Get a conversation's threshold override",
57
57
  description:
58
- "Returns { threshold: null } when no override exists. (Gateways predating that behavior returned 404 for the same condition; clients tolerate both during rollout.)",
58
+ "Returns { threshold: null } when no override exists. Gateways predating that behavior returned 404 for the same condition; clients tolerate both during rollout.",
59
59
  tags: ["permissions"],
60
60
  pathParameters: [
61
61
  { name: "conversation_id", description: "The conversation id" },
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Cadet identity validation — platform-managed email.
2
+ * Cadet identity validation — cloud-managed email.
3
3
  *
4
- * The route's edge-scoped auth already authenticates the platform,
4
+ * The route's edge-scoped auth already authenticates the cloud,
5
5
  * so no external API key validation is needed.
6
6
  */
7
7
 
@@ -44,7 +44,7 @@ export const ROUTES: GatewayRouteDefinition[] = [
44
44
  operationId: "channelAdmissionPolicyList",
45
45
  summary: "List per-channel admission floors",
46
46
  description:
47
- "Returns one entry per enforced channel (exempt and hidden channels are omitted), seeded with defaults for channels without a stored row.",
47
+ "Returns one entry per enforced channel, excluding exempt and hidden channels, seeded with defaults for channels without a stored row.",
48
48
  tags: ["channel-admission-policy"],
49
49
  responseBody: z.object({
50
50
  policies: z.array(ChannelPolicyViewSchema),
@@ -59,7 +59,7 @@ export const ROUTES: GatewayRouteDefinition[] = [
59
59
  "Upserts the channel's admission policy. Exempt and hidden channels return 403.",
60
60
  tags: ["channel-admission-policy"],
61
61
  pathParameters: [
62
- { name: "channel_type", description: "The channel type (e.g. slack)" },
62
+ { name: "channel_type", description: "The channel type, e.g. slack" },
63
63
  ],
64
64
  requestBody: SetChannelPolicyRequestSchema,
65
65
  responseBody: z.object({ policy: ChannelPolicyViewSchema }),
@@ -9,7 +9,7 @@ import type { GatewayRouteDefinition } from "./types.js";
9
9
  * scripts/generate-openapi.ts). Unlike the neighbouring channel APIs there
10
10
  * are no assistant-scoped `/v1/assistants/{assistant_id}/...` variants: the
11
11
  * guardian reaches these flat paths directly rather than through the
12
- * platform proxy.
12
+ * cloud proxy.
13
13
  *
14
14
  * The handlers live in `channel-ingress.ts`; that module imports
15
15
  * `ApproveChannelIngressRequestSchema` so wire validation and the published
@@ -110,7 +110,7 @@ export const ROUTES: GatewayRouteDefinition[] = [
110
110
  pathParameters: [
111
111
  {
112
112
  name: "source",
113
- description: "The declaring ingress source (today, a plugin name)",
113
+ description: "The declaring ingress source, today a plugin name",
114
114
  },
115
115
  ],
116
116
  requestBody: ApproveChannelIngressRequestSchema,
@@ -127,7 +127,7 @@ export const ROUTES: GatewayRouteDefinition[] = [
127
127
  pathParameters: [
128
128
  {
129
129
  name: "source",
130
- description: "The declaring ingress source (today, a plugin name)",
130
+ description: "The declaring ingress source, today a plugin name",
131
131
  },
132
132
  ],
133
133
  responseBody: z.object({ source: z.string(), revoked: z.boolean() }),
@@ -273,7 +273,18 @@ describe("approve", () => {
273
273
  refresh: () => {},
274
274
  pollIntervalMs: 10,
275
275
  });
276
- await new Promise((done) => setTimeout(done, 40));
276
+ // The watcher polls every 10ms, so the retry normally lands in tens of
277
+ // milliseconds — but a fixed sleep races the poll under CI contention
278
+ // and starves it. Wait on a deadline instead: exit as soon as the routes
279
+ // appear, and let the assertion below name the failure if the watcher
280
+ // genuinely never reclaims them.
281
+ const retryDeadline = Date.now() + 5_000;
282
+ while (
283
+ listWebhookIngressRoutes().length === 0 &&
284
+ Date.now() < retryDeadline
285
+ ) {
286
+ await new Promise((done) => setTimeout(done, 5));
287
+ }
277
288
  unwatch();
278
289
 
279
290
  expect(
@@ -596,7 +607,7 @@ describe("list", () => {
596
607
 
597
608
  it("reports a cadet-signed route as served while its source waits", async () => {
598
609
  // Approval is the general gate, and a cadet-signed route is the
599
- // exception: only a caller holding the platform secret can open it. A
610
+ // exception: only a caller holding the cloud secret can open it. A
600
611
  // listing that read servability off the source's state would call a live
601
612
  // route dormant, and say nothing about which half of a mixed declaration
602
613
  // is already reachable.