其他
通过 Cargo Hosting 发布托管 Web…
适用场景:需要用 Cargo Hosting 把静态前端或 serverless edge worker 放到互联网,并管理部署、促销上线、环境变量、密钥、本地调试、自定义域名和索引。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 35/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 38/100 ×0.15
适用场景
通过 Cargo Hosting 发布托特定
解决思路
- 用 folders 组织 apps/workers 时,使用 `cargo-workspace-management`(`folder …`);本技能中的 `--folder-uuid` flags 消费那些 folder UUIDs。
- 全局安装 CLI:`npm install -g @cargo-ai/cli`;如果不能全局安装,则每条命令前加 `npx @cargo-ai/cli`。
- 登录:`cargo-ai login --email you@company.com`(邮件验证码,无浏览器,首次使用会创建账号);替代方式 `--oauth`(浏览器)或 `--token <api-token>`(CI)。
- 在任何写操作前运行 `cargo-ai whoami` 确认当前 workspace。
- 所有命令向 stdout 输出 JSON;失败以非零退出并返回 `{"errorMessage": "..."}`;任何创建 run 或 batch 的异步操作传 `--wait-until-finished` 或轮询匹配的 `get`。
- 安装完整技能包时,参考 `../cargo/references/prerequisites.md` 获取 CLI 版本 pin、token scopes 和 admin-only surface。
- 遵循同一生命周期:`init`(本地脚手架)→ `create`(slot + slug)→ `deployment create`(构建+上传)→ `deployment promote`(上线)。
- 用 `hosting app init <dir>` 或 `hosting worker init <dir>` 从模板脚手架本地项目。
- 用 `hosting app create --name --slug`(或 worker 对应命令)在工作区创建 slot,取得 `appUuid` 或 `workerUuid`;`--slug` 会成为子域一部分,并且必须在 workspace 内唯一。
- 可选:接线本地开发。app 用 `hosting app env <appUuid>` 打印本地副本需要的 `.env.local` 行(Cargo OAuth + workspace + app UUID + API URL)。worker 在脚手架中运行 `npm run dev`;调用 Cargo API 的 worker 在首次部署前需要 `CARGO_API_TOKEN` secret。
- 部署:`hosting deployment create --app-uuid <uuid> --source <dir>` 上传源码;后端在沙箱中构建:app 先 `npm ci --ignore-scripts`,再运行 app 自己的 `build` 脚本,或没有则运行框架默认构建;worker 打包 entrypoint;返回 `deploymentUuid`。
- 上线:`hosting deployment promote --uuid <deploymentUuid>` 把 live URL 指向该构建。
- 部署会异步构建——在 promote 前轮询 `hosting deployment get <uuid>` 直到状态为终态。
- live host 是 `<slug>-<workspace UUID 前 8 字符>` 加 hosting 根域;app 和 worker 有不同根域:生产 app 是 `https://<slug>-<ws>.app.getcargo.run`,worker 是 `https://<slug>-<ws>.worker.getcargo.run`;workspace 后缀使 host 全局唯一。
- 不要手工拼 URL;从 `create` 或 `get` 返回的 `url` 读取,因为根域随环境不同。
- 每个 deployment 在 promoted 前有一个 preview host:`https://deployment-<deploymentUuid>.<root>`。
- 因为 app 和 worker 根域不同,app 调 worker 永远是跨源请求;没有选项能让它们同源,所以 worker 必须响应 CORS;参考 `references/examples/workers.md` 中 app + worker 模式。
- 发现 app:`cargo-ai hosting app list`(可用 `--folder-uuid <uuid>` 过滤);`cargo-ai hosting app get <uuid>`。
- 本地脚手架 app:`cargo-ai hosting app init ./my-app --list-templates` 查看可用模板,然后 `cargo-ai hosting app init ./my-app --template blank --name "My App"`。
- 创建 app slot:`cargo-ai hosting app create --name "My App" --slug my-app --folder-uuid <folder-uuid>`;响应中的 `url` 是 live host。
- 打印本地开发 `.env.local`:`cargo-ai hosting app env <app-uuid>`;非生产 API 用 `cargo-ai hosting app env <app-uuid> --api-url https://api.getcargo.io`。
- 更新/移除 app:`cargo-ai hosting app update --uuid <app-uuid> --name "Renamed"`;`cargo-ai hosting app update --uuid <app-uuid> --folder-uuid null` 把资源移回 workspace root;`cargo-ai hosting app remove <app-uuid>` 同时移除其 deployments。
- app 模板:`blank`(最小起点)、`territories-overview`(只读 territories 网格,演示 `useCargoApi()` + react-query)、`public-site`(公开、可索引站点,用自己的 build 脚本预渲染每个路由,并发布 `robots.txt` + `sitemap.xml`);用 `app init <dir> --list-templates` 查看当前列表。
- 如果 `package.json` 声明了 `build` 脚本,Cargo 会运行它,并且该脚本拥有整个构建;Cargo 不会在它之前或之后运行任何东西,所以脚本必须产出 client bundle 以及额外内容,例如预渲染 HTML。没有 `build` 脚本时,运行检测到的框架默认命令。
- 框架默认构建表:Vite 和未检测到任何框架时用 `vite build`,输出 `dist`,公开环境变量前缀 `VITE_`;Next.js(static export)用 `next build`,输出 `out`,前缀 `NEXT_PUBLIC_`;Astro 用 `astro build`,输出 `dist`,前缀 `PUBLIC_`;SvelteKit 用 `svelte-kit build`,输出 `build`,前缀 `PUBLIC_`;Nuxt 用 `nuxt generate`,输出 `.output/public`,前缀 `NUXT_PUBLIC_`;Gatsby 用 `gatsby build`,输出 `public`,前缀 `GATSBY_`;Create React App 用 `react-scripts build`,输出 `build`,前缀 `REACT_APP_`。
- 构建输出必须落在该框架的输出目录并包含 `index.html`,否则构建失败;未知路径回退到该 shell。
- 构建脚本当前做的任何事都会在每次部署时运行,包括 `tsc` pass、不同的 `--mode`、`prebuild`/`postbuild` hooks;在那里失败会让部署失败;live deployment 继续服务,因为 promotion 只在成功构建后进行。
- Cargo 无法使用的 `build` 脚本会静默回退:包括无法解析的 `package.json`、空脚本或非字符串 entry;部署仍会变绿,只有构建日志说明原因,所以当预渲染步骤看起来被跳过时检查构建日志。
- 平台值会在每个公开前缀下注入:Vite app 读 `VITE_CARGO_API_URL`,Next.js app 读 `NEXT_PUBLIC_CARGO_API_URL`;使用 `build` 脚本时,它们也作为真实 process env vars 传入,因此普通 Node 预渲染步骤能看到它们;用户 env 值会从构建日志中脱敏。
- app 只读取 key 以公开前缀开头的 env vars:`VITE_`、`NEXT_PUBLIC_`、`PUBLIC_`、`NUXT_PUBLIC_`、`GATSBY_` 或 `REACT_APP_`;任何这些前缀在任意框架下都可用;它们来自 workspace env vars 和 app-level entries(`POST /v1/hosting/env-vars` 带 `"kind":"app"`,或 CDK `defineApp({ env })`);每一个都会编译进任何人都能下载的 bundle。
- app env vars 不能是 secret:API 用 `secretNotSupportedForApp` 拒绝 `isSecret: true`,CDK `defineApp` 对 `secret()` 值抛错,secret workspace entries 永远不会到达 app build;凭据应放在 app 调用的 worker 中。
- 匹配平台 key 的 key 在任意前缀下都保留(`*_CARGO_API_URL`、`*_CARGO_WORKSPACE_UUID`、`*_APP_BASE_PATH` 等)。
- app env var 的值在构建时烘焙,所以更改需要新的 deploy + promote。
- Cargo 拥有的 host 是 `noindex`:默认 `*.app.getcargo.run` host 和每个 `deployment-<uuid>` preview 都返回 `X-Robots-Tag: noindex`,所以 app 只有在自定义域名上才可索引。CLI 1.0.96 没有 CLI 命令附加自定义域名,使用 API:`curl -X POST https://api.getcargo.io/v1/hosting/custom-domains -H "authorization: Bearer $CARGO_API_TOKEN" -H "content-type: application/json" -d '{"kind":"app","appUuid":"<uuid>","hostname":"www.example.com"}'`,返回要添加的 DNS records:certificate validation records + hostname 的 `cnameTarget`。
- 刷新自定义域名状态:`curl -X POST https://api.getcargo.io/v1/hosting/custom-domains/<domain-uuid>/refresh-status -H "authorization: Bearer $CARGO_API_TOKEN"`,重复直到 status 为 `active`。
- 自定义域名 hostname 需要至少三个 label,所以附加 `www.example.com`,不是 `example.com`。
- worker 也接受自定义域名(`"kind":"worker","workerUuid":…`);分开的 hostname 仍然是分开的 origin,所以 app → worker CORS 仍适用。
- 搜索索引还需要每个 URL 的真实 HTML:在 `build` 脚本中预渲染(`public-site` 模板展示方法);将预渲染路由链接为 `.html` 路径:`/about.html` 提供预渲染文件,而 `/about` 回退到 SPA shell;发布 `public/robots.txt` + `public/sitemap.xml`,并在每个预渲染 head 中放置 title、description、canonical 和 Open Graph tags。
- 托管的 app 从不返回 404;未知路径以 `200` 提供 SPA shell,所以客户端 not-found 视图应自行设置 `<meta name="robots" content="noindex">`。
- 基于 `CargoRefineApp` 的 app 需要 Cargo 登录且不能索引;公开站点渲染自己的 tree。
- 不会替你向搜索引擎提交内容;在 Search Console 提交 sitemap。
- worker 使用与 app 相同的命令形状,把 `app` 换成 `worker`:`cargo-ai hosting worker list`(可用 `--folder-uuid <uuid>` 过滤);`cargo-ai hosting worker get <uuid>`。
- 脚手架 worker:`cargo-ai hosting worker init ./my-worker --list-templates`;`cargo-ai hosting worker init ./my-worker --template blank --name "My Worker"`。
- 创建 worker slot:`cargo-ai hosting worker create --name "My Worker" --slug my-worker --folder-uuid <folder-uuid>`。
- 更新/移除 worker:`cargo-ai hosting worker update --uuid <worker-uuid> --name "Renamed"`;`cargo-ai hosting worker remove <worker-uuid>` 同时移除其 deployments。
- worker 模板:`blank`(自动 OpenAPI spec + Swagger UI)和 `custom-integration`(Cargo Custom Integration — manifest / actions / extractors / autocompletes / dynamic schemas)。
- worker entrypoint:构建打包第一个存在的 `src/index.ts`、`src/index.js`、`index.ts`、`index.js`,都不存在则失败;`.mjs`、`.mts`、`.cjs` entrypoints 不会被拾取,重命名为 `.js`/`.ts`;ES module syntax 在 `.js` 中可用,因为脚手架的 `package.json` 设置 `"type": "module"`。
- worker 从 `c.env.KEY`(Hono context)或 `fetch(request, env)` 的 `env` 参数读取配置;三个来源:platform bindings 自动提供 `CARGO_API_URL`、`CARGO_WORKSPACE_UUID`、`CARGO_WORKER_UUID`;workspace env vars 用 `cargo-ai workspaceManagement envVar create --key K [--secret]` 设置,会到达 workspace 中每个 worker(apps 只得到非 secret、public-prefixed 的);worker env vars 用 CDK `defineWorker({ env })` 或 `POST /v1/hosting/env-vars`(CLI 1.0.96 没有 hosting CLI 命令)设置,只到达该 worker,且 worker entry 覆盖同名 workspace entry。
- `CARGO_API_TOKEN` 不会自动注入;`createCargoApi(c.env)` 在提供前会抛 `Missing CARGO_API_TOKEN…`。在首次部署前铸造 workspace API token 并存为 secret:`cargo-ai workspaceManagement token create --name "worker: my-worker"`(值只显示一次);`export CARGO_API_TOKEN=<token value>`;`cargo-ai workspaceManagement envVar create --key CARGO_API_TOKEN --secret --description "Cargo API token for hosted workers"`(省略 `--value` → 从 `$CARGO_API_TOKEN` 读取)。
- workspace entry 会给每个 worker 该 token;如果只有一个 worker 应持有它,改为在该 worker 上设置。CDK:`defineWorker("my-worker", { path, env: { CARGO_API_TOKEN: secret("CARGO_API_TOKEN") } })`。API:`POST /v1/hosting/env-vars` 带 `{"kind":"worker","workerUuid":"<uuid>","key":"CARGO_API_TOKEN","value":"…","isSecret":true}`;从 TypeScript 是 `api.hosting.envVars.create(…)`,`list` 接收 `{ workerUuid }`。
- env var 值在部署时捕获,不是实时读取;bindings 在 deployment promoted 时附加,非 secret 值也会编译进 bundle 为 `process.env.KEY`;添加或改变变量后再次运行 `deployment create` 和 `promote`;运行中的 worker 在此之前保持旧值。
- secret 从不进入 bundle;secret 绑定为加密运行时值;只有非 secret 值会被编译,bundle 可从 per-deployment preview host 下载,所以敏感信息必须 `--secret` / `isSecret: true`。
- 两个 worker 模板都带 `dev.ts` harness:`npm run dev` 在 Node 下服务 `src/index.ts`,热重载于 `http://localhost:8787`(用 `PORT` 覆盖);`dev.ts` 永远不会部署。
- 本地没有 platform bindings,所以 `c.env` 为空;`createCargoApi` 回退到 `process.env`,所以在 `npm run dev` 前在 shell 导出 `CARGO_API_TOKEN`(非生产 API 还要 `CARGO_API_URL`);你自己的变量也需要在代码中做同样回退。
- `manifest.json` 的 `outboundAllowlist` 和 cron triggers 本地不执行;在 deployment 上测试它们。
- 在 `dev.ts` 存在之前脚手架的项目可从一个新的 `hosting worker init` 复制它,以及 `dev` 脚本和 `@hono/node-server` + `tsx` dev dependencies。
- `createWorker()` 捕获 Cargo 分派的每个请求期间的 `console.log/info/warn/error/debug` 并送到 worker logs(每请求最多 50 行);未捕获错误会带 stack 记录并以裸 `500` 回答。
- 被捕获的错误不留痕迹;如果 route 捕获异常并返回自己的 sanitized response,例如 `502 "The data provider is unavailable"`,日志只有 HTTP line;在 sanitize 前记录错误:`try { return c.json(await loadData(createCargoApi(c.env))); } catch (err) { console.error(err); return c.json({ error: "The data provider is unavailable." }, 502); }`。
- CLI 1.0.96 时日志可在 web app 或 API 读取:`POST /v1/hosting/logs/list` 带 `{"workerUuid":"<uuid>","levels":["error"],"limit":50}`,或从 TypeScript 用 `api.hosting.log.list(…)`;还按 `runUuid`、`search`、`occurredAfter`/`occurredBefore` 过滤;CLI 还没有 logs 命令。
- deployment 只属于一个 app 或一个 worker(`--app-uuid` 和 `--worker-uuid` 互斥)。
- 列出/检查 deployment:`cargo-ai hosting deployment list --app-uuid <uuid>` 或 `--worker-uuid <uuid>`;`cargo-ai hosting deployment get <deployment-uuid>`;`cargo-ai hosting deployment get-promoted --app-uuid <uuid>` 查看当前 live。
- 构建并上传本地源码目录(指向 package root,不是 `dist/`):`cargo-ai hosting deployment create --app-uuid <uuid> --source ./my-app`;`cargo-ai hosting deployment create --worker-uuid <uuid> --source ./my-worker`;默认忽略 `node_modules,dist,build,.git,.next`,用 `--ignore "a,b,c"` 覆盖。
- 上线:`cargo-ai hosting deployment promote --uuid <deployment-uuid>`。
- `--slug` 每个 workspace 唯一,live host 是 `<slug>-<workspace prefix>.<root>`,app 和 worker 根域不同;使用 `get` 返回的 `url` 而不是手工拼接;重复 slug 会在 `create` 时以 `duplicateSlug` 失败。
- app 调 worker 是跨源;worker 必须为 app 的 origin 发送 CORS headers;不存在 same-origin mount。
- `CARGO_API_TOKEN` 由你提供;它从不自动注入,没有它 `createCargoApi` 会抛错;在需要它的部署前设为 secret(workspace 或 worker env var)。
- Env var 更改需要新的 deploy + promote;值在 promote 时绑定,非 secret 编译进 bundle,所以编辑变量直到下一次 deployment live 才生效。
- 在 sanitize 前 log;只有未捕获错误带 stack 到日志;返回友好消息的 `catch` 必须首先 `console.error(err)`,否则原因丢失。
- Deploying ≠ going live;`deployment create` 构建并上传,只有 `deployment promote` 该 deployment 才改变 URL;用 `deployment get-promoted` 查看当前 live。
- `--source` 是 package root,不是 `dist/`;构建在 Cargo sandbox 运行:app 先 `npm ci --ignore-scripts`,再运行 app 的 `build` 脚本或框架默认;worker 打包 entrypoint;交付预构建 `dist/` 不会工作。
- App env vars 是公开且从不 secret;它们编译进 bundle,`isSecret` 被拒绝;把凭据放在 worker。
- Cargo-owned hosts 是 `noindex`;公开站点需要自定义域名(1.0.96 仅 API)和预渲染 HTML 才可索引。
- Builds 异步——在 promote 前轮询 `deployment get` 到 terminal。
- `--app-uuid` / `--worker-uuid` 在 `deployment create`、`deployment list`、`deployment get-promoted` 上互斥;只传一个。
- `remove` 级联——移除 app 或 worker 也移除其所有 deployments。
- `update --folder-uuid null`(字面字符串 `null`)把资源移回 workspace root。
- Hosting 每月每资源消耗 credits;每个 app/worker 有 `chargedUntil`,每小时 sweep 一次推进一个月,所以 live app/worker 会持续计费 hosting credits——不再服务就 `remove` 资源;通过 `cargo-billing` 跟踪消耗。
- `deployment create` 启动沙箱构建;deployment 的 `status` 从 `pending` → `building` → `success`(或 `error` / `cancelled`);轮询直到 terminal,然后 promote `success` 的那个。
- 轮询命令:`cargo-ai hosting deployment get <deployment-uuid>`,每约 2–5 秒直到 status terminal。
- Terminal statuses 是 `success`、`error`、`cancelled`——只 promote `success` deployment;遇到 `error`,读 deployment 的 `errorMessage`(以及 `buildLogS3Filename`)诊断构建;一般轮询模式参考 `../cargo-orchestration/references/polling.md`。
- 端到端 walkthroughs 见 `references/examples/apps.md`、`references/examples/workers.md`、`references/examples/deployments.md`;JSON response structures 见 `references/response-shapes.md`;常见错误和修复见 `references/troubleshooting.md`。
- 每个命令支持 `--help`:`cargo-ai hosting app create --help`、`cargo-ai hosting deployment create --help`。
适用边界 · 注意事项
- 当 app 或 worker 应作为提交到工作区的代码声明时,改用 `cargo-project`。
- 未安装 `@cargo-ai/cli`、没有 Cargo 账号,或不能使用 Cargo 托管服务时。
- 需要 app 与 worker 同源挂载且不能为 worker 添加 CORS 时。