@orgloop/core 0.1.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.
Files changed (46) hide show
  1. package/LICENSE.md +21 -0
  2. package/dist/bus.d.ts +35 -0
  3. package/dist/bus.d.ts.map +1 -0
  4. package/dist/bus.js +76 -0
  5. package/dist/bus.js.map +1 -0
  6. package/dist/engine.d.ts +88 -0
  7. package/dist/engine.d.ts.map +1 -0
  8. package/dist/engine.js +401 -0
  9. package/dist/engine.js.map +1 -0
  10. package/dist/errors.d.ts +31 -0
  11. package/dist/errors.d.ts.map +1 -0
  12. package/dist/errors.js +55 -0
  13. package/dist/errors.js.map +1 -0
  14. package/dist/http.d.ts +18 -0
  15. package/dist/http.d.ts.map +1 -0
  16. package/dist/http.js +75 -0
  17. package/dist/http.js.map +1 -0
  18. package/dist/index.d.ts +22 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +26 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/logger.d.ts +22 -0
  23. package/dist/logger.d.ts.map +1 -0
  24. package/dist/logger.js +49 -0
  25. package/dist/logger.js.map +1 -0
  26. package/dist/router.d.ts +17 -0
  27. package/dist/router.d.ts.map +1 -0
  28. package/dist/router.js +55 -0
  29. package/dist/router.js.map +1 -0
  30. package/dist/scheduler.d.ts +27 -0
  31. package/dist/scheduler.d.ts.map +1 -0
  32. package/dist/scheduler.js +62 -0
  33. package/dist/scheduler.js.map +1 -0
  34. package/dist/schema.d.ts +24 -0
  35. package/dist/schema.d.ts.map +1 -0
  36. package/dist/schema.js +186 -0
  37. package/dist/schema.js.map +1 -0
  38. package/dist/store.d.ts +51 -0
  39. package/dist/store.d.ts.map +1 -0
  40. package/dist/store.js +133 -0
  41. package/dist/store.js.map +1 -0
  42. package/dist/transform.d.ts +32 -0
  43. package/dist/transform.d.ts.map +1 -0
  44. package/dist/transform.js +158 -0
  45. package/dist/transform.js.map +1 -0
  46. package/package.json +38 -0
