Skip to content

Commit b342387

Browse files
KingDoxikvoidhash-bot
authored andcommitted
Merge pull request #273 from voidhashcom/agent/oss-mimic-db-cloudflare
GitOrigin-RevId: bbafb7a631045cb4ca318566d7ae3c9387606db8
1 parent bb2e18a commit b342387

20 files changed

Lines changed: 2693 additions & 162 deletions

apps/backend/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
"@voidhash/backend": "workspace:*",
1616
"@voidhash/core": "workspace:*",
1717
"@voidhash/lib": "workspace:*",
18+
"@voidhash/mimic-db": "workspace:*",
19+
"@voidhash/mimic-schema": "workspace:*",
1820
"@voidhash/platform": "workspace:*",
1921
"@voidhash/platform-cloudflare": "workspace:*",
2022
"alchemy": "catalog:",

apps/backend/stack.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
import * as Alchemy from "alchemy";
22
import * as Cloudflare from "alchemy/Cloudflare";
3+
import * as Output from "alchemy/Output";
4+
import * as Config from "effect/Config";
35
import * as Effect from "effect/Effect";
6+
import * as Option from "effect/Option";
7+
import * as Redacted from "effect/Redacted";
48

59
import { DatabaseHyperdrive } from "./infrastructure/Hyperdrive.ts";
610
import { PaywallArtifactsBucket } from "./r2/PaywallArtifactsBucket.ts";
711
import { PublicFileStorageBucket } from "./r2/PublicFileStorageBucket.ts";
812
import { CommunityWebsite } from "./workers/WwwWorker.ts";
913
import CommunityBackend from "./workers/BackendWorker.ts";
14+
import MimicDbWorker, { MIMIC_DB_DEV_PORT } from "./workers/MimicDbWorker.ts";
15+
16+
const dieOnBlankWwwOrigin = (): never =>
17+
Effect.runSync(
18+
Effect.die(
19+
new Error("www origin resolved empty — refusing to bind a blank CORS_ORIGINS on mimic-db"),
20+
),
21+
);
1022

1123
/** Resolved Community Cloudflare deployment outputs. */
1224
export interface CommunityStackOutput {
1325
readonly backendUrl: string;
1426
readonly hyperdriveId: string;
27+
readonly mimicDbUrl: string;
1528
readonly wwwUrl: string;
1629
}
1730

