querysub 0.535.0 → 0.536.0
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/.claude/settings.local.json +2 -1
- package/appSecrets.ts +74 -4
- package/package.json +3 -3
- package/src/-a-archives/archives.ts +1 -1
- package/src/-a-archives/archivesBackBlaze.ts +1 -14
- package/src/deployManager/machineApplyMainCode.ts +12 -2
- package/src/deployManager/setupMachineMain.ts +1 -1
- package/src/-b-authorities/cloudflareHelpers.ts +0 -20
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"WebFetch(domain:blog.cloudflare.com)",
|
|
31
31
|
"WebFetch(domain:developers.cloudflare.com)",
|
|
32
32
|
"PowerShell(yarn type *)",
|
|
33
|
-
"PowerShell(Remove-Item -Confirm:$false \"C:\\\\Users\\\\quent\\\\.claude\\\\projects\\\\D--repos-querysub\\\\memory\\\\no-naming-new-bins.md\")"
|
|
33
|
+
"PowerShell(Remove-Item -Confirm:$false \"C:\\\\Users\\\\quent\\\\.claude\\\\projects\\\\D--repos-querysub\\\\memory\\\\no-naming-new-bins.md\")",
|
|
34
|
+
"Bash(python -)"
|
|
34
35
|
]
|
|
35
36
|
}
|
|
36
37
|
}
|
package/appSecrets.ts
CHANGED
|
@@ -1,12 +1,82 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import os from "os";
|
|
3
|
+
import { isNode } from "socket-function/src/misc";
|
|
4
|
+
import { lazy } from "socket-function/src/caching";
|
|
5
|
+
import { ArchivesBackblaze } from "sliftutils/storage/backblaze";
|
|
6
|
+
import { parseArgsFactory } from "./src/misc/rawParams";
|
|
4
7
|
import { Querysub } from "./src/4-querysub/Querysub";
|
|
5
8
|
|
|
9
|
+
// getSecret always imports us relative to the process cwd, so the cwd is the repo root and this matches what getStorageDir would resolve
|
|
10
|
+
const STORAGE_DIR = "./database-storage/";
|
|
11
|
+
|
|
12
|
+
// querysubConfig and getDomain are copied verbatim from src/config.ts, so this file has no dependencies on our own application (parseArgsFactory is fine to import, as it has no dependencies of its own)
|
|
13
|
+
|
|
14
|
+
let yargObj = parseArgsFactory()
|
|
15
|
+
.option("domain", { type: "string", desc: `Sets the domain` })
|
|
16
|
+
.argv
|
|
17
|
+
;
|
|
18
|
+
|
|
19
|
+
type QuerysubConfig = {
|
|
20
|
+
domain?: string;
|
|
21
|
+
emaildomain?: string;
|
|
22
|
+
notifyemails?: string[];
|
|
23
|
+
};
|
|
24
|
+
let querysubConfig = lazy((): QuerysubConfig => {
|
|
25
|
+
if (!isNode()) throw new Error("querysubConfig is only available on the server");
|
|
26
|
+
const path = "./querysub.json";
|
|
27
|
+
if (!fs.existsSync(path)) {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(fs.readFileSync(path, "utf8"));
|
|
32
|
+
} catch (e) {
|
|
33
|
+
console.error("Error parsing querysub.json", e);
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export function getDomain() {
|
|
39
|
+
if (!isNode()) {
|
|
40
|
+
return location.hostname.split(".").slice(-2).join(".");
|
|
41
|
+
}
|
|
42
|
+
return yargObj.domain || querysubConfig().domain || "querysub.com";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const keysArchives = lazy(() => new ArchivesBackblaze({ bucketName: getDomain() }));
|
|
46
|
+
|
|
47
|
+
export function getBackblazePath() {
|
|
48
|
+
let testPaths = [
|
|
49
|
+
STORAGE_DIR + "backblaze.json",
|
|
50
|
+
os.homedir() + "/backblaze.json",
|
|
51
|
+
];
|
|
52
|
+
for (let path of testPaths) {
|
|
53
|
+
if (fs.existsSync(path)) {
|
|
54
|
+
return path;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return testPaths[0];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const getCloudflareCreds = lazy(async (): Promise<{ key: string; email: string }> => {
|
|
61
|
+
let archives = keysArchives();
|
|
62
|
+
let credsJSON = await archives.get("keys/cloudflare.json");
|
|
63
|
+
if (!credsJSON) {
|
|
64
|
+
let localPath = STORAGE_DIR + "cloudflare.json";
|
|
65
|
+
if (fs.existsSync(localPath)) {
|
|
66
|
+
credsJSON = fs.readFileSync(localPath);
|
|
67
|
+
await archives.set("keys/cloudflare.json", credsJSON);
|
|
68
|
+
} else {
|
|
69
|
+
throw new Error(`b2:/keys/cloudflare.json is missing. It should contain { "key": "your-key", "email": "your-email" }`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return JSON.parse(credsJSON.toString());
|
|
73
|
+
});
|
|
74
|
+
|
|
6
75
|
/** Serves the secret keys sliftutils' getSecret expects, reading them the way querysub already does: backblaze creds off disk (getBackblazePath), cloudflare creds from the keys archives bucket (with its local file fallback). */
|
|
7
76
|
export async function getAppSecret(key: string): Promise<string | undefined> {
|
|
8
|
-
//
|
|
9
|
-
|
|
77
|
+
// todonext;
|
|
78
|
+
// Add this back after we finish testing. We need this in order to get logging, but for testing, It just adds extra logging, which is annoying and slows down runs.
|
|
79
|
+
// Querysub;
|
|
10
80
|
if (key.startsWith("backblaze.json.")) {
|
|
11
81
|
let creds = JSON.parse(fs.readFileSync(getBackblazePath(), "utf8")) as { applicationKeyId?: string; applicationKey?: string };
|
|
12
82
|
if (key === "backblaze.json.applicationKeyId") return creds.applicationKeyId;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "querysub",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.536.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
|
|
@@ -71,8 +71,8 @@
|
|
|
71
71
|
"node-forge": "https://github.com/sliftist/forge#e618181b469b07bdc70b968b0391beb8ef5fecd6",
|
|
72
72
|
"pako": "^2.1.0",
|
|
73
73
|
"peggy": "^5.0.6",
|
|
74
|
-
"sliftutils": "^1.7.
|
|
75
|
-
"socket-function": "^1.2.
|
|
74
|
+
"sliftutils": "^1.7.20",
|
|
75
|
+
"socket-function": "^1.2.25",
|
|
76
76
|
"terser": "^5.31.0",
|
|
77
77
|
"typenode": "^6.6.1",
|
|
78
78
|
"typesafecss": "^0.32.0",
|
|
@@ -18,7 +18,7 @@ export interface Archives {
|
|
|
18
18
|
// Skips checking if the file exists on the remote. Only appropriate when the file name is fresh (recently obtained from find).
|
|
19
19
|
fastRead?: boolean;
|
|
20
20
|
}): Promise<Buffer | undefined>;
|
|
21
|
-
set(path: string, data: Buffer): Promise<void>;
|
|
21
|
+
set(path: string, data: Buffer): Promise<string | void>;
|
|
22
22
|
del(path: string): Promise<void>;
|
|
23
23
|
|
|
24
24
|
append(path: string, data: Buffer): Promise<void>;
|
|
@@ -1,28 +1,15 @@
|
|
|
1
1
|
import { cache } from "socket-function/src/caching";
|
|
2
|
-
import { getStorageDir } from "../fs";
|
|
3
2
|
import { Archives } from "./archives";
|
|
4
3
|
import fs from "fs";
|
|
5
|
-
import os from "os";
|
|
6
4
|
import { isNode, timeInMinute } from "socket-function/src/misc";
|
|
7
5
|
import { isLogBackblaze } from "../config";
|
|
6
|
+
import { getBackblazePath } from "../../appSecrets";
|
|
8
7
|
import { ArchivesBackblaze as ArchivesBackblazeBase } from "sliftutils/storage/backblaze";
|
|
9
8
|
import type { IArchives, ArchivesConfig } from "sliftutils/storage/IArchives";
|
|
10
9
|
|
|
11
10
|
export function hasBackblazePermissions() {
|
|
12
11
|
return isNode() && fs.existsSync(getBackblazePath());
|
|
13
12
|
}
|
|
14
|
-
export function getBackblazePath() {
|
|
15
|
-
let testPaths = [
|
|
16
|
-
getStorageDir() + "backblaze.json",
|
|
17
|
-
os.homedir() + "/backblaze.json",
|
|
18
|
-
];
|
|
19
|
-
for (let path of testPaths) {
|
|
20
|
-
if (fs.existsSync(path)) {
|
|
21
|
-
return path;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return testPaths[0];
|
|
25
|
-
}
|
|
26
13
|
|
|
27
14
|
// The implementation lives in sliftutils (it reads credentials via getSecret, which our appSecrets.ts serves from getBackblazePath). We forward to an inner instance instead of subclassing, because our Archives interface's move/copy take a querysub Archives target (with getBaseArchives unwrapping) which is type-incompatible with the base class's IArchives signatures.
|
|
28
15
|
export class ArchivesBackblaze {
|
|
@@ -696,7 +696,7 @@ const resyncServicesBase = runInSerial(measureWrap(async function resyncServices
|
|
|
696
696
|
try {
|
|
697
697
|
await ensureOldInstance({
|
|
698
698
|
old: { ...oldParameters, command: applyCommandTemplate(oldParameters.command, oldTargets[i].variables) },
|
|
699
|
-
aliveWindow: [releaseTime, releaseTime + overlapTime],
|
|
699
|
+
aliveWindow: [oldParameters.releaseTime || 0, releaseTime + overlapTime],
|
|
700
700
|
index: i,
|
|
701
701
|
screenNamesUsed,
|
|
702
702
|
screenStateMap,
|
|
@@ -764,9 +764,10 @@ const resyncServicesBase = runInSerial(measureWrap(async function resyncServices
|
|
|
764
764
|
let screenIsRunning = screenStateMap.get(screenName)?.isProcessRunning;
|
|
765
765
|
|
|
766
766
|
const syncTimeline = async (pid: string | undefined) => {
|
|
767
|
+
// The windows overlap: a version runs from its releaseTime until the NEXT version's releaseTime + overlapTime (the overlap is when both run)
|
|
767
768
|
let entries: ParametersTimelineEntry[] = [{
|
|
768
769
|
pid: parseInt(pid || "") || undefined,
|
|
769
|
-
aliveWindow: [config.parameters.releaseTime || 0, isUpcomingRelease ? releaseTime : ALIVE_WINDOW_FOREVER],
|
|
770
|
+
aliveWindow: [config.parameters.releaseTime || 0, isUpcomingRelease ? releaseTime + overlapTime : ALIVE_WINDOW_FOREVER],
|
|
770
771
|
parameters: instanceParameters,
|
|
771
772
|
}];
|
|
772
773
|
if (isUpcomingRelease) {
|
|
@@ -778,6 +779,15 @@ const resyncServicesBase = runInSerial(measureWrap(async function resyncServices
|
|
|
778
779
|
});
|
|
779
780
|
}
|
|
780
781
|
}
|
|
782
|
+
if (isOverlapRunning && record.oldParameters) {
|
|
783
|
+
let oldTargets = getMachineTargets(record.oldParameters).filter(target => target.machineId === machineId);
|
|
784
|
+
if (i < oldTargets.length) {
|
|
785
|
+
entries.push({
|
|
786
|
+
aliveWindow: [record.oldParameters.releaseTime || 0, releaseTime + overlapTime],
|
|
787
|
+
parameters: { ...record.oldParameters, command: applyCommandTemplate(record.oldParameters.command, oldTargets[i].variables) },
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
}
|
|
781
791
|
await syncParametersTimelineFiles(folder, entries);
|
|
782
792
|
};
|
|
783
793
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getBackblazePath } from "
|
|
1
|
+
import { getBackblazePath } from "../../appSecrets";
|
|
2
2
|
import { getGitURLLive, getGitRefLive } from "../4-deploy/git";
|
|
3
3
|
import { Querysub } from "../4-querysub/Querysub";
|
|
4
4
|
import { runPromise } from "../functional/runCommand";
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { getArchives } from "../-a-archives/archives";
|
|
2
|
-
import { lazy } from "socket-function/src/caching";
|
|
3
|
-
import { getStorageDir } from "../fs";
|
|
4
|
-
import fs from "fs";
|
|
5
|
-
|
|
6
|
-
const keys = lazy(() => getArchives("keys"));
|
|
7
|
-
|
|
8
|
-
export const getCloudflareCreds = lazy(async (): Promise<{ key: string; email: string }> => {
|
|
9
|
-
let credsJSON = await keys().get("cloudflare.json");
|
|
10
|
-
if (!credsJSON) {
|
|
11
|
-
let localPath = getStorageDir() + "cloudflare.json";
|
|
12
|
-
if (fs.existsSync(localPath)) {
|
|
13
|
-
credsJSON = fs.readFileSync(localPath);
|
|
14
|
-
await keys().set("cloudflare.json", credsJSON);
|
|
15
|
-
} else {
|
|
16
|
-
throw new Error(`b2:/keys/cloudflare.json is missing. It should contain { "key": "your-key", "email": "your-email" }`);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return JSON.parse(credsJSON.toString());
|
|
20
|
-
});
|