@crossdelta/infrastructure 0.5.2 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env node
2
+
3
+ // bin/generate-env.ts
4
+ import { execSync } from "node:child_process";
5
+ import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ var toEnvKey = (name) => name.toUpperCase().replace(/-/g, "_");
8
+ var resolveNumber = (value, fileContent) => {
9
+ const literal = Number.parseInt(value, 10);
10
+ if (!Number.isNaN(literal))
11
+ return literal;
12
+ const varMatch = fileContent.match(new RegExp(`(?:const|let|var)\\s+${value}\\s*=\\s*(\\d+)`));
13
+ return varMatch?.[1] ? Number.parseInt(varMatch[1], 10) : undefined;
14
+ };
15
+ var extract = {
16
+ string: (content, pattern) => content.match(pattern)?.[1],
17
+ number: (content, pattern) => {
18
+ const match = content.match(pattern)?.[1];
19
+ return match ? resolveNumber(match, content) : undefined;
20
+ },
21
+ numberArray: (content, pattern) => {
22
+ const match = content.match(pattern)?.[1];
23
+ if (!match)
24
+ return;
25
+ const numbers = match.split(",").map((v) => resolveNumber(v.trim(), content)).filter((n) => n !== undefined);
26
+ return numbers.length > 0 ? numbers : undefined;
27
+ }
28
+ };
29
+ var LOCK_FILES = ["bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"];
30
+ var hasLockFile = (dir) => LOCK_FILES.some((file) => existsSync(join(dir, file)));
31
+ var findWorkspaceRoot = () => {
32
+ let dir = process.cwd();
33
+ while (!hasLockFile(dir)) {
34
+ const parent = join(dir, "..");
35
+ if (parent === dir)
36
+ throw new Error("Could not locate workspace root");
37
+ dir = parent;
38
+ }
39
+ return dir;
40
+ };
41
+ var loadPulumiConfig = async (infraDir, stack) => {
42
+ try {
43
+ const stdout = execSync(`pulumi config --show-secrets --json --stack ${stack} --cwd ${infraDir}`, {
44
+ encoding: "utf-8",
45
+ stdio: ["pipe", "pipe", "pipe"]
46
+ });
47
+ const config = JSON.parse(stdout);
48
+ return Object.entries(config).filter(([key]) => key.includes(":")).filter(([, entry]) => entry.value !== undefined && entry.value !== null && entry.value !== "undefined").map(([fullKey, entry]) => {
49
+ const [, rawKey] = fullKey.split(":");
50
+ return `${rawKey}=${entry.value}`;
51
+ });
52
+ } catch {
53
+ return [];
54
+ }
55
+ };
56
+ var discoverServices = (servicesDir) => {
57
+ if (!existsSync(servicesDir))
58
+ return [];
59
+ const files = readdirSync(servicesDir).filter((file) => file.endsWith(".ts") && file !== "index.ts");
60
+ return files.map((file) => {
61
+ const content = readFileSync(join(servicesDir, file), "utf-8");
62
+ const portsApiMatch = content.match(/ports\(\)\.(?:http|https|grpc|primary)\((\d+)\)/) || content.match(/ports\(\)\.add\((\d+)/);
63
+ return {
64
+ name: extract.string(content, /name:\s*['"]([^'"]+)['"]/) ?? file.replace(".ts", ""),
65
+ primaryPort: portsApiMatch?.[1] ? Number.parseInt(portsApiMatch[1], 10) : undefined,
66
+ containerPort: extract.number(content, /containerPort:\s*(\w+)/),
67
+ httpPort: extract.number(content, /httpPort:\s*(\w+)/),
68
+ internalPorts: extract.numberArray(content, /internalPorts:\s*\[([^\]]+)\]/),
69
+ internalUrl: extract.string(content, /internalUrl:\s*[`'"]([^`'"]+)[`'"]/)
70
+ };
71
+ });
72
+ };
73
+ var getServicePort = (config) => {
74
+ if (config.primaryPort)
75
+ return config.primaryPort;
76
+ if (config.containerPort)
77
+ return config.containerPort;
78
+ if (config.httpPort)
79
+ return config.httpPort;
80
+ if (config.internalPorts?.[0])
81
+ return config.internalPorts[0];
82
+ return;
83
+ };
84
+ var getLocalUrl = (config) => {
85
+ const port = getServicePort(config);
86
+ if (!port)
87
+ return;
88
+ if (config.internalUrl) {
89
+ const protocolMatch = config.internalUrl.match(/^(\w+):\/\//);
90
+ if (protocolMatch) {
91
+ return `${protocolMatch[1]}://localhost:${port}`;
92
+ }
93
+ }
94
+ return `http://localhost:${port}`;
95
+ };
96
+ var main = async () => {
97
+ const noPulumi = process.argv.includes("--no-pulumi");
98
+ const workspaceRootDir = findWorkspaceRoot();
99
+ const infraDir = join(workspaceRootDir, "infra");
100
+ const servicesDir = join(infraDir, "services");
101
+ const envLines = ["# Generated .env.local"];
102
+ if (!noPulumi && existsSync(join(infraDir, "Pulumi.yaml"))) {
103
+ const pulumiEnvs = await loadPulumiConfig(infraDir, "dev");
104
+ if (pulumiEnvs.length > 0) {
105
+ envLines.push("", "# Pulumi Secrets");
106
+ envLines.push(...pulumiEnvs);
107
+ }
108
+ }
109
+ const serviceConfigs = discoverServices(servicesDir);
110
+ if (serviceConfigs.length > 0) {
111
+ envLines.push("", "# Service URLs");
112
+ for (const config of serviceConfigs) {
113
+ const url = getLocalUrl(config);
114
+ if (url) {
115
+ envLines.push(`${toEnvKey(config.name)}_URL=${url}`);
116
+ }
117
+ }
118
+ envLines.push("", "# Service Ports");
119
+ for (const config of serviceConfigs) {
120
+ const port = getServicePort(config);
121
+ if (port) {
122
+ envLines.push(`${toEnvKey(config.name)}_PORT=${port}`);
123
+ }
124
+ }
125
+ console.log(`✅ Discovered ${serviceConfigs.length} services`);
126
+ }
127
+ writeFileSync(join(workspaceRootDir, ".env.local"), `${envLines.join(`
128
+ `)}
129
+ `);
130
+ console.log(`✅ .env.local generated at ${workspaceRootDir}`);
131
+ };
132
+ main().catch((err) => {
133
+ console.error("❌", err.message);
134
+ process.exit(1);
135
+ });
@@ -48,8 +48,8 @@ export interface ValidationResult {
48
48
  *
49
49
  * const streams = collectStreamDefinitions(contracts)
50
50
  * // [
51
- * // { stream: 'ORDERS', subjects: ['orders.created', 'orders.updated'] },
52
- * // { stream: 'CUSTOMERS', subjects: ['customers.updated'] }
51
+ * // { stream: 'ORDERS', subjects: ['order.created', 'order.updated'] },
52
+ * // { stream: 'CUSTOMERS', subjects: ['customer.updated'] }
53
53
  * // ]
54
54
  * ```
55
55
  */