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

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 +608 -2
  2. package/dist/cloudflare/index.d.ts +21 -1
  3. package/dist/cloudflare/index.d.ts.map +1 -1
  4. package/dist/cloudflare/index.js +21 -1
  5. package/dist/cloudflare/sentinel.d.ts +69 -0
  6. package/dist/cloudflare/sentinel.d.ts.map +1 -0
  7. package/dist/cloudflare/sentinel.js +50 -0
  8. package/dist/cloudflare/worker.d.ts +511 -0
  9. package/dist/cloudflare/worker.d.ts.map +1 -0
  10. package/dist/cloudflare/worker.js +738 -0
  11. package/dist/dev/index.d.ts +8 -0
  12. package/dist/dev/index.d.ts.map +1 -0
  13. package/dist/dev/index.js +7 -0
  14. package/dist/dev/keypair.d.ts +24 -0
  15. package/dist/dev/keypair.d.ts.map +1 -0
  16. package/dist/dev/keypair.js +60 -0
  17. package/dist/internal/aiProviders.d.ts +67 -0
  18. package/dist/internal/aiProviders.d.ts.map +1 -0
  19. package/dist/internal/aiProviders.js +220 -0
  20. package/dist/internal/appSettings.d.ts +237 -0
  21. package/dist/internal/appSettings.d.ts.map +1 -0
  22. package/dist/internal/appSettings.js +374 -0
  23. package/dist/internal/capabilities.d.ts +1344 -0
  24. package/dist/internal/capabilities.d.ts.map +1 -0
  25. package/dist/internal/capabilities.js +1521 -0
  26. package/dist/internal/devProviders.d.ts +49 -0
  27. package/dist/internal/devProviders.d.ts.map +1 -0
  28. package/dist/internal/devProviders.js +62 -0
  29. package/dist/internal/email.d.ts +280 -0
  30. package/dist/internal/email.d.ts.map +1 -0
  31. package/dist/internal/email.js +613 -0
  32. package/dist/internal/events.d.ts +182 -0
  33. package/dist/internal/events.d.ts.map +1 -0
  34. package/dist/internal/events.js +324 -0
  35. package/dist/internal/gatewaySettings.d.ts +82 -0
  36. package/dist/internal/gatewaySettings.d.ts.map +1 -0
  37. package/dist/internal/gatewaySettings.js +209 -0
  38. package/dist/internal/identity.d.ts +88 -0
  39. package/dist/internal/identity.d.ts.map +1 -0
  40. package/dist/internal/identity.js +231 -0
  41. package/dist/internal/index.d.ts +19 -0
  42. package/dist/internal/index.d.ts.map +1 -0
  43. package/dist/internal/index.js +18 -0
  44. package/dist/internal/members.d.ts +35 -0
  45. package/dist/internal/members.d.ts.map +1 -0
  46. package/dist/internal/members.js +7 -0
  47. package/dist/internal/oauthClient.d.ts +63 -0
  48. package/dist/internal/oauthClient.d.ts.map +1 -0
  49. package/dist/internal/oauthClient.js +194 -0
  50. package/dist/internal/oauthScopes.d.ts +117 -0
  51. package/dist/internal/oauthScopes.d.ts.map +1 -0
  52. package/dist/internal/oauthScopes.js +416 -0
  53. package/dist/internal/organizationName.d.ts +18 -0
  54. package/dist/internal/organizationName.d.ts.map +1 -0
  55. package/dist/internal/organizationName.js +24 -0
  56. package/dist/internal/protocol.d.ts +195 -0
  57. package/dist/internal/protocol.d.ts.map +1 -0
  58. package/dist/internal/protocol.js +250 -0
  59. package/dist/internal/providerApps.d.ts +75 -0
  60. package/dist/internal/providerApps.d.ts.map +1 -0
  61. package/dist/internal/providerApps.js +59 -0
  62. package/dist/internal/providerRegistry.d.ts +147 -0
  63. package/dist/internal/providerRegistry.d.ts.map +1 -0
  64. package/dist/internal/providerRegistry.js +262 -0
  65. package/dist/internal/providerSpec.d.ts +55 -0
  66. package/dist/internal/providerSpec.d.ts.map +1 -0
  67. package/dist/internal/providerSpec.js +746 -0
  68. package/dist/internal/remoteMcp.d.ts +188 -0
  69. package/dist/internal/remoteMcp.d.ts.map +1 -0
  70. package/dist/internal/remoteMcp.js +543 -0
  71. package/dist/internal/tools.d.ts +115 -0
  72. package/dist/internal/tools.d.ts.map +1 -0
  73. package/dist/internal/tools.js +80 -0
  74. package/dist/server/attribution.d.ts +39 -0
  75. package/dist/server/attribution.d.ts.map +1 -0
  76. package/dist/server/attribution.js +67 -0
  77. package/dist/server/authorizeUrl.d.ts +43 -0
  78. package/dist/server/authorizeUrl.d.ts.map +1 -0
  79. package/dist/server/authorizeUrl.js +110 -0
  80. package/dist/server/emit.d.ts +63 -0
  81. package/dist/server/emit.d.ts.map +1 -0
  82. package/dist/server/emit.js +101 -0
  83. package/dist/server/everyApp.d.ts +81 -0
  84. package/dist/server/everyApp.d.ts.map +1 -0
  85. package/dist/server/everyApp.js +185 -0
  86. package/dist/server/gatewayFetch.d.ts +37 -0
  87. package/dist/server/gatewayFetch.d.ts.map +1 -0
  88. package/dist/server/gatewayFetch.js +115 -0
  89. package/dist/server/index.d.ts +18 -0
  90. package/dist/server/index.d.ts.map +1 -0
  91. package/dist/server/index.js +15 -0
  92. package/dist/server/integrationFetch.d.ts +131 -0
  93. package/dist/server/integrationFetch.d.ts.map +1 -0
  94. package/dist/server/integrationFetch.js +526 -0
  95. package/dist/server/listMembers.d.ts +32 -0
  96. package/dist/server/listMembers.d.ts.map +1 -0
  97. package/dist/server/listMembers.js +74 -0
  98. package/dist/server/nodeServer.d.ts +48 -0
  99. package/dist/server/nodeServer.d.ts.map +1 -0
  100. package/dist/server/nodeServer.js +45 -0
  101. package/dist/server/sendEmail.d.ts +39 -0
  102. package/dist/server/sendEmail.d.ts.map +1 -0
  103. package/dist/server/sendEmail.js +114 -0
  104. package/dist/server/tools.d.ts +184 -0
  105. package/dist/server/tools.d.ts.map +1 -0
  106. package/dist/server/tools.js +347 -0
  107. package/dist/server/toolsEndpoint.d.ts +32 -0
  108. package/dist/server/toolsEndpoint.d.ts.map +1 -0
  109. package/dist/server/toolsEndpoint.js +231 -0
  110. package/package.json +21 -31
  111. package/dist/cloudflare/getLocalD1Url.d.ts +0 -2
  112. package/dist/cloudflare/getLocalD1Url.d.ts.map +0 -1
  113. package/dist/cloudflare/getLocalD1Url.js +0 -40
  114. package/dist/cloudflare/lazyInit.d.ts +0 -22
  115. package/dist/cloudflare/lazyInit.d.ts.map +0 -1
  116. package/dist/cloudflare/lazyInit.js +0 -65
  117. package/dist/cloudflare/server/gateway.d.ts +0 -29
  118. package/dist/cloudflare/server/gateway.d.ts.map +0 -1
  119. package/dist/cloudflare/server/gateway.js +0 -69
  120. package/dist/cloudflare/server/index.d.ts +0 -3
  121. package/dist/cloudflare/server/index.d.ts.map +0 -1
  122. package/dist/cloudflare/server/index.js +0 -2
  123. package/dist/core/authenticatedFetch.d.ts +0 -9
  124. package/dist/core/authenticatedFetch.d.ts.map +0 -1
  125. package/dist/core/authenticatedFetch.js +0 -31
  126. package/dist/core/index.d.ts +0 -4
  127. package/dist/core/index.d.ts.map +0 -1
  128. package/dist/core/index.js +0 -2
  129. package/dist/core/sessionManager.d.ts +0 -58
  130. package/dist/core/sessionManager.d.ts.map +0 -1
  131. package/dist/core/sessionManager.js +0 -357
  132. package/dist/shared/bypassGatewayLocalOnly.d.ts +0 -15
  133. package/dist/shared/bypassGatewayLocalOnly.d.ts.map +0 -1
  134. package/dist/shared/bypassGatewayLocalOnly.js +0 -45
  135. package/dist/shared/parseMessagePayload.d.ts +0 -3
  136. package/dist/shared/parseMessagePayload.d.ts.map +0 -1
  137. package/dist/shared/parseMessagePayload.js +0 -18
  138. package/dist/tanstack/EmbeddedAppProvider.d.ts +0 -30
  139. package/dist/tanstack/EmbeddedAppProvider.d.ts.map +0 -1
  140. package/dist/tanstack/EmbeddedAppProvider.js +0 -57
  141. package/dist/tanstack/GatewayRequiredError.d.ts +0 -20
  142. package/dist/tanstack/GatewayRequiredError.d.ts.map +0 -1
  143. package/dist/tanstack/GatewayRequiredError.js +0 -91
  144. package/dist/tanstack/_internal/useEveryAppSession.d.ts +0 -18
  145. package/dist/tanstack/_internal/useEveryAppSession.d.ts.map +0 -1
  146. package/dist/tanstack/_internal/useEveryAppSession.js +0 -47
  147. package/dist/tanstack/index.d.ts +0 -4
  148. package/dist/tanstack/index.d.ts.map +0 -1
  149. package/dist/tanstack/index.js +0 -3
  150. package/dist/tanstack/server/authConfig.d.ts +0 -3
  151. package/dist/tanstack/server/authConfig.d.ts.map +0 -1
  152. package/dist/tanstack/server/authConfig.js +0 -13
  153. package/dist/tanstack/server/authenticateRequest.d.ts +0 -31
  154. package/dist/tanstack/server/authenticateRequest.d.ts.map +0 -1
  155. package/dist/tanstack/server/authenticateRequest.js +0 -154
  156. package/dist/tanstack/server/index.d.ts +0 -4
  157. package/dist/tanstack/server/index.d.ts.map +0 -1
  158. package/dist/tanstack/server/index.js +0 -2
  159. package/dist/tanstack/server/types.d.ts +0 -5
  160. package/dist/tanstack/server/types.d.ts.map +0 -1
  161. package/dist/tanstack/server/types.js +0 -1
  162. package/dist/tanstack/useEveryAppRouter.d.ts +0 -7
  163. package/dist/tanstack/useEveryAppRouter.d.ts.map +0 -1
  164. package/dist/tanstack/useEveryAppRouter.js +0 -66
  165. package/dist/tanstack/useSessionTokenClientMiddleware.d.ts +0 -2
  166. package/dist/tanstack/useSessionTokenClientMiddleware.d.ts.map +0 -1
  167. package/dist/tanstack/useSessionTokenClientMiddleware.js +0 -29
