@every-app/sdk 0.3.0-rc.1 → 0.3.0-rc.10

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 (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -1
  3. package/dist/cloudflare/catalogSettings.generated.d.ts +81 -0
  4. package/dist/cloudflare/catalogSettings.generated.d.ts.map +1 -0
  5. package/dist/cloudflare/catalogSettings.generated.js +174 -0
  6. package/dist/cloudflare/index.d.ts +3 -2
  7. package/dist/cloudflare/index.d.ts.map +1 -1
  8. package/dist/cloudflare/index.js +4 -1
  9. package/dist/cloudflare/sentinel.d.ts +60 -2
  10. package/dist/cloudflare/sentinel.d.ts.map +1 -1
  11. package/dist/cloudflare/sentinel.js +37 -2
  12. package/dist/cloudflare/worker.d.ts +357 -63
  13. package/dist/cloudflare/worker.d.ts.map +1 -1
  14. package/dist/cloudflare/worker.js +363 -104
  15. package/dist/dev/index.d.ts +1 -1
  16. package/dist/dev/index.d.ts.map +1 -1
  17. package/dist/dev/index.js +1 -1
  18. package/dist/dev/keypair.d.ts +2 -0
  19. package/dist/dev/keypair.d.ts.map +1 -1
  20. package/dist/dev/keypair.js +2 -0
  21. package/dist/index.d.ts +6 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +5 -0
  24. package/dist/internal/aiDefault.d.ts +204 -0
  25. package/dist/internal/aiDefault.d.ts.map +1 -0
  26. package/dist/internal/aiDefault.js +334 -0
  27. package/dist/internal/aiProviders.d.ts +7 -2
  28. package/dist/internal/aiProviders.d.ts.map +1 -1
  29. package/dist/internal/aiProviders.js +17 -4
  30. package/dist/internal/appSettings.d.ts +82 -4
  31. package/dist/internal/appSettings.d.ts.map +1 -1
  32. package/dist/internal/appSettings.js +204 -29
  33. package/dist/internal/audit.d.ts +108 -0
  34. package/dist/internal/audit.d.ts.map +1 -0
  35. package/dist/internal/audit.js +235 -0
  36. package/dist/internal/capabilities.d.ts +2268 -438
  37. package/dist/internal/capabilities.d.ts.map +1 -1
  38. package/dist/internal/capabilities.js +128 -539
  39. package/dist/internal/catalog/commerce.d.ts +394 -0
  40. package/dist/internal/catalog/commerce.d.ts.map +1 -0
  41. package/dist/internal/catalog/commerce.js +477 -0
  42. package/dist/internal/catalog/comms.d.ts +375 -0
  43. package/dist/internal/catalog/comms.d.ts.map +1 -0
  44. package/dist/internal/catalog/comms.js +520 -0
  45. package/dist/internal/catalog/index.d.ts +1973 -0
  46. package/dist/internal/catalog/index.d.ts.map +1 -0
  47. package/dist/internal/catalog/index.js +19 -0
  48. package/dist/internal/catalog/inference.d.ts +393 -0
  49. package/dist/internal/catalog/inference.d.ts.map +1 -0
  50. package/dist/internal/catalog/inference.js +460 -0
  51. package/dist/internal/catalog/infra.d.ts +423 -0
  52. package/dist/internal/catalog/infra.d.ts.map +1 -0
  53. package/dist/internal/catalog/infra.js +543 -0
  54. package/dist/internal/catalog/search.d.ts +400 -0
  55. package/dist/internal/catalog/search.d.ts.map +1 -0
  56. package/dist/internal/catalog/search.js +463 -0
  57. package/dist/internal/devProviders.d.ts +2 -2
  58. package/dist/internal/devProviders.d.ts.map +1 -1
  59. package/dist/internal/devProviders.js +19 -1
  60. package/dist/internal/events.d.ts +13 -2
  61. package/dist/internal/events.d.ts.map +1 -1
  62. package/dist/internal/events.js +47 -4
  63. package/dist/internal/gatewaySettings.d.ts +3 -2
  64. package/dist/internal/gatewaySettings.d.ts.map +1 -1
  65. package/dist/internal/gatewaySettings.js +12 -6
  66. package/dist/internal/identity.d.ts +41 -4
  67. package/dist/internal/identity.d.ts.map +1 -1
  68. package/dist/internal/identity.js +48 -10
  69. package/dist/internal/index.d.ts +6 -1
  70. package/dist/internal/index.d.ts.map +1 -1
  71. package/dist/internal/index.js +6 -1
  72. package/dist/internal/members.d.ts +3 -2
  73. package/dist/internal/members.d.ts.map +1 -1
  74. package/dist/internal/oauthClient.d.ts +10 -12
  75. package/dist/internal/oauthClient.d.ts.map +1 -1
  76. package/dist/internal/oauthClient.js +20 -81
  77. package/dist/internal/oauthPresets.d.ts +33 -0
  78. package/dist/internal/oauthPresets.d.ts.map +1 -0
  79. package/dist/internal/oauthPresets.js +1064 -0
  80. package/dist/internal/oauthScopes.d.ts +56 -1
  81. package/dist/internal/oauthScopes.d.ts.map +1 -1
  82. package/dist/internal/oauthScopes.js +98 -4
  83. package/dist/internal/oauthSpec.d.ts +102 -0
  84. package/dist/internal/oauthSpec.d.ts.map +1 -0
  85. package/dist/internal/oauthSpec.js +789 -0
  86. package/dist/internal/protocol.d.ts +64 -1
  87. package/dist/internal/protocol.d.ts.map +1 -1
  88. package/dist/internal/protocol.js +51 -1
  89. package/dist/internal/providerRegistry.d.ts +77 -6
  90. package/dist/internal/providerRegistry.d.ts.map +1 -1
  91. package/dist/internal/providerRegistry.js +178 -8
  92. package/dist/internal/providerSpec.d.ts +18 -7
  93. package/dist/internal/providerSpec.d.ts.map +1 -1
  94. package/dist/internal/providerSpec.js +442 -34
  95. package/dist/internal/signInProviders.d.ts +104 -0
  96. package/dist/internal/signInProviders.d.ts.map +1 -0
  97. package/dist/internal/signInProviders.js +245 -0
  98. package/dist/manifest.d.ts +238 -0
  99. package/dist/manifest.d.ts.map +1 -0
  100. package/dist/manifest.js +30 -0
  101. package/dist/server/ai.d.ts +111 -0
  102. package/dist/server/ai.d.ts.map +1 -0
  103. package/dist/server/ai.js +145 -0
  104. package/dist/server/aiBinding.d.ts +68 -0
  105. package/dist/server/aiBinding.d.ts.map +1 -0
  106. package/dist/server/aiBinding.js +294 -0
  107. package/dist/server/attribution.d.ts +9 -5
  108. package/dist/server/attribution.d.ts.map +1 -1
  109. package/dist/server/attribution.js +12 -4
  110. package/dist/server/authorizeUrl.d.ts +1 -1
  111. package/dist/server/authorizeUrl.d.ts.map +1 -1
  112. package/dist/server/authorizeUrl.js +2 -6
  113. package/dist/server/connectUrl.d.ts +21 -0
  114. package/dist/server/connectUrl.d.ts.map +1 -0
  115. package/dist/server/connectUrl.js +37 -0
  116. package/dist/server/context.d.ts +68 -0
  117. package/dist/server/context.d.ts.map +1 -0
  118. package/dist/server/context.js +117 -0
  119. package/dist/server/emailBinding.d.ts +72 -0
  120. package/dist/server/emailBinding.d.ts.map +1 -0
  121. package/dist/server/emailBinding.js +124 -0
  122. package/dist/server/emit.d.ts +1 -1
  123. package/dist/server/emit.d.ts.map +1 -1
  124. package/dist/server/emit.js +7 -7
  125. package/dist/server/env.d.ts +44 -0
  126. package/dist/server/env.d.ts.map +1 -0
  127. package/dist/server/env.js +1 -0
  128. package/dist/server/everyApp.d.ts +27 -7
  129. package/dist/server/everyApp.d.ts.map +1 -1
  130. package/dist/server/everyApp.js +106 -5
  131. package/dist/server/fromMcpTools.d.ts +89 -0
  132. package/dist/server/fromMcpTools.d.ts.map +1 -0
  133. package/dist/server/fromMcpTools.js +192 -0
  134. package/dist/server/gatewayFetch.d.ts +42 -18
  135. package/dist/server/gatewayFetch.d.ts.map +1 -1
  136. package/dist/server/gatewayFetch.js +138 -19
  137. package/dist/server/gatewayUrl.d.ts +13 -0
  138. package/dist/server/gatewayUrl.d.ts.map +1 -0
  139. package/dist/server/gatewayUrl.js +34 -0
  140. package/dist/server/index.d.ts +15 -4
  141. package/dist/server/index.d.ts.map +1 -1
  142. package/dist/server/index.js +12 -2
  143. package/dist/server/integrationFetch.d.ts +70 -39
  144. package/dist/server/integrationFetch.d.ts.map +1 -1
  145. package/dist/server/integrationFetch.js +244 -82
  146. package/dist/server/listMembers.d.ts +1 -1
  147. package/dist/server/listMembers.d.ts.map +1 -1
  148. package/dist/server/listMembers.js +8 -11
  149. package/dist/server/refusal.d.ts +55 -0
  150. package/dist/server/refusal.d.ts.map +1 -0
  151. package/dist/server/refusal.js +193 -0
  152. package/dist/server/sendEmail.d.ts +1 -1
  153. package/dist/server/sendEmail.d.ts.map +1 -1
  154. package/dist/server/sendEmail.js +7 -7
  155. package/dist/server/toolsEndpoint.d.ts.map +1 -1
  156. package/dist/server/toolsEndpoint.js +11 -5
  157. package/dist/tanstack-start/index.d.ts +9 -0
  158. package/dist/tanstack-start/index.d.ts.map +1 -0
  159. package/dist/tanstack-start/index.js +29 -0
  160. package/dist/testing/index.d.ts +93 -0
  161. package/dist/testing/index.d.ts.map +1 -0
  162. package/dist/testing/index.js +156 -0
  163. package/package.json +35 -14
@@ -2,8 +2,13 @@ import { createHash, createHmac } from "node:crypto";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { parseEnv } from "node:util";
5
- import { DEV_ISSUER, DEV_PUBLIC_KEY_PEM } from "../dev/keypair.js";
6
- import { sentinelDeployTarget } from "./sentinel.js";
5
+ import { DEV_ISSUER, DEV_ORG_ID, DEV_PUBLIC_KEY_PEM } from "../dev/keypair.js";
6
+ // The catalog's settings, generated from ../internal/capabilities.ts, which
7
+ // this file must not import (see ./index.ts: the Vite plugin hides whatever
8
+ // cloudflare.config.ts imports from the Worker).
9
+ import { DEV_GATEWAY_KEYS } from "./catalogSettings.generated.js";
10
+ import { helperWorkerName, sentinelDeployTarget, workflowNameFor, } from "./sentinel.js";
11
+ export { helperWorkerName, workflowNameFor } from "./sentinel.js";
7
12
  /** The names of the manifest's `secrets`, whichever form each took. */
8
13
  function manifestSecretNames(manifest) {
9
14
  return (manifest.secrets ?? []).map((entry) => typeof entry === "string" ? entry : entry.name);
@@ -12,69 +17,6 @@ function manifestSecretNames(manifest) {
12
17
  function manifestProviderIds(manifest) {
13
18
  return (manifest.providers ?? []).map((entry) => typeof entry === "string" ? entry : entry.id);
14
19
  }
15
- /**
16
- * The gateway secrets holding the keys of the AI providers and capabilities
17
- * an app may ask for, with the settings a provider needs besides its key
18
- * (Workers AI's account). With no gateway in development, the SDK reaches
19
- * them with the developer's own values under the same names. A copy of the
20
- * tables in ../internal, which the Worker loads: the Vite plugin hides
21
- * whatever cloudflare.config.ts imports from the Worker. A test keeps them
22
- * in step.
23
- */
24
- const DEV_GATEWAY_KEYS = {
25
- providers: {
26
- openai: ["OPENAI_API_KEY"],
27
- openrouter: ["OPENROUTER_API_KEY"],
28
- "workers-ai": ["WORKERS_AI_API_TOKEN", "CLOUDFLARE_ACCOUNT_ID"],
29
- },
30
- capabilities: {
31
- dataforseo: ["DATAFORSEO_API_KEY"],
32
- context: ["CONTEXT_API_KEY"],
33
- // The sender, and the developer's own Email Sending account: set all
34
- // but the name and sendEmail() really sends; otherwise it prints.
35
- // Resend's key and EMAIL_PROVIDER pick the provider integrationStatus()
36
- // names, as the gateway would.
37
- // TODO(integration): the last two added by the email-providers lane
38
- // (this file is outside its ownership list).
39
- email: [
40
- "EMAIL_FROM",
41
- "EMAIL_FROM_NAME",
42
- "EMAIL_REST_API_TOKEN",
43
- "CLOUDFLARE_ACCOUNT_ID",
44
- "RESEND_API_KEY",
45
- "EMAIL_PROVIDER",
46
- ],
47
- // The organization's members: nothing to set; listMembers() answers
48
- // from the dev identity.
49
- members: [],
50
- // OAuth clients: the id, the secret, and the instance a provider with
51
- // no fixed host is on.
52
- linkedin: ["LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET"],
53
- facebook: ["FACEBOOK_APP_ID", "FACEBOOK_APP_SECRET"],
54
- instagram: ["INSTAGRAM_APP_ID", "INSTAGRAM_APP_SECRET"],
55
- threads: ["THREADS_APP_ID", "THREADS_APP_SECRET"],
56
- youtube: ["YOUTUBE_CLIENT_ID", "YOUTUBE_CLIENT_SECRET"],
57
- tiktok: ["TIKTOK_CLIENT_ID", "TIKTOK_CLIENT_SECRET"],
58
- "tiktok-business": [
59
- "TIKTOK_BUSINESS_CLIENT_ID",
60
- "TIKTOK_BUSINESS_CLIENT_SECRET",
61
- ],
62
- reddit: ["REDDIT_CLIENT_ID", "REDDIT_CLIENT_SECRET"],
63
- pinterest: ["PINTEREST_CLIENT_ID", "PINTEREST_CLIENT_SECRET"],
64
- discord: ["DISCORD_CLIENT_ID", "DISCORD_CLIENT_SECRET"],
65
- slack: ["SLACK_CLIENT_ID", "SLACK_CLIENT_SECRET"],
66
- mastodon: ["MASTODON_CLIENT_ID", "MASTODON_CLIENT_SECRET", "MASTODON_URL"],
67
- kick: ["KICK_CLIENT_ID", "KICK_CLIENT_SECRET"],
68
- twitch: ["TWITCH_CLIENT_ID", "TWITCH_CLIENT_SECRET"],
69
- tumblr: ["TUMBLR_CLIENT_ID", "TUMBLR_CLIENT_SECRET"],
70
- dribbble: ["DRIBBBLE_CLIENT_ID", "DRIBBBLE_CLIENT_SECRET"],
71
- "google-workspace": [
72
- "GOOGLE_WORKSPACE_CLIENT_ID",
73
- "GOOGLE_WORKSPACE_CLIENT_SECRET",
74
- ],
75
- "microsoft-365": ["MICROSOFT_365_CLIENT_ID", "MICROSOFT_365_CLIENT_SECRET"],
76
- },
77
- };
78
20
  /**
79
21
  * Observability every Every App Worker ships with: logs (with invocation
80
22
  * logs), sampled traces and Workers Issues, with query strings redacted so
@@ -104,6 +46,19 @@ const BUILD_ENV = "EVERYAPP_BUILD";
104
46
  const RESERVED_SECRET_NAME = /^(GATEWAY_URL|CF_VERSION_METADATA|EVERYAPP_\w*|EVERY_APP_\w*|APP__\w*)$/i;
105
47
  const GATEWAY_WORKER_NAME = "every-app-gateway";
106
48
  const GATEWAY_ENTRYPOINT = "AppGateway";
49
+ /**
50
+ * Where `everyapp dev` serves its launcher, which it passes to the app's dev
51
+ * server in EVERYAPP_DEV_GATEWAY_URL; its default address otherwise. The
52
+ * deployed Worker gets the Gateway's URL from the deploy instead.
53
+ */
54
+ const DEV_GATEWAY_URL_ENV = "EVERYAPP_DEV_GATEWAY_URL";
55
+ const DEFAULT_DEV_GATEWAY_URL = "http://localhost:8787";
56
+ function devGatewayUrl() {
57
+ return {
58
+ type: "text",
59
+ value: process.env[DEV_GATEWAY_URL_ENV] || DEFAULT_DEV_GATEWAY_URL,
60
+ };
61
+ }
107
62
  /**
108
63
  * The manifest's `capabilities` as the SDK's local-dev twin of the gateway
109
64
  * reads them: with no gateway to hold an OAuth client's calls to the scope
@@ -115,9 +70,12 @@ function devCapabilities(manifest) {
115
70
  /**
116
71
  * The binding the dev Worker gets the specs of providers registered on a
117
72
  * gateway in (`DEV_PROVIDERS_ENV` in ../internal/devProviders.ts; a copy,
118
- * kept in step by a test, for the reason {@link DEV_GATEWAY_KEYS} is one).
73
+ * kept in step by a test, since this file may not import ../internal).
119
74
  */
120
75
  const DEV_PROVIDERS_ENV = "EVERYAPP_DEV_PROVIDERS";
76
+ /** Linked dev's env names (`LINKED_DEV_URL_ENV`, `LINKED_DEV_NONCE_ENV` in ../internal/protocol.ts; copies, kept in step by the same test). */
77
+ const LINKED_DEV_URL_ENV = "EVERYAPP_LINKED_DEV_URL";
78
+ const LINKED_DEV_NONCE_ENV = "EVERYAPP_LINKED_DEV_NONCE";
121
79
  /**
122
80
  * The specs `everyapp provider add` (in an app directory) and `everyapp
123
81
  * provider show <id> --save` wrote under the app, in name order; none
@@ -148,6 +106,22 @@ function devProviderFiles(root) {
148
106
  return { file: `.everyapp/providers/${name}`, spec };
149
107
  });
150
108
  }
109
+ /**
110
+ * Linked dev (`everyapp dev --gateway`, docs/design/linked-dev.md): the
111
+ * gateway-lite starts the app's dev server with the forwarder's loopback
112
+ * URL and the run's nonce in the process environment; the dev Worker gets
113
+ * both as text, and the SDK's `gatewayBinding()` builds the shim from
114
+ * them in place of the missing service binding. Absent in every other
115
+ * run, and never in a deploy.
116
+ */
117
+ function addLinkedDev(env) {
118
+ const url = process.env[LINKED_DEV_URL_ENV]?.trim();
119
+ const nonce = process.env[LINKED_DEV_NONCE_ENV];
120
+ if (!url || !nonce)
121
+ return;
122
+ env[LINKED_DEV_URL_ENV] = { type: "text", value: url };
123
+ env[LINKED_DEV_NONCE_ENV] = { type: "text", value: nonce };
124
+ }
151
125
  /** EVERYAPP_DEV_PROVIDERS, when the app has any spec files. */
152
126
  function addDevProviders(env, root) {
153
127
  const files = devProviderFiles(root);
@@ -194,8 +168,14 @@ function devProviderKeys(manifest, root) {
194
168
  }
195
169
  /** Cloudflare's limit on a Workflow's name. */
196
170
  const MAX_WORKFLOW_NAME_LENGTH = 64;
171
+ /**
172
+ * The store development binds Secrets Store secrets in: Miniflare keeps
173
+ * one per id under `.cloudflare/state`, and any id works locally.
174
+ */
175
+ const LOCAL_SECRETS_STORE_ID = "local";
176
+ /** Cloudflare's limit on a Vectorize index's name. */
177
+ const MAX_VECTORIZE_NAME_LENGTH = 64;
197
178
  /** Cloudflare's limit on a Worker's name. */
198
- const MAX_WORKER_NAME_LENGTH = 63;
199
179
  /**
200
180
  * Where a developer puts a local Postgres URL for a Hyperdrive binding
201
181
  * (`.dev.vars` or `.env`), the variable wrangler reads for the same.
@@ -222,6 +202,12 @@ export function everyAppWorker(options) {
222
202
  const { deploy, name } = appWorkerName(options, "everyAppWorker");
223
203
  const env = {
224
204
  EVERYAPP_APP_ID: { type: "text", value: manifest.id },
205
+ // The manifest itself, for a page that shows what the app asked for:
206
+ // the Worker can't import everyapp.config.ts (see ./index.ts).
207
+ EVERYAPP_MANIFEST: {
208
+ type: "json",
209
+ value: manifest,
210
+ },
225
211
  CF_VERSION_METADATA: { type: "version-metadata" },
226
212
  };
227
213
  if (deploy) {
@@ -248,9 +234,24 @@ export function everyAppWorker(options) {
248
234
  value: JSON.stringify([DEV_PUBLIC_KEY_PEM]),
249
235
  };
250
236
  env["EVERYAPP_IDENTITY_ISSUER"] = { type: "text", value: DEV_ISSUER };
237
+ env["GATEWAY_URL"] = devGatewayUrl();
238
+ // The stub gateway's organization, as the deploy's secret would be, so
239
+ // background work's withOrganization(env.EVERY_APP_ORG_ID, …) runs
240
+ // here too. Not a pin: under the dev opt-in everyApp() enforces none,
241
+ // so `everyapp dev --mode mirror`'s real organizations still open.
242
+ env["EVERY_APP_ORG_ID"] = { type: "text", value: DEV_ORG_ID };
251
243
  addDevProviders(env, options.root);
244
+ addLinkedDev(env);
252
245
  }
253
246
  Object.assign(env, storageBindings(manifest, name, deploy));
247
+ addQueueBindings(env, manifest, name, deploy);
248
+ addAiBindings(env, manifest, deploy);
249
+ addBrowserBindings(env, manifest);
250
+ addImagesBindings(env, manifest);
251
+ addAiGatewayBindings(env, manifest, name, deploy);
252
+ addSendEmailBindings(env, manifest);
253
+ addSecretsStoreBindings(env, manifest, name, deploy);
254
+ addAnalyticsEngineBindings(env, manifest, name);
254
255
  addDatabaseBindings(env, options, name, undefined, deploy);
255
256
  // The app binds every class, a helper Worker's in that Worker, and
256
257
  // exports only its own.
@@ -268,13 +269,19 @@ export function everyAppWorker(options) {
268
269
  };
269
270
  }
270
271
  addSecrets(env, options, deploy);
271
- const triggers = cronTriggers(options.crons);
272
+ const triggers = [
273
+ ...cronTriggers(options.crons),
274
+ ...queueTriggers(manifest, name, undefined, deploy),
275
+ ];
272
276
  const compatibilityDate = manifest.compatibilityDate ?? DEFAULT_COMPATIBILITY_DATE;
273
277
  // cf types a Durable Object namespace with its class only when the binding
274
278
  // names the defining Worker by a definition whose module it can read, so
275
279
  // the classes this Worker defines name it that way; cf resolves the
276
280
  // reference to the Worker's name. A path entrypoint gives cf no module.
281
+ // Only here: `EveryAppBinding` names Workers by name, as the Vite
282
+ // plugin's `auxiliaryWorkers` require.
277
283
  const { entrypoint } = options;
284
+ const ownClasses = {};
278
285
  if (typeof entrypoint === "object") {
279
286
  const self = {
280
287
  name,
@@ -284,7 +291,7 @@ export function everyAppWorker(options) {
284
291
  for (const durableObject of manifest.resources?.durableObjects ?? []) {
285
292
  if (durableObject.worker !== undefined)
286
293
  continue;
287
- env[durableObject.name] = {
294
+ ownClasses[durableObject.name] = {
288
295
  type: "durable-object",
289
296
  worker: self,
290
297
  exportName: durableObject.className,
@@ -301,7 +308,8 @@ export function everyAppWorker(options) {
301
308
  ...(triggers.length ? { triggers } : {}),
302
309
  ...runtimeSettings(manifest, manifest.limits, deploy),
303
310
  observability: observability(),
304
- env: env,
311
+ // Each class keeps its key's place in `env`: classBindings bound it by name.
312
+ env: { ...env, ...ownClasses },
305
313
  exports: exports,
306
314
  };
307
315
  }
@@ -309,7 +317,10 @@ export function everyAppWorker(options) {
309
317
  * Build the definition of one of the app's helper Workers (the manifest's
310
318
  * `workers`), e.g. one that runs a memory-hungry job away from the app's
311
319
  * Worker. It is named `<app worker>--<worker>`, is private like the app, and
312
- * binds the app's D1 databases, KV namespaces and R2 buckets, the classes it defines, and
320
+ * binds the app's and Analytics Engine datasets, the classes it defines, and
321
+ * binds the app's D1 databases, KV namespaces, R2 buckets, Workers AI,
322
+ * Browser Rendering, Images, Vectorize indexes, AI Gateways, `send_email`
323
+ * bindings and Secrets Store secrets, the classes it defines, and
313
324
  * the gateway (with the app's identity, for capabilities). Only the app's
314
325
  * Worker reaches it. Pass it to the Vite plugin:
315
326
  *
@@ -331,6 +342,8 @@ export function everyAppAuxiliaryWorker(options) {
331
342
  EVERYAPP_APP_ID: { type: "text", value: manifest.id },
332
343
  ...storageBindings(manifest, appWorker, deploy),
333
344
  };
345
+ addQueueBindings(env, manifest, appWorker, deploy);
346
+ addSendEmailBindings(env, manifest);
334
347
  if (deploy) {
335
348
  // The app's identity: the gateway treats its helper Workers as the app.
336
349
  env["EVERY_APP_GATEWAY"] = gatewayBinding(deploy, manifest.id, appWorker);
@@ -342,13 +355,25 @@ export function everyAppAuxiliaryWorker(options) {
342
355
  else {
343
356
  env["EVERYAPP_DEV"] = { type: "text", value: "1" };
344
357
  env["EVERYAPP_DEV_CAPABILITIES"] = devCapabilities(manifest);
358
+ env["GATEWAY_URL"] = devGatewayUrl();
359
+ env["EVERY_APP_ORG_ID"] = { type: "text", value: DEV_ORG_ID };
345
360
  addDevProviders(env, options.root);
361
+ addLinkedDev(env);
346
362
  }
363
+ addAiBindings(env, manifest, deploy);
364
+ addBrowserBindings(env, manifest);
365
+ addImagesBindings(env, manifest);
366
+ addAiGatewayBindings(env, manifest, appWorker, deploy);
367
+ addSecretsStoreBindings(env, manifest, appWorker, deploy);
368
+ addAnalyticsEngineBindings(env, manifest, appWorker);
347
369
  addDatabaseBindings(env, options, appWorker, worker, deploy);
348
370
  const { bindings, exports } = classBindings(manifest, appWorker, worker, env);
349
371
  Object.assign(env, bindings);
350
372
  addSecrets(env, options, deploy);
351
- const triggers = cronTriggers(options.crons);
373
+ const triggers = [
374
+ ...cronTriggers(options.crons),
375
+ ...queueTriggers(manifest, appWorker, worker, deploy),
376
+ ];
352
377
  return {
353
378
  name,
354
379
  entrypoint: options.entrypoint,
@@ -363,18 +388,6 @@ export function everyAppAuxiliaryWorker(options) {
363
388
  exports,
364
389
  };
365
390
  }
366
- /**
367
- * A helper Worker's name: `<app worker>--<name>`, within Cloudflare's
368
- * limit. New app ids can't contain `--`, so it is never another app's
369
- * Worker name.
370
- */
371
- export function helperWorkerName(appWorker, helper) {
372
- const name = `${appWorker}--${helper}`;
373
- if (name.length > MAX_WORKER_NAME_LENGTH) {
374
- throw new Error(`Helper Worker ${name} is longer than Cloudflare's ${MAX_WORKER_NAME_LENGTH} characters; shorten its name in everyapp.config.ts.`);
375
- }
376
- return name;
377
- }
378
391
  /** The placeholder target (in production) and the app Worker's name. */
379
392
  function appWorkerName(options, builder) {
380
393
  const { manifest, ctx } = options;
@@ -382,7 +395,7 @@ function appWorkerName(options, builder) {
382
395
  let deploy;
383
396
  if (ctx.mode === "production") {
384
397
  if (process.env[BUILD_ENV] !== "1") {
385
- throw new Error(`Every App Workers are built for production only by \`everyapp deploy\` (\`pnpm run deploy\`), which sets ${BUILD_ENV}=1 and installs the build: ` +
398
+ throw new Error(`EveryApp Workers are built for production only by \`everyapp deploy\` (\`pnpm run deploy\`), which sets ${BUILD_ENV}=1 and installs the build: ` +
386
399
  "a bare `cf build` or `cf deploy` would ship a Worker whose name, identity keys, gateway binding and resources are placeholders. " +
387
400
  "For a local build, run Vite in development mode (`vite build --mode development`).");
388
401
  }
@@ -410,8 +423,8 @@ function gatewayBinding(deploy, appId, appWorker) {
410
423
  };
411
424
  }
412
425
  /**
413
- * The app's D1 databases, KV namespaces and R2 buckets, which all its
414
- * Workers share.
426
+ * The app's D1 databases, KV namespaces, R2 buckets and Vectorize indexes,
427
+ * which all its Workers share.
415
428
  */
416
429
  function storageBindings(manifest, appWorker, deploy) {
417
430
  const env = {};
@@ -461,8 +474,237 @@ function storageBindings(manifest, appWorker, deploy) {
461
474
  env[binding] = { type: "r2", name: bucketNameFor(appWorker, binding) };
462
475
  }
463
476
  }
477
+ // Deployed, the index the deploy provisioned (a placeholder until
478
+ // installed); in development the account's index of the dev Worker's
479
+ // name, reached remotely: Cloudflare has no local Vectorize, so calls
480
+ // throw until the Vite plugin's remoteBindings is on.
481
+ for (const { name: binding } of manifest.resources?.vectorize ?? []) {
482
+ if (env[binding]) {
483
+ throw new Error(`vectorize: ${binding} reuses a binding name the Worker already has.`);
484
+ }
485
+ if (deploy) {
486
+ env[binding] = {
487
+ type: "vectorize",
488
+ name: provisioned(deploy.resources.vectorize, binding).name,
489
+ };
490
+ continue;
491
+ }
492
+ const index = suffixedName(appWorker, binding);
493
+ if (index.length > MAX_VECTORIZE_NAME_LENGTH) {
494
+ throw new Error(`vectorize: ${binding} would be the Vectorize index "${index}", longer than Cloudflare's ${MAX_VECTORIZE_NAME_LENGTH} characters; shorten the binding name.`);
495
+ }
496
+ env[binding] = { type: "vectorize", name: index, dev: { remote: true } };
497
+ }
464
498
  return env;
465
499
  }
500
+ /**
501
+ * A producer binding to each of the app's queues, which every one of its
502
+ * Workers gets. Deployed, each names the queue the deploy provisioned (a
503
+ * placeholder until installed); in development, the queue its rule gives
504
+ * (Miniflare makes it, shared by the Workers of one `cf dev`).
505
+ */
506
+ function addQueueBindings(env, manifest, appWorker, deploy) {
507
+ for (const { name: binding } of manifest.resources?.queues ?? []) {
508
+ if (env[binding]) {
509
+ throw new Error(`queues: ${binding} reuses a binding name the Worker already has.`);
510
+ }
511
+ env[binding] = {
512
+ type: "queue",
513
+ name: queueName(appWorker, binding, deploy),
514
+ };
515
+ }
516
+ }
517
+ /**
518
+ * The manifest's Workers AI bindings, which every one of the app's Workers
519
+ * gets: `{ type: "ai" }` deployed (account-wide, nothing to provision), and
520
+ * marked remote in development, where Miniflare has no Workers AI. The
521
+ * remote mark does nothing until the app's Vite config sets
522
+ * `remoteBindings: true`, so turning that on is the one switch.
523
+ */
524
+ function addAiBindings(env, manifest, deploy) {
525
+ for (const binding of manifest.resources?.ai ?? []) {
526
+ if (env[binding]) {
527
+ throw new Error(`ai: ${binding} reuses a binding name the Worker already has.`);
528
+ }
529
+ env[binding] = deploy
530
+ ? { type: "ai" }
531
+ : { type: "ai", dev: { remote: true } };
532
+ }
533
+ }
534
+ /**
535
+ * The consumer triggers of one of the app's Workers: each queue whose
536
+ * `consumer` is this Worker (`true`, or no `worker`, for the app's own;
537
+ * `forWorker` for a helper), with its settings and its dead-letter queue,
538
+ * another of the app's queues, by name.
539
+ */
540
+ function queueTriggers(manifest, appWorker, forWorker, deploy) {
541
+ const triggers = [];
542
+ for (const queue of manifest.resources?.queues ?? []) {
543
+ if (queue.consumer === undefined)
544
+ continue;
545
+ const settings = queue.consumer === true ? {} : queue.consumer;
546
+ if (settings.worker !== forWorker)
547
+ continue;
548
+ const { deadLetterQueue } = settings;
549
+ if (deadLetterQueue !== undefined &&
550
+ !manifest.resources?.queues?.some((other) => other.name === deadLetterQueue)) {
551
+ throw new Error(`queues: ${queue.name}'s deadLetterQueue "${deadLetterQueue}" isn't one of resources.queues.`);
552
+ }
553
+ triggers.push({
554
+ type: "queue",
555
+ name: queueName(appWorker, queue.name, deploy),
556
+ ...(deadLetterQueue !== undefined
557
+ ? { deadLetterQueue: queueName(appWorker, deadLetterQueue, deploy) }
558
+ : {}),
559
+ ...Object.fromEntries(QUEUE_CONSUMER_SETTINGS.flatMap((key) => settings[key] === undefined ? [] : [[key, settings[key]]])),
560
+ });
561
+ }
562
+ return triggers;
563
+ }
564
+ /** The consumer settings a queue trigger carries, in the order it lists them. */
565
+ const QUEUE_CONSUMER_SETTINGS = [
566
+ "maxBatchSize",
567
+ "maxBatchTimeout",
568
+ "maxRetries",
569
+ "maxConcurrency",
570
+ "retryDelay",
571
+ "visibilityTimeoutMs",
572
+ ];
573
+ /** A queue binding's queue: the deploy's placeholder, or in development its rule. */
574
+ function queueName(appWorker, binding, deploy) {
575
+ return deploy
576
+ ? provisioned(deploy.resources.queues, binding).name
577
+ : queueNameFor(appWorker, binding);
578
+ }
579
+ /**
580
+ * The manifest's Browser Rendering bindings, which every one of the app's
581
+ * Workers gets: `{ type: "browser" }` in both modes (account-wide,
582
+ * nothing to provision; Miniflare serves a local browser in development).
583
+ */
584
+ function addBrowserBindings(env, manifest) {
585
+ for (const binding of manifest.resources?.browser ?? []) {
586
+ if (env[binding]) {
587
+ throw new Error(`browser: ${binding} reuses a binding name the Worker already has.`);
588
+ }
589
+ env[binding] = { type: "browser" };
590
+ }
591
+ }
592
+ /**
593
+ * The manifest's Images bindings, which every one of the app's Workers
594
+ * gets: `{ type: "images" }` in both modes (account-wide, nothing to
595
+ * provision; Miniflare answers it locally in development).
596
+ */
597
+ function addImagesBindings(env, manifest) {
598
+ for (const binding of manifest.resources?.images ?? []) {
599
+ if (env[binding]) {
600
+ throw new Error(`images: ${binding} reuses a binding name the Worker already has.`);
601
+ }
602
+ env[binding] = { type: "images" };
603
+ }
604
+ }
605
+ /**
606
+ * The app's AI Gateways, which all its Workers share, each a `json`
607
+ * binding of `{ id, accountId, url }`. Deployed, the gateway the deploy
608
+ * provisioned (a placeholder until installed); in development the id the
609
+ * deploy's rule gives, with an empty account and URL: there is no gateway,
610
+ * so the app calls the provider directly.
611
+ */
612
+ function addAiGatewayBindings(env, manifest, appWorker, deploy) {
613
+ for (const { name: binding } of manifest.resources?.aiGateway ?? []) {
614
+ if (env[binding]) {
615
+ throw new Error(`aiGateway: ${binding} reuses a binding name the Worker already has.`);
616
+ }
617
+ const value = deploy
618
+ ? { ...provisioned(deploy.resources.aiGateway, binding) }
619
+ : { id: aiGatewayIdFor(appWorker, binding), accountId: "", url: "" };
620
+ env[binding] = { type: "json", value };
621
+ }
622
+ }
623
+ /**
624
+ * The manifest's `send_email` bindings, the same on every one of the
625
+ * app's Workers in both modes: Cloudflare's binding with the addresses
626
+ * the manifest lists (the deploy's policy holds the built lists to them).
627
+ * Deployed, Cloudflare checks a message against them and the account's
628
+ * Email Sending domains when the Worker sends; in development Miniflare
629
+ * logs the message and checks the senders.
630
+ */
631
+ function addSendEmailBindings(env, manifest) {
632
+ for (const entry of manifest.resources?.sendEmail ?? []) {
633
+ if (env[entry.name]) {
634
+ throw new Error(`sendEmail: ${entry.name} reuses a binding name the Worker already has.`);
635
+ }
636
+ const senders = entry.allowedSenderAddresses
637
+ ? { allowedSenderAddresses: [...entry.allowedSenderAddresses] }
638
+ : {};
639
+ if (entry.destinationAddress !== undefined &&
640
+ entry.allowedDestinationAddresses !== undefined) {
641
+ throw new Error(`sendEmail: ${entry.name} sets both destinationAddress and allowedDestinationAddresses; set one.`);
642
+ }
643
+ env[entry.name] =
644
+ entry.destinationAddress !== undefined
645
+ ? {
646
+ type: "send-email",
647
+ ...senders,
648
+ destinationAddress: entry.destinationAddress,
649
+ }
650
+ : entry.allowedDestinationAddresses !== undefined
651
+ ? {
652
+ type: "send-email",
653
+ ...senders,
654
+ allowedDestinationAddresses: [
655
+ ...entry.allowedDestinationAddresses,
656
+ ],
657
+ }
658
+ : { type: "send-email", ...senders };
659
+ }
660
+ }
661
+ /**
662
+ * The manifest's Secrets Store secrets, which every one of the app's
663
+ * Workers binds. Deployed, the store and secret the deploy provisioned
664
+ * (placeholders until installed); in development the local store `local`,
665
+ * under the name the deploy would give the secret, so a seeded local
666
+ * secret is named like a deployed one.
667
+ */
668
+ function addSecretsStoreBindings(env, manifest, appWorker, deploy) {
669
+ for (const { name: binding } of manifest.resources?.secretsStore ?? []) {
670
+ if (env[binding]) {
671
+ throw new Error(`secretsStore: ${binding} reuses a binding name the Worker already has.`);
672
+ }
673
+ if (deploy) {
674
+ const secret = provisioned(deploy.resources.secretsStore, binding);
675
+ env[binding] = {
676
+ type: "secrets-store-secret",
677
+ storeId: secret.storeId,
678
+ secretName: secret.secretName,
679
+ };
680
+ }
681
+ else {
682
+ env[binding] = {
683
+ type: "secrets-store-secret",
684
+ storeId: LOCAL_SECRETS_STORE_ID,
685
+ secretName: suffixedName(appWorker, binding),
686
+ };
687
+ }
688
+ }
689
+ }
690
+ /**
691
+ * The manifest's Analytics Engine datasets, which every one of the app's
692
+ * Workers writes to: the `dataset` an entry names, or
693
+ * `<app worker>--<binding>`. Deployed, the app's Worker name is the build's
694
+ * placeholder, which the install rewrites like every other; a named
695
+ * dataset holds none and stays as written.
696
+ */
697
+ function addAnalyticsEngineBindings(env, manifest, appWorker) {
698
+ for (const entry of manifest.resources?.analyticsEngine ?? []) {
699
+ if (env[entry.name]) {
700
+ throw new Error(`analyticsEngine: ${entry.name} reuses a binding name the Worker already has.`);
701
+ }
702
+ env[entry.name] = {
703
+ type: "analytics-engine-dataset",
704
+ name: entry.dataset ?? suffixedName(appWorker, entry.name),
705
+ };
706
+ }
707
+ }
466
708
  /**
467
709
  * DATABASE_PROVIDER and the Hyperdrive configs one of the app's Workers
468
710
  * binds: each config every Worker shares, and those a helper (`forWorker`)
@@ -572,18 +814,25 @@ taken) {
572
814
  return { bindings, exports };
573
815
  }
574
816
  /**
575
- * Check the names of the manifest's `secrets`, and in dev declare the ones
576
- * set locally, with the developer's own keys for the manifest's providers
577
- * and capabilities.
817
+ * Check the names of the manifest's `secrets` and `settings`, and in dev
818
+ * declare the ones set locally (a setting that isn't, with its default),
819
+ * with the developer's own keys for the manifest's providers and
820
+ * capabilities.
578
821
  */
579
822
  function addSecrets(env, options, deploy) {
580
- const secrets = manifestSecretNames(options.manifest);
823
+ const settings = options.manifest.settings ?? [];
824
+ const secrets = [
825
+ ...manifestSecretNames(options.manifest),
826
+ ...settings.map((setting) => setting.name),
827
+ ];
828
+ const settingNames = new Set(settings.map((setting) => setting.name));
581
829
  for (const secret of secrets) {
830
+ const field = settingNames.has(secret) ? "settings" : "secrets";
582
831
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(secret)) {
583
- throw new Error(`secrets: "${secret}" isn't a valid binding name.`);
832
+ throw new Error(`${field}: "${secret}" isn't a valid binding name.`);
584
833
  }
585
834
  if (env[secret] || RESERVED_SECRET_NAME.test(secret)) {
586
- throw new Error(`secrets: ${secret} is a name the deploy sets or a binding it builds.`);
835
+ throw new Error(`${field}: ${secret} is a name the deploy sets or a binding it builds.`);
587
836
  }
588
837
  }
589
838
  if (!deploy) {
@@ -600,6 +849,12 @@ function addSecrets(env, options, deploy) {
600
849
  for (const secret of locallySetSecrets(options.root ?? process.cwd(), options.ctx.mode ?? "development", [...names].filter((name) => !env[name]))) {
601
850
  env[secret] = { type: "secret" };
602
851
  }
852
+ // A setting nobody set locally reads its default, as a deployed one does.
853
+ for (const setting of settings) {
854
+ if (!env[setting.name] && setting.default !== undefined) {
855
+ env[setting.name] = { type: "text", value: setting.default };
856
+ }
857
+ }
603
858
  }
604
859
  }
605
860
  /** The {@link DEV_GATEWAY_KEYS} of the manifest's providers and capabilities. */
@@ -630,15 +885,6 @@ function observability() {
630
885
  issues: { ...EVERYAPP_OBSERVABILITY.issues },
631
886
  };
632
887
  }
633
- /**
634
- * The Workflow a binding defines, named after the app's Worker:
635
- * `every-acme-seo` and `RANK_CHECK` → `every-acme-seo--rank-check`.
636
- * Workflow names are unique in the account, and new app ids can't contain
637
- * `--`, so one app's Workflow is never named like another app's.
638
- */
639
- export function workflowNameFor(workerName, binding) {
640
- return `${workerName}--${binding.toLowerCase().replaceAll("_", "-")}`;
641
- }
642
888
  /**
643
889
  * The local D1 database id for a binding: a 32-hex string, because
644
890
  * `cf d1 … --local` rejects names. The everyapp CLI computes the same id to
@@ -709,8 +955,10 @@ function workerNameFor(appId) {
709
955
  }
710
956
  /**
711
957
  * Copies of the gateway's naming rules (@every-app/perimeter/manifest's
712
- * resourceNameFor and bucketNameFor): `DB` and `KV` (`R2` for a bucket) take
713
- * the Worker's name, any other binding `<worker>--<binding>`.
958
+ * resourceNameFor, bucketNameFor, vectorizeNameFor and storeSecretNameFor):
959
+ * `DB` and `KV` (`R2` for a bucket) take the Worker's name, any other
960
+ * binding (and every Vectorize index and Secrets Store secret)
961
+ * `<worker>--<binding>`.
714
962
  */
715
963
  function resourceNameFor(workerName, binding) {
716
964
  return binding === "DB" || binding === "KV"
@@ -720,9 +968,20 @@ function resourceNameFor(workerName, binding) {
720
968
  function bucketNameFor(workerName, binding) {
721
969
  return binding === "R2" ? workerName : suffixedName(workerName, binding);
722
970
  }
971
+ /** A copy of @every-app/perimeter/manifest's queueNameFor: `<worker>--<binding>`. */
972
+ function queueNameFor(workerName, binding) {
973
+ return suffixedName(workerName, binding);
974
+ }
723
975
  function suffixedName(workerName, binding) {
724
976
  return `${workerName}--${binding.toLowerCase().replaceAll("_", "-")}`;
725
977
  }
978
+ /**
979
+ * A copy of the gateway's aiGatewayIdFor: one hyphen, since an AI
980
+ * Gateway's id may not hold `--`.
981
+ */
982
+ function aiGatewayIdFor(workerName, binding) {
983
+ return `${workerName}-${binding.toLowerCase().replaceAll("_", "-")}`;
984
+ }
726
985
  function assertAppId(id) {
727
986
  if (typeof id !== "string" || !/^[a-z]([a-z0-9-]*[a-z0-9])?$/.test(id)) {
728
987
  throw new Error(`everyapp.config.ts id must be kebab-case (lowercase letters, digits, hyphens); got ${JSON.stringify(id)}.`);
@@ -3,6 +3,6 @@
3
3
  * signs with, its issuer and its key id. For the platform's local dev tools
4
4
  * (the CLI, `@every-app/perimeter/dev`); never imported by a Worker.
5
5
  */
6
- export { DEV_ISSUER, DEV_PRIVATE_KEY_PEM, DEV_PUBLIC_KEY_PEM, } from "./keypair.js";
6
+ export { DEV_ISSUER, DEV_ORG_ID, DEV_PRIVATE_KEY_PEM, DEV_PUBLIC_KEY_PEM, } from "./keypair.js";
7
7
  export { IDENTITY_DEV_KEY_ID } from "../internal/protocol.js";
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dev/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dev/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC"}
package/dist/dev/index.js CHANGED
@@ -3,5 +3,5 @@
3
3
  * signs with, its issuer and its key id. For the platform's local dev tools
4
4
  * (the CLI, `@every-app/perimeter/dev`); never imported by a Worker.
5
5
  */
6
- export { DEV_ISSUER, DEV_PRIVATE_KEY_PEM, DEV_PUBLIC_KEY_PEM, } from "./keypair.js";
6
+ export { DEV_ISSUER, DEV_ORG_ID, DEV_PRIVATE_KEY_PEM, DEV_PUBLIC_KEY_PEM, } from "./keypair.js";
7
7
  export { IDENTITY_DEV_KEY_ID } from "../internal/protocol.js";