Skip to content

Commit a9b2d7a

Browse files
committed
Merge branch 'main' into docs/examples-solidjs
2 parents e49f0b5 + df091a7 commit a9b2d7a

71 files changed

Lines changed: 2271 additions & 775 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/package-impact-map.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Source of truth for which repo paths should trigger CI and release workflows for
99
- **CI gates compatibility.** A change to SuperDoc core should run the CI of every dependent package — that's how breakage in `@superdoc-dev/react` or `@superdoc-dev/sdk` gets caught before it ships. CI paths follow *compatibility* impact.
1010
- **Release gates artifact changes.** A package should only publish a new version when its own published artifact actually changes. Release paths follow *artifact* impact.
1111

12-
These two are not the same. `template-builder` and `esign` externalize `superdoc` in their builds and declare it as a `peerDependency`, so a core change doesn't change their tarballs → CI broad, release narrow. CLI bundles core into platform binaries, so a core change does change the CLI tarball → both broad.
12+
These two are not the same. `template-builder` and `esign` externalize `superdoc` in their builds and declare it as both a dependency and peer dependency, so a core change inside the declared range doesn't change their tarballs → CI broad, release narrow. CLI bundles core into platform binaries, so a core change does change the CLI tarball → both broad.
1313

1414
## Surfaces
1515

