Repository navigation
Conversation
interface-data-api 0.7 removed RowFields, which interface-dms 0.13.3 names in its published declarations, so a project that resolves data-api 0.7 fails tsc. interface-dms and dms now build against data-api 0.7 and name StoredRow. The guard-row read in column-conditions is typed from the published fetchRowForGuard, and dms reads a row id as text through rowIdText, which refuses an id holding a row, a list or a document.
…tarball interface-data-api main (d70049c, #129) declares the decorators-0.5 ContainerModifier fix, packed as 0.7.2. The tarball stands in for the release until it ships; interface-dms requires >=0.7.2 <0.8.0.
interface-data-api 0.7.2 declares its modifier keys as Class<ContainerModifier> and requires decorators >=0.5.0; decorators 0.3.1's LocalizationModifier does not satisfy it. dms, the playground and interface-dms's development build move to decorators >=0.5.2.
… run every query interface-data-api #133 runs each DefaultRoutes query through .run(), which interface-database 0.4 needs. Packed as 0.7.2 like the tarball it replaces.
…terValue holds a boolean interface-data-api 0.8 types a filter value as string | boolean (ANT-2463). DataType.filter takes that value and hands its compare mode String(value), which the value parser reads back as the same boolean; the date type's override reads it as text. interface-dms and dms require data-api >=0.8.0 <0.9.0.
interface-data-api 0.8 types a filter value as string | boolean, so archiveFilter returns [true, mode] as typed and the SAFETY comment and chained assertion go.
interface-database 0.4.0 queries are not thenable: every query runs through .run(). dms, the playground and interface-dms require interface-database >=0.4.0 and interface-database-decorators >=0.5.2; the test host and the playground run @antelopejs/mongodb 1.8.0.
…r through a tarball The published @antelopejs/interface-dms-builder 0.4.1 is not standalone, so a project installing dms from this branch fails to load with an unresolved interface dependency. The branch's builder, packed as 0.4.2, stands in until it ships.
Upd4ting
force-pushed
the
fix/interface-dms-stored-row
branch
from
November 13, 2026 20:10
ca837f0 to
42b25e5
Compare
Upd4ting
force-pushed
the
feat/interface-database-0-4
branch
from
November 13, 2026 20:11
e031d8c to
0068a03
Compare
This was referenced Nov 13, 2026
Merged
Upd4ting
added a commit
that referenced
this pull request
Nov 14, 2026
…auth routes read (#909) ANT-1093's dms part. AntelopeJS/dms-frontend#338 (`refactor/unknown-server-json`) makes `event.backend()` and `readJson()` resolve to `unknown` instead of a type the caller picks. frontend-vue's auth routes read those results as typed values. This narrows each backend answer with a zod schema and each request body with an object check (`readJsonObject`; the route then checks the fields it reads), so frontend-vue compiles against today's dms-frontend and against #338. A malformed answer is refused, never cast through. ⚠ sensitive: auth (sign-in, 2FA, tenant switch, stored accounts, session renewal, OAuth). ## Summary ```diff layers/dms-auth/server/actions.ts, session.ts, oauth.ts; server/html-render.ts - const answer = await event.backend<SessionTokens>("/api/auth/refresh", …); + const answer = tokenPair.parse(await event.backend("/api/auth/refresh", …)); - const input = await readJson<Input>(event); + const input = readJsonObject(await readJson(event)); // 400 "Invalid request body" otherwise - input.accountId as string + isString(input.accountId) ? … : … +layers/dms-auth/server/backend-answers.ts loginOutcome (tagged union), tokenPair, sessionUser, oauthAuthorization +server/request-body.ts readJsonObject (packages/dms/frontend-vue/server/) ``` Neither new file sits in an auto-imported folder. `SessionTokens` is now derived from the schema, so `EstablishResult` and `OAuthResult` are gone. | Call site | Backend route | Schema or guard | A malformed answer | | --- | --- | --- | --- | | actions.ts login, register, verify-2fa, establish | `/api/auth/login`, `/signup`, `/verify-2fa`, establish endpoint | `loginOutcome` | 502 `error.500.description`; no session written | | actions.ts switch-tenant | `/api/auth/switch-tenant`, `/api/auth/me` | `tokenPair`, `sessionUser` | 502 | | actions.ts switch-account | `/api/auth/refresh`, `/api/auth/me` | `tokenPair`, `sessionUser` | 502; the account is kept | | actions.ts validate-account | `/api/auth/refresh` | `tokenPair` | `{ valid: null }`; the account is kept | | session.ts renewSession | `/api/auth/refresh`, `/api/auth/me` | `tokenPair`, `sessionUser` | session kept; nothing new used for the request | | oauth.ts start | `/api/auth/oauth/:provider/authorize-url` | `oauthAuthorization` | redirect to `error.oauth.failed` | | oauth.ts callback | `/api/auth/oauth/:provider/callback` | `loginOutcome` | redirect to `error.oauth.failed`; no handoff, no session | | actions.ts request bodies (9 routes: login, register, verify-2fa, request-2fa-email, establish, remove-account, switch-tenant, switch-account, validate-account), html-render.ts | client body | `readJsonObject` (an object; the route checks its own fields) | 400 `Invalid request body`, as for a non-JSON body; no backend call | A malformed backend answer fails like a backend error: the existing 502 path. It is never taken as a refusal, so nothing is cleared or removed. Valid answers behave as before. `sessionUser` and the 2FA and tenant-assignment steps use `.passthrough()`, because the session and the browser receive them whole. `tokenPair` and `oauthAuthorization` strip the fields nobody reads. ## Evidence - **Typecheck, `ajs dms verify-source`:** | dms-frontend | Before | After | | --- | ---: | ---: | | installed 0.10.6 | 0 | 0 | | #338 head e015184 (tarball, not committed) | 57 (actions.ts 39, oauth.ts 7, session.ts 4, html-render.ts 7) | 0 | - **Review round: a step answer never opens a session.** At a46b600 the session shape ignored the step flags, so an answer with `requires_2fa: true` (or `requires_tenant_assignment: true`), a malformed step and a token pair failed both step shapes and opened a session; main refused it. The session shape now accepts the flags only absent or `false`. Two new tests: - `opens no session from a malformed step answer that also carries a token pair, and answers it as a failed backend` (login, register, verify-2fa, establish); - `ends a provider sign-in on a malformed step answer that also carries a token pair as on a failed backend` (OAuth callback). Each tries `{ ...CHALLENGE, ...PAIR, methods: [5] }` and `{ ...ASSIGNMENT, ...PAIR, tenant_assignment_token: 5 }`. **Before** (a46b600's `backend-answers.ts`, `accounts.ts`, `actions.ts`): ``` × opens no session from a malformed step answer that also carries a token pair, and answers it as a failed backend × ends a provider sign-in on a malformed step answer that also carries a token pair as on a failed backend AssertionError: /auth/login {"requires_2fa":true,"two_factor_token":"challenge-1","methods":[5],"access_token":"header.eyJ0ZW5hbnRJZCI6InQxIn0.signature","refresh_token":"refresh-1"}: expected { status: 200, location: null, …(3) } to deeply equal { status: 502, location: null, …(3) } AssertionError: {"requires_2fa":true,"two_factor_token":"challenge-1","methods":[5],"access_token":"header.eyJ0ZW5hbnRJZCI6InQxIn0.signature","refresh_token":"refresh-1"}: expected { status: 302, …(4) } to deeply equal { status: 302, …(4) } Tests 2 failed | 9 skipped (11) ``` **After:** ``` Tests 2 passed | 9 skipped (11) ``` - **`tests/server-backend-answers.test.ts`.** It runs the real router against a fake backend and checks that each spoiled answer gives the same whole route answer as a failing backend. - It covers the sign-in answer of another shape (4 routes), the malformed step that carries a token pair (4 routes and the OAuth callback), empty tokens, empty OAuth `state` and `authorizeUrl`, stored-user fields of another type, a sign-in step handed over whole, the OAuth callback, authorize-url, session renewal, switch-tenant, the stored-account switch and validation, and request and render bodies that are not objects. - Each of 9 schema or guard mutations, applied one at a time and then reverted, makes a test fail. - Against main's code, the cast, 8 of 9 tests fail. The ninth is the valid-answer test. - **Suites:** - `server-backend-answers.test.ts`: 11 tests (re-run alone after this round, `--maxWorkers=4`); - full frontend vitest locally: 3516 passed, 1 failed (`live-block-families` polling count, a timing test this PR does not touch, at load average 45–73); CI runs the full suite green; - the dms auth integration subset (15 files): 83 passing, unchanged; - `pnpm run checks`: 11 passed; - root typecheck, oxlint and frontend `eslint .` are clean. API: 3 packages, 379 entries unchanged against origin/main (committed HEAD). API: skipped ., private. API: skipped packages/dms/playground, private. API: skipped packages/dms/playground/frontend-vue, private. Runtime API: 3 packages, 376 entries unchanged against origin/main (committed HEAD). Auto-imports: 1 packages, 944 entries unchanged against origin/main (committed HEAD). No behavioural probe ran. Suppressions in authored code files (origin/main and committed HEAD). A lint directive counts once per rule it names; `*` is a directive naming none. | Suppressions | base | HEAD | | --- | ---: | ---: | | Lint suppressions, all rules | 163 | 163 | | Lint suppressions, `@typescript-eslint/no-unused-vars` | 2 | 2 | | Lint suppressions, `anti-slop/no-chained-type-assertions` | 1 | 1 | | Lint suppressions, `anti-slop/no-known-value-widening` | 1 | 1 | | Lint suppressions, `anti-slop/no-object-parameters` | 1 | 1 | | Lint suppressions, `anti-slop/no-reflect-apply` | 1 | 1 | | Lint suppressions, `anti-slop/no-reflect-get` | 2 | 2 | | Lint suppressions, `anti-slop/no-shape-in-symbol-names` | 16 | 16 | | Lint suppressions, `anti-slop/no-unknown-parameters` | 39 | 39 | | Lint suppressions, `anti-slop/no-unknown-returns` | 7 | 7 | | Lint suppressions, `anti-slop/no-unsafe-dictionary-type` | 79 | 79 | | Lint suppressions, `eslint/max-params` | 6 | 6 | | Lint suppressions, `no-empty` | 3 | 3 | | Lint suppressions, `typescript/no-redundant-type-constituents` | 1 | 1 | | Lint suppressions, `typescript/no-unsafe-assignment` | 2 | 2 | | Lint suppressions, `typescript/no-unsafe-return` | 2 | 2 | | `@ts-expect-error` | 0 | 0 | | `@ts-ignore` | 0 | 0 | | `SAFETY:` comments | 35 | 35 | | Lint config rule-offs, all rules | 7 | 7 | | Lint config rule-offs, `no-redeclare for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | | Lint config rule-offs, `no-unused-vars for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | | Lint config rule-offs, `vue/html-indent for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | | Lint config rule-offs, `vue/max-attributes-per-line for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | | Lint config rule-offs, `vue/multi-word-component-names for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | | Lint config rule-offs, `vue/require-default-prop for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | | Lint config rule-offs, `vue/singleline-html-element-content-newline for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | <!-- antelopejs-proof base=debd8d0ad82074c42be8cae54f15e4dc0d70c530 head=bc89cc71b2cf89ae7b048a67f17e53903bff0348 lines=37 digest=f18e0ecdf4da36d7 command: antelopejs-api-diff origin/main --allow-added '**/internal/**' --> ## Attention - **Behaviour changes, on malformed input only:** - A JSON body that is not an object now gets a 400. Before, `null` crashed with a 502, and other values reached the backend. - A 2FA step or tenant assignment without its token or a `string[]` of methods is refused. - A sign-in answer that sets `requires_2fa` or `requires_tenant_assignment` never opens a session; with a malformed step it fails as a backend error (main returned it as a step). A flag that is `null`, `0` or `""` on a session answer is refused too; the backend never sends a flag on one. - An empty `access_token`, `refresh_token`, `two_factor_token`, `tenant_assignment_token`, OAuth `state` or `authorizeUrl` is refused, so an empty sealed `state` can no longer match an empty `?state=`. - A user whose `_id`, `id`, `email`, `name` or `language` is not a string is refused at sign-in. No backend write path stores one. A stored account reads its user through the same schema, which replaces the `as SessionUser` assertion in `accounts.ts`. - `register` and `request-2fa-email` now refuse a body that is not a JSON object with 400, like the other routes. - **Live sign-in did not run.** `dms-control up --prepare` fails to start the backend on main itself (`this.table.get(...).then is not a function`): main's playground pins `@antelopejs/mongodb` 1.6.2, which predates interface-database 0.4. #907 fixes that. - 2FA and OAuth are proven only by route tests against a fake backend; the playground configures neither. - The schemas were matched to the backend routes by reading their types (`AuthResponse`, `LoginOutcome`, `OAuthAuthorizeUrl`, `sanitizeUser`). - **No independent review has run yet.** - **Order:** this PR lands first; dms-frontend#338 follows. The two removed `as string` assertions may meet ANT-2241's later slices on rebase. ## Merge Danger **Door:** two-way. Server-side parsing only. Published auto-imports and runtime exports are unchanged (api-diff above). **Blast Radius:** moderate. Every sign-in, session renewal, tenant and account switch, and OAuth flow, on malformed backend answers or bodies.
Upd4ting
added a commit
that referenced
this pull request
Nov 14, 2026
…910) Part of ANT-1088: every suppression in `guardrails.suppressions.json` goes. Antony decided to rename the single-word Vue components to multi-word names and to turn `vue/multi-word-component-names` back on as an error, exempting only the Nuxt pages so routes do not change. This removes the frontend-vue config off for that rule. ⚠ sensitive: it is breaking. Component names are registered under the `Dms` prefix and named by string in backend code, stored mockups and page drafts. It changes the strings interface-dms's builders emit, and it is well over 400 lines (mostly renames). ## Summary All 38 single-word components are renamed with `git mv`. Each row is `Dms<Old>` → `Dms<New>`, and the kebab form follows (`dms-card` → `dms-card-panel`). | Old | New | Old | New | | --- | --- | --- | --- | | Container | LayoutContainer | Cascader | InputCascader | | Footer | LayoutFooter | Checkbox | InputCheckbox | | Spacer | StackSpacer | Display | DisplayValue | | Platform | StepPlatform | File | InputFile | | Ready | StepReady | Image | InputImage | | Register | StepRegister | Relation | InputRelation | | Actions | TableActions | Repeater | InputRepeater | | Empty | TableEmpty | Select | InputSelect | | Menu | TableMenu | Slider | InputSlider | | Pagination | TablePagination | Switch | InputSwitch | | Table | TableRoot | Textarea | InputTextarea | | Tabs | TableTabs | Grid | GridBlock | | Views | TableViews | Guard | GuardBlock | | Placeholder | PlaceholderBlock | Meter | MeterBar | | Banner | NoticeBanner | Eyebrow | EyebrowLabel | | Card | CardPanel | Section | SectionPanel | | Chart | ChartBlock | Segmented | SegmentedControl | | Sparkline | SparklineChart | Tab | TabBlock | | Form | FormBlock | Calendar | InputCalendar | - **Entry files renamed to match their component:** `layout/Footer`, `onboarding/steps/ready`, `table/Actions`, `table/Empty`, `table/Pagination`, `table/Table` and `table/Views`. - **References updated:** - relative and `#dms-*` imports, entry re-exports and `import.meta.glob` paths; - `Dms<Old>` in templates, `resolveComponent` and test registrations; - the kebab strings emitted in `packages/interface-dms/src`, `packages/dms/src`, frontend-vue and the playground (`dms-chart`, `dms-form`, `dms-grid`, `dms-guard`, `dms-placeholder`, `dms-spacer`, `dms-tab` and the eleven inputs); - `COMPONENT_ALIASES`; - the probe manifest and `check-page-invariants.mjs`; - the mockup-starters fixture; - `docs-data/blocks.json` (regenerated) and `examples.json`; - the prose docs. - **Not updated:** the older migration guides and changelogs, which stay as history. - **Rule configuration:** ```js "vue/multi-word-component-names": ["error", { ignores: [ "Icon", "2fa", "accounts", "backup", "error", "forgot", "login", "modules", "onboarding", "recover", "roles", "shortcuts", "signup", "validate", "[...slug]", ] }] ``` - The page names are the twelve custom pages, the `[...slug]` dynamic page and the app-level `error.vue`. - `Icon` is Nuxt's own component. Two tests register a stub under that fixed upstream name. - **Budget:** the config entry for `vue/multi-word-component-names` goes from 1 to 0, and nothing else changes. - **Documentation:** - `packages/interface-dms/UPGRADING.md` (Unreleased) has the full old → new table. - `packages/dms/docs/02.building/18.migration-0-13-to-0-14.md` explains what breaks: hand-written name strings, stored mockups and drafts, templates in modules, and the seven entry paths. Its Cascader section now names `DmsInputCascader`. ## Evidence - **Before:** `eslint` with the rule on reports every single-word component. **After:** `pnpm --dir packages/dms/frontend-vue exec eslint .` gives 0 errors with the rule at `error`. - **Suites:** - `pnpm run checks` 11 passed; - frontend-vue typecheck clean; vitest 3506 passed, 1 skipped (`--testTimeout=60000`; at the default, 2 to 4 heavy-import tests time out under a load average of 30 and pass alone); - `dms test:unit` 2627, `test:integration` 419; - the playground tests pass. - **Live:** with the `verify-dms` skill, the `smoke` journey PASSES, 21/21 checks over 15 steps. Doctor is clean, and no log says "failed to resolve component". - The playground backend does not start on main, because main's playground resolves `@antelopejs/mongodb` 1.8.0 against interface-database-decorators 0.3.1 (#907 fixes that). - The run used a verification-only `@antelopejs/mongodb` 1.6.4 pin, which is not committed. API: differences against origin/main (committed HEAD). diff --git a/base/packages/interface-dms/exports/subpath/base%2Finternal%2Fchart.d.ts b/head/packages/interface-dms/exports/subpath/base%2Finternal%2Fchart.d.ts index 1a31648..6a592cf 100644 --- a/base/packages/interface-dms/exports/subpath/base%2Finternal%2Fchart.d.ts +++ b/head/packages/interface-dms/exports/subpath/base%2Finternal%2Fchart.d.ts @@ -1,4 +1,4 @@ -export declare const CHART_COMPONENT_NAME = "dms-chart"; +export declare const CHART_COMPONENT_NAME = "dms-chart-block"; export declare const CHART_META_BY_TYPE: Record<ChartType, ChartTypeMeta>; declare enum ChartType { LINE = "line", diff --git a/base/packages/interface-dms/exports/subpath/base%2Finternal%2Fform-block-schema.d.ts b/head/packages/interface-dms/exports/subpath/base%2Finternal%2Fform-block-schema.d.ts index ee3e30d..77eca52 100644 --- a/base/packages/interface-dms/exports/subpath/base%2Finternal%2Fform-block-schema.d.ts +++ b/head/packages/interface-dms/exports/subpath/base%2Finternal%2Fform-block-schema.d.ts @@ -1,2 +1,2 @@ export {}; -export declare const FORM_COMPONENT_NAME = "dms-form"; +export declare const FORM_COMPONENT_NAME = "dms-form-block"; API: skipped ., private. API: skipped packages/dms/playground, private. API: skipped packages/dms/playground/frontend-vue, private. Runtime API: 3 packages, 376 entries unchanged against origin/main (committed HEAD). Auto-imports: 1 packages, 944 entries unchanged against origin/main (committed HEAD). No behavioural probe ran. Suppressions in authored code files (origin/main and committed HEAD). A lint directive counts once per rule it names; `*` is a directive naming none. | Suppressions | base | HEAD | | --- | ---: | ---: | | Lint suppressions, all rules | 163 | 163 | | Lint suppressions, `@typescript-eslint/no-unused-vars` | 2 | 2 | | Lint suppressions, `anti-slop/no-chained-type-assertions` | 1 | 1 | | Lint suppressions, `anti-slop/no-known-value-widening` | 1 | 1 | | Lint suppressions, `anti-slop/no-object-parameters` | 1 | 1 | | Lint suppressions, `anti-slop/no-reflect-apply` | 1 | 1 | | Lint suppressions, `anti-slop/no-reflect-get` | 2 | 2 | | Lint suppressions, `anti-slop/no-shape-in-symbol-names` | 16 | 16 | | Lint suppressions, `anti-slop/no-unknown-parameters` | 39 | 39 | | Lint suppressions, `anti-slop/no-unknown-returns` | 7 | 7 | | Lint suppressions, `anti-slop/no-unsafe-dictionary-type` | 79 | 79 | | Lint suppressions, `eslint/max-params` | 6 | 6 | | Lint suppressions, `no-empty` | 3 | 3 | | Lint suppressions, `typescript/no-redundant-type-constituents` | 1 | 1 | | Lint suppressions, `typescript/no-unsafe-assignment` | 2 | 2 | | Lint suppressions, `typescript/no-unsafe-return` | 2 | 2 | | `@ts-expect-error` | 0 | 0 | | `@ts-ignore` | 0 | 0 | | `SAFETY:` comments | 35 | 35 | | Lint config rule-offs, all rules | 7 | 6 | | Lint config rule-offs, `no-redeclare for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | | Lint config rule-offs, `no-unused-vars for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | | Lint config rule-offs, `vue/html-indent for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | | Lint config rule-offs, `vue/max-attributes-per-line for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | | Lint config rule-offs, `vue/multi-word-component-names for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 0 | | Lint config rule-offs, `vue/require-default-prop for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | | Lint config rule-offs, `vue/singleline-html-element-content-newline for packages/dms/frontend-vue/**/*.{js,mjs,cjs,ts,vue}` | 1 | 1 | <!-- antelopejs-proof base=debd8d0ad82074c42be8cae54f15e4dc0d70c530 head=4193595036a99111ccb28288156b1015e053f98b lines=55 digest=fe26bf8b5740506d command: antelopejs-api-diff origin/main --allow-added '**/internal/**' --> Runtime exports and auto-imports are unchanged, because components are registered, not auto-imported. The only differences api-diff reports are two `@internal` constants: `CHART_COMPONENT_NAME` (`dms-chart-block`) and `FORM_COMPONENT_NAME` (`dms-form-block`). ## Attention - **Stored mockups and page drafts** that hold an old `componentName` fail to compile after the upgrade. The guide says so, and no alias is kept, by Antony's decision that this is breaking. - **Names to check:** `StackSpacer`, `TableRoot`, and the `*Block` suffix on Grid, Guard, Tab, Chart, Form and Placeholder were judgement calls. - **After the Nuxt-preset PR:** the preset's `onResolved` rewrites `vue/multi-word-component-names` to off in any block appended after it. Whichever of the two PRs lands second passes this rule through `antelopeNuxtConfig({ rules: … })`, so it stays on. I do that rebase. - One test thumbnail prop changed from `demo` to `demo-mockup`. ## Merge Danger **Door:** one-way once released. Modules and stored specs that name components by string must migrate. **Blast Radius:** wide. Every registered DMS component name, the strings the interface builders emit, stored mockups and drafts, and modules that render DMS components by name.
Upd4ting
added a commit
that referenced
this pull request
Nov 14, 2026
…form ownership from user.owner (#913) ⚠ sensitive (permissions) ## Why A member allowed to edit roles could make themselves the platform owner. The roles API let them add `*` to any role, their own included. Four checks read `*` as platform ownership: the module store, the modules listing, `isOwner` in the site layout, and `permissionsOpenPage` for owner-only pages. #887 already stopped `assertPlatformOwner` from accepting `*`, and this PR closes the rest. Task: ANT-2425, found by the review of ANT-2391 (#887). ## What changes - **The roles API grants only what the editor holds.** Creating, updating or copying a role answers 403 (`$page.settings.roles.error.ungrantable`) when the role would gain `*` or a permission the editor does not hold. That covers the editor routes (`create`, `PUT :id`, `:id/duplicate`) and the roles table routes (`/api/tables/roles/new` and `/edit`, through new `new` and `edit` guards). `*` is refused to everyone, the platform owner included, so no role holds it. The check runs on the stored set, after `withRequiredPermissions` adds ancestors and dependencies. An edit may keep what the role held already, so an editor can rename a role that holds more than they do. - **Ownership comes from `user.owner`.** `buildAccessContext` sets `isOwner` from `user.owner`, not from `*` in the effective set. That feeds `isPlatformOwner` (the module store), `/dms/modules-listing`, `isOwner` in `/dms/sitelayout`, and menu access. `permissionsOpenPage` takes `{ permissions, isOwner }`. `userCanAccessPage` passes `user.owner`, and `page_verify`'s `roleOpensPage` passes `false`, because a role is never the owner. `assertPlatformOwner` drops its separate `user.owner` test, which `isPlatformOwner` now carries. - **Docs.** "Who can grant what" says the roles routes cap grants to what the editor holds. The member and invitation editors keep no cap, as before. The Modules docs and the `dms-module` skill call the platform owner the user flagged `owner`, not the `*` holder. Unchanged on purpose: - The role preview still treats a previewed `*` as the owner. It writes nothing, and it shows only what the viewer is already served. - A member editor can still give any member any role, as "Who can grant what" documents. - The `dms-saas` resolvers keep `*` for a platform owner outside a preview, so reading `user.owner` gives no owner more access than before. ```mermaid flowchart LR subgraph Roles API W[create / update / duplicate / table new, edit] --> C{role gains * or a permission the editor lacks?} C -- yes --> F[403 ungrantable] C -- no --> S[role saved] end subgraph Owner checks R[store, modules-listing, sitelayout, owner-only page] --> O{user.owner === true} O -- no --> D[refused / isOwner false] O -- yes --> G{tenant gate allows} G -- yes --> A[served] G -- no --> D end ``` Before, the owner checks branched on `permissions.has("*")`, which any role holding `*` passed. ## Proof New tests: `src/test/integration/role-wildcard-owner.test.ts` and one case in `src/test/unit/implementations/dms/owner-only-page.test.ts`. A member whose stored role holds `*` is refused on each of the four checks. The roles API refuses `*` and unheld permissions on every write route, and still saves held ones and keeps a role's existing ones. **Before**: the new tests against origin/main (debd8d0): ``` 6 passing (4s) 9 failing 1) [integration] a member whose role holds * is refused the module store before its body is read: AssertionError: [{"code":"invalid_type",...,"path":["id"],"message":"Required"}]: expected 400 to equal 403 2) [integration] a member whose role holds * is refused the modules listing: -200 +403 3) [integration] a member whose role holds * is not the owner in the site layout: AssertionError: expected true to equal false 4) [integration] the roles API grants only what the editor holds refuses * on the editor's own role, and leaves it unchanged: -200 +403 5) [integration] the roles API grants only what the editor holds refuses a permission the editor does not hold: -200 +403 6) [integration] the roles API grants only what the editor holds refuses * to the platform owner too: AssertionError: {"id":"cffd5836-…"}: expected 200 to equal 403 7) [integration] the roles API grants only what the editor holds refuses * and unheld permissions through the roles table routes: AssertionError: {"_id":"dfb7acc8-…","name":"Everything","permissions":["*"],…}: expected 200 to equal 403 8) [integration] the roles API grants only what the editor holds refuses to copy a role holding what the editor does not: AssertionError: {"id":"4950bf63-…"}: expected 200 to equal 403 9) [unit] implementations/dms/page — ownerOnly pages denies a member whose role holds *, which only the owner holds: AssertionError: expected true to equal false ``` The member got past the store's owner check to body validation (400), was served the modules listing, and was `isOwner: true` in the site layout. **After**: on this branch, the new tests with the existing role suites: ``` [integration] a member whose role holds * ✔ is refused the module store before its body is read ✔ is refused the modules listing ✔ is not the owner in the site layout [integration] the roles API grants only what the editor holds ✔ refuses * on the editor's own role, and leaves it unchanged ✔ refuses a permission the editor does not hold ✔ refuses * to the platform owner too ✔ refuses * and unheld permissions through the roles table routes ✔ refuses to copy a role holding what the editor does not ✔ grants what the editor holds, and keeps what a role held already [integration] role permissions and their ancestors ✔ (7 cases) [integration] role delete with reassignment ✔ (2 cases) [unit] implementations/dms/page — ownerOnly pages ✔ denies a member whose role holds *, which only the owner holds ✔ (5 other cases) 24 passing (18s) ``` **verify-dms.** The `settings-roles` feature gains the `role-editor-grants-only-held` journey. A member who can edit roles ticks "Export reports" on their own role and saves. They get "You can’t grant permissions you don’t hold yourself.", the stored role is unchanged, and their `PUT` adding `*` and their `GET /dms/modules-listing` both answer 403. The platform owner then saves the same tick. The journey has not run yet. `dms-control up` cannot start the playground on this base: its backend stops with `this.table.get(...).then is not a function`, because the playground's `interface-database-decorators` 0.3.1 awaits a query that `interface-database` 0.4.0 no longer runs. This PR changes no manifest, and #907 moves the playground to 0.4.0. The full backend suites pass on this branch: `test:unit` 2628 passing, `test:integration` 430 passing. Stored data: a role saved with `*` before this change keeps it. It no longer passes the four owner checks above, and a role editor can no longer save it with `*` kept. `HasPermission` still reads `*` as every permission, module-scoped ones included, so such a role still opens module table routes. Only a role written before this change, or straight to the database, can hold `*`. Making `GetUserPermissions` drop `*` from role grants closes that in `interface-dms`, and it is proposed as a follow-up.
Upd4ting
added a commit
that referenced
this pull request
Nov 14, 2026
## Why
A mockup spec may write a `Form` whose `sections` each hold their own
`fields`, the shape the `Form` factory takes and the block schema
describes. The `dms-form` component reads the shape the factory
serializes instead: every field in `fields`, and each section naming its
fields by `fieldIds`. So such a spec passed validation, and its preview
then crashed (`Cannot read properties of undefined (reading 'map')`).
Because of that, the Edit-mode Form starter could not ship with a
section.
## What
- The mockup compiler hands a `Form` or `ResourceForm` the layout the
factory serializes. Each section's own fields move after the form's
`fields`, in order, and the section names them in `fieldIds`. It still
validates the spec as written, so an issue points into the section where
the author wrote the field.
- `componentOptionsOf` in `validate.ts` runs a new `toComponentOptions`
step on each preview adapter. Only the form adapter changes anything.
- A section that writes both `fields` and `fieldIds` gets an issue at
its `fieldIds`. Before, the written ids were dropped with no issue.
- The Edit-mode Form starter now has a `Contact` section holding
`Email`, next to a top-level `Name`. The starter fixture `nodes.json` is
regenerated.
- The mockups docs page describes both section shapes.
```mermaid
flowchart LR
spec["spec Form: sections[].fields"] --> validate["validateBlockOptions (spec as written)"]
validate --> issues["issues at /sections/i/fields/j"]
spec --> serialize["componentOptionsOf: fields += section fields, section.fieldIds"]
serialize --> component["dms-form draws the sections"]
```
## Proof
`packages/dms/src/test/unit/mockup/form-sections.test.ts` compares the
compiled options with what the real `Form` factory serializes, for
`Form` and for `ResourceForm`.
Before (on `origin/main` sources):
```
[unit] a mockup form written with sections that hold their fields
1) reaches the component in the layout the Form factory serializes (fails when the sections reach it with fields and no fieldIds)
2) reaches the component of a ResourceForm in the same layout (fails when only the Form block is serialized)
✔ keeps a section that names its fields by id as written (fails when the serialized layout is rewritten)
✔ reports a bad field inside a section at its pointer in the spec (fails when validation reads the serialized layout)
2 passing (136ms)
2 failing
AssertionError: expected { fieldIds: [ 'intro' ], …(1) } to deeply equal { fieldIds: [ 'intro', …(3) ], …(1) }
```
After:
```
✔ reaches the component in the layout the Form factory serializes (fails when the sections reach it with fields and no fieldIds)
✔ reaches the component of a ResourceForm in the same layout (fails when only the Form block is serialized)
✔ keeps a section that names its fields by id as written (fails when the serialized layout is rewritten)
✔ reports a bad field inside a section at its pointer in the spec (fails when validation reads the serialized layout)
✔ reports a section that both holds fields and names them by id, at its fieldIds (fails when the written ids are dropped in silence)
```
The `mockup/compile`, `mockup/starter-nodes` and frontend
`mockup-starters` and `mockup-catalog` suites pass. On a verify-dms
playground run, the `smoke`, `mockups` and `module-pages` journeys all
pass. A spec Form with sections draws them in `/mockup`, and adding a
Form from the Edit-mode Add tab draws its `Contact` section. Screenshots
and a video are kept outside the PR.
## Attention
The playground's dev backend does not start on `main` today. The
`@antelopejs/mongodb` `^1.4.3` range resolves 1.8.0, which implements
interface-database 0.4.0, and `interface-database-decorators` 0.3.1
still calls `.then` on a query. For the proof runs only, the mongodb
module was pinned to 1.7.0 in the run's copy, and that pin is not
committed. #907 moves dms to interface-database 0.4.0.
Upd4ting
added a commit
that referenced
this pull request
Nov 14, 2026
…ol up --dev-backend (#942) ## Why An agent that reads the verify-dms feature files to drive a development-only page should be pointed at the harness command that starts a development backend. It should not learn that it has to start one by hand, or that it cannot drive the page at all. dms#881 added `dms-control up --dev-backend`, and journeys name their backend with `backend: "dev"` or `"production"`. ## What - `features/branding.md`. The gotcha said a run's backend is always `ajs project start`, so the editor "cannot be driven there". It now says `branding-absent-outside-dev` pins `backend: "production"`, and that driving the editor by hand needs `dms-control up --dev-backend` and an administrator session. Both pages have been owner-only since #887. - `features/mockups.md`. #887 already pointed this gotcha at `up --dev-backend`. It now names the full command, `dms-control up --dev-backend`, as Branding does. ## Proof Docs-only change to two agent-facing Markdown files. No code, test or config changes. Gotcha before: ``` - A run's backend is `ajs project start` on a build, so it is not in development and the editor itself cannot be driven there; only its absence is. ``` Gotcha after: ``` - `branding-absent-outside-dev` sets `backend: "production"`, so it passes in any run. To drive the editor by hand, run `dms-control up --dev-backend` and sign the browser in as the administrator first: the page refuses anyone else. ``` The statements are taken from the code. `journeys/branding.mjs` sets `backend: "production"`. SKILL.md describes `--dev-backend` as running `ajs project dev -e docs`. `src/test/integration/owner-only-dev-pages.test.ts` covers the owner-only Branding and mockup pages. The drive itself did not run end to end. On main (`debd8d0ad`), `dms-control up --prepare --dev-backend` and a plain `dms-control up` both stop with a backend that fails to start: ``` ✖ Failed to start modules this.table.get(...).then is not a function ``` The playground resolves `@antelopejs/interface-database-decorators` 0.3.1, and its `Model.get` calls `.then` on a query. That breakage is unrelated to this PR. #907 moves to interface-database 0.4.0.
Upd4ting
added a commit
that referenced
this pull request
Nov 14, 2026
…944) ## Why The verify-dms journey `mcp-server/page-verify-reports-a-page` fails with `desktop: block table (dms-table-view) is missing` on the playground's users page. That page draws its table. The cause is `page_verify` itself, not the journey's page. ## Cause The page probe walked the Vue tree from `element.__vue_app__._instance.subTree`. Vue sets `app._instance` only in a development build or one with `__VUE_PROD_DEVTOOLS__`. The dashboard `ajs dms build` serves is a production build, so the walk found no `RecursiveComponent` and every block of the layout read as missing. The table's data check still passed, because it reads the `data-dms-block-state` attributes from the DOM. On the live run, the users page held one mount root (`#app`) with `__vue_app__` set, `_instance` null, and `#app._vnode` set to the root component vnode. ## Change The probe walks from `element._vnode`, the root vnode that Vue's `render` and `hydrate` store on the mount element in every build. ```mermaid flowchart LR root["mount element (#app, data-server-rendered)"] -->|before| inst["__vue_app__._instance.subTree<br/>(null in a production build)"] --> none["no block found: every block 'is missing'"] root -->|after| vnode["_vnode (set by render and hydrate in every build)"] --> walk["walk to each RecursiveComponent"] --> found["blocks found by layoutPath"] ``` ## Proof `src/test/unit/mcp/page-verify-probe.test.ts` mounts an app from Vue's production build in jsdom, asserts the app holds no `_instance`, and runs `probePage` on it. Probing from `_instance`, as before, it finds no block. Before (the new test against the old probe): ``` 0 passing (161ms) 1 failing 1) [unit] mcp page_verify probe finds the blocks of an app mounted from Vue's production build, which keeps no app instance: AssertionError: expected [] to deeply equal [ { path: 'table', …(1) } ] + expected - actual -[] +[ + { + "componentName": "dms-table-view" + "path": "table" + } +] ``` After (`page-verify-probe.test.js` and `page-verify.test.js`, under `scripts/backend-runtime-boundaries.cjs` as `test:unit` runs them): ``` 9 passing (234ms) ``` The journey on a dms-control run, before: ``` FAIL mcp-server/page-verify-reports-a-page 03-the-users-page-passes-and-the-unknown-route-fails: users page passes (["desktop: block table (dms-table-view) is missing"]) ``` After, the whole `mcp-server` feature: ``` PASS bridge-initializes-and-lists-tools PASS bridge-calls-a-read-tool PASS bridge-refuses-unknown-tool-and-method PASS route-refuses-uncredentialled-callers PASS page-verify-reports-a-page PASS bridge-files-published ``` Both runs used #907's head with and without this change. On main today the playground backend does not start (`this.table.get(...).then is not a function`). The playground's `@antelopejs/mongodb` `^1.4.3` now resolves 1.8.0, which implements interface-database 0.4.0, while the lockfile pins interface-database-decorators 0.3.1. #907 moves dms to interface-database 0.4.0. The journey passes on main once both PRs land.
Upd4ting
added a commit
that referenced
this pull request
Nov 14, 2026
…945) ## Why No test ran `page_verify` as a member role against a mockup (seen in ANT-2391). The unit harness has no browser, so the path where the page opens as a member while the `/mockup` viewer, which only the owner may open, opens through the owner's session was never exercised. ## What A verify-dms journey, `mcp-server/page-verify-member-against-mockup`, on a development backend: 1. writes a one-table mockup to the run's `mockups/page-verify-member/`; 2. creates a role holding the users page and its table, and invites a member with only that role; 3. checks the owner reads `GET /api/mockup/page-verify-member` (200) and the member is refused (403); 4. calls `page_verify` through the stdio bridge with `role` and `mockup`, and checks the report names the member, the viewer drew the mockup, its screenshot is written, the mockup table pairs with the page table, and the member's page drew that table. The feature file lists the journey and a gotcha: run the `page_verify` journeys on `up --dev-frontend`. On the built dashboard the tool's block probe misses the users table, which the page draws. The existing `page-verify-reports-a-page` fails there for that reason, and passes on the dev frontend. ```mermaid sequenceDiagram participant J as journey participant B as page_verify (bridge) participant M as member context participant O as owner context J->>J: write mockups/page-verify-member/spec.json J->>J: role + invited member (only that role) J->>B: page_verify {page, role, mockup} B->>M: open /table-view/table-view-users B->>O: open /mockup?name=page-verify-member (owner-only) B-->>J: report: account=member, mockup matched ``` ## Proof Run on a playground started with `dms-control up --dev-frontend`. `main` cannot boot the playground today: `@antelopejs/mongodb ^1.4.3` resolves a release for interface-database 0.4.0 while `main` runs decorators 0.3.1 (`this.table.get(...).then is not a function`). #907 fixes that, so the run used a scratch checkout of #907's head with this PR's two files copied in. Before (the journey did not exist): ``` $ dms-control journey "$RUN" mcp-server page-verify-member-against-mockup dms-control: Unknown journeys of mcp-server: page-verify-member-against-mockup ``` After, the checks of the final step: ``` True signed in as a member True the member is the invited one True the member holds the asked role True the comparison names the mockup True the viewer drew the mockup True the mockup screenshot is written True the mockup table pairs with the page table True the member's page drew that table ``` `page-verify-reports-a-page` and `page-verify-member-against-mockup` both `PASS` on the same run.
Upd4ting
force-pushed
the
fix/interface-dms-stored-row
branch
from
November 14, 2026 02:44
8b13090 to
0ff7f02
Compare
Upd4ting
added a commit
that referenced
this pull request
Nov 14, 2026
ANT-2384. interface-data-api 0.7.0 replaced the published `RowFields` with `StoredRow`. `@antelopejs/interface-dms` 0.13.3 still names `RowFields` in its published declarations and accepts data-api `>=0.6.0 <1.0.0`. A fresh project resolves data-api 0.7, so a module the Builder's Connect generates fails `tsc`. ⚠ sensitive: this changes the interface-dms contract: its published declarations (metadata constructors, `.target`, `CreatedPage.target`, `DataType.filter`, `StoredRow`) and its peer ranges. ## Published declarations and query parameters that change Published declarations (interface-dms): - `TableViewMeta`, `SearchableMeta` and `PageMetadata`: the constructor parameter and the public `target` are `DecoratorTarget` (were `Class` / `ControllerClass`). interface-core 0.5's `GetMetadata` constructs a metadata class with whatever it is called on, prototype-chain links included, down to `Object.prototype`. - `CreatedPage.target` (what an `onCreated` hook receives) is `DecoratorTarget` (was `ControllerClass`), since the hook receives the `PageMetadata` itself. - A reader that needs the controller narrows through `@internal` `pageController` (`page/internal/page-controller`), which throws `PageTargetError` (a `TypeError`) for a non-controller target; dms's bulk selection checks that the target is a function and answers 500 otherwise, before its existing prototype check. - `DataType.filter`'s `value` is `FilterValue[0]` (`string | boolean`), and the table-view routes name `StoredRow` (see Summary). - Peers: interface-data-api `>=0.8.0 <0.9.0`, interface-database-decorators `>=0.5.2`, interface-core `>=0.5.1`; dms and the playground take interface-data-api `>=0.8.0 <1.0.0` (the interface range check refuses a cap below the next breaking release there), interface-api `>=0.3.0`, interface-core `>=0.5.1` and `@antelopejs/core` `>=1.23.0` (core 1.21 pins interface-core 0.4.0 exactly). - interface-database stays on 0.3 here: interface-data-api 0.8.0's `>=0.4.0 <0.5.0` peer is unmet on this PR and CI is green with it; #907 moves to 0.4. Query parameters (interface-api 0.3 types `@Parameter(name, "query")` as `string | true | undefined`; `?name` with no value arrives as `true`). Main's #934 typed the 12 dms parameters and added `queryText`, which reads a valueless parameter as absent. Four of them still let `true` through, and this PR routes them through `queryText`: notifications `limit` and `offset` (`Number(true)` is 1, so `?offset` skipped the first notification) and files `resourceKey` and `storage` (`true` reached the metadata schema, a 400 with another message). None of the 12 is read as a flag: | Route | Parameter | A valueless `?name` now | | --- | --- | --- | | `GET /dms/page` | `path` | 400 `error.path_required`, as when missing | | `GET /dms/page` | `shared` | absent: the shared page is included, as without it | | `GET /dms/frontend` | `clientUrl`, `renderer`, `rendererVersion` | absent, the manifest as without them | | `GET /dms/pagelayout` | `slug` | 400 `error.slug_required`, as when missing | | `GET <notifications>/list` and `/inbox` | `limit`, `offset` | absent: default page size and offset (fixed here) | | `GET /api/files/metadata` | `resourceKey` | 400, as when missing (fixed here) | | `GET /api/files/metadata` | `storage` | absent, the default storage (fixed here) | `src/test/integration/valueless-query.test.ts` checks each against the same request without the parameter (5 tests, 12 parameters). Before the fix, the notifications and file metadata tests failed: ``` /dms/pages/settings/user/notifications/list?limit&offset - "body": [] + "body": [ { "_id": "notification-recent:…", "title": "$dms.notifications.messages.welcome.title", … } ] /api/files/metadata?resourceKey - "message": "Expected string, received boolean" + "message": "Required" ``` The playground (a private demo module) follows the same rule at its query parameters through its own `queryText` (main's #934); it is covered by its typecheck only. ## Summary ```diff @antelopejs/interface-dms - peer interface-data-api >=0.6.0 <1.0.0 + peer interface-data-api >=0.8.0 <0.9.0 - DataType.filter(…, value: string, …) + DataType.filter(…, value: FilterValue[0], …) // string | boolean; compare modes get String(value) dist/base/table-view/routes.d.ts (TableViewRoutes.Get, Edit, get, edit) - DataControllerCallback<…, import("@antelopejs/interface-data-api/metadata").RowFields, …> + DataControllerCallback<…, import("@antelopejs/interface-data-api/metadata").StoredRow, …> internal/column-conditions.ts - row: RowFields + row: GuardRow // NonNullable<Awaited<ReturnType<typeof fetchRowForGuard>>> @antelopejs/dms - RowFields in guard-row, footer-summary, search-route, table-view, invite routes, export jobs, row rules + StoredRow - String(row[idField]) + rowIdText(row[idField]) // same text for primitives and dates; refuses a row, list or document id interface-database-decorators >=0.3.1 -> >=0.5.2 ``` Why decorators move: data-api 0.8 declares its modifier keys as `Class<ContainerModifier>` and requires decorators `>=0.5.0`. Decorators 0.3.1's `LocalizationModifier` does not satisfy that type (TS2345 in `src/test/attachment-host/native.ts`). With decorators 0.5.2 the workspace typechecks on interface-database 0.3.1, and the unit suite passes on mongodb 1.6.2. The interface-database 0.4.0 move stays in its own PR (ANT-2382). The `ContainerModifier` TS2635 in the task comes from data-api's own declarations: data-api 0.7.1 and 0.6.3 write `typeof ContainerModifier<any>`, which decorators 0.5.x refuses. data-api 0.8 fixes it, so the new floor covers it. Why `DataType.filter` widens: data-api 0.8 types a filter value as `string | boolean`, so a field's filter can be handed a boolean. `DataType.filter` takes that type and hands its compare mode `String(value)`, which the value parser reads back as the same boolean; the date type's override reads it as text. Main's #947 now sends the archive filter as the text `"true"`; its `@internal` `filterArchiveField` takes the same `string | boolean` here and reads a boolean as itself (`table-view-archive-field.test.ts` fails when a boolean is refused). `packages/interface-dms/UPGRADING.md` has an Unreleased section with these changes. ## Evidence Consumer typecheck of a module the Builder generates. It is produced by the engine (`MapResources` on a two-table catalog with a relation, then `scaffoldLocalModule`) with the Builder's default compiler options and no hand edit. It is installed from public npm with interface-database 0.4.0, decorators 0.5.2, interface-core 0.5.1 and interface-api 0.3.2. Then `npx tsc --noEmit -p .`: - **Before:** published interface-dms 0.13.3 with data-api 0.7.1, exit 2: ``` node_modules/@antelopejs/interface-data-api/dist/metadata.d.ts(39,48): error TS2635: Type 'typeof ContainerModifier' has no signatures for which the type argument list is applicable. node_modules/@antelopejs/interface-data-api/dist/metadata.d.ts(166,74): error TS2635: Type 'typeof ContainerModifier' has no signatures for which the type argument list is applicable. node_modules/@antelopejs/interface-data-api/dist/metadata.d.ts(278,76): error TS2635: Type 'typeof ContainerModifier' has no signatures for which the type argument list is applicable. node_modules/@antelopejs/interface-dms/dist/base/table-view/routes.d.ts(12,115): error TS2694: Namespace '".../interface-data-api/dist/metadata"' has no exported member 'RowFields'. node_modules/@antelopejs/interface-dms/dist/base/table-view/routes.d.ts(44,117): error TS2694: Namespace '".../interface-data-api/dist/metadata"' has no exported member 'RowFields'. node_modules/@antelopejs/interface-dms/dist/base/table-view/routes.d.ts(77,122): error TS2694: Namespace '".../interface-data-api/dist/metadata"' has no exported member 'RowFields'. node_modules/@antelopejs/interface-dms/dist/base/table-view/routes.d.ts(86,124): error TS2694: Namespace '".../interface-data-api/dist/metadata"' has no exported member 'RowFields'. ``` **After:** interface-dms packed from this branch with the data-api tarball (then 2def09c, packed as 0.7.2): `tsc` exits 0 with no output. - Forcing data-api 0.6.3 under this branch's interface-dms fails on `StoredRow` at the same four lines, so the floor is needed. - Workspace, rebased on main 1416277: - `pnpm run typecheck` passes, and backend-checks pass. - Locally: the builder specs that failed on the previous CI run (`query-response`, `query-roundtrip`, `compose-page`) pass 31/31 on #934's emitter with no emitter change; `valueless-query` and `table-view-archive` integration pass 9/9; `table-view-archive-field` passes 5/5. CI runs the full suites. - `pnpm run checks` fails only on `eslint(max-lines)` in `dms-builder/engine/project-config.ts`, which fails the same way on main and is being fixed outside this PR. ## Merge Danger **Door:** two-way in the repo. The published contract is one-way once released: interface-dms requires data-api `>=0.8.0 <0.9.0`, so a module on data-api 0.6 must move with it. **Blast Radius:** wide. It covers every module that types against `TableViewRoutes.Get` or `Edit`, and every project's data-api and decorators versions. dms-saas and dms-database consume this branch.
This branch has not been deployed
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.
ANT-2382. Moves dms onto
@antelopejs/interface-database0.4.0, where a query is a plain object that runs only through.run(). Stacked on #888 (fix/interface-dms-stored-row).⚠ sensitive: it changes the interface-dms contract (peer
@antelopejs/interface-database>=0.4.0 <1.0.0) and the database module a deployment must run.tgz-pending:
@antelopejs/interface-data-apicomes through fix(interface-dms)!: move to interface-data-api 0.7's StoredRow #888's tarball: main 170f079, packed as 0.8.0.@antelopejs/interface-dms-buildercomes through.tgz-deps/antelopejs-interface-dms-builder-b04af21.tgz: this repo's own builder, packed as 0.4.2. npm's 0.4.1 is notstandalone, so a project loading the DMS without a builder module fails with "Unresolved interface dependencies: dms requires @antelopejs/interface-dms-builder".swap-tgz.shrestores>=0.8.0 <0.9.0and>=0.4.2 <1.0.0.Summary
#903 already made the runtime run its own queries through
.run(). This PR adds:packages/dms/docs/02.building/20.migration-interface-database-0-4.mdis the deployment and module guide.packages/interface-dms/UPGRADING.md(Unreleased) lists the peer range.Evidence
registerExistingTenantInstancesbuilds aSetfrom a query object ("object is not iterable"). ANT-2375's live run saw "this.table.get(...).then is not a function" with decorators 0.3.1.After:
dms-control up --prepareboots the playground on mongodb 1.8.0 (loaded from.antelope/cache, version 1.8.0),doctorpasses, and thesmokejourney passes (15 steps, invite mail captured).run()and nothenthat is awaited, put inPromise.all/race, given a.then, or returned from anasyncfunction. It finds 0 on this head. On main's oldtenant-instances.tsit reports the 4 broken sites, so it sees them. Queries typedanywould escape it.table-view-capabilities17 (/count/batchanswers{ mine: 2 },POST …/newno longer answers 500);test:unit2629;pnpm run checks11/11.findUnresolvedInterfaces, run on a freshnpm installof the packed dms:dms requires @antelopejs/interface-dms-builderis unresolved.standaloneand nothing is unresolved.Attention
>=0.13.0 <0.14.0here. The releasevalidatejob requires the interface version in the tree to satisfy that range, and the workspace links interface-dms only while its 0.13.x version satisfies it. So raising it before interface-dms 0.14.0 is bumped breaks install and validation. interface-dms'safter:bumprunssyncand stages dms's README, but does not move dms's range. The raise to>=0.14.0 <0.15.0therefore has to be committed right after the interface-dms 0.14.0 release and before dms 0.20.0..run(). Builder-generated stats routes written before this PR answer with the query object until.run()is added; the guide says so.Merge Danger
Door: one-way once released. Deployments must run a database module that implements interface-database 0.4, and modules must run their queries through
.run().Blast Radius: wide. Every deployment's database module, every module that queries the database, and the code the Builder generates.