package/dist/schema.js ADDED
@@ -0,0 +1,186 @@
1
+ /**
2
+ * YAML config loading + JSON Schema validation.
3
+ *
4
+ * Loads orgloop.yaml and all referenced YAML files, resolves ${} env vars,
5
+ * validates against schema, and returns a fully resolved OrgLoopConfig.
6
+ */
7
+ import { readFile } from 'node:fs/promises';
8
+ import { dirname, isAbsolute, resolve } from 'node:path';
9
+ import AjvModule from 'ajv';
10
+ import yaml from 'js-yaml';
11
+ const Ajv = AjvModule.default ?? AjvModule;
12
+ import { ConfigError, SchemaError } from './errors.js';
13
+ // ─── JSON Schema for project config ──────────────────────────────────────────
14
+ const projectSchema = {
15
+ type: 'object',
16
+ required: ['apiVersion', 'kind', 'metadata'],
17
+ properties: {
18
+ apiVersion: { type: 'string' },
19
+ kind: { const: 'Project' },
20
+ metadata: {
21
+ type: 'object',
22
+ required: ['name'],
23
+ properties: {
24
+ name: { type: 'string' },
25
+ description: { type: 'string' },
26
+ },
27
+ },
28
+ defaults: {
29
+ type: 'object',
30
+ properties: {
31
+ poll_interval: { type: 'string' },
32
+ event_retention: { type: 'string' },
33
+ log_level: { type: 'string' },
34
+ },
35
+ },
36
+ connectors: { type: 'array', items: { type: 'string' } },
37
+ transforms: { type: 'array', items: { type: 'string' } },
38
+ loggers: { type: 'array', items: { type: 'string' } },
39
+ modules: {
40
+ type: 'array',
41
+ items: {
42
+ type: 'object',
43
+ required: ['package', 'params'],
44
+ properties: {
45
+ package: { type: 'string' },
46
+ params: { type: 'object' },
47
+ },
48
+ },
49
+ },
50
+ },
51
+ };
52
+ // ─── Env var substitution ─────────────────────────────────────────────────────
53
+ function substituteEnvVars(value) {
54
+ if (typeof value === 'string') {
55
+ return value.replace(/\$\{([^}]+)\}/g, (_match, varName) => {
56
+ const envVal = process.env[varName];
57
+ if (envVal === undefined) {
58
+ throw new ConfigError(`Environment variable "${varName}" is not set`);
59
+ }
60
+ return envVal;
61
+ });
62
+ }
63
+ if (Array.isArray(value)) {
64
+ return value.map(substituteEnvVars);
65
+ }
66
+ if (value !== null && typeof value === 'object') {
67
+ const result = {};
68
+ for (const [k, v] of Object.entries(value)) {
69
+ result[k] = substituteEnvVars(v);
70
+ }
71
+ return result;
72
+ }
73
+ return value;
74
+ }
75
+ // ─── YAML file loader ─────────────────────────────────────────────────────────
76
+ async function loadYamlFile(filePath) {
77
+ try {
78
+ const content = await readFile(filePath, 'utf-8');
79
+ const parsed = yaml.load(content);
80
+ return substituteEnvVars(parsed);
81
+ }
82
+ catch (err) {
83
+ if (err instanceof ConfigError)
84
+ throw err;
85
+ throw new ConfigError(`Failed to load YAML file: ${filePath}`, { cause: err });
86
+ }
87
+ }
88
+ async function loadConnectorFiles(basePath, files) {
89
+ const sources = [];
90
+ const actors = [];
91
+ for (const file of files) {
92
+ const filePath = isAbsolute(file) ? file : resolve(basePath, file);
93
+ const data = (await loadYamlFile(filePath));
94
+ if (data?.sources)
95
+ sources.push(...data.sources);
96
+ if (data?.actors)
97
+ actors.push(...data.actors);
98
+ }
99
+ return { sources, actors };
100
+ }
101
+ async function loadTransformFiles(basePath, files) {
102
+ const transforms = [];
103
+ for (const file of files) {
104
+ const filePath = isAbsolute(file) ? file : resolve(basePath, file);
105
+ const data = (await loadYamlFile(filePath));
106
+ if (data?.transforms)
107
+ transforms.push(...data.transforms);
108
+ }
109
+ return transforms;
110
+ }
111
+ async function loadLoggerFiles(basePath, files) {
112
+ const loggers = [];
113
+ for (const file of files) {
114
+ const filePath = isAbsolute(file) ? file : resolve(basePath, file);
115
+ const data = (await loadYamlFile(filePath));
116
+ if (data?.loggers)
117
+ loggers.push(...data.loggers);
118
+ }
119
+ return loggers;
120
+ }
121
+ async function loadRouteFile(filePath) {
122
+ const data = (await loadYamlFile(filePath));
123
+ const routes = data?.routes ?? [];
124
+ // Resolve with.prompt_file paths relative to the route YAML file
125
+ const routeDir = dirname(filePath);
126
+ for (const route of routes) {
127
+ if (route.with?.prompt_file) {
128
+ route.with.prompt_file = resolve(routeDir, route.with.prompt_file);
129
+ }
130
+ }
131
+ return routes;
132
+ }
133
+ /**
134
+ * Load and validate an OrgLoop configuration from YAML.
135
+ */
136
+ export async function loadConfig(options) {
137
+ const { configPath, routeFiles = [] } = options;
138
+ const basePath = dirname(resolve(configPath));
139
+ // Load and validate root config
140
+ const raw = await loadYamlFile(resolve(configPath));
141
+ const ajv = new Ajv({ allErrors: true });
142
+ const validate = ajv.compile(projectSchema);
143
+ if (!validate(raw)) {
144
+ const errors = (validate.errors ?? []).map((e) => `${e.instancePath || '/'}: ${e.message}`);
145
+ throw new SchemaError('Invalid project configuration', errors);
146
+ }
147
+ const project = raw;
148
+ // Load referenced files
149
+ const { sources, actors } = await loadConnectorFiles(basePath, project.connectors ?? []);
150
+ const transforms = await loadTransformFiles(basePath, project.transforms ?? []);
151
+ const loggers = await loadLoggerFiles(basePath, project.loggers ?? []);
152
+ // Load route files
153
+ const routes = [];
154
+ for (const rf of routeFiles) {
155
+ const rfPath = isAbsolute(rf) ? rf : resolve(basePath, rf);
156
+ routes.push(...(await loadRouteFile(rfPath)));
157
+ }
158
+ return {
159
+ project: {
160
+ name: project.metadata.name,
161
+ description: project.metadata.description,
162
+ },
163
+ sources,
164
+ actors,
165
+ routes,
166
+ transforms,
167
+ loggers,
168
+ defaults: project.defaults,
169
+ };
170
+ }
171
+ /**
172
+ * Build an OrgLoopConfig programmatically (for library/testing use).
173
+ */
174
+ export function buildConfig(partial) {
175
+ return {
176
+ project: partial.project,
177
+ sources: partial.sources ?? [],
178
+ actors: partial.actors ?? [],
179
+ routes: partial.routes ?? [],
180
+ transforms: partial.transforms ?? [],
181
+ loggers: partial.loggers ?? [],
182
+ defaults: partial.defaults,
183
+ data_dir: partial.data_dir,
184
+ };
185
+ }
186
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Event store + checkpoint persistence.
3
+ *
4
+ * CheckpointStore: persists source poll checkpoints for crash recovery.
5
+ * EventStore: append-only JSONL WAL for at-least-once delivery guarantee.
6
+ */
7
+ import type { OrgLoopEvent } from '@orgloop/sdk';
8
+ export interface CheckpointStore {
9
+ get(sourceId: string): Promise<string | null>;
10
+ set(sourceId: string, checkpoint: string): Promise<void>;
11
+ }
12
+ export declare class FileCheckpointStore implements CheckpointStore {
13
+ private readonly dir;
14
+ constructor(dataDir?: string);
15
+ private filePath;
16
+ get(sourceId: string): Promise<string | null>;
17
+ set(sourceId: string, checkpoint: string): Promise<void>;
18
+ }
19
+ export interface WalEntry {
20
+ id: string;
21
+ event: OrgLoopEvent;
22
+ written_at: string;
23
+ acked: boolean;
24
+ }
25
+ export interface EventStore {
26
+ write(event: OrgLoopEvent): Promise<WalEntry>;
27
+ ack(entryId: string): Promise<void>;
28
+ unacked(): Promise<WalEntry[]>;
29
+ }
30
+ export declare class FileEventStore implements EventStore {
31
+ private readonly walDir;
32
+ private readonly walFile;
33
+ private readonly ackedSet;
34
+ constructor(dataDir?: string);
35
+ write(event: OrgLoopEvent): Promise<WalEntry>;
36
+ ack(entryId: string): Promise<void>;
37
+ unacked(): Promise<WalEntry[]>;
38
+ }
39
+ export declare class InMemoryCheckpointStore implements CheckpointStore {
40
+ private readonly data;
41
+ get(sourceId: string): Promise<string | null>;
42
+ set(sourceId: string, checkpoint: string): Promise<void>;
43
+ }
44
+ export declare class InMemoryEventStore implements EventStore {
45
+ private readonly entries;
46
+ private readonly ackedSet;
47
+ write(event: OrgLoopEvent): Promise<WalEntry>;
48
+ ack(entryId: string): Promise<void>;
49
+ unacked(): Promise<WalEntry[]>;
50
+ }
51
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAIjD,MAAM,WAAW,eAAe;IAC/B,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC9C,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED,qBAAa,mBAAoB,YAAW,eAAe;IAC1D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAEjB,OAAO,CAAC,EAAE,MAAM;IAM5B,OAAO,CAAC,QAAQ;IAIV,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAU7C,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAQ9D;AAID,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,YAAY,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;CACf;AAID,MAAM,WAAW,UAAU;IAC1B,KAAK,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9C,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CAC/B;AAED,qBAAa,cAAe,YAAW,UAAU;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;gBAElC,OAAO,CAAC,EAAE,MAAM;IAKtB,KAAK,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC;IAY7C,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWnC,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;CAmCpC;AAID,qBAAa,uBAAwB,YAAW,eAAe;IAC9D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6B;IAE5C,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI7C,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9D;AAED,qBAAa,kBAAmB,YAAW,UAAU;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAExC,KAAK,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC;IAW7C,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInC,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;CASpC"}
package/dist/store.js ADDED
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Event store + checkpoint persistence.
3
+ *
4
+ * CheckpointStore: persists source poll checkpoints for crash recovery.
5
+ * EventStore: append-only JSONL WAL for at-least-once delivery guarantee.
6
+ */
7
+ import { appendFile, mkdir, readFile, writeFile } from 'node:fs/promises';
8
+ import { homedir } from 'node:os';
9
+ import { dirname, join } from 'node:path';
10
+ export class FileCheckpointStore {
11
+ dir;
12
+ constructor(dataDir) {
13
+ this.dir = dataDir
14
+ ? join(dataDir, 'checkpoints')
15
+ : join(homedir(), '.orgloop', 'data', 'checkpoints');
16
+ }
17
+ filePath(sourceId) {
18
+ return join(this.dir, `${sourceId}.json`);
19
+ }
20
+ async get(sourceId) {
21
+ try {
22
+ const content = await readFile(this.filePath(sourceId), 'utf-8');
23
+ const data = JSON.parse(content);
24
+ return data.checkpoint;
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ async set(sourceId, checkpoint) {
31
+ await mkdir(this.dir, { recursive: true });
32
+ await writeFile(this.filePath(sourceId), JSON.stringify({ checkpoint, updated_at: new Date().toISOString() }), 'utf-8');
33
+ }
34
+ }
35
+ export class FileEventStore {
36
+ walDir;
37
+ walFile;
38
+ ackedSet = new Set();
39
+ constructor(dataDir) {
40
+ this.walDir = dataDir ? join(dataDir, 'wal') : join(homedir(), '.orgloop', 'data', 'wal');
41
+ this.walFile = join(this.walDir, 'events.jsonl');
42
+ }
43
+ async write(event) {
44
+ await mkdir(this.walDir, { recursive: true });
45
+ const entry = {
46
+ id: event.id,
47
+ event,
48
+ written_at: new Date().toISOString(),
49
+ acked: false,
50
+ };
51
+ await appendFile(this.walFile, `${JSON.stringify(entry)}\n`, 'utf-8');
52
+ return entry;
53
+ }
54
+ async ack(entryId) {
55
+ this.ackedSet.add(entryId);
56
+ // Write ack marker to WAL
57
+ await mkdir(this.walDir, { recursive: true });
58
+ await appendFile(this.walFile, `${JSON.stringify({ type: 'ack', id: entryId, acked_at: new Date().toISOString() })}\n`, 'utf-8');
59
+ }
60
+ async unacked() {
61
+ let content;
62
+ try {
63
+ content = await readFile(this.walFile, 'utf-8');
64
+ }
65
+ catch {
66
+ return [];
67
+ }
68
+ const entries = new Map();
69
+ const acked = new Set(this.ackedSet);
70
+ for (const line of content.split('\n')) {
71
+ if (!line.trim())
72
+ continue;
73
+ try {
74
+ const parsed = JSON.parse(line);
75
+ if (parsed.type === 'ack') {
76
+ acked.add(parsed.id);
77
+ }
78
+ else {
79
+ const entry = parsed;
80
+ entries.set(entry.id, entry);
81
+ }
82
+ }
83
+ catch {
84
+ // Skip malformed lines
85
+ }
86
+ }
87
+ // Return entries not acked
88
+ const result = [];
89
+ for (const [id, entry] of entries) {
90
+ if (!acked.has(id)) {
91
+ result.push(entry);
92
+ }
93
+ }
94
+ return result;
95
+ }
96
+ }
97
+ // ─── In-memory stores (for testing) ──────────────────────────────────────────
98
+ export class InMemoryCheckpointStore {
99
+ data = new Map();
100
+ async get(sourceId) {
101
+ return this.data.get(sourceId) ?? null;
102
+ }
103
+ async set(sourceId, checkpoint) {
104
+ this.data.set(sourceId, checkpoint);
105
+ }
106
+ }
107
+ export class InMemoryEventStore {
108
+ entries = new Map();
109
+ ackedSet = new Set();
110
+ async write(event) {
111
+ const entry = {
112
+ id: event.id,
113
+ event,
114
+ written_at: new Date().toISOString(),
115
+ acked: false,
116
+ };
117
+ this.entries.set(entry.id, entry);
118
+ return entry;
119
+ }
120
+ async ack(entryId) {
121
+ this.ackedSet.add(entryId);
122
+ }
123
+ async unacked() {
124
+ const result = [];
125
+ for (const [id, entry] of this.entries) {
126
+ if (!this.ackedSet.has(id)) {
127
+ result.push(entry);
128
+ }
129
+ }
130
+ return result;
131
+ }
132
+ }
133
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Transform pipeline executor.
3
+ *
4
+ * Executes transforms in sequence for a route. Supports both script
5
+ * transforms (shell scripts via child_process) and package transforms.
6
+ *
7
+ * Script transform contract:
8
+ * - stdin = JSON event
9
+ * - stdout = modified JSON event (or empty = drop)
10
+ * - exit 0 = success, exit 1 = drop, exit >= 2 = error (fail-open)
11
+ */
12
+ import type { LogEntry, OrgLoopEvent, RouteTransformRef, TransformDefinition } from '@orgloop/sdk';
13
+ import type { Transform, TransformContext } from '@orgloop/sdk';
14
+ export interface TransformPipelineOptions {
15
+ /** All registered transform definitions */
16
+ definitions: TransformDefinition[];
17
+ /** Loaded package transform instances (keyed by name) */
18
+ packageTransforms: Map<string, Transform>;
19
+ /** Log callback for pipeline observability */
20
+ onLog?: (entry: Partial<LogEntry>) => void;
21
+ }
22
+ export interface TransformPipelineResult {
23
+ event: OrgLoopEvent | null;
24
+ dropped: boolean;
25
+ dropTransform?: string;
26
+ error?: Error;
27
+ }
28
+ /**
29
+ * Execute a transform pipeline for a route.
30
+ */
31
+ export declare function executeTransformPipeline(event: OrgLoopEvent, context: TransformContext, transformRefs: RouteTransformRef[], options: TransformPipelineOptions): Promise<TransformPipelineResult>;
32
+ //# sourceMappingURL=transform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnG,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AA4EhE,MAAM,WAAW,wBAAwB;IACxC,2CAA2C;IAC3C,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,yDAAyD;IACzD,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1C,8CAA8C;IAC9C,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,uBAAuB;IACvC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC;CACd;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC7C,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,iBAAiB,EAAE,EAClC,OAAO,EAAE,wBAAwB,GAC/B,OAAO,CAAC,uBAAuB,CAAC,CA2GlC"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Transform pipeline executor.
3
+ *
4
+ * Executes transforms in sequence for a route. Supports both script
5
+ * transforms (shell scripts via child_process) and package transforms.
6
+ *
7
+ * Script transform contract:
8
+ * - stdin = JSON event
9
+ * - stdout = modified JSON event (or empty = drop)
10
+ * - exit 0 = success, exit 1 = drop, exit >= 2 = error (fail-open)
11
+ */
12
+ import { execFile } from 'node:child_process';
13
+ import { TransformError } from './errors.js';
14
+ // ─── Script Transform Execution ──────────────────────────────────────────────
15
+ const DEFAULT_TIMEOUT_MS = 30_000;
16
+ function runScript(scriptPath, event, context, timeoutMs) {
17
+ return new Promise((resolve) => {
18
+ const env = {
19
+ ...process.env,
20
+ ORGLOOP_SOURCE: context.source,
21
+ ORGLOOP_TARGET: context.target,
22
+ ORGLOOP_EVENT_TYPE: context.eventType,
23
+ ORGLOOP_EVENT_ID: event.id,
24
+ ORGLOOP_ROUTE: context.routeName,
25
+ };
26
+ const child = execFile(scriptPath, [], { timeout: timeoutMs, env, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, _stderr) => {
27
+ if (error) {
28
+ // execFile errors have a `code` property that is the exit code (number)
29
+ // or a Node error code (string) for system errors
30
+ const errWithCode = error;
31
+ const exitCode = typeof errWithCode.code === 'number' ? errWithCode.code : null;
32
+ // exit 1 = intentional drop
33
+ if (exitCode === 1) {
34
+ resolve({ event: null, dropped: true });
35
+ return;
36
+ }
37
+ // exit >= 2 or other errors = fail-open (pass through original)
38
+ resolve({ event, dropped: false, error: error });
39
+ return;
40
+ }
41
+ const trimmed = stdout.trim();
42
+ if (!trimmed) {
43
+ // Empty stdout = drop
44
+ resolve({ event: null, dropped: true });
45
+ return;
46
+ }
47
+ try {
48
+ const modified = JSON.parse(trimmed);
49
+ resolve({ event: modified, dropped: false });
50
+ }
51
+ catch (parseErr) {
52
+ // Invalid JSON = fail-open
53
+ resolve({ event, dropped: false, error: parseErr });
54
+ }
55
+ });
56
+ // Write event JSON to stdin
57
+ if (child.stdin) {
58
+ child.stdin.write(JSON.stringify(event));
59
+ child.stdin.end();
60
+ }
61
+ });
62
+ }
63
+ /**
64
+ * Execute a transform pipeline for a route.
65
+ */
66
+ export async function executeTransformPipeline(event, context, transformRefs, options) {
67
+ let current = event;
68
+ for (const ref of transformRefs) {
69
+ const def = options.definitions.find((d) => d.name === ref.ref);
70
+ if (!def) {
71
+ throw new TransformError(ref.ref, `Transform "${ref.ref}" not found in definitions`);
72
+ }
73
+ const startTime = Date.now();
74
+ options.onLog?.({
75
+ phase: 'transform.start',
76
+ transform: def.name,
77
+ event_id: current.id,
78
+ trace_id: current.trace_id,
79
+ });
80
+ if (def.type === 'script' && def.script) {
81
+ const result = await runScript(def.script, current, context, def.timeout_ms ?? DEFAULT_TIMEOUT_MS);
82
+ const durationMs = Date.now() - startTime;
83
+ if (result.dropped) {
84
+ options.onLog?.({
85
+ phase: 'transform.drop',
86
+ transform: def.name,
87
+ event_id: current.id,
88
+ trace_id: current.trace_id,
89
+ duration_ms: durationMs,
90
+ });
91
+ return { event: null, dropped: true, dropTransform: def.name };
92
+ }
93
+ if (result.error) {
94
+ options.onLog?.({
95
+ phase: 'transform.error',
96
+ transform: def.name,
97
+ event_id: current.id,
98
+ trace_id: current.trace_id,
99
+ error: result.error.message,
100
+ duration_ms: durationMs,
101
+ });
102
+ // fail-open: continue with current event
103
+ }
104
+ if (result.event) {
105
+ current = result.event;
106
+ }
107
+ options.onLog?.({
108
+ phase: 'transform.pass',
109
+ transform: def.name,
110
+ event_id: current.id,
111
+ trace_id: current.trace_id,
112
+ duration_ms: durationMs,
113
+ });
114
+ }
115
+ else if (def.type === 'package') {
116
+ const transform = options.packageTransforms.get(def.name);
117
+ if (!transform) {
118
+ throw new TransformError(def.name, `Package transform "${def.name}" not loaded`);
119
+ }
120
+ try {
121
+ const result = await transform.execute(current, context);
122
+ const durationMs = Date.now() - startTime;
123
+ if (result === null) {
124
+ options.onLog?.({
125
+ phase: 'transform.drop',
126
+ transform: def.name,
127
+ event_id: current.id,
128
+ trace_id: current.trace_id,
129
+ duration_ms: durationMs,
130
+ });
131
+ return { event: null, dropped: true, dropTransform: def.name };
132
+ }
133
+ current = result;
134
+ options.onLog?.({
135
+ phase: 'transform.pass',
136
+ transform: def.name,
137
+ event_id: current.id,
138
+ trace_id: current.trace_id,
139
+ duration_ms: durationMs,
140
+ });
141
+ }
142
+ catch (err) {
143
+ const durationMs = Date.now() - startTime;
144
+ options.onLog?.({
145
+ phase: 'transform.error',
146
+ transform: def.name,
147
+ event_id: current.id,
148
+ trace_id: current.trace_id,
149
+ error: err.message,
150
+ duration_ms: durationMs,
151
+ });
152
+ // fail-open: continue with current event
153
+ }
154
+ }
155
+ }
156
+ return { event: current, dropped: false };
157
+ }
158
+ //# sourceMappingURL=transform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.js","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@orgloop/core",
3
+ "version": "0.1.0",
4
+ "description": "OrgLoop runtime engine — library-first event routing",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "dependencies": {
15
+ "ajv": "^8.17.0",
16
+ "js-yaml": "^4.1.0",
17
+ "uuid": "^11.0.0",
18
+ "@orgloop/sdk": "0.1.0"
19
+ },
20
+ "devDependencies": {
21
+ "@types/js-yaml": "^4.0.9",
22
+ "@types/uuid": "^10.0.0",
23
+ "fast-check": "^4.0.0"
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "license": "MIT",
32
+ "scripts": {
33
+ "build": "tsc",
34
+ "clean": "rm -rf dist",
35
+ "typecheck": "tsc --noEmit",
36
+ "test": "vitest run"
37
+ }
38
+ }