@deepnote/database-integrations 1.7.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import z, { z as z$1 } from "zod";
2
+ import { convertToEnvironmentVariableName, parseYaml } from "@deepnote/blocks";
2
3
  import { isMap, isSeq, parseDocument } from "yaml";
3
- import { parseYaml } from "@deepnote/blocks";
4
4
  //#region src/sql-integration-auth-methods.ts
5
5
  const AwsAuthMethods = {
6
6
  AccessKeys: "access-keys",
@@ -404,6 +404,73 @@ const databaseIntegrationConfigSchema = z.discriminatedUnion("type", [
404
404
  })
405
405
  ]);
406
406
  //#endregion
407
+ //#region src/secret-field-paths.ts
408
+ /**
409
+ * All secret fields for each integration type.
410
+ * This includes all possible secret fields regardless of auth method.
411
+ *
412
+ * Note: For integrations with multiple auth methods (e.g., snowflake, bigquery),
413
+ * this includes all secret fields from all auth variants.
414
+ */
415
+ const SECRET_PATHS = {
416
+ alloydb: ["password", "caCertificateText"],
417
+ mariadb: ["password", "caCertificateText"],
418
+ materialize: ["password", "caCertificateText"],
419
+ mindsdb: ["password", "caCertificateText"],
420
+ mysql: ["password", "caCertificateText"],
421
+ pgsql: ["password", "caCertificateText"],
422
+ "sql-server": ["password"],
423
+ clickhouse: ["password", "caCertificateText"],
424
+ databricks: ["token"],
425
+ dremio: ["token"],
426
+ athena: ["secret_access_key"],
427
+ spanner: ["service_account"],
428
+ "cloud-sql": ["service_account"],
429
+ mongodb: [
430
+ "password",
431
+ "connection_string",
432
+ "rawConnectionString",
433
+ "caCertificateText"
434
+ ],
435
+ "pandas-dataframe": [],
436
+ "big-query": ["service_account", "clientSecret"],
437
+ snowflake: [
438
+ "password",
439
+ "clientSecret",
440
+ "privateKey",
441
+ "privateKeyPassphrase",
442
+ "dbtServiceToken"
443
+ ],
444
+ redshift: ["password", "caCertificateText"],
445
+ trino: [
446
+ "password",
447
+ "clientSecret",
448
+ "caCertificateText"
449
+ ]
450
+ };
451
+ /**
452
+ * Get the list of secret field paths for a given integration type.
453
+ *
454
+ * @param type - The integration type (e.g., 'pgsql', 'snowflake')
455
+ * @returns Array of field names that contain secrets
456
+ *
457
+ * @example
458
+ * getSecretFieldPaths('pgsql') // => ['password', 'caCertificateText']
459
+ * getSecretFieldPaths('snowflake') // => ['password', 'clientSecret', 'privateKey', 'privateKeyPassphrase', 'dbtServiceToken']
460
+ */
461
+ function getSecretFieldPaths(type) {
462
+ return SECRET_PATHS[type] ?? [];
463
+ }
464
+ /**
465
+ * Whether `key` is a secret field of an integration whose `metadata.authMethod` is federated.
466
+ * Such integrations authenticate each user with their own identity, so the value never needs
467
+ * to reach notebook code.
468
+ */
469
+ function isFederatedAuthSecretField(type, metadata, key) {
470
+ const { authMethod } = metadata;
471
+ return typeof authMethod === "string" && isFederatedAuthMethod(authMethod) && getSecretFieldPaths(type).includes(key);
472
+ }
473
+ //#endregion
407
474
  //#region src/snowflake-integration-env-vars.ts
