@mycadet/gateway 0.12.7 → 0.12.8

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 (167) hide show
  1. package/README.md +3 -3
  2. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/package.json +1 -1
  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/src/rpc-client.ts +1 -1
  11. package/node_modules/@mycadet/environments/src/seeds.ts +6 -6
  12. package/node_modules/@mycadet/environments/src/shell.test.ts +1 -1
  13. package/node_modules/@mycadet/environments/src/types.ts +6 -6
  14. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/package.json +1 -1
  15. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/{platform-credential.ts → cloud-credential.ts} +9 -9
  16. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
  17. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
  18. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
  19. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
  20. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
  21. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
  22. package/node_modules/@mycadet/gateway-client/src/binding-strength-contract.ts +5 -5
  23. package/node_modules/@mycadet/gateway-client/src/gateway-ipc-contracts.ts +1 -1
  24. package/node_modules/@mycadet/gateway-client/src/inbound-contract.ts +2 -2
  25. package/node_modules/@mycadet/gateway-client/src/outbound-contract.ts +1 -1
  26. package/node_modules/@mycadet/service-contracts/package.json +1 -1
  27. package/node_modules/@mycadet/service-contracts/src/{platform-credential.ts → cloud-credential.ts} +9 -9
  28. package/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
  29. package/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
  30. package/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
  31. package/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
  32. package/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
  33. package/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
  34. package/package.json +1 -1
  35. package/src/__tests__/actor-token-revocation.test.ts +0 -1
  36. package/src/__tests__/{backup-worker-platform-mode.test.ts → backup-worker-cloud-mode.test.ts} +4 -4
  37. package/src/__tests__/channel-verification-session-proxy.test.ts +0 -1
  38. package/src/__tests__/{platform-identity.test.ts → cloud-identity.test.ts} +72 -86
  39. package/src/__tests__/config.test.ts +0 -24
  40. package/src/__tests__/contacts-control-plane-proxy.test.ts +0 -1
  41. package/src/__tests__/credential-requests.test.ts +6 -6
  42. package/src/__tests__/{credential-watcher-managed-bootstrap.test.ts → credential-watcher-cloud-bootstrap.test.ts} +1 -1
  43. package/src/__tests__/edge-auth.test.ts +18 -18
  44. package/src/__tests__/edge-guardian-auth.test.ts +10 -10
  45. package/src/__tests__/guardian-init-lockfile.test.ts +6 -8
  46. package/src/__tests__/guardian-pin.test.ts +8 -8
  47. package/src/__tests__/handle-inbound-admission.test.ts +0 -1
  48. package/src/__tests__/handle-inbound-app-context.test.ts +0 -1
  49. package/src/__tests__/handle-inbound-invite-intercept.test.ts +0 -1
  50. package/src/__tests__/handle-inbound-trust-verdict.test.ts +0 -1
  51. package/src/__tests__/inbound-contact-seed.test.ts +1 -1
  52. package/src/__tests__/live-voice-websocket.test.ts +12 -12
  53. package/src/__tests__/load-guards.test.ts +0 -1
  54. package/src/__tests__/migration-teleport-gcs-proxy.test.ts +0 -1
  55. package/src/__tests__/oauth-callback.test.ts +0 -1
  56. package/src/__tests__/remote-feature-flag-sync.test.ts +35 -45
  57. package/src/__tests__/resolve-assistant.test.ts +0 -1
  58. package/src/__tests__/route-schema-guard.test.ts +4 -1
  59. package/src/__tests__/runtime-client.test.ts +1 -2
  60. package/src/__tests__/runtime-health-proxy.test.ts +0 -1
  61. package/src/__tests__/runtime-proxy-auth.test.ts +3 -2
  62. package/src/__tests__/runtime-proxy-device-stamp.test.ts +0 -1
  63. package/src/__tests__/runtime-proxy-error-body.test.ts +0 -1
  64. package/src/__tests__/runtime-proxy.test.ts +0 -1
  65. package/src/__tests__/runtime-stream-test-utils.ts +0 -1
  66. package/src/__tests__/shared-invite-registration.test.ts +15 -32
  67. package/src/__tests__/slack-control-plane-proxy.test.ts +0 -1
  68. package/src/__tests__/slack-display-name.test.ts +0 -1
  69. package/src/__tests__/slack-normalize.test.ts +0 -1
  70. package/src/__tests__/slack-reaction-normalize.test.ts +0 -1
  71. package/src/__tests__/slack-socket-mode-catchup.test.ts +0 -1
  72. package/src/__tests__/slack-socket-mode-group-dm.test.ts +0 -1
  73. package/src/__tests__/slack-socket-mode-liveness.test.ts +0 -1
  74. package/src/__tests__/slack-socket-mode-outbound-root.test.ts +0 -1
  75. package/src/__tests__/slack-socket-mode-thread-tracking.test.ts +0 -1
  76. package/src/__tests__/speech-relay-websocket.test.ts +16 -14
  77. package/src/__tests__/stt-stream-websocket.test.ts +5 -5
  78. package/src/__tests__/telegram-control-plane-proxy.test.ts +0 -1
  79. package/src/__tests__/telegram-webhook-drop-visibility.test.ts +0 -1
  80. package/src/__tests__/telegram-webhook-handler.test.ts +0 -1
  81. package/src/__tests__/telegram-webhook-manager.test.ts +79 -80
  82. package/src/__tests__/twilio-media-websocket.test.ts +0 -1
  83. package/src/__tests__/twilio-webhooks.test.ts +6 -7
  84. package/src/__tests__/whatsapp-download.test.ts +0 -1
  85. package/src/__tests__/whatsapp-webhook.test.ts +0 -1
  86. package/src/attachments/ingest.test.ts +0 -1
  87. package/src/auth/guardian-bootstrap.ts +17 -15
  88. package/src/auth/scopes.ts +1 -1
  89. package/src/auth-fallback-reporter.ts +1 -1
  90. package/src/backup/backup-worker.ts +2 -2
  91. package/src/channels/inbound-event.ts +3 -3
  92. package/src/channels/ingress-inbound-vendors.test.ts +2 -2
  93. package/src/channels/ingress-inbound.ts +1 -1
  94. package/src/channels/ingress-verification.test.ts +2 -2
  95. package/src/channels/ingress-verification.ts +4 -4
  96. package/src/channels/plugin-ingress-approvals.test.ts +1 -1
  97. package/src/channels/plugin-ingress-approvals.ts +1 -1
  98. package/src/channels/plugin-ingress.test.ts +3 -3
  99. package/src/channels/plugin-ingress.ts +3 -3
  100. package/src/channels/room-admission.ts +2 -2
  101. package/src/{platform-identity.ts → cloud-identity.ts} +60 -68
  102. package/src/cloud-url.ts +14 -0
  103. package/src/{platform-user-id.ts → cloud-user-id.ts} +4 -4
  104. package/src/config.ts +2 -4
  105. package/src/credential-reader.ts +2 -2
  106. package/src/db/assistant-db-proxy.ts +1 -1
  107. package/src/discord/forward.ts +1 -1
  108. package/src/email/normalize.ts +4 -4
  109. package/src/email/register-callback.test.ts +27 -34
  110. package/src/email/register-callback.ts +21 -26
  111. package/src/feature-flag-registry.json +5 -5
  112. package/src/feature-flag-remote-store.ts +2 -2
  113. package/src/feature-flag-resolver.ts +5 -5
  114. package/src/http/cadet-signature.ts +1 -1
  115. package/src/http/edge-forwarded-header.ts +1 -1
  116. package/src/http/loopback-guard.ts +1 -1
  117. package/src/http/middleware/auth.ts +22 -22
  118. package/src/http/router.ts +1 -1
  119. package/src/http/routes/cadet-identity.ts +2 -2
  120. package/src/http/routes/channel-ingress-routes.ts +1 -1
  121. package/src/http/routes/channel-ingress.test.ts +13 -2
  122. package/src/http/routes/channel-verification-session-proxy.ts +9 -9
  123. package/src/http/routes/{platform-push-proxy.test.ts → cloud-push-proxy.test.ts} +21 -22
  124. package/src/http/routes/{platform-push-proxy.ts → cloud-push-proxy.ts} +13 -14
  125. package/src/http/routes/contacts-control-plane-proxy.ts +2 -2
  126. package/src/http/routes/email-webhook.test.ts +2 -3
  127. package/src/http/routes/email-webhook.ts +4 -4
  128. package/src/http/routes/guardian-channel-create.ts +3 -3
  129. package/src/http/routes/guardian-pin.ts +9 -9
  130. package/src/http/routes/inbound-register.ts +2 -2
  131. package/src/http/routes/ingress-domains.test.ts +129 -0
  132. package/src/http/routes/ingress-domains.ts +73 -0
  133. package/src/http/routes/live-voice-websocket.ts +2 -2
  134. package/src/http/routes/log-export.test.ts +0 -1
  135. package/src/http/routes/log-tail.test.ts +0 -1
  136. package/src/http/routes/migration-proxy.ts +1 -1
  137. package/src/http/routes/plugin-webhook-websocket.test.ts +3 -3
  138. package/src/http/routes/plugin-webhook.test.ts +9 -8
  139. package/src/http/routes/plugin-webhook.ts +1 -1
  140. package/src/http/routes/speech-relay-websocket.ts +8 -11
  141. package/src/http/routes/stt-stream-websocket.ts +1 -1
  142. package/src/http/routes/telegram-webhook.test.ts +0 -1
  143. package/src/http/routes/twilio-voice-verify-callback.ts +3 -3
  144. package/src/http/routes/twilio-voice-webhook.test.ts +3 -4
  145. package/src/http/routes/twilio-voice-webhook.ts +3 -3
  146. package/src/http/routes/whatsapp-webhook.test.ts +0 -1
  147. package/src/index.ts +57 -56
  148. package/src/ipc/credential-request-handlers.ts +4 -4
  149. package/src/ipc/debug-export-handlers.test.ts +0 -1
  150. package/src/ipc/log-tail-handlers.test.ts +0 -1
  151. package/src/ipc/risk-classification-handlers.test.ts +4 -4
  152. package/src/ipc/risk-classification-handlers.ts +2 -2
  153. package/src/remote-feature-flag-sync.ts +16 -18
  154. package/src/risk/command-registry/commands/assistant.ts +2 -2
  155. package/src/risk/skill-risk-classifier.test.ts +24 -24
  156. package/src/risk/skill-risk-classifier.ts +10 -10
  157. package/src/runtime/client.ts +17 -17
  158. package/src/schema.ts +5 -5
  159. package/src/telegram/send.test.ts +0 -1
  160. package/src/telegram/webhook-manager.ts +33 -38
  161. package/src/tunnel/allowed-paths.test.ts +3 -3
  162. package/src/tunnel/allowed-paths.ts +1 -1
  163. package/src/tunnel/client.test.ts +20 -21
  164. package/src/tunnel/client.ts +17 -17
  165. package/src/verification/shared-invite-registration.ts +22 -17
  166. package/src/version.ts +1 -1
  167. package/src/platform-url.ts +0 -24
