diff --git a/content/docs/references/ai/agent.mdx b/content/docs/references/ai/agent.mdx index 7d260dfcd07..7c12cc50f36 100644 --- a/content/docs/references/ai/agent.mdx +++ b/content/docs/references/ai/agent.mdx @@ -48,7 +48,7 @@ const result = AIModelConfigSchema.parse(data); | **avatar** | `string` | optional | | | **role** | `string` | ✅ | The persona/role (e.g. "Senior Support Engineer") | | **instructions** | `string` | ✅ | System Prompt / Prime Directives | -| **model** | `{ provider: Enum<'openai' \| 'azure_openai' \| 'anthropic' \| 'local'>; model: string; temperature: number; maxTokens?: number; … }` | optional | | +| **model** | `{ provider?: Enum<'openai' \| 'azure_openai' \| 'anthropic' \| 'local'>; model: string; temperature?: number; maxTokens?: number; … }` | optional | | | **lifecycle** | `never` | optional | [REMOVED] `agent.lifecycle` was removed in @objectstack/spec 17.7.0 (ADR-0049 enforce-or-remove) — no runtime ever read it: no agent moved through a declared state and no transition was ever refused. Delete the key. A phase of a conversation is a skill with its own `instructions` and `tools`, selected by its `triggerConditions` (ADR-0064); multi-step process orchestration is a Flow (ADR-0019); a record's status transitions are a `state_machine` validation rule on the object (ADR-0020). Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | | **surface** | `Enum<'ask' \| 'build'>` | optional (default: `"ask"`) | Product surface this agent binds ('ask' \| 'build') — ADR-0063 §1 | | **skills** | `string[]` | optional | Skill names to attach (Agent→Skill→Tool architecture) | @@ -57,10 +57,10 @@ const result = AIModelConfigSchema.parse(data); | **active** | `boolean` | optional (default: `true`) | | | **access** | `string[]` | optional | Who can chat with this agent | | **permissions** | `string[]` | optional | Required permission-set capabilities | -| **planning** | `{ maxIterations: integer }` | optional | Autonomous reasoning and planning configuration | +| **planning** | `{ maxIterations?: integer }` | optional | Autonomous reasoning and planning configuration | | **memory** | `{ longTerm?: object; reflectionInterval?: integer }` | optional | Agent memory (long-term notes recalled before each conversation and written by periodic reflection), enforced by the cloud AI runtime; the open framework edition does not run agents. | | **guardrails** | `{ maxTokensPerInvocation?: integer; maxExecutionTimeSec?: integer; blockedTopics?: string[] }` | optional | Safety guardrails for the agent (token budget, time limit, blocked topics), enforced per user turn by the cloud AI runtime; the open framework edition does not run agents. | -| **structuredOutput** | `{ format: Enum<'json_object' \| 'json_schema'>; schema?: Record; strict: boolean; retryOnValidationFailure: boolean; … }` | optional | Structured output contract for the agent's final answer (JSON format, schema, retries, fallback format, transform steps), enforced on every final answer by the cloud AI runtime; the open framework edition does not run agents. | +| **structuredOutput** | `{ format: Enum<'json_object' \| 'json_schema'>; schema?: Record; strict?: boolean; retryOnValidationFailure?: boolean; … }` | optional | Structured output contract for the agent's final answer (JSON format, schema, retries, fallback format, transform steps), enforced on every final answer by the cloud AI runtime; the open framework edition does not run agents. | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this agent. | | **_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. | @@ -90,7 +90,7 @@ const result = AIModelConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **longTerm** | `{ enabled: boolean; maxEntries?: integer }` | optional | Long-term memory: distilled notes kept per user and agent and recalled before each conversation | +| **longTerm** | `{ enabled?: boolean; maxEntries?: integer }` | optional | Long-term memory: distilled notes kept per user and agent and recalled before each conversation | | **reflectionInterval** | `integer` | optional | Reflect every N delivered interactions: each reflection writes one distilled note to long-term memory. Required when longTerm.enabled is true, and refused without it | ### Nested Shape: `Agent.guardrails` diff --git a/content/docs/references/ai/conversation.mdx b/content/docs/references/ai/conversation.mdx index b58d2c0785e..dd06ec89a67 100644 --- a/content/docs/references/ai/conversation.mdx +++ b/content/docs/references/ai/conversation.mdx @@ -94,9 +94,9 @@ const result = CodeContentSchema.parse(data); | **id** | `string` | ✅ | Unique message ID | | **timestamp** | `string` | ✅ | ISO 8601 timestamp | | **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 })[]` | ✅ | Message content (multimodal array) | +| **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 })[]` | ✅ | Message content (multimodal array) | | **functionCall** | `{ name: string; arguments: string; result?: string }` | optional | Legacy function call | -| **toolCalls** | `{ id: string; type: Enum<'function'>; function: object }[]` | optional | Tool calls | +| **toolCalls** | `{ id: string; type?: Enum<'function'>; function: object }[]` | optional | Tool calls | | **toolCallId** | `string` | optional | Tool call ID this message responds to | | **name** | `string` | optional | Name of the function/user | | **tokens** | `{ promptTokens: integer; completionTokens: integer; totalTokens: integer }` | optional | Token usage for this message | @@ -179,9 +179,9 @@ const result = CodeContentSchema.parse(data); | **name** | `string` | optional | Session name/title | | **context** | `{ sessionId: string; userId?: string; agentId?: string; object?: string; … }` | ✅ | | | **modelId** | `string` | optional | AI model ID | -| **tokenBudget** | `{ maxTokens: integer; maxPromptTokens?: integer; maxCompletionTokens?: integer; reserveTokens: integer; … }` | ✅ | | +| **tokenBudget** | `{ maxTokens: integer; maxPromptTokens?: integer; maxCompletionTokens?: integer; reserveTokens?: integer; … }` | ✅ | | | **messages** | `{ id: string; timestamp: string; role: Enum<'system' \| 'user' \| 'assistant' \| 'function' \| 'tool'>; content: (object \| … +3 more)[]; … }[]` | optional (default: `[]`) | | -| **tokens** | `{ promptTokens: integer; completionTokens: integer; totalTokens: integer; budgetLimit: integer; … }` | optional | | +| **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 | | **status** | `Enum<'active' \| 'paused' \| 'completed' \| 'archived'>` | optional (default: `"active"`) | | @@ -228,9 +228,9 @@ const result = CodeContentSchema.parse(data); | **id** | `string` | ✅ | Unique message ID | | **timestamp** | `string` | ✅ | ISO 8601 timestamp | | **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 })[]` | ✅ | Message content (multimodal array) | +| **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 })[]` | ✅ | Message content (multimodal array) | | **functionCall** | `{ name: string; arguments: string; result?: string }` | optional | Legacy function call | -| **toolCalls** | `{ id: string; type: Enum<'function'>; function: object }[]` | optional | Tool calls | +| **toolCalls** | `{ id: string; type?: Enum<'function'>; function: object }[]` | optional | Tool calls | | **toolCallId** | `string` | optional | Tool call ID this message responds to | | **name** | `string` | optional | Name of the function/user | | **tokens** | `{ promptTokens: integer; completionTokens: integer; totalTokens: integer }` | optional | Token usage for this message | diff --git a/content/docs/references/ai/model-registry.mdx b/content/docs/references/ai/model-registry.mdx index d2540a94b9b..c6e5746dc79 100644 --- a/content/docs/references/ai/model-registry.mdx +++ b/content/docs/references/ai/model-registry.mdx @@ -54,9 +54,9 @@ const result = ModelCapabilitySchema.parse(data); | **name** | `string` | ✅ | Model display name | | **version** | `string` | ✅ | Model version (e.g., "gpt-4-turbo-2024-04-09") | | **provider** | `Enum<'openai' \| 'azure_openai' \| 'anthropic' \| 'google' \| 'cohere' \| 'huggingface' \| 'local' \| 'custom'>` | ✅ | | -| **capabilities** | `{ textGeneration: boolean; textEmbedding: boolean; imageGeneration: boolean; imageUnderstanding: boolean; … }` | ✅ | | +| **capabilities** | `{ textGeneration?: boolean; textEmbedding?: boolean; imageGeneration?: boolean; imageUnderstanding?: boolean; … }` | ✅ | | | **limits** | `{ maxTokens: integer; contextWindow: integer; maxOutputTokens?: integer; rateLimit?: object }` | ✅ | | -| **pricing** | `{ currency: string; inputCostPer1kTokens?: number; outputCostPer1kTokens?: number; embeddingCostPer1kTokens?: number }` | optional | | +| **pricing** | `{ currency?: string; inputCostPer1kTokens?: number; outputCostPer1kTokens?: number; embeddingCostPer1kTokens?: number }` | optional | | | **endpoint** | `string` | optional | Custom API endpoint | | **apiKey** | `string` | optional | API key (Warning: Prefer secretRef) | | **secretRef** | `string` | optional | Reference to stored secret (e.g. system:openai_api_key) | @@ -202,7 +202,7 @@ const result = ModelCapabilitySchema.parse(data); | **status** | `Enum<'active' \| 'deprecated' \| 'experimental' \| 'disabled'>` | optional (default: `"active"`) | | | **priority** | `integer` | optional (default: `0`) | Priority for model selection | | **fallbackModels** | `string[]` | optional | Fallback model IDs | -| **healthCheck** | `{ enabled: boolean; intervalSeconds: integer; lastChecked?: string; status: Enum<'healthy' \| 'unhealthy' \| 'unknown'> }` | optional | | +| **healthCheck** | `{ enabled?: boolean; intervalSeconds?: integer; lastChecked?: string; status?: Enum<'healthy' \| 'unhealthy' \| 'unknown'> }` | optional | | ### Nested Shape: `ModelRegistryEntry.model` @@ -212,9 +212,9 @@ const result = ModelCapabilitySchema.parse(data); | **name** | `string` | ✅ | Model display name | | **version** | `string` | ✅ | Model version (e.g., "gpt-4-turbo-2024-04-09") | | **provider** | `Enum<'openai' \| 'azure_openai' \| 'anthropic' \| 'google' \| 'cohere' \| 'huggingface' \| 'local' \| 'custom'>` | ✅ | | -| **capabilities** | `{ textGeneration: boolean; textEmbedding: boolean; imageGeneration: boolean; imageUnderstanding: boolean; … }` | ✅ | | +| **capabilities** | `{ textGeneration?: boolean; textEmbedding?: boolean; imageGeneration?: boolean; imageUnderstanding?: boolean; … }` | ✅ | | | **limits** | `{ maxTokens: integer; contextWindow: integer; maxOutputTokens?: integer; rateLimit?: object }` | ✅ | | -| **pricing** | `{ currency: string; inputCostPer1kTokens?: number; outputCostPer1kTokens?: number; embeddingCostPer1kTokens?: number }` | optional | | +| **pricing** | `{ currency?: string; inputCostPer1kTokens?: number; outputCostPer1kTokens?: number; embeddingCostPer1kTokens?: number }` | optional | | | **endpoint** | `string` | optional | Custom API endpoint | | **apiKey** | `string` | optional | API key (Warning: Prefer secretRef) | | **secretRef** | `string` | optional | Reference to stored secret (e.g. system:openai_api_key) | diff --git a/content/docs/references/ai/solution-blueprint.mdx b/content/docs/references/ai/solution-blueprint.mdx index fbd373fe5f5..f3c2a34bba9 100644 --- a/content/docs/references/ai/solution-blueprint.mdx +++ b/content/docs/references/ai/solution-blueprint.mdx @@ -45,7 +45,7 @@ const result = BlueprintAppSchema.parse(data); | **name** | `string` | ✅ | App machine name (snake_case) | | **label** | `string` | optional | App display label | | **icon** | `string` | optional | Lucide icon for the App Launcher | -| **nav** | `{ type: Enum<'object' \| 'dashboard'>; target: string; label?: string; icon?: string; … }[]` | optional | Navigation entries; omit to auto-surface every created object and dashboard | +| **nav** | `{ type?: Enum<'object' \| 'dashboard'>; target: string; label?: string; icon?: string; … }[]` | optional | Navigation entries; omit to auto-surface every created object and dashboard | ### Nested Shape: `BlueprintApp.nav[number]` @@ -298,7 +298,7 @@ const result = BlueprintAppSchema.parse(data); | **assumptions** | `string[]` | optional (default: `[]`) | 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: object[]; … }[]` | ✅ | Objects (tables) to create | -| **views** | `{ object: string; name: string; label?: string; type: Enum<'list' \| 'form' \| 'kanban' \| 'calendar' \| 'gallery' \| 'gantt'>; … }[]` | optional | Views 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?: 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) | @@ -340,7 +340,7 @@ const result = BlueprintAppSchema.parse(data); | **name** | `string` | ✅ | App machine name (snake_case) | | **label** | `string` | optional | App display label | | **icon** | `string` | optional | Lucide icon for the App Launcher | -| **nav** | `{ type: Enum<'object' \| 'dashboard'>; target: string; label?: string; icon?: string; … }[]` | optional | Navigation entries; omit to auto-surface every created object and dashboard | +| **nav** | `{ type?: Enum<'object' \| 'dashboard'>; target: string; label?: string; icon?: string; … }[]` | optional | Navigation entries; omit to auto-surface every created object and dashboard | ### Nested Shape: `SolutionBlueprint.seedData[number]` diff --git a/content/docs/references/api/auth-endpoints.mdx b/content/docs/references/api/auth-endpoints.mdx index f0e77ba4937..0e2c32070b2 100644 --- a/content/docs/references/api/auth-endpoints.mdx +++ b/content/docs/references/api/auth-endpoints.mdx @@ -156,8 +156,8 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **emailPassword** | `{ enabled: boolean; disableSignUp?: boolean; requireEmailVerification?: boolean }` | ✅ | Email/password authentication config | -| **socialProviders** | `{ id: string; name: string; enabled: boolean; type: Enum<'social' \| 'oidc'> }[]` | ✅ | Available social/OAuth providers | -| **features** | `{ twoFactor: boolean; organization: boolean; ssoEnforced?: boolean; phoneNumber?: boolean; … }` | ✅ | Enabled authentication features | +| **socialProviders** | `{ id: string; name: string; enabled: boolean; type?: Enum<'social' \| 'oidc'> }[]` | ✅ | Available social/OAuth providers | +| **features** | `{ twoFactor?: boolean; organization?: boolean; ssoEnforced?: boolean; phoneNumber?: boolean; … }` | ✅ | Enabled authentication features | ### Nested Shape: `GetAuthConfigResponse.emailPassword` diff --git a/content/docs/references/api/auth.mdx b/content/docs/references/api/auth.mdx index c9b7f3e424e..fc1ff171330 100644 --- a/content/docs/references/api/auth.mdx +++ b/content/docs/references/api/auth.mdx @@ -150,7 +150,7 @@ const result = AuthProvider.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **session** | `{ id: string; expiresAt: string; token?: string; ipAddress?: string; … }` | ✅ | Active Session Info | -| **user** | `{ id: string; email: string; emailVerified: boolean; name: string; … }` | ✅ | Current User Details | +| **user** | `{ id: string; email: string; emailVerified?: boolean; name: string; … }` | ✅ | Current User Details | | **token** | `string` | optional | Bearer token if not using cookies | @@ -187,7 +187,7 @@ const result = AuthProvider.parse(data); | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| …>; declaredCode?: string; message: string; userMessage?: string; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ id: string; email: string; emailVerified: boolean; name: string; … }` | ✅ | | +| **data** | `{ id: string; email: string; emailVerified?: boolean; name: string; … }` | ✅ | | ### Nested Shape: `UserProfileResponse.error` diff --git a/content/docs/references/api/batch.mdx b/content/docs/references/api/batch.mdx index f4255532e8b..a560df5d36a 100644 --- a/content/docs/references/api/batch.mdx +++ b/content/docs/references/api/batch.mdx @@ -43,7 +43,7 @@ const result = BatchConfigSchema.parse(data); | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | optional (default: `true`) | Enable batch operations | | **maxRecordsPerBatch** | `integer` | optional (default: `200`) | Maximum records per batch | -| **defaultOptions** | `{ atomic: boolean; returnRecords: boolean; continueOnError: boolean }` | optional | Default batch options | +| **defaultOptions** | `{ atomic?: boolean; returnRecords?: boolean; continueOnError?: boolean }` | optional | Default batch options | ### Nested Shape: `BatchConfig.defaultOptions` @@ -144,7 +144,7 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | :--- | :--- | :--- | :--- | | **operation** | `Enum<'create' \| 'update' \| 'upsert' \| 'delete'>` | ✅ | Type of batch operation | | **records** | `{ id?: string; data?: Record; externalId?: string }[]` | ✅ | Array of records to process (server caps the count — see batch.maxBatchSize) | -| **options** | `{ atomic: boolean; returnRecords: boolean; continueOnError: boolean }` | optional | Batch operation options | +| **options** | `{ atomic?: boolean; returnRecords?: boolean; continueOnError?: boolean }` | optional | Batch operation options | ### Nested Shape: `BatchUpdateRequest.records[number]` @@ -254,7 +254,7 @@ A cross-object batch strip event: dropped fields plus the operation index | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **operations** | `{ object: string; action: Enum<'create' \| 'update' \| 'delete'>; id?: string; data?: Record }[]` | ✅ | Ordered operations executed in one transaction | +| **operations** | `{ object: string; action?: Enum<'create' \| 'update' \| 'delete'>; id?: string; data?: Record }[]` | ✅ | Ordered operations executed in one transaction | | **atomic** | `boolean` | optional (default: `true`) | Always true — the cross-object batch is all-or-nothing | ### Nested Shape: `CrossObjectBatchRequest.operations[number]` @@ -299,7 +299,7 @@ A cross-object batch strip event: dropped fields plus the operation index | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **ids** | `string[]` | ✅ | Array of record IDs to delete (server caps the count — see batch.maxBatchSize) | -| **options** | `{ atomic: boolean; returnRecords: boolean; continueOnError: boolean }` | optional | Delete options | +| **options** | `{ atomic?: boolean; returnRecords?: boolean; continueOnError?: boolean }` | optional | Delete options | ### Nested Shape: `DeleteManyRequest.options` @@ -332,7 +332,7 @@ A cross-object batch strip event: dropped fields plus the operation index | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **records** | `{ id: string; data: Record }[]` | ✅ | Array of records to update (server caps the count — see batch.maxBatchSize) | -| **options** | `{ atomic: boolean; returnRecords: boolean; continueOnError: boolean }` | optional | Update options | +| **options** | `{ atomic?: boolean; returnRecords?: boolean; continueOnError?: boolean }` | optional | Update options | ### Nested Shape: `UpdateManyRequest.records[number]` diff --git a/content/docs/references/api/contract.mdx b/content/docs/references/api/contract.mdx index 7c05cfac3a8..9438412b1e2 100644 --- a/content/docs/references/api/contract.mdx +++ b/content/docs/references/api/contract.mdx @@ -555,9 +555,9 @@ const result = ApiErrorSchema.parse(data); | **object** | `string` | ✅ | Object name (e.g. account) | | **fields** | `string[]` | optional | Fields to retrieve — names of the queried object's OWN columns. A dotted path (`owner.name`) is not a projection: no driver resolves one, and the ingress refuses it with `400 INVALID_FIELD`. Related data is read with `expand`, whose nested QueryAST both filters (`where`) and selects (`fields`) the related record's columns. The projection must RETAIN the foreign-key column: `fields: ['title']` with `expand: 'project_id'` resolves nothing, because the relation is carried by that key — add `'project_id'` and it works. Where the value is wanted on the queried object itself, denormalise it onto that object (a stored field, written when the source changes), the same remedy the sort axis prescribes. | | **where** | `any` | optional | Filtering criteria (WHERE) | -| **search** | `string \| { query: string; fields?: string[]; fuzzy: boolean; operator: Enum<'and' \| 'or'>; … }` | optional | Full-text search — the query text (canonical, ADR-0061 D1), or a structured FullTextSearch configuration | +| **search** | `string \| { query: string; fields?: string[]; fuzzy?: boolean; operator?: Enum<'and' \| 'or'>; … }` | optional | Full-text search — the query text (canonical, ADR-0061 D1), or a structured FullTextSearch configuration | | **searchFields** | `string[]` | optional | Narrow the search to these fields (server-intersected with the allowed searchable set — can only narrow, never widen; ADR-0061 D1) | -| **orderBy** | `{ field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | Sorting instructions (ORDER BY) | +| **orderBy** | `{ field: string; order?: Enum<'asc' \| 'desc'> }[]` | optional | Sorting instructions (ORDER BY) | | **limit** | `number` | optional | Max records to return (LIMIT) | | **offset** | `number` | optional | Records to skip (OFFSET) | | **top** | `number` | optional | Alias for limit (OData compatibility) | @@ -608,9 +608,9 @@ const result = ApiErrorSchema.parse(data); | **object** | `string` | ✅ | Object name (e.g. account) | | **fields** | `string[]` | optional | Fields to retrieve — names of the queried object's OWN columns. A dotted path (`owner.name`) is not a projection: no driver resolves one, and the ingress refuses it with `400 INVALID_FIELD`. Related data is read with `expand`, whose nested QueryAST both filters (`where`) and selects (`fields`) the related record's columns. The projection must RETAIN the foreign-key column: `fields: ['title']` with `expand: 'project_id'` resolves nothing, because the relation is carried by that key — add `'project_id'` and it works. Where the value is wanted on the queried object itself, denormalise it onto that object (a stored field, written when the source changes), the same remedy the sort axis prescribes. | | **where** | `any` | optional | Filtering criteria (WHERE) | -| **search** | `string \| { query: string; fields?: string[]; fuzzy: boolean; operator: Enum<'and' \| 'or'>; … }` | optional | Full-text search — the query text (canonical, ADR-0061 D1), or a structured FullTextSearch configuration | +| **search** | `string \| { query: string; fields?: string[]; fuzzy?: boolean; operator?: Enum<'and' \| 'or'>; … }` | optional | Full-text search — the query text (canonical, ADR-0061 D1), or a structured FullTextSearch configuration | | **searchFields** | `string[]` | optional | Narrow the search to these fields (server-intersected with the allowed searchable set — can only narrow, never widen; ADR-0061 D1) | -| **orderBy** | `{ field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | Sorting instructions (ORDER BY) | +| **orderBy** | `{ field: string; order?: Enum<'asc' \| 'desc'> }[]` | optional | Sorting instructions (ORDER BY) | | **limit** | `number` | optional | Max records to return (LIMIT) | | **offset** | `number` | optional | Records to skip (OFFSET) | | **top** | `number` | optional | Alias for limit (OData compatibility) | @@ -722,8 +722,8 @@ const result = ApiErrorSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **preventNPlusOne** | `boolean` | ✅ | Enable N+1 query detection and prevention | -| **dataLoader** | `{ maxBatchSize: integer; batchScheduleFn: Enum<'microtask' \| 'timeout' \| 'manual'>; cacheEnabled: boolean; cacheKeyFn?: string; … }` | optional | DataLoader batch loading configuration | -| **batchStrategy** | `{ strategy: Enum<'dataloader' \| 'windowed' \| 'prefetch'>; windowMs?: number; prefetchDepth?: integer; associationLoading: Enum<'lazy' \| 'eager' \| 'batch'> }` | optional | Batch loading strategy configuration | +| **dataLoader** | `{ maxBatchSize?: integer; batchScheduleFn?: Enum<'microtask' \| 'timeout' \| 'manual'>; cacheEnabled?: boolean; cacheKeyFn?: string; … }` | optional | DataLoader batch loading configuration | +| **batchStrategy** | `{ strategy: Enum<'dataloader' \| 'windowed' \| 'prefetch'>; windowMs?: number; prefetchDepth?: integer; associationLoading?: Enum<'lazy' \| 'eager' \| 'batch'> }` | optional | Batch loading strategy configuration | | **maxQueryDepth** | `integer` | ✅ | Maximum depth for nested relation queries | | **queryComplexityLimit** | `number` | optional | Maximum allowed query complexity score | | **enableQueryPlan** | `boolean` | optional (default: `false`) | Log query execution plans for debugging | diff --git a/content/docs/references/api/dispatcher.mdx b/content/docs/references/api/dispatcher.mdx index 0d4dd2bfed2..39b5281a0c0 100644 --- a/content/docs/references/api/dispatcher.mdx +++ b/content/docs/references/api/dispatcher.mdx @@ -49,7 +49,7 @@ const result = DispatcherConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **routes** | `{ prefix: string; service: Enum<'metadata' \| 'data' \| 'auth' \| 'storage' \| 'file-storage' \| 'search' \| 'cache' \| …>; authRequired: boolean; criticality: Enum<'required' \| 'core' \| 'optional'>; … }[]` | ✅ | Route-to-service mappings | +| **routes** | `{ prefix: string; service: Enum<'metadata' \| 'data' \| 'auth' \| 'storage' \| 'file-storage' \| 'search' \| 'cache' \| …>; authRequired?: boolean; criticality?: Enum<'required' \| 'core' \| 'optional'>; … }[]` | ✅ | Route-to-service mappings | | **fallback** | `Enum<'404' \| 'proxy' \| 'custom'>` | optional (default: `"404"`) | Behavior when no route matches | | **proxyTarget** | `string` | optional | Proxy target URL when fallback is "proxy" | diff --git a/content/docs/references/api/documentation.mdx b/content/docs/references/api/documentation.mdx index be6ed8a03e6..2ecf7386c39 100644 --- a/content/docs/references/api/documentation.mdx +++ b/content/docs/references/api/documentation.mdx @@ -62,7 +62,7 @@ const result = ApiChangelogEntrySchema.parse(data); | :--- | :--- | :--- | :--- | | **version** | `string` | ✅ | API version | | **date** | `string` | ✅ | Release date | -| **changes** | `{ added: string[]; changed: string[]; deprecated: string[]; removed: string[]; … }` | ✅ | Version changes | +| **changes** | `{ added?: string[]; changed?: string[]; deprecated?: string[]; removed?: string[]; … }` | ✅ | Version changes | | **migrationGuide** | `string` | optional | Migration guide URL or text | ### Nested Shape: `ApiChangelogEntry.changes` @@ -90,10 +90,10 @@ const result = ApiChangelogEntrySchema.parse(data); | **version** | `string` | ✅ | API version | | **description** | `string` | optional | API description | | **servers** | `{ url: string; description?: string; variables?: Record }[]` | optional (default: `[]`) | 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 | +| **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` | optional (default: `true`) | Generate OpenAPI 3.0 specification | | **generateTestCollections** | `boolean` | optional (default: `true`) | Generate API test collections | -| **testCollections** | `{ name: string; description?: string; variables: Record; requests: object[]; … }[]` | optional (default: `[]`) | Predefined test collections | +| **testCollections** | `{ name: string; description?: string; variables?: Record; requests: object[]; … }[]` | optional (default: `[]`) | Predefined test collections | | **changelog** | `{ version: string; date: string; changes: object; migrationGuide?: string }[]` | optional (default: `[]`) | API version changelog | | **codeTemplates** | `{ language: string; name: string; template: string; variables?: string[] }[]` | optional (default: `[]`) | Code generation templates | | **termsOfService** | `string` | optional | Terms of service URL | @@ -126,7 +126,7 @@ const result = ApiChangelogEntrySchema.parse(data); | **syntaxHighlighting** | `boolean` | optional (default: `true`) | Enable syntax highlighting | | **customCssUrl** | `string` | optional | Custom CSS stylesheet URL | | **customJsUrl** | `string` | optional | Custom JavaScript URL | -| **layout** | `{ showExtensions: boolean; showCommonExtensions: boolean; deepLinking: boolean; displayOperationId: boolean; … }` | optional | Layout configuration | +| **layout** | `{ showExtensions?: boolean; showCommonExtensions?: boolean; deepLinking?: boolean; displayOperationId?: boolean; … }` | optional | Layout configuration | ### Nested Shape: `ApiDocumentationConfig.testCollections[number]` @@ -144,7 +144,7 @@ const result = ApiChangelogEntrySchema.parse(data); | :--- | :--- | :--- | :--- | | **version** | `string` | ✅ | API version | | **date** | `string` | ✅ | Release date | -| **changes** | `{ added: string[]; changed: string[]; deprecated: string[]; removed: string[]; … }` | ✅ | Version changes | +| **changes** | `{ added?: string[]; changed?: string[]; deprecated?: string[]; removed?: string[]; … }` | ✅ | Version changes | | **migrationGuide** | `string` | optional | Migration guide URL or text | ### Nested Shape: `ApiDocumentationConfig.codeTemplates[number]` @@ -237,7 +237,7 @@ const result = ApiChangelogEntrySchema.parse(data); | **syntaxHighlighting** | `boolean` | optional (default: `true`) | Enable syntax highlighting | | **customCssUrl** | `string` | optional | Custom CSS stylesheet URL | | **customJsUrl** | `string` | optional | Custom JavaScript URL | -| **layout** | `{ showExtensions: boolean; showCommonExtensions: boolean; deepLinking: boolean; displayOperationId: boolean; … }` | optional | Layout configuration | +| **layout** | `{ showExtensions?: boolean; showCommonExtensions?: boolean; deepLinking?: boolean; displayOperationId?: boolean; … }` | optional | Layout configuration | ### Nested Shape: `ApiTestingUiConfig.layout` @@ -291,8 +291,8 @@ const result = ApiChangelogEntrySchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **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 | +| **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 | diff --git a/content/docs/references/api/endpoint.mdx b/content/docs/references/api/endpoint.mdx index 8d3998015c0..cd2826a75a1 100644 --- a/content/docs/references/api/endpoint.mdx +++ b/content/docs/references/api/endpoint.mdx @@ -39,7 +39,7 @@ const result = ApiEndpointSchema.parse(data); | **inputMapping** | `{ source: string; target: string; transform?: string }[]` | optional | Map Request Body to Internal Params | | **outputMapping** | `{ source: string; target: string; transform?: string }[]` | optional | Map Internal Result to Response Body | | **authRequired** | `boolean` | optional (default: `true`) | Require authentication | -| **rateLimit** | `{ enabled: boolean; windowMs: integer; maxRequests: integer }` | optional | Rate limiting policy | +| **rateLimit** | `{ enabled?: boolean; windowMs?: integer; maxRequests?: integer }` | optional | Rate limiting policy | | **cacheTtlSeconds** | `number` | optional | Response cache TTL in seconds | | **cacheTtl** | `never` | optional | [REMOVED] `ApiEndpoint.cacheTtl` was renamed to `cacheTtlSeconds` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Rename the key to `cacheTtlSeconds`; the value (seconds) is unchanged, and it stays GET-only. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | diff --git a/content/docs/references/api/export.mdx b/content/docs/references/api/export.mdx index f23145e74e0..44b5aebccfb 100644 --- a/content/docs/references/api/export.mdx +++ b/content/docs/references/api/export.mdx @@ -49,7 +49,7 @@ const result = CreateImportJobRequestSchema.parse(data); | **rows** | `Record[]` | optional | Row objects (when format = json) | | **xlsxBase64** | `string` | optional | Base64-encoded .xlsx workbook bytes (when format = xlsx); parsed server-side | | **sheet** | `string \| integer` | optional | Worksheet name or 1-based index to read (xlsx; defaults to the first sheet) | -| **mapping** | `Record \| { sourceField: string; targetField: string; targetLabel?: string; transform: Enum<'none' \| 'uppercase' \| 'lowercase' \| 'trim' \| 'date_format' \| 'lookup'>; … }[]` | optional | Source column → target field mapping | +| **mapping** | `Record \| { sourceField: string; targetField: string; targetLabel?: string; transform?: Enum<'none' \| 'uppercase' \| 'lowercase' \| 'trim' \| 'date_format' \| 'lookup'>; … }[]` | optional | Source column → target field mapping | | **mappingName** | `string` | optional | Name of a registered `mapping` metadata artifact to apply; the server resolves it (org-scoped rows first, then env-wide) and projects columns through it. Mutually exclusive with an inline `mapping` — supplying both is refused (400 CONFLICTING_MAPPING). | | **dryRun** | `boolean` | optional (default: `false`) | Validate + coerce every row without persisting. The verdict is the engine's own write-path validation, with one boundary an author should know: a preview runs NO automations. Hooks never fire in a dry run — a preview that executed user-authored side effects (mail, outbound calls, writes to other objects) would be the retired `validateOnly` defect in a new spelling. So a dry run with `runAutomations: true` can report `required` for a field a `beforeInsert` hook would populate during the real import; for hook-derived fields the real write is authoritative. | | **writeMode** | `Enum<'insert' \| 'update' \| 'upsert'>` | optional (default: `"insert"`) | insert / update / upsert semantics | @@ -128,7 +128,7 @@ const result = CreateImportJobRequestSchema.parse(data); | **object** | `string` | ✅ | Target object name | | **direction** | `Enum<'import' \| 'export' \| 'bidirectional'>` | ✅ | Template direction | | **format** | `Enum<'csv' \| 'json' \| 'jsonl' \| 'xlsx' \| 'parquet'>` | optional | Default file format for this template | -| **mappings** | `{ sourceField: string; targetField: string; targetLabel?: string; transform: Enum<'none' \| 'uppercase' \| 'lowercase' \| 'trim' \| 'date_format' \| 'lookup'>; … }[]` | ✅ | Field mapping entries | +| **mappings** | `{ sourceField: string; targetField: string; targetLabel?: string; transform?: Enum<'none' \| 'uppercase' \| 'lowercase' \| 'trim' \| 'date_format' \| 'lookup'>; … }[]` | ✅ | Field mapping entries | | **createdAt** | `string` | optional | Template creation timestamp | | **updatedAt** | `string` | optional | Last update timestamp | | **createdBy** | `string` | optional | User who created the template | @@ -285,7 +285,7 @@ Type: `Record` #### Option 2 -Type: `{ sourceField: string; targetField: string; targetLabel?: string; transform: Enum<'none' | 'uppercase' | 'lowercase' | 'trim' | 'date_format' | 'lookup'>; … }[]` +Type: `{ sourceField: string; targetField: string; targetLabel?: string; transform?: Enum<'none' | 'uppercase' | 'lowercase' | 'trim' | 'date_format' | 'lookup'>; … }[]` --- @@ -303,7 +303,7 @@ Type: `{ sourceField: string; targetField: string; targetLabel?: string; transfo | **rows** | `Record[]` | optional | Row objects (when format = json) | | **xlsxBase64** | `string` | optional | Base64-encoded .xlsx workbook bytes (when format = xlsx); parsed server-side | | **sheet** | `string \| integer` | optional | Worksheet name or 1-based index to read (xlsx; defaults to the first sheet) | -| **mapping** | `Record \| { sourceField: string; targetField: string; targetLabel?: string; transform: Enum<'none' \| 'uppercase' \| 'lowercase' \| 'trim' \| 'date_format' \| 'lookup'>; … }[]` | optional | Source column → target field mapping | +| **mapping** | `Record \| { sourceField: string; targetField: string; targetLabel?: string; transform?: Enum<'none' \| 'uppercase' \| 'lowercase' \| 'trim' \| 'date_format' \| 'lookup'>; … }[]` | optional | Source column → target field mapping | | **mappingName** | `string` | optional | Name of a registered `mapping` metadata artifact to apply; the server resolves it (org-scoped rows first, then env-wide) and projects columns through it. Mutually exclusive with an inline `mapping` — supplying both is refused (400 CONFLICTING_MAPPING). | | **dryRun** | `boolean` | optional (default: `false`) | Validate + coerce every row without persisting. The verdict is the engine's own write-path validation, with one boundary an author should know: a preview runs NO automations. Hooks never fire in a dry run — a preview that executed user-authored side effects (mail, outbound calls, writes to other objects) would be the retired `validateOnly` defect in a new spelling. So a dry run with `runAutomations: true` can report `required` for a field a `beforeInsert` hook would populate during the real import; for hook-derived fields the real write is authoritative. | | **writeMode** | `Enum<'insert' \| 'update' \| 'upsert'>` | optional (default: `"insert"`) | insert / update / upsert semantics | @@ -407,7 +407,7 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **mode** | `Enum<'strict' \| 'lenient' \| 'dry_run'>` | optional (default: `"strict"`) | Validation mode for the import | -| **deduplication** | `{ strategy: Enum<'skip' \| 'update' \| 'create_new' \| 'fail'>; matchFields: string[] }` | optional | Deduplication configuration | +| **deduplication** | `{ strategy?: Enum<'skip' \| 'update' \| 'create_new' \| 'fail'>; matchFields: string[] }` | optional | Deduplication configuration | | **maxErrors** | `integer` | optional (default: `100`) | Maximum validation errors before aborting | | **trimWhitespace** | `boolean` | optional (default: `true`) | Trim leading/trailing whitespace from string fields | | **dateFormat** | `string` | optional | Expected date format in import data (e.g., "YYYY-MM-DD") | diff --git a/content/docs/references/api/http-cache.mdx b/content/docs/references/api/http-cache.mdx index a23193b1147..cf918585cf3 100644 --- a/content/docs/references/api/http-cache.mdx +++ b/content/docs/references/api/http-cache.mdx @@ -163,7 +163,7 @@ const result = CacheControlSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **data** | `any` | optional | Metadata payload (omitted for 304 Not Modified) | -| **etag** | `{ value: string; weak: boolean }` | optional | ETag for this resource version | +| **etag** | `{ value: string; weak?: boolean }` | optional | ETag for this resource version | | **lastModified** | `string` | optional | Last modification timestamp | | **cacheControl** | `{ directives: Enum<'public' \| 'private' \| 'no-cache' \| 'no-store' \| 'must-revalidate' \| 'max-age'>[]; maxAge?: number; staleWhileRevalidate?: number; staleIfError?: number }` | optional | Cache control directives | | **notModified** | `boolean` | optional (default: `false`) | True if resource has not been modified (304 response) | diff --git a/content/docs/references/api/odata.mdx b/content/docs/references/api/odata.mdx index 5851840af64..4ebed188339 100644 --- a/content/docs/references/api/odata.mdx +++ b/content/docs/references/api/odata.mdx @@ -180,7 +180,7 @@ const result = ODataConfigSchema.parse(data); | :--- | :--- | :--- | :--- | | **name** | `string` | ✅ | Entity type name | | **key** | `string[]` | ✅ | Key fields | -| **properties** | `{ name: string; type: string; nullable: boolean }[]` | ✅ | | +| **properties** | `{ name: string; type: string; nullable?: boolean }[]` | ✅ | | | **navigationProperties** | `{ name: string; type: string; partner?: string }[]` | optional | | ### Nested Shape: `ODataMetadata.entitySets[number]` diff --git a/content/docs/references/api/package-api.mdx b/content/docs/references/api/package-api.mdx index cad00f891e3..2d29ba891b8 100644 --- a/content/docs/references/api/package-api.mdx +++ b/content/docs/references/api/package-api.mdx @@ -678,7 +678,7 @@ Upload artifact request | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **artifact** | `{ formatVersion: string; packageId: string; version: string; format: Enum<'tgz' \| 'zip'>; … }` | ✅ | Package artifact metadata | +| **artifact** | `{ formatVersion?: string; packageId: string; version: string; format?: Enum<'tgz' \| 'zip'>; … }` | ✅ | Package artifact metadata | | **sha256** | `string` | optional | SHA256 checksum of the uploaded file | | **token** | `string` | optional | Publisher authentication token | | **releaseNotes** | `string` | optional | Release notes for this version | @@ -696,8 +696,8 @@ Upload artifact request | **builtWith** | `string` | optional | Build tool identifier (e.g. "os-cli@3.2.0") | | **files** | `{ path: string; size: integer; category?: Enum<'objects' \| 'views' \| 'pages' \| 'flows' \| 'dashboards' \| 'permissions' \| …> }[]` | optional | List of files contained in the artifact | | **metadataCategories** | `Enum<'objects' \| 'views' \| 'pages' \| 'flows' \| 'dashboards' \| 'permissions' \| …>[]` | optional | Metadata categories included in this artifact | -| **checksums** | `{ algorithm: Enum<'sha256' \| 'sha384' \| 'sha512'>; files: Record }` | optional | SHA256 checksums for artifact integrity verification | -| **signature** | `{ algorithm: Enum<'RSA-SHA256' \| 'RSA-SHA384' \| 'RSA-SHA512' \| 'ECDSA-SHA256'>; publicKeyRef: string; signature: string; signedAt?: string; … }` | optional | Digital signature for artifact authenticity verification | +| **checksums** | `{ algorithm?: Enum<'sha256' \| 'sha384' \| 'sha512'>; files: Record }` | optional | SHA256 checksums for artifact integrity verification | +| **signature** | `{ algorithm?: Enum<'RSA-SHA256' \| 'RSA-SHA384' \| 'RSA-SHA512' \| 'ECDSA-SHA256'>; publicKeyRef: string; signature: string; signedAt?: string; … }` | optional | Digital signature for artifact authenticity verification | --- @@ -743,7 +743,7 @@ Upload artifact response | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **success** | `boolean` | ✅ | Whether the upload succeeded | -| **artifactRef** | `{ url: string; sha256: string; size: integer; format: Enum<'tgz' \| 'zip'>; … }` | optional | Artifact reference in the registry | +| **artifactRef** | `{ url: string; sha256: string; size: integer; format?: Enum<'tgz' \| 'zip'>; … }` | optional | Artifact reference in the registry | | **submissionId** | `string` | optional | Marketplace submission ID for review tracking | | **message** | `string` | optional | Upload status message | diff --git a/content/docs/references/api/plugin-rest-api.mdx b/content/docs/references/api/plugin-rest-api.mdx index 24b76d440f9..4f0c769b076 100644 --- a/content/docs/references/api/plugin-rest-api.mdx +++ b/content/docs/references/api/plugin-rest-api.mdx @@ -204,13 +204,13 @@ const result = ErrorHandlingConfigSchema.parse(data); | **basePath** | `string` | optional (default: `"/api"`) | Base path for all API routes | | **version** | `string` | optional (default: `"v1"`) | API version identifier | | **routes** | `{ prefix: string; service: string; category: Enum<'discovery' \| 'metadata' \| 'data' \| 'batch' \| 'permission' \| 'analytics' \| …>; methods?: string[]; … }[]` | ✅ | Route registrations | -| **validation** | `{ enabled: boolean; mode: Enum<'strict' \| 'permissive' \| 'strip'>; validateBody: boolean; validateQuery: boolean; … }` | optional | Request validation configuration | -| **responseEnvelope** | `{ enabled: boolean; includeMetadata: boolean; includeTimestamp: boolean; includeRequestId: boolean; … }` | optional | Response envelope configuration | -| **errorHandling** | `{ enabled: boolean; includeStackTrace: boolean; logErrors: boolean; exposeInternalErrors: boolean; … }` | optional | Error handling configuration | -| **openApi** | `{ enabled: boolean; version: Enum<'3.0.0' \| '3.0.1' \| '3.0.2' \| '3.0.3' \| '3.1.0'>; title: string; description?: string; … }` | optional | OpenAPI documentation configuration | -| **globalMiddleware** | `{ name: string; type: Enum<'authentication' \| 'authorization' \| 'logging' \| 'validation' \| 'transformation' \| 'error' \| 'custom'>; enabled: boolean; order: integer; … }[]` | optional | Global middleware stack | -| **cors** | `{ enabled: boolean; origins?: string[]; methods?: Enum<'GET' \| 'POST' \| 'PUT' \| 'DELETE' \| 'PATCH' \| 'HEAD' \| 'OPTIONS'>[]; credentials: boolean }` | optional | CORS configuration | -| **performance** | `{ enableCompression: boolean; enableETag: boolean; enableCaching: boolean; defaultCacheTtlSeconds: integer }` | optional | Performance optimization settings | +| **validation** | `{ enabled?: boolean; mode?: Enum<'strict' \| 'permissive' \| 'strip'>; validateBody?: boolean; validateQuery?: boolean; … }` | optional | Request validation configuration | +| **responseEnvelope** | `{ enabled?: boolean; includeMetadata?: boolean; includeTimestamp?: boolean; includeRequestId?: boolean; … }` | optional | Response envelope configuration | +| **errorHandling** | `{ enabled?: boolean; includeStackTrace?: boolean; logErrors?: boolean; exposeInternalErrors?: boolean; … }` | optional | Error handling configuration | +| **openApi** | `{ enabled?: boolean; version?: Enum<'3.0.0' \| '3.0.1' \| '3.0.2' \| '3.0.3' \| '3.1.0'>; title?: string; description?: string; … }` | optional | OpenAPI documentation configuration | +| **globalMiddleware** | `{ name: string; type: Enum<'authentication' \| 'authorization' \| 'logging' \| 'validation' \| 'transformation' \| 'error' \| 'custom'>; enabled?: boolean; order?: integer; … }[]` | optional | Global middleware stack | +| **cors** | `{ enabled?: boolean; origins?: string[]; methods?: Enum<'GET' \| 'POST' \| 'PUT' \| 'DELETE' \| 'PATCH' \| 'HEAD' \| 'OPTIONS'>[]; credentials?: boolean }` | optional | CORS configuration | +| **performance** | `{ enableCompression?: boolean; enableETag?: boolean; enableCaching?: boolean; defaultCacheTtlSeconds?: integer }` | optional | Performance optimization settings | ### Nested Shape: `RestApiPluginConfig.routes[number]` @@ -221,7 +221,7 @@ const result = ErrorHandlingConfigSchema.parse(data); | **category** | `Enum<'discovery' \| 'metadata' \| 'data' \| 'batch' \| 'permission' \| 'analytics' \| …>` | ✅ | Primary category for this route group | | **methods** | `string[]` | optional | Protocol method names implemented | | **endpoints** | `{ method: Enum<'GET' \| 'POST' \| 'PUT' \| 'DELETE' \| 'PATCH' \| 'HEAD' \| 'OPTIONS'>; path: string; handler: string; category: Enum<'discovery' \| 'metadata' \| 'data' \| 'batch' \| 'permission' \| 'analytics' \| …>; … }[]` | optional | Endpoint definitions | -| **middleware** | `{ name: string; type: Enum<'authentication' \| 'authorization' \| 'logging' \| 'validation' \| 'transformation' \| 'error' \| 'custom'>; enabled: boolean; order: integer; … }[]` | optional | Middleware stack for this route group | +| **middleware** | `{ name: string; type: Enum<'authentication' \| 'authorization' \| 'logging' \| 'validation' \| 'transformation' \| 'error' \| 'custom'>; enabled?: boolean; order?: integer; … }[]` | optional | Middleware stack for this route group | | **authRequired** | `boolean` | optional (default: `true`) | Whether authentication is required by default | | **documentation** | `{ title?: string; description?: string; tags?: string[] }` | optional | Documentation metadata for this route group | @@ -342,7 +342,7 @@ const result = ErrorHandlingConfigSchema.parse(data); | **category** | `Enum<'discovery' \| 'metadata' \| 'data' \| 'batch' \| 'permission' \| 'analytics' \| 'automation' \| 'ui' \| 'realtime' \| 'notification' \| 'ai' \| 'i18n'>` | ✅ | Primary category for this route group | | **methods** | `string[]` | optional | Protocol method names implemented | | **endpoints** | `{ method: Enum<'GET' \| 'POST' \| 'PUT' \| 'DELETE' \| 'PATCH' \| 'HEAD' \| 'OPTIONS'>; path: string; handler: string; category: Enum<'discovery' \| 'metadata' \| 'data' \| 'batch' \| 'permission' \| 'analytics' \| …>; … }[]` | optional | Endpoint definitions | -| **middleware** | `{ name: string; type: Enum<'authentication' \| 'authorization' \| 'logging' \| 'validation' \| 'transformation' \| 'error' \| 'custom'>; enabled: boolean; order: integer; … }[]` | optional | Middleware stack for this route group | +| **middleware** | `{ name: string; type: Enum<'authentication' \| 'authorization' \| 'logging' \| 'validation' \| 'transformation' \| 'error' \| 'custom'>; enabled?: boolean; order?: integer; … }[]` | optional | Middleware stack for this route group | | **authRequired** | `boolean` | optional (default: `true`) | Whether authentication is required by default | | **documentation** | `{ title?: string; description?: string; tags?: string[] }` | optional | Documentation metadata for this route group | diff --git a/content/docs/references/api/protocol.mdx b/content/docs/references/api/protocol.mdx index 05e08a29e58..31a4fe51eda 100644 --- a/content/docs/references/api/protocol.mdx +++ b/content/docs/references/api/protocol.mdx @@ -402,7 +402,7 @@ Canonical cross-paradigm action/node descriptor (ADR-0018) | :--- | :--- | :--- | :--- | | **operation** | `Enum<'create' \| 'update' \| 'upsert' \| 'delete'>` | ✅ | Type of batch operation | | **records** | `{ id?: string; data?: Record; externalId?: string }[]` | ✅ | Array of records to process (server caps the count — see batch.maxBatchSize) | -| **options** | `{ atomic: boolean; returnRecords: boolean; continueOnError: boolean }` | optional | Batch operation options | +| **options** | `{ atomic?: boolean; returnRecords?: boolean; continueOnError?: boolean }` | optional | Batch operation options | --- @@ -628,7 +628,7 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **ids** | `string[]` | ✅ | Array of record IDs to delete (server caps the count — see batch.maxBatchSize) | -| **options** | `{ atomic: boolean; returnRecords: boolean; continueOnError: boolean }` | optional | Delete options | +| **options** | `{ atomic?: boolean; returnRecords?: boolean; continueOnError?: boolean }` | optional | Delete options | | **object** | `string` | ✅ | Object name | ### Nested Shape: `DeleteManyDataRequest.options` @@ -1097,7 +1097,7 @@ Enable package response | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **objects** | `Record` | ✅ | Effective object permissions keyed by object name | +| **objects** | `Record` | ✅ | Effective object permissions keyed by object name | | **systemPermissions** | `string[]` | ✅ | Effective system-level permissions | ### Nested Shape: `GetEffectivePermissionsResponse.objects[string]` @@ -1170,7 +1170,7 @@ Enable package response | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **locales** | `{ code: string; label: string; isDefault: boolean }[]` | ✅ | Available locales | +| **locales** | `{ code: string; label: string; isDefault?: boolean }[]` | ✅ | Available locales | ### Nested Shape: `GetLocalesResponse.locales[number]` @@ -1244,7 +1244,7 @@ Enable package response | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **data** | `any` | optional | Metadata payload (omitted for 304 Not Modified) | -| **etag** | `{ value: string; weak: boolean }` | optional | ETag for this resource version | +| **etag** | `{ value: string; weak?: boolean }` | optional | ETag for this resource version | | **lastModified** | `string` | optional | Last modification timestamp | | **cacheControl** | `{ directives: Enum<'public' \| 'private' \| 'no-cache' \| 'no-store' \| 'must-revalidate' \| 'max-age'>[]; maxAge?: number; staleWhileRevalidate?: number; staleIfError?: number }` | optional | Cache control directives | | **notModified** | `boolean` | optional (default: `false`) | True if resource has not been modified (304 response) | @@ -1446,7 +1446,7 @@ Enable package response | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **preferences** | `{ email: boolean; push: boolean; inApp: boolean; digest: Enum<'none' \| 'daily' \| 'weekly'>; … }` | ✅ | Current notification preferences | +| **preferences** | `{ email?: boolean; push?: boolean; inApp?: boolean; digest?: Enum<'none' \| 'daily' \| 'weekly'>; … }` | ✅ | Current notification preferences | ### Nested Shape: `GetNotificationPreferencesResponse.preferences` @@ -1456,7 +1456,7 @@ Enable package response | **push** | `boolean` | optional (default: `true`) | Receive push notifications | | **inApp** | `boolean` | optional (default: `true`) | Receive in-app notifications | | **digest** | `Enum<'none' \| 'daily' \| 'weekly'>` | optional (default: `"none"`) | Email digest frequency | -| **channels** | `Record` | optional | Per-channel notification preferences | +| **channels** | `Record` | optional | Per-channel notification preferences | --- @@ -1479,8 +1479,8 @@ Enable package response | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **object** | `string` | ✅ | Object name | -| **permissions** | `{ allowCreate: boolean; allowRead: boolean; allowEdit: boolean; allowDelete: boolean; … }` | ✅ | Object-level permissions | -| **fieldPermissions** | `Record` | optional | Field-level permissions keyed by field name | +| **permissions** | `{ allowCreate?: boolean; allowRead?: boolean; allowEdit?: boolean; allowDelete?: boolean; … }` | ✅ | Object-level permissions | +| **fieldPermissions** | `Record` | optional | Field-level permissions keyed by field name | ### Nested Shape: `GetObjectPermissionsResponse.permissions` @@ -2263,7 +2263,7 @@ Installed package with runtime lifecycle state | **push** | `boolean` | optional (default: `true`) | Receive push notifications | | **inApp** | `boolean` | optional (default: `true`) | Receive in-app notifications | | **digest** | `Enum<'none' \| 'daily' \| 'weekly'>` | optional (default: `"none"`) | Email digest frequency | -| **channels** | `Record` | optional | Per-channel notification preferences | +| **channels** | `Record` | optional | Per-channel notification preferences | ### Nested Shape: `NotificationPreferences.channels[string]` @@ -2833,7 +2833,7 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **records** | `{ id: string; data: Record }[]` | ✅ | Array of records to update (server caps the count — see batch.maxBatchSize) | -| **options** | `{ atomic: boolean; returnRecords: boolean; continueOnError: boolean }` | optional | Update options | +| **options** | `{ atomic?: boolean; returnRecords?: boolean; continueOnError?: boolean }` | optional | Update options | | **object** | `string` | ✅ | Object name | ### Nested Shape: `UpdateManyDataRequest.records[number]` @@ -2923,7 +2923,7 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | **push** | `boolean` | optional (default: `true`) | Receive push notifications | | **inApp** | `boolean` | optional (default: `true`) | Receive in-app notifications | | **digest** | `Enum<'none' \| 'daily' \| 'weekly'>` | optional (default: `"none"`) | Email digest frequency | -| **channels** | `Record` | optional | Per-channel notification preferences | +| **channels** | `Record` | optional | Per-channel notification preferences | --- @@ -2934,7 +2934,7 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **preferences** | `{ email: boolean; push: boolean; inApp: boolean; digest: Enum<'none' \| 'daily' \| 'weekly'>; … }` | ✅ | Updated notification preferences | +| **preferences** | `{ email?: boolean; push?: boolean; inApp?: boolean; digest?: Enum<'none' \| 'daily' \| 'weekly'>; … }` | ✅ | Updated notification preferences | ### Nested Shape: `UpdateNotificationPreferencesResponse.preferences` @@ -2944,7 +2944,7 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | **push** | `boolean` | optional (default: `true`) | Receive push notifications | | **inApp** | `boolean` | optional (default: `true`) | Receive in-app notifications | | **digest** | `Enum<'none' \| 'daily' \| 'weekly'>` | optional (default: `"none"`) | Email digest frequency | -| **channels** | `Record` | optional | Per-channel notification preferences | +| **channels** | `Record` | optional | Per-channel notification preferences | --- diff --git a/content/docs/references/api/query-adapter.mdx b/content/docs/references/api/query-adapter.mdx index cbe499d7fe2..2f05b161b44 100644 --- a/content/docs/references/api/query-adapter.mdx +++ b/content/docs/references/api/query-adapter.mdx @@ -46,7 +46,7 @@ const result = ODataQueryAdapterSchema.parse(data); | **version** | `Enum<'v2' \| 'v4'>` | optional (default: `"v4"`) | OData version | | **usePrefix** | `boolean` | optional (default: `true`) | Use $ prefix for system query options ($filter vs filter) | | **stringFunctions** | `Enum<'contains' \| 'startswith' \| 'endswith' \| 'tolower' \| 'toupper' \| 'trim' \| 'concat' \| 'substring' \| 'length'>[]` | optional | Supported OData string functions | -| **expand** | `{ enabled: boolean; maxDepth: integer }` | optional | $expand configuration | +| **expand** | `{ enabled?: boolean; maxDepth?: integer }` | optional | $expand configuration | ### Nested Shape: `ODataQueryAdapter.expand` @@ -78,8 +78,8 @@ const result = ODataQueryAdapterSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **operatorMappings** | `{ operator: string; rest?: string; odata?: string }[]` | optional | Custom operator mappings | -| **rest** | `{ filterStyle: Enum<'bracket' \| 'dot' \| 'flat' \| 'rsql'>; pagination?: object; sorting?: object; fieldsParam: string }` | optional | REST query adapter configuration | -| **odata** | `{ version: Enum<'v2' \| 'v4'>; usePrefix: boolean; stringFunctions?: Enum<'contains' \| 'startswith' \| 'endswith' \| 'tolower' \| 'toupper' \| 'trim' \| …>[]; expand?: object }` | optional | OData query adapter configuration | +| **rest** | `{ filterStyle?: Enum<'bracket' \| 'dot' \| 'flat' \| 'rsql'>; pagination?: object; sorting?: object; fieldsParam?: string }` | optional | REST query adapter configuration | +| **odata** | `{ version?: Enum<'v2' \| 'v4'>; usePrefix?: boolean; stringFunctions?: Enum<'contains' \| 'startswith' \| 'endswith' \| 'tolower' \| 'toupper' \| 'trim' \| …>[]; expand?: object }` | optional | OData query adapter configuration | ### Nested Shape: `QueryAdapterConfig.operatorMappings[number]` @@ -94,8 +94,8 @@ const result = ODataQueryAdapterSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **filterStyle** | `Enum<'bracket' \| 'dot' \| 'flat' \| 'rsql'>` | optional (default: `"bracket"`) | REST filter parameter encoding style | -| **pagination** | `{ limitParam: string; offsetParam: string; cursorParam: string; pageParam: string }` | optional | Pagination parameter name mappings | -| **sorting** | `{ param: string; format: Enum<'comma' \| 'array' \| 'pipe'> }` | optional | Sort parameter mapping | +| **pagination** | `{ limitParam?: string; offsetParam?: string; cursorParam?: string; pageParam?: string }` | optional | Pagination parameter name mappings | +| **sorting** | `{ param?: string; format?: Enum<'comma' \| 'array' \| 'pipe'> }` | optional | Sort parameter mapping | | **fieldsParam** | `string` | optional (default: `"fields"`) | Field selection parameter name | ### Nested Shape: `QueryAdapterConfig.odata` @@ -105,7 +105,7 @@ const result = ODataQueryAdapterSchema.parse(data); | **version** | `Enum<'v2' \| 'v4'>` | optional (default: `"v4"`) | OData version | | **usePrefix** | `boolean` | optional (default: `true`) | Use $ prefix for system query options ($filter vs filter) | | **stringFunctions** | `Enum<'contains' \| 'startswith' \| 'endswith' \| 'tolower' \| 'toupper' \| 'trim' \| …>[]` | optional | Supported OData string functions | -| **expand** | `{ enabled: boolean; maxDepth: integer }` | optional | $expand configuration | +| **expand** | `{ enabled?: boolean; maxDepth?: integer }` | optional | $expand configuration | --- @@ -127,8 +127,8 @@ const result = ODataQueryAdapterSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **filterStyle** | `Enum<'bracket' \| 'dot' \| 'flat' \| 'rsql'>` | optional (default: `"bracket"`) | REST filter parameter encoding style | -| **pagination** | `{ limitParam: string; offsetParam: string; cursorParam: string; pageParam: string }` | optional | Pagination parameter name mappings | -| **sorting** | `{ param: string; format: Enum<'comma' \| 'array' \| 'pipe'> }` | optional | Sort parameter mapping | +| **pagination** | `{ limitParam?: string; offsetParam?: string; cursorParam?: string; pageParam?: string }` | optional | Pagination parameter name mappings | +| **sorting** | `{ param?: string; format?: Enum<'comma' \| 'array' \| 'pipe'> }` | optional | Sort parameter mapping | | **fieldsParam** | `string` | optional (default: `"fields"`) | Field selection parameter name | ### Nested Shape: `RestQueryAdapter.pagination` diff --git a/content/docs/references/api/rest-server.mdx b/content/docs/references/api/rest-server.mdx index f01fe5a1457..e727515985e 100644 --- a/content/docs/references/api/rest-server.mdx +++ b/content/docs/references/api/rest-server.mdx @@ -87,7 +87,7 @@ const result = BatchEndpointsConfigSchema.parse(data); | :--- | :--- | :--- | :--- | | **maxBatchSize** | `integer` | optional (default: `200`) | Maximum records per batch operation | | **enableBatchEndpoint** | `boolean` | optional (default: `true`) | Enable POST /data/:object/batch endpoint | -| **operations** | `{ createMany: boolean; updateMany: boolean; deleteMany: boolean }` | optional | Enable/disable specific batch operations | +| **operations** | `{ createMany?: boolean; updateMany?: boolean; deleteMany?: boolean }` | optional | Enable/disable specific batch operations | | **defaultAtomic** | `never` | optional | [REMOVED] `batch.defaultAtomic` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — no batch handler ever consulted it: atomicity is decided per request by `options.atomic` in the batch body (`BatchOptions`, ADR-0119 D4, opt-in), and a server-side default that flipped it silently would change the failure semantics of callers who send nothing. Delete the key; a caller that needs all-or-nothing sends `options: { atomic: true }`. | ### Nested Shape: `BatchEndpointsConfig.operations` @@ -108,7 +108,7 @@ const result = BatchEndpointsConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **operations** | `{ create: boolean; read: boolean; update: boolean; delete: boolean; … }` | optional | Enable/disable operations | +| **operations** | `{ create?: boolean; read?: boolean; update?: boolean; delete?: boolean; … }` | optional | Enable/disable operations | | **patterns** | `never` | optional | [REMOVED] `crud.patterns` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: every CRUD route is mounted from the fixed method/path pairs in the REST server's `registerCrudEndpoints`, so a custom pattern was validated and ignored. Delete the key. The mounted CRUD paths are the contract the client SDK, the discovery document and the served /openapi.json all describe, and `crud.dataPrefix` is the one live knob that moves them; an endpoint on a custom path or method is a declarative `api` endpoint (`type: 'object_operation'`, `ApiEndpoint` in `@objectstack/spec/api`), which is matched, executed and documented. | | **dataPrefix** | `string` | optional (default: `"/data"`) | URL prefix for data endpoints | | **objectParamStyle** | `never` | optional | [REMOVED] `crud.objectParamStyle` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: every CRUD route takes the object name as a path segment, so `'query'` was validated and mounted exactly what `'path'` mounts. Delete the key; the object name is always a path segment. | @@ -216,7 +216,7 @@ const result = BatchEndpointsConfigSchema.parse(data); | **enableCache** | `boolean` | optional (default: `true`) | Enable HTTP cache headers (ETag, Last-Modified) | | **cacheTtl** | `never` | optional | [REMOVED] `metadata.cacheTtl` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: `metadata.enableCache` selects the protocol's `getMetaItemCached` read path, which takes no TTL, and no Cache-Control / ETag header was ever built from this value. Delete the key; `metadata.enableCache` is the live switch, and a declarative `api` endpoint's `cacheTtl` is the key that does reach the wire. | | **maskObjectFields** | `boolean` | optional (default: `true`) | [ADR-0106 D8] Mask served object schemas to the caller's readable fields | -| **endpoints** | `{ types: boolean; items: boolean; item: boolean; maintenance: boolean }` | optional | Enable/disable specific endpoints | +| **endpoints** | `{ types?: boolean; items?: boolean; item?: boolean; maintenance?: boolean }` | optional | Enable/disable specific endpoints | ### Nested Shape: `MetadataEndpointsConfig.endpoints` @@ -274,10 +274,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; dataPrefix: string }` | optional | CRUD endpoints configuration (embedder-only: written by a host that constructs this config, never by `os serve` or the dev plugin) | -| **metadata** | `{ prefix: string; enableCache: boolean; maskObjectFields: boolean; endpoints?: object }` | optional | Metadata endpoints configuration (embedder-only: written by a host that constructs this config, never by `os serve` or the dev plugin) | -| **batch** | `{ maxBatchSize: integer; enableBatchEndpoint: boolean; operations?: object }` | optional | Batch endpoints configuration (embedder-only: written by a host that constructs this config, never by `os serve` or the dev plugin) | +| **api** | `{ version?: string; basePath?: string; apiPath?: string; enableCrud?: boolean; … }` | optional | REST API configuration | +| **crud** | `{ operations?: object; dataPrefix?: string }` | optional | CRUD endpoints configuration (embedder-only: written by a host that constructs this config, never by `os serve` or the dev plugin) | +| **metadata** | `{ prefix?: string; enableCache?: boolean; maskObjectFields?: boolean; endpoints?: object }` | optional | Metadata endpoints configuration (embedder-only: written by a host that constructs this config, never by `os serve` or the dev plugin) | +| **batch** | `{ maxBatchSize?: integer; enableBatchEndpoint?: boolean; operations?: object }` | optional | Batch endpoints configuration (embedder-only: written by a host that constructs this config, never by `os serve` or the dev plugin) | | **routes** | `{ }` | optional | Route generation configuration | | **openApi31** | `never` | optional | [REMOVED] `RestServerConfig.openApi31` was removed in @objectstack/spec 17 (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`. | @@ -305,7 +305,7 @@ const result = BatchEndpointsConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **operations** | `{ create: boolean; read: boolean; update: boolean; delete: boolean; … }` | optional | Enable/disable operations | +| **operations** | `{ create?: boolean; read?: boolean; update?: boolean; delete?: boolean; … }` | optional | Enable/disable operations | | **patterns** | `never` | optional | [REMOVED] `crud.patterns` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: every CRUD route is mounted from the fixed method/path pairs in the REST server's `registerCrudEndpoints`, so a custom pattern was validated and ignored. Delete the key. The mounted CRUD paths are the contract the client SDK, the discovery document and the served /openapi.json all describe, and `crud.dataPrefix` is the one live knob that moves them; an endpoint on a custom path or method is a declarative `api` endpoint (`type: 'object_operation'`, `ApiEndpoint` in `@objectstack/spec/api`), which is matched, executed and documented. | | **dataPrefix** | `string` | optional (default: `"/data"`) | URL prefix for data endpoints | | **objectParamStyle** | `never` | optional | [REMOVED] `crud.objectParamStyle` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: every CRUD route takes the object name as a path segment, so `'query'` was validated and mounted exactly what `'path'` mounts. Delete the key; the object name is always a path segment. | @@ -318,7 +318,7 @@ const result = BatchEndpointsConfigSchema.parse(data); | **enableCache** | `boolean` | optional (default: `true`) | Enable HTTP cache headers (ETag, Last-Modified) | | **cacheTtl** | `never` | optional | [REMOVED] `metadata.cacheTtl` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: `metadata.enableCache` selects the protocol's `getMetaItemCached` read path, which takes no TTL, and no Cache-Control / ETag header was ever built from this value. Delete the key; `metadata.enableCache` is the live switch, and a declarative `api` endpoint's `cacheTtl` is the key that does reach the wire. | | **maskObjectFields** | `boolean` | optional (default: `true`) | [ADR-0106 D8] Mask served object schemas to the caller's readable fields | -| **endpoints** | `{ types: boolean; items: boolean; item: boolean; maintenance: boolean }` | optional | Enable/disable specific endpoints | +| **endpoints** | `{ types?: boolean; items?: boolean; item?: boolean; maintenance?: boolean }` | optional | Enable/disable specific endpoints | ### Nested Shape: `RestServerConfig.batch` @@ -326,7 +326,7 @@ const result = BatchEndpointsConfigSchema.parse(data); | :--- | :--- | :--- | :--- | | **maxBatchSize** | `integer` | optional (default: `200`) | Maximum records per batch operation | | **enableBatchEndpoint** | `boolean` | optional (default: `true`) | Enable POST /data/:object/batch endpoint | -| **operations** | `{ createMany: boolean; updateMany: boolean; deleteMany: boolean }` | optional | Enable/disable specific batch operations | +| **operations** | `{ createMany?: boolean; updateMany?: boolean; deleteMany?: boolean }` | optional | Enable/disable specific batch operations | | **defaultAtomic** | `never` | optional | [REMOVED] `batch.defaultAtomic` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — no batch handler ever consulted it: atomicity is decided per request by `options.atomic` in the batch body (`BatchOptions`, ADR-0119 D4, opt-in), and a server-side default that flipped it silently would change the failure semantics of callers who send nothing. Delete the key; a caller that needs all-or-nothing sends `options: { atomic: true }`. | diff --git a/content/docs/references/api/router.mdx b/content/docs/references/api/router.mdx index 5864807f10f..0050ce73aef 100644 --- a/content/docs/references/api/router.mdx +++ b/content/docs/references/api/router.mdx @@ -93,8 +93,8 @@ HTTP method — the full routing vocabulary (`api/*` endpoints, router and REST- | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **basePath** | `string` | optional (default: `"/api"`) | Global API prefix | -| **mounts** | `{ data: string; metadata: string; auth: string; automation: string; … }` | optional (has default) | | -| **cors** | `{ enabled: boolean; origins: string \| string[]; methods?: Enum<'GET' \| 'POST' \| 'PUT' \| 'DELETE' \| 'PATCH' \| 'HEAD' \| 'OPTIONS'>[]; credentials: boolean; … }` | optional | | +| **mounts** | `{ data?: string; metadata?: string; auth?: string; automation?: string; … }` | optional (has default) | | +| **cors** | `{ enabled?: boolean; origins?: string \| string[]; methods?: Enum<'GET' \| 'POST' \| 'PUT' \| 'DELETE' \| 'PATCH' \| 'HEAD' \| 'OPTIONS'>[]; credentials?: boolean; … }` | optional | | | **staticMounts** | `{ path: string; directory: string; cacheControl?: string }[]` | optional | | ### Nested Shape: `RouterConfig.mounts` diff --git a/content/docs/references/api/versioning.mdx b/content/docs/references/api/versioning.mdx index 0840491c239..936a2cb787e 100644 --- a/content/docs/references/api/versioning.mdx +++ b/content/docs/references/api/versioning.mdx @@ -107,7 +107,7 @@ const result = VersionDefinitionSchema.parse(data); | **headerName** | `string` | optional (default: `"ObjectStack-Version"`) | HTTP header name for version negotiation (header/dateBased strategies) | | **queryParamName** | `string` | optional (default: `"version"`) | Query parameter name for version specification (queryParam strategy) | | **urlPrefix** | `string` | optional (default: `"/api"`) | URL prefix before version segment (urlPath strategy) | -| **deprecation** | `{ warnHeader: boolean; sunsetHeader: boolean; linkHeader: boolean; rejectRetired: boolean; … }` | optional | Deprecation lifecycle behavior | +| **deprecation** | `{ warnHeader?: boolean; sunsetHeader?: boolean; linkHeader?: boolean; rejectRetired?: boolean; … }` | optional | Deprecation lifecycle behavior | | **includeInDiscovery** | `boolean` | optional (default: `true`) | Include version information in the API discovery endpoint | ### Nested Shape: `VersioningConfig.versions[number]` diff --git a/content/docs/references/automation/approval.mdx b/content/docs/references/automation/approval.mdx index b5183c1810f..1fc6a5eb5f3 100644 --- a/content/docs/references/automation/approval.mdx +++ b/content/docs/references/automation/approval.mdx @@ -76,7 +76,7 @@ const result = ApprovalDecision.parse(data); | **onEmptyApprovers** | `Enum<'admin_rescue' \| 'fail' \| 'auto_approve' \| 'fallback'>` | optional (default: `"admin_rescue"`) | Behavior when no concrete approver resolves at node entry — 'fallback' opens the request on fallbackApprovers instead | | **fallbackApprovers** | `{ type: Enum<'manager' \| 'position' \| 'department' \| 'team' \| 'field' \| 'expression' \| …>; value?: string; resolveAs?: Enum<'user' \| 'department' \| 'position' \| 'team'>; group?: string; … }[]` | optional | Approvers the request opens on when onEmptyApprovers is 'fallback' | | **decisionOutputs** | `(string \| { key: string; label?: string; type?: Enum<'text' \| 'user' \| 'department' \| 'position' \| 'team'>; multiple?: boolean; … })[]` | optional | Author-declared decision outputs — bare keys or typed `{ key, type, multiple }` declarations | -| **escalation** | `{ enabled: boolean; timeoutHours: number; action: Enum<'reassign' \| 'auto_approve' \| 'auto_reject' \| 'notify'>; escalateTo?: string; … }` | optional | Per-node SLA escalation | +| **escalation** | `{ enabled?: boolean; timeoutHours: number; action?: Enum<'reassign' \| 'auto_approve' \| 'auto_reject' \| 'notify'>; escalateTo?: string; … }` | optional | Per-node SLA escalation | | **maxRevisions** | `integer` | optional (default: `3`) | Max send-backs for revision before auto-reject (0 = send-back disabled) | ### Nested Shape: `ApprovalNodeConfig.approvers[number]` diff --git a/content/docs/references/automation/bpmn-interop.mdx b/content/docs/references/automation/bpmn-interop.mdx index 45f73c991ea..e581fcf4087 100644 --- a/content/docs/references/automation/bpmn-interop.mdx +++ b/content/docs/references/automation/bpmn-interop.mdx @@ -73,7 +73,7 @@ Options for exporting an ObjectStack flow as BPMN 2.0 XML | **version** | `Enum<'2.0' \| '2.0.2'>` | optional (default: `"2.0"`) | Target BPMN specification version | | **includeLayout** | `boolean` | optional (default: `true`) | Include BPMN DI layout data from canvas positions | | **includeExtensions** | `boolean` | optional (default: `false`) | Include ObjectStack extensions in BPMN extensionElements | -| **customMappings** | `{ bpmnType: string; flowNodeAction: string; bidirectional: boolean; notes?: string }[]` | optional | Custom element mappings for export | +| **customMappings** | `{ bpmnType: string; flowNodeAction: string; bidirectional?: boolean; notes?: string }[]` | optional | Custom element mappings for export | | **prettyPrint** | `boolean` | optional (default: `true`) | Pretty-print XML output with indentation | | **namespacePrefix** | `string` | optional (default: `"bpmn"`) | XML namespace prefix for BPMN elements | @@ -100,7 +100,7 @@ Options for importing BPMN 2.0 XML into an ObjectStack flow | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **unmappedStrategy** | `Enum<'skip' \| 'warn' \| 'error' \| 'comment'>` | optional (default: `"warn"`) | How to handle unmapped BPMN elements | -| **customMappings** | `{ bpmnType: string; flowNodeAction: string; bidirectional: boolean; notes?: string }[]` | optional | Custom element mappings to override or extend defaults | +| **customMappings** | `{ bpmnType: string; flowNodeAction: string; bidirectional?: boolean; notes?: string }[]` | optional | Custom element mappings to override or extend defaults | | **importLayout** | `boolean` | optional (default: `true`) | Import BPMN DI layout positions into canvas node coordinates | | **importDocumentation** | `boolean` | optional (default: `true`) | Import BPMN documentation elements as node descriptions | | **flowName** | `string` | optional | Override flow name (defaults to BPMN process name) | diff --git a/content/docs/references/data/data-engine.mdx b/content/docs/references/data/data-engine.mdx index 0323835ee9b..c170512b420 100644 --- a/content/docs/references/data/data-engine.mdx +++ b/content/docs/references/data/data-engine.mdx @@ -488,7 +488,7 @@ Query options for IDataEngine.find() operations | **context** | `{ userId?: string; actor?: string; attributedUserId?: string; email?: string; … }` | optional | | | **filter** | `Record \| any` | optional | Data Engine query filter conditions | | **select** | `string[]` | optional | | -| **sort** | `Record> \| Record \| { field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | Sort order definition | +| **sort** | `Record> \| Record \| { field: string; order?: Enum<'asc' \| 'desc'> }[]` | optional | Sort order definition | | **limit** | `integer` | optional | | | **skip** | `integer` | optional | | | **top** | `integer` | optional | | @@ -769,7 +769,7 @@ Type: `Record` #### Option 3 -Type: `{ field: string; order: Enum<'asc' | 'desc'> }[]` +Type: `{ field: string; order?: Enum<'asc' | 'desc'> }[]` --- @@ -902,7 +902,7 @@ QueryAST-aligned options for DataEngine.aggregate operations | **aggregations** | `{ function: Enum<'count' \| 'sum' \| 'avg' \| 'min' \| 'max' \| 'count_distinct'>; field?: string; alias: string; filter?: any }[]` | optional | | | **having** | `any` | optional | HAVING — filter over the aggregated rows (aggregation aliases + groupBy projections); applied engine-side after aggregation | | **timezone** | `string` | optional | | -| **search** | `string \| { query: string; fields?: string[]; fuzzy: boolean; operator: Enum<'and' \| 'or'>; … }` | optional | | +| **search** | `string \| { query: string; fields?: string[]; fuzzy?: boolean; operator?: Enum<'and' \| 'or'>; … }` | optional | | | **searchFields** | `string[]` | optional | | ### Nested Shape: `EngineAggregateOptions.context` @@ -1090,12 +1090,12 @@ QueryAST-aligned query options for IDataEngine.find() operations | **context** | `{ userId?: string; actor?: string; attributedUserId?: string; email?: string; … }` | optional | | | **where** | `Record \| any` | optional | | | **fields** | `string[]` | optional | | -| **orderBy** | `{ field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | | +| **orderBy** | `{ field: string; order?: Enum<'asc' \| 'desc'> }[]` | optional | | | **limit** | `number` | optional | | | **offset** | `number` | optional | | | **top** | `number` | optional | | | **cursor** | `never` | optional | [REMOVED] `query.cursor` was removed in @objectstack/spec 17 (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** | `string \| { query: string; fields?: string[]; fuzzy: boolean; operator: Enum<'and' \| 'or'>; … }` | optional | | +| **search** | `string \| { query: string; fields?: string[]; fuzzy?: boolean; operator?: Enum<'and' \| 'or'>; … }` | optional | | | **searchFields** | `string[]` | optional | | | **expand** | `Record` | optional | | | **distinct** | `never` | optional | [REMOVED] `query.distinct` was removed in @objectstack/spec 17 (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. | @@ -1157,9 +1157,9 @@ QueryAST-aligned query options for IDataEngine.find() operations | **object** | `string` | ✅ | Object name (e.g. account) | | **fields** | `string[]` | optional | Fields to retrieve — names of the queried object's OWN columns. A dotted path (`owner.name`) is not a projection: no driver resolves one, and the ingress refuses it with `400 INVALID_FIELD`. Related data is read with `expand`, whose nested QueryAST both filters (`where`) and selects (`fields`) the related record's columns. The projection must RETAIN the foreign-key column: `fields: ['title']` with `expand: 'project_id'` resolves nothing, because the relation is carried by that key — add `'project_id'` and it works. Where the value is wanted on the queried object itself, denormalise it onto that object (a stored field, written when the source changes), the same remedy the sort axis prescribes. | | **where** | `any` | optional | Filtering criteria (WHERE) | -| **search** | `string \| { query: string; fields?: string[]; fuzzy: boolean; operator: Enum<'and' \| 'or'>; … }` | optional | Full-text search — the query text (canonical, ADR-0061 D1), or a structured FullTextSearch configuration | +| **search** | `string \| { query: string; fields?: string[]; fuzzy?: boolean; operator?: Enum<'and' \| 'or'>; … }` | optional | Full-text search — the query text (canonical, ADR-0061 D1), or a structured FullTextSearch configuration | | **searchFields** | `string[]` | optional | Narrow the search to these fields (server-intersected with the allowed searchable set — can only narrow, never widen; ADR-0061 D1) | -| **orderBy** | `{ field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | Sorting instructions (ORDER BY) | +| **orderBy** | `{ field: string; order?: Enum<'asc' \| 'desc'> }[]` | optional | Sorting instructions (ORDER BY) | | **limit** | `number` | optional | Max records to return (LIMIT) | | **offset** | `number` | optional | Records to skip (OFFSET) | | **top** | `number` | optional | Alias for limit (OData compatibility) | @@ -1241,16 +1241,16 @@ Transport spellings of the QueryAST slots — folded to canonical keys at the bo | **filters** | `[string, string, any] \| [string, string] \| [string, object, ...object[]] \| object[] \| Record \| any \| null` | optional | Transport spelling of `where` (plural of `filter`) | | **$top** | `number \| string \| null` | optional | Transport spelling of `limit` (OData `$top`) — a number, or the digits a querystring carries it as | | **$skip** | `number \| string \| null` | optional | Transport spelling of `offset` (OData `$skip`) — a number, or the digits a querystring carries it as | -| **$orderby** | `Record> \| Record \| { field: string; order: Enum<'asc' \| 'desc'> }[] \| null` | optional | Transport spelling of `orderBy` (OData `$orderby`) | +| **$orderby** | `Record> \| Record \| { field: string; order?: Enum<'asc' \| 'desc'> }[] \| null` | optional | Transport spelling of `orderBy` (OData `$orderby`) | | **$select** | `string \| string[] \| null` | optional | Transport spelling of `fields` (OData `$select`) | | **$expand** | `string \| string[] \| Record \| null` | optional | Transport spelling of `expand` (OData `$expand`) | -| **$search** | `string \| { query: string; fields?: string[]; fuzzy: boolean; operator: Enum<'and' \| 'or'>; … } \| null` | optional | Transport spelling of `search` (OData `$search`) | +| **$search** | `string \| { query: string; fields?: string[]; fuzzy?: boolean; operator?: Enum<'and' \| 'or'>; … } \| null` | optional | Transport spelling of `search` (OData `$search`) | | **$searchFields** | `string \| string[] \| null` | optional | Transport spelling of `searchFields` (OData `$searchFields`) | | **$count** | `boolean \| Enum<'true' \| 'false'> \| null` | optional | Transport spelling of the response total-count flag (OData `$count`) | | **count** | `boolean \| Enum<'true' \| 'false'> \| null` | optional | Response total-count flag — only an explicit `false` skips the COUNT query | | **filter** | `[string, string, any] \| [string, string] \| [string, object, ...object[]] \| object[] \| Record \| any \| null` | optional | Transport spelling of `where` | | **select** | `string \| string[] \| null` | optional | Transport spelling of `fields` | -| **sort** | `Record> \| Record \| { field: string; order: Enum<'asc' \| 'desc'> }[] \| null` | optional | Transport spelling of `orderBy` | +| **sort** | `Record> \| Record \| { field: string; order?: Enum<'asc' \| 'desc'> }[] \| null` | optional | Transport spelling of `orderBy` | | **skip** | `number \| string \| null` | optional | Transport spelling of `offset` | | **populate** | `string \| string[] \| null` | optional | Transport spelling of `expand` | @@ -1261,9 +1261,9 @@ Transport spellings of the QueryAST slots — folded to canonical keys at the bo | **object** | `string` | ✅ | Object name (e.g. account) | | **fields** | `string[]` | optional | Fields to retrieve — names of the queried object's OWN columns. A dotted path (`owner.name`) is not a projection: no driver resolves one, and the ingress refuses it with `400 INVALID_FIELD`. Related data is read with `expand`, whose nested QueryAST both filters (`where`) and selects (`fields`) the related record's columns. The projection must RETAIN the foreign-key column: `fields: ['title']` with `expand: 'project_id'` resolves nothing, because the relation is carried by that key — add `'project_id'` and it works. Where the value is wanted on the queried object itself, denormalise it onto that object (a stored field, written when the source changes), the same remedy the sort axis prescribes. | | **where** | `any` | optional | Filtering criteria (WHERE) | -| **search** | `string \| { query: string; fields?: string[]; fuzzy: boolean; operator: Enum<'and' \| 'or'>; … }` | optional | Full-text search — the query text (canonical, ADR-0061 D1), or a structured FullTextSearch configuration | +| **search** | `string \| { query: string; fields?: string[]; fuzzy?: boolean; operator?: Enum<'and' \| 'or'>; … }` | optional | Full-text search — the query text (canonical, ADR-0061 D1), or a structured FullTextSearch configuration | | **searchFields** | `string[]` | optional | Narrow the search to these fields (server-intersected with the allowed searchable set — can only narrow, never widen; ADR-0061 D1) | -| **orderBy** | `{ field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | Sorting instructions (ORDER BY) | +| **orderBy** | `{ field: string; order?: Enum<'asc' \| 'desc'> }[]` | optional | Sorting instructions (ORDER BY) | | **limit** | `number` | optional | Max records to return (LIMIT) | | **offset** | `number` | optional | Records to skip (OFFSET) | | **top** | `number` | optional | Alias for limit (OData compatibility) | diff --git a/content/docs/references/data/datasource.mdx b/content/docs/references/data/datasource.mdx index c1297f9dfde..c000603c1cc 100644 --- a/content/docs/references/data/datasource.mdx +++ b/content/docs/references/data/datasource.mdx @@ -32,13 +32,13 @@ const result = DatasourceSchema.parse(data); | **label** | `string` | optional | Display label | | **driver** | `string` | ✅ | Underlying driver type | | **config** | `Record` | ✅ | Driver specific configuration | -| **pool** | `{ min: number; max: number; idleTimeoutMillis: number; connectionTimeoutMillis: number }` | optional | Connection pool settings | -| **ssl** | `{ enabled: boolean; rejectUnauthorized: boolean; ca?: string; cert?: string; … }` | optional | SSL/TLS configuration for secure database connections | +| **pool** | `{ min?: number; max?: number; idleTimeoutMillis?: number; connectionTimeoutMillis?: number }` | optional | Connection pool settings | +| **ssl** | `{ enabled?: boolean; rejectUnauthorized?: boolean; ca?: string; cert?: string; … }` | optional | SSL/TLS configuration for secure database connections | | **description** | `string` | optional | Internal description | | **active** | `boolean` | optional (default: `true`) | Is datasource enabled | | **autoConnect** | `boolean` | optional (default: `false`) | Force a live driver connection at boot even when managed + unrouted (ADR-0062 D2). | | **schemaMode** | `Enum<'managed' \| 'external' \| 'validate-only'>` | optional (default: `"managed"`) | Schema ownership mode | -| **external** | `{ allowedSchemas?: string[]; allowWrites: boolean; validation: object; credentialsRef?: string; … }` | optional | External datasource settings: federation policy (schemaMode != "managed") plus the secrets-store credentials reference (valid in every schemaMode) | +| **external** | `{ allowedSchemas?: string[]; allowWrites?: boolean; validation?: object; credentialsRef?: string; … }` | optional | External datasource settings: federation policy (schemaMode != "managed") plus the secrets-store credentials reference (valid in every schemaMode) | | **origin** | `Enum<'code' \| 'runtime'>` | optional (default: `"code"`) | Datasource provenance (server-managed, read-only) | | **_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. | @@ -73,7 +73,7 @@ const result = DatasourceSchema.parse(data); | :--- | :--- | :--- | :--- | | **allowedSchemas** | `string[]` | optional | Whitelist of remote schemas/databases that may be exposed. | | **allowWrites** | `boolean` | optional (default: `false`) | Global write gate. Individual objects must also opt in via object.external.writable. | -| **validation** | `{ onMismatch: Enum<'fail' \| 'warn' \| 'ignore'>; checkOnBoot: boolean; checkIntervalMs?: number }` | optional (default: `{"onMismatch":"fail","checkOnBoot":true}`) | Boot/drift validation policy | +| **validation** | `{ onMismatch?: Enum<'fail' \| 'warn' \| 'ignore'>; checkOnBoot?: boolean; checkIntervalMs?: number }` | optional (default: `{"onMismatch":"fail","checkOnBoot":true}`) | Boot/drift validation policy | | **credentialsRef** | `string` | optional | Reference into the secrets store; never inline credentials. Valid in every schemaMode — the one `external` key a managed datasource may carry. | | **queryTimeoutMs** | `number` | optional (default: `30000`) | Hard cap on per-query execution time. | @@ -114,7 +114,7 @@ External datasource settings: federation policy (schemaMode != "managed") plus t | :--- | :--- | :--- | :--- | | **allowedSchemas** | `string[]` | optional | Whitelist of remote schemas/databases that may be exposed. | | **allowWrites** | `boolean` | optional (default: `false`) | Global write gate. Individual objects must also opt in via object.external.writable. | -| **validation** | `{ onMismatch: Enum<'fail' \| 'warn' \| 'ignore'>; checkOnBoot: boolean; checkIntervalMs?: number }` | optional (default: `{"onMismatch":"fail","checkOnBoot":true}`) | Boot/drift validation policy | +| **validation** | `{ onMismatch?: Enum<'fail' \| 'warn' \| 'ignore'>; checkOnBoot?: boolean; checkIntervalMs?: number }` | optional (default: `{"onMismatch":"fail","checkOnBoot":true}`) | Boot/drift validation policy | | **credentialsRef** | `string` | optional | Reference into the secrets store; never inline credentials. Valid in every schemaMode — the one `external` key a managed datasource may carry. | | **queryTimeoutMs** | `number` | optional (default: `30000`) | Hard cap on per-query execution time. | diff --git a/content/docs/references/data/document.mdx b/content/docs/references/data/document.mdx index 6f876bf9b26..39e05501ad6 100644 --- a/content/docs/references/data/document.mdx +++ b/content/docs/references/data/document.mdx @@ -37,8 +37,8 @@ const result = DocumentSchema.parse(data); | **tags** | `string[]` | optional | Document tags | | **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: object[] }` | optional | E-signature config | -| **access** | `{ isPublic: boolean; sharedWith?: string[]; expiresAt?: integer }` | optional | Access control | +| **eSignature** | `{ provider: Enum<'docusign' \| 'adobe-sign' \| 'hellosign' \| 'custom'>; enabled?: boolean; signers: object[] }` | optional | E-signature config | +| **access** | `{ isPublic?: boolean; sharedWith?: string[]; expiresAt?: integer }` | optional | Access control | | **metadata** | `Record` | optional | Custom metadata | ### Nested Shape: `Document.versioning` @@ -59,7 +59,7 @@ const result = DocumentSchema.parse(data); | **description** | `string` | optional | Template description | | **fileUrl** | `string` | ✅ | Template file URL | | **fileType** | `string` | ✅ | File MIME type | -| **placeholders** | `{ key: string; label: string; type: Enum<'text' \| 'number' \| 'date' \| 'image'>; required: boolean }[]` | ✅ | Template placeholders | +| **placeholders** | `{ key: string; label: string; type: Enum<'text' \| 'number' \| 'date' \| 'image'>; required?: boolean }[]` | ✅ | Template placeholders | ### Nested Shape: `Document.eSignature` @@ -93,7 +93,7 @@ const result = DocumentSchema.parse(data); | **description** | `string` | optional | Template description | | **fileUrl** | `string` | ✅ | Template file URL | | **fileType** | `string` | ✅ | File MIME type | -| **placeholders** | `{ key: string; label: string; type: Enum<'text' \| 'number' \| 'date' \| 'image'>; required: boolean }[]` | ✅ | Template placeholders | +| **placeholders** | `{ key: string; label: string; type: Enum<'text' \| 'number' \| 'date' \| 'image'>; required?: boolean }[]` | ✅ | Template placeholders | ### Nested Shape: `DocumentTemplate.placeholders[number]` diff --git a/content/docs/references/data/driver-nosql.mdx b/content/docs/references/data/driver-nosql.mdx index 4f7c1b7bc99..2ccf0446457 100644 --- a/content/docs/references/data/driver-nosql.mdx +++ b/content/docs/references/data/driver-nosql.mdx @@ -143,13 +143,13 @@ const result = AggregationPipelineSchema.parse(data); | **type** | `'nosql'` | ✅ | Driver type must be "nosql" | | **capabilities** | `{ queryDateGranularity?: Record; autonumber?: boolean; batchSchemaSync?: boolean; transactionsUnsupported?: boolean }` | ✅ | Driver capability flags | | **connectionString** | `string` | optional | Database connection string (driver-specific format) | -| **poolConfig** | `{ min: number; max: number; idleTimeoutMillis: number; connectionTimeoutMillis: number }` | optional | Connection pool configuration | +| **poolConfig** | `{ min?: number; max?: number; idleTimeoutMillis?: number; connectionTimeoutMillis?: number }` | optional | Connection pool configuration | | **databaseType** | `Enum<'mongodb' \| 'couchdb' \| 'dynamodb' \| 'cassandra' \| 'redis' \| 'elasticsearch' \| 'neo4j' \| 'orientdb'>` | ✅ | Specific NoSQL database type | | **dataTypeMapping** | `{ text: string; number: string; boolean: string; date: string; … }` | ✅ | NoSQL data type mapping configuration | | **consistency** | `Enum<'all' \| 'quorum' \| 'one' \| 'local_quorum' \| 'each_quorum' \| 'eventual'>` | optional | Consistency level for operations | -| **replication** | `{ enabled: boolean; replicaSetName?: string; replicas?: integer; readPreference?: Enum<'primary' \| 'primaryPreferred' \| 'secondary' \| 'secondaryPreferred' \| 'nearest'>; … }` | optional | Replication configuration | -| **sharding** | `{ enabled: boolean; shardKey?: string; shardingStrategy?: Enum<'hash' \| 'range' \| 'zone'>; numShards?: integer }` | optional | Sharding configuration | -| **schemaValidation** | `{ enabled: boolean; validationLevel?: Enum<'strict' \| 'moderate' \| 'off'>; validationAction?: Enum<'error' \| 'warn'>; jsonSchema?: Record }` | optional | Document schema validation | +| **replication** | `{ enabled?: boolean; replicaSetName?: string; replicas?: integer; readPreference?: Enum<'primary' \| 'primaryPreferred' \| 'secondary' \| 'secondaryPreferred' \| 'nearest'>; … }` | optional | Replication configuration | +| **sharding** | `{ enabled?: boolean; shardKey?: string; shardingStrategy?: Enum<'hash' \| 'range' \| 'zone'>; numShards?: integer }` | optional | Sharding configuration | +| **schemaValidation** | `{ enabled?: boolean; validationLevel?: Enum<'strict' \| 'moderate' \| 'off'>; validationAction?: Enum<'error' \| 'warn'>; jsonSchema?: Record }` | optional | Document schema validation | | **region** | `string` | optional | AWS region (for managed NoSQL services) | | **accessKeyId** | `string` | optional | AWS access key ID | | **secretAccessKey** | `string` | optional | AWS secret access key | diff --git a/content/docs/references/data/driver-sql.mdx b/content/docs/references/data/driver-sql.mdx index 052b725ae2b..8a15a6b2d3c 100644 --- a/content/docs/references/data/driver-sql.mdx +++ b/content/docs/references/data/driver-sql.mdx @@ -64,11 +64,11 @@ const result = DataTypeMappingSchema.parse(data); | **type** | `'sql'` | ✅ | Driver type must be "sql" | | **capabilities** | `{ queryDateGranularity?: Record; autonumber?: boolean; batchSchemaSync?: boolean; transactionsUnsupported?: boolean }` | ✅ | Driver capability flags | | **connectionString** | `string` | optional | Database connection string (driver-specific format) | -| **poolConfig** | `{ min: number; max: number; idleTimeoutMillis: number; connectionTimeoutMillis: number }` | optional | Connection pool configuration | +| **poolConfig** | `{ min?: number; max?: number; idleTimeoutMillis?: number; connectionTimeoutMillis?: number }` | optional | Connection pool configuration | | **dialect** | `Enum<'postgresql' \| 'mysql' \| 'sqlite' \| 'mssql' \| 'oracle' \| 'mariadb'>` | ✅ | SQL database dialect | | **dataTypeMapping** | `{ text: string; number: string; boolean: string; date: string; … }` | ✅ | SQL data type mapping configuration | | **ssl** | `boolean` | optional (default: `false`) | Enable SSL/TLS connection | -| **sslConfig** | `{ rejectUnauthorized: boolean; ca?: string; cert?: string; key?: string }` | optional | SSL/TLS configuration (required when ssl is true) | +| **sslConfig** | `{ rejectUnauthorized?: boolean; ca?: string; cert?: string; key?: string }` | optional | SSL/TLS configuration (required when ssl is true) | ### Nested Shape: `SQLDriverConfig.capabilities` diff --git a/content/docs/references/data/driver.mdx b/content/docs/references/data/driver.mdx index 1f1babbd574..4a04b8a6100 100644 --- a/content/docs/references/data/driver.mdx +++ b/content/docs/references/data/driver.mdx @@ -77,7 +77,7 @@ const result = DriverCapabilitiesSchema.parse(data); | **type** | `Enum<'sql' \| 'nosql' \| 'cache' \| 'search' \| 'graph' \| 'timeseries'>` | ✅ | Driver type category | | **capabilities** | `{ queryDateGranularity?: Record; autonumber?: boolean; batchSchemaSync?: boolean; transactionsUnsupported?: boolean }` | ✅ | Driver capability flags | | **connectionString** | `string` | optional | Database connection string (driver-specific format) | -| **poolConfig** | `{ min: number; max: number; idleTimeoutMillis: number; connectionTimeoutMillis: number }` | optional | Connection pool configuration | +| **poolConfig** | `{ min?: number; max?: number; idleTimeoutMillis?: number; connectionTimeoutMillis?: number }` | optional | Connection pool configuration | ### Nested Shape: `DriverConfig.capabilities` diff --git a/content/docs/references/data/external-catalog.mdx b/content/docs/references/data/external-catalog.mdx index e17233e5bf1..0637012a5f5 100644 --- a/content/docs/references/data/external-catalog.mdx +++ b/content/docs/references/data/external-catalog.mdx @@ -49,7 +49,7 @@ const result = ExternalCatalogSchema.parse(data); | :--- | :--- | :--- | :--- | | **remoteSchema** | `string` | optional | Remote schema/database qualifier | | **remoteName** | `string` | ✅ | Remote table/view name | -| **columns** | `{ name: string; sqlType: string; nullable: boolean; primaryKey: boolean; … }[]` | ✅ | Remote columns | +| **columns** | `{ name: string; sqlType: string; nullable: boolean; primaryKey?: boolean; … }[]` | ✅ | Remote columns | | **indexes** | `{ name: string; columns: string[]; unique: boolean }[]` | optional | Remote indexes, when introspectable | | **rowCountEstimate** | `number` | optional | Approximate row count | @@ -79,7 +79,7 @@ const result = ExternalCatalogSchema.parse(data); | :--- | :--- | :--- | :--- | | **remoteSchema** | `string` | optional | Remote schema/database qualifier | | **remoteName** | `string` | ✅ | Remote table/view name | -| **columns** | `{ name: string; sqlType: string; nullable: boolean; primaryKey: boolean; … }[]` | ✅ | Remote columns | +| **columns** | `{ name: string; sqlType: string; nullable: boolean; primaryKey?: boolean; … }[]` | ✅ | Remote columns | | **indexes** | `{ name: string; columns: string[]; unique: boolean }[]` | optional | Remote indexes, when introspectable | | **rowCountEstimate** | `number` | optional | Approximate row count | diff --git a/content/docs/references/data/mapping.mdx b/content/docs/references/data/mapping.mdx index e3f4b0f6ee5..09328256be3 100644 --- a/content/docs/references/data/mapping.mdx +++ b/content/docs/references/data/mapping.mdx @@ -46,7 +46,7 @@ const result = ImportFieldMappingSchema.parse(data); | **label** | `string` | optional | | | **sourceFormat** | `Enum<'csv' \| 'json' \| 'xml' \| 'sql'>` | optional (default: `"csv"`) | | | **targetObject** | `string` | ✅ | Target Object Name | -| **fieldMapping** | `{ source: string \| string[]; target: string \| string[]; transform: Enum<'none' \| 'constant' \| 'lookup' \| 'split' \| 'join' \| 'javascript' \| 'map'>; params?: object }[]` | ✅ | | +| **fieldMapping** | `{ source: string \| string[]; target: string \| string[]; transform?: Enum<'none' \| 'constant' \| 'lookup' \| 'split' \| 'join' \| 'javascript' \| 'map'>; params?: object }[]` | ✅ | | | **mode** | `Enum<'insert' \| 'update' \| 'upsert'>` | optional (default: `"insert"`) | | | **upsertKey** | `string[]` | optional | Fields to match for upsert (e.g. email) | | **connectorSource** | `{ connector: string; action: string; input?: Record; recordsPath?: string; … }` | optional | Pull binding: the rest/openapi connector this mapping pulls rows from (one-way, full or timestamp-incremental; a `job` sets the cadence). Pulled when a job drives it; nothing schedules it yet, so the binding alone moves no rows — schedule the pull with a `job` once a job can drive one | diff --git a/content/docs/references/data/query.mdx b/content/docs/references/data/query.mdx index 8a7e4b211f5..ce28a4101b3 100644 --- a/content/docs/references/data/query.mdx +++ b/content/docs/references/data/query.mdx @@ -131,9 +131,9 @@ Type: `string` | **object** | `string` | ✅ | Object name (e.g. account) | | **fields** | `string[]` | optional | Fields to retrieve — names of the queried object's OWN columns. A dotted path (`owner.name`) is not a projection: no driver resolves one, and the ingress refuses it with `400 INVALID_FIELD`. Related data is read with `expand`, whose nested QueryAST both filters (`where`) and selects (`fields`) the related record's columns. The projection must RETAIN the foreign-key column: `fields: ['title']` with `expand: 'project_id'` resolves nothing, because the relation is carried by that key — add `'project_id'` and it works. Where the value is wanted on the queried object itself, denormalise it onto that object (a stored field, written when the source changes), the same remedy the sort axis prescribes. | | **where** | `any` | optional | Filtering criteria (WHERE) | -| **search** | `string \| { query: string; fields?: string[]; fuzzy: boolean; operator: Enum<'and' \| 'or'>; … }` | optional | Full-text search — the query text (canonical, ADR-0061 D1), or a structured FullTextSearch configuration | +| **search** | `string \| { query: string; fields?: string[]; fuzzy?: boolean; operator?: Enum<'and' \| 'or'>; … }` | optional | Full-text search — the query text (canonical, ADR-0061 D1), or a structured FullTextSearch configuration | | **searchFields** | `string[]` | optional | Narrow the search to these fields (server-intersected with the allowed searchable set — can only narrow, never widen; ADR-0061 D1) | -| **orderBy** | `{ field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | Sorting instructions (ORDER BY) | +| **orderBy** | `{ field: string; order?: Enum<'asc' \| 'desc'> }[]` | optional | Sorting instructions (ORDER BY) | | **limit** | `number` | optional | Max records to return (LIMIT) | | **offset** | `number` | optional | Records to skip (OFFSET) | | **top** | `number` | optional | Alias for limit (OData compatibility) | diff --git a/content/docs/references/data/seed-loader.mdx b/content/docs/references/data/seed-loader.mdx index 175ed6f882a..a0628bc1fc6 100644 --- a/content/docs/references/data/seed-loader.mdx +++ b/content/docs/references/data/seed-loader.mdx @@ -62,7 +62,7 @@ Object node in the seed data dependency graph | :--- | :--- | :--- | :--- | | **object** | `string` | ✅ | Object name (snake_case) | | **dependsOn** | `string[]` | ✅ | Objects this object depends on | -| **references** | `{ field: string; targetObject: string; targetField: string; fieldType: Enum<'lookup' \| 'master_detail' \| 'user'>; … }[]` | ✅ | Field-level reference details | +| **references** | `{ field: string; targetObject: string; targetField?: string; fieldType: Enum<'lookup' \| 'master_detail' \| 'user'>; … }[]` | ✅ | Field-level reference details | --- @@ -77,7 +77,7 @@ Object node in the seed data dependency graph | :--- | :--- | :--- | :--- | | **object** | `string` | ✅ | Object name (snake_case) | | **dependsOn** | `string[]` | ✅ | Objects this object depends on | -| **references** | `{ field: string; targetObject: string; targetField: string; fieldType: Enum<'lookup' \| 'master_detail' \| 'user'>; … }[]` | ✅ | Field-level reference details | +| **references** | `{ field: string; targetObject: string; targetField?: string; fieldType: Enum<'lookup' \| 'master_detail' \| 'user'>; … }[]` | ✅ | Field-level reference details | ### Nested Shape: `ObjectDependencyNode.references[number]` @@ -219,8 +219,8 @@ Seed loader request with datasets and configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **seeds** | `{ object: string; externalId: string \| string[]; mode: Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>; env: Enum<'prod' \| 'dev' \| 'test'>[]; … }[]` | ✅ | Seeds to load | -| **config** | `{ dryRun: boolean; haltOnError: boolean; multiPass: boolean; defaultMode: Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>; … }` | optional (has default) | Loader configuration | +| **seeds** | `{ object: string; externalId?: string \| string[]; mode?: Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>; env?: Enum<'prod' \| 'dev' \| 'test'>[]; … }[]` | ✅ | Seeds to load | +| **config** | `{ dryRun?: boolean; haltOnError?: boolean; multiPass?: boolean; defaultMode?: Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>; … }` | optional (has default) | Loader configuration | ### Nested Shape: `SeedLoaderRequest.seeds[number]` @@ -268,7 +268,7 @@ Complete seed loader result | :--- | :--- | :--- | :--- | | **success** | `boolean` | ✅ | Overall success status | | **dryRun** | `boolean` | ✅ | Whether this was a dry-run | -| **dependencyGraph** | `{ nodes: object[]; 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/identity/scim.mdx b/content/docs/references/identity/scim.mdx index 89c02258d86..1eb8b13d847 100644 --- a/content/docs/references/identity/scim.mdx +++ b/content/docs/references/identity/scim.mdx @@ -274,7 +274,7 @@ const result = SCIMAddressSchema.parse(data); | :--- | :--- | :--- | :--- | | **schemas** | `string[]` | optional (default: `["urn:ietf:params:scim:api:messages:2.0:ListResponse"]`) | SCIM schema URIs | | **totalResults** | `integer` | ✅ | Total results count | -| **Resources** | `({ schemas: string[]; id?: string; externalId?: string; userName: string; … } \| { schemas: string[]; id?: string; externalId?: string; displayName: string; … } \| Record)[]` | ✅ | Resources array (Users, Groups, or custom resources) | +| **Resources** | `({ schemas?: string[]; id?: string; externalId?: string; userName: string; … } \| { schemas?: string[]; id?: string; externalId?: string; displayName: string; … } \| Record)[]` | ✅ | Resources array (Users, Groups, or custom resources) | | **startIndex** | `integer` | optional | Start index (1-based) | | **itemsPerPage** | `integer` | optional | Items per page | @@ -297,8 +297,8 @@ const result = SCIMAddressSchema.parse(data); | **timezone** | `string` | optional | Timezone | | **active** | `boolean` | optional (default: `true`) | Account active status | | **password** | `string` | optional | Password (write-only) | -| **emails** | `{ value: string; type?: Enum<'work' \| 'home' \| 'other'>; display?: string; primary: boolean }[]` | optional | Email addresses | -| **phoneNumbers** | `{ value: string; type?: Enum<'work' \| 'home' \| 'mobile' \| 'fax' \| 'pager' \| 'other'>; display?: string; primary: boolean }[]` | optional | Phone numbers | +| **emails** | `{ value: string; type?: Enum<'work' \| 'home' \| 'other'>; display?: string; primary?: boolean }[]` | optional | Email addresses | +| **phoneNumbers** | `{ value: string; type?: Enum<'work' \| 'home' \| 'mobile' \| 'fax' \| 'pager' \| 'other'>; display?: string; primary?: boolean }[]` | optional | Phone numbers | | **ims** | `{ value: string; type?: string; primary?: boolean }[]` | optional | IM addresses | | **photos** | `{ value: string; type?: Enum<'photo' \| 'thumbnail'>; primary?: boolean }[]` | optional | Photo URLs | | **addresses** | `{ formatted?: string; streetAddress?: string; locality?: string; region?: string; … }[]` | optional | Physical addresses | @@ -436,8 +436,8 @@ const result = SCIMAddressSchema.parse(data); | **timezone** | `string` | optional | Timezone | | **active** | `boolean` | optional (default: `true`) | Account active status | | **password** | `string` | optional | Password (write-only) | -| **emails** | `{ value: string; type?: Enum<'work' \| 'home' \| 'other'>; display?: string; primary: boolean }[]` | optional | Email addresses | -| **phoneNumbers** | `{ value: string; type?: Enum<'work' \| 'home' \| 'mobile' \| 'fax' \| 'pager' \| 'other'>; display?: string; primary: boolean }[]` | optional | Phone numbers | +| **emails** | `{ value: string; type?: Enum<'work' \| 'home' \| 'other'>; display?: string; primary?: boolean }[]` | optional | Email addresses | +| **phoneNumbers** | `{ value: string; type?: Enum<'work' \| 'home' \| 'mobile' \| 'fax' \| 'pager' \| 'other'>; display?: string; primary?: boolean }[]` | optional | Phone numbers | | **ims** | `{ value: string; type?: string; primary?: boolean }[]` | optional | IM addresses | | **photos** | `{ value: string; type?: Enum<'photo' \| 'thumbnail'>; primary?: boolean }[]` | optional | Photo URLs | | **addresses** | `{ formatted?: string; streetAddress?: string; locality?: string; region?: string; … }[]` | optional | Physical addresses | diff --git a/content/docs/references/integration/connector.mdx b/content/docs/references/integration/connector.mdx index 858e7508cca..02b3d7a0962 100644 --- a/content/docs/references/integration/connector.mdx +++ b/content/docs/references/integration/connector.mdx @@ -185,7 +185,7 @@ const result = ConnectorSchema.parse(data); | **type** | `Enum<'saas' \| 'database' \| 'file_storage' \| 'message_queue' \| 'api' \| 'custom'>` | ✅ | Connector type | | **description** | `string` | optional | Connector description | | **icon** | `string` | optional | Icon identifier | -| **authentication** | `{ type: 'oauth2'; authorizationUrl: string; tokenUrl: string; clientId: string; … } \| { type: 'api-key'; key: string; headerName: string; paramName?: string } \| { type: 'basic'; username: string; password: string } \| { type: 'bearer'; token: string } \| { type: 'none' }` | optional (default: `{"type":"none"}`) | Authentication configuration (runtime shape with inline secrets — plugin-supplied at registerConnector). Authored entries must not inline secrets: use `auth.credentialRef` on a provider-bound instance. | +| **authentication** | `{ type: 'oauth2'; authorizationUrl: string; tokenUrl: string; clientId: string; … } \| { type: 'api-key'; key: string; headerName?: string; paramName?: string } \| { type: 'basic'; username: string; password: string } \| { type: 'bearer'; token: string } \| { type: 'none' }` | optional (default: `{"type":"none"}`) | Authentication configuration (runtime shape with inline secrets — plugin-supplied at registerConnector). Authored entries must not inline secrets: use `auth.credentialRef` on a provider-bound instance. | | **provider** | `string` | optional | Generic-executor key that materializes this declarative entry at boot (e.g. openapi/mcp/rest). Omit for a catalog-only descriptor. Unknown provider ⇒ hard boot error (ADR-0097). | | **providerConfig** | `Record` | optional | Provider-specific config validated by the provider factory at boot (e.g. `{ spec, baseUrl }` for openapi, where spec is an inline document, a package-relative file path like './billing-openapi.json', or an http(s) URL). Requires `provider`. | | **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). | @@ -195,7 +195,7 @@ const result = ConnectorSchema.parse(data); | **fieldMappings** | `never` | optional | [REMOVED] `connector.fieldMappings` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — no engine ever moved a value through a connector field mapping: nothing read `source`, `target`, `defaultValue`, `dataType`, `required` or `syncMode`. Delete the key; the `ConnectorFieldMapping` shape leaves with it. Map fields on the sync's TARGET instead: a `mapping`'s `fieldMapping` (`source` → `target`, with a `transform` the import path executes), which its `connectorSource` pulls through. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | | **webhooks** | `never` | optional | [REMOVED] `connector.webhooks` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — a webhook nested inside a connector was never registered as a `webhook` item, so it was never materialized into `sys_webhook` and never delivered, and nothing emits the connector events its `events` list could name (`sync.completed`, `auth.expired` and the rest). Delete the key; the nested shape leaves with it (`WebhookConfig`, `WebhookEvent`, `WebhookSignatureAlgorithm`). To have a webhook actually sent, declare it in the stack's top-level `webhooks:` collection, which is materialized into `sys_webhook` and delivered on record events — note that doing so STARTS deliveries this connector never made. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | | **rateLimitConfig** | `never` | optional | [REMOVED] `connector.rateLimitConfig` was removed in @objectstack/spec 17.0.0 (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 list the mechanical edits for existing sources; apply them by hand. | -| **retryConfig** | `{ strategy: Enum<'exponential_backoff' \| 'linear_backoff' \| 'fixed_delay' \| 'no_retry'>; maxAttempts: number; initialDelayMs: number; maxDelayMs: number; … }` | optional | Retry configuration | +| **retryConfig** | `{ strategy?: Enum<'exponential_backoff' \| 'linear_backoff' \| 'fixed_delay' \| 'no_retry'>; maxAttempts?: number; initialDelayMs?: number; maxDelayMs?: number; … }` | optional | Retry configuration | | **connectionTimeoutMs** | `never` | optional | [REMOVED] `connector.connectionTimeoutMs` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — the platform never honoured it and cannot honour it where it was declared: a connector's outbound call is a WHATWG `fetch`, whose only cancellation surface is one `AbortSignal` over the whole operation, so nothing there observes the connection phase separately, and the value only ever travelled (onto the reported def and the materialization fingerprint) without ever bounding a connect. Delete the key. Use `requestTimeoutMs` for the deadline the platform does keep — it is applied as `resilientFetch`'s per-attempt timeout — and bound the connect phase at a connector provider or upstream gateway on a transport that can separate the phases. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | | **requestTimeoutMs** | `number` | optional (default: `30000`) | Request timeout in ms | | **status** | `never` | optional | [REMOVED] `connector.status` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: `status: 'active'` neither enabled nor advertised a connector, and `'error'` or `'configuring'` changed nothing either. Delete the key; the `ConnectorStatus` enum leaves with it. On a declarative entry, `enabled: false` is what withdraws a materialized instance or marks a catalog-only descriptor, and whether a registered connector can be dispatched is computed by the runtime and reported as `state` (`ready` or `degraded`) on `GET /api/v1/automation/connectors` — no authored value sets it. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | @@ -482,7 +482,7 @@ Connector type | **type** | `Enum<'saas' \| 'database' \| 'file_storage' \| 'message_queue' \| 'api' \| 'custom'>` | ✅ | Connector type | | **description** | `string` | optional | Connector description | | **icon** | `string` | optional | Icon identifier | -| **authentication** | `{ type: 'oauth2'; authorizationUrl: string; tokenUrl: string; clientId: string; … } \| { type: 'api-key'; key: string; headerName: string; paramName?: string } \| { type: 'basic'; username: string; password: string } \| { type: 'bearer'; token: string } \| { type: 'none' }` | optional (default: `{"type":"none"}`) | Authentication configuration (runtime shape with inline secrets — plugin-supplied at registerConnector). Authored entries must not inline secrets: use `auth.credentialRef` on a provider-bound instance. | +| **authentication** | `{ type: 'oauth2'; authorizationUrl: string; tokenUrl: string; clientId: string; … } \| { type: 'api-key'; key: string; headerName?: string; paramName?: string } \| { type: 'basic'; username: string; password: string } \| { type: 'bearer'; token: string } \| { type: 'none' }` | optional (default: `{"type":"none"}`) | Authentication configuration (runtime shape with inline secrets — plugin-supplied at registerConnector). Authored entries must not inline secrets: use `auth.credentialRef` on a provider-bound instance. | | **provider** | `string` | optional | Generic-executor key that materializes this declarative entry at boot (e.g. openapi/mcp/rest). Omit for a catalog-only descriptor. Unknown provider ⇒ hard boot error (ADR-0097). | | **providerConfig** | `Record` | optional | Provider-specific config validated by the provider factory at boot (e.g. `{ spec, baseUrl }` for openapi, where spec is an inline document, a package-relative file path like './billing-openapi.json', or an http(s) URL). Requires `provider`. | | **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). | @@ -492,7 +492,7 @@ Connector type | **fieldMappings** | `never` | optional | [REMOVED] `connector.fieldMappings` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — no engine ever moved a value through a connector field mapping: nothing read `source`, `target`, `defaultValue`, `dataType`, `required` or `syncMode`. Delete the key; the `ConnectorFieldMapping` shape leaves with it. Map fields on the sync's TARGET instead: a `mapping`'s `fieldMapping` (`source` → `target`, with a `transform` the import path executes), which its `connectorSource` pulls through. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | | **webhooks** | `never` | optional | [REMOVED] `connector.webhooks` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — a webhook nested inside a connector was never registered as a `webhook` item, so it was never materialized into `sys_webhook` and never delivered, and nothing emits the connector events its `events` list could name (`sync.completed`, `auth.expired` and the rest). Delete the key; the nested shape leaves with it (`WebhookConfig`, `WebhookEvent`, `WebhookSignatureAlgorithm`). To have a webhook actually sent, declare it in the stack's top-level `webhooks:` collection, which is materialized into `sys_webhook` and delivered on record events — note that doing so STARTS deliveries this connector never made. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | | **rateLimitConfig** | `never` | optional | [REMOVED] `connector.rateLimitConfig` was removed in @objectstack/spec 17.0.0 (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 list the mechanical edits for existing sources; apply them by hand. | -| **retryConfig** | `{ strategy: Enum<'exponential_backoff' \| 'linear_backoff' \| 'fixed_delay' \| 'no_retry'>; maxAttempts: number; initialDelayMs: number; maxDelayMs: number; … }` | optional | Retry configuration | +| **retryConfig** | `{ strategy?: Enum<'exponential_backoff' \| 'linear_backoff' \| 'fixed_delay' \| 'no_retry'>; maxAttempts?: number; initialDelayMs?: number; maxDelayMs?: number; … }` | optional | Retry configuration | | **connectionTimeoutMs** | `never` | optional | [REMOVED] `connector.connectionTimeoutMs` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — the platform never honoured it and cannot honour it where it was declared: a connector's outbound call is a WHATWG `fetch`, whose only cancellation surface is one `AbortSignal` over the whole operation, so nothing there observes the connection phase separately, and the value only ever travelled (onto the reported def and the materialization fingerprint) without ever bounding a connect. Delete the key. Use `requestTimeoutMs` for the deadline the platform does keep — it is applied as `resilientFetch`'s per-attempt timeout — and bound the connect phase at a connector provider or upstream gateway on a transport that can separate the phases. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | | **requestTimeoutMs** | `number` | optional (default: `30000`) | Request timeout in ms | | **status** | `never` | optional | [REMOVED] `connector.status` was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: `status: 'active'` neither enabled nor advertised a connector, and `'error'` or `'configuring'` changed nothing either. Delete the key; the `ConnectorStatus` enum leaves with it. On a declarative entry, `enabled: false` is what withdraws a materialized instance or marks a catalog-only descriptor, and whether a registered connector can be dispatched is computed by the runtime and reported as `state` (`ready` or `degraded`) on `GET /api/v1/automation/connectors` — no authored value sets it. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | diff --git a/content/docs/references/kernel/events-bus.mdx b/content/docs/references/kernel/events-bus.mdx index f44dafa6f7d..ee02e4bbe66 100644 --- a/content/docs/references/kernel/events-bus.mdx +++ b/content/docs/references/kernel/events-bus.mdx @@ -28,15 +28,15 @@ const result = EventBusConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **persistence** | `{ enabled: boolean; retentionDays: integer; filter?: any; storage: Enum<'database' \| 'file' \| 's3' \| 'custom'> }` | optional | Event persistence configuration | -| **queue** | `{ name: string; concurrency: integer; retryPolicy?: object; deadLetterQueue?: string; … }` | optional | Event queue configuration | -| **eventSourcing** | `{ enabled: boolean; snapshotInterval: integer; snapshotRetention: integer; retentionDays: integer; … }` | optional | Event sourcing configuration | -| **replay** | `{ enabled: boolean }` | optional | Event replay configuration | -| **webhooks** | `{ id?: string; eventPattern: string; url: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH'>; … }[]` | optional | Webhook configurations | -| **messageQueue** | `{ provider: Enum<'kafka' \| 'rabbitmq' \| 'aws-sqs' \| 'redis-pubsub' \| 'google-pubsub' \| 'azure-service-bus'>; topic: string; eventPattern: string; partitionKey?: string; … }` | optional | Message queue integration | -| **realtime** | `{ enabled: boolean; protocol: Enum<'websocket' \| 'sse' \| 'long-polling'>; eventPattern: string; userFilter: boolean; … }` | optional | Real-time notification configuration | -| **eventTypes** | `{ name: string; version: string; schema?: any; description?: string; … }[]` | optional | Event type definitions | -| **handlers** | `{ id?: string; eventName: string; handler: any; priority: integer; … }[]` | optional | Global event handlers | +| **persistence** | `{ enabled?: boolean; retentionDays: integer; filter?: any; storage?: Enum<'database' \| 'file' \| 's3' \| 'custom'> }` | optional | Event persistence configuration | +| **queue** | `{ name?: string; concurrency?: integer; retryPolicy?: object; deadLetterQueue?: string; … }` | optional | Event queue configuration | +| **eventSourcing** | `{ enabled?: boolean; snapshotInterval?: integer; snapshotRetention?: integer; retentionDays?: integer; … }` | optional | Event sourcing configuration | +| **replay** | `{ enabled?: boolean }` | optional | Event replay configuration | +| **webhooks** | `{ id?: string; eventPattern: string; url: string; method?: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH'>; … }[]` | optional | Webhook configurations | +| **messageQueue** | `{ provider: Enum<'kafka' \| 'rabbitmq' \| 'aws-sqs' \| 'redis-pubsub' \| 'google-pubsub' \| 'azure-service-bus'>; topic: string; eventPattern?: string; partitionKey?: string; … }` | optional | Message queue integration | +| **realtime** | `{ enabled?: boolean; protocol?: Enum<'websocket' \| 'sse' \| 'long-polling'>; eventPattern?: string; userFilter?: boolean; … }` | optional | Real-time notification configuration | +| **eventTypes** | `{ name: string; version?: string; schema?: any; description?: string; … }[]` | optional | Event type definitions | +| **handlers** | `{ id?: string; eventName: string; handler: any; priority?: integer; … }[]` | optional | Global event handlers | ### Nested Shape: `EventBusConfig.persistence` @@ -54,7 +54,7 @@ const result = EventBusConfigSchema.parse(data); | :--- | :--- | :--- | :--- | | **name** | `string` | optional (default: `"events"`) | Event queue name | | **concurrency** | `integer` | optional (default: `10`) | Max concurrent event handlers | -| **retryPolicy** | `{ maxRetries: integer; backoffStrategy: Enum<'fixed' \| 'linear' \| 'exponential'>; initialDelayMs: integer; maxDelayMs: integer }` | optional | Default retry policy for events | +| **retryPolicy** | `{ maxRetries?: integer; backoffStrategy?: Enum<'fixed' \| 'linear' \| 'exponential'>; initialDelayMs?: integer; maxDelayMs?: integer }` | optional | Default retry policy for events | | **deadLetterQueue** | `string` | optional | Dead letter queue name for failed events | | **priorityEnabled** | `boolean` | optional (default: `true`) | Process events based on priority | @@ -68,7 +68,7 @@ const result = EventBusConfigSchema.parse(data); | **retentionDays** | `integer` | optional (default: `365`) | Days to retain events | | **retention** | `never` | optional | [REMOVED] `EventSourcingConfig.retention` was renamed to `retentionDays` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Rename the key to `retentionDays`; the value (days) is unchanged. The neighbouring `snapshotRetention` is a COUNT of snapshots, not a duration, so it keeps its name. | | **aggregateTypes** | `string[]` | optional | Aggregate types to enable event sourcing for | -| **storage** | `{ type: Enum<'database' \| 'file' \| 's3' \| 'eventstore'>; options?: Record }` | optional | Event store configuration | +| **storage** | `{ type?: Enum<'database' \| 'file' \| 's3' \| 'eventstore'>; options?: Record }` | optional | Event store configuration | ### Nested Shape: `EventBusConfig.replay` @@ -86,7 +86,7 @@ const result = EventBusConfigSchema.parse(data); | **method** | `Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH'>` | optional (default: `"POST"`) | HTTP method | | **headers** | `Record` | optional | HTTP headers | | **authentication** | `{ type: Enum<'none' \| 'bearer' \| 'basic' \| 'api-key'>; credentials?: Record }` | optional | Authentication configuration | -| **retryPolicy** | `{ maxRetries: integer; backoffStrategy: Enum<'fixed' \| 'linear' \| 'exponential'>; initialDelayMs: integer; maxDelayMs: integer }` | optional | Retry policy | +| **retryPolicy** | `{ maxRetries?: integer; backoffStrategy?: Enum<'fixed' \| 'linear' \| 'exponential'>; initialDelayMs?: integer; maxDelayMs?: integer }` | optional | Retry policy | | **timeoutMs** | `integer` | optional (default: `30000`) | Request timeout in milliseconds | | **transform** | `any` | optional | Transform event before sending | | **enabled** | `boolean` | optional (default: `true`) | Whether webhook is enabled | @@ -115,7 +115,7 @@ const result = EventBusConfigSchema.parse(data); | **userFilter** | `boolean` | optional (default: `true`) | Filter events by user | | **tenantFilter** | `boolean` | optional (default: `true`) | Filter events by tenant | | **channels** | `{ name: string; eventPattern: string; filter?: any }[]` | optional | Named channels for event broadcasting | -| **rateLimit** | `{ maxEventsPerSecond: integer; windowMs: integer }` | optional | Rate limiting configuration | +| **rateLimit** | `{ maxEventsPerSecond: integer; windowMs?: integer }` | optional | Rate limiting configuration | ### Nested Shape: `EventBusConfig.eventTypes[number]` @@ -137,7 +137,7 @@ const result = EventBusConfigSchema.parse(data); | **handler** | `any` | ✅ | Handler function | | **priority** | `integer` | optional (default: `0`) | Execution priority (lower numbers execute first) | | **async** | `boolean` | optional (default: `true`) | Execute in background (true) or block (false) | -| **retry** | `{ maxRetries: integer; backoffMs: integer; backoffMultiplier: number }` | optional | Retry policy for failed handlers | +| **retry** | `{ maxRetries?: integer; backoffMs?: integer; backoffMultiplier?: number }` | optional | Retry policy for failed handlers | | **timeoutMs** | `integer` | optional | Handler timeout in milliseconds | | **filter** | `any` | optional | Optional filter to determine if handler should execute | diff --git a/content/docs/references/kernel/events-core.mdx b/content/docs/references/kernel/events-core.mdx index 67e81d3cc28..1e68cfde83a 100644 --- a/content/docs/references/kernel/events-core.mdx +++ b/content/docs/references/kernel/events-core.mdx @@ -44,7 +44,7 @@ const result = EventSchema.parse(data); | **correlationId** | `string` | optional | Correlation ID for event tracing | | **causationId** | `string` | optional | ID of the event that caused this event | | **priority** | `Enum<'critical' \| 'high' \| 'normal' \| 'low' \| 'background'>` | optional (default: `"normal"`) | Event priority | -| **cluster** | `{ scope: Enum<'local' \| 'cluster' \| 'tenant'>; deliverySemantics?: Enum<'best-effort' \| 'at-least-once' \| 'exactly-once'>; partitionKey?: string }` | optional | Per-emit cluster routing & delivery options. See /docs/kernel/cluster §4. | +| **cluster** | `{ scope?: Enum<'local' \| 'cluster' \| 'tenant'>; deliverySemantics?: Enum<'best-effort' \| 'at-least-once' \| 'exactly-once'>; partitionKey?: string }` | optional | Per-emit cluster routing & delivery options. See /docs/kernel/cluster §4. | --- @@ -62,7 +62,7 @@ const result = EventSchema.parse(data); | **correlationId** | `string` | optional | Correlation ID for event tracing | | **causationId** | `string` | optional | ID of the event that caused this event | | **priority** | `Enum<'critical' \| 'high' \| 'normal' \| 'low' \| 'background'>` | optional (default: `"normal"`) | Event priority | -| **cluster** | `{ scope: Enum<'local' \| 'cluster' \| 'tenant'>; deliverySemantics?: Enum<'best-effort' \| 'at-least-once' \| 'exactly-once'>; partitionKey?: string }` | optional | Per-emit cluster routing & delivery options. See /docs/kernel/cluster §4. | +| **cluster** | `{ scope?: Enum<'local' \| 'cluster' \| 'tenant'>; deliverySemantics?: Enum<'best-effort' \| 'at-least-once' \| 'exactly-once'>; partitionKey?: string }` | optional | Per-emit cluster routing & delivery options. See /docs/kernel/cluster §4. | ### Nested Shape: `EventMetadata.cluster` diff --git a/content/docs/references/kernel/events-handlers.mdx b/content/docs/references/kernel/events-handlers.mdx index d08764824bd..ee760308c89 100644 --- a/content/docs/references/kernel/events-handlers.mdx +++ b/content/docs/references/kernel/events-handlers.mdx @@ -33,7 +33,7 @@ const result = EventHandlerSchema.parse(data); | **handler** | `any` | ✅ | Handler function | | **priority** | `integer` | optional (default: `0`) | Execution priority (lower numbers execute first) | | **async** | `boolean` | optional (default: `true`) | Execute in background (true) or block (false) | -| **retry** | `{ maxRetries: integer; backoffMs: integer; backoffMultiplier: number }` | optional | Retry policy for failed handlers | +| **retry** | `{ maxRetries?: integer; backoffMs?: integer; backoffMultiplier?: number }` | optional | Retry policy for failed handlers | | **timeoutMs** | `integer` | optional | Handler timeout in milliseconds | | **filter** | `any` | optional | Optional filter to determine if handler should execute | diff --git a/content/docs/references/kernel/events-integrations.mdx b/content/docs/references/kernel/events-integrations.mdx index 18ced1dcfb8..3aae0ed817d 100644 --- a/content/docs/references/kernel/events-integrations.mdx +++ b/content/docs/references/kernel/events-integrations.mdx @@ -53,7 +53,7 @@ const result = EventMessageQueueConfigSchema.parse(data); | **method** | `Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH'>` | optional (default: `"POST"`) | HTTP method | | **headers** | `Record` | optional | HTTP headers | | **authentication** | `{ type: Enum<'none' \| 'bearer' \| 'basic' \| 'api-key'>; credentials?: Record }` | optional | Authentication configuration | -| **retryPolicy** | `{ maxRetries: integer; backoffStrategy: Enum<'fixed' \| 'linear' \| 'exponential'>; initialDelayMs: integer; maxDelayMs: integer }` | optional | Retry policy | +| **retryPolicy** | `{ maxRetries?: integer; backoffStrategy?: Enum<'fixed' \| 'linear' \| 'exponential'>; initialDelayMs?: integer; maxDelayMs?: integer }` | optional | Retry policy | | **timeoutMs** | `integer` | optional (default: `30000`) | Request timeout in milliseconds | | **transform** | `any` | optional | Transform event before sending | | **enabled** | `boolean` | optional (default: `true`) | Whether webhook is enabled | @@ -89,7 +89,7 @@ const result = EventMessageQueueConfigSchema.parse(data); | **userFilter** | `boolean` | optional (default: `true`) | Filter events by user | | **tenantFilter** | `boolean` | optional (default: `true`) | Filter events by tenant | | **channels** | `{ name: string; eventPattern: string; filter?: any }[]` | optional | Named channels for event broadcasting | -| **rateLimit** | `{ maxEventsPerSecond: integer; windowMs: integer }` | optional | Rate limiting configuration | +| **rateLimit** | `{ maxEventsPerSecond: integer; windowMs?: integer }` | optional | Rate limiting configuration | ### Nested Shape: `RealTimeNotificationConfig.channels[number]` diff --git a/content/docs/references/kernel/events-queue.mdx b/content/docs/references/kernel/events-queue.mdx index 9bd88c4bdc8..5a01c582705 100644 --- a/content/docs/references/kernel/events-queue.mdx +++ b/content/docs/references/kernel/events-queue.mdx @@ -30,7 +30,7 @@ const result = EventQueueConfigSchema.parse(data); | :--- | :--- | :--- | :--- | | **name** | `string` | optional (default: `"events"`) | Event queue name | | **concurrency** | `integer` | optional (default: `10`) | Max concurrent event handlers | -| **retryPolicy** | `{ maxRetries: integer; backoffStrategy: Enum<'fixed' \| 'linear' \| 'exponential'>; initialDelayMs: integer; maxDelayMs: integer }` | optional | Default retry policy for events | +| **retryPolicy** | `{ maxRetries?: integer; backoffStrategy?: Enum<'fixed' \| 'linear' \| 'exponential'>; initialDelayMs?: integer; maxDelayMs?: integer }` | optional | Default retry policy for events | | **deadLetterQueue** | `string` | optional | Dead letter queue name for failed events | | **priorityEnabled** | `boolean` | optional (default: `true`) | Process events based on priority | @@ -74,7 +74,7 @@ const result = EventQueueConfigSchema.parse(data); | **retentionDays** | `integer` | optional (default: `365`) | Days to retain events | | **retention** | `never` | optional | [REMOVED] `EventSourcingConfig.retention` was renamed to `retentionDays` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Rename the key to `retentionDays`; the value (days) is unchanged. The neighbouring `snapshotRetention` is a COUNT of snapshots, not a duration, so it keeps its name. | | **aggregateTypes** | `string[]` | optional | Aggregate types to enable event sourcing for | -| **storage** | `{ type: Enum<'database' \| 'file' \| 's3' \| 'eventstore'>; options?: Record }` | optional | Event store configuration | +| **storage** | `{ type?: Enum<'database' \| 'file' \| 's3' \| 'eventstore'>; options?: Record }` | optional | Event store configuration | ### Nested Shape: `EventSourcingConfig.storage` diff --git a/content/docs/references/kernel/metadata-loader.mdx b/content/docs/references/kernel/metadata-loader.mdx index 3557d6f1757..5418fd8bd93 100644 --- a/content/docs/references/kernel/metadata-loader.mdx +++ b/content/docs/references/kernel/metadata-loader.mdx @@ -52,10 +52,10 @@ const result = MetadataFallbackStrategySchema.parse(data); | **formats** | `Enum<'yaml' \| 'json' \| 'typescript' \| 'javascript'>[]` | optional (default: `["typescript","json","yaml"]`) | Enabled formats | | **cache** | `{ databaseLoader?: object }` | optional | Cache settings — only `databaseLoader` is read at runtime; the outer keys are retired | | **watch** | `boolean` | optional (default: `false`) | Enable file watching | -| **watchOptions** | `{ ignored?: string[]; persistent: boolean; ignoreInitial: boolean }` | optional | File watcher options | -| **validation** | `{ strict: boolean; throwOnError: boolean }` | optional | Validation settings | +| **watchOptions** | `{ ignored?: string[]; persistent?: boolean; ignoreInitial?: boolean }` | optional | File watcher options | +| **validation** | `{ strict?: boolean; throwOnError?: boolean }` | optional | Validation settings | | **loaderOptions** | `Record` | optional | Loader-specific configuration | -| **persistence** | `{ writable: boolean }` | optional | Persistence write gates | +| **persistence** | `{ writable?: boolean }` | optional | Persistence write gates | ### Nested Shape: `MetadataManagerConfig.cache` @@ -65,7 +65,7 @@ const result = MetadataFallbackStrategySchema.parse(data); | **ttlSeconds** | `never` | optional | [REMOVED] `cache.ttlSeconds` was removed from `MetadataManagerConfig` in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: the outer `cache` block was declared and documented but consumed by no runtime, so the number expired nothing. Delete the key. The TTL that is honoured is `cache.databaseLoader.ttlMs` (milliseconds, default 60000) on the DatabaseLoader read-through cache. | | **ttl** | `never` | optional | [REMOVED] `cache.ttl` was removed from `MetadataManagerConfig` in @objectstack/spec 17 — nothing ever read it: the outer `cache` block was declared and documented but consumed by no runtime, and its unit-suffixed respelling `ttlSeconds` was retired with it before it shipped (ADR-0049 enforce-or-remove). Delete the key. The TTL that is honoured is `cache.databaseLoader.ttlMs` (milliseconds, default 60000) on the DatabaseLoader read-through cache. | | **maxSize** | `never` | optional | [REMOVED] `cache.maxSize` was removed from `MetadataManagerConfig` in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: the outer `cache` block was declared and documented but consumed by no runtime, so the byte cap capped nothing. Delete the key. The cap that is honoured is `cache.databaseLoader.maxSize` (an entry count, default 500) on the DatabaseLoader read-through cache. | -| **databaseLoader** | `{ enabled: boolean; maxSize: integer; ttlMs: integer }` | optional | DatabaseLoader read-through cache | +| **databaseLoader** | `{ enabled?: boolean; maxSize?: integer; ttlMs?: integer }` | optional | DatabaseLoader read-through cache | ### Nested Shape: `MetadataManagerConfig.watchOptions` diff --git a/content/docs/references/kernel/metadata-plugin.mdx b/content/docs/references/kernel/metadata-plugin.mdx index 0c6c114c0ff..f74024aa5c1 100644 --- a/content/docs/references/kernel/metadata-plugin.mdx +++ b/content/docs/references/kernel/metadata-plugin.mdx @@ -100,7 +100,7 @@ const result = MetadataBulkResultSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **storage** | `{ datasource?: string; tableName: string; fallback: Enum<'filesystem' \| 'memory' \| 'none'>; rootDir?: string; … }` | ✅ | Storage backend configuration | +| **storage** | `{ datasource?: string; tableName?: string; fallback?: Enum<'filesystem' \| 'memory' \| 'none'>; rootDir?: string; … }` | ✅ | Storage backend configuration | | **customizationPolicies** | `never` | optional | [REMOVED] `config.customizationPolicies` was removed from `MetadataPluginConfig` in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — it never had an effect: no code ever read a customization policy, and the overlay protocol it configured was itself unreachable from any served surface (ADR-0126 supersedes it on the record). Delete the key. What a customization may touch is governed by the real mechanisms: ADR-0005's org-scoped overlay (opt-in via `allowOrgOverride` on `DEFAULT_METADATA_TYPE_REGISTRY`, enforced at the REST meta write doors) and ADR-0126's packaged-metadata model (clone + ledger disable). | | **mergeStrategy** | `never` | optional | [REMOVED] `config.mergeStrategy` was removed from `MetadataPluginConfig` in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — it never had an effect: no 3-way merge engine ever existed to read it, and package upgrades do not merge customizations (ADR-0126: upgrades rewrite the packaged base; customer choices live in the ledger and are never merged). Delete the key. There is no replacement — upgrade-vs-customization separation is the model, not a configurable strategy. | | **additionalTypes** | `never` | optional | [REMOVED] `config.additionalTypes` was removed from `MetadataPluginConfig` in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — it never had an effect: the only production writer of the metadata type registry is `setTypeRegistry(DEFAULT_METADATA_TYPE_REGISTRY)`, which replaces the array outright, so nothing ever merged these entries and the live type set was exactly the built-in registry whatever you declared here. Delete the key. There is no declared-kind channel: a kind enters the live metadata-type set as a side effect of registering an ITEM of that kind (`SchemaRegistry.registerItem` during app/manifest registration, or `MetadataManager.register` at runtime); bind its schema with `registerMetadataTypeSchema(type, schema)` from your plugin's `init(ctx)` so `GET /api/v1/meta` serves a real JSON Schema for it. | @@ -121,10 +121,10 @@ const result = MetadataBulkResultSchema.parse(data); | **formats** | `Enum<'yaml' \| 'json' \| 'typescript' \| 'javascript'>[]` | optional (default: `["typescript","json","yaml"]`) | Enabled formats | | **cache** | `{ databaseLoader?: object }` | optional | Cache settings — only `databaseLoader` is read at runtime; the outer keys are retired | | **watch** | `boolean` | optional (default: `false`) | Enable file watching | -| **watchOptions** | `{ ignored?: string[]; persistent: boolean; ignoreInitial: boolean }` | optional | File watcher options | -| **validation** | `{ strict: boolean; throwOnError: boolean }` | optional | Validation settings | +| **watchOptions** | `{ ignored?: string[]; persistent?: boolean; ignoreInitial?: boolean }` | optional | File watcher options | +| **validation** | `{ strict?: boolean; throwOnError?: boolean }` | optional | Validation settings | | **loaderOptions** | `Record` | optional | Loader-specific configuration | -| **persistence** | `{ writable: boolean }` | optional | Persistence write gates | +| **persistence** | `{ writable?: boolean }` | optional | Persistence write gates | --- @@ -140,8 +140,8 @@ const result = MetadataBulkResultSchema.parse(data); | **version** | `string` | ✅ | Plugin version (SemVer 2.0.0 — e.g. 1.2.3, 2.0.0-beta.1) | | **type** | `'standard'` | ✅ | Plugin type | | **description** | `string` | optional (default: `"Core metadata management service for ObjectStack platform"`) | Plugin description | -| **capabilities** | `{ crud: boolean; query: boolean; overlay: boolean; watch: boolean; … }` | ✅ | Plugin capabilities | -| **config** | `{ storage: object; enableEvents: boolean; validateOnWrite: boolean; enableVersioning: boolean; … }` | optional | Plugin configuration | +| **capabilities** | `{ crud?: boolean; query?: boolean; overlay?: boolean; watch?: boolean; … }` | ✅ | Plugin capabilities | +| **config** | `{ storage: object; enableEvents?: boolean; validateOnWrite?: boolean; enableVersioning?: boolean; … }` | optional | Plugin configuration | ### Nested Shape: `MetadataPluginManifest.capabilities` @@ -160,7 +160,7 @@ const result = MetadataBulkResultSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **storage** | `{ datasource?: string; tableName: string; fallback: Enum<'filesystem' \| 'memory' \| 'none'>; rootDir?: string; … }` | ✅ | Storage backend configuration | +| **storage** | `{ datasource?: string; tableName?: string; fallback?: Enum<'filesystem' \| 'memory' \| 'none'>; rootDir?: string; … }` | ✅ | Storage backend configuration | | **customizationPolicies** | `never` | optional | [REMOVED] `config.customizationPolicies` was removed from `MetadataPluginConfig` in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — it never had an effect: no code ever read a customization policy, and the overlay protocol it configured was itself unreachable from any served surface (ADR-0126 supersedes it on the record). Delete the key. What a customization may touch is governed by the real mechanisms: ADR-0005's org-scoped overlay (opt-in via `allowOrgOverride` on `DEFAULT_METADATA_TYPE_REGISTRY`, enforced at the REST meta write doors) and ADR-0126's packaged-metadata model (clone + ledger disable). | | **mergeStrategy** | `never` | optional | [REMOVED] `config.mergeStrategy` was removed from `MetadataPluginConfig` in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — it never had an effect: no 3-way merge engine ever existed to read it, and package upgrades do not merge customizations (ADR-0126: upgrades rewrite the packaged base; customer choices live in the ledger and are never merged). Delete the key. There is no replacement — upgrade-vs-customization separation is the model, not a configurable strategy. | | **additionalTypes** | `never` | optional | [REMOVED] `config.additionalTypes` was removed from `MetadataPluginConfig` in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — it never had an effect: the only production writer of the metadata type registry is `setTypeRegistry(DEFAULT_METADATA_TYPE_REGISTRY)`, which replaces the array outright, so nothing ever merged these entries and the live type set was exactly the built-in registry whatever you declared here. Delete the key. There is no declared-kind channel: a kind enters the live metadata-type set as a side effect of registering an ITEM of that kind (`SchemaRegistry.registerItem` during app/manifest registration, or `MetadataManager.register` at runtime); bind its schema with `registerMetadataTypeSchema(type, schema)` from your plugin's `init(ctx)` so `GET /api/v1/meta` serves a real JSON Schema for it. | diff --git a/content/docs/references/kernel/package-artifact.mdx b/content/docs/references/kernel/package-artifact.mdx index 035cb848b47..93e7ae6f9dc 100644 --- a/content/docs/references/kernel/package-artifact.mdx +++ b/content/docs/references/kernel/package-artifact.mdx @@ -161,8 +161,8 @@ Package artifact structure and metadata | **builtWith** | `string` | optional | Build tool identifier (e.g. "os-cli@3.2.0") | | **files** | `{ path: string; size: integer; category?: Enum<'objects' \| 'views' \| 'pages' \| 'flows' \| 'dashboards' \| 'permissions' \| …> }[]` | optional | List of files contained in the artifact | | **metadataCategories** | `Enum<'objects' \| 'views' \| 'pages' \| 'flows' \| 'dashboards' \| 'permissions' \| 'agents' \| 'reports' \| 'actions' \| 'translations' \| 'themes' \| 'datasets' \| 'apis' \| 'triggers' \| 'workflows'>[]` | optional | Metadata categories included in this artifact | -| **checksums** | `{ algorithm: Enum<'sha256' \| 'sha384' \| 'sha512'>; files: Record }` | optional | SHA256 checksums for artifact integrity verification | -| **signature** | `{ algorithm: Enum<'RSA-SHA256' \| 'RSA-SHA384' \| 'RSA-SHA512' \| 'ECDSA-SHA256'>; publicKeyRef: string; signature: string; signedAt?: string; … }` | optional | Digital signature for artifact authenticity verification | +| **checksums** | `{ algorithm?: Enum<'sha256' \| 'sha384' \| 'sha512'>; files: Record }` | optional | SHA256 checksums for artifact integrity verification | +| **signature** | `{ algorithm?: Enum<'RSA-SHA256' \| 'RSA-SHA384' \| 'RSA-SHA512' \| 'ECDSA-SHA256'>; publicKeyRef: string; signature: string; signedAt?: string; … }` | optional | Digital signature for artifact authenticity verification | ### Nested Shape: `PackageArtifact.files[number]` diff --git a/content/docs/references/kernel/package-upgrade.mdx b/content/docs/references/kernel/package-upgrade.mdx index e9f1f59696b..8ff3ad5963f 100644 --- a/content/docs/references/kernel/package-upgrade.mdx +++ b/content/docs/references/kernel/package-upgrade.mdx @@ -194,7 +194,7 @@ Upgrade package response | **fromVersion** | `string` | ✅ | Currently installed version | | **toVersion** | `string` | ✅ | Target upgrade version | | **impactLevel** | `Enum<'none' \| 'low' \| 'medium' \| 'high' \| 'critical'>` | ✅ | Severity assessment from none (seamless) to critical (breaking changes) | -| **changes** | `{ type: string; name: string; changeType: Enum<'added' \| 'modified' \| 'removed' \| 'renamed'>; hasConflict: boolean; … }[]` | ✅ | All metadata changes | +| **changes** | `{ type: string; name: string; changeType: Enum<'added' \| 'modified' \| 'removed' \| 'renamed'>; hasConflict?: boolean; … }[]` | ✅ | All metadata changes | | **affectedCustomizations** | `integer` | optional (default: `0`) | Count of customizations that may be affected | | **requiresMigration** | `boolean` | optional (default: `false`) | Whether data migration scripts are needed | | **migrationScripts** | `string[]` | optional | Paths to migration scripts | @@ -238,7 +238,7 @@ Upgrade analysis plan generated before execution | **fromVersion** | `string` | ✅ | Currently installed version | | **toVersion** | `string` | ✅ | Target upgrade version | | **impactLevel** | `Enum<'none' \| 'low' \| 'medium' \| 'high' \| 'critical'>` | ✅ | Severity assessment from none (seamless) to critical (breaking changes) | -| **changes** | `{ type: string; name: string; changeType: Enum<'added' \| 'modified' \| 'removed' \| 'renamed'>; hasConflict: boolean; … }[]` | ✅ | All metadata changes | +| **changes** | `{ type: string; name: string; changeType: Enum<'added' \| 'modified' \| 'removed' \| 'renamed'>; hasConflict?: boolean; … }[]` | ✅ | All metadata changes | | **affectedCustomizations** | `integer` | optional (default: `0`) | Count of customizations that may be affected | | **requiresMigration** | `boolean` | optional (default: `false`) | Whether data migration scripts are needed | | **migrationScripts** | `string[]` | optional | Paths to migration scripts | diff --git a/content/docs/references/kernel/plugin-capability.mdx b/content/docs/references/kernel/plugin-capability.mdx index 7afdef64152..0e2c201aec7 100644 --- a/content/docs/references/kernel/plugin-capability.mdx +++ b/content/docs/references/kernel/plugin-capability.mdx @@ -79,7 +79,7 @@ Level of protocol conformance | **protocol** | `{ id: string; label: string; version: object; specification?: string; … }` | ✅ | | | **conformance** | `Enum<'full' \| 'partial' \| 'experimental' \| 'deprecated'>` | optional (default: `"full"`) | Level of protocol conformance | | **implementedFeatures** | `string[]` | optional | List of implemented feature names | -| **features** | `{ name: string; enabled: boolean; description?: string; sinceVersion?: string; … }[]` | optional | | +| **features** | `{ name: string; enabled?: boolean; description?: string; sinceVersion?: string; … }[]` | optional | | | **metadata** | `Record` | optional | | | **certified** | `boolean` | optional (default: `false`) | Has passed official conformance tests | | **certificationDate** | `string` | optional | | @@ -113,11 +113,11 @@ Level of protocol conformance | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **implements** | `{ protocol: object; conformance: Enum<'full' \| 'partial' \| 'experimental' \| 'deprecated'>; implementedFeatures?: string[]; features?: object[]; … }[]` | 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 | +| **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 | -| **extensions** | `{ targetPluginId: string; extensionPointId: string; implementation: string; priority: integer }[]` | optional | Extensions contributed to other plugins | +| **extensions** | `{ targetPluginId: string; extensionPointId: string; implementation: string; priority?: integer }[]` | optional | Extensions contributed to other plugins | ### Nested Shape: `PluginCapabilityManifest.implements[number]` @@ -126,7 +126,7 @@ Level of protocol conformance | **protocol** | `{ id: string; label: string; version: object; specification?: string; … }` | ✅ | | | **conformance** | `Enum<'full' \| 'partial' \| 'experimental' \| 'deprecated'>` | optional (default: `"full"`) | Level of protocol conformance | | **implementedFeatures** | `string[]` | optional | List of implemented feature names | -| **features** | `{ name: string; enabled: boolean; description?: string; sinceVersion?: string; … }[]` | optional | | +| **features** | `{ name: string; enabled?: boolean; description?: string; sinceVersion?: string; … }[]` | optional | | | **metadata** | `Record` | optional | | | **certified** | `boolean` | optional (default: `false`) | Has passed official conformance tests | | **certificationDate** | `string` | optional | | @@ -211,7 +211,7 @@ Level of protocol conformance | :--- | :--- | :--- | :--- | | **name** | `string` | ✅ | Method name | | **description** | `string` | optional | | -| **parameters** | `{ name: string; type: string; required: boolean; description?: string }[]` | optional | | +| **parameters** | `{ name: string; type: string; required?: boolean; description?: string }[]` | optional | | | **returnType** | `string` | optional | Return value type | | **async** | `boolean` | optional (default: `false`) | Whether method returns a Promise | diff --git a/content/docs/references/kernel/plugin-lifecycle-advanced.mdx b/content/docs/references/kernel/plugin-lifecycle-advanced.mdx index 2bc5ca3d130..bb98f21c54e 100644 --- a/content/docs/references/kernel/plugin-lifecycle-advanced.mdx +++ b/content/docs/references/kernel/plugin-lifecycle-advanced.mdx @@ -146,7 +146,7 @@ Current health status of the plugin | **version** | `string` | ✅ | | | **timestamp** | `string` | ✅ | | | **state** | `Record` | ✅ | | -| **metadata** | `{ checksum?: string; compressed: boolean; encryption?: string }` | optional | | +| **metadata** | `{ checksum?: string; compressed?: boolean; encryption?: string }` | optional | | ### Nested Shape: `PluginStateSnapshot.metadata` diff --git a/content/docs/references/kernel/plugin-registry.mdx b/content/docs/references/kernel/plugin-registry.mdx index dfbecac3494..880b165cc32 100644 --- a/content/docs/references/kernel/plugin-registry.mdx +++ b/content/docs/references/kernel/plugin-registry.mdx @@ -87,7 +87,7 @@ const result = PluginInstallConfigSchema.parse(data); | **links** | `{ homepage?: string; repository?: string; documentation?: string; bugs?: string; … }` | optional | | | **media** | `{ icon?: string; logo?: string; screenshots?: string[]; video?: string }` | optional | | | **quality** | `{ testCoverage?: number; documentationScore?: number; codeQuality?: number; conformanceTests?: object[] }` | optional | | -| **statistics** | `{ downloads: integer; downloadsLastMonth: integer; activeInstallations: integer; ratings?: object; … }` | optional | | +| **statistics** | `{ downloads?: integer; downloadsLastMonth?: integer; activeInstallations?: integer; ratings?: object; … }` | optional | | | **license** | `string` | optional | SPDX license identifier | | **pricing** | `{ model: Enum<'free' \| 'freemium' \| 'paid' \| 'enterprise'>; price?: number; currency?: string; billingPeriod?: Enum<'one-time' \| 'monthly' \| 'yearly'> }` | optional | | | **publishedAt** | `string` | optional | | @@ -95,7 +95,7 @@ const result = PluginInstallConfigSchema.parse(data); | **deprecated** | `boolean` | optional (default: `false`) | | | **deprecationMessage** | `string` | optional | | | **replacedBy** | `string` | optional | Plugin ID that replaces this one | -| **flags** | `{ experimental: boolean; beta: boolean; featured: boolean; verified: boolean }` | optional | | +| **flags** | `{ experimental?: boolean; beta?: boolean; featured?: boolean; verified?: boolean }` | optional | | ### Nested Shape: `PluginRegistryEntry.vendor` @@ -112,11 +112,11 @@ const result = PluginInstallConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **implements** | `{ protocol: object; conformance: Enum<'full' \| 'partial' \| 'experimental' \| 'deprecated'>; implementedFeatures?: string[]; features?: object[]; … }[]` | 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 | +| **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 | -| **extensions** | `{ targetPluginId: string; extensionPointId: string; implementation: string; priority: integer }[]` | optional | Extensions contributed to other plugins | +| **extensions** | `{ targetPluginId: string; extensionPointId: string; implementation: string; priority?: integer }[]` | optional | Extensions contributed to other plugins | ### Nested Shape: `PluginRegistryEntry.quality` @@ -161,7 +161,7 @@ const result = PluginInstallConfigSchema.parse(data); | **downloads** | `integer` | optional (default: `0`) | | | **downloadsLastMonth** | `integer` | optional (default: `0`) | | | **activeInstallations** | `integer` | optional (default: `0`) | | -| **ratings** | `{ average: number; count: integer; distribution?: object }` | optional | | +| **ratings** | `{ average?: number; count?: integer; distribution?: object }` | optional | | | **stars** | `integer` | optional | | | **dependents** | `integer` | optional (default: `0`) | | diff --git a/content/docs/references/kernel/plugin-security-advanced.mdx b/content/docs/references/kernel/plugin-security-advanced.mdx index 559e7726b59..10cdc5d4832 100644 --- a/content/docs/references/kernel/plugin-security-advanced.mdx +++ b/content/docs/references/kernel/plugin-security-advanced.mdx @@ -47,12 +47,12 @@ const result = KernelSecurityPolicySchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **csp** | `{ directives?: Record; reportOnly: boolean }` | optional | | -| **cors** | `{ allowedOrigins: string[]; allowedMethods: string[]; allowedHeaders: string[]; allowCredentials: boolean; … }` | optional | | -| **rateLimit** | `{ enabled: boolean; maxRequests: integer; windowMs: integer; strategy: Enum<'fixed' \| 'sliding' \| 'token-bucket'> }` | optional | | -| **authentication** | `{ required: boolean; methods: Enum<'jwt' \| 'oauth2' \| 'api-key' \| 'session' \| 'certificate'>[]; tokenExpirationSeconds?: integer }` | optional | | -| **encryption** | `{ dataAtRest: boolean; dataInTransit: boolean; algorithm?: string; minKeyLength?: integer }` | optional | | -| **auditLog** | `{ enabled: boolean; events?: string[]; retentionDays?: integer }` | optional | | +| **csp** | `{ directives?: Record; reportOnly?: boolean }` | optional | | +| **cors** | `{ allowedOrigins: string[]; allowedMethods: string[]; allowedHeaders: string[]; allowCredentials?: boolean; … }` | optional | | +| **rateLimit** | `{ enabled?: boolean; maxRequests: integer; windowMs: integer; strategy?: Enum<'fixed' \| 'sliding' \| 'token-bucket'> }` | optional | | +| **authentication** | `{ required?: boolean; methods: Enum<'jwt' \| 'oauth2' \| 'api-key' \| 'session' \| 'certificate'>[]; tokenExpirationSeconds?: integer }` | optional | | +| **encryption** | `{ dataAtRest?: boolean; dataInTransit?: boolean; algorithm?: string; minKeyLength?: integer }` | optional | | +| **auditLog** | `{ enabled?: boolean; events?: string[]; retentionDays?: integer }` | optional | | ### Nested Shape: `KernelSecurityPolicy.cors` @@ -343,13 +343,13 @@ Type of resource being accessed | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | optional (default: `true`) | | | **level** | `Enum<'none' \| 'minimal' \| 'standard' \| 'strict' \| 'paranoid'>` | optional (default: `"standard"`) | | -| **runtime** | `{ engine: Enum<'v8-isolate' \| 'wasm' \| 'container' \| 'process'>; engineConfig?: object; resourceLimits?: object }` | optional | Execution environment and isolation settings | -| **filesystem** | `{ mode: Enum<'none' \| 'readonly' \| 'restricted' \| 'full'>; allowedPaths?: string[]; deniedPaths?: string[]; maxFileSize?: integer }` | optional | | -| **network** | `{ mode: Enum<'none' \| 'local' \| 'restricted' \| 'full'>; allowedHosts?: string[]; deniedHosts?: string[]; allowedPorts?: number[]; … }` | optional | | -| **process** | `{ allowSpawn: boolean; allowedCommands?: string[]; timeoutMs?: integer }` | optional | | +| **runtime** | `{ engine?: Enum<'v8-isolate' \| 'wasm' \| 'container' \| 'process'>; engineConfig?: object; resourceLimits?: object }` | optional | Execution environment and isolation settings | +| **filesystem** | `{ mode?: Enum<'none' \| 'readonly' \| 'restricted' \| 'full'>; allowedPaths?: string[]; deniedPaths?: string[]; maxFileSize?: integer }` | optional | | +| **network** | `{ mode?: Enum<'none' \| 'local' \| 'restricted' \| 'full'>; allowedHosts?: string[]; deniedHosts?: string[]; allowedPorts?: number[]; … }` | optional | | +| **process** | `{ allowSpawn?: boolean; allowedCommands?: string[]; timeoutMs?: integer }` | optional | | | **memory** | `{ maxHeap?: integer; maxStack?: integer }` | optional | | | **cpu** | `{ maxCpuPercent?: number; maxThreads?: integer }` | optional | | -| **environment** | `{ mode: Enum<'none' \| 'readonly' \| 'restricted' \| 'full'>; allowedVars?: string[]; deniedVars?: string[] }` | optional | | +| **environment** | `{ mode?: Enum<'none' \| 'readonly' \| 'restricted' \| 'full'>; allowedVars?: string[]; deniedVars?: string[] }` | optional | | ### Nested Shape: `SandboxConfig.runtime` diff --git a/content/docs/references/kernel/plugin-security.mdx b/content/docs/references/kernel/plugin-security.mdx index dd2c1885a9f..94456e9e233 100644 --- a/content/docs/references/kernel/plugin-security.mdx +++ b/content/docs/references/kernel/plugin-security.mdx @@ -44,7 +44,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: object[]; 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 | @@ -63,7 +63,7 @@ A node in the dependency graph representing a resolved package | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier of the package | | **version** | `string` | ✅ | Resolved version of the package | -| **dependencies** | `{ name: string; versionConstraint: string; type: Enum<'required' \| 'optional' \| 'peer' \| 'dev'>; resolvedVersion?: string }[]` | optional (default: `[]`) | Dependencies required by this package | +| **dependencies** | `{ name: string; versionConstraint: string; type?: Enum<'required' \| 'optional' \| 'peer' \| 'dev'>; resolvedVersion?: string }[]` | optional (default: `[]`) | Dependencies required by this package | | **depth** | `integer` | ✅ | Depth level in the dependency tree (0 = root) | | **isDirect** | `boolean` | ✅ | Whether this is a direct (top-level) dependency | | **metadata** | `{ name: string; description?: string; license?: string; homepage?: string }` | optional | Additional metadata about the package | @@ -97,7 +97,7 @@ A node in the dependency graph representing a resolved package | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier of the package | | **version** | `string` | ✅ | Resolved version of the package | -| **dependencies** | `{ name: string; versionConstraint: string; type: Enum<'required' \| 'optional' \| 'peer' \| 'dev'>; resolvedVersion?: string }[]` | optional (default: `[]`) | Dependencies required by this package | +| **dependencies** | `{ name: string; versionConstraint: string; type?: Enum<'required' \| 'optional' \| 'peer' \| 'dev'>; resolvedVersion?: string }[]` | optional (default: `[]`) | Dependencies required by this package | | **depth** | `integer` | ✅ | Depth level in the dependency tree (0 = root) | | **isDirect** | `boolean` | ✅ | Whether this is a direct (top-level) dependency | | **metadata** | `{ name: string; description?: string; license?: string; homepage?: string }` | optional | Additional metadata about the package | @@ -178,7 +178,7 @@ Result of a dependency resolution process | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **root** | `{ id: string; version: string }` | ✅ | Root package of the dependency graph | -| **nodes** | `{ id: string; version: string; dependencies: object[]; 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 | @@ -398,12 +398,12 @@ Security policy governing plugin scanning and enforcement | :--- | :--- | :--- | :--- | | **id** | `string` | ✅ | Unique identifier for the security policy | | **name** | `string` | ✅ | Human-readable name of the security policy | -| **autoScan** | `{ enabled: boolean; frequency: Enum<'on-publish' \| 'daily' \| 'weekly' \| 'monthly'> }` | ✅ | Automatic security scanning configuration | -| **thresholds** | `{ maxCritical: integer; maxHigh: integer; maxMedium: integer }` | ✅ | Vulnerability count thresholds for policy enforcement | +| **autoScan** | `{ enabled?: boolean; frequency?: Enum<'on-publish' \| 'daily' \| 'weekly' \| 'monthly'> }` | ✅ | Automatic security scanning configuration | +| **thresholds** | `{ maxCritical?: integer; maxHigh?: integer; maxMedium?: integer }` | ✅ | Vulnerability count thresholds for policy enforcement | | **allowedLicenses** | `string[]` | optional (default: `["MIT","Apache-2.0","BSD-3-Clause","BSD-2-Clause","ISC"]`) | List of SPDX license identifiers that are permitted | | **prohibitedLicenses** | `string[]` | optional (default: `["GPL-3.0","AGPL-3.0"]`) | List of SPDX license identifiers that are prohibited | -| **codeSigning** | `{ required: boolean; allowedSigners: string[] }` | optional | Code signing requirements for plugin artifacts | -| **sandbox** | `{ networkAccess: Enum<'none' \| 'localhost' \| 'allowlist' \| 'all'>; allowedDestinations: string[]; filesystemAccess: Enum<'none' \| 'read-only' \| 'temp-only' \| 'full'>; maxMemoryMB?: integer; … }` | optional | Sandbox restrictions for plugin execution | +| **codeSigning** | `{ required?: boolean; allowedSigners?: string[] }` | optional | Code signing requirements for plugin artifacts | +| **sandbox** | `{ networkAccess?: Enum<'none' \| 'localhost' \| 'allowlist' \| 'all'>; allowedDestinations?: string[]; filesystemAccess?: Enum<'none' \| 'read-only' \| 'temp-only' \| 'full'>; maxMemoryMB?: integer; … }` | optional | Sandbox restrictions for plugin execution | ### Nested Shape: `SecurityPolicy.autoScan` @@ -454,9 +454,9 @@ Result of a security scan performed on a plugin | **scanner** | `{ name: string; version: string }` | ✅ | Information about the scanner tool used | | **status** | `Enum<'passed' \| 'failed' \| 'warning'>` | ✅ | Overall result status of the security scan | | **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 | +| **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'> }[]` | optional (default: `[]`) | License compliance issues found during the scan | -| **codeQuality** | `{ score?: number; issues: object[] }` | 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 | ### Nested Shape: `SecurityScanResult.plugin` diff --git a/content/docs/references/kernel/plugin-versioning.mdx b/content/docs/references/kernel/plugin-versioning.mdx index 916deb41a5e..2befdfabeab 100644 --- a/content/docs/references/kernel/plugin-versioning.mdx +++ b/content/docs/references/kernel/plugin-versioning.mdx @@ -108,7 +108,7 @@ Compatibility level between versions | **type** | `Enum<'version-mismatch' \| 'missing-dependency' \| 'circular-dependency' \| 'incompatible-versions' \| 'conflicting-interfaces'>` | ✅ | | | **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 | | +| **resolutions** | `{ strategy: Enum<'upgrade' \| 'downgrade' \| 'replace' \| 'disable' \| 'manual'>; description: string; automaticResolution?: boolean; riskLevel: Enum<'low' \| 'medium' \| 'high'> }[]` | optional | | | **severity** | `Enum<'critical' \| 'error' \| 'warning' \| 'info'>` | ✅ | | ### Nested Shape: `DependencyConflict.plugins[number]` @@ -180,7 +180,7 @@ Compatibility level between versions | **pluginId** | `string` | ✅ | | | **currentVersion** | `string` | ✅ | | | **compatibilityMatrix** | `{ from: string; to: string; compatibility: Enum<'fully-compatible' \| 'backward-compatible' \| 'deprecated-compatible' \| …>; breakingChanges?: object[]; … }[]` | ✅ | | -| **supportedVersions** | `{ version: string; supported: boolean; endOfLife?: string; securitySupport: boolean }[]` | ✅ | | +| **supportedVersions** | `{ version: string; supported: boolean; endOfLife?: string; securitySupport?: boolean }[]` | ✅ | | | **minimumCompatibleVersion** | `string` | optional | Oldest version that can be directly upgraded | ### Nested Shape: `PluginCompatibilityMatrix.compatibilityMatrix[number]` @@ -242,7 +242,7 @@ Compatibility level between versions | **compatibilityMatrix** | `{ from: string; to: string; compatibility: Enum<'fully-compatible' \| 'backward-compatible' \| 'deprecated-compatible' \| …>; 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 }` | ✅ | | +| **support** | `{ status: Enum<'active' \| 'maintenance' \| 'deprecated' \| 'eol'>; endOfLife?: string; securitySupport?: boolean }` | ✅ | | ### Nested Shape: `PluginVersionMetadata.version` diff --git a/content/docs/references/kernel/service-registry.mdx b/content/docs/references/kernel/service-registry.mdx index 11a9f3e65cb..aaab902cd1e 100644 --- a/content/docs/references/kernel/service-registry.mdx +++ b/content/docs/references/kernel/service-registry.mdx @@ -72,7 +72,7 @@ const result = ScopeConfigSchema.parse(data); | **scope** | `Enum<'singleton' \| 'transient' \| 'scoped'>` | optional (default: `"singleton"`) | Service scope type | | **factoryType** | `Enum<'sync' \| 'async'>` | optional (default: `"sync"`) | Whether factory is synchronous or asynchronous | | **singleton** | `boolean` | optional (default: `true`) | Whether to cache the factory result (singleton pattern) | -| **cluster** | `{ clusterScope: Enum<'node' \| 'cluster'>; leaderStrategy?: Enum<'leader-elected' \| 'partitioned' \| 'idempotent-broadcast'>; clusterId?: string }` | optional | Cluster scope & leader strategy for this service. | +| **cluster** | `{ clusterScope?: Enum<'node' \| 'cluster'>; leaderStrategy?: Enum<'leader-elected' \| 'partitioned' \| 'idempotent-broadcast'>; clusterId?: string }` | optional | Cluster scope & leader strategy for this service. | ### Nested Shape: `ServiceFactoryRegistration.cluster` @@ -96,7 +96,7 @@ const result = ScopeConfigSchema.parse(data); | **type** | `string` | optional | Service type or interface name | | **registeredAt** | `integer` | optional | Unix timestamp in milliseconds when service was registered | | **metadata** | `Record` | optional | Additional service-specific metadata | -| **cluster** | `{ clusterScope: Enum<'node' \| 'cluster'>; leaderStrategy?: Enum<'leader-elected' \| 'partitioned' \| 'idempotent-broadcast'>; clusterId?: string }` | optional | Cluster scope & leader strategy. See /docs/kernel/cluster §5. | +| **cluster** | `{ clusterScope?: Enum<'node' \| 'cluster'>; leaderStrategy?: Enum<'leader-elected' \| 'partitioned' \| 'idempotent-broadcast'>; clusterId?: string }` | optional | Cluster scope & leader strategy. See /docs/kernel/cluster §5. | ### Nested Shape: `ServiceMetadata.cluster` diff --git a/content/docs/references/marketplace/marketplace.mdx b/content/docs/references/marketplace/marketplace.mdx index c758ca8e7ee..8bd987d3495 100644 --- a/content/docs/references/marketplace/marketplace.mdx +++ b/content/docs/references/marketplace/marketplace.mdx @@ -147,7 +147,7 @@ Install from marketplace request | **licenseKey** | `string` | optional | License key for paid packages | | **settings** | `Record` | optional | User-provided settings at install time | | **enableOnInstall** | `boolean` | optional | Whether to enable immediately after install — the marketplace channel's own install option, not the platform install-door key (api/PackageInstallRequest); `true` asks the channel to enable, `false` not to, and ABSENT leaves the package's current lifecycle state alone | -| **artifactRef** | `{ url: string; sha256: string; size: integer; format: Enum<'tgz' \| 'zip'>; … }` | optional | Artifact reference for direct installation | +| **artifactRef** | `{ url: string; sha256: string; size: integer; format?: Enum<'tgz' \| 'zip'>; … }` | optional | Artifact reference for direct installation | | **tenantId** | `string` | optional | Tenant identifier | ### Nested Shape: `MarketplaceInstallRequest.artifactRef` @@ -207,7 +207,7 @@ Public-facing package listing on the marketplace | **latestVersion** | `string` | ✅ | Latest published version | | **minPlatformVersion** | `string` | optional | Minimum ObjectStack platform version | | **versions** | `{ version: string; releaseDate: string; releaseNotes?: string; minPlatformVersion?: string; … }[]` | optional | Published versions | -| **stats** | `{ totalInstalls: integer; activeInstalls: integer; averageRating?: number; totalRatings: integer; … }` | optional | Aggregate marketplace statistics | +| **stats** | `{ totalInstalls?: integer; activeInstalls?: integer; averageRating?: number; totalRatings?: integer; … }` | optional | Aggregate marketplace statistics | | **publishedAt** | `string` | optional | First published timestamp | | **updatedAt** | `string` | optional | Last updated timestamp | | **translations** | `Record` | optional | Locale-keyed overrides for name / tagline / description / screenshot captions | @@ -221,7 +221,7 @@ Public-facing package listing on the marketplace | **releaseNotes** | `string` | optional | Release notes | | **minPlatformVersion** | `string` | optional | Minimum platform version | | **deprecated** | `boolean` | optional (default: `false`) | Whether this version is deprecated | -| **artifact** | `{ url: string; sha256: string; size: integer; format: Enum<'tgz' \| 'zip'>; … }` | optional | Downloadable artifact for this version | +| **artifact** | `{ url: string; sha256: string; size: integer; format?: Enum<'tgz' \| 'zip'>; … }` | optional | Downloadable artifact for this version | ### Nested Shape: `MarketplaceListing.stats` @@ -278,7 +278,7 @@ Marketplace search response | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **items** | `{ id: string; packageId: string; packageType: Enum<'app'>; publisherId: string; … }[]` | ✅ | Search result listings | +| **items** | `{ id: string; packageId: string; packageType?: Enum<'app'>; publisherId: string; … }[]` | ✅ | Search result listings | | **total** | `integer` | ✅ | Total matching results | | **page** | `integer` | ✅ | Current page number | | **pageSize** | `integer` | ✅ | Items per page | @@ -310,7 +310,7 @@ Public-facing package listing on the marketplace | **latestVersion** | `string` | ✅ | Latest published version | | **minPlatformVersion** | `string` | optional | Minimum ObjectStack platform version | | **versions** | `{ version: string; releaseDate: string; releaseNotes?: string; minPlatformVersion?: string; … }[]` | optional | Published versions | -| **stats** | `{ totalInstalls: integer; activeInstalls: integer; averageRating?: number; totalRatings: integer; … }` | optional | Aggregate marketplace statistics | +| **stats** | `{ totalInstalls?: integer; activeInstalls?: integer; averageRating?: number; totalRatings?: integer; … }` | optional | Aggregate marketplace statistics | | **publishedAt** | `string` | optional | First published timestamp | | **updatedAt** | `string` | optional | Last updated timestamp | | **translations** | `Record` | optional | Locale-keyed overrides for name / tagline / description / screenshot captions | diff --git a/content/docs/references/marketplace/package-version.mdx b/content/docs/references/marketplace/package-version.mdx index 3d3f4b5d378..b3b7a35df39 100644 --- a/content/docs/references/marketplace/package-version.mdx +++ b/content/docs/references/marketplace/package-version.mdx @@ -83,7 +83,7 @@ Package manifest snapshot embedded in a package version | **description** | `string` | optional | Short description | | **scope** | `Enum<'platform' \| 'environment'>` | optional (default: `"environment"`) | Package scope | | **minPlatformVersion** | `string` | optional | Minimum required platform version (semver) | -| **dependencies** | `{ packageId: string; versionRange: string; optional: boolean }[]` | optional (default: `[]`) | Package dependencies | +| **dependencies** | `{ packageId: string; versionRange: string; optional?: boolean }[]` | optional (default: `[]`) | Package dependencies | | **metadataTypes** | `string[]` | optional (default: `[]`) | Metadata types provided by this package | | **migrations** | `string[]` | optional (default: `[]`) | Migration script identifiers (ordered) | | **configurationSchema** | `Record` | optional | JSON Schema for per-installation configuration properties | diff --git a/content/docs/references/security/explain.mdx b/content/docs/references/security/explain.mdx index 6813a6568da..f88bd525934 100644 --- a/content/docs/references/security/explain.mdx +++ b/content/docs/references/security/explain.mdx @@ -105,7 +105,7 @@ ADR-0095 D2 posture rung — PLATFORM_ADMIN crosses the tenant wall where object | **allowed** | `boolean` | ✅ | | | **object** | `string` | ✅ | | | **operation** | `Enum<'read' \| 'create' \| 'update' \| 'delete' \| 'transfer' \| 'restore' \| 'purge' \| 'export'>` | ✅ | | -| **principal** | `{ userId: string \| null; positions: string[]; permissionSets: string[]; principalKind?: Enum<'human' \| 'agent' \| 'service' \| 'guest' \| 'system'>; … }` | ✅ | | +| **principal** | `{ userId: string \| null; positions?: string[]; permissionSets?: string[]; principalKind?: Enum<'human' \| 'agent' \| 'service' \| 'guest' \| 'system'>; … }` | ✅ | | | **layers** | `{ layer: Enum<'tenant_isolation' \| 'principal' \| 'required_permissions' \| 'object_crud' \| …>; kernelTier?: Enum<'layer_0_tenant' \| 'layer_1_business'>; verdict: Enum<'grants' \| 'denies' \| 'narrows' \| 'widens' \| 'neutral' \| 'not_applicable'>; detail: string; … }[]` | ✅ | | | **readFilter** | `any` | optional | The composed row filter the caller would be served with — the machine artifact behind the prose (null = unrestricted). Two shapes mean zero rows — `{ id: "__deny_all__" }` and the fail-closed RLS denial (`__rls_deny__` plus a colon and a UUID-shaped suffix, which can also ride inside an $and composite) — so a consumer pattern-matching this payload alone must match both; the decision itself is allowed plus the rls layer verdict. | | **record** | `{ recordId: string; visible: boolean; decidedBy?: Enum<'tenant_isolation' \| 'principal' \| 'required_permissions' \| 'object_crud' \| …> }` | optional | Row-level verdict for the specific record; set only for singular record-grained requests. | @@ -131,7 +131,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' \| 'deactivated'> }[]` | optional (default: `[]`) | | -| **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. | +| **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. | ### Nested Shape: `ExplainDecision.record` @@ -163,7 +163,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' \| 'deactivated'> }[]` | optional (default: `[]`) | | -| **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. | +| **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. | ### Nested Shape: `ExplainLayer.record` diff --git a/content/docs/references/security/permission.mdx b/content/docs/references/security/permission.mdx index 344f23c30d7..ed59116daaf 100644 --- a/content/docs/references/security/permission.mdx +++ b/content/docs/references/security/permission.mdx @@ -120,12 +120,12 @@ const result = AdminScopeSchema.parse(data); | **packageId** | `string` | optional | [ADR-0086 D3] Owning package id for a package-shipped set (absent = env-authored) | | **managedBy** | `Enum<'package' \| 'platform' \| 'user'>` | optional | [ADR-0086 D3] Record provenance: package (upgrade-owned metadata) vs platform/user (env config) | | **isDefault** | `boolean` | optional (default: `false`) | [ADR-0090 D5] App baseline for the everyone position: app-level sets are auto-bound at boot (guarded, idempotent); package-level sets become install-time suggestions an admin confirms | -| **objects** | `Record` | ✅ | Entity permissions | -| **fields** | `Record` | optional | Field level security | +| **objects** | `Record` | ✅ | Entity permissions | +| **fields** | `Record` | optional | Field level security | | **systemPermissions** | `string[]` | optional | System level capabilities | | **tabPermissions** | `Record>` | optional | App/tab visibility: visible, hidden, default_on (shown by default), default_off (available but hidden initially) | | **rowLevelSecurity** | `{ name: string; label?: string; description?: string; object: string; … }[]` | optional | Row-level security policies (see rls.zod.ts for full spec) | -| **adminScope** | `{ businessUnit: string; includeSubtree: boolean; manageAssignments: boolean; manageBindings: boolean; … }` | optional | [ADR-0090 D12] Scoped delegated-administration grant (BU subtree + assignable-set allowlist) | +| **adminScope** | `{ businessUnit: string; includeSubtree?: boolean; manageAssignments?: boolean; manageBindings?: boolean; … }` | optional | [ADR-0090 D12] Scoped delegated-administration grant (BU subtree + assignable-set allowlist) | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this permission set. | | **_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/studio/flow-builder.mdx b/content/docs/references/studio/flow-builder.mdx index 901a278b188..428ea0e7db0 100644 --- a/content/docs/references/studio/flow-builder.mdx +++ b/content/docs/references/studio/flow-builder.mdx @@ -57,8 +57,8 @@ Studio Flow Builder configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **snap** | `{ enabled: boolean; gridSize: integer; showGrid: boolean }` | optional (default: `{"enabled":true,"gridSize":16,"showGrid":true}`) | Canvas snap-to-grid settings | -| **zoom** | `{ min: number; max: number; default: number; step: number }` | optional (default: `{"min":0.25,"max":3,"default":1,"step":0.1}`) | Canvas zoom settings | +| **snap** | `{ enabled?: boolean; gridSize?: integer; showGrid?: boolean }` | optional (default: `{"enabled":true,"gridSize":16,"showGrid":true}`) | Canvas snap-to-grid settings | +| **zoom** | `{ min?: number; max?: number; default?: number; step?: number }` | optional (default: `{"min":0.25,"max":3,"default":1,"step":0.1}`) | Canvas zoom settings | | **layoutAlgorithm** | `Enum<'dagre' \| 'elk' \| 'force' \| 'manual'>` | optional (default: `"dagre"`) | Default auto-layout algorithm | | **layoutDirection** | `Enum<'TB' \| 'BT' \| 'LR' \| 'RL'>` | optional (default: `"TB"`) | Default auto-layout direction | | **nodeDescriptors** | `{ action: string; shape: Enum<'rounded_rect' \| 'circle' \| 'diamond' \| 'parallelogram' \| 'hexagon' \| …>; icon: string; defaultLabel: string; … }[]` | optional | Custom node render descriptors (merged with built-in defaults) | diff --git a/content/docs/references/studio/object-designer.mdx b/content/docs/references/studio/object-designer.mdx index 53949360d8b..833e0123ce6 100644 --- a/content/docs/references/studio/object-designer.mdx +++ b/content/docs/references/studio/object-designer.mdx @@ -84,7 +84,7 @@ const result = ERDiagramConfigSchema.parse(data); | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | optional (default: `true`) | Enable ER diagram panel | | **layout** | `Enum<'force' \| 'hierarchy' \| 'grid' \| 'circular'>` | optional (default: `"force"`) | Default layout algorithm | -| **nodeDisplay** | `{ showFields: boolean; maxFieldsVisible: number; showFieldTypes: boolean; showRequiredIndicator: boolean; … }` | optional (has default) | Node display configuration | +| **nodeDisplay** | `{ showFields?: boolean; maxFieldsVisible?: number; showFieldTypes?: boolean; showRequiredIndicator?: boolean; … }` | optional (has default) | Node display configuration | | **showMinimap** | `boolean` | optional (default: `true`) | Show minimap for large diagrams | | **zoomControls** | `boolean` | optional (default: `true`) | Show zoom in/out/fit controls | | **minZoom** | `number` | optional (default: `0.1`) | Minimum zoom level | @@ -153,8 +153,8 @@ ER diagram layout algorithm | **dragReorder** | `boolean` | optional (default: `true`) | Enable drag-and-drop field reordering | | **showFieldGroups** | `boolean` | optional (default: `true`) | Show field group headers | | **showPropertyPanel** | `boolean` | optional (default: `true`) | Show the right-side property panel | -| **propertySections** | `{ key: string; label: string; icon?: string; defaultExpanded: boolean; … }[]` | optional (has default) | Property panel section definitions | -| **fieldGroups** | `{ key: string; label: string; icon?: string; defaultExpanded: boolean; … }[]` | optional (default: `[]`) | Field group definitions | +| **propertySections** | `{ key: string; label: string; icon?: string; defaultExpanded?: boolean; … }[]` | optional (has default) | Property panel section definitions | +| **fieldGroups** | `{ key: string; label: string; icon?: string; defaultExpanded?: boolean; … }[]` | optional (default: `[]`) | Field group definitions | | **paginationThreshold** | `number` | optional (default: `50`) | Number of fields before pagination is enabled | | **batchOperations** | `boolean` | optional (default: `true`) | Enable batch add/remove field operations | | **showUsageStats** | `boolean` | optional (default: `false`) | Show field usage statistics | @@ -219,11 +219,11 @@ ER diagram layout algorithm | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **defaultView** | `Enum<'field-editor' \| 'relationship-mapper' \| 'er-diagram' \| 'object-manager'>` | optional (default: `"field-editor"`) | Default view | -| **fieldEditor** | `{ inlineEditing: boolean; dragReorder: boolean; showFieldGroups: boolean; showPropertyPanel: boolean; … }` | optional (has default) | Field editor configuration | -| **relationshipMapper** | `{ visualCreation: boolean; showReverseRelationships: boolean; showCascadeWarnings: boolean; displayConfig: object[] }` | optional (has default) | Relationship mapper configuration | -| **erDiagram** | `{ enabled: boolean; layout: Enum<'force' \| 'hierarchy' \| 'grid' \| 'circular'>; nodeDisplay: object; showMinimap: boolean; … }` | optional (has default) | ER diagram configuration | -| **objectManager** | `{ defaultDisplayMode: Enum<'table' \| 'cards' \| 'tree'>; defaultSortField: Enum<'name' \| 'label' \| 'fieldCount' \| 'updatedAt'>; defaultSortDirection: Enum<'asc' \| 'desc'>; defaultFilter: object; … }` | optional (has default) | Object manager configuration | -| **objectPreview** | `{ tabs: object[]; defaultTab: string; showHeader: boolean; showBreadcrumbs: boolean }` | optional (has default) | Object preview configuration | +| **fieldEditor** | `{ inlineEditing?: boolean; dragReorder?: boolean; showFieldGroups?: boolean; showPropertyPanel?: boolean; … }` | optional (has default) | Field editor configuration | +| **relationshipMapper** | `{ visualCreation?: boolean; showReverseRelationships?: boolean; showCascadeWarnings?: boolean; displayConfig?: object[] }` | optional (has default) | Relationship mapper configuration | +| **erDiagram** | `{ enabled?: boolean; layout?: Enum<'force' \| 'hierarchy' \| 'grid' \| 'circular'>; nodeDisplay?: object; showMinimap?: boolean; … }` | optional (has default) | ER diagram configuration | +| **objectManager** | `{ defaultDisplayMode?: Enum<'table' \| 'cards' \| 'tree'>; defaultSortField?: Enum<'name' \| 'label' \| 'fieldCount' \| 'updatedAt'>; defaultSortDirection?: Enum<'asc' \| 'desc'>; defaultFilter?: object; … }` | optional (has default) | Object manager configuration | +| **objectPreview** | `{ tabs?: object[]; defaultTab?: string; showHeader?: boolean; showBreadcrumbs?: boolean }` | optional (has default) | Object preview configuration | ### Nested Shape: `ObjectDesignerConfig.fieldEditor` @@ -233,8 +233,8 @@ ER diagram layout algorithm | **dragReorder** | `boolean` | optional (default: `true`) | Enable drag-and-drop field reordering | | **showFieldGroups** | `boolean` | optional (default: `true`) | Show field group headers | | **showPropertyPanel** | `boolean` | optional (default: `true`) | Show the right-side property panel | -| **propertySections** | `{ key: string; label: string; icon?: string; defaultExpanded: boolean; … }[]` | optional (has default) | Property panel section definitions | -| **fieldGroups** | `{ key: string; label: string; icon?: string; defaultExpanded: boolean; … }[]` | optional (default: `[]`) | Field group definitions | +| **propertySections** | `{ key: string; label: string; icon?: string; defaultExpanded?: boolean; … }[]` | optional (has default) | Property panel section definitions | +| **fieldGroups** | `{ key: string; label: string; icon?: string; defaultExpanded?: boolean; … }[]` | optional (default: `[]`) | Field group definitions | | **paginationThreshold** | `number` | optional (default: `50`) | Number of fields before pagination is enabled | | **batchOperations** | `boolean` | optional (default: `true`) | Enable batch add/remove field operations | | **showUsageStats** | `boolean` | optional (default: `false`) | Show field usage statistics | @@ -246,7 +246,7 @@ ER diagram layout algorithm | **visualCreation** | `boolean` | optional (default: `true`) | Enable drag-to-create relationships | | **showReverseRelationships** | `boolean` | optional (default: `true`) | Show reverse/child-to-parent relationships | | **showCascadeWarnings** | `boolean` | optional (default: `true`) | Show cascade delete behavior warnings | -| **displayConfig** | `{ type: Enum<'lookup' \| 'master_detail' \| 'tree'>; lineStyle: Enum<'solid' \| 'dashed' \| 'dotted'>; color: string; highlightColor: string; … }[]` | optional (has default) | Visual config per relationship type | +| **displayConfig** | `{ type: Enum<'lookup' \| 'master_detail' \| 'tree'>; lineStyle?: Enum<'solid' \| 'dashed' \| 'dotted'>; color?: string; highlightColor?: string; … }[]` | optional (has default) | Visual config per relationship type | ### Nested Shape: `ObjectDesignerConfig.erDiagram` @@ -254,7 +254,7 @@ ER diagram layout algorithm | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | optional (default: `true`) | Enable ER diagram panel | | **layout** | `Enum<'force' \| 'hierarchy' \| 'grid' \| 'circular'>` | optional (default: `"force"`) | Default layout algorithm | -| **nodeDisplay** | `{ showFields: boolean; maxFieldsVisible: number; showFieldTypes: boolean; showRequiredIndicator: boolean; … }` | optional (has default) | Node display configuration | +| **nodeDisplay** | `{ showFields?: boolean; maxFieldsVisible?: number; showFieldTypes?: boolean; showRequiredIndicator?: boolean; … }` | optional (has default) | Node display configuration | | **showMinimap** | `boolean` | optional (default: `true`) | Show minimap for large diagrams | | **zoomControls** | `boolean` | optional (default: `true`) | Show zoom in/out/fit controls | | **minZoom** | `number` | optional (default: `0.1`) | Minimum zoom level | @@ -274,7 +274,7 @@ ER diagram layout algorithm | **defaultDisplayMode** | `Enum<'table' \| 'cards' \| 'tree'>` | optional (default: `"table"`) | Default list display mode | | **defaultSortField** | `Enum<'name' \| 'label' \| 'fieldCount' \| 'updatedAt'>` | optional (default: `"label"`) | Default sort field | | **defaultSortDirection** | `Enum<'asc' \| 'desc'>` | optional (default: `"asc"`) | Default sort direction | -| **defaultFilter** | `{ package?: string; tags?: string[]; includeSystem: boolean; includeAbstract: boolean; … }` | optional (default: `{"includeSystem":true,"includeAbstract":false}`) | Default filter configuration | +| **defaultFilter** | `{ package?: string; tags?: string[]; includeSystem?: boolean; includeAbstract?: boolean; … }` | optional (default: `{"includeSystem":true,"includeAbstract":false}`) | Default filter configuration | | **showFieldCount** | `boolean` | optional (default: `true`) | Show field count badge | | **showRelationshipCount** | `boolean` | optional (default: `true`) | Show relationship count badge | | **showQuickPreview** | `boolean` | optional (default: `true`) | Show quick field preview tooltip on hover | @@ -287,7 +287,7 @@ ER diagram layout algorithm | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **tabs** | `{ key: string; label: string; icon?: string; enabled: boolean; … }[]` | optional (has default) | Object detail preview tabs | +| **tabs** | `{ key: string; label: string; icon?: string; enabled?: boolean; … }[]` | optional (has default) | Object detail preview tabs | | **defaultTab** | `string` | optional (default: `"fields"`) | Default active tab key | | **showHeader** | `boolean` | optional (default: `true`) | Show object summary header | | **showBreadcrumbs** | `boolean` | optional (default: `true`) | Show navigation breadcrumbs | @@ -348,7 +348,7 @@ Object list display mode | **defaultDisplayMode** | `Enum<'table' \| 'cards' \| 'tree'>` | optional (default: `"table"`) | Default list display mode | | **defaultSortField** | `Enum<'name' \| 'label' \| 'fieldCount' \| 'updatedAt'>` | optional (default: `"label"`) | Default sort field | | **defaultSortDirection** | `Enum<'asc' \| 'desc'>` | optional (default: `"asc"`) | Default sort direction | -| **defaultFilter** | `{ package?: string; tags?: string[]; includeSystem: boolean; includeAbstract: boolean; … }` | optional (default: `{"includeSystem":true,"includeAbstract":false}`) | Default filter configuration | +| **defaultFilter** | `{ package?: string; tags?: string[]; includeSystem?: boolean; includeAbstract?: boolean; … }` | optional (default: `{"includeSystem":true,"includeAbstract":false}`) | Default filter configuration | | **showFieldCount** | `boolean` | optional (default: `true`) | Show field count badge | | **showRelationshipCount** | `boolean` | optional (default: `true`) | Show relationship count badge | | **showQuickPreview** | `boolean` | optional (default: `true`) | Show quick field preview tooltip on hover | @@ -378,7 +378,7 @@ Object list display mode | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **tabs** | `{ key: string; label: string; icon?: string; enabled: boolean; … }[]` | optional (has default) | Object detail preview tabs | +| **tabs** | `{ key: string; label: string; icon?: string; enabled?: boolean; … }[]` | optional (has default) | Object detail preview tabs | | **defaultTab** | `string` | optional (default: `"fields"`) | Default active tab key | | **showHeader** | `boolean` | optional (default: `true`) | Show object summary header | | **showBreadcrumbs** | `boolean` | optional (default: `true`) | Show navigation breadcrumbs | @@ -449,7 +449,7 @@ Object list sort field | **visualCreation** | `boolean` | optional (default: `true`) | Enable drag-to-create relationships | | **showReverseRelationships** | `boolean` | optional (default: `true`) | Show reverse/child-to-parent relationships | | **showCascadeWarnings** | `boolean` | optional (default: `true`) | Show cascade delete behavior warnings | -| **displayConfig** | `{ type: Enum<'lookup' \| 'master_detail' \| 'tree'>; lineStyle: Enum<'solid' \| 'dashed' \| 'dotted'>; color: string; highlightColor: string; … }[]` | optional (has default) | Visual config per relationship type | +| **displayConfig** | `{ type: Enum<'lookup' \| 'master_detail' \| 'tree'>; lineStyle?: Enum<'solid' \| 'dashed' \| 'dotted'>; color?: string; highlightColor?: string; … }[]` | optional (has default) | Visual config per relationship type | ### Nested Shape: `RelationshipMapperConfig.displayConfig[number]` diff --git a/content/docs/references/studio/plugin.mdx b/content/docs/references/studio/plugin.mdx index a6361415bde..63491e9f1fd 100644 --- a/content/docs/references/studio/plugin.mdx +++ b/content/docs/references/studio/plugin.mdx @@ -185,11 +185,11 @@ const result = ActionContributionSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **metadataViewers** | `{ id: string; metadataTypes: string[]; label: string; priority: number; … }[]` | optional (default: `[]`) | | +| **metadataViewers** | `{ id: string; metadataTypes: string[]; label: string; priority?: number; … }[]` | optional (default: `[]`) | | | **sidebarGroups** | `{ key: string; label: string; icon?: string; metadataTypes: string[]; … }[]` | optional (default: `[]`) | | | **actions** | `{ id: string; label: string; icon?: string; location: Enum<'toolbar' \| 'contextMenu' \| 'commandPalette'>; … }[]` | optional (default: `[]`) | | | **metadataIcons** | `{ metadataType: string; label: string; icon: string }[]` | optional (default: `[]`) | | -| **panels** | `{ id: string; label: string; icon?: string; location: Enum<'bottom' \| 'right' \| 'modal'> }[]` | optional (default: `[]`) | | +| **panels** | `{ id: string; label: string; icon?: string; location?: Enum<'bottom' \| 'right' \| 'modal'> }[]` | optional (default: `[]`) | | | **commands** | `{ id: string; label: string; shortcut?: string; icon?: string }[]` | optional (default: `[]`) | | ### Nested Shape: `StudioPluginContributions.metadataViewers[number]` @@ -262,7 +262,7 @@ const result = ActionContributionSchema.parse(data); | **version** | `string` | optional (default: `"0.0.1"`) | Plugin version | | **description** | `string` | optional | Plugin description | | **author** | `string` | optional | Author | -| **contributes** | `{ metadataViewers: object[]; sidebarGroups: object[]; actions: object[]; metadataIcons: object[]; … }` | optional (has default) | | +| **contributes** | `{ metadataViewers?: object[]; sidebarGroups?: object[]; actions?: object[]; metadataIcons?: object[]; … }` | optional (has default) | | --- diff --git a/content/docs/references/system/auth-config.mdx b/content/docs/references/system/auth-config.mdx index 1c8c62f64a5..23953ae00a1 100644 --- a/content/docs/references/system/auth-config.mdx +++ b/content/docs/references/system/auth-config.mdx @@ -70,17 +70,17 @@ Advanced / low-level Better-Auth options | **uiBasePath** | `string` | optional (default: `"/_console"`) | Basename where the auth UI (Console) is mounted (default `/_console`) | | **databaseUrl** | `string` | optional | Database connection string | | **providers** | `{ id: string; clientId: string; clientSecret: string; scope?: string[] }[]` | optional | | -| **plugins** | `{ organization: boolean; twoFactor: boolean; passkeys: boolean; passwordRejectBreached: boolean; … }` | optional | | -| **session** | `{ expiresIn: number; updateAge: number }` | optional | | +| **plugins** | `{ organization?: boolean; twoFactor?: boolean; passkeys?: boolean; passwordRejectBreached?: boolean; … }` | optional | | +| **session** | `{ expiresIn?: number; updateAge?: number }` | optional | | | **trustedOrigins** | `string[]` | optional | Trusted origins for CSRF protection. Supports wildcards (e.g. "https://*.example.com"). The baseUrl origin is always trusted implicitly. | -| **socialProviders** | `Record>` | optional | Social/OAuth provider map forwarded to better-auth socialProviders. Keys are provider ids (google, github, apple, …). | +| **socialProviders** | `Record>` | optional | Social/OAuth provider map forwarded to better-auth socialProviders. Keys are provider ids (google, github, apple, …). | | **oidcProviders** | `{ providerId: string; name?: string; discoveryUrl?: string; issuer?: string; … }[]` | optional | List of OIDC/OAuth2 providers for enterprise SSO. Product or enterprise packages can pass this directly or contribute it through auth:configure. | -| **emailAndPassword** | `{ enabled: boolean; disableSignUp?: boolean; requireEmailVerification?: boolean; minPasswordLength?: number; … }` | optional | Email and password authentication options forwarded to better-auth | +| **emailAndPassword** | `{ enabled?: boolean; disableSignUp?: boolean; requireEmailVerification?: boolean; minPasswordLength?: number; … }` | optional | Email and password authentication options forwarded to better-auth | | **emailVerification** | `{ sendOnSignUp?: boolean; sendOnSignIn?: boolean; autoSignInAfterVerification?: boolean; expiresIn?: number }` | optional | Email verification options forwarded to better-auth | -| **audience** | `{ posture: Enum<'invite_only' \| 'email_domain' \| 'open'>; allowedEmailDomains?: string[]; selfRegistrationPermissionSet?: string }` | optional | Audience posture: who may self-register into this environment (invite_only — the default — \| email_domain \| open). See AudienceConfigSchema. | +| **audience** | `{ posture?: Enum<'invite_only' \| 'email_domain' \| 'open'>; allowedEmailDomains?: string[]; selfRegistrationPermissionSet?: string }` | optional | Audience posture: who may self-register into this environment (invite_only — the default — \| email_domain \| open). See AudienceConfigSchema. | | **advanced** | `{ crossSubDomainCookies?: object; useSecureCookies?: boolean; disableCSRFCheck?: boolean; cookiePrefix?: string }` | optional | Advanced / low-level Better-Auth options | | **ssoOnlyMode** | `boolean` | optional | SSO-only login: hide the local password form + self-registration (the break-glass password endpoint stays enabled) | -| **mutualTls** | `{ enabled: boolean; clientCertRequired: boolean; trustedCAs: string[]; crlUrl?: string; … }` | optional | Mutual TLS (mTLS) configuration | +| **mutualTls** | `{ enabled?: boolean; clientCertRequired?: boolean; trustedCAs: string[]; crlUrl?: string; … }` | optional | Mutual TLS (mTLS) configuration | ### Nested Shape: `AuthConfig.providers[number]` @@ -334,7 +334,7 @@ List of OIDC/OAuth2 providers for enterprise SSO. Product or enterprise packages Social/OAuth provider map forwarded to better-auth socialProviders. Keys are provider ids (google, github, apple, …). -**Type:** `Record>` +**Type:** `Record>` --- diff --git a/content/docs/references/system/cache.mdx b/content/docs/references/system/cache.mdx index 150a6049cf5..219cf2f8022 100644 --- a/content/docs/references/system/cache.mdx +++ b/content/docs/references/system/cache.mdx @@ -53,9 +53,9 @@ Cache avalanche/stampede prevention configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **jitterTtl** | `{ enabled: boolean; maxJitterSeconds: number }` | optional | TTL jitter to prevent simultaneous expiration | -| **circuitBreaker** | `{ enabled: boolean; failureThreshold: number; resetTimeoutSeconds: number }` | optional | Circuit breaker for backend protection | -| **lockout** | `{ enabled: boolean; lockTimeoutMs: number }` | optional | Lock-based stampede prevention | +| **jitterTtl** | `{ enabled?: boolean; maxJitterSeconds?: number }` | optional | TTL jitter to prevent simultaneous expiration | +| **circuitBreaker** | `{ enabled?: boolean; failureThreshold?: number; resetTimeoutSeconds?: number }` | optional | Circuit breaker for backend protection | +| **lockout** | `{ enabled?: boolean; lockTimeoutMs?: number }` | optional | Lock-based stampede prevention | ### Nested Shape: `CacheAvalanchePrevention.jitterTtl` @@ -92,7 +92,7 @@ Top-level application cache configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | optional (default: `false`) | Enable application-level caching | -| **tiers** | `{ name: string; type: Enum<'memory' \| 'redis' \| 'memcached' \| 'cdn'>; maxSize?: number; ttlSeconds: number; … }[]` | ✅ | Ordered cache tier hierarchy | +| **tiers** | `{ name: string; type: Enum<'memory' \| 'redis' \| 'memcached' \| 'cdn'>; maxSize?: number; ttlSeconds?: number; … }[]` | ✅ | Ordered cache tier hierarchy | | **invalidation** | `{ trigger: Enum<'create' \| 'update' \| 'delete' \| 'manual'>; scope: Enum<'key' \| 'pattern' \| 'tag' \| 'all'>; pattern?: string; tags?: string[] }[]` | ✅ | Cache invalidation rules | | **prefetch** | `boolean` | optional (default: `false`) | Enable cache prefetching | | **compression** | `boolean` | optional (default: `false`) | Enable data compression in cache | @@ -214,14 +214,14 @@ Distributed cache configuration with consistency and avalanche prevention | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | optional (default: `false`) | Enable application-level caching | -| **tiers** | `{ name: string; type: Enum<'memory' \| 'redis' \| 'memcached' \| 'cdn'>; maxSize?: number; ttlSeconds: number; … }[]` | ✅ | Ordered cache tier hierarchy | +| **tiers** | `{ name: string; type: Enum<'memory' \| 'redis' \| 'memcached' \| 'cdn'>; maxSize?: number; ttlSeconds?: number; … }[]` | ✅ | Ordered cache tier hierarchy | | **invalidation** | `{ trigger: Enum<'create' \| 'update' \| 'delete' \| 'manual'>; scope: Enum<'key' \| 'pattern' \| 'tag' \| 'all'>; pattern?: string; tags?: string[] }[]` | ✅ | Cache invalidation rules | | **prefetch** | `boolean` | optional (default: `false`) | Enable cache prefetching | | **compression** | `boolean` | optional (default: `false`) | Enable data compression in cache | | **encryption** | `boolean` | optional (default: `false`) | 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'>; patterns?: string[]; concurrency: number }` | optional | Cache warmup strategy | +| **warmup** | `{ enabled?: boolean; strategy?: Enum<'eager' \| 'lazy'>; patterns?: string[]; concurrency?: number }` | optional | Cache warmup strategy | ### Nested Shape: `DistributedCacheConfig.tiers[number]` @@ -252,9 +252,9 @@ Rule defining when and how cached entries are invalidated | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **jitterTtl** | `{ enabled: boolean; maxJitterSeconds: number }` | optional | TTL jitter to prevent simultaneous expiration | -| **circuitBreaker** | `{ enabled: boolean; failureThreshold: number; resetTimeoutSeconds: number }` | optional | Circuit breaker for backend protection | -| **lockout** | `{ enabled: boolean; lockTimeoutMs: number }` | optional | Lock-based stampede prevention | +| **jitterTtl** | `{ enabled?: boolean; maxJitterSeconds?: number }` | optional | TTL jitter to prevent simultaneous expiration | +| **circuitBreaker** | `{ enabled?: boolean; failureThreshold?: number; resetTimeoutSeconds?: number }` | optional | Circuit breaker for backend protection | +| **lockout** | `{ enabled?: boolean; lockTimeoutMs?: number }` | optional | Lock-based stampede prevention | ### Nested Shape: `DistributedCacheConfig.warmup` diff --git a/content/docs/references/system/collaboration.mdx b/content/docs/references/system/collaboration.mdx index a5e5e728f33..a9a2e94da2d 100644 --- a/content/docs/references/system/collaboration.mdx +++ b/content/docs/references/system/collaboration.mdx @@ -329,7 +329,7 @@ This schema accepts one of the following structures: | :--- | :--- | :--- | :--- | | **sessionId** | `string` | ✅ | Session identifier | | **documentId** | `string` | ✅ | Document identifier | -| **config** | `{ mode: Enum<'ot' \| 'crdt' \| 'lock' \| 'hybrid'>; enableCursorSharing: boolean; enablePresence: boolean; enableAwareness: boolean; … }` | ✅ | Session configuration | +| **config** | `{ mode: Enum<'ot' \| 'crdt' \| 'lock' \| 'hybrid'>; enableCursorSharing?: boolean; enablePresence?: boolean; enableAwareness?: boolean; … }` | ✅ | Session configuration | | **users** | `{ userId: string; sessionId: string; userName: string; userAvatar?: string; … }[]` | ✅ | Active users | | **cursors** | `{ userId: string; sessionId: string; documentId: string; userName: string; … }[]` | ✅ | Active cursors | | **version** | `integer` | ✅ | Current document version | @@ -379,7 +379,7 @@ This schema accepts one of the following structures: | **userName** | `string` | ✅ | Display name of user | | **position** | `{ line: integer; column: integer }` | ✅ | Current cursor position | | **selection** | `{ anchor: object; focus: object; direction?: Enum<'forward' \| 'backward'> }` | optional | Current text selection | -| **style** | `{ color: Enum<'blue' \| 'green' \| 'red' \| 'yellow' \| 'purple' \| 'orange' \| 'pink' \| 'teal' \| 'indigo' \| 'cyan'> \| string; opacity: number; label?: string; showLabel: boolean; … }` | ✅ | Visual style for this cursor | +| **style** | `{ color: Enum<'blue' \| 'green' \| 'red' \| 'yellow' \| 'purple' \| 'orange' \| 'pink' \| 'teal' \| 'indigo' \| 'cyan'> \| string; opacity?: number; label?: string; showLabel?: boolean; … }` | ✅ | Visual style for this cursor | | **isTyping** | `boolean` | optional (default: `false`) | Whether user is currently typing | | **lastUpdate** | `string` | ✅ | ISO 8601 datetime of last cursor update | | **metadata** | `Record` | optional | Additional cursor metadata | @@ -452,7 +452,7 @@ This schema accepts one of the following structures: | **userName** | `string` | ✅ | Display name of user | | **position** | `{ line: integer; column: integer }` | ✅ | Current cursor position | | **selection** | `{ anchor: object; focus: object; direction?: Enum<'forward' \| 'backward'> }` | optional | Current text selection | -| **style** | `{ color: Enum<'blue' \| 'green' \| 'red' \| 'yellow' \| 'purple' \| 'orange' \| 'pink' \| 'teal' \| 'indigo' \| 'cyan'> \| string; opacity: number; label?: string; showLabel: boolean; … }` | ✅ | Visual style for this cursor | +| **style** | `{ color: Enum<'blue' \| 'green' \| 'red' \| 'yellow' \| 'purple' \| 'orange' \| 'pink' \| 'teal' \| 'indigo' \| 'cyan'> \| string; opacity?: number; label?: string; showLabel?: boolean; … }` | ✅ | Visual style for this cursor | | **isTyping** | `boolean` | optional (default: `false`) | Whether user is currently typing | | **lastUpdate** | `string` | ✅ | ISO 8601 datetime of last cursor update | | **metadata** | `Record` | optional | Additional cursor metadata | diff --git a/content/docs/references/system/deploy-bundle.mdx b/content/docs/references/system/deploy-bundle.mdx index 4eac4152a52..c1067036065 100644 --- a/content/docs/references/system/deploy-bundle.mdx +++ b/content/docs/references/system/deploy-bundle.mdx @@ -42,7 +42,7 @@ Deploy bundle containing all metadata for deployment | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **manifest** | `{ version: string; checksum?: string; objects: string[]; views: string[]; … }` | ✅ | Deployment manifest | +| **manifest** | `{ version: string; checksum?: string; objects?: string[]; views?: string[]; … }` | ✅ | Deployment manifest | | **objects** | `Record[]` | optional (default: `[]`) | Object definitions | | **views** | `Record[]` | optional (default: `[]`) | View definitions | | **flows** | `Record[]` | optional (default: `[]`) | Flow definitions | @@ -73,7 +73,7 @@ Schema diff between current and desired state | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **changes** | `{ entityType: Enum<'object' \| 'field' \| 'index' \| 'view' \| 'flow' \| 'permission'>; entityName: string; parentEntity?: string; changeType: Enum<'added' \| 'modified' \| 'removed'>; … }[]` | optional (default: `[]`) | List of schema changes | -| **summary** | `{ added: integer; modified: integer; removed: integer }` | ✅ | Change summary counts | +| **summary** | `{ added?: integer; modified?: integer; removed?: integer }` | ✅ | Change summary counts | | **hasBreakingChanges** | `boolean` | optional (default: `false`) | Whether diff contains breaking changes | ### Nested Shape: `DeployDiff.changes[number]` @@ -187,7 +187,7 @@ Ordered migration plan | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **statements** | `{ sql: string; reversible: boolean; rollbackSql?: string; order: integer }[]` | optional (default: `[]`) | Ordered DDL statements | +| **statements** | `{ sql: string; reversible?: boolean; rollbackSql?: string; order: integer }[]` | optional (default: `[]`) | Ordered DDL statements | | **dialect** | `string` | ✅ | Target SQL dialect | | **reversible** | `boolean` | optional (default: `true`) | Whether the plan can be fully rolled back | | **estimatedDurationMs** | `integer` | optional | Estimated execution time in milliseconds | diff --git a/content/docs/references/system/disaster-recovery.mdx b/content/docs/references/system/disaster-recovery.mdx index d4f88e019d2..0919bccd59e 100644 --- a/content/docs/references/system/disaster-recovery.mdx +++ b/content/docs/references/system/disaster-recovery.mdx @@ -31,10 +31,10 @@ Backup configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **strategy** | `Enum<'full' \| 'incremental' \| 'differential'>` | optional (default: `"incremental"`) | Backup strategy | -| **retention** | `{ days: number; minCopies: number; maxCopies?: number }` | ✅ | Backup retention policy | +| **retention** | `{ days: number; minCopies?: number; maxCopies?: number }` | ✅ | Backup retention policy | | **destination** | `{ type: Enum<'s3' \| 'gcs' \| 'azure_blob' \| 'local'>; bucket?: string; path?: string; region?: string }` | ✅ | Backup storage destination | -| **encryption** | `{ enabled: boolean; algorithm: Enum<'AES-256-GCM' \| 'AES-256-CBC' \| 'ChaCha20-Poly1305'>; keyId?: string }` | optional | Backup encryption settings | -| **compression** | `{ enabled: boolean; algorithm: Enum<'gzip' \| 'zstd' \| 'lz4' \| 'snappy'> }` | optional | Backup compression settings | +| **encryption** | `{ enabled?: boolean; algorithm?: Enum<'AES-256-GCM' \| 'AES-256-CBC' \| 'ChaCha20-Poly1305'>; keyId?: string }` | optional | Backup encryption settings | +| **compression** | `{ enabled?: boolean; algorithm?: Enum<'gzip' \| 'zstd' \| 'lz4' \| 'snappy'> }` | optional | Backup compression settings | | **verifyAfterBackup** | `boolean` | optional (default: `true`) | Verify backup integrity after creation | ### Nested Shape: `BackupConfig.retention` @@ -109,12 +109,12 @@ Complete disaster recovery plan configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | optional (default: `false`) | 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'>; retention: object; destination: object; encryption?: object; … }` | ✅ | Backup configuration | -| **failover** | `{ mode: Enum<'active_passive' \| 'active_active' \| 'pilot_light' \| 'warm_standby'>; autoFailover: boolean; healthCheckIntervalSeconds: 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; notificationChannel?: string }` | optional | Automated disaster recovery testing | +| **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'>; retention: object; destination: object; encryption?: object; … }` | ✅ | Backup configuration | +| **failover** | `{ mode?: Enum<'active_passive' \| 'active_active' \| 'pilot_light' \| 'warm_standby'>; autoFailover?: boolean; healthCheckIntervalSeconds?: 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; 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 | @@ -137,10 +137,10 @@ Complete disaster recovery plan configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **strategy** | `Enum<'full' \| 'incremental' \| 'differential'>` | optional (default: `"incremental"`) | Backup strategy | -| **retention** | `{ days: number; minCopies: number; maxCopies?: number }` | ✅ | Backup retention policy | +| **retention** | `{ days: number; minCopies?: number; maxCopies?: number }` | ✅ | Backup retention policy | | **destination** | `{ type: Enum<'s3' \| 'gcs' \| 'azure_blob' \| 'local'>; bucket?: string; path?: string; region?: string }` | ✅ | Backup storage destination | -| **encryption** | `{ enabled: boolean; algorithm: Enum<'AES-256-GCM' \| 'AES-256-CBC' \| 'ChaCha20-Poly1305'>; keyId?: string }` | optional | Backup encryption settings | -| **compression** | `{ enabled: boolean; algorithm: Enum<'gzip' \| 'zstd' \| 'lz4' \| 'snappy'> }` | optional | Backup compression settings | +| **encryption** | `{ enabled?: boolean; algorithm?: Enum<'AES-256-GCM' \| 'AES-256-CBC' \| 'ChaCha20-Poly1305'>; keyId?: string }` | optional | Backup encryption settings | +| **compression** | `{ enabled?: boolean; algorithm?: Enum<'gzip' \| 'zstd' \| 'lz4' \| 'snappy'> }` | optional | Backup compression settings | | **verifyAfterBackup** | `boolean` | optional (default: `true`) | Verify backup integrity after creation | ### Nested Shape: `DisasterRecoveryPlan.failover` @@ -153,7 +153,7 @@ Complete disaster recovery plan configuration | **healthCheckInterval** | `never` | optional | [REMOVED] `FailoverConfig.healthCheckInterval` was renamed to `healthCheckIntervalSeconds` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Rename the key to `healthCheckIntervalSeconds`; the value (seconds) and the 30 default are unchanged. | | **failureThreshold** | `number` | optional (default: `3`) | Consecutive failures before failover | | **regions** | `{ name: string; role: Enum<'primary' \| 'secondary' \| 'witness'>; endpoint?: string; priority?: number }[]` | ✅ | Multi-region configuration (minimum 2 regions) | -| **dns** | `{ ttl: number; provider?: Enum<'route53' \| 'cloudflare' \| 'azure_dns' \| 'custom'> }` | optional | DNS failover settings | +| **dns** | `{ ttl?: number; provider?: Enum<'route53' \| 'cloudflare' \| 'azure_dns' \| 'custom'> }` | optional | DNS failover settings | ### Nested Shape: `DisasterRecoveryPlan.replication` @@ -197,7 +197,7 @@ Failover configuration | **healthCheckInterval** | `never` | optional | [REMOVED] `FailoverConfig.healthCheckInterval` was renamed to `healthCheckIntervalSeconds` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Rename the key to `healthCheckIntervalSeconds`; the value (seconds) and the 30 default are unchanged. | | **failureThreshold** | `number` | optional (default: `3`) | Consecutive failures before failover | | **regions** | `{ name: string; role: Enum<'primary' \| 'secondary' \| 'witness'>; endpoint?: string; priority?: number }[]` | ✅ | Multi-region configuration (minimum 2 regions) | -| **dns** | `{ ttl: number; provider?: Enum<'route53' \| 'cloudflare' \| 'azure_dns' \| 'custom'> }` | optional | DNS failover settings | +| **dns** | `{ ttl?: number; provider?: Enum<'route53' \| 'cloudflare' \| 'azure_dns' \| 'custom'> }` | optional | DNS failover settings | ### Nested Shape: `FailoverConfig.regions[number]` diff --git a/content/docs/references/system/email-template.mdx b/content/docs/references/system/email-template.mdx index a3a85945af8..2441cd0907e 100644 --- a/content/docs/references/system/email-template.mdx +++ b/content/docs/references/system/email-template.mdx @@ -49,7 +49,7 @@ const result = EmailTemplateDefinitionSchema.parse(data); | **subject** | `string` | ✅ | Subject template | | **bodyHtml** | `string` | ✅ | HTML body template | | **bodyText** | `string` | optional | Plain-text body template (auto-derived from HTML when omitted) | -| **variables** | `{ name: string; type: Enum<'string' \| 'number' \| 'boolean' \| 'date' \| 'url' \| 'user' \| 'record'>; required: boolean; description?: string }[]` | optional (default: `[]`) | | +| **variables** | `{ name: string; type?: Enum<'string' \| 'number' \| 'boolean' \| 'date' \| 'url' \| 'user' \| 'record'>; required?: boolean; description?: string }[]` | optional (default: `[]`) | | | **fromOverride** | `{ name?: string; address: string }` | optional | | | **replyTo** | `string` | optional | | | **active** | `boolean` | optional (default: `true`) | | diff --git a/content/docs/references/system/encryption.mdx b/content/docs/references/system/encryption.mdx index 21a080ea6b5..428c154d6e2 100644 --- a/content/docs/references/system/encryption.mdx +++ b/content/docs/references/system/encryption.mdx @@ -56,7 +56,7 @@ Field-level encryption configuration | :--- | :--- | :--- | :--- | | **provider** | `Enum<'local' \| 'aws-kms' \| 'azure-key-vault' \| 'gcp-kms' \| 'hashicorp-vault'>` | ✅ | Key management service provider | | **keyId** | `string` | optional | Key identifier in the provider | -| **rotationPolicy** | `{ enabled: boolean; frequencyDays: number; retainOldVersions: number; autoRotate: boolean }` | optional | Key rotation policy | +| **rotationPolicy** | `{ enabled?: boolean; frequencyDays?: number; retainOldVersions?: number; autoRotate?: boolean }` | optional | Key rotation policy | --- @@ -70,7 +70,7 @@ Per-field encryption assignment | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **fieldName** | `string` | ✅ | Name of the field to encrypt | -| **encryptionConfig** | `{ enabled: boolean; algorithm: Enum<'aes-256-gcm' \| 'aes-256-cbc' \| 'chacha20-poly1305'>; keyManagement: object; scope: Enum<'field' \| 'record' \| 'table' \| 'database'>; … }` | ✅ | Encryption settings for this field | +| **encryptionConfig** | `{ enabled?: boolean; algorithm?: Enum<'aes-256-gcm' \| 'aes-256-cbc' \| 'chacha20-poly1305'>; keyManagement: object; scope: Enum<'field' \| 'record' \| 'table' \| 'database'>; … }` | ✅ | Encryption settings for this field | | **indexable** | `boolean` | optional (default: `false`) | Allow indexing on encrypted field | ### Nested Shape: `FieldEncryption.encryptionConfig` diff --git a/content/docs/references/system/http-server.mdx b/content/docs/references/system/http-server.mdx index e166b5d9b70..43b4aa8d252 100644 --- a/content/docs/references/system/http-server.mdx +++ b/content/docs/references/system/http-server.mdx @@ -79,7 +79,7 @@ const result = MiddlewareConfigSchema.parse(data); | **path** | `string` | ✅ | URL path pattern | | **handler** | `string` | ✅ | Handler identifier or name | | **metadata** | `{ summary?: string; description?: string; tags?: string[]; operationId?: string }` | optional | | -| **security** | `{ authRequired: boolean; permissions?: string[]; rateLimit?: string }` | optional | | +| **security** | `{ authRequired?: boolean; permissions?: string[]; rateLimit?: string }` | optional | | ### Nested Shape: `RouteHandlerMetadata.metadata` diff --git a/content/docs/references/system/logging.mdx b/content/docs/references/system/logging.mdx index 53dfac65190..77822c48448 100644 --- a/content/docs/references/system/logging.mdx +++ b/content/docs/references/system/logging.mdx @@ -91,7 +91,7 @@ File destination configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **path** | `string` | ✅ | Log file path | -| **rotation** | `{ maxSize: string; maxFiles: integer; compress: boolean; interval?: Enum<'hourly' \| 'daily' \| 'weekly' \| 'monthly'> }` | optional | | +| **rotation** | `{ maxSize?: string; maxFiles?: integer; compress?: boolean; interval?: Enum<'hourly' \| 'daily' \| 'weekly' \| 'monthly'> }` | optional | | | **encoding** | `string` | optional (default: `"utf8"`) | | | **append** | `boolean` | optional (default: `true`) | | @@ -110,8 +110,8 @@ HTTP destination configuration | **method** | `Enum<'POST' \| 'PUT'>` | optional (default: `"POST"`) | | | **headers** | `Record` | optional | | | **auth** | `{ type: Enum<'basic' \| 'bearer' \| 'api_key'>; username?: string; password?: string; token?: string; … }` | optional | | -| **batch** | `{ maxSize: integer; flushIntervalMs: integer }` | optional | | -| **retry** | `{ maxAttempts: integer; initialDelayMs: integer; backoffMultiplier: number }` | optional | | +| **batch** | `{ maxSize?: integer; flushIntervalMs?: integer }` | optional | | +| **retry** | `{ maxAttempts?: integer; initialDelayMs?: integer; backoffMultiplier?: number }` | optional | | | **timeoutMs** | `integer` | optional (default: `30000`) | Timeout in milliseconds | | **timeout** | `never` | optional | [REMOVED] `HttpDestinationConfig.timeout` was renamed to `timeoutMs` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (milliseconds) lived in a source JSDoc only and the key carried no `.describe()` at all, so the reference page published a bare 30000. Rename the key to `timeoutMs`; the value (milliseconds) and the 30000 default are unchanged. | @@ -158,9 +158,9 @@ Log destination configuration | **type** | `Enum<'console' \| 'file' \| 'syslog' \| 'elasticsearch' \| 'cloudwatch' \| 'stackdriver' \| 'azure_monitor' \| 'datadog' \| 'splunk' \| 'loki' \| 'http' \| 'kafka' \| 'redis' \| 'custom'>` | ✅ | Destination type | | **level** | `Enum<'trace' \| 'debug' \| 'info' \| 'warn' \| 'error' \| 'fatal'>` | optional (default: `"info"`) | Extended log severity level | | **enabled** | `boolean` | optional (default: `true`) | | -| **console** | `{ stream: Enum<'stdout' \| 'stderr'>; colors: boolean; prettyPrint: boolean }` | optional | Console destination configuration | -| **file** | `{ path: string; rotation?: object; encoding: string; append: boolean }` | optional | File destination configuration | -| **http** | `{ url: string; method: Enum<'POST' \| 'PUT'>; headers?: Record; auth?: object; … }` | optional | HTTP destination configuration | +| **console** | `{ stream?: Enum<'stdout' \| 'stderr'>; colors?: boolean; prettyPrint?: boolean }` | optional | Console destination configuration | +| **file** | `{ path: string; rotation?: object; encoding?: string; append?: boolean }` | optional | File destination configuration | +| **http** | `{ url: string; method?: Enum<'POST' \| 'PUT'>; headers?: Record; auth?: object; … }` | optional | HTTP destination configuration | | **externalService** | `{ endpoint?: string; region?: string; credentials?: object; logGroup?: string; … }` | optional | External service destination configuration | | **format** | `Enum<'json' \| 'text' \| 'pretty'>` | optional (default: `"json"`) | | | **filterId** | `string` | optional | Filter function identifier | @@ -170,7 +170,7 @@ Log destination configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **path** | `string` | ✅ | Log file path | -| **rotation** | `{ maxSize: string; maxFiles: integer; compress: boolean; interval?: Enum<'hourly' \| 'daily' \| 'weekly' \| 'monthly'> }` | optional | | +| **rotation** | `{ maxSize?: string; maxFiles?: integer; compress?: boolean; interval?: Enum<'hourly' \| 'daily' \| 'weekly' \| 'monthly'> }` | optional | | | **encoding** | `string` | optional (default: `"utf8"`) | | | **append** | `boolean` | optional (default: `true`) | | @@ -182,8 +182,8 @@ Log destination configuration | **method** | `Enum<'POST' \| 'PUT'>` | optional (default: `"POST"`) | | | **headers** | `Record` | optional | | | **auth** | `{ type: Enum<'basic' \| 'bearer' \| 'api_key'>; username?: string; password?: string; token?: string; … }` | optional | | -| **batch** | `{ maxSize: integer; flushIntervalMs: integer }` | optional | | -| **retry** | `{ maxAttempts: integer; initialDelayMs: integer; backoffMultiplier: number }` | optional | | +| **batch** | `{ maxSize?: integer; flushIntervalMs?: integer }` | optional | | +| **retry** | `{ maxAttempts?: integer; initialDelayMs?: integer; backoffMultiplier?: number }` | optional | | | **timeoutMs** | `integer` | optional (default: `30000`) | Timeout in milliseconds | | **timeout** | `never` | optional | [REMOVED] `HttpDestinationConfig.timeout` was renamed to `timeoutMs` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (milliseconds) lived in a source JSDoc only and the key carried no `.describe()` at all, so the reference page published a bare 30000. Rename the key to `timeoutMs`; the value (milliseconds) and the 30000 default are unchanged. | @@ -227,7 +227,7 @@ Log enrichment configuration | **addHostname** | `boolean` | optional (default: `true`) | | | **addProcessId** | `boolean` | optional (default: `true`) | | | **addEnvironment** | `boolean` | optional (default: `true`) | | -| **addTimestampFormats** | `{ unix: boolean; iso: boolean }` | optional | | +| **addTimestampFormats** | `{ unix?: boolean; iso?: boolean }` | optional | | | **addCaller** | `boolean` | optional (default: `false`) | | | **addCorrelationIds** | `boolean` | optional (default: `true`) | | @@ -294,7 +294,7 @@ Log severity level | **redact** | `string[]` | optional (default: `["password","token","secret","key"]`) | Keys to redact from log context | | **sourceLocation** | `boolean` | optional (default: `false`) | Include file and line number | | **file** | `string` | optional | Path to log file | -| **rotation** | `{ maxSize: string; maxFiles: number }` | optional | | +| **rotation** | `{ maxSize?: string; maxFiles?: number }` | optional | | --- @@ -311,14 +311,14 @@ Logging configuration | **label** | `string` | ✅ | Display label | | **enabled** | `boolean` | optional (default: `true`) | | | **level** | `Enum<'trace' \| 'debug' \| 'info' \| 'warn' \| 'error' \| 'fatal'>` | optional (default: `"info"`) | Extended log severity level | -| **default** | `{ name?: string; level: Enum<'debug' \| 'info' \| 'warn' \| 'error' \| 'fatal' \| 'silent'>; format: Enum<'json' \| 'text' \| 'pretty'>; redact: string[]; … }` | optional | Default logger configuration | -| **loggers** | `Record; format: Enum<'json' \| 'text' \| 'pretty'>; redact: string[]; … }>` | optional | Named logger configurations | -| **destinations** | `{ name: string; type: Enum<'console' \| 'file' \| 'syslog' \| 'elasticsearch' \| 'cloudwatch' \| 'stackdriver' \| …>; level: Enum<'trace' \| 'debug' \| 'info' \| 'warn' \| 'error' \| 'fatal'>; enabled: boolean; … }[]` | ✅ | Log destinations | -| **enrichment** | `{ staticFields?: Record; dynamicEnrichers?: string[]; addHostname: boolean; addProcessId: boolean; … }` | optional | Log enrichment configuration | +| **default** | `{ name?: string; level?: Enum<'debug' \| 'info' \| 'warn' \| 'error' \| 'fatal' \| 'silent'>; format?: Enum<'json' \| 'text' \| 'pretty'>; redact?: string[]; … }` | optional | Default logger configuration | +| **loggers** | `Record; format?: Enum<'json' \| 'text' \| 'pretty'>; redact?: string[]; … }>` | optional | Named logger configurations | +| **destinations** | `{ name: string; type: Enum<'console' \| 'file' \| 'syslog' \| 'elasticsearch' \| 'cloudwatch' \| 'stackdriver' \| …>; level?: Enum<'trace' \| 'debug' \| 'info' \| 'warn' \| 'error' \| 'fatal'>; enabled?: boolean; … }[]` | ✅ | Log destinations | +| **enrichment** | `{ staticFields?: Record; dynamicEnrichers?: string[]; addHostname?: boolean; addProcessId?: boolean; … }` | optional | Log enrichment configuration | | **redact** | `string[]` | optional (has default) | Fields to redact | -| **sampling** | `{ enabled: boolean; rate: number; rateByLevel?: Record }` | optional | | -| **buffer** | `{ enabled: boolean; size: integer; flushIntervalMs: integer; flushOnShutdown: boolean }` | optional | | -| **performance** | `{ async: boolean; workers: integer }` | optional | | +| **sampling** | `{ enabled?: boolean; rate?: number; rateByLevel?: Record }` | optional | | +| **buffer** | `{ enabled?: boolean; size?: integer; flushIntervalMs?: integer; flushOnShutdown?: boolean }` | optional | | +| **performance** | `{ async?: boolean; workers?: integer }` | optional | | ### Nested Shape: `LoggingConfig.default` @@ -330,7 +330,7 @@ Logging configuration | **redact** | `string[]` | optional (default: `["password","token","secret","key"]`) | Keys to redact from log context | | **sourceLocation** | `boolean` | optional (default: `false`) | Include file and line number | | **file** | `string` | optional | Path to log file | -| **rotation** | `{ maxSize: string; maxFiles: number }` | optional | | +| **rotation** | `{ maxSize?: string; maxFiles?: number }` | optional | | ### Nested Shape: `LoggingConfig.loggers[string]` @@ -342,7 +342,7 @@ Logging configuration | **redact** | `string[]` | optional (default: `["password","token","secret","key"]`) | Keys to redact from log context | | **sourceLocation** | `boolean` | optional (default: `false`) | Include file and line number | | **file** | `string` | optional | Path to log file | -| **rotation** | `{ maxSize: string; maxFiles: number }` | optional | | +| **rotation** | `{ maxSize?: string; maxFiles?: number }` | optional | | ### Nested Shape: `LoggingConfig.destinations[number]` @@ -354,9 +354,9 @@ Log destination configuration | **type** | `Enum<'console' \| 'file' \| 'syslog' \| 'elasticsearch' \| 'cloudwatch' \| 'stackdriver' \| …>` | ✅ | Destination type | | **level** | `Enum<'trace' \| 'debug' \| 'info' \| 'warn' \| 'error' \| 'fatal'>` | optional (default: `"info"`) | Extended log severity level | | **enabled** | `boolean` | optional (default: `true`) | | -| **console** | `{ stream: Enum<'stdout' \| 'stderr'>; colors: boolean; prettyPrint: boolean }` | optional | Console destination configuration | -| **file** | `{ path: string; rotation?: object; encoding: string; append: boolean }` | optional | File destination configuration | -| **http** | `{ url: string; method: Enum<'POST' \| 'PUT'>; headers?: Record; auth?: object; … }` | optional | HTTP destination configuration | +| **console** | `{ stream?: Enum<'stdout' \| 'stderr'>; colors?: boolean; prettyPrint?: boolean }` | optional | Console destination configuration | +| **file** | `{ path: string; rotation?: object; encoding?: string; append?: boolean }` | optional | File destination configuration | +| **http** | `{ url: string; method?: Enum<'POST' \| 'PUT'>; headers?: Record; auth?: object; … }` | optional | HTTP destination configuration | | **externalService** | `{ endpoint?: string; region?: string; credentials?: object; logGroup?: string; … }` | optional | External service destination configuration | | **format** | `Enum<'json' \| 'text' \| 'pretty'>` | optional (default: `"json"`) | | | **filterId** | `string` | optional | Filter function identifier | @@ -370,7 +370,7 @@ Log destination configuration | **addHostname** | `boolean` | optional (default: `true`) | | | **addProcessId** | `boolean` | optional (default: `true`) | | | **addEnvironment** | `boolean` | optional (default: `true`) | | -| **addTimestampFormats** | `{ unix: boolean; iso: boolean }` | optional | | +| **addTimestampFormats** | `{ unix?: boolean; iso?: boolean }` | optional | | | **addCaller** | `boolean` | optional (default: `false`) | | | **addCorrelationIds** | `boolean` | optional (default: `true`) | | diff --git a/content/docs/references/system/metadata-persistence.mdx b/content/docs/references/system/metadata-persistence.mdx index 1c33b6e1252..4d02471544b 100644 --- a/content/docs/references/system/metadata-persistence.mdx +++ b/content/docs/references/system/metadata-persistence.mdx @@ -227,7 +227,7 @@ Metadata file format | **supportsWatch** | `boolean` | optional | | | **supportsWrite** | `boolean` | optional | | | **supportsCache** | `boolean` | optional | | -| **capabilities** | `{ read: boolean; write: boolean; watch: boolean; list: boolean }` | ✅ | | +| **capabilities** | `{ read?: boolean; write?: boolean; watch?: boolean; list?: boolean }` | ✅ | | --- @@ -245,10 +245,10 @@ Metadata file format | **formats** | `Enum<'yaml' \| 'json' \| 'typescript' \| 'javascript'>[]` | optional (default: `["typescript","json","yaml"]`) | Enabled formats | | **cache** | `{ databaseLoader?: object }` | optional | Cache settings — only `databaseLoader` is read at runtime; the outer keys are retired | | **watch** | `boolean` | optional (default: `false`) | Enable file watching | -| **watchOptions** | `{ ignored?: string[]; persistent: boolean; ignoreInitial: boolean }` | optional | File watcher options | -| **validation** | `{ strict: boolean; throwOnError: boolean }` | optional | Validation settings | +| **watchOptions** | `{ ignored?: string[]; persistent?: boolean; ignoreInitial?: boolean }` | optional | File watcher options | +| **validation** | `{ strict?: boolean; throwOnError?: boolean }` | optional | Validation settings | | **loaderOptions** | `Record` | optional | Loader-specific configuration | -| **persistence** | `{ writable: boolean }` | optional | Persistence write gates | +| **persistence** | `{ writable?: boolean }` | optional | Persistence write gates | ### Nested Shape: `MetadataManagerConfig.cache` @@ -258,7 +258,7 @@ Metadata file format | **ttlSeconds** | `never` | optional | [REMOVED] `cache.ttlSeconds` was removed from `MetadataManagerConfig` in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: the outer `cache` block was declared and documented but consumed by no runtime, so the number expired nothing. Delete the key. The TTL that is honoured is `cache.databaseLoader.ttlMs` (milliseconds, default 60000) on the DatabaseLoader read-through cache. | | **ttl** | `never` | optional | [REMOVED] `cache.ttl` was removed from `MetadataManagerConfig` in @objectstack/spec 17 — nothing ever read it: the outer `cache` block was declared and documented but consumed by no runtime, and its unit-suffixed respelling `ttlSeconds` was retired with it before it shipped (ADR-0049 enforce-or-remove). Delete the key. The TTL that is honoured is `cache.databaseLoader.ttlMs` (milliseconds, default 60000) on the DatabaseLoader read-through cache. | | **maxSize** | `never` | optional | [REMOVED] `cache.maxSize` was removed from `MetadataManagerConfig` in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: the outer `cache` block was declared and documented but consumed by no runtime, so the byte cap capped nothing. Delete the key. The cap that is honoured is `cache.databaseLoader.maxSize` (an entry count, default 500) on the DatabaseLoader read-through cache. | -| **databaseLoader** | `{ enabled: boolean; maxSize: integer; ttlMs: integer }` | optional | DatabaseLoader read-through cache | +| **databaseLoader** | `{ enabled?: boolean; maxSize?: integer; ttlMs?: integer }` | optional | DatabaseLoader read-through cache | ### Nested Shape: `MetadataManagerConfig.watchOptions` diff --git a/content/docs/references/system/metrics.mdx b/content/docs/references/system/metrics.mdx index 0b4cfb71300..0d579e408e1 100644 --- a/content/docs/references/system/metrics.mdx +++ b/content/docs/references/system/metrics.mdx @@ -78,7 +78,7 @@ Metric aggregation configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **type** | `Enum<'sum' \| 'avg' \| 'min' \| 'max' \| 'count' \| 'p50' \| 'p75' \| 'p90' \| 'p95' \| 'p99' \| 'p999' \| 'rate' \| 'stddev'>` | ✅ | Aggregation type | -| **window** | `{ durationSeconds: integer; sliding: boolean; slideInterval?: integer }` | optional | | +| **window** | `{ durationSeconds: integer; sliding?: boolean; slideInterval?: integer }` | optional | | | **groupBy** | `string[]` | optional | Group by label names | | **filters** | `Record` | optional | Filter criteria | @@ -167,7 +167,7 @@ Metric definition | **description** | `string` | optional | Metric description | | **labelNames** | `string[]` | optional (default: `[]`) | Label names | | **histogram** | `{ type: Enum<'linear' \| 'exponential' \| 'explicit'>; linear?: object; exponential?: object; explicit?: object }` | optional | Histogram bucket configuration | -| **summary** | `{ quantiles: number[]; maxAgeSeconds: integer; ageBuckets: integer }` | optional | | +| **summary** | `{ quantiles?: number[]; maxAgeSeconds?: integer; ageBuckets?: integer }` | optional | | | **enabled** | `boolean` | optional (default: `true`) | | ### Allowed Values: `MetricDefinition.unit` @@ -226,7 +226,7 @@ Metric export configuration | **endpoint** | `string` | optional | Export endpoint | | **intervalSeconds** | `integer` | optional (default: `60`) | Export interval in seconds | | **interval** | `never` | optional | [REMOVED] `MetricExportConfig.interval` was renamed to `intervalSeconds` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (seconds) lived in a source JSDoc only and the key carried no describe at all, so a reader of the reference page could not tell 60 seconds from 60 milliseconds. Rename the key to `intervalSeconds`; the value (seconds) is unchanged. | -| **batch** | `{ enabled: boolean; size: integer }` | optional | | +| **batch** | `{ enabled?: boolean; size?: integer }` | optional | | | **auth** | `{ type: Enum<'none' \| 'basic' \| 'bearer' \| 'api_key'>; username?: string; password?: string; token?: string; … }` | optional | | | **config** | `Record` | optional | Additional configuration | @@ -312,11 +312,11 @@ Metrics configuration | **aggregations** | `{ type: Enum<'sum' \| 'avg' \| 'min' \| 'max' \| 'count' \| 'p50' \| 'p75' \| 'p90' \| 'p95' \| 'p99' \| …>; window?: object; groupBy?: string[]; filters?: Record }[]` | optional (default: `[]`) | | | **slis** | `{ name: string; label: string; description?: string; metric: string; … }[]` | optional (default: `[]`) | | | **slos** | `{ name: string; label: string; description?: string; sli: string; … }[]` | optional (default: `[]`) | | -| **exports** | `{ type: Enum<'prometheus' \| 'openmetrics' \| 'graphite' \| 'statsd' \| 'influxdb' \| 'datadog' \| …>; endpoint?: string; intervalSeconds: integer; batch?: object; … }[]` | optional (default: `[]`) | | +| **exports** | `{ type: Enum<'prometheus' \| 'openmetrics' \| 'graphite' \| 'statsd' \| 'influxdb' \| 'datadog' \| …>; endpoint?: string; intervalSeconds?: integer; batch?: object; … }[]` | optional (default: `[]`) | | | **collectionIntervalSeconds** | `integer` | optional (default: `15`) | Collection interval in seconds | | **collectionInterval** | `never` | optional | [REMOVED] `MetricsConfig.collectionInterval` was renamed to `collectionIntervalSeconds` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (seconds) lived in a source JSDoc only and the key carried no describe at all, so a reader of the reference page could not tell 15 seconds from 15 milliseconds. The qualifier is kept — `collectionIntervalSeconds`, not `intervalSeconds` — because `MetricExportConfig.intervalSeconds` is a different cadence one def over. Rename the key to `collectionIntervalSeconds`; the value (seconds) is unchanged. | -| **retention** | `{ durationSeconds: integer; downsampling?: object[] }` | optional | | -| **cardinalityLimits** | `{ maxLabelCombinations: integer; onLimitExceeded: Enum<'drop' \| 'sample' \| 'alert'> }` | optional | | +| **retention** | `{ durationSeconds?: integer; downsampling?: object[] }` | optional | | +| **cardinalityLimits** | `{ maxLabelCombinations?: integer; onLimitExceeded?: Enum<'drop' \| 'sample' \| 'alert'> }` | optional | | ### Nested Shape: `MetricsConfig.metrics[number]` @@ -331,7 +331,7 @@ Metric definition | **description** | `string` | optional | Metric description | | **labelNames** | `string[]` | optional (default: `[]`) | Label names | | **histogram** | `{ type: Enum<'linear' \| 'exponential' \| 'explicit'>; linear?: object; exponential?: object; explicit?: object }` | optional | Histogram bucket configuration | -| **summary** | `{ quantiles: number[]; maxAgeSeconds: integer; ageBuckets: integer }` | optional | | +| **summary** | `{ quantiles?: number[]; maxAgeSeconds?: integer; ageBuckets?: integer }` | optional | | | **enabled** | `boolean` | optional (default: `true`) | | ### Nested Shape: `MetricsConfig.aggregations[number]` @@ -341,7 +341,7 @@ Metric aggregation configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **type** | `Enum<'sum' \| 'avg' \| 'min' \| 'max' \| 'count' \| 'p50' \| 'p75' \| 'p90' \| 'p95' \| 'p99' \| …>` | ✅ | Aggregation type | -| **window** | `{ durationSeconds: integer; sliding: boolean; slideInterval?: integer }` | optional | | +| **window** | `{ durationSeconds: integer; sliding?: boolean; slideInterval?: integer }` | optional | | | **groupBy** | `string[]` | optional | Group by label names | | **filters** | `Record` | optional | Filter criteria | @@ -357,7 +357,7 @@ Service Level Indicator | **metric** | `string` | ✅ | Base metric name | | **type** | `Enum<'availability' \| 'latency' \| 'throughput' \| 'error_rate' \| 'saturation' \| 'custom'>` | ✅ | SLI type | | **successCriteria** | `{ threshold: number; operator: Enum<'lt' \| 'lte' \| 'gt' \| 'gte' \| 'eq'>; percentile?: number }` | ✅ | Success criteria — a structured threshold rule. A CEL predicate is NOT accepted here: that arm was removed in 17.5.0 because nothing evaluated it. | -| **window** | `{ durationSeconds: integer; rolling: boolean }` | ✅ | Measurement window | +| **window** | `{ durationSeconds: integer; rolling?: boolean }` | ✅ | Measurement window | | **enabled** | `boolean` | optional (default: `true`) | | ### Nested Shape: `MetricsConfig.slos[number]` @@ -372,7 +372,7 @@ Service Level Objective | **sli** | `string` | ✅ | SLI name | | **target** | `number` | ✅ | Target percentage | | **period** | `{ type: Enum<'rolling' \| 'calendar'>; durationSeconds?: integer; calendar?: Enum<'daily' \| 'weekly' \| 'monthly' \| 'quarterly' \| 'yearly'> }` | ✅ | Time period | -| **errorBudget** | `{ enabled: boolean; alertThreshold: number; burnRateWindows?: object[] }` | optional | | +| **errorBudget** | `{ enabled?: boolean; alertThreshold?: number; burnRateWindows?: object[] }` | optional | | | **alerts** | `{ name: string; severity: Enum<'info' \| 'warning' \| 'critical'>; condition: object }[]` | optional (default: `[]`) | | | **enabled** | `boolean` | optional (default: `true`) | | @@ -386,7 +386,7 @@ Metric export configuration | **endpoint** | `string` | optional | Export endpoint | | **intervalSeconds** | `integer` | optional (default: `60`) | Export interval in seconds | | **interval** | `never` | optional | [REMOVED] `MetricExportConfig.interval` was renamed to `intervalSeconds` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (seconds) lived in a source JSDoc only and the key carried no describe at all, so a reader of the reference page could not tell 60 seconds from 60 milliseconds. Rename the key to `intervalSeconds`; the value (seconds) is unchanged. | -| **batch** | `{ enabled: boolean; size: integer }` | optional | | +| **batch** | `{ enabled?: boolean; size?: integer }` | optional | | | **auth** | `{ type: Enum<'none' \| 'basic' \| 'bearer' \| 'api_key'>; username?: string; password?: string; token?: string; … }` | optional | | | **config** | `Record` | optional | Additional configuration | @@ -415,7 +415,7 @@ Service Level Indicator | **metric** | `string` | ✅ | Base metric name | | **type** | `Enum<'availability' \| 'latency' \| 'throughput' \| 'error_rate' \| 'saturation' \| 'custom'>` | ✅ | SLI type | | **successCriteria** | `{ threshold: number; operator: Enum<'lt' \| 'lte' \| 'gt' \| 'gte' \| 'eq'>; percentile?: number }` | ✅ | Success criteria — a structured threshold rule. A CEL predicate is NOT accepted here: that arm was removed in 17.5.0 because nothing evaluated it. | -| **window** | `{ durationSeconds: integer; rolling: boolean }` | ✅ | Measurement window | +| **window** | `{ durationSeconds: integer; rolling?: boolean }` | ✅ | Measurement window | | **enabled** | `boolean` | optional (default: `true`) | | ### Nested Shape: `ServiceLevelIndicator.successCriteria` @@ -451,7 +451,7 @@ Service Level Objective | **sli** | `string` | ✅ | SLI name | | **target** | `number` | ✅ | Target percentage | | **period** | `{ type: Enum<'rolling' \| 'calendar'>; durationSeconds?: integer; calendar?: Enum<'daily' \| 'weekly' \| 'monthly' \| 'quarterly' \| 'yearly'> }` | ✅ | Time period | -| **errorBudget** | `{ enabled: boolean; alertThreshold: number; burnRateWindows?: object[] }` | optional | | +| **errorBudget** | `{ enabled?: boolean; alertThreshold?: number; burnRateWindows?: object[] }` | optional | | | **alerts** | `{ name: string; severity: Enum<'info' \| 'warning' \| 'critical'>; condition: object }[]` | optional (default: `[]`) | | | **enabled** | `boolean` | optional (default: `true`) | | diff --git a/content/docs/references/system/object-storage.mdx b/content/docs/references/system/object-storage.mdx index fe193352b92..24146e49e8b 100644 --- a/content/docs/references/system/object-storage.mdx +++ b/content/docs/references/system/object-storage.mdx @@ -48,7 +48,7 @@ const result = AccessControlConfigSchema.parse(data); | **maxAgeSeconds** | `number` | optional | CORS preflight cache duration in seconds | | **maxAge** | `never` | optional | [REMOVED] `AccessControlConfig.maxAge` was renamed to `maxAgeSeconds` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Every bucket-CORS standard this value is forwarded to already spells the unit (S3 MaxAgeSeconds, GCS maxAgeSeconds, Azure MaxAgeInSeconds), so the bare name was a deviation from them rather than a mirror of them. Rename the key to `maxAgeSeconds`; the value (seconds) is unchanged. The unrelated `CorsConfig.maxAge` on the shared HTTP surface keeps its name — that one mirrors the Access-Control-Max-Age response header, which carries no unit token. | | **corsEnabled** | `boolean` | optional (default: `false`) | Enable CORS configuration | -| **publicAccess** | `{ allowPublicRead: boolean; allowPublicWrite: boolean; allowPublicList: boolean }` | optional | Public access control | +| **publicAccess** | `{ allowPublicRead?: boolean; allowPublicWrite?: boolean; allowPublicList?: boolean }` | optional | Public access control | | **allowedIps** | `string[]` | optional | Allowed IP addresses/CIDR blocks | | **blockedIps** | `string[]` | optional | Blocked IP addresses/CIDR blocks | @@ -77,10 +77,10 @@ const result = AccessControlConfigSchema.parse(data); | **endpoint** | `string` | optional | Custom endpoint URL (for S3-compatible providers) | | **pathStyle** | `boolean` | optional (default: `false`) | Use path-style URLs (for S3-compatible providers) | | **versioning** | `boolean` | optional (default: `false`) | 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' \| …>; allowedOrigins?: string[]; allowedMethods?: Enum<'GET' \| 'PUT' \| 'POST' \| 'DELETE' \| 'HEAD'>[]; allowedHeaders?: string[]; … }` | optional | Access control configuration | -| **lifecyclePolicy** | `{ enabled: boolean; rules: object[] }` | optional | Lifecycle policy configuration | -| **multipartConfig** | `{ enabled: boolean; partSize: number; maxParts: number; threshold: number; … }` | optional | Multipart upload configuration | +| **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' \| …>; allowedOrigins?: string[]; allowedMethods?: Enum<'GET' \| 'PUT' \| 'POST' \| 'DELETE' \| 'HEAD'>[]; allowedHeaders?: string[]; … }` | optional | Access control 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 | | **enabled** | `boolean` | optional (default: `true`) | Enable this bucket | @@ -105,7 +105,7 @@ const result = AccessControlConfigSchema.parse(data); | **maxAgeSeconds** | `number` | optional | CORS preflight cache duration in seconds | | **maxAge** | `never` | optional | [REMOVED] `AccessControlConfig.maxAge` was renamed to `maxAgeSeconds` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Every bucket-CORS standard this value is forwarded to already spells the unit (S3 MaxAgeSeconds, GCS maxAgeSeconds, Azure MaxAgeInSeconds), so the bare name was a deviation from them rather than a mirror of them. Rename the key to `maxAgeSeconds`; the value (seconds) is unchanged. The unrelated `CorsConfig.maxAge` on the shared HTTP surface keeps its name — that one mirrors the Access-Control-Max-Age response header, which carries no unit token. | | **corsEnabled** | `boolean` | optional (default: `false`) | Enable CORS configuration | -| **publicAccess** | `{ allowPublicRead: boolean; allowPublicWrite: boolean; allowPublicList: boolean }` | optional | Public access control | +| **publicAccess** | `{ allowPublicRead?: boolean; allowPublicWrite?: boolean; allowPublicList?: boolean }` | optional | Public access control | | **allowedIps** | `string[]` | optional | Allowed IP addresses/CIDR blocks | | **blockedIps** | `string[]` | optional | Blocked IP addresses/CIDR blocks | @@ -114,7 +114,7 @@ const result = AccessControlConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | optional (default: `false`) | Enable lifecycle policies | -| **rules** | `{ id: string; enabled: boolean; action: Enum<'transition' \| 'delete' \| 'abort'>; prefix?: string; … }[]` | optional (default: `[]`) | Lifecycle rules | +| **rules** | `{ id: string; enabled?: boolean; action: Enum<'transition' \| 'delete' \| 'abort'>; prefix?: string; … }[]` | optional (default: `[]`) | Lifecycle rules | ### Nested Shape: `BucketConfig.multipartConfig` @@ -168,7 +168,7 @@ Lifecycle policy action type | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | optional (default: `false`) | Enable lifecycle policies | -| **rules** | `{ id: string; enabled: boolean; action: Enum<'transition' \| 'delete' \| 'abort'>; prefix?: string; … }[]` | optional (default: `[]`) | Lifecycle rules | +| **rules** | `{ id: string; enabled?: boolean; action: Enum<'transition' \| 'delete' \| 'abort'>; prefix?: string; … }[]` | optional (default: `[]`) | Lifecycle rules | ### Nested Shape: `LifecyclePolicyConfig.rules[number]` @@ -298,10 +298,10 @@ Lifecycle policy action type | **endpoint** | `string` | optional | Custom endpoint URL (for S3-compatible providers) | | **pathStyle** | `boolean` | optional (default: `false`) | Use path-style URLs (for S3-compatible providers) | | **versioning** | `boolean` | optional (default: `false`) | 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' \| …>; allowedOrigins?: string[]; allowedMethods?: Enum<'GET' \| 'PUT' \| 'POST' \| 'DELETE' \| 'HEAD'>[]; allowedHeaders?: string[]; … }` | optional | Access control configuration | -| **lifecyclePolicy** | `{ enabled: boolean; rules: object[] }` | optional | Lifecycle policy configuration | -| **multipartConfig** | `{ enabled: boolean; partSize: number; maxParts: number; threshold: number; … }` | optional | Multipart upload configuration | +| **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' \| …>; allowedOrigins?: string[]; allowedMethods?: Enum<'GET' \| 'PUT' \| 'POST' \| 'DELETE' \| 'HEAD'>[]; allowedHeaders?: string[]; … }` | optional | Access control 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 | | **enabled** | `boolean` | optional (default: `true`) | Enable this bucket | diff --git a/content/docs/references/system/registry-config.mdx b/content/docs/references/system/registry-config.mdx index 321eaef9b6a..fb09a0dbf98 100644 --- a/content/docs/references/system/registry-config.mdx +++ b/content/docs/references/system/registry-config.mdx @@ -34,14 +34,14 @@ const result = RegistryConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **type** | `Enum<'public' \| 'private' \| 'hybrid'>` | ✅ | Registry deployment type | -| **upstream** | `{ url: string; syncPolicy: Enum<'manual' \| 'auto' \| 'proxy'>; syncIntervalSeconds?: integer; auth?: object; … }[]` | optional | Upstream registries to sync from or proxy to | +| **upstream** | `{ url: string; syncPolicy?: Enum<'manual' \| 'auto' \| 'proxy'>; syncIntervalSeconds?: integer; auth?: object; … }[]` | optional | Upstream registries to sync from or proxy to | | **scope** | `string[]` | optional | npm-style scopes managed by this registry (e.g., @my-corp, @enterprise) | | **defaultScope** | `string` | optional | Default scope prefix for new plugins | -| **storage** | `{ backend: Enum<'local' \| 's3' \| 'gcs' \| 'azure-blob' \| 'oss'>; path?: string; credentials?: Record }` | optional | | +| **storage** | `{ backend?: Enum<'local' \| 's3' \| 'gcs' \| 'azure-blob' \| 'oss'>; path?: string; credentials?: Record }` | optional | | | **visibility** | `Enum<'public' \| 'private' \| 'internal'>` | optional (default: `"private"`) | Who can access this registry | -| **accessControl** | `{ requireAuthForRead: boolean; requireAuthForWrite: boolean; allowedPrincipals?: string[] }` | optional | | -| **cache** | `{ enabled: boolean; ttlSeconds: integer; maxSize?: integer }` | optional | | -| **mirrors** | `{ url: string; priority: integer }[]` | optional | Mirror registries for redundancy | +| **accessControl** | `{ requireAuthForRead?: boolean; requireAuthForWrite?: boolean; allowedPrincipals?: string[] }` | optional | | +| **cache** | `{ enabled?: boolean; ttlSeconds?: integer; maxSize?: integer }` | optional | | +| **mirrors** | `{ url: string; priority?: integer }[]` | optional | Mirror registries for redundancy | ### Nested Shape: `RegistryConfig.upstream[number]` @@ -51,11 +51,11 @@ const result = RegistryConfigSchema.parse(data); | **syncPolicy** | `Enum<'manual' \| 'auto' \| 'proxy'>` | optional (default: `"auto"`) | Registry synchronization strategy | | **syncIntervalSeconds** | `integer` | optional | Auto-sync interval in seconds | | **syncInterval** | `never` | optional | [REMOVED] `RegistryUpstream.syncInterval` was renamed to `syncIntervalSeconds` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose, and the `timeout` beside it on this same block is milliseconds. Rename the key to `syncIntervalSeconds`; the value (seconds) and the min-60 bound are unchanged. | -| **auth** | `{ type: Enum<'none' \| 'basic' \| 'bearer' \| 'api-key' \| 'oauth2'>; username?: string; password?: string; token?: string; … }` | optional | | -| **tls** | `{ enabled: boolean; verifyCertificate: boolean; certificate?: string; privateKey?: string }` | optional | | +| **auth** | `{ type?: Enum<'none' \| 'basic' \| 'bearer' \| 'api-key' \| 'oauth2'>; username?: string; password?: string; token?: string; … }` | optional | | +| **tls** | `{ enabled?: boolean; verifyCertificate?: boolean; certificate?: string; privateKey?: string }` | optional | | | **timeoutMs** | `integer` | optional (default: `30000`) | Request timeout in milliseconds | | **timeout** | `never` | optional | [REMOVED] `RegistryUpstream.timeout` was renamed to `timeoutMs` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose, and `syncIntervalSeconds` on this same block is seconds. Rename the key to `timeoutMs`; the value (milliseconds), the 30000 default and the min-1000 bound are unchanged. | -| **retry** | `{ maxAttempts: integer; backoff: Enum<'fixed' \| 'linear' \| 'exponential'> }` | optional | | +| **retry** | `{ maxAttempts?: integer; backoff?: Enum<'fixed' \| 'linear' \| 'exponential'> }` | optional | | ### Nested Shape: `RegistryConfig.cache` @@ -92,11 +92,11 @@ Registry synchronization strategy | **syncPolicy** | `Enum<'manual' \| 'auto' \| 'proxy'>` | optional (default: `"auto"`) | Registry synchronization strategy | | **syncIntervalSeconds** | `integer` | optional | Auto-sync interval in seconds | | **syncInterval** | `never` | optional | [REMOVED] `RegistryUpstream.syncInterval` was renamed to `syncIntervalSeconds` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose, and the `timeout` beside it on this same block is milliseconds. Rename the key to `syncIntervalSeconds`; the value (seconds) and the min-60 bound are unchanged. | -| **auth** | `{ type: Enum<'none' \| 'basic' \| 'bearer' \| 'api-key' \| 'oauth2'>; username?: string; password?: string; token?: string; … }` | optional | | -| **tls** | `{ enabled: boolean; verifyCertificate: boolean; certificate?: string; privateKey?: string }` | optional | | +| **auth** | `{ type?: Enum<'none' \| 'basic' \| 'bearer' \| 'api-key' \| 'oauth2'>; username?: string; password?: string; token?: string; … }` | optional | | +| **tls** | `{ enabled?: boolean; verifyCertificate?: boolean; certificate?: string; privateKey?: string }` | optional | | | **timeoutMs** | `integer` | optional (default: `30000`) | Request timeout in milliseconds | | **timeout** | `never` | optional | [REMOVED] `RegistryUpstream.timeout` was renamed to `timeoutMs` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose, and `syncIntervalSeconds` on this same block is seconds. Rename the key to `timeoutMs`; the value (milliseconds), the 30000 default and the min-1000 bound are unchanged. | -| **retry** | `{ maxAttempts: integer; backoff: Enum<'fixed' \| 'linear' \| 'exponential'> }` | optional | | +| **retry** | `{ maxAttempts?: integer; backoff?: Enum<'fixed' \| 'linear' \| 'exponential'> }` | optional | | --- diff --git a/content/docs/references/system/search-engine.mdx b/content/docs/references/system/search-engine.mdx index 56523c31b7f..e595a42d2e6 100644 --- a/content/docs/references/system/search-engine.mdx +++ b/content/docs/references/system/search-engine.mdx @@ -62,9 +62,9 @@ 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: object[]; 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 | +| **facets** | `{ field: string; maxValues?: number; sort?: Enum<'count' \| 'alpha'> }[]` | optional | Faceted search configurations | | **typoTolerance** | `boolean` | optional (default: `true`) | Enable typo-tolerant search | | **synonyms** | `Record` | optional | Synonym mappings for search expansion | | **ranking** | `Enum<'typo' \| 'geo' \| 'words' \| 'filters' \| 'proximity' \| 'attribute' \| 'exact' \| 'custom'>[]` | optional | Custom ranking rule order | @@ -77,7 +77,7 @@ Search index definition mapping an ObjectQL object to a search engine index | :--- | :--- | :--- | :--- | | **indexName** | `string` | ✅ | Name of the search index | | **objectName** | `string` | ✅ | Source ObjectQL object | -| **fields** | `{ name: string; type: Enum<'text' \| 'keyword' \| 'number' \| 'date' \| 'boolean' \| 'geo'>; analyzer?: string; searchable: boolean; … }[]` | ✅ | Fields to include in the search index | +| **fields** | `{ name: string; type: Enum<'text' \| 'keyword' \| 'number' \| 'date' \| 'boolean' \| 'geo'>; analyzer?: string; searchable?: boolean; … }[]` | ✅ | Fields to include in the search index | | **replicas** | `number` | optional (default: `1`) | Number of index replicas for availability | | **shards** | `number` | optional (default: `1`) | Number of index shards for distribution | @@ -115,7 +115,7 @@ Search index definition mapping an ObjectQL object to a search engine index | :--- | :--- | :--- | :--- | | **indexName** | `string` | ✅ | Name of the search index | | **objectName** | `string` | ✅ | Source ObjectQL object | -| **fields** | `{ name: string; type: Enum<'text' \| 'keyword' \| 'number' \| 'date' \| 'boolean' \| 'geo'>; analyzer?: string; searchable: boolean; … }[]` | ✅ | Fields to include in the search index | +| **fields** | `{ name: string; type: Enum<'text' \| 'keyword' \| 'number' \| 'date' \| 'boolean' \| 'geo'>; analyzer?: string; searchable?: boolean; … }[]` | ✅ | Fields to include in the search index | | **replicas** | `number` | optional (default: `1`) | Number of index replicas for availability | | **shards** | `number` | optional (default: `1`) | Number of index shards for distribution | diff --git a/content/docs/references/system/security-context.mdx b/content/docs/references/system/security-context.mdx index 3a2e872370c..ed080ef1680 100644 --- a/content/docs/references/system/security-context.mdx +++ b/content/docs/references/system/security-context.mdx @@ -150,11 +150,11 @@ Unified security context governance configuration | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **enabled** | `boolean` | optional (default: `true`) | Enable unified security context governance | -| **complianceAuditRequirements** | `{ framework: Enum<'gdpr' \| 'hipaa' \| 'sox' \| 'pci_dss' \| 'ccpa' \| 'iso27001'>; requiredEvents: string[]; retentionDays: number; alertOnMissing: boolean }[]` | optional | Compliance-driven audit event requirements | -| **complianceEncryptionRequirements** | `{ framework: Enum<'gdpr' \| 'hipaa' \| 'sox' \| 'pci_dss' \| 'ccpa' \| 'iso27001'>; dataClassifications: Enum<'pii' \| 'phi' \| 'pci' \| 'financial' \| 'confidential' \| 'internal' \| 'public'>[]; minimumAlgorithm: Enum<'aes-256-gcm' \| 'aes-256-cbc' \| 'chacha20-poly1305'>; keyRotationMaxDays: number }[]` | optional | Compliance-driven encryption requirements by data classification | -| **maskingVisibility** | `{ dataClassification: Enum<'pii' \| 'phi' \| 'pci' \| 'financial' \| 'confidential' \| 'internal' \| 'public'>; defaultMasked: boolean; unmaskRoles?: string[]; auditUnmask: boolean; … }[]` | optional | Masking visibility rules per data classification | -| **dataClassifications** | `{ classification: Enum<'pii' \| 'phi' \| 'pci' \| 'financial' \| 'confidential' \| 'internal' \| 'public'>; requireEncryption: boolean; requireMasking: boolean; requireAudit: boolean; … }[]` | optional | Data classification policies for unified security enforcement | -| **eventCorrelation** | `{ enabled: boolean; correlationId: boolean; linkAuthToAudit: boolean; linkEncryptionToAudit: boolean; … }` | optional | Cross-subsystem security event correlation settings | +| **complianceAuditRequirements** | `{ framework: Enum<'gdpr' \| 'hipaa' \| 'sox' \| 'pci_dss' \| 'ccpa' \| 'iso27001'>; requiredEvents: string[]; retentionDays: number; alertOnMissing?: boolean }[]` | optional | Compliance-driven audit event requirements | +| **complianceEncryptionRequirements** | `{ framework: Enum<'gdpr' \| 'hipaa' \| 'sox' \| 'pci_dss' \| 'ccpa' \| 'iso27001'>; dataClassifications: Enum<'pii' \| 'phi' \| 'pci' \| 'financial' \| 'confidential' \| 'internal' \| 'public'>[]; minimumAlgorithm?: Enum<'aes-256-gcm' \| 'aes-256-cbc' \| 'chacha20-poly1305'>; keyRotationMaxDays?: number }[]` | optional | Compliance-driven encryption requirements by data classification | +| **maskingVisibility** | `{ dataClassification: Enum<'pii' \| 'phi' \| 'pci' \| 'financial' \| 'confidential' \| 'internal' \| 'public'>; defaultMasked?: boolean; unmaskRoles?: string[]; auditUnmask?: boolean; … }[]` | optional | Masking visibility rules per data classification | +| **dataClassifications** | `{ classification: Enum<'pii' \| 'phi' \| 'pci' \| 'financial' \| 'confidential' \| 'internal' \| 'public'>; requireEncryption?: boolean; requireMasking?: boolean; requireAudit?: boolean; … }[]` | optional | Data classification policies for unified security enforcement | +| **eventCorrelation** | `{ enabled?: boolean; correlationId?: boolean; linkAuthToAudit?: boolean; linkEncryptionToAudit?: boolean; … }` | optional | Cross-subsystem security event correlation settings | | **enforceOnWrite** | `boolean` | optional (default: `true`) | Enforce encryption and masking requirements on data write operations | | **enforceOnRead** | `boolean` | optional (default: `true`) | Enforce masking and audit requirements on data read operations | | **failOpen** | `boolean` | optional (default: `false`) | When false (default), deny access if security context cannot be evaluated | diff --git a/content/docs/references/system/stack-server.mdx b/content/docs/references/system/stack-server.mdx index 4f44c4164cf..dd693954c06 100644 --- a/content/docs/references/system/stack-server.mdx +++ b/content/docs/references/system/stack-server.mdx @@ -107,7 +107,7 @@ const result = ServerRateLimitConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **rateLimit** | `{ enabled: boolean; windowMs: integer; maxRequests: integer }` | optional | Global inbound rate limit. When `enabled`, every inbound request consumes from a token bucket derived from this budget (capacity = `maxRequests`, refill = `maxRequests / (windowMs / 1000)` tokens per second); an empty bucket answers 429 with a `Retry-After` header. The bucket is keyed by the RESOLVED PRINCIPAL, falling back to the caller IP for anonymous traffic — so one abusive session cannot exhaust another user's budget, and credential-stuffing traffic (which has no principal yet) is still metered per source. See `server.trustProxy` for how that IP is determined. | +| **rateLimit** | `{ enabled?: boolean; windowMs?: integer; maxRequests?: integer }` | optional | Global inbound rate limit. When `enabled`, every inbound request consumes from a token bucket derived from this budget (capacity = `maxRequests`, refill = `maxRequests / (windowMs / 1000)` tokens per second); an empty bucket answers 429 with a `Retry-After` header. The bucket is keyed by the RESOLVED PRINCIPAL, falling back to the caller IP for anonymous traffic — so one abusive session cannot exhaust another user's budget, and credential-stuffing traffic (which has no principal yet) is still metered per source. See `server.trustProxy` for how that IP is determined. | --- @@ -118,7 +118,7 @@ const result = ServerRateLimitConfigSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **rateLimit** | `{ enabled: boolean; windowMs: integer; maxRequests: integer }` | optional | Global inbound rate limit. When `enabled`, every inbound request consumes from a token bucket derived from this budget (capacity = `maxRequests`, refill = `maxRequests / (windowMs / 1000)` tokens per second); an empty bucket answers 429 with a `Retry-After` header. The bucket is keyed by the RESOLVED PRINCIPAL, falling back to the caller IP for anonymous traffic — so one abusive session cannot exhaust another user's budget, and credential-stuffing traffic (which has no principal yet) is still metered per source. See `server.trustProxy` for how that IP is determined. | +| **rateLimit** | `{ enabled?: boolean; windowMs?: integer; maxRequests?: integer }` | optional | Global inbound rate limit. When `enabled`, every inbound request consumes from a token bucket derived from this budget (capacity = `maxRequests`, refill = `maxRequests / (windowMs / 1000)` tokens per second); an empty bucket answers 429 with a `Retry-After` header. The bucket is keyed by the RESOLVED PRINCIPAL, falling back to the caller IP for anonymous traffic — so one abusive session cannot exhaust another user's budget, and credential-stuffing traffic (which has no principal yet) is still metered per source. See `server.trustProxy` for how that IP is determined. | ### Nested Shape: `StackServerSecurity.rateLimit` diff --git a/content/docs/references/system/supplier-security.mdx b/content/docs/references/system/supplier-security.mdx index 3f7959759de..26b5eb80e6e 100644 --- a/content/docs/references/system/supplier-security.mdx +++ b/content/docs/references/system/supplier-security.mdx @@ -69,12 +69,12 @@ Supplier security assessment record per ISO 27001:2022 A.5.19–A.5.21 | **assessedBy** | `string` | ✅ | Assessor user ID or team | | **assessedAt** | `integer` | ✅ | Assessment timestamp | | **validUntil** | `integer` | ✅ | Assessment validity expiry timestamp | -| **requirements** | `{ id: string; description: string; controlReference?: string; mandatory: boolean; … }[]` | ✅ | Security requirements and their compliance status | +| **requirements** | `{ id: string; description: string; controlReference?: string; mandatory?: boolean; … }[]` | ✅ | Security requirements and their compliance status | | **overallCompliant** | `boolean` | ✅ | Whether supplier meets all mandatory requirements | | **dataClassificationsShared** | `Enum<'pii' \| 'phi' \| 'pci' \| 'financial' \| 'confidential' \| 'internal' \| 'public'>[]` | optional | Data classifications shared with supplier | | **servicesProvided** | `string[]` | optional | Services provided by this supplier | | **certifications** | `string[]` | optional | Supplier certifications (e.g., ISO 27001, SOC 2) | -| **remediationItems** | `{ requirementId: string; action: string; deadline: integer; status: Enum<'pending' \| 'in_progress' \| 'completed'> }[]` | optional | Remediation items for non-compliant requirements | +| **remediationItems** | `{ requirementId: string; action: string; deadline: integer; status?: Enum<'pending' \| 'in_progress' \| 'completed'> }[]` | optional | Remediation items for non-compliant requirements | | **metadata** | `Record` | optional | Custom metadata key-value pairs | ### Nested Shape: `SupplierSecurityAssessment.requirements[number]` diff --git a/content/docs/references/system/tenant.mdx b/content/docs/references/system/tenant.mdx index 45a61b0f9c9..98eb5b34884 100644 --- a/content/docs/references/system/tenant.mdx +++ b/content/docs/references/system/tenant.mdx @@ -40,10 +40,10 @@ const result = DatabaseLevelIsolationStrategySchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **strategy** | `'isolated_db'` | ✅ | Database-level isolation strategy | -| **database** | `{ namingPattern: string; serverStrategy: Enum<'shared' \| 'sharded' \| 'dedicated'>; separateCredentials: boolean; autoCreateDatabase: boolean }` | optional | Database configuration | -| **connectionPool** | `{ poolSize: integer; maxActivePools: integer; idleTimeoutSeconds: integer; usePooler: boolean }` | optional | Connection pool configuration | -| **backup** | `{ strategy: Enum<'individual' \| 'consolidated' \| 'on_demand'>; frequencyHours: integer; retentionDays: integer }` | optional | Backup configuration | -| **encryption** | `{ perTenantKeys: boolean; algorithm: string; keyManagement?: Enum<'aws_kms' \| 'azure_key_vault' \| 'gcp_kms' \| 'hashicorp_vault' \| 'custom'> }` | optional | Encryption configuration | +| **database** | `{ namingPattern?: string; serverStrategy?: Enum<'shared' \| 'sharded' \| 'dedicated'>; separateCredentials?: boolean; autoCreateDatabase?: boolean }` | optional | Database configuration | +| **connectionPool** | `{ poolSize?: integer; maxActivePools?: integer; idleTimeoutSeconds?: integer; usePooler?: boolean }` | optional | Connection pool configuration | +| **backup** | `{ strategy?: Enum<'individual' \| 'consolidated' \| 'on_demand'>; frequencyHours?: integer; retentionDays?: integer }` | optional | Backup configuration | +| **encryption** | `{ perTenantKeys?: boolean; algorithm?: string; keyManagement?: Enum<'aws_kms' \| 'azure_key_vault' \| 'gcp_kms' \| 'hashicorp_vault' \| 'custom'> }` | optional | Encryption configuration | ### Nested Shape: `DatabaseLevelIsolationStrategy.database` @@ -120,8 +120,8 @@ Quota enforcement check result | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **strategy** | `'shared_schema'` | ✅ | Row-level isolation strategy | -| **database** | `{ enableRLS: boolean; contextMethod: Enum<'session_variable' \| 'search_path' \| 'application_name'>; contextVariable: string; applicationValidation: boolean }` | optional | Database configuration | -| **performance** | `{ usePartialIndexes: boolean; usePartitioning: boolean; poolSizePerTenant?: integer }` | optional | Performance settings | +| **database** | `{ enableRLS?: boolean; contextMethod?: Enum<'session_variable' \| 'search_path' \| 'application_name'>; contextVariable?: string; applicationValidation?: boolean }` | optional | Database configuration | +| **performance** | `{ usePartialIndexes?: boolean; usePartitioning?: boolean; poolSizePerTenant?: integer }` | optional | Performance settings | ### Nested Shape: `RowLevelIsolationStrategy.database` @@ -150,9 +150,9 @@ Quota enforcement check result | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **strategy** | `'isolated_schema'` | ✅ | Schema-level isolation strategy | -| **schema** | `{ namingPattern: string; includePublicSchema: boolean; sharedSchema: string; autoCreateSchema: boolean }` | optional | Schema configuration | -| **migrations** | `{ strategy: Enum<'parallel' \| 'sequential' \| 'on_demand'>; maxConcurrent: integer; rollbackOnError: boolean }` | optional | Migration configuration | -| **performance** | `{ poolPerSchema: boolean; schemaCacheTtlSeconds: integer }` | optional | Performance settings | +| **schema** | `{ namingPattern?: string; includePublicSchema?: boolean; sharedSchema?: string; autoCreateSchema?: boolean }` | optional | Schema configuration | +| **migrations** | `{ strategy?: Enum<'parallel' \| 'sequential' \| 'on_demand'>; maxConcurrent?: integer; rollbackOnError?: boolean }` | optional | Migration configuration | +| **performance** | `{ poolPerSchema?: boolean; schemaCacheTtlSeconds?: integer }` | optional | Performance settings | ### Nested Shape: `SchemaLevelIsolationStrategy.schema` @@ -249,8 +249,8 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **strategy** | `'shared_schema'` | ✅ | Row-level isolation strategy | -| **database** | `{ enableRLS: boolean; contextMethod: Enum<'session_variable' \| 'search_path' \| 'application_name'>; contextVariable: string; applicationValidation: boolean }` | optional | Database configuration | -| **performance** | `{ usePartialIndexes: boolean; usePartitioning: boolean; poolSizePerTenant?: integer }` | optional | Performance settings | +| **database** | `{ enableRLS?: boolean; contextMethod?: Enum<'session_variable' \| 'search_path' \| 'application_name'>; contextVariable?: string; applicationValidation?: boolean }` | optional | Database configuration | +| **performance** | `{ usePartialIndexes?: boolean; usePartitioning?: boolean; poolSizePerTenant?: integer }` | optional | Performance settings | ### Nested Shape: `TenantIsolationConfig[strategy='shared_schema'].database` @@ -278,9 +278,9 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **strategy** | `'isolated_schema'` | ✅ | Schema-level isolation strategy | -| **schema** | `{ namingPattern: string; includePublicSchema: boolean; sharedSchema: string; autoCreateSchema: boolean }` | optional | Schema configuration | -| **migrations** | `{ strategy: Enum<'parallel' \| 'sequential' \| 'on_demand'>; maxConcurrent: integer; rollbackOnError: boolean }` | optional | Migration configuration | -| **performance** | `{ poolPerSchema: boolean; schemaCacheTtlSeconds: integer }` | optional | Performance settings | +| **schema** | `{ namingPattern?: string; includePublicSchema?: boolean; sharedSchema?: string; autoCreateSchema?: boolean }` | optional | Schema configuration | +| **migrations** | `{ strategy?: Enum<'parallel' \| 'sequential' \| 'on_demand'>; maxConcurrent?: integer; rollbackOnError?: boolean }` | optional | Migration configuration | +| **performance** | `{ poolPerSchema?: boolean; schemaCacheTtlSeconds?: integer }` | optional | Performance settings | ### Nested Shape: `TenantIsolationConfig[strategy='isolated_schema'].schema` @@ -316,10 +316,10 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **strategy** | `'isolated_db'` | ✅ | Database-level isolation strategy | -| **database** | `{ namingPattern: string; serverStrategy: Enum<'shared' \| 'sharded' \| 'dedicated'>; separateCredentials: boolean; autoCreateDatabase: boolean }` | optional | Database configuration | -| **connectionPool** | `{ poolSize: integer; maxActivePools: integer; idleTimeoutSeconds: integer; usePooler: boolean }` | optional | Connection pool configuration | -| **backup** | `{ strategy: Enum<'individual' \| 'consolidated' \| 'on_demand'>; frequencyHours: integer; retentionDays: integer }` | optional | Backup configuration | -| **encryption** | `{ perTenantKeys: boolean; algorithm: string; keyManagement?: Enum<'aws_kms' \| 'azure_key_vault' \| 'gcp_kms' \| 'hashicorp_vault' \| 'custom'> }` | optional | Encryption configuration | +| **database** | `{ namingPattern?: string; serverStrategy?: Enum<'shared' \| 'sharded' \| 'dedicated'>; separateCredentials?: boolean; autoCreateDatabase?: boolean }` | optional | Database configuration | +| **connectionPool** | `{ poolSize?: integer; maxActivePools?: integer; idleTimeoutSeconds?: integer; usePooler?: boolean }` | optional | Connection pool configuration | +| **backup** | `{ strategy?: Enum<'individual' \| 'consolidated' \| 'on_demand'>; frequencyHours?: integer; retentionDays?: integer }` | optional | Backup configuration | +| **encryption** | `{ perTenantKeys?: boolean; algorithm?: string; keyManagement?: Enum<'aws_kms' \| 'azure_key_vault' \| 'gcp_kms' \| 'hashicorp_vault' \| 'custom'> }` | optional | Encryption configuration | ### Nested Shape: `TenantIsolationConfig[strategy='isolated_db'].database` @@ -395,9 +395,9 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **encryption** | `{ atRest: boolean; inTransit: boolean; fieldLevel: boolean }` | optional | Encryption requirements | -| **accessControl** | `{ requireMFA: boolean; requireSSO: boolean; ipWhitelist?: string[]; sessionTimeoutSeconds: integer }` | optional | Access control requirements | -| **compliance** | `{ standards?: Enum<'sox' \| 'hipaa' \| 'gdpr' \| 'pci_dss' \| 'iso_27001' \| 'fedramp'>[]; requireAuditLog: boolean; auditRetentionDays: integer; dataResidency?: object }` | optional | Compliance requirements | +| **encryption** | `{ atRest?: boolean; inTransit?: boolean; fieldLevel?: boolean }` | optional | Encryption requirements | +| **accessControl** | `{ requireMFA?: boolean; requireSSO?: boolean; ipWhitelist?: string[]; sessionTimeoutSeconds?: integer }` | optional | Access control requirements | +| **compliance** | `{ standards?: Enum<'sox' \| 'hipaa' \| 'gdpr' \| 'pci_dss' \| 'iso_27001' \| 'fedramp'>[]; requireAuditLog?: boolean; auditRetentionDays?: integer; dataResidency?: object }` | optional | Compliance requirements | ### Nested Shape: `TenantSecurityPolicy.encryption` diff --git a/content/docs/references/system/tracing.mdx b/content/docs/references/system/tracing.mdx index caf2176a405..fe3b0cc5a93 100644 --- a/content/docs/references/system/tracing.mdx +++ b/content/docs/references/system/tracing.mdx @@ -42,7 +42,7 @@ OpenTelemetry compatibility configuration | **sdkVersion** | `string` | optional | OTel SDK version | | **exporter** | `{ type: Enum<'otlp_http' \| 'otlp_grpc' \| 'jaeger' \| 'zipkin' \| 'console' \| 'datadog' \| …>; endpoint?: string; protocol?: string; headers?: Record; … }` | ✅ | Exporter configuration | | **resource** | `{ serviceName: string; serviceVersion?: string; serviceInstanceId?: string; serviceNamespace?: string; … }` | ✅ | Resource attributes | -| **instrumentation** | `{ autoInstrumentation: boolean; libraries?: string[]; disabledLibraries?: string[] }` | optional | | +| **instrumentation** | `{ autoInstrumentation?: boolean; libraries?: string[]; disabledLibraries?: string[] }` | optional | | | **semanticConventionsVersion** | `string` | optional | Semantic conventions version | ### Nested Shape: `OpenTelemetryCompatibility.exporter` @@ -56,7 +56,7 @@ OpenTelemetry compatibility configuration | **timeoutMs** | `integer` | optional (default: `10000`) | Exporter request timeout in milliseconds | | **timeout** | `never` | optional | [REMOVED] `OpenTelemetryCompatibility.exporter.timeout` was renamed to `timeoutMs` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (milliseconds) lived in a source JSDoc only and the key carried no describe at all, so the reference-page reader got a bare 10000 and could not tell it from 10000 seconds. Rename the key to `timeoutMs`; the value (milliseconds) and the 10000 default are unchanged. | | **compression** | `Enum<'none' \| 'gzip'>` | optional (default: `"none"`) | | -| **batch** | `{ maxBatchSize: integer; maxQueueSize: integer; exportTimeoutMs: integer; scheduledDelayMs: integer }` | optional | | +| **batch** | `{ maxBatchSize?: integer; maxQueueSize?: integer; exportTimeoutMs?: integer; scheduledDelayMs?: integer }` | optional | | ### Nested Shape: `OpenTelemetryCompatibility.resource` @@ -139,7 +139,7 @@ OpenTelemetry span | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **context** | `{ traceId: string; spanId: string; traceFlags: integer; traceState?: object; … }` | ✅ | Trace context | +| **context** | `{ traceId: string; spanId: string; traceFlags?: integer; traceState?: object; … }` | ✅ | Trace context | | **name** | `string` | ✅ | Span name | | **kind** | `Enum<'internal' \| 'server' \| 'client' \| 'producer' \| 'consumer'>` | optional (default: `"internal"`) | Span kind | | **startTime** | `string` | ✅ | Span start time | @@ -188,7 +188,7 @@ Span link | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **context** | `{ traceId: string; spanId: string; traceFlags: integer; traceState?: object; … }` | ✅ | Linked trace context | +| **context** | `{ traceId: string; spanId: string; traceFlags?: integer; traceState?: object; … }` | ✅ | Linked trace context | | **attributes** | `Record` | optional | Link attributes | ### Nested Shape: `Span.instrumentationLibrary` @@ -295,7 +295,7 @@ Span link | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **context** | `{ traceId: string; spanId: string; traceFlags: integer; traceState?: object; … }` | ✅ | Linked trace context | +| **context** | `{ traceId: string; spanId: string; traceFlags?: integer; traceState?: object; … }` | ✅ | Linked trace context | | **attributes** | `Record` | optional | Link attributes | ### Nested Shape: `SpanLink.context` @@ -363,7 +363,7 @@ Trace context propagation | **extract** | `boolean` | optional (default: `true`) | | | **inject** | `boolean` | optional (default: `true`) | | | **headers** | `{ traceId?: string; spanId?: string; traceFlags?: string; traceState?: string }` | optional | | -| **baggage** | `{ enabled: boolean; maxSize: integer; allowedKeys?: string[] }` | optional | | +| **baggage** | `{ enabled?: boolean; maxSize?: integer; allowedKeys?: string[] }` | optional | | --- @@ -405,7 +405,7 @@ Trace sampling configuration | **type** | `Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| 'probability' \| 'composite' \| 'custom'>` | ✅ | Sampling strategy | | **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' \| …>; whenParentNotSampled: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; root: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; rootRatio: number }` | optional | | +| **parentBased** | `{ whenParentSampled?: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; whenParentNotSampled?: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; root?: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; rootRatio?: number }` | optional | | | **composite** | `{ strategy: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; ratio?: number; condition?: Record }[]` | optional | | | **rules** | `{ name: string; match?: object; decision: Enum<'drop' \| 'record_only' \| 'record_and_sample'>; rate?: number }[]` | optional (default: `[]`) | | | **customSamplerId** | `string` | optional | Custom sampler identifier | @@ -464,12 +464,12 @@ Tracing configuration | **label** | `string` | ✅ | Display label | | **enabled** | `boolean` | optional (default: `true`) | | | **sampling** | `{ type: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; ratio?: number; rateLimit?: number; parentBased?: object; … }` | optional (default: `{"type":"always_on","rules":[]}`) | Trace sampling configuration | -| **propagation** | `{ formats: Enum<'w3c' \| 'b3' \| 'b3_multi' \| 'jaeger' \| 'xray' \| 'ottrace' \| 'custom'>[]; extract: boolean; inject: boolean; headers?: object; … }` | optional (default: `{"formats":["w3c"],"extract":true,"inject":true}`) | Trace context propagation | +| **propagation** | `{ formats?: Enum<'w3c' \| 'b3' \| 'b3_multi' \| 'jaeger' \| 'xray' \| 'ottrace' \| 'custom'>[]; extract?: boolean; inject?: boolean; headers?: object; … }` | optional (default: `{"formats":["w3c"],"extract":true,"inject":true}`) | Trace context propagation | | **openTelemetry** | `{ sdkVersion?: string; exporter: object; resource: object; instrumentation?: object; … }` | optional | OpenTelemetry compatibility configuration | -| **spanLimits** | `{ maxAttributes: integer; maxEvents: integer; maxLinks: integer; maxAttributeValueLength: integer }` | optional | | +| **spanLimits** | `{ maxAttributes?: integer; maxEvents?: integer; maxLinks?: integer; maxAttributeValueLength?: integer }` | optional | | | **traceIdGenerator** | `Enum<'random' \| 'uuid' \| 'custom'>` | optional (default: `"random"`) | | | **customTraceIdGeneratorId** | `string` | optional | Custom generator identifier | -| **performance** | `{ asyncExport: boolean; exportIntervalMs: integer }` | optional | | +| **performance** | `{ asyncExport?: boolean; exportIntervalMs?: integer }` | optional | | ### Nested Shape: `TracingConfig.sampling` @@ -478,7 +478,7 @@ Tracing configuration | **type** | `Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>` | ✅ | Sampling strategy | | **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' \| …>; whenParentNotSampled: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; root: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; rootRatio: number }` | optional | | +| **parentBased** | `{ whenParentSampled?: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; whenParentNotSampled?: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; root?: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; rootRatio?: number }` | optional | | | **composite** | `{ strategy: Enum<'always_on' \| 'always_off' \| 'trace_id_ratio' \| 'rate_limiting' \| 'parent_based' \| …>; ratio?: number; condition?: Record }[]` | optional | | | **rules** | `{ name: string; match?: object; decision: Enum<'drop' \| 'record_only' \| 'record_and_sample'>; rate?: number }[]` | optional (default: `[]`) | | | **customSamplerId** | `string` | optional | Custom sampler identifier | @@ -490,7 +490,7 @@ Tracing configuration | **sdkVersion** | `string` | optional | OTel SDK version | | **exporter** | `{ type: Enum<'otlp_http' \| 'otlp_grpc' \| 'jaeger' \| 'zipkin' \| 'console' \| 'datadog' \| …>; endpoint?: string; protocol?: string; headers?: Record; … }` | ✅ | Exporter configuration | | **resource** | `{ serviceName: string; serviceVersion?: string; serviceInstanceId?: string; serviceNamespace?: string; … }` | ✅ | Resource attributes | -| **instrumentation** | `{ autoInstrumentation: boolean; libraries?: string[]; disabledLibraries?: string[] }` | optional | | +| **instrumentation** | `{ autoInstrumentation?: boolean; libraries?: string[]; disabledLibraries?: string[] }` | optional | | | **semanticConventionsVersion** | `string` | optional | Semantic conventions version | ### Nested Shape: `TracingConfig.performance` diff --git a/content/docs/references/system/worker.mdx b/content/docs/references/system/worker.mdx index d145d4b6301..16f560ba2e9 100644 --- a/content/docs/references/system/worker.mdx +++ b/content/docs/references/system/worker.mdx @@ -77,10 +77,10 @@ const result = BatchProgressSchema.parse(data); | **name** | `string` | ✅ | Queue name (snake_case) | | **concurrency** | `integer` | optional (default: `5`) | Max concurrent task executions | | **rateLimit** | `{ max: integer; durationMs: integer }` | optional | Rate limit configuration | -| **defaultRetryPolicy** | `{ maxRetries: integer; backoffStrategy: Enum<'fixed' \| 'linear' \| 'exponential'>; initialDelayMs: integer; maxDelayMs: integer; … }` | optional | Default retry policy for tasks | +| **defaultRetryPolicy** | `{ maxRetries?: integer; backoffStrategy?: Enum<'fixed' \| 'linear' \| 'exponential'>; initialDelayMs?: integer; maxDelayMs?: integer; … }` | optional | Default retry policy for tasks | | **deadLetterQueue** | `string` | optional | Dead letter queue name | | **priority** | `integer` | optional (default: `0`) | Queue priority (lower = higher priority) | -| **autoScale** | `{ enabled: boolean; minWorkers: integer; maxWorkers: integer; scaleUpThreshold: integer; … }` | optional | Auto-scaling configuration | +| **autoScale** | `{ enabled?: boolean; minWorkers?: integer; maxWorkers?: integer; scaleUpThreshold?: integer; … }` | optional | Auto-scaling configuration | ### Nested Shape: `QueueConfig.rateLimit` @@ -124,7 +124,7 @@ const result = BatchProgressSchema.parse(data); | **payload** | `any` | ✅ | Task payload data | | **queue** | `string` | optional (default: `"default"`) | Queue name | | **priority** | `Enum<'critical' \| 'high' \| 'normal' \| 'low' \| 'background'>` | optional (default: `"normal"`) | Task priority level | -| **retryPolicy** | `{ maxRetries: integer; backoffStrategy: Enum<'fixed' \| 'linear' \| 'exponential'>; initialDelayMs: integer; maxDelayMs: integer; … }` | optional | Retry policy configuration | +| **retryPolicy** | `{ maxRetries?: integer; backoffStrategy?: Enum<'fixed' \| 'linear' \| 'exponential'>; initialDelayMs?: integer; maxDelayMs?: integer; … }` | optional | Retry policy configuration | | **timeoutMs** | `integer` | optional | Task timeout in milliseconds | | **scheduledAt** | `string` | optional | ISO 8601 datetime to execute task | | **attempts** | `integer` | optional (default: `0`) | Number of execution attempts | diff --git a/content/docs/references/ui/app.mdx b/content/docs/references/ui/app.mdx index f58707c3a4d..d21247d5f46 100644 --- a/content/docs/references/ui/app.mdx +++ b/content/docs/references/ui/app.mdx @@ -326,7 +326,7 @@ Documentation entry on the app menu (ADR-0046). Targets a `book` and/or a `doc` | **id** | `string` | ✅ | Selector id; selected value is exposed as the nav template var `{}` | | **label** | `string \| Record` | ✅ | Dropdown label | | **icon** | `string` | optional | Icon name | -| **optionsSource** | `{ endpoint: string; valueKey: string; labelKey: string; filter?: object[] }` | ✅ | Option data source | +| **optionsSource** | `{ endpoint: string; valueKey?: string; labelKey?: string; filter?: object[] }` | ✅ | Option data source | | **allValue** | `string` | optional (default: `""`) | Sentinel value meaning "no concrete selection yet" (empty string is almost always right) | | **persist** | `Enum<'query' \| 'session' \| 'none'>` | optional (default: `"query"`) | Persist selection via URL query, sessionStorage, or not at all | @@ -337,7 +337,7 @@ Documentation entry on the app menu (ADR-0046). Targets a `book` and/or a `doc` | **endpoint** | `string` | ✅ | REST endpoint returning the option rows (e.g. /api/v1/packages) | | **valueKey** | `string` | optional (default: `"id"`) | Row property used as the option value (dotted path allowed, e.g. "manifest.id") | | **labelKey** | `string` | optional (default: `"name"`) | Row property used as the option label (dotted path allowed, e.g. "manifest.name") | -| **filter** | `{ key: string; op: Enum<'eq' \| 'ne' \| 'in' \| 'nin'>; value: string \| string[] }[]` | optional | Predicates (AND) each option row must satisfy | +| **filter** | `{ key: string; op?: Enum<'eq' \| 'ne' \| 'in' \| 'nin'>; value: string \| string[] }[]` | optional | Predicates (AND) each option row must satisfy | --- diff --git a/content/docs/references/ui/chart.mdx b/content/docs/references/ui/chart.mdx index 6def1716ac2..ae29db3cfff 100644 --- a/content/docs/references/ui/chart.mdx +++ b/content/docs/references/ui/chart.mdx @@ -116,8 +116,8 @@ Inline aggregation for an object-bound chart | **height** | `number` | optional | Fixed plot height in pixels (overrides the container default) | | **showLegend** | `boolean` | optional (default: `true`) | Display legend | | **showDataLabels** | `boolean` | optional (default: `false`) | Display data labels | -| **annotations** | `{ type: Enum<'line' \| 'region'>; axis: Enum<'x' \| 'y'>; value: number \| string; endValue?: number \| string; … }[]` | optional | Reference lines/bands drawn over the plot: `{ type: "line" \| "region", axis: "x" \| "y", value, endValue?, color?, label?, style? }` | -| **interaction** | `{ tooltips: boolean; brush: boolean }` | optional | Interaction toggles: `{ tooltips?, brush? }` | +| **annotations** | `{ type?: Enum<'line' \| 'region'>; axis?: Enum<'x' \| 'y'>; value: number \| string; endValue?: number \| string; … }[]` | optional | Reference lines/bands drawn over the plot: `{ type: "line" \| "region", axis: "x" \| "y", value, endValue?, color?, label?, style? }` | +| **interaction** | `{ tooltips?: boolean; brush?: boolean }` | optional | Interaction toggles: `{ tooltips?, brush? }` | | **aria** | `never` | optional | [REMOVED] `ChartConfig.aria` — authored as `dashboard.widgets[].chartConfig.aria`, `report.chart.aria` and `report.blocks[].chart.aria` — was removed in @objectstack/spec 17 (ADR-0049 D2). No chart renderer ever applied it: the chart implementation declares no `aria` prop, the presentation lowering names it nowhere, and the react `` block never published it, so ARIA attributes declared here parsed and then silently did not reach the DOM. Delete the key. The accessible name that IS applied on this same chart config is its sibling `description`, which the chart renderer lowers onto the chart graphic as `role="img"` plus `aria-label`. The shared `AriaProps` shape is NOT gone — `ariaLabel` / `ariaDescribedBy` / `role` stay live in the `aria` block on `page.aria`, `page.components[].aria` and the list view `aria`. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | ### Allowed Values: `ChartConfig.type` diff --git a/content/docs/references/ui/component.mdx b/content/docs/references/ui/component.mdx index d6e0a544082..98f5f5ac31e 100644 --- a/content/docs/references/ui/component.mdx +++ b/content/docs/references/ui/component.mdx @@ -488,7 +488,7 @@ Sort field and direction pair | **staticData** | `any[]` | optional | Static inline records | | **locale** | `string` | optional | Locale override for the calendar chrome | | **loading** | `boolean` | optional | External loading state (honoured only alongside `data`) | -| **navigation** | `{ mode: Enum<'page' \| 'drawer' \| 'modal' \| 'split' \| 'popover' \| 'new_window' \| 'none'>; preventNavigation: boolean; openNewTab: boolean; size: Enum<'auto' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'>; … }` | optional | Event-click navigation config — the same block `ListViewSchema.navigation` declares (`{ mode, size, openNewTab, preventNavigation }`). The renderer's own default is `{ mode: 'drawer' }` when the key is absent; it is documented rather than declared, so a parsed calendar carries the key only when the author wrote it | +| **navigation** | `{ mode?: Enum<'page' \| 'drawer' \| 'modal' \| 'split' \| 'popover' \| 'new_window' \| 'none'>; preventNavigation?: boolean; openNewTab?: boolean; size?: Enum<'auto' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'>; … }` | optional | Event-click navigation config — the same block `ListViewSchema.navigation` declares (`{ mode, size, openNewTab, preventNavigation }`). The renderer's own default is `{ mode: 'drawer' }` when the key is absent; it is documented rather than declared, so a parsed calendar carries the key only when the author wrote it | ### Nested Shape: `ObjectCalendarProps.filter[number]` @@ -608,8 +608,8 @@ Sort field and direction pair | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **provider** | `'api'` | ✅ | | -| **read** | `{ url: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for fetching data | -| **write** | `{ url: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for submitting data (for forms/editable tables) | +| **read** | `{ url: string; method?: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for fetching data | +| **write** | `{ url: string; method?: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for submitting data (for forms/editable tables) | ### Nested Shape: `ObjectGanttProps.data[provider='value']` @@ -895,7 +895,7 @@ Sort field and direction pair | **quickAdd** | `never` | optional | [REMOVED] `object-kanban` property `quickAdd` was removed in @objectstack/spec 17 (ADR-0049) — the board forwarded it, but the per-column affordance is gated on both `quickAdd` and `onQuickAdd`, and `onQuickAdd` is a host-supplied function JSON cannot carry and no producer ever put on an `object-kanban` node, so authoring it was a parse-clean no-op. Delete the key; `object-kanban` offers no quick-add control. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | | **coverImageField** | `string` | optional | Image field rendered as the card cover | | **conditionalFormatting** | `any` | optional | Card conditional formatting rules | -| **navigation** | `{ mode: Enum<'page' \| 'drawer' \| 'modal' \| 'split' \| 'popover' \| 'new_window' \| 'none'>; preventNavigation: boolean; openNewTab: boolean; size: Enum<'auto' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'>; … }` | optional | Card-click navigation config — the same block `ListViewSchema.navigation` declares (`{ mode, size, openNewTab, preventNavigation }`). The renderer's own default is `{ mode: 'drawer' }` when the key is absent; it is documented rather than declared, so a parsed board carries the key only when the author wrote it | +| **navigation** | `{ mode?: Enum<'page' \| 'drawer' \| 'modal' \| 'split' \| 'popover' \| 'new_window' \| 'none'>; preventNavigation?: boolean; openNewTab?: boolean; size?: Enum<'auto' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'>; … }` | optional | Card-click navigation config — the same block `ListViewSchema.navigation` declares (`{ mode, size, openNewTab, preventNavigation }`). The renderer's own default is `{ mode: 'drawer' }` when the key is absent; it is documented rather than declared, so a parsed board carries the key only when the author wrote it | ### Nested Shape: `ObjectKanbanProps.filter[number]` @@ -911,7 +911,7 @@ View filter rule | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **fields** | `{ field: string; order: Enum<'asc' \| 'desc'>; collapsed: boolean }[]` | ✅ | Fields to group by, in nesting order — the first entry is the outermost group and each later entry nests one level deeper (at least one field); the same order as the group header query's `groupBy` | +| **fields** | `{ field: string; order?: Enum<'asc' \| 'desc'>; collapsed?: boolean }[]` | ✅ | Fields to group by, in nesting order — the first entry is the outermost group and each later entry nests one level deeper (at least one field); the same order as the group header query's `groupBy` | ### Nested Shape: `ObjectKanbanProps.navigation` @@ -955,8 +955,8 @@ View filter rule | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **provider** | `'api'` | ✅ | | -| **read** | `{ url: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for fetching data | -| **write** | `{ url: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for submitting data (for forms/editable tables) | +| **read** | `{ url: string; method?: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for fetching data | +| **write** | `{ url: string; method?: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for submitting data (for forms/editable tables) | ### Nested Shape: `ObjectMapProps.data[provider='value']` @@ -1107,7 +1107,7 @@ View filter rule | **maxDate** | `string` | optional | Pin the gantt axis end (ISO `yyyy-mm-dd`) instead of deriving it from the rows; only a non-empty value is honoured | | **descriptionField** | `string` | optional | Field rendered as each entry's description (renderer default `description`). Declared FLAT because the `timeline` block has no member for it — it is the only spelling this binding has | | **mapping** | `any` | optional | Record-to-entry field mapping (`{ title, date, description, variant }`) — the objectui-side binding record read BETWEEN the `timeline` block and the flat fallbacks. Its `variant` member (the field whose value picks each marker colour, renderer default `variant`) is the only spelling that binding has | -| **navigation** | `{ mode: Enum<'page' \| 'drawer' \| 'modal' \| 'split' \| 'popover' \| 'new_window' \| 'none'>; preventNavigation: boolean; openNewTab: boolean; size: Enum<'auto' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'>; … }` | optional | Entry-click navigation config — the same block `ListViewSchema.navigation` declares (`{ mode, size, openNewTab, preventNavigation }`) | +| **navigation** | `{ mode?: Enum<'page' \| 'drawer' \| 'modal' \| 'split' \| 'popover' \| 'new_window' \| 'none'>; preventNavigation?: boolean; openNewTab?: boolean; size?: Enum<'auto' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'>; … }` | optional | Entry-click navigation config — the same block `ListViewSchema.navigation` declares (`{ mode, size, openNewTab, preventNavigation }`) | ### Nested Shape: `ObjectTimelineProps.timeline` @@ -1178,8 +1178,8 @@ Sort field and direction pair | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **provider** | `'api'` | ✅ | | -| **read** | `{ url: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for fetching data | -| **write** | `{ url: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for submitting data (for forms/editable tables) | +| **read** | `{ url: string; method?: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for fetching data | +| **write** | `{ url: string; method?: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for submitting data (for forms/editable tables) | ### Nested Shape: `ObjectTreeProps.data[provider='value']` @@ -1224,7 +1224,7 @@ View filter rule | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **items** | `{ label: string \| Record; icon?: string; collapsed: boolean; children: any[] }[]` | ✅ | | +| **items** | `{ label: string \| Record; icon?: string; collapsed?: boolean; children: any[] }[]` | ✅ | | | **allowMultiple** | `boolean` | optional (default: `false`) | Allow multiple panels to be expanded simultaneously | | **variant** | `Enum<'flush' \| 'card'>` | optional (default: `"flush"`) | Panel framing: 'flush' draws a divider under each panel; 'card' leaves the border to each panel's own content | | **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | @@ -1428,7 +1428,7 @@ View filter rule | **width** | `string \| number` | optional | Panel width (e.g., "350px", "30%") — side positions (`right`/`left`) only. | | **collapsible** | `boolean` | optional | Whether the panel can be collapsed (renderer default: off). | | **defaultCollapsed** | `boolean` | optional | Whether the panel starts collapsed (renderer default: off; only meaningful with `collapsible`). | -| **feed** | `{ types?: (Enum<'comment' \| 'field_change' \| 'task' \| 'event' \| 'email' \| 'call' \| 'note' \| …> \| string)[]; filterMode: Enum<'all' \| 'comments_only' \| 'changes_only' \| 'tasks_only'>; showFilterToggle: boolean; limit: integer; … }` | optional | Embedded activity feed configuration | +| **feed** | `{ types?: (Enum<'comment' \| 'field_change' \| 'task' \| 'event' \| 'email' \| 'call' \| 'note' \| …> \| string)[]; filterMode?: Enum<'all' \| 'comments_only' \| 'changes_only' \| 'tasks_only'>; showFilterToggle?: boolean; limit?: integer; … }` | optional | Embedded activity feed configuration | | **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | ### Nested Shape: `RecordChatterProps.feed` @@ -1755,7 +1755,7 @@ Sort field and direction pair | **type** | `string` | optional | Renderer type override (e.g., "currency", "date") | | **pinned** | `Enum<'left' \| 'right'>` | optional | Pin/freeze column to left or right side | | **summary** | `Enum<'none' \| 'count' \| 'count_empty' \| 'count_filled' \| 'count_unique' \| …> \| { type: Enum<'none' \| 'count' \| 'count_empty' \| 'count_filled' \| 'count_unique' \| …>; field?: string }` | optional | Footer aggregation for this column — the function alone, or `{ type, field }` to aggregate another field | -| **prefix** | `{ field: string; type: Enum<'badge' \| 'text'> }` | optional | Field rendered inline before this cell value | +| **prefix** | `{ field: string; type?: Enum<'badge' \| 'text'> }` | optional | Field rendered inline before this cell value | | **link** | `boolean` | optional | Functions as the primary navigation link (triggers View navigation) | | **action** | `string` | optional | Registered Action ID to execute when clicked | @@ -1773,7 +1773,7 @@ View filter rule | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **picker** | `{ object: string; valueField: string; labelField?: string; filter?: object[] }` | ✅ | Where the Add affordance sources records from. | +| **picker** | `{ object: string; valueField?: string; labelField?: string; filter?: object[] }` | ✅ | Where the Add affordance sources records from. | | **linkField** | `string` | optional | Field on `objectName` that stores the picked record id (junction case). Omit for a 1:m re-parent. | | **label** | `string \| Record` | optional | Label for the Add button (default "Add"). | diff --git a/content/docs/references/ui/dashboard.mdx b/content/docs/references/ui/dashboard.mdx index e090e1f83b1..2fc25e9d515 100644 --- a/content/docs/references/ui/dashboard.mdx +++ b/content/docs/references/ui/dashboard.mdx @@ -31,13 +31,13 @@ const result = DashboardSchema.parse(data); | **name** | `string` | ✅ | Dashboard unique name | | **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 \| Record; description?: string \| Record; type: Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| …>; … }[]` | ✅ | Widgets to display | +| **header** | `{ showTitle?: boolean; showDescription?: boolean; actions?: object[] }` | optional | Dashboard header configuration | +| **widgets** | `{ id: string; title?: string \| Record; description?: string \| Record; type?: Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| …>; … }[]` | ✅ | Widgets to display | | **columns** | `integer` | optional | Number of grid columns (default 12) | | **gap** | `integer` | optional | Space between widgets, in steps of 0.25rem (4 = 1rem) | | **refreshIntervalSeconds** | `number` | optional | Auto-refresh interval in seconds | | **refreshInterval** | `never` | optional | [REMOVED] `dashboard.refreshInterval` was renamed to `refreshIntervalSeconds` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Rename the key to `refreshIntervalSeconds`; the value (seconds) is unchanged. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | -| **dateRange** | `{ field?: string; defaultRange: Enum<'today' \| 'yesterday' \| 'this_week' \| 'last_week' \| 'this_month' \| 'last_month' \| …>; allowCustomRange: boolean }` | optional | Global dashboard date range filter configuration | +| **dateRange** | `{ field?: string; defaultRange?: Enum<'today' \| 'yesterday' \| 'this_week' \| 'last_week' \| 'this_month' \| 'last_month' \| …>; allowCustomRange?: boolean }` | optional | Global dashboard date range filter configuration | | **globalFilters** | `{ name?: string; field: string; object?: string; label?: string \| Record; … }[]` | 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 (audit close-out) — no dashboard renderer ever applied it, so declared ARIA attributes silently did not reach the DOM. Delete the key. Run `os migrate meta --from 16` to list the mechanical edits for existing sources; apply them by hand. | | **performance** | `never` | optional | [REMOVED] `dashboard.performance` was removed in @objectstack/spec 17.0.0 (audit close-out) — no renderer or runtime read it; dashboard performance tuning was never implemented. Delete the key. Run `os migrate meta --from 16` to list the mechanical edits for existing sources; apply them by hand. | @@ -228,8 +228,8 @@ Dashboard header action | **height** | `number` | optional | Fixed plot height in pixels (overrides the container default) | | **showLegend** | `boolean` | optional (default: `true`) | Display legend | | **showDataLabels** | `boolean` | optional (default: `false`) | Display data labels | -| **annotations** | `{ type: Enum<'line' \| 'region'>; axis: Enum<'x' \| 'y'>; value: number \| string; endValue?: number \| string; … }[]` | optional | Reference lines/bands drawn over the plot: `{ type: "line" \| "region", axis: "x" \| "y", value, endValue?, color?, label?, style? }` | -| **interaction** | `{ tooltips: boolean; brush: boolean }` | optional | Interaction toggles: `{ tooltips?, brush? }` | +| **annotations** | `{ type?: Enum<'line' \| 'region'>; axis?: Enum<'x' \| 'y'>; value: number \| string; endValue?: number \| string; … }[]` | optional | Reference lines/bands drawn over the plot: `{ type: "line" \| "region", axis: "x" \| "y", value, endValue?, color?, label?, style? }` | +| **interaction** | `{ tooltips?: boolean; brush?: boolean }` | optional | Interaction toggles: `{ tooltips?, brush? }` | | **aria** | `never` | optional | [REMOVED] `ChartConfig.aria` — authored as `dashboard.widgets[].chartConfig.aria`, `report.chart.aria` and `report.blocks[].chart.aria` — was removed in @objectstack/spec 17 (ADR-0049 D2). No chart renderer ever applied it: the chart implementation declares no `aria` prop, the presentation lowering names it nowhere, and the react `` block never published it, so ARIA attributes declared here parsed and then silently did not reach the DOM. Delete the key. The accessible name that IS applied on this same chart config is its sibling `description`, which the chart renderer lowers onto the chart graphic as `role="img"` plus `aria-label`. The shared `AriaProps` shape is NOT gone — `ariaLabel` / `ariaDescribedBy` / `role` stay live in the `aria` block on `page.aria`, `page.components[].aria` and the list view `aria`. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | ### Nested Shape: `DashboardWidget.compareTo` @@ -271,8 +271,8 @@ Chart APPEARANCE for a dataset-bound widget (ADR-0021): title, subtitle, descrip | **height** | `number` | optional | Fixed plot height in pixels (overrides the container default) | | **showLegend** | `boolean` | optional (default: `true`) | Display legend | | **showDataLabels** | `boolean` | optional (default: `false`) | Display data labels | -| **annotations** | `{ type: Enum<'line' \| 'region'>; axis: Enum<'x' \| 'y'>; value: number \| string; endValue?: number \| string; … }[]` | optional | Reference lines/bands drawn over the plot: `{ type: "line" \| "region", axis: "x" \| "y", value, endValue?, color?, label?, style? }` | -| **interaction** | `{ tooltips: boolean; brush: boolean }` | optional | Interaction toggles: `{ tooltips?, brush? }` | +| **annotations** | `{ type?: Enum<'line' \| 'region'>; axis?: Enum<'x' \| 'y'>; value: number \| string; endValue?: number \| string; … }[]` | optional | Reference lines/bands drawn over the plot: `{ type: "line" \| "region", axis: "x" \| "y", value, endValue?, color?, label?, style? }` | +| **interaction** | `{ tooltips?: boolean; brush?: boolean }` | optional | Interaction toggles: `{ tooltips?, brush? }` | | **aria** | `never` | optional | [REMOVED] `ChartConfig.aria` — authored as `dashboard.widgets[].chartConfig.aria`, `report.chart.aria` and `report.blocks[].chart.aria` — was removed in @objectstack/spec 17 (ADR-0049 D2). No chart renderer ever applied it: the chart implementation declares no `aria` prop, the presentation lowering names it nowhere, and the react `` block never published it, so ARIA attributes declared here parsed and then silently did not reach the DOM. Delete the key. The accessible name that IS applied on this same chart config is its sibling `description`, which the chart renderer lowers onto the chart graphic as `role="img"` plus `aria-label`. The shared `AriaProps` shape is NOT gone — `ariaLabel` / `ariaDescribedBy` / `role` stay live in the `aria` block on `page.aria`, `page.components[].aria` and the list view `aria`. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | ### Nested Shape: `DashboardWidgetChartConfig.annotations[number]` diff --git a/content/docs/references/ui/page.mdx b/content/docs/references/ui/page.mdx index 1e0689019f1..02305770f86 100644 --- a/content/docs/references/ui/page.mdx +++ b/content/docs/references/ui/page.mdx @@ -70,10 +70,10 @@ Interface-level page configuration (Airtable parity) | **filterBy** | `{ field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'icontains' \| …>; value?: string \| number \| boolean \| null \| (string \| number)[] }[]` | optional | Always-on page filter (base filter). | | **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?: 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 | +| **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?: 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 | | **recordAction** | `Enum<'drawer' \| 'page' \| 'modal' \| 'none'>` | optional | How clicking a record opens its detail (drawer \| page \| modal \| none). Default: drawer | | **showRecordCount** | `boolean` | optional | Show record count at page bottom | @@ -94,7 +94,7 @@ Interface-level page configuration (Airtable parity) | **type** | `string` | optional | Renderer type override (e.g., "currency", "date") | | **pinned** | `Enum<'left' \| 'right'>` | optional | Pin/freeze column to left or right side | | **summary** | `Enum<'none' \| 'count' \| 'count_empty' \| 'count_filled' \| 'count_unique' \| …> \| { type: Enum<'none' \| 'count' \| 'count_empty' \| 'count_filled' \| 'count_unique' \| …>; field?: string }` | optional | Footer aggregation for this column — the function alone, or `{ type, field }` to aggregate another field | -| **prefix** | `{ field: string; type: Enum<'badge' \| 'text'> }` | optional | Field rendered inline before this cell value | +| **prefix** | `{ field: string; type?: Enum<'badge' \| 'text'> }` | optional | Field rendered inline before this cell value | | **link** | `boolean` | optional | Functions as the primary navigation link (triggers View navigation) | | **action** | `string` | optional | Registered Action ID to execute when clicked | diff --git a/content/docs/references/ui/report.mdx b/content/docs/references/ui/report.mdx index 7ef75d94fd4..69a5cd57c5e 100644 --- a/content/docs/references/ui/report.mdx +++ b/content/docs/references/ui/report.mdx @@ -37,7 +37,7 @@ const result = JoinedReportBlockSchema.parse(data); | **columns** | `string[]` | optional | Dimension names across (matrix, dataset-bound) | | **values** | `string[]` | optional | Measure names to show (dataset-bound) | | **runtimeFilter** | `any` | optional | Render-time scope filter (dataset-bound) | -| **order** | `{ by: string; direction: Enum<'asc' \| 'desc'> }[]` | optional | Result ordering, most significant key first | +| **order** | `{ by: string; direction?: Enum<'asc' \| 'desc'> }[]` | optional | Result ordering, most significant key first | ### Nested Shape: `JoinedReportBlock.order[number]` @@ -64,10 +64,10 @@ const result = JoinedReportBlockSchema.parse(data); | **columns** | `string[]` | optional | Dimension names across (matrix) | | **values** | `string[]` | optional | Measure names to show | | **runtimeFilter** | `any` | optional | Render-time scope filter | -| **order** | `{ by: string; direction: Enum<'asc' \| 'desc'> }[]` | optional | Result ordering, most significant key first | +| **order** | `{ by: string; direction?: Enum<'asc' \| 'desc'> }[]` | optional | Result ordering, most significant key first | | **drilldown** | `boolean` | optional (default: `true`) | Click-through to underlying records | | **chart** | `{ type: Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| …>; title?: string \| Record; subtitle?: string \| Record; description?: string \| Record; … }` | optional | Embedded chart configuration (refused on a joined report, which draws tables only) | -| **blocks** | `{ name: string; label?: string \| Record; description?: string \| Record; type: Enum<'tabular' \| 'summary' \| 'matrix'>; … }[]` | optional | Sub-reports for type=joined | +| **blocks** | `{ name: string; label?: string \| Record; description?: string \| Record; type?: Enum<'tabular' \| 'summary' \| 'matrix'>; … }[]` | optional | Sub-reports for type=joined | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this report. | | **_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. | @@ -99,8 +99,8 @@ const result = JoinedReportBlockSchema.parse(data); | **height** | `number` | optional | Fixed plot height in pixels (overrides the container default) | | **showLegend** | `boolean` | optional (default: `true`) | Display legend | | **showDataLabels** | `boolean` | optional (default: `false`) | Display data labels | -| **annotations** | `{ type: Enum<'line' \| 'region'>; axis: Enum<'x' \| 'y'>; value: number \| string; endValue?: number \| string; … }[]` | optional | Reference lines/bands drawn over the plot: `{ type: "line" \| "region", axis: "x" \| "y", value, endValue?, color?, label?, style? }` | -| **interaction** | `{ tooltips: boolean; brush: boolean }` | optional | Interaction toggles: `{ tooltips?, brush? }` | +| **annotations** | `{ type?: Enum<'line' \| 'region'>; axis?: Enum<'x' \| 'y'>; value: number \| string; endValue?: number \| string; … }[]` | optional | Reference lines/bands drawn over the plot: `{ type: "line" \| "region", axis: "x" \| "y", value, endValue?, color?, label?, style? }` | +| **interaction** | `{ tooltips?: boolean; brush?: boolean }` | optional | Interaction toggles: `{ tooltips?, brush? }` | | **aria** | `never` | optional | [REMOVED] `ChartConfig.aria` — authored as `dashboard.widgets[].chartConfig.aria`, `report.chart.aria` and `report.blocks[].chart.aria` — was removed in @objectstack/spec 17 (ADR-0049 D2). No chart renderer ever applied it: the chart implementation declares no `aria` prop, the presentation lowering names it nowhere, and the react `` block never published it, so ARIA attributes declared here parsed and then silently did not reach the DOM. Delete the key. The accessible name that IS applied on this same chart config is its sibling `description`, which the chart renderer lowers onto the chart graphic as `role="img"` plus `aria-label`. The shared `AriaProps` shape is NOT gone — `ariaLabel` / `ariaDescribedBy` / `role` stay live in the `aria` block on `page.aria`, `page.components[].aria` and the list view `aria`. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | ### Nested Shape: `Report.blocks[number]` @@ -116,7 +116,7 @@ const result = JoinedReportBlockSchema.parse(data); | **columns** | `string[]` | optional | Dimension names across (matrix, dataset-bound) | | **values** | `string[]` | optional | Measure names to show (dataset-bound) | | **runtimeFilter** | `any` | optional | Render-time scope filter (dataset-bound) | -| **order** | `{ by: string; direction: Enum<'asc' \| 'desc'> }[]` | optional | Result ordering, most significant key first | +| **order** | `{ by: string; direction?: Enum<'asc' \| 'desc'> }[]` | optional | Result ordering, most significant key first | ### Nested Shape: `Report.protection` @@ -146,8 +146,8 @@ const result = JoinedReportBlockSchema.parse(data); | **height** | `number` | optional | Fixed plot height in pixels (overrides the container default) | | **showLegend** | `boolean` | optional (default: `true`) | Display legend | | **showDataLabels** | `boolean` | optional (default: `false`) | Display data labels | -| **annotations** | `{ type: Enum<'line' \| 'region'>; axis: Enum<'x' \| 'y'>; value: number \| string; endValue?: number \| string; … }[]` | optional | Reference lines/bands drawn over the plot: `{ type: "line" \| "region", axis: "x" \| "y", value, endValue?, color?, label?, style? }` | -| **interaction** | `{ tooltips: boolean; brush: boolean }` | optional | Interaction toggles: `{ tooltips?, brush? }` | +| **annotations** | `{ type?: Enum<'line' \| 'region'>; axis?: Enum<'x' \| 'y'>; value: number \| string; endValue?: number \| string; … }[]` | optional | Reference lines/bands drawn over the plot: `{ type: "line" \| "region", axis: "x" \| "y", value, endValue?, color?, label?, style? }` | +| **interaction** | `{ tooltips?: boolean; brush?: boolean }` | optional | Interaction toggles: `{ tooltips?, brush? }` | | **aria** | `never` | optional | [REMOVED] `ChartConfig.aria` — authored as `dashboard.widgets[].chartConfig.aria`, `report.chart.aria` and `report.blocks[].chart.aria` — was removed in @objectstack/spec 17 (ADR-0049 D2). No chart renderer ever applied it: the chart implementation declares no `aria` prop, the presentation lowering names it nowhere, and the react `` block never published it, so ARIA attributes declared here parsed and then silently did not reach the DOM. Delete the key. The accessible name that IS applied on this same chart config is its sibling `description`, which the chart renderer lowers onto the chart graphic as `role="img"` plus `aria-label`. The shared `AriaProps` shape is NOT gone — `ariaLabel` / `ariaDescribedBy` / `role` stay live in the `aria` block on `page.aria`, `page.components[].aria` and the list view `aria`. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. | ### Allowed Values: `ReportChart.type` diff --git a/content/docs/references/ui/view.mdx b/content/docs/references/ui/view.mdx index 4b7be09c7aa..b2f7ca209a3 100644 --- a/content/docs/references/ui/view.mdx +++ b/content/docs/references/ui/view.mdx @@ -613,7 +613,7 @@ Record grouping configuration — SERVER-SIDE: the set of groups and every numbe | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **fields** | `{ field: string; order: Enum<'asc' \| 'desc'>; collapsed: boolean }[]` | ✅ | Fields to group by, in nesting order — the first entry is the outermost group and each later entry nests one level deeper (at least one field); the same order as the group header query's `groupBy` | +| **fields** | `{ field: string; order?: Enum<'asc' \| 'desc'>; collapsed?: boolean }[]` | ✅ | Fields to group by, in nesting order — the first entry is the outermost group and each later entry nests one level deeper (at least one field); the same order as the group header query's `groupBy` | ### Nested Shape: `GroupingConfig.fields[number]` @@ -716,7 +716,7 @@ List chart view configuration | **type** | `string` | optional | Renderer type override (e.g., "currency", "date") | | **pinned** | `Enum<'left' \| 'right'>` | optional | Pin/freeze column to left or right side | | **summary** | `Enum<'none' \| 'count' \| 'count_empty' \| 'count_filled' \| 'count_unique' \| 'percent_empty' \| 'percent_filled' \| 'sum' \| 'avg' \| 'min' \| 'max'> \| { type: Enum<'none' \| 'count' \| 'count_empty' \| 'count_filled' \| 'count_unique' \| …>; field?: string }` | optional | Footer aggregation for this column — the function alone, or `{ type, field }` to aggregate another field | -| **prefix** | `{ field: string; type: Enum<'badge' \| 'text'> }` | optional | Field rendered inline before this cell value | +| **prefix** | `{ field: string; type?: Enum<'badge' \| 'text'> }` | optional | Field rendered inline before this cell value | | **link** | `boolean` | optional | Functions as the primary navigation link (triggers View navigation) | | **action** | `string` | optional | Registered Action ID to execute when clicked | @@ -1942,8 +1942,8 @@ This schema accepts one of the following structures: | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **provider** | `'api'` | ✅ | | -| **read** | `{ url: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for fetching data | -| **write** | `{ url: string; method: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for submitting data (for forms/editable tables) | +| **read** | `{ url: string; method?: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for fetching data | +| **write** | `{ url: string; method?: Enum<'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'>; headers?: Record; params?: Record; … }` | optional | Configuration for submitting data (for forms/editable tables) | ### Nested Shape: `ViewData[provider='api'].read` diff --git a/packages/spec/scripts/lib/format-type.ts b/packages/spec/scripts/lib/format-type.ts index 5d73339a6a2..d89531310da 100644 --- a/packages/spec/scripts/lib/format-type.ts +++ b/packages/spec/scripts/lib/format-type.ts @@ -307,6 +307,41 @@ function isNeverNode(prop: any): boolean { ); } +/** + * Does this property node carry a `default` keyword? `'default' in` is the + * test, never truthiness: `null`, `false`, `0` and `""` are real defaults an + * author gets by omitting the key. + */ +export function carriesDefault(prop: any): boolean { + return prop !== null && typeof prop === 'object' && Object.prototype.hasOwnProperty.call(prop, 'default'); +} + +/** + * May an author omit this member? The ONE answer a reference page gives, in + * every position that states optionality: the Required column + * (`renderRequiredCell` in `schema-section.ts`) and the `key?:` marker of a + * `{ … }` shape summary below. + * + * #8703's rule. `build-schemas.ts` emits each published document in ONE io + * mode — OUTPUT (post-parse) by default, INPUT only when the output projection + * throws, which one `.transform` anywhere in the document causes. The two modes + * disagree about a `.default()` member's `required` entry: output lists it (the + * parse always produces it), input does not (the author may leave it out). + * Both keep its `default`. So `default` decides and `required` only breaks the + * tie for a member that has none. + * + * Reading `required` alone here made a def's face a property of the DOCUMENT + * it was emitted inside, not of the def (#21466): one shared def rendered + * `order:` inside an output-mode document and `order?:` inside an input-mode + * one, on the same page, and a member gaining a `.transform` flipped every + * defaulted key the whole document reaches. Measured before this answer was + * shared: 1398 exports project in both modes, 215 of them rendered + * differently, and all 483 differing lines were this marker. + */ +export function isAuthorOmittable(prop: any, required: boolean): boolean { + return !required || carriesDefault(prop); +} + /** * One JSON Schema literal value — a `const`, or a single member of an `enum` — * rendered as the TypeScript literal an author would have to type. @@ -1077,7 +1112,9 @@ function renderType(prop: any, ctx: TypeContext | undefined, depth: number): str 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) ? '' : '?'; + // `default` decides, `required` breaks the tie — the Required column's + // answer, so the marker cannot depend on the emitting io mode (#21466). + const optional = isAuthorOmittable(child, (prop.required || []).includes(k)) ? '?' : ''; // 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 diff --git a/packages/spec/scripts/lib/schema-section.ts b/packages/spec/scripts/lib/schema-section.ts index 857c11129cf..ef607fe5821 100644 --- a/packages/spec/scripts/lib/schema-section.ts +++ b/packages/spec/scripts/lib/schema-section.ts @@ -14,9 +14,11 @@ import { escapeMdxDescription } from './escape-mdx'; import { + carriesDefault, discriminantKeyOf, formatPropertyType, formatType, + isAuthorOmittable, nestedShapesOf, variantSelector, type NestedShape, @@ -209,9 +211,10 @@ export const INLINE_DEFAULT_WIDTH_LIMIT = 64; * @param required Whether the enclosing object lists the property in `required`. */ export function renderRequiredCell(prop: any, required: boolean): string { - const hasDefault = - prop !== null && typeof prop === 'object' && Object.prototype.hasOwnProperty.call(prop, 'default'); - if (!hasDefault) return required ? '✅' : 'optional'; + // The same predicate the `{ … }` summary's `key?:` marker reads, so the two + // positions cannot disagree about one member (#21466). + if (!isAuthorOmittable(prop, required)) return '✅'; + if (!carriesDefault(prop)) return 'optional'; // Canonical JSON, no whitespace — the same spelling the #4666 default ratchet // fingerprints, so a value printed here and a value recorded there cannot diff --git a/packages/spec/scripts/schema-section.test.ts b/packages/spec/scripts/schema-section.test.ts index 9773556ca85..851f5f3d5d1 100644 --- a/packages/spec/scripts/schema-section.test.ts +++ b/packages/spec/scripts/schema-section.test.ts @@ -33,7 +33,10 @@ */ import { describe, expect, it } from 'vitest'; +import { z } from 'zod'; +import { formatType } from './lib/format-type'; +import { projectPublishedJsonSchema } from './lib/refinement-projection'; import { INLINE_DEFAULT_WIDTH_LIMIT, renderRequiredCell, @@ -272,6 +275,124 @@ describe('renderRequiredCell — a `.default()` member is author-omittable (#870 }); }); +/** + * THE DEFECT THIS PINS (#21466) — #8703's rule, in the position #8703 missed. + * `renderRequiredCell` read `default`, but the `{ … }` shape summary in the + * Type column still marked `key?:` from `required` alone. A published document + * is emitted in ONE io mode — output, or input when one `.transform` anywhere + * in it makes the output projection throw — so a def shared by two documents + * rendered `order:` in one and `order?:` in the other, on the same page. Found + * when an object-grid member gained a transform and the grid's grouping and + * `data[provider='api']` rows flipped while the kanban / gantt / map / tree + * rows sharing those defs did not. + * + * The fixture is that shape, through the generator's own projection, with two + * parent rows: one projectable in output mode, one only in input mode. The + * precondition assertions are what keep the pin from passing vacuously — they + * prove the two documents DISAGREE about `required` for the shared def, so an + * identical rendering is the renderer's doing and not the fixture's. + */ +describe('one shared def renders one face, whichever io mode its document took (#21466)', () => { + const GroupingField = z.object({ + field: z.string().describe('Field name to group by'), + order: z.enum(['asc', 'desc']).default('asc').describe('Group sort order'), + collapsed: z.boolean().default(false).describe('Collapse groups by default'), + }); + const Grouping = z.object({ + fields: z.array(GroupingField).min(1).describe('Fields to group by, in nesting order'), + }); + const ApiRequest = z.object({ + url: z.string().describe('Endpoint URL'), + method: z.enum(['GET', 'POST']).default('GET').describe('HTTP method'), + }); + + // Same two shared defs, two parents. The second carries a transform, which is + // what sends a document to the input projection in `build-schemas.ts`. + const OutputParent = z.object({ + grouping: Grouping.optional().describe('Row grouping config'), + read: ApiRequest.optional().describe('Configuration for fetching data'), + }); + const InputParent = OutputParent.extend({ + label: z.string().transform((s) => s.trim()).describe('Trimmed label'), + }); + + // `build-schemas.ts`'s fallback reads exactly this text (KNOWN_UNSUPPORTED_PATTERNS), + // so it is the message a consumer parses, not prose. + it('the fixture really is one output-mode and one input-mode document', () => { + expect(() => projectPublishedJsonSchema(OutputParent)).not.toThrow(); + expect(() => projectPublishedJsonSchema(InputParent)).toThrow(/cannot be represented in JSON Schema/); + }); + + const outDoc = projectPublishedJsonSchema(OutputParent) as any; + const inDoc = projectPublishedJsonSchema(InputParent, { io: 'input' }) as any; + + it('the two documents disagree about `required` for the shared defs', () => { + expect(outDoc.properties.grouping.properties.fields.items.required).toEqual(['field', 'order', 'collapsed']); + expect(inDoc.properties.grouping.properties.fields.items.required).toEqual(['field']); + expect(outDoc.properties.read.required).toEqual(['url', 'method']); + expect(inDoc.properties.read.required).toEqual(['url']); + }); + + /** The rows of one `### Nested Shape:` table, heading excluded. */ + const nestedShapeRows = (md: string, path: string): string[] => { + const lines = md.split('\n'); + const start = lines.indexOf(`### Nested Shape: \`${path}\``); + expect(start).toBeGreaterThan(-1); + const rows: string[] = []; + for (const line of lines.slice(start + 1)) { + if (line.startsWith('|')) rows.push(line); + else if (rows.length > 0) break; + } + return rows; + }; + + /** One property's row of the section's own `### Properties` table. */ + const propertyRow = (md: string, key: string): string | undefined => + md.split('\n').find((line) => line.startsWith(`| **${key}** |`)); + + it('renders the shared defs byte-identical through both parent rows — the input face', () => { + const outMd = renderSchemaSection('OutputParent', outDoc); + const inMd = renderSchemaSection('InputParent', inDoc); + + // The card's row: the nested grouping table's `fields` summary. + const outGrouping = nestedShapeRows(outMd, 'OutputParent.grouping'); + expect(nestedShapeRows(inMd, 'InputParent.grouping')).toEqual(outGrouping); + expect(outGrouping).toContain( + "| **fields** | `{ field: string; order?: Enum<'asc' \\| 'desc'>; collapsed?: boolean }[]` | ✅ | Fields to group by, in nesting order |", + ); + + // The card's other row: a `{ url; method }` request def summarized in place. + expect(propertyRow(inMd, 'read')).toBe(propertyRow(outMd, 'read')); + expect(propertyRow(outMd, 'read')).toBe( + "| **read** | `{ url: string; method?: Enum<'GET' \\| 'POST'> }` | optional | Configuration for fetching data |", + ); + + // And the summary agrees with the Required column about the same members. + const outRead = nestedShapeRows(outMd, 'OutputParent.read'); + expect(nestedShapeRows(inMd, 'InputParent.read')).toEqual(outRead); + expect(outRead).toContain('| **method** | `Enum<\'GET\' \\| \'POST\'>` | optional (default: `"GET"`) | HTTP method |'); + }); + + it('marks a defaulted key optional whatever `required` says, and leaves the rest to `required`', () => { + const summary = (required: string[]) => + formatType({ + type: 'object', + properties: { + a: { type: 'string', default: 'x' }, + b: { type: 'string' }, + c: { type: 'boolean', default: false }, + d: { type: 'integer' }, + }, + required, + }); + + // The output-mode spelling (defaulted members listed) and the input-mode + // one (not listed) are one cell. + expect(summary(['a', 'b', 'c'])).toBe('{ a?: string; b: string; c?: boolean; d?: integer }'); + expect(summary(['b'])).toBe(summary(['a', 'b', 'c'])); + }); +}); + describe('selectRootDef — precedence', () => { it('prefers the definition named after the schema', () => { const named = { type: 'string', description: 'from $defs' };