@runium/core 0.0.7 → 0.0.9

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.
@@ -0,0 +1,510 @@
1
+ declare module '@runium/core' {
2
+ import { ChildProcessWithoutNullStreams } from 'node:child_process';
3
+ import { EventEmitter } from 'node:events';
4
+ import { WriteStream } from 'node:fs';
5
+
6
+ export function applyMacros(text: string, macros: MacrosCollection): string;
7
+
8
+ export class EventTrigger extends RuniumTrigger<EventTriggerOptions> {
9
+ constructor(
10
+ options: EventTriggerOptions,
11
+ project: RuniumTriggerProjectAccessible
12
+ );
13
+ enable(): void;
14
+ disable(): void;
15
+ }
16
+
17
+ export interface EventTriggerOptions extends RuniumTriggerOptions {
18
+ event: string;
19
+ }
20
+
21
+ export function extendProjectSchema(
22
+ schema: object,
23
+ extensions: ProjectSchemaExtension
24
+ ): object;
25
+
26
+ export enum FileErrorCode {
27
+ READ_JSON = 'file-read-json',
28
+ WRITE_JSON = 'file-write-json',
29
+ }
30
+
31
+ export function getProjectSchema(): object;
32
+
33
+ export const ID_REGEX: RegExp;
34
+
35
+ export class IntervalTrigger extends RuniumTrigger<IntervalTriggerOptions> {
36
+ constructor(
37
+ options: IntervalTriggerOptions,
38
+ project: RuniumTriggerProjectAccessible
39
+ );
40
+ enable(): void;
41
+ disable(): void;
42
+ }
43
+
44
+ export interface IntervalTriggerOptions extends RuniumTriggerOptions {
45
+ interval: number;
46
+ }
47
+
48
+ export function isCustomAction(
49
+ action: ProjectAction
50
+ ): action is ProjectCustomAction;
51
+
52
+ export function isCustomTrigger(
53
+ trigger: ProjectTrigger
54
+ ): trigger is ProjectCustomTrigger;
55
+
56
+ export function isProcessTaskAction(
57
+ action: ProjectAction
58
+ ): action is ProjectActionProcessTask;
59
+
60
+ export function isRuniumError(error: unknown): boolean;
61
+
62
+ export function isToggleTriggerAction(
63
+ action: ProjectAction
64
+ ): action is ProjectActionToggleTrigger;
65
+
66
+ export interface JSONObject {
67
+ [x: string]: JSONValue;
68
+ }
69
+
70
+ export type JSONValue = string | number | boolean | JSONObject | JSONValue[];
71
+
72
+ export type Macro = (...params: string[]) => string;
73
+
74
+ export type MacrosCollection = Record<string, Macro>;
75
+
76
+ export enum MacrosErrorCode {
77
+ MACRO_APPLY_ERROR = 'macro-apply-error',
78
+ }
79
+
80
+ export class Project extends EventEmitter {
81
+ constructor(config: ProjectConfig);
82
+ validate(): void;
83
+ getConfig(): ProjectConfig;
84
+ setConfig(config: ProjectConfig): void;
85
+ getState(): ProjectState;
86
+ start(): Promise<void>;
87
+ stop(reason?: string): Promise<void>;
88
+ extendValidationSchema(extensions: ProjectSchemaExtension): void;
89
+ registerAction(type: string, processor: RuniumActionProcessor): void;
90
+ registerTask(
91
+ type: string,
92
+ processor: RuniumTaskConstructor<unknown, any>
93
+ ): void;
94
+ registerTrigger(
95
+ type: string,
96
+ processor: RuniumTriggerConstructor<any>
97
+ ): void;
98
+ startTask(taskId: string): Promise<void>;
99
+ stopTask(taskId: string): Promise<void>;
100
+ restartTask(taskId: string): Promise<void>;
101
+ getTaskState<T extends RuniumTaskState = RuniumTaskState>(
102
+ taskId: string
103
+ ): T | null;
104
+ processAction(action: ProjectAction): void;
105
+ enableTrigger(triggerId: string): void;
106
+ disableTrigger(triggerId: string): void;
107
+ }
108
+
109
+ export type ProjectAction =
110
+ | ProjectCustomAction
111
+ | ProjectActionEmitEvent
112
+ | ProjectActionProcessTask
113
+ | ProjectActionStopProject
114
+ | ProjectActionToggleTrigger;
115
+
116
+ export interface ProjectActionEmitEvent {
117
+ type: ProjectActionType.EMIT_EVENT;
118
+ event: string;
119
+ }
120
+
121
+ export interface ProjectActionProcessTask {
122
+ type:
123
+ | ProjectActionType.START_TASK
124
+ | ProjectActionType.RESTART_TASK
125
+ | ProjectActionType.STOP_TASK;
126
+ taskId: string;
127
+ }
128
+
129
+ export interface ProjectActionStopProject {
130
+ type: ProjectActionType.STOP_PROJECT;
131
+ }
132
+
133
+ export interface ProjectActionToggleTrigger {
134
+ type: ProjectActionType.ENABLE_TRIGGER | ProjectActionType.DISABLE_TRIGGER;
135
+ triggerId: string;
136
+ }
137
+
138
+ export enum ProjectActionType {
139
+ EMIT_EVENT = 'emit-event',
140
+ START_TASK = 'start-task',
141
+ RESTART_TASK = 'restart-task',
142
+ STOP_TASK = 'stop-task',
143
+ STOP_PROJECT = 'stop-project',
144
+ ENABLE_TRIGGER = 'enable-trigger',
145
+ DISABLE_TRIGGER = 'disable-trigger',
146
+ }
147
+
148
+ export interface ProjectConfig {
149
+ id: string;
150
+ name?: string;
151
+ tasks: ProjectTaskConfig[];
152
+ triggers?: ProjectTrigger[];
153
+ }
154
+
155
+ export enum ProjectConfigErrorCode {
156
+ INCORRECT_DATA = 'project-config-incorrect-data',
157
+ TASKS_CIRCULAR_DEPENDENCY = 'project-config-tasks-circular-dependency',
158
+ TASK_NOT_EXISTS = 'project-config-task-not-exists',
159
+ TRIGGER_NOT_EXISTS = 'project-config-trigger-not-exists',
160
+ }
161
+
162
+ export interface ProjectCustomAction {
163
+ type: string;
164
+ payload?: unknown;
165
+ }
166
+
167
+ export interface ProjectCustomTrigger extends ProjectTriggerBase {
168
+ type: string;
169
+ payload?: unknown;
170
+ }
171
+
172
+ export interface ProjectDefaultTaskConfig
173
+ extends ProjectTaskConfig<TaskOptions> {
174
+ type?: ProjectTaskType.DEFAULT;
175
+ }
176
+
177
+ export enum ProjectErrorCode {
178
+ ACTION_PROCESSOR_ALREADY_REGISTERED = 'project-action-processor-already-registered',
179
+ ACTION_PROCESSOR_INCORRECT = 'project-action-processor-incorrect',
180
+ TASK_PROCESSOR_NOT_FOUND = 'project-task-processor-not-found',
181
+ TASK_PROCESSOR_ALREADY_REGISTERED = 'project-task-processor-already-registered',
182
+ TASK_PROCESSOR_INCORRECT = 'project-task-processor-incorrect',
183
+ TRIGGER_PROCESSOR_ALREADY_REGISTERED = 'project-trigger-processor-already-registered',
184
+ TRIGGER_PROCESSOR_INCORRECT = 'project-trigger-processor-incorrect',
185
+ }
186
+
187
+ export enum ProjectEvent {
188
+ STATE_CHANGE = 'state-change',
189
+ START_TASK = 'start-task',
190
+ RESTART_TASK = 'restart-task',
191
+ STOP_TASK = 'stop-task',
192
+ PROCESS_ACTION = 'process-action',
193
+ ENABLE_TRIGGER = 'enable-trigger',
194
+ DISABLE_TRIGGER = 'disable-trigger',
195
+ TASK_STATE_CHANGE = 'task-state-change',
196
+ TASK_STDOUT = 'task-stdout',
197
+ TASK_STDERR = 'task-stderr',
198
+ }
199
+
200
+ export enum ProjectSchemaErrorCode {
201
+ ACTION_TYPE_ALREADY_USED = 'project-schema-action-type-already-used',
202
+ TASK_TYPE_ALREADY_USED = 'project-schema-task-type-already-used',
203
+ TRIGGER_TYPE_ALREADY_USED = 'project-schema-trigger-type-already-used',
204
+ }
205
+
206
+ export interface ProjectSchemaExtensionProject {
207
+ properties: unknown;
208
+ required?: string[];
209
+ }
210
+
211
+ export interface ProjectSchemaExtensionTask {
212
+ type: string;
213
+ options: unknown;
214
+ }
215
+
216
+ export interface ProjectSchemaExtensionAction {
217
+ type: string;
218
+ payload?: unknown;
219
+ }
220
+
221
+ export interface ProjectSchemaExtensionTrigger {
222
+ type: string;
223
+ payload?: unknown;
224
+ }
225
+
226
+ export interface ProjectSchemaExtension {
227
+ project?: {
228
+ properties: unknown;
229
+ required?: string[];
230
+ };
231
+ tasks?: Record<
232
+ string,
233
+ {
234
+ type: string;
235
+ options: unknown;
236
+ }
237
+ >;
238
+ definitions?: Record<string, unknown>;
239
+ actions?: Record<
240
+ string,
241
+ {
242
+ type: string;
243
+ payload?: unknown;
244
+ }
245
+ >;
246
+ triggers?: Record<
247
+ string,
248
+ {
249
+ type: string;
250
+ payload?: unknown;
251
+ }
252
+ >;
253
+ }
254
+
255
+ export interface ProjectState {
256
+ status: ProjectStatus;
257
+ timestamp: number;
258
+ reason?: string;
259
+ }
260
+
261
+ export enum ProjectStatus {
262
+ IDLE = 'idle',
263
+ STARTING = 'starting',
264
+ STARTED = 'started',
265
+ STOPPING = 'stopping',
266
+ STOPPED = 'stopped',
267
+ }
268
+
269
+ export interface ProjectTaskConfig<Options = unknown> {
270
+ id: string;
271
+ options: Options;
272
+ type?: ProjectTaskType | string;
273
+ name?: string;
274
+ mode?: ProjectTaskStartMode;
275
+ dependencies?: ProjectTaskDependency[];
276
+ handlers?: ProjectTaskHandler[];
277
+ restart?: ProjectTaskRestartPolicy;
278
+ }
279
+
280
+ export interface ProjectTaskDependency {
281
+ taskId: string;
282
+ condition: ProjectTaskStateCondition;
283
+ }
284
+
285
+ export interface ProjectTaskHandler {
286
+ condition: ProjectTaskStateCondition;
287
+ action: ProjectAction;
288
+ }
289
+
290
+ export type ProjectTaskRestartPolicy =
291
+ | ProjectTaskRestartPolicyAlways
292
+ | ProjectTaskRestartPolicyOnFailure;
293
+
294
+ export interface ProjectTaskRestartPolicyAlways {
295
+ policy: ProjectTaskRestartPolicyType.ALWAYS;
296
+ delay?: number;
297
+ }
298
+
299
+ export interface ProjectTaskRestartPolicyOnFailure {
300
+ policy: ProjectTaskRestartPolicyType.ON_FAILURE;
301
+ delay?: number;
302
+ maxRetries?: number;
303
+ }
304
+
305
+ export enum ProjectTaskRestartPolicyType {
306
+ ALWAYS = 'always',
307
+ ON_FAILURE = 'on-failure',
308
+ }
309
+
310
+ export enum ProjectTaskStartMode {
311
+ IMMEDIATE = 'immediate',
312
+ DEFERRED = 'deferred',
313
+ IGNORE = 'ignore',
314
+ }
315
+
316
+ export type ProjectTaskStateCondition =
317
+ | string
318
+ | boolean
319
+ | Partial<RuniumTaskState>
320
+ | ((state: RuniumTaskState) => boolean);
321
+
322
+ export enum ProjectTaskType {
323
+ DEFAULT = 'default',
324
+ }
325
+
326
+ export type ProjectTrigger =
327
+ | ProjectTriggerEvent
328
+ | ProjectTriggerInterval
329
+ | ProjectTriggerTimeout
330
+ | ProjectCustomTrigger;
331
+
332
+ interface ProjectTriggerBase {
333
+ id: string;
334
+ type: ProjectTriggerType | string;
335
+ action: ProjectAction;
336
+ disabled?: boolean;
337
+ }
338
+
339
+ export interface ProjectTriggerEvent extends ProjectTriggerBase {
340
+ type: ProjectTriggerType.EVENT;
341
+ event: string;
342
+ }
343
+
344
+ export interface ProjectTriggerInterval extends ProjectTriggerBase {
345
+ type: ProjectTriggerType.INTERVAL;
346
+ interval: number;
347
+ }
348
+
349
+ export interface ProjectTriggerTimeout extends ProjectTriggerBase {
350
+ type: ProjectTriggerType.TIMEOUT;
351
+ timeout: number;
352
+ }
353
+
354
+ export enum ProjectTriggerType {
355
+ EVENT = 'event',
356
+ TIMEOUT = 'timeout',
357
+ INTERVAL = 'interval',
358
+ }
359
+
360
+ export function readJsonFile<T = JSONValue>(path: string): Promise<T>;
361
+
362
+ type RuniumActionProcessor = (payload: unknown) => void;
363
+
364
+ export class RuniumError extends Error {
365
+ code: string;
366
+ payload: unknown;
367
+ constructor(message: string, code: string, payload?: unknown);
368
+ }
369
+
370
+ export abstract class RuniumTask<
371
+ Options = unknown,
372
+ State = RuniumTaskState,
373
+ > extends EventEmitter {
374
+ protected options: Options;
375
+ protected constructor(options: Options);
376
+ abstract getOptions(): Options;
377
+ abstract getState(): State;
378
+ abstract start(): Promise<void>;
379
+ abstract stop(reason?: string): Promise<void>;
380
+ abstract restart(): Promise<void>;
381
+ }
382
+
383
+ export type RuniumTaskConstructor<
384
+ Options = unknown,
385
+ State extends RuniumTaskState = RuniumTaskState,
386
+ > = new (options: any) => RuniumTask<Options, State>;
387
+
388
+ export interface RuniumTaskState {
389
+ status: TaskStatus;
390
+ timestamp: number;
391
+ iteration: number;
392
+ exitCode?: number;
393
+ error?: Error;
394
+ reason?: string;
395
+ }
396
+
397
+ export abstract class RuniumTrigger<Options extends RuniumTriggerOptions> {
398
+ protected project: RuniumTriggerProjectAccessible;
399
+ protected id: string;
400
+ protected action: ProjectAction;
401
+ protected disabled: boolean;
402
+ constructor(options: Options, project: RuniumTriggerProjectAccessible);
403
+ abstract enable(): void;
404
+ abstract disable(): void;
405
+ getId(): string;
406
+ isDisabled(): boolean;
407
+ }
408
+
409
+ export type RuniumTriggerConstructor<Options extends RuniumTriggerOptions> =
410
+ new (
411
+ options: Options,
412
+ project: RuniumTriggerProjectAccessible
413
+ ) => RuniumTrigger<Options>;
414
+
415
+ export interface RuniumTriggerOptions {
416
+ id: string;
417
+ action: ProjectAction;
418
+ disabled?: boolean;
419
+ }
420
+
421
+ export interface RuniumTriggerProjectAccessible {
422
+ processAction(action: ProjectAction): void;
423
+ on: NodeJS.EventEmitter['on'];
424
+ off: NodeJS.EventEmitter['off'];
425
+ }
426
+
427
+ export const SILENT_EXIT_CODE = -1;
428
+
429
+ export class Task extends RuniumTask<TaskOptions, TaskState> {
430
+ protected readonly options: TaskOptions;
431
+ protected state: TaskState;
432
+ protected process: ChildProcessWithoutNullStreams | null;
433
+ protected stdoutStream: WriteStream | null;
434
+ protected stderrStream: WriteStream | null;
435
+ protected ttlTimer: NodeJS.Timeout | null;
436
+ constructor(options: TaskOptions);
437
+ getState(): TaskState;
438
+ getOptions(): TaskOptions;
439
+ protected canStart(): boolean;
440
+ start(): Promise<void>;
441
+ protected canStop(): boolean;
442
+ stop(reason?: string): Promise<void>;
443
+ restart(): Promise<void>;
444
+ protected updateState(state: Partial<TaskState>): void;
445
+ protected initLogStreams(): Promise<void>;
446
+ protected setTTLTimer(): void;
447
+ protected addProcessListeners(): void;
448
+ protected onStdOutData(data: Buffer): void;
449
+ protected onStdErrData(data: Buffer): void;
450
+ protected onExit(code: number | null): void;
451
+ protected onError(error: Error): void;
452
+ protected cleanup(): void;
453
+ }
454
+
455
+ export enum TaskEvent {
456
+ STATE_CHANGE = 'state-change',
457
+ STDOUT = 'stdout',
458
+ STDERR = 'stderr',
459
+ }
460
+
461
+ export interface TaskOptions {
462
+ command: string;
463
+ arguments?: string[];
464
+ shell?: boolean;
465
+ stopSignal?: string;
466
+ cwd?: string;
467
+ env?: {
468
+ [key: string]: string | number | boolean;
469
+ };
470
+ ttl?: number;
471
+ log?: {
472
+ stdout?: string | null;
473
+ stderr?: string | null;
474
+ };
475
+ }
476
+
477
+ export interface TaskState extends RuniumTaskState {
478
+ pid: number;
479
+ }
480
+
481
+ export enum TaskStatus {
482
+ IDLE = 'idle',
483
+ STARTING = 'starting',
484
+ STARTED = 'started',
485
+ COMPLETED = 'completed',
486
+ FAILED = 'failed',
487
+ STOPPING = 'stopping',
488
+ STOPPED = 'stopped',
489
+ }
490
+
491
+ export class TimeoutTrigger extends RuniumTrigger<TimeoutTriggerOptions> {
492
+ constructor(
493
+ options: TimeoutTriggerOptions,
494
+ project: RuniumTriggerProjectAccessible
495
+ );
496
+ enable(): void;
497
+ disable(): void;
498
+ }
499
+
500
+ export interface TimeoutTriggerOptions extends RuniumTriggerOptions {
501
+ timeout: number;
502
+ }
503
+
504
+ export function validateProject(project: ProjectConfig, schema: object): void;
505
+
506
+ export function writeJsonFile<T = JSONValue>(
507
+ path: string,
508
+ data: T
509
+ ): Promise<void>;
510
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@runium/types-core",
3
+ "version": "0.0.0",
4
+ "description": "TypeScript type definitions for Runium Core",
5
+ "author": "TheBeastApp",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "index.d.ts",
9
+ "types": "index.d.ts",
10
+ "files": [
11
+ "index.d.ts"
12
+ ],
13
+ "keywords": [
14
+ "runium",
15
+ "core",
16
+ "types",
17
+ "typescript"
18
+ ],
19
+ "dependencies": {
20
+ "@types/node": "^22.18.0"
21
+ }
22
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,123 @@
1
+ import { resolve } from 'node:path';
2
+ import { writeFileSync, cpSync, readFileSync } from 'node:fs';
3
+ import { defineConfig, UserConfig } from 'vite';
4
+ import dts from 'vite-plugin-dts';
5
+ import { externalizeDeps } from 'vite-plugin-externalize-deps';
6
+ import { terser } from 'rollup-plugin-terser';
7
+
8
+ export default defineConfig({
9
+ base: './',
10
+ plugins: [
11
+ externalizeDeps(),
12
+ dts({
13
+ rollupTypes: true,
14
+ insertTypesEntry: true,
15
+ outDir: 'dist/core',
16
+ strictOutput: true,
17
+ beforeWriteFile: (filePath, content) => {
18
+ const replacedContent = removePrivateMembers(content);
19
+ return {
20
+ filePath,
21
+ content: replacedContent,
22
+ };
23
+ },
24
+ }),
25
+ afterBuildPlugin(),
26
+ ],
27
+ build: {
28
+ target: 'es2022',
29
+ outDir: 'dist/core',
30
+ emptyOutDir: true,
31
+ sourcemap: false,
32
+ rollupOptions: {
33
+ plugins: [terser({ compress: true, module: true })],
34
+ },
35
+ lib: {
36
+ entry: resolve(__dirname, 'src/index.ts'),
37
+ formats: ['es'],
38
+ fileName: 'index',
39
+ },
40
+ },
41
+ } satisfies UserConfig);
42
+
43
+ function afterBuildPlugin() {
44
+ const processPackageJson = () => {
45
+ let packageJson = JSON.parse(
46
+ readFileSync(resolve(__dirname, 'package.json'), 'utf-8')
47
+ );
48
+
49
+ const { dependencies } = packageJson;
50
+
51
+ delete packageJson.dependencies;
52
+ delete packageJson.devDependencies;
53
+ delete packageJson.scripts;
54
+
55
+ packageJson = Object.assign(packageJson, {
56
+ main: './index.js',
57
+ module: './index.js',
58
+ files: ['index.js'],
59
+ exports: {
60
+ '.': {
61
+ import: './index.js',
62
+ },
63
+ },
64
+ dependencies,
65
+ });
66
+
67
+ writeFileSync(
68
+ resolve(__dirname, 'dist', 'core', 'package.json'),
69
+ JSON.stringify(packageJson, null, 2)
70
+ );
71
+ };
72
+
73
+ const processTypes = () => {
74
+ // Copy types folder to dist
75
+ cpSync(resolve(__dirname, 'types'), resolve(__dirname, 'dist', 'types'), {
76
+ recursive: true,
77
+ });
78
+
79
+ // Read core package version
80
+ const corePackageJson = JSON.parse(
81
+ readFileSync(resolve(__dirname, 'package.json'), 'utf-8')
82
+ );
83
+ const coreVersion = corePackageJson.version;
84
+
85
+ // Update types package.json version
86
+ const typesPackageJsonPath = resolve(
87
+ __dirname,
88
+ 'dist',
89
+ 'types',
90
+ 'package.json'
91
+ );
92
+ const typesPackageJson = JSON.parse(
93
+ readFileSync(typesPackageJsonPath, 'utf-8')
94
+ );
95
+ typesPackageJson.version = coreVersion;
96
+
97
+ writeFileSync(
98
+ typesPackageJsonPath,
99
+ JSON.stringify(typesPackageJson, null, 2)
100
+ );
101
+ };
102
+
103
+ return {
104
+ name: 'after-build',
105
+ buildStart() {},
106
+ buildEnd() {},
107
+ closeBundle() {
108
+ processPackageJson();
109
+ processTypes();
110
+ },
111
+ };
112
+ }
113
+
114
+ function removePrivateMembers(content) {
115
+ const result = [];
116
+ content.split('\n').forEach(str => {
117
+ const isPrivate = str.includes('private ');
118
+ if (!isPrivate) {
119
+ result.push(str);
120
+ }
121
+ });
122
+ return result.join('\n');
123
+ }