@@ -114,7 +114,7 @@ interface InboundEventBase<C extends InboundChannelId> {
114
114
  isDirectMessage?: boolean;
115
115
  /**
116
116
  * Whether the message addresses the assistant by name, an @-mention on
117
- * the platforms that have one. Stated only where the channel proved it,
117
+ * the clouds that have one. Stated only where the channel proved it,
118
118
  * in whichever direction it can prove; absent means "not established".
119
119
  * Slack states it for an `app_mention`; Discord reads its own id out of
120
120
  * the mentions array. The runtime reads it to decide whether a reply is
@@ -122,11 +122,11 @@ interface InboundEventBase<C extends InboundChannelId> {
122
122
  */
123
123
  botMentioned?: boolean;
124
124
  /**
125
- * True when the platform names no actor for this event: the synthetic
125
+ * True when the cloud names no actor for this event: the synthetic
126
126
  * actorExternalId identifies the channel's system, not a person, so
127
127
  * nothing downstream may treat it as an identity claim. A delete on a
128
128
  * platform whose dispatch carries no author is the canonical case, and so
129
- * is a delete of the assistant's own post on a platform that names the
129
+ * is a delete of the assistant's own post on a cloud that names the
130
130
  * author but never the deleter. The daemon then applies the event only to
131
131
  * a row it already holds for that chat: one it ingested from an author
132
132
  * who cleared the ACL on arrival, or one the assistant posted itself.
@@ -121,7 +121,7 @@ describe("a Comms declaration", () => {
121
121
  *
122
122
  * The two things a single path could not express are both here. The
123
123
  * conversation falls back from `message.space.id` to `space.id`, which in code
124
- * is `message.space ?? event.space`, and the platform is mapped to the two
124
+ * is `message.space ?? event.space`, and the cloud is mapped to the two
125
125
  * values admission acts on. The vendor\'s own casing is used for the map key,
126
126
  * because a declaration should be able to quote what the wire says.
127
127
  */
@@ -187,7 +187,7 @@ describe("a Photon declaration", () => {
187
187
  );
188
188
  });
