fix(examples): typecheck example apps clean + gate in CI#2023
Merged
Conversation
The example apps failed their own `tsc --noEmit`. Root cause: app-crm imported types from the root `@objectstack/spec`, which intentionally exports no types — those imports resolved to `any` and silently suppressed all object-literal type checking, masking ~30 real errors. tsup builds the apps without a full typecheck, so nothing caught it. - Repoint app-crm type imports to canonical subpaths (`@objectstack/spec/data`, `/ui`, `/security`, ...). - Type authored literals with input types: add the missing `*Input` aliases to @objectstack/spec (following the existing FieldInput/ ActionInput/ReportInput/PortalInput convention) so `.default()` fields stay optional and CEL fields accept string shorthands. - Fix genuine content drift: drop unsupported `description` on agent/Action/PermissionSet; `parentRole` -> `parent` on roles. - app-todo: drop unmodeled `Field.color` options, guard `input.subject.includes` on an `unknown` value, add the `vitest` devDep its `src/` test needs. - CI (lint.yml): build workspace packages, then typecheck every example via the path filter `./examples/*` (the `@objectstack/example-*` scope glob silently skips `@example/app-todo`). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 89 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
added a commit
that referenced
this pull request
Jun 18, 2026
#2026) Scope consistency with the other example apps (@objectstack/example-crm, @objectstack/example-showcase). The inconsistent scope meant a `--filter @objectstack/example-*` glob silently skipped app-todo — the follow-up noted in #2023. Updates the package name, the root `dev:todo` script, current docs (root + app-todo READMEs) and the `// Run via:` comments in the test files. CHANGELOGs are left untouched (historical record). No lockfile churn — pnpm keys importers by path, not name. Package is private (not published), so no changeset. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang
added a commit
that referenced
this pull request
Jun 18, 2026
…2029) The repo had an ESLint flat config whose only rule — no-restricted-imports banning `@objectstack/spec` root namespace imports (the ~1.2GB RSS regression vector) — was never enforced: eslint wasn't even a devDep, no `lint` script existed, and the `lint.yml` workflow only ran tsc. The config's own comment said "To enable: pnpm add -DW eslint". So the guard that should have caught the root-import drift fixed in #2023 was dormant. - Add `eslint` + `@typescript-eslint/parser` devDeps; wire the parser into the flat config so .ts files parse. - Add root `lint` script (`eslint . --no-inline-config`). The flag ignores orphaned `eslint-disable` directives left over from a richer rule set this minimal config no longer registers; the sole active rule should never be opted out locally anyway. - Add a fast `lint` job to lint.yml (syntactic only, no build needed). Complements the example-app typecheck gate from #2023: typecheck catches concrete-type root imports, ESLint catches the namespace-name imports and gives a faster signal. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
5 tasks
xuyushun441-sys
added a commit
that referenced
this pull request
Jun 21, 2026
…ritable domains (#2035) (#2088) * feat(spec): defineX factories + XInput aliases for the 16 remaining writable domains (#2035) Adds one type-safe authoring entry per writable domain — defineDatasource, defineConnector, definePolicy, defineSharingRule, defineRole, definePermissionSet, defineEmailTemplateDefinition, defineReport, defineWebhook, defineObjectExtension, defineCube, defineMapping, defineTheme, defineTranslationBundle, definePage, defineAction — mirroring the 19 existing factories (XSchema.parse(z.input)). Each factory is a *value* export: a broken import hard-errors instead of silently degrading to `any` (the #2023 failure mode), and authoring errors surface at .parse() time with field-level messages. Also backfills the six missing input aliases: PolicyInput, CubeInput, MappingInput, ThemeInput, TranslationBundleInput, PageInput. Purely additive — no existing exports change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(examples): author metadata via defineX factories (#2035) Migrates every example authoring file across crm/showcase/todo from bare output-type literals (`: Page`, `: UI.ActionInput`, …) to the corresponding defineX factory. The factory accepts input-shape config and validates each definition at module load, so a malformed metadata object now fails loudly at authoring time instead of silently passing as `any` (#2023). Covers 36 files / 16 domains — including files the *.{domain}.ts filename scan missed (reports/index.ts, actions/index.ts, security/sales-roles.ts, …), which the new lint guard surfaced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(lint): guard examples against bare metadata literals (#2035) Adds an AST-only no-restricted-syntax rule that flags exported consts in examples/** annotated with a spec domain type (simple `Page` or qualified `UI.Page`) instead of being wrapped in the defineX factory. Turns the authoring convention into an invariant so the "pick by history" pattern cannot creep back into the reference corpus AI learns from — it already caught 15 unmigrated authoring files in this change. No type info required. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
xuyushun441-sys
added a commit
that referenced
this pull request
Jun 21, 2026
…2035) (#2089) Adds `@objectstack/downstream-contract` — a frozen, representative third-party consumer of `@objectstack/spec`, and the CI gate that runs it. Why: every other spec consumer the framework tests (example apps, `@objectstack/dogfood`) lives in this repo and co-evolves with the spec in the same commit, so none can catch a change that breaks a *real* third party (e.g. hotcrm) pinned to a published release. This fixture is authored the way an external project does — builder + `defineX` factories + bare metadata literals (the pre-#2035 pattern) — and is FROZEN: a spec change that requires editing it to stay green is, by definition, breaking. Two signals, both wired into existing CI jobs (no new workflow): • typecheck — fixtures are typed with real spec types (`ActionInput`, `ReportInput`, `PageInput`, …); a removed/narrowed export fails (the #2023 class). Added to lint.yml's TypeScript Type Check job. • test — each bare-literal fixture is run through its schema's `.parse()`, and everything is assembled via `defineStack` (schema + cross-reference validation, the metadata core of `objectstack validate`). Rides `turbo run test` (Test Core). Verified locally: typecheck + test green; confirmed the schema parse has teeth (rejects a broken action `type`). README documents the freeze contract. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
xuyushun441-sys
added a commit
that referenced
this pull request
Jun 21, 2026
…ft (#2035) (#2092) For a metadata-driven platform the spec package IS the third-party API surface. A removed/renamed/kind-changed export silently breaks every consumer pinned to a published release the moment they upgrade (the #2023 class) — and no in-repo consumer catches it, because they all co-evolve with the spec in the same commit. `scripts/build-api-surface.ts` enumerates every exported `name (kind)` from the built `.d.ts` of each public entry point (`.`, `./ui`, `./data`, … 16 entries, 4251 exports), resolving re-export aliases to their real kind. The result is committed at `packages/spec/api-surface.json`. pnpm --filter @objectstack/spec gen:api-surface # regenerate + write pnpm --filter @objectstack/spec check:api-surface # CI: fail on any drift Wired into lint.yml's TypeScript Type Check job (after the build step). A REMOVED export fails as breaking (bump major); an ADDED export still requires regenerating the snapshot, so every change to the public surface is deliberate, never silent. Complements the downstream-contract gate: that proves exercised exports still ACCEPT real third-party metadata (depth); this proves the whole export set still EXISTS (breadth). Dev tooling only — the script and snapshot are not in the package `files`, so nothing ships to consumers. Sort is code-unit (not locale) for cross-platform determinism; verified the check passes clean and rejects a simulated removal. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The example apps (
app-crm,app-showcase,app-todo) failed their owntsc --noEmit, and nothing in CI caught it — the typecheck job only rantscon@objectstack/spec.The task looked like "~12
TS2305import errors," but those were masking the real damage: app-crm imported types from the root@objectstack/spec, which intentionally exports no types (packages/spec/src/index.ts:8, enforced by ESLintno-restricted-imports). Those imports resolved toany, which silently suppressed all object-literal type checking in those files. Fixing the imports unmasked ~30 real type-conformance errors that had never been checked. tsup transpiles the apps without a full typecheck, so the build stayed green the whole time.Fix
Import direction — Option B (subpath imports), the canonical one:
@objectstack/spec/data,/ui,/security,/integration, ...).Output-vs-input types (the bulk of the unmasked errors):
z.infer), where every.default()field becomes required and CEL/Expression fields reject bare strings.XInputconvention (FieldInput,ActionInput,ReportInput,PortalInput) — add the 9 missing aliases (DatasourceInput,ConnectorInput,SharingRuleInput,JobInput,WebhookInput,EmailTemplateDefinitionInput,RoleInput,PermissionSetInput,ObjectExtensionInput) and type the examples with them. Keeps templates clean instead of padding them with default values.Genuine content bugs (also previously masked):
descriptionon agent / Action / PermissionSet (schemas don't define it;labelkept).parentRole->parenton roles.Field.color({colorFormat, presetColors})options; guardedinput.subject.includeson anunknownvalue; added the missingvitestdevDep itssrc/**/*.test.tsneeds.CI gate (.github/workflows/lint.yml):
pnpm --filter './examples/*' run typecheck../examples/*, not@objectstack/example-*—app-todois named@example/app-todo, so the scope glob silently skips it.Verification
Note
Follow-up (not in this PR):
@example/app-todoshould probably be renamed@objectstack/example-todofor scope consistency. The path-based CI filter sidesteps the need for now.🤖 Generated with Claude Code