Skip to content
Source
Sign inSign up

TestProviderHost.ts

81 lines3.2 KB

1import { DEFAULT_SERVER_SETTINGS, type ServerSettings } from "@t3tools/contracts";
2import * as ProviderHost from "@t3tools/provider-core/server/ProviderHost";
3import * as Context from "effect/Context";
4import * as Effect from "effect/Effect";
5import * as FileSystem from "effect/FileSystem";
6import * as Layer from "effect/Layer";
7import * as Option from "effect/Option";
8import * as Path from "effect/Path";
9import * as Ref from "effect/Ref";
10import * as Stream from "effect/Stream";
11​
12export interface TestProviderHostOptions {
13 readonly cwd?: string;
14 readonly settings?: ServerSettings;
15 readonly runBackgroundWork?: boolean;
17​
18export class TestProviderHostSettings extends Context.Service<
19 TestProviderHostSettings,
20 { readonly set: (settings: ServerSettings) => Effect.Effect<void> }
21>()("@t3tools/provider-testing/TestProviderHost/TestProviderHostSettings") {}
22​
23export const layer = (
24 options: TestProviderHostOptions = {},
25): Layer.Layer<
26 ProviderHost.ProviderHost | TestProviderHostSettings,
27 never,
28 FileSystem.FileSystem | Path.Path
29> =>
30 Layer.effectContext(
31 Effect.gen(function* () {
32 const fileSystem = yield* FileSystem.FileSystem;
33 const path = yield* Path.Path;
34 const baseDir = yield* fileSystem
35 .makeTempDirectoryScoped({ prefix: "t3-provider-host-" })
36 .pipe(Effect.orDie);
37 const stateDir = path.join(baseDir, "userdata");
38 const providerStatusCacheDir = path.join(baseDir, "caches");
39 const attachmentsDir = path.join(stateDir, "attachments");
40 for (const directory of [stateDir, providerStatusCacheDir, attachmentsDir]) {
41 yield* fileSystem.makeDirectory(directory, { recursive: true }).pipe(Effect.orDie);
42 }
43 const settings = yield* Ref.make(options.settings ?? DEFAULT_SERVER_SETTINGS);
44 const credentials = new Map<string, Uint8Array>();
45 const host = ProviderHost.ProviderHost.of({
46 paths: {
47 cwd: options.cwd ?? process.cwd(),
48 baseDir,
49 stateDir,
50 providerStatusCacheDir,
51 attachmentsDir,
52 },
53 settings: {
54 get: Ref.get(settings),
55 withSnapshot: (use) => Ref.get(settings).pipe(Effect.flatMap(use)),
56 changes: Stream.empty,
57 subscribe: Effect.succeed(Stream.empty),
58 },
59 shouldRunBackgroundWork: Effect.fn("ProviderHost.shouldRunBackgroundWork")(function () {
60 return Effect.succeed(options.runBackgroundWork ?? true);
61 }),
62 resolveAttachmentPath: (attachment) => path.join(attachmentsDir, attachment.id),
63 credentials: Effect.fn("ProviderHost.credentials")(function (namespace, bindingId) {
64 return Effect.sync(() => {
65 const key = `${namespace}:${bindingId}`;
66 return {
67 binding: { owner: "t3" as const, key },
68 get: Effect.sync(() => Option.fromUndefinedOr(credentials.get(key))),
69 set: (value: Uint8Array) => Effect.sync(() => void credentials.set(key, value)),
70 remove: Effect.sync(() => void credentials.delete(key)),
71 };
72 });
73 }),
74 });
75 return Context.make(ProviderHost.ProviderHost, host).pipe(
76 Context.add(TestProviderHostSettings, {
77 set: (next) => Ref.set(settings, next),
78 }),
79 );
80 }),
81 );