@marimo-team/islands 0.20.5-dev62 → 0.20.5-dev64

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/main.js CHANGED
@@ -70719,7 +70719,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
70719
70719
  return Logger.warn("Failed to get version from mount config"), null;
70720
70720
  }
70721
70721
  }
70722
- const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.20.5-dev62"), showCodeInRunModeAtom = atom(true);
70722
+ const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.20.5-dev64"), showCodeInRunModeAtom = atom(true);
70723
70723
  atom(null);
70724
70724
  var import_compiler_runtime$89 = require_compiler_runtime();
70725
70725
  function useKeydownOnElement(e, r) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.20.5-dev62",
3
+ "version": "0.20.5-dev64",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -248,16 +248,95 @@ _password = os.environ.get("SNOWFLAKE_PASSWORD", "pass")
248
248
  engine = sqlmodel.create_engine(
249
249
  URL(
250
250
  account="account",
251
+ database="db",
252
+ warehouse="warehouse",
253
+ schema="schema",
254
+ role="role",
251
255
  user="user",
256
+ password=_password,
257
+ )
258
+ )"
259
+ `;
260
+
261
+ exports[`generateDatabaseCode > basic connections > snowflake with MFA 1`] = `
262
+ "from snowflake.sqlalchemy import URL
263
+ import os
264
+ import sqlmodel
265
+
266
+ _password = os.environ.get("SNOWFLAKE_PASSWORD", "pass")
267
+ engine = sqlmodel.create_engine(
268
+ URL(
269
+ account="account",
252
270
  database="db",
253
271
  warehouse="warehouse",
254
272
  schema="schema",
255
273
  role="role",
274
+ user="user",
256
275
  password=_password,
276
+ ),
277
+ connect_args={"authenticator": "username_password_mfa"},
278
+ )"
279
+ `;
280
+
281
+ exports[`generateDatabaseCode > basic connections > snowflake with OAuth/PAT 1`] = `
282
+ "from snowflake.sqlalchemy import URL
283
+ import os
284
+ import sqlmodel
285
+
286
+ _password = os.environ.get("SNOWFLAKE_TOKEN", "my_token")
287
+ engine = sqlmodel.create_engine(
288
+ URL(
289
+ account="account",
290
+ database="db",
291
+ warehouse="warehouse",
292
+ schema="schema",
293
+ role="role",
294
+ authenticator="oauth",
295
+ token=_password,
296
+ )
297
+ )"
298
+ `;
299
+
300
+ exports[`generateDatabaseCode > basic connections > snowflake with SSO 1`] = `
301
+ "from snowflake.sqlalchemy import URL
302
+ import sqlmodel
303
+
304
+ engine = sqlmodel.create_engine(
305
+ URL(
306
+ account="account",
307
+ database="db",
308
+ warehouse="warehouse",
309
+ schema="schema",
310
+ role="role",
311
+ user="user",
312
+ authenticator="externalbrowser",
257
313
  )
258
314
  )"
259
315
  `;
260
316
 
317
+ exports[`generateDatabaseCode > basic connections > snowflake with key pair 1`] = `
318
+ "from snowflake.sqlalchemy import URL
319
+ import os
320
+ import sqlmodel
321
+
322
+ _password = os.environ.get("SNOWFLAKE_PRIVATE_KEY_PASSPHRASE", "my_passphrase")
323
+ engine = sqlmodel.create_engine(
324
+ URL(
325
+ account="account",
326
+ database="db",
327
+ warehouse="warehouse",
328
+ schema="schema",
329
+ role="role",
330
+ user="user",
331
+ ),
332
+ connect_args={
333
+ "authenticator": "SNOWFLAKE_JWT",
334
+ "private_key_file": "/path/to/rsa_key.p8",
335
+ "private_key_file_pwd": _password,
336
+ },
337
+ )"
338
+ `;
339
+
261
340
  exports[`generateDatabaseCode > basic connections > sqlite 1`] = `
262
341
  "import sqlmodel
263
342
 
