From 9610b1370496d248eabddaa93377dc21521be997 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 2 Aug 2026 09:25:53 +0000 Subject: [PATCH 1/3] =?UTF-8?q?feat(spec)!:=20resolve=20the=20MetadataEven?= =?UTF-8?q?t/MetadataBulkRegisterRequest=20dual=20source=20=E2=80=94=20./k?= =?UTF-8?q?ernel=20copies=20removed,=20./api=20keeps=20the=20bare=20names?= =?UTF-8?q?=20(#4587)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The three #4535-C2 baseline rows were the #4411 trap on the kernel metadata family: MetadataEvent(Schema) and MetadataBulkRegisterRequestSchema each had a second, different declaration in ./kernel, and which shape a consumer got depended only on the import path. Import-statement-level scan across framework, cloud and objectui: - ./kernel copies: zero importers outside their own unit test in all three repos. The kernel MetadataEvent lifecycle vocabulary (metadata.registered/.../exported) has NO producer anywhere; the kernel bulk-register per-item `namespace` field matches no enforced write path (IMetadataService.bulkRegister and MetadataManager.bulkRegister both take {type,name,data} items only). - ./api MetadataEvent is the live realtime contract: MetadataManager publishes metadata.{type}.{created|deleted} events and @objectstack/client / client-react subscribe against the type. - ./api MetadataBulkRegisterRequestSchema is the POST /api/meta/bulk/register contract whose item shape matches the runtime. Disposal (route 1, dead-side delete, v17 major window): both kernel copies removed; ./api is the sole owner of the bare names. Name continuity for the kernel-only type alias: `MetadataBulkRegisterRequest` (z.input) is now exported from ./api beside its schema, per the family convention and the #4570 docs-import concern. Compile-time pin (typeof import conditional type, #4581 pattern) keeps the bare names out of ./kernel; new events.test.ts covers the surviving ./api declarations. dual-source-exports.baseline.json: exactly the 3 named rows removed (31 -> 28). json-schema.manifest: kernel/MetadataEvent and kernel/MetadataBulkRegisterRequest retired deliberately; their 11 authorable-surface rows hand-deleted per the #4458/#4568/#4581 precedent (plugin TS types, schema bodies deleted — no silent-strip path, misuse fails at the import site at compile time). Changeset: @objectstack/spec major with FROM -> TO migration lines. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL --- .../metadata-event-dual-source-kernel-side.md | 55 ++++++++ packages/spec/authorable-surface.json | 11 -- .../spec/dual-source-exports.baseline.json | 3 - packages/spec/json-schema.manifest.json | 2 - packages/spec/src/api/events.test.ts | 124 ++++++++++++++++++ packages/spec/src/api/metadata.test.ts | 19 +++ packages/spec/src/api/metadata.zod.ts | 10 ++ .../spec/src/kernel/metadata-plugin.test.ts | 116 +++------------- .../spec/src/kernel/metadata-plugin.zod.ts | 90 ++++--------- 9 files changed, 253 insertions(+), 177 deletions(-) create mode 100644 .changeset/metadata-event-dual-source-kernel-side.md create mode 100644 packages/spec/src/api/events.test.ts diff --git a/.changeset/metadata-event-dual-source-kernel-side.md b/.changeset/metadata-event-dual-source-kernel-side.md new file mode 100644 index 0000000000..13b266e820 --- /dev/null +++ b/.changeset/metadata-event-dual-source-kernel-side.md @@ -0,0 +1,55 @@ +--- +"@objectstack/spec": major +--- + +feat(spec)!: `@objectstack/spec/kernel` no longer exports `MetadataEvent(Schema)` / `MetadataBulkRegisterRequest(Schema)` — the bare names belong to `./api` alone (#4587) + +The names `MetadataEvent` / `MetadataEventSchema` / +`MetadataBulkRegisterRequestSchema` resolved to **two different declarations** +depending on the import path (`./api` vs `./kernel`) — the #4411 dual-source +trap. Resolution (three-repo, import-statement-level consumer scan: framework, +cloud, objectui — the `./kernel` copies had zero importers outside their own +unit test): + +- **Removed** `MetadataEventSchema` / `MetadataEvent` from + `@objectstack/spec/kernel`. This was a lifecycle-event envelope + (`event: 'metadata.registered' | … | 'metadata.exported'`, plus + `actor`/`payload`/`namespace`) that **nothing ever emitted or consumed** — + the vocabulary appears in no producer in any of the three repos. The live + contract is `./api`'s `MetadataEvent(Schema)` + (`type: 'metadata.{type}.{created|updated|deleted}'`, with `id` / `definition` + / `userId`): `MetadataManager` publishes those events to the realtime + service and `@objectstack/client` / `@objectstack/client-react` subscribe to + them. + - FROM `import { MetadataEvent } from '@objectstack/spec/kernel'` → + TO `import type { MetadataEvent } from '@objectstack/spec/api'`. + **Shape change**: the api event has `id` (uuid), `type` + (`metadata.{type}.{created|updated|deleted}`), `definition`, `userId`; the + removed kernel shape's `event` / `actor` / `payload` / `namespace` fields + do not exist there. If you needed runtime *watch* events, that contract is + `MetadataWatchEvent` in `@objectstack/spec/system`; repository change-log + events are `MetadataEvent` from `@objectstack/metadata-core` (ADR-0008) — + a third, unrelated declaration that is not part of `@objectstack/spec`. +- **Removed** `MetadataBulkRegisterRequestSchema` / + `MetadataBulkRegisterRequest` from `@objectstack/spec/kernel`. It was a dead + near-duplicate of the REST contract that also diverged from the enforced + write path: its per-item `namespace` field exists neither in + `IMetadataService.bulkRegister` (contracts) nor in + `MetadataManager.bulkRegister`, and `namespace` is deprecated platform-wide. + - FROM `import { MetadataBulkRegisterRequestSchema, MetadataBulkRegisterRequest } from '@objectstack/spec/kernel'` → + TO `import { MetadataBulkRegisterRequestSchema, type MetadataBulkRegisterRequest } from '@objectstack/spec/api'` + (the `POST /api/meta/bulk/register` contract; the type export is new on + `./api` in this release). **Shape change**: items are strictly + `{ type, name, data }` — a per-item `namespace` no longer parses into the + accepted shape. `MetadataBulkRegisterRequest` is the authoring-side type + (`z.input`): `continueOnError` / `validate` stay optional and carry + defaults, as before. +- `@objectstack/spec/api`'s `MetadataEvent(Schema)` and + `MetadataBulkRegisterRequestSchema` are **unchanged** and are now the sole + owners of the bare names. Imports from `./api` need no migration. +- `@objectstack/spec/kernel`'s `MetadataBulkResultSchema` / + `MetadataBulkResult` are **unchanged** — only the bulk *register request* + pair moved. + +`dual-source-exports.baseline.json` shrinks by exactly these 3 rows (31 → 28, +#4535 C2). diff --git a/packages/spec/authorable-surface.json b/packages/spec/authorable-surface.json index 1822757c91..e6535c86f0 100644 --- a/packages/spec/authorable-surface.json +++ b/packages/spec/authorable-surface.json @@ -4639,9 +4639,6 @@ "kernel/MergeStrategyConfig:alwaysKeepCustom", "kernel/MergeStrategyConfig:autoResolveNonConflicting", "kernel/MergeStrategyConfig:defaultStrategy", - "kernel/MetadataBulkRegisterRequest:continueOnError", - "kernel/MetadataBulkRegisterRequest:items", - "kernel/MetadataBulkRegisterRequest:validate", "kernel/MetadataBulkResult:errors", "kernel/MetadataBulkResult:failed", "kernel/MetadataBulkResult:succeeded", @@ -4657,14 +4654,6 @@ "kernel/MetadataDiffItem:previousName", "kernel/MetadataDiffItem:summary", "kernel/MetadataDiffItem:type", - "kernel/MetadataEvent:actor", - "kernel/MetadataEvent:event", - "kernel/MetadataEvent:metadataType", - "kernel/MetadataEvent:name", - "kernel/MetadataEvent:namespace", - "kernel/MetadataEvent:packageId", - "kernel/MetadataEvent:payload", - "kernel/MetadataEvent:timestamp", "kernel/MetadataManagerConfig:cache", "kernel/MetadataManagerConfig:datasource", "kernel/MetadataManagerConfig:fallback", diff --git a/packages/spec/dual-source-exports.baseline.json b/packages/spec/dual-source-exports.baseline.json index 4658d64d2b..fde8e2ce41 100644 --- a/packages/spec/dual-source-exports.baseline.json +++ b/packages/spec/dual-source-exports.baseline.json @@ -15,9 +15,6 @@ "FieldMappingSchema — [./data (const)] ≠ [./integration (const)] ≠ [./shared (const)]", "HttpMethod — [./api, ./shared (type)] ≠ [./ui (type)]", "HttpRequest — [./shared (type)] ≠ [./ui (type)]", - "MetadataBulkRegisterRequestSchema — [./api (const)] ≠ [./kernel (const)]", - "MetadataEvent — [./api (type)] ≠ [./kernel (type)]", - "MetadataEventSchema — [./api (const)] ≠ [./kernel (const)]", "Notification — [./api (type)] ≠ [./ui (type)]", "NotificationConfig — [./system (type)] ≠ [./ui (type)]", "NotificationConfigSchema — [./system (const)] ≠ [./ui (const)]", diff --git a/packages/spec/json-schema.manifest.json b/packages/spec/json-schema.manifest.json index 3717c980ad..ba5434f476 100644 --- a/packages/spec/json-schema.manifest.json +++ b/packages/spec/json-schema.manifest.json @@ -966,14 +966,12 @@ "kernel/MergeConflict", "kernel/MergeResult", "kernel/MergeStrategyConfig", - "kernel/MetadataBulkRegisterRequest", "kernel/MetadataBulkResult", "kernel/MetadataCategoryEnum", "kernel/MetadataChangeOperation", "kernel/MetadataChangeType", "kernel/MetadataDependency", "kernel/MetadataDiffItem", - "kernel/MetadataEvent", "kernel/MetadataFallbackStrategy", "kernel/MetadataLock", "kernel/MetadataLockSource", diff --git a/packages/spec/src/api/events.test.ts b/packages/spec/src/api/events.test.ts new file mode 100644 index 0000000000..76624c65b0 --- /dev/null +++ b/packages/spec/src/api/events.test.ts @@ -0,0 +1,124 @@ +import { describe, it, expect } from 'vitest'; +import { + MetadataEventType, + DataEventType, + MetadataEventSchema, + DataEventSchema, +} from './events.zod'; + +// Coverage added with the v17 dual-source cleanup (#4587): ./api is now the +// SOLE owner of the bare names MetadataEvent(Schema). This vocabulary is the +// live realtime contract — `MetadataManager` publishes +// `metadata.{type}.{created|deleted}` events and the client SDK +// (`@objectstack/client` subscribeMetadata / `@objectstack/client-react`) +// subscribes against exactly these names. The kernel-side lifecycle envelope +// (`metadata.registered/…`) that used to share the names was removed — it had +// no producer and no consumer. + +describe('MetadataEventType', () => { + it('follows the metadata.{type}.{created|updated|deleted} pattern for every member', () => { + for (const value of MetadataEventType.options) { + expect(value).toMatch(/^metadata\.[a-z]+\.(created|updated|deleted)$/); + } + }); + + it('covers the created/updated/deleted triple for each covered metadata type', () => { + const byType = new Map(); + for (const value of MetadataEventType.options) { + const [, metadataType, action] = value.split('.'); + const actions = byType.get(metadataType) ?? []; + actions.push(action); + byType.set(metadataType, actions); + } + for (const [metadataType, actions] of byType) { + expect(actions, `actions of metadata.${metadataType}.*`).toEqual([ + 'created', + 'updated', + 'deleted', + ]); + } + }); + + it('includes the event names the client SDK subscribes to', () => { + // `RealtimeAPI.subscribeMetadata(type)` filters on exactly these three. + for (const name of [ + 'metadata.object.created', + 'metadata.object.updated', + 'metadata.object.deleted', + ]) { + expect(MetadataEventType.options).toContain(name); + } + }); +}); + +describe('MetadataEventSchema', () => { + const base = { + id: '4b4720e8-97c3-4a12-9b70-b70a3d2314a1', + type: 'metadata.object.created', + metadataType: 'object', + name: 'account', + timestamp: new Date().toISOString(), + }; + + it('validates a minimal realtime metadata event', () => { + const event = MetadataEventSchema.parse(base); + expect(event.type).toBe('metadata.object.created'); + expect(event.name).toBe('account'); + }); + + it('accepts the optional payload fields', () => { + const event = MetadataEventSchema.parse({ + ...base, + packageId: 'com.acme.crm', + definition: { label: 'Account' }, + userId: 'usr_1', + }); + expect(event.packageId).toBe('com.acme.crm'); + expect(event.userId).toBe('usr_1'); + }); + + it('rejects event types outside the vocabulary', () => { + expect(() => MetadataEventSchema.parse({ + ...base, + // The retired kernel-side lifecycle vocabulary must NOT parse here — + // it was never produced by anything and is not part of this contract. + type: 'metadata.registered', + })).toThrow(); + }); + + it('rejects a non-uuid id and a non-datetime timestamp', () => { + expect(() => MetadataEventSchema.parse({ ...base, id: 'evt-1' })).toThrow(); + expect(() => MetadataEventSchema.parse({ ...base, timestamp: 'yesterday' })).toThrow(); + }); +}); + +describe('DataEventSchema', () => { + it('validates a data record event', () => { + const event = DataEventSchema.parse({ + id: '4b4720e8-97c3-4a12-9b70-b70a3d2314a2', + type: 'data.record.updated', + object: 'account', + recordId: 'rec_1', + changes: { name: 'New Name' }, + timestamp: new Date().toISOString(), + }); + expect(event.object).toBe('account'); + expect(event.recordId).toBe('rec_1'); + }); + + it('rejects types outside the DataEventType vocabulary', () => { + expect(DataEventType.options).toEqual([ + 'data.record.created', + 'data.record.updated', + 'data.record.deleted', + 'data.field.changed', + ]); + expect(() => DataEventSchema.parse({ + id: '4b4720e8-97c3-4a12-9b70-b70a3d2314a3', + type: 'data.record.upserted', + object: 'account', + recordId: 'rec_1', + timestamp: new Date().toISOString(), + })).toThrow(); + }); +}); diff --git a/packages/spec/src/api/metadata.test.ts b/packages/spec/src/api/metadata.test.ts index 9dc2b50c4f..f207db427d 100644 --- a/packages/spec/src/api/metadata.test.ts +++ b/packages/spec/src/api/metadata.test.ts @@ -35,6 +35,7 @@ import { // Dependencies MetadataDependenciesResponseSchema, MetadataDependentsResponseSchema, + type MetadataBulkRegisterRequest, } from './metadata.zod'; // ========================================== @@ -469,6 +470,24 @@ describe('MetadataBulkRegisterRequestSchema', () => { expect(result.continueOnError).toBe(true); expect(result.validate).toBe(false); }); + + // v17 (#4587): `MetadataBulkRegisterRequest` moved here from ./kernel, + // which carried a dead near-duplicate of this schema (extra per-item + // `namespace` that no enforced write path reads). The exported type is the + // authoring-side shape (z.input): the defaulted flags stay optional, and a + // per-item `namespace` is NOT part of the contract. + it('exports the authoring-side MetadataBulkRegisterRequest type (#4587)', () => { + const minimal: MetadataBulkRegisterRequest = { + items: [{ type: 'object', name: 'account', data: { label: 'Account' } }], + }; + const parsed = MetadataBulkRegisterRequestSchema.parse(minimal); + expect(parsed.continueOnError).toBe(false); + expect(parsed.validate).toBe(true); + + type Item = MetadataBulkRegisterRequest['items'][number]; + const hasNamespace: 'namespace' extends keyof Item ? true : false = false; + expect(hasNamespace).toBe(false); + }); }); describe('MetadataBulkUnregisterRequestSchema', () => { diff --git a/packages/spec/src/api/metadata.zod.ts b/packages/spec/src/api/metadata.zod.ts index 5d6be167f4..d02bc390fc 100644 --- a/packages/spec/src/api/metadata.zod.ts +++ b/packages/spec/src/api/metadata.zod.ts @@ -353,6 +353,16 @@ export type MetadataNamesResponse = z.infer; export type MetadataExistsResponse = z.infer; export type MetadataDeleteResponse = z.infer; export type MetadataQueryResponse = z.infer; +/** + * Authoring-side shape of the bulk register request (`continueOnError` / + * `validate` stay optional — they carry defaults). + * + * v17 (#4587): this name moved here from `@objectstack/spec/kernel`, whose + * copy of the schema was a dead duplicate (its extra per-item `namespace` + * field matched no enforced write path). `./api` is the single owner of + * `MetadataBulkRegisterRequest(Schema)` now. + */ +export type MetadataBulkRegisterRequest = z.input; export type MetadataBulkResponse = z.infer; export type MetadataOverlayResponse = z.infer; export type MetadataEffectiveResponse = z.infer; diff --git a/packages/spec/src/kernel/metadata-plugin.test.ts b/packages/spec/src/kernel/metadata-plugin.test.ts index 94f8ea0e03..11bb625f51 100644 --- a/packages/spec/src/kernel/metadata-plugin.test.ts +++ b/packages/spec/src/kernel/metadata-plugin.test.ts @@ -4,11 +4,9 @@ import { MetadataTypeRegistryEntrySchema, MetadataQuerySchema, MetadataQueryResultSchema, - MetadataEventSchema, MetadataValidationResultSchema, MetadataPluginConfigSchema, MetadataPluginManifestSchema, - MetadataBulkRegisterRequestSchema, MetadataBulkResultSchema, MetadataDependencySchema, DEFAULT_METADATA_TYPE_REGISTRY, @@ -234,65 +232,27 @@ describe('MetadataPluginProtocol', () => { }); }); - describe('MetadataEventSchema', () => { - it('should validate metadata events', () => { - const events = [ - { event: 'metadata.registered', metadataType: 'object', name: 'account', timestamp: new Date().toISOString() }, - { event: 'metadata.updated', metadataType: 'view', name: 'account_list', timestamp: new Date().toISOString() }, - { event: 'metadata.unregistered', metadataType: 'flow', name: 'approval_flow', timestamp: new Date().toISOString() }, - ] as const; - - events.forEach(event => { - const validated = MetadataEventSchema.parse(event); - expect(validated.event).toBe(event.event); - expect(validated.name).toBe(event.name); - }); - }); - - it('should accept all event types', () => { - const eventTypes = [ - 'metadata.registered', 'metadata.updated', 'metadata.unregistered', - 'metadata.validated', 'metadata.deployed', - 'metadata.overlay.applied', 'metadata.overlay.removed', - 'metadata.imported', 'metadata.exported', - ] as const; - - eventTypes.forEach(event => { - expect(() => MetadataEventSchema.parse({ - event, - metadataType: 'object', - name: 'test', - timestamp: new Date().toISOString(), - })).not.toThrow(); - }); - }); - - it('should accept optional fields', () => { - const event = { - event: 'metadata.registered' as const, - metadataType: 'object' as const, - name: 'account', - namespace: 'crm', - packageId: 'com.acme.crm', - timestamp: new Date().toISOString(), - actor: 'admin@example.com', - payload: { version: '1.0.0' }, - }; - - const validated = MetadataEventSchema.parse(event); - expect(validated.namespace).toBe('crm'); - expect(validated.actor).toBe('admin@example.com'); - expect(validated.payload).toEqual({ version: '1.0.0' }); - }); - - it('should reject invalid event types', () => { - expect(() => MetadataEventSchema.parse({ - event: 'metadata.unknown', - metadataType: 'object', - name: 'test', - timestamp: new Date().toISOString(), - })).toThrow(); - }); + // v17 dual-source cleanup (#4587): the bare names MetadataEvent(Schema) / + // MetadataBulkRegisterRequest(Schema) now belong to @objectstack/spec/api + // alone (realtime metadata change feed / POST /api/meta/bulk/register + // contract). The copies this module carried were the #4411-style dead side: + // zero importers outside this test across framework/cloud/objectui, a + // lifecycle-event vocabulary (`metadata.registered/…`) nothing ever + // emitted, and a per-item `namespace` field no enforced write path reads. + // Pin: this module no longer declares the bare names. The pin is + // compile-time (typeof import is type-level only — no runtime barrel + // load): if either bare name is re-added here, the conditional type flips + // to `true` and the `false` assignment fails `tsc --noEmit`. + it('does not re-expose the bare MetadataEvent/MetadataBulkRegisterRequest names from ./kernel (#4587)', () => { + type MetadataPluginModule = typeof import('./metadata-plugin.zod'); + const hasEventSchema: 'MetadataEventSchema' extends keyof MetadataPluginModule + ? true + : false = false; + const hasBulkRegisterSchema: 'MetadataBulkRegisterRequestSchema' extends keyof MetadataPluginModule + ? true + : false = false; + expect(hasEventSchema).toBe(false); + expect(hasBulkRegisterSchema).toBe(false); }); describe('MetadataValidationResultSchema', () => { @@ -476,40 +436,6 @@ describe('MetadataPluginProtocol', () => { }); }); - describe('MetadataBulkRegisterRequestSchema', () => { - it('should validate a bulk register request', () => { - const request = { - items: [ - { type: 'object', name: 'account', data: { label: 'Account' } }, - { type: 'view', name: 'account_list', data: { label: 'Account List' } }, - ], - }; - - const result = MetadataBulkRegisterRequestSchema.parse(request); - expect(result.items).toHaveLength(2); - expect(result.continueOnError).toBe(false); - expect(result.validate).toBe(true); - }); - - it('should reject empty items array', () => { - expect(() => MetadataBulkRegisterRequestSchema.parse({ - items: [], - })).toThrow(); - }); - - it('should accept options', () => { - const request = { - items: [{ type: 'object', name: 'test', data: {} }], - continueOnError: true, - validate: false, - }; - - const result = MetadataBulkRegisterRequestSchema.parse(request); - expect(result.continueOnError).toBe(true); - expect(result.validate).toBe(false); - }); - }); - describe('MetadataBulkResultSchema', () => { it('should validate a successful bulk result', () => { const result = { total: 5, succeeded: 5, failed: 0 }; diff --git a/packages/spec/src/kernel/metadata-plugin.zod.ts b/packages/spec/src/kernel/metadata-plugin.zod.ts index 3934cef4f8..5003c9d8a7 100644 --- a/packages/spec/src/kernel/metadata-plugin.zod.ts +++ b/packages/spec/src/kernel/metadata-plugin.zod.ts @@ -351,51 +351,17 @@ export type MetadataQueryResult = z.infer; // ========================================== // Metadata Lifecycle Events // ========================================== - -/** - * Metadata Event Schema - * - * Events emitted by the metadata plugin when metadata changes. - * Enables reactive patterns across the platform (cache invalidation, - * UI refresh, dependency tracking, etc.). - */ -export const MetadataEventSchema = lazySchema(() => z.object({ - /** Event type */ - event: z.enum([ - 'metadata.registered', - 'metadata.updated', - 'metadata.unregistered', - 'metadata.validated', - 'metadata.deployed', - 'metadata.overlay.applied', - 'metadata.overlay.removed', - 'metadata.imported', - 'metadata.exported', - ]).describe('Event type'), - - /** Metadata type */ - metadataType: MetadataTypeSchema.describe('Metadata type'), - - /** Item name */ - name: z.string().describe('Metadata item name'), - - /** Namespace */ - namespace: z.string().optional().describe('Namespace'), - - /** Package ID (if package-managed) */ - packageId: z.string().optional().describe('Owning package ID'), - - /** Timestamp */ - timestamp: z.string().datetime().describe('Event timestamp'), - - /** Actor who caused the event */ - actor: z.string().optional().describe('User or system that triggered the event'), - - /** Additional event-specific payload */ - payload: z.record(z.string(), z.unknown()).optional().describe('Event-specific payload'), -})); - -export type MetadataEvent = z.infer; +// v17 dual-source cleanup (#4587): the `MetadataEvent(Schema)` pair that +// lived here (a `metadata.registered/…/exported` lifecycle-event envelope) +// was removed. It was the #4411-family dead copy: zero importers outside its +// own unit test across framework/cloud/objectui, and NOTHING ever emitted +// its event vocabulary. The bare names now belong to `@objectstack/spec/api` +// alone (`src/api/events.zod.ts`) — the realtime metadata change feed +// (`metadata.{type}.{created|updated|deleted}`) that `MetadataManager` +// publishes and the client SDK (`@objectstack/client`) subscribes to. +// Runtime *watch* events remain `MetadataWatchEvent` in +// `@objectstack/spec/system`; repository change-log events are +// `@objectstack/metadata-core`'s own `MetadataEvent` (ADR-0008). // ========================================== // Metadata Validation @@ -783,27 +749,19 @@ export const DEFAULT_METADATA_TYPE_REGISTRY: MetadataTypeRegistryEntry[] = [ // ========================================== // Bulk Operation Types // ========================================== - -/** - * Bulk Register Request - */ -export const MetadataBulkRegisterRequestSchema = lazySchema(() => z.object({ - /** Items to register */ - items: z.array(z.object({ - type: z.string().describe('Metadata type'), - name: z.string().describe('Item name'), - data: z.record(z.string(), z.unknown()).describe('Metadata payload'), - namespace: z.string().optional().describe('Namespace'), - })).min(1).describe('Items to register'), - - /** Continue on individual item failure */ - continueOnError: z.boolean().default(false).describe('Continue if individual item fails'), - - /** Validate items before registering */ - validate: z.boolean().default(true).describe('Validate before register'), -})); - -export type MetadataBulkRegisterRequest = z.input; +// v17 dual-source cleanup (#4587): `MetadataBulkRegisterRequest(Schema)` +// was removed from this module. It was a dead copy of the REST request +// contract — zero importers outside its own unit test across +// framework/cloud/objectui — and it diverged from the enforced write path: +// its per-item `namespace` field exists nowhere in +// `IMetadataService.bulkRegister` (contracts) or +// `MetadataManager.bulkRegister`, and `namespace` is deprecated repo-wide +// (Prime Directive #6). The bare names now belong to +// `@objectstack/spec/api` alone (`src/api/metadata.zod.ts` — the +// POST /api/meta/bulk/register contract, whose item shape +// `{type, name, data}` matches what the runtime actually accepts). +// `MetadataBulkResultSchema` below stays: it is the live result type +// consumed by `@objectstack/metadata` and re-exported by ./api responses. /** * Bulk Operation Result From 0281703c8fdfe2381fa8850bb6403b2edcda7747 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 2 Aug 2026 09:27:04 +0000 Subject: [PATCH 2/3] chore(spec): regenerate api-surface + reference docs for #4587 (check:generated --fix, 2 proved stale) api-surface.json: ./kernel loses MetadataEvent(type)/MetadataEventSchema and MetadataBulkRegisterRequest(type)/MetadataBulkRegisterRequestSchema; ./api gains the MetadataBulkRegisterRequest type alias beside its schema. Reference docs: the api/metadata-plugin.mdx page (which documented the removed kernel pair under the api section and advertised a then-nonexistent ./api type import) is no longer emitted; api/events.mdx now documents MetadataEvent, api/metadata.mdx documents MetadataBulkRegisterRequest, and kernel/metadata-plugin.mdx drops the removed schemas. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL --- content/docs/references/api/events.mdx | 22 +++++++- content/docs/references/api/meta.json | 1 - .../docs/references/api/metadata-plugin.mdx | 50 ------------------- content/docs/references/api/metadata.mdx | 17 ++++++- .../references/kernel/metadata-plugin.mdx | 37 ++------------ packages/spec/api-surface.json | 5 +- 6 files changed, 39 insertions(+), 93 deletions(-) delete mode 100644 content/docs/references/api/metadata-plugin.mdx diff --git a/content/docs/references/api/events.mdx b/content/docs/references/api/events.mdx index 56d3e9879a..8419789e9c 100644 --- a/content/docs/references/api/events.mdx +++ b/content/docs/references/api/events.mdx @@ -26,8 +26,8 @@ Examples: ## TypeScript Usage ```typescript -import { DataEvent, DataEventType, MetadataEventType } from '@objectstack/spec/api'; -import type { DataEvent, DataEventType, MetadataEventType } from '@objectstack/spec/api'; +import { DataEvent, DataEventType, MetadataEvent, MetadataEventType } from '@objectstack/spec/api'; +import type { DataEvent, DataEventType, MetadataEvent, MetadataEventType } from '@objectstack/spec/api'; // Validate data const result = DataEvent.parse(data); @@ -64,6 +64,24 @@ const result = DataEvent.parse(data); * `data.field.changed` +--- + +## MetadataEvent + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **id** | `string` | ✅ | Unique event identifier | +| **type** | `Enum<'metadata.object.created' \| 'metadata.object.updated' \| 'metadata.object.deleted' \| 'metadata.field.created' \| 'metadata.field.updated' \| 'metadata.field.deleted' \| 'metadata.view.created' \| 'metadata.view.updated' \| 'metadata.view.deleted' \| 'metadata.app.created' \| 'metadata.app.updated' \| 'metadata.app.deleted' \| 'metadata.agent.created' \| 'metadata.agent.updated' \| 'metadata.agent.deleted' \| 'metadata.tool.created' \| 'metadata.tool.updated' \| 'metadata.tool.deleted' \| 'metadata.flow.created' \| 'metadata.flow.updated' \| 'metadata.flow.deleted' \| 'metadata.action.created' \| 'metadata.action.updated' \| 'metadata.action.deleted' \| 'metadata.workflow.created' \| 'metadata.workflow.updated' \| 'metadata.workflow.deleted' \| 'metadata.dashboard.created' \| 'metadata.dashboard.updated' \| 'metadata.dashboard.deleted' \| 'metadata.report.created' \| 'metadata.report.updated' \| 'metadata.report.deleted' \| 'metadata.role.created' \| 'metadata.role.updated' \| 'metadata.role.deleted' \| 'metadata.permission.created' \| 'metadata.permission.updated' \| 'metadata.permission.deleted'>` | ✅ | Event type | +| **metadataType** | `string` | ✅ | Metadata type (object, view, agent, etc.) | +| **name** | `string` | ✅ | Metadata item name | +| **packageId** | `string` | optional | Package ID | +| **definition** | `any` | optional | Full definition (create/update only) | +| **userId** | `string` | optional | User who triggered the event | +| **timestamp** | `string` | ✅ | Event timestamp | + + --- ## MetadataEventType diff --git a/content/docs/references/api/meta.json b/content/docs/references/api/meta.json index 13b3509ecb..f689bb447a 100644 --- a/content/docs/references/api/meta.json +++ b/content/docs/references/api/meta.json @@ -32,7 +32,6 @@ "export", "identity", "metadata", - "metadata-plugin", "notification", "package-api", "package-registry", diff --git a/content/docs/references/api/metadata-plugin.mdx b/content/docs/references/api/metadata-plugin.mdx deleted file mode 100644 index 75edc8ead2..0000000000 --- a/content/docs/references/api/metadata-plugin.mdx +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Metadata Plugin -description: Metadata Plugin protocol schemas ---- - -{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} - -## TypeScript Usage - -```typescript -import { MetadataBulkRegisterRequest, MetadataEvent } from '@objectstack/spec/api'; -import type { MetadataBulkRegisterRequest, MetadataEvent } from '@objectstack/spec/api'; - -// Validate data -const result = MetadataBulkRegisterRequest.parse(data); -``` - ---- - -## MetadataBulkRegisterRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **items** | `{ type: string; name: string; data: Record }[]` | ✅ | Items to register | -| **continueOnError** | `boolean` | ✅ | Continue on individual failure | -| **validate** | `boolean` | ✅ | Validate before registering | - - ---- - -## MetadataEvent - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Unique event identifier | -| **type** | `Enum<'metadata.object.created' \| 'metadata.object.updated' \| 'metadata.object.deleted' \| 'metadata.field.created' \| 'metadata.field.updated' \| 'metadata.field.deleted' \| 'metadata.view.created' \| 'metadata.view.updated' \| 'metadata.view.deleted' \| 'metadata.app.created' \| 'metadata.app.updated' \| 'metadata.app.deleted' \| 'metadata.agent.created' \| 'metadata.agent.updated' \| 'metadata.agent.deleted' \| 'metadata.tool.created' \| 'metadata.tool.updated' \| 'metadata.tool.deleted' \| 'metadata.flow.created' \| 'metadata.flow.updated' \| 'metadata.flow.deleted' \| 'metadata.action.created' \| 'metadata.action.updated' \| 'metadata.action.deleted' \| 'metadata.workflow.created' \| 'metadata.workflow.updated' \| 'metadata.workflow.deleted' \| 'metadata.dashboard.created' \| 'metadata.dashboard.updated' \| 'metadata.dashboard.deleted' \| 'metadata.report.created' \| 'metadata.report.updated' \| 'metadata.report.deleted' \| 'metadata.role.created' \| 'metadata.role.updated' \| 'metadata.role.deleted' \| 'metadata.permission.created' \| 'metadata.permission.updated' \| 'metadata.permission.deleted'>` | ✅ | Event type | -| **metadataType** | `string` | ✅ | Metadata type (object, view, agent, etc.) | -| **name** | `string` | ✅ | Metadata item name | -| **packageId** | `string` | optional | Package ID | -| **definition** | `any` | optional | Full definition (create/update only) | -| **userId** | `string` | optional | User who triggered the event | -| **timestamp** | `string` | ✅ | Event timestamp | - - ---- - diff --git a/content/docs/references/api/metadata.mdx b/content/docs/references/api/metadata.mdx index 21182b5916..e51cc34e87 100644 --- a/content/docs/references/api/metadata.mdx +++ b/content/docs/references/api/metadata.mdx @@ -50,8 +50,8 @@ the entire platform, including Hono, Next.js, and NestJS adapters. ## TypeScript Usage ```typescript -import { AppDefinitionResponse, ConceptListResponse, MetadataBulkResponse, MetadataBulkUnregisterRequest, MetadataDeleteResponse, MetadataDependenciesResponse, MetadataDependentsResponse, MetadataEffectiveResponse, MetadataExistsResponse, MetadataExportRequest, MetadataExportResponse, MetadataImportRequest, MetadataImportResponse, MetadataItemResponse, MetadataListResponse, MetadataNamesResponse, MetadataOverlayResponse, MetadataOverlaySaveRequest, MetadataQueryRequest, MetadataQueryResponse, MetadataRegisterRequest, MetadataTypeInfoResponse, MetadataTypesResponse, MetadataValidateRequest, MetadataValidateResponse, ObjectDefinitionResponse } from '@objectstack/spec/api'; -import type { AppDefinitionResponse, ConceptListResponse, MetadataBulkResponse, MetadataBulkUnregisterRequest, MetadataDeleteResponse, MetadataDependenciesResponse, MetadataDependentsResponse, MetadataEffectiveResponse, MetadataExistsResponse, MetadataExportRequest, MetadataExportResponse, MetadataImportRequest, MetadataImportResponse, MetadataItemResponse, MetadataListResponse, MetadataNamesResponse, MetadataOverlayResponse, MetadataOverlaySaveRequest, MetadataQueryRequest, MetadataQueryResponse, MetadataRegisterRequest, MetadataTypeInfoResponse, MetadataTypesResponse, MetadataValidateRequest, MetadataValidateResponse, ObjectDefinitionResponse } from '@objectstack/spec/api'; +import { AppDefinitionResponse, ConceptListResponse, MetadataBulkRegisterRequest, MetadataBulkResponse, MetadataBulkUnregisterRequest, MetadataDeleteResponse, MetadataDependenciesResponse, MetadataDependentsResponse, MetadataEffectiveResponse, MetadataExistsResponse, MetadataExportRequest, MetadataExportResponse, MetadataImportRequest, MetadataImportResponse, MetadataItemResponse, MetadataListResponse, MetadataNamesResponse, MetadataOverlayResponse, MetadataOverlaySaveRequest, MetadataQueryRequest, MetadataQueryResponse, MetadataRegisterRequest, MetadataTypeInfoResponse, MetadataTypesResponse, MetadataValidateRequest, MetadataValidateResponse, ObjectDefinitionResponse } from '@objectstack/spec/api'; +import type { AppDefinitionResponse, ConceptListResponse, MetadataBulkRegisterRequest, MetadataBulkResponse, MetadataBulkUnregisterRequest, MetadataDeleteResponse, MetadataDependenciesResponse, MetadataDependentsResponse, MetadataEffectiveResponse, MetadataExistsResponse, MetadataExportRequest, MetadataExportResponse, MetadataImportRequest, MetadataImportResponse, MetadataItemResponse, MetadataListResponse, MetadataNamesResponse, MetadataOverlayResponse, MetadataOverlaySaveRequest, MetadataQueryRequest, MetadataQueryResponse, MetadataRegisterRequest, MetadataTypeInfoResponse, MetadataTypesResponse, MetadataValidateRequest, MetadataValidateResponse, ObjectDefinitionResponse } from '@objectstack/spec/api'; // Validate data const result = AppDefinitionResponse.parse(data); @@ -85,6 +85,19 @@ const result = AppDefinitionResponse.parse(data); | **data** | `{ name: string; label: string; icon?: string; description?: string }[]` | ✅ | List of available concepts (Objects, Apps, Flows) | +--- + +## MetadataBulkRegisterRequest + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **items** | `{ type: string; name: string; data: Record }[]` | ✅ | Items to register | +| **continueOnError** | `boolean` | ✅ | Continue on individual failure | +| **validate** | `boolean` | ✅ | Validate before registering | + + --- ## MetadataBulkResponse diff --git a/content/docs/references/kernel/metadata-plugin.mdx b/content/docs/references/kernel/metadata-plugin.mdx index b7604e5ea9..fee8491b9b 100644 --- a/content/docs/references/kernel/metadata-plugin.mdx +++ b/content/docs/references/kernel/metadata-plugin.mdx @@ -72,26 +72,13 @@ cohesive plugin that "takes over" the entire platform's metadata management: ## TypeScript Usage ```typescript -import { MetadataBulkRegisterRequest, MetadataBulkResult, MetadataDependency, MetadataEvent, MetadataPluginConfig, MetadataPluginManifest, MetadataQuery, MetadataQueryResult, MetadataType, MetadataTypeRegistryEntry, MetadataValidationResult } from '@objectstack/spec/kernel'; -import type { MetadataBulkRegisterRequest, MetadataBulkResult, MetadataDependency, MetadataEvent, MetadataPluginConfig, MetadataPluginManifest, MetadataQuery, MetadataQueryResult, MetadataType, MetadataTypeRegistryEntry, MetadataValidationResult } from '@objectstack/spec/kernel'; +import { MetadataBulkResult, MetadataDependency, MetadataPluginConfig, MetadataPluginManifest, MetadataQuery, MetadataQueryResult, MetadataType, MetadataTypeRegistryEntry, MetadataValidationResult } from '@objectstack/spec/kernel'; +import type { MetadataBulkResult, MetadataDependency, MetadataPluginConfig, MetadataPluginManifest, MetadataQuery, MetadataQueryResult, MetadataType, MetadataTypeRegistryEntry, MetadataValidationResult } from '@objectstack/spec/kernel'; // Validate data -const result = MetadataBulkRegisterRequest.parse(data); +const result = MetadataBulkResult.parse(data); ``` ---- - -## MetadataBulkRegisterRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **items** | `{ type: string; name: string; data: Record; namespace?: string }[]` | ✅ | Items to register | -| **continueOnError** | `boolean` | ✅ | Continue if individual item fails | -| **validate** | `boolean` | ✅ | Validate before register | - - --- ## MetadataBulkResult @@ -121,24 +108,6 @@ const result = MetadataBulkRegisterRequest.parse(data); | **kind** | `Enum<'reference' \| 'extends' \| 'includes' \| 'triggers'>` | ✅ | How the dependency is formed | ---- - -## MetadataEvent - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **event** | `Enum<'metadata.registered' \| 'metadata.updated' \| 'metadata.unregistered' \| 'metadata.validated' \| 'metadata.deployed' \| 'metadata.overlay.applied' \| 'metadata.overlay.removed' \| 'metadata.imported' \| 'metadata.exported'>` | ✅ | Event type | -| **metadataType** | `Enum<'object' \| 'field' \| 'hook' \| 'seed' \| 'mapping' \| 'view' \| 'page' \| 'dashboard' \| 'app' \| 'action' \| 'report' \| 'dataset' \| 'flow' \| 'job' \| 'datasource' \| 'external_catalog' \| 'translation' \| 'email_template' \| 'doc' \| 'book' \| 'permission' \| 'position' \| 'agent' \| 'tool' \| 'skill'>` | ✅ | Metadata type | -| **name** | `string` | ✅ | Metadata item name | -| **namespace** | `string` | optional | Namespace | -| **packageId** | `string` | optional | Owning package ID | -| **timestamp** | `string` | ✅ | Event timestamp | -| **actor** | `string` | optional | User or system that triggered the event | -| **payload** | `Record` | optional | Event-specific payload | - - --- ## MetadataPluginConfig diff --git a/packages/spec/api-surface.json b/packages/spec/api-surface.json index 83dc5ec0ff..2444ed6a92 100644 --- a/packages/spec/api-surface.json +++ b/packages/spec/api-surface.json @@ -1611,8 +1611,6 @@ "MergeResultSchema (const)", "MergeStrategyConfig (type)", "MergeStrategyConfigSchema (const)", - "MetadataBulkRegisterRequest (type)", - "MetadataBulkRegisterRequestSchema (const)", "MetadataBulkResult (type)", "MetadataBulkResultSchema (const)", "MetadataCategory (type)", @@ -1627,8 +1625,6 @@ "MetadataDependencySchema (const)", "MetadataDiffItem (type)", "MetadataDiffItemSchema (const)", - "MetadataEvent (type)", - "MetadataEventSchema (const)", "MetadataFallbackStrategy (type)", "MetadataFallbackStrategySchema (const)", "MetadataLock (type)", @@ -2846,6 +2842,7 @@ "MarkNotificationsReadRequestSchema (const)", "MarkNotificationsReadResponse (type)", "MarkNotificationsReadResponseSchema (const)", + "MetadataBulkRegisterRequest (type)", "MetadataBulkRegisterRequestSchema (const)", "MetadataBulkResponse (type)", "MetadataBulkResponseSchema (const)", From 65d5dc8f7a39d8c122083d90dc371be4a497e4e9 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 2 Aug 2026 10:02:17 +0000 Subject: [PATCH 3/3] chore(spec): regenerate reference docs after merging main's import-surface gate (#4595) The merge brought in build-docs' new import-surface ratchet. This PR's MetadataBulkRegisterRequest type alias on ./api closes the gap the fresh baseline had accepted, so its line is deleted (shrink-only ratchet). --- content/docs/references/api/events.mdx | 22 +++++++- .../docs/references/api/metadata-plugin.mdx | 50 ------------------- content/docs/references/api/metadata.mdx | 17 ++++++- .../references/kernel/metadata-plugin.mdx | 37 ++------------ .../spec/docs-import-surface.baseline.json | 1 - 5 files changed, 38 insertions(+), 89 deletions(-) delete mode 100644 content/docs/references/api/metadata-plugin.mdx diff --git a/content/docs/references/api/events.mdx b/content/docs/references/api/events.mdx index 4e53260c7d..6b27f61acc 100644 --- a/content/docs/references/api/events.mdx +++ b/content/docs/references/api/events.mdx @@ -26,8 +26,8 @@ Examples: ## TypeScript Usage ```typescript -import { DataEventSchema, DataEventType, MetadataEventType } from '@objectstack/spec/api'; -import type { DataEvent, DataEventType, MetadataEventType } from '@objectstack/spec/api'; +import { DataEventSchema, DataEventType, MetadataEventSchema, MetadataEventType } from '@objectstack/spec/api'; +import type { DataEvent, DataEventType, MetadataEvent, MetadataEventType } from '@objectstack/spec/api'; // Validate data const result = DataEventSchema.parse(data); @@ -64,6 +64,24 @@ const result = DataEventSchema.parse(data); * `data.field.changed` +--- + +## MetadataEvent + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **id** | `string` | ✅ | Unique event identifier | +| **type** | `Enum<'metadata.object.created' \| 'metadata.object.updated' \| 'metadata.object.deleted' \| 'metadata.field.created' \| 'metadata.field.updated' \| 'metadata.field.deleted' \| 'metadata.view.created' \| 'metadata.view.updated' \| 'metadata.view.deleted' \| 'metadata.app.created' \| 'metadata.app.updated' \| 'metadata.app.deleted' \| 'metadata.agent.created' \| 'metadata.agent.updated' \| 'metadata.agent.deleted' \| 'metadata.tool.created' \| 'metadata.tool.updated' \| 'metadata.tool.deleted' \| 'metadata.flow.created' \| 'metadata.flow.updated' \| 'metadata.flow.deleted' \| 'metadata.action.created' \| 'metadata.action.updated' \| 'metadata.action.deleted' \| 'metadata.workflow.created' \| 'metadata.workflow.updated' \| 'metadata.workflow.deleted' \| 'metadata.dashboard.created' \| 'metadata.dashboard.updated' \| 'metadata.dashboard.deleted' \| 'metadata.report.created' \| 'metadata.report.updated' \| 'metadata.report.deleted' \| 'metadata.role.created' \| 'metadata.role.updated' \| 'metadata.role.deleted' \| 'metadata.permission.created' \| 'metadata.permission.updated' \| 'metadata.permission.deleted'>` | ✅ | Event type | +| **metadataType** | `string` | ✅ | Metadata type (object, view, agent, etc.) | +| **name** | `string` | ✅ | Metadata item name | +| **packageId** | `string` | optional | Package ID | +| **definition** | `any` | optional | Full definition (create/update only) | +| **userId** | `string` | optional | User who triggered the event | +| **timestamp** | `string` | ✅ | Event timestamp | + + --- ## MetadataEventType diff --git a/content/docs/references/api/metadata-plugin.mdx b/content/docs/references/api/metadata-plugin.mdx deleted file mode 100644 index 51f86433f1..0000000000 --- a/content/docs/references/api/metadata-plugin.mdx +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Metadata Plugin -description: Metadata Plugin protocol schemas ---- - -{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} - -## TypeScript Usage - -```typescript -import { MetadataBulkRegisterRequestSchema, MetadataEventSchema } from '@objectstack/spec/api'; -import type { MetadataEvent } from '@objectstack/spec/api'; - -// Validate data -const result = MetadataBulkRegisterRequestSchema.parse(data); -``` - ---- - -## MetadataBulkRegisterRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **items** | `{ type: string; name: string; data: Record }[]` | ✅ | Items to register | -| **continueOnError** | `boolean` | ✅ | Continue on individual failure | -| **validate** | `boolean` | ✅ | Validate before registering | - - ---- - -## MetadataEvent - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Unique event identifier | -| **type** | `Enum<'metadata.object.created' \| 'metadata.object.updated' \| 'metadata.object.deleted' \| 'metadata.field.created' \| 'metadata.field.updated' \| 'metadata.field.deleted' \| 'metadata.view.created' \| 'metadata.view.updated' \| 'metadata.view.deleted' \| 'metadata.app.created' \| 'metadata.app.updated' \| 'metadata.app.deleted' \| 'metadata.agent.created' \| 'metadata.agent.updated' \| 'metadata.agent.deleted' \| 'metadata.tool.created' \| 'metadata.tool.updated' \| 'metadata.tool.deleted' \| 'metadata.flow.created' \| 'metadata.flow.updated' \| 'metadata.flow.deleted' \| 'metadata.action.created' \| 'metadata.action.updated' \| 'metadata.action.deleted' \| 'metadata.workflow.created' \| 'metadata.workflow.updated' \| 'metadata.workflow.deleted' \| 'metadata.dashboard.created' \| 'metadata.dashboard.updated' \| 'metadata.dashboard.deleted' \| 'metadata.report.created' \| 'metadata.report.updated' \| 'metadata.report.deleted' \| 'metadata.role.created' \| 'metadata.role.updated' \| 'metadata.role.deleted' \| 'metadata.permission.created' \| 'metadata.permission.updated' \| 'metadata.permission.deleted'>` | ✅ | Event type | -| **metadataType** | `string` | ✅ | Metadata type (object, view, agent, etc.) | -| **name** | `string` | ✅ | Metadata item name | -| **packageId** | `string` | optional | Package ID | -| **definition** | `any` | optional | Full definition (create/update only) | -| **userId** | `string` | optional | User who triggered the event | -| **timestamp** | `string` | ✅ | Event timestamp | - - ---- - diff --git a/content/docs/references/api/metadata.mdx b/content/docs/references/api/metadata.mdx index 99cad980d5..3bf38641bb 100644 --- a/content/docs/references/api/metadata.mdx +++ b/content/docs/references/api/metadata.mdx @@ -50,8 +50,8 @@ the entire platform, including Hono, Next.js, and NestJS adapters. ## TypeScript Usage ```typescript -import { AppDefinitionResponseSchema, ConceptListResponseSchema, MetadataBulkResponseSchema, MetadataBulkUnregisterRequestSchema, MetadataDeleteResponseSchema, MetadataDependenciesResponseSchema, MetadataDependentsResponseSchema, MetadataEffectiveResponseSchema, MetadataExistsResponseSchema, MetadataExportRequestSchema, MetadataExportResponseSchema, MetadataImportRequestSchema, MetadataImportResponseSchema, MetadataItemResponseSchema, MetadataListResponseSchema, MetadataNamesResponseSchema, MetadataOverlayResponseSchema, MetadataOverlaySaveRequestSchema, MetadataQueryRequestSchema, MetadataQueryResponseSchema, MetadataRegisterRequestSchema, MetadataTypeInfoResponseSchema, MetadataTypesResponseSchema, MetadataValidateRequestSchema, MetadataValidateResponseSchema, ObjectDefinitionResponseSchema } from '@objectstack/spec/api'; -import type { AppDefinitionResponse, ConceptListResponse, MetadataBulkResponse, MetadataDeleteResponse, MetadataDependenciesResponse, MetadataDependentsResponse, MetadataEffectiveResponse, MetadataExistsResponse, MetadataExportResponse, MetadataImportResponse, MetadataItemResponse, MetadataListResponse, MetadataNamesResponse, MetadataOverlayResponse, MetadataQueryResponse, MetadataRegisterRequest, MetadataTypeInfoResponse, MetadataTypesResponse, MetadataValidateResponse, ObjectDefinitionResponse } from '@objectstack/spec/api'; +import { AppDefinitionResponseSchema, ConceptListResponseSchema, MetadataBulkRegisterRequestSchema, MetadataBulkResponseSchema, MetadataBulkUnregisterRequestSchema, MetadataDeleteResponseSchema, MetadataDependenciesResponseSchema, MetadataDependentsResponseSchema, MetadataEffectiveResponseSchema, MetadataExistsResponseSchema, MetadataExportRequestSchema, MetadataExportResponseSchema, MetadataImportRequestSchema, MetadataImportResponseSchema, MetadataItemResponseSchema, MetadataListResponseSchema, MetadataNamesResponseSchema, MetadataOverlayResponseSchema, MetadataOverlaySaveRequestSchema, MetadataQueryRequestSchema, MetadataQueryResponseSchema, MetadataRegisterRequestSchema, MetadataTypeInfoResponseSchema, MetadataTypesResponseSchema, MetadataValidateRequestSchema, MetadataValidateResponseSchema, ObjectDefinitionResponseSchema } from '@objectstack/spec/api'; +import type { AppDefinitionResponse, ConceptListResponse, MetadataBulkRegisterRequest, MetadataBulkResponse, MetadataDeleteResponse, MetadataDependenciesResponse, MetadataDependentsResponse, MetadataEffectiveResponse, MetadataExistsResponse, MetadataExportResponse, MetadataImportResponse, MetadataItemResponse, MetadataListResponse, MetadataNamesResponse, MetadataOverlayResponse, MetadataQueryResponse, MetadataRegisterRequest, MetadataTypeInfoResponse, MetadataTypesResponse, MetadataValidateResponse, ObjectDefinitionResponse } from '@objectstack/spec/api'; // Validate data const result = AppDefinitionResponseSchema.parse(data); @@ -85,6 +85,19 @@ const result = AppDefinitionResponseSchema.parse(data); | **data** | `{ name: string; label: string; icon?: string; description?: string }[]` | ✅ | List of available concepts (Objects, Apps, Flows) | +--- + +## MetadataBulkRegisterRequest + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **items** | `{ type: string; name: string; data: Record }[]` | ✅ | Items to register | +| **continueOnError** | `boolean` | ✅ | Continue on individual failure | +| **validate** | `boolean` | ✅ | Validate before registering | + + --- ## MetadataBulkResponse diff --git a/content/docs/references/kernel/metadata-plugin.mdx b/content/docs/references/kernel/metadata-plugin.mdx index 2e2f0e176b..1852b6d866 100644 --- a/content/docs/references/kernel/metadata-plugin.mdx +++ b/content/docs/references/kernel/metadata-plugin.mdx @@ -72,26 +72,13 @@ cohesive plugin that "takes over" the entire platform's metadata management: ## TypeScript Usage ```typescript -import { MetadataBulkRegisterRequestSchema, MetadataBulkResultSchema, MetadataDependencySchema, MetadataEventSchema, MetadataPluginConfigSchema, MetadataPluginManifestSchema, MetadataQuerySchema, MetadataQueryResultSchema, MetadataTypeSchema, MetadataTypeRegistryEntrySchema, MetadataValidationResultSchema } from '@objectstack/spec/kernel'; -import type { MetadataBulkRegisterRequest, MetadataBulkResult, MetadataDependency, MetadataEvent, MetadataPluginConfig, MetadataPluginManifest, MetadataQuery, MetadataQueryResult, MetadataType, MetadataTypeRegistryEntry, MetadataValidationResult } from '@objectstack/spec/kernel'; +import { MetadataBulkResultSchema, MetadataDependencySchema, MetadataPluginConfigSchema, MetadataPluginManifestSchema, MetadataQuerySchema, MetadataQueryResultSchema, MetadataTypeSchema, MetadataTypeRegistryEntrySchema, MetadataValidationResultSchema } from '@objectstack/spec/kernel'; +import type { MetadataBulkResult, MetadataDependency, MetadataPluginConfig, MetadataPluginManifest, MetadataQuery, MetadataQueryResult, MetadataType, MetadataTypeRegistryEntry, MetadataValidationResult } from '@objectstack/spec/kernel'; // Validate data -const result = MetadataBulkRegisterRequestSchema.parse(data); +const result = MetadataBulkResultSchema.parse(data); ``` ---- - -## MetadataBulkRegisterRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **items** | `{ type: string; name: string; data: Record; namespace?: string }[]` | ✅ | Items to register | -| **continueOnError** | `boolean` | ✅ | Continue if individual item fails | -| **validate** | `boolean` | ✅ | Validate before register | - - --- ## MetadataBulkResult @@ -121,24 +108,6 @@ const result = MetadataBulkRegisterRequestSchema.parse(data); | **kind** | `Enum<'reference' \| 'extends' \| 'includes' \| 'triggers'>` | ✅ | How the dependency is formed | ---- - -## MetadataEvent - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **event** | `Enum<'metadata.registered' \| 'metadata.updated' \| 'metadata.unregistered' \| 'metadata.validated' \| 'metadata.deployed' \| 'metadata.overlay.applied' \| 'metadata.overlay.removed' \| 'metadata.imported' \| 'metadata.exported'>` | ✅ | Event type | -| **metadataType** | `Enum<'object' \| 'field' \| 'hook' \| 'seed' \| 'mapping' \| 'view' \| 'page' \| 'dashboard' \| 'app' \| 'action' \| 'report' \| 'dataset' \| 'flow' \| 'job' \| 'datasource' \| 'external_catalog' \| 'translation' \| 'email_template' \| 'doc' \| 'book' \| 'permission' \| 'position' \| 'agent' \| 'tool' \| 'skill'>` | ✅ | Metadata type | -| **name** | `string` | ✅ | Metadata item name | -| **namespace** | `string` | optional | Namespace | -| **packageId** | `string` | optional | Owning package ID | -| **timestamp** | `string` | ✅ | Event timestamp | -| **actor** | `string` | optional | User or system that triggered the event | -| **payload** | `Record` | optional | Event-specific payload | - - --- ## MetadataPluginConfig diff --git a/packages/spec/docs-import-surface.baseline.json b/packages/spec/docs-import-surface.baseline.json index 2bab818b39..b74009abe4 100644 --- a/packages/spec/docs-import-surface.baseline.json +++ b/packages/spec/docs-import-surface.baseline.json @@ -11,7 +11,6 @@ "api/Discovery — no type export", "api/GetAnalyticsMetaRequest — no type export", "api/HttpFindQueryParams — no type export", - "api/MetadataBulkRegisterRequest — no type export", "api/MetadataBulkUnregisterRequest — no type export", "api/MetadataExportRequest — no type export", "api/MetadataImportRequest — no type export",