@arcanejs/protocol 0.6.0 → 0.8.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/README.md CHANGED
@@ -1,43 +1,108 @@
1
- # `@arcanejs/diff`
1
+ # `@arcanejs/protocol`
2
2
 
3
- [![NPM Version](https://img.shields.io/npm/v/%40arcanejs%2Fdiff)](https://www.npmjs.com/package/@arcanejs/diff)
3
+ [![NPM Version](https://img.shields.io/npm/v/%40arcanejs%2Fprotocol)](https://www.npmjs.com/package/@arcanejs/protocol)
4
4
 
5
- This package provides an easy way to:
5
+ TypeScript protocol contracts for ArcaneJS.
6
6
 
7
- - Create diffs by comparing objects
8
- - Update objects by applying diffs
7
+ This package defines the shared wire/message types used between:
9
8
 
10
- This library is written in TypeScript,
11
- and produces diffs that are type-safe,
12
- and can only be applied to objects that match the type
13
- of the objects being compared.
9
+ - ArcaneJS server runtime (`@arcanejs/toolkit`)
10
+ - Browser frontend stage (`@arcanejs/toolkit/frontend` + `@arcanejs/toolkit-frontend`)
11
+ - Custom extensions (custom namespaces/components)
14
12
 
15
- This package is part of the
16
- [`arcanejs` project](https://github.com/arcanejs/arcanejs#arcanejs),
17
- and is used to maintain a copy of a JSON tree in downstream clients in real-time
18
- via websockets.
13
+ ## Install
19
14
 
20
- ## Usage
15
+ ```bash
16
+ npm install @arcanejs/protocol
17
+ ```
18
+
19
+ ## What It Defines
20
+
21
+ ## Base protocol (`@arcanejs/protocol`)
22
+
23
+ - Base component envelope (`BaseComponentProto`, `AnyComponentProto`)
24
+ - Server messages:
25
+ - `metadata`
26
+ - `tree-full`
27
+ - `tree-diff`
28
+ - `call-response`
29
+ - `pong`
30
+ - Client messages:
31
+ - `component-message`
32
+ - `component-call`
33
+ - `ping`
34
+ - Type helpers for call/response pair typing:
35
+ - `BaseClientComponentCallPair`
36
+ - `CallForPair`
37
+ - `ReturnForPair`
38
+
39
+ ## Core namespace (`@arcanejs/protocol/core`)
40
+
41
+ Core component protocol types and guards:
42
+
43
+ - Component types: `ButtonComponent`, `GroupComponent`, `LabelComponent`, `RectComponent`, `SliderButtonComponent`, `SwitchComponent`, `TabComponent`, `TabsComponent`, `TextInputComponent`, `TimelineComponent`
44
+ - Message types: `CoreComponentMessage` and specific message variants
45
+ - Call type map: `CoreComponentCalls`
46
+ - Guards:
47
+ - `isCoreComponent(...)`
48
+ - `isCoreComponentMessage(...)`
49
+ - `isCoreComponentCall(...)`
50
+
51
+ ## Supporting modules
52
+
53
+ - `@arcanejs/protocol/styles`: shared style contracts (`GroupComponentStyle`, `LabelComponentStyle`)
54
+ - `@arcanejs/protocol/logging`: logger contract (`Logger`)
55
+
56
+ ## Usage Example
21
57
 
22
58
  ```ts
23
- import { diffJson, Diff } from '@arcanejs/diff/diff';
24
- import { patchJson } from '@arcanejs/diff/patch';
59
+ import type {
60
+ ServerMessage,
61
+ ClientMessage,
62
+ BaseComponentProto,
63
+ CallForPair,
64
+ ReturnForPair,
65
+ } from '@arcanejs/protocol';
66
+
67
+ import type {
68
+ CoreComponentCalls,
69
+ CoreComponentMessage,
70
+ } from '@arcanejs/protocol/core';
71
+
72
+ const onServerMessage = (msg: ServerMessage) => {
73
+ if (msg.type === 'tree-full') {
74
+ const root: BaseComponentProto<string, string> = msg.root;
75
+ console.log(root.namespace, root.component);
76
+ }
77
+ };
25
78
 
26
- type E = {
27
- foo: string;
28
- bar?: number[];
79
+ const message: CoreComponentMessage = {
80
+ type: 'component-message',
81
+ namespace: 'core',
82
+ componentKey: 1,
83
+ component: 'switch',
29
84
  };
30
85
 
31
- const a: E = { foo: 'bar' };
32
- const b: E = { foo: 'baz', bar: [1] };
86
+ const callMessage: CallForPair<'core', CoreComponentCalls, 'press'> = {
87
+ type: 'component-call',
88
+ namespace: 'core',
89
+ componentKey: 5,
90
+ action: 'press',
91
+ };
92
+
93
+ type PressReturn = ReturnForPair<CoreComponentCalls, 'press'>; // true
94
+ const _resultExample: PressReturn = true;
33
95
 
34
- const diffA: Diff<E> = diffJson(a, b);
96
+ const _clientMessage: ClientMessage = message;
97
+ ```
35
98
 
36
- const resultA = patchJson(a, diffA);
99
+ ## Notes
37
100
 
38
- console.log(resultB); // { foo: 'baz', bar: [1] }
101
+ - This package is primarily type contracts and guard helpers.
102
+ - `tree-diff` payloads use `Diff<...>` from `@arcanejs/diff`.
103
+ - `ping`/`pong` can be used for browser/server clock sync. `pong` includes `serverTimeMillis`.
104
+ - Custom namespaces should follow the same pattern as `core`: define component proto types, message/call unions, and guard helpers.
39
105
 
40
- const c = { baz: 'foo' };
106
+ ## Example Reference
41
107
 
42
- const resultB = patchJson(c, diffA); // TypeScript Type Error: Property 'baz' is missing in type '{ foo: string; bar?: number[] | undefined; }' but required in type '{ baz: string; }'
43
- ```
108
+ - Custom protocol implementation example: <https://github.com/ArcaneWizards/arcanejs/blob/main/examples/custom-components/src/custom-proto.ts>
package/dist/core.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { BaseComponentProto, AnyComponentProto, BaseClientComponentMessage } from './index.mjs';
1
+ import { BaseComponentProto, AnyComponentProto, BaseClientComponentCall, BaseClientComponentMessage } from './index.mjs';
2
2
  import { GroupComponentStyle } from './styles.mjs';
3
3
  import '@arcanejs/diff';
4
4
 
@@ -13,8 +13,7 @@ type Gradient = Array<{
13
13
  */
14
14
  position: number;
15
15
  }>;
16
- type ButtonComponent = BaseComponentProto<CoreNamespace> & {
17
- component: 'button';
16
+ type ButtonComponent = BaseComponentProto<CoreNamespace, 'button'> & {
18
17
  text: string;
19
18
  icon?: string;
20
19
  state: {
@@ -26,12 +25,10 @@ type ButtonComponent = BaseComponentProto<CoreNamespace> & {
26
25
  };
27
26
  type GroupCollapsedState = 'open' | 'closed';
28
27
  type DefaultGroupCollapsedState = GroupCollapsedState | 'auto';
29
- type GroupHeaderComponent = BaseComponentProto<CoreNamespace> & {
30
- component: 'group-header';
28
+ type GroupHeaderComponent = BaseComponentProto<CoreNamespace, 'group-header'> & {
31
29
  children: AnyComponentProto[];
32
30
  };
33
- type GroupComponent = BaseComponentProto<CoreNamespace> & GroupComponentStyle & {
34
- component: 'group';
31
+ type GroupComponent = BaseComponentProto<CoreNamespace, 'group'> & GroupComponentStyle & {
35
32
  title?: string;
36
33
  children: AnyComponentProto[];
37
34
  headers?: GroupHeaderComponent[];
@@ -45,21 +42,18 @@ type GroupComponent = BaseComponentProto<CoreNamespace> & GroupComponentStyle &
45
42
  */
46
43
  defaultCollapsibleState?: DefaultGroupCollapsedState;
47
44
  };
48
- type LabelComponent = BaseComponentProto<CoreNamespace> & {
49
- component: 'label';
45
+ type LabelComponent = BaseComponentProto<CoreNamespace, 'label'> & {
50
46
  bold?: boolean;
51
47
  text: string;
52
48
  };
53
- type RectComponent = BaseComponentProto<CoreNamespace> & {
54
- component: 'rect';
49
+ type RectComponent = BaseComponentProto<CoreNamespace, 'rect'> & {
55
50
  color: string;
56
51
  /**
57
52
  * Set to true if the component should increase its size to fill the available space.
58
53
  */
59
54
  grow?: boolean;
60
55
  };
61
- type SliderButtonComponent = BaseComponentProto<CoreNamespace> & {
62
- component: 'slider_button';
56
+ type SliderButtonComponent = BaseComponentProto<CoreNamespace, 'slider_button'> & {
63
57
  min: number;
64
58
  max: number;
65
59
  step: number;
@@ -70,21 +64,17 @@ type SliderButtonComponent = BaseComponentProto<CoreNamespace> & {
70
64
  */
71
65
  grow?: boolean;
72
66
  };
73
- type SwitchComponent = BaseComponentProto<CoreNamespace> & {
74
- component: 'switch';
67
+ type SwitchComponent = BaseComponentProto<CoreNamespace, 'switch'> & {
75
68
  state: 'on' | 'off';
76
69
  };
77
- type TabComponent = BaseComponentProto<CoreNamespace> & {
78
- component: 'tab';
70
+ type TabComponent = BaseComponentProto<CoreNamespace, 'tab'> & {
79
71
  name: string;
80
72
  child?: AnyComponentProto;
81
73
  };
82
- type TabsComponent = BaseComponentProto<CoreNamespace> & {
83
- component: 'tabs';
74
+ type TabsComponent = BaseComponentProto<CoreNamespace, 'tabs'> & {
84
75
  tabs: TabComponent[];
85
76
  };
86
- type TextInputComponent = BaseComponentProto<CoreNamespace> & {
87
- component: 'text-input';
77
+ type TextInputComponent = BaseComponentProto<CoreNamespace, 'text-input'> & {
88
78
  value: string;
89
79
  };
90
80
  type TimelineState = {
@@ -97,8 +87,7 @@ type TimelineState = {
97
87
  totalTimeMillis: number;
98
88
  currentTimeMillis: number;
99
89
  };
100
- type TimelineComponent = BaseComponentProto<CoreNamespace> & {
101
- component: 'timeline';
90
+ type TimelineComponent = BaseComponentProto<CoreNamespace, 'timeline'> & {
102
91
  state: TimelineState;
103
92
  title?: string;
104
93
  subtitles?: string[];
@@ -108,9 +97,7 @@ type TimelineComponent = BaseComponentProto<CoreNamespace> & {
108
97
  };
109
98
  type CoreComponent = ButtonComponent | GroupComponent | GroupHeaderComponent | LabelComponent | RectComponent | SliderButtonComponent | SwitchComponent | TabComponent | TabsComponent | TextInputComponent | TimelineComponent;
110
99
  declare const isCoreComponent: (component: AnyComponentProto) => component is CoreComponent;
111
- type ButtonPressMessage = BaseClientComponentMessage<CoreNamespace> & {
112
- component: 'button';
113
- };
100
+ type ButtonPressMessage = BaseClientComponentCall<CoreNamespace, 'press'>;
114
101
  type GroupTitleChangeMessage = BaseClientComponentMessage<CoreNamespace> & {
115
102
  component: 'group';
116
103
  title: string;
@@ -126,9 +113,16 @@ type TextInputUpdateMessage = BaseClientComponentMessage<CoreNamespace> & {
126
113
  component: 'text-input';
127
114
  value: string;
128
115
  };
129
- type CoreComponentMessage = ButtonPressMessage | GroupTitleChangeMessage | SliderButtonUpdateMessage | SwitchToggleMessage | TextInputUpdateMessage;
130
- declare const isCoreComponentMessage: <C extends "button" | "group" | "slider_button" | "switch" | "text-input">(message: BaseClientComponentMessage<string>, component: C) => message is CoreComponentMessage & {
116
+ type CoreComponentMessage = GroupTitleChangeMessage | SliderButtonUpdateMessage | SwitchToggleMessage | TextInputUpdateMessage;
117
+ interface CoreComponentCalls {
118
+ press: {
119
+ call: ButtonPressMessage;
120
+ return: true;
121
+ };
122
+ }
123
+ declare const isCoreComponentMessage: <C extends "group" | "slider_button" | "switch" | "text-input">(message: BaseClientComponentMessage<string>, component: C) => message is CoreComponentMessage & {
131
124
  component: C;
132
125
  };
126
+ declare const isCoreComponentCall: <A extends "press">(call: BaseClientComponentCall<string, string>, action: A) => call is CoreComponentCalls[A]["call"];
133
127
 
134
- export { type ButtonComponent, type ButtonPressMessage, type CoreComponent, type CoreComponentMessage, type CoreNamespace, type DefaultGroupCollapsedState, type Gradient, type GroupCollapsedState, type GroupComponent, type GroupHeaderComponent, type GroupTitleChangeMessage, type LabelComponent, type RectComponent, type SliderButtonComponent, type SliderButtonUpdateMessage, type SwitchComponent, type SwitchToggleMessage, type TabComponent, type TabsComponent, type TextInputComponent, type TextInputUpdateMessage, type TimelineComponent, type TimelineState, isCoreComponent, isCoreComponentMessage };
128
+ export { type ButtonComponent, type ButtonPressMessage, type CoreComponent, type CoreComponentCalls, type CoreComponentMessage, type CoreNamespace, type DefaultGroupCollapsedState, type Gradient, type GroupCollapsedState, type GroupComponent, type GroupHeaderComponent, type GroupTitleChangeMessage, type LabelComponent, type RectComponent, type SliderButtonComponent, type SliderButtonUpdateMessage, type SwitchComponent, type SwitchToggleMessage, type TabComponent, type TabsComponent, type TextInputComponent, type TextInputUpdateMessage, type TimelineComponent, type TimelineState, isCoreComponent, isCoreComponentCall, isCoreComponentMessage };
package/dist/core.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { BaseComponentProto, AnyComponentProto, BaseClientComponentMessage } from './index.js';
1
+ import { BaseComponentProto, AnyComponentProto, BaseClientComponentCall, BaseClientComponentMessage } from './index.js';
2
2
  import { GroupComponentStyle } from './styles.js';
3
3
  import '@arcanejs/diff';
4
4
 
@@ -13,8 +13,7 @@ type Gradient = Array<{
13
13
  */
14
14
  position: number;
15
15
  }>;
16
- type ButtonComponent = BaseComponentProto<CoreNamespace> & {
17
- component: 'button';
16
+ type ButtonComponent = BaseComponentProto<CoreNamespace, 'button'> & {
18
17
  text: string;
19
18
  icon?: string;
20
19
  state: {
@@ -26,12 +25,10 @@ type ButtonComponent = BaseComponentProto<CoreNamespace> & {
26
25
  };
27
26
  type GroupCollapsedState = 'open' | 'closed';
28
27
  type DefaultGroupCollapsedState = GroupCollapsedState | 'auto';
29
- type GroupHeaderComponent = BaseComponentProto<CoreNamespace> & {
30
- component: 'group-header';
28
+ type GroupHeaderComponent = BaseComponentProto<CoreNamespace, 'group-header'> & {
31
29
  children: AnyComponentProto[];
32
30
  };
33
- type GroupComponent = BaseComponentProto<CoreNamespace> & GroupComponentStyle & {
34
- component: 'group';
31
+ type GroupComponent = BaseComponentProto<CoreNamespace, 'group'> & GroupComponentStyle & {
35
32
  title?: string;
36
33
  children: AnyComponentProto[];
37
34
  headers?: GroupHeaderComponent[];
@@ -45,21 +42,18 @@ type GroupComponent = BaseComponentProto<CoreNamespace> & GroupComponentStyle &
45
42
  */
46
43
  defaultCollapsibleState?: DefaultGroupCollapsedState;
47
44
  };
48
- type LabelComponent = BaseComponentProto<CoreNamespace> & {
49
- component: 'label';
45
+ type LabelComponent = BaseComponentProto<CoreNamespace, 'label'> & {
50
46
  bold?: boolean;
51
47
  text: string;
52
48
  };
53
- type RectComponent = BaseComponentProto<CoreNamespace> & {
54
- component: 'rect';
49
+ type RectComponent = BaseComponentProto<CoreNamespace, 'rect'> & {
55
50
  color: string;
56
51
  /**
57
52
  * Set to true if the component should increase its size to fill the available space.
58
53
  */
59
54
  grow?: boolean;
60
55
  };
61
- type SliderButtonComponent = BaseComponentProto<CoreNamespace> & {
62
- component: 'slider_button';
56
+ type SliderButtonComponent = BaseComponentProto<CoreNamespace, 'slider_button'> & {
63
57
  min: number;
64
58
  max: number;
65
59
  step: number;
@@ -70,21 +64,17 @@ type SliderButtonComponent = BaseComponentProto<CoreNamespace> & {
70
64
  */
71
65
  grow?: boolean;
72
66
  };
73
- type SwitchComponent = BaseComponentProto<CoreNamespace> & {
74
- component: 'switch';
67
+ type SwitchComponent = BaseComponentProto<CoreNamespace, 'switch'> & {
75
68
  state: 'on' | 'off';
76
69
  };
77
- type TabComponent = BaseComponentProto<CoreNamespace> & {
78
- component: 'tab';
70
+ type TabComponent = BaseComponentProto<CoreNamespace, 'tab'> & {
79
71
  name: string;
80
72
  child?: AnyComponentProto;
81
73
  };
82
- type TabsComponent = BaseComponentProto<CoreNamespace> & {
83
- component: 'tabs';
74
+ type TabsComponent = BaseComponentProto<CoreNamespace, 'tabs'> & {
84
75
  tabs: TabComponent[];
85
76
  };
86
- type TextInputComponent = BaseComponentProto<CoreNamespace> & {
87
- component: 'text-input';
77
+ type TextInputComponent = BaseComponentProto<CoreNamespace, 'text-input'> & {
88
78
  value: string;
89
79
  };
90
80
  type TimelineState = {
@@ -97,8 +87,7 @@ type TimelineState = {
97
87
  totalTimeMillis: number;
98
88
  currentTimeMillis: number;
99
89
  };
100
- type TimelineComponent = BaseComponentProto<CoreNamespace> & {
101
- component: 'timeline';
90
+ type TimelineComponent = BaseComponentProto<CoreNamespace, 'timeline'> & {
102
91
  state: TimelineState;
103
92
  title?: string;
104
93
  subtitles?: string[];
@@ -108,9 +97,7 @@ type TimelineComponent = BaseComponentProto<CoreNamespace> & {
108
97
  };
109
98
  type CoreComponent = ButtonComponent | GroupComponent | GroupHeaderComponent | LabelComponent | RectComponent | SliderButtonComponent | SwitchComponent | TabComponent | TabsComponent | TextInputComponent | TimelineComponent;
110
99
  declare const isCoreComponent: (component: AnyComponentProto) => component is CoreComponent;
111
- type ButtonPressMessage = BaseClientComponentMessage<CoreNamespace> & {
112
- component: 'button';
113
- };
100
+ type ButtonPressMessage = BaseClientComponentCall<CoreNamespace, 'press'>;
114
101
  type GroupTitleChangeMessage = BaseClientComponentMessage<CoreNamespace> & {
115
102
  component: 'group';
116
103
  title: string;
@@ -126,9 +113,16 @@ type TextInputUpdateMessage = BaseClientComponentMessage<CoreNamespace> & {
126
113
  component: 'text-input';
127
114
  value: string;
128
115
  };
129
- type CoreComponentMessage = ButtonPressMessage | GroupTitleChangeMessage | SliderButtonUpdateMessage | SwitchToggleMessage | TextInputUpdateMessage;
130
- declare const isCoreComponentMessage: <C extends "button" | "group" | "slider_button" | "switch" | "text-input">(message: BaseClientComponentMessage<string>, component: C) => message is CoreComponentMessage & {
116
+ type CoreComponentMessage = GroupTitleChangeMessage | SliderButtonUpdateMessage | SwitchToggleMessage | TextInputUpdateMessage;
117
+ interface CoreComponentCalls {
118
+ press: {
119
+ call: ButtonPressMessage;
120
+ return: true;
121
+ };
122
+ }
123
+ declare const isCoreComponentMessage: <C extends "group" | "slider_button" | "switch" | "text-input">(message: BaseClientComponentMessage<string>, component: C) => message is CoreComponentMessage & {
131
124
  component: C;
132
125
  };
126
+ declare const isCoreComponentCall: <A extends "press">(call: BaseClientComponentCall<string, string>, action: A) => call is CoreComponentCalls[A]["call"];
133
127
 
134
- export { type ButtonComponent, type ButtonPressMessage, type CoreComponent, type CoreComponentMessage, type CoreNamespace, type DefaultGroupCollapsedState, type Gradient, type GroupCollapsedState, type GroupComponent, type GroupHeaderComponent, type GroupTitleChangeMessage, type LabelComponent, type RectComponent, type SliderButtonComponent, type SliderButtonUpdateMessage, type SwitchComponent, type SwitchToggleMessage, type TabComponent, type TabsComponent, type TextInputComponent, type TextInputUpdateMessage, type TimelineComponent, type TimelineState, isCoreComponent, isCoreComponentMessage };
128
+ export { type ButtonComponent, type ButtonPressMessage, type CoreComponent, type CoreComponentCalls, type CoreComponentMessage, type CoreNamespace, type DefaultGroupCollapsedState, type Gradient, type GroupCollapsedState, type GroupComponent, type GroupHeaderComponent, type GroupTitleChangeMessage, type LabelComponent, type RectComponent, type SliderButtonComponent, type SliderButtonUpdateMessage, type SwitchComponent, type SwitchToggleMessage, type TabComponent, type TabsComponent, type TextInputComponent, type TextInputUpdateMessage, type TimelineComponent, type TimelineState, isCoreComponent, isCoreComponentCall, isCoreComponentMessage };
package/dist/core.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/core.ts
2
2
  var isCoreComponent = (component) => component.namespace === "core";
3
3
  var isCoreComponentMessage = (message, component) => message.namespace === "core" && message.component === component;
4
+ var isCoreComponentCall = (call, action) => call.namespace === "core" && call.action === action;
4
5
 
5
6
 
6
7
 
7
- exports.isCoreComponent = isCoreComponent; exports.isCoreComponentMessage = isCoreComponentMessage;
8
+
9
+ exports.isCoreComponent = isCoreComponent; exports.isCoreComponentCall = isCoreComponentCall; exports.isCoreComponentMessage = isCoreComponentMessage;
package/dist/core.mjs CHANGED
@@ -1,7 +1,9 @@
1
1
  // src/core.ts
2
2
  var isCoreComponent = (component) => component.namespace === "core";
3
3
  var isCoreComponentMessage = (message, component) => message.namespace === "core" && message.component === component;
4
+ var isCoreComponentCall = (call, action) => call.namespace === "core" && call.action === action;
4
5
  export {
5
6
  isCoreComponent,
7
+ isCoreComponentCall,
6
8
  isCoreComponentMessage
7
9
  };
package/dist/index.d.mts CHANGED
@@ -1,32 +1,80 @@
1
1
  import { Diff } from '@arcanejs/diff';
2
2
 
3
- type BaseComponentProto<Namespace extends string> = {
3
+ type BaseComponentProto<Namespace extends string, Component extends string> = {
4
4
  key: number;
5
5
  namespace: Namespace;
6
+ component: Component;
6
7
  };
7
- type AnyComponentProto = BaseComponentProto<string>;
8
+ type AnyComponentProto = BaseComponentProto<string, string>;
8
9
  type MetadataMessage = {
9
10
  type: 'metadata';
10
11
  /**
11
12
  * The UUID for the current connection
12
13
  */
13
14
  connectionUuid: string;
15
+ clockSync: {
16
+ /**
17
+ * How often the frontend should send ping requests.
18
+ */
19
+ pingIntervalMs: number;
20
+ } | null;
14
21
  };
15
22
  type SendTreeMsg = {
16
23
  type: 'tree-full';
17
- root: BaseComponentProto<string>;
24
+ root: BaseComponentProto<string, string>;
18
25
  };
19
26
  type UpdateTreeMsg = {
20
27
  type: 'tree-diff';
21
- diff: Diff<BaseComponentProto<string>>;
28
+ diff: Diff<BaseComponentProto<string, string>>;
22
29
  };
23
- type ServerMessage = MetadataMessage | SendTreeMsg | UpdateTreeMsg;
30
+ type CallResponseMsg<Namespace extends string, T> = {
31
+ type: 'call-response';
32
+ namespace: Namespace;
33
+ requestId: number;
34
+ } & ({
35
+ success: true;
36
+ returnValue: T;
37
+ } | {
38
+ success: false;
39
+ errorMessage: string;
40
+ });
41
+ type PongResponseMessage = {
42
+ type: 'pong';
43
+ pingId: number;
44
+ /**
45
+ * Server clock time in milliseconds.
46
+ */
47
+ serverTimeMillis: number;
48
+ };
49
+ type ServerMessage = MetadataMessage | SendTreeMsg | UpdateTreeMsg | CallResponseMsg<string, unknown> | PongResponseMessage;
24
50
  type BaseClientComponentMessage<Namespace extends string> = {
25
51
  type: 'component-message';
26
52
  namespace: Namespace;
27
53
  componentKey: number;
28
54
  };
55
+ type BaseClientComponentCall<Namespace extends string, Action extends string> = {
56
+ type: 'component-call';
57
+ namespace: Namespace;
58
+ componentKey: number;
59
+ requestId: number;
60
+ action: Action;
61
+ };
62
+ type BaseClientComponentCallPair<Namespace extends string, Action extends string, Call extends BaseClientComponentCall<Namespace, Action>, Return = unknown> = {
63
+ call: Call;
64
+ return: Return;
65
+ };
66
+ type CallForPair<Namespace extends string, Pairs, Action extends string & keyof Pairs> = Pairs extends Record<Action, {
67
+ call: infer R;
68
+ }> ? Omit<R & BaseClientComponentCall<Namespace, Action>, 'requestId'> : never;
69
+ type ReturnForPair<Pairs, Action extends string & keyof Pairs> = Pairs extends Record<Action, {
70
+ return: infer R;
71
+ }> ? R : never;
29
72
  type AnyClientComponentMessage = BaseClientComponentMessage<string>;
30
- type ClientMessage = AnyClientComponentMessage;
73
+ type AnyClientComponentCall = BaseClientComponentCall<string, string>;
74
+ type PingRequestMessage = {
75
+ type: 'ping';
76
+ pingId: number;
77
+ };
78
+ type ClientMessage = AnyClientComponentMessage | AnyClientComponentCall | PingRequestMessage;
31
79
 
32
- export type { AnyClientComponentMessage, AnyComponentProto, BaseClientComponentMessage, BaseComponentProto, ClientMessage, MetadataMessage, SendTreeMsg, ServerMessage, UpdateTreeMsg };
80
+ export type { AnyClientComponentCall, AnyClientComponentMessage, AnyComponentProto, BaseClientComponentCall, BaseClientComponentCallPair, BaseClientComponentMessage, BaseComponentProto, CallForPair, CallResponseMsg, ClientMessage, MetadataMessage, PingRequestMessage, PongResponseMessage, ReturnForPair, SendTreeMsg, ServerMessage, UpdateTreeMsg };
package/dist/index.d.ts CHANGED
@@ -1,32 +1,80 @@
1
1
  import { Diff } from '@arcanejs/diff';
2
2
 
3
- type BaseComponentProto<Namespace extends string> = {
3
+ type BaseComponentProto<Namespace extends string, Component extends string> = {
4
4
  key: number;
5
5
  namespace: Namespace;
6
+ component: Component;
6
7
  };
7
- type AnyComponentProto = BaseComponentProto<string>;
8
+ type AnyComponentProto = BaseComponentProto<string, string>;
8
9
  type MetadataMessage = {
9
10
  type: 'metadata';
10
11
  /**
11
12
  * The UUID for the current connection
12
13
  */
13
14
  connectionUuid: string;
15
+ clockSync: {
16
+ /**
17
+ * How often the frontend should send ping requests.
18
+ */
19
+ pingIntervalMs: number;
20
+ } | null;
14
21
  };
15
22
  type SendTreeMsg = {
16
23
  type: 'tree-full';
17
- root: BaseComponentProto<string>;
24
+ root: BaseComponentProto<string, string>;
18
25
  };
19
26
  type UpdateTreeMsg = {
20
27
  type: 'tree-diff';
21
- diff: Diff<BaseComponentProto<string>>;
28
+ diff: Diff<BaseComponentProto<string, string>>;
22
29
  };
23
- type ServerMessage = MetadataMessage | SendTreeMsg | UpdateTreeMsg;
30
+ type CallResponseMsg<Namespace extends string, T> = {
31
+ type: 'call-response';
32
+ namespace: Namespace;
33
+ requestId: number;
34
+ } & ({
35
+ success: true;
36
+ returnValue: T;
37
+ } | {
38
+ success: false;
39
+ errorMessage: string;
40
+ });
41
+ type PongResponseMessage = {
42
+ type: 'pong';
43
+ pingId: number;
44
+ /**
45
+ * Server clock time in milliseconds.
46
+ */
47
+ serverTimeMillis: number;
48
+ };
49
+ type ServerMessage = MetadataMessage | SendTreeMsg | UpdateTreeMsg | CallResponseMsg<string, unknown> | PongResponseMessage;
24
50
  type BaseClientComponentMessage<Namespace extends string> = {
25
51
  type: 'component-message';
26
52
  namespace: Namespace;
27
53
  componentKey: number;
28
54
  };
55
+ type BaseClientComponentCall<Namespace extends string, Action extends string> = {
56
+ type: 'component-call';
57
+ namespace: Namespace;
58
+ componentKey: number;
59
+ requestId: number;
60
+ action: Action;
61
+ };
62
+ type BaseClientComponentCallPair<Namespace extends string, Action extends string, Call extends BaseClientComponentCall<Namespace, Action>, Return = unknown> = {
63
+ call: Call;
64
+ return: Return;
65
+ };
66
+ type CallForPair<Namespace extends string, Pairs, Action extends string & keyof Pairs> = Pairs extends Record<Action, {
67
+ call: infer R;
68
+ }> ? Omit<R & BaseClientComponentCall<Namespace, Action>, 'requestId'> : never;
69
+ type ReturnForPair<Pairs, Action extends string & keyof Pairs> = Pairs extends Record<Action, {
70
+ return: infer R;
71
+ }> ? R : never;
29
72
  type AnyClientComponentMessage = BaseClientComponentMessage<string>;
30
- type ClientMessage = AnyClientComponentMessage;
73
+ type AnyClientComponentCall = BaseClientComponentCall<string, string>;
74
+ type PingRequestMessage = {
75
+ type: 'ping';
76
+ pingId: number;
77
+ };
78
+ type ClientMessage = AnyClientComponentMessage | AnyClientComponentCall | PingRequestMessage;
31
79
 
32
- export type { AnyClientComponentMessage, AnyComponentProto, BaseClientComponentMessage, BaseComponentProto, ClientMessage, MetadataMessage, SendTreeMsg, ServerMessage, UpdateTreeMsg };
80
+ export type { AnyClientComponentCall, AnyClientComponentMessage, AnyComponentProto, BaseClientComponentCall, BaseClientComponentCallPair, BaseClientComponentMessage, BaseComponentProto, CallForPair, CallResponseMsg, ClientMessage, MetadataMessage, PingRequestMessage, PongResponseMessage, ReturnForPair, SendTreeMsg, ServerMessage, UpdateTreeMsg };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcanejs/protocol",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "private": false,
5
5
  "description": "The JSON protocol types for the @arcanejs Toolkit",
6
6
  "license": "MIT",
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "repository": {
12
12
  "type": "git",
13
- "url": "https://github.com/arcanejs/arcanejs.git"
13
+ "url": "https://github.com/ArcaneWizards/arcanejs.git"
14
14
  },
15
15
  "exports": {
16
16
  ".": {
@@ -34,7 +34,7 @@
34
34
  "./package.json": "./package.json"
35
35
  },
36
36
  "dependencies": {
37
- "@arcanejs/diff": "^0.5.1"
37
+ "@arcanejs/diff": "^0.5.2"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/eslint": "^8.56.5",