Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
7a75252
Add opt-in hybrid API documentation POC
IEvangelist Oct 11, 2026
755965e
Preserve hybrid Markdown paths and verify local renderer wiring
IEvangelist Oct 11, 2026
63fdfee
Verify emitted hybrid artifacts in focused opt-in CI
IEvangelist Oct 11, 2026
1657196
Validate hybrid redirects without requiring static redirect files
IEvangelist Oct 11, 2026
4063162
Support platform-matched POC artifacts and bounded runtime images
IEvangelist Oct 11, 2026
8a80476
Preserve slash-form image requests and clarify POC build command
IEvangelist Oct 11, 2026
32e2034
Serve the selected hybrid client without placeholder asset shadowing
IEvangelist Oct 11, 2026
d0476d4
Wait for client navigation before validating lazy API images
IEvangelist Oct 11, 2026
502c941
Use native Astro caching with renderer readiness and failover
IEvangelist Oct 13, 2026
9209f05
Package hybrid renderers as private App Service sidecars
IEvangelist Oct 13, 2026
861d8e2
Require renderer readiness during App Service warmup
IEvangelist Oct 13, 2026
55f9ba5
Close the hybrid renderer runtime dependency set
IEvangelist Oct 13, 2026
45d688f
Allow isolated local and Azure hybrid artifact selection
IEvangelist Oct 13, 2026
ecbdc0c
Compress hybrid static and forwarded responses
IEvangelist Oct 13, 2026
5f6063c
Assert compression savings only for the large body
IEvangelist Oct 13, 2026
8b974b2
Serve API search indexes as separate JSON instead of inline HTML
IEvangelist Oct 13, 2026
b6656eb
Run the StaticHost e2e spec only through the hybrid config
IEvangelist Oct 13, 2026
25d1b7f
Update hybrid acceptance for the external API search index
IEvangelist Oct 13, 2026
d4417e8
Truncate long member signatures instead of widening the page
IEvangelist Oct 14, 2026
8e10b3c
Harden the hybrid API renderer path
IEvangelist Oct 14, 2026
b9cb354
Fix the acceptance validator check to ignore the direct worker hit
IEvangelist Oct 14, 2026
1ffec64
Serve prerendered API landings as static files
IEvangelist Oct 14, 2026
20469b6
Serve client files without a MIME mapping in hybrid mode
IEvangelist Oct 14, 2026
3a73428
Leave the production plan's instance count and scaling alone
IEvangelist Oct 14, 2026
20c4fe9
Run the hybrid API POC checks on this PR
IEvangelist Oct 14, 2026
a523816
Give each sidecar its own port through an app setting
IEvangelist Oct 14, 2026
1883e42
Re-run CI for the sidecar port fix
IEvangelist Oct 14, 2026
8087036
Merge release/17.0 into the hybrid API rendering branch
IEvangelist Oct 15, 2026
2f75c44
Regenerate the lockfile against the public npm registry
IEvangelist Oct 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ concurrency:

permissions:
contents: read
actions: read
security-events: write

jobs:
Expand Down Expand Up @@ -103,6 +104,11 @@ jobs:
if: ${{ needs.changes.outputs.apphost == 'true' }}
uses: ./.github/workflows/apphost-build.yml

hybrid-api-poc:
needs: changes
if: ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'hybrid-api-poc') }}
uses: ./.github/workflows/hybrid-api-docs-poc.yml

release-sync-tests:
runs-on: ubuntu-latest
steps:
Expand All @@ -115,7 +121,7 @@ jobs:
bash .github/scripts/test-merge-main-into-release.sh

ci-gate:
needs: [changes, frontend-build, apphost-build, release-sync-tests]
needs: [changes, frontend-build, apphost-build, release-sync-tests, hybrid-api-poc]
if: ${{ always() && !cancelled() }}
runs-on: ubuntu-latest
steps:
Expand All @@ -128,13 +134,19 @@ jobs:
FRONTEND_RESULT: ${{ needs['frontend-build'].result }}
APPHOST_RESULT: ${{ needs['apphost-build'].result }}
RELEASE_SYNC_RESULT: ${{ needs['release-sync-tests'].result }}
HYBRID_REQUESTED: ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'hybrid-api-poc') }}
HYBRID_RESULT: ${{ needs['hybrid-api-poc'].result }}
run: |
echo "changes result: $CHANGES_RESULT"
echo "frontend changed: $FRONTEND_CHANGED"
echo "frontend-build result: $FRONTEND_RESULT"
echo "apphost changed: $APPHOST_CHANGED"
echo "apphost-build result: $APPHOST_RESULT"
echo "release-sync-tests result: $RELEASE_SYNC_RESULT"
if [[ "$HYBRID_REQUESTED" == "true" && "$HYBRID_RESULT" != "success" ]]; then
echo "The opted-in hybrid API POC checks must succeed."
exit 1
fi

