@synnaxlabs/client 0.57.1 → 0.57.3

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 (53) hide show
  1. package/dist/{client-DDACDVZ-.js → client-CX6CMvCc.js} +3686 -3548
  2. package/dist/client-CX6CMvCc.js.map +1 -0
  3. package/dist/client.js +1 -1
  4. package/dist/src/arc/client.d.ts.map +1 -1
  5. package/dist/src/channel/client.d.ts +1 -0
  6. package/dist/src/channel/client.d.ts.map +1 -1
  7. package/dist/src/device/client.d.ts.map +1 -1
  8. package/dist/src/framer/streamer.d.ts +34 -18
  9. package/dist/src/framer/streamer.d.ts.map +1 -1
  10. package/dist/src/label/store.d.ts +1 -1
  11. package/dist/src/label/store.d.ts.map +1 -1
  12. package/dist/src/ontology/client.d.ts.map +1 -1
  13. package/dist/src/ontology/store.d.ts +16 -1
  14. package/dist/src/ontology/store.d.ts.map +1 -1
  15. package/dist/src/query/external.d.ts +1 -0
  16. package/dist/src/query/external.d.ts.map +1 -1
  17. package/dist/src/query/indexes.d.ts +38 -0
  18. package/dist/src/query/indexes.d.ts.map +1 -0
  19. package/dist/src/query/table.d.ts +20 -4
  20. package/dist/src/query/table.d.ts.map +1 -1
  21. package/dist/src/rack/client.d.ts.map +1 -1
  22. package/dist/src/ranger/client.d.ts +11 -1
  23. package/dist/src/ranger/client.d.ts.map +1 -1
  24. package/dist/src/status/client.d.ts.map +1 -1
  25. package/dist/src/status/status.d.ts +2 -0
  26. package/dist/src/status/status.d.ts.map +1 -1
  27. package/dist/src/task/client.d.ts +19 -1
  28. package/dist/src/task/client.d.ts.map +1 -1
  29. package/dist/src/testutil/client.d.ts +2 -0
  30. package/dist/src/testutil/client.d.ts.map +1 -1
  31. package/dist/src/testutil/proxy.d.ts +8 -0
  32. package/dist/src/testutil/proxy.d.ts.map +1 -1
  33. package/dist/testutil.js +80 -60
  34. package/dist/testutil.js.map +1 -1
  35. package/package.json +5 -5
  36. package/src/arc/client.ts +2 -20
  37. package/src/channel/client.ts +11 -6
  38. package/src/device/client.ts +4 -3
  39. package/src/framer/streamer.ts +71 -6
  40. package/src/label/store.ts +7 -2
  41. package/src/ontology/client.ts +15 -8
  42. package/src/ontology/store.ts +27 -5
  43. package/src/query/external.ts +1 -0
  44. package/src/query/indexes.ts +94 -0
  45. package/src/query/table.ts +74 -12
  46. package/src/rack/client.ts +5 -4
  47. package/src/ranger/client.ts +65 -24
  48. package/src/status/client.ts +15 -11
  49. package/src/status/status.ts +14 -0
  50. package/src/task/client.ts +54 -19
  51. package/src/testutil/client.ts +5 -1
  52. package/src/testutil/proxy.ts +59 -6
  53. package/dist/client-DDACDVZ-.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/status/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/status/client.ts"],"names":[],"mappings":"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"}
@@ -54,6 +54,8 @@ export declare const detailsOf: (status: Status) => record.Unknown | undefined;
54
54
  export declare const keepVariants: (variant?: Variant, keep?: Variant | Variant[]) => Variant | undefined;
55
55
  /** @returns the variant unless it is one of the removed ones. */
56
56
  export declare const removeVariants: (variant?: Variant, remove?: Variant | Variant[]) => Variant | undefined;
57
+ /** @returns true when a is more severe than b. */
58
+ export declare const moreSevere: (a: Variant, b: Variant) => boolean;
57
59
  /** Options for {@link toString}. */
58
60
  export interface ToStringOptions {
59
61
  includeTimestamp?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/status/status.ts"],"names":[],"mappings":"AASA,OAAO,EAIL,KAAK,QAAQ,EAEb,MAAM,EACN,SAAS,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAG/D,KAAK,IAAI,CAAC,CAAC,SAAS,OAAO,IAAI;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC;AAEF,oEAAoE;AACpE,MAAM,MAAM,KAAK,CACf,aAAa,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,QAAQ,EAC5C,CAAC,SAAS,OAAO,GAAG,OAAO,IACzB,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC,GACrD,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG;IAAE,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;CAAE,CAAC,CAAC;AAErF;;;;;;GAMG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;CAClD;AA0BD,+DAA+D;AAC/D,eAAO,MAAM,sBAAsB;;;8FAKV,CAAC;AAc1B;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,KAAK,OAAO,EACZ,UAAU,MAAM,KACf,MAAM,CAAC,OAAO,sBAAsB,EAAE,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAwB7D,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,GAClB,GAAG,MAAM,CAAC,OAAO,sBAAsB,EAAE,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,KAC9D,KAMF,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,MAAM,GACjB,aAAa,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,QAAQ,EAC5C,CAAC,SAAS,OAAO,GAAG,OAAO,EAE3B,MAAM,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,KAC5B,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAOM,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,KAAG,MAAM,CAAC,OAAO,GAAG,SACV,CAAC;AAEnD,4EAA4E;AAC5E,eAAO,MAAM,YAAY,GACvB,UAAU,OAAO,EACjB,OAAM,OAAO,GAAG,OAAO,EAAO,KAC7B,OAAO,GAAG,SAOZ,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,cAAc,GACzB,UAAU,OAAO,EACjB,SAAQ,OAAO,GAAG,OAAO,EAAO,KAC/B,OAAO,GAAG,SAOZ,CAAC;AAEF,oCAAoC;AACpC,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAiBD,6EAA6E;AAC7E,eAAO,MAAM,QAAQ,GAAI,OAAO,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,QAAQ,EAC7D,MAAM,MAAM,CAAC,OAAO,CAAC,EACrB,UAAS,eAAoB,KAC5B,MAqBF,CAAC"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/status/status.ts"],"names":[],"mappings":"AASA,OAAO,EAIL,KAAK,QAAQ,EAEb,MAAM,EACN,SAAS,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAG/D,KAAK,IAAI,CAAC,CAAC,SAAS,OAAO,IAAI;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC;AAEF,oEAAoE;AACpE,MAAM,MAAM,KAAK,CACf,aAAa,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,QAAQ,EAC5C,CAAC,SAAS,OAAO,GAAG,OAAO,IACzB,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC,GACrD,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG;IAAE,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;CAAE,CAAC,CAAC;AAErF;;;;;;GAMG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;CAClD;AA0BD,+DAA+D;AAC/D,eAAO,MAAM,sBAAsB;;;8FAKV,CAAC;AAc1B;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,KAAK,OAAO,EACZ,UAAU,MAAM,KACf,MAAM,CAAC,OAAO,sBAAsB,EAAE,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAwB7D,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,GAClB,GAAG,MAAM,CAAC,OAAO,sBAAsB,EAAE,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,KAC9D,KAMF,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,MAAM,GACjB,aAAa,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,QAAQ,EAC5C,CAAC,SAAS,OAAO,GAAG,OAAO,EAE3B,MAAM,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,KAC5B,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAOM,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,KAAG,MAAM,CAAC,OAAO,GAAG,SACV,CAAC;AAEnD,4EAA4E;AAC5E,eAAO,MAAM,YAAY,GACvB,UAAU,OAAO,EACjB,OAAM,OAAO,GAAG,OAAO,EAAO,KAC7B,OAAO,GAAG,SAOZ,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,cAAc,GACzB,UAAU,OAAO,EACjB,SAAQ,OAAO,GAAG,OAAO,EAAO,KAC/B,OAAO,GAAG,SAOZ,CAAC;AAYF,kDAAkD;AAClD,eAAO,MAAM,UAAU,GAAI,GAAG,OAAO,EAAE,GAAG,OAAO,KAAG,OACzB,CAAC;AAE5B,oCAAoC;AACpC,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAiBD,6EAA6E;AAC7E,eAAO,MAAM,QAAQ,GAAI,OAAO,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,QAAQ,EAC7D,MAAM,MAAM,CAAC,OAAO,CAAC,EACrB,UAAS,eAAoB,KAC5B,MAqBF,CAAC"}
