@lunora/config 1.0.0-alpha.80 → 1.0.0-alpha.82
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/dist/index.mjs +1 -30
- package/dist/packem_shared/ACCENT-CLeV5v0K.mjs +7 -0
- package/dist/packem_shared/AGENT_MODE_ENV-B54hVQ_w.mjs +1 -0
- package/dist/packem_shared/AGENT_RULES_DIR-hP9TiDNx.mjs +1 -0
- package/dist/packem_shared/DEV_DAEMON_ENV-D9Z83rlU.mjs +4 -0
- package/dist/packem_shared/DEV_VARS_EXAMPLE_FILE-DX6xGbpr.mjs +1 -0
- package/dist/packem_shared/LINKED_PROJECT_DIR-CMzUvj-1.mjs +2 -0
- package/dist/packem_shared/LUNORA_CONFIG_FILE-3bpx6TZN.mjs +1 -0
- package/dist/packem_shared/LUNORA_EVENT_SOURCE-ZclWASXS.mjs +1 -0
- package/dist/packem_shared/LunoraReporter-BnXUqh8t.mjs +6 -0
- package/dist/packem_shared/PACKAGE_SECRETS_REGISTRY-BgmvEPA-.mjs +1 -0
- package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-CUYWD0Mh.mjs +1 -0
- package/dist/packem_shared/REMOTE_ELIGIBLE_KEYS-ws6iE0y-.mjs +1 -0
- package/dist/packem_shared/REQUIRED_COMPATIBILITY_DATE-DPcRuAhj.mjs +1 -0
- package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-CZ8rSh2k.mjs +1 -0
- package/dist/packem_shared/SEED_ENDPOINT-BaYShU8q.mjs +1 -0
- package/dist/packem_shared/WORKERS_CACHE_MIN_DATE-B1h_wNDN.mjs +1 -0
- package/dist/packem_shared/WRANGLER_FILES-Bi_18Pj6.mjs +1 -0
- package/dist/packem_shared/applyAdditiveEdit-BdcnSa-j.mjs +6 -0
- package/dist/packem_shared/assetContentType-DNZyUOuF.mjs +1 -0
- package/dist/packem_shared/buildPackageSecretsBlock-BpvaZzQ8.mjs +18 -0
- package/dist/packem_shared/classifyPolicyEdit-BzC_MfYK.mjs +24 -0
- package/dist/packem_shared/collectWranglerSecretVariables-OacEwPmL.mjs +1 -0
- package/dist/packem_shared/createConfirm-7IL0kZyE.mjs +7 -0
- package/dist/packem_shared/detectFramework-VTQfCNXy.mjs +1 -0
- package/dist/packem_shared/discoverAgentInfo-BJm0QtoI.mjs +1 -0
- package/dist/packem_shared/discoverContainerInfo-CYG9j2LY.mjs +1 -0
- package/dist/packem_shared/discoverSchemaInfo-B2W3VrcT.mjs +1 -0
- package/dist/packem_shared/discoverWorkflowInfo-Bbc0u2gE.mjs +1 -0
- package/dist/packem_shared/inferLunoraBindings-DWSabh1j.mjs +1 -0
- package/dist/packem_shared/jsonc-edit-BZVpxVA0.mjs +1 -0
- package/dist/packem_shared/parseDevVariable-NAVJ8tgA.mjs +1 -0
- package/dist/packem_shared/parseSchema-BPmtMgmb.mjs +1 -0
- package/dist/packem_shared/reconcileWranglerBindings-Dd3tLauZ.mjs +1 -0
- package/dist/packem_shared/reconcileWranglerCompatibilityDate-BXNiEQ7p.mjs +1 -0
- package/dist/packem_shared/reconcileWranglerCrons-BmQa_kGL.mjs +1 -0
- package/dist/packem_shared/renderStudioHtml-B2AkxcW1.mjs +15 -0
- package/dist/packem_shared/serveJsonHandler-C5GWlWJF.mjs +1 -0
- package/dist/packem_shared/streamContainerLogs-BPYBNrWS.mjs +2 -0
- package/dist/packem_shared/write-atomic-Cdr2oQb-.mjs +1 -0
- package/dist/studio-host/index.mjs +1 -7
- package/package.json +3 -3
- package/dist/packem_shared/ACCENT-DW1XJn8i.mjs +0 -40
- package/dist/packem_shared/AGENT_MODE_ENV-B5R7jpY7.mjs +0 -17
- package/dist/packem_shared/AGENT_RULES_DIR-lcgC08aE.mjs +0 -40
- package/dist/packem_shared/DEV_DAEMON_ENV-FIEtW7Fz.mjs +0 -163
- package/dist/packem_shared/DEV_VARS_EXAMPLE_FILE-dJPNTEnK.mjs +0 -37
- package/dist/packem_shared/LINKED_PROJECT_DIR-CXwXzV_C.mjs +0 -52
- package/dist/packem_shared/LUNORA_CONFIG_FILE-CtcIcB5-.mjs +0 -34
- package/dist/packem_shared/LUNORA_EVENT_SOURCE-M1KM9_pR.mjs +0 -112
- package/dist/packem_shared/LunoraReporter-Ci-bDCK9.mjs +0 -70
- package/dist/packem_shared/PACKAGE_SECRETS_REGISTRY-NCTSphDk.mjs +0 -138
- package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-CvTZpaZF.mjs +0 -100
- package/dist/packem_shared/REMOTE_ELIGIBLE_KEYS-C-F_Flgy.mjs +0 -100
- package/dist/packem_shared/REQUIRED_COMPATIBILITY_DATE-DP0SFVy9.mjs +0 -607
- package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-Bt2SNkpV.mjs +0 -95
- package/dist/packem_shared/SEED_ENDPOINT-7izz_Jao.mjs +0 -61
- package/dist/packem_shared/WORKERS_CACHE_MIN_DATE-CaXbS7CX.mjs +0 -11
- package/dist/packem_shared/WRANGLER_FILES-DwSuC-Kn.mjs +0 -25
- package/dist/packem_shared/applyAdditiveEdit-C-snTFEV.mjs +0 -228
- package/dist/packem_shared/assetContentType-ByZjeV3D.mjs +0 -72
- package/dist/packem_shared/buildPackageSecretsBlock-BxOcyaAY.mjs +0 -281
- package/dist/packem_shared/classifyPolicyEdit-BHeAqF8P.mjs +0 -99
- package/dist/packem_shared/collectWranglerSecretVariables-BRWIvT-e.mjs +0 -56
- package/dist/packem_shared/createConfirm-BMikeJC9.mjs +0 -117
- package/dist/packem_shared/detectFramework-U08038Yp.mjs +0 -41
- package/dist/packem_shared/discoverAgentInfo-eXA3hF4v.mjs +0 -19
- package/dist/packem_shared/discoverContainerInfo-BXFs6Wav.mjs +0 -19
- package/dist/packem_shared/discoverSchemaInfo-BB-CKlTK.mjs +0 -25
- package/dist/packem_shared/discoverWorkflowInfo-CedvR0mn.mjs +0 -19
- package/dist/packem_shared/inferLunoraBindings-BcvvtpSG.mjs +0 -397
- package/dist/packem_shared/jsonc-edit-SbcD7MAe.mjs +0 -9
- package/dist/packem_shared/parseDevVariable-B0FEvfHC.mjs +0 -21
- package/dist/packem_shared/parseSchema-DSeyktvG.mjs +0 -107
- package/dist/packem_shared/reconcileWranglerBindings-2Cww5VLa.mjs +0 -362
- package/dist/packem_shared/reconcileWranglerCompatibilityDate-C8c497ag.mjs +0 -31
- package/dist/packem_shared/reconcileWranglerCrons-DvsceVFz.mjs +0 -29
- package/dist/packem_shared/renderStudioHtml-449Ysn75.mjs +0 -37
- package/dist/packem_shared/serveJsonHandler-Cl2Wqkv8.mjs +0 -86
- package/dist/packem_shared/streamContainerLogs-BZ4cOZwH.mjs +0 -157
- package/dist/packem_shared/write-atomic-B2REqapi.mjs +0 -14
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
|
|
4
|
-
const AGENT_RULES_DIR = ".agents/skills";
|
|
5
|
-
const AGENT_RULES_HINT_ENV = "LUNORA_RULES_HINT_SHOWN";
|
|
6
|
-
const LUNORA_SKILL_NAMES = [
|
|
7
|
-
"lunora",
|
|
8
|
-
"lunora-quickstart",
|
|
9
|
-
"lunora-functions",
|
|
10
|
-
"lunora-realtime",
|
|
11
|
-
"lunora-setup-auth",
|
|
12
|
-
"lunora-create-package",
|
|
13
|
-
"lunora-migration-helper",
|
|
14
|
-
"lunora-deploy",
|
|
15
|
-
"lunora-performance-audit"
|
|
16
|
-
];
|
|
17
|
-
const ROOT_SKILL_NAME = "lunora";
|
|
18
|
-
const AGENT_RULES_HINT = "Lunora AI rules not installed — run `lunora rules install` so your coding agent knows how to use Lunora.";
|
|
19
|
-
const claimAgentRulesHint = () => {
|
|
20
|
-
if (process.env[AGENT_RULES_HINT_ENV] === "1") {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
process.env[AGENT_RULES_HINT_ENV] = "1";
|
|
24
|
-
return true;
|
|
25
|
-
};
|
|
26
|
-
const skillFile = (projectRoot, name) => join(projectRoot, AGENT_RULES_DIR, name, "SKILL.md");
|
|
27
|
-
const detectAgentRules = (projectRoot) => {
|
|
28
|
-
const present = [];
|
|
29
|
-
const missing = [];
|
|
30
|
-
for (const name of LUNORA_SKILL_NAMES) {
|
|
31
|
-
if (existsSync(skillFile(projectRoot, name))) {
|
|
32
|
-
present.push(name);
|
|
33
|
-
} else {
|
|
34
|
-
missing.push(name);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return { installed: existsSync(skillFile(projectRoot, ROOT_SKILL_NAME)), missing, present };
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export { AGENT_RULES_DIR, AGENT_RULES_HINT, AGENT_RULES_HINT_ENV, LUNORA_SKILL_NAMES, ROOT_SKILL_NAME, claimAgentRulesHint, detectAgentRules };
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync, rmSync, existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
|
|
4
|
-
const DEV_STATE_DIR = ".lunora";
|
|
5
|
-
const DEV_STATE_FILE = join(DEV_STATE_DIR, "dev.json");
|
|
6
|
-
const DEV_LOG_FILE = join(DEV_STATE_DIR, "dev.log");
|
|
7
|
-
const DEV_DAEMON_ENV = "LUNORA_DEV_DAEMON";
|
|
8
|
-
const DEV_LOG_FILE_ENV = "LUNORA_DEV_LOG_FILE";
|
|
9
|
-
const DEV_HANDOFF_ENV = "LUNORA_DEV_HANDOFF_PID";
|
|
10
|
-
const isObject = (value) => value !== null && typeof value === "object";
|
|
11
|
-
const stringField = (record, key) => {
|
|
12
|
-
const value = record[key];
|
|
13
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
14
|
-
};
|
|
15
|
-
const isProcessAlive = (pid) => {
|
|
16
|
-
if (!Number.isInteger(pid) || pid <= 0) {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
try {
|
|
20
|
-
process.kill(pid, 0);
|
|
21
|
-
return true;
|
|
22
|
-
} catch {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
const START_TIME_SKEW_MS = 1e4;
|
|
27
|
-
const LINUX_CLOCK_TICKS_PER_SECOND = 100;
|
|
28
|
-
const processStartTimeMs = (pid) => {
|
|
29
|
-
if (process.platform !== "linux") {
|
|
30
|
-
return void 0;
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
|
-
const stat = readFileSync(`/proc/${String(pid)}/stat`, "utf8");
|
|
34
|
-
const fields = stat.slice(stat.lastIndexOf(")") + 2).split(" ");
|
|
35
|
-
const startTicks = Number(fields[19]);
|
|
36
|
-
const bootLine = readFileSync("/proc/stat", "utf8").split("\n").find((line) => line.startsWith("btime "));
|
|
37
|
-
const bootSeconds = Number(bootLine?.slice("btime ".length));
|
|
38
|
-
if (!Number.isFinite(startTicks) || !Number.isFinite(bootSeconds)) {
|
|
39
|
-
return void 0;
|
|
40
|
-
}
|
|
41
|
-
return bootSeconds * 1e3 + startTicks / LINUX_CLOCK_TICKS_PER_SECOND * 1e3;
|
|
42
|
-
} catch {
|
|
43
|
-
return void 0;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
const isRecordedProcessCurrent = (state) => {
|
|
47
|
-
if (!isProcessAlive(state.pid)) {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
const recordedAtMs = state.startedAt === void 0 ? Number.NaN : Date.parse(state.startedAt);
|
|
51
|
-
if (Number.isNaN(recordedAtMs)) {
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
const actualStartMs = processStartTimeMs(state.pid);
|
|
55
|
-
return actualStartMs === void 0 || actualStartMs <= recordedAtMs + START_TIME_SKEW_MS;
|
|
56
|
-
};
|
|
57
|
-
const readDevServerState = (projectRoot) => {
|
|
58
|
-
const path = join(projectRoot, DEV_STATE_FILE);
|
|
59
|
-
if (!existsSync(path)) {
|
|
60
|
-
return void 0;
|
|
61
|
-
}
|
|
62
|
-
let parsed;
|
|
63
|
-
try {
|
|
64
|
-
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
65
|
-
} catch {
|
|
66
|
-
return void 0;
|
|
67
|
-
}
|
|
68
|
-
if (!isObject(parsed) || typeof parsed["pid"] !== "number") {
|
|
69
|
-
return void 0;
|
|
70
|
-
}
|
|
71
|
-
const url = stringField(parsed, "url");
|
|
72
|
-
if (url === void 0) {
|
|
73
|
-
return void 0;
|
|
74
|
-
}
|
|
75
|
-
return {
|
|
76
|
-
background: parsed["background"] === true,
|
|
77
|
-
logFile: stringField(parsed, "logFile"),
|
|
78
|
-
mode: parsed["mode"] === "vite" ? "vite" : "cli",
|
|
79
|
-
pid: parsed["pid"],
|
|
80
|
-
startedAt: stringField(parsed, "startedAt"),
|
|
81
|
-
studioUrl: stringField(parsed, "studioUrl"),
|
|
82
|
-
url
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
|
-
const writeDevServerState = (projectRoot, state) => {
|
|
86
|
-
try {
|
|
87
|
-
mkdirSync(join(projectRoot, DEV_STATE_DIR), { recursive: true });
|
|
88
|
-
const path = join(projectRoot, DEV_STATE_FILE);
|
|
89
|
-
writeFileSync(path, `${JSON.stringify(state, void 0, 2)}
|
|
90
|
-
`, "utf8");
|
|
91
|
-
return path;
|
|
92
|
-
} catch {
|
|
93
|
-
return void 0;
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
const updateDevServerState = (projectRoot, patch) => {
|
|
97
|
-
const existing = readDevServerState(projectRoot);
|
|
98
|
-
if (existing === void 0) {
|
|
99
|
-
return void 0;
|
|
100
|
-
}
|
|
101
|
-
const merged = { ...existing, ...patch };
|
|
102
|
-
writeDevServerState(projectRoot, merged);
|
|
103
|
-
return merged;
|
|
104
|
-
};
|
|
105
|
-
const clearDevServerState = (projectRoot, expectedPid) => {
|
|
106
|
-
try {
|
|
107
|
-
if (expectedPid !== void 0) {
|
|
108
|
-
const current = readDevServerState(projectRoot);
|
|
109
|
-
if (current !== void 0 && current.pid !== expectedPid) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
rmSync(join(projectRoot, DEV_STATE_FILE), { force: true });
|
|
114
|
-
} catch {
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
const readLiveDevServerState = (projectRoot) => {
|
|
118
|
-
const state = readDevServerState(projectRoot);
|
|
119
|
-
if (state === void 0) {
|
|
120
|
-
return void 0;
|
|
121
|
-
}
|
|
122
|
-
if (isRecordedProcessCurrent(state)) {
|
|
123
|
-
return state;
|
|
124
|
-
}
|
|
125
|
-
clearDevServerState(projectRoot, state.pid);
|
|
126
|
-
return void 0;
|
|
127
|
-
};
|
|
128
|
-
const resolveClaimConflict = (projectRoot, state, supersedePid) => {
|
|
129
|
-
const existing = readLiveDevServerState(projectRoot);
|
|
130
|
-
if (existing === void 0) {
|
|
131
|
-
return void 0;
|
|
132
|
-
}
|
|
133
|
-
if (supersedePid !== void 0 && existing.pid === supersedePid) {
|
|
134
|
-
return { ok: writeDevServerState(projectRoot, state) !== void 0 };
|
|
135
|
-
}
|
|
136
|
-
if (existing.pid !== state.pid) {
|
|
137
|
-
return { existing, ok: false };
|
|
138
|
-
}
|
|
139
|
-
return { ok: writeDevServerState(projectRoot, state) !== void 0 };
|
|
140
|
-
};
|
|
141
|
-
const claimDevServerState = (projectRoot, state, options) => {
|
|
142
|
-
const path = join(projectRoot, DEV_STATE_FILE);
|
|
143
|
-
const payload = `${JSON.stringify(state, void 0, 2)}
|
|
144
|
-
`;
|
|
145
|
-
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
146
|
-
try {
|
|
147
|
-
mkdirSync(join(projectRoot, DEV_STATE_DIR), { recursive: true });
|
|
148
|
-
writeFileSync(path, payload, { encoding: "utf8", flag: "wx" });
|
|
149
|
-
return { ok: true };
|
|
150
|
-
} catch (error) {
|
|
151
|
-
if (error.code !== "EEXIST") {
|
|
152
|
-
return { ok: writeDevServerState(projectRoot, state) !== void 0 };
|
|
153
|
-
}
|
|
154
|
-
const resolved = resolveClaimConflict(projectRoot, state, options?.supersedePid);
|
|
155
|
-
if (resolved !== void 0) {
|
|
156
|
-
return resolved;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return { ok: writeDevServerState(projectRoot, state) !== void 0 };
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
export { DEV_DAEMON_ENV, DEV_HANDOFF_ENV, DEV_LOG_FILE, DEV_LOG_FILE_ENV, DEV_STATE_DIR, DEV_STATE_FILE, claimDevServerState, clearDevServerState, isProcessAlive, isRecordedProcessCurrent, readDevServerState, readLiveDevServerState, updateDevServerState, writeDevServerState };
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
const DEV_VARS_FILE = ".dev.vars";
|
|
2
|
-
const DEV_VARS_EXAMPLE_FILE = ".dev.vars.example";
|
|
3
|
-
const DEV_VARS_KEY_PATTERN = /^[A-Za-z_]\w*$/u;
|
|
4
|
-
const DEV_VARS_NEWLINE = /\r?\n/u;
|
|
5
|
-
const unquoteDevVariable = (value) => {
|
|
6
|
-
if (value.length >= 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
7
|
-
return value.slice(1, -1);
|
|
8
|
-
}
|
|
9
|
-
return value;
|
|
10
|
-
};
|
|
11
|
-
const splitDevVariableLine = (line) => {
|
|
12
|
-
const trimmed = line.trim();
|
|
13
|
-
if (trimmed === "" || trimmed.startsWith("#")) {
|
|
14
|
-
return void 0;
|
|
15
|
-
}
|
|
16
|
-
const equals = trimmed.indexOf("=");
|
|
17
|
-
if (equals <= 0) {
|
|
18
|
-
return void 0;
|
|
19
|
-
}
|
|
20
|
-
const key = trimmed.slice(0, equals).trim();
|
|
21
|
-
if (!DEV_VARS_KEY_PATTERN.test(key)) {
|
|
22
|
-
return void 0;
|
|
23
|
-
}
|
|
24
|
-
return { key, value: trimmed.slice(equals + 1).trim() };
|
|
25
|
-
};
|
|
26
|
-
const parseDevVariableEntries = (content) => {
|
|
27
|
-
const entries = [];
|
|
28
|
-
for (const line of content.split(DEV_VARS_NEWLINE)) {
|
|
29
|
-
const parsed = splitDevVariableLine(line);
|
|
30
|
-
if (parsed) {
|
|
31
|
-
entries.push({ key: parsed.key, value: unquoteDevVariable(parsed.value) });
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return entries;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export { DEV_VARS_EXAMPLE_FILE, DEV_VARS_FILE, DEV_VARS_KEY_PATTERN, DEV_VARS_NEWLINE, parseDevVariableEntries, splitDevVariableLine, unquoteDevVariable };
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { parse } from 'jsonc-parser';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
|
|
5
|
-
const LINKED_PROJECT_DIR = ".lunora";
|
|
6
|
-
const LINKED_PROJECT_FILE = join(LINKED_PROJECT_DIR, "project.json");
|
|
7
|
-
const isObject = (value) => value !== null && typeof value === "object";
|
|
8
|
-
const stringField = (record, key) => {
|
|
9
|
-
const value = record[key];
|
|
10
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
11
|
-
};
|
|
12
|
-
const readLinkedProject = (projectRoot) => {
|
|
13
|
-
const path = join(projectRoot, LINKED_PROJECT_FILE);
|
|
14
|
-
if (!existsSync(path)) {
|
|
15
|
-
return void 0;
|
|
16
|
-
}
|
|
17
|
-
let text;
|
|
18
|
-
try {
|
|
19
|
-
text = readFileSync(path, "utf8");
|
|
20
|
-
} catch {
|
|
21
|
-
return void 0;
|
|
22
|
-
}
|
|
23
|
-
const parseErrors = [];
|
|
24
|
-
const parsed = parse(text, parseErrors, { allowTrailingComma: true });
|
|
25
|
-
if (parseErrors.length > 0 || !isObject(parsed)) {
|
|
26
|
-
return void 0;
|
|
27
|
-
}
|
|
28
|
-
return {
|
|
29
|
-
account: stringField(parsed, "account"),
|
|
30
|
-
env: stringField(parsed, "env"),
|
|
31
|
-
linkedAt: stringField(parsed, "linkedAt"),
|
|
32
|
-
workerName: stringField(parsed, "workerName"),
|
|
33
|
-
workerUrl: stringField(parsed, "workerUrl")
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
const writeLinkedProject = (projectRoot, link) => {
|
|
37
|
-
const directory = join(projectRoot, LINKED_PROJECT_DIR);
|
|
38
|
-
mkdirSync(directory, { recursive: true });
|
|
39
|
-
const record = {};
|
|
40
|
-
for (const key of ["account", "env", "linkedAt", "workerName", "workerUrl"]) {
|
|
41
|
-
const value = link[key];
|
|
42
|
-
if (value !== void 0 && value !== "") {
|
|
43
|
-
record[key] = value;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const path = join(projectRoot, LINKED_PROJECT_FILE);
|
|
47
|
-
writeFileSync(path, `${JSON.stringify(record, void 0, 2)}
|
|
48
|
-
`, "utf8");
|
|
49
|
-
return path;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export { LINKED_PROJECT_DIR, LINKED_PROJECT_FILE, readLinkedProject, writeLinkedProject };
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { parse } from 'jsonc-parser';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
|
|
5
|
-
const LUNORA_CONFIG_FILE = "lunora.json";
|
|
6
|
-
const interpretRemote = (value) => {
|
|
7
|
-
if (typeof value === "boolean") {
|
|
8
|
-
return value;
|
|
9
|
-
}
|
|
10
|
-
if (value !== null && typeof value === "object") {
|
|
11
|
-
return true;
|
|
12
|
-
}
|
|
13
|
-
return void 0;
|
|
14
|
-
};
|
|
15
|
-
const readProjectRemotePreference = (projectRoot) => {
|
|
16
|
-
const configPath = join(projectRoot, LUNORA_CONFIG_FILE);
|
|
17
|
-
if (!existsSync(configPath)) {
|
|
18
|
-
return void 0;
|
|
19
|
-
}
|
|
20
|
-
let text;
|
|
21
|
-
try {
|
|
22
|
-
text = readFileSync(configPath, "utf8");
|
|
23
|
-
} catch {
|
|
24
|
-
return void 0;
|
|
25
|
-
}
|
|
26
|
-
const parseErrors = [];
|
|
27
|
-
const parsed = parse(text, parseErrors, { allowTrailingComma: true });
|
|
28
|
-
if (parseErrors.length > 0 || parsed === null || typeof parsed !== "object") {
|
|
29
|
-
return void 0;
|
|
30
|
-
}
|
|
31
|
-
return interpretRemote(parsed.remote);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export { LUNORA_CONFIG_FILE, interpretRemote, readProjectRemotePreference };
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
const stringifyFieldValue = (value) => {
|
|
2
|
-
if (typeof value === "string") {
|
|
3
|
-
return value;
|
|
4
|
-
}
|
|
5
|
-
try {
|
|
6
|
-
return JSON.stringify(value) ?? String(value);
|
|
7
|
-
} catch {
|
|
8
|
-
return String(value);
|
|
9
|
-
}
|
|
10
|
-
};
|
|
11
|
-
const formatLogFields = (fields) => {
|
|
12
|
-
if (typeof fields !== "object" || fields === null || Array.isArray(fields)) {
|
|
13
|
-
return "";
|
|
14
|
-
}
|
|
15
|
-
return Object.entries(fields).map(([key, value]) => `${key}=${stringifyFieldValue(value)}`).join(" ");
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const LUNORA_EVENT_SOURCE = "lunora";
|
|
19
|
-
const ROOT_SHARD_NAME = "__root__";
|
|
20
|
-
const asString = (value) => typeof value === "string" ? value : "";
|
|
21
|
-
const asStringList = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
22
|
-
const formatDuration = (value) => typeof value === "number" && Number.isFinite(value) ? `${String(Math.round(value))}ms` : "?ms";
|
|
23
|
-
const toLineLevel = (rawLevel) => {
|
|
24
|
-
if (rawLevel === "error" || rawLevel === "fatal") {
|
|
25
|
-
return "error";
|
|
26
|
-
}
|
|
27
|
-
if (rawLevel === "warn") {
|
|
28
|
-
return "warn";
|
|
29
|
-
}
|
|
30
|
-
return "info";
|
|
31
|
-
};
|
|
32
|
-
const parseLunoraEvent = (line) => {
|
|
33
|
-
const trimmed = line.trim();
|
|
34
|
-
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
|
|
35
|
-
return void 0;
|
|
36
|
-
}
|
|
37
|
-
let parsed;
|
|
38
|
-
try {
|
|
39
|
-
parsed = JSON.parse(trimmed);
|
|
40
|
-
} catch {
|
|
41
|
-
return void 0;
|
|
42
|
-
}
|
|
43
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
44
|
-
return void 0;
|
|
45
|
-
}
|
|
46
|
-
const event = parsed;
|
|
47
|
-
return event.source === LUNORA_EVENT_SOURCE ? event : void 0;
|
|
48
|
-
};
|
|
49
|
-
const labelFor = (functionPath, event) => {
|
|
50
|
-
const shard = asString(event.shard);
|
|
51
|
-
return shard === "" || shard === ROOT_SHARD_NAME ? functionPath : `${functionPath}@${shard}`;
|
|
52
|
-
};
|
|
53
|
-
const formatRequest = (event, functionPath) => {
|
|
54
|
-
const failed = event.outcome === "error";
|
|
55
|
-
const parts = [labelFor(functionPath, event), failed ? "error" : "ok", formatDuration(event.durationMs)];
|
|
56
|
-
const read = asStringList(event.tablesRead);
|
|
57
|
-
const written = asStringList(event.tablesWritten);
|
|
58
|
-
if (read.length > 0) {
|
|
59
|
-
parts.push(`read[${read.join(",")}]`);
|
|
60
|
-
}
|
|
61
|
-
if (written.length > 0) {
|
|
62
|
-
parts.push(`write[${written.join(",")}]`);
|
|
63
|
-
}
|
|
64
|
-
if (event.cacheHit === true) {
|
|
65
|
-
parts.push("cached");
|
|
66
|
-
}
|
|
67
|
-
const errorMessage = asString(event.error);
|
|
68
|
-
if (failed && errorMessage !== "") {
|
|
69
|
-
parts.push(errorMessage);
|
|
70
|
-
}
|
|
71
|
-
return { kind: "rpc", level: failed ? "error" : "info", text: parts.join(" ") };
|
|
72
|
-
};
|
|
73
|
-
const formatContainer = (event) => {
|
|
74
|
-
const name = asString(event.container) || "<unknown>";
|
|
75
|
-
const instance = asString(event.instance);
|
|
76
|
-
const transition = asString(event.event) || "event";
|
|
77
|
-
const shortId = instance === "" || instance === "unknown" ? "" : `#${instance.slice(0, 8)}`;
|
|
78
|
-
const message = asString(event.message);
|
|
79
|
-
const parts = [`container:${name}${shortId}`, transition];
|
|
80
|
-
if (message !== "") {
|
|
81
|
-
parts.push(message);
|
|
82
|
-
}
|
|
83
|
-
return { kind: "log", level: event.event === "error" ? "error" : "info", text: parts.join(" ") };
|
|
84
|
-
};
|
|
85
|
-
const formatLunoraEvent = (line) => {
|
|
86
|
-
const event = parseLunoraEvent(line);
|
|
87
|
-
if (!event) {
|
|
88
|
-
return void 0;
|
|
89
|
-
}
|
|
90
|
-
const functionPath = asString(event.function) || "<unknown>";
|
|
91
|
-
if (event.type === "log") {
|
|
92
|
-
const parts = [`${labelFor(functionPath, event)} ${asString(event.message)}`.trimEnd()];
|
|
93
|
-
const fields = formatLogFields(event.fields);
|
|
94
|
-
if (fields !== "") {
|
|
95
|
-
parts.push(fields);
|
|
96
|
-
}
|
|
97
|
-
const traceId = asString(event.traceId);
|
|
98
|
-
if (traceId !== "") {
|
|
99
|
-
parts.push(`trace=${traceId.slice(0, 8)}`);
|
|
100
|
-
}
|
|
101
|
-
return { kind: "log", level: toLineLevel(asString(event.level)), text: parts.join(" ") };
|
|
102
|
-
}
|
|
103
|
-
if (event.type === "request") {
|
|
104
|
-
return formatRequest(event, functionPath);
|
|
105
|
-
}
|
|
106
|
-
if (event.type === "container") {
|
|
107
|
-
return formatContainer(event);
|
|
108
|
-
}
|
|
109
|
-
return void 0;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
export { LUNORA_EVENT_SOURCE, formatLunoraEvent };
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { paintBadge, badgeWidth, BADGES } from './ACCENT-DW1XJn8i.mjs';
|
|
2
|
-
|
|
3
|
-
const NAME_ALIASES = {
|
|
4
|
-
informational: "info",
|
|
5
|
-
warning: "warn"
|
|
6
|
-
};
|
|
7
|
-
const STDERR_LEVELS = /* @__PURE__ */ new Set(["alert", "critical", "emergency", "error", "warn", "warning"]);
|
|
8
|
-
const resolveBadge = (name) => {
|
|
9
|
-
if (name in BADGES) {
|
|
10
|
-
return BADGES[name];
|
|
11
|
-
}
|
|
12
|
-
const alias = NAME_ALIASES[name];
|
|
13
|
-
return alias === void 0 ? void 0 : BADGES[alias];
|
|
14
|
-
};
|
|
15
|
-
const renderContextArgument = (value) => {
|
|
16
|
-
if (value instanceof Error) {
|
|
17
|
-
return `
|
|
18
|
-
${value.stack ?? value.message}`;
|
|
19
|
-
}
|
|
20
|
-
if (typeof value === "object" && value !== null) {
|
|
21
|
-
try {
|
|
22
|
-
return ` ${JSON.stringify(value)}`;
|
|
23
|
-
} catch {
|
|
24
|
-
return " [unserializable]";
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return ` ${String(value)}`;
|
|
28
|
-
};
|
|
29
|
-
const composeMessage = (meta) => {
|
|
30
|
-
const base = typeof meta.message === "string" ? meta.message : String(meta.message);
|
|
31
|
-
const context = meta.context ?? [];
|
|
32
|
-
return context.length === 0 ? base : base + context.map((value) => renderContextArgument(value)).join("");
|
|
33
|
-
};
|
|
34
|
-
class LunoraReporter {
|
|
35
|
-
#stdout = process.stdout;
|
|
36
|
-
#stderr = process.stderr;
|
|
37
|
-
setStdout(stdout) {
|
|
38
|
-
this.#stdout = stdout;
|
|
39
|
-
}
|
|
40
|
-
setStderr(stderr) {
|
|
41
|
-
this.#stderr = stderr;
|
|
42
|
-
}
|
|
43
|
-
// Note: pail's other reporter setters (setLoggerTypes / setInteractiveManager /
|
|
44
|
-
// setIsInteractive) are optional and intentionally omitted — this reporter keeps
|
|
45
|
-
// no type or interactive state; it only needs the two stream setters above.
|
|
46
|
-
log(meta) {
|
|
47
|
-
const data = meta;
|
|
48
|
-
const badge = resolveBadge(data.type.name);
|
|
49
|
-
const stream = STDERR_LEVELS.has(data.type.level ?? data.type.name) ? this.#stderr : this.#stdout;
|
|
50
|
-
stream.write(LunoraReporter.#render(badge, composeMessage(data)));
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Frame `text` under `badge`: `<badge> <first line>`, with any further lines
|
|
54
|
-
* indented to align beneath the message. Without a badge (unknown type) the
|
|
55
|
-
* message is written plain.
|
|
56
|
-
*/
|
|
57
|
-
static #render(badge, text) {
|
|
58
|
-
if (badge === void 0) {
|
|
59
|
-
return `${text}
|
|
60
|
-
`;
|
|
61
|
-
}
|
|
62
|
-
const [first = "", ...rest] = text.split("\n");
|
|
63
|
-
const indent = " ".repeat(badgeWidth() + 1);
|
|
64
|
-
const lines = [`${paintBadge(badge)} ${first}`, ...rest.map((line) => `${indent}${line}`)];
|
|
65
|
-
return `${lines.join("\n")}
|
|
66
|
-
`;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export { LunoraReporter as default };
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
const CORE_SECRETS = [
|
|
2
|
-
{
|
|
3
|
-
description: "Bearer token the local Lunora Studio uses to call the worker's admin endpoints (data browser, schema edits) in dev. Generate with: openssl rand -hex 32",
|
|
4
|
-
docsUrl: "https://lunora.sh/docs/packages/studio",
|
|
5
|
-
key: "LUNORA_ADMIN_TOKEN",
|
|
6
|
-
placeholderValue: "replace-with-openssl-rand-hex-32"
|
|
7
|
-
}
|
|
8
|
-
];
|
|
9
|
-
const PACKAGE_SECRETS_REGISTRY = {
|
|
10
|
-
"@lunora/auth": [
|
|
11
|
-
{
|
|
12
|
-
description: "32-byte random secret used to sign sessions and tokens. Generate with: openssl rand -hex 32",
|
|
13
|
-
docsUrl: "https://lunora.sh/docs/packages/auth#secrets",
|
|
14
|
-
key: "AUTH_SECRET",
|
|
15
|
-
placeholderValue: "replace-with-openssl-rand-hex-32"
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
description: "Public base URL of your worker (used by better-auth for redirects and cookie domain). For local dev this is typically http://localhost:8787",
|
|
19
|
-
docsUrl: "https://lunora.sh/docs/packages/auth#secrets",
|
|
20
|
-
key: "AUTH_URL",
|
|
21
|
-
placeholderValue: "http://localhost:8787"
|
|
22
|
-
}
|
|
23
|
-
],
|
|
24
|
-
"@lunora/mail": [
|
|
25
|
-
{
|
|
26
|
-
description: "Resend API key for sending transactional email via @lunora/mail. Obtain at https://resend.com/api-keys",
|
|
27
|
-
docsUrl: "https://lunora.sh/docs/packages/mail#secrets",
|
|
28
|
-
key: "RESEND_API_KEY",
|
|
29
|
-
placeholderValue: "<your-resend-api-key>"
|
|
30
|
-
}
|
|
31
|
-
],
|
|
32
|
-
"@lunora/notify": [
|
|
33
|
-
{
|
|
34
|
-
description: "Public VAPID key (base64url) for Web Push. Generate a keypair once with: npx web-push generate-vapid-keys — the public key is also shipped to the browser to subscribe.",
|
|
35
|
-
docsUrl: "https://lunora.sh/docs/packages/notify#web-push",
|
|
36
|
-
key: "VAPID_PUBLIC_KEY",
|
|
37
|
-
placeholderValue: "<your-vapid-public-key>"
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
description: "Private VAPID key (base64url) for Web Push — the application-server signing key. Generate with: npx web-push generate-vapid-keys",
|
|
41
|
-
docsUrl: "https://lunora.sh/docs/packages/notify#web-push",
|
|
42
|
-
key: "VAPID_PRIVATE_KEY",
|
|
43
|
-
placeholderValue: "<your-vapid-private-key>"
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
description: "VAPID `sub` contact — a mailto: or https: URL identifying the application server (e.g. mailto:you@example.com).",
|
|
47
|
-
docsUrl: "https://lunora.sh/docs/packages/notify#web-push",
|
|
48
|
-
key: "VAPID_SUBJECT",
|
|
49
|
-
placeholderValue: "mailto:you@example.com"
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
description: "Firebase project id for FCM (HTTP v1) push. Found in the Firebase console project settings.",
|
|
53
|
-
docsUrl: "https://lunora.sh/docs/packages/notify#fcm",
|
|
54
|
-
key: "FCM_PROJECT_ID",
|
|
55
|
-
placeholderValue: "<your-firebase-project-id>"
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
description: "OAuth2 access token for FCM (HTTP v1). Convenient for dev but expires — in production supply a getAccessToken() in defineNotify instead. Obtain via the Google Cloud SDK / a service account.",
|
|
59
|
-
docsUrl: "https://lunora.sh/docs/packages/notify#fcm",
|
|
60
|
-
key: "FCM_ACCESS_TOKEN",
|
|
61
|
-
placeholderValue: "<your-fcm-access-token>"
|
|
62
|
-
}
|
|
63
|
-
],
|
|
64
|
-
"@lunora/payment": [
|
|
65
|
-
{
|
|
66
|
-
description: "Stripe secret key (sk_test_…). Required when using the Stripe adapter. Obtain at https://dashboard.stripe.com/apikeys",
|
|
67
|
-
docsUrl: "https://lunora.sh/docs/packages/payment#stripe",
|
|
68
|
-
key: "STRIPE_SECRET_KEY",
|
|
69
|
-
placeholderValue: "<your-stripe-secret-key>"
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
description: "Stripe webhook signing secret (whsec_…) for verifying event payloads. Obtain at https://dashboard.stripe.com/webhooks",
|
|
73
|
-
docsUrl: "https://lunora.sh/docs/packages/payment#stripe",
|
|
74
|
-
key: "STRIPE_WEBHOOK_SECRET",
|
|
75
|
-
placeholderValue: "<your-stripe-webhook-secret>"
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
description: "Polar access token for the Polar payment adapter. Obtain at https://polar.sh/settings/tokens",
|
|
79
|
-
docsUrl: "https://lunora.sh/docs/packages/payment#polar",
|
|
80
|
-
key: "POLAR_ACCESS_TOKEN",
|
|
81
|
-
placeholderValue: "<your-polar-access-token>"
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
description: "Polar webhook secret for verifying event payloads from Polar. Obtain at https://polar.sh/settings/webhooks",
|
|
85
|
-
docsUrl: "https://lunora.sh/docs/packages/payment#polar",
|
|
86
|
-
key: "POLAR_WEBHOOK_SECRET",
|
|
87
|
-
placeholderValue: "<your-polar-webhook-secret>"
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
description: "Autumn secret key (am_sk_…) for the Autumn payment adapter. Obtain at https://app.useautumn.com/dev",
|
|
91
|
-
docsUrl: "https://lunora.sh/docs/packages/payment#autumn",
|
|
92
|
-
key: "AUTUMN_SECRET_KEY",
|
|
93
|
-
placeholderValue: "<your-autumn-secret-key>"
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
description: "Autumn webhook signing secret for verifying Standard Webhooks event payloads. Obtain from your Autumn dashboard webhook settings.",
|
|
97
|
-
docsUrl: "https://lunora.sh/docs/packages/payment#autumn",
|
|
98
|
-
key: "AUTUMN_WEBHOOK_SECRET",
|
|
99
|
-
placeholderValue: "<your-autumn-webhook-secret>"
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
description: "Dodo Payments API key (bearer token) for the Dodo Payments adapter. Obtain at https://app.dodopayments.com/developer/api-keys",
|
|
103
|
-
docsUrl: "https://lunora.sh/docs/packages/payment#dodo-payments",
|
|
104
|
-
key: "DODO_PAYMENTS_API_KEY",
|
|
105
|
-
placeholderValue: "<your-dodo-payments-api-key>"
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
description: "Dodo Payments webhook signing secret (whsec_…) for verifying event payloads. Obtain at https://app.dodopayments.com/developer/webhooks",
|
|
109
|
-
docsUrl: "https://lunora.sh/docs/packages/payment#dodo-payments",
|
|
110
|
-
key: "DODO_PAYMENTS_WEBHOOK_KEY",
|
|
111
|
-
placeholderValue: "<your-dodo-payments-webhook-secret>"
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
description: "Creem API key for the Creem payment adapter. Obtain at https://www.creem.io/dashboard/developers",
|
|
115
|
-
docsUrl: "https://lunora.sh/docs/packages/payment#creem",
|
|
116
|
-
key: "CREEM_API_KEY",
|
|
117
|
-
placeholderValue: "<your-creem-api-key>"
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
description: "Creem webhook signing secret for verifying the creem-signature header. Obtain from your Creem dashboard webhook settings.",
|
|
121
|
-
docsUrl: "https://lunora.sh/docs/packages/payment#creem",
|
|
122
|
-
key: "CREEM_WEBHOOK_SECRET",
|
|
123
|
-
placeholderValue: "<your-creem-webhook-secret>"
|
|
124
|
-
}
|
|
125
|
-
]
|
|
126
|
-
};
|
|
127
|
-
const secretsForPackages = (packageNames) => {
|
|
128
|
-
const result = [];
|
|
129
|
-
for (const name of packageNames) {
|
|
130
|
-
const entries = PACKAGE_SECRETS_REGISTRY[name];
|
|
131
|
-
if (entries !== void 0) {
|
|
132
|
-
result.push(...entries);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return result;
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
export { CORE_SECRETS, PACKAGE_SECRETS_REGISTRY, secretsForPackages };
|