From c18446153ea20f763936690a1c43221e8dead589 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 8 Aug 2026 05:13:00 +0000 Subject: [PATCH 1/2] =?UTF-8?q?fix(spec):=20=E5=86=85=E8=81=94=E5=BD=A2?= =?UTF-8?q?=E7=8A=B6=E6=91=98=E8=A6=81=E5=8F=AA=E5=B1=95=E5=BC=80=E4=B8=80?= =?UTF-8?q?=E5=B1=82,=E5=9B=9B=E6=9D=A1=E4=B8=8B=E9=92=BB=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E5=85=B1=E7=94=A8=E5=90=8C=E4=B8=80=E6=9D=A1=E6=B7=B1?= =?UTF-8?q?=E5=BA=A6=E9=A2=84=E7=AE=97=20(#6374)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `format-type.ts` 一直只展开一层 `{ … }` 形状,但这条预算写在键循环的三元 表达式里,于是只有直接对象子节点受它约束。数组元素、`Record` 的值、联合的 变体这三条路径都会重新进入对象分支而预算不在作用域内,单元格宽度于是等于 每层键数 × 变体数 × 每个形状宽度,一层一层乘上去。`ui/page.mdx` 的 `Page.slots` 因此是 1538 字符 —— 而且是在 #5340 的枚举省略已在该格生效 8 次之后的宽度。 新常量 `SHAPE_DEPTH_LIMIT` 把同一条预算移到对象分支本身,四条路径都要过它。 阈值 1 不是选出来的,是取回来的:它就是直接子节点路径上一直生效的那个值。 全语料实测(215 页 / 8499 个类型单元格),任何大于 1 的取值都比不改还差, 因为提高上限必然放松那条本来就是 1 的路径。 深度上限 | 改前 | 1 | 2 | 3 | 4 >200 字符 | 121 | 42 | 173 | 191 | 191 >400 字符 | 9 | 1 | 19 | 35 | 35 >900 字符 | 1 | 0 | 1 | 1 | 1 最宽 | 1538 | 656 | 1538 | 1538 | 1538 改后仅剩的 >400 单元格是 `PageComponent.type`(656),落在联合变体里的顶层 词表,#6225 有意不收,且不含任何嵌套形状 —— 形状深度带来的宽度已经从语料 里消失。 `content/docs/references/**` 55 页由 `gen:schema && gen:docs` 重生成, 无一处手改。 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01AZgRyPVwi1jLb1mNNuUQ9o --- .changeset/inline-shape-depth-budget.md | 53 ++++ content/docs/references/ai/conversation.mdx | 2 +- content/docs/references/ai/model-registry.mdx | 2 +- .../docs/references/ai/solution-blueprint.mdx | 12 +- content/docs/references/api/analytics.mdx | 4 +- .../docs/references/api/automation-api.mdx | 6 +- content/docs/references/api/batch.mdx | 2 +- content/docs/references/api/contract.mdx | 4 +- content/docs/references/api/documentation.mdx | 12 +- content/docs/references/api/export.mdx | 6 +- content/docs/references/api/metadata.mdx | 6 +- content/docs/references/api/odata.mdx | 6 +- content/docs/references/api/package-api.mdx | 6 +- content/docs/references/api/protocol.mdx | 20 +- content/docs/references/api/realtime.mdx | 2 +- content/docs/references/api/rest-server.mdx | 4 +- .../references/automation/control-flow.mdx | 12 +- content/docs/references/automation/flow.mdx | 2 +- .../references/automation/state-machine.mdx | 8 +- content/docs/references/cloud/marketplace.mdx | 4 +- content/docs/references/data/data-engine.mdx | 14 +- content/docs/references/data/document.mdx | 4 +- .../docs/references/data/external-catalog.mdx | 2 +- content/docs/references/data/object.mdx | 6 +- content/docs/references/data/seed-loader.mdx | 4 +- .../docs/references/integration/connector.mdx | 8 +- content/docs/references/kernel/manifest.mdx | 8 +- .../references/kernel/metadata-plugin.mdx | 2 +- .../references/kernel/package-registry.mdx | 2 +- .../references/kernel/plugin-capability.mdx | 4 +- .../references/kernel/plugin-registry.mdx | 2 +- .../kernel/plugin-security-advanced.mdx | 8 +- .../references/kernel/plugin-security.mdx | 8 +- .../references/kernel/plugin-versioning.mdx | 8 +- content/docs/references/qa/testing.mdx | 6 +- content/docs/references/security/explain.mdx | 2 +- .../references/studio/object-designer.mdx | 4 +- content/docs/references/studio/plugin.mdx | 2 +- content/docs/references/system/book.mdx | 2 +- content/docs/references/system/cache.mdx | 2 +- .../references/system/change-management.mdx | 6 +- .../docs/references/system/collaboration.mdx | 2 +- .../references/system/disaster-recovery.mdx | 4 +- .../references/system/incident-response.mdx | 2 +- content/docs/references/system/job.mdx | 2 +- content/docs/references/system/metrics.mdx | 8 +- .../docs/references/system/object-storage.mdx | 2 +- .../docs/references/system/search-engine.mdx | 2 +- content/docs/references/system/tracing.mdx | 2 +- .../docs/references/system/translation.mdx | 26 +- content/docs/references/ui/action.mdx | 4 +- content/docs/references/ui/app.mdx | 2 +- content/docs/references/ui/component.mdx | 2 +- content/docs/references/ui/dashboard.mdx | 2 +- content/docs/references/ui/page.mdx | 10 +- content/docs/references/ui/view.mdx | 28 +- packages/spec/scripts/format-type.test.ts | 281 +++++++++++++++++- packages/spec/scripts/lib/format-type.ts | 91 +++++- 58 files changed, 565 insertions(+), 182 deletions(-) create mode 100644 .changeset/inline-shape-depth-budget.md diff --git a/.changeset/inline-shape-depth-budget.md b/.changeset/inline-shape-depth-budget.md new file mode 100644 index 0000000000..468b815871 --- /dev/null +++ b/.changeset/inline-shape-depth-budget.md @@ -0,0 +1,53 @@ +--- +"@objectstack/spec": patch +--- + +fix(spec): 参考文档的内联形状摘要只展开一层,不再沿数组/Record/联合无预算下钻 (#6374) + +`content/docs/references/**` 的类型单元格里,最宽的一格是 `ui/page.mdx` 的 +`Page.slots`,**1538 字符** —— 而且是在 #5340 的枚举省略已经在这一格生效 8 次 +之后的宽度。本次修完,这一格是 **122 字符**。 + +## 机制 + +`format-type.ts` 一直只展开**一层** `{ … }` 形状:再往下的对象打印 `object`。 +但这条预算写在键循环的三元表达式里,于是只有**直接对象子节点**受它约束。数组元素 +(`{ … }[]`)、`Record` 的值(`Record`)、联合的变体 +(`{ … } | { … }[]`)这三条路径都会重新进入对象分支,而预算不在作用域内 —— +单元格宽度于是等于「每层键数 × 变体数 × 每个形状的宽度」,一层一层乘上去。 + +同一个形状在同一个阅读深度上,**印全还是印 `object`,取决于作者有没有把它包在数组 +里** —— 这是关于 Zod 写法的事实,不是关于读者怎么读的事实,和 #6225 拆掉的那种 +不对称完全同类。 + +新常量 `SHAPE_DEPTH_LIMIT` 把同一条预算移到对象分支本身,四条下钻路径都要过它。 +**阈值 1 不是选出来的,是取回来的** —— 它就是直接子节点路径上一直生效的那个值; +全语料实测,任何大于 1 的取值都比不改还差(>200 字符的单元格 121 → 173+,因为 +提高上限必然放松那条本来就是 1 的路径)。 + +## 读者看到的变化(全语料 215 页 / 8499 个类型单元格) + +| | 修改前 | 修改后 | +|---|---|---| +| >200 字符 | 121 | **42** | +| >400 字符 | 9 | **1** | +| >900 字符 | 1 | **0** | +| p95 / p99 | 145 / 229 | **124 / 180** | +| 最宽单元格 | 1538 | **656** | + +修改后仅剩的那个 >400 单元格是 `ui/page.mdx` 的 `PageComponent.type`(656), +一个落在联合变体里的顶层词表 —— #6225 有意不收它,它也**不含任何嵌套形状**。 +也就是说:**由形状深度带来的宽度已经从语料里消失了**。 + +## 省略掉的信息去哪了 + +`object` 不是截断:它对键**什么都不声称**,所以不像前缀那样会被误读成完整列表 —— +这正是 #5340 定下的原则用在形状上而不是枚举成员上。它也不是这些表格里的新省略 +风格:嵌套形状本来就一直印 `object`。完整形状仍在原处 —— 生成器为它出页时是它 +自己的 `## Schema` 一节,任何情况下都在 `json-schema/` 里。 + +#5340 / #6226 的两个标记都还活着,只是有些出现位置被上游的深度预算吸收了: +枚举标记 178 → 156,变体标记 16 → 9。#6226 的旗舰样本 `App.navigation` 在深度 0, +逐字未变。 + +⛔ 所有 `.mdx` 均由 `gen:schema && gen:docs` 重生成,无一处手改。 diff --git a/content/docs/references/ai/conversation.mdx b/content/docs/references/ai/conversation.mdx index aa4694814c..8c8cf30326 100644 --- a/content/docs/references/ai/conversation.mdx +++ b/content/docs/references/ai/conversation.mdx @@ -118,7 +118,7 @@ const result = CodeContentSchema.parse(data); | **context** | `{ sessionId: string; userId?: string; agentId?: string; object?: string; … }` | ✅ | | | **modelId** | `string` | optional | AI model ID | | **tokenBudget** | `{ maxTokens: integer; maxPromptTokens?: integer; maxCompletionTokens?: integer; reserveTokens: integer; … }` | ✅ | | -| **messages** | `{ id: string; timestamp: string; role: Enum<'system' \| 'user' \| 'assistant' \| 'function' \| 'tool'>; content: ({ type: 'text'; text: string; metadata?: Record } \| { type: 'image'; imageUrl: string; detail: Enum<'low' \| 'high' \| 'auto'>; metadata?: Record } \| { type: 'file'; fileUrl: string; mimeType: string; fileName?: string; … } \| { type: 'code'; text: string; language: string; metadata?: Record })[]; … }[]` | ✅ | | +| **messages** | `{ id: string; timestamp: string; role: Enum<'system' \| 'user' \| 'assistant' \| 'function' \| 'tool'>; content: (object \| object \| object \| object)[]; … }[]` | ✅ | | | **tokens** | `{ promptTokens: integer; completionTokens: integer; totalTokens: integer; budgetLimit: integer; … }` | optional | | | **totalTokens** | `{ promptTokens: integer; completionTokens: integer; totalTokens: integer }` | optional | Total tokens across all messages | | **totalCost** | `number` | optional | Total cost for this session in USD | diff --git a/content/docs/references/ai/model-registry.mdx b/content/docs/references/ai/model-registry.mdx index 69c1ae3703..c65d9bd738 100644 --- a/content/docs/references/ai/model-registry.mdx +++ b/content/docs/references/ai/model-registry.mdx @@ -120,7 +120,7 @@ const result = ModelCapabilitySchema.parse(data); | :--- | :--- | :--- | :--- | | **name** | `string` | ✅ | Registry name | | **models** | `Record; priority?: integer; fallbackModels?: string[]; … }>` | ✅ | Model entries by ID | -| **promptTemplates** | `Record; source?: string; ast?: any; meta?: object }; … }>` | optional | Prompt templates by name | +| **promptTemplates** | `Record` | optional | Prompt templates by name | | **defaultModel** | `string` | optional | Default model ID | | **enableAutoFallback** | `boolean` | optional | Auto-fallback on errors | diff --git a/content/docs/references/ai/solution-blueprint.mdx b/content/docs/references/ai/solution-blueprint.mdx index 215f659a71..d3f64b4aaf 100644 --- a/content/docs/references/ai/solution-blueprint.mdx +++ b/content/docs/references/ai/solution-blueprint.mdx @@ -226,10 +226,10 @@ const result = BlueprintAppSchema.parse(data); | **summary** | `string` | optional | One-line description of the proposed solution | | **assumptions** | `string[]` | ✅ | Design assumptions made from the underspecified goal | | **questions** | `string[]` | optional | At most 1-2 structure-deciding questions to confirm before building | -| **objects** | `{ name: string; label?: string; description?: string; fields: { name: string; label?: string; type: Enum<'text' \| 'textarea' \| 'email' \| 'url' \| 'phone' \| 'password' \| 'secret' \| … +42 more>; required?: boolean; … }[]; … }[]` | ✅ | Objects (tables) to create | +| **objects** | `{ name: string; label?: string; description?: string; fields: object[]; … }[]` | ✅ | Objects (tables) to create | | **views** | `{ object: string; name: string; label?: string; type: Enum<'list' \| 'form' \| 'kanban' \| 'calendar' \| 'gallery' \| 'gantt'>; … }[]` | optional | Views to create | -| **dashboards** | `{ name: string; label?: string; widgets?: { id: string; title?: string; object?: string; chart?: Enum<'metric' \| 'bar' \| 'line' \| 'pie' \| 'table'>; … }[] }[]` | optional | Dashboards to create | -| **app** | `{ name: string; label?: string; icon?: string; nav?: { type: Enum<'object' \| 'dashboard'>; target: string; label?: string; icon?: string }[] }` | optional | The navigation shell (app) that surfaces the created objects/dashboards to end users | +| **dashboards** | `{ name: string; label?: string; widgets?: object[] }[]` | optional | Dashboards to create | +| **app** | `{ name: string; label?: string; icon?: string; nav?: object[] }` | optional | The navigation shell (app) that surfaces the created objects/dashboards to end users | | **seedData** | `{ object: string; records: Record[] }[]` | optional | Suggested seed data (reported, not auto-applied in Phase C) | @@ -244,10 +244,10 @@ const result = BlueprintAppSchema.parse(data); | **summary** | `string` | ✅ | One-line description of the proposed solution | | **assumptions** | `string[]` | ✅ | Design assumptions made from the underspecified goal | | **questions** | `string[] \| null` | ✅ | At most 1-2 structure-deciding questions to confirm before building, or null | -| **objects** | `{ name: string; label: string \| null; description: string \| null; fields: { name: string; label: string \| null; type: Enum<'text' \| 'textarea' \| 'email' \| 'url' \| 'phone' \| 'password' \| 'secret' \| … +42 more>; required: boolean \| null; … }[] }[]` | ✅ | Objects (tables) to create | +| **objects** | `{ name: string; label: string \| null; description: string \| null; fields: object[] }[]` | ✅ | Objects (tables) to create | | **views** | `{ object: string; name: string; label: string \| null; type: Enum<'list' \| 'form' \| 'kanban' \| 'calendar' \| 'gallery' \| 'gantt'> \| null; … }[] \| null` | ✅ | Views to create, or null | -| **dashboards** | `{ name: string; label: string \| null; widgets: { id: string; title: string \| null; object: string \| null; chart: Enum<'metric' \| 'bar' \| 'line' \| 'pie' \| 'table'> \| null; … }[] \| null }[] \| null` | ✅ | Dashboards to create, or null | -| **app** | `{ name: string; label: string \| null; icon: string \| null; nav: { type: Enum<'object' \| 'dashboard'>; target: string; label: string \| null; icon: string \| null }[] \| null } \| null` | ✅ | The navigation shell (app) that surfaces the created objects/dashboards, or null | +| **dashboards** | `{ name: string; label: string \| null; widgets: object[] \| null }[] \| null` | ✅ | Dashboards to create, or null | +| **app** | `{ name: string; label: string \| null; icon: string \| null; nav: object[] \| null } \| null` | ✅ | The navigation shell (app) that surfaces the created objects/dashboards, or null | --- diff --git a/content/docs/references/api/analytics.mdx b/content/docs/references/api/analytics.mdx index 11e2e4b55f..ad22e17a09 100644 --- a/content/docs/references/api/analytics.mdx +++ b/content/docs/references/api/analytics.mdx @@ -46,7 +46,7 @@ const result = AnalyticsEndpoint.parse(data); | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ cubes: { name: string; title?: string; description?: string; sql: string; … }[] }` | ✅ | | +| **data** | `{ cubes: object[] }` | ✅ | | --- @@ -81,7 +81,7 @@ const result = AnalyticsEndpoint.parse(data); | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ rows: Record[]; fields: { name: string; type: string }[]; sql?: string }` | ✅ | | +| **data** | `{ rows: Record[]; fields: object[]; sql?: string }` | ✅ | | --- diff --git a/content/docs/references/api/automation-api.mdx b/content/docs/references/api/automation-api.mdx index 65c930e9f8..e4e720a9e5 100644 --- a/content/docs/references/api/automation-api.mdx +++ b/content/docs/references/api/automation-api.mdx @@ -96,7 +96,7 @@ const result = AutomationApiErrorCode.parse(data); | **type** | `Enum<'autolaunched' \| 'record_change' \| 'schedule' \| 'screen' \| 'api'>` | ✅ | Flow type | | **variables** | `{ name: string; type: string; isInput?: boolean; isOutput?: boolean }[]` | optional | Flow variables | | **nodes** | `{ id: string; type: string; label: string; config?: Record; … }[]` | ✅ | Flow nodes | -| **edges** | `{ id: string; source: string; target: string; condition?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; … }[]` | ✅ | Flow connections | +| **edges** | `{ id: string; source: string; target: string; condition?: string \| object; … }[]` | ✅ | Flow connections | | **active** | `never` | optional | [REMOVED] `flow.active` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it never had an effect: the engine arms flows from `status`, and `active: false` did NOT stop a flow (worse, the default read as disabled while the engine treated unset as enabled). Delete the key. Use `status: 'obsolete'` (or 'invalid') to unbind and disable a flow, `status: 'active'` to arm it. | | **runAs** | `Enum<'system' \| 'user'>` | optional | Execution identity for the run: system = elevated (bypasses RLS), user = the triggering user (RLS-respecting). A run with no trigger user has no identity to scope to, so under user its data operations are REFUSED — declare system to make the elevation explicit. This covers schedule/time-relative/api triggers AND any record-change flow fired by a write that carried no user. | | **errorHandling** | `{ strategy?: Enum<'fail' \| 'retry' \| 'continue'>; maxRetries?: integer; backoffMs?: integer; backoffMultiplier?: number; … }` | optional | Flow-level error handling configuration | @@ -243,7 +243,7 @@ const result = AutomationApiErrorCode.parse(data); | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ flows: { name: string; label: string; type: string; status: string; … }[]; total?: integer; nextCursor?: string; hasMore: boolean }` | ✅ | | +| **data** | `{ flows: object[]; total?: integer; nextCursor?: string; hasMore: boolean }` | ✅ | | --- @@ -271,7 +271,7 @@ const result = AutomationApiErrorCode.parse(data); | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ runs: { id: string; flowName: string; flowVersion?: integer; status: Enum<'pending' \| 'running' \| 'paused' \| 'completed' \| 'failed' \| 'cancelled' \| … +2 more>; … }[]; total?: integer; nextCursor?: string; hasMore: boolean }` | ✅ | | +| **data** | `{ runs: object[]; total?: integer; nextCursor?: string; hasMore: boolean }` | ✅ | | --- diff --git a/content/docs/references/api/batch.mdx b/content/docs/references/api/batch.mdx index 6118e517ee..0a50d71614 100644 --- a/content/docs/references/api/batch.mdx +++ b/content/docs/references/api/batch.mdx @@ -128,7 +128,7 @@ const result = BatchConfigSchema.parse(data); | **total** | `number` | ✅ | Total number of records in the batch | | **succeeded** | `number` | ✅ | Number of records that succeeded | | **failed** | `number` | ✅ | Number of records that failed | -| **results** | `{ id?: string; success: boolean; errors?: { code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }[]; data?: Record; … }[]` | ✅ | Detailed results for each record | +| **results** | `{ id?: string; success: boolean; errors?: object[]; data?: Record; … }[]` | ✅ | Detailed results for each record | --- diff --git a/content/docs/references/api/contract.mdx b/content/docs/references/api/contract.mdx index 144d9f6f0b..037aeaa013 100644 --- a/content/docs/references/api/contract.mdx +++ b/content/docs/references/api/contract.mdx @@ -348,7 +348,7 @@ const result = ApiErrorSchema.parse(data); | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ id?: string; success: boolean; errors?: { code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }[]; index?: number; … }[]` | ✅ | Results for each item in the batch | +| **data** | `{ id?: string; success: boolean; errors?: object[]; index?: number; … }[]` | ✅ | Results for each item in the batch | --- @@ -417,7 +417,7 @@ const result = ApiErrorSchema.parse(data); | **having** | `any` | optional | HAVING — filter over the AGGREGATED rows (aggregation aliases + groupBy projections); applied engine-side after aggregation | | **windowFunctions** | `never` | optional | [REMOVED] `query.windowFunctions` was removed in @objectstack/spec 17 (#4286, ADR-0049) — `find()` never applied it: no engine or driver read the key on the query path, so every OVER clause it declared was silently dropped. Delete the key. Window functions are a SQL-driver capability behind `SqlDriver.findWithWindowFunctions(object, query)` (embedder-level; not on the `IDataDriver` contract or the REST surface); request-level analytics are `aggregations` + `groupBy`. | | **distinct** | `never` | optional | [REMOVED] `query.distinct` was removed in @objectstack/spec 17 (#4286, ADR-0049 / ADR-0078) — no driver ever rendered SELECT DISTINCT; the flag's only observable effect was MIS-WIRED: the REST list path treated a distinct query as not countable and silently degraded `total`/`hasMore` to a page-local estimate while still returning duplicate rows. Delete the key; `QueryBuilder.distinct()` was removed with it, and the count suppression is gone (`total` is truthful again). For unique values of one column use the SQL/memory drivers' `distinct(object, field)` door; for unique combinations, `groupBy`; for a deduplicated count, the `count_distinct` aggregation. | -| **expand** | `Record; … }; … }>` | optional | Recursive relation loading map. Keys are lookup/master_detail field names; values are nested QueryAST objects that control select (`fields`) and filter (`where`, AND-merged with the batch $in), plus further expansion on the related object. The engine resolves expand via batch $in queries (driver-agnostic) with a default max depth of 3; per-parent `limit`/`offset`/`orderBy` are NOT applied on this path. | +| **expand** | `Record` | optional | Recursive relation loading map. Keys are lookup/master_detail field names; values are nested QueryAST objects that control select (`fields`) and filter (`where`, AND-merged with the batch $in), plus further expansion on the related object. The engine resolves expand via batch $in queries (driver-agnostic) with a default max depth of 3; per-parent `limit`/`offset`/`orderBy` are NOT applied on this path. | --- diff --git a/content/docs/references/api/documentation.mdx b/content/docs/references/api/documentation.mdx index e16fcb07ad..11b2ca18c4 100644 --- a/content/docs/references/api/documentation.mdx +++ b/content/docs/references/api/documentation.mdx @@ -77,11 +77,11 @@ const result = ApiChangelogEntrySchema.parse(data); | **title** | `string` | ✅ | Documentation title | | **version** | `string` | ✅ | API version | | **description** | `string` | optional | API description | -| **servers** | `{ url: string; description?: string; variables?: Record }[]` | ✅ | API server URLs | +| **servers** | `{ url: string; description?: string; variables?: Record }[]` | ✅ | API server URLs | | **ui** | `{ type: Enum<'swagger-ui' \| 'redoc' \| 'rapidoc' \| 'stoplight' \| 'scalar' \| 'graphiql' \| 'postman' \| 'custom'>; path: string; theme: Enum<'light' \| 'dark' \| 'auto'>; enableTryItOut: boolean; … }` | optional | Testing UI configuration | | **generateOpenApi** | `boolean` | ✅ | Generate OpenAPI 3.0 specification | | **generateTestCollections** | `boolean` | ✅ | Generate API test collections | -| **testCollections** | `{ name: string; description?: string; variables: Record; requests: { name: string; description?: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE' \| 'HEAD' \| 'OPTIONS'>; url: string; … }[]; … }[]` | ✅ | Predefined test collections | +| **testCollections** | `{ name: string; description?: string; variables: Record; requests: object[]; … }[]` | ✅ | Predefined test collections | | **changelog** | `{ version: string; date: string; changes: object; migrationGuide?: string }[]` | ✅ | API version changelog | | **codeTemplates** | `{ language: string; name: string; template: string; variables?: string[] }[]` | ✅ | Code generation templates | | **termsOfService** | `string` | optional | Terms of service URL | @@ -104,7 +104,7 @@ const result = ApiChangelogEntrySchema.parse(data); | **description** | `string` | optional | Collection description | | **variables** | `Record` | ✅ | Shared variables | | **requests** | `{ name: string; description?: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE' \| 'HEAD' \| 'OPTIONS'>; url: string; … }[]` | ✅ | Test requests in this collection | -| **folders** | `{ name: string; description?: string; requests: { name: string; description?: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE' \| 'HEAD' \| 'OPTIONS'>; url: string; … }[] }[]` | optional | Request folders for organization | +| **folders** | `{ name: string; description?: string; requests: object[] }[]` | optional | Request folders for organization | --- @@ -186,8 +186,8 @@ const result = ApiChangelogEntrySchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **openApiSpec** | `{ openapi: string; info: object; servers: { url: string; description?: string; variables?: Record }[]; paths: Record; … }` | optional | Generated OpenAPI specification | -| **testCollections** | `{ name: string; description?: string; variables: Record; requests: { name: string; description?: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE' \| 'HEAD' \| 'OPTIONS'>; url: string; … }[]; … }[]` | optional | Generated test collections | +| **openApiSpec** | `{ openapi: string; info: object; servers: object[]; paths: Record; … }` | optional | Generated OpenAPI specification | +| **testCollections** | `{ name: string; description?: string; variables: Record; requests: object[]; … }[]` | optional | Generated test collections | | **markdown** | `string` | optional | Generated markdown documentation | | **html** | `string` | optional | Generated HTML documentation | | **generatedAt** | `string` | ✅ | Generation timestamp | @@ -235,7 +235,7 @@ const result = ApiChangelogEntrySchema.parse(data); | :--- | :--- | :--- | :--- | | **openapi** | `string` | ✅ | OpenAPI specification version | | **info** | `{ title: string; version: string; description?: string; termsOfService?: string; … }` | ✅ | API metadata | -| **servers** | `{ url: string; description?: string; variables?: Record }[]` | ✅ | API servers | +| **servers** | `{ url: string; description?: string; variables?: Record }[]` | ✅ | API servers | | **paths** | `Record` | ✅ | API paths and operations | | **components** | `{ schemas?: Record; responses?: Record; parameters?: Record; examples?: Record; … }` | optional | Reusable components | | **security** | `Record[]` | optional | Global security requirements | diff --git a/content/docs/references/api/export.mdx b/content/docs/references/api/export.mdx index 7f5e8f41cb..6575db0e5b 100644 --- a/content/docs/references/api/export.mdx +++ b/content/docs/references/api/export.mdx @@ -490,7 +490,7 @@ Type: `{ sourceField: string; targetField: string; targetLabel?: string; transfo | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ jobs: { jobId: string; object: string; status: Enum<'pending' \| 'processing' \| 'completed' \| 'failed' \| 'cancelled' \| 'expired'>; format: Enum<'csv' \| 'json' \| 'jsonl' \| 'xlsx' \| 'parquet'>; … }[]; nextCursor?: string; hasMore: boolean }` | ✅ | | +| **data** | `{ jobs: object[]; nextCursor?: string; hasMore: boolean }` | ✅ | | --- @@ -533,7 +533,7 @@ Type: `{ sourceField: string; targetField: string; targetLabel?: string; transfo | **fields** | `string[]` | optional | Fields to include | | **filter** | `Record` | optional | Record filter criteria | | **templateId** | `string` | optional | Export template ID for field mappings | -| **schedule** | `{ cronExpression: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; timezone?: string }` | ✅ | Schedule timing configuration | +| **schedule** | `{ cronExpression: string \| object; timezone?: string }` | ✅ | Schedule timing configuration | | **delivery** | `{ method: Enum<'email' \| 'storage' \| 'webhook'>; recipients?: string[]; storagePath?: string; webhookUrl?: string }` | ✅ | Export delivery configuration | @@ -567,7 +567,7 @@ Type: `{ sourceField: string; targetField: string; targetLabel?: string; transfo | **fields** | `string[]` | optional | Fields to include | | **filter** | `Record` | optional | Record filter criteria | | **templateId** | `string` | optional | Export template ID for field mappings | -| **schedule** | `{ cronExpression: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; timezone?: string }` | ✅ | Schedule timing configuration | +| **schedule** | `{ cronExpression: string \| object; timezone?: string }` | ✅ | Schedule timing configuration | | **delivery** | `{ method: Enum<'email' \| 'storage' \| 'webhook'>; recipients?: string[]; storagePath?: string; webhookUrl?: string }` | ✅ | Export delivery configuration | | **enabled** | `boolean` | optional | Whether the scheduled export is active | | **lastRunAt** | `string` | optional | Last execution timestamp | diff --git a/content/docs/references/api/metadata.mdx b/content/docs/references/api/metadata.mdx index 35d6a3e68a..c61423d396 100644 --- a/content/docs/references/api/metadata.mdx +++ b/content/docs/references/api/metadata.mdx @@ -94,7 +94,7 @@ const result = AppDefinitionResponseSchema.parse(data); | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ total: integer; succeeded: integer; failed: integer; errors?: { type: string; name: string; error: string }[] }` | ✅ | Bulk operation result | +| **data** | `{ total: integer; succeeded: integer; failed: integer; errors?: object[] }` | ✅ | Bulk operation result | --- @@ -350,7 +350,7 @@ Metadata query with filtering, sorting, and pagination | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ items: { type: string; name: string; namespace?: string; label?: string; … }[]; total: integer; page: integer; pageSize: integer }` | ✅ | Paginated query result | +| **data** | `{ items: object[]; total: integer; page: integer; pageSize: integer }` | ✅ | Paginated query result | --- @@ -447,7 +447,7 @@ Metadata query with filtering, sorting, and pagination | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ valid: boolean; errors?: { path: string; message: string; code?: string }[]; warnings?: { path: string; message: string }[] }` | ✅ | Validation result | +| **data** | `{ valid: boolean; errors?: object[]; warnings?: object[] }` | ✅ | Validation result | --- diff --git a/content/docs/references/api/odata.mdx b/content/docs/references/api/odata.mdx index 6ec9d90812..dacda928ad 100644 --- a/content/docs/references/api/odata.mdx +++ b/content/docs/references/api/odata.mdx @@ -91,7 +91,7 @@ const result = ODataConfigSchema.parse(data); | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | ✅ | Enable OData API | | **path** | `string` | ✅ | OData endpoint path | -| **metadata** | `{ namespace: string; entityTypes: { name: string; key: string[]; properties: { name: string; type: string; nullable: boolean }[]; navigationProperties?: { name: string; type: string; partner?: string }[] }[]; entitySets: { name: string; entityType: string }[] }` | optional | OData metadata configuration | +| **metadata** | `{ namespace: string; entityTypes: object[]; entitySets: object[] }` | optional | OData metadata configuration | --- @@ -102,7 +102,7 @@ const result = ODataConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **error** | `{ code: string; message: string; target?: string; details?: { code: string; message: string; target?: string }[]; … }` | ✅ | | +| **error** | `{ code: string; message: string; target?: string; details?: object[]; … }` | ✅ | | --- @@ -150,7 +150,7 @@ const result = ODataConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **namespace** | `string` | ✅ | Service namespace | -| **entityTypes** | `{ name: string; key: string[]; properties: { name: string; type: string; nullable: boolean }[]; navigationProperties?: { name: string; type: string; partner?: string }[] }[]` | ✅ | Entity types | +| **entityTypes** | `{ name: string; key: string[]; properties: object[]; navigationProperties?: object[] }[]` | ✅ | Entity types | | **entitySets** | `{ name: string; entityType: string }[]` | ✅ | Entity sets | diff --git a/content/docs/references/api/package-api.mdx b/content/docs/references/api/package-api.mdx index 869cc6cfbb..3c76c77bf2 100644 --- a/content/docs/references/api/package-api.mdx +++ b/content/docs/references/api/package-api.mdx @@ -91,7 +91,7 @@ List installed packages response | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ packages: { manifest: object; status?: Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>; enabled?: boolean; installedAt?: string; … }[]; total?: integer; nextCursor?: string; hasMore: boolean }` | ✅ | | +| **data** | `{ packages: object[]; total?: integer; nextCursor?: string; hasMore: boolean }` | ✅ | | --- @@ -145,7 +145,7 @@ Install package response | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ package: object; dependencyResolution?: object; namespaceConflicts?: { type: 'namespace_conflict'; requestedNamespace: string; conflictingPackageId: string; conflictingPackageName: string; … }[]; message?: string }` | ✅ | | +| **data** | `{ package: object; dependencyResolution?: object; namespaceConflicts?: object[]; message?: string }` | ✅ | | --- @@ -252,7 +252,7 @@ Resolve dependencies response | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ dependencies: { packageId: string; requiredRange: string; resolvedVersion?: string; installedVersion?: string; … }[]; canProceed: boolean; requiredActions: { type: Enum<'install' \| 'upgrade' \| 'confirm_conflict'>; packageId: string; description: string }[]; installOrder: string[]; … }` | ✅ | Dependency resolution result with topological sort | +| **data** | `{ dependencies: object[]; canProceed: boolean; requiredActions: object[]; installOrder: string[]; … }` | ✅ | Dependency resolution result with topological sort | --- diff --git a/content/docs/references/api/protocol.mdx b/content/docs/references/api/protocol.mdx index 8cbc817c82..0aa520fe41 100644 --- a/content/docs/references/api/protocol.mdx +++ b/content/docs/references/api/protocol.mdx @@ -268,7 +268,7 @@ const result = AiAgentCapabilitiesSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **object** | `string` | ✅ | Object name | -| **request** | `{ operation: Enum<'create' \| 'update' \| 'upsert' \| 'delete'>; records: { id?: string; data?: Record; externalId?: string }[]; options?: object }` | ✅ | Batch operation request | +| **request** | `{ operation: Enum<'create' \| 'update' \| 'upsert' \| 'delete'>; records: object[]; options?: object }` | ✅ | Batch operation request | --- @@ -286,7 +286,7 @@ const result = AiAgentCapabilitiesSchema.parse(data); | **total** | `number` | ✅ | Total number of records in the batch | | **succeeded** | `number` | ✅ | Number of records that succeeded | | **failed** | `number` | ✅ | Number of records that failed | -| **results** | `{ id?: string; success: boolean; errors?: { code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }[]; data?: Record; … }[]` | ✅ | Detailed results for each record | +| **results** | `{ id?: string; success: boolean; errors?: object[]; data?: Record; … }[]` | ✅ | Detailed results for each record | --- @@ -459,7 +459,7 @@ const result = AiAgentCapabilitiesSchema.parse(data); | **total** | `number` | ✅ | Total number of records in the batch | | **succeeded** | `number` | ✅ | Number of records that succeeded | | **failed** | `number` | ✅ | Number of records that failed | -| **results** | `{ id?: string; success: boolean; errors?: { code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }[]; data?: Record; … }[]` | ✅ | Detailed results for each record | +| **results** | `{ id?: string; success: boolean; errors?: object[]; data?: Record; … }[]` | ✅ | Detailed results for each record | --- @@ -575,7 +575,7 @@ Enable package response | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **object** | `string` | ✅ | The unique machine name of the object to query (e.g. "account"). | -| **query** | `{ object: string; fields?: string[]; where?: any; search?: string \| { query: string; fields?: string[]; fuzzy: boolean; operator: Enum<'and' \| 'or'>; … }; … }` | optional | Structured query definition (filter, sort, select, pagination). | +| **query** | `{ object: string; fields?: string[]; where?: any; search?: string \| object; … }` | optional | Structured query definition (filter, sort, select, pagination). | --- @@ -935,7 +935,7 @@ Get package response | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **locale** | `string` | ✅ | Locale code | -| **translations** | `{ objects?: Record }>; … }>; apps?: Record }>; messages?: Record; globalActions?: Record }>; … }>; … }` | ✅ | Translation data | +| **translations** | `{ objects?: Record; apps?: Record; messages?: Record; globalActions?: Record; … }` | ✅ | Translation data | --- @@ -961,9 +961,9 @@ Get package response | **name** | `string` | optional | Item name — supplied by the metadata door; for an object-scoped container it is the object name. | | **label** | `string` | optional | Human-readable label shown in metadata lists. | | **object** | `string` | optional | Object this container binds to — how a stack-level `views: [...]` entry says which object its views belong to; read by `getViewsByObject()` / `GET /meta/view?object=`. | -| **list** | `{ name?: string; label?: string; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: { provider: 'object'; object: string } \| { provider: 'api'; read?: object; write?: object } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record }; … }` | optional | | +| **list** | `{ name?: string; label?: string; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }` | optional | | | **form** | `{ type?: Enum<'simple' \| 'tabbed' \| 'wizard' \| 'split' \| 'drawer' \| 'modal'>; layout?: Enum<'vertical' \| 'horizontal' \| 'inline' \| 'grid'>; columns?: integer; title?: string; … }` | optional | | -| **listViews** | `Record; data?: { provider: 'object'; object: string } \| { provider: 'api'; read?: object; write?: object } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record }; … }>` | optional | Additional named list views (views mode — dropdown userFilters allowed, no tabs; ADR-0047) | +| **listViews** | `Record; data?: object \| object \| object \| object; … }>` | optional | Additional named list views (views mode — dropdown userFilters allowed, no tabs; ADR-0047) | | **formViews** | `Record; layout?: Enum<'vertical' \| 'horizontal' \| 'inline' \| 'grid'>; columns?: integer; title?: string; … }>` | optional | Additional named form views | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this view. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | @@ -1048,7 +1048,7 @@ Install package response | :--- | :--- | :--- | :--- | | **package** | `{ manifest: object; status?: Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>; enabled?: boolean; installedAt?: string; … }` | ✅ | Installed package details | | **message** | `string` | optional | Installation status message | -| **dependencyResolution** | `{ dependencies: { packageId: string; requiredRange: string; resolvedVersion?: string; installedVersion?: string; … }[]; canProceed: boolean; requiredActions: { type: Enum<'install' \| 'upgrade' \| 'confirm_conflict'>; packageId: string; description: string }[]; installOrder: string[]; … }` | optional | Dependency resolution result from install analysis | +| **dependencyResolution** | `{ dependencies: object[]; canProceed: boolean; requiredActions: object[]; installOrder: string[]; … }` | optional | Dependency resolution result from install analysis | --- @@ -1561,7 +1561,7 @@ Uninstall package response | **total** | `number` | ✅ | Total number of records in the batch | | **succeeded** | `number` | ✅ | Number of records that succeeded | | **failed** | `number` | ✅ | Number of records that failed | -| **results** | `{ id?: string; success: boolean; errors?: { code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }[]; data?: Record; … }[]` | ✅ | Detailed results for each record | +| **results** | `{ id?: string; success: boolean; errors?: object[]; data?: Record; … }[]` | ✅ | Detailed results for each record | --- @@ -1649,7 +1649,7 @@ Uninstall package response | **object** | `string` | ✅ | The object name. | | **mode** | `Enum<'insert' \| 'update'>` | ✅ | The write mode the verdict was reached for. | | **valid** | `boolean` | ✅ | True when EVERY row is valid — the whole-set answer. | -| **results** | `{ valid: boolean; errors: { field: string; code: string; message: string }[]; warnings: { field: string; code: string; message: string }[] }[]` | ✅ | Per-row verdicts, in submission order. | +| **results** | `{ valid: boolean; errors: object[]; warnings: object[] }[]` | ✅ | Per-row verdicts, in submission order. | | **posture** | `{ valueShapeStrict: boolean; mediaValueShapeStrict: boolean }` | ✅ | The ADR-0104 posture the verdict was reached under — reported because it is the difference between "this row is fine" and "this row is fine HERE". The same row can be an error on a self-certified deployment and an admitted warning on an un-migrated one, and a caller explaining a verdict needs to know which it got. An unconditionally-strict preview was considered and rejected (#4633 option B): it would fail rows on every un-migrated deployment that the write would have accepted. | diff --git a/content/docs/references/api/realtime.mdx b/content/docs/references/api/realtime.mdx index 66ac1e4f17..11ab0fa9e2 100644 --- a/content/docs/references/api/realtime.mdx +++ b/content/docs/references/api/realtime.mdx @@ -29,7 +29,7 @@ const result = RealtimeConfigSchema.parse(data); | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | ✅ | Enable realtime synchronization | | **transport** | `Enum<'websocket' \| 'sse' \| 'polling'>` | ✅ | Transport protocol | -| **subscriptions** | `{ id: string; events: { type: Enum<'record.created' \| 'record.updated' \| 'record.deleted' \| 'field.changed'>; object?: string; filters?: any }[]; transport: Enum<'websocket' \| 'sse' \| 'polling'>; channel?: string }[]` | optional | Default subscriptions | +| **subscriptions** | `{ id: string; events: object[]; transport: Enum<'websocket' \| 'sse' \| 'polling'>; channel?: string }[]` | optional | Default subscriptions | --- diff --git a/content/docs/references/api/rest-server.mdx b/content/docs/references/api/rest-server.mdx index 159e03e37a..4f6fb4fea3 100644 --- a/content/docs/references/api/rest-server.mdx +++ b/content/docs/references/api/rest-server.mdx @@ -169,10 +169,10 @@ const result = BatchEndpointsConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **api** | `{ version: string; basePath: string; apiPath?: string; enableCrud: boolean; … }` | optional | REST API configuration | -| **crud** | `{ operations?: object; patterns?: Record; path: string; summary?: string; description?: string }>; dataPrefix: string; objectParamStyle: Enum<'path' \| 'query'> }` | optional | CRUD endpoints configuration | +| **crud** | `{ operations?: object; patterns?: Record; dataPrefix: string; objectParamStyle: Enum<'path' \| 'query'> }` | optional | CRUD endpoints configuration | | **metadata** | `{ prefix: string; enableCache: boolean; cacheTtl: integer; endpoints?: object }` | optional | Metadata endpoints configuration | | **batch** | `{ maxBatchSize: integer; enableBatchEndpoint: boolean; operations?: object; defaultAtomic: boolean }` | optional | Batch endpoints configuration | -| **routes** | `{ includeObjects?: string[]; excludeObjects?: string[]; nameTransform: Enum<'none' \| 'plural' \| 'kebab-case' \| 'camelCase'>; overrides?: Record }> }` | optional | Route generation configuration | +| **routes** | `{ includeObjects?: string[]; excludeObjects?: string[]; nameTransform: Enum<'none' \| 'plural' \| 'kebab-case' \| 'camelCase'>; overrides?: Record }` | optional | Route generation configuration | | **openApi31** | `never` | optional | [REMOVED] `RestServerConfig.openApi31` was removed in @objectstack/spec 17 (#4579, ADR-0049) — no runtime ever read it: the REST server forwards only `api`/`crud`/`metadata`/`batch`/`routes`, and the served /openapi.json is the pre-generated contract enriched with the live server URL and the registered objects, so webhook/callback definitions declared here never appeared in it. Delete the key. Config-driven OpenAPI 3.1 webhooks/callbacks documentation is a new capability and must arrive via the enforce route of ADR-0049 (a new ADR), not by re-declaring the key; for a real outbound webhook use `Webhook` from `@objectstack/spec/automation`. | diff --git a/content/docs/references/automation/control-flow.mdx b/content/docs/references/automation/control-flow.mdx index 7a839bca46..c3331ccfb4 100644 --- a/content/docs/references/automation/control-flow.mdx +++ b/content/docs/references/automation/control-flow.mdx @@ -94,7 +94,7 @@ const result = FlowRegionSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **nodes** | `{ id: string; type: string; label: string; config?: Record; … }[]` | ✅ | Region body nodes (single-entry/single-exit sub-graph) | -| **edges** | `{ id: string; source: string; target: string; condition?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; … }[]` | optional | Region body edges | +| **edges** | `{ id: string; source: string; target: string; condition?: string \| object; … }[]` | optional | Region body edges | --- @@ -109,7 +109,7 @@ const result = FlowRegionSchema.parse(data); | **iteratorVariable** | `string` | optional | Loop variable holding the current item | | **indexVariable** | `string` | optional | Optional loop variable holding the current index | | **maxIterations** | `integer` | optional | Hard cap on iterations (clamped to the engine ceiling) | -| **body** | `{ nodes: { id: string; type: string; label: string; config?: Record; … }[]; edges?: { id: string; source: string; target: string; condition?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; … }[] }` | optional | Loop body region (omit for legacy flat-graph loops) | +| **body** | `{ nodes: object[]; edges?: object[] }` | optional | Loop body region (omit for legacy flat-graph loops) | --- @@ -122,7 +122,7 @@ const result = FlowRegionSchema.parse(data); | :--- | :--- | :--- | :--- | | **name** | `string` | optional | Branch label | | **nodes** | `{ id: string; type: string; label: string; config?: Record; … }[]` | ✅ | Branch body nodes | -| **edges** | `{ id: string; source: string; target: string; condition?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; … }[]` | optional | Branch body edges | +| **edges** | `{ id: string; source: string; target: string; condition?: string \| object; … }[]` | optional | Branch body edges | --- @@ -133,7 +133,7 @@ const result = FlowRegionSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **branches** | `{ name?: string; nodes: { id: string; type: string; label: string; config?: Record; … }[]; edges?: { id: string; source: string; target: string; condition?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; … }[] }[]` | ✅ | Branch regions executed concurrently; implicit join at block end | +| **branches** | `{ name?: string; nodes: object[]; edges?: object[] }[]` | ✅ | Branch regions executed concurrently; implicit join at block end | --- @@ -160,8 +160,8 @@ const result = FlowRegionSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **try** | `{ nodes: { id: string; type: string; label: string; config?: Record; … }[]; edges?: { id: string; source: string; target: string; condition?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; … }[] }` | ✅ | Protected region | -| **catch** | `{ nodes: { id: string; type: string; label: string; config?: Record; … }[]; edges?: { id: string; source: string; target: string; condition?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; … }[] }` | optional | Handler region run when the try region fails | +| **try** | `{ nodes: object[]; edges?: object[] }` | ✅ | Protected region | +| **catch** | `{ nodes: object[]; edges?: object[] }` | optional | Handler region run when the try region fails | | **errorVariable** | `string` | optional | Variable holding the caught error in the catch region | | **retry** | `{ maxRetries?: integer; backoffMs?: integer; backoffMultiplier?: number; maxRetryDelayMs?: integer; … }` | optional | Optional retry policy for the try region | diff --git a/content/docs/references/automation/flow.mdx b/content/docs/references/automation/flow.mdx index b1a8c783c1..70c3538c94 100644 --- a/content/docs/references/automation/flow.mdx +++ b/content/docs/references/automation/flow.mdx @@ -50,7 +50,7 @@ const result = FlowSchema.parse(data); | **type** | `Enum<'autolaunched' \| 'record_change' \| 'schedule' \| 'screen' \| 'api'>` | ✅ | Flow type | | **variables** | `{ name: string; type: string; isInput?: boolean; isOutput?: boolean }[]` | optional | Flow variables | | **nodes** | `{ id: string; type: string; label: string; config?: Record; … }[]` | ✅ | Flow nodes | -| **edges** | `{ id: string; source: string; target: string; condition?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; … }[]` | ✅ | Flow connections | +| **edges** | `{ id: string; source: string; target: string; condition?: string \| object; … }[]` | ✅ | Flow connections | | **active** | `never` | optional | [REMOVED] `flow.active` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it never had an effect: the engine arms flows from `status`, and `active: false` did NOT stop a flow (worse, the default read as disabled while the engine treated unset as enabled). Delete the key. Use `status: 'obsolete'` (or 'invalid') to unbind and disable a flow, `status: 'active'` to arm it. | | **runAs** | `Enum<'system' \| 'user'>` | optional | Execution identity for the run: system = elevated (bypasses RLS), user = the triggering user (RLS-respecting). A run with no trigger user has no identity to scope to, so under user its data operations are REFUSED — declare system to make the elevation explicit. This covers schedule/time-relative/api triggers AND any record-change flow fired by a write that carried no user. | | **errorHandling** | `{ strategy?: Enum<'fail' \| 'retry' \| 'continue'>; maxRetries?: integer; backoffMs?: integer; backoffMultiplier?: number; … }` | optional | Flow-level error handling configuration | diff --git a/content/docs/references/automation/state-machine.mdx b/content/docs/references/automation/state-machine.mdx index cd7019fd24..e6c9356019 100644 --- a/content/docs/references/automation/state-machine.mdx +++ b/content/docs/references/automation/state-machine.mdx @@ -143,8 +143,8 @@ Type: `string` | **description** | `string` | optional | | | **contextSchema** | `Record` | optional | Zod Schema for the machine context/memory | | **initial** | `string` | ✅ | Initial State ID | -| **states** | `Record; entry?: (string \| { type: string; params?: Record })[]; exit?: (string \| { type: string; params?: Record })[]; on?: Record }; actions?: (string \| { type: string; params?: Record })[]; description?: string } \| { target?: string; cond?: string \| { type: string; params?: Record }; actions?: (string \| { type: string; params?: Record })[]; description?: string }[]>; … }>` | ✅ | State Nodes | -| **on** | `Record }; actions?: (string \| { type: string; params?: Record })[]; description?: string } \| { target?: string; cond?: string \| { type: string; params?: Record }; actions?: (string \| { type: string; params?: Record })[]; description?: string }[]>` | optional | | +| **states** | `Record; entry?: (string \| object)[]; exit?: (string \| object)[]; on?: Record; … }>` | ✅ | State Nodes | +| **on** | `Record` | optional | | --- @@ -158,8 +158,8 @@ Type: `string` | **type** | `Enum<'atomic' \| 'compound' \| 'parallel' \| 'final' \| 'history'>` | ✅ | | | **entry** | `(string \| { type: string; params?: Record })[]` | optional | Actions to run when entering this state | | **exit** | `(string \| { type: string; params?: Record })[]` | optional | Actions to run when leaving this state | -| **on** | `Record }; actions?: (string \| { type: string; params?: Record })[]; description?: string } \| { target?: string; cond?: string \| { type: string; params?: Record }; actions?: (string \| { type: string; params?: Record })[]; description?: string }[]>` | optional | Map of Event Type -> Transition Definition | -| **always** | `{ target?: string; cond?: string \| { type: string; params?: Record }; actions?: (string \| { type: string; params?: Record })[]; description?: string }[]` | optional | | +| **on** | `Record` | optional | Map of Event Type -> Transition Definition | +| **always** | `{ target?: string; cond?: string \| object; actions?: (string \| object)[]; description?: string }[]` | optional | | | **initial** | `string` | optional | Initial child state (if compound) | | **states** | `Record` | optional | | | **meta** | `{ label?: string; description?: string; color?: string; aiInstructions?: string }` | optional | | diff --git a/content/docs/references/cloud/marketplace.mdx b/content/docs/references/cloud/marketplace.mdx index f0a006ea65..a0749ca250 100644 --- a/content/docs/references/cloud/marketplace.mdx +++ b/content/docs/references/cloud/marketplace.mdx @@ -238,7 +238,7 @@ Marketplace search response | **total** | `integer` | ✅ | Total matching results | | **page** | `integer` | ✅ | Current page number | | **pageSize** | `integer` | ✅ | Items per page | -| **facets** | `{ categories?: { category: Enum<'crm' \| 'erp' \| 'hr' \| 'finance' \| 'project' \| 'collaboration' \| 'analytics' \| … +8 more>; count: integer }[]; pricing?: { model: Enum<'free' \| 'freemium' \| 'paid' \| 'subscription' \| 'usage-based' \| 'contact-sales'>; count: integer }[] }` | optional | Aggregation facets for refining search | +| **facets** | `{ categories?: object[]; pricing?: object[] }` | optional | Aggregation facets for refining search | --- @@ -259,7 +259,7 @@ Developer submission of a package version for review | **artifactUrl** | `string` | ✅ | Package artifact URL for review | | **releaseNotes** | `string` | optional | Release notes for this version | | **isNewListing** | `boolean` | ✅ | Whether this is a new listing submission | -| **scanResults** | `{ passed: boolean; securityScore?: number; compatibilityCheck?: boolean; issues?: { severity: Enum<'critical' \| 'high' \| 'medium' \| 'low' \| 'info'>; message: string; file?: string; line?: number }[] }` | optional | Automated scan results | +| **scanResults** | `{ passed: boolean; securityScore?: number; compatibilityCheck?: boolean; issues?: object[] }` | optional | Automated scan results | | **reviewerNotes** | `string` | optional | Notes from the platform reviewer | | **submittedAt** | `string` | optional | Submission timestamp | | **reviewedAt** | `string` | optional | Review completion timestamp | diff --git a/content/docs/references/data/data-engine.mdx b/content/docs/references/data/data-engine.mdx index 07ae177fa0..8f1a753238 100644 --- a/content/docs/references/data/data-engine.mdx +++ b/content/docs/references/data/data-engine.mdx @@ -65,7 +65,7 @@ Options for DataEngine.aggregate operations | :--- | :--- | :--- | :--- | | **method** | `'aggregate'` | ✅ | | | **object** | `string` | ✅ | | -| **query** | `{ context?: object; where?: Record \| any; groupBy?: string[]; aggregations?: { function: Enum<'count' \| 'sum' \| 'avg' \| 'min' \| 'max' \| 'count_distinct'>; field?: string; alias: string; distinct?: boolean; … }[]; … }` | ✅ | | +| **query** | `{ context?: object; where?: Record \| any; groupBy?: string[]; aggregations?: object[]; … }` | ✅ | | --- @@ -170,7 +170,7 @@ Reference: any | :--- | :--- | :--- | :--- | | **method** | `'findOne'` | ✅ | | | **object** | `string` | ✅ | | -| **query** | `{ context?: object; where?: Record \| any; fields?: string[]; orderBy?: { field: string; order?: Enum<'asc' \| 'desc'> }[]; … }` | optional | | +| **query** | `{ context?: object; where?: Record \| any; fields?: string[]; orderBy?: object[]; … }` | optional | | --- @@ -183,7 +183,7 @@ Reference: any | :--- | :--- | :--- | :--- | | **method** | `'find'` | ✅ | | | **object** | `string` | ✅ | | -| **query** | `{ context?: object; where?: Record \| any; fields?: string[]; orderBy?: { field: string; order?: Enum<'asc' \| 'desc'> }[]; … }` | optional | | +| **query** | `{ context?: object; where?: Record \| any; fields?: string[]; orderBy?: object[]; … }` | optional | | --- @@ -252,7 +252,7 @@ This schema accepts one of the following structures: | :--- | :--- | :--- | :--- | | **method** | `'find'` | ✅ | | | **object** | `string` | ✅ | | -| **query** | `{ context?: object; where?: Record \| any; fields?: string[]; orderBy?: { field: string; order?: Enum<'asc' \| 'desc'> }[]; … }` | optional | | +| **query** | `{ context?: object; where?: Record \| any; fields?: string[]; orderBy?: object[]; … }` | optional | | --- @@ -264,7 +264,7 @@ This schema accepts one of the following structures: | :--- | :--- | :--- | :--- | | **method** | `'findOne'` | ✅ | | | **object** | `string` | ✅ | | -| **query** | `{ context?: object; where?: Record \| any; fields?: string[]; orderBy?: { field: string; order?: Enum<'asc' \| 'desc'> }[]; … }` | optional | | +| **query** | `{ context?: object; where?: Record \| any; fields?: string[]; orderBy?: object[]; … }` | optional | | --- @@ -328,7 +328,7 @@ This schema accepts one of the following structures: | :--- | :--- | :--- | :--- | | **method** | `'aggregate'` | ✅ | | | **object** | `string` | ✅ | | -| **query** | `{ context?: object; where?: Record \| any; groupBy?: string[]; aggregations?: { function: Enum<'count' \| 'sum' \| 'avg' \| 'min' \| 'max' \| 'count_distinct'>; field?: string; alias: string; distinct?: boolean; … }[]; … }` | ✅ | | +| **query** | `{ context?: object; where?: Record \| any; groupBy?: string[]; aggregations?: object[]; … }` | ✅ | | --- @@ -521,7 +521,7 @@ QueryAST-aligned query options for IDataEngine.find() operations | **cursor** | `never` | optional | [REMOVED] `query.cursor` was removed in @objectstack/spec 17 (#4286, ADR-0049) — no driver ever implemented keyset pagination, so the cursor was accepted and ignored and every page came back identical (a caller looping "until hasMore is false" never terminates). Delete the key; `QueryBuilder.cursor()` was removed with it. Express the keyset as an ordinary `where` predicate on your sort key — `where: { created_at: { $gt: last.created_at } }` with the matching `orderBy` — which every driver executes with canonicalised comparands. A first-class cursor, if ever built, will be a response-minted opaque token, not this caller-built record. | | **search** | `{ query: string; fields?: string[]; fuzzy: boolean; operator: Enum<'and' \| 'or'>; … }` | optional | | | **searchFields** | `string[]` | optional | | -| **expand** | `Record; … }; … }>` | optional | | +| **expand** | `Record` | optional | | | **distinct** | `never` | optional | [REMOVED] `query.distinct` was removed in @objectstack/spec 17 (#4286, ADR-0049 / ADR-0078) — no driver ever rendered SELECT DISTINCT; the flag's only observable effect was MIS-WIRED: the REST list path treated a distinct query as not countable and silently degraded `total`/`hasMore` to a page-local estimate while still returning duplicate rows. Delete the key; `QueryBuilder.distinct()` was removed with it, and the count suppression is gone (`total` is truthful again). For unique values of one column use the SQL/memory drivers' `distinct(object, field)` door; for unique combinations, `groupBy`; for a deduplicated count, the `count_distinct` aggregation. | diff --git a/content/docs/references/data/document.mdx b/content/docs/references/data/document.mdx index d78f2561c2..6be292d5b4 100644 --- a/content/docs/references/data/document.mdx +++ b/content/docs/references/data/document.mdx @@ -52,9 +52,9 @@ const result = DocumentSchema.parse(data); | **fileSize** | `number` | ✅ | File size in bytes | | **category** | `string` | optional | Document category | | **tags** | `string[]` | optional | Document tags | -| **versioning** | `{ enabled: boolean; versions: { versionNumber: number; createdAt: number; createdBy: string; size: number; … }[]; majorVersion: number; minorVersion: number }` | optional | Version control | +| **versioning** | `{ enabled: boolean; versions: object[]; majorVersion: number; minorVersion: number }` | optional | Version control | | **template** | `{ id: string; name: string; description?: string; fileUrl: string; … }` | optional | Document template | -| **eSignature** | `{ provider: Enum<'docusign' \| 'adobe-sign' \| 'hellosign' \| 'custom'>; enabled: boolean; signers: { email: string; name: string; role: string; order: number }[]; expirationDays: number; … }` | optional | E-signature config | +| **eSignature** | `{ provider: Enum<'docusign' \| 'adobe-sign' \| 'hellosign' \| 'custom'>; enabled: boolean; signers: object[]; expirationDays: number; … }` | optional | E-signature config | | **access** | `{ isPublic: boolean; sharedWith?: string[]; expiresAt?: number }` | optional | Access control | | **metadata** | `Record` | optional | Custom metadata | diff --git a/content/docs/references/data/external-catalog.mdx b/content/docs/references/data/external-catalog.mdx index 72017be763..dc57749550 100644 --- a/content/docs/references/data/external-catalog.mdx +++ b/content/docs/references/data/external-catalog.mdx @@ -40,7 +40,7 @@ const result = ExternalCatalogSchema.parse(data); | **datasource** | `string` | ✅ | Datasource.name this catalog snapshots. | | **snapshotAt** | `string` | ✅ | When the snapshot was taken (ISO 8601). | | **dialect** | `string` | optional | Remote SQL dialect, when known. | -| **tables** | `{ remoteSchema?: string; remoteName: string; columns: { name: string; sqlType: string; nullable: boolean; primaryKey: boolean; … }[]; indexes?: { name: string; columns: string[]; unique: boolean }[]; … }[]` | ✅ | Snapshotted remote tables. | +| **tables** | `{ remoteSchema?: string; remoteName: string; columns: object[]; indexes?: object[]; … }[]` | ✅ | Snapshotted remote tables. | --- diff --git a/content/docs/references/data/object.mdx b/content/docs/references/data/object.mdx index a343475980..77ccb1eb4a 100644 --- a/content/docs/references/data/object.mdx +++ b/content/docs/references/data/object.mdx @@ -81,7 +81,7 @@ const result = ApiMethod.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **class** | `Enum<'record' \| 'audit' \| 'telemetry' \| 'transient' \| 'event'>` | ✅ | Persistence contract: record (business truth, permanent) \| audit (compliance ledger) \| telemetry (high-freq log) \| transient (ephemeral state) \| event (bus messages). | -| **retention** | `{ maxAge: string; onlyWhen?: Record }` | optional | Age-based retention window enforced by the LifecycleService Reaper. | +| **retention** | `{ maxAge: string; onlyWhen?: Record }` | optional | Age-based retention window enforced by the LifecycleService Reaper. | | **ttl** | `{ field: string; expireAfter: string }` | optional | Per-row TTL auto-expiry (transient/event classes). | | **storage** | `{ strategy: 'rotation'; shards: integer; unit: Enum<'day' \| 'week' \| 'month'> }` | optional | Physical storage strategy for high-frequency telemetry (LifecycleService Rotator). | | **archive** | `{ after: string; to: string; keep?: string }` | optional | Cold-store archival (LifecycleService Archiver) — audit-class hot→cold hand-off. | @@ -117,7 +117,7 @@ const result = ApiMethod.parse(data); | **isSystem** | `boolean` | optional | Is system object (protected from deletion; defaults its org-wide sharing to public when no sharingModel is set — plugin-sharing) | | **managedBy** | `Enum<'platform' \| 'config' \| 'system-data' \| 'engine-owned' \| 'append-only' \| 'better-auth'>` | optional | Lifecycle bucket — platform (user CRUD) \| config (admin authored) \| system-data (platform-defined schema, admin/user-writable data) \| engine-owned (engine owns the lifecycle, no user writes) \| append-only (audit) \| better-auth (identity). UI clients honour the resolved affordance matrix. | | **ownership** | `Enum<'user' \| 'org' \| 'none'>` | optional | Record-ownership model: user (default — injects reassignable owner_id) \| org \| none (no per-record owner, skips owner_id). Distinct from the package own/extend contribution kind. | -| **userActions** | `{ create?: boolean; import?: boolean; edit?: boolean \| { enabled?: boolean; visibleWhen?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; disabledWhen?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object } }; delete?: boolean \| { enabled?: boolean; visibleWhen?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; disabledWhen?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object } }; … }` | optional | Per-object override of the resolved CRUD affordance matrix. | +| **userActions** | `{ create?: boolean; import?: boolean; edit?: boolean \| object; delete?: boolean \| object; … }` | optional | Per-object override of the resolved CRUD affordance matrix. | | **systemFields** | `false \| { tenant?: boolean; audit?: boolean }` | optional | Opt out of, or selectively disable, registry-level system-field auto-injection. | | **datasource** | `string` | optional | Target Datasource ID. "default" is the primary DB. | | **external** | `{ remoteName?: string; remoteSchema?: string; writable?: boolean; columnMap?: Record; … }` | optional | Remote table binding for federated (external) objects. | @@ -136,7 +136,7 @@ const result = ApiMethod.parse(data); | **titleFormat** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | [DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField, a composite to a formula field designated as nameField. | | **highlightFields** | `string[]` | optional | [ADR-0085] Ordered most-important fields; first entry wins where only one fits. Drives default columns, cards, previews, detail highlight strip. Renamed from compactLayout. | | **stageField** | `string \| false` | optional | [ADR-0085] Lifecycle stage field (linear/ordered), or false to declare the status field non-linear and suppress stage heuristics. Absent = heuristic detection allowed. | -| **listViews** | `Record; data?: { provider: 'object'; object: string } \| { provider: 'api'; read?: object; write?: object } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record }; … }>` | optional | Built-in named list views (segmented tabs) shipped with the object schema — "views" mode, dropdown userFilters allowed, no page-only tabs (ADR-0047) | +| **listViews** | `Record; data?: object \| object \| object \| object; … }>` | optional | Built-in named list views (segmented tabs) shipped with the object schema — "views" mode, dropdown userFilters allowed, no page-only tabs (ADR-0047) | | **searchableFields** | `string[]` | optional | Fields the `$search` query matches against (ADR-0061). Canonical default for the record picker, list quick-search and global search; views may narrow it. When unset, search auto-defaults to the name/title field plus short-text fields. | | **enable** | `{ trackHistory?: boolean; searchable?: boolean; apiEnabled?: boolean; apiMethods?: Enum<'get' \| 'list' \| 'create' \| 'update' \| 'delete' \| 'bulk'>[]; … }` | optional | Enabled system features modules | | **sharingModel** | `Enum<'private' \| 'public_read' \| 'public_read_write' \| 'controlled_by_parent'>` | optional | Org-Wide Default record visibility (OWD) for INTERNAL users. Canonical four only (legacy aliases removed, ADR-0090 D4): private (owner-only) \| public_read (everyone reads, owner writes) \| public_read_write (everyone reads+writes) \| controlled_by_parent (derived from the master record). A CUSTOM object that omits this resolves to private at runtime (ADR-0090 D1). | diff --git a/content/docs/references/data/seed-loader.mdx b/content/docs/references/data/seed-loader.mdx index 0189cf7d33..1203ceffc5 100644 --- a/content/docs/references/data/seed-loader.mdx +++ b/content/docs/references/data/seed-loader.mdx @@ -49,7 +49,7 @@ Complete object dependency graph for seed data loading | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **nodes** | `{ object: string; dependsOn: string[]; references: { field: string; targetObject: string; targetField: string; fieldType: Enum<'lookup' \| 'master_detail' \| 'user'>; … }[] }[]` | ✅ | All objects in the dependency graph | +| **nodes** | `{ object: string; dependsOn: string[]; references: object[] }[]` | ✅ | All objects in the dependency graph | | **insertOrder** | `string[]` | ✅ | Topologically sorted insert order | | **circularDependencies** | `string[][]` | ✅ | Circular dependency chains (e.g., [["a", "b", "a"]]) | @@ -190,7 +190,7 @@ Complete seed loader result | :--- | :--- | :--- | :--- | | **success** | `boolean` | ✅ | Overall success status | | **dryRun** | `boolean` | ✅ | Whether this was a dry-run | -| **dependencyGraph** | `{ nodes: { object: string; dependsOn: string[]; references: { field: string; targetObject: string; targetField: string; fieldType: Enum<'lookup' \| 'master_detail' \| 'user'>; … }[] }[]; insertOrder: string[]; circularDependencies: string[][] }` | ✅ | Object dependency graph | +| **dependencyGraph** | `{ nodes: object[]; insertOrder: string[]; circularDependencies: string[][] }` | ✅ | Object dependency graph | | **results** | `{ object: string; mode: Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>; inserted: integer; updated: integer; … }[]` | ✅ | Per-object load results | | **errors** | `{ sourceObject: string; field: string; targetObject: string; targetField: string; … }[]` | ✅ | All reference resolution errors | | **summary** | `{ objectsProcessed: integer; totalRecords: integer; totalInserted: integer; totalUpdated: integer; … }` | ✅ | Summary statistics | diff --git a/content/docs/references/integration/connector.mdx b/content/docs/references/integration/connector.mdx index c109cc96fa..d5db6d0fbf 100644 --- a/content/docs/references/integration/connector.mdx +++ b/content/docs/references/integration/connector.mdx @@ -165,7 +165,7 @@ Circuit breaker configuration | **auth** | `{ type: 'none' } \| { type: 'bearer'; credentialRef: string } \| { type: 'api-key'; credentialRef: string; headerName?: string; paramName?: string } \| { type: 'basic'; username: string; credentialRef: string }` | optional | Declarative instance auth — references credentials via `credentialRef` (resolved at boot), never inline secrets. Requires `provider` (ADR-0097). | | **actions** | `{ key: string; label: string; description?: string; inputSchema?: Record; … }[]` | optional | | | **triggers** | `{ key: string; label: string; description?: string; type: Enum<'polling' \| 'webhook'>; … }[]` | optional | Trigger definitions (not yet enforced — never read at registration; see #3197) | -| **syncConfig** | `{ strategy?: Enum<'full' \| 'incremental' \| 'upsert' \| 'append_only'>; direction?: Enum<'import' \| 'export' \| 'bidirectional'>; schedule?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; realtimeSync?: boolean; … }` | optional | Data sync configuration | +| **syncConfig** | `{ strategy?: Enum<'full' \| 'incremental' \| 'upsert' \| 'append_only'>; direction?: Enum<'import' \| 'export' \| 'bidirectional'>; schedule?: string \| object; realtimeSync?: boolean; … }` | optional | Data sync configuration | | **fieldMappings** | `{ source: string; target: string; defaultValue?: any; dataType?: Enum<'string' \| 'number' \| 'boolean' \| 'date' \| 'datetime' \| 'json' \| 'array'>; … }[]` | optional | Field mapping rules | | **webhooks** | `{ name: string; label?: string; object?: string; triggers?: Enum<'create' \| 'update' \| 'delete' \| 'bulk_update' \| 'bulk_delete'>[]; … }[]` | optional | Webhook configurations (not yet enforced — never read at registration; see #3197) | | **rateLimitConfig** | `never` | optional | [REMOVED] `connector.rateLimitConfig` was removed in @objectstack/spec 17.0.0 (#4911, ADR-0049 D2) — the entire shape is gone, not just this key: `ConnectorRateLimitConfig` and its `RateLimitStrategy` enum were removed with it, because no outbound rate-limiting engine ever existed. The platform's only token bucket (runtime `security/rate-limit.ts`) throttles INBOUND requests to us; nothing throttled the calls a connector makes out, so every knob here was inert while reading like a configured cap. Delete the key. Do NOT substitute `shared` `RateLimitConfig` — that is the inbound limiter and would cap the wrong direction; until an outbound throttle exists, rate-limit at the connector provider or upstream gateway. Run `os migrate meta --from 16` to rewrite it automatically. | @@ -174,7 +174,7 @@ Circuit breaker configuration | **requestTimeoutMs** | `number` | optional | Request timeout in ms | | **status** | `Enum<'active' \| 'inactive' \| 'error' \| 'configuring'>` | optional | Connector status | | **enabled** | `boolean` | optional | Enable connector. On declarative stack entries, false marks a deliberate catalog-only descriptor (#2612). | -| **errorMapping** | `{ rules: { sourceCode: string \| number; sourceMessage?: string; targetCode: string; targetCategory: Enum<'validation' \| 'authorization' \| 'not_found' \| 'conflict' \| 'rate_limit' \| … +3 more>; … }[]; defaultCategory?: Enum<'validation' \| 'authorization' \| 'not_found' \| 'conflict' \| 'rate_limit' \| … +3 more>; unmappedBehavior: Enum<'passthrough' \| 'generic_error' \| 'throw'>; logUnmapped?: boolean }` | optional | Error mapping configuration | +| **errorMapping** | `{ rules: object[]; defaultCategory?: Enum<'validation' \| 'authorization' \| 'not_found' \| 'conflict' \| 'rate_limit' \| … +3 more>; unmappedBehavior: Enum<'passthrough' \| 'generic_error' \| 'throw'>; logUnmapped?: boolean }` | optional | Error mapping configuration | | **health** | `{ healthCheck?: object; circuitBreaker?: object }` | optional | Health and resilience configuration | | **metadata** | `Record` | optional | Custom connector metadata | @@ -480,7 +480,7 @@ Connector type | **auth** | `{ type: 'none' } \| { type: 'bearer'; credentialRef: string } \| { type: 'api-key'; credentialRef: string; headerName?: string; paramName?: string } \| { type: 'basic'; username: string; credentialRef: string }` | optional | Declarative instance auth — references credentials via `credentialRef` (resolved at boot), never inline secrets. Requires `provider` (ADR-0097). | | **actions** | `{ key: string; label: string; description?: string; inputSchema?: Record; … }[]` | optional | | | **triggers** | `{ key: string; label: string; description?: string; type: Enum<'polling' \| 'webhook'>; … }[]` | optional | Trigger definitions (not yet enforced — never read at registration; see #3197) | -| **syncConfig** | `{ strategy?: Enum<'full' \| 'incremental' \| 'upsert' \| 'append_only'>; direction?: Enum<'import' \| 'export' \| 'bidirectional'>; schedule?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; realtimeSync?: boolean; … }` | optional | Data sync configuration | +| **syncConfig** | `{ strategy?: Enum<'full' \| 'incremental' \| 'upsert' \| 'append_only'>; direction?: Enum<'import' \| 'export' \| 'bidirectional'>; schedule?: string \| object; realtimeSync?: boolean; … }` | optional | Data sync configuration | | **fieldMappings** | `{ source: string; target: string; defaultValue?: any; dataType?: Enum<'string' \| 'number' \| 'boolean' \| 'date' \| 'datetime' \| 'json' \| 'array'>; … }[]` | optional | Field mapping rules | | **webhooks** | `{ name: string; label?: string; object?: string; triggers?: Enum<'create' \| 'update' \| 'delete' \| 'bulk_update' \| 'bulk_delete'>[]; … }[]` | optional | Webhook configurations (not yet enforced — never read at registration; see #3197) | | **rateLimitConfig** | `never` | optional | [REMOVED] `connector.rateLimitConfig` was removed in @objectstack/spec 17.0.0 (#4911, ADR-0049 D2) — the entire shape is gone, not just this key: `ConnectorRateLimitConfig` and its `RateLimitStrategy` enum were removed with it, because no outbound rate-limiting engine ever existed. The platform's only token bucket (runtime `security/rate-limit.ts`) throttles INBOUND requests to us; nothing throttled the calls a connector makes out, so every knob here was inert while reading like a configured cap. Delete the key. Do NOT substitute `shared` `RateLimitConfig` — that is the inbound limiter and would cap the wrong direction; until an outbound throttle exists, rate-limit at the connector provider or upstream gateway. Run `os migrate meta --from 16` to rewrite it automatically. | @@ -489,7 +489,7 @@ Connector type | **requestTimeoutMs** | `number` | optional | Request timeout in ms | | **status** | `Enum<'active' \| 'inactive' \| 'error' \| 'configuring'>` | optional | Connector status | | **enabled** | `boolean` | optional | Enable connector. On declarative stack entries, false marks a deliberate catalog-only descriptor (#2612). | -| **errorMapping** | `{ rules: { sourceCode: string \| number; sourceMessage?: string; targetCode: string; targetCategory: Enum<'validation' \| 'authorization' \| 'not_found' \| 'conflict' \| 'rate_limit' \| … +3 more>; … }[]; defaultCategory?: Enum<'validation' \| 'authorization' \| 'not_found' \| 'conflict' \| 'rate_limit' \| … +3 more>; unmappedBehavior: Enum<'passthrough' \| 'generic_error' \| 'throw'>; logUnmapped?: boolean }` | optional | Error mapping configuration | +| **errorMapping** | `{ rules: object[]; defaultCategory?: Enum<'validation' \| 'authorization' \| 'not_found' \| 'conflict' \| 'rate_limit' \| … +3 more>; unmappedBehavior: Enum<'passthrough' \| 'generic_error' \| 'throw'>; logUnmapped?: boolean }` | optional | Error mapping configuration | | **health** | `{ healthCheck?: object; circuitBreaker?: object }` | optional | Health and resilience configuration | | **metadata** | `Record` | optional | Custom connector metadata | diff --git a/content/docs/references/kernel/manifest.mdx b/content/docs/references/kernel/manifest.mdx index b7a54c7a72..f0f3ca8e3f 100644 --- a/content/docs/references/kernel/manifest.mdx +++ b/content/docs/references/kernel/manifest.mdx @@ -39,12 +39,12 @@ const result = ManifestSchema.parse(data); | **objects** | `string[]` | optional | Glob patterns for ObjectQL schemas files | | **datasources** | `string[]` | optional | Glob patterns for Datasource definitions | | **dependencies** | `Record` | optional | Package dependencies | -| **configuration** | `{ title?: string; properties: Record; default?: any; description?: string; required?: boolean; … }> }` | optional | Plugin configuration settings | -| **contributes** | `{ kinds?: { id: string; globs: string[]; description?: string }[]; events?: string[]; menus?: Record; themes?: { id: string; label: string; path: string }[]; … }` | optional | Platform contributions | +| **configuration** | `{ title?: string; properties: Record }` | optional | Plugin configuration settings | +| **contributes** | `{ kinds?: object[]; events?: string[]; menus?: Record; themes?: object[]; … }` | optional | Platform contributions | | **data** | `{ object: string; externalId?: string \| string[]; mode?: Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>; env?: Enum<'prod' \| 'dev' \| 'test'>[]; … }[]` | optional | Initial seed data (prefer top-level data field) | -| **capabilities** | `{ implements?: { protocol: object; conformance?: Enum<'full' \| 'partial' \| 'experimental' \| 'deprecated'>; implementedFeatures?: string[]; features?: { name: string; enabled?: boolean; description?: string; sinceVersion?: string; … }[]; … }[]; provides?: { id: string; name: string; description?: string; version: object; … }[]; requires?: { pluginId: string; version: string; optional?: boolean; reason?: string; … }[]; extensionPoints?: { id: string; name: string; description?: string; type: Enum<'action' \| 'hook' \| 'widget' \| 'provider' \| 'transformer' \| 'validator' \| 'decorator'>; … }[]; … }` | optional | Plugin capability declarations for interoperability | +| **capabilities** | `{ implements?: object[]; provides?: object[]; requires?: object[]; extensionPoints?: object[]; … }` | optional | Plugin capability declarations for interoperability | | **extensions** | `Record` | optional | Extension points and contributions | -| **navigationContributions** | `{ app: string; group?: string; priority?: integer; items: ({ id: string; label: string; icon?: string; order?: number; … } \| { id: string; label: string; icon?: string; order?: number; … } \| { id: string; label: string; icon?: string; order?: number; … } \| { id: string; label: string; icon?: string; order?: number; … } \| … +5 more)[] }[]` | optional | Navigation items this package contributes into apps owned by other packages | +| **navigationContributions** | `{ app: string; group?: string; priority?: integer; items: (object \| object \| object \| object \| … +5 more)[] }[]` | optional | Navigation items this package contributes into apps owned by other packages | | **loading** | `{ strategy?: Enum<'eager' \| 'lazy' \| 'parallel' \| 'deferred' \| 'on-demand'>; preload?: object; codeSplitting?: object; dynamicImport?: object; … }` | optional | Plugin loading and runtime behavior configuration | | **engine** | `{ objectstack: string }` | optional | Platform compatibility requirements (legacy; superseded by `engines`) | | **engines** | `{ platform?: string; protocol?: string }` | optional | Plugin compatibility ranges (ADR-0025 §3.2; supersedes `engine`) | diff --git a/content/docs/references/kernel/metadata-plugin.mdx b/content/docs/references/kernel/metadata-plugin.mdx index 43c7ed896f..8882213df7 100644 --- a/content/docs/references/kernel/metadata-plugin.mdx +++ b/content/docs/references/kernel/metadata-plugin.mdx @@ -117,7 +117,7 @@ const result = MetadataBulkResultSchema.parse(data); | **type** | `'standard'` | ✅ | Plugin type | | **description** | `string` | optional | Plugin description | | **capabilities** | `{ crud?: boolean; query?: boolean; overlay?: boolean; watch?: boolean; … }` | ✅ | Plugin capabilities | -| **config** | `{ storage: object; customizationPolicies?: { metadataType: string; allowCustomization?: boolean; lockedFields?: string[]; customizableFields?: string[]; … }[]; mergeStrategy?: object; additionalTypes?: { label: string; description?: string; filePatterns: string[]; supportsOverlay?: boolean; … }[]; … }` | optional | Plugin configuration | +| **config** | `{ storage: object; customizationPolicies?: object[]; mergeStrategy?: object; additionalTypes?: object[]; … }` | optional | Plugin configuration | --- diff --git a/content/docs/references/kernel/package-registry.mdx b/content/docs/references/kernel/package-registry.mdx index ec093169db..19aabb879f 100644 --- a/content/docs/references/kernel/package-registry.mdx +++ b/content/docs/references/kernel/package-registry.mdx @@ -149,7 +149,7 @@ Install package response | :--- | :--- | :--- | :--- | | **package** | `{ manifest: object; status?: Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>; enabled?: boolean; installedAt?: string; … }` | ✅ | Installed package details | | **message** | `string` | optional | Installation status message | -| **dependencyResolution** | `{ dependencies: { packageId: string; requiredRange: string; resolvedVersion?: string; installedVersion?: string; … }[]; canProceed: boolean; requiredActions: { type: Enum<'install' \| 'upgrade' \| 'confirm_conflict'>; packageId: string; description: string }[]; installOrder: string[]; … }` | optional | Dependency resolution result from install analysis | +| **dependencyResolution** | `{ dependencies: object[]; canProceed: boolean; requiredActions: object[]; installOrder: string[]; … }` | optional | Dependency resolution result from install analysis | --- diff --git a/content/docs/references/kernel/plugin-capability.mdx b/content/docs/references/kernel/plugin-capability.mdx index 76f5477750..b7b24a6383 100644 --- a/content/docs/references/kernel/plugin-capability.mdx +++ b/content/docs/references/kernel/plugin-capability.mdx @@ -84,7 +84,7 @@ Level of protocol conformance | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **implements** | `{ protocol: object; conformance: Enum<'full' \| 'partial' \| 'experimental' \| 'deprecated'>; implementedFeatures?: string[]; features?: { name: string; enabled: boolean; description?: string; sinceVersion?: string; … }[]; … }[]` | optional | List of protocols this plugin conforms to | +| **implements** | `{ protocol: object; conformance: Enum<'full' \| 'partial' \| 'experimental' \| 'deprecated'>; implementedFeatures?: string[]; features?: object[]; … }[]` | optional | List of protocols this plugin conforms to | | **provides** | `{ id: string; name: string; description?: string; version: object; … }[]` | optional | Services/APIs this plugin offers to others | | **requires** | `{ pluginId: string; version: string; optional: boolean; reason?: string; … }[]` | optional | Required plugins and their capabilities | | **extensionPoints** | `{ id: string; name: string; description?: string; type: Enum<'action' \| 'hook' \| 'widget' \| 'provider' \| 'transformer' \| 'validator' \| 'decorator'>; … }[]` | optional | Points where other plugins can extend this plugin | @@ -118,7 +118,7 @@ Level of protocol conformance | **name** | `string` | ✅ | | | **description** | `string` | optional | | | **version** | `{ major: integer; minor: integer; patch: integer }` | ✅ | Semantic version of the protocol | -| **methods** | `{ name: string; description?: string; parameters?: { name: string; type: string; required: boolean; description?: string }[]; returnType?: string; … }[]` | ✅ | | +| **methods** | `{ name: string; description?: string; parameters?: object[]; returnType?: string; … }[]` | ✅ | | | **events** | `{ name: string; description?: string; payload?: string }[]` | optional | | | **stability** | `Enum<'stable' \| 'beta' \| 'alpha' \| 'experimental'>` | ✅ | | diff --git a/content/docs/references/kernel/plugin-registry.mdx b/content/docs/references/kernel/plugin-registry.mdx index 3a43b1b1c5..40d6dfa5e8 100644 --- a/content/docs/references/kernel/plugin-registry.mdx +++ b/content/docs/references/kernel/plugin-registry.mdx @@ -71,7 +71,7 @@ const result = PluginInstallConfigSchema.parse(data); | **category** | `Enum<'data' \| 'integration' \| 'ui' \| 'analytics' \| 'security' \| 'automation' \| 'ai' \| 'utility' \| 'driver' \| 'gateway' \| 'adapter'>` | optional | | | **tags** | `string[]` | optional | | | **vendor** | `{ id: string; name: string; website?: string; email?: string; … }` | ✅ | | -| **capabilities** | `{ implements?: { protocol: object; conformance: Enum<'full' \| 'partial' \| 'experimental' \| 'deprecated'>; implementedFeatures?: string[]; features?: { name: string; enabled: boolean; description?: string; sinceVersion?: string; … }[]; … }[]; provides?: { id: string; name: string; description?: string; version: object; … }[]; requires?: { pluginId: string; version: string; optional: boolean; reason?: string; … }[]; extensionPoints?: { id: string; name: string; description?: string; type: Enum<'action' \| 'hook' \| 'widget' \| 'provider' \| 'transformer' \| 'validator' \| 'decorator'>; … }[]; … }` | optional | | +| **capabilities** | `{ implements?: object[]; provides?: object[]; requires?: object[]; extensionPoints?: object[]; … }` | optional | | | **compatibility** | `{ minObjectStackVersion?: string; maxObjectStackVersion?: string; nodeVersion?: string; platforms?: Enum<'linux' \| 'darwin' \| 'win32' \| 'browser'>[] }` | optional | | | **links** | `{ homepage?: string; repository?: string; documentation?: string; bugs?: string; … }` | optional | | | **media** | `{ icon?: string; logo?: string; screenshots?: string[]; video?: string }` | optional | | diff --git a/content/docs/references/kernel/plugin-security-advanced.mdx b/content/docs/references/kernel/plugin-security-advanced.mdx index 9864a98b63..620ca607ef 100644 --- a/content/docs/references/kernel/plugin-security-advanced.mdx +++ b/content/docs/references/kernel/plugin-security-advanced.mdx @@ -61,7 +61,7 @@ const result = KernelSecurityPolicySchema.parse(data); | **vulnerabilities** | `{ cve?: string; id: string; severity: Enum<'critical' \| 'high' \| 'medium' \| 'low' \| 'info'>; category?: string; … }[]` | optional | | | **codeIssues** | `{ severity: Enum<'error' \| 'warning' \| 'info'>; type: string; file: string; line?: integer; … }[]` | optional | | | **dependencyVulnerabilities** | `{ package: string; version: string; vulnerability: object }[]` | optional | | -| **licenseCompliance** | `{ status: Enum<'compliant' \| 'non-compliant' \| 'unknown'>; issues?: { package: string; license: string; reason: string }[] }` | optional | | +| **licenseCompliance** | `{ status: Enum<'compliant' \| 'non-compliant' \| 'unknown'>; issues?: object[] }` | optional | | | **summary** | `{ totalVulnerabilities: integer; criticalCount: integer; highCount: integer; mediumCount: integer; … }` | ✅ | | @@ -140,7 +140,7 @@ Scope of permission application | **resource** | `Enum<'data.object' \| 'data.record' \| 'data.field' \| 'ui.view' \| 'ui.dashboard' \| 'ui.report' \| 'system.config' \| 'system.plugin' \| 'system.api' \| 'system.service' \| … +6 more>` | ✅ | Type of resource being accessed | | **actions** | `Enum<'create' \| 'read' \| 'update' \| 'delete' \| 'execute' \| 'manage' \| 'configure' \| 'share' \| 'export' \| 'import' \| 'admin'>[]` | ✅ | | | **scope** | `Enum<'global' \| 'tenant' \| 'user' \| 'resource' \| 'plugin'>` | optional | Scope of permission application | -| **filter** | `{ resourceIds?: string[]; condition?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; fields?: string[] }` | optional | | +| **filter** | `{ resourceIds?: string[]; condition?: string \| object; fields?: string[] }` | optional | | | **description** | `string` | ✅ | | | **required** | `boolean` | optional | | | **justification** | `string` | optional | Why this permission is needed | @@ -188,10 +188,10 @@ Scope of permission application | :--- | :--- | :--- | :--- | | **pluginId** | `string` | ✅ | | | **trustLevel** | `Enum<'verified' \| 'trusted' \| 'community' \| 'untrusted' \| 'blocked'>` | ✅ | Trust level of the plugin | -| **permissions** | `{ permissions: { id: string; resource: Enum<'data.object' \| 'data.record' \| 'data.field' \| 'ui.view' \| 'ui.dashboard' \| … +11 more>; actions: Enum<'create' \| 'read' \| 'update' \| 'delete' \| 'execute' \| 'manage' \| 'configure' \| … +4 more>[]; scope?: Enum<'global' \| 'tenant' \| 'user' \| 'resource' \| 'plugin'>; … }[]; groups?: { name: string; description: string; permissions: string[] }[]; defaultGrant?: Enum<'prompt' \| 'allow' \| 'deny' \| 'inherit'> }` | ✅ | | +| **permissions** | `{ permissions: object[]; groups?: object[]; defaultGrant?: Enum<'prompt' \| 'allow' \| 'deny' \| 'inherit'> }` | ✅ | | | **sandbox** | `{ enabled?: boolean; level?: Enum<'none' \| 'minimal' \| 'standard' \| 'strict' \| 'paranoid'>; runtime?: object; filesystem?: object; … }` | ✅ | | | **policy** | `{ csp?: object; cors?: object; rateLimit?: object; authentication?: object; … }` | optional | | -| **scanResults** | `{ timestamp: string; scanner: object; status: Enum<'passed' \| 'failed' \| 'warning'>; vulnerabilities?: { cve?: string; id: string; severity: Enum<'critical' \| 'high' \| 'medium' \| 'low' \| 'info'>; category?: string; … }[]; … }[]` | optional | | +| **scanResults** | `{ timestamp: string; scanner: object; status: Enum<'passed' \| 'failed' \| 'warning'>; vulnerabilities?: object[]; … }[]` | optional | | | **vulnerabilities** | `{ cve?: string; id: string; severity: Enum<'critical' \| 'high' \| 'medium' \| 'low' \| 'info'>; category?: string; … }[]` | optional | | | **codeSigning** | `{ signed: boolean; signature?: string; certificate?: string; algorithm?: string; … }` | optional | | | **certifications** | `{ name: string; issuer: string; issuedDate: string; expiryDate?: string; … }[]` | optional | | diff --git a/content/docs/references/kernel/plugin-security.mdx b/content/docs/references/kernel/plugin-security.mdx index 273d787132..94cc1a9c2a 100644 --- a/content/docs/references/kernel/plugin-security.mdx +++ b/content/docs/references/kernel/plugin-security.mdx @@ -43,7 +43,7 @@ Complete dependency graph for a package and its transitive dependencies | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **root** | `{ id: string; version: string }` | ✅ | Root package of the dependency graph | -| **nodes** | `{ id: string; version: string; dependencies: { name: string; versionConstraint: string; type: Enum<'required' \| 'optional' \| 'peer' \| 'dev'>; resolvedVersion?: string }[]; depth: integer; … }[]` | ✅ | All resolved package nodes in the dependency graph | +| **nodes** | `{ id: string; version: string; dependencies: object[]; depth: integer; … }[]` | ✅ | All resolved package nodes in the dependency graph | | **edges** | `{ from: string; to: string; constraint: string }[]` | ✅ | Directed edges representing dependency relationships | | **stats** | `{ totalDependencies: integer; directDependencies: integer; maxDepth: integer }` | ✅ | Summary statistics for the dependency graph | @@ -93,8 +93,8 @@ Result of a dependency resolution process | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **status** | `Enum<'success' \| 'conflict' \| 'error'>` | ✅ | Overall status of the dependency resolution | -| **graph** | `{ root: object; nodes: { id: string; version: string; dependencies: { name: string; versionConstraint: string; type: Enum<'required' \| 'optional' \| 'peer' \| 'dev'>; resolvedVersion?: string }[]; depth: integer; … }[]; edges: { from: string; to: string; constraint: string }[]; stats: object }` | optional | Resolved dependency graph if resolution succeeded | -| **conflicts** | `{ package: string; conflicts: { version: string; requestedBy: string[]; constraint: string }[]; resolution?: object; severity: Enum<'error' \| 'warning' \| 'info'> }[]` | ✅ | List of dependency conflicts detected during resolution | +| **graph** | `{ root: object; nodes: object[]; edges: object[]; stats: object }` | optional | Resolved dependency graph if resolution succeeded | +| **conflicts** | `{ package: string; conflicts: object[]; resolution?: object; severity: Enum<'error' \| 'warning' \| 'info'> }[]` | ✅ | List of dependency conflicts detected during resolution | | **errors** | `{ package: string; error: string }[]` | ✅ | Errors encountered during dependency resolution | | **installOrder** | `string[]` | ✅ | Topologically sorted list of package IDs for installation | | **resolvedIn** | `integer` | optional | Time taken to resolve dependencies in milliseconds | @@ -227,7 +227,7 @@ Result of a security scan performed on a plugin | **vulnerabilities** | `{ cve?: string; id: string; title: string; description: string; … }[]` | ✅ | List of vulnerabilities discovered during the scan | | **summary** | `{ critical: integer; high: integer; medium: integer; low: integer; … }` | ✅ | Summary counts of vulnerabilities by severity | | **licenseIssues** | `{ package: string; license: string; reason: string; severity: Enum<'error' \| 'warning' \| 'info'> }[]` | ✅ | License compliance issues found during the scan | -| **codeQuality** | `{ score?: number; issues: { type: Enum<'security' \| 'quality' \| 'style'>; severity: Enum<'error' \| 'warning' \| 'info'>; message: string; file?: string; … }[] }` | optional | Code quality analysis results | +| **codeQuality** | `{ score?: number; issues: object[] }` | optional | Code quality analysis results | | **nextScanAt** | `string` | optional | ISO 8601 timestamp for the next scheduled scan | diff --git a/content/docs/references/kernel/plugin-versioning.mdx b/content/docs/references/kernel/plugin-versioning.mdx index 0f4d31be83..1ce70ca14d 100644 --- a/content/docs/references/kernel/plugin-versioning.mdx +++ b/content/docs/references/kernel/plugin-versioning.mdx @@ -124,7 +124,7 @@ Compatibility level between versions | **enabled** | `boolean` | optional | | | **maxConcurrentVersions** | `integer` | optional | How many versions can run at the same time | | **selectionStrategy** | `Enum<'latest' \| 'stable' \| 'compatible' \| 'pinned' \| 'canary' \| 'custom'>` | optional | | -| **routing** | `{ condition: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; version: string; priority?: integer }[]` | optional | | +| **routing** | `{ condition: string \| object; version: string; priority?: integer }[]` | optional | | | **rollout** | `{ enabled?: boolean; strategy: Enum<'percentage' \| 'blue-green' \| 'canary'>; percentage?: number; duration?: integer }` | optional | | @@ -138,7 +138,7 @@ Compatibility level between versions | :--- | :--- | :--- | :--- | | **pluginId** | `string` | ✅ | | | **currentVersion** | `string` | ✅ | | -| **compatibilityMatrix** | `{ from: string; to: string; compatibility: Enum<'fully-compatible' \| 'backward-compatible' \| 'deprecated-compatible' \| … +2 more>; breakingChanges?: { introducedIn: string; type: Enum<'api-removed' \| 'api-renamed' \| 'api-signature-changed' \| 'behavior-changed' \| … +3 more>; description: string; migrationGuide?: string; … }[]; … }[]` | ✅ | | +| **compatibilityMatrix** | `{ from: string; to: string; compatibility: Enum<'fully-compatible' \| 'backward-compatible' \| 'deprecated-compatible' \| … +2 more>; breakingChanges?: object[]; … }[]` | ✅ | | | **supportedVersions** | `{ version: string; supported: boolean; endOfLife?: string; securitySupport: boolean }[]` | ✅ | | | **minimumCompatibleVersion** | `string` | optional | Oldest version that can be directly upgraded | @@ -153,7 +153,7 @@ Compatibility level between versions | :--- | :--- | :--- | :--- | | **success** | `boolean` | ✅ | | | **resolved** | `{ pluginId: string; version: string; resolvedVersion: string }[]` | optional | | -| **conflicts** | `{ type: Enum<'version-mismatch' \| 'missing-dependency' \| 'circular-dependency' \| … +2 more>; plugins: { pluginId: string; version: string; requirement?: string }[]; description: string; resolutions?: { strategy: Enum<'upgrade' \| 'downgrade' \| 'replace' \| 'disable' \| 'manual'>; description: string; automaticResolution: boolean; riskLevel: Enum<'low' \| 'medium' \| 'high'> }[]; … }[]` | optional | | +| **conflicts** | `{ type: Enum<'version-mismatch' \| 'missing-dependency' \| 'circular-dependency' \| … +2 more>; plugins: object[]; description: string; resolutions?: object[]; … }[]` | optional | | | **warnings** | `string[]` | optional | | | **installationOrder** | `string[]` | optional | Plugin IDs in order they should be installed | | **dependencyGraph** | `Record` | optional | Map of plugin ID to its dependencies | @@ -174,7 +174,7 @@ Compatibility level between versions | **releaseNotes** | `string` | optional | | | **breakingChanges** | `{ introducedIn: string; type: Enum<'api-removed' \| 'api-renamed' \| 'api-signature-changed' \| 'behavior-changed' \| … +3 more>; description: string; migrationGuide?: string; … }[]` | optional | | | **deprecations** | `{ feature: string; deprecatedIn: string; removeIn?: string; reason: string; … }[]` | optional | | -| **compatibilityMatrix** | `{ from: string; to: string; compatibility: Enum<'fully-compatible' \| 'backward-compatible' \| 'deprecated-compatible' \| … +2 more>; breakingChanges?: { introducedIn: string; type: Enum<'api-removed' \| 'api-renamed' \| 'api-signature-changed' \| 'behavior-changed' \| … +3 more>; description: string; migrationGuide?: string; … }[]; … }[]` | optional | | +| **compatibilityMatrix** | `{ from: string; to: string; compatibility: Enum<'fully-compatible' \| 'backward-compatible' \| 'deprecated-compatible' \| … +2 more>; breakingChanges?: object[]; … }[]` | optional | | | **securityFixes** | `{ cve?: string; severity: Enum<'critical' \| 'high' \| 'medium' \| 'low'>; description: string; fixedIn: string }[]` | optional | | | **statistics** | `{ downloads?: integer; installations?: integer; ratings?: number }` | optional | | | **support** | `{ status: Enum<'active' \| 'maintenance' \| 'deprecated' \| 'eol'>; endOfLife?: string; securitySupport: boolean }` | ✅ | | diff --git a/content/docs/references/qa/testing.mdx b/content/docs/references/qa/testing.mdx index 08f31aca25..a5606a5e62 100644 --- a/content/docs/references/qa/testing.mdx +++ b/content/docs/references/qa/testing.mdx @@ -106,9 +106,9 @@ A complete test scenario with setup, execution steps, and teardown | **name** | `string` | ✅ | Scenario name for test reports | | **description** | `string` | optional | Detailed description of the test scenario | | **tags** | `string[]` | optional | Tags for filtering and categorization (e.g. "critical", "regression", "crm") | -| **setup** | `{ name: string; description?: string; action: object; assertions?: { field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'is_null' \| 'not_null' \| … +5 more>; expectedValue: any }[]; … }[]` | optional | Steps to run before main test (preconditions) | -| **steps** | `{ name: string; description?: string; action: object; assertions?: { field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'is_null' \| 'not_null' \| … +5 more>; expectedValue: any }[]; … }[]` | ✅ | Main test sequence to execute | -| **teardown** | `{ name: string; description?: string; action: object; assertions?: { field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'is_null' \| 'not_null' \| … +5 more>; expectedValue: any }[]; … }[]` | optional | Steps to cleanup after test execution | +| **setup** | `{ name: string; description?: string; action: object; assertions?: object[]; … }[]` | optional | Steps to run before main test (preconditions) | +| **steps** | `{ name: string; description?: string; action: object; assertions?: object[]; … }[]` | ✅ | Main test sequence to execute | +| **teardown** | `{ name: string; description?: string; action: object; assertions?: object[]; … }[]` | optional | Steps to cleanup after test execution | | **requires** | `{ params?: string[]; plugins?: string[] }` | optional | Environment requirements for this scenario | diff --git a/content/docs/references/security/explain.mdx b/content/docs/references/security/explain.mdx index cf20bd3926..9d1b548d2e 100644 --- a/content/docs/references/security/explain.mdx +++ b/content/docs/references/security/explain.mdx @@ -123,7 +123,7 @@ ADR-0095 D2 posture rung — PLATFORM_ADMIN crosses the tenant wall where object | **verdict** | `Enum<'grants' \| 'denies' \| 'narrows' \| 'widens' \| 'neutral' \| 'not_applicable'>` | ✅ | | | **detail** | `string` | ✅ | | | **contributors** | `{ kind: Enum<'permission_set' \| 'position' \| 'system'>; name: string; via?: string; state?: Enum<'active' \| 'expired'> }[]` | ✅ | | -| **record** | `{ outcome: Enum<'admitted' \| 'excluded' \| 'not_evaluated'>; rowFilter?: any; matchesRecord?: boolean; rules: { kind: Enum<'tenant_filter' \| 'owd_baseline' \| 'ownership' \| 'record_share' \| 'sharing_rule' \| … +3 more>; name: string; grants?: Enum<'read' \| 'edit' \| 'full'>; via?: string; … }[]; … }` | optional | Row-level determination for the specific record under explanation; set only for record-grained requests. | +| **record** | `{ outcome: Enum<'admitted' \| 'excluded' \| 'not_evaluated'>; rowFilter?: any; matchesRecord?: boolean; rules: object[]; … }` | optional | Row-level determination for the specific record under explanation; set only for record-grained requests. | --- diff --git a/content/docs/references/studio/object-designer.mdx b/content/docs/references/studio/object-designer.mdx index e99b9c8b05..48e162fcdf 100644 --- a/content/docs/references/studio/object-designer.mdx +++ b/content/docs/references/studio/object-designer.mdx @@ -190,10 +190,10 @@ ER diagram layout algorithm | :--- | :--- | :--- | :--- | | **defaultView** | `Enum<'field-editor' \| 'relationship-mapper' \| 'er-diagram' \| 'object-manager'>` | ✅ | Default view | | **fieldEditor** | `{ inlineEditing: boolean; dragReorder: boolean; showFieldGroups: boolean; showPropertyPanel: boolean; … }` | ✅ | Field editor configuration | -| **relationshipMapper** | `{ visualCreation: boolean; showReverseRelationships: boolean; showCascadeWarnings: boolean; displayConfig: { type: Enum<'lookup' \| 'master_detail' \| 'tree'>; lineStyle: Enum<'solid' \| 'dashed' \| 'dotted'>; color: string; highlightColor: string; … }[] }` | ✅ | Relationship mapper configuration | +| **relationshipMapper** | `{ visualCreation: boolean; showReverseRelationships: boolean; showCascadeWarnings: boolean; displayConfig: object[] }` | ✅ | Relationship mapper configuration | | **erDiagram** | `{ enabled: boolean; layout: Enum<'force' \| 'hierarchy' \| 'grid' \| 'circular'>; nodeDisplay: object; showMinimap: boolean; … }` | ✅ | ER diagram configuration | | **objectManager** | `{ defaultDisplayMode: Enum<'table' \| 'cards' \| 'tree'>; defaultSortField: Enum<'name' \| 'label' \| 'fieldCount' \| 'updatedAt'>; defaultSortDirection: Enum<'asc' \| 'desc'>; defaultFilter: object; … }` | ✅ | Object manager configuration | -| **objectPreview** | `{ tabs: { key: string; label: string; icon?: string; enabled: boolean; … }[]; defaultTab: string; showHeader: boolean; showBreadcrumbs: boolean }` | ✅ | Object preview configuration | +| **objectPreview** | `{ tabs: object[]; defaultTab: string; showHeader: boolean; showBreadcrumbs: boolean }` | ✅ | Object preview configuration | --- diff --git a/content/docs/references/studio/plugin.mdx b/content/docs/references/studio/plugin.mdx index 2e05ce00bc..a56e85d4f9 100644 --- a/content/docs/references/studio/plugin.mdx +++ b/content/docs/references/studio/plugin.mdx @@ -208,7 +208,7 @@ const result = ActionContributionSchema.parse(data); | **version** | `string` | ✅ | Plugin version | | **description** | `string` | optional | Plugin description | | **author** | `string` | optional | Author | -| **contributes** | `{ metadataViewers: { id: string; metadataTypes: string[]; label: string; priority: number; … }[]; sidebarGroups: { key: string; label: string; icon?: string; metadataTypes: string[]; … }[]; actions: { id: string; label: string; icon?: string; location: Enum<'toolbar' \| 'contextMenu' \| 'commandPalette'>; … }[]; metadataIcons: { metadataType: string; label: string; icon: string }[]; … }` | ✅ | | +| **contributes** | `{ metadataViewers: object[]; sidebarGroups: object[]; actions: object[]; metadataIcons: object[]; … }` | ✅ | | --- diff --git a/content/docs/references/system/book.mdx b/content/docs/references/system/book.mdx index 93b96c83e1..f8f0bb8e1c 100644 --- a/content/docs/references/system/book.mdx +++ b/content/docs/references/system/book.mdx @@ -52,7 +52,7 @@ const result = BookSchema.parse(data); | **icon** | `string` | optional | | | **order** | `number` | optional | Orders books within the portal | | **audience** | `'org' \| 'public' \| { permissionSet: string }` | optional | Access audience; defaults to 'org' (inherits package grant) | -| **groups** | `{ key: string; label: string; order?: number; include?: string \| { tag: string }; … }[]` | ✅ | The spine: ordered sections. Two levels total. | +| **groups** | `{ key: string; label: string; order?: number; include?: string \| object; … }[]` | ✅ | The spine: ordered sections. Two levels total. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | | **_lockReason** | `string` | optional | Human-readable reason shown when a write is refused by _lock. | | **_lockSource** | `Enum<'artifact' \| 'package' \| 'env-forced'>` | optional | Layer that set _lock (artifact \| package \| env-forced). | diff --git a/content/docs/references/system/cache.mdx b/content/docs/references/system/cache.mdx index 5639ae575f..813c09590a 100644 --- a/content/docs/references/system/cache.mdx +++ b/content/docs/references/system/cache.mdx @@ -172,7 +172,7 @@ Distributed cache configuration with consistency and avalanche prevention | **encryption** | `boolean` | optional | Enable encryption for cached data | | **consistency** | `Enum<'write_through' \| 'write_behind' \| 'write_around' \| 'refresh_ahead'>` | optional | Distributed cache consistency strategy | | **avalanchePrevention** | `{ jitterTtl?: object; circuitBreaker?: object; lockout?: object }` | optional | Cache avalanche and stampede prevention | -| **warmup** | `{ enabled?: boolean; strategy?: Enum<'eager' \| 'lazy' \| 'scheduled'>; schedule?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; patterns?: string[]; … }` | optional | Cache warmup strategy | +| **warmup** | `{ enabled?: boolean; strategy?: Enum<'eager' \| 'lazy' \| 'scheduled'>; schedule?: string \| object; patterns?: string[]; … }` | optional | Cache warmup strategy | --- diff --git a/content/docs/references/system/change-management.mdx b/content/docs/references/system/change-management.mdx index bb764ce3e3..077932c2b6 100644 --- a/content/docs/references/system/change-management.mdx +++ b/content/docs/references/system/change-management.mdx @@ -67,11 +67,11 @@ const result = ChangeImpactSchema.parse(data); | **requestedBy** | `string` | ✅ | Requester user ID | | **requestedAt** | `number` | ✅ | Request timestamp | | **impact** | `{ level: Enum<'low' \| 'medium' \| 'high' \| 'critical'>; affectedSystems: string[]; affectedUsers?: number; downtime?: object }` | ✅ | Impact assessment | -| **implementation** | `{ description: string; steps: { order: number; description: string; estimatedMinutes: number }[]; testing?: string }` | ✅ | Implementation plan | -| **rollbackPlan** | `{ description: string; steps: { order: number; description: string; estimatedMinutes: number }[]; testProcedure?: string }` | ✅ | Rollback plan | +| **implementation** | `{ description: string; steps: object[]; testing?: string }` | ✅ | Implementation plan | +| **rollbackPlan** | `{ description: string; steps: object[]; testProcedure?: string }` | ✅ | Rollback plan | | **schedule** | `{ plannedStart: number; plannedEnd: number; actualStart?: number; actualEnd?: number }` | optional | Schedule | | **securityImpact** | `{ assessed: boolean; riskLevel?: Enum<'none' \| 'low' \| 'medium' \| 'high' \| 'critical'>; affectedDataClassifications?: Enum<'pii' \| 'phi' \| 'pci' \| 'financial' \| 'confidential' \| 'internal' \| 'public'>[]; requiresSecurityApproval: boolean; … }` | optional | Security impact assessment per ISO 27001:2022 A.8.32 | -| **approval** | `{ required: boolean; approvers: { userId: string; approvedAt?: number; comments?: string }[] }` | optional | Approval workflow | +| **approval** | `{ required: boolean; approvers: object[] }` | optional | Approval workflow | | **attachments** | `{ name: string; url: string }[]` | optional | Attachments | | **metadata** | `Record` | optional | Custom metadata key-value pairs for extensibility | diff --git a/content/docs/references/system/collaboration.mdx b/content/docs/references/system/collaboration.mdx index 494bf360be..7ba7593e14 100644 --- a/content/docs/references/system/collaboration.mdx +++ b/content/docs/references/system/collaboration.mdx @@ -102,7 +102,7 @@ const result = AwarenessEventSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **state** | `{ type: 'lww-register'; value: any; timestamp: string; replicaId: string; … } \| { type: 'g-counter'; counts: Record } \| { type: 'pn-counter'; positive: Record; negative: Record } \| { type: 'or-set'; elements: { value: any; timestamp: string; replicaId: string; uid: string; … }[] } \| … +1 more` | ✅ | Merged CRDT state | +| **state** | `{ type: 'lww-register'; value: any; timestamp: string; replicaId: string; … } \| { type: 'g-counter'; counts: Record } \| { type: 'pn-counter'; positive: Record; negative: Record } \| { type: 'or-set'; elements: object[] } \| … +1 more` | ✅ | Merged CRDT state | | **conflicts** | `{ type: string; description: string; resolved: boolean }[]` | optional | Conflicts encountered during merge | diff --git a/content/docs/references/system/disaster-recovery.mdx b/content/docs/references/system/disaster-recovery.mdx index 1144635220..2c7e42dbed 100644 --- a/content/docs/references/system/disaster-recovery.mdx +++ b/content/docs/references/system/disaster-recovery.mdx @@ -97,10 +97,10 @@ Complete disaster recovery plan configuration | **enabled** | `boolean` | optional | Enable disaster recovery plan | | **rpo** | `{ value: number; unit?: Enum<'seconds' \| 'minutes' \| 'hours'> }` | ✅ | Recovery Point Objective | | **rto** | `{ value: number; unit?: Enum<'seconds' \| 'minutes' \| 'hours'> }` | ✅ | Recovery Time Objective | -| **backup** | `{ strategy?: Enum<'full' \| 'incremental' \| 'differential'>; schedule?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; retention: object; destination: object; … }` | ✅ | Backup configuration | +| **backup** | `{ strategy?: Enum<'full' \| 'incremental' \| 'differential'>; schedule?: string \| object; retention: object; destination: object; … }` | ✅ | Backup configuration | | **failover** | `{ mode?: Enum<'active_passive' \| 'active_active' \| 'pilot_light' \| 'warm_standby'>; autoFailover?: boolean; healthCheckInterval?: number; failureThreshold?: number; … }` | optional | Multi-region failover configuration | | **replication** | `{ mode?: Enum<'synchronous' \| 'asynchronous' \| 'semi_synchronous'>; maxLagSeconds?: number; includeObjects?: string[]; excludeObjects?: string[] }` | optional | Data replication settings | -| **testing** | `{ enabled?: boolean; schedule?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; notificationChannel?: string }` | optional | Automated disaster recovery testing | +| **testing** | `{ enabled?: boolean; schedule?: string \| object; notificationChannel?: string }` | optional | Automated disaster recovery testing | | **runbookUrl** | `string` | optional | URL to disaster recovery runbook/playbook | | **contacts** | `{ name: string; role: string; email?: string; phone?: string }[]` | optional | Emergency contact list for DR incidents | diff --git a/content/docs/references/system/incident-response.mdx b/content/docs/references/system/incident-response.mdx index d9ed052ee1..9c6499c074 100644 --- a/content/docs/references/system/incident-response.mdx +++ b/content/docs/references/system/incident-response.mdx @@ -154,7 +154,7 @@ Organization-level incident response policy per ISO 27001:2022 | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | ✅ | Enable incident response management | -| **notificationMatrix** | `{ rules: { severity: Enum<'critical' \| 'high' \| 'medium' \| 'low'>; channels: Enum<'email' \| 'sms' \| 'slack' \| 'pagerduty' \| 'webhook'>[]; recipients: string[]; withinMinutes: number; … }[]; escalationTimeoutMinutes: number; escalationChain: string[] }` | ✅ | Notification and escalation matrix | +| **notificationMatrix** | `{ rules: object[]; escalationTimeoutMinutes: number; escalationChain: string[] }` | ✅ | Notification and escalation matrix | | **defaultResponseTeam** | `string` | ✅ | Default incident response team or role | | **triageDeadlineHours** | `number` | ✅ | Maximum hours to begin triage after detection | | **requirePostIncidentReview** | `boolean` | ✅ | Require post-incident review for all incidents | diff --git a/content/docs/references/system/job.mdx b/content/docs/references/system/job.mdx index 99afb5395d..0986570879 100644 --- a/content/docs/references/system/job.mdx +++ b/content/docs/references/system/job.mdx @@ -58,7 +58,7 @@ const result = CronScheduleSchema.parse(data); | **name** | `string` | ✅ | Job name (snake_case) | | **label** | `string` | optional | Human-readable label | | **description** | `string` | optional | Job description / purpose | -| **schedule** | `{ type: 'cron'; expression: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; timezone?: string } \| { type: 'interval'; intervalMs: integer } \| { type: 'once'; at: string }` | ✅ | Job schedule configuration | +| **schedule** | `{ type: 'cron'; expression: string \| object; timezone?: string } \| { type: 'interval'; intervalMs: integer } \| { type: 'once'; at: string }` | ✅ | Job schedule configuration | | **handler** | `string` | ✅ | Handler function name (must match a key in `defineStack({ functions })`) | | **retryPolicy** | `{ maxRetries?: integer; backoffMs?: integer; backoffMultiplier?: number; maxRetryDelayMs?: integer; … }` | optional | Retry policy: failed runs (including timeouts) are retried with exponential backoff (delay = min(backoffMs * backoffMultiplier^(retry-1), maxRetryDelayMs), optionally jittered) up to maxRetries retries after the initial attempt (#3494). Omit the block for a single attempt; declaring it without `maxRetries` also means no retry since 17.0.0 (#4661) — state a count to opt in. | | **timeout** | `integer` | optional | Per-attempt time limit in milliseconds; an over-limit run is recorded with execution status "timeout" (#3494). The in-flight handler is abandoned, not forcibly cancelled. Omit for no time limit. | diff --git a/content/docs/references/system/metrics.mdx b/content/docs/references/system/metrics.mdx index ce0e0337e3..c1975e9bde 100644 --- a/content/docs/references/system/metrics.mdx +++ b/content/docs/references/system/metrics.mdx @@ -98,8 +98,8 @@ Metric data point | **timestamp** | `string` | ✅ | Observation timestamp | | **value** | `number` | optional | Metric value | | **labels** | `Record` | optional | Metric labels | -| **histogram** | `{ count: integer; sum: number; buckets: { upperBound: number; count: integer }[] }` | optional | | -| **summary** | `{ count: integer; sum: number; quantiles: { quantile: number; value: number }[] }` | optional | | +| **histogram** | `{ count: integer; sum: number; buckets: object[] }` | optional | | +| **summary** | `{ count: integer; sum: number; quantiles: object[] }` | optional | | --- @@ -231,7 +231,7 @@ Metrics configuration | **slos** | `{ name: string; label: string; description?: string; sli: string; … }[]` | optional | | | **exports** | `{ type: Enum<'prometheus' \| 'openmetrics' \| 'graphite' \| 'statsd' \| 'influxdb' \| 'datadog' \| … +5 more>; endpoint?: string; interval?: integer; batch?: object; … }[]` | optional | | | **collectionInterval** | `integer` | optional | | -| **retention** | `{ period?: integer; downsampling?: { afterSeconds: integer; resolution: integer }[] }` | optional | | +| **retention** | `{ period?: integer; downsampling?: object[] }` | optional | | | **cardinalityLimits** | `{ maxLabelCombinations?: integer; onLimitExceeded?: Enum<'drop' \| 'sample' \| 'alert'> }` | optional | | @@ -271,7 +271,7 @@ Service Level Objective | **sli** | `string` | ✅ | SLI name | | **target** | `number` | ✅ | Target percentage | | **period** | `{ type: Enum<'rolling' \| 'calendar'>; duration?: integer; calendar?: Enum<'daily' \| 'weekly' \| 'monthly' \| 'quarterly' \| 'yearly'> }` | ✅ | Time period | -| **errorBudget** | `{ enabled: boolean; alertThreshold: number; burnRateWindows?: { window: integer; threshold: number }[] }` | optional | | +| **errorBudget** | `{ enabled: boolean; alertThreshold: number; burnRateWindows?: object[] }` | optional | | | **alerts** | `{ name: string; severity: Enum<'info' \| 'warning' \| 'critical'>; condition: object }[]` | ✅ | | | **enabled** | `boolean` | ✅ | | diff --git a/content/docs/references/system/object-storage.mdx b/content/docs/references/system/object-storage.mdx index 09598c58f5..4ee5db46cd 100644 --- a/content/docs/references/system/object-storage.mdx +++ b/content/docs/references/system/object-storage.mdx @@ -69,7 +69,7 @@ const result = AccessControlConfigSchema.parse(data); | **versioning** | `boolean` | ✅ | Enable object versioning | | **encryption** | `{ enabled: boolean; algorithm: Enum<'AES256' \| 'aws:kms' \| 'azure:kms' \| 'gcp:kms'>; kmsKeyId?: string }` | optional | Server-side encryption configuration | | **accessControl** | `{ acl: Enum<'private' \| 'public_read' \| 'public_read_write' \| 'authenticated_read' \| … +2 more>; allowedOrigins?: string[]; allowedMethods?: Enum<'GET' \| 'PUT' \| 'POST' \| 'DELETE' \| 'HEAD'>[]; allowedHeaders?: string[]; … }` | optional | Access control configuration | -| **lifecyclePolicy** | `{ enabled: boolean; rules: { id: string; enabled: boolean; action: Enum<'transition' \| 'delete' \| 'abort'>; prefix?: string; … }[] }` | optional | Lifecycle policy configuration | +| **lifecyclePolicy** | `{ enabled: boolean; rules: object[] }` | optional | Lifecycle policy configuration | | **multipartConfig** | `{ enabled: boolean; partSize: number; maxParts: number; threshold: number; … }` | optional | Multipart upload configuration | | **tags** | `Record` | optional | Bucket tags for organization | | **description** | `string` | optional | Bucket description | diff --git a/content/docs/references/system/search-engine.mdx b/content/docs/references/system/search-engine.mdx index feaba3219d..c6731fb110 100644 --- a/content/docs/references/system/search-engine.mdx +++ b/content/docs/references/system/search-engine.mdx @@ -64,7 +64,7 @@ Top-level full-text search engine configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **provider** | `Enum<'elasticsearch' \| 'algolia' \| 'meilisearch' \| 'typesense' \| 'opensearch'>` | ✅ | Search engine backend provider | -| **indexes** | `{ indexName: string; objectName: string; fields: { name: string; type: Enum<'text' \| 'keyword' \| 'number' \| 'date' \| 'boolean' \| 'geo'>; analyzer?: string; searchable: boolean; … }[]; replicas: number; … }[]` | ✅ | Search index definitions | +| **indexes** | `{ indexName: string; objectName: string; fields: object[]; replicas: number; … }[]` | ✅ | Search index definitions | | **analyzers** | `Record; language?: string; stopwords?: string[]; customFilters?: string[] }>` | optional | Named text analyzer configurations | | **facets** | `{ field: string; maxValues: number; sort: Enum<'count' \| 'alpha'> }[]` | optional | Faceted search configurations | | **typoTolerance** | `boolean` | ✅ | Enable typo-tolerant search | diff --git a/content/docs/references/system/tracing.mdx b/content/docs/references/system/tracing.mdx index 06ea56e116..d2523cbc00 100644 --- a/content/docs/references/system/tracing.mdx +++ b/content/docs/references/system/tracing.mdx @@ -297,7 +297,7 @@ Trace sampling configuration | **ratio** | `number` | optional | Sample ratio (0-1) | | **rateLimit** | `number` | optional | Traces per second | | **parentBased** | `{ whenParentSampled?: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| … +3 more>; whenParentNotSampled?: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| … +3 more>; root?: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| … +3 more>; rootRatio?: number }` | optional | | -| **composite** | `{ strategy: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| … +3 more>; ratio?: number; condition?: Record \| string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object } }[]` | optional | | +| **composite** | `{ strategy: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| … +3 more>; ratio?: number; condition?: Record \| string \| object }[]` | optional | | | **rules** | `{ name: string; match?: object; decision: Enum<'drop' \| 'record_only' \| 'record_and_sample'>; rate?: number }[]` | optional | | | **customSamplerId** | `string` | optional | Custom sampler identifier | diff --git a/content/docs/references/system/translation.mdx b/content/docs/references/system/translation.mdx index 41115a4ab9..704b8f2a15 100644 --- a/content/docs/references/system/translation.mdx +++ b/content/docs/references/system/translation.mdx @@ -85,7 +85,7 @@ Translation data for a single object | **description** | `string` | optional | Translated object description | | **fields** | `Record }>` | optional | Field-level translations | | **_views** | `Record` | optional | View translations keyed by view name | -| **_actions** | `Record }>; … }>` | optional | Action translations keyed by action name | +| **_actions** | `Record; … }>` | optional | Action translations keyed by action name | | **_sections** | `Record` | optional | Section translations keyed by section name | @@ -139,14 +139,14 @@ Translation data for objects, apps, and UI messages | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **objects** | `Record }>; … }>` | optional | Object translations keyed by object name | -| **apps** | `Record }>` | optional | App translations keyed by app name | +| **objects** | `Record; … }>` | optional | Object translations keyed by object name | +| **apps** | `Record }>` | optional | App translations keyed by app name | | **messages** | `Record` | optional | UI message translations keyed by message ID | -| **globalActions** | `Record }>; … }>` | optional | Global action translations keyed by action name | -| **dashboards** | `Record; widgets?: Record }>` | optional | Dashboard translations keyed by dashboard name | +| **globalActions** | `Record; … }>` | optional | Global action translations keyed by action name | +| **dashboards** | `Record; widgets?: Record }>` | optional | Dashboard translations keyed by dashboard name | | **pages** | `Record` | optional | Page translations keyed by page name | -| **settings** | `Record; keys?: Record }>; … }>` | optional | Settings manifest translations keyed by namespace | -| **metadataForms** | `Record; fields?: Record }>` | optional | Translations for metadata-type configuration forms keyed by metadata type | +| **settings** | `Record; keys?: Record; … }>` | optional | Settings manifest translations keyed by namespace | +| **metadataForms** | `Record; fields?: Record }>` | optional | Translations for metadata-type configuration forms keyed by metadata type | | **settingsCommon** | `{ sourceLabels?: object }` | optional | Cross-namespace Settings UI strings | @@ -192,14 +192,14 @@ One locale of translations — the `translation` metadata type | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **objects** | `Record }>; … }>` | optional | Object translations keyed by object name | -| **apps** | `Record }>` | optional | App translations keyed by app name | +| **objects** | `Record; … }>` | optional | Object translations keyed by object name | +| **apps** | `Record }>` | optional | App translations keyed by app name | | **messages** | `Record` | optional | UI message translations keyed by message ID | -| **globalActions** | `Record }>; … }>` | optional | Global action translations keyed by action name | -| **dashboards** | `Record; widgets?: Record }>` | optional | Dashboard translations keyed by dashboard name | +| **globalActions** | `Record; … }>` | optional | Global action translations keyed by action name | +| **dashboards** | `Record; widgets?: Record }>` | optional | Dashboard translations keyed by dashboard name | | **pages** | `Record` | optional | Page translations keyed by page name | -| **settings** | `Record; keys?: Record }>; … }>` | optional | Settings manifest translations keyed by namespace | -| **metadataForms** | `Record; fields?: Record }>` | optional | Translations for metadata-type configuration forms keyed by metadata type | +| **settings** | `Record; keys?: Record; … }>` | optional | Settings manifest translations keyed by namespace | +| **metadataForms** | `Record; fields?: Record }>` | optional | Translations for metadata-type configuration forms keyed by metadata type | | **settingsCommon** | `{ sourceLabels?: object }` | optional | Cross-namespace Settings UI strings | | **locale** | `string` | ✅ | BCP-47 locale this item translates (e.g. "zh-CN") | | **name** | `string` | optional | Item name — conventionally the locale code (`zh-CN`); the runtime sync falls back to it when `locale` is absent | diff --git a/content/docs/references/ui/action.mdx b/content/docs/references/ui/action.mdx index 691ce611b4..07280cefdc 100644 --- a/content/docs/references/ui/action.mdx +++ b/content/docs/references/ui/action.mdx @@ -86,7 +86,7 @@ const result = ActionSchema.parse(data); | **requiredPermissions** | `string[]` | optional | [ADR-0066 D4] Capabilities required to invoke this action. Enforced with 403 on the platform action route (script/flow/modal + MCP) and mirrored as a UI hide; a `type: api` action pointed at a custom endpoint must re-check it there. | | **shortcut** | `never` | optional | [REMOVED] `action.shortcut` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it never triggered anything: no keydown listener feeds ActionEngine.getShortcuts(), and objectui's keyboard stack (useKeyboardShortcuts) is hand-registered and never consults action metadata. Delete the key. For a real shortcut, register the key in the Console keyboard stack and have its handler invoke the action by name. | | **bulkEnabled** | `never` | optional | [REMOVED] `action.bulkEnabled` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — the multi-select toolbar is driven by the LIST VIEW's `bulkActions` / `bulkActionDefs`, never by this flag, so setting it changed nothing. Delete the key and declare the action in the view's `bulkActions` instead. | -| **ai** | `{ exposed?: boolean; description?: string; category?: Enum<'data' \| 'action' \| 'flow' \| 'integration' \| 'vector_search' \| 'analytics' \| 'utility'>; paramHints?: Record; … }` | optional | AI exposure (opt-in). Set ai.exposed=true + ai.description to make this callable by agents. | +| **ai** | `{ exposed?: boolean; description?: string; category?: Enum<'data' \| 'action' \| 'flow' \| 'integration' \| 'vector_search' \| 'analytics' \| 'utility'>; paramHints?: Record; … }` | optional | AI exposure (opt-in). Set ai.exposed=true + ai.description to make this callable by agents. | | **recordIdParam** | `string` | optional | Body key to inject the row id into when running from a list_item context. | | **recordIdField** | `string` | optional | Row field whose value seeds recordIdParam. Defaults to "id". | | **bodyShape** | `'flat' \| { wrap: string }` | optional | Body wrapping: flat (default) or `{ wrap: key }` to nest user-collected params under a key. | @@ -166,7 +166,7 @@ const result = ActionSchema.parse(data); | **label** | `string` | optional | Display label (plain string; i18n keys are auto-generated by the framework) | | **type** | `Enum<'text' \| 'textarea' \| 'email' \| 'url' \| 'phone' \| 'password' \| 'secret' \| 'markdown' \| 'html' \| 'richtext' \| 'number' \| 'currency' \| 'percent' \| 'date' \| … +35 more>` | optional | | | **required** | `boolean` | optional | | -| **options** | `{ label: string; value: string; visibleWhen?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object } }[]` | optional | | +| **options** | `{ label: string; value: string; visibleWhen?: string \| object }[]` | optional | | | **placeholder** | `string` | optional | | | **helpText** | `string` | optional | | | **defaultValue** | `any` | optional | | diff --git a/content/docs/references/ui/app.mdx b/content/docs/references/ui/app.mdx index 6987dd2b8b..e8e1aa05db 100644 --- a/content/docs/references/ui/app.mdx +++ b/content/docs/references/ui/app.mdx @@ -120,7 +120,7 @@ const result = ActionNavItemSchema.parse(data); | **id** | `string` | ✅ | Selector id; selected value is exposed as the nav template var `{}` | | **label** | `string` | ✅ | Dropdown label | | **icon** | `string` | optional | Icon name | -| **optionsSource** | `{ endpoint: string; valueKey: string; labelKey: string; filter?: { key: string; op: Enum<'eq' \| 'ne' \| 'in' \| 'nin'>; value: string \| string[] }[] }` | ✅ | Option data source | +| **optionsSource** | `{ endpoint: string; valueKey: string; labelKey: string; filter?: object[] }` | ✅ | Option data source | | **allValue** | `string` | ✅ | Sentinel value meaning "no concrete selection yet" (empty string is almost always right) | | **persist** | `Enum<'query' \| 'session' \| 'none'>` | ✅ | Persist selection via URL query, sessionStorage, or not at all | diff --git a/content/docs/references/ui/component.mdx b/content/docs/references/ui/component.mdx index 4748dfb39c..48db0516fe 100644 --- a/content/docs/references/ui/component.mdx +++ b/content/docs/references/ui/component.mdx @@ -256,7 +256,7 @@ const result = AIChatWindowProps.parse(data); | :--- | :--- | :--- | :--- | | **type** | `Enum<'line' \| 'card' \| 'pill'>` | optional | | | **position** | `Enum<'top' \| 'left'>` | optional | | -| **items** | `{ label: string; icon?: string; visibleWhen?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; value?: string; … }[]` | ✅ | | +| **items** | `{ label: string; icon?: string; visibleWhen?: string \| object; value?: string; … }[]` | ✅ | | | **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | diff --git a/content/docs/references/ui/dashboard.mdx b/content/docs/references/ui/dashboard.mdx index 9dfc88c073..5d72cf3b46 100644 --- a/content/docs/references/ui/dashboard.mdx +++ b/content/docs/references/ui/dashboard.mdx @@ -32,7 +32,7 @@ const result = DashboardSchema.parse(data); | **name** | `string` | ✅ | Dashboard unique name | | **label** | `string` | ✅ | Dashboard label | | **description** | `string` | optional | Dashboard description | -| **header** | `{ showTitle: boolean; showDescription: boolean; actions?: { label: string; actionUrl: string; actionType?: Enum<'script' \| 'url' \| 'modal' \| 'flow' \| 'api' \| 'form'>; icon?: string }[] }` | optional | Dashboard header configuration | +| **header** | `{ showTitle: boolean; showDescription: boolean; actions?: object[] }` | optional | Dashboard header configuration | | **widgets** | `{ id: string; title?: string; description?: string; type: Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| … +13 more>; … }[]` | ✅ | Widgets to display | | **columns** | `integer` | optional | Number of grid columns (default 12) | | **gap** | `integer` | optional | Grid gap in Tailwind spacing units | diff --git a/content/docs/references/ui/page.mdx b/content/docs/references/ui/page.mdx index d055e8f864..b4fb239761 100644 --- a/content/docs/references/ui/page.mdx +++ b/content/docs/references/ui/page.mdx @@ -54,7 +54,7 @@ Interface-level page configuration (Airtable parity) | **levels** | `integer` | optional | Number of hierarchy levels to display | | **sourceView** | `string` | optional | @deprecated Legacy named-view inheritance. Define columns/sort/filterBy on the page instead. | | **appearance** | `{ showDescription: boolean; allowedVisualizations?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>[] }` | optional | Appearance and visualization configuration | -| **userFilters** | `{ element: Enum<'dropdown' \| 'tabs' \| 'toggle'>; fields?: { field: string; label?: string; type?: Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>; options?: { value: string \| number \| boolean; label: string; color?: string }[]; … }[]; tabs?: { name: string; label?: string; icon?: string; view?: string; … }[]; showAllRecords?: boolean; … }` | optional | End-user quick-filter bar for this page (overrides the source view's userFilters) | +| **userFilters** | `{ element: Enum<'dropdown' \| 'tabs' \| 'toggle'>; fields?: object[]; tabs?: object[]; showAllRecords?: boolean; … }` | optional | End-user quick-filter bar for this page (overrides the source view's userFilters) | | **userActions** | `{ sort: boolean; search: boolean; filter: boolean; refresh: boolean; … }` | optional | User action toggles | | **addRecord** | `{ enabled: boolean; position: Enum<'top' \| 'bottom' \| 'both'>; mode: Enum<'inline' \| 'form' \| 'modal'>; formView?: string }` | optional | Add record entry point configuration | | **buttons** | `string[]` | optional | Toolbar buttons — names of the source object's actions to surface in the page toolbar | @@ -79,13 +79,13 @@ Interface-level page configuration (Airtable parity) | **variables** | `{ name: string; type?: Enum<'string' \| 'number' \| 'boolean' \| 'object' \| 'array' \| 'record_id'>; defaultValue?: any; source?: string }[]` | optional | Local page state, exposed to expressions as `page.` and writable by interactive elements via `source` (master/detail, filtered dashboards). | | **object** | `string` | optional | Bound object (for Record pages) | | **template** | `string` | optional | Layout template name (e.g. "header-sidebar-main") | -| **regions** | `{ name: string; width?: Enum<'small' \| 'medium' \| 'large' \| 'full'>; components: { type: Enum<'page:header' \| 'page:footer' \| 'page:sidebar' \| 'page:tabs' \| 'page:accordion' \| … +29 more> \| string; id?: string; label?: string; properties?: Record; … }[] }[]` | optional | Layout regions (header, main, sidebar, footer) with their components. Optional — list pages use interfaceConfig, slotted pages use slots, and an empty full page falls back to the synthesized default layout. | +| **regions** | `{ name: string; width?: Enum<'small' \| 'medium' \| 'large' \| 'full'>; components: object[] }[]` | optional | Layout regions (header, main, sidebar, footer) with their components. Optional — list pages use interfaceConfig, slotted pages use slots, and an empty full page falls back to the synthesized default layout. | | **isDefault** | `boolean` | optional | | | **assignedProfiles** | `string[]` | optional | | -| **interfaceConfig** | `{ source?: string; columns?: string[] \| { field: string; label?: string; width?: number; align?: Enum<'left' \| 'center' \| 'right'>; … }[]; sort?: { field: string; order: Enum<'asc' \| 'desc'> }[]; filterBy?: { field: string; operator?: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'starts_with' \| … +14 more>; value?: string \| number \| boolean \| null \| (string \| number)[] }[]; … }` | optional | Interface-level page configuration (for Airtable-style interface pages) | +| **interfaceConfig** | `{ source?: string; columns?: string[] \| object[]; sort?: object[]; filterBy?: object[]; … }` | optional | Interface-level page configuration (for Airtable-style interface pages) | | **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | | **kind** | `Enum<'full' \| 'slotted' \| 'html' \| 'react' \| 'jsx'>` | optional | Page override mode. full \| slotted = structured authoring; html = author-written constrained JSX/HTML+Tailwind compiled (parsed, never executed) to the tree (ADR-0080; the legacy value 'jsx' is a deprecated alias); react = real-React source executed at render by the runtime (ADR-0081); it runs author JS, so it is gated by a host capability that defaults ON and is disabled server-side via the OS_PAGE_REACT=off env toggle. | -| **slots** | `{ header?: { type: Enum<'page:header' \| 'page:footer' \| 'page:sidebar' \| 'page:tabs' \| 'page:accordion' \| … +29 more> \| string; id?: string; label?: string; properties?: Record; … } \| { type: Enum<'page:header' \| 'page:footer' \| 'page:sidebar' \| 'page:tabs' \| 'page:accordion' \| … +29 more> \| string; id?: string; label?: string; properties?: Record; … }[]; actions?: { type: Enum<'page:header' \| 'page:footer' \| 'page:sidebar' \| 'page:tabs' \| 'page:accordion' \| … +29 more> \| string; id?: string; label?: string; properties?: Record; … } \| { type: Enum<'page:header' \| 'page:footer' \| 'page:sidebar' \| 'page:tabs' \| 'page:accordion' \| … +29 more> \| string; id?: string; label?: string; properties?: Record; … }[]; alerts?: { type: Enum<'page:header' \| 'page:footer' \| 'page:sidebar' \| 'page:tabs' \| 'page:accordion' \| … +29 more> \| string; id?: string; label?: string; properties?: Record; … } \| { type: Enum<'page:header' \| 'page:footer' \| 'page:sidebar' \| 'page:tabs' \| 'page:accordion' \| … +29 more> \| string; id?: string; label?: string; properties?: Record; … }[]; highlights?: { type: Enum<'page:header' \| 'page:footer' \| 'page:sidebar' \| 'page:tabs' \| 'page:accordion' \| … +29 more> \| string; id?: string; label?: string; properties?: Record; … } \| { type: Enum<'page:header' \| 'page:footer' \| 'page:sidebar' \| 'page:tabs' \| 'page:accordion' \| … +29 more> \| string; id?: string; label?: string; properties?: Record; … }[]; … }` | optional | Slot override map for slotted pages | +| **slots** | `{ header?: object \| object[]; actions?: object \| object[]; alerts?: object \| object[]; highlights?: object \| object[]; … }` | optional | Slot override map for slotted pages | | **source** | `string` | optional | Page source text. For kind==='html' (alias 'jsx') it is constrained JSX/HTML+Tailwind compiled to the tree by @objectstack/sdui-parser at save time (parse, never execute). For kind==='react' it is real React/JSX executed at render by @object-ui/react-runtime (trusted tier). Authoritative over `regions` in both. | | **requires** | `string[]` | optional | Plugin namespaces the JSX source references (validated at save and load) | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | @@ -115,7 +115,7 @@ Interface-level page configuration (Airtable parity) | **responsiveStyles** | `{ large?: Record; medium?: Record; small?: Record; xsmall?: Record }` | optional | Per-breakpoint scoped style maps (ADR-0065) | | **visibleWhen** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | Visibility predicate (CEL) — component rendered only when TRUE. Binds `record`, `current_user`, `page.`. e.g. "page.selectedProjectId != ''" | | **visibility** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | [DEPRECATED → `visibleWhen`] Visibility predicate (CEL). Normalized to `visibleWhen` at parse. | -| **dataSource** | `{ object: string; view?: string; filter?: any; sort?: { field: string; order: Enum<'asc' \| 'desc'> }[]; … }` | optional | Per-element data binding for multi-object pages | +| **dataSource** | `{ object: string; view?: string; filter?: any; sort?: object[]; … }` | optional | Per-element data binding for multi-object pages | | **responsive** | `{ breakpoint?: Enum<'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'>; hiddenOn?: Enum<'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'>[]; columns?: object; order?: object }` | optional | Responsive layout configuration | | **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | diff --git a/content/docs/references/ui/view.mdx b/content/docs/references/ui/view.mdx index 5240493b32..3e729aa4a3 100644 --- a/content/docs/references/ui/view.mdx +++ b/content/docs/references/ui/view.mdx @@ -234,7 +234,7 @@ Column footer summary configuration | **visibleOn** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | [DEPRECATED → `visibleWhen`] Visibility predicate (CEL). Hides the whole section when false. Normalized to `visibleWhen` at parse. | | **columns** | `Enum<'1' \| '2' \| '3' \| '4'> \| 1 \| 2 \| 3 \| 4` | optional | | | **pane** | `Enum<'primary' \| 'secondary'>` | optional | Split pane this section renders in (split forms only; a parse error elsewhere). Omitted → first section 'primary', others 'secondary'. | -| **fields** | `(string \| { field: string; type?: Enum<'text' \| 'textarea' \| 'email' \| 'url' \| 'phone' \| 'password' \| 'secret' \| … +42 more>; options?: { label: string; value: string; color?: string; default?: boolean; … }[]; reference?: string; … })[]` | ✅ | | +| **fields** | `(string \| { field: string; type?: Enum<'text' \| 'textarea' \| 'email' \| 'url' \| 'phone' \| 'password' \| 'secret' \| … +42 more>; options?: object[]; reference?: string; … })[]` | ✅ | | --- @@ -313,7 +313,7 @@ Gallery/card view configuration | **effortField** | `string` | optional | Per-task load units (resource view; default 1) | | **capacity** | `number` | optional | Per-resource capacity ceiling; loads above this flag overload | | **tooltipFields** | `(string \| { field: string; label?: string })[]` | optional | Fields to surface in the hover tooltip, in display order | -| **quickFilters** | `{ field: string; label?: string; options?: (string \| { value: string \| number; label?: string })[] }[]` | optional | Multi-select filter dropdowns rendered above the chart | +| **quickFilters** | `{ field: string; label?: string; options?: (string \| object)[] }[]` | optional | Multi-select filter dropdowns rendered above the chart | | **autoZoomToFilter** | `boolean` | optional | When true (default), filtering zooms the range to the filtered tasks | @@ -456,7 +456,7 @@ List chart view configuration | **sort** | `string \| { field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | | | **searchableFields** | `string[]` | optional | Fields enabled for search | | **filterableFields** | `string[]` | optional | Legacy shorthand for userFilters.fields — bare field names enabled for end-user filtering. Prefer userFilters | -| **userFilters** | `{ element?: Enum<'dropdown' \| 'tabs' \| 'toggle'>; fields?: { field: string; label?: string; type?: Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>; options?: { value: string \| number \| boolean; label: string; color?: string }[]; … }[]; tabs?: { name: string; label?: string; icon?: string; view?: string; … }[]; showAllRecords?: boolean; … }` | optional | End-user quick-filter bar: dropdown/toggle fields or tab presets. Omit to let the renderer derive filters from select/boolean fields | +| **userFilters** | `{ element?: Enum<'dropdown' \| 'tabs' \| 'toggle'>; fields?: object[]; tabs?: object[]; showAllRecords?: boolean; … }` | optional | End-user quick-filter bar: dropdown/toggle fields or tab presets. Omit to let the renderer derive filters from select/boolean fields | | **resizable** | `boolean` | optional | Enable column resizing | | **striped** | `boolean` | optional | Striped row styling | | **bordered** | `boolean` | optional | Show borders | @@ -474,7 +474,7 @@ List chart view configuration | **description** | `string` | optional | View description for documentation/tooltips | | **sharing** | `{ type?: Enum<'personal' \| 'collaborative'>; lockedBy?: string }` | optional | View sharing and access configuration | | **rowHeight** | `Enum<'compact' \| 'short' \| 'medium' \| 'tall' \| 'extra_tall'>` | optional | Row height / density setting | -| **grouping** | `{ fields: { field: string; order?: Enum<'asc' \| 'desc'>; collapsed?: boolean }[] }` | optional | Group records by one or more fields | +| **grouping** | `{ fields: object[] }` | optional | Group records by one or more fields | | **rowColor** | `{ field: string; colors?: Record }` | optional | Color rows based on field value | | **hiddenFields** | `string[]` | optional | Fields to hide in this specific view | | **fieldOrder** | `string[]` | optional | Explicit field display order for this view | @@ -482,7 +482,7 @@ List chart view configuration | **bulkActions** | `string[]` | optional | Actions available when multiple rows are selected | | **bulkActionDefs** | `{ name: string; label?: string; icon?: string; variant?: Enum<'primary' \| 'secondary' \| 'danger' \| 'ghost' \| 'outline'>; … }[]` | optional | Rich bulk action definitions (schema-driven, executed via BulkActionDialog). Use a def for a mass data-plane mutation ('update' with a `patch` / 'delete') that no action expresses, or for an `operation: 'custom'` + `execution: 'aggregate'` entry (objectui#3139) that dispatches the action it NAMES once for the whole selection — the renderer injects `params._selectedIds: string[]` (read that on the server, not `recordId`) so a single call can produce one aggregate artifact (zip of QR codes, merged PDF, batch print). Aggregate results are all-or-nothing: a handler that cannot cover the whole selection must reject, and per-row retry is replaced by re-running the action. `batchSize` does not apply (the call is never chunked); set `maxRecords` on defs whose server work is expensive. For the PER-RECORD dispatch use `bulkActions: ['']` instead — the bare-string form, promoted with the action's own label, params and `visible`; a 'custom' def without `execution: 'aggregate'` has no dispatcher and is refused at parse time (#4457). Toolbar url/api actions can also interpolate the current selection via `${ctx.selection.ids}` / `${ctx.selection.count}`. | | **virtualScroll** | `boolean` | optional | Enable virtual scrolling for large datasets | -| **conditionalFormatting** | `{ condition: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; style: Record }[]` | optional | Conditional formatting rules for list rows | +| **conditionalFormatting** | `{ condition: string \| object; style: Record }[]` | optional | Conditional formatting rules for list rows | | **inlineEdit** | `boolean` | optional | Allow inline editing of records directly in the list view | | **exportOptions** | `Enum<'csv' \| 'xlsx' \| 'pdf' \| 'json'>[]` | optional | Available export format options | | **userActions** | `{ sort?: boolean; search?: boolean; filter?: boolean; refresh?: boolean; … }` | optional | User action toggles for the view toolbar | @@ -562,7 +562,7 @@ List chart view configuration | **description** | `string` | optional | View description for documentation/tooltips | | **sharing** | `{ type?: Enum<'personal' \| 'collaborative'>; lockedBy?: string }` | optional | View sharing and access configuration | | **rowHeight** | `Enum<'compact' \| 'short' \| 'medium' \| 'tall' \| 'extra_tall'>` | optional | Row height / density setting | -| **grouping** | `{ fields: { field: string; order?: Enum<'asc' \| 'desc'>; collapsed?: boolean }[] }` | optional | Group records by one or more fields | +| **grouping** | `{ fields: object[] }` | optional | Group records by one or more fields | | **rowColor** | `{ field: string; colors?: Record }` | optional | Color rows based on field value | | **hiddenFields** | `string[]` | optional | Fields to hide in this specific view | | **fieldOrder** | `string[]` | optional | Explicit field display order for this view | @@ -570,7 +570,7 @@ List chart view configuration | **bulkActions** | `string[]` | optional | Actions available when multiple rows are selected | | **bulkActionDefs** | `{ name: string; label?: string; icon?: string; variant?: Enum<'primary' \| 'secondary' \| 'danger' \| 'ghost' \| 'outline'>; … }[]` | optional | Rich bulk action definitions (schema-driven, executed via BulkActionDialog). Use a def for a mass data-plane mutation ('update' with a `patch` / 'delete') that no action expresses, or for an `operation: 'custom'` + `execution: 'aggregate'` entry (objectui#3139) that dispatches the action it NAMES once for the whole selection — the renderer injects `params._selectedIds: string[]` (read that on the server, not `recordId`) so a single call can produce one aggregate artifact (zip of QR codes, merged PDF, batch print). Aggregate results are all-or-nothing: a handler that cannot cover the whole selection must reject, and per-row retry is replaced by re-running the action. `batchSize` does not apply (the call is never chunked); set `maxRecords` on defs whose server work is expensive. For the PER-RECORD dispatch use `bulkActions: ['']` instead — the bare-string form, promoted with the action's own label, params and `visible`; a 'custom' def without `execution: 'aggregate'` has no dispatcher and is refused at parse time (#4457). Toolbar url/api actions can also interpolate the current selection via `${ctx.selection.ids}` / `${ctx.selection.count}`. | | **virtualScroll** | `boolean` | optional | Enable virtual scrolling for large datasets | -| **conditionalFormatting** | `{ condition: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; style: Record }[]` | optional | Conditional formatting rules for list rows | +| **conditionalFormatting** | `{ condition: string \| object; style: Record }[]` | optional | Conditional formatting rules for list rows | | **inlineEdit** | `boolean` | optional | Allow inline editing of records directly in the list view | | **exportOptions** | `Enum<'csv' \| 'xlsx' \| 'pdf' \| 'json'>[]` | optional | Available export format options | | **userActions** | `{ sort?: boolean; search?: boolean; filter?: boolean; refresh?: boolean; … }` | optional | User action toggles for the view toolbar | @@ -583,7 +583,7 @@ List chart view configuration | **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes for the list view | | **responsive** | `never` | optional | [REMOVED] `view.responsive` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer ever read it; the grid is responsive by its own layout rules. Delete the key. | | **performance** | `never` | optional | [REMOVED] `view.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; list-view performance tuning was never implemented. Delete the key. | -| **userFilters** | `{ element?: Enum<'dropdown' \| 'toggle'>; fields?: { field: string; label?: string; type?: Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>; options?: { value: string \| number \| boolean; label: string; color?: string }[]; … }[] }` | optional | | +| **userFilters** | `{ element?: Enum<'dropdown' \| 'toggle'>; fields?: object[] }` | optional | | --- @@ -595,7 +595,7 @@ List chart view configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **element** | `Enum<'dropdown' \| 'toggle'>` | ✅ | Filter control style on object views: "dropdown" (per-field value chips). "toggle" is deprecated. "tabs" is page-only — use `listViews` for named presets. | -| **fields** | `{ field: string; label?: string; type?: Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>; options?: { value: string \| number \| boolean; label: string; color?: string }[]; … }[]` | optional | Fields exposed as quick filters (dropdown/toggle elements) | +| **fields** | `{ field: string; label?: string; type?: Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>; options?: object[]; … }[]` | optional | Fields exposed as quick filters (dropdown/toggle elements) | --- @@ -731,7 +731,7 @@ End-user quick-filter configuration (Airtable "User filters" parity) | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **element** | `Enum<'dropdown' \| 'tabs' \| 'toggle'>` | ✅ | Filter control style: "dropdown" (per-field value selectors) or "tabs" (named presets). "toggle" is deprecated. | -| **fields** | `{ field: string; label?: string; type?: Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>; options?: { value: string \| number \| boolean; label: string; color?: string }[]; … }[]` | optional | Fields exposed as quick filters (dropdown/toggle elements) | +| **fields** | `{ field: string; label?: string; type?: Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>; options?: object[]; … }[]` | optional | Fields exposed as quick filters (dropdown/toggle elements) | | **tabs** | `{ name: string; label?: string; icon?: string; view?: string; … }[]` | optional | Named filter presets rendered as tabs (tabs element). Reuses ViewTabSchema | | **showAllRecords** | `boolean` | optional | Show an "All records" tab before the presets (tabs element) | | **allowAddTab** | `boolean` | optional | Render an "add tab" affordance after the presets (tabs element). Page lists only — object views use `listViews` for named presets | @@ -748,9 +748,9 @@ End-user quick-filter configuration (Airtable "User filters" parity) | **name** | `string` | optional | Item name — supplied by the metadata door; for an object-scoped container it is the object name. | | **label** | `string` | optional | Human-readable label shown in metadata lists. | | **object** | `string` | optional | Object this container binds to — how a stack-level `views: [...]` entry says which object its views belong to; read by `getViewsByObject()` / `GET /meta/view?object=`. | -| **list** | `{ name?: string; label?: string; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: { provider: 'object'; object: string } \| { provider: 'api'; read?: object; write?: object } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record }; … }` | optional | | +| **list** | `{ name?: string; label?: string; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }` | optional | | | **form** | `{ type?: Enum<'simple' \| 'tabbed' \| 'wizard' \| 'split' \| 'drawer' \| 'modal'>; layout?: Enum<'vertical' \| 'horizontal' \| 'inline' \| 'grid'>; columns?: integer; title?: string; … }` | optional | | -| **listViews** | `Record; data?: { provider: 'object'; object: string } \| { provider: 'api'; read?: object; write?: object } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record }; … }>` | optional | Additional named list views (views mode — dropdown userFilters allowed, no tabs; ADR-0047) | +| **listViews** | `Record; data?: object \| object \| object \| object; … }>` | optional | Additional named list views (views mode — dropdown userFilters allowed, no tabs; ADR-0047) | | **formViews** | `Record; layout?: Enum<'vertical' \| 'horizontal' \| 'inline' \| 'grid'>; columns?: integer; title?: string; … }>` | optional | Additional named form views | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this view. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | @@ -869,7 +869,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **viewKind** | `'list'` | ✅ | | -| **config** | `{ name?: string; label?: string; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: { provider: 'object'; object: string } \| { provider: 'api'; read?: object; write?: object } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record }; … }` | ✅ | List-family view configuration. | +| **config** | `{ name?: string; label?: string; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }` | ✅ | List-family view configuration. | | **name** | `string` | ✅ | Globally-unique view id, `.`. | | **object** | `string` | ✅ | Bound object name — the foreign key used to aggregate views. | | **label** | `string` | optional | Display label (supports i18n). | @@ -935,7 +935,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **viewKind** | `'list'` | ✅ | | -| **config** | `{ name?: string; label?: string; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: { provider: 'object'; object: string } \| { provider: 'api'; read?: object; write?: object } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record }; … }` | ✅ | List-family view configuration. | +| **config** | `{ name?: string; label?: string; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }` | ✅ | List-family view configuration. | | **name** | `string` | ✅ | Globally-unique view id, `.`. | | **object** | `string` | ✅ | Bound object name — the foreign key used to aggregate views. | | **label** | `string` | optional | Display label (supports i18n). | diff --git a/packages/spec/scripts/format-type.test.ts b/packages/spec/scripts/format-type.test.ts index aa241395c9..baa14e7264 100644 --- a/packages/spec/scripts/format-type.test.ts +++ b/packages/spec/scripts/format-type.test.ts @@ -784,15 +784,25 @@ describe('formatType — over-wide enums inside a shape summary are elided with expect(rendered.length).toBe(174); }); - it('elides through array-of-object nesting — the `api/*.mdx` `error` shape', () => { - // A direct object child is forced opaque, but an ARRAY of objects recurses, - // which is how a 261-member enum reached a cell two levels down. - const rendered = formatType(ERROR_RESPONSE, ctx()); - expect(rendered).toBe( - "{ success: boolean; error?: { code: Enum<'VALIDATION_ERROR' | 'INVALID_FIELD' | " + - "'MISSING_REQUIRED_FIELD' | … +258 more>; message: string }[] }", + it('elides through a WRAPPER reached from a summary — array of enum', () => { + // REPLACED FIXTURE (#6374). This case used to run on `ERROR_RESPONSE`, whose + // enum sat two SHAPE levels down (`{ success; error?: { code: Enum<…> }[] }`) + // — a route the shape budget closes: that inner shape now prints `object`, + // so there is no enum there left to elide and the old assertion could only + // have been kept by asserting an emptiness. What #5340 actually claims is + // that the elision composes through the wrappers between a summary and a + // vocabulary, and that is still true and still worth pinning — the budget + // stops the renderer re-entering the OBJECT branch, it does not sever + // `inShapeSummary` from arrays and records. `ERROR_RESPONSE` keeps its job + // one block down, where it now pins the budget itself. + const rendered = formatType( + { type: 'object', properties: { codes: { type: 'array', items: { type: 'string', enum: ERROR_CODES } } } }, + ctx(), ); + expect(rendered).toContain('… +258 more'); expect(3 + 258).toBe(ERROR_CODES.length); + // Still an array OF the elided vocabulary, not an elided array. + expect(rendered.endsWith('>[] }')).toBe(true); // Was 5000+ characters in one table cell. expect(rendered.length).toBeLessThan(150); }); @@ -1199,17 +1209,266 @@ describe('formatType — a union spells four variants and counts the rest (#6226 expect(rendered).toContain('… +5 more'); }); - it('caps a union nested inside a shape summary too, alongside the enum elision', () => { - // The two elisions compose: `Page.slots`-shaped cells carry both. + it('caps a union nested inside a shape summary too — the `Manifest.navigationContributions` cell', () => { + // REPLACED FIXTURE (#6374). This case used to build six OBJECT variants + // under a key and assert `… +2 more`. Below a summary those six now all + // render `object`, and six six-character spellings are narrower than the + // marker that would replace two of them, so the shared pay-for-your-marker + // guard refuses — correctly, and the case would have been asserting the + // guard rather than the cap. The corpus keeps exactly one cell where a + // nested union is still wide enough for the cap to pay, and this is it. + const rendered = formatType( + { + type: 'object', + properties: { + app: { type: 'string' }, + items: { type: 'array', items: { anyOf: Array.from({ length: 9 }, (_, i) => variant(`k${i}`)) } }, + }, + required: ['app', 'items'], + }, + ctx(), + ); + expect(rendered).toBe('{ app: string; items: (object | object | object | object | … +5 more)[] }'); + // 4 shown + 5 hidden = the 9 the schema declares, below a summary exactly as + // above one: the budget changes what a variant SPELLS, never the arity the + // cap reports. + expect(4 + 5).toBe(9); + }); +}); + +/** + * The real `ui/page.mdx` `Page.slots` node, as `gen:schema` emits it — seven + * slot keys, each a union of `PageComponent` or an array of it, and + * `PageComponent` inlined by value (not `$ref`d) at all fourteen positions. + * + * This is the corpus maximum #6374 was filed on: 1538 characters in one table + * cell, WITH `INLINE_ENUM_WIDTH_LIMIT` already firing eight times inside it. + */ +const PAGE_COMPONENT = { + type: 'object', + properties: { + type: { + anyOf: [ + { + type: 'string', + enum: [ + 'page:header', 'page:footer', 'page:sidebar', 'page:tabs', 'page:accordion', + 'page:card', 'page:section', 'record:details', 'record:highlights', + 'record:related_list', 'record:activity', 'record:chatter', 'record:path', + 'record:alert', 'record:quick_actions', 'record:reference_rail', 'record:history', + 'app:launcher', 'nav:menu', 'nav:breadcrumb', 'global:search', + 'global:notifications', 'user:profile', 'ai:chat_window', 'ai:suggestion', + 'element:text', 'element:number', 'element:image', 'element:divider', + 'element:button', 'element:filter', 'element:form', 'element:record_picker', + 'element:text_input', + ], + }, + { type: 'string' }, + ], + }, + id: { type: 'string' }, + label: { type: 'string' }, + properties: { type: 'object', additionalProperties: {} }, + events: { type: 'object', additionalProperties: {} }, + }, + required: ['type'], + additionalProperties: false, +}; + +const PAGE_SLOTS = { + type: 'object', + properties: Object.fromEntries( + ['header', 'actions', 'alerts', 'highlights', 'details', 'tabs', 'discussion'].map(k => [ + k, + { anyOf: [PAGE_COMPONENT, { type: 'array', items: PAGE_COMPONENT }] }, + ]), + ), + additionalProperties: false, +}; + +/** + * Pin for the shape-depth budget — #6374. + * + * The renderer has always opened exactly ONE `{ … }` level per cell, but it + * spent that budget in the key loop, so only a DIRECT object child was held to + * it. An array element, a `Record` value and a union variant each re-entered + * the object branch with the budget out of scope, and cell width became keys × + * variants × shape width, multiplied per level. `SHAPE_DEPTH_LIMIT` moves the + * same budget to the object branch itself, where all four descents pass. + * + * REVERSE VERIFICATION, predicted BEFORE running. Reverting = deleting the + * `depth >= SHAPE_DEPTH_LIMIT` guard and putting the + * `child?.type === 'object' && child.properties ? 'object' : …` ternary back. + * The direction is NOT uniformly red, and that asymmetry is the point of the + * block: this fix makes an existing rule uniform, so the cases pinning the + * limb that already existed MUST stay green under the revert or they are not + * pinning uniformity at all. Predicted: + * RED — every case whose `object` is reached through an array, a `Record` + * value or a union variant (the three descents the budget adds), and + * the no-`ctx` case, which reaches its `object` through a variant. + * GREEN — 'a direct object child was ALREADY opaque' (that IS the ternary), + * both 'a wrapper does not spend the budget' cases (one level either + * way), and 'a keyless `Record` is not a shape' (the guard sits + * inside the declared-keys branch and cannot fire there). + * Predicted split: 6 red, 4 green. + * ACTUAL: recorded in the PR body against this prediction. + */ +describe('formatType — one shape level, whichever way down (#6374)', () => { + it('renders the `Page.slots` cell without re-expanding `PageComponent` (the filed instance)', () => { + const rendered = formatType(PAGE_SLOTS, ctx()); + expect(rendered).toBe( + '{ header?: object | object[]; actions?: object | object[]; alerts?: object | object[]; ' + + 'highlights?: object | object[]; … }', + ); + // 1538 → 122 characters. The vacuity guard for the whole block: with the + // budget reverted this node renders the same `PageComponent` summary eight + // times, so both of these are false by more than an order of magnitude. + expect(rendered.length).toBe(122); + expect(rendered).not.toContain('Enum<'); + }); + + it('holds an ARRAY element to the budget — the `api/*.mdx` `error` shape', () => { + // `ERROR_RESPONSE`'s old job, kept as the array case: the 261-member + // vocabulary sat two shape levels down and reached the cell because + // `{ … }[]` re-entered the object branch. The array is not what is elided — + // the cell still says "an array of them". + expect(formatType(ERROR_RESPONSE, ctx())).toBe('{ success: boolean; error?: object[] }'); + }); + + it('holds a `Record` VALUE to the budget — the `GetTranslationsResponse` shape', () => { + expect( + formatType( + { + type: 'object', + properties: { + objects: { + type: 'object', + additionalProperties: { type: 'object', properties: { label: { type: 'string' } } }, + }, + }, + }, + ctx(), + ), + ).toBe('{ objects?: Record }'); + }); + + it('holds a union VARIANT to the budget — the `Object.userActions` shape', () => { + expect( + formatType( + { + type: 'object', + properties: { + edit: { + anyOf: [ + { type: 'boolean' }, + { type: 'object', properties: { enabled: { type: 'boolean' } } }, + ], + }, + }, + }, + ctx(), + ), + ).toBe('{ edit?: boolean | object }'); + }); + + it('holds a direct object child to the budget — the limb that was ALREADY opaque', () => { + // Unchanged by this commit and asserted here on purpose: it is the rule the + // other three cases were brought into line with, so it has to be read as + // one rule with them rather than as a fourth special case. + expect( + formatType( + { + type: 'object', + properties: { inner: { type: 'object', properties: { deep: { type: 'string' } } } }, + }, + ctx(), + ), + ).toBe('{ inner?: object }'); + }); + + it('spends the budget on SHAPES, so a wrapper at the top of a cell still opens one level', () => { + // `{ … }[]` and `Record` are one shape level, not two — the + // budget counts `{ … }`, and a wrapper is not one. Getting this wrong would + // collapse the whole `ConversationSession.messages` family to a bare + // `object[]` and take the corpus with it. + expect( + formatType({ type: 'array', items: { type: 'object', properties: { a: { type: 'string' } } } }, ctx()), + ).toBe('{ a?: string }[]'); + expect( + formatType( + { type: 'object', additionalProperties: { type: 'object', properties: { a: { type: 'string' } } } }, + ctx(), + ), + ).toBe('Record'); + }); + + it('does not fire on a keyless `Record` below a summary — that is not a shape', () => { + // `properties?: Record` is on `PageComponent` itself and on + // hundreds of other nodes. The guard sits inside the declared-keys branch, + // so an open object with NO declared keys renders as it always did. + expect( + formatType( + { type: 'object', properties: { properties: { type: 'object', additionalProperties: {} } } }, + ctx(), + ), + ).toBe('{ properties?: Record }'); + }); + + it('applies without a `ctx`, because depth is recursion state and not page state', () => { + // The ternary this replaces needed no `ctx` either. A budget that lived in + // `TypeContext` would silently switch itself off for every caller that + // renders a type string without page context — the failure mode + // `inShapeSummary` documents one field up, and not one to copy. + expect( + formatType({ + type: 'object', + properties: { + edit: { anyOf: [{ type: 'boolean' }, { type: 'object', properties: { a: { type: 'string' } } }] }, + }, + }), + ).toBe('{ edit?: boolean | object }'); + }); + + it('leaves a cell that never opened a second shape level byte-identical', () => { + // The corpus check that the budget is not a rewrite: 173 of the 215 pages + // do not move at all. `BulkActionDef.params` (#5340's instance) and + // `App.navigation` (#6226's) are both one level deep and both unchanged. + expect(formatType(BULK_ACTION_PARAMS, ctx()).length).toBe(174); + expect(formatType(INDEX_SCHEMA, ctx())).toBe( + "{ name?: string; fields: string[]; unique?: boolean | 'global' | 'organization' }[]", + ); + expect(formatType(BULK_ACTION_OPTIONS, ctx())).toBe( + '({ label: string; value: string | number | boolean } & Record)[]', + ); + }); + + it('prints an identical variant once per variant — the budget may not drop the arity', () => { + // Six object variants below a summary all print `object`, and the cell says + // so six times. It reads oddly and it is deliberate: #6226 ruled that a + // union elision must SELF-REPORT what it hid, and the shared + // pay-for-your-marker guard refuses a marker here because six six-character + // spellings are narrower than the count that would replace two of them. + // Collapsing them to one `object` would drop the arity — the one fact the + // cell still carries — and would re-decide #6226 on a surface the + // maintainer has just ruled on. The renderer already ships exactly this + // shape for scalars (`string | string | string | string | string`, pinned + // in the #6226 block), so this is that pinned behaviour meeting a new + // spelling, not a new behaviour. Filed for the maintainer as a finding. const rendered = formatType( { type: 'object', properties: { - slot: { anyOf: Array.from({ length: 6 }, (_, i) => variant(`k${i}`)) }, + slot: { + anyOf: Array.from({ length: 6 }, (_, i) => ({ + type: 'object', + properties: { id: { type: 'string' }, [`k${i}`]: { type: 'string' } }, + })), + }, }, }, ctx(), ); - expect(rendered).toContain('… +2 more'); + expect(rendered).toBe('{ slot?: object | object | object | object | object | object }'); + expect(rendered).not.toContain('more'); }); }); diff --git a/packages/spec/scripts/lib/format-type.ts b/packages/spec/scripts/lib/format-type.ts index aa235b7fca..2819662949 100644 --- a/packages/spec/scripts/lib/format-type.ts +++ b/packages/spec/scripts/lib/format-type.ts @@ -74,6 +74,62 @@ export const anchorFor = (schemaName: string) => `#${schemaName.toLowerCase()}`; /** How many declared keys an inline object shows before eliding the rest. */ const INLINE_KEY_LIMIT = 4; +/** + * How many `{ … }` shape levels one cell expands before printing `object` + * (#6374). + * + * `INLINE_KEY_LIMIT` caps a summary's KEYS at its own level; the two enum + * budgets cap one key's VOCABULARY; `VARIANT_LIMIT` caps a union's ARITY. + * Nothing capped how many times a cell could re-enter the object branch, and + * cell width is the product of all four axes. `ui/page.mdx`'s `Page.slots` was + * the corpus maximum at 1538 characters with the enum elision already firing + * eight times inside it: 4 keys × a 2-variant union × a 176-character shape. + * + * WHY 1 — the number is RECOVERED, not chosen. This renderer has always had a + * depth budget of exactly one shape level, written as the ternary in the key + * loop below: a child that is itself an object printed `object` rather than its + * shape. That budget was applied on ONE of the four ways down. An array element + * (`{ … }[]`), a `Record` value (`Record`) and a union variant + * (`{ … } | { … }[]`) each re-entered the object branch through `renderType` + * with the budget nowhere in scope, so the same shape at the same reader-facing + * depth printed opaquely or in full depending on whether its author had wrapped + * it in an array. That is a fact about the Zod spelling, not about how a reader + * needs to read it — the same asymmetry #6225 removed for vocabularies. This + * constant makes the existing rule apply to all four descents; the ternary it + * replaces is its depth-1 case. + * + * The corpus confirms 1 is the only admissible value. Regenerating all 215 + * pages (8499 type cells) at each candidate, counting emitted cell widths: + * + * depth limit | (none, before) | 1 | 2 | 3 | 4 + * cells >200 | 121 | 42 | 173 | 191 | 191 + * cells >400 | 9 | 1 | 19 | 35 | 35 + * cells >600 | 3 | 1 | 2 | 14 | 22 + * cells >900 | 1 | 0 | 1 | 1 | 1 + * p95 / p99 | 145 / 229 | 124/180 | 154/260 | 154/280 | 154/287 + * max | 1538 | 656 | 1538 | 1538 | 1538 + * + * Every limit above 1 is worse than shipping nothing: raising it necessarily + * LOOSENS the direct-object-child path, which was already at 1, so cells over + * 200 rise from 121 to 173+ and the flagship never moves. There is no sweep to + * balance here and no threshold to tune — 1 is the status quo made uniform, + * and 2 and up are a regression dressed as a budget. + * + * At 1, every cell still over 400 characters is `ui/page.mdx`'s + * `PageComponent.type` (656), a top-level vocabulary in a union variant that + * #6225 deliberately leaves alone and that carries no nested shape at all. + * Shape-driven width is gone from the corpus. + * + * WHAT A READER LOSES, and why `object` is the honest rendering. Nothing is + * silently truncated: `object` claims nothing about keys, so unlike a prefix it + * cannot be mistaken for a complete list — which is the #5340 principle applied + * to shapes rather than to enum members. It is also not a new elision style in + * these tables: `object` is what a nested shape has always printed, and the + * complete shape stays where it always was — its own `## Schema` section when + * the generator emits one, and `json-schema/` in every case. + */ +const SHAPE_DEPTH_LIMIT = 1; + /** * Character budget for one `Enum<…>` BODY rendered INSIDE an inline shape * summary. Over it, members are dropped until the body fits and the count of @@ -426,7 +482,18 @@ export function formatPropertyType(prop: any, ctx?: TypeContext): RenderedProper return { cell: formatType(prop, ctx), allowedValues: null }; } +/** + * `depth` is the count of `{ … }` shape levels already OPEN above this node, + * and it is a parameter rather than a `TypeContext` field on purpose: a caller + * that passes no `ctx` (every unit test that only wants a type string) must + * still get the width budget, the way it always got the ternary this replaces. + * `ctx` carries facts about the PAGE; depth is a fact about the RECURSION. + */ export function formatType(prop: any, ctx?: TypeContext): string { + return renderType(prop, ctx, 0); +} + +function renderType(prop: any, ctx: TypeContext | undefined, depth: number): string { if (!prop) return 'any'; // A `retiredKey()` tombstone. `never` is both the accurate TypeScript (the @@ -452,7 +519,7 @@ export function formatType(prop: any, ctx?: TypeContext): string { if (ctx!.expanding?.has(name)) return 'object'; const expanding = new Set(ctx!.expanding ?? []); expanding.add(name); - return formatType({ ...target, $ref: undefined }, { ...ctx!, expanding }); + return renderType({ ...target, $ref: undefined }, { ...ctx!, expanding }, depth); } const href = ctx?.schemaHref?.(name) ?? null; @@ -460,7 +527,7 @@ export function formatType(prop: any, ctx?: TypeContext): string { } if (prop.type === 'array') { - const element = formatType(prop.items, ctx); + const element = renderType(prop.items, ctx, depth); // An open object element renders as an intersection and a multi-variant // element as a union — `[]` would re-associate either — so parenthesize // and the cell keeps meaning "array of that". @@ -477,7 +544,7 @@ export function formatType(prop: any, ctx?: TypeContext): string { if (prop.anyOf || prop.oneOf) { const variants = prop.anyOf || prop.oneOf; - const rendered = variants.map((v: any) => formatType(v, ctx)); + const rendered = variants.map((v: any) => renderType(v, ctx, depth)); const full = rendered.join(' | '); if (rendered.length <= VARIANT_LIMIT) return full; // The variants a reader does not see are counted, never silently dropped — @@ -496,7 +563,7 @@ export function formatType(prop: any, ctx?: TypeContext): string { // open object with a declared shape printed as a bare `Record` // and the author-facing page lost keys the schema *requires*. const open = prop.additionalProperties - ? `Record` + ? `Record` : null; // Inline object: show its shape one level deep instead of an opaque `Object`. @@ -517,18 +584,22 @@ export function formatType(prop: any, ctx?: TypeContext): string { : []; if (keys.length > 0) { + // The shape budget, spent HERE rather than at each of the four descents + // that reach this branch (#6374). A cell opens `SHAPE_DEPTH_LIMIT` shape + // levels; below that a shape prints `object`, whichever way down it was + // reached — a direct object child, an array element, a `Record` value or + // a union variant. Wrappers do not spend the budget, only shapes do, so + // `{ … }[]` and `Record` are one level, not two. + if (depth >= SHAPE_DEPTH_LIMIT) return 'object'; const shown = keys.slice(0, INLINE_KEY_LIMIT).map(k => { const child = prop.properties[k]; const optional = (prop.required || []).includes(k) ? '' : '?'; - // Depth-limited: nested objects stay opaque so a table cell can't explode. // Everything below this point is a SUMMARY of the child, not the // child's own row, so a long enum reached from here is elided (#5340). // The flag is set once, here, and inherited by every branch underneath - // — arrays of objects recurse (only a direct object child is forced - // opaque above), so `errors?: { code: Enum<…> }[]` is reached this way. - const childType = child?.type === 'object' && child.properties - ? 'object' - : formatType(child, ctx && { ...ctx, inShapeSummary: true }); + // — arrays of objects recurse, so `errors?: { code: Enum<…> }[]` is + // reached this way. + const childType = renderType(child, ctx && { ...ctx, inShapeSummary: true }, depth + 1); return `${k}${optional}: ${childType}`; }); // `…` elides further LIVE declared keys; `& Record<…>` states that From bb6cad6e9424495b4eb0a464d4867e4b28a3c238 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 8 Aug 2026 05:59:26 +0000 Subject: [PATCH 2/2] =?UTF-8?q?chore(spec):=20=E5=9C=A8=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E5=90=8E=E7=9A=84=E6=A0=91=E4=B8=8A=E9=87=8D=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=8F=82=E8=80=83=E6=96=87=E6=A1=A3=20(#6374)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `origin/main` 上有三个提交改了 schema 并各自重生成了 `content/docs/references/**`(#6512 i18n 标签契约、#6540 capability 注册、 #6526 ADR-0049 退役 sweep),与本分支的重生成在 13 个文件上相交。 `.gitattributes` 的 `merge=os-regen` 驱动按设计**没有做文本合并**,而是把这 13 个文件标记为「必须在合并后的树上重生成」—— 否则会落地 #6224 那种「零冲突 却陈旧」的组合。 本提交就是那次重生成:`gen:schema && gen:docs` 跑在合并后的树上,12 个文件 被修正,`check-regen-pending` 标记已清除。无一处手改 `.mdx`; `packages/spec/scripts/lib/format-type.ts` 与其测试**逐字未动**(main 上没有 任何提交碰过这两个文件)。 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01AZgRyPVwi1jLb1mNNuUQ9o --- content/docs/references/api/metadata.mdx | 7 +- content/docs/references/api/protocol.mdx | 134 +----------------- content/docs/references/data/object.mdx | 4 +- .../docs/references/integration/connector.mdx | 26 ++-- .../references/kernel/metadata-plugin.mdx | 8 +- .../docs/references/system/translation.mdx | 1 + content/docs/references/ui/action.mdx | 28 ++-- content/docs/references/ui/app.mdx | 52 +++---- content/docs/references/ui/component.mdx | 78 +++++----- content/docs/references/ui/dashboard.mdx | 22 +-- content/docs/references/ui/page.mdx | 14 +- content/docs/references/ui/view.mdx | 72 +++++----- 12 files changed, 166 insertions(+), 280 deletions(-) diff --git a/content/docs/references/api/metadata.mdx b/content/docs/references/api/metadata.mdx index c61423d396..6c61eff280 100644 --- a/content/docs/references/api/metadata.mdx +++ b/content/docs/references/api/metadata.mdx @@ -53,7 +53,7 @@ const result = AppDefinitionResponseSchema.parse(data); | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +257 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ name: string; label: string; description?: string; icon?: string; … }` | ✅ | Full App Configuration | +| **data** | `{ name: string; label: string \| Record; description?: string \| Record; icon?: string; … }` | ✅ | Full App Configuration | --- @@ -326,7 +326,7 @@ Metadata query with filtering, sorting, and pagination | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **types** | `Enum<'object' \| 'field' \| 'hook' \| 'seed' \| 'mapping' \| 'view' \| 'page' \| 'dashboard' \| 'app' \| 'action' \| 'report' \| 'dataset' \| 'flow' \| 'job' \| 'datasource' \| 'external_catalog' \| 'translation' \| 'api' \| 'email_template' \| 'doc' \| 'book' \| 'permission' \| 'position' \| 'agent' \| 'tool' \| 'skill'>[]` | optional | Filter by metadata types | +| **types** | `Enum<'object' \| 'field' \| 'hook' \| 'seed' \| 'mapping' \| 'view' \| 'page' \| 'dashboard' \| 'app' \| 'action' \| 'report' \| 'dataset' \| 'flow' \| 'job' \| 'datasource' \| 'external_catalog' \| 'translation' \| 'api' \| 'email_template' \| 'doc' \| 'book' \| 'permission' \| 'position' \| 'capability' \| 'agent' \| 'tool' \| 'skill'>[]` | optional | Filter by metadata types | | **namespaces** | `string[]` | optional | Filter by namespaces | | **packageId** | `string` | optional | Filter by owning package | | **search** | `string` | optional | Full-text search query | @@ -361,7 +361,7 @@ Metadata query with filtering, sorting, and pagination | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **type** | `Enum<'object' \| 'field' \| 'hook' \| 'seed' \| 'mapping' \| 'view' \| 'page' \| 'dashboard' \| 'app' \| 'action' \| 'report' \| 'dataset' \| 'flow' \| 'job' \| 'datasource' \| … +11 more>` | ✅ | Metadata type | +| **type** | `Enum<'object' \| 'field' \| 'hook' \| 'seed' \| 'mapping' \| 'view' \| 'page' \| 'dashboard' \| 'app' \| 'action' \| 'report' \| 'dataset' \| 'flow' \| 'job' \| 'datasource' \| … +12 more>` | ✅ | Metadata type | | **name** | `string` | ✅ | Item name (snake_case) | | **data** | `Record` | ✅ | Metadata payload | | **namespace** | `string` | optional | Optional namespace | @@ -391,6 +391,7 @@ Metadata query with filtering, sorting, and pagination * `book` * `permission` * `position` +* `capability` * `agent` * `tool` * `skill` diff --git a/content/docs/references/api/protocol.mdx b/content/docs/references/api/protocol.mdx index 0aa520fe41..eecf05b587 100644 --- a/content/docs/references/api/protocol.mdx +++ b/content/docs/references/api/protocol.mdx @@ -12,8 +12,8 @@ description: Protocol protocol schemas ## TypeScript Usage ```typescript -import { AiAgentCapabilitiesSchema, AiAgentChatRequestSchema, AiAgentSummarySchema, AiAgentsResponseSchema, AiChatRequestSchema, AiChatResponseSchema, AiCompleteRequestSchema, AiConversationSchema, AiMessageSchema, AiModelsResponseSchema, AiPendingActionSchema, AiPendingActionStatusSchema, AiStreamChunkSchema, ApproveAiPendingActionResponseSchema, AutomationActionsResponseSchema, AutomationTriggerRequestSchema, AutomationTriggerResponseSchema, BatchDataRequestSchema, BatchDataResponseSchema, CheckPermissionRequestSchema, CheckPermissionResponseSchema, CreateAiConversationRequestSchema, CreateDataRequestSchema, CreateDataResponseSchema, CreateManyDataRequestSchema, CreateManyDataResponseSchema, CreateViewRequestSchema, CreateViewResponseSchema, DeleteDataRequestSchema, DeleteDataResponseSchema, DeleteManyDataRequestSchema, DeleteManyDataResponseSchema, DeleteMetaItemRequestSchema, DeleteMetaItemResponseSchema, DeleteViewRequestSchema, DeleteViewResponseSchema, DisablePackageRequestSchema, DisablePackageResponseSchema, EnablePackageRequestSchema, EnablePackageResponseSchema, FindDataRequestSchema, FindDataResponseSchema, GetDataRequestSchema, GetDataResponseSchema, GetDiscoveryRequestSchema, GetDiscoveryResponseSchema, GetEffectivePermissionsRequestSchema, GetEffectivePermissionsResponseSchema, GetFieldLabelsRequestSchema, GetFieldLabelsResponseSchema, GetLocalesRequestSchema, GetLocalesResponseSchema, GetMetaItemCachedRequestSchema, GetMetaItemCachedResponseSchema, GetMetaItemRequestSchema, GetMetaItemResponseSchema, GetMetaItemsRequestSchema, GetMetaItemsResponseSchema, GetMetaTypesRequestSchema, GetMetaTypesResponseSchema, GetNotificationPreferencesRequestSchema, GetNotificationPreferencesResponseSchema, GetObjectPermissionsRequestSchema, GetObjectPermissionsResponseSchema, GetPackageRequestSchema, GetPackageResponseSchema, GetPresenceRequestSchema, GetPresenceResponseSchema, GetTranslationsRequestSchema, GetTranslationsResponseSchema, GetUiViewRequestSchema, GetUiViewResponseSchema, GetViewRequestSchema, GetViewResponseSchema, HttpFindQueryParamsSchema, InstallPackageRequestSchema, InstallPackageResponseSchema, ListAiConversationsRequestSchema, ListAiConversationsResponseSchema, ListAiPendingActionsRequestSchema, ListAiPendingActionsResponseSchema, ListNotificationsRequestSchema, ListNotificationsResponseSchema, ListPackagesRequestSchema, ListPackagesResponseSchema, ListViewsRequestSchema, ListViewsResponseSchema, MarkAllNotificationsReadRequestSchema, MarkAllNotificationsReadResponseSchema, MarkNotificationsReadRequestSchema, MarkNotificationsReadResponseSchema, NotificationSchema, NotificationPreferencesSchema, RealtimeConnectRequestSchema, RealtimeConnectResponseSchema, RealtimeDisconnectRequestSchema, RealtimeDisconnectResponseSchema, RealtimeSubscribeRequestSchema, RealtimeSubscribeResponseSchema, RealtimeUnsubscribeRequestSchema, RealtimeUnsubscribeResponseSchema, RegisterDeviceRequestSchema, RegisterDeviceResponseSchema, RejectAiPendingActionResponseSchema, SaveMetaItemRequestSchema, SaveMetaItemResponseSchema, SetPresenceRequestSchema, SetPresenceResponseSchema, UninstallPackageRequestSchema, UninstallPackageResponseSchema, UnregisterDeviceRequestSchema, UnregisterDeviceResponseSchema, UpdateAiConversationRequestSchema, UpdateDataRequestSchema, UpdateDataResponseSchema, UpdateManyDataRequestSchema, UpdateManyDataResponseSchema, UpdateNotificationPreferencesRequestSchema, UpdateNotificationPreferencesResponseSchema, UpdateViewRequestSchema, UpdateViewResponseSchema, ValidateDataIssueSchema, ValidateDataRequestSchema, ValidateDataResponseSchema } from '@objectstack/spec/api'; -import type { AiAgentCapabilities, AiAgentChatRequest, AiAgentSummary, AiAgentsResponse, AiChatRequest, AiChatResponse, AiCompleteRequest, AiConversation, AiMessage, AiModelsResponse, AiPendingAction, AiPendingActionStatus, AiStreamChunk, ApproveAiPendingActionResponse, AutomationActionsResponse, AutomationTriggerRequest, AutomationTriggerResponse, BatchDataRequest, BatchDataResponse, CheckPermissionRequest, CheckPermissionResponse, CreateAiConversationRequest, CreateDataRequest, CreateDataResponse, CreateManyDataRequest, CreateManyDataResponse, CreateViewRequest, CreateViewResponse, DeleteDataRequest, DeleteDataResponse, DeleteManyDataRequest, DeleteManyDataResponse, DeleteMetaItemRequest, DeleteMetaItemResponse, DeleteViewRequest, DeleteViewResponse, DisablePackageRequest, DisablePackageResponse, EnablePackageRequest, EnablePackageResponse, FindDataRequest, FindDataResponse, GetDataRequest, GetDataResponse, GetDiscoveryRequest, GetDiscoveryResponse, GetEffectivePermissionsRequest, GetEffectivePermissionsResponse, GetFieldLabelsRequest, GetFieldLabelsResponse, GetLocalesRequest, GetLocalesResponse, GetMetaItemCachedRequest, GetMetaItemCachedResponse, GetMetaItemRequest, GetMetaItemResponse, GetMetaItemsRequest, GetMetaItemsResponse, GetMetaTypesRequest, GetMetaTypesResponse, GetNotificationPreferencesRequest, GetNotificationPreferencesResponse, GetObjectPermissionsRequest, GetObjectPermissionsResponse, GetPackageRequest, GetPackageResponse, GetPresenceRequest, GetPresenceResponse, GetTranslationsRequest, GetTranslationsResponse, GetUiViewRequest, GetUiViewResponse, GetViewRequest, GetViewResponse, InstallPackageRequest, InstallPackageResponse, ListAiConversationsRequest, ListAiConversationsResponse, ListAiPendingActionsRequest, ListAiPendingActionsResponse, ListNotificationsRequest, ListNotificationsResponse, ListPackagesRequest, ListPackagesResponse, ListViewsRequest, ListViewsResponse, MarkAllNotificationsReadRequest, MarkAllNotificationsReadResponse, MarkNotificationsReadRequest, MarkNotificationsReadResponse, Notification, NotificationPreferences, RealtimeConnectRequest, RealtimeConnectResponse, RealtimeDisconnectRequest, RealtimeDisconnectResponse, RealtimeSubscribeRequest, RealtimeSubscribeResponse, RealtimeUnsubscribeRequest, RealtimeUnsubscribeResponse, RegisterDeviceRequest, RegisterDeviceResponse, RejectAiPendingActionResponse, SaveMetaItemRequest, SaveMetaItemResponse, SetPresenceRequest, SetPresenceResponse, UninstallPackageRequest, UninstallPackageResponse, UnregisterDeviceRequest, UnregisterDeviceResponse, UpdateAiConversationRequest, UpdateDataRequest, UpdateDataResponse, UpdateManyDataRequest, UpdateManyDataResponse, UpdateNotificationPreferencesRequest, UpdateNotificationPreferencesResponse, UpdateViewRequest, UpdateViewResponse, ValidateDataIssue, ValidateDataRequest, ValidateDataResponse } from '@objectstack/spec/api'; +import { AiAgentCapabilitiesSchema, AiAgentChatRequestSchema, AiAgentSummarySchema, AiAgentsResponseSchema, AiChatRequestSchema, AiChatResponseSchema, AiCompleteRequestSchema, AiConversationSchema, AiMessageSchema, AiModelsResponseSchema, AiPendingActionSchema, AiPendingActionStatusSchema, AiStreamChunkSchema, ApproveAiPendingActionResponseSchema, AutomationActionsResponseSchema, AutomationTriggerRequestSchema, AutomationTriggerResponseSchema, BatchDataRequestSchema, BatchDataResponseSchema, CheckPermissionRequestSchema, CheckPermissionResponseSchema, CreateAiConversationRequestSchema, CreateDataRequestSchema, CreateDataResponseSchema, CreateManyDataRequestSchema, CreateManyDataResponseSchema, DeleteDataRequestSchema, DeleteDataResponseSchema, DeleteManyDataRequestSchema, DeleteManyDataResponseSchema, DeleteMetaItemRequestSchema, DeleteMetaItemResponseSchema, DisablePackageRequestSchema, DisablePackageResponseSchema, EnablePackageRequestSchema, EnablePackageResponseSchema, FindDataRequestSchema, FindDataResponseSchema, GetDataRequestSchema, GetDataResponseSchema, GetDiscoveryRequestSchema, GetDiscoveryResponseSchema, GetEffectivePermissionsRequestSchema, GetEffectivePermissionsResponseSchema, GetFieldLabelsRequestSchema, GetFieldLabelsResponseSchema, GetLocalesRequestSchema, GetLocalesResponseSchema, GetMetaItemCachedRequestSchema, GetMetaItemCachedResponseSchema, GetMetaItemRequestSchema, GetMetaItemResponseSchema, GetMetaItemsRequestSchema, GetMetaItemsResponseSchema, GetMetaTypesRequestSchema, GetMetaTypesResponseSchema, GetNotificationPreferencesRequestSchema, GetNotificationPreferencesResponseSchema, GetObjectPermissionsRequestSchema, GetObjectPermissionsResponseSchema, GetPackageRequestSchema, GetPackageResponseSchema, GetPresenceRequestSchema, GetPresenceResponseSchema, GetTranslationsRequestSchema, GetTranslationsResponseSchema, GetUiViewRequestSchema, GetUiViewResponseSchema, HttpFindQueryParamsSchema, InstallPackageRequestSchema, InstallPackageResponseSchema, ListAiConversationsRequestSchema, ListAiConversationsResponseSchema, ListAiPendingActionsRequestSchema, ListAiPendingActionsResponseSchema, ListNotificationsRequestSchema, ListNotificationsResponseSchema, ListPackagesRequestSchema, ListPackagesResponseSchema, MarkAllNotificationsReadRequestSchema, MarkAllNotificationsReadResponseSchema, MarkNotificationsReadRequestSchema, MarkNotificationsReadResponseSchema, NotificationSchema, NotificationPreferencesSchema, RealtimeConnectRequestSchema, RealtimeConnectResponseSchema, RealtimeDisconnectRequestSchema, RealtimeDisconnectResponseSchema, RealtimeSubscribeRequestSchema, RealtimeSubscribeResponseSchema, RealtimeUnsubscribeRequestSchema, RealtimeUnsubscribeResponseSchema, RegisterDeviceRequestSchema, RegisterDeviceResponseSchema, RejectAiPendingActionResponseSchema, SaveMetaItemRequestSchema, SaveMetaItemResponseSchema, SetPresenceRequestSchema, SetPresenceResponseSchema, UninstallPackageRequestSchema, UninstallPackageResponseSchema, UnregisterDeviceRequestSchema, UnregisterDeviceResponseSchema, UpdateAiConversationRequestSchema, UpdateDataRequestSchema, UpdateDataResponseSchema, UpdateManyDataRequestSchema, UpdateManyDataResponseSchema, UpdateNotificationPreferencesRequestSchema, UpdateNotificationPreferencesResponseSchema, ValidateDataIssueSchema, ValidateDataRequestSchema, ValidateDataResponseSchema } from '@objectstack/spec/api'; +import type { AiAgentCapabilities, AiAgentChatRequest, AiAgentSummary, AiAgentsResponse, AiChatRequest, AiChatResponse, AiCompleteRequest, AiConversation, AiMessage, AiModelsResponse, AiPendingAction, AiPendingActionStatus, AiStreamChunk, ApproveAiPendingActionResponse, AutomationActionsResponse, AutomationTriggerRequest, AutomationTriggerResponse, BatchDataRequest, BatchDataResponse, CheckPermissionRequest, CheckPermissionResponse, CreateAiConversationRequest, CreateDataRequest, CreateDataResponse, CreateManyDataRequest, CreateManyDataResponse, DeleteDataRequest, DeleteDataResponse, DeleteManyDataRequest, DeleteManyDataResponse, DeleteMetaItemRequest, DeleteMetaItemResponse, DisablePackageRequest, DisablePackageResponse, EnablePackageRequest, EnablePackageResponse, FindDataRequest, FindDataResponse, GetDataRequest, GetDataResponse, GetDiscoveryRequest, GetDiscoveryResponse, GetEffectivePermissionsRequest, GetEffectivePermissionsResponse, GetFieldLabelsRequest, GetFieldLabelsResponse, GetLocalesRequest, GetLocalesResponse, GetMetaItemCachedRequest, GetMetaItemCachedResponse, GetMetaItemRequest, GetMetaItemResponse, GetMetaItemsRequest, GetMetaItemsResponse, GetMetaTypesRequest, GetMetaTypesResponse, GetNotificationPreferencesRequest, GetNotificationPreferencesResponse, GetObjectPermissionsRequest, GetObjectPermissionsResponse, GetPackageRequest, GetPackageResponse, GetPresenceRequest, GetPresenceResponse, GetTranslationsRequest, GetTranslationsResponse, GetUiViewRequest, GetUiViewResponse, InstallPackageRequest, InstallPackageResponse, ListAiConversationsRequest, ListAiConversationsResponse, ListAiPendingActionsRequest, ListAiPendingActionsResponse, ListNotificationsRequest, ListNotificationsResponse, ListPackagesRequest, ListPackagesResponse, MarkAllNotificationsReadRequest, MarkAllNotificationsReadResponse, MarkNotificationsReadRequest, MarkNotificationsReadResponse, Notification, NotificationPreferences, RealtimeConnectRequest, RealtimeConnectResponse, RealtimeDisconnectRequest, RealtimeDisconnectResponse, RealtimeSubscribeRequest, RealtimeSubscribeResponse, RealtimeUnsubscribeRequest, RealtimeUnsubscribeResponse, RegisterDeviceRequest, RegisterDeviceResponse, RejectAiPendingActionResponse, SaveMetaItemRequest, SaveMetaItemResponse, SetPresenceRequest, SetPresenceResponse, UninstallPackageRequest, UninstallPackageResponse, UnregisterDeviceRequest, UnregisterDeviceResponse, UpdateAiConversationRequest, UpdateDataRequest, UpdateDataResponse, UpdateManyDataRequest, UpdateManyDataResponse, UpdateNotificationPreferencesRequest, UpdateNotificationPreferencesResponse, ValidateDataIssue, ValidateDataRequest, ValidateDataResponse } from '@objectstack/spec/api'; // Validate data const result = AiAgentCapabilitiesSchema.parse(data); @@ -380,31 +380,6 @@ const result = AiAgentCapabilitiesSchema.parse(data); | **droppedFields** | `{ object: string; fields: string[]; reason: Enum<'readonly' \| 'readonly_when'> }[]` | optional | Write-observability (#3407/#3431/#3455): caller-supplied `readonly` fields the #3043 create-ingress strip removed before the rows were written. AGGREGATED across the batch (one event per object/reason with the union of dropped field names) rather than per-row, because the insert-time strip is static-`readonly` only — schema-uniform, so every row drops the same set. Present ONLY when ≥1 field was dropped; the creates still succeeded without them (count/success unchanged). Optional — omit-when-empty keeps the shape backward-compatible. (The per-row `insertMany`/`batch` paths carry per-row `droppedFields` on each result instead — see BatchOperationResultSchema.) | ---- - -## CreateViewRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **object** | `string` | ✅ | Object name (snake_case) | -| **data** | `{ name?: string; label?: string; object?: string; list?: object; … }` | ✅ | View definition to create | - - ---- - -## CreateViewResponse - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **object** | `string` | ✅ | Object name | -| **viewId** | `string` | ✅ | Created view identifier | -| **view** | `{ name?: string; label?: string; object?: string; list?: object; … }` | ✅ | Created view definition | - - --- ## DeleteDataRequest @@ -487,31 +462,6 @@ const result = AiAgentCapabilitiesSchema.parse(data); | **message** | `string` | optional | | ---- - -## DeleteViewRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **object** | `string` | ✅ | Object name (snake_case) | -| **viewId** | `string` | ✅ | View identifier to delete | - - ---- - -## DeleteViewResponse - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **object** | `string` | ✅ | Object name | -| **viewId** | `string` | ✅ | Deleted view identifier | -| **success** | `boolean` | ✅ | Whether deletion succeeded | - - --- ## DisablePackageRequest @@ -959,11 +909,11 @@ Get package response | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **name** | `string` | optional | Item name — supplied by the metadata door; for an object-scoped container it is the object name. | -| **label** | `string` | optional | Human-readable label shown in metadata lists. | +| **label** | `string \| Record` | optional | Human-readable label shown in metadata lists. | | **object** | `string` | optional | Object this container binds to — how a stack-level `views: [...]` entry says which object its views belong to; read by `getViewsByObject()` / `GET /meta/view?object=`. | -| **list** | `{ name?: string; label?: string; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }` | optional | | +| **list** | `{ name?: string; label?: string \| Record; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }` | optional | | | **form** | `{ type?: Enum<'simple' \| 'tabbed' \| 'wizard' \| 'split' \| 'drawer' \| 'modal'>; layout?: Enum<'vertical' \| 'horizontal' \| 'inline' \| 'grid'>; columns?: integer; title?: string; … }` | optional | | -| **listViews** | `Record; data?: object \| object \| object \| object; … }>` | optional | Additional named list views (views mode — dropdown userFilters allowed, no tabs; ADR-0047) | +| **listViews** | `Record; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }>` | optional | Additional named list views (views mode — dropdown userFilters allowed, no tabs; ADR-0047) | | **formViews** | `Record; layout?: Enum<'vertical' \| 'horizontal' \| 'inline' \| 'grid'>; columns?: integer; title?: string; … }>` | optional | Additional named form views | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this view. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | @@ -975,30 +925,6 @@ Get package response | **_lockDocsUrl** | `string` | optional | Optional documentation link surfaced next to _lockReason. | ---- - -## GetViewRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **object** | `string` | ✅ | Object name (snake_case) | -| **viewId** | `string` | ✅ | View identifier | - - ---- - -## GetViewResponse - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **object** | `string` | ✅ | Object name | -| **view** | `{ name?: string; label?: string; object?: string; list?: object; … }` | ✅ | View definition | - - --- ## HttpFindQueryParams @@ -1156,30 +1082,6 @@ List packages response | **total** | `number` | ✅ | Total package count | ---- - -## ListViewsRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **object** | `string` | ✅ | Object name (snake_case) | -| **type** | `Enum<'list' \| 'form'>` | optional | Filter by view type | - - ---- - -## ListViewsResponse - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **object** | `string` | ✅ | Object name | -| **views** | `{ name?: string; label?: string; object?: string; list?: object; … }[]` | ✅ | Array of view definitions | - - --- ## MarkAllNotificationsReadRequest @@ -1586,32 +1488,6 @@ Uninstall package response | **preferences** | `{ email: boolean; push: boolean; inApp: boolean; digest: Enum<'none' \| 'daily' \| 'weekly'>; … }` | ✅ | Updated notification preferences | ---- - -## UpdateViewRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **object** | `string` | ✅ | Object name (snake_case) | -| **viewId** | `string` | ✅ | View identifier | -| **data** | `{ name?: string; label?: string; object?: string; list?: object; … }` | ✅ | Partial view data to update | - - ---- - -## UpdateViewResponse - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **object** | `string` | ✅ | Object name | -| **viewId** | `string` | ✅ | Updated view identifier | -| **view** | `{ name?: string; label?: string; object?: string; list?: object; … }` | ✅ | Updated view definition | - - --- ## ValidateDataIssue diff --git a/content/docs/references/data/object.mdx b/content/docs/references/data/object.mdx index 77ccb1eb4a..c49c98c332 100644 --- a/content/docs/references/data/object.mdx +++ b/content/docs/references/data/object.mdx @@ -136,13 +136,13 @@ const result = ApiMethod.parse(data); | **titleFormat** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | [DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField, a composite to a formula field designated as nameField. | | **highlightFields** | `string[]` | optional | [ADR-0085] Ordered most-important fields; first entry wins where only one fits. Drives default columns, cards, previews, detail highlight strip. Renamed from compactLayout. | | **stageField** | `string \| false` | optional | [ADR-0085] Lifecycle stage field (linear/ordered), or false to declare the status field non-linear and suppress stage heuristics. Absent = heuristic detection allowed. | -| **listViews** | `Record; data?: object \| object \| object \| object; … }>` | optional | Built-in named list views (segmented tabs) shipped with the object schema — "views" mode, dropdown userFilters allowed, no page-only tabs (ADR-0047) | +| **listViews** | `Record; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }>` | optional | Built-in named list views (segmented tabs) shipped with the object schema — "views" mode, dropdown userFilters allowed, no page-only tabs (ADR-0047) | | **searchableFields** | `string[]` | optional | Fields the `$search` query matches against (ADR-0061). Canonical default for the record picker, list quick-search and global search; views may narrow it. When unset, search auto-defaults to the name/title field plus short-text fields. | | **enable** | `{ trackHistory?: boolean; searchable?: boolean; apiEnabled?: boolean; apiMethods?: Enum<'get' \| 'list' \| 'create' \| 'update' \| 'delete' \| 'bulk'>[]; … }` | optional | Enabled system features modules | | **sharingModel** | `Enum<'private' \| 'public_read' \| 'public_read_write' \| 'controlled_by_parent'>` | optional | Org-Wide Default record visibility (OWD) for INTERNAL users. Canonical four only (legacy aliases removed, ADR-0090 D4): private (owner-only) \| public_read (everyone reads, owner writes) \| public_read_write (everyone reads+writes) \| controlled_by_parent (derived from the master record). A CUSTOM object that omits this resolves to private at runtime (ADR-0090 D1). | | **externalSharingModel** | `Enum<'private' \| 'public_read' \| 'public_read_write' \| 'controlled_by_parent'>` | optional | [ADR-0090 D11] OWD for external (portal/partner) principals. Defaults to private; must be <= sharingModel in openness. | | **publicSharing** | `{ enabled?: boolean; allowedAudiences?: Enum<'public' \| 'link_only' \| 'signed_in' \| 'email'>[]; allowedPermissions?: Enum<'view' \| 'comment' \| 'edit'>[]; maxExpiryDays?: integer; … }` | optional | Public share-link policy (Notion/Figma-style link sharing) | -| **actions** | `{ name: string; label: string; objectName?: string; icon?: string; … }[]` | optional | Actions associated with this object (auto-populated from top-level actions via objectName) | +| **actions** | `{ name: string; label: string \| Record; objectName?: string; icon?: string; … }[]` | optional | Actions associated with this object (auto-populated from top-level actions via objectName) | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this object. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | | **_lockReason** | `string` | optional | Human-readable reason shown when a write is refused by _lock. | diff --git a/content/docs/references/integration/connector.mdx b/content/docs/references/integration/connector.mdx index d5db6d0fbf..2b2ccf5cea 100644 --- a/content/docs/references/integration/connector.mdx +++ b/content/docs/references/integration/connector.mdx @@ -11,10 +11,12 @@ Defines the standard connector specification for external system integration. Connectors enable ObjectStack to sync data with SaaS apps, databases, file storage, and message queues through a unified protocol. -**Positioning in the sync/integration layering** (L1 "Simple Sync" was -retired in #4738 — narrative-only, zero consumers; see -`packages/spec/docs/SYNC_ARCHITECTURE.md`): -- **ETL Pipeline** ([automation/etl.zod.ts](/docs/references/automation/etl)) - Data engineers - Aggregate 10 sources to warehouse +**Positioning in the sync/integration layering** — this file is now the ONLY +layer. Both layers above it were retired under ADR-0049 for the same measured +reason, that no engine ever executed them: L1 "Simple Sync" +(`automation/sync.zod.ts`) in #4738, and L2 "ETL Pipeline" +(`automation/etl.zod.ts`) in #6414. See +`packages/spec/docs/SYNC_ARCHITECTURE.md`: - **Enterprise Connector** (THIS FILE) - System integrators - Full SAP integration; connector-attached sync via `syncConfig` **SCOPE: Most comprehensive integration layer.** @@ -95,9 +97,11 @@ Authentication is now imported from the canonical `auth/config.zod.ts`. - Microsoft Dynamics 365 connector **When to downgrade:** -- Data transformation only → Use [ETL Pipeline](/docs/references/automation/etl) - -See also: [../automation/etl.zod.ts](/docs/references/automation/etl) for the ETL Pipeline layer (data engineering) +- Per-field value conversion on import only → the import mapping's own + `transform` (`data/mapping.zod.ts`), which the REST import path executes + row by row. (This used to point at `automation/etl.zod.ts`; L2 was retired + at #6414 for having no executor, so the pointer would have been a signpost + landing nowhere — the same defect class this header names below.) ## There is no "Trigger Registry" alternative @@ -110,9 +114,11 @@ platform's authority, at a dead end (#4499; removed alongside the #4480 per-provider template cluster). The same defect class as the `capabilities.readOnly` prescription #4487 corrected: a signpost must land somewhere enforced. Lightweight cases are served HERE — a connector instance -with simple `auth` — or by `automation/etl.zod.ts` for transformation -pipelines. (The automation-side L1 "Simple Sync" file was itself retired as -a dead end of the same class in #4738.) +with simple `auth`. (Both automation-side layers were themselves retired as +dead ends of the same class: L1 "Simple Sync" in #4738, L2 `etl.zod.ts` in +#6414. This paragraph named L2 as the transformation destination until the +second retirement; a signpost that must land somewhere enforced cannot make +an exception for itself.) **Source:** `packages/spec/src/integration/connector.zod.ts` diff --git a/content/docs/references/kernel/metadata-plugin.mdx b/content/docs/references/kernel/metadata-plugin.mdx index 8882213df7..fd6c36030e 100644 --- a/content/docs/references/kernel/metadata-plugin.mdx +++ b/content/docs/references/kernel/metadata-plugin.mdx @@ -128,7 +128,7 @@ const result = MetadataBulkResultSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **types** | `Enum<'object' \| 'field' \| 'hook' \| 'seed' \| 'mapping' \| 'view' \| 'page' \| 'dashboard' \| 'app' \| 'action' \| 'report' \| 'dataset' \| 'flow' \| 'job' \| 'datasource' \| 'external_catalog' \| 'translation' \| 'api' \| 'email_template' \| 'doc' \| 'book' \| 'permission' \| 'position' \| 'agent' \| 'tool' \| 'skill'>[]` | optional | Filter by metadata types | +| **types** | `Enum<'object' \| 'field' \| 'hook' \| 'seed' \| 'mapping' \| 'view' \| 'page' \| 'dashboard' \| 'app' \| 'action' \| 'report' \| 'dataset' \| 'flow' \| 'job' \| 'datasource' \| 'external_catalog' \| 'translation' \| 'api' \| 'email_template' \| 'doc' \| 'book' \| 'permission' \| 'position' \| 'capability' \| 'agent' \| 'tool' \| 'skill'>[]` | optional | Filter by metadata types | | **namespaces** | `string[]` | optional | Filter by namespaces | | **packageId** | `string` | optional | Filter by owning package | | **search** | `string` | optional | Full-text search query | @@ -184,6 +184,7 @@ const result = MetadataBulkResultSchema.parse(data); * `book` * `permission` * `position` +* `capability` * `agent` * `tool` * `skill` @@ -197,7 +198,7 @@ const result = MetadataBulkResultSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **type** | `Enum<'object' \| 'field' \| 'hook' \| 'seed' \| 'mapping' \| 'view' \| 'page' \| 'dashboard' \| 'app' \| 'action' \| 'report' \| 'dataset' \| 'flow' \| 'job' \| 'datasource' \| … +11 more>` | ✅ | Metadata type identifier | +| **type** | `Enum<'object' \| 'field' \| 'hook' \| 'seed' \| 'mapping' \| 'view' \| 'page' \| 'dashboard' \| 'app' \| 'action' \| 'report' \| 'dataset' \| 'flow' \| 'job' \| 'datasource' \| … +12 more>` | ✅ | Metadata type identifier | | **label** | `string` | ✅ | Display label for the metadata type | | **description** | `string` | optional | Description of the metadata type | | **filePatterns** | `string[]` | ✅ | Glob patterns to discover files of this type | @@ -208,7 +209,7 @@ const result = MetadataBulkResultSchema.parse(data); | **executionPinned** | `boolean` | optional | Transaction rows reference a specific version_hash; history GC is disabled and getByHash() MUST resolve old hashes (ADR-0009) | | **loadOrder** | `integer` | optional | Loading priority (lower = earlier) | | **domain** | `Enum<'data' \| 'ui' \| 'automation' \| 'system' \| 'security' \| 'ai'>` | ✅ | Protocol domain | -| **actions** | `{ name: string; label: string; objectName?: string; icon?: string; … }[]` | optional | Declarative type-level actions (e.g. datasource "Test connection"), reusing ActionSchema; merged with plugin-registered actions when emitted | +| **actions** | `{ name: string; label: string \| Record; objectName?: string; icon?: string; … }[]` | optional | Declarative type-level actions (e.g. datasource "Test connection"), reusing ActionSchema; merged with plugin-registered actions when emitted | ### Allowed Values: `MetadataTypeRegistryEntry.type` @@ -235,6 +236,7 @@ const result = MetadataBulkResultSchema.parse(data); * `book` * `permission` * `position` +* `capability` * `agent` * `tool` * `skill` diff --git a/content/docs/references/system/translation.mdx b/content/docs/references/system/translation.mdx index 704b8f2a15..553e8e7841 100644 --- a/content/docs/references/system/translation.mdx +++ b/content/docs/references/system/translation.mdx @@ -87,6 +87,7 @@ Translation data for a single object | **_views** | `Record` | optional | View translations keyed by view name | | **_actions** | `Record; … }>` | optional | Action translations keyed by action name | | **_sections** | `Record` | optional | Section translations keyed by section name | +| **_tabs** | `Record` | optional | Filter-preset tab translations keyed by tab name | --- diff --git a/content/docs/references/ui/action.mdx b/content/docs/references/ui/action.mdx index 07280cefdc..3bac9f7988 100644 --- a/content/docs/references/ui/action.mdx +++ b/content/docs/references/ui/action.mdx @@ -61,7 +61,7 @@ const result = ActionSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **name** | `string` | ✅ | Machine name (lowercase snake_case) | -| **label** | `string` | ✅ | Display label | +| **label** | `string \| Record` | ✅ | Display label | | **objectName** | `string` | optional | Target object this action belongs to. When set, the action is auto-merged into the object's actions array by defineStack(). | | **icon** | `string` | optional | Icon name | | **locations** | `Enum<'list_toolbar' \| 'list_item' \| 'record_header' \| 'record_more' \| 'record_related' \| 'record_section' \| 'global_nav'>[]` | optional | Locations where this action is visible | @@ -71,15 +71,15 @@ const result = ActionSchema.parse(data); | **openIn** | `Enum<'self' \| 'new-tab'>` | optional | For type:'url' — where to open `target`. 'new-tab' opens a new browser tab; 'self' navigates in place. When omitted, external/absolute URLs open in a new tab and relative URLs navigate in place. Static execution option — keep it OUT of `params` (which is user-input-collection only). | | **body** | `{ language: 'expression'; source: string } \| { language: 'js'; source: string; capabilities?: Enum<'api.read' \| 'api.write' \| 'api.transaction' \| 'crypto.uuid' \| 'log'>[]; timeoutMs?: integer; … }` | optional | Action body — expression (L1) or sandboxed JS (L2). Only used when type is `script`. | | **execute** | `never` | optional | [REMOVED] `execute` was removed in @objectstack/spec 17 (#3855) — use `target`. Rename the key; the value (a handler / flow / URL ref) is unchanged. Run `os migrate meta --from 16` to rewrite it automatically. | -| **params** | `{ name?: string; field?: string; objectOverride?: string; label?: string; … }[]` | optional | Input parameters required from user | +| **params** | `{ name?: string; field?: string; objectOverride?: string; label?: string \| Record; … }[]` | optional | Input parameters required from user | | **variant** | `Enum<'primary' \| 'secondary' \| 'danger' \| 'ghost' \| 'link'>` | optional | Button visual variant for styling (primary = highlighted, danger = destructive, ghost = transparent) | | **order** | `number` | optional | Sort order within a location group (lower = higher). Promotes/demotes an action toward the record_header primary button; stable, so actions without `order` keep their registration order. | -| **confirmText** | `string` | optional | Confirmation message before execution | -| **successMessage** | `string` | optional | Success message to show after execution | -| **errorMessage** | `string` | optional | Error message to show when the action fails (overrides the raw error). | +| **confirmText** | `string \| Record` | optional | Confirmation message before execution | +| **successMessage** | `string \| Record` | optional | Success message to show after execution | +| **errorMessage** | `string \| Record` | optional | Error message to show when the action fails (overrides the raw error). | | **refreshAfter** | `boolean` | optional | Refresh view after execution | | **undoable** | `boolean` | optional | Offer an Undo affordance after this single-record update action succeeds. | -| **resultDialog** | `{ title?: string; description?: string; acknowledge?: string; format?: Enum<'qrcode' \| 'code-list' \| 'secret' \| 'text' \| 'json'>; … }` | optional | Render API response in a one-shot reveal dialog (suppresses successMessage when set). | +| **resultDialog** | `{ title?: string \| Record; description?: string \| Record; acknowledge?: string \| Record; format?: Enum<'qrcode' \| 'code-list' \| 'secret' \| 'text' \| 'json'>; … }` | optional | Render API response in a one-shot reveal dialog (suppresses successMessage when set). | | **visible** | `boolean \| string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | Visibility predicate — `true`/`false` literal, CEL string, or `{dialect, source}` envelope. The action is offered when it evaluates TRUE. Omit = always visible. | | **requiresFeature** | `Enum<'twoFactor' \| 'passkeys' \| 'magicLink' \| 'organization' \| 'multiOrgEnabled' \| 'degradedTenancy' \| 'oidcProvider' \| 'sso' \| 'ssoEnforced' \| 'deviceAuthorization' \| … +3 more>` | optional | Public auth feature flag gating this action; lowered into `visible` at parse time. | | **disabled** | `boolean \| string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | Disabled predicate — `true`/`false` literal, CEL string, or `{dialect, source}` envelope. The action is shown but refused when it evaluates TRUE. Omit = never disabled. | @@ -95,7 +95,7 @@ const result = ActionSchema.parse(data); | **mode** | `Enum<'create' \| 'edit' \| 'delete' \| 'custom'>` | optional | Semantic mode of the action. | | **opensInNewTab** | `boolean` | optional | Open the action result in a new tab. The renderer pre-opens the tab synchronously on click (popup-blocker-safe) and navigates it to the handler's redirectUrl. | | **newTabUrl** | `string` | optional | Direct new-tab URL template (`{recordId}` placeholder). When set with opensInNewTab, the renderer navigates the pre-opened tab here immediately — no action POST. The endpoint must enforce auth itself. | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | | **_lockReason** | `string` | optional | Human-readable reason shown when a write is refused by _lock. | | **_lockSource** | `Enum<'artifact' \| 'package' \| 'env-forced'>` | optional | Layer that set _lock (artifact \| package \| env-forced). | @@ -163,10 +163,10 @@ const result = ActionSchema.parse(data); | **name** | `string` | optional | | | **field** | `string` | optional | Snake case identifier (lowercase with underscores only) | | **objectOverride** | `string` | optional | Snake case identifier (lowercase with underscores only) | -| **label** | `string` | optional | Display label (plain string; i18n keys are auto-generated by the framework) | +| **label** | `string \| Record` | optional | Display label — the default-language string, or an inline locale map (`{ en, "zh-CN" }`) resolved at render time | | **type** | `Enum<'text' \| 'textarea' \| 'email' \| 'url' \| 'phone' \| 'password' \| 'secret' \| 'markdown' \| 'html' \| 'richtext' \| 'number' \| 'currency' \| 'percent' \| 'date' \| … +35 more>` | optional | | | **required** | `boolean` | optional | | -| **options** | `{ label: string; value: string; visibleWhen?: string \| object }[]` | optional | | +| **options** | `{ label: string \| Record; value: string; visibleWhen?: string \| object }[]` | optional | | | **placeholder** | `string` | optional | | | **helpText** | `string` | optional | | | **defaultValue** | `any` | optional | | @@ -271,14 +271,14 @@ const result = ActionSchema.parse(data); | :--- | :--- | :--- | :--- | | **type** | `Enum<'script' \| 'url' \| 'modal' \| 'flow' \| 'api' \| 'form'>` | optional | Action functionality type | | **name** | `string` | optional | Machine name (lowercase snake_case) | -| **label** | `string` | optional | Display label | +| **label** | `string \| Record` | optional | Display label | | **target** | `string` | optional | URL, Script Name, Flow ID, or API Endpoint. Supports $`{param.X}` and $`{ctx.X}` interpolation. | | **openIn** | `Enum<'self' \| 'new-tab'>` | optional | For type:'url' — where to open `target`. 'new-tab' opens a new browser tab; 'self' navigates in place. When omitted, external/absolute URLs open in a new tab and relative URLs navigate in place. Static execution option — keep it OUT of `params` (which is user-input-collection only). | | **method** | `Enum<'POST' \| 'PATCH' \| 'PUT' \| 'DELETE'>` | optional | HTTP method for type:"api" actions. Defaults to POST. | -| **params** | `{ name?: string; field?: string; objectOverride?: string; label?: string; … }[]` | optional | Input parameters required from user | -| **confirmText** | `string` | optional | Confirmation message before execution | -| **successMessage** | `string` | optional | Success message to show after execution | -| **errorMessage** | `string` | optional | Error message to show when the action fails (overrides the raw error). | +| **params** | `{ name?: string; field?: string; objectOverride?: string; label?: string \| Record; … }[]` | optional | Input parameters required from user | +| **confirmText** | `string \| Record` | optional | Confirmation message before execution | +| **successMessage** | `string \| Record` | optional | Success message to show after execution | +| **errorMessage** | `string \| Record` | optional | Error message to show when the action fails (overrides the raw error). | | **refreshAfter** | `boolean` | optional | Refresh view after execution | | **opensInNewTab** | `boolean` | optional | Open the action result in a new tab. The renderer pre-opens the tab synchronously on click (popup-blocker-safe) and navigates it to the handler's redirectUrl. | diff --git a/content/docs/references/ui/app.mdx b/content/docs/references/ui/app.mdx index e8e1aa05db..c5b94429ad 100644 --- a/content/docs/references/ui/app.mdx +++ b/content/docs/references/ui/app.mdx @@ -43,7 +43,7 @@ const result = ActionNavItemSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -65,17 +65,17 @@ const result = ActionNavItemSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **name** | `string` | ✅ | App unique machine name (lowercase snake_case) | -| **label** | `string` | ✅ | App display label | +| **label** | `string \| Record` | ✅ | App display label | | **version** | `never` | optional | [REMOVED] `App.version` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — no consumer in framework or objectui). An app is versioned by its owning package: use `manifest.version`. Delete the key. | -| **description** | `string` | optional | App description | +| **description** | `string \| Record` | optional | App description | | **icon** | `string` | optional | App icon used in the App Launcher | | **branding** | `{ primaryColor?: string; accentColor?: string; logo?: string; favicon?: string }` | optional | App-specific branding | | **active** | `boolean` | optional | Whether the app is enabled | | **isDefault** | `boolean` | optional | Is default app | | **hidden** | `boolean` | optional | Hide from the App Switcher; the shell surfaces hidden apps via the avatar menu instead | -| **navigation** | `({ id: string; label: string; icon?: string; order?: number; … } \| { id: string; label: string; icon?: string; order?: number; … } \| { id: string; label: string; icon?: string; order?: number; … } \| { id: string; label: string; icon?: string; order?: number; … } \| … +5 more)[]` | optional | Full navigation tree for the app sidebar | -| **areas** | `{ id: string; label: string; icon?: string; description?: string; … }[]` | optional | Navigation areas for partitioning navigation by business domain | -| **contextSelectors** | `{ id: string; label: string; icon?: string; optionsSource: object; … }[]` | optional | App-level scope dropdowns whose value is injected into nav items as `{}` template vars | +| **navigation** | `({ id: string; label: string \| Record; icon?: string; order?: number; … } \| { id: string; label: string \| Record; icon?: string; order?: number; … } \| { id: string; label: string \| Record; icon?: string; order?: number; … } \| { id: string; label: string \| Record; icon?: string; order?: number; … } \| … +5 more)[]` | optional | Full navigation tree for the app sidebar | +| **areas** | `{ id: string; label: string \| Record; icon?: string; description?: string \| Record; … }[]` | optional | Navigation areas for partitioning navigation by business domain | +| **contextSelectors** | `{ id: string; label: string \| Record; icon?: string; optionsSource: object; … }[]` | optional | App-level scope dropdowns whose value is injected into nav items as `{}` template vars | | **homePageId** | `never` | optional | [REMOVED] `app.homePageId` was removed in @objectstack/spec 17.0.0 (#4667, #4709, ADR-0049). objectui's console did read it before v17 (`resolveLandingRoute`), so this key had a consumer — it was retired because the capability is better expressed on the navigation item itself than as an ID cross-reference that silently falls back when it dangles. An app's landing page IS its first navigation item (by `order`), and the root landing follows `isDefault` routing. Delete the key; to change where an app opens, reorder `navigation` so the intended entry is first, and set `isDefault` on the app that should own the root landing. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **requiredPermissions** | `string[]` | optional | Permissions required to access this app | | **objects** | `never` | optional | [REMOVED] `App.objects` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — never read; the spec itself labelled it "config file convenience"). Objects belong to the stack (`defineStack({ objects })`); an app reaches them through its navigation items. Delete the key. | @@ -118,7 +118,7 @@ const result = ActionNavItemSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Selector id; selected value is exposed as the nav template var `{}` | -| **label** | `string` | ✅ | Dropdown label | +| **label** | `string \| Record` | ✅ | Dropdown label | | **icon** | `string` | optional | Icon name | | **optionsSource** | `{ endpoint: string; valueKey: string; labelKey: string; filter?: object[] }` | ✅ | Option data source | | **allValue** | `string` | ✅ | Sentinel value meaning "no concrete selection yet" (empty string is almost always right) | @@ -134,7 +134,7 @@ const result = ActionNavItemSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -157,7 +157,7 @@ const result = ActionNavItemSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -179,7 +179,7 @@ const result = ActionNavItemSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -201,10 +201,10 @@ const result = ActionNavItemSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique area identifier (lowercase snake_case) | -| **label** | `string` | ✅ | Area display label | +| **label** | `string \| Record` | ✅ | Area display label | | **icon** | `string` | optional | Area icon name | -| **description** | `string` | optional | Area description | -| **navigation** | `({ id: string; label: string; icon?: string; order?: number; … } \| { id: string; label: string; icon?: string; order?: number; … } \| { id: string; label: string; icon?: string; order?: number; … } \| { id: string; label: string; icon?: string; order?: number; … } \| … +5 more)[]` | ✅ | Navigation items within this area | +| **description** | `string \| Record` | optional | Area description | +| **navigation** | `({ id: string; label: string \| Record; icon?: string; order?: number; … } \| { id: string; label: string \| Record; icon?: string; order?: number; … } \| { id: string; label: string \| Record; icon?: string; order?: number; … } \| { id: string; label: string \| Record; icon?: string; order?: number; … } \| … +5 more)[]` | ✅ | Navigation items within this area | --- @@ -220,7 +220,7 @@ A navigation contribution: a package injecting nav items into an app it does not | **app** | `string` | ✅ | Target app name to contribute navigation into (e.g. "setup") | | **group** | `string` | optional | Target group nav-item id to append into (e.g. "group_integrations"); omit to append at the app top level | | **priority** | `integer` | optional | Merge priority within the target group — lower applied first (matches object extender priority) | -| **items** | `({ id: string; label: string; icon?: string; order?: number; … } \| { id: string; label: string; icon?: string; order?: number; … } \| { id: string; label: string; icon?: string; order?: number; … } \| { id: string; label: string; icon?: string; order?: number; … } \| … +5 more)[]` | ✅ | Navigation items contributed into the target app/group | +| **items** | `({ id: string; label: string \| Record; icon?: string; order?: number; … } \| { id: string; label: string \| Record; icon?: string; order?: number; … } \| { id: string; label: string \| Record; icon?: string; order?: number; … } \| { id: string; label: string \| Record; icon?: string; order?: number; … } \| … +5 more)[]` | ✅ | Navigation items contributed into the target app/group | --- @@ -240,7 +240,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -268,7 +268,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -291,7 +291,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -315,7 +315,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -339,7 +339,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -362,7 +362,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -385,7 +385,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -423,7 +423,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -448,7 +448,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -474,7 +474,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -497,7 +497,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | @@ -519,7 +519,7 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for this navigation item (lowercase snake_case) | -| **label** | `string` | ✅ | Display proper label | +| **label** | `string \| Record` | ✅ | Display proper label | | **icon** | `string` | optional | Icon name | | **order** | `number` | optional | Sort order within the same level (lower = first) | | **badge** | `string \| number` | optional | Badge text or count displayed on the item | diff --git a/content/docs/references/ui/component.mdx b/content/docs/references/ui/component.mdx index 48db0516fe..04ca6e1ef5 100644 --- a/content/docs/references/ui/component.mdx +++ b/content/docs/references/ui/component.mdx @@ -32,7 +32,7 @@ const result = AIChatWindowProps.parse(data); | **mode** | `Enum<'float' \| 'sidebar' \| 'inline'>` | ✅ | Display mode for the chat window | | **agentId** | `string` | optional | Specific AI agent to use | | **context** | `Record` | optional | Contextual data to pass to the AI | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -43,14 +43,14 @@ const result = AIChatWindowProps.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **label** | `string` | ✅ | Button display label | +| **label** | `string \| Record` | ✅ | Button display label | | **variant** | `Enum<'primary' \| 'secondary' \| 'danger' \| 'ghost' \| 'link'>` | optional | Button visual variant | | **size** | `Enum<'small' \| 'medium' \| 'large'>` | optional | Button size | | **icon** | `string` | optional | Icon name (Lucide icon) | | **iconPosition** | `Enum<'left' \| 'right'>` | optional | Icon position relative to label | | **disabled** | `boolean` | optional | Disable the button | -| **action** | `{ type?: Enum<'script' \| 'url' \| 'modal' \| 'flow' \| 'api' \| 'form'>; name?: string; label?: string; target?: string; … }` | optional | Inline action executed on click | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **action** | `{ type?: Enum<'script' \| 'url' \| 'modal' \| 'flow' \| 'api' \| 'form'>; name?: string; label?: string \| Record; target?: string; … }` | optional | Inline action executed on click | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -66,7 +66,7 @@ const result = AIChatWindowProps.parse(data); | **targetVariable** | `string` | optional | Page variable to store filter state | | **layout** | `Enum<'inline' \| 'dropdown' \| 'sidebar'>` | ✅ | Filter display layout | | **showSearch** | `boolean` | ✅ | Show search input | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -80,9 +80,9 @@ const result = AIChatWindowProps.parse(data); | **object** | `string` | ✅ | Object for the form | | **fields** | `string[]` | optional | Fields to display (defaults to all editable fields) | | **mode** | `Enum<'create' \| 'edit'>` | optional | Form mode | -| **submitLabel** | `string` | optional | Submit button label | +| **submitLabel** | `string \| Record` | optional | Submit button label | | **onSubmit** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | Action expression on form submit (CEL) | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -97,7 +97,7 @@ const result = AIChatWindowProps.parse(data); | **alt** | `string` | optional | Alt text for accessibility | | **fit** | `Enum<'cover' \| 'contain' \| 'fill'>` | ✅ | Image object-fit mode | | **height** | `number` | optional | Fixed height in pixels | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -113,7 +113,7 @@ const result = AIChatWindowProps.parse(data); | **object** | `string` | optional | Owning object — required for object-scoped kinds: state_machine is a rule ON an object (ADR-0020), permission renders a matrix FOR one; omit for top-level flow | | **mode** | `Enum<'diagram' \| 'matrix' \| 'summary'>` | optional | Render form; defaults per type (diagram for flow/state_machine, matrix for permission) | | **detail** | `Enum<'business' \| 'technical'>` | ✅ | Authoring altitude (ADR-0051 §3.4): business collapses technical flow nodes to business steps + approvals. NOT access (cf. book.audience); permission projection is automatic and render-time, never set here | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -131,7 +131,7 @@ const result = AIChatWindowProps.parse(data); | **format** | `Enum<'number' \| 'currency' \| 'percent'>` | optional | Number display format | | **prefix** | `string` | optional | Prefix text (e.g. "$") | | **suffix** | `string` | optional | Suffix text (e.g. "%") | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -145,15 +145,15 @@ const result = AIChatWindowProps.parse(data); | **object** | `string` | ✅ | Object to pick records from | | **labelField** | `string` | optional | Field rendered as each row's text (default `name`) | | **valueField** | `string` | optional | Field whose value is written into the bound page variable (default `id`) | -| **label** | `string` | optional | Control label rendered above the select | +| **label** | `string \| Record` | optional | Control label rendered above the select | | **filter** | `any` | optional | Filter criteria for available records | | **targetVariable** | `string` | optional | Page variable to bind selected record ID(s) | -| **placeholder** | `string` | optional | Placeholder text | -| **emptyText** | `string` | optional | Text shown when the query returns no records (default "No records") | +| **placeholder** | `string \| Record` | optional | Placeholder text | +| **emptyText** | `string \| Record` | optional | Text shown when the query returns no records (default "No records") | | **displayField** | `never` | optional | [REMOVED] `element:record_picker` property `displayField` was removed in @objectstack/spec 17.0.0 (#5775, ADR-0087 D2) — it was a required declaration no renderer ever read, while the renderer honoured `labelField` for the same thing and defaulted to `name`. Rename the key to `labelField`; the value (a field name) is unchanged. Run `os migrate meta --from 16` to rewrite it automatically. | | **searchFields** | `never` | optional | [REMOVED] `element:record_picker` property `searchFields` was removed in @objectstack/spec 17.0.0 (#5775, ADR-0049) — the picker renders a plain single-select with no search input, so no renderer ever read it and it narrowed nothing. Delete the key. To restrict which records the picker offers, use `filter` (or the component-level `dataSource.filter`), which the query path does apply. Run `os migrate meta --from 16` to remove it automatically. | | **multiple** | `never` | optional | [REMOVED] `element:record_picker` property `multiple` was removed in @objectstack/spec 17.0.0 (#5775, ADR-0049) — the picker is a single-select `Select` and the bound page variable holds one record id, so `multiple: true` selected nothing extra and reported success. Delete the key; multi-record selection is not implemented on this element. Run `os migrate meta --from 16` to remove it automatically. | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -165,14 +165,14 @@ const result = AIChatWindowProps.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **inputType** | `Enum<'text' \| 'email' \| 'number' \| 'tel' \| 'url' \| 'password'>` | ✅ | Native input type — drives keyboard/validation affordance and how the bound value is coerced (number → numeric). | -| **label** | `string` | optional | Field label shown above the input | -| **placeholder** | `string` | optional | Placeholder text shown when empty | +| **label** | `string \| Record` | optional | Field label shown above the input | +| **placeholder** | `string \| Record` | optional | Placeholder text shown when empty | | **defaultValue** | `string \| number` | optional | Initial value; seeds the bound page variable on mount | | **required** | `boolean` | ✅ | Mark the field as required | | **disabled** | `boolean` | ✅ | Disable the input | -| **description** | `string` | optional | Helper text shown below the input | +| **description** | `string \| Record` | optional | Helper text shown below the input | | **targetVariable** | `string` | optional | Page variable this input writes to. Declarative hint; the live binding resolves via the variable whose `source` equals this component id (see PageVariableSchema). | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -183,10 +183,10 @@ const result = AIChatWindowProps.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **content** | `string` | ✅ | Text or Markdown content | +| **content** | `string \| Record` | ✅ | Text or Markdown content — a plain string, or an inline locale map | | **variant** | `Enum<'heading' \| 'subheading' \| 'body' \| 'caption'>` | ✅ | Text style variant | | **align** | `Enum<'left' \| 'center' \| 'right'>` | ✅ | Text alignment | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -197,9 +197,9 @@ const result = AIChatWindowProps.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **items** | `{ label: string; icon?: string; collapsed: boolean; children: any[] }[]` | ✅ | | +| **items** | `{ label: string \| Record; icon?: string; collapsed: boolean; children: any[] }[]` | ✅ | | | **allowMultiple** | `boolean` | ✅ | Allow multiple panels to be expanded simultaneously | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -210,13 +210,13 @@ const result = AIChatWindowProps.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **title** | `string` | optional | Display label (plain string; i18n keys are auto-generated by the framework) | +| **title** | `string \| Record` | optional | Display label — the default-language string, or an inline locale map (`{ en, "zh-CN" }`) resolved at render time | | **bordered** | `boolean` | ✅ | | | **actions** | `string[]` | optional | | | **children** | `any[]` | optional | Card content components, in order (the card body slot) | | **body** | `never` | optional | [REMOVED] `page:card` property `body` was removed in @objectstack/spec 17.0.0 (#5775, ADR-0087 D2) — it was a second spelling of the composition slot every other container calls `children`, and the renderer reads both. Rename the key to `children`; the value (an array of child components) is unchanged. Run `os migrate meta --from 16` to rewrite it automatically. | | **footer** | `any[]` | optional | Card footer components (slot) | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -238,12 +238,12 @@ const result = AIChatWindowProps.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **title** | `string` | ✅ | Page title | -| **subtitle** | `string` | optional | Page subtitle | +| **title** | `string \| Record` | ✅ | Page title | +| **subtitle** | `string \| Record` | optional | Page subtitle | | **icon** | `string` | optional | Icon name | | **breadcrumb** | `boolean` | ✅ | Show breadcrumb | | **actions** | `string[]` | optional | Action IDs to show in header | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -256,8 +256,8 @@ const result = AIChatWindowProps.parse(data); | :--- | :--- | :--- | :--- | | **type** | `Enum<'line' \| 'card' \| 'pill'>` | optional | | | **position** | `Enum<'top' \| 'left'>` | optional | | -| **items** | `{ label: string; icon?: string; visibleWhen?: string \| object; value?: string; … }[]` | ✅ | | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **items** | `{ label: string \| Record; icon?: string; visibleWhen?: string \| object; value?: string; … }[]` | ✅ | | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -279,7 +279,7 @@ const result = AIChatWindowProps.parse(data); | **enableReactions** | `boolean` | ✅ | Enable emoji reactions on feed items | | **enableThreading** | `boolean` | ✅ | Enable threaded replies on comments | | **showSubscriptionToggle** | `boolean` | ✅ | Show bell icon for record-level notification subscription | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -295,7 +295,7 @@ const result = AIChatWindowProps.parse(data); | **collapsible** | `boolean` | ✅ | Whether the panel can be collapsed | | **defaultCollapsed** | `boolean` | ✅ | Whether the panel starts collapsed | | **feed** | `{ types?: Enum<'comment' \| 'field_change' \| 'task' \| 'event' \| 'email' \| 'call' \| 'note' \| … +6 more>[]; filterMode: Enum<'all' \| 'comments_only' \| 'changes_only' \| 'tasks_only'>; showFilterToggle: boolean; limit: integer; … }` | optional | Embedded activity feed configuration | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -308,10 +308,10 @@ const result = AIChatWindowProps.parse(data); | :--- | :--- | :--- | :--- | | **columns** | `Enum<'1' \| '2' \| '3' \| '4'>` | ✅ | Number of columns for field layout (1-4) | | **layout** | `Enum<'auto' \| 'custom'>` | ✅ | Layout mode: auto uses object highlightFields, custom uses explicit sections | -| **sections** | `{ name?: string; label?: string; columns?: integer; fields: string[] }[]` | optional | Field groups rendered as the detail body, in order. Object form: `{ name?, label?, columns?, fields }`. | +| **sections** | `{ name?: string; label?: string \| Record; columns?: integer; fields: string[] }[]` | optional | Field groups rendered as the detail body, in order. Object form: `{ name?, label?, columns?, fields }`. | | **fields** | `string[]` | optional | Explicit field list to display (optional, overrides highlightFields) | | **hideFields** | `string[]` | optional | Field names to omit from the body — applied to `fields` and to every section's `fields` (used to dedupe fields already shown in `record:highlights` or as the page title) | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -355,7 +355,7 @@ Type: `string` | :--- | :--- | :--- | :--- | | **fields** | `(string \| { name: string; label?: string; icon?: string; type?: string; … })[]` | ✅ | Key fields to highlight (1-7 fields max, typically displayed as prominent cards). Each item may be a bare field name or `{name, label?, icon?, type?, readonly?}` for inline overrides. | | **layout** | `Enum<'horizontal' \| 'vertical'>` | ✅ | Layout orientation for highlight fields | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -367,8 +367,8 @@ Type: `string` | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **statusField** | `string` | ✅ | Field name representing the current status/stage | -| **stages** | `{ value: string; label: string; terminal?: Enum<'won' \| 'lost'> }[]` | optional | Explicit stage definitions (if not using field metadata) | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **stages** | `{ value: string; label: string \| Record; terminal?: Enum<'won' \| 'lost'> }[]` | optional | Explicit stage definitions (if not using field metadata) | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -386,11 +386,11 @@ Type: `string` | **sort** | `string \| { field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | Sort order for related records | | **limit** | `integer` | ✅ | Number of records to display initially | | **filter** | `{ field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'starts_with' \| … +14 more>; value?: string \| number \| boolean \| null \| (string \| number)[] }[]` | optional | Additional filter criteria for related records | -| **title** | `string` | optional | Custom title for the related list | +| **title** | `string \| Record` | optional | Custom title for the related list | | **showViewAll** | `boolean` | ✅ | Show "View All" link to see all related records | | **actions** | `string[]` | optional | Action IDs available for related records | -| **add** | `{ picker: object; linkField?: string; label?: string }` | optional | Add-existing-via-picker config (generic m2m/junction assignment). | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **add** | `{ picker: object; linkField?: string; label?: string \| Record }` | optional | Add-existing-via-picker config (generic m2m/junction assignment). | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- diff --git a/content/docs/references/ui/dashboard.mdx b/content/docs/references/ui/dashboard.mdx index 5d72cf3b46..0844861eb8 100644 --- a/content/docs/references/ui/dashboard.mdx +++ b/content/docs/references/ui/dashboard.mdx @@ -30,15 +30,15 @@ const result = DashboardSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **name** | `string` | ✅ | Dashboard unique name | -| **label** | `string` | ✅ | Dashboard label | -| **description** | `string` | optional | Dashboard description | +| **label** | `string \| Record` | ✅ | Dashboard label | +| **description** | `string \| Record` | optional | Dashboard description | | **header** | `{ showTitle: boolean; showDescription: boolean; actions?: object[] }` | optional | Dashboard header configuration | -| **widgets** | `{ id: string; title?: string; description?: string; type: Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| … +13 more>; … }[]` | ✅ | Widgets to display | +| **widgets** | `{ id: string; title?: string \| Record; description?: string \| Record; type: Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| … +13 more>; … }[]` | ✅ | Widgets to display | | **columns** | `integer` | optional | Number of grid columns (default 12) | | **gap** | `integer` | optional | Grid gap in Tailwind spacing units | | **refreshInterval** | `number` | optional | Auto-refresh interval in seconds | | **dateRange** | `{ field?: string; defaultRange: Enum<'today' \| 'yesterday' \| 'this_week' \| 'last_week' \| 'this_month' \| 'last_month' \| … +8 more>; allowCustomRange: boolean }` | optional | Global dashboard date range filter configuration | -| **globalFilters** | `{ name?: string; field: string; label?: string; type?: Enum<'text' \| 'select' \| 'date' \| 'number' \| 'lookup'>; … }[]` | optional | Global filters that apply to all widgets in the dashboard | +| **globalFilters** | `{ name?: string; field: string; label?: string \| Record; type?: Enum<'text' \| 'select' \| 'date' \| 'number' \| 'lookup'>; … }[]` | optional | Global filters that apply to all widgets in the dashboard | | **aria** | `never` | optional | [REMOVED] `dashboard.aria` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no dashboard renderer ever applied it, so declared ARIA attributes silently did not reach the DOM. Delete the key. | | **performance** | `never` | optional | [REMOVED] `dashboard.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; dashboard performance tuning was never implemented. Delete the key. | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this dashboard. | @@ -63,7 +63,7 @@ Dashboard header configuration | :--- | :--- | :--- | :--- | | **showTitle** | `boolean` | ✅ | Show dashboard title in header | | **showDescription** | `boolean` | ✅ | Show dashboard description in header | -| **actions** | `{ label: string; actionUrl: string; actionType?: Enum<'script' \| 'url' \| 'modal' \| 'flow' \| 'api' \| 'form'>; icon?: string }[]` | optional | Header action buttons | +| **actions** | `{ label: string \| Record; actionUrl: string; actionType?: Enum<'script' \| 'url' \| 'modal' \| 'flow' \| 'api' \| 'form'>; icon?: string }[]` | optional | Header action buttons | --- @@ -76,7 +76,7 @@ Dashboard header action | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **label** | `string` | ✅ | Action button label | +| **label** | `string \| Record` | ✅ | Action button label | | **actionUrl** | `string` | ✅ | URL or target for the action | | **actionType** | `Enum<'script' \| 'url' \| 'modal' \| 'flow' \| 'api' \| 'form'>` | optional | Type of action | | **icon** | `string` | optional | Icon identifier for the action button | @@ -91,10 +91,10 @@ Dashboard header action | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique widget identifier (snake_case) | -| **title** | `string` | optional | Widget title | -| **description** | `string` | optional | Widget description text below the header | +| **title** | `string \| Record` | optional | Widget title | +| **description** | `string \| Record` | optional | Widget description text below the header | | **type** | `Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| 'funnel' \| 'scatter' \| 'treemap' \| 'sankey' \| 'combo' \| 'gauge' \| 'solid-gauge' \| … +6 more>` | ✅ | Visualization type | -| **chartConfig** | `{ type: Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| … +13 more>; title?: string; subtitle?: string; description?: string; … }` | optional | Chart visualization configuration | +| **chartConfig** | `{ type: Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| … +13 more>; title?: string \| Record; subtitle?: string \| Record; description?: string \| Record; … }` | optional | Chart visualization configuration | | **colorVariant** | `Enum<'default' \| 'blue' \| 'teal' \| 'orange' \| 'purple' \| 'success' \| 'warning' \| 'danger'>` | optional | Widget color variant for theming | | **requiresObject** | `string` | optional | Hide the widget unless the named object is registered | | **requiresService** | `string` | optional | Hide the widget unless the named kernel service is registered | @@ -164,9 +164,9 @@ Widget configuration — declared query keys + open renderer extras | :--- | :--- | :--- | :--- | | **name** | `string` | optional | Stable filter name (variable key); defaults to field | | **field** | `string` | ✅ | Field name to filter on | -| **label** | `string` | optional | Display label for the filter | +| **label** | `string \| Record` | optional | Display label for the filter | | **type** | `Enum<'text' \| 'select' \| 'date' \| 'number' \| 'lookup'>` | optional | Filter input type | -| **options** | `{ value: string \| number \| boolean; label: string }[]` | optional | Static filter options | +| **options** | `{ value: string \| number \| boolean; label: string \| Record }[]` | optional | Static filter options | | **optionsFrom** | `{ object: string; valueField: string; labelField: string; filter?: any }` | optional | Dynamic filter options from object | | **defaultValue** | `string \| number \| boolean` | optional | Default filter value | | **scope** | `Enum<'dashboard' \| 'widget'>` | ✅ | Filter application scope | diff --git a/content/docs/references/ui/page.mdx b/content/docs/references/ui/page.mdx index b4fb239761..a41db28292 100644 --- a/content/docs/references/ui/page.mdx +++ b/content/docs/references/ui/page.mdx @@ -48,7 +48,7 @@ Interface-level page configuration (Airtable parity) | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **source** | `string` | optional | Source object name for the page | -| **columns** | `string[] \| { field: string; label?: string; width?: number; align?: Enum<'left' \| 'center' \| 'right'>; … }[]` | optional | Columns shown by the page. Blank = all object fields. Defined directly on the page (no view inheritance). | +| **columns** | `string[] \| { field: string; label?: string \| Record; width?: number; align?: Enum<'left' \| 'center' \| 'right'>; … }[]` | optional | Columns shown by the page. Blank = all object fields. Defined directly on the page (no view inheritance). | | **sort** | `{ field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | Default sort order for the page, defined directly on the page. | | **filterBy** | `{ field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'starts_with' \| … +14 more>; value?: string \| number \| boolean \| null \| (string \| number)[] }[]` | optional | Always-on page filter (base filter). | | **levels** | `integer` | optional | Number of hierarchy levels to display | @@ -72,8 +72,8 @@ Interface-level page configuration (Airtable parity) | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **name** | `string` | ✅ | Page unique name (lowercase snake_case) | -| **label** | `string` | ✅ | Display label (plain string; i18n keys are auto-generated by the framework) | -| **description** | `string` | optional | Display label (plain string; i18n keys are auto-generated by the framework) | +| **label** | `string \| Record` | ✅ | Display label — the default-language string, or an inline locale map (`{ en, "zh-CN" }`) resolved at render time | +| **description** | `string \| Record` | optional | Display label — the default-language string, or an inline locale map (`{ en, "zh-CN" }`) resolved at render time | | **icon** | `string` | optional | Page icon name | | **type** | `Enum<'record' \| 'home' \| 'app' \| 'utility' \| 'list'>` | optional | Page type | | **variables** | `{ name: string; type?: Enum<'string' \| 'number' \| 'boolean' \| 'object' \| 'array' \| 'record_id'>; defaultValue?: any; source?: string }[]` | optional | Local page state, exposed to expressions as `page.` and writable by interactive elements via `source` (master/detail, filtered dashboards). | @@ -83,7 +83,7 @@ Interface-level page configuration (Airtable parity) | **isDefault** | `boolean` | optional | | | **assignedProfiles** | `string[]` | optional | | | **interfaceConfig** | `{ source?: string; columns?: string[] \| object[]; sort?: object[]; filterBy?: object[]; … }` | optional | Interface-level page configuration (for Airtable-style interface pages) | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | | **kind** | `Enum<'full' \| 'slotted' \| 'html' \| 'react' \| 'jsx'>` | optional | Page override mode. full \| slotted = structured authoring; html = author-written constrained JSX/HTML+Tailwind compiled (parsed, never executed) to the tree (ADR-0080; the legacy value 'jsx' is a deprecated alias); react = real-React source executed at render by the runtime (ADR-0081); it runs author JS, so it is gated by a host capability that defaults ON and is disabled server-side via the OS_PAGE_REACT=off env toggle. | | **slots** | `{ header?: object \| object[]; actions?: object \| object[]; alerts?: object \| object[]; highlights?: object \| object[]; … }` | optional | Slot override map for slotted pages | | **source** | `string` | optional | Page source text. For kind==='html' (alias 'jsx') it is constrained JSX/HTML+Tailwind compiled to the tree by @objectstack/sdui-parser at save time (parse, never execute). For kind==='react' it is real React/JSX executed at render by @object-ui/react-runtime (trusted tier). Authoritative over `regions` in both. | @@ -107,7 +107,7 @@ Interface-level page configuration (Airtable parity) | :--- | :--- | :--- | :--- | | **type** | `Enum<'page:header' \| 'page:footer' \| 'page:sidebar' \| 'page:tabs' \| 'page:accordion' \| 'page:card' \| 'page:section' \| 'record:details' \| 'record:highlights' \| 'record:related_list' \| 'record:activity' \| 'record:chatter' \| 'record:path' \| 'record:alert' \| 'record:quick_actions' \| 'record:reference_rail' \| 'record:history' \| 'app:launcher' \| 'nav:menu' \| 'nav:breadcrumb' \| 'global:search' \| 'global:notifications' \| 'user:profile' \| 'ai:chat_window' \| 'ai:suggestion' \| 'element:text' \| 'element:number' \| 'element:image' \| 'element:divider' \| 'element:button' \| 'element:filter' \| 'element:form' \| 'element:record_picker' \| 'element:text_input'> \| string` | ✅ | Component Type (Standard enum or custom string) | | **id** | `string` | optional | Unique instance ID | -| **label** | `string` | optional | Display label (plain string; i18n keys are auto-generated by the framework) | +| **label** | `string \| Record` | optional | Display label — the default-language string, or an inline locale map (`{ en, "zh-CN" }`) resolved at render time | | **properties** | `Record` | optional | Component props passed to the widget. See component.zod.ts for schemas. | | **events** | `Record` | optional | Event handlers map | | **style** | `Record` | optional | Inline styles or utility classes | @@ -117,7 +117,7 @@ Interface-level page configuration (Airtable parity) | **visibility** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | [DEPRECATED → `visibleWhen`] Visibility predicate (CEL). Normalized to `visibleWhen` at parse. | | **dataSource** | `{ object: string; view?: string; filter?: any; sort?: object[]; … }` | optional | Per-element data binding for multi-object pages | | **responsive** | `{ breakpoint?: Enum<'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'>; hiddenOn?: Enum<'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'>[]; columns?: object; order?: object }` | optional | Responsive layout configuration | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | --- @@ -172,7 +172,7 @@ Interface-level page configuration (Airtable parity) | :--- | :--- | :--- | :--- | | **name** | `string` | ✅ | Region name (e.g. "sidebar", "main", "header") | | **width** | `Enum<'small' \| 'medium' \| 'large' \| 'full'>` | optional | | -| **components** | `{ type: Enum<'page:header' \| 'page:footer' \| 'page:sidebar' \| 'page:tabs' \| 'page:accordion' \| … +29 more> \| string; id?: string; label?: string; properties?: Record; … }[]` | ✅ | Components in this region | +| **components** | `{ type: Enum<'page:header' \| 'page:footer' \| 'page:sidebar' \| 'page:tabs' \| 'page:accordion' \| … +29 more> \| string; id?: string; label?: string \| Record; properties?: Record; … }[]` | ✅ | Components in this region | --- diff --git a/content/docs/references/ui/view.mdx b/content/docs/references/ui/view.mdx index 3e729aa4a3..59b1c39d14 100644 --- a/content/docs/references/ui/view.mdx +++ b/content/docs/references/ui/view.mdx @@ -124,7 +124,7 @@ Column footer summary configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **show** | `boolean` | optional | Whether the button is rendered (renderer default applies when omitted) | -| **label** | `string` | optional | Button label (i18n-capable; renderer default when omitted) | +| **label** | `string \| Record` | optional | Button label (i18n-capable; renderer default when omitted) | --- @@ -146,9 +146,9 @@ Column footer summary configuration | **precision** | `number` | optional | Total digits (for number/currency) | | **scale** | `number` | optional | Decimal places | | **multiple** | `boolean` | optional | Allow multiple values (for select/lookup/file/image) | -| **label** | `string` | optional | Display label override | -| **placeholder** | `string` | optional | Placeholder text | -| **helpText** | `string` | optional | Help/hint text | +| **label** | `string \| Record` | optional | Display label override | +| **placeholder** | `string \| Record` | optional | Placeholder text | +| **helpText** | `string \| Record` | optional | Help/hint text | | **readonly** | `boolean` | optional | Read-only override | | **immutable** | `boolean` | optional | Editable on create, locked once the record exists (e.g. machine names). | | **required** | `boolean` | optional | Required override | @@ -157,7 +157,7 @@ Column footer summary configuration | **span** | `Enum<'auto' \| 'full'>` | optional | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count (wide widgets like textarea/richtext/json/file/subform take the whole row). 'full': whole row at any column count. Prefer this over the absolute `colSpan`. | | **widget** | `string` | optional | Custom widget/component name (overrides type-based inference) | | **language** | `string` | optional | Code editor language (for type=code) | -| **keyField** | `{ field?: string; label?: string; placeholder?: string; helpText?: string; … }` | optional | Key column config for record-typed fields | +| **keyField** | `{ field?: string; label?: string \| Record; placeholder?: string \| Record; helpText?: string \| Record; … }` | optional | Key column config for record-typed fields | | **dependsOn** | `string` | optional | Parent field name for cascading | | **visibleWhen** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | Visibility predicate (CEL) — field shown only when TRUE. Root: `record` (+ `previous`, `parent`) in runtime forms, or `data` in metadata forms. No `current_user` at field level — it is unbound here and the predicate would fault open (per-option `visibleWhen` is the surface that binds it). Inside a repeater `data` is the ROW, but it is still spelled `data` — a bare identifier is unbound and faults open too. e.g. P`record.priority == 'urgent'` | | **visibleOn** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | [DEPRECATED → `visibleWhen`] Visibility predicate (CEL). Normalized to `visibleWhen` at parse. | @@ -226,7 +226,7 @@ Column footer summary configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **name** | `string` | optional | Stable section identifier for i18n lookup (snake_case) | -| **label** | `string` | optional | Display label (plain string; i18n keys are auto-generated by the framework) | +| **label** | `string \| Record` | optional | Display label — the default-language string, or an inline locale map (`{ en, "zh-CN" }`) resolved at render time | | **description** | `string` | optional | Optional description rendered under the section header. | | **collapsible** | `boolean` | optional | | | **collapsed** | `boolean` | optional | | @@ -261,8 +261,8 @@ Column footer summary configuration | **drawerWidth** | `string` | optional | [DEPRECATED → size buckets] Drawer width, e.g. "480px". A pixel width cannot be chosen without knowing the client viewport — the renderer derives it. | | **modalSize** | `Enum<'sm' \| 'default' \| 'lg' \| 'xl' \| 'full'>` | optional | Modal size (modal forms) | | **data** | `{ provider: 'object'; object: string } \| { provider: 'api'; read?: object; write?: object } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record }` | optional | Data source configuration (defaults to "object" provider) | -| **sections** | `{ name?: string; label?: string; description?: string; collapsible?: boolean; … }[]` | optional | | -| **groups** | `{ name?: string; label?: string; description?: string; collapsible?: boolean; … }[]` | optional | | +| **sections** | `{ name?: string; label?: string \| Record; description?: string; collapsible?: boolean; … }[]` | optional | | +| **groups** | `{ name?: string; label?: string \| Record; description?: string; collapsible?: boolean; … }[]` | optional | | | **subforms** | `{ childObject: string; relationshipField?: string; columns?: any[]; amountField?: string; … }[]` | optional | Inline master-detail child collections | | **defaultSort** | `never` | optional | [REMOVED] `form.defaultSort` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — nothing read it: a related list inside a form sorts by its own list view's `sort`. Delete the key and set the sort on the related list view instead. | | **sharing** | `{ enabled?: boolean; publicLink?: string; password?: string; allowedDomains?: string[]; … }` | optional | Public sharing configuration for this form | @@ -424,7 +424,7 @@ List chart view configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **field** | `string` | ✅ | Field name (snake_case) | -| **label** | `string` | optional | Display label override | +| **label** | `string \| Record` | optional | Display label override | | **width** | `number` | optional | Column width in pixels | | **align** | `Enum<'left' \| 'center' \| 'right'>` | optional | Text alignment | | **hidden** | `boolean` | optional | Hide column by default | @@ -448,10 +448,10 @@ List chart view configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **name** | `string` | optional | Internal view name (lowercase snake_case) | -| **label** | `string` | optional | Display label (plain string; i18n keys are auto-generated by the framework) | +| **label** | `string \| Record` | optional | Display label — the default-language string, or an inline locale map (`{ en, "zh-CN" }`) resolved at render time | | **type** | `Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>` | optional | | | **data** | `{ provider: 'object'; object: string } \| { provider: 'api'; read?: object; write?: object } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record }` | optional | Data source configuration (defaults to "object" provider) | -| **columns** | `string[] \| { field: string; label?: string; width?: number; align?: Enum<'left' \| 'center' \| 'right'>; … }[]` | ✅ | Fields to display as columns | +| **columns** | `string[] \| { field: string; label?: string \| Record; width?: number; align?: Enum<'left' \| 'center' \| 'right'>; … }[]` | ✅ | Fields to display as columns | | **filter** | `{ field: string; operator?: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'starts_with' \| … +14 more>; value?: string \| number \| boolean \| null \| (string \| number)[] }[]` | optional | Filter criteria (JSON Rules) | | **sort** | `string \| { field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | | | **searchableFields** | `string[]` | optional | Fields enabled for search | @@ -471,7 +471,7 @@ List chart view configuration | **timeline** | `{ startDateField: string; endDateField?: string; titleField: string; groupByField?: string; … }` | optional | Timeline view configuration | | **chart** | `{ chartType?: Enum<'bar' \| 'line' \| 'pie' \| 'area' \| 'scatter'>; dataset: string; dimensions?: string[]; values: string[] }` | optional | List chart view configuration | | **tree** | `{ parentField?: string; labelField?: string; fields?: string[]; defaultExpandedDepth?: integer } & Record` | optional | Tree/hierarchy configuration — applies when the view renders as a tree layout | -| **description** | `string` | optional | View description for documentation/tooltips | +| **description** | `string \| Record` | optional | View description for documentation/tooltips | | **sharing** | `{ type?: Enum<'personal' \| 'collaborative'>; lockedBy?: string }` | optional | View sharing and access configuration | | **rowHeight** | `Enum<'compact' \| 'short' \| 'medium' \| 'tall' \| 'extra_tall'>` | optional | Row height / density setting | | **grouping** | `{ fields: object[] }` | optional | Group records by one or more fields | @@ -487,12 +487,12 @@ List chart view configuration | **exportOptions** | `Enum<'csv' \| 'xlsx' \| 'pdf' \| 'json'>[]` | optional | Available export format options | | **userActions** | `{ sort?: boolean; search?: boolean; filter?: boolean; refresh?: boolean; … }` | optional | User action toggles for the view toolbar | | **appearance** | `{ showDescription?: boolean; allowedVisualizations?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>[] }` | optional | Appearance and visualization configuration | -| **tabs** | `{ name: string; label?: string; icon?: string; view?: string; … }[]` | optional | Tab definitions for multi-tab view interface | +| **tabs** | `{ name: string; label?: string \| Record; icon?: string; view?: string; … }[]` | optional | Tab definitions for multi-tab view interface | | **addRecord** | `{ enabled?: boolean; position?: Enum<'top' \| 'bottom' \| 'both'>; mode?: Enum<'inline' \| 'form' \| 'modal'>; formView?: string }` | optional | Add record entry point configuration | | **showRecordCount** | `boolean` | optional | Show record count at the bottom of the list | | **allowPrinting** | `boolean` | optional | Allow users to print the view | -| **emptyState** | `{ title?: string; message?: string; icon?: string }` | optional | Empty state configuration when no records found | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes for the list view | +| **emptyState** | `{ title?: string \| Record; message?: string \| Record; icon?: string }` | optional | Empty state configuration when no records found | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes for the list view | | **responsive** | `never` | optional | [REMOVED] `view.responsive` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer ever read it; the grid is responsive by its own layout rules. Delete the key. | | **performance** | `never` | optional | [REMOVED] `view.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; list-view performance tuning was never implemented. Delete the key. | @@ -537,10 +537,10 @@ List chart view configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **name** | `string` | optional | Internal view name (lowercase snake_case) | -| **label** | `string` | optional | Display label (plain string; i18n keys are auto-generated by the framework) | +| **label** | `string \| Record` | optional | Display label — the default-language string, or an inline locale map (`{ en, "zh-CN" }`) resolved at render time | | **type** | `Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>` | optional | | | **data** | `{ provider: 'object'; object: string } \| { provider: 'api'; read?: object; write?: object } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record }` | optional | Data source configuration (defaults to "object" provider) | -| **columns** | `string[] \| { field: string; label?: string; width?: number; align?: Enum<'left' \| 'center' \| 'right'>; … }[]` | ✅ | Fields to display as columns | +| **columns** | `string[] \| { field: string; label?: string \| Record; width?: number; align?: Enum<'left' \| 'center' \| 'right'>; … }[]` | ✅ | Fields to display as columns | | **filter** | `{ field: string; operator?: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'starts_with' \| … +14 more>; value?: string \| number \| boolean \| null \| (string \| number)[] }[]` | optional | Filter criteria (JSON Rules) | | **sort** | `string \| { field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | | | **searchableFields** | `string[]` | optional | Fields enabled for search | @@ -559,7 +559,7 @@ List chart view configuration | **timeline** | `{ startDateField: string; endDateField?: string; titleField: string; groupByField?: string; … }` | optional | Timeline view configuration | | **chart** | `{ chartType?: Enum<'bar' \| 'line' \| 'pie' \| 'area' \| 'scatter'>; dataset: string; dimensions?: string[]; values: string[] }` | optional | List chart view configuration | | **tree** | `{ parentField?: string; labelField?: string; fields?: string[]; defaultExpandedDepth?: integer } & Record` | optional | Tree/hierarchy configuration — applies when the view renders as a tree layout | -| **description** | `string` | optional | View description for documentation/tooltips | +| **description** | `string \| Record` | optional | View description for documentation/tooltips | | **sharing** | `{ type?: Enum<'personal' \| 'collaborative'>; lockedBy?: string }` | optional | View sharing and access configuration | | **rowHeight** | `Enum<'compact' \| 'short' \| 'medium' \| 'tall' \| 'extra_tall'>` | optional | Row height / density setting | | **grouping** | `{ fields: object[] }` | optional | Group records by one or more fields | @@ -575,12 +575,12 @@ List chart view configuration | **exportOptions** | `Enum<'csv' \| 'xlsx' \| 'pdf' \| 'json'>[]` | optional | Available export format options | | **userActions** | `{ sort?: boolean; search?: boolean; filter?: boolean; refresh?: boolean; … }` | optional | User action toggles for the view toolbar | | **appearance** | `{ showDescription?: boolean; allowedVisualizations?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>[] }` | optional | Appearance and visualization configuration | -| **tabs** | `{ name: string; label?: string; icon?: string; view?: string; … }[]` | optional | Tab definitions for multi-tab view interface | +| **tabs** | `{ name: string; label?: string \| Record; icon?: string; view?: string; … }[]` | optional | Tab definitions for multi-tab view interface | | **addRecord** | `{ enabled?: boolean; position?: Enum<'top' \| 'bottom' \| 'both'>; mode?: Enum<'inline' \| 'form' \| 'modal'>; formView?: string }` | optional | Add record entry point configuration | | **showRecordCount** | `boolean` | optional | Show record count at the bottom of the list | | **allowPrinting** | `boolean` | optional | Allow users to print the view | -| **emptyState** | `{ title?: string; message?: string; icon?: string }` | optional | Empty state configuration when no records found | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes for the list view | +| **emptyState** | `{ title?: string \| Record; message?: string \| Record; icon?: string }` | optional | Empty state configuration when no records found | +| **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes for the list view | | **responsive** | `never` | optional | [REMOVED] `view.responsive` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer ever read it; the grid is responsive by its own layout rules. Delete the key. | | **performance** | `never` | optional | [REMOVED] `view.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; list-view performance tuning was never implemented. Delete the key. | | **userFilters** | `{ element?: Enum<'dropdown' \| 'toggle'>; fields?: object[] }` | optional | | @@ -595,7 +595,7 @@ List chart view configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **element** | `Enum<'dropdown' \| 'toggle'>` | ✅ | Filter control style on object views: "dropdown" (per-field value chips). "toggle" is deprecated. "tabs" is page-only — use `listViews` for named presets. | -| **fields** | `{ field: string; label?: string; type?: Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>; options?: object[]; … }[]` | optional | Fields exposed as quick filters (dropdown/toggle elements) | +| **fields** | `{ field: string; label?: string \| Record; type?: Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>; options?: object[]; … }[]` | optional | Fields exposed as quick filters (dropdown/toggle elements) | --- @@ -713,9 +713,9 @@ Quick-filter field configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **field** | `string` | ✅ | Field name on the source object (must exist — checked by reference diagnostics) | -| **label** | `string` | optional | Display label override (defaults to the field label) | +| **label** | `string \| Record` | optional | Display label override (defaults to the field label) | | **type** | `Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>` | optional | Filter control type. Omit to infer from the field definition | -| **options** | `{ value: string \| number \| boolean; label: string; color?: string }[]` | optional | Static options. Omit to derive from the field definition (select options / lookup records) | +| **options** | `{ value: string \| number \| boolean; label: string \| Record; color?: string }[]` | optional | Static options. Omit to derive from the field definition (select options / lookup records) | | **showCount** | `boolean` | optional | Show per-option record counts | | **defaultValues** | `(string \| number \| boolean)[]` | optional | Pre-selected values when the view loads | @@ -731,8 +731,8 @@ End-user quick-filter configuration (Airtable "User filters" parity) | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **element** | `Enum<'dropdown' \| 'tabs' \| 'toggle'>` | ✅ | Filter control style: "dropdown" (per-field value selectors) or "tabs" (named presets). "toggle" is deprecated. | -| **fields** | `{ field: string; label?: string; type?: Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>; options?: object[]; … }[]` | optional | Fields exposed as quick filters (dropdown/toggle elements) | -| **tabs** | `{ name: string; label?: string; icon?: string; view?: string; … }[]` | optional | Named filter presets rendered as tabs (tabs element). Reuses ViewTabSchema | +| **fields** | `{ field: string; label?: string \| Record; type?: Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>; options?: object[]; … }[]` | optional | Fields exposed as quick filters (dropdown/toggle elements) | +| **tabs** | `{ name: string; label?: string \| Record; icon?: string; view?: string; … }[]` | optional | Named filter presets rendered as tabs (tabs element). Reuses ViewTabSchema | | **showAllRecords** | `boolean` | optional | Show an "All records" tab before the presets (tabs element) | | **allowAddTab** | `boolean` | optional | Render an "add tab" affordance after the presets (tabs element). Page lists only — object views use `listViews` for named presets | @@ -746,11 +746,11 @@ End-user quick-filter configuration (Airtable "User filters" parity) | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **name** | `string` | optional | Item name — supplied by the metadata door; for an object-scoped container it is the object name. | -| **label** | `string` | optional | Human-readable label shown in metadata lists. | +| **label** | `string \| Record` | optional | Human-readable label shown in metadata lists. | | **object** | `string` | optional | Object this container binds to — how a stack-level `views: [...]` entry says which object its views belong to; read by `getViewsByObject()` / `GET /meta/view?object=`. | -| **list** | `{ name?: string; label?: string; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }` | optional | | +| **list** | `{ name?: string; label?: string \| Record; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }` | optional | | | **form** | `{ type?: Enum<'simple' \| 'tabbed' \| 'wizard' \| 'split' \| 'drawer' \| 'modal'>; layout?: Enum<'vertical' \| 'horizontal' \| 'inline' \| 'grid'>; columns?: integer; title?: string; … }` | optional | | -| **listViews** | `Record; data?: object \| object \| object \| object; … }>` | optional | Additional named list views (views mode — dropdown userFilters allowed, no tabs; ADR-0047) | +| **listViews** | `Record; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }>` | optional | Additional named list views (views mode — dropdown userFilters allowed, no tabs; ADR-0047) | | **formViews** | `Record; layout?: Enum<'vertical' \| 'horizontal' \| 'inline' \| 'grid'>; columns?: integer; title?: string; … }>` | optional | Additional named form views | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this view. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | @@ -869,10 +869,10 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **viewKind** | `'list'` | ✅ | | -| **config** | `{ name?: string; label?: string; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }` | ✅ | List-family view configuration. | +| **config** | `{ name?: string; label?: string \| Record; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }` | ✅ | List-family view configuration. | | **name** | `string` | ✅ | Globally-unique view id, `.`. | | **object** | `string` | ✅ | Bound object name — the foreign key used to aggregate views. | -| **label** | `string` | optional | Display label (supports i18n). | +| **label** | `string \| Record` | optional | Display label (supports i18n). | | **isDefault** | `boolean` | optional | Whether this is the object's default view in the switcher. | | **order** | `integer` | optional | Sort order within the object's view switcher / left rail. | | **scope** | `Enum<'package' \| 'shared' \| 'personal'>` | optional | Identity layer (defaults to `package` for source-loaded views). | @@ -899,7 +899,7 @@ This schema accepts one of the following structures: | **config** | `{ type?: Enum<'simple' \| 'tabbed' \| 'wizard' \| 'split' \| 'drawer' \| 'modal'>; layout?: Enum<'vertical' \| 'horizontal' \| 'inline' \| 'grid'>; columns?: integer; title?: string; … }` | ✅ | Form view configuration. | | **name** | `string` | ✅ | Globally-unique view id, `.`. | | **object** | `string` | ✅ | Bound object name — the foreign key used to aggregate views. | -| **label** | `string` | optional | Display label (supports i18n). | +| **label** | `string \| Record` | optional | Display label (supports i18n). | | **isDefault** | `boolean` | optional | Whether this is the object's default view in the switcher. | | **order** | `integer` | optional | Sort order within the object's view switcher / left rail. | | **scope** | `Enum<'package' \| 'shared' \| 'personal'>` | optional | Identity layer (defaults to `package` for source-loaded views). | @@ -935,10 +935,10 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **viewKind** | `'list'` | ✅ | | -| **config** | `{ name?: string; label?: string; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }` | ✅ | List-family view configuration. | +| **config** | `{ name?: string; label?: string \| Record; type?: Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>; data?: object \| object \| object \| object; … }` | ✅ | List-family view configuration. | | **name** | `string` | ✅ | Globally-unique view id, `.`. | | **object** | `string` | ✅ | Bound object name — the foreign key used to aggregate views. | -| **label** | `string` | optional | Display label (supports i18n). | +| **label** | `string \| Record` | optional | Display label (supports i18n). | | **isDefault** | `boolean` | optional | Whether this is the object's default view in the switcher. | | **order** | `integer` | optional | Sort order within the object's view switcher / left rail. | | **scope** | `Enum<'package' \| 'shared' \| 'personal'>` | optional | Identity layer (defaults to `package` for source-loaded views). | @@ -967,7 +967,7 @@ This schema accepts one of the following structures: | **config** | `{ type?: Enum<'simple' \| 'tabbed' \| 'wizard' \| 'split' \| 'drawer' \| 'modal'>; layout?: Enum<'vertical' \| 'horizontal' \| 'inline' \| 'grid'>; columns?: integer; title?: string; … }` | ✅ | Form view configuration. | | **name** | `string` | ✅ | Globally-unique view id, `.`. | | **object** | `string` | ✅ | Bound object name — the foreign key used to aggregate views. | -| **label** | `string` | optional | Display label (supports i18n). | +| **label** | `string \| Record` | optional | Display label (supports i18n). | | **isDefault** | `boolean` | optional | Whether this is the object's default view in the switcher. | | **order** | `integer` | optional | Sort order within the object's view switcher / left rail. | | **scope** | `Enum<'package' \| 'shared' \| 'personal'>` | optional | Identity layer (defaults to `package` for source-loaded views). | @@ -1037,7 +1037,7 @@ Tab configuration for multi-tab view interface | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **name** | `string` | ✅ | Tab identifier (snake_case) | -| **label** | `string` | optional | Display label | +| **label** | `string \| Record` | optional | Display label | | **icon** | `string` | optional | Tab icon name | | **view** | `string` | optional | Referenced list view name from listViews | | **filter** | `{ field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'starts_with' \| … +14 more>; value?: string \| number \| boolean \| null \| (string \| number)[] }[]` | optional | Tab-specific filter criteria |