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 @@
1export * from "./knownEnvironment";
2export * from "./scoped";
packages/client-runtime/src/knownEnvironment.test.ts+63−0
@@ -0,0 +1,63 @@
1import { EnvironmentId, ProjectId, ThreadId } from "@t3tools/contracts";
2import { describe, expect, it } from "vitest";
3
4import { createKnownEnvironmentFromWsUrl } from "./knownEnvironment";
5import {
6 parseScopedProjectKey,
7 parseScopedThreadKey,
8 scopedProjectKey,
9 scopedRefKey,
10 scopedThreadKey,
11 scopeProjectRef,
12 scopeThreadRef,
13} from "./scoped";
14
15describe("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
34describe("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 @@
1import type { EnvironmentId } from "@t3tools/contracts";
2
3export interface KnownEnvironmentConnectionTarget {
4 readonly type: "ws";
5 readonly wsUrl: string;
6}
7
8export type KnownEnvironmentSource = "configured" | "desktop-managed" | "manual" | "window-origin";
9
10export interface KnownEnvironment {
11 readonly id: string;
12 readonly label: string;
13 readonly source: KnownEnvironmentSource;
14 readonly environmentId?: EnvironmentId;
15 readonly target: KnownEnvironmentConnectionTarget;
16}
17
18export 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
35export 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 @@
1import type {
2 EnvironmentId,
3 ProjectId,
4 ScopedProjectRef,
5 ScopedThreadRef,
6 ThreadId,
7} from "@t3tools/contracts";
8
9export function scopeProjectRef(
10 environmentId: EnvironmentId,
11 projectId: ProjectId,
12): ScopedProjectRef {
13 return { environmentId, projectId };
14}
15
16export function scopeThreadRef(environmentId: EnvironmentId, threadId: ThreadId): ScopedThreadRef {
17 return { environmentId, threadId };
18}
19
20export function scopedRefKey(ref: ScopedProjectRef | ScopedThreadRef): string {
21 const localId = "projectId" in ref ? ref.projectId : ref.threadId;
22 return `${ref.environmentId}:${localId}`;
23}
24
25export function scopedProjectKey(ref: ScopedProjectRef): string {
26 return scopedRefKey(ref);
27}
28
29export function scopedThreadKey(ref: ScopedThreadRef): string {
30 return scopedRefKey(ref);
31}
32
33function 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
44export 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
55export 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}