@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 +120 -0
- package/dist/app-adapter.d.ts +2 -0
- package/dist/app-adapter.js +61 -0
- package/dist/drizzle-storage.d.ts +5 -1
- package/dist/drizzle-storage.js +48 -20
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/schema.d.ts +499 -0
- package/dist/schema.js +34 -0
- package/package.json +8 -2
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,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
|
-
|
|
4
|
+
type DrizzleDB = NodePgDatabase<any> | NeonHttpDatabase<any>;
|
|
5
|
+
export declare function createDrizzleBridgeStorage(db: DrizzleDB): IBridgeStorage;
|
|
6
|
+
export {};
|
package/dist/drizzle-storage.js
CHANGED
|
@@ -1,61 +1,89 @@
|
|
|
1
|
-
|
|
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
|
|
7
|
+
return db.select().from(bridgeCompanies);
|
|
5
8
|
},
|
|
6
9
|
async getCompany(id) {
|
|
7
|
-
|
|
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
|
-
|
|
14
|
+
const rows = await db.insert(bridgeCompanies).values({ name, description }).returning();
|
|
15
|
+
return rows[0];
|
|
11
16
|
},
|
|
12
17
|
async updateCompany(id, updates) {
|
|
13
|
-
|
|
18
|
+
await db.update(bridgeCompanies).set(updates).where(eq(bridgeCompanies.id, id));
|
|
14
19
|
},
|
|
15
20
|
async deleteCompany(id) {
|
|
16
|
-
|
|
21
|
+
await db.delete(bridgeCompanies).where(eq(bridgeCompanies.id, id));
|
|
17
22
|
},
|
|
18
23
|
async getAgents() {
|
|
19
|
-
return
|
|
24
|
+
return db.select().from(bridgeAgents);
|
|
20
25
|
},
|
|
21
26
|
async getAgent(id) {
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
47
|
+
await db.update(bridgeAgents).set(updates).where(eq(bridgeAgents.id, id));
|
|
32
48
|
},
|
|
33
49
|
async updateAgentStatus(id, status, lastHeartbeat) {
|
|
34
|
-
|
|
50
|
+
await db.update(bridgeAgents).set({ status, lastHeartbeat }).where(eq(bridgeAgents.id, id));
|
|
35
51
|
},
|
|
36
52
|
async deleteAgent(id) {
|
|
37
|
-
|
|
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
|
|
57
|
+
return db.select().from(bridgeQueries).orderBy(desc(bridgeQueries.submittedAt));
|
|
41
58
|
},
|
|
42
59
|
async getQuery(id) {
|
|
43
|
-
|
|
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
|
|
64
|
+
return db.select().from(bridgeQueries).orderBy(desc(bridgeQueries.submittedAt)).limit(limit);
|
|
47
65
|
},
|
|
48
66
|
async getPendingQueriesForAgent(agentId) {
|
|
49
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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";
|
package/dist/schema.d.ts
ADDED
|
@@ -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.
|
|
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",
|