if [[ "$RELEASE_SYNC_RESULT" != "success" ]]; then
echo "The release sync tests must succeed."
Expand Down
45 changes: 44 additions & 1 deletion .github/workflows/frontend-build.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
name: Frontend Build

on:
workflow_dispatch:
inputs:
node_version:
description: Node.js version
default: "24.x"
type: string
hybrid_api_poc:
description: Run the opt-in static/hybrid POC comparison
default: false
type: boolean
hybrid_artifact_run_id:
description: Recheck hybrid container packaging against an existing Linux artifact
default: ""
type: string
workflow_call:
inputs:
node_version:
Expand All @@ -18,6 +32,16 @@ on:
required: false
default: false
type: boolean
hybrid_api_poc:
description: Also verify the opt-in hybrid API documentation POC
required: false
default: false
type: boolean
hybrid_artifact_run_id:
description: Recheck hybrid container packaging against an existing Linux artifact
required: false
default: ""
type: string
secrets:
ASPIRE_BOT_APP_ID:
required: false
Expand All @@ -26,9 +50,17 @@ on:

permissions:
contents: read
actions: read

jobs:
hybrid-api-poc:
if: ${{ inputs.hybrid_api_poc }}
uses: ./.github/workflows/hybrid-api-docs-poc.yml
with:
artifact_run_id: ${{ inputs.hybrid_artifact_run_id }}

build:
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.hybrid_api_poc }}
name: Frontend Build
runs-on: ubuntu-latest
defaults:
Expand Down Expand Up @@ -247,6 +279,7 @@ jobs:
ls -la dist

validation:
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.hybrid_api_poc }}
name: Frontend validation
runs-on: ubuntu-latest
defaults:
Expand Down Expand Up @@ -422,7 +455,7 @@ jobs:
frontend-gate:
name: Frontend gate
if: ${{ always() }}
needs: [build, validation, e2e, report]
needs: [build, validation, e2e, report, hybrid-api-poc]
runs-on: ubuntu-latest
steps:
- name: Require all frontend checks
Expand All @@ -431,7 +464,17 @@ jobs:
VALIDATION: ${{ needs.validation.result }}
E2E: ${{ needs.e2e.result }}
REPORT: ${{ needs.report.result }}
HYBRID_REQUESTED: ${{ inputs.hybrid_api_poc }}
HYBRID_RESULT: ${{ needs['hybrid-api-poc'].result }}
POC_ONLY: ${{ github.event_name == 'workflow_dispatch' && inputs.hybrid_api_poc }}
run: |
if [[ "$HYBRID_REQUESTED" == "true" && "$HYBRID_RESULT" != "success" ]]; then
echo "::error::The opted-in hybrid POC must succeed."
exit 1
fi
if [[ "$POC_ONLY" == "true" ]]; then
exit 0
fi
for result in "$BUILD" "$VALIDATION" "$E2E" "$REPORT"; do
if [[ "$result" != "success" ]]; then
echo "::error::Every frontend job must succeed (build=$BUILD validation=$VALIDATION e2e=$E2E report=$REPORT)."
Expand Down
171 changes: 171 additions & 0 deletions .github/workflows/hybrid-api-docs-poc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
name: Hybrid API docs POC

on:
workflow_call:
inputs:
artifact_run_id:
description: Recheck container packaging using an existing Linux hybrid artifact
required: false
default: ''
type: string
workflow_dispatch:
inputs:
artifact_run_id:
description: Recheck container packaging using an existing Linux hybrid artifact
required: false
default: ''
type: string

permissions:
contents: read
actions: read

jobs:
windows-artifact:
if: ${{ inputs.artifact_run_id == '' }}
runs-on: windows-latest
defaults:
run:
working-directory: src/frontend
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24.x
cache: pnpm
cache-dependency-path: src/frontend/pnpm-lock.yaml
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
global-json-file: global.json
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Build Windows hybrid artifact
env:
ASTRO_TELEMETRY_DISABLED: '1'
NODE_OPTIONS: --max-old-space-size=8192
ASPIRE_HYBRID_API_DOCS: '1'
run: pnpm build:production
- name: Verify Windows StaticHost contracts
env:
ASPIRE_HYBRID_API_DOCS: '1'
run: dotnet test ../../tests/StaticHost.Tests/StaticHost.Tests.csproj --filter 'FullyQualifiedName~HybridApiDocs' --nologo
- name: Upload Windows POC artifact
if: success()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: hybrid-api-docs-poc-windows
path: src/frontend/dist-hybrid
include-hidden-files: true
if-no-files-found: error
retention-days: 7

