feat(plugins): Phase 3 — ordering + cron liveness + reconciliation (T3.1–T3.6)#852
Open
lane711 wants to merge 1 commit into
Open
feat(plugins): Phase 3 — ordering + cron liveness + reconciliation (T3.1–T3.6)#852lane711 wants to merge 1 commit into
lane711 wants to merge 1 commit into
Conversation
…observability (T3.1–T3.6)
T3.1 — Dependency topo-sort + cycle detection:
- `plugins/topo-sort.ts`: DFS topo-sort with `visiting` stack, throws
`PluginDependencyCycleError` on cycles, warns/throws on missing dep ids (strict).
- `MountablePlugin` + `WirablePlugin` extended with optional `id` + `dependencies`.
- `registerPluginRoutes` + `wireRegisteredPlugins` now sort by dependencies by
default (sortByDependencies=true); old-style plugins without `dependencies`
keep their original declaration order.
T3.2 — bootIsolate extraction:
- HTTP middleware body factored into `boot: BootIsolateFn` closure — the same
once-guarded `initEmailService` + `wirePlugins` call, now exposed on the
returned `SonicJSApp` object.
- `SonicJSApp` type extended with `readonly boot: BootIsolateFn`.
- The HTTP middleware now calls `boot(c.env)`, sharing the once-guard with any
other caller (cron, test harness).
T3.3 — Wire scheduled() end-to-end:
- `createScheduledHandler` gains optional `boot?` parameter. Called before the
first cron dispatch so a cron-first cold isolate has a populated hook bus and
reachable email service; warm isolates return instantly (once-guard).
- `my-sonicjs-app/src/index.ts` restructured to export `{ fetch, scheduled }` —
a proper Worker object instead of a bare Hono app. `scheduled` wires through
`app.boot`.
T3.4 — wrangler.toml [triggers] codegen:
- `plugins/generate-triggers.ts`: `parseCronTriggers`, `updateWranglerTriggers`,
`generateTriggersComment` utilities.
- `my-sonicjs-app/scripts/generate-cron-triggers.ts`: a tsx script that reads
plugin `crons[]` and writes the `[triggers]` section; `--check` mode for CI.
T3.5 — Per-provider reconciliation + observability migration:
- `EmailProvider.reconcile?()` optional method for delivery-state backfill.
- `EmailLogRow` type for reconciliation inputs.
- Migration `038_email_log_observability.sql`: adds `user_id`, `context_type`,
`context_id`, `tenant_id`, `delivery_state`, `delivery_synced_at` (all
nullable, no defaults — forward-only D1 / NULL-safe). Partial index for
reconciliation queries; per-user history index.
T3.6 — CloudflareEmailProvider:
- `services/email/providers/cloudflare.ts`: `CloudflareEmailProvider` wraps the
`send_email` Workers binding (MailChannels / CF Email Routing).
New exports: `createScheduledHandler`, `dispatchCronTick`, `collectCrons`,
`collectCronSchedules`, `getHookSystem`, `topoSort`, `PluginDependencyCycleError`,
`CloudflareEmailProvider`, `parseCronTriggers`, `updateWranglerTriggers`,
`BootIsolateFn`.
Tests: +25 (topo-sort: 11, boot-isolate: 8, generate-triggers: 6).
Full suite: 1647 passed, 0 failed; tsc + lint clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This was referenced Jun 6, 2026
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.
Summary
Phase 3 of the plugin framework overhaul — takes the system to production-ready by making dependency ordering, cron cold-start wiring, delivery reconciliation, and the Worker entry real.
Stacked on: #844 (
lane711/plugin-system-define)T3.1 — Dependency topo-sort + cycle detection
plugins/topo-sort.ts: DFS topo-sort withvisitingstack, throwsPluginDependencyCycleErroron cycles, warns/throws on missing dep IDs (strict/non-strict).MountablePlugin+WirablePluginextended withid?+dependencies?.registerPluginRoutesandwireRegisteredPluginsnow sort by dependencies before mounting/wiring. Old-style PluginBuilder plugins (nodependencies) keep their original order.T3.2 — bootIsolate extraction
boot: BootIsolateFn— the same once-guardedinitEmailService + wirePluginscall, now exposed onSonicJSApp.SonicJSApp.boot(env): callable from cron handlers, tests, or any non-HTTP context. Idempotent.T3.3 — Wire
scheduled()end-to-endcreateScheduledHandlergains optionalboot?parameter: called before the first dispatch so cron-first cold isolates have a populated hook bus.my-sonicjs-app/src/index.tsrestructured to export{ fetch, scheduled }— a proper Worker object that wires plugins even when cron fires first.T3.4 — wrangler.toml
[triggers]codegenplugins/generate-triggers.ts:parseCronTriggers,updateWranglerTriggers,generateTriggersComment.my-sonicjs-app/scripts/generate-cron-triggers.ts:--checkmode for CI sync guard.T3.5 — Per-provider reconciliation + observability migration
EmailProvider.reconcile?()optional method;EmailLogRowtype.038: addsuser_id,context_type,context_id,tenant_id,delivery_state,delivery_synced_attoemail_log(all nullable, no defaults). Partial index for reconciliation; per-user history index.T3.6 — CloudflareEmailProvider
services/email/providers/cloudflare.ts: wraps thesend_emailWorkers binding (MailChannels / CF Email Routing). ConfigurabledefaultFrom.Test plan
npm test --workspace=@sonicjs-cms/core→ 1647 passed, 0 failedtsc --noEmit→ cleaneslint src/→ 0 errors🤖 Generated with Claude Code