everyapp 0.2.2 → 0.3.0-rc.2

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 (128) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -77
  3. package/bin/everyapp.js +235 -0
  4. package/dist/access-LGEN3ABJ.js +1 -0
  5. package/dist/activity-RSD4D66F.js +12 -0
  6. package/dist/apps-4RCFXT74.js +13 -0
  7. package/dist/chunk-23HJ5I2A.js +2 -0
  8. package/dist/chunk-2Y5Q6A5K.js +6 -0
  9. package/dist/chunk-4JRIS6S6.js +1 -0
  10. package/dist/chunk-5PTNYZK6.js +4 -0
  11. package/dist/chunk-6OGVO7QK.js +6 -0
  12. package/dist/chunk-6PGUCTJ6.js +11 -0
  13. package/dist/chunk-AGTCKFRB.js +22 -0
  14. package/dist/chunk-BHMRY53V.js +2 -0
  15. package/dist/chunk-CB4U7H2G.js +4 -0
  16. package/dist/chunk-CCWBPAKH.js +4 -0
  17. package/dist/chunk-CZTEDWZ2.js +22 -0
  18. package/dist/chunk-CZXHKPRZ.js +2 -0
  19. package/dist/chunk-E3EPK27P.js +10 -0
  20. package/dist/chunk-EGEWRFVY.js +1 -0
  21. package/dist/chunk-ELK7QZ2M.js +1 -0
  22. package/dist/chunk-FJJSSVET.js +33 -0
  23. package/dist/chunk-GKBPYVP3.js +25 -0
  24. package/dist/chunk-H6QQMY7B.js +18 -0
  25. package/dist/chunk-H7PDL3X5.js +1 -0
  26. package/dist/chunk-HOUHG236.js +20 -0
  27. package/dist/chunk-IFCPALVC.js +46 -0
  28. package/dist/chunk-IUOBIB5M.js +30 -0
  29. package/dist/chunk-J35DDCNU.js +1 -0
  30. package/dist/chunk-J455FAEN.js +7 -0
  31. package/dist/chunk-JYKRUS5C.js +1 -0
  32. package/dist/chunk-LXYMDZER.js +1 -0
  33. package/dist/chunk-LYNBZ7RV.js +57 -0
  34. package/dist/chunk-M2QQ2UD7.js +132 -0
  35. package/dist/chunk-N4E5YE4X.js +5 -0
  36. package/dist/chunk-N5GQLGEC.js +2 -0
  37. package/dist/chunk-NFU4YFXB.js +1 -0
  38. package/dist/chunk-OM2HDWVP.js +1 -0
  39. package/dist/chunk-ONLNJXVQ.js +32 -0
  40. package/dist/chunk-OP4DYXYI.js +2 -0
  41. package/dist/chunk-PNLU5U3P.js +1 -0
  42. package/dist/chunk-PS7S74DG.js +6 -0
  43. package/dist/chunk-RMF4YGD6.js +98 -0
  44. package/dist/chunk-T2GD7RHS.js +10 -0
  45. package/dist/chunk-TLRM3P7V.js +15 -0
  46. package/dist/chunk-W3JCQHHU.js +1 -0
  47. package/dist/chunk-WOVS3GV5.js +10 -0
  48. package/dist/chunk-YHJZMJYZ.js +1 -0
  49. package/dist/chunk-ZECBN24L.js +15 -0
  50. package/dist/chunk-ZEXVHB22.js +2 -0
  51. package/dist/chunk-ZFCUH5PK.js +7 -0
  52. package/dist/configure-F7UZCJUG.js +8 -0
  53. package/dist/create-2E5HVWYK.js +22 -0
  54. package/dist/db-HEQVTDTM.js +9 -0
  55. package/dist/delete-XCSIQIRS.js +3 -0
  56. package/dist/deploy-3QOZEZHC.js +1 -0
  57. package/dist/dev-JL3ZP5BT.js +86 -0
  58. package/dist/email-RLZFUFUN.js +10 -0
  59. package/dist/events-2V5VRBWP.js +15 -0
  60. package/dist/groups-HDG5DVFY.js +8 -0
  61. package/dist/index.js +97 -1
  62. package/dist/install-Z5FYXUYM.js +1 -0
  63. package/dist/login-KHJBC64Z.js +1 -0
  64. package/dist/mcp-EFDUKJ5V.js +1 -0
  65. package/dist/provider-EOI5PTFH.js +13 -0
  66. package/dist/release-74J5ZIL3.js +1 -0
  67. package/dist/restore-FFGYV7NO.js +3 -0
  68. package/dist/secret-7FKKTLHB.js +1 -0
  69. package/dist/setup-PAKRCAFO.js +1 -0
  70. package/dist/signin-AP3D4XM4.js +12 -0
  71. package/dist/status-RMWNHOEK.js +4 -0
  72. package/dist/teardown-E4JNKAZJ.js +22 -0
  73. package/dist/update-DWVZFNPS.js +1 -0
  74. package/dist/workspace-CJC5I66L.js +21 -0
  75. package/package.json +19 -16
  76. package/skills/build-every-app/SKILL.md +199 -0
  77. package/skills/build-every-app/patterns.md +140 -0
  78. package/skills/everyapp/SKILL.md +292 -0
  79. package/skills/everyapp/mcp.md +350 -0
  80. package/skills/everyapp/security-review.md +61 -0
  81. package/skills/everyapp/setup/README.md +274 -0
  82. package/skills/everyapp/setup/access.md +178 -0
  83. package/skills/everyapp/setup/context.md +117 -0
  84. package/skills/everyapp/setup/dataforseo.md +287 -0
  85. package/skills/everyapp/setup/email.md +366 -0
  86. package/skills/everyapp/setup/gateway.md +243 -0
  87. package/skills/everyapp/setup/google.md +360 -0
  88. package/skills/everyapp/setup/microsoft-365.md +281 -0
  89. package/skills/everyapp/setup/openai.md +318 -0
  90. package/skills/everyapp/setup/openrouter.md +309 -0
  91. package/skills/everyapp/setup/providers.md +1253 -0
  92. package/skills/everyapp/setup/remote-mcp.md +199 -0
  93. package/skills/everyapp/setup/signin-apple.md +178 -0
  94. package/skills/everyapp/setup/signin-cloudflare.md +148 -0
  95. package/skills/everyapp/setup/signin-github.md +139 -0
  96. package/skills/everyapp/setup/signin-google.md +178 -0
  97. package/skills/everyapp/setup/signin-microsoft.md +183 -0
  98. package/skills/everyapp/setup/signin-oidc.md +163 -0
  99. package/skills/everyapp/setup/slack.md +344 -0
  100. package/skills/everyapp/setup/workers-ai.md +138 -0
  101. package/bin/__everyapp_bash_complete.js +0 -12
  102. package/dist/bash-complete.js +0 -3
  103. package/dist/chunk-7BOQJFI5.js +0 -8
  104. package/dist/chunk-7YVJFS4A.js +0 -1
  105. package/dist/chunk-BIXKPCDH.js +0 -2
  106. package/dist/chunk-DLGPLHBH.js +0 -47
  107. package/dist/chunk-FD6K2YA7.js +0 -9
  108. package/dist/chunk-GAJEQYJH.js +0 -39
  109. package/dist/chunk-O2KDOP5R.js +0 -13
  110. package/dist/chunk-OI2MBGBG.js +0 -4
  111. package/dist/chunk-POSDLD3G.js +0 -8
  112. package/dist/chunk-RB5D2R45.js +0 -1
  113. package/dist/chunk-U4LIQ5VR.js +0 -1
  114. package/dist/chunk-VEYSNPDH.js +0 -3
  115. package/dist/chunk-VP6SKW44.js +0 -7
  116. package/dist/chunk-WO3NE7ZU.js +0 -7
  117. package/dist/chunk-XTO2VTPY.js +0 -6
  118. package/dist/chunk-YJ2DKIZS.js +0 -1
  119. package/dist/create-DYQ3NBWJ.js +0 -22
  120. package/dist/deploy-PYTCMDGV.js +0 -7
  121. package/dist/deploy-RMAHOA4Z.js +0 -55
  122. package/dist/dev-SAE237FS.js +0 -0
  123. package/dist/generateConfig-46Z3ERF3.js +0 -1
  124. package/dist/login-B6EF3SMX.js +0 -1
  125. package/dist/logout-XMKZBLNV.js +0 -1
  126. package/dist/remoteD1Shell-A67JMO3H.js +0 -6
  127. package/dist/setupLocal-TZJUW5ES.js +0 -6
  128. package/gateway/every-app-gateway-build.tar.gz +0 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Every App, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,82 +1,11 @@
1
1
  # everyapp
2
2
 
