@databricks-solutions/lakebase-scm-utils 0.3.9 → 0.3.11

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 (69) hide show
  1. package/dist/{pr-e-E4aP4j.d.cts → pr-D-eayWyJ.d.cts} +59 -1
  2. package/dist/{pr-e-E4aP4j.d.ts → pr-D-eayWyJ.d.ts} +59 -1
  3. package/dist/scripts/git/index.cjs +30 -14
  4. package/dist/scripts/git/index.d.cts +32 -1
  5. package/dist/scripts/git/index.d.ts +32 -1
  6. package/dist/scripts/git/index.js +28 -14
  7. package/dist/scripts/github/index.d.cts +2 -60
  8. package/dist/scripts/github/index.d.ts +2 -60
  9. package/dist/scripts/index.cjs +301 -98
  10. package/dist/scripts/index.d.cts +4 -4
  11. package/dist/scripts/index.d.ts +4 -4
  12. package/dist/scripts/index.js +296 -98
  13. package/dist/scripts/lakebase/branch.cli.cjs +55 -10
  14. package/dist/scripts/lakebase/branch.cli.js +55 -10
  15. package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +59 -24
  16. package/dist/scripts/lakebase/ci-resolve-branch.cli.js +59 -24
  17. package/dist/scripts/lakebase/collapse-heads.cli.cjs +16 -14
  18. package/dist/scripts/lakebase/collapse-heads.cli.js +16 -14
  19. package/dist/scripts/lakebase/cut-backup.cli.cjs +43 -10
  20. package/dist/scripts/lakebase/cut-backup.cli.js +43 -10
  21. package/dist/scripts/lakebase/cut-tier.cli.cjs +43 -10
  22. package/dist/scripts/lakebase/cut-tier.cli.js +43 -10
  23. package/dist/scripts/lakebase/detect-language.cli.cjs +16 -14
  24. package/dist/scripts/lakebase/detect-language.cli.js +16 -14
  25. package/dist/scripts/lakebase/doctor.cli.cjs +16 -14
  26. package/dist/scripts/lakebase/doctor.cli.js +16 -14
  27. package/dist/scripts/lakebase/get-connection.cli.cjs +16 -14
  28. package/dist/scripts/lakebase/get-connection.cli.js +16 -14
  29. package/dist/scripts/lakebase/index.cjs +313 -99
  30. package/dist/scripts/lakebase/index.d.cts +97 -2
  31. package/dist/scripts/lakebase/index.d.ts +97 -2
  32. package/dist/scripts/lakebase/index.js +310 -99
  33. package/dist/scripts/lakebase/infra-runner.cli.cjs +16 -14
  34. package/dist/scripts/lakebase/infra-runner.cli.js +16 -14
  35. package/dist/scripts/lakebase/new-migration.cli.cjs +16 -14
  36. package/dist/scripts/lakebase/new-migration.cli.js +16 -14
  37. package/dist/scripts/lakebase/schema-diff.cli.cjs +16 -14
  38. package/dist/scripts/lakebase/schema-diff.cli.js +16 -14
  39. package/dist/scripts/lakebase/schema-migrate.cli.cjs +16 -14
  40. package/dist/scripts/lakebase/schema-migrate.cli.js +16 -14
  41. package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +59 -24
  42. package/dist/scripts/lakebase/scm-claim-feature.cli.js +59 -24
  43. package/dist/scripts/lakebase/scm-doctor.cli.cjs +59 -24
  44. package/dist/scripts/lakebase/scm-doctor.cli.js +59 -24
  45. package/dist/scripts/lakebase/scm-merge.cli.cjs +16 -14
  46. package/dist/scripts/lakebase/scm-merge.cli.js +16 -14
  47. package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +16 -14
  48. package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +16 -14
  49. package/dist/scripts/lakebase/scm-recover-orphans.cli.cjs +43 -10
  50. package/dist/scripts/lakebase/scm-recover-orphans.cli.js +43 -10
  51. package/dist/scripts/lakebase/snapshot.cli.cjs +418 -0
  52. package/dist/scripts/lakebase/snapshot.cli.d.cts +1 -0
  53. package/dist/scripts/lakebase/snapshot.cli.d.ts +1 -0
  54. package/dist/scripts/lakebase/snapshot.cli.js +395 -0
  55. package/dist/scripts/util/index.cjs +2 -2
  56. package/dist/scripts/util/index.js +2 -2
  57. package/package.json +2 -1
  58. package/scripts/git/commit-push.ts +60 -14
  59. package/scripts/lakebase/branch-create.ts +93 -14
  60. package/scripts/lakebase/branch.cli.ts +15 -0
  61. package/scripts/lakebase/create-preflight.ts +213 -1
  62. package/scripts/lakebase/create-project.ts +98 -30
  63. package/scripts/lakebase/get-connection.ts +29 -12
  64. package/scripts/lakebase/snapshot.cli.ts +117 -0
  65. package/scripts/lakebase/snapshot.ts +85 -0
  66. package/templates/project/common/scripts/run-tests.sh +43 -2
  67. package/templates/project/python/tests/conftest.py +22 -0
  68. package/templates/project/common/tests/e2e/__pycache__/conftest.cpython-314.pyc +0 -0
  69. package/templates/project/python/tests/__pycache__/conftest.cpython-314.pyc +0 -0
