@deepnote/database-integrations 1.5.0 → 1.7.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.cjs CHANGED
@@ -1,4 +1,5 @@
1
- //#region rolldown:runtime
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -15,19 +16,15 @@ var __copyProps = (to, from, except, desc) => {
15
16
  }
16
17
  return to;
17
18
  };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
19
20
  value: mod,
20
21
  enumerable: true
21
22
  }) : target, mod));
22
-
23
23
  //#endregion
24
24
  let zod = require("zod");
25
- zod = __toESM(zod);
25
+ zod = __toESM(zod, 1);
26
26
  let yaml = require("yaml");
27
- yaml = __toESM(yaml);
28
- let __deepnote_blocks = require("@deepnote/blocks");
29
- __deepnote_blocks = __toESM(__deepnote_blocks);
30
-
27
+ let _deepnote_blocks = require("@deepnote/blocks");
31
28
  //#region src/sql-integration-auth-methods.ts
32
29
  const AwsAuthMethods = {
33
30
  AccessKeys: "access-keys",
@@ -68,7 +65,6 @@ function isFederatedAuthMethod(authMethod) {
68
65
  function isFederatedAuthMetadata(metadata) {
69
66
  return metadata.authMethod !== void 0 && isFederatedAuthMethod(metadata.authMethod);
70
67
  }
71
-
72
68
  //#endregion
73
69
  //#region src/database-integration-metadata-schemas.ts
74
70
  const athenaMetadataSchema = zod.z.object({
@@ -296,8 +292,6 @@ const pgsqlMetadataSchema = commonDatabaseSchema.extend({
296
292
  caCertificateName: zod.z.string().optional(),
297
293
  caCertificateText: zod.z.string().optional()
298
294
  });
299
- const materializeMetadataSchema = pgsqlMetadataSchema.extend({ cluster: zod.z.string() });
300
- const sqlServerMetadataSchema = commonDatabaseSchema.extend({ port: zod.z.string() });
301
295
  const databaseMetadataSchemasByType = {
302
296
  "alloydb": alloydbMetadataSchema,
303
297
  "athena": athenaMetadataSchema,
@@ -307,7 +301,7 @@ const databaseMetadataSchemasByType = {
307
301
  "databricks": databricksMetadataSchema,
308
302
  "dremio": dremioMetadataSchema,
309
303
  "mariadb": mariadbMetadataSchema,
310
- "materialize": materializeMetadataSchema,
304
+ "materialize": pgsqlMetadataSchema.extend({ cluster: zod.z.string() }),
311
305
  "mindsdb": mindsdbMetadataSchema,
312
306
  "mongodb": mongodbMetadataSchema,
313
307
  "mysql": mysqlMetadataSchema,
@@ -316,10 +310,9 @@ const databaseMetadataSchemasByType = {
316
310
  "redshift": redshiftMetadataSchema,
317
311
  "snowflake": snowflakeMetadataSchema,
318
312
  "spanner": spannerMetadataSchema,
319
- "sql-server": sqlServerMetadataSchema,
313
+ "sql-server": commonDatabaseSchema.extend({ port: zod.z.string() }),
320
314
  "trino": trinoMetadataSchema
321
315
  };
322
-
323
316
  //#endregion
324
317
  //#region src/database-integration-config.ts
325
318
  const commonIntegrationConfig = zod.default.object({
@@ -434,7 +427,6 @@ const databaseIntegrationConfigSchema = zod.default.discriminatedUnion("type", [
434
427
  federated_auth_method: zod.default.enum(["trino-oauth", "password"]).optional().nullable()
435
428
  })
436
429
  ]);
437
-
438
430
  //#endregion
439
431
  //#region src/snowflake-integration-env-vars.ts
440
432
  /**
@@ -500,7 +492,6 @@ function createSqlAlchemyInputFromUrl(url, keyPair) {
500
492
  param_style: "pyformat"
501
493
  };
502
494
  }
503
-
504
495
  //#endregion
505
496
  //#region src/database-integration-env-vars.ts
506
497
  function getEnvironmentVariablesForIntegrations(integrations, params) {
@@ -865,7 +856,6 @@ function getSqlEnvVarName(integrationId) {
865
856
  function assertNever(value) {
866
857
  throw new Error(`Unexpected value: ${value}`);
867
858
  }
868
-
869
859
  //#endregion
870
860
  //#region src/database-integration-types.ts
871
861
  const sqlIntegrationTypes = [
@@ -910,7 +900,6 @@ function isSqlIntegrationType(type) {
910
900
  function isDatabaseIntegrationTypeWithSslSupport(type) {
911
901
  return databaseIntegrationTypesWithSslSupport.includes(type);
912
902
  }
913
-
914
903
  //#endregion
915
904
  //#region src/loading/api-error.ts
916
905
  /**
@@ -924,18 +913,31 @@ var ApiError = class extends Error {
924
913
  this.statusCode = statusCode;
925
914
  }
926
915
  };
927
-
928
916
  //#endregion
929
917
  //#region src/loading/constants.ts
930
- /** Built-in integrations that don't require external configuration. */
931
- const BUILTIN_INTEGRATIONS = new Set(["deepnote-dataframe-sql", "pandas-dataframe"]);
918
+ /** Built-in integrations that don't require external configuration. Keys are canonical lowercase IDs. */
919
+ const BUILTIN_INTEGRATIONS = /* @__PURE__ */ new Set(["deepnote-dataframe-sql", "pandas-dataframe"]);
920
+ /**
921
+ * Return whether the given integration ID refers to a built-in integration.
922
+ *
923
+ * The comparison is case-insensitive: built-in IDs are stored as canonical
924
+ * lowercase strings in {@link BUILTIN_INTEGRATIONS}, and SQL block metadata may
925
+ * reference them in any casing (e.g. `Pandas-DataFrame`). This mirrors the
926
+ * case-insensitive env-var derivation in `getSqlEnvVarName`, so a built-in is
927
+ * recognized regardless of how a notebook cased its `sql_integration_id`.
928
+ *
929
+ * @param integrationId - The integration ID from SQL block metadata.
930
+ * @returns `true` when the ID matches a built-in integration regardless of casing.
931
+ */
932
+ function isBuiltinIntegration(integrationId) {
933
+ return BUILTIN_INTEGRATIONS.has(integrationId.toLowerCase());
934
+ }
932
935
  /** Default `.env` file name for storing integration secrets. */
933
936
  const DEFAULT_ENV_FILE = ".env";
934
937
  /** Default integrations file name. */
935
938
  const DEFAULT_INTEGRATIONS_FILE = ".deepnote.env.yaml";
936
939
  /** Default Deepnote API base URL. */
937
940
  const DEFAULT_API_URL = "https://api.deepnote.com";
938
-
939
941
  //#endregion
940
942
  //#region src/loading/env-var-refs.ts
941
943
  const ENV_VAR_REF_PREFIX = "env:";
@@ -944,7 +946,7 @@ function generateEnvVarName(integrationId, fieldPath) {
944
946
  }
945
947
  function parseEnvVarRef(value) {
946
948
  if (typeof value !== "string") return null;
947
- if (!value.startsWith(ENV_VAR_REF_PREFIX)) return null;
949
+ if (!value.startsWith("env:")) return null;
948
950
  const varName = value.slice(4);
949
951
  if (!varName) return null;
950
952
  return {
@@ -1007,7 +1009,6 @@ function resolveEnvVarRefsFromMap(obj, vars, currentPath) {
1007
1009
  }
1008
1010
  return obj;
1009
1011
  }
1010
-
1011
1012
  //#endregion
1012
1013
  //#region src/loading/fetch-integrations.ts
1013
1014
  /**
@@ -1018,15 +1019,19 @@ const apiIntegrationSchema = zod.z.object({
1018
1019
  name: zod.z.string(),
1019
1020
  type: zod.z.string(),
1020
1021
  metadata: zod.z.unknown(),
1021
- is_public: zod.z.boolean(),
1022
- created_at: zod.z.string(),
1023
- updated_at: zod.z.string(),
1024
- federated_auth_method: zod.z.string().nullable()
1022
+ is_public: zod.z.boolean().nullish(),
1023
+ created_at: zod.z.string().nullish(),
1024
+ updated_at: zod.z.string().nullish(),
1025
+ federated_auth_method: zod.z.string().nullish()
1025
1026
  }).passthrough();
1026
1027
  /**
1027
1028
  * Schema for the full API response.
1028
1029
  */
1029
1030
  const apiResponseSchema = zod.z.object({ integrations: zod.z.array(apiIntegrationSchema) }).passthrough();
1031
+ const REQUEST_TIMEOUT_MS = 3e4;
1032
+ function trimTrailingSlash(url) {
1033
+ return url.replace(/\/+$/, "");
1034
+ }
1030
1035
  /**
1031
1036
  * Fetch integrations from the Deepnote API.
1032
1037
  *
@@ -1034,21 +1039,25 @@ const apiResponseSchema = zod.z.object({ integrations: zod.z.array(apiIntegratio
1034
1039
  *
1035
1040
  * @param baseUrl - The base URL of the Deepnote API
1036
1041
  * @param token - The authentication token
1037
- * @param integrationIds - Optional list of integration IDs to fetch. When provided, only these integrations are returned.
1042
+ * @param integrationIds - Optional list of integration UUIDs to fetch. When provided, only these integrations are returned.
1038
1043
  * @returns Array of integrations from the API
1039
1044
  * @throws ApiError if the request fails
1040
1045
  */
1041
1046
  async function fetchIntegrations(baseUrl, token, integrationIds) {
1042
- const endpoint = new URL(`${baseUrl}/v2/integrations`);
1047
+ const endpoint = new URL(`${trimTrailingSlash(baseUrl)}/v2/integrations`);
1043
1048
  endpoint.searchParams.set("includeMetadata", "true");
1044
- if (integrationIds && integrationIds.length > 0) endpoint.searchParams.set("integrationIds", integrationIds.join(","));
1049
+ if (integrationIds && integrationIds.length > 0) {
1050
+ const normalizedIntegrationIds = new Set(integrationIds.map((id) => id.toLowerCase()));
1051
+ endpoint.searchParams.set("integrationIds", Array.from(normalizedIntegrationIds).join(","));
1052
+ }
1045
1053
  const url = endpoint.toString();
1046
1054
  const response = await fetch(url, {
1047
1055
  method: "GET",
1048
1056
  headers: {
1049
1057
  Authorization: `Bearer ${token}`,
1050
1058
  "Content-Type": "application/json"
1051
- }
1059
+ },
1060
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
1052
1061
  });
1053
1062
  if (!response.ok) {
1054
1063
  if (response.status === 401) throw new ApiError(401, "Authentication failed. Please check your API token.");
@@ -1060,21 +1069,38 @@ async function fetchIntegrations(baseUrl, token, integrationIds) {
1060
1069
  if (!parseResult.success) throw new Error(`Invalid API response: ${parseResult.error.message}`);
1061
1070
  return parseResult.data.integrations;
1062
1071
  }
1063
-
1064
1072
  //#endregion
1065
1073
  //#region src/loading/integrations-document.ts
1066
1074
  /**
1075
+ * Error thrown when integrations YAML content cannot be parsed.
1076
+ */
1077
+ var IntegrationsYamlParseError = class extends Error {
1078
+ /** The underlying parse errors reported by the `yaml` library. */
1079
+ errors;
1080
+ constructor(errors) {
1081
+ super(`Failed to parse integrations YAML: ${errors[0]?.message ?? "unknown parse error"}`);
1082
+ this.name = "IntegrationsYamlParseError";
1083
+ this.errors = errors;
1084
+ }
1085
+ };
1086
+ /**
1067
1087
  * Parse integrations YAML content into a mutable `yaml` Document that preserves
1068
1088
  * comments and formatting. Returns `null` for empty content.
1069
1089
  *
1070
1090
  * This is the content-accepting counterpart of the Node-only `readIntegrationsDocument`.
1091
+ *
1092
+ * @throws {IntegrationsYamlParseError} If the content is not valid YAML. Malformed
1093
+ * content is rejected here rather than at serialization time, where `yaml` would
1094
+ * otherwise fail with an opaque "Document with errors cannot be stringified".
1071
1095
  */
1072
1096
  function parseIntegrationsDocument(content) {
1073
1097
  if (!content.trim()) return null;
1074
- return (0, yaml.parseDocument)(content, {
1098
+ const doc = (0, yaml.parseDocument)(content, {
1075
1099
  strict: true,
1076
1100
  version: "1.2"
1077
1101
  });
1102
+ if (doc.errors.length > 0) throw new IntegrationsYamlParseError(doc.errors);
1103
+ return doc;
1078
1104
  }
1079
1105
  /**
1080
1106
  * Serialize an integrations Document back to YAML text, preserving comments and
@@ -1083,7 +1109,6 @@ function parseIntegrationsDocument(content) {
1083
1109
  function serializeIntegrationsDocument(doc) {
1084
1110
  return doc.toString({ lineWidth: 0 });
1085
1111
  }
1086
-
1087
1112
  //#endregion
1088
1113
  //#region src/loading/integrations-file-schema.ts
1089
1114
  /**
@@ -1104,7 +1129,6 @@ function serializeIntegrationsDocument(doc) {
1104
1129
  */
1105
1130
  const baseIntegrationsFileSchema = zod.z.object({ integrations: zod.z.array(zod.z.record(zod.z.unknown())).optional().default([]) });
1106
1131
  const integrationsFileSchema = zod.z.object({ integrations: zod.z.array(databaseIntegrationConfigSchema) });
1107
-
1108
1132
  //#endregion
1109
1133
  //#region src/secret-field-paths.ts
1110
1134
  /**
@@ -1140,7 +1164,8 @@ const SECRET_PATHS = {
1140
1164
  "password",
1141
1165
  "clientSecret",
1142
1166
  "privateKey",
1143
- "privateKeyPassphrase"
1167
+ "privateKeyPassphrase",
1168
+ "dbtServiceToken"
1144
1169
  ],
1145
1170
  redshift: ["password", "caCertificateText"],
1146
1171
  trino: [
@@ -1157,12 +1182,11 @@ const SECRET_PATHS = {
1157
1182
  *
1158
1183
  * @example
1159
1184
  * getSecretFieldPaths('pgsql') // => ['password', 'caCertificateText']
1160
- * getSecretFieldPaths('snowflake') // => ['password', 'clientSecret', 'privateKey', 'privateKeyPassphrase']
1185
+ * getSecretFieldPaths('snowflake') // => ['password', 'clientSecret', 'privateKey', 'privateKeyPassphrase', 'dbtServiceToken']
1161
1186
  */
1162
1187
  function getSecretFieldPaths(type) {
1163
1188
  return SECRET_PATHS[type] ?? [];
1164
1189
  }
1165
-
1166
1190
  //#endregion
1167
1191
  //#region src/loading/merge-integrations.ts
1168
1192
  /**
@@ -1232,7 +1256,7 @@ function updateIntegrationMetadataMap({ metadataMap, integrationId, integrationM
1232
1256
  * @returns Record of extracted secrets (envVarName -> secretValue)
1233
1257
  */
1234
1258
  function updateIntegrationInDocument(doc, integrationMap, integration) {
1235
- const { id, name, type, metadata, federated_auth_method,...rest } = integration;
1259
+ const { id, name, type, metadata, federated_auth_method, ...rest } = integration;
1236
1260
  integrationMap.set("id", id);
1237
1261
  integrationMap.set("name", name);
1238
1262
  integrationMap.set("type", type);
@@ -1255,7 +1279,7 @@ function updateIntegrationInDocument(doc, integrationMap, integration) {
1255
1279
  */
1256
1280
  function addIntegrationToSeq(doc, integrationsSeq, integration) {
1257
1281
  const secretPaths = getSecretFieldPaths(integration.type);
1258
- const { metadata,...restIntegration } = integration;
1282
+ const { metadata, ...restIntegration } = integration;
1259
1283
  const integrationMap = doc.createNode(restIntegration);
1260
1284
  const metadataMap = doc.createNode({});
1261
1285
  const secrets = updateIntegrationMetadataMap({
@@ -1382,7 +1406,6 @@ function mergeApiIntegrationsIntoDocument(doc, apiIntegrations) {
1382
1406
  skipped
1383
1407
  };
1384
1408
  }
1385
-
1386
1409
  //#endregion
1387
1410
  //#region src/loading/merge-into-yaml.ts
1388
1411
  /**
@@ -1396,6 +1419,14 @@ function mergeApiIntegrationsIntoDocument(doc, apiIntegrations) {
1396
1419
  *
1397
1420
  * @param existingContent - Current YAML content, or `null` if the file doesn't exist yet
1398
1421
  * @param apiIntegrations - Integrations fetched from the API
1422
+ *
1423
+ * @throws {IntegrationsYamlParseError} If `existingContent` is not valid YAML (for
1424
+ * example, unresolved git merge conflict markers). Callers that want to rebuild the
1425
+ * file from scratch instead of surfacing the error can catch it and re-run with
1426
+ * `mergeApiIntegrationsIntoYaml(null, apiIntegrations)` — note this discards the
1427
+ * existing content, including any local-only integrations and comments.
1428
+ * @throws {InvalidIntegrationsTypeError} If the existing `integrations` property is
1429
+ * present but is not a list.
1399
1430
  */
1400
1431
  function mergeApiIntegrationsIntoYaml(existingContent, apiIntegrations) {
1401
1432
  const doc = (existingContent != null ? parseIntegrationsDocument(existingContent) : null) ?? createNewDocument();
@@ -1408,7 +1439,6 @@ function mergeApiIntegrationsIntoYaml(existingContent, apiIntegrations) {
1408
1439
  skipped
1409
1440
  };
1410
1441
  }
1411
-
1412
1442
  //#endregion
1413
1443
  //#region src/loading/parse-integrations.ts
1414
1444
  /**
@@ -1432,12 +1462,12 @@ function formatZodIssues(issues, pathPrefix) {
1432
1462
  *
1433
1463
  * @returns Object containing valid integrations and any validation issues
1434
1464
  */
1435
- function parseIntegrations({ yaml: yaml$1, env = {} }) {
1465
+ function parseIntegrations({ yaml, env = {} }) {
1436
1466
  const emptyIntegrations = [];
1437
1467
  const issues = [];
1438
1468
  let parsed;
1439
1469
  try {
1440
- parsed = (0, __deepnote_blocks.parseYaml)(yaml$1);
1470
+ parsed = (0, _deepnote_blocks.parseYaml)(yaml);
1441
1471
  } catch (error) {
1442
1472
  const message = error instanceof Error ? error.message : String(error);
1443
1473
  issues.push({
@@ -1497,7 +1527,6 @@ function parseIntegrations({ yaml: yaml$1, env = {} }) {
1497
1527
  issues
1498
1528
  };
1499
1529
  }
1500
-
1501
1530
  //#endregion
1502
1531
  exports.ApiError = ApiError;
1503
1532
  exports.AwsAuthMethods = AwsAuthMethods;
@@ -1510,6 +1539,7 @@ exports.DEFAULT_INTEGRATIONS_FILE = DEFAULT_INTEGRATIONS_FILE;
1510
1539
  exports.DatabaseAuthMethods = DatabaseAuthMethods;
1511
1540
  exports.ENV_VAR_REF_PREFIX = ENV_VAR_REF_PREFIX;
1512
1541
  exports.EnvVarResolutionError = EnvVarResolutionError;
1542
+ exports.IntegrationsYamlParseError = IntegrationsYamlParseError;
1513
1543
  exports.InvalidIntegrationError = InvalidIntegrationError;
1514
1544
  exports.InvalidIntegrationsTypeError = InvalidIntegrationsTypeError;
1515
1545
  exports.JSON_SCHEMA_URL = JSON_SCHEMA_URL;
@@ -1540,6 +1570,7 @@ exports.getSnowflakeFederatedAuthSqlAlchemyInput = getSnowflakeFederatedAuthSqlA
1540
1570
  exports.getSqlAlchemyInput = getSqlAlchemyInput;
1541
1571
  exports.getSqlEnvVarName = getSqlEnvVarName;
1542
1572
  exports.integrationsFileSchema = integrationsFileSchema;
1573
+ exports.isBuiltinIntegration = isBuiltinIntegration;
1543
1574
  exports.isDatabaseIntegrationType = isDatabaseIntegrationType;
1544
1575
  exports.isDatabaseIntegrationTypeWithSslSupport = isDatabaseIntegrationTypeWithSslSupport;
1545
1576
  exports.isEnvVarRef = isEnvVarRef;
@@ -1556,4 +1587,4 @@ exports.resolveEnvVarRefsFromMap = resolveEnvVarRefsFromMap;
1556
1587
  exports.serializeIntegrationsDocument = serializeIntegrationsDocument;
1557
1588
  exports.sqlIntegrationTypes = sqlIntegrationTypes;
1558
1589
  exports.updateIntegrationInDocument = updateIntegrationInDocument;
1559
- exports.updateIntegrationMetadataMap = updateIntegrationMetadataMap;
1590
+ exports.updateIntegrationMetadataMap = updateIntegrationMetadataMap;