querysub 0.186.0 → 0.187.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.186.0",
3
+ "version": "0.187.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",
@@ -128,15 +128,19 @@ export class RemoteWatcher {
128
128
  public watchLatest(config: WatchConfig & { debugName?: string }) {
129
129
  logErrors(this.watchLatestPromise(config));
130
130
  }
131
+ // IMPORTANT! If this shows up as being slow in a profile, try again with devtools closed! It is often slow because async calls are many times slower when devtools is open...
131
132
  // NOTE: This is private, as who wants to wait for watch to finish?
132
133
  // 1) The value won't be ready when it finishes.
133
134
  // 2) If it errors out, they can't do anything to fix the error
134
135
  // 3) We retry internally anyways
135
136
  private watchLatestPromise(config: WatchConfig & { debugName?: string }) {
136
- // NOTE: If none of the values are remote... early out. This has been profile to save a bit of time,
137
+ // NOTE: If none of the values are remote... early out. This has been profiled to save a bit of time,
137
138
  // mostly due to avoiding the async call.
138
- if (config.parentPaths.length === 0 && config.paths.every(x => pathValueAuthority2.isSelfAuthority(x))) {
139
- return;
139
+ if (config.parentPaths.length === 0) {
140
+ let isSelf = measureBlock(() => config.paths.every(x => pathValueAuthority2.isSelfAuthority(x)), "RemoteWatcher()|watchLatestPromise|isSelfCheck");
141
+ if (isSelf) {
142
+ return;
143
+ }
140
144
  }
141
145
  return this.watchLatestBase(config);
142
146
  }
@@ -440,6 +440,7 @@ export class ClientWatcher {
440
440
  this.allWatchers.delete(callback);
441
441
  }
442
442
 
443
+ @measureFnc
443
444
  private updateUnwatches(watchSpec: WatchSpec) {
444
445
  const { callback, paths, parentPaths } = watchSpec;
445
446
  let prevSpec = this.allWatchers.get(callback);
@@ -488,14 +489,15 @@ export class ClientWatcher {
488
489
  watchSpec = prevSpec;
489
490
 
490
491
  let expiryTime = Date.now() + ClientWatcher.WATCH_STICK_TIME;
491
- if (isDevDebugbreak()) {
492
- for (let path of fullyUnwatchedPaths) {
493
- auditLog("clientWatcher UNWATCH", { path });
494
- }
495
- for (let path of fullyUnwatchedParents) {
496
- auditLog("clientWatcher UNWATCH PARENT", { path });
497
- }
498
- }
492
+ // Commented out, as this is showing up as a bit slow in profiling
493
+ // if (isDevDebugbreak()) {
494
+ // for (let path of fullyUnwatchedPaths) {
495
+ // auditLog("clientWatcher UNWATCH", { path });
496
+ // }
497
+ // for (let path of fullyUnwatchedParents) {
498
+ // auditLog("clientWatcher UNWATCH PARENT", { path });
499
+ // }
500
+ // }
499
501
  for (let path of fullyUnwatchedPaths) {
500
502
  this.pendingUnwatches.set(path, expiryTime);
501
503
  }
@@ -550,35 +552,39 @@ export class ClientWatcher {
550
552
  this.updateUnwatches(watchSpec);
551
553
 
552
554
  this.allWatchers.set(callback, watchSpec);
553
- for (let path of paths) {
554
- let watchers = this.valueFunctionWatchers.get(path);
555
- if (!watchers) {
556
- watchers = new Map();
557
- this.valueFunctionWatchers.set(path, watchers);
558
- }
559
- watchers.set(callback, watchSpec);
560
- this.pendingUnwatches.delete(path);
561
- }
562
- for (let path of parentPaths) {
563
- let basePath = hack_stripPackedPath(path);
564
- let watchersBase = this.parentValueFunctionWatchers.get(basePath);
565
- if (!watchersBase) {
566
- watchersBase = new Map();
567
- this.parentValueFunctionWatchers.set(basePath, watchersBase);
555
+ measureBlock(() => {
556
+ for (let path of paths) {
557
+ let watchers = this.valueFunctionWatchers.get(path);
558
+ if (!watchers) {
559
+ watchers = new Map();
560
+ this.valueFunctionWatchers.set(path, watchers);
561
+ }
562
+ watchers.set(callback, watchSpec);
563
+ this.pendingUnwatches.delete(path);
568
564
  }
569
- let watchers = watchersBase.get(path);
570
- if (!watchers) {
571
- let range = decodeParentFilter(path) || { start: 0, end: 1 };
572
- watchers = {
573
- start: range.start,
574
- end: range.end,
575
- lookup: new Map()
576
- };
577
- watchersBase.set(path, watchers);
565
+ }, "ClientWatcher()|setWatches|paths");
566
+ measureBlock(() => {
567
+ for (let path of parentPaths) {
568
+ let basePath = hack_stripPackedPath(path);
569
+ let watchersBase = this.parentValueFunctionWatchers.get(basePath);
570
+ if (!watchersBase) {
571
+ watchersBase = new Map();
572
+ this.parentValueFunctionWatchers.set(basePath, watchersBase);
573
+ }
574
+ let watchers = watchersBase.get(path);
575
+ if (!watchers) {
576
+ let range = decodeParentFilter(path) || { start: 0, end: 1 };
577
+ watchers = {
578
+ start: range.start,
579
+ end: range.end,
580
+ lookup: new Map()
581
+ };
582
+ watchersBase.set(path, watchers);
583
+ }
584
+ watchers.lookup.set(callback, watchSpec);
585
+ this.pendingParentUnwatches.delete(path);
578
586
  }
579
- watchers.lookup.set(callback, watchSpec);
580
- this.pendingParentUnwatches.delete(path);
581
- }
587
+ }, "ClientWatcher()|setWatches|parentPaths");
582
588
 
583
589
  // Audit code to check if we failed to correctly maintain our paths
584
590
  // OR (more likely), the watcher mutated the paths Set, which breaks our watching
@@ -604,27 +610,33 @@ export class ClientWatcher {
604
610
  }
605
611
  */
606
612
 
607
- let pathsArray = Array.from(paths);
608
- let parentPathsArray = Array.from(parentPaths);
613
+ let pathsArray!: string[];
614
+ let parentPathsArray!: string[];
615
+ measureBlock(() => {
616
+ pathsArray = Array.from(paths);
617
+ parentPathsArray = Array.from(parentPaths);
618
+ }, "ClientWatcher()|setWatches|Array.from");
609
619
  let debugName = watchSpec.callback.name;
610
620
 
611
621
  if (pathsArray.length === 0 && parentPathsArray.length === 0) {
612
622
  return;
613
623
  }
614
624
 
615
- // Watch it locally as well, so when we get the value we know to trigger the client callback
616
- pathWatcher.watchPath({
617
- callback: getOwnNodeId(),
618
- paths: pathsArray,
619
- parentPaths: parentPathsArray,
620
- debugName,
621
- noInitialTrigger: watchSpec.noInitialTrigger,
622
- });
623
- remoteWatcher.watchLatest({
624
- paths: pathsArray,
625
- parentPaths: parentPathsArray,
626
- debugName,
627
- });
625
+ measureBlock(() => {
626
+ // Watch it locally as well, so when we get the value we know to trigger the client callback
627
+ pathWatcher.watchPath({
628
+ callback: getOwnNodeId(),
629
+ paths: pathsArray,
630
+ parentPaths: parentPathsArray,
631
+ debugName,
632
+ noInitialTrigger: watchSpec.noInitialTrigger,
633
+ });
634
+ remoteWatcher.watchLatest({
635
+ paths: pathsArray,
636
+ parentPaths: parentPathsArray,
637
+ debugName,
638
+ });
639
+ }, "ClientWatcher()|setWatches|watchCalls");
628
640
  }
629
641
 
630
642
  private lastVersions = registerResource("paths|lastVersion", new Map<number, number>());
@@ -32,7 +32,7 @@ import { DEPTH_TO_DATA, MODULE_INDEX, getCurrentCall, getCurrentCallObj } from "
32
32
  import { inlineNestedCalls } from "../3-path-functions/syncSchema";
33
33
  import { interceptCallsBase, runCall } from "../3-path-functions/PathFunctionHelpers";
34
34
  import { deepCloneCborx } from "../misc/cloneHelpers";
35
- import { formatPercent } from "socket-function/src/formatting/format";
35
+ import { formatPercent, formatTime } from "socket-function/src/formatting/format";
36
36
  import { addStatPeriodic, interceptCalls, onAllPredictionsFinished, onTimeProfile } from "../-0-hooks/hooks";
37
37
  import { onNextPaint } from "../functional/onNextPaint";
38
38
 
@@ -202,6 +202,12 @@ export interface WatcherOptions<Result> {
202
202
  * what you want, it depends on the usecase.
203
203
  */
204
204
  runOncePerPaint?: string;
205
+
206
+ /** Logs time to go from unsynced to synced, and the paths that were unloaded.
207
+ * - In order to tell what paths to pre-load, and how much time we are waiting to load data.
208
+ * - Also to tell us how long and how many paths are loading on startup.
209
+ */
210
+ logSyncTimings?: boolean;
205
211
  }
206
212
 
207
213
  let harvestableReadyLoopCount = 0;
@@ -330,6 +336,15 @@ export type SyncWatcher = {
330
336
  hackHistory: { message: string; time: number }[];
331
337
 
332
338
  createTime: number;
339
+
340
+ logSyncTimings?: {
341
+ startTime: number;
342
+ unsyncedPaths: Set<string>;
343
+ unsyncedStages: {
344
+ paths: string[];
345
+ time: number;
346
+ }[];
347
+ };
333
348
  }
334
349
  function addToHistory(watcher: SyncWatcher, message: string) {
335
350
  watcher.hackHistory.push({ message, time: Date.now() });
@@ -860,7 +875,6 @@ export class PathValueProxyWatcher {
860
875
  return getKeys(pathValue?.value) as string[];
861
876
  }
862
877
 
863
- let keys: string[] = [];
864
878
  let childPaths = authorityStorage.getPathsFromParent(pathStr);
865
879
 
866
880
  // We need to also get keys from pendingWrites
@@ -877,23 +891,26 @@ export class PathValueProxyWatcher {
877
891
  }
878
892
  }
879
893
 
894
+ let keys = new Set<string>();
880
895
  if (childPaths) {
881
896
  let targetDepth = getPathDepth(pathStr);
882
897
  for (let childPath of childPaths) {
883
898
  let key = getPathIndexAssert(childPath, targetDepth);
884
899
  let childValue = this.getCallback(childPath, undefined, "readTransparent");
885
900
  if (childValue?.value !== undefined) {
886
- keys.push(key);
901
+ keys.add(key);
887
902
  }
888
903
  }
889
904
  }
890
905
 
906
+ let keysArray = Array.from(keys);
907
+
891
908
  // NOTE: Because getPathsFromParent does not preserve order, we have to sort here to ensure
892
909
  // we provide a consistent order (which might not be the order the user wants, but at least
893
910
  // it will always fail if it does fail).
894
- keys.sort();
911
+ keysArray.sort();
895
912
 
896
- return keys;
913
+ return keysArray;
897
914
  };
898
915
 
899
916
  private getSymbol = (pathStr: string, symbol: symbol): { value: unknown } | undefined => {
@@ -1255,8 +1272,56 @@ export class PathValueProxyWatcher {
1255
1272
  const specialPromiseUnsynced = watcher.specialPromiseUnsynced;
1256
1273
  watcher.specialPromiseUnsynced = false;
1257
1274
 
1275
+ let anyUnsynced = watcher.hasAnyUnsyncedAccesses();
1276
+ if (watcher.options.logSyncTimings) {
1277
+ if (anyUnsynced) {
1278
+ watcher.logSyncTimings = watcher.logSyncTimings || {
1279
+ startTime: Date.now(),
1280
+ unsyncedPaths: new Set(),
1281
+ unsyncedStages: [],
1282
+ };
1283
+ let newPaths: string[] = [];
1284
+ let set = watcher.logSyncTimings.unsyncedPaths;
1285
+ function addPath(path: string) {
1286
+ if (set.has(path)) return;
1287
+ set.add(path);
1288
+ newPaths.push(path);
1289
+ }
1290
+ for (let path of watcher.lastUnsyncedAccesses) {
1291
+ addPath(path);
1292
+ }
1293
+ for (let path of watcher.lastUnsyncedParentAccesses) {
1294
+ addPath(path);
1295
+ }
1296
+ if (newPaths.length > 0) {
1297
+ watcher.logSyncTimings.unsyncedStages.push({
1298
+ paths: newPaths,
1299
+ time: Date.now(),
1300
+ });
1301
+ }
1302
+ } else {
1303
+ if (watcher.logSyncTimings) {
1304
+ let now = Date.now();
1305
+ console.groupCollapsed(`${watcher.debugName} synced in ${formatTime(now - watcher.logSyncTimings.startTime)}`);
1306
+ // Log the stages
1307
+ let stages = watcher.logSyncTimings.unsyncedStages;
1308
+ for (let i = 0; i < stages.length; i++) {
1309
+ let nextTime = stages[i + 1]?.time || now;
1310
+ let stage = stages[i];
1311
+ console.groupCollapsed(`${formatTime(nextTime - stage.time)}`);
1312
+ for (let path of stage.paths) {
1313
+ console.log(path);
1314
+ }
1315
+ console.groupEnd();
1316
+ }
1317
+ console.groupEnd();
1318
+ watcher.logSyncTimings = undefined;
1319
+ }
1320
+ }
1321
+ }
1322
+
1258
1323
  if (!watcher.options.static) {
1259
- if (!watcher.hasAnyUnsyncedAccesses()) {
1324
+ if (!anyUnsynced) {
1260
1325
  watcher.countSinceLastFullSync = 0;
1261
1326
  watcher.lastSyncTime = Date.now();
1262
1327
  watcher.syncRunCount++;
@@ -134,6 +134,9 @@ export interface QComponentStatic {
134
134
  * UNLESS the child explicitly sets this to false.
135
135
  * */
136
136
  multiRendersPerPaint?: boolean;
137
+
138
+ /** If true, logs time it takes for component to load synced data (if at all), and the paths that were unloaded. */
139
+ logLoadTime?: boolean;
137
140
  }
138
141
 
139
142
  /** See QComponentStatic.jsonComparePropUpdates */
@@ -416,7 +419,14 @@ function getAncestor(
416
419
  }
417
420
  function onDispose(fnc: () => void) {
418
421
  let component = getRenderingComponent();
419
- if (!component) throw new Error(`Can only call onDispose if inside of a render (or componentDidMount) function. If an an event callback, call qreact.getRenderingComponent in render, and then call qreact.watchDispose(component, callback).`);
422
+ if (!component) {
423
+ if (QRenderClass.renderingComponentId !== undefined) {
424
+ // If it's already disposed... call the function immediately?
425
+ fnc();
426
+ return;
427
+ }
428
+ throw new Error(`Can only call onDispose if inside of a render (or componentDidMount) function. If an an event callback, call qreact.getRenderingComponent in render, and then call qreact.watchDispose(component, callback).`);
429
+ }
420
430
  watchDispose(component, fnc);
421
431
  }
422
432
  function watchDispose(renderClass: ExternalRenderClass, fnc: () => void) {
@@ -616,6 +626,7 @@ class QRenderClass {
616
626
  const renderWatcher = this.renderWatcher = proxyWatcher.createWatcher({
617
627
  debugName: getDebugName("render"),
618
628
  canWrite: true,
629
+ logSyncTimings: statics.logLoadTime,
619
630
  runOncePerPaint: !multiRendersPerPaint && `${this.debugName}|${self.id}` || undefined,
620
631
  watchFunction() {
621
632
 
@@ -859,6 +870,10 @@ class QRenderClass {
859
870
  if ("data-break" in nextProps) {
860
871
  debugger;
861
872
  }
873
+ todonext;
874
+ // First of all, we are accessing deepProps on the WRONG value. We should be accessing it on the child statics, not our statics!
875
+ // Second of all... we need to check if our child is JSON comparing, and if so, do an atomic write of the props. Usually we don't want to do an atomic write, as this would force an update every render, but... if it is JSON comparing, it won't force an update.
876
+ // - Which is actually trivial. We just literally set .props = nextProps. Done.
862
877
  if (statics.deepProps) {
863
878
  // NOTE: By removing atomic we can leverage the proxy automatically decomposing
864
879
  // the props to each individual primitive value, and checking each individual
@@ -1953,14 +1968,17 @@ function updateDOMNodeFields(domNode: DOMNode, vNode: VirtualDOM, prevVNode: Vir
1953
1968
  if (typeof v === "number" && !IS_NON_DIMENSIONAL.test(key)) {
1954
1969
  v = v + "px";
1955
1970
  }
1956
- (domNode as any).style[key] = v ?? "";
1971
+ if (String(v).endsWith("!important")) {
1972
+ (domNode as any).style.setProperty(key, String(v).slice(0, -"!important".length), "important");
1973
+ } else {
1974
+ (domNode as any).style[key] = v ?? "";
1975
+ }
1957
1976
  }
1958
1977
  if (canHaveChildren(prevValue)) {
1959
1978
  for (let key in prevValue) {
1960
1979
  if (!(key in value)) {
1961
1980
  (domNode as any).style[key] = "";
1962
1981
  }
1963
-
1964
1982
  }
1965
1983
  }
1966
1984
  }
@@ -361,6 +361,9 @@ export class Querysub {
361
361
  allowProxyResults: true,
362
362
  });
363
363
  }
364
+ public static fastReadAsync<T>(fnc: () => T, options?: Partial<WatcherOptions<T>>) {
365
+ return Querysub.serviceWrite(fnc, { ...options, allowProxyResults: true });
366
+ }
364
367
  public static localRead<T>(fnc: () => T, options?: Partial<WatcherOptions<T>>) {
365
368
  return proxyWatcher.runOnce({
366
369
  watchFunction: fnc,
@@ -447,7 +450,7 @@ export class Querysub {
447
450
  * you can't call this at the start of your function (as nothing will have been called yet).
448
451
  * NOTE: This can also be used to prevent
449
452
  */
450
- public static afterPredictions(callback: () => Promise<void>) {
453
+ public static afterPredictions(callback: () => MaybePromise<void>) {
451
454
  let calls = proxyWatcher.getTriggeredWatcher().pendingCalls.map(x => x.call);
452
455
  Querysub.onCommitFinished(async () => {
453
456
  await Promise.all(calls.map(x => Querysub.onCallPredict(x)));
@@ -186,10 +186,15 @@ class WatchModal extends qreact.Component<{
186
186
  || {}
187
187
  }
188
188
  style={
189
- pos === "fill" && {}
190
- || pos === "top" && { maxHeight: "100%" }
191
- || pos === "bottom" && { maxHeight: "100%" }
192
- || {}
189
+ {
190
+ ...(
191
+ pos === "fill" && {}
192
+ || pos === "top" && { maxHeight: "100%" }
193
+ || pos === "bottom" && { maxHeight: "100%" }
194
+ || {}
195
+ ),
196
+ background: "rgb(255, 255, 255)!important",
197
+ }
193
198
  }
194
199
  onCancel={() => {
195
200
  if (this.state.pos !== "fill") {
@@ -197,7 +202,7 @@ class WatchModal extends qreact.Component<{
197
202
  }
198
203
  }}
199
204
  >
200
- <div class={css.hsl(0, 0, 100).vbox(6)}>
205
+ <div class={css.hsl(0, 0, 100).hslcolor(0, 0, 10).vbox(6)}>
201
206
  <div class={css.hbox(10).fillWidth}>
202
207
  {component.debugName}
203
208
  {parent && <Button onClick={() => this.state.parentNavigate++}>
@@ -53,7 +53,10 @@ export class ArchiveViewerTree extends qreact.Component<{
53
53
  let { remainingWidth, nodePath, scaleType } = config;
54
54
  const selectedPath = archiveTreeSelected.value;
55
55
 
56
- const sumFormatter = this.props.sumFormatter || formatNumber;
56
+ let sumFormatter: (value: number) => string = formatNumber;
57
+ if (archiveTreeScale.value === "size") {
58
+ sumFormatter = this.props.sumFormatter || formatNumber;
59
+ }
57
60
 
58
61
  let isSelected = selectedPath === nodePath;
59
62
  let isDescendantSelected = selectedPath.startsWith(nodePath);
package/src/errors.ts CHANGED
@@ -112,6 +112,7 @@ export function errorify(error: any, messageOverride?: string) {
112
112
  errorObj.stack = error;
113
113
  } else {
114
114
  errorObj.message = error;
115
+ errorObj.stack = error + "\n" + errorObj.stack;
115
116
  }
116
117
  if (messageOverride) {
117
118
  errorObj.message = messageOverride;
@@ -29,6 +29,7 @@ export type ATagProps = (
29
29
  rawLink?: boolean;
30
30
  lightMode?: boolean;
31
31
  noStyles?: boolean;
32
+ onRef?: (element: HTMLAnchorElement | null) => void;
32
33
  }
33
34
  );
34
35
 
@@ -51,6 +52,7 @@ export class ATag extends qreact.Component<ATagProps> {
51
52
  <a
52
53
  tabIndex={0}
53
54
  {...props}
55
+ ref={props.onRef}
54
56
  className={
55
57
  (isCurrent ? css.color(`hsl(110, 75%, ${lightness}%)`) : css.color(`hsl(210, 100%, ${lightness}%)`))
56
58
  + css.textDecoration("none")
@@ -251,16 +251,18 @@ export class UserPage extends qreact.Component {
251
251
  <table>
252
252
  <tr>
253
253
  <th>User ID</th>
254
+ <th>Email</th>
254
255
  <th>Time</th>
255
256
  </tr>
256
- {sort(Object.entries(userObj.invitedUsers), x => -x[1].time).map(([userId, inviteData]) => {
257
+ {sort(Object.entries(userObj.invitedUsers2), x => -x[1].time).map(([email, inviteData]) => {
257
258
  return (
258
259
  <tr>
259
260
  <td>
260
- <Anchor values={[{ param: viewingUserURL, value: userId }]}>
261
- {userId}
261
+ <Anchor values={[{ param: viewingUserURL, value: inviteData.userId }]}>
262
+ {inviteData.userId}
262
263
  </Anchor>
263
264
  </td>
265
+ <td>{inviteData.email}</td>
264
266
  <td>{inviteData.time}</td>
265
267
  </tr>
266
268
  );
@@ -133,8 +133,10 @@ export type User = {
133
133
  };
134
134
 
135
135
  invitesRemaining: number;
136
- invitedUsers: {
137
- [userId: string]: {
136
+ invitedUsers2: {
137
+ [email: string]: {
138
+ userId: string;
139
+ email: string;
138
140
  time: number;
139
141
  };
140
142
  };
@@ -427,7 +429,7 @@ function getLoadingUserObj() {
427
429
  email: "",
428
430
  settings: { displayName: "" }, userType: "anonymous" as const,
429
431
  createTime: 0,
430
- machineIds: {}, allowedIPs: {}, loginTokens: {}, lastPageLoadsIPs: {}, invitedUsers: {},
432
+ machineIds: {}, allowedIPs: {}, loginTokens: {}, lastPageLoadsIPs: {}, invitedUsers2: {},
431
433
  invitesRemaining: 0
432
434
  };
433
435
  }
@@ -452,7 +454,7 @@ export function getCurrentUserObj(): User | undefined {
452
454
  allowedIPs: {},
453
455
  loginTokens: {},
454
456
  lastPageLoadsIPs: {},
455
- invitedUsers: {},
457
+ invitedUsers2: {},
456
458
  invitesRemaining: 0,
457
459
  };
458
460
  }
@@ -537,9 +539,10 @@ function internalCreateUser(config: {
537
539
  allowedIPs: {},
538
540
  loginTokens: {},
539
541
  lastPageLoadsIPs: {},
540
- invitedUsers: {},
542
+ invitedUsers2: {},
541
543
  invitesRemaining: 0,
542
544
  };
545
+ data().secure.emailToUserId[email] = userId;
543
546
  }
544
547
  return data().users[userId];
545
548
  }
@@ -776,7 +779,7 @@ function registerPageLoadTime() {
776
779
  function inviteUser(config: { email: string }) {
777
780
  Querysub.ignorePermissionsChecks(() => {
778
781
  let curUserObj = getUserObjAssert();
779
- if (config.email in curUserObj.invitedUsers) {
782
+ if (config.email in curUserObj.invitedUsers2) {
780
783
  console.info(`User ${config.email} already invited`);
781
784
  return;
782
785
  }
@@ -793,7 +796,9 @@ function inviteUser(config: { email: string }) {
793
796
  throw new Error("No invites remaining");
794
797
  }
795
798
 
796
- curUserObj.invitedUsers[config.email] = atomicObjectWrite({
799
+ curUserObj.invitedUsers2[email] = atomicObjectWrite({
800
+ userId,
801
+ email,
797
802
  time: Querysub.getCallTime(),
798
803
  });
799
804
  curUserObj.invitesRemaining--;
@@ -923,7 +928,7 @@ export function scriptCreateUser(config: {
923
928
  allowedIPs: {},
924
929
  loginTokens: {},
925
930
  lastPageLoadsIPs: {},
926
- invitedUsers: {},
931
+ invitedUsers2: {},
927
932
  invitesRemaining: 0,
928
933
  };
929
934
  data().secure.emailToUserId[email] = userId;
@@ -980,7 +985,7 @@ export async function registerServicePermissions() {
980
985
  allowedIPs: {},
981
986
  loginTokens: {},
982
987
  lastPageLoadsIPs: {},
983
- invitedUsers: {},
988
+ invitedUsers2: {},
984
989
  invitesRemaining: 0,
985
990
  };
986
991
  }