verify:
runs-on: ubuntu-latest
services:
redis:
image: redis:8.2-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 3s
--health-retries 10
defaults:
run:
working-directory: src/frontend
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24.x
cache: pnpm
cache-dependency-path: src/frontend/pnpm-lock.yaml
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
global-json-file: global.json
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Download existing Linux hybrid artifact for packaging verification
if: ${{ inputs.artifact_run_id != '' }}
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: hybrid-api-docs-poc
path: src/frontend/dist-hybrid
github-token: ${{ github.token }}
run-id: ${{ inputs.artifact_run_id }}
- name: Verify POC unit contracts
env:
ASTRO_TELEMETRY_DISABLED: '1'
run: |
pnpm exec astro sync
pnpm exec eslint . --max-warnings 0
pnpm exec vitest run --config vitest.config.ts tests/unit/hybrid-api-docs.vitest.test.ts tests/unit/hybrid-native-cache.vitest.test.ts tests/unit/api-markdown.vitest.test.ts tests/unit/ts-api-route-catalog.vitest.test.ts tests/unit/build-performance.vitest.test.ts
dotnet test ../../tests/StaticHost.Tests/StaticHost.Tests.csproj --filter 'FullyQualifiedName~HybridApiDocs' --nologo
dotnet test ../../tests/Aspire.Dev.AppHost.Tests/Aspire.Dev.AppHost.Tests.csproj --filter 'FullyQualifiedName~HybridApiDocs' --nologo
- name: Build static baseline
if: ${{ inputs.artifact_run_id == '' }}
env:
ASTRO_TELEMETRY_DISABLED: '1'
NODE_OPTIONS: --max-old-space-size=8192
BUILD_TIMING: '1'
BUILD_TIMING_OUT: ${{ runner.temp }}/hybrid-poc/static-timing.jsonl
run: |
mkdir -p "$RUNNER_TEMP/hybrid-poc"
/usr/bin/time -v -o "$RUNNER_TEMP/hybrid-poc/static-resources.txt" pnpm build:production
- name: Build opted-in hybrid artifact
if: ${{ inputs.artifact_run_id == '' }}
env:
ASTRO_TELEMETRY_DISABLED: '1'
NODE_OPTIONS: --max-old-space-size=8192
ASPIRE_HYBRID_API_DOCS: '1'
BUILD_TIMING: '1'
BUILD_TIMING_OUT: ${{ runner.temp }}/hybrid-poc/hybrid-timing.jsonl
run: /usr/bin/time -v -o "$RUNNER_TEMP/hybrid-poc/hybrid-resources.txt" pnpm build:production
- name: Verify output and non-API parity
if: ${{ inputs.artifact_run_id == '' }}
run: |
node scripts/verify-hybrid-output.mjs
rm -r dist
- name: Build independent StaticHost and Astro images
env:
ASPIRE_HYBRID_API_DOCS: '1'
run: |
dotnet publish ../statichost/StaticHost/StaticHost.csproj -c Release --os linux --arch x64 \
-t:PublishContainer -p:ContainerRepository=hybrid-poc-host -p:ContainerImageTag=test --nologo
docker build -f Dockerfile.hybrid -t hybrid-poc-renderer:test .
- name: Verify rendering, caching and worker outages
env:
ConnectionStrings__cache: localhost:6379,abortConnect=false
HYBRID_TEST_BROWSER: '1'
HYBRID_TEST_CONTAINERS: '1'
run: node scripts/test-hybrid-host.mjs
- name: Upload private POC artifact
if: ${{ always() && inputs.artifact_run_id == '' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: hybrid-api-docs-poc
path: src/frontend/dist-hybrid
include-hidden-files: true
if-no-files-found: warn
retention-days: 7
- name: Upload POC measurements
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: hybrid-api-docs-results
path: |
src/frontend/hybrid-output-results.json
src/frontend/hybrid-host-results.json
src/frontend/hybrid-host-processes.log
${{ runner.temp }}/hybrid-poc
if-no-files-found: warn
retention-days: 7
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

# build output
dist/
dist-hybrid/
hybrid-output-results.json
hybrid-host-results.json
playwright-report/
blob-report/
test-results/
Expand Down
Loading
Loading