@deepnote/database-integrations 1.0.0 → 1.1.1
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/LICENSE +201 -0
- package/README.md +4 -4
- package/dist/index.cjs +46 -44
- package/dist/index.d.cts +564 -31
- package/dist/index.d.ts +564 -31
- package/dist/index.js +46 -43
- package/package.json +8 -9
package/dist/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import buildUrl from "build-url-ts";
|
|
2
1
|
import { z } from "zod";
|
|
3
2
|
|
|
4
3
|
//#region src/sql-integration-auth-methods.ts
|
|
@@ -39,30 +38,35 @@ function isFederatedAuthMetadata(metadata) {
|
|
|
39
38
|
|
|
40
39
|
//#endregion
|
|
41
40
|
//#region src/snowflake-integration-env-vars.ts
|
|
41
|
+
/**
|
|
42
|
+
* Build a URL with path and query parameters using native URL API
|
|
43
|
+
*/
|
|
44
|
+
function buildUrl(baseUrl, options) {
|
|
45
|
+
const url = new URL(baseUrl.replace(/^(\w+):\/\//, "http://"));
|
|
46
|
+
if (options.path) url.pathname = options.path;
|
|
47
|
+
if (options.queryParams) {
|
|
48
|
+
for (const [key, value] of Object.entries(options.queryParams)) if (value !== void 0) url.searchParams.set(key, value);
|
|
49
|
+
}
|
|
50
|
+
return url.href.replace(/^http:\/\//, baseUrl.match(/^(\w+):\/\//)?.[0] || "http://");
|
|
51
|
+
}
|
|
42
52
|
function getSnowflakeSqlAlchemyInput(metadata, params) {
|
|
43
53
|
if (isFederatedAuthMetadata(metadata)) return null;
|
|
44
54
|
const { username, accountName, database, authMethod } = metadata;
|
|
45
|
-
if (authMethod === SnowflakeAuthMethods.ServiceAccountKeyPair) {
|
|
46
|
-
const url$1 = buildUrl(`snowflake://${encodeURIComponent(username)}@${encodeURIComponent(accountName)}`, {
|
|
47
|
-
path: database,
|
|
48
|
-
queryParams: {
|
|
49
|
-
...createBaseQueryParams(metadata, params.snowflakePartnerIdentifier),
|
|
50
|
-
authenticator: "snowflake_jwt"
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
if (!url$1) throw new Error("getSnowflakeEnvVar URL must be defined");
|
|
54
|
-
return createSqlAlchemyInputFromUrl(url$1, {
|
|
55
|
-
privateKey: metadata.privateKey,
|
|
56
|
-
password: metadata.privateKeyPassphrase,
|
|
57
|
-
username: metadata.username
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
const url = buildUrl(`snowflake://${encodeURIComponent(username)}:${encodeURIComponent(metadata.password)}@${encodeURIComponent(accountName)}`, {
|
|
55
|
+
if (authMethod === SnowflakeAuthMethods.ServiceAccountKeyPair) return createSqlAlchemyInputFromUrl(buildUrl(`snowflake://${encodeURIComponent(username)}@${encodeURIComponent(accountName)}`, {
|
|
61
56
|
path: database,
|
|
62
|
-
queryParams: {
|
|
57
|
+
queryParams: {
|
|
58
|
+
...createBaseQueryParams(metadata, params.snowflakePartnerIdentifier),
|
|
59
|
+
authenticator: "snowflake_jwt"
|
|
60
|
+
}
|
|
61
|
+
}), {
|
|
62
|
+
privateKey: metadata.privateKey,
|
|
63
|
+
password: metadata.privateKeyPassphrase,
|
|
64
|
+
username: metadata.username
|
|
63
65
|
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
return createSqlAlchemyInputFromUrl(buildUrl(`snowflake://${encodeURIComponent(username)}:${encodeURIComponent(metadata.password)}@${encodeURIComponent(accountName)}`, {
|
|
67
|
+
path: database,
|
|
68
|
+
queryParams: { ...createBaseQueryParams(metadata, params.snowflakePartnerIdentifier) }
|
|
69
|
+
}));
|
|
66
70
|
}
|
|
67
71
|
function createBaseQueryParams(metadata, snowflakePartnerIdentifier) {
|
|
68
72
|
return {
|
|
@@ -75,8 +79,8 @@ function createSqlAlchemyInputFromUrl(url, keyPair) {
|
|
|
75
79
|
return {
|
|
76
80
|
url,
|
|
77
81
|
params: keyPair ? {
|
|
78
|
-
snowflake_private_key:
|
|
79
|
-
snowflake_private_key_passphrase: keyPair.password
|
|
82
|
+
snowflake_private_key: btoa(keyPair.privateKey),
|
|
83
|
+
...keyPair.password ? { snowflake_private_key_passphrase: keyPair.password } : {}
|
|
80
84
|
} : {},
|
|
81
85
|
param_style: "pyformat"
|
|
82
86
|
};
|
|
@@ -84,10 +88,10 @@ function createSqlAlchemyInputFromUrl(url, keyPair) {
|
|
|
84
88
|
|
|
85
89
|
//#endregion
|
|
86
90
|
//#region src/database-integration-env-vars.ts
|
|
87
|
-
function
|
|
91
|
+
function getEnvironmentVariablesForIntegrations(integrations, params) {
|
|
88
92
|
const envVars = [];
|
|
89
93
|
const errors = [];
|
|
90
|
-
|
|
94
|
+
integrations.forEach((integration) => {
|
|
91
95
|
const namePrefix = convertToEnvironmentVariableName(integration.name);
|
|
92
96
|
const envVarsForThisIntegration = Object.entries(integration.metadata).map(([key, rawValue]) => {
|
|
93
97
|
const name = `${namePrefix}_${key.toUpperCase()}`;
|
|
@@ -114,11 +118,6 @@ function getIntegrationListEnv(sqlIntegrations, params) {
|
|
|
114
118
|
errors
|
|
115
119
|
};
|
|
116
120
|
}
|
|
117
|
-
const duckDbEnvVar = {
|
|
118
|
-
url: `deepnote+duckdb:///:memory:`,
|
|
119
|
-
params: {},
|
|
120
|
-
param_style: "qmark"
|
|
121
|
-
};
|
|
122
121
|
function addSslOptionsToMongoConnectionString(projectRoot, connectionString, integrationId, metadata) {
|
|
123
122
|
const [base, paramString] = connectionString.split("?");
|
|
124
123
|
const params = new URLSearchParams(paramString);
|
|
@@ -137,7 +136,7 @@ function getEnvVarForSqlCells(integration, params) {
|
|
|
137
136
|
const sqlAlchemyInput = getSqlAlchemyInput(integration, params);
|
|
138
137
|
if (!sqlAlchemyInput) return null;
|
|
139
138
|
return {
|
|
140
|
-
name:
|
|
139
|
+
name: getSqlEnvVarName(integration.id),
|
|
141
140
|
value: JSON.stringify({
|
|
142
141
|
integration_id: integration.id,
|
|
143
142
|
...sqlAlchemyInput
|
|
@@ -168,7 +167,11 @@ function getSqlAlchemyInput(integration, params) {
|
|
|
168
167
|
case "mindsdb":
|
|
169
168
|
case "mysql": return getMySqlSqlAlchemyInput(integration.id, params.projectRootDirectory, integration.metadata);
|
|
170
169
|
case "materialize": return getMaterializePostgresSqlAlchemyInput(integration.id, params.projectRootDirectory, integration.metadata);
|
|
171
|
-
case "pandas-dataframe": return {
|
|
170
|
+
case "pandas-dataframe": return {
|
|
171
|
+
url: `deepnote+duckdb:///:memory:`,
|
|
172
|
+
params: {},
|
|
173
|
+
param_style: "qmark"
|
|
174
|
+
};
|
|
172
175
|
case "redshift": return getRedshiftSqlAlchemyInput(integration.id, params.projectRootDirectory, integration.metadata);
|
|
173
176
|
case "snowflake": return getSnowflakeSqlAlchemyInput(integration.metadata, { snowflakePartnerIdentifier: params.snowflakePartnerIdentifier });
|
|
174
177
|
case "spanner": return getSpannerSqlAlchemyInput(integration.metadata);
|
|
@@ -187,7 +190,7 @@ const getDatabricksSqlAlchemyInput = ({ httpPath, host, token, port, schema, cat
|
|
|
187
190
|
} },
|
|
188
191
|
param_style: "pyformat",
|
|
189
192
|
ssh_options: {
|
|
190
|
-
enabled: String(sshEnabled),
|
|
193
|
+
enabled: sshEnabled == null ? void 0 : String(sshEnabled),
|
|
191
194
|
host: sshHost,
|
|
192
195
|
port: sshPort,
|
|
193
196
|
user: sshUser
|
|
@@ -195,7 +198,7 @@ const getDatabricksSqlAlchemyInput = ({ httpPath, host, token, port, schema, cat
|
|
|
195
198
|
};
|
|
196
199
|
};
|
|
197
200
|
const getDremioSqlAlchemyInput = ({ port, host, token, schema, sshEnabled, sshHost, sshPort, sshUser }) => {
|
|
198
|
-
const url = new URL(`dremio+flight://${host}:${port}${schema ?
|
|
201
|
+
const url = new URL(`dremio+flight://${host}:${port}${schema ? `/${schema}` : ""}`);
|
|
199
202
|
url.searchParams.set("UseEncryption", "true");
|
|
200
203
|
url.searchParams.set("Token", token);
|
|
201
204
|
return {
|
|
@@ -203,7 +206,7 @@ const getDremioSqlAlchemyInput = ({ port, host, token, schema, sshEnabled, sshHo
|
|
|
203
206
|
params: {},
|
|
204
207
|
param_style: "pyformat",
|
|
205
208
|
ssh_options: {
|
|
206
|
-
enabled: String(sshEnabled),
|
|
209
|
+
enabled: sshEnabled == null ? void 0 : String(sshEnabled),
|
|
207
210
|
host: sshHost,
|
|
208
211
|
port: sshPort,
|
|
209
212
|
user: sshUser
|
|
@@ -217,7 +220,7 @@ const getSQLServerVar = ({ user, password, host, port, database, sshEnabled, ssh
|
|
|
217
220
|
params: {},
|
|
218
221
|
param_style: "pyformat",
|
|
219
222
|
ssh_options: {
|
|
220
|
-
enabled: String(sshEnabled),
|
|
223
|
+
enabled: sshEnabled == null ? void 0 : String(sshEnabled),
|
|
221
224
|
host: sshHost,
|
|
222
225
|
port: sshPort,
|
|
223
226
|
user: sshUser
|
|
@@ -243,7 +246,7 @@ const getPostgresSqlAlchemyInput = (integrationId, projectRootDirectory, { user,
|
|
|
243
246
|
} },
|
|
244
247
|
param_style: "pyformat",
|
|
245
248
|
ssh_options: {
|
|
246
|
-
enabled: String(sshEnabled),
|
|
249
|
+
enabled: sshEnabled == null ? void 0 : String(sshEnabled),
|
|
247
250
|
host: sshHost,
|
|
248
251
|
port: sshPort,
|
|
249
252
|
user: sshUser
|
|
@@ -271,7 +274,7 @@ const getRedshiftSqlAlchemyInput = (integrationId, projectRootDirectory, metadat
|
|
|
271
274
|
} },
|
|
272
275
|
param_style: "pyformat",
|
|
273
276
|
ssh_options: {
|
|
274
|
-
enabled: String(metadata.sshEnabled),
|
|
277
|
+
enabled: metadata.sshEnabled == null ? void 0 : String(metadata.sshEnabled),
|
|
275
278
|
host: metadata.sshHost,
|
|
276
279
|
port: metadata.sshPort,
|
|
277
280
|
user: metadata.sshUser
|
|
@@ -303,7 +306,7 @@ const getMaterializePostgresSqlAlchemyInput = (integrationId, projectRootDirecto
|
|
|
303
306
|
} },
|
|
304
307
|
param_style: "pyformat",
|
|
305
308
|
ssh_options: {
|
|
306
|
-
enabled: String(sshEnabled),
|
|
309
|
+
enabled: sshEnabled == null ? void 0 : String(sshEnabled),
|
|
307
310
|
host: sshHost,
|
|
308
311
|
port: sshPort,
|
|
309
312
|
user: sshUser
|
|
@@ -356,7 +359,7 @@ const getClickHouseSqlAlchemyInput = (integrationId, projectRootDirectory, { use
|
|
|
356
359
|
params: {},
|
|
357
360
|
param_style: "pyformat",
|
|
358
361
|
ssh_options: {
|
|
359
|
-
enabled: String(sshEnabled),
|
|
362
|
+
enabled: sshEnabled == null ? void 0 : String(sshEnabled),
|
|
360
363
|
host: sshHost,
|
|
361
364
|
port: sshPort,
|
|
362
365
|
user: sshUser
|
|
@@ -422,7 +425,7 @@ const getMySqlSqlAlchemyInput = (integrationId, projectRootDirectory, { user, pa
|
|
|
422
425
|
params: { connect_args: { ssl } },
|
|
423
426
|
param_style: "pyformat",
|
|
424
427
|
ssh_options: {
|
|
425
|
-
enabled: String(sshEnabled),
|
|
428
|
+
enabled: sshEnabled == null ? void 0 : String(sshEnabled),
|
|
426
429
|
host: sshHost,
|
|
427
430
|
port: sshPort,
|
|
428
431
|
user: sshUser
|
|
@@ -430,13 +433,13 @@ const getMySqlSqlAlchemyInput = (integrationId, projectRootDirectory, { user, pa
|
|
|
430
433
|
};
|
|
431
434
|
};
|
|
432
435
|
function getCACertificatePath({ projectRoot, integrationId, caCertificateName }) {
|
|
433
|
-
return `${projectRoot
|
|
436
|
+
return `${projectRoot}/.deepnote/${integrationId}/${caCertificateName}`;
|
|
434
437
|
}
|
|
435
438
|
function convertToEnvironmentVariableName(str) {
|
|
436
439
|
return (/^\d/.test(str) ? `_${str}` : str).toUpperCase().replace(/[^\w]/g, "_");
|
|
437
440
|
}
|
|
438
441
|
function getSqlEnvVarName(integrationId) {
|
|
439
|
-
return `SQL_${integrationId}
|
|
442
|
+
return convertToEnvironmentVariableName(`SQL_${integrationId}`);
|
|
440
443
|
}
|
|
441
444
|
function assertNever(value) {
|
|
442
445
|
throw new Error(`Unexpected value: ${value}`);
|
|
@@ -693,4 +696,4 @@ const databaseIntegrationTypesWithSslSupport = [
|
|
|
693
696
|
];
|
|
694
697
|
|
|
695
698
|
//#endregion
|
|
696
|
-
export { AwsAuthMethods, BigQueryAuthMethods, BigQueryServiceAccountParseError, DatabaseAuthMethods, SnowflakeAuthMethods, SpannerServiceAccountParseError, databaseIntegrationTypes, databaseIntegrationTypesWithSslSupport, databaseMetadataSchemasByType,
|
|
699
|
+
export { AwsAuthMethods, BigQueryAuthMethods, BigQueryServiceAccountParseError, DatabaseAuthMethods, SnowflakeAuthMethods, SpannerServiceAccountParseError, databaseIntegrationTypes, databaseIntegrationTypesWithSslSupport, databaseMetadataSchemasByType, getEnvironmentVariablesForIntegrations, getSqlAlchemyInput, isFederatedAuthMetadata, isFederatedAuthMethod, sqlIntegrationTypes };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepnote/database-integrations",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Deepnote database integration definitions",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"repository": {
|
|
@@ -26,17 +26,16 @@
|
|
|
26
26
|
"LICENSE",
|
|
27
27
|
"package.json"
|
|
28
28
|
],
|
|
29
|
-
"scripts": {
|
|
30
|
-
"build": "tsdown --format esm --format cjs --dts",
|
|
31
|
-
"test": "vitest",
|
|
32
|
-
"watch": "tsdown --watch --format esm --format cjs --dts"
|
|
33
|
-
},
|
|
34
29
|
"dependencies": {
|
|
35
|
-
"
|
|
36
|
-
"zod": "^4.1.12"
|
|
30
|
+
"zod": "3.25.76"
|
|
37
31
|
},
|
|
38
32
|
"publishConfig": {
|
|
39
33
|
"access": "public",
|
|
40
34
|
"registry": "https://registry.npmjs.org"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsdown --format esm --format cjs --dts",
|
|
38
|
+
"test": "vitest",
|
|
39
|
+
"watch": "tsdown --watch --format esm --format cjs --dts"
|
|
41
40
|
}
|
|
42
|
-
}
|
|
41
|
+
}
|