@@ -49,7 +49,7 @@ These two are not the same. `template-builder` and `esign` externalize `superdoc
4949

5050
## Why each classification
5151

52-
- **`template-builder` and `esign`** externalize `superdoc` in their Vite build (`rollupOptions.external`) and declare it as a `peerDependency`. A SuperDoc core change does not change the wrapper's published bundle — consumers receive the new core through their own `npm install`. Release-on-core is pure version noise; CI-on-core remains necessary to catch breaking API changes.
52+
- **`template-builder` and `esign`** externalize `superdoc` in their Vite build (`rollupOptions.external`) and declare it in **both** `dependencies` and `peerDependencies`. The `dependencies` entry preserves auto-install for customers who use the wrapper as their SuperDoc entrypoint; the `peerDependencies` entry signals the singleton contract for apps that also install SuperDoc directly. A SuperDoc core change inside the declared range does not change the wrapper's published bundle or manifest, so release-on-core is pure version noise; CI-on-core remains necessary to catch breaking API changes.
5353
- **`react`** externalizes `superdoc` in its Vite build the same way, and declares `superdoc` in **both** `dependencies` and `peerDependencies`. The `dependencies` entry preserves auto-install for every consumer (zero-break regardless of package manager); the `peerDependencies` entry signals the singleton contract and aligns the manifest with template-builder/esign. Because the `dependencies` entry still pins via lockfiles, existing consumers only pick up a new core version when react republishes, so release-on-core stays correct *today*. The unlock for release-narrow is to remove `superdoc` from `dependencies` entirely — that is a breaking change and tracked as a separate decision.
5454
- **CLI / SDK** bundle engine behavior into platform-specific native binaries (see `apps/cli/.releaserc.cjs` and `packages/sdk/.releaserc.cjs` — both use `patch-commit-filter.cjs` to expand release analysis into core paths). The published artifact genuinely changes when core changes.
5555
- **MCP** depends on SDK via `workspace:*` and imports engine/session code directly. Its current release trigger (`apps/mcp/**` only) causes it to lag SDK releases. Expand to match SDK's release paths.
@@ -61,6 +61,6 @@ These two are not the same. `template-builder` and `esign` externalize `superdoc
6161
## Notes
6262

6363
- `packages/ai/**` has been removed from all release and CI triggers. `@superdoc-dev/ai` is being deprecated; npm-side deprecation is a separate operational step.
64-
- When SuperDoc core ships a breaking API change, `template-builder` and `esign` must be manually updated and released. Their `peerDependencies` version bump is the signal; semantic-release won't auto-trigger on upstream changes for them.
65-
- `@superdoc-dev/react` declares `superdoc` in both `dependencies` and `peerDependencies` to preserve zero-break install semantics while still signaling the singleton contract. Removing `superdoc` from `dependencies` is the unlock for release-narrow and is tracked as a separate decision.
64+
- When SuperDoc core ships a breaking API change, `template-builder` and `esign` must be manually updated and released. Their dependency and peer-dependency floor bump is the signal; semantic-release won't auto-trigger on upstream changes for them.
65+
- `@superdoc-dev/react`, `@superdoc-dev/template-builder`, and `@superdoc-dev/esign` declare `superdoc` in both `dependencies` and `peerDependencies` to preserve automatic install semantics while still signaling the singleton contract. Removing `superdoc` from `dependencies` is the unlock for release-narrow and is tracked as a separate decision.
6666
- When editing a release or CI workflow, its `paths:` filter must match the corresponding row in this map. Workflow-lint rules should enforce this.

.github/workflows/promote-stable.yml

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ jobs:
3131
with:
3232
app-id: ${{ secrets.APP_ID }}
3333
private-key: ${{ secrets.APP_PRIVATE_KEY }}
34-
permission-contents: write
35-
permission-pull-requests: write
36-
permission-workflows: write
3734

3835
- uses: actions/checkout@v6
3936
with:
@@ -71,19 +68,60 @@ jobs:
7168
if git merge --no-ff --no-edit "origin/${SOURCE_BRANCH}"; then
7269
MERGE_STATUS="clean"
7370
else
74-
# Auto-resolve release artifact conflicts: keep stable's version.
71+
normalize_json_without_keys() {
72+
python3 -c 'import json, sys; data = json.load(sys.stdin); [data.pop(key, None) for key in sys.argv[1:]]; sys.stdout.write(json.dumps(data, sort_keys=True, separators=(",", ":")))' "$@"
73+
}
74+
75+
release_artifact_only_conflict() {
76+
local f="$1"
77+
local tmpdir
78+
local status
79+
tmpdir="$(mktemp -d)"
80+
81+
case "$f" in
82+
package.json|*/package.json)
83+
git show ":2:${f}" | normalize_json_without_keys version > "${tmpdir}/ours" || { rm -rf "${tmpdir}"; return 1; }
84+
git show ":3:${f}" | normalize_json_without_keys version > "${tmpdir}/theirs" || { rm -rf "${tmpdir}"; return 1; }
85+
;;
86+
pyproject.toml|*/pyproject.toml)
87+
git show ":2:${f}" | sed -E '/^[[:space:]]*version[[:space:]]*=/d' > "${tmpdir}/ours" || { rm -rf "${tmpdir}"; return 1; }
88+
git show ":3:${f}" | sed -E '/^[[:space:]]*version[[:space:]]*=/d' > "${tmpdir}/theirs" || { rm -rf "${tmpdir}"; return 1; }
89+
;;
90+
version.json|*/version.json)
91+
git show ":2:${f}" | normalize_json_without_keys version sdkVersion > "${tmpdir}/ours" || { rm -rf "${tmpdir}"; return 1; }
92+
git show ":3:${f}" | normalize_json_without_keys version sdkVersion > "${tmpdir}/theirs" || { rm -rf "${tmpdir}"; return 1; }
93+
;;
94+
*)
95+
rm -rf "${tmpdir}"
96+
return 1
97+
;;
98+
esac
99+
100+
cmp -s "${tmpdir}/ours" "${tmpdir}/theirs"
101+
status=$?
102+
rm -rf "${tmpdir}"
103+
return "${status}"
104+
}
105+
106+
# Auto-resolve release artifact conflicts only when the conflict is
107+
# version-only: keep stable's version, but never drop dependency,
108+
# script, export, or package metadata changes from main.
75109
# npm/PyPI already have stable's published version; downgrading to
76110
# main's track would break the next stable release. Mirrors the
77111
# auto-resolve in sync-patches.yml, biased the other direction.
78-
git diff --name-only --diff-filter=U | while read -r f; do
112+
while read -r f; do
79113
case "$f" in
80114
package.json|*/package.json|pyproject.toml|*/pyproject.toml|version.json|*/version.json)
81-
echo " Auto-resolving $f (keeping stable's version)"
82-
git checkout --ours "$f"
83-
git add "$f"
115+
if release_artifact_only_conflict "$f"; then
116+
echo " Auto-resolving $f (version-only; keeping stable's version)"
117+
git checkout --ours "$f"
118+
git add "$f"
119+
else
120+
echo " Leaving $f unresolved (contains non-version changes)"
121+
fi
84122
;;
85123
esac
86-
done
124+
done < <(git diff --name-only --diff-filter=U)
87125
88126
if [ -z "$(git diff --name-only --diff-filter=U)" ]; then
89127
MERGE_STATUS="auto_resolved"
@@ -141,7 +179,7 @@ jobs:
141179
142180
- creates \`${BRANCH_NAME}\` from \`${BASE_BRANCH}\`
143181
- merges \`${SOURCE_BRANCH}\` into the candidate branch
144-
- release artifact conflicts (package.json, pyproject.toml, version.json) auto-resolved to keep stable's published version
182+
- version-only release artifact conflicts (package.json, pyproject.toml, version.json) auto-resolved to keep stable's published version
145183
146184
---
147185
_Auto-created by promote-stable workflow._

.github/workflows/release-cli.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,14 @@ permissions:
2727
packages: write
2828

2929
concurrency:
30+
# Release runs never cancel an in-progress release (each merge is a release-worthy
31+
# state). queue: max keeps GitHub from dropping older pending stable releases when
32+
# a stable push touches multiple wrapper packages in the shared release-stable group;
33+
# default queue: single only allows one pending. queue: max requires
34+
# cancel-in-progress: false (cannot be combined with true).
3035
group: ${{ github.ref_name == 'stable' && 'release-stable' || format('{0}-{1}', github.workflow, github.ref) }}
31-
cancel-in-progress: ${{ github.ref_name != 'stable' }}
36+
cancel-in-progress: false
37+
queue: max
3238

3339
jobs:
3440
release:
@@ -46,8 +52,11 @@ jobs:
4652
fetch-depth: 0
4753
token: ${{ steps.generate_token.outputs.token }}
4854

49-
- name: Refresh stable branch head
50-
if: github.ref_name == 'stable'
55+
- name: Refresh branch head
56+
# Queued release runs may start against a stale checkout (queue: max
57+
# plus cancel-in-progress: false). Refresh to the current branch head
58+
# so @semantic-release/git pushes fast-forward; semantic-release no-ops
59+
# if no new commits were added since the previous queued run released.
5160
run: |
5261
git fetch origin "${{ github.ref_name }}" --tags
5362
git checkout -B "${{ github.ref_name }}" "origin/${{ github.ref_name }}"

.github/workflows/release-create.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,14 @@ permissions:
1717
packages: write
1818

1919
concurrency:
20+
# Release runs never cancel an in-progress release (each merge is a release-worthy
21+
# state). queue: max keeps GitHub from dropping older pending stable releases when
22+
# a stable push touches multiple wrapper packages in the shared release-stable group;
23+
# default queue: single only allows one pending. queue: max requires
24+
# cancel-in-progress: false (cannot be combined with true).
2025
group: ${{ github.ref_name == 'stable' && 'release-stable' || format('{0}-{1}', github.workflow, github.ref) }}
21-
cancel-in-progress: ${{ github.ref_name != 'stable' }}
26+
cancel-in-progress: false
27+
queue: max
2228

2329
jobs:
2430
release:
@@ -36,8 +42,11 @@ jobs:
3642
fetch-depth: 0
3743
token: ${{ steps.generate_token.outputs.token }}
3844

39-
- name: Refresh stable branch head
40-
if: github.ref_name == 'stable'
45+
- name: Refresh branch head
46+
# Queued release runs may start against a stale checkout (queue: max
47+
# plus cancel-in-progress: false). Refresh to the current branch head
48+
# so @semantic-release/git pushes fast-forward; semantic-release no-ops
49+
# if no new commits were added since the previous queued run released.
4150
run: |
4251
git fetch origin "${{ github.ref_name }}" --tags
4352
git checkout -B "${{ github.ref_name }}" "origin/${{ github.ref_name }}"

.github/workflows/release-esign.yml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@ permissions:
1919
concurrency:
2020
# Stable releases share the `release-stable` group so @semantic-release/git
2121
# pushes to `stable` serialize across workflows; per-workflow groups would
22-
# let releases race on `git push origin stable`.
22+
# let releases race on `git push origin stable`. queue: max keeps GitHub
23+
# from dropping older pending stable releases when a stable push touches
24+
# multiple wrapper packages; default queue: single only allows one pending.
25+
# queue: max requires cancel-in-progress: false (cannot be combined with true).
2326
group: ${{ github.ref_name == 'stable' && 'release-stable' || format('{0}-{1}', github.workflow, github.ref) }}
24-
cancel-in-progress: ${{ github.ref_name != 'stable' }}
27+
cancel-in-progress: false
28+
queue: max
2529

2630
jobs:
2731
release:
@@ -39,8 +43,11 @@ jobs:
3943
fetch-depth: 0
4044
token: ${{ steps.generate_token.outputs.token }}
4145

42-
- name: Refresh stable branch head
43-
if: github.ref_name == 'stable'
46+
- name: Refresh branch head
47+
# Queued release runs may start against a stale checkout (queue: max
48+
# plus cancel-in-progress: false). Refresh to the current branch head
49+
# so @semantic-release/git pushes fast-forward; semantic-release no-ops
50+
# if no new commits were added since the previous queued run released.
4451
run: |
4552
git fetch origin "${{ github.ref_name }}" --tags
4653
git checkout -B "${{ github.ref_name }}" "origin/${{ github.ref_name }}"

.github/workflows/release-mcp.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,14 @@ permissions:
2929
packages: write
3030

3131
concurrency:
32+
# Release runs never cancel an in-progress release (each merge is a release-worthy
33+
# state). queue: max keeps GitHub from dropping older pending stable releases when
34+
# a stable push touches multiple wrapper packages in the shared release-stable group;
35+
# default queue: single only allows one pending. queue: max requires
36+
# cancel-in-progress: false (cannot be combined with true).
3237
group: ${{ github.ref_name == 'stable' && 'release-stable' || format('{0}-{1}', github.workflow, github.ref) }}
33-
cancel-in-progress: ${{ github.ref_name != 'stable' }}
38+
cancel-in-progress: false
39+
queue: max
3440

3541
jobs:
3642
release:
@@ -48,8 +54,11 @@ jobs:
4854
fetch-depth: 0
4955
token: ${{ steps.generate_token.outputs.token }}
5056

51-
- name: Refresh stable branch head
52-
if: github.ref_name == 'stable'
57+
- name: Refresh branch head
58+
# Queued release runs may start against a stale checkout (queue: max
59+
# plus cancel-in-progress: false). Refresh to the current branch head
60+
# so @semantic-release/git pushes fast-forward; semantic-release no-ops
61+
# if no new commits were added since the previous queued run released.
5362
run: |
5463
git fetch origin "${{ github.ref_name }}" --tags
5564
git checkout -B "${{ github.ref_name }}" "origin/${{ github.ref_name }}"

.github/workflows/release-react.yml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,18 @@ permissions:
3030
concurrency:
3131
# Stable releases share the `release-stable` group so @semantic-release/git
3232
# pushes to `stable` serialize across workflows; per-workflow groups would
33-
# let releases race on `git push origin stable`.
33+
# let releases race on `git push origin stable`. queue: max keeps GitHub
34+
# from dropping older pending stable releases when a stable push touches
35+
# multiple wrapper packages; default queue: single only allows one pending.
36+
# queue: max requires cancel-in-progress: false (cannot be combined with true).
3437
group: ${{ github.ref_name == 'stable' && 'release-stable' || format('{0}-{1}', github.workflow, github.ref) }}
35-
cancel-in-progress: ${{ github.ref_name != 'stable' }}
38+
cancel-in-progress: false
39+
queue: max
3640

3741
jobs:
3842
release:
43+
# Stable publishes must go through release-stable.yml.
44+
if: ${{ github.event_name != 'workflow_dispatch' || github.ref_name != 'stable' }}
3945
runs-on: ubuntu-24.04
4046
steps:
4147
- name: Generate token
@@ -50,8 +56,11 @@ jobs:
5056
fetch-depth: 0
5157
token: ${{ steps.generate_token.outputs.token }}
5258

53-
- name: Refresh stable branch head
54-
if: github.ref_name == 'stable'
59+
- name: Refresh branch head
60+
# Queued release runs may start against a stale checkout (queue: max
61+
# plus cancel-in-progress: false). Refresh to the current branch head
62+
# so @semantic-release/git pushes fast-forward; semantic-release no-ops
63+
# if no new commits were added since the previous queued run released.
5564
run: |
5665
git fetch origin "${{ github.ref_name }}" --tags
5766
git checkout -B "${{ github.ref_name }}" "origin/${{ github.ref_name }}"

.github/workflows/release-sdk.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,14 @@ permissions:
4444
id-token: write # PyPI trusted publishing (OIDC)
4545

4646
concurrency:
47+
# Release runs never cancel an in-progress release (each merge is a release-worthy
48+
# state). queue: max keeps GitHub from dropping older pending stable releases when
49+
# a stable push touches multiple wrapper packages in the shared release-stable group;
50+
# default queue: single only allows one pending. queue: max requires
51+
# cancel-in-progress: false (cannot be combined with true).
4752
group: ${{ github.ref_name == 'stable' && 'release-stable' || format('{0}-{1}', github.workflow, github.ref) }}
48-
cancel-in-progress: ${{ github.ref_name != 'stable' }}
53+
cancel-in-progress: false
54+
queue: max
4955

5056
jobs:
5157
# -------------------------------------------------------------------
@@ -71,8 +77,11 @@ jobs:
7177
fetch-depth: 0
7278
token: ${{ steps.generate_token.outputs.token }}
7379

74-
- name: Refresh stable branch head
75-
if: github.ref_name == 'stable'
80+
- name: Refresh branch head
81+
# Queued release runs may start against a stale checkout (queue: max
82+
# plus cancel-in-progress: false). Refresh to the current branch head
83+
# so @semantic-release/git pushes fast-forward; semantic-release no-ops
84+
# if no new commits were added since the previous queued run released.
7685
run: |
7786
git fetch origin "${{ github.ref_name }}" --tags
7887
git checkout -B "${{ github.ref_name }}" "origin/${{ github.ref_name }}"

.github/workflows/release-stable.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@ concurrency:
2929
# `git push origin stable`, leaving npm/PyPI tarballs published without
3030
# a corresponding tag/commit pushed.
3131
# [skip ci] writeback runs use a per-run group so they cannot evict a real
32-
# pending stable push while the bundle is active.
32+
# pending stable push while the bundle is active. queue: max keeps GitHub
33+
# from dropping older pending stable releases when a stable push touches
34+
# multiple wrapper packages; default queue: single only allows one pending.
3335
group: ${{ github.event_name == 'push' && contains(github.event.head_commit.message, '[skip ci]') && format('release-stable-skip-{0}', github.run_id) || 'release-stable' }}
3436
cancel-in-progress: false
37+
queue: max
3538

3639
jobs:
3740
release:

0 commit comments

Comments
 (0)