Package the Tasks app's project-config bridge
Status#
The connector, tiny package artifact, pkg.pr.new publishing, and docs are
implemented. Repo-wide lint, typecheck, and tests pass. The PR was reshaped
mid-flight: an earlier revision wired @iterate-com/tasks into the OS seeded
template and taught the kernel (config, env, seeding, dynamic builds, deploy)
to preview-pin it; that was all reverted — apps/os is now untouched. Only
the companion iterate/config PR and its install proof remain.
Goal#
Let project config workers import one tiny connector for the independently deployed Tasks app instead of copying its auth and reverse-proxy code:
import { TasksApp } from "@iterate-com/tasks";
const tasksApp = TasksApp.create(env, {
auth: { policy: "project-member" },
proxy: {
origin: "https://tasks.iterate.workers.dev",
originOverrideKvKey: "tasks-app-origin",
},
});The returned object exposes only:
{ fetch(request: Request): Promise<Response> }Tasks remains a separately deployed stateless vessel. The package contains only the config-side connector; it must not ship the Tasks client, server, Durable Object, or their dependency graph.
Locked decisions#
- The OS kernel stays tasks-free.
@iterate-com/tasksis a package for external config repos (iterate/configfirst); OS never depends on it, the seeded template doesn't reference it, and no kernel code (config schema, env, repo seeding, dynamic worker builds, deploy) knows its name. The only in-repo consumers areapps/tasksitself and the pkg.pr.new workflow that publishes it. - Consequence: no preview pinning for the tasks package. Config repos install
it from
https://pkg.pr.new/iterate/iterate/@iterate-com/tasks@main(or a pinned@<sha>); preview environments don't co-test bridge changes. That's acceptable for a thin proxy connector — if it ever isn't, generic (name- agnostic) pkg.pr.new ref pinning is the follow-up, not per-package kernel knobs. - The public name is
TasksApp; “bridge” is only an internal term. - Export
TasksAppfrom the root of@iterate-com/tasks. The package has no other public export. TasksApp.fetchowns both auth and proxying so one ITX session serves the member gate and KV lookup.- Every deployment/policy choice is a required
createinput. - The only accepted auth value is
{ policy: "project-member" }. proxy.originis a full HTTPS origin.proxy.originOverrideKvKeynames a KV entry whose value, when present, is also a full HTTPS origin.- Replacing the request origin preserves method, path, query, headers, body, redirects, and WebSocket upgrades. Manual redirect handling is an internal proxy invariant, not an option.
- There is no
processEvent: Tasks owns no config-worker stream state. - Do not add generic remote-app abstractions or speculative auth, protocol, header, or fetch options.
Checklist#
- Add a public-interface spec for
TasksApp.create(env, { auth, proxy }).fetch(request), starting with member denial and successful proxying.config-bridge.test.tscovers both branches, full-origin overrides, and malformed origins. - Implement the connector with required options and runtime validation of
configured/default and KV override origins.
config-bridge.tsexposes onlyTasksApp.create(...).fetch. - Preserve the trusted project ID header and project auth cookie across normal HTTP and WebSocket proxy requests. The transparent-proxy spec checks body, routing headers, cookie, and upgrade.
- Give
apps/tasksa separate connector-only package build and root export while preserving its existing Vite/Cloudflare app build. A separatetsconfig.package.jsonemits the package; the full Vite build remains green. - Make all Tasks app packages development-only for publication. The connector uses a self-contained structural ITX type, so the tarball has no runtime or peer dependencies.
- Add a packed-tarball test proving no app source, client/server bundles,
Durable Objects, or app dependency graph ships. The exact four-artifact
allowlist plus README/license is checked after
pnpm pack. - Publish
packages/iterateandapps/tasksin one lockedpkg-pr-newinvocation. The workflow uses lockedpkg-pr-new@0.0.79; both long-form URLs (.../iterate/iterate/iterate@<ref>and.../iterate/iterate/@iterate-com/tasks@<ref>) verified resolving. AddReverted by decision: the template (and everything under@iterate-com/tasksto the OS project-config template and replace the hand-written Tasks branch withTasksApp.apps/os) stays tasks-free. The template keeps its inline proxy;iterate/configis the package's consumer. A follow-up could switch the template to the package after this merges (once@mainexists), if wanted.Pin bothReverted by decision: no kernel knowledge of the tasks package. Preview pinning remains iterate-only, exactly as on main.iterateand@iterate-com/tasksto the same exact PR SHA in preview-created and preview-rebuilt config repos.- Update Tasks and remote-app docs, including full-origin KV examples.
The README, vessel landing page, and remote-app guide use
TasksAppand complete HTTPS KV values. - Open the companion
iterate/configPR using the published package and the same declarativeTasksAppcall. Post-merge follow-up: draft iterate/config#20 exists; it lands after this merges, once the tasks package's@mainchannel starts publishing. - Prove a fresh minimal config install/typecheck, the normal Tasks app
build, package contents, member denial, HTTP proxying, KV override
proxying, and WebSocket forwarding. Post-merge follow-up, via
iterate/config#20 against the
@mainchannel. Install/typecheck was already proven pre-reshape on the PR channel; the packed artifact is unchanged since apart from theif (override)fallback tweak. - Run scoped tests/typechecks/lint/format, then the repo-required validation appropriate to the touched packages.
Implementation notes#
tasks-app-originvalues are full HTTPS origins in all examples now; the package throws on non-HTTPS or non-origin values, and a falsy/absent KV value falls back to the configured origin.- The structural ITX input type keeps
@iterate-com/taskscompletely dependency-free while accepting the platform's realenv.ITXbinding. - Publishing two packages in one pkg.pr.new invocation keeps the existing
long-form iterate URL (
https://pkg.pr.new/iterate/iterate/iterate@<ref>) working — verified against this PR's own head SHA — so the kernel'sTEMPLATE_ITERATE_PACKAGE_SPECneeded no change. - The companion config PR must follow the Iterate PR because its dependency
needs the scoped package URL emitted by
pkg.pr.new(from@mainafter merge, or a@<sha>/@<pr>channel before).