sliftutils 1.8.19 → 1.9.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.
Files changed (37) hide show
  1. package/.cursor/rules/mobx-state.mdc +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/electron/electronRenderer.tsx +1 -3
  4. package/examplestorage/browser.tsx +1 -3
  5. package/examplestorage/exampleserver.ts +0 -1
  6. package/index.d.ts +7 -2
  7. package/misc/apiKeys.tsx +1 -3
  8. package/misc/helpers.d.ts +1 -0
  9. package/misc/helpers.ts +6 -0
  10. package/package.json +1 -1
  11. package/render-utils/DropdownCustom.tsx +1 -3
  12. package/render-utils/FullscreenModal.tsx +1 -3
  13. package/render-utils/InputLabel.tsx +1 -3
  14. package/render-utils/InputPicker.tsx +1 -3
  15. package/render-utils/LocalStorageParam.ts +1 -3
  16. package/render-utils/SyncedController.ts +1 -3
  17. package/render-utils/Table.tsx +1 -3
  18. package/render-utils/URLParam.ts +1 -3
  19. package/render-utils/asyncObservable.ts +1 -3
  20. package/render-utils/dist/LocalStorageParam.ts.cache +4 -5
  21. package/render-utils/mobxTyped.d.ts +2 -1
  22. package/render-utils/mobxTyped.ts +5 -3
  23. package/render-utils/modal.tsx +1 -4
  24. package/render-utils/observer.d.ts +1 -1
  25. package/render-utils/observer.tsx +1 -5
  26. package/storage/FileFolderAPI.tsx +1 -3
  27. package/storage/PendingManager.tsx +1 -3
  28. package/storage/StorageObservable.ts +1 -3
  29. package/storage/backblaze.d.ts +3 -0
  30. package/storage/backblaze.ts +29 -3
  31. package/storage/remoteStorage/ArchivesDelayed.ts +7 -1
  32. package/storage/remoteStorage/accessPage.tsx +0 -2
  33. package/storage/remoteStorage/storageServer.ts +0 -2
  34. package/testsite/browser.tsx +1 -3
  35. package/testsite/server.ts +0 -1
  36. package/web/ExamplePage.tsx +1 -3
  37. package/web/browser.tsx +1 -3
@@ -11,7 +11,7 @@ For example:
11
11
 
12
12
  ```tsx
13
13
  import preact from "preact";
14
- import { observable } from "mobx";
14
+ import { observable } from "sliftutils/render-utils/mobxTyped";
15
15
 
16
16
  @observer
17
17
  class Example extends preact.Component {
package/CLAUDE.md CHANGED
@@ -56,7 +56,7 @@ We use MobX. Components store local state in a field called `synced`, which is a
56
56
 
57
57
  ```tsx
58
58
  import preact from "preact";
59
- import { observable } from "mobx";
59
+ import { observable } from "sliftutils/render-utils/mobxTyped";
60
60
  import { observer } from "sliftutils/render-utils/observer";
61
61
 
62
62
  @observer
@@ -1,7 +1,5 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import * as preact from "preact";
4
- import { observable } from "mobx";
2
+ import { observable } from "../render-utils/mobxTyped";
5
3
  import { observer } from "../render-utils/observer";
6
4
  import { isNode } from "typesafecss";
7
5
  import { enableHotReloading } from "../builders/hotReload";
@@ -1,7 +1,5 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import preact from "preact";
4
- import { observable } from "mobx";
2
+ import { observable } from "../render-utils/mobxTyped";
5
3
  import { observer } from "../render-utils/observer";
6
4
  import { isNode } from "socket-function/src/misc";
7
5
  import { delay } from "socket-function/src/batching";
@@ -1,4 +1,3 @@
1
- process.env.NODE_ENV = "production";
2
1
  import path from "path";
3
2
  import { SocketFunction } from "socket-function/SocketFunction";
4
3
  import { RequireController } from "socket-function/require/RequireController";
package/index.d.ts CHANGED
@@ -60,6 +60,7 @@ declare module "sliftutils/misc/getSecret" {
60
60
  }
61
61
 
62
62
  declare module "sliftutils/misc/helpers" {
63
+ export declare function throwDetached(error: unknown): void;
63
64
  export declare function waitForDiskCollectionFlush(): Promise<void>;
64
65
 
65
66
  }
@@ -852,7 +853,8 @@ declare module "sliftutils/render-utils/colors" {
852
853
  }
853
854
 
854
855
  declare module "sliftutils/render-utils/mobxTyped" {
855
- export { observable, runInAction, computed, autorun, onBecomeObserved, onBecomeUnobserved } from "mobx";
856
+ import { observable, runInAction, computed, autorun, onBecomeObserved, onBecomeUnobserved, Reaction } from "mobx";
857
+ export { observable, runInAction, computed, autorun, onBecomeObserved, onBecomeUnobserved, Reaction };
856
858
  export declare function configureMobxNextFrameScheduler(): void;
857
859
 
858
860
  }
