Skip to content

feat(shared-rules): anonymous community registry for rewrite rules (#53) - #57

Open
yinxulai wants to merge 1 commit into
mainfrom
feat/shared-rewrite-rules
Open

yinxulai wants to merge 1 commit into
mainfrom
feat/shared-rewrite-rules

Conversation

@yinxulai

@yinxulai yinxulai commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Summary

Implements #53: a shared rewrite-rule directory on top of the existing apps/apis Cloudflare Worker. Users can publish request rewrite rules anonymously and adopt them without installing anything — save and it just works. Lists are ranked by usage count.

Closes #53.

What changed

Contracts (packages/contracts/source/shared-rewrite-rules.ts)

  • SharedRewriteRulePayloadSchema (.strict()), SharedRewriteRuleSchema (record: +id/usageCount/createdTime/updatedTime).
  • List/Get/Publish/Use input schemas, SharedRewriteRuleSortSchema (popular | recent), size/limit/length constants, and a stage guard sharedRewriteRuleDisabledReason() that rejects payloads carrying response-stage actions.

Worker (apps/apis)

  • schema.sql D1 table shared_rewrite_rules with idx_shared_rewrite_rules_usage (usage DESC, updated DESC) and idx_shared_rewrite_rules_recent (updated DESC).
  • source/registry/*: POST /v1/rules/{list,get,publish,use}. The record id is a content signature (canonical JSON -> sha256, sha256:<hex>) so re-publishing the same rule is an idempotent upsert. Only the use path increments usage_count.

Core relay (packages/core/source/management/shared-rules/*)

  • Outbound client (endpoint derived from getSettings().telemetryEndpoint, 404 -> RESOURCE_NOT_FOUND, non-2xx -> UPSTREAM_ERROR, 10s timeout) + management service + route POST /api/shared-rewrite-rule/{list,get,publish,use}.
  • publishRuleToDirectory(ruleId) is stage-gated (RESPONSE_REWRITE_DISABLED 400). adoptSharedRule(id) creates a local rule with source: 'imported', enabled: true and best-effort bumps remote usage.

Console (packages/console)

  • New /shared-rules page (search, popular/recent sort, adopt button) under the advanced nav section; a Share action on the local rules table; i18n catalogs (ui.en.ts / ui.zh-CN.ts).

Docs

  • apps/docs/specs/shared-rewrite-rules.md — final-state spec (contract, relay, storage, deployment).

Autonomous decisions

  • Anonymous publish, usage-ranked ordering, save-and-use (adopt creates a local rule) exactly as the issue asks.
  • Content-signature id: publishing is idempotent; no separate dedupe needed, and it avoids trusting a client-supplied id.
  • Graceful degradation: the D1 binding is optional. When it is missing the Worker returns not_configured (500) instead of crashing, so the Worker can ship before D1 is provisioned.
  • Response-stage rules can't be published — the directory only carries request-stage actions.

Deployment (manual, not done here)

wrangler is not authenticated in this environment, so D1 was not provisioned and the Worker was not deployed. Before deploying the Worker release:

  1. wrangler d1 create osw-shared-rules
  2. Put the returned id into apps/apis/wrangler.toml (currently the placeholder REPLACE_WITH_D1_DATABASE_ID).
  3. wrangler d1 execute osw-shared-rules --remote --file apps/apis/schema.sql
  4. wrangler deploy

If steps 1–3 are skipped, the endpoints respond not_configured but the rest of the Worker is unaffected.

Verification

  • typecheck — pass
  • eslint — pass (includes i18n / boundary / package-boundary rules)
  • vitest — 215 files / 2618 tests pass (baseline was 194 files / 2298 tests)

No version numbers were touched; this is not a release.

Add a shared rewrite-rule directory so users can publish and adopt
request rewrite rules without installing anything: anonymous publish,
ranked by usage count.

- contracts: SharedRewriteRule payload/record schemas, list/get/publish/
  use input schemas, sort enum, size limits, and a stage guard that
  rejects rules carrying response-stage actions.
- apis worker: D1-backed registry (schema.sql + registry/*) exposing
  POST /v1/rules/{list,get,publish,use}. Id is a content signature
  (canonical JSON -> sha256) so publishing the same rule is an idempotent
  upsert; only the `use` path increments usage_count. DB is optional:
  when the binding is missing the worker degrades to not_configured (500)
  instead of crashing, so the worker can ship before D1 is provisioned.
- core: outbound client + management service + route
  POST /api/shared-rewrite-rule/{list,get,publish,use}; adopting a rule
  creates a local rule with source 'imported' and best-effort usage bump.
- console: /shared-rules page (search, popular/recent sort, adopt), a
  Share action on the local rules table, i18n catalogs, routing + nav.
- docs: apps/docs/specs/shared-rewrite-rules.md final-state spec.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
osw-apis d9fb3b2 Oct 04 2026, 02:09 AM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Failed ❌

View logs ↗
d9fb3b2 2026-10-04T02:10:56.653Z View logs ↗

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

共享重写规则:从只读规则源浏览、预览、安装社区模板(区别于私有云备份)

1 participant