@koed-labs/server 0.0.0-stage → 0.10.3
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/LICENSE +201 -0
- package/README.md +64 -2
- package/bin/koed.js +7 -0
- package/package.json +26 -4
- package/third-party-notices.json +92 -0
- package/vendor/chunk-2BWTLF7A.js +13883 -0
- package/vendor/chunk-2DA7EFZV.js +924 -0
- package/vendor/chunk-2S3OGPUC.js +58 -0
- package/vendor/chunk-473OA62O.js +26827 -0
- package/vendor/chunk-6JRWGOQG.js +236 -0
- package/vendor/chunk-7NOQSX4T.js +14 -0
- package/vendor/chunk-7NXKPDF3.js +1586 -0
- package/vendor/chunk-A4NKL2PK.js +153 -0
- package/vendor/chunk-A6WMU2GG.js +48 -0
- package/vendor/chunk-AFLKCQHF.js +73 -0
- package/vendor/chunk-BTS4ZTF3.js +43 -0
- package/vendor/chunk-C3N4N5HR.js +108 -0
- package/vendor/chunk-DXTAWHY3.js +25 -0
- package/vendor/chunk-G4IIVVJO.js +56 -0
- package/vendor/chunk-GELDEJJ2.js +4337 -0
- package/vendor/chunk-HFM6ROJL.js +188 -0
- package/vendor/chunk-HK2H3MVE.js +328 -0
- package/vendor/chunk-HZJK5RWC.js +5088 -0
- package/vendor/chunk-J2L726BC.js +2497 -0
- package/vendor/chunk-JBGD4JLR.js +3779 -0
- package/vendor/chunk-JJNLH5GA.js +2470 -0
- package/vendor/chunk-JKOG52PE.js +128 -0
- package/vendor/chunk-K2EIFEQF.js +89 -0
- package/vendor/chunk-KUIWH33N.js +16 -0
- package/vendor/chunk-NEWIOOM6.js +34 -0
- package/vendor/chunk-NM5NXCVM.js +2404 -0
- package/vendor/chunk-PT3AUPGE.js +459 -0
- package/vendor/chunk-PY5LYLV7.js +143 -0
- package/vendor/chunk-QIIKMG3M.js +103 -0
- package/vendor/chunk-QT24SAW6.js +110 -0
- package/vendor/chunk-RVYJKKWA.js +22 -0
- package/vendor/chunk-SKVYP7NY.js +1647 -0
- package/vendor/chunk-TSRPHKAC.js +780 -0
- package/vendor/chunk-UI5RLBKQ.js +30 -0
- package/vendor/chunk-VPC5NLZG.js +259 -0
- package/vendor/chunk-W2HNI6AA.js +75 -0
- package/vendor/chunk-X6M525ZJ.js +20 -0
- package/vendor/chunk-XIZVLPHZ.js +18 -0
- package/vendor/chunk-XNFVSVBS.js +242 -0
- package/vendor/chunk-YCDEMYY6.js +2076 -0
- package/vendor/chunk-YJ6XUZT6.js +292 -0
- package/vendor/chunk-YJWREXN6.js +26020 -0
- package/vendor/chunk-YK4F4VY2.js +173 -0
- package/vendor/chunk-YOFI4PCH.js +36 -0
- package/vendor/chunk-ZUGNCQZE.js +247 -0
- package/vendor/chunk-ZXX4ZNJY.js +21 -0
- package/vendor/cli.js +7 -0
- package/vendor/component-manifest-catalog.js +8 -0
- package/vendor/control-plane.js +23 -0
- package/vendor/package.json +1 -0
- package/vendor/privacy-service-bootstrap.js +6 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createRequire as createKoedRequire } from "node:module"; const require = createKoedRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// packages/koed-server/dist/runtime-artifact-source.js
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
var runtimeProcess = process;
|
|
6
|
+
var trimRuntimeValue = (value) => {
|
|
7
|
+
const trimmed = value?.trim();
|
|
8
|
+
return trimmed ? trimmed : void 0;
|
|
9
|
+
};
|
|
10
|
+
var isPackagedRuntimeMode = (environment = process.env) => environment.KOED_PACKAGED_DESKTOP === "1";
|
|
11
|
+
var allowsPackagedSourceFallback = (environment = process.env) => environment.KOED_ALLOW_PACKAGED_SOURCE_FALLBACK === "1";
|
|
12
|
+
var canUseSourceCheckoutFallback = (environment = process.env) => !isPackagedRuntimeMode(environment) || allowsPackagedSourceFallback(environment);
|
|
13
|
+
var resolvePackagedResourcesPath = (environment = process.env) => {
|
|
14
|
+
const explicit = trimRuntimeValue(environment.KOED_PACKAGED_RESOURCES_PATH);
|
|
15
|
+
if (explicit) {
|
|
16
|
+
return resolve(explicit);
|
|
17
|
+
}
|
|
18
|
+
return runtimeProcess.resourcesPath ? resolve(runtimeProcess.resourcesPath) : void 0;
|
|
19
|
+
};
|
|
20
|
+
var resolvePackagedKoedRuntimeRoot = (environment = process.env) => {
|
|
21
|
+
const resourcesPath = resolvePackagedResourcesPath(environment);
|
|
22
|
+
return resourcesPath ? resolve(resourcesPath, "koed-runtime") : void 0;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
isPackagedRuntimeMode,
|
|
27
|
+
canUseSourceCheckoutFallback,
|
|
28
|
+
resolvePackagedResourcesPath,
|
|
29
|
+
resolvePackagedKoedRuntimeRoot
|
|
30
|
+
};
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { createRequire as createKoedRequire } from "node:module"; const require = createKoedRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
PINNED_PRIVACY_MODEL_FILES,
|
|
4
|
+
PINNED_PRIVACY_MODEL_ID,
|
|
5
|
+
PINNED_PRIVACY_MODEL_REVISION
|
|
6
|
+
} from "./chunk-473OA62O.js";
|
|
7
|
+
|
|
8
|
+
// packages/koed-server/dist/privacy-model-runtime.js
|
|
9
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
10
|
+
import { createReadStream, createWriteStream, existsSync, linkSync, lstatSync, mkdirSync, renameSync, rmSync, statSync } from "node:fs";
|
|
11
|
+
import { dirname, resolve } from "node:path";
|
|
12
|
+
import { Readable, Transform } from "node:stream";
|
|
13
|
+
import { pipeline } from "node:stream/promises";
|
|
14
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
15
|
+
var PRIVACY_MODEL_ID = PINNED_PRIVACY_MODEL_ID;
|
|
16
|
+
var PRIVACY_MODEL_REVISION = PINNED_PRIVACY_MODEL_REVISION;
|
|
17
|
+
var PRIVACY_MODEL_FILES = PINNED_PRIVACY_MODEL_FILES;
|
|
18
|
+
var resolvePrivacyModelPaths = (paths) => ({
|
|
19
|
+
blobsDir: resolve(paths.modelsDir, "privacy", "blobs", "sha256"),
|
|
20
|
+
cacheDir: resolve(paths.modelsDir, "privacy", "transformers-cache")
|
|
21
|
+
});
|
|
22
|
+
var cachePath = (paths, file) => resolve(paths.cacheDir, PRIVACY_MODEL_ID, PRIVACY_MODEL_REVISION, file.path);
|
|
23
|
+
var blobPath = (paths, file) => resolve(paths.blobsDir, file.sha256);
|
|
24
|
+
var isSameFile = (left, right) => {
|
|
25
|
+
try {
|
|
26
|
+
const leftStat = statSync(left);
|
|
27
|
+
const rightStat = lstatSync(right);
|
|
28
|
+
return rightStat.isFile() && leftStat.dev === rightStat.dev && leftStat.ino === rightStat.ino;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error.code === "ENOENT")
|
|
31
|
+
return false;
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var materializePrivacyModelCacheEntry = (blob, target) => {
|
|
36
|
+
if (isSameFile(blob, target))
|
|
37
|
+
return;
|
|
38
|
+
rmSync(target, { force: true });
|
|
39
|
+
try {
|
|
40
|
+
linkSync(blob, target);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error.code === "EEXIST" && isSameFile(blob, target)) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var sha256File = async (path, signal) => {
|
|
49
|
+
const hash = createHash("sha256");
|
|
50
|
+
await pipeline(createReadStream(path), hash, signal ? { signal } : {});
|
|
51
|
+
return hash.digest("hex");
|
|
52
|
+
};
|
|
53
|
+
var materializeCacheEntry = (paths, file) => {
|
|
54
|
+
const target = cachePath(paths, file);
|
|
55
|
+
mkdirSync(dirname(target), { recursive: true, mode: 448 });
|
|
56
|
+
materializePrivacyModelCacheEntry(blobPath(paths, file), target);
|
|
57
|
+
};
|
|
58
|
+
var retryableTransferError = (error) => {
|
|
59
|
+
if (error instanceof TypeError)
|
|
60
|
+
return true;
|
|
61
|
+
const code = error?.code;
|
|
62
|
+
return [
|
|
63
|
+
"ECONNRESET",
|
|
64
|
+
"ECONNREFUSED",
|
|
65
|
+
"ETIMEDOUT",
|
|
66
|
+
"EAI_AGAIN",
|
|
67
|
+
"UND_ERR_SOCKET",
|
|
68
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
69
|
+
"UND_ERR_HEADERS_TIMEOUT",
|
|
70
|
+
"UND_ERR_BODY_TIMEOUT"
|
|
71
|
+
].includes(code ?? "");
|
|
72
|
+
};
|
|
73
|
+
var downloadPrivacyAsset = async (file, temporary, fetcher, options) => {
|
|
74
|
+
const url = `https://huggingface.co/${PRIVACY_MODEL_ID}/resolve/${PRIVACY_MODEL_REVISION}/${file.path}`;
|
|
75
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
76
|
+
options.signal?.throwIfAborted();
|
|
77
|
+
rmSync(temporary, { force: true });
|
|
78
|
+
const idle = new AbortController();
|
|
79
|
+
let idleTimer;
|
|
80
|
+
const activity = () => {
|
|
81
|
+
clearTimeout(idleTimer);
|
|
82
|
+
idleTimer = setTimeout(() => idle.abort(new Error("Privacy model transfer stalled.")), 3e4);
|
|
83
|
+
};
|
|
84
|
+
activity();
|
|
85
|
+
const signal = options.signal ? AbortSignal.any([options.signal, idle.signal]) : idle.signal;
|
|
86
|
+
try {
|
|
87
|
+
const response = await fetcher(url, { signal });
|
|
88
|
+
if (!response.ok || !response.body) {
|
|
89
|
+
await response.body?.cancel();
|
|
90
|
+
const retryAfter = response.headers.get("retry-after");
|
|
91
|
+
const seconds = retryAfter === null ? NaN : Number(retryAfter);
|
|
92
|
+
const requestedDelay = retryAfter === null ? NaN : Number.isFinite(seconds) ? seconds * 1e3 : Date.parse(retryAfter) - Date.now();
|
|
93
|
+
const retryDelay = Number.isFinite(requestedDelay) ? Math.max(0, requestedDelay) : 250 * attempt;
|
|
94
|
+
if (attempt < 3 && retryDelay <= 3e4 && (response.status === 408 || response.status === 429 || response.status >= 500)) {
|
|
95
|
+
clearTimeout(idleTimer);
|
|
96
|
+
await delay(retryDelay, void 0, options.signal ? { signal: options.signal } : {});
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
return response.status;
|
|
100
|
+
}
|
|
101
|
+
let transferredBytes = 0;
|
|
102
|
+
let lastProgressAt = 0;
|
|
103
|
+
const headerSize = Number(response.headers.get("content-length"));
|
|
104
|
+
const totalBytes = file.size ?? (Number.isSafeInteger(headerSize) && headerSize > 0 ? headerSize : void 0);
|
|
105
|
+
options.progress?.({
|
|
106
|
+
phase: "model-download",
|
|
107
|
+
transferredBytes,
|
|
108
|
+
...totalBytes === void 0 ? {} : { totalBytes },
|
|
109
|
+
file: file.path
|
|
110
|
+
});
|
|
111
|
+
const monitor = new Transform({
|
|
112
|
+
transform(chunk, _encoding, callback) {
|
|
113
|
+
activity();
|
|
114
|
+
transferredBytes += chunk.length;
|
|
115
|
+
if (Date.now() - lastProgressAt >= 100) {
|
|
116
|
+
options.progress?.({
|
|
117
|
+
phase: "model-download",
|
|
118
|
+
transferredBytes,
|
|
119
|
+
...totalBytes === void 0 ? {} : { totalBytes },
|
|
120
|
+
file: file.path
|
|
121
|
+
});
|
|
122
|
+
lastProgressAt = Date.now();
|
|
123
|
+
}
|
|
124
|
+
callback(null, chunk);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
await pipeline(Readable.fromWeb(response.body), monitor, createWriteStream(temporary, { mode: 384 }), { signal });
|
|
128
|
+
options.progress?.({
|
|
129
|
+
phase: "model-download",
|
|
130
|
+
transferredBytes,
|
|
131
|
+
...totalBytes === void 0 ? {} : { totalBytes },
|
|
132
|
+
file: file.path
|
|
133
|
+
});
|
|
134
|
+
return void 0;
|
|
135
|
+
} catch (error) {
|
|
136
|
+
rmSync(temporary, { force: true });
|
|
137
|
+
options.signal?.throwIfAborted();
|
|
138
|
+
if (!idle.signal.aborted && !retryableTransferError(error))
|
|
139
|
+
throw error;
|
|
140
|
+
if (attempt === 3) {
|
|
141
|
+
throw new Error(`Could not download pinned Privacy Filter model asset ${file.path}: transfer failed after ${attempt} attempts.`, { cause: error });
|
|
142
|
+
}
|
|
143
|
+
clearTimeout(idleTimer);
|
|
144
|
+
await delay(250 * attempt, void 0, options.signal ? { signal: options.signal } : {});
|
|
145
|
+
} finally {
|
|
146
|
+
clearTimeout(idleTimer);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
throw new Error("Privacy Filter model transfer did not complete.");
|
|
150
|
+
};
|
|
151
|
+
var collectPrivacyModelStatus = async (serverPaths, signal) => {
|
|
152
|
+
const paths = resolvePrivacyModelPaths(serverPaths);
|
|
153
|
+
const files = [];
|
|
154
|
+
for (const file of PRIVACY_MODEL_FILES) {
|
|
155
|
+
signal?.throwIfAborted();
|
|
156
|
+
const blob = blobPath(paths, file);
|
|
157
|
+
if (!existsSync(blob)) {
|
|
158
|
+
return {
|
|
159
|
+
ok: false,
|
|
160
|
+
state: "missing",
|
|
161
|
+
message: `Pinned Privacy Filter model asset is missing: ${file.path}.`,
|
|
162
|
+
action: "Run koed models install --kind privacy.",
|
|
163
|
+
modelPath: paths.cacheDir,
|
|
164
|
+
files
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
const sizeBytes = statSync(blob).size;
|
|
168
|
+
const actual = await sha256File(blob, signal);
|
|
169
|
+
files.push({ path: file.path, sha256: actual, sizeBytes });
|
|
170
|
+
if (actual !== file.sha256 || file.size !== void 0 && sizeBytes !== file.size) {
|
|
171
|
+
return {
|
|
172
|
+
ok: false,
|
|
173
|
+
state: "checksum_mismatch",
|
|
174
|
+
message: `Pinned Privacy Filter model asset failed verification: ${file.path}.`,
|
|
175
|
+
action: "Run koed models install --kind privacy to replace the invalid content-addressed asset.",
|
|
176
|
+
modelPath: paths.cacheDir,
|
|
177
|
+
files
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
materializeCacheEntry(paths, file);
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
ok: true,
|
|
184
|
+
state: "installed",
|
|
185
|
+
message: "Pinned Privacy Filter model assets are installed and verified.",
|
|
186
|
+
modelPath: paths.cacheDir,
|
|
187
|
+
files
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
var installPrivacyModel = async (serverPaths, environment = process.env, fetcher = globalThis.fetch.bind(globalThis), options = {}) => {
|
|
191
|
+
if (environment.KOED_DEPENDENCY_MODE?.trim() === "external") {
|
|
192
|
+
return {
|
|
193
|
+
ok: false,
|
|
194
|
+
state: "not_configured",
|
|
195
|
+
message: "Privacy Filter model downloads are disabled in external dependency mode.",
|
|
196
|
+
action: "Run the Operator-managed Privacy Filter Service with its pinned model assets.",
|
|
197
|
+
modelPath: resolvePrivacyModelPaths(serverPaths).cacheDir,
|
|
198
|
+
files: []
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
const paths = resolvePrivacyModelPaths(serverPaths);
|
|
202
|
+
mkdirSync(paths.blobsDir, { recursive: true, mode: 448 });
|
|
203
|
+
for (const file of PRIVACY_MODEL_FILES) {
|
|
204
|
+
options.signal?.throwIfAborted();
|
|
205
|
+
const blob = blobPath(paths, file);
|
|
206
|
+
if (existsSync(blob) && await sha256File(blob, options.signal) === file.sha256) {
|
|
207
|
+
materializeCacheEntry(paths, file);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const temporary = `${blob}.${process.pid}.${randomUUID()}.download`;
|
|
211
|
+
try {
|
|
212
|
+
const failedStatus = await downloadPrivacyAsset(file, temporary, fetcher, options);
|
|
213
|
+
if (failedStatus !== void 0) {
|
|
214
|
+
return {
|
|
215
|
+
ok: false,
|
|
216
|
+
state: "missing",
|
|
217
|
+
message: `Could not download pinned Privacy Filter model asset ${file.path} (HTTP ${failedStatus}).`,
|
|
218
|
+
action: "Check network access to huggingface.co and retry.",
|
|
219
|
+
modelPath: paths.cacheDir,
|
|
220
|
+
files: []
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const sizeBytes = statSync(temporary).size;
|
|
224
|
+
options.progress?.({
|
|
225
|
+
phase: "model-verify",
|
|
226
|
+
transferredBytes: sizeBytes,
|
|
227
|
+
totalBytes: sizeBytes,
|
|
228
|
+
file: file.path
|
|
229
|
+
});
|
|
230
|
+
const actual = await sha256File(temporary, options.signal);
|
|
231
|
+
if (actual !== file.sha256 || file.size !== void 0 && sizeBytes !== file.size) {
|
|
232
|
+
return {
|
|
233
|
+
ok: false,
|
|
234
|
+
state: "checksum_mismatch",
|
|
235
|
+
message: `Downloaded Privacy Filter model asset failed verification: ${file.path}.`,
|
|
236
|
+
action: "Do not use the asset; verify the pinned upstream revision and retry.",
|
|
237
|
+
modelPath: paths.cacheDir,
|
|
238
|
+
files: [{ path: file.path, sha256: actual, sizeBytes }]
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
rmSync(blob, { force: true });
|
|
242
|
+
renameSync(temporary, blob);
|
|
243
|
+
materializeCacheEntry(paths, file);
|
|
244
|
+
} finally {
|
|
245
|
+
rmSync(temporary, { force: true });
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return collectPrivacyModelStatus(serverPaths, options.signal);
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
export {
|
|
252
|
+
PRIVACY_MODEL_ID,
|
|
253
|
+
PRIVACY_MODEL_REVISION,
|
|
254
|
+
PRIVACY_MODEL_FILES,
|
|
255
|
+
resolvePrivacyModelPaths,
|
|
256
|
+
materializePrivacyModelCacheEntry,
|
|
257
|
+
collectPrivacyModelStatus,
|
|
258
|
+
installPrivacyModel
|
|
259
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createRequire as createKoedRequire } from "node:module"; const require = createKoedRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// packages/koed-server/dist/env-file.js
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
var parseEnvFile = (content, options = {}) => {
|
|
7
|
+
const values = {};
|
|
8
|
+
const fail = (lineNumber, reason) => {
|
|
9
|
+
throw new Error(`${options.source ?? "Environment file"}:${lineNumber}: ${reason}`);
|
|
10
|
+
};
|
|
11
|
+
for (const [index, line] of content.split(/\r?\n/).entries()) {
|
|
12
|
+
const trimmed = line.trim();
|
|
13
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
const equals = trimmed.indexOf("=");
|
|
17
|
+
if (equals <= 0) {
|
|
18
|
+
if (options.strict)
|
|
19
|
+
fail(index + 1, "expected KEY=VALUE");
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const key = trimmed.slice(0, equals).trim();
|
|
23
|
+
let value = trimmed.slice(equals + 1).trim();
|
|
24
|
+
const quoted = value.startsWith('"') || value.startsWith("'");
|
|
25
|
+
if (quoted && options.strict) {
|
|
26
|
+
const quote = value[0];
|
|
27
|
+
let closingQuote = -1;
|
|
28
|
+
for (let position = 1; position < value.length; position += 1) {
|
|
29
|
+
if (quote === '"' && value[position] === "\\") {
|
|
30
|
+
position += 1;
|
|
31
|
+
} else if (value[position] === quote) {
|
|
32
|
+
closingQuote = position;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (closingQuote < 0) {
|
|
37
|
+
fail(index + 1, `unterminated quoted value for ${key}`);
|
|
38
|
+
}
|
|
39
|
+
const trailing = value.slice(closingQuote + 1).trim();
|
|
40
|
+
if (trailing && !trailing.startsWith("#")) {
|
|
41
|
+
fail(index + 1, `unexpected text after quoted value for ${key}`);
|
|
42
|
+
}
|
|
43
|
+
value = value.slice(1, closingQuote);
|
|
44
|
+
} else if (quoted) {
|
|
45
|
+
if (value.length < 2 || value.at(-1) !== value[0]) {
|
|
46
|
+
} else {
|
|
47
|
+
value = value.slice(1, -1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (options.strict && !/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
51
|
+
fail(index + 1, `invalid environment variable name ${key}`);
|
|
52
|
+
}
|
|
53
|
+
values[key] = value;
|
|
54
|
+
}
|
|
55
|
+
return values;
|
|
56
|
+
};
|
|
57
|
+
var loadRepoEnv = (repoRoot, environment = process.env) => {
|
|
58
|
+
const envPath = environment.KOED_ENV_PATH?.trim() ? resolve(environment.KOED_ENV_PATH) : resolve(repoRoot, ".env");
|
|
59
|
+
if (!existsSync(envPath)) {
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
return parseEnvFile(readFileSync(envPath, "utf8"));
|
|
63
|
+
};
|
|
64
|
+
var environmentWithRepoEnv = (repoRoot, environment = process.env) => ({
|
|
65
|
+
...loadRepoEnv(repoRoot, environment),
|
|
66
|
+
...environment
|
|
67
|
+
});
|
|
68
|
+
var resolveApiUrl = (environment, repoEnv) => ((environment.KOED_AUTO_PORTS === "1" && environment.API_HOST_PORT ? `http://localhost:${environment.API_HOST_PORT}` : null) ?? environment.MEMORY_API_URL ?? (environment.API_HOST_PORT ? `http://localhost:${environment.API_HOST_PORT}` : null) ?? repoEnv.MEMORY_API_URL ?? (repoEnv.API_HOST_PORT ? `http://localhost:${repoEnv.API_HOST_PORT}` : null) ?? environment.CODEX_MEMORY_BASE_URL ?? repoEnv.CODEX_MEMORY_BASE_URL ?? "http://localhost:3300").trim();
|
|
69
|
+
|
|
70
|
+
export {
|
|
71
|
+
parseEnvFile,
|
|
72
|
+
loadRepoEnv,
|
|
73
|
+
environmentWithRepoEnv,
|
|
74
|
+
resolveApiUrl
|
|
75
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as createKoedRequire } from "node:module"; const require = createKoedRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
isKoedServerCliEntrypoint,
|
|
5
|
+
runKoedServerCli,
|
|
6
|
+
shouldExitPackagedSupervisor
|
|
7
|
+
} from "./chunk-GELDEJJ2.js";
|
|
8
|
+
import {
|
|
9
|
+
startKoedServerDaemon
|
|
10
|
+
} from "./chunk-JKOG52PE.js";
|
|
11
|
+
import "./chunk-A4NKL2PK.js";
|
|
12
|
+
import "./chunk-K2EIFEQF.js";
|
|
13
|
+
import "./chunk-UI5RLBKQ.js";
|
|
14
|
+
import "./chunk-BTS4ZTF3.js";
|
|
15
|
+
export {
|
|
16
|
+
isKoedServerCliEntrypoint,
|
|
17
|
+
runKoedServerCli,
|
|
18
|
+
shouldExitPackagedSupervisor,
|
|
19
|
+
startKoedServerDaemon
|
|
20
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createRequire as createKoedRequire } from "node:module"; const require = createKoedRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
getProjectTeamWorkspaceLink,
|
|
4
|
+
linkProjectTeamWorkspace,
|
|
5
|
+
listProjectTeamWorkspaceLinks,
|
|
6
|
+
removeProjectTeamWorkspaceLink,
|
|
7
|
+
removeProjectTeamWorkspaceLinksForBackend,
|
|
8
|
+
removeProjectTeamWorkspaceLinksForMismatchedBinding
|
|
9
|
+
} from "./chunk-6JRWGOQG.js";
|
|
10
|
+
import "./chunk-BTS4ZTF3.js";
|
|
11
|
+
export {
|
|
12
|
+
getProjectTeamWorkspaceLink,
|
|
13
|
+
linkProjectTeamWorkspace,
|
|
14
|
+
listProjectTeamWorkspaceLinks,
|
|
15
|
+
removeProjectTeamWorkspaceLink,
|
|
16
|
+
removeProjectTeamWorkspaceLinksForBackend,
|
|
17
|
+
removeProjectTeamWorkspaceLinksForMismatchedBinding
|
|
18
|
+
};
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { createRequire as createKoedRequire } from "node:module"; const require = createKoedRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
require_proper_lockfile
|
|
4
|
+
} from "./chunk-7NXKPDF3.js";
|
|
5
|
+
import {
|
|
6
|
+
createPlatformHostProofStore,
|
|
7
|
+
deviceIdentityStatePathFor,
|
|
8
|
+
deviceProofFingerprint,
|
|
9
|
+
hostProofReferenceFor,
|
|
10
|
+
inspectDeviceIdentity,
|
|
11
|
+
serializeHostProof
|
|
12
|
+
} from "./chunk-473OA62O.js";
|
|
13
|
+
import {
|
|
14
|
+
__toESM
|
|
15
|
+
} from "./chunk-BTS4ZTF3.js";
|
|
16
|
+
|
|
17
|
+
// packages/koed-server/dist/device-identity.js
|
|
18
|
+
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
19
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
20
|
+
import { existsSync, lstatSync, mkdirSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
21
|
+
import { resolve } from "node:path";
|
|
22
|
+
var lockStaleMs = 3e4;
|
|
23
|
+
var defaultProof = () => randomBytes(32).toString("base64url");
|
|
24
|
+
var testProofDirectory = (paths) => {
|
|
25
|
+
const proofRoot = resolve(`${paths.koedHome}-proof-root`);
|
|
26
|
+
mkdirSync(proofRoot, { recursive: true, mode: 448 });
|
|
27
|
+
return resolve(proofRoot, "proof");
|
|
28
|
+
};
|
|
29
|
+
var dependencies = (paths, deps) => {
|
|
30
|
+
const environment = deps.environment ?? process.env;
|
|
31
|
+
return {
|
|
32
|
+
environment,
|
|
33
|
+
proofStore: deps.proofStore ?? createPlatformHostProofStore({
|
|
34
|
+
koedHome: paths.koedHome,
|
|
35
|
+
environment: environment.NODE_ENV === "test" ? {
|
|
36
|
+
...environment,
|
|
37
|
+
KOED_DEVICE_PROOF_DIR: testProofDirectory(paths)
|
|
38
|
+
} : environment
|
|
39
|
+
}),
|
|
40
|
+
now: deps.now ?? (() => /* @__PURE__ */ new Date()),
|
|
41
|
+
randomId: deps.randomId ?? randomUUID,
|
|
42
|
+
randomProof: deps.randomProof ?? defaultProof,
|
|
43
|
+
onPhase: deps.onPhase ?? (() => void 0)
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
var lockTarget = (paths) => resolve(paths.runDir, "device-identity");
|
|
47
|
+
var bootstrapTombstonePath = (paths) => resolve(paths.configDir, "device-identity-bootstrap.json");
|
|
48
|
+
var withDeviceIdentityLock = async (paths, mutation) => {
|
|
49
|
+
mkdirSync(paths.runDir, { recursive: true, mode: 448 });
|
|
50
|
+
const release = await import_proper_lockfile.default.lock(lockTarget(paths), {
|
|
51
|
+
realpath: false,
|
|
52
|
+
stale: lockStaleMs,
|
|
53
|
+
update: lockStaleMs / 3,
|
|
54
|
+
retries: {
|
|
55
|
+
retries: 100,
|
|
56
|
+
factor: 1,
|
|
57
|
+
minTimeout: 25,
|
|
58
|
+
maxTimeout: 100,
|
|
59
|
+
randomize: true
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
try {
|
|
63
|
+
return await mutation();
|
|
64
|
+
} finally {
|
|
65
|
+
await release();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var writeState = (statePath, state) => {
|
|
69
|
+
mkdirSync(resolve(statePath, ".."), { recursive: true, mode: 448 });
|
|
70
|
+
const temporary = `${statePath}.${randomUUID()}.tmp`;
|
|
71
|
+
try {
|
|
72
|
+
writeFileSync(temporary, `${JSON.stringify(state, null, 2)}
|
|
73
|
+
`, {
|
|
74
|
+
mode: 384,
|
|
75
|
+
flag: "wx"
|
|
76
|
+
});
|
|
77
|
+
renameSync(temporary, statePath);
|
|
78
|
+
} finally {
|
|
79
|
+
rmSync(temporary, { force: true });
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var prepareIdentityStorage = (paths) => {
|
|
83
|
+
mkdirSync(paths.koedHome, { recursive: true, mode: 448 });
|
|
84
|
+
if (lstatSync(paths.koedHome).isSymbolicLink()) {
|
|
85
|
+
throw new Error("KOED_HOME must not be a symbolic link.");
|
|
86
|
+
}
|
|
87
|
+
mkdirSync(paths.configDir, { recursive: true, mode: 448 });
|
|
88
|
+
if (lstatSync(paths.configDir).isSymbolicLink()) {
|
|
89
|
+
throw new Error("Device identity config directory must not be a symbolic link.");
|
|
90
|
+
}
|
|
91
|
+
return realpathSync(paths.koedHome);
|
|
92
|
+
};
|
|
93
|
+
var writeBootstrapTombstone = (paths, now) => {
|
|
94
|
+
const tombstonePath = bootstrapTombstonePath(paths);
|
|
95
|
+
if (existsSync(tombstonePath))
|
|
96
|
+
return;
|
|
97
|
+
const temporary = `${tombstonePath}.${randomUUID()}.tmp`;
|
|
98
|
+
try {
|
|
99
|
+
writeFileSync(temporary, `${JSON.stringify({ schemaVersion: 1, initializedAt: now.toISOString() })}
|
|
100
|
+
`, { mode: 384, flag: "wx" });
|
|
101
|
+
renameSync(temporary, tombstonePath);
|
|
102
|
+
} finally {
|
|
103
|
+
rmSync(temporary, { force: true });
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var newIdentityState = (now, randomId, randomProof, remoteOperations, deploymentId = randomId(), pendingRemoteRevocation = false) => {
|
|
107
|
+
const deviceInstanceId = randomId();
|
|
108
|
+
const proof = randomProof();
|
|
109
|
+
const timestamp = now.toISOString();
|
|
110
|
+
return {
|
|
111
|
+
state: {
|
|
112
|
+
schemaVersion: 1,
|
|
113
|
+
deploymentId,
|
|
114
|
+
deviceInstanceId,
|
|
115
|
+
proof: {
|
|
116
|
+
reference: hostProofReferenceFor(deviceInstanceId),
|
|
117
|
+
fingerprint: deviceProofFingerprint(proof)
|
|
118
|
+
},
|
|
119
|
+
remoteOperations,
|
|
120
|
+
deploymentIdentityAdoptionPending: true,
|
|
121
|
+
...pendingRemoteRevocation ? { pendingRemoteRevocation: true } : {},
|
|
122
|
+
createdAt: timestamp,
|
|
123
|
+
updatedAt: timestamp
|
|
124
|
+
},
|
|
125
|
+
proof
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
var result = (identity, options = {}) => ({
|
|
129
|
+
...identity,
|
|
130
|
+
initialized: options.initialized ?? false,
|
|
131
|
+
rotated: options.rotated ?? false,
|
|
132
|
+
...options.referencesInvalidated === void 0 ? {} : { referencesInvalidated: options.referencesInvalidated }
|
|
133
|
+
});
|
|
134
|
+
var inspect = (paths, proofStore) => inspectDeviceIdentity({
|
|
135
|
+
statePath: deviceIdentityStatePathFor(paths.koedHome),
|
|
136
|
+
proofStore
|
|
137
|
+
});
|
|
138
|
+
var inspectDeviceIdentityStatus = (paths, deps = {}) => {
|
|
139
|
+
const resolved = dependencies(paths, deps);
|
|
140
|
+
return Promise.resolve(result(inspect(paths, resolved.proofStore)));
|
|
141
|
+
};
|
|
142
|
+
var ensureDeviceIdentity = async (paths, deps = {}) => {
|
|
143
|
+
const resolved = dependencies(paths, deps);
|
|
144
|
+
return withDeviceIdentityLock(paths, () => {
|
|
145
|
+
try {
|
|
146
|
+
const canonicalKoedHome = prepareIdentityStorage(paths);
|
|
147
|
+
const current = inspect(paths, resolved.proofStore);
|
|
148
|
+
if (current.health !== "missing_state")
|
|
149
|
+
return result(current);
|
|
150
|
+
if (existsSync(bootstrapTombstonePath(paths)))
|
|
151
|
+
return result(current);
|
|
152
|
+
writeBootstrapTombstone(paths, resolved.now());
|
|
153
|
+
resolved.onPhase("tombstone");
|
|
154
|
+
const next = newIdentityState(resolved.now(), resolved.randomId, resolved.randomProof, "repair_required");
|
|
155
|
+
resolved.proofStore.write(next.state.proof.reference, serializeHostProof({
|
|
156
|
+
deploymentId: next.state.deploymentId,
|
|
157
|
+
deviceInstanceId: next.state.deviceInstanceId,
|
|
158
|
+
proof: next.proof,
|
|
159
|
+
canonicalKoedHome
|
|
160
|
+
}));
|
|
161
|
+
resolved.onPhase("proof");
|
|
162
|
+
writeState(deviceIdentityStatePathFor(paths.koedHome), next.state);
|
|
163
|
+
resolved.onPhase("state");
|
|
164
|
+
writeState(deviceIdentityStatePathFor(paths.koedHome), {
|
|
165
|
+
...next.state,
|
|
166
|
+
remoteOperations: "enabled",
|
|
167
|
+
updatedAt: resolved.now().toISOString()
|
|
168
|
+
});
|
|
169
|
+
return result(inspect(paths, resolved.proofStore), { initialized: true });
|
|
170
|
+
} catch {
|
|
171
|
+
return result(inspect(paths, resolved.proofStore));
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
var rotateDeviceIdentity = async (paths, options) => {
|
|
176
|
+
const resolved = dependencies(paths, options.dependencies ?? {});
|
|
177
|
+
return withDeviceIdentityLock(paths, async () => {
|
|
178
|
+
let canonicalKoedHome;
|
|
179
|
+
try {
|
|
180
|
+
canonicalKoedHome = prepareIdentityStorage(paths);
|
|
181
|
+
} catch {
|
|
182
|
+
return result(inspect(paths, resolved.proofStore), { rotated: false });
|
|
183
|
+
}
|
|
184
|
+
const previous = inspect(paths, resolved.proofStore);
|
|
185
|
+
const previousReference = previous.deviceInstanceId ? hostProofReferenceFor(previous.deviceInstanceId) : null;
|
|
186
|
+
const next = newIdentityState(resolved.now(), resolved.randomId, resolved.randomProof, "repair_required", previous.deploymentId ?? void 0, true);
|
|
187
|
+
delete next.state.deploymentIdentityAdoptionPending;
|
|
188
|
+
try {
|
|
189
|
+
writeBootstrapTombstone(paths, resolved.now());
|
|
190
|
+
resolved.proofStore.write(next.state.proof.reference, serializeHostProof({
|
|
191
|
+
deploymentId: next.state.deploymentId,
|
|
192
|
+
deviceInstanceId: next.state.deviceInstanceId,
|
|
193
|
+
proof: next.proof,
|
|
194
|
+
canonicalKoedHome
|
|
195
|
+
}));
|
|
196
|
+
writeState(deviceIdentityStatePathFor(paths.koedHome), next.state);
|
|
197
|
+
} catch {
|
|
198
|
+
return result(inspect(paths, resolved.proofStore), { rotated: false });
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
const invalidation = await options.invalidateRemoteReferences();
|
|
202
|
+
if (invalidation?.pendingRemoteRevocation) {
|
|
203
|
+
return result(inspect(paths, resolved.proofStore), {
|
|
204
|
+
rotated: true,
|
|
205
|
+
referencesInvalidated: false
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
} catch {
|
|
209
|
+
return result(inspect(paths, resolved.proofStore), {
|
|
210
|
+
rotated: true,
|
|
211
|
+
referencesInvalidated: false
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
const completed = {
|
|
215
|
+
...next.state,
|
|
216
|
+
remoteOperations: "enabled",
|
|
217
|
+
updatedAt: resolved.now().toISOString()
|
|
218
|
+
};
|
|
219
|
+
delete completed.pendingRemoteRevocation;
|
|
220
|
+
try {
|
|
221
|
+
writeState(deviceIdentityStatePathFor(paths.koedHome), completed);
|
|
222
|
+
if (previousReference && previousReference !== completed.proof.reference) {
|
|
223
|
+
resolved.proofStore.remove(previousReference);
|
|
224
|
+
}
|
|
225
|
+
return result(inspect(paths, resolved.proofStore), {
|
|
226
|
+
rotated: true,
|
|
227
|
+
referencesInvalidated: true
|
|
228
|
+
});
|
|
229
|
+
} catch {
|
|
230
|
+
return result(inspect(paths, resolved.proofStore), {
|
|
231
|
+
rotated: true,
|
|
232
|
+
referencesInvalidated: false
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
export {
|
|
239
|
+
inspectDeviceIdentityStatus,
|
|
240
|
+
ensureDeviceIdentity,
|
|
241
|
+
rotateDeviceIdentity
|
|
242
|
+
};
|