@thyn-ai/sqai 0.1.4 → 0.1.5
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 +202 -0
- package/dist/index.cjs +241 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +201 -32
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,12 +17,21 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var index_exports = {};
|
|
22
32
|
__export(index_exports, {
|
|
23
33
|
ContractIndex: () => ContractIndex,
|
|
34
|
+
LoginError: () => LoginError,
|
|
24
35
|
ResultStore: () => ResultStore,
|
|
25
36
|
RuntimeProvisioner: () => RuntimeProvisioner,
|
|
26
37
|
SQAI: () => SQAI,
|
|
@@ -31,15 +42,19 @@ __export(index_exports, {
|
|
|
31
42
|
currentPlatformKey: () => currentPlatformKey,
|
|
32
43
|
invocationHash: () => invocationHash,
|
|
33
44
|
isReadOnlyEligible: () => isReadOnlyEligible,
|
|
45
|
+
login: () => login,
|
|
46
|
+
logout: () => logout,
|
|
34
47
|
lookupCapability: () => lookupCapability,
|
|
48
|
+
readCachedApiKey: () => readCachedApiKey,
|
|
35
49
|
runtimeCacheDir: () => runtimeCacheDir,
|
|
50
|
+
sqaiHome: () => sqaiHome,
|
|
36
51
|
validateComputation: () => validateComputation
|
|
37
52
|
});
|
|
38
53
|
module.exports = __toCommonJS(index_exports);
|
|
39
54
|
|
|
40
55
|
// src/sqai.ts
|
|
41
|
-
var
|
|
42
|
-
var
|
|
56
|
+
var import_node_crypto7 = require("crypto");
|
|
57
|
+
var import_node_os3 = require("os");
|
|
43
58
|
var import_algenta_sdk3 = require("algenta-sdk");
|
|
44
59
|
|
|
45
60
|
// src/contract-data.json
|
|
@@ -354,22 +369,180 @@ var ResultStore = class {
|
|
|
354
369
|
};
|
|
355
370
|
|
|
356
371
|
// src/runtime/provision.ts
|
|
357
|
-
var
|
|
358
|
-
var
|
|
359
|
-
var
|
|
360
|
-
var
|
|
372
|
+
var import_node_os2 = require("os");
|
|
373
|
+
var import_node_path3 = require("path");
|
|
374
|
+
var import_node_fs3 = require("fs");
|
|
375
|
+
var import_node_crypto6 = require("crypto");
|
|
361
376
|
var import_node_stream = require("stream");
|
|
362
377
|
var import_promises = require("stream/promises");
|
|
363
378
|
var import_algenta_sdk2 = require("algenta-sdk");
|
|
364
379
|
|
|
365
|
-
// src/runtime/
|
|
366
|
-
var
|
|
367
|
-
var import_node_crypto4 = require("crypto");
|
|
380
|
+
// src/runtime/auth.ts
|
|
381
|
+
var import_node_crypto3 = require("crypto");
|
|
368
382
|
var import_node_fs = require("fs");
|
|
383
|
+
var import_node_os = require("os");
|
|
369
384
|
var import_node_path = require("path");
|
|
385
|
+
var CLIENT_ID = "sqai-cli";
|
|
386
|
+
var SCOPE = "sqai";
|
|
387
|
+
var PRODUCT = "sqai";
|
|
388
|
+
var DEFAULT_PLAN = "sqai_developer";
|
|
389
|
+
var DEFAULT_ACCOUNTS_URL = "https://accounts.thyn.ai";
|
|
390
|
+
var DEFAULT_API_URL = "https://api.sqai.com";
|
|
391
|
+
var LoginError = class extends Error {
|
|
392
|
+
};
|
|
393
|
+
function sqaiHome() {
|
|
394
|
+
return process.env.SQAI_HOME ?? (0, import_node_path.join)((0, import_node_os.homedir)(), ".sqai");
|
|
395
|
+
}
|
|
396
|
+
var p = (name) => (0, import_node_path.join)(sqaiHome(), name);
|
|
397
|
+
var apiKeyPath = () => p("api_key");
|
|
398
|
+
var tokenPath = () => p("token");
|
|
399
|
+
var deviceIdPath = () => p("device_id");
|
|
400
|
+
var accountsUrl = () => (process.env.SQAI_ACCOUNTS_URL ?? DEFAULT_ACCOUNTS_URL).replace(/\/$/, "");
|
|
401
|
+
var apiUrl = () => (process.env.SQAI_API_URL ?? DEFAULT_API_URL).replace(/\/$/, "");
|
|
402
|
+
function readSecret(path) {
|
|
403
|
+
try {
|
|
404
|
+
const v = (0, import_node_fs.readFileSync)(path, "utf8").trim();
|
|
405
|
+
return v || void 0;
|
|
406
|
+
} catch {
|
|
407
|
+
return void 0;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
async function readCachedApiKey() {
|
|
411
|
+
return process.env.SQAI_API_KEY ?? process.env.ALGENTA_API_KEY ?? readSecret(apiKeyPath());
|
|
412
|
+
}
|
|
413
|
+
function cache(path, value) {
|
|
414
|
+
(0, import_node_fs.mkdirSync)(sqaiHome(), { recursive: true });
|
|
415
|
+
(0, import_node_fs.writeFileSync)(path, value.trim() + "\n", "utf8");
|
|
416
|
+
try {
|
|
417
|
+
(0, import_node_fs.chmodSync)(path, 384);
|
|
418
|
+
} catch {
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
function deviceId() {
|
|
422
|
+
const existing = readSecret(deviceIdPath());
|
|
423
|
+
if (existing) return existing;
|
|
424
|
+
const value = (0, import_node_crypto3.createHash)("sha256").update(`${(0, import_node_os.hostname)()}:${Date.now()}:${Math.random()}`).digest("hex");
|
|
425
|
+
cache(deviceIdPath(), value);
|
|
426
|
+
return value;
|
|
427
|
+
}
|
|
428
|
+
async function request(method, url, opts = {}) {
|
|
429
|
+
const headers = { Accept: "application/json", "User-Agent": "sqai-cli" };
|
|
430
|
+
if (opts.body !== void 0) headers["Content-Type"] = "application/json";
|
|
431
|
+
if (opts.bearer) headers["Authorization"] = `Bearer ${opts.bearer}`;
|
|
432
|
+
let res;
|
|
433
|
+
try {
|
|
434
|
+
res = await fetch(url, {
|
|
435
|
+
method,
|
|
436
|
+
headers,
|
|
437
|
+
body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0
|
|
438
|
+
});
|
|
439
|
+
} catch (e) {
|
|
440
|
+
throw new LoginError(`${method} ${url}: ${e instanceof Error ? e.message : String(e)}`);
|
|
441
|
+
}
|
|
442
|
+
let json = {};
|
|
443
|
+
try {
|
|
444
|
+
json = await res.json();
|
|
445
|
+
} catch {
|
|
446
|
+
json = {};
|
|
447
|
+
}
|
|
448
|
+
return { status: res.status, json };
|
|
449
|
+
}
|
|
450
|
+
async function deviceAuthorize(accounts, openBrowser, maxWaitMs = 3e5) {
|
|
451
|
+
const { json: start } = await request("POST", `${accounts}/oauth/device/code`, {
|
|
452
|
+
body: { client_id: CLIENT_ID, scope: SCOPE }
|
|
453
|
+
});
|
|
454
|
+
const deviceCode = start.device_code;
|
|
455
|
+
const userCode = start.user_code;
|
|
456
|
+
const verify = start.verification_uri_complete || start.verification_uri;
|
|
457
|
+
const interval = Number(start.interval ?? 5);
|
|
458
|
+
if (!deviceCode || !userCode || !verify) throw new LoginError("accounts device-code response missing fields");
|
|
459
|
+
process.stdout.write(`
|
|
460
|
+
Open ${verify}
|
|
461
|
+
and enter code: ${userCode}
|
|
462
|
+
|
|
463
|
+
`);
|
|
464
|
+
if (openBrowser) await tryOpenBrowser(verify);
|
|
465
|
+
const deadline = Date.now() + maxWaitMs;
|
|
466
|
+
while (Date.now() < deadline) {
|
|
467
|
+
await new Promise((r) => setTimeout(r, interval * 1e3));
|
|
468
|
+
const { status, json: tok } = await request("POST", `${accounts}/oauth/device/token`, {
|
|
469
|
+
body: {
|
|
470
|
+
client_id: CLIENT_ID,
|
|
471
|
+
device_code: deviceCode,
|
|
472
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code"
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
const access = tok.access_token;
|
|
476
|
+
if (access) return access;
|
|
477
|
+
const error = tok.error;
|
|
478
|
+
if (error === "authorization_pending" || error === "slow_down" || status === 400 || status === 428) continue;
|
|
479
|
+
throw new LoginError(`device authorization failed: ${error ?? `HTTP ${status}`}`);
|
|
480
|
+
}
|
|
481
|
+
throw new LoginError("timed out waiting for device authorization");
|
|
482
|
+
}
|
|
483
|
+
async function tryOpenBrowser(url) {
|
|
484
|
+
try {
|
|
485
|
+
const { spawn: spawn2 } = await import("child_process");
|
|
486
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
487
|
+
spawn2(cmd, [url], { stdio: "ignore", detached: true, shell: process.platform === "win32" }).unref();
|
|
488
|
+
} catch {
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
async function createApiKey(api, accessToken, plan) {
|
|
492
|
+
const { status, json } = await request("POST", `${api}/v1/products/${PRODUCT}/onboard`, {
|
|
493
|
+
bearer: accessToken,
|
|
494
|
+
body: { name: CLIENT_ID, product: PRODUCT, plan }
|
|
495
|
+
});
|
|
496
|
+
const key = json.raw_key || json.key || json.api_key;
|
|
497
|
+
if (status >= 400 || !key) {
|
|
498
|
+
const detail = json.error && typeof json.error === "object" ? json.error.message : void 0;
|
|
499
|
+
throw new LoginError(`could not create API key (HTTP ${status})${detail ? `: ${detail}` : ""}`);
|
|
500
|
+
}
|
|
501
|
+
return key;
|
|
502
|
+
}
|
|
503
|
+
async function login(opts = {}) {
|
|
504
|
+
const plan = opts.plan ?? DEFAULT_PLAN;
|
|
505
|
+
const accounts = accountsUrl();
|
|
506
|
+
const api = apiUrl();
|
|
507
|
+
let token = opts.accessToken ?? process.env.SQAI_TOKEN;
|
|
508
|
+
if (token) {
|
|
509
|
+
process.stdout.write("using supplied token (headless)\n");
|
|
510
|
+
} else {
|
|
511
|
+
process.stdout.write(`authenticating via ${accounts} \u2026
|
|
512
|
+
`);
|
|
513
|
+
token = await deviceAuthorize(accounts, opts.openBrowser ?? true);
|
|
514
|
+
}
|
|
515
|
+
cache(tokenPath(), token);
|
|
516
|
+
process.stdout.write("creating your free SQAI Developer API key \u2026\n");
|
|
517
|
+
const apiKey = await createApiKey(api, token, plan);
|
|
518
|
+
cache(apiKeyPath(), apiKey);
|
|
519
|
+
deviceId();
|
|
520
|
+
process.stdout.write(
|
|
521
|
+
"\n \u2713 sqai login complete \u2014 the local runtime will provision a device-bound offline license on first use.\n SQAI runs fully on your machine; no data leaves it.\n\n"
|
|
522
|
+
);
|
|
523
|
+
return {
|
|
524
|
+
device_id: deviceId(),
|
|
525
|
+
plan,
|
|
526
|
+
api_key_prefix: apiKey.includes("_") ? `${apiKey.split("_", 1)[0]}_\u2026` : `${apiKey.slice(0, 6)}\u2026`
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
function logout() {
|
|
530
|
+
for (const path of [tokenPath(), apiKeyPath()]) {
|
|
531
|
+
try {
|
|
532
|
+
(0, import_node_fs.rmSync)(path);
|
|
533
|
+
} catch {
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// src/runtime/bundle.ts
|
|
539
|
+
var import_node_child_process = require("child_process");
|
|
540
|
+
var import_node_crypto5 = require("crypto");
|
|
541
|
+
var import_node_fs2 = require("fs");
|
|
542
|
+
var import_node_path2 = require("path");
|
|
370
543
|
|
|
371
544
|
// src/runtime/trust.ts
|
|
372
|
-
var
|
|
545
|
+
var import_node_crypto4 = require("crypto");
|
|
373
546
|
var RELEASE_1_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
374
547
|
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7m4G1dEMi5FppLa5hu9N
|
|
375
548
|
4pUyoGELPaN5X7bO+9Qktgbv21+c8I4sQCufKouZEVNMNluKNrWcQ5dSwOuVxxS9
|
|
@@ -468,11 +641,11 @@ function keyValidNow(key, nowMs) {
|
|
|
468
641
|
}
|
|
469
642
|
function signatureVerifies(manifestBytes, signature, publicKeyPem) {
|
|
470
643
|
try {
|
|
471
|
-
const key = (0,
|
|
644
|
+
const key = (0, import_node_crypto4.createPublicKey)(publicKeyPem);
|
|
472
645
|
if (key.asymmetricKeyType !== "rsa") {
|
|
473
646
|
return false;
|
|
474
647
|
}
|
|
475
|
-
return (0,
|
|
648
|
+
return (0, import_node_crypto4.verify)("sha256", manifestBytes, key, signature);
|
|
476
649
|
} catch {
|
|
477
650
|
return false;
|
|
478
651
|
}
|
|
@@ -652,7 +825,7 @@ async function hashTarMember(tarball, member, cap) {
|
|
|
652
825
|
const child = (0, import_node_child_process.spawn)("tar", ["-xOf", tarball, "--", member], {
|
|
653
826
|
stdio: ["ignore", "pipe", "pipe"]
|
|
654
827
|
});
|
|
655
|
-
const digest = (0,
|
|
828
|
+
const digest = (0, import_node_crypto5.createHash)("sha256");
|
|
656
829
|
let total = 0;
|
|
657
830
|
let overflow = false;
|
|
658
831
|
child.stdout.on("data", (chunk) => {
|
|
@@ -686,7 +859,7 @@ async function hashTarMember(tarball, member, cap) {
|
|
|
686
859
|
});
|
|
687
860
|
}
|
|
688
861
|
async function extractTarball(tarball, destinationDir) {
|
|
689
|
-
await
|
|
862
|
+
await import_node_fs2.promises.mkdir(destinationDir, { recursive: true });
|
|
690
863
|
await new Promise((resolve, reject) => {
|
|
691
864
|
const child = (0, import_node_child_process.spawn)("tar", ["-xf", tarball, "-C", destinationDir], {
|
|
692
865
|
stdio: ["ignore", "ignore", "pipe"]
|
|
@@ -712,8 +885,8 @@ async function extractTarball(tarball, destinationDir) {
|
|
|
712
885
|
}
|
|
713
886
|
function sha256File(path) {
|
|
714
887
|
return new Promise((resolve, reject) => {
|
|
715
|
-
const digest = (0,
|
|
716
|
-
const stream = (0,
|
|
888
|
+
const digest = (0, import_node_crypto5.createHash)("sha256");
|
|
889
|
+
const stream = (0, import_node_fs2.createReadStream)(path);
|
|
717
890
|
stream.on("data", (chunk) => digest.update(chunk));
|
|
718
891
|
stream.on("error", reject);
|
|
719
892
|
stream.on("end", () => resolve(digest.digest("hex")));
|
|
@@ -722,7 +895,7 @@ function sha256File(path) {
|
|
|
722
895
|
function digestsEqual(actualHex, expectedHex) {
|
|
723
896
|
const actual = Buffer.from(actualHex.toLowerCase(), "utf-8");
|
|
724
897
|
const expected = Buffer.from(expectedHex.toLowerCase(), "utf-8");
|
|
725
|
-
return actual.length === expected.length && (0,
|
|
898
|
+
return actual.length === expected.length && (0, import_node_crypto5.timingSafeEqual)(actual, expected);
|
|
726
899
|
}
|
|
727
900
|
function parseVerifiedManifest(manifestBytes) {
|
|
728
901
|
let manifest;
|
|
@@ -872,7 +1045,7 @@ async function verifyBundleTarball(tarball, expectations) {
|
|
|
872
1045
|
return manifest;
|
|
873
1046
|
}
|
|
874
1047
|
async function listFilesRecursively(root, relative = "") {
|
|
875
|
-
const entries = await
|
|
1048
|
+
const entries = await import_node_fs2.promises.readdir((0, import_node_path2.join)(root, relative), { withFileTypes: true });
|
|
876
1049
|
const files = [];
|
|
877
1050
|
for (const entry of entries) {
|
|
878
1051
|
const relPath = relative === "" ? entry.name : `${relative}/${entry.name}`;
|
|
@@ -896,21 +1069,21 @@ async function listFilesRecursively(root, relative = "") {
|
|
|
896
1069
|
return files;
|
|
897
1070
|
}
|
|
898
1071
|
async function verifyInstalledBundleDir(installDir, expectations) {
|
|
899
|
-
const manifestPath = (0,
|
|
900
|
-
const signaturePath = (0,
|
|
1072
|
+
const manifestPath = (0, import_node_path2.join)(installDir, MANIFEST_NAME);
|
|
1073
|
+
const signaturePath = (0, import_node_path2.join)(installDir, MANIFEST_SIG_NAME);
|
|
901
1074
|
let manifestBytes;
|
|
902
1075
|
let signature;
|
|
903
1076
|
try {
|
|
904
|
-
const manifestStat = await
|
|
905
|
-
const signatureStat = await
|
|
1077
|
+
const manifestStat = await import_node_fs2.promises.lstat(manifestPath);
|
|
1078
|
+
const signatureStat = await import_node_fs2.promises.lstat(signaturePath);
|
|
906
1079
|
if (!manifestStat.isFile() || !signatureStat.isFile() || manifestStat.size > MAX_MANIFEST_BYTES || signatureStat.size > MAX_SIG_BYTES) {
|
|
907
1080
|
throw new BundleVerificationError(
|
|
908
1081
|
"member_unreadable",
|
|
909
1082
|
"installed bundle manifest/signature is not a capped regular file"
|
|
910
1083
|
);
|
|
911
1084
|
}
|
|
912
|
-
manifestBytes = await
|
|
913
|
-
signature = await
|
|
1085
|
+
manifestBytes = await import_node_fs2.promises.readFile(manifestPath);
|
|
1086
|
+
signature = await import_node_fs2.promises.readFile(signaturePath);
|
|
914
1087
|
} catch (error) {
|
|
915
1088
|
if (error instanceof BundleVerificationError) {
|
|
916
1089
|
throw error;
|
|
@@ -937,8 +1110,8 @@ async function verifyInstalledBundleDir(installDir, expectations) {
|
|
|
937
1110
|
`installed file not listed in signed manifest: '${relPath}'`
|
|
938
1111
|
);
|
|
939
1112
|
}
|
|
940
|
-
const absolute = (0,
|
|
941
|
-
const stat = await
|
|
1113
|
+
const absolute = (0, import_node_path2.join)(installDir, relPath);
|
|
1114
|
+
const stat = await import_node_fs2.promises.lstat(absolute);
|
|
942
1115
|
if (stat.nlink > 1) {
|
|
943
1116
|
throw new BundleVerificationError(
|
|
944
1117
|
"unsafe_member",
|
|
@@ -994,28 +1167,28 @@ var LOCK_FRESH_MS = 10 * 60 * 1e3;
|
|
|
994
1167
|
var LOCK_WAIT_TIMEOUT_MS = 90 * 1e3;
|
|
995
1168
|
var LOCK_POLL_INTERVAL_MS = 1e3;
|
|
996
1169
|
function currentPlatformKey() {
|
|
997
|
-
const os = (0,
|
|
998
|
-
const arch = (0,
|
|
1170
|
+
const os = (0, import_node_os2.platform)();
|
|
1171
|
+
const arch = (0, import_node_os2.arch)();
|
|
999
1172
|
const osName = os === "darwin" ? "darwin" : os === "linux" ? "linux" : os;
|
|
1000
1173
|
return `${osName}-${arch}`;
|
|
1001
1174
|
}
|
|
1002
1175
|
function cacheDirFor(brand) {
|
|
1003
|
-
const os = (0,
|
|
1176
|
+
const os = (0, import_node_os2.platform)();
|
|
1004
1177
|
if (os === "darwin") {
|
|
1005
|
-
return (0,
|
|
1178
|
+
return (0, import_node_path3.join)((0, import_node_os2.homedir)(), "Library", "Caches", brand, "runtime");
|
|
1006
1179
|
}
|
|
1007
1180
|
if (os === "win32") {
|
|
1008
|
-
const localAppData = process.env.LOCALAPPDATA ?? (0,
|
|
1009
|
-
return (0,
|
|
1181
|
+
const localAppData = process.env.LOCALAPPDATA ?? (0, import_node_path3.join)((0, import_node_os2.homedir)(), "AppData", "Local");
|
|
1182
|
+
return (0, import_node_path3.join)(localAppData, brand, "runtime");
|
|
1010
1183
|
}
|
|
1011
|
-
const xdgCache = process.env.XDG_CACHE_HOME ?? (0,
|
|
1012
|
-
return (0,
|
|
1184
|
+
const xdgCache = process.env.XDG_CACHE_HOME ?? (0, import_node_path3.join)((0, import_node_os2.homedir)(), ".cache");
|
|
1185
|
+
return (0, import_node_path3.join)(xdgCache, brand.toLowerCase(), "runtime");
|
|
1013
1186
|
}
|
|
1014
1187
|
function runtimeCacheDir() {
|
|
1015
1188
|
const current = cacheDirFor("SQAI");
|
|
1016
|
-
if (!(0,
|
|
1189
|
+
if (!(0, import_node_fs3.existsSync)(current)) {
|
|
1017
1190
|
const legacy = cacheDirFor("Algenta");
|
|
1018
|
-
if (legacy !== current && (0,
|
|
1191
|
+
if (legacy !== current && (0, import_node_fs3.existsSync)(legacy)) {
|
|
1019
1192
|
return legacy;
|
|
1020
1193
|
}
|
|
1021
1194
|
}
|
|
@@ -1034,12 +1207,12 @@ async function defaultDownloadBundle(url, destination) {
|
|
|
1034
1207
|
}
|
|
1035
1208
|
await (0, import_promises.pipeline)(
|
|
1036
1209
|
import_node_stream.Readable.fromWeb(response.body),
|
|
1037
|
-
(0,
|
|
1210
|
+
(0, import_node_fs3.createWriteStream)(destination)
|
|
1038
1211
|
);
|
|
1039
1212
|
}
|
|
1040
1213
|
async function removeQuietly(path) {
|
|
1041
1214
|
try {
|
|
1042
|
-
await
|
|
1215
|
+
await import_node_fs3.promises.rm(path, { recursive: true, force: true });
|
|
1043
1216
|
} catch {
|
|
1044
1217
|
}
|
|
1045
1218
|
}
|
|
@@ -1164,7 +1337,7 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
|
|
|
1164
1337
|
localCacheKey(modules, platformKey) {
|
|
1165
1338
|
const canonical = modules.join(",");
|
|
1166
1339
|
const version = this.options.contract.runtime_bundle.version;
|
|
1167
|
-
return (0,
|
|
1340
|
+
return (0, import_node_crypto6.createHash)("sha256").update(`${canonical}|${platformKey}|${version}`).digest("hex").slice(0, 20);
|
|
1168
1341
|
}
|
|
1169
1342
|
/**
|
|
1170
1343
|
* Deterministic per-filter daemon endpoint so a filtered runtime never collides
|
|
@@ -1173,7 +1346,7 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
|
|
|
1173
1346
|
filterEndpoint(cacheKey) {
|
|
1174
1347
|
const seed = parseInt(cacheKey.slice(0, 6), 16) || 0;
|
|
1175
1348
|
const port = 50100 + seed % 800;
|
|
1176
|
-
return { sock: (0,
|
|
1349
|
+
return { sock: (0, import_node_path3.join)(this.cacheDir(), `${cacheKey}.sock`), tcp: `127.0.0.1:${port}` };
|
|
1177
1350
|
}
|
|
1178
1351
|
static DAEMON_ENDPOINT_ENV = [
|
|
1179
1352
|
"ALGENTA_DAEMON_SOCK",
|
|
@@ -1190,7 +1363,7 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
|
|
|
1190
1363
|
process.env.ALGENTA_DAEMON_SOCK = endpoint.sock;
|
|
1191
1364
|
process.env.ALGENTA_DAEMON_TCP = endpoint.tcp;
|
|
1192
1365
|
process.env.ALGENTA_MOJO_SOCK = `${endpoint.sock}.worker`;
|
|
1193
|
-
process.env.ALGENTA_RUNTIME_DIR = (0,
|
|
1366
|
+
process.env.ALGENTA_RUNTIME_DIR = (0, import_node_path3.join)(installDir, ".runtime");
|
|
1194
1367
|
return saved;
|
|
1195
1368
|
}
|
|
1196
1369
|
restoreEnv(saved) {
|
|
@@ -1305,9 +1478,9 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
|
|
|
1305
1478
|
}
|
|
1306
1479
|
/** Verify an existing install if present; returns null when absent/invalid. */
|
|
1307
1480
|
async verifiedInstallOrNull(platformKey, version, removeOnFailure, installKey = version) {
|
|
1308
|
-
const installDir = (0,
|
|
1481
|
+
const installDir = (0, import_node_path3.join)(this.cacheDir(), installKey);
|
|
1309
1482
|
try {
|
|
1310
|
-
await
|
|
1483
|
+
await import_node_fs3.promises.access((0, import_node_path3.join)(installDir, MANIFEST_NAME));
|
|
1311
1484
|
} catch {
|
|
1312
1485
|
return null;
|
|
1313
1486
|
}
|
|
@@ -1327,7 +1500,7 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
|
|
|
1327
1500
|
async acquireLock(lockPath) {
|
|
1328
1501
|
const payload = JSON.stringify({ pid: process.pid, created_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1329
1502
|
try {
|
|
1330
|
-
const handle = await
|
|
1503
|
+
const handle = await import_node_fs3.promises.open(lockPath, "wx");
|
|
1331
1504
|
try {
|
|
1332
1505
|
await handle.writeFile(payload, "utf-8");
|
|
1333
1506
|
} finally {
|
|
@@ -1341,7 +1514,7 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
|
|
|
1341
1514
|
async lockIsStale(lockPath) {
|
|
1342
1515
|
const freshMs = this.options.lockFreshMs ?? LOCK_FRESH_MS;
|
|
1343
1516
|
try {
|
|
1344
|
-
const raw = await
|
|
1517
|
+
const raw = await import_node_fs3.promises.readFile(lockPath, "utf-8");
|
|
1345
1518
|
const parsed = JSON.parse(raw);
|
|
1346
1519
|
const createdAt = typeof parsed.created_at === "string" ? Date.parse(parsed.created_at) : NaN;
|
|
1347
1520
|
if (!Number.isFinite(createdAt)) {
|
|
@@ -1359,12 +1532,12 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
|
|
|
1359
1532
|
/** Serialize installers on `<cacheDir>/<installKey>.lock`; returns the verified install. */
|
|
1360
1533
|
async ensureInstalled(platformKey, version, platformBundle, installKey = version) {
|
|
1361
1534
|
const cacheDir = this.cacheDir();
|
|
1362
|
-
await
|
|
1535
|
+
await import_node_fs3.promises.mkdir(cacheDir, { recursive: true });
|
|
1363
1536
|
const existing = await this.verifiedInstallOrNull(platformKey, version, true, installKey);
|
|
1364
1537
|
if (existing) {
|
|
1365
1538
|
return existing;
|
|
1366
1539
|
}
|
|
1367
|
-
const lockPath = (0,
|
|
1540
|
+
const lockPath = (0, import_node_path3.join)(cacheDir, `${installKey}.lock`);
|
|
1368
1541
|
const waitTimeoutMs = this.options.lockWaitTimeoutMs ?? LOCK_WAIT_TIMEOUT_MS;
|
|
1369
1542
|
const pollIntervalMs = this.options.lockPollIntervalMs ?? LOCK_POLL_INTERVAL_MS;
|
|
1370
1543
|
const deadline = Date.now() + waitTimeoutMs;
|
|
@@ -1409,10 +1582,10 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
|
|
|
1409
1582
|
/** Holder-of-the-lock path: download → verify → extract → atomic rename. */
|
|
1410
1583
|
async downloadVerifyExtract(platformKey, version, platformBundle, installKey = version) {
|
|
1411
1584
|
const cacheDir = this.cacheDir();
|
|
1412
|
-
const token = (0,
|
|
1413
|
-
const tarballPath = (0,
|
|
1414
|
-
const extractDir = (0,
|
|
1415
|
-
const installDir = (0,
|
|
1585
|
+
const token = (0, import_node_crypto6.randomBytes)(6).toString("hex");
|
|
1586
|
+
const tarballPath = (0, import_node_path3.join)(cacheDir, `tmp-${token}.tgz`);
|
|
1587
|
+
const extractDir = (0, import_node_path3.join)(cacheDir, `tmp-${token}`);
|
|
1588
|
+
const installDir = (0, import_node_path3.join)(cacheDir, installKey);
|
|
1416
1589
|
const url = resolveBundleUrl(platformBundle.url, version, platformKey);
|
|
1417
1590
|
try {
|
|
1418
1591
|
const download = this.options.downloadBundle ?? defaultDownloadBundle;
|
|
@@ -1457,7 +1630,7 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
|
|
|
1457
1630
|
throw this.wrapVerificationError(error, platformKey, version);
|
|
1458
1631
|
}
|
|
1459
1632
|
try {
|
|
1460
|
-
await
|
|
1633
|
+
await import_node_fs3.promises.rename(extractDir, installDir);
|
|
1461
1634
|
} catch (error) {
|
|
1462
1635
|
const raced = await this.verifiedInstallOrNull(platformKey, version, false, installKey);
|
|
1463
1636
|
if (raced) {
|
|
@@ -1487,10 +1660,16 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
|
|
|
1487
1660
|
throw this.wrapVerificationError(error, platformKey, version);
|
|
1488
1661
|
}
|
|
1489
1662
|
const daemonCommand = [
|
|
1490
|
-
(0,
|
|
1663
|
+
(0, import_node_path3.join)(installed.installDir, ...entryRelative.split("/")),
|
|
1491
1664
|
"start",
|
|
1492
1665
|
"--foreground"
|
|
1493
1666
|
];
|
|
1667
|
+
if (!process.env.ALGENTA_API_KEY && !process.env.DE_API_KEY) {
|
|
1668
|
+
const key = await readCachedApiKey();
|
|
1669
|
+
if (key) {
|
|
1670
|
+
process.env.ALGENTA_API_KEY = key;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1494
1673
|
const managed = this.newRuntime(
|
|
1495
1674
|
endpoint ? { autoStart: true, daemonCommand, tcpAddress: endpoint.tcp } : { autoStart: true, daemonCommand }
|
|
1496
1675
|
);
|
|
@@ -1524,8 +1703,8 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
|
|
|
1524
1703
|
}
|
|
1525
1704
|
}
|
|
1526
1705
|
try {
|
|
1527
|
-
await
|
|
1528
|
-
(0,
|
|
1706
|
+
await import_node_fs3.promises.writeFile(
|
|
1707
|
+
(0, import_node_path3.join)(this.cacheDir(), "state.json"),
|
|
1529
1708
|
JSON.stringify(
|
|
1530
1709
|
{ pid: null, version, started_at: (/* @__PURE__ */ new Date()).toISOString() },
|
|
1531
1710
|
null,
|
|
@@ -1894,7 +2073,7 @@ var SQAI = class {
|
|
|
1894
2073
|
async compute(spec) {
|
|
1895
2074
|
const resolvedBindings = await this.resolveBindings(spec.bindings ?? []);
|
|
1896
2075
|
const validated = validateComputation(spec, this.contractIndex, this.policy, resolvedBindings);
|
|
1897
|
-
const requestId = `sqai_${(0,
|
|
2076
|
+
const requestId = `sqai_${(0, import_node_crypto7.randomBytes)(8).toString("hex")}`;
|
|
1898
2077
|
const target = await this.dispatchTarget();
|
|
1899
2078
|
const outcome = await dispatchComputation(
|
|
1900
2079
|
target,
|
|
@@ -1937,7 +2116,7 @@ var SQAI = class {
|
|
|
1937
2116
|
runtime_bundle_version: bundle.version || "unmanaged",
|
|
1938
2117
|
runtime_bundle_sha256: platformBundle?.sha256 ?? "unmanaged",
|
|
1939
2118
|
platform: currentPlatformKey(),
|
|
1940
|
-
architecture: (0,
|
|
2119
|
+
architecture: (0, import_node_os3.arch)(),
|
|
1941
2120
|
kernel_build: outcome.engine_used,
|
|
1942
2121
|
precision_mode: "float64",
|
|
1943
2122
|
thread_count: 1,
|
|
@@ -2091,6 +2270,7 @@ function mapSource(registration) {
|
|
|
2091
2270
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2092
2271
|
0 && (module.exports = {
|
|
2093
2272
|
ContractIndex,
|
|
2273
|
+
LoginError,
|
|
2094
2274
|
ResultStore,
|
|
2095
2275
|
RuntimeProvisioner,
|
|
2096
2276
|
SQAI,
|
|
@@ -2101,8 +2281,12 @@ function mapSource(registration) {
|
|
|
2101
2281
|
currentPlatformKey,
|
|
2102
2282
|
invocationHash,
|
|
2103
2283
|
isReadOnlyEligible,
|
|
2284
|
+
login,
|
|
2285
|
+
logout,
|
|
2104
2286
|
lookupCapability,
|
|
2287
|
+
readCachedApiKey,
|
|
2105
2288
|
runtimeCacheDir,
|
|
2289
|
+
sqaiHome,
|
|
2106
2290
|
validateComputation
|
|
2107
2291
|
});
|
|
2108
2292
|
//# sourceMappingURL=index.cjs.map
|