import { env } from "cloudflare:workers";
import type { RepoRow } from "~/lib/types";
import { artifactsCall } from "./artifacts-call";
import { artifactsBinding } from "./artifacts-shards";
const TOKEN_TTL_SECONDS = 3600;
const TOKEN_CACHE_SECONDS = 3000;
/** A cached token must outlive its longest use (a git request) by this much. */
const TOKEN_EXPIRY_MARGIN_SECONDS = 600;
/** KV's minimum expirationTtl. */
const MIN_KV_TTL_SECONDS = 60;
export type TokenScope = "read" | "write";
export function tokenSecret(plaintext: string): string {
return plaintext.split("?expires=")[0];
}
/** Seconds until the `?expires=<unix>` suffix of a token plaintext, or null when it has none. */
export function tokenLifetimeSeconds(plaintext: string, now = Date.now()): number | null {
const expires = Number(plaintext.split("?expires=")[1]);
return Number.isFinite(expires) && expires > 0 ? Math.floor(expires - now / 1000) : null;
}
function tokenCacheKey(artifactsName: string, scope: TokenScope): string {
return `artifacts-token:${artifactsName}:${scope}`;
}
async function cacheToken(artifactsName: string, scope: TokenScope, plaintext: string): Promise<void> {
const lifetime = tokenLifetimeSeconds(plaintext) ?? TOKEN_TTL_SECONDS;
const ttl = Math.min(TOKEN_CACHE_SECONDS, lifetime - TOKEN_EXPIRY_MARGIN_SECONDS);
if (ttl < MIN_KV_TTL_SECONDS) return;
await env.KV.put(tokenCacheKey(artifactsName, scope), tokenSecret(plaintext), { expirationTtl: ttl });
}
/**
* `create()` and `fork()` return a write token; caching it saves the `get()` + `createToken()` pair the
* first push (e.g. the initial README commit) would otherwise make. Best effort.
*/
export async function rememberInitialToken(artifactsName: string, plaintext: string | undefined): Promise<void> {