@ema-unlimited/frontier-apps-sdk

中文文档
0.3.0发布于 2026/10/22TypeScriptESM + CJS零依赖近 30 天下载 6951

SDK for Frontier Apps——数据库、存储和Ema API通过Frontier-apps-Gateway访问

中文使用文档
文档目录23 节
  1. 为什么
  2. 安装
  3. 子路径
  4. 根 (E) @ema-unlimited/frontier-apps-sdk (中文(简体) )
  5. 一次性客户端输入
  6. 蒙戈DB (英语: @ema-unlimited/frontier-apps-sdk/mongodb (中文(简体) )
  7. 定义一个方案( Mongoose 的机械交换)
  8. 查询
  9. 支助行动
  10. 批量写入
  11. 索引
  12. 屏蔽在外层
  13. 处理错误
  14. 储存 @ema-unlimited/frontier-apps-sdk/storage (中文(简体) )
  15. 密钥布局
  16. 高级上传( 为您签名)
  17. 浏览器直接上传( 大文件, 节点代理 hop)
  18. 回读 / 列表 / 删除
  19. 制约因素(服务器强制)
  20. 处理错误
  21. 哪里的东西降落在GCS
  22. 发展
  23. 设计

@ ema- 无限制/ frontier- apps- sdk

SDK for Frontier Apps ——通过该程序提供数据库,存储和Ema API访问 frontier-apps-gateway。每种能力都是一种单独的子路径导入,所以应用程序 只能拉他们用的东西.

状态 : v.x- DB 路线 (/v1/db/*(已部署) 储存路线 (单位:千美元)/v1/storage/*添加到 0.2.0 (中文(简体) ) (目前为 rc 频道; 见 rc (原始内容存档于2019-09-31). Dutt-tag. Ema API线路计划未来发布.

为什么

每个部署的边境App 之前直接与蒙戈DB交谈。 单人 运行后查询可以饱和每个应用程序的复制集. 这个SDK部队 所有通过安全屏蔽列表的网关的流量,每个应用程序连接 游泳池,审计线索现场直播.

App代码只更改其导入行——调用表面( Mongoose) Schema, (中文(简体) ), model(),查询链)被保留.

安装

pnpm add @ema-unlimited/frontier-apps-sdk mongoose

mongoose 是 DB 子路径所需的对等依赖。 SDK再出口 mongoose.Schema 财务报告和审定财务报表 InferSchemaType 因此,从一个直接的迁移 Mongoose连接是一个单行导入互换. SDK从不打开 MongoDB连接本身——Schema建筑纯粹是JS道路建设.

该软件包发布在 npm 公共注册处——不需要认证:

npm install @ema-unlimited/frontier-apps-sdk

子路径

导入状态它会做什么
@ema-unlimited/frontier-apps-sdk可用网关输入( E)initGatewayClient+ 基准错误类
@ema-unlimited/frontier-apps-sdk/mongodb可用MongoDB 式 DB 访问( 完整的 Mongoose 表面)
@ema-unlimited/frontier-apps-sdk/storage可用通过 V4 签名的 URL 文件存储 (put 编号 : get 编号 : list / .) (中文(简体) )

@ema-unlimited/frontier-apps-sdk/ema (Ema API 代理)已经计划,但尚未添加.


根 (E)@ema-unlimited/frontier-apps-sdk(中文(简体) )

根出口只是网关基础设施,而不是一种能力.

import { initGatewayClient, FrontierError } from '@ema-unlimited/frontier-apps-sdk'
import type { GatewayClientConfig } from '@ema-unlimited/frontier-apps-sdk'

一次性客户端输入

initGatewayClient({
  gatewayUrl: process.env.FRONTIER_GATEWAY_URL!,  // injected by publisher
  appId: process.env.APP_ID!,                      // injected by publisher
})

APP_ID 是出版商提供的值:用于出版范围的完整UUID, preview-{shortId} 用于预览范围。 一次在应用靴子上叫这个——它有线 所有子路径使用的共享运输.


蒙戈DB (英语:@ema-unlimited/frontier-apps-sdk/mongodb(中文(简体) )

定义一个方案( Mongoose 的机械交换)

// Before
import mongoose, { Schema, type InferSchemaType } from 'mongoose'

// After — only the import line changes
import { Schema, model, type InferSchemaType } from '@ema-unlimited/frontier-apps-sdk/mongodb'

const noteSchema = new Schema(
  {
    userId: { type: String, required: true, index: true },
    title: { type: String, required: true },
    content: { type: String, default: '' },
  },
  { timestamps: true },
)

export type NoteDocument = InferSchemaType<typeof noteSchema>
export const Note = model<NoteDocument>('Note', noteSchema)

查询

const notes = await Note.find({ userId }).sort({ createdAt: -1 }).limit(20)

const note = await Note.findOneAndUpdate(
  { _id: id, userId },
  { $set: { title: 'New' } },
  { new: true },
)

await Note.deleteOne({ _id: id, userId })

支助行动

方法回返
find(filter?, options?)QueryBuilder<T[]> (可兑换)
findOne(filter)QueryBuilder<T | null>
findById(id)QueryBuilder<T | null>
findOneAndUpdate(filter, update, ?)QueryBuilder<T | null>
findByIdAndUpdate(id, update, ?)QueryBuilder<T | null>
findOneAndDelete(filter)QueryBuilder<T | null>
findByIdAndDelete(id)QueryBuilder<T | null>
create(doc | docs[])Promise<T | T[]>
insertOne(doc)Promise<T>
insertMany(docs[])Promise<T[]>
updateOne(filter, update)Promise<UpdateResult>
updateMany(filter, update)Promise<UpdateResult>
deleteOne(filter)Promise<DeleteResult>
deleteMany(filter)Promise<DeleteResult>
countDocuments(filter?)Promise<number>
distinct(field, filter?)Promise<unknown[]>
aggregate(pipeline[])Promise<unknown[]>
bulkWrite(ops[], options?)Promise<BulkWriteResult>
createIndex(keys, options?)Promise<string> (索引名称)
listIndexes()Promise<IndexInfo[]>

查询链很懒—— .sort(), (中文(简体) ), .limit(), (中文(简体) ), .skip(), (中文(简体) ), .lean() 返回时 同样的 QueryBuilder 而 HTTP 仅在 await编. .lean() 是一个无操作( 网关总是返回普通 JSON ).

批量写入

bulkWrite 使用相同的操作阵列 mongoose.Model.bulkWrite 选择:

await LineItem.bulkWrite([
  { updateOne: { filter: { _id: id }, update: { $set: { verdict: 'pass' } } } },
  { insertOne: { document: { sku: 'new' } } },
  { deleteOne: { filter: { sku: 'old' } } },
])

序与孟oose相异. 此默认为 ordered: false 地点 默认值为 true,所以失败的行动不会丢弃剩下的 批号。 过 { ordered: true } 用于止于一时的语义.

一个批量的上限为1000 行动, 整个请求机构在10 MiB——块 以上为两个。 即使一些操作落地, 批次也会丢出失败; 错误 信件带有应用过的计数器.

索引

// Idempotent: safe to call at every boot.
await Note.createIndex({ userId: 1, createdAt: -1 })
await Person.createIndex({ email: 1 }, { unique: true })
const live = await Note.listIndexes()

密钥顺序对复合指数很重要 并且保存在电线上, 因此,将密钥谱构建为对象字元。 支持的选项 : name, (中文(简体) ), unique, (中文(简体) ), sparse, (中文(简体) ), hidden, (中文(简体) ), expireAfterSeconds, (中文(简体) ), partialFilterExpression。 。 。 . 任何其他选项是: 被拒绝而不是丢弃,所以一个应用永远不会 认为它有限制 数据库没有强制.

重新创建一个具有相同光谱的索引是没有的。 一样 名称 与 不同的规格是 IndexOptionsConflict 从服务器。 一个收藏是 上限为64个指数,MongoDB自己的极限.

createIndex 使用5分钟而非通常的30秒: a 索引构建运行到命令返回前完成 .

屏蔽在外层

这些在任何网络呼叫前同步抛出 :

  • .populate() • 使用 aggregate 与 $lookup
  • .drop() 编号 : dropCollection() - 计划管理没有暴露
  • dropIndex() • 使用 createIndex 财务报告和审定财务报表 listIndexes

额外屏蔽的网关 $where, (中文(简体) ), $function, (中文(简体) ), $accumulator, (中文(简体) ), $out, (中文(简体) ), mapReduce,且无约束 find({}) 打电话 这些返回 HTTP 400,即: SDK 表面为 FrontierDbError。 。 。 .

处理错误

import { FrontierError } from '@ema-unlimited/frontier-apps-sdk'
import { FrontierDbError } from '@ema-unlimited/frontier-apps-sdk/mongodb'

try {
  await Note.find({})
} catch (err) {
  if (err instanceof FrontierDbError) {
    console.error(err.status, err.code, err.message)
  }
  // Or catch any SDK error across subpaths:
  if (err instanceof FrontierError) { ... }
}

储存@ema-unlimited/frontier-apps-sdk/storage(中文(简体) )

每个应用程序文件存储由GCS支持. SDK从不触及GCS证书—— 网关薄荷短命 V4 签名的 URL (5-min PUT, 15-min Get) (中文(简体) ) 浏览器/节点客户端直接向 storage.googleapis.com控制平面(自动、内容类型验证, 配额,审计)运行于网关;数据平面跳过.

存储是一个纯字节存储器——它从不分析您的文件——所以它接受 任意 结构良好的内容类型。没有上传允许列表可以生长。 安全问题 对活性内容执行 服务 时间: 网关服务 text/html, (中文(简体) ), image/svg+xml,以及 */xml 对象为 Content-Disposition: attachment 因此,他们下载,而不是在共享的GCS上执行内置 源代码。 (这不影响 <img> 编号 : <video> 编号 : <audio> 嵌入- 浏览器 忽略 Content-Disposition 用于子资源负载。 )

密钥布局

SDK发送的每个密钥都经过了消毒和前缀的服务器侧:

tenants/<tenantId>/frontier-apps/<appId>/uploads/<your-key>

租户+应用由网关解决(每个应用K8s秘密)——SDK 不能影响他们。 用户提供的密钥必须匹配 [A-Za-z0-9._/-] 财务报告和审定财务报表 无法从 / 或包含 .. / NUL (英语).

高级上传( 为您签名)

import { put } from '@ema-unlimited/frontier-apps-sdk/storage'

const blob = new Blob([fileBytes], { type: 'image/png' })
const meta = await put(`users/${userId}/avatar.png`, blob, {
  contentType: 'image/png',
})
// → { key, size, contentType }

在车盖下 put() 签名 + PUT(直接对GCS) + 确认 . 如果PUT失败, confirm-put 实值 没有 没有孤儿记录.

浏览器直接上传( 大文件, 节点代理 hop)

当上传来自浏览器时, 将 URL 服务器端薄荷并让 浏览器执行 PUT. 一样 Content-Type + 大小被钉入 签名,所以调用者无法在 网关授权.

import { signPut, confirmPut } from '@ema-unlimited/frontier-apps-sdk/storage'

// 1. Server side — mint the signed URL.
const signed = await signPut(`users/${userId}/big.zip`, {
  contentType: 'application/zip',
  size: file.size,
})

// 2. Browser side — PUT bytes direct to GCS.
await fetch(signed.url, {
  method: 'PUT',
  headers: signed.requiredHeaders,  // includes Content-Type + X-Goog-Content-Length-Range
  body: file,
})

// 3. Server side — record the upload.
const meta = await confirmPut(`users/${userId}/big.zip`)

回读 / 列表 / 删除

import { get, getMeta, list, del } from '@ema-unlimited/frontier-apps-sdk/storage'

// Signed GET URL — usable directly in <img src>, <video src>, <a download>.
const { url, expiresAt, size, contentType } = await get(`users/${userId}/avatar.png`)

// Metadata only (no signing, no transfer).
const meta = await getMeta(`users/${userId}/avatar.png`)

// Paginated list scoped to the app's prefix.
const { items, nextCursor } = await list(`users/${userId}/`, { limit: 50 })

// Idempotent delete.
await del(`users/${userId}/avatar.png`)

制约因素(服务器强制)

限制默认
每个对象大小1个GIB
已签名 PUT TTL5分钟
签名获取 TTL15分钟
内容类型任何身材不错的 type/subtype 已接受。 活动类型( A)text/html, (中文(简体) ), image/svg+xml, (中文(简体) ), */xml)作为下载服务.
密钥字符集[A-Za-z0-9._/-] 没有 ..无线索 /,无 NUL

处理错误

import { FrontierStorageError } from '@ema-unlimited/frontier-apps-sdk/storage'

try {
  await put('uploads/x.pdf', blob, { contentType: 'application/pdf' })
} catch (err) {
  if (err instanceof FrontierStorageError) {
    console.error(err.status, err.code, err.message)
    // err.status: HTTP status (e.g. 422 for a denied/invalid content-type or oversize)
    // err.code:   the gateway error code (e.g. "VALIDATION_ERROR") or a client
    //             classifier ("network_error" | "gcs_put_failed" | "timeout" | "aborted")
  }
}

哪里的东西降落在GCS

gs://<project-id>-frontier-apps-uploads/
  tenants/
    <tenantId>/
      frontier-apps/
        <appId>/
          uploads/
            users/<userId>/avatar.png           ← written by the storage SDK
            users/<userId>/reports/2026-Q1.pdf

该桶是专门用于每个应用程序用户上传的,与 共享 <env>-emu-blobs 那边的桶 frontier-apps-builder 保留它 即兴表演 租户下船是单人 gsutil -m rm -r gs://<bucket>/tenants/<tenantId>/ 对抗这个桶.


发展

pnpm install
pnpm typecheck
pnpm test
pnpm build

设计

见 docs/design-frontier-apps-db-proxy.md。 。 。 .

版本与发布记录

@ema-unlimited/frontier-apps-sdk 共发布 9 个版本,首次发布于 2026/05/21;过去 12 个月发布了 9 个版本。

版本发布日期距今
0.3.0latest2026/10/2222 天前
0.2.22026/09/231 个月前
0.2.12026/06/174 个月前
0.2.02026/05/285 个月前
0.2.0-rc.4rc2026/05/225 个月前
0.2.0-rc.32026/05/215 个月前

关于 @ema-unlimited/frontier-apps-sdk 的常见问题

@ema-unlimited/frontier-apps-sdk 是什么?

SDK for Frontier Apps——数据库、存储和Ema API通过Frontier-apps-Gateway访问

如何安装 @ema-unlimited/frontier-apps-sdk?

在项目目录运行 npm install @ema-unlimited/frontier-apps-sdk,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:mongoose(^8.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@ema-unlimited/frontier-apps-sdk 支持 TypeScript 吗?

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

@ema-unlimited/frontier-apps-sdk 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@ema-unlimited/frontier-apps-sdk 可以商用吗?

@ema-unlimited/frontier-apps-sdk 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@ema-unlimited/frontier-apps-sdk 的下载量有多少?

根据 npm 官方下载统计,@ema-unlimited/frontier-apps-sdk 在 2026/10/14 – 2026/11/12 这 30 天内被下载 6,951 次,日均约 232 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@ema-unlimited/frontier-apps-sdk 还在维护吗?

最新版本 0.3.0 发布于 2026/10/22(22 天前);至今共发布 9 个版本,其中过去 12 个月发布了 9 个;首次发布于 2026/05/21。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。