skedyul 0.1.8 → 0.1.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/dist/cli/commands/diff.d.ts +1 -0
- package/dist/cli/commands/diff.js +295 -0
- package/dist/cli/commands/invoke.d.ts +1 -0
- package/dist/cli/commands/invoke.js +222 -0
- package/dist/cli/commands/serve.d.ts +1 -0
- package/dist/cli/commands/serve.js +123 -0
- package/dist/cli/commands/tools.d.ts +1 -0
- package/dist/cli/commands/tools.js +148 -0
- package/dist/cli/commands/validate.d.ts +1 -0
- package/dist/cli/commands/validate.js +269 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +94 -0
- package/dist/cli/utils.d.ts +25 -0
- package/dist/cli/utils.js +186 -0
- package/dist/config.d.ts +116 -0
- package/dist/config.js +233 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -1
- package/dist/server.js +21 -3
- package/package.json +4 -1
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseArgs = parseArgs;
|
|
37
|
+
exports.parseEnvFlags = parseEnvFlags;
|
|
38
|
+
exports.loadEnvFile = loadEnvFile;
|
|
39
|
+
exports.loadRegistry = loadRegistry;
|
|
40
|
+
exports.formatJson = formatJson;
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
/**
|
|
44
|
+
* Parse command line arguments into flags and positional args
|
|
45
|
+
*/
|
|
46
|
+
function parseArgs(args) {
|
|
47
|
+
const flags = {};
|
|
48
|
+
const positional = [];
|
|
49
|
+
let i = 0;
|
|
50
|
+
while (i < args.length) {
|
|
51
|
+
const arg = args[i];
|
|
52
|
+
if (arg.startsWith('--')) {
|
|
53
|
+
const key = arg.slice(2);
|
|
54
|
+
// Check if it's a key=value format
|
|
55
|
+
if (key.includes('=')) {
|
|
56
|
+
const [k, ...vParts] = key.split('=');
|
|
57
|
+
flags[k] = vParts.join('=');
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// Check if next arg is the value (not another flag)
|
|
61
|
+
const nextArg = args[i + 1];
|
|
62
|
+
if (nextArg && !nextArg.startsWith('-')) {
|
|
63
|
+
flags[key] = nextArg;
|
|
64
|
+
i++;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
flags[key] = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (arg.startsWith('-') && arg.length === 2) {
|
|
72
|
+
const key = arg.slice(1);
|
|
73
|
+
const nextArg = args[i + 1];
|
|
74
|
+
if (nextArg && !nextArg.startsWith('-')) {
|
|
75
|
+
flags[key] = nextArg;
|
|
76
|
+
i++;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
flags[key] = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
positional.push(arg);
|
|
84
|
+
}
|
|
85
|
+
i++;
|
|
86
|
+
}
|
|
87
|
+
return { flags, positional };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Parse multiple --env flags into a record
|
|
91
|
+
*/
|
|
92
|
+
function parseEnvFlags(args) {
|
|
93
|
+
const env = {};
|
|
94
|
+
for (let i = 0; i < args.length; i++) {
|
|
95
|
+
const arg = args[i];
|
|
96
|
+
if (arg === '--env' || arg === '-e') {
|
|
97
|
+
const nextArg = args[i + 1];
|
|
98
|
+
if (nextArg && nextArg.includes('=')) {
|
|
99
|
+
const [key, ...valueParts] = nextArg.split('=');
|
|
100
|
+
env[key] = valueParts.join('=');
|
|
101
|
+
i++;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else if (arg.startsWith('--env=')) {
|
|
105
|
+
const value = arg.slice(6);
|
|
106
|
+
if (value.includes('=')) {
|
|
107
|
+
const [key, ...valueParts] = value.split('=');
|
|
108
|
+
env[key] = valueParts.join('=');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return env;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Load environment variables from a .env file
|
|
116
|
+
*/
|
|
117
|
+
function loadEnvFile(filePath) {
|
|
118
|
+
const env = {};
|
|
119
|
+
const absolutePath = path.resolve(process.cwd(), filePath);
|
|
120
|
+
if (!fs.existsSync(absolutePath)) {
|
|
121
|
+
throw new Error(`Environment file not found: ${absolutePath}`);
|
|
122
|
+
}
|
|
123
|
+
const content = fs.readFileSync(absolutePath, 'utf-8');
|
|
124
|
+
const lines = content.split('\n');
|
|
125
|
+
for (const line of lines) {
|
|
126
|
+
const trimmed = line.trim();
|
|
127
|
+
// Skip empty lines and comments
|
|
128
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const equalIndex = trimmed.indexOf('=');
|
|
132
|
+
if (equalIndex === -1) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const key = trimmed.slice(0, equalIndex).trim();
|
|
136
|
+
let value = trimmed.slice(equalIndex + 1).trim();
|
|
137
|
+
// Remove surrounding quotes
|
|
138
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
139
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
140
|
+
value = value.slice(1, -1);
|
|
141
|
+
}
|
|
142
|
+
env[key] = value;
|
|
143
|
+
}
|
|
144
|
+
return env;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Load a registry from a JS/TS file
|
|
148
|
+
*/
|
|
149
|
+
async function loadRegistry(registryPath) {
|
|
150
|
+
const absolutePath = path.resolve(process.cwd(), registryPath);
|
|
151
|
+
if (!fs.existsSync(absolutePath)) {
|
|
152
|
+
throw new Error(`Registry file not found: ${absolutePath}`);
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
// Use dynamic import for ES modules compatibility
|
|
156
|
+
const module = await Promise.resolve(`${absolutePath}`).then(s => __importStar(require(s)));
|
|
157
|
+
// Check for registry export (default or named)
|
|
158
|
+
const registry = module.registry || module.default?.registry || module.default;
|
|
159
|
+
if (!registry || typeof registry !== 'object') {
|
|
160
|
+
throw new Error(`Registry file must export a 'registry' object. Got: ${typeof registry}`);
|
|
161
|
+
}
|
|
162
|
+
// Validate it looks like a tool registry
|
|
163
|
+
const keys = Object.keys(registry);
|
|
164
|
+
if (keys.length === 0) {
|
|
165
|
+
throw new Error('Registry is empty');
|
|
166
|
+
}
|
|
167
|
+
// Check that at least one entry has expected tool shape
|
|
168
|
+
const firstTool = registry[keys[0]];
|
|
169
|
+
if (!firstTool || typeof firstTool.name !== 'string') {
|
|
170
|
+
throw new Error('Registry entries must have a "name" property. Is this a valid tool registry?');
|
|
171
|
+
}
|
|
172
|
+
return registry;
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
if (error instanceof Error && error.message.includes('Registry')) {
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
throw new Error(`Failed to load registry from ${absolutePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Format JSON for console output with optional color
|
|
183
|
+
*/
|
|
184
|
+
function formatJson(data, pretty = true) {
|
|
185
|
+
return pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
186
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export type EnvVisibility = 'visible' | 'encrypted';
|
|
2
|
+
export interface EnvVariableDefinition {
|
|
3
|
+
/** Human-readable label for the variable */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Whether this variable is required */
|
|
6
|
+
required?: boolean;
|
|
7
|
+
/** Visibility setting (encrypted values are hidden in UI) */
|
|
8
|
+
visibility?: EnvVisibility;
|
|
9
|
+
/** Default value if not provided */
|
|
10
|
+
default?: string;
|
|
11
|
+
/** Description/help text */
|
|
12
|
+
description?: string;
|
|
13
|
+
/** Placeholder text for input fields */
|
|
14
|
+
placeholder?: string;
|
|
15
|
+
}
|
|
16
|
+
export type EnvSchema = Record<string, EnvVariableDefinition>;
|
|
17
|
+
export interface AppModelDefinition {
|
|
18
|
+
/** Unique handle for the entity (e.g., 'client', 'patient') */
|
|
19
|
+
entityHandle: string;
|
|
20
|
+
/** Human-readable label */
|
|
21
|
+
label: string;
|
|
22
|
+
/** Description of what this model represents */
|
|
23
|
+
description?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface InstallConfig {
|
|
26
|
+
/**
|
|
27
|
+
* Per-install environment variables.
|
|
28
|
+
* These are configured by the user when installing the app.
|
|
29
|
+
* Values are stored per-installation and can differ between installs.
|
|
30
|
+
*/
|
|
31
|
+
env?: EnvSchema;
|
|
32
|
+
/**
|
|
33
|
+
* Model mappings required for this app.
|
|
34
|
+
* Users will map these to their CRM models during installation.
|
|
35
|
+
*/
|
|
36
|
+
appModels?: AppModelDefinition[];
|
|
37
|
+
}
|
|
38
|
+
export type ComputeLayerType = 'serverless' | 'dedicated';
|
|
39
|
+
export type RuntimeType = 'node-22' | 'node-20' | 'node-18';
|
|
40
|
+
export interface SkedyulConfig {
|
|
41
|
+
/** App name */
|
|
42
|
+
name: string;
|
|
43
|
+
/** App version (semver) */
|
|
44
|
+
version?: string;
|
|
45
|
+
/** App description */
|
|
46
|
+
description?: string;
|
|
47
|
+
/** Compute layer: 'serverless' (Lambda) or 'dedicated' (ECS/Docker) */
|
|
48
|
+
computeLayer?: ComputeLayerType;
|
|
49
|
+
/** Runtime environment */
|
|
50
|
+
runtime?: RuntimeType;
|
|
51
|
+
/** Path to the tool registry file (default: './src/registry.ts') */
|
|
52
|
+
tools?: string;
|
|
53
|
+
/** Path to the workflows directory (default: './workflows') */
|
|
54
|
+
workflows?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Global/version-level environment variables.
|
|
57
|
+
* These are baked into the container and are the same for all installations.
|
|
58
|
+
* Use for configuration that doesn't change per-install.
|
|
59
|
+
*/
|
|
60
|
+
env?: EnvSchema;
|
|
61
|
+
/**
|
|
62
|
+
* Install-time configuration.
|
|
63
|
+
* Defines what users need to configure when installing the app.
|
|
64
|
+
*/
|
|
65
|
+
install?: InstallConfig;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Define a Skedyul app configuration with full type safety.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* // skedyul.config.ts
|
|
73
|
+
* import { defineConfig } from 'skedyul'
|
|
74
|
+
*
|
|
75
|
+
* export default defineConfig({
|
|
76
|
+
* name: 'My App',
|
|
77
|
+
* computeLayer: 'dedicated',
|
|
78
|
+
* tools: './src/registry.ts',
|
|
79
|
+
* env: {
|
|
80
|
+
* LOG_LEVEL: { label: 'Log Level', default: 'info' },
|
|
81
|
+
* },
|
|
82
|
+
* install: {
|
|
83
|
+
* env: {
|
|
84
|
+
* API_KEY: { label: 'API Key', required: true, visibility: 'encrypted' },
|
|
85
|
+
* },
|
|
86
|
+
* },
|
|
87
|
+
* })
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare function defineConfig(config: SkedyulConfig): SkedyulConfig;
|
|
91
|
+
/**
|
|
92
|
+
* Default config file names to search for
|
|
93
|
+
*/
|
|
94
|
+
export declare const CONFIG_FILE_NAMES: string[];
|
|
95
|
+
/**
|
|
96
|
+
* Load a Skedyul config from a file path
|
|
97
|
+
*/
|
|
98
|
+
export declare function loadConfig(configPath: string): Promise<SkedyulConfig>;
|
|
99
|
+
/**
|
|
100
|
+
* Validate a config object
|
|
101
|
+
*/
|
|
102
|
+
export declare function validateConfig(config: SkedyulConfig): {
|
|
103
|
+
valid: boolean;
|
|
104
|
+
errors: string[];
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Get all required install env keys from a config
|
|
108
|
+
*/
|
|
109
|
+
export declare function getRequiredInstallEnvKeys(config: SkedyulConfig): string[];
|
|
110
|
+
/**
|
|
111
|
+
* Get all env keys (both global and install) from a config
|
|
112
|
+
*/
|
|
113
|
+
export declare function getAllEnvKeys(config: SkedyulConfig): {
|
|
114
|
+
global: string[];
|
|
115
|
+
install: string[];
|
|
116
|
+
};
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.CONFIG_FILE_NAMES = void 0;
|
|
37
|
+
exports.defineConfig = defineConfig;
|
|
38
|
+
exports.loadConfig = loadConfig;
|
|
39
|
+
exports.validateConfig = validateConfig;
|
|
40
|
+
exports.getRequiredInstallEnvKeys = getRequiredInstallEnvKeys;
|
|
41
|
+
exports.getAllEnvKeys = getAllEnvKeys;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const os = __importStar(require("os"));
|
|
45
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
46
|
+
// Helper Function
|
|
47
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
48
|
+
/**
|
|
49
|
+
* Define a Skedyul app configuration with full type safety.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* // skedyul.config.ts
|
|
54
|
+
* import { defineConfig } from 'skedyul'
|
|
55
|
+
*
|
|
56
|
+
* export default defineConfig({
|
|
57
|
+
* name: 'My App',
|
|
58
|
+
* computeLayer: 'dedicated',
|
|
59
|
+
* tools: './src/registry.ts',
|
|
60
|
+
* env: {
|
|
61
|
+
* LOG_LEVEL: { label: 'Log Level', default: 'info' },
|
|
62
|
+
* },
|
|
63
|
+
* install: {
|
|
64
|
+
* env: {
|
|
65
|
+
* API_KEY: { label: 'API Key', required: true, visibility: 'encrypted' },
|
|
66
|
+
* },
|
|
67
|
+
* },
|
|
68
|
+
* })
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
function defineConfig(config) {
|
|
72
|
+
return config;
|
|
73
|
+
}
|
|
74
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
75
|
+
// Config Loading Utilities
|
|
76
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
77
|
+
/**
|
|
78
|
+
* Default config file names to search for
|
|
79
|
+
*/
|
|
80
|
+
exports.CONFIG_FILE_NAMES = [
|
|
81
|
+
'skedyul.config.ts',
|
|
82
|
+
'skedyul.config.js',
|
|
83
|
+
'skedyul.config.mjs',
|
|
84
|
+
'skedyul.config.cjs',
|
|
85
|
+
];
|
|
86
|
+
/**
|
|
87
|
+
* Transpile a TypeScript config file to JavaScript
|
|
88
|
+
*/
|
|
89
|
+
async function transpileTypeScript(filePath) {
|
|
90
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
91
|
+
// Simple transpilation: remove type annotations and convert to CommonJS
|
|
92
|
+
// For more complex configs, users should pre-compile or use a JS config
|
|
93
|
+
let transpiled = content
|
|
94
|
+
// Remove import type statements
|
|
95
|
+
.replace(/import\s+type\s+\{[^}]+\}\s+from\s+['"][^'"]+['"]\s*;?\n?/g, '')
|
|
96
|
+
// Convert import { defineConfig } from 'skedyul' to require
|
|
97
|
+
.replace(/import\s+\{\s*defineConfig\s*\}\s+from\s+['"]skedyul['"]\s*;?\n?/g, '')
|
|
98
|
+
// Remove type annotations like : SkedyulConfig
|
|
99
|
+
.replace(/:\s*SkedyulConfig/g, '')
|
|
100
|
+
// Convert export default to module.exports
|
|
101
|
+
.replace(/export\s+default\s+/, 'module.exports = ')
|
|
102
|
+
// Replace defineConfig() wrapper with just the object
|
|
103
|
+
.replace(/defineConfig\s*\(\s*\{/, '{')
|
|
104
|
+
// Remove the closing paren from defineConfig
|
|
105
|
+
.replace(/\}\s*\)\s*;?\s*$/, '}');
|
|
106
|
+
return transpiled;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Load a Skedyul config from a file path
|
|
110
|
+
*/
|
|
111
|
+
async function loadConfig(configPath) {
|
|
112
|
+
const absolutePath = path.resolve(configPath);
|
|
113
|
+
if (!fs.existsSync(absolutePath)) {
|
|
114
|
+
throw new Error(`Config file not found: ${absolutePath}`);
|
|
115
|
+
}
|
|
116
|
+
const isTypeScript = absolutePath.endsWith('.ts');
|
|
117
|
+
try {
|
|
118
|
+
let moduleToLoad = absolutePath;
|
|
119
|
+
if (isTypeScript) {
|
|
120
|
+
// Transpile TypeScript to a temp JS file
|
|
121
|
+
const transpiled = await transpileTypeScript(absolutePath);
|
|
122
|
+
const tempDir = os.tmpdir();
|
|
123
|
+
const tempFile = path.join(tempDir, `skedyul-config-${Date.now()}.js`);
|
|
124
|
+
fs.writeFileSync(tempFile, transpiled);
|
|
125
|
+
moduleToLoad = tempFile;
|
|
126
|
+
try {
|
|
127
|
+
const module = require(moduleToLoad);
|
|
128
|
+
const config = module.default || module;
|
|
129
|
+
if (!config || typeof config !== 'object') {
|
|
130
|
+
throw new Error('Config file must export a configuration object');
|
|
131
|
+
}
|
|
132
|
+
if (!config.name || typeof config.name !== 'string') {
|
|
133
|
+
throw new Error('Config must have a "name" property');
|
|
134
|
+
}
|
|
135
|
+
return config;
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
// Clean up temp file
|
|
139
|
+
try {
|
|
140
|
+
fs.unlinkSync(tempFile);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Ignore cleanup errors
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// For JS files, use dynamic import
|
|
148
|
+
const module = await Promise.resolve(`${moduleToLoad}`).then(s => __importStar(require(s)));
|
|
149
|
+
const config = module.default || module;
|
|
150
|
+
if (!config || typeof config !== 'object') {
|
|
151
|
+
throw new Error('Config file must export a configuration object');
|
|
152
|
+
}
|
|
153
|
+
if (!config.name || typeof config.name !== 'string') {
|
|
154
|
+
throw new Error('Config must have a "name" property');
|
|
155
|
+
}
|
|
156
|
+
return config;
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
throw new Error(`Failed to load config from ${configPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Validate a config object
|
|
164
|
+
*/
|
|
165
|
+
function validateConfig(config) {
|
|
166
|
+
const errors = [];
|
|
167
|
+
// Required fields
|
|
168
|
+
if (!config.name) {
|
|
169
|
+
errors.push('Missing required field: name');
|
|
170
|
+
}
|
|
171
|
+
// Validate computeLayer
|
|
172
|
+
if (config.computeLayer && !['serverless', 'dedicated'].includes(config.computeLayer)) {
|
|
173
|
+
errors.push(`Invalid computeLayer: ${config.computeLayer}. Must be 'serverless' or 'dedicated'`);
|
|
174
|
+
}
|
|
175
|
+
// Validate runtime
|
|
176
|
+
if (config.runtime && !['node-22', 'node-20', 'node-18'].includes(config.runtime)) {
|
|
177
|
+
errors.push(`Invalid runtime: ${config.runtime}. Must be 'node-22', 'node-20', or 'node-18'`);
|
|
178
|
+
}
|
|
179
|
+
// Validate env schema
|
|
180
|
+
if (config.env) {
|
|
181
|
+
for (const [key, def] of Object.entries(config.env)) {
|
|
182
|
+
if (!def.label) {
|
|
183
|
+
errors.push(`env.${key}: Missing required field 'label'`);
|
|
184
|
+
}
|
|
185
|
+
if (def.visibility && !['visible', 'encrypted'].includes(def.visibility)) {
|
|
186
|
+
errors.push(`env.${key}: Invalid visibility '${def.visibility}'`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Validate install.env schema
|
|
191
|
+
if (config.install?.env) {
|
|
192
|
+
for (const [key, def] of Object.entries(config.install.env)) {
|
|
193
|
+
if (!def.label) {
|
|
194
|
+
errors.push(`install.env.${key}: Missing required field 'label'`);
|
|
195
|
+
}
|
|
196
|
+
if (def.visibility && !['visible', 'encrypted'].includes(def.visibility)) {
|
|
197
|
+
errors.push(`install.env.${key}: Invalid visibility '${def.visibility}'`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Validate appModels
|
|
202
|
+
if (config.install?.appModels) {
|
|
203
|
+
for (let i = 0; i < config.install.appModels.length; i++) {
|
|
204
|
+
const model = config.install.appModels[i];
|
|
205
|
+
if (!model.entityHandle) {
|
|
206
|
+
errors.push(`install.appModels[${i}]: Missing required field 'entityHandle'`);
|
|
207
|
+
}
|
|
208
|
+
if (!model.label) {
|
|
209
|
+
errors.push(`install.appModels[${i}]: Missing required field 'label'`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return { valid: errors.length === 0, errors };
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Get all required install env keys from a config
|
|
217
|
+
*/
|
|
218
|
+
function getRequiredInstallEnvKeys(config) {
|
|
219
|
+
if (!config.install?.env)
|
|
220
|
+
return [];
|
|
221
|
+
return Object.entries(config.install.env)
|
|
222
|
+
.filter(([, def]) => def.required)
|
|
223
|
+
.map(([key]) => key);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Get all env keys (both global and install) from a config
|
|
227
|
+
*/
|
|
228
|
+
function getAllEnvKeys(config) {
|
|
229
|
+
return {
|
|
230
|
+
global: config.env ? Object.keys(config.env) : [],
|
|
231
|
+
install: config.install?.env ? Object.keys(config.install.env) : [],
|
|
232
|
+
};
|
|
233
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export * from './types';
|
|
2
2
|
export { server } from './server';
|
|
3
3
|
export { workplace, communicationChannel } from './core/client';
|
|
4
|
+
export { defineConfig, loadConfig, validateConfig, getRequiredInstallEnvKeys, getAllEnvKeys, CONFIG_FILE_NAMES, } from './config';
|
|
5
|
+
export type { SkedyulConfig, EnvVariableDefinition, EnvSchema, EnvVisibility, InstallConfig, AppModelDefinition, ComputeLayerType, RuntimeType, } from './config';
|
package/dist/index.js
CHANGED
|
@@ -14,10 +14,17 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.communicationChannel = exports.workplace = exports.server = void 0;
|
|
17
|
+
exports.CONFIG_FILE_NAMES = exports.getAllEnvKeys = exports.getRequiredInstallEnvKeys = exports.validateConfig = exports.loadConfig = exports.defineConfig = exports.communicationChannel = exports.workplace = exports.server = void 0;
|
|
18
18
|
__exportStar(require("./types"), exports);
|
|
19
19
|
var server_1 = require("./server");
|
|
20
20
|
Object.defineProperty(exports, "server", { enumerable: true, get: function () { return server_1.server; } });
|
|
21
21
|
var client_1 = require("./core/client");
|
|
22
22
|
Object.defineProperty(exports, "workplace", { enumerable: true, get: function () { return client_1.workplace; } });
|
|
23
23
|
Object.defineProperty(exports, "communicationChannel", { enumerable: true, get: function () { return client_1.communicationChannel; } });
|
|
24
|
+
var config_1 = require("./config");
|
|
25
|
+
Object.defineProperty(exports, "defineConfig", { enumerable: true, get: function () { return config_1.defineConfig; } });
|
|
26
|
+
Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
|
|
27
|
+
Object.defineProperty(exports, "validateConfig", { enumerable: true, get: function () { return config_1.validateConfig; } });
|
|
28
|
+
Object.defineProperty(exports, "getRequiredInstallEnvKeys", { enumerable: true, get: function () { return config_1.getRequiredInstallEnvKeys; } });
|
|
29
|
+
Object.defineProperty(exports, "getAllEnvKeys", { enumerable: true, get: function () { return config_1.getAllEnvKeys; } });
|
|
30
|
+
Object.defineProperty(exports, "CONFIG_FILE_NAMES", { enumerable: true, get: function () { return config_1.CONFIG_FILE_NAMES; } });
|
package/dist/server.js
CHANGED
|
@@ -42,8 +42,20 @@ const http_1 = __importDefault(require("http"));
|
|
|
42
42
|
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
43
43
|
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
44
44
|
const z = __importStar(require("zod"));
|
|
45
|
-
const
|
|
45
|
+
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
46
46
|
const service_1 = require("./core/service");
|
|
47
|
+
const zodToJsonSchemaLoose = zod_to_json_schema_1.zodToJsonSchema;
|
|
48
|
+
let toJsonSchemaCompatFn = null;
|
|
49
|
+
try {
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
|
|
51
|
+
const compat = require('@modelcontextprotocol/sdk/server/zod-json-schema-compat.js');
|
|
52
|
+
if (compat?.toJsonSchemaCompat) {
|
|
53
|
+
toJsonSchemaCompatFn = compat.toJsonSchemaCompat;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
toJsonSchemaCompatFn = null;
|
|
58
|
+
}
|
|
47
59
|
function normalizeBilling(billing) {
|
|
48
60
|
if (!billing || typeof billing.credits !== 'number') {
|
|
49
61
|
return { credits: 0 };
|
|
@@ -54,9 +66,15 @@ function toJsonSchema(schema) {
|
|
|
54
66
|
if (!schema)
|
|
55
67
|
return undefined;
|
|
56
68
|
try {
|
|
57
|
-
|
|
69
|
+
if (toJsonSchemaCompatFn) {
|
|
70
|
+
return toJsonSchemaCompatFn(schema, {
|
|
71
|
+
target: 'jsonSchema7',
|
|
72
|
+
pipeStrategy: 'input',
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return zodToJsonSchemaLoose(schema, {
|
|
58
76
|
target: 'jsonSchema7',
|
|
59
|
-
|
|
77
|
+
$refStrategy: 'none',
|
|
60
78
|
});
|
|
61
79
|
}
|
|
62
80
|
catch {
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skedyul",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "The Skedyul SDK for Node.js",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"skedyul": "./dist/cli/index.js"
|
|
9
|
+
},
|
|
7
10
|
"exports": {
|
|
8
11
|
".": {
|
|
9
12
|
"types": "./dist/index.d.ts",
|