From c225e48db8d650025b4917d1541158b7e9498b2a Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 17 Sep 2026 12:11:58 +0000 Subject: [PATCH 1/4] =?UTF-8?q?feat(spec)!:=20the=20genuine=20duration=20r?= =?UTF-8?q?ows=20declare=20their=20unit=20=E2=80=94=20DurationMs/DurationS?= =?UTF-8?q?econds=20and=20two=20externalVocabulary=20mirrors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step 3 of ruling A on #18115: eight of the ten census rows now declare their unit through a channel the reader reaches. Two rows are reported back rather than converted. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude --- packages/spec/src/api/contract.zod.ts | 3 ++- .../src/kernel/plugin-lifecycle-advanced.zod.ts | 12 +++++++++--- .../src/kernel/plugin-security-advanced.zod.ts | 8 +++++++- packages/spec/src/system/auth-config.zod.ts | 3 ++- .../spec/src/system/metadata-persistence.zod.ts | 5 +++-- packages/spec/src/system/metrics.zod.ts | 14 +++++++++++--- 6 files changed, 34 insertions(+), 11 deletions(-) diff --git a/packages/spec/src/api/contract.zod.ts b/packages/spec/src/api/contract.zod.ts index a7fcb0510e8..5f94f903943 100644 --- a/packages/spec/src/api/contract.zod.ts +++ b/packages/spec/src/api/contract.zod.ts @@ -2,6 +2,7 @@ import { z } from 'zod'; import { QuerySchema } from '../data/query.zod'; +import { DurationMs } from '../shared/duration.zod'; import { ErrorCode } from './error-code-ledger.zod'; import { StandardErrorCode } from './errors.zod'; @@ -308,7 +309,7 @@ export const BaseResponseSchema = lazySchema(() => z.object({ error: ApiErrorSchema.optional().describe('Error details if success is false'), meta: z.object({ timestamp: z.string(), - duration: z.number().optional(), + duration: DurationMs.optional().describe('Server-side processing duration in milliseconds'), requestId: z.string().optional(), traceId: z.string().optional(), }).optional().describe('Response metadata'), diff --git a/packages/spec/src/kernel/plugin-lifecycle-advanced.zod.ts b/packages/spec/src/kernel/plugin-lifecycle-advanced.zod.ts index 08f871ef615..267d74926cc 100644 --- a/packages/spec/src/kernel/plugin-lifecycle-advanced.zod.ts +++ b/packages/spec/src/kernel/plugin-lifecycle-advanced.zod.ts @@ -1,6 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { z } from 'zod'; +import { DurationMs } from '../shared/duration.zod'; /** * # Advanced Plugin Lifecycle — host-driven library vocabularies @@ -408,10 +409,15 @@ export const HotReloadConfigSchema = lazySchema(() => z.object({ .describe('How to preserve state during reload'), /** - * Graceful shutdown timeout + * Graceful shutdown timeout, in milliseconds */ - shutdownTimeout: z.number().int().min(0).default(30000) - .describe('Maximum time to wait for graceful shutdown'), + // Typed `DurationMs` (#18124, step ③ of ruling A on #18115) rather than + // renamed: the `#15676` wave that renamed this def's `debounceDelay` left this + // sibling alone on purpose, and the type declares the unit without retiring an + // authorable key. `DurationMs` is `.int().nonnegative()`, the same accepted set + // `.int().min(0)` carried, so nothing that parsed before stops parsing. + shutdownTimeout: DurationMs.default(30000) + .describe('Maximum time to wait for graceful shutdown, in milliseconds'), /** * Pre-reload hooks diff --git a/packages/spec/src/kernel/plugin-security-advanced.zod.ts b/packages/spec/src/kernel/plugin-security-advanced.zod.ts index 160ab1868dc..dd727f50e7f 100644 --- a/packages/spec/src/kernel/plugin-security-advanced.zod.ts +++ b/packages/spec/src/kernel/plugin-security-advanced.zod.ts @@ -620,7 +620,13 @@ export const KernelSecurityPolicySchema = lazySchema(() => z.object({ allowedMethods: z.array(z.string()), allowedHeaders: z.array(z.string()), allowCredentials: z.boolean().default(false), - maxAge: z.number().int().optional(), + // `externalVocabulary` mirror (#14478 ruling B), the same declaration its + // twin `CorsConfig.maxAge` (`src/shared/http.zod.ts`) already carries: this + // key IS the CORS `Access-Control-Max-Age` response header, whose value the + // standard defines in seconds. Renaming it to `maxAgeSeconds` would break the + // one-to-one reading between this policy and the header it emits. + maxAge: z.number().int().optional().describe('Preflight cache duration in seconds') + .meta({ externalVocabulary: 'CORS `Access-Control-Max-Age` (WHATWG Fetch)' }), }).optional(), /** diff --git a/packages/spec/src/system/auth-config.zod.ts b/packages/spec/src/system/auth-config.zod.ts index d406d116eff..e1fd6e449e6 100644 --- a/packages/spec/src/system/auth-config.zod.ts +++ b/packages/spec/src/system/auth-config.zod.ts @@ -560,7 +560,8 @@ export const AuthConfigSchema = lazySchema(() => z.object({ // defaults above are that library's defaults (7 days / 1 day). expiresIn: z.number().default(60 * 60 * 24 * 7).describe('Session duration in seconds') .meta({ externalVocabulary: 'better-auth `session.expiresIn`' }), - updateAge: z.number().default(60 * 60 * 24).describe('Session update frequency'), + updateAge: z.number().default(60 * 60 * 24).describe('Session update frequency in seconds') + .meta({ externalVocabulary: 'better-auth `session.updateAge`' }), }).optional(), trustedOrigins: z.array(z.string()).optional().describe( 'Trusted origins for CSRF protection. Supports wildcards (e.g. "https://*.example.com"). ' + diff --git a/packages/spec/src/system/metadata-persistence.zod.ts b/packages/spec/src/system/metadata-persistence.zod.ts index 913ed61e680..2f2e3aab4ec 100644 --- a/packages/spec/src/system/metadata-persistence.zod.ts +++ b/packages/spec/src/system/metadata-persistence.zod.ts @@ -1,6 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { z } from 'zod'; +import { DurationMs } from '../shared/duration.zod'; import { MetadataFormatSchema } from '../shared/metadata-types.zod'; /** @@ -256,7 +257,7 @@ export const MetadataLoadResultSchema = lazySchema(() => z.object({ fromCache: z.boolean().optional(), etag: z.string().optional(), notModified: z.boolean().optional(), - loadTime: z.number().optional(), + loadTime: DurationMs.optional().describe('How long the load took, in milliseconds'), })); /** @@ -284,7 +285,7 @@ export const MetadataSaveResultSchema = lazySchema(() => z.object({ stats: MetadataStatsSchema.optional(), etag: z.string().optional(), size: z.number().optional(), - saveTime: z.number().optional(), + saveTime: DurationMs.optional().describe('How long the save took, in milliseconds'), backupPath: z.string().optional(), })); diff --git a/packages/spec/src/system/metrics.zod.ts b/packages/spec/src/system/metrics.zod.ts index a747965b7dd..2063c360949 100644 --- a/packages/spec/src/system/metrics.zod.ts +++ b/packages/spec/src/system/metrics.zod.ts @@ -1,6 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { z } from 'zod'; +import { DurationSeconds } from '../shared/duration.zod'; import { ExpressionInputSchema } from '../shared/expression.zod'; /** @@ -407,9 +408,13 @@ export const MetricAggregationConfigSchema = lazySchema(() => z.object({ sliding: z.boolean().optional().default(false), /** - * Slide interval for sliding windows + * Slide interval for sliding windows, in seconds */ - slideInterval: z.number().int().positive().optional(), + // Seconds, from the sibling `durationSeconds` this interval slides across in + // the same object literal. `.positive()` is kept on top of `DurationSeconds` + // (`.int().nonnegative()`) so the floor this key already declared is unchanged. + slideInterval: DurationSeconds.positive().optional() + .describe('Slide interval for sliding windows, in seconds'), }).optional(), /** @@ -844,7 +849,10 @@ export const MetricsConfigSchema = lazySchema(() => z.object({ /** * Resolution in seconds */ - resolution: z.number().int().positive().describe('Downsampled resolution'), + // The unit lived in the JSDoc alone — the published reference page prints + // the describe, so the reader who needed it could not reach it. Typed and + // described now; `.positive()` keeps the floor this key already declared. + resolution: DurationSeconds.positive().describe('Downsampled resolution in seconds'), })).optional(), }).optional(), From 35b8b4d4669ebd4b9fb00ee2ad6f41c6e8ea58e9 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 17 Sep 2026 12:21:51 +0000 Subject: [PATCH 2/4] =?UTF-8?q?test(spec):=20pin=20the=20new=20duration=20?= =?UTF-8?q?declarations=20=E2=80=94=20refusals,=20floors=20and=20the=20two?= =?UTF-8?q?=20mirrors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude --- content/docs/references/api/analytics.mdx | 33 +++- content/docs/references/api/auth.mdx | 22 ++- .../docs/references/api/automation-api.mdx | 99 +++++++++- content/docs/references/api/batch.mdx | 11 +- content/docs/references/api/contract.mdx | 55 +++++- content/docs/references/api/export.mdx | 66 ++++++- content/docs/references/api/metadata.mdx | 187 ++++++++++++++++-- content/docs/references/api/package-api.mdx | 77 +++++++- content/docs/references/api/protocol.mdx | 33 +++- content/docs/references/api/storage.mdx | 88 ++++++++- .../kernel/plugin-lifecycle-advanced.mdx | 2 +- .../kernel/plugin-security-advanced.mdx | 10 + .../docs/references/system/auth-config.mdx | 2 +- .../system/metadata-persistence.mdx | 4 +- content/docs/references/system/metrics.mdx | 2 +- packages/spec/src/api/contract.test.ts | 52 +++++ .../kernel/plugin-lifecycle-advanced.test.ts | 33 ++++ .../kernel/plugin-security-advanced.test.ts | 41 ++++ packages/spec/src/system/auth-config.test.ts | 39 ++++ .../src/system/metadata-persistence.test.ts | 37 ++++ packages/spec/src/system/metrics.test.ts | 64 ++++++ skills/objectstack-api/references/_index.md | 1 + 22 files changed, 892 insertions(+), 66 deletions(-) diff --git a/content/docs/references/api/analytics.mdx b/content/docs/references/api/analytics.mdx index 4c455e7e5bb..717020c4f84 100644 --- a/content/docs/references/api/analytics.mdx +++ b/content/docs/references/api/analytics.mdx @@ -45,7 +45,7 @@ const result = AnalyticsEndpoint.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ name: string; title?: string; measures: object[]; dimensions: object[] }[]` | ✅ | Available cubes, each as the `CubeMeta` discovery projection — the cube name, its title, and the measures/dimensions a client may name in a query. A bare array: there is no `cubes` wrapper object, and no cube `sql` is published. | ### Nested Shape: `AnalyticsMetadataResponse.error` @@ -62,6 +62,15 @@ const result = AnalyticsEndpoint.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `AnalyticsMetadataResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `AnalyticsMetadataResponse.data[number]` | Property | Type | Required | Description | @@ -111,7 +120,7 @@ const result = AnalyticsEndpoint.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ rows: Record[]; fields: object[]; sql?: string; totals?: object[] }` | ✅ | | ### Nested Shape: `AnalyticsResultResponse.error` @@ -128,6 +137,15 @@ const result = AnalyticsEndpoint.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `AnalyticsResultResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `AnalyticsResultResponse.data` | Property | Type | Required | Description | @@ -148,7 +166,7 @@ const result = AnalyticsEndpoint.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ sql: string; params: any[] }` | ✅ | | ### Nested Shape: `AnalyticsSqlResponse.error` @@ -165,6 +183,15 @@ const result = AnalyticsEndpoint.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `AnalyticsSqlResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + --- diff --git a/content/docs/references/api/auth.mdx b/content/docs/references/api/auth.mdx index ca9d593cd20..ba6782f84ed 100644 --- a/content/docs/references/api/auth.mdx +++ b/content/docs/references/api/auth.mdx @@ -118,7 +118,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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ session: object; user: object; token?: string }` | ✅ | | ### Nested Shape: `SessionResponse.error` @@ -135,6 +135,15 @@ const result = AuthProvider.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `SessionResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `SessionResponse.data` | Property | Type | Required | Description | @@ -176,7 +185,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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ id: string; email: string; emailVerified: boolean; name: string; … }` | ✅ | | ### Nested Shape: `UserProfileResponse.error` @@ -193,6 +202,15 @@ const result = AuthProvider.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `UserProfileResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `UserProfileResponse.data` | Property | Type | Required | Description | diff --git a/content/docs/references/api/automation-api.mdx b/content/docs/references/api/automation-api.mdx index 8cd367940bc..e23785f3158 100644 --- a/content/docs/references/api/automation-api.mdx +++ b/content/docs/references/api/automation-api.mdx @@ -181,7 +181,7 @@ const result = AutomationApiErrorCode.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ name: string; label: string; description?: string; successMessage?: string; … }` | ✅ | The created flow, canonicalized — the parsed shape the engine stored, identical to what a subsequent GET answers | ### Nested Shape: `CreateFlowResponse.error` @@ -198,6 +198,15 @@ const result = AutomationApiErrorCode.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `CreateFlowResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `CreateFlowResponse.data` | Property | Type | Required | Description | @@ -248,7 +257,7 @@ const result = AutomationApiErrorCode.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ name: string; deleted: boolean }` | ✅ | | ### Nested Shape: `DeleteFlowResponse.error` @@ -265,6 +274,15 @@ const result = AutomationApiErrorCode.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `DeleteFlowResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `DeleteFlowResponse.data` | Property | Type | Required | Description | @@ -312,7 +330,7 @@ const result = AutomationApiErrorCode.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ name: string; label: string; description?: string; successMessage?: string; … }` | ✅ | Full flow definition | ### Nested Shape: `GetFlowResponse.error` @@ -329,6 +347,15 @@ const result = AutomationApiErrorCode.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `GetFlowResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `GetFlowResponse.data` | Property | Type | Required | Description | @@ -380,7 +407,7 @@ const result = AutomationApiErrorCode.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ id: string; flowName: string; flowVersion?: integer; status: Enum<'pending' \| 'running' \| 'paused' \| 'completed' \| 'failed' \| 'cancelled' \| …>; … }` | ✅ | Full execution log with step details | ### Nested Shape: `GetRunResponse.error` @@ -397,6 +424,15 @@ const result = AutomationApiErrorCode.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `GetRunResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `GetRunResponse.data` | Property | Type | Required | Description | @@ -441,7 +477,7 @@ const result = AutomationApiErrorCode.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ flows: object[]; total?: integer; nextCursor?: string; hasMore: boolean }` | ✅ | | ### Nested Shape: `ListFlowsResponse.error` @@ -458,6 +494,15 @@ const result = AutomationApiErrorCode.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `ListFlowsResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `ListFlowsResponse.data` | Property | Type | Required | Description | @@ -492,7 +537,7 @@ const result = AutomationApiErrorCode.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ runs: object[]; total?: integer; nextCursor?: string; hasMore: boolean }` | ✅ | | ### Nested Shape: `ListRunsResponse.error` @@ -509,6 +554,15 @@ const result = AutomationApiErrorCode.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `ListRunsResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `ListRunsResponse.data` | Property | Type | Required | Description | @@ -554,7 +608,7 @@ const result = AutomationApiErrorCode.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ name: string; enabled: boolean }` | ✅ | | ### Nested Shape: `ToggleFlowResponse.error` @@ -571,6 +625,15 @@ const result = AutomationApiErrorCode.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `ToggleFlowResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `ToggleFlowResponse.data` | Property | Type | Required | Description | @@ -605,7 +668,7 @@ const result = AutomationApiErrorCode.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ success: boolean; output?: any; error?: string; durationMs?: number; … }` | ✅ | | ### Nested Shape: `TriggerFlowResponse.error` @@ -622,6 +685,15 @@ const result = AutomationApiErrorCode.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `TriggerFlowResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `TriggerFlowResponse.data` | Property | Type | Required | Description | @@ -690,7 +762,7 @@ const result = AutomationApiErrorCode.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ name: string; label: string; description?: string; successMessage?: string; … }` | ✅ | The updated flow, canonicalized — the parsed shape the engine stored, identical to what a subsequent GET answers | ### Nested Shape: `UpdateFlowResponse.error` @@ -707,6 +779,15 @@ const result = AutomationApiErrorCode.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `UpdateFlowResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `UpdateFlowResponse.data` | Property | Type | Required | Description | diff --git a/content/docs/references/api/batch.mdx b/content/docs/references/api/batch.mdx index 9044729b360..716ff532c22 100644 --- a/content/docs/references/api/batch.mdx +++ b/content/docs/references/api/batch.mdx @@ -173,7 +173,7 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **operation** | `Enum<'create' \| 'update' \| 'upsert' \| 'delete'>` | optional | Operation type that was performed | | **total** | `number` | ✅ | Total number of records in the batch | | **succeeded** | `number` | ✅ | Number of records that succeeded | @@ -194,6 +194,15 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `BatchUpdateResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `BatchUpdateResponse.results[number]` | Property | Type | Required | Description | diff --git a/content/docs/references/api/contract.mdx b/content/docs/references/api/contract.mdx index 105a2d8d696..1264d0c9010 100644 --- a/content/docs/references/api/contract.mdx +++ b/content/docs/references/api/contract.mdx @@ -383,7 +383,7 @@ const result = ApiErrorSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | ### Nested Shape: `BaseResponse.error` @@ -399,6 +399,15 @@ const result = ApiErrorSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `BaseResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + --- @@ -436,7 +445,7 @@ const result = ApiErrorSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ id?: string; success: boolean; errors?: object[]; index?: number; … }[]` | ✅ | Results for each item in the batch | ### Nested Shape: `BulkResponse.error` @@ -453,6 +462,15 @@ const result = ApiErrorSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `BulkResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `BulkResponse.data[number]` | Property | Type | Required | Description | @@ -503,7 +521,7 @@ const result = ApiErrorSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **id** | `string` | ✅ | ID of the deleted record | ### Nested Shape: `DeleteResponse.error` @@ -520,6 +538,15 @@ const result = ApiErrorSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `DeleteResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + --- @@ -622,7 +649,7 @@ const result = ApiErrorSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `Record[]` | ✅ | Array of matching records | | **pagination** | `{ total?: number; limit?: number; offset?: number; cursor?: string; … }` | ✅ | Pagination info | @@ -640,6 +667,15 @@ const result = ApiErrorSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `ListRecordResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `ListRecordResponse.pagination` | Property | Type | Required | Description | @@ -738,7 +774,7 @@ Key-value map of record 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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `Record` | ✅ | The requested or modified record | ### Nested Shape: `SingleRecordResponse.error` @@ -755,6 +791,15 @@ Key-value map of record data | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `SingleRecordResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + --- diff --git a/content/docs/references/api/export.mdx b/content/docs/references/api/export.mdx index 9a3a1fa8fef..97dd9ddbbb4 100644 --- a/content/docs/references/api/export.mdx +++ b/content/docs/references/api/export.mdx @@ -65,7 +65,7 @@ const result = CreateExportJobRequestSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ jobId: string; status: Enum<'pending' \| 'processing' \| 'completed' \| 'failed' \| 'cancelled' \| 'expired'>; estimatedRecords?: integer; createdAt: string }` | ✅ | | ### Nested Shape: `CreateExportJobResponse.error` @@ -82,6 +82,15 @@ const result = CreateExportJobRequestSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `CreateExportJobResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `CreateExportJobResponse.data` | Property | Type | Required | Description | @@ -211,7 +220,7 @@ const result = CreateExportJobRequestSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ jobId: string; status: Enum<'pending' \| 'processing' \| 'completed' \| 'failed' \| 'cancelled' \| 'expired'>; format: Enum<'csv' \| 'json' \| 'jsonl' \| 'xlsx' \| 'parquet'>; totalRecords?: integer; … }` | ✅ | | ### Nested Shape: `ExportJobProgress.error` @@ -228,6 +237,15 @@ const result = CreateExportJobRequestSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `ExportJobProgress.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `ExportJobProgress.data` | Property | Type | Required | Description | @@ -316,7 +334,7 @@ const result = CreateExportJobRequestSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ jobId: string; downloadUrl: string; fileName: string; fileSize: integer; … }` | ✅ | | ### Nested Shape: `GetExportJobDownloadResponse.error` @@ -333,6 +351,15 @@ const result = CreateExportJobRequestSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `GetExportJobDownloadResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `GetExportJobDownloadResponse.data` | Property | Type | Required | Description | @@ -603,7 +630,7 @@ Type: `{ sourceField: string; targetField: string; targetLabel?: string; transfo | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ totalRecords: integer; validRecords: integer; invalidRecords: integer; duplicateRecords: integer; … }` | ✅ | | ### Nested Shape: `ImportValidationResult.error` @@ -620,6 +647,15 @@ Type: `{ sourceField: string; targetField: string; targetLabel?: string; transfo | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `ImportValidationResult.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `ImportValidationResult.data` | Property | Type | Required | Description | @@ -667,7 +703,7 @@ Type: `{ sourceField: string; targetField: string; targetLabel?: string; transfo | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ jobs: object[]; nextCursor?: string; hasMore: boolean }` | ✅ | | ### Nested Shape: `ListExportJobsResponse.error` @@ -684,6 +720,15 @@ Type: `{ sourceField: string; targetField: string; targetLabel?: string; transfo | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `ListExportJobsResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `ListExportJobsResponse.data` | Property | Type | Required | Description | @@ -780,7 +825,7 @@ Type: `{ sourceField: string; targetField: string; targetLabel?: string; transfo | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ id: string; name: string; enabled: boolean; nextRunAt?: string; … }` | ✅ | | ### Nested Shape: `ScheduleExportResponse.error` @@ -797,6 +842,15 @@ Type: `{ sourceField: string; targetField: string; targetLabel?: string; transfo | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `ScheduleExportResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `ScheduleExportResponse.data` | Property | Type | Required | Description | diff --git a/content/docs/references/api/metadata.mdx b/content/docs/references/api/metadata.mdx index f8a82eca568..b083c1c39c7 100644 --- a/content/docs/references/api/metadata.mdx +++ b/content/docs/references/api/metadata.mdx @@ -52,7 +52,7 @@ const result = AppDefinitionResponseSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ name: string; label: string \| Record; description?: string \| Record; icon?: string; … }` | ✅ | Full App Configuration | ### Nested Shape: `AppDefinitionResponse.error` @@ -69,6 +69,15 @@ const result = AppDefinitionResponseSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `AppDefinitionResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `AppDefinitionResponse.data` | Property | Type | Required | Description | @@ -115,7 +124,7 @@ const result = AppDefinitionResponseSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ name: string; label: string; icon?: string; description?: string }[]` | ✅ | List of available concepts (Objects, Apps, Flows) | ### Nested Shape: `ConceptListResponse.error` @@ -132,6 +141,15 @@ const result = AppDefinitionResponseSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `ConceptListResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + --- @@ -164,7 +182,7 @@ const result = AppDefinitionResponseSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ total: integer; succeeded: integer; failed: integer; errors?: object[] }` | ✅ | Bulk operation result | ### Nested Shape: `MetadataBulkResponse.error` @@ -181,6 +199,15 @@ const result = AppDefinitionResponseSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataBulkResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `MetadataBulkResponse.data` | Property | Type | Required | Description | @@ -219,7 +246,7 @@ const result = AppDefinitionResponseSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ type: string; name: string }` | ✅ | | ### Nested Shape: `MetadataDeleteResponse.error` @@ -236,6 +263,15 @@ const result = AppDefinitionResponseSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataDeleteResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `MetadataDeleteResponse.data` | Property | Type | Required | Description | @@ -254,7 +290,7 @@ const result = AppDefinitionResponseSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ sourceType: string; sourceName: string; targetType: string; targetName: string; … }[]` | ✅ | Items this item depends on | ### Nested Shape: `MetadataDependenciesResponse.error` @@ -271,6 +307,15 @@ const result = AppDefinitionResponseSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataDependenciesResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `MetadataDependenciesResponse.data[number]` | Property | Type | Required | Description | @@ -292,7 +337,7 @@ const result = AppDefinitionResponseSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ sourceType: string; sourceName: string; targetType: string; targetName: string; … }[]` | ✅ | Items that depend on this item | ### Nested Shape: `MetadataDependentsResponse.error` @@ -309,6 +354,15 @@ const result = AppDefinitionResponseSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataDependentsResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `MetadataDependentsResponse.data[number]` | Property | Type | Required | Description | @@ -330,7 +384,7 @@ const result = AppDefinitionResponseSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ exists: boolean }` | ✅ | | ### Nested Shape: `MetadataExistsResponse.error` @@ -347,6 +401,15 @@ const result = AppDefinitionResponseSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataExistsResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `MetadataExistsResponse.data` | Property | Type | Required | Description | @@ -377,7 +440,7 @@ const result = AppDefinitionResponseSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `any` | ✅ | Exported metadata bundle | ### Nested Shape: `MetadataExportResponse.error` @@ -394,6 +457,15 @@ const result = AppDefinitionResponseSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataExportResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + --- @@ -419,7 +491,7 @@ const result = AppDefinitionResponseSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ total: integer; imported: integer; skipped: integer; failed: integer; … }` | ✅ | Import result | ### Nested Shape: `MetadataImportResponse.error` @@ -436,6 +508,15 @@ const result = AppDefinitionResponseSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataImportResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + --- @@ -447,7 +528,7 @@ const result = AppDefinitionResponseSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ type: string; name: string; definition: Record }` | ✅ | Metadata item | ### Nested Shape: `MetadataItemResponse.error` @@ -464,6 +545,15 @@ const result = AppDefinitionResponseSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataItemResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `MetadataItemResponse.data` | Property | Type | Required | Description | @@ -483,7 +573,7 @@ const result = AppDefinitionResponseSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `Record[]` | ✅ | Array of metadata definitions | ### Nested Shape: `MetadataListResponse.error` @@ -500,6 +590,15 @@ const result = AppDefinitionResponseSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataListResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + --- @@ -511,7 +610,7 @@ const result = AppDefinitionResponseSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `string[]` | ✅ | Array of metadata item names | ### Nested Shape: `MetadataNamesResponse.error` @@ -528,6 +627,15 @@ const result = AppDefinitionResponseSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataNamesResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + --- @@ -562,7 +670,7 @@ Metadata query with filtering, sorting, and pagination | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ items: object[]; total: integer; page: integer; pageSize: integer }` | ✅ | Paginated query result | ### Nested Shape: `MetadataQueryResponse.error` @@ -579,6 +687,15 @@ Metadata query with filtering, sorting, and pagination | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataQueryResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `MetadataQueryResponse.data` | Property | Type | Required | Description | @@ -643,7 +760,7 @@ Metadata query with filtering, sorting, and pagination | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ type: string; label: string; description?: string; filePatterns: string[]; … }` | optional | Type info | ### Nested Shape: `MetadataTypeInfoResponse.error` @@ -660,6 +777,15 @@ Metadata query with filtering, sorting, and pagination | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataTypeInfoResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `MetadataTypeInfoResponse.data` | Property | Type | Required | Description | @@ -683,7 +809,7 @@ Metadata query with filtering, sorting, and pagination | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `string[]` | ✅ | Registered metadata type identifiers | ### Nested Shape: `MetadataTypesResponse.error` @@ -700,6 +826,15 @@ Metadata query with filtering, sorting, and pagination | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataTypesResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + --- @@ -723,7 +858,7 @@ Metadata query with filtering, sorting, and pagination | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ valid: boolean; errors?: object[]; warnings?: object[] }` | ✅ | Validation result | ### Nested Shape: `MetadataValidateResponse.error` @@ -740,6 +875,15 @@ Metadata query with filtering, sorting, and pagination | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `MetadataValidateResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `MetadataValidateResponse.data` | Property | Type | Required | Description | @@ -759,7 +903,7 @@ Metadata query with filtering, sorting, and pagination | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ name: string; label?: string; pluralLabel?: string; description?: string; … }` | ✅ | Full Object Schema | ### Nested Shape: `ObjectDefinitionResponse.error` @@ -776,6 +920,15 @@ Metadata query with filtering, sorting, and pagination | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `ObjectDefinitionResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `ObjectDefinitionResponse.data` | Property | Type | Required | Description | diff --git a/content/docs/references/api/package-api.mdx b/content/docs/references/api/package-api.mdx index 8fe0531d73f..e99e0c7902e 100644 --- a/content/docs/references/api/package-api.mdx +++ b/content/docs/references/api/package-api.mdx @@ -154,7 +154,7 @@ Get installed package response | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ manifest: object; status?: Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>; enabled?: boolean; installedAt?: string; … } \| … +1 more` | ✅ | Installed package details | ### Nested Shape: `GetInstalledPackageResponse.error` @@ -171,6 +171,15 @@ Get installed package response | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `GetInstalledPackageResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `GetInstalledPackageResponse.data[option 1]` Installed package with runtime lifecycle state @@ -405,7 +414,7 @@ List installed packages response | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ packages: (object \| object)[]; total?: integer; nextCursor?: string; hasMore: boolean }` | ✅ | | ### Nested Shape: `ListInstalledPackagesResponse.error` @@ -422,6 +431,15 @@ List installed packages response | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `ListInstalledPackagesResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `ListInstalledPackagesResponse.data` | Property | Type | Required | Description | @@ -522,7 +540,7 @@ Install package response | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ package: object; dependencyResolution?: object; namespaceConflicts?: object[]; message?: string }` | ✅ | | ### Nested Shape: `PackageInstallResponse.error` @@ -539,6 +557,15 @@ Install package response | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `PackageInstallResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `PackageInstallResponse.data` | Property | Type | Required | Description | @@ -636,7 +663,7 @@ Upgrade package response | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ success: boolean; phase: string; plan?: object; snapshotId?: string; … }` | ✅ | | ### Nested Shape: `PackageUpgradeResponse.error` @@ -653,6 +680,15 @@ Upgrade package response | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `PackageUpgradeResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `PackageUpgradeResponse.data` | Property | Type | Required | Description | @@ -722,7 +758,7 @@ Resolve dependencies response | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ dependencies: object[]; canProceed: boolean; requiredActions: object[]; installOrder: string[]; … }` | ✅ | Dependency resolution result with topological sort | ### Nested Shape: `ResolveDependenciesResponse.error` @@ -739,6 +775,15 @@ Resolve dependencies response | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `ResolveDependenciesResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `ResolveDependenciesResponse.data` | Property | Type | Required | Description | @@ -773,7 +818,7 @@ Uninstall package response | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ packageId: string; success: boolean; message?: string }` | ✅ | | ### Nested Shape: `UninstallPackageApiResponse.error` @@ -790,6 +835,15 @@ Uninstall package response | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `UninstallPackageApiResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `UninstallPackageApiResponse.data` | Property | Type | Required | Description | @@ -843,7 +897,7 @@ Upload artifact response | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ success: boolean; artifactRef?: object; submissionId?: string; message?: string }` | ✅ | | ### Nested Shape: `UploadArtifactResponse.error` @@ -860,6 +914,15 @@ Upload artifact response | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `UploadArtifactResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `UploadArtifactResponse.data` | Property | Type | Required | Description | diff --git a/content/docs/references/api/protocol.mdx b/content/docs/references/api/protocol.mdx index e0aa4ac3f76..5047ed154e5 100644 --- a/content/docs/references/api/protocol.mdx +++ b/content/docs/references/api/protocol.mdx @@ -414,7 +414,7 @@ Canonical cross-paradigm action/node descriptor (ADR-0018) | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **operation** | `Enum<'create' \| 'update' \| 'upsert' \| 'delete'>` | optional | Operation type that was performed | | **total** | `number` | ✅ | Total number of records in the batch | | **succeeded** | `number` | ✅ | Number of records that succeeded | @@ -435,6 +435,15 @@ Canonical cross-paradigm action/node descriptor (ADR-0018) | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `BatchDataResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `BatchDataResponse.results[number]` | Property | Type | Required | Description | @@ -641,7 +650,7 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **operation** | `Enum<'create' \| 'update' \| 'upsert' \| 'delete'>` | optional | Operation type that was performed | | **total** | `number` | ✅ | Total number of records in the batch | | **succeeded** | `number` | ✅ | Number of records that succeeded | @@ -662,6 +671,15 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `DeleteManyDataResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `DeleteManyDataResponse.results[number]` | Property | Type | Required | Description | @@ -2819,7 +2837,7 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | :--- | :--- | :--- | :--- | | **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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **operation** | `Enum<'create' \| 'update' \| 'upsert' \| 'delete'>` | optional | Operation type that was performed | | **total** | `number` | ✅ | Total number of records in the batch | | **succeeded** | `number` | ✅ | Number of records that succeeded | @@ -2840,6 +2858,15 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `UpdateManyDataResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `UpdateManyDataResponse.results[number]` | Property | Type | Required | Description | diff --git a/content/docs/references/api/storage.mdx b/content/docs/references/api/storage.mdx index 11fba345d8c..e286e9c4d30 100644 --- a/content/docs/references/api/storage.mdx +++ b/content/docs/references/api/storage.mdx @@ -54,7 +54,7 @@ const result = CompleteChunkedUploadRequestSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ fileId: string; key: string; size: integer; mimeType: string; … }` | ✅ | | ### Nested Shape: `CompleteChunkedUploadResponse.error` @@ -71,6 +71,15 @@ const result = CompleteChunkedUploadRequestSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `CompleteChunkedUploadResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `CompleteChunkedUploadResponse.data` | Property | Type | Required | Description | @@ -105,7 +114,7 @@ const result = CompleteChunkedUploadRequestSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ url: string }` | ✅ | | ### Nested Shape: `FileDownloadUrlResponse.error` @@ -122,6 +131,15 @@ const result = CompleteChunkedUploadRequestSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `FileDownloadUrlResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `FileDownloadUrlResponse.data` | Property | Type | Required | Description | @@ -154,7 +172,7 @@ const result = CompleteChunkedUploadRequestSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ path: string; name: string; size: integer; mimeType: string; … }` | ✅ | Uploaded file metadata | ### Nested Shape: `FileUploadResponse.error` @@ -171,6 +189,15 @@ const result = CompleteChunkedUploadRequestSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `FileUploadResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `FileUploadResponse.data` | Property | Type | Required | Description | @@ -227,7 +254,7 @@ const result = CompleteChunkedUploadRequestSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ uploadId: string; resumeToken: string; fileId: string; totalChunks: integer; … }` | ✅ | | ### Nested Shape: `InitiateChunkedUploadResponse.error` @@ -244,6 +271,15 @@ const result = CompleteChunkedUploadRequestSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `InitiateChunkedUploadResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `InitiateChunkedUploadResponse.data` | Property | Type | Required | Description | @@ -266,7 +302,7 @@ const result = CompleteChunkedUploadRequestSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ uploadUrl: string; downloadUrl?: string; fileId: string; method: Enum<'PUT' \| 'POST'>; … }` | ✅ | | ### Nested Shape: `PresignedUrlResponse.error` @@ -283,6 +319,15 @@ const result = CompleteChunkedUploadRequestSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `PresignedUrlResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `PresignedUrlResponse.data` | Property | Type | Required | Description | @@ -305,7 +350,7 @@ const result = CompleteChunkedUploadRequestSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ key: string }` | ✅ | | ### Nested Shape: `RawUploadResponse.error` @@ -322,6 +367,15 @@ const result = CompleteChunkedUploadRequestSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `RawUploadResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `RawUploadResponse.data` | Property | Type | Required | Description | @@ -352,7 +406,7 @@ const result = CompleteChunkedUploadRequestSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ chunkIndex: integer; eTag: string; bytesReceived: integer }` | ✅ | | ### Nested Shape: `UploadChunkResponse.error` @@ -369,6 +423,15 @@ const result = CompleteChunkedUploadRequestSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `UploadChunkResponse.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `UploadChunkResponse.data` | Property | Type | Required | Description | @@ -388,7 +451,7 @@ const result = CompleteChunkedUploadRequestSchema.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?: number; requestId?: string; traceId?: string }` | optional | Response metadata | +| **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | | **data** | `{ uploadId: string; fileId: string; filename: string; totalSize: integer; … }` | ✅ | | ### Nested Shape: `UploadProgress.error` @@ -405,6 +468,15 @@ const result = CompleteChunkedUploadRequestSchema.parse(data); | **details** | `any` | optional | Additional error context (e.g. field validation errors) | | **requestId** | `string` | optional | Request ID for tracking | +### Nested Shape: `UploadProgress.meta` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **timestamp** | `string` | ✅ | | +| **duration** | `integer` | optional | Server-side processing duration in milliseconds | +| **requestId** | `string` | optional | | +| **traceId** | `string` | optional | | + ### Nested Shape: `UploadProgress.data` | Property | Type | Required | Description | diff --git a/content/docs/references/kernel/plugin-lifecycle-advanced.mdx b/content/docs/references/kernel/plugin-lifecycle-advanced.mdx index a269bea1420..ab56ccc1dee 100644 --- a/content/docs/references/kernel/plugin-lifecycle-advanced.mdx +++ b/content/docs/references/kernel/plugin-lifecycle-advanced.mdx @@ -46,7 +46,7 @@ const result = HotReloadConfigSchema.parse(data); | **debounceDelay** | `never` | optional | [REMOVED] `HotReloadConfig.debounceDelay` was renamed to `debounceDelayMs` 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 published describe named none, so the reference-page reader got a bare 1000. Rename the key to `debounceDelayMs`; the value (milliseconds) and the 1000 default are unchanged. | | **preserveState** | `boolean` | optional (default: `true`) | Keep plugin state across reloads | | **stateStrategy** | `Enum<'memory' \| 'none'>` | optional (default: `"memory"`) | How to preserve state during reload | -| **shutdownTimeout** | `integer` | optional (default: `30000`) | Maximum time to wait for graceful shutdown | +| **shutdownTimeout** | `integer` | optional (default: `30000`) | Maximum time to wait for graceful shutdown, in milliseconds | | **beforeReload** | `string[]` | optional | Hook names to call before reload | | **afterReload** | `string[]` | optional | Hook names to call after reload | diff --git a/content/docs/references/kernel/plugin-security-advanced.mdx b/content/docs/references/kernel/plugin-security-advanced.mdx index 19b190eef18..2132c471d48 100644 --- a/content/docs/references/kernel/plugin-security-advanced.mdx +++ b/content/docs/references/kernel/plugin-security-advanced.mdx @@ -46,6 +46,16 @@ const result = KernelSecurityPolicySchema.parse(data); | **encryption** | `{ dataAtRest: boolean; dataInTransit: boolean; algorithm?: string; minKeyLength?: integer }` | optional | | | **auditLog** | `{ enabled: boolean; events?: string[]; retentionDays?: integer }` | optional | | +### Nested Shape: `KernelSecurityPolicy.cors` + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **allowedOrigins** | `string[]` | ✅ | | +| **allowedMethods** | `string[]` | ✅ | | +| **allowedHeaders** | `string[]` | ✅ | | +| **allowCredentials** | `boolean` | optional (default: `false`) | | +| **maxAge** | `integer` | optional | Preflight cache duration in seconds (unit per CORS `Access-Control-Max-Age` (WHATWG Fetch)) | + ### Nested Shape: `KernelSecurityPolicy.rateLimit` | Property | Type | Required | Description | diff --git a/content/docs/references/system/auth-config.mdx b/content/docs/references/system/auth-config.mdx index 89c9cde5121..af7159166a6 100644 --- a/content/docs/references/system/auth-config.mdx +++ b/content/docs/references/system/auth-config.mdx @@ -113,7 +113,7 @@ Advanced / low-level Better-Auth options | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **expiresIn** | `number` | optional (default: `604800`) | Session duration in seconds (unit per better-auth `session.expiresIn`) | -| **updateAge** | `number` | optional (default: `86400`) | Session update frequency | +| **updateAge** | `number` | optional (default: `86400`) | Session update frequency in seconds (unit per better-auth `session.updateAge`) | ### Nested Shape: `AuthConfig.socialProviders[string]` diff --git a/content/docs/references/system/metadata-persistence.mdx b/content/docs/references/system/metadata-persistence.mdx index 6add79ed777..f10013384a6 100644 --- a/content/docs/references/system/metadata-persistence.mdx +++ b/content/docs/references/system/metadata-persistence.mdx @@ -196,7 +196,7 @@ Metadata file format | **fromCache** | `boolean` | optional | | | **etag** | `string` | optional | | | **notModified** | `boolean` | optional | | -| **loadTime** | `number` | optional | | +| **loadTime** | `integer` | optional | How long the load took, in milliseconds | ### Nested Shape: `MetadataLoadResult.stats` @@ -351,7 +351,7 @@ Metadata file format | **stats** | `{ path?: string; size?: number; mtime?: string; hash?: string; … }` | optional | | | **etag** | `string` | optional | | | **size** | `number` | optional | | -| **saveTime** | `number` | optional | | +| **saveTime** | `integer` | optional | How long the save took, in milliseconds | | **backupPath** | `string` | optional | | ### Nested Shape: `MetadataSaveResult.stats` diff --git a/content/docs/references/system/metrics.mdx b/content/docs/references/system/metrics.mdx index b2b051fe4ba..221ab13f820 100644 --- a/content/docs/references/system/metrics.mdx +++ b/content/docs/references/system/metrics.mdx @@ -88,7 +88,7 @@ Metric aggregation configuration | **durationSeconds** | `integer` | ✅ | Window duration in seconds | | **size** | `never` | optional | [REMOVED] The aggregation/SLI window key `size` was renamed to `durationSeconds` in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. The new name is not `sizeSeconds`: `size` means a byte or row count everywhere else in this spec, so the rename drops it rather than bolting a unit onto it. Rename `window.size` to `window.durationSeconds` on both MetricAggregationConfig and ServiceLevelIndicator; the value (seconds) is unchanged. | | **sliding** | `boolean` | optional (default: `false`) | | -| **slideInterval** | `integer` | optional | | +| **slideInterval** | `integer` | optional | Slide interval for sliding windows, in seconds | --- diff --git a/packages/spec/src/api/contract.test.ts b/packages/spec/src/api/contract.test.ts index 60c1560ad8d..5228f3b017a 100644 --- a/packages/spec/src/api/contract.test.ts +++ b/packages/spec/src/api/contract.test.ts @@ -797,3 +797,55 @@ describe('DataLoaderConfig.cacheTtl \u2192 cacheTtlSeconds (#15677)', () => { expect(DataLoaderConfigSchema.safeParse({ cacheTtlSeconds: -1 }).success).toBe(false); }); }); +// #18124 — step 3 of ruling A on #18115. `BaseResponse.meta.duration` declares +// its unit through the closed `DurationMs` type (`src/shared/duration.zod.ts`) +// rather than through a rename, so the unit rides the contract and the published +// JSON Schema instead of only the key name. +// +// The unit was MEASURED, not read off the name, and the measurement is worth +// recording because it came back EMPTY: nothing in this repo writes this `meta` +// block — `packages/rest/src` contains no `timestamp:` writer at all, and the +// repo-wide sweep for `duration:` assignments finds only `Date.now() - start` +// call sites (the CLI's `timer.elapsed()`, the QA runner). With no producer to +// contradict, the declaration is taken from the sibling channel that does speak: +// every key in this spec that spells the unit for a processing time spells +// milliseconds (`tracing.durationMs`, `worker.durationMs`, `worker.avgExecutionMs`). +describe('BaseResponse.meta.duration declares milliseconds (#18124)', () => { + it('refuses a fractional millisecond count', () => { + const result = BaseResponseSchema.safeParse({ + success: true, + meta: { timestamp: '2024-01-01T00:00:00Z', duration: 150.5 }, + }); + expect(result.success).toBe(false); + const issue = result.error!.issues.find((i) => i.path.join('.') === 'meta.duration'); + expect(issue).toBeDefined(); + expect(issue!.code).toBe('invalid_type'); + }); + + it('refuses a negative span', () => { + const result = BaseResponseSchema.safeParse({ + success: true, + meta: { timestamp: '2024-01-01T00:00:00Z', duration: -1 }, + }); + expect(result.success).toBe(false); + const issue = result.error!.issues.find((i) => i.path.join('.') === 'meta.duration'); + expect(issue).toBeDefined(); + expect(issue!.code).toBe('too_small'); + }); + + it('still accepts a whole, non-negative count — including zero', () => { + const base = { timestamp: '2024-01-01T00:00:00Z' }; + expect(BaseResponseSchema.parse({ success: true, meta: { ...base, duration: 150 } }).meta?.duration).toBe(150); + expect(BaseResponseSchema.parse({ success: true, meta: { ...base, duration: 0 } }).meta?.duration).toBe(0); + }); + + it('publishes the unit in the describe the reference page renders', () => { + const json = z.toJSONSchema(BaseResponseSchema, { + target: 'draft-2020-12', + io: 'input', + unrepresentable: 'any', + }) as { properties?: { meta?: { properties?: { duration?: { description?: unknown } } } } }; + expect(json.properties?.meta?.properties?.duration?.description) + .toBe('Server-side processing duration in milliseconds'); + }); +}); diff --git a/packages/spec/src/kernel/plugin-lifecycle-advanced.test.ts b/packages/spec/src/kernel/plugin-lifecycle-advanced.test.ts index 7b226ffc380..69de510bfd9 100644 --- a/packages/spec/src/kernel/plugin-lifecycle-advanced.test.ts +++ b/packages/spec/src/kernel/plugin-lifecycle-advanced.test.ts @@ -424,3 +424,36 @@ describe('plugin lifecycle durations carry their unit (#17780, #14478)', () => { ); }); }); +// #18124 — step 3 of ruling A on #18115. `HotReloadConfig.shutdownTimeout` takes +// the TYPE route rather than the rename route, and that is the disposition this +// def already recorded: the #15676 wave that renamed its siblings to `intervalMs` +// / `timeoutMs` / `debounceDelayMs` wrote down that this key was "deliberately NOT +// renamed with them". Measured unit: `packages/core/src/hot-reload.ts` is the only +// in-repo reader and treats it as a millisecond budget (its own test suite drives +// 120_000, 1000 and 50 through it). +// +// `DurationMs` is `z.number().int().nonnegative()` and this key declared +// `z.number().int().min(0)`, so the accepted set is UNCHANGED — the pins below +// are about what the declaration now refuses loudly at the authoring site. +describe('HotReloadConfig.shutdownTimeout declares milliseconds (#18124)', () => { + it('refuses a fractional millisecond count', () => { + const result = HotReloadConfigSchema.safeParse({ shutdownTimeout: 30000.5 }); + expect(result.success).toBe(false); + const issue = result.error!.issues.find((i) => i.path.join('.') === 'shutdownTimeout'); + expect(issue).toBeDefined(); + expect(issue!.code).toBe('invalid_type'); + }); + + it('refuses a negative span', () => { + const result = HotReloadConfigSchema.safeParse({ shutdownTimeout: -1 }); + expect(result.success).toBe(false); + const issue = result.error!.issues.find((i) => i.path.join('.') === 'shutdownTimeout'); + expect(issue).toBeDefined(); + expect(issue!.code).toBe('too_small'); + }); + + it('keeps the accepted set it already had — the 30000 default and the zero floor', () => { + expect(HotReloadConfigSchema.parse({}).shutdownTimeout).toBe(30000); + expect(HotReloadConfigSchema.parse({ shutdownTimeout: 0 }).shutdownTimeout).toBe(0); + }); +}); diff --git a/packages/spec/src/kernel/plugin-security-advanced.test.ts b/packages/spec/src/kernel/plugin-security-advanced.test.ts index f284c46b6d5..21ce41bdfc5 100644 --- a/packages/spec/src/kernel/plugin-security-advanced.test.ts +++ b/packages/spec/src/kernel/plugin-security-advanced.test.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; +import { z } from 'zod'; import { RuntimeConfigSchema, SandboxConfigSchema, @@ -465,3 +466,43 @@ describe('RuntimeConfig.resourceLimits.timeout → timeoutMs (#15939 ruling A, # expect(sandboxMsg).not.toContain('`RuntimeConfig.resourceLimits.timeout`'); }); }); +// #18124 — step 3 of ruling A on #18115. `KernelSecurityPolicy.cors.maxAge` is a +// CORS `Access-Control-Max-Age` mirror, so it takes the `externalVocabulary` +// route rather than a type or a rename: it is the SAME key as its already-declared +// twin `CorsConfig.maxAge` (`src/shared/http.zod.ts`), which carries exactly this +// marker and exactly this unit. The standard defines the header's value in +// seconds; renaming it to `maxAgeSeconds` would break the one-to-one reading +// between this policy and the header it emits. +// +// ⚠️ No gate can catch this key losing its marker, because a marker's absence is +// how an undeclared key looks — the census simply stops admitting it. This pin is +// the only guard, exactly as the twin's pin in `system/object-storage.test.ts` is. +describe('KernelSecurityPolicy.cors.maxAge declares seconds by mirror (#18124)', () => { + const policy = { + cors: { + allowedOrigins: ['https://app.example.com'], + allowedMethods: ['GET'], + allowedHeaders: ['content-type'], + maxAge: 86400, + }, + }; + + it('keeps the bare name and the value it always accepted', () => { + expect(KernelSecurityPolicySchema.parse(policy).cors?.maxAge).toBe(86400); + }); + + it('emits the externalVocabulary marker and the unit through z.toJSONSchema', () => { + const json = z.toJSONSchema(KernelSecurityPolicySchema, { + target: 'draft-2020-12', + io: 'input', + unrepresentable: 'any', + }) as { + properties?: { + cors?: { properties?: { maxAge?: { externalVocabulary?: unknown; description?: unknown } } }; + }; + }; + const maxAge = json.properties?.cors?.properties?.maxAge; + expect(maxAge?.externalVocabulary).toBe('CORS `Access-Control-Max-Age` (WHATWG Fetch)'); + expect(maxAge?.description).toBe('Preflight cache duration in seconds'); + }); +}); diff --git a/packages/spec/src/system/auth-config.test.ts b/packages/spec/src/system/auth-config.test.ts index 8cf57cb55c9..b77b9566293 100644 --- a/packages/spec/src/system/auth-config.test.ts +++ b/packages/spec/src/system/auth-config.test.ts @@ -1,4 +1,5 @@ import { describe, it, expect } from 'vitest'; +import { z } from 'zod'; import { AuthProviderConfigSchema, AuthPluginConfigSchema, @@ -508,3 +509,41 @@ describe('AudienceConfigSchema (#11739)', () => { expect(() => AuthConfigSchema.parse({ audience: { posture: 'bogus' } })).toThrow(); }); }); +// #18124 — step 3 of ruling A on #18115. `AuthConfig.session.updateAge` takes the +// `externalVocabulary` route, the one its sibling `session.expiresIn` already +// carries. The comment above the pair in the schema calls BOTH of them better-auth +// names "forwarded by name", and the forwarding is real: +// `packages/plugins/plugin-auth/src/auth-manager.ts` passes +// `updateAge: this.config.session?.updateAge || 60 * 60 * 24` straight into +// better-auth's `session.updateAge`, whose unit is seconds. Only `expiresIn` +// carried the marker; this closes the pair. +describe('AuthConfig.session.updateAge declares seconds by mirror (#18124)', () => { + it('keeps the bare name, the default and the value it always accepted', () => { + expect(AuthConfigSchema.parse({}).session).toBeUndefined(); + const parsed = AuthConfigSchema.parse({ session: { updateAge: 3 * 86_400 } }); + expect(parsed.session?.updateAge).toBe(3 * 86_400); + expect(AuthConfigSchema.parse({ session: {} }).session?.updateAge).toBe(86_400); + }); + + it('emits the externalVocabulary marker and the unit through z.toJSONSchema', () => { + const json = z.toJSONSchema(AuthConfigSchema, { + target: 'draft-2020-12', + io: 'input', + unrepresentable: 'any', + }) as { + properties?: { + session?: { + properties?: { + updateAge?: { externalVocabulary?: unknown; description?: unknown }; + expiresIn?: { externalVocabulary?: unknown }; + }; + }; + }; + }; + const session = json.properties?.session?.properties; + expect(session?.updateAge?.externalVocabulary).toBe('better-auth `session.updateAge`'); + expect(session?.updateAge?.description).toBe('Session update frequency in seconds'); + // The sibling this row was matched to — unchanged, and still declared. + expect(session?.expiresIn?.externalVocabulary).toBe('better-auth `session.expiresIn`'); + }); +}); diff --git a/packages/spec/src/system/metadata-persistence.test.ts b/packages/spec/src/system/metadata-persistence.test.ts index ace613b0ad4..53f99379591 100644 --- a/packages/spec/src/system/metadata-persistence.test.ts +++ b/packages/spec/src/system/metadata-persistence.test.ts @@ -563,3 +563,40 @@ describe('PackagePublishResultSchema', () => { expect(() => PackagePublishResultSchema.parse({ success: true })).toThrow(); }); }); +// #18124 — step 3 of ruling A on #18115. `MetadataLoadResult.loadTime` and +// `MetadataSaveResult.saveTime` are the census's class-D rows: bare +// `z.number().optional()` with no describe and no JSDoc, beside `size` and `etag`, +// so their unit lived in no channel at all. +// +// The producers were measured and they agree: every writer in +// `packages/metadata/src/loaders/` computes `Date.now() - startTime` +// (`filesystem-loader.ts`, `database-loader.ts`) or writes a literal `0` +// (`memory-loader.ts`, `remote-loader.ts`). Milliseconds, integral, non-negative +// — which is exactly `DurationMs`. +describe('metadata load/save result durations declare milliseconds (#18124)', () => { + it('loadTime refuses a fractional millisecond count and a negative span', () => { + const fractional = MetadataLoadResultSchema.safeParse({ data: null, loadTime: 42.5 }); + expect(fractional.success).toBe(false); + expect(fractional.error!.issues.find((i) => i.path.join('.') === 'loadTime')?.code).toBe('invalid_type'); + + const negative = MetadataLoadResultSchema.safeParse({ data: null, loadTime: -1 }); + expect(negative.success).toBe(false); + expect(negative.error!.issues.find((i) => i.path.join('.') === 'loadTime')?.code).toBe('too_small'); + }); + + it('saveTime refuses a fractional millisecond count and a negative span', () => { + const fractional = MetadataSaveResultSchema.safeParse({ success: true, saveTime: 42.5 }); + expect(fractional.success).toBe(false); + expect(fractional.error!.issues.find((i) => i.path.join('.') === 'saveTime')?.code).toBe('invalid_type'); + + const negative = MetadataSaveResultSchema.safeParse({ success: true, saveTime: -1 }); + expect(negative.success).toBe(false); + expect(negative.error!.issues.find((i) => i.path.join('.') === 'saveTime')?.code).toBe('too_small'); + }); + + it('accepts what every measured producer actually writes — an elapsed count, and zero', () => { + expect(MetadataLoadResultSchema.parse({ data: null, loadTime: 42 }).loadTime).toBe(42); + expect(MetadataLoadResultSchema.parse({ data: null, loadTime: 0 }).loadTime).toBe(0); + expect(MetadataSaveResultSchema.parse({ success: true, saveTime: 0 }).saveTime).toBe(0); + }); +}); diff --git a/packages/spec/src/system/metrics.test.ts b/packages/spec/src/system/metrics.test.ts index 5ed1c668164..8f3208aa95f 100644 --- a/packages/spec/src/system/metrics.test.ts +++ b/packages/spec/src/system/metrics.test.ts @@ -722,3 +722,67 @@ describe('metrics JSDoc-only durations carry their unit (#15939, #14478)', () => }).period.durationSeconds).toBe(2592000); }); }); +// #18124 — step 3 of ruling A on #18115. Two metrics rows declare their unit +// through `DurationSeconds`: +// +// - `MetricAggregationConfig.window.slideInterval` — seconds, from the +// `durationSeconds` sibling it slides across in the same object literal. +// - `MetricsConfig.retention.downsampling[].resolution` — seconds, stated in its +// JSDoc and by its `afterSeconds` sibling, and in NEITHER published channel +// until now (the #14519 shape: the reader of the reference page could not +// reach the unit at all). +// +// Both keep the `.positive()` floor they already declared, so the accepted set +// narrows only by the integer requirement `DurationSeconds` carries. +describe('metrics duration rows declare seconds through the type (#18124)', () => { + const window = { durationSeconds: 300, sliding: true }; + + it('slideInterval refuses a fractional second count', () => { + const result = MetricAggregationConfigSchema.safeParse({ + type: 'avg', + window: { ...window, slideInterval: 60.5 }, + }); + expect(result.success).toBe(false); + const issue = result.error!.issues.find((i) => i.path.join('.') === 'window.slideInterval'); + expect(issue).toBeDefined(); + expect(issue!.code).toBe('invalid_type'); + }); + + it('slideInterval keeps its positive floor — zero and negatives still refused', () => { + for (const bad of [0, -60]) { + const result = MetricAggregationConfigSchema.safeParse({ + type: 'avg', + window: { ...window, slideInterval: bad }, + }); + expect(result.success).toBe(false); + const issue = result.error!.issues.find((i) => i.path.join('.') === 'window.slideInterval'); + expect(issue).toBeDefined(); + expect(issue!.code).toBe('too_small'); + } + }); + + it('slideInterval still accepts the whole-second value it always did', () => { + const parsed = MetricAggregationConfigSchema.parse({ + type: 'avg', + window: { ...window, slideInterval: 60 }, + }); + expect(parsed.window?.slideInterval).toBe(60); + }); + + it('downsampling resolution refuses a fractional second count and keeps its floor', () => { + const config = (resolution: number) => ({ + name: 'test_metrics', + label: 'Test Metrics', + retention: { downsampling: [{ afterSeconds: 3600, resolution }] }, + }); + const fractional = MetricsConfigSchema.safeParse(config(60.5)); + expect(fractional.success).toBe(false); + expect(fractional.error!.issues.some((i) => i.code === 'invalid_type')).toBe(true); + + const zero = MetricsConfigSchema.safeParse(config(0)); + expect(zero.success).toBe(false); + expect(zero.error!.issues.some((i) => i.code === 'too_small')).toBe(true); + + expect(MetricsConfigSchema.parse(config(60)).retention?.downsampling?.[0]?.resolution).toBe(60); + }); +}); diff --git a/skills/objectstack-api/references/_index.md b/skills/objectstack-api/references/_index.md index b37beedfc23..282fa430d15 100644 --- a/skills/objectstack-api/references/_index.md +++ b/skills/objectstack-api/references/_index.md @@ -30,6 +30,7 @@ from `node_modules` — there is no local copy in the skill bundle. - `node_modules/@objectstack/spec/src/kernel/execution-context.zod.ts` — Exports: ExecutionContextSchema - `node_modules/@objectstack/spec/src/kernel/metadata-protection.zod.ts` — Metadata Protection Model — Phase 1 (ADR-0010) - `node_modules/@objectstack/spec/src/security/explain.zod.ts` — [ADR-0090 D6] Access-explanation contract — `explain(principal, object, +- `node_modules/@objectstack/spec/src/shared/duration.zod.ts` — Exports: DurationMs, DurationSeconds - `node_modules/@objectstack/spec/src/shared/epoch.zod.ts` — Exports: EpochMs - `node_modules/@objectstack/spec/src/shared/expression.zod.ts` — Expression Protocol - `node_modules/@objectstack/spec/src/shared/http.zod.ts` — Shared HTTP Schemas From 78e98c856cc016e20c14e8d9435d2d219d9dd79f Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 17 Sep 2026 12:22:34 +0000 Subject: [PATCH 3/4] chore(changeset): declare the duration-declaration tranche Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude --- ...enuine-duration-rows-declare-their-unit.md | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .changeset/18124-genuine-duration-rows-declare-their-unit.md diff --git a/.changeset/18124-genuine-duration-rows-declare-their-unit.md b/.changeset/18124-genuine-duration-rows-declare-their-unit.md new file mode 100644 index 00000000000..301052f62c2 --- /dev/null +++ b/.changeset/18124-genuine-duration-rows-declare-their-unit.md @@ -0,0 +1,29 @@ +--- +'@objectstack/spec': minor +--- + +spec: the genuine duration rows declare their unit — `DurationMs` / `DurationSeconds` and two `externalVocabulary` mirrors (#18124) + +**BREAKING** — three keys that accepted any `number` now accept whole, non-negative numbers only. No key is renamed, added or removed, and no exported symbol moves. + +Step ③ of ruling A on #18115. Step ① added the closed duration vocabulary and step ② taught `check:duration-unit-keys` to read it; this converts the rows the census found carrying a genuine duration with its unit written down in no channel a reader can reach. + +**Six rows declare the unit on the value**, by adopting `DurationMs` / `DurationSeconds` (`@objectstack/spec/shared`) and stating the unit in the describe the reference page renders: + +- `API.BaseResponse.meta.duration` — milliseconds +- `Kernel.HotReloadConfig.shutdownTimeout` — milliseconds +- `System.MetricAggregationConfig.window.slideInterval` — seconds +- `System.MetricsConfig.retention.downsampling[].resolution` — seconds +- `System.MetadataLoadResult.loadTime`, `System.MetadataSaveResult.saveTime` — milliseconds + +**Two rows declare it by mirror**, with `.meta({ externalVocabulary })` plus the unit in the describe, because the key name is fixed outside this repo and renaming it would break the correspondence that makes it readable: + +- `Kernel.KernelSecurityPolicy.cors.maxAge` — seconds, per CORS `Access-Control-Max-Age` (WHATWG Fetch). This is the same declaration its twin `CorsConfig.maxAge` already carried. +- `System.AuthConfig.session.updateAge` — seconds, per better-auth `session.updateAge`. Its sibling `session.expiresIn` already carried the marker; this closes the pair. + +**What an author must change: nothing, unless they were writing a fraction or a negative span.** Only `meta.duration`, `loadTime` and `saveTime` change what they accept — each was a bare `z.number()` and is now `z.number().int().nonnegative()`. `shutdownTimeout` declared `.int().min(0)` and `slideInterval` / `resolution` declared `.int().positive()`; all three keep their floor, so their accepted set is byte-for-byte what it was and only their description is new. The two mirror rows keep their types untouched. + +Every unit is a measurement of the row's producer, printed in the PR body per row, never a reading of the key name. + +Clause-②: no (narrowing) +ADR-0087 disposition: none — no key is renamed, removed or retired, so no conversion-layer entry and no tombstone is owed. The three narrowing rows refuse a value no measured producer writes. From 43b24d4c7086d12d0f78046b2f08fdc2385d677b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 17 Sep 2026 12:23:04 +0000 Subject: [PATCH 4/4] chore(changeset): answer the ADR-0087 disposition in writing Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude --- .changeset/18124-genuine-duration-rows-declare-their-unit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/18124-genuine-duration-rows-declare-their-unit.md b/.changeset/18124-genuine-duration-rows-declare-their-unit.md index 301052f62c2..2d9245ae55c 100644 --- a/.changeset/18124-genuine-duration-rows-declare-their-unit.md +++ b/.changeset/18124-genuine-duration-rows-declare-their-unit.md @@ -26,4 +26,4 @@ Step ③ of ruling A on #18115. Step ① added the closed duration vocabulary an Every unit is a measurement of the row's producer, printed in the PR body per row, never a reading of the key name. Clause-②: no (narrowing) -ADR-0087 disposition: none — no key is renamed, removed or retired, so no conversion-layer entry and no tombstone is owed. The three narrowing rows refuse a value no measured producer writes. +