deployai 0.1.0-beta.1 → 0.1.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -7
- package/dist/index.js +196 -56
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,12 +41,12 @@ Node 20 or newer. No other setup: the CLI talks to https://deployai.co.il.
|
|
|
41
41
|
| `deployai init` | Creates `DEPLOYAI.md` (rules for the AI agent) and `.deployai/project.json`. Never edits your code and does not link a project (use `link`). `--force` overwrites `DEPLOYAI.md`. |
|
|
42
42
|
| `deployai inspect` | Shows framework, package manager, language, database, storage and the number of env files (values are never read). `--json` for machine output. |
|
|
43
43
|
| `deployai check` | Lists blockers and warnings with file and line. It answers only whether the project can run on DeployAI. More below. |
|
|
44
|
-
| `deployai login` | Logs in through the browser (device code). The token is stored in `~/.deployai/config.json
|
|
45
|
-
| `deployai logout` |
|
|
44
|
+
| `deployai login` | Logs in through the browser (device code). The token lasts 30 days and is stored in `~/.deployai/config.json` with the API address that issued it; it is never sent to another address. |
|
|
45
|
+
| `deployai logout` | Cancels the token on DeployAI and removes it from this computer. |
|
|
46
46
|
| `deployai whoami` | Shows the logged in user. |
|
|
47
|
-
| `deployai link [project]` | Links this folder to a project (slug, id or name). `--create "<name>"` makes a new project. |
|
|
47
|
+
| `deployai link [project]` | Links this folder to a project (slug, id or name). `--create "<name>"` makes a new project. With no name it never links on its own: in a terminal it asks first, an agent gets the exact `link <slug>` command. |
|
|
48
48
|
| `deployai deploy -m "<message>"` | Runs the check, packs the source and uploads it. Prints the version, the queue position and the preview address. |
|
|
49
|
-
| `deployai versions` | Lists versions: number, live or not, status, date, size, message. |
|
|
49
|
+
| `deployai versions` | Lists versions: number, live or not, status ("replaced by a newer upload" for one that never built), date, size, message, and a dashboard link when its SQL waits for approval. |
|
|
50
50
|
| `deployai rollback v5` | Puts version 5 back live, with no rebuild. |
|
|
51
51
|
| `deployai promote v5` | Puts version 5 live. |
|
|
52
52
|
| `deployai status` | Site state, address, live version and queue. |
|
|
@@ -78,6 +78,7 @@ Global options:
|
|
|
78
78
|
**`deployai deploy --guest`**
|
|
79
79
|
- No login needed: puts the site live as a temporary site with a claim link, deleted after the days DeployAI sets unless you claim it.
|
|
80
80
|
- A temporary site may have a small database, but no file storage or environment variables.
|
|
81
|
+
- A folder linked to a site in an account refuses: run `login`, then `deploy`.
|
|
81
82
|
- For a database sample it prints the site's owner keys once ("shown once, save them now"). They are never stored, so save them right away.
|
|
82
83
|
|
|
83
84
|
**`deployai samples [name] [folder]`**
|
|
@@ -111,9 +112,11 @@ The default is `https://deployai.co.il`. The order is: `--api <url>`, then env `
|
|
|
111
112
|
The source folder, packed as a `.tar.gz`. The upload is capped at 50 MB.
|
|
112
113
|
|
|
113
114
|
Never uploaded:
|
|
114
|
-
- `node_modules`, `.git`,
|
|
115
|
+
- `node_modules`, `.git`, and tool caches like `.next`, `.astro`, `.svelte-kit`, `.wrangler`
|
|
116
|
+
- `dist`, `build`, `out` at the project root when `package.json` has a build script (DeployAI builds them again). Folders like `assets/build/` are uploaded.
|
|
117
|
+
- `.deployai/`, `DEPLOYAI.md`, `CLAUDE.md`, `AGENTS.md`, `.claude/`, `.cursor/`, `.vscode/` and other dotfiles (except `.well-known/` and build config like `.babelrc`). DeployAI never serves these either, however they arrive.
|
|
115
118
|
- Any `.env*` file
|
|
116
|
-
- Anything
|
|
119
|
+
- Anything in the root `.gitignore` or in `.deployaiignore` (gitignore style, read last, so `!file` brings a file back)
|
|
117
120
|
- Files over 10 MB
|
|
118
121
|
|
|
119
122
|
## Telemetry
|
|
@@ -143,4 +146,4 @@ pnpm --filter ./packages/cli start -- check
|
|
|
143
146
|
- `@deployai/shared` and `zod` are bundled into `dist/index.js` by tsup, so the published package depends only on `commander`.
|
|
144
147
|
- The package ships only `dist` and this README (check with `npm pack --dry-run`).
|
|
145
148
|
- Publish from this folder with `pnpm publish`: `prepublishOnly` builds and runs the tests first.
|
|
146
|
-
-
|
|
149
|
+
- On npm as `deployai`: run it with `npx deployai@latest <command>`.
|
package/dist/index.js
CHANGED
|
@@ -20910,18 +20910,23 @@ var DeployResponse = external_exports.object({
|
|
|
20910
20910
|
versionId: external_exports.string(),
|
|
20911
20911
|
number: external_exports.number(),
|
|
20912
20912
|
queuePosition: external_exports.number(),
|
|
20913
|
-
previewUrl: external_exports.string()
|
|
20913
|
+
previewUrl: external_exports.string(),
|
|
20914
|
+
/** Only for a heavy home page (D-420): the files it loads from the site and whether it prefetches links. */
|
|
20915
|
+
page: external_exports.object({ files: external_exports.number(), prefetches: external_exports.boolean() }).optional()
|
|
20914
20916
|
});
|
|
20917
|
+
var VersionStatus = external_exports.enum(["queued", "building", "ready", "failed", "replaced"]);
|
|
20918
|
+
var MigrationStatus = external_exports.enum(["waiting", "queued", "running", "done", "failed"]);
|
|
20915
20919
|
var Version = external_exports.object({
|
|
20916
20920
|
id: external_exports.string(),
|
|
20917
20921
|
number: external_exports.number(),
|
|
20918
20922
|
message: external_exports.string(),
|
|
20919
|
-
status:
|
|
20923
|
+
status: VersionStatus,
|
|
20920
20924
|
isLive: external_exports.boolean(),
|
|
20921
20925
|
createdAt: external_exports.string(),
|
|
20922
20926
|
sizeBytes: external_exports.number(),
|
|
20923
20927
|
/** Why the build failed, in words the customer's AI can act on. Null unless status is failed. */
|
|
20924
|
-
error: external_exports.string().nullable().optional()
|
|
20928
|
+
error: external_exports.string().nullable().optional(),
|
|
20929
|
+
migrationStatus: MigrationStatus.nullable().optional()
|
|
20925
20930
|
});
|
|
20926
20931
|
var VersionsResponse = external_exports.object({ versions: external_exports.array(Version) });
|
|
20927
20932
|
var EnvSetRequest = external_exports.object({ projectId: external_exports.string(), key: external_exports.string(), value: external_exports.string(), secret: external_exports.boolean().default(true) });
|
|
@@ -20934,13 +20939,15 @@ var StatusResponse = external_exports.object({
|
|
|
20934
20939
|
project: Project,
|
|
20935
20940
|
queue: external_exports.object({ position: external_exports.number(), running: external_exports.boolean() }),
|
|
20936
20941
|
/** The newest version, with the error and the end of the build log when it failed. */
|
|
20937
|
-
latest: external_exports.object({ number: external_exports.number(), status:
|
|
20942
|
+
latest: external_exports.object({ number: external_exports.number(), status: VersionStatus, error: external_exports.string().nullable(), logTail: external_exports.string().nullable(), migrationStatus: MigrationStatus.nullable().optional() }).nullable().optional()
|
|
20938
20943
|
});
|
|
20939
20944
|
var ApiError = external_exports.object({
|
|
20940
20945
|
error: external_exports.string(),
|
|
20941
20946
|
messageHe: external_exports.string().optional(),
|
|
20942
20947
|
/** Where to buy what the call needs (D-206). */
|
|
20943
|
-
buyUrl: external_exports.string().optional()
|
|
20948
|
+
buyUrl: external_exports.string().optional(),
|
|
20949
|
+
/** The dashboard page that resolves the refusal, for example the SQL to approve. */
|
|
20950
|
+
url: external_exports.string().optional()
|
|
20944
20951
|
});
|
|
20945
20952
|
var AddonRunStatus = external_exports.enum(["todo", "served", "done", "failed", "skipped"]);
|
|
20946
20953
|
var AddonItem = external_exports.object({
|
|
@@ -21127,17 +21134,17 @@ var ARCH_NODES = [
|
|
|
21127
21134
|
{ id: "postgres", kind: "db", zone: "platform", label: "Postgres", summary: "\u05DE\u05E1\u05D3 \u05D4\u05E0\u05EA\u05D5\u05E0\u05D9\u05DD \u05E9\u05DC\u05E0\u05D5: \u05DE\u05E9\u05EA\u05DE\u05E9\u05D9\u05DD, \u05D0\u05EA\u05E8\u05D9\u05DD, \u05D2\u05E8\u05E1\u05D0\u05D5\u05EA, \u05EA\u05E9\u05DC\u05D5\u05DE\u05D9\u05DD, \u05D1\u05D9\u05E7\u05D5\u05E8\u05D9\u05DD \u05D5\u05D9\u05D5\u05DE\u05DF. \u05D1\u05D9\u05D9\u05E6\u05D5\u05E8 \u05D2\u05D9\u05D1\u05D5\u05D9 pg_dump \u05DC\u05D9\u05DC\u05D9 \u05DC\u05D3\u05DC\u05D9 R2 \u05E0\u05E4\u05E8\u05D3 (14 \u05D9\u05D5\u05DE\u05D9\u05D9\u05DD, 4 \u05E9\u05D1\u05D5\u05E2\u05D9\u05D9\u05DD), \u05DE\u05D5\u05E6\u05E4\u05DF \u05D1\u05BEage, \u05D5\u05DE\u05D2\u05D1\u05D9\u05DD \u05D2\u05DD \u05D9\u05D3\u05E0\u05D9\u05EA \u05DE\u05D0\u05D3\u05DE\u05D9\u05DF, \u05E9\u05E8\u05EA, \u05D2\u05D9\u05D1\u05D5\u05D9\u05D9\u05DD.", summaryEn: "Our database: users, sites, versions, payments, visits and the audit log. In production a nightly pg_dump goes to its own R2 bucket (14 daily, 4 weekly), encrypted with age, plus manual copies from Admin, Server, Backups.", code: ["apps/web/src/server/db/schema.ts", "scripts/backup-db.sh", "apps/web/src/server/backups.ts"], env: ["DATABASE_URL", "BACKUP_S3_ACCESS_KEY_ID", "BACKUP_S3_SECRET_ACCESS_KEY", "BACKUP_AGE_RECIPIENT"], portability: "Our database", docs: ["docs/04-architecture.md", "docs/22-go-live.md", "docs/23-server.md"], decisions: ["D-336", "D-340"] },
|
|
21128
21135
|
{ id: "files", kind: "storage", zone: "platform", label: "Version files", summary: "\u05D0\u05E8\u05DB\u05D9\u05D5\u05E0\u05D9 \u05DE\u05E7\u05D5\u05E8 \u05D5\u05EA\u05D5\u05E6\u05E8\u05D9 \u05D1\u05E0\u05D9\u05D9\u05D4 \u05E9\u05DC \u05DB\u05DC \u05D2\u05E8\u05E1\u05D4, \u05D3\u05E8\u05DA storage.ts \u05D1\u05DC\u05D1\u05D3. \u05D3\u05DC\u05D9 R2 \u05DC\u05DB\u05DC \u05E1\u05D1\u05D9\u05D1\u05D4, \u05D5\u05E0\u05D9\u05E7\u05D5\u05D9 \u05DC\u05D9\u05DC\u05D9 \u05E9\u05DC \u05E7\u05D1\u05E6\u05D9\u05DD \u05E9\u05D0\u05E3 \u05D2\u05E8\u05E1\u05D4 \u05DC\u05D0 \u05DE\u05E9\u05EA\u05DE\u05E9\u05EA \u05D1\u05D4\u05DD.", summaryEn: "Source archives and build output of every version, through storage.ts only. One R2 bucket per place, and a nightly sweep of files no version uses.", code: ["apps/web/src/server/storage.ts", "apps/web/src/server/storage-sweep.ts"], env: ["STORAGE_DIR", "S3_ACCESS_KEY_ID", "S3_SECRET_ACCESS_KEY"], portability: "Version files (uploads and build output)", docs: ["docs/17-portability.md"], decisions: ["D-095", "D-096", "D-316"] },
|
|
21129
21136
|
// Services
|
|
21130
|
-
{ id: "email-sending", kind: "external", zone: "services", label: "CF Email Sending", summary: "\u05E9\u05DC\u05D9\u05D7\u05EA \u05DE\u05D9\u05D9\u05DC\u05D9\u05DD \u05D3\u05E8\u05DA Cloudflare Email Sending. \u05D1\u05DC\u05D9 \u05D8\u05D5\u05E7\u05DF \u05D4\u05DE\u05D9\u05D9\u05DC \u05DE\u05D5\u05D3\u05E4\u05E1 \u05D1\u05DC\u05D5\u05D2.", summaryEn: "Sends email through Cloudflare Email Sending. Without a token, the email is printed to the log.", code: ["apps/web/src/server/email.ts"],
|
|
21137
|
+
{ id: "email-sending", kind: "external", zone: "services", label: "CF Email Sending", summary: "\u05E9\u05DC\u05D9\u05D7\u05EA \u05DE\u05D9\u05D9\u05DC\u05D9\u05DD \u05D3\u05E8\u05DA Cloudflare Email Sending. \u05D1\u05DC\u05D9 \u05D8\u05D5\u05E7\u05DF \u05D4\u05DE\u05D9\u05D9\u05DC \u05DE\u05D5\u05D3\u05E4\u05E1 \u05D1\u05DC\u05D5\u05D2.", summaryEn: "Sends email through Cloudflare Email Sending. Without a token, the email is printed to the log.", code: ["apps/web/src/server/email.ts"], portability: "Emails" },
|
|
21131
21138
|
{ id: "oauth", kind: "external", zone: "services", label: "Google / GitHub OAuth", summary: "\u05D4\u05EA\u05D7\u05D1\u05E8\u05D5\u05EA \u05E2\u05DD Google \u05D0\u05D5 GitHub \u05D3\u05E8\u05DA Better Auth.", summaryEn: "Log in with Google or GitHub through Better Auth.", code: ["apps/web/src/server/auth.ts"], env: ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET"], decisions: ["D-020"] },
|
|
21132
|
-
{ id: "payments", kind: "external", zone: "services", label: "Payment provider (Cardcom)", summary: "\u05E7\u05D0\u05E8\u05D3\u05E7\u05D5\u05DD \u05DB\u05D1\u05E8\u05D9\u05E8\u05EA \u05DE\u05D7\u05D3\u05DC, \u05D5\u05E0\u05D1\u05D7\u05E8 \u05D1\u05D4\u05D2\u05D3\u05E8\u05D5\u05EA \u05D4\u05D0\u05D3\u05DE\u05D9\u05DF (\u05D0\u05D5 \u05DE\u05D3\u05D5\u05DE\u05D4 \u05DC\u05D1\u05D3\u05D9\u05E7\u05D5\u05EA). \u05D4\u05DB\u05E8\u05D8\u05D9\u05E1 \u05DE\u05D5\u05E7\u05DC\u05D3 \u05D1\u05D3\u05E3 \u05D4\u05DE\u05D0\u05D5\u05D1\u05D8\u05D7 \u05E9\u05DC \u05E7\u05D0\u05E8\u05D3\u05E7\u05D5\u05DD \u05D5\u05E0\u05E9\u05DE\u05E8 \u05DB\u05D8\u05D5\u05E7\u05DF \u05DE\u05D5\u05E6\u05E4\u05DF, \u05DB\u05DC \u05D7\u05D9\u05D5\u05D1 \u05E2\u05DD \u05DE\u05E4\u05EA\u05D7 \u05D0\u05D9\u05D3\u05DE\u05E4\u05D5\u05D8\u05E0\u05D8\u05D9\u05D5\u05EA, \u05D5\u05E7\u05D0\u05E8\u05D3\u05E7\u05D5\u05DD \u05DE\u05E4\u05D9\u05E7\u05D4 \u05D7\u05E9\u05D1\u05D5\u05E0\u05D9\u05EA \u05DE\u05E1 \u05DC\u05DB\u05DC \u05D7\u05D9\u05D5\u05D1 \u05D5\u05D7\u05E9\u05D1\u05D5\u05E0\u05D9\u05EA \u05D6\u05D9\u05DB\u05D5\u05D9 \u05DC\u05DB\u05DC \u05D4\u05D7\u05D6\u05E8.", summaryEn: "Cardcom by default, chosen in admin settings (or simulated for tests). The card is typed on the secure Cardcom page and saved as a sealed token, every charge carries an idempotency key, and Cardcom issues a tax invoice per charge and a credit invoice per refund.", code: ["apps/web/src/server/billing/provider.ts", "apps/web/src/server/billing/cardcom.ts", "apps/web/src/server/billing/card-pages.ts", "apps/web/src/app/api/billing/card"], env: ["BILLING_PROVIDER", "BILLING_MOCK_FAIL", "CARDCOM_TERMINAL", "CARDCOM_API_NAME", "CARDCOM_API_PASSWORD", "CARDCOM_INVOICES", "CARDCOM_CSS_URL", "CARDCOM_TOKEN_KEY"], portability: "Payments", decisions: ["D-175", "D-292"] },
|
|
21133
|
-
{ id: "registrar", kind: "external", zone: "services", label: "Domain
|
|
21134
|
-
{ id: "mcp", kind: "external", zone: "services", label: "MCP for AI tools (/api/mcp)", summary: "ChatGPT \u05D5-Claude \u05DE\u05EA\u05D7\u05D1\u05E8\u05D9\u05DD \u05D1\u05DC\u05D9 \u05D8\u05E8\u05DE\u05D9\u05E0\u05DC: OAuth \u05E2\u05DD \u05D0\u05D9\u05E9\u05D5\u05E8 \u05D1\u05D3\u05E4\u05D3\u05E4\u05DF, \u05D5\u05D0\u05D6 \u05DB\u05DC\u05D9\u05DD \u05DC\u05E8\u05E9\u05D9\u05DE\u05EA \u05D4\u05D0\u05EA\u05E8\u05D9\u05DD, \u05D1\u05D3\u05D9\u05E7\u05D4, \u05D4\u05E2\u05DC\u05D0\u05EA \u05D2\u05E8\u05E1\u05D4 \u05DC\u05EA\u05E6\u05D5\u05D2\u05D4 \u05DE\u05E7\u05D3\u05D9\u05DE\u05D4, \u05D5\u05D4\u05E2\u05DC\u05D0\u05D4 \u05DC\u05D0\u05D5\u05D5\u05D9\u05E8 \u05E8\u05E7 \u05E2\u05DD \u05D4\u05E8\u05E9\u05D0\u05D4 \u05D5\u05D0\u05D9\u05E9\u05D5\u05E8.", summaryEn: "ChatGPT and Claude connect without a terminal: OAuth with a browser consent, then tools to list sites, check, upload a version to a preview, and go live only with the permission and a yes.", code: ["apps/web/src/app/api/mcp/route.ts", "apps/web/src/server/mcp-tools.ts", "apps/web/src/server/auth.ts"], decisions: ["D-302"] },
|
|
21139
|
+
{ id: "payments", kind: "external", zone: "services", label: "Payment provider (Cardcom)", summary: "\u05E7\u05D0\u05E8\u05D3\u05E7\u05D5\u05DD \u05DB\u05D1\u05E8\u05D9\u05E8\u05EA \u05DE\u05D7\u05D3\u05DC, \u05D5\u05E0\u05D1\u05D7\u05E8 \u05D1\u05D4\u05D2\u05D3\u05E8\u05D5\u05EA \u05D4\u05D0\u05D3\u05DE\u05D9\u05DF (\u05D0\u05D5 \u05DE\u05D3\u05D5\u05DE\u05D4 \u05DC\u05D1\u05D3\u05D9\u05E7\u05D5\u05EA). \u05D4\u05DB\u05E8\u05D8\u05D9\u05E1 \u05DE\u05D5\u05E7\u05DC\u05D3 \u05D1\u05D3\u05E3 \u05D4\u05DE\u05D0\u05D5\u05D1\u05D8\u05D7 \u05E9\u05DC \u05E7\u05D0\u05E8\u05D3\u05E7\u05D5\u05DD \u05D5\u05E0\u05E9\u05DE\u05E8 \u05DB\u05D8\u05D5\u05E7\u05DF \u05DE\u05D5\u05E6\u05E4\u05DF, \u05DB\u05DC \u05D7\u05D9\u05D5\u05D1 \u05E2\u05DD \u05DE\u05E4\u05EA\u05D7 \u05D0\u05D9\u05D3\u05DE\u05E4\u05D5\u05D8\u05E0\u05D8\u05D9\u05D5\u05EA, \u05D5\u05E7\u05D0\u05E8\u05D3\u05E7\u05D5\u05DD \u05DE\u05E4\u05D9\u05E7\u05D4 \u05D7\u05E9\u05D1\u05D5\u05E0\u05D9\u05EA \u05DE\u05E1 \u05DC\u05DB\u05DC \u05D7\u05D9\u05D5\u05D1 \u05D5\u05D7\u05E9\u05D1\u05D5\u05E0\u05D9\u05EA \u05D6\u05D9\u05DB\u05D5\u05D9 \u05DC\u05DB\u05DC \u05D4\u05D7\u05D6\u05E8.", summaryEn: "Cardcom by default, chosen in admin settings (or simulated for tests). The card is typed on the secure Cardcom page and saved as a sealed token, every charge carries an idempotency key, and Cardcom issues a tax invoice per charge and a credit invoice per refund.", code: ["apps/web/src/server/billing/provider.ts", "apps/web/src/server/billing/cardcom.ts", "apps/web/src/server/billing/card-pages.ts", "apps/web/src/app/api/billing/card"], env: ["BILLING_PROVIDER", "BILLING_MOCK_FAIL", "CARDCOM_TERMINAL", "CARDCOM_API_NAME", "CARDCOM_API_PASSWORD", "CARDCOM_INVOICES", "CARDCOM_CSS_URL", "CARDCOM_TOKEN_KEY", "CARDCOM_DEPARTMENT_ID"], portability: "Payments", decisions: ["D-175", "D-292"] },
|
|
21140
|
+
{ id: "registrar", kind: "external", zone: "services", label: "Domain registrars (Cloudflare, LiveDNS)", summary: "\u05E7\u05E0\u05D9\u05D9\u05EA \u05D3\u05D5\u05DE\u05D9\u05D9\u05E0\u05D9\u05DD \u05DC\u05D0\u05EA\u05E8: \u05DB\u05DC \u05E9\u05DD \u05D4\u05D5\u05DC\u05DA \u05DC\u05E8\u05E9\u05DD \u05D4\u05D6\u05D5\u05DC \u05D1\u05D9\u05D5\u05EA\u05E8 \u05E9\u05E4\u05D5\u05E2\u05DC (Cloudflare \u05D1\u05D3\u05D5\u05DC\u05E8\u05D9\u05DD, LiveDNS \u05DC\u05D9\u05E9\u05E8\u05D0\u05DC\u05D9\u05D9\u05DD \u05DE\u05E7\u05E8\u05D3\u05D9\u05D8 \u05D1\u05E9\u05E7\u05DC\u05D9\u05DD, \u05D0\u05D5 \u05D9\u05D3\u05E0\u05D9 \u05DE\u05EA\u05D5\u05E8 \u05D4\u05E6\u05D5\u05D5\u05EA), \u05E8\u05D9\u05E9\u05D5\u05DD \u05D0\u05D7\u05D3 \u05DC\u05DB\u05DC \u05D4\u05D6\u05DE\u05E0\u05D4, \u05D9\u05D5\u05DE\u05DF \u05E7\u05E8\u05D9\u05D0\u05D5\u05EA \u05DC\u05DB\u05DC \u05D4\u05D6\u05DE\u05E0\u05D4, \u05D5\u05D7\u05D9\u05D3\u05D5\u05E9 \u05E9\u05E0\u05EA\u05D9 \u05D0\u05E6\u05DC \u05D0\u05D5\u05EA\u05D5 \u05E8\u05E9\u05DD. \u05DC\u05D3\u05D5\u05DE\u05D9\u05D9\u05DF \u05E9\u05E0\u05E7\u05E0\u05D4: \u05D3\u05D5\u05D0\u05E8 \u05D3\u05E8\u05DA Cloudflare Email Routing.", summaryEn: "Buying domains for a site: each name goes to the cheapest registrar that is on (Cloudflare in dollars, LiveDNS for Israeli names from shekel credit, or by hand from the team queue), one registration per order, a call log per order, yearly renewal at the same registrar. For a bought domain: email through Cloudflare Email Routing.", code: ["apps/web/src/server/registrar.ts", "apps/web/src/server/registrar-livedns.ts", "apps/web/src/server/registrar-log.ts", "apps/web/src/server/domain-sales.ts", "apps/web/src/server/domain-email.ts", "apps/web/src/server/billing/services.ts"], env: ["CF_REGISTRAR_TOKEN", "LIVEDNS_USER", "LIVEDNS_PASSWORD"], decisions: ["D-299", "D-300", "D-301", "D-458"] },
|
|
21141
|
+
{ id: "mcp", kind: "external", zone: "services", label: "MCP for AI tools (/api/mcp)", summary: "ChatGPT \u05D5-Claude \u05DE\u05EA\u05D7\u05D1\u05E8\u05D9\u05DD \u05D1\u05DC\u05D9 \u05D8\u05E8\u05DE\u05D9\u05E0\u05DC: OAuth \u05E2\u05DD \u05D0\u05D9\u05E9\u05D5\u05E8 \u05D1\u05D3\u05E4\u05D3\u05E4\u05DF, \u05D5\u05D0\u05D6 \u05DB\u05DC\u05D9\u05DD \u05DC\u05E8\u05E9\u05D9\u05DE\u05EA \u05D4\u05D0\u05EA\u05E8\u05D9\u05DD, \u05D1\u05D3\u05D9\u05E7\u05D4, \u05D4\u05E2\u05DC\u05D0\u05EA \u05D2\u05E8\u05E1\u05D4 \u05DC\u05EA\u05E6\u05D5\u05D2\u05D4 \u05DE\u05E7\u05D3\u05D9\u05DE\u05D4, \u05D4\u05E8\u05E6\u05EA \u05EA\u05D5\u05E1\u05E4\u05D9\u05DD \u05E9\u05D4\u05D0\u05EA\u05E8 \u05E7\u05E0\u05D4 (\u05D4\u05E7\u05E0\u05D9\u05D9\u05D4 \u05E8\u05E7 \u05D1\u05D0\u05EA\u05E8), \u05D5\u05D4\u05E2\u05DC\u05D0\u05D4 \u05DC\u05D0\u05D5\u05D5\u05D9\u05E8 \u05E8\u05E7 \u05E2\u05DD \u05D4\u05E8\u05E9\u05D0\u05D4 \u05D5\u05D0\u05D9\u05E9\u05D5\u05E8.", summaryEn: "ChatGPT and Claude connect without a terminal: OAuth with a browser consent, then tools to list sites, check, upload a version to a preview, run add-ons the site owns (buying stays on the site), and go live only with the permission and a yes.", code: ["apps/web/src/app/api/mcp/route.ts", "apps/web/src/server/mcp-tools.ts", "apps/web/src/server/auth.ts"], decisions: ["D-302"] },
|
|
21135
21142
|
{ id: "npm", kind: "external", zone: "services", label: "npm registry", summary: "\u05DE\u05E4\u05D9\u05E5 \u05D0\u05EA \u05D4\u05BECLI, \u05D5\u05DE\u05DE\u05E0\u05D5 \u05D4\u05D1\u05E0\u05D9\u05D9\u05D4 \u05DE\u05EA\u05E7\u05D9\u05E0\u05D4 \u05EA\u05DC\u05D5\u05D9\u05D5\u05EA.", summaryEn: "Distributes the CLI, and the build installs dependencies from it." },
|
|
21136
21143
|
{ id: "pagespeed", kind: "external", zone: "services", label: "Google PageSpeed Insights", summary: "\u05D1\u05D3\u05D9\u05E7\u05D5\u05EA \u05D4\u05DE\u05D4\u05D9\u05E8\u05D5\u05EA, \u05D4\u05E0\u05D2\u05D9\u05E9\u05D5\u05EA \u05D5\u05D4-SEO \u05D4\u05D7\u05D9\u05E0\u05DE\u05D9\u05D5\u05EA: Lighthouse \u05D1\u05DE\u05E2\u05D1\u05D3\u05D4 \u05E9\u05DC \u05D2\u05D5\u05D2\u05DC (\u05DB\u05D5\u05DC\u05DC \u05E1\u05D5\u05DB\u05E0\u05D9 AI) \u05D5\u05E0\u05EA\u05D5\u05E0\u05D9 \u05DE\u05D1\u05E7\u05E8\u05D9\u05DD \u05D0\u05DE\u05D9\u05EA\u05D9\u05D9\u05DD.", summaryEn: "The free speed, accessibility and SEO tests: Lighthouse run at Google (AI agents included) plus real visitor data.", env: ["PAGESPEED_API_KEY"], decisions: ["D-199", "D-222"] },
|
|
21137
21144
|
{ id: "turnstile", kind: "external", zone: "services", label: "CF Turnstile", summary: '\u05D1\u05D3\u05D9\u05E7\u05EA "\u05D4\u05D0\u05DD \u05D0\u05EA\u05DD \u05D1\u05E0\u05D9 \u05D0\u05D3\u05DD" \u05D1\u05D8\u05E4\u05E1\u05D9 \u05D4\u05DB\u05DC\u05D9\u05DD \u05D4\u05D7\u05D9\u05E0\u05DE\u05D9\u05D9\u05DD, \u05D1\u05DC\u05D9 \u05E4\u05D0\u05D6\u05DC\u05D9\u05DD \u05DC\u05E8\u05D5\u05D1 \u05D4\u05DE\u05D1\u05E7\u05E8\u05D9\u05DD.', summaryEn: 'The "are you human" check on the free tool forms, with no puzzle for most visitors.', env: ["TURNSTILE_SITE_KEY", "TURNSTILE_SECRET"], decisions: ["D-199"] },
|
|
21138
21145
|
// Cloudflare
|
|
21139
21146
|
{ id: "tunnel", kind: "cf-resource", zone: "cloudflare", label: "Cloudflare Tunnel", summary: "\u05D4\u05D9\u05D5\u05DD \u05D4\u05D0\u05E4\u05DC\u05D9\u05E7\u05E6\u05D9\u05D4 \u05E8\u05E6\u05D4 \u05E2\u05DC \u05D4\u05DE\u05D7\u05E9\u05D1 \u05D4\u05D6\u05D4 \u05D5\u05E0\u05D7\u05E9\u05E4\u05EA \u05D3\u05E8\u05DA dev.deployai.co.il (pnpm tunnel, \u05D0\u05D5 \u05D4\u05DB\u05DC \u05D9\u05D7\u05D3 \u05D1\u05BEpnpm dev:public).", summaryEn: "Today the app runs on this computer and is exposed through dev.deployai.co.il (pnpm tunnel, or everything at once with pnpm dev:public).", code: ["scripts/dev-public.ts"], env: ["TUNNEL_ORIGIN_CERT"], decisions: ["D-089", "D-148"] },
|
|
21140
|
-
{ id: "cfapi", kind: "external", zone: "cloudflare", label: "Cloudflare API", summary: "\u05DB\u05DC \u05E4\u05E2\u05D5\u05DC\u05D4 \u05DE\u05D5\u05DC Cloudflare \u05E2\u05D5\u05D1\u05E8\u05EA \u05D1\u05BEREST API \u05E2\u05DD \u05D3\u05DC\u05D9 \u05D8\u05D5\u05E7\u05E0\u05D9\u05DD \u05DE\u05E9\u05D5\u05EA\u05E3. \u05D1\u05DC\u05D9 Wrangler.", summaryEn: "Every Cloudflare action goes through the REST API with a shared token bucket. No Wrangler.", code: ["apps/web/src/server/cloudflare.ts", "scripts/cf-setup.ts"], env: ["CF_API_TOKEN"], docs: ["docs/10-cloudflare-reference.md"], decisions: ["D-007", "D-031", "D-058"] },
|
|
21147
|
+
{ id: "cfapi", kind: "external", zone: "cloudflare", label: "Cloudflare API", summary: "\u05DB\u05DC \u05E4\u05E2\u05D5\u05DC\u05D4 \u05DE\u05D5\u05DC Cloudflare \u05E2\u05D5\u05D1\u05E8\u05EA \u05D1\u05BEREST API \u05E2\u05DD \u05D3\u05DC\u05D9 \u05D8\u05D5\u05E7\u05E0\u05D9\u05DD \u05DE\u05E9\u05D5\u05EA\u05E3. \u05D1\u05DC\u05D9 Wrangler.", summaryEn: "Every Cloudflare action goes through the REST API with a shared token bucket. No Wrangler.", code: ["apps/web/src/server/cloudflare.ts", "scripts/cf-setup.ts", "apps/web/src/server/admin-geo.ts"], env: ["CF_API_TOKEN", "ADMIN_GEO_MANAGE"], docs: ["docs/10-cloudflare-reference.md"], decisions: ["D-007", "D-031", "D-058", "D-455"] },
|
|
21141
21148
|
{ id: "demos", kind: "worker", zone: "cloudflare", label: "deployai-demos", summary: "\u05D4\u05D3\u05DE\u05D5\u05D0\u05D9\u05DD \u05D1\u05DB\u05EA\u05D5\u05D1\u05D5\u05EA \u05DB\u05DE\u05D5 shop.deploy-net.com, \u05E2\u05DC \u05DB\u05DC \u05D3\u05D5\u05DE\u05D9\u05D9\u05DF \u05D0\u05EA\u05E8\u05D9\u05DD: \u05DE\u05D5\u05E9\u05DA \u05D0\u05EA /demo/<key> \u05DE\u05D4\u05D0\u05EA\u05E8 \u05E9\u05DC\u05E0\u05D5 \u05D5\u05DE\u05E1\u05D9\u05E8 \u05D0\u05EA \u05D4\u05E7\u05D9\u05D3\u05D5\u05DE\u05EA, noindex.", summaryEn: "The demos on hosts like shop.deploy-net.com, on every sites domain: fetches /demo/<key> from our site and strips the prefix, noindex.", code: ["workers/demos/src", "scripts/deploy-demos.ts", "packages/shared/src/demos.ts"], env: ["CHROME_PATH", "SHOTS_BASE"], docs: ["workers/demos/README.md"], decisions: ["D-112", "D-293"] },
|
|
21142
21149
|
{ id: "tools-worker", kind: "worker", zone: "cloudflare", label: "deployai-tools", summary: "\u05DE\u05D5\u05E8\u05D9\u05D3 \u05D0\u05EA \u05D4\u05E2\u05DE\u05D5\u05D3\u05D9\u05DD \u05D5\u05D4\u05EA\u05DE\u05D5\u05E0\u05D5\u05EA \u05E9\u05D4\u05DB\u05DC\u05D9\u05DD \u05D4\u05D7\u05D9\u05E0\u05DE\u05D9\u05D9\u05DD \u05D1\u05D5\u05D3\u05E7\u05D9\u05DD, \u05DB\u05D3\u05D9 \u05E9\u05DB\u05EA\u05D5\u05D1\u05EA \u05E9\u05DE\u05D1\u05E7\u05E8 \u05D4\u05E7\u05DC\u05D9\u05D3 \u05DC\u05D0 \u05EA\u05D9\u05D8\u05E2\u05DF \u05DE\u05D4\u05E9\u05E8\u05EA \u05E9\u05DC\u05E0\u05D5. \u05E8\u05E7 \u05E9\u05DE\u05D5\u05EA \u05E6\u05D9\u05D1\u05D5\u05E8\u05D9\u05D9\u05DD, \u05DB\u05DC \u05EA\u05E9\u05D5\u05D1\u05EA DNS \u05D5\u05DB\u05DC \u05D4\u05E4\u05E0\u05D9\u05D4 \u05E0\u05D1\u05D3\u05E7\u05D5\u05EA.", summaryEn: "Downloads the pages and images the free tools test, so an address a visitor typed is never fetched from our server. Public names only; every DNS answer and redirect is checked.", code: ["workers/tools/src", "scripts/deploy-tools.ts", "packages/shared/src/safe-url.ts"], env: ["TOOLS_FETCH_SECRET"], decisions: ["D-199"] },
|
|
21143
21150
|
{ id: "uptime-worker", kind: "worker", zone: "cloudflare", label: "deployai-uptime", summary: "\u05D1\u05D5\u05D3\u05E7 \u05DE\u05D1\u05D7\u05D5\u05E5 \u05DB\u05DC 2 \u05D3\u05E7\u05D5\u05EA \u05E9-/api/health \u05E2\u05D5\u05E0\u05D4, \u05DB\u05D9 \u05E9\u05E8\u05EA \u05E9\u05E0\u05E4\u05DC \u05DC\u05D0 \u05D9\u05DB\u05D5\u05DC \u05DC\u05D3\u05D5\u05D5\u05D7 \u05E2\u05DC \u05E2\u05E6\u05DE\u05D5. \u05E9\u05D5\u05DE\u05E8 \u05D0\u05EA \u05D4\u05EA\u05D5\u05E6\u05D0\u05D4 \u05D1-KV, \u05D5\u05E9\u05EA\u05D9 \u05E0\u05E4\u05D9\u05DC\u05D5\u05EA \u05D1\u05E8\u05E6\u05E3 \u05E9\u05D5\u05DC\u05D7\u05D5\u05EA \u05DE\u05D9\u05D9\u05DC \u05DC\u05E6\u05D5\u05D5\u05EA.", summaryEn: "Checks from outside every 2 minutes that /api/health answers, because a server that is down cannot report itself. Keeps the result in KV; two failures in a row email the team.", code: ["workers/uptime/src", "scripts/deploy-uptime.ts", "apps/web/src/app/api/health/route.ts"], env: ["UPTIME_ALERT_TO", "UPTIME_ALERT_TOKEN"], decisions: ["D-331"] },
|
|
@@ -21210,7 +21217,7 @@ var ARCH_FLOWS = [
|
|
|
21210
21217
|
labelEn: "Site visit",
|
|
21211
21218
|
steps: [
|
|
21212
21219
|
{ edge: "visitor-dispatch", text: "\u05DB\u05DC \u05DB\u05EA\u05D5\u05D1\u05EA \u05DE\u05D2\u05D9\u05E2\u05D4 \u05DC\u05BEdispatch Worker.", textEn: "Every address reaches the dispatch Worker." },
|
|
21213
|
-
{ edge: dispatchEdgeId("ROUTES"), text: "\u05D4\u05DB\u05EA\u05D5\u05D1\u05EA \u05DE\u05DE\u05D5\u05E4\u05D4 \u05DC\u05E1\u05E7\u05E8\u05D9\u05E4\u05D8 (\u05EA\u05EA \u05D3\u05D5\u05DE\u05D9\u05D9\u05DF \u05D1\u05DC\u05D9 \u05E7\u05E8\u05D9\u05D0\u05D4, \u05D3\u05D5\u05DE\u05D9\u05D9\u05DF \u05E9\u05DC \u05DC\u05E7\u05D5\u05D7 \u05D1\u05BEhost:), \u05D5\u05E0\u05E7\u05E8\u05D0\u05EA \u05E8\u05E9\u05D5\u05DE\u05EA \u05D4\u05D0\u05EA\u05E8 site:: \u05DE\u05E1\u05DC\u05D5\u05DC, \u05DE\u05E2\u05D1\u05D3, \u05EA\u05D2, \u05DE\u05D9 \u05E8\u05E9\u05D0\u05D9 \u05DC\u05D4\u05D9\u05DB\u05E0\u05E1
|
|
21220
|
+
{ edge: dispatchEdgeId("ROUTES"), text: "\u05D4\u05DB\u05EA\u05D5\u05D1\u05EA \u05DE\u05DE\u05D5\u05E4\u05D4 \u05DC\u05E1\u05E7\u05E8\u05D9\u05E4\u05D8 (\u05EA\u05EA \u05D3\u05D5\u05DE\u05D9\u05D9\u05DF \u05D1\u05DC\u05D9 \u05E7\u05E8\u05D9\u05D0\u05D4, \u05D3\u05D5\u05DE\u05D9\u05D9\u05DF \u05E9\u05DC \u05DC\u05E7\u05D5\u05D7 \u05D1\u05BEhost:), \u05D5\u05E0\u05E7\u05E8\u05D0\u05EA \u05E8\u05E9\u05D5\u05DE\u05EA \u05D4\u05D0\u05EA\u05E8 site:: \u05DE\u05E1\u05DC\u05D5\u05DC, \u05DE\u05E2\u05D1\u05D3, \u05EA\u05D2, \u05DE\u05D9 \u05E8\u05E9\u05D0\u05D9 \u05DC\u05D4\u05D9\u05DB\u05E0\u05E1 \u05D5\u05DB\u05D1\u05D5\u05D9. \u05E0\u05E9\u05DE\u05E8\u05EA \u05D1\u05D6\u05D9\u05DB\u05E8\u05D5\u05DF \u05D3\u05E7\u05D4 (D-249).", textEn: "The address is mapped to a script (our subdomain without a read, a customer domain by host:), and the site record site: is read: tier, CPU, badge, who may come in and off. Kept a minute in memory (D-249)." },
|
|
21214
21221
|
{ edge: dispatchEdgeId("RATE_FREE"), text: "\u05D1\u05D3\u05D9\u05E7\u05EA \u05E7\u05E6\u05D1 \u05DC\u05E4\u05D9 IP \u05D5\u05D0\u05EA\u05E8, \u05D1\u05DE\u05D2\u05D1\u05DC\u05D4 \u05E9\u05DC \u05D4\u05DE\u05E1\u05DC\u05D5\u05DC (\u05D6\u05DE\u05E0\u05D9, \u05D7\u05D9\u05E0\u05DE\u05D9 \u05D0\u05D5 \u05D1\u05EA\u05E9\u05DC\u05D5\u05DD).", textEn: "Rate check by IP and site, with the tier limit (temporary, free or paid)." },
|
|
21215
21222
|
{ edge: dispatchEdgeId("DISPATCHER"), text: "\u05D4\u05D1\u05E7\u05E9\u05D4 \u05E2\u05D5\u05D1\u05E8\u05EA \u05DC\u05BEnamespace.", textEn: "The request goes to the namespace." },
|
|
21216
21223
|
{ edge: "dispatcher-site", text: "\u05D4\u05BEWorker \u05E9\u05DC \u05D4\u05D0\u05EA\u05E8 \u05E2\u05D5\u05E0\u05D4.", textEn: "The site's Worker answers." },
|
|
@@ -21228,7 +21235,7 @@ var ARCH_FLOWS = [
|
|
|
21228
21235
|
{ edge: "web-queue", text: "\u05E2\u05D1\u05D5\u05D3\u05EA site-toggle \u05D1\u05E2\u05D3\u05D9\u05E4\u05D5\u05EA \u05D3\u05D7\u05D5\u05E4\u05D4.", textEn: "A site-toggle job with urgent priority." },
|
|
21229
21236
|
{ edge: "queue-worker", text: "\u05D4\u05BEworker \u05DE\u05E8\u05D9\u05E5 \u05D0\u05D5\u05EA\u05D4.", textEn: "The worker runs it." },
|
|
21230
21237
|
{ edge: "worker-cfapi", text: "\u05E4\u05E0\u05D9\u05D9\u05D4 \u05DC\u05BECloudflare API.", textEn: "A call to the Cloudflare API." },
|
|
21231
|
-
{ edge: "cfapi-kv", text: '\u05E8\u05E9\u05D5\u05DE\u05EA \u05D4\u05D0\u05EA\u05E8 site: \u05D1\u05BEKV \u05E0\u05DB\u05EA\u05D1\u05EA \u05DE\u05D7\u05D3\u05E9 \u05E2\u05DD \u05DB\u05D1\u05D5\u05D9
|
|
21238
|
+
{ edge: "cfapi-kv", text: '\u05E8\u05E9\u05D5\u05DE\u05EA \u05D4\u05D0\u05EA\u05E8 site: \u05D1\u05BEKV \u05E0\u05DB\u05EA\u05D1\u05EA \u05DE\u05D7\u05D3\u05E9 \u05E2\u05DD \u05DB\u05D1\u05D5\u05D9, \u05D5\u05DE\u05D2\u05D9\u05E2\u05D4 \u05DC\u05DE\u05D1\u05E7\u05E8\u05D9\u05DD \u05EA\u05D5\u05DA \u05D3\u05E7\u05D4 (D-249). \u05D4\u05BEdispatch Worker \u05E2\u05D5\u05E0\u05D4 \u05D1\u05E2\u05DE\u05D5\u05D3 "\u05D4\u05D0\u05EA\u05E8 \u05DC\u05D0 \u05D6\u05DE\u05D9\u05DF" \u05D1\u05E9\u05E4\u05EA \u05D4\u05D3\u05E4\u05D3\u05E4\u05DF \u05E9\u05DC \u05D4\u05DE\u05D1\u05E7\u05E8 (D-413), \u05E2\u05DD \u05D4\u05DC\u05D5\u05D2\u05D5 \u05D5\u05E7\u05D9\u05E9\u05D5\u05E8 \u05DC DeployAI (D-178).', textEn: 'The site record site: in KV is written again with off, and reaches visitors within a minute (D-249). The dispatch Worker answers the "site unavailable" page in the browser language of the visitor (D-413), with the logo and a link to DeployAI (D-178).' }
|
|
21232
21239
|
]
|
|
21233
21240
|
},
|
|
21234
21241
|
{
|
|
@@ -21261,8 +21268,8 @@ var ARCH_FLOWS = [
|
|
|
21261
21268
|
|
|
21262
21269
|
// ../shared/src/cost-model.ts
|
|
21263
21270
|
var DEFAULT_FLEET = {
|
|
21264
|
-
mix: { basic: 0.65, business: 0.3,
|
|
21265
|
-
sitesPerAccount: { free: 1, basic: 1, business: 2,
|
|
21271
|
+
mix: { basic: 0.65, business: 0.3, agency: 0.05 },
|
|
21272
|
+
sitesPerAccount: { free: 1, basic: 1, business: 2, agency: 6 },
|
|
21266
21273
|
freeProfile: "quiet",
|
|
21267
21274
|
paidProfile: "typical",
|
|
21268
21275
|
ownDomainShare: 0.6,
|
|
@@ -21283,12 +21290,10 @@ var PLAN_FEATURES = [
|
|
|
21283
21290
|
{ key: "ssl" },
|
|
21284
21291
|
{ key: "analytics", limit: "analyticsDays" },
|
|
21285
21292
|
{ key: "data", limit: "maxDataMb" },
|
|
21286
|
-
{ key: "
|
|
21293
|
+
{ key: "pageViews", limit: "maxPageViewsMonth" },
|
|
21287
21294
|
{ key: "deploys", limit: "maxDeploysDay" },
|
|
21288
|
-
{ key: "buildMinutes", limit: "maxBuildMinutesMonth" },
|
|
21289
21295
|
{ key: "emails", limit: "maxEmailsMonth" },
|
|
21290
21296
|
{ key: "versions", limit: "maxVersionsMb" },
|
|
21291
|
-
{ key: "invitedUsers", limit: "maxInvitedUsers" },
|
|
21292
21297
|
{ key: "helpDeploys" },
|
|
21293
21298
|
{ key: "helpEmail" },
|
|
21294
21299
|
{ key: "whatsapp", soon: true }
|
|
@@ -21352,7 +21357,7 @@ var CLI_MAP_NODES = [
|
|
|
21352
21357
|
n("cmd-init", "cli", "init", "\u05D9\u05D5\u05E6\u05E8 DEPLOYAI.md \u05D5 .deployai/project.json.", "Creates DEPLOYAI.md and .deployai/project.json."),
|
|
21353
21358
|
n("cmd-inspect", "cli", "inspect", "\u05DE\u05D4 \u05D6\u05D5\u05D4\u05D4 \u05D1\u05E4\u05E8\u05D5\u05D9\u05E7\u05D8: \u05DE\u05E1\u05D2\u05E8\u05EA, \u05E9\u05E4\u05D4, \u05DE\u05E1\u05D3 \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD.", "What the project is: framework, language, database."),
|
|
21354
21359
|
n("cmd-login", "cli", "login", "\u05DB\u05E0\u05D9\u05E1\u05D4 \u05D1\u05D3\u05E4\u05D3\u05E4\u05DF, \u05D1\u05E2\u05DC \u05D4\u05D0\u05EA\u05E8 \u05DE\u05D0\u05E9\u05E8.", "Login in the browser, the owner approves."),
|
|
21355
|
-
n("cmd-logout", "cli", "logout", "\
|
|
21360
|
+
n("cmd-logout", "cli", "logout", "\u05DE\u05D1\u05D8\u05DC \u05D0\u05EA \u05D4\u05D8\u05D5\u05E7\u05DF \u05D5\u05D9\u05D5\u05E6\u05D0 \u05DE\u05D4\u05D7\u05E9\u05D1\u05D5\u05DF \u05D1\u05DE\u05D7\u05E9\u05D1 \u05D4\u05D6\u05D4.", "Cancels the token and logs out on this computer."),
|
|
21356
21361
|
n("cmd-whoami", "cli", "whoami", "\u05E2\u05DD \u05D0\u05D9\u05D6\u05D4 \u05D7\u05E9\u05D1\u05D5\u05DF \u05DE\u05D7\u05D5\u05D1\u05E8\u05D9\u05DD.", "Which account is logged in."),
|
|
21357
21362
|
n("cmd-link", "cli", "link [site]", "\u05DE\u05D7\u05D1\u05E8 \u05D0\u05EA \u05D4\u05EA\u05D9\u05E7\u05D9\u05D9\u05D4 \u05DC\u05D0\u05EA\u05E8, \u05D0\u05D5 \u05D9\u05D5\u05E6\u05E8 \u05D0\u05EA\u05E8 \u05E2\u05DD --create.", "Links the folder to a site, or makes one with --create."),
|
|
21358
21363
|
n("cmd-deploy", "cli", "deploy -m", "\u05D1\u05D5\u05D3\u05E7, \u05D0\u05D5\u05E8\u05D6 \u05D5\u05DE\u05E2\u05DC\u05D4 \u05D2\u05E8\u05E1\u05D4 \u05DC\u05EA\u05E6\u05D5\u05D2\u05D4 \u05DE\u05E7\u05D3\u05D9\u05DE\u05D4.", "Checks, packs and uploads a version to a preview."),
|
|
@@ -21363,7 +21368,7 @@ var CLI_MAP_NODES = [
|
|
|
21363
21368
|
n("cmd-promote", "cli", "promote v<N>", "\u05DE\u05E2\u05DC\u05D4 \u05DC\u05D0\u05D5\u05D5\u05D9\u05E8 \u05D2\u05E8\u05E1\u05D4 \u05E9\u05D0\u05D5\u05E9\u05E8\u05D4.", "Puts an approved version live."),
|
|
21364
21369
|
n("cmd-versions", "cli", "versions", "\u05E8\u05E9\u05D9\u05DE\u05EA \u05D4\u05D2\u05E8\u05E1\u05D0\u05D5\u05EA \u05E9\u05DC \u05D4\u05D0\u05EA\u05E8.", "The site's versions."),
|
|
21365
21370
|
n("cmd-rollback", "cli", "rollback v<N>", "\u05D7\u05D5\u05D6\u05E8 \u05DC\u05D2\u05E8\u05E1\u05D4 \u05E7\u05D5\u05D3\u05DE\u05EA.", "Goes back to an earlier version."),
|
|
21366
|
-
n("cmd-addons", "cli", "addons / addon next", "\u05D4\u05EA\u05D5\u05E1\u05E4\u05D9\u05DD \u05E9\u05DC \u05D4\u05D0\u05EA\u05E8, \
|
|
21371
|
+
n("cmd-addons", "cli", "addons / addon next / addon buy", "\u05D4\u05EA\u05D5\u05E1\u05E4\u05D9\u05DD \u05E9\u05DC \u05D4\u05D0\u05EA\u05E8, \u05D4\u05E9\u05DC\u05D1 \u05D4\u05D1\u05D0 \u05E9\u05DC \u05EA\u05D5\u05E1\u05E3 \u05E9\u05E0\u05E7\u05E0\u05D4, \u05D5\u05E7\u05D9\u05E9\u05D5\u05E8 \u05E7\u05E0\u05D9\u05D9\u05D4 \u05DC\u05D1\u05E2\u05DC \u05D4\u05D0\u05EA\u05E8.", "The site's add-ons, the next step of one it bought, and a buy link for the owner."),
|
|
21367
21372
|
n("cmd-addon-run", "cli", "addon run / done", "\u05EA\u05D5\u05E1\u05E3 \u05D0\u05D7\u05D3 \u05DC\u05E4\u05D9 \u05E9\u05DD, \u05D5\u05D3\u05D9\u05D5\u05D5\u05D7 \u05E9\u05D4\u05E9\u05DC\u05D1 \u05D4\u05E1\u05EA\u05D9\u05D9\u05DD.", "One add-on by name, and the report that a step is done."),
|
|
21368
21373
|
n("cmd-env", "cli", "env list / set / remove", "\u05DE\u05E9\u05EA\u05E0\u05D9 \u05D4\u05E1\u05D1\u05D9\u05D1\u05D4 \u05E9\u05DC \u05D4\u05D0\u05EA\u05E8. \u05E1\u05D5\u05D3 \u05DB\u05D1\u05E8\u05D9\u05E8\u05EA \u05DE\u05D7\u05D3\u05DC, \u05D5\u05DC\u05D0 \u05DE\u05D5\u05E6\u05D2 \u05E9\u05D5\u05D1.", "The site's environment variables. A secret by default, never shown again."),
|
|
21369
21374
|
n("cmd-speed", "cli", "speed <url>", "\u05D1\u05D3\u05D9\u05E7\u05EA \u05DE\u05D4\u05D9\u05E8\u05D5\u05EA \u05E9\u05DC \u05DB\u05EA\u05D5\u05D1\u05EA \u05D7\u05D9\u05D4.", "A speed test of a live address."),
|
|
@@ -21460,6 +21465,31 @@ function findSecretLine(text, re) {
|
|
|
21460
21465
|
}
|
|
21461
21466
|
return null;
|
|
21462
21467
|
}
|
|
21468
|
+
var PRIVATE_DIRS = /* @__PURE__ */ new Set([".deployai", ".claude", ".cursor", ".vscode", ".idea", ".git", ".github", ".husky"]);
|
|
21469
|
+
var PRIVATE_FILES = /* @__PURE__ */ new Set(["DEPLOYAI.md", "CLAUDE.md", "AGENTS.md", ".cursorrules", ".windsurfrules"]);
|
|
21470
|
+
var SERVED_DOT_DIR = ".well-known";
|
|
21471
|
+
var BUILD_DOTFILES = /* @__PURE__ */ new Set([".babelrc", ".babelrc.json", ".browserslistrc", ".postcssrc", ".postcssrc.json", ".postcssrc.js", ".postcssrc.cjs", ".postcssrc.mjs", ".swcrc", ".nvmrc", ".node-version", ".assetsignore"]);
|
|
21472
|
+
var segments = (path) => path.replace(/^\/+/, "").split("/").filter(Boolean);
|
|
21473
|
+
function privateProjectFile(path) {
|
|
21474
|
+
const parts = segments(path);
|
|
21475
|
+
const base = parts[parts.length - 1] ?? "";
|
|
21476
|
+
return PRIVATE_FILES.has(base) || parts.slice(0, -1).some((p) => PRIVATE_DIRS.has(p)) || PRIVATE_DIRS.has(base);
|
|
21477
|
+
}
|
|
21478
|
+
function dotPath(path) {
|
|
21479
|
+
const parts = segments(path);
|
|
21480
|
+
if (parts[0] === SERVED_DOT_DIR) parts.shift();
|
|
21481
|
+
return parts.some((p) => p.startsWith("."));
|
|
21482
|
+
}
|
|
21483
|
+
function neverUploadedFile(rel) {
|
|
21484
|
+
if (privateProjectFile(rel)) return true;
|
|
21485
|
+
const parts = segments(rel);
|
|
21486
|
+
if (parts.length === 1 && BUILD_DOTFILES.has(parts[0])) return false;
|
|
21487
|
+
return dotPath(rel);
|
|
21488
|
+
}
|
|
21489
|
+
|
|
21490
|
+
// ../shared/src/domain-sales.ts
|
|
21491
|
+
var IL_TLDS = ["co.il", "org.il", "net.il"];
|
|
21492
|
+
var LIVEDNS_TLDS = [...IL_TLDS, "com", "net", "org"];
|
|
21463
21493
|
|
|
21464
21494
|
// ../shared/src/env-scopes.ts
|
|
21465
21495
|
var ENV_KEYS = {
|
|
@@ -21471,11 +21501,13 @@ var ENV_KEYS = {
|
|
|
21471
21501
|
TUNNEL_ORIGIN_CERT: { scope: "local", section: "app", about: "The cloudflared login certificate pnpm dev:public checks. Default ~/.cloudflared/cert.pem." },
|
|
21472
21502
|
CF_API_TOKEN: { scope: "own", section: "cloudflare", required: ["server"], about: "Cloudflare token (pnpm cf:token-link): sites, KV, D1, R2, routes, custom hostnames and our emails. Each machine its own. Without it everything Cloudflare is a dry run." },
|
|
21473
21503
|
CF_REGISTRAR_TOKEN: { scope: "server", section: "cloudflare", about: "Buys real domains (D-300): a Cloudflare token with Registrar edit only. Server only." },
|
|
21504
|
+
LIVEDNS_USER: { scope: "server", section: "cloudflare", about: "Buys real Israeli domains at LiveDNS (D-458): the API user of our LiveDNS partner account. Server only: LiveDNS refuses some networks, and it spends prepaid credit." },
|
|
21505
|
+
LIVEDNS_PASSWORD: { scope: "server", section: "cloudflare", about: "Its password, sent in every LiveDNS call; never logged. Server only." },
|
|
21506
|
+
ADMIN_GEO_MANAGE: { scope: "server", section: "cloudflare", about: "1 lets the superadmin change the admin-geo rule on Admin, Server, Security (temporary, D-455); CF_API_TOKEN needs Zone WAF Edit. Off or unset: the card only shows it. The rule stays in Cloudflare either way." },
|
|
21474
21507
|
DISPATCH_RATE_LIMIT_GUEST: { scope: "same", section: "cloudflare", about: "pnpm dispatch:deploy: requests per IP per period on a temporary site (D-087, D-238)." },
|
|
21475
21508
|
DISPATCH_RATE_LIMIT_FREE: { scope: "same", section: "cloudflare", about: "The same on a site on a free plan." },
|
|
21476
21509
|
DISPATCH_RATE_LIMIT_PAID: { scope: "same", section: "cloudflare", about: "The same on a site on a paid plan." },
|
|
21477
21510
|
DISPATCH_RATE_LIMIT_PERIOD: { scope: "same", section: "cloudflare", about: "The rate limit period in seconds: 10 or 60." },
|
|
21478
|
-
MAIL_POSTAL_ADDRESS: { scope: "same", section: "email", about: "The business address in the footer of lifecycle emails (anti-spam law, D-180). Required before a tips or offers email can be turned on or sent (D-370)." },
|
|
21479
21511
|
GOOGLE_CLIENT_ID: { scope: "same", section: "login", about: "Google Cloud Console, OAuth client, with both the laptop and the server redirect addresses on it." },
|
|
21480
21512
|
GOOGLE_CLIENT_SECRET: { scope: "same", section: "login", about: "The secret of that Google client." },
|
|
21481
21513
|
GITHUB_CLIENT_ID: { scope: "same", section: "login", about: "GitHub, Settings, Developer settings, OAuth Apps, with both redirect addresses on it." },
|
|
@@ -21629,6 +21661,7 @@ function loadConfig() {
|
|
|
21629
21661
|
};
|
|
21630
21662
|
if (typeof raw.apiUrl === "string") cfg.apiUrl = raw.apiUrl;
|
|
21631
21663
|
if (typeof raw.token === "string") cfg.token = raw.token;
|
|
21664
|
+
if (typeof raw.tokenApiUrl === "string") cfg.tokenApiUrl = raw.tokenApiUrl;
|
|
21632
21665
|
if (typeof raw.email === "string") cfg.email = raw.email;
|
|
21633
21666
|
if (raw.guestClaims && typeof raw.guestClaims === "object") {
|
|
21634
21667
|
const links = Object.fromEntries(Object.entries(raw.guestClaims).filter(([, v]) => typeof v === "string"));
|
|
@@ -21765,6 +21798,9 @@ var M = {
|
|
|
21765
21798
|
goesLive: "The new version goes live when its build is done.",
|
|
21766
21799
|
followBuild: " Run: npx deployai@latest status (to follow the build)",
|
|
21767
21800
|
thenPromote: " Then, only after the owner approves the preview: npx deployai@latest promote v{n} (to put it live)",
|
|
21801
|
+
heavyPage: "The home page loads {n} files from the site. Fewer files make it faster for visitors.",
|
|
21802
|
+
prefetchPage: "The home page fetches pages before anyone opens them (link prefetch). Turning it off on long link lists saves visitors data.",
|
|
21803
|
+
speedHint: " Check it: npx deployai@latest speed {url}",
|
|
21768
21804
|
queueWaiting: "waiting in queue, position {n}",
|
|
21769
21805
|
files: "Files",
|
|
21770
21806
|
skipped: "Skipped",
|
|
@@ -21869,10 +21905,18 @@ var M = {
|
|
|
21869
21905
|
startExpired: "These instructions expired (they last 7 days). Copy them again from the DeployAI site.",
|
|
21870
21906
|
startUsedUp: "These instructions were already used 5 times. Copy them again from the DeployAI site.",
|
|
21871
21907
|
loginExpired: "The login code expired. Run: npx deployai@latest login",
|
|
21872
|
-
loggedOut: "Logged out. The token was removed from this computer.",
|
|
21908
|
+
loggedOut: "Logged out. The token was canceled and removed from this computer.",
|
|
21873
21909
|
protocol: "Unexpected answer from DeployAI. Run the latest CLI: npx deployai@latest",
|
|
21874
21910
|
guestClaimFirst: "This folder holds a temporary site, and you are logged in. Claim the site to your account first: {url}",
|
|
21875
21911
|
guestClaimFirstNoLink: "This folder holds a temporary site, and you are logged in. Claim it to your account first with the claim link deploy --guest printed.",
|
|
21912
|
+
guestAccountSite: "This folder belongs to a site in an account, so it cannot go up as a temporary site. Run: npx deployai@latest login, then: npx deployai@latest deploy",
|
|
21913
|
+
sqlWaitingLine: "Database changes (SQL) wait for your approval before this version goes live: {url}",
|
|
21914
|
+
sqlWaiting: "This version has database changes (SQL) that have not run yet. Approve them in the dashboard first, then promote again: {url}",
|
|
21915
|
+
tokenOtherApi: "The login on this computer is for {saved}, not {url}. Run: npx deployai@latest login --api {url}, or drop --api and DEPLOYAI_API_URL.",
|
|
21916
|
+
linkConfirm: "Link this folder to {name} ({address})? (y/N) ",
|
|
21917
|
+
linkOnlyOne: "You have one site: {name} ({address}). To link it, or a new site, run:",
|
|
21918
|
+
linkCancelled: "Not linked. Nothing changed.",
|
|
21919
|
+
loggedOutLocalOnly: "Logged out on this computer. DeployAI could not be reached, so the token stays valid until it expires (30 days).",
|
|
21876
21920
|
savedIn: "Saved in .deployai/project.json",
|
|
21877
21921
|
createdProject: "Created the site {name}.",
|
|
21878
21922
|
noProjects: "No sites yet.",
|
|
@@ -21883,7 +21927,7 @@ var M = {
|
|
|
21883
21927
|
runLink: " Run: npx deployai@latest link",
|
|
21884
21928
|
nextSteps: "Next steps",
|
|
21885
21929
|
readme: "Read README.md in the folder for what each file does.",
|
|
21886
|
-
states: { online: "live", building: "building", ready: "ready for review", failed: "failed", paused: "paused", off: "off", queued: "waiting", deleted: "deleted", new: "new" }
|
|
21930
|
+
states: { online: "live", building: "building", ready: "ready for review", failed: "failed", paused: "paused", off: "off", queued: "waiting", replaced: "replaced by a newer upload", deleted: "deleted", new: "new" }
|
|
21887
21931
|
},
|
|
21888
21932
|
he: {
|
|
21889
21933
|
startTitle: "DeployAI start",
|
|
@@ -21919,6 +21963,9 @@ var M = {
|
|
|
21919
21963
|
goesLive: "\u05D4\u05D2\u05E8\u05E1\u05D4 \u05D4\u05D7\u05D3\u05E9\u05D4 \u05E2\u05D5\u05DC\u05D4 \u05DC\u05D0\u05D5\u05D5\u05D9\u05E8 \u05DB\u05E9\u05D4\u05D1\u05E0\u05D9\u05D9\u05D4 \u05E9\u05DC\u05D4 \u05DE\u05E1\u05EA\u05D9\u05D9\u05DE\u05EA.",
|
|
21920
21964
|
followBuild: " \u05D4\u05E8\u05D9\u05E6\u05D5: npx deployai@latest status (\u05DB\u05D3\u05D9 \u05DC\u05E2\u05E7\u05D5\u05D1 \u05D0\u05D7\u05E8\u05D9 \u05D4\u05D1\u05E0\u05D9\u05D9\u05D4)",
|
|
21921
21965
|
thenPromote: " \u05D5\u05E8\u05E7 \u05D0\u05D7\u05E8\u05D9 \u05E9\u05D1\u05E2\u05DC \u05D4\u05D0\u05EA\u05E8 \u05D0\u05D9\u05E9\u05E8 \u05D0\u05EA \u05D4\u05EA\u05E6\u05D5\u05D2\u05D4 \u05D4\u05DE\u05E7\u05D3\u05D9\u05DE\u05D4: npx deployai@latest promote v{n} (\u05DB\u05D3\u05D9 \u05DC\u05D4\u05E2\u05DC\u05D5\u05EA \u05D0\u05D5\u05EA\u05D4 \u05DC\u05D0\u05D5\u05D5\u05D9\u05E8)",
|
|
21966
|
+
heavyPage: "\u05E2\u05DE\u05D5\u05D3 \u05D4\u05D1\u05D9\u05EA \u05D8\u05D5\u05E2\u05DF {n} \u05E7\u05D1\u05E6\u05D9\u05DD \u05DE\u05D4\u05D0\u05EA\u05E8. \u05E4\u05D7\u05D5\u05EA \u05E7\u05D1\u05E6\u05D9\u05DD \u05D6\u05D4 \u05D0\u05EA\u05E8 \u05DE\u05D4\u05D9\u05E8 \u05D9\u05D5\u05EA\u05E8 \u05DC\u05DE\u05D1\u05E7\u05E8\u05D9\u05DD.",
|
|
21967
|
+
prefetchPage: "\u05E2\u05DE\u05D5\u05D3 \u05D4\u05D1\u05D9\u05EA \u05D8\u05D5\u05E2\u05DF \u05E2\u05DE\u05D5\u05D3\u05D9\u05DD \u05DC\u05E4\u05E0\u05D9 \u05E9\u05DE\u05D9\u05E9\u05D4\u05D5 \u05E4\u05D5\u05EA\u05D7 \u05D0\u05D5\u05EA\u05DD (prefetch). \u05DB\u05D9\u05D1\u05D5\u05D9 \u05E9\u05DC\u05D5 \u05D1\u05E8\u05E9\u05D9\u05DE\u05D5\u05EA \u05E7\u05D9\u05E9\u05D5\u05E8\u05D9\u05DD \u05D0\u05E8\u05D5\u05DB\u05D5\u05EA \u05D7\u05D5\u05E1\u05DA \u05DC\u05DE\u05D1\u05E7\u05E8\u05D9\u05DD \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD.",
|
|
21968
|
+
speedHint: " \u05DC\u05D1\u05D3\u05D9\u05E7\u05D4: npx deployai@latest speed {url}",
|
|
21922
21969
|
queueWaiting: "\u05DE\u05DE\u05EA\u05D9\u05DF \u05D1\u05EA\u05D5\u05E8, \u05DE\u05E7\u05D5\u05DD {n}",
|
|
21923
21970
|
files: "\u05E7\u05D1\u05E6\u05D9\u05DD",
|
|
21924
21971
|
skipped: "\u05D3\u05D9\u05DC\u05D2\u05E0\u05D5",
|
|
@@ -22023,10 +22070,18 @@ var M = {
|
|
|
22023
22070
|
startExpired: "\u05E4\u05D2 \u05D4\u05EA\u05D5\u05E7\u05E3 \u05E9\u05DC \u05D4\u05D4\u05D5\u05E8\u05D0\u05D5\u05EA \u05D4\u05D0\u05DC\u05D4 (\u05D4\u05DF \u05EA\u05E7\u05E4\u05D5\u05EA 7 \u05D9\u05DE\u05D9\u05DD). \u05D4\u05E2\u05EA\u05D9\u05E7\u05D5 \u05D0\u05D5\u05EA\u05DF \u05E9\u05D5\u05D1 \u05DE\u05D4\u05D0\u05EA\u05E8 \u05E9\u05DC DeployAI.",
|
|
22024
22071
|
startUsedUp: "\u05DB\u05D1\u05E8 \u05D4\u05E9\u05EA\u05DE\u05E9\u05D5 \u05D1\u05D4\u05D5\u05E8\u05D0\u05D5\u05EA \u05D4\u05D0\u05DC\u05D4 5 \u05E4\u05E2\u05DE\u05D9\u05DD. \u05D4\u05E2\u05EA\u05D9\u05E7\u05D5 \u05D0\u05D5\u05EA\u05DF \u05E9\u05D5\u05D1 \u05DE\u05D4\u05D0\u05EA\u05E8 \u05E9\u05DC DeployAI.",
|
|
22025
22072
|
loginExpired: "\u05E7\u05D5\u05D3 \u05D4\u05DB\u05E0\u05D9\u05E1\u05D4 \u05E4\u05D2. \u05D4\u05E8\u05D9\u05E6\u05D5: npx deployai@latest login",
|
|
22026
|
-
loggedOut: "\u05D4\u05EA\u05E0\u05EA\u05E7\u05EA\u05DD. \u05D4\u05D8\u05D5\u05E7\u05DF \u05E0\u05DE\u05D7\u05E7 \u05DE\u05D4\u05DE\u05D7\u05E9\u05D1 \u05D4\u05D6\u05D4.",
|
|
22073
|
+
loggedOut: "\u05D4\u05EA\u05E0\u05EA\u05E7\u05EA\u05DD. \u05D4\u05D8\u05D5\u05E7\u05DF \u05D1\u05D5\u05D8\u05DC \u05D5\u05E0\u05DE\u05D7\u05E7 \u05DE\u05D4\u05DE\u05D7\u05E9\u05D1 \u05D4\u05D6\u05D4.",
|
|
22027
22074
|
protocol: "\u05EA\u05E9\u05D5\u05D1\u05D4 \u05DC\u05D0 \u05E6\u05E4\u05D5\u05D9\u05D4 \u05DE DeployAI. \u05D4\u05E8\u05D9\u05E6\u05D5 \u05D0\u05EA \u05D4\u05D2\u05E8\u05E1\u05D4 \u05D4\u05D0\u05D7\u05E8\u05D5\u05E0\u05D4: npx deployai@latest",
|
|
22028
22075
|
guestClaimFirst: "\u05D1\u05EA\u05D9\u05E7\u05D9\u05D9\u05D4 \u05D4\u05D6\u05D5 \u05D9\u05E9 \u05D0\u05EA\u05E8 \u05D6\u05DE\u05E0\u05D9, \u05D5\u05D0\u05EA\u05DD \u05DE\u05D7\u05D5\u05D1\u05E8\u05D9\u05DD \u05DC\u05D7\u05E9\u05D1\u05D5\u05DF. \u05E7\u05D5\u05D3\u05DD \u05E9\u05DE\u05E8\u05D5 \u05D0\u05EA \u05D4\u05D0\u05EA\u05E8 \u05D1\u05D7\u05E9\u05D1\u05D5\u05DF: {url}",
|
|
22029
22076
|
guestClaimFirstNoLink: "\u05D1\u05EA\u05D9\u05E7\u05D9\u05D9\u05D4 \u05D4\u05D6\u05D5 \u05D9\u05E9 \u05D0\u05EA\u05E8 \u05D6\u05DE\u05E0\u05D9, \u05D5\u05D0\u05EA\u05DD \u05DE\u05D7\u05D5\u05D1\u05E8\u05D9\u05DD \u05DC\u05D7\u05E9\u05D1\u05D5\u05DF. \u05E7\u05D5\u05D3\u05DD \u05E9\u05DE\u05E8\u05D5 \u05D0\u05D5\u05EA\u05D5 \u05D1\u05D7\u05E9\u05D1\u05D5\u05DF \u05E2\u05DD \u05E7\u05D9\u05E9\u05D5\u05E8 \u05D4\u05E9\u05DE\u05D9\u05E8\u05D4 \u05E9 deploy --guest \u05D4\u05D3\u05E4\u05D9\u05E1.",
|
|
22077
|
+
guestAccountSite: "\u05D4\u05EA\u05D9\u05E7\u05D9\u05D9\u05D4 \u05D4\u05D6\u05D5 \u05E9\u05D9\u05D9\u05DB\u05EA \u05DC\u05D0\u05EA\u05E8 \u05D1\u05D7\u05E9\u05D1\u05D5\u05DF, \u05D5\u05DC\u05DB\u05DF \u05D4\u05D9\u05D0 \u05DC\u05D0 \u05D9\u05DB\u05D5\u05DC\u05D4 \u05DC\u05E2\u05DC\u05D5\u05EA \u05DB\u05D0\u05EA\u05E8 \u05D6\u05DE\u05E0\u05D9. \u05D4\u05E8\u05D9\u05E6\u05D5: npx deployai@latest login, \u05D5\u05D0\u05D6: npx deployai@latest deploy",
|
|
22078
|
+
sqlWaitingLine: "\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05D1\u05DE\u05E1\u05D3 \u05D4\u05E0\u05EA\u05D5\u05E0\u05D9\u05DD (SQL) \u05DE\u05D7\u05DB\u05D9\u05DD \u05DC\u05D0\u05D9\u05E9\u05D5\u05E8 \u05E9\u05DC\u05DB\u05DD \u05DC\u05E4\u05E0\u05D9 \u05E9\u05D4\u05D2\u05E8\u05E1\u05D4 \u05D4\u05D6\u05D5 \u05E2\u05D5\u05DC\u05D4 \u05DC\u05D0\u05D5\u05D5\u05D9\u05E8: {url}",
|
|
22079
|
+
sqlWaiting: "\u05D1\u05D2\u05E8\u05E1\u05D4 \u05D4\u05D6\u05D5 \u05D9\u05E9 \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05D1\u05DE\u05E1\u05D3 \u05D4\u05E0\u05EA\u05D5\u05E0\u05D9\u05DD (SQL) \u05E9\u05E2\u05D5\u05D3 \u05DC\u05D0 \u05E8\u05E6\u05D5. \u05D0\u05E9\u05E8\u05D5 \u05D0\u05D5\u05EA\u05DD \u05E7\u05D5\u05D3\u05DD \u05D1\u05DC\u05D5\u05D7 \u05D4\u05D1\u05E7\u05E8\u05D4, \u05D5\u05D0\u05D6 \u05D4\u05E2\u05DC\u05D5 \u05DC\u05D0\u05D5\u05D5\u05D9\u05E8 \u05E9\u05D5\u05D1: {url}",
|
|
22080
|
+
tokenOtherApi: "\u05D4\u05DB\u05E0\u05D9\u05E1\u05D4 \u05D1\u05DE\u05D7\u05E9\u05D1 \u05D4\u05D6\u05D4 \u05D4\u05D9\u05D0 \u05DC {saved}, \u05DC\u05D0 \u05DC {url}. \u05D4\u05E8\u05D9\u05E6\u05D5: npx deployai@latest login --api {url}, \u05D0\u05D5 \u05D4\u05D5\u05E8\u05D9\u05D3\u05D5 \u05D0\u05EA --api \u05D5\u05D0\u05EA DEPLOYAI_API_URL.",
|
|
22081
|
+
linkConfirm: "\u05DC\u05D7\u05D1\u05E8 \u05D0\u05EA \u05D4\u05EA\u05D9\u05E7\u05D9\u05D9\u05D4 \u05D4\u05D6\u05D5 \u05DC {name} ({address})? (y/N) ",
|
|
22082
|
+
linkOnlyOne: "\u05D9\u05E9 \u05DC\u05DB\u05DD \u05D0\u05EA\u05E8 \u05D0\u05D7\u05D3: {name} ({address}). \u05DB\u05D3\u05D9 \u05DC\u05D7\u05D1\u05E8 \u05D0\u05D5\u05EA\u05D5, \u05D0\u05D5 \u05D0\u05EA\u05E8 \u05D7\u05D3\u05E9, \u05D4\u05E8\u05D9\u05E6\u05D5:",
|
|
22083
|
+
linkCancelled: "\u05DC\u05D0 \u05D7\u05D5\u05D1\u05E8. \u05E9\u05D5\u05DD \u05D3\u05D1\u05E8 \u05DC\u05D0 \u05D4\u05E9\u05EA\u05E0\u05D4.",
|
|
22084
|
+
loggedOutLocalOnly: "\u05D4\u05EA\u05E0\u05EA\u05E7\u05EA\u05DD \u05D1\u05DE\u05D7\u05E9\u05D1 \u05D4\u05D6\u05D4. \u05DC\u05D0 \u05D4\u05E6\u05DC\u05D7\u05E0\u05D5 \u05DC\u05D4\u05D2\u05D9\u05E2 \u05DC DeployAI, \u05D0\u05D6 \u05D4\u05D8\u05D5\u05E7\u05DF \u05EA\u05E7\u05E3 \u05E2\u05D3 \u05E9\u05D9\u05E4\u05D5\u05D2 (30 \u05D9\u05D5\u05DD).",
|
|
22030
22085
|
savedIn: "\u05E0\u05E9\u05DE\u05E8 \u05D1 .deployai/project.json",
|
|
22031
22086
|
createdProject: "\u05E0\u05D5\u05E6\u05E8 \u05D4\u05D0\u05EA\u05E8 {name}.",
|
|
22032
22087
|
noProjects: "\u05D0\u05D9\u05DF \u05E2\u05D3\u05D9\u05D9\u05DF \u05D0\u05EA\u05E8\u05D9\u05DD.",
|
|
@@ -22037,7 +22092,7 @@ var M = {
|
|
|
22037
22092
|
runLink: " \u05D4\u05E8\u05D9\u05E6\u05D5: npx deployai@latest link",
|
|
22038
22093
|
nextSteps: "\u05D4\u05E9\u05DC\u05D1\u05D9\u05DD \u05D4\u05D1\u05D0\u05D9\u05DD",
|
|
22039
22094
|
readme: "\u05D1 README.md \u05E9\u05D1\u05EA\u05D9\u05E7\u05D9\u05D9\u05D4 \u05DB\u05EA\u05D5\u05D1 \u05DE\u05D4 \u05DB\u05DC \u05E7\u05D5\u05D1\u05E5 \u05E2\u05D5\u05E9\u05D4.",
|
|
22040
|
-
states: { online: "\u05D1\u05D0\u05D5\u05D5\u05D9\u05E8", building: "\u05D1\u05D1\u05E0\u05D9\u05D9\u05D4", ready: "\u05DE\u05D7\u05DB\u05D4 \u05DC\u05D0\u05D9\u05E9\u05D5\u05E8", failed: "\u05E0\u05DB\u05E9\u05DC", paused: "\u05DE\u05D5\u05E9\u05D4\u05D4", off: "\u05DB\u05D1\u05D5\u05D9", queued: "\u05D1\u05EA\u05D5\u05E8", deleted: "\u05E0\u05DE\u05D7\u05E7", new: "\u05D7\u05D3\u05E9" }
|
|
22095
|
+
states: { online: "\u05D1\u05D0\u05D5\u05D5\u05D9\u05E8", building: "\u05D1\u05D1\u05E0\u05D9\u05D9\u05D4", ready: "\u05DE\u05D7\u05DB\u05D4 \u05DC\u05D0\u05D9\u05E9\u05D5\u05E8", failed: "\u05E0\u05DB\u05E9\u05DC", paused: "\u05DE\u05D5\u05E9\u05D4\u05D4", off: "\u05DB\u05D1\u05D5\u05D9", queued: "\u05D1\u05EA\u05D5\u05E8", replaced: "\u05D4\u05D5\u05D7\u05DC\u05E4\u05D4 \u05D1\u05D4\u05E2\u05DC\u05D0\u05D4 \u05D7\u05D3\u05E9\u05D4 \u05D9\u05D5\u05EA\u05E8", deleted: "\u05E0\u05DE\u05D7\u05E7", new: "\u05D7\u05D3\u05E9" }
|
|
22041
22096
|
}
|
|
22042
22097
|
};
|
|
22043
22098
|
function stateName(state, root) {
|
|
@@ -22050,7 +22105,7 @@ function messages(root) {
|
|
|
22050
22105
|
}
|
|
22051
22106
|
|
|
22052
22107
|
// src/version.ts
|
|
22053
|
-
var CLI_VERSION = "0.1.0-beta.
|
|
22108
|
+
var CLI_VERSION = "0.1.0-beta.3";
|
|
22054
22109
|
|
|
22055
22110
|
// src/api.ts
|
|
22056
22111
|
function apiContext(apiFlag) {
|
|
@@ -22062,6 +22117,8 @@ function userAgent(cfg) {
|
|
|
22062
22117
|
}
|
|
22063
22118
|
function requireToken(ctx) {
|
|
22064
22119
|
if (!ctx.config.token) throw new CliError(messages(process.cwd())("notLoggedIn"), 1, "auth");
|
|
22120
|
+
const saved = ctx.config.tokenApiUrl?.replace(/\/+$/, "");
|
|
22121
|
+
if (saved && saved !== ctx.apiUrl.replace(/\/+$/, "")) throw new CliError(messages(process.cwd())("tokenOtherApi", { saved, url: ctx.apiUrl }), 1, "auth");
|
|
22065
22122
|
return ctx.config.token;
|
|
22066
22123
|
}
|
|
22067
22124
|
async function apiRequest(ctx, path, schema, opts = {}) {
|
|
@@ -22106,6 +22163,9 @@ async function apiRequest(ctx, path, schema, opts = {}) {
|
|
|
22106
22163
|
if (parsed2.success && parsed2.data.error === "not_entitled") {
|
|
22107
22164
|
throw new CliError(t("notEntitled", { url: parsed2.data.buyUrl ?? ctx.apiUrl }), 1, "not_entitled");
|
|
22108
22165
|
}
|
|
22166
|
+
if (parsed2.success && parsed2.data.error === "sql_waiting") {
|
|
22167
|
+
throw new CliError(t("sqlWaiting", { url: parsed2.data.url ?? `${ctx.apiUrl}/dashboard` }), 1, "sql_waiting");
|
|
22168
|
+
}
|
|
22109
22169
|
const known = parsed2.success ? knownError(parsed2.data.error, data?.max, t, { ...data, billingUrl: `${ctx.apiUrl}/billing` }) : null;
|
|
22110
22170
|
if (known) throw new CliError(known, 1, parsed2.success ? parsed2.data.error : "api");
|
|
22111
22171
|
const msg = parsed2.success ? parsed2.data.error : `HTTP ${res.status}`;
|
|
@@ -22274,22 +22334,20 @@ async function sendTelemetryEvent(ctx, event) {
|
|
|
22274
22334
|
}
|
|
22275
22335
|
|
|
22276
22336
|
// src/commands/init.ts
|
|
22277
|
-
import { existsSync as
|
|
22337
|
+
import { existsSync as existsSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
22278
22338
|
import { join as join5 } from "path";
|
|
22279
22339
|
|
|
22280
22340
|
// src/analyze.ts
|
|
22281
22341
|
import { execFileSync } from "child_process";
|
|
22282
|
-
import { existsSync as
|
|
22342
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, readdirSync as readdirSync2 } from "fs";
|
|
22283
22343
|
import { join as join4 } from "path";
|
|
22284
22344
|
|
|
22285
22345
|
// src/files.ts
|
|
22286
|
-
import { readdirSync, readFileSync as readFileSync3, lstatSync } from "fs";
|
|
22346
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, lstatSync } from "fs";
|
|
22287
22347
|
import { join as join3 } from "path";
|
|
22288
22348
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
22289
22349
|
"node_modules",
|
|
22290
22350
|
".git",
|
|
22291
|
-
"dist",
|
|
22292
|
-
"build",
|
|
22293
22351
|
".next",
|
|
22294
22352
|
".astro",
|
|
22295
22353
|
".svelte-kit",
|
|
@@ -22297,9 +22355,19 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
22297
22355
|
".vercel",
|
|
22298
22356
|
".wrangler",
|
|
22299
22357
|
".turbo",
|
|
22300
|
-
".cache"
|
|
22301
|
-
"coverage"
|
|
22358
|
+
".cache"
|
|
22302
22359
|
]);
|
|
22360
|
+
var ROOT_BUILD_DIRS = /* @__PURE__ */ new Set(["dist", "build", "out", "coverage"]);
|
|
22361
|
+
function rootBuilds(root) {
|
|
22362
|
+
const file2 = join3(root, "package.json");
|
|
22363
|
+
if (!existsSync3(file2)) return false;
|
|
22364
|
+
try {
|
|
22365
|
+
const pkg = JSON.parse(readFileSync3(file2, "utf8"));
|
|
22366
|
+
return typeof pkg?.scripts?.build === "string";
|
|
22367
|
+
} catch {
|
|
22368
|
+
return true;
|
|
22369
|
+
}
|
|
22370
|
+
}
|
|
22303
22371
|
var MAX_FILE_BYTES = 10 * 1024 * 1024;
|
|
22304
22372
|
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
22305
22373
|
function isEnvFile(name) {
|
|
@@ -22370,10 +22438,19 @@ function loadIgnore(root) {
|
|
|
22370
22438
|
return [];
|
|
22371
22439
|
}
|
|
22372
22440
|
}
|
|
22441
|
+
function loadUploadIgnore(root) {
|
|
22442
|
+
let git = [];
|
|
22443
|
+
try {
|
|
22444
|
+
git = parseIgnore(readFileSync3(join3(root, ".gitignore"), "utf8"));
|
|
22445
|
+
} catch {
|
|
22446
|
+
}
|
|
22447
|
+
return [...git, ...loadIgnore(root)];
|
|
22448
|
+
}
|
|
22373
22449
|
function walkFiles(root, opts = {}) {
|
|
22374
22450
|
const result = [];
|
|
22375
22451
|
const maxFiles = opts.maxFiles ?? 2e4;
|
|
22376
22452
|
const rules = opts.ignore ?? [];
|
|
22453
|
+
const skipRootBuild = opts.skipRootBuild ?? rootBuilds(root);
|
|
22377
22454
|
const visit2 = (dirAbs, dirRel) => {
|
|
22378
22455
|
let names;
|
|
22379
22456
|
try {
|
|
@@ -22394,6 +22471,7 @@ function walkFiles(root, opts = {}) {
|
|
|
22394
22471
|
if (st.isSymbolicLink()) continue;
|
|
22395
22472
|
if (st.isDirectory()) {
|
|
22396
22473
|
if (SKIP_DIRS.has(name)) continue;
|
|
22474
|
+
if (!dirRel && skipRootBuild && ROOT_BUILD_DIRS.has(name)) continue;
|
|
22397
22475
|
if (isIgnored(rules, rel, true)) continue;
|
|
22398
22476
|
visit2(abs, rel);
|
|
22399
22477
|
} else if (st.isFile()) {
|
|
@@ -22407,12 +22485,12 @@ function walkFiles(root, opts = {}) {
|
|
|
22407
22485
|
return result;
|
|
22408
22486
|
}
|
|
22409
22487
|
function planUpload(root) {
|
|
22410
|
-
const all = walkFiles(root, { ignore:
|
|
22488
|
+
const all = walkFiles(root, { ignore: loadUploadIgnore(root), skipEnv: true, maxFiles: 1e5 });
|
|
22411
22489
|
const files = [];
|
|
22412
22490
|
const skippedLarge = [];
|
|
22413
22491
|
let totalBytes = 0;
|
|
22414
22492
|
for (const f of all) {
|
|
22415
|
-
if (f.rel
|
|
22493
|
+
if (neverUploadedFile(f.rel)) continue;
|
|
22416
22494
|
if (f.size > MAX_FILE_BYTES) {
|
|
22417
22495
|
skippedLarge.push(f);
|
|
22418
22496
|
continue;
|
|
@@ -22501,10 +22579,10 @@ function depLine(pkgText, dep) {
|
|
|
22501
22579
|
return l ?? void 0;
|
|
22502
22580
|
}
|
|
22503
22581
|
function detectPackageManager(root, pkg) {
|
|
22504
|
-
if (
|
|
22505
|
-
if (
|
|
22506
|
-
if (
|
|
22507
|
-
if (
|
|
22582
|
+
if (existsSync4(join4(root, "pnpm-lock.yaml"))) return "pnpm";
|
|
22583
|
+
if (existsSync4(join4(root, "bun.lockb")) || existsSync4(join4(root, "bun.lock"))) return "bun";
|
|
22584
|
+
if (existsSync4(join4(root, "yarn.lock"))) return "yarn";
|
|
22585
|
+
if (existsSync4(join4(root, "package-lock.json"))) return "npm";
|
|
22508
22586
|
const pm = pkg?.packageManager?.split("@")[0];
|
|
22509
22587
|
if (pm === "pnpm" || pm === "yarn" || pm === "bun" || pm === "npm") return pm;
|
|
22510
22588
|
return pkg ? "npm" : "none";
|
|
@@ -22532,7 +22610,7 @@ function detectFramework2(root, pkg, files, sources) {
|
|
|
22532
22610
|
}
|
|
22533
22611
|
function detectLanguage(root, pkg, files) {
|
|
22534
22612
|
const deps = { ...pkg?.devDependencies ?? {}, ...pkg?.dependencies ?? {} };
|
|
22535
|
-
if (
|
|
22613
|
+
if (existsSync4(join4(root, "tsconfig.json")) || deps.typescript) return "TypeScript";
|
|
22536
22614
|
if (files.some((f) => /\.(ts|tsx|mts|cts)$/.test(f.rel) && !f.rel.endsWith(".d.ts"))) return "TypeScript";
|
|
22537
22615
|
if (files.some((f) => /\.(js|jsx|mjs|cjs)$/.test(f.rel)) || pkg) return "JavaScript";
|
|
22538
22616
|
return "HTML";
|
|
@@ -22549,7 +22627,7 @@ function isBuildTimeFile(rel) {
|
|
|
22549
22627
|
return /\.config\.(js|ts|mjs|cjs|mts|cts)$/.test(base) || /^(scripts|tools|tests?|__tests__|e2e|cypress|prisma\/seed)\//.test(rel) || /\/(__tests__|__mocks__)\//.test(rel) || /\.(test|spec|stories)\.[a-z]+$/.test(base) || base.endsWith(".d.ts") || /^seed\.(js|ts|mjs)$/.test(base);
|
|
22550
22628
|
}
|
|
22551
22629
|
function trackedEnvFiles(root) {
|
|
22552
|
-
if (!
|
|
22630
|
+
if (!existsSync4(join4(root, ".git"))) return [];
|
|
22553
22631
|
try {
|
|
22554
22632
|
const out2 = execFileSync("git", ["ls-files", "-z"], { cwd: root, encoding: "utf8", timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] });
|
|
22555
22633
|
return out2.split("\0").filter((p) => {
|
|
@@ -22720,7 +22798,7 @@ function analyzeProject(root) {
|
|
|
22720
22798
|
}
|
|
22721
22799
|
if (!databases.some((d) => d.kind === "d1")) {
|
|
22722
22800
|
for (const name of ["wrangler.toml", "wrangler.json", "wrangler.jsonc"]) {
|
|
22723
|
-
if (!
|
|
22801
|
+
if (!existsSync4(join4(root, name))) continue;
|
|
22724
22802
|
const text = readFileSync4(join4(root, name), "utf8");
|
|
22725
22803
|
const at = text.search(/d1_databases/);
|
|
22726
22804
|
if (at < 0) continue;
|
|
@@ -22897,7 +22975,7 @@ function runInit(root, opts = {}) {
|
|
|
22897
22975
|
const created = [];
|
|
22898
22976
|
const kept = [];
|
|
22899
22977
|
const md = join5(root, "DEPLOYAI.md");
|
|
22900
|
-
if (
|
|
22978
|
+
if (existsSync5(md) && !opts.force) {
|
|
22901
22979
|
kept.push("DEPLOYAI.md");
|
|
22902
22980
|
} else {
|
|
22903
22981
|
writeFileSync3(md, DEPLOYAI_MD);
|
|
@@ -23199,7 +23277,7 @@ async function loginCommand(ctx, opts = {}) {
|
|
|
23199
23277
|
});
|
|
23200
23278
|
if (poll.status === "approved") {
|
|
23201
23279
|
if (!poll.token) throw new CliError(messages()("loginNoToken"), 1, "protocol");
|
|
23202
|
-
updateConfig({ token: poll.token, email: poll.email, apiUrl: ctx.apiUrl });
|
|
23280
|
+
updateConfig({ token: poll.token, email: poll.email, apiUrl: ctx.apiUrl, tokenApiUrl: ctx.apiUrl });
|
|
23203
23281
|
out();
|
|
23204
23282
|
out(poll.email ? t("loggedInAs", { email: poll.email }) : t("loggedIn"));
|
|
23205
23283
|
out(t("nextStep"));
|
|
@@ -23210,9 +23288,18 @@ async function loginCommand(ctx, opts = {}) {
|
|
|
23210
23288
|
}
|
|
23211
23289
|
throw new CliError(t("loginExpired"), 1, "auth_expired");
|
|
23212
23290
|
}
|
|
23213
|
-
function logoutCommand() {
|
|
23214
|
-
|
|
23215
|
-
|
|
23291
|
+
async function logoutCommand(ctx) {
|
|
23292
|
+
let revoked = true;
|
|
23293
|
+
if (ctx.config.token) {
|
|
23294
|
+
const apiUrl = (ctx.config.tokenApiUrl ?? ctx.apiUrl).replace(/\/+$/, "");
|
|
23295
|
+
try {
|
|
23296
|
+
await apiRequest({ apiUrl, config: ctx.config }, "/api/cli/logout", null, { method: "POST", body: {}, timeoutMs: 1e4 });
|
|
23297
|
+
} catch (e2) {
|
|
23298
|
+
revoked = e2 instanceof CliError && e2.category === "auth";
|
|
23299
|
+
}
|
|
23300
|
+
}
|
|
23301
|
+
updateConfig({ token: void 0, tokenApiUrl: void 0, email: void 0 });
|
|
23302
|
+
out(messages()(revoked ? "loggedOut" : "loggedOutLocalOnly"));
|
|
23216
23303
|
}
|
|
23217
23304
|
async function whoamiCommand(ctx) {
|
|
23218
23305
|
const me = await apiRequest(ctx, "/api/cli/me", MeResponse);
|
|
@@ -23301,8 +23388,21 @@ async function linkCommand(root, ctx, target, opts) {
|
|
|
23301
23388
|
return;
|
|
23302
23389
|
}
|
|
23303
23390
|
if (projects.length === 1) {
|
|
23304
|
-
|
|
23305
|
-
|
|
23391
|
+
const p = projects[0];
|
|
23392
|
+
const address = p.url ?? p.slug;
|
|
23393
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
23394
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
23395
|
+
let answer;
|
|
23396
|
+
try {
|
|
23397
|
+
answer = (await rl.question(t("linkConfirm", { name: p.name, address }))).trim().toLowerCase();
|
|
23398
|
+
} finally {
|
|
23399
|
+
rl.close();
|
|
23400
|
+
}
|
|
23401
|
+
if (answer === "y" || answer === "yes") return save(root, p);
|
|
23402
|
+
out(t("linkCancelled"));
|
|
23403
|
+
return;
|
|
23404
|
+
}
|
|
23405
|
+
throw new CliError([t("linkOnlyOne", { name: p.name, address }), ` npx deployai@latest link ${p.slug}`, ' npx deployai@latest link --create "<name>"'].join("\n"), 1, "usage");
|
|
23306
23406
|
}
|
|
23307
23407
|
const current = readProject(root)?.projectId;
|
|
23308
23408
|
out(t("projects"));
|
|
@@ -23482,6 +23582,7 @@ async function deployCommand(root, ctx, opts) {
|
|
|
23482
23582
|
if (!ctx.config.token) {
|
|
23483
23583
|
const guestToken = project?.projectId ? ctx.config.guestTokens?.[project.projectId] : void 0;
|
|
23484
23584
|
if (guestToken) return deployVersion(root, { ...ctx, config: { ...ctx.config, token: guestToken } }, opts, true);
|
|
23585
|
+
if (project?.projectId) throw new CliError(messages(root)("guestAccountSite"), 1, "auth");
|
|
23485
23586
|
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
23486
23587
|
if (!opts.guest && !(interactive && await askGuest(root))) {
|
|
23487
23588
|
throw new CliError(messages(root)("deployNotLoggedIn"), 1, "auth");
|
|
@@ -23493,7 +23594,7 @@ async function deployCommand(root, ctx, opts) {
|
|
|
23493
23594
|
try {
|
|
23494
23595
|
return await deployVersion(root, ctx, opts, false);
|
|
23495
23596
|
} catch (e2) {
|
|
23496
|
-
if (!claim2 || !(e2 instanceof CliError) || e2.category !== "forbidden") throw e2;
|
|
23597
|
+
if (!claim2 || !(e2 instanceof CliError) || e2.category !== "forbidden" && e2.category !== "not_found") throw e2;
|
|
23497
23598
|
const t = messages(root);
|
|
23498
23599
|
const url2 = ctx.config.guestClaims?.[claim2];
|
|
23499
23600
|
throw new CliError(url2 ? t("guestClaimFirst", { url: url2 }) : t("guestClaimFirstNoLink"), 1, "guest_unclaimed");
|
|
@@ -23540,6 +23641,7 @@ async function deployVersion(root, ctx, opts, guest) {
|
|
|
23540
23641
|
out(rows([[t("version"), `v${res.number}`], [t("queue"), queueText(res.queuePosition, root)], [t("address"), res.previewUrl]]));
|
|
23541
23642
|
out();
|
|
23542
23643
|
out(t("goesLive"));
|
|
23644
|
+
pageHint(res, root);
|
|
23543
23645
|
return;
|
|
23544
23646
|
}
|
|
23545
23647
|
out(
|
|
@@ -23553,6 +23655,15 @@ async function deployVersion(root, ctx, opts, guest) {
|
|
|
23553
23655
|
out(t("nextStep"));
|
|
23554
23656
|
out(t("followBuild"));
|
|
23555
23657
|
out(t("thenPromote", { n: res.number }));
|
|
23658
|
+
pageHint(res, root);
|
|
23659
|
+
}
|
|
23660
|
+
function pageHint(res, root) {
|
|
23661
|
+
if (!res.page) return;
|
|
23662
|
+
const t = messages(root);
|
|
23663
|
+
out();
|
|
23664
|
+
if (res.page.files > 40) out(t("heavyPage", { n: res.page.files }));
|
|
23665
|
+
if (res.page.prefetches) out(t("prefetchPage"));
|
|
23666
|
+
out(t("speedHint", { url: res.previewUrl.split("?")[0] }));
|
|
23556
23667
|
}
|
|
23557
23668
|
async function deployGuest(root, ctx, opts) {
|
|
23558
23669
|
const message = (opts.message ?? "").trim() || "first version";
|
|
@@ -23604,7 +23715,7 @@ async function claimCommand(root, ctx, opts) {
|
|
|
23604
23715
|
|
|
23605
23716
|
// src/commands/samples.ts
|
|
23606
23717
|
import { createInterface as createInterface3 } from "readline/promises";
|
|
23607
|
-
import { existsSync as
|
|
23718
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readdirSync as readdirSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
23608
23719
|
import { dirname, join as join6, relative, resolve, sep } from "path";
|
|
23609
23720
|
import { gunzipSync } from "zlib";
|
|
23610
23721
|
var SAMPLES = [
|
|
@@ -23626,7 +23737,7 @@ function listSamples(apiUrl) {
|
|
|
23626
23737
|
out(`See them live: ${apiUrl}/samples`);
|
|
23627
23738
|
}
|
|
23628
23739
|
function filesIn(dir) {
|
|
23629
|
-
return
|
|
23740
|
+
return existsSync6(dir) ? readdirSync3(dir).filter((f) => !IGNORED.has(f)) : [];
|
|
23630
23741
|
}
|
|
23631
23742
|
function freeFolder(cwd, key) {
|
|
23632
23743
|
for (let n2 = 1; ; n2++) {
|
|
@@ -23709,7 +23820,7 @@ async function samplesCommand(cwd, ctx, key, opts = {}) {
|
|
|
23709
23820
|
}
|
|
23710
23821
|
const written = await downloadSample(ctx, sample.key, root);
|
|
23711
23822
|
const base = resolve(root);
|
|
23712
|
-
const hasPackage =
|
|
23823
|
+
const hasPackage = existsSync6(join6(base, "package.json"));
|
|
23713
23824
|
out(base === resolve(cwd) ? `Downloaded the ${sample.key} sample: ${written} files.` : `Downloaded the ${sample.key} sample into the new folder ${relative(cwd, base)}: ${written} files. Work in that folder from now on.`);
|
|
23714
23825
|
out("");
|
|
23715
23826
|
const t = messages(base);
|
|
@@ -23781,18 +23892,23 @@ async function versionsCommand(root, ctx) {
|
|
|
23781
23892
|
const sorted = [...versions].sort((a, b) => b.number - a.number);
|
|
23782
23893
|
out("Versions");
|
|
23783
23894
|
for (const v of sorted) {
|
|
23895
|
+
const status = v.status === "replaced" ? stateName("replaced", root) : v.status;
|
|
23784
23896
|
const cols = [
|
|
23785
23897
|
`v${v.number}`.padEnd(6),
|
|
23786
23898
|
(v.isLive ? "live" : "").padEnd(6),
|
|
23787
|
-
|
|
23899
|
+
status.padEnd(10),
|
|
23788
23900
|
shortDate(v.createdAt).padEnd(18),
|
|
23789
23901
|
formatBytes(v.sizeBytes).padEnd(10),
|
|
23790
23902
|
v.message
|
|
23791
23903
|
];
|
|
23792
23904
|
out(` ${cols.join("")}`);
|
|
23793
23905
|
if (v.error) out(` ${v.error}`);
|
|
23906
|
+
if (v.migrationStatus === "waiting") out(` ${messages(root)("sqlWaitingLine", { url: versionsPage(ctx, projectId) })}`);
|
|
23794
23907
|
}
|
|
23795
23908
|
}
|
|
23909
|
+
function versionsPage(ctx, projectId) {
|
|
23910
|
+
return `${ctx.apiUrl}/project/${encodeURIComponent(projectId)}/versions`;
|
|
23911
|
+
}
|
|
23796
23912
|
async function changeLiveCommand(root, ctx, version2, kind) {
|
|
23797
23913
|
requireToken(ctx);
|
|
23798
23914
|
const projectId = linkedProjectId(root);
|
|
@@ -23820,6 +23936,10 @@ async function statusCommand(root, ctx) {
|
|
|
23820
23936
|
[t("queue"), s.queue.running ? t("buildingNow") : s.queue.position > 0 ? queueText(s.queue.position, root) : t("idle")]
|
|
23821
23937
|
])
|
|
23822
23938
|
);
|
|
23939
|
+
if (s.latest?.migrationStatus === "waiting") {
|
|
23940
|
+
out();
|
|
23941
|
+
out(t("sqlWaitingLine", { url: versionsPage(ctx, projectId) }));
|
|
23942
|
+
}
|
|
23823
23943
|
if (s.latest?.status !== "failed") return;
|
|
23824
23944
|
out();
|
|
23825
23945
|
out(t("buildFailed", { n: s.latest.number }));
|
|
@@ -23835,7 +23955,7 @@ async function statusCommand(root, ctx) {
|
|
|
23835
23955
|
|
|
23836
23956
|
// src/commands/start.ts
|
|
23837
23957
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
23838
|
-
import { existsSync as
|
|
23958
|
+
import { existsSync as existsSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
23839
23959
|
import { join as join7, relative as relative2, resolve as resolve2 } from "path";
|
|
23840
23960
|
var REASONS = { start_not_found: "startNotFound", start_expired: "startExpired", start_used_up: "startUsedUp" };
|
|
23841
23961
|
var reason = (code) => messages(process.cwd())(REASONS[code] ?? "startNotFound");
|
|
@@ -23874,7 +23994,7 @@ async function startCommand(cwd, ctx, id, opts = {}) {
|
|
|
23874
23994
|
if (sample && !sameSite) {
|
|
23875
23995
|
const written = await downloadSample(ctx, sample.key, root);
|
|
23876
23996
|
done.push(t("startDownloaded", { key: sample.key, n: written }));
|
|
23877
|
-
if (
|
|
23997
|
+
if (existsSync7(join7(root, "package.json"))) {
|
|
23878
23998
|
if (opts.install !== false && install(root)) done.push(t("startInstalled"));
|
|
23879
23999
|
else steps.unshift({ cmd: "npm install", say: "Installs the sample's packages." });
|
|
23880
24000
|
}
|
|
@@ -23945,6 +24065,25 @@ async function addonsCommand(root, ctx) {
|
|
|
23945
24065
|
}
|
|
23946
24066
|
out(`Next: ${r.next}. Ask the site owner if they want to start it now, then run: npx deployai@latest addon next`);
|
|
23947
24067
|
}
|
|
24068
|
+
async function addonBuyCommand(root, ctx, key) {
|
|
24069
|
+
requireToken(ctx);
|
|
24070
|
+
const projectId = linkedProjectId2(root);
|
|
24071
|
+
const name = key.trim().toLowerCase();
|
|
24072
|
+
const r = await apiRequest(ctx, `/api/cli/addons?projectId=${encodeURIComponent(projectId)}`, AddonsResponse);
|
|
24073
|
+
if (!r.open) {
|
|
24074
|
+
out("The DeployAI marketplace is not open yet. Add-ons open soon.");
|
|
24075
|
+
return;
|
|
24076
|
+
}
|
|
24077
|
+
const a = r.addons.find((x) => x.key === name);
|
|
24078
|
+
if (!a) throw new CliError(`No add-on named ${name}. See the list: npx deployai@latest addons`, 1, "unknown");
|
|
24079
|
+
if (a.owned) {
|
|
24080
|
+
out(`This site already has ${a.name}. To run it: npx deployai@latest addon run ${a.key}`);
|
|
24081
|
+
return;
|
|
24082
|
+
}
|
|
24083
|
+
if (!a.buyUrl) throw new CliError(`${a.name} is not for sale right now.`, 1, "not_for_sale");
|
|
24084
|
+
out(`Send this link to the site owner. They pay once for this site, then run: npx deployai@latest addon run ${a.key}`);
|
|
24085
|
+
out(a.buyUrl);
|
|
24086
|
+
}
|
|
23948
24087
|
function printAddon(a) {
|
|
23949
24088
|
out(`DeployAI add-on ${a.position} of ${a.total}: ${a.name} (${a.key}, run ${a.runId}).`);
|
|
23950
24089
|
out("Follow these instructions step by step, with the site owner:");
|
|
@@ -24079,7 +24218,7 @@ function buildProgram() {
|
|
|
24079
24218
|
program.command("start").description("start from the line copied on the DeployAI site: prepares this folder with every choice made there, then prints the steps").argument("<id>", "the code from the copied line").option("--here", "put a new site in this folder even when it has files").option("--no-install", "do not run npm install for the sample").action((id, opts, cmd) => startCommand(root(cmd), ctx(cmd), id, opts));
|
|
24080
24219
|
program.command("samples").description("list the official sample sites, or download one (into this folder when empty, else a new one)").argument("[name]", "landing, business, form, crud, shop or admin").argument("[folder]", "put the sample in this folder (default: this one when empty, else asks or makes a new one)").option("--force", "write into this folder even when it has files").action((name, folder, opts, cmd) => samplesCommand(root(cmd), ctx(cmd), name, { ...opts, folder }));
|
|
24081
24220
|
program.command("login").description("log in through the browser").action((_opts, cmd) => loginCommand(ctx(cmd), { root: root(cmd) }));
|
|
24082
|
-
program.command("logout").description("
|
|
24221
|
+
program.command("logout").description("cancel the login token and remove it from this computer").action((_opts, cmd) => logoutCommand(ctx(cmd)));
|
|
24083
24222
|
program.command("whoami").description("show the logged in user").action((_opts, cmd) => whoamiCommand(ctx(cmd)));
|
|
24084
24223
|
program.command("telemetry").description("show what is sent, or turn telemetry on or off").argument("[action]", "status, on or off", "status").action((action) => telemetryCommand(action));
|
|
24085
24224
|
program.command("link").description("link this folder to a DeployAI project").argument("[project]", "project slug or id").option("--create <name>", "create a new project and link it").action(
|
|
@@ -24096,6 +24235,7 @@ function buildProgram() {
|
|
|
24096
24235
|
const addon = program.command("addon").description("run the add-ons of this site, one at a time");
|
|
24097
24236
|
addon.command("next").description("print the next add-on for your agent").action((_opts, cmd) => addonNextCommand(root(cmd), ctx(cmd)));
|
|
24098
24237
|
addon.command("run").description("print one add-on by name").argument("<name>", "the add-on name, as npx deployai@latest addons lists it").action((name, _opts, cmd) => addonRunCommand(root(cmd), ctx(cmd), name));
|
|
24238
|
+
addon.command("buy").description("print the link where the site owner buys an add-on").argument("<name>", "the add-on name, as npx deployai@latest addons lists it").action((name, _opts, cmd) => addonBuyCommand(root(cmd), ctx(cmd), name));
|
|
24099
24239
|
addon.command("done").description("save the report of a finished add-on and print the next one").argument("<runId>", "the run id printed at the top of the add-on").option("--status <status>", "done, failed or skipped", "done").option("--report <file>", "the JSON report, for example .deployai/addon-report.json").action((runId, opts, cmd) => addonDoneCommand(root(cmd), ctx(cmd), runId, opts));
|
|
24100
24240
|
program.command("speed").description("Google PageSpeed test of a page: lab results, real visitor data, biggest opportunities").argument("<url>", "the page address").option("--desktop", "test a desktop load instead of a phone").action((url2, opts, cmd) => speedCommand(ctx(cmd), url2, opts));
|
|
24101
24241
|
const env = program.command("env").description("the site's environment variables: secrets by default, never shown again");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deployai",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.3",
|
|
4
4
|
"description": "Check a site built with an AI editor, see what has to change, and publish it to DeployAI. Hebrew first.",
|
|
5
5
|
"keywords": ["deployai", "deploy", "hosting", "cli", "ai", "claude-code", "cursor", "copilot", "codex", "antigravity", "static-site", "astro", "vite", "hebrew", "israel"],
|
|
6
6
|
"homepage": "https://deployai.co.il/developers",
|