Skip to content

ComponentMeta at the registry: derive it from the one declaration, extend it under a named type - #6297

Merged
os-litant merged 2 commits into
mainfrom
claude/issue-6067-core-componentmeta-third-copy
Aug 25, 2026
Merged

ComponentMeta at the registry: derive it from the one declaration, extend it under a named type#6297
os-litant merged 2 commits into
mainfrom
claude/issue-6067-core-componentmeta-third-copy

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#6067

@object-ui/core's ComponentMeta no longer restates the canonical declaration. It is now derived from it, and tags / description reach the registration surface.

// packages/core/src/registry/Registry.tsimporttype{ComponentMetaasCanonicalComponentMeta}from'@object-ui/types';exporttypeRegistryComponentMetaExtras={tier?: 'public'|'internal';namespace?: string;skipFallback?: boolean;labelling?: 'control'|'group'|'display';};exporttypeComponentMeta=CanonicalComponentMeta&RegistryComponentMetaExtras;

1. Premise, re-derived on today's main — it holds

Re-derived from scratch at merge-base c456d91f4, not carried from the card.

Declaration census. A repo-wide search for a type / interface / class declaration of the exact name returns exactly two:

declarationform
packages/types/src/base.ts:511export interface ComponentMeta { — the canonical one
packages/core/src/registry/Registry.ts:37export type ComponentMeta = { — the structural copy

So core's is the only remaining structural copy, exactly as the 04:18Z triage comment graded it, and the count the first triage comment (16:29Z) asked to be re-verified on the merged ref is confirmed: #5893 collapsed packages/types' two onto one, and the card's title ("a THIRD declaration") is the pre-#5893 count.

Control probe for the census, because the whole task is counting declarations and a zero-hit is not a reading on its own: the same pattern run against the sibling type ComponentInput returns exactly one declaration (packages/types/src/base.ts:379) — the state #5671 left it in — and the pattern matches both the export type and the export interface spellings, which is where the card's own filing probe went wrong.

Key sets, re-counted — canonical 11, core 13, symmetric difference 6, all confirmed:

  • Only on the canonical type (2):tags, description
  • Only on core's (4):tier, namespace, skipFallback, labelling
  • Shared (9):label, icon, category, inputs, defaultProps, examples, isContainer, resizable, resizeConstraints — including resizeConstraints, whose six members were identical

2. The disposition: converge, not rename

The ruling admitted two resolutions. This PR converges, and the reason is that rename cannot be executed here without a contract break:

  • @object-ui/core is published, and ComponentMeta is part of its export surface: src/index.ts carries export * from './registry/Registry.js', and package.json maps "."./dist/index.d.ts.
  • Dropping the name would break every external consumer; keeping it as an alias would leave the mirror claim standing under a second spelling, which the ruling explicitly says fixes nothing.

The other rejected option was moving the four registry keys onto @object-ui/types' ComponentMeta and re-exporting outright, the way #5671 handled ComponentInput. skipFallback and namespace describe how the registry keys an entry, not what a component is, and @object-ui/types' ComponentMeta is the general, plugin-facing, AI-facing type. They stay where they are read, under their own named type.

Nothing is removed and nothing is renamed. All fifteen keys on the resulting type are writable; two of them are new.

3. The four registry-only keys ARE published behaviour with consumers

Requested by the dispatch as the measurement that decides whether converge-with-extension is safe. It is, and this is why a rename would not have been.

keywriters (in-repo, non-test)readerspublished-type consumers
namespace~137 registration call sites across packages/**Registry.ts:247, Registry.ts:315 — the bare-key fallback decision
skipFallback44 literal writes across 23 files (action-bar.tsx, action-button.tsx, record-approvals-renderer.tsx, …)Registry.ts:247, Registry.ts:315, same decision
labelling45 field widgets carry a decision via FIELD_WIDGET_LABELLING (packages/fields/src/index.tsx:2934); 14 of them (10 group + 4 display) write the key into the meta at index.tsx:3009'control' is spelled as absencepackages/components/src/renderers/form/form.tsx:446ComponentRegistry.getMeta(…)?.labellingpackages/fields/src/index.tsx:2936, packages/app-shell/…/DashboardWidgetInspector.tsx:581 and packages/app-shell/…/widgets.tsx:2547 all take an indexed accessComponentMeta['labelling'] off the type published by @object-ui/core
tier0 in-repo as a meta key — the in-repo opt-in is the PUBLIC_BLOCKS list; tier: 'public' is the documented per-registration opt-in (ADR-0080)Registry.ts:560, Registry.ts:564 (getPublicConfigs), packages/sdui-parser/src/index.ts:148 (publicOnly)

labelling additionally appears in three shipped CHANGELOGs as "@object-ui/coreComponentMeta gains labelling?: 'control' \| 'group'", so it is published behaviour on the record, not merely in-repo usage.

Direct importers of the type itself: packages/fields/src/index.tsx:11, packages/app-shell/…/widgets.tsx:44, packages/app-shell/…/DashboardWidgetInspector.tsx:33.

4. The measurement that shaped the pin: extends is a ghost here

Every member of both shapes is optional, so a type with fewer optional members is assignable to one with more and vice versa. Mutual assignability therefore holds across the diverged pair — an extends-based mirror assertion is green on the defect and could never have caught it.

Measured with a TypeScript program resolved against the emitted .d.ts of both packages (packages/types/dist/index.d.ts and packages/core/dist/registry/Registry.d.ts), before and after:

readingbefore (diverged)after (this PR)
Core extends Canonicaltruetrue
Canonical extends Coretruetrue
Exclude<keyof Canonical, keyof Core>"tags" | "description"never
Exclude<keyof Core, keyof Canonical>"tier" | "namespace" | "skipFallback" | "labelling"unchanged

Exactly one reading moved. That reading is the pin; the assignability pair is kept beside it in the test, labelled, as the control that demonstrates the contrast.

This also means the triage wording "asserting a mirror relationship that is false in both directions" is true of the key sets and false of TypeScript assignability. Recorded because acting on the assignability reading would have produced a test that cannot fail.

5. Pinning against the emitted declaration, not the source

The dispatch flagged the #6267 trap: a source-level assertion passing while the shipped .d.ts is wrong. Measured rather than assumed for this package:

  • @object-ui/core's build is a bare tsc, not a .d.ts bundler, so a module re-export survives into the emit rather than being inlined. Natural control:ComponentInput: re-export the one declaration instead of restating it three times #5671's export type { ComponentInput } from '@object-ui/types'; appears verbatim at dist/registry/Registry.d.ts:31 on the pre-change tree. After this PR, dist/registry/Registry.d.ts likewise carries import type { ComponentMeta as CanonicalComponentMeta } from '@object-ui/types'; and export type ComponentMeta = CanonicalComponentMeta & RegistryComponentMetaExtras; — so the shipped declaration references the canonical one by module specifier. There is one declaration of the shared eleven in the published artifact, not a copy of it.
  • The type-level assertions in the new test are compiled by packages/core/tsconfig.test.json, which sets "paths": {} so @object-ui/types resolves through the workspace dependency's built dist/index.d.ts. That project is chained from this package's type-check script, and turbo's type-check task dependsOn: ["^build"], so CI's Type Check job builds the dependency before compiling it. The canonical half of every assertion is therefore read off the emitted declaration.
  • Deliberately not asserted: anything read out of packages/core/dist. CI's test job runs pnpm test (root vitest run) with no build ahead of it at all, so a dist-reading assertion would be absent-or-red depending on whether someone ran a build — the standard this repo already records in src/actions/__tests__/actionKeys.types.test.ts: an assertion whose colour depends on whether someone ran a build is not a pin. The packages/core/dist half is covered by the out-of-band measurement above and reported here rather than encoded as a green-by-luck test.

6. Evidence — per-point ablation

Direction predicted before each run; both predictions held. Each ablation restored under trap … EXIT INT TERM with a cwd-independent git -C … checkout HEAD --, and each restore printed an empty git diff HEAD --stat. Mutations proved on disk by grepping the injected and the removed text separately, with anchor uniqueness asserted before the edit. Committed before ablating.

A. Revert only the convergence (Registry.ts back to origin/main; test and changeset kept)

Predicted: the key-set pin and the tags/description counter-probe go red; the assignability control stays green.

tsc -p tsconfig.test.jsonexit 2, six diagnostics, all naming the pin file:

(81,30): TS2305 Module '"../Registry.js"' has no exported member 'RegistryComponentMetaExtras'.
(101,11): TS2322 Type 'true' is not assignable to type 'false'. <- the key-set pin
(122,11): TS2322 Type 'true' is not assignable to type 'false'.
(166,7): TS2353 Object literal may only specify known properties, and 'tags' does not exist in type 'ComponentMeta'.
(170,25): TS2339 Property 'tags' does not exist on type 'ComponentMeta'.
(171,25): TS2339 Property 'description' does not exist on type 'ComponentMeta'.

Root vitestexit 1, Tests 2 failed | 5 passed (7): imports the canonical declaration instead of restating it, declares none of the canonical members locally.

Still passing after the revert — reported because it is the point of the exercise:

  • is mutually assignable with the canonical declarationno diagnostic at all under tsc, and green under vitest. This is the ghost, demonstrated on the real defect.
  • adds exactly the four registry-only keys, named (line 113) — no diagnostic: the pre-convergence type also carried exactly those four, so this assertion is correctly indifferent to the convergence.
  • still declares the four registry-only members here — green: the old declaration still declared them.
  • Both type-level tests and the tags/description counter-probe pass under vitest, because annotations are erased there. tsc is their enforcement, which is why both legs are reported.

B. Delete exactly one registry-only key (labelling) from RegistryComponentMetaExtras

Predicted: the named-keys assertion goes red while the canonical-key pin stays green — proving the two are independent instruments, not one assertion written twice.

Anchor asserted unique (1 occurrence) before the edit; landing site 1 file changed, 1 deletion(-).

tsc -p tsconfig.test.jsonexit 2, three diagnostics:

(115,11): TS2322 Type 'true' is not assignable to type 'false'. <- registryOnlyKeys
(162,7): TS2353 … 'labelling' does not exist in type 'ComponentMeta'.
(180,20): TS2339 Property 'labelling' does not exist on type 'ComponentMeta'.

Root vitestexit 1, Tests 1 failed | 6 passed (7): still declares the four registry-only members here.

Still passing:leaves no canonical key unreachable at the registration surface (line 101 — no diagnostic), the assignability control, and — informatively — extrasSupplyThem (line 122), which compares the extras type against itself and so shrinks with it. That contrast is exactly why the four keys are pinned to a literal union as well.

7. Gates run locally

All exit codes captured before any pipe. Union run at 8ef81a944, the final commit.

gateresult
turbo run build --filter=@object-ui/core --forceexit 0 — 2 successful, 2 total
pnpm --filter @object-ui/core type-check (tsc --noEmit && tsc -p tsconfig.test.json)exit 0
pnpm exec vitest run packages/core/ (repo root)exit 0 — Test Files 100 passed (100), Tests 2023 passed (2023)
pnpm exec vitest run packages/core/src/registry/__tests__/component-meta-derives-from-canonical.test.tsexit 0 — Tests 7 passed (7)
turbo run type-check --filter='...@object-ui/core' --filter='!@object-ui/site' --forceexit 0 — Tasks: 71 successful, 71 total
node scripts/check-changeset-presence.mjsexit 0 — "1 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)"
node scripts/check-changeset-no-major.mjsexit 0 — "No changeset declares a major bump."
pnpm --filter @object-ui/core lintexit 0 — 0 errors (515 pre-existing no-explicit-any warnings; the new test file contributes none)
node scripts/check-control-bytes.mjsexit 0 — "scanned 5182 tracked text file(s)"
node scripts/check-type-check-coverage.mjsexit 0 — "41/41 packages compile their tests"
node scripts/check-lint-coverage.mjsexit 0 — "46/46 packages linted"
node scripts/check-phantom-dependencies.mjsexit 0
node scripts/check-package-self-import.mjsexit 0
node scripts/check-vi-mock-specifiers.mjsexit 0
node scripts/check-doc-component-types.mjsexit 0 — "Every documented component type is registered."
node scripts/check-shell-escape-residue.mjsexit 0

Filter direction demonstrated, not asserted — the consumer direction is the prefix form, and it is the one used above:

pnpm --filter '...@object-ui/core' → 38 packages (core + 37 dependents)
pnpm --filter '@object-ui/core...' → 2 packages (core + @object-ui/types, its dependency)

Declared narrowings.pnpm test / pnpm lint / pnpm type-check repo-wide, check:readme-exports, check:doc-snippets, check:esm-specifiers, check:node-esm-load, check:published-dist and check:eager-closure were not run locally; CI runs the farm regardless. The downstream type-check row above is the load-bearing one for a published-type change and it was run in full. @object-ui/site is excluded from the downstream row for runtime; it consumes @object-ui/core only through documentation snippets, which check:doc-snippets covers in CI.

8. Scope

  • Files touched:packages/core/src/registry/Registry.ts, packages/core/src/registry/__tests__/component-meta-derives-from-canonical.test.ts, .changeset/6067-component-meta-derive-from-canonical.md. Nothing outside packages/core/src/registry/** plus the mandatory changeset.
  • packages/types was not edited. Convergence did not require it: the canonical declaration already carries everything core needed, so importing it was sufficient. That package is held by fix(types): StackSchema ships its declared members instead of collapsing under BaseSchema's index signature #6267.
  • No docs edit is owed.content/docs/guide/component-registry.md is the only doc that names ComponentMeta; it shows a registration literal and does not enumerate the key set, so nothing it states became false. Enumerating the newly reachable keys there would be a docs change outside this card's file surface.
  • PR stays draft. No ready flip, no merge queue, no auto-merge.

Out-of-scope finding, not fixed here

ComponentConfig is the same species one type down: packages/core/src/registry/Registry.ts:141 declares export type ComponentConfig<T = any> = ComponentMeta & { … } while packages/types/src/base.ts:578 declares export interface ComponentConfig extends ComponentMeta { … } — two same-named published declarations, differing in genericity and in which ComponentMeta half they build on. This PR reduces it (the shared eleven are now single-sourced through ComponentMeta on both) without closing it. Filed separately, unassigned, as a finding. #4631 does not cover it — that card is about a component type's three disagreeing surfaces (schema type / registry inputs / renderer reads), and names ComponentConfig nowhere.


Generated by Claude Code

…aration
`packages/core/src/registry/Registry.ts` carried its own thirteen-key
`ComponentMeta`: nine members restated from `@object-ui/types`' `base.ts`, four
registry-only keys added here, and `tags` / `description` absent — though both
are declared on the canonical type and on the `ComponentMetaSchema` zod mirror.
Two of the three authorities agreed and the registration surface did not, so
those two keys were unwritable at exactly the declaration most component
registrations import. Same two-key delta objectui#5893 closed inside
`@object-ui/types`, on a third declaration.
The nine shared members are no longer restated. `ComponentMeta` is now
`CanonicalComponentMeta & RegistryComponentMetaExtras`, where the newly exported
`RegistryComponentMetaExtras` carries `tier` / `namespace` / `skipFallback` /
`labelling` — the four keys that are genuinely registry mechanics and have live
consumers. Nothing is removed or renamed; `tags` and `description` are added.
Pinned by key set rather than by assignability. Every member of both shapes is
optional, so `extends` is mutually true across the diverged pair and an
assignability assertion is green on the defect. Measured on the emitted `.d.ts`
of both packages, `Exclude<keyof Canonical, keyof Core>` moved from
`"tags" | "description"` to `never` while both `extends` readings stayed `true`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mn4BZ5AVDM81pvfij1WwM9
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3222.7 KB3266.6 KB
Main entry chunk (gzip)154.1 KB350 KB
Entry fileindex-BiWtLRaE.js
StatusPASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)10.96KB4.16KB
app-shell (runtime-config.js)18.10KB6.51KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)505.63KB114.68KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)171.74KB47.48KB
fields (index.js)238.40KB59.89KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.53KB3.38KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.64KB1.50KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)1.93KB0.88KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.66KB18.32KB
plugin-chatbot (index.js)188.21KB44.67KB
plugin-dashboard (index.js)133.35KB34.45KB
plugin-designer (index.js)212.33KB42.81KB
plugin-detail (index.js)244.74KB62.20KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)126.42KB30.80KB
plugin-gantt (index.js)164.17KB39.89KB
plugin-grid (index.js)201.14KB54.40KB
plugin-kanban (index.js)52.83KB14.55KB
plugin-list (index.js)111.94KB27.24KB
plugin-map (index.js)20.09KB6.62KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.49KB11.93KB
plugin-timeline (index.js)26.49KB7.59KB
plugin-tree (index.js)9.26KB3.13KB
plugin-view (index.js)84.55KB20.74KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)54.84KB18.43KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.35KB0.70KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)12.13KB3.65KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)7.54KB2.63KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.49KB2.14KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@os-litantClaude

Copy link
Copy Markdown
CollaboratorAuthor

The out-of-scope finding named at the end of the description is filed as #6298 (finding, unassigned) — ComponentConfig, the same two-published-declarations shape one type down. This PR reduces half of that delta (the shared eleven members become single-sourced through ComponentMeta on both sides) and closes none of it.

Also: the downstream consumer type-check row in the description was re-run at the final commit 8ef81a944 after the test and changeset were added — turbo run type-check --filter='...@object-ui/core' --filter='!@object-ui/site' --force → exit 0, Tasks: 71 successful, 71 total.


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3222.7 KB3266.6 KB
Main entry chunk (gzip)154.1 KB350 KB
Entry fileindex-BiWtLRaE.js
StatusPASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)10.96KB4.16KB
app-shell (runtime-config.js)18.10KB6.51KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)505.63KB114.68KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)171.74KB47.48KB
fields (index.js)238.40KB59.89KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.53KB3.38KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.64KB1.50KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)1.93KB0.88KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.66KB18.32KB
plugin-chatbot (index.js)188.21KB44.67KB
plugin-dashboard (index.js)133.35KB34.45KB
plugin-designer (index.js)212.33KB42.81KB
plugin-detail (index.js)244.74KB62.20KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)126.42KB30.80KB
plugin-gantt (index.js)164.17KB39.89KB
plugin-grid (index.js)201.14KB54.40KB
plugin-kanban (index.js)52.83KB14.55KB
plugin-list (index.js)111.94KB27.24KB
plugin-map (index.js)20.09KB6.62KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.49KB11.93KB
plugin-timeline (index.js)26.49KB7.59KB
plugin-tree (index.js)9.26KB3.13KB
plugin-view (index.js)84.55KB20.74KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)54.84KB18.43KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.35KB0.70KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)12.13KB3.65KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)7.54KB2.63KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.49KB2.14KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@os-litant
os-litant marked this pull request as ready for review August 25, 2026 10:53
@os-litant
os-litant added this pull request to the merge queueAug 25, 2026
Merged via the queue into main with commit 44d075bAug 25, 2026
28 checks passed
@os-litant
os-litant deleted the claude/issue-6067-core-componentmeta-third-copy branch August 25, 2026 11:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-litant@claude