@databricks-solutions/lakebase-scm-utils 0.3.8 → 0.3.10

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.
Files changed (56) hide show
  1. package/dist/scripts/index.cjs +59 -24
  2. package/dist/scripts/index.js +59 -24
  3. package/dist/scripts/lakebase/branch.cli.cjs +55 -10
  4. package/dist/scripts/lakebase/branch.cli.js +55 -10
  5. package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +59 -24
  6. package/dist/scripts/lakebase/ci-resolve-branch.cli.js +59 -24
  7. package/dist/scripts/lakebase/collapse-heads.cli.cjs +16 -14
  8. package/dist/scripts/lakebase/collapse-heads.cli.js +16 -14
  9. package/dist/scripts/lakebase/cut-backup.cli.cjs +43 -10
  10. package/dist/scripts/lakebase/cut-backup.cli.js +43 -10
  11. package/dist/scripts/lakebase/cut-tier.cli.cjs +43 -10
  12. package/dist/scripts/lakebase/cut-tier.cli.js +43 -10
  13. package/dist/scripts/lakebase/detect-language.cli.cjs +16 -14
  14. package/dist/scripts/lakebase/detect-language.cli.js +16 -14
  15. package/dist/scripts/lakebase/doctor.cli.cjs +16 -14
  16. package/dist/scripts/lakebase/doctor.cli.js +16 -14
  17. package/dist/scripts/lakebase/get-connection.cli.cjs +16 -14
  18. package/dist/scripts/lakebase/get-connection.cli.js +16 -14
  19. package/dist/scripts/lakebase/index.cjs +59 -24
  20. package/dist/scripts/lakebase/index.d.cts +23 -0
  21. package/dist/scripts/lakebase/index.d.ts +23 -0
  22. package/dist/scripts/lakebase/index.js +59 -24
  23. package/dist/scripts/lakebase/infra-runner.cli.cjs +16 -14
  24. package/dist/scripts/lakebase/infra-runner.cli.js +16 -14
  25. package/dist/scripts/lakebase/new-migration.cli.cjs +16 -14
  26. package/dist/scripts/lakebase/new-migration.cli.js +16 -14
  27. package/dist/scripts/lakebase/schema-diff.cli.cjs +16 -14
  28. package/dist/scripts/lakebase/schema-diff.cli.js +16 -14
  29. package/dist/scripts/lakebase/schema-migrate.cli.cjs +16 -14
  30. package/dist/scripts/lakebase/schema-migrate.cli.js +16 -14
  31. package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +59 -24
  32. package/dist/scripts/lakebase/scm-claim-feature.cli.js +59 -24
  33. package/dist/scripts/lakebase/scm-doctor.cli.cjs +59 -24
  34. package/dist/scripts/lakebase/scm-doctor.cli.js +59 -24
  35. package/dist/scripts/lakebase/scm-merge.cli.cjs +16 -14
  36. package/dist/scripts/lakebase/scm-merge.cli.js +16 -14
  37. package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +16 -14
  38. package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +16 -14
  39. package/dist/scripts/lakebase/scm-recover-orphans.cli.cjs +43 -10
  40. package/dist/scripts/lakebase/scm-recover-orphans.cli.js +43 -10
  41. package/dist/scripts/lakebase/snapshot.cli.cjs +418 -0
  42. package/dist/scripts/lakebase/snapshot.cli.d.cts +1 -0
  43. package/dist/scripts/lakebase/snapshot.cli.d.ts +1 -0
  44. package/dist/scripts/lakebase/snapshot.cli.js +395 -0
  45. package/dist/scripts/util/index.cjs +2 -2
  46. package/dist/scripts/util/index.js +2 -2
  47. package/package.json +2 -1
  48. package/scripts/lakebase/branch-create.ts +93 -14
  49. package/scripts/lakebase/branch.cli.ts +15 -0
  50. package/scripts/lakebase/get-connection.ts +29 -12
  51. package/scripts/lakebase/snapshot.cli.ts +117 -0
  52. package/scripts/lakebase/snapshot.ts +85 -0
  53. package/templates/project/common/scripts/run-tests.sh +43 -2
  54. package/templates/project/common/tests/e2e/conftest.py +5 -1
  55. package/templates/project/python/tests/conftest.py +60 -4
  56. package/templates/project/python/tests/__pycache__/conftest.cpython-314.pyc +0 -0
