# @everystack/cli 中文文档

规范地址：https://npmcn.com/package/%40everystack/cli/

版本：0\.4\.107
npm 元数据更新时间：2026-11-01T01:30:10.034Z
中文译文更新时间：2026-11-01T02:49:58.202Z
软件包许可：AGPL-3\.0-only

本文由上游 README 机器翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40everystack/cli
原文对照：https://npmcn.com/package/%40everystack/cli/?lang=original
项目主页：https://github.com/scalable-technology/everystack#readme
源码仓库：https://github.com/scalable-technology/everystack

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：3.1 MB，217 个文件
- 模块格式：CommonJS
- TypeScript 类型：包内自带
- 运行依赖：18 个
- peer 依赖：react 19\.2\.0，postgres 3\.4\.9，drizzle-orm 0\.41\.0，expo-updates 55\.0\.21，react-native 0\.83\.6，@everystack/server \>=0\.4\.0，@aws-sdk/client-cloudwatch 3\.1053\.0，@aws-sdk/s3-request-presigner 3\.1053\.0
- 首次发布：2026-05-15T04:42:36.138Z
- 最新版本发布：2026-11-01T01:30:09.854Z
- 已发布版本数：160（近 12 个月 160 个）

## 中文简介

博览会应用的CLI和OTA更新

## 安装

```sh
npm install @everystack/cli
```

也可以使用：`pnpm add @everystack/cli`、`yarn add @everystack/cli`、`bun add @everystack/cli`

## README

# @everystack / cli

博览会应用的CLI和OTA更新。数据库管理(`db:migrate`， `db:seed`)， OTA发布，Expo Updates协议（v0/v1），可插拔存储，RSA-SHA256代码签名和通道。

## 安装

```bash
pnpm add @everystack/cli drizzle-orm structured-headers
```

对于S3存储：

```bash
pnpm add @aws-sdk/client-s3
```

## 入口点

| 进口 | 描述 |
| --- | --- |
| `@everystack/cli` | 服务器：处理程序、存储适配器 |
| `@everystack/cli/client` | 客户端：UpdatesProvider， AppStateUpdateProvider |
| `@everystack/cli/schema` | 细雨表（渠道、发布、资产） |

## 服务器:处理程序

创建一个实现Expo Updates清单协议的Web标准处理程序：

```typescript
import { createUpdatesHandler, createStorage } from '@everystack/cli';
import { db } from './db';

const storage = createStorage({
  type: 'filesystem',
  directory: './updates',
});

const handler = createUpdatesHandler({
  db,
  storage,
  baseUrl: 'https://myapp.com',
  basePath: '/api/updates',
  defaultChannel: 'production',
  auth: {
    verifyToken: async (token) => verifyJWT(token),
  },
  privateKey: process.env.CODE_SIGNING_PRIVATE_KEY, // PEM for RSA-SHA256
});
```

### 越来越多

```typescript
// app/api/updates/[...path]+api.ts
export function GET(request: Request) { return handler(request); }
export function POST(request: Request) { return handler(request); }
```

### 处理程序端点

处理程序提供：

-   **清单要求** - Expo以多部分/混合格式更新协议v0/v1清单响应
-   **资产下载** -二进制资产从您配置的存储
-   **发布端点** —经过认证的新版本上传（CLI使用）

### 处理程序选项

```typescript
interface UpdatesHandlerOptions {
  db: DrizzleDb;                // Drizzle instance
  storage: StorageAdapter;      // Filesystem or S3
  baseUrl: string;              // Public URL (for asset references in manifests)
  basePath?: string;            // URL prefix to strip
  auth?: {
    verifyToken: (token: string) => Promise<Record<string, unknown> | null>;
  };
  privateKey?: string;          // PEM for RSA-SHA256 code signing
  defaultChannel?: string;      // Default channel (default: 'production')
}
```

## 存储适配器

### 文件系统

```typescript
import { createStorage } from '@everystack/cli';

const storage = createStorage({
  type: 'filesystem',
  directory: './updates',
});
```

### S3

```typescript
const storage = createStorage({
  type: 's3',
  bucket: 'my-updates-bucket',
  region: 'us-east-1',
  endpoint: 'https://s3.us-east-1.amazonaws.com', // Optional
});
```

S3客户端为 **默认有界** 所以单个调用永远不会挂起：a 连接超时（3秒），每个请求超时（10秒），有界重试（3次尝试）， 还有一个帽子 `list()` （有页面挡板的页面）。这是最重要的 可观察性卷起- S3 503风暴下的无界客户端阻塞直到 Lambda自己的超时，并且每个挂起的调用都固定一个并发插槽，因此 它可以耗尽账户池并使它所观察到的应用程序饿死。

每个字段通过调优 `options`，或通过env var覆盖超时/重试 无需更改代码（env可以方便地在Lambda上转动旋钮）：

