@hamak/ui-store-impl 0.4.7 → 0.4.19

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.
Files changed (38) hide show
  1. package/dist/core/store-manager.d.ts +3 -0
  2. package/dist/core/store-manager.d.ts.map +1 -1
  3. package/dist/core/store-manager.js +7 -0
  4. package/dist/es2015/core/store-manager.js +7 -0
  5. package/dist/es2015/plugin/store-plugin-factory.js +14 -1
  6. package/dist/plugin/store-plugin-factory.d.ts +1 -0
  7. package/dist/plugin/store-plugin-factory.d.ts.map +1 -1
  8. package/dist/plugin/store-plugin-factory.js +14 -1
  9. package/package.json +9 -6
  10. package/.turbo/turbo-build.log +0 -1
  11. package/.turbo/turbo-test.log +0 -115
  12. package/CHANGELOG.md +0 -41
  13. package/project.json +0 -24
  14. package/src/core/index.ts +0 -3
  15. package/src/core/middleware-registry.test.ts +0 -247
  16. package/src/core/middleware-registry.ts +0 -64
  17. package/src/core/reducer-registry.test.ts +0 -215
  18. package/src/core/reducer-registry.ts +0 -71
  19. package/src/core/store-manager.test.ts +0 -288
  20. package/src/core/store-manager.ts +0 -125
  21. package/src/extensions/store-extensions.ts +0 -90
  22. package/src/fs/commands/fs-commands.ts +0 -389
  23. package/src/fs/commands/structure-commands.ts +0 -105
  24. package/src/fs/core/fs-adapter.ts +0 -180
  25. package/src/fs/core/fs-facade.ts +0 -100
  26. package/src/fs/index.ts +0 -14
  27. package/src/fs/utils/data-updater.ts +0 -273
  28. package/src/fs/utils/deep-equal.ts +0 -35
  29. package/src/index.ts +0 -9
  30. package/src/middleware/event-bridge-middleware.test.ts +0 -131
  31. package/src/middleware/event-bridge-middleware.ts +0 -26
  32. package/src/middleware/index.ts +0 -6
  33. package/src/middleware/logger-middleware.test.ts +0 -129
  34. package/src/middleware/logger-middleware.ts +0 -25
  35. package/src/plugin/index.ts +0 -5
  36. package/src/plugin/store-plugin-factory.ts +0 -142
  37. package/tsconfig.es2015.json +0 -24
  38. package/tsconfig.json +0 -19