408
475
  /**
409
476
  * Build a URL with path and query parameters using native URL API
@@ -476,7 +543,7 @@ function getEnvironmentVariablesForIntegrations(integrations, params) {
476
543
  integrations.forEach((integration) => {
477
544
  const namePrefix = convertToEnvironmentVariableName(integration.name);
478
545
  const envVarsForThisIntegration = Object.entries(integration.metadata).filter(([key]) => {
479
- return key !== "caCertificateText";
546
+ return key !== "caCertificateText" && !isFederatedAuthSecretField(integration.type, integration.metadata, key);
480
547
  }).map(([key, rawValue]) => {
481
548
  const name = `${namePrefix}_${key.toUpperCase()}`;
482
549
  const value = String(rawValue);
@@ -774,6 +841,21 @@ const getBigQuerySqlAlchemyInput = (metadata) => {
774
841
  throw new BigQueryServiceAccountParseError("Failed to parse bigquery service account, returning empty environment variable.", { cause: error instanceof Error ? error : new Error(String(error)) });
775
842
  }
776
843
  };
844
+ /**
845
+ * @returns sql alchemy input for a BigQuery integration authenticated via Google OAuth, given an
846
+ * access token minted by the caller. `user_supplied_client=true` tells the runtime to build its
847
+ * BigQuery client from `access_token` / `project` instead of a service account.
848
+ */
849
+ function getBigQueryOAuthSqlAlchemyInput(metadata, accessToken) {
850
+ return {
851
+ url: "bigquery://?user_supplied_client=true",
852
+ params: {
853
+ access_token: accessToken,
854
+ project: metadata.project
855
+ },
856
+ param_style: "pyformat"
857
+ };
858
+ }
777
859
  var SpannerServiceAccountParseError = class extends Error {
778
860
  cause;
779
861
  constructor(message, params) {
@@ -823,9 +905,6 @@ const getMySqlSqlAlchemyInput = (integrationId, projectRootDirectory, { user, pa
823
905
  function getCACertificatePath({ projectRoot, integrationId, caCertificateName }) {
824
906
  return `${projectRoot}/.deepnote/${integrationId}/${caCertificateName}`;
825
907
  }
826
- function convertToEnvironmentVariableName(str) {
827
- return (/^\d/.test(str) ? `_${str}` : str).toUpperCase().replace(/[^\w]/g, "_");
828
- }
829
908
  function getSqlEnvVarName(integrationId) {
830
909
  return convertToEnvironmentVariableName(`SQL_${integrationId}`);
831
910
  }
@@ -994,7 +1073,7 @@ const apiIntegrationSchema = z$1.object({
994
1073
  id: z$1.string(),
995
1074
  name: z$1.string(),
996
1075
  type: z$1.string(),
997
- metadata: z$1.unknown(),
1076
+ metadata: z$1.unknown().optional(),
998
1077
  is_public: z$1.boolean().nullish(),
999
1078
  created_at: z$1.string().nullish(),
1000
1079
  updated_at: z$1.string().nullish(),
@@ -1103,67 +1182,9 @@ function serializeIntegrationsDocument(doc) {
1103
1182
  * ...
1104
1183
  * ```
1105
1184
  */
1106
- const baseIntegrationsFileSchema = z$1.object({ integrations: z$1.array(z$1.record(z$1.unknown())).optional().default([]) });
1185
+ const baseIntegrationsFileSchema = z$1.object({ integrations: z$1.array(z$1.record(z$1.string(), z$1.unknown())).optional().default([]) });
1107
1186
  const integrationsFileSchema = z$1.object({ integrations: z$1.array(databaseIntegrationConfigSchema) });
1108
1187
  //#endregion
1109
- //#region src/secret-field-paths.ts
1110
- /**
1111
- * All secret fields for each integration type.
1112
- * This includes all possible secret fields regardless of auth method.
1113
- *
1114
- * Note: For integrations with multiple auth methods (e.g., snowflake, bigquery),
1115
- * this includes all secret fields from all auth variants.
1116
- */
1117
- const SECRET_PATHS = {
1118
- alloydb: ["password", "caCertificateText"],
1119
- mariadb: ["password", "caCertificateText"],
1120
- materialize: ["password", "caCertificateText"],
1121
- mindsdb: ["password", "caCertificateText"],
1122
- mysql: ["password", "caCertificateText"],
1123
- pgsql: ["password", "caCertificateText"],
1124
- "sql-server": ["password"],
1125
- clickhouse: ["password", "caCertificateText"],
1126
- databricks: ["token"],
1127
- dremio: ["token"],
1128
- athena: ["secret_access_key"],
1129
- spanner: ["service_account"],
1130
- "cloud-sql": ["service_account"],
1131
- mongodb: [
1132
- "password",
1133
- "connection_string",
1134
- "rawConnectionString",
1135
- "caCertificateText"
1136
- ],
1137
- "pandas-dataframe": [],
1138
- "big-query": ["service_account", "clientSecret"],
1139
- snowflake: [
1140
- "password",
1141
- "clientSecret",
1142
- "privateKey",
1143
- "privateKeyPassphrase",
1144
- "dbtServiceToken"
1145
- ],
1146
- redshift: ["password", "caCertificateText"],
1147
- trino: [
1148
- "password",
1149
- "clientSecret",
1150
- "caCertificateText"
1151
- ]
1152
- };
1153
- /**
1154
- * Get the list of secret field paths for a given integration type.
1155
- *
1156
- * @param type - The integration type (e.g., 'pgsql', 'snowflake')
1157
- * @returns Array of field names that contain secrets
1158
- *
1159
- * @example
1160
- * getSecretFieldPaths('pgsql') // => ['password', 'caCertificateText']
1161
- * getSecretFieldPaths('snowflake') // => ['password', 'clientSecret', 'privateKey', 'privateKeyPassphrase', 'dbtServiceToken']
1162
- */
1163
- function getSecretFieldPaths(type) {
1164
- return SECRET_PATHS[type] ?? [];
1165
- }
1166
- //#endregion
1167
1188
  //#region src/loading/merge-integrations.ts
1168
1189
  /**
1169
1190
  * JSON schema URL for the integrations file.
@@ -1504,4 +1525,4 @@ function parseIntegrations({ yaml, env = {} }) {
1504
1525
  };
1505
1526
  }
1506
1527
  //#endregion
1507
- export { ApiError, AwsAuthMethods, BUILTIN_INTEGRATIONS, BigQueryAuthMethods, BigQueryServiceAccountParseError, DEFAULT_API_URL, DEFAULT_ENV_FILE, DEFAULT_INTEGRATIONS_FILE, DatabaseAuthMethods, ENV_VAR_REF_PREFIX, EnvVarResolutionError, IntegrationsYamlParseError, InvalidIntegrationError, InvalidIntegrationsTypeError, JSON_SCHEMA_URL, SCHEMA_COMMENT, SnowflakeAuthMethods, SpannerServiceAccountParseError, TrinoAuthMethods, addIntegrationToSeq, apiIntegrationSchema, apiResponseSchema, baseIntegrationsFileSchema, convertApiIntegrations, createEnvVarRef, createNewDocument, databaseIntegrationConfigSchema, databaseIntegrationTypes, databaseIntegrationTypesWithSslSupport, databaseMetadataSchemasByType, extractEnvVarName, federatedAuthMethods, fetchIntegrations, generateEnvVarName, getEnvironmentVariablesForIntegrations, getOrCreateIntegrationMetadata, getOrCreateIntegrationsFromDocument, getSecretFieldPaths, getSnowflakeFederatedAuthSqlAlchemyInput, getSqlAlchemyInput, getSqlEnvVarName, integrationsFileSchema, isBuiltinIntegration, isDatabaseIntegrationType, isDatabaseIntegrationTypeWithSslSupport, isEnvVarRef, isFederatedAuthMetadata, isFederatedAuthMethod, isSqlIntegrationType, mergeApiIntegrationsIntoDocument, mergeApiIntegrationsIntoYaml, mergeProcessedIntegrations, parseEnvVarRef, parseIntegrations, parseIntegrationsDocument, resolveEnvVarRefsFromMap, serializeIntegrationsDocument, sqlIntegrationTypes, updateIntegrationInDocument, updateIntegrationMetadataMap };
1528
+ export { ApiError, AwsAuthMethods, BUILTIN_INTEGRATIONS, BigQueryAuthMethods, BigQueryServiceAccountParseError, DEFAULT_API_URL, DEFAULT_ENV_FILE, DEFAULT_INTEGRATIONS_FILE, DatabaseAuthMethods, ENV_VAR_REF_PREFIX, EnvVarResolutionError, IntegrationsYamlParseError, InvalidIntegrationError, InvalidIntegrationsTypeError, JSON_SCHEMA_URL, SCHEMA_COMMENT, SnowflakeAuthMethods, SpannerServiceAccountParseError, TrinoAuthMethods, addIntegrationToSeq, apiIntegrationSchema, apiResponseSchema, baseIntegrationsFileSchema, convertApiIntegrations, createEnvVarRef, createNewDocument, databaseIntegrationConfigSchema, databaseIntegrationTypes, databaseIntegrationTypesWithSslSupport, databaseMetadataSchemasByType, extractEnvVarName, federatedAuthMethods, fetchIntegrations, generateEnvVarName, getBigQueryOAuthSqlAlchemyInput, getEnvironmentVariablesForIntegrations, getOrCreateIntegrationMetadata, getOrCreateIntegrationsFromDocument, getSecretFieldPaths, getSnowflakeFederatedAuthSqlAlchemyInput, getSqlAlchemyInput, getSqlEnvVarName, integrationsFileSchema, isBuiltinIntegration, isDatabaseIntegrationType, isDatabaseIntegrationTypeWithSslSupport, isEnvVarRef, isFederatedAuthMetadata, isFederatedAuthMethod, isFederatedAuthSecretField, isSqlIntegrationType, mergeApiIntegrationsIntoDocument, mergeApiIntegrationsIntoYaml, mergeProcessedIntegrations, parseEnvVarRef, parseIntegrations, parseIntegrationsDocument, resolveEnvVarRefsFromMap, serializeIntegrationsDocument, sqlIntegrationTypes, updateIntegrationInDocument, updateIntegrationMetadataMap };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepnote/database-integrations",
3
- "version": "1.7.1",
3
+ "version": "2.1.0",
4
4
  "description": "Deepnote database integration definitions",
5
5
  "keywords": [],
6
6
  "repository": {
@@ -28,8 +28,8 @@
28
28
  ],
29
29
  "dependencies": {
30
30
  "yaml": "^2.9.0",
31
- "zod": "3.25.76",
32
- "@deepnote/blocks": "4.8.1"
31
+ "zod": "^4.6.7",
32
+ "@deepnote/blocks": "5.0.0"
33
33
  },
34
34
  "publishConfig": {
35
35
  "access": "public",