@@ -7,7 +7,7 @@ import { query } from '../query';
7
7
  import { Key as RackKey } from '../rack/types.gen';
8
8
  import { ranger } from '../ranger';
9
9
  import { status } from '../status';
10
- import { Key, New, Payload, PayloadSchemas as Schemas, Status } from './types.gen';
10
+ import { Key, New, Payload, PayloadSchemas as Schemas, Status, StatusDetailsZodObject } from './types.gen';
11
11
  export type { PayloadSchemas as Schemas } from './types.gen';
12
12
  export declare const COMMAND_CHANNEL_NAME = "sy_task_cmd";
13
13
  export declare const SET_CHANNEL_NAME = "sy_task_set";
@@ -34,6 +34,18 @@ export interface DriftedParams extends Pick<Payload, "configHash" | "rack" | "st
34
34
  * @returns True when a redeploy (start) would change the running instance.
35
35
  */
36
36
  export declare const drifted: (task: DriftedParams) => boolean;
37
+ /**
38
+ * The task status schema without a details-data schema. Hoisted because statusZ()
39
+ * builds a fresh schema per call, which costs far more than the parse itself.
40
+ */
41
+ export declare const defaultStatusZ: status.StatusZodObject<StatusDetailsZodObject<z.ZodNever>, z.ZodEnum<{
42
+ error: "error";
43
+ success: "success";
44
+ info: "info";
45
+ warning: "warning";
46
+ loading: "loading";
47
+ disabled: "disabled";
48
+ }>>;
37
49
  /** One command sent to a task, as issued from the task itself. */
38
50
  export interface TaskExecuteCommandParams {
39
51
  type: string;
@@ -241,6 +253,7 @@ export declare class Client extends query.Retriever<typeof retrieveMultiParamsZ,
241
253
  /** The task record table; injected into sibling clients at wiring. */
242
254
  readonly store: query.Table<Key, Omit<Task, "status">>;
243
255
  private readonly cfg;
256
+ private readonly statusesByTask;
244
257
  private readonly commandDeadlines;
245
258
  constructor(cfg: ClientConfig);
246
259
  create(task: New): Promise<Task>;
@@ -293,6 +306,11 @@ export declare class Client extends query.Retriever<typeof retrieveMultiParamsZ,
293
306
  }
294
307
  /** @returns the key of the status that reports on the given task. */
295
308
  export declare const statusKey: (key: Key) => string;
309
+ /**
310
+ * @returns the keys of the tasks a status change affects, or null when none. A status
311
+ * names its task in `details.task`, with the "task:<key>" status key as a fallback.
312
+ */
313
+ export declare const affectedKeys: (event: query.TableEvent<status.Key, status.Status>) => Key[] | null;
296
314
  /** A command queued for a task. */