@@ -880,7 +882,7 @@ declare module "sliftutils/render-utils/niceStringify" {
880
882
 
881
883
  declare module "sliftutils/render-utils/observer" {
882
884
  import * as preact from "preact";
883
- import { Reaction } from "mobx";
885
+ import { Reaction } from "./mobxTyped";
884
886
  export declare function observer<T extends {
885
887
  new (...args: any[]): {
886
888
  render(): preact.ComponentChild;
@@ -3022,6 +3024,9 @@ declare module "sliftutils/storage/backblaze" {
3022
3024
  private getBucketAPI;
3023
3025
  private currentReset;
3024
3026
  private last503Reset;
3027
+ private lastAPIReset;
3028
+ private consecutiveFailures;
3029
+ private resetAPIs;
3025
3030
  private apiRetryLogic;
3026
3031
  get(fileName: string, config?: GetConfig): Promise<Buffer | undefined>;
3027
3032
  get2(fileName: string, config?: GetConfig): Promise<{
package/misc/apiKeys.tsx CHANGED
@@ -1,11 +1,9 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import preact from "preact";
4
2
  import { cache, lazy } from "socket-function/src/caching";
5
3
  import { css, isNode } from "typesafecss";
6
4
  import fs from "fs";
7
5
  import os from "os";
8
- import { observable } from "mobx";
6
+ import { observable } from "../render-utils/mobxTyped";
9
7
  import { InputLabel } from "../render-utils/InputLabel";
10
8
  import { showModal } from "../render-utils/modal";
11
9
  import { observer } from "../render-utils/observer";
package/misc/helpers.d.ts CHANGED
@@ -1 +1,2 @@
1
+ export declare function throwDetached(error: unknown): void;
1
2
  export declare function waitForDiskCollectionFlush(): Promise<void>;
package/misc/helpers.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  import { delay } from "socket-function/src/batching";
2
2
  import { hasPending } from "../storage/PendingManager";
3
3
 
4
+ export function throwDetached(error: unknown): void {
5
+ void Promise.resolve().then(() => {
6
+ throw error;
7
+ });
8
+ }
9
+
4
10
  export async function waitForDiskCollectionFlush() {
5
11
  await delay(2000);
6
12
  while (hasPending()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sliftutils",
3
- "version": "1.8.19",
3
+ "version": "1.9.0",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -1,7 +1,5 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import preact from "preact";
4
- import { observable } from "mobx";
2
+ import { observable } from "./mobxTyped";
5
3
  import { observer } from "./observer";
6
4
  import { css } from "typesafecss";
7
5
  import { LengthOrPercentage, LengthOrPercentageOrAuto } from "typesafecss/cssTypes";
@@ -1,8 +1,6 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import preact from "preact";
4
2
  import { showModal } from "./modal";
5
- import { observable } from "mobx";
3
+ import { observable } from "./mobxTyped";
6
4
  import { observer } from "./observer";
7
5
 
8
6
  export function showFullscreenModal(config: {
@@ -1,11 +1,9 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import preact from "preact";
4
2
  import { Input } from "./Input";
5
3
  import { css } from "typesafecss";
6
4
  import { lazy } from "socket-function/src/caching";
7
5
  import { observer } from "./observer";
8
- import { observable } from "mobx";
6
+ import { observable } from "./mobxTyped";
9
7
 
10
8
  // IMPORTANT! InputProps is in both InputLabel.tsx and Input.tsx, so the types export correctly
11
9
  export type InputProps = (
@@ -1,7 +1,5 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import preact from "preact";
4
- import { observable } from "mobx";
2
+ import { observable } from "./mobxTyped";
5
3
  import { observer } from "./observer";
6
4
  import { sort } from "socket-function/src/misc";
7
5
  import { css } from "typesafecss";
@@ -1,7 +1,5 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import { isNode } from "typesafecss";
4
- import { observable } from "mobx";
2
+ import { observable } from "./mobxTyped";
5
3
 
6
4
  let allParams: LocalStorageParamStr[] = [];
7
5
 
@@ -1,12 +1,10 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import { SocketFunction } from "socket-function/SocketFunction";
4
2
  import { SocketRegistered } from "socket-function/SocketFunctionTypes";
5
3
  import { onHotReload } from "socket-function/hot/HotReloadController";
6
4
  import { cache } from "socket-function/src/caching";
7
5
  import { nextId } from "socket-function/src/misc";
8
6
  import { MaybePromise } from "socket-function/src/types";
9
- import { observable } from "mobx";
7
+ import { observable } from "./mobxTyped";
10
8
  import { formatTime } from "socket-function/src/formatting/format";
11
9
  import { isNode } from "typesafecss";
12
10
  import { delay } from "socket-function/src/batching";
@@ -1,12 +1,10 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import preact from "preact";
4
2
  import { css } from "typesafecss";
5
3
  import { formatValue, JSXFormatter, toSpaceCase } from "./GenericFormat";
6
4
  import { observer } from "./observer";
7
5
  import { canHaveChildren } from "socket-function/src/types";
8
6
  import { showFullscreenModal } from "./FullscreenModal";
9
- import { observable } from "mobx";
7
+ import { observable } from "./mobxTyped";
10
8
 
11
9
  // Null means the column is removed
12
10
  export type ColumnType<T = unknown, Row extends RowType = RowType> = undefined | null | {
@@ -1,7 +1,5 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import { isNode } from "typesafecss";
4
- import { observable } from "mobx";
2
+ import { observable } from "./mobxTyped";
5
3
  import { throttleFunction } from "socket-function/src/misc";
6
4
  import { createSingleton } from "socket-function/src/createSingleton";
7
5
  import { niceParse, niceStringify } from "./niceStringify";
@@ -1,6 +1,4 @@
1
- process.env.NODE_ENV = "production";
2
-
3
- import { observable } from "mobx";
1
+ import { observable } from "./mobxTyped";
4
2
 
5
3
  export function asyncCache<Args, T>(getValue: (args: Args) => Promise<T>): {
6
4
  (args: Args): T | undefined;
@@ -1,15 +1,14 @@
1
1
  "use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
3
3
  //exports.LocalStorageParamStr = void 0;
4
- process.env.NODE_ENV = "production";
5
4
  const typesafecss_1 = require("typesafecss");
6
- const mobx_1 = require("mobx");
5
+ const mobxTyped_1 = require("./mobxTyped");
7
6
  let allParams = [];
8
7
  class LocalStorageParamStr {
9
8
  constructor(storageKey, defaultValue = "") {
10
9
  this.storageKey = storageKey;
11
10
  this.defaultValue = defaultValue;
12
- this.state = (0, mobx_1.observable)({
11
+ this.state = (0, mobxTyped_1.observable)({
13
12
  seqNum: 0
14
13
  });
15
14
  this.lastSetValue = "";
@@ -58,5 +57,5 @@ if (!(0, typesafecss_1.isNode)()) {
58
57
  }
59
58
  });
60
59
  }
61
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTG9jYWxTdG9yYWdlUGFyYW0uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJMb2NhbFN0b3JhZ2VQYXJhbS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsR0FBRyxZQUFZLENBQUM7QUFFcEMsNkNBQXFDO0FBQ3JDLCtCQUFrQztBQUVsQyxJQUFJLFNBQVMsR0FBMkIsRUFBRSxDQUFDO0FBRTNDLE1BQWEsb0JBQW9CO0lBSzdCLFlBQTRCLFVBQWtCLEVBQVUsZUFBdUIsRUFBRTtRQUFyRCxlQUFVLEdBQVYsVUFBVSxDQUFRO1FBQVUsaUJBQVksR0FBWixZQUFZLENBQWE7UUFKekUsVUFBSyxHQUFHLElBQUEsaUJBQVUsRUFBQztZQUN2QixNQUFNLEVBQUUsQ0FBQztTQUNaLENBQUMsQ0FBQztRQUNJLGlCQUFZLEdBQUcsRUFBRSxDQUFDO1FBRXJCLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUNNLFdBQVc7UUFDZCxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFFTSxHQUFHO1FBQ04sSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7UUFDbEIsSUFBSSxJQUFBLG9CQUFNLEdBQUU7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUN4QixPQUFPLFlBQVksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUN2RCxDQUFDO0lBQ00sR0FBRyxDQUFDLEtBQWE7UUFDcEIsSUFBSSxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ3RCLElBQUksQ0FBQyxZQUFZLEdBQUcsS0FBSyxDQUFDO1FBQzFCLElBQUksQ0FBQyxJQUFBLG9CQUFNLEdBQUUsRUFBRSxDQUFDO1lBQ1osSUFBSSxLQUFLLEtBQUssRUFBRSxFQUFFLENBQUM7Z0JBQ2YsWUFBWSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDN0MsQ0FBQztpQkFBTSxDQUFDO2dCQUNKLFlBQVksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNqRCxDQUFDO1FBQ0wsQ0FBQztRQUNELElBQUksS0FBSyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUN2QixJQUFJLElBQUksS0FBSyxLQUFLLEVBQUUsQ0FBQztZQUNqQixJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ3hCLENBQUM7SUFDTCxDQUFDO0lBRUQsSUFBVyxLQUFLO1FBQ1osT0FBTyxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQztJQUMzQyxDQUFDO0lBQ0QsSUFBVyxLQUFLLENBQUMsS0FBYTtRQUMxQixJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3BCLENBQUM7Q0FDSjtBQXZDRCxvREF1Q0M7QUFFRCxJQUFJLENBQUMsSUFBQSxvQkFBTSxHQUFFLEVBQUUsQ0FBQztJQUNaLG1EQUFtRDtJQUNuRCxNQUFNLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUU7UUFDckMsS0FBSyxJQUFJLEtBQUssSUFBSSxTQUFTLEVBQUUsQ0FBQztZQUMxQixJQUFJLENBQUMsQ0FBQyxHQUFHLEtBQUssS0FBSyxDQUFDLFVBQVUsRUFBRSxDQUFDO2dCQUM3QixLQUFLLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDeEIsQ0FBQztRQUNMLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNQLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJwcm9jZXNzLmVudi5OT0RFX0VOViA9IFwicHJvZHVjdGlvblwiO1xuXG5pbXBvcnQgeyBpc05vZGUgfSBmcm9tIFwidHlwZXNhZmVjc3NcIjtcbmltcG9ydCB7IG9ic2VydmFibGUgfSBmcm9tIFwibW9ieFwiO1xuXG5sZXQgYWxsUGFyYW1zOiBMb2NhbFN0b3JhZ2VQYXJhbVN0cltdID0gW107XG5cbmV4cG9ydCBjbGFzcyBMb2NhbFN0b3JhZ2VQYXJhbVN0ciB7XG4gICAgcHJpdmF0ZSBzdGF0ZSA9IG9ic2VydmFibGUoe1xuICAgICAgICBzZXFOdW06IDBcbiAgICB9KTtcbiAgICBwdWJsaWMgbGFzdFNldFZhbHVlID0gXCJcIjtcbiAgICBjb25zdHJ1Y3RvcihwdWJsaWMgcmVhZG9ubHkgc3RvcmFnZUtleTogc3RyaW5nLCBwcml2YXRlIGRlZmF1bHRWYWx1ZTogc3RyaW5nID0gXCJcIikge1xuICAgICAgICBhbGxQYXJhbXMucHVzaCh0aGlzKTtcbiAgICB9XG4gICAgcHVibGljIGZvcmNlVXBkYXRlKCkge1xuICAgICAgICB0aGlzLnN0YXRlLnNlcU51bSsrO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQoKSB7XG4gICAgICAgIHRoaXMuc3RhdGUuc2VxTnVtO1xuICAgICAgICBpZiAoaXNOb2RlKCkpIHJldHVybiBcIlwiO1xuICAgICAgICByZXR1cm4gbG9jYWxTdG9yYWdlLmdldEl0ZW0odGhpcy5zdG9yYWdlS2V5KSB8fCBcIlwiO1xuICAgIH1cbiAgICBwdWJsaWMgc2V0KHZhbHVlOiBzdHJpbmcpIHtcbiAgICAgICAgbGV0IHByZXYgPSB0aGlzLmdldCgpO1xuICAgICAgICB0aGlzLmxhc3RTZXRWYWx1ZSA9IHZhbHVlO1xuICAgICAgICBpZiAoIWlzTm9kZSgpKSB7XG4gICAgICAgICAgICBpZiAodmFsdWUgPT09IFwiXCIpIHtcbiAgICAgICAgICAgICAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbSh0aGlzLnN0b3JhZ2VLZXkpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSh0aGlzLnN0b3JhZ2VLZXksIHZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBsZXQgYWZ0ZXIgPSB0aGlzLmdldCgpO1xuICAgICAgICBpZiAocHJldiAhPT0gYWZ0ZXIpIHtcbiAgICAgICAgICAgIHRoaXMuc3RhdGUuc2VxTnVtKys7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHZhbHVlKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXQoKSB8fCB0aGlzLmRlZmF1bHRWYWx1ZTtcbiAgICB9XG4gICAgcHVibGljIHNldCB2YWx1ZSh2YWx1ZTogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuc2V0KHZhbHVlKTtcbiAgICB9XG59XG5cbmlmICghaXNOb2RlKCkpIHtcbiAgICAvLyBXYXRjaCBmb3Igc3RvcmFnZSBldmVudHMgZnJvbSBvdGhlciB0YWJzL3dpbmRvd3NcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInN0b3JhZ2VcIiwgKGUpID0+IHtcbiAgICAgICAgZm9yIChsZXQgcGFyYW0gb2YgYWxsUGFyYW1zKSB7XG4gICAgICAgICAgICBpZiAoZS5rZXkgPT09IHBhcmFtLnN0b3JhZ2VLZXkpIHtcbiAgICAgICAgICAgICAgICBwYXJhbS5mb3JjZVVwZGF0ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSk7XG59XG4iXX0=
62
- /* _JS_SOURCE_HASH = "03278904af59362b290f72cfb231971a3e53e50185dbd467364de254d3c4f05a"; */
60
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTG9jYWxTdG9yYWdlUGFyYW0uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJMb2NhbFN0b3JhZ2VQYXJhbS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2Q0FBcUM7QUFDckMsMkNBQXlDO0FBRXpDLElBQUksU0FBUyxHQUEyQixFQUFFLENBQUM7QUFFM0MsTUFBYSxvQkFBb0I7SUFLN0IsWUFBNEIsVUFBa0IsRUFBVSxlQUF1QixFQUFFO1FBQXJELGVBQVUsR0FBVixVQUFVLENBQVE7UUFBVSxpQkFBWSxHQUFaLFlBQVksQ0FBYTtRQUp6RSxVQUFLLEdBQUcsSUFBQSxzQkFBVSxFQUFDO1lBQ3ZCLE1BQU0sRUFBRSxDQUFDO1NBQ1osQ0FBQyxDQUFDO1FBQ0ksaUJBQVksR0FBRyxFQUFFLENBQUM7UUFFckIsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN6QixDQUFDO0lBQ00sV0FBVztRQUNkLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDeEIsQ0FBQztJQUVNLEdBQUc7UUFDTixJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQztRQUNsQixJQUFJLElBQUEsb0JBQU0sR0FBRTtZQUFFLE9BQU8sRUFBRSxDQUFDO1FBQ3hCLE9BQU8sWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3ZELENBQUM7SUFDTSxHQUFHLENBQUMsS0FBYTtRQUNwQixJQUFJLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDdEIsSUFBSSxDQUFDLFlBQVksR0FBRyxLQUFLLENBQUM7UUFDMUIsSUFBSSxDQUFDLElBQUEsb0JBQU0sR0FBRSxFQUFFLENBQUM7WUFDWixJQUFJLEtBQUssS0FBSyxFQUFFLEVBQUUsQ0FBQztnQkFDZixZQUFZLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUM3QyxDQUFDO2lCQUFNLENBQUM7Z0JBQ0osWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ2pELENBQUM7UUFDTCxDQUFDO1FBQ0QsSUFBSSxLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ3ZCLElBQUksSUFBSSxLQUFLLEtBQUssRUFBRSxDQUFDO1lBQ2pCLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDeEIsQ0FBQztJQUNMLENBQUM7SUFFRCxJQUFXLEtBQUs7UUFDWixPQUFPLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDO0lBQzNDLENBQUM7SUFDRCxJQUFXLEtBQUssQ0FBQyxLQUFhO1FBQzFCLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDcEIsQ0FBQztDQUNKO0FBdkNELG9EQXVDQztBQUVELElBQUksQ0FBQyxJQUFBLG9CQUFNLEdBQUUsRUFBRSxDQUFDO0lBQ1osbURBQW1EO0lBQ25ELE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRTtRQUNyQyxLQUFLLElBQUksS0FBSyxJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQzFCLElBQUksQ0FBQyxDQUFDLEdBQUcsS0FBSyxLQUFLLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQzdCLEtBQUssQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUN4QixDQUFDO1FBQ0wsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0FBQ1AsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGlzTm9kZSB9IGZyb20gXCJ0eXBlc2FmZWNzc1wiO1xuaW1wb3J0IHsgb2JzZXJ2YWJsZSB9IGZyb20gXCIuL21vYnhUeXBlZFwiO1xuXG5sZXQgYWxsUGFyYW1zOiBMb2NhbFN0b3JhZ2VQYXJhbVN0cltdID0gW107XG5cbmV4cG9ydCBjbGFzcyBMb2NhbFN0b3JhZ2VQYXJhbVN0ciB7XG4gICAgcHJpdmF0ZSBzdGF0ZSA9IG9ic2VydmFibGUoe1xuICAgICAgICBzZXFOdW06IDBcbiAgICB9KTtcbiAgICBwdWJsaWMgbGFzdFNldFZhbHVlID0gXCJcIjtcbiAgICBjb25zdHJ1Y3RvcihwdWJsaWMgcmVhZG9ubHkgc3RvcmFnZUtleTogc3RyaW5nLCBwcml2YXRlIGRlZmF1bHRWYWx1ZTogc3RyaW5nID0gXCJcIikge1xuICAgICAgICBhbGxQYXJhbXMucHVzaCh0aGlzKTtcbiAgICB9XG4gICAgcHVibGljIGZvcmNlVXBkYXRlKCkge1xuICAgICAgICB0aGlzLnN0YXRlLnNlcU51bSsrO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQoKSB7XG4gICAgICAgIHRoaXMuc3RhdGUuc2VxTnVtO1xuICAgICAgICBpZiAoaXNOb2RlKCkpIHJldHVybiBcIlwiO1xuICAgICAgICByZXR1cm4gbG9jYWxTdG9yYWdlLmdldEl0ZW0odGhpcy5zdG9yYWdlS2V5KSB8fCBcIlwiO1xuICAgIH1cbiAgICBwdWJsaWMgc2V0KHZhbHVlOiBzdHJpbmcpIHtcbiAgICAgICAgbGV0IHByZXYgPSB0aGlzLmdldCgpO1xuICAgICAgICB0aGlzLmxhc3RTZXRWYWx1ZSA9IHZhbHVlO1xuICAgICAgICBpZiAoIWlzTm9kZSgpKSB7XG4gICAgICAgICAgICBpZiAodmFsdWUgPT09IFwiXCIpIHtcbiAgICAgICAgICAgICAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbSh0aGlzLnN0b3JhZ2VLZXkpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSh0aGlzLnN0b3JhZ2VLZXksIHZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBsZXQgYWZ0ZXIgPSB0aGlzLmdldCgpO1xuICAgICAgICBpZiAocHJldiAhPT0gYWZ0ZXIpIHtcbiAgICAgICAgICAgIHRoaXMuc3RhdGUuc2VxTnVtKys7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHZhbHVlKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXQoKSB8fCB0aGlzLmRlZmF1bHRWYWx1ZTtcbiAgICB9XG4gICAgcHVibGljIHNldCB2YWx1ZSh2YWx1ZTogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuc2V0KHZhbHVlKTtcbiAgICB9XG59XG5cbmlmICghaXNOb2RlKCkpIHtcbiAgICAvLyBXYXRjaCBmb3Igc3RvcmFnZSBldmVudHMgZnJvbSBvdGhlciB0YWJzL3dpbmRvd3NcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInN0b3JhZ2VcIiwgKGUpID0+IHtcbiAgICAgICAgZm9yIChsZXQgcGFyYW0gb2YgYWxsUGFyYW1zKSB7XG4gICAgICAgICAgICBpZiAoZS5rZXkgPT09IHBhcmFtLnN0b3JhZ2VLZXkpIHtcbiAgICAgICAgICAgICAgICBwYXJhbS5mb3JjZVVwZGF0ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSk7XG59XG4iXX0=
61
+ /* _JS_SOURCE_HASH = "5466f08de8de5a62b1bf7013d692bb483c05d10612e9c9babe2c5cf5ce0050e1"; */
@@ -1,2 +1,3 @@
1
- export { observable, runInAction, computed, autorun, onBecomeObserved, onBecomeUnobserved } from "mobx";
1
+ import { observable, runInAction, computed, autorun, onBecomeObserved, onBecomeUnobserved, Reaction } from "mobx";
2
+ export { observable, runInAction, computed, autorun, onBecomeObserved, onBecomeUnobserved, Reaction };
2
3
  export declare function configureMobxNextFrameScheduler(): void;
@@ -1,10 +1,12 @@
1
1
  process.env.NODE_ENV = "production";
2
2
 
3
- import * as mobx from "mobx";
3
+ import { observable, runInAction, computed, autorun, onBecomeObserved, onBecomeUnobserved, Reaction, configure } from "mobx";
4
+ import { setFlag } from "socket-function/require/compileFlags";
4
5
  import { batchFunction } from "socket-function/src/batching";
5
6
 
6
7
  // Re-export the core mobx primitives so downstream packages (which may have their own duplicate mobx in node_modules) can share THIS mobx instance, otherwise reactivity doesn't cross package boundaries.
7
- export { observable, runInAction, computed, autorun, onBecomeObserved, onBecomeUnobserved } from "mobx";
8
+ export { observable, runInAction, computed, autorun, onBecomeObserved, onBecomeUnobserved, Reaction };
9
+ setFlag(require, "mobx", "allowclient", true);
8
10
  export function configureMobxNextFrameScheduler() {
9
11
  // NOTE: This makes a big difference if we do await calls in a loop which mutates observable state. BUT... we should probably just do those await calls before the loop?
10
12
  let batchReactionScheduler = batchFunction({
@@ -19,7 +21,7 @@ export function configureMobxNextFrameScheduler() {
19
21
  });
20
22
 
21
23
  let lastRenderTime = 0;
22
- mobx.configure({
24
+ configure({
23
25
  enforceActions: "never",
24
26
  reactionScheduler(callback) {
25
27
  let now = performance.now();
@@ -1,8 +1,5 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import preact from "preact";
4
- import { observable } from "mobx";
5
- import * as mobx from "mobx";
2
+ import { observable } from "./mobxTyped";
6
3
  import { observer } from "./observer";
7
4
  import { lazy } from "socket-function/src/caching";
8
5
  import { nextId } from "socket-function/src/misc";
@@ -1,5 +1,5 @@
1
1
  import * as preact from "preact";
2
- import { Reaction } from "mobx";
2
+ import { Reaction } from "./mobxTyped";
3
3
  export declare function observer<T extends {
4
4
  new (...args: any[]): {
5
5
  render(): preact.ComponentChild;
@@ -1,9 +1,5 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import * as preact from "preact";
4
- import { observable, Reaction } from "mobx";
5
- import { setFlag } from "socket-function/require/compileFlags";
6
- setFlag(require, "mobx", "allowclient", true);
2
+ import { observable, Reaction } from "./mobxTyped";
7
3
  import { measureBlock } from "socket-function/src/profiling/measure";
8
4
 
9
5
  let globalConstructOrder = 1;
@@ -1,8 +1,6 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import preact from "preact";
4
2
  import { findGrantedPointerHandle, getFileSystemPointer, storeFileSystemPointer } from "./fileSystemPointer";
5
- import { observable } from "mobx";
3
+ import { observable } from "../render-utils/mobxTyped";
6
4
  import { observer } from "../render-utils/observer";
7
5
  import { cache, lazy } from "socket-function/src/caching";
8
6
  import { css, isNode } from "typesafecss";
@@ -1,7 +1,5 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import { throttleFunction } from "socket-function/src/misc";
4
- import { observable } from "mobx";
2
+ import { observable } from "../render-utils/mobxTyped";
5
3
  import preact from "preact";
6
4
  import { css } from "typesafecss";
7
5
  import { observer } from "../render-utils/observer";
@@ -1,6 +1,4 @@
1
- process.env.NODE_ENV = "production";
2
-
3
- import { observable } from "mobx";
1
+ import { observable } from "../render-utils/mobxTyped";
4
2
  import { deepFreezeObject, freezeObject, isDefined } from "../misc/types";
5
3
  import { IStorage, IStorageSync } from "./IStorage";
6
4
  import { PromiseObj } from "socket-function/src/misc";
@@ -21,6 +21,9 @@ export declare class ArchivesBackblaze implements IArchives {
21
21
  private getBucketAPI;
22
22
  private currentReset;
23
23
  private last503Reset;
24
+ private lastAPIReset;
25
+ private consecutiveFailures;
26
+ private resetAPIs;
24
27
  private apiRetryLogic;
25
28
  get(fileName: string, config?: GetConfig): Promise<Buffer | undefined>;
26
29
  get2(fileName: string, config?: GetConfig): Promise<{
@@ -29,6 +29,9 @@ let backblazeCreds = lazy(async (): Promise<BackblazeCreds> => {
29
29
  const MIN_BUCKET_CACHE_TIME = 60 * 1000;
30
30
  // Backblaze requires 5MB chunks for large files, but larger is more efficient for us (and their "last part" size check misbehaves on retries, which chunks this big sidestep - see setLargeFile)
31
31
  const LARGE_FILE_MIN_CHUNK_SIZE = 32 * 1024 * 1024;
32
+ const CONSECUTIVE_FAILURES_BEFORE_RESET = 10;
33
+ const MIN_API_RESET_INTERVAL = 1000;
34
+ const CONNECTION_DEAD_MARKERS = ["TLS", "ECONNRESET", "ECONNREFUSED", "EPIPE", "socket hang up", "socket disconnected"];
32
35
 
33
36
  // A B2 download/HEAD response's headers carry the file's metadata. content-range's total wins over content-length for ranged responses (which only report the slice's length).
34
37
  function parseFileMetadataHeaders(response: HttpsResponseInfo): { size: number; writeTime: number } {
@@ -562,6 +565,17 @@ export class ArchivesBackblaze implements IArchives {
562
565
 
563
566
  // Keep track of when we last reset because of a 503
564
567
  private last503Reset = 0;
568
+ private lastAPIReset = 0;
569
+ private consecutiveFailures = 0;
570
+
571
+ private resetAPIs(context: string, reason: string, err: Error) {
572
+ if (Date.now() - this.lastAPIReset < MIN_API_RESET_INTERVAL) return;
573
+ this.lastAPIReset = Date.now();
574
+ console.warn(`[${context}] Resetting getAPI and getBucketAPI for ${this.getDebugName()} (${reason}, ${this.consecutiveFailures} consecutive failures): ${err.message}`);
575
+ getAPI.reset();
576
+ this.getBucketAPI.reset();
577
+ this.consecutiveFailures = 0;
578
+ }
565
579
  // IMPORTANT! We must always CATCH AROUND the apiRetryLogic, NEVER inside of fnc. Otherwise we won't be able to recreate the auth token. `context` is a short label (verb + file path) included in every retry/error log so a stuck silent-retry loop is identifiable from the logs.
566
580
  private async apiRetryLogic<T>(
567
581
  context: string,
@@ -571,10 +585,10 @@ export class ArchivesBackblaze implements IArchives {
571
585
  let api: B2Api | undefined;
572
586
  try {
573
587
  api = await this.getBucketAPI();
574
- return await fnc(api);
588
+ let result = await fnc(api);
589
+ this.consecutiveFailures = 0;
590
+ return result;
575
591
  } catch (err: any) {
576
- if (retries <= 0) throw err;
577
-
578
592
  // A file that does not exist is an answer, not a failure. It is the one error here that
579
593
  // cannot become anything else by asking again, so it is thrown at once instead of being
580
594
  // slept on twice - callers turn it into undefined, which is what they were asking.
@@ -583,9 +597,21 @@ export class ArchivesBackblaze implements IArchives {
583
597
  || err.stack.includes(`file_not_found`)
584
598
  || err.stack.includes(`"status": 404`)
585
599
  ) {
600
+ this.consecutiveFailures = 0;
586
601
  throw err;
587
602
  }
588
603
 
604
+ this.consecutiveFailures++;
605
+ if (!api) {
606
+ this.resetAPIs(context, "acquiring the api failed, so the lazy holds a rejected promise", err);
607
+ } else if (CONNECTION_DEAD_MARKERS.some(marker => err.stack.includes(marker))) {
608
+ this.resetAPIs(context, "connection level error", err);
609
+ } else if (this.consecutiveFailures >= CONSECUTIVE_FAILURES_BEFORE_RESET) {
610
+ this.resetAPIs(context, `${CONSECUTIVE_FAILURES_BEFORE_RESET} calls in a row failed`, err);
611
+ }
612
+
613
+ if (retries <= 0) throw err;
614
+
589
615
  // If it's a 503 and it's been a minute since we last reset, then Wait and reset.
590
616
  if (
591
617
  (err.stack.includes(`"status": 503`)
@@ -1,4 +1,5 @@
1
1
  import { runInfinitePoll } from "socket-function/src/batching";
2
+ import { throwDetached } from "../../misc/helpers";
2
3
  import {
3
4
  IArchives, ArchiveFileInfo, ArchivesConfig, ArchivesSyncStatus, ChangesAfterConfig, DelConfig,
4
5
  FindConfig, GetConfig, GetInfoConfig, SetConfig, SetLargeFileConfig, SourceConfig,
@@ -105,8 +106,13 @@ export class ArchivesDelayed implements IArchives {
105
106
  let deadlineReached = force || this.deadlinePassed();
106
107
  for (let [fileName, entry] of [...this.pending]) {
107
108
  if (!deadlineReached && entry.dueAt > now) continue;
109
+ try {
110
+ await this.write(fileName, entry);
111
+ } catch (e) {
112
+ throwDetached(new Error(`Flushing ${JSON.stringify(fileName)} (${entry.data.length} bytes, writeTime ${entry.writeTime}) to ${this.inner.getDebugName()} failed, it stays pending: ${(e as Error).stack ?? e}`));
113
+ continue;
114
+ }
108
115
  // Only drop it if it wasn't overwritten while we were writing
109
- await this.write(fileName, entry);
110
116
  if (this.pending.get(fileName) === entry) {
111
117
  this.pending.delete(fileName);
112
118
  }
@@ -1,5 +1,3 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import preact from "preact";
4
2
  import { isNode } from "socket-function/src/misc";
5
3
  import { css } from "typesafecss";
@@ -1,5 +1,3 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import os from "os";
4
2
  import path from "path";
5
3
  import fsp from "fs/promises";
@@ -1,7 +1,5 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import preact from "preact";
4
- import { observable } from "mobx";
2
+ import { observable } from "../render-utils/mobxTyped";
5
3
  import { observer } from "../render-utils/observer";
6
4
  import { isNode } from "socket-function/src/misc";
7
5
  import { css } from "typesafecss";
@@ -1,4 +1,3 @@
1
- process.env.NODE_ENV = "production";
2
1
  import path from "path";
3
2
  import { SocketFunction } from "socket-function/SocketFunction";
4
3
  import { RequireController } from "socket-function/require/RequireController";
@@ -1,6 +1,4 @@
1
- process.env.NODE_ENV = "production";
2
-
3
- import { observable } from "mobx";
1
+ import { observable } from "../render-utils/mobxTyped";
4
2
  import { list } from "socket-function/src/misc";
5
3
  import { css } from "typesafecss";
6
4
  import { URLParam } from "../render-utils/URLParam";
package/web/browser.tsx CHANGED
@@ -1,7 +1,5 @@
1
- process.env.NODE_ENV = "production";
2
-
3
1
  import * as preact from "preact";
4
- import { observable } from "mobx";
2
+ import { observable } from "../render-utils/mobxTyped";
5
3
  import { observer } from "../render-utils/observer";
6
4
  import { css, isNode } from "typesafecss";
7
5
  import { list } from "socket-function/src/misc";