@every-app/sdk 0.3.0-rc.13 → 0.3.0-rc.14
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.
- package/README.md +7 -8
- package/dist/cloudflare/worker.d.ts +18 -9
- package/dist/cloudflare/worker.d.ts.map +1 -1
- package/dist/cloudflare/worker.js +13 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/internal/appSettings.d.ts +124 -79
- package/dist/internal/appSettings.d.ts.map +1 -1
- package/dist/internal/appSettings.js +236 -124
- package/dist/manifest.d.ts +49 -13
- package/dist/manifest.d.ts.map +1 -1
- package/dist/server/tools.d.ts +5 -2
- package/dist/server/tools.d.ts.map +1 -1
- package/dist/server/tools.js +5 -2
- package/package.json +1 -1
|
@@ -8,17 +8,20 @@
|
|
|
8
8
|
* (`providers`) and a capability (`capabilities`) are the Gateway's: their
|
|
9
9
|
* keys and clients live on the Gateway Worker, set once for every app
|
|
10
10
|
* with `everyapp secret set <NAME>`. The app's own secrets (`secrets`)
|
|
11
|
-
* live on its Worker, set from its directory.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
11
|
+
* live on its Worker, set from its directory. Everything the manifest
|
|
12
|
+
* lists at its top level is required: the app doesn't open until it is
|
|
13
|
+
* set. The rest is grouped into features (`features`): each a named set of
|
|
14
|
+
* secrets, settings and the Gateway capabilities and providers it needs,
|
|
15
|
+
* with numbered setup steps. A required feature's values are required; an
|
|
16
|
+
* optional feature is all or nothing, never blocking: off while none of
|
|
17
|
+
* its own values is set, incomplete while some are, ready once all are.
|
|
18
|
+
* Each declaration may say `why` it is needed, where it comes from
|
|
19
|
+
* (`docs`, an https URL) and, for an app's own value, `how` to get it;
|
|
20
|
+
* for providers and capabilities the registries here supply a default. An
|
|
21
|
+
* app's plain settings (`settings`: a host, a project id, a region) are
|
|
22
|
+
* held like its secrets, on its Worker, but are values rather than keys:
|
|
23
|
+
* each says what it takes (a URL, a number, one of a list) and may give a
|
|
24
|
+
* default.
|
|
22
25
|
*
|
|
23
26
|
* Everything in this module is pure and tenant-neutral: a manifest ships
|
|
24
27
|
* in a release, and what is set is asked of the caller (`isSet`), which
|
|
@@ -29,17 +32,6 @@ import { CATALOG, capabilitySettings, } from "./capabilities.js";
|
|
|
29
32
|
import { aiDefaultSetupHint, aiRequiredSettings, resolveAiDefault, } from "./aiDefault.js";
|
|
30
33
|
import { isInstallOwnedGatewaySetting, isSettableGatewaySetting, } from "./gatewaySettings.js";
|
|
31
34
|
import { hasRemoteMcpBlock, remoteMcpBlockProblem } from "./remoteMcp.js";
|
|
32
|
-
/** The need an entry declares; required unless it says otherwise. */
|
|
33
|
-
export function needOf(entry) {
|
|
34
|
-
if (!entry)
|
|
35
|
-
return { kind: "required" };
|
|
36
|
-
if (typeof entry.anyOf === "string" && entry.anyOf.trim()) {
|
|
37
|
-
return { kind: "anyOf", group: entry.anyOf.trim() };
|
|
38
|
-
}
|
|
39
|
-
if (entry.optional === true)
|
|
40
|
-
return { kind: "optional" };
|
|
41
|
-
return { kind: "required" };
|
|
42
|
-
}
|
|
43
35
|
function needFields(entry) {
|
|
44
36
|
if (!entry || typeof entry !== "object")
|
|
45
37
|
return {};
|
|
@@ -47,11 +39,66 @@ function needFields(entry) {
|
|
|
47
39
|
return {
|
|
48
40
|
...(typeof record["why"] === "string" ? { why: record["why"] } : {}),
|
|
49
41
|
...(typeof record["docs"] === "string" ? { docs: record["docs"] } : {}),
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** `how`, `generate` and `file` as a stored entry has them. */
|
|
45
|
+
function ownValueFields(entry) {
|
|
46
|
+
if (!entry || typeof entry !== "object")
|
|
47
|
+
return {};
|
|
48
|
+
const record = entry;
|
|
49
|
+
return {
|
|
50
|
+
...(typeof record["how"] === "string" ? { how: record["how"] } : {}),
|
|
51
|
+
...(record["generate"] === true ? { generate: true } : {}),
|
|
52
|
+
...(record["file"] === true ? { file: true } : {}),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const stringList = (value) => Array.isArray(value)
|
|
56
|
+
? value.filter((each) => typeof each === "string")
|
|
57
|
+
: [];
|
|
58
|
+
/** The features the manifest declares, in order, each read whatever a stored row holds. */
|
|
59
|
+
export function featureEntries(manifest) {
|
|
60
|
+
const features = manifest.features;
|
|
61
|
+
if (!features || typeof features !== "object")
|
|
62
|
+
return [];
|
|
63
|
+
return Object.entries(features).flatMap(([id, raw]) => {
|
|
64
|
+
if (!raw || typeof raw !== "object")
|
|
65
|
+
return [];
|
|
66
|
+
const record = raw;
|
|
67
|
+
return [
|
|
68
|
+
{
|
|
69
|
+
id,
|
|
70
|
+
name: typeof record["name"] === "string" && record["name"].trim()
|
|
71
|
+
? record["name"]
|
|
72
|
+
: id,
|
|
73
|
+
required: record["required"] === true,
|
|
74
|
+
...(typeof record["why"] === "string" ? { why: record["why"] } : {}),
|
|
75
|
+
steps: stringList(record["steps"]),
|
|
76
|
+
capabilities: stringList(record["capabilities"]),
|
|
77
|
+
providers: stringList(record["providers"]),
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/** One feature's raw `secrets` or `settings` list, with the feature id. */
|
|
83
|
+
function featureLists(manifest, key) {
|
|
84
|
+
const features = manifest.features;
|
|
85
|
+
if (!features || typeof features !== "object")
|
|
86
|
+
return [];
|
|
87
|
+
return Object.entries(features).flatMap(([feature, raw]) => {
|
|
88
|
+
const list = raw && typeof raw === "object"
|
|
89
|
+
? raw[key]
|
|
90
|
+
: undefined;
|
|
91
|
+
return Array.isArray(list) ? [{ feature, list }] : [];
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/** The need of a capability or provider: optional when an optional feature lists it, else required. */
|
|
95
|
+
function gatewayNeedOf(features, kind, id) {
|
|
96
|
+
const owner = features.find((feature) => feature[kind].includes(id));
|
|
97
|
+
if (!owner)
|
|
98
|
+
return { need: { kind: "required" } };
|
|
99
|
+
return {
|
|
100
|
+
need: { kind: owner.required ? "required" : "optional" },
|
|
101
|
+
feature: owner.id,
|
|
55
102
|
};
|
|
56
103
|
}
|
|
57
104
|
/** The providers the manifest lists, each as an entry whatever form it took. */
|
|
@@ -69,50 +116,68 @@ export function providerEntries(manifest) {
|
|
|
69
116
|
export function providerIds(manifest) {
|
|
70
117
|
return providerEntries(manifest).map((entry) => entry.id);
|
|
71
118
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
119
|
+
function secretEntryOf(entry, feature) {
|
|
120
|
+
const tag = feature === undefined ? {} : { feature };
|
|
121
|
+
if (typeof entry === "string")
|
|
122
|
+
return [{ name: entry, ...tag }];
|
|
123
|
+
if (entry && typeof entry === "object") {
|
|
124
|
+
const name = entry.name;
|
|
125
|
+
if (typeof name === "string") {
|
|
126
|
+
return [{ name, ...needFields(entry), ...ownValueFields(entry), ...tag }];
|
|
79
127
|
}
|
|
80
|
-
|
|
81
|
-
|
|
128
|
+
}
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The app's own secrets the manifest lists, each as an entry whatever form
|
|
133
|
+
* it took: the top-level ones, then each feature's (tagged with it).
|
|
134
|
+
*/
|
|
135
|
+
export function secretEntries(manifest) {
|
|
136
|
+
return [
|
|
137
|
+
...(manifest.secrets ?? []).flatMap((entry) => secretEntryOf(entry)),
|
|
138
|
+
...featureLists(manifest, "secrets").flatMap(({ feature, list }) => list.flatMap((entry) => secretEntryOf(entry, feature))),
|
|
139
|
+
];
|
|
82
140
|
}
|
|
83
141
|
/** The names of the app's own secrets, in order. */
|
|
84
142
|
export function secretNames(manifest) {
|
|
85
143
|
return secretEntries(manifest).map((entry) => entry.name);
|
|
86
144
|
}
|
|
87
|
-
|
|
145
|
+
function settingEntryOf(entry, feature) {
|
|
146
|
+
if (!entry || typeof entry !== "object")
|
|
147
|
+
return [];
|
|
148
|
+
const record = entry;
|
|
149
|
+
if (typeof record["name"] !== "string")
|
|
150
|
+
return [];
|
|
151
|
+
const type = record["type"];
|
|
152
|
+
const values = record["values"];
|
|
153
|
+
return [
|
|
154
|
+
{
|
|
155
|
+
name: record["name"],
|
|
156
|
+
...needFields(entry),
|
|
157
|
+
...(typeof record["how"] === "string" ? { how: record["how"] } : {}),
|
|
158
|
+
...(type === "url" ||
|
|
159
|
+
type === "number" ||
|
|
160
|
+
type === "boolean" ||
|
|
161
|
+
type === "text"
|
|
162
|
+
? { type }
|
|
163
|
+
: {}),
|
|
164
|
+
...(Array.isArray(values) &&
|
|
165
|
+
values.every((value) => typeof value === "string")
|
|
166
|
+
? { values: values }
|
|
167
|
+
: {}),
|
|
168
|
+
...(typeof record["default"] === "string"
|
|
169
|
+
? { default: record["default"] }
|
|
170
|
+
: {}),
|
|
171
|
+
...(feature === undefined ? {} : { feature }),
|
|
172
|
+
},
|
|
173
|
+
];
|
|
174
|
+
}
|
|
175
|
+
/** The app's plain settings the manifest lists, each as an entry: the top-level ones, then each feature's. */
|
|
88
176
|
export function settingEntries(manifest) {
|
|
89
|
-
return
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const record = entry;
|
|
94
|
-
const type = record["type"];
|
|
95
|
-
const values = record["values"];
|
|
96
|
-
return [
|
|
97
|
-
{
|
|
98
|
-
name: entry.name,
|
|
99
|
-
...needFields(entry),
|
|
100
|
-
...(type === "url" ||
|
|
101
|
-
type === "number" ||
|
|
102
|
-
type === "boolean" ||
|
|
103
|
-
type === "text"
|
|
104
|
-
? { type }
|
|
105
|
-
: {}),
|
|
106
|
-
...(Array.isArray(values) &&
|
|
107
|
-
values.every((value) => typeof value === "string")
|
|
108
|
-
? { values: values }
|
|
109
|
-
: {}),
|
|
110
|
-
...(typeof record["default"] === "string"
|
|
111
|
-
? { default: record["default"] }
|
|
112
|
-
: {}),
|
|
113
|
-
},
|
|
114
|
-
];
|
|
115
|
-
});
|
|
177
|
+
return [
|
|
178
|
+
...(manifest.settings ?? []).flatMap((entry) => settingEntryOf(entry)),
|
|
179
|
+
...featureLists(manifest, "settings").flatMap(({ feature, list }) => list.flatMap((entry) => settingEntryOf(entry, feature))),
|
|
180
|
+
];
|
|
116
181
|
}
|
|
117
182
|
/** The names of the app's plain settings, in order. */
|
|
118
183
|
export function settingNames(manifest) {
|
|
@@ -256,19 +321,59 @@ function providerHint(capability, names) {
|
|
|
256
321
|
];
|
|
257
322
|
return lines.length > 0 ? { hint: lines.join(" ") } : {};
|
|
258
323
|
}
|
|
259
|
-
function withNeed(setting, entry, defaults = {}) {
|
|
324
|
+
function withNeed(setting, entry, need, defaults = {}) {
|
|
260
325
|
const docs = entry?.docs ?? defaults.docs;
|
|
261
|
-
// The registry's guide for a Gateway setting; the manifest's for the app's own secret.
|
|
262
|
-
const setup = setting.holder === "gateway" ? defaults.setup : entry?.setup;
|
|
263
326
|
return {
|
|
264
327
|
...setting,
|
|
265
|
-
need:
|
|
328
|
+
need: need.need,
|
|
329
|
+
...(need.feature === undefined ? {} : { feature: need.feature }),
|
|
266
330
|
...(entry?.why ? { why: entry.why } : {}),
|
|
267
331
|
...(docs ? { docs } : {}),
|
|
268
|
-
...(setup ? { setup } : {}),
|
|
332
|
+
...(defaults.setup ? { setup: defaults.setup } : {}),
|
|
269
333
|
...(defaults.hint ? { hint: defaults.hint } : {}),
|
|
270
334
|
};
|
|
271
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* A stored manifest from before features (deployed before 0.3.0-rc.14) marks a
|
|
338
|
+
* value `optional: true`. The strict schema refuses that key now, but a stored
|
|
339
|
+
* row keeps it until the app is redeployed, so it still reads as optional:
|
|
340
|
+
* updating the Gateway never puts a working app into Needs setup.
|
|
341
|
+
*/
|
|
342
|
+
function storedOptional(need, raw) {
|
|
343
|
+
if (need.feature !== undefined || need.need.kind === "optional")
|
|
344
|
+
return need;
|
|
345
|
+
const optional = raw !== null &&
|
|
346
|
+
typeof raw === "object" &&
|
|
347
|
+
raw["optional"] === true;
|
|
348
|
+
return optional ? { need: { kind: "optional" } } : need;
|
|
349
|
+
}
|
|
350
|
+
/** The raw entry named `name` in a stored list (`secrets`, `settings`, `providers`). */
|
|
351
|
+
function rawEntry(list, name, key) {
|
|
352
|
+
if (!Array.isArray(list))
|
|
353
|
+
return undefined;
|
|
354
|
+
return list.find((entry) => entry !== null &&
|
|
355
|
+
typeof entry === "object" &&
|
|
356
|
+
entry[key] === name);
|
|
357
|
+
}
|
|
358
|
+
/** An app's own value's need: its feature's (required, or optional), or required at the top level. */
|
|
359
|
+
function ownNeedOf(features, feature) {
|
|
360
|
+
if (feature === undefined)
|
|
361
|
+
return { need: { kind: "required" } };
|
|
362
|
+
const owner = features.find((each) => each.id === feature);
|
|
363
|
+
return {
|
|
364
|
+
need: { kind: owner?.required ? "required" : "optional" },
|
|
365
|
+
feature,
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
/** `how`, `generate` and `file` onto an app's own setting, when its entry says them. */
|
|
369
|
+
function withOwnValue(setting, entry) {
|
|
370
|
+
return {
|
|
371
|
+
...setting,
|
|
372
|
+
...(entry.how ? { how: entry.how } : {}),
|
|
373
|
+
...(entry.generate ? { generate: true } : {}),
|
|
374
|
+
...(entry.file ? { file: true } : {}),
|
|
375
|
+
};
|
|
376
|
+
}
|
|
272
377
|
/**
|
|
273
378
|
* Every setting the manifest declares, in manifest order: its AI
|
|
274
379
|
* providers, its capabilities, then the app's own secrets. A provider or capability the
|
|
@@ -279,6 +384,7 @@ function withNeed(setting, entry, defaults = {}) {
|
|
|
279
384
|
*/
|
|
280
385
|
export function appSettings(manifest, lookup = CATALOG, options = {}) {
|
|
281
386
|
const settings = [];
|
|
387
|
+
const features = featureEntries(manifest);
|
|
282
388
|
const chat = manifest.ai?.chat;
|
|
283
389
|
if (chat === true || (chat && typeof chat === "object")) {
|
|
284
390
|
// The default resolves on what is set: with nothing set, the first of
|
|
@@ -302,24 +408,25 @@ export function appSettings(manifest, lookup = CATALOG, options = {}) {
|
|
|
302
408
|
alternatives: resolution.candidates
|
|
303
409
|
.map((candidate) => settable(candidate.settings))
|
|
304
410
|
.filter((names) => names.length > 0),
|
|
305
|
-
}, chat === true ? undefined : chat, {
|
|
411
|
+
}, chat === true ? undefined : needFields(chat), storedOptional({ need: { kind: "required" } }, chat), {
|
|
306
412
|
...(provider?.mode === "ai" ? { docs: provider.docs } : {}),
|
|
307
413
|
setup: "setup/ai.md",
|
|
308
414
|
hint: aiDefaultSetupHint(resolution),
|
|
309
415
|
}));
|
|
310
416
|
}
|
|
311
|
-
// The default's settings: an optional pin
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
// serves the default.
|
|
417
|
+
// The default's settings: an optional pin (a provider an optional
|
|
418
|
+
// feature lists) that needs only those is the same row (one key, set
|
|
419
|
+
// once), so it isn't listed twice. A required pin stays: it needs that
|
|
420
|
+
// provider's key even while another provider serves the default.
|
|
315
421
|
const defaultNames = settings.find((setting) => setting.kind === "ai-default")?.names;
|
|
316
422
|
for (const entry of providerEntries(manifest)) {
|
|
317
423
|
const capability = lookup.get(entry.id);
|
|
318
424
|
if (capability?.mode !== "ai")
|
|
319
425
|
continue;
|
|
320
426
|
const names = providerNames(capability);
|
|
427
|
+
const need = storedOptional(gatewayNeedOf(features, "providers", entry.id), rawEntry(manifest.providers, entry.id, "id"));
|
|
321
428
|
if (defaultNames &&
|
|
322
|
-
|
|
429
|
+
need.need.kind === "optional" &&
|
|
323
430
|
names.length > 0 &&
|
|
324
431
|
names.every((name) => defaultNames.includes(name))) {
|
|
325
432
|
continue;
|
|
@@ -331,7 +438,7 @@ export function appSettings(manifest, lookup = CATALOG, options = {}) {
|
|
|
331
438
|
holder: "gateway",
|
|
332
439
|
names,
|
|
333
440
|
alsoReads: [],
|
|
334
|
-
}, entry, {
|
|
441
|
+
}, entry, need, {
|
|
335
442
|
docs: capability.docs,
|
|
336
443
|
setup: capability.setup,
|
|
337
444
|
...providerHint(capability, names),
|
|
@@ -350,7 +457,7 @@ export function appSettings(manifest, lookup = CATALOG, options = {}) {
|
|
|
350
457
|
holder: "gateway",
|
|
351
458
|
names,
|
|
352
459
|
alsoReads,
|
|
353
|
-
}, needFields(entry), {
|
|
460
|
+
}, needFields(entry), storedOptional(gatewayNeedOf(features, "capabilities", id), entry), {
|
|
354
461
|
docs: capabilityDocs(capability),
|
|
355
462
|
setup: capability.setup,
|
|
356
463
|
...providerHint(capability, names),
|
|
@@ -376,27 +483,30 @@ export function appSettings(manifest, lookup = CATALOG, options = {}) {
|
|
|
376
483
|
});
|
|
377
484
|
}
|
|
378
485
|
for (const entry of secretEntries(manifest)) {
|
|
379
|
-
settings.push(withNeed({
|
|
486
|
+
settings.push(withOwnValue(withNeed({
|
|
380
487
|
kind: "secret",
|
|
381
488
|
id: entry.name,
|
|
382
489
|
label: entry.name,
|
|
383
490
|
holder: "app",
|
|
384
491
|
names: [entry.name],
|
|
385
492
|
alsoReads: [],
|
|
386
|
-
}, entry));
|
|
493
|
+
}, entry, storedOptional(ownNeedOf(features, entry.feature), rawEntry(manifest.secrets, entry.name, "name"))), entry));
|
|
387
494
|
}
|
|
388
495
|
for (const entry of settingEntries(manifest)) {
|
|
389
|
-
|
|
390
|
-
const need = entry.default !== undefined ? { ...entry, optional: true } : entry;
|
|
496
|
+
const own = storedOptional(ownNeedOf(features, entry.feature), rawEntry(manifest.settings, entry.name, "name"));
|
|
391
497
|
settings.push({
|
|
392
|
-
...withNeed({
|
|
498
|
+
...withOwnValue(withNeed({
|
|
393
499
|
kind: "setting",
|
|
394
500
|
id: entry.name,
|
|
395
501
|
label: entry.name,
|
|
396
502
|
holder: "app",
|
|
397
503
|
names: [entry.name],
|
|
398
504
|
alsoReads: [],
|
|
399
|
-
},
|
|
505
|
+
}, entry,
|
|
506
|
+
// A setting with a default is never unset for long: the deploy writes it.
|
|
507
|
+
entry.default !== undefined
|
|
508
|
+
? { ...own, need: { kind: "optional" } }
|
|
509
|
+
: own), entry),
|
|
400
510
|
value: settingValueRule(entry),
|
|
401
511
|
});
|
|
402
512
|
}
|
|
@@ -433,12 +543,24 @@ function settingIsSet(setting, isSet) {
|
|
|
433
543
|
}
|
|
434
544
|
return unknown ? null : false;
|
|
435
545
|
}
|
|
546
|
+
/**
|
|
547
|
+
* A feature's state from its settings (see {@link FeatureState}). Whether
|
|
548
|
+
* it is started is read from its own values that have no default (a
|
|
549
|
+
* default is written by the deploy, so it says nothing), or, for a
|
|
550
|
+
* feature of Gateway settings alone, from those.
|
|
551
|
+
*/
|
|
552
|
+
function featureState(settings) {
|
|
553
|
+
if (settings.every((setting) => setting.set !== false))
|
|
554
|
+
return "ready";
|
|
555
|
+
const own = settings.filter((setting) => setting.holder === "app" && setting.value?.default === undefined);
|
|
556
|
+
const started = (own.length > 0 ? own : settings).some((setting) => setting.set === true);
|
|
557
|
+
return started ? "incomplete" : "off";
|
|
558
|
+
}
|
|
436
559
|
/**
|
|
437
560
|
* Every setting against what is set. `isSet` answers per holder and name:
|
|
438
561
|
* true, false, or null when it can't tell (the registry never recorded
|
|
439
|
-
* the app Worker's secret names), which never blocks.
|
|
440
|
-
*
|
|
441
|
-
* member blocks.
|
|
562
|
+
* the app Worker's secret names), which never blocks. A required setting
|
|
563
|
+
* that is unset blocks; an optional one (an optional feature's) never does.
|
|
442
564
|
*/
|
|
443
565
|
export function evaluateAppSettings(settings, isSet, options = {}) {
|
|
444
566
|
const evaluated = settings.map((setting) => {
|
|
@@ -449,47 +571,30 @@ export function evaluateAppSettings(settings, isSet, options = {}) {
|
|
|
449
571
|
blocking: false,
|
|
450
572
|
};
|
|
451
573
|
});
|
|
452
|
-
const groups = [];
|
|
453
|
-
for (const setting of evaluated) {
|
|
454
|
-
if (setting.need.kind !== "anyOf")
|
|
455
|
-
continue;
|
|
456
|
-
const group = setting.need.group;
|
|
457
|
-
let found = groups.find((each) => each.group === group);
|
|
458
|
-
if (!found) {
|
|
459
|
-
found = { group, members: [], met: false };
|
|
460
|
-
groups.push(found);
|
|
461
|
-
}
|
|
462
|
-
found.members.push(setting);
|
|
463
|
-
}
|
|
464
|
-
for (const group of groups) {
|
|
465
|
-
group.met = group.members.some((member) => member.set === true);
|
|
466
|
-
const unknown = group.members.some((member) => member.set === null);
|
|
467
|
-
if (!group.met && !unknown) {
|
|
468
|
-
for (const member of group.members)
|
|
469
|
-
member.blocking = true;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
574
|
for (const setting of evaluated) {
|
|
473
575
|
if (setting.need.kind === "required" && setting.set === false) {
|
|
474
576
|
setting.blocking = true;
|
|
475
577
|
}
|
|
476
578
|
}
|
|
477
579
|
const unmet = evaluated.filter((setting) => setting.blocking);
|
|
478
|
-
|
|
580
|
+
const features = (options.features ?? []).map((feature) => {
|
|
581
|
+
const own = evaluated.filter((setting) => setting.feature === feature.id);
|
|
582
|
+
return { ...feature, settings: own, state: featureState(own) };
|
|
583
|
+
});
|
|
584
|
+
return { ready: unmet.length === 0, settings: evaluated, unmet, features };
|
|
479
585
|
}
|
|
480
586
|
/**
|
|
481
587
|
* What to run for an app that needs setup: `everyapp configure <app>`,
|
|
482
588
|
* which reads the app's manifest (from the registry, so it runs from
|
|
483
|
-
* anywhere), prompts for each unmet setting
|
|
484
|
-
*
|
|
589
|
+
* anywhere), prompts for each unmet setting, feature by feature, and sets
|
|
590
|
+
* them where they are held. Null when
|
|
485
591
|
* the app is ready. `cli` is how the operator runs everyapp (`pnpm
|
|
486
592
|
* everyapp` from a checkout). Scripts that set one name at a time use
|
|
487
593
|
* `everyapp secret set NAME [--app <id>]` instead.
|
|
488
594
|
*
|
|
489
595
|
* A provider app (`provider`: the gateway's own, with no Worker and no
|
|
490
596
|
* directory; `everyapp mcp on <id>`, an MCP app) has nothing to configure: its
|
|
491
|
-
* command is the `secret set` of its Gateway key
|
|
492
|
-
* unmet any-of group), as `mcp list` says it.
|
|
597
|
+
* command is the `secret set` of its Gateway key, as `mcp list` says it.
|
|
493
598
|
*/
|
|
494
599
|
export function setupCommand(report, { cli, appId, provider = false, }) {
|
|
495
600
|
if (report.unmet.length === 0)
|
|
@@ -506,15 +611,8 @@ export function setupCommand(report, { cli, appId, provider = false, }) {
|
|
|
506
611
|
if (!names.includes(name))
|
|
507
612
|
names.push(name);
|
|
508
613
|
};
|
|
509
|
-
for (const setting of report.unmet)
|
|
510
|
-
|
|
511
|
-
add(setting);
|
|
512
|
-
}
|
|
513
|
-
for (const group of report.groups) {
|
|
514
|
-
const first = group.members.find((member) => member.blocking);
|
|
515
|
-
if (first)
|
|
516
|
-
add(first);
|
|
517
|
-
}
|
|
614
|
+
for (const setting of report.unmet)
|
|
615
|
+
add(setting);
|
|
518
616
|
return { command: `${cli} secret set ${names.join(" ")}` };
|
|
519
617
|
}
|
|
520
618
|
export function appSetupOf(report, options) {
|
|
@@ -523,10 +621,9 @@ export function appSetupOf(report, options) {
|
|
|
523
621
|
ready: report.ready,
|
|
524
622
|
settings: report.settings.map(strip),
|
|
525
623
|
unmet: report.unmet.map(strip),
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
members: group.members.map((member) => member.id),
|
|
624
|
+
features: report.features.map((feature) => ({
|
|
625
|
+
...feature,
|
|
626
|
+
settings: feature.settings.map((setting) => setting.id),
|
|
530
627
|
})),
|
|
531
628
|
command: options.withCommand === false ? null : setupCommand(report, options),
|
|
532
629
|
};
|
|
@@ -540,3 +637,18 @@ export function apiKeyCapabilityOf(id, lookup = CATALOG) {
|
|
|
540
637
|
const capability = lookup.get(id);
|
|
541
638
|
return capability?.mode === "api_key" ? capability : undefined;
|
|
542
639
|
}
|
|
640
|
+
/**
|
|
641
|
+
* A fresh value for a secret the manifest marks `generate: true`: 32
|
|
642
|
+
* bytes from the platform's cryptographic random source, base64url
|
|
643
|
+
* without padding (43 characters).
|
|
644
|
+
*/
|
|
645
|
+
export function generatedSecret() {
|
|
646
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
647
|
+
let binary = "";
|
|
648
|
+
for (const byte of bytes)
|
|
649
|
+
binary += String.fromCharCode(byte);
|
|
650
|
+
return btoa(binary)
|
|
651
|
+
.replace(/\+/g, "-")
|
|
652
|
+
.replace(/\//g, "_")
|
|
653
|
+
.replace(/=+$/, "");
|
|
654
|
+
}
|
package/dist/manifest.d.ts
CHANGED
|
@@ -20,16 +20,16 @@
|
|
|
20
20
|
* The Worker reads the manifest back as `env.EVERYAPP_MANIFEST`, which
|
|
21
21
|
* `everyAppWorker()` sets and `cf workers types` types from the file.
|
|
22
22
|
*/
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Why a setting is needed (the settings model). Everything listed at the
|
|
25
|
+
* top level is required; what the app works without goes in an optional
|
|
26
|
+
* feature (`features`).
|
|
27
|
+
*/
|
|
24
28
|
export interface EveryAppSettingNeed {
|
|
25
29
|
/** Why the app needs it, for whoever sets it. At most 200 characters. */
|
|
26
30
|
readonly why?: string;
|
|
27
31
|
/** An https page that says where the key or client comes from. */
|
|
28
32
|
readonly docs?: string;
|
|
29
|
-
/** The app opens without it; the feature using it says what is missing. */
|
|
30
|
-
readonly optional?: boolean;
|
|
31
|
-
/** The group of which one member is enough ("AI model"). */
|
|
32
|
-
readonly anyOf?: string;
|
|
33
33
|
}
|
|
34
34
|
/** A route reachable without a signed-in member. */
|
|
35
35
|
export interface EveryAppPublicRoute {
|
|
@@ -142,12 +142,16 @@ export interface EveryAppOAuthCapabilityEntry extends EveryAppSettingNeed {
|
|
|
142
142
|
* differs per install (a PostHog host, a region), set with `everyapp
|
|
143
143
|
* configure <app>` and read from `env`.
|
|
144
144
|
*/
|
|
145
|
-
export interface EveryAppSettingEntry {
|
|
146
|
-
readonly name: string;
|
|
145
|
+
export interface EveryAppSettingEntry extends EveryAppFeatureSettingEntry {
|
|
147
146
|
/** Why the app needs it: what whoever installs the app reads. */
|
|
148
147
|
readonly why: string;
|
|
149
148
|
readonly docs?: string;
|
|
150
|
-
|
|
149
|
+
}
|
|
150
|
+
/** A plain setting in a feature: the feature says why. */
|
|
151
|
+
export interface EveryAppFeatureSettingEntry {
|
|
152
|
+
readonly name: string;
|
|
153
|
+
/** Where the value is and what it needs, for whoever sets it (200 characters at most; `{appUrl}`, `{gatewayUrl}` are filled in). */
|
|
154
|
+
readonly how?: string;
|
|
151
155
|
/** What it takes; text when not given. */
|
|
152
156
|
readonly type?: "text" | "url" | "number" | "boolean";
|
|
153
157
|
/** The values a text setting may take. */
|
|
@@ -155,11 +159,39 @@ export interface EveryAppSettingEntry {
|
|
|
155
159
|
/** What the app reads while nobody has set it; the deploy writes it. */
|
|
156
160
|
readonly default?: string;
|
|
157
161
|
}
|
|
158
|
-
/** One of the app's own secrets
|
|
159
|
-
export interface
|
|
162
|
+
/** One of the app's own secrets in a feature: the feature says why. */
|
|
163
|
+
export interface EveryAppFeatureSecretEntry {
|
|
164
|
+
readonly name: string;
|
|
165
|
+
/** Where the value is and what permission it needs (200 characters at most; `{appUrl}`, `{gatewayUrl}` are filled in). */
|
|
166
|
+
readonly how?: string;
|
|
167
|
+
/** `everyapp configure` makes it (32 random bytes, base64url) when unset; shown once when `how` says where to paste it. */
|
|
168
|
+
readonly generate?: boolean;
|
|
169
|
+
/** The value is a file's contents (a .pem): the prompt takes the file's path. */
|
|
170
|
+
readonly file?: boolean;
|
|
171
|
+
}
|
|
172
|
+
/** One of the app's own secrets. */
|
|
173
|
+
export interface EveryAppSecretEntry extends EveryAppSettingNeed, EveryAppFeatureSecretEntry {
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* One feature: a named group of secrets, settings and Gateway capabilities
|
|
177
|
+
* with numbered setup steps. A required one keeps the app closed until it
|
|
178
|
+
* is set; an optional one (the default) is all or nothing.
|
|
179
|
+
*/
|
|
180
|
+
export interface EveryAppFeature {
|
|
181
|
+
/** What people read: "GitHub". */
|
|
160
182
|
readonly name: string;
|
|
161
|
-
/**
|
|
162
|
-
readonly
|
|
183
|
+
/** Default false: the app opens without it. */
|
|
184
|
+
readonly required?: boolean;
|
|
185
|
+
/** What it gives the app, in one sentence (200 characters at most). */
|
|
186
|
+
readonly why: string;
|
|
187
|
+
/** Short Markdown lines, numbered when shown; links as plain URLs or `[text](url)`; `{appUrl}`, `{gatewayUrl}` are filled in. */
|
|
188
|
+
readonly steps?: readonly string[];
|
|
189
|
+
readonly settings?: readonly EveryAppFeatureSettingEntry[];
|
|
190
|
+
readonly secrets?: readonly (string | EveryAppFeatureSecretEntry)[];
|
|
191
|
+
/** Capabilities it needs, by id; each declared under `capabilities` too. */
|
|
192
|
+
readonly capabilities?: readonly string[];
|
|
193
|
+
/** AI providers it needs, by id; each declared under `providers` too. */
|
|
194
|
+
readonly providers?: readonly string[];
|
|
163
195
|
}
|
|
164
196
|
/** `everyapp.config.ts`. */
|
|
165
197
|
export interface EveryAppManifest {
|
|
@@ -204,6 +236,10 @@ export interface EveryAppManifest {
|
|
|
204
236
|
readonly secrets?: readonly (string | EveryAppSecretEntry)[];
|
|
205
237
|
/** The app's plain settings: per-install values that aren't secrets. */
|
|
206
238
|
readonly settings?: readonly EveryAppSettingEntry[];
|
|
239
|
+
/** Features by id (a lowercase slug): what the app needs set, grouped, with setup steps. */
|
|
240
|
+
readonly features?: {
|
|
241
|
+
readonly [id: string]: EveryAppFeature;
|
|
242
|
+
};
|
|
207
243
|
readonly ai?: {
|
|
208
244
|
/** Model ids the app may request; any other is `model_not_allowed`. */
|
|
209
245
|
readonly models?: readonly string[];
|
|
@@ -218,7 +254,7 @@ export interface EveryAppManifest {
|
|
|
218
254
|
};
|
|
219
255
|
/** Who can open the app once registered; `"admins"` by default. */
|
|
220
256
|
readonly access?: "everyone" | "admins";
|
|
221
|
-
/** Shell command that builds the app; `cf build` by default. */
|
|
257
|
+
/** Shell command that builds the app; `cf build` by default (`--mode production` without Vite). */
|
|
222
258
|
readonly build?: string;
|
|
223
259
|
/** Shell command `everyapp dev` starts; it must listen on PORT. */
|
|
224
260
|
readonly dev?: string;
|
package/dist/manifest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
|