189
189
 
190
- it("maps the platform case-insensitively", () => {
190
+ it("maps the cloud case-insensitively", () => {
191
191
  // Photon spells it `iMessage`. A map that missed on capitalisation would
192
192
  // silently downgrade every blue bubble to the spoofable-sender treatment.
193
193
  const result = read("imessage", photonDelivery(), PHOTON);
@@ -198,7 +198,7 @@ const INBOUND_FIELD_NAMES = Object.keys(
198
198
  /**
199
199
  * What the sender's id is, so it can be compared with the ones already stored.
200
200
  *
201
- * `opaque` (the default) is right for a platform-stable id and is the only
201
+ * `opaque` (the default) is right for a cloud-stable id and is the only
202
202
  * safe guess, because rewriting an id that was already canonical is how a
203
203
  * returning sender stops matching their own contact record.
204
204
  */
@@ -664,9 +664,9 @@ describe("HMAC URL and form payloads", () => {
664
664
  expect(result).toEqual({ ok: true });
665
665
  });
666
666
 
667
- it("verifies against the platform-injected URL first", () => {
667
+ it("verifies against the cloud-injected URL first", () => {
668
668
  const injected =
669
- "https://platform.example.test/v1/gateway/callbacks/abc123";
669
+ "https://test-cloud.mycadet.ai.test/v1/gateway/callbacks/abc123";
670
670
  const result = verify(
671
671
  URL_AND_FORM_HMAC,
672
672
  {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Declared signature verification for plugin ingress routes.
3
3
  *
4
- * A plugin route that receives third-party webhooks cannot use the platform
4
+ * A plugin route that receives third-party webhooks cannot use the cloud
5
5
  * scheme (`Cadet-Signature`, see `../http/cadet-signature.ts`): the caller is
6
6
  * Comms, or Photon, or Stripe, and it signs the way it signs. Before this,
7
7
  * such a route could be declared, approved, registered with the vendor, and
@@ -22,10 +22,10 @@
22
22
  * - **The credential's service.** A descriptor names a *field*; the service is
23
23
  * composed from the plugin's own directory name by the caller. A manifest
24
24
  * that could name the service could point a route at another plugin's secret,
25
- * or at the platform's.
25
+ * or at the cloud's.
26
26
  * - **Fail-closed parsing.** Anything unrecognized — an unknown `kind`,
27
27
  * algorithm, encoding, or an extra key — fails the manifest rather than
28
- * falling back to the platform scheme. A route the plugin believes is
28
+ * falling back to the cloud scheme. A route the plugin believes is
29
29
  * verified one way and the gateway verifies another is worse than no route.
30
30
  * - **Canonical payload parts.** `body` is the bytes as received. Other
31
31
  * payload parts declare their own canonicalization, so a manifest cannot
@@ -192,7 +192,7 @@ export type VerificationResult =
192
192
  /**
193
193
  * The public URLs a caller might have signed.
194
194
  *
195
- * The platform callback proxy can preserve the original URL explicitly, while
195
+ * The cloud callback proxy can preserve the original URL explicitly, while
196
196
  * a reverse proxy can expose it through forwarding headers. A configured
197
197
  * public base and the raw request URL cover direct deployments. Each distinct
198
198
  * candidate is tried because only the caller knows which public spelling it
@@ -404,7 +404,7 @@ describe("findServableRoute", () => {
404
404
  });
405
405
 
406
406
  it("serves a cadet-signed route without approval", () => {
407
- // Only a caller holding the platform secret can open it, and that trust
407
+ // Only a caller holding the cloud secret can open it, and that trust
408
408
  // was already given when the account was connected.
409
409
  const res = resolution({
410
410
  pending: [
@@ -177,7 +177,7 @@ function resolveDiscoveredPluginIngress(
177
177
  *
178
178
  * Approval is the general gate, with one exception: a route declaring
179
179
  * `signer: "cadet"` is served without it. Such a route only opens to a
180
- * caller holding the platform's own webhook secret, which is to say us, and
180
+ * caller holding the cloud's own webhook secret, which is to say us, and
181
181
  * the user extended that trust when they connected their account, so asking
182
182
  * them to approve it again buys nothing. A route signed by anyone else still
183
183
  * needs a guardian decision, because approval is what establishes who that
@@ -112,7 +112,7 @@ describe("parsePluginIngressManifest", () => {
112
112
  });
113
113
 
114
114
  it("defaults an undeclared signer to the plugin's own secret", () => {
115
- // The safe default: a plugin gets no reach against the platform's key
115
+ // The safe default: a plugin gets no reach against the cloud's key
116
116
  // unless it asks for it and a guardian approves that declaration.
117
117
  const manifest = parsePluginIngressManifest(JSON.parse(VALID));
118
118
  expect(manifest.routes[0]!.signer).toBe("plugin");
@@ -238,7 +238,7 @@ describe("parsePluginIngressManifest", () => {
238
238
  });
239
239
 
240
240
  it("leaves verification undeclared when the manifest omits it", () => {
241
- // Absent means the platform scheme, exactly as before the field existed.
241
+ // Absent means the cloud scheme, exactly as before the field existed.
242
242
  const manifest = parsePluginIngressManifest(JSON.parse(VALID));
243
243
  expect(manifest.routes[0]!.verification).toBeUndefined();
244
244
  });
@@ -339,7 +339,7 @@ describe("parsePluginIngressManifest", () => {
339
339
  });
340
340
 
341
341
  it("rejects a verification descriptor the gateway cannot run", () => {
342
- // Fail the manifest rather than falling back to the platform scheme: a
342
+ // Fail the manifest rather than falling back to the cloud scheme: a
343
343
  // route verified differently than declared is worse than no route.
344
344
  expect(() =>
345
345
  parsePluginIngressManifest({
@@ -106,7 +106,7 @@ export const IngressRouteSchema = z.object({
106
106
  * `webhook_secret`, so a plugin can receive third-party callbacks it has
107
107
  * arranged itself, and a guardian decides whether that route is served.
108
108
  *
109
- * `cadet` verifies against the platform's `webhook_secret`, for routes
109
+ * `cadet` verifies against the cloud's `webhook_secret`, for routes
110
110
  * only Cadet calls, which would otherwise need a per-plugin secret
111
111
  * provisioned for a caller we already authenticate. Such a route is
112
112
  * served without a guardian approval: the trust it relies on was given
@@ -120,7 +120,7 @@ export const IngressRouteSchema = z.object({
120
120
  /**
121
121
  * How the caller proves it holds the signing secret.
122
122
  *
123
- * `signed-headers` (the default) is the platform's scheme: the signature
123
+ * `signed-headers` (the default) is the cloud's scheme: the signature
124
124
  * travels in `Cadet-Signature`, over the body for HTTP and over
125
125
  * `<timestamp>.<pathname>` for a WebSocket upgrade.
126
126
  *
@@ -142,7 +142,7 @@ export const IngressRouteSchema = z.object({
142
142
  /**
143
143
  * How a third-party caller's signature is checked, when it is not ours.
144
144
  *
145
- * Absent (the default) means the platform scheme: `Cadet-Signature` over
145
+ * Absent (the default) means the cloud scheme: `Cadet-Signature` over
146
146
  * the body, keyed by whichever `webhook_secret` {@link signer} selects.
147
147
  * That is right for a caller Cadet controls and wrong for every other one
148
148
  * — Comms signs `X-Osis-Signature`, Photon signs `X-Spectrum-Signature` over
@@ -14,11 +14,11 @@
14
14
  * admits is a chat, not a person: who may be answered there is the
15
15
  * trust-class admission floor's decision downstream.
16
16
  *
17
- * The candidate is neutral on purpose. How a platform proves "direct" (Discord
17
+ * The candidate is neutral on purpose. How a cloud proves "direct" (Discord
18
18
  * by the absence of a guild, Telegram by `chat.type`) and "addressed" (a
19
19
  * mentions array, text entities, a reply to the bot's post) is the adapter's
20
20
  * side of the seam, built in `discord/admit.ts` and `telegram/admit.ts`. This
21
- * module never reads a platform field.
21
+ * module never reads a cloud field.
22
22
  */
23
23
 
24
24
  import type { AdmissionDropLogLevel } from "./admission-drop-log.js";
@@ -2,9 +2,9 @@
2
2
  * Bound platform identity (assistant, organization, user).
3
3
  *
4
4
  * Django maps an assistant API key to these ids via
5
- * `POST /v1/internal/assistants/validate/`. Resolution reads in-memory
6
- * overrides (and `PLATFORM_ASSISTANT_ID` / `PLATFORM_ORGANIZATION_ID` /
7
- * `PLATFORM_USER_ID` when set). When the bound ids are empty, or the
5
+ * `POST /v1/internal/assistants/validate/`. Resolution reads the in-memory
6
+ * overrides the validate response populates — nothing else. When the bound
7
+ * ids are empty, or the
8
8
  * API key / platform base URL that produced them has changed, the next
9
9
  * resolve retries validate (single-flight, with a cooldown after a failed
10
10
  * validate attempt for the same credentials).
@@ -21,30 +21,28 @@ import { readCredentialResult } from "./credential-reader.js";
21
21
  import { fetchImpl } from "./fetch.js";
22
22
  import { getLogger } from "./logger.js";
23
23
 
24
- const log = getLogger("platform-identity");
24
+ const log = getLogger("cloud-identity");
25
25
 
26
- export const PLATFORM_IDENTITY_VALIDATE_PATH =
27
- "/v1/internal/assistants/validate/";
26
+ export const CLOUD_IDENTITY_VALIDATE_PATH = "/v1/internal/assistants/validate/";
28
27
 
29
28
  const VALIDATE_TIMEOUT_MS = 5_000;
30
29
  const ENSURE_COOLDOWN_MS = 10_000;
31
30
 
32
31
  const ASSISTANT_API_KEY_ACCOUNT = credentialKey("cadet", "assistant_api_key");
33
- const PLATFORM_BASE_URL_ACCOUNT = credentialKey("cadet", "platform_base_url");
34
32
 
35
- export type PlatformIdentityIds = {
33
+ export type CloudIdentityIds = {
36
34
  assistantId: string;
37
35
  organizationId: string;
38
36
  userId: string;
39
37
  };
40
38
 
41
- export type StoredPlatformUserId = {
39
+ export type StoredCloudUserId = {
42
40
  userId: string | undefined;
43
41
  unreachable: boolean;
44
42
  };
45
43
 
46
- let platformAssistantIdOverride: string | undefined;
47
- let platformOrganizationIdOverride: string | undefined;
44
+ let cloudAssistantIdOverride: string | undefined;
45
+ let cloudOrganizationIdOverride: string | undefined;
48
46
  let platformUserIdOverride: string | undefined;
49
47
  let identityBoundToFingerprint: string | undefined;
50
48
  let lastAttemptFingerprint: string | undefined;
@@ -65,42 +63,38 @@ function envTrim(name: string): string {
65
63
  return process.env[name]?.trim() ?? "";
66
64
  }
67
65
 
68
- function getPlatformAssistantId(): string {
69
- return (
70
- platformAssistantIdOverride || envTrim("PLATFORM_ASSISTANT_ID")
71
- ).trim();
66
+ function getCloudAssistantId(): string {
67
+ return (cloudAssistantIdOverride ?? "").trim();
72
68
  }
73
69
 
74
- function getPlatformOrganizationId(): string {
75
- return (
76
- platformOrganizationIdOverride || envTrim("PLATFORM_ORGANIZATION_ID")
77
- ).trim();
70
+ function getCloudOrganizationId(): string {
71
+ return (cloudOrganizationIdOverride ?? "").trim();
78
72
  }
79
73
 
80
- function getPlatformUserId(): string {
81
- return (platformUserIdOverride || envTrim("PLATFORM_USER_ID")).trim();
74
+ function getCloudUserId(): string {
75
+ return (platformUserIdOverride ?? "").trim();
82
76
  }
83
77
 
84
78
  function hasBoundIdentity(): boolean {
85
- return Boolean(getPlatformAssistantId() && getPlatformUserId());
79
+ return Boolean(getCloudAssistantId() && getCloudUserId());
86
80
  }
87
81
 
88
82
  function identityFingerprint(apiKey: string, baseUrl: string): string {
89
83
  return `${baseUrl}\0${apiKey}`;
90
84
  }
91
85
 
92
- function clearPlatformIdentityOverrides(): void {
93
- platformAssistantIdOverride = undefined;
94
- platformOrganizationIdOverride = undefined;
86
+ function clearCloudIdentityOverrides(): void {
87
+ cloudAssistantIdOverride = undefined;
88
+ cloudOrganizationIdOverride = undefined;
95
89
  platformUserIdOverride = undefined;
96
90
  }
97
91
 
98
- export function applyPlatformIdentityIds(ids: PlatformIdentityIds): void {
92
+ export function applyCloudIdentityIds(ids: CloudIdentityIds): void {
99
93
  if (ids.assistantId) {
100
- platformAssistantIdOverride = ids.assistantId;
94
+ cloudAssistantIdOverride = ids.assistantId;
101
95
  }
102
96
  if (ids.organizationId) {
103
- platformOrganizationIdOverride = ids.organizationId;
97
+ cloudOrganizationIdOverride = ids.organizationId;
104
98
  }
105
99
  if (ids.userId) {
106
100
  platformUserIdOverride = ids.userId;
@@ -111,16 +105,16 @@ export function applyPlatformIdentityIds(ids: PlatformIdentityIds): void {
111
105
  * Use the gateway credential cache for API key / base URL lookups so a
112
106
  * vault outage can still retry validate with last-good secrets.
113
107
  */
114
- export function bindPlatformIdentityCredentialCache(
108
+ export function bindCloudIdentityCredentialCache(
115
109
  cache: CredentialCache | undefined,
116
110
  ): void {
117
111
  credentialCache = cache;
118
112
  }
119
113
 
120
114
  /** @internal Test-only: drop in-memory identity and in-flight ensure state. */
121
- export function _resetPlatformIdentityForTests(): void {
122
- platformAssistantIdOverride = undefined;
123
- platformOrganizationIdOverride = undefined;
115
+ export function _resetCloudIdentityForTests(): void {
116
+ cloudAssistantIdOverride = undefined;
117
+ cloudOrganizationIdOverride = undefined;
124
118
  platformUserIdOverride = undefined;
125
119
  identityBoundToFingerprint = undefined;
126
120
  lastAttemptFingerprint = undefined;
@@ -132,20 +126,20 @@ export function _resetPlatformIdentityForTests(): void {
132
126
 
133
127
  /** @internal Alias so existing auth tests can reset the bound owner id. */
134
128
  export function _resetLastKnownPlatformUserIdForTest(): void {
135
- _resetPlatformIdentityForTests();
129
+ _resetCloudIdentityForTests();
136
130
  }
137
131
 
138
132
  /**
139
133
  * Trade an assistant API key for the bound platform ids.
140
134
  *
141
- * Returns null when the platform is unreachable, refuses the key, or the
135
+ * Returns null when the cloud is unreachable, refuses the key, or the
142
136
  * body has no ids. Never throws.
143
137
  */
144
- export async function fetchPlatformIdentityIds(
138
+ export async function fetchCloudIdentityIds(
145
139
  baseUrl: string,
146
140
  apiKey: string,
147
- ): Promise<PlatformIdentityIds | null> {
148
- const url = `${baseUrl.replace(/\/+$/, "")}${PLATFORM_IDENTITY_VALIDATE_PATH}`;
141
+ ): Promise<CloudIdentityIds | null> {
142
+ const url = `${baseUrl.replace(/\/+$/, "")}${CLOUD_IDENTITY_VALIDATE_PATH}`;
149
143
  try {
150
144
  const res = await fetchImpl(url, {
151
145
  method: "POST",
@@ -211,20 +205,18 @@ async function readAuthPrerequisites(): Promise<{
211
205
  unreachable: boolean;
212
206
  }> {
213
207
  const envKey = envTrim("ASSISTANT_API_KEY");
214
- const envUrl = envTrim("CADET_PLATFORM_URL").replace(/\/+$/, "");
215
-
216
- const [apiKeyRead, baseUrlRead] = await Promise.all([
217
- readCredentialOrEnv(ASSISTANT_API_KEY_ACCOUNT, envKey),
218
- readCredentialOrEnv(PLATFORM_BASE_URL_ACCOUNT, envUrl),
219
- ]);
220
-
221
- const apiKey = apiKeyRead.value;
222
- const baseUrl = baseUrlRead.value.replace(/\/+$/, "");
223
- const unreachable =
224
- (!apiKey && apiKeyRead.unreachable) ||
225
- (!baseUrl && baseUrlRead.unreachable);
226
-
227
- return { apiKey, baseUrl, unreachable };
208
+ const envUrl = envTrim("CADET_CLOUD_URL").replace(/\/+$/, "");
209
+
210
+ const apiKeyRead = await readCredentialOrEnv(
211
+ ASSISTANT_API_KEY_ACCOUNT,
212
+ envKey,
213
+ );
214
+
215
+ return {
216
+ apiKey: apiKeyRead.value,
217
+ baseUrl: envUrl,
218
+ unreachable: !apiKeyRead.value && apiKeyRead.unreachable,
219
+ };
228
220
  }
229
221
 
230
222
  /**
@@ -236,7 +228,7 @@ async function readAuthPrerequisites(): Promise<{
236
228
  * validate for the same credentials is still inside the cooldown window.
237
229
  * Concurrent callers share one in-flight request.
238
230
  */
239
- export async function ensurePlatformIdentityIds(): Promise<void> {
231
+ export async function ensureCloudIdentityIds(): Promise<void> {
240
232
  if (!ensureInFlight) {
241
233
  ensureInFlight = (async () => {
242
234
  try {
@@ -258,7 +250,7 @@ export async function ensurePlatformIdentityIds(): Promise<void> {
258
250
  identityBoundToFingerprint !== undefined &&
259
251
  identityBoundToFingerprint !== fingerprint
260
252
  ) {
261
- clearPlatformIdentityOverrides();
253
+ clearCloudIdentityOverrides();
262
254
  identityBoundToFingerprint = undefined;
263
255
  }
264
256
  if (
@@ -268,19 +260,19 @@ export async function ensurePlatformIdentityIds(): Promise<void> {
268
260
  return;
269
261
  }
270
262
  lastAttemptFingerprint = fingerprint;
271
- const ids = await fetchPlatformIdentityIds(baseUrl, apiKey);
263
+ const ids = await fetchCloudIdentityIds(baseUrl, apiKey);
272
264
  if (!ids) {
273
265
  nextEnsureAttemptAt = Date.now() + ENSURE_COOLDOWN_MS;
274
266
  return;
275
267
  }
276
- applyPlatformIdentityIds(ids);
268
+ applyCloudIdentityIds(ids);
277
269
  identityBoundToFingerprint = fingerprint;
278
270
  nextEnsureAttemptAt = 0;
279
271
  log.info(
280
272
  {
281
- hasAssistantId: Boolean(getPlatformAssistantId()),
282
- hasOrganizationId: Boolean(getPlatformOrganizationId()),
283
- hasUserId: Boolean(getPlatformUserId()),
273
+ hasAssistantId: Boolean(getCloudAssistantId()),
274
+ hasOrganizationId: Boolean(getCloudOrganizationId()),
275
+ hasUserId: Boolean(getCloudUserId()),
284
276
  },
285
277
  "Loaded platform identity from platform validate",
286
278
  );
@@ -292,26 +284,26 @@ export async function ensurePlatformIdentityIds(): Promise<void> {
292
284
  await ensureInFlight;
293
285
  }
294
286
 
295
- export async function resolvePlatformAssistantId(): Promise<string> {
296
- await ensurePlatformIdentityIds();
297
- return getPlatformAssistantId();
287
+ export async function resolveCloudAssistantId(): Promise<string> {
288
+ await ensureCloudIdentityIds();
289
+ return getCloudAssistantId();
298
290
  }
299
291
 
300
- export function peekPlatformAssistantId(): string | undefined {
301
- const id = getPlatformAssistantId();
292
+ export function peekCloudAssistantId(): string | undefined {
293
+ const id = getCloudAssistantId();
302
294
  return id || undefined;
303
295
  }
304
296
 
305
- export async function resolvePlatformAssistantIdOrUndefined(): Promise<
297
+ export async function resolveCloudAssistantIdOrUndefined(): Promise<
306
298
  string | undefined
307
299
  > {
308
- const id = await resolvePlatformAssistantId();
300
+ const id = await resolveCloudAssistantId();
309
301
  return id || undefined;
310
302
  }
311
303
 
312
304
  export async function resolvePlatformUserId(): Promise<string> {
313
- await ensurePlatformIdentityIds();
314
- return getPlatformUserId();
305
+ await ensureCloudIdentityIds();
306
+ return getCloudUserId();
315
307
  }
316
308
 
317
309
  /**
@@ -322,7 +314,7 @@ export async function resolvePlatformUserId(): Promise<string> {
322
314
  * prior successful resolve is cached. A cached owner is returned with
323
315
  * `unreachable: false` so callers keep treating the assistant as reachable.
324
316
  */
325
- export async function readStoredPlatformUserId(): Promise<StoredPlatformUserId> {
317
+ export async function readStoredCloudUserId(): Promise<StoredCloudUserId> {
326
318
  const userId = await resolvePlatformUserId();
327
319
  if (userId) {
328
320
  return { userId, unreachable: false };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Resolve the cloud base URL from the `CADET_CLOUD_URL` environment
3
+ * variable, defaulting to `https://cloud.mycadet.ai`.
4
+ *
5
+ * The returned URL is trimmed and has any trailing slashes removed so callers
6
+ * can safely append path segments.
7
+ */
8
+ export function getCloudBaseUrl(): string {
9
+ const url = (process.env.CADET_CLOUD_URL?.trim() || "").replace(
10
+ /\/+$/,
11
+ "",
12
+ );
13
+ return url || "https://cloud.mycadet.ai";
14
+ }
@@ -2,11 +2,11 @@
2
2
  * Bound platform owner id for managed-mode edge auth.
3
3
  *
4
4
  * Identity is resolved from platform validate and in-memory last-known
5
- * values. See {@link readStoredPlatformUserId} in `platform-identity.ts`.
5
+ * values. See {@link readStoredCloudUserId} in `cloud-identity.ts`.
6
6
  */
7
7
 
8
8
  export {
9
9
  _resetLastKnownPlatformUserIdForTest,
10
- readStoredPlatformUserId,
11
- type StoredPlatformUserId,
12
- } from "./platform-identity.js";
10
+ readStoredCloudUserId,
11
+ type StoredCloudUserId,
12
+ } from "./cloud-identity.js";
package/src/config.ts CHANGED
@@ -25,7 +25,7 @@ export type GatewayConfig = {
25
25
  /**
26
26
  * Body cap for the inbound email webhook (`/webhooks/email`). Email
27
27
  * attachments arrive inlined as base64 in the payload, so this ceiling is
28
- * much larger than {@link maxWebhookPayloadBytes} to fit the platform's
28
+ * much larger than {@link maxWebhookPayloadBytes} to fit the cloud's
29
29
  * per-file / per-message attachment cap. Optional — callers fall back to
30
30
  * {@link maxWebhookPayloadBytes} when unset.
31
31
  */
@@ -36,7 +36,6 @@ export type GatewayConfig = {
36
36
  runtimeMaxRetries: number;
37
37
  runtimeProxyRequireAuth: boolean;
38
38
  runtimeTimeoutMs: number;
39
- shutdownDrainMs: number;
40
39
  /** When true, trust X-Forwarded-For for client IP resolution (set when behind a reverse proxy). */
41
40
  trustProxy: boolean;
42
41
  };
@@ -217,7 +216,7 @@ export function loadConfig(): GatewayConfig {
217
216
  },
218
217
  maxAttachmentConcurrency: 3,
219
218
  maxWebhookPayloadBytes: 1024 * 1024,
220
- // Fits the platform's inbound-attachment cap (25 MB/file × 10 files),
219
+ // Fits the cloud's inbound-attachment cap (25 MB/file × 10 files),
221
220
  // expanded by base64 (~4/3) plus body/JSON overhead.
222
221
  maxEmailWebhookPayloadBytes: 350 * 1024 * 1024,
223
222
  port,
@@ -226,7 +225,6 @@ export function loadConfig(): GatewayConfig {
226
225
  runtimeMaxRetries: 2,
227
226
  runtimeProxyRequireAuth,
228
227
  runtimeTimeoutMs,
229
- shutdownDrainMs: 5000,
230
228
  trustProxy,
231
229
  };
232
230
  }
@@ -196,7 +196,7 @@ export function getCesHttpConfig():
196
196
  }
197
197
 
198
198
  /**
199
- * Try to read a credential from the CES managed service over HTTP.
199
+ * Try to read a credential from the CES cloud service over HTTP.
200
200
  *
201
201
  * Delegates to `@mycadet/ces-client/http-credentials` for the transport.
202
202
  * Activated when `CES_CREDENTIAL_URL` is set (e.g. `http://ces-host:8090`).
@@ -404,7 +404,7 @@ export const DISCORD_CHANNEL_CREDENTIAL_SPEC: ServiceCredentialSpec = {
404
404
 
405
405
  export const CADET_CREDENTIAL_SPEC: ServiceCredentialSpec = {
406
406
  service: "cadet",
407
- requiredFields: ["platform_base_url", "assistant_api_key", "webhook_secret"],
407
+ requiredFields: ["assistant_api_key", "webhook_secret"],
408
408
  } as const;
409
409
 
410
410
  export const ALL_CREDENTIAL_SPECS: readonly ServiceCredentialSpec[] = [
@@ -3,7 +3,7 @@
3
3
  * SQLite database via IPC. Gateway one-time data migrations (m0002, m0010,
4
4
  * m0014, et al.) need raw read/drop access to the assistant DB on first boot
5
5
  * of upgraded installs, and direct cross-container file access corrupts the
6
- * DB on platform pods (fcntl locks are not shared across mount namespaces +
6
+ * DB on cloud pods (fcntl locks are not shared across mount namespaces +
7
7
  * a SQLite WAL-reset bug in ≤3.51.2) — so migrations reach the assistant DB
8
8
  * only through this route.
9
9
  *
@@ -24,7 +24,7 @@ export function createDiscordInboundEventHandler(options: {
24
24
  const { config, log, notifyRecordActivity, forwardQueue } = options;
25
25
 
26
26
  return (event, attachmentRefs) => {
27
- // Reset the platform idle-sleep timer so inbound Discord activity keeps
27
+ // Reset the cloud idle-sleep timer so inbound Discord activity keeps
28
28
  // the assistant awake like any other channel.
29
29
  notifyRecordActivity();
30
30
 
@@ -24,7 +24,7 @@ export interface EmailAttachment {
24
24
  * Shape of a normalized inbound email event as sent by the Cadet
25
25
  * platform (or any upstream caller).
26
26
  *
27
- * The platform is responsible for provider-specific parsing (e.g.
27
+ * The cloud is responsible for provider-specific parsing (e.g.
28
28
  * Mailgun multipart → JSON). By the time the payload reaches the
29
29
  * gateway it should already be in this canonical shape.
30
30
  */
@@ -47,15 +47,15 @@ export interface CadetEmailPayload {
47
47
  inReplyTo?: string;
48
48
  /** Space-separated chain of ancestor Message-IDs (References header). */
49
49
  references?: string;
50
- /** Stable conversation/thread identifier derived by the platform. */
50
+ /** Stable conversation/thread identifier derived by the cloud. */
51
51
  conversationId: string;
52
52
  /** ISO 8601 timestamp of the original email. */
53
53
  timestamp?: string;
54
54
  /**
55
- * Whether the platform authenticated the sender's `From:` address against
55
+ * Whether the cloud authenticated the sender's `From:` address against
56
56
  * the message's SPF/DKIM/DMARC results. `true` when authentication passed,
57
57
  * `false` when it was evaluated and failed (spoofable sender), omitted when
58
- * the platform could not evaluate (no auth-results header). The gateway
58
+ * the cloud could not evaluate (no auth-results header). The gateway
59
59
  * downgrades an unauthenticated sender so a forged `From:` cannot inherit
60
60
  * guardian/trusted_contact trust.
61
61
  */