@@ -9172,9 +9172,46 @@ function dbcli2(args, host, timeout = KIT_TIMEOUTS.cliDefault) {
9172
9172
  }
9173
9173
 
9174
9174
  // scripts/lakebase/branch-create.ts
9175
+ function snapshotPath(instance, snapshot) {
9176
+ return snapshot.includes("/") ? snapshot : `${projectPath(instance)}/snapshots/${snapshot}`;
9177
+ }
9178
+ function applyExpiration(spec, ttl, noExpiry) {
9179
+ if (ttl && noExpiry === true) {
9180
+ throw new LakebaseBranchError(
9181
+ `Cannot set both ttl ("${ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
9182
+ );
9183
+ }
9184
+ if (ttl) spec.ttl = ttl;
9185
+ else if (noExpiry ?? true) spec.no_expiry = true;
9186
+ }
9175
9187
  async function createBranch(args) {
9176
9188
  const sanitized = sanitizeBranchName(args.branch);
9177
9189
  const lookup = { instance: args.instance, host: args.host };
9190
+ if (args.fromSnapshot) {
9191
+ if (args.parentBranch || args.sourceBranchTime || args.sourceBranchLsn) {
9192
+ throw new LakebaseBranchError(
9193
+ `fromSnapshot is mutually exclusive with parentBranch / sourceBranchTime / sourceBranchLsn (the Lakebase API rejects source_snapshot combined with any source_branch field).`
9194
+ );
9195
+ }
9196
+ const existing2 = await getBranchByName(sanitized, lookup);
9197
+ if (existing2) return existing2;
9198
+ const spec = { source_snapshot: snapshotPath(args.instance, args.fromSnapshot) };
9199
+ applyExpiration(spec, args.ttl, args.noExpiry);
9200
+ try {
9201
+ await createWithTtlRecovery(args.instance, sanitized, spec, args.host);
9202
+ } catch (err) {
9203
+ if (err instanceof LakebaseBranchTtlTooLongError) throw err;
9204
+ const landed = await getBranchByName(sanitized, lookup);
9205
+ if (!landed) throw err;
9206
+ }
9207
+ return waitForBranchReady({
9208
+ instance: args.instance,
9209
+ host: args.host,
9210
+ branch: sanitized,
9211
+ timeoutMs: args.readyTimeoutMs ?? KIT_TIMEOUTS.readyWait,
9212
+ pollIntervalMs: args.pollIntervalMs ?? KIT_TIMEOUTS.readyPoll
9213
+ });
9214
+ }
9178
9215
  let sourceBranchPath;
9179
9216
  if (args.parentBranch) {
9180
9217
  if (looksLikeBranchUid(args.parentBranch)) {
@@ -9222,19 +9259,15 @@ async function createBranch(args) {
9222
9259
  assertSourceMatches(existing, sourceBranchPath, sanitized);
9223
9260
  return existing;
9224
9261
  }
9225
- if (args.ttl && args.noExpiry === true) {
9262
+ if (args.sourceBranchTime && args.sourceBranchLsn) {
9226
9263
  throw new LakebaseBranchError(
9227
- `Cannot set both ttl ("${args.ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
9264
+ `sourceBranchTime and sourceBranchLsn are mutually exclusive \u2013 pass at most one point-in-time.`
9228
9265
  );
9229
9266
  }
9230
- const specObj = {
9231
- source_branch: sourceBranchPath
9232
- };
9233
- if (args.ttl) {
9234
- specObj.ttl = args.ttl;
9235
- } else if (args.noExpiry ?? true) {
9236
- specObj.no_expiry = true;
9237
- }
9267
+ const specObj = { source_branch: sourceBranchPath };
9268
+ if (args.sourceBranchTime) specObj.source_branch_time = args.sourceBranchTime;
9269
+ else if (args.sourceBranchLsn) specObj.source_branch_lsn = args.sourceBranchLsn;
9270
+ applyExpiration(specObj, args.ttl, args.noExpiry);
9238
9271
  try {
9239
9272
  await createWithTtlRecovery(args.instance, sanitized, specObj, args.host);
9240
9273
  } catch (err) {
@@ -9393,8 +9426,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
9393
9426
  var cached;
9394
9427
  function substrateSelfVersion() {
9395
9428
  if (cached !== void 0) return cached;
9396
- if ("0.3.9".length > 0) {
9397
- cached = "0.3.9";
9429
+ if ("0.3.11".length > 0) {
9430
+ cached = "0.3.11";
9398
9431
  return cached;
9399
9432
  }
9400
9433
  cached = "unknown";
@@ -9441,22 +9474,24 @@ async function getConnection(args) {
9441
9474
  const endpointPath2 = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
9442
9475
  if (args.output === "dsn") {
9443
9476
  const host2 = await resolveEndpointHost(args.instance, branchId);
9444
- const { token, email: email2 } = await mintCredential(endpointPath2);
9445
- const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token });
9477
+ const { token: token2, email: email2 } = await mintCredential(endpointPath2);
9478
+ const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
9446
9479
  return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath: endpointPath2 };
9447
9480
  }
9448
9481
  const host = await resolveEndpointHost(args.instance, branchId);
9449
- const email = await resolveCurrentUser();
9450
9482
  process.env.PGAPPNAME = connectionApplicationName();
9451
- return createLakebasePool({
9452
- endpoint: endpointPath2,
9453
- host,
9454
- database,
9455
- user: email,
9456
- // workspaceClient is passed through verbatim. createLakebasePool falls
9457
- // back to environment / ServiceContext when omitted.
9458
- ...args.workspaceClient !== void 0 ? { workspaceClient: args.workspaceClient } : {}
9459
- });
9483
+ if (args.workspaceClient !== void 0) {
9484
+ const email2 = await resolveCurrentUser();
9485
+ return createLakebasePool({
9486
+ endpoint: endpointPath2,
9487
+ host,
9488
+ database,
9489
+ user: email2,
9490
+ workspaceClient: args.workspaceClient
9491
+ });
9492
+ }
9493
+ const { token, email } = await mintCredential(endpointPath2);
9494
+ return createLakebasePool({ host, database, user: email, password: token });
9460
9495
  }
9461
9496
  async function resolveEndpointHost(instance, branch) {
9462
9497
  const branchId = await resolveBranchId({ instance, branch });
@@ -88825,8 +88825,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
88825
88825
  var cached;
88826
88826
  function substrateSelfVersion() {
88827
88827
  if (cached !== void 0) return cached;
88828
- if ("0.3.9".length > 0) {
88829
- cached = "0.3.9";
88828
+ if ("0.3.11".length > 0) {
88829
+ cached = "0.3.11";
88830
88830
  return cached;
88831
88831
  }
88832
88832
  cached = "unknown";
@@ -88873,22 +88873,24 @@ async function getConnection(args) {
88873
88873
  const endpointPath = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
88874
88874
  if (args.output === "dsn") {
88875
88875
  const host2 = await resolveEndpointHost(args.instance, branchId);
88876
- const { token, email: email2 } = await mintCredential(endpointPath);
88877
- const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token });
88876
+ const { token: token2, email: email2 } = await mintCredential(endpointPath);
88877
+ const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
88878
88878
  return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath };
88879
88879
  }
88880
88880
  const host = await resolveEndpointHost(args.instance, branchId);
88881
- const email = await resolveCurrentUser();
88882
88881
  process.env.PGAPPNAME = connectionApplicationName();
88883
- return createLakebasePool({
88884
- endpoint: endpointPath,
88885
- host,
88886
- database,
88887
- user: email,
88888
- // workspaceClient is passed through verbatim. createLakebasePool falls
88889
- // back to environment / ServiceContext when omitted.
88890
- ...args.workspaceClient !== void 0 ? { workspaceClient: args.workspaceClient } : {}
88891
- });
88882
+ if (args.workspaceClient !== void 0) {
88883
+ const email2 = await resolveCurrentUser();
88884
+ return createLakebasePool({
88885
+ endpoint: endpointPath,
88886
+ host,
88887
+ database,
88888
+ user: email2,
88889
+ workspaceClient: args.workspaceClient
88890
+ });
88891
+ }
88892
+ const { token, email } = await mintCredential(endpointPath);
88893
+ return createLakebasePool({ host, database, user: email, password: token });
88892
88894
  }
88893
88895
  async function resolveEndpointHost(instance, branch) {
88894
88896
  const branchId = await resolveBranchId({ instance, branch });
@@ -9978,8 +9978,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
9978
9978
  var cached;
9979
9979
  function substrateSelfVersion() {
9980
9980
  if (cached !== void 0) return cached;
9981
- if ("0.3.9".length > 0) {
9982
- cached = "0.3.9";
9981
+ if ("0.3.11".length > 0) {
9982
+ cached = "0.3.11";
9983
9983
  return cached;
9984
9984
  }
9985
9985
  cached = "unknown";
@@ -10026,22 +10026,24 @@ async function getConnection(args) {
10026
10026
  const endpointPath = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
10027
10027
  if (args.output === "dsn") {
10028
10028
  const host2 = await resolveEndpointHost(args.instance, branchId);
10029
- const { token, email: email2 } = await mintCredential(endpointPath);
10030
- const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token });
10029
+ const { token: token2, email: email2 } = await mintCredential(endpointPath);
10030
+ const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
10031
10031
  return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath };
10032
10032
  }
10033
10033
  const host = await resolveEndpointHost(args.instance, branchId);
10034
- const email = await resolveCurrentUser();
10035
10034
  process.env.PGAPPNAME = connectionApplicationName();
10036
- return createLakebasePool({
10037
- endpoint: endpointPath,
10038
- host,
10039
- database,
10040
- user: email,
10041
- // workspaceClient is passed through verbatim. createLakebasePool falls
10042
- // back to environment / ServiceContext when omitted.
10043
- ...args.workspaceClient !== void 0 ? { workspaceClient: args.workspaceClient } : {}
10044
- });
10035
+ if (args.workspaceClient !== void 0) {
10036
+ const email2 = await resolveCurrentUser();
10037
+ return createLakebasePool({
10038
+ endpoint: endpointPath,
10039
+ host,
10040
+ database,
10041
+ user: email2,
10042
+ workspaceClient: args.workspaceClient
10043
+ });
10044
+ }
10045
+ const { token, email } = await mintCredential(endpointPath);
10046
+ return createLakebasePool({ host, database, user: email, password: token });
10045
10047
  }
10046
10048
  async function resolveEndpointHost(instance, branch) {
10047
10049
  const branchId = await resolveBranchId({ instance, branch });
@@ -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.9".length > 0) {
79292
- cached = "0.3.9";
79291
+ if ("0.3.11".length > 0) {
79292
+ cached = "0.3.11";
79293
79293
  return cached;
79294
79294
  }
79295
79295
  cached = "unknown";
@@ -79336,22 +79336,24 @@ async function getConnection(args) {
79336
79336
  const endpointPath = `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(endpointPath);
79340
- const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token });
79339
+ const { token: token2, email: email2 } = await mintCredential(endpointPath);
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 };
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: endpointPath,
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: endpointPath,
79349
+ host,
79350
+ database,
79351
+ user: email2,
79352
+ workspaceClient: args.workspaceClient
79353
+ });
79354
+ }
79355
+ const { token, email } = await mintCredential(endpointPath);
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.9".length > 0) {
393
- cached = "0.3.9";
392
+ if ("0.3.11".length > 0) {
393
+ cached = "0.3.11";
394
394
  return cached;
395
395
  }
396
396
  cached = "unknown";
@@ -437,22 +437,24 @@ async function getConnection(args) {
437
437
  const endpointPath = `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(endpointPath);
441
- const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token });
440
+ const { token: token2, email: email2 } = await mintCredential(endpointPath);
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 };
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: endpointPath,
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: endpointPath,
450
+ host,
451
+ database,
452
+ user: email2,
453
+ workspaceClient: args.workspaceClient
454
+ });
455
+ }
456
+ const { token, email } = await mintCredential(endpointPath);
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 });
@@ -78204,9 +78204,46 @@ function dbcli2(args, host, timeout = KIT_TIMEOUTS.cliDefault) {
78204
78204
  }
