@allternit/ix 0.1.0 → 0.1.1
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 +6 -6
- package/dist/adapters/json-render.d.ts +5 -5
- package/dist/adapters/json-render.js +12 -12
- package/dist/collab/visual-editor.d.ts +1 -1
- package/dist/collab/visual-editor.js +4 -4
- package/dist/collab/visual-editor.js.map +1 -1
- package/dist/collab/yjs-adapter.d.ts +1 -1
- package/dist/collab/yjs-adapter.js +2 -2
- package/dist/collab/yjs-adapter.js.map +1 -1
- package/dist/collab/yjs-client.js +1 -1
- package/dist/collab/yjs-client.js.map +1 -1
- package/dist/collab/yjs-types.js +1 -1
- package/dist/collab/yjs-types.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/pipeline/llm-to-ix.d.ts +5 -5
- package/dist/pipeline/llm-to-ix.d.ts.map +1 -1
- package/dist/pipeline/llm-to-ix.js +6 -6
- package/dist/react/renderer.d.ts +2 -2
- package/dist/react/renderer.js +3 -3
- package/dist/react/renderer.js.map +1 -1
- package/dist/renderer/renderer.d.ts +1 -1
- package/dist/renderer/renderer.js +1 -1
- package/dist/runtime/capsule-runtime.d.ts +1 -1
- package/dist/runtime/capsule-runtime.js +1 -1
- package/dist/sdk/api.d.ts +3 -3
- package/dist/sdk/api.js +3 -3
- package/dist/sdk/index.d.ts +2 -2
- package/dist/sdk/index.js +2 -2
- package/dist/sdk/react.d.ts +2 -2
- package/dist/sdk/react.js +2 -2
- package/dist/state/index.d.ts +1 -1
- package/dist/state/index.js +1 -1
- package/dist/state/store.d.ts +1 -1
- package/dist/state/store.js +3 -3
- package/dist/state/store.js.map +1 -1
- package/dist/svelte/index.d.ts +1 -1
- package/dist/svelte/index.js +1 -1
- package/dist/svelte/renderer.d.ts +3 -3
- package/dist/svelte/renderer.js +4 -4
- package/dist/svelte/renderer.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +1 -1
- package/dist/vue/renderer.d.ts +3 -3
- package/dist/vue/renderer.js +5 -5
- package/dist/vue/renderer.js.map +1 -1
- package/package.json +8 -8
- package/dist/adapters/json-render.d.ts.bak +0 -211
- package/dist/adapters/json-render.js.bak +0 -576
- package/dist/catalog/registry.d.ts.bak +0 -65
- package/dist/catalog/registry.js.bak +0 -388
- package/dist/collab/capsule-registry.d.ts.bak +0 -114
- package/dist/collab/capsule-registry.js.bak +0 -271
- package/dist/collab/index.d.ts.bak +0 -21
- package/dist/collab/index.js.bak +0 -32
- package/dist/collab/visual-editor.d.ts.bak +0 -199
- package/dist/collab/visual-editor.js.bak +0 -259
- package/dist/collab/yjs-adapter.d.ts.bak +0 -95
- package/dist/collab/yjs-adapter.js.bak +0 -282
- package/dist/collab/yjs-client.d.ts.bak +0 -101
- package/dist/collab/yjs-client.js.bak +0 -193
- package/dist/collab/yjs-protocols.d.ts.bak +0 -128
- package/dist/collab/yjs-protocols.js.bak +0 -245
- package/dist/collab/yjs-types.d.ts.bak +0 -201
- package/dist/collab/yjs-types.js.bak +0 -45
- package/dist/index.d.ts.bak +0 -38
- package/dist/index.js.bak +0 -48
- package/dist/pipeline/llm-to-ix.d.ts.bak +0 -249
- package/dist/pipeline/llm-to-ix.js.bak +0 -992
- package/dist/react/index.d.ts.bak +0 -18
- package/dist/react/index.js.bak +0 -18
- package/dist/react/renderer.d.ts.bak +0 -47
- package/dist/react/renderer.js.bak +0 -420
- package/dist/renderer/renderer.d.ts.bak +0 -55
- package/dist/renderer/renderer.js.bak +0 -232
- package/dist/runtime/capsule-runtime.d.ts.bak +0 -227
- package/dist/runtime/capsule-runtime.js.bak +0 -563
- package/dist/runtime/policy-gates.d.ts.bak +0 -116
- package/dist/runtime/policy-gates.js.bak +0 -317
- package/dist/schema/ui-ir.d.ts.bak +0 -26
- package/dist/schema/ui-ir.js.bak +0 -51
- package/dist/sdk/api.d.ts.bak +0 -101
- package/dist/sdk/api.js.bak +0 -177
- package/dist/sdk/index.d.ts.bak +0 -9
- package/dist/sdk/index.js.bak +0 -10
- package/dist/sdk/react.d.ts.bak +0 -63
- package/dist/sdk/react.js.bak +0 -161
- package/dist/state/index.d.ts.bak +0 -8
- package/dist/state/index.js.bak +0 -8
- package/dist/state/patch.d.ts.bak +0 -73
- package/dist/state/patch.js.bak +0 -437
- package/dist/state/store.d.ts.bak +0 -50
- package/dist/state/store.js.bak +0 -246
- package/dist/svelte/index.d.ts.bak +0 -15
- package/dist/svelte/index.js.bak +0 -15
- package/dist/svelte/renderer.d.ts.bak +0 -35
- package/dist/svelte/renderer.js.bak +0 -317
- package/dist/types/index.d.ts.bak +0 -349
- package/dist/types/index.js.bak +0 -152
- package/dist/vue/index.d.ts.bak +0 -18
- package/dist/vue/index.js.bak +0 -18
- package/dist/vue/renderer.d.ts.bak +0 -46
- package/dist/vue/renderer.js.bak +0 -302
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Visual Editor for A2R-IX
|
|
3
|
-
*
|
|
4
|
-
* Declarative API for building UI IR visually.
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Create visual editor
|
|
8
|
-
*/
|
|
9
|
-
export function createVisualEditor() {
|
|
10
|
-
return {
|
|
11
|
-
create(version = '1.0.0') {
|
|
12
|
-
return createUIRootBuilder(version);
|
|
13
|
-
},
|
|
14
|
-
load(root) {
|
|
15
|
-
return createUIRootBuilder(root.version, root);
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Create UI root builder
|
|
21
|
-
*/
|
|
22
|
-
function createUIRootBuilder(version, existing) {
|
|
23
|
-
const root = existing || {
|
|
24
|
-
version,
|
|
25
|
-
components: [],
|
|
26
|
-
state: { variables: [], computed: [], initial: {} },
|
|
27
|
-
actions: [],
|
|
28
|
-
};
|
|
29
|
-
let metadata = {};
|
|
30
|
-
return {
|
|
31
|
-
metadata(meta) {
|
|
32
|
-
metadata = { ...metadata, ...meta };
|
|
33
|
-
return this;
|
|
34
|
-
},
|
|
35
|
-
add(component) {
|
|
36
|
-
const comp = 'build' in component ? component.build() : component;
|
|
37
|
-
root.components.push(comp);
|
|
38
|
-
return this;
|
|
39
|
-
},
|
|
40
|
-
state(path, type, defaultValue) {
|
|
41
|
-
root.state.variables.push({ path, type, default: defaultValue });
|
|
42
|
-
if (defaultValue !== undefined) {
|
|
43
|
-
root.state.initial[path] = defaultValue;
|
|
44
|
-
}
|
|
45
|
-
return this;
|
|
46
|
-
},
|
|
47
|
-
computed(name, deps, compute) {
|
|
48
|
-
if (!root.state.computed) {
|
|
49
|
-
root.state.computed = [];
|
|
50
|
-
}
|
|
51
|
-
root.state.computed.push({
|
|
52
|
-
name,
|
|
53
|
-
deps,
|
|
54
|
-
compute: { $expr: compute },
|
|
55
|
-
});
|
|
56
|
-
return this;
|
|
57
|
-
},
|
|
58
|
-
action(id, type, handler) {
|
|
59
|
-
root.actions.push({ id, type, handler });
|
|
60
|
-
return this;
|
|
61
|
-
},
|
|
62
|
-
css(styles) {
|
|
63
|
-
root.css = styles;
|
|
64
|
-
return this;
|
|
65
|
-
},
|
|
66
|
-
build() {
|
|
67
|
-
if (Object.keys(metadata).length > 0) {
|
|
68
|
-
root.metadata = { ...root.metadata, ...metadata };
|
|
69
|
-
}
|
|
70
|
-
return root;
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Component type builders
|
|
76
|
-
*/
|
|
77
|
-
export const components = {
|
|
78
|
-
/** Layout components */
|
|
79
|
-
layout: {
|
|
80
|
-
Box: (props) => createComponentBuilder('Box', props),
|
|
81
|
-
Stack: (props) => createComponentBuilder('Stack', props),
|
|
82
|
-
Grid: (props) => createComponentBuilder('Grid', props),
|
|
83
|
-
Flex: (props) => createComponentBuilder('Flex', props),
|
|
84
|
-
Container: (props) => createComponentBuilder('Container', props),
|
|
85
|
-
},
|
|
86
|
-
/** Typography components */
|
|
87
|
-
typography: {
|
|
88
|
-
Text: (text, props) => createComponentBuilder('Text', { children: text, ...props }),
|
|
89
|
-
Heading: (text, level = 1, props) => createComponentBuilder('Heading', { children: text, level, ...props }),
|
|
90
|
-
Paragraph: (text, props) => createComponentBuilder('Paragraph', { children: text, ...props }),
|
|
91
|
-
Label: (text, props) => createComponentBuilder('Label', { children: text, ...props }),
|
|
92
|
-
},
|
|
93
|
-
/** Input components */
|
|
94
|
-
input: {
|
|
95
|
-
Button: (text, props) => createComponentBuilder('Button', { children: text, ...props }),
|
|
96
|
-
Input: (props) => createComponentBuilder('Input', props),
|
|
97
|
-
TextArea: (props) => createComponentBuilder('TextArea', props),
|
|
98
|
-
Select: (options, props) => createComponentBuilder('Select', { options, ...props }),
|
|
99
|
-
Checkbox: (props) => createComponentBuilder('Checkbox', props),
|
|
100
|
-
Radio: (props) => createComponentBuilder('Radio', props),
|
|
101
|
-
Switch: (props) => createComponentBuilder('Switch', props),
|
|
102
|
-
},
|
|
103
|
-
/** Display components */
|
|
104
|
-
display: {
|
|
105
|
-
Image: (src, props) => createComponentBuilder('Image', { src, ...props }),
|
|
106
|
-
Icon: (name, props) => createComponentBuilder('Icon', { name, ...props }),
|
|
107
|
-
Badge: (text, props) => createComponentBuilder('Badge', { children: text, ...props }),
|
|
108
|
-
Card: (props) => createComponentBuilder('Card', props),
|
|
109
|
-
List: (items, renderItem, props) => createComponentBuilder('List', { items, renderItem, ...props }),
|
|
110
|
-
Table: (data, columns, props) => createComponentBuilder('Table', { data, columns, ...props }),
|
|
111
|
-
},
|
|
112
|
-
};
|
|
113
|
-
/**
|
|
114
|
-
* Create component builder
|
|
115
|
-
*/
|
|
116
|
-
function createComponentBuilder(type, initialProps = {}) {
|
|
117
|
-
const component = {
|
|
118
|
-
id: generateId(),
|
|
119
|
-
type,
|
|
120
|
-
props: { ...initialProps },
|
|
121
|
-
};
|
|
122
|
-
return {
|
|
123
|
-
id(id) {
|
|
124
|
-
component.id = id;
|
|
125
|
-
return this;
|
|
126
|
-
},
|
|
127
|
-
props(props) {
|
|
128
|
-
Object.assign(component.props, props);
|
|
129
|
-
return this;
|
|
130
|
-
},
|
|
131
|
-
prop(key, value) {
|
|
132
|
-
component.props[key] = value;
|
|
133
|
-
return this;
|
|
134
|
-
},
|
|
135
|
-
bind(prop, statePath, direction = 'one-way') {
|
|
136
|
-
if (!component.bindings) {
|
|
137
|
-
component.bindings = [];
|
|
138
|
-
}
|
|
139
|
-
component.bindings.push({ prop, statePath, direction });
|
|
140
|
-
return this;
|
|
141
|
-
},
|
|
142
|
-
on(event, action, params) {
|
|
143
|
-
if (!component.events) {
|
|
144
|
-
component.events = [];
|
|
145
|
-
}
|
|
146
|
-
component.events.push({ event, action, params });
|
|
147
|
-
return this;
|
|
148
|
-
},
|
|
149
|
-
child(childComponent) {
|
|
150
|
-
if (!component.children) {
|
|
151
|
-
component.children = [];
|
|
152
|
-
}
|
|
153
|
-
const child = 'build' in childComponent ? childComponent.build() : childComponent;
|
|
154
|
-
component.children.push(child);
|
|
155
|
-
return this;
|
|
156
|
-
},
|
|
157
|
-
when(condition) {
|
|
158
|
-
component.condition = { $expr: condition };
|
|
159
|
-
return this;
|
|
160
|
-
},
|
|
161
|
-
repeat(items, as, options) {
|
|
162
|
-
component.repeat = {
|
|
163
|
-
items,
|
|
164
|
-
as,
|
|
165
|
-
indexAs: options?.indexAs,
|
|
166
|
-
filter: options?.filter ? { $expr: options.filter } : undefined,
|
|
167
|
-
sort: options?.sort ? { $expr: options.sort } : undefined,
|
|
168
|
-
};
|
|
169
|
-
return this;
|
|
170
|
-
},
|
|
171
|
-
style(styles) {
|
|
172
|
-
component.style = styles;
|
|
173
|
-
return this;
|
|
174
|
-
},
|
|
175
|
-
className(className) {
|
|
176
|
-
component.className = className;
|
|
177
|
-
return this;
|
|
178
|
-
},
|
|
179
|
-
build() {
|
|
180
|
-
return component;
|
|
181
|
-
},
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Generate unique ID
|
|
186
|
-
*/
|
|
187
|
-
function generateId() {
|
|
188
|
-
return `comp_${Math.random().toString(36).substr(2, 9)}`;
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Fluent API for common patterns
|
|
192
|
-
*/
|
|
193
|
-
export const patterns = {
|
|
194
|
-
/** Create a form with inputs */
|
|
195
|
-
form: (fields, submitAction) => {
|
|
196
|
-
const editor = createVisualEditor();
|
|
197
|
-
const builder = editor.create();
|
|
198
|
-
// Add state for each field
|
|
199
|
-
fields.forEach((field) => {
|
|
200
|
-
builder.state(`form.${field.name}`, field.type === 'number' ? 'number' : 'string', '');
|
|
201
|
-
});
|
|
202
|
-
// Build form components
|
|
203
|
-
const formContainer = components.layout.Stack({ spacing: 4 })
|
|
204
|
-
.className('a2r-form');
|
|
205
|
-
fields.forEach((field) => {
|
|
206
|
-
formContainer.child(components.layout.Stack({ direction: 'vertical', spacing: 1 })
|
|
207
|
-
.child(components.typography.Label(field.label))
|
|
208
|
-
.child(components.input.Input({ type: field.type })
|
|
209
|
-
.bind('value', `form.${field.name}`, 'two-way')));
|
|
210
|
-
});
|
|
211
|
-
formContainer.child(components.input.Button('Submit', { variant: 'primary' })
|
|
212
|
-
.on('onClick', submitAction));
|
|
213
|
-
builder.add(formContainer);
|
|
214
|
-
return builder;
|
|
215
|
-
},
|
|
216
|
-
/** Create a data table */
|
|
217
|
-
dataTable: (dataPath, columns) => {
|
|
218
|
-
return components.display.Table([], [])
|
|
219
|
-
.bind('data', dataPath)
|
|
220
|
-
.prop('columns', columns);
|
|
221
|
-
},
|
|
222
|
-
/** Create a modal/dialog */
|
|
223
|
-
modal: (title, content, onClose) => {
|
|
224
|
-
return components.layout.Box({ padding: 4 })
|
|
225
|
-
.className('a2r-modal')
|
|
226
|
-
.child(components.layout.Stack({ direction: 'vertical', spacing: 2 })
|
|
227
|
-
.child(components.layout.Stack({ direction: 'horizontal', justify: 'between' })
|
|
228
|
-
.child(components.typography.Heading(title, 3))
|
|
229
|
-
.child(components.input.Button('×', { variant: 'ghost', size: 'sm' })
|
|
230
|
-
.on('onClick', onClose)))
|
|
231
|
-
.child(content));
|
|
232
|
-
},
|
|
233
|
-
/** Create a navigation menu */
|
|
234
|
-
navMenu: (items) => {
|
|
235
|
-
const list = components.layout.Stack({ direction: 'vertical', spacing: 1 })
|
|
236
|
-
.className('a2r-nav-menu');
|
|
237
|
-
items.forEach((item) => {
|
|
238
|
-
const btn = components.input.Button(item.label, { variant: 'ghost' })
|
|
239
|
-
.on('onClick', item.action);
|
|
240
|
-
if (item.icon) {
|
|
241
|
-
btn.prop('icon', item.icon);
|
|
242
|
-
}
|
|
243
|
-
list.child(btn);
|
|
244
|
-
});
|
|
245
|
-
return list;
|
|
246
|
-
},
|
|
247
|
-
};
|
|
248
|
-
// Export fluent API
|
|
249
|
-
export const ui = {
|
|
250
|
-
/** Create new UI */
|
|
251
|
-
create: (version) => createVisualEditor().create(version),
|
|
252
|
-
/** Load existing UI */
|
|
253
|
-
load: (root) => createVisualEditor().load(root),
|
|
254
|
-
/** Component builders */
|
|
255
|
-
components,
|
|
256
|
-
/** Pattern builders */
|
|
257
|
-
patterns,
|
|
258
|
-
};
|
|
259
|
-
//# sourceMappingURL=visual-editor.js.map
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Yjs/CRDT Adapter for A2R-IX
|
|
3
|
-
*
|
|
4
|
-
* Real-time collaborative state synchronization using Yjs.
|
|
5
|
-
*/
|
|
6
|
-
import type { StateStore, StateStoreConfig } from '../state/store';
|
|
7
|
-
import type { JSONPatch } from '../state/patch';
|
|
8
|
-
interface YDoc {
|
|
9
|
-
getMap(name: string): YMap;
|
|
10
|
-
on(event: string, callback: () => void): void;
|
|
11
|
-
off(event: string, callback: () => void): void;
|
|
12
|
-
transact(callback: () => void): void;
|
|
13
|
-
destroy(): void;
|
|
14
|
-
}
|
|
15
|
-
interface YMap {
|
|
16
|
-
set(key: string, value: unknown): void;
|
|
17
|
-
get(key: string): unknown;
|
|
18
|
-
has(key: string): boolean;
|
|
19
|
-
delete(key: string): void;
|
|
20
|
-
toJSON(): Record<string, unknown>;
|
|
21
|
-
observe(callback: (event: YMapEvent) => void): void;
|
|
22
|
-
unobserve(callback: (event: YMapEvent) => void): void;
|
|
23
|
-
}
|
|
24
|
-
interface YMapEvent {
|
|
25
|
-
changes: {
|
|
26
|
-
keys: Map<string, {
|
|
27
|
-
action: 'add' | 'update' | 'delete';
|
|
28
|
-
oldValue: unknown;
|
|
29
|
-
}>;
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
interface YProvider {
|
|
33
|
-
on(event: string, callback: () => void): void;
|
|
34
|
-
off(event: string, callback: () => void): void;
|
|
35
|
-
destroy(): void;
|
|
36
|
-
}
|
|
37
|
-
export interface YjsAdapterConfig {
|
|
38
|
-
/** Yjs document instance */
|
|
39
|
-
doc: YDoc;
|
|
40
|
-
/** Yjs provider (WebSocket, WebRTC, etc.) */
|
|
41
|
-
provider?: YProvider;
|
|
42
|
-
/** Map name for state storage */
|
|
43
|
-
mapName?: string;
|
|
44
|
-
/** User ID for awareness */
|
|
45
|
-
userId?: string;
|
|
46
|
-
/** User info for awareness */
|
|
47
|
-
userInfo?: Record<string, unknown>;
|
|
48
|
-
/** Conflict resolution strategy */
|
|
49
|
-
conflictResolution?: 'last-write-wins' | 'first-write-wins' | 'merge';
|
|
50
|
-
/** Batch updates (ms) */
|
|
51
|
-
batchDelay?: number;
|
|
52
|
-
}
|
|
53
|
-
export interface YjsAdapter {
|
|
54
|
-
/** Get local state store */
|
|
55
|
-
getStore(): StateStore;
|
|
56
|
-
/** Apply local patch (will sync to others) */
|
|
57
|
-
applyPatch(patch: JSONPatch): void;
|
|
58
|
-
/** Get current awareness state */
|
|
59
|
-
getAwareness(): Map<number, AwarenessState>;
|
|
60
|
-
/** Set local awareness state */
|
|
61
|
-
setAwareness(state: Partial<AwarenessState>): void;
|
|
62
|
-
/** Subscribe to awareness changes */
|
|
63
|
-
subscribeAwareness(callback: (states: Map<number, AwarenessState>) => void): () => void;
|
|
64
|
-
/** Get sync status */
|
|
65
|
-
getSyncStatus(): 'synced' | 'syncing' | 'disconnected';
|
|
66
|
-
/** Subscribe to sync status changes */
|
|
67
|
-
subscribeSyncStatus(callback: (status: 'synced' | 'syncing' | 'disconnected') => void): () => void;
|
|
68
|
-
/** Destroy adapter */
|
|
69
|
-
destroy(): void;
|
|
70
|
-
}
|
|
71
|
-
export interface AwarenessState {
|
|
72
|
-
user?: {
|
|
73
|
-
id: string;
|
|
74
|
-
name?: string;
|
|
75
|
-
color?: string;
|
|
76
|
-
[key: string]: unknown;
|
|
77
|
-
};
|
|
78
|
-
cursor?: {
|
|
79
|
-
x: number;
|
|
80
|
-
y: number;
|
|
81
|
-
componentId?: string;
|
|
82
|
-
};
|
|
83
|
-
selection?: string[];
|
|
84
|
-
[key: string]: unknown;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Create Yjs adapter for collaborative state
|
|
88
|
-
*/
|
|
89
|
-
export declare function createYjsAdapter(config: YjsAdapterConfig): YjsAdapter;
|
|
90
|
-
/**
|
|
91
|
-
* Create collaborative state store
|
|
92
|
-
*/
|
|
93
|
-
export declare function createCollaborativeStore(yjsConfig: YjsAdapterConfig, localConfig?: Omit<StateStoreConfig, 'initial' | 'variables'>): StateStore;
|
|
94
|
-
export {};
|
|
95
|
-
//# sourceMappingURL=yjs-adapter.d.ts.map
|
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Yjs/CRDT Adapter for A2R-IX
|
|
3
|
-
*
|
|
4
|
-
* Real-time collaborative state synchronization using Yjs.
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Create Yjs adapter for collaborative state
|
|
8
|
-
*/
|
|
9
|
-
export function createYjsAdapter(config) {
|
|
10
|
-
const { doc, provider, mapName = 'a2r-ix-state' } = config;
|
|
11
|
-
const ymap = doc.getMap(mapName);
|
|
12
|
-
// Local state store wrapper
|
|
13
|
-
let localState = {};
|
|
14
|
-
const subscribers = new Map();
|
|
15
|
-
const syncStatusSubscribers = new Set();
|
|
16
|
-
const awarenessSubscribers = new Set();
|
|
17
|
-
let syncStatus = 'syncing';
|
|
18
|
-
const awarenessMap = new Map();
|
|
19
|
-
const clientId = 0;
|
|
20
|
-
/**
|
|
21
|
-
* Initialize from Yjs map
|
|
22
|
-
*/
|
|
23
|
-
function initialize() {
|
|
24
|
-
// Load initial state
|
|
25
|
-
localState = { ...ymap.toJSON() };
|
|
26
|
-
// Observe Yjs changes
|
|
27
|
-
ymap.observe((event) => {
|
|
28
|
-
doc.transact(() => {
|
|
29
|
-
event.changes.keys.forEach((change, key) => {
|
|
30
|
-
const newValue = ymap.get(key);
|
|
31
|
-
if (change.action === 'delete') {
|
|
32
|
-
delete localState[key];
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
localState[key] = newValue;
|
|
36
|
-
}
|
|
37
|
-
// Notify local subscribers
|
|
38
|
-
notifySubscribers(key, newValue);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
// Set up provider sync status
|
|
43
|
-
if (provider) {
|
|
44
|
-
provider.on('sync', () => {
|
|
45
|
-
updateSyncStatus('synced');
|
|
46
|
-
});
|
|
47
|
-
provider.on('disconnect', () => {
|
|
48
|
-
updateSyncStatus('disconnected');
|
|
49
|
-
});
|
|
50
|
-
provider.on('connect', () => {
|
|
51
|
-
updateSyncStatus('syncing');
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Update sync status
|
|
57
|
-
*/
|
|
58
|
-
function updateSyncStatus(status) {
|
|
59
|
-
syncStatus = status;
|
|
60
|
-
syncStatusSubscribers.forEach((cb) => cb(status));
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Notify subscribers
|
|
64
|
-
*/
|
|
65
|
-
function notifySubscribers(path, value) {
|
|
66
|
-
const pathSubscribers = subscribers.get(path);
|
|
67
|
-
if (pathSubscribers) {
|
|
68
|
-
pathSubscribers.forEach((cb) => cb(value));
|
|
69
|
-
}
|
|
70
|
-
// Notify parent path subscribers
|
|
71
|
-
const parts = path.split('.');
|
|
72
|
-
while (parts.length > 1) {
|
|
73
|
-
parts.pop();
|
|
74
|
-
const parentPath = parts.join('.');
|
|
75
|
-
const parentSubscribers = subscribers.get(parentPath);
|
|
76
|
-
if (parentSubscribers) {
|
|
77
|
-
const parentValue = getValue(parentPath);
|
|
78
|
-
parentSubscribers.forEach((cb) => cb(parentValue));
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Get value at path
|
|
84
|
-
*/
|
|
85
|
-
function getValue(path) {
|
|
86
|
-
const parts = path.split('.');
|
|
87
|
-
let current = localState;
|
|
88
|
-
for (const part of parts) {
|
|
89
|
-
if (current && typeof current === 'object') {
|
|
90
|
-
current = current[part];
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return current;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Set value at path
|
|
100
|
-
*/
|
|
101
|
-
function setValue(path, value) {
|
|
102
|
-
const parts = path.split('.');
|
|
103
|
-
doc.transact(() => {
|
|
104
|
-
if (parts.length === 1) {
|
|
105
|
-
if (value === undefined) {
|
|
106
|
-
ymap.delete(path);
|
|
107
|
-
delete localState[path];
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
ymap.set(path, value);
|
|
111
|
-
localState[path] = value;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
// Handle nested paths
|
|
116
|
-
const rootKey = parts[0];
|
|
117
|
-
let root = ymap.get(rootKey) || {};
|
|
118
|
-
// Clone to avoid modifying shared Yjs object directly
|
|
119
|
-
root = { ...root };
|
|
120
|
-
let current = root;
|
|
121
|
-
for (let i = 1; i < parts.length - 1; i++) {
|
|
122
|
-
const part = parts[i];
|
|
123
|
-
if (!current[part] || typeof current[part] !== 'object') {
|
|
124
|
-
current[part] = {};
|
|
125
|
-
}
|
|
126
|
-
current = current[part];
|
|
127
|
-
}
|
|
128
|
-
if (value === undefined) {
|
|
129
|
-
delete current[parts[parts.length - 1]];
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
current[parts[parts.length - 1]] = value;
|
|
133
|
-
}
|
|
134
|
-
ymap.set(rootKey, root);
|
|
135
|
-
localState[rootKey] = root;
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
notifySubscribers(path, value);
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Apply JSON Patch
|
|
142
|
-
*/
|
|
143
|
-
function applyPatch(patch) {
|
|
144
|
-
doc.transact(() => {
|
|
145
|
-
patch.forEach((op) => {
|
|
146
|
-
const path = op.path.slice(1).replace(/\//g, '.');
|
|
147
|
-
switch (op.op) {
|
|
148
|
-
case 'add':
|
|
149
|
-
case 'replace':
|
|
150
|
-
setValue(path, op.value);
|
|
151
|
-
break;
|
|
152
|
-
case 'remove':
|
|
153
|
-
setValue(path, undefined);
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Create state store interface
|
|
161
|
-
*/
|
|
162
|
-
function getStore() {
|
|
163
|
-
return {
|
|
164
|
-
get: (path) => getValue(path),
|
|
165
|
-
set: (path, value) => setValue(path, value),
|
|
166
|
-
subscribe: (path, callback) => {
|
|
167
|
-
if (!subscribers.has(path)) {
|
|
168
|
-
subscribers.set(path, new Set());
|
|
169
|
-
}
|
|
170
|
-
subscribers.get(path).add(callback);
|
|
171
|
-
return () => {
|
|
172
|
-
subscribers.get(path)?.delete(callback);
|
|
173
|
-
};
|
|
174
|
-
},
|
|
175
|
-
batch: (updates) => {
|
|
176
|
-
doc.transact(() => {
|
|
177
|
-
Object.entries(updates).forEach(([path, value]) => {
|
|
178
|
-
setValue(path, value);
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
},
|
|
182
|
-
snapshot: () => ({ ...localState }),
|
|
183
|
-
restore: (snapshot) => {
|
|
184
|
-
doc.transact(() => {
|
|
185
|
-
Object.entries(snapshot).forEach(([key, value]) => {
|
|
186
|
-
ymap.set(key, value);
|
|
187
|
-
localState[key] = value;
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
},
|
|
191
|
-
reset: () => {
|
|
192
|
-
doc.transact(() => {
|
|
193
|
-
Object.keys(ymap.toJSON()).forEach((key) => {
|
|
194
|
-
ymap.delete(key);
|
|
195
|
-
});
|
|
196
|
-
localState = {};
|
|
197
|
-
});
|
|
198
|
-
},
|
|
199
|
-
compute: () => { },
|
|
200
|
-
bind: () => { },
|
|
201
|
-
getBindings: () => [],
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Get awareness state
|
|
206
|
-
*/
|
|
207
|
-
function getAwareness() {
|
|
208
|
-
return new Map(awarenessMap);
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Set awareness state
|
|
212
|
-
*/
|
|
213
|
-
function setAwareness(state) {
|
|
214
|
-
const current = awarenessMap.get(clientId) || {};
|
|
215
|
-
awarenessMap.set(clientId, { ...current, ...state });
|
|
216
|
-
// Broadcast to others (would use y-protocols in production)
|
|
217
|
-
awarenessSubscribers.forEach((cb) => cb(new Map(awarenessMap)));
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Subscribe to awareness changes
|
|
221
|
-
*/
|
|
222
|
-
function subscribeAwareness(callback) {
|
|
223
|
-
awarenessSubscribers.add(callback);
|
|
224
|
-
return () => awarenessSubscribers.delete(callback);
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Get sync status
|
|
228
|
-
*/
|
|
229
|
-
function getSyncStatus() {
|
|
230
|
-
return syncStatus;
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Subscribe to sync status
|
|
234
|
-
*/
|
|
235
|
-
function subscribeSyncStatus(callback) {
|
|
236
|
-
syncStatusSubscribers.add(callback);
|
|
237
|
-
return () => syncStatusSubscribers.delete(callback);
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Destroy adapter
|
|
241
|
-
*/
|
|
242
|
-
function destroy() {
|
|
243
|
-
subscribers.clear();
|
|
244
|
-
syncStatusSubscribers.clear();
|
|
245
|
-
awarenessSubscribers.clear();
|
|
246
|
-
if (provider) {
|
|
247
|
-
provider.destroy();
|
|
248
|
-
}
|
|
249
|
-
// Clear all keys from ymap
|
|
250
|
-
const keys = Object.keys(ymap.toJSON());
|
|
251
|
-
keys.forEach((key) => ymap.delete(key));
|
|
252
|
-
}
|
|
253
|
-
// Initialize
|
|
254
|
-
initialize();
|
|
255
|
-
// Set initial user awareness
|
|
256
|
-
if (config.userId) {
|
|
257
|
-
setAwareness({
|
|
258
|
-
user: {
|
|
259
|
-
id: config.userId,
|
|
260
|
-
...config.userInfo,
|
|
261
|
-
},
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
return {
|
|
265
|
-
getStore,
|
|
266
|
-
applyPatch,
|
|
267
|
-
getAwareness,
|
|
268
|
-
setAwareness,
|
|
269
|
-
subscribeAwareness,
|
|
270
|
-
getSyncStatus,
|
|
271
|
-
subscribeSyncStatus,
|
|
272
|
-
destroy,
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* Create collaborative state store
|
|
277
|
-
*/
|
|
278
|
-
export function createCollaborativeStore(yjsConfig, localConfig = {}) {
|
|
279
|
-
const adapter = createYjsAdapter(yjsConfig);
|
|
280
|
-
return adapter.getStore();
|
|
281
|
-
}
|
|
282
|
-
//# sourceMappingURL=yjs-adapter.js.map
|