routeflow-api 0.2.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 (70) hide show
  1. package/README.md +93 -0
  2. package/dist/adapters/cassandra.cjs +117 -0
  3. package/dist/adapters/cassandra.cjs.map +1 -0
  4. package/dist/adapters/cassandra.d.cts +37 -0
  5. package/dist/adapters/cassandra.d.ts +37 -0
  6. package/dist/adapters/cassandra.js +90 -0
  7. package/dist/adapters/cassandra.js.map +1 -0
  8. package/dist/adapters/dynamodb.cjs +180 -0
  9. package/dist/adapters/dynamodb.cjs.map +1 -0
  10. package/dist/adapters/dynamodb.d.cts +48 -0
  11. package/dist/adapters/dynamodb.d.ts +48 -0
  12. package/dist/adapters/dynamodb.js +153 -0
  13. package/dist/adapters/dynamodb.js.map +1 -0
  14. package/dist/adapters/elasticsearch.cjs +120 -0
  15. package/dist/adapters/elasticsearch.cjs.map +1 -0
  16. package/dist/adapters/elasticsearch.d.cts +43 -0
  17. package/dist/adapters/elasticsearch.d.ts +43 -0
  18. package/dist/adapters/elasticsearch.js +93 -0
  19. package/dist/adapters/elasticsearch.js.map +1 -0
  20. package/dist/adapters/mongodb.cjs +159 -0
  21. package/dist/adapters/mongodb.cjs.map +1 -0
  22. package/dist/adapters/mongodb.d.cts +54 -0
  23. package/dist/adapters/mongodb.d.ts +54 -0
  24. package/dist/adapters/mongodb.js +132 -0
  25. package/dist/adapters/mongodb.js.map +1 -0
  26. package/dist/adapters/mysql.cjs +159 -0
  27. package/dist/adapters/mysql.cjs.map +1 -0
  28. package/dist/adapters/mysql.d.cts +63 -0
  29. package/dist/adapters/mysql.d.ts +63 -0
  30. package/dist/adapters/mysql.js +132 -0
  31. package/dist/adapters/mysql.js.map +1 -0
  32. package/dist/adapters/opensearch.cjs +120 -0
  33. package/dist/adapters/opensearch.cjs.map +1 -0
  34. package/dist/adapters/opensearch.d.cts +2 -0
  35. package/dist/adapters/opensearch.d.ts +2 -0
  36. package/dist/adapters/opensearch.js +93 -0
  37. package/dist/adapters/opensearch.js.map +1 -0
  38. package/dist/adapters/postgres.cjs +271 -0
  39. package/dist/adapters/postgres.cjs.map +1 -0
  40. package/dist/adapters/postgres.d.cts +81 -0
  41. package/dist/adapters/postgres.d.ts +81 -0
  42. package/dist/adapters/postgres.js +244 -0
  43. package/dist/adapters/postgres.js.map +1 -0
  44. package/dist/adapters/redis.cjs +153 -0
  45. package/dist/adapters/redis.cjs.map +1 -0
  46. package/dist/adapters/redis.d.cts +40 -0
  47. package/dist/adapters/redis.d.ts +40 -0
  48. package/dist/adapters/redis.js +126 -0
  49. package/dist/adapters/redis.js.map +1 -0
  50. package/dist/adapters/snowflake.cjs +117 -0
  51. package/dist/adapters/snowflake.cjs.map +1 -0
  52. package/dist/adapters/snowflake.d.cts +37 -0
  53. package/dist/adapters/snowflake.d.ts +37 -0
  54. package/dist/adapters/snowflake.js +90 -0
  55. package/dist/adapters/snowflake.js.map +1 -0
  56. package/dist/client/index.cjs +484 -0
  57. package/dist/client/index.cjs.map +1 -0
  58. package/dist/client/index.d.cts +174 -0
  59. package/dist/client/index.d.ts +174 -0
  60. package/dist/client/index.js +455 -0
  61. package/dist/client/index.js.map +1 -0
  62. package/dist/index.cjs +935 -0
  63. package/dist/index.cjs.map +1 -0
  64. package/dist/index.d.cts +190 -0
  65. package/dist/index.d.ts +190 -0
  66. package/dist/index.js +890 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/types-tPDla8AE.d.cts +75 -0
  69. package/dist/types-tPDla8AE.d.ts +75 -0
  70. package/package.json +157 -0
