Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ updates:
semver-major-days: 30
semver-minor-days: 7
semver-patch-days: 3
ignore:
- dependency-name: '*'
update-types:
- version-update:semver-major
groups:
production-dependencies:
dependency-type: production
Expand Down
101 changes: 0 additions & 101 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ on:
- synchronize
- reopened
- ready_for_review
merge_group:
types:
- checks_requested
workflow_dispatch:

permissions:
Expand All @@ -25,7 +22,6 @@ concurrency:
group: >-
client-checks-${{
github.event.pull_request.number ||
github.event.merge_group.head_sha ||
github.ref
}}
cancel-in-progress: true
Expand Down Expand Up @@ -91,60 +87,6 @@ jobs:
echo "- Runtime contract: \`$CONTRACT_REVISION\`"
} >> "$GITHUB_STEP_SUMMARY"

database-contract:
name: Database contract
needs: core-release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0

- name: Install the pinned pnpm release
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 11.11.0

- name: Set up Node
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version-file: package.json
cache: pnpm
registry-url: https://npm.pkg.github.com
scope: '@inkcre'

- name: Install the frozen workspace
run: pnpm install --frozen-lockfile
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Authenticate to GHCR
uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Generate types from the selected raw schema
run: pnpm contract:sync -- --image "${{ needs.core-release.outputs.image }}"

- name: Upload the generated database contract
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: generated-database-contract-${{ github.sha }}
path: |
packages/core/src/database/database.generated.ts
packages/core/src/database/runtime-contract.generated.json
if-no-files-found: error
retention-days: 7

- name: Reject a stale checked-in database contract
run: >-
git diff --exit-code --
packages/core/src/database/database.generated.ts
packages/core/src/database/runtime-contract.generated.json

workspace:
name: Workspace contract
runs-on: ubuntu-latest
Expand Down Expand Up @@ -182,39 +124,6 @@ jobs:
--core-package packages/core/package.json
--artifact-directory extensions/twitter/dist/client-web

toolchain-shadow:
name: Type-aware and TypeScript 7 shadow
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Install the pinned pnpm release
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 11.11.0

- name: Set up Node
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version-file: package.json
cache: pnpm
registry-url: https://npm.pkg.github.com
scope: '@inkcre'

- name: Install the frozen workspace
run: pnpm install --frozen-lockfile
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Run type-aware Oxlint
continue-on-error: true
run: pnpm lint:type-aware

- name: Run the native TypeScript 7 preview
continue-on-error: true
run: pnpm type-check:ts7

peer-database:
name: client-web E2E
needs: core-release
Expand Down Expand Up @@ -301,16 +210,6 @@ jobs:
- name: Build the Firefox extension
run: pnpm --filter @inkcre/client-webext build:firefox

- name: Retain the exact browser-extension artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: client-webext-builds
path: |
apps/client-webext/.output/chrome-mv3
apps/client-webext/.output/firefox-mv2
if-no-files-found: error
retention-days: 7

- name: Upload browser evidence on failure
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand Down
77 changes: 1 addition & 76 deletions .github/workflows/extension-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,79 +107,4 @@ jobs:
INKCRE_EXTENSION_REGISTRY_TOKEN: ${{ secrets.INKCRE_EXTENSION_REGISTRY_TOKEN }}
SOURCE_REPOSITORY: https://github.com/${{ github.repository }}
SOURCE_REVISION: ${{ github.sha }}
run: |
test -n "$INKCRE_EXTENSION_REGISTRY_TOKEN"
mkdir -p .extension-delivery

