@synnaxlabs/x 0.55.0 → 0.56.1
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/.turbo/turbo-build.log +10 -13
- package/dist/src/array/nullable.d.ts +1 -1
- package/dist/src/array/nullable.d.ts.map +1 -1
- package/dist/src/caseconv/caseconv.d.ts.map +1 -1
- package/dist/src/compare/compare.d.ts +14 -0
- package/dist/src/compare/compare.d.ts.map +1 -1
- package/dist/src/debounce/debounce.d.ts +7 -2
- package/dist/src/debounce/debounce.d.ts.map +1 -1
- package/dist/src/deep/merge.d.ts.map +1 -1
- package/dist/src/deep/set.d.ts.map +1 -1
- package/dist/src/destructor/destructor.d.ts +1 -0
- package/dist/src/destructor/destructor.d.ts.map +1 -1
- package/dist/src/errors/errors.d.ts +18 -10
- package/dist/src/errors/errors.d.ts.map +1 -1
- package/dist/src/index.d.ts +4 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/migrate/migrate.d.ts.map +1 -1
- package/dist/src/notation/external.d.ts +3 -0
- package/dist/src/notation/external.d.ts.map +1 -0
- package/dist/src/notation/index.d.ts +1 -1
- package/dist/src/notation/notation.d.ts +5 -9
- package/dist/src/notation/notation.d.ts.map +1 -1
- package/dist/src/notation/types.gen.d.ts +9 -0
- package/dist/src/notation/types.gen.d.ts.map +1 -0
- package/dist/src/primitive/primitive.d.ts +16 -0
- package/dist/src/primitive/primitive.d.ts.map +1 -1
- package/dist/src/record/record.d.ts +8 -1
- package/dist/src/record/record.d.ts.map +1 -1
- package/dist/src/require/index.d.ts +2 -0
- package/dist/src/require/index.d.ts.map +1 -0
- package/dist/src/require/require.d.ts +2 -0
- package/dist/src/require/require.d.ts.map +1 -0
- package/dist/src/spatial/base.d.ts +1 -103
- package/dist/src/spatial/base.d.ts.map +1 -1
- package/dist/src/spatial/bounds/bounds.d.ts +3 -3
- package/dist/src/spatial/bounds/bounds.d.ts.map +1 -1
- package/dist/src/spatial/box/box.d.ts +7 -13
- package/dist/src/spatial/box/box.d.ts.map +1 -1
- package/dist/src/spatial/direction/direction.d.ts +17 -16
- package/dist/src/spatial/direction/direction.d.ts.map +1 -1
- package/dist/src/spatial/external.d.ts +1 -2
- package/dist/src/spatial/external.d.ts.map +1 -1
- package/dist/src/spatial/location/location.d.ts +28 -28
- package/dist/src/spatial/location/location.d.ts.map +1 -1
- package/dist/src/spatial/scale/scale.d.ts +2 -2
- package/dist/src/spatial/scale/scale.d.ts.map +1 -1
- package/dist/src/spatial/sticky/sticky.d.ts +15 -15
- package/dist/src/spatial/sticky/sticky.d.ts.map +1 -1
- package/dist/src/spatial/types.gen.d.ts +179 -2
- package/dist/src/spatial/types.gen.d.ts.map +1 -1
- package/dist/src/spatial/xy/xy.d.ts +4 -4
- package/dist/src/spatial/xy/xy.d.ts.map +1 -1
- package/dist/src/status/status.d.ts +11 -0
- package/dist/src/status/status.d.ts.map +1 -1
- package/dist/src/telem/external.d.ts +1 -0
- package/dist/src/telem/external.d.ts.map +1 -1
- package/dist/src/telem/series.d.ts +5 -2
- package/dist/src/telem/series.d.ts.map +1 -1
- package/dist/src/telem/telem.d.ts +42 -34
- package/dist/src/telem/telem.d.ts.map +1 -1
- package/dist/src/telem/types.gen.d.ts +19 -0
- package/dist/src/telem/types.gen.d.ts.map +1 -0
- package/dist/src/text/external.d.ts +3 -0
- package/dist/src/text/external.d.ts.map +1 -0
- package/dist/src/text/index.d.ts +2 -0
- package/dist/src/text/index.d.ts.map +1 -0
- package/dist/src/text/types.d.ts +21 -0
- package/dist/src/text/types.d.ts.map +1 -0
- package/dist/src/text/types.gen.d.ts +13 -0
- package/dist/src/text/types.gen.d.ts.map +1 -0
- package/dist/src/throttle/index.d.ts +2 -0
- package/dist/src/throttle/index.d.ts.map +1 -0
- package/dist/src/throttle/throttle.d.ts +3 -0
- package/dist/src/throttle/throttle.d.ts.map +1 -0
- package/dist/src/throttle/throttle.spec.d.ts +2 -0
- package/dist/src/throttle/throttle.spec.d.ts.map +1 -0
- package/dist/src/zod/parse.d.ts.map +1 -1
- package/dist/x.cjs +10 -10
- package/dist/x.js +1497 -1365
- package/package.json +11 -11
- package/src/array/nullable.ts +1 -4
- package/src/caseconv/caseconv.spec.ts +71 -0
- package/src/caseconv/caseconv.ts +15 -2
- package/src/compare/compare.spec.ts +115 -0
- package/src/compare/compare.ts +29 -0
- package/src/debounce/debounce.spec.ts +258 -24
- package/src/debounce/debounce.ts +49 -30
- package/src/deep/copy.spec.ts +13 -0
- package/src/deep/difference.ts +1 -1
- package/src/deep/merge.ts +2 -1
- package/src/deep/set.ts +2 -1
- package/src/destructor/destructor.ts +2 -0
- package/src/errors/errors.spec.ts +122 -0
- package/src/errors/errors.ts +51 -17
- package/src/index.ts +4 -1
- package/src/migrate/migrate.ts +2 -1
- package/src/notation/external.ts +11 -0
- package/src/notation/index.ts +1 -1
- package/src/notation/notation.spec.ts +260 -2
- package/src/notation/notation.ts +25 -7
- package/src/notation/types.gen.ts +16 -0
- package/src/primitive/primitive.spec.ts +58 -5
- package/src/primitive/primitive.ts +22 -0
- package/src/record/record.spec.ts +26 -0
- package/src/record/record.ts +20 -5
- package/src/require/index.ts +10 -0
- package/src/require/require.ts +10 -0
- package/src/spatial/base.ts +1 -93
- package/src/spatial/bounds/bounds.ts +10 -10
- package/src/spatial/box/box.ts +5 -5
- package/src/spatial/direction/direction.ts +16 -17
- package/src/spatial/external.ts +1 -2
- package/src/spatial/location/location.ts +19 -17
- package/src/spatial/scale/scale.ts +2 -2
- package/src/spatial/sticky/sticky.spec.ts +2 -2
- package/src/spatial/sticky/sticky.ts +6 -13
- package/src/spatial/types.gen.ts +140 -0
- package/src/spatial/xy/xy.ts +7 -7
- package/src/status/status.spec.ts +82 -2
- package/src/status/status.ts +35 -9
- package/src/telem/external.ts +8 -0
- package/src/telem/series.spec.ts +183 -0
- package/src/telem/series.ts +54 -16
- package/src/telem/telem.spec.ts +128 -9
- package/src/telem/telem.ts +91 -79
- package/src/telem/types.gen.ts +28 -0
- package/src/text/external.ts +11 -0
- package/src/text/index.ts +10 -0
- package/src/text/types.gen.ts +16 -0
- package/src/text/types.ts +37 -0
- package/src/{worker → throttle}/index.ts +1 -1
- package/src/throttle/throttle.spec.ts +147 -0
- package/src/throttle/throttle.ts +44 -0
- package/src/zod/parse.ts +2 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/src/spatial/spatial.d.ts +0 -3
- package/dist/src/spatial/spatial.d.ts.map +0 -1
- package/dist/src/worker/index.d.ts +0 -2
- package/dist/src/worker/index.d.ts.map +0 -1
- package/dist/src/worker/worker.d.ts +0 -33
- package/dist/src/worker/worker.d.ts.map +0 -1
- package/dist/src/worker/worker.spec.d.ts +0 -2
- package/dist/src/worker/worker.spec.d.ts.map +0 -1
- package/src/spatial/spatial.ts +0 -44
- package/src/worker/worker.spec.ts +0 -41
- package/src/worker/worker.ts +0 -86
package/src/debounce/debounce.ts
CHANGED
|
@@ -7,38 +7,57 @@
|
|
|
7
7
|
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
func: F,
|
|
12
|
-
waitFor: number,
|
|
13
|
-
): F => {
|
|
14
|
-
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
15
|
-
if (waitFor === 0) return func;
|
|
10
|
+
import { type CrudeTimeSpan, TimeSpan } from "@/telem/telem";
|
|
16
11
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
};
|
|
12
|
+
// DebouncedFn is the function returned by debounce. It carries cancel and
|
|
13
|
+
// flush handles so callers (e.g., React cleanup paths) can drop pending
|
|
14
|
+
// invocations or force them to run immediately on demand. Shape matches
|
|
15
|
+
// lodash.debounce.
|
|
16
|
+
export interface DebouncedFn<Args extends unknown[]> {
|
|
17
|
+
(...args: Args): void;
|
|
18
|
+
cancel: () => void;
|
|
19
|
+
flush: () => void;
|
|
20
|
+
}
|
|
27
21
|
|
|
28
|
-
|
|
29
|
-
func: F,
|
|
30
|
-
waitFor: number,
|
|
31
|
-
): F => {
|
|
32
|
-
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
33
|
-
if (waitFor === 0) return func;
|
|
22
|
+
const noop = (): void => {};
|
|
34
23
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
24
|
+
export const debounce = <Args extends unknown[]>(
|
|
25
|
+
func: (...args: Args) => void,
|
|
26
|
+
waitFor: CrudeTimeSpan,
|
|
27
|
+
): DebouncedFn<Args> => {
|
|
28
|
+
const debouncePeriod = new TimeSpan(waitFor);
|
|
29
|
+
if (debouncePeriod.valueOf() <= 0) {
|
|
30
|
+
const passthrough = ((...args: Args) => func(...args)) as DebouncedFn<Args>;
|
|
31
|
+
passthrough.cancel = noop;
|
|
32
|
+
passthrough.flush = noop;
|
|
33
|
+
return passthrough;
|
|
34
|
+
}
|
|
35
|
+
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
36
|
+
let latestArgs: Args | null = null;
|
|
37
|
+
const invoke = (): void => {
|
|
38
|
+
if (latestArgs === null) return;
|
|
39
|
+
const args = latestArgs;
|
|
40
|
+
latestArgs = null;
|
|
41
|
+
func(...args);
|
|
41
42
|
};
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
const debounced = ((...args: Args): void => {
|
|
44
|
+
latestArgs = args;
|
|
45
|
+
clearTimeout(timeout);
|
|
46
|
+
timeout = setTimeout(() => {
|
|
47
|
+
timeout = undefined;
|
|
48
|
+
invoke();
|
|
49
|
+
}, debouncePeriod.milliseconds);
|
|
50
|
+
}) as DebouncedFn<Args>;
|
|
51
|
+
debounced.cancel = (): void => {
|
|
52
|
+
clearTimeout(timeout);
|
|
53
|
+
timeout = undefined;
|
|
54
|
+
latestArgs = null;
|
|
55
|
+
};
|
|
56
|
+
debounced.flush = (): void => {
|
|
57
|
+
if (timeout === undefined) return;
|
|
58
|
+
clearTimeout(timeout);
|
|
59
|
+
timeout = undefined;
|
|
60
|
+
invoke();
|
|
61
|
+
};
|
|
62
|
+
return debounced;
|
|
44
63
|
};
|
package/src/deep/copy.spec.ts
CHANGED
|
@@ -145,4 +145,17 @@ describe("copy", () => {
|
|
|
145
145
|
expect(copied.uint8).not.toBe(uint8);
|
|
146
146
|
} else expect(Array.from(copied.uint8 as Uint8Array)).toEqual([1, 2, 3]);
|
|
147
147
|
});
|
|
148
|
+
|
|
149
|
+
// Mirrors the immer Draft scenario: callers store snapshots of mutable
|
|
150
|
+
// proxy state in long-lived structures (e.g., undo entries) that outlive
|
|
151
|
+
// the proxy. The snapshot must own its data so it survives revocation.
|
|
152
|
+
it("should produce a snapshot detached from a revocable proxy source", () => {
|
|
153
|
+
const target = { nested: { value: 1 }, list: [1, 2, 3] };
|
|
154
|
+
const { proxy, revoke } = Proxy.revocable(target, {});
|
|
155
|
+
const copied = deep.copy(proxy);
|
|
156
|
+
revoke();
|
|
157
|
+
expect(copied).toEqual({ nested: { value: 1 }, list: [1, 2, 3] });
|
|
158
|
+
expect(copied.nested).not.toBe(target.nested);
|
|
159
|
+
expect(copied.list).not.toBe(target.list);
|
|
160
|
+
});
|
|
148
161
|
});
|
package/src/deep/difference.ts
CHANGED
|
@@ -30,7 +30,7 @@ export const difference = (
|
|
|
30
30
|
}
|
|
31
31
|
for (let i = 0; i < a.length; i++) compare(a[i], b[i], `${currentPath}[${i}]`);
|
|
32
32
|
} else {
|
|
33
|
-
const keys = new Set([...Object.keys(a
|
|
33
|
+
const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
34
34
|
keys.forEach((key) => {
|
|
35
35
|
compare(
|
|
36
36
|
a[key as keyof typeof a],
|
package/src/deep/merge.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { type z } from "zod";
|
|
11
11
|
|
|
12
12
|
import { type Partial } from "@/deep/partial";
|
|
13
|
+
import { errors } from "@/errors";
|
|
13
14
|
import { narrow } from "@/narrow";
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -32,7 +33,7 @@ export const override = <T>(base: T, ...overrides: Array<Partial<T>>): T => {
|
|
|
32
33
|
} catch (e) {
|
|
33
34
|
if (e instanceof TypeError)
|
|
34
35
|
throw new TypeError(`.${key}: ${e.message}`, { cause: e });
|
|
35
|
-
throw e;
|
|
36
|
+
throw errors.fromUnknown(e);
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
return override(base, ...overrides);
|
package/src/deep/set.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
import { defaultGetter, findBestKey, getIndex, SEPARATOR } from "@/deep/path";
|
|
11
|
+
import { errors } from "@/errors";
|
|
11
12
|
import { type record } from "@/record";
|
|
12
13
|
|
|
13
14
|
export const set = <V>(obj: V, path: string, value: unknown): void => {
|
|
@@ -86,6 +87,6 @@ export const set = <V>(obj: V, path: string, value: unknown): void => {
|
|
|
86
87
|
result[lastPart] = value;
|
|
87
88
|
} catch (e) {
|
|
88
89
|
console.error("failed to set value", value, "at path", path, "on object", obj);
|
|
89
|
-
throw e;
|
|
90
|
+
throw errors.fromUnknown(e);
|
|
90
91
|
}
|
|
91
92
|
};
|
|
@@ -96,6 +96,128 @@ describe("errors", () => {
|
|
|
96
96
|
const decoded = errors.decode(encoded);
|
|
97
97
|
expect(errors.Unknown.matches(decoded)).toBe(true);
|
|
98
98
|
});
|
|
99
|
+
|
|
100
|
+
it("should preserve name and stack across encode/decode for a generic Error", () => {
|
|
101
|
+
const error = new TypeError("boom");
|
|
102
|
+
const encoded = errors.encode(error);
|
|
103
|
+
expect(encoded.name).toEqual("TypeError");
|
|
104
|
+
expect(encoded.stack).toEqual(error.stack);
|
|
105
|
+
const decoded = errors.decode(encoded);
|
|
106
|
+
expect((decoded as Error).name).toEqual("TypeError");
|
|
107
|
+
expect((decoded as Error).stack).toEqual(error.stack);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("should preserve name and stack when a typed error round-trips through a provider", () => {
|
|
111
|
+
errors.register({
|
|
112
|
+
encode: myCustomErrorEncoder,
|
|
113
|
+
decode: myCustomErrorDecoder,
|
|
114
|
+
});
|
|
115
|
+
const error = new ErrorOne("boom");
|
|
116
|
+
const encoded = errors.encode(error);
|
|
117
|
+
expect(encoded.name).toEqual(ErrorOne.TYPE);
|
|
118
|
+
expect(encoded.stack).toEqual(error.stack);
|
|
119
|
+
const decoded = errors.decode(encoded);
|
|
120
|
+
expect(ErrorOne.matches(decoded)).toBe(true);
|
|
121
|
+
expect((decoded as Error).stack).toEqual(error.stack);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should leave the decoded error untouched when the payload omits name and stack", () => {
|
|
125
|
+
const decoded = errors.decode({ type: errors.UNKNOWN, data: "no native fields" });
|
|
126
|
+
expect(decoded).toBeInstanceOf(Error);
|
|
127
|
+
expect((decoded as Error).message).toEqual("no native fields");
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe("fromUnknown", () => {
|
|
132
|
+
it("should return the same Error instance when given an Error", () => {
|
|
133
|
+
const original = new Error("already an error");
|
|
134
|
+
const result = errors.fromUnknown(original);
|
|
135
|
+
expect(result).toBe(original);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("should preserve typed-error subclasses when given one", () => {
|
|
139
|
+
const original = new ErrorOne("typed");
|
|
140
|
+
const result = errors.fromUnknown(original);
|
|
141
|
+
expect(result).toBe(original);
|
|
142
|
+
expect(ErrorOne.matches(result)).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("should preserve other Error subclasses like TypeError", () => {
|
|
146
|
+
const original = new TypeError("bad type");
|
|
147
|
+
const result = errors.fromUnknown(original);
|
|
148
|
+
expect(result).toBe(original);
|
|
149
|
+
expect(result).toBeInstanceOf(TypeError);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("should wrap a string with the string as the message", () => {
|
|
153
|
+
const result = errors.fromUnknown("plain string");
|
|
154
|
+
expect(result).toBeInstanceOf(Error);
|
|
155
|
+
expect(result.message).toEqual('"plain string"');
|
|
156
|
+
expect(result.cause).toEqual("plain string");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("should wrap a number using JSON.stringify for the message", () => {
|
|
160
|
+
const result = errors.fromUnknown(42);
|
|
161
|
+
expect(result).toBeInstanceOf(Error);
|
|
162
|
+
expect(result.message).toEqual("42");
|
|
163
|
+
expect(result.cause).toEqual(42);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("should wrap an object using JSON.stringify for the message", () => {
|
|
167
|
+
const value = { foo: "bar", n: 1 };
|
|
168
|
+
const result = errors.fromUnknown(value);
|
|
169
|
+
expect(result).toBeInstanceOf(Error);
|
|
170
|
+
expect(result.message).toEqual('{"foo":"bar","n":1}');
|
|
171
|
+
expect(result.cause).toBe(value);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("should fall back to String() when JSON.stringify throws on a circular ref", () => {
|
|
175
|
+
const value: Record<string, unknown> = { name: "loop" };
|
|
176
|
+
value.self = value;
|
|
177
|
+
const result = errors.fromUnknown(value);
|
|
178
|
+
expect(result).toBeInstanceOf(Error);
|
|
179
|
+
// Plain objects without a custom toString fall through to "[object Object]".
|
|
180
|
+
expect(result.message).toEqual("[object Object]");
|
|
181
|
+
expect(result.cause).toBe(value);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("should fall back to String() for a BigInt", () => {
|
|
185
|
+
const value = 9007199254740993n;
|
|
186
|
+
const result = errors.fromUnknown(value);
|
|
187
|
+
expect(result).toBeInstanceOf(Error);
|
|
188
|
+
expect(result.message).toEqual(String(value));
|
|
189
|
+
expect(result.cause).toBe(value);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("should wrap null with a stringified message", () => {
|
|
193
|
+
const result = errors.fromUnknown(null);
|
|
194
|
+
expect(result).toBeInstanceOf(Error);
|
|
195
|
+
expect(result.message).toEqual("null");
|
|
196
|
+
expect(result.cause).toBeNull();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("should fall back to String() for undefined (JSON.stringify returns undefined)", () => {
|
|
200
|
+
const result = errors.fromUnknown(undefined);
|
|
201
|
+
expect(result).toBeInstanceOf(Error);
|
|
202
|
+
expect(result.message).toEqual("undefined");
|
|
203
|
+
expect(result.cause).toBeUndefined();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it("should fall back to String() for a function (JSON.stringify returns undefined)", () => {
|
|
207
|
+
const value = function named() {};
|
|
208
|
+
const result = errors.fromUnknown(value);
|
|
209
|
+
expect(result).toBeInstanceOf(Error);
|
|
210
|
+
expect(result.message).toEqual(String(value));
|
|
211
|
+
expect(result.cause).toBe(value);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("should fall back to String() for a symbol (JSON.stringify returns undefined)", () => {
|
|
215
|
+
const value = Symbol("sym");
|
|
216
|
+
const result = errors.fromUnknown(value);
|
|
217
|
+
expect(result).toBeInstanceOf(Error);
|
|
218
|
+
expect(result.message).toEqual("Symbol(sym)");
|
|
219
|
+
expect(result.cause).toBe(value);
|
|
220
|
+
});
|
|
99
221
|
});
|
|
100
222
|
|
|
101
223
|
describe("matches", () => {
|
package/src/errors/errors.ts
CHANGED
|
@@ -142,6 +142,28 @@ export const isTyped = (error: unknown): error is Typed => {
|
|
|
142
142
|
return true;
|
|
143
143
|
};
|
|
144
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Coerces an arbitrary thrown value into an `Error` so it can be re-thrown without
|
|
147
|
+
* tripping `@typescript-eslint/only-throw-error` and so callers can rely on a uniform
|
|
148
|
+
* `Error` shape. The original value is preserved on `Error.cause` for stack-trace
|
|
149
|
+
* continuity.
|
|
150
|
+
*
|
|
151
|
+
* - If `value` is already an `Error`, it is returned unchanged.
|
|
152
|
+
* - Otherwise the message is derived from `JSON.stringify(value)` when possible (which
|
|
153
|
+
* carries more detail for plain objects), falling back to `String(value)` for
|
|
154
|
+
* circular structures, BigInts, or anything else that fails to serialize.
|
|
155
|
+
*/
|
|
156
|
+
export const fromUnknown = (value: unknown): Error => {
|
|
157
|
+
if (value instanceof Error) return value;
|
|
158
|
+
let message: string;
|
|
159
|
+
try {
|
|
160
|
+
message = JSON.stringify(value) ?? String(value);
|
|
161
|
+
} catch {
|
|
162
|
+
message = String(value);
|
|
163
|
+
}
|
|
164
|
+
return new Error(message, { cause: value });
|
|
165
|
+
};
|
|
166
|
+
|
|
145
167
|
/** Constant representing an unknown error type */
|
|
146
168
|
export const UNKNOWN = "unknown";
|
|
147
169
|
|
|
@@ -169,6 +191,18 @@ interface Provider {
|
|
|
169
191
|
decode: Decoder;
|
|
170
192
|
}
|
|
171
193
|
|
|
194
|
+
const withNative = (payload: Payload, error: Error): Payload => ({
|
|
195
|
+
...payload,
|
|
196
|
+
name: error.name,
|
|
197
|
+
stack: error.stack,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const applyNative = (error: Error, payload: Payload): Error => {
|
|
201
|
+
if (payload.name != null) error.name = payload.name;
|
|
202
|
+
if (payload.stack != null) error.stack = payload.stack;
|
|
203
|
+
return error;
|
|
204
|
+
};
|
|
205
|
+
|
|
172
206
|
class Registry {
|
|
173
207
|
private readonly providers: Provider[] = [];
|
|
174
208
|
|
|
@@ -181,9 +215,10 @@ class Registry {
|
|
|
181
215
|
if (isTyped(error))
|
|
182
216
|
for (const provider of this.providers) {
|
|
183
217
|
const payload = provider.encode(error);
|
|
184
|
-
if (payload != null) return payload;
|
|
218
|
+
if (payload != null) return withNative(payload, error);
|
|
185
219
|
}
|
|
186
|
-
if (error instanceof Error)
|
|
220
|
+
if (error instanceof Error)
|
|
221
|
+
return withNative({ type: UNKNOWN, data: error.message }, error);
|
|
187
222
|
if (typeof error === "string") return { type: UNKNOWN, data: error };
|
|
188
223
|
try {
|
|
189
224
|
return { type: UNKNOWN, data: JSON.stringify(error) };
|
|
@@ -194,12 +229,13 @@ class Registry {
|
|
|
194
229
|
|
|
195
230
|
decode(payload?: Payload | null): Error | null {
|
|
196
231
|
if (payload == null || payload.type === NONE) return null;
|
|
197
|
-
if (payload.type === UNKNOWN)
|
|
232
|
+
if (payload.type === UNKNOWN)
|
|
233
|
+
return applyNative(new Unknown(payload.data), payload);
|
|
198
234
|
for (const provider of this.providers) {
|
|
199
235
|
const error = provider.decode(payload);
|
|
200
|
-
if (error != null) return error;
|
|
236
|
+
if (error != null) return applyNative(error, payload);
|
|
201
237
|
}
|
|
202
|
-
return new Unknown(payload.data);
|
|
238
|
+
return applyNative(new Unknown(payload.data), payload);
|
|
203
239
|
}
|
|
204
240
|
}
|
|
205
241
|
|
|
@@ -242,8 +278,16 @@ export const decode = (payload?: Payload | null): Error | null => {
|
|
|
242
278
|
*/
|
|
243
279
|
export class Unknown extends createTyped("unknown") {}
|
|
244
280
|
|
|
245
|
-
/** Zod schema for validating error payloads
|
|
246
|
-
|
|
281
|
+
/** Zod schema for validating error payloads. `name` and `stack` are TypeScript-only
|
|
282
|
+
* fields; Go and Python don't populate them. They're carried opaquely across the wire
|
|
283
|
+
* and re-applied to the reconstructed error on decode, which keeps the original error
|
|
284
|
+
* name (e.g. "TypeError") and stack trace alive across worker / network boundaries. */
|
|
285
|
+
export const payloadZ = z.object({
|
|
286
|
+
type: z.string(),
|
|
287
|
+
data: z.string(),
|
|
288
|
+
name: z.string().optional(),
|
|
289
|
+
stack: z.string().optional(),
|
|
290
|
+
});
|
|
247
291
|
|
|
248
292
|
/** Network-portable representation of an error */
|
|
249
293
|
export type Payload = z.infer<typeof payloadZ>;
|
|
@@ -251,15 +295,5 @@ export type Payload = z.infer<typeof payloadZ>;
|
|
|
251
295
|
/** Error for representing the cancellation of an operation */
|
|
252
296
|
export class Canceled extends createTyped("canceled") {}
|
|
253
297
|
|
|
254
|
-
/** A payload representing a native JavaScript Error */
|
|
255
|
-
export interface NativePayload {
|
|
256
|
-
/** The name of the error */
|
|
257
|
-
name: string;
|
|
258
|
-
/** The message of the error */
|
|
259
|
-
message: string;
|
|
260
|
-
/** The stack trace of the error */
|
|
261
|
-
stack?: string;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
298
|
/** Error for representing a method that is not implemented */
|
|
265
299
|
export class NotImplemented extends createTyped("not_implemented") {}
|
package/src/index.ts
CHANGED
|
@@ -33,10 +33,12 @@ export * from "@/math";
|
|
|
33
33
|
export * from "@/migrate";
|
|
34
34
|
export * from "@/narrow";
|
|
35
35
|
export * from "@/notation";
|
|
36
|
+
export * from "@/numeric";
|
|
36
37
|
export * from "@/observe";
|
|
37
38
|
export * from "@/optional";
|
|
38
39
|
export * from "@/primitive";
|
|
39
40
|
export * from "@/record";
|
|
41
|
+
export * from "@/require";
|
|
40
42
|
export * from "@/runtime";
|
|
41
43
|
export * from "@/scheduler";
|
|
42
44
|
export * from "@/shallow";
|
|
@@ -47,9 +49,10 @@ export * from "@/strings";
|
|
|
47
49
|
export * from "@/sync";
|
|
48
50
|
export * from "@/telem";
|
|
49
51
|
export * from "@/testutil";
|
|
52
|
+
export * from "@/text";
|
|
53
|
+
export * from "@/throttle";
|
|
50
54
|
export * from "@/types";
|
|
51
55
|
export * from "@/unique";
|
|
52
56
|
export * from "@/url";
|
|
53
57
|
export * from "@/uuid";
|
|
54
|
-
export * from "@/worker";
|
|
55
58
|
export * from "@/zod";
|
package/src/migrate/migrate.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
|
|
12
12
|
import { compare } from "@/compare";
|
|
13
|
+
import { errors } from "@/errors";
|
|
13
14
|
import { type optional } from "@/optional";
|
|
14
15
|
|
|
15
16
|
export const semVerZ = z
|
|
@@ -203,7 +204,7 @@ export const createMigration =
|
|
|
203
204
|
} catch (e) {
|
|
204
205
|
console.log(`${name} failed to migrate from ${input.version}`);
|
|
205
206
|
console.error(e);
|
|
206
|
-
throw e;
|
|
207
|
+
throw errors.fromUnknown(e);
|
|
207
208
|
}
|
|
208
209
|
};
|
|
209
210
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Copyright 2026 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
export * from "@/notation/notation";
|
|
11
|
+
export { type Notation, NOTATIONS, notationZ } from "@/notation/types.gen";
|
package/src/notation/index.ts
CHANGED