From 8cca94cae5c167dc8e72ac24567c8f8a0accb01b Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Fri, 11 Sep 2026 07:08:10 +0000 Subject: [PATCH] (janitor/dedupe): consolidate web sandboxIdFromUserId onto worker-utils apps/web re-declared sandboxIdFromUserId and inlined isValidInstanceId / sandboxIdFromInstanceId with comments saying they "must stay in sync" with @kilocode/worker-utils. The canonical implementation already lives in @kilocode/worker-utils/sandbox-id (and /instance-id), and web already imports that package's subpaths elsewhere. Delete the duplicate and point the single test consumer at the canonical module. Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com> --- apps/web/src/lib/kiloclaw/sandbox-id.ts | 52 ------------------- .../routers/kiloclaw-billing-router.test.ts | 2 +- 2 files changed, 1 insertion(+), 53 deletions(-) delete mode 100644 apps/web/src/lib/kiloclaw/sandbox-id.ts diff --git a/apps/web/src/lib/kiloclaw/sandbox-id.ts b/apps/web/src/lib/kiloclaw/sandbox-id.ts deleted file mode 100644 index 17040adf7d..0000000000 --- a/apps/web/src/lib/kiloclaw/sandbox-id.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Derive a deterministic sandbox ID from a user ID. - * - * Identical logic to kiloclaw/src/auth/sandbox-id.ts — base64url encoding - * of the UTF-8 bytes of the userId. Used by the Next.js backend to - * pre-generate sandbox_id when inserting the instance row into Postgres. - * - * Must stay in sync with the worker's sandboxIdFromUserId. - */ - -const MAX_SANDBOX_ID_LENGTH = 63; - -function bytesToBase64url(bytes: Uint8Array): string { - const binString = Array.from(bytes, b => String.fromCodePoint(b)).join(''); - return btoa(binString).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); -} - -export function sandboxIdFromUserId(userId: string): string { - const bytes = new TextEncoder().encode(userId); - const encoded = bytesToBase64url(bytes); - if (encoded.length > MAX_SANDBOX_ID_LENGTH) { - throw new Error( - `userId too long: encoded sandboxId would be ${encoded.length} chars (max ${MAX_SANDBOX_ID_LENGTH})` - ); - } - return encoded; -} - -// ─── Instance-scoped identity ─────────────────────────────────────── -// Canonical implementation lives in @kilocode/worker-utils/instance-id. -// Inlined here because Next.js moduleResolution can't resolve the -// worker-utils subpath export. Keep in sync with worker-utils/src/instance-id.ts. - -const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; - -export function isValidInstanceId(id: string): boolean { - return UUID_RE.test(id); -} - -export function sandboxIdFromInstanceId(instanceId: string): string { - if (!isValidInstanceId(instanceId)) { - throw new Error('Invalid instanceId: must be a UUID'); - } - const hex = instanceId.replace(/-/g, ''); - const prefixed = `ki_${hex}`; - if (prefixed.length > MAX_SANDBOX_ID_LENGTH) { - throw new Error( - `instanceId too long: prefixed sandboxId would be ${prefixed.length} chars (max ${MAX_SANDBOX_ID_LENGTH})` - ); - } - return prefixed; -} diff --git a/apps/web/src/routers/kiloclaw-billing-router.test.ts b/apps/web/src/routers/kiloclaw-billing-router.test.ts index e2b207e2cf..718324f1be 100644 --- a/apps/web/src/routers/kiloclaw-billing-router.test.ts +++ b/apps/web/src/routers/kiloclaw-billing-router.test.ts @@ -29,7 +29,7 @@ import { user_affiliate_events, } from '@kilocode/db/schema'; import { eq } from 'drizzle-orm'; -import { sandboxIdFromUserId } from '@/lib/kiloclaw/sandbox-id'; +import { sandboxIdFromUserId } from '@kilocode/worker-utils/sandbox-id'; import { createOrganization } from '@/lib/organizations/organizations'; import { insertTestUser } from '@/tests/helpers/user.helper'; import type { User } from '@kilocode/db/schema';