History

Prepare datamodel for multi-environment (#1765)

Julius Marminge committed 7 months ago

Commit b96308f1 parent 72b7f90121 files · +10206 −4969Browse files

Showing the changes to packages/client-runtime/src (4 of 121 files). Show all

Unified · Split

4 files
  1. packages/client-runtime/src/index.ts +2 −0
  2. packages/client-runtime/src/knownEnvironment.test.ts +63 −0
  3. packages/client-runtime/src/knownEnvironment.ts +39 −0
  4. packages/client-runtime/src/scoped.ts +64 −0
packages/client-runtime/src/index.ts+2−0
@@ -0,0 +1,2 @@
1+export * from "./knownEnvironment";
2+export * from "./scoped";
packages/client-runtime/src/knownEnvironment.test.ts+63−0
@@ -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+});
packages/client-runtime/src/knownEnvironment.ts+39−0
@@ -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+}
packages/client-runtime/src/scoped.ts+64−0
@@ -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+}