diff --git a/.changeset/config.json b/.changeset/config.json index a970114509..f34c2fa1d9 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -21,6 +21,7 @@ "@objectstack/metadata-core", "@objectstack/metadata-fs", "@objectstack/objectql", + "@objectstack/metadata-protocol", "@objectstack/observability", "@objectstack/formula", "@objectstack/lint", diff --git a/.changeset/extract-metadata-protocol.md b/.changeset/extract-metadata-protocol.md new file mode 100644 index 0000000000..97cc7e0ebd --- /dev/null +++ b/.changeset/extract-metadata-protocol.md @@ -0,0 +1,16 @@ +--- +'@objectstack/objectql': minor +'@objectstack/metadata-protocol': minor +--- + +Extract metadata management into `@objectstack/metadata-protocol` (ADR-0076) + +`protocol.ts` (the `ObjectStackProtocol` implementation — sys_metadata CRUD, draft/publish, locks, package ownership, diagnostics) plus its `sys-metadata-repository`, `metadata-diagnostics`, `seed-loader`, and `build-probes` helpers were metadata-domain code that lived inside `@objectstack/objectql` for historical reasons. They now live in a dedicated **`@objectstack/metadata-protocol`** package. + +The protocol no longer depends on the concrete `ObjectQL` class — it is typed against an injected `MetadataHostEngine` interface (the engine is still injected at runtime). Dependency direction is now one-way (`objectql → metadata-protocol`); there is no cycle. + +**Non-breaking**: `@objectstack/objectql` re-exports every previously public symbol (`ObjectStackProtocolImplementation`, `SysMetadataRepository`, `SysMetadataEngine`, `SeedLoaderService`, `runBuildProbes`, …), so existing imports keep working. + +This is Step 1 of ADR-0076. A later step turns the protocol into a capability plugin so `objectql` itself stops depending on it (making the engine lean by construction). + +Also adds a lean **`@objectstack/objectql/core`** entry — the engine/registry/hooks/validation surface only, with no kernel plugin or metadata protocol — so a thin embedder can import just the engine and never pull `@objectstack/metadata-protocol` into its bundle. A boundary ratchet test guards the entry. diff --git a/packages/metadata-protocol/README.md b/packages/metadata-protocol/README.md new file mode 100644 index 0000000000..5715bc028b --- /dev/null +++ b/packages/metadata-protocol/README.md @@ -0,0 +1,7 @@ +# @objectstack/metadata-protocol + +The ObjectStack metadata-management protocol, extracted from `@objectstack/objectql` per [ADR-0076](../../docs/adr/0076-objectql-core-tiering.md). + +Implements `ObjectStackProtocol`: `sys_metadata` CRUD, draft/publish lifecycle, write locks, package ownership/installation, metadata diagnostics, seed application, and build probes. + +It uses a data engine purely as storage + schema registry, injected at runtime via the `MetadataHostEngine` interface — so this package does **not** depend on `@objectstack/objectql`. diff --git a/packages/metadata-protocol/package.json b/packages/metadata-protocol/package.json new file mode 100644 index 0000000000..1a57f13afc --- /dev/null +++ b/packages/metadata-protocol/package.json @@ -0,0 +1,61 @@ +{ + "name": "@objectstack/metadata-protocol", + "version": "11.0.0", + "license": "Apache-2.0", + "description": "ObjectStack metadata management protocol: sys_metadata CRUD, draft/publish, locks, package ownership, diagnostics (ADR-0076).", + "type": "module", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": [ + "dist", + "README.md" + ], + "scripts": { + "build": "tsup", + "dev": "tsc --watch", + "clean": "rm -rf dist", + "test": "vitest run", + "test:watch": "vitest" + }, + "keywords": [ + "objectstack", + "metadata", + "protocol", + "sys-metadata" + ], + "dependencies": { + "@objectstack/core": "workspace:*", + "@objectstack/formula": "workspace:*", + "@objectstack/metadata-core": "workspace:*", + "@objectstack/spec": "workspace:*", + "@objectstack/types": "workspace:*", + "zod": "^4.4.3" + }, + "devDependencies": { + "@types/node": "^26.0.0", + "tsup": "^8.5.1", + "typescript": "^6.0.3", + "vitest": "^4.1.9" + }, + "author": "ObjectStack", + "repository": { + "type": "git", + "url": "https://github.com/objectstack-ai/framework.git", + "directory": "packages/metadata-protocol" + }, + "homepage": "https://objectstack.ai/docs", + "bugs": "https://github.com/objectstack-ai/framework/issues", + "publishConfig": { + "access": "public" + }, + "engines": { + "node": ">=18.0.0" + } +} diff --git a/packages/objectql/src/build-probes.ts b/packages/metadata-protocol/src/build-probes.ts similarity index 100% rename from packages/objectql/src/build-probes.ts rename to packages/metadata-protocol/src/build-probes.ts diff --git a/packages/metadata-protocol/src/host-engine.ts b/packages/metadata-protocol/src/host-engine.ts new file mode 100644 index 0000000000..6c1f4143a4 --- /dev/null +++ b/packages/metadata-protocol/src/host-engine.ts @@ -0,0 +1,25 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +import type { IDataEngine } from '@objectstack/core'; + +/** + * The engine surface the metadata protocol needs from its host (ADR-0076). + * + * The protocol uses the data engine purely as storage + a schema registry; it + * is injected a concrete engine at runtime (today `@objectstack/objectql`'s + * `ObjectQL`). Typing against this interface — instead of the concrete class — + * is what lets `@objectstack/metadata-protocol` avoid a dependency on + * `@objectstack/objectql` (which would otherwise form a cycle, since the + * ObjectQL plugin constructs the protocol). + */ +export interface MetadataHostEngine extends IDataEngine { + /** Schema registry (listItems/getItem/registerItem/getObject/registerObject/installPackage/...). */ + registry: any; + /** DDL: create/sync the physical table for an object schema. */ + syncObjectSchema(...args: any[]): Promise; + /** DDL: drop the physical table for an object schema. */ + dropObjectSchema(...args: any[]): Promise; + // Protocol accesses additional engine members structurally; keep it permissive + // for this relocation (behavior unchanged — the concrete engine is injected). + [key: string]: any; +} diff --git a/packages/metadata-protocol/src/index.test.ts b/packages/metadata-protocol/src/index.test.ts new file mode 100644 index 0000000000..4fabdb5c2f --- /dev/null +++ b/packages/metadata-protocol/src/index.test.ts @@ -0,0 +1,47 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. +// +// Self-contained smoke for @objectstack/metadata-protocol: the package must +// import cleanly and expose its public surface without needing a data engine. +// (Protocol behavior is exercised end-to-end by the @objectstack/objectql suite, +// which injects a real engine.) + +import { describe, it, expect } from 'vitest'; +import { + ObjectStackProtocolImplementation, + ConcurrentUpdateError, + normalizeViewMetadata, + SysMetadataRepository, + resetEnvWritableMetadataTypes, + computeMetadataDiagnostics, + computeViewReferenceDiagnostics, + decorateMetadataItem, + SeedLoaderService, + runBuildProbes, +} from './index.js'; + +describe('@objectstack/metadata-protocol public surface', () => { + it('exposes the protocol, repository, seed-loader and probe entry points', () => { + expect(typeof ObjectStackProtocolImplementation).toBe('function'); + expect(typeof SysMetadataRepository).toBe('function'); + expect(typeof SeedLoaderService).toBe('function'); + expect(typeof runBuildProbes).toBe('function'); + expect(ConcurrentUpdateError.prototype).toBeInstanceOf(Error); + }); + + it('exposes pure metadata helpers', () => { + expect(typeof normalizeViewMetadata).toBe('function'); + expect(typeof computeMetadataDiagnostics).toBe('function'); + expect(typeof computeViewReferenceDiagnostics).toBe('function'); + expect(typeof decorateMetadataItem).toBe('function'); + expect(typeof resetEnvWritableMetadataTypes).toBe('function'); + }); + + it('normalizeViewMetadata passes a non-view item through without throwing', () => { + const item = { name: 'acct', label: 'Account' }; + expect(() => normalizeViewMetadata('object', item, 'acct')).not.toThrow(); + }); + + it('resetEnvWritableMetadataTypes is callable (state reset, no engine needed)', () => { + expect(() => resetEnvWritableMetadataTypes()).not.toThrow(); + }); +}); diff --git a/packages/metadata-protocol/src/index.ts b/packages/metadata-protocol/src/index.ts new file mode 100644 index 0000000000..718a264f41 --- /dev/null +++ b/packages/metadata-protocol/src/index.ts @@ -0,0 +1,31 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +export { ObjectStackProtocolImplementation, ConcurrentUpdateError, normalizeViewMetadata } from './protocol.js'; + +export { SysMetadataRepository, resetEnvWritableMetadataTypes } from './sys-metadata-repository.js'; +export type { + SysMetadataEngine, + SysMetadataRepositoryOptions, + OverlayState, + ExtendedOperation, +} from './sys-metadata-repository.js'; + +export { + computeMetadataDiagnostics, + computeViewReferenceDiagnostics, + decorateMetadataItem, + decorateMetadataItems, +} from './metadata-diagnostics.js'; +export type { MetadataDiagnostics } from './metadata-diagnostics.js'; + +export type { MetadataHostEngine } from './host-engine.js'; + +export { SeedLoaderService } from './seed-loader.js'; +export { runBuildProbes } from './build-probes.js'; +export type { + RuntimeBuildIssue, + BuildProbeReport, + RunBuildProbesOptions, + ProbeEngine, + ProbeAnalytics, +} from './build-probes.js'; diff --git a/packages/objectql/src/metadata-diagnostics.ts b/packages/metadata-protocol/src/metadata-diagnostics.ts similarity index 100% rename from packages/objectql/src/metadata-diagnostics.ts rename to packages/metadata-protocol/src/metadata-diagnostics.ts diff --git a/packages/objectql/src/protocol.ts b/packages/metadata-protocol/src/protocol.ts similarity index 99% rename from packages/objectql/src/protocol.ts rename to packages/metadata-protocol/src/protocol.ts index 62125506c4..32105335ca 100644 --- a/packages/objectql/src/protocol.ts +++ b/packages/metadata-protocol/src/protocol.ts @@ -3,7 +3,7 @@ import { ObjectStackProtocol } from '@objectstack/spec/api'; import { IDataEngine } from '@objectstack/core'; import { readEnvWithDeprecation } from '@objectstack/types'; -import type { ObjectQL } from './engine.js'; +import type { MetadataHostEngine } from './host-engine.js'; import { SysMetadataRepository, type SysMetadataEngine } from './sys-metadata-repository.js'; import { ConflictError } from '@objectstack/metadata-core'; import type { @@ -667,7 +667,7 @@ function detectDestructiveObjectChanges(prev: any, next: any): Array<{ } export class ObjectStackProtocolImplementation implements ObjectStackProtocol { - private engine: ObjectQL; + private engine: MetadataHostEngine; private getServicesRegistry?: () => Map; private getFeedService?: () => IFeedService | undefined; /** @@ -694,7 +694,7 @@ export class ObjectStackProtocolImplementation implements ObjectStackProtocol { getFeedService?: () => IFeedService | undefined, environmentId?: string, ) { - this.engine = engine as ObjectQL; + this.engine = engine as MetadataHostEngine; this.getServicesRegistry = getServicesRegistry; this.getFeedService = getFeedService; this.environmentId = environmentId; diff --git a/packages/objectql/src/seed-loader.ts b/packages/metadata-protocol/src/seed-loader.ts similarity index 100% rename from packages/objectql/src/seed-loader.ts rename to packages/metadata-protocol/src/seed-loader.ts diff --git a/packages/objectql/src/sys-metadata-repository.ts b/packages/metadata-protocol/src/sys-metadata-repository.ts similarity index 100% rename from packages/objectql/src/sys-metadata-repository.ts rename to packages/metadata-protocol/src/sys-metadata-repository.ts diff --git a/packages/metadata-protocol/tsconfig.json b/packages/metadata-protocol/tsconfig.json new file mode 100644 index 0000000000..20f06375b8 --- /dev/null +++ b/packages/metadata-protocol/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ], + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": [ + "node" + ] + } +} diff --git a/packages/metadata-protocol/tsup.config.ts b/packages/metadata-protocol/tsup.config.ts new file mode 100644 index 0000000000..086365e59b --- /dev/null +++ b/packages/metadata-protocol/tsup.config.ts @@ -0,0 +1,14 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/index.ts'], + splitting: true, + sourcemap: true, + clean: true, + dts: !process.env.OS_SKIP_DTS, + format: ['esm', 'cjs'], + target: 'es2020', + external: ['vitest'], +}); diff --git a/packages/objectql/package.json b/packages/objectql/package.json index db0a329654..7b97dade91 100644 --- a/packages/objectql/package.json +++ b/packages/objectql/package.json @@ -10,16 +10,22 @@ "types": "./dist/index.d.ts", "import": "./dist/index.mjs", "require": "./dist/index.js" + }, + "./core": { + "types": "./dist/core.d.ts", + "import": "./dist/core.mjs", + "require": "./dist/core.js" } }, "scripts": { - "build": "tsup --config ../../tsup.config.ts", + "build": "tsup", "test": "vitest run" }, "dependencies": { "@objectstack/core": "workspace:*", "@objectstack/formula": "workspace:*", "@objectstack/metadata-core": "workspace:*", + "@objectstack/metadata-protocol": "workspace:*", "@objectstack/spec": "workspace:*", "@objectstack/types": "workspace:*", "ajv": "^8.20.0", diff --git a/packages/objectql/src/build-probes.test.ts b/packages/objectql/src/build-probes.test.ts index 57d147a8f1..22190d12c8 100644 --- a/packages/objectql/src/build-probes.test.ts +++ b/packages/objectql/src/build-probes.test.ts @@ -1,8 +1,8 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, vi } from 'vitest'; -import { runBuildProbes, type ProbeEngine } from './build-probes.js'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { runBuildProbes, type ProbeEngine } from '@objectstack/metadata-protocol'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; /** * ADR-0038 L3 — runtime probes. Each probe is one real read; findings are diff --git a/packages/objectql/src/core-boundary.ratchet.test.ts b/packages/objectql/src/core-boundary.ratchet.test.ts new file mode 100644 index 0000000000..844fa1686f --- /dev/null +++ b/packages/objectql/src/core-boundary.ratchet.test.ts @@ -0,0 +1,73 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. +// +// ADR-0076 D2 boundary ratchet. The lean engine entry `@objectstack/objectql/core` +// (src/core.ts) and its entire local import closure must NOT depend on the kernel +// plugin, the kernel factory, or the metadata-management protocol — so a thin +// embedder importing `@objectstack/objectql/core` never pulls +// `@objectstack/metadata-protocol` (or its 268KB) into its graph. +// +// If this test fails, you added a forbidden import somewhere reachable from +// core.ts. Keep metadata/plugin/kernel concerns out of the core closure. + +import { describe, it, expect } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const SRC = dirname(fileURLToPath(import.meta.url)); + +const FORBIDDEN_PACKAGES = ['@objectstack/metadata-protocol']; +const FORBIDDEN_LOCAL = ['plugin', 'kernel-factory']; + +function localImports(source: string): string[] { + const out: string[] = []; + const re = /(?:from|import)\s*\(?\s*['"](\.\.?\/[^'"]+)['"]/g; + let m: RegExpExecArray | null; + while ((m = re.exec(source))) out.push(m[1]); + return out; +} + +function toTsPath(fromFile: string, spec: string): string { + const base = resolve(dirname(fromFile), spec.replace(/\.js$/, '')); + return base.endsWith('.ts') ? base : `${base}.ts`; +} + +describe('ADR-0076 D2 — @objectstack/objectql/core boundary', () => { + it('core.ts closure pulls neither metadata-protocol nor plugin/kernel-factory', () => { + const entry = resolve(SRC, 'core.ts'); + const visited = new Set(); + const violations: string[] = []; + const stack = [entry]; + + while (stack.length) { + const file = stack.pop()!; + if (visited.has(file)) continue; + visited.add(file); + + let src: string; + try { + src = readFileSync(file, 'utf8'); + } catch { + continue; // generated / non-existent; ignore + } + + for (const pkg of FORBIDDEN_PACKAGES) { + if (new RegExp(`['"]${pkg.replace('/', '\\/')}['"]`).test(src)) { + violations.push(`${file} imports forbidden package ${pkg}`); + } + } + + for (const spec of localImports(src)) { + const base = spec.replace(/\.js$/, '').split('/').pop(); + if (FORBIDDEN_LOCAL.includes(base ?? '')) { + violations.push(`${file} imports forbidden local module ./${base}`); + } + stack.push(toTsPath(file, spec)); + } + } + + expect(violations, violations.join('\n')).toEqual([]); + // sanity: the engine itself IS in the closure + expect([...visited].some((f) => f.endsWith('/engine.ts'))).toBe(true); + }); +}); diff --git a/packages/objectql/src/core.ts b/packages/objectql/src/core.ts new file mode 100644 index 0000000000..b01df4d44f --- /dev/null +++ b/packages/objectql/src/core.ts @@ -0,0 +1,78 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. +// +// Lean engine entry (ADR-0076). Exposes the data engine surface — engine, +// registry, hooks, validation, in-memory aggregation, utilities — WITHOUT the +// kernel plugin (`ObjectQLPlugin`), the kernel factory, or any metadata +// management (`@objectstack/metadata-protocol`). Embedders that want only the +// engine (e.g. a thin gateway) import from `@objectstack/objectql/core` so the +// 268KB metadata protocol is never pulled into their dependency graph. +// +// A boundary ratchet (ADR-0076 D2) keeps this entry free of protocol/plugin +// imports; do not add `./plugin`, `./kernel-factory`, or `@objectstack/metadata-protocol` +// re-exports here. + +// Registry +export { + SchemaRegistry, + applySystemFields, + computeFQN, + parseFQN, + RESERVED_NAMESPACES, + DEFAULT_OWNER_PRIORITY, + DEFAULT_EXTENDER_PRIORITY, +} from './registry.js'; +export type { ObjectContributor, SchemaRegistryOptions } from './registry.js'; + +// Engine +export { ObjectQL, ObjectRepository, ScopedContext } from './engine.js'; +export type { ObjectQLHostContext, HookHandler, HookEntry, OperationContext, EngineMiddleware } from './engine.js'; + +// In-memory aggregation fallback +export { applyInMemoryAggregation, bucketDateValue } from './in-memory-aggregation.js'; + +// Hook binder & wrappers (declarative-metadata → engine glue) +export { bindHooksToEngine } from './hook-binder.js'; +export type { BindHooksOptions, BindHooksResult } from './hook-binder.js'; +export { wrapDeclarativeHook } from './hook-wrappers.js'; +export type { WrapDeclarativeOptions } from './hook-wrappers.js'; + +// Validation +export { ValidationError, validateRecord } from './validation/record-validator.js'; +export type { FieldValidationError } from './validation/record-validator.js'; +export { evaluateValidationRules, needsPriorRecord, legalNextStates } from './validation/rule-validator.js'; +export type { EvaluateRulesOptions } from './validation/rule-validator.js'; +export { + InMemoryHookMetricsRecorder, + noopHookMetricsRecorder, +} from './hook-metrics.js'; +export type { + HookMetricsRecorder, + HookMetricLabel, + HookMetricOutcome, + HookSkipReason, +} from './hook-metrics.js'; + +// MetadataFacade +export { MetadataFacade } from './metadata-facade.js'; + +// Secret-field channel helpers +export { + SECRET_REF_PREFIX, + SECRET_MASK, + makeSecretRef, + isSecretRef, + parseSecretRef, + collectSecretFields, +} from './secret-fields.js'; + +// Utilities +export { + toTitleCase, + convertIntrospectedSchemaToObjects, +} from './util.js'; +export type { + IntrospectedColumn, + IntrospectedForeignKey, + IntrospectedTable, + IntrospectedSchema, +} from './util.js'; diff --git a/packages/objectql/src/index.ts b/packages/objectql/src/index.ts index 4fc260e68c..23fcfbbb41 100644 --- a/packages/objectql/src/index.ts +++ b/packages/objectql/src/index.ts @@ -13,11 +13,11 @@ export { export type { ObjectContributor, SchemaRegistryOptions } from './registry.js'; // Export Protocol Implementation -export { ObjectStackProtocolImplementation } from './protocol.js'; +export { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; // ADR-0008 PR-10b: MetadataRepository wrapper over the existing sys_metadata table. -export { SysMetadataRepository } from './sys-metadata-repository.js'; -export type { SysMetadataEngine, SysMetadataRepositoryOptions } from './sys-metadata-repository.js'; +export { SysMetadataRepository } from '@objectstack/metadata-protocol'; +export type { SysMetadataEngine, SysMetadataRepositoryOptions } from '@objectstack/metadata-protocol'; // Export Engine export { ObjectQL, ObjectRepository, ScopedContext } from './engine.js'; @@ -83,9 +83,9 @@ export type { // Seed loader — materializes `seed` metadata into rows (used by publishMetaItem // and the runtime dispatcher/app plugins). -export { SeedLoaderService } from './seed-loader.js'; +export { SeedLoaderService } from '@objectstack/metadata-protocol'; // ADR-0038 L3 — post-publish runtime probes (one real read per published // artifact); findings are BuildIssue-shaped with layer 'runtime'. -export { runBuildProbes } from './build-probes.js'; -export type { RuntimeBuildIssue, BuildProbeReport, RunBuildProbesOptions } from './build-probes.js'; +export { runBuildProbes } from '@objectstack/metadata-protocol'; +export type { RuntimeBuildIssue, BuildProbeReport, RunBuildProbesOptions } from '@objectstack/metadata-protocol'; diff --git a/packages/objectql/src/layered-overlay-integration.test.ts b/packages/objectql/src/layered-overlay-integration.test.ts index 8bd87c0d2c..b6669c929c 100644 --- a/packages/objectql/src/layered-overlay-integration.test.ts +++ b/packages/objectql/src/layered-overlay-integration.test.ts @@ -18,7 +18,7 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { LayeredRepository, InMemoryRepository, hashSpec } from '@objectstack/metadata-core'; import type { MetaRef } from '@objectstack/metadata-core'; -import { SysMetadataRepository } from './sys-metadata-repository.js'; +import { SysMetadataRepository } from '@objectstack/metadata-protocol'; interface Row { id: string; diff --git a/packages/objectql/src/metadata-diagnostics.test.ts b/packages/objectql/src/metadata-diagnostics.test.ts index d503cf829a..f31b0fe00b 100644 --- a/packages/objectql/src/metadata-diagnostics.test.ts +++ b/packages/objectql/src/metadata-diagnostics.test.ts @@ -10,7 +10,7 @@ */ import { describe, expect, it } from 'vitest'; -import { computeViewReferenceDiagnostics } from './metadata-diagnostics.js'; +import { computeViewReferenceDiagnostics } from '@objectstack/metadata-protocol'; const objectDef = { fields: { diff --git a/packages/objectql/src/metadata-validation-sweep.test.ts b/packages/objectql/src/metadata-validation-sweep.test.ts index 59caa80ee4..e3ad7d64e3 100644 --- a/packages/objectql/src/metadata-validation-sweep.test.ts +++ b/packages/objectql/src/metadata-validation-sweep.test.ts @@ -21,7 +21,7 @@ */ import { describe, it, expect, vi } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { SchemaRegistry } from './registry.js'; import { DEFAULT_METADATA_TYPE_REGISTRY, diff --git a/packages/objectql/src/normalize-view-metadata.test.ts b/packages/objectql/src/normalize-view-metadata.test.ts index 34f48ebf2e..a3a672c993 100644 --- a/packages/objectql/src/normalize-view-metadata.test.ts +++ b/packages/objectql/src/normalize-view-metadata.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect } from 'vitest'; -import { normalizeViewMetadata } from './protocol.js'; +import { normalizeViewMetadata } from '@objectstack/metadata-protocol'; /** * The `view` write path guarantees a top-level `name` on every view body so diff --git a/packages/objectql/src/overlay-precedence.test.ts b/packages/objectql/src/overlay-precedence.test.ts index fc66ec82c7..3a8843da9b 100644 --- a/packages/objectql/src/overlay-precedence.test.ts +++ b/packages/objectql/src/overlay-precedence.test.ts @@ -32,7 +32,7 @@ */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { SchemaRegistry } from './registry.js'; import { canonicalize, hashSpec } from '@objectstack/metadata-core'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; diff --git a/packages/objectql/src/plugin.ts b/packages/objectql/src/plugin.ts index 6c4c88a91d..d0c1c55a67 100644 --- a/packages/objectql/src/plugin.ts +++ b/packages/objectql/src/plugin.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { ObjectQL } from './engine.js'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { Plugin, PluginContext } from '@objectstack/core'; import { StorageNameMapping } from '@objectstack/spec/system'; import { diff --git a/packages/objectql/src/protocol-clone-real-engine.test.ts b/packages/objectql/src/protocol-clone-real-engine.test.ts index ce68e3677b..bdae421c51 100644 --- a/packages/objectql/src/protocol-clone-real-engine.test.ts +++ b/packages/objectql/src/protocol-clone-real-engine.test.ts @@ -10,7 +10,7 @@ */ import { describe, it, expect, beforeEach } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { ObjectQL } from './engine.js'; // A clonable object: business fields + an engine-generated autonumber that diff --git a/packages/objectql/src/protocol-commit-history.test.ts b/packages/objectql/src/protocol-commit-history.test.ts index de9003ee4e..5eff21c50c 100644 --- a/packages/objectql/src/protocol-commit-history.test.ts +++ b/packages/objectql/src/protocol-commit-history.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, vi } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; /** * ADR-0067 — package-scoped commit history & rollback. diff --git a/packages/objectql/src/protocol-data.test.ts b/packages/objectql/src/protocol-data.test.ts index fc460a369d..c25e61e2d5 100644 --- a/packages/objectql/src/protocol-data.test.ts +++ b/packages/objectql/src/protocol-data.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; /** * Tests for the Protocol Implementation's data methods (findData, getData). diff --git a/packages/objectql/src/protocol-destructive.test.ts b/packages/objectql/src/protocol-destructive.test.ts index 3417c4a514..40e8030d13 100644 --- a/packages/objectql/src/protocol-destructive.test.ts +++ b/packages/objectql/src/protocol-destructive.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { SchemaRegistry } from './registry.js'; /** diff --git a/packages/objectql/src/protocol-discovery.test.ts b/packages/objectql/src/protocol-discovery.test.ts index 5b4338d9c7..9a3be0e302 100644 --- a/packages/objectql/src/protocol-discovery.test.ts +++ b/packages/objectql/src/protocol-discovery.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, beforeEach } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { ObjectQL } from './engine.js'; describe('ObjectStackProtocolImplementation - Dynamic Service Discovery', () => { diff --git a/packages/objectql/src/protocol-feed.test.ts b/packages/objectql/src/protocol-feed.test.ts index 1d6eaf6d67..e24bd2f27c 100644 --- a/packages/objectql/src/protocol-feed.test.ts +++ b/packages/objectql/src/protocol-feed.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { ObjectQL } from './engine.js'; import type { IFeedService } from '@objectstack/spec/contracts'; diff --git a/packages/objectql/src/protocol-install-package.test.ts b/packages/objectql/src/protocol-install-package.test.ts index 3e087ab75d..fccf4280f4 100644 --- a/packages/objectql/src/protocol-install-package.test.ts +++ b/packages/objectql/src/protocol-install-package.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, vi } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; /** * ADR-0033 package-subsystem consolidation — `protocol.installPackage` is the diff --git a/packages/objectql/src/protocol-layered-get.test.ts b/packages/objectql/src/protocol-layered-get.test.ts index 0e74d22cab..b4ad600d7e 100644 --- a/packages/objectql/src/protocol-layered-get.test.ts +++ b/packages/objectql/src/protocol-layered-get.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { SchemaRegistry } from './registry.js'; /** diff --git a/packages/objectql/src/protocol-lock-enforcement.test.ts b/packages/objectql/src/protocol-lock-enforcement.test.ts index 00d82b4b26..91405785fb 100644 --- a/packages/objectql/src/protocol-lock-enforcement.test.ts +++ b/packages/objectql/src/protocol-lock-enforcement.test.ts @@ -21,7 +21,7 @@ */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { SchemaRegistry } from './registry.js'; import type { MetadataLock } from '@objectstack/spec/kernel'; diff --git a/packages/objectql/src/protocol-meta-types-rich.test.ts b/packages/objectql/src/protocol-meta-types-rich.test.ts index dd2de01830..33986fee33 100644 --- a/packages/objectql/src/protocol-meta-types-rich.test.ts +++ b/packages/objectql/src/protocol-meta-types-rich.test.ts @@ -1,9 +1,9 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { SchemaRegistry } from './registry.js'; -import { resetEnvWritableMetadataTypes } from './sys-metadata-repository.js'; +import { resetEnvWritableMetadataTypes } from '@objectstack/metadata-protocol'; /** * Phase 3a-1 + 3a-env-writable tests. diff --git a/packages/objectql/src/protocol-meta.test.ts b/packages/objectql/src/protocol-meta.test.ts index 59379961ab..243d81296d 100644 --- a/packages/objectql/src/protocol-meta.test.ts +++ b/packages/objectql/src/protocol-meta.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { SchemaRegistry } from './registry.js'; /** diff --git a/packages/objectql/src/protocol-package-lifecycle.test.ts b/packages/objectql/src/protocol-package-lifecycle.test.ts index 7695a575fb..20eddfff53 100644 --- a/packages/objectql/src/protocol-package-lifecycle.test.ts +++ b/packages/objectql/src/protocol-package-lifecycle.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, vi } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; /** * ADR-0033 — package-level lifecycle beyond publish: diff --git a/packages/objectql/src/protocol-publish-package-drafts.test.ts b/packages/objectql/src/protocol-publish-package-drafts.test.ts index 0c109befa9..87314c553c 100644 --- a/packages/objectql/src/protocol-publish-package-drafts.test.ts +++ b/packages/objectql/src/protocol-publish-package-drafts.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, vi } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; /** * ADR-0033 — `publishPackageDrafts` promotes every pending draft bound to a diff --git a/packages/objectql/src/protocol-publish-rollback.test.ts b/packages/objectql/src/protocol-publish-rollback.test.ts index 29be8765c6..9b2e9b4276 100644 --- a/packages/objectql/src/protocol-publish-rollback.test.ts +++ b/packages/objectql/src/protocol-publish-rollback.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, expect, it, vi } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; /** * Protocol-level coverage for the per-item draft / publish / rollback / diff --git a/packages/objectql/src/protocol-references.test.ts b/packages/objectql/src/protocol-references.test.ts index f6c80534ac..8335212d63 100644 --- a/packages/objectql/src/protocol-references.test.ts +++ b/packages/objectql/src/protocol-references.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { SchemaRegistry } from './registry.js'; /** diff --git a/packages/objectql/src/protocol-registry-shadow.test.ts b/packages/objectql/src/protocol-registry-shadow.test.ts index df55c1ee58..c761a4f584 100644 --- a/packages/objectql/src/protocol-registry-shadow.test.ts +++ b/packages/objectql/src/protocol-registry-shadow.test.ts @@ -23,7 +23,7 @@ */ import { describe, it, expect, beforeEach } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { ObjectQL } from './engine.js'; import { SchemaRegistry } from './registry.js'; diff --git a/packages/objectql/src/protocol-save-meta-repo-path-real-engine.test.ts b/packages/objectql/src/protocol-save-meta-repo-path-real-engine.test.ts index f6e5d34715..05bf468177 100644 --- a/packages/objectql/src/protocol-save-meta-repo-path-real-engine.test.ts +++ b/packages/objectql/src/protocol-save-meta-repo-path-real-engine.test.ts @@ -11,7 +11,7 @@ */ import { describe, it, expect, beforeEach } from 'vitest'; -import { ObjectStackProtocolImplementation } from './protocol.js'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { ObjectQL } from './engine.js'; const sysMetadataObject = { diff --git a/packages/objectql/src/protocol-save-meta-repo-path.test.ts b/packages/objectql/src/protocol-save-meta-repo-path.test.ts index 195c426958..381e63e991 100644 --- a/packages/objectql/src/protocol-save-meta-repo-path.test.ts +++ b/packages/objectql/src/protocol-save-meta-repo-path.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { hashSpec } from '@objectstack/metadata-core'; -import { ObjectStackProtocolImplementation } from './protocol'; +import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; /** * Repository write-path coverage (post PR-10d.6). diff --git a/packages/objectql/src/seed-loader-org-fallback.test.ts b/packages/objectql/src/seed-loader-org-fallback.test.ts index 2c412dc5e7..bebc90d84e 100644 --- a/packages/objectql/src/seed-loader-org-fallback.test.ts +++ b/packages/objectql/src/seed-loader-org-fallback.test.ts @@ -8,7 +8,7 @@ // many orgs → leave rows org-less (genuinely ambiguous → historical behavior). import { describe, it, expect } from 'vitest'; -import { SeedLoaderService } from './seed-loader'; +import { SeedLoaderService } from '@objectstack/metadata-protocol'; import { SeedLoaderConfigSchema } from '@objectstack/spec/data'; function harness(orgRows: Array<{ id: string }>) { diff --git a/packages/objectql/src/sys-metadata-repository-list-drafts.test.ts b/packages/objectql/src/sys-metadata-repository-list-drafts.test.ts index 1f91327515..b175626a42 100644 --- a/packages/objectql/src/sys-metadata-repository-list-drafts.test.ts +++ b/packages/objectql/src/sys-metadata-repository-list-drafts.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, vi } from 'vitest'; -import { SysMetadataRepository } from './sys-metadata-repository.js'; +import { SysMetadataRepository } from '@objectstack/metadata-protocol'; /** * ADR-0033 — `listDrafts` surfaces pending DRAFT rows (what an AI authored but diff --git a/packages/objectql/src/sys-metadata-repository.test.ts b/packages/objectql/src/sys-metadata-repository.test.ts index f28e0be70e..f918b54d68 100644 --- a/packages/objectql/src/sys-metadata-repository.test.ts +++ b/packages/objectql/src/sys-metadata-repository.test.ts @@ -10,7 +10,7 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { ConflictError, hashSpec } from '@objectstack/metadata-core'; -import { SysMetadataRepository } from './sys-metadata-repository.js'; +import { SysMetadataRepository } from '@objectstack/metadata-protocol'; interface Row { id: string; diff --git a/packages/objectql/tsup.config.ts b/packages/objectql/tsup.config.ts new file mode 100644 index 0000000000..e664fcc78f --- /dev/null +++ b/packages/objectql/tsup.config.ts @@ -0,0 +1,16 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +import { defineConfig } from 'tsup'; + +export default defineConfig({ + // `core` is the lean engine entry (ADR-0076) — engine/registry/hooks/validation + // only, no kernel plugin or @objectstack/metadata-protocol. `index` is the + // batteries-included barrel. + entry: ['src/index.ts', 'src/core.ts'], + splitting: false, + sourcemap: true, + clean: true, + dts: !process.env.OS_SKIP_DTS, + format: ['esm', 'cjs'], + target: 'es2020', +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b963d4002..14be2822bd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -917,6 +917,40 @@ importers: specifier: ^4.1.9 version: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@26.0.0)(@vitest/coverage-v8@4.1.9)(happy-dom@20.10.2)(msw@2.14.6(@types/node@26.0.0)(typescript@6.0.3))(vite@8.0.16(@types/node@26.0.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) + packages/metadata-protocol: + dependencies: + '@objectstack/core': + specifier: workspace:* + version: link:../core + '@objectstack/formula': + specifier: workspace:* + version: link:../formula + '@objectstack/metadata-core': + specifier: workspace:* + version: link:../metadata-core + '@objectstack/spec': + specifier: workspace:* + version: link:../spec + '@objectstack/types': + specifier: workspace:* + version: link:../types + zod: + specifier: ^4.4.3 + version: 4.4.3 + devDependencies: + '@types/node': + specifier: ^26.0.0 + version: 26.0.0 + tsup: + specifier: ^8.5.1 + version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@6.0.3)(yaml@2.9.0) + typescript: + specifier: ^6.0.3 + version: 6.0.3 + vitest: + specifier: ^4.1.9 + version: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@26.0.0)(@vitest/coverage-v8@4.1.9)(happy-dom@20.10.2)(msw@2.14.6(@types/node@26.0.0)(typescript@6.0.3))(vite@8.0.16(@types/node@26.0.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) + packages/objectql: dependencies: '@objectstack/core': @@ -928,6 +962,9 @@ importers: '@objectstack/metadata-core': specifier: workspace:* version: link:../metadata-core + '@objectstack/metadata-protocol': + specifier: workspace:* + version: link:../metadata-protocol '@objectstack/spec': specifier: workspace:* version: link:../spec