@@ -0,0 +1,63 @@
1
+ import { D as DatabaseAdapter, C as ChangeEvent } from '../types-tPDla8AE.js';
2
+
3
+ interface MySqlBinlogTableMap {
4
+ parentSchema?: string;
5
+ schemaName?: string;
6
+ tableName?: string;
7
+ }
8
+ interface MySqlWriteRowsEvent {
9
+ getTypeName?: () => string;
10
+ tableMap?: MySqlBinlogTableMap;
11
+ rows: Array<Record<string, unknown>>;
12
+ }
13
+ interface MySqlDeleteRowsEvent {
14
+ getTypeName?: () => string;
15
+ tableMap?: MySqlBinlogTableMap;
16
+ rows: Array<Record<string, unknown>>;
17
+ }
18
+ interface MySqlUpdateRowsEvent {
19
+ getTypeName?: () => string;
20
+ tableMap?: MySqlBinlogTableMap;
21
+ rows: Array<{
22
+ before: Record<string, unknown>;
23
+ after: Record<string, unknown>;
24
+ }>;
25
+ }
26
+ type MySqlBinlogEvent = MySqlWriteRowsEvent | MySqlDeleteRowsEvent | MySqlUpdateRowsEvent;
27
+ interface MySqlBinlogSource {
28
+ on(event: 'binlog', listener: (event: MySqlBinlogEvent) => void): void;
29
+ on(event: 'error', listener: (error: Error) => void): void;
30
+ off?(event: 'binlog' | 'error', listener: (...args: any[]) => void): void;
31
+ removeListener?(event: 'binlog' | 'error', listener: (...args: any[]) => void): void;
32
+ start?(options?: Record<string, unknown>): Promise<void> | void;
33
+ stop?(): Promise<void> | void;
34
+ }
35
+ interface MySqlAdapterOptions {
36
+ source: MySqlBinlogSource;
37
+ schema?: string;
38
+ startOptions?: Record<string, unknown>;
39
+ onError?: (error: unknown) => void;
40
+ }
41
+
42
+ /**
43
+ * MySQL adapter for RouteFlow.
44
+ *
45
+ * It consumes a binlog event source compatible with libraries such as ZongJi.
46
+ */
47
+ declare class MySqlAdapter implements DatabaseAdapter {
48
+ private readonly source;
49
+ private readonly schema?;
50
+ private readonly startOptions?;
51
+ private readonly onError?;
52
+ private readonly listeners;
53
+ private readonly handleBinlogBound;
54
+ private readonly handleErrorBound;
55
+ private connected;
56
+ constructor(options: MySqlAdapterOptions);
57
+ connect(): Promise<void>;
58
+ disconnect(): Promise<void>;
59
+ onChange(table: string, callback: (event: ChangeEvent) => void): () => void;
60
+ private handleBinlog;
61
+ }
62
+
63
+ export { MySqlAdapter, type MySqlAdapterOptions };
@@ -0,0 +1,132 @@
1
+ // src/core/errors.ts
2
+ var ReactiveApiError = class extends Error {
3
+ /** Machine-readable error code (e.g. 'ADAPTER_NOT_CONNECTED', 'INVALID_ROUTE') */
4
+ code;
5
+ constructor(code, message) {
6
+ super(message);
7
+ this.name = "ReactiveApiError";
8
+ this.code = code;
9
+ Object.setPrototypeOf(this, new.target.prototype);
10
+ }
11
+ };
12
+
13
+ // src/adapters/mysql/mysql-adapter.ts
14
+ var MySqlAdapter = class {
15
+ source;
16
+ schema;
17
+ startOptions;
18
+ onError;
19
+ listeners = /* @__PURE__ */ new Map();
20
+ handleBinlogBound = (event) => {
21
+ this.handleBinlog(event);
22
+ };
23
+ handleErrorBound = (error) => {
24
+ this.onError?.(error);
25
+ };
26
+ connected = false;
27
+ constructor(options) {
28
+ this.source = options.source;
29
+ this.schema = options.schema;
30
+ this.startOptions = options.startOptions;
31
+ this.onError = options.onError;
32
+ }
33
+ async connect() {
34
+ if (this.connected) return;
35
+ this.source.on("binlog", this.handleBinlogBound);
36
+ this.source.on("error", this.handleErrorBound);
37
+ try {
38
+ await this.source.start?.(this.startOptions);
39
+ } catch (error) {
40
+ throw new ReactiveApiError(
41
+ "MYSQL_BINLOG_START_FAILED",
42
+ `Failed to start MySQL binlog source: ${errorMessage(error)}`
43
+ );
44
+ }
45
+ this.connected = true;
46
+ }
47
+ async disconnect() {
48
+ if (!this.connected) return;
49
+ removeListener(this.source, "binlog", this.handleBinlogBound);
50
+ removeListener(this.source, "error", this.handleErrorBound);
51
+ await this.source.stop?.();
52
+ this.listeners.clear();
53
+ this.connected = false;
54
+ }
55
+ onChange(table, callback) {
56
+ if (!this.listeners.has(table)) {
57
+ this.listeners.set(table, /* @__PURE__ */ new Set());
58
+ }
59
+ this.listeners.get(table).add(callback);
60
+ return () => {
61
+ const callbacks = this.listeners.get(table);
62
+ if (!callbacks) return;
63
+ callbacks.delete(callback);
64
+ if (callbacks.size === 0) {
65
+ this.listeners.delete(table);
66
+ }
67
+ };
68
+ }
69
+ handleBinlog(event) {
70
+ const changes = normaliseBinlogEvent(event);
71
+ if (changes.length === 0) return;
72
+ for (const change of changes) {
73
+ if (this.schema && readSchemaName(event) !== this.schema) continue;
74
+ const callbacks = this.listeners.get(change.table);
75
+ if (!callbacks) continue;
76
+ const fluxEvent = {
77
+ ...change,
78
+ timestamp: Date.now()
79
+ };
80
+ for (const callback of callbacks) {
81
+ callback(fluxEvent);
82
+ }
83
+ }
84
+ }
85
+ };
86
+ function normaliseBinlogEvent(event) {
87
+ const typeName = event.getTypeName?.().toLowerCase() ?? "";
88
+ const table = event.tableMap?.tableName;
89
+ if (!table) return [];
90
+ if (typeName.includes("write")) {
91
+ return event.rows.map((row) => ({
92
+ table,
93
+ operation: "INSERT",
94
+ newRow: row,
95
+ oldRow: null
96
+ }));
97
+ }
98
+ if (typeName.includes("delete")) {
99
+ return event.rows.map((row) => ({
100
+ table,
101
+ operation: "DELETE",
102
+ newRow: null,
103
+ oldRow: row
104
+ }));
105
+ }
106
+ if (typeName.includes("update")) {
107
+ return event.rows.map((row) => ({
108
+ table,
109
+ operation: "UPDATE",
110
+ newRow: row.after,
111
+ oldRow: row.before
112
+ }));
113
+ }
114
+ return [];
115
+ }
116
+ function readSchemaName(event) {
117
+ return event.tableMap?.parentSchema ?? event.tableMap?.schemaName;
118
+ }
119
+ function removeListener(source, event, listener) {
120
+ if (source.off) {
121
+ source.off(event, listener);
122
+ return;
123
+ }
124
+ source.removeListener?.(event, listener);
125
+ }
126
+ function errorMessage(error) {
127
+ return error instanceof Error ? error.message : String(error);
128
+ }
129
+ export {
130
+ MySqlAdapter
131
+ };
132
+ //# sourceMappingURL=mysql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/errors.ts","../../src/adapters/mysql/mysql-adapter.ts"],"sourcesContent":["/**\n * Base error class for all RouteFlow errors.\n * Always use this instead of plain `Error` throughout the framework.\n */\nexport class ReactiveApiError extends Error {\n /** Machine-readable error code (e.g. 'ADAPTER_NOT_CONNECTED', 'INVALID_ROUTE') */\n readonly code: string\n\n constructor(code: string, message: string) {\n super(message)\n this.name = 'ReactiveApiError'\n this.code = code\n // Restore prototype chain (required when extending built-ins in TS)\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","import type { ChangeEvent, DatabaseAdapter } from '../../core/types.js'\nimport { ReactiveApiError } from '../../core/errors.js'\nimport type {\n MySqlAdapterOptions,\n MySqlBinlogEvent,\n MySqlBinlogSource,\n NormalisedMySqlChange,\n} from './types.js'\n\n/**\n * MySQL adapter for RouteFlow.\n *\n * It consumes a binlog event source compatible with libraries such as ZongJi.\n */\nexport class MySqlAdapter implements DatabaseAdapter {\n private readonly source: MySqlBinlogSource\n private readonly schema?: string\n private readonly startOptions?: Record<string, unknown>\n private readonly onError?: (error: unknown) => void\n private readonly listeners: Map<string, Set<(event: ChangeEvent) => void>> = new Map()\n private readonly handleBinlogBound = (event: MySqlBinlogEvent) => {\n this.handleBinlog(event)\n }\n private readonly handleErrorBound = (error: Error) => {\n this.onError?.(error)\n }\n private connected = false\n\n constructor(options: MySqlAdapterOptions) {\n this.source = options.source\n this.schema = options.schema\n this.startOptions = options.startOptions\n this.onError = options.onError\n }\n\n async connect(): Promise<void> {\n if (this.connected) return\n\n this.source.on('binlog', this.handleBinlogBound)\n this.source.on('error', this.handleErrorBound)\n\n try {\n await this.source.start?.(this.startOptions)\n } catch (error) {\n throw new ReactiveApiError(\n 'MYSQL_BINLOG_START_FAILED',\n `Failed to start MySQL binlog source: ${errorMessage(error)}`,\n )\n }\n\n this.connected = true\n }\n\n async disconnect(): Promise<void> {\n if (!this.connected) return\n\n removeListener(this.source, 'binlog', this.handleBinlogBound)\n removeListener(this.source, 'error', this.handleErrorBound)\n await this.source.stop?.()\n this.listeners.clear()\n this.connected = false\n }\n\n onChange(table: string, callback: (event: ChangeEvent) => void): () => void {\n if (!this.listeners.has(table)) {\n this.listeners.set(table, new Set())\n }\n\n this.listeners.get(table)!.add(callback)\n\n return () => {\n const callbacks = this.listeners.get(table)\n if (!callbacks) return\n\n callbacks.delete(callback)\n if (callbacks.size === 0) {\n this.listeners.delete(table)\n }\n }\n }\n\n private handleBinlog(event: MySqlBinlogEvent): void {\n const changes = normaliseBinlogEvent(event)\n if (changes.length === 0) return\n\n for (const change of changes) {\n if (this.schema && readSchemaName(event) !== this.schema) continue\n\n const callbacks = this.listeners.get(change.table)\n if (!callbacks) continue\n\n const fluxEvent: ChangeEvent = {\n ...change,\n timestamp: Date.now(),\n }\n\n for (const callback of callbacks) {\n callback(fluxEvent)\n }\n }\n }\n}\n\nfunction normaliseBinlogEvent(event: MySqlBinlogEvent): NormalisedMySqlChange[] {\n const typeName = event.getTypeName?.().toLowerCase() ?? ''\n const table = event.tableMap?.tableName\n if (!table) return []\n\n if (typeName.includes('write')) {\n return event.rows.map((row) => ({\n table,\n operation: 'INSERT',\n newRow: row,\n oldRow: null,\n }))\n }\n\n if (typeName.includes('delete')) {\n return event.rows.map((row) => ({\n table,\n operation: 'DELETE',\n newRow: null,\n oldRow: row,\n }))\n }\n\n if (typeName.includes('update')) {\n return event.rows.map((row) => ({\n table,\n operation: 'UPDATE',\n newRow: row.after,\n oldRow: row.before,\n }))\n }\n\n return []\n}\n\nfunction readSchemaName(event: MySqlBinlogEvent): string | undefined {\n return event.tableMap?.parentSchema ?? event.tableMap?.schemaName\n}\n\nfunction removeListener(\n source: MySqlBinlogSource,\n event: 'binlog' | 'error',\n listener: (...args: any[]) => void,\n): void {\n if (source.off) {\n source.off(event, listener)\n return\n }\n\n source.removeListener?.(event, listener)\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/adapters/opensearch.ts
21
+ var opensearch_exports = {};
22
+ __export(opensearch_exports, {
23
+ OpenSearchAdapter: () => ElasticsearchAdapter
24
+ });
25
+ module.exports = __toCommonJS(opensearch_exports);
26
+
27
+ // src/core/errors.ts
28
+ var ReactiveApiError = class extends Error {
29
+ /** Machine-readable error code (e.g. 'ADAPTER_NOT_CONNECTED', 'INVALID_ROUTE') */
30
+ code;
31
+ constructor(code, message) {
32
+ super(message);
33
+ this.name = "ReactiveApiError";
34
+ this.code = code;
35
+ Object.setPrototypeOf(this, new.target.prototype);
36
+ }
37
+ };
38
+
39
+ // src/adapters/elasticsearch/elasticsearch-adapter.ts
40
+ var ElasticsearchAdapter = class {
41
+ source;
42
+ onError;
43
+ listeners = /* @__PURE__ */ new Map();
44
+ handleChangeBound = (change) => {
45
+ this.handleChange(change);
46
+ };
47
+ handleErrorBound = (error) => {
48
+ this.onError?.(error);
49
+ };
50
+ connected = false;
51
+ constructor(options) {
52
+ this.source = options.source;
53
+ this.onError = options.onError;
54
+ }
55
+ async connect() {
56
+ if (this.connected) return;
57
+ this.source.on("change", this.handleChangeBound);
58
+ this.source.on("error", this.handleErrorBound);
59
+ try {
60
+ await this.source.start?.();
61
+ } catch (error) {
62
+ throw new ReactiveApiError(
63
+ "ELASTICSEARCH_SOURCE_START_FAILED",
64
+ `Failed to start Elasticsearch change source: ${errorMessage(error)}`
65
+ );
66
+ }
67
+ this.connected = true;
68
+ }
69
+ async disconnect() {
70
+ if (!this.connected) return;
71
+ removeListener(this.source, "change", this.handleChangeBound);
72
+ removeListener(this.source, "error", this.handleErrorBound);
73
+ await this.source.stop?.();
74
+ this.listeners.clear();
75
+ this.connected = false;
76
+ }
77
+ onChange(index, callback) {
78
+ if (!this.listeners.has(index)) {
79
+ this.listeners.set(index, /* @__PURE__ */ new Set());
80
+ }
81
+ this.listeners.get(index).add(callback);
82
+ return () => {
83
+ const callbacks = this.listeners.get(index);
84
+ if (!callbacks) return;
85
+ callbacks.delete(callback);
86
+ if (callbacks.size === 0) {
87
+ this.listeners.delete(index);
88
+ }
89
+ };
90
+ }
91
+ handleChange(change) {
92
+ const callbacks = this.listeners.get(change.index);
93
+ if (!callbacks) return;
94
+ const event = {
95
+ table: change.index,
96
+ operation: change.operation,
97
+ newRow: change.newDocument,
98
+ oldRow: change.oldDocument,
99
+ timestamp: change.timestamp ?? Date.now()
100
+ };
101
+ for (const callback of callbacks) {
102
+ callback(event);
103
+ }
104
+ }
105
+ };
106
+ function removeListener(source, event, listener) {
107
+ if (source.off) {
108
+ source.off(event, listener);
109
+ return;
110
+ }
111
+ source.removeListener?.(event, listener);
112
+ }
113
+ function errorMessage(error) {
114
+ return error instanceof Error ? error.message : String(error);
115
+ }
116
+ // Annotate the CommonJS export names for ESM import in node:
117
+ 0 && (module.exports = {
118
+ OpenSearchAdapter
119
+ });
120
+ //# sourceMappingURL=opensearch.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/opensearch.ts","../../src/core/errors.ts","../../src/adapters/elasticsearch/elasticsearch-adapter.ts"],"sourcesContent":["export { ElasticsearchAdapter as OpenSearchAdapter } from './elasticsearch/elasticsearch-adapter.js'\nexport type {\n ElasticsearchAdapterOptions as OpenSearchAdapterOptions,\n ElasticsearchChangeSource as OpenSearchChangeSource,\n ElasticsearchSourceEvent as OpenSearchSourceEvent,\n} from './elasticsearch/types.js'\n","/**\n * Base error class for all RouteFlow errors.\n * Always use this instead of plain `Error` throughout the framework.\n */\nexport class ReactiveApiError extends Error {\n /** Machine-readable error code (e.g. 'ADAPTER_NOT_CONNECTED', 'INVALID_ROUTE') */\n readonly code: string\n\n constructor(code: string, message: string) {\n super(message)\n this.name = 'ReactiveApiError'\n this.code = code\n // Restore prototype chain (required when extending built-ins in TS)\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","import type { ChangeEvent, DatabaseAdapter } from '../../core/types.js'\nimport { ReactiveApiError } from '../../core/errors.js'\nimport type {\n ElasticsearchAdapterOptions,\n ElasticsearchChangeSource,\n ElasticsearchSourceEvent,\n} from './types.js'\n\n/**\n * Elasticsearch adapter for RouteFlow.\n *\n * Elasticsearch does not provide a built-in change stream, so this adapter\n * consumes an external source that emits index-level change events.\n */\nexport class ElasticsearchAdapter implements DatabaseAdapter {\n private readonly source: ElasticsearchChangeSource\n private readonly onError?: ElasticsearchAdapterOptions['onError']\n private readonly listeners: Map<string, Set<(event: ChangeEvent) => void>> = new Map()\n private readonly handleChangeBound = (change: ElasticsearchSourceEvent) => {\n this.handleChange(change)\n }\n private readonly handleErrorBound = (error: Error) => {\n this.onError?.(error)\n }\n private connected = false\n\n constructor(options: ElasticsearchAdapterOptions) {\n this.source = options.source\n this.onError = options.onError\n }\n\n async connect(): Promise<void> {\n if (this.connected) return\n\n this.source.on('change', this.handleChangeBound)\n this.source.on('error', this.handleErrorBound)\n\n try {\n await this.source.start?.()\n } catch (error) {\n throw new ReactiveApiError(\n 'ELASTICSEARCH_SOURCE_START_FAILED',\n `Failed to start Elasticsearch change source: ${errorMessage(error)}`,\n )\n }\n\n this.connected = true\n }\n\n async disconnect(): Promise<void> {\n if (!this.connected) return\n\n removeListener(this.source, 'change', this.handleChangeBound)\n removeListener(this.source, 'error', this.handleErrorBound)\n await this.source.stop?.()\n this.listeners.clear()\n this.connected = false\n }\n\n onChange(index: string, callback: (event: ChangeEvent) => void): () => void {\n if (!this.listeners.has(index)) {\n this.listeners.set(index, new Set())\n }\n\n this.listeners.get(index)!.add(callback)\n\n return () => {\n const callbacks = this.listeners.get(index)\n if (!callbacks) return\n\n callbacks.delete(callback)\n if (callbacks.size === 0) {\n this.listeners.delete(index)\n }\n }\n }\n\n private handleChange(change: ElasticsearchSourceEvent): void {\n const callbacks = this.listeners.get(change.index)\n if (!callbacks) return\n\n const event: ChangeEvent = {\n table: change.index,\n operation: change.operation,\n newRow: change.newDocument,\n oldRow: change.oldDocument,\n timestamp: change.timestamp ?? Date.now(),\n }\n\n for (const callback of callbacks) {\n callback(event)\n }\n }\n}\n\nfunction removeListener(\n source: ElasticsearchChangeSource,\n event: 'change' | 'error',\n listener: (...args: any[]) => void,\n): void {\n if (source.off) {\n source.off(event, listener)\n return\n }\n\n source.removeListener?.(event, listener)\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACIO,IAAM,mBAAN,cAA+B,MAAM;AAAA;AAAA,EAEjC;AAAA,EAET,YAAY,MAAc,SAAiB;AACzC,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAEZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;;;ACDO,IAAM,uBAAN,MAAsD;AAAA,EAC1C;AAAA,EACA;AAAA,EACA,YAA4D,oBAAI,IAAI;AAAA,EACpE,oBAAoB,CAAC,WAAqC;AACzE,SAAK,aAAa,MAAM;AAAA,EAC1B;AAAA,EACiB,mBAAmB,CAAC,UAAiB;AACpD,SAAK,UAAU,KAAK;AAAA,EACtB;AAAA,EACQ,YAAY;AAAA,EAEpB,YAAY,SAAsC;AAChD,SAAK,SAAS,QAAQ;AACtB,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA,EAEA,MAAM,UAAyB;AAC7B,QAAI,KAAK,UAAW;AAEpB,SAAK,OAAO,GAAG,UAAU,KAAK,iBAAiB;AAC/C,SAAK,OAAO,GAAG,SAAS,KAAK,gBAAgB;AAE7C,QAAI;AACF,YAAM,KAAK,OAAO,QAAQ;AAAA,IAC5B,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR;AAAA,QACA,gDAAgD,aAAa,KAAK,CAAC;AAAA,MACrE;AAAA,IACF;AAEA,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,aAA4B;AAChC,QAAI,CAAC,KAAK,UAAW;AAErB,mBAAe,KAAK,QAAQ,UAAU,KAAK,iBAAiB;AAC5D,mBAAe,KAAK,QAAQ,SAAS,KAAK,gBAAgB;AAC1D,UAAM,KAAK,OAAO,OAAO;AACzB,SAAK,UAAU,MAAM;AACrB,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,SAAS,OAAe,UAAoD;AAC1E,QAAI,CAAC,KAAK,UAAU,IAAI,KAAK,GAAG;AAC9B,WAAK,UAAU,IAAI,OAAO,oBAAI,IAAI,CAAC;AAAA,IACrC;AAEA,SAAK,UAAU,IAAI,KAAK,EAAG,IAAI,QAAQ;AAEvC,WAAO,MAAM;AACX,YAAM,YAAY,KAAK,UAAU,IAAI,KAAK;AAC1C,UAAI,CAAC,UAAW;AAEhB,gBAAU,OAAO,QAAQ;AACzB,UAAI,UAAU,SAAS,GAAG;AACxB,aAAK,UAAU,OAAO,KAAK;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAa,QAAwC;AAC3D,UAAM,YAAY,KAAK,UAAU,IAAI,OAAO,KAAK;AACjD,QAAI,CAAC,UAAW;AAEhB,UAAM,QAAqB;AAAA,MACzB,OAAO,OAAO;AAAA,MACd,WAAW,OAAO;AAAA,MAClB,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO,aAAa,KAAK,IAAI;AAAA,IAC1C;AAEA,eAAW,YAAY,WAAW;AAChC,eAAS,KAAK;AAAA,IAChB;AAAA,EACF;AACF;AAEA,SAAS,eACP,QACA,OACA,UACM;AACN,MAAI,OAAO,KAAK;AACd,WAAO,IAAI,OAAO,QAAQ;AAC1B;AAAA,EACF;AAEA,SAAO,iBAAiB,OAAO,QAAQ;AACzC;AAEA,SAAS,aAAa,OAAwB;AAC5C,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;","names":[]}
@@ -0,0 +1,2 @@
1
+ export { ElasticsearchAdapter as OpenSearchAdapter, ElasticsearchAdapterOptions as OpenSearchAdapterOptions, ElasticsearchChangeSource as OpenSearchChangeSource, ElasticsearchSourceEvent as OpenSearchSourceEvent } from './elasticsearch.cjs';
2
+ import '../types-tPDla8AE.cjs';
@@ -0,0 +1,2 @@
1
+ export { ElasticsearchAdapter as OpenSearchAdapter, ElasticsearchAdapterOptions as OpenSearchAdapterOptions, ElasticsearchChangeSource as OpenSearchChangeSource, ElasticsearchSourceEvent as OpenSearchSourceEvent } from './elasticsearch.js';
2
+ import '../types-tPDla8AE.js';
@@ -0,0 +1,93 @@
1
+ // src/core/errors.ts
2
+ var ReactiveApiError = class extends Error {
3
+ /** Machine-readable error code (e.g. 'ADAPTER_NOT_CONNECTED', 'INVALID_ROUTE') */
4
+ code;
5
+ constructor(code, message) {
6
+ super(message);
7
+ this.name = "ReactiveApiError";
8
+ this.code = code;
9
+ Object.setPrototypeOf(this, new.target.prototype);
10
+ }
11
+ };
12
+
13
+ // src/adapters/elasticsearch/elasticsearch-adapter.ts
14
+ var ElasticsearchAdapter = class {
15
+ source;
16
+ onError;
17
+ listeners = /* @__PURE__ */ new Map();
18
+ handleChangeBound = (change) => {
19
+ this.handleChange(change);
20
+ };
21
+ handleErrorBound = (error) => {
22
+ this.onError?.(error);
23
+ };
24
+ connected = false;
25
+ constructor(options) {
26
+ this.source = options.source;
27
+ this.onError = options.onError;
28
+ }
29
+ async connect() {
30
+ if (this.connected) return;
31
+ this.source.on("change", this.handleChangeBound);
32
+ this.source.on("error", this.handleErrorBound);
33
+ try {
34
+ await this.source.start?.();
35
+ } catch (error) {
36
+ throw new ReactiveApiError(
37
+ "ELASTICSEARCH_SOURCE_START_FAILED",
38
+ `Failed to start Elasticsearch change source: ${errorMessage(error)}`
39
+ );
40
+ }
41
+ this.connected = true;
42
+ }
43
+ async disconnect() {
44
+ if (!this.connected) return;
45
+ removeListener(this.source, "change", this.handleChangeBound);
46
+ removeListener(this.source, "error", this.handleErrorBound);
47
+ await this.source.stop?.();
48
+ this.listeners.clear();
49
+ this.connected = false;
50
+ }
51
+ onChange(index, callback) {
52
+ if (!this.listeners.has(index)) {
53
+ this.listeners.set(index, /* @__PURE__ */ new Set());
54
+ }
55
+ this.listeners.get(index).add(callback);
56
+ return () => {
57
+ const callbacks = this.listeners.get(index);
58
+ if (!callbacks) return;
59
+ callbacks.delete(callback);
60
+ if (callbacks.size === 0) {
61
+ this.listeners.delete(index);
62
+ }
63
+ };
64
+ }
65
+ handleChange(change) {
66
+ const callbacks = this.listeners.get(change.index);
67
+ if (!callbacks) return;
68
+ const event = {
69
+ table: change.index,
70
+ operation: change.operation,
71
+ newRow: change.newDocument,
72
+ oldRow: change.oldDocument,
73
+ timestamp: change.timestamp ?? Date.now()
74
+ };
75
+ for (const callback of callbacks) {
76
+ callback(event);
77
+ }
78
+ }
79
+ };
80
+ function removeListener(source, event, listener) {
81
+ if (source.off) {
82
+ source.off(event, listener);
83
+ return;
84
+ }
85
+ source.removeListener?.(event, listener);
86
+ }
87
+ function errorMessage(error) {
88
+ return error instanceof Error ? error.message : String(error);
89
+ }
90
+ export {
91
+ ElasticsearchAdapter as OpenSearchAdapter
92
+ };
93
+ //# sourceMappingURL=opensearch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/errors.ts","../../src/adapters/elasticsearch/elasticsearch-adapter.ts"],"sourcesContent":["/**\n * Base error class for all RouteFlow errors.\n * Always use this instead of plain `Error` throughout the framework.\n */\nexport class ReactiveApiError extends Error {\n /** Machine-readable error code (e.g. 'ADAPTER_NOT_CONNECTED', 'INVALID_ROUTE') */\n readonly code: string\n\n constructor(code: string, message: string) {\n super(message)\n this.name = 'ReactiveApiError'\n this.code = code\n // Restore prototype chain (required when extending built-ins in TS)\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","import type { ChangeEvent, DatabaseAdapter } from '../../core/types.js'\nimport { ReactiveApiError } from '../../core/errors.js'\nimport type {\n ElasticsearchAdapterOptions,\n ElasticsearchChangeSource,\n ElasticsearchSourceEvent,\n} from './types.js'\n\n/**\n * Elasticsearch adapter for RouteFlow.\n *\n * Elasticsearch does not provide a built-in change stream, so this adapter\n * consumes an external source that emits index-level change events.\n */\nexport class ElasticsearchAdapter implements DatabaseAdapter {\n private readonly source: ElasticsearchChangeSource\n private readonly onError?: ElasticsearchAdapterOptions['onError']\n private readonly listeners: Map<string, Set<(event: ChangeEvent) => void>> = new Map()\n private readonly handleChangeBound = (change: ElasticsearchSourceEvent) => {\n this.handleChange(change)\n }\n private readonly handleErrorBound = (error: Error) => {\n this.onError?.(error)\n }\n private connected = false\n\n constructor(options: ElasticsearchAdapterOptions) {\n this.source = options.source\n this.onError = options.onError\n }\n\n async connect(): Promise<void> {\n if (this.connected) return\n\n this.source.on('change', this.handleChangeBound)\n this.source.on('error', this.handleErrorBound)\n\n try {\n await this.source.start?.()\n } catch (error) {\n throw new ReactiveApiError(\n 'ELASTICSEARCH_SOURCE_START_FAILED',\n `Failed to start Elasticsearch change source: ${errorMessage(error)}`,\n )\n }\n\n this.connected = true\n }\n\n async disconnect(): Promise<void> {\n if (!this.connected) return\n\n removeListener(this.source, 'change', this.handleChangeBound)\n removeListener(this.source, 'error', this.handleErrorBound)\n await this.source.stop?.()\n this.listeners.clear()\n this.connected = false\n }\n\n onChange(index: string, callback: (event: ChangeEvent) => void): () => void {\n if (!this.listeners.has(index)) {\n this.listeners.set(index, new Set())\n }\n\n this.listeners.get(index)!.add(callback)\n\n return () => {\n const callbacks = this.listeners.get(index)\n if (!callbacks) return\n\n callbacks.delete(callback)\n if (callbacks.size === 0) {\n this.listeners.delete(index)\n }\n }\n }\n\n private handleChange(change: ElasticsearchSourceEvent): void {\n const callbacks = this.listeners.get(change.index)\n if (!callbacks) return\n\n const event: ChangeEvent = {\n table: change.index,\n operation: change.operation,\n newRow: change.newDocument,\n oldRow: change.oldDocument,\n timestamp: change.timestamp ?? Date.now(),\n }\n\n for (const callback of callbacks) {\n callback(event)\n }\n }\n}\n\nfunction removeListener(\n source: ElasticsearchChangeSource,\n event: 'change' | 'error',\n listener: (...args: any[]) => void,\n): void {\n if (source.off) {\n source.off(event, listener)\n return\n }\n\n source.removeListener?.(event, listener)\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n"],"mappings":";AAIO,IAAM,mBAAN,cAA+B,MAAM;AAAA;AAAA,EAEjC;AAAA,EAET,YAAY,MAAc,SAAiB;AACzC,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAEZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;;;ACDO,IAAM,uBAAN,MAAsD;AAAA,EAC1C;AAAA,EACA;AAAA,EACA,YAA4D,oBAAI,IAAI;AAAA,EACpE,oBAAoB,CAAC,WAAqC;AACzE,SAAK,aAAa,MAAM;AAAA,EAC1B;AAAA,EACiB,mBAAmB,CAAC,UAAiB;AACpD,SAAK,UAAU,KAAK;AAAA,EACtB;AAAA,EACQ,YAAY;AAAA,EAEpB,YAAY,SAAsC;AAChD,SAAK,SAAS,QAAQ;AACtB,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA,EAEA,MAAM,UAAyB;AAC7B,QAAI,KAAK,UAAW;AAEpB,SAAK,OAAO,GAAG,UAAU,KAAK,iBAAiB;AAC/C,SAAK,OAAO,GAAG,SAAS,KAAK,gBAAgB;AAE7C,QAAI;AACF,YAAM,KAAK,OAAO,QAAQ;AAAA,IAC5B,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR;AAAA,QACA,gDAAgD,aAAa,KAAK,CAAC;AAAA,MACrE;AAAA,IACF;AAEA,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,aAA4B;AAChC,QAAI,CAAC,KAAK,UAAW;AAErB,mBAAe,KAAK,QAAQ,UAAU,KAAK,iBAAiB;AAC5D,mBAAe,KAAK,QAAQ,SAAS,KAAK,gBAAgB;AAC1D,UAAM,KAAK,OAAO,OAAO;AACzB,SAAK,UAAU,MAAM;AACrB,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,SAAS,OAAe,UAAoD;AAC1E,QAAI,CAAC,KAAK,UAAU,IAAI,KAAK,GAAG;AAC9B,WAAK,UAAU,IAAI,OAAO,oBAAI,IAAI,CAAC;AAAA,IACrC;AAEA,SAAK,UAAU,IAAI,KAAK,EAAG,IAAI,QAAQ;AAEvC,WAAO,MAAM;AACX,YAAM,YAAY,KAAK,UAAU,IAAI,KAAK;AAC1C,UAAI,CAAC,UAAW;AAEhB,gBAAU,OAAO,QAAQ;AACzB,UAAI,UAAU,SAAS,GAAG;AACxB,aAAK,UAAU,OAAO,KAAK;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAa,QAAwC;AAC3D,UAAM,YAAY,KAAK,UAAU,IAAI,OAAO,KAAK;AACjD,QAAI,CAAC,UAAW;AAEhB,UAAM,QAAqB;AAAA,MACzB,OAAO,OAAO;AAAA,MACd,WAAW,OAAO;AAAA,MAClB,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO,aAAa,KAAK,IAAI;AAAA,IAC1C;AAEA,eAAW,YAAY,WAAW;AAChC,eAAS,KAAK;AAAA,IAChB;AAAA,EACF;AACF;AAEA,SAAS,eACP,QACA,OACA,UACM;AACN,MAAI,OAAO,KAAK;AACd,WAAO,IAAI,OAAO,QAAQ;AAC1B;AAAA,EACF;AAEA,SAAO,iBAAiB,OAAO,QAAQ;AACzC;AAEA,SAAS,aAAa,OAAwB;AAC5C,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;","names":[]}