diff --git a/.changeset/25921-types-api-block.md b/.changeset/25921-types-api-block.md new file mode 100644 index 00000000000..56d26bb665e --- /dev/null +++ b/.changeset/25921-types-api-block.md @@ -0,0 +1,19 @@ +--- +'@object-ui/types': patch +--- + +refactor(types)!: delete the api-types module and its eight names nothing reads + +Clause-②: no (narrowing) +Metadata-protocol: none + + + +**BREAKING** for a host that imports any of these eight types from `@object-ui/types`. None had an importer anywhere in the workspace or in hotcrm, so the Console and every `@object-ui/*` package are unaffected. + +They are **gone from the package, not only from the entry**: the whole `api-types.ts` module (the entry's "API and Events" block) is deleted. The objectui#6497 tombstone for `UIEventHandler` and `EventableSchema` it carried now stands in the entry where the block was; those two stay retired. + +What leaves, and what to write instead: + +- FROM `HTTPMethod`, `APIRequest`, `APIConfig`, `DataFetchConfig`, `DataFetchableSchema`, `APISchema` TO no replacement in this package. A component reads data through this package's `DataSource` interface; a host that kept its own request shape declares it locally. +- FROM `ExpressionContext`, `ExpressionNodeSchema` TO no replacement in this package. Expressions are `${…}` strings evaluated by `@object-ui/core`'s `ExpressionEvaluator` against its own `ExpressionContext` class. diff --git a/ui/packages/types/src/__tests__/eventable-schema-retired-6497.test.ts b/ui/packages/types/src/__tests__/eventable-schema-retired-6497.test.ts index da333e3952e..d4ca47d78c7 100644 --- a/ui/packages/types/src/__tests__/eventable-schema-retired-6497.test.ts +++ b/ui/packages/types/src/__tests__/eventable-schema-retired-6497.test.ts @@ -26,6 +26,15 @@ * external TypeScript consumer that imported either name gets a compile error * naming the symbol, and the changeset is what it reads. * + * ## The declaring module is gone (#25921, batch 9) + * + * Both names were declared in `../api-types.ts`. That whole module was DELETED + * by #25921 batch 9 (its eight surviving names had no reader either), and the + * tombstone moved into the barrel where its export block stood. So the pin's + * module legs now assert the FILE is gone, and every text check reads the + * barrel. Its assertions about `UIEventHandler` / `EventableSchema` staying + * unexported are unchanged; only the file they read moved. + * * ## Three instruments, and why the obvious fourth is absent * * - `tsc` sees the `@ts-expect-error` legs. They are the only half that tells @@ -33,9 +42,9 @@ * TypeScript-only refusal, and they mean nothing unless `type-check` runs * (vitest strips types). This package compiles every `*.test.ts` file * through `tsconfig.test.json`, which is what makes them real. - * - vitest reads the declaring module and the barrel as TEXT, so a - * re-introduced interface or re-export reddens even in a run that never - * type-checks. + * - vitest reads the barrel as TEXT (and checks the deleted declaring module + * stays deleted), so a re-introduced interface or re-export reddens even in + * a run that never type-checks. * - vitest scans the whole TRACKED tree for both spellings, with a lit * control on the same probe. * - ⛔ A runtime `name in module` leg is deliberately absent: both names were @@ -44,7 +53,7 @@ */ import { describe, it, expect } from 'vitest'; -import { readFileSync } from 'node:fs'; +import { existsSync, readFileSync } from 'node:fs'; import { execFileSync } from 'node:child_process'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -52,72 +61,74 @@ import { fileURLToPath } from 'node:url'; /** Rooted at THIS file, never at `process.cwd()` — the two differ per invocation. */ const HERE = dirname(fileURLToPath(import.meta.url)); const REPO_ROOT = resolve(HERE, '../../../..'); -const DECLARATION_PATH = resolve(HERE, '..', 'api-types.ts'); +/** The declaring module of both names, DELETED whole by #25921 batch 9. */ +const RETIRED_DECLARATION_PATH = resolve(HERE, '..', 'api-types.ts'); const BARREL_PATH = resolve(HERE, '..', 'index.ts'); -/* ── The type face: both symbols are gone from the module AND from the barrel ── */ - -// @ts-expect-error objectui#6497 — `UIEventHandler` is RETIRED from `../api-types`. No replacement type; see the tombstone in that file. -type _HandlerRetiredFromTheDeclaringModule = import('../api-types').UIEventHandler; +/* ── The type face: both symbols are gone from the published barrel ── */ +// (The declaring-module legs went with `../api-types.ts` itself; the file's +// absence is asserted at runtime below, where a missing module cannot be +// mistaken for a satisfied directive.) -// @ts-expect-error objectui#6497 — `EventableSchema` is RETIRED from `../api-types`. No replacement type; see the tombstone in that file. -type _EventableRetiredFromTheDeclaringModule = import('../api-types').EventableSchema; - -// @ts-expect-error objectui#6497 — and `UIEventHandler` is RETIRED from the published barrel, the face an external consumer imports. +// @ts-expect-error objectui#6497 — `UIEventHandler` is RETIRED from the published barrel, the face an external consumer imports. type _HandlerRetiredFromThePublishedBarrel = import('../index').UIEventHandler; -// @ts-expect-error objectui#6497 — and `EventableSchema` is RETIRED from the published barrel, the face an external consumer imports. +// @ts-expect-error objectui#6497 — `EventableSchema` is RETIRED from the published barrel, the face an external consumer imports. type _EventableRetiredFromThePublishedBarrel = import('../index').EventableSchema; /** - * ⭐ THE LIT CONTROLS for the four directives above, on the same instrument. + * ⭐ THE LIT CONTROLS for the two directives above, on the same instrument. * * `@ts-expect-error` fails loudly when the line below it compiles (TS2578, * "unused directive"), so the directives cannot rot into silence. What they - * cannot rule out on their own is a module that stopped resolving ANYTHING — an - * emptied `../api-types` or a moved barrel would satisfy all four. These resolve - * siblings the ruling left alone, through the exact same import forms, with no - * directive. + * cannot rule out on their own is a barrel that stopped resolving ANYTHING — a + * moved or emptied `../index` would satisfy both. These resolve names the + * ruling left alone, through the exact same import form, with no directive. */ -type _SiblingStillResolvesFromTheModule = import('../api-types').DataFetchableSchema; -type _SiblingStillResolvesFromTheBarrel = import('../index').ExpressionNodeSchema; -type _UnionStillResolvesFromTheBarrel = import('../index').APISchema; +type _SiblingStillResolvesFromTheBarrel = import('../index').BaseSchema; +type _UnionStillResolvesFromTheBarrel = import('../index').AnySchema; /** Consumed so the controls are not unused type aliases. */ type _ControlsAreReferenced = [ - _SiblingStillResolvesFromTheModule['type'], _SiblingStillResolvesFromTheBarrel['type'], _UnionStillResolvesFromTheBarrel['type'], ]; describe('objectui#6497 — the event-handler dialect stays retired (type face)', () => { - it('the DECLARING module no longer declares either interface', () => { - const source = readFileSync(DECLARATION_PATH, 'utf8'); + it('the DECLARING module is gone, and the barrel declares neither interface', () => { + // #25921 batch 9 deleted `../api-types.ts` whole. ⭐ LIT CONTROL on the + // same probe: the barrel, resolved the same way, exists. + expect(existsSync(RETIRED_DECLARATION_PATH)).toBe(false); + expect(existsSync(BARREL_PATH)).toBe(true); + + const source = readFileSync(BARREL_PATH, 'utf8'); - expect(/^export interface UIEventHandler\b/m.test(source)).toBe(false); - expect(/^export interface EventableSchema\b/m.test(source)).toBe(false); + expect(/^export (?:interface|type) UIEventHandler\b/m.test(source)).toBe(false); + expect(/^export (?:interface|type) EventableSchema\b/m.test(source)).toBe(false); - // ⭐ LIT CONTROL — the same matcher shape, one sibling over, still fires. - // Without it both absences above would also be satisfied by a truncated - // read or a matcher that can never match. - expect(/^export interface DataFetchableSchema\b/m.test(source)).toBe(true); + // ⭐ LIT CONTROL — the same matcher shape still fires on a declaration the + // barrel does carry. Without it both absences above would also be satisfied + // by a truncated read or a matcher that can never match. + expect(/^export (?:interface|type) AnySchema\b/m.test(source)).toBe(true); - // The tombstone stays: it records the ruling, what went and the supported - // form. A retirement whose reasoning is deleted is re-litigated by the next - // sweep. + // The tombstone stays (moved here from the deleted module): it records the + // ruling, what went and the supported form. A retirement whose reasoning is + // deleted is re-litigated by the next sweep. expect(source).toContain('`UIEventHandler` and `EventableSchema` — RETIRED'); }); - it('`APISchema` no longer carries an `EventableSchema` arm', () => { - const source = readFileSync(DECLARATION_PATH, 'utf8'); - const union = /^export type APISchema =([^;]*);/m.exec(source); + it('the barrel\'s schema union carries no `EventableSchema` arm', () => { + // The arm once sat on `APISchema`, deleted with its module (#25921 batch 9); + // `AnySchema` is the union the barrel still declares. + const source = readFileSync(BARREL_PATH, 'utf8'); + const union = /^export type AnySchema =([^;]*);/m.exec(source); // The union is still declared (a missing union would make the next two - // assertions vacuous), it no longer names the retired arm, and it still + // assertions vacuous), it does not name the retired arm, and it still // names a surviving arm — the lit control on the same extracted text. expect(union).not.toBeNull(); expect(union![1]).not.toMatch(/\bEventableSchema\b/); - expect(union![1]).toMatch(/\bDataFetchableSchema\b/); + expect(union![1]).toMatch(/\bBaseSchema\b/); }); it('the published BARREL no longer re-exports either symbol', () => { @@ -129,10 +140,9 @@ describe('objectui#6497 — the event-handler dialect stays retired (type face)' expect(/^\s*UIEventHandler,\s*$/m.test(barrel)).toBe(false); expect(/^\s*EventableSchema,\s*$/m.test(barrel)).toBe(false); - // ⭐ LIT CONTROL — the identical matcher finds siblings that ARE still - // re-exported from the same block. - expect(/^\s*DataFetchableSchema,\s*$/m.test(barrel)).toBe(true); - expect(/^\s*APISchema,\s*$/m.test(barrel)).toBe(true); + // ⭐ LIT CONTROL — the identical matcher finds a name that IS still + // re-exported (the block these two sat in went whole, #25921 batch 9). + expect(/^\s*BaseSchema,\s*$/m.test(barrel)).toBe(true); }); }); @@ -143,16 +153,16 @@ describe('objectui#6497 — nothing in this TRACKED tree carries either symbol', * * - `*CHANGELOG.md` and `.changeset/` — the published RECORD of retirements, * including this one, which must keep naming what it removed. - * - `api-types.ts` and `index.ts` — the two files the retirement EDITED. Each - * carries a tombstone comment naming both symbols on purpose; that they no - * longer DECLARE or RE-EXPORT them is asserted above by matchers shaped for - * a declaration and an export-list entry. + * - `index.ts` — the barrel, which carries the tombstone comment naming both + * symbols on purpose (moved there when #25921 batch 9 deleted + * `api-types.ts`, the other file the retirement edited); that it does not + * DECLARE or RE-EXPORT them is asserted above by matchers shaped for a + * declaration and an export-list entry. * - this pin, which must write both spellings to probe for them. */ const EXCLUDED = [ ':!*CHANGELOG.md', ':!.changeset/', - ':!packages/types/src/api-types.ts', ':!packages/types/src/index.ts', ':!packages/types/src/__tests__/eventable-schema-retired-6497.test.ts', ]; diff --git a/ui/packages/types/src/api-types.ts b/ui/packages/types/src/api-types.ts deleted file mode 100644 index 9b7010e8654..00000000000 --- a/ui/packages/types/src/api-types.ts +++ /dev/null @@ -1,342 +0,0 @@ -/** - * ObjectUI - * Copyright (c) 2024-present ObjectStack Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/** - * @object-ui/types - API Schemas - * - * Type definitions for API integration, data fetching and expression nodes. - * These schemas enable dynamic API calls. The event-handler dialect this module - * once declared is RETIRED (objectui#6497); its tombstone stands where it was. - * - * @module api - * @packageDocumentation - */ - -import type { BaseSchema } from './base.js'; - -/** - * HTTP Method types - */ -export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'; - -/** - * API request configuration - */ -export interface APIRequest { - /** - * API endpoint URL - * Supports variable substitution: "/api/users/${userId}" - */ - url: string; - /** - * HTTP method - * @default 'GET' - */ - method?: HTTPMethod; - /** - * Request headers - */ - headers?: Record; - /** - * Request body data - * For POST, PUT, PATCH requests - */ - data?: any; - /** - * Query parameters - */ - params?: Record; - /** - * Request timeout in milliseconds - */ - timeout?: number; - /** - * Whether to send credentials (cookies) - * @default false - */ - withCredentials?: boolean; - /** - * Data transformation function - * Transform request data before sending - */ - transformRequest?: string; - /** - * Response transformation function - * Transform response data after receiving - */ - transformResponse?: string; -} - -/** - * API configuration for components - */ -export interface APIConfig { - /** - * API request configuration - */ - request?: APIRequest; - /** - * Success handler - * JavaScript expression or function name - */ - onSuccess?: string; - /** - * Error handler - * JavaScript expression or function name - */ - onError?: string; - /** - * Loading indicator - * Whether to show loading state during request - * @default true - */ - showLoading?: boolean; - /** - * Success message to display - */ - successMessage?: string; - /** - * Error message to display - */ - errorMessage?: string; - /** - * Whether to reload data after success - * @default false - */ - reload?: boolean; - /** - * Whether to redirect after success - */ - redirect?: string; - /** - * Whether to close dialog/modal after success - * @default false - */ - close?: boolean; - /** - * Retry configuration - */ - retry?: { - /** - * Maximum retry attempts - */ - maxAttempts?: number; - /** - * Delay between retries in milliseconds - */ - delay?: number; - /** - * HTTP status codes to retry - */ - retryOn?: number[]; - }; - /** - * Cache configuration - */ - cache?: { - /** - * Cache key - */ - key?: string; - /** - * Cache duration in milliseconds - */ - duration?: number; - /** - * Whether to use stale cache while revalidating - */ - staleWhileRevalidate?: boolean; - }; -} - -/** - * `UIEventHandler` and `EventableSchema` — RETIRED. This comment is the - * tombstone: both were TypeScript interfaces, which erase and leave no runtime - * residue that could carry a marker of their own. - * - * RETIRED under ADR-0049 enforce-or-remove by the director-seat ruling recorded - * on objectui#6497 (2026-09-24, maintainer verbatim 「同意」): the re-priced - * option 2 of the three that card offered. ⛔ Not option 1 (mirror the dialect in - * zod, have component schemas extend it, build a dispatcher for it) and ⛔ not - * option 3 (leave it on the published surface). The ruling follows objectui#6182 - * (ruled A, 2026-08-25): an authored handler EXPRESSION is not a supported - * authoring form. - * - * **What went.** Both exported interfaces and their `@object-ui/types` barrel - * re-exports. `UIEventHandler` was an event-handler object: `event`, a `type` of - * `action | api | script | navigation | dialog | toast | custom`, one config - * member per type, then `condition`, `preventDefault`, `stopPropagation`, - * `debounce` and `throttle`. Its `dialog.actions[]` entries carried a recursive - * `handler?: UIEventHandler`, which went with it. `EventableSchema` extended - * {@link BaseSchema} with an `events` array and nine `on*` keys, each typed - * `UIEventHandler | string`. Its arm of {@link APISchema} went too. There is no - * replacement type and no replacement key. - * - * **Why.** Declared and inert, an island: no component schema extended - * `EventableSchema`, neither type had a zod mirror (so `objectui validate` had - * no path to the dialect), and nothing outside this file and the barrel read - * either one. Only `tsc` said yes, which invited authors to write a handler - * dialect that no runtime dispatches. - * - * **The supported form.** An action is the declarative `ActionDef` object that - * `@object-ui/core`'s `ActionRunner` executes, and a control that runs - * something is the `action:button` node type (AGENTS.md, commandment #4). - * Runtime callbacks stay the programmatic face. - */ - -/** - * Data fetching configuration - */ -export interface DataFetchConfig { - /** - * Data source API - */ - api: string | APIRequest; - /** - * Whether to fetch on mount - * @default true - */ - fetchOnMount?: boolean; - /** - * Polling interval in milliseconds - * If set, data will be refetched at this interval - */ - pollInterval?: number; - /** - * Dependencies for refetching - * Array of variable names to watch - */ - dependencies?: string[]; - /** - * Default data before fetch completes - */ - defaultData?: any; - /** - * Transform function for fetched data - * JavaScript expression or function name - */ - transform?: string; - /** - * Filter function for data - * JavaScript expression or function name - */ - filter?: string; - /** - * Sort configuration - */ - sort?: { - /** - * Field to sort by - */ - field: string; - /** - * Sort order - */ - order: 'asc' | 'desc'; - }; - /** - * Pagination configuration - */ - pagination?: { - /** - * Current page - */ - page?: number; - /** - * Page size - */ - pageSize?: number; - /** - * Whether pagination is enabled - */ - enabled?: boolean; - }; -} - -/** - * Component with data fetching - */ -export interface DataFetchableSchema extends BaseSchema { - /** - * Data fetching configuration - */ - dataSource?: DataFetchConfig; - /** - * Loading state - */ - loading?: boolean; - /** - * Error state - */ - error?: string | null; - /** - * Fetched data - */ - data?: any; -} - -/** - * Expression evaluation context - */ -export interface ExpressionContext { - /** - * Current component data - */ - data?: any; - /** - * Global application state - */ - state?: any; - /** - * Form values (when in form context) - */ - form?: any; - /** - * Current user information - */ - user?: any; - /** - * Environment variables - */ - env?: Record; - /** - * Utility functions - */ - utils?: Record any>; -} - -/** - * Expression schema for dynamic values - */ -export interface ExpressionNodeSchema { - /** - * Expression type - */ - type: 'expression'; - /** - * Expression string - * Supports ${} syntax for variable interpolation - */ - value: string; - /** - * Default value if expression fails - */ - defaultValue?: any; - /** - * Whether to watch and re-evaluate on context changes - * @default true - */ - reactive?: boolean; -} - -/** - * Union type of all API schemas - */ -export type APISchema = - | DataFetchableSchema - | ExpressionNodeSchema; diff --git a/ui/packages/types/src/index.ts b/ui/packages/types/src/index.ts index 9e7fa0ab02e..1b2e5a7ebc1 100644 --- a/ui/packages/types/src/index.ts +++ b/ui/packages/types/src/index.ts @@ -820,25 +820,48 @@ export { // See `packages/types/src/internal/retired-field-keys.ts` for the registry. // ============================================================================ -// API and Events - API Integration and Event Handling -// ============================================================================ -export type { - HTTPMethod, - APIRequest, - APIConfig, - // `UIEventHandler` and `EventableSchema` are GONE from this block, not - // emptied out of it: both were RETIRED in objectui#6497 (ADR-0049 - // enforce-or-remove, director ruling of 2026-09-24, maintainer verbatim - // 「同意」). Declared, unmirrored, unextended and unread, they only invited a - // handler dialect no runtime dispatches. The supported form is the - // declarative `ActionDef` object from `@object-ui/core`; the reasoning is the - // tombstone in `./api-types.ts`. - DataFetchConfig, - DataFetchableSchema, - ExpressionContext, - ExpressionNodeSchema, - APISchema, -} from './api-types.js'; +// API and Events — RETIRED (no block stands here any more) +// ============================================================================ +// #25921 (batch 9): the whole `./api-types.ts` module is DELETED, with its eight +// names `HTTPMethod`, `APIRequest`, `APIConfig`, `DataFetchConfig`, +// `DataFetchableSchema`, `ExpressionContext`, `ExpressionNodeSchema` and +// `APISchema`: TypeScript-only shapes no renderer, adapter or host read, in this +// workspace or in hotcrm. No replacement type; the changeset carries the FROM/TO. +// The `ExpressionContext` an expression runs against is `@object-ui/core`'s class. +// +// `UIEventHandler` and `EventableSchema` — RETIRED. This comment is the +// tombstone (it moved here from the deleted `./api-types.ts`): both were +// TypeScript interfaces, which erase and leave no runtime residue that could +// carry a marker of their own. +// +// RETIRED under ADR-0049 enforce-or-remove by the director-seat ruling recorded +// on objectui#6497 (2026-09-24, maintainer verbatim 「同意」): the re-priced +// option 2 of the three that card offered. ⛔ Not option 1 (mirror the dialect in +// zod, have component schemas extend it, build a dispatcher for it) and ⛔ not +// option 3 (leave it on the published surface). The ruling follows objectui#6182 +// (ruled A, 2026-08-25): an authored handler EXPRESSION is not a supported +// authoring form. +// +// What went: both exported interfaces and their barrel re-exports. +// `UIEventHandler` was an event-handler object: `event`, a `type` of +// `action | api | script | navigation | dialog | toast | custom`, one config +// member per type, then `condition`, `preventDefault`, `stopPropagation`, +// `debounce` and `throttle`. The action entries of its `dialog` member carried a +// recursive `handler?: UIEventHandler`, which went with it. `EventableSchema` extended +// `BaseSchema` with an `events` array and nine `on*` keys, each typed +// `UIEventHandler | string`. Its arm of the (since deleted) `APISchema` union +// went too. There is no replacement type and no replacement key. +// +// Why: declared and inert, an island: no component schema extended +// `EventableSchema`, neither type had a zod mirror (so `objectui validate` had no +// path to the dialect), and nothing outside its module and this barrel read +// either one. Only `tsc` said yes, which invited authors to write a handler +// dialect that no runtime dispatches. +// +// The supported form: an action is the declarative `ActionDef` object that +// `@object-ui/core`'s `ActionRunner` executes, and a control that runs something +// is the `action:button` node type (AGENTS.md, commandment #4). Runtime +// callbacks stay the programmatic face. // ============================================================================ // Union Types - Discriminated Unions for All Schemas