```typescript
const storage = createStorage({
  type: 's3',
  bucket: 'my-updates-bucket',
  region: 'us-east-1',
  options: {
    connectionTimeoutMs: 3000, // env: EVERYSTACK_S3_CONNECT_TIMEOUT_MS
    requestTimeoutMs: 10000,    // env: EVERYSTACK_S3_REQUEST_TIMEOUT_MS
    maxAttempts: 3,             // env: EVERYSTACK_S3_MAX_ATTEMPTS
    listMaxKeys: 1000,          // keys per ListObjectsV2 page
    listMaxPages: 1000,         // hard backstop before list() truncates (warns)
  },
});
```

每个字段的优先级：显式 `options` > env var > default。

### 自定义适配器

实现 `StorageAdapter` 接口:

```typescript
interface StorageAdapter {
  put(key: string, data: Buffer | Uint8Array, contentType?: string): Promise<void>;
  get(key: string): Promise<{ data: Buffer; contentType: string } | null>;
  exists(key: string): Promise<boolean>;
  list(prefix: string): Promise<string[]>;
  delete(key: string): Promise<void>;
}
```

## 命令行界面

从命令行发布更新、管理证书和通道。

### 发布更新

```bash
everystack update \
  --channel production \
  --message "Fix login bug" \
  --platform ios          # ios | android | web | all (default: all)
```

这将捆绑您的应用程序，将资产上传到存储，创建发布记录，并签署清单。

中配置的媒体资产 `app.config.js` 下 `extra.everystack.assets` 使用8个字符的内容哈希(例如， `logo.png` → `logo-a1b2c3d4.png`)，并同步到媒体桶。一个 `media-manifest.json` 将逻辑名映射到指纹路径写入桶根。以前部署的过时指纹文件将被自动修剪。

```javascript
// app.config.js
extra: {
  everystack: {
    assets: [
      { from: 'server/email/assets', to: 'email/', include: '*.{png,jpg}' },
      { from: 'assets/og', to: 'og/' },
    ],
  },
}
```

使用 `@everystack/server/media` 在SSR、电子邮件模板和工作程序的运行时解析指纹url。

### 代码签名

生成用于舱单签名的RSA密钥对：

```bash
everystack certs:generate --output ./certs
# Creates ./certs/private-key.pem and ./certs/certificate.pem

everystack certs:configure --input ./certs --keyid main
# Configures your app to use the generated certificates
```

### 渠道管理

```bash
everystack channels list
everystack channels create --name staging
everystack channels create --name production
```

### 部署

```bash
everystack deploy --stage dev           # provision infrastructure (wraps `sst deploy`)
```

