@optimizely/ocp-local-env 1.0.0-beta.10
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 +51 -0
- package/dist/package.json +112 -0
- package/dist/public/bundle.82dc5d29fffb9f205051.js +3 -0
- package/dist/public/bundle.82dc5d29fffb9f205051.js.LICENSE.txt +92 -0
- package/dist/public/bundle.82dc5d29fffb9f205051.js.map +1 -0
- package/dist/public/index.html +1 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +115 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/executor/DestinationExecutor.d.ts +19 -0
- package/dist/src/executor/DestinationExecutor.js +72 -0
- package/dist/src/executor/DestinationExecutor.js.map +1 -0
- package/dist/src/executor/FunctionExecutor.d.ts +67 -0
- package/dist/src/executor/FunctionExecutor.js +189 -0
- package/dist/src/executor/FunctionExecutor.js.map +1 -0
- package/dist/src/executor/JobExecutor.d.ts +79 -0
- package/dist/src/executor/JobExecutor.js +215 -0
- package/dist/src/executor/JobExecutor.js.map +1 -0
- package/dist/src/executor/LifecycleExecutor.d.ts +64 -0
- package/dist/src/executor/LifecycleExecutor.js +167 -0
- package/dist/src/executor/LifecycleExecutor.js.map +1 -0
- package/dist/src/executor/SourceExecutor.d.ts +32 -0
- package/dist/src/executor/SourceExecutor.js +163 -0
- package/dist/src/executor/SourceExecutor.js.map +1 -0
- package/dist/src/executor/watcher.d.ts +62 -0
- package/dist/src/executor/watcher.js +213 -0
- package/dist/src/executor/watcher.js.map +1 -0
- package/dist/src/functions/hello.d.ts +4 -0
- package/dist/src/functions/hello.js +8 -0
- package/dist/src/functions/hello.js.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/jobs/dailyJob.d.ts +4 -0
- package/dist/src/jobs/dailyJob.js +8 -0
- package/dist/src/jobs/dailyJob.js.map +1 -0
- package/dist/src/local_engine/LocalFunctionApi.d.ts +17 -0
- package/dist/src/local_engine/LocalFunctionApi.js +54 -0
- package/dist/src/local_engine/LocalFunctionApi.js.map +1 -0
- package/dist/src/local_engine/LocalJobApi.d.ts +67 -0
- package/dist/src/local_engine/LocalJobApi.js +205 -0
- package/dist/src/local_engine/LocalJobApi.js.map +1 -0
- package/dist/src/local_engine/LocalNotifier.d.ts +9 -0
- package/dist/src/local_engine/LocalNotifier.js +26 -0
- package/dist/src/local_engine/LocalNotifier.js.map +1 -0
- package/dist/src/local_engine/local-engine-child-base.d.ts +110 -0
- package/dist/src/local_engine/local-engine-child-base.js +607 -0
- package/dist/src/local_engine/local-engine-child-base.js.map +1 -0
- package/dist/src/local_engine/local-engine-client.d.ts +161 -0
- package/dist/src/local_engine/local-engine-client.js +888 -0
- package/dist/src/local_engine/local-engine-client.js.map +1 -0
- package/dist/src/local_engine/local-engine-types.d.ts +245 -0
- package/dist/src/local_engine/local-engine-types.js +6 -0
- package/dist/src/local_engine/local-engine-types.js.map +1 -0
- package/dist/src/local_engine/local-engine-unified.d.ts +71 -0
- package/dist/src/local_engine/local-engine-unified.js +723 -0
- package/dist/src/local_engine/local-engine-unified.js.map +1 -0
- package/dist/src/local_engine/local-engine-utils.d.ts +68 -0
- package/dist/src/local_engine/local-engine-utils.js +219 -0
- package/dist/src/local_engine/local-engine-utils.js.map +1 -0
- package/dist/src/local_engine/localSDKConfig.d.ts +40 -0
- package/dist/src/local_engine/localSDKConfig.js +247 -0
- package/dist/src/local_engine/localSDKConfig.js.map +1 -0
- package/dist/src/local_engine/storage/BaseKVStoreWrapper.d.ts +37 -0
- package/dist/src/local_engine/storage/BaseKVStoreWrapper.js +110 -0
- package/dist/src/local_engine/storage/BaseKVStoreWrapper.js.map +1 -0
- package/dist/src/local_engine/storage/LocalConfigStore.d.ts +74 -0
- package/dist/src/local_engine/storage/LocalConfigStore.js +178 -0
- package/dist/src/local_engine/storage/LocalConfigStore.js.map +1 -0
- package/dist/src/local_engine/storage/LocalJobStore.d.ts +111 -0
- package/dist/src/local_engine/storage/LocalJobStore.js +249 -0
- package/dist/src/local_engine/storage/LocalJobStore.js.map +1 -0
- package/dist/src/local_engine/storage/LocalKVStore.d.ts +106 -0
- package/dist/src/local_engine/storage/LocalKVStore.js +1061 -0
- package/dist/src/local_engine/storage/LocalKVStore.js.map +1 -0
- package/dist/src/local_engine/storage/LocalNotificationStore.d.ts +28 -0
- package/dist/src/local_engine/storage/LocalNotificationStore.js +149 -0
- package/dist/src/local_engine/storage/LocalNotificationStore.js.map +1 -0
- package/dist/src/local_engine/storage/LocalSecretsStore.d.ts +115 -0
- package/dist/src/local_engine/storage/LocalSecretsStore.js +350 -0
- package/dist/src/local_engine/storage/LocalSecretsStore.js.map +1 -0
- package/dist/src/local_engine/storage/LocalSecretsStoreWrapper.d.ts +19 -0
- package/dist/src/local_engine/storage/LocalSecretsStoreWrapper.js +52 -0
- package/dist/src/local_engine/storage/LocalSecretsStoreWrapper.js.map +1 -0
- package/dist/src/local_engine/storage/LocalSettingsStore.d.ts +168 -0
- package/dist/src/local_engine/storage/LocalSettingsStore.js +509 -0
- package/dist/src/local_engine/storage/LocalSettingsStore.js.map +1 -0
- package/dist/src/local_engine/storage/LocalSettingsStoreWrapper.d.ts +15 -0
- package/dist/src/local_engine/storage/LocalSettingsStoreWrapper.js +28 -0
- package/dist/src/local_engine/storage/LocalSettingsStoreWrapper.js.map +1 -0
- package/dist/src/local_engine/storage/NumberSet.d.ts +21 -0
- package/dist/src/local_engine/storage/NumberSet.js +32 -0
- package/dist/src/local_engine/storage/NumberSet.js.map +1 -0
- package/dist/src/local_engine/storage/SourceDataStore.d.ts +23 -0
- package/dist/src/local_engine/storage/SourceDataStore.js +83 -0
- package/dist/src/local_engine/storage/SourceDataStore.js.map +1 -0
- package/dist/src/local_engine/storage/SourceJobExecutionStore.d.ts +25 -0
- package/dist/src/local_engine/storage/SourceJobExecutionStore.js +61 -0
- package/dist/src/local_engine/storage/SourceJobExecutionStore.js.map +1 -0
- package/dist/src/local_engine/storage/StringSet.d.ts +21 -0
- package/dist/src/local_engine/storage/StringSet.js +32 -0
- package/dist/src/local_engine/storage/StringSet.js.map +1 -0
- package/dist/src/local_engine/types.d.ts +53 -0
- package/dist/src/local_engine/types.js +6 -0
- package/dist/src/local_engine/types.js.map +1 -0
- package/dist/src/local_engine/utils.d.ts +33 -0
- package/dist/src/local_engine/utils.js +143 -0
- package/dist/src/local_engine/utils.js.map +1 -0
- package/dist/src/logging/LogManager.d.ts +246 -0
- package/dist/src/logging/LogManager.js +343 -0
- package/dist/src/logging/LogManager.js.map +1 -0
- package/dist/src/server/api/destinations.d.ts +7 -0
- package/dist/src/server/api/destinations.js +170 -0
- package/dist/src/server/api/destinations.js.map +1 -0
- package/dist/src/server/api/functions.d.ts +7 -0
- package/dist/src/server/api/functions.js +80 -0
- package/dist/src/server/api/functions.js.map +1 -0
- package/dist/src/server/api/jobs.d.ts +10 -0
- package/dist/src/server/api/jobs.js +244 -0
- package/dist/src/server/api/jobs.js.map +1 -0
- package/dist/src/server/api/settings.d.ts +6 -0
- package/dist/src/server/api/settings.js +116 -0
- package/dist/src/server/api/settings.js.map +1 -0
- package/dist/src/server/api/sources.d.ts +7 -0
- package/dist/src/server/api/sources.js +382 -0
- package/dist/src/server/api/sources.js.map +1 -0
- package/dist/src/server/api/stores.d.ts +2 -0
- package/dist/src/server/api/stores.js +341 -0
- package/dist/src/server/api/stores.js.map +1 -0
- package/dist/src/server/api/v1.d.ts +10 -0
- package/dist/src/server/api/v1.js +718 -0
- package/dist/src/server/api/v1.js.map +1 -0
- package/dist/src/server/api.d.ts +8 -0
- package/dist/src/server/api.js +217 -0
- package/dist/src/server/api.js.map +1 -0
- package/dist/src/server/app-discovery.d.ts +5 -0
- package/dist/src/server/app-discovery.js +113 -0
- package/dist/src/server/app-discovery.js.map +1 -0
- package/dist/src/server/config.d.ts +26 -0
- package/dist/src/server/config.js +112 -0
- package/dist/src/server/config.js.map +1 -0
- package/dist/src/server/mockDataGenerator.d.ts +1 -0
- package/dist/src/server/mockDataGenerator.js +154 -0
- package/dist/src/server/mockDataGenerator.js.map +1 -0
- package/dist/src/server/websocket.d.ts +0 -0
- package/dist/src/server/websocket.js +2 -0
- package/dist/src/server/websocket.js.map +1 -0
- package/dist/src/server.d.ts +2 -0
- package/dist/src/server.js +735 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/types/app.d.ts +154 -0
- package/dist/src/types/app.js +24 -0
- package/dist/src/types/app.js.map +1 -0
- package/dist/src/types/kvstore.d.ts +320 -0
- package/dist/src/types/kvstore.js +5 -0
- package/dist/src/types/kvstore.js.map +1 -0
- package/dist/src/ui/components/App.d.ts +6 -0
- package/dist/src/ui/components/App.js +432 -0
- package/dist/src/ui/components/App.js.map +1 -0
- package/dist/src/ui/components/DestinationBatchEditor.d.ts +7 -0
- package/dist/src/ui/components/DestinationBatchEditor.js +160 -0
- package/dist/src/ui/components/DestinationBatchEditor.js.map +1 -0
- package/dist/src/ui/components/DestinationSchemaViewer.d.ts +7 -0
- package/dist/src/ui/components/DestinationSchemaViewer.js +61 -0
- package/dist/src/ui/components/DestinationSchemaViewer.js.map +1 -0
- package/dist/src/ui/components/DestinationsView.d.ts +14 -0
- package/dist/src/ui/components/DestinationsView.js +68 -0
- package/dist/src/ui/components/DestinationsView.js.map +1 -0
- package/dist/src/ui/components/FunctionsView.d.ts +13 -0
- package/dist/src/ui/components/FunctionsView.js +288 -0
- package/dist/src/ui/components/FunctionsView.js.map +1 -0
- package/dist/src/ui/components/JobsView.d.ts +13 -0
- package/dist/src/ui/components/JobsView.js +320 -0
- package/dist/src/ui/components/JobsView.js.map +1 -0
- package/dist/src/ui/components/KVStoreViewer.d.ts +11 -0
- package/dist/src/ui/components/KVStoreViewer.js +168 -0
- package/dist/src/ui/components/KVStoreViewer.js.map +1 -0
- package/dist/src/ui/components/MetadataModal.d.ts +14 -0
- package/dist/src/ui/components/MetadataModal.js +28 -0
- package/dist/src/ui/components/MetadataModal.js.map +1 -0
- package/dist/src/ui/components/MetadataModal.test.d.ts +1 -0
- package/dist/src/ui/components/MetadataModal.test.js +143 -0
- package/dist/src/ui/components/MetadataModal.test.js.map +1 -0
- package/dist/src/ui/components/NotificationViewer.d.ts +16 -0
- package/dist/src/ui/components/NotificationViewer.js +69 -0
- package/dist/src/ui/components/NotificationViewer.js.map +1 -0
- package/dist/src/ui/components/SecretsStoreViewer.d.ts +11 -0
- package/dist/src/ui/components/SecretsStoreViewer.js +179 -0
- package/dist/src/ui/components/SecretsStoreViewer.js.map +1 -0
- package/dist/src/ui/components/SettingsStoreViewer.d.ts +24 -0
- package/dist/src/ui/components/SettingsStoreViewer.js +132 -0
- package/dist/src/ui/components/SettingsStoreViewer.js.map +1 -0
- package/dist/src/ui/components/SourceDataViewer.d.ts +8 -0
- package/dist/src/ui/components/SourceDataViewer.js +84 -0
- package/dist/src/ui/components/SourceDataViewer.js.map +1 -0
- package/dist/src/ui/components/SourceJobsSection.d.ts +8 -0
- package/dist/src/ui/components/SourceJobsSection.js +99 -0
- package/dist/src/ui/components/SourceJobsSection.js.map +1 -0
- package/dist/src/ui/components/SourceLifecycleSection.d.ts +7 -0
- package/dist/src/ui/components/SourceLifecycleSection.js +58 -0
- package/dist/src/ui/components/SourceLifecycleSection.js.map +1 -0
- package/dist/src/ui/components/SourceSchemaViewer.d.ts +7 -0
- package/dist/src/ui/components/SourceSchemaViewer.js +65 -0
- package/dist/src/ui/components/SourceSchemaViewer.js.map +1 -0
- package/dist/src/ui/components/SourceWebhookEditor.d.ts +8 -0
- package/dist/src/ui/components/SourceWebhookEditor.js +181 -0
- package/dist/src/ui/components/SourceWebhookEditor.js.map +1 -0
- package/dist/src/ui/components/SourcesView.d.ts +14 -0
- package/dist/src/ui/components/SourcesView.js +74 -0
- package/dist/src/ui/components/SourcesView.js.map +1 -0
- package/dist/src/ui/components/StoreViewer.d.ts +16 -0
- package/dist/src/ui/components/StoreViewer.js +86 -0
- package/dist/src/ui/components/StoreViewer.js.map +1 -0
- package/dist/src/ui/components/TabbedConsole.d.ts +17 -0
- package/dist/src/ui/components/TabbedConsole.js +163 -0
- package/dist/src/ui/components/TabbedConsole.js.map +1 -0
- package/dist/src/ui/components/common/DataTree.d.ts +15 -0
- package/dist/src/ui/components/common/DataTree.js +95 -0
- package/dist/src/ui/components/common/DataTree.js.map +1 -0
- package/dist/src/ui/components/common/EyeIcon.d.ts +11 -0
- package/dist/src/ui/components/common/EyeIcon.js +11 -0
- package/dist/src/ui/components/common/EyeIcon.js.map +1 -0
- package/dist/src/ui/hooks/useEntityNavigation.d.ts +72 -0
- package/dist/src/ui/hooks/useEntityNavigation.js +150 -0
- package/dist/src/ui/hooks/useEntityNavigation.js.map +1 -0
- package/dist/src/ui/hooks/useQueryParams.d.ts +6 -0
- package/dist/src/ui/hooks/useQueryParams.js +39 -0
- package/dist/src/ui/hooks/useQueryParams.js.map +1 -0
- package/dist/src/ui/index.d.ts +1 -0
- package/dist/src/ui/index.js +23 -0
- package/dist/src/ui/index.js.map +1 -0
- package/dist/src/ui/store/formStateSlice.d.ts +54 -0
- package/dist/src/ui/store/formStateSlice.js +94 -0
- package/dist/src/ui/store/formStateSlice.js.map +1 -0
- package/dist/src/ui/store/hooks.d.ts +6 -0
- package/dist/src/ui/store/hooks.js +8 -0
- package/dist/src/ui/store/hooks.js.map +1 -0
- package/dist/src/ui/store/index.d.ts +11 -0
- package/dist/src/ui/store/index.js +107 -0
- package/dist/src/ui/store/index.js.map +1 -0
- package/dist/src/utils/functionEndpoints.d.ts +24 -0
- package/dist/src/utils/functionEndpoints.js +45 -0
- package/dist/src/utils/functionEndpoints.js.map +1 -0
- package/package.json +112 -0
|
@@ -0,0 +1,723 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Local Engine Unified
|
|
5
|
+
*
|
|
6
|
+
* This script runs in the app's Node.js process context and executes both OCP functions
|
|
7
|
+
* and lifecycle methods using IPC communication with the parent process.
|
|
8
|
+
* This is a single, persistent process that handles all app execution requests.
|
|
9
|
+
*/
|
|
10
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
11
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.LocalEngineUnified = void 0;
|
|
15
|
+
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const fs_1 = __importDefault(require("fs"));
|
|
17
|
+
const local_engine_child_base_1 = require("./local-engine-child-base");
|
|
18
|
+
const utils_1 = require("./utils");
|
|
19
|
+
const SourceDataStore_1 = require("./storage/SourceDataStore");
|
|
20
|
+
const SourceJobExecutionStore_1 = require("./storage/SourceJobExecutionStore");
|
|
21
|
+
class LocalEngineUnified extends local_engine_child_base_1.LocalEngineChildBase {
|
|
22
|
+
constructor() {
|
|
23
|
+
super(...arguments);
|
|
24
|
+
this.runtime = null;
|
|
25
|
+
this.isInitialized = false;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Initialize the wrapper with app configuration
|
|
29
|
+
* This happens once when the process starts
|
|
30
|
+
*/
|
|
31
|
+
async initialize(appConfig, appDir) {
|
|
32
|
+
if (this.isInitialized) {
|
|
33
|
+
this.sendLog('info', 'Wrapper already initialized, skipping initialization');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.sendLog('info', `Initializing unified wrapper for app: ${appConfig.manifest.meta?.app_id || 'unknown'}`);
|
|
37
|
+
try {
|
|
38
|
+
// Load the SDK from app's node_modules
|
|
39
|
+
this.sdkComponents = (0, utils_1.loadAppSDK)(appDir);
|
|
40
|
+
this.sendLog('info', 'SDK loaded successfully');
|
|
41
|
+
// Initialize Runtime
|
|
42
|
+
this.sendLog('info', 'Initializing Runtime...');
|
|
43
|
+
// Try initializing with dist directory first (where built files are)
|
|
44
|
+
try {
|
|
45
|
+
const distDir = path_1.default.join(appDir, 'dist');
|
|
46
|
+
this.runtime = await this.sdkComponents.Runtime.initialize(distDir);
|
|
47
|
+
this.sendLog('info', 'Runtime initialized successfully with dist directory');
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
// Fallback: try with base directory
|
|
51
|
+
this.sendLog('warn', `Runtime initialization with dist dir failed: ${error}, trying base directory`);
|
|
52
|
+
this.runtime = await this.sdkComponents.Runtime.initialize(appDir);
|
|
53
|
+
this.sendLog('info', 'Runtime initialized successfully with base directory');
|
|
54
|
+
}
|
|
55
|
+
// Import local engine components using dynamic require
|
|
56
|
+
const localEngineDir = __dirname;
|
|
57
|
+
const storageDir = path_1.default.join(__dirname, 'storage');
|
|
58
|
+
const localSDKConfig = require(path_1.default.join(localEngineDir, 'localSDKConfig'));
|
|
59
|
+
this.configureLocalSDKs = localSDKConfig.configureLocalSDKs;
|
|
60
|
+
this.cleanUpLocalSDKs = localSDKConfig.cleanUpLocalSDKs;
|
|
61
|
+
this.LocalSettingsStore = require(path_1.default.join(storageDir, 'LocalSettingsStore')).LocalSettingsStore;
|
|
62
|
+
this.LocalConfigStore = require(path_1.default.join(storageDir, 'LocalConfigStore')).LocalConfigStore;
|
|
63
|
+
this.sendLog('info', 'Local engine components loaded');
|
|
64
|
+
// Configure SDKs for the app
|
|
65
|
+
const settingsStore = this.LocalSettingsStore.getInstance(appDir);
|
|
66
|
+
const configStore = new this.LocalConfigStore(appDir);
|
|
67
|
+
this.sendLog('info', 'Configuring SDKs for local testing...');
|
|
68
|
+
this.configureLocalSDKs(appConfig, settingsStore, appDir, 1, configStore, appConfig.account, appConfig.baseUrl);
|
|
69
|
+
// Initialize source stores
|
|
70
|
+
this.sourceDataStore = new SourceDataStore_1.SourceDataStore(appDir);
|
|
71
|
+
this.sourceJobExecutionStore = new SourceJobExecutionStore_1.SourceJobExecutionStore(appDir);
|
|
72
|
+
this.isInitialized = true;
|
|
73
|
+
this.sendLog('info', 'Unified wrapper initialized successfully - ready to handle function and lifecycle requests');
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
this.sendLog('error', `Initialization failed: ${error}`);
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Execute a function with the given request
|
|
82
|
+
*/
|
|
83
|
+
async executeFunction(request) {
|
|
84
|
+
if (!this.appConfig || !this.appDir) {
|
|
85
|
+
throw new Error('Wrapper not properly initialized');
|
|
86
|
+
}
|
|
87
|
+
if (!this.isInitialized) {
|
|
88
|
+
throw new Error('SDK not initialized');
|
|
89
|
+
}
|
|
90
|
+
this.sendLog('info', `Executing function: ${request.functionId}`, this.currentRequestId);
|
|
91
|
+
this.sendProgress(this.currentRequestId, 'Finding function file', 20);
|
|
92
|
+
// Find the built function file
|
|
93
|
+
const functionPath = (0, utils_1.findFunctionFile)(this.appDir, request.functionId, this.appConfig.manifest);
|
|
94
|
+
this.sendLog('info', `Using function file: ${functionPath}`, this.currentRequestId);
|
|
95
|
+
this.sendProgress(this.currentRequestId, 'Loading function module', 40);
|
|
96
|
+
// Load the function module
|
|
97
|
+
const FunctionModule = require(functionPath);
|
|
98
|
+
const FunctionClass = (0, utils_1.findFunctionClass)(FunctionModule);
|
|
99
|
+
this.sendLog('info', 'Function class found, creating request object...', this.currentRequestId);
|
|
100
|
+
this.sendProgress(this.currentRequestId, 'Creating request object', 60);
|
|
101
|
+
// Convert headers array to the format expected by InternalRequest
|
|
102
|
+
const headers = request.headers || [];
|
|
103
|
+
// Convert body to Uint8Array if present
|
|
104
|
+
let bodyArray = null;
|
|
105
|
+
if (request.body !== null && request.body !== undefined) {
|
|
106
|
+
const bodyString = typeof request.body === 'string' ?
|
|
107
|
+
request.body : JSON.stringify(request.body);
|
|
108
|
+
bodyArray = new Uint8Array(Buffer.from(bodyString, 'utf8'));
|
|
109
|
+
}
|
|
110
|
+
const internalRequest = new this.sdkComponents.App.InternalRequest(request.method, request.fullpath, request.path, request.params || {}, headers, bodyArray);
|
|
111
|
+
this.sendLog('debug', `Created InternalRequest - method: ${request.method}, path: ${request.path}`, this.currentRequestId);
|
|
112
|
+
// Create function instance and call perform
|
|
113
|
+
const functionInstance = new FunctionClass(internalRequest);
|
|
114
|
+
if (typeof functionInstance.perform !== 'function') {
|
|
115
|
+
throw new Error('Function class does not implement perform method');
|
|
116
|
+
}
|
|
117
|
+
this.sendLog('info', 'Executing function perform method...', this.currentRequestId);
|
|
118
|
+
this.sendProgress(this.currentRequestId, 'Executing function', 80);
|
|
119
|
+
// Call the function's perform method
|
|
120
|
+
const response = await functionInstance.perform();
|
|
121
|
+
this.sendLog('info', `Function execution completed - status: ${response.status}`, this.currentRequestId);
|
|
122
|
+
this.sendProgress(this.currentRequestId, 'Function execution completed', 100);
|
|
123
|
+
// Convert response to serializable format
|
|
124
|
+
const result = {
|
|
125
|
+
success: true,
|
|
126
|
+
status: response.status || 200,
|
|
127
|
+
headers: response.headers ? response.headers.toArray() : [],
|
|
128
|
+
body: response.bodyAsU8Array ? Array.from(response.bodyAsU8Array) : null
|
|
129
|
+
};
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Execute a lifecycle method with the given request
|
|
134
|
+
*/
|
|
135
|
+
async executeLifecycle(request) {
|
|
136
|
+
if (!this.appConfig || !this.appDir) {
|
|
137
|
+
throw new Error('Wrapper not properly initialized');
|
|
138
|
+
}
|
|
139
|
+
if (!this.isInitialized) {
|
|
140
|
+
throw new Error('SDK not initialized');
|
|
141
|
+
}
|
|
142
|
+
this.sendLog('info', `Executing lifecycle method: ${request.method}`, this.currentRequestId);
|
|
143
|
+
this.sendProgress(this.currentRequestId, 'Checking lifecycle file', 20);
|
|
144
|
+
// Check if built file exists
|
|
145
|
+
if (!fs_1.default.existsSync(request.scriptPath)) {
|
|
146
|
+
throw new Error(`Lifecycle file not built or not found at ${request.scriptPath}`);
|
|
147
|
+
}
|
|
148
|
+
this.sendLog('info', `Using lifecycle file: ${request.scriptPath}`, this.currentRequestId);
|
|
149
|
+
this.sendProgress(this.currentRequestId, 'Loading lifecycle module', 40);
|
|
150
|
+
// Load the lifecycle module
|
|
151
|
+
const LifecycleModule = require(request.scriptPath);
|
|
152
|
+
const LifecycleClass = (0, utils_1.findLifecycleClass)(LifecycleModule);
|
|
153
|
+
// Create instance and call the method
|
|
154
|
+
const lifecycle = new LifecycleClass();
|
|
155
|
+
if (typeof lifecycle[request.method] !== 'function') {
|
|
156
|
+
throw new Error(`Method ${request.method} not found on Lifecycle class`);
|
|
157
|
+
}
|
|
158
|
+
this.sendLog('info', `Executing ${request.method} with params: ${JSON.stringify(request.params)}`, this.currentRequestId);
|
|
159
|
+
this.sendProgress(this.currentRequestId, 'Executing lifecycle method', 60);
|
|
160
|
+
// Call the lifecycle method with appropriate parameters
|
|
161
|
+
let result;
|
|
162
|
+
if (request.method === 'onUpgrade') {
|
|
163
|
+
result = await lifecycle[request.method](request.params?.fromVersion || '0.0.0');
|
|
164
|
+
}
|
|
165
|
+
else if (request.method === 'onSettingsForm') {
|
|
166
|
+
const params = request.params || {};
|
|
167
|
+
result = await lifecycle[request.method](params.page, params.action, params.formData);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
result = await lifecycle[request.method]();
|
|
171
|
+
}
|
|
172
|
+
this.sendLog('info', `Lifecycle method result: ${JSON.stringify(result)}`, this.currentRequestId);
|
|
173
|
+
this.sendProgress(this.currentRequestId, 'Processing result', 80);
|
|
174
|
+
// Handle different lifecycle method return types
|
|
175
|
+
let processedResult;
|
|
176
|
+
if (request.method === 'onSettingsForm') {
|
|
177
|
+
// The result should be a LifecycleSettingsResult with getResponse method
|
|
178
|
+
let settingsResponse = {};
|
|
179
|
+
if (result && typeof result.getResponse === 'function') {
|
|
180
|
+
this.sendLog('debug', 'Getting response from LifecycleSettingsResult', this.currentRequestId);
|
|
181
|
+
const params = request.params || {};
|
|
182
|
+
settingsResponse = result.getResponse(params.page);
|
|
183
|
+
this.sendLog('debug', `Settings response: ${JSON.stringify(settingsResponse)}`, this.currentRequestId);
|
|
184
|
+
}
|
|
185
|
+
else if (result) {
|
|
186
|
+
this.sendLog('debug', 'Using result as fallback', this.currentRequestId);
|
|
187
|
+
// Fallback - use result as is
|
|
188
|
+
settingsResponse = result;
|
|
189
|
+
}
|
|
190
|
+
// Mock the storage.settings.getAllSections() call since we don't have the full SDK context
|
|
191
|
+
// In real implementation, this would fetch from the app's settings store
|
|
192
|
+
const mockFormData = {}; // This will be populated by the REST endpoint
|
|
193
|
+
processedResult = {
|
|
194
|
+
result: settingsResponse,
|
|
195
|
+
data: mockFormData
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
else if (request.method === 'onInstall' || request.method === 'onUninstall' || request.method === 'onUpgrade') {
|
|
199
|
+
// These methods return LifecycleResult with success property
|
|
200
|
+
if (result && typeof result === 'object' && 'success' in result) {
|
|
201
|
+
processedResult = result;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// If the result doesn't have success property, assume success if no error was thrown
|
|
205
|
+
this.sendLog('warn', `Lifecycle method ${request.method} did not return a proper LifecycleResult object. Assuming success.`, this.currentRequestId);
|
|
206
|
+
processedResult = {
|
|
207
|
+
success: true,
|
|
208
|
+
message: result?.message || 'Operation completed without explicit success status'
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else if (request.method === 'canUninstall') {
|
|
213
|
+
// canUninstall returns CanUninstallResult with uninstallable property
|
|
214
|
+
if (result && typeof result === 'object' && 'uninstallable' in result) {
|
|
215
|
+
processedResult = result;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
// If the result doesn't have uninstallable property, this is an error
|
|
219
|
+
throw new Error(`Lifecycle method canUninstall did not return a proper CanUninstallResult object with uninstallable property. Result: ${JSON.stringify(result)}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
// Default fallback for other methods
|
|
224
|
+
processedResult = result;
|
|
225
|
+
}
|
|
226
|
+
this.sendProgress(this.currentRequestId, 'Lifecycle execution completed', 100);
|
|
227
|
+
return {
|
|
228
|
+
success: request.method === 'onSettingsForm' ? true : (processedResult?.success !== false),
|
|
229
|
+
result: processedResult
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Execute a job with the given request
|
|
234
|
+
*/
|
|
235
|
+
async executeJob(request) {
|
|
236
|
+
if (!this.appConfig || !this.appDir) {
|
|
237
|
+
throw new Error('Local engine not properly initialized');
|
|
238
|
+
}
|
|
239
|
+
if (!this.isInitialized) {
|
|
240
|
+
throw new Error('SDK not initialized');
|
|
241
|
+
}
|
|
242
|
+
this.sendLog('info', `Executing job: ${request.jobId}`, this.currentRequestId);
|
|
243
|
+
this.sendProgress(this.currentRequestId, 'Finding job file', 20);
|
|
244
|
+
// Find job definition in manifest
|
|
245
|
+
const manifest = this.appConfig.manifest;
|
|
246
|
+
let jobDef = null;
|
|
247
|
+
let isSourceJob = false;
|
|
248
|
+
// Check regular jobs
|
|
249
|
+
if (manifest.jobs && manifest.jobs[request.jobId]) {
|
|
250
|
+
jobDef = manifest.jobs[request.jobId];
|
|
251
|
+
isSourceJob = false;
|
|
252
|
+
}
|
|
253
|
+
// Check source jobs (nested under sources)
|
|
254
|
+
else if (manifest.sources) {
|
|
255
|
+
for (const [sourceId, source] of Object.entries(manifest.sources)) {
|
|
256
|
+
const sourceAny = source;
|
|
257
|
+
if (sourceAny.jobs) {
|
|
258
|
+
const compositeJobId = `${sourceId}_${Object.keys(sourceAny.jobs)[0]}`;
|
|
259
|
+
if (compositeJobId === request.jobId || Object.keys(sourceAny.jobs).includes(request.jobId)) {
|
|
260
|
+
const actualJobId = request.jobId.includes('_') ? request.jobId.split('_')[1] : request.jobId;
|
|
261
|
+
jobDef = sourceAny.jobs[actualJobId];
|
|
262
|
+
isSourceJob = true;
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (!jobDef) {
|
|
269
|
+
throw new Error(`Job not found in manifest: ${request.jobId}`);
|
|
270
|
+
}
|
|
271
|
+
// Find the built job file
|
|
272
|
+
const jobPath = path_1.default.join(this.appDir, 'dist', 'jobs', `${jobDef.entry_point}.js`);
|
|
273
|
+
if (!fs_1.default.existsSync(jobPath)) {
|
|
274
|
+
throw new Error(`Job file not built or not found: dist/jobs/${jobDef.entry_point}.js`);
|
|
275
|
+
}
|
|
276
|
+
this.sendLog('info', `Using job file: ${jobPath}`, this.currentRequestId);
|
|
277
|
+
this.sendProgress(this.currentRequestId, 'Loading job module', 40);
|
|
278
|
+
// Import job module
|
|
279
|
+
const JobModule = require(jobPath);
|
|
280
|
+
// Find job class (look for default export or named export matching entry point)
|
|
281
|
+
let JobClass = JobModule.default || JobModule[jobDef.entry_point] || JobModule;
|
|
282
|
+
if (typeof JobClass !== 'function') {
|
|
283
|
+
// Look for any class in the module
|
|
284
|
+
const exports = Object.keys(JobModule);
|
|
285
|
+
for (const key of exports) {
|
|
286
|
+
if (typeof JobModule[key] === 'function' && JobModule[key].prototype) {
|
|
287
|
+
JobClass = JobModule[key];
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (typeof JobClass !== 'function') {
|
|
293
|
+
throw new Error(`No job class found in ${jobPath}`);
|
|
294
|
+
}
|
|
295
|
+
this.sendLog('info', 'Job class found, creating invocation...', this.currentRequestId);
|
|
296
|
+
this.sendProgress(this.currentRequestId, 'Creating job invocation', 60);
|
|
297
|
+
// Create job invocation
|
|
298
|
+
const invocation = {
|
|
299
|
+
jobId: `${request.jobId}_${Date.now()}`, // Unique run ID
|
|
300
|
+
scheduledAt: new Date(),
|
|
301
|
+
parameters: request.parameters || {}
|
|
302
|
+
};
|
|
303
|
+
// Add dataSyncId for source jobs
|
|
304
|
+
if (isSourceJob && request.dataSyncId) {
|
|
305
|
+
invocation.dataSyncId = request.dataSyncId;
|
|
306
|
+
}
|
|
307
|
+
this.sendLog('info', 'Creating job instance...', this.currentRequestId);
|
|
308
|
+
// Create job instance
|
|
309
|
+
let jobInstance;
|
|
310
|
+
if (isSourceJob && request.dataSyncId) {
|
|
311
|
+
// Source job requires source parameter
|
|
312
|
+
const mockSource = { id: request.sourceKey || 'local-source' };
|
|
313
|
+
jobInstance = new JobClass(invocation, mockSource);
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
jobInstance = new JobClass(invocation);
|
|
317
|
+
}
|
|
318
|
+
// Validate job instance has required methods
|
|
319
|
+
if (typeof jobInstance.prepare !== 'function') {
|
|
320
|
+
throw new Error('Job class does not implement prepare method');
|
|
321
|
+
}
|
|
322
|
+
if (typeof jobInstance.perform !== 'function') {
|
|
323
|
+
throw new Error('Job class does not implement perform method');
|
|
324
|
+
}
|
|
325
|
+
this.sendLog('info', 'Executing job prepare method...', this.currentRequestId);
|
|
326
|
+
this.sendProgress(this.currentRequestId, 'Preparing job', 70);
|
|
327
|
+
// Import LocalJobStore to track state
|
|
328
|
+
const { LocalJobStore } = require('./storage/LocalJobStore');
|
|
329
|
+
const jobStore = LocalJobStore.getInstance(request.appDir);
|
|
330
|
+
const { createHash } = require('crypto');
|
|
331
|
+
let status;
|
|
332
|
+
let statusHash;
|
|
333
|
+
try {
|
|
334
|
+
// Execute prepare phase
|
|
335
|
+
this.sendLog('info', 'Executing job prepare method...', this.currentRequestId);
|
|
336
|
+
status = await jobInstance.prepare(request.parameters || {});
|
|
337
|
+
statusHash = createHash('sha256').update(JSON.stringify(status)).digest('hex');
|
|
338
|
+
// Save initial state from prepare
|
|
339
|
+
jobStore.saveState(request.executionId, status, status.complete || false, statusHash, 'prepare');
|
|
340
|
+
this.sendLog('info', 'Job prepared successfully', this.currentRequestId);
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
this.sendLog('error', `Job prepare failed: ${error.message}`, this.currentRequestId);
|
|
344
|
+
// Mark job as failed in store
|
|
345
|
+
const { LocalJobStore, JobExecutionStatus } = require('./storage/LocalJobStore');
|
|
346
|
+
const failedJobStore = LocalJobStore.getInstance(request.appDir);
|
|
347
|
+
failedJobStore.updateExecutionStatus(request.executionId, JobExecutionStatus.FAILED, {
|
|
348
|
+
message: error.message,
|
|
349
|
+
stack: error.stack
|
|
350
|
+
});
|
|
351
|
+
throw new Error(`Job prepare method failed: ${error.message}`);
|
|
352
|
+
}
|
|
353
|
+
this.sendLog('info', 'Job prepared, starting perform loop...', this.currentRequestId);
|
|
354
|
+
this.sendProgress(this.currentRequestId, 'Executing job', 80);
|
|
355
|
+
// Execute perform loop
|
|
356
|
+
let loopCount = 0;
|
|
357
|
+
const maxLoops = 1000; // Safety limit
|
|
358
|
+
while (!status.complete && loopCount < maxLoops) {
|
|
359
|
+
this.sendLog('debug', `Job perform loop ${loopCount + 1}`, this.currentRequestId);
|
|
360
|
+
try {
|
|
361
|
+
status = await jobInstance.perform(status);
|
|
362
|
+
loopCount++;
|
|
363
|
+
// Check if state changed and save if so
|
|
364
|
+
const newStatusHash = createHash('sha256').update(JSON.stringify(status)).digest('hex');
|
|
365
|
+
if (statusHash !== newStatusHash) {
|
|
366
|
+
jobStore.saveState(request.executionId, status, status.complete || false, newStatusHash, 'perform');
|
|
367
|
+
statusHash = newStatusHash;
|
|
368
|
+
}
|
|
369
|
+
// Update progress
|
|
370
|
+
this.sendProgress(this.currentRequestId, `Job perform loop ${loopCount}`, 80 + (loopCount / maxLoops) * 15);
|
|
371
|
+
}
|
|
372
|
+
catch (error) {
|
|
373
|
+
this.sendLog('error', `Job perform failed at loop ${loopCount + 1}: ${error.message}`, this.currentRequestId);
|
|
374
|
+
// Mark job as failed in store
|
|
375
|
+
const { LocalJobStore, JobExecutionStatus } = require('./storage/LocalJobStore');
|
|
376
|
+
const failedJobStore = LocalJobStore.getInstance(request.appDir);
|
|
377
|
+
failedJobStore.updateExecutionStatus(request.executionId, JobExecutionStatus.FAILED, {
|
|
378
|
+
message: error.message,
|
|
379
|
+
stack: error.stack
|
|
380
|
+
});
|
|
381
|
+
throw new Error(`Job perform method failed at loop ${loopCount + 1}: ${error.message}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (loopCount >= maxLoops && !status.complete) {
|
|
385
|
+
// Mark job as failed due to excessive loops
|
|
386
|
+
const { LocalJobStore, JobExecutionStatus } = require('./storage/LocalJobStore');
|
|
387
|
+
const failedJobStore = LocalJobStore.getInstance(request.appDir);
|
|
388
|
+
failedJobStore.updateExecutionStatus(request.executionId, JobExecutionStatus.FAILED, {
|
|
389
|
+
message: `Job exceeded maximum loop count (${maxLoops})`,
|
|
390
|
+
stack: new Error().stack
|
|
391
|
+
});
|
|
392
|
+
throw new Error(`Job exceeded maximum loop count (${maxLoops})`);
|
|
393
|
+
}
|
|
394
|
+
this.sendLog('info', `Job completed after ${loopCount} perform loops`, this.currentRequestId);
|
|
395
|
+
this.sendProgress(this.currentRequestId, 'Job execution completed', 100);
|
|
396
|
+
return {
|
|
397
|
+
success: true,
|
|
398
|
+
result: status,
|
|
399
|
+
loopCount
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Execute destination ready() method
|
|
404
|
+
*/
|
|
405
|
+
async executeDestinationReady(data) {
|
|
406
|
+
const { destinationId } = data; // entryPoint no longer needed
|
|
407
|
+
if (!this.runtime) {
|
|
408
|
+
throw new Error('Runtime not initialized');
|
|
409
|
+
}
|
|
410
|
+
this.sendLog('info', `Executing ready() for destination: ${destinationId}`, this.currentRequestId);
|
|
411
|
+
// Use Runtime to get destination class
|
|
412
|
+
const DestinationClass = await this.runtime.getDestinationClass(destinationId);
|
|
413
|
+
const destination = new DestinationClass();
|
|
414
|
+
const result = await destination.ready();
|
|
415
|
+
this.sendLog('info', `Destination ready() result: ${JSON.stringify(result)}`, this.currentRequestId);
|
|
416
|
+
return result;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Execute destination deliver() method
|
|
420
|
+
*/
|
|
421
|
+
async executeDestinationDeliver(data) {
|
|
422
|
+
const { destinationId, batch } = data; // entryPoint no longer needed
|
|
423
|
+
if (!this.runtime) {
|
|
424
|
+
throw new Error('Runtime not initialized');
|
|
425
|
+
}
|
|
426
|
+
this.sendLog('debug', `Batch: ${JSON.stringify(batch)}`, this.currentRequestId);
|
|
427
|
+
// Use Runtime to get destination class
|
|
428
|
+
const DestinationClass = await this.runtime.getDestinationClass(destinationId);
|
|
429
|
+
const destination = new DestinationClass();
|
|
430
|
+
const result = await destination.deliver(batch);
|
|
431
|
+
this.sendLog('info', `Destination deliver() result: ${JSON.stringify(result)}`, this.currentRequestId);
|
|
432
|
+
return result;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Execute destination schema function
|
|
436
|
+
*/
|
|
437
|
+
async executeDestinationSchema(data) {
|
|
438
|
+
const { destinationId } = data;
|
|
439
|
+
if (!this.runtime) {
|
|
440
|
+
throw new Error('Runtime not initialized');
|
|
441
|
+
}
|
|
442
|
+
this.sendLog('info', `Loading schema for destination: ${destinationId}`, this.currentRequestId);
|
|
443
|
+
// Get destination definition from manifest via Runtime
|
|
444
|
+
const destination = this.runtime.manifest.destinations?.[destinationId];
|
|
445
|
+
if (!destination) {
|
|
446
|
+
// Use Runtime's error message format for consistency with production
|
|
447
|
+
throw new Error(`No destination '${destinationId}' defined in manifest`);
|
|
448
|
+
}
|
|
449
|
+
let schema;
|
|
450
|
+
// Check if schema is static (YAML) or dynamic (function)
|
|
451
|
+
if (typeof destination.schema === 'string') {
|
|
452
|
+
// Load static YAML schema using Runtime
|
|
453
|
+
this.sendLog('info', `Loading static YAML schema: ${destination.schema}`, this.currentRequestId);
|
|
454
|
+
const allSchemas = this.runtime.getDestinationSchema();
|
|
455
|
+
// Runtime returns schemas keyed by file path, e.g., "destinations/schema/myschema.yml"
|
|
456
|
+
const schemaKey = `destinations/schema/${destination.schema}.yml`;
|
|
457
|
+
const schemaKeyYaml = `destinations/schema/${destination.schema}.yaml`;
|
|
458
|
+
schema = allSchemas[schemaKey] || allSchemas[schemaKeyYaml];
|
|
459
|
+
if (!schema) {
|
|
460
|
+
throw new Error(`Schema file not found: ${destination.schema}.yml or .yaml`);
|
|
461
|
+
}
|
|
462
|
+
this.sendLog('info', `Static schema loaded: ${destination.schema}`, this.currentRequestId);
|
|
463
|
+
}
|
|
464
|
+
else if (destination.schema?.entry_point) {
|
|
465
|
+
// Load dynamic schema function using Runtime
|
|
466
|
+
this.sendLog('info', `Loading dynamic schema function for: ${destinationId}`, this.currentRequestId);
|
|
467
|
+
const SchemaFunctionClass = await this.runtime.getDestinationSchemaFunctionClass(destinationId);
|
|
468
|
+
const schemaFunction = new SchemaFunctionClass({ destinationKey: destinationId });
|
|
469
|
+
schema = await schemaFunction.getDestinationsSchema();
|
|
470
|
+
this.sendLog('info', `Dynamic schema loaded for ${destinationId}: ${schema.name}`, this.currentRequestId);
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
throw new Error(`Destination '${destinationId}' has invalid schema configuration`);
|
|
474
|
+
}
|
|
475
|
+
return schema;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Handle source webhook
|
|
479
|
+
*/
|
|
480
|
+
async handleSourceWebhook(message) {
|
|
481
|
+
const { sourceId, guid, method, fullpath, path, params, headers, body } = message.data;
|
|
482
|
+
if (!this.appConfig) {
|
|
483
|
+
throw new Error('App configuration not initialized');
|
|
484
|
+
}
|
|
485
|
+
// Create configuration
|
|
486
|
+
const sources = this.appConfig.manifest.sources || {};
|
|
487
|
+
const sourceManifest = sources[sourceId];
|
|
488
|
+
if (!sourceManifest) {
|
|
489
|
+
throw new Error(`Source ${sourceId} not found in manifest`);
|
|
490
|
+
}
|
|
491
|
+
const config = {
|
|
492
|
+
dataSyncId: 'mock-data-sync-id',
|
|
493
|
+
sourceKey: sourceId,
|
|
494
|
+
schema: sourceManifest.schema,
|
|
495
|
+
webhookUrl: `http://localhost:${process.env.PORT || 8080}/sources/${this.appConfig.manifest.meta?.app_id}/${sourceId}/${guid}`
|
|
496
|
+
};
|
|
497
|
+
// Load SourceFunction class using runtime - pass sourceId, runtime looks up entry_point
|
|
498
|
+
const SourceFunctionClass = await this.runtime.getSourceFunctionClass(sourceId);
|
|
499
|
+
// Create Request instance using dynamically loaded class
|
|
500
|
+
// Convert body to Buffer format (SDK expects raw body as Uint8Array, not parsed object)
|
|
501
|
+
const bodyBuffer = body ? Buffer.from(JSON.stringify(body)) : Buffer.from('');
|
|
502
|
+
const request = new this.sdkComponents.Request(method, path, params, headers, bodyBuffer);
|
|
503
|
+
// Create mocked Source instance
|
|
504
|
+
const mockedSource = {
|
|
505
|
+
emit: async (data) => {
|
|
506
|
+
this.sourceDataStore.push(sourceId, data, 'webhook');
|
|
507
|
+
return { success: true };
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
// Instantiate and execute
|
|
511
|
+
const sourceFunction = new SourceFunctionClass(config, request, mockedSource);
|
|
512
|
+
const response = await sourceFunction.perform();
|
|
513
|
+
// Return response (convert to serializable format like function execution)
|
|
514
|
+
return {
|
|
515
|
+
status: response.status,
|
|
516
|
+
headers: response.headers ? response.headers.toArray() : [],
|
|
517
|
+
body: response.bodyAsU8Array ? Array.from(response.bodyAsU8Array) : null
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Handle source lifecycle
|
|
522
|
+
*/
|
|
523
|
+
async handleSourceLifecycle(message, action) {
|
|
524
|
+
const { sourceId, guid } = message.data;
|
|
525
|
+
if (!this.appConfig) {
|
|
526
|
+
throw new Error('App configuration not initialized');
|
|
527
|
+
}
|
|
528
|
+
// Create configuration
|
|
529
|
+
const sources = this.appConfig.manifest.sources || {};
|
|
530
|
+
const sourceManifest = sources[sourceId];
|
|
531
|
+
if (!sourceManifest) {
|
|
532
|
+
throw new Error(`Source ${sourceId} not found in manifest`);
|
|
533
|
+
}
|
|
534
|
+
const config = {
|
|
535
|
+
dataSyncId: 'mock-data-sync-id',
|
|
536
|
+
sourceKey: sourceId,
|
|
537
|
+
schema: sourceManifest.schema,
|
|
538
|
+
webhookUrl: `http://localhost:${process.env.PORT || 8080}/sources/${this.appConfig.manifest.meta?.app_id}/${sourceId}/${guid}`
|
|
539
|
+
};
|
|
540
|
+
// Load SourceLifecycle class using runtime - pass sourceId, runtime looks up entry_point
|
|
541
|
+
// Returns null if no lifecycle handler defined
|
|
542
|
+
const SourceLifecycleClass = await this.runtime.getSourceLifecycleClass(sourceId);
|
|
543
|
+
if (!SourceLifecycleClass) {
|
|
544
|
+
return {
|
|
545
|
+
success: true,
|
|
546
|
+
message: 'No lifecycle handler defined for this source'
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
// Instantiate lifecycle handler
|
|
550
|
+
const lifecycle = new SourceLifecycleClass(config);
|
|
551
|
+
// Call appropriate method
|
|
552
|
+
let result;
|
|
553
|
+
switch (action) {
|
|
554
|
+
case 'create':
|
|
555
|
+
result = await lifecycle.onSourceCreate();
|
|
556
|
+
break;
|
|
557
|
+
case 'update':
|
|
558
|
+
result = await lifecycle.onSourceUpdate();
|
|
559
|
+
break;
|
|
560
|
+
case 'delete':
|
|
561
|
+
result = await lifecycle.onSourceDelete();
|
|
562
|
+
break;
|
|
563
|
+
case 'enable':
|
|
564
|
+
result = await lifecycle.onSourceEnable();
|
|
565
|
+
break;
|
|
566
|
+
case 'pause':
|
|
567
|
+
result = await lifecycle.onSourcePause();
|
|
568
|
+
break;
|
|
569
|
+
default:
|
|
570
|
+
throw new Error(`Unknown lifecycle action: ${action}`);
|
|
571
|
+
}
|
|
572
|
+
return result;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Handle source job
|
|
576
|
+
*/
|
|
577
|
+
async handleSourceJob(message) {
|
|
578
|
+
const { sourceId, jobId, parameters } = message.data;
|
|
579
|
+
const startTime = Date.now();
|
|
580
|
+
const logs = [];
|
|
581
|
+
try {
|
|
582
|
+
if (!this.appConfig) {
|
|
583
|
+
throw new Error('App configuration not initialized');
|
|
584
|
+
}
|
|
585
|
+
// Load SourceJob class using runtime - pass sourceId and jobId, runtime looks up entry_point
|
|
586
|
+
const SourceJobClass = await this.runtime.getSourceJobClass(sourceId, jobId);
|
|
587
|
+
// Create mocked Source instance
|
|
588
|
+
const mockedSource = {
|
|
589
|
+
emit: async (data) => {
|
|
590
|
+
this.sourceDataStore.push(sourceId, data, 'job');
|
|
591
|
+
logs.push(`Pushed data: ${JSON.stringify(data)}`);
|
|
592
|
+
return { success: true };
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
// Create invocation
|
|
596
|
+
const invocation = {
|
|
597
|
+
jobId,
|
|
598
|
+
scheduledAt: new Date(),
|
|
599
|
+
parameters: parameters || {},
|
|
600
|
+
dataSyncId: 'mock-data-sync-id'
|
|
601
|
+
};
|
|
602
|
+
// Instantiate job
|
|
603
|
+
const job = new SourceJobClass(invocation, mockedSource);
|
|
604
|
+
// Execute prepare
|
|
605
|
+
logs.push('Preparing job...');
|
|
606
|
+
let status = await job.prepare(parameters || {});
|
|
607
|
+
logs.push('Job prepared');
|
|
608
|
+
// Execute perform loop
|
|
609
|
+
let iterations = 0;
|
|
610
|
+
const maxIterations = 100;
|
|
611
|
+
while (!status.complete && iterations < maxIterations) {
|
|
612
|
+
logs.push(`Performing iteration ${iterations + 1}...`);
|
|
613
|
+
status = await job.perform(status);
|
|
614
|
+
iterations++;
|
|
615
|
+
}
|
|
616
|
+
if (!status.complete) {
|
|
617
|
+
logs.push(`Warning: Job did not complete after ${maxIterations} iterations`);
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
logs.push('Job completed successfully');
|
|
621
|
+
}
|
|
622
|
+
const executionTime = Date.now() - startTime;
|
|
623
|
+
// Store execution
|
|
624
|
+
this.sourceJobExecutionStore.addExecution(sourceId, {
|
|
625
|
+
jobId,
|
|
626
|
+
timestamp: Date.now(),
|
|
627
|
+
success: true,
|
|
628
|
+
logs,
|
|
629
|
+
executionTime,
|
|
630
|
+
result: status
|
|
631
|
+
});
|
|
632
|
+
return {
|
|
633
|
+
success: true,
|
|
634
|
+
logs,
|
|
635
|
+
executionTime,
|
|
636
|
+
result: status
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
catch (error) {
|
|
640
|
+
const executionTime = Date.now() - startTime;
|
|
641
|
+
logs.push(`Error: ${error.message}`);
|
|
642
|
+
// Store failed execution
|
|
643
|
+
this.sourceJobExecutionStore.addExecution(sourceId, {
|
|
644
|
+
jobId,
|
|
645
|
+
timestamp: Date.now(),
|
|
646
|
+
success: false,
|
|
647
|
+
logs,
|
|
648
|
+
executionTime,
|
|
649
|
+
error: error.message
|
|
650
|
+
});
|
|
651
|
+
throw error; // Let the base class handler catch and send the error
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Handle source schema
|
|
656
|
+
*/
|
|
657
|
+
async handleSourceSchema(message) {
|
|
658
|
+
const { sourceId } = message.data;
|
|
659
|
+
if (!this.appConfig) {
|
|
660
|
+
throw new Error('App configuration not initialized');
|
|
661
|
+
}
|
|
662
|
+
if (!this.runtime) {
|
|
663
|
+
throw new Error('Runtime not initialized');
|
|
664
|
+
}
|
|
665
|
+
const sources = this.appConfig.manifest.sources || {};
|
|
666
|
+
const sourceManifest = sources[sourceId];
|
|
667
|
+
if (!sourceManifest) {
|
|
668
|
+
throw new Error(`Source ${sourceId} not found in manifest`);
|
|
669
|
+
}
|
|
670
|
+
const schema = sourceManifest.schema;
|
|
671
|
+
// Static schema - load from YAML file using Runtime
|
|
672
|
+
if (typeof schema === 'string') {
|
|
673
|
+
this.sendLog('info', `Loading static YAML schema: ${schema}`, this.currentRequestId);
|
|
674
|
+
const allSchemas = this.runtime.getSourceSchema();
|
|
675
|
+
// Runtime returns schemas keyed by file path, e.g., "sources/schema/myschema.yml"
|
|
676
|
+
const schemaKey = `sources/schema/${schema}.yml`;
|
|
677
|
+
const schemaKeyYaml = `sources/schema/${schema}.yaml`;
|
|
678
|
+
const loadedSchema = allSchemas[schemaKey] || allSchemas[schemaKeyYaml];
|
|
679
|
+
if (!loadedSchema) {
|
|
680
|
+
throw new Error(`Schema file not found: ${schema}.yml or .yaml`);
|
|
681
|
+
}
|
|
682
|
+
this.sendLog('info', `Static schema loaded: ${schema}`, this.currentRequestId);
|
|
683
|
+
return loadedSchema;
|
|
684
|
+
}
|
|
685
|
+
// Dynamic schema - call the schema function
|
|
686
|
+
if (typeof schema === 'object' && schema.entry_point) {
|
|
687
|
+
this.sendLog('info', `Loading dynamic schema function for: ${sourceId}`, this.currentRequestId);
|
|
688
|
+
const SchemaFunctionClass = await this.runtime.getSourceSchemaFunctionClass(sourceId);
|
|
689
|
+
const config = {
|
|
690
|
+
sourceKey: sourceId
|
|
691
|
+
};
|
|
692
|
+
const schemaFunction = new SchemaFunctionClass(config);
|
|
693
|
+
const result = await schemaFunction.getSourcesSchema();
|
|
694
|
+
this.sendLog('info', `Dynamic schema loaded for ${sourceId}`, this.currentRequestId);
|
|
695
|
+
return result;
|
|
696
|
+
}
|
|
697
|
+
throw new Error('Invalid schema configuration');
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Clean up SDK configuration
|
|
701
|
+
* This only happens when the process is shutting down
|
|
702
|
+
*/
|
|
703
|
+
async cleanup() {
|
|
704
|
+
this.sendLog('info', 'Cleaning up unified wrapper');
|
|
705
|
+
if (this.cleanUpLocalSDKs && this.appDir && this.isInitialized) {
|
|
706
|
+
try {
|
|
707
|
+
this.cleanUpLocalSDKs(this.appDir);
|
|
708
|
+
this.sendLog('info', 'SDK cleanup completed');
|
|
709
|
+
this.isInitialized = false;
|
|
710
|
+
}
|
|
711
|
+
catch (error) {
|
|
712
|
+
this.sendLog('warn', `SDK cleanup error: ${error}`);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
exports.LocalEngineUnified = LocalEngineUnified;
|
|
718
|
+
// Only execute if this script is run directly (not imported)
|
|
719
|
+
if (require.main === module) {
|
|
720
|
+
const localEngine = new LocalEngineUnified();
|
|
721
|
+
localEngine.start();
|
|
722
|
+
}
|
|
723
|
+
//# sourceMappingURL=local-engine-unified.js.map
|