78205
78205
 
78206
78206
  // scripts/lakebase/branch-create.ts
78207
+ function snapshotPath(instance, snapshot) {
78208
+ return snapshot.includes("/") ? snapshot : `${projectPath(instance)}/snapshots/${snapshot}`;
78209
+ }
78210
+ function applyExpiration(spec, ttl, noExpiry) {
78211
+ if (ttl && noExpiry === true) {
78212
+ throw new LakebaseBranchError(
78213
+ `Cannot set both ttl ("${ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
78214
+ );
78215
+ }
78216
+ if (ttl) spec.ttl = ttl;
78217
+ else if (noExpiry ?? true) spec.no_expiry = true;
78218
+ }
78207
78219
  async function createBranch(args) {
78208
78220
  const sanitized = sanitizeBranchName(args.branch);
78209
78221
  const lookup = { instance: args.instance, host: args.host };
78222
+ if (args.fromSnapshot) {
78223
+ if (args.parentBranch || args.sourceBranchTime || args.sourceBranchLsn) {
78224
+ throw new LakebaseBranchError(
78225
+ `fromSnapshot is mutually exclusive with parentBranch / sourceBranchTime / sourceBranchLsn (the Lakebase API rejects source_snapshot combined with any source_branch field).`
78226
+ );
78227
+ }
78228
+ const existing2 = await getBranchByName(sanitized, lookup);
78229
+ if (existing2) return existing2;
78230
+ const spec = { source_snapshot: snapshotPath(args.instance, args.fromSnapshot) };
78231
+ applyExpiration(spec, args.ttl, args.noExpiry);
78232
+ try {
78233
+ await createWithTtlRecovery(args.instance, sanitized, spec, args.host);
78234
+ } catch (err) {
78235
+ if (err instanceof LakebaseBranchTtlTooLongError) throw err;
78236
+ const landed = await getBranchByName(sanitized, lookup);
78237
+ if (!landed) throw err;
78238
+ }
78239
+ return waitForBranchReady({
78240
+ instance: args.instance,
78241
+ host: args.host,
78242
+ branch: sanitized,
78243
+ timeoutMs: args.readyTimeoutMs ?? KIT_TIMEOUTS.readyWait,
78244
+ pollIntervalMs: args.pollIntervalMs ?? KIT_TIMEOUTS.readyPoll
78245
+ });
78246
+ }
78210
78247
  let sourceBranchPath;
78211
78248
  if (args.parentBranch) {
78212
78249
  if (looksLikeBranchUid(args.parentBranch)) {
@@ -78254,19 +78291,15 @@ async function createBranch(args) {
78254
78291
  assertSourceMatches(existing, sourceBranchPath, sanitized);
78255
78292
  return existing;
78256
78293
  }
78257
- if (args.ttl && args.noExpiry === true) {
78294
+ if (args.sourceBranchTime && args.sourceBranchLsn) {
78258
78295
  throw new LakebaseBranchError(
78259
- `Cannot set both ttl ("${args.ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
78296
+ `sourceBranchTime and sourceBranchLsn are mutually exclusive \u2013 pass at most one point-in-time.`
78260
78297
  );
78261
78298
  }
78262
- const specObj = {
78263
- source_branch: sourceBranchPath
78264
- };
78265
- if (args.ttl) {
78266
- specObj.ttl = args.ttl;
78267
- } else if (args.noExpiry ?? true) {
78268
- specObj.no_expiry = true;
78269
- }
78299
+ const specObj = { source_branch: sourceBranchPath };
78300
+ if (args.sourceBranchTime) specObj.source_branch_time = args.sourceBranchTime;
78301
+ else if (args.sourceBranchLsn) specObj.source_branch_lsn = args.sourceBranchLsn;
78302
+ applyExpiration(specObj, args.ttl, args.noExpiry);
78270
78303
  try {
78271
78304
  await createWithTtlRecovery(args.instance, sanitized, specObj, args.host);
78272
78305
  } catch (err) {
@@ -659,9 +659,46 @@ function dbcli2(args, host, timeout = KIT_TIMEOUTS.cliDefault) {
659
659
  }
660
660
 
661
661
  // scripts/lakebase/branch-create.ts
662
+ function snapshotPath(instance, snapshot) {
663
+ return snapshot.includes("/") ? snapshot : `${projectPath(instance)}/snapshots/${snapshot}`;
664
+ }
665
+ function applyExpiration(spec, ttl, noExpiry) {
666
+ if (ttl && noExpiry === true) {
667
+ throw new LakebaseBranchError(
668
+ `Cannot set both ttl ("${ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
669
+ );
670
+ }
671
+ if (ttl) spec.ttl = ttl;
672
+ else if (noExpiry ?? true) spec.no_expiry = true;
673
+ }
662
674
  async function createBranch(args) {
663
675
  const sanitized = sanitizeBranchName(args.branch);
664
676
  const lookup = { instance: args.instance, host: args.host };
677
+ if (args.fromSnapshot) {
678
+ if (args.parentBranch || args.sourceBranchTime || args.sourceBranchLsn) {
679
+ throw new LakebaseBranchError(
680
+ `fromSnapshot is mutually exclusive with parentBranch / sourceBranchTime / sourceBranchLsn (the Lakebase API rejects source_snapshot combined with any source_branch field).`
681
+ );
682
+ }
683
+ const existing2 = await getBranchByName(sanitized, lookup);
684
+ if (existing2) return existing2;
685
+ const spec = { source_snapshot: snapshotPath(args.instance, args.fromSnapshot) };
686
+ applyExpiration(spec, args.ttl, args.noExpiry);
687
+ try {
688
+ await createWithTtlRecovery(args.instance, sanitized, spec, args.host);
689
+ } catch (err) {
690
+ if (err instanceof LakebaseBranchTtlTooLongError) throw err;
691
+ const landed = await getBranchByName(sanitized, lookup);
692
+ if (!landed) throw err;
693
+ }
694
+ return waitForBranchReady({
695
+ instance: args.instance,
696
+ host: args.host,
697
+ branch: sanitized,
698
+ timeoutMs: args.readyTimeoutMs ?? KIT_TIMEOUTS.readyWait,
699
+ pollIntervalMs: args.pollIntervalMs ?? KIT_TIMEOUTS.readyPoll
700
+ });
701
+ }
665
702
  let sourceBranchPath;
666
703
  if (args.parentBranch) {
667
704
  if (looksLikeBranchUid(args.parentBranch)) {
@@ -709,19 +746,15 @@ async function createBranch(args) {
709
746
  assertSourceMatches(existing, sourceBranchPath, sanitized);
710
747
  return existing;
711
748
  }
712
- if (args.ttl && args.noExpiry === true) {
749
+ if (args.sourceBranchTime && args.sourceBranchLsn) {
713
750
  throw new LakebaseBranchError(
714
- `Cannot set both ttl ("${args.ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
751
+ `sourceBranchTime and sourceBranchLsn are mutually exclusive \u2013 pass at most one point-in-time.`
715
752
  );
716
753
  }
717
- const specObj = {
718
- source_branch: sourceBranchPath
719
- };
720
- if (args.ttl) {
721
- specObj.ttl = args.ttl;
722
- } else if (args.noExpiry ?? true) {
723
- specObj.no_expiry = true;
724
- }
754
+ const specObj = { source_branch: sourceBranchPath };
755
+ if (args.sourceBranchTime) specObj.source_branch_time = args.sourceBranchTime;
756
+ else if (args.sourceBranchLsn) specObj.source_branch_lsn = args.sourceBranchLsn;
757
+ applyExpiration(specObj, args.ttl, args.noExpiry);
725
758
  try {
726
759
  await createWithTtlRecovery(args.instance, sanitized, specObj, args.host);
727
760
  } catch (err) {