@elevasis/sdk 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +77 -5
- package/dist/index.d.ts +67 -1
- package/dist/index.js +73 -1
- package/dist/worker/index.js +121 -0
- package/package.json +4 -4
- package/dist/server/index.js +0 -174
package/dist/cli.cjs
CHANGED
|
@@ -39746,9 +39746,15 @@ var ResourceRegistry = class {
|
|
|
39746
39746
|
}
|
|
39747
39747
|
/**
|
|
39748
39748
|
* Pre-serialized organization data cache
|
|
39749
|
-
* Computed once at construction,
|
|
39749
|
+
* Computed once at construction for static orgs, updated incrementally for runtime orgs
|
|
39750
39750
|
*/
|
|
39751
39751
|
serializedCache;
|
|
39752
|
+
/**
|
|
39753
|
+
* Runtime-registered organizations (external deployments)
|
|
39754
|
+
* Tracks which orgs were added at runtime vs. static startup.
|
|
39755
|
+
* Used to guard against unregistering static orgs and to store remote config.
|
|
39756
|
+
*/
|
|
39757
|
+
runtimeOrgs = /* @__PURE__ */ new Map();
|
|
39752
39758
|
/**
|
|
39753
39759
|
* Validates registry on construction
|
|
39754
39760
|
* - Checks for duplicate resourceIds within organizations
|
|
@@ -39848,6 +39854,72 @@ var ResourceRegistry = class {
|
|
|
39848
39854
|
return this.registry;
|
|
39849
39855
|
}
|
|
39850
39856
|
// ============================================================================
|
|
39857
|
+
// Runtime Organization Registration (External Deployments)
|
|
39858
|
+
// ============================================================================
|
|
39859
|
+
/**
|
|
39860
|
+
* Register an external organization at runtime
|
|
39861
|
+
*
|
|
39862
|
+
* Called during deploy pipeline when an external developer deploys their bundle.
|
|
39863
|
+
* Adds the org's stub definitions to the registry and stores remote config
|
|
39864
|
+
* for worker thread execution branching.
|
|
39865
|
+
*
|
|
39866
|
+
* - If orgName conflicts with a static (startup) org, throws an error
|
|
39867
|
+
* - If orgName is already runtime-registered (redeploy), unregisters first
|
|
39868
|
+
*
|
|
39869
|
+
* @param orgName - Organization name (used as registry key)
|
|
39870
|
+
* @param org - Stub resource definitions (workflows/agents with placeholder handlers)
|
|
39871
|
+
* @param remote - Remote configuration (bundle path, deployment ID, env vars)
|
|
39872
|
+
* @throws Error if orgName conflicts with a static organization
|
|
39873
|
+
*/
|
|
39874
|
+
registerOrganization(orgName, org, remote) {
|
|
39875
|
+
if (this.registry[orgName] && !this.runtimeOrgs.has(orgName)) {
|
|
39876
|
+
throw new Error(`Organization '${orgName}' conflicts with a static organization`);
|
|
39877
|
+
}
|
|
39878
|
+
if (this.runtimeOrgs.has(orgName)) {
|
|
39879
|
+
this.unregisterOrganization(orgName);
|
|
39880
|
+
}
|
|
39881
|
+
this.registry[orgName] = org;
|
|
39882
|
+
this.runtimeOrgs.set(orgName, remote);
|
|
39883
|
+
this.serializedCache.set(orgName, serializeOrganization(org));
|
|
39884
|
+
}
|
|
39885
|
+
/**
|
|
39886
|
+
* Unregister a runtime-registered organization
|
|
39887
|
+
*
|
|
39888
|
+
* Only removes organizations that were registered at runtime (via registerOrganization).
|
|
39889
|
+
* Static organizations loaded at startup are protected and cannot be unregistered.
|
|
39890
|
+
* No-op if the org is not runtime-registered.
|
|
39891
|
+
*
|
|
39892
|
+
* @param orgName - Organization name to unregister
|
|
39893
|
+
*/
|
|
39894
|
+
unregisterOrganization(orgName) {
|
|
39895
|
+
if (!this.runtimeOrgs.has(orgName)) return;
|
|
39896
|
+
delete this.registry[orgName];
|
|
39897
|
+
this.runtimeOrgs.delete(orgName);
|
|
39898
|
+
this.serializedCache.delete(orgName);
|
|
39899
|
+
}
|
|
39900
|
+
/**
|
|
39901
|
+
* Get remote configuration for an organization
|
|
39902
|
+
*
|
|
39903
|
+
* Returns the RemoteOrgConfig if the org was registered at runtime,
|
|
39904
|
+
* or null if it's a static org or doesn't exist.
|
|
39905
|
+
* Used by the execution coordinator to branch between local and worker execution.
|
|
39906
|
+
*
|
|
39907
|
+
* @param orgName - Organization name
|
|
39908
|
+
* @returns Remote config or null
|
|
39909
|
+
*/
|
|
39910
|
+
getRemoteConfig(orgName) {
|
|
39911
|
+
return this.runtimeOrgs.get(orgName) ?? null;
|
|
39912
|
+
}
|
|
39913
|
+
/**
|
|
39914
|
+
* Check if an organization is a remote (externally deployed) organization
|
|
39915
|
+
*
|
|
39916
|
+
* @param orgName - Organization name
|
|
39917
|
+
* @returns true if the org was registered at runtime
|
|
39918
|
+
*/
|
|
39919
|
+
isRemote(orgName) {
|
|
39920
|
+
return this.runtimeOrgs.has(orgName);
|
|
39921
|
+
}
|
|
39922
|
+
// ============================================================================
|
|
39851
39923
|
// Resource Manifest Accessors
|
|
39852
39924
|
// ============================================================================
|
|
39853
39925
|
/**
|
|
@@ -40233,13 +40305,13 @@ function registerDeployCommand(program3) {
|
|
|
40233
40305
|
console.log("");
|
|
40234
40306
|
}
|
|
40235
40307
|
const bundleSpinner = ora("Bundling...").start();
|
|
40236
|
-
const wrapperPath = (0, import_path2.resolve)("
|
|
40308
|
+
const wrapperPath = (0, import_path2.resolve)("__elevasis_worker.ts");
|
|
40237
40309
|
const bundleOutfile = (0, import_path2.resolve)("dist/bundle.js");
|
|
40238
40310
|
try {
|
|
40239
40311
|
const entryImport = entryPath.replace(/\.ts$/, ".js");
|
|
40240
40312
|
const wrapperContent = `import org from ${JSON.stringify(entryImport)}
|
|
40241
|
-
import {
|
|
40242
|
-
|
|
40313
|
+
import { startWorker } from '@elevasis/sdk/worker'
|
|
40314
|
+
startWorker(org)
|
|
40243
40315
|
`;
|
|
40244
40316
|
await (0, import_promises.writeFile)(wrapperPath, wrapperContent, "utf-8");
|
|
40245
40317
|
await (0, import_promises.mkdir)((0, import_path2.resolve)("dist"), { recursive: true });
|
|
@@ -40703,7 +40775,7 @@ var import_path3 = require("path");
|
|
|
40703
40775
|
var import_promises2 = require("fs/promises");
|
|
40704
40776
|
|
|
40705
40777
|
// src/cli/version.ts
|
|
40706
|
-
var SDK_VERSION = "0.
|
|
40778
|
+
var SDK_VERSION = "0.4.0";
|
|
40707
40779
|
|
|
40708
40780
|
// src/cli/commands/init.ts
|
|
40709
40781
|
var SCAFFOLD_FILES = [
|
package/dist/index.d.ts
CHANGED
|
@@ -1054,6 +1054,22 @@ interface IterationContext {
|
|
|
1054
1054
|
* - Command View data generation
|
|
1055
1055
|
*/
|
|
1056
1056
|
|
|
1057
|
+
/**
|
|
1058
|
+
* Configuration for a remotely-deployed organization
|
|
1059
|
+
*
|
|
1060
|
+
* Stored alongside runtime-registered organizations to support
|
|
1061
|
+
* worker thread execution branching and credential management.
|
|
1062
|
+
*/
|
|
1063
|
+
interface RemoteOrgConfig {
|
|
1064
|
+
/** Path to the esbuild bundle on disk */
|
|
1065
|
+
bundlePath: string;
|
|
1066
|
+
/** Deployment record ID */
|
|
1067
|
+
deploymentId: string;
|
|
1068
|
+
/** Developer-provided environment variables injected into the worker */
|
|
1069
|
+
envVars?: Record<string, string>;
|
|
1070
|
+
/** Platform tool name -> credential name mapping */
|
|
1071
|
+
toolCredentials?: Record<string, string>;
|
|
1072
|
+
}
|
|
1057
1073
|
/**
|
|
1058
1074
|
* Organization-specific resource collection
|
|
1059
1075
|
*
|
|
@@ -1084,9 +1100,15 @@ declare class ResourceRegistry {
|
|
|
1084
1100
|
private registry;
|
|
1085
1101
|
/**
|
|
1086
1102
|
* Pre-serialized organization data cache
|
|
1087
|
-
* Computed once at construction,
|
|
1103
|
+
* Computed once at construction for static orgs, updated incrementally for runtime orgs
|
|
1088
1104
|
*/
|
|
1089
1105
|
private serializedCache;
|
|
1106
|
+
/**
|
|
1107
|
+
* Runtime-registered organizations (external deployments)
|
|
1108
|
+
* Tracks which orgs were added at runtime vs. static startup.
|
|
1109
|
+
* Used to guard against unregistering static orgs and to store remote config.
|
|
1110
|
+
*/
|
|
1111
|
+
private runtimeOrgs;
|
|
1090
1112
|
constructor(registry: OrganizationRegistry);
|
|
1091
1113
|
/**
|
|
1092
1114
|
* Validates registry on construction
|
|
@@ -1122,6 +1144,50 @@ declare class ResourceRegistry {
|
|
|
1122
1144
|
* NOTE: For debugging only - returns raw registry data
|
|
1123
1145
|
*/
|
|
1124
1146
|
listAllResources(): OrganizationRegistry;
|
|
1147
|
+
/**
|
|
1148
|
+
* Register an external organization at runtime
|
|
1149
|
+
*
|
|
1150
|
+
* Called during deploy pipeline when an external developer deploys their bundle.
|
|
1151
|
+
* Adds the org's stub definitions to the registry and stores remote config
|
|
1152
|
+
* for worker thread execution branching.
|
|
1153
|
+
*
|
|
1154
|
+
* - If orgName conflicts with a static (startup) org, throws an error
|
|
1155
|
+
* - If orgName is already runtime-registered (redeploy), unregisters first
|
|
1156
|
+
*
|
|
1157
|
+
* @param orgName - Organization name (used as registry key)
|
|
1158
|
+
* @param org - Stub resource definitions (workflows/agents with placeholder handlers)
|
|
1159
|
+
* @param remote - Remote configuration (bundle path, deployment ID, env vars)
|
|
1160
|
+
* @throws Error if orgName conflicts with a static organization
|
|
1161
|
+
*/
|
|
1162
|
+
registerOrganization(orgName: string, org: OrganizationResources, remote: RemoteOrgConfig): void;
|
|
1163
|
+
/**
|
|
1164
|
+
* Unregister a runtime-registered organization
|
|
1165
|
+
*
|
|
1166
|
+
* Only removes organizations that were registered at runtime (via registerOrganization).
|
|
1167
|
+
* Static organizations loaded at startup are protected and cannot be unregistered.
|
|
1168
|
+
* No-op if the org is not runtime-registered.
|
|
1169
|
+
*
|
|
1170
|
+
* @param orgName - Organization name to unregister
|
|
1171
|
+
*/
|
|
1172
|
+
unregisterOrganization(orgName: string): void;
|
|
1173
|
+
/**
|
|
1174
|
+
* Get remote configuration for an organization
|
|
1175
|
+
*
|
|
1176
|
+
* Returns the RemoteOrgConfig if the org was registered at runtime,
|
|
1177
|
+
* or null if it's a static org or doesn't exist.
|
|
1178
|
+
* Used by the execution coordinator to branch between local and worker execution.
|
|
1179
|
+
*
|
|
1180
|
+
* @param orgName - Organization name
|
|
1181
|
+
* @returns Remote config or null
|
|
1182
|
+
*/
|
|
1183
|
+
getRemoteConfig(orgName: string): RemoteOrgConfig | null;
|
|
1184
|
+
/**
|
|
1185
|
+
* Check if an organization is a remote (externally deployed) organization
|
|
1186
|
+
*
|
|
1187
|
+
* @param orgName - Organization name
|
|
1188
|
+
* @returns true if the org was registered at runtime
|
|
1189
|
+
*/
|
|
1190
|
+
isRemote(orgName: string): boolean;
|
|
1125
1191
|
/**
|
|
1126
1192
|
* Get triggers for an organization
|
|
1127
1193
|
* @param organizationName - Organization name
|
package/dist/index.js
CHANGED
|
@@ -3162,9 +3162,15 @@ var ResourceRegistry = class {
|
|
|
3162
3162
|
}
|
|
3163
3163
|
/**
|
|
3164
3164
|
* Pre-serialized organization data cache
|
|
3165
|
-
* Computed once at construction,
|
|
3165
|
+
* Computed once at construction for static orgs, updated incrementally for runtime orgs
|
|
3166
3166
|
*/
|
|
3167
3167
|
serializedCache;
|
|
3168
|
+
/**
|
|
3169
|
+
* Runtime-registered organizations (external deployments)
|
|
3170
|
+
* Tracks which orgs were added at runtime vs. static startup.
|
|
3171
|
+
* Used to guard against unregistering static orgs and to store remote config.
|
|
3172
|
+
*/
|
|
3173
|
+
runtimeOrgs = /* @__PURE__ */ new Map();
|
|
3168
3174
|
/**
|
|
3169
3175
|
* Validates registry on construction
|
|
3170
3176
|
* - Checks for duplicate resourceIds within organizations
|
|
@@ -3264,6 +3270,72 @@ var ResourceRegistry = class {
|
|
|
3264
3270
|
return this.registry;
|
|
3265
3271
|
}
|
|
3266
3272
|
// ============================================================================
|
|
3273
|
+
// Runtime Organization Registration (External Deployments)
|
|
3274
|
+
// ============================================================================
|
|
3275
|
+
/**
|
|
3276
|
+
* Register an external organization at runtime
|
|
3277
|
+
*
|
|
3278
|
+
* Called during deploy pipeline when an external developer deploys their bundle.
|
|
3279
|
+
* Adds the org's stub definitions to the registry and stores remote config
|
|
3280
|
+
* for worker thread execution branching.
|
|
3281
|
+
*
|
|
3282
|
+
* - If orgName conflicts with a static (startup) org, throws an error
|
|
3283
|
+
* - If orgName is already runtime-registered (redeploy), unregisters first
|
|
3284
|
+
*
|
|
3285
|
+
* @param orgName - Organization name (used as registry key)
|
|
3286
|
+
* @param org - Stub resource definitions (workflows/agents with placeholder handlers)
|
|
3287
|
+
* @param remote - Remote configuration (bundle path, deployment ID, env vars)
|
|
3288
|
+
* @throws Error if orgName conflicts with a static organization
|
|
3289
|
+
*/
|
|
3290
|
+
registerOrganization(orgName, org, remote) {
|
|
3291
|
+
if (this.registry[orgName] && !this.runtimeOrgs.has(orgName)) {
|
|
3292
|
+
throw new Error(`Organization '${orgName}' conflicts with a static organization`);
|
|
3293
|
+
}
|
|
3294
|
+
if (this.runtimeOrgs.has(orgName)) {
|
|
3295
|
+
this.unregisterOrganization(orgName);
|
|
3296
|
+
}
|
|
3297
|
+
this.registry[orgName] = org;
|
|
3298
|
+
this.runtimeOrgs.set(orgName, remote);
|
|
3299
|
+
this.serializedCache.set(orgName, serializeOrganization(org));
|
|
3300
|
+
}
|
|
3301
|
+
/**
|
|
3302
|
+
* Unregister a runtime-registered organization
|
|
3303
|
+
*
|
|
3304
|
+
* Only removes organizations that were registered at runtime (via registerOrganization).
|
|
3305
|
+
* Static organizations loaded at startup are protected and cannot be unregistered.
|
|
3306
|
+
* No-op if the org is not runtime-registered.
|
|
3307
|
+
*
|
|
3308
|
+
* @param orgName - Organization name to unregister
|
|
3309
|
+
*/
|
|
3310
|
+
unregisterOrganization(orgName) {
|
|
3311
|
+
if (!this.runtimeOrgs.has(orgName)) return;
|
|
3312
|
+
delete this.registry[orgName];
|
|
3313
|
+
this.runtimeOrgs.delete(orgName);
|
|
3314
|
+
this.serializedCache.delete(orgName);
|
|
3315
|
+
}
|
|
3316
|
+
/**
|
|
3317
|
+
* Get remote configuration for an organization
|
|
3318
|
+
*
|
|
3319
|
+
* Returns the RemoteOrgConfig if the org was registered at runtime,
|
|
3320
|
+
* or null if it's a static org or doesn't exist.
|
|
3321
|
+
* Used by the execution coordinator to branch between local and worker execution.
|
|
3322
|
+
*
|
|
3323
|
+
* @param orgName - Organization name
|
|
3324
|
+
* @returns Remote config or null
|
|
3325
|
+
*/
|
|
3326
|
+
getRemoteConfig(orgName) {
|
|
3327
|
+
return this.runtimeOrgs.get(orgName) ?? null;
|
|
3328
|
+
}
|
|
3329
|
+
/**
|
|
3330
|
+
* Check if an organization is a remote (externally deployed) organization
|
|
3331
|
+
*
|
|
3332
|
+
* @param orgName - Organization name
|
|
3333
|
+
* @returns true if the org was registered at runtime
|
|
3334
|
+
*/
|
|
3335
|
+
isRemote(orgName) {
|
|
3336
|
+
return this.runtimeOrgs.has(orgName);
|
|
3337
|
+
}
|
|
3338
|
+
// ============================================================================
|
|
3267
3339
|
// Resource Manifest Accessors
|
|
3268
3340
|
// ============================================================================
|
|
3269
3341
|
/**
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { parentPort } from 'worker_threads';
|
|
2
|
+
|
|
3
|
+
// src/worker/index.ts
|
|
4
|
+
function resolveNext(next, data) {
|
|
5
|
+
if (next === null) return null;
|
|
6
|
+
if (next.type === "linear") return next.target;
|
|
7
|
+
for (const route of next.routes) {
|
|
8
|
+
if (route.condition(data)) return route.target;
|
|
9
|
+
}
|
|
10
|
+
return next.default;
|
|
11
|
+
}
|
|
12
|
+
async function executeWorkflow(workflow, input) {
|
|
13
|
+
const logs = [];
|
|
14
|
+
const origLog = console.log;
|
|
15
|
+
const origWarn = console.warn;
|
|
16
|
+
const origError = console.error;
|
|
17
|
+
const capture = (level, orig) => (...args) => {
|
|
18
|
+
logs.push({ level, message: args.map(String).join(" ") });
|
|
19
|
+
orig(...args);
|
|
20
|
+
};
|
|
21
|
+
console.log = capture("info", origLog);
|
|
22
|
+
console.warn = capture("warn", origWarn);
|
|
23
|
+
console.error = capture("error", origError);
|
|
24
|
+
try {
|
|
25
|
+
let currentData = workflow.contract.inputSchema ? workflow.contract.inputSchema.parse(input) : input;
|
|
26
|
+
let stepId = workflow.entryPoint;
|
|
27
|
+
while (stepId !== null) {
|
|
28
|
+
const step = workflow.steps[stepId];
|
|
29
|
+
if (!step) {
|
|
30
|
+
throw new Error(`Step '${stepId}' not found in workflow '${workflow.config.resourceId}'`);
|
|
31
|
+
}
|
|
32
|
+
const stepInput = step.inputSchema.parse(currentData);
|
|
33
|
+
const rawOutput = await step.handler(stepInput, {
|
|
34
|
+
executionId: "",
|
|
35
|
+
organizationId: "",
|
|
36
|
+
organizationName: "",
|
|
37
|
+
resourceId: workflow.config.resourceId,
|
|
38
|
+
executionDepth: 0,
|
|
39
|
+
store: /* @__PURE__ */ new Map(),
|
|
40
|
+
logger: {
|
|
41
|
+
debug: (msg) => console.log(`[debug] ${msg}`),
|
|
42
|
+
info: (msg) => console.log(`[info] ${msg}`),
|
|
43
|
+
warn: (msg) => console.warn(`[warn] ${msg}`),
|
|
44
|
+
error: (msg) => console.error(`[error] ${msg}`)
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
currentData = step.outputSchema.parse(rawOutput);
|
|
48
|
+
stepId = resolveNext(step.next, currentData);
|
|
49
|
+
}
|
|
50
|
+
if (workflow.contract.outputSchema) {
|
|
51
|
+
currentData = workflow.contract.outputSchema.parse(currentData);
|
|
52
|
+
}
|
|
53
|
+
return { output: currentData, logs };
|
|
54
|
+
} finally {
|
|
55
|
+
console.log = origLog;
|
|
56
|
+
console.warn = origWarn;
|
|
57
|
+
console.error = origError;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function startWorker(org) {
|
|
61
|
+
const workflows = new Map(
|
|
62
|
+
(org.workflows ?? []).map((w) => [w.config.resourceId, w])
|
|
63
|
+
);
|
|
64
|
+
const agents = new Map(
|
|
65
|
+
(org.agents ?? []).map((a) => [a.config.resourceId, a])
|
|
66
|
+
);
|
|
67
|
+
parentPort.on("message", async (msg) => {
|
|
68
|
+
if (msg.type === "manifest") {
|
|
69
|
+
parentPort.postMessage({
|
|
70
|
+
type: "manifest",
|
|
71
|
+
workflows: (org.workflows ?? []).map((w) => ({
|
|
72
|
+
resourceId: w.config.resourceId,
|
|
73
|
+
name: w.config.name,
|
|
74
|
+
type: w.config.type,
|
|
75
|
+
status: w.config.status,
|
|
76
|
+
description: w.config.description,
|
|
77
|
+
version: w.config.version
|
|
78
|
+
})),
|
|
79
|
+
agents: (org.agents ?? []).map((a) => ({
|
|
80
|
+
resourceId: a.config.resourceId,
|
|
81
|
+
name: a.config.name,
|
|
82
|
+
type: a.config.type,
|
|
83
|
+
status: a.config.status,
|
|
84
|
+
description: a.config.description,
|
|
85
|
+
version: a.config.version
|
|
86
|
+
}))
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (msg.type === "execute") {
|
|
91
|
+
const { resourceId, input } = msg;
|
|
92
|
+
const workflow = workflows.get(resourceId);
|
|
93
|
+
if (workflow) {
|
|
94
|
+
try {
|
|
95
|
+
const { output, logs } = await executeWorkflow(workflow, input);
|
|
96
|
+
parentPort.postMessage({ type: "result", status: "completed", output, logs });
|
|
97
|
+
} catch (err) {
|
|
98
|
+
parentPort.postMessage({ type: "result", status: "failed", error: String(err), logs: [] });
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (agents.has(resourceId)) {
|
|
103
|
+
parentPort.postMessage({
|
|
104
|
+
type: "result",
|
|
105
|
+
status: "failed",
|
|
106
|
+
error: "Agent execution not yet supported in worker runtime",
|
|
107
|
+
logs: []
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
parentPort.postMessage({
|
|
112
|
+
type: "result",
|
|
113
|
+
status: "failed",
|
|
114
|
+
error: `Resource not found: ${resourceId}`,
|
|
115
|
+
logs: []
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export { startWorker };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elevasis/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "SDK for building Elevasis organization resources",
|
|
5
5
|
"comment:bin": "IMPORTANT: This package shares the 'elevasis' binary name with @repo/cli. They never conflict because @elevasis/sdk must NEVER be added as a dependency of any workspace package (apps/*, packages/*, organizations/*). Workspace projects use @repo/cli for the 'elevasis' binary. External developers (outside the workspace) get this SDK's binary via npm install.",
|
|
6
6
|
"type": "module",
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"import": "./dist/index.js"
|
|
15
15
|
},
|
|
16
|
-
"./
|
|
17
|
-
"import": "./dist/
|
|
16
|
+
"./worker": {
|
|
17
|
+
"import": "./dist/worker/index.js"
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
21
|
"dist/index.js",
|
|
22
22
|
"dist/index.d.ts",
|
|
23
|
-
"dist/
|
|
23
|
+
"dist/worker/index.js",
|
|
24
24
|
"dist/cli.cjs"
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
package/dist/server/index.js
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import { createServer } from 'http';
|
|
2
|
-
|
|
3
|
-
// src/server/index.ts
|
|
4
|
-
function readBody(req) {
|
|
5
|
-
return new Promise((resolve, reject) => {
|
|
6
|
-
const chunks = [];
|
|
7
|
-
req.on("data", (chunk) => chunks.push(chunk));
|
|
8
|
-
req.on("end", () => resolve(Buffer.concat(chunks).toString()));
|
|
9
|
-
req.on("error", reject);
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
function json(res, status, data) {
|
|
13
|
-
res.writeHead(status, { "Content-Type": "application/json" });
|
|
14
|
-
res.end(JSON.stringify(data));
|
|
15
|
-
}
|
|
16
|
-
function resolveNext(next, data) {
|
|
17
|
-
if (next === null) return null;
|
|
18
|
-
if (next.type === "linear") return next.target;
|
|
19
|
-
for (const route of next.routes) {
|
|
20
|
-
if (route.condition(data)) return route.target;
|
|
21
|
-
}
|
|
22
|
-
return next.default;
|
|
23
|
-
}
|
|
24
|
-
async function executeWorkflow(workflow, input, context) {
|
|
25
|
-
let currentData = workflow.contract.inputSchema.parse(input);
|
|
26
|
-
let stepId = workflow.entryPoint;
|
|
27
|
-
while (stepId !== null) {
|
|
28
|
-
if (context.signal?.aborted) {
|
|
29
|
-
throw new Error("Execution cancelled");
|
|
30
|
-
}
|
|
31
|
-
const step = workflow.steps[stepId];
|
|
32
|
-
if (!step) {
|
|
33
|
-
throw new Error(`Step '${stepId}' not found in workflow '${workflow.config.resourceId}'`);
|
|
34
|
-
}
|
|
35
|
-
const stepInput = step.inputSchema.parse(currentData);
|
|
36
|
-
const rawOutput = await step.handler(stepInput, context);
|
|
37
|
-
currentData = step.outputSchema.parse(rawOutput);
|
|
38
|
-
stepId = resolveNext(step.next, currentData);
|
|
39
|
-
}
|
|
40
|
-
if (workflow.contract.outputSchema) {
|
|
41
|
-
currentData = workflow.contract.outputSchema.parse(currentData);
|
|
42
|
-
}
|
|
43
|
-
return currentData;
|
|
44
|
-
}
|
|
45
|
-
function withLogCapture(fn) {
|
|
46
|
-
const logs = [];
|
|
47
|
-
const orig = { log: console.log, warn: console.warn, error: console.error };
|
|
48
|
-
const capture = (level, origFn) => (...args) => {
|
|
49
|
-
logs.push({ level, message: args.map(String).join(" "), timestamp: Date.now() });
|
|
50
|
-
origFn(...args);
|
|
51
|
-
};
|
|
52
|
-
console.log = capture("info", orig.log);
|
|
53
|
-
console.warn = capture("warn", orig.warn);
|
|
54
|
-
console.error = capture("error", orig.error);
|
|
55
|
-
return fn().then((result) => ({ result, logs })).finally(() => {
|
|
56
|
-
console.log = orig.log;
|
|
57
|
-
console.warn = orig.warn;
|
|
58
|
-
console.error = orig.error;
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
function startServer(org) {
|
|
62
|
-
const port = parseInt(process.env.PORT || "3000");
|
|
63
|
-
const workflows = new Map(
|
|
64
|
-
(org.workflows ?? []).map((w) => [w.config.resourceId, w])
|
|
65
|
-
);
|
|
66
|
-
const agents = new Map(
|
|
67
|
-
(org.agents ?? []).map((a) => [a.config.resourceId, a])
|
|
68
|
-
);
|
|
69
|
-
const controllers = /* @__PURE__ */ new Map();
|
|
70
|
-
const server = createServer(async (req, res) => {
|
|
71
|
-
try {
|
|
72
|
-
if (req.url === "/health" && req.method === "GET") {
|
|
73
|
-
res.writeHead(200).end("ok");
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
if (req.url === "/manifest" && req.method === "GET") {
|
|
77
|
-
json(res, 200, {
|
|
78
|
-
workflows: (org.workflows ?? []).map((w) => ({
|
|
79
|
-
resourceId: w.config.resourceId,
|
|
80
|
-
name: w.config.name,
|
|
81
|
-
type: w.config.type,
|
|
82
|
-
status: w.config.status,
|
|
83
|
-
description: w.config.description,
|
|
84
|
-
version: w.config.version
|
|
85
|
-
})),
|
|
86
|
-
agents: (org.agents ?? []).map((a) => ({
|
|
87
|
-
resourceId: a.config.resourceId,
|
|
88
|
-
name: a.config.name,
|
|
89
|
-
type: a.config.type,
|
|
90
|
-
status: a.config.status,
|
|
91
|
-
description: a.config.description,
|
|
92
|
-
version: a.config.version
|
|
93
|
-
}))
|
|
94
|
-
});
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
if (req.url === "/execute" && req.method === "POST") {
|
|
98
|
-
const body = JSON.parse(await readBody(req));
|
|
99
|
-
const { resourceId, executionId, input } = body;
|
|
100
|
-
const workflow = workflows.get(resourceId);
|
|
101
|
-
if (workflow) {
|
|
102
|
-
const controller = new AbortController();
|
|
103
|
-
controllers.set(executionId, controller);
|
|
104
|
-
const deadline = req.headers["x-elevasis-deadline"];
|
|
105
|
-
const timer = deadline ? setTimeout(() => controller.abort(), Number(deadline) - Date.now()) : void 0;
|
|
106
|
-
const context = {
|
|
107
|
-
executionId,
|
|
108
|
-
organizationId: "",
|
|
109
|
-
organizationName: "",
|
|
110
|
-
resourceId,
|
|
111
|
-
executionDepth: 0,
|
|
112
|
-
store: /* @__PURE__ */ new Map(),
|
|
113
|
-
signal: controller.signal,
|
|
114
|
-
logger: {
|
|
115
|
-
debug: (msg) => console.log(`[debug] ${msg}`),
|
|
116
|
-
info: (msg) => console.log(`[info] ${msg}`),
|
|
117
|
-
warn: (msg) => console.warn(`[warn] ${msg}`),
|
|
118
|
-
error: (msg) => console.error(`[error] ${msg}`)
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
try {
|
|
122
|
-
const { result: output, logs } = await withLogCapture(
|
|
123
|
-
() => executeWorkflow(workflow, input, context)
|
|
124
|
-
);
|
|
125
|
-
json(res, 200, { status: "completed", output, logs });
|
|
126
|
-
} catch (err) {
|
|
127
|
-
const { logs } = await withLogCapture(async () => {
|
|
128
|
-
});
|
|
129
|
-
json(res, 500, { status: "failed", error: String(err), logs });
|
|
130
|
-
} finally {
|
|
131
|
-
controllers.delete(executionId);
|
|
132
|
-
if (timer) clearTimeout(timer);
|
|
133
|
-
}
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
const agent = agents.get(resourceId);
|
|
137
|
-
if (agent) {
|
|
138
|
-
json(res, 501, {
|
|
139
|
-
status: "failed",
|
|
140
|
-
error: `Agent execution is not supported in SDK server v0.3.0. Resource '${resourceId}' is an agent.`,
|
|
141
|
-
logs: []
|
|
142
|
-
});
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
json(res, 404, { error: `Resource not found: ${resourceId}` });
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
if (req.url === "/cancel" && req.method === "POST") {
|
|
149
|
-
const body = JSON.parse(await readBody(req));
|
|
150
|
-
const { executionId } = body;
|
|
151
|
-
const controller = controllers.get(executionId);
|
|
152
|
-
if (controller) {
|
|
153
|
-
controller.abort();
|
|
154
|
-
controllers.delete(executionId);
|
|
155
|
-
json(res, 200, { cancelled: true });
|
|
156
|
-
} else {
|
|
157
|
-
json(res, 404, { error: `No running execution: ${executionId}` });
|
|
158
|
-
}
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
res.writeHead(404).end();
|
|
162
|
-
} catch (err) {
|
|
163
|
-
console.error("Unhandled server error:", err);
|
|
164
|
-
if (!res.headersSent) {
|
|
165
|
-
json(res, 500, { error: "Internal server error" });
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
server.listen(port, () => {
|
|
170
|
-
console.log(`Elevasis SDK server listening on port ${port}`);
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export { startServer };
|