Skip to content

fix(app-shell): stop the flow node inspector writing a spec-refused description, and converge the duplicated node/edge shapes - #6330

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-6287-flownode-description-key
Aug 25, 2026
Merged

fix(app-shell): stop the flow node inspector writing a spec-refused description, and converge the duplicated node/edge shapes#6330
os-support-ai merged 2 commits into
mainfrom
claude/issue-6287-flownode-description-key

Conversation

@claude

@claudeclaudeBot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Fixes#6287

The card is right that FlowNodeInspector's local FlowNode admits a key the strict contract refuses. What the measurements changed is what that costs and where the fix has to land: this is not type hygiene, it is a live UI control that made flows unsavable, and the type-only version of the fix would have been a ghost.

What was measured first

Both premise probes reproduced against the installed @objectstack/spec@17.2.0 (lockfile read, not the ^17.0.0 specifier: single resolution 17.2.0(ai@7.0.65(zod@4.4.3)), on-disk 17.2.0), each with a positive control so a refusal cannot be an artefact of a broken probe:

safeParse({ id, type, label, description, config }) -> unrecognized_keys: ["description"]
safeParse({ id, type, config }) -> invalid_type at path ["label"]
safeParse({ id, type, label }) -> PARSES (control)

FlowNodeSchema's authorable surface is exactly eleven keys — id type label config connectorConfig position timeoutMs inputSchema outputSchema waitEventConfig boundaryConfig — with no note key of any spelling. So the premise holds, and the premise fork does not open: there is no reader for a node description to grow into, nothing in metadata-admin reads node.description back, and adding one to the spec would be a new authoring surface with zero measured consumers.

The part the card did not have: the type was describing a live producer

FlowNodeInspector.tsx:373 rendered a Description text field whose onCommit wrote patchNode({ description: v || undefined }). By this package's own established reading of .strict(), that is not untidiness:

a draft carrying ui is unsavable, not merely untidy: FlowSchema's node is .strict() (objectstack#4001), so the key surfaces as unrecognized_keys in the live client validation and as a 422 on save
flow-canvas-layout.withCanonicalGeometry, on the identical retired-key case

description is refused by that same mechanism, measured above. So every keystroke in that box made the flow unsavable, and nothing read the value back. The field is removed, and its two now-dead locale entries with it.

Stored flows heal on the author's first edit. Removing the field alone would have made a pre-existing bad state unrecoverable — an author who had already saved a description would have had no control left to clear it. All three node write paths (patchNode, setField, commitAdvanced) now strip it, the same migrate-on-write boundary withCanonicalGeometry gives the retired ui geometry. Deliberately a named key rather than "everything the spec does not list": the index signature is load-bearing (the canvas round-trips node properties this layer does not understand), so a blanket strip would be exactly the data loss that type exists to prevent.

Why the obvious fix would have been a ghost — measured, twice

  1. The local copy is not the type the value flows through.const node = loc?.node ?? null is FlowNodeLike (exported from flow-nested-selection.ts), a third copy of the shape carrying the same description?: string. Narrowing only FlowNodeInspector's copy would have changed no read in the file.
  2. The index signature absorbs the key in both worlds. With [k: string]: unknown on the shape, an object literal carrying description type-checks before and after. A @ts-expect-error negative test does not go red before the fix — it goes red after it, as an unused directive. That trap is documented in the new test's header so the next reader does not re-lay it.

So the pin is placed where the two worlds actually differ, and was proved red before the fix:

  • Compile time — the declared members of the node read type, index signature stripped, must be a subset of the spec's own FlowNode keys. Red before: tsc exit 2, one error, FlowNodeInspector.specKeys.test.tsx(158,33): error TS2344: Type 'false' does not satisfy the constraint 'true' — the _NoRefusedKey line. Green after. This closes the whole class, not the one key.
  • Runtime — what the inspector actually emits must parse through the real FlowNodeSchema. Red before: 3 failed / 2 passed, the heal test failing on expect('description' in node).toBe(false). Green after.

Both carry anti-degeneracy guards: IsAny probes plus an assertion that the index-signature strip left a non-empty key set (a strip that removed everything would pass every subset test while measuring nothing), and on the runtime side a positive control that the schema under test really is the strict one that refuses description, plus getByLabelText finding the controls that should be present before asserting the Description control absent.

⚠️ The ruling's second half is a no-op, and I did not apply it

The dispatch ruled label must become required. Measured, under a trap with the mutation proved on disk (label?: string 1→0, label: string 0→1, blob 9b19f411dd5504a3) and the restore proved (blob back to 9b19f411, git diff HEAD --stat empty):

tsc exit 0, zero errors. Not one call site breaks.

Every node reaches this type through as FlowNodeLike[] casts out of Record<string, unknown>, and a cast bypasses a required member. So the change would catch nothing — while asserting over stored metadata a guarantee the reader cannot enforce. It is also mildly harmful: node.label ?? '' and node.label || node.id are guards the optional type forces, and making it required would let node.label.trim() compile against a value that is genuinely absent.

That is the layer difference this repo already adjudicated, in the canonical canvas type's own words:

the spec's FlowNode is a COMPLETE authored node (label required), while a canvas holds nodes the user has dropped but not finished. A freshly dropped node has no label yet; typing it as the spec's would make the editor's own intermediate state unrepresentable.
FlowDesignerNode, flow-canvas-layout.ts

The two halves are not the same defect and do not point the same way. description was an over-wide write: the panel produced a key the contract refuses. An optional label is a read looseness over data that genuinely occurs; it admits nothing the contract rejects, it only declines to promise something about stored data. The new pin is a key-set assertion, so it closes the refused-key class without freezing this optionality either way — if the maintainer wants label required, that stays available as a separate decision, on evidence about producers rather than about the contract.

