店铺契约
storefront-contract v3:店铺后端是 @delieta/shop-runtime 包,两个很薄的转发文件,可发布密钥放在服务端,签名刷新。
店铺契约(storefront-contract@v3)描述 Delieta 上的店铺。店铺后端是 npm 包 @delieta/shop-runtime(版本 1.6.0),而不是店铺仓库里的文件。店铺仓库只放外观和两个很薄的转发文件。其余部分(Partner API 访问、购物车、结账、刷新)都来自这个包,所以一次发布就能把 runtime 修复送到所有店铺。
四个环境变量
DELIETA_API_URL=https://delieta.pl
DELIETA_PUBLISHABLE_KEY=dlt_live_…
DELIETA_REVALIDATE_SECRET=…
DELIETA_DATA_MODE=live
DELIETA_API_URL 只是来源:不带 /api/v1,不带结尾斜杠。DELIETA_PUBLISHABLE_KEY 是 catalog:read + checkout:create 密钥。DELIETA_REVALIDATE_SECRET 用于签名刷新信号,并在示例数据店铺上校验预览链接。DELIETA_DATA_MODE 可选:sample 或 live,未设置即 live,构建会拒绝其他任何值。它们都没有 NEXT_PUBLIC_ 前缀。
没有环境变量 → 显示“请配置店铺”页面,而不是假装成店铺的空站点。环境变量已设置但 Delieta 无响应 → 显示“产品暂不可用”页面,而不是看起来像已部署、实则零商品的菜单。
可发布密钥:只在服务端
可发布密钥恰好是 catalog:read + checkout:create。它能创建购物车,所以绝不能到达浏览器。runtime 把它保存在服务端并自己发送。构建之后,若密钥泄漏到客户端 JS 代码,delieta-shop-assert 会中止。保密密钥(orders:write、eta:quote、reservations:write、catering:write)既不进店铺,也不进它的仓库。dlt_test_… 放进 HTML 同样不安全。
密钥决定公司。不要发送 companyId。
三个部分
| 部分 | 来源 | 说明 |
|---|---|---|
| 产品与品牌 | 用可发布密钥调用 GET /api/v1/menu 和 GET /api/v1/shop-config,不缓存地读取。 | 格罗什,PLN。不可用商品被省略。品牌、营业时间、模块和下单规则来自面板。 |
| 购物车 | { itemId, quantity, options? }[]。屏幕上的合计来自产品列表。 | 通过 options: [{ group, option }] 选择选项。客户端发送买什么,绝不发送多少钱。 |
| 结账 | POST /api/v1/checkout 经 /api/delieta/checkout 转发,结果来自 GET /api/v1/checkout/result。 | Delieta 按目录定价;返回支付地址,现金则返回 trackingUrl。 |
flowchart TD env["Env: origin, klucz publikowalny, sekret odswiezania"] --> rt["@delieta/shop-runtime"] rt --> menu["GET /menu i /shop-config bez cache"] menu --> cart["Koszyk: itemId, ilosc, opcje"] cart --> pipe["/api/delieta/checkout"] pipe --> checkout["POST /checkout, ceny liczy Delieta"] checkout --> result["GET /checkout/result i status"] secret["Klucz sekretny"] -.->|"nigdy w sklepie"| rt push["Delieta: podpisany POST /api/revalidate"] --> rt
这个密钥“可发布”,只是因为它无法读取订单、司机和客户。即便如此,它仍留在服务端。
店铺仓库里的两个转发文件
每个店铺恰好有两个来自我们的文件。每个都只有一行 export;你不要编辑它们,有人改动时 delieta-shop-assert 会失败。
// app/api/delieta/[...path]/route.ts
export { GET, POST } from "@delieta/shop-runtime/proxy";
// app/api/revalidate/route.ts
export { POST } from "@delieta/shop-runtime/revalidate";
第一个是 /api/delieta/… 代理,带有路径白名单:GET 平面图、预订可用时段、结账时段和按短码查询的订单状态,POST 结账、预订和咨询。其他一律拒绝。顾客的浏览器调用代理,代理在服务端补上密钥。第二个接收签名刷新。
刷新、心跳与守卫
runtime 不缓存地读取 Delieta。店主修改菜单、设置或平面图时,Delieta 发送签名的 POST /api/revalidate,店铺使其标签失效(menu、shop-config、floor-plan)。next build 之后,delieta-shop-assert 检查三件事:转发文件未被改动、应用不是静态导出、可发布密钥没有泄漏到客户端代码。它还会发送带 runtime 版本的心跳。静态导出的应用没有服务器,因此不满足契约 v3。
金额与错误
金额是整数格罗什;到显示时再格式化。Partner API 的错误是 application/problem+json;根据 code 判断,例如 unauthorized、scope_required、rate_limited、shop_closed、slot_unavailable。完整的错误码列表和店铺用到的所有操作见 Partner API。

