diff --git a/packages/data-objectstack/README.md b/packages/data-objectstack/README.md index da20ba7729..dffebf8293 100644 --- a/packages/data-objectstack/README.md +++ b/packages/data-objectstack/README.md @@ -23,6 +23,9 @@ npm install @object-ui/data-objectstack ```typescript import { createObjectStackAdapter } from '@object-ui/data-objectstack'; import { SchemaRenderer } from '@object-ui/react'; +import type { ComponentSchema } from '@object-ui/types'; + +declare const mySchema: ComponentSchema; // 1. Create the adapter const dataSource = createObjectStackAdapter({ @@ -41,9 +44,21 @@ function App() { } ``` +> **Reaching the adapter-only API from TypeScript.** `createObjectStackAdapter` +> declares `DataSource` as its return type, so the members below that belong to the +> adapter rather than to every data source — `getClient`, the cache methods, the +> connection-state and batch-progress subscriptions — are not on the type the factory +> hands back, even though they are on the object it hands back. Until +> [#7323](https://github.com/objectstack-ai/objectui/issues/7323) is settled, hold the +> adapter as `ObjectStackAdapter` (the exported class, whose constructor is documented +> under **API Reference** below) wherever you use those members; the examples in this +> README do exactly that. + ### Advanced Configuration ```typescript +import { createObjectStackAdapter } from '@object-ui/data-objectstack'; + const dataSource = createObjectStackAdapter({ baseUrl: 'https://api.example.com', token: 'your-api-token', @@ -78,6 +93,10 @@ ObjectStack's native query format, so a schema never has to be written in the protocol's own shape: ```typescript +import type { ObjectStackAdapter } from '@object-ui/data-objectstack'; + +declare const dataSource: ObjectStackAdapter; + // Query with filters (MongoDB-like operators) const result = await dataSource.find('tasks', { $filter: { @@ -92,7 +111,7 @@ const result = await dataSource.find('tasks', { // Escape hatch: reach the underlying ObjectStack client for anything // the DataSource interface does not cover const client = dataSource.getClient(); -const metadata = await client.meta.getObject('task'); +const metadata = await client.meta.getItem('object', 'task'); ``` ### Query Parameter Mapping @@ -186,6 +205,10 @@ array that the spec's own `isFilterAST` gate rejects is refused here rather than shipped: ```typescript +import type { ObjectStackAdapter } from '@object-ui/data-objectstack'; + +declare const dataSource: ObjectStackAdapter; + // ✅ lowered — reaches the wire unchanged await dataSource.aggregate('opportunity', { groupBy: ['stage'], @@ -215,6 +238,10 @@ declares), and an empty array (`[]` means "no filter"). ### Sorting ```typescript +import type { ObjectStackAdapter } from '@object-ui/data-objectstack'; + +declare const dataSource: ObjectStackAdapter; + // OData-style await dataSource.find('users', { $orderby: { @@ -231,6 +258,10 @@ await dataSource.find('users', { The adapter includes built-in metadata caching to improve performance when fetching schemas: ```typescript +import type { ObjectStackAdapter } from '@object-ui/data-objectstack'; + +declare const dataSource: ObjectStackAdapter; + // Get cache statistics const stats = dataSource.getCacheStats(); console.log(`Cache hit rate: ${stats.hitRate * 100}%`); @@ -257,6 +288,10 @@ dataSource.clearCache(); The adapter provides real-time connection state monitoring with automatic reconnection: ```typescript +import type { ObjectStackAdapter } from '@object-ui/data-objectstack'; + +declare const dataSource: ObjectStackAdapter; + // Monitor connection state changes const unsubscribe = dataSource.onConnectionStateChange((event) => { console.log('Connection state:', event.state); @@ -301,6 +336,12 @@ The adapter automatically attempts to reconnect on connection failures: Track progress of bulk operations in real-time: ```typescript +import type { ObjectStackAdapter } from '@object-ui/data-objectstack'; + +declare const dataSource: ObjectStackAdapter; + +declare const largeDataset: Array>; + // Monitor batch operation progress const unsubscribe = dataSource.onBatchProgress((event) => { console.log(`${event.operation}: ${event.percentage.toFixed(1)}%`); @@ -358,24 +399,36 @@ import { ### Error Handling Example ```typescript +import { + ObjectStackError, + MetadataNotFoundError, + ConnectionError, + AuthenticationError, + type ObjectStackAdapter, +} from '@object-ui/data-objectstack'; + +declare const dataSource: ObjectStackAdapter; + try { const schema = await dataSource.getObjectSchema('users'); } catch (error) { if (error instanceof MetadataNotFoundError) { - console.error(`Schema not found: ${error.details.objectName}`); + console.error(`Schema not found: ${error.details?.objectName}`); } else if (error instanceof ConnectionError) { console.error(`Connection failed to: ${error.url}`); } else if (error instanceof AuthenticationError) { console.error('Authentication required'); } - - // All errors have consistent structure - console.error({ - code: error.code, - message: error.message, - statusCode: error.statusCode, - details: error.details - }); + + // Every error this adapter throws carries the same shape + if (error instanceof ObjectStackError) { + console.error({ + code: error.code, + message: error.message, + statusCode: error.statusCode, + details: error.details, + }); + } } ``` @@ -384,6 +437,12 @@ try { Bulk operations provide detailed error reporting with partial success information: ```typescript +import { BulkOperationError, type ObjectStackAdapter } from '@object-ui/data-objectstack'; + +declare const dataSource: ObjectStackAdapter; + +declare const records: Array>; + try { await dataSource.bulk('users', 'update', records); } catch (error) { @@ -420,6 +479,10 @@ All errors include unique error codes for programmatic handling: The adapter supports optimized batch operations with automatic fallback: ```typescript +import type { ObjectStackAdapter } from '@object-ui/data-objectstack'; + +declare const dataSource: ObjectStackAdapter; + // Batch create const newUsers = await dataSource.bulk('users', 'create', [ { name: 'Alice', email: 'alice@example.com' }, @@ -453,6 +516,10 @@ writes as a single all-or-nothing unit — the master-detail case, where a paren and its children must commit or roll back together — use `batchTransaction`: ```typescript +import type { ObjectStackAdapter } from '@object-ui/data-objectstack'; + +declare const dataSource: ObjectStackAdapter; + // Create a parent and a child that references it, atomically. // `{ $ref: 0 }` resolves to the id minted by operation 0 (the parent). await dataSource.batchTransaction([ @@ -515,9 +582,12 @@ In addition to the main `DataSource` adapter, this package ships persist per-user UI state (favorites, recent items) into ObjectStack. ```typescript -import { createObjectStackUserStateAdapter } from '@object-ui/data-objectstack'; +import { createObjectStackUserStateAdapter, type ObjectStackAdapter } from '@object-ui/data-objectstack'; import { useAttachUserStateAdapters } from '@object-ui/app-shell'; +declare const dataSource: ObjectStackAdapter; +declare const user: { id: string }; + const favoritesAdapter = createObjectStackUserStateAdapter({ dataSource, // the ObjectStack DataSource userId: user.id, @@ -526,6 +596,8 @@ const favoritesAdapter = createObjectStackUserStateAdapter({ // onError: (op, err) => console.warn(`[user-state] ${op} failed`, err), }); +const attach = useAttachUserStateAdapters(); + attach('favorites', favoritesAdapter); ``` @@ -560,6 +632,8 @@ for the full design. #### Constructor + + ```typescript new ObjectStackAdapter(config: { baseUrl: string; @@ -613,6 +687,10 @@ new ObjectStackAdapter(config: { #### Schema Not Found ```typescript +import type { ObjectStackAdapter } from '@object-ui/data-objectstack'; + +declare const dataSource: ObjectStackAdapter; + // Error: MetadataNotFoundError // Solution: Verify object name and ensure schema exists on server const schema = await dataSource.getObjectSchema('correct_object_name'); @@ -621,6 +699,8 @@ const schema = await dataSource.getObjectSchema('correct_object_name'); #### Connection Errors ```typescript +import { createObjectStackAdapter } from '@object-ui/data-objectstack'; + // Error: ConnectionError // Solution: Check baseUrl and network connectivity const dataSource = createObjectStackAdapter({ @@ -632,6 +712,10 @@ const dataSource = createObjectStackAdapter({ #### Cache Issues ```typescript +import type { ObjectStackAdapter } from '@object-ui/data-objectstack'; + +declare const dataSource: ObjectStackAdapter; + // Clear cache if stale data is being returned dataSource.clearCache(); diff --git a/packages/plugin-form/README.md b/packages/plugin-form/README.md index 4360541f4b..e3577cfa25 100644 --- a/packages/plugin-form/README.md +++ b/packages/plugin-form/README.md @@ -294,6 +294,8 @@ field. A field may declare both, and it is coherent authoring — storage-level required, with the value guaranteed by the producer: + + ```ts remind_at: Field.datetime({ required: true, defaultValue: 'NOW()' }), ``` @@ -310,6 +312,8 @@ predicate says "required in this state", but `NOW()` / `current_user` resolve at insert regardless of state, so the producer's guarantee covers the conditional claim exactly as it covers the unconditional one: + + ```ts remind_at: Field.datetime({ requiredWhen: 'record.status == "scheduled"', defaultValue: 'NOW()' }), ``` @@ -331,6 +335,11 @@ The two halves of that verdict are importable, so a host with its own form renderer applies the same rule rather than re-deriving it (objectui#6059): ```typescript +declare const field: { required?: unknown; defaultValue?: unknown }; +declare const isCreateForm: boolean; +declare const values: Record; +declare const objectSchema: { fields?: Record }; + import { isRequiredInForm, omitServerResolvedDefaults } from '@object-ui/plugin-form'; // Should this create form enforce `required` on the field? @@ -419,6 +428,8 @@ strands every section but the first outside the submit, and (in tabs) lets the inactive panel unmount with its values — declare tabs on the single form and let the renderer distribute the fields: + + ```typescript { type: 'form', @@ -551,6 +562,8 @@ The same rule for side-by-side panels: the `
` wraps the whole panel group and each pane holds only fields, so one react-hook-form instance spans the divider. + + ```typescript { type: 'form', @@ -853,6 +866,7 @@ and hands them to your `onSubmit`, which the renderer awaits whatever that function does: ```typescript +import { createObjectStackAdapter } from '@object-ui/data-objectstack'; import type { FormSchema } from '@object-ui/types'; const dataSource = createObjectStackAdapter({ diff --git a/packages/plugin-view/README.md b/packages/plugin-view/README.md index 384849bafd..822c22cf03 100644 --- a/packages/plugin-view/README.md +++ b/packages/plugin-view/README.md @@ -229,6 +229,8 @@ schema.pageSize`; `if (schema.selection?.type) … else if (schema.selectable the pair itself: ```typescript +import type { ObjectViewSchema } from '@object-ui/types'; + const schema: ObjectViewSchema = { type: 'object-view', objectName: 'products', @@ -259,7 +261,9 @@ from `table.fields` (objectui#5269, open). Toggle between multiple view configurations: ```typescript -{ +import type { ViewSwitcherSchema } from '@object-ui/types'; + +const viewSwitcher: ViewSwitcherSchema = { type: 'view-switcher', views: [ { type: 'grid', label: 'Grid', schema: { type: 'text', content: 'Grid content' } }, @@ -270,7 +274,7 @@ Toggle between multiple view configurations: position: 'top', persistPreference: true, storageKey: 'my-view-switcher' -} +}; ``` ### FilterUI @@ -278,7 +282,9 @@ Toggle between multiple view configurations: Render a filter toolbar with multiple field types: ```typescript -{ +import type { FilterUISchema } from '@object-ui/types'; + +const filterUi: FilterUISchema = { type: 'filter-ui', layout: 'popover', showApply: true, @@ -291,7 +297,7 @@ Render a filter toolbar with multiple field types: ] }, { field: 'created_at', label: 'Created', type: 'date-range' } ] -} +}; ``` ### SortUI @@ -299,7 +305,9 @@ Render a filter toolbar with multiple field types: Configure sorting with dropdowns or buttons: ```typescript -{ +import type { SortUISchema } from '@object-ui/types'; + +const sortUi: SortUISchema = { type: 'sort-ui', variant: 'dropdown', multiple: true, @@ -308,7 +316,7 @@ Configure sorting with dropdowns or buttons: { field: 'created_at', label: 'Created At' } ], sort: [{ field: 'name', direction: 'asc' }] -} +}; ``` ## Examples @@ -319,6 +327,8 @@ The list is always rendered; `defaultViewType` picks which renderer draws it, and `table` configures the grid: ```typescript +import type { ObjectViewSchema } from '@object-ui/types'; + const schema: ObjectViewSchema = { type: 'object-view', objectName: 'users', @@ -341,6 +351,8 @@ Create and edit share one record surface. `layout` chooses where it opens and no authored `mode`: ```typescript +import type { ObjectViewSchema } from '@object-ui/types'; + const schema: ObjectViewSchema = { type: 'object-view', objectName: 'users', @@ -364,6 +376,11 @@ row. `navigation.mode` decides how, and `onNavigate` is what hands a page-mode record off to your router: ```typescript +import type { ObjectViewSchema } from '@object-ui/types'; + +// your application's router +declare const router: { push: (href: string) => void }; + const schema: ObjectViewSchema = { type: 'object-view', objectName: 'users', @@ -392,6 +409,8 @@ not wire handlers for them — you switch them on or off with `operations`, and Both default to on, and the new-record form opens on the `layout` surface: ```typescript +import type { ObjectViewSchema } from '@object-ui/types'; + const schema: ObjectViewSchema = { type: 'object-view', objectName: 'products', @@ -411,6 +430,8 @@ Search, filter and sort are toolbar toggles; column set, filter, sort and page size live in `table`: ```typescript +import type { ObjectViewSchema } from '@object-ui/types'; + const schema: ObjectViewSchema = { type: 'object-view', objectName: 'products', @@ -430,6 +451,8 @@ Saved views are `listViews`, keyed by view name, with `defaultListView` selecting which opens first: ```typescript +import type { ObjectViewSchema } from '@object-ui/types'; + const schema: ObjectViewSchema = { type: 'object-view', objectName: 'products', @@ -451,6 +474,8 @@ Editing is reached from a row's edit action; `operations.update` is what gates it. The edited record is chosen by the click, never by an authored `recordId`: ```typescript +import type { ObjectViewSchema } from '@object-ui/types'; + const schema: ObjectViewSchema = { type: 'object-view', objectName: 'products', @@ -468,6 +493,8 @@ Under `layout: 'page'` this becomes `onNavigate(recordId, 'edit')`. no `enableDelete` key and no `onDelete` callback: ```typescript +import type { ObjectViewSchema } from '@object-ui/types'; + const schema: ObjectViewSchema = { type: 'object-view', objectName: 'products', @@ -518,6 +545,8 @@ that is what makes the view "automatic". What the schema node chooses is **which** fields appear and how they are grouped: ```typescript +import type { ObjectViewSchema } from '@object-ui/types'; + const schema: ObjectViewSchema = { type: 'object-view', objectName: 'users', @@ -547,6 +576,8 @@ There is no `nestedFields` key. A child collection is declared as a **subform** on the record form, which is where an order's line items belong: ```typescript +import type { ObjectViewSchema } from '@object-ui/types'; + const schema: ObjectViewSchema = { type: 'object-view', objectName: 'orders', @@ -576,6 +607,8 @@ the **saved-view** tab bar: declare the views and render `` (or let a host such as `@object-ui/app-shell` do it): ```typescript +import type { ObjectViewSchema } from '@object-ui/types'; + const schema: ObjectViewSchema = { type: 'object-view', objectName: 'users', diff --git a/scripts/check-doc-snippet-types.mjs b/scripts/check-doc-snippet-types.mjs index 196313e345..424636f2c2 100644 --- a/scripts/check-doc-snippet-types.mjs +++ b/scripts/check-doc-snippet-types.mjs @@ -475,8 +475,6 @@ const UNGATED_DOCS = { 'the documented override flow did not compile. It now returns `DeepMutable` and that ' + 'diagnostic is gone. Covering this page still needs the 5 undefined-name blocks made ' + 'self-contained or declared, plus a way to declare a block whose rejection IS the point.', - 'packages/data-objectstack/README.md': - '10 parse diagnostic(s) — blocks fenced `ts` that are bare object literals or elided bodies; 41 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines', 'packages/fields/README.md': '2 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines; 1 unresolved-module diagnostic(s)', 'packages/i18n/README.md': @@ -503,8 +501,6 @@ const UNGATED_DOCS = { '5 parse diagnostic(s) — blocks fenced `ts` that are bare object literals or elided bodies; 15 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines', 'packages/plugin-editor/README.md': '6 parse diagnostic(s) — blocks fenced `ts` that are bare object literals or elided bodies', - 'packages/plugin-form/README.md': - '12 parse diagnostic(s) — blocks fenced `ts` that are bare object literals or elided bodies; 1 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines', 'packages/plugin-gantt/README.md': '9 parse diagnostic(s) — blocks fenced `ts` that are bare object literals or elided bodies; 12 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines', 'packages/plugin-kanban/README.md': @@ -519,8 +515,6 @@ const UNGATED_DOCS = { '16 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines; plus TS1108x1 — candidate real defects, un-triaged', 'packages/plugin-tree/README.md': '3 parse diagnostic(s) — blocks fenced `ts` that are bare object literals or elided bodies', - 'packages/plugin-view/README.md': - '14 parse diagnostic(s) — blocks fenced `ts` that are bare object literals or elided bodies; 14 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines', 'packages/providers/README.md': '7 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines; plus TS2741x1 — candidate real defects, un-triaged', 'packages/react-runtime/README.md':