@@ -362,17 +441,17 @@ exports[`generateDatabaseCode > connections with secrets > snowflake with multip
362
441
  import os
363
442
  import sqlmodel
364
443
 
365
- _password = os.environ.get("ENV_PASSWORD")
366
444
  _account = os.environ.get("ENV_ACCOUNT")
445
+ _password = os.environ.get("ENV_PASSWORD")
367
446
  _user = os.environ.get("ENV_USER")
368
447
  engine = sqlmodel.create_engine(
369
448
  URL(
370
449
  account=_account,
371
- user=_user,
372
450
  database="db",
373
451
  warehouse="warehouse",
374
452
  schema="schema",
375
453
  role="role",
454
+ user=_user,
376
455
  password=_password,
377
456
  )
378
457
  )"
@@ -563,6 +642,26 @@ DATABASE_URL = f"postgresql://用户:{_password}@localhost:5432/测试数据库"
563
642
  engine = sqlmodel.create_engine(DATABASE_URL, connect_args={'sslmode': 'require'})"
564
643
  `;
565
644
 
645
+ exports[`generateDatabaseCode > edge cases > snowflake key pair without passphrase 1`] = `
646
+ "from snowflake.sqlalchemy import URL
647
+ import sqlmodel
648
+
649
+ engine = sqlmodel.create_engine(
650
+ URL(
651
+ account="account",
652
+ database="db",
653
+ warehouse="warehouse",
654
+ schema="schema",
655
+ role="role",
656
+ user="user",
657
+ ),
658
+ connect_args={
659
+ "authenticator": "SNOWFLAKE_JWT",
660
+ "private_key_file": "/path/to/rsa_key.p8",
661
+ },
662
+ )"
663
+ `;
664
+
566
665
  exports[`generateDatabaseCode > edge cases > snowflake with all optional fields filled 1`] = `
567
666
  "from snowflake.sqlalchemy import URL
568
667
  import os
@@ -572,11 +671,11 @@ _password = os.environ.get("SNOWFLAKE_PASSWORD", "pass")
572
671
  engine = sqlmodel.create_engine(
573
672
  URL(
574
673
  account="org-account",
575
- user="user",
576
674
  database="db",
577
675
  warehouse="compute_wh",
578
676
  schema="public",
579
677
  role="accountadmin",
678
+ user="user",
580
679
  password=_password,
581
680
  )
582
681
  )"
@@ -591,8 +690,8 @@ _password = os.environ.get("SNOWFLAKE_PASSWORD", "pass")
591
690
  engine = sqlmodel.create_engine(
592
691
  URL(
593
692
  account="account",
594
- user="user",
595
693
  database="db",
694
+ user="user",
596
695
  password=_password,
597
696
  )
598
697
  )"
@@ -711,11 +810,11 @@ _password = os.environ.get("SNOWFLAKE_PASSWORD", "pass")
711
810
  engine = sqlmodel.create_engine(
712
811
  URL(
713
812
  account="account-with-password123",
714
- user="user",
715
813
  database="db",
716
814
  warehouse="warehouse",
717
815
  schema="schema",
718
816
  role="role",
817
+ user="user",
719
818
  password=_password,
720
819
  )
721
820
  )"
@@ -730,11 +829,11 @@ _password = os.environ.get("SNOWFLAKE_PASSWORD", "pass")
730
829
  engine = sqlalchemy.create_engine(
731
830
  URL(
732
831
  account="account-with-password123",
733
- user="user",
734
832
  database="db",
735
833
  warehouse="warehouse",
736
834
  schema="schema",
737
835
  role="role",
836
+ user="user",
738
837
  password=_password,
739
838
  )
740
839
  )"
@@ -46,12 +46,72 @@ describe("generateDatabaseCode", () => {
46
46
  const snowflakeConnection: DatabaseConnection = {
47
47
  type: "snowflake",
48
48
  account: "account",
49
- username: "user",
50
- password: "pass",
51
49
  warehouse: "warehouse",
52
50
  database: "db",
53
51
  schema: "schema",
54
52
  role: "role",
53
+ authType: {
54
+ type: "Password",
55
+ username: "user",
56
+ password: "pass",
57
+ enable_mfa: false,
58
+ },
59
+ };
60
+
61
+ const snowflakeMFAConnection: DatabaseConnection = {
62
+ type: "snowflake",
63
+ account: "account",
64
+ warehouse: "warehouse",
65
+ database: "db",
66
+ schema: "schema",
67
+ role: "role",
68
+ authType: {
69
+ type: "Password",
70
+ username: "user",
71
+ password: "pass",
72
+ enable_mfa: true,
73
+ },
74
+ };
75
+
76
+ const snowflakeSSOConnection: DatabaseConnection = {
77
+ type: "snowflake",
78
+ account: "account",
79
+ warehouse: "warehouse",
80
+ database: "db",
81
+ schema: "schema",
82
+ role: "role",
83
+ authType: {
84
+ type: "SSO (Browser)",
85
+ username: "user",
86
+ },
87
+ };
88
+
89
+ const snowflakeKeyPairConnection: DatabaseConnection = {
90
+ type: "snowflake",
91
+ account: "account",
92
+ warehouse: "warehouse",
93
+ database: "db",
94
+ schema: "schema",
95
+ role: "role",
96
+ authType: {
97
+ type: "Key Pair",
98
+ username: "user",
99
+ private_key_path: "/path/to/rsa_key.p8",
100
+ private_key_passphrase: "my_passphrase",
101
+ },
102
+ };
103
+
104
+ const snowflakeOAuthConnection: DatabaseConnection = {
105
+ type: "snowflake",
106
+ account: "account",
107
+ warehouse: "warehouse",
108
+ database: "db",
109
+ schema: "schema",
110
+ role: "role",
111
+ authType: {
112
+ type: "OAuth / PAT",
113
+ token: "my_token",
114
+ },
55
115
  };
56
116
 
57
117
  const bigqueryConnection: DatabaseConnection = {
@@ -240,6 +300,10 @@ describe("generateDatabaseCode", () => {
240
300
  ["duckdb", duckdbConnection, "duckdb"],
241
301
  ["motherduck", motherduckConnection, "duckdb"],
242
302
  ["snowflake", snowflakeConnection, "sqlmodel"],
303
+ ["snowflake with MFA", snowflakeMFAConnection, "sqlmodel"],
304
+ ["snowflake with SSO", snowflakeSSOConnection, "sqlmodel"],
305
+ ["snowflake with key pair", snowflakeKeyPairConnection, "sqlmodel"],
306
+ ["snowflake with OAuth/PAT", snowflakeOAuthConnection, "sqlmodel"],
243
307
  ["bigquery", bigqueryConnection, "sqlmodel"],
244
308
  ["clickhouse", clickhouseConnection, "clickhouse_connect"],
245
309
  ["chdb", chdbConnection, "chdb"],
@@ -300,9 +364,13 @@ describe("generateDatabaseCode", () => {
300
364
  "snowflake with multiple secrets",
301
365
  {
302
366
  ...snowflakeConnection,
303
- username: prefixSecret("ENV_USER"),
304
- password: prefixSecret("ENV_PASSWORD"),
305
367
  account: prefixSecret("ENV_ACCOUNT"),
368
+ authType: {
369
+ type: "Password" as const,
370
+ username: prefixSecret("ENV_USER"),
371
+ password: prefixSecret("ENV_PASSWORD"),
372
+ enable_mfa: false,
373
+ },
306
374
  },
307
375
  "sqlmodel",
308
376
  ],
@@ -388,12 +456,16 @@ describe("generateDatabaseCode", () => {
388
456
  {
389
457
  type: "snowflake",
390
458
  account: "account",
391
- username: "user",
392
- password: "pass",
393
459
  database: "db",
394
460
  warehouse: "",
395
461
  schema: "",
396
462
  role: "",
463
+ authType: {
464
+ type: "Password" as const,
465
+ username: "user",
466
+ password: "pass",
467
+ enable_mfa: false,
468
+ },
397
469
  },
398
470
  "sqlmodel",
399
471
  ],
@@ -489,12 +561,33 @@ describe("generateDatabaseCode", () => {
489
561
  {
490
562
  type: "snowflake",
491
563
  account: "org-account",
492
- username: "user",
493
- password: "pass",
494
564
  database: "db",
495
565
  warehouse: "compute_wh",
496
566
  schema: "public",
497
567
  role: "accountadmin",
568
+ authType: {
569
+ type: "Password" as const,
570
+ username: "user",
571
+ password: "pass",
572
+ enable_mfa: false,
573
+ },
574
+ },
575
+ "sqlmodel",
576
+ ],
577
+ [
578
+ "snowflake key pair without passphrase",
579
+ {
580
+ type: "snowflake",
581
+ account: "account",
582
+ database: "db",
583
+ warehouse: "warehouse",
584
+ schema: "schema",
585
+ role: "role",
586
+ authType: {
587
+ type: "Key Pair" as const,
588
+ username: "user",
589
+ private_key_path: "/path/to/rsa_key.p8",
590
+ },
498
591
  },
499
592
  "sqlmodel",
500
593
  ],
@@ -293,34 +293,124 @@ class SnowflakeGenerator extends CodeGenerator<"snowflake"> {
293
293
  }
294
294
 
295
295
  generateConnectionCode(): string {
296
- const password = this.secrets.printPassword(
297
- this.connection.password,
298
- "SNOWFLAKE_PASSWORD",
299
- false,
300
- );
301
- const params = {
302
- account: this.secrets.print("account", this.connection.account),
303
- user: this.secrets.print("user", this.connection.username),
304
- database: this.secrets.print("database", this.connection.database),
305
- warehouse: this.connection.warehouse
306
- ? this.secrets.print("warehouse", this.connection.warehouse)
307
- : undefined,
308
- schema: this.connection.schema
309
- ? this.secrets.print("schema", this.connection.schema)
310
- : undefined,
311
- role: this.connection.role
312
- ? this.secrets.print("role", this.connection.role)
296
+ const { authType, account, database, warehouse, schema, role } =
297
+ this.connection;
298
+ const baseParams: Record<string, string | undefined> = {
299
+ account: this.secrets.print("account", account),
300
+ database: this.secrets.print("database", database),
301
+ warehouse: warehouse
302
+ ? this.secrets.print("warehouse", warehouse)
313
303
  : undefined,
314
- password: password,
304
+ schema: schema ? this.secrets.print("schema", schema) : undefined,
305
+ role: role ? this.secrets.print("role", role) : undefined,
315
306
  };
316
307
 
317
- return dedent(`
318
- engine = ${this.orm}.create_engine(
319
- URL(
320
- ${formatUrlParams(params, (inner) => ` ${inner}`)},
321
- )
322
- )
323
- `);
308
+ switch (authType.type) {
309
+ case "Password": {
310
+ const password = this.secrets.printPassword(
311
+ authType.password,
312
+ "SNOWFLAKE_PASSWORD",
313
+ false,
314
+ );
315
+ const params = {
316
+ ...baseParams,
317
+ user: this.secrets.print("user", authType.username),
318
+ password,
319
+ };
320
+ if (authType.enable_mfa) {
321
+ return dedent(`
322
+ engine = ${this.orm}.create_engine(
323
+ URL(
324
+ ${formatUrlParams(params, (inner) => ` ${inner}`)},
325
+ ),
326
+ connect_args={"authenticator": "username_password_mfa"},
327
+ )
328
+ `);
329
+ }
330
+ return dedent(`
331
+ engine = ${this.orm}.create_engine(
332
+ URL(
333
+ ${formatUrlParams(params, (inner) => ` ${inner}`)},
334
+ )
335
+ )
336
+ `);
337
+ }
338
+
339
+ case "SSO (Browser)": {
340
+ const params = {
341
+ ...baseParams,
342
+ user: this.secrets.print("user", authType.username),
343
+ authenticator: '"externalbrowser"',
344
+ };
345
+ return dedent(`
346
+ engine = ${this.orm}.create_engine(
347
+ URL(
348
+ ${formatUrlParams(params, (inner) => ` ${inner}`)},
349
+ )
350
+ )
351
+ `);
352
+ }
353
+
354
+ case "Key Pair": {
355
+ const params = {
356
+ ...baseParams,
357
+ user: this.secrets.print("user", authType.username),
358
+ };
359
+ const privateKeyPath = this.secrets.print(
360
+ "private_key_path",
361
+ authType.private_key_path,
362
+ );
363
+ const passphrase = authType.private_key_passphrase
364
+ ? this.secrets.printPassword(
365
+ authType.private_key_passphrase,
366
+ "SNOWFLAKE_PRIVATE_KEY_PASSPHRASE",
367
+ false,
368
+ )
369
+ : undefined;
370
+ const connectArgLines = [
371
+ ` "authenticator": "SNOWFLAKE_JWT"`,
372
+ ` "private_key_file": ${privateKeyPath}`,
373
+ ];
374
+ if (passphrase) {
375
+ connectArgLines.push(
376
+ ` "private_key_file_pwd": ${passphrase}`,
377
+ );
378
+ }
379
+ return dedent(`
380
+ engine = ${this.orm}.create_engine(
381
+ URL(
382
+ ${formatUrlParams(params, (inner) => ` ${inner}`)},
383
+ ),
384
+ connect_args={
385
+ ${connectArgLines.join(",\n")},
386
+ },
387
+ )
388
+ `);
389
+ }
390
+
391
+ case "OAuth / PAT": {
392
+ const token = this.secrets.printPassword(
393
+ authType.token,
394
+ "SNOWFLAKE_TOKEN",
395
+ false,
396
+ );
397
+ const params = {
398
+ ...baseParams,
399
+ authenticator: '"oauth"',
400
+ token,
401
+ };
402
+ return dedent(`
403
+ engine = ${this.orm}.create_engine(
404
+ URL(
405
+ ${formatUrlParams(params, (inner) => ` ${inner}`)},
406
+ )
407
+ )
408
+ `);
409
+ }
410
+
411
+ default:
412
+ assertNever(authType);
413
+ }
324
414
  }
325
415
  }
326
416
 
@@ -218,12 +218,59 @@ export const SnowflakeConnectionSchema = z
218
218
  optionRegex: ".*snowflake.*",
219
219
  }),
220
220
  ),
221
- username: usernameField(),
222
- password: passwordField(),
223
221
  role: z
224
222
  .string()
225
223
  .optional()
226
224
  .describe(FieldOptions.of({ label: "Role" })),
225
+ authType: z
226
+ .discriminatedUnion("type", [
227
+ z.object({
228
+ type: z.literal("Password"),
229
+ username: usernameField(),
230
+ password: passwordField(),
231
+ enable_mfa: z
232
+ .boolean()
233
+ .default(false)
234
+ .describe(FieldOptions.of({ label: "Enable MFA (Duo Push)" })),
235
+ }),
236
+ z.object({
237
+ type: z.literal("SSO (Browser)"),
238
+ username: usernameField(),
239
+ }),
240
+ z.object({
241
+ type: z.literal("Key Pair"),
242
+ username: usernameField(),
243
+ private_key_path: z
244
+ .string()
245
+ .nonempty()
246
+ .describe(
247
+ FieldOptions.of({
248
+ label: "Private Key Path",
249
+ placeholder: "/path/to/rsa_key.p8",
250
+ }),
251
+ ),
252
+ private_key_passphrase: z
253
+ .string()
254
+ .optional()
255
+ .describe(
256
+ FieldOptions.of({
257
+ label: "Private Key Passphrase",
258
+ inputType: "password",
259
+ optionRegex: ".*passphrase.*",
260
+ }),
261
+ ),
262
+ }),
263
+ z.object({
264
+ type: z.literal("OAuth / PAT"),
265
+ token: tokenField("Token", true),
266
+ }),
267
+ ])
268
+ .default({
269
+ type: "Password",
270
+ username: "username",
271
+ enable_mfa: false,
272
+ })
273
+ .describe(FieldOptions.of({ special: "tabs" })),
227
274
  })
228
275
  .describe(FieldOptions.of({ direction: "two-columns" }));
229
276