@@ -22,15 +35,101 @@ export default Alchemy.Stack(
2235
state: Cloudflare.state(),
2336
},
2437
Effect.gen(function* () {
38+
const { stage } = yield* Alchemy.Stack;
39+
const dev = Option.match(yield* Effect.serviceOption(Alchemy.AlchemyContext), {
40+
onNone: () => false,
41+
onSome: (context) => context.dev,
42+
});
43+
const isEphemeral = stage !== "production" && stage !== "preview";
2544
const hyperdrive = yield* DatabaseHyperdrive;
2645
yield* PaywallArtifactsBucket;
2746
yield* PublicFileStorageBucket;
2847
const backend = yield* CommunityBackend;
48+
const mimicDb = yield* MimicDbWorker;
49+
yield* backend.bind`MimicHostServiceBinding`({
50+
bindings: [
51+
{
52+
type: "service",
53+
name: "MIMIC_HOST",
54+
service: mimicDb.workerName,
55+
},
56+
],
57+
});
2958
const www = yield* CommunityWebsite({ apiUrl: backend.url.as<string>() });
3059

60+
if (!dev) {
61+
yield* mimicDb.bind`MimicPublicBaseUrl`({
62+
bindings: [
63+
{
64+
type: "plain_text",
65+
name: "MIMIC_PUBLIC_BASE_URL",
66+
text: Output.map(mimicDb.url, (url) => url ?? ""),
67+
},
68+
],
69+
});
70+
}
71+
72+
const mimicRootPassword = yield* Config.redacted("MIMIC_ROOT_PASSWORD").pipe(
73+
Config.withDefault(Redacted.make("")),
74+
Effect.flatMap((password) => {
75+
if (Redacted.value(password) !== "") return Effect.succeed(password);
76+
if (isEphemeral) return Effect.succeed(Redacted.make("password"));
77+
return Effect.die(
78+
new Error("MIMIC_ROOT_PASSWORD must be set for production/preview deploys"),
79+
);
80+
}),
81+
);
82+
const resolveMimicCorsOrigins = () => {
83+
if (dev) {
84+
return [
85+
"http://localhost:3000",
86+
"http://localhost:5173",
87+
"http://localhost:4173",
88+
"http://localhost:4460",
89+
"http://localhost:3003",
90+
].join(",");
91+
}
92+
return Output.map(www.url, (url) => {
93+
const origin = (url ?? "").replace(/\/+$/, "");
94+
if (origin === "" && !isEphemeral) return dieOnBlankWwwOrigin();
95+
return origin;
96+
});
97+
};
98+
const mimicCorsOrigins = resolveMimicCorsOrigins();
99+
const resolveMimicDbUrl = () => {
100+
if (dev) return `http://localhost:${MIMIC_DB_DEV_PORT}`;
101+
return Output.map(mimicDb.url, (url) => url ?? "");
102+
};
103+
104+
yield* mimicDb.bind`MimicDbSecurity`({
105+
bindings: [
106+
{
107+
type: "secret_text",
108+
name: "ROOT_PASSWORD",
109+
text: Redacted.value(mimicRootPassword),
110+
},
111+
{ type: "plain_text", name: "CORS_ORIGINS", text: mimicCorsOrigins },
112+
],
113+
});
114+
yield* backend.bind`MimicDbCredentials`({
115+
bindings: [
116+
{
117+
type: "plain_text",
118+
name: "MIMIC_DB_URL",
119+
text: resolveMimicDbUrl(),
120+
},
121+
{
122+
type: "secret_text",
123+
name: "MIMIC_ROOT_PASSWORD",
124+
text: Redacted.value(mimicRootPassword),
125+
},
126+
],
127+
});
128+
31129
return {
32130
backendUrl: backend.url,
33131
hyperdriveId: hyperdrive.hyperdriveId,
132+
mimicDbUrl: mimicDb.url,
34133
wwwUrl: www.url,
35134
};
36135
}),

apps/backend/workers/BackendWorker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import { RuntimeContext } from "alchemy/RuntimeContext";
44
import { EventCaptureApi } from "@voidhash/api-contracts/event-capture";
55
import {
66
BackendComponentCompilerStubLive,
7-
BackendMimicHostStubLive,
87
BackendNoopIdentityProjectionPublisherLive,
98
BackendPaymentProviderStubsLive,
109
BackendSnapshotImageRendererStubLive,
1110
NoBackendFeatures,
1211
NoBackendRpcExtension,
1312
buildBackendFetch,
1413
} from "@voidhash/backend/BackendApp";
14+
import { makeMimicHostLive } from "@voidhash/backend/MimicHostLive";
1515
import { RpcAuthLive } from "@voidhash/backend/RpcMiddlewares";
1616
import { EventCaptureGroupLive } from "@voidhash/backend/routes/event-capture";
1717
import { AnalyticsEventStore } from "@voidhash/core/services/analytics/AnalyticsEventStore";
@@ -211,7 +211,7 @@ export default Cloudflare.Worker(
211211
publicFileStore,
212212
BackendPaymentProviderStubsLive,
213213
BackendNoopIdentityProjectionPublisherLive,
214-
BackendMimicHostStubLive,
214+
makeMimicHostLive(environment),
215215
BackendComponentCompilerStubLive,
216216
BackendSnapshotImageRendererStubLive,
217217
ProjectSchemaCacheLive,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { makeMimicDbWorker } from "@voidhash/mimic-db/cloudflare/MimicDbWorker";
2+
import { PaywallMigrationRegistry } from "@voidhash/mimic-schema";
3+
4+
import { DatabaseHyperdrive } from "../infrastructure/Hyperdrive.ts";
5+
6+
export const MIMIC_DB_DEV_PORT = 5001;
7+
8+
/** Community deployment composition for the mimic-db Cloudflare Worker. */
9+
const MimicDbWorker: ReturnType<typeof makeMimicDbWorker> = makeMimicDbWorker({
10+
devPort: MIMIC_DB_DEV_PORT,
11+
hyperdrive: DatabaseHyperdrive,
12+
main: import.meta.filename,
13+
migrations: PaywallMigrationRegistry,
14+
});
15+
16+
export default MimicDbWorker;

0 commit comments

Comments
 (0)