querysub 0.154.0 → 0.155.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "querysub",
3
- "version": "0.154.0",
3
+ "version": "0.155.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",
@@ -24,7 +24,7 @@
24
24
  "node-forge": "https://github.com/sliftist/forge#e618181b469b07bdc70b968b0391beb8ef5fecd6",
25
25
  "pako": "^2.1.0",
26
26
  "preact": "^10.11.3",
27
- "socket-function": "^0.87.0",
27
+ "socket-function": "^0.88.0",
28
28
  "terser": "^5.31.0",
29
29
  "typesafecss": "^0.6.3",
30
30
  "yaml": "^2.5.0",
@@ -137,11 +137,13 @@ export async function deployMain() {
137
137
  debugName: "setLiveDeployedHash",
138
138
  inlineNestedWatchers: true,
139
139
  watchFunction: () => {
140
- if (!yargObj.deployonlycode) {
140
+ if (yargObj.deployonlycode) {
141
141
  void setLiveDeployedHash({ hash: gitRef, refreshThresholdTime, });
142
- }
143
- if (!yargObj.deployonlyui) {
142
+ } else if (yargObj.deployonlyui) {
143
+ void replaceFunctions({ domainName, functions: currentFunctions, });
144
+ } else {
144
145
  void replaceFunctions({ domainName, functions: currentFunctions, });
146
+ void setLiveDeployedHash({ hash: gitRef, refreshThresholdTime, });
145
147
  }
146
148
  },
147
149
  });