@@ -0,0 +1,374 @@
1
+ /**
2
+ * What an app needs set before it works, and whether it is: the model
3
+ * behind "needs setup" wherever an app is shown (the gateway's home and
4
+ * Admin → Apps, `everyapp status`, `everyapp secret list`, the end of
5
+ * `everyapp deploy`, and what `everyapp configure <app>` walks through).
6
+ *
7
+ * A manifest declares three kinds of setting. An AI provider
8
+ * (`providers`) and a capability (`capabilities`) are the Gateway's: their
9
+ * keys and clients live on the Gateway Worker, set once for every app
10
+ * with `everyapp secret set <NAME>`. The app's own secrets (`secrets`)
11
+ * live on its Worker, set from its directory. Each declaration carries a
12
+ * need: required (the default; the app doesn't open until it is set),
13
+ * optional (the app opens, and the feature says what is missing where it
14
+ * is used), or a member of a named any-of group (the app opens once any
15
+ * member is set; only for an app that picks among the set members at run
16
+ * time). Each may say `why` it is needed and where it comes from
17
+ * (`docs`, an https URL); for providers and capabilities the registries
18
+ * here supply a default.
19
+ *
20
+ * Everything in this module is pure and tenant-neutral: a manifest ships
21
+ * in a release, and what is set is asked of the caller (`isSet`), which
22
+ * reads the Gateway's env, cf's secret list, or the registry's record of
23
+ * the app Worker's secret names.
24
+ */
25
+ import { CATALOG, capabilitySettings, } from "./capabilities.js";
26
+ import { isInstallOwnedGatewaySetting, isSettableGatewaySetting, } from "./gatewaySettings.js";
27
+ import { remoteMcpAuthLabel, remoteMcpOf, remoteMcpSecretOf, } from "./remoteMcp.js";
28
+ /** The need an entry declares; required unless it says otherwise. */
29
+ export function needOf(entry) {
30
+ if (!entry)
31
+ return { kind: "required" };
32
+ if (typeof entry.anyOf === "string" && entry.anyOf.trim()) {
33
+ return { kind: "anyOf", group: entry.anyOf.trim() };
34
+ }
35
+ if (entry.optional === true)
36
+ return { kind: "optional" };
37
+ return { kind: "required" };
38
+ }
39
+ function needFields(entry) {
40
+ if (!entry || typeof entry !== "object")
41
+ return {};
42
+ const record = entry;
43
+ return {
44
+ ...(typeof record["why"] === "string" ? { why: record["why"] } : {}),
45
+ ...(typeof record["docs"] === "string" ? { docs: record["docs"] } : {}),
46
+ ...(typeof record["optional"] === "boolean"
47
+ ? { optional: record["optional"] }
48
+ : {}),
49
+ ...(typeof record["setup"] === "string" ? { setup: record["setup"] } : {}),
50
+ ...(typeof record["anyOf"] === "string" ? { anyOf: record["anyOf"] } : {}),
51
+ };
52
+ }
53
+ /** The providers the manifest lists, each as an entry whatever form it took. */
54
+ export function providerEntries(manifest) {
55
+ return (manifest.providers ?? []).flatMap((entry) => {
56
+ if (typeof entry === "string")
57
+ return [{ id: entry }];
58
+ if (entry && typeof entry === "object" && typeof entry.id === "string") {
59
+ return [{ id: entry.id, ...needFields(entry) }];
60
+ }
61
+ return [];
62
+ });
63
+ }
64
+ /** The provider ids the manifest lists, in order. */
65
+ export function providerIds(manifest) {
66
+ return providerEntries(manifest).map((entry) => entry.id);
67
+ }
68
+ /** The app's own secrets the manifest lists, each as an entry whatever form it took. */
69
+ export function secretEntries(manifest) {
70
+ return (manifest.secrets ?? []).flatMap((entry) => {
71
+ if (typeof entry === "string")
72
+ return [{ name: entry }];
73
+ if (entry && typeof entry === "object" && typeof entry.name === "string") {
74
+ return [{ name: entry.name, ...needFields(entry) }];
75
+ }
76
+ return [];
77
+ });
78
+ }
79
+ /** The names of the app's own secrets, in order. */
80
+ export function secretNames(manifest) {
81
+ return secretEntries(manifest).map((entry) => entry.name);
82
+ }
83
+ /**
84
+ * The Gateway settings an AI provider needs, the install's left out (set
85
+ * already). A catalog provider's names are settable by definition; a
86
+ * registered row's are its own, so they count too.
87
+ */
88
+ function providerNames(capability) {
89
+ return capabilitySettings(capability).filter((name) => !isInstallOwnedGatewaySetting(name));
90
+ }
91
+ /** A capability's Gateway settings: what it needs, and what it also reads. */
92
+ function capabilityNames(capability) {
93
+ const settable = (names) => names.filter((name) => isSettableGatewaySetting(name) && !isInstallOwnedGatewaySetting(name));
94
+ switch (capability.mode) {
95
+ case "api_key":
96
+ return { names: [...capabilitySettings(capability)], alsoReads: [] };
97
+ case "ai":
98
+ return { names: providerNames(capability), alsoReads: [] };
99
+ case "service":
100
+ return {
101
+ names: settable(capability.settings),
102
+ alsoReads: settable(capability.optionalSettings),
103
+ };
104
+ case "oauth_client": {
105
+ const names = [
106
+ capability.secrets.clientId,
107
+ ...(capability.secrets.clientSecret
108
+ ? [capability.secrets.clientSecret]
109
+ : []),
110
+ ];
111
+ const host = capability.hostSetting ? [capability.hostSetting] : [];
112
+ // An instance setting with a default is read when set; without one
113
+ // the provider has no origin until it is set.
114
+ return capability.defaultOrigin
115
+ ? { names, alsoReads: host }
116
+ : { names: [...names, ...host], alsoReads: [] };
117
+ }
118
+ }
119
+ }
120
+ /**
121
+ * Where a capability's key or client comes from, when the registry knows:
122
+ * an API-key provider's access page, or an OAuth client's console (a path
123
+ * on the default instance for a provider with no fixed host).
124
+ */
125
+ function capabilityDocs(capability) {
126
+ switch (capability.mode) {
127
+ case "api_key":
128
+ case "ai":
129
+ return capability.docs;
130
+ case "oauth_client":
131
+ if (capability.console.startsWith("https://"))
132
+ return capability.console;
133
+ return capability.defaultOrigin
134
+ ? `${capability.defaultOrigin}${capability.console}`
135
+ : undefined;
136
+ case "service":
137
+ return undefined;
138
+ }
139
+ }
140
+ /** What a provider's entry says about getting its key: its hint, then each setting's own, named when there are several. */
141
+ function providerHint(capability, names) {
142
+ if (capability.mode === "service" || capability.mode === "oauth_client") {
143
+ return {};
144
+ }
145
+ const details = capability.secrets ?? [];
146
+ const lines = [
147
+ ...(capability.hint ? [capability.hint] : []),
148
+ ...details
149
+ .filter((detail) => detail.hint && names.includes(detail.name))
150
+ .map((detail) => names.length > 1 ? `${detail.name}: ${detail.hint}` : detail.hint),
151
+ ];
152
+ return lines.length > 0 ? { hint: lines.join(" ") } : {};
153
+ }
154
+ function withNeed(setting, entry, defaults = {}) {
155
+ const docs = entry?.docs ?? defaults.docs;
156
+ // The registry's guide for a Gateway setting; the manifest's for the app's own secret.
157
+ const setup = setting.holder === "gateway" ? defaults.setup : entry?.setup;
158
+ return {
159
+ ...setting,
160
+ need: needOf(entry),
161
+ ...(entry?.why ? { why: entry.why } : {}),
162
+ ...(docs ? { docs } : {}),
163
+ ...(setup ? { setup } : {}),
164
+ ...(defaults.hint ? { hint: defaults.hint } : {}),
165
+ };
166
+ }
167
+ /**
168
+ * Every setting the manifest declares, in manifest order: its AI
169
+ * providers, its capabilities, the AI proxy's extra routes when `ai.routes`
170
+ * asks for any, then the app's own secrets. A provider or capability the
171
+ * gateway doesn't offer contributes nothing (the manifest validator refuses
172
+ * it elsewhere); so does a capability with nothing to set (`members`),
173
+ * which is always set. `lookup` is where ids are found: the catalog alone
174
+ * by default, or a gateway's registry with its registered rows.
175
+ */
176
+ export function appSettings(manifest, lookup = CATALOG) {
177
+ const settings = [];
178
+ for (const entry of providerEntries(manifest)) {
179
+ const capability = lookup.get(entry.id);
180
+ if (capability?.mode !== "ai")
181
+ continue;
182
+ const names = providerNames(capability);
183
+ settings.push(withNeed({
184
+ kind: "provider",
185
+ id: entry.id,
186
+ label: capability.label,
187
+ holder: "gateway",
188
+ names,
189
+ alsoReads: [],
190
+ }, entry, {
191
+ docs: capability.docs,
192
+ setup: capability.setup,
193
+ ...providerHint(capability, names),
194
+ }));
195
+ }
196
+ for (const [id, entry] of Object.entries(manifest.capabilities ?? {})) {
197
+ const capability = lookup.get(id);
198
+ // An AI provider under `capabilities` is the validator's to refuse.
199
+ if (!capability || capability.mode === "ai")
200
+ continue;
201
+ const { names, alsoReads } = capabilityNames(capability);
202
+ settings.push(withNeed({
203
+ kind: "capability",
204
+ id,
205
+ label: capability.label,
206
+ holder: "gateway",
207
+ names,
208
+ alsoReads,
209
+ }, needFields(entry), {
210
+ docs: capabilityDocs(capability),
211
+ setup: capability.setup,
212
+ ...providerHint(capability, names),
213
+ }));
214
+ }
215
+ if (manifest.ai?.routes?.length) {
216
+ settings.push({
217
+ kind: "ai-routes",
218
+ id: "ai-routes",
219
+ label: "AI proxy routes",
220
+ holder: "gateway",
221
+ names: ["AI_PROXY_EXTRA_ROUTES"],
222
+ alsoReads: [],
223
+ need: { kind: "required" },
224
+ why: `Lets the app call ${manifest.ai.routes.join(", ")} through the AI proxy.`,
225
+ setup: "setup/openai.md",
226
+ });
227
+ }
228
+ const remote = remoteMcpOf(manifest);
229
+ if (remote) {
230
+ const secret = remoteMcpSecretOf(remote.auth);
231
+ if (secret) {
232
+ const label = typeof manifest.name === "string" && manifest.name.trim()
233
+ ? manifest.name.trim()
234
+ : "the MCP server";
235
+ settings.push({
236
+ kind: "remote-mcp",
237
+ id: secret,
238
+ label: `${label} credential`,
239
+ holder: "gateway",
240
+ names: [secret],
241
+ alsoReads: [],
242
+ need: { kind: "required" },
243
+ why: `What ${label} expects: ${remoteMcpAuthLabel(remote.auth)}. The Gateway sends it to ${remote.url} and nowhere else.`,
244
+ setup: "setup/remote-mcp.md",
245
+ });
246
+ }
247
+ }
248
+ for (const entry of secretEntries(manifest)) {
249
+ settings.push(withNeed({
250
+ kind: "secret",
251
+ id: entry.name,
252
+ label: entry.name,
253
+ holder: "app",
254
+ names: [entry.name],
255
+ alsoReads: [],
256
+ }, entry));
257
+ }
258
+ return settings;
259
+ }
260
+ /** Whether each name of `setting` is set: all → true, one unset → false, else unknown. */
261
+ function settingIsSet(setting, isSet) {
262
+ let unknown = false;
263
+ for (const name of setting.names) {
264
+ const state = isSet(setting.holder, name);
265
+ if (state === false)
266
+ return false;
267
+ if (state === null)
268
+ unknown = true;
269
+ }
270
+ return unknown ? null : true;
271
+ }
272
+ /**
273
+ * Every setting against what is set. `isSet` answers per holder and name:
274
+ * true, false, or null when it can't tell (the registry never recorded
275
+ * the app Worker's secret names), which never blocks. An any-of group is
276
+ * met once any member is set; while none is and none is unknown, every
277
+ * member blocks.
278
+ */
279
+ export function evaluateAppSettings(settings, isSet, options = {}) {
280
+ const evaluated = settings.map((setting) => {
281
+ const ready = options.readiness?.(setting);
282
+ return {
283
+ ...setting,
284
+ set: ready === undefined ? settingIsSet(setting, isSet) : ready,
285
+ blocking: false,
286
+ };
287
+ });
288
+ const groups = [];
289
+ for (const setting of evaluated) {
290
+ if (setting.need.kind !== "anyOf")
291
+ continue;
292
+ const group = setting.need.group;
293
+ let found = groups.find((each) => each.group === group);
294
+ if (!found) {
295
+ found = { group, members: [], met: false };
296
+ groups.push(found);
297
+ }
298
+ found.members.push(setting);
299
+ }
300
+ for (const group of groups) {
301
+ group.met = group.members.some((member) => member.set === true);
302
+ const unknown = group.members.some((member) => member.set === null);
303
+ if (!group.met && !unknown) {
304
+ for (const member of group.members)
305
+ member.blocking = true;
306
+ }
307
+ }
308
+ for (const setting of evaluated) {
309
+ if (setting.need.kind === "required" && setting.set === false) {
310
+ setting.blocking = true;
311
+ }
312
+ }
313
+ const unmet = evaluated.filter((setting) => setting.blocking);
314
+ return { ready: unmet.length === 0, settings: evaluated, groups, unmet };
315
+ }
316
+ /**
317
+ * What to run for an app that needs setup: `everyapp configure <app>`,
318
+ * which reads the app's manifest (from the registry, so it runs from
319
+ * anywhere), prompts for each unmet setting (one member of an any-of group
320
+ * is enough: it asks which) and sets them where they are held. Null when
321
+ * the app is ready. `cli` is how the operator runs everyapp (`pnpm
322
+ * everyapp` from a checkout). Scripts that set one name at a time use
323
+ * `everyapp secret set NAME [--app <id>]` instead.
324
+ *
325
+ * A provider app (`provider`: the gateway's own, with no Worker and no
326
+ * directory; `everyapp mcp on <id>`, an MCP app) has nothing to configure: its
327
+ * command is the `secret set` of its Gateway key (the first member of an
328
+ * unmet any-of group), as `mcp list` says it.
329
+ */
330
+ export function setupCommand(report, { cli, appId, provider = false, }) {
331
+ if (report.unmet.length === 0)
332
+ return null;
333
+ if (!provider)
334
+ return { command: `${cli} configure ${appId}` };
335
+ const names = [];
336
+ const add = (setting) => {
337
+ for (const name of setting.names)
338
+ if (!names.includes(name))
339
+ names.push(name);
340
+ };
341
+ for (const setting of report.unmet) {
342
+ if (setting.need.kind === "required")
343
+ add(setting);
344
+ }
345
+ for (const group of report.groups) {
346
+ const first = group.members.find((member) => member.blocking);
347
+ if (first)
348
+ add(first);
349
+ }
350
+ return { command: `${cli} secret set ${names.join(" ")}` };
351
+ }
352
+ export function appSetupOf(report, options) {
353
+ const strip = ({ alsoReads: _alsoReads, ...setting }) => setting;
354
+ return {
355
+ ready: report.ready,
356
+ settings: report.settings.map(strip),
357
+ unmet: report.unmet.map(strip),
358
+ groups: report.groups.map((group) => ({
359
+ group: group.group,
360
+ met: group.met,
361
+ members: group.members.map((member) => member.id),
362
+ })),
363
+ command: options.withCommand === false ? null : setupCommand(report, options),
364
+ };
365
+ }
366
+ /** The provider registry's labels, for anything that names a provider to a person. */
367
+ export function providerLabel(id, lookup = CATALOG) {
368
+ return lookup.get(id)?.label ?? id;
369
+ }
370
+ /** The capability `id` names in `lookup`, as an API-key provider, or undefined. */
371
+ export function apiKeyCapabilityOf(id, lookup = CATALOG) {
372
+ const capability = lookup.get(id);
373
+ return capability?.mode === "api_key" ? capability : undefined;
374
+ }