在SST上有一个薄包装，所以你永远不会打字 `sst` 直接。仅限基础设施—迁移和包发布保持显式(`db:migrate`， `update`）。

### 数据库管理

这些命令通过IAM直接调用Lambda（没有数据库凭据离开AWS）：

```bash
# Migrations
everystack db:migrate                   # apply Drizzle migrations
everystack db:seed                      # seed (dev only)
everystack db:psql --stage dev [-c SQL] # interactive psql / one-off query via Lambda

# Model-driven schema (@everystack/model)
everystack db:generate                  # diff Models vs the live DB → next migration
everystack db:pull                      # introspect a live DB → field() Models (brownfield on-ramp)
everystack db:reconcile                 # deploy the derived layer (functions/views/matviews/triggers) from the declared descriptors in db/models — no migrations
everystack db:fingerprint               # content-address the live base schema vs the Models — MATCH/MISMATCH
everystack db:sync                      # make the database match your checkout — state + compute, one verb (dev DBs)
everystack db:diff                      # the state edge between two declared states — no DB, CI-pure; reverse = computed rollback
everystack db:plan | db:apply           # mint a reviewable plan against a target, apply it fingerprint-verified at both ends + the fast-forward rule (checkout must descend from the commit declaring the target's state); destructive plans: --confirm + snapshot + approver set when declared
everystack db:check                     # the CI gate per PR: merged declared state composes + artifacts match regeneration (+ ephemeral from-scratch build w/ a scratch PG)
everystack db:approvers                 # declare who can DESTROY: the stage's destructive-approver set (SSM, STS-verified at apply)
everystack db:backfill                  # one-shot data jobs in db/backfills/*.sql — content-hash identity, own per-DB record, never a schema side effect
everystack db:template:refresh          # (re)build the dev template from the declared state + your db:seed script — never a data copy
everystack db:branch                    # per-branch dev DB minted from the template, keyed on the git branch (--list / --prune --confirm)
everystack db:fork                      # fork a deployed stage's DB into a feature stage (backup → presigned hand-off → restore); production is never a target

# Security
everystack db:doctor                    # is the DB least-privilege + RLS-subject?
everystack db:provision                 # role chain + converge declared ownership (ENACT grants, ADOPT plain objects)
everystack db:provision --confirm       # + ADOPT SECURITY DEFINER functions / views / matviews (runtime change)
everystack db:authz:pull|diff|test|owner|report   # the authorization contract + red-team

# Backups (see docs/backups.md)
everystack db:backup | db:backups | db:restore --from <id> --confirm   # logical pg_dump → S3
everystack db:backup:download <id>      # presigned URL to a dump (1h)
everystack db:snapshot | db:snapshots   # physical RDS snapshots
```

完整的命令参考-包括 `secrets`， `logs:*`， `status`， `cache:purge`， `branches`每一面旗帜——都在 [文档/ cli.md](https://npmcn.com/package/docs/cli.md).

### 交互式控制台

```bash
everystack console --stage dev          # Connect to deployed database
everystack console --stage dev --sandbox  # Sandbox mode: rolls back after each expression
```

连接到已部署数据库的REPL `db`， `schema`, `eq`/`and`/`or` 范围内的helper。支持多行输入、持久历史记录和制表符完成。

**点命令:**

-   `.tables` / `.schema [table]` -检查数据库模式
-   `.login` -使用电子邮件/密码（隐藏输入）进行身份验证
-   `.user` -显示当前授权上下文
-   `.logout` —清除授权上下文
-   `.sandbox` -切换沙盒模式

后 `.login`，查询通过应用RLS策略运行 `pgSettings`。这个 `current_user` 变量在作用域中可用。密码是根据历史编辑的。

## 客户端：React Native

### UpdatesProvider

包装你的应用来检查和应用OTA更新：

```tsx
import { UpdatesProvider } from '@everystack/cli/client';

function App() {
  return (
    <UpdatesProvider
      url="https://myapp.com/api/updates"
      channel="production"
      checkInterval={60000} // Check every 60 seconds
      onUpdateAvailable={(update) => {
        // Optional: prompt user or auto-apply
        console.log('Update available:', update.message);
      }}
      onUpdateApplied={() => {
        console.log('Update applied, restarting...');
      }}
    >
      <MyApp />
    </UpdatesProvider>
  );
}
```

### AppStateUpdateProvider

当应用程序从后台返回时检查更新：

```tsx
import { AppStateUpdateProvider } from '@everystack/cli/client';

function App() {
  return (
    <AppStateUpdateProvider url="https://myapp.com/api/updates" channel="production">
      <MyApp />
    </AppStateUpdateProvider>
  );
}
```

## 模式

将更新表添加到Drizzle迁移中：

```typescript
import { channels, releases, assets } from '@everystack/cli/schema';
```

表:

-   **渠道** -命名的发布渠道（生产、发布等）
-   **释放** -发布带有元数据的更新包
-   **资产** -发布引用的单个资产文件

## 博览会更新协议

处理程序实现了完整的Expo Updates清单协议：

-   **协议v0**：旧的Expo SDK版本的遗留格式
-   **协议v1**：现代多部分/混合响应格式
-   **代码签名**： manifest指令上的RSA-SHA256签名
-   **平台过滤**：根据请求头提供特定于平台的包
-   **通道路由**：多个发行渠道与独立的版本轨道

### 它是如何工作的

1.  Expo应用程序发送带有平台、运行时版本和当前更新ID的清单请求
2.  处理程序查找所请求通道和平台的最新版本
3.  如果存在更新的版本，它将返回带有资产url的签名清单
4.  Expo运行时下载资产并应用更新

## 同行依赖性

| 包 | 版本 | 要求 |
| --- | --- | --- |
| `drizzle-orm` | `>=0.30.0` | 是 |
| `structured-headers` | `^1.0.0` | 是（运行时深度） |
| `@aws-sdk/client-s3` | `>=3.0.0` | 对于S3存储 |
| `expo-updates` | `>=0.25.0` | 客户端SDK |
| `react` | `>=18.0.0` | 客户端SDK |
| `react-native` | `>=18.0.0` | 客户端SDK |

## 许可证

[agpl - 3.0](https://www.gnu.org/licenses/agpl-3.0.html) ©Scalable Technology, Inc.

对于不能或不希望使用商业许可证的组织，可以使用商业许可证 遵守AGPL-3.0条款。如需商业许可，请联系 [licensing@scalable.technology](mailto:licensing@scalable.technology).

## 常见问题

### @everystack/cli 是什么？

博览会应用的CLI和OTA更新

### 如何安装 @everystack/cli？

在项目目录运行 npm install @everystack/cli，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：drizzle-orm（0\.41\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。它还提供命令行工具 everystack，可以用 npx everystack 直接运行。

### @everystack/cli 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @everystack/cli 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @everystack/cli 可以商用吗？

@everystack/cli 使用 AGPL-3\.0-only 许可。最严格的 Copyleft：除分发外，通过网络向用户提供基于它的服务也需要开源对应源码。闭源 SaaS 使用前务必评估。以上为概括，不构成法律意见，请以许可原文为准。

### @everystack/cli 还在维护吗？

最新版本 0\.4\.107 发布于 2026/11/01（2 天前）；至今共发布 160 个版本，其中过去 12 个月发布了 160 个；首次发布于 2026/05/15。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

