Showing the changes to packages/client-runtime/src (4 of 121 files). Show all
Unified · Split
| @@ -0,0 +1,2 @@ | ||
| 1 | +export * from "./knownEnvironment"; | |
| 2 | +export * from "./scoped"; | |
| @@ -0,0 +1,63 @@ | ||
| 1 | +import { EnvironmentId, ProjectId, ThreadId } from "@t3tools/contracts"; | |
| 2 | +import { describe, expect, it } from "vitest"; | |
| 3 | + | |
| 4 | +import { createKnownEnvironmentFromWsUrl } from "./knownEnvironment"; | |
| 5 | +import { | |
| 6 | + parseScopedProjectKey, | |
| 7 | + parseScopedThreadKey, | |
| 8 | + scopedProjectKey, | |
| 9 | + scopedRefKey, | |
| 10 | + scopedThreadKey, | |
| 11 | + scopeProjectRef, | |
| 12 | + scopeThreadRef, | |
| 13 | +} from "./scoped"; | |
| 14 | + | |
| 15 | +describe("known environment bootstrap helpers", () => { | |
| 16 | + it("creates known environments from explicit ws urls", () => { | |
| 17 | + expect( | |
| 18 | + createKnownEnvironmentFromWsUrl({ | |
| 19 | + label: "Remote environment", | |
| 20 | + wsUrl: "wss://remote.example.com/ws", | |
| 21 | + }), | |
| 22 | + ).toEqual({ | |
| 23 | + id: "ws:Remote environment", | |
| 24 | + label: "Remote environment", | |
| 25 | + source: "manual", | |
| 26 | + target: { | |
| 27 | + type: "ws", | |
| 28 | + wsUrl: "wss://remote.example.com/ws", | |
| 29 | + }, | |
| 30 | + }); | |
| 31 | + }); | |
| 32 | +}); | |
| 33 | + | |
| 34 | +describe("scoped refs", () => { | |
| 35 | + const environmentId = EnvironmentId.makeUnsafe("environment-test"); | |
| 36 | + const projectRef = scopeProjectRef(environmentId, ProjectId.makeUnsafe("project-1")); | |
| 37 | + const threadRef = scopeThreadRef(environmentId, ThreadId.makeUnsafe("thread-1")); | |
| 38 | + | |
| 39 | + it("builds stable scoped project and thread keys", () => { | |
| 40 | + expect(scopedRefKey(projectRef)).toBe("environment-test:project-1"); | |
| 41 | + expect(scopedRefKey(threadRef)).toBe("environment-test:thread-1"); | |
| 42 | + expect(scopedProjectKey(projectRef)).toBe("environment-test:project-1"); | |
| 43 | + expect(scopedThreadKey(threadRef)).toBe("environment-test:thread-1"); | |
| 44 | + }); | |
| 45 | + | |
| 46 | + it("returns typed scoped refs", () => { | |
| 47 | + expect(projectRef).toEqual({ | |
| 48 | + environmentId, | |
| 49 | + projectId: ProjectId.makeUnsafe("project-1"), | |
| 50 | + }); | |
| 51 | + expect(threadRef).toEqual({ | |
| 52 | + environmentId, | |
| 53 | + threadId: ThreadId.makeUnsafe("thread-1"), | |
| 54 | + }); | |
| 55 | + }); | |
| 56 | + | |
| 57 | + it("parses scoped project and thread keys back into refs", () => { | |
| 58 | + expect(parseScopedProjectKey("environment-test:project-1")).toEqual(projectRef); | |
| 59 | + expect(parseScopedThreadKey("environment-test:thread-1")).toEqual(threadRef); | |
| 60 | + expect(parseScopedProjectKey("bad-key")).toBeNull(); | |
| 61 | + expect(parseScopedThreadKey("bad-key")).toBeNull(); | |
| 62 | + }); | |
| 63 | +}); | |
| @@ -0,0 +1,39 @@ | ||
| 1 | +import type { EnvironmentId } from "@t3tools/contracts"; | |
| 2 | + | |
| 3 | +export interface KnownEnvironmentConnectionTarget { | |
| 4 | + readonly type: "ws"; | |
| 5 | + readonly wsUrl: string; | |
| 6 | +} | |
| 7 | + | |
| 8 | +export type KnownEnvironmentSource = "configured" | "desktop-managed" | "manual" | "window-origin"; | |
| 9 | + | |
| 10 | +export interface KnownEnvironment { | |
| 11 | + readonly id: string; | |
| 12 | + readonly label: string; | |
| 13 | + readonly source: KnownEnvironmentSource; | |
| 14 | + readonly environmentId?: EnvironmentId; | |
| 15 | + readonly target: KnownEnvironmentConnectionTarget; | |
| 16 | +} | |
| 17 | + | |
| 18 | +export function createKnownEnvironmentFromWsUrl(input: { | |
| 19 | + readonly id?: string; | |
| 20 | + readonly label: string; | |
| 21 | + readonly source?: KnownEnvironmentSource; | |
| 22 | + readonly wsUrl: string; | |
| 23 | +}): KnownEnvironment { | |
| 24 | + return { | |
| 25 | + id: input.id ?? `ws:${input.label}`, | |
| 26 | + label: input.label, | |
| 27 | + source: input.source ?? "manual", | |
| 28 | + target: { | |
| 29 | + type: "ws", | |
| 30 | + wsUrl: input.wsUrl, | |
| 31 | + }, | |
| 32 | + }; | |
| 33 | +} | |
| 34 | + | |
| 35 | +export function getKnownEnvironmentBaseUrl( | |
| 36 | + environment: KnownEnvironment | null | undefined, | |
| 37 | +): string | null { | |
| 38 | + return environment?.target.wsUrl ?? null; | |
| 39 | +} | |
| @@ -0,0 +1,64 @@ | ||
| 1 | +import type { | |
| 2 | + EnvironmentId, | |
| 3 | + ProjectId, | |
| 4 | + ScopedProjectRef, | |
| 5 | + ScopedThreadRef, | |
| 6 | + ThreadId, | |
| 7 | +} from "@t3tools/contracts"; | |
| 8 | + | |
| 9 | +export function scopeProjectRef( | |
| 10 | + environmentId: EnvironmentId, | |
| 11 | + projectId: ProjectId, | |
| 12 | +): ScopedProjectRef { | |
| 13 | + return { environmentId, projectId }; | |
| 14 | +} | |
| 15 | + | |
| 16 | +export function scopeThreadRef(environmentId: EnvironmentId, threadId: ThreadId): ScopedThreadRef { | |
| 17 | + return { environmentId, threadId }; | |
| 18 | +} | |
| 19 | + | |
| 20 | +export function scopedRefKey(ref: ScopedProjectRef | ScopedThreadRef): string { | |
| 21 | + const localId = "projectId" in ref ? ref.projectId : ref.threadId; | |
| 22 | + return `${ref.environmentId}:${localId}`; | |
| 23 | +} | |
| 24 | + | |
| 25 | +export function scopedProjectKey(ref: ScopedProjectRef): string { | |
| 26 | + return scopedRefKey(ref); | |
| 27 | +} | |
| 28 | + | |
| 29 | +export function scopedThreadKey(ref: ScopedThreadRef): string { | |
| 30 | + return scopedRefKey(ref); | |
| 31 | +} | |
| 32 | + | |
| 33 | +function parseScopedKey(key: string): { environmentId: EnvironmentId; localId: string } | null { | |
| 34 | + const separatorIndex = key.indexOf(":"); | |
| 35 | + if (separatorIndex <= 0 || separatorIndex >= key.length - 1) { | |
| 36 | + return null; | |
| 37 | + } | |
| 38 | + return { | |
| 39 | + environmentId: key.slice(0, separatorIndex) as EnvironmentId, | |
| 40 | + localId: key.slice(separatorIndex + 1), | |
| 41 | + }; | |
| 42 | +} | |
| 43 | + | |
| 44 | +export function parseScopedProjectKey(key: string): ScopedProjectRef | null { | |
| 45 | + const parsed = parseScopedKey(key); | |
| 46 | + if (!parsed) { | |
| 47 | + return null; | |
| 48 | + } | |
| 49 | + return { | |
| 50 | + environmentId: parsed.environmentId, | |
| 51 | + projectId: parsed.localId as ProjectId, | |
| 52 | + }; | |
| 53 | +} | |
| 54 | + | |
| 55 | +export function parseScopedThreadKey(key: string): ScopedThreadRef | null { | |
| 56 | + const parsed = parseScopedKey(key); | |
| 57 | + if (!parsed) { | |
| 58 | + return null; | |
| 59 | + } | |
| 60 | + return { | |
| 61 | + environmentId: parsed.environmentId, | |
| 62 | + threadId: parsed.localId as ThreadId, | |
| 63 | + }; | |
| 64 | +} | |