@@ -79288,8 +79288,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
79288
79288
  var cached;
79289
79289
  function substrateSelfVersion() {
79290
79290
  if (cached !== void 0) return cached;
79291
- if ("0.3.8".length > 0) {
79292
- cached = "0.3.8";
79291
+ if ("0.3.10".length > 0) {
79292
+ cached = "0.3.10";
79293
79293
  return cached;
79294
79294
  }
79295
79295
  cached = "unknown";
@@ -79336,22 +79336,24 @@ async function getConnection(args) {
79336
79336
  const endpointPath2 = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
79337
79337
  if (args.output === "dsn") {
79338
79338
  const host2 = await resolveEndpointHost(args.instance, branchId);
79339
- const { token, email: email2 } = await mintCredential(endpointPath2);
79340
- const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token });
79339
+ const { token: token2, email: email2 } = await mintCredential(endpointPath2);
79340
+ const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
79341
79341
  return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath: endpointPath2 };
79342
79342
  }
79343
79343
  const host = await resolveEndpointHost(args.instance, branchId);
79344
- const email = await resolveCurrentUser();
79345
79344
  process.env.PGAPPNAME = connectionApplicationName();
79346
- return createLakebasePool({
79347
- endpoint: endpointPath2,
79348
- host,
79349
- database,
79350
- user: email,
79351
- // workspaceClient is passed through verbatim. createLakebasePool falls
79352
- // back to environment / ServiceContext when omitted.
79353
- ...args.workspaceClient !== void 0 ? { workspaceClient: args.workspaceClient } : {}
79354
- });
79345
+ if (args.workspaceClient !== void 0) {
79346
+ const email2 = await resolveCurrentUser();
79347
+ return createLakebasePool({
79348
+ endpoint: endpointPath2,
79349
+ host,
79350
+ database,
79351
+ user: email2,
79352
+ workspaceClient: args.workspaceClient
79353
+ });
79354
+ }
79355
+ const { token, email } = await mintCredential(endpointPath2);
79356
+ return createLakebasePool({ host, database, user: email, password: token });
79355
79357
  }
79356
79358
  async function resolveEndpointHost(instance, branch) {
79357
79359
  const branchId = await resolveBranchId({ instance, branch });
@@ -389,8 +389,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
389
389
  var cached;
390
390
  function substrateSelfVersion() {
391
391
  if (cached !== void 0) return cached;
392
- if ("0.3.8".length > 0) {
393
- cached = "0.3.8";
392
+ if ("0.3.10".length > 0) {
393
+ cached = "0.3.10";
394
394
  return cached;
395
395
  }
396
396
  cached = "unknown";
@@ -437,22 +437,24 @@ async function getConnection(args) {
437
437
  const endpointPath2 = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
438
438
  if (args.output === "dsn") {
439
439
  const host2 = await resolveEndpointHost(args.instance, branchId);
440
- const { token, email: email2 } = await mintCredential(endpointPath2);
441
- const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token });
440
+ const { token: token2, email: email2 } = await mintCredential(endpointPath2);
441
+ const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
442
442
  return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath: endpointPath2 };
443
443
  }
444
444
  const host = await resolveEndpointHost(args.instance, branchId);
445
- const email = await resolveCurrentUser();
446
445
  process.env.PGAPPNAME = connectionApplicationName();
447
- return createLakebasePool({
448
- endpoint: endpointPath2,
449
- host,
450
- database,
451
- user: email,
452
- // workspaceClient is passed through verbatim. createLakebasePool falls
453
- // back to environment / ServiceContext when omitted.
454
- ...args.workspaceClient !== void 0 ? { workspaceClient: args.workspaceClient } : {}
455
- });
446
+ if (args.workspaceClient !== void 0) {
447
+ const email2 = await resolveCurrentUser();
448
+ return createLakebasePool({
449
+ endpoint: endpointPath2,
450
+ host,
451
+ database,
452
+ user: email2,
453
+ workspaceClient: args.workspaceClient
454
+ });
455
+ }
456
+ const { token, email } = await mintCredential(endpointPath2);
457
+ return createLakebasePool({ host, database, user: email, password: token });
456
458
  }
