@hamak/ui-remote-resource-impl 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 (41) hide show
  1. package/dist/es2015/index.js +33 -0
  2. package/dist/es2015/middleware/entity-middleware.js +209 -0
  3. package/dist/es2015/middleware/entity-sync-middleware.js +36 -0
  4. package/dist/es2015/middleware/resource-middleware.js +111 -0
  5. package/dist/es2015/middleware/sync-middleware.js +85 -0
  6. package/dist/es2015/plugin/resource-plugin-factory.js +151 -0
  7. package/dist/es2015/providers/mock-resource-provider.js +215 -0
  8. package/dist/es2015/providers/rest-resource-provider.js +140 -0
  9. package/dist/es2015/registry/entity-registry.js +50 -0
  10. package/dist/es2015/registry/resource-registry.js +68 -0
  11. package/dist/index.d.ts +18 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +16 -0
  14. package/dist/middleware/entity-middleware.d.ts +13 -0
  15. package/dist/middleware/entity-middleware.d.ts.map +1 -0
  16. package/dist/middleware/entity-middleware.js +221 -0
  17. package/dist/middleware/entity-sync-middleware.d.ts +7 -0
  18. package/dist/middleware/entity-sync-middleware.d.ts.map +1 -0
  19. package/dist/middleware/entity-sync-middleware.js +31 -0
  20. package/dist/middleware/resource-middleware.d.ts +13 -0
  21. package/dist/middleware/resource-middleware.d.ts.map +1 -0
  22. package/dist/middleware/resource-middleware.js +97 -0
  23. package/dist/middleware/sync-middleware.d.ts +12 -0
  24. package/dist/middleware/sync-middleware.d.ts.map +1 -0
  25. package/dist/middleware/sync-middleware.js +80 -0
  26. package/dist/plugin/resource-plugin-factory.d.ts +31 -0
  27. package/dist/plugin/resource-plugin-factory.d.ts.map +1 -0
  28. package/dist/plugin/resource-plugin-factory.js +131 -0
  29. package/dist/providers/mock-resource-provider.d.ts +147 -0
  30. package/dist/providers/mock-resource-provider.d.ts.map +1 -0
  31. package/dist/providers/mock-resource-provider.js +196 -0
  32. package/dist/providers/rest-resource-provider.d.ts +51 -0
  33. package/dist/providers/rest-resource-provider.d.ts.map +1 -0
  34. package/dist/providers/rest-resource-provider.js +117 -0
  35. package/dist/registry/entity-registry.d.ts +54 -0
  36. package/dist/registry/entity-registry.d.ts.map +1 -0
  37. package/dist/registry/entity-registry.js +46 -0
  38. package/dist/registry/resource-registry.d.ts +80 -0
  39. package/dist/registry/resource-registry.d.ts.map +1 -0
  40. package/dist/registry/resource-registry.js +64 -0
  41. package/package.json +57 -0
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createEntitySyncMiddleware = exports.createEntityMiddleware = exports.createSyncMiddleware = exports.createResourceMiddleware = exports.EntityRegistry = exports.ResourceRegistry = exports.MockResourceProvider = exports.RestResourceProvider = exports.STORE_EXTENSIONS_TOKEN = exports.MIDDLEWARE_REGISTRY_TOKEN = exports.STORE_MANAGER_TOKEN = exports.ENTITY_REGISTRY_TOKEN = exports.RESOURCE_REGISTRY_TOKEN = exports.createResourcePlugin = void 0;
4
+ // Plugin factory (main export)
5
+ var resource_plugin_factory_1 = require("./plugin/resource-plugin-factory");
6
+ Object.defineProperty(exports, "createResourcePlugin", { enumerable: true, get: function () { return resource_plugin_factory_1.createResourcePlugin; } });
7
+ var resource_plugin_factory_2 = require("./plugin/resource-plugin-factory");
8
+ Object.defineProperty(exports, "RESOURCE_REGISTRY_TOKEN", { enumerable: true, get: function () { return resource_plugin_factory_2.RESOURCE_REGISTRY_TOKEN; } });
9
+ Object.defineProperty(exports, "ENTITY_REGISTRY_TOKEN", { enumerable: true, get: function () { return resource_plugin_factory_2.ENTITY_REGISTRY_TOKEN; } });
10
+ // Re-export store tokens from ui-store-api for convenience
11
+ var ui_store_api_1 = require("@hamak/ui-store-api");
12
+ Object.defineProperty(exports, "STORE_MANAGER_TOKEN", { enumerable: true, get: function () { return ui_store_api_1.STORE_MANAGER_TOKEN; } });
13
+ Object.defineProperty(exports, "MIDDLEWARE_REGISTRY_TOKEN", { enumerable: true, get: function () { return ui_store_api_1.MIDDLEWARE_REGISTRY_TOKEN; } });
14
+ Object.defineProperty(exports, "STORE_EXTENSIONS_TOKEN", { enumerable: true, get: function () { return ui_store_api_1.STORE_EXTENSIONS_TOKEN; } });
15
+ // Built-in providers (exported for convenience and testing)
16
+ var rest_resource_provider_1 = require("./providers/rest-resource-provider");
17
+ Object.defineProperty(exports, "RestResourceProvider", { enumerable: true, get: function () { return rest_resource_provider_1.RestResourceProvider; } });
18
+ var mock_resource_provider_1 = require("./providers/mock-resource-provider");
19
+ Object.defineProperty(exports, "MockResourceProvider", { enumerable: true, get: function () { return mock_resource_provider_1.MockResourceProvider; } });
20
+ // Registry implementations (internal, but exported for testing)
21
+ var resource_registry_1 = require("./registry/resource-registry");
22
+ Object.defineProperty(exports, "ResourceRegistry", { enumerable: true, get: function () { return resource_registry_1.ResourceRegistry; } });
23
+ var entity_registry_1 = require("./registry/entity-registry");
24
+ Object.defineProperty(exports, "EntityRegistry", { enumerable: true, get: function () { return entity_registry_1.EntityRegistry; } });
25
+ // Middleware factories (internal, but exported for advanced use cases)
26
+ var resource_middleware_1 = require("./middleware/resource-middleware");
27
+ Object.defineProperty(exports, "createResourceMiddleware", { enumerable: true, get: function () { return resource_middleware_1.createResourceMiddleware; } });
28
+ var sync_middleware_1 = require("./middleware/sync-middleware");
29
+ Object.defineProperty(exports, "createSyncMiddleware", { enumerable: true, get: function () { return sync_middleware_1.createSyncMiddleware; } });
30
+ var entity_middleware_1 = require("./middleware/entity-middleware");
31
+ Object.defineProperty(exports, "createEntityMiddleware", { enumerable: true, get: function () { return entity_middleware_1.createEntityMiddleware; } });
32
+ var entity_sync_middleware_1 = require("./middleware/entity-sync-middleware");
33
+ Object.defineProperty(exports, "createEntitySyncMiddleware", { enumerable: true, get: function () { return entity_sync_middleware_1.createEntitySyncMiddleware; } });
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createEntityMiddleware = void 0;
4
+ const ui_remote_resource_api_1 = require("@hamak/ui-remote-resource-api");
5
+ /**
6
+ * Entity middleware
7
+ * Translates entity actions to resource actions
8
+ */
9
+ function createEntityMiddleware(config) {
10
+ const { entityRegistry, fsSliceName, onError } = config;
11
+ const resourceActionFactory = new ui_remote_resource_api_1.ResourceActionFactory();
12
+ return (store) => (next) => (action) => {
13
+ // Only handle entity actions
14
+ if (!isEntityAction(action)) {
15
+ return next(action);
16
+ }
17
+ // Pass through for tracking
18
+ next(action);
19
+ const entityAction = action;
20
+ try {
21
+ // Translate entity action to resource action
22
+ const resourceAction = translateEntityAction(entityAction, entityRegistry, resourceActionFactory, store.getState(), fsSliceName);
23
+ // Dispatch resource action
24
+ store.dispatch(resourceAction);
25
+ }
26
+ catch (error) {
27
+ onError === null || onError === void 0 ? void 0 : onError(error, entityAction);
28
+ console.error('Entity middleware error:', error);
29
+ }
30
+ };
31
+ }
32
+ exports.createEntityMiddleware = createEntityMiddleware;
33
+ function isEntityAction(action) {
34
+ return [
35
+ ui_remote_resource_api_1.EntityActionTypes.FETCH_ENTITY,
36
+ ui_remote_resource_api_1.EntityActionTypes.UPDATE_ENTITY,
37
+ ui_remote_resource_api_1.EntityActionTypes.DELETE_ENTITY,
38
+ ui_remote_resource_api_1.EntityActionTypes.CREATE_ENTITY
39
+ ].includes(action.type);
40
+ }
41
+ function translateEntityAction(entityAction, entityRegistry, resourceActionFactory, state, fsSliceName) {
42
+ const { entityId } = entityAction.payload;
43
+ // Get entity definition
44
+ const entityDef = entityRegistry.getEntity(entityId);
45
+ if (!entityDef) {
46
+ throw new Error(`Entity not found: ${entityId}`);
47
+ }
48
+ switch (entityAction.type) {
49
+ case ui_remote_resource_api_1.EntityActionTypes.FETCH_ENTITY:
50
+ return handleFetchEntity(entityAction, entityDef, resourceActionFactory);
51
+ case ui_remote_resource_api_1.EntityActionTypes.UPDATE_ENTITY:
52
+ return handleUpdateEntity(entityAction, entityDef, resourceActionFactory, state, fsSliceName);
53
+ case ui_remote_resource_api_1.EntityActionTypes.DELETE_ENTITY:
54
+ return handleDeleteEntity(entityAction, entityDef, resourceActionFactory, state, fsSliceName);
55
+ case ui_remote_resource_api_1.EntityActionTypes.CREATE_ENTITY:
56
+ return handleCreateEntity(entityAction, entityDef, resourceActionFactory);
57
+ default:
58
+ throw new Error(`Unknown entity action type: ${entityAction.type}`);
59
+ }
60
+ }
61
+ /**
62
+ * Handle FETCH_ENTITY: keys provided, generate path and params
63
+ */
64
+ function handleFetchEntity(action, entityDef, resourceActionFactory) {
65
+ const { keys, params, path } = action.payload;
66
+ // Validate keys
67
+ validateKeys(keys, entityDef.keySchema);
68
+ // Generate path from keys (if not explicitly provided)
69
+ const targetPath = path || generatePath(keys, entityDef);
70
+ // Map keys to resource params
71
+ const resourceParams = entityDef.keyMapper(keys, 'fetch');
72
+ // Merge with additional params
73
+ const mergedParams = Object.assign(Object.assign(Object.assign({}, resourceParams.params), params), {
74
+ // Store entity context for entity sync middleware
75
+ _entityContext: {
76
+ entityId: entityDef.id,
77
+ keys,
78
+ keyFields: entityDef.keySchema.fields
79
+ } });
80
+ return resourceActionFactory.callRequest(entityDef.resourceEndpointId, 'fetch', mergedParams, targetPath, action.id);
81
+ }
82
+ /**
83
+ * Handle UPDATE_ENTITY: path provided, read keys from file attributes
84
+ */
85
+ function handleUpdateEntity(action, entityDef, resourceActionFactory, state, fsSliceName) {
86
+ const { path, data, params } = action.payload;
87
+ // Read file node
88
+ const fileNode = selectFileNode(state, path, fsSliceName);
89
+ if (!fileNode) {
90
+ throw new Error(`Entity not found at path: ${JSON.stringify(path)}`);
91
+ }
92
+ // Get entity keys from extension state
93
+ const keys = ui_remote_resource_api_1.resourceAttributesUtil.getEntityKeys(fileNode);
94
+ if (!keys) {
95
+ throw new Error(`Entity keys not found in file attributes at: ${JSON.stringify(path)}`);
96
+ }
97
+ // Validate keys
98
+ validateKeys(keys, entityDef.keySchema);
99
+ // Map keys to resource params
100
+ const resourceParams = entityDef.keyMapper(keys, 'update');
101
+ // Merge with body data and additional params
102
+ const mergedParams = Object.assign(Object.assign(Object.assign({}, resourceParams.params), params), { body: data, _entityContext: {
103
+ entityId: entityDef.id,
104
+ keys,
105
+ keyFields: entityDef.keySchema.fields
106
+ } });
107
+ return resourceActionFactory.callRequest(entityDef.resourceEndpointId, 'update', mergedParams, path, action.id);
108
+ }
109
+ /**
110
+ * Handle DELETE_ENTITY: path provided, read keys from file attributes
111
+ */
112
+ function handleDeleteEntity(action, entityDef, resourceActionFactory, state, fsSliceName) {
113
+ const { path, params } = action.payload;
114
+ // Read file node
115
+ const fileNode = selectFileNode(state, path, fsSliceName);
116
+ if (!fileNode) {
117
+ throw new Error(`Entity not found at path: ${JSON.stringify(path)}`);
118
+ }
119
+ // Get entity keys from extension state
120
+ const keys = ui_remote_resource_api_1.resourceAttributesUtil.getEntityKeys(fileNode);
121
+ if (!keys) {
122
+ throw new Error(`Entity keys not found in file attributes at: ${JSON.stringify(path)}`);
123
+ }
124
+ // Validate keys
125
+ validateKeys(keys, entityDef.keySchema);
126
+ // Map keys to resource params
127
+ const resourceParams = entityDef.keyMapper(keys, 'delete');
128
+ // Merge with additional params
129
+ const mergedParams = Object.assign(Object.assign(Object.assign({}, resourceParams.params), params), { _entityContext: {
130
+ entityId: entityDef.id,
131
+ keys,
132
+ keyFields: entityDef.keySchema.fields
133
+ } });
134
+ return resourceActionFactory.callRequest(entityDef.resourceEndpointId, 'delete', mergedParams, path, action.id);
135
+ }
136
+ /**
137
+ * Handle CREATE_ENTITY: keys optional (may be generated by server)
138
+ */
139
+ function handleCreateEntity(action, entityDef, resourceActionFactory) {
140
+ const { keys, data, path, params } = action.payload;
141
+ // Keys are optional for create (server may generate ID)
142
+ let targetPath = path;
143
+ let resourceParams;
144
+ if (keys) {
145
+ validateKeys(keys, entityDef.keySchema, true); // Partial validation
146
+ targetPath = path || generatePath(keys, entityDef);
147
+ resourceParams = entityDef.keyMapper(keys, 'create');
148
+ }
149
+ else {
150
+ resourceParams = { params: {} };
151
+ }
152
+ // Merge with body data and additional params
153
+ const mergedParams = Object.assign(Object.assign(Object.assign({}, resourceParams.params), params), { body: data, _entityContext: keys
154
+ ? {
155
+ entityId: entityDef.id,
156
+ keys,
157
+ keyFields: entityDef.keySchema.fields
158
+ }
159
+ : undefined });
160
+ return resourceActionFactory.callRequest(entityDef.resourceEndpointId, 'create', mergedParams, targetPath, action.id);
161
+ }
162
+ /**
163
+ * Validate entity keys against schema
164
+ */
165
+ function validateKeys(keys, schema, partial = false) {
166
+ if (!partial) {
167
+ for (const field of schema.fields) {
168
+ if (!(field in keys) || keys[field] === undefined || keys[field] === null) {
169
+ throw new Error(`Missing required key field: ${field}`);
170
+ }
171
+ }
172
+ }
173
+ if (schema.validate) {
174
+ const result = schema.validate(keys);
175
+ if (result !== true) {
176
+ throw new Error(typeof result === 'string' ? result : 'Invalid entity keys');
177
+ }
178
+ }
179
+ }
180
+ /**
181
+ * Generate file path from entity keys
182
+ */
183
+ function generatePath(keys, entityDef) {
184
+ if (entityDef.pathGenerator) {
185
+ const result = entityDef.pathGenerator(keys, entityDef.id);
186
+ return Array.isArray(result) ? result : [result];
187
+ }
188
+ // Default path generator: ['entities', entityId, ...keyValues]
189
+ const keyValues = entityDef.keySchema.fields.map((field) => String(keys[field]));
190
+ return ['entities', entityDef.id, ...keyValues];
191
+ }
192
+ /**
193
+ * Select file node from state
194
+ */
195
+ function selectFileNode(state, path, fsSliceName) {
196
+ var _a;
197
+ const fsState = state[fsSliceName];
198
+ if (!(fsState === null || fsState === void 0 ? void 0 : fsState.root))
199
+ return undefined;
200
+ const pathArray = Array.isArray(path) ? path : [path];
201
+ let currentNode = fsState.root;
202
+ for (const segment of pathArray) {
203
+ if (!currentNode || currentNode.type !== 'directory') {
204
+ return undefined;
205
+ }
206
+ currentNode = (_a = currentNode.children) === null || _a === void 0 ? void 0 : _a[segment];
207
+ }
208
+ return currentNode;
209
+ }
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createEntitySyncMiddleware = void 0;
4
+ const ui_remote_resource_api_1 = require("@hamak/ui-remote-resource-api");
5
+ /**
6
+ * Entity sync middleware
7
+ * Stores entity keys in extension state when resource calls succeed
8
+ */
9
+ function createEntitySyncMiddleware() {
10
+ return (store) => (next) => (action) => {
11
+ const result = next(action);
12
+ // Listen for resource success actions that originated from entity actions
13
+ if (action.type === ui_remote_resource_api_1.ResourceActionTypes.RESOURCE_CALL_SUCCESS) {
14
+ handleEntityResourceSuccess(store, action);
15
+ }
16
+ return result;
17
+ };
18
+ }
19
+ exports.createEntitySyncMiddleware = createEntitySyncMiddleware;
20
+ function handleEntityResourceSuccess(store, action) {
21
+ var _a;
22
+ const { request } = action;
23
+ // Check if this resource action originated from an entity action
24
+ const entityContext = (_a = request.payload.params) === null || _a === void 0 ? void 0 : _a._entityContext;
25
+ if (!entityContext) {
26
+ return; // Not an entity-originated action
27
+ }
28
+ const { entityId, keys, keyFields } = entityContext;
29
+ const { path } = action.payload;
30
+ // Create entity attributes
31
+ const entityAttrs = ui_remote_resource_api_1.resourceAttributesUtil.createEntityAttributes(entityId, keys, keyFields);
32
+ // TODO: Entity attributes are no longer stored in file extension state
33
+ // The FileSystemAdapter doesn't support updating extension states directly
34
+ // Entity information is now tracked through the file content itself
35
+ // Future: Consider adding entity metadata support to FileSystemAdapter
36
+ }
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.createResourceMiddleware = void 0;
13
+ const ui_remote_resource_api_1 = require("@hamak/ui-remote-resource-api");
14
+ /**
15
+ * Resource middleware
16
+ * Intercepts RESOURCE_CALL_REQUEST actions and executes API calls via providers
17
+ */
18
+ function createResourceMiddleware(config) {
19
+ const { registry, onError, onSuccess } = config;
20
+ const actionFactory = new ui_remote_resource_api_1.ResourceActionFactory();
21
+ return (store) => (next) => (action) => __awaiter(this, void 0, void 0, function* () {
22
+ // Only handle RESOURCE_CALL_REQUEST actions
23
+ if (action.type !== ui_remote_resource_api_1.ResourceActionTypes.RESOURCE_CALL_REQUEST) {
24
+ return next(action);
25
+ }
26
+ // Continue action flow (for sync middleware to set loading state)
27
+ next(action);
28
+ const requestAction = action;
29
+ const { endpointId, operation, params, path } = requestAction.payload;
30
+ try {
31
+ // Lookup endpoint
32
+ const endpointDef = registry.getEndpoint(endpointId);
33
+ if (!endpointDef) {
34
+ throw new Error(`Endpoint not found: ${endpointId}`);
35
+ }
36
+ // Get provider
37
+ const provider = registry.getProvider(endpointDef.providerType);
38
+ if (!provider) {
39
+ throw new Error(`Provider not found: ${endpointDef.providerType}`);
40
+ }
41
+ // Map action to call params (mapper receives entire action)
42
+ const callParams = endpointDef.payloadMapper
43
+ ? endpointDef.payloadMapper(requestAction)
44
+ : { params }; // Default: just use params
45
+ // Execute provider call
46
+ const result = yield provider.call(endpointDef.endpoint, callParams, operation);
47
+ // Transform response (transformer receives entire action)
48
+ const transformedData = endpointDef.responseTransformer
49
+ ? endpointDef.responseTransformer(result.data, result.metadata, requestAction)
50
+ : result.data;
51
+ // Determine storage path
52
+ const storagePath = determinePath(path, endpointDef, params, operation);
53
+ // Dispatch success action
54
+ const successAction = actionFactory.callSuccess(endpointId, storagePath, transformedData, result.metadata, requestAction);
55
+ store.dispatch(successAction);
56
+ onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(result, requestAction);
57
+ }
58
+ catch (error) {
59
+ // Determine storage path for error state
60
+ const endpointDef = registry.getEndpoint(endpointId);
61
+ const storagePath = determinePath(path, endpointDef, params, operation);
62
+ // Dispatch failure action
63
+ const failureAction = actionFactory.callFailure(endpointId, storagePath, normalizeError(error), requestAction);
64
+ store.dispatch(failureAction);
65
+ onError === null || onError === void 0 ? void 0 : onError(error, requestAction);
66
+ }
67
+ });
68
+ }
69
+ exports.createResourceMiddleware = createResourceMiddleware;
70
+ /**
71
+ * Determine the file path where resource should be stored
72
+ */
73
+ function determinePath(explicitPath, endpointDef, params, operation) {
74
+ // 1. Use explicit path from action if provided
75
+ if (explicitPath) {
76
+ return explicitPath;
77
+ }
78
+ // 2. Use endpoint's default folder + generate filename
79
+ if (endpointDef === null || endpointDef === void 0 ? void 0 : endpointDef.defaultFolder) {
80
+ const folder = Array.isArray(endpointDef.defaultFolder)
81
+ ? endpointDef.defaultFolder
82
+ : [endpointDef.defaultFolder];
83
+ // Generate filename from params or operation
84
+ const filename = generateFilename(params, operation);
85
+ return [...folder, filename];
86
+ }
87
+ // 3. Fallback to root with generated filename
88
+ return [generateFilename(params, operation)];
89
+ }
90
+ /**
91
+ * Generate filename from params or operation
92
+ */
93
+ function generateFilename(params, operation) {
94
+ // If params has an id field, use it
95
+ if (params === null || params === void 0 ? void 0 : params.id) {
96
+ return String(params.id);
97
+ }
98
+ // Otherwise generate based on operation + timestamp
99
+ return `${operation}-${Date.now()}`;
100
+ }
101
+ /**
102
+ * Normalize error to consistent format
103
+ */
104
+ function normalizeError(error) {
105
+ var _a, _b, _c;
106
+ return {
107
+ message: error.message || 'Unknown error',
108
+ code: error.code || ((_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === null || _b === void 0 ? void 0 : _b.toString()),
109
+ details: ((_c = error.response) === null || _c === void 0 ? void 0 : _c.data) || error
110
+ };
111
+ }
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSyncMiddleware = void 0;
4
+ const ui_remote_resource_api_1 = require("@hamak/ui-remote-resource-api");
5
+ const navigation_utils_1 = require("@hamak/navigation-utils");
6
+ /**
7
+ * Sync middleware
8
+ * Updates file system state when resource actions complete
9
+ */
10
+ function createSyncMiddleware(config) {
11
+ const { fsActions } = config;
12
+ return (store) => (next) => (action) => {
13
+ // Pass through all actions first
14
+ const result = next(action);
15
+ // Handle request action (set loading state)
16
+ if (action.type === ui_remote_resource_api_1.ResourceActionTypes.RESOURCE_CALL_REQUEST) {
17
+ handleRequestAction(store, action, fsActions);
18
+ }
19
+ // Handle success action (update content)
20
+ if (action.type === ui_remote_resource_api_1.ResourceActionTypes.RESOURCE_CALL_SUCCESS) {
21
+ handleSuccessAction(store, action, fsActions);
22
+ }
23
+ // Handle failure action (set error state)
24
+ if (action.type === ui_remote_resource_api_1.ResourceActionTypes.RESOURCE_CALL_FAILURE) {
25
+ handleFailureAction(store, action, fsActions);
26
+ }
27
+ return result;
28
+ };
29
+ }
30
+ exports.createSyncMiddleware = createSyncMiddleware;
31
+ function handleRequestAction(store, action, fsActions) {
32
+ const { path } = action.payload;
33
+ if (!path) {
34
+ // Loading state will be set when success/failure with resolved path
35
+ return;
36
+ }
37
+ // Normalize path using Pathway utility
38
+ const pathway = navigation_utils_1.Pathway.of(path);
39
+ const parentPathway = pathway.getParent();
40
+ const parentSegments = parentPathway.getSegments();
41
+ // Ensure parent directory exists
42
+ if (parentSegments.length > 0) {
43
+ store.dispatch(fsActions.mkdir(parentSegments, true));
44
+ }
45
+ // Set loading state by creating file node with contentIsPresent=false
46
+ store.dispatch(fsActions.setFile(path, null, 'xs:any', { override: false, contentIsPresent: false }));
47
+ }
48
+ function handleSuccessAction(store, action, fsActions) {
49
+ var _a;
50
+ const { path, data } = action.payload;
51
+ const { request } = action;
52
+ // Normalize path using Pathway utility
53
+ const pathway = navigation_utils_1.Pathway.of(path);
54
+ const parentPathway = pathway.getParent();
55
+ const parentSegments = parentPathway.getSegments();
56
+ // Ensure parent directory exists
57
+ if (parentSegments.length > 0) {
58
+ store.dispatch(fsActions.mkdir(parentSegments, true));
59
+ }
60
+ // Set file content from remote (automatically sets contentLoaded=true and clears loading)
61
+ // Schema should come from endpoint definition if available
62
+ const schema = ((_a = request.meta) === null || _a === void 0 ? void 0 : _a.schema) || 'xs:any';
63
+ // First ensure file exists with proper schema
64
+ store.dispatch(fsActions.setFile(path, data, schema, { override: true, contentIsPresent: true }));
65
+ // Then set content from remote to mark it as loaded from remote source
66
+ store.dispatch(fsActions.setFileContent(path, data, true));
67
+ }
68
+ function handleFailureAction(store, action, fsActions) {
69
+ const { path, error } = action.payload;
70
+ if (!path) {
71
+ return;
72
+ }
73
+ // Normalize path using Pathway utility
74
+ const pathway = navigation_utils_1.Pathway.of(path);
75
+ const parentPathway = pathway.getParent();
76
+ const parentSegments = parentPathway.getSegments();
77
+ // Ensure parent directory exists
78
+ if (parentSegments.length > 0) {
79
+ store.dispatch(fsActions.mkdir(parentSegments, true));
80
+ }
81
+ // For now, just ensure the file exists and set content to null/error placeholder
82
+ // TODO: FileSystemAdapter doesn't currently support setting error state directly
83
+ // We might need to extend it or handle errors differently
84
+ store.dispatch(fsActions.setFile(path, { error }, 'xs:any', { override: true, contentIsPresent: true }));
85
+ }
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.createResourcePlugin = exports.ENTITY_REGISTRY_TOKEN = exports.RESOURCE_REGISTRY_TOKEN = void 0;
13
+ const ui_store_api_1 = require("@hamak/ui-store-api");
14
+ const ui_store_impl_1 = require("@hamak/ui-store-impl");
15
+ const resource_registry_1 = require("../registry/resource-registry");
16
+ const entity_registry_1 = require("../registry/entity-registry");
17
+ const rest_resource_provider_1 = require("../providers/rest-resource-provider");
18
+ const mock_resource_provider_1 = require("../providers/mock-resource-provider");
19
+ const resource_middleware_1 = require("../middleware/resource-middleware");
20
+ const sync_middleware_1 = require("../middleware/sync-middleware");
21
+ const entity_middleware_1 = require("../middleware/entity-middleware");
22
+ const entity_sync_middleware_1 = require("../middleware/entity-sync-middleware");
23
+ // Dependency injection tokens (for local use)
24
+ exports.RESOURCE_REGISTRY_TOKEN = 'RESOURCE_REGISTRY';
25
+ exports.ENTITY_REGISTRY_TOKEN = 'ENTITY_REGISTRY';
26
+ /**
27
+ * Create remote resource plugin
28
+ *
29
+ * @param config - Plugin configuration
30
+ * @returns Plugin module for microkernel registration
31
+ */
32
+ function createResourcePlugin(config = {}) {
33
+ const resourceRegistry = new resource_registry_1.ResourceRegistry();
34
+ const entityRegistry = new entity_registry_1.EntityRegistry();
35
+ return {
36
+ initialize(ctx) {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ // Register default providers
39
+ const restProvider = new rest_resource_provider_1.RestResourceProvider();
40
+ const mockProvider = new mock_resource_provider_1.MockResourceProvider();
41
+ resourceRegistry.registerProvider(restProvider);
42
+ resourceRegistry.registerProvider(mockProvider);
43
+ // Register custom providers
44
+ if (config.providers) {
45
+ config.providers.forEach((provider) => {
46
+ resourceRegistry.registerProvider(provider);
47
+ });
48
+ }
49
+ // Register endpoints
50
+ if (config.endpoints) {
51
+ config.endpoints.forEach((endpoint) => {
52
+ resourceRegistry.registerEndpoint(endpoint);
53
+ });
54
+ }
55
+ // Register entities
56
+ if (config.entities) {
57
+ config.entities.forEach((entity) => {
58
+ entityRegistry.registerEntity(entity);
59
+ });
60
+ }
61
+ // Provide registries via DI
62
+ ctx.provide({
63
+ provide: exports.RESOURCE_REGISTRY_TOKEN,
64
+ useValue: resourceRegistry
65
+ });
66
+ ctx.provide({
67
+ provide: exports.ENTITY_REGISTRY_TOKEN,
68
+ useValue: entityRegistry
69
+ });
70
+ // Register middleware during initialization
71
+ try {
72
+ // Access resolve method if available on context
73
+ const resolve = ctx.resolve;
74
+ if (resolve) {
75
+ // Resolve FileSystemAdapter from DI
76
+ const fsAdapter = resolve(ui_store_impl_1.FILESYSTEM_ADAPTER_TOKEN);
77
+ if (!fsAdapter) {
78
+ console.warn('[ui-remote-resource] FileSystemAdapter not available in DI');
79
+ return;
80
+ }
81
+ const fsActions = fsAdapter.getActions();
82
+ const fsSliceName = fsAdapter.sliceName;
83
+ // Create middleware with FileSystemAdapter actions
84
+ const entityMiddleware = (0, entity_middleware_1.createEntityMiddleware)({
85
+ entityRegistry,
86
+ fsSliceName,
87
+ onError: config.onError
88
+ });
89
+ const resourceMiddleware = (0, resource_middleware_1.createResourceMiddleware)({
90
+ registry: resourceRegistry,
91
+ onError: config.onError,
92
+ onSuccess: config.onSuccess
93
+ });
94
+ const entitySyncMiddleware = (0, entity_sync_middleware_1.createEntitySyncMiddleware)();
95
+ const resourceSyncMiddleware = (0, sync_middleware_1.createSyncMiddleware)({
96
+ fsActions
97
+ });
98
+ const middlewareRegistry = resolve(ui_store_api_1.MIDDLEWARE_REGISTRY_TOKEN);
99
+ middlewareRegistry.register({
100
+ id: 'entity-middleware',
101
+ middleware: entityMiddleware,
102
+ priority: 110,
103
+ plugin: 'ui-remote-resource'
104
+ });
105
+ middlewareRegistry.register({
106
+ id: 'resource-middleware',
107
+ middleware: resourceMiddleware,
108
+ priority: 100,
109
+ plugin: 'ui-remote-resource'
110
+ });
111
+ middlewareRegistry.register({
112
+ id: 'entity-sync-middleware',
113
+ middleware: entitySyncMiddleware,
114
+ priority: 60,
115
+ plugin: 'ui-remote-resource'
116
+ });
117
+ middlewareRegistry.register({
118
+ id: 'resource-sync-middleware',
119
+ middleware: resourceSyncMiddleware,
120
+ priority: 50,
121
+ plugin: 'ui-remote-resource'
122
+ });
123
+ }
124
+ else {
125
+ console.warn('Resolve method not available in initialization context');
126
+ }
127
+ }
128
+ catch (error) {
129
+ console.warn('Failed to register middleware during initialization:', error);
130
+ }
131
+ });
132
+ },
133
+ activate(ctx) {
134
+ return __awaiter(this, void 0, void 0, function* () {
135
+ var _a;
136
+ // Emit ready event
137
+ (_a = ctx.hooks) === null || _a === void 0 ? void 0 : _a.emit('ui-remote-resource:ready', {
138
+ resourceRegistry,
139
+ entityRegistry
140
+ });
141
+ });
142
+ },
143
+ deactivate() {
144
+ return __awaiter(this, void 0, void 0, function* () {
145
+ // Cleanup if needed
146
+ // For now, no cleanup required
147
+ });
148
+ }
149
+ };
150
+ }
151
+ exports.createResourcePlugin = createResourcePlugin;