TypeScript
The TypeScript kit brings the provider-neutral contract to browsers, Node, and Cloudflare Workers. It keeps all platform-specific APIs injected so the core remains portable.
Implementation
Related
TypeScript Implementation Guide
This is the runbook for continuing the TypeScript kits (libs/typescript ->
@git-pont/core, kits/worker -> @git-pont/worker). It exists so a new
contributor - human or agent - can pick up the remaining work without
re-deriving context. The GitHub path is complete end to end; the tasks below are
the documented follow-ups.
Read first: Architecture, Provider Model, Authentication, Provider APIs, TypeScript Core Kit, Cloudflare Worker Service.
Ground rules (do not break these)
- The Swift kit is canonical. TypeScript must preserve field names, behavior,
and error semantics. When in doubt, match
libs/swift. - No secrets in errors or logs. Error messages must never contain token values (see Security).
- File content is raw bytes (
Uint8Array), never a pre-decoded string. - Preserve remote version identifiers (
GitRemoteVersion) for conflict detection on writes. - Everything is injected: HTTP via
HttpClient, storage viaConnectionStore/CredentialStore. Never callfetchor touch KV directly from@git-pont/core. - Tests use a mock
HttpClientwith fixtures - never hit the network in unit tests (mirrors Testing). Add tests for every new capability. - Keep
@git-pont/corefree of any Cloudflare/Node-only APIs; it must keep running in Workers, Node, and browsers.
Layout and parity map
| TypeScript | Swift source of truth |
|---|---|
libs/typescript/src/models.ts | GitPontCore/Models.swift |
libs/typescript/src/protocols.ts | GitPontCore/Protocols.swift |
libs/typescript/src/errors.ts | GitPontCore/Errors.swift |
libs/typescript/src/git-pont.ts | GitPontCore/GitPontCore.swift (facade) |
libs/typescript/src/providers/github.ts | GitPontGitHub/GitHubProvider.swift |
libs/typescript/src/providers/scaffold.ts | GitLab/Forge/Bitbucket stubs -> port targets below |
The GitProvider interface each provider must satisfy is in protocols.ts; the
complete, worked example to copy structure from is providers/github.ts.
Dev setup
npm install # from repo root (workspaces)
npm run ts:build # build @git-pont/core (tsc, strict)
npm run ts:test # @git-pont/core unit tests (vitest)
npm run worker:typecheck # typecheck @git-pont/worker
npm run test --workspace @git-pont/worker # worker unit tests
npm run worker:dev # run the worker locally (wrangler dev + .dev.vars)
libs/typescript/test/ shows the mock-client pattern (test/helpers.ts).
kits/worker/test/ shows the KV/crypto pattern (test/mock-kv.ts).
Follow-up tasks
Do them in order; each is independently shippable.
1. GitLab provider (@git-pont/core)
- Create
libs/typescript/src/providers/gitlab.tsimplementingGitProvider+GitAuthenticationProvider. Replace theGitLabProviderscaffold export insrc/index.ts/providers/scaffold.ts. - Port from
libs/swift/Sources/GitPontGitLab/GitLabProvider.swift. - API notes: Provider APIs (GitLab section) -
Repository Files API needs
apiscope for writes;x-next-pagepagination; MR wording is a UI label only (changeRequestTerm: "mergeRequest"). - Auth: OAuth PKCE preferred, PAT fallback. Implement
refreshCredential(GitLab OAuth access tokens expire ~2h and rotate the refresh token - a duplicate refresh invalidates the winner). The facade already serializes refresh per connection; do not add a second refresh path. - Support self-hosted: the constructor already takes an
instanceslist; useinstance.apiBaseURLfor all requests (never hardcodegitlab.com). - Acceptance: Acceptance Criteria GitLab rows.
Add unit tests mirroring
test/github.test.ts(account, repos withx-next-pagepagination, read file, commit conflict, OAuth PKCE complete, refresh).
2. Forgejo/Gitea provider (@git-pont/core)
- Create
libs/typescript/src/providers/forge.ts; port fromlibs/swift/Sources/GitPontForge/ForgeProvider.swift. - Key detail: use
Authorization: token <pat>for PATs andAuthorization: Bearer <token>for OAuth (covered by tests in the Swift kit). Codeberg is a preset Forgejo instance, not a separate provider kind. - Acceptance: acceptance-criteria Forgejo/Gitea rows + unit tests.
3. Bitbucket provider (@git-pont/core)
- Create
libs/typescript/src/providers/bitbucket.ts; port fromlibs/swift/Sources/GitPontBitbucket/BitbucketProvider.swift. - Follow provider-apis.md (Bitbucket section) for pagination and PR shape.
- Acceptance: acceptance-criteria Bitbucket rows + unit tests.
4. Multi-provider OAuth in the worker (@git-pont/worker)
- Today
kits/worker/src/routes/auth.tsandsrc/gitpont.tsare GitHub-only. Generalize: add:providerhandling so/auth/:provider/startand/auth/:provider/callbackwork forgithubandgitlab(browser/PKCE) andforgejo/gitea/bitbucketas configured. - Add per-provider OAuth config from env (client id/secret/scopes) and register
the matching provider in
buildUserGitPont. Keep the state-cookie CSRF check and the encrypted-credential storage unchanged. - A user may now have connections on multiple instances; the session already
carries
connectionIdsand the API resolves per repo instance. Add a?connectionId=selector where the caller must disambiguate. - Acceptance: repeat the GitHub smoke test (
/auth/:provider/start-> 302 + state cookie; callback persists an encrypted connection;/sessionlists it) for GitLab.
5. Worker write endpoints (@git-pont/worker)
- Add
POST /repos/:owner/:repo/commit,POST /repos/:owner/:repo/pulls, andPOST /repos/:owner/:repo/submit(maps toGitPont.submitChange). - Content comes in as base64 or UTF-8 text; convert to
Uint8Arraybefore buildingGitFileChange. Pass throughexpectedVersionfor conflict safety and surface409 conflictvia the existingstatusForCodemap inroutes/repos.ts. - Acceptance: a request that commits a file, and one that opens a PR via the
branchAndPullRequeststrategy, against a mock/live repo.
6. Serialized GitLab refresh via Durable Object (@git-pont/worker)
- The in-process refresh lock in
git-pont.tsis per-isolate. For GitLab's rotating refresh tokens under concurrent Worker isolates, add a Durable Object that serializes refresh per connection, and have the worker's credential path route refreshes through it. Only needed once GitLab OAuth is live.
7. Optional Client SDK
- A thin
@git-pont/clientwrapping the worker's REST API with typed methods andcredentials: "include", so GitKanban imports functions instead of hand-rolled fetches.
Definition of done per task
npm run ts:buildandnpm run worker:typecheckpass (strict, noanyleaks).- New unit tests pass and cover the capability against a mock client.
npm run docs:buildstill succeeds; update Provider APIs or TypeScript Core Kit if behavior/notes changed.- No secret ever appears in an error, log, or committed file.
- Behavior matches the Swift source and Acceptance Criteria.
TypeScript Core Kit
@git-pont/core (libs/typescript) is a TypeScript port of the canonical
git-pont contract. It is the auth + REST proxy layer: the same provider-neutral
concepts as the Swift library — connection, repository, branch, file reference,
commit, pull request — expressed as TypeScript types and a GitPont facade.
It is framework-agnostic. It depends only on the global fetch and WebCrypto,
so it runs unchanged in Cloudflare Workers, Node 18+, and browsers. The
Cloudflare Worker kit (kits/worker, @git-pont/worker) consumes this package
and adds sessions and persistence; you can also use @git-pont/core on its own.
Contract parity
The types mirror libs/swift/Sources/GitPontCore/Models.swift and
Protocols.swift field-for-field. Swift enums with associated values become
discriminated unions:
type GitRemoteVersion =
| { kind: "blobSHA"; sha: string }
| { kind: "commitID"; id: string }
| { kind: "opaque"; provider: GitProviderKind; value: string };
File content is raw bytes (Uint8Array), never a decoded string, matching the
Swift Data contract. Errors are a single GitPontError class with a
discriminated code and optional payload; messages never contain token values.
Facade
import {
GitPont,
GitHubProvider,
FetchHttpClient,
InMemoryConnectionStore,
InMemoryCredentialStore,
} from "@git-pont/core";
const gitPont = new GitPont({
providers: [new GitHubProvider(new FetchHttpClient(), githubOAuthConfig)],
connectionStore: new InMemoryConnectionStore(),
credentialStore: new InMemoryCredentialStore(),
});
const parsed = gitPont.parse("https://github.com/owner/repo/blob/feature/x/doc.md");
const reference = await gitPont.resolve(parsed); // disambiguates slashed branches
const file = await gitPont.openFile("https://github.com/owner/repo");
const repos = await gitPont.repositories(connectionId);
The facade owns provider/connection resolution, proactive and race-free token
refresh (serialized per connection — the JS analog of the Swift refresh actor),
retry policy, two-phase URL parsing, and the change-submission strategies
(directCommit, existingBranch, branchAndPullRequest, forkAndPullRequest,
automatic).
Providers
- GitHub — complete: OAuth device flow, OAuth authorization-code (web) flow for backend-mediated consumers, and PAT; account, repositories, repository, branches, read file, list directory, commit, delete, create branch, create repository, fork, and create pull request.
- GitLab / Forgejo-Gitea / Bitbucket — scaffolded. They declare identity,
capabilities, and host routing (
canHandle) so the registry works, and throwunsupportedCapabilityfor operations until ported from the Swift kit.
Storage abstractions
CredentialStore and ConnectionStore are the same async protocols as the
Swift kit. @git-pont/core ships in-memory implementations for tests; the
worker kit provides Cloudflare KV-backed implementations with encrypted
credentials.
Tests
Vitest specs cover URL parsing (including ambiguous slashed branches),
connection resolution, serialized token refresh, and the GitHub provider against
a mock HttpClient — no network access, mirroring the Swift unit-test approach.
npm run ts:build # tsc, strict
npm run ts:test # vitest