3
- CLI for [Every App](https://everyapp.dev) - deploy and manage self-hosted apps on Cloudflare.
3
+ The CLI for [Every App](https://everyapp.com): deploy and run private web apps on your own Cloudflare account.
4
4
 
5
- ## Installation
5
+ Nothing is published while we work from the repository (`.github/RELEASE.md`), so the CLI runs from a checkout of it: `pnpm install` once at the root, then `pnpm everyapp <command>` anywhere in the repository (never `npx everyapp`, which is npm's old 0.2 CLI). It builds itself the first time and again whenever its source, or the SDK, perimeter or toolbus it bundles, changed (`bin/everyapp.js`). Requires Node.js 22.18 or newer.
6
6
 
7
- ```bash
8
- # Run the latest CLI directly with npx
9
- npx -y everyapp@latest <command>
10
- ```
7
+ Every command but `dev` takes `--json` (NDJSON events on stdout; exit 0 done, 1 error, 2 action required) and `--help` lists its flags.
11
8
 
12
- ## Commands
13
-
14
- ### Deploy the Gateway
15
-
16
- Deploy the Every App Gateway to your Cloudflare account:
17
-
18
- ```bash
19
- npx -y everyapp@latest gateway deploy
20
- ```
21
-
22
- ### Create a new app
23
-
24
- Create a new app from the starter template:
25
-
26
- ```bash
27
- npx -y everyapp@latest app create [name]
28
- ```
29
-
30
- This will:
31
-
32
- 1. Prompt for an app ID (or use the provided name)
33
- 2. Deploy to Cloudflare (D1 database, KV namespace, Worker)
34
- 3. Configure wrangler.jsonc, package.json, and .env files
35
- 4. Install dependencies and run local migrations
36
-
37
- ### Deploy an app
38
-
39
- Deploy your app to Cloudflare:
40
-
41
- ```bash
42
- npx -y everyapp@latest app deploy
43
- ```
44
-
45
- Run this from your app directory to build and deploy updates.
46
-
47
- ### Set up local environment
48
-
49
- Set up local development for an existing Every App app (for example, after cloning a repo):
50
-
51
- ```bash
52
- npx -y everyapp@latest app setup-local
53
- ```
54
-
55
- This will:
56
-
57
- 1. Verify Cloudflare and gateway setup
58
- 2. Install dependencies
59
- 3. Create or refresh `.env.local`
60
- 4. Generate Cloudflare types and run local migrations
61
-
62
- ### Remote D1 shell
63
-
64
- Run commands with access to your production D1 database:
65
-
66
- ```bash
67
- npx -y everyapp@latest app remote-d1-shell -- <command>
68
- ```
69
-
70
- Examples:
71
-
72
- ```bash
73
- # Run migrations
74
- npx -y everyapp@latest app remote-d1-shell -- npx drizzle-kit migrate
75
-
76
- # Open Drizzle Studio
77
- npx -y everyapp@latest app remote-d1-shell -- npx drizzle-kit studio
78
- ```
79
-
80
- ## Documentation
81
-
82
- For full documentation, visit [everyapp.dev/docs](https://everyapp.dev/docs).
9
+ - Every command, explained: https://everyapp.com/docs/commands
10
+ - What coding agents read: [`skills/everyapp/SKILL.md`](skills/everyapp/SKILL.md), copied into each new app by `everyapp create`
11
+ - How it is tested: [`../../docs/TESTING.md`](../../docs/TESTING.md)
package/bin/everyapp.js CHANGED
@@ -1,6 +1,241 @@
1
1
  #!/usr/bin/env node
2
2
  // Committed launcher so package managers can link the bin at install time,
3
3
  // before dist/ exists (fresh CI checkouts install with --ignore-scripts).
4
+ //
5
+ // everyapp runs from a checkout of the Every App repository: nothing is
6
+ // published while we work from the repository (.github/RELEASE.md). So when
7
+ // the CLI's source, or the SDK, perimeter or toolbus it bundles, changed
8
+ // since dist/ was built, it is rebuilt first: a few seconds, and only after
9
+ // a change, so `everyapp` always runs the code in front of you.
10
+ //
11
+ // Dependency-free, and nothing newer than Node 18 runs before the Node
12
+ // check below: an old Node must reach the friendly message, not a
13
+ // SyntaxError. (src/bin/launcher.test.ts holds the imports to that.)
14
+ import { spawnSync } from "node:child_process";
15
+ import fs from "node:fs";
16
+ import path from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+
19
+ // The Node this needs, said as src/lib/runtime.ts says it (the launcher
20
+ // can't import src): cf loads cloudflare.config.ts with Node's built-in
21
+ // TypeScript stripping, which Node gained in 22.18.0.
22
+ const MIN_NODE_VERSION = "22.18.0";
23
+
24
+ /** Whether `version` is older than `minimum` (both "major.minor.patch", a leading v allowed). */
25
+ function olderThan(version, minimum) {
26
+ const parse = (value) =>
27
+ value
28
+ .replace(/^v/, "")
29
+ .split(/[.-]/)
30
+ .slice(0, 3)
31
+ .map((part) => Number.parseInt(part, 10) || 0);
32
+ const [left, right] = [parse(version), parse(minimum)];
33
+ for (let i = 0; i < 3; i += 1) {
34
+ if ((left[i] ?? 0) !== (right[i] ?? 0)) return (left[i] ?? 0) < (right[i] ?? 0);
35
+ }
36
+ return false;
37
+ }
38
+
39
+ // Colors as the CLI decides them (src/lib/output/terminal.ts): never with
40
+ // NO_COLOR, only at a terminal that isn't dumb; FORCE_COLOR decides alone.
41
+ const colors =
42
+ process.env.FORCE_COLOR !== undefined
43
+ ? process.env.FORCE_COLOR !== "0"
44
+ : Boolean(process.stderr.isTTY) && !process.env.NO_COLOR && process.env.TERM !== "dumb";
45
+ const dim = (text) => (colors ? `\x1b[2m${text}\x1b[22m` : text);
46
+ const red = (text) => (colors ? `\x1b[31m${text}\x1b[39m` : text);
47
+
48
+ if (olderThan(process.versions.node, MIN_NODE_VERSION)) {
49
+ const message = `everyapp needs Node.js ${MIN_NODE_VERSION} or newer; this is ${process.versions.node}\nThe Cloudflare CLI loads cloudflare.config.ts with Node's built-in TypeScript support.`;
50
+ const fix = "install Node 22 or 24, then run the command again";
51
+ if (process.argv.includes("--json")) {
52
+ // One event on stdout, as the CLI's --json would write it.
53
+ process.stdout.write(
54
+ `${JSON.stringify({
55
+ v: 1,
56
+ ts: new Date().toISOString(),
57
+ type: "error",
58
+ code: "UNSUPPORTED_RUNTIME",
59
+ message,
60
+ retryable: false,
61
+ data: { fix },
62
+ })}\n`,
63
+ );
64
+ } else {
65
+ const [headline, ...detail] = message.split("\n");
66
+ process.stderr.write(
67
+ [`${red("✗")} ${headline}`, ...detail.map((line) => dim(` ${line}`)), ` Fix: ${fix}`, ""].join("\n"),
68
+ );
69
+ }
70
+ process.exit(1);
71
+ }
72
+
73
+ const cliDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
74
+ const packagesDir = path.dirname(cliDir);
75
+ const sdkDir = path.join(packagesDir, "sdk");
76
+
77
+ /** When `file` was last written, in ms; 0 when it doesn't exist. */
78
+ function writtenAt(file) {
79
+ return fs.statSync(file, { throwIfNoEntry: false })?.mtimeMs ?? 0;
80
+ }
81
+
82
+ /** The newest write to any of `entries` (files, or directories walked whole), tests aside. */
83
+ function newestWrite(entries) {
84
+ let newest = 0;
85
+ for (const entry of entries) {
86
+ const stat = fs.statSync(entry, { throwIfNoEntry: false });
87
+ if (!stat) continue;
88
+ if (!stat.isDirectory()) {
89
+ newest = Math.max(newest, stat.mtimeMs);
90
+ continue;
91
+ }
92
+ for (const file of fs.readdirSync(entry, { recursive: true, withFileTypes: true })) {
93
+ if (!file.isFile() || file.name.endsWith(".test.ts")) continue;
94
+ newest = Math.max(newest, writtenAt(path.join(file.parentPath, file.name)));
95
+ }
96
+ }
97
+ return newest;
98
+ }
99
+
100
+ /** Which of the SDK and the CLI changed since their dist/ was built. */
101
+ function staleness() {
102
+ const sdkBuilt = writtenAt(path.join(sdkDir, "dist", "server", "index.js"));
103
+ const sdk =
104
+ newestWrite([
105
+ path.join(sdkDir, "src"),
106
+ path.join(sdkDir, "package.json"),
107
+ path.join(sdkDir, "tsconfig.json"),
108
+ path.join(sdkDir, "tsconfig.build.json"),
109
+ ]) > sdkBuilt;
110
+ const cli =
111
+ sdk ||
112
+ newestWrite([
113
+ path.join(cliDir, "src"),
114
+ path.join(cliDir, "package.json"),
115
+ path.join(cliDir, "tsconfig.json"),
116
+ path.join(packagesDir, "perimeter", "src"),
117
+ path.join(packagesDir, "perimeter", "package.json"),
118
+ path.join(packagesDir, "toolbus", "src"),
119
+ path.join(packagesDir, "toolbus", "package.json"),
120
+ path.join(sdkDir, "dist"),
121
+ ]) > writtenAt(path.join(cliDir, "dist", "index.js"));
122
+ return { sdk, cli };
123
+ }
124
+
125
+ /**
126
+ * Run one build command; whether it succeeded. A failure prints the build's
127
+ * output and what failed, and is reported rather than exited on: the caller
128
+ * holds the rebuild lock, and process.exit would skip the finally that
129
+ * releases it.
130
+ */
131
+ function rebuild(command, args, cwd) {
132
+ const result = spawnSync(command, args, { cwd, encoding: "utf8" });
133
+ if (result.status === 0) return true;
134
+ process.stderr.write(result.stdout ?? "");
135
+ process.stderr.write(result.stderr ?? "");
136
+ console.error(
137
+ `everyapp: couldn't rebuild from this checkout: \`${[command, ...args].join(" ")}\` in ${cwd} ${result.error ? `failed (${result.error.message})` : `exited ${result.status}`}.`,
138
+ );
139
+ return false;
140
+ }
141
+
142
+ // One rebuild at a time per checkout. Two everyapps started together (an
143
+ // agent running commands in parallel, two terminals) would both rebuild,
144
+ // and one would trip over the files the other just cleaned. The lock is a
145
+ // directory under the checkout's build cache: mkdir without `recursive` is
146
+ // atomic, so EEXIST means another process holds it. The holder writes its
147
+ // pid; a lock older than 5 minutes, or whose holder is gone, is taken over.
148
+ const LOCK_DIR = path.join(path.dirname(packagesDir), "node_modules", ".cache", "everyapp", "rebuild.lock");
149
+ const LOCK_STALE_MS = 5 * 60_000;
150
+ const LOCK_POLL_MS = 200;
151
+
152
+ /** Whether the lock at `lockDir` was left behind: too old, or its holder is gone. */
153
+ function abandoned(lockDir) {
154
+ const stat = fs.statSync(lockDir, { throwIfNoEntry: false });
155
+ if (!stat) return false;
156
+ if (Date.now() - stat.mtimeMs > LOCK_STALE_MS) return true;
157
+ let pid;
158
+ try {
159
+ pid = Number.parseInt(fs.readFileSync(path.join(lockDir, "pid"), "utf8"), 10);
160
+ } catch {
161
+ // Just made, its pid not written yet: the age rule covers a holder that died here.
162
+ return false;
163
+ }
164
+ if (!Number.isInteger(pid) || pid <= 0) return false;
165
+ try {
166
+ process.kill(pid, 0);
167
+ return false;
168
+ } catch (error) {
169
+ return error?.code === "ESRCH";
170
+ }
171
+ }
172
+
173
+ function sleep(ms) {
174
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
175
+ }
176
+
177
+ /**
178
+ * Run `build` holding the rebuild lock, unless `stillNeeded` says the wait
179
+ * made it moot; what `build` returned, or true when nothing was needed.
180
+ * The lock is released on the way out whatever happened inside.
181
+ */
182
+ function withRebuildLock(stillNeeded, build) {
183
+ fs.mkdirSync(path.dirname(LOCK_DIR), { recursive: true });
184
+ let waiting = false;
185
+ for (;;) {
186
+ try {
187
+ fs.mkdirSync(LOCK_DIR);
188
+ break;
189
+ } catch (error) {
190
+ if (error?.code !== "EEXIST") throw error;
191
+ }
192
+ if (abandoned(LOCK_DIR)) {
193
+ fs.rmSync(LOCK_DIR, { recursive: true, force: true });
194
+ continue;
195
+ }
196
+ if (!waiting) {
197
+ waiting = true;
198
+ console.error(dim("Waiting for another everyapp to finish rebuilding the CLI..."));
199
+ }
200
+ sleep(LOCK_POLL_MS);
201
+ }
202
+ try {
203
+ fs.writeFileSync(path.join(LOCK_DIR, "pid"), String(process.pid));
204
+ const stale = stillNeeded();
205
+ return stale ? build(stale) : true;
206
+ } finally {
207
+ fs.rmSync(LOCK_DIR, { recursive: true, force: true });
208
+ }
209
+ }
210
+
211
+ // Only in a checkout: a packed CLI has dist/ and no source.
212
+ if (fs.existsSync(path.join(cliDir, "src")) && fs.existsSync(path.join(sdkDir, "src")) && staleness().cli) {
213
+ const built = withRebuildLock(
214
+ // Checked again under the lock: the everyapp we waited for may have rebuilt.
215
+ () => {
216
+ const stale = staleness();
217
+ return stale.cli ? stale : null;
218
+ },
219
+ (stale) => {
220
+ // The CLI bundles the SDK from its dist/, and apps load it from there too.
221
+ if (stale.sdk && !rebuild("pnpm", ["run", "build"], sdkDir)) return false;
222
+ // tsup alone, no type check: `pnpm -C packages/cli build` type-checks.
223
+ if (!rebuild("pnpm", ["exec", "tsup", "--silent"], cliDir)) return false;
224
+ // The checkout's short commit. Not --dirty: that answers for every tracked
225
+ // file in the repository (after `create` inside the checkout, the lockfile),
226
+ // not for the sources this rebuild came from, and reads as a fault.
227
+ const commit = spawnSync("git", ["describe", "--always", "--exclude=*"], {
228
+ cwd: cliDir,
229
+ encoding: "utf8",
230
+ }).stdout.trim();
231
+ console.error(dim(`Rebuilt the everyapp CLI from this checkout (${commit})`));
232
+ return true;
233
+ },
234
+ );
235
+ // Exited here, with the lock released: process.exit skips a finally.
236
+ if (!built) process.exit(1);
237
+ }
238
+
4
239
  import("../dist/index.js").catch((error) => {
5
240
  if (error?.code === "ERR_MODULE_NOT_FOUND") {
6
241
  console.error(
@@ -0,0 +1 @@
1
+ import{a,b,c,d,e,f,g,h,i}from"./chunk-AGTCKFRB.js";import"./chunk-E3EPK27P.js";import"./chunk-IFCPALVC.js";import"./chunk-WOVS3GV5.js";import"./chunk-OM2HDWVP.js";import"./chunk-TLRM3P7V.js";import"./chunk-ZFCUH5PK.js";import"./chunk-4JRIS6S6.js";import"./chunk-ZECBN24L.js";import"./chunk-HOUHG236.js";import"./chunk-RMF4YGD6.js";import"./chunk-NFU4YFXB.js";import"./chunk-T2GD7RHS.js";import"./chunk-H7PDL3X5.js";import"./chunk-CCWBPAKH.js";import"./chunk-JYKRUS5C.js";import"./chunk-LYNBZ7RV.js";export{c as APPS_APPLICATION_NAME,b as GATEWAY_APPLICATION_NAME,a as POLICY_NAME,e as off,d as on,f as show,i as showAccess,h as turnAccessOff,g as turnAccessOn};
@@ -0,0 +1,12 @@
1
+ import{a as $,c as b,d as C,e as A,f as g}from"./chunk-ELK7QZ2M.js";import{J as O,K as P,M as R,N as L,O as N,P as W,Q as M,g as E}from"./chunk-M2QQ2UD7.js";import"./chunk-RMF4YGD6.js";import"./chunk-NFU4YFXB.js";import"./chunk-T2GD7RHS.js";import"./chunk-CCWBPAKH.js";import"./chunk-JYKRUS5C.js";import{c as k,f,pc as v,wc as y}from"./chunk-LYNBZ7RV.js";import a from"chalk";var w="workspace.update";async function ee(e){await y(e,p=>j({flags:e,out:p}))}async function ae(e){await y(e,p=>B({flags:e,out:p}))}async function te(e){await y(e,p=>K({flags:e,out:p}))}async function se(e,p){await y(e,i=>H({flags:e,out:i},p))}async function oe(e){await y(e,p=>q({flags:e,out:p}))}async function ie(e,p){await y(e,i=>X({flags:e,out:i},p))}var m=e=>e.toLocaleString("en-US"),T=e=>e===0?a.dim("\u2013"):`$${(e/1e6).toFixed(4)}`;async function j(e){let{out:p,flags:i}=e,{ws:r}=await $(e),s=i.month??O(new Date(r.now)),o=await P(r,s),n=t=>{if(!t.callable)return a.dim("removed");if(t.capUnlimited)return a.dim("none (unlimited)");if(t.effectiveMonthlyCallCap===null)return a.dim("none");let h=m(t.effectiveMonthlyCallCap),I=t.capSource==="default"?`${h} ${a.dim("(default)")}`:h;return t.paused?`${I} ${a.yellow("paused")}`:I},u=v(["APP","CALLS","FAILED","TOOL CALLS","TOKENS IN/OUT","COST","CAP"],o.byApp.map(t=>[t.appSlug??t.appRowId,m(t.calls),t.failures>0?a.yellow(m(t.failures)):a.dim("0"),m(t.toolCalls),`${m(t.inputTokens)}/${m(t.outputTokens)}`,T(t.costMicros),n(t)])),l=v(["MEMBER","CALLS","FAILED","TOOL CALLS","TOKENS IN/OUT","COST"],o.byMember.map(t=>[t.userId===""?a.dim("the apps themselves"):t.email??a.dim(`${t.userId} (no longer a member)`),m(t.calls),t.failures>0?a.yellow(m(t.failures)):a.dim("0"),m(t.toolCalls),`${m(t.inputTokens)}/${m(t.outputTokens)}`,T(t.costMicros)])),c=v(["PROVIDER","KIND","CALLS","FAILED","TOKENS IN/OUT","COST"],o.byTarget.map(t=>[t.target,t.kind,m(t.calls),t.failures>0?a.yellow(m(t.failures)):a.dim("0"),`${m(t.inputTokens)}/${m(t.outputTokens)}`,T(t.costMicros)])),d=o.byApp.reduce((t,h)=>t+h.calls,0),D=o.byApp.reduce((t,h)=>t+h.toolCalls,0),x=o.byApp.filter(t=>t.paused).length,S=`${r.organization.name}, ${s}: ${f(d,"provider call")} and ${f(D,"tool call")} across ${f(o.byApp.length,"app")}${x>0?`, ${x} paused`:""}`,U=o.defaultMonthlyCallCap===null?"No workspace default cap.":`Workspace default cap: ${m(o.defaultMonthlyCallCap)} calls a month for every app without its own.`;p.emit({type:"done",message:S,display:[S,a.dim(U),"",a.bold("By app"),...o.byApp.length>0?u:[a.dim("no apps")],"",a.bold("By member"),...o.byMember.length>0?l:[a.dim("no calls")],"",a.bold("By provider"),...o.byTarget.length>0?c:[a.dim("no calls")],"",a.dim(`Cap an app: ${k} workspace app cap <app> <n|off|--unlimited>; the default: ${k} workspace cap default <n|off>`)].join(`
2
+ `),data:{organization:r.organization,...o}})}async function B(e){let{out:p,flags:i}=e,{ws:r}=await $(e),s=i.app===void 0?void 0:await E(r,i.app,{callable:!0}),o=i.user===void 0?void 0:await b(r,i.user),n=await R(r,{limit:i.limit,before:i.before,appRowId:s?.id,userId:o?.id,decision:i.decision,risk:i.risk,since:i.since}),u=v(["WHEN (UTC)","WHO","APP","TOOL","RISK","DECISION","OUTCOME","MS","CLIENT"],n.calls.map(d=>[A(d.createdAt),d.user.email??a.dim(d.user.id),d.app.slug?`${d.app.slug}${d.app.removed?a.dim(" (removed)"):""}`:a.dim("gateway"),d.tool.via?`${d.tool.name} ${a.dim(`via ${d.tool.via}`)}`:d.tool.name,d.tool.risk??a.dim("\u2013"),d.decision==="allowed"?a.green("allowed"):a.red(`blocked${d.reason?a.dim(` (${d.reason})`):""}`),d.outcome,d.durationMs===null?a.dim("\u2013"):String(d.durationMs),d.credential.clientName??d.credential.clientInfo??a.dim(d.credential.kind)])),l=n.nextBefore?`${n.nextBefore.createdAt}:${n.nextBefore.id}`:null,c=`${f(n.calls.length,"tool call")} in ${r.organization.name}${n.nextBefore?" (more before this page)":""}`;p.emit({type:"done",message:c,display:[n.calls.length>0?u.join(`
3
+ `):a.dim("No tool calls match."),...l?[a.dim(`Next page: ${k} workspace activity --before ${l}`)]:[]].join(`
4
+ `),data:{organization:r.organization,calls:n.calls.map(d=>({...d,createdAt:g(d.createdAt)})),nextBefore:l,...l?{next:[{command:`${k} workspace activity --before ${l}`,note:"the next page"}]}:{}}})}var F=e=>({id:e.id,user:e.user,name:e.name,prefix:e.prefix,app:e.app.slug,scopes:e.scopes,active:e.active,createdAt:g(e.createdAt),expiresAt:g(e.expiresAt),lastUsedAt:g(e.lastUsedAt),revokedAt:g(e.revokedAt)});async function K(e){let{out:p,flags:i}=e,{ws:r}=await $(e),s=i.user===void 0?void 0:await b(r,i.user),o=await L(r,s?.id),n=i.all?o:o.filter(c=>c.active),u=v(["ID","MEMBER","NAME","PREFIX","APP","SCOPES","STATE","LAST USED","EXPIRES"],n.map(c=>[c.id,c.user.email,c.name,`${c.prefix}\u2026`,c.app.slug??a.dim("all apps"),c.scopes.join(","),c.revokedAt!==null?a.dim("revoked"):c.active?a.green("active"):a.yellow("expired"),A(c.lastUsedAt),A(c.expiresAt)])),l=`${f(n.length,i.all?"personal access token":"active personal access token")}${s?` of ${C(s)}`:""} in ${r.organization.name}${!i.all&&o.length>n.length?` (${o.length-n.length} revoked or expired: --all)`:""}`;p.emit({type:"done",message:l,display:[n.length>0?u.join(`
5
+ `):a.dim(l),a.dim(`Revoke one: ${k} workspace token revoke <id>. Tokens are made in Admin \u2192 Tokens; a value is never shown again.`)].join(`
6
+ `),data:{organization:r.organization,tokens:n.map(F)}})}async function H(e,p){let{out:i}=e,{ws:r}=await $(e);i.emit({type:"step",step:w,status:"start",message:`Revoking the token ${p}...`});let{token:s,already:o}=await N(r,p);i.emit({type:"step",step:w,status:"ok",message:`Revoked ${s.name}`,data:{tokenId:s.id,already:o}});let n=o?[`${s.user.email}'s token ${s.name} (${s.prefix}\u2026) was revoked already, on ${A(s.revokedAt)} UTC.`]:[`Revoked ${s.user.email}'s token ${s.name} (${s.prefix}\u2026).`,"It stops working on its next request."];i.emit({type:"done",message:n.join(`
7
+ `),display:[n[0],...n.slice(1).map(u=>a.dim(u))].join(`
8
+ `),data:{organization:r.organization,token:F(s),already:o}})}var z=e=>({id:e.id,user:e.user,clientName:e.clientName,clientDomain:e.clientDomain,redirectHost:e.redirectHost,apps:e.apps,access:e.access,createdAt:g(e.createdAt),lastUsedAt:g(e.lastUsedAt),revokedAt:g(e.revokedAt),revokedReason:e.revokedReason});async function q(e){let{out:p,flags:i}=e,{ws:r}=await $(e),s=i.user===void 0?void 0:await b(r,i.user),o=await W(r,s?.id),n=v(["ID","MEMBER","AI APP","APPS","ACCESS","LAST USED","SINCE"],o.map(l=>[l.id,l.user.email,`${l.clientName}${l.clientDomain?a.dim(` (${l.clientDomain})`):""}`,l.apps==="all"?"all":l.apps.join(", ")||a.dim("none"),l.access==="write"?"read & write":"read",A(l.lastUsedAt),A(l.createdAt)])),u=`${f(o.length,"AI connection")}${s?` of ${C(s)}`:""} in ${r.organization.name}`;p.emit({type:"done",message:u,display:[o.length>0?n.join(`
9
+ `):a.dim(u),a.dim(`Revoke one: ${k} workspace connection revoke <id>`)].join(`
10
+ `),data:{organization:r.organization,connections:o.map(z)}})}async function X(e,p){let{out:i}=e,{ws:r}=await $(e);i.emit({type:"step",step:w,status:"start",message:`Revoking the connection ${p}...`});let{connection:s,already:o}=await M(r,p);i.emit({type:"step",step:w,status:"ok",message:`Revoked ${s.clientName}`,data:{connectionId:s.id,already:o}});let n=o?[`${s.user.email}'s connection from ${s.clientName} was revoked already${s.revokedReason?` (${s.revokedReason})`:""}.`]:[`Revoked ${s.user.email}'s connection from ${s.clientName}.`,"The client is out on its next request; its grant in the Gateway's authorization server lapses on its own."];i.emit({type:"done",message:n.join(`
11
+ `),display:[n[0],...n.slice(1).map(u=>a.dim(u))].join(`
12
+ `),data:{organization:r.organization,connection:z(s),already:o}})}export{ae as activity,ie as connectionRevoke,oe as connections,B as listActivity,q as listConnections,K as listTokens,j as reportUsage,X as revokeConnection,H as revokeToken,se as tokenRevoke,te as tokens,ee as usage};
@@ -0,0 +1,13 @@
1
+ import{a as w,g as _,h as k,j as D}from"./chunk-ELK7QZ2M.js";import{B as x,D as G,E as M,F as U,G as F,H as R,g as T}from"./chunk-M2QQ2UD7.js";import{a as O,d as j,e as E}from"./chunk-OM2HDWVP.js";import"./chunk-4JRIS6S6.js";import"./chunk-RMF4YGD6.js";import{a as W}from"./chunk-NFU4YFXB.js";import"./chunk-T2GD7RHS.js";import"./chunk-CCWBPAKH.js";import"./chunk-JYKRUS5C.js";import{Bb as C,Fb as N,c as v,f as u,pc as P,wc as f}from"./chunk-LYNBZ7RV.js";import d from"chalk";var g="workspace.update";async function ce(e){await f(e,a=>q({flags:e,out:a}))}async function le(e,a){await f(e,o=>B({flags:e,out:o},a))}async function me(e,a){await f(e,o=>Q({flags:e,out:o},a))}var L=e=>e==="off"?null:e;async function de(e,a,o){await f(e,s=>X({flags:e,out:s},a,o===void 0?void 0:L(o),e.unlimited??!1))}async function ue(e,a){await f(e,o=>Y({flags:e,out:o},L(a)))}function J(e){if(!e)return null;try{let a=JSON.parse(e);return a&&typeof a=="object"&&!Array.isArray(a)?a:null}catch{return null}}function K(e,a){let o=J(e.manifest);if(!o||e.tier==="dispatch"||e.status==="pending")return null;try{return E(o)?j({manifest:o,appId:e.appSlug,gatewayNames:a,secretNames:W(e.secretNames)}).setup:null}catch{return null}}var b=(e,a)=>({id:e.id,appId:e.appSlug,name:e.name,description:e.description,status:e.status,scope:e.scope,tier:e.tier,hostname:e.hostname,everyone:e.everyone,accessCount:e.accessCount,...a===void 0?{}:{setup:a}});async function q(e){let{out:a}=e,{gateway:o,ws:s}=await w(e),p=await x(s),i=null;try{i=await O(o.cf)}catch(n){a.emit({type:"warning",code:"SETTINGS_UNKNOWN",message:`Couldn't list the Gateway's settings, so what each app needs set is unknown
2
+ ${N(n)}`})}let t=p.map(n=>({app:n,setup:K(n,i)})),r=P(["APP","NAME","STATUS","WHO CAN OPEN","SETUP"],t.map(({app:n,setup:l})=>[n.appSlug,n.name,n.status==="active"?d.green(n.status):d.yellow(n.status),n.scope==="shared"?"everyone, every organization":n.everyone?`everyone ${d.dim(`(${n.accessCount})`)}`:u(n.accessCount,"member"),l===null?d.dim("\u2013"):l.ready?d.green("ready"):d.yellow(`needs ${l.unmet.map(y=>y.names.join(" or ")).join(", ")}`)])),c=t.filter(({setup:n})=>n&&!n.ready);a.emit({type:"done",message:`${u(p.length,"app")} in ${s.organization.name}${c.length>0?`, ${c.length} needing setup`:""}`,display:p.length>0?r.join(`
3
+ `):d.dim(`No apps in ${s.organization.name} yet.`),data:{organization:s.organization,apps:t.map(({app:n,setup:l})=>b(n,l)),...c.length>0?{next:c.flatMap(({app:n,setup:l})=>l?.command?[{command:l.command.command,note:n.appSlug}]:[])}:{}}})}async function B(e,a){let{out:o,flags:s}=e,{ws:p}=await w(e);o.emit({type:"step",step:g,status:"start",message:`Updating ${a}...`});let{app:i,granted:t}=await G(p,a,{name:s.name,description:s.description,everyone:s.everyone===void 0?void 0:s.everyone==="on"});o.emit({type:"step",step:g,status:"ok",message:`Updated ${i.appSlug}`,data:{appRowId:i.id,granted:t}});let r=[`${i.appSlug} is "${i.name}"${i.description?`: ${i.description}`:""}.`,i.scope==="shared"?"A shared app: every member of every organization can open it.":i.everyone?`Available to everyone in ${p.organization.name}${t>0?` (${u(t,"member")} granted now)`:""}; new members get it on joining.`:`Private: ${u(i.accessCount,"member")} can open it (workspace app access ${i.appSlug}).`];o.emit({type:"done",message:r.join(`
4
+ `),display:[r[0],d.dim(r[1])].join(`
5
+ `),data:{organization:p.organization,app:b(i),granted:t}})}async function Q(e,a){let{out:o,flags:s}=e,{change:p}=D(s),{ws:i}=await w(e),t=await T(i,a),r=[],c=[],n;p?(o.emit({type:"step",step:g,status:"start",message:`Changing who can open ${t.appSlug}...`}),{granted:r,revoked:c,users:n}=await U(i,t,p),o.emit({type:"step",step:g,status:"ok",message:`${t.appSlug}: ${u(r.length,"grant")} added, ${c.length} revoked`,data:{appRowId:t.id,granted:r.length,revoked:c.length}})):n=await M(i,t);let l=n.filter(m=>m.direct||m.viaGroups.length>0),y=P(["EMAIL","ROLE","STATUS","DIRECT","VIA GROUPS"],n.map(m=>[m.email,m.primaryRole??m.role,_(m),m.direct?d.green("yes"):d.dim("no"),m.viaGroups.length>0?m.viaGroups.join(", "):d.dim("\u2013")])),h=p?`${t.appSlug}: granted ${r.length>0?r.map(m=>m.email).join(", "):"nobody"}, revoked ${c.length>0?c.map(m=>m.email).join(", "):"nobody"}; ${u(l.length,"member")} can open it now.`:`${u(l.length,"member")} of ${n.length} can open ${t.appSlug}${t.everyone?" (available to everyone)":""}.`;o.emit({type:"done",message:h,display:[h,y.join(`
6
+ `)].join(`
7
+ `),data:{organization:i.organization,app:b({...t,accessCount:l.length}),users:n.map(m=>({...k(m),direct:m.direct,viaGroups:m.viaGroups})),...p?{granted:r.map(k),revoked:c.map(k)}:{}}})}var I=e=>`${e.toLocaleString("en-US")} calls a month`;function S(e,a){return e!==null?I(e):a?"no cap at all":"no cap of its own"}function V(e){return e===null?null:{subscriptionId:e,message:`Owners and admins are emailed at 80% and at the cap (the built-in Cap alerts subscription; ${v} events list shows it).`}}var z="a provider tool answers a tool error naming the cap, and an app's brokered call gets 429 app_monthly_cap_exceeded until the next UTC month.";async function X(e,a,o,s=!1){let{out:p}=e;if(s&&o!==void 0)throw new C("INVALID_VALUE",`--unlimited takes no number and no off
8
+ An app has a cap (a number), no cap whatever the workspace default (--unlimited), or neither (off).`,{fix:`give --unlimited alone: ${v} workspace app cap ${a} --unlimited`});if(!s&&o===void 0)throw new C("MISSING_ARGUMENT",`Missing the cap
9
+ Give a number of calls per month, off for no cap of its own, or --unlimited.`,{data:{usage:`${v} workspace app cap <app> [<n|off>] [--unlimited] [flags]`}});let{ws:i}=await w(e);p.emit({type:"step",step:g,status:"start",message:`Setting ${a}'s cap...`});let t=await F(i,a,o??null,{unlimited:s}),{app:r,was:c,wasUnlimited:n,effective:l,before:y,capAlertsId:h}=t,m=t.cap===c&&s===n;p.emit({type:"step",step:g,status:"ok",message:`${r.appSlug}: ${S(t.cap,s)}`,data:{appRowId:r.id,cap:t.cap,unlimited:s,was:c,wasUnlimited:n,effectiveCap:l.cap,capSource:l.source}});let $=[m?`${r.appSlug} had ${S(t.cap,s)} already. Nothing changed.`:`${r.appSlug}: ${S(t.cap,s)} for ${i.organization.name} (was ${S(c,n)}).`,l.cap===null?y.cap===null?"Its provider calls are not capped.":"Its provider calls are no longer capped.":l.source==="default"?`The workspace default of ${I(l.cap)} binds it; past it, ${z}`:`Past it, ${z}`],A=V(h);A&&$.push(A.message),p.emit({type:"done",message:$.join(`
10
+ `),display:[$[0],...$.slice(1).map(H=>d.dim(H))].join(`
11
+ `),data:{organization:i.organization,app:b(r),cap:t.cap,unlimited:s,was:c,wasUnlimited:n,effectiveCap:l.cap,capSource:l.source,capAlerts:A}})}async function Y(e,a){let{out:o}=e,{ws:s}=await w(e);o.emit({type:"step",step:g,status:"start",message:"Setting the workspace default cap..."});let{was:p,capAlertsId:i}=await R(s,a),t=n=>n===null?"no default cap":`a default cap of ${I(n)}`;o.emit({type:"step",step:g,status:"ok",message:`${s.organization.name}: ${t(a)}`,data:{cap:a,was:p}});let r=[a===p?`${s.organization.name} had ${t(a)} already. Nothing changed.`:`${s.organization.name}: ${t(a)} (was ${t(p)}).`,a===null?"Every app without a cap of its own is uncapped on the Gateway within 30 seconds; an app's own cap or --unlimited stays.":`Every app without a cap or --unlimited of its own is held to it on the Gateway within 30 seconds; past it, ${z}`],c=V(i);c&&r.push(c.message),o.emit({type:"done",message:r.join(`
12
+ `),display:[r[0],...r.slice(1).map(n=>d.dim(n))].join(`
13
+ `),data:{organization:s.organization,cap:a,was:p,capAlerts:c}})}export{me as appAccess,Q as appAccessCommand,de as appCap,le as appSet,ce as apps,ue as capDefault,q as listApps,X as setCap,Y as setDefaultCap,B as updateApp};
@@ -0,0 +1,2 @@
1
+ import{Bb as o}from"./chunk-LYNBZ7RV.js";import i from"node:fs";import t from"node:path";import{fileURLToPath as a}from"node:url";function p(e=import.meta.url){let r=t.dirname(a(e));for(let n=r;;n=t.dirname(n)){if(i.existsSync(t.join(n,"apps","every-app-gateway","scripts","build-release.ts"))&&i.existsSync(t.join(n,"packages","cli","package.json")))return n;if(t.dirname(n)===n)return null}}function c(e=import.meta.url){let r=p(e);if(r)return r;throw new o("CHECKOUT_MISSING",`everyapp has to run from a checkout of the Every App repository
2
+ This copy is installed in ${u(t.dirname(a(e)))}, outside any checkout.`,{fix:`in your checkout, run pnpm everyapp ${process.argv.slice(2).join(" ")}`.trimEnd()})}function u(e){for(let r=e;t.dirname(r)!==r;r=t.dirname(r))if(i.existsSync(t.join(r,"package.json")))return r;return e}function s(e){try{return i.realpathSync(e)}catch{return t.resolve(e)}}function h(e,r=c()){let n=t.relative(s(r),s(e));return n===""||n!==".."&&!n.startsWith(`..${t.sep}`)&&!t.isAbsolute(n)}export{p as a,c as b,s as c,h as d};
@@ -0,0 +1,6 @@
1
+ import{h as M,i as G,o as z}from"./chunk-H6QQMY7B.js";import{i as _}from"./chunk-6OGVO7QK.js";import{c as x,d as W}from"./chunk-W3JCQHHU.js";import{c as S}from"./chunk-ZFCUH5PK.js";import{b as I}from"./chunk-4JRIS6S6.js";import{h as O}from"./chunk-HOUHG236.js";import{a as L,j as P,k,l as C}from"./chunk-RMF4YGD6.js";import{Fb as v,qb as y}from"./chunk-LYNBZ7RV.js";async function Oe(e){let{cf:n,out:r,databaseId:a}=e,s=L(n,a),d=await k(s);if(!d)throw P();if(!e.force&&!e.stagedSecrets&&!e.unsetSecrets){let{inSync:g,desired:f}=await Z(n,s,d);if(g)return r.emit({type:"step",step:"gateway.reconcile",status:"skip",message:`The gateway already binds ${f.appWorkers.length===1?"the 1 app":`all ${f.appWorkers.length} apps`} its registry lists.`}),{versionId:d.liveVersionId,firstDeploy:!1,appWorkers:f.appWorkers,domains:d.liveDomains,newHosts:[],changed:!1}}let w=await e.openRelease();try{_(w.manifest,e.cliVersion);let g=await O({db:s,out:r,leaseWaitMs:e.leaseWaitMs,sleep:e.sleep},"gateway.reconcile");try{let f=await k(s)??d;return e.unsetSecrets?.length&&(await g.check(),f=await ee(n,s,f,e.unsetSecrets)),{...await z({cf:n,out:r,reason:"reconcile",release:w,accountId:e.accountId,gatewayHost:f.gatewayHost,zone:{id:f.zoneId,name:f.zoneName},appBaseDomain:f.appBaseDomain,forceDns:e.forceDns,resources:{d1Id:a,oauthKvId:f.oauthKvId,created:[]},db:s,interactive:e.interactive,confirm:e.confirm,cliVersion:e.cliVersion,stagedSecrets:e.stagedSecrets,heldLease:g,sleep:e.sleep}),changed:!0}}finally{await g.release()}}finally{await w.cleanup()}}async function Z(e,n,r){let a=await G(n,M(e));if(!([...r.liveAppWorkers].sort().join(`
2
+ `)===a.appWorkers.join(`
3
+ `))||!X(r,a.appHosts))return{inSync:!1,desired:a};let d=await S(e,y);return{inSync:!!d?.versionId&&d?.versionId===r.liveVersionId,desired:a}}function X(e,n){if(!e.liveDomains.includes(e.gatewayHost))return!1;let r=e.liveDomains.filter(s=>s!==e.gatewayHost),a=x(n,e.appBaseDomain);return[...r].sort().join(`
4
+ `)===[...a].sort().join(`
5
+ `)}async function ee(e,n,r,a){for(let w of a)await I(e,y,w);let s=await S(e,y);if(!s?.versionId||s.versionId===r.liveVersionId)return r;let d={...r,liveVersionId:s.versionId,updatedAt:Date.now()};return await C(n,d),d}import{Agent as ae,fetch as ie}from"undici";import $ from"node:dns";import{isIP as H}from"node:net";var te=["1.1.1.1","1.0.0.1"],ne=2e3,se=2,F=3e3,D=new Set(["ENODATA","ENOTFOUND"]),re={createResolver:e=>{let n=new $.promises.Resolver({timeout:ne,tries:se});return n.setServers(e),n},osLookup:e=>$.promises.lookup(e,{all:!0})};function E(e){return e?.code}function b(e,n){return Object.assign(new Error(n),{code:"ENOTFOUND",hostname:e})}function oe(e=re){let n=new Map,r=new Set,a=new Set,s=new Map,d=new Map,w=te.join(",");function g(t,o){return o.then(i=>(r.add(t),i),i=>{throw D.has(E(i)??"")&&r.add(t),i})}function f(t){if(a.has(t))throw new Error(`${t} didn't answer earlier in this run.`);let o=n.get(t);if(o)return o;let i=e.createResolver(t.split(",")),l={resolveNs:c=>g(t,i.resolveNs(c)),resolve4:c=>g(t,i.resolve4(c)),resolve6:c=>g(t,i.resolve6(c)),resolveSoa:c=>g(t,i.resolveSoa(c)),cancel:()=>i.cancel()};return n.set(t,l),l}async function A(t){let o=d.get(t);if(o)return o;let i=f(w);for(let l of W(t)){if(!s.has(l)){let c;try{c=await i.resolveNs(l)}catch(u){if(D.has(E(u)??""))continue;throw u}if(c.length===0)continue;let m=(await Promise.allSettled(c.map(u=>i.resolve4(u)))).flatMap(u=>u.status==="fulfilled"?u.value:[]);if(m.length===0)throw new Error(`No address for ${l}'s nameservers.`);s.set(l,[...new Set(m)])}return d.set(t,l),l}throw new Error(`No zone found for ${t}.`)}function R(t){let o=d.get(t),i=o&&s.get(o)?.join(",");return i?[w,i]:[w]}async function N(t,o){let i,l=new Promise((p,m)=>{i=setTimeout(()=>{for(let u of R(t))n.get(u)?.cancel();m(new Error(`No answer for ${t} within ${F/1e3} s.`))},F)}),c=(async()=>{let p=await A(t);return o(p,f(s.get(p).join(",")))})();try{return await Promise.race([c,l])}catch(p){for(let m of R(t))r.has(m)||a.add(m);throw p}finally{clearTimeout(i)}}async function J(t,o){let i=await Promise.allSettled([o.resolve4(t),o.resolve6(t)]),l=i.flatMap((p,m)=>p.status==="fulfilled"?p.value.map(u=>({address:u,family:m===0?4:6})):[]);if(l.length>0)return l;let c=i.find(p=>p.status==="rejected"&&!D.has(E(p.reason)??""));if(c?.status==="rejected")throw c.reason;return l}async function K(t){if(H(t))return[{address:t,family:H(t)}];let o;try{o=await N(t,(i,l)=>J(t,l))}catch{return e.osLookup(t)}if(o.length===0)throw b(t,`${t} has no address at its zone's nameservers yet`);return o}let q=(t,o,i)=>{let l=typeof o=="function"?o:i,c=typeof o=="function"?{}:typeof o=="number"?{family:o}:o??{},p=c.family==="IPv4"?4:c.family==="IPv6"?6:c.family??0,m=(...u)=>process.nextTick(()=>l(...u));K(t).then(u=>{let T=p?u.filter(Q=>Q.family===p):u,h=T[0];h?c.all?m(null,T):m(null,h.address,h.family):m(b(t,`${t} has no IPv${p} address`),"")},u=>m(u instanceof Error?u:b(t,String(u)),""))};async function Y(t){try{let o=await N(t,async(i,l)=>(await l.resolveSoa(i)).minttl);return Number.isFinite(o)?o:null}catch{return null}}return{lookup:q,negativeCacheTtlSeconds:Y}}var j=oe(),U=j.lookup,V=j.negativeCacheTtlSeconds;var ce=1e4;function le(e){return/cloudflareaccess\.com|\/cdn-cgi\/access\//i.test(e??"")}var ue=new Set(["ENOTFOUND","EAI_AGAIN","ENODATA"]),de=new Set(["EPROTO","ECONNRESET"]);function pe(e){let n=[];for(let r=e;r!==void 0&&n.length<5;)n.push(r),r=r instanceof Error?r.cause:void 0;return n}function fe(e){let n=pe(e),r=n.map(s=>String(s?.code??"")),a=n.map(v).join(`
6
+ `);return r.some(s=>ue.has(s))||/\b(ENOTFOUND|EAI_AGAIN|ENODATA)\b/.test(a)?"dns":r.some(s=>s.startsWith("ERR_SSL_")||s.startsWith("ERR_TLS_")||de.has(s))||/handshake|alert|certificate/i.test(a)?"tls":"other"}var B,me=(e,n)=>(B??=new ae({connect:{lookup:U}}),ie(e,{...n,dispatcher:B}));function we(e){let n=e instanceof Error&&e.cause instanceof Error?e.cause:e;return v(n)}async function ze(e,n=me,r=ce){try{let a=await n(e,{method:"GET",redirect:"manual",signal:AbortSignal.timeout(r),headers:{"user-agent":"everyapp-cli"}});await a.body?.cancel().catch(()=>{});let s=a.headers.get("location");return{answered:!0,status:a.status,access:a.status>=300&&a.status<400&&le(s)}}catch(a){return{answered:!1,reason:we(a),kind:fe(a)}}}import ge from"node:dns";var je={lookup:e=>ge.promises.lookup(e,{all:!0}),negativeCacheTtlSeconds:V};function ye(e){let n=e?.code??"";return n==="ENOTFOUND"||n==="ENODATA"||n.startsWith("EAI_")}function he(e){if(e===null)return"half an hour";let n=Math.max(1,Math.ceil(e/60));return n===1?"a minute":`${n} minutes`}async function Ue({host:e,lead:n,out:r,step:a,localDns:s}){try{return await s.lookup(e),!1}catch(w){if(!ye(w))return!1}let d=await s.negativeCacheTtlSeconds(e).catch(()=>null);return r.emit({type:"warning",code:"LOCAL_DNS_STALE",step:a,message:`${n}, but this computer's DNS resolver, or this network's, still remembers ${e} as missing from before it existed. That clears by itself within ${he(d)}; a browser with its own DNS, such as Chrome, works now. On macOS, \`sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder\` clears this computer's own cache, but not the network's.`,data:{host:e,negativeCacheTtlSeconds:d}}),!0}export{Oe as a,Z as b,ze as c,je as d,Ue as e};
@@ -0,0 +1 @@
1
+ import{n as a}from"./chunk-JYKRUS5C.js";import{Gb as c,bc as i}from"./chunk-LYNBZ7RV.js";async function m(e,t){return(await i(e,{plane:"account",args:["workers","secrets","list","--worker",t]},a)).map(r=>r.name).sort()}async function p(e,t,n){try{return await e.run({plane:"account",mode:"json",args:["workers","secrets","delete",n,"--worker",t,"--force"]}),!0}catch(r){if(r instanceof c&&(r.kind==="not_found"||/not[_ ]found/i.test(r.message)))return!1;throw r}}async function d(e,t,n){let r={secrets:Object.fromEntries(Object.entries(n).map(([s,o])=>[s,o===null?null:{name:s,type:"secret_text",text:o}]))};await e.run({plane:"account",mode:"json",files:{"secrets.json":r},args:s=>["workers","secrets","bulk","--worker",t,"--body",`@${s["secrets.json"]}`]})}export{m as a,p as b,d as c};
@@ -0,0 +1,4 @@
1
+ import{c as e}from"./chunk-LYNBZ7RV.js";import{buildCommand as n,buildRouteMap as c}from"@stricli/core";var r={kind:"parsed",parse:String,brief:"The Gateway's URL, checked against the Gateway in your Cloudflare account (default: EVERYAPP_GATEWAY_URL)",optional:!0},i={kind:"parsed",parse:String,brief:"The Cloudflare account of the Gateway, when your login sees several (default: CLOUDFLARE_ACCOUNT_ID)",optional:!0},g={kind:"parsed",parse:String,brief:"The organization to act on, by slug, id or name (default: the install organization; a name two organizations share is refused, ORG_AMBIGUOUS: give the slug)",placeholder:"slug",optional:!0},l={kind:"boolean",brief:"Print NDJSON events on stdout and never prompt (exit 0 done, 1 error, 2 action required, 251/252 bad command or arguments)",optional:!0},f={kind:"boolean",brief:"Print the result as an NDJSON event",optional:!0},d={kind:"boolean",brief:"Show every step and progress line, the output of what everyapp runs, and an unexpected error's stack trace",optional:!0},w={kind:"boolean",brief:"Skip everyapp's own confirmations (never cf's questions, or the one before replacing a Worker changed outside everyapp)",optional:!0},u={kind:"boolean",brief:"Publish new hostnames even where a DNS record answers them (one at a hostname is replaced)",optional:!0},y={"allow-delete-durable-object-data":{kind:"boolean",brief:"Deploy even though Durable Object classes were removed, deleting their data",optional:!0},"allow-delete-workflows":{kind:"boolean",brief:"Deploy even though Workflows were removed, deleting them and their instances",optional:!0},"force-dns":{...u,brief:"Publish the app's new hostname even where a DNS record answers it (one at the hostname is replaced)"},"enable-email-routing":{kind:"boolean",brief:"Turn on Email Routing for the domains the app's inbound addresses (everyapp email set --inbound) name that don't route mail yet (locks their MX and SPF records to Cloudflare)",optional:!0}};var p=(o=>(o.Senders="senders",o.Inbound="inbound",o))(p||{}),t={manifest:{kind:"parsed",parse:String,brief:"Path to everyapp.config.ts, if it isn't in this directory",placeholder:"path",optional:!0},gateway:r,"account-id":i,json:l,verbose:d},m=n({loader:async()=>{let{set:a}=await import("./email-RLZFUFUN.js");return a},parameters:{positional:{kind:"tuple",parameters:[]},flags:{sender:{kind:"parsed",parse:String,variadic:!0,optional:!0,placeholder:"pattern",brief:"Address the app may send as: '*@<domain>' or one address (repeat, up to 20)"},inbound:{kind:"parsed",parse:String,variadic:!0,optional:!0,placeholder:"address",brief:"Address whose mail goes to the app: '*@<apex>' or one address (repeat, up to 50)"},"enable-email-routing":{kind:"boolean",optional:!0,brief:"Turn on Email Routing for inbound domains without asking"},...t}},docs:{brief:"Set senders or inbound addresses, without a deploy",fullDescription:["Each flag replaces its whole list; a list you don't name is kept. The Gateway","picks up a change within 30 seconds, without a deploy. Addresses set before","the app's first upload are routed by its next deploy.","","Requirements:"," --sender everyapp.config.ts lists capabilities.email; each domain is set up for Email Sending"," --inbound everyapp.config.ts declares email: { inbound: true }; the domain is on Cloudflare DNS","","Examples:",` ${e} email set --sender '*@mail.example.com'`,` ${e} email set --inbound reports@mail.example.com`,` ${e} email set --inbound '*@example.com' --enable-email-routing`].join(`
2
+ `)}}),b=n({loader:async()=>{let{unset:a}=await import("./email-RLZFUFUN.js");return a},parameters:{positional:{kind:"array",minimum:1,parameter:{brief:"List to clear: senders or inbound",placeholder:"senders|inbound",parse:a=>{let s=Object.values(p).find(o=>o===a);if(!s)throw new Error("Use senders, inbound, or both.");return s}}},flags:t},docs:{brief:"Clear senders or inbound addresses, without a deploy",fullDescription:["Clearing inbound addresses removes their Email Routing rules; a catch-all goes","back to dropping mail. Nothing is built or deployed.","","Examples:",` ${e} email unset inbound`,` ${e} email unset senders inbound`].join(`
3
+ `)}}),h=n({loader:async()=>{let{show:a}=await import("./email-RLZFUFUN.js");return a},parameters:{positional:{kind:"tuple",parameters:[]},flags:t},docs:{brief:"Show the app's senders and inbound addresses",fullDescription:["Lists the app's senders and inbound addresses on the Gateway, and whether each","inbound address is routed.","","Examples:",` ${e} email show`,` ${e} email show --manifest ../analytics/everyapp.config.ts`].join(`
4
+ `)}}),S=c({routes:{show:h,set:m,unset:b},docs:{brief:"Manage the addresses an app sends as and receives at"}});export{r as a,i as b,g as c,l as d,f as e,d as f,w as g,u as h,y as i,S as j};
@@ -0,0 +1,6 @@
1
+ import{b as v}from"./chunk-W3JCQHHU.js";import{f as _}from"./chunk-ONLNJXVQ.js";import{Ab as O,Bb as c,Yb as h,Zb as S,zb as k}from"./chunk-LYNBZ7RV.js";import E from"node:fs/promises";import d from"node:path";import{OutputWorkerSchema as b}from"@cloudflare/config";import R from"node:fs/promises";import g from"node:path";var L=g.join(".cloudflare","output","v0"),A=g.join(L,"workers"),D="default";async function*ie(e){let t=g.join(e,A);for(let n of await R.readdir(t,{withFileTypes:!0})){if(!n.isDirectory())continue;let r=g.join(t,n.name),i=g.join(r,"worker.config.json"),o=JSON.parse(await R.readFile(i,"utf8"));yield{name:n.name,directory:r,file:i,config:o}}}async function oe(e){let t=JSON.parse(await R.readFile(g.join(e,"config.json"),"utf8"));return t.buildContext?.mode==="production"&&!t.buildContext.isPreview}var I=d.join(A,D),j=d.join(I,"worker.config.json"),C=d.join(I,"bundle"),N="__EVERYAPP_PATCH__",B="every-app-gateway";function U(e){return[e.gatewayHost,...[...new Set(e.appHosts)].filter(t=>t!==e.gatewayHost).sort()]}async function ge(e,t){let n=d.join(e,j),r=JSON.parse(await E.readFile(n,"utf8")),i={...r.env??{}};for(let a of Object.keys(i))a.startsWith(k)&&delete i[a];delete i.KV,i.DB={type:"d1",name:B,id:t.d1Id},i.OAUTH_KV={type:"kv",id:t.oauthKvId},i.EVERYAPP_RELEASE={type:"json",value:t.release},i.CF_VERSION_METADATA={type:"version-metadata"};for(let a of[...new Set(t.appWorkers)].sort())i[O(a)]={type:"worker",worker:a};if(r.env=i,t.gatewayHost!==t.appBaseDomain)throw new c("INVALID_APP_BASE_DOMAIN",`Apps live one label below the gateway host ${t.gatewayHost}, so APP_BASE_DOMAIN must be ${t.gatewayHost}, not ${t.appBaseDomain}.`);let o=t.appHosts.filter(a=>!v(a,t.appBaseDomain));if(o.length>0)throw new c("INVALID_APP_HOST",`Refusing to publish ${o.join(", ")} on the gateway: app hosts are one label below ${t.appBaseDomain}.`);i.APP_BASE_DOMAIN={type:"text",value:t.appBaseDomain},r.domains=U(t);let s=(r.triggers??[]).filter(a=>a.type!=="fetch");if(s.length>0?r.triggers=s:delete r.triggers,r.workersDev=!1,r.previewUrls=!1,r.observability??=structuredClone(_),r.manifest){let a={...r.manifest.modules??{}};for(let w of await F(d.join(e,C)))a[w]={type:"sourcemap"};r.manifest={...r.manifest,modules:a}}return V(r,{requireDomain:!0}),await E.writeFile(n,`${JSON.stringify(r,null,2)}
2
+ `),r}function V(e,{requireDomain:t=!1}={}){let n=b.safeParse(e);if(!n.success)throw new c("INVALID_BUILD_OUTPUT",`The patched Worker config isn't valid Build Output: ${n.error.issues.map(r=>`${r.path.join(".")||"(root)"}: ${r.message}`).join("; ")}`);if(JSON.stringify(e).includes(N))throw new c("INVALID_BUILD_OUTPUT","The Worker config still has a deploy-time placeholder.");if(t&&!n.data.domains?.length)throw new c("INVALID_BUILD_OUTPUT","The gateway has no domain to deploy to.")}async function F(e){let t;try{t=await E.readdir(e,{recursive:!0,withFileTypes:!0})}catch{return[]}return t.filter(n=>n.isFile()&&n.name.endsWith(".map")).map(n=>d.relative(e,d.join(n.parentPath,n.name)).split(d.sep).join("/")).sort()}import{spawn as W}from"node:child_process";import{createHash as $}from"node:crypto";import m from"node:fs/promises";import p from"node:path";import{z as l}from"zod";var Se="every-app-gateway-release.tar.gz",x="v0",M={gateway:new Set([".cloudflare","drizzle","release.json"]),app:new Set([".cloudflare","migrations","release.json"])},H=l.looseObject({schema:l.literal(1),kind:l.string().optional(),version:l.string(),gitSha:l.string(),builtAt:l.string(),cfVersion:l.string(),buildOutputVersion:l.string(),sha256:l.string().regex(/^[0-9a-f]{64}$/),migrations:l.array(l.object({tag:l.string(),when:l.number()})),minCli:l.string(),minSdk:l.string()}),G=H.extend({committedAt:l.string().optional(),pluginVersion:l.string(),configVersion:l.string()});function _e({version:e,commit:t}){return t?`commit ${t.hash}${t.uncommittedChanges?" with uncommitted changes":""}`:e}function ve(e){switch(e.kind){case"checkout":return"this checkout";case"github":return`${e.repo} release ${e.tag}`;case"url":return e.url;case"file":return e.path}}async function K(e){let t=(await m.readdir(e,{recursive:!0,withFileTypes:!0})).filter(n=>n.isFile()).map(n=>p.relative(e,p.join(n.parentPath,n.name)).split(p.sep).join("/")).filter(n=>n!=="release.json");return z(e,t)}async function z(e,t){let n=$("sha256");for(let r of[...t].sort()){let i;try{i=await m.readFile(p.join(e,r))}catch(o){if(!h(o))throw o;n.update(`${r}\0-
3
+ `);continue}n.update(`${r}\0${$("sha256").update(i).digest("hex")}
4
+ `)}return n.digest("hex")}function J(e,t){return new Promise((n,r)=>{let i=W("tar",["-xzf",e,"-C",t],{stdio:"ignore"});i.once("error",r),i.once("close",o=>o===0?n():r(new Error(`tar couldn't extract ${e} (exit ${o})`)))})}async function Y(e,t,n){let r=await m.readdir(e,{recursive:!0,withFileTypes:!0});for(let i of r){let o=p.join(i.parentPath,i.name),s=p.relative(e,o).split(p.sep).join("/");if(i.isSymbolicLink()||!(i.isFile()||i.isDirectory()))throw new c("RELEASE_INVALID",`${t} isn't ${n}: ${s} is a link or a special file, not a regular file.`);if(i.isFile()&&(await m.lstat(o)).nlink>1)throw new c("RELEASE_INVALID",`${t} isn't ${n}: ${s} is a hard link, not a regular file.`)}}function q(e){return typeof e=="string"&&e.length>0&&!p.isAbsolute(e)&&!/[\\\0-\x1f]/.test(e)&&e.split("/").every(t=>t!==""&&t!=="."&&t!=="..")}async function X(e,t,n){let r=p.join(e,".cloudflare","output","v0","workers"),i;try{i=await m.readdir(r)}catch(o){if(h(o))return;throw o}for(let o of i){let s;try{s=JSON.parse(await m.readFile(p.join(r,o,"worker.config.json"),"utf8"))}catch(u){if(h(u))continue;throw u}let a=s?.manifest,f=[a?.mainModule,...Object.keys(a?.modules&&typeof a.modules=="object"?a.modules:{})].filter(u=>u!==void 0).find(u=>!q(u));if(f!==void 0)throw new c("RELEASE_INVALID",`${t} isn't ${n}: its ${o} Worker lists a module outside its bundle: ${String(f)}.`)}}var T={gateway:{a:"a gateway release",the:"Gateway release"},app:{a:"an app release",the:"App release"}};async function Z(e,t,n){let r=T[t],{dir:i,cleanup:o}=await S(`${t}-release-`);try{await J(e,i),await Y(i,e,r.a),await X(i,e,r.a);let s=JSON.parse(await m.readFile(p.join(i,"release.json"),"utf8")),a=s?.kind??"gateway";if(a!==t){let y=a==="app"||a==="gateway"?T[a].a:`a ${String(a)} release`;throw new c("RELEASE_INVALID",`${e} is ${y}, not ${t==="gateway"?"a Gateway release":r.a}.`)}let w=(await m.readdir(i)).filter(y=>!M[t].has(y));if(w.length>0)throw new c("RELEASE_INVALID",`${e} holds more than ${r.a}: ${w.join(", ")}.`);let f=n.safeParse(s);if(!f.success)throw new c("RELEASE_INVALID",`${e} isn't a valid ${r.the.toLowerCase()}
5
+ Its release.json is malformed: ${f.error.issues[0]?.message}`);let u=f.data;if(u.buildOutputVersion!==x)throw new c("RELEASE_UNSUPPORTED",`${r.the} ${u.version} needs a newer everyapp`,{fix:"update everyapp (in a checkout: git pull), then run this again",data:{buildOutputVersion:u.buildOutputVersion,supported:x}});let P=await K(i);if(P!==u.sha256)throw new c("RELEASE_CORRUPT",`${r.the} ${u.version} doesn't match its checksum
6
+ The download may be damaged. Download it again.`,{data:{expected:u.sha256,actual:P}});return{dir:i,manifest:u,cleanup:o}}catch(s){throw await o(),s instanceof SyntaxError||h(s)?new c("RELEASE_INVALID",`${e} isn't ${r.a}: ${s.message}`):s}}async function De(e,t={origin:{kind:"file",path:e}}){let{dir:n,manifest:r,cleanup:i}=await Z(e,"gateway",G),o=Q(r),s={treeSha256:t.treeSha256??null,order:{...o,committedAt:t.committedAt??o.committedAt},origin:t.origin};return{dir:n,tarball:e,manifest:r,source:s,cleanup:i}}function Q(e){return{schema:ee(e.migrations),committedAt:Date.parse(e.committedAt??"")||Date.parse(e.builtAt)||0}}function Ie(e,t,n=`Gateway ${e.version}`){if(te(e.minCli,t)>0)throw new c("CLI_TOO_OLD",`${n} needs everyapp ${e.minCli} or newer (this is ${t})`,{fix:"update everyapp (in a checkout: git pull), then run this again",data:{minCli:e.minCli,cliVersion:t}})}function ee(e){return Math.max(0,...e.map(t=>t.when))}function $e(e,t){return e.schema-t.schema||e.committedAt-t.committedAt}function te(e,t){let n=o=>o.replace(/^v/,"").split("-")[0].split(".").map(s=>Number.parseInt(s,10)||0),[r,i]=[n(e),n(t)];for(let o=0;o<Math.max(r.length,i.length);o+=1){let s=(r[o]??0)-(i[o]??0);if(s!==0)return s}return 0}export{Se as a,H as b,_e as c,ve as d,K as e,z as f,Z as g,De as h,Ie as i,ee as j,$e as k,L as l,D as m,ie as n,oe as o,U as p,ge as q,V as r,F as s};
@@ -0,0 +1,11 @@
1
+ import{d as o,f as s}from"./chunk-HOUHG236.js";var r={sql:`CREATE TABLE IF NOT EXISTS _everyapp_restore_points (
2
+ target TEXT PRIMARY KEY,
3
+ database_id TEXT NOT NULL,
4
+ bookmark TEXT NOT NULL,
5
+ migrations TEXT NOT NULL,
6
+ created_at INTEGER NOT NULL,
7
+ created_by TEXT NOT NULL
8
+ )`},d=o,c=s;async function g(a,t){await a.run([r,{sql:`INSERT INTO _everyapp_restore_points (target, database_id, bookmark, migrations, created_at, created_by)
9
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6)
10
+ ON CONFLICT (target) DO UPDATE SET database_id = excluded.database_id, bookmark = excluded.bookmark,
11
+ migrations = excluded.migrations, created_at = excluded.created_at, created_by = excluded.created_by`,params:[t.target,t.databaseId,t.bookmark,JSON.stringify(t.migrations),t.createdAt,t.createdBy]}])}async function E(a,t){let[,i=[]]=await a.run([r,{sql:"SELECT target, database_id, bookmark, migrations, created_at, created_by FROM _everyapp_restore_points WHERE target = ?",params:[t]}]),e=i[0];return e?{target:String(e.target),databaseId:String(e.database_id),bookmark:String(e.bookmark),migrations:JSON.parse(String(e.migrations)).map(String),createdAt:Number(e.created_at),createdBy:String(e.created_by)}:null}async function T(a,t){await a.run([r,{sql:"DELETE FROM _everyapp_restore_points WHERE target = ?",params:[t]}])}export{d as a,c as b,g as c,E as d,T as e};
@@ -0,0 +1,22 @@
1
+ import{a as Te,b as tt,c as nt,d as Le,e as q}from"./chunk-E3EPK27P.js";import{B as Me}from"./chunk-IFCPALVC.js";import{A as Q,B as Z,C as Xe,D as Ke,E as Qe,F as Ce,G as Ee,H as ve,I as De,J as Oe,K as ke,L as et,M as Pe,N as me,O as ct,b as Ae,c as We,d as je,e as we,f as Be,g as He,h as $e,i as Ve,k as Ye,l as ie,m as Ze,n as be,o as Se,p as qe,q as xe,r as ce,s as Ie,t as K,u as le,v as re,w as Y,x as de,y as Je,z as _e}from"./chunk-TLRM3P7V.js";import{a as oe}from"./chunk-4JRIS6S6.js";import{c as it,e as ot}from"./chunk-HOUHG236.js";import{$ as dt,B as rt,qa as pt,sa as mt,y as lt}from"./chunk-RMF4YGD6.js";import{a as pe,f as st,i as at}from"./chunk-CCWBPAKH.js";import{Bb as z,Gb as Fe,c as H,f as V,k as A,oc as Re,qb as ae,rc as ne,wc as ue}from"./chunk-LYNBZ7RV.js";import u from"chalk";var x="Every App gateway members",ut="Every App gateway",It="Every App apps",_t="720h",tn=24*3600,D="access.update";async function nn(t){await ue(t,e=>Dt({flags:t,out:e,emails:t.email,emailDomains:t["email-domain"],team:t.team,session:t.session,teamSession:t["team-session"],writeSettings:t["write-settings"]}))}async function sn(t){await ue(t,e=>Tt({flags:t,out:e,keepApplications:t["keep-applications"]}))}async function an(t){await ue(t,e=>Lt({flags:t,out:e}))}var Ct=/^[^\s@]+@[^\s@]+\.[^\s@]+$/,Et=/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9-]{2,63}$/,ht=/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;function Ge({flags:t,out:e,createCf:s}){return mt({gateway:pt(t.gateway),accountId:t["account-id"],interactive:pe(t.json??!1),login:{json:t.json,out:e,step:"login"},createCf:s})}function ft(t){if(t.deploymentMode==="hosted")throw new z("ACCESS_HOSTED",`This Gateway can't be put behind Cloudflare Access
2
+ Hosted Gateways ignore the Access settings.`)}function gt(t,e){let s=e.trim(),n=et(s);if(n===null||n<=0)throw new z("ACCESS_SESSION_INVALID",`${t} ${e} isn't a duration Access takes
3
+ Use hours and minutes, like 720h or 2h30m.`);return s}async function yt(t,e){let s="(u.banned IS NULL OR u.banned = 0 OR (u.ban_expires IS NOT NULL AND u.ban_expires <= ?1))",[n=[],m=[],f=[]]=await t.run([{sql:`SELECT u.email FROM users u WHERE ${s} ORDER BY u.email`,params:[e]},{sql:"SELECT DISTINCT email FROM invitations WHERE status = 'pending' AND expires_at > ?1 ORDER BY email",params:[e]},{sql:`SELECT u.email FROM users u
4
+ WHERE ${s}
5
+ AND EXISTS (SELECT 1 FROM accounts a WHERE a.user_id = u.id AND a.provider_id = 'credential')
6
+ AND NOT EXISTS (SELECT 1 FROM accounts a WHERE a.user_id = u.id AND a.provider_id = 'cloudflare-access')
7
+ ORDER BY u.email`,params:[e]}]),y=g=>[...new Set(g.map(l=>String(l.email).toLowerCase()))];return{members:y(n),invited:y(m),toLink:y(f)}}function vt(t,e){let s=[],n=[],m=[];for(let f of t){let y=f.trim().toLowerCase();if(!Ct.test(y))throw new z("ACCESS_EMAIL_INVALID",`--email ${f} isn't an email address`);s.push(de(y)),n.push(y)}for(let f of e){let y=f.trim().toLowerCase().replace(/^@/,"");if(!Et.test(y))throw new z("ACCESS_DOMAIN_INVALID",`--email-domain ${f} isn't a domain
8
+ Use the part after the @, like example.com.`);s.push(Je(y)),m.push(y)}return{rules:s,emails:n,domains:m}}async function Dt(t){let{out:e}=t,s=t.now??Date.now,n=t.session===void 0?_t:gt("--session",t.session),m=t.teamSession===void 0?null:gt("--team-session",t.teamSession),f=vt(t.emails??[],t.emailDomains??[]),y=t.interactive??pe(t.flags.json??!1);e.emit({type:"step",step:D,status:"start",message:"Checking Cloudflare Access..."});let g=await Ge(t),{cf:l,db:I,install:w}=g;ft(w);let r=me(w),{gatewayHost:_,appBaseDomain:C}=r,b=await yt(I,s()),h=[...b.members.map(de),...b.invited.map(de),...f.rules],c=await Ae(l),$=c?(await $e(l)).find(o=>o.name===x)??null:null;if(h.length===0&&!$)throw new z("ACCESS_NOBODY_ALLOWED",`Nobody to let in yet
9
+ The Gateway has no members or invitations, and no --email was given, so the Access policy would let nobody in. Claim the Gateway first, or name who will (the setup link is then behind Access too).`,{rerun:`${H} access on --email <your address>`});let O=f.emails.filter(o=>!b.members.includes(o)&&!b.invited.includes(o));O.length>0&&e.emit({type:"warning",code:"ACCESS_EMAIL_NOT_INVITED",step:D,message:`${A(O)} ${O.length===1?"has":"have"} no account on this Gateway
10
+ Access will let ${O.length===1,"them"} through, but the Gateway refuses anyone it doesn't know. Invite ${O.length===1,"them"} in Manage workspace \u2192 Users.`,data:{emails:O}});let S=!1,a=null;if(c)m!==null&&c.session_duration!==m&&(e.emit({type:"progress",step:D,message:`Setting the team's global session to ${m}`}),c=await je(l,c,m),a=m);else{let o=w.zoneName.split(".")[0].toLowerCase().replace(/[^a-z0-9-]/g,"")||"every-app",E=t.team;if(E===void 0){if(!y)throw new z("ACCESS_TEAM_REQUIRED",`Choose a name for the Zero Trust team with --team
11
+ This Cloudflare account has none yet. Its sign-in page becomes https://<name>.cloudflareaccess.com and can't be changed later.`,{fix:`add --team ${o}, or another name`,data:{suggested:o}});E=await(t.askTeam??Ot)(o)}if(!ht.test(E))throw new z("ACCESS_TEAM_INVALID",`${t.team===void 0?"":"--team "}${E} can't be a team name
12
+ Use lowercase letters, digits and dashes: it becomes <name>.cloudflareaccess.com.`);e.emit({type:"progress",step:D,message:`Creating the Zero Trust team ${E}.cloudflareaccess.com`});try{c=await We(l,{name:E,auth_domain:`${E}.cloudflareaccess.com`,session_duration:m??n})}catch(B){throw!(B instanceof Fe)||B.kind==="auth"?B:new z("ACCESS_TEAM_CREATE_FAILED",`Cloudflare didn't create the Zero Trust team ${E}
13
+ ${B.message.split(`
14
+ `)[0]}`,{fix:"pick another name with --team: team names are shared across Cloudflare",data:{team:E}})}S=!0,a=m??n}let v=c.auth_domain.toLowerCase(),i=await we(l),d=Ce(i),T=!1,W=!1;d.cloudflare&&(e.emit({type:"progress",step:D,message:"Adding Sign in with Cloudflare (members of this Cloudflare account)"}),i=[...i,await He(l)],T=!0),d.pin&&(e.emit({type:"progress",step:D,message:"Adding the one-time PIN identity provider"}),i=[...i,await Be(l)],W=!0);let ee=De(i),j=i.filter(o=>Qe.includes(o.type));j.length>0&&e.emit({type:"warning",code:"ACCESS_IDP_UNVERIFIED_EMAILS",step:D,message:`${A(j.map(o=>`${o.name??o.id} (${o.type})`))} ${j.length===1?"is a generic provider, left off the Every App applications":"are generic providers, left off the Every App applications"}
15
+ The Gateway signs people in as the email Access asserts. A provider that lets people choose their own address would let them choose someone else's; allow only providers that verify addresses (runbook: "Verified emails").`,data:{providers:j.map(o=>({id:o.id,type:o.type,name:o.name??null}))}}),wt(e,i);let L=g.deployer.email?.toLowerCase()??null;L!==null&&!b.members.includes(L)&&!b.invited.includes(L)&&!f.emails.includes(L)&&e.emit({type:"warning",code:"ACCESS_LOGIN_NOT_MEMBER",step:D,message:`Sign in with Cloudflare signs you in as ${L}, which has no account on this Gateway
16
+ Access asserts your Cloudflare login's address, and the Gateway refuses anyone it doesn't know. Sign in with the code Access emails to your Gateway account's address instead, or invite ${L} in Manage workspace \u2192 Users.`,data:{email:L}});let k,M=!1,P=[];if($){let o=_e($.include??[],h);o.added.length>0?(e.emit({type:"progress",step:D,message:`Adding ${V(o.added.length,"rule")} to the Access policy`}),k=await Ye(l,$,o.include),P=o.added):k=$}else{let o=_e([],h);e.emit({type:"progress",step:D,message:`Creating the Access policy "${x}"`}),k=await Ve(l,{name:x,decision:"allow",include:o.include}),M=!0,P=o.include}let J=await it({db:I,id:ot,purpose:"access.sync",out:e,step:"gateway.lease"}),R,F,X,te,N;try{let o=re(await ie(l),r),E=Y(o.gateway);N=Ie(C,await Pe(I),{managedOAuth:E}),X=o.gateway!==null&&o.apps!==null&&o.gateway.id===o.apps.id;let B=[],fe=U=>{if(!U)return;let ze=K(U.destinations??[],r).foreign;ze.length>0&&B.push({application:U.name??U.id,uris:ze.map(St=>St.uri??"(private)")})},ye={scope:r,policyId:k.id,session:n,sessionGiven:t.session!==void 0,allowedIdps:ee.map(U=>U.id)};if(X){e.emit({type:"warning",code:"ACCESS_ONE_APPLICATION",step:D,message:`One Access application covers ${_} and *.${C}
17
+ It is kept and updated. The runbook recommends two, so an app host's Access cookie is never a Gateway login.`}),fe(o.gateway);let U=await Ne(l,e,o.gateway,{...ye,name:o.gateway.name??ut,destinations:[ce(_,E),...N.destinations],appLauncherVisible:!0});R=U,F=U}else fe(o.apps),fe(o.gateway),R=await Ne(l,e,o.apps,{...ye,name:It,destinations:N.destinations,appLauncherVisible:!1}),F=await Ne(l,e,o.gateway,{...ye,name:ut,destinations:[ce(_,E)],appLauncherVisible:!0});te={dropped:N.dropped,outsideBase:N.outsideBase,foreign:B}}finally{await J.release()}ct(e,te);let he=await oe(l,ae),p=q.filter(o=>!he.includes(o)),G={teamDomain:v,gatewayAud:F.application.aud,appsAud:R.application.aud},Ue=await Te(I),bt=R.outcome==="created"||F.outcome==="created",se=p.length>0?"missing":bt?"created":Ue===null?"unrecorded":Le(Ue,G)?t.writeSettings?"asked":null:"changed";if(se){await Me(g,{CLOUDFLARE_ACCESS_TEAM_DOMAIN:G.teamDomain,CLOUDFLARE_ACCESS_APPS_AUD:G.appsAud,CLOUDFLARE_ACCESS_AUD:G.gatewayAud},{flags:t.flags,out:e});let o=se==="asked"?[]:await At(I,g.deployer,{access:"on",teamDomain:v,...Z(k.include??[]).length>0?{emailDomains:Z(k.include??[])}:{}});await tt(I,{...G,writtenAt:s()},o)}e.emit({type:"step",step:D,status:"ok"}),kt(e,{teamDomain:v,organization:{created:S,sessionSet:a,globalSession:c.session_duration??null},signInMethods:i,allowedMethods:ee,cloudflareAdded:T,pinAdded:W,policy:{id:k.id,name:k.name,created:M,added:[...Q(P),...Z(P).map(o=>`@${o}`)],emails:Q(k.include??[]),domains:Z(k.include??[])},gateway:F,apps:R,combined:X,settings:se?{outcome:"set",reason:se}:{outcome:"kept",reason:null},toLink:b.toLink,emailDomains:f.domains},{gatewayHost:_,base:C,session:n,appsWithRoutes:N.destinations.filter(o=>o.overrides.some(E=>!xe.includes(E.path_pattern))).length,appsWithMcp:N.destinations.filter(o=>o.overrides.some(E=>E.path_pattern==="/mcp")).length})}async function At(t,e,s){let n=await dt(t);return n?rt(t,{organizationId:n.organization.id,type:"access.changed",actor:lt(e),data:s}):[]}function wt(t,e){let s=Ee(e);s.length!==0&&t.emit({type:"warning",code:"ACCESS_IDP_ANY_CLOUDFLARE_ACCOUNT",step:D,message:`${A(s.map(n=>`${n.name??n.id} (${n.type})`))} ${s.length===1?"is":"are"} open to any Cloudflare account, so left off the Every App applications
18
+ Restrict to account members is off, so anyone with a Cloudflare account could sign in there, and Cloudflare doesn't promise the address it asserts is verified: someone who registers a Cloudflare account under a member's address could sign in as that member. Turn Restrict to account members on (Zero Trust \u2192 Settings \u2192 Authentication \u2192 the provider), then run access on again; an application that allowed it before keeps it.`,data:{providers:s.map(n=>({id:n.id,type:n.type,name:n.name??null}))}})}function Ot(t){return st("Zero Trust team name",{initial:t,context:["This Cloudflare account has no Zero Trust team yet. People will sign in at","https://<name>.cloudflareaccess.com; the name can't be changed later."],validate:e=>ht.test(e.trim())?null:"Lowercase letters, digits and dashes only."})}async function Ne(t,e,s,n){if(!s){e.emit({type:"progress",step:D,message:`Creating the Access application "${n.name}"`});let c=Oe(null,n.allowedIdps);return{application:await Ze(t,{name:n.name,type:"self_hosted",destinations:n.destinations,policies:[n.policyId],session_duration:n.session,http_only_cookie_attribute:!0,enable_binding_cookie:!0,...c.allowedIdps.length>0?{allowed_idps:c.allowedIdps}:{},auto_redirect_to_identity:c.autoRedirect,app_launcher_visible:n.appLauncherVisible}),outcome:"created",signInAdded:c.allowedIdps}}let m=s.destinations??[],f=[...K(m,n.scope).foreign,...n.destinations],y=[...s.policies??[]].sort((c,$)=>(c.precedence??0)-($.precedence??0)),g=y.filter(c=>c.reusable===!1);if(g.length>0)return e.emit({type:"warning",code:"ACCESS_INLINE_POLICIES",step:D,message:`The Access application "${s.name??s.id}" has ${g.length===1?"a policy":"policies"} of its own: ${A(g.map(c=>c.name??c.id))}
19
+ It is left as it is: Access takes either application policies or reusable ones, not both, so the policy "${x}" can't be attached and its paths aren't managed here. Make its policies reusable in the dashboard, or manage it there.`,data:{application:s.id,policies:g.map(c=>c.id)}}),{application:s,outcome:"skipped",signInAdded:[]};let l=y.map(c=>c.id),I=l.includes(n.policyId)?l:[...l,n.policyId],w=Y(s)?s.enable_binding_cookie??!1:!0,r=Oe(s,n.allowedIdps),_=r.allowedIdps.filter(c=>!(s.allowed_idps??[]).includes(c)),C={destinations:f,policies:I,http_only_cookie_attribute:!0,enable_binding_cookie:w,allowed_idps:r.allowedIdps,auto_redirect_to_identity:r.autoRedirect,...n.sessionGiven?{session_duration:n.session}:{}};return le(m,f)&&I.join(",")===l.join(",")&&s.http_only_cookie_attribute===!0&&(s.enable_binding_cookie??!1)===w&&ke(s,n.allowedIdps)&&(!n.sessionGiven||s.session_duration===n.session)?{application:s,outcome:"unchanged",signInAdded:[]}:(e.emit({type:"progress",step:D,message:`Updating the Access application "${s.name??n.name}"`}),{application:await Se(t,s.id,be(s,C)),outcome:"updated",signInAdded:_})}function kt(t,e,s){let{gatewayHost:n,base:m}=s,f=[],y=[],g=(d,T)=>{f.push(ne(d,T)),y.push(`${d}${T?` (${T})`:""}.`)},l=d=>{f.push(u.dim(d)),y.push(d)},I=ve(e.allowedMethods);e.organization.created?g(`Zero Trust team ${e.teamDomain}`,`created \xB7 sign-in with ${I}`):e.organization.sessionSet?g(`Zero Trust team ${e.teamDomain}`,`global session now ${e.organization.sessionSet}, for every Access application in the account`):l(`Zero Trust team ${e.teamDomain} \xB7 sign-in with ${I}.`),e.cloudflareAdded&&g("Sign in with Cloudflare","added: members of this Cloudflare account sign in with their Cloudflare account"),e.pinAdded&&g("One-time PIN sign-in","added: Access emails everyone else a code");let{policy:w}=e,r=[...w.emails,...w.domains.map(d=>`@${d}`)];w.created?g(`Access policy "${w.name}"`,`lets in ${A(r)}`):w.added.length>0?g(`Access policy "${w.name}"`,`now also lets in ${A(w.added)}`):l(`Access policy "${w.name}" lets in ${A(r)}.`);let _=s.appsWithRoutes>0?`public routes of ${V(s.appsWithRoutes,"app")} let through${s.appsWithMcp>0?`, /mcp on ${V(s.appsWithMcp,"app host")}`:""}`:s.appsWithMcp>0?`/mcp on ${V(s.appsWithMcp,"app host")} let through`:"no app has public routes or /mcp",C="MCP, the OAuth endpoints and /health let through",b=d=>d.outcome==="updated"&&d.signInAdded.length>0?" \xB7 sign-in methods added":"",h=d=>l(`Access in front of ${d} left as it is (see the warning above).`);if(e.combined){let d=`${n} and *.${m}`;e.gateway.outcome==="skipped"?h(d):e.gateway.outcome==="unchanged"?l(`Access in front of ${d} is as it should be.`):g(`Access in front of ${d}`,`${e.gateway.outcome}${b(e.gateway)} \xB7 ${C} \xB7 ${_}`)}else e.gateway.outcome==="skipped"?h(n):e.gateway.outcome==="unchanged"?l(`Access in front of ${n} is as it should be.`):g(`Access in front of ${n}`,`${e.gateway.outcome}${b(e.gateway)} \xB7 ${C}`),e.apps.outcome==="skipped"?h(`*.${m}`):e.apps.outcome==="unchanged"?l(`Access in front of *.${m} is as it should be (${_}).`):g(`Access in front of *.${m}`,`${e.apps.outcome}${b(e.apps)} \xB7 ${_}`);if(e.settings.outcome==="set"){let d=e.settings.reason==="changed"?" \xB7 an application's AUD tag had changed":e.settings.reason==="unrecorded"?" \xB7 recorded, so a rerun can tell when they go stale":"";g("Gateway settings",`${q.join(", ")} \xB7 one new version${d}`)}else l("Gateway settings kept: they name these applications already (--write-settings writes them again).");let c=e.allowedMethods.every(d=>d.type===Ke),$=e.allowedMethods.length>1,O=$?"Access asks them to sign in first, with their Cloudflare account if they are a member of this Cloudflare account, otherwise with a code emailed to them":c?"Access emails them a code first":"Access asks them to sign in first",S=e.toLink.length>0?`${A(e.toLink)} ${e.toLink.length===1?"signs":"sign"} in once with ${e.toLink.length===1?"their":"their own"} password; ${O}. After that Access alone signs them in.`:null,a=[],v=[];e.emailDomains.length>0&&(a.push(`People at ${A(e.emailDomains)} pass Access, but still need an invitation here, unless they may join on their first sign-in: ${H} secret set CLOUDFLARE_ACCESS_AUTO_JOIN_DOMAINS (${e.emailDomains.join(", ")}).`),v.push({command:`${H} secret set CLOUDFLARE_ACCESS_AUTO_JOIN_DOMAINS`,note:`${e.emailDomains.join(", ")}: people there join as members on their first sign-in`}));let i=e.signInMethods.filter(d=>!e.allowedMethods.includes(d));i.length>0&&a.push(`${A(i.map(d=>`${d.name??d.id} (${d.type})`))} ${i.length===1?"is":"are"} on the team but not allowed on the Every App applications: access on allows only the one-time PIN and a Cloudflare provider restricted to this account's members. Allow another on both applications in the dashboard (Zero Trust \u2192 Access controls \u2192 Applications); access on never takes a method off.`),a.push("MCP clients and personal access tokens keep working: the Gateway's /mcp, the OAuth endpoints, /health and each app's public routes are let through without a login (an app host's /mcp only where its manifest asks for it)."),a.push(`Once everyone has signed in through Access, passwords can go: ${H} secret set EMAIL_PASSWORD_SIGN_IN (false).`),v.push({command:`${H} secret set EMAIL_PASSWORD_SIGN_IN`,note:"false, once everyone has linked Access"}),t.emit({type:"done",message:[...y,...S?[`Sign in at https://${n}: ${S}`]:[],...a].join(" "),display:[...f,"",...Re([{label:"Sign in",value:u.cyan(`https://${n}`)}]),...S?[`${" ".repeat(7+2)}${S}`]:[],...a.map(d=>u.dim(d))].join(`
20
+ `),data:{team:{domain:e.teamDomain,created:e.organization.created,sessionSet:e.organization.sessionSet,globalSession:e.organization.globalSession},signInMethods:e.signInMethods.map(d=>$t(d,e.allowedMethods)),identityProviders:{oneTimePinAdded:e.pinAdded,cloudflareAdded:e.cloudflareAdded},policy:w,applications:{gateway:ge(e.gateway),apps:ge(e.apps),combined:e.combined},settings:{names:[...q],...e.settings},signIn:{url:`https://${n}`,pending:e.toLink,first:$?"both":c?"pin":"idp"},next:v}})}function $t(t,e){return{id:t.id,type:t.type,name:t.name??null,allowed:e.some(s=>s.id===t.id),...t.type===Xe?{restrictToAccountMembers:t.config?.restrict_to_account_members===!0}:{}}}function ge({application:t,outcome:e,signInAdded:s}){return{id:t.id,aud:t.aud,name:t.name??null,outcome:e,destinations:(t.destinations??[]).map(n=>({uri:n.uri??null,public:(n.overrides??[]).map(m=>m.path_pattern)})),allowedIdps:t.allowed_idps??[],signInAdded:s}}async function Tt(t){let{out:e}=t,s=t.interactive??pe(t.flags.json??!1),n=await Ge(t),{cf:m,db:f,install:y}=n;ft(y);let g=me(y),{gatewayHost:l,appBaseDomain:I}=g,w=await oe(m,ae),r=q.filter(i=>w.includes(i)),_=re(await ie(m),g),C=t.keepApplications?[]:[...new Map([_.gateway,_.apps].filter(i=>i!==null).map(i=>[i.id,i])).values()],b=C.filter(i=>K(i.destinations??[],g).foreign.length===0),h=C.filter(i=>!b.includes(i));if(r.length===0&&C.length===0){let i=`Cloudflare Access isn't in front of ${l}. Nothing changed.`;e.emit({type:"done",message:i,display:u.dim(i),data:{removed:!1}});return}let c=i=>i.name??i.id;await at({yes:t.flags.yes,interactive:s,confirm:t.confirm,question:`Turn Cloudflare Access off for ${l}?`,unattended:"Turning Access off needs confirmation at a terminal, or --yes",context:[...r.length>0?[`Removes ${A(r)} from the Gateway: passwords sign people in again at once.`]:[],...b.length>0?[`Deletes ${V(b.length,"Access application")}: ${A(b.map(c))}.`]:[],...h.length>0?[`Takes ${l} and *.${I} out of ${A(h.map(c))}, which also covers something else.`]:[],...t.keepApplications&&(_.gateway||_.apps)?["The Access applications stay: Access still asks people to sign in there."]:[],...b.some(Y)?["The Gateway's application has Managed OAuth on: AI apps connected through it stop."]:[],"The team, its identity providers and the policy stay."],cancelled:"Cancelled. Access stays on."}),e.emit({type:"step",step:"access.off",status:"start",message:"Turning Cloudflare Access off..."}),r.length>0&&await Me(n,Object.fromEntries(r.map(i=>[i,null])),{flags:t.flags,out:e}),await nt(f,await At(f,n.deployer,{access:"off"}));let $=[];for(let i of b)await qe(m,i.id)&&$.push(c(i));let O=[];for(let i of h){let d=K(i.destinations??[],g).foreign;await Se(m,i.id,be(i,{destinations:d})),O.push(c(i))}e.emit({type:"step",step:"access.off",status:"ok"});let S=[],a=[];if(r.length>0&&(S.push(ne("Gateway settings removed",A(r))),a.push(`Removed ${A(r)} from the Gateway.`)),$.length>0&&(S.push(ne(`${V($.length,"Access application")} deleted`,A($))),a.push(`Deleted ${A($)}.`)),O.length>0&&(S.push(ne(`${l} and *.${I} taken out of ${A(O)}`)),a.push(`Took ${l} and *.${I} out of ${A(O)}.`)),t.keepApplications&&(_.gateway||_.apps)){let i="The Access applications stay: Access still asks people to sign in there, and the Gateway no longer requires it.";S.push(u.dim(i)),a.push(i)}let v=`Passwords sign people in as before. The Zero Trust team, its identity providers and the policy "${x}" are left as they were.`;e.emit({type:"done",message:[...a,v].join(" "),display:[...S,u.dim(v)].join(`
21
+ `),data:{removed:!0,settings:r,applications:{deleted:b.filter(i=>$.includes(c(i))).map(i=>i.id),trimmed:h.map(i=>i.id),kept:t.keepApplications??!1}}})}async function Lt(t){let{out:e}=t,s=t.now??Date.now,n=await Ge(t),{cf:m,db:f,install:y}=n,g=me(y),{gatewayHost:l,appBaseDomain:I}=g,w=y.deploymentMode==="hosted",r=w?null:await Ae(m),_=await oe(m,ae),C=q.filter(p=>_.includes(p)),b=w?null:await Te(f),h=r?(await $e(m)).find(p=>p.name===x)??null:null,c=r?await we(m):[],$=De(c),O=$.map(p=>p.id),S=Ce(c),a=r?re(await ie(m),g):{gateway:null,apps:null},v=await yt(f,s()),i=Y(a.gateway),d=Ie(I,await Pe(f),{managedOAuth:i});r&&wt(e,c);let T=C.length===q.length&&a.gateway!==null,W=T&&b&&r&&a.apps?Le(b,{teamDomain:r.auth_domain.toLowerCase(),gatewayAud:a.gateway.aud,appsAud:a.apps.aud}):null,ee=p=>K(p.destinations??[],g).owned,j=a.gateway!==null&&a.gateway.id===a.apps?.id,L=a.apps?le(ee(a.apps).filter(p=>!j||(p.uri??"").toLowerCase()!==l),d.destinations):!1,k=a.gateway?le(ee(a.gateway).filter(p=>(p.uri??"").toLowerCase()===l),[ce(l,i)]):!1,M=p=>p===null?null:ke(p,O),P=p=>p===null||h===null||(p.policies??[]).some(G=>G.id===h.id),J=h?[...v.members,...v.invited].filter(p=>!Q(h.include??[]).includes(p)):[],R=[];!w&&(!T||W===!1||!L||!k||!P(a.gateway)||!P(a.apps)||J.length>0||r!==null&&(S.cloudflare||S.pin)||M(a.gateway)===!1||M(a.apps)===!1)&&R.push(`${H} access on`);let F=[...S.cloudflare?["a Cloudflare account"]:[],...S.pin?["a one-time PIN"]:[]],X=Ee(c),te=c.filter(p=>!$.includes(p)),N=h?[...Q(h.include??[]),...Z(h.include??[]).map(p=>`@${p}`)]:[],he=[{label:"Access",value:w?u.dim("not available on a hosted Gateway"):T?u.green("on"):a.gateway?u.yellow("applications exist, Gateway settings missing"):u.dim("off")},{label:"Team",value:r?`${r.auth_domain}${r.session_duration?u.dim(` \xB7 global session ${r.session_duration}`):""}`:u.dim(w?"":"none in this Cloudflare account")},{label:"Lets in",value:h?`${A(N)}${J.length>0?u.yellow(` \xB7 not yet: ${A(J)}`):""}${u.dim(` (policy "${h.name}")`)}`:u.dim(`no policy "${x}" yet`)},...r?[{label:"Sign in",value:`${$.length>0?`with ${ve($)}`:u.dim("no sign-in method yet")}${F.length>0?u.yellow(` \xB7 access on adds ${A(F)}`):""}${X.length>0?u.yellow(" \xB7 open to any Cloudflare account (see the warning)"):""}${te.length>0?u.dim(` \xB7 on the team, not allowed here: ${A(te.map(p=>p.name??p.id))}`):""}`}]:[],{label:l,value:a.gateway?`${a.gateway.name??a.gateway.id} \xB7 ${k?"paths as they should be":u.yellow("paths differ")}${M(a.gateway)===!1?u.yellow(" \xB7 sign-in methods differ"):""}${Y(a.gateway)?" \xB7 Managed OAuth":""}${P(a.gateway)?"":u.yellow(" \xB7 policy not attached")}`:u.dim("no Access application")},{label:`*.${I}`,value:a.apps?`${a.apps.name??a.apps.id} \xB7 ${L?"public routes as they should be":u.yellow("public routes differ")}${M(a.apps)===!1?u.yellow(" \xB7 sign-in methods differ"):""}${P(a.apps)?"":u.yellow(" \xB7 policy not attached")}`:u.dim("no Access application")},{label:"Settings",value:C.length>0?`${A(C)}${W===!1?u.yellow(" \xB7 name an application that no longer exists: nobody can sign in"):W===!0?u.dim(" \xB7 name the applications above"):u.dim(" (values can't be read back)")}`:u.dim("none")},...v.toLink.length>0&&T?[{label:"To link",value:`${A(v.toLink)} (sign in once with the password through Access)`}]:[]];e.emit({type:"done",message:`Cloudflare Access is ${T?"on":"off"} for ${l}.`,display:[...Re(he),...R.length>0?["",u.dim("To fix: ")+u.bold(R.join(", "))]:[]].join(`
22
+ `),data:{on:T,hosted:w,team:r?{domain:r.auth_domain,sessionDuration:r.session_duration??null}:null,policy:h?{id:h.id,name:h.name,emails:Q(h.include??[]),domains:Z(h.include??[]),notYet:J}:null,signIn:r?{methods:c.map(p=>$t(p,$)),cloudflare:!S.cloudflare,pin:!S.pin,openToAnyCloudflareAccount:X.map(p=>p.id)}:null,applications:{gateway:a.gateway?{...ge({application:a.gateway,outcome:"unchanged",signInAdded:[]}),inSync:k,signInInSync:M(a.gateway),managedOAuth:Y(a.gateway),policyAttached:P(a.gateway)}:null,apps:a.apps?{...ge({application:a.apps,outcome:"unchanged",signInAdded:[]}),inSync:L,signInInSync:M(a.apps),policyAttached:P(a.apps)}:null,combined:j},desired:{apps:d.destinations.map(p=>({uri:p.uri,public:p.overrides.map(G=>G.path_pattern)}))},settings:{names:C,current:W},linkPending:v.toLink,...R.length>0?{fixes:R}:{}}})}export{x as a,ut as b,It as c,nn as d,sn as e,an as f,Dt as g,Tt as h,Lt as i};
@@ -0,0 +1,2 @@
1
+ import o from"node:fs/promises";import t from"node:path";var i=["No cloudflare.config.ts in this app","Every App apps build their Worker in a cloudflare.config.ts at the app root:","",' import { defineConfig } from "cf/config";',' import { everyAppWorker } from "@every-app/sdk/cloudflare";',' import * as entrypoint from "./src/entry.worker.ts" with { type: "cf-worker" };',' import manifest from "./everyapp.config.ts";',""," export default defineConfig((ctx) => ({"," worker: everyAppWorker({ manifest, entrypoint, ctx }),"," }));","","starter/ has the full setup (package.json, vite.config.ts)."].join(`
2
+ `);async function s(e){try{let r=await o.readFile(t.join(e,"cloudflare.config.ts"),"utf8");return{usesEveryAppWorker:r.includes("everyAppWorker"),hasCrons:/\bcrons\s*:/.test(r)}}catch{return null}}export{i as a,s as b};
@@ -0,0 +1,4 @@
1
+ import{d as L}from"./chunk-M2QQ2UD7.js";import{A as x,E as T,O as y,P as h,Q as O,R as F,qa as k,sa as z,w as I}from"./chunk-RMF4YGD6.js";import{a as D}from"./chunk-CCWBPAKH.js";import{c as v,f as A,pc as C}from"./chunk-LYNBZ7RV.js";import u from"chalk";import f from"chalk";async function E(t){let{flags:e,out:l,createCf:i}=t,r=await z({gateway:k(e.gateway),accountId:e["account-id"],interactive:D(e.json??!1),login:{json:e.json,out:l,step:"login"},createCf:i});await x(r.db);let o=await L(r.db,e.org);return{gateway:r,organization:o}}function $(t){return t===null?f.dim("never"):new Date(t).toISOString().slice(0,16).replace("T"," ")}var d=t=>t===null?null:new Date(t).toISOString();function R(t){return t.sink==="email"?t.recipients==="owners"?"email \u2192 owners":"email \u2192 owners and admins":t.url?I(t.url):"(no URL)"}function B(t){return t.includes("*")?"everything":t.join(", ")}function X(t){return{id:t.id,name:t.name,sink:t.sink,target:R(t),recipients:t.recipients,events:t.events,enabled:t.enabled,builtin:t.builtin,createdAt:d(t.createdAt),createdBy:t.createdBy,lastDeliveryAt:d(t.lastDeliveryAt),lastDeliveryStatus:t.lastDeliveryStatus,consecutiveFailures:t.consecutiveFailures}}var H=t=>`${t.name} (${t.id})`;function N(t,e){let l=y(t,e),i=t.lastStatusCode!==null&&t.lastStatusCode>0?t.lastStatusCode:null,r=i===null?"":t.sink==="email"?`, ${i} mailed`:` ${i}`;switch(l){case"delivered":return f.green(`delivered${r}`);case"dead":return f.red("dead");case"failed":return f.yellow(`failed${r}, retrying`);default:return f.dim(t.attempts>0?"sending":"queued")}}function b(t,e){return{id:t.id,eventId:t.eventId,type:t.type,subscriptionId:t.subscriptionId,subscriptionName:t.subscriptionName,sink:t.sink,status:t.status,state:y(t,e),attempts:t.attempts,lastStatusCode:t.lastStatusCode,lastError:t.lastError,nextAttemptAt:d(t.nextAttemptAt),lastAttemptAt:d(t.lastAttemptAt),deliveredAt:d(t.deliveredAt),redeliveredAt:d(t.redeliveredAt),createdAt:d(t.createdAt)}}var S=t=>({id:t.id,name:t.name,slug:t.slug});var j=20;function et(t){let e=Number(t);if(!Number.isInteger(e)||e<1||e>h)throw new Error(`Use a whole number from 1 to ${h}.`);return e}var G=t=>{let e=t.lastError?.split(`
2
+ `)[0];return e?u.dim(e.length>60?`${e.slice(0,59)}\u2026`:e):""};async function nt(t,e){let{out:l,flags:i}=t,{gateway:r,organization:o}=await E(t),c=t.now?.()??Date.now(),n=e?await T(r.db,o,e):null,s=await O(r.db,{organizationId:o.id,...n?{subscriptionId:n.id}:{},dead:i.dead??!1,limit:i.limit??j,now:c}),m=n?` to ${n.name}`:"",p=i.dead?"dead ":"",g=s.length===0?`No ${p}deliveries${m} in the last 30 days`:s.length===1?`The last ${p}delivery${m}`:`The last ${s.length} ${p}deliveries${m}`,w=s.filter(a=>a.status==="dead");l.emit({type:"done",message:g,display:[...s.length===0?[u.dim(`${g}.`)]:[...C(["WHEN","DELIVERY","EVENT","TO","STATUS","TRIES","NEXT","LAST ERROR"],s.map(a=>[$(a.createdAt),a.id,a.type??u.dim("(expired)"),a.subscriptionName??u.dim(a.subscriptionId),N(a,c),String(a.attempts),a.status==="pending"&&a.nextAttemptAt!==null?$(a.nextAttemptAt):"",G(a)])),...w.length>0?["",u.dim(`Send a dead one again: ${v} events redeliver <delivery>`)]:[]]].join(`
3
+ `),data:{organization:S(o),subscriptionId:n?.id??null,dead:i.dead??!1,deliveries:s.map(a=>b(a,c))}})}async function at(t,e){let{out:l}=t,{gateway:i,organization:r}=await E(t),o=t.now?.()??Date.now(),{delivery:c,previous:n,outcome:s}=await F(i.db,r,e,o),m=`${n.type??"the event"} to ${n.subscriptionName??n.subscriptionId}`,p=n.status==="dead"?`it was dead after ${A(n.attempts,"attempt")}`:`it was ${n.attempts>0?"failing":"queued"}`,g=s==="attempting"?`${n.id} is being sent right now. Nothing changed.`:s==="delivered"?`${n.id} was already delivered (${m}). Nothing changed.`:`Queued ${n.id} again (${m}; ${p}).`,w=s==="queued"?"The Gateway sends it within a minute, with the full retry schedule.":`See how it went: ${v} events deliveries ${n.subscriptionId}`;l.emit({type:"done",message:`${g} ${w}`,display:[g,u.dim(w)].join(`
4
+ `),data:{outcome:s,delivery:b(c,o),previousStatus:n.status,organization:S(r)}})}export{E as a,$ as b,R as c,B as d,X as e,H as f,b as g,S as h,et as i,nt as j,at as k};
@@ -0,0 +1,4 @@
1
+ import{Bb as g,Db as m,Lb as d}from"./chunk-LYNBZ7RV.js";import{confirm as f,input as u,password as h,select as y}from"@inquirer/prompts";import t from"chalk";function A(e){return!!(process.stdin.isTTY&&process.stderr.isTTY)&&!e&&!process.env.CI}var a={prefix:{idle:t.cyan("?"),done:t.green("\u2714")},style:{message:(e,r)=>r==="done"?`${e} ${t.dim("\xB7")}`:t.bold(e),answer:e=>t.cyan(e),defaultAnswer:e=>t.dim(`(${e})`),highlight:e=>t.cyan(e),help:e=>t.dim(e),error:e=>t.red(`> ${e}`),description:e=>t.dim(e),keysHelpTip:()=>{}}};async function l({context:e=[]},r){d(),e.length>0&&process.stderr.write(`${e.map(n=>t.dim(n)).join(`
2
+ `)}
3
+ `);try{return await r({output:process.stderr})}catch(n){throw n instanceof Error&&n.name==="ExitPromptError"?new m:n}}var T=(e,r)=>l({context:r},n=>f({message:e,default:!1,theme:a},n)),C=(e,r)=>l({context:r},n=>f({message:e,default:!0,theme:a},n));async function w(e,r,{context:n,cancelled:s}={}){if(!await e(r,n))throw new m(s)}function P(e,r,n={}){let s=Math.max(...r.map(i=>i.label.length));return l(n,i=>y({message:e,choices:r.map(o=>({name:o.hint?`${o.label.padEnd(s)} ${t.dim(o.hint)}`:o.label,short:o.label,value:o.value})),theme:a},i))}function E(e,r={}){let{validate:n}=r;return l(r,s=>u({message:e,...r.initial?{default:r.initial}:{},...n?{validate:i=>n(i)??!0}:{},theme:a},s))}function $(e,r={}){let n="";return l(r,s=>h({message:e,mask:!1,toggleMask:!1,validate:i=>(n=i,i.trim()||r.optional?!0:"Enter a value."),theme:{...a,style:{...a.style,maskedText:"(hidden)",answer:()=>n.trim()?t.dim("\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"):t.dim("skipped")}}},s))}function I(e){d(),process.stderr.write(`${e}
4
+ `)}async function R({yes:e,interactive:r,confirm:n=T,question:s,unattended:i,context:o,cancelled:p,data:c}){if(!e){if(!r)throw new g("CONFIRMATION_REQUIRED",i,c?{data:c}:{});await w(n,s,{context:o,cancelled:p})}}export{A as a,T as b,C as c,w as d,P as e,E as f,$ as g,I as h,R as i};