@synnaxlabs/client 0.56.1 → 0.57.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/dist/client-B08VDLSA.js +14463 -0
- package/dist/client-B08VDLSA.js.map +1 -0
- package/dist/client.js +1128 -14876
- package/dist/client.js.map +1 -0
- package/dist/src/access/client.d.ts +10 -1
- package/dist/src/access/client.d.ts.map +1 -1
- package/dist/src/access/enforce.d.ts.map +1 -1
- package/dist/src/access/external.d.ts +1 -0
- package/dist/src/access/external.d.ts.map +1 -1
- package/dist/src/access/granted.d.ts +39 -0
- package/dist/src/access/granted.d.ts.map +1 -0
- package/dist/src/access/policy/client.d.ts +136 -147
- package/dist/src/access/policy/client.d.ts.map +1 -1
- package/dist/src/access/policy/types.gen.d.ts +15 -68
- package/dist/src/access/policy/types.gen.d.ts.map +1 -1
- package/dist/src/access/role/client.d.ts +77 -58
- package/dist/src/access/role/client.d.ts.map +1 -1
- package/dist/src/access/role/types.gen.d.ts +8 -14
- package/dist/src/access/role/types.gen.d.ts.map +1 -1
- package/dist/src/actions/actions.d.ts +5 -6
- package/dist/src/actions/actions.d.ts.map +1 -1
- package/dist/src/actions/controller.d.ts +194 -0
- package/dist/src/actions/controller.d.ts.map +1 -0
- package/dist/src/actions/external.d.ts +1 -0
- package/dist/src/actions/external.d.ts.map +1 -1
- package/dist/src/arc/actions.d.ts +575 -0
- package/dist/src/arc/actions.d.ts.map +1 -0
- package/dist/src/arc/actions.gen.d.ts +1439 -0
- package/dist/src/arc/actions.gen.d.ts.map +1 -0
- package/dist/src/arc/client.d.ts +97 -13
- package/dist/src/arc/client.d.ts.map +1 -1
- package/dist/src/arc/compiler/types.gen.d.ts +3 -3
- package/dist/src/arc/compiler/types.gen.d.ts.map +1 -1
- package/dist/src/arc/external.d.ts +2 -0
- package/dist/src/arc/external.d.ts.map +1 -1
- package/dist/src/arc/graph/types.gen.d.ts +45 -597
- package/dist/src/arc/graph/types.gen.d.ts.map +1 -1
- package/dist/src/arc/ir/index.d.ts +1 -1
- package/dist/src/arc/ir/index.d.ts.map +1 -1
- package/dist/src/arc/ir/ir.d.ts +2 -0
- package/dist/src/arc/ir/ir.d.ts.map +1 -0
- package/dist/src/arc/ir/types.gen.d.ts +58 -2807
- package/dist/src/arc/ir/types.gen.d.ts.map +1 -1
- package/dist/src/arc/module/types.gen.d.ts +18 -1090
- package/dist/src/arc/module/types.gen.d.ts.map +1 -1
- package/dist/src/arc/program/types.gen.d.ts +18 -1090
- package/dist/src/arc/program/types.gen.d.ts.map +1 -1
- package/dist/src/arc/text/types.gen.d.ts +54 -1
- package/dist/src/arc/text/types.gen.d.ts.map +1 -1
- package/dist/src/arc/types/types.gen.d.ts +35 -153
- package/dist/src/arc/types/types.gen.d.ts.map +1 -1
- package/dist/src/arc/types.gen.d.ts +98 -2278
- package/dist/src/arc/types.gen.d.ts.map +1 -1
- package/dist/src/auth/auth.d.ts +14 -2
- package/dist/src/auth/auth.d.ts.map +1 -1
- package/dist/src/channel/client.d.ts +113 -75
- package/dist/src/channel/client.d.ts.map +1 -1
- package/dist/src/channel/external.d.ts +0 -1
- package/dist/src/channel/external.d.ts.map +1 -1
- package/dist/src/channel/payload.d.ts +65 -56
- package/dist/src/channel/payload.d.ts.map +1 -1
- package/dist/src/channel/types.gen.d.ts +26 -73
- package/dist/src/channel/types.gen.d.ts.map +1 -1
- package/dist/src/channel/writer.d.ts +1 -3
- package/dist/src/channel/writer.d.ts.map +1 -1
- package/dist/src/client.d.ts +55 -27
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/connection/client.d.ts +146 -0
- package/dist/src/connection/client.d.ts.map +1 -0
- package/dist/src/connection/external.d.ts +3 -0
- package/dist/src/connection/external.d.ts.map +1 -0
- package/dist/src/connection/index.d.ts +1 -1
- package/dist/src/connection/index.d.ts.map +1 -1
- package/dist/src/connection/status.d.ts +252 -0
- package/dist/src/connection/status.d.ts.map +1 -0
- package/dist/src/control/client.d.ts +31 -7
- package/dist/src/control/client.d.ts.map +1 -1
- package/dist/src/control/state.d.ts +47 -16
- package/dist/src/control/state.d.ts.map +1 -1
- package/dist/src/device/client.d.ts +59 -17
- package/dist/src/device/client.d.ts.map +1 -1
- package/dist/src/device/types.gen.d.ts +17 -67
- package/dist/src/device/types.gen.d.ts.map +1 -1
- package/dist/src/errors.d.ts +17 -20
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/ethercat/external.d.ts +2 -0
- package/dist/src/ethercat/external.d.ts.map +1 -0
- package/dist/src/ethercat/index.d.ts +2 -0
- package/dist/src/ethercat/index.d.ts.map +1 -0
- package/dist/src/ethercat/types.gen.d.ts +243 -0
- package/dist/src/ethercat/types.gen.d.ts.map +1 -0
- package/dist/src/framer/adapter.d.ts +8 -5
- package/dist/src/framer/adapter.d.ts.map +1 -1
- package/dist/src/framer/benchutil.d.ts +19 -0
- package/dist/src/framer/benchutil.d.ts.map +1 -0
- package/dist/src/framer/cache/cache.d.ts +38 -0
- package/dist/src/framer/cache/cache.d.ts.map +1 -0
- package/dist/src/framer/cache/dynamic.d.ts +71 -0
- package/dist/src/framer/cache/dynamic.d.ts.map +1 -0
- package/dist/src/framer/cache/reader.d.ts +43 -0
- package/dist/src/framer/cache/reader.d.ts.map +1 -0
- package/dist/src/framer/cache/static.d.ts +66 -0
- package/dist/src/framer/cache/static.d.ts.map +1 -0
- package/dist/src/framer/cache/streamer.d.ts +86 -0
- package/dist/src/framer/cache/streamer.d.ts.map +1 -0
- package/dist/src/framer/cache/transform.d.ts +18 -0
- package/dist/src/framer/cache/transform.d.ts.map +1 -0
- package/dist/src/framer/cache/unary.d.ts +37 -0
- package/dist/src/framer/cache/unary.d.ts.map +1 -0
- package/dist/src/framer/client.d.ts +35 -14
- package/dist/src/framer/client.d.ts.map +1 -1
- package/dist/src/framer/codec.d.ts.map +1 -1
- package/dist/src/framer/deleter.d.ts +3 -2
- package/dist/src/framer/deleter.d.ts.map +1 -1
- package/dist/src/framer/external.d.ts +6 -0
- package/dist/src/framer/external.d.ts.map +1 -1
- package/dist/src/framer/feed.d.ts +40 -0
- package/dist/src/framer/feed.d.ts.map +1 -0
- package/dist/src/framer/frame.d.ts +16 -20
- package/dist/src/framer/frame.d.ts.map +1 -1
- package/dist/src/framer/hardened.d.ts +70 -0
- package/dist/src/framer/hardened.d.ts.map +1 -0
- package/dist/src/framer/iterator.d.ts +36 -43
- package/dist/src/framer/iterator.d.ts.map +1 -1
- package/dist/src/framer/reader.d.ts +3 -2
- package/dist/src/framer/reader.d.ts.map +1 -1
- package/dist/src/framer/streamer.d.ts +132 -205
- package/dist/src/framer/streamer.d.ts.map +1 -1
- package/dist/src/framer/writer.d.ts +130 -161
- package/dist/src/framer/writer.d.ts.map +1 -1
- package/dist/src/group/client.d.ts +66 -9
- package/dist/src/group/client.d.ts.map +1 -1
- package/dist/src/group/types.gen.d.ts +2 -2
- package/dist/src/http/external.d.ts +2 -0
- package/dist/src/http/external.d.ts.map +1 -0
- package/dist/src/http/index.d.ts +2 -0
- package/dist/src/http/index.d.ts.map +1 -0
- package/dist/src/http/types.gen.d.ts +451 -0
- package/dist/src/http/types.gen.d.ts.map +1 -0
- package/dist/src/imex/client.d.ts +88 -0
- package/dist/src/imex/client.d.ts.map +1 -0
- package/dist/src/imex/index.d.ts +2 -0
- package/dist/src/imex/index.d.ts.map +1 -0
- package/dist/src/index.d.ts +18 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/label/client.d.ts +55 -36
- package/dist/src/label/client.d.ts.map +1 -1
- package/dist/src/label/external.d.ts +2 -0
- package/dist/src/label/external.d.ts.map +1 -1
- package/dist/src/label/payload.d.ts +4 -46
- package/dist/src/label/payload.d.ts.map +1 -1
- package/dist/src/label/store.d.ts +8 -0
- package/dist/src/label/store.d.ts.map +1 -0
- package/dist/src/label/types.gen.d.ts +45 -0
- package/dist/src/label/types.gen.d.ts.map +1 -0
- package/dist/src/labjack/external.d.ts +2 -0
- package/dist/src/labjack/external.d.ts.map +1 -0
- package/dist/src/labjack/index.d.ts +2 -0
- package/dist/src/labjack/index.d.ts.map +1 -0
- package/dist/src/labjack/types.gen.d.ts +442 -0
- package/dist/src/labjack/types.gen.d.ts.map +1 -0
- package/dist/src/lineplot/actions.d.ts +914 -0
- package/dist/src/lineplot/actions.d.ts.map +1 -0
- package/dist/src/lineplot/actions.gen.d.ts +4208 -0
- package/dist/src/lineplot/actions.gen.d.ts.map +1 -0
- package/dist/src/lineplot/client.d.ts +66 -16
- package/dist/src/lineplot/client.d.ts.map +1 -1
- package/dist/src/lineplot/external.d.ts +3 -0
- package/dist/src/lineplot/external.d.ts.map +1 -1
- package/dist/src/lineplot/line.d.ts +16 -0
- package/dist/src/lineplot/line.d.ts.map +1 -0
- package/dist/src/lineplot/types.gen.d.ts +837 -14
- package/dist/src/lineplot/types.gen.d.ts.map +1 -1
- package/dist/src/log/actions.d.ts +271 -0
- package/dist/src/log/actions.d.ts.map +1 -0
- package/dist/src/log/actions.gen.d.ts +1529 -0
- package/dist/src/log/actions.gen.d.ts.map +1 -0
- package/dist/src/log/client.d.ts +66 -16
- package/dist/src/log/client.d.ts.map +1 -1
- package/dist/src/log/external.d.ts +2 -0
- package/dist/src/log/external.d.ts.map +1 -1
- package/dist/src/log/types.gen.d.ts +139 -14
- package/dist/src/log/types.gen.d.ts.map +1 -1
- package/dist/src/modbus/external.d.ts +2 -0
- package/dist/src/modbus/external.d.ts.map +1 -0
- package/dist/src/modbus/index.d.ts +2 -0
- package/dist/src/modbus/index.d.ts.map +1 -0
- package/dist/src/modbus/types.gen.d.ts +280 -0
- package/dist/src/modbus/types.gen.d.ts.map +1 -0
- package/dist/src/ni/external.d.ts +2 -0
- package/dist/src/ni/external.d.ts.map +1 -0
- package/dist/src/ni/index.d.ts +2 -0
- package/dist/src/ni/index.d.ts.map +1 -0
- package/dist/src/ni/types.gen.d.ts +21029 -0
- package/dist/src/ni/types.gen.d.ts.map +1 -0
- package/dist/src/node/index.d.ts +2 -0
- package/dist/src/node/index.d.ts.map +1 -0
- package/dist/src/node/types.gen.d.ts +4 -0
- package/dist/src/node/types.gen.d.ts.map +1 -0
- package/dist/src/ontology/client.d.ts +314 -67
- package/dist/src/ontology/client.d.ts.map +1 -1
- package/dist/src/ontology/external.d.ts +1 -0
- package/dist/src/ontology/external.d.ts.map +1 -1
- package/dist/src/ontology/payload.d.ts +60 -18
- package/dist/src/ontology/payload.d.ts.map +1 -1
- package/dist/src/ontology/store.d.ts +32 -0
- package/dist/src/ontology/store.d.ts.map +1 -0
- package/dist/src/ontology/types.gen.d.ts +3 -2
- package/dist/src/ontology/types.gen.d.ts.map +1 -1
- package/dist/src/ontology/writer.d.ts +16 -10
- package/dist/src/ontology/writer.d.ts.map +1 -1
- package/dist/src/opcua/external.d.ts +2 -0
- package/dist/src/opcua/external.d.ts.map +1 -0
- package/dist/src/opcua/index.d.ts +2 -0
- package/dist/src/opcua/index.d.ts.map +1 -0
- package/dist/src/opcua/types.gen.d.ts +82 -0
- package/dist/src/opcua/types.gen.d.ts.map +1 -0
- package/dist/src/pagerduty/external.d.ts +2 -0
- package/dist/src/pagerduty/external.d.ts.map +1 -0
- package/dist/src/pagerduty/index.d.ts +2 -0
- package/dist/src/pagerduty/index.d.ts.map +1 -0
- package/dist/src/pagerduty/types.gen.d.ts +30 -0
- package/dist/src/pagerduty/types.gen.d.ts.map +1 -0
- package/dist/src/panel/actions.d.ts +273 -0
- package/dist/src/panel/actions.d.ts.map +1 -0
- package/dist/src/panel/actions.gen.d.ts +1255 -0
- package/dist/src/panel/actions.gen.d.ts.map +1 -0
- package/dist/src/panel/client.d.ts +148 -0
- package/dist/src/panel/client.d.ts.map +1 -0
- package/dist/src/panel/external.d.ts +6 -0
- package/dist/src/panel/external.d.ts.map +1 -0
- package/dist/src/panel/index.d.ts +2 -0
- package/dist/src/panel/index.d.ts.map +1 -0
- package/dist/src/panel/tree.d.ts +50 -0
- package/dist/src/panel/tree.d.ts.map +1 -0
- package/dist/src/panel/types.gen.d.ts +370 -0
- package/dist/src/panel/types.gen.d.ts.map +1 -0
- package/dist/src/project/client.d.ts +89 -0
- package/dist/src/project/client.d.ts.map +1 -0
- package/dist/src/project/external.d.ts.map +1 -0
- package/dist/src/project/index.d.ts +2 -0
- package/dist/src/project/index.d.ts.map +1 -0
- package/dist/src/project/types.gen.d.ts +27 -0
- package/dist/src/project/types.gen.d.ts.map +1 -0
- package/dist/src/query/cache.d.ts +132 -0
- package/dist/src/query/cache.d.ts.map +1 -0
- package/dist/src/query/deleted.d.ts +20 -0
- package/dist/src/query/deleted.d.ts.map +1 -0
- package/dist/src/query/derived.d.ts +33 -0
- package/dist/src/query/derived.d.ts.map +1 -0
- package/dist/src/query/external.d.ts +10 -0
- package/dist/src/query/external.d.ts.map +1 -0
- package/dist/src/query/index.d.ts +2 -0
- package/dist/src/query/index.d.ts.map +1 -0
- package/dist/src/query/query.d.ts +235 -0
- package/dist/src/query/query.d.ts.map +1 -0
- package/dist/src/query/retriever.d.ts +135 -0
- package/dist/src/query/retriever.d.ts.map +1 -0
- package/dist/src/query/streamer.d.ts +67 -0
- package/dist/src/query/streamer.d.ts.map +1 -0
- package/dist/src/query/table.d.ts +219 -0
- package/dist/src/query/table.d.ts.map +1 -0
- package/dist/src/query/types.d.ts +35 -0
- package/dist/src/query/types.d.ts.map +1 -0
- package/dist/src/query/write.d.ts +21 -0
- package/dist/src/query/write.d.ts.map +1 -0
- package/dist/src/rack/client.d.ts +58 -20
- package/dist/src/rack/client.d.ts.map +1 -1
- package/dist/src/rack/types.gen.d.ts +11 -12
- package/dist/src/rack/types.gen.d.ts.map +1 -1
- package/dist/src/range/alias/types.gen.d.ts +2 -3
- package/dist/src/range/alias/types.gen.d.ts.map +1 -1
- package/dist/src/ranger/client.d.ts +138 -27
- package/dist/src/ranger/client.d.ts.map +1 -1
- package/dist/src/ranger/kv/client.d.ts +7 -4
- package/dist/src/ranger/kv/client.d.ts.map +1 -1
- package/dist/src/ranger/payload.d.ts +3 -0
- package/dist/src/ranger/payload.d.ts.map +1 -1
- package/dist/src/ranger/types.gen.d.ts +45 -101
- package/dist/src/ranger/types.gen.d.ts.map +1 -1
- package/dist/src/ranger/writer.d.ts +2 -74
- package/dist/src/ranger/writer.d.ts.map +1 -1
- package/dist/src/schematic/actions.d.ts +90 -33
- package/dist/src/schematic/actions.d.ts.map +1 -1
- package/dist/src/schematic/actions.gen.d.ts +207 -114
- package/dist/src/schematic/actions.gen.d.ts.map +1 -1
- package/dist/src/schematic/client.d.ts +70 -68
- package/dist/src/schematic/client.d.ts.map +1 -1
- package/dist/src/schematic/symbol/client.d.ts +133 -27
- package/dist/src/schematic/symbol/client.d.ts.map +1 -1
- package/dist/src/schematic/symbol/types.gen.d.ts +258 -153
- package/dist/src/schematic/symbol/types.gen.d.ts.map +1 -1
- package/dist/src/schematic/types.gen.d.ts +17 -96
- package/dist/src/schematic/types.gen.d.ts.map +1 -1
- package/dist/src/status/client.d.ts +69 -14
- package/dist/src/status/client.d.ts.map +1 -1
- package/dist/src/status/external.d.ts +2 -0
- package/dist/src/status/external.d.ts.map +1 -1
- package/dist/src/status/payload.d.ts +2 -36
- package/dist/src/status/payload.d.ts.map +1 -1
- package/dist/src/status/status.d.ts +65 -0
- package/dist/src/status/status.d.ts.map +1 -0
- package/dist/src/status/types.gen.d.ts +58 -0
- package/dist/src/status/types.gen.d.ts.map +1 -0
- package/dist/src/table/actions.d.ts +72 -13
- package/dist/src/table/actions.d.ts.map +1 -1
- package/dist/src/table/actions.gen.d.ts +221 -137
- package/dist/src/table/actions.gen.d.ts.map +1 -1
- package/dist/src/table/client.d.ts +64 -40
- package/dist/src/table/client.d.ts.map +1 -1
- package/dist/src/table/types.gen.d.ts +20 -55
- package/dist/src/table/types.gen.d.ts.map +1 -1
- package/dist/src/task/client.d.ts +149 -28
- package/dist/src/task/client.d.ts.map +1 -1
- package/dist/src/task/types.gen.d.ts +71 -89
- package/dist/src/task/types.gen.d.ts.map +1 -1
- package/dist/src/testutil/access.d.ts +27 -1
- package/dist/src/testutil/access.d.ts.map +1 -1
- package/dist/src/testutil/channels.d.ts +2 -0
- package/dist/src/testutil/channels.d.ts.map +1 -1
- package/dist/src/testutil/client.d.ts +5 -0
- package/dist/src/testutil/client.d.ts.map +1 -1
- package/dist/src/testutil/connection.d.ts +10 -0
- package/dist/src/testutil/connection.d.ts.map +1 -0
- package/dist/src/testutil/index.d.ts +9 -0
- package/dist/src/testutil/index.d.ts.map +1 -0
- package/dist/src/testutil/panels.d.ts +8 -0
- package/dist/src/testutil/panels.d.ts.map +1 -0
- package/dist/src/testutil/proxy.d.ts +29 -0
- package/dist/src/testutil/proxy.d.ts.map +1 -0
- package/dist/src/testutil/query.d.ts +7 -0
- package/dist/src/testutil/query.d.ts.map +1 -0
- package/dist/src/testutil/telem.d.ts +4 -0
- package/dist/src/testutil/telem.d.ts.map +1 -1
- package/dist/src/transport.d.ts +10 -4
- package/dist/src/transport.d.ts.map +1 -1
- package/dist/src/user/client.d.ts +29 -28
- package/dist/src/user/client.d.ts.map +1 -1
- package/dist/src/user/external.d.ts +1 -1
- package/dist/src/user/external.d.ts.map +1 -1
- package/dist/src/user/types.gen.d.ts +4 -4
- package/dist/src/util/retrieve.d.ts +2 -2
- package/dist/src/util/retrieve.d.ts.map +1 -1
- package/dist/src/util/telem.d.ts.map +1 -1
- package/dist/src/view/client.d.ts +30 -14
- package/dist/src/view/client.d.ts.map +1 -1
- package/dist/src/view/types.gen.d.ts +7 -15
- package/dist/src/view/types.gen.d.ts.map +1 -1
- package/dist/testutil.js +189 -0
- package/dist/testutil.js.map +1 -0
- package/package.json +40 -17
- package/src/access/client.ts +14 -3
- package/src/access/enforce.ts +0 -3
- package/src/access/external.ts +1 -0
- package/src/access/granted.ts +114 -0
- package/src/access/policy/client.ts +135 -43
- package/src/access/policy/types.gen.ts +9 -11
- package/src/access/role/client.ts +160 -38
- package/src/access/role/types.gen.ts +8 -12
- package/src/actions/actions.ts +5 -6
- package/src/actions/controller.ts +626 -0
- package/src/actions/external.ts +11 -0
- package/src/arc/actions.gen.ts +313 -0
- package/src/arc/actions.ts +192 -0
- package/src/arc/client.ts +424 -41
- package/src/arc/compiler/types.gen.ts +5 -6
- package/src/arc/external.ts +2 -0
- package/src/arc/graph/types.gen.ts +24 -22
- package/src/arc/ir/index.ts +1 -1
- package/{eslint.config.ts → src/arc/ir/ir.ts} +1 -4
- package/src/arc/ir/types.gen.ts +42 -41
- package/src/arc/text/types.gen.ts +21 -2
- package/src/arc/types/types.gen.ts +40 -32
- package/src/arc/types.gen.ts +31 -29
- package/src/auth/auth.ts +40 -8
- package/src/channel/client.ts +529 -132
- package/src/channel/external.ts +0 -1
- package/src/channel/payload.ts +30 -3
- package/src/channel/types.gen.ts +37 -48
- package/src/channel/writer.ts +2 -11
- package/src/client.ts +215 -91
- package/src/connection/client.ts +495 -0
- package/src/connection/external.ts +34 -0
- package/src/connection/index.ts +1 -1
- package/src/connection/status.ts +442 -0
- package/src/control/client.ts +84 -12
- package/src/control/state.ts +17 -36
- package/src/device/client.ts +293 -41
- package/src/device/types.gen.ts +15 -26
- package/src/errors.ts +45 -22
- package/src/{workspace → ethercat}/external.ts +1 -2
- package/src/{workspace → ethercat}/index.ts +1 -1
- package/src/ethercat/types.gen.ts +151 -0
- package/src/framer/adapter.ts +60 -37
- package/src/framer/benchutil.ts +67 -0
- package/src/framer/cache/cache.ts +115 -0
- package/src/framer/cache/dynamic.ts +279 -0
- package/src/framer/cache/reader.ts +160 -0
- package/src/framer/cache/static.ts +215 -0
- package/src/framer/cache/streamer.ts +391 -0
- package/src/framer/cache/transform.ts +31 -0
- package/src/framer/cache/unary.ts +104 -0
- package/src/framer/client.ts +71 -43
- package/src/framer/codec.ts +55 -18
- package/src/framer/deleter.ts +4 -6
- package/src/framer/external.ts +10 -0
- package/src/framer/feed.ts +108 -0
- package/src/framer/frame.ts +13 -23
- package/src/framer/hardened.ts +283 -0
- package/src/framer/iterator.ts +31 -42
- package/src/framer/reader.ts +11 -11
- package/src/framer/streamer.ts +18 -178
- package/src/framer/writer.ts +39 -59
- package/src/group/client.ts +158 -23
- package/src/http/external.ts +10 -0
- package/src/{cluster → http}/index.ts +1 -1
- package/src/http/types.gen.ts +245 -0
- package/src/imex/client.ts +125 -0
- package/src/imex/index.ts +10 -0
- package/src/index.ts +18 -6
- package/src/label/client.ts +193 -54
- package/src/label/external.ts +2 -0
- package/src/label/payload.ts +4 -9
- package/src/label/store.ts +28 -0
- package/src/label/types.gen.ts +31 -0
- package/src/labjack/external.ts +10 -0
- package/src/labjack/index.ts +10 -0
- package/src/labjack/types.gen.ts +251 -0
- package/src/lineplot/actions.gen.ts +880 -0
- package/src/lineplot/actions.ts +535 -0
- package/src/lineplot/client.ts +224 -52
- package/src/lineplot/external.ts +3 -0
- package/src/lineplot/line.ts +80 -0
- package/src/lineplot/types.gen.ts +225 -12
- package/src/log/actions.gen.ts +474 -0
- package/src/log/actions.ts +242 -0
- package/src/log/client.ts +223 -52
- package/src/log/external.ts +2 -0
- package/src/log/types.gen.ts +45 -14
- package/src/modbus/external.ts +10 -0
- package/src/modbus/index.ts +10 -0
- package/src/modbus/types.gen.ts +185 -0
- package/src/ni/external.ts +10 -0
- package/src/ni/index.ts +10 -0
- package/src/ni/types.gen.ts +1632 -0
- package/src/node/index.ts +10 -0
- package/src/{cluster → node}/types.gen.ts +2 -2
- package/src/ontology/client.ts +408 -99
- package/src/ontology/external.ts +7 -0
- package/src/ontology/payload.ts +48 -7
- package/src/ontology/store.ts +83 -0
- package/src/ontology/types.gen.ts +2 -1
- package/src/ontology/writer.ts +1 -0
- package/src/opcua/external.ts +10 -0
- package/src/opcua/index.ts +10 -0
- package/src/opcua/types.gen.ts +65 -0
- package/src/pagerduty/external.ts +10 -0
- package/src/pagerduty/index.ts +10 -0
- package/src/pagerduty/types.gen.ts +41 -0
- package/src/panel/actions.gen.ts +267 -0
- package/src/panel/actions.ts +357 -0
- package/src/panel/client.ts +327 -0
- package/src/panel/external.ts +14 -0
- package/src/panel/index.ts +10 -0
- package/src/panel/tree.ts +163 -0
- package/src/panel/types.gen.ts +164 -0
- package/src/project/client.ts +273 -0
- package/src/project/external.ts +11 -0
- package/src/project/index.ts +10 -0
- package/src/project/types.gen.ts +40 -0
- package/src/query/cache.ts +326 -0
- package/src/query/deleted.ts +38 -0
- package/src/query/derived.ts +101 -0
- package/src/query/external.ts +51 -0
- package/src/query/index.ts +10 -0
- package/src/query/query.ts +865 -0
- package/src/query/retriever.ts +308 -0
- package/src/query/streamer.ts +207 -0
- package/src/query/table.ts +625 -0
- package/src/query/types.ts +54 -0
- package/src/query/write.ts +42 -0
- package/src/rack/client.ts +233 -45
- package/src/rack/types.gen.ts +15 -16
- package/src/range/alias/types.gen.ts +2 -3
- package/src/ranger/client.ts +581 -70
- package/src/ranger/kv/client.ts +52 -21
- package/src/ranger/payload.ts +3 -0
- package/src/ranger/types.gen.ts +21 -23
- package/src/ranger/writer.ts +4 -8
- package/src/schematic/actions.gen.ts +62 -53
- package/src/schematic/actions.ts +44 -42
- package/src/schematic/client.ts +226 -70
- package/src/schematic/symbol/client.ts +277 -48
- package/src/schematic/symbol/types.gen.ts +22 -34
- package/src/schematic/types.gen.ts +22 -29
- package/src/status/client.ts +321 -44
- package/src/status/external.ts +2 -0
- package/src/status/payload.ts +1 -23
- package/src/status/status.ts +241 -0
- package/src/status/types.gen.ts +108 -0
- package/src/table/actions.gen.ts +96 -63
- package/src/table/actions.ts +44 -19
- package/src/table/client.ts +220 -56
- package/src/table/types.gen.ts +24 -31
- package/src/task/client.ts +580 -101
- package/src/task/types.gen.ts +68 -75
- package/src/testutil/access.ts +102 -6
- package/src/testutil/channels.ts +29 -0
- package/src/testutil/client.ts +27 -2
- package/src/testutil/connection.ts +47 -0
- package/src/testutil/index.ts +17 -0
- package/src/testutil/panels.ts +26 -0
- package/src/testutil/proxy.ts +106 -0
- package/src/testutil/query.ts +28 -0
- package/src/testutil/telem.ts +17 -1
- package/src/transport.ts +18 -7
- package/src/user/client.ts +165 -64
- package/src/user/external.ts +1 -1
- package/src/user/types.gen.ts +5 -5
- package/src/util/retrieve.ts +4 -4
- package/src/util/telem.ts +0 -1
- package/src/view/client.ts +120 -37
- package/src/view/types.gen.ts +8 -11
- package/.turbo/turbo-build.log +0 -20
- package/.vscode/settings.json +0 -3
- package/CONTRIBUTING.md +0 -47
- package/dist/client.cjs +0 -118
- package/dist/eslint.config.d.ts +0 -4
- package/dist/eslint.config.d.ts.map +0 -1
- package/dist/src/access/enforce.spec.d.ts +0 -2
- package/dist/src/access/enforce.spec.d.ts.map +0 -1
- package/dist/src/access/policy/access.spec.d.ts +0 -2
- package/dist/src/access/policy/access.spec.d.ts.map +0 -1
- package/dist/src/access/role/role.spec.d.ts +0 -2
- package/dist/src/access/role/role.spec.d.ts.map +0 -1
- package/dist/src/actions/actions.spec.d.ts +0 -2
- package/dist/src/actions/actions.spec.d.ts.map +0 -1
- package/dist/src/arc/access.spec.d.ts +0 -2
- package/dist/src/arc/access.spec.d.ts.map +0 -1
- package/dist/src/arc/arc.spec.d.ts +0 -2
- package/dist/src/arc/arc.spec.d.ts.map +0 -1
- package/dist/src/arc/lsp.spec.d.ts +0 -2
- package/dist/src/arc/lsp.spec.d.ts.map +0 -1
- package/dist/src/auth/auth.spec.d.ts +0 -2
- package/dist/src/auth/auth.spec.d.ts.map +0 -1
- package/dist/src/channel/access.spec.d.ts +0 -2
- package/dist/src/channel/access.spec.d.ts.map +0 -1
- package/dist/src/channel/batchRetriever.spec.d.ts +0 -2
- package/dist/src/channel/batchRetriever.spec.d.ts.map +0 -1
- package/dist/src/channel/channel.spec.d.ts +0 -2
- package/dist/src/channel/channel.spec.d.ts.map +0 -1
- package/dist/src/channel/payload.spec.d.ts +0 -2
- package/dist/src/channel/payload.spec.d.ts.map +0 -1
- package/dist/src/channel/retriever.d.ts +0 -64
- package/dist/src/channel/retriever.d.ts.map +0 -1
- package/dist/src/cluster/index.d.ts +0 -2
- package/dist/src/cluster/index.d.ts.map +0 -1
- package/dist/src/cluster/types.gen.d.ts +0 -4
- package/dist/src/cluster/types.gen.d.ts.map +0 -1
- package/dist/src/connection/checker.d.ts +0 -86
- package/dist/src/connection/checker.d.ts.map +0 -1
- package/dist/src/connection/connection.spec.d.ts +0 -2
- package/dist/src/connection/connection.spec.d.ts.map +0 -1
- package/dist/src/connection.spec.d.ts +0 -2
- package/dist/src/connection.spec.d.ts.map +0 -1
- package/dist/src/control/state.spec.d.ts +0 -2
- package/dist/src/control/state.spec.d.ts.map +0 -1
- package/dist/src/device/access.spec.d.ts +0 -2
- package/dist/src/device/access.spec.d.ts.map +0 -1
- package/dist/src/device/device.spec.d.ts +0 -2
- package/dist/src/device/device.spec.d.ts.map +0 -1
- package/dist/src/device/payload.spec.d.ts +0 -2
- package/dist/src/device/payload.spec.d.ts.map +0 -1
- package/dist/src/errors.spec.d.ts +0 -2
- package/dist/src/errors.spec.d.ts.map +0 -1
- package/dist/src/framer/adapter.spec.d.ts +0 -2
- package/dist/src/framer/adapter.spec.d.ts.map +0 -1
- package/dist/src/framer/client.spec.d.ts +0 -2
- package/dist/src/framer/client.spec.d.ts.map +0 -1
- package/dist/src/framer/codec.spec.d.ts +0 -2
- package/dist/src/framer/codec.spec.d.ts.map +0 -1
- package/dist/src/framer/deleter.spec.d.ts +0 -2
- package/dist/src/framer/deleter.spec.d.ts.map +0 -1
- package/dist/src/framer/frame.spec.d.ts +0 -2
- package/dist/src/framer/frame.spec.d.ts.map +0 -1
- package/dist/src/framer/iterator.spec.d.ts +0 -2
- package/dist/src/framer/iterator.spec.d.ts.map +0 -1
- package/dist/src/framer/reader.spec.d.ts +0 -2
- package/dist/src/framer/reader.spec.d.ts.map +0 -1
- package/dist/src/framer/streamer.spec.d.ts +0 -2
- package/dist/src/framer/streamer.spec.d.ts.map +0 -1
- package/dist/src/framer/writer.spec.d.ts +0 -2
- package/dist/src/framer/writer.spec.d.ts.map +0 -1
- package/dist/src/group/access.spec.d.ts +0 -2
- package/dist/src/group/access.spec.d.ts.map +0 -1
- package/dist/src/group/group.spec.d.ts +0 -2
- package/dist/src/group/group.spec.d.ts.map +0 -1
- package/dist/src/label/access.spec.d.ts +0 -2
- package/dist/src/label/access.spec.d.ts.map +0 -1
- package/dist/src/label/label.spec.d.ts +0 -2
- package/dist/src/label/label.spec.d.ts.map +0 -1
- package/dist/src/lineplot/access.spec.d.ts +0 -2
- package/dist/src/lineplot/access.spec.d.ts.map +0 -1
- package/dist/src/lineplot/lineplot.spec.d.ts +0 -2
- package/dist/src/lineplot/lineplot.spec.d.ts.map +0 -1
- package/dist/src/log/access.spec.d.ts +0 -2
- package/dist/src/log/access.spec.d.ts.map +0 -1
- package/dist/src/log/log.spec.d.ts +0 -2
- package/dist/src/log/log.spec.d.ts.map +0 -1
- package/dist/src/ontology/ontology.spec.d.ts +0 -2
- package/dist/src/ontology/ontology.spec.d.ts.map +0 -1
- package/dist/src/rack/access.spec.d.ts +0 -2
- package/dist/src/rack/access.spec.d.ts.map +0 -1
- package/dist/src/rack/rack.spec.d.ts +0 -2
- package/dist/src/rack/rack.spec.d.ts.map +0 -1
- package/dist/src/ranger/access.spec.d.ts +0 -2
- package/dist/src/ranger/access.spec.d.ts.map +0 -1
- package/dist/src/ranger/alias/payload.spec.d.ts +0 -2
- package/dist/src/ranger/alias/payload.spec.d.ts.map +0 -1
- package/dist/src/ranger/ranger.spec.d.ts +0 -2
- package/dist/src/ranger/ranger.spec.d.ts.map +0 -1
- package/dist/src/schematic/access.spec.d.ts +0 -2
- package/dist/src/schematic/access.spec.d.ts.map +0 -1
- package/dist/src/schematic/actions.spec.d.ts +0 -2
- package/dist/src/schematic/actions.spec.d.ts.map +0 -1
- package/dist/src/schematic/schematic.spec.d.ts +0 -2
- package/dist/src/schematic/schematic.spec.d.ts.map +0 -1
- package/dist/src/schematic/symbol/access.spec.d.ts +0 -2
- package/dist/src/schematic/symbol/access.spec.d.ts.map +0 -1
- package/dist/src/schematic/symbol/client.spec.d.ts +0 -2
- package/dist/src/schematic/symbol/client.spec.d.ts.map +0 -1
- package/dist/src/status/access.spec.d.ts +0 -2
- package/dist/src/status/access.spec.d.ts.map +0 -1
- package/dist/src/status/status.spec.d.ts +0 -2
- package/dist/src/status/status.spec.d.ts.map +0 -1
- package/dist/src/table/access.spec.d.ts +0 -2
- package/dist/src/table/access.spec.d.ts.map +0 -1
- package/dist/src/table/table.spec.d.ts +0 -2
- package/dist/src/table/table.spec.d.ts.map +0 -1
- package/dist/src/task/access.spec.d.ts +0 -2
- package/dist/src/task/access.spec.d.ts.map +0 -1
- package/dist/src/task/payload.spec.d.ts +0 -2
- package/dist/src/task/payload.spec.d.ts.map +0 -1
- package/dist/src/task/task.spec.d.ts +0 -2
- package/dist/src/task/task.spec.d.ts.map +0 -1
- package/dist/src/user/access.spec.d.ts +0 -2
- package/dist/src/user/access.spec.d.ts.map +0 -1
- package/dist/src/user/user.spec.d.ts +0 -2
- package/dist/src/user/user.spec.d.ts.map +0 -1
- package/dist/src/util/retrieve.spec.d.ts +0 -2
- package/dist/src/util/retrieve.spec.d.ts.map +0 -1
- package/dist/src/view/view.spec.d.ts +0 -2
- package/dist/src/view/view.spec.d.ts.map +0 -1
- package/dist/src/workspace/access.spec.d.ts +0 -2
- package/dist/src/workspace/access.spec.d.ts.map +0 -1
- package/dist/src/workspace/client.d.ts +0 -36
- package/dist/src/workspace/client.d.ts.map +0 -1
- package/dist/src/workspace/external.d.ts.map +0 -1
- package/dist/src/workspace/index.d.ts +0 -2
- package/dist/src/workspace/index.d.ts.map +0 -1
- package/dist/src/workspace/types.gen.d.ts +0 -34
- package/dist/src/workspace/types.gen.d.ts.map +0 -1
- package/dist/src/workspace/workspace.spec.d.ts +0 -2
- package/dist/src/workspace/workspace.spec.d.ts.map +0 -1
- package/examples/node/basicReadWrite.js +0 -86
- package/examples/node/createChannels.js +0 -50
- package/examples/node/createRange.js +0 -67
- package/examples/node/package-lock.json +0 -133
- package/examples/node/package.json +0 -17
- package/examples/node/readLatest.js +0 -76
- package/examples/node/seriesAndFrames.js +0 -173
- package/examples/node/streamRead.js +0 -50
- package/examples/node/streamWrite.js +0 -87
- package/src/access/enforce.spec.ts +0 -188
- package/src/access/policy/access.spec.ts +0 -147
- package/src/access/role/role.spec.ts +0 -95
- package/src/actions/actions.spec.ts +0 -229
- package/src/arc/access.spec.ts +0 -149
- package/src/arc/arc.spec.ts +0 -44
- package/src/arc/lsp.spec.ts +0 -717
- package/src/auth/auth.spec.ts +0 -101
- package/src/channel/access.spec.ts +0 -116
- package/src/channel/batchRetriever.spec.ts +0 -115
- package/src/channel/channel.spec.ts +0 -352
- package/src/channel/payload.spec.ts +0 -117
- package/src/channel/retriever.ts +0 -252
- package/src/connection/checker.ts +0 -203
- package/src/connection/connection.spec.ts +0 -152
- package/src/connection.spec.ts +0 -145
- package/src/control/state.spec.ts +0 -22
- package/src/device/access.spec.ts +0 -159
- package/src/device/device.spec.ts +0 -461
- package/src/device/payload.spec.ts +0 -142
- package/src/errors.spec.ts +0 -71
- package/src/framer/adapter.spec.ts +0 -620
- package/src/framer/client.spec.ts +0 -180
- package/src/framer/codec.spec.ts +0 -383
- package/src/framer/deleter.spec.ts +0 -103
- package/src/framer/frame.spec.ts +0 -973
- package/src/framer/iterator.spec.ts +0 -169
- package/src/framer/reader.spec.ts +0 -865
- package/src/framer/streamer.spec.ts +0 -871
- package/src/framer/writer.spec.ts +0 -486
- package/src/group/access.spec.ts +0 -77
- package/src/group/group.spec.ts +0 -65
- package/src/label/access.spec.ts +0 -109
- package/src/label/label.spec.ts +0 -83
- package/src/lineplot/access.spec.ts +0 -134
- package/src/lineplot/lineplot.spec.ts +0 -120
- package/src/log/access.spec.ts +0 -132
- package/src/log/log.spec.ts +0 -106
- package/src/ontology/ontology.spec.ts +0 -521
- package/src/rack/access.spec.ts +0 -102
- package/src/rack/rack.spec.ts +0 -171
- package/src/ranger/access.spec.ts +0 -115
- package/src/ranger/alias/payload.spec.ts +0 -52
- package/src/ranger/ranger.spec.ts +0 -343
- package/src/schematic/access.spec.ts +0 -134
- package/src/schematic/actions.spec.ts +0 -699
- package/src/schematic/schematic.spec.ts +0 -340
- package/src/schematic/symbol/access.spec.ts +0 -172
- package/src/schematic/symbol/client.spec.ts +0 -160
- package/src/status/access.spec.ts +0 -129
- package/src/status/status.spec.ts +0 -448
- package/src/table/access.spec.ts +0 -128
- package/src/table/table.spec.ts +0 -651
- package/src/task/access.spec.ts +0 -131
- package/src/task/payload.spec.ts +0 -113
- package/src/task/task.spec.ts +0 -657
- package/src/user/access.spec.ts +0 -107
- package/src/user/user.spec.ts +0 -290
- package/src/util/retrieve.spec.ts +0 -49
- package/src/view/view.spec.ts +0 -165
- package/src/workspace/access.spec.ts +0 -108
- package/src/workspace/client.ts +0 -112
- package/src/workspace/types.gen.ts +0 -46
- package/src/workspace/workspace.spec.ts +0 -111
- package/tsconfig.json +0 -5
- package/tsconfig.vite.json +0 -4
- package/vite.config.ts +0 -29
- /package/dist/src/{workspace → project}/external.d.ts +0 -0
|
@@ -0,0 +1,442 @@
|
|
|
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 {
|
|
11
|
+
type CrudeTimeSpan,
|
|
12
|
+
deep,
|
|
13
|
+
type destructor,
|
|
14
|
+
id,
|
|
15
|
+
migrate,
|
|
16
|
+
observe,
|
|
17
|
+
TimeSpan,
|
|
18
|
+
TimeStamp,
|
|
19
|
+
} from "@synnaxlabs/x";
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
|
|
22
|
+
import { AuthError, DisconnectedError } from "@/errors";
|
|
23
|
+
import { status } from "@/status";
|
|
24
|
+
|
|
25
|
+
export const REASONS = ["unreachable", "auth", "incompatible"] as const;
|
|
26
|
+
export const reasonZ = z.enum(REASONS);
|
|
27
|
+
/** Why the connection is in the error variant. */
|
|
28
|
+
export type Reason = z.infer<typeof reasonZ>;
|
|
29
|
+
|
|
30
|
+
/** The fact vector beneath the connection's status variant. */
|
|
31
|
+
export const statusDetailsZ = z.object({
|
|
32
|
+
error: z.instanceof(Error).optional(),
|
|
33
|
+
authenticated: z.boolean(),
|
|
34
|
+
streamLive: z.boolean(),
|
|
35
|
+
// The cluster refused the change stream. Unary calls the user is allowed to
|
|
36
|
+
// make still work; live updates do not arrive.
|
|
37
|
+
streamDenied: z.boolean(),
|
|
38
|
+
epoch: z.number(),
|
|
39
|
+
clusterKey: z.string(),
|
|
40
|
+
clientVersion: z.string(),
|
|
41
|
+
nodeVersion: z.string().optional(),
|
|
42
|
+
clientServerCompatible: z.boolean(),
|
|
43
|
+
clockSkew: TimeSpan.z,
|
|
44
|
+
clockSkewExceeded: z.boolean(),
|
|
45
|
+
retry: z.object({ attempt: z.number(), nextAt: TimeStamp.z }).nullable(),
|
|
46
|
+
// A check is in flight right now. A process fact, not a judgment: the
|
|
47
|
+
// variant holds its verdict while attempts run beneath it.
|
|
48
|
+
checking: z.boolean(),
|
|
49
|
+
});
|
|
50
|
+
export interface StatusDetails extends z.infer<typeof statusDetailsZ> {}
|
|
51
|
+
|
|
52
|
+
/** Error-variant details: the same facts plus the reason the connection failed. */
|
|
53
|
+
export const errorStatusDetailsZ = statusDetailsZ.extend({ reason: reasonZ });
|
|
54
|
+
export interface ErrorStatusDetails extends z.infer<typeof errorStatusDetailsZ> {}
|
|
55
|
+
|
|
56
|
+
export const nonErrorVariantZ = z.enum([
|
|
57
|
+
"success",
|
|
58
|
+
"info",
|
|
59
|
+
"warning",
|
|
60
|
+
"loading",
|
|
61
|
+
"disabled",
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The connection status: a standard status whose details carry the connection's
|
|
66
|
+
* facts. Renders anywhere a status does, with no translation. Discriminated on
|
|
67
|
+
* variant: `reason` exists only on the error member.
|
|
68
|
+
*/
|
|
69
|
+
export const statusZ = z.discriminatedUnion("variant", [
|
|
70
|
+
status.statusZ({ v: status.errorVariantZ, details: errorStatusDetailsZ }),
|
|
71
|
+
status.statusZ({ v: nonErrorVariantZ, details: statusDetailsZ }),
|
|
72
|
+
]);
|
|
73
|
+
export type ErrorStatus = status.Status<
|
|
74
|
+
typeof errorStatusDetailsZ,
|
|
75
|
+
typeof status.errorVariantZ
|
|
76
|
+
>;
|
|
77
|
+
export type NonErrorStatus = status.Status<
|
|
78
|
+
typeof statusDetailsZ,
|
|
79
|
+
typeof nonErrorVariantZ
|
|
80
|
+
>;
|
|
81
|
+
export type Status = ErrorStatus | NonErrorStatus;
|
|
82
|
+
|
|
83
|
+
const DEFAULT_STATUS_DETAILS: StatusDetails = {
|
|
84
|
+
authenticated: false,
|
|
85
|
+
streamLive: false,
|
|
86
|
+
streamDenied: false,
|
|
87
|
+
epoch: 0,
|
|
88
|
+
clusterKey: "",
|
|
89
|
+
clientVersion: __VERSION__,
|
|
90
|
+
clientServerCompatible: false,
|
|
91
|
+
clockSkew: TimeSpan.ZERO,
|
|
92
|
+
clockSkewExceeded: false,
|
|
93
|
+
retry: null,
|
|
94
|
+
checking: false,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/** The status of a client that does not exist. */
|
|
98
|
+
export const DEFAULT_STATUS: Status = {
|
|
99
|
+
key: "connection",
|
|
100
|
+
name: "Connection",
|
|
101
|
+
variant: "disabled",
|
|
102
|
+
message: "Disconnected",
|
|
103
|
+
description: "",
|
|
104
|
+
time: TimeStamp.ZERO,
|
|
105
|
+
details: DEFAULT_STATUS_DETAILS,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/** Consecutive check failures before escalating to error(unreachable). */
|
|
109
|
+
export const DEFAULT_ESCALATE_AFTER = 4;
|
|
110
|
+
|
|
111
|
+
export interface Config {
|
|
112
|
+
clientVersion: string;
|
|
113
|
+
/** Human-readable cluster name for status messages. */
|
|
114
|
+
name?: string;
|
|
115
|
+
escalateAfter: number;
|
|
116
|
+
clockSkewThreshold: TimeSpan;
|
|
117
|
+
/** Whether success requires a live change stream. */
|
|
118
|
+
requiresStream: boolean;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* The consumer-facing view of a client's connection. Read {@link Handle.status}
|
|
123
|
+
* or subscribe via {@link Handle.onChange}; the client owns every transition.
|
|
124
|
+
*/
|
|
125
|
+
export interface Handle {
|
|
126
|
+
/** The current connection status. */
|
|
127
|
+
readonly status: Status;
|
|
128
|
+
/** Subscribes to status changes. Returns a destructor that unsubscribes. */
|
|
129
|
+
onChange: (callback: (status: Status) => void) => destructor.Destructor;
|
|
130
|
+
/**
|
|
131
|
+
* Resets the retry backoff and checks immediately. Auth and incompatibility
|
|
132
|
+
* errors are not cleared: those rest until the user supplies something new.
|
|
133
|
+
*/
|
|
134
|
+
retryNow: () => void;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const isSettled = ({ variant }: Status): boolean =>
|
|
138
|
+
variant === "success" ||
|
|
139
|
+
variant === "warning" ||
|
|
140
|
+
variant === "error" ||
|
|
141
|
+
variant === "disabled";
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Resolves once the connection is usable: success, or warning when the cluster
|
|
145
|
+
* refuses live updates. Rejects with the stored failure when it settles on an
|
|
146
|
+
* error variant or is closed. The current status is evaluated first, so an
|
|
147
|
+
* already-connected handle resolves without waiting.
|
|
148
|
+
* @throws {Error} if the timeout elapses first.
|
|
149
|
+
*/
|
|
150
|
+
export const awaitConnected = async (
|
|
151
|
+
handle: Handle,
|
|
152
|
+
timeout?: CrudeTimeSpan,
|
|
153
|
+
): Promise<Status> => {
|
|
154
|
+
const settled = await observe.until(handle, () => handle.status, isSettled, timeout);
|
|
155
|
+
if (settled.variant !== "success" && settled.variant !== "warning")
|
|
156
|
+
throw settled.details.error ?? new DisconnectedError(settled.message);
|
|
157
|
+
return settled;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/** The facts a single connectivity check yields. */
|
|
161
|
+
export interface Info {
|
|
162
|
+
clusterKey: string;
|
|
163
|
+
nodeVersion: string;
|
|
164
|
+
/** Skew measured across the check's round trip. */
|
|
165
|
+
clockSkew: TimeSpan;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Everything that can move the connection status. The client is the only
|
|
170
|
+
* producer: check and retry events come from its own loop, the rest arrive as
|
|
171
|
+
* outside facts through its notify inbox.
|
|
172
|
+
*/
|
|
173
|
+
export type Event =
|
|
174
|
+
| { type: "check.started" }
|
|
175
|
+
| { type: "check.success"; info: Info }
|
|
176
|
+
| { type: "check.failure"; error: Error; attempt: number }
|
|
177
|
+
| { type: "stream.live" }
|
|
178
|
+
| { type: "stream.drop"; error?: Error }
|
|
179
|
+
| { type: "stream.denied"; error?: Error }
|
|
180
|
+
| { type: "auth.success" }
|
|
181
|
+
| { type: "auth.failure"; error: Error }
|
|
182
|
+
| { type: "epoch.advanced"; epoch: number }
|
|
183
|
+
| { type: "retry.scheduled"; attempt: number; nextAt: TimeStamp }
|
|
184
|
+
| { type: "retry.exhausted" }
|
|
185
|
+
| { type: "retry.requested" }
|
|
186
|
+
| { type: "credentials.replaced" }
|
|
187
|
+
| { type: "closed" };
|
|
188
|
+
|
|
189
|
+
const CONNECTING = "Connecting";
|
|
190
|
+
const RECONNECTING = "Reconnecting";
|
|
191
|
+
const UNREACHABLE = "Cannot reach cluster";
|
|
192
|
+
const STREAM_DENIED =
|
|
193
|
+
"Live updates are unavailable. This user cannot read the change channels.";
|
|
194
|
+
|
|
195
|
+
const connectedMessage = ({ name }: Config): string =>
|
|
196
|
+
`Connected to ${name ?? "cluster"}`;
|
|
197
|
+
|
|
198
|
+
/** The status a freshly constructed client starts in. */
|
|
199
|
+
export const createInitialStatus = (config: Config): Status => ({
|
|
200
|
+
...DEFAULT_STATUS,
|
|
201
|
+
key: id.create(),
|
|
202
|
+
name: config.name ?? DEFAULT_STATUS.name,
|
|
203
|
+
time: TimeStamp.now(),
|
|
204
|
+
variant: "loading",
|
|
205
|
+
message: `Connecting to ${config.name ?? "cluster"}`,
|
|
206
|
+
details: { ...DEFAULT_STATUS_DETAILS, clientVersion: config.clientVersion },
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Merges facts without touching variant or reason, so the union member holds.
|
|
210
|
+
const update = <S extends Status>(prev: S, details: Partial<StatusDetails>): S => ({
|
|
211
|
+
...prev,
|
|
212
|
+
details: { ...prev.details, ...details },
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
/** Moves to a non-error variant, structurally dropping any parked reason. */
|
|
216
|
+
const enter = (
|
|
217
|
+
prev: Status,
|
|
218
|
+
variant: Exclude<status.Variant, "error">,
|
|
219
|
+
message: string,
|
|
220
|
+
details: Partial<StatusDetails> = {},
|
|
221
|
+
description: string = "",
|
|
222
|
+
): NonErrorStatus => {
|
|
223
|
+
const { reason: _, ...merged }: StatusDetails & { reason?: Reason } = {
|
|
224
|
+
...prev.details,
|
|
225
|
+
...details,
|
|
226
|
+
};
|
|
227
|
+
return { ...prev, variant, message, description, details: merged };
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const enterError = (
|
|
231
|
+
prev: Status,
|
|
232
|
+
message: string,
|
|
233
|
+
reason: Reason,
|
|
234
|
+
details: Partial<StatusDetails> = {},
|
|
235
|
+
): ErrorStatus => ({
|
|
236
|
+
...prev,
|
|
237
|
+
variant: "error",
|
|
238
|
+
message,
|
|
239
|
+
description: "",
|
|
240
|
+
details: { ...prev.details, ...details, reason },
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
const isCompatible = (nodeVersion: string, clientVersion: string): boolean =>
|
|
244
|
+
migrate.versionsEqual(clientVersion, nodeVersion, {
|
|
245
|
+
checkMajor: true,
|
|
246
|
+
checkMinor: true,
|
|
247
|
+
checkPatch: false,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const checkFacts = (info: Info, config: Config): Partial<StatusDetails> => ({
|
|
251
|
+
clusterKey: info.clusterKey,
|
|
252
|
+
nodeVersion: info.nodeVersion,
|
|
253
|
+
// the check traverses the auth middleware, so a response is proof of auth
|
|
254
|
+
authenticated: true,
|
|
255
|
+
clockSkew: info.clockSkew,
|
|
256
|
+
clockSkewExceeded: info.clockSkew.abs().greaterThan(config.clockSkewThreshold),
|
|
257
|
+
clientServerCompatible: isCompatible(info.nodeVersion, config.clientVersion),
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Connected, with live updates refused. A settled outcome: only a policy
|
|
261
|
+
// change lifts it, so the machine rests here instead of chasing the stream.
|
|
262
|
+
const enterStreamDenied = (
|
|
263
|
+
prev: Status,
|
|
264
|
+
config: Config,
|
|
265
|
+
details: Partial<StatusDetails> = {},
|
|
266
|
+
): Status =>
|
|
267
|
+
enter(
|
|
268
|
+
prev,
|
|
269
|
+
"warning",
|
|
270
|
+
connectedMessage(config),
|
|
271
|
+
{
|
|
272
|
+
...details,
|
|
273
|
+
streamDenied: true,
|
|
274
|
+
streamLive: false,
|
|
275
|
+
error: undefined,
|
|
276
|
+
retry: null,
|
|
277
|
+
},
|
|
278
|
+
STREAM_DENIED,
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
const reduceCheckSuccess = (prev: Status, info: Info, config: Config): Status => {
|
|
282
|
+
const { clusterKey } = prev.details;
|
|
283
|
+
if (clusterKey !== "" && info.clusterKey !== clusterKey)
|
|
284
|
+
return reduceClusterReplaced(prev, info, config);
|
|
285
|
+
const facts = checkFacts(info, config);
|
|
286
|
+
// reachable but the stream is still dark: the client re-demands it and we
|
|
287
|
+
// stay degraded until it reports live. A parked unreachable error must
|
|
288
|
+
// lift out of error: the short circuit it drives would starve the very
|
|
289
|
+
// stream reopen this state waits on.
|
|
290
|
+
if (config.requiresStream && !prev.details.streamLive) {
|
|
291
|
+
if (prev.details.streamDenied) return enterStreamDenied(prev, config, facts);
|
|
292
|
+
if (prev.variant === "error" && prev.details.reason === "unreachable")
|
|
293
|
+
return enter(prev, "loading", RECONNECTING, {
|
|
294
|
+
...facts,
|
|
295
|
+
error: undefined,
|
|
296
|
+
retry: null,
|
|
297
|
+
});
|
|
298
|
+
return update(prev, facts);
|
|
299
|
+
}
|
|
300
|
+
if (prev.variant === "success") return update(prev, { ...facts, retry: null });
|
|
301
|
+
return enter(prev, "success", connectedMessage(config), {
|
|
302
|
+
...facts,
|
|
303
|
+
error: undefined,
|
|
304
|
+
retry: null,
|
|
305
|
+
});
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
// The cluster answering the check is not the one previously contacted.
|
|
309
|
+
// Everything learned from the old cluster is void, so the machine returns to
|
|
310
|
+
// first contact: loading at epoch 0 with a dark stream.
|
|
311
|
+
const reduceClusterReplaced = (prev: Status, info: Info, config: Config): Status =>
|
|
312
|
+
enter(prev, "loading", `Connecting to ${config.name ?? "cluster"}`, {
|
|
313
|
+
...checkFacts(info, config),
|
|
314
|
+
streamLive: false,
|
|
315
|
+
streamDenied: false,
|
|
316
|
+
epoch: 0,
|
|
317
|
+
error: undefined,
|
|
318
|
+
retry: null,
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
const reduceAuthFailure = (prev: Status, error: Error): Status =>
|
|
322
|
+
enterError(prev, error.message, "auth", {
|
|
323
|
+
error,
|
|
324
|
+
authenticated: false,
|
|
325
|
+
retry: null,
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
const reduceCheckFailure = (
|
|
329
|
+
prev: Status,
|
|
330
|
+
error: Error,
|
|
331
|
+
attempt: number,
|
|
332
|
+
config: Config,
|
|
333
|
+
): Status => {
|
|
334
|
+
if (AuthError.matches(error)) return reduceAuthFailure(prev, error);
|
|
335
|
+
const escalating = prev.variant === "loading";
|
|
336
|
+
if (escalating && attempt >= config.escalateAfter)
|
|
337
|
+
return enterError(prev, error.message ?? UNREACHABLE, "unreachable", { error });
|
|
338
|
+
if (prev.variant === "success")
|
|
339
|
+
return enter(prev, "loading", RECONNECTING, { error });
|
|
340
|
+
return update(prev, { error });
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
const reduceStreamLive = (prev: Status, config: Config): Status => {
|
|
344
|
+
const parked = prev.variant === "error" && prev.details.reason !== "unreachable";
|
|
345
|
+
if (parked) return update(prev, { streamLive: true, streamDenied: false });
|
|
346
|
+
return enter(prev, "success", connectedMessage(config), {
|
|
347
|
+
streamLive: true,
|
|
348
|
+
streamDenied: false,
|
|
349
|
+
error: undefined,
|
|
350
|
+
retry: null,
|
|
351
|
+
});
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const reduceStreamDrop = (prev: Status, error?: Error): Status => {
|
|
355
|
+
if (prev.variant !== "success") return update(prev, { streamLive: false });
|
|
356
|
+
return enter(prev, "loading", RECONNECTING, { streamLive: false, error });
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
const reduceRetryExhausted = (prev: Status): Status => {
|
|
360
|
+
if (prev.variant !== "loading") return update(prev, { retry: null });
|
|
361
|
+
return enterError(prev, prev.details.error?.message ?? UNREACHABLE, "unreachable", {
|
|
362
|
+
retry: null,
|
|
363
|
+
});
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Folds an event into the connection status. Pure: every transition in the
|
|
368
|
+
* lifecycle lives here and nowhere else. `disabled` is terminal.
|
|
369
|
+
*/
|
|
370
|
+
export const reduce = (prev: Status, event: Event, config: Config): Status => {
|
|
371
|
+
if (prev.variant === "disabled") return prev;
|
|
372
|
+
switch (event.type) {
|
|
373
|
+
case "check.started":
|
|
374
|
+
return update(prev, { checking: true });
|
|
375
|
+
case "check.success":
|
|
376
|
+
return update(reduceCheckSuccess(prev, event.info, config), { checking: false });
|
|
377
|
+
case "check.failure":
|
|
378
|
+
return update(reduceCheckFailure(prev, event.error, event.attempt, config), {
|
|
379
|
+
checking: false,
|
|
380
|
+
});
|
|
381
|
+
case "stream.live":
|
|
382
|
+
return reduceStreamLive(prev, config);
|
|
383
|
+
case "stream.drop":
|
|
384
|
+
return reduceStreamDrop(prev, event.error);
|
|
385
|
+
case "stream.denied":
|
|
386
|
+
return enterStreamDenied(prev, config);
|
|
387
|
+
case "auth.success":
|
|
388
|
+
return update(prev, { authenticated: true });
|
|
389
|
+
case "auth.failure":
|
|
390
|
+
return reduceAuthFailure(prev, event.error);
|
|
391
|
+
case "epoch.advanced":
|
|
392
|
+
return update(prev, { epoch: event.epoch });
|
|
393
|
+
case "retry.scheduled":
|
|
394
|
+
return update(prev, { retry: { attempt: event.attempt, nextAt: event.nextAt } });
|
|
395
|
+
case "retry.exhausted":
|
|
396
|
+
return reduceRetryExhausted(prev);
|
|
397
|
+
case "retry.requested":
|
|
398
|
+
// deliberately does not clear auth or incompatibility: those rest until
|
|
399
|
+
// the user supplies something new
|
|
400
|
+
if (prev.variant !== "error" || prev.details.reason !== "unreachable")
|
|
401
|
+
return prev;
|
|
402
|
+
return enter(prev, "loading", CONNECTING);
|
|
403
|
+
case "credentials.replaced":
|
|
404
|
+
// the new user may hold the permissions the old one lacked
|
|
405
|
+
return enter(prev, "loading", CONNECTING, {
|
|
406
|
+
error: undefined,
|
|
407
|
+
streamDenied: false,
|
|
408
|
+
});
|
|
409
|
+
case "closed":
|
|
410
|
+
return enter(prev, "disabled", "Closed", {
|
|
411
|
+
streamLive: false,
|
|
412
|
+
retry: null,
|
|
413
|
+
checking: false,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
// Fields that legitimately churn without meaning anything: the stamp moves on
|
|
419
|
+
// every advance and raw skew jitters on every successful check. Everything
|
|
420
|
+
// else is material, so new fields notify by default.
|
|
421
|
+
const comparable = ({ time: _, ...rest }: Status): unknown => ({
|
|
422
|
+
...rest,
|
|
423
|
+
details: { ...rest.details, clockSkew: undefined },
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
/** Whether the change is worth notifying observers about. */
|
|
427
|
+
export const materialChange = (prev: Status, next: Status): boolean =>
|
|
428
|
+
!deep.equal(comparable(prev), comparable(next));
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Folds the event and stamps the status time when the result is worth publishing.
|
|
432
|
+
* @returns the next status and whether observers should be notified.
|
|
433
|
+
*/
|
|
434
|
+
export const advance = (
|
|
435
|
+
prev: Status,
|
|
436
|
+
event: Event,
|
|
437
|
+
config: Config,
|
|
438
|
+
): [Status, boolean] => {
|
|
439
|
+
const next = reduce(prev, event, config);
|
|
440
|
+
if (!materialChange(prev, next)) return [next, false];
|
|
441
|
+
return [{ ...next, time: TimeStamp.now() }, true];
|
|
442
|
+
};
|
package/src/control/client.ts
CHANGED
|
@@ -7,23 +7,95 @@
|
|
|
7
7
|
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { type UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
+
import { z } from "zod";
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
import { type channel } from "@/channel";
|
|
14
|
+
import { keyZ } from "@/channel/types.gen";
|
|
15
|
+
import { type KeyedState, keyedStateZ, updateZ } from "@/control/state";
|
|
16
|
+
import { query } from "@/query";
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
/** The free virtual channel carrying control updates for the entire cluster. */
|
|
19
|
+
const CHANNEL_NAME = "sy_control";
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
const RETRIEVE_ENDPOINT = "/control/retrieve";
|
|
22
|
+
|
|
23
|
+
const retrieveRequestZ = z.object({ keys: keyZ.array().optional() });
|
|
24
|
+
const retrieveMultiParamsZ = retrieveRequestZ.or(query.keyListZ(keyZ));
|
|
25
|
+
const retrieveResZ = z.object({ states: keyedStateZ.array().default(() => []) });
|
|
26
|
+
|
|
27
|
+
export type RetrieveMultipleParams = z.input<typeof retrieveRequestZ>;
|
|
28
|
+
|
|
29
|
+
interface RetrieveRequest extends z.infer<typeof retrieveRequestZ> {}
|
|
30
|
+
|
|
31
|
+
export interface ClientConfig {
|
|
32
|
+
unary: UnaryClient;
|
|
33
|
+
cache: query.Cache;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Reads the control state of channels across the cluster. A channel is in the table
|
|
38
|
+
* exactly while a subject holds it, so absence is the uncontrolled state: a release
|
|
39
|
+
* deletes the entry instead of storing a sentinel.
|
|
40
|
+
*/
|
|
41
|
+
export class Client extends query.Retriever<
|
|
42
|
+
typeof retrieveMultiParamsZ,
|
|
43
|
+
channel.Key,
|
|
44
|
+
KeyedState
|
|
45
|
+
> {
|
|
46
|
+
readonly type: string = "control";
|
|
47
|
+
/** The control state table, keyed by the channel under control. */
|
|
48
|
+
readonly store: query.Table<channel.Key, KeyedState>;
|
|
49
|
+
private readonly cfg: ClientConfig;
|
|
50
|
+
|
|
51
|
+
constructor(cfg: ClientConfig) {
|
|
52
|
+
const store = cfg.cache.createTable<channel.Key, KeyedState>({
|
|
53
|
+
name: "control",
|
|
54
|
+
fetch: async (keys) => await this.execRetrieve({ keys }),
|
|
55
|
+
listen: [transferListener()],
|
|
56
|
+
});
|
|
57
|
+
super(cfg.cache, {
|
|
58
|
+
name: "control",
|
|
59
|
+
table: store,
|
|
60
|
+
request: {
|
|
61
|
+
schema: retrieveMultiParamsZ,
|
|
62
|
+
fetch: async (req) => await this.execRetrieve(req),
|
|
63
|
+
matches: (state, req) => req.keys == null || req.keys.includes(state.key),
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
this.cfg = cfg;
|
|
67
|
+
this.store = store;
|
|
20
68
|
}
|
|
21
69
|
|
|
22
|
-
async
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
70
|
+
private async execRetrieve(req: RetrieveRequest): Promise<KeyedState[]> {
|
|
71
|
+
// An empty key set reads the whole cluster, so it must not reach the Core here.
|
|
72
|
+
if (req.keys != null && req.keys.length === 0) return [];
|
|
73
|
+
const { states } = await this.cfg.unary.send(
|
|
74
|
+
RETRIEVE_ENDPOINT,
|
|
75
|
+
{ keys: req.keys ?? [] },
|
|
76
|
+
retrieveRequestZ,
|
|
77
|
+
retrieveResZ,
|
|
26
78
|
);
|
|
27
|
-
return
|
|
79
|
+
return states;
|
|
28
80
|
}
|
|
29
81
|
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Mirrors the cluster's control transfers into the table: the `to` end of a transfer
|
|
85
|
+
* sets the channel's holder, and a transfer without one deletes the entry.
|
|
86
|
+
*/
|
|
87
|
+
const transferListener = (): query.ListenerSpec<channel.Key, KeyedState> => ({
|
|
88
|
+
bind: (table): query.Listener<typeof updateZ> => ({
|
|
89
|
+
channel: CHANNEL_NAME,
|
|
90
|
+
schema: updateZ,
|
|
91
|
+
onChange: (updates) =>
|
|
92
|
+
table.batch(() =>
|
|
93
|
+
updates
|
|
94
|
+
.flatMap((u) => u.transfers)
|
|
95
|
+
.forEach(({ from, to }) => {
|
|
96
|
+
if (to == null) table.delete(from.resource);
|
|
97
|
+
else table.set({ key: to.resource, ...to });
|
|
98
|
+
}),
|
|
99
|
+
),
|
|
100
|
+
}),
|
|
101
|
+
});
|
package/src/control/state.ts
CHANGED
|
@@ -7,21 +7,35 @@
|
|
|
7
7
|
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { control } from "@synnaxlabs/x";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
13
|
import { type channel } from "@/channel";
|
|
14
14
|
import { keyZ } from "@/channel/types.gen";
|
|
15
|
-
import { framer } from "@/framer";
|
|
16
15
|
|
|
16
|
+
/** How strongly a writer claims a channel. The highest authority holds control. */
|
|
17
17
|
export type Authority = control.Authority;
|
|
18
|
+
/** The highest authority. A writer holding it cannot be displaced. */
|
|
18
19
|
export const ABSOLUTE_AUTHORITY = control.ABSOLUTE_AUTHORITY;
|
|
20
|
+
/** The lowest authority. Any other writer displaces it. */
|
|
19
21
|
export const ZERO_AUTHORITY = control.ZERO_AUTHORITY;
|
|
22
|
+
/** Control of one channel moving between writers, or being released. */
|
|
20
23
|
export type Transfer = control.Transfer<typeof channel.keyZ>;
|
|
24
|
+
/** Who holds control of a channel, and at what authority. */
|
|
21
25
|
export interface State extends control.State<typeof channel.keyZ> {}
|
|
26
|
+
/** A named party that can hold control. */
|
|
22
27
|
export interface Subject extends control.Subject {}
|
|
28
|
+
/** Zod schema for {@link State}. */
|
|
23
29
|
export const stateZ = control.stateZ(z.number());
|
|
24
30
|
|
|
31
|
+
/**
|
|
32
|
+
* A control state stored under the channel it controls, which is how the client caches
|
|
33
|
+
* it.
|
|
34
|
+
*/
|
|
35
|
+
export const keyedStateZ = stateZ.transform((s) => ({ key: s.resource, ...s }));
|
|
36
|
+
export interface KeyedState extends z.infer<typeof keyedStateZ> {}
|
|
37
|
+
|
|
38
|
+
/** Renders a {@link Transfer} as readable text, for logs and status messages. */
|
|
25
39
|
export const transferString = (t: Transfer): string => {
|
|
26
40
|
const fromResource = t.from?.resource;
|
|
27
41
|
const toResource = t.to?.resource;
|
|
@@ -35,41 +49,8 @@ export const transferString = (t: Transfer): string => {
|
|
|
35
49
|
} (${t.to.authority.toString()})`;
|
|
36
50
|
};
|
|
37
51
|
|
|
38
|
-
const updateZ = z.object({
|
|
52
|
+
export const updateZ = z.object({
|
|
39
53
|
transfers: z.array(control.transferZ(keyZ)),
|
|
40
54
|
});
|
|
41
55
|
|
|
42
56
|
export interface Update extends z.infer<typeof updateZ> {}
|
|
43
|
-
|
|
44
|
-
export class StateTracker
|
|
45
|
-
extends framer.ObservableStreamer<Transfer[]>
|
|
46
|
-
implements observe.ObservableAsyncCloseable<Transfer[]>
|
|
47
|
-
{
|
|
48
|
-
readonly states: Map<channel.Key, State>;
|
|
49
|
-
private readonly codec: binary.JSONCodec;
|
|
50
|
-
|
|
51
|
-
constructor(streamer: framer.Streamer) {
|
|
52
|
-
super(streamer, (frame) => {
|
|
53
|
-
const raw = Array.from(frame.series[0].as("string"));
|
|
54
|
-
const updates: Update[] = raw.map((r) => this.codec.decodeString(r, updateZ));
|
|
55
|
-
updates.forEach((u) => this.merge(u));
|
|
56
|
-
return [updates.flatMap((u) => u.transfers), true];
|
|
57
|
-
});
|
|
58
|
-
this.states = new Map();
|
|
59
|
-
this.codec = new binary.JSONCodec();
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
subjects(): Subject[] {
|
|
63
|
-
const subjects = new Map<string, Subject>();
|
|
64
|
-
this.states.forEach((s) => subjects.set(s.subject.key, s.subject));
|
|
65
|
-
return Array.from(subjects.values());
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
private merge(update: Update): void {
|
|
69
|
-
update.transfers.forEach((t) => {
|
|
70
|
-
if (t.from == null && t.to == null) console.warn("Invalid transfer: ", t);
|
|
71
|
-
if (t.to == null) this.states.delete(t.from.resource);
|
|
72
|
-
else this.states.set(t.to.resource, t.to);
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
}
|