457
459
  async function resolveEndpointHost(instance, branch) {
458
460
  const branchId = await resolveBranchId({ instance, branch });
@@ -79324,8 +79324,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
79324
79324
  var cached;
79325
79325
  function substrateSelfVersion() {
79326
79326
  if (cached !== void 0) return cached;
79327
- if ("0.3.8".length > 0) {
79328
- cached = "0.3.8";
79327
+ if ("0.3.10".length > 0) {
79328
+ cached = "0.3.10";
79329
79329
  return cached;
79330
79330
  }
79331
79331
  cached = "unknown";
@@ -79372,22 +79372,24 @@ async function getConnection(args) {
79372
79372
  const endpointPath = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
79373
79373
  if (args.output === "dsn") {
79374
79374
  const host2 = await resolveEndpointHost(args.instance, branchId);
79375
- const { token, email: email2 } = await mintCredential(endpointPath);
79376
- const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token });
79375
+ const { token: token2, email: email2 } = await mintCredential(endpointPath);
79376
+ const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
79377
79377
  return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath };
79378
79378
  }
79379
79379
  const host = await resolveEndpointHost(args.instance, branchId);
79380
- const email = await resolveCurrentUser();
79381
79380
  process.env.PGAPPNAME = connectionApplicationName();
79382
- return createLakebasePool({
79383
- endpoint: endpointPath,
79384
- host,
79385
- database,
79386
- user: email,
79387
- // workspaceClient is passed through verbatim. createLakebasePool falls
79388
- // back to environment / ServiceContext when omitted.
79389
- ...args.workspaceClient !== void 0 ? { workspaceClient: args.workspaceClient } : {}
79390
- });
79381
+ if (args.workspaceClient !== void 0) {
79382
+ const email2 = await resolveCurrentUser();
79383
+ return createLakebasePool({
79384
+ endpoint: endpointPath,
79385
+ host,
79386
+ database,
79387
+ user: email2,
79388
+ workspaceClient: args.workspaceClient
79389
+ });
79390
+ }
79391
+ const { token, email } = await mintCredential(endpointPath);
79392
+ return createLakebasePool({ host, database, user: email, password: token });
79391
79393
  }
79392
79394
  async function resolveEndpointHost(instance, branch) {
79393
79395
  const branchId = await resolveBranchId({ instance, branch });
@@ -427,8 +427,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
427
427
  var cached;
428
428
  function substrateSelfVersion() {
429
429
  if (cached !== void 0) return cached;
430
- if ("0.3.8".length > 0) {
431
- cached = "0.3.8";
430
+ if ("0.3.10".length > 0) {
431
+ cached = "0.3.10";
432
432
  return cached;
433
433
  }
434
434
  cached = "unknown";
@@ -475,22 +475,24 @@ async function getConnection(args) {
475
475
  const endpointPath = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
476
476
  if (args.output === "dsn") {
477
477
  const host2 = await resolveEndpointHost(args.instance, branchId);
478
- const { token, email: email2 } = await mintCredential(endpointPath);
479
- const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token });
478
+ const { token: token2, email: email2 } = await mintCredential(endpointPath);
479
+ const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
480
480
  return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath };
481
481
  }
482
482
  const host = await resolveEndpointHost(args.instance, branchId);
483
- const email = await resolveCurrentUser();
484
483
  process.env.PGAPPNAME = connectionApplicationName();
485
- return createLakebasePool({
486
- endpoint: endpointPath,
487
- host,
488
- database,
489
- user: email,
490
- // workspaceClient is passed through verbatim. createLakebasePool falls
491
- // back to environment / ServiceContext when omitted.
492
- ...args.workspaceClient !== void 0 ? { workspaceClient: args.workspaceClient } : {}
493
- });
484
+ if (args.workspaceClient !== void 0) {
485
+ const email2 = await resolveCurrentUser();
486
+ return createLakebasePool({
487
+ endpoint: endpointPath,
488
+ host,
489
+ database,
490
+ user: email2,
491
+ workspaceClient: args.workspaceClient
492
+ });
493
+ }
494
+ const { token, email } = await mintCredential(endpointPath);
495
+ return createLakebasePool({ host, database, user: email, password: token });
494
496
  }
