@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
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
// Code generated by Oracle. DO NOT EDIT.
|
|
11
11
|
|
|
12
|
+
import { uuid } from "@synnaxlabs/x";
|
|
12
13
|
import { z } from "zod";
|
|
13
14
|
|
|
14
15
|
import { ontology } from "@/ontology";
|
|
@@ -18,29 +19,24 @@ export type Key = z.infer<typeof keyZ>;
|
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Role is a named collection of policies that can be assigned to users, enabling
|
|
21
|
-
* group-based permission management. Roles define what actions users can
|
|
22
|
-
*
|
|
22
|
+
* group-based permission management. Roles define what actions users can perform on
|
|
23
|
+
* resources.
|
|
23
24
|
*/
|
|
24
25
|
export const roleZ = z.object({
|
|
25
26
|
/** key is the unique identifier for this role. */
|
|
26
|
-
key: keyZ,
|
|
27
|
-
/**
|
|
28
|
-
* name is a human-readable name for the role (e.g., 'Administrator',
|
|
29
|
-
* 'Engineer').
|
|
30
|
-
*/
|
|
27
|
+
key: keyZ.default(uuid.create),
|
|
28
|
+
/** name is a human-readable name for the role (e.g., 'Administrator', 'Engineer'). */
|
|
31
29
|
name: z.string(),
|
|
32
30
|
/**
|
|
33
31
|
* description is an optional description explaining what permissions the role
|
|
34
32
|
* provides.
|
|
35
33
|
*/
|
|
36
|
-
description: z.string().
|
|
34
|
+
description: z.string().default(""),
|
|
37
35
|
/** internal is true if this is a built-in system role that cannot be deleted. */
|
|
38
|
-
internal: z.boolean().
|
|
36
|
+
internal: z.boolean().default(false),
|
|
39
37
|
});
|
|
40
38
|
export interface Role extends z.infer<typeof roleZ> {}
|
|
41
|
-
|
|
42
|
-
export const newZ = roleZ.partial({ key: true });
|
|
43
|
-
export interface New extends z.input<typeof newZ> {}
|
|
39
|
+
export interface New extends z.input<typeof roleZ> {}
|
|
44
40
|
|
|
45
41
|
export const ontologyID = ontology.createIDFactory<Key>("role");
|
|
46
42
|
export const TYPE_ONTOLOGY_ID = ontologyID("");
|
package/src/actions/actions.ts
CHANGED
|
@@ -40,12 +40,11 @@ export interface ReduceAllResult<S, A> {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
* Returns a plain-object snapshot of an Immer draft so the result is safe to
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* crash if it called `current` unconditionally.
|
|
43
|
+
* Returns a plain-object snapshot of an Immer draft so the result is safe to embed in
|
|
44
|
+
* an action stored on the undo stack. Returns non-draft inputs unchanged. The non-draft
|
|
45
|
+
* passthrough exists because when a reducer applies multiple actions in one produce(),
|
|
46
|
+
* an earlier action's wholesale assignment leaves the slot as a plain object, so the
|
|
47
|
+
* next action would crash if it called `current` unconditionally.
|
|
49
48
|
*/
|
|
50
49
|
export const snapshotDraft = <T>(v: T): T => (isDraft(v) ? current(v as Draft<T>) : v);
|
|
51
50
|
|
|
@@ -0,0 +1,626 @@
|
|
|
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
|
+
compare,
|
|
12
|
+
destructor,
|
|
13
|
+
errors,
|
|
14
|
+
id,
|
|
15
|
+
type record,
|
|
16
|
+
TimeSpan,
|
|
17
|
+
TimeStamp,
|
|
18
|
+
} from "@synnaxlabs/x";
|
|
19
|
+
import type z from "zod";
|
|
20
|
+
|
|
21
|
+
import { type query } from "@/query";
|
|
22
|
+
import { Table } from "@/query/table";
|
|
23
|
+
|
|
24
|
+
const DEFAULT_COALESCE_WINDOW = TimeSpan.milliseconds(500);
|
|
25
|
+
const DEFAULT_STACK_CAP = 200;
|
|
26
|
+
const STALE_AUTO_ADVANCE_CAP = 10;
|
|
27
|
+
|
|
28
|
+
export interface StackEntry<Action> {
|
|
29
|
+
forward: Action[];
|
|
30
|
+
inverse: Action[];
|
|
31
|
+
kind: string;
|
|
32
|
+
/** Wall-clock push time, used only for coalescing. */
|
|
33
|
+
ts: TimeStamp;
|
|
34
|
+
/** Tick of the earliest push, used to order the entry against remote touches. */
|
|
35
|
+
tick: number;
|
|
36
|
+
targets: readonly string[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface UndoState<Action> {
|
|
40
|
+
undo: StackEntry<Action>[];
|
|
41
|
+
redo: StackEntry<Action>[];
|
|
42
|
+
remoteTouched: Record<string, number>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const ZERO_UNDO = <A>(): UndoState<A> => ({ undo: [], redo: [], remoteTouched: {} });
|
|
46
|
+
|
|
47
|
+
const pushOnto = <A>(
|
|
48
|
+
stack: StackEntry<A>[],
|
|
49
|
+
next: StackEntry<A>,
|
|
50
|
+
window: TimeSpan,
|
|
51
|
+
cap: number,
|
|
52
|
+
): StackEntry<A>[] => {
|
|
53
|
+
const top = stack[stack.length - 1];
|
|
54
|
+
const merged =
|
|
55
|
+
top != null &&
|
|
56
|
+
top.kind === next.kind &&
|
|
57
|
+
next.ts.span(top.ts).lessThanOrEqual(window) &&
|
|
58
|
+
compare.unorderedPrimitiveArrays(top.targets, next.targets) === compare.EQUAL
|
|
59
|
+
? {
|
|
60
|
+
forward: [...top.forward, ...next.forward],
|
|
61
|
+
inverse: [...next.inverse, ...top.inverse],
|
|
62
|
+
kind: next.kind,
|
|
63
|
+
ts: next.ts,
|
|
64
|
+
tick: top.tick,
|
|
65
|
+
targets: top.targets,
|
|
66
|
+
}
|
|
67
|
+
: null;
|
|
68
|
+
const out = merged != null ? [...stack.slice(0, -1), merged] : [...stack, next];
|
|
69
|
+
return out.length > cap ? out.slice(out.length - cap) : out;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export interface Reducer<State extends query.Data, Action> {
|
|
73
|
+
(
|
|
74
|
+
state: State,
|
|
75
|
+
actions: Action[],
|
|
76
|
+
): { next: State; inverse: Action[]; targets: readonly string[] };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Result of replaying a set of actions locally. The caller commits the
|
|
80
|
+
* matching server send and runs `rollback` on failure. */
|
|
81
|
+
export interface ReplayResult<Action> {
|
|
82
|
+
processed: Action[];
|
|
83
|
+
inverse: Action[];
|
|
84
|
+
targets: readonly string[];
|
|
85
|
+
// changed reports whether the replay produced a different state. Reducers
|
|
86
|
+
// return the input state by reference when no action touched it, so a false
|
|
87
|
+
// value means the entire vector was a no-op and need not reach the server.
|
|
88
|
+
changed: boolean;
|
|
89
|
+
rollback: destructor.Destructor;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Result of preparing to undo or redo. The caller applies `actions` and runs
|
|
93
|
+
* `commit` on success (which itself returns a destructor for failure-rollback). */
|
|
94
|
+
export interface Reversal<Action> {
|
|
95
|
+
actions: Action[];
|
|
96
|
+
commit: () => destructor.Destructor;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* A staged set of dispatches committed atomically as one undoable. Commit
|
|
101
|
+
* resolves false when there is nothing to send; a send failure rolls back the
|
|
102
|
+
* staged state and rethrows.
|
|
103
|
+
*/
|
|
104
|
+
export interface Transaction<Action> {
|
|
105
|
+
add: (actions: Action | Action[]) => void;
|
|
106
|
+
commit: () => Promise<boolean>;
|
|
107
|
+
abort: () => void;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Sends an already-processed action list to the server. Supplied by the
|
|
111
|
+
* caller so the controller stays free of network concerns. */
|
|
112
|
+
export type Send<Action> = (actions: Action[]) => Promise<void>;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Network send used by the dispatch/undo/redo loops. Receives the
|
|
116
|
+
* controller-generated dispatch key that was registered as outstanding before
|
|
117
|
+
* the call, so the broadcast echo is recognized as own.
|
|
118
|
+
*/
|
|
119
|
+
export type SendDispatch<Action> = (
|
|
120
|
+
actions: Action[],
|
|
121
|
+
dispatchKey: string,
|
|
122
|
+
) => Promise<void>;
|
|
123
|
+
|
|
124
|
+
/** Rewrites an action batch against the current document before replay. */
|
|
125
|
+
export type Preprocess<State, Action> = (state: State, actions: Action[]) => Action[];
|
|
126
|
+
|
|
127
|
+
/** Options accepted by domain-client dispatch methods. */
|
|
128
|
+
export interface Options<State, Action> {
|
|
129
|
+
/**
|
|
130
|
+
* Per-call action rewrite requiring caller context the domain client lacks
|
|
131
|
+
* (e.g. diagram geometry). Runs against the cached doc before replay.
|
|
132
|
+
*/
|
|
133
|
+
preprocess?: Preprocess<State, Action>;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** The action-dispatch surface a document domain client exposes. */
|
|
137
|
+
export interface Domain<Key extends record.Key, State extends query.Data, Action> {
|
|
138
|
+
dispatch(
|
|
139
|
+
key: Key,
|
|
140
|
+
actions: Action | Action[],
|
|
141
|
+
opts?: Options<State, Action>,
|
|
142
|
+
): Promise<boolean>;
|
|
143
|
+
undo(key: Key): Promise<boolean>;
|
|
144
|
+
redo(key: Key): Promise<boolean>;
|
|
145
|
+
hasUndo(key: Key): boolean;
|
|
146
|
+
hasRedo(key: Key): boolean;
|
|
147
|
+
onUndoStateChange(callback: () => void, key?: Key): destructor.Destructor;
|
|
148
|
+
beginTransaction(key: Key, kind?: string): Transaction<Action>;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* The canonical wire shape for a broadcast action frame. The consumer's `schema` must
|
|
153
|
+
* produce this shape (use a zod transform if the server emits differently-named
|
|
154
|
+
* fields). `seq` is a per-key monotonic sequence stamped by the originating server node
|
|
155
|
+
* and is used to skip echoes that are stale relative to the high-water mark — see
|
|
156
|
+
* `applyRemote`. `dispatchKey` is the client-generated batch identifier the originator
|
|
157
|
+
* registered as outstanding before sending; it is used to recognize own echoes
|
|
158
|
+
* race-safely so a redundant reduce can be skipped when no foreign action interleaved.
|
|
159
|
+
*/
|
|
160
|
+
export interface Frame<Key, Action> {
|
|
161
|
+
key: Key;
|
|
162
|
+
dispatchKey: string;
|
|
163
|
+
seq: number;
|
|
164
|
+
actions: Action[];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface ControllerParams<
|
|
168
|
+
Key extends record.Key,
|
|
169
|
+
State extends query.Data,
|
|
170
|
+
Action,
|
|
171
|
+
> {
|
|
172
|
+
/** The table holding the documents this controller dispatches over. */
|
|
173
|
+
store: Table<Key, State>;
|
|
174
|
+
/** Reports listener errors that have no caller to throw to. */
|
|
175
|
+
onError: (error: Error) => void;
|
|
176
|
+
reduce: Reducer<State, Action>;
|
|
177
|
+
preprocess?: (state: State, actions: Action[]) => Action[];
|
|
178
|
+
isUndoable?: (action: Action) => boolean;
|
|
179
|
+
kindOf?: (actions: Action[]) => string;
|
|
180
|
+
/**
|
|
181
|
+
* Returns the document carried by a create action, undefined otherwise.
|
|
182
|
+
* Lets remote frames for never-cached documents ingest instead of drop.
|
|
183
|
+
*/
|
|
184
|
+
createOf?: (action: Action) => State | undefined;
|
|
185
|
+
coalesceWindow?: TimeSpan;
|
|
186
|
+
stackCap?: number;
|
|
187
|
+
/** Clock stamping entries for the coalesce window. Defaults to TimeStamp.now. */
|
|
188
|
+
now?: () => TimeStamp;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Owns the action-dispatch loop for one document table: local replay with
|
|
193
|
+
* rollback, per-doc undo/redo stacks, echo recognition, and remote-frame
|
|
194
|
+
* application. Operates on a plain cache table; all dispatch bookkeeping is
|
|
195
|
+
* session-local and dropped when a document's row is deleted (tombstoned).
|
|
196
|
+
*/
|
|
197
|
+
export class Controller<Key extends record.Key, State extends query.Data, Action> {
|
|
198
|
+
private readonly docs: Table<Key, State>;
|
|
199
|
+
private readonly undos: Table<Key, UndoState<Action>>;
|
|
200
|
+
private readonly params: Required<
|
|
201
|
+
Omit<ControllerParams<Key, State, Action>, "store">
|
|
202
|
+
>;
|
|
203
|
+
// lastAppliedSeq tracks the highest broadcast sequence number applied for each key.
|
|
204
|
+
// Echoes whose seq does not exceed this are stale (a fresher value already overwrote
|
|
205
|
+
// them on the server) and are dropped. A seq of 0 is treated as "unstamped" and
|
|
206
|
+
// always applies — that covers frames from servers that predate the field.
|
|
207
|
+
private readonly lastAppliedSeq = new Map<Key, number>();
|
|
208
|
+
// outstandingDispatches tracks per-key dispatches the originator has applied locally
|
|
209
|
+
// via replay but whose broadcast echo has not yet arrived. Each entry's `disturbed`
|
|
210
|
+
// flag is flipped to true when a foreign echo lands during the outstanding window; on
|
|
211
|
+
// own-echo arrival, an entry that is not disturbed skips the reduce (the local replay
|
|
212
|
+
// was authoritative) and an entry that is disturbed re-runs to recover from the
|
|
213
|
+
// foreign overwrite.
|
|
214
|
+
private readonly outstandingDispatches = new Map<
|
|
215
|
+
Key,
|
|
216
|
+
Map<string, { disturbed: boolean }>
|
|
217
|
+
>();
|
|
218
|
+
// Monotonic counter ordering entry pushes against remote touches. Program
|
|
219
|
+
// order is the ground truth here; the wall clock ties within a millisecond
|
|
220
|
+
// and steps on sleep/wake or NTP resync, so it cannot be trusted for this.
|
|
221
|
+
private tick = 0;
|
|
222
|
+
|
|
223
|
+
constructor(opts: ControllerParams<Key, State, Action>) {
|
|
224
|
+
this.params = {
|
|
225
|
+
onError: opts.onError,
|
|
226
|
+
reduce: opts.reduce,
|
|
227
|
+
preprocess: opts.preprocess ?? ((_, a) => a),
|
|
228
|
+
isUndoable: opts.isUndoable ?? (() => true),
|
|
229
|
+
kindOf: opts.kindOf ?? (() => "default"),
|
|
230
|
+
createOf: opts.createOf ?? (() => undefined),
|
|
231
|
+
coalesceWindow: opts.coalesceWindow ?? DEFAULT_COALESCE_WINDOW,
|
|
232
|
+
stackCap: opts.stackCap ?? DEFAULT_STACK_CAP,
|
|
233
|
+
now: opts.now ?? (() => TimeStamp.now()),
|
|
234
|
+
};
|
|
235
|
+
this.docs = opts.store;
|
|
236
|
+
// Undo states are rebuilt objects on every update; comparing them would
|
|
237
|
+
// be pure waste, so equality is disabled.
|
|
238
|
+
this.undos = new Table<Key, UndoState<Action>>({
|
|
239
|
+
onError: this.params.onError,
|
|
240
|
+
equal: () => false,
|
|
241
|
+
});
|
|
242
|
+
// Stacks are session-local: when a document is deleted (tombstoned), its
|
|
243
|
+
// dispatch bookkeeping goes with it.
|
|
244
|
+
this.docs.subscribe((event) => {
|
|
245
|
+
if (event.variant === "delete") this.drop(event.key);
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private drop(key: Key): void {
|
|
250
|
+
this.undos.delete(key);
|
|
251
|
+
this.lastAppliedSeq.delete(key);
|
|
252
|
+
this.outstandingDispatches.delete(key);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private updateUndo(
|
|
256
|
+
key: Key,
|
|
257
|
+
fn: (s: UndoState<Action>) => UndoState<Action>,
|
|
258
|
+
): destructor.Destructor {
|
|
259
|
+
return this.undos.set(key, (prev) => fn(prev ?? ZERO_UNDO<Action>()));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Run preprocess + reduce against the cached doc and write the result.
|
|
264
|
+
* Returns the reducer output and a rollback that restores the prior doc
|
|
265
|
+
* state. Returns null if the doc isn't cached.
|
|
266
|
+
*/
|
|
267
|
+
replay(
|
|
268
|
+
key: Key,
|
|
269
|
+
actions: Action[],
|
|
270
|
+
opts: { skipPreprocess?: boolean } = {},
|
|
271
|
+
): ReplayResult<Action> | null {
|
|
272
|
+
const current = this.docs.get(key);
|
|
273
|
+
if (current == null) return null;
|
|
274
|
+
const processed = opts.skipPreprocess
|
|
275
|
+
? actions
|
|
276
|
+
: this.params.preprocess(current, actions);
|
|
277
|
+
const { next, inverse, targets } = this.params.reduce(current, processed);
|
|
278
|
+
return {
|
|
279
|
+
processed,
|
|
280
|
+
inverse,
|
|
281
|
+
targets,
|
|
282
|
+
changed: next !== current,
|
|
283
|
+
rollback: this.docs.set(key, next),
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Append an undoable entry to the stack. Filters non-undoable actions,
|
|
289
|
+
* derives the kind, and coalesces with the prior entry if it falls within
|
|
290
|
+
* the configured window with matching kind/targets. Clears redo.
|
|
291
|
+
*/
|
|
292
|
+
recordEntry(
|
|
293
|
+
key: Key,
|
|
294
|
+
forward: Action[],
|
|
295
|
+
inverse: Action[],
|
|
296
|
+
targets: readonly string[],
|
|
297
|
+
kindOverride?: string,
|
|
298
|
+
): destructor.Destructor {
|
|
299
|
+
if (targets.length === 0) return destructor.NOOP;
|
|
300
|
+
const undoableForward = forward.filter(this.params.isUndoable);
|
|
301
|
+
if (undoableForward.length === 0) return destructor.NOOP;
|
|
302
|
+
const entry: StackEntry<Action> = {
|
|
303
|
+
forward: undoableForward,
|
|
304
|
+
inverse,
|
|
305
|
+
kind: kindOverride ?? this.params.kindOf(forward),
|
|
306
|
+
ts: this.params.now(),
|
|
307
|
+
tick: ++this.tick,
|
|
308
|
+
targets,
|
|
309
|
+
};
|
|
310
|
+
return this.updateUndo(key, (s) => ({
|
|
311
|
+
...s,
|
|
312
|
+
undo: pushOnto(s.undo, entry, this.params.coalesceWindow, this.params.stackCap),
|
|
313
|
+
redo: [],
|
|
314
|
+
}));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Walks the chosen stack from the top, skipping entries whose targets were
|
|
318
|
+
// remote-touched after the entry was pushed. Caps the walk at
|
|
319
|
+
// STALE_AUTO_ADVANCE_CAP and drops a fully stale tail. On hit, returns the
|
|
320
|
+
// entry's reversal actions (inverse for undo, forward for redo) and a
|
|
321
|
+
// commit that moves the entry to the opposite stack.
|
|
322
|
+
private prepareReversal(key: Key, side: "undo" | "redo"): Reversal<Action> | null {
|
|
323
|
+
const state = this.undos.get(key);
|
|
324
|
+
if (state == null) return null;
|
|
325
|
+
const stack = state[side];
|
|
326
|
+
if (stack.length === 0) return null;
|
|
327
|
+
let stale = 0;
|
|
328
|
+
let idx = -1;
|
|
329
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
330
|
+
const e = stack[i];
|
|
331
|
+
if (e.targets.some((t) => (state.remoteTouched[t] ?? 0) > e.tick)) {
|
|
332
|
+
stale++;
|
|
333
|
+
if (stale >= STALE_AUTO_ADVANCE_CAP) break;
|
|
334
|
+
} else {
|
|
335
|
+
idx = i;
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (idx === -1) {
|
|
340
|
+
if (stale > 0)
|
|
341
|
+
this.updateUndo(key, (s) => ({
|
|
342
|
+
...s,
|
|
343
|
+
[side]: s[side].slice(0, s[side].length - stale),
|
|
344
|
+
}));
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
const entry = stack[idx];
|
|
348
|
+
const other = side === "undo" ? "redo" : "undo";
|
|
349
|
+
return {
|
|
350
|
+
actions: side === "undo" ? entry.inverse : entry.forward,
|
|
351
|
+
commit: () =>
|
|
352
|
+
this.updateUndo(key, (s) => ({
|
|
353
|
+
...s,
|
|
354
|
+
[side]: s[side].slice(0, idx),
|
|
355
|
+
[other]: [...s[other], entry],
|
|
356
|
+
})),
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Reduce + send with rollback: replay locally, run the per-op stack
|
|
361
|
+
// mutation, register the batch as outstanding *before* the network send
|
|
362
|
+
// (the broadcast echo can race the HTTP response), and roll back stack and
|
|
363
|
+
// state when the send fails. Returns false when the doc isn't cached.
|
|
364
|
+
private async applySend(
|
|
365
|
+
key: Key,
|
|
366
|
+
actions: Action[],
|
|
367
|
+
commitStack: (r: ReplayResult<Action>) => destructor.Destructor,
|
|
368
|
+
send: SendDispatch<Action>,
|
|
369
|
+
preprocess?: Preprocess<State, Action>,
|
|
370
|
+
): Promise<boolean> {
|
|
371
|
+
const current = this.docs.get(key);
|
|
372
|
+
if (current == null) return false;
|
|
373
|
+
const processed = preprocess == null ? actions : preprocess(current, actions);
|
|
374
|
+
const r = this.replay(key, processed, { skipPreprocess: true });
|
|
375
|
+
if (r == null) return false;
|
|
376
|
+
const stackRollback = commitStack(r);
|
|
377
|
+
// A replay that left the state untouched has nothing for the server: no
|
|
378
|
+
// document change, no broadcast worth echoing. The stack mutation still
|
|
379
|
+
// runs above so undo/redo consume their entry instead of pinning it.
|
|
380
|
+
if (!r.changed) return true;
|
|
381
|
+
const dispatchKey = id.create();
|
|
382
|
+
this.registerOutstandingDispatch(key, dispatchKey);
|
|
383
|
+
try {
|
|
384
|
+
await send(r.processed, dispatchKey);
|
|
385
|
+
return true;
|
|
386
|
+
} catch (e) {
|
|
387
|
+
stackRollback();
|
|
388
|
+
r.rollback();
|
|
389
|
+
throw errors.fromUnknown(e);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Apply an action batch to the cached doc and send it to the server,
|
|
395
|
+
* recording an undoable entry. Returns false without side effects when the
|
|
396
|
+
* doc isn't cached. Rolls back the local apply and rethrows on send failure.
|
|
397
|
+
*/
|
|
398
|
+
async dispatch(
|
|
399
|
+
key: Key,
|
|
400
|
+
actions: Action[],
|
|
401
|
+
send: SendDispatch<Action>,
|
|
402
|
+
opts: Options<State, Action> = {},
|
|
403
|
+
): Promise<boolean> {
|
|
404
|
+
if (actions.length === 0) return true;
|
|
405
|
+
return await this.applySend(
|
|
406
|
+
key,
|
|
407
|
+
actions,
|
|
408
|
+
({ processed, inverse, targets }) =>
|
|
409
|
+
this.recordEntry(key, processed, inverse, targets),
|
|
410
|
+
send,
|
|
411
|
+
opts.preprocess,
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Apply and send the top live undo entry, moving it to the redo stack. Returns false
|
|
417
|
+
* when nothing is undoable. Rolls back and rethrows on send failure.
|
|
418
|
+
*/
|
|
419
|
+
async undo(key: Key, send: SendDispatch<Action>): Promise<boolean> {
|
|
420
|
+
const prepared = this.prepareUndo(key);
|
|
421
|
+
if (prepared == null) return false;
|
|
422
|
+
return await this.applySend(key, prepared.actions, () => prepared.commit(), send);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Mirror of {@link undo} for the redo stack. */
|
|
426
|
+
async redo(key: Key, send: SendDispatch<Action>): Promise<boolean> {
|
|
427
|
+
const prepared = this.prepareRedo(key);
|
|
428
|
+
if (prepared == null) return false;
|
|
429
|
+
return await this.applySend(key, prepared.actions, () => prepared.commit(), send);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Stage actions committed atomically as one undoable entry, registering the batch as
|
|
434
|
+
* outstanding before the send so the broadcast echo is recognized as own.
|
|
435
|
+
*/
|
|
436
|
+
transaction(
|
|
437
|
+
key: Key,
|
|
438
|
+
send: SendDispatch<Action>,
|
|
439
|
+
kind?: string,
|
|
440
|
+
): Transaction<Action> {
|
|
441
|
+
return this.beginTransaction(
|
|
442
|
+
key,
|
|
443
|
+
async (actions) => {
|
|
444
|
+
const dispatchKey = id.create();
|
|
445
|
+
this.registerOutstandingDispatch(key, dispatchKey);
|
|
446
|
+
await send(actions, dispatchKey);
|
|
447
|
+
},
|
|
448
|
+
kind,
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
prepareUndo(key: Key): Reversal<Action> | null {
|
|
453
|
+
return this.prepareReversal(key, "undo");
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
prepareRedo(key: Key): Reversal<Action> | null {
|
|
457
|
+
return this.prepareReversal(key, "redo");
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
beginTransaction(key: Key, send: Send<Action>, kind?: string): Transaction<Action> {
|
|
461
|
+
const initial = this.docs.get(key);
|
|
462
|
+
const accumulated: Action[] = [];
|
|
463
|
+
let done = false;
|
|
464
|
+
return {
|
|
465
|
+
add: (actions) => {
|
|
466
|
+
if (done) throw new Error("transaction finalized");
|
|
467
|
+
if (initial == null) return;
|
|
468
|
+
const arr = Array.isArray(actions) ? actions : [actions];
|
|
469
|
+
const r = this.replay(key, arr);
|
|
470
|
+
if (r != null) accumulated.push(...r.processed);
|
|
471
|
+
},
|
|
472
|
+
commit: async () => {
|
|
473
|
+
if (done) return false;
|
|
474
|
+
done = true;
|
|
475
|
+
if (accumulated.length === 0 || initial == null) return false;
|
|
476
|
+
// Inverse must be computed against the pre-transaction snapshot so
|
|
477
|
+
// undo restores to where the user started, not the last-add post-state.
|
|
478
|
+
const { inverse, targets } = this.params.reduce(initial, accumulated);
|
|
479
|
+
const stackRollback = this.recordEntry(
|
|
480
|
+
key,
|
|
481
|
+
accumulated,
|
|
482
|
+
inverse,
|
|
483
|
+
targets,
|
|
484
|
+
kind,
|
|
485
|
+
);
|
|
486
|
+
try {
|
|
487
|
+
await send(accumulated);
|
|
488
|
+
return true;
|
|
489
|
+
} catch (e) {
|
|
490
|
+
stackRollback();
|
|
491
|
+
this.docs.set(key, initial);
|
|
492
|
+
throw errors.fromUnknown(e);
|
|
493
|
+
}
|
|
494
|
+
},
|
|
495
|
+
abort: () => {
|
|
496
|
+
if (done) return;
|
|
497
|
+
done = true;
|
|
498
|
+
if (initial != null) this.docs.set(key, initial);
|
|
499
|
+
},
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
markRemoteTouched(key: Key, targets: readonly string[]): destructor.Destructor {
|
|
504
|
+
if (targets.length === 0) return destructor.NOOP;
|
|
505
|
+
const tick = ++this.tick;
|
|
506
|
+
return this.updateUndo(key, (s) => {
|
|
507
|
+
const remoteTouched = { ...s.remoteTouched };
|
|
508
|
+
for (const t of targets) remoteTouched[t] = tick;
|
|
509
|
+
return { ...s, remoteTouched };
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/** Whether any locally replayed dispatch for the key still awaits its echo. */
|
|
514
|
+
hasOutstanding(key: Key): boolean {
|
|
515
|
+
return (this.outstandingDispatches.get(key)?.size ?? 0) > 0;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Register a dispatch as outstanding so when its broadcast echo arrives it
|
|
520
|
+
* can be recognized as own and a redundant reduce skipped. Called by the
|
|
521
|
+
* dispatcher *before* the network send so the registration always wins the
|
|
522
|
+
* race against a fast echo. A registration whose echo has already been
|
|
523
|
+
* applied (seq advanced past it) is silently dropped; that's the safe
|
|
524
|
+
* fallback when the echo arrives before the dispatch promise resolves.
|
|
525
|
+
*/
|
|
526
|
+
registerOutstandingDispatch(key: Key, dispatchKey: string): void {
|
|
527
|
+
let bucket = this.outstandingDispatches.get(key);
|
|
528
|
+
if (bucket == null) {
|
|
529
|
+
bucket = new Map();
|
|
530
|
+
this.outstandingDispatches.set(key, bucket);
|
|
531
|
+
}
|
|
532
|
+
bucket.set(dispatchKey, { disturbed: false });
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Apply a remote frame. The frame is dropped if its seq does not exceed the
|
|
537
|
+
* high-water mark previously applied for this key. If `dispatchKey` matches an entry
|
|
538
|
+
* the originator registered as outstanding, these actions were already applied via
|
|
539
|
+
* replay: if no foreign action interleaved during the outstanding window, skip the
|
|
540
|
+
* reduce; otherwise re-run it to recover from the foreign overwrite. A foreign frame
|
|
541
|
+
* (one whose dispatchKey is unknown) always reduces and marks every outstanding own
|
|
542
|
+
* dispatch with a greater seq as needing recovery.
|
|
543
|
+
*/
|
|
544
|
+
applyRemote(key: Key, seq: number, dispatchKey: string, actions: Action[]): void {
|
|
545
|
+
if (seq !== 0) {
|
|
546
|
+
const last = this.lastAppliedSeq.get(key) ?? 0;
|
|
547
|
+
if (seq <= last) return;
|
|
548
|
+
this.lastAppliedSeq.set(key, seq);
|
|
549
|
+
}
|
|
550
|
+
// Create frames carry no dispatch key, so the originator cannot recognize
|
|
551
|
+
// its own echo; applying one to a cached doc would revert local edits to
|
|
552
|
+
// the creation state. Drop the create and keep any trailing actions.
|
|
553
|
+
if (
|
|
554
|
+
actions.length > 0 &&
|
|
555
|
+
this.params.createOf(actions[0]) != null &&
|
|
556
|
+
this.docs.get(key) != null
|
|
557
|
+
) {
|
|
558
|
+
actions = actions.slice(1);
|
|
559
|
+
if (actions.length === 0) return;
|
|
560
|
+
}
|
|
561
|
+
const bucket = this.outstandingDispatches.get(key);
|
|
562
|
+
const ownEntry = bucket?.get(dispatchKey);
|
|
563
|
+
const isOwnEcho = ownEntry != null;
|
|
564
|
+
if (ownEntry != null) {
|
|
565
|
+
bucket?.delete(dispatchKey);
|
|
566
|
+
// Local replay was authoritative; nothing interleaved.
|
|
567
|
+
if (!ownEntry.disturbed) return;
|
|
568
|
+
// Fall through to reduce: a foreign echo overwrote state during the
|
|
569
|
+
// outstanding window, so we must re-apply to recover.
|
|
570
|
+
} else if (bucket != null)
|
|
571
|
+
// Foreign echo: any outstanding own dispatch represents a local replay that the
|
|
572
|
+
// server has not yet broadcast back. We don't know each entry's server-stamped
|
|
573
|
+
// seq yet (the echo carrying it hasn't arrived), so we can't tell whether the
|
|
574
|
+
// foreign was applied before or after it on the server — mark every outstanding
|
|
575
|
+
// entry as disturbed. Entries whose seq turns out to be greater than this
|
|
576
|
+
// foreign's seq genuinely need recovery; entries whose seq was lower will re-run
|
|
577
|
+
// idempotently and converge to the same value.
|
|
578
|
+
for (const entry of bucket.values()) entry.disturbed = true;
|
|
579
|
+
const current = this.docs.get(key);
|
|
580
|
+
if (current == null) {
|
|
581
|
+
// A create-headed frame seeds the document; anything else predates our
|
|
582
|
+
// knowledge of the doc and is unreconstructable, so it drops.
|
|
583
|
+
const created = actions.length > 0 ? this.params.createOf(actions[0]) : undefined;
|
|
584
|
+
if (created == null) return;
|
|
585
|
+
const { next } = this.params.reduce(created, actions.slice(1));
|
|
586
|
+
this.docs.set(key, next);
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
const { next, targets } = this.params.reduce(current, actions);
|
|
590
|
+
this.docs.set(key, next);
|
|
591
|
+
if (!isOwnEcho) this.markRemoteTouched(key, targets);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
hasUndo(key: Key): boolean {
|
|
595
|
+
const s = this.undos.get(key);
|
|
596
|
+
return (s?.undo.length ?? 0) > 0;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
hasRedo(key: Key): boolean {
|
|
600
|
+
const s = this.undos.get(key);
|
|
601
|
+
return (s?.redo.length ?? 0) > 0;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
onUndoStateChange(callback: () => void, key?: Key): destructor.Destructor {
|
|
605
|
+
return this.undos.subscribe(() => callback(), key);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Builds a channel listener that applies broadcast action frames from the
|
|
610
|
+
* given channel to this controller. Registered via {@link query.Cache.listen}.
|
|
611
|
+
*/
|
|
612
|
+
listener(
|
|
613
|
+
channel: string,
|
|
614
|
+
schema: z.ZodType<Frame<Key, Action>>,
|
|
615
|
+
): query.Listener<z.ZodType<Frame<Key, Action>>> {
|
|
616
|
+
return {
|
|
617
|
+
channel,
|
|
618
|
+
schema,
|
|
619
|
+
onChange: (frames) => {
|
|
620
|
+
frames.forEach(({ key, seq, dispatchKey, actions }) =>
|
|
621
|
+
this.applyRemote(key, seq, dispatchKey, actions),
|
|
622
|
+
);
|
|
623
|
+
},
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
}
|