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.
@@ -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 { getBackblazePath } from "./src/-a-archives/archivesBackBlaze";
3
- import { getCloudflareCreds } from "./src/-b-authorities/cloudflareHelpers";
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
- // Use this so some of our default imports get imported
9
- Querysub;
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.535.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.18",
75
- "socket-function": "^1.2.24",
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 "../-a-archives/archivesBackBlaze";
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
- });