Merge main into stable#3458
Merged
Merged
Conversation
…ted-link regression
…inding for documentMode change
… command parsing - Updated `launchHost` function to accept an optional `extraArgs` parameter for additional command-line arguments. - Implemented tests to validate the behavior of the `--request-timeout-ms` flag, ensuring it correctly triggers a timeout error when set to a low value and rejects non-positive integers. - Introduced `parseHostCommandTokens` function to handle command-line argument parsing, including validation for the `--request-timeout-ms` flag. - Added end-to-end tests to verify that the SDK correctly propagates the `requestTimeoutMs` option to the host process. - Enhanced documentation for command usage to include the new timeout option.
…outms-from-superdocclient-to
…(SD-3212 a0) The superdoc root entry resolves through four package.json#exports fields that can diverge: - types.import → dist/superdoc/src/index.d.ts - types.require → dist/superdoc/src/index.d.cts - import → dist/superdoc.es.js - require → dist/superdoc.cjs This adds a no-growth gate on each source's name set independently, plus a companion evidence report for the SD-3212 classification pass (PR A1). What ships: - snapshot-superdoc-root-exports.mjs: enumerates each source via TS API (for .d.ts/.d.cts) or AST/string scan (for the bundled .es.js/.cjs). - snapshots/superdoc-root-exports.json: canonical baseline. Drift in any source name set fails the gate. - snapshots/superdoc-root-exports.md: human review surface with evidence columns per name (presence in each source, fixture import count, JSDoc typedef membership, docs/examples/demos mentions, package-boundaries.md reference). Regenerated on --write; not a drift gate. - CI hook in ci-superdoc.yml runs --check after the consumer matrix has packed and installed the fixture. What it gates and what it doesn't: - gates: drift in any of the four source name sets vs baseline. - not gates: cross-source mismatches (typed-only / runtime-only / ESM vs CJS divergence). Those are reported as evidence for A1, not blockers. - not gates: docs/examples mention counts. Unrelated docs edits will not make the snapshot noisy. Initial baseline numbers: types.import: 200, types.require: 200 (perfect parity) import: 41, require: 41 (perfect parity) union: 200 typed-only: 159 (matches the JSDoc typedef block; classification in A1) runtime-only: 0 (no silent shadow on root) This is PR A0 of the SD-3212 split: inventory + snapshot only. No src/public/index.ts change, no classification bucket assigned. A1 layers the bucket column on top of this report; B re-curates the facade; C is the mechanical root types flip.
PR CI already runs the SD-3212 root snapshot --check. Mirror that into release-superdoc.yml and release-stable.yml so a release cannot bypass the new root baseline. Matches the existing SD-3176 legacy-gate pattern that already runs in all three workflows.
Adds `ui.metadata.getRect({ id })` and `ui.metadata.scrollIntoView({ id })`
keyed on the metadata id (= the value passed to
`editor.doc.metadata.attach`, or the SDT's w:tag underneath). The
handle hides the metadata-id → SDT-node-id → painter-geometry bridge
that the SD-3208 demo had to compose by hand from
`useSuperDocContentControls` + a tag→nodeId map +
`ui.contentControls.getRect`.
Failure mapping reuses the existing ViewportRectResult union:
empty id → `invalid-target`; unknown id (no matching
`properties.tag` in cc.items) → `unresolved`; SDT present but
unpainted → whatever `contentControls.getRect` returns
(`not-mounted` / `not-ready`) propagates as-is.
`scrollIntoView` resolves the id via
`editor.doc.metadata.resolve`, converts the SelectionTarget into a
TextTarget (same-block is one segment, cross-block is two collapsed
endpoints — defensive, since metadata v1 anchors are same-block),
and forwards to `ui.viewport.scrollIntoView`. nodeEdge endpoints
fail with `{ success: false }` rather than approximating.
No `getRects` (`ViewportRectResult.success.rects[]` already
exposes the per-line array), no namespace param (`attach` enforces
globally unique ids), no React hook, no mutation helpers — those
wait for second-customer signal.
…nventory-snapshot feat(consumer-typecheck): root export 4-source snapshot + drift gate (SD-3212 a0)
…outms-from-superdocclient-to
…data.* (SD-3204)
Anchored-metadata uses an inline SDT's `w:tag` to mark anchors in
the body, but `w:tag` is not reserved for metadata — an imported
DOCX can carry Word-authored content controls whose tag happens to
match a metadata id. `editor.doc.metadata.resolve` previously
matched on tag alone, so foreign controls would resolve as if they
were metadata anchors and any consumer (including `ui.metadata.*`)
would be steered at an unrelated control.
Fix at the source: `metadataResolveWrapper` now requires both
halves of the anchor — the SDT in the body AND a payload entry in a
customXml part — to agree before returning a non-null result.
Mirrors what `metadata.get` already does for payload reads.
Defensive UI-layer gate: `ui.metadata.getRect` and
`ui.metadata.scrollIntoView` both call `editor.doc.metadata.get`
first and short-circuit on null. Keeps the UI handle symmetrical
for direct callers that bypass `resolve` and protects against the
same class of bug if a future source-side change widens `resolve`.
Tests:
- anchored-metadata-wrappers: foreign SDT with matching w:tag and
no payload → `metadata.resolve` returns null.
- ui.metadata.getRect / scrollIntoView: same scenario → reports
`unresolved` / `{ success: false }` without delegating to
viewport.
`hasMetadataPayload` used `!== null` against an `unknown | null` structural return type. Production `metadata.get` always returns null on miss, so this was correct for the runtime path, but a stub or adapter returning `undefined` would have slipped through. Switched to `!= null` so both shapes gate the same way.
…adata-geometry feat(ui): metadata-id geometry on ui.metadata (SD-3204)
Classification of all 200 names in the locked SD-3212 PR A0 root-exports
snapshot. Each name is assigned a bucket with rationale and confidence:
- supported-root (132): documented public API; first-class root surface.
- legacy-root (59): real historical API or compat-required type;
typed for compat, not the recommended root story.
- internal-candidate (9): accidental implementation leak; not used in
any exported class/method signature.
- move-to-subpath (0): no canonical subpath destinations exist today
for the root candidates (verified during A1).
Rubric: supported-root is documented public API; legacy-root is real
historical API kept typed for compat; internal-candidate is accidental
leak (not in any exported method signature).
Dependency-closure rule applied: a type required to type a supported-root
or legacy-root exported class/method must be at least legacy-root.
Examples surfaced and applied during classification:
- PresentationEditor.getPages(): LayoutPage[] → LayoutPage,
LayoutFragment legacy-root.
- PresentationEditor.onLayoutUpdated payload → LayoutState, Layout,
LayoutMetrics, FlowBlock, Measure legacy-root.
- PresentationEditor.getPaintSnapshot() → PaintSnapshot legacy-root.
- PresentationEditor.setTrackedChangesOverrides → TrackedChangesOverrides
legacy-root.
- Editor extends EventEmitter<EditorEventMap> → PaginationPayload,
ListDefinitionsPayload legacy-root (also EditorConfig.onListDefinitionsChange).
- Config.layoutEngineOptions: SuperDocLayoutEngineOptions → supported-root.
Out of scope for A1: no src/public/index.ts change, no package.json#exports
change, no root flip. PR B re-curates src/public/index.ts using this
artifact; PR C flips package.json#exports['.'].types after PR B.
Verified locally:
- All 200 names from the A0 baseline are present in the classification.
- All buckets are approved enum values.
- 98 high-confidence, 100 medium-confidence, 0 needs-review.
Enforces the SD-3212 A1 dependency-closure rule mechanically: no
supported-root or legacy-root exported root symbol may reference an
internal-candidate root symbol in its public declared type.
v1 scope (intentionally narrow):
- Loads emitted root .d.ts via TS compiler API.
- For each supported-root and legacy-root exported root symbol, walks
the declared type (properties, union/intersection members, call
signatures including parameters and return types, type arguments)
with a bounded-depth visited-set walk.
- Asserts no referenced root symbol is classified internal-candidate.
- Supports a manual OVERRIDES set for DOM globals / upstream types /
generic utility shapes (empty today).
Out of scope for v1:
- Runtime implementation analysis.
- Private field walks (TS hides # private fields from getProperties).
- Cross-package type origins (only asserts within root-exported names).
Caught a real violation on first run:
SectionMetadata was classified internal-candidate but is the return-
type member of PresentationEditor.getLayoutSnapshot()
({ ..., sectionMetadata: SectionMetadata[] } at line 2744). Manual
classification missed it because the name also appears in #private
fields (line 504). Closure walk traced Editor -> PresentationEditor
-> getLayoutSnapshot return -> SectionMetadata.
Fix applied: SectionMetadata promoted to legacy-root with rationale
referencing the PE.getLayoutSnapshot exposure.
New final v6 distribution:
supported-root: 132
legacy-root: 60 (+1 from SectionMetadata)
internal-candidate: 8 (-1)
move-to-subpath: 0
Gate wired into ci-superdoc.yml + release-superdoc.yml +
release-stable.yml alongside the existing SD-3176 and SD-3212 A0 gates.
This PR is stacked on the SD-3212 A1 classification PR (#3380) and
should merge after A1.
…rides (SD-3212 a1b)
Per review feedback: the OVERRIDES escape hatch should require a reason
string per entry, not just a symbol name, so any future exception is
reviewable and searchable later via grep.
Changes:
- OVERRIDES is now Map<symbolName, reasonString> instead of Set<string>.
- Startup validator aborts (exit 2) if any entry has a missing or too-short
(<20 chars) reason.
- When an override is applied during the check, the script logs the symbol
pair and the reason so the audit trail is visible in CI output.
Empty today. Any addition must land in its own PR with the rationale
visible in the commit message.
…osure-gate feat(consumer-typecheck): root classification closure gate (SD-3212 a1b)
…changes-remaining-jsdoc fix(types): type remaining trackChangesHelpers via JSDoc (SD-2980 PR C)
…se 1) Today, validating the published superdoc public type surface requires three separate invocations across different working directories: pnpm run build:superdoc cd tests/consumer-typecheck && node deep-type-audit.mjs --pack --strict-supported-root cd tests/consumer-typecheck && node typecheck-matrix.mjs This wrapper orchestrates them as one command: pnpm check:public-contract Behavior: - Runs each stage in order, prints a section header per stage - Fails fast on the first failure so the real error stays visible - Prints a PASS / FAIL summary with elapsed time at the end - On FAIL, prints the exact command to re-run the failing stage for iteration - Zero behavior change for the validators themselves; pure DX Phase 1 of the SD-3256 umbrella (public-contract consolidation + ./super-editor facade curation). Phase 1 deliberately adds no new enforcement and no config changes; it just collapses three invocations into one obvious entry point. Phases 2-4 (tier metadata, ./super-editor facade, ratchet) are tracked separately under SD-3256 and need design / team alignment before implementation. Verified locally: pnpm check:public-contract → PASS (3 stages, 189s) on post-SD-2980 main. Each stage's exit code is preserved.
…-check-public-contract-wrapper feat(scripts): add check:public-contract wrapper command (SD-3256 Phase 1)
…e 2) Adds a `publicContract` section to the canonical `type-surface.config.cjs`. Every `package.json#exports` subpath now has a declared tier: - supported (4): root, ./types, ./ui, ./ui/react — route through src/public/** - legacy (6): ./converter, ./docx-zipper, ./file-zipper, ./headless-toolbar, ./headless-toolbar/react, ./headless-toolbar/vue — route through src/public/legacy/** - legacy-raw (1): ./super-editor — resolves directly to dist/superdoc/src/super-editor.d.ts, NOT through src/public/legacy/**. SD-3256 Phase 3 will curate this through src/public/legacy/super-editor.ts after team alignment on which exports stay public. - asset (1): ./style.css — no types - deprecated (0) This phase is design-light: it adds metadata + a read-only report script. NO new enforcement, NO behavior change, NO export changes. The classification is open for team review before Phase 3 / Phase 4 build on it. New command: pnpm report:public-contract Prints the tier breakdown plus a cross-check that every `package.json#exports` subpath has a `publicContract` entry and vice versa. The cross-check warns but does not fail CI in this phase (read-only by design); Phase 4 will gate. Source-of-truth notes in the config explain each tier's intended policy (supported = strict gate, legacy = no-growth, legacy-raw = Phase 3 target). Phase 4's ratchet will read these tiers to apply per-tier enforcement rules. Verified: pnpm report:public-contract → 12 / 12 entries, cross-check OK. pnpm check:public-contract → PASS (3 stages, 199s). pnpm run type-check clean. pnpm run build:superdoc clean.
…-tier-metadata feat(scripts): add public-contract tier metadata report (SD-3256 Phase 2)
…22-123951 🔄 Sync stable → main
…t (SD-673 Phase 1) Makes `pnpm check:public-contract` the single official path for public-type validation, locally and in CI. **No coverage change**: exactly the same scenarios run; only the orchestration changes. Wrapper changes: - Reordered stages so `typecheck-matrix` runs BEFORE `deep-type-audit`. Matrix packs and installs the superdoc tarball into the consumer fixture as part of its normal run; the audit then reuses that install instead of doing a redundant `--pack` of its own. Drops one pack + install per invocation. Local full-run time: 199s → 135s. - New `--skip-build` flag. CI's existing Build step already runs `pnpm run build` (= `build:superdoc && type-check`); the wrapper must not re-build. Local users get the full from-scratch behavior by default. - Skip output now reports `N ran, M skipped` so CI logs make the skip explicit instead of silently dropping a stage. CI changes (`.github/workflows/ci-superdoc.yml`): - Removed: `Consumer typecheck (matrix)` step - Removed: `Deep public-type audit (supported-root strict, SD-3213e)` step - Added: `Public-contract check (matrix + supported-root strict audit)` which runs `pnpm check:public-contract --skip-build`. Single step, identical coverage. Net: 10 named CI steps → 9. Why now: SD-3256 Phase 1 shipped the wrapper but only as a DX tool. SD-673 Phase 1 makes it the load-bearing CI path so "is the public contract healthy?" has exactly one command answer, locally and in CI. Future phases (additional stages, stricter gates) extend one wrapper instead of duplicating CI yaml. Verified locally: pnpm check:public-contract → PASS (3 stages, 135.6s) pnpm check:public-contract --skip-build → PASS (2 ran, 1 skipped, 97.9s)
Doc-backed operations missing from the CLI response-envelope hint table were silently serialized under a literal "undefined" property, and the SDK contract exporter coerced the same missing entry to a null envelope key, leaking the wrap to SDK callers. Customer hit this on doc.create.contentControl. Backfill the four hint maps so every CliExposedOperationId has an entry, add fail-closed hasOwnProperty guards in both orchestrators and the SDK exporter, generalize the conformance "no undefined key" check from doc.history.* to all ops, and add a runtime coverage test (apps/cli does not run tsc --noEmit in CI, so the type-level exhaustiveness check isn't enforced). Follow-up SD-3259 tracks moving from four hand-maintained Records to derived defaults plus override layers.
Per repo convention, comments shouldn't reference task IDs that go stale. The why-lines remain; the (SD-XXXX) parentheticals are gone.
…(SD-673 Phase 2) Disposes the 6 doc-api check scripts that the Phase 0 audit flagged as "orphan" (not wired into CI). Reading the existing `packages/document-api/scripts/README.md` reframes the picture: three of the six are intentionally documented as focused local-debug variants of `check-contract-outputs` (the per-PR superset). One is genuinely missing from the wired chain. Two are intended as per-PR gates but blocked by pre-existing content drift on main. Phase 2 makes the classification explicit: - **Per-PR (wired into `docapi:check`)**: `check-contract-parity`, `check-contract-outputs`, **`check-examples`** (newly wired here; passes on main, low-cost, ensures workflow example headings stay documented in `src/README.md`). - **Focused / manual**: `check-stable-schemas`, `check-agent-artifacts`, `check-generated-reference-docs`. Targeted local-debug variants of `check-contract-outputs`. Not wired into CI by design (the superset already covers their failure modes). Status was already in the scripts README; this PR makes the "not in CI by design" framing explicit. - **Per-PR intent, blocked by drift**: `check-doc-coverage` (5 missing operation sections in `src/README.md`), `check-overview-alignment` (missing alpha + subject-to-change disclaimers in `apps/docs/document-api/overview.mdx`). Wire after the drift is fixed. Follow-ups: SD-3261, SD-3262. Net change: - `docapi:check` now runs 3 scripts (was 2): parity + outputs + examples. - `packages/document-api/scripts/README.md` gains a "Which checks run where" section so the disposition is visible at the call site. - No deletions; no script removals. The "focused" ones stay as documented local-debug tools. Stacks on #3450 (Phase 1 CI wiring). After #3450 merges and this lands, "is the doc-api contract healthy?" has exactly one CI-wired command (`docapi:check`) covering parity + outputs + examples. Verified: `pnpm run docapi:check` → exit 0 (parity: 403 ops; outputs: 446 files; examples: 5 found).
…check-public-contract-ci ci(types): collapse matrix + audit CI steps into check:public-contract (SD-673 Phase 1)
The hasOwnProperty guard inside buildEnvelopeData fired AFTER invokeOperation and any persistence step (exportToPath, writeContextMetadata, session pool mark-dirty). A drifted hint table would have advanced on-disk state before the OPERATION_HINT_MISSING error surfaced. Extract resolveResponseEnvelopeKey into a small shared helper and call it at the top of both executeMutationOperation and executeReadOperation, before opening the document. buildEnvelopeData now takes the pre-resolved key instead of re-indexing the map. Verified: removing create.contentControl from the hint table now fails the CLI in ~2ms with no output file written; the prior guard would have exported the new docx before throwing.
…imers (SD-3262) `check-overview-alignment.ts` was failing on `main` because the `apps/docs/document-api/available-operations.mdx` page was missing two required disclaimers (the script checks for `/\balpha\b/i` and `/subject to (?:breaking )?changes?/i`). SD-673 Phase 2 deferred this to a follow-up because it was blocked by content drift. Changes: - Add a `<Warning>` block at the top of `available-operations.mdx`: "Status: alpha. The Document API surface is stabilizing but is still subject to breaking changes between minor versions. Pin a version when integrating, and review the changelog before upgrading." Honest customer-facing copy (not boilerplate to satisfy the script) and satisfies both required patterns. - Wire `check-overview-alignment` into `docapi:check`. The chain is now: parity → outputs → examples → overview-alignment. - Update `packages/document-api/scripts/README.md`: move `check-overview-alignment` from "blocked by drift" to "Per-PR (wired)". `check-doc-coverage` stays in the "blocked" bucket but the framing is now "blocked by design question" with a pointer to SD-3261 (rescoped after the original 5-op drift turned out to be 348 ops; needs a docs-model decision before wiring). Note on file path: the original SD-3262 description (and SD-673 Phase 0 audit) referred to `overview.mdx`. The script actually reads `apps/docs/document-api/available-operations.mdx`; the constant `OVERVIEW_PATH` in `lib/reference-docs-artifacts.ts` points there. This PR edits the correct file. Stacks on #3452 (SD-673 Phase 2). After both merge, `docapi:check` gates 4 sub-checks; the only remaining orphan is `check-doc-coverage` under SD-3261. Verified: `pnpm run docapi:sync:check` → exit 0 (parity 403; outputs 446; examples 5; overview 404 member paths).
Removed alpha status warning from the Document API documentation.
…ew-disclaimers docs(document-api): wire check-overview-alignment + add status disclaimers (SD-3262)
…docapi-orphans chore(types): classify doc-api check scripts and wire check-examples (SD-673 Phase 2)
…velope-undefined-key fix(cli): stop wrapping responses under "undefined" key (SD-3260)
The Document API is live, not in alpha. `check-overview-alignment` was still requiring `/\balpha\b/i` and `/subject to (?:breaking )?changes?/i` in `apps/docs/document-api/available-operations.mdx`. That requirement landed in SD-3262 (#3453) when the API's docs explicitly described it as alpha. Commit 1154ede removed the alpha warning from the docs (API is now live), which broke `docapi:check` on main: the script fails because it expects launch-phase framing that the docs correctly no longer have. The fix is to retire the launch-phase requirements, not restore the warning. Per-PR gates should enforce durable structural correctness (reference link present, generated markers present, no stale placeholders, only known `editor.doc.*` paths). They should not force old product positioning back into the docs. Changes: - `check-overview-alignment.ts`: remove `alpha disclaimer` and `subject-to-change disclaimer` from `REQUIRED_PATTERNS`. Keep the `generated reference link` + generated-marker requirements, the forbidden-placeholders list, and the unknown-member-path detection. - Refresh the file header to describe what the gate actually enforces now, and call out that product-status framing is intentionally NOT enforced. - `packages/document-api/scripts/README.md`: update the script-index row description so it matches the new behavior (and the correct filename `available-operations.mdx`, not `overview.mdx`). Verified: `pnpm run docapi:sync:check` → exit 0 (parity 403; outputs 446; examples 5; overview 404 member paths).
…up-stop-requiring-alpha fix(document-api): stop requiring alpha wording in overview check
`check-doc-coverage.ts` required every `OPERATION_ID` (403 today) to have a dedicated `### \`<opId>\`` section in `packages/document-api/src/README.md`. That model was wrong for the current architecture: - Per-operation customer-facing docs are already generated from the contract via `pnpm run docapi:sync` → `buildReferenceDocsArtifacts()` → `apps/docs/document-api/reference/**` (440 files, 403 per-op pages). - The generator is unconditional and `OPERATION_REFERENCE_DOC_PATH_MAP` has 403 entries with 0 missing. - `check-contract-outputs` (wired into `docapi:check`) already gates that those generated files match the contract. The manual README catalog only ever covered 50 of 403 operations (`348 missing` per the script). Closing the gap by hand would duplicate the generated docs and create two sources of truth. The generated reference is the catalog; the README is for concepts, workflows, and contributor notes. Changes: - Delete `packages/document-api/scripts/check-doc-coverage.ts`. - `packages/document-api/scripts/README.md`: remove the script's row from the "Script index" table and drop the now-empty "blocked" bucket from the "Which checks run where" section (was a 3-bucket table; now 2). - `packages/document-api/src/README.md`: replace the 535-line "Operation Reference" section (50 hand-written op subsections plus group headers) with a 13-line pointer to the generated reference docs, explaining where the catalog lives and how to regenerate. README drops from 726 lines to 203. `check-contract-outputs` remains the per-operation reference-doc coverage gate. Verified: `pnpm run docapi:sync:check` → exit 0 (parity 403; outputs 446; examples 5; overview 404 member paths).
…-check-doc-coverage chore(document-api): retire check-doc-coverage (SD-3261)
Contributor
|
📖 Docs preview: https://superdoc-nick-v-1-35-0-main-stable.mintlify.app |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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.
No description provided.