@synnaxlabs/client 0.49.2 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +10 -10
- package/CONTRIBUTING.md +1 -2
- package/README.md +1 -1
- package/dist/client.cjs +29 -29
- package/dist/client.js +3660 -3598
- package/dist/src/access/policy/client.d.ts +90 -76
- package/dist/src/access/policy/client.d.ts.map +1 -1
- package/dist/src/access/policy/payload.d.ts +17 -14
- package/dist/src/access/policy/payload.d.ts.map +1 -1
- package/dist/src/access/role/payload.d.ts +2 -2
- package/dist/src/arc/payload.d.ts +21 -20
- package/dist/src/arc/payload.d.ts.map +1 -1
- package/dist/src/channel/client.d.ts +5 -10
- package/dist/src/channel/client.d.ts.map +1 -1
- package/dist/src/channel/payload.d.ts +11 -9
- package/dist/src/channel/payload.d.ts.map +1 -1
- package/dist/src/channel/retriever.d.ts.map +1 -1
- package/dist/src/client.d.ts +2 -0
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/device/client.d.ts +2 -2
- package/dist/src/device/payload.d.ts +1 -1
- package/dist/src/framer/client.d.ts +2 -2
- package/dist/src/framer/external.d.ts +1 -0
- package/dist/src/framer/external.d.ts.map +1 -1
- package/dist/src/framer/iterator.d.ts +5 -0
- package/dist/src/framer/iterator.d.ts.map +1 -1
- package/dist/src/framer/reader.d.ts +3 -1
- package/dist/src/framer/reader.d.ts.map +1 -1
- package/dist/src/framer/streamer.d.ts +1 -11
- package/dist/src/framer/streamer.d.ts.map +1 -1
- package/dist/src/framer/writer.d.ts +0 -10
- package/dist/src/framer/writer.d.ts.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/label/client.d.ts +11 -8
- package/dist/src/label/client.d.ts.map +1 -1
- package/dist/src/ontology/client.d.ts +6 -4
- package/dist/src/ontology/client.d.ts.map +1 -1
- package/dist/src/ontology/group/client.d.ts +3 -2
- package/dist/src/ontology/group/client.d.ts.map +1 -1
- package/dist/src/ontology/group/payload.d.ts +1 -1
- package/dist/src/ontology/group/payload.d.ts.map +1 -1
- package/dist/src/ontology/payload.d.ts +25 -20
- package/dist/src/ontology/payload.d.ts.map +1 -1
- package/dist/src/ontology/writer.d.ts +15 -10
- package/dist/src/ontology/writer.d.ts.map +1 -1
- package/dist/src/rack/client.d.ts +2 -2
- package/dist/src/ranger/client.d.ts +2 -2
- package/dist/src/ranger/writer.d.ts +3 -2
- package/dist/src/ranger/writer.d.ts.map +1 -1
- package/dist/src/status/payload.d.ts +2 -2
- package/dist/src/task/client.d.ts +2 -2
- package/dist/src/task/client.d.ts.map +1 -1
- package/dist/src/task/payload.d.ts +1 -0
- package/dist/src/task/payload.d.ts.map +1 -1
- package/dist/src/task/payload.spec.d.ts +2 -0
- package/dist/src/task/payload.spec.d.ts.map +1 -0
- package/dist/src/user/client.d.ts +2 -2
- package/dist/src/view/client.d.ts +43 -0
- package/dist/src/view/client.d.ts.map +1 -0
- package/dist/src/view/external.d.ts +3 -0
- package/dist/src/view/external.d.ts.map +1 -0
- package/dist/src/view/index.d.ts +2 -0
- package/dist/src/view/index.d.ts.map +1 -0
- package/dist/src/view/payload.d.ts +20 -0
- package/dist/src/view/payload.d.ts.map +1 -0
- package/dist/src/view/view.spec.d.ts +2 -0
- package/dist/src/view/view.spec.d.ts.map +1 -0
- package/dist/src/workspace/client.d.ts +3 -3
- package/dist/src/workspace/lineplot/client.d.ts +2 -2
- package/dist/src/workspace/lineplot/payload.d.ts +3 -3
- package/dist/src/workspace/log/client.d.ts +2 -2
- package/dist/src/workspace/log/payload.d.ts +3 -3
- package/dist/src/workspace/payload.d.ts +3 -3
- package/dist/src/workspace/schematic/client.d.ts +2 -2
- package/dist/src/workspace/schematic/payload.d.ts +3 -3
- package/dist/src/workspace/table/client.d.ts +2 -2
- package/dist/src/workspace/table/payload.d.ts +3 -3
- package/eslint.config.ts +1 -1
- package/examples/node/basicReadWrite.js +1 -1
- package/examples/node/createChannels.js +50 -0
- package/examples/node/createRange.js +67 -0
- package/examples/node/readLatest.js +76 -0
- package/examples/node/seriesAndFrames.js +2 -2
- package/examples/node/{liveStream.js → streamRead.js} +1 -1
- package/examples/node/streamWrite.js +1 -1
- package/package.json +10 -10
- package/src/access/client.ts +1 -1
- package/src/access/enforce.spec.ts +1 -1
- package/src/access/enforce.ts +1 -1
- package/src/access/external.ts +1 -1
- package/src/access/index.ts +1 -1
- package/src/access/payload.ts +1 -1
- package/src/access/policy/access.spec.ts +1 -1
- package/src/access/policy/client.ts +1 -1
- package/src/access/policy/external.ts +1 -1
- package/src/access/policy/index.ts +1 -1
- package/src/access/policy/payload.ts +1 -1
- package/src/access/role/client.ts +1 -1
- package/src/access/role/external.ts +1 -1
- package/src/access/role/index.ts +1 -1
- package/src/access/role/payload.ts +1 -1
- package/src/access/role/role.spec.ts +1 -1
- package/src/arc/access.spec.ts +1 -7
- package/src/arc/client.ts +1 -1
- package/src/arc/external.ts +1 -1
- package/src/arc/index.ts +1 -1
- package/src/arc/lsp.spec.ts +2 -5
- package/src/arc/payload.ts +7 -12
- package/src/auth/auth.spec.ts +1 -1
- package/src/auth/auth.ts +1 -1
- package/src/auth/index.ts +1 -1
- package/src/channel/access.spec.ts +1 -1
- package/src/channel/batchRetriever.spec.ts +1 -3
- package/src/channel/channel.spec.ts +13 -20
- package/src/channel/client.ts +5 -36
- package/src/channel/external.ts +1 -1
- package/src/channel/index.ts +1 -1
- package/src/channel/payload.spec.ts +1 -1
- package/src/channel/payload.ts +12 -5
- package/src/channel/retriever.ts +5 -3
- package/src/channel/writer.ts +1 -1
- package/src/client.ts +8 -3
- package/src/connection/checker.ts +2 -2
- package/src/connection/connection.spec.ts +1 -1
- package/src/connection/index.ts +1 -1
- package/src/connection.spec.ts +1 -1
- package/src/control/client.ts +1 -1
- package/src/control/external.ts +1 -1
- package/src/control/index.ts +1 -1
- package/src/control/state.spec.ts +1 -1
- package/src/control/state.ts +1 -1
- package/src/device/access.spec.ts +1 -1
- package/src/device/client.ts +1 -1
- package/src/device/device.spec.ts +1 -1
- package/src/device/external.ts +1 -1
- package/src/device/index.ts +1 -1
- package/src/device/payload.ts +1 -1
- package/src/errors.spec.ts +1 -1
- package/src/errors.ts +1 -1
- package/src/framer/adapter.spec.ts +1 -1
- package/src/framer/adapter.ts +1 -1
- package/src/framer/client.spec.ts +1 -1
- package/src/framer/client.ts +1 -1
- package/src/framer/codec.spec.ts +1 -1
- package/src/framer/codec.ts +1 -1
- package/src/framer/deleter.spec.ts +1 -1
- package/src/framer/deleter.ts +1 -1
- package/src/framer/external.ts +2 -1
- package/src/framer/frame.spec.ts +1 -1
- package/src/framer/frame.ts +1 -1
- package/src/framer/index.ts +1 -1
- package/src/framer/iterator.spec.ts +68 -1
- package/src/framer/iterator.ts +8 -1
- package/src/framer/payload.ts +1 -1
- package/src/framer/reader.spec.ts +213 -84
- package/src/framer/reader.ts +14 -7
- package/src/framer/streamProxy.ts +1 -1
- package/src/framer/streamer.spec.ts +1 -2
- package/src/framer/streamer.ts +4 -4
- package/src/framer/writer.spec.ts +1 -1
- package/src/framer/writer.ts +1 -1
- package/src/index.ts +2 -1
- package/src/label/access.spec.ts +1 -1
- package/src/label/client.ts +1 -1
- package/src/label/external.ts +1 -1
- package/src/label/index.ts +1 -1
- package/src/label/label.spec.ts +1 -1
- package/src/label/payload.ts +1 -1
- package/src/ontology/client.ts +6 -7
- package/src/ontology/external.ts +1 -1
- package/src/ontology/group/access.spec.ts +1 -1
- package/src/ontology/group/client.ts +1 -1
- package/src/ontology/group/external.ts +1 -1
- package/src/ontology/group/group.spec.ts +1 -1
- package/src/ontology/group/index.ts +1 -1
- package/src/ontology/group/payload.ts +1 -1
- package/src/ontology/index.ts +1 -1
- package/src/ontology/ontology.spec.ts +1 -1
- package/src/ontology/payload.ts +6 -3
- package/src/ontology/writer.ts +1 -1
- package/src/rack/access.spec.ts +1 -1
- package/src/rack/client.ts +1 -1
- package/src/rack/external.ts +1 -1
- package/src/rack/index.ts +1 -1
- package/src/rack/payload.ts +1 -1
- package/src/rack/rack.spec.ts +1 -1
- package/src/ranger/access.spec.ts +1 -1
- package/src/ranger/alias.ts +1 -1
- package/src/ranger/client.ts +1 -1
- package/src/ranger/external.ts +1 -1
- package/src/ranger/index.ts +1 -1
- package/src/ranger/kv.ts +1 -1
- package/src/ranger/payload.ts +1 -1
- package/src/ranger/ranger.spec.ts +1 -1
- package/src/ranger/writer.ts +1 -1
- package/src/status/access.spec.ts +1 -1
- package/src/status/client.ts +1 -1
- package/src/status/external.ts +1 -1
- package/src/status/index.ts +1 -1
- package/src/status/payload.ts +1 -1
- package/src/status/status.spec.ts +1 -1
- package/src/task/access.spec.ts +1 -1
- package/src/task/client.ts +11 -6
- package/src/task/external.ts +1 -1
- package/src/task/index.ts +1 -1
- package/src/task/payload.spec.ts +113 -0
- package/src/task/payload.ts +10 -5
- package/src/task/task.spec.ts +1 -1
- package/src/testutil/access.ts +1 -1
- package/src/testutil/channels.ts +1 -1
- package/src/testutil/client.ts +1 -1
- package/src/testutil/telem.ts +1 -1
- package/src/transport.ts +1 -1
- package/src/user/access.spec.ts +1 -1
- package/src/user/client.ts +1 -1
- package/src/user/external.ts +1 -1
- package/src/user/index.ts +1 -1
- package/src/user/payload.ts +1 -1
- package/src/user/user.spec.ts +1 -1
- package/src/util/decodeJSONString.ts +1 -1
- package/src/util/parseWithoutKeyConversion.ts +1 -1
- package/src/util/retrieve.spec.ts +1 -1
- package/src/util/retrieve.ts +1 -1
- package/src/util/telem.ts +1 -1
- package/src/view/client.ts +96 -0
- package/src/view/external.ts +11 -0
- package/src/view/index.ts +10 -0
- package/src/view/payload.ts +25 -0
- package/src/view/view.spec.ts +161 -0
- package/src/vite-env.d.ts +1 -1
- package/src/workspace/access.spec.ts +1 -1
- package/src/workspace/client.ts +1 -1
- package/src/workspace/external.ts +1 -1
- package/src/workspace/index.ts +1 -1
- package/src/workspace/lineplot/access.spec.ts +1 -1
- package/src/workspace/lineplot/client.ts +1 -1
- package/src/workspace/lineplot/external.ts +1 -1
- package/src/workspace/lineplot/index.ts +1 -1
- package/src/workspace/lineplot/lineplot.spec.ts +1 -1
- package/src/workspace/lineplot/payload.ts +1 -1
- package/src/workspace/log/access.spec.ts +1 -1
- package/src/workspace/log/client.ts +1 -1
- package/src/workspace/log/external.ts +1 -1
- package/src/workspace/log/index.ts +1 -1
- package/src/workspace/log/log.spec.ts +1 -1
- package/src/workspace/log/payload.ts +1 -1
- package/src/workspace/payload.ts +1 -1
- package/src/workspace/schematic/access.spec.ts +1 -1
- package/src/workspace/schematic/client.ts +1 -1
- package/src/workspace/schematic/external.ts +1 -1
- package/src/workspace/schematic/index.ts +1 -1
- package/src/workspace/schematic/payload.ts +1 -1
- package/src/workspace/schematic/schematic.spec.ts +1 -1
- package/src/workspace/schematic/symbol/access.spec.ts +1 -1
- package/src/workspace/schematic/symbol/client.spec.ts +1 -1
- package/src/workspace/schematic/symbol/client.ts +1 -1
- package/src/workspace/schematic/symbol/external.ts +1 -1
- package/src/workspace/schematic/symbol/index.ts +1 -1
- package/src/workspace/schematic/symbol/payload.ts +1 -1
- package/src/workspace/table/access.spec.ts +1 -1
- package/src/workspace/table/client.ts +1 -1
- package/src/workspace/table/external.ts +1 -1
- package/src/workspace/table/index.ts +1 -1
- package/src/workspace/table/payload.ts +1 -1
- package/src/workspace/table/table.spec.ts +1 -1
- package/src/workspace/workspace.spec.ts +1 -1
- package/vite.config.ts +1 -1
|
@@ -0,0 +1,113 @@
|
|
|
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
|
+
import { describe, expect, it } from "vitest";
|
|
11
|
+
|
|
12
|
+
import { newKey, rackKey } from "@/task/payload";
|
|
13
|
+
|
|
14
|
+
describe("newKey", () => {
|
|
15
|
+
describe("basic key generation", () => {
|
|
16
|
+
// Verifies that newKey correctly combines rack and task keys via bit shifting.
|
|
17
|
+
// The rack key occupies the upper 32 bits, task key the lower 32.
|
|
18
|
+
const cases = [
|
|
19
|
+
{ rackKey: 1, taskKey: 1, expected: ((1n << 32n) + 1n).toString() },
|
|
20
|
+
{ rackKey: 1, taskKey: 0, expected: (1n << 32n).toString() },
|
|
21
|
+
{ rackKey: 0, taskKey: 1, expected: "1" },
|
|
22
|
+
{ rackKey: 0, taskKey: 0, expected: "0" },
|
|
23
|
+
{ rackKey: 255, taskKey: 65535, expected: ((255n << 32n) + 65535n).toString() },
|
|
24
|
+
];
|
|
25
|
+
cases.forEach(({ rackKey: r, taskKey: t, expected }) => {
|
|
26
|
+
it(`should combine rackKey=${r} and taskKey=${t}`, () => {
|
|
27
|
+
expect(newKey(r, t)).toBe(expected);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe("default taskKey", () => {
|
|
33
|
+
// Verifies that omitting taskKey defaults to 0, producing rackKey << 32.
|
|
34
|
+
const rackKeys = [0, 1, 42, 1000];
|
|
35
|
+
rackKeys.forEach((r) => {
|
|
36
|
+
it(`should default taskKey to 0 for rackKey=${r}`, () => {
|
|
37
|
+
expect(newKey(r)).toBe(newKey(r, 0));
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("roundtrip with rackKey", () => {
|
|
43
|
+
// Verifies that rackKey correctly extracts the rack portion from a combined key.
|
|
44
|
+
// This ensures newKey and rackKey are inverse operations for the rack component.
|
|
45
|
+
const cases = [
|
|
46
|
+
{ rack: 1, task: 1 },
|
|
47
|
+
{ rack: 1, task: 0 },
|
|
48
|
+
{ rack: 0, task: 1 },
|
|
49
|
+
{ rack: 100, task: 50000 },
|
|
50
|
+
{ rack: 2147483647, task: 2147483647 }, // max 32-bit signed integers
|
|
51
|
+
];
|
|
52
|
+
cases.forEach(({ rack, task }) => {
|
|
53
|
+
it(`should extract rack=${rack} from key generated with task=${task}`, () => {
|
|
54
|
+
const key = newKey(rack, task);
|
|
55
|
+
expect(rackKey(key)).toBe(rack);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe("edge cases", () => {
|
|
61
|
+
// Verifies behavior at boundary values to ensure no overflow or precision issues.
|
|
62
|
+
it("should handle max 32-bit unsigned rack key", () => {
|
|
63
|
+
const maxUint32 = 0xffffffff;
|
|
64
|
+
const key = newKey(maxUint32, 0);
|
|
65
|
+
expect(rackKey(key)).toBe(maxUint32);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("should handle max 32-bit unsigned task key", () => {
|
|
69
|
+
const maxUint32 = 0xffffffff;
|
|
70
|
+
const key = newKey(1, maxUint32);
|
|
71
|
+
expect(key).toBe(((1n << 32n) + BigInt(maxUint32)).toString());
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("should handle both max 32-bit values", () => {
|
|
75
|
+
const maxUint32 = 0xffffffff;
|
|
76
|
+
const key = newKey(maxUint32, maxUint32);
|
|
77
|
+
const expected = ((BigInt(maxUint32) << 32n) + BigInt(maxUint32)).toString();
|
|
78
|
+
expect(key).toBe(expected);
|
|
79
|
+
expect(rackKey(key)).toBe(maxUint32);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe("rackKey", () => {
|
|
85
|
+
// Verifies rackKey extracts upper 32 bits from various key formats.
|
|
86
|
+
// Keys can be string, bigint, or number per keyZ schema.
|
|
87
|
+
describe("key format handling", () => {
|
|
88
|
+
const rack = 42;
|
|
89
|
+
const task = 100;
|
|
90
|
+
const expectedKey = newKey(rack, task);
|
|
91
|
+
|
|
92
|
+
it("should extract rack from string key", () => {
|
|
93
|
+
expect(rackKey(expectedKey)).toBe(rack);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("should extract rack from numeric string", () => {
|
|
97
|
+
const numericKey = ((42n << 32n) + 100n).toString();
|
|
98
|
+
expect(rackKey(numericKey)).toBe(42);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe("zero handling", () => {
|
|
103
|
+
// Verifies correct behavior when rack or task portions are zero.
|
|
104
|
+
it("should return 0 for key with zero rack", () => {
|
|
105
|
+
expect(rackKey("100")).toBe(0);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should return rack when task portion is zero", () => {
|
|
109
|
+
const key = newKey(5, 0);
|
|
110
|
+
expect(rackKey(key)).toBe(5);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
package/src/task/payload.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright
|
|
1
|
+
// Copyright 2026 Synnax Labs, Inc.
|
|
2
2
|
//
|
|
3
3
|
// Use of this software is governed by the Business Source License included in the file
|
|
4
4
|
// licenses/BSL.txt.
|
|
@@ -46,8 +46,9 @@ const newStatusDetailsZ = <DataSchema extends z.ZodType>(data: DataSchema) =>
|
|
|
46
46
|
export const newStatusZ = <DataSchema extends z.ZodType>(data: DataSchema) =>
|
|
47
47
|
status.statusZ(newStatusDetailsZ(data)).partial({ key: true, name: true });
|
|
48
48
|
|
|
49
|
-
export interface NewStatus<DataSchema extends z.ZodType = z.ZodUnknown>
|
|
50
|
-
|
|
49
|
+
export interface NewStatus<DataSchema extends z.ZodType = z.ZodUnknown> extends z.infer<
|
|
50
|
+
ReturnType<typeof newStatusZ<DataSchema>>
|
|
51
|
+
> {}
|
|
51
52
|
|
|
52
53
|
export const taskZ = <
|
|
53
54
|
Type extends z.ZodLiteral<string> = z.ZodLiteral<string>,
|
|
@@ -138,9 +139,13 @@ export interface Command extends Omit<z.infer<typeof commandZ>, "args"> {
|
|
|
138
139
|
args?: record.Unknown;
|
|
139
140
|
}
|
|
140
141
|
|
|
141
|
-
export interface StateObservable<
|
|
142
|
-
extends
|
|
142
|
+
export interface StateObservable<
|
|
143
|
+
StatusData extends z.ZodType,
|
|
144
|
+
> extends observe.ObservableAsyncCloseable<Status<StatusData>> {}
|
|
143
145
|
|
|
144
146
|
export interface CommandObservable extends observe.ObservableAsyncCloseable<Command> {}
|
|
145
147
|
|
|
146
148
|
export const rackKey = (key: Key): RackKey => Number(BigInt(key) >> 32n);
|
|
149
|
+
|
|
150
|
+
export const newKey = (rackKey: RackKey, taskKey: number = 0): Key =>
|
|
151
|
+
((BigInt(rackKey) << 32n) + BigInt(taskKey)).toString();
|
package/src/task/task.spec.ts
CHANGED
package/src/testutil/access.ts
CHANGED
package/src/testutil/channels.ts
CHANGED
package/src/testutil/client.ts
CHANGED
package/src/testutil/telem.ts
CHANGED
package/src/transport.ts
CHANGED
package/src/user/access.spec.ts
CHANGED
package/src/user/client.ts
CHANGED
package/src/user/external.ts
CHANGED
package/src/user/index.ts
CHANGED
package/src/user/payload.ts
CHANGED
package/src/user/user.spec.ts
CHANGED
package/src/util/retrieve.ts
CHANGED
package/src/util/telem.ts
CHANGED
|
@@ -0,0 +1,96 @@
|
|
|
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
|
+
import { sendRequired, type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
+
import { array } from "@synnaxlabs/x";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
14
|
+
import { type ontology } from "@/ontology";
|
|
15
|
+
import { checkForMultipleOrNoResults } from "@/util/retrieve";
|
|
16
|
+
import { type Key, keyZ, type New, newZ, type View, viewZ } from "@/view/payload";
|
|
17
|
+
|
|
18
|
+
export const SET_CHANNEL_NAME = "sy_view_set";
|
|
19
|
+
export const DELETE_CHANNEL_NAME = "sy_view_delete";
|
|
20
|
+
|
|
21
|
+
const createReqZ = z.object({ views: newZ.array() });
|
|
22
|
+
const createResZ = z.object({ views: viewZ.array() });
|
|
23
|
+
const deleteReqZ = z.object({ keys: keyZ.array() });
|
|
24
|
+
const emptyResZ = z.object({});
|
|
25
|
+
|
|
26
|
+
const retrieveRequestZ = z.object({
|
|
27
|
+
keys: keyZ.array().optional(),
|
|
28
|
+
types: z.string().array().optional(),
|
|
29
|
+
searchTerm: z.string().optional(),
|
|
30
|
+
offset: z.number().optional(),
|
|
31
|
+
limit: z.number().optional(),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const singleRetrieveArgsZ = z
|
|
35
|
+
.object({ key: keyZ })
|
|
36
|
+
.transform(({ key }) => ({ keys: [key] }));
|
|
37
|
+
|
|
38
|
+
const retrieveArgsZ = z.union([singleRetrieveArgsZ, retrieveRequestZ]);
|
|
39
|
+
|
|
40
|
+
export interface RetrieveSingleParams extends z.input<typeof singleRetrieveArgsZ> {}
|
|
41
|
+
export interface RetrieveMultipleParams extends z.input<typeof retrieveRequestZ> {}
|
|
42
|
+
|
|
43
|
+
const retrieveResponseZ = z.object({ views: array.nullableZ(viewZ) });
|
|
44
|
+
|
|
45
|
+
export class Client {
|
|
46
|
+
private readonly client: UnaryClient;
|
|
47
|
+
|
|
48
|
+
constructor(client: UnaryClient) {
|
|
49
|
+
this.client = client;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async retrieve(args: RetrieveSingleParams): Promise<View>;
|
|
53
|
+
async retrieve(args: RetrieveMultipleParams): Promise<View[]>;
|
|
54
|
+
async retrieve(
|
|
55
|
+
args: RetrieveSingleParams | RetrieveMultipleParams,
|
|
56
|
+
): Promise<View | View[]> {
|
|
57
|
+
const isSingle = "key" in args;
|
|
58
|
+
const res = await sendRequired(
|
|
59
|
+
this.client,
|
|
60
|
+
"/view/retrieve",
|
|
61
|
+
args,
|
|
62
|
+
retrieveArgsZ,
|
|
63
|
+
retrieveResponseZ,
|
|
64
|
+
);
|
|
65
|
+
checkForMultipleOrNoResults("View", args, res.views, isSingle);
|
|
66
|
+
return isSingle ? res.views[0] : res.views;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async create(view: New): Promise<View>;
|
|
70
|
+
async create(views: New[]): Promise<View[]>;
|
|
71
|
+
async create(views: New | New[]): Promise<View | View[]> {
|
|
72
|
+
const isMany = Array.isArray(views);
|
|
73
|
+
const res = await sendRequired<typeof createReqZ, typeof createResZ>(
|
|
74
|
+
this.client,
|
|
75
|
+
"/view/create",
|
|
76
|
+
{ views: array.toArray(views) },
|
|
77
|
+
createReqZ,
|
|
78
|
+
createResZ,
|
|
79
|
+
);
|
|
80
|
+
return isMany ? res.views : res.views[0];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async delete(keys: Key | Key[]): Promise<void> {
|
|
84
|
+
await sendRequired<typeof deleteReqZ, typeof emptyResZ>(
|
|
85
|
+
this.client,
|
|
86
|
+
"/view/delete",
|
|
87
|
+
{ keys: array.toArray(keys) },
|
|
88
|
+
deleteReqZ,
|
|
89
|
+
emptyResZ,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const ontologyID = (key: Key): ontology.ID => ({ type: "view", key });
|
|
95
|
+
|
|
96
|
+
export const TYPE_ONTOLOGY_ID = ontologyID("");
|
|
@@ -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 "@/view/client";
|
|
11
|
+
export * from "@/view/payload";
|
|
@@ -0,0 +1,10 @@
|
|
|
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 * as view from "@/view/external";
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
import { record } from "@synnaxlabs/x";
|
|
11
|
+
import z from "zod";
|
|
12
|
+
|
|
13
|
+
export const keyZ = z.uuid();
|
|
14
|
+
export type Key = z.infer<typeof keyZ>;
|
|
15
|
+
|
|
16
|
+
export const viewZ = z.object({
|
|
17
|
+
key: keyZ,
|
|
18
|
+
name: z.string(),
|
|
19
|
+
type: z.string(),
|
|
20
|
+
query: record.unknownZ,
|
|
21
|
+
});
|
|
22
|
+
export interface View extends z.infer<typeof viewZ> {}
|
|
23
|
+
|
|
24
|
+
export const newZ = viewZ.extend({ key: keyZ.optional() });
|
|
25
|
+
export interface New extends z.infer<typeof newZ> {}
|
|
@@ -0,0 +1,161 @@
|
|
|
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
|
+
import { id } from "@synnaxlabs/x";
|
|
11
|
+
import { describe, expect, it } from "vitest";
|
|
12
|
+
|
|
13
|
+
import { NotFoundError } from "@/errors";
|
|
14
|
+
import { createTestClient } from "@/testutil/client";
|
|
15
|
+
|
|
16
|
+
describe("View", () => {
|
|
17
|
+
describe("create", () => {
|
|
18
|
+
it("should create a single view", async () => {
|
|
19
|
+
const client = createTestClient();
|
|
20
|
+
const v = await client.views.create({
|
|
21
|
+
name: "Test View",
|
|
22
|
+
type: "lineplot",
|
|
23
|
+
query: { channels: ["test-1", "test-2"] },
|
|
24
|
+
});
|
|
25
|
+
expect(v.name).toEqual("Test View");
|
|
26
|
+
expect(v.type).toEqual("lineplot");
|
|
27
|
+
expect(v.key).toBeDefined();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should create multiple views", async () => {
|
|
31
|
+
const client = createTestClient();
|
|
32
|
+
const views = await client.views.create([
|
|
33
|
+
{
|
|
34
|
+
name: "View 1",
|
|
35
|
+
type: "table",
|
|
36
|
+
query: { channels: ["ch-1"] },
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "View 2",
|
|
40
|
+
type: "lineplot",
|
|
41
|
+
query: { channels: ["ch-2"] },
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
expect(views).toHaveLength(2);
|
|
45
|
+
expect(views[0].name).toEqual("View 1");
|
|
46
|
+
expect(views[0].query).toEqual({ channels: ["ch-1"] });
|
|
47
|
+
expect(views[1].name).toEqual("View 2");
|
|
48
|
+
expect(views[1].query).toEqual({ channels: ["ch-2"] });
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("retrieve", () => {
|
|
53
|
+
it("should retrieve a view by key", async () => {
|
|
54
|
+
const client = createTestClient();
|
|
55
|
+
const created = await client.views.create({
|
|
56
|
+
name: "Retrieve Test",
|
|
57
|
+
type: "table",
|
|
58
|
+
query: { channels: ["test"] },
|
|
59
|
+
});
|
|
60
|
+
const retrieved = await client.views.retrieve({ key: created.key });
|
|
61
|
+
expect(retrieved.key).toEqual(created.key);
|
|
62
|
+
expect(retrieved.name).toEqual("Retrieve Test");
|
|
63
|
+
expect(retrieved.query).toEqual({ channels: ["test"] });
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should retrieve multiple views", async () => {
|
|
67
|
+
const client = createTestClient();
|
|
68
|
+
const created = await client.views.create([
|
|
69
|
+
{
|
|
70
|
+
name: "Multi 1",
|
|
71
|
+
type: "table",
|
|
72
|
+
query: { channels: ["ch-1"] },
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: "Multi 2",
|
|
76
|
+
type: "lineplot",
|
|
77
|
+
query: { channels: ["ch-2"] },
|
|
78
|
+
},
|
|
79
|
+
]);
|
|
80
|
+
const keys = created.map((v) => v.key);
|
|
81
|
+
const retrieved = await client.views.retrieve({ keys });
|
|
82
|
+
expect(retrieved).toHaveLength(2);
|
|
83
|
+
expect(retrieved[0].name).toEqual("Multi 1");
|
|
84
|
+
expect(retrieved[0].query).toEqual({ channels: ["ch-1"] });
|
|
85
|
+
expect(retrieved[1].name).toEqual("Multi 2");
|
|
86
|
+
expect(retrieved[1].query).toEqual({ channels: ["ch-2"] });
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should retrieve views by type", async () => {
|
|
90
|
+
const client = createTestClient();
|
|
91
|
+
const type = id.create();
|
|
92
|
+
await client.views.create([
|
|
93
|
+
{
|
|
94
|
+
name: "Type 1",
|
|
95
|
+
type,
|
|
96
|
+
query: { channels: ["ch-1"] },
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "Type 2",
|
|
100
|
+
type,
|
|
101
|
+
query: { channels: ["ch-2"] },
|
|
102
|
+
},
|
|
103
|
+
]);
|
|
104
|
+
const retrieved = await client.views.retrieve({ types: [type] });
|
|
105
|
+
expect(retrieved).toHaveLength(2);
|
|
106
|
+
retrieved.forEach((v) => expect(v.type).toEqual(type));
|
|
107
|
+
retrieved.sort((a, b) => a.name.localeCompare(b.name));
|
|
108
|
+
expect(retrieved[0].name).toEqual("Type 1");
|
|
109
|
+
expect(retrieved[0].query).toEqual({ channels: ["ch-1"] });
|
|
110
|
+
expect(retrieved[1].name).toEqual("Type 2");
|
|
111
|
+
expect(retrieved[1].query).toEqual({ channels: ["ch-2"] });
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("should search for views by name", async () => {
|
|
115
|
+
const client = createTestClient();
|
|
116
|
+
await client.views.create({
|
|
117
|
+
name: "Searchable View",
|
|
118
|
+
type: "lineplot",
|
|
119
|
+
query: { channels: ["search"] },
|
|
120
|
+
});
|
|
121
|
+
const results = await client.views.retrieve({ searchTerm: "Searchable" });
|
|
122
|
+
expect(results.length).toBeGreaterThan(0);
|
|
123
|
+
expect(results[0].name).toContain("Searchable");
|
|
124
|
+
expect(results[0].query).toEqual({ channels: ["search"] });
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe("delete", () => {
|
|
129
|
+
it("should delete a single view", async () => {
|
|
130
|
+
const client = createTestClient();
|
|
131
|
+
const v = await client.views.create({
|
|
132
|
+
name: "To Delete",
|
|
133
|
+
type: "table",
|
|
134
|
+
query: { channels: ["delete"] },
|
|
135
|
+
});
|
|
136
|
+
await client.views.delete(v.key);
|
|
137
|
+
await expect(client.views.retrieve({ key: v.key })).rejects.toThrow(
|
|
138
|
+
NotFoundError,
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should delete multiple views", async () => {
|
|
143
|
+
const client = createTestClient();
|
|
144
|
+
const views = await client.views.create([
|
|
145
|
+
{
|
|
146
|
+
name: "Delete 1",
|
|
147
|
+
type: "table",
|
|
148
|
+
query: { channels: ["d1"] },
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: "Delete 2",
|
|
152
|
+
type: "lineplot",
|
|
153
|
+
query: { channels: ["d2"] },
|
|
154
|
+
},
|
|
155
|
+
]);
|
|
156
|
+
const keys = views.map((v) => v.key);
|
|
157
|
+
await client.views.delete(keys);
|
|
158
|
+
await expect(client.views.retrieve({ keys })).rejects.toThrow(NotFoundError);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
});
|
package/src/vite-env.d.ts
CHANGED
package/src/workspace/client.ts
CHANGED
package/src/workspace/index.ts
CHANGED