From 643031bf288f5f6bbd7cc6982048b911ab30a58b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 6 Nov 2026 15:18:46 +0000 Subject: [PATCH] refactor(types)!: delete the api-types module and its eight names nothing reads The whole ui/packages/types/src/api-types.ts module goes, with the barrel's "API and Events" block: HTTPMethod, APIRequest, APIConfig, DataFetchConfig, DataFetchableSchema, ExpressionContext, ExpressionNodeSchema and APISchema. None has a reader in the workspace or in hotcrm; the ExpressionContext hits elsewhere are core's own class. The objectui#6497 tombstone the module carried moves into the barrel where the block stood, and the 6497 pin now asserts the declaring file is gone, keeps its barrel legs with lit controls on BaseSchema / AnySchema, and reads the tombstone from the barrel. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01L9qibzeiKfRPSysJDdZzQL --- .changeset/25921-types-api-block.md | 19 + .../eventable-schema-retired-6497.test.ts | 106 +++--- ui/packages/types/src/api-types.ts | 342 ------------------ ui/packages/types/src/index.ts | 61 +++- 4 files changed, 119 insertions(+), 409 deletions(-) create mode 100644 .changeset/25921-types-api-block.md delete mode 100644 ui/packages/types/src/api-types.ts 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