@bestoneconsulting/sap-b1-bridge 1.1.0 → 1.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.
package/README.md CHANGED
@@ -335,6 +335,126 @@ const bridge = await createSAPB1Bridge(options, new MyDatabaseStorage());
335
335
 
336
336
  See the full [`IBridgeStorage` interface](https://github.com/bestoneconsulting/sap-b1-bridge/blob/main/bridge/storage.ts) for method signatures and return types.
337
337
 
338
+ ### Built-in PostgreSQL Storage (Drizzle ORM)
339
+
340
+ The package includes a ready-to-use PostgreSQL storage adapter built on [Drizzle ORM](https://orm.drizzle.team/). This gives you persistent storage without writing any database code.
341
+
342
+ **1. Install Drizzle dependencies:**
343
+
344
+ ```bash
345
+ npm install drizzle-orm @neondatabase/serverless drizzle-kit
346
+ ```
347
+
348
+ Or if you use a standard PostgreSQL server (not Neon):
349
+
350
+ ```bash
351
+ npm install drizzle-orm pg drizzle-kit
352
+ npm install -D @types/pg
353
+ ```
354
+
355
+ **2. Set up the database connection and push the schema:**
356
+
357
+ Create a `drizzle.config.ts` in your project root:
358
+
359
+ ```typescript
360
+ import { defineConfig } from "drizzle-kit";
361
+
362
+ export default defineConfig({
363
+ out: "./drizzle",
364
+ schema: "./src/db/schema.ts",
365
+ dialect: "postgresql",
366
+ dbCredentials: {
367
+ url: process.env.DATABASE_URL!,
368
+ },
369
+ });
370
+ ```
371
+
372
+ Create `src/db/schema.ts` that re-exports the bridge schema (and any of your own tables):
373
+
374
+ ```typescript
375
+ export { bridgeCompanies, bridgeAgents, bridgeQueries } from "@bestoneconsulting/sap-b1-bridge";
376
+
377
+ // Add your own application tables here if needed
378
+ ```
379
+
380
+ Push the schema to your database:
381
+
382
+ ```bash
383
+ npx drizzle-kit push
384
+ ```
385
+
386
+ This creates three tables: `bridge_companies`, `bridge_agents`, and `bridge_queries`. The `bridge_` prefix avoids conflicts with your own application tables.
387
+
388
+ **3. Create the Drizzle client and pass it to the bridge:**
389
+
390
+ For Neon serverless PostgreSQL:
391
+
392
+ ```typescript
393
+ import express from "express";
394
+ import { createServer } from "http";
395
+ import { neon } from "@neondatabase/serverless";
396
+ import { drizzle } from "drizzle-orm/neon-http";
397
+ import { createSAPB1Bridge, createDrizzleBridgeStorage } from "@bestoneconsulting/sap-b1-bridge";
398
+
399
+ const sql = neon(process.env.DATABASE_URL!);
400
+ const db = drizzle(sql);
401
+
402
+ const app = express();
403
+ app.use(express.json());
404
+ const server = createServer(app);
405
+
406
+ const storage = createDrizzleBridgeStorage(db);
407
+
408
+ const bridge = await createSAPB1Bridge(
409
+ { app, server, appName: "My SAP App" },
410
+ storage
411
+ );
412
+
413
+ bridge.mountUI("/bridge");
414
+ server.listen(3000);
415
+ ```
416
+
417
+ For standard PostgreSQL (using `pg`):
418
+
419
+ ```typescript
420
+ import express from "express";
421
+ import { createServer } from "http";
422
+ import { Pool } from "pg";
423
+ import { drizzle } from "drizzle-orm/node-postgres";
424
+ import { createSAPB1Bridge, createDrizzleBridgeStorage } from "@bestoneconsulting/sap-b1-bridge";
425
+
426
+ const pool = new Pool({ connectionString: process.env.DATABASE_URL });
427
+ const db = drizzle(pool);
428
+
429
+ const app = express();
430
+ app.use(express.json());
431
+ const server = createServer(app);
432
+
433
+ const storage = createDrizzleBridgeStorage(db);
434
+
435
+ const bridge = await createSAPB1Bridge(
436
+ { app, server, appName: "My SAP App" },
437
+ storage
438
+ );
439
+
440
+ bridge.mountUI("/bridge");
441
+ server.listen(3000);
442
+ ```
443
+
444
+ **Schema details:**
445
+
446
+ | Table | Purpose |
447
+ |-------|---------|
448
+ | `bridge_companies` | Organization grouping for agents |
449
+ | `bridge_agents` | Registered agents with API keys and connection status |
450
+ | `bridge_queries` | Query history with status, results, and execution metrics |
451
+
452
+ The Drizzle schema objects are exported for advanced use cases (custom queries, migrations, extending):
453
+
454
+ ```typescript
455
+ import { bridgeCompanies, bridgeAgents, bridgeQueries } from "@bestoneconsulting/sap-b1-bridge";
456
+ ```
457
+
338
458
  ## Configuration Options
339
459
 
340
460
  | Option | Type | Default | Description |
@@ -0,0 +1,2 @@
1
+ import type { IBridgeStorage } from "./storage";
2
+ export declare function createAppBridgeStorage(dbStorage: any): IBridgeStorage;
@@ -0,0 +1,61 @@
1
+ export function createAppBridgeStorage(dbStorage) {
2
+ return {
3
+ async getCompanies() {
4
+ return dbStorage.getCompanies();
5
+ },
6
+ async getCompany(id) {
7
+ return dbStorage.getCompany(id);
8
+ },
9
+ async createCompany(name, description) {
10
+ return dbStorage.createCompany({ name, description });
11
+ },
12
+ async updateCompany(id, updates) {
13
+ return dbStorage.updateCompany(id, updates);
14
+ },
15
+ async deleteCompany(id) {
16
+ return dbStorage.deleteCompany(id);
17
+ },
18
+ async getAgents() {
19
+ return dbStorage.getAgents();
20
+ },
21
+ async getAgent(id) {
22
+ return dbStorage.getAgent(id);
23
+ },
24
+ async getAgentByApiKey(apiKey) {
25
+ return dbStorage.getAgentByApiKey(apiKey);
26
+ },
27
+ async createAgent(data) {
28
+ return dbStorage.createAgent(data);
29
+ },
30
+ async updateAgent(id, updates) {
31
+ return dbStorage.updateAgent(id, updates);
32
+ },
33
+ async updateAgentStatus(id, status, lastHeartbeat) {
34
+ return dbStorage.updateAgentStatus(id, status, lastHeartbeat);
35
+ },
36
+ async deleteAgent(id) {
37
+ return dbStorage.deleteAgent(id);
38
+ },
39
+ async getQueries() {
40
+ return dbStorage.getQueries();
41
+ },
42
+ async getQuery(id) {
43
+ return dbStorage.getQuery(id);
44
+ },
45
+ async getRecentQueries(limit) {
46
+ return dbStorage.getRecentQueries(limit);
47
+ },
48
+ async getPendingQueriesForAgent(agentId) {
49
+ return dbStorage.getPendingQueriesForAgent(agentId);
50
+ },
51
+ async getActiveQuery() {
52
+ return dbStorage.getActiveQuery();
53
+ },
54
+ async createQuery(data) {
55
+ return dbStorage.createQuery(data);
56
+ },
57
+ async updateQueryStatus(id, status, updates) {
58
+ return dbStorage.updateQueryStatus(id, status, updates);
59
+ },
60
+ };
61
+ }
@@ -1,2 +1,6 @@
1
+ import type { NodePgDatabase } from "drizzle-orm/node-postgres";
2
+ import type { NeonHttpDatabase } from "drizzle-orm/neon-http";
1
3
  import type { IBridgeStorage } from "./storage";
2
- export declare function createDrizzleBridgeStorage(dbStorage: any): IBridgeStorage;
4
+ type DrizzleDB = NodePgDatabase<any> | NeonHttpDatabase<any>;
5
+ export declare function createDrizzleBridgeStorage(db: DrizzleDB): IBridgeStorage;
6
+ export {};
@@ -1,61 +1,89 @@
1
- export function createDrizzleBridgeStorage(dbStorage) {
1
+ import { eq, desc, and, asc } from "drizzle-orm";
2
+ import { randomUUID } from "crypto";
3
+ import { bridgeCompanies, bridgeAgents, bridgeQueries } from "./schema";
4
+ export function createDrizzleBridgeStorage(db) {
2
5
  return {
3
6
  async getCompanies() {
4
- return dbStorage.getCompanies();
7
+ return db.select().from(bridgeCompanies);
5
8
  },
6
9
  async getCompany(id) {
7
- return dbStorage.getCompany(id);
10
+ const rows = await db.select().from(bridgeCompanies).where(eq(bridgeCompanies.id, id));
11
+ return rows[0];
8
12
  },
9
13
  async createCompany(name, description) {
10
- return dbStorage.createCompany({ name, description });
14
+ const rows = await db.insert(bridgeCompanies).values({ name, description }).returning();
15
+ return rows[0];
11
16
  },
12
17
  async updateCompany(id, updates) {
13
- return dbStorage.updateCompany(id, updates);
18
+ await db.update(bridgeCompanies).set(updates).where(eq(bridgeCompanies.id, id));
14
19
  },
15
20
  async deleteCompany(id) {
16
- return dbStorage.deleteCompany(id);
21
+ await db.delete(bridgeCompanies).where(eq(bridgeCompanies.id, id));
17
22
  },
18
23
  async getAgents() {
19
- return dbStorage.getAgents();
24
+ return db.select().from(bridgeAgents);
20
25
  },
21
26
  async getAgent(id) {
22
- return dbStorage.getAgent(id);
27
+ const rows = await db.select().from(bridgeAgents).where(eq(bridgeAgents.id, id));
28
+ return rows[0];
23
29
  },
24
30
  async getAgentByApiKey(apiKey) {
25
- return dbStorage.getAgentByApiKey(apiKey);
31
+ const rows = await db.select().from(bridgeAgents).where(eq(bridgeAgents.apiKey, apiKey));
32
+ return rows[0];
26
33
  },
27
34
  async createAgent(data) {
28
- return dbStorage.createAgent(data);
35
+ const apiKey = `agent_${randomUUID().replace(/-/g, "")}`;
36
+ const rows = await db.insert(bridgeAgents).values({
37
+ name: data.name,
38
+ serverName: data.serverName,
39
+ capabilities: data.capabilities || ["sql_server"],
40
+ companyId: data.companyId || null,
41
+ apiKey,
42
+ status: "offline",
43
+ }).returning();
44
+ return rows[0];
29
45
  },
30
46
  async updateAgent(id, updates) {
31
- return dbStorage.updateAgent(id, updates);
47
+ await db.update(bridgeAgents).set(updates).where(eq(bridgeAgents.id, id));
32
48
  },
33
49
  async updateAgentStatus(id, status, lastHeartbeat) {
34
- return dbStorage.updateAgentStatus(id, status, lastHeartbeat);
50
+ await db.update(bridgeAgents).set({ status, lastHeartbeat }).where(eq(bridgeAgents.id, id));
35
51
  },
36
52
  async deleteAgent(id) {
37
- return dbStorage.deleteAgent(id);
53
+ await db.delete(bridgeQueries).where(eq(bridgeQueries.agentId, id));
54
+ await db.delete(bridgeAgents).where(eq(bridgeAgents.id, id));
38
55
  },
39
56
  async getQueries() {
40
- return dbStorage.getQueries();
57
+ return db.select().from(bridgeQueries).orderBy(desc(bridgeQueries.submittedAt));
41
58
  },
42
59
  async getQuery(id) {
43
- return dbStorage.getQuery(id);
60
+ const rows = await db.select().from(bridgeQueries).where(eq(bridgeQueries.id, id));
61
+ return rows[0];
44
62
  },
45
63
  async getRecentQueries(limit) {
46
- return dbStorage.getRecentQueries(limit);
64
+ return db.select().from(bridgeQueries).orderBy(desc(bridgeQueries.submittedAt)).limit(limit);
47
65
  },
48
66
  async getPendingQueriesForAgent(agentId) {
49
- return dbStorage.getPendingQueriesForAgent(agentId);
67
+ return db.select().from(bridgeQueries)
68
+ .where(and(eq(bridgeQueries.agentId, agentId), eq(bridgeQueries.status, "pending")))
69
+ .orderBy(asc(bridgeQueries.submittedAt));
50
70
  },
51
71
  async getActiveQuery() {
52
- return dbStorage.getActiveQuery();
72
+ const rows = await db.select().from(bridgeQueries).orderBy(desc(bridgeQueries.submittedAt)).limit(1);
73
+ return rows[0] || null;
53
74
  },
54
75
  async createQuery(data) {
55
- return dbStorage.createQuery(data);
76
+ const rows = await db.insert(bridgeQueries).values({
77
+ agentId: data.agentId || null,
78
+ targetType: data.targetType || "sql_server",
79
+ sqlQuery: data.sqlQuery,
80
+ requestPayload: data.requestPayload || null,
81
+ status: "pending",
82
+ }).returning();
83
+ return rows[0];
56
84
  },
57
85
  async updateQueryStatus(id, status, updates) {
58
- return dbStorage.updateQueryStatus(id, status, updates);
86
+ await db.update(bridgeQueries).set({ status, ...updates }).where(eq(bridgeQueries.id, id));
59
87
  },
60
88
  };
61
89
  }
package/dist/index.d.ts CHANGED
@@ -3,5 +3,7 @@ import { type IBridgeStorage } from "./storage";
3
3
  export declare function createSAPB1Bridge(options: SAPB1BridgeOptions, storage?: IBridgeStorage): Promise<SAPB1BridgeAPI>;
4
4
  export { SAPB1Bridge } from "./core";
5
5
  export { MemBridgeStorage } from "./storage";
6
- export type { IBridgeStorage } from "./storage";
6
+ export { createDrizzleBridgeStorage } from "./drizzle-storage";
7
+ export { bridgeCompanies, bridgeAgents, bridgeQueries } from "./schema";
8
+ export type { IBridgeStorage, BridgeQuery } from "./storage";
7
9
  export type { SAPB1BridgeOptions, SAPB1BridgeAPI, AgentInfo, QueryResult, ServiceLayerRequest, DiApiRequest, CapabilityStatus, AgentCapabilities, CompanyInfo, RegisterAgentOptions, } from "./types";
package/dist/index.js CHANGED
@@ -4,3 +4,5 @@ export async function createSAPB1Bridge(options, storage) {
4
4
  }
5
5
  export { SAPB1Bridge } from "./core";
6
6
  export { MemBridgeStorage } from "./storage";
7
+ export { createDrizzleBridgeStorage } from "./drizzle-storage";
8
+ export { bridgeCompanies, bridgeAgents, bridgeQueries } from "./schema";
@@ -0,0 +1,499 @@
1
+ export declare const bridgeCompanies: import("drizzle-orm/pg-core").PgTableWithColumns<{
2
+ name: "bridge_companies";
3
+ schema: undefined;
4
+ columns: {
5
+ id: import("drizzle-orm/pg-core").PgColumn<{
6
+ name: "id";
7
+ tableName: "bridge_companies";
8
+ dataType: "string";
9
+ columnType: "PgVarchar";
10
+ data: string;
11
+ driverParam: string;
12
+ notNull: true;
13
+ hasDefault: true;
14
+ isPrimaryKey: true;
15
+ isAutoincrement: false;
16
+ hasRuntimeDefault: false;
17
+ enumValues: [string, ...string[]];
18
+ baseColumn: never;
19
+ identity: undefined;
20
+ generated: undefined;
21
+ }, {}, {
22
+ length: number | undefined;
23
+ }>;
24
+ name: import("drizzle-orm/pg-core").PgColumn<{
25
+ name: "name";
26
+ tableName: "bridge_companies";
27
+ dataType: "string";
28
+ columnType: "PgText";
29
+ data: string;
30
+ driverParam: string;
31
+ notNull: true;
32
+ hasDefault: false;
33
+ isPrimaryKey: false;
34
+ isAutoincrement: false;
35
+ hasRuntimeDefault: false;
36
+ enumValues: [string, ...string[]];
37
+ baseColumn: never;
38
+ identity: undefined;
39
+ generated: undefined;
40
+ }, {}, {}>;
41
+ description: import("drizzle-orm/pg-core").PgColumn<{
42
+ name: "description";
43
+ tableName: "bridge_companies";
44
+ dataType: "string";
45
+ columnType: "PgText";
46
+ data: string;
47
+ driverParam: string;
48
+ notNull: false;
49
+ hasDefault: false;
50
+ isPrimaryKey: false;
51
+ isAutoincrement: false;
52
+ hasRuntimeDefault: false;
53
+ enumValues: [string, ...string[]];
54
+ baseColumn: never;
55
+ identity: undefined;
56
+ generated: undefined;
57
+ }, {}, {}>;
58
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
59
+ name: "created_at";
60
+ tableName: "bridge_companies";
61
+ dataType: "date";
62
+ columnType: "PgTimestamp";
63
+ data: Date;
64
+ driverParam: string;
65
+ notNull: false;
66
+ hasDefault: true;
67
+ isPrimaryKey: false;
68
+ isAutoincrement: false;
69
+ hasRuntimeDefault: false;
70
+ enumValues: undefined;
71
+ baseColumn: never;
72
+ identity: undefined;
73
+ generated: undefined;
74
+ }, {}, {}>;
75
+ };
76
+ dialect: "pg";
77
+ }>;
78
+ export declare const bridgeAgents: import("drizzle-orm/pg-core").PgTableWithColumns<{
79
+ name: "bridge_agents";
80
+ schema: undefined;
81
+ columns: {
82
+ id: import("drizzle-orm/pg-core").PgColumn<{
83
+ name: "id";
84
+ tableName: "bridge_agents";
85
+ dataType: "string";
86
+ columnType: "PgVarchar";
87
+ data: string;
88
+ driverParam: string;
89
+ notNull: true;
90
+ hasDefault: true;
91
+ isPrimaryKey: true;
92
+ isAutoincrement: false;
93
+ hasRuntimeDefault: false;
94
+ enumValues: [string, ...string[]];
95
+ baseColumn: never;
96
+ identity: undefined;
97
+ generated: undefined;
98
+ }, {}, {
99
+ length: number | undefined;
100
+ }>;
101
+ name: import("drizzle-orm/pg-core").PgColumn<{
102
+ name: "name";
103
+ tableName: "bridge_agents";
104
+ dataType: "string";
105
+ columnType: "PgText";
106
+ data: string;
107
+ driverParam: string;
108
+ notNull: true;
109
+ hasDefault: false;
110
+ isPrimaryKey: false;
111
+ isAutoincrement: false;
112
+ hasRuntimeDefault: false;
113
+ enumValues: [string, ...string[]];
114
+ baseColumn: never;
115
+ identity: undefined;
116
+ generated: undefined;
117
+ }, {}, {}>;
118
+ serverName: import("drizzle-orm/pg-core").PgColumn<{
119
+ name: "server_name";
120
+ tableName: "bridge_agents";
121
+ dataType: "string";
122
+ columnType: "PgText";
123
+ data: string;
124
+ driverParam: string;
125
+ notNull: true;
126
+ hasDefault: false;
127
+ isPrimaryKey: false;
128
+ isAutoincrement: false;
129
+ hasRuntimeDefault: false;
130
+ enumValues: [string, ...string[]];
131
+ baseColumn: never;
132
+ identity: undefined;
133
+ generated: undefined;
134
+ }, {}, {}>;
135
+ companyId: import("drizzle-orm/pg-core").PgColumn<{
136
+ name: "company_id";
137
+ tableName: "bridge_agents";
138
+ dataType: "string";
139
+ columnType: "PgVarchar";
140
+ data: string;
141
+ driverParam: string;
142
+ notNull: false;
143
+ hasDefault: false;
144
+ isPrimaryKey: false;
145
+ isAutoincrement: false;
146
+ hasRuntimeDefault: false;
147
+ enumValues: [string, ...string[]];
148
+ baseColumn: never;
149
+ identity: undefined;
150
+ generated: undefined;
151
+ }, {}, {
152
+ length: number | undefined;
153
+ }>;
154
+ status: import("drizzle-orm/pg-core").PgColumn<{
155
+ name: "status";
156
+ tableName: "bridge_agents";
157
+ dataType: "string";
158
+ columnType: "PgText";
159
+ data: string;
160
+ driverParam: string;
161
+ notNull: true;
162
+ hasDefault: true;
163
+ isPrimaryKey: false;
164
+ isAutoincrement: false;
165
+ hasRuntimeDefault: false;
166
+ enumValues: [string, ...string[]];
167
+ baseColumn: never;
168
+ identity: undefined;
169
+ generated: undefined;
170
+ }, {}, {}>;
171
+ lastHeartbeat: import("drizzle-orm/pg-core").PgColumn<{
172
+ name: "last_heartbeat";
173
+ tableName: "bridge_agents";
174
+ dataType: "date";
175
+ columnType: "PgTimestamp";
176
+ data: Date;
177
+ driverParam: string;
178
+ notNull: false;
179
+ hasDefault: false;
180
+ isPrimaryKey: false;
181
+ isAutoincrement: false;
182
+ hasRuntimeDefault: false;
183
+ enumValues: undefined;
184
+ baseColumn: never;
185
+ identity: undefined;
186
+ generated: undefined;
187
+ }, {}, {}>;
188
+ version: import("drizzle-orm/pg-core").PgColumn<{
189
+ name: "version";
190
+ tableName: "bridge_agents";
191
+ dataType: "string";
192
+ columnType: "PgText";
193
+ data: string;
194
+ driverParam: string;
195
+ notNull: false;
196
+ hasDefault: false;
197
+ isPrimaryKey: false;
198
+ isAutoincrement: false;
199
+ hasRuntimeDefault: false;
200
+ enumValues: [string, ...string[]];
201
+ baseColumn: never;
202
+ identity: undefined;
203
+ generated: undefined;
204
+ }, {}, {}>;
205
+ apiKey: import("drizzle-orm/pg-core").PgColumn<{
206
+ name: "api_key";
207
+ tableName: "bridge_agents";
208
+ dataType: "string";
209
+ columnType: "PgText";
210
+ data: string;
211
+ driverParam: string;
212
+ notNull: true;
213
+ hasDefault: false;
214
+ isPrimaryKey: false;
215
+ isAutoincrement: false;
216
+ hasRuntimeDefault: false;
217
+ enumValues: [string, ...string[]];
218
+ baseColumn: never;
219
+ identity: undefined;
220
+ generated: undefined;
221
+ }, {}, {}>;
222
+ capabilities: import("drizzle-orm/pg-core").PgColumn<{
223
+ name: "capabilities";
224
+ tableName: "bridge_agents";
225
+ dataType: "array";
226
+ columnType: "PgArray";
227
+ data: string[];
228
+ driverParam: string | string[];
229
+ notNull: true;
230
+ hasDefault: true;
231
+ isPrimaryKey: false;
232
+ isAutoincrement: false;
233
+ hasRuntimeDefault: false;
234
+ enumValues: [string, ...string[]];
235
+ baseColumn: import("drizzle-orm").Column<{
236
+ name: "capabilities";
237
+ tableName: "bridge_agents";
238
+ dataType: "string";
239
+ columnType: "PgText";
240
+ data: string;
241
+ driverParam: string;
242
+ notNull: false;
243
+ hasDefault: false;
244
+ isPrimaryKey: false;
245
+ isAutoincrement: false;
246
+ hasRuntimeDefault: false;
247
+ enumValues: [string, ...string[]];
248
+ baseColumn: never;
249
+ identity: undefined;
250
+ generated: undefined;
251
+ }, {}, {}>;
252
+ identity: undefined;
253
+ generated: undefined;
254
+ }, {}, {
255
+ baseBuilder: import("drizzle-orm/pg-core").PgColumnBuilder<{
256
+ name: "capabilities";
257
+ dataType: "string";
258
+ columnType: "PgText";
259
+ data: string;
260
+ enumValues: [string, ...string[]];
261
+ driverParam: string;
262
+ }, {}, {}, import("drizzle-orm").ColumnBuilderExtraConfig>;
263
+ size: undefined;
264
+ }>;
265
+ };
266
+ dialect: "pg";
267
+ }>;
268
+ export declare const bridgeQueries: import("drizzle-orm/pg-core").PgTableWithColumns<{
269
+ name: "bridge_queries";
270
+ schema: undefined;
271
+ columns: {
272
+ id: import("drizzle-orm/pg-core").PgColumn<{
273
+ name: "id";
274
+ tableName: "bridge_queries";
275
+ dataType: "string";
276
+ columnType: "PgVarchar";
277
+ data: string;
278
+ driverParam: string;
279
+ notNull: true;
280
+ hasDefault: true;
281
+ isPrimaryKey: true;
282
+ isAutoincrement: false;
283
+ hasRuntimeDefault: false;
284
+ enumValues: [string, ...string[]];
285
+ baseColumn: never;
286
+ identity: undefined;
287
+ generated: undefined;
288
+ }, {}, {
289
+ length: number | undefined;
290
+ }>;
291
+ agentId: import("drizzle-orm/pg-core").PgColumn<{
292
+ name: "agent_id";
293
+ tableName: "bridge_queries";
294
+ dataType: "string";
295
+ columnType: "PgVarchar";
296
+ data: string;
297
+ driverParam: string;
298
+ notNull: false;
299
+ hasDefault: false;
300
+ isPrimaryKey: false;
301
+ isAutoincrement: false;
302
+ hasRuntimeDefault: false;
303
+ enumValues: [string, ...string[]];
304
+ baseColumn: never;
305
+ identity: undefined;
306
+ generated: undefined;
307
+ }, {}, {
308
+ length: number | undefined;
309
+ }>;
310
+ targetType: import("drizzle-orm/pg-core").PgColumn<{
311
+ name: "target_type";
312
+ tableName: "bridge_queries";
313
+ dataType: "string";
314
+ columnType: "PgText";
315
+ data: string;
316
+ driverParam: string;
317
+ notNull: true;
318
+ hasDefault: true;
319
+ isPrimaryKey: false;
320
+ isAutoincrement: false;
321
+ hasRuntimeDefault: false;
322
+ enumValues: [string, ...string[]];
323
+ baseColumn: never;
324
+ identity: undefined;
325
+ generated: undefined;
326
+ }, {}, {}>;
327
+ sqlQuery: import("drizzle-orm/pg-core").PgColumn<{
328
+ name: "sql_query";
329
+ tableName: "bridge_queries";
330
+ dataType: "string";
331
+ columnType: "PgText";
332
+ data: string;
333
+ driverParam: string;
334
+ notNull: true;
335
+ hasDefault: false;
336
+ isPrimaryKey: false;
337
+ isAutoincrement: false;
338
+ hasRuntimeDefault: false;
339
+ enumValues: [string, ...string[]];
340
+ baseColumn: never;
341
+ identity: undefined;
342
+ generated: undefined;
343
+ }, {}, {}>;
344
+ requestPayload: import("drizzle-orm/pg-core").PgColumn<{
345
+ name: "request_payload";
346
+ tableName: "bridge_queries";
347
+ dataType: "json";
348
+ columnType: "PgJsonb";
349
+ data: unknown;
350
+ driverParam: unknown;
351
+ notNull: false;
352
+ hasDefault: false;
353
+ isPrimaryKey: false;
354
+ isAutoincrement: false;
355
+ hasRuntimeDefault: false;
356
+ enumValues: undefined;
357
+ baseColumn: never;
358
+ identity: undefined;
359
+ generated: undefined;
360
+ }, {}, {}>;
361
+ status: import("drizzle-orm/pg-core").PgColumn<{
362
+ name: "status";
363
+ tableName: "bridge_queries";
364
+ dataType: "string";
365
+ columnType: "PgText";
366
+ data: string;
367
+ driverParam: string;
368
+ notNull: true;
369
+ hasDefault: true;
370
+ isPrimaryKey: false;
371
+ isAutoincrement: false;
372
+ hasRuntimeDefault: false;
373
+ enumValues: [string, ...string[]];
374
+ baseColumn: never;
375
+ identity: undefined;
376
+ generated: undefined;
377
+ }, {}, {}>;
378
+ submittedAt: import("drizzle-orm/pg-core").PgColumn<{
379
+ name: "submitted_at";
380
+ tableName: "bridge_queries";
381
+ dataType: "date";
382
+ columnType: "PgTimestamp";
383
+ data: Date;
384
+ driverParam: string;
385
+ notNull: false;
386
+ hasDefault: true;
387
+ isPrimaryKey: false;
388
+ isAutoincrement: false;
389
+ hasRuntimeDefault: false;
390
+ enumValues: undefined;
391
+ baseColumn: never;
392
+ identity: undefined;
393
+ generated: undefined;
394
+ }, {}, {}>;
395
+ executedAt: import("drizzle-orm/pg-core").PgColumn<{
396
+ name: "executed_at";
397
+ tableName: "bridge_queries";
398
+ dataType: "date";
399
+ columnType: "PgTimestamp";
400
+ data: Date;
401
+ driverParam: string;
402
+ notNull: false;
403
+ hasDefault: false;
404
+ isPrimaryKey: false;
405
+ isAutoincrement: false;
406
+ hasRuntimeDefault: false;
407
+ enumValues: undefined;
408
+ baseColumn: never;
409
+ identity: undefined;
410
+ generated: undefined;
411
+ }, {}, {}>;
412
+ completedAt: import("drizzle-orm/pg-core").PgColumn<{
413
+ name: "completed_at";
414
+ tableName: "bridge_queries";
415
+ dataType: "date";
416
+ columnType: "PgTimestamp";
417
+ data: Date;
418
+ driverParam: string;
419
+ notNull: false;
420
+ hasDefault: false;
421
+ isPrimaryKey: false;
422
+ isAutoincrement: false;
423
+ hasRuntimeDefault: false;
424
+ enumValues: undefined;
425
+ baseColumn: never;
426
+ identity: undefined;
427
+ generated: undefined;
428
+ }, {}, {}>;
429
+ rowCount: import("drizzle-orm/pg-core").PgColumn<{
430
+ name: "row_count";
431
+ tableName: "bridge_queries";
432
+ dataType: "number";
433
+ columnType: "PgInteger";
434
+ data: number;
435
+ driverParam: string | number;
436
+ notNull: false;
437
+ hasDefault: false;
438
+ isPrimaryKey: false;
439
+ isAutoincrement: false;
440
+ hasRuntimeDefault: false;
441
+ enumValues: undefined;
442
+ baseColumn: never;
443
+ identity: undefined;
444
+ generated: undefined;
445
+ }, {}, {}>;
446
+ executionTime: import("drizzle-orm/pg-core").PgColumn<{
447
+ name: "execution_time";
448
+ tableName: "bridge_queries";
449
+ dataType: "number";
450
+ columnType: "PgInteger";
451
+ data: number;
452
+ driverParam: string | number;
453
+ notNull: false;
454
+ hasDefault: false;
455
+ isPrimaryKey: false;
456
+ isAutoincrement: false;
457
+ hasRuntimeDefault: false;
458
+ enumValues: undefined;
459
+ baseColumn: never;
460
+ identity: undefined;
461
+ generated: undefined;
462
+ }, {}, {}>;
463
+ error: import("drizzle-orm/pg-core").PgColumn<{
464
+ name: "error";
465
+ tableName: "bridge_queries";
466
+ dataType: "string";
467
+ columnType: "PgText";
468
+ data: string;
469
+ driverParam: string;
470
+ notNull: false;
471
+ hasDefault: false;
472
+ isPrimaryKey: false;
473
+ isAutoincrement: false;
474
+ hasRuntimeDefault: false;
475
+ enumValues: [string, ...string[]];
476
+ baseColumn: never;
477
+ identity: undefined;
478
+ generated: undefined;
479
+ }, {}, {}>;
480
+ result: import("drizzle-orm/pg-core").PgColumn<{
481
+ name: "result";
482
+ tableName: "bridge_queries";
483
+ dataType: "json";
484
+ columnType: "PgJsonb";
485
+ data: unknown;
486
+ driverParam: unknown;
487
+ notNull: false;
488
+ hasDefault: false;
489
+ isPrimaryKey: false;
490
+ isAutoincrement: false;
491
+ hasRuntimeDefault: false;
492
+ enumValues: undefined;
493
+ baseColumn: never;
494
+ identity: undefined;
495
+ generated: undefined;
496
+ }, {}, {}>;
497
+ };
498
+ dialect: "pg";
499
+ }>;
package/dist/schema.js ADDED
@@ -0,0 +1,34 @@
1
+ import { sql } from "drizzle-orm";
2
+ import { pgTable, text, varchar, timestamp, jsonb, integer } from "drizzle-orm/pg-core";
3
+ export const bridgeCompanies = pgTable("bridge_companies", {
4
+ id: varchar("id").primaryKey().default(sql `gen_random_uuid()`),
5
+ name: text("name").notNull(),
6
+ description: text("description"),
7
+ createdAt: timestamp("created_at").defaultNow(),
8
+ });
9
+ export const bridgeAgents = pgTable("bridge_agents", {
10
+ id: varchar("id").primaryKey().default(sql `gen_random_uuid()`),
11
+ name: text("name").notNull(),
12
+ serverName: text("server_name").notNull(),
13
+ companyId: varchar("company_id").references(() => bridgeCompanies.id),
14
+ status: text("status").notNull().default("offline"),
15
+ lastHeartbeat: timestamp("last_heartbeat"),
16
+ version: text("version"),
17
+ apiKey: text("api_key").notNull().unique(),
18
+ capabilities: text("capabilities").array().notNull().default(sql `ARRAY['sql_server']::text[]`),
19
+ });
20
+ export const bridgeQueries = pgTable("bridge_queries", {
21
+ id: varchar("id").primaryKey().default(sql `gen_random_uuid()`),
22
+ agentId: varchar("agent_id").references(() => bridgeAgents.id),
23
+ targetType: text("target_type").notNull().default("sql_server"),
24
+ sqlQuery: text("sql_query").notNull(),
25
+ requestPayload: jsonb("request_payload"),
26
+ status: text("status").notNull().default("pending"),
27
+ submittedAt: timestamp("submitted_at").defaultNow(),
28
+ executedAt: timestamp("executed_at"),
29
+ completedAt: timestamp("completed_at"),
30
+ rowCount: integer("row_count"),
31
+ executionTime: integer("execution_time"),
32
+ error: text("error"),
33
+ result: jsonb("result"),
34
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bestoneconsulting/sap-b1-bridge",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "SAP Business One & SQL Server bridge for secure database and ERP access behind firewalls via WebSocket agents",
@@ -27,7 +27,13 @@
27
27
  "peerDependencies": {
28
28
  "express": ">=4.0.0",
29
29
  "ws": ">=8.0.0",
30
- "zod": ">=3.0.0"
30
+ "zod": ">=3.0.0",
31
+ "drizzle-orm": ">=0.30.0"
32
+ },
33
+ "peerDependenciesMeta": {
34
+ "drizzle-orm": {
35
+ "optional": true
36
+ }
31
37
  },
32
38
  "scripts": {
33
39
  "build": "tsc -p ../tsconfig.bridge.json",