495
497
  async function resolveEndpointHost(instance, branch) {
496
498
  const branchId = await resolveBranchId({ instance, branch });
@@ -78193,9 +78193,46 @@ function dbcli2(args, host, timeout = KIT_TIMEOUTS.cliDefault) {
78193
78193
  }
78194
78194
 
78195
78195
  // scripts/lakebase/branch-create.ts
78196
+ function snapshotPath(instance, snapshot) {
78197
+ return snapshot.includes("/") ? snapshot : `${projectPath(instance)}/snapshots/${snapshot}`;
78198
+ }
78199
+ function applyExpiration(spec, ttl, noExpiry) {
78200
+ if (ttl && noExpiry === true) {
78201
+ throw new LakebaseBranchError(
78202
+ `Cannot set both ttl ("${ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
78203
+ );
78204
+ }
78205
+ if (ttl) spec.ttl = ttl;
78206
+ else if (noExpiry ?? true) spec.no_expiry = true;
78207
+ }
78196
78208
  async function createBranch(args) {
78197
78209
  const sanitized = sanitizeBranchName(args.branch);
78198
78210
  const lookup = { instance: args.instance, host: args.host };
78211
+ if (args.fromSnapshot) {
78212
+ if (args.parentBranch || args.sourceBranchTime || args.sourceBranchLsn) {
78213
+ throw new LakebaseBranchError(
78214
+ `fromSnapshot is mutually exclusive with parentBranch / sourceBranchTime / sourceBranchLsn (the Lakebase API rejects source_snapshot combined with any source_branch field).`
78215
+ );
78216
+ }
78217
+ const existing2 = await getBranchByName(sanitized, lookup);
78218
+ if (existing2) return existing2;
78219
+ const spec = { source_snapshot: snapshotPath(args.instance, args.fromSnapshot) };
78220
+ applyExpiration(spec, args.ttl, args.noExpiry);
78221
+ try {
78222
+ await createWithTtlRecovery(args.instance, sanitized, spec, args.host);
78223
+ } catch (err) {
78224
+ if (err instanceof LakebaseBranchTtlTooLongError) throw err;
78225
+ const landed = await getBranchByName(sanitized, lookup);
78226
+ if (!landed) throw err;
78227
+ }
78228
+ return waitForBranchReady({
78229
+ instance: args.instance,
78230
+ host: args.host,
78231
+ branch: sanitized,
78232
+ timeoutMs: args.readyTimeoutMs ?? KIT_TIMEOUTS.readyWait,
78233
+ pollIntervalMs: args.pollIntervalMs ?? KIT_TIMEOUTS.readyPoll
78234
+ });
78235
+ }
78199
78236
  let sourceBranchPath;
78200
78237
  if (args.parentBranch) {
78201
78238
  if (looksLikeBranchUid(args.parentBranch)) {
@@ -78243,19 +78280,15 @@ async function createBranch(args) {
78243
78280
  assertSourceMatches(existing, sourceBranchPath, sanitized);
78244
78281
  return existing;
78245
78282
  }
78246
- if (args.ttl && args.noExpiry === true) {
78283
+ if (args.sourceBranchTime && args.sourceBranchLsn) {
78247
78284
  throw new LakebaseBranchError(
78248
- `Cannot set both ttl ("${args.ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
78285
+ `sourceBranchTime and sourceBranchLsn are mutually exclusive \u2013 pass at most one point-in-time.`
78249
78286
  );
78250
78287
  }
78251
- const specObj = {
78252
- source_branch: sourceBranchPath
78253
- };
78254
- if (args.ttl) {
78255
- specObj.ttl = args.ttl;
78256
- } else if (args.noExpiry ?? true) {
78257
- specObj.no_expiry = true;
78258
- }
78288
+ const specObj = { source_branch: sourceBranchPath };
78289
+ if (args.sourceBranchTime) specObj.source_branch_time = args.sourceBranchTime;
78290
+ else if (args.sourceBranchLsn) specObj.source_branch_lsn = args.sourceBranchLsn;
78291
+ applyExpiration(specObj, args.ttl, args.noExpiry);
78259
78292
  try {
78260
78293
  await createWithTtlRecovery(args.instance, sanitized, specObj, args.host);
78261
78294
  } catch (err) {
@@ -79783,8 +79816,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
79783
79816
  var cached;
79784
79817
  function substrateSelfVersion() {
79785
79818
  if (cached !== void 0) return cached;
79786
- if ("0.3.8".length > 0) {
79787
- cached = "0.3.8";
79819
+ if ("0.3.10".length > 0) {
79820
+ cached = "0.3.10";
79788
79821
  return cached;
79789
79822
  }
79790
79823
  cached = "unknown";
@@ -79831,22 +79864,24 @@ async function getConnection(args) {
79831
79864
  const endpointPath2 = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
79832
79865
  if (args.output === "dsn") {
79833
79866
  const host2 = await resolveEndpointHost(args.instance, branchId);
79834
- const { token, email: email2 } = await mintCredential(endpointPath2);
79835
- const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token });
79867
+ const { token: token2, email: email2 } = await mintCredential(endpointPath2);
79868
+ const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
79836
79869
  return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath: endpointPath2 };
79837
79870
  }
79838
79871
  const host = await resolveEndpointHost(args.instance, branchId);
79839
- const email = await resolveCurrentUser();
79840
79872
  process.env.PGAPPNAME = connectionApplicationName();
79841
- return createLakebasePool({
79842
- endpoint: endpointPath2,
79843
- host,
79844
- database,
79845
- user: email,
79846
- // workspaceClient is passed through verbatim. createLakebasePool falls
79847
- // back to environment / ServiceContext when omitted.
79848
- ...args.workspaceClient !== void 0 ? { workspaceClient: args.workspaceClient } : {}
79849
- });
79873
+ if (args.workspaceClient !== void 0) {
79874
+ const email2 = await resolveCurrentUser();
79875
+ return createLakebasePool({
79876
+ endpoint: endpointPath2,
79877
+ host,
79878
+ database,
79879
+ user: email2,
79880
+ workspaceClient: args.workspaceClient
79881
+ });
79882
+ }
79883
+ const { token, email } = await mintCredential(endpointPath2);
79884
+ return createLakebasePool({ host, database, user: email, password: token });
79850
79885
  }
79851
79886
  async function resolveEndpointHost(instance, branch) {
79852
79887
  const branchId = await resolveBranchId({ instance, branch });
@@ -650,9 +650,46 @@ function dbcli2(args, host, timeout = KIT_TIMEOUTS.cliDefault) {
650
650
  }
651
651
 
652
652
  // scripts/lakebase/branch-create.ts
653
+ function snapshotPath(instance, snapshot) {
654
+ return snapshot.includes("/") ? snapshot : `${projectPath(instance)}/snapshots/${snapshot}`;
655
+ }
656
+ function applyExpiration(spec, ttl, noExpiry) {
657
+ if (ttl && noExpiry === true) {
658
+ throw new LakebaseBranchError(
659
+ `Cannot set both ttl ("${ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
660
+ );
661
+ }
662
+ if (ttl) spec.ttl = ttl;
663
+ else if (noExpiry ?? true) spec.no_expiry = true;
664
+ }
653
665
  async function createBranch(args) {
654
666
  const sanitized = sanitizeBranchName(args.branch);
655
667
  const lookup = { instance: args.instance, host: args.host };
668
+ if (args.fromSnapshot) {
669
+ if (args.parentBranch || args.sourceBranchTime || args.sourceBranchLsn) {
670
+ throw new LakebaseBranchError(
671
+ `fromSnapshot is mutually exclusive with parentBranch / sourceBranchTime / sourceBranchLsn (the Lakebase API rejects source_snapshot combined with any source_branch field).`
672
+ );
673
+ }
674
+ const existing2 = await getBranchByName(sanitized, lookup);
675
+ if (existing2) return existing2;
676
+ const spec = { source_snapshot: snapshotPath(args.instance, args.fromSnapshot) };
677
+ applyExpiration(spec, args.ttl, args.noExpiry);
678
+ try {
679
+ await createWithTtlRecovery(args.instance, sanitized, spec, args.host);
680
+ } catch (err) {
681
+ if (err instanceof LakebaseBranchTtlTooLongError) throw err;
682
+ const landed = await getBranchByName(sanitized, lookup);
683
+ if (!landed) throw err;
684
+ }
685
+ return waitForBranchReady({
686
+ instance: args.instance,
687
+ host: args.host,
688
+ branch: sanitized,
689
+ timeoutMs: args.readyTimeoutMs ?? KIT_TIMEOUTS.readyWait,
690
+ pollIntervalMs: args.pollIntervalMs ?? KIT_TIMEOUTS.readyPoll
691
+ });
692
+ }
656
693
  let sourceBranchPath;
657
694
  if (args.parentBranch) {
658
695
  if (looksLikeBranchUid(args.parentBranch)) {
@@ -700,19 +737,15 @@ async function createBranch(args) {
700
737
  assertSourceMatches(existing, sourceBranchPath, sanitized);
701
738
  return existing;
702
739
  }
703
- if (args.ttl && args.noExpiry === true) {
740
+ if (args.sourceBranchTime && args.sourceBranchLsn) {
704
741
  throw new LakebaseBranchError(
705
- `Cannot set both ttl ("${args.ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
742
+ `sourceBranchTime and sourceBranchLsn are mutually exclusive \u2013 pass at most one point-in-time.`
706
743
  );
707
744
  }
708
- const specObj = {
709
- source_branch: sourceBranchPath
710
- };
711
- if (args.ttl) {
712
- specObj.ttl = args.ttl;
713
- } else if (args.noExpiry ?? true) {
714
- specObj.no_expiry = true;
715
- }
745
+ const specObj = { source_branch: sourceBranchPath };
746
+ if (args.sourceBranchTime) specObj.source_branch_time = args.sourceBranchTime;
747
+ else if (args.sourceBranchLsn) specObj.source_branch_lsn = args.sourceBranchLsn;
748
+ applyExpiration(specObj, args.ttl, args.noExpiry);
716
749
  try {
717
750
  await createWithTtlRecovery(args.instance, sanitized, specObj, args.host);
718
751
  } catch (err) {
@@ -864,8 +897,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
864
897
  var cached;
865
898
  function substrateSelfVersion() {
866
899
  if (cached !== void 0) return cached;
867
- if ("0.3.8".length > 0) {
868
- cached = "0.3.8";
900
+ if ("0.3.10".length > 0) {
901
+ cached = "0.3.10";
869
902
  return cached;
870
903
  }
871
904
  cached = "unknown";
@@ -912,22 +945,24 @@ async function getConnection(args) {
912
945
  const endpointPath2 = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
913
946
  if (args.output === "dsn") {
914
947
  const host2 = await resolveEndpointHost(args.instance, branchId);
915
- const { token, email: email2 } = await mintCredential(endpointPath2);
916
- const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token });
948
+ const { token: token2, email: email2 } = await mintCredential(endpointPath2);
949
+ const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
917
950
  return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath: endpointPath2 };
918
951
  }
919
952
  const host = await resolveEndpointHost(args.instance, branchId);
920
- const email = await resolveCurrentUser();
921
953
  process.env.PGAPPNAME = connectionApplicationName();
922
- return createLakebasePool({
923
- endpoint: endpointPath2,
924
- host,
925
- database,
926
- user: email,
927
- // workspaceClient is passed through verbatim. createLakebasePool falls
928
- // back to environment / ServiceContext when omitted.
929
- ...args.workspaceClient !== void 0 ? { workspaceClient: args.workspaceClient } : {}
930
- });
954
+ if (args.workspaceClient !== void 0) {
955
+ const email2 = await resolveCurrentUser();
956
+ return createLakebasePool({
957
+ endpoint: endpointPath2,
958
+ host,
959
+ database,
960
+ user: email2,
961
+ workspaceClient: args.workspaceClient
962
+ });
963
+ }
964
+ const { token, email } = await mintCredential(endpointPath2);
965
+ return createLakebasePool({ host, database, user: email, password: token });
931
966
  }
932
967
  async function resolveEndpointHost(instance, branch) {
933
968
  const branchId = await resolveBranchId({ instance, branch });
@@ -86650,9 +86650,46 @@ function dbcli2(args, host, timeout = KIT_TIMEOUTS.cliDefault) {
86650
86650
  }
86651
86651
 
86652
86652
  // scripts/lakebase/branch-create.ts
86653
+ function snapshotPath(instance, snapshot) {
86654
+ return snapshot.includes("/") ? snapshot : `${projectPath(instance)}/snapshots/${snapshot}`;
86655
+ }
86656
+ function applyExpiration(spec, ttl, noExpiry) {
86657
+ if (ttl && noExpiry === true) {
86658
+ throw new LakebaseBranchError(
86659
+ `Cannot set both ttl ("${ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
86660
+ );
86661
+ }
86662
+ if (ttl) spec.ttl = ttl;
86663
+ else if (noExpiry ?? true) spec.no_expiry = true;
86664
+ }
86653
86665
  async function createBranch(args) {
86654
86666
  const sanitized = sanitizeBranchName(args.branch);
86655
86667
  const lookup = { instance: args.instance, host: args.host };
86668
+ if (args.fromSnapshot) {
86669
+ if (args.parentBranch || args.sourceBranchTime || args.sourceBranchLsn) {
86670
+ throw new LakebaseBranchError(
86671
+ `fromSnapshot is mutually exclusive with parentBranch / sourceBranchTime / sourceBranchLsn (the Lakebase API rejects source_snapshot combined with any source_branch field).`
86672
+ );
86673
+ }
86674
+ const existing2 = await getBranchByName(sanitized, lookup);
86675
+ if (existing2) return existing2;
86676
+ const spec = { source_snapshot: snapshotPath(args.instance, args.fromSnapshot) };
86677
+ applyExpiration(spec, args.ttl, args.noExpiry);
86678
+ try {
86679
+ await createWithTtlRecovery(args.instance, sanitized, spec, args.host);
86680
+ } catch (err) {
86681
+ if (err instanceof LakebaseBranchTtlTooLongError) throw err;
86682
+ const landed = await getBranchByName(sanitized, lookup);
86683
+ if (!landed) throw err;
86684
+ }
86685
+ return waitForBranchReady({
86686
+ instance: args.instance,
86687
+ host: args.host,
86688
+ branch: sanitized,
86689
+ timeoutMs: args.readyTimeoutMs ?? KIT_TIMEOUTS.readyWait,
86690
+ pollIntervalMs: args.pollIntervalMs ?? KIT_TIMEOUTS.readyPoll
86691
+ });
86692
+ }
86656
86693
  let sourceBranchPath;
86657
86694
  if (args.parentBranch) {
86658
86695
  if (looksLikeBranchUid(args.parentBranch)) {
@@ -86700,19 +86737,15 @@ async function createBranch(args) {
86700
86737
  assertSourceMatches(existing, sourceBranchPath, sanitized);
86701
86738
  return existing;
86702
86739
  }
86703
- if (args.ttl && args.noExpiry === true) {
86740
+ if (args.sourceBranchTime && args.sourceBranchLsn) {
86704
86741
  throw new LakebaseBranchError(
86705
- `Cannot set both ttl ("${args.ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
86742
+ `sourceBranchTime and sourceBranchLsn are mutually exclusive \u2013 pass at most one point-in-time.`
86706
86743
  );
86707
86744
  }
86708
- const specObj = {
86709
- source_branch: sourceBranchPath
86710
- };
86711
- if (args.ttl) {
86712
- specObj.ttl = args.ttl;
86713
- } else if (args.noExpiry ?? true) {
86714
- specObj.no_expiry = true;
86715
- }
86745
+ const specObj = { source_branch: sourceBranchPath };
86746
+ if (args.sourceBranchTime) specObj.source_branch_time = args.sourceBranchTime;
86747
+ else if (args.sourceBranchLsn) specObj.source_branch_lsn = args.sourceBranchLsn;
86748
+ applyExpiration(specObj, args.ttl, args.noExpiry);
86716
86749
  try {
86717
86750
  await createWithTtlRecovery(args.instance, sanitized, specObj, args.host);
86718
86751
  } catch (err) {
@@ -88240,8 +88273,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
88240
88273
  var cached;
88241
88274
  function substrateSelfVersion() {
88242
88275
  if (cached !== void 0) return cached;
88243
- if ("0.3.8".length > 0) {
88244
- cached = "0.3.8";
88276
+ if ("0.3.10".length > 0) {
88277
+ cached = "0.3.10";
88245
88278
  return cached;
88246
88279
  }
88247
88280
  cached = "unknown";
@@ -88288,22 +88321,24 @@ async function getConnection(args) {
88288
88321
  const endpointPath2 = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
88289
88322
  if (args.output === "dsn") {
88290
88323
  const host2 = await resolveEndpointHost(args.instance, branchId);
88291
- const { token, email: email2 } = await mintCredential(endpointPath2);
88292
- const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token });
88324
+ const { token: token2, email: email2 } = await mintCredential(endpointPath2);
88325
+ const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
88293
88326
  return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath: endpointPath2 };
88294
88327
  }
88295
88328
  const host = await resolveEndpointHost(args.instance, branchId);
88296
- const email = await resolveCurrentUser();
88297
88329
  process.env.PGAPPNAME = connectionApplicationName();
88298
- return createLakebasePool({
88299
- endpoint: endpointPath2,
88300
- host,
88301
- database,
88302
- user: email,
88303
- // workspaceClient is passed through verbatim. createLakebasePool falls
88304
- // back to environment / ServiceContext when omitted.
88305
- ...args.workspaceClient !== void 0 ? { workspaceClient: args.workspaceClient } : {}
88306
- });
88330
+ if (args.workspaceClient !== void 0) {
88331
+ const email2 = await resolveCurrentUser();
88332
+ return createLakebasePool({
88333
+ endpoint: endpointPath2,
88334
+ host,
88335
+ database,
88336
+ user: email2,
88337
+ workspaceClient: args.workspaceClient
88338
+ });
88339
+ }
88340
+ const { token, email } = await mintCredential(endpointPath2);
88341
+ return createLakebasePool({ host, database, user: email, password: token });
88307
88342
  }
88308
88343
  async function resolveEndpointHost(instance, branch) {
88309
88344
  const branchId = await resolveBranchId({ instance, branch });