@@ -79,6 +79,7 @@ export namespace qreact {
79
79
  export type ComponentChildren = preact.ComponentChildren;
80
80
  export type VDom = preact.ComponentChildren;
81
81
  export type Component = InstanceType<typeof Component>;
82
+ export type ComponentClass = preact.ComponentClass;
82
83
  export namespace JSX {
83
84
  export type IntrinsicElements = {
84
85
  [key in keyof preact.JSX.IntrinsicElements]: (
@@ -41,7 +41,8 @@ if (isNode()) {
41
41
  .replaceAll(` logDisk(`, ` logDisk(console.__context, { __LINE__: ${index} },`)
42
42
  ;
43
43
  }).join("\n");
44
- return `var console = (${shimConsole.toString()})();\n${contents}`;
44
+ // IMPORTANT! No newlines, so the line numbers match up with the original source.
45
+ return `var console = (${shimConsole.toString().replaceAll("\n", " ")})(); ${contents}`;
45
46
  });
46
47
 
47
48
  // We want to call shimConsoleLogs early. Before we call it, our additional context isn't
@@ -63,14 +63,19 @@ export function createURLSync<T>(urlKey: string, defaultValue: T, config?: {
63
63
  if (config?.storage === "localStorage") {
64
64
  localStorageKeys.add(urlKey);
65
65
  }
66
- setImmediate(() => {
66
+ function setDefaults() {
67
67
  Querysub.localCommit(() => {
68
68
  data().defaults[urlKey] = defaultValue;
69
69
  if (!(urlKey in loadSearchCache)) {
70
70
  data().params[urlKey] = deepCloneJSON(defaultValue);
71
71
  }
72
72
  });
73
- });
73
+ }
74
+ if (!Querysub) {
75
+ setImmediate(setDefaults);
76
+ } else {
77
+ setDefaults();
78
+ }
74
79
  function deleteKeys(obj: any) {
75
80
  if (!canHaveChildren(obj)) return;
76
81
  for (let key in obj) {
@@ -0,0 +1,93 @@
1
+ import { qreact } from "../4-dom/qreact";
2
+ import { Querysub } from "../4-querysub/Querysub";
3
+ import { css } from "typesafecss";
4
+ import { formatNumber, formatTime } from "socket-function/src/formatting/format";
5
+
6
+ export class UnsyncedIndicator extends qreact.Component {
7
+ lastSynced = Date.now();
8
+ render() {
9
+ let unsynced = Querysub.watchUnsyncedComponents();
10
+ let unsyncedCount = unsynced.size;
11
+ if (unsyncedCount === 0) {
12
+ this.lastSynced = Date.now();
13
+ return undefined;
14
+ }
15
+ let timeSinceLastSync = Date.now() - this.lastSynced;
16
+ if (timeSinceLastSync < 1500) {
17
+ return undefined;
18
+ }
19
+ if (timeSinceLastSync > 30 * 1000) {
20
+ return (
21
+ <div
22
+ title={`Server has not responded for ${formatTime(timeSinceLastSync)}`}
23
+ className={
24
+ css.vbox(10).pad(20)
25
+ .hsla(0, 0, 0, 0.8)
26
+ .position("fixed")
27
+ .bottom(10)
28
+ .right(10)
29
+ .zIndex(1000)
30
+ }
31
+ >
32
+ <div className={css.vbox(10).maxWidth(250)}>
33
+ <h3 className={css.margin(0)}>Server Not Responding</h3>
34
+ <div>The server has not responded for {formatTime(timeSinceLastSync)}. It is recommended to refresh the page to try to resolve this issue.</div>
35
+ </div>
36
+ <div className={css.hbox(10).justifyContent("flex-end")}>
37
+ <button
38
+ className={css.pad(8, 16).hsl(200, 50, 50).color("white").pointer}
39
+ onClick={() => {
40
+ window.location.reload();
41
+ }}
42
+ >
43
+ Refresh Now
44
+ </button>
45
+ </div>
46
+ </div>
47
+ );
48
+ }
49
+ let magnitude = Math.ceil(Math.log2(unsyncedCount + 1) / Math.log2(6));
50
+ return <div
51
+ class={
52
+ css
53
+ .position("fixed").bottom(0).right(0)
54
+ .background("hsl(0, 0%, 10%)").color("hsl(0, 0%, 80%)")
55
+ .fontSize(12).zIndex(1000)
56
+ .borderRadius(100)
57
+ }
58
+ title={`Loading data for ${formatNumber(unsyncedCount)} components`}
59
+ >
60
+ <svg
61
+ width="60px" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"
62
+
63
+ >
64
+ {
65
+ [
66
+ // The smaller they are, the faster they should go
67
+ // Large should be more blue, smaller more red
68
+ ["hsl(-20, 75%, 75%)", "1.5", "1s", "10"],
69
+ ["hsl(-5, 75%, 75%)", "2", "1.5s", "15"],
70
+ ["hsl(-35, 75%, 75%)", "1", "0.5s", "5"],
71
+ ["hsl(10, 75%, 75%)", "2.5", "2s", "20"],
72
+ ["hsl(25, 75%, 75%)", "3", "2.5s", "25"],
73
+ ["hsl(70, 75%, 75%)", "3.5", "3s", "30"],
74
+ ["hsl(115, 75%, 75%)", "4", "3.5s", "35"],
75
+ ["hsl(160, 75%, 75%)", "4.5", "4s", "40"],
76
+ ["hsl(205, 75%, 75%)", "5", "4.5s", "45"],
77
+ ["hsl(230, 75%, 75%)", "5.5", "5s", "50"],
78
+ ].slice(0, magnitude).map(([color, r, dur, o]) =>
79
+ <circle cx="50" cy={50 + Number(o)} r={Number(r) * 2} fill={color}>
80
+ <animateTransform
81
+ attributeName="transform"
82
+ type="rotate"
83
+ from={`0 50 50`} to={`360 50 50`}
84
+ dur={dur} repeatCount="indefinite"
85
+ />
86
+ </circle>
87
+ )
88
+ }
89
+ </svg>
90
+
91
+ </div>;
92
+ }
93
+ }
@@ -43,7 +43,7 @@ export class LoginPage extends qreact.Component {
43
43
  </>;
44
44
  }
45
45
  return (
46
- <div class={css.vbox(60).fillWidth.center.fontSize(20)}>
46
+ <div class={css.vbox(60).fillBoth.center.fontSize(20)}>
47
47
  <div class={css.vbox(10)}>
48
48
  {contents}
49
49
  </div>
@@ -239,7 +239,7 @@ export class UserPage extends qreact.Component {
239
239
  {isSuper &&
240
240
  <div class={css.hbox(10).padv(6)}>
241
241
  <InputLabel
242
- label="Adds Remaining"
242
+ label="Invites Remaining"
243
243
  number
244
244
  value={userObj.invitesRemaining}
245
245
  onChange={e => {
@@ -1,14 +1,20 @@
1
1
  import { Querysub } from "../4-querysub/Querysub";
2
2
  import { scriptCreateUser } from "./userData";
3
3
  import { pathValueCommitter } from "../0-path-value-core/PathValueCommitter";
4
+ import yargs from "yargs";
5
+ import { isNodeTrue } from "socket-function/src/misc";
6
+
7
+ let yargObj = isNodeTrue() && yargs(process.argv)
8
+ .option("email", { type: "string", desc: `The email of the user to add as a superuser.` })
9
+ .argv || {}
10
+ ;
4
11
 
5
12
  async function main() {
6
- const howToCall = ` Call with yarn addsuperuser <email>`;
7
- const args = process.argv.slice(2).filter(x => !x.startsWith("--"));
8
- const userId = args[0];
9
- console.log(process.argv);
10
- if (!userId) throw new Error("No userId provided." + howToCall);
11
- if (!userId.includes("@")) throw new Error(`Invalid email ${userId}.` + howToCall);
13
+ const howToCall = ` Call with yarn addsuperuser --email <email>`;
14
+ const email = yargObj.email;
15
+ if (!email) throw new Error("No email provided." + howToCall);
16
+ if (!email.includes("@")) throw new Error(`Invalid email ${email}.` + howToCall);
17
+ const userId = email;
12
18
 
13
19
  await Querysub.hostService("addSuperUser");
14
20
 
@@ -1,15 +1,20 @@
1
1
  import { Querysub } from "../4-querysub/Querysub";
2
2
  import { pathValueCommitter } from "../0-path-value-core/PathValueCommitter";
3
3
  import { scriptSetPostmarkAPIKey } from "./userData";
4
+ import { isNodeTrue } from "socket-function/src/misc";
5
+ import yargs from "yargs";
6
+
7
+ let yargObj = isNodeTrue() && yargs(process.argv)
8
+ .option("key", { type: "string", desc: `The key to set for the email.` })
9
+ .argv || {}
10
+ ;
4
11
 
5
12
  async function main() {
6
- const howToCall = ` Call with yarn setemailkey <key>`;
7
- const args = process.argv.slice(2).filter(x => !x.startsWith("--"));
8
- const key = args[0];
9
- console.log(process.argv);
13
+ const howToCall = ` Call with yarn setemailkey --key <key>`;
14
+ const key = yargObj.key;
10
15
  if (!key) throw new Error("No key provided." + howToCall);
11
16
 
12
- await Querysub.hostService("setSendgridKey");
17
+ await Querysub.hostService("setEmailKey");
13
18
 
14
19
  await Querysub.commitSynced(() => {
15
20
  scriptSetPostmarkAPIKey({ apiKey: key });
@@ -651,6 +651,8 @@ function sendLoginEmail(config: {
651
651
  await sendEmail_postmark({
652
652
  apiKey,
653
653
  to: email,
654
+ // TODO: Allow configuring this (defaulting to getDomain() if unconfigured). For now we hardcode it, because it takes
655
+ // a while to verify a new postmark email, and we don't even know what final domain we will be using.
654
656
  from: "login@querysub.com",
655
657
  subject,
656
658
  contents,