@@ -1,125 +0,0 @@
1
- /**
2
- * Store Manager Implementation
3
- */
4
-
5
- import { createStore, applyMiddleware, compose, type Store, type Reducer } from 'redux';
6
- import type { IStoreManager, StoreConfig, RootState, AppAction } from '@hamak/ui-store-api';
7
- import { MiddlewareRegistry } from './middleware-registry';
8
- import { ReducerRegistry } from './reducer-registry';
9
-
10
- export class StoreManager implements IStoreManager {
11
- private store: Store<RootState, AppAction> | null = null;
12
- private middlewareRegistry: MiddlewareRegistry;
13
- private reducerRegistry: ReducerRegistry;
14
- private initialized = false;
15
- private config: StoreConfig | null = null;
16
-
17
- constructor() {
18
- this.middlewareRegistry = new MiddlewareRegistry();
19
- this.reducerRegistry = new ReducerRegistry((rootReducer: any) => {
20
- // Hot replacement callback
21
- if (this.store) {
22
- this.store.replaceReducer(rootReducer);
23
- }
24
- });
25
- }
26
-
27
- getMiddlewareRegistry() {
28
- return this.middlewareRegistry;
29
- }
30
-
31
- getReducerRegistry() {
32
- return this.reducerRegistry;
33
- }
34
-
35
- isInitialized(): boolean {
36
- return this.initialized;
37
- }
38
-
39
- initialize(config: StoreConfig = {}): Store<RootState, AppAction> {
40
- if (this.initialized) {
41
- throw new Error('[StoreManager] Store already initialized');
42
- }
43
-
44
- this.config = config;
45
-
46
- // Get all middleware in priority order
47
- const middleware = this.middlewareRegistry.getAll();
48
-
49
- // Lock the middleware registry
50
- this.middlewareRegistry.lock();
51
-
52
- // Get combined reducer
53
- const rootReducer = this.reducerRegistry.getCombinedReducer();
54
-
55
- // Create enhancers
56
- const enhancers = config.enhancers || [];
57
-
58
- // Setup Redux DevTools
59
- let composeEnhancers = compose;
60
- if (config.devTools !== false && typeof window !== 'undefined') {
61
- const devToolsExtension = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
62
- if (devToolsExtension) {
63
- composeEnhancers = devToolsExtension({
64
- trace: true,
65
- traceLimit: 25,
66
- });
67
- }
68
- }
69
-
70
- // Create store
71
- const enhancer = composeEnhancers(
72
- applyMiddleware(...middleware),
73
- ...enhancers
74
- ) as any;
75
-
76
- this.store = createStore(
77
- rootReducer as any,
78
- config.preloadedState,
79
- enhancer
80
- );
81
-
82
- this.initialized = true;
83
-
84
- console.log('[StoreManager] Store initialized with:', {
85
- reducers: this.reducerRegistry.getAllRegistrations().map(r => r.key),
86
- middleware: this.middlewareRegistry.getAllRegistrations().map(m => ({
87
- id: m.id,
88
- priority: m.priority,
89
- plugin: m.plugin,
90
- })),
91
- devTools: config.devTools !== false,
92
- });
93
-
94
- return this.store;
95
- }
96
-
97
- getStore(): Store<RootState, AppAction> {
98
- if (!this.store) {
99
- throw new Error('[StoreManager] Store not initialized. Call initialize() first.');
100
- }
101
- return this.store;
102
- }
103
-
104
- dispatch<A extends AppAction>(action: A): A {
105
- return this.getStore().dispatch(action);
106
- }
107
-
108
- getState<S = RootState>(): S {
109
- return this.getStore().getState() as S;
110
- }
111
-
112
- subscribe(listener: () => void): () => void {
113
- return this.getStore().subscribe(listener);
114
- }
115
-
116
- replaceReducer(nextReducer: Reducer<RootState, AppAction>): void {
117
- this.getStore().replaceReducer(nextReducer);
118
- }
119
-
120
- destroy(): void {
121
- this.store = null;
122
- this.initialized = false;
123
- console.log('[StoreManager] Store destroyed');
124
- }
125
- }
@@ -1,90 +0,0 @@
1
- /**
2
- * Store extensions collector
3
- */
4
-
5
- import type {
6
- IMiddlewareRegistry,
7
- IReducerRegistry,
8
- StoreExtensionsRegistry,
9
- StorePluginExtensions,
10
- StoreMiddlewareExtension,
11
- } from '@hamak/ui-store-api';
12
-
13
- interface StoreExtensionsEntry {
14
- source: string;
15
- extensions: StorePluginExtensions;
16
- }
17
-
18
- /**
19
- * Collects middleware and reducer contributions until the store boots
20
- */
21
- export class StoreExtensionsCollector implements StoreExtensionsRegistry {
22
- private entries: StoreExtensionsEntry[] = [];
23
-
24
- register(source: string, extensions: StorePluginExtensions): void {
25
- const hasMiddleware = Boolean(extensions.middleware?.length);
26
- const hasReducers = Boolean(extensions.reducers && Object.keys(extensions.reducers).length);
27
-
28
- if (!hasMiddleware && !hasReducers) {
29
- return;
30
- }
31
-
32
- this.entries.push({
33
- source,
34
- extensions: {
35
- middleware: extensions.middleware,
36
- reducers: extensions.reducers,
37
- },
38
- });
39
- }
40
-
41
- /**
42
- * Drain collected extensions (used internally by the plugin)
43
- */
44
- drain(): StoreExtensionsEntry[] {
45
- const snapshot = this.entries;
46
- this.entries = [];
47
- return snapshot;
48
- }
49
- }
50
-
51
- function withSourceMetadata(
52
- middleware: StoreMiddlewareExtension | undefined,
53
- source: string
54
- ): StoreMiddlewareExtension | undefined {
55
- if (!middleware) {
56
- return undefined;
57
- }
58
-
59
- return {
60
- plugin: middleware.plugin ?? source,
61
- ...middleware,
62
- };
63
- }
64
-
65
- export function applyStoreExtensions(
66
- collector: StoreExtensionsCollector,
67
- middlewareRegistry: IMiddlewareRegistry,
68
- reducerRegistry: IReducerRegistry
69
- ): void {
70
- const entries = collector.drain();
71
-
72
- entries.forEach(({ source, extensions }) => {
73
- extensions.middleware?.forEach((mw) => {
74
- const middleware = withSourceMetadata(mw, source);
75
- if (middleware) {
76
- middlewareRegistry.register(middleware);
77
- }
78
- });
79
-
80
- if (extensions.reducers) {
81
- Object.entries(extensions.reducers).forEach(([key, reducer]) => {
82
- reducerRegistry.register(key, reducer);
83
- });
84
- }
85
- });
86
- }
87
-
88
- export function createStoreExtensionsCollector(): StoreExtensionsCollector {
89
- return new StoreExtensionsCollector();
90
- }
@@ -1,389 +0,0 @@
1
- import {
2
- DirectoryNode,
3
- FileNode,
4
- FileSystemNode,
5
- FileSystemState,
6
- FileContentSchema,
7
- fileSystemNodeInitialState,
8
- FileSystemNodeState
9
- } from '@hamak/ui-store-api';
10
- import { Pathway, Holder, pathSteps, parentPathSteps } from '@hamak/shared-utils';
11
- import { StructureNodeCommand } from './structure-commands';
12
- import { DataUpdater } from '../utils/data-updater';
13
- import { produce, current, isDraft, original } from 'immer';
14
- import { deepEqual } from '../utils/deep-equal';
15
-
16
- /**
17
- * Base interface for filesystem commands
18
- */
19
- export interface FsCommandBase {
20
- name : 'mkdir' | 'set-file' | 'remove' | 'update-file-content' | 'set-file-content'
21
- path : string | string[]
22
- }
23
-
24
- /**
25
- * Create directory command
26
- */
27
- export interface MkdirCommand extends FsCommandBase{
28
- name : 'mkdir'
29
- parents? : boolean
30
- }
31
-
32
- /**
33
- * Remove file or directory command
34
- */
35
- export interface RemoveCommand extends FsCommandBase{
36
- name : 'remove'
37
- recursive? : boolean
38
- }
39
-
40
- /**
41
- * Set file command (create or update)
42
- */
43
- export interface SetFileCommand extends FsCommandBase{
44
- name : 'set-file'
45
- content : any
46
- schema : FileContentSchema
47
- override? : boolean
48
- contentIsPresent? : boolean
49
- }
50
-
51
- /**
52
- * Update file content with structure command
53
- */
54
- export interface UpdateFileContentCommand extends FsCommandBase{
55
- name : 'update-file-content'
56
- contentCommand : StructureNodeCommand
57
- }
58
-
59
- /**
60
- * Set file content directly
61
- */
62
- export interface SetFileContentCommand extends FsCommandBase{
63
- name : 'set-file-content'
64
- content : any,
65
- fromRemote?: boolean
66
- }
67
-
68
- /**
69
- * Union type for all filesystem commands
70
- */
71
- export type FileSystemCommand =
72
- | MkdirCommand
73
- | RemoveCommand
74
- | SetFileCommand
75
- | UpdateFileContentCommand
76
- | SetFileContentCommand
77
-
78
- // Re-export path utilities from shared-utils for internal use
79
- export { pathSteps, parentPathSteps } from '@hamak/shared-utils';
80
-
81
- /**
82
- * Get filesystem node at path
83
- */
84
- export function getFileSystemNode(fsNode: FileSystemNode, path : string | string[]) : FileSystemNode | undefined {
85
- const steps = pathSteps(path)
86
- let result : FileSystemNode | undefined = fsNode
87
- for(let i = 0; i < steps.length; i++) {
88
- const step = steps[i]
89
- if (result === undefined){
90
- return undefined
91
- } else if(result.type === 'directory'){
92
- result = result.children[step]
93
- } else {
94
- return undefined
95
- }
96
- }
97
-
98
- return result
99
- }
100
-
101
- /**
102
- * Create a directory node
103
- */
104
- function createDirectoryNode(step: string) : DirectoryNode{
105
- return {
106
- type: 'directory',
107
- state: fileSystemNodeInitialState(),
108
- name: step,
109
- children: {}
110
- };
111
- }
112
-
113
- /**
114
- * Create a file node
115
- */
116
- function createFileNode(name: string, content : any, schema : FileContentSchema, state : FileSystemNodeState) : FileNode{
117
- return {type: 'file', name, content, schema, state};
118
- }
119
-
120
- /**
121
- * FileSystem command handler - executes filesystem operations
122
- */
123
- export class FileSystemCommandHandler {
124
- readonly contentCommandHandler = new FileContentCommandHandler()
125
-
126
- execute(state: FileSystemState, command: FileSystemCommand): FileSystemState {
127
- switch (command.name) {
128
- case 'mkdir': return this.executeMkdir(state, command)
129
- case 'set-file': return this.executeSetFile(state, command)
130
- case 'update-file-content' : return this.executeContentCommand(state, command)
131
- case 'set-file-content' : return this.executeSetContentCommand(state, command)
132
- case 'remove': return this.executeRemove(state, command)
133
- }
134
- }
135
-
136
- private executeMkdir(state: FileSystemState, command : MkdirCommand) : FileSystemState{
137
- const {path, parents} = command
138
- const steps = pathSteps(path)
139
-
140
- return produce(state, draft => {
141
- const {root} = draft
142
- let dir = root
143
- for(let i = 0; i < steps.length; i++){
144
- const step = steps[i]
145
- if(i + 1 === steps.length){
146
- // Last step is the element to create
147
- if(dir.children[step] === undefined){
148
- dir.children[step] = createDirectoryNode(step)
149
- }
150
- }else {
151
- let child = dir.children[step]
152
- if(child === undefined){
153
- if(parents === true){
154
- child = createDirectoryNode(step)
155
- dir.children[step] = child
156
- }else {
157
- return
158
- }
159
- }else if(child.type === 'directory'){
160
- dir = child
161
- }else {
162
- return;
163
- }
164
-
165
- dir = child
166
- }
167
- }
168
- })
169
- }
170
-
171
-
172
- private executeRemove(state: FileSystemState, command : RemoveCommand) : FileSystemState{
173
- const {path, recursive} = command
174
- const steps = pathSteps(path)
175
-
176
- return produce(state, draft => {
177
- const {root} = draft
178
- const parentDir = getFileSystemNode(root, steps.slice(0, steps.length - 1))
179
- if(parentDir === undefined ){
180
- return
181
- }
182
-
183
- if(parentDir.type === 'directory'){
184
- const last = steps[steps.length - 1]
185
- const child = parentDir.children[last]
186
- if(child?.type === 'directory'
187
- && Object.keys(child.children).length > 0
188
- && !(recursive === true) ){
189
- return;
190
- }
191
-
192
- delete parentDir.children[last]
193
- }
194
- })
195
- }
196
-
197
- private executeSetFile(state: FileSystemState, command : SetFileCommand) : FileSystemState{
198
- const {path, content, schema, override, contentIsPresent} = command
199
- const steps = pathSteps(path)
200
-
201
- return produce(state, draft => {
202
- const {root} = draft
203
- const parentPath = steps.slice(0, steps.length - 1);
204
- const parentDir = getFileSystemNode(root, parentPath)
205
- if(parentDir === undefined ){
206
- return
207
- }
208
-
209
- if(parentDir.type === 'directory'){
210
- const last = steps[steps.length - 1]
211
- const child = parentDir.children[last]
212
- if(child === undefined || override === true){
213
- parentDir.children[last] = createFileNode(last, content, schema, fileSystemNodeInitialState(contentIsPresent))
214
- } else {
215
- console.warn(`File already exists at location`, path)
216
- }
217
- }else{
218
- console.warn(`Parent file is not directory`, parentPath)
219
- }
220
- })
221
- }
222
-
223
-
224
- private executeContentCommand(state: FileSystemState, command : UpdateFileContentCommand) : FileSystemState{
225
- const {path, contentCommand} = command
226
-
227
- return produce(state, draft => {
228
- const {root} = draft
229
- const fileNode = getFileSystemNode(root, path)
230
-
231
- if(fileNode !== undefined){
232
- if(fileNode.type === 'file'){
233
- this.contentCommandHandler.execute(fileNode, contentCommand);
234
-
235
- const previousFile = getFileSystemNode(state.root, path)
236
- const previousContent = previousFile?.type === "file" ? previousFile.content : undefined
237
-
238
- this.contentMayChange(fileNode);
239
- }else{
240
- console.warn(`Not a file at location`, path)
241
- }
242
- }else{
243
- console.warn(`No file found at location`, path)
244
- }
245
-
246
- })
247
- }
248
-
249
-
250
- private contentMayChange(fileNode: FileNode) {
251
- const changed = ! deepEqual(this.original(fileNode.content), this.current(fileNode.content))
252
- if(changed){
253
- if (fileNode.state === undefined) {
254
- fileNode.state = fileSystemNodeInitialState()
255
- }
256
- fileNode.state.contentHistory.push(this.original(fileNode.content))
257
-
258
- // check compared to memo modification status
259
- if (fileNode.state.memo !== undefined) {
260
- const memo = fileNode.state.memo
261
- memo.modified = !deepEqual(this.current(memo.originalContent), this.current(fileNode.content))
262
- }
263
- }
264
- }
265
-
266
- private executeSetContentCommand(state: FileSystemState, command : SetFileContentCommand) : FileSystemState{
267
- const {path, content, fromRemote} = command
268
-
269
- return produce(state, draft => {
270
- const {root} = draft
271
- const fileNode = getFileSystemNode(root, path)
272
-
273
- if(fileNode !== undefined){
274
- if(fileNode.type === 'file'){
275
- fileNode.content = content
276
- if(fileNode.state === undefined){
277
- fileNode.state = fileSystemNodeInitialState(true)
278
- }
279
- if(fromRemote){
280
- fileNode.state.contentLoaded = true
281
- if(fileNode.state.memo === undefined){
282
- fileNode.state.memo = {originalContent: {value: content}, modified: false}
283
- } else {
284
- const memo = fileNode.state.memo
285
- memo.originalContent = {value: content}
286
- memo.modified = false
287
- }
288
- } else {
289
- this.contentMayChange(fileNode)
290
- }
291
- }else{
292
- console.warn(`Not a file at location`, path)
293
- }
294
- }else{
295
- console.warn(`No file found at location`, path)
296
- }
297
-
298
- })
299
- }
300
-
301
- protected current<T = any>(o : T):T{
302
- if(o === null || o === undefined){
303
- return o
304
- }
305
-
306
- return isDraft(o) ? current(o) : o
307
- }
308
-
309
- protected original<T = any>(o : T):T | undefined{
310
- if(o === null || o === undefined){
311
- return o
312
- }
313
-
314
- return isDraft(o) ? original(o) : o
315
- }
316
- }
317
-
318
- /**
319
- * File content command handler - handles structure commands on file content
320
- */
321
- export class FileContentCommandHandler {
322
- readonly updater = new DataUpdater()
323
-
324
- execute(file : FileNode, command: StructureNodeCommand) {
325
- switch (command.name) {
326
- case 'add-at':{
327
- this.executeAdd(file, command)
328
- }break
329
- case 'insert-at':{
330
- this.executeInsert(file, command)
331
- }break
332
- case 'set-at':{
333
- this.executeSet(file, command)
334
- } break
335
- case 'delete-at': {
336
- this.executeDelete(file, command)
337
- } break
338
- case 'batch-update': {
339
- this.executeBatch(file, command)
340
- } break
341
- }
342
- }
343
-
344
- private executeDelete(file : FileNode, command: any) {
345
- const {itinerary} = command
346
- if (itinerary === undefined) {
347
- file.content = undefined
348
- }
349
-
350
- const {content} = file
351
- this.updater.executeDelete(content, itinerary)
352
- }
353
-
354
- private executeSet(file : FileNode, command: any) {
355
- const {itinerary, value} = command
356
- if (itinerary === undefined) {
357
- file.content = value
358
- }
359
-
360
- const {content} = file
361
- this.updater.executeSet(content, itinerary, value)
362
- }
363
-
364
- private executeAdd(file: FileNode, command: any) {
365
- const {itinerary, value} = command
366
-
367
- const {content} = file
368
- this.updater.executeAdd(content, itinerary, value)
369
- }
370
-
371
- private executeInsert(file: FileNode, command: any) {
372
- const {itinerary, value} = command
373
- if (itinerary === undefined) {
374
- return
375
- }
376
-
377
- const {content} = file
378
- this.updater.executeInsert(content, itinerary, value)
379
- }
380
-
381
- /**
382
- * Executes a batch of commands, rebasing each on previous mutations.
383
- */
384
- public executeBatch(file: FileNode, command: any): void {
385
- const { content } = file;
386
- this.updater.executeBatch(content, command);
387
- }
388
-
389
- }
@@ -1,105 +0,0 @@
1
- import { Itinerary, StackElement } from '@hamak/shared-utils';
2
-
3
- /**
4
- * Base interface for structure node commands
5
- */
6
- export interface StructureNodeCommandBase {
7
- name: "add-at" | "set-at" | "delete-at" | 'insert-at' | "batch-update"
8
- }
9
-
10
- /**
11
- * Base interface for unitary (single operation) commands
12
- */
13
- export interface UnitaryStructureNodeCommandBase extends StructureNodeCommandBase {
14
- name: "add-at" | "set-at" | "delete-at" | 'insert-at'
15
- itinerary: Itinerary
16
- }
17
-
18
- /**
19
- * Base interface for commands that insert/update values
20
- */
21
- export interface StructureNodeUpsertCommandBase extends UnitaryStructureNodeCommandBase{
22
- name: "add-at" | "set-at" | 'insert-at'
23
- prototypes? : StackElement<any>
24
- }
25
-
26
- /**
27
- * Add a value at the specified itinerary
28
- */
29
- export interface AddStructureNodeCommand extends StructureNodeUpsertCommandBase {
30
- name: "add-at"
31
- value: any
32
- }
33
-
34
- /**
35
- * Insert a value at the specified position
36
- */
37
- export interface InsertStructureNodeCommand extends StructureNodeUpsertCommandBase {
38
- name: "insert-at"
39
- value: any
40
- }
41
-
42
- /**
43
- * Set a value at the specified itinerary
44
- */
45
- export interface SetStructureNodeCommand extends StructureNodeUpsertCommandBase {
46
- name: "set-at"
47
- value: any
48
- }
49
-
50
- /**
51
- * Delete a value at the specified itinerary
52
- */
53
- export interface DeleteStructureNodeCommand extends UnitaryStructureNodeCommandBase {
54
- name: "delete-at"
55
- }
56
-
57
- /**
58
- * Batch update multiple operations
59
- */
60
- export interface BatchUpdateStructureNodeCommand extends StructureNodeCommandBase {
61
- name: "batch-update"
62
- autoRebase?: boolean
63
- commands: UnitaryStructureNodeCommand[]
64
- }
65
-
66
- /**
67
- * Union type for unitary structure node commands
68
- */
69
- export type UnitaryStructureNodeCommand =
70
- | AddStructureNodeCommand
71
- | InsertStructureNodeCommand
72
- | SetStructureNodeCommand
73
- | DeleteStructureNodeCommand
74
-
75
- /**
76
- * Union type for all structure node commands
77
- */
78
- export type StructureNodeCommand = UnitaryStructureNodeCommand | BatchUpdateStructureNodeCommand
79
-
80
- /**
81
- * Helper class for creating structure node commands
82
- */
83
- export class StructureNodeCommandHelper {
84
- addNode(itinerary : Itinerary, value : any, prototypes?: StackElement<any>) : AddStructureNodeCommand{
85
- return {name:'add-at', itinerary, value, prototypes}
86
- }
87
-
88
- insertNode(itinerary : Itinerary, value : any, prototypes?: StackElement<any>) : InsertStructureNodeCommand{
89
- return {name:'insert-at', itinerary, value, prototypes}
90
- }
91
-
92
- setNode(itinerary : Itinerary, value : any, prototypes?: StackElement<any>) : SetStructureNodeCommand{
93
- return {name:'set-at', itinerary, value, prototypes}
94
- }
95
-
96
- deleteNode(itinerary : Itinerary) : DeleteStructureNodeCommand{
97
- return {name:'delete-at', itinerary}
98
- }
99
-
100
- batchUpdate(commands : UnitaryStructureNodeCommand[], autoRebase = false) : BatchUpdateStructureNodeCommand{
101
- return {name:'batch-update', commands, autoRebase}
102
- }
103
- }
104
-
105
- export const structs = new StructureNodeCommandHelper()