for package_path in extensions/*/package.json; do
descriptor="$(node --input-type=module --eval '
import { readFile } from "node:fs/promises"
import path from "node:path"
const packagePath = process.argv[1]
const manifest = JSON.parse(await readFile(packagePath, "utf8"))
if (!manifest.inkcre?.module_federation) process.exit(0)
process.stdout.write([path.basename(path.dirname(packagePath)), manifest.inkcre.name, manifest.version].join("\t"))
' "$package_path")"
if [[ -z "$descriptor" ]]; then
continue
fi
IFS=$'\t' read -r extension_directory extension_path release_path <<< "$descriptor"

delivery_directory=".extension-delivery/$extension_directory"
artifact_directory="extensions/$extension_directory/dist/client-web"
mkdir -p "$delivery_directory"
public_descriptor="$delivery_directory/public-release.json"
status="$(curl --silent --show-error --output "$public_descriptor" --write-out '%{http_code}' \
"${INKCRE_EXTENSION_REGISTRY_URL%/}/v1/extensions/${extension_path}/releases/${release_path}")"
if [[ "$status" == '200' ]]; then
has_native_association="$(node --input-type=module --eval 'import { readFile } from "node:fs/promises"; const release = JSON.parse(await readFile(process.argv[1], "utf8")); process.stdout.write(String(release.module_federation !== null))' "$public_descriptor")"
elif [[ "$status" == '404' ]]; then
has_native_association=false
else
echo "Cannot determine $extension_path $release_path Registry state: HTTP $status." >&2
exit 1
fi
if [[ "$has_native_association" == 'true' ]]; then
echo "$extension_path $release_path is already published." >> "$GITHUB_STEP_SUMMARY"
continue
fi

node scripts/verify-native-extension-distribution.mjs prepare-body \
--package "$package_path" \
--core-package packages/core/package.json \
--artifact-directory "$artifact_directory" \
--source-repository "$SOURCE_REPOSITORY" \
--source-revision "$SOURCE_REVISION" \
--build-id "client-web-extension-release-${GITHUB_RUN_ID}" \
--output "$delivery_directory/prepare.json"
(
cd "$artifact_directory"
zip -q -r "$GITHUB_WORKSPACE/$delivery_directory/snapshot.zip" .
)

curl --fail-with-body --silent --show-error \
--request POST \
--header "Authorization: Bearer $INKCRE_EXTENSION_REGISTRY_TOKEN" \
--header 'Content-Type: application/json' \
--data-binary "@$delivery_directory/prepare.json" \
"${INKCRE_EXTENSION_REGISTRY_URL%/}/v1/extensions/${extension_path}/releases" \
> "$delivery_directory/prepared-release.json"
curl --fail-with-body --silent --show-error \
--request POST \
--header "Authorization: Bearer $INKCRE_EXTENSION_REGISTRY_TOKEN" \
--form "content=@$delivery_directory/snapshot.zip;type=application/zip" \
"${INKCRE_EXTENSION_REGISTRY_URL%/}/v1/extensions/${extension_path}/releases/${release_path}/module-federation" \
> "$delivery_directory/uploaded-release.json"
curl --fail-with-body --silent --show-error \
--request POST \
--header "Authorization: Bearer $INKCRE_EXTENSION_REGISTRY_TOKEN" \
"${INKCRE_EXTENSION_REGISTRY_URL%/}/v1/extensions/${extension_path}/releases/${release_path}/publish" \
> "$delivery_directory/published-release.json"
node scripts/verify-native-extension-distribution.mjs verify-public \
--registry-url "$INKCRE_EXTENSION_REGISTRY_URL" \
--package "$package_path" \
--core-package packages/core/package.json \
--artifact-directory "$artifact_directory" \
--output "$delivery_directory/verification.json"
echo "$extension_path $release_path published and verified." >> "$GITHUB_STEP_SUMMARY"
done
run: bash scripts/publish-native-extensions.sh
15 changes: 0 additions & 15 deletions .github/workflows/pages-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,6 @@ jobs:
working-directory: release
run: pnpm build

- name: Reverify main before Pages delivery
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
SOURCE_SHA: ${{ needs.identity.outputs.source_sha }}
with:
script: |
const currentMain = await github.rest.git.getRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: 'heads/main',
})
if (currentMain.data.object.sha !== process.env.SOURCE_SHA) {
core.setFailed('Main changed after the release build; refusing Pages delivery.')
}

- name: Deploy to Cloudflare Pages
id: pages
uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0
Expand Down
79 changes: 0 additions & 79 deletions .github/workflows/pages-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ on:
permissions:
contents: read
packages: read
pull-requests: read

jobs:
identity:
Expand Down Expand Up @@ -57,7 +56,6 @@ jobs:
contents: read
deployments: write
packages: read
pull-requests: read
runs-on: ubuntu-latest
timeout-minutes: 25
environment: preview
Expand Down Expand Up @@ -123,61 +121,6 @@ jobs:
cp -R .preview-registry/. apps/client-web/dist/
cp -R apps/client-web/dist "$GITHUB_WORKSPACE/.pages-preview"

- name: Reverify pull-request identity before delivery
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
PREVIEW_BRANCH: ${{ needs.identity.outputs.branch }}
PREVIEW_HEAD_SHA: ${{ needs.identity.outputs.head_sha }}
PULL_NUMBER: ${{ needs.identity.outputs.pull_number }}
with:
script: |
const expectedBranch = `preview/client-web/pr-${process.env.PULL_NUMBER}`
if (process.env.PREVIEW_BRANCH !== expectedBranch) {
core.setFailed(`Unexpected Pages preview branch: ${process.env.PREVIEW_BRANCH}`)
return
}
const { data: pull } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: Number(process.env.PULL_NUMBER),
})
if (
pull.state !== 'open' ||
pull.base.ref !== 'main' ||
pull.head.sha !== process.env.PREVIEW_HEAD_SHA ||
pull.head.repo?.full_name !== `${context.repo.owner}/${context.repo.repo}`
) {
core.setFailed('Pull-request identity changed after the exact-head build.')
}

- name: Register the pull-request deployment
id: github-deployment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
PREVIEW_HEAD_SHA: ${{ needs.identity.outputs.head_sha }}
PULL_NUMBER: ${{ needs.identity.outputs.pull_number }}
with:
script: |
const { data: deployment } = await github.rest.repos.createDeployment({
owner: context.repo.owner,
repo: context.repo.repo,
ref: process.env.PREVIEW_HEAD_SHA,
environment: 'preview',
description: `Cloudflare Pages preview for PR #${process.env.PULL_NUMBER}`,
auto_merge: false,
required_contexts: [],
transient_environment: true,
production_environment: false,
})
core.setOutput('deployment_id', String(deployment.id))
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: deployment.id,
state: 'in_progress',
log_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
})

- name: Deploy to the isolated Pages preview branch
id: pages
uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0
Expand All @@ -193,25 +136,3 @@ jobs:
--branch=${{ needs.identity.outputs.branch }}
--commit-hash=${{ needs.identity.outputs.head_sha }}
--commit-dirty=false

- name: Report the pull-request deployment
if: ${{ always() && steps.github-deployment.outputs.deployment_id != '' }}
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
DEPLOYMENT_ID: ${{ steps.github-deployment.outputs.deployment_id }}
JOB_STATUS: ${{ job.status }}
PREVIEW_URL: ${{ steps.pages.outputs.pages-deployment-alias-url }}
with:
script: |
const success = process.env.JOB_STATUS === 'success'
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: Number(process.env.DEPLOYMENT_ID),
state: success ? 'success' : 'failure',
description: success ? 'Pull-request preview is ready' : 'Pull-request preview failed',
log_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
...(success && process.env.PREVIEW_URL
? { environment_url: process.env.PREVIEW_URL }
: {}),
})
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Reason in English. Communicate with humans in Chinese.
- Diagnose: `pnpm run doctor` (`pnpm doctor` is a different pnpm command).
- Develop: `pnpm dev`, `pnpm dev:all`, or an explicit source lane documented in `docs/40-deployment/development-runtime.md`.
- Required verification: `pnpm check`; required production outputs: `pnpm build`.
- Shadow verification: `pnpm lint:type-aware` and `pnpm type-check:ts7`.
- Optional local migration probes: `pnpm lint:type-aware` and `pnpm type-check:ts7`.
- Follow the organization-wide [Verification and Test Policy](https://github.com/InKCre/.github/blob/main/TESTING.md).
The admitted Playwright E2E suites do not authorize new automation by analogy.
- Follow `.agents/prompts/code-for-human.md` for source changes.
Expand Down
11 changes: 7 additions & 4 deletions docs/40-deployment/development-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,13 @@ accepts only a ready development runtime, and resets only this worktree's client
resources. Client-web refuses to reset or stop an external core-py runtime; recovery and cleanup
must go through core-py. Browser E2E always creates and removes its own isolated database runtime.

The database contract is generated from the selected immutable core release. CI regenerates and
checks it, runs the real core service in an isolated browser/database chain, and rejects a moved
`stable` selection before admission. Pull-request evidence does not establish source-branch or
migration equality between repositories.
The checked database projection records the contract revision intentionally adopted by this
consumer. Update it with `pnpm contract:sync` when client work adopts a newer compatible revision;
an unrelated pull request does not chase a moving `stable` channel. CI still resolves `stable` once
to an immutable image and runs that real core service through the isolated browser/database chain,
which proves the checked client remains compatible with current delivery. A breaking contract
revision requires the coordinated producer-first migration defined by the shared contract.
Pull-request evidence does not establish source-branch or migration equality between repositories.

## Operator Commands

Expand Down
Loading
Loading