The duplicate copies

FlowPreview.tsx already made this move for its own pair and its comment — "two copies of one shape is how the wrong one survives being fixed" — is about this one. Aliasing was reachable: both imports are import type, erased at compile time, and flow-canvas-layout is dependency-free by design, so no cycle and no new dependency.

  • FlowNodeInspector's node type → FlowNodeLike (the type its value already had).
  • FlowNodeInspector's edge type → FlowDesignerEdge, whose conditionis the spec's ExpressionInput.

⚠️A file outside the declared surface had to move, and here is why. Aliasing the edge turned the build red with 5 errors at the flow-decision-edges boundary — a fourth copy, DecisionEdge, still spelling condition?: unknown months after #3202 narrowed the designer's edge, and incompatible in both directions (unknownExpressionInput, and no index signature the other way). The two ways forward were casts in this file, or converging that copy. Casts at the consumer are the tolerant-fallback anti-pattern — the defect is in the producer — so DecisionEdge is now = FlowDesignerEdge, which also deletes the condText workaround that existed only to cast back to the narrow type on every read. That helper is the module's own written admission that the looseness was never wanted: the one value it ever writes to condition is a bare CEL string, which ExpressionInput has always admitted. Mechanical and self-contained — tsc went 5 errors → 0, and flow-decision-edges.test.ts passes untouched.

FlowEdgeInspector's declaration is not modified — it is the reference, and it agrees with FlowDesignerEdge on the load-bearing member. Three copies of the edge shape are now one, and this panel inherits flow-designer-edge.types.test.ts's existing pin instead of needing its own.

Verification

All gates below ran on the final commit 081e2239d; exit codes captured before any pipe, and each result quoted from the gate's own verdict line.

gateresult
tsc -p packages/app-shell/tsconfig.test.jsonFINAL_TSC_EXIT=0, 0 errors
tsc --noEmit (package source)FINAL_SRC_TSC_EXIT=0, 0 errors
targeted vitest, 12 filesTest Files 12 passed (12)
eslint . (whole app-shell, unnarrowed)ESLINT_EXIT=0 — 0 errors, 2679 pre-existing warnings
check:control-bytes✅ OK (scanned 5195 tracked text file(s))
check:spec-symbols✅ spec symbol derivation: 1305 files scanned
check:vi-mock-specifiers✅ OK (432 carry a mock)
check:i18n-keys✅ Every in-scope call-site key resolves against the en pack
check:i18n-drift✅ No en value changed in this range
check-changeset-presence.mjs✅ 4 source file(s) of 1 released package(s) changed … declares 1 changeset(s)
check-changeset-no-major.mjs✅ No changeset declares a major bump

The new test file was confirmed genuinely in the checked program with --listFiles, not assumed. The dependency closure was built first (pnpm --filter '@object-ui/app-shell^...' build) — the worktree had nodist anywhere, and tsconfig.test.json sets paths: {}, so an unbuilt run would have buried the pin's single error under module-resolution noise and read as a convincing false red.

Out of scope

ActionParam (ActionDefaultInspector.tsx:266 / ActionPreview.tsx:47) was verified on origin/main and filed as #6329 — the two copies disagree on label's type, options, helpText, defaultValue, and the index signature. Not folded in: different files, different pair, and the card excluded it. scripts/check-spec-symbol-derivation.mjs's non-exported-declaration hole is #5899's and was not touched.

Generated by Claude Code


Generated by Claude Code

…description`
`FlowNodeSchema` is `.strict()` and refuses `description` by name, so the node
inspector's Description field produced an unsavable draft on every keystroke
(`unrecognized_keys` in client validation, 422 on save) and nothing ever read
the value back. Remove the field, and strip a stored `description` on write so
flows that already carry one heal on the author's first edit — the same
migrate-on-write boundary the retired `ui` geometry gets.
Converge the hand-written shape copies that hid the drift: the inspector's node
and edge types now alias `FlowNodeLike` / `FlowDesignerEdge`, and
`flow-decision-edges`' fourth edge copy aliases the canvas edge instead of
restating it with a `condition?: unknown` that outlived objectui#3202's
narrowing, taking its workaround cast with it.
Pinned in both worlds: a compile-time assertion that the declared members of the
node read type (index signature stripped) are a subset of the spec's own node
keys, and runtime assertions that what the inspector emits parses through the
real `FlowNodeSchema`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3223.1 KB3266.6 KB
Main entry chunk (gzip)154.2 KB350 KB
Entry fileindex-YpYMGP3_.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.75KB114.70KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)171.74KB47.48KB
fields (index.js)238.79KB59.99KB
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)211.95KB42.75KB
plugin-detail (index.js)245.10KB62.31KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)126.92KB30.85KB
plugin-gantt (index.js)164.14KB39.87KB
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

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3223.1 KB3266.6 KB
Main entry chunk (gzip)154.2 KB350 KB
Entry fileindex-YpYMGP3_.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.75KB114.70KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)171.74KB47.48KB
fields (index.js)238.79KB59.99KB
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)211.95KB42.75KB
plugin-detail (index.js)245.10KB62.31KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)126.92KB30.85KB
plugin-gantt (index.js)164.14KB39.87KB
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-support-ai
os-support-ai marked this pull request as ready for review August 25, 2026 13:27
@os-support-ai
os-support-ai added this pull request to the merge queueAug 25, 2026
Merged via the queue into main with commit 944a929Aug 25, 2026
28 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-6287-flownode-description-key branch August 25, 2026 13:40
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants

@os-support-ai@claude