querysub 0.471.0 → 0.473.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.471.0",
3
+ "version": "0.473.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",
@@ -1664,7 +1664,7 @@ export class PathValueProxyWatcher {
1664
1664
 
1665
1665
  let maxLocks = watcher.options.maxLocksOverride || DEFAULT_MAX_LOCKS;
1666
1666
  if (locks.length > maxLocks) {
1667
- throw new Error(`Too many locks for ${watcher.debugName} (${locks.length} > ${maxLocks}). Use Querysub.noLocks(() => ...) around code that is accessing too many values, assuming you don't want to lock them. You can override max locks with maxLocksOverride (in options / functionMetadata). Some locks are ${JSON.stringify(locks.slice(0, 3).map(x => ({ path: x.path, startTime: x.startTime, endTime: x.endTime })))}.`);
1667
+ throw new Error(`Too many locks for ${watcher.debugName} (${locks.length} > ${maxLocks}). Use Querysub.noLocks(() => ...) around code that is accessing too many values, assuming you don't want to lock them. You can override max locks with maxLocksOverride (in options / functionMetadata). Some write keys (which will be lost) are: ${JSON.stringify(Array.from(watcher.pendingWrites.keys()).slice(-10))}. Some locks are ${JSON.stringify(locks.slice(-10).map(x => ({ path: x.path, startTime: x.startTime, endTime: x.endTime })))}.`);
1668
1668
  }
1669
1669
 
1670
1670
 
@@ -144,6 +144,10 @@ export function writeFunctionCall(config: {
144
144
  }) {
145
145
  let { domainName, moduleId, functionId, args, metadata } = config;
146
146
 
147
+ if (isNode() && !curInterceptor) {
148
+ throw new Error(`Naked function writes are not allowed serverside. Wrap your code in a Querysub.commitAsync!`);
149
+ }
150
+
147
151
  // NOTE: Having this be an always-increasing time means that at least if it's the same client making the call ID, the numbers will always be increasing. So we can go from the call ID to determine the order of the calls, which is extremely useful.
148
152
  let now = getTimeUnique();
149
153
  // IMPORTANT! CallId MUST be secure, otherwise other users can guess it, and read our calls
@@ -0,0 +1,100 @@
1
+ import { css } from "typesafecss";
2
+ import { InputProps } from "./Input";
3
+ import { qreact } from "../4-dom/qreact";
4
+
5
+ export class InputAutocomplete extends qreact.Component<InputProps & {
6
+ value: string | { value: string };
7
+ label?: string;
8
+ options: string[];
9
+ onChangeValue: (value: string) => void;
10
+ focusOnMount?: boolean;
11
+ }> {
12
+ handleInput = (e: Event) => {
13
+ const input = e.currentTarget as HTMLInputElement;
14
+ const inputEvent = e as InputEvent;
15
+
16
+ // Only autocomplete on text insertion, not deletion
17
+ if (!inputEvent.inputType || !inputEvent.inputType.startsWith("insert")) {
18
+ return;
19
+ }
20
+
21
+ const selectionStart = input.selectionStart || 0;
22
+ const userTyped = input.value.slice(0, selectionStart);
23
+
24
+ if (!userTyped) {
25
+ return;
26
+ }
27
+
28
+ // Find matching character names
29
+ const options = this.props.options;
30
+ const lowerUserTyped = userTyped.toLowerCase();
31
+ const match = options.find(name =>
32
+ name.toLowerCase().startsWith(lowerUserTyped)
33
+ );
34
+
35
+ if (match) {
36
+ // Replace with the matched name's casing
37
+ input.value = match;
38
+ input.setSelectionRange(userTyped.length, match.length);
39
+ }
40
+ };
41
+
42
+ handleKeyDown = (e: KeyboardEvent) => {
43
+ const input = e.currentTarget as HTMLInputElement;
44
+
45
+ if (e.key === "Tab" || e.key === "Enter") {
46
+ e.preventDefault();
47
+ this.props.onChangeValue(input.value);
48
+ input.blur();
49
+ } else if (e.key === "Escape") {
50
+ input.value = this.getValue();
51
+ input.blur();
52
+ }
53
+ };
54
+
55
+ handleBlur = (e: FocusEvent) => {
56
+ const input = e.currentTarget as HTMLInputElement;
57
+ this.props.onChangeValue(input.value);
58
+ };
59
+ getValue() {
60
+ if (typeof this.props.value === "string") {
61
+ return this.props.value;
62
+ }
63
+ return this.props.value.value;
64
+ }
65
+
66
+ render() {
67
+ let { value, options, onChangeValue, focusOnMount, ...nativeProps } = this.props;
68
+ const styleClass = (
69
+ css.border("1px solid hsl(0, 0%, 50%)", "soft")
70
+ .background("hsl(0, 0%, 7%)", "soft")
71
+ .color("hsl(0, 0%, 95%)", "soft")
72
+ .display("flex", "soft")
73
+ .outline("3px solid hsl(204, 100%, 50%)", "focus", "soft")
74
+ + " " + css.width("100%", "soft")
75
+ + " " + (nativeProps.className || "")
76
+ );
77
+ return (
78
+ <input
79
+ {...nativeProps as any}
80
+ ref={elem => {
81
+ if (elem) {
82
+ elem.value = this.getValue();
83
+ if (focusOnMount) {
84
+ setTimeout(() => {
85
+ elem.focus();
86
+ elem.select();
87
+ }, 0);
88
+ }
89
+ }
90
+ }}
91
+ type="text"
92
+ onFocus={e => (e.currentTarget as HTMLInputElement).select()}
93
+ onInput={this.handleInput}
94
+ onKeyDown={this.handleKeyDown}
95
+ onBlur={this.handleBlur}
96
+ className={styleClass}
97
+ />
98
+ );
99
+ }
100
+ }
@@ -12,9 +12,9 @@ function onUncaught(...args: unknown[]) {
12
12
  }
13
13
  // Ignore ResizeObserver errors, they are spurious
14
14
  // - https://github.com/vercel/next.js/discussions/51551
15
- if (error.message.startsWith("ResizeObserver loop")) return;
15
+ if (error.message?.startsWith("ResizeObserver loop")) return;
16
16
  // We should really do this better. Basically, if we're disposing or canceling, it's not actually an error, just ignore it.
17
- if (error.message.startsWith("Dispose")) return;
17
+ if (error.message?.startsWith("Dispose")) return;
18
18
 
19
19
  onMessage({
20
20
  type: "error",