297
315
  export interface NewCommand {
298
316
  task: Key;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/task/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/task/client.ts"],"names":[],"mappings":"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"}
@@ -6,4 +6,6 @@ export declare const TEST_CLIENT_PARAMS: SynnaxParams;
6
6
  * not need to close it themselves.
7
7
  */
8
8
  export declare const createTestClient: (params?: Partial<SynnaxParams>) => Synnax;
9
+ /** Spies on the client's unary send so specs can count requests on the wire. */
10
+ export declare const spyOnSend: (client: Synnax, field?: "transport") => import('vitest').Mock<(<RQ extends import('zod').ZodType, RS extends import('zod').ZodType = RQ>(target: string, req: import('zod').input<RQ> | import('zod').infer<RQ>, reqSchema: RQ, resSchema: RS) => Promise<import('zod').infer<RS>>)>;
9
11
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/testutil/client.ts"],"names":[],"mappings":"AAYA,OAAO,MAAM,EAAE,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAErD,eAAO,MAAM,kBAAkB,EAAE,YAUhC,CAAC;AAkBF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,OAAO,CAAC,YAAY,CAAC,KAAG,MAIjE,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/testutil/client.ts"],"names":[],"mappings":"AAYA,OAAO,MAAM,EAAE,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAErD,eAAO,MAAM,kBAAkB,EAAE,YAUhC,CAAC;AAkBF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,OAAO,CAAC,YAAY,CAAC,KAAG,MAIjE,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,QAAO,WAAyB,iPACnC,CAAC"}
@@ -15,6 +15,14 @@ export interface SeverableProxy {
15
15
  port: number;
16
16
  /** Drops every live connection and refuses new ones, as if the cluster died. */
17
17
  sever: () => Promise<void>;
18
+ /**
19
+ * Silently kills every live WebSocket connection, modeling a half-open socket (NAT
20
+ * timeout, VPN drop, laptop sleep): the cluster side is destroyed while the client
21
+ * side is held open with its writes discarded, so no close or reset ever reaches the
22
+ * client. New connections still forward. Returns how many connections were
23
+ * blackholed.
24
+ */
25
+ blackholeStreams: () => number;
18
26
  /** Accepts connections again on the same port. */
19
27
  restore: () => Promise<void>;
20
28
  /** Shuts the proxy down for good. */
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../../src/testutil/proxy.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,OAAO,EAAY,MAAM,eAAe,CAAC;AAIvD;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,OAAO,CAAC,MAIhC,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,kDAAkD;IAClD,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,qCAAqC;IACrC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAQ,oBAAyB,KAChC,OAAO,CAAC,cAAc,CAuDxB,CAAC"}
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../../src/testutil/proxy.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,OAAO,EAAY,MAAM,eAAe,CAAC;AAIvD;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,OAAO,CAAC,MAIhC,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B;;;;;;OAMG;IACH,gBAAgB,EAAE,MAAM,MAAM,CAAC;IAC/B,kDAAkD;IAClD,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,qCAAqC;IACrC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AASD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAQ,oBAAyB,KAChC,OAAO,CAAC,cAAc,CA6FxB,CAAC"}
package/dist/testutil.js CHANGED
@@ -1,9 +1,9 @@
1
- import { B as e, G as t, K as n, V as r, W as i, Z as a, d as o, t as s, z as c } from "./client-DDACDVZ-.js";
1
+ import { B as e, G as t, K as n, V as r, W as i, Z as a, d as o, t as s, z as c } from "./client-CX6CMvCc.js";
2
2
  import { DataType as l, TimeSpan as u, TimeStamp as d, array as f, errors as p, id as m } from "@synnaxlabs/x";
3
- import { afterAll as h } from "vitest";
4
- import { connect as g, createServer as _ } from "node:net";
3
+ import { afterAll as h, vi as g } from "vitest";
4
+ import { connect as _, createServer as v } from "node:net";
5
5
  //#region src/testutil/client.ts
6
- var v = {
6
+ var y = {
7
7
  host: "localhost",
8
8
  port: 9090,
9
9
  username: "synnax",
@@ -13,32 +13,32 @@ var v = {
13
13
  baseInterval: u.seconds(1),
14
14
  scale: 1.5
15
15
  }
16
- }, y = [];
16
+ }, b = [];
17
17
  h(async () => {
18
- let e = (await Promise.allSettled(y.map((e) => e.close()))).filter((e) => e.status === "rejected");
18
+ let e = (await Promise.allSettled(b.map((e) => e.close()))).filter((e) => e.status === "rejected");
19
19
  if (e.length > 0) throw AggregateError(e.map((e) => e.reason), "failed to close test clients");
20
20
  });
21
- var b = (e) => {
21
+ var x = (e) => {
22
22
  let t = new s({
23
- ...v,
23
+ ...y,
24
24
  ...e
25
25
  });
26
- return y.push(t), t;
27
- }, x = (e) => n.matches(e) || e instanceof Error && e.cause != null && x(e.cause), S = async (e, t) => {
28
- let n = b({
26
+ return b.push(t), t;
27
+ }, S = (e, t = "transport") => g.spyOn(e[t].unary, "send"), C = (e) => n.matches(e) || e instanceof Error && e.cause != null && C(e.cause), w = async (e, t) => {
28
+ let n = x({
29
29
  username: e,
30
30
  password: "test",
31
31
  onInternalError: (e) => {
32
- x(e) || console.error(e);
32
+ C(e) || console.error(e);
33
33
  }
34
34
  });
35
35
  try {
36
36
  await n.access.policies.retrieveForSubject(c(t));
37
37
  } catch (e) {
38
- if (!x(e)) throw p.fromUnknown(e);
38
+ if (!C(e)) throw p.fromUnknown(e);
39
39
  }
40
40
  return n;
41
- }, C = async (e) => {
41
+ }, T = async (e) => {
42
42
  let t = m.create();
43
43
  return {
44
44
  username: t,
@@ -49,30 +49,30 @@ var b = (e) => {
49
49
  lastName: "test"
50
50
  })).key
51
51
  };
52
- }, w = async (t, n) => {
53
- let i = await C(t), a = await Promise.all(f.toArray(n).map(async (e) => await t.access.policies.create(e))), o = await t.access.roles.create({
52
+ }, E = async (t, n) => {
53
+ let i = await T(t), a = await Promise.all(f.toArray(n).map(async (e) => await t.access.policies.create(e))), o = await t.access.roles.create({
54
54
  name: "test",
55
55
  description: "test"
56
56
  });
57
57
  return await t.ontology.addChildren(e(o.key), ...a.map(({ key: e }) => r(e))), await t.access.roles.assign({
58
58
  user: i.key,
59
59
  role: o.key
60
- }), await S(i.username, i.key);
61
- }, T = [
60
+ }), await w(i.username, i.key);
61
+ }, D = [
62
62
  "Owner",
63
63
  "Engineer",
64
64
  "Host",
65
65
  "Operator",
66
66
  "Viewer"
67
- ], E = async (e, t) => {
67
+ ], O = async (e, t) => {
68
68
  let n = (await e.access.roles.retrieve({})).find((e) => e.name === t);
69
69
  if (n == null) throw new a(`no built-in role named ${t}`);
70
- let r = await C(e);
70
+ let r = await T(e);
71
71
  return await e.access.roles.assign({
72
72
  user: r.key,
73
73
  role: n.key
74
- }), await S(r.username, r.key);
75
- }, D = class {
74
+ }), await w(r.username, r.key);
75
+ }, k = class {
76
76
  client;
77
77
  byRole = /* @__PURE__ */ new Map();
78
78
  constructor(e) {
@@ -81,10 +81,10 @@ var b = (e) => {
81
81
  async get(e) {
82
82
  let t = this.byRole.get(e);
83
83
  if (t != null) return await t;
84
- let n = E(this.client, e);
84
+ let n = O(this.client, e);
85
85
  return this.byRole.set(e, n), await n;
86
86
  }
87
- }, O = async (e) => {
87
+ }, A = async (e) => {
88
88
  let t = await e.channels.create({
89
89
  leaseholder: 1,
90
90
  name: m.create(),
@@ -97,7 +97,7 @@ var b = (e) => {
97
97
  dataType: l.FLOAT64,
98
98
  index: t.key
99
99
  })];
100
- }, k = async (e) => {
100
+ }, j = async (e) => {
101
101
  let t = await e.channels.create({
102
102
  leaseholder: 1,
103
103
  name: m.create(),
@@ -110,80 +110,100 @@ var b = (e) => {
110
110
  dataType: l.BOOLEAN,
111
111
  index: t.key
112
112
  })];
113
- }, A = async (e) => await e.channels.create({
113
+ }, M = async (e) => await e.channels.create({
114
114
  name: m.create(),
115
115
  dataType: l.FLOAT64,
116
116
  virtual: !0
117
- }), j = async (e) => await e.channels.create({
117
+ }), N = async (e) => await e.channels.create({
118
118
  name: m.create(),
119
119
  dataType: l.BOOLEAN,
120
120
  virtual: !0
121
- }), M = async (e, t, n = u.seconds(5)) => t(e.status) ? e.status : await new Promise((r, i) => {
121
+ }), P = async (e, t, n = u.seconds(5)) => t(e.status) ? e.status : await new Promise((r, i) => {
122
122
  let a = setTimeout(() => {
123
123
  o(), i(/* @__PURE__ */ Error("timed out waiting for connection status"));
124
124
  }, n.milliseconds), o = e.onChange((e) => {
125
125
  t(e) && (clearTimeout(a), o(), r(e));
126
126
  });
127
- }), N = async (e, t) => await M(e, ({ variant: e, details: t }) => e === "success" && t.streamLive, t), P = async (e) => {
127
+ }), F = async (e, t) => await P(e, ({ variant: e, details: t }) => e === "success" && t.streamLive, t), I = async (e) => {
128
128
  let t = await e.projects.create({
129
129
  name: `project-${m.create()}`,
130
130
  layout: {}
131
131
  });
132
132
  return o(t.key);
133
- }, F = {
133
+ }, L = {
134
134
  host: "localhost",
135
135
  port: 9090
136
- }, I = {
136
+ }, R = {
137
137
  baseInterval: u.milliseconds(10),
138
138
  maxInterval: u.milliseconds(50),
139
139
  scale: 1.5
140
- }, L = async (e = {}) => {
140
+ }, z = async (e = {}) => {
141
141
  let { host: t, port: n } = {
142
- ...F,
142
+ ...L,
143
143
  ...e
144
- }, r = /* @__PURE__ */ new Set(), i = !1, a = _((e) => {
145
- if (i) {
144
+ }, r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = !1, o = v((e) => {
145
+ if (a) {
146
146
  e.destroy();
147
147
  return;
148
148
  }
149
- let a = g(n, t);
150
- r.add(e).add(a);
151
- let o = () => {
152
- r.delete(e), r.delete(a), e.destroy(), a.destroy();
149
+ let i = _(n, t), o = {
150
+ downstream: e,
151
+ upstream: i,
152
+ ws: !1
153
153
  };
154
- e.on("error", o), a.on("error", o), e.on("close", o), a.on("close", o), e.pipe(a), a.pipe(e);
155
- }), o = async (e) => await new Promise((t, n) => {
156
- a.once("error", n), a.listen(e, () => {
157
- a.removeListener("error", n), t();
154
+ r.add(o), e.on("data", (e) => {
155
+ !o.ws && /upgrade:\s*websocket/i.test(e.toString("latin1")) && (o.ws = !0);
156
+ });
157
+ let s = () => {
158
+ r.delete(o), e.destroy(), i.destroy();
159
+ };
160
+ e.on("error", s), i.on("error", s), e.on("close", s), i.on("close", s), e.pipe(i), i.pipe(e);
161
+ }), s = async (e) => await new Promise((t, n) => {
162
+ o.once("error", n), o.listen(e, () => {
163
+ o.removeListener("error", n), t();
158
164
  });
159
165
  });
160
- await o(0);
161
- let s = a.address();
162
- if (s == null || typeof s == "string") throw Error("proxy failed to bind a port");
163
- let c = s.port, l = async () => {
164
- i = !0;
165
- let e = new Promise((e) => a.close(() => e()));
166
- r.forEach((e) => e.destroy()), r.clear(), await e;
166
+ await s(0);
167
+ let c = o.address();
168
+ if (c == null || typeof c == "string") throw Error("proxy failed to bind a port");
169
+ let l = c.port, u = async () => {
170
+ a = !0;
171
+ let e = new Promise((e) => o.close(() => e()));
172
+ r.forEach(({ downstream: e, upstream: t }) => {
173
+ e.destroy(), t.destroy();
174
+ }), r.clear(), i.forEach((e) => e.destroy()), i.clear(), await e;
167
175
  };
168
176
  return {
169
- port: c,
170
- sever: l,
177
+ port: l,
178
+ sever: u,
179
+ blackholeStreams: () => {
180
+ let e = 0;
181
+ for (let t of [...r]) {
182
+ if (!t.ws) continue;
183
+ e += 1;
184
+ let { downstream: n, upstream: a } = t;
185
+ n.unpipe(a), a.unpipe(n);
186
+ for (let e of [n, a]) e.removeAllListeners("close"), e.removeAllListeners("error"), e.on("error", () => {});
187
+ n.on("data", () => {}), n.resume(), a.destroy(), r.delete(t), i.add(n);
188
+ }
189
+ return e;
190
+ },
171
191
  restore: async () => {
172
- i = !1, await o(c);
192
+ a = !1, await s(l);
173
193
  },
174
- close: l
194
+ close: u
175
195
  };
176
- }, R = (e) => {
196
+ }, B = (e) => {
177
197
  if (!i(e)) throw Error("expected a live cached answer");
178
198
  return e;
179
- }, z = (e) => {
199
+ }, V = (e) => {
180
200
  if (!t.matches(e)) throw Error("expected a deleted answer");
181
201
  return e;
182
- }, B = (e, t) => Array.from({ length: t }, (t, n) => e + n).map((e) => d.seconds(e)), V = (e) => e.isVariable || e.equals(l.UINT8), H = {
183
- resolveDataType: (e) => V(e) ? e : l.FLOAT32,
184
- convert: (e, t) => V(e.dataType) ? e : (t == null && e.dataType.usesBigInt && e.length > 0 && (t = BigInt(e.data[0])), e.convert(l.FLOAT32, t))
202
+ }, H = (e, t) => Array.from({ length: t }, (t, n) => e + n).map((e) => d.seconds(e)), U = (e) => e.isVariable || e.equals(l.UINT8), W = {
203
+ resolveDataType: (e) => U(e) ? e : l.FLOAT32,
204
+ convert: (e, t) => U(e.dataType) ? e : (t == null && e.dataType.usesBigInt && e.length > 0 && (t = BigInt(e.data[0])), e.convert(l.FLOAT32, t))
185
205
  };
186
206
  //#endregion
187
- export { T as BUILT_IN_ROLES, I as FAST_RETRY, D as RoleClients, v as TEST_CLIENT_PARAMS, P as createPanelParent, L as createSeverableProxy, b as createTestClient, w as createTestClientWithPolicy, E as createTestClientWithRole, z as expectDeleted, R as expectLive, H as glTransform, i as isLive, k as newIndexedBoolPair, O as newIndexedPair, j as newVirtualBoolChannel, A as newVirtualChannel, B as secondsLinspace, M as waitForStatus, N as waitForStreamLive };
207
+ export { D as BUILT_IN_ROLES, R as FAST_RETRY, k as RoleClients, y as TEST_CLIENT_PARAMS, I as createPanelParent, z as createSeverableProxy, x as createTestClient, E as createTestClientWithPolicy, O as createTestClientWithRole, V as expectDeleted, B as expectLive, W as glTransform, i as isLive, j as newIndexedBoolPair, A as newIndexedPair, N as newVirtualBoolChannel, M as newVirtualChannel, H as secondsLinspace, S as spyOnSend, P as waitForStatus, F as waitForStreamLive };
188
208
 
189
209
  //# sourceMappingURL=testutil.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"testutil.js","names":[],"sources":["../src/testutil/client.ts","../src/testutil/access.ts","../src/testutil/channels.ts","../src/testutil/connection.ts","../src/testutil/panels.ts","../src/testutil/proxy.ts","../src/testutil/query.ts","../src/testutil/telem.ts"],"sourcesContent":["// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { TimeSpan } from \"@synnaxlabs/x\";\nimport { afterAll } from \"vitest\";\n\nimport Synnax, { type SynnaxParams } from \"@/client\";\n\nexport const TEST_CLIENT_PARAMS: SynnaxParams = {\n host: \"localhost\",\n port: 9090,\n username: \"synnax\",\n password: \"seldon\",\n retry: {\n maxRetries: 4,\n baseInterval: TimeSpan.seconds(1),\n scale: 1.5,\n },\n};\n\n// A hook registered mid-test is silently dropped by vitest, so per-client afterAll\n// calls leak clients created inside test bodies. This module-level hook registers\n// during spec collection (import time) and covers every call site.\nconst openClients: Synnax[] = [];\n// Awaited so every close finishes before vitest tears down the worker; a close\n// still in flight at teardown races its logging against the closing RPC channel.\nafterAll(async () => {\n const results = await Promise.allSettled(openClients.map((client) => client.close()));\n const failures = results.filter((result) => result.status === \"rejected\");\n if (failures.length > 0)\n throw new AggregateError(\n failures.map((failure) => failure.reason),\n \"failed to close test clients\",\n );\n});\n\n/**\n * Creates a client connected to the local test cluster. The client is closed\n * automatically once every test in the current spec file has finished, so callers do\n * not need to close it themselves.\n */\nexport const createTestClient = (params?: Partial<SynnaxParams>): Synnax => {\n const client = new Synnax({ ...TEST_CLIENT_PARAMS, ...params });\n openClients.push(client);\n return client;\n};\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { array, errors, id } from \"@synnaxlabs/x\";\n\nimport { policy } from \"@/access/policy\";\nimport { role } from \"@/access/role\";\nimport type Synnax from \"@/client\";\nimport { AccessDeniedError, NotFoundError } from \"@/errors\";\nimport { createTestClient } from \"@/testutil/client\";\nimport { user } from \"@/user\";\n\n/** Reports whether the error, or any error in its cause chain, is an access denial. */\nconst isDenial = (err: unknown): boolean =>\n AccessDeniedError.matches(err) ||\n (err instanceof Error && err.cause != null && isDenial(err.cause));\n\n/**\n * Connects as a new user and primes its policy cache. Denials are tolerated: the Core\n * refuses restricted subjects by design, and the change-stream refusal logs after\n * teardown, which vitest counts as an unhandled error.\n */\nconst connectAs = async (username: string, key: user.Key) => {\n const client = createTestClient({\n username,\n password: \"test\",\n onInternalError: (err) => {\n if (!isDenial(err)) console.error(err);\n },\n });\n try {\n await client.access.policies.retrieveForSubject(user.ontologyID(key));\n } catch (err) {\n if (!isDenial(err)) throw errors.fromUnknown(err);\n }\n return client;\n};\n\nconst createUser = async (client: Synnax) => {\n const username = id.create();\n const u = await client.users.create({\n username,\n password: \"test\",\n firstName: \"test\",\n lastName: \"test\",\n });\n return { username, key: u.key };\n};\n\n/**\n * Creates a client authenticated as a new user holding a role that carries the\n * policies. Pass several to grant different actions on different objects, which one\n * policy cannot express.\n */\nexport const createTestClientWithPolicy = async (\n client: Synnax,\n pol: policy.New | policy.New[],\n) => {\n const u = await createUser(client);\n const policies = await Promise.all(\n array.toArray(pol).map(async (p) => await client.access.policies.create(p)),\n );\n const r = await client.access.roles.create({\n name: \"test\",\n description: \"test\",\n });\n await client.ontology.addChildren(\n role.ontologyID(r.key),\n ...policies.map(({ key }) => policy.ontologyID(key)),\n );\n await client.access.roles.assign({ user: u.key, role: r.key });\n return await connectAs(u.username, u.key);\n};\n\n/** The roles the Core provisions on startup. */\nexport const BUILT_IN_ROLES = [\n \"Owner\",\n \"Engineer\",\n \"Host\",\n \"Operator\",\n \"Viewer\",\n] as const;\n\nexport type BuiltInRole = (typeof BUILT_IN_ROLES)[number];\n\n/**\n * Creates a client authenticated as a new user holding one of the Core's built-in\n * roles, for exercising a real role's permission set instead of a synthetic policy.\n * @param name - The built-in role to assign.\n * @throws {NotFoundError} if the Core provisions no role under the name.\n */\nexport const createTestClientWithRole = async (\n client: Synnax,\n name: BuiltInRole,\n): Promise<Synnax> => {\n const roles = await client.access.roles.retrieve({});\n const r = roles.find((r) => r.name === name);\n if (r == null) throw new NotFoundError(`no built-in role named ${name}`);\n const u = await createUser(client);\n await client.access.roles.assign({ user: u.key, role: r.key });\n return await connectAs(u.username, u.key);\n};\n\n/**\n * Caches one client per built-in role, so a spec covering many roles pays the user\n * creation cost once each. Construct one per spec file.\n */\nexport class RoleClients {\n private readonly client: Synnax;\n private readonly byRole = new Map<BuiltInRole, Promise<Synnax>>();\n\n constructor(client: Synnax) {\n this.client = client;\n }\n\n /** Returns a client authenticated as a user holding the role. */\n async get(name: BuiltInRole): Promise<Synnax> {\n const existing = this.byRole.get(name);\n if (existing != null) return await existing;\n const created = createTestClientWithRole(this.client, name);\n this.byRole.set(name, created);\n return await created;\n }\n}\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { DataType, id } from \"@synnaxlabs/x\";\n\nimport { type channel } from \"@/channel\";\nimport type Synnax from \"@/client\";\n\nexport const newIndexedPair = async (\n client: Synnax,\n): Promise<[channel.Channel, channel.Channel]> => {\n const index = await client.channels.create({\n leaseholder: 1,\n name: id.create(),\n dataType: DataType.TIMESTAMP,\n isIndex: true,\n });\n const data = await client.channels.create({\n leaseholder: 1,\n name: id.create(),\n dataType: DataType.FLOAT64,\n index: index.key,\n });\n return [index, data];\n};\n\nexport const newIndexedBoolPair = async (\n client: Synnax,\n): Promise<[channel.Channel, channel.Channel]> => {\n const index = await client.channels.create({\n leaseholder: 1,\n name: id.create(),\n dataType: DataType.TIMESTAMP,\n isIndex: true,\n });\n const data = await client.channels.create({\n leaseholder: 1,\n name: id.create(),\n dataType: DataType.BOOLEAN,\n index: index.key,\n });\n return [index, data];\n};\n\nexport const newVirtualChannel = async (client: Synnax): Promise<channel.Channel> => {\n const ch = await client.channels.create({\n name: id.create(),\n dataType: DataType.FLOAT64,\n virtual: true,\n });\n return ch;\n};\n\nexport const newVirtualBoolChannel = async (\n client: Synnax,\n): Promise<channel.Channel> => {\n const ch = await client.channels.create({\n name: id.create(),\n dataType: DataType.BOOLEAN,\n virtual: true,\n });\n return ch;\n};\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { TimeSpan } from \"@synnaxlabs/x\";\n\nimport { type connection } from \"@/connection\";\n\n/** Resolves once the handle's status satisfies the predicate. */\nexport const waitForStatus = async (\n handle: connection.Handle,\n predicate: (status: connection.Status) => boolean,\n timeout: TimeSpan = TimeSpan.seconds(5),\n): Promise<connection.Status> => {\n if (predicate(handle.status)) return handle.status;\n return await new Promise<connection.Status>((resolve, reject) => {\n const timer = setTimeout(() => {\n detach();\n reject(new Error(\"timed out waiting for connection status\"));\n }, timeout.milliseconds);\n const detach = handle.onChange((status) => {\n if (!predicate(status)) return;\n clearTimeout(timer);\n detach();\n resolve(status);\n });\n });\n};\n\n/**\n * Resolves once the handle's change stream is live, so every later cluster write\n * reaches the client's cache.\n */\nexport const waitForStreamLive = async (\n handle: connection.Handle,\n timeout?: TimeSpan,\n): Promise<connection.Status> =>\n await waitForStatus(\n handle,\n ({ variant, details }) => variant === \"success\" && details.streamLive,\n timeout,\n );\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { id } from \"@synnaxlabs/x\";\n\nimport type Synnax from \"@/client\";\nimport { type ontology } from \"@/ontology\";\nimport { project } from \"@/project\";\n\n/**\n * Creates a throwaway project and returns its ontology ID. Panel creation requires a\n * parent, so tests that mint panels directly parent them here.\n */\nexport const createPanelParent = async (client: Synnax): Promise<ontology.ID> => {\n const proj = await client.projects.create({\n name: `project-${id.create()}`,\n layout: {},\n });\n return project.ontologyID(proj.key);\n};\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { connect, createServer, type Socket } from \"node:net\";\n\nimport { type breaker, TimeSpan } from \"@synnaxlabs/x\";\n\nconst DEFAULT_TARGET = { host: \"localhost\", port: 9090 };\n\n/**\n * Retry policy for a client pointed at a severable proxy. A spec drives its own\n * retries, so the client's must finish well inside one assertion budget: the\n * default policy waits seconds per request and outlasts a single `expect.poll`\n * attempt, which reports as a timeout rather than the real answer.\n */\nexport const FAST_RETRY: breaker.Config = {\n baseInterval: TimeSpan.milliseconds(10),\n maxInterval: TimeSpan.milliseconds(50),\n scale: 1.5,\n};\n\nexport interface SeverableProxyTarget {\n host?: string;\n port?: number;\n}\n\nexport interface SeverableProxy {\n /** Port the proxy accepts connections on. Point the client here. */\n port: number;\n /** Drops every live connection and refuses new ones, as if the cluster died. */\n sever: () => Promise<void>;\n /** Accepts connections again on the same port. */\n restore: () => Promise<void>;\n /** Shuts the proxy down for good. */\n close: () => Promise<void>;\n}\n\n/**\n * Creates a TCP proxy in front of the live test cluster so specs can simulate\n * cluster downtime without touching the cluster itself. Connect a client to\n * the returned port, then sever() and restore() the link.\n */\nexport const createSeverableProxy = async (\n target: SeverableProxyTarget = {},\n): Promise<SeverableProxy> => {\n const { host, port } = { ...DEFAULT_TARGET, ...target };\n const sockets = new Set<Socket>();\n let severed = false;\n const server = createServer((downstream) => {\n // A connection the kernel accepted before the sever is still delivered after it,\n // and forwarding it would let a request through a severed link.\n if (severed) {\n downstream.destroy();\n return;\n }\n const upstream = connect(port, host);\n sockets.add(downstream).add(upstream);\n const destroy = (): void => {\n sockets.delete(downstream);\n sockets.delete(upstream);\n downstream.destroy();\n upstream.destroy();\n };\n downstream.on(\"error\", destroy);\n upstream.on(\"error\", destroy);\n downstream.on(\"close\", destroy);\n upstream.on(\"close\", destroy);\n downstream.pipe(upstream);\n upstream.pipe(downstream);\n });\n const listen = async (listenPort: number): Promise<void> =>\n await new Promise((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(listenPort, () => {\n server.removeListener(\"error\", reject);\n resolve();\n });\n });\n await listen(0);\n const address = server.address();\n if (address == null || typeof address === \"string\")\n throw new Error(\"proxy failed to bind a port\");\n const boundPort = address.port;\n const sever = async (): Promise<void> => {\n severed = true;\n const closed = new Promise<void>((resolve) => server.close(() => resolve()));\n sockets.forEach((socket) => socket.destroy());\n sockets.clear();\n await closed;\n };\n return {\n port: boundPort,\n sever,\n restore: async () => {\n severed = false;\n await listen(boundPort);\n },\n close: sever,\n };\n};\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { query } from \"@/query\";\n\nexport { isLive } from \"@/query/query\";\n\n/** Asserts the cached answer is live (present and not deleted) and returns it. */\nexport const expectLive = <D extends query.Data>(\n value: query.Cached<D> | undefined,\n): D => {\n if (!query.isLive<D>(value)) throw new Error(\"expected a live cached answer\");\n return value;\n};\n\n/** Asserts the cached answer is a deletion and returns it. */\nexport const expectDeleted = <D extends query.Data>(\n value: query.Cached<D> | undefined,\n): query.Deleted<D> => {\n if (!query.Deleted.matches<D>(value)) throw new Error(\"expected a deleted answer\");\n return value;\n};\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { DataType, type Series, TimeStamp } from \"@synnaxlabs/x\";\n\nimport { type framer } from \"@/framer\";\n\nexport const secondsLinspace = (start: number, n: number): TimeStamp[] =>\n Array.from({ length: n }, (_, i) => start + i).map((n) => TimeStamp.seconds(n));\n\nconst isRaw = (dt: DataType): boolean => dt.isVariable || dt.equals(DataType.UINT8);\n\n/** Narrows every numeric series to float32, anchoring bigints on an offset. Mirrors\n * the transform the visualization layer injects for WebGL rendering. */\nexport const glTransform: framer.Transform = {\n resolveDataType: (dt: DataType) => (isRaw(dt) ? dt : DataType.FLOAT32),\n convert: (series: Series, offset) => {\n if (isRaw(series.dataType)) return series;\n if (offset == null && series.dataType.usesBigInt && series.length > 0)\n offset = BigInt(series.data[0]);\n return series.convert(DataType.FLOAT32, offset);\n },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"testutil.js","names":[],"sources":["../src/testutil/client.ts","../src/testutil/access.ts","../src/testutil/channels.ts","../src/testutil/connection.ts","../src/testutil/panels.ts","../src/testutil/proxy.ts","../src/testutil/query.ts","../src/testutil/telem.ts"],"sourcesContent":["// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { TimeSpan } from \"@synnaxlabs/x\";\nimport { afterAll, vi } from \"vitest\";\n\nimport Synnax, { type SynnaxParams } from \"@/client\";\n\nexport const TEST_CLIENT_PARAMS: SynnaxParams = {\n host: \"localhost\",\n port: 9090,\n username: \"synnax\",\n password: \"seldon\",\n retry: {\n maxRetries: 4,\n baseInterval: TimeSpan.seconds(1),\n scale: 1.5,\n },\n};\n\n// A hook registered mid-test is silently dropped by vitest, so per-client afterAll\n// calls leak clients created inside test bodies. This module-level hook registers\n// during spec collection (import time) and covers every call site.\nconst openClients: Synnax[] = [];\n// Awaited so every close finishes before vitest tears down the worker; a close\n// still in flight at teardown races its logging against the closing RPC channel.\nafterAll(async () => {\n const results = await Promise.allSettled(openClients.map((client) => client.close()));\n const failures = results.filter((result) => result.status === \"rejected\");\n if (failures.length > 0)\n throw new AggregateError(\n failures.map((failure) => failure.reason),\n \"failed to close test clients\",\n );\n});\n\n/**\n * Creates a client connected to the local test cluster. The client is closed\n * automatically once every test in the current spec file has finished, so callers do\n * not need to close it themselves.\n */\nexport const createTestClient = (params?: Partial<SynnaxParams>): Synnax => {\n const client = new Synnax({ ...TEST_CLIENT_PARAMS, ...params });\n openClients.push(client);\n return client;\n};\n\n/** Spies on the client's unary send so specs can count requests on the wire. */\nexport const spyOnSend = (client: Synnax, field: \"transport\" = \"transport\") =>\n vi.spyOn(client[field].unary, \"send\");\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { array, errors, id } from \"@synnaxlabs/x\";\n\nimport { policy } from \"@/access/policy\";\nimport { role } from \"@/access/role\";\nimport type Synnax from \"@/client\";\nimport { AccessDeniedError, NotFoundError } from \"@/errors\";\nimport { createTestClient } from \"@/testutil/client\";\nimport { user } from \"@/user\";\n\n/** Reports whether the error, or any error in its cause chain, is an access denial. */\nconst isDenial = (err: unknown): boolean =>\n AccessDeniedError.matches(err) ||\n (err instanceof Error && err.cause != null && isDenial(err.cause));\n\n/**\n * Connects as a new user and primes its policy cache. Denials are tolerated: the Core\n * refuses restricted subjects by design, and the change-stream refusal logs after\n * teardown, which vitest counts as an unhandled error.\n */\nconst connectAs = async (username: string, key: user.Key) => {\n const client = createTestClient({\n username,\n password: \"test\",\n onInternalError: (err) => {\n if (!isDenial(err)) console.error(err);\n },\n });\n try {\n await client.access.policies.retrieveForSubject(user.ontologyID(key));\n } catch (err) {\n if (!isDenial(err)) throw errors.fromUnknown(err);\n }\n return client;\n};\n\nconst createUser = async (client: Synnax) => {\n const username = id.create();\n const u = await client.users.create({\n username,\n password: \"test\",\n firstName: \"test\",\n lastName: \"test\",\n });\n return { username, key: u.key };\n};\n\n/**\n * Creates a client authenticated as a new user holding a role that carries the\n * policies. Pass several to grant different actions on different objects, which one\n * policy cannot express.\n */\nexport const createTestClientWithPolicy = async (\n client: Synnax,\n pol: policy.New | policy.New[],\n) => {\n const u = await createUser(client);\n const policies = await Promise.all(\n array.toArray(pol).map(async (p) => await client.access.policies.create(p)),\n );\n const r = await client.access.roles.create({\n name: \"test\",\n description: \"test\",\n });\n await client.ontology.addChildren(\n role.ontologyID(r.key),\n ...policies.map(({ key }) => policy.ontologyID(key)),\n );\n await client.access.roles.assign({ user: u.key, role: r.key });\n return await connectAs(u.username, u.key);\n};\n\n/** The roles the Core provisions on startup. */\nexport const BUILT_IN_ROLES = [\n \"Owner\",\n \"Engineer\",\n \"Host\",\n \"Operator\",\n \"Viewer\",\n] as const;\n\nexport type BuiltInRole = (typeof BUILT_IN_ROLES)[number];\n\n/**\n * Creates a client authenticated as a new user holding one of the Core's built-in\n * roles, for exercising a real role's permission set instead of a synthetic policy.\n * @param name - The built-in role to assign.\n * @throws {NotFoundError} if the Core provisions no role under the name.\n */\nexport const createTestClientWithRole = async (\n client: Synnax,\n name: BuiltInRole,\n): Promise<Synnax> => {\n const roles = await client.access.roles.retrieve({});\n const r = roles.find((r) => r.name === name);\n if (r == null) throw new NotFoundError(`no built-in role named ${name}`);\n const u = await createUser(client);\n await client.access.roles.assign({ user: u.key, role: r.key });\n return await connectAs(u.username, u.key);\n};\n\n/**\n * Caches one client per built-in role, so a spec covering many roles pays the user\n * creation cost once each. Construct one per spec file.\n */\nexport class RoleClients {\n private readonly client: Synnax;\n private readonly byRole = new Map<BuiltInRole, Promise<Synnax>>();\n\n constructor(client: Synnax) {\n this.client = client;\n }\n\n /** Returns a client authenticated as a user holding the role. */\n async get(name: BuiltInRole): Promise<Synnax> {\n const existing = this.byRole.get(name);\n if (existing != null) return await existing;\n const created = createTestClientWithRole(this.client, name);\n this.byRole.set(name, created);\n return await created;\n }\n}\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { DataType, id } from \"@synnaxlabs/x\";\n\nimport { type channel } from \"@/channel\";\nimport type Synnax from \"@/client\";\n\nexport const newIndexedPair = async (\n client: Synnax,\n): Promise<[channel.Channel, channel.Channel]> => {\n const index = await client.channels.create({\n leaseholder: 1,\n name: id.create(),\n dataType: DataType.TIMESTAMP,\n isIndex: true,\n });\n const data = await client.channels.create({\n leaseholder: 1,\n name: id.create(),\n dataType: DataType.FLOAT64,\n index: index.key,\n });\n return [index, data];\n};\n\nexport const newIndexedBoolPair = async (\n client: Synnax,\n): Promise<[channel.Channel, channel.Channel]> => {\n const index = await client.channels.create({\n leaseholder: 1,\n name: id.create(),\n dataType: DataType.TIMESTAMP,\n isIndex: true,\n });\n const data = await client.channels.create({\n leaseholder: 1,\n name: id.create(),\n dataType: DataType.BOOLEAN,\n index: index.key,\n });\n return [index, data];\n};\n\nexport const newVirtualChannel = async (client: Synnax): Promise<channel.Channel> => {\n const ch = await client.channels.create({\n name: id.create(),\n dataType: DataType.FLOAT64,\n virtual: true,\n });\n return ch;\n};\n\nexport const newVirtualBoolChannel = async (\n client: Synnax,\n): Promise<channel.Channel> => {\n const ch = await client.channels.create({\n name: id.create(),\n dataType: DataType.BOOLEAN,\n virtual: true,\n });\n return ch;\n};\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { TimeSpan } from \"@synnaxlabs/x\";\n\nimport { type connection } from \"@/connection\";\n\n/** Resolves once the handle's status satisfies the predicate. */\nexport const waitForStatus = async (\n handle: connection.Handle,\n predicate: (status: connection.Status) => boolean,\n timeout: TimeSpan = TimeSpan.seconds(5),\n): Promise<connection.Status> => {\n if (predicate(handle.status)) return handle.status;\n return await new Promise<connection.Status>((resolve, reject) => {\n const timer = setTimeout(() => {\n detach();\n reject(new Error(\"timed out waiting for connection status\"));\n }, timeout.milliseconds);\n const detach = handle.onChange((status) => {\n if (!predicate(status)) return;\n clearTimeout(timer);\n detach();\n resolve(status);\n });\n });\n};\n\n/**\n * Resolves once the handle's change stream is live, so every later cluster write\n * reaches the client's cache.\n */\nexport const waitForStreamLive = async (\n handle: connection.Handle,\n timeout?: TimeSpan,\n): Promise<connection.Status> =>\n await waitForStatus(\n handle,\n ({ variant, details }) => variant === \"success\" && details.streamLive,\n timeout,\n );\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { id } from \"@synnaxlabs/x\";\n\nimport type Synnax from \"@/client\";\nimport { type ontology } from \"@/ontology\";\nimport { project } from \"@/project\";\n\n/**\n * Creates a throwaway project and returns its ontology ID. Panel creation requires a\n * parent, so tests that mint panels directly parent them here.\n */\nexport const createPanelParent = async (client: Synnax): Promise<ontology.ID> => {\n const proj = await client.projects.create({\n name: `project-${id.create()}`,\n layout: {},\n });\n return project.ontologyID(proj.key);\n};\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { connect, createServer, type Socket } from \"node:net\";\n\nimport { type breaker, TimeSpan } from \"@synnaxlabs/x\";\n\nconst DEFAULT_TARGET = { host: \"localhost\", port: 9090 };\n\n/**\n * Retry policy for a client pointed at a severable proxy. A spec drives its own\n * retries, so the client's must finish well inside one assertion budget: the\n * default policy waits seconds per request and outlasts a single `expect.poll`\n * attempt, which reports as a timeout rather than the real answer.\n */\nexport const FAST_RETRY: breaker.Config = {\n baseInterval: TimeSpan.milliseconds(10),\n maxInterval: TimeSpan.milliseconds(50),\n scale: 1.5,\n};\n\nexport interface SeverableProxyTarget {\n host?: string;\n port?: number;\n}\n\nexport interface SeverableProxy {\n /** Port the proxy accepts connections on. Point the client here. */\n port: number;\n /** Drops every live connection and refuses new ones, as if the cluster died. */\n sever: () => Promise<void>;\n /**\n * Silently kills every live WebSocket connection, modeling a half-open socket (NAT\n * timeout, VPN drop, laptop sleep): the cluster side is destroyed while the client\n * side is held open with its writes discarded, so no close or reset ever reaches the\n * client. New connections still forward. Returns how many connections were\n * blackholed.\n */\n blackholeStreams: () => number;\n /** Accepts connections again on the same port. */\n restore: () => Promise<void>;\n /** Shuts the proxy down for good. */\n close: () => Promise<void>;\n}\n\ninterface ProxiedPair {\n downstream: Socket;\n upstream: Socket;\n /** Whether a WebSocket upgrade was observed on this connection. */\n ws: boolean;\n}\n\n/**\n * Creates a TCP proxy in front of the live test cluster so specs can simulate\n * cluster downtime without touching the cluster itself. Connect a client to\n * the returned port, then sever() and restore() the link.\n */\nexport const createSeverableProxy = async (\n target: SeverableProxyTarget = {},\n): Promise<SeverableProxy> => {\n const { host, port } = { ...DEFAULT_TARGET, ...target };\n const pairs = new Set<ProxiedPair>();\n // Client-side sockets of blackholed connections: held open, silent, until the proxy\n // is severed or closed.\n const zombies = new Set<Socket>();\n let severed = false;\n const server = createServer((downstream) => {\n // A connection the kernel accepted before the sever is still delivered after it,\n // and forwarding it would let a request through a severed link.\n if (severed) {\n downstream.destroy();\n return;\n }\n const upstream = connect(port, host);\n const pair: ProxiedPair = { downstream, upstream, ws: false };\n pairs.add(pair);\n // The upgrade can arrive on any request of a pooled keep-alive connection, not just\n // the first, so every chunk is sniffed until one is seen.\n downstream.on(\"data\", (chunk: Buffer) => {\n if (!pair.ws && /upgrade:\\s*websocket/i.test(chunk.toString(\"latin1\")))\n pair.ws = true;\n });\n const destroy = (): void => {\n pairs.delete(pair);\n downstream.destroy();\n upstream.destroy();\n };\n downstream.on(\"error\", destroy);\n upstream.on(\"error\", destroy);\n downstream.on(\"close\", destroy);\n upstream.on(\"close\", destroy);\n downstream.pipe(upstream);\n upstream.pipe(downstream);\n });\n const listen = async (listenPort: number): Promise<void> =>\n await new Promise((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(listenPort, () => {\n server.removeListener(\"error\", reject);\n resolve();\n });\n });\n await listen(0);\n const address = server.address();\n if (address == null || typeof address === \"string\")\n throw new Error(\"proxy failed to bind a port\");\n const boundPort = address.port;\n const sever = async (): Promise<void> => {\n severed = true;\n const closed = new Promise<void>((resolve) => server.close(() => resolve()));\n pairs.forEach(({ downstream, upstream }) => {\n downstream.destroy();\n upstream.destroy();\n });\n pairs.clear();\n zombies.forEach((socket) => socket.destroy());\n zombies.clear();\n await closed;\n };\n const blackholeStreams = (): number => {\n let count = 0;\n for (const pair of [...pairs]) {\n if (!pair.ws) continue;\n count += 1;\n const { downstream, upstream } = pair;\n downstream.unpipe(upstream);\n upstream.unpipe(downstream);\n for (const socket of [downstream, upstream]) {\n socket.removeAllListeners(\"close\");\n socket.removeAllListeners(\"error\");\n socket.on(\"error\", () => {});\n }\n // Discard anything the client still writes so backpressure cannot close the\n // socket on the proxy's behalf.\n downstream.on(\"data\", () => {});\n downstream.resume();\n upstream.destroy();\n pairs.delete(pair);\n zombies.add(downstream);\n }\n return count;\n };\n return {\n port: boundPort,\n sever,\n blackholeStreams,\n restore: async () => {\n severed = false;\n await listen(boundPort);\n },\n close: sever,\n };\n};\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { query } from \"@/query\";\n\nexport { isLive } from \"@/query/query\";\n\n/** Asserts the cached answer is live (present and not deleted) and returns it. */\nexport const expectLive = <D extends query.Data>(\n value: query.Cached<D> | undefined,\n): D => {\n if (!query.isLive<D>(value)) throw new Error(\"expected a live cached answer\");\n return value;\n};\n\n/** Asserts the cached answer is a deletion and returns it. */\nexport const expectDeleted = <D extends query.Data>(\n value: query.Cached<D> | undefined,\n): query.Deleted<D> => {\n if (!query.Deleted.matches<D>(value)) throw new Error(\"expected a deleted answer\");\n return value;\n};\n","// Copyright 2026 Synnax Labs, Inc.\n//\n// Use of this software is governed by the Business Source License included in the file\n// licenses/BSL.txt.\n//\n// As of the Change Date specified in that file, in accordance with the Business Source\n// License, use of this software will be governed by the Apache License, Version 2.0,\n// included in the file licenses/APL.txt.\n\nimport { DataType, type Series, TimeStamp } from \"@synnaxlabs/x\";\n\nimport { type framer } from \"@/framer\";\n\nexport const secondsLinspace = (start: number, n: number): TimeStamp[] =>\n Array.from({ length: n }, (_, i) => start + i).map((n) => TimeStamp.seconds(n));\n\nconst isRaw = (dt: DataType): boolean => dt.isVariable || dt.equals(DataType.UINT8);\n\n/** Narrows every numeric series to float32, anchoring bigints on an offset. Mirrors\n * the transform the visualization layer injects for WebGL rendering. */\nexport const glTransform: framer.Transform = {\n resolveDataType: (dt: DataType) => (isRaw(dt) ? dt : DataType.FLOAT32),\n convert: (series: Series, offset) => {\n if (isRaw(series.dataType)) return series;\n if (offset == null && series.dataType.usesBigInt && series.length > 0)\n offset = BigInt(series.data[0]);\n return series.convert(DataType.FLOAT32, offset);\n },\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synnaxlabs/client",
3
- "version": "0.57.1",
3
+ "version": "0.57.3",
4
4
  "description": "The Synnax Client Library",
5
5
  "keywords": [
6
6
  "synnax",
@@ -26,8 +26,8 @@
26
26
  "immer": "^11.1.15",
27
27
  "zod": "^4.4.3",
28
28
  "@synnaxlabs/alamos": "^0.57.0",
29
- "@synnaxlabs/freighter": "^0.57.0",
30
- "@synnaxlabs/x": "^0.57.1"
29
+ "@synnaxlabs/x": "^0.57.1",
30
+ "@synnaxlabs/freighter": "^0.57.0"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "vitest": "^4.1.10"
@@ -46,8 +46,8 @@
46
46
  "vitest": "^4.1.10",
47
47
  "@synnaxlabs/eslint-config": "^0.0.0",
48
48
  "@synnaxlabs/madge": "^0.0.0",
49
- "@synnaxlabs/vite-plugin": "^0.0.0",
50
- "@synnaxlabs/tsconfig": "^0.0.0"
49
+ "@synnaxlabs/tsconfig": "^0.0.0",
50
+ "@synnaxlabs/vite-plugin": "^0.0.0"
51
51
  },
52
52
  "type": "module",
53
53
  "files": [
package/src/arc/client.ts CHANGED
@@ -120,24 +120,6 @@ const isTaskChild = (rel: ontology.Relationship, arcKey: Key): boolean =>
120
120
  to: { type: "task" },
121
121
  });
122
122
 
123
- const taskStatusZ = z.object({ details: z.object({ task: task.keyZ }) });
124
-
125
- // Task statuses may arrive under any status key; the referenced task lives in
126
- // the details, with the "task:<key>" status key as a fallback.
127
- const affectedTaskKeys = (
128
- event: query.TableEvent<status.Key, status.Status>,
129
- ): task.Key[] | null => {
130
- const keys: task.Key[] = [];
131
- if (event.variant === "set") {
132
- const parsed = taskStatusZ.safeParse(event.value);
133
- if (parsed.success) keys.push(parsed.data.details.task);
134
- }
135
- const [type, key] = event.key.split(":");
136
- if (type === "task" && primitive.isNonZero(key) && !keys.includes(key))
137
- keys.push(key);
138
- return keys.length === 0 ? null : keys;
139
- };
140
-
141
123
  export interface ClientConfig {
142
124
  unary: UnaryClient;
143
125
  stream: StreamClient;
@@ -210,7 +192,7 @@ export class Client extends query.Retriever<
210
192
  compose: (record) => this.composeTask(record),
211
193
  equal: (a, b) => deep.equal(a.payload, b.payload),
212
194
  watch: [
213
- query.deriveWatch(this.cfg.statusStore, (event) => affectedTaskKeys(event)),
195
+ query.deriveWatch(this.cfg.statusStore, (event) => task.affectedKeys(event)),
214
196
  ],
215
197
  });
216
198
  this.taskAnswers = cache.queries<Key, task.Task | null, task.Key, task.Task>({
@@ -473,7 +455,7 @@ export class Client extends query.Retriever<
473
455
  const cachedStatus = this.cfg.statusStore.get(task.statusKey(cached.key));
474
456
  const payload = cached.payload;
475
457
  if (cachedStatus == null) return this.cfg.tasks.sugar(payload);
476
- const parsed = task.statusZ().safeParse(cachedStatus);
458
+ const parsed = task.defaultStatusZ.safeParse(cachedStatus);
477
459
  if (!parsed.success) return this.cfg.tasks.sugar(payload);
478
460
  return this.cfg.tasks.sugar({ ...payload, status: parsed.data });
479
461
  }