@almadar/integrations 2.19.0 → 2.20.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/dist/{BaseIntegration-B9lSTRQm.d.ts → BaseIntegration-MA-b4fh8.d.ts} +1 -1
- package/dist/{contracts-B28G_7ur.d.ts → contracts-DaVfyPnd.d.ts} +40 -2
- package/dist/{factory-TNgVDujm.d.ts → factory-DTdVeyAi.d.ts} +1 -1
- package/dist/index.d.ts +45 -5
- package/dist/index.js +264 -22
- package/dist/index.js.map +1 -1
- package/dist/integrations/github/index.d.ts +1 -1
- package/dist/mocks/index.d.ts +2 -2
- package/dist/runtime/index.d.ts +3 -3
- package/package.json +4 -2
|
@@ -146,4 +146,4 @@ declare abstract class BaseIntegration {
|
|
|
146
146
|
protected executeWithRetry<T>(fn: () => Promise<T>): Promise<T>;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
export { BaseIntegration as B, type IntegrationConfig as I, type ValidationError as V, IntegrationError as a, type IntegrationErrorCode as b, type IntegrationLogger as c, type
|
|
149
|
+
export { BaseIntegration as B, type IntegrationConfig as I, type ValidationError as V, IntegrationError as a, type IntegrationErrorCode as b, type IntegrationLogger as c, type IntegrationParamValue as d, type IntegrationParams as e, type IntegrationResult as f, type ValidationResult as g, validateParams as v };
|
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
import { ServiceParamsValue, ServiceParams } from '@almadar/core';
|
|
2
|
-
import { d as IntegrationParams } from './BaseIntegration-
|
|
2
|
+
import { d as IntegrationParamValue, e as IntegrationParams } from './BaseIntegration-MA-b4fh8.js';
|
|
3
|
+
|
|
4
|
+
/** Scalar value admissible as a SQL bind parameter. */
|
|
5
|
+
type DatabaseQueryParamValue = string | number | boolean | Date | null;
|
|
6
|
+
/** Params for the `query` action. */
|
|
7
|
+
type DatabaseQueryParams = {
|
|
8
|
+
connectionRef: string;
|
|
9
|
+
sql: string;
|
|
10
|
+
params?: DatabaseQueryParamValue[];
|
|
11
|
+
};
|
|
12
|
+
/** One result row, keyed by column name. */
|
|
13
|
+
type DatabaseRow = Record<string, IntegrationParamValue>;
|
|
14
|
+
/** Result of a read-only query. */
|
|
15
|
+
interface DatabaseQueryResult {
|
|
16
|
+
rows: DatabaseRow[];
|
|
17
|
+
rowCount: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Driver seam behind the `query` action. Postgres is the first
|
|
21
|
+
* implementation; MySQL/SQLite slot behind this interface later.
|
|
22
|
+
*/
|
|
23
|
+
interface DatabaseDriver {
|
|
24
|
+
query(sql: string, params: readonly DatabaseQueryParamValue[]): Promise<DatabaseQueryResult>;
|
|
25
|
+
end(): Promise<void>;
|
|
26
|
+
}
|
|
3
27
|
|
|
4
28
|
/**
|
|
5
29
|
* ServiceContract type definitions for all @almadar/integrations.
|
|
@@ -848,6 +872,19 @@ type DeepAgentActions = {
|
|
|
848
872
|
};
|
|
849
873
|
};
|
|
850
874
|
};
|
|
875
|
+
type DatabaseActions = {
|
|
876
|
+
query: {
|
|
877
|
+
params: {
|
|
878
|
+
connectionRef: string;
|
|
879
|
+
sql: string;
|
|
880
|
+
params?: DatabaseQueryParamValue[];
|
|
881
|
+
};
|
|
882
|
+
result: {
|
|
883
|
+
rows: DatabaseRow[];
|
|
884
|
+
rowCount: number;
|
|
885
|
+
};
|
|
886
|
+
};
|
|
887
|
+
};
|
|
851
888
|
/**
|
|
852
889
|
* Maps each integration name (as used in `registerIntegration`) to its action
|
|
853
890
|
* map type. Use with `ServiceContract<IntegrationContracts[K]>` to get a fully
|
|
@@ -877,6 +914,7 @@ type IntegrationContracts = {
|
|
|
877
914
|
otel: OtelActions;
|
|
878
915
|
cli: CLIActions;
|
|
879
916
|
deepagent: DeepAgentActions;
|
|
917
|
+
database: DatabaseActions;
|
|
880
918
|
};
|
|
881
919
|
/** Integration name literal union. */
|
|
882
920
|
type IntegrationName = keyof IntegrationContracts;
|
|
@@ -891,4 +929,4 @@ type IntegrationName = keyof IntegrationContracts;
|
|
|
891
929
|
*/
|
|
892
930
|
type IntegrationActionName<K extends IntegrationName> = keyof IntegrationContracts[K] & string;
|
|
893
931
|
|
|
894
|
-
export type { CLIActions as C,
|
|
932
|
+
export type { CLIActions as C, DatabaseActions as D, EmailActions as E, GitHubActions as G, IntegrationActionName as I, LLMIntegrationActions as L, MLActions as M, OAuthActions as O, QueueActions as Q, RedisActions as R, StorageActions as S, TwilioActions as T, YouTubeActions as Y, DatabaseDriver as a, DatabaseQueryParamValue as b, DatabaseQueryParams as c, DatabaseQueryResult as d, DatabaseRow as e, DeepAgentActions as f, DockerActions as g, IntegrationContracts as h, IntegrationName as i, OtelActions as j, StripeActions as k };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as IntegrationConfig, B as BaseIntegration,
|
|
1
|
+
import { I as IntegrationConfig, B as BaseIntegration, e as IntegrationParams, f as IntegrationResult } from './BaseIntegration-MA-b4fh8.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Factory for creating and managing integration instances
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { c as IntegrationLogger, b as IntegrationErrorCode, I as IntegrationConfig, B as BaseIntegration,
|
|
2
|
-
export { a as IntegrationError, V as ValidationError,
|
|
3
|
-
export { C as CLIActions, D as
|
|
1
|
+
import { c as IntegrationLogger, b as IntegrationErrorCode, I as IntegrationConfig, B as BaseIntegration, e as IntegrationParams, f as IntegrationResult } from './BaseIntegration-MA-b4fh8.js';
|
|
2
|
+
export { a as IntegrationError, d as IntegrationParamValue, V as ValidationError, g as ValidationResult, v as validateParams } from './BaseIntegration-MA-b4fh8.js';
|
|
3
|
+
export { C as CLIActions, D as DatabaseActions, a as DatabaseDriver, b as DatabaseQueryParamValue, c as DatabaseQueryParams, d as DatabaseQueryResult, e as DatabaseRow, f as DeepAgentActions, g as DockerActions, E as EmailActions, G as GitHubActions, I as IntegrationActionName, h as IntegrationContracts, i as IntegrationName, L as LLMIntegrationActions, M as MLActions, O as OAuthActions, j as OtelActions, Q as QueueActions, R as RedisActions, S as StorageActions, k as StripeActions, T as TwilioActions, Y as YouTubeActions } from './contracts-DaVfyPnd.js';
|
|
4
4
|
import { LogMeta } from '@almadar/core';
|
|
5
|
-
export { I as IntegrationFactory, g as getIntegrationFactory, r as resetIntegrationFactory } from './factory-
|
|
5
|
+
export { I as IntegrationFactory, g as getIntegrationFactory, r as resetIntegrationFactory } from './factory-DTdVeyAi.js';
|
|
6
6
|
export { GitHubIntegration } from './integrations/github/index.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -560,4 +560,44 @@ declare class DockerIntegration extends BaseIntegration {
|
|
|
560
560
|
private list;
|
|
561
561
|
}
|
|
562
562
|
|
|
563
|
-
|
|
563
|
+
/**
|
|
564
|
+
* Read-only SQL enforcement for the database integration.
|
|
565
|
+
*
|
|
566
|
+
* The guard accepts exactly one SELECT statement (optionally CTE-led) and
|
|
567
|
+
* nothing else. Comments are stripped and string/identifier contents are
|
|
568
|
+
* blanked before keyword checks, so denied keywords inside literals (e.g.
|
|
569
|
+
* `WHERE note = 'delete this'`) never false-positive, and comment/quote
|
|
570
|
+
* tricks cannot smuggle a second statement past the check.
|
|
571
|
+
*/
|
|
572
|
+
interface SqlGuardResult {
|
|
573
|
+
ok: boolean;
|
|
574
|
+
reason?: string;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Verify `sql` is a single read-only SELECT statement.
|
|
578
|
+
* Returns `{ ok: false, reason }` for anything else.
|
|
579
|
+
*/
|
|
580
|
+
declare function assertReadOnlySelect(sql: string): SqlGuardResult;
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Database Integration for Almadar
|
|
584
|
+
* Read-only SQL queries over external connections (migration fetch seam).
|
|
585
|
+
*/
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Generic database integration. One action — `query` — with read-only
|
|
589
|
+
* enforced in the integration itself (single SELECT only, statement
|
|
590
|
+
* timeout). `connectionRef` is an environment variable NAME, never the
|
|
591
|
+
* secret; the connection string is resolved from `process.env` at run time.
|
|
592
|
+
*/
|
|
593
|
+
declare class DatabaseIntegration extends BaseIntegration {
|
|
594
|
+
private drivers;
|
|
595
|
+
private statementTimeoutMs;
|
|
596
|
+
constructor(config: IntegrationConfig);
|
|
597
|
+
execute(action: string, params: IntegrationParams): Promise<IntegrationResult>;
|
|
598
|
+
private runQuery;
|
|
599
|
+
/** Resolve (and cache) the driver for a connection reference. */
|
|
600
|
+
private driverFor;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
export { type AlmadarCheckoutSession, type AlmadarCustomer, type AlmadarInvoiceFailure, type AlmadarInvoicePayment, type AlmadarPortalSession, type AlmadarStripeEvent, type AlmadarStripeEventOk, type AlmadarSubscription, type AlmadarSubscriptionStatus, type AlmadarTier, BaseIntegration, CLIIntegration, type CancelSubscriptionInput, ConsoleLogger, type CreateCheckoutInput, type CreateCustomerInput, type CreatePortalInput, DatabaseIntegration, DeepAgentIntegration, DockerIntegration, EmailIntegration, IntegrationConfig, type IntegrationConstructor, IntegrationErrorCode, IntegrationLogger, IntegrationParams, IntegrationResult, LLMIntegration, MLIntegration, OAuthIntegration, OtelIntegration, QueueIntegration, RedisIntegration, type RetryConfig, type SqlGuardResult, StorageIntegration, StripeIntegration, type StripePriceMap, TwilioIntegration, type UpdateSubscriptionInput, type VerifyAndParseInput, YouTubeIntegration, assertReadOnlySelect, getIntegration, getRegisteredIntegrations, isKnownIntegration, registerIntegration, verifyAndParseStripeEvent, withRetry };
|
package/dist/index.js
CHANGED
|
@@ -11,8 +11,27 @@ import { execSync, spawn } from 'child_process';
|
|
|
11
11
|
import { mkdtempSync, writeFileSync, rmSync, promises } from 'fs';
|
|
12
12
|
import { join } from 'path';
|
|
13
13
|
import { tmpdir } from 'os';
|
|
14
|
+
import { Pool } from 'pg';
|
|
14
15
|
|
|
15
|
-
// src/
|
|
16
|
+
// src/types.ts
|
|
17
|
+
var IntegrationError = class extends Error {
|
|
18
|
+
constructor(message, code = "UNKNOWN_ERROR", details) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = "IntegrationError";
|
|
21
|
+
this.code = code;
|
|
22
|
+
this.details = details;
|
|
23
|
+
}
|
|
24
|
+
toJSON() {
|
|
25
|
+
return {
|
|
26
|
+
name: this.name,
|
|
27
|
+
message: this.message,
|
|
28
|
+
code: this.code,
|
|
29
|
+
integration: this.integration,
|
|
30
|
+
action: this.action,
|
|
31
|
+
details: this.details
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
};
|
|
16
35
|
var ConsoleLogger = class {
|
|
17
36
|
constructor(_level = "info") {
|
|
18
37
|
this.log = createLogger("almadar:integrations");
|
|
@@ -1121,26 +1140,6 @@ Return ONLY valid JSON matching the schema.`,
|
|
|
1121
1140
|
};
|
|
1122
1141
|
registerIntegration("llm", LLMIntegration);
|
|
1123
1142
|
|
|
1124
|
-
// src/types.ts
|
|
1125
|
-
var IntegrationError = class extends Error {
|
|
1126
|
-
constructor(message, code = "UNKNOWN_ERROR", details) {
|
|
1127
|
-
super(message);
|
|
1128
|
-
this.name = "IntegrationError";
|
|
1129
|
-
this.code = code;
|
|
1130
|
-
this.details = details;
|
|
1131
|
-
}
|
|
1132
|
-
toJSON() {
|
|
1133
|
-
return {
|
|
1134
|
-
name: this.name,
|
|
1135
|
-
message: this.message,
|
|
1136
|
-
code: this.code,
|
|
1137
|
-
integration: this.integration,
|
|
1138
|
-
action: this.action,
|
|
1139
|
-
details: this.details
|
|
1140
|
-
};
|
|
1141
|
-
}
|
|
1142
|
-
};
|
|
1143
|
-
|
|
1144
1143
|
// src/integrations/ml/index.ts
|
|
1145
1144
|
var INFERRED_EVENT = "INFERRED";
|
|
1146
1145
|
var INFER_FAILED_EVENT = "INFER_FAILED";
|
|
@@ -3172,6 +3171,249 @@ var DockerIntegration = class extends BaseIntegration {
|
|
|
3172
3171
|
};
|
|
3173
3172
|
registerIntegration("docker", DockerIntegration);
|
|
3174
3173
|
|
|
3175
|
-
|
|
3174
|
+
// src/integrations/database/sql-guard.ts
|
|
3175
|
+
var DENIED_KEYWORDS = /* @__PURE__ */ new Set(["INSERT", "UPDATE", "DELETE", "MERGE", "INTO", "FOR"]);
|
|
3176
|
+
function isWordChar(ch) {
|
|
3177
|
+
return ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch >= "0" && ch <= "9" || ch === "_" || ch === "$";
|
|
3178
|
+
}
|
|
3179
|
+
function skipSingleQuoted(sql, start, eString) {
|
|
3180
|
+
let i = start + 1;
|
|
3181
|
+
while (i < sql.length) {
|
|
3182
|
+
if (eString && sql[i] === "\\") {
|
|
3183
|
+
i += 2;
|
|
3184
|
+
continue;
|
|
3185
|
+
}
|
|
3186
|
+
if (sql[i] === "'") {
|
|
3187
|
+
if (sql[i + 1] === "'") {
|
|
3188
|
+
i += 2;
|
|
3189
|
+
continue;
|
|
3190
|
+
}
|
|
3191
|
+
return i + 1;
|
|
3192
|
+
}
|
|
3193
|
+
i++;
|
|
3194
|
+
}
|
|
3195
|
+
return sql.length;
|
|
3196
|
+
}
|
|
3197
|
+
function skipDoubleQuoted(sql, start) {
|
|
3198
|
+
let i = start + 1;
|
|
3199
|
+
while (i < sql.length) {
|
|
3200
|
+
if (sql[i] === '"') {
|
|
3201
|
+
if (sql[i + 1] === '"') {
|
|
3202
|
+
i += 2;
|
|
3203
|
+
continue;
|
|
3204
|
+
}
|
|
3205
|
+
return i + 1;
|
|
3206
|
+
}
|
|
3207
|
+
i++;
|
|
3208
|
+
}
|
|
3209
|
+
return sql.length;
|
|
3210
|
+
}
|
|
3211
|
+
function matchDollarTag(sql, start) {
|
|
3212
|
+
let i = start + 1;
|
|
3213
|
+
if (sql[i] === "$") return "$$";
|
|
3214
|
+
const first = sql[i];
|
|
3215
|
+
if (!first || !(first >= "a" && first <= "z" || first >= "A" && first <= "Z" || first === "_")) {
|
|
3216
|
+
return void 0;
|
|
3217
|
+
}
|
|
3218
|
+
i++;
|
|
3219
|
+
while (i < sql.length && isWordChar(sql[i]) && sql[i] !== "$") i++;
|
|
3220
|
+
if (sql[i] !== "$") return void 0;
|
|
3221
|
+
return sql.slice(start, i + 1);
|
|
3222
|
+
}
|
|
3223
|
+
function sanitizeSql(sql) {
|
|
3224
|
+
const out = [];
|
|
3225
|
+
let i = 0;
|
|
3226
|
+
while (i < sql.length) {
|
|
3227
|
+
const ch = sql[i];
|
|
3228
|
+
if (ch === "-" && sql[i + 1] === "-") {
|
|
3229
|
+
while (i < sql.length && sql[i] !== "\n") i++;
|
|
3230
|
+
out.push(" ");
|
|
3231
|
+
continue;
|
|
3232
|
+
}
|
|
3233
|
+
if (ch === "/" && sql[i + 1] === "*") {
|
|
3234
|
+
let depth = 1;
|
|
3235
|
+
i += 2;
|
|
3236
|
+
while (i < sql.length && depth > 0) {
|
|
3237
|
+
if (sql[i] === "/" && sql[i + 1] === "*") {
|
|
3238
|
+
depth++;
|
|
3239
|
+
i += 2;
|
|
3240
|
+
} else if (sql[i] === "*" && sql[i + 1] === "/") {
|
|
3241
|
+
depth--;
|
|
3242
|
+
i += 2;
|
|
3243
|
+
} else {
|
|
3244
|
+
i++;
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
out.push(" ");
|
|
3248
|
+
continue;
|
|
3249
|
+
}
|
|
3250
|
+
if (ch === "'") {
|
|
3251
|
+
let j = i - 1;
|
|
3252
|
+
while (j >= 0 && (sql[j] === " " || sql[j] === " " || sql[j] === "\n" || sql[j] === "\r")) j--;
|
|
3253
|
+
const prev = j >= 0 ? sql[j] : "";
|
|
3254
|
+
const eString = (prev === "e" || prev === "E") && (j === 0 || !isWordChar(sql[j - 1]));
|
|
3255
|
+
i = skipSingleQuoted(sql, i, eString);
|
|
3256
|
+
out.push("''");
|
|
3257
|
+
continue;
|
|
3258
|
+
}
|
|
3259
|
+
if (ch === '"') {
|
|
3260
|
+
i = skipDoubleQuoted(sql, i);
|
|
3261
|
+
out.push('""');
|
|
3262
|
+
continue;
|
|
3263
|
+
}
|
|
3264
|
+
if (ch === "$") {
|
|
3265
|
+
const tag = matchDollarTag(sql, i);
|
|
3266
|
+
if (tag) {
|
|
3267
|
+
const close = sql.indexOf(tag, i + tag.length);
|
|
3268
|
+
i = close === -1 ? sql.length : close + tag.length;
|
|
3269
|
+
out.push("$$");
|
|
3270
|
+
continue;
|
|
3271
|
+
}
|
|
3272
|
+
}
|
|
3273
|
+
out.push(ch);
|
|
3274
|
+
i++;
|
|
3275
|
+
}
|
|
3276
|
+
return out.join("");
|
|
3277
|
+
}
|
|
3278
|
+
function assertReadOnlySelect(sql) {
|
|
3279
|
+
const sanitized = sanitizeSql(sql);
|
|
3280
|
+
const statements = sanitized.split(";").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
3281
|
+
if (statements.length === 0) {
|
|
3282
|
+
return { ok: false, reason: "Empty statement" };
|
|
3283
|
+
}
|
|
3284
|
+
if (statements.length > 1) {
|
|
3285
|
+
return { ok: false, reason: "Only a single statement is allowed" };
|
|
3286
|
+
}
|
|
3287
|
+
const words = (statements[0].match(/\b[A-Za-z_][A-Za-z0-9_]*\b/g) ?? []).map(
|
|
3288
|
+
(w) => w.toUpperCase()
|
|
3289
|
+
);
|
|
3290
|
+
const first = words[0];
|
|
3291
|
+
if (first !== "SELECT" && first !== "WITH") {
|
|
3292
|
+
return { ok: false, reason: "Only SELECT statements are allowed" };
|
|
3293
|
+
}
|
|
3294
|
+
const denied = words.find((w) => DENIED_KEYWORDS.has(w));
|
|
3295
|
+
if (denied) {
|
|
3296
|
+
return { ok: false, reason: `Keyword not allowed in a read-only query: ${denied}` };
|
|
3297
|
+
}
|
|
3298
|
+
return { ok: true };
|
|
3299
|
+
}
|
|
3300
|
+
|
|
3301
|
+
// src/integrations/database/index.ts
|
|
3302
|
+
var DEFAULT_STATEMENT_TIMEOUT_MS = 1e4;
|
|
3303
|
+
var PG_QUERY_CANCELED = "57014";
|
|
3304
|
+
var PostgresDriver = class {
|
|
3305
|
+
constructor(connectionString, statementTimeoutMs) {
|
|
3306
|
+
this.pool = new Pool({
|
|
3307
|
+
connectionString,
|
|
3308
|
+
statement_timeout: statementTimeoutMs,
|
|
3309
|
+
query_timeout: statementTimeoutMs
|
|
3310
|
+
});
|
|
3311
|
+
}
|
|
3312
|
+
async query(sql, params) {
|
|
3313
|
+
const result = await this.pool.query(sql, [...params]);
|
|
3314
|
+
return {
|
|
3315
|
+
rows: result.rows,
|
|
3316
|
+
rowCount: result.rowCount ?? result.rows.length
|
|
3317
|
+
};
|
|
3318
|
+
}
|
|
3319
|
+
async end() {
|
|
3320
|
+
await this.pool.end();
|
|
3321
|
+
}
|
|
3322
|
+
};
|
|
3323
|
+
function mapDriverError(error) {
|
|
3324
|
+
if (error instanceof IntegrationError) return error;
|
|
3325
|
+
const code = error.code;
|
|
3326
|
+
if (code === PG_QUERY_CANCELED) {
|
|
3327
|
+
return new IntegrationError("Statement timeout exceeded", "TIMEOUT_ERROR");
|
|
3328
|
+
}
|
|
3329
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3330
|
+
return new IntegrationError(message, "SERVICE_ERROR");
|
|
3331
|
+
}
|
|
3332
|
+
var DatabaseIntegration = class extends BaseIntegration {
|
|
3333
|
+
constructor(config) {
|
|
3334
|
+
super(config);
|
|
3335
|
+
this.drivers = /* @__PURE__ */ new Map();
|
|
3336
|
+
const fromEnv = config.env.DATABASE_STATEMENT_TIMEOUT_MS;
|
|
3337
|
+
if (fromEnv) {
|
|
3338
|
+
const parsed = Number(fromEnv);
|
|
3339
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
3340
|
+
throw new Error(`Invalid DATABASE_STATEMENT_TIMEOUT_MS: ${fromEnv}`);
|
|
3341
|
+
}
|
|
3342
|
+
this.statementTimeoutMs = parsed;
|
|
3343
|
+
} else {
|
|
3344
|
+
this.statementTimeoutMs = config.timeout ?? DEFAULT_STATEMENT_TIMEOUT_MS;
|
|
3345
|
+
}
|
|
3346
|
+
this.logger.info("Database integration initialized", {
|
|
3347
|
+
statementTimeoutMs: this.statementTimeoutMs
|
|
3348
|
+
});
|
|
3349
|
+
}
|
|
3350
|
+
async execute(action, params) {
|
|
3351
|
+
const validation = this.validateParams(action, params);
|
|
3352
|
+
if (!validation.valid) {
|
|
3353
|
+
return {
|
|
3354
|
+
success: false,
|
|
3355
|
+
error: {
|
|
3356
|
+
name: "IntegrationError",
|
|
3357
|
+
message: "Validation failed",
|
|
3358
|
+
code: "VALIDATION_ERROR",
|
|
3359
|
+
details: validation.errors
|
|
3360
|
+
},
|
|
3361
|
+
metadata: this.createMetadata(action, 0)
|
|
3362
|
+
};
|
|
3363
|
+
}
|
|
3364
|
+
const startTime = Date.now();
|
|
3365
|
+
try {
|
|
3366
|
+
let data;
|
|
3367
|
+
switch (action) {
|
|
3368
|
+
case "query":
|
|
3369
|
+
data = await this.executeWithRetry(() => this.runQuery(params));
|
|
3370
|
+
break;
|
|
3371
|
+
default:
|
|
3372
|
+
throw new Error(`Unknown action: ${action}`);
|
|
3373
|
+
}
|
|
3374
|
+
return {
|
|
3375
|
+
success: true,
|
|
3376
|
+
data,
|
|
3377
|
+
metadata: this.createMetadata(action, Date.now() - startTime)
|
|
3378
|
+
};
|
|
3379
|
+
} catch (error) {
|
|
3380
|
+
return this.handleError(action, error);
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
async runQuery(params) {
|
|
3384
|
+
const guard = assertReadOnlySelect(params.sql);
|
|
3385
|
+
if (!guard.ok) {
|
|
3386
|
+
throw new IntegrationError(
|
|
3387
|
+
`Read-only violation: ${guard.reason ?? "not a SELECT statement"}`,
|
|
3388
|
+
"VALIDATION_ERROR"
|
|
3389
|
+
);
|
|
3390
|
+
}
|
|
3391
|
+
const driver = this.driverFor(params.connectionRef);
|
|
3392
|
+
this.logger.debug("Database QUERY", { connectionRef: params.connectionRef });
|
|
3393
|
+
try {
|
|
3394
|
+
return await driver.query(params.sql, params.params ?? []);
|
|
3395
|
+
} catch (error) {
|
|
3396
|
+
throw mapDriverError(error);
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
/** Resolve (and cache) the driver for a connection reference. */
|
|
3400
|
+
driverFor(connectionRef) {
|
|
3401
|
+
const connectionString = process.env[connectionRef];
|
|
3402
|
+
if (!connectionString) {
|
|
3403
|
+
throw new IntegrationError(
|
|
3404
|
+
`Connection reference "${connectionRef}" is not set in the environment`,
|
|
3405
|
+
"AUTH_ERROR"
|
|
3406
|
+
);
|
|
3407
|
+
}
|
|
3408
|
+
const cached = this.drivers.get(connectionString);
|
|
3409
|
+
if (cached) return cached;
|
|
3410
|
+
const driver = new PostgresDriver(connectionString, this.statementTimeoutMs);
|
|
3411
|
+
this.drivers.set(connectionString, driver);
|
|
3412
|
+
return driver;
|
|
3413
|
+
}
|
|
3414
|
+
};
|
|
3415
|
+
registerIntegration("database", DatabaseIntegration);
|
|
3416
|
+
|
|
3417
|
+
export { BaseIntegration, CLIIntegration, ConsoleLogger, DatabaseIntegration, DeepAgentIntegration, DockerIntegration, EmailIntegration, GitHubIntegration, IntegrationError, IntegrationFactory, LLMIntegration, MLIntegration, OAuthIntegration, OtelIntegration, QueueIntegration, RedisIntegration, StorageIntegration, StripeIntegration, TwilioIntegration, YouTubeIntegration, assertReadOnlySelect, getIntegration, getIntegrationFactory, getRegisteredIntegrations, isKnownIntegration, registerIntegration, resetIntegrationFactory, validateParams, verifyAndParseStripeEvent, withRetry };
|
|
3176
3418
|
//# sourceMappingURL=index.js.map
|
|
3177
3419
|
//# sourceMappingURL=index.js.map
|