@iskra-bun/db-oracle 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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @iskra-bun/db-oracle
2
+
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Initial public release.
package/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # @iskra-bun/db-oracle
2
+
3
+ Soporte para Oracle Database en Iskra a traves de un puente/sidecar (IPC). Permite ejecutar consultas contra Oracle desde una app Iskra sin acoplar el cliente nativo al proceso principal.
4
+
5
+ ## Instalacion
6
+
7
+ ```bash
8
+ bun add @iskra-bun/db-oracle @iskra-bun/core
9
+ ```
10
+
11
+ ## Uso rapido
12
+
13
+ ```typescript
14
+ import { App } from '@iskra-bun/core'
15
+ import { OracleDriver } from '@iskra-bun/db-oracle'
16
+
17
+ const app = new App({ name: 'mi-app' })
18
+ app.register(new OracleDriver({ /* config del puente */ }))
19
+
20
+ await app.start()
21
+ ```
22
+
23
+ ## Estado
24
+
25
+ Implementacion via puente/sidecar (protocolo request/response sobre un proceso Node). No incluye aun pooling de conexiones ni recuperacion avanzada de errores; ver la guia para los detalles del bridge.
26
+
27
+ ## Documentacion
28
+
29
+ Guia completa: [docs/db-kit.md](../../docs/db-kit.md)
30
+
31
+ ## Licencia
32
+
33
+ AGPL-3.0-or-later
@@ -0,0 +1,17 @@
1
+ import { Driver, App } from '@iskra-bun/core';
2
+
3
+ declare class OracleDriver implements Driver {
4
+ name: string;
5
+ private proc;
6
+ private reqId;
7
+ private pending;
8
+ private bridgePath;
9
+ constructor(bridgePath?: string);
10
+ init(app: App): Promise<void>;
11
+ start(app?: App): Promise<void>;
12
+ stop(): Promise<void>;
13
+ query(sql: string, params?: any[]): Promise<unknown>;
14
+ private readStream;
15
+ }
16
+
17
+ export { OracleDriver };
package/dist/index.js ADDED
@@ -0,0 +1,99 @@
1
+ // src/driver.ts
2
+ import { spawn } from "bun";
3
+ import { resolve } from "path";
4
+ var OracleDriver = class {
5
+ name = "db";
6
+ // Replaces standard db driver if used, or can be 'oracle'
7
+ proc = null;
8
+ reqId = 0;
9
+ pending = /* @__PURE__ */ new Map();
10
+ bridgePath;
11
+ constructor(bridgePath) {
12
+ this.bridgePath = bridgePath || resolve(import.meta.dir, "../bridge/runner.js");
13
+ }
14
+ async init(app) {
15
+ app.context.set("oracle", this);
16
+ }
17
+ async start(app) {
18
+ if (!process.env.ORA_CONN) {
19
+ console.warn("Oracle connection string (ORA_CONN) not set. Oracle driver will not start.");
20
+ return;
21
+ }
22
+ this.proc = spawn(["node", this.bridgePath], {
23
+ stdin: "pipe",
24
+ stdout: "pipe",
25
+ env: { ...process.env }
26
+ });
27
+ if (!this.proc.stdout) {
28
+ throw new Error("Failed to spawn Oracle bridge process (no stdout)");
29
+ }
30
+ this.readStream(this.proc.stdout);
31
+ }
32
+ async stop() {
33
+ if (this.proc) {
34
+ this.proc.kill();
35
+ this.proc = null;
36
+ }
37
+ }
38
+ async query(sql, params = []) {
39
+ if (!this.proc || !this.proc.stdin) {
40
+ throw new Error("Oracle driver not started");
41
+ }
42
+ const id = this.reqId++;
43
+ return new Promise((resolve2, reject) => {
44
+ this.pending.set(id, { resolve: resolve2, reject });
45
+ const msg = JSON.stringify({ id, sql, params }) + "\n";
46
+ const stdin = this.proc.stdin;
47
+ if (stdin.write) {
48
+ stdin.write(msg);
49
+ stdin.flush();
50
+ }
51
+ });
52
+ }
53
+ async readStream(stream) {
54
+ const reader = stream.getReader();
55
+ const decoder = new TextDecoder();
56
+ let buffer = "";
57
+ try {
58
+ while (true) {
59
+ const { done, value } = await reader.read();
60
+ if (done) break;
61
+ buffer += decoder.decode(value, { stream: true });
62
+ const lines = buffer.split("\n");
63
+ buffer = lines.pop() || "";
64
+ for (const line of lines) {
65
+ if (!line.trim()) continue;
66
+ try {
67
+ const msg = JSON.parse(line);
68
+ if (msg.type === "ready") {
69
+ continue;
70
+ }
71
+ if (msg.type === "fatal") {
72
+ console.error("Oracle Bridge Fatal Error:", msg.error);
73
+ continue;
74
+ }
75
+ if (msg.id !== void 0 && this.pending.has(msg.id)) {
76
+ const { resolve: resolve2, reject } = this.pending.get(msg.id);
77
+ this.pending.delete(msg.id);
78
+ if (msg.error) {
79
+ reject(new Error(msg.error));
80
+ } else {
81
+ resolve2(msg.data);
82
+ }
83
+ }
84
+ } catch (err) {
85
+ console.error("Error parsing bridge message:", err, line);
86
+ }
87
+ }
88
+ }
89
+ } catch (err) {
90
+ console.error("Error reading from Oracle bridge:", err);
91
+ } finally {
92
+ reader.releaseLock();
93
+ }
94
+ }
95
+ };
96
+ export {
97
+ OracleDriver
98
+ };
99
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/driver.ts"],"sourcesContent":["import type { Driver, App } from '@iskra-bun/core';\nimport { spawn, type Subprocess } from 'bun';\nimport { resolve } from 'path';\n\nexport class OracleDriver implements Driver {\n name = 'db'; // Replaces standard db driver if used, or can be 'oracle'\n private proc: Subprocess | null = null;\n private reqId = 0;\n private pending = new Map<number, { resolve: (val: any) => void, reject: (err: any) => void }>();\n private bridgePath: string;\n\n constructor(bridgePath?: string) {\n // Allow overriding path for flexibility (absolute path)\n // Defaults to calculating relative to this file in a built package structure\n // Adjust logic if needed based on where this file ends up (dist vs src)\n // For dev (src), it's ../bridge/runner.js\n this.bridgePath = bridgePath || resolve(import.meta.dir, '../bridge/runner.js');\n }\n\n async init(app: App) {\n // If we want to replace the main 'db' object or sit alongside it\n app.context.set('oracle', this);\n }\n\n async start(app?: App) { // app optional to satisfy interface but we might need config from it\n // Check env vars\n if (!process.env.ORA_CONN) {\n console.warn('Oracle connection string (ORA_CONN) not set. Oracle driver will not start.');\n return;\n }\n\n this.proc = spawn(['node', this.bridgePath], {\n stdin: 'pipe',\n stdout: 'pipe',\n env: { ...process.env },\n });\n\n if (!this.proc.stdout) {\n throw new Error('Failed to spawn Oracle bridge process (no stdout)');\n }\n\n this.readStream(this.proc.stdout as ReadableStream);\n\n // Wait for ready signal?\n // For now we assume optimistic start or we could wait for 'ready' message\n }\n\n async stop() {\n if (this.proc) {\n this.proc.kill();\n this.proc = null;\n }\n }\n\n async query(sql: string, params: any[] = []) {\n if (!this.proc || !this.proc.stdin) {\n throw new Error('Oracle driver not started');\n }\n\n const id = this.reqId++;\n\n return new Promise((resolve, reject) => {\n this.pending.set(id, { resolve, reject });\n\n const msg = JSON.stringify({ id, sql, params }) + '\\n';\n const stdin = this.proc!.stdin as any; // Bun FileSink/writer\n if (stdin.write) {\n stdin.write(msg);\n stdin.flush();\n }\n });\n }\n\n private async readStream(stream: ReadableStream) {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || ''; // Keep incomplete line\n\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const msg = JSON.parse(line);\n\n if (msg.type === 'ready') {\n // console.log('Oracle Bridge Ready');\n continue;\n }\n if (msg.type === 'fatal') {\n console.error('Oracle Bridge Fatal Error:', msg.error);\n // Reject all pending?\n continue;\n }\n\n if (msg.id !== undefined && this.pending.has(msg.id)) {\n const { resolve, reject } = this.pending.get(msg.id)!;\n this.pending.delete(msg.id);\n\n if (msg.error) {\n reject(new Error(msg.error));\n } else {\n resolve(msg.data);\n }\n }\n } catch (err) {\n console.error('Error parsing bridge message:', err, line);\n }\n }\n }\n } catch (err) {\n console.error('Error reading from Oracle bridge:', err);\n } finally {\n reader.releaseLock();\n }\n }\n}\n"],"mappings":";AACA,SAAS,aAA8B;AACvC,SAAS,eAAe;AAEjB,IAAM,eAAN,MAAqC;AAAA,EACxC,OAAO;AAAA;AAAA,EACC,OAA0B;AAAA,EAC1B,QAAQ;AAAA,EACR,UAAU,oBAAI,IAAyE;AAAA,EACvF;AAAA,EAER,YAAY,YAAqB;AAK7B,SAAK,aAAa,cAAc,QAAQ,YAAY,KAAK,qBAAqB;AAAA,EAClF;AAAA,EAEA,MAAM,KAAK,KAAU;AAEjB,QAAI,QAAQ,IAAI,UAAU,IAAI;AAAA,EAClC;AAAA,EAEA,MAAM,MAAM,KAAW;AAEnB,QAAI,CAAC,QAAQ,IAAI,UAAU;AACvB,cAAQ,KAAK,4EAA4E;AACzF;AAAA,IACJ;AAEA,SAAK,OAAO,MAAM,CAAC,QAAQ,KAAK,UAAU,GAAG;AAAA,MACzC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,IAC1B,CAAC;AAED,QAAI,CAAC,KAAK,KAAK,QAAQ;AACnB,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACvE;AAEA,SAAK,WAAW,KAAK,KAAK,MAAwB;AAAA,EAItD;AAAA,EAEA,MAAM,OAAO;AACT,QAAI,KAAK,MAAM;AACX,WAAK,KAAK,KAAK;AACf,WAAK,OAAO;AAAA,IAChB;AAAA,EACJ;AAAA,EAEA,MAAM,MAAM,KAAa,SAAgB,CAAC,GAAG;AACzC,QAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,KAAK,OAAO;AAChC,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC/C;AAEA,UAAM,KAAK,KAAK;AAEhB,WAAO,IAAI,QAAQ,CAACA,UAAS,WAAW;AACpC,WAAK,QAAQ,IAAI,IAAI,EAAE,SAAAA,UAAS,OAAO,CAAC;AAExC,YAAM,MAAM,KAAK,UAAU,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI;AAClD,YAAM,QAAQ,KAAK,KAAM;AACzB,UAAI,MAAM,OAAO;AACb,cAAM,MAAM,GAAG;AACf,cAAM,MAAM;AAAA,MAChB;AAAA,IACJ,CAAC;AAAA,EACL;AAAA,EAEA,MAAc,WAAW,QAAwB;AAC7C,UAAM,SAAS,OAAO,UAAU;AAChC,UAAM,UAAU,IAAI,YAAY;AAChC,QAAI,SAAS;AAEb,QAAI;AACA,aAAO,MAAM;AACT,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AAEV,kBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,cAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,iBAAS,MAAM,IAAI,KAAK;AAExB,mBAAW,QAAQ,OAAO;AACtB,cAAI,CAAC,KAAK,KAAK,EAAG;AAClB,cAAI;AACA,kBAAM,MAAM,KAAK,MAAM,IAAI;AAE3B,gBAAI,IAAI,SAAS,SAAS;AAEtB;AAAA,YACJ;AACA,gBAAI,IAAI,SAAS,SAAS;AACtB,sBAAQ,MAAM,8BAA8B,IAAI,KAAK;AAErD;AAAA,YACJ;AAEA,gBAAI,IAAI,OAAO,UAAa,KAAK,QAAQ,IAAI,IAAI,EAAE,GAAG;AAClD,oBAAM,EAAE,SAAAA,UAAS,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,EAAE;AACnD,mBAAK,QAAQ,OAAO,IAAI,EAAE;AAE1B,kBAAI,IAAI,OAAO;AACX,uBAAO,IAAI,MAAM,IAAI,KAAK,CAAC;AAAA,cAC/B,OAAO;AACH,gBAAAA,SAAQ,IAAI,IAAI;AAAA,cACpB;AAAA,YACJ;AAAA,UACJ,SAAS,KAAK;AACV,oBAAQ,MAAM,iCAAiC,KAAK,IAAI;AAAA,UAC5D;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ,SAAS,KAAK;AACV,cAAQ,MAAM,qCAAqC,GAAG;AAAA,IAC1D,UAAE;AACE,aAAO,YAAY;AAAA,IACvB;AAAA,EACJ;AACJ;","names":["resolve"]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@iskra-bun/db-oracle",
3
+ "version": "0.1.0",
4
+ "description": "Soporte para Oracle Database en Iskra (via puente/sidecar).",
5
+ "keywords": [
6
+ "iskra",
7
+ "bun",
8
+ "typescript",
9
+ "oracle",
10
+ "database",
11
+ "sql",
12
+ "experimental"
13
+ ],
14
+ "author": "Joan Lascano",
15
+ "license": "AGPL-3.0-or-later",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/fearful/iskra.git",
19
+ "directory": "packages/db-oracle"
20
+ },
21
+ "homepage": "https://github.com/fearful/iskra/tree/main/packages/db-oracle#readme",
22
+ "bugs": "https://github.com/fearful/iskra/issues",
23
+ "type": "module",
24
+ "main": "./dist/index.js",
25
+ "module": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "source": "./src/index.ts",
30
+ "bun": "./src/index.ts",
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js",
33
+ "default": "./dist/index.js"
34
+ }
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "src",
39
+ "README.md",
40
+ "CHANGELOG.md"
41
+ ],
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "scripts": {
46
+ "test": "bun test",
47
+ "build": "tsup --config ../../tsup.config.ts"
48
+ },
49
+ "dependencies": {
50
+ "@iskra-bun/core": "0.1.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^22.10.2",
54
+ "bun-types": "latest"
55
+ }
56
+ }
package/src/driver.ts ADDED
@@ -0,0 +1,124 @@
1
+ import type { Driver, App } from '@iskra-bun/core';
2
+ import { spawn, type Subprocess } from 'bun';
3
+ import { resolve } from 'path';
4
+
5
+ export class OracleDriver implements Driver {
6
+ name = 'db'; // Replaces standard db driver if used, or can be 'oracle'
7
+ private proc: Subprocess | null = null;
8
+ private reqId = 0;
9
+ private pending = new Map<number, { resolve: (val: any) => void, reject: (err: any) => void }>();
10
+ private bridgePath: string;
11
+
12
+ constructor(bridgePath?: string) {
13
+ // Allow overriding path for flexibility (absolute path)
14
+ // Defaults to calculating relative to this file in a built package structure
15
+ // Adjust logic if needed based on where this file ends up (dist vs src)
16
+ // For dev (src), it's ../bridge/runner.js
17
+ this.bridgePath = bridgePath || resolve(import.meta.dir, '../bridge/runner.js');
18
+ }
19
+
20
+ async init(app: App) {
21
+ // If we want to replace the main 'db' object or sit alongside it
22
+ app.context.set('oracle', this);
23
+ }
24
+
25
+ async start(app?: App) { // app optional to satisfy interface but we might need config from it
26
+ // Check env vars
27
+ if (!process.env.ORA_CONN) {
28
+ console.warn('Oracle connection string (ORA_CONN) not set. Oracle driver will not start.');
29
+ return;
30
+ }
31
+
32
+ this.proc = spawn(['node', this.bridgePath], {
33
+ stdin: 'pipe',
34
+ stdout: 'pipe',
35
+ env: { ...process.env },
36
+ });
37
+
38
+ if (!this.proc.stdout) {
39
+ throw new Error('Failed to spawn Oracle bridge process (no stdout)');
40
+ }
41
+
42
+ this.readStream(this.proc.stdout as ReadableStream);
43
+
44
+ // Wait for ready signal?
45
+ // For now we assume optimistic start or we could wait for 'ready' message
46
+ }
47
+
48
+ async stop() {
49
+ if (this.proc) {
50
+ this.proc.kill();
51
+ this.proc = null;
52
+ }
53
+ }
54
+
55
+ async query(sql: string, params: any[] = []) {
56
+ if (!this.proc || !this.proc.stdin) {
57
+ throw new Error('Oracle driver not started');
58
+ }
59
+
60
+ const id = this.reqId++;
61
+
62
+ return new Promise((resolve, reject) => {
63
+ this.pending.set(id, { resolve, reject });
64
+
65
+ const msg = JSON.stringify({ id, sql, params }) + '\n';
66
+ const stdin = this.proc!.stdin as any; // Bun FileSink/writer
67
+ if (stdin.write) {
68
+ stdin.write(msg);
69
+ stdin.flush();
70
+ }
71
+ });
72
+ }
73
+
74
+ private async readStream(stream: ReadableStream) {
75
+ const reader = stream.getReader();
76
+ const decoder = new TextDecoder();
77
+ let buffer = '';
78
+
79
+ try {
80
+ while (true) {
81
+ const { done, value } = await reader.read();
82
+ if (done) break;
83
+
84
+ buffer += decoder.decode(value, { stream: true });
85
+ const lines = buffer.split('\n');
86
+ buffer = lines.pop() || ''; // Keep incomplete line
87
+
88
+ for (const line of lines) {
89
+ if (!line.trim()) continue;
90
+ try {
91
+ const msg = JSON.parse(line);
92
+
93
+ if (msg.type === 'ready') {
94
+ // console.log('Oracle Bridge Ready');
95
+ continue;
96
+ }
97
+ if (msg.type === 'fatal') {
98
+ console.error('Oracle Bridge Fatal Error:', msg.error);
99
+ // Reject all pending?
100
+ continue;
101
+ }
102
+
103
+ if (msg.id !== undefined && this.pending.has(msg.id)) {
104
+ const { resolve, reject } = this.pending.get(msg.id)!;
105
+ this.pending.delete(msg.id);
106
+
107
+ if (msg.error) {
108
+ reject(new Error(msg.error));
109
+ } else {
110
+ resolve(msg.data);
111
+ }
112
+ }
113
+ } catch (err) {
114
+ console.error('Error parsing bridge message:', err, line);
115
+ }
116
+ }
117
+ }
118
+ } catch (err) {
119
+ console.error('Error reading from Oracle bridge:', err);
120
+ } finally {
121
+ reader.releaseLock();
122
+ }
123
+ }
124
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './driver';