@flink-app/flink 2.0.0-alpha.58 → 2.0.0-alpha.60
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.
- package/CHANGELOG.md +12 -0
- package/cli/cli-utils.ts +1 -0
- package/cli/dev.ts +27 -4
- package/cli/loadEnvFiles.ts +116 -0
- package/cli/run.ts +14 -0
- package/dist/cli/cli-utils.js +13 -10
- package/dist/cli/dev.js +26 -8
- package/dist/cli/loadEnvFiles.d.ts +30 -0
- package/dist/cli/loadEnvFiles.js +113 -0
- package/dist/cli/run.js +15 -4
- package/dist/src/TypeScriptCompiler.d.ts +20 -0
- package/dist/src/TypeScriptCompiler.js +99 -4
- package/dist/src/ai/AgentRunner.js +1 -1
- package/dist/src/ai/FlinkAgent.d.ts +3 -2
- package/dist/src/ai/agentInstructions.js +60 -20
- package/dist/src/utils/loadFlinkConfig.d.ts +23 -1
- package/dist/src/utils/loadFlinkConfig.js +3 -3
- package/package.json +2 -2
- package/spec/AgentRunner.spec.ts +1 -1
- package/spec/FlinkAgent.spec.ts +1 -1
- package/src/TypeScriptCompiler.ts +93 -2
- package/src/ai/AgentRunner.ts +1 -1
- package/src/ai/FlinkAgent.ts +3 -2
- package/src/ai/agentInstructions.ts +67 -21
- package/src/utils/loadFlinkConfig.ts +26 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @flink-app/flink
|
|
2
2
|
|
|
3
|
+
## 2.0.0-alpha.60
|
|
4
|
+
|
|
5
|
+
## 2.0.0-alpha.59
|
|
6
|
+
|
|
7
|
+
### Minor Changes
|
|
8
|
+
|
|
9
|
+
- dbc2119: feat: add generic compiler extension system and @flink-app/inbound-email-plugin
|
|
10
|
+
|
|
11
|
+
Add `compilerPlugins` to `FlinkConfig` and `FlinkCompilerPlugin` interface so plugins can declare custom scan directories for auto-discovery. The TypeScript compiler reads these at build time, generates the corresponding `.flink/generatedXxx.ts` registration files, and includes them in the start script.
|
|
12
|
+
|
|
13
|
+
Introduce `@flink-app/inbound-email-plugin` as the first consumer of this system. It starts an SMTP server and automatically routes inbound emails to matching `EmailHandler` files discovered in `src/email-handlers/`. User and permission context are injected via `AsyncLocalStorage` for seamless integration with Flink tools and agents.
|
|
14
|
+
|
|
3
15
|
## 2.0.0-alpha.58
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/cli/cli-utils.ts
CHANGED
|
@@ -116,6 +116,7 @@ export async function compile(opts: CompileOptions): Promise<void> {
|
|
|
116
116
|
await compiler.parseTools();
|
|
117
117
|
await compiler.parseAgents();
|
|
118
118
|
await compiler.parseJobs();
|
|
119
|
+
await compiler.parseAllExtensionDirs();
|
|
119
120
|
await compiler.parseHandlers();
|
|
120
121
|
await compiler.generateStartScript(entry);
|
|
121
122
|
await compiler.generateAllSchemas();
|
package/cli/dev.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { existsSync } from "fs";
|
|
|
6
6
|
import { parseArgs, hasFlag, getOption, normalizeEntry, printHelp, compile, forkApp } from "./cli-utils";
|
|
7
7
|
import { FlinkLogFactory } from "../src/FlinkLogFactory";
|
|
8
8
|
import { loadFlinkConfig } from "../src/utils/loadFlinkConfig";
|
|
9
|
+
import { loadEnvFiles } from "./loadEnvFiles";
|
|
9
10
|
|
|
10
11
|
// Load config BEFORE creating logger
|
|
11
12
|
const flinkConfig = loadFlinkConfig();
|
|
@@ -16,6 +17,19 @@ const logger = FlinkLogFactory.createLogger("flink.dev");
|
|
|
16
17
|
module.exports = async function dev(args: string[]) {
|
|
17
18
|
const parsed = parseArgs(args);
|
|
18
19
|
|
|
20
|
+
// Load .env files before anything else so all env vars are available at startup.
|
|
21
|
+
// NODE_ENV defaults to "development" when not explicitly set.
|
|
22
|
+
if (!process.env.NODE_ENV) {
|
|
23
|
+
process.env.NODE_ENV = "development";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const initLogger = FlinkLogFactory.createLogger("flink.init");
|
|
27
|
+
const { loaded, injected } = loadEnvFiles(parsed.dir, "development");
|
|
28
|
+
|
|
29
|
+
if (loaded.length > 0) {
|
|
30
|
+
initLogger.info(`Loaded env files: ${loaded.join(", ")} (${injected} vars injected)`);
|
|
31
|
+
}
|
|
32
|
+
|
|
19
33
|
if (hasFlag(parsed, "help")) {
|
|
20
34
|
printHelp({
|
|
21
35
|
description:
|
|
@@ -181,15 +195,24 @@ function startTscWatch(dir: string): ChildProcess {
|
|
|
181
195
|
|
|
182
196
|
if (!trimmed) continue;
|
|
183
197
|
|
|
184
|
-
|
|
198
|
+
// Filter out noisy watch-mode status lines
|
|
199
|
+
if (
|
|
200
|
+
trimmed.includes("Starting compilation") ||
|
|
201
|
+
trimmed.includes("File change detected") ||
|
|
202
|
+
trimmed.match(/^\[\d+:\d+:\d+\s+[AP]M\] Watching for file changes/)
|
|
203
|
+
) {
|
|
185
204
|
continue;
|
|
186
205
|
}
|
|
187
206
|
|
|
188
207
|
if (trimmed.includes("Found 0 errors")) {
|
|
189
208
|
console.log(`[tsc] ✓ No type errors`);
|
|
190
|
-
} else if (trimmed.
|
|
191
|
-
|
|
192
|
-
|
|
209
|
+
} else if (trimmed.match(/Found \d+ errors?/)) {
|
|
210
|
+
// Pretty-print the error count summary
|
|
211
|
+
const match = trimmed.match(/Found (\d+) errors?/);
|
|
212
|
+
const count = match?.[1];
|
|
213
|
+
console.log(`[tsc] ❌ Found ${count} type error${count === "1" ? "" : "s"} — see details above`);
|
|
214
|
+
} else {
|
|
215
|
+
// Show everything else: error details, file paths, code context, etc.
|
|
193
216
|
console.log(`[tsc] ${trimmed}`);
|
|
194
217
|
}
|
|
195
218
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "fs";
|
|
2
|
+
import { resolve, join } from "path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Parse the contents of a .env file into a key/value map.
|
|
6
|
+
*
|
|
7
|
+
* Rules:
|
|
8
|
+
* - Empty lines and lines starting with # are skipped
|
|
9
|
+
* - "export FOO=bar" is treated the same as "FOO=bar"
|
|
10
|
+
* - Quoted values (single or double) are unquoted, and their content is used as-is
|
|
11
|
+
* - Unquoted values have inline comments stripped: FOO=bar # comment → "bar"
|
|
12
|
+
*/
|
|
13
|
+
export function parseEnvContent(content: string): Record<string, string> {
|
|
14
|
+
const result: Record<string, string> = {};
|
|
15
|
+
|
|
16
|
+
for (const rawLine of content.split("\n")) {
|
|
17
|
+
let line = rawLine.trim();
|
|
18
|
+
|
|
19
|
+
// Skip empty lines and full-line comments
|
|
20
|
+
if (!line || line.startsWith("#")) continue;
|
|
21
|
+
|
|
22
|
+
// Strip "export " prefix
|
|
23
|
+
if (line.startsWith("export ")) {
|
|
24
|
+
line = line.slice(7).trim();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const eqIdx = line.indexOf("=");
|
|
28
|
+
if (eqIdx === -1) continue;
|
|
29
|
+
|
|
30
|
+
const key = line.slice(0, eqIdx).trim();
|
|
31
|
+
if (!key) continue;
|
|
32
|
+
|
|
33
|
+
let value = line.slice(eqIdx + 1);
|
|
34
|
+
|
|
35
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
36
|
+
// Quoted value — strip quotes, preserve content as-is
|
|
37
|
+
value = value.slice(1, -1);
|
|
38
|
+
} else {
|
|
39
|
+
// Unquoted — strip inline comments (" # ...") and trim
|
|
40
|
+
const commentIdx = value.search(/ #/);
|
|
41
|
+
if (commentIdx !== -1) {
|
|
42
|
+
value = value.slice(0, commentIdx);
|
|
43
|
+
}
|
|
44
|
+
value = value.trim();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
result[key] = value;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function readEnvFile(filepath: string): Record<string, string> | null {
|
|
54
|
+
if (!existsSync(filepath)) return null;
|
|
55
|
+
try {
|
|
56
|
+
return parseEnvContent(readFileSync(filepath, "utf-8"));
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface LoadEnvFilesResult {
|
|
63
|
+
/** Relative filenames that were found and loaded, in load order */
|
|
64
|
+
loaded: string[];
|
|
65
|
+
/** Number of variables injected into process.env (excludes already-set vars) */
|
|
66
|
+
injected: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Load .env files in Next.js-compatible order.
|
|
71
|
+
*
|
|
72
|
+
* Priority (highest wins):
|
|
73
|
+
* 1. process.env (already-set variables are never overridden)
|
|
74
|
+
* 2. .env.[environment].local
|
|
75
|
+
* 3. .env.local (skipped when environment === "test")
|
|
76
|
+
* 4. .env.[environment]
|
|
77
|
+
* 5. .env
|
|
78
|
+
*
|
|
79
|
+
* @param dir Root directory of the Flink app (where .env files live)
|
|
80
|
+
* @param environment "development" | "production" | "test"
|
|
81
|
+
*/
|
|
82
|
+
export function loadEnvFiles(dir: string, environment: "development" | "production" | "test"): LoadEnvFilesResult {
|
|
83
|
+
const absoluteDir = resolve(dir);
|
|
84
|
+
|
|
85
|
+
// Files listed from lowest to highest priority so that Object.assign
|
|
86
|
+
// naturally lets later files override earlier ones.
|
|
87
|
+
const candidates: string[] = [
|
|
88
|
+
".env",
|
|
89
|
+
`.env.${environment}`,
|
|
90
|
+
// .env.local is intentionally skipped in test (matches Next.js behaviour)
|
|
91
|
+
...(environment !== "test" ? [".env.local"] : []),
|
|
92
|
+
`.env.${environment}.local`,
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
const loaded: string[] = [];
|
|
96
|
+
const merged: Record<string, string> = {};
|
|
97
|
+
|
|
98
|
+
for (const filename of candidates) {
|
|
99
|
+
const parsed = readEnvFile(join(absoluteDir, filename));
|
|
100
|
+
if (parsed !== null) {
|
|
101
|
+
loaded.push(filename);
|
|
102
|
+
Object.assign(merged, parsed);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Inject into process.env — existing values always win
|
|
107
|
+
let injected = 0;
|
|
108
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
109
|
+
if (!(key in process.env)) {
|
|
110
|
+
process.env[key] = value;
|
|
111
|
+
injected++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return { loaded, injected };
|
|
116
|
+
}
|
package/cli/run.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { parseArgs, hasFlag, getOption, normalizeEntry, printHelp, compile, forkApp } from "./cli-utils";
|
|
3
3
|
import { FlinkLogFactory } from "../src/FlinkLogFactory";
|
|
4
4
|
import { loadFlinkConfig } from "../src/utils/loadFlinkConfig";
|
|
5
|
+
import { loadEnvFiles } from "./loadEnvFiles";
|
|
5
6
|
|
|
6
7
|
// Load config BEFORE creating logger
|
|
7
8
|
const flinkConfig = loadFlinkConfig();
|
|
@@ -10,6 +11,19 @@ FlinkLogFactory.configure(flinkConfig?.logging);
|
|
|
10
11
|
module.exports = async function run(args: string[]) {
|
|
11
12
|
const parsed = parseArgs(args);
|
|
12
13
|
|
|
14
|
+
// Load .env files before anything else so all env vars are available at startup.
|
|
15
|
+
// NODE_ENV defaults to "production" when not explicitly set.
|
|
16
|
+
if (!process.env.NODE_ENV) {
|
|
17
|
+
process.env.NODE_ENV = "production";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const initLogger = FlinkLogFactory.createLogger("flink.init");
|
|
21
|
+
const { loaded, injected } = loadEnvFiles(parsed.dir, "production");
|
|
22
|
+
|
|
23
|
+
if (loaded.length > 0) {
|
|
24
|
+
initLogger.info(`Loaded env files: ${loaded.join(", ")} (${injected} vars injected)`);
|
|
25
|
+
}
|
|
26
|
+
|
|
13
27
|
if (hasFlag(parsed, "help")) {
|
|
14
28
|
printHelp({
|
|
15
29
|
description: "Compiles and starts the application.",
|
package/dist/cli/cli-utils.js
CHANGED
|
@@ -125,17 +125,20 @@ function compile(opts) {
|
|
|
125
125
|
return [4 /*yield*/, compiler.parseJobs()];
|
|
126
126
|
case 5:
|
|
127
127
|
_c.sent();
|
|
128
|
-
return [4 /*yield*/, compiler.
|
|
128
|
+
return [4 /*yield*/, compiler.parseAllExtensionDirs()];
|
|
129
129
|
case 6:
|
|
130
130
|
_c.sent();
|
|
131
|
-
return [4 /*yield*/, compiler.
|
|
131
|
+
return [4 /*yield*/, compiler.parseHandlers()];
|
|
132
132
|
case 7:
|
|
133
133
|
_c.sent();
|
|
134
|
-
return [4 /*yield*/, compiler.
|
|
134
|
+
return [4 /*yield*/, compiler.generateStartScript(entry)];
|
|
135
135
|
case 8:
|
|
136
136
|
_c.sent();
|
|
137
|
-
return [4 /*yield*/, compiler.
|
|
137
|
+
return [4 /*yield*/, compiler.generateAllSchemas()];
|
|
138
138
|
case 9:
|
|
139
|
+
_c.sent();
|
|
140
|
+
return [4 /*yield*/, compiler.saveAllModifiedFiles()];
|
|
141
|
+
case 10:
|
|
139
142
|
_c.sent();
|
|
140
143
|
if (typeCheck) {
|
|
141
144
|
stepStart = Date.now();
|
|
@@ -145,14 +148,14 @@ function compile(opts) {
|
|
|
145
148
|
time("Type checking (getPreEmitDiagnostics)", stepStart);
|
|
146
149
|
}
|
|
147
150
|
stepStart = Date.now();
|
|
148
|
-
if (!(process.env.FLINK_USE_TSC === "true")) return [3 /*break*/,
|
|
151
|
+
if (!(process.env.FLINK_USE_TSC === "true")) return [3 /*break*/, 11];
|
|
149
152
|
compiler.emitWithTsc();
|
|
150
|
-
return [3 /*break*/,
|
|
151
|
-
case
|
|
152
|
-
case 11:
|
|
153
|
-
_c.sent();
|
|
154
|
-
_c.label = 12;
|
|
153
|
+
return [3 /*break*/, 13];
|
|
154
|
+
case 11: return [4 /*yield*/, compiler.emit()];
|
|
155
155
|
case 12:
|
|
156
|
+
_c.sent();
|
|
157
|
+
_c.label = 13;
|
|
158
|
+
case 13:
|
|
156
159
|
time("Transpilation (".concat(process.env.FLINK_USE_TSC === "true" ? "tsc" : "swc", ")"), stepStart);
|
|
157
160
|
if (timingLogs) {
|
|
158
161
|
console.log("Compilation done in ".concat(Date.now() - start, "ms"));
|
package/dist/cli/dev.js
CHANGED
|
@@ -47,18 +47,29 @@ var fs_1 = require("fs");
|
|
|
47
47
|
var cli_utils_1 = require("./cli-utils");
|
|
48
48
|
var FlinkLogFactory_1 = require("../src/FlinkLogFactory");
|
|
49
49
|
var loadFlinkConfig_1 = require("../src/utils/loadFlinkConfig");
|
|
50
|
+
var loadEnvFiles_1 = require("./loadEnvFiles");
|
|
50
51
|
// Load config BEFORE creating logger
|
|
51
52
|
var flinkConfig = (0, loadFlinkConfig_1.loadFlinkConfig)();
|
|
52
53
|
FlinkLogFactory_1.FlinkLogFactory.configure(flinkConfig === null || flinkConfig === void 0 ? void 0 : flinkConfig.logging);
|
|
53
54
|
var logger = FlinkLogFactory_1.FlinkLogFactory.createLogger("flink.dev");
|
|
54
55
|
module.exports = function dev(args) {
|
|
55
56
|
return __awaiter(this, void 0, void 0, function () {
|
|
56
|
-
var parsed, dir, entry, typecheck, noTypecheck, serverProcess, tscProcess, isRebuilding, pendingRebuild, watcher;
|
|
57
|
+
var parsed, initLogger, _a, loaded, injected, dir, entry, typecheck, noTypecheck, serverProcess, tscProcess, isRebuilding, pendingRebuild, watcher;
|
|
57
58
|
var _this = this;
|
|
58
|
-
return __generator(this, function (
|
|
59
|
-
switch (
|
|
59
|
+
return __generator(this, function (_b) {
|
|
60
|
+
switch (_b.label) {
|
|
60
61
|
case 0:
|
|
61
62
|
parsed = (0, cli_utils_1.parseArgs)(args);
|
|
63
|
+
// Load .env files before anything else so all env vars are available at startup.
|
|
64
|
+
// NODE_ENV defaults to "development" when not explicitly set.
|
|
65
|
+
if (!process.env.NODE_ENV) {
|
|
66
|
+
process.env.NODE_ENV = "development";
|
|
67
|
+
}
|
|
68
|
+
initLogger = FlinkLogFactory_1.FlinkLogFactory.createLogger("flink.init");
|
|
69
|
+
_a = (0, loadEnvFiles_1.loadEnvFiles)(parsed.dir, "development"), loaded = _a.loaded, injected = _a.injected;
|
|
70
|
+
if (loaded.length > 0) {
|
|
71
|
+
initLogger.info("Loaded env files: ".concat(loaded.join(", "), " (").concat(injected, " vars injected)"));
|
|
72
|
+
}
|
|
62
73
|
if ((0, cli_utils_1.hasFlag)(parsed, "help")) {
|
|
63
74
|
(0, cli_utils_1.printHelp)({
|
|
64
75
|
description: "Starts development mode with watch and auto-reload.\n Fast rebuilds with swc (skips type checking by default).\n Runs background tsc --watch for async type error reporting.",
|
|
@@ -81,7 +92,7 @@ module.exports = function dev(args) {
|
|
|
81
92
|
console.log("\uD83D\uDCE6 Initial build ".concat(typecheck ? "(with type checking)" : "(fast mode, skipping type check)", "..."));
|
|
82
93
|
return [4 /*yield*/, (0, cli_utils_1.compile)({ dir: dir, entry: entry, typeCheck: typecheck })];
|
|
83
94
|
case 1:
|
|
84
|
-
|
|
95
|
+
_b.sent();
|
|
85
96
|
serverProcess = null;
|
|
86
97
|
tscProcess = null;
|
|
87
98
|
isRebuilding = false;
|
|
@@ -215,16 +226,23 @@ function startTscWatch(dir) {
|
|
|
215
226
|
var trimmed = line.replace(/\x1Bc/g, "").trim();
|
|
216
227
|
if (!trimmed)
|
|
217
228
|
continue;
|
|
218
|
-
|
|
229
|
+
// Filter out noisy watch-mode status lines
|
|
230
|
+
if (trimmed.includes("Starting compilation") ||
|
|
231
|
+
trimmed.includes("File change detected") ||
|
|
232
|
+
trimmed.match(/^\[\d+:\d+:\d+\s+[AP]M\] Watching for file changes/)) {
|
|
219
233
|
continue;
|
|
220
234
|
}
|
|
221
235
|
if (trimmed.includes("Found 0 errors")) {
|
|
222
236
|
console.log("[tsc] \u2713 No type errors");
|
|
223
237
|
}
|
|
224
|
-
else if (trimmed.
|
|
225
|
-
|
|
238
|
+
else if (trimmed.match(/Found \d+ errors?/)) {
|
|
239
|
+
// Pretty-print the error count summary
|
|
240
|
+
var match = trimmed.match(/Found (\d+) errors?/);
|
|
241
|
+
var count = match === null || match === void 0 ? void 0 : match[1];
|
|
242
|
+
console.log("[tsc] \u274C Found ".concat(count, " type error").concat(count === "1" ? "" : "s", " \u2014 see details above"));
|
|
226
243
|
}
|
|
227
|
-
else
|
|
244
|
+
else {
|
|
245
|
+
// Show everything else: error details, file paths, code context, etc.
|
|
228
246
|
console.log("[tsc] ".concat(trimmed));
|
|
229
247
|
}
|
|
230
248
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse the contents of a .env file into a key/value map.
|
|
3
|
+
*
|
|
4
|
+
* Rules:
|
|
5
|
+
* - Empty lines and lines starting with # are skipped
|
|
6
|
+
* - "export FOO=bar" is treated the same as "FOO=bar"
|
|
7
|
+
* - Quoted values (single or double) are unquoted, and their content is used as-is
|
|
8
|
+
* - Unquoted values have inline comments stripped: FOO=bar # comment → "bar"
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseEnvContent(content: string): Record<string, string>;
|
|
11
|
+
export interface LoadEnvFilesResult {
|
|
12
|
+
/** Relative filenames that were found and loaded, in load order */
|
|
13
|
+
loaded: string[];
|
|
14
|
+
/** Number of variables injected into process.env (excludes already-set vars) */
|
|
15
|
+
injected: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Load .env files in Next.js-compatible order.
|
|
19
|
+
*
|
|
20
|
+
* Priority (highest wins):
|
|
21
|
+
* 1. process.env (already-set variables are never overridden)
|
|
22
|
+
* 2. .env.[environment].local
|
|
23
|
+
* 3. .env.local (skipped when environment === "test")
|
|
24
|
+
* 4. .env.[environment]
|
|
25
|
+
* 5. .env
|
|
26
|
+
*
|
|
27
|
+
* @param dir Root directory of the Flink app (where .env files live)
|
|
28
|
+
* @param environment "development" | "production" | "test"
|
|
29
|
+
*/
|
|
30
|
+
export declare function loadEnvFiles(dir: string, environment: "development" | "production" | "test"): LoadEnvFilesResult;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
3
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
4
|
+
if (ar || !(i in from)) {
|
|
5
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
6
|
+
ar[i] = from[i];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.parseEnvContent = parseEnvContent;
|
|
13
|
+
exports.loadEnvFiles = loadEnvFiles;
|
|
14
|
+
var fs_1 = require("fs");
|
|
15
|
+
var path_1 = require("path");
|
|
16
|
+
/**
|
|
17
|
+
* Parse the contents of a .env file into a key/value map.
|
|
18
|
+
*
|
|
19
|
+
* Rules:
|
|
20
|
+
* - Empty lines and lines starting with # are skipped
|
|
21
|
+
* - "export FOO=bar" is treated the same as "FOO=bar"
|
|
22
|
+
* - Quoted values (single or double) are unquoted, and their content is used as-is
|
|
23
|
+
* - Unquoted values have inline comments stripped: FOO=bar # comment → "bar"
|
|
24
|
+
*/
|
|
25
|
+
function parseEnvContent(content) {
|
|
26
|
+
var result = {};
|
|
27
|
+
for (var _i = 0, _a = content.split("\n"); _i < _a.length; _i++) {
|
|
28
|
+
var rawLine = _a[_i];
|
|
29
|
+
var line = rawLine.trim();
|
|
30
|
+
// Skip empty lines and full-line comments
|
|
31
|
+
if (!line || line.startsWith("#"))
|
|
32
|
+
continue;
|
|
33
|
+
// Strip "export " prefix
|
|
34
|
+
if (line.startsWith("export ")) {
|
|
35
|
+
line = line.slice(7).trim();
|
|
36
|
+
}
|
|
37
|
+
var eqIdx = line.indexOf("=");
|
|
38
|
+
if (eqIdx === -1)
|
|
39
|
+
continue;
|
|
40
|
+
var key = line.slice(0, eqIdx).trim();
|
|
41
|
+
if (!key)
|
|
42
|
+
continue;
|
|
43
|
+
var value = line.slice(eqIdx + 1);
|
|
44
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
45
|
+
// Quoted value — strip quotes, preserve content as-is
|
|
46
|
+
value = value.slice(1, -1);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Unquoted — strip inline comments (" # ...") and trim
|
|
50
|
+
var commentIdx = value.search(/ #/);
|
|
51
|
+
if (commentIdx !== -1) {
|
|
52
|
+
value = value.slice(0, commentIdx);
|
|
53
|
+
}
|
|
54
|
+
value = value.trim();
|
|
55
|
+
}
|
|
56
|
+
result[key] = value;
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
function readEnvFile(filepath) {
|
|
61
|
+
if (!(0, fs_1.existsSync)(filepath))
|
|
62
|
+
return null;
|
|
63
|
+
try {
|
|
64
|
+
return parseEnvContent((0, fs_1.readFileSync)(filepath, "utf-8"));
|
|
65
|
+
}
|
|
66
|
+
catch (_a) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Load .env files in Next.js-compatible order.
|
|
72
|
+
*
|
|
73
|
+
* Priority (highest wins):
|
|
74
|
+
* 1. process.env (already-set variables are never overridden)
|
|
75
|
+
* 2. .env.[environment].local
|
|
76
|
+
* 3. .env.local (skipped when environment === "test")
|
|
77
|
+
* 4. .env.[environment]
|
|
78
|
+
* 5. .env
|
|
79
|
+
*
|
|
80
|
+
* @param dir Root directory of the Flink app (where .env files live)
|
|
81
|
+
* @param environment "development" | "production" | "test"
|
|
82
|
+
*/
|
|
83
|
+
function loadEnvFiles(dir, environment) {
|
|
84
|
+
var absoluteDir = (0, path_1.resolve)(dir);
|
|
85
|
+
// Files listed from lowest to highest priority so that Object.assign
|
|
86
|
+
// naturally lets later files override earlier ones.
|
|
87
|
+
var candidates = __spreadArray(__spreadArray([
|
|
88
|
+
".env",
|
|
89
|
+
".env.".concat(environment)
|
|
90
|
+
], (environment !== "test" ? [".env.local"] : []), true), [
|
|
91
|
+
".env.".concat(environment, ".local"),
|
|
92
|
+
], false);
|
|
93
|
+
var loaded = [];
|
|
94
|
+
var merged = {};
|
|
95
|
+
for (var _i = 0, candidates_1 = candidates; _i < candidates_1.length; _i++) {
|
|
96
|
+
var filename = candidates_1[_i];
|
|
97
|
+
var parsed = readEnvFile((0, path_1.join)(absoluteDir, filename));
|
|
98
|
+
if (parsed !== null) {
|
|
99
|
+
loaded.push(filename);
|
|
100
|
+
Object.assign(merged, parsed);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Inject into process.env — existing values always win
|
|
104
|
+
var injected = 0;
|
|
105
|
+
for (var _a = 0, _b = Object.entries(merged); _a < _b.length; _a++) {
|
|
106
|
+
var _c = _b[_a], key = _c[0], value = _c[1];
|
|
107
|
+
if (!(key in process.env)) {
|
|
108
|
+
process.env[key] = value;
|
|
109
|
+
injected++;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return { loaded: loaded, injected: injected };
|
|
113
|
+
}
|
package/dist/cli/run.js
CHANGED
|
@@ -40,16 +40,27 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
40
40
|
var cli_utils_1 = require("./cli-utils");
|
|
41
41
|
var FlinkLogFactory_1 = require("../src/FlinkLogFactory");
|
|
42
42
|
var loadFlinkConfig_1 = require("../src/utils/loadFlinkConfig");
|
|
43
|
+
var loadEnvFiles_1 = require("./loadEnvFiles");
|
|
43
44
|
// Load config BEFORE creating logger
|
|
44
45
|
var flinkConfig = (0, loadFlinkConfig_1.loadFlinkConfig)();
|
|
45
46
|
FlinkLogFactory_1.FlinkLogFactory.configure(flinkConfig === null || flinkConfig === void 0 ? void 0 : flinkConfig.logging);
|
|
46
47
|
module.exports = function run(args) {
|
|
47
48
|
return __awaiter(this, void 0, void 0, function () {
|
|
48
|
-
var parsed, entry;
|
|
49
|
-
return __generator(this, function (
|
|
50
|
-
switch (
|
|
49
|
+
var parsed, initLogger, _a, loaded, injected, entry;
|
|
50
|
+
return __generator(this, function (_b) {
|
|
51
|
+
switch (_b.label) {
|
|
51
52
|
case 0:
|
|
52
53
|
parsed = (0, cli_utils_1.parseArgs)(args);
|
|
54
|
+
// Load .env files before anything else so all env vars are available at startup.
|
|
55
|
+
// NODE_ENV defaults to "production" when not explicitly set.
|
|
56
|
+
if (!process.env.NODE_ENV) {
|
|
57
|
+
process.env.NODE_ENV = "production";
|
|
58
|
+
}
|
|
59
|
+
initLogger = FlinkLogFactory_1.FlinkLogFactory.createLogger("flink.init");
|
|
60
|
+
_a = (0, loadEnvFiles_1.loadEnvFiles)(parsed.dir, "production"), loaded = _a.loaded, injected = _a.injected;
|
|
61
|
+
if (loaded.length > 0) {
|
|
62
|
+
initLogger.info("Loaded env files: ".concat(loaded.join(", "), " (").concat(injected, " vars injected)"));
|
|
63
|
+
}
|
|
53
64
|
if ((0, cli_utils_1.hasFlag)(parsed, "help")) {
|
|
54
65
|
(0, cli_utils_1.printHelp)({
|
|
55
66
|
description: "Compiles and starts the application.",
|
|
@@ -80,7 +91,7 @@ module.exports = function run(args) {
|
|
|
80
91
|
typeCheck: true,
|
|
81
92
|
})];
|
|
82
93
|
case 1:
|
|
83
|
-
|
|
94
|
+
_b.sent();
|
|
84
95
|
(0, cli_utils_1.forkApp)({
|
|
85
96
|
dir: parsed.dir,
|
|
86
97
|
args: args,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SourceFile } from "ts-morph";
|
|
2
|
+
import { FlinkCompilerPlugin } from "./utils/loadFlinkConfig";
|
|
2
3
|
declare class TypeScriptCompiler {
|
|
3
4
|
private cwd;
|
|
4
5
|
private project;
|
|
@@ -24,6 +25,14 @@ declare class TypeScriptCompiler {
|
|
|
24
25
|
* Tool ID registry for agent validation (built during segmentation)
|
|
25
26
|
*/
|
|
26
27
|
private toolIdRegistry;
|
|
28
|
+
/**
|
|
29
|
+
* Compiler plugins loaded from flink.config.js
|
|
30
|
+
*/
|
|
31
|
+
private compilerPlugins;
|
|
32
|
+
/**
|
|
33
|
+
* Extension files collected during segmentation, keyed by generatedFile name
|
|
34
|
+
*/
|
|
35
|
+
private extensionFiles;
|
|
27
36
|
/**
|
|
28
37
|
* Generates a schema $id from a file path and type name using the same algorithm
|
|
29
38
|
* as the schema generator's defineId callback.
|
|
@@ -206,5 +215,16 @@ declare class TypeScriptCompiler {
|
|
|
206
215
|
* Scans project for jobs so they can be registered during start.
|
|
207
216
|
*/
|
|
208
217
|
parseJobs(): Promise<SourceFile>;
|
|
218
|
+
/**
|
|
219
|
+
* Generates a .flink/generatedXxx.ts file for a single compiler plugin extension.
|
|
220
|
+
* Mirrors the same namespace-import + spread pattern used by parseJobs.
|
|
221
|
+
*/
|
|
222
|
+
parseExtensionDir(ext: FlinkCompilerPlugin): Promise<SourceFile>;
|
|
223
|
+
/**
|
|
224
|
+
* Iterates all compilerPlugins from flink.config.js and generates
|
|
225
|
+
* a .flink/generatedXxx.ts file for each one.
|
|
226
|
+
* Call this after parseJobs() and before generateStartScript().
|
|
227
|
+
*/
|
|
228
|
+
parseAllExtensionDirs(): Promise<void>;
|
|
209
229
|
}
|
|
210
230
|
export default TypeScriptCompiler;
|