@warmhub/cli 0.109.0 → 0.111.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.
Files changed (2) hide show
  1. package/dist/wh.js +1197 -172
  2. package/package.json +1 -1
package/dist/wh.js CHANGED
@@ -11910,7 +11910,7 @@ var require_response = __commonJS((exports, module) => {
11910
11910
  var { types } = __require("node:util");
11911
11911
  var textEncoder2 = new TextEncoder("utf-8");
11912
11912
 
11913
- class Response {
11913
+ class Response2 {
11914
11914
  static error() {
11915
11915
  const responseObject = fromInnerResponse(makeNetworkError(), "immutable");
11916
11916
  return responseObject;
@@ -11966,11 +11966,11 @@ var require_response = __commonJS((exports, module) => {
11966
11966
  initializeResponse(this, init, bodyWithType);
11967
11967
  }
11968
11968
  get type() {
11969
- webidl.brandCheck(this, Response);
11969
+ webidl.brandCheck(this, Response2);
11970
11970
  return this[kState].type;
11971
11971
  }
11972
11972
  get url() {
11973
- webidl.brandCheck(this, Response);
11973
+ webidl.brandCheck(this, Response2);
11974
11974
  const urlList = this[kState].urlList;
11975
11975
  const url2 = urlList[urlList.length - 1] ?? null;
11976
11976
  if (url2 === null) {
@@ -11979,35 +11979,35 @@ var require_response = __commonJS((exports, module) => {
11979
11979
  return URLSerializer(url2, true);
11980
11980
  }
11981
11981
  get redirected() {
11982
- webidl.brandCheck(this, Response);
11982
+ webidl.brandCheck(this, Response2);
11983
11983
  return this[kState].urlList.length > 1;
11984
11984
  }
11985
11985
  get status() {
11986
- webidl.brandCheck(this, Response);
11986
+ webidl.brandCheck(this, Response2);
11987
11987
  return this[kState].status;
11988
11988
  }
11989
11989
  get ok() {
11990
- webidl.brandCheck(this, Response);
11990
+ webidl.brandCheck(this, Response2);
11991
11991
  return this[kState].status >= 200 && this[kState].status <= 299;
11992
11992
  }
11993
11993
  get statusText() {
11994
- webidl.brandCheck(this, Response);
11994
+ webidl.brandCheck(this, Response2);
11995
11995
  return this[kState].statusText;
11996
11996
  }
11997
11997
  get headers() {
11998
- webidl.brandCheck(this, Response);
11998
+ webidl.brandCheck(this, Response2);
11999
11999
  return this[kHeaders];
12000
12000
  }
12001
12001
  get body() {
12002
- webidl.brandCheck(this, Response);
12002
+ webidl.brandCheck(this, Response2);
12003
12003
  return this[kState].body ? this[kState].body.stream : null;
12004
12004
  }
12005
12005
  get bodyUsed() {
12006
- webidl.brandCheck(this, Response);
12006
+ webidl.brandCheck(this, Response2);
12007
12007
  return !!this[kState].body && util.isDisturbed(this[kState].body.stream);
12008
12008
  }
12009
12009
  clone() {
12010
- webidl.brandCheck(this, Response);
12010
+ webidl.brandCheck(this, Response2);
12011
12011
  if (bodyUnusable(this)) {
12012
12012
  throw webidl.errors.exception({
12013
12013
  header: "Response.clone",
@@ -12039,8 +12039,8 @@ var require_response = __commonJS((exports, module) => {
12039
12039
  return `Response ${nodeUtil.formatWithOptions(options, properties)}`;
12040
12040
  }
12041
12041
  }
12042
- mixinBody(Response);
12043
- Object.defineProperties(Response.prototype, {
12042
+ mixinBody(Response2);
12043
+ Object.defineProperties(Response2.prototype, {
12044
12044
  type: kEnumerableProperty,
12045
12045
  url: kEnumerableProperty,
12046
12046
  status: kEnumerableProperty,
@@ -12056,7 +12056,7 @@ var require_response = __commonJS((exports, module) => {
12056
12056
  configurable: true
12057
12057
  }
12058
12058
  });
12059
- Object.defineProperties(Response, {
12059
+ Object.defineProperties(Response2, {
12060
12060
  json: kEnumerableProperty,
12061
12061
  redirect: kEnumerableProperty,
12062
12062
  error: kEnumerableProperty
@@ -12182,7 +12182,7 @@ var require_response = __commonJS((exports, module) => {
12182
12182
  }
12183
12183
  }
12184
12184
  function fromInnerResponse(innerResponse, guard) {
12185
- const response = new Response(kConstruct);
12185
+ const response = new Response2(kConstruct);
12186
12186
  response[kState] = innerResponse;
12187
12187
  response[kHeaders] = new Headers2(kConstruct);
12188
12188
  setHeadersList(response[kHeaders], innerResponse.headersList);
@@ -12244,7 +12244,7 @@ var require_response = __commonJS((exports, module) => {
12244
12244
  makeResponse,
12245
12245
  makeAppropriateNetworkError,
12246
12246
  filterResponse,
12247
- Response,
12247
+ Response: Response2,
12248
12248
  cloneResponse,
12249
12249
  fromInnerResponse
12250
12250
  };
@@ -14688,7 +14688,7 @@ var require_cache = __commonJS((exports, module) => {
14688
14688
  var { urlEquals, getFieldValues } = require_util5();
14689
14689
  var { kEnumerableProperty, isDisturbed } = require_util();
14690
14690
  var { webidl } = require_webidl();
14691
- var { Response, cloneResponse, fromInnerResponse } = require_response();
14691
+ var { Response: Response2, cloneResponse, fromInnerResponse } = require_response();
14692
14692
  var { Request, fromInnerRequest } = require_request2();
14693
14693
  var { kState } = require_symbols2();
14694
14694
  var { fetching } = require_fetch();
@@ -15178,7 +15178,7 @@ var require_cache = __commonJS((exports, module) => {
15178
15178
  converter: webidl.converters.DOMString
15179
15179
  }
15180
15180
  ]);
15181
- webidl.converters.Response = webidl.interfaceConverter(Response);
15181
+ webidl.converters.Response = webidl.interfaceConverter(Response2);
15182
15182
  webidl.converters["sequence<RequestInfo>"] = webidl.sequenceConverter(webidl.converters.RequestInfo);
15183
15183
  module.exports = {
15184
15184
  Cache
@@ -17301,7 +17301,7 @@ var require_eventsource_stream = __commonJS((exports, module) => {
17301
17301
  var { Transform } = __require("node:stream");
17302
17302
  var { isASCIINumber, isValidLastEventId } = require_util8();
17303
17303
  var BOM = [239, 187, 191];
17304
- var LF = 10;
17304
+ var LF3 = 10;
17305
17305
  var CR = 13;
17306
17306
  var COLON = 58;
17307
17307
  var SPACE = 32;
@@ -17374,7 +17374,7 @@ var require_eventsource_stream = __commonJS((exports, module) => {
17374
17374
  while (this.pos < this.buffer.length) {
17375
17375
  if (this.eventEndCheck) {
17376
17376
  if (this.crlfCheck) {
17377
- if (this.buffer[this.pos] === LF) {
17377
+ if (this.buffer[this.pos] === LF3) {
17378
17378
  this.buffer = this.buffer.subarray(this.pos + 1);
17379
17379
  this.pos = 0;
17380
17380
  this.crlfCheck = false;
@@ -17382,7 +17382,7 @@ var require_eventsource_stream = __commonJS((exports, module) => {
17382
17382
  }
17383
17383
  this.crlfCheck = false;
17384
17384
  }
17385
- if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) {
17385
+ if (this.buffer[this.pos] === LF3 || this.buffer[this.pos] === CR) {
17386
17386
  if (this.buffer[this.pos] === CR) {
17387
17387
  this.crlfCheck = true;
17388
17388
  }
@@ -17397,7 +17397,7 @@ var require_eventsource_stream = __commonJS((exports, module) => {
17397
17397
  this.eventEndCheck = false;
17398
17398
  continue;
17399
17399
  }
17400
- if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) {
17400
+ if (this.buffer[this.pos] === LF3 || this.buffer[this.pos] === CR) {
17401
17401
  if (this.buffer[this.pos] === CR) {
17402
17402
  this.crlfCheck = true;
17403
17403
  }
@@ -35401,6 +35401,37 @@ var checkpointManifestFields = {
35401
35401
  var checkpointManifestContentSchema = exports_external.object(checkpointManifestFields).strict();
35402
35402
  var checkpointManifestV2Schema = checkpointManifestContentSchema.extend({ contentSha256: checkpointSha256Schema }).strict();
35403
35403
 
35404
+ // ../../packages/rules/src/canonical-line.ts
35405
+ var utf8Encoder2 = new TextEncoder;
35406
+ var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
35407
+ function encodeCanonicalLine(value) {
35408
+ return utf8Encoder2.encode(`${stableJson(value)}
35409
+ `);
35410
+ }
35411
+ function assertCanonicalLineFraming(bytes, subject) {
35412
+ if (bytes.length === 0 || bytes.at(-1) !== 10) {
35413
+ throw new Error(`${subject} must end with one LF`);
35414
+ }
35415
+ if (bytes.length >= 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) {
35416
+ throw new Error(`${subject} must not contain a UTF-8 BOM`);
35417
+ }
35418
+ for (let index = 0;index < bytes.length - 1; index += 1) {
35419
+ if (bytes[index] === 10 || bytes[index] === 13) {
35420
+ throw new Error(`${subject} must contain exactly one LF and no CR`);
35421
+ }
35422
+ }
35423
+ }
35424
+ function parseCanonicalLine(bytes, schema, subject) {
35425
+ assertCanonicalLineFraming(bytes, subject);
35426
+ const decoded = utf8Decoder.decode(bytes);
35427
+ const parsed = schema.parse(JSON.parse(decoded.slice(0, -1)));
35428
+ if (decoded !== `${stableJson(parsed)}
35429
+ `) {
35430
+ throw new Error(`${subject} bytes are not canonical`);
35431
+ }
35432
+ return parsed;
35433
+ }
35434
+
35404
35435
  // ../../packages/rules/src/repository-checkpoint/paths.ts
35405
35436
  var MAX_CHECKPOINT_PART = 10 ** CHECKPOINT_PART_DIGITS - 1;
35406
35437
  async function checkpointShapeKey(shapeName) {
@@ -35427,7 +35458,7 @@ function assertCheckpointPart(part) {
35427
35458
  }
35428
35459
 
35429
35460
  // ../../packages/rules/src/repository-checkpoint/manifest.ts
35430
- var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
35461
+ var utf8Decoder2 = new TextDecoder("utf-8", { fatal: true });
35431
35462
  async function validateCheckpointManifest(input) {
35432
35463
  const manifest = checkpointManifestV2Schema.parse(input);
35433
35464
  const { contentSha256, ...content } = manifest;
@@ -35444,8 +35475,8 @@ async function encodeCheckpointManifest(input) {
35444
35475
  `);
35445
35476
  }
35446
35477
  async function parseCheckpointManifest(bytes) {
35447
- assertCanonicalManifestFraming(bytes);
35448
- const decoded = utf8Decoder.decode(bytes);
35478
+ assertCanonicalLineFraming(bytes, "Checkpoint manifest");
35479
+ const decoded = utf8Decoder2.decode(bytes);
35449
35480
  const manifest = await validateCheckpointManifest(checkpointManifestV2Schema.parse(JSON.parse(decoded.slice(0, -1))));
35450
35481
  const canonical = await encodeCheckpointManifest(manifest);
35451
35482
  if (!bytesEqual(bytes, canonical)) {
@@ -35491,46 +35522,14 @@ function addSafeCounts(left, right) {
35491
35522
  }
35492
35523
  return total;
35493
35524
  }
35494
- function assertCanonicalManifestFraming(bytes) {
35495
- if (bytes.length === 0 || bytes.at(-1) !== 10) {
35496
- throw new Error("Checkpoint manifest must end with one LF");
35497
- }
35498
- if (bytes.length >= 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) {
35499
- throw new Error("Checkpoint manifest must not contain a UTF-8 BOM");
35500
- }
35501
- for (let index = 0;index < bytes.length - 1; index += 1) {
35502
- if (bytes[index] === 10 || bytes[index] === 13) {
35503
- throw new Error("Checkpoint manifest must contain exactly one LF and no CR");
35504
- }
35505
- }
35506
- }
35507
35525
  function bytesEqual(left, right) {
35508
35526
  if (left.length !== right.length)
35509
35527
  return false;
35510
35528
  return left.every((byte, index) => byte === right[index]);
35511
35529
  }
35512
35530
  // ../../packages/rules/src/repository-checkpoint/row-codec.ts
35513
- var utf8Encoder2 = new TextEncoder;
35514
- var utf8Decoder2 = new TextDecoder("utf-8", { fatal: true });
35515
35531
  function parseCheckpointRowLine(bytes) {
35516
- if (bytes.length === 0 || bytes[bytes.length - 1] !== 10) {
35517
- throw new Error("Checkpoint row must end with one LF");
35518
- }
35519
- if (bytes.length >= 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) {
35520
- throw new Error("Checkpoint row must not contain a UTF-8 BOM");
35521
- }
35522
- for (let index = 0;index < bytes.length - 1; index += 1) {
35523
- if (bytes[index] === 10 || bytes[index] === 13) {
35524
- throw new Error("Checkpoint row must contain exactly one LF and no CR");
35525
- }
35526
- }
35527
- const decoded = utf8Decoder2.decode(bytes);
35528
- const parsed = checkpointRowSchema.parse(JSON.parse(decoded.slice(0, -1)));
35529
- if (decoded !== `${stableJson(parsed)}
35530
- `) {
35531
- throw new Error("Checkpoint row bytes are not canonical");
35532
- }
35533
- return parsed;
35532
+ return parseCanonicalLine(bytes, checkpointRowSchema, "Checkpoint row");
35534
35533
  }
35535
35534
  // ../../packages/rules/src/repository-checkpoint/streams.ts
35536
35535
  function createCheckpointStreamValidationState(shapeName) {
@@ -35582,6 +35581,327 @@ function addOneSafe(value) {
35582
35581
  }
35583
35582
  return next;
35584
35583
  }
35584
+ // ../../packages/rules/src/repository-export/types.ts
35585
+ var REPOSITORY_EXPORT_FORMAT_VERSION = 3;
35586
+ var REPOSITORY_EXPORT_MEDIA_TYPE = "application/x-ndjson";
35587
+ var repositoryExportSha256Schema = exports_external.string().regex(/^[0-9a-f]{64}$/);
35588
+ var nonnegativeSafeIntegerSchema2 = exports_external.number().int().nonnegative();
35589
+ var positiveSafeIntegerSchema2 = exports_external.number().int().positive();
35590
+ var REPOSITORY_EXPORT_ROW_KINDS = [
35591
+ "shape",
35592
+ "thing",
35593
+ "collection",
35594
+ "assertion"
35595
+ ];
35596
+ var REPOSITORY_EXPORT_MODES = ["heads", "ops"];
35597
+ var REPOSITORY_EXPORT_SHAPE_PROVENANCES = [
35598
+ "captured",
35599
+ "migration-stamped",
35600
+ "reconstructed"
35601
+ ];
35602
+ var repositoryExportShapeCertificateSchema = exports_external.object({
35603
+ name: exports_external.string().min(1),
35604
+ v: positiveSafeIntegerSchema2,
35605
+ durableId: exports_external.string().min(1),
35606
+ provenance: exports_external.enum(REPOSITORY_EXPORT_SHAPE_PROVENANCES),
35607
+ declared: exports_external.boolean()
35608
+ }).strict();
35609
+ var repositoryExportReferenceSchema = exports_external.object({
35610
+ wref: exports_external.string().min(1),
35611
+ v: positiveSafeIntegerSchema2.optional(),
35612
+ durableId: exports_external.string().min(1)
35613
+ }).strict();
35614
+ function refineStrictlyIncreasing(entries, key, message, context) {
35615
+ let previous;
35616
+ entries.forEach((entry, index) => {
35617
+ const current = key(entry);
35618
+ if (previous !== undefined && compareUnsignedUtf8(previous, current) >= 0) {
35619
+ context.addIssue({ code: "custom", path: [index], message });
35620
+ }
35621
+ previous = current;
35622
+ });
35623
+ }
35624
+ var shapesSchema = exports_external.array(repositoryExportShapeCertificateSchema).superRefine((shapes, context) => {
35625
+ refineStrictlyIncreasing(shapes, (entry) => entry.durableId, "Shape certificates must be unique and strictly increasing by durableId", context);
35626
+ });
35627
+ var affirmedSchema = exports_external.array(repositoryExportReferenceSchema).superRefine((affirmed, context) => {
35628
+ refineStrictlyIncreasing(affirmed, (entry) => entry.wref, "Affirmed references must be unique and strictly increasing", context);
35629
+ });
35630
+ var rowEnvelopeFields = {
35631
+ wref: exports_external.string().min(1),
35632
+ durableId: exports_external.string().min(1),
35633
+ version: positiveSafeIntegerSchema2
35634
+ };
35635
+ var activeRowFields = {
35636
+ ...rowEnvelopeFields,
35637
+ active: exports_external.literal(true),
35638
+ data: exports_external.record(exports_external.string(), jsonValueSchema)
35639
+ };
35640
+ var activeRowSchema = exports_external.discriminatedUnion("kind", [
35641
+ exports_external.object({
35642
+ ...activeRowFields,
35643
+ kind: exports_external.literal("shape"),
35644
+ shapes: exports_external.array(repositoryExportShapeCertificateSchema).max(0)
35645
+ }).strict(),
35646
+ exports_external.object({
35647
+ ...activeRowFields,
35648
+ kind: exports_external.enum(["thing", "collection"]),
35649
+ shapes: shapesSchema
35650
+ }).strict(),
35651
+ exports_external.object({
35652
+ ...activeRowFields,
35653
+ kind: exports_external.literal("assertion"),
35654
+ shapes: shapesSchema,
35655
+ about: repositoryExportReferenceSchema,
35656
+ affirmed: affirmedSchema
35657
+ }).strict()
35658
+ ]);
35659
+ var tombstoneRowSchema = exports_external.object({
35660
+ ...rowEnvelopeFields,
35661
+ kind: exports_external.enum(REPOSITORY_EXPORT_ROW_KINDS),
35662
+ active: exports_external.literal(false)
35663
+ }).strict();
35664
+ var repositoryExportRowSchema = exports_external.union([
35665
+ activeRowSchema,
35666
+ tombstoneRowSchema
35667
+ ]);
35668
+ var repositoryExportHeaderSchema = exports_external.object({
35669
+ kind: exports_external.literal("header"),
35670
+ formatVersion: exports_external.literal(REPOSITORY_EXPORT_FORMAT_VERSION),
35671
+ repo: exports_external.string().regex(/^[^/\s]+\/[^/\s]+$/, 'repo must be "<org>/<repo>"'),
35672
+ mode: exports_external.enum(REPOSITORY_EXPORT_MODES),
35673
+ sinceRepoSeq: nonnegativeSafeIntegerSchema2,
35674
+ atRepoSeq: nonnegativeSafeIntegerSchema2
35675
+ }).strict().refine((header) => header.atRepoSeq >= header.sinceRepoSeq, "atRepoSeq must not precede sinceRepoSeq");
35676
+ var repositoryExportTrailerSchema = exports_external.object({
35677
+ kind: exports_external.literal("trailer"),
35678
+ recordCount: nonnegativeSafeIntegerSchema2,
35679
+ contentSha256: repositoryExportSha256Schema,
35680
+ atRepoSeq: nonnegativeSafeIntegerSchema2
35681
+ }).strict();
35682
+ function repositoryExportAllowsTombstones(header) {
35683
+ return header.sinceRepoSeq > 0;
35684
+ }
35685
+
35686
+ // ../../packages/rules/src/repository-export/codec.ts
35687
+ function encodeRepositoryExportRow(row) {
35688
+ return encodeCanonicalLine(repositoryExportRowSchema.parse(row));
35689
+ }
35690
+ function encodeRepositoryExportHeader(header) {
35691
+ return encodeCanonicalLine(repositoryExportHeaderSchema.parse(header));
35692
+ }
35693
+ function encodeRepositoryExportTrailer(trailer) {
35694
+ return encodeCanonicalLine(repositoryExportTrailerSchema.parse(trailer));
35695
+ }
35696
+ function parseRepositoryExportRowLine(bytes) {
35697
+ return parseCanonicalLine(bytes, repositoryExportRowSchema, "Repository export row");
35698
+ }
35699
+ function parseRepositoryExportHeaderLine(bytes) {
35700
+ return parseCanonicalLine(bytes, repositoryExportHeaderSchema, "Repository export header");
35701
+ }
35702
+ function parseRepositoryExportTrailerLine(bytes) {
35703
+ return parseCanonicalLine(bytes, repositoryExportTrailerSchema, "Repository export trailer");
35704
+ }
35705
+ // ../../packages/rules/src/repository-export/sha256.ts
35706
+ var ROUND_CONSTANTS = Uint32Array.from([
35707
+ 1116352408,
35708
+ 1899447441,
35709
+ 3049323471,
35710
+ 3921009573,
35711
+ 961987163,
35712
+ 1508970993,
35713
+ 2453635748,
35714
+ 2870763221,
35715
+ 3624381080,
35716
+ 310598401,
35717
+ 607225278,
35718
+ 1426881987,
35719
+ 1925078388,
35720
+ 2162078206,
35721
+ 2614888103,
35722
+ 3248222580,
35723
+ 3835390401,
35724
+ 4022224774,
35725
+ 264347078,
35726
+ 604807628,
35727
+ 770255983,
35728
+ 1249150122,
35729
+ 1555081692,
35730
+ 1996064986,
35731
+ 2554220882,
35732
+ 2821834349,
35733
+ 2952996808,
35734
+ 3210313671,
35735
+ 3336571891,
35736
+ 3584528711,
35737
+ 113926993,
35738
+ 338241895,
35739
+ 666307205,
35740
+ 773529912,
35741
+ 1294757372,
35742
+ 1396182291,
35743
+ 1695183700,
35744
+ 1986661051,
35745
+ 2177026350,
35746
+ 2456956037,
35747
+ 2730485921,
35748
+ 2820302411,
35749
+ 3259730800,
35750
+ 3345764771,
35751
+ 3516065817,
35752
+ 3600352804,
35753
+ 4094571909,
35754
+ 275423344,
35755
+ 430227734,
35756
+ 506948616,
35757
+ 659060556,
35758
+ 883997877,
35759
+ 958139571,
35760
+ 1322822218,
35761
+ 1537002063,
35762
+ 1747873779,
35763
+ 1955562222,
35764
+ 2024104815,
35765
+ 2227730452,
35766
+ 2361852424,
35767
+ 2428436474,
35768
+ 2756734187,
35769
+ 3204031479,
35770
+ 3329325298
35771
+ ]);
35772
+ var INITIAL_STATE = Uint32Array.from([
35773
+ 1779033703,
35774
+ 3144134277,
35775
+ 1013904242,
35776
+ 2773480762,
35777
+ 1359893119,
35778
+ 2600822924,
35779
+ 528734635,
35780
+ 1541459225
35781
+ ]);
35782
+ var BLOCK_BYTES = 64;
35783
+ function rotr(value, bits) {
35784
+ return (value >>> bits | value << 32 - bits) >>> 0;
35785
+ }
35786
+
35787
+ class Sha256 {
35788
+ #state = Uint32Array.from(INITIAL_STATE);
35789
+ #schedule = new Uint32Array(64);
35790
+ #block = new Uint8Array(BLOCK_BYTES);
35791
+ #blockLength = 0;
35792
+ #byteLength = 0;
35793
+ #finished = false;
35794
+ update(bytes) {
35795
+ if (this.#finished) {
35796
+ throw new Error("SHA-256 hasher is already finalized");
35797
+ }
35798
+ this.#byteLength += bytes.length;
35799
+ if (!Number.isSafeInteger(this.#byteLength)) {
35800
+ throw new RangeError("SHA-256 input length must be a safe integer");
35801
+ }
35802
+ let offset = 0;
35803
+ if (this.#blockLength > 0) {
35804
+ const take = Math.min(BLOCK_BYTES - this.#blockLength, bytes.length);
35805
+ this.#block.set(bytes.subarray(0, take), this.#blockLength);
35806
+ this.#blockLength += take;
35807
+ offset = take;
35808
+ if (this.#blockLength < BLOCK_BYTES)
35809
+ return;
35810
+ this.#compress(this.#block, 0);
35811
+ this.#blockLength = 0;
35812
+ }
35813
+ while (offset + BLOCK_BYTES <= bytes.length) {
35814
+ this.#compress(bytes, offset);
35815
+ offset += BLOCK_BYTES;
35816
+ }
35817
+ if (offset < bytes.length) {
35818
+ this.#block.set(bytes.subarray(offset), 0);
35819
+ this.#blockLength = bytes.length - offset;
35820
+ }
35821
+ }
35822
+ digestHex() {
35823
+ if (this.#finished) {
35824
+ throw new Error("SHA-256 hasher is already finalized");
35825
+ }
35826
+ this.#finished = true;
35827
+ const tail = new Uint8Array(this.#blockLength < 56 ? 64 : 128);
35828
+ tail.set(this.#block.subarray(0, this.#blockLength), 0);
35829
+ tail[this.#blockLength] = 128;
35830
+ const view = new DataView(tail.buffer);
35831
+ view.setUint32(tail.length - 8, Math.floor(this.#byteLength / 536870912));
35832
+ view.setUint32(tail.length - 4, this.#byteLength << 3 >>> 0);
35833
+ for (let offset = 0;offset < tail.length; offset += BLOCK_BYTES) {
35834
+ this.#compress(tail, offset);
35835
+ }
35836
+ return Array.from(this.#state, (word) => word.toString(16).padStart(8, "0")).join("");
35837
+ }
35838
+ #compress(bytes, offset) {
35839
+ const schedule = this.#schedule;
35840
+ for (let index = 0;index < 16; index += 1) {
35841
+ const at = offset + index * 4;
35842
+ schedule[index] = (bytes[at] << 24 | bytes[at + 1] << 16 | bytes[at + 2] << 8 | bytes[at + 3]) >>> 0;
35843
+ }
35844
+ for (let index = 16;index < 64; index += 1) {
35845
+ const previous = schedule[index - 15];
35846
+ const recent = schedule[index - 2];
35847
+ const s0 = (rotr(previous, 7) ^ rotr(previous, 18) ^ previous >>> 3) >>> 0;
35848
+ const s1 = (rotr(recent, 17) ^ rotr(recent, 19) ^ recent >>> 10) >>> 0;
35849
+ schedule[index] = schedule[index - 16] + s0 + schedule[index - 7] + s1 >>> 0;
35850
+ }
35851
+ const state = this.#state;
35852
+ let a = state[0];
35853
+ let b = state[1];
35854
+ let c = state[2];
35855
+ let d = state[3];
35856
+ let e = state[4];
35857
+ let f = state[5];
35858
+ let g = state[6];
35859
+ let h = state[7];
35860
+ for (let index = 0;index < 64; index += 1) {
35861
+ const s1 = (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) >>> 0;
35862
+ const choice = (e & f ^ ~e & g) >>> 0;
35863
+ const temp1 = h + s1 + choice + ROUND_CONSTANTS[index] + schedule[index] >>> 0;
35864
+ const s0 = (rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) >>> 0;
35865
+ const majority = (a & b ^ a & c ^ b & c) >>> 0;
35866
+ const temp2 = s0 + majority >>> 0;
35867
+ h = g;
35868
+ g = f;
35869
+ f = e;
35870
+ e = d + temp1 >>> 0;
35871
+ d = c;
35872
+ c = b;
35873
+ b = a;
35874
+ a = temp1 + temp2 >>> 0;
35875
+ }
35876
+ state[0] = a + state[0] >>> 0;
35877
+ state[1] = b + state[1] >>> 0;
35878
+ state[2] = c + state[2] >>> 0;
35879
+ state[3] = d + state[3] >>> 0;
35880
+ state[4] = e + state[4] >>> 0;
35881
+ state[5] = f + state[5] >>> 0;
35882
+ state[6] = g + state[6] >>> 0;
35883
+ state[7] = h + state[7] >>> 0;
35884
+ }
35885
+ }
35886
+
35887
+ // ../../packages/rules/src/repository-export/digest.ts
35888
+ class RepositoryExportDigest {
35889
+ #hash = new Sha256;
35890
+ #rowCount = 0;
35891
+ get rowCount() {
35892
+ return this.#rowCount;
35893
+ }
35894
+ update(rowBytes) {
35895
+ this.#hash.update(rowBytes);
35896
+ this.#rowCount += 1;
35897
+ }
35898
+ finalize() {
35899
+ return this.#hash.digestHex();
35900
+ }
35901
+ }
35902
+ function createRepositoryExportDigest() {
35903
+ return new RepositoryExportDigest;
35904
+ }
35585
35905
  // ../../packages/rules/src/shape-types.ts
35586
35906
  var BASE_PRIMITIVE_TYPES = [
35587
35907
  "number",
@@ -43355,18 +43675,6 @@ function toRepositoryCheckpointSelector(selector) {
43355
43675
  }
43356
43676
  function createRepositoryCheckpointClient(getTrpc, toWarmHubError) {
43357
43677
  return {
43358
- generate: async (orgName, repoName, options) => {
43359
- try {
43360
- const result = await getTrpc().repo.checkpoint.generate.mutate({
43361
- orgName,
43362
- repoName,
43363
- atLeastRepoSeq: options?.atLeastRepoSeq
43364
- });
43365
- return normalizeRepositoryCheckpointStatus(result.checkpoint);
43366
- } catch (error51) {
43367
- throw toWarmHubError(error51);
43368
- }
43369
- },
43370
43678
  status: async (orgName, repoName, selector) => {
43371
43679
  try {
43372
43680
  const result = await getTrpc().repo.checkpoint.status.query({
@@ -43402,22 +43710,464 @@ function createRepositoryCheckpointClient(getTrpc, toWarmHubError) {
43402
43710
  } catch (error51) {
43403
43711
  throw toWarmHubError(error51);
43404
43712
  }
43405
- },
43406
- retry: async (orgName, repoName, checkpointId) => {
43713
+ }
43714
+ };
43715
+ }
43716
+
43717
+ // ../../packages/sdk-ts/src/repository-export/types.ts
43718
+ class RepositoryExportError extends Error {
43719
+ reason;
43720
+ name = "RepositoryExportError";
43721
+ constructor(reason, message) {
43722
+ super(message ?? REASON_MESSAGES[reason]);
43723
+ this.reason = reason;
43724
+ }
43725
+ }
43726
+ var REASON_MESSAGES = {
43727
+ count_mismatch: "Repository export trailer record count does not match the rows read",
43728
+ digest_mismatch: "Repository export content digest does not match the trailer",
43729
+ fence_mismatch: "Repository export header and trailer disagree about atRepoSeq",
43730
+ header_invalid: "Repository export header is invalid",
43731
+ row_invalid: "Repository export row is invalid or not canonical",
43732
+ row_out_of_order: "Repository export rows are not strictly increasing by durableId",
43733
+ since_below_epoch_floor: "Repository export delta base is below the epoch floor",
43734
+ trailer_invalid: "Repository export trailer is invalid",
43735
+ truncated: "Repository export stream ended before its trailer"
43736
+ };
43737
+
43738
+ class RepositoryExportSession {
43739
+ #streamDigest = createRepositoryExportDigest();
43740
+ #segmentDigest = createRepositoryExportDigest();
43741
+ #segmentRowCount = 0;
43742
+ #header;
43743
+ #lastDurableId;
43744
+ #token;
43745
+ #complete = false;
43746
+ #unverifiable = false;
43747
+ #contentSha256;
43748
+ get header() {
43749
+ return this.#header;
43750
+ }
43751
+ get lastDurableId() {
43752
+ return this.#lastDurableId;
43753
+ }
43754
+ get rowCount() {
43755
+ return this.#streamDigest.rowCount;
43756
+ }
43757
+ get segmentRowCount() {
43758
+ return this.#segmentRowCount;
43759
+ }
43760
+ get contentSha256() {
43761
+ return this.#contentSha256;
43762
+ }
43763
+ finalizeContentSha256() {
43764
+ if (this.#contentSha256 === undefined) {
43765
+ this.#contentSha256 = this.#streamDigest.finalize();
43766
+ this.#complete = true;
43767
+ }
43768
+ return this.#contentSha256;
43769
+ }
43770
+ beginSegment() {
43771
+ this.assertResumable();
43772
+ this.#segmentDigest = createRepositoryExportDigest();
43773
+ this.#segmentRowCount = 0;
43774
+ }
43775
+ markUnverifiable() {
43776
+ this.#unverifiable = true;
43777
+ }
43778
+ finalizeSegment() {
43779
+ return this.#segmentDigest.finalize();
43780
+ }
43781
+ get token() {
43782
+ return this.#token;
43783
+ }
43784
+ set token(value) {
43785
+ this.#token = value;
43786
+ }
43787
+ get complete() {
43788
+ return this.#complete;
43789
+ }
43790
+ markComplete() {
43791
+ this.finalizeContentSha256();
43792
+ }
43793
+ assertResumable() {
43794
+ if (this.#unverifiable) {
43795
+ throw new RepositoryExportError("digest_mismatch", "Repository export session failed verification and cannot be resumed; " + "start a new session");
43796
+ }
43797
+ if (this.#complete) {
43798
+ throw new RepositoryExportError("header_invalid", "Repository export session is already complete; start a new session");
43799
+ }
43800
+ }
43801
+ adoptHeader(header) {
43802
+ this.assertResumable();
43803
+ const previous = this.#header;
43804
+ if (previous !== undefined && (previous.repo !== header.repo || previous.mode !== header.mode || previous.sinceRepoSeq !== header.sinceRepoSeq || previous.atRepoSeq !== header.atRepoSeq)) {
43805
+ throw new RepositoryExportError("header_invalid", "Resumed repository export header does not match the opening header");
43806
+ }
43807
+ this.#header = header;
43808
+ }
43809
+ recordRow(durableId, lineBytes) {
43810
+ if (this.#header?.mode === "heads" && this.#lastDurableId !== undefined && compareUnsignedUtf8(this.#lastDurableId, durableId) >= 0) {
43811
+ throw new RepositoryExportError("row_out_of_order", `Repository export row '${durableId}' does not follow '${this.#lastDurableId}'`);
43812
+ }
43813
+ this.#streamDigest.update(lineBytes);
43814
+ this.#segmentDigest.update(lineBytes);
43815
+ this.#segmentRowCount += 1;
43816
+ this.#lastDurableId = durableId;
43817
+ }
43818
+ }
43819
+ function createRepositoryExportSession() {
43820
+ return new RepositoryExportSession;
43821
+ }
43822
+
43823
+ // ../../packages/sdk-ts/src/repository-export/stream.ts
43824
+ var LF = 10;
43825
+ var utf8 = new TextDecoder;
43826
+ function resumedHeader(session) {
43827
+ const header = session.header;
43828
+ if (!header) {
43829
+ throw new RepositoryExportError("header_invalid", "Repository export resumed without an opening header to inherit");
43830
+ }
43831
+ return header;
43832
+ }
43833
+ async function readHeader(lines, session, expected) {
43834
+ const first = await lines.next();
43835
+ if (first.done)
43836
+ throw new RepositoryExportError("truncated");
43837
+ let header;
43838
+ try {
43839
+ header = parseRepositoryExportHeaderLine(first.value);
43840
+ } catch (error51) {
43841
+ rethrowAs("header_invalid", error51);
43842
+ }
43843
+ if (header.formatVersion !== REPOSITORY_EXPORT_FORMAT_VERSION || expected !== undefined && (header.repo !== expected.repo || header.mode !== expected.mode || expected.sinceRepoSeq !== undefined && header.sinceRepoSeq !== expected.sinceRepoSeq || expected.atRepoSeq !== undefined && header.atRepoSeq !== expected.atRepoSeq)) {
43844
+ throw new RepositoryExportError("header_invalid", expected === undefined ? `Repository export header declares format version ${header.formatVersion}; expected ${REPOSITORY_EXPORT_FORMAT_VERSION}` : `Repository export header describes ${header.repo} (${header.mode}, ` + `${header.sinceRepoSeq}..${header.atRepoSeq}); expected ${expected.repo} ` + `(${expected.mode}${expected.sinceRepoSeq !== undefined ? `, since ${expected.sinceRepoSeq}` : ""}` + `${expected.atRepoSeq !== undefined ? `, at ${expected.atRepoSeq}` : ""})`);
43845
+ }
43846
+ session.adoptHeader(header);
43847
+ return header;
43848
+ }
43849
+ async function* readLines(source, tail) {
43850
+ let buffer = new Uint8Array(0);
43851
+ for await (const chunk of toAsyncIterable(source)) {
43852
+ const merged = new Uint8Array(buffer.length + chunk.length);
43853
+ merged.set(buffer);
43854
+ merged.set(chunk, buffer.length);
43855
+ buffer = merged;
43856
+ let index = buffer.indexOf(LF);
43857
+ while (index !== -1) {
43858
+ yield buffer.subarray(0, index + 1);
43859
+ buffer = buffer.subarray(index + 1);
43860
+ index = buffer.indexOf(LF);
43861
+ }
43862
+ }
43863
+ tail.unterminated = buffer.length > 0;
43864
+ }
43865
+ function toAsyncIterable(source) {
43866
+ if (Symbol.asyncIterator in source)
43867
+ return source;
43868
+ return {
43869
+ async* [Symbol.asyncIterator]() {
43870
+ const reader = source.getReader();
43407
43871
  try {
43408
- const result = await getTrpc().repo.checkpoint.retry.mutate({
43409
- orgName,
43410
- repoName,
43411
- checkpointId
43412
- });
43413
- return normalizeRepositoryCheckpointStatus(result.checkpoint);
43414
- } catch (error51) {
43415
- throw toWarmHubError(error51);
43872
+ while (true) {
43873
+ const { done, value } = await reader.read();
43874
+ if (done)
43875
+ return;
43876
+ if (value)
43877
+ yield value;
43878
+ }
43879
+ } finally {
43880
+ reader.releaseLock();
43416
43881
  }
43417
43882
  }
43418
43883
  };
43419
43884
  }
43885
+ function lineKind(bytes) {
43886
+ try {
43887
+ const value = JSON.parse(utf8.decode(bytes));
43888
+ if (value !== null && typeof value === "object" && "kind" in value) {
43889
+ const kind = value.kind;
43890
+ if (typeof kind === "string")
43891
+ return kind;
43892
+ }
43893
+ } catch {}
43894
+ return "";
43895
+ }
43896
+ function rethrowAs(reason, error51) {
43897
+ if (error51 instanceof RepositoryExportError)
43898
+ throw error51;
43899
+ throw new RepositoryExportError(reason, error51 instanceof Error ? error51.message : undefined);
43900
+ }
43901
+ async function* readRepositoryExportStream(source, session, expected, options = {}) {
43902
+ yield* readSegment(source, session, expected, options);
43903
+ }
43904
+ async function restoreRepositoryExportSession(source, options = {}) {
43905
+ const session = createRepositoryExportSession();
43906
+ const replay = readSegment(source, session, undefined, options);
43907
+ let next = await replay.next();
43908
+ while (!next.done)
43909
+ next = await replay.next();
43910
+ return session;
43911
+ }
43912
+ async function* readSegment(source, session, expected, options) {
43913
+ const tail = { unterminated: false };
43914
+ const lines = readLines(source, tail);
43915
+ try {
43916
+ yield* readVerified(lines, tail, session, expected, options);
43917
+ } finally {
43918
+ await lines.return(undefined);
43919
+ }
43920
+ }
43921
+ async function* readVerified(lines, tail, session, expected, options) {
43922
+ session.assertResumable();
43923
+ const header = options.resumed === true ? resumedHeader(session) : await readHeader(lines, session, expected);
43924
+ const tombstonesAllowed = repositoryExportAllowsTombstones(header);
43925
+ session.beginSegment();
43926
+ while (true) {
43927
+ const next = await lines.next();
43928
+ if (next.done) {
43929
+ if (options.partial === true)
43930
+ return;
43931
+ throw new RepositoryExportError("truncated");
43932
+ }
43933
+ const bytes = next.value;
43934
+ if (lineKind(bytes) !== "trailer") {
43935
+ let row;
43936
+ try {
43937
+ row = parseRepositoryExportRowLine(bytes);
43938
+ } catch (error51) {
43939
+ rethrowAs("row_invalid", error51);
43940
+ }
43941
+ if (!row.active && !tombstonesAllowed) {
43942
+ throw new RepositoryExportError("row_invalid", "Repository export tombstone is not legal in a full export");
43943
+ }
43944
+ session.recordRow(row.durableId, bytes);
43945
+ yield row;
43946
+ continue;
43947
+ }
43948
+ let trailer;
43949
+ try {
43950
+ trailer = parseRepositoryExportTrailerLine(bytes);
43951
+ if (trailer.atRepoSeq !== header.atRepoSeq) {
43952
+ throw new RepositoryExportError("fence_mismatch");
43953
+ }
43954
+ if (trailer.recordCount !== session.segmentRowCount) {
43955
+ throw new RepositoryExportError("count_mismatch");
43956
+ }
43957
+ if (trailer.contentSha256 !== session.finalizeSegment()) {
43958
+ throw new RepositoryExportError("digest_mismatch");
43959
+ }
43960
+ } catch (error51) {
43961
+ session.markUnverifiable();
43962
+ if (error51 instanceof RepositoryExportError)
43963
+ throw error51;
43964
+ rethrowAs("trailer_invalid", error51);
43965
+ }
43966
+ if (!(await lines.next()).done || tail.unterminated) {
43967
+ throw new RepositoryExportError("trailer_invalid", "Repository export stream continues past its trailer");
43968
+ }
43969
+ session.markComplete();
43970
+ return;
43971
+ }
43972
+ }
43420
43973
 
43974
+ // ../../packages/sdk-ts/src/repository-export/client.ts
43975
+ var EPOCH_FLOOR_CODE = "since-below-epoch-floor";
43976
+ var DEFAULT_POLL_INTERVAL_MS = 1000;
43977
+ var MIN_POLL_INTERVAL_MS = 50;
43978
+ var MAX_DOWNLOAD_ATTEMPTS = 3;
43979
+ function buildPath(orgName, repoName, query) {
43980
+ const params = new URLSearchParams;
43981
+ for (const [key, value] of Object.entries(query)) {
43982
+ if (value !== undefined)
43983
+ params.set(key, String(value));
43984
+ }
43985
+ const search = params.toString();
43986
+ return `/api/repos/${encodeURIComponent(orgName)}/${encodeURIComponent(repoName)}/export${search ? `?${search}` : ""}`;
43987
+ }
43988
+ function abortReason(signal) {
43989
+ const reason = signal?.reason;
43990
+ return reason instanceof Error ? reason : new Error("Repository export was aborted");
43991
+ }
43992
+ function pollIntervalMs(requested) {
43993
+ if (requested === undefined || !Number.isFinite(requested)) {
43994
+ return DEFAULT_POLL_INTERVAL_MS;
43995
+ }
43996
+ return Math.max(requested, MIN_POLL_INTERVAL_MS);
43997
+ }
43998
+ async function delay(ms, signal) {
43999
+ if (signal?.aborted)
44000
+ throw abortReason(signal);
44001
+ await new Promise((resolve, reject) => {
44002
+ const onAbort = () => {
44003
+ clearTimeout(timer);
44004
+ reject(abortReason(signal));
44005
+ };
44006
+ const timer = setTimeout(() => {
44007
+ signal?.removeEventListener("abort", onAbort);
44008
+ resolve();
44009
+ }, ms);
44010
+ signal?.addEventListener("abort", onAbort, { once: true });
44011
+ });
44012
+ }
44013
+ async function exportHttpError(response, httpError) {
44014
+ let body;
44015
+ try {
44016
+ body = await response.clone().json();
44017
+ } catch {}
44018
+ if ((body?.code ?? body?.error?.code) === EPOCH_FLOOR_CODE) {
44019
+ return new RepositoryExportError("since_below_epoch_floor", body?.message);
44020
+ }
44021
+ if (body?.code !== undefined && body.error === undefined) {
44022
+ return await httpError(new Response(JSON.stringify({ error: body }), {
44023
+ status: response.status,
44024
+ headers: { "content-type": "application/json" }
44025
+ }));
44026
+ }
44027
+ return await httpError(response);
44028
+ }
44029
+ function isDownloadEnvelope(value) {
44030
+ const envelope = value;
44031
+ return typeof envelope?.url === "string" && envelope.url !== "" && typeof envelope.expiresAt === "number" && typeof envelope.atRepoSeq === "number" && typeof envelope.recordCount === "number" && typeof envelope.contentSha256 === "string";
44032
+ }
44033
+ async function readDownloadEnvelope(response) {
44034
+ let body;
44035
+ try {
44036
+ body = await response.json();
44037
+ } catch {
44038
+ throw new RepositoryExportError("header_invalid", "Repository export redemption did not return a JSON download envelope");
44039
+ }
44040
+ if (!isDownloadEnvelope(body)) {
44041
+ throw new RepositoryExportError("header_invalid", "Repository export download envelope must carry url, expiresAt, atRepoSeq, recordCount, and contentSha256");
44042
+ }
44043
+ return body;
44044
+ }
44045
+ function assertAttested(session, envelope) {
44046
+ const fence = session.header?.atRepoSeq;
44047
+ if (fence !== envelope.atRepoSeq) {
44048
+ throw new RepositoryExportError("fence_mismatch", `Repository export download is pinned to ${fence}; the redemption named ${envelope.atRepoSeq}`);
44049
+ }
44050
+ if (session.rowCount !== envelope.recordCount) {
44051
+ throw new RepositoryExportError("count_mismatch", `Repository export download carried ${session.rowCount} rows; the redemption named ${envelope.recordCount}`);
44052
+ }
44053
+ if (session.contentSha256 !== envelope.contentSha256) {
44054
+ throw new RepositoryExportError("digest_mismatch", "Repository export download digest does not match the digest the redemption named");
44055
+ }
44056
+ }
44057
+ function createRepositoryExportClient(transport, httpError, download = (url2, init) => globalThis.fetch(url2, init)) {
44058
+ const request = async (path, signal) => {
44059
+ const response = await transport(path, {
44060
+ method: "GET",
44061
+ headers: { accept: REPOSITORY_EXPORT_MEDIA_TYPE },
44062
+ ...signal ? { signal } : {}
44063
+ });
44064
+ if (!response.ok && response.status !== 202) {
44065
+ throw await exportHttpError(response, httpError);
44066
+ }
44067
+ return response;
44068
+ };
44069
+ const prepare = async (orgName, repoName, options = {}) => {
44070
+ const response = await request(buildPath(orgName, repoName, {
44071
+ mode: options.mode ?? "heads",
44072
+ sinceRepoSeq: options.sinceRepoSeq,
44073
+ atRepoSeq: options.atRepoSeq,
44074
+ prefer: "async"
44075
+ }), options.signal);
44076
+ const accepted = await response.json();
44077
+ if (typeof accepted.exportToken !== "string" || typeof accepted.atRepoSeq !== "number") {
44078
+ throw new RepositoryExportError("header_invalid", "Repository export async request did not return an exportToken and atRepoSeq");
44079
+ }
44080
+ return { exportToken: accepted.exportToken, atRepoSeq: accepted.atRepoSeq };
44081
+ };
44082
+ const stream = (orgName, repoName, options = {}) => {
44083
+ const cursor = options.session?.lastDurableId ?? options.afterDurableId;
44084
+ if (cursor !== undefined && (options.token !== undefined || options.session?.token !== undefined || options.prefer === "async")) {
44085
+ throw new RepositoryExportError("header_invalid", `Repository export token download cannot continue from '${cursor}': redemption returns the whole prepared object. ` + "Start a new session and redeem the token again.");
44086
+ }
44087
+ if (options.afterDurableId !== undefined && options.session?.header === undefined) {
44088
+ throw new RepositoryExportError("header_invalid", "Repository export afterDurableId needs a session carrying the opening header; " + "reuse the session the broken stream wrote, or rebuild one with restoreRepositoryExportSession");
44089
+ }
44090
+ return streamExport(orgName, repoName, options);
44091
+ };
44092
+ return { prepare, stream };
44093
+ async function* streamExport(orgName, repoName, options) {
44094
+ const session = options.session ?? createRepositoryExportSession();
44095
+ const resumed = session.header;
44096
+ const signal = options.signal;
44097
+ const query = {
44098
+ mode: resumed?.mode ?? options.mode ?? "heads",
44099
+ sinceRepoSeq: resumed?.sinceRepoSeq ?? options.sinceRepoSeq,
44100
+ atRepoSeq: resumed?.atRepoSeq ?? options.atRepoSeq,
44101
+ afterDurableId: session.lastDurableId ?? options.afterDurableId
44102
+ };
44103
+ const expected = {
44104
+ repo: `${orgName}/${repoName}`,
44105
+ mode: query.mode,
44106
+ ...options.sinceRepoSeq === undefined ? {} : { sinceRepoSeq: options.sinceRepoSeq },
44107
+ ...options.atRepoSeq === undefined ? {} : { atRepoSeq: options.atRepoSeq }
44108
+ };
44109
+ if (options.token !== undefined && session.token !== undefined && options.token !== session.token) {
44110
+ throw new RepositoryExportError("header_invalid", `Repository export session was redeeming token ${session.token}; ` + `resuming it with token ${options.token} would splice two exports`);
44111
+ }
44112
+ const token = options.token ?? session.token;
44113
+ if (token !== undefined) {
44114
+ session.token = token;
44115
+ yield* downloadPrepared(token);
44116
+ return;
44117
+ }
44118
+ if (options.prefer === "async") {
44119
+ const prepared = await prepare(orgName, repoName, {
44120
+ mode: query.mode,
44121
+ ...query.sinceRepoSeq === undefined ? {} : { sinceRepoSeq: query.sinceRepoSeq },
44122
+ ...query.atRepoSeq === undefined ? {} : { atRepoSeq: query.atRepoSeq },
44123
+ ...signal ? { signal } : {}
44124
+ });
44125
+ session.token = prepared.exportToken;
44126
+ yield* downloadPrepared(prepared.exportToken);
44127
+ return;
44128
+ }
44129
+ const response = await request(buildPath(orgName, repoName, query), signal);
44130
+ if (!response.body)
44131
+ throw new RepositoryExportError("truncated");
44132
+ yield* readRepositoryExportStream(response.body, session, expected, {
44133
+ resumed: query.afterDurableId !== undefined
44134
+ });
44135
+ async function* downloadPrepared(exportToken) {
44136
+ for (let attempt = 1;; attempt += 1) {
44137
+ const envelope = await redeem(exportToken);
44138
+ try {
44139
+ yield* readObject(envelope);
44140
+ return;
44141
+ } catch (error51) {
44142
+ const transportFault = !(error51 instanceof RepositoryExportError) || error51.reason === "truncated";
44143
+ if (!transportFault || session.rowCount > 0 || attempt >= MAX_DOWNLOAD_ATTEMPTS || signal?.aborted === true) {
44144
+ throw error51;
44145
+ }
44146
+ }
44147
+ }
44148
+ }
44149
+ async function* readObject(envelope) {
44150
+ const object2 = await download(envelope.url, signal ? { signal } : {});
44151
+ if (!object2.ok || !object2.body) {
44152
+ await object2.body?.cancel();
44153
+ throw new RepositoryExportError("truncated", `Repository export download returned HTTP ${object2.status}`);
44154
+ }
44155
+ yield* readRepositoryExportStream(object2.body, session, expected, {
44156
+ resumed: false
44157
+ });
44158
+ assertAttested(session, envelope);
44159
+ }
44160
+ async function redeem(exportToken) {
44161
+ const path = buildPath(orgName, repoName, { token: exportToken });
44162
+ while (true) {
44163
+ const pending = await request(path, signal);
44164
+ if (pending.status !== 202)
44165
+ return await readDownloadEnvelope(pending);
44166
+ await delay(pollIntervalMs(options.pollIntervalMs), signal);
44167
+ }
44168
+ }
44169
+ }
44170
+ }
43421
44171
  // ../../packages/sdk-ts/src/shape-preflight.ts
43422
44172
  function shapeDefinitionPreflightError(name, data, verb) {
43423
44173
  const result = validateShapeDefinition(data, verb === "revise" ? { allowUnsafeFieldNamePaths: collectUnsafeShapeFieldNamePaths(data) } : undefined);
@@ -44496,7 +45246,7 @@ function createStreamingSubmissionHandle(input, deps) {
44496
45246
  // ../../packages/sdk-ts/package.json
44497
45247
  var package_default = {
44498
45248
  name: "@warmhub/sdk-ts",
44499
- version: "0.107.0",
45249
+ version: "0.109.0",
44500
45250
  private: false,
44501
45251
  type: "module",
44502
45252
  description: "The TypeScript SDK for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -44534,6 +45284,7 @@ var package_default = {
44534
45284
  sideEffects: false,
44535
45285
  files: [
44536
45286
  "dist",
45287
+ "CHANGELOG.md",
44537
45288
  "README.md"
44538
45289
  ],
44539
45290
  publishConfig: {
@@ -44600,6 +45351,7 @@ var package_default = {
44600
45351
  "@vitest/coverage-v8": "catalog:",
44601
45352
  "@warmhub/backend": "workspace:*",
44602
45353
  "@warmhub/rules": "workspace:*",
45354
+ pako: "2.1.0",
44603
45355
  "@types/react": "catalog:",
44604
45356
  react: "19.2.6",
44605
45357
  tsup: "8.5.1",
@@ -45059,6 +45811,7 @@ class WarmHubClient {
45059
45811
  getToken;
45060
45812
  compatibilityCheck;
45061
45813
  overrideNoticePrinted = false;
45814
+ repositoryExport = createRepositoryExportClient((path, init) => this.fetchWithAuth(`${this.apiUrl.replace(/\/$/, "")}${path}`, init), (response) => this.httpResponseError(response), (url2, init) => (this.fetchImpl ?? globalThis.fetch)(url2, init));
45062
45815
  noteCompatibilityOverride() {
45063
45816
  if (this.overrideNoticePrinted)
45064
45817
  return;
@@ -45577,6 +46330,8 @@ class WarmHubClient {
45577
46330
  };
45578
46331
  repo = {
45579
46332
  checkpoint: createRepositoryCheckpointClient(() => this.trpc, toWarmHubError),
46333
+ export: (orgName, repoName, options) => this.repositoryExport.stream(orgName, repoName, options),
46334
+ exportPrepare: (orgName, repoName, options) => this.repositoryExport.prepare(orgName, repoName, options),
45580
46335
  get: async (orgName, repoName) => {
45581
46336
  try {
45582
46337
  return await this.trpc.repo.get.query({
@@ -49363,7 +50118,7 @@ function corruptedAuthError(path, cause) {
49363
50118
  function isAuthLockError(error51, authPath) {
49364
50119
  return error51 instanceof Error && error51.code === "ELOCKED" && (error51.file === undefined || error51.file === authPath);
49365
50120
  }
49366
- function delay(ms) {
50121
+ function delay2(ms) {
49367
50122
  return new Promise((resolve) => setTimeout(resolve, ms));
49368
50123
  }
49369
50124
  function getTokenInfo(profile) {
@@ -49485,7 +50240,7 @@ async function getValidToken(profile) {
49485
50240
  duration_ms: Date.now() - refreshStarted,
49486
50241
  error_name: err instanceof Error ? err.name : "Unknown"
49487
50242
  });
49488
- await delay(1000);
50243
+ await delay2(1000);
49489
50244
  log.info("auth.refresh.retry", { profile: profileName, attempt: 2 });
49490
50245
  let retryStarted = Date.now();
49491
50246
  try {
@@ -49821,6 +50576,9 @@ function shouldGuardDomain(domainPath, canonicalVerb, args) {
49821
50576
  if (domainPath[0] === "repo" && domainPath[1] === "checkpoint" && canonicalVerb === "verify") {
49822
50577
  return false;
49823
50578
  }
50579
+ if (domainPath[0] === "repo" && canonicalVerb === "verify") {
50580
+ return false;
50581
+ }
49824
50582
  return true;
49825
50583
  }
49826
50584
  async function probeCapabilities(ctx) {
@@ -56640,7 +57398,7 @@ var NUL = String.fromCharCode(0);
56640
57398
  function findInvalidControlByte(data, rootLabel = "data") {
56641
57399
  const segs = [];
56642
57400
  const pos = visit(data, segs);
56643
- return pos === -1 ? null : { path: buildPath(rootLabel, segs), position: pos };
57401
+ return pos === -1 ? null : { path: buildPath2(rootLabel, segs), position: pos };
56644
57402
  }
56645
57403
  function visit(value, segs) {
56646
57404
  if (typeof value === "string")
@@ -56671,7 +57429,7 @@ function visit(value, segs) {
56671
57429
  }
56672
57430
  return -1;
56673
57431
  }
56674
- function buildPath(root, segs) {
57432
+ function buildPath2(root, segs) {
56675
57433
  let out = root;
56676
57434
  for (const s of segs)
56677
57435
  out += typeof s === "number" ? `[${s}]` : `.${s}`;
@@ -62192,7 +62950,7 @@ class StreamingByteReader {
62192
62950
  #loadedBytes = 0;
62193
62951
  position = 0;
62194
62952
  constructor(source) {
62195
- this.#iterator = toAsyncIterable(source)[Symbol.asyncIterator]();
62953
+ this.#iterator = toAsyncIterable2(source)[Symbol.asyncIterator]();
62196
62954
  }
62197
62955
  async peekU32() {
62198
62956
  const bytes = await this.readExact(4);
@@ -62279,7 +63037,7 @@ class StreamingByteReader {
62279
63037
  }
62280
63038
  }
62281
63039
  }
62282
- function toAsyncIterable(source) {
63040
+ function toAsyncIterable2(source) {
62283
63041
  if (Symbol.asyncIterator in source)
62284
63042
  return source;
62285
63043
  return {
@@ -63018,12 +63776,6 @@ var checkpointFlags = {
63018
63776
  "repo-seq": flag.number({
63019
63777
  description: "Repository sequence for the checkpoint"
63020
63778
  }),
63021
- "at-least-repo-seq": flag.number({
63022
- description: "Generate at or after this repository sequence"
63023
- }),
63024
- wait: flag.boolean({
63025
- description: "Poll until the checkpoint completes or fails"
63026
- }),
63027
63779
  latest: flag.boolean({
63028
63780
  description: "Use the latest completed checkpoint"
63029
63781
  }),
@@ -63042,19 +63794,10 @@ var CHECKPOINT_ID_EXAMPLE = "0198f6d5-78aa-7000-8000-000000000001";
63042
63794
  var CHECKPOINT_ACCESS_EXAMPLE = "wh repo checkpoint access acme/widgets --latest --archive";
63043
63795
  var CHECKPOINT_DOWNLOAD_EXAMPLE = "wh repo checkpoint download acme/widgets --latest --archive --output checkpoint.zip";
63044
63796
  var CHECKPOINT_READ_NOTE = "Requires unrestricted repo:read plus repo:checkpoint-read.";
63045
- var CHECKPOINT_MANAGEMENT_NOTE = "Requires unrestricted repo:read, repo:checkpoint-read, and repo:checkpoint-generate (or repo:admin for compatibility).";
63046
- var generateFlags = {
63047
- "at-least-repo-seq": checkpointFlags["at-least-repo-seq"],
63048
- wait: checkpointFlags.wait
63049
- };
63050
63797
  var statusFlags = {
63051
63798
  checkpoint: checkpointFlags.checkpoint,
63052
63799
  "repo-seq": checkpointFlags["repo-seq"]
63053
63800
  };
63054
- var retryFlags = {
63055
- checkpoint: checkpointFlags.checkpoint,
63056
- wait: checkpointFlags.wait
63057
- };
63058
63801
  var accessFlags = {
63059
63802
  latest: checkpointFlags.latest,
63060
63803
  checkpoint: checkpointFlags.checkpoint,
@@ -63070,17 +63813,17 @@ var downloadFlags = {
63070
63813
  function repoFor(ctx, args) {
63071
63814
  return parseOrgRepo(getRepoRef(ctx) ?? args[0], ctx.config);
63072
63815
  }
63073
- function requireSequence(value, flagName) {
63816
+ function requireSequence(value) {
63074
63817
  if (value === undefined)
63075
63818
  return;
63076
63819
  if (!Number.isSafeInteger(value) || value < 0) {
63077
- throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagName} must be a non-negative safe integer`);
63820
+ throw new CliError(2 /* UserInput */, "USER_INPUT", "--repo-seq must be a non-negative safe integer");
63078
63821
  }
63079
63822
  return value;
63080
63823
  }
63081
63824
  function selectCheckpoint(flags) {
63082
63825
  const checkpointId = flags.checkpoint;
63083
- const repoSeq = requireSequence(flags["repo-seq"], "--repo-seq");
63826
+ const repoSeq = requireSequence(flags["repo-seq"]);
63084
63827
  if (checkpointId === undefined === (repoSeq === undefined)) {
63085
63828
  usageError("Provide exactly one of --checkpoint or --repo-seq.", `wh repo checkpoint status acme/widgets --checkpoint ${CHECKPOINT_ID_EXAMPLE}`);
63086
63829
  }
@@ -63144,43 +63887,6 @@ function printCheckpoint(ctx, result) {
63144
63887
  ctx.out(`Failure: ${result.failureCode}`);
63145
63888
  });
63146
63889
  }
63147
- async function waitForCompletion(ctx, org, repo2, initial) {
63148
- let result = initial;
63149
- let delayMs = 200;
63150
- while (result.state === "queued" || result.state === "running") {
63151
- ctx.status(`Checkpoint ${result.checkpointId} is ${result.state}; waiting…`);
63152
- await delay2(delayMs, ctx.signal);
63153
- result = await checkpointClient(ctx).status(org, repo2, {
63154
- checkpointId: result.checkpointId
63155
- });
63156
- delayMs = Math.min(delayMs * 2, 5000);
63157
- }
63158
- return result;
63159
- }
63160
- function delay2(ms, signal) {
63161
- return new Promise((resolve4, reject) => {
63162
- if (signal?.aborted) {
63163
- reject(new Error("CLI invocation cancelled"));
63164
- return;
63165
- }
63166
- const onAbort = () => {
63167
- clearTimeout(timer);
63168
- reject(new Error("CLI invocation cancelled"));
63169
- };
63170
- const timer = setTimeout(() => {
63171
- signal?.removeEventListener("abort", onAbort);
63172
- resolve4();
63173
- }, ms);
63174
- signal?.addEventListener("abort", onAbort, { once: true });
63175
- });
63176
- }
63177
- var handleGenerate = async (ctx, { args, flags }) => {
63178
- const { org, repo: repo2 } = repoFor(ctx, args);
63179
- const result = await checkpointClient(ctx).generate(org, repo2, {
63180
- atLeastRepoSeq: requireSequence(flags["at-least-repo-seq"], "--at-least-repo-seq")
63181
- });
63182
- printCheckpoint(ctx, flags.wait ? await waitForCompletion(ctx, org, repo2, result) : result);
63183
- };
63184
63890
  var handleStatus2 = async (ctx, { args, flags }) => {
63185
63891
  const { org, repo: repo2 } = repoFor(ctx, args);
63186
63892
  printCheckpoint(ctx, await checkpointClient(ctx).status(org, repo2, selectCheckpoint(flags)));
@@ -63189,14 +63895,6 @@ var handleLatest = async (ctx, { args }) => {
63189
63895
  const { org, repo: repo2 } = repoFor(ctx, args);
63190
63896
  printCheckpoint(ctx, await checkpointClient(ctx).latest(org, repo2));
63191
63897
  };
63192
- var handleRetry = async (ctx, { args, flags }) => {
63193
- if (!flags.checkpoint) {
63194
- usageError("--checkpoint is required for retry.", `wh repo checkpoint retry acme/widgets --checkpoint ${CHECKPOINT_ID_EXAMPLE}`);
63195
- }
63196
- const { org, repo: repo2 } = repoFor(ctx, args);
63197
- const result = await checkpointClient(ctx).retry(org, repo2, flags.checkpoint);
63198
- printCheckpoint(ctx, flags.wait ? await waitForCompletion(ctx, org, repo2, result) : result);
63199
- };
63200
63898
  var handleDownload = async (ctx, { args, flags }) => {
63201
63899
  if (!flags.output) {
63202
63900
  usageError("--output PATH|- is required for download.", CHECKPOINT_DOWNLOAD_EXAMPLE);
@@ -63253,16 +63951,8 @@ var handleVerify = async (ctx, { args }) => {
63253
63951
  };
63254
63952
  var CHECKPOINT_SUBDOMAIN = defineDomain({
63255
63953
  name: "checkpoint",
63256
- summary: "Generate, access, download, and verify repository checkpoints",
63954
+ summary: "Access, download, and verify stored repository checkpoints",
63257
63955
  verbs: {
63258
- generate: {
63259
- summary: "Generate a repository checkpoint",
63260
- args: "[org/repo]",
63261
- flags: generateFlags,
63262
- notes: [CHECKPOINT_MANAGEMENT_NOTE],
63263
- examples: ["wh repo checkpoint generate acme/widgets --wait"],
63264
- handler: handleGenerate
63265
- },
63266
63956
  status: {
63267
63957
  summary: "Show one checkpoint status",
63268
63958
  args: "[org/repo]",
@@ -63283,16 +63973,6 @@ var CHECKPOINT_SUBDOMAIN = defineDomain({
63283
63973
  examples: ["wh repo checkpoint latest acme/widgets"],
63284
63974
  handler: handleLatest
63285
63975
  },
63286
- retry: {
63287
- summary: "Retry a failed checkpoint",
63288
- args: "[org/repo]",
63289
- flags: retryFlags,
63290
- notes: [CHECKPOINT_MANAGEMENT_NOTE, "Requires --checkpoint."],
63291
- examples: [
63292
- `wh repo checkpoint retry acme/widgets --checkpoint ${CHECKPOINT_ID_EXAMPLE} --wait`
63293
- ],
63294
- handler: handleRetry
63295
- },
63296
63976
  access: {
63297
63977
  summary: "Show a short-lived checkpoint artifact URL",
63298
63978
  args: "[org/repo]",
@@ -63684,6 +64364,346 @@ var handleCreate6 = async (ctx, { flags, args }) => {
63684
64364
  });
63685
64365
  };
63686
64366
 
64367
+ // ../../packages/warmhub-cli/src/domains/repo/export-file.ts
64368
+ import { createReadStream as createReadStream7 } from "node:fs";
64369
+ import { open as open5, truncate } from "node:fs/promises";
64370
+ var LF2 = 10;
64371
+ async function scanRepositoryExportFile(path2, options = {}) {
64372
+ const counter = { completeBytes: 0 };
64373
+ const session = await restoreRepositoryExportSession(countedChunks(path2, counter), options);
64374
+ return { session, completeBytes: counter.completeBytes };
64375
+ }
64376
+ async function openExportSink(ctx, output, resumeFrom) {
64377
+ if (output === "-") {
64378
+ const writeBinary = ctx.writeBinary;
64379
+ if (!writeBinary) {
64380
+ throw new CliError(1 /* Runtime */, "UNKNOWN", "Binary stdout is unavailable for this command context.");
64381
+ }
64382
+ return {
64383
+ write: async (bytes) => {
64384
+ if (await writeBinary(bytes))
64385
+ return;
64386
+ throw new CliError(1 /* Runtime */, "UNKNOWN", "Export output closed before the stream finished.");
64387
+ },
64388
+ close: async () => {
64389
+ return;
64390
+ }
64391
+ };
64392
+ }
64393
+ if (resumeFrom !== undefined)
64394
+ await truncate(output, resumeFrom);
64395
+ const handle = await openOutput(output, resumeFrom === undefined);
64396
+ return {
64397
+ write: (bytes) => writeAll(handle, bytes),
64398
+ close: async () => {
64399
+ await handle.sync();
64400
+ await handle.close();
64401
+ }
64402
+ };
64403
+ }
64404
+ async function openOutput(output, fresh) {
64405
+ try {
64406
+ return await open5(output, fresh ? "wx" : "a", 384);
64407
+ } catch (error51) {
64408
+ if (error51.code === "EEXIST") {
64409
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Refusing to overwrite existing output path '${output}'.`, error51, "Delete it, choose another --output, or pass --resume to continue an interrupted export.");
64410
+ }
64411
+ throw error51;
64412
+ }
64413
+ }
64414
+ async function* countedChunks(path2, counter) {
64415
+ let read = 0;
64416
+ for await (const chunk of createReadStream7(path2)) {
64417
+ const bytes = chunk;
64418
+ const lastLf = bytes.lastIndexOf(LF2);
64419
+ if (lastLf !== -1)
64420
+ counter.completeBytes = read + lastLf + 1;
64421
+ read += bytes.byteLength;
64422
+ yield bytes;
64423
+ }
64424
+ }
64425
+
64426
+ // ../../packages/warmhub-cli/src/domains/repo/export.ts
64427
+ var exportFlags = {
64428
+ output: flag.string({
64429
+ description: "Write the export to PATH, or - for stdout",
64430
+ constraints: { nonEmpty: true }
64431
+ }),
64432
+ mode: flag.string({
64433
+ description: "Export mode: heads (default)",
64434
+ constraints: { choices: ["heads", "ops"] },
64435
+ conflictsWith: ["resume"]
64436
+ }),
64437
+ "since-repo-seq": flag.number({
64438
+ description: "Delta base: export only what changed after this sequence",
64439
+ conflictsWith: ["resume", "token"]
64440
+ }),
64441
+ "at-repo-seq": flag.number({
64442
+ description: "Pin the export to this repository sequence",
64443
+ conflictsWith: ["resume", "token"]
64444
+ }),
64445
+ async: flag.boolean({
64446
+ description: "Prepare the export server-side and print the token that redeems it",
64447
+ conflictsWith: ["resume", "token"]
64448
+ }),
64449
+ wait: flag.boolean({
64450
+ description: "Download the prepared export instead of printing its token",
64451
+ requires: [{ flag: "async", mustBeTrue: true }],
64452
+ conflictsWith: ["resume", "token"]
64453
+ }),
64454
+ token: flag.string({
64455
+ description: "Download the prepared export this token names",
64456
+ constraints: { nonEmpty: true },
64457
+ conflictsWith: ["async", "wait", "resume", "since-repo-seq", "at-repo-seq"]
64458
+ }),
64459
+ resume: flag.boolean({
64460
+ description: "Continue an interrupted export already at --output PATH",
64461
+ conflictsWith: [
64462
+ "async",
64463
+ "wait",
64464
+ "token",
64465
+ "mode",
64466
+ "since-repo-seq",
64467
+ "at-repo-seq"
64468
+ ]
64469
+ })
64470
+ };
64471
+ var POLL_INTERVAL_MS = 2000;
64472
+ var EXPORT_EXAMPLE = "wh repo export acme/widgets --output widgets.ndjson --format json";
64473
+ var ASYNC_EXAMPLE = "wh repo export acme/widgets --async";
64474
+ function requireSequence2(value, flagName) {
64475
+ if (value === undefined)
64476
+ return;
64477
+ if (!Number.isSafeInteger(value) || value < 0) {
64478
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagName} must be a non-negative safe integer`);
64479
+ }
64480
+ return value;
64481
+ }
64482
+ function printReceipt(ctx, header, session, contentSha256) {
64483
+ const result = {
64484
+ repo: header.repo,
64485
+ mode: header.mode,
64486
+ sinceRepoSeq: header.sinceRepoSeq,
64487
+ atRepoSeq: header.atRepoSeq,
64488
+ recordCount: session.rowCount,
64489
+ contentSha256
64490
+ };
64491
+ writeOutput(ctx, result, () => {
64492
+ ctx.out(`Repository: ${result.repo}`);
64493
+ ctx.out(`Mode: ${result.mode}`);
64494
+ if (result.sinceRepoSeq > 0)
64495
+ ctx.out(`Delta base: ${result.sinceRepoSeq}`);
64496
+ ctx.out(`Repository sequence: ${result.atRepoSeq}`);
64497
+ ctx.out(`Records: ${result.recordCount}`);
64498
+ ctx.out(`SHA-256: ${result.contentSha256}`);
64499
+ });
64500
+ }
64501
+ function exportFailure(error51, asked) {
64502
+ const asyncRefusal = asked.async && asked.mode !== "ops";
64503
+ if (error51 instanceof RepositoryExportError) {
64504
+ if (error51.reason === "since_below_epoch_floor") {
64505
+ throw new CliError(2 /* UserInput */, "USER_INPUT", "The delta base has expired; run a full export.", error51, "Re-run without --since-repo-seq.");
64506
+ }
64507
+ throw new CliError(4 /* Backend */, "BACKEND", error51.message, error51);
64508
+ }
64509
+ if (error51 instanceof WarmHubError) {
64510
+ if (error51.status === 429) {
64511
+ throw new CliError(4 /* Backend */, "RATE_LIMITED", "Another repository export is already streaming for this organization.", error51, "Retry with --async --wait to queue this export instead.");
64512
+ }
64513
+ if (error51.status === 501) {
64514
+ throw new CliError(4 /* Backend */, "BACKEND", asyncRefusal ? "Asynchronous repository export is not enabled on this deployment." : 'Export mode "ops" is not enabled on this deployment.', error51, asyncRefusal ? "Re-run without --async." : "Use --mode heads.");
64515
+ }
64516
+ if (error51.status === 500 && (asked.async || asked.token)) {
64517
+ throw new CliError(4 /* Backend */, "BACKEND", "The repository export job failed.", error51, asked.token ? "The token is spent; prepare a new export with --async." : "Re-run the command; it starts a new export job.");
64518
+ }
64519
+ }
64520
+ throw error51;
64521
+ }
64522
+ var handleExport = async (ctx, { args, flags }) => {
64523
+ const output = flags.output;
64524
+ if (flags.async && !flags.wait) {
64525
+ if (output) {
64526
+ usageError("--output is unused when --async only prints the token. Add --wait to download now, or redeem the token later with --token.", ASYNC_EXAMPLE);
64527
+ }
64528
+ return await prepareExport(ctx, args, flags);
64529
+ }
64530
+ if (!output) {
64531
+ usageError("--output PATH|- is required for export.", EXPORT_EXAMPLE);
64532
+ }
64533
+ if (output === "-" && ctx.format !== "pretty") {
64534
+ throw new CliError(2 /* UserInput */, "USER_INPUT", "Stdout output requires --format pretty; JSON and JSONL cannot carry export bytes.");
64535
+ }
64536
+ if (flags.resume && output === "-") {
64537
+ usageError("--resume needs a file; stdout cannot be continued.", EXPORT_EXAMPLE);
64538
+ }
64539
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx) ?? args[0], ctx.config);
64540
+ let session = createRepositoryExportSession();
64541
+ let resumeFrom;
64542
+ if (flags.resume) {
64543
+ const scan = await resumeScan(output);
64544
+ session = scan.session;
64545
+ const opened = requireHeader(session);
64546
+ if (opened.repo !== `${org}/${repo2}`) {
64547
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `'${output}' is an export of ${opened.repo}, not ${org}/${repo2}.`, undefined, `Resume it as ${opened.repo}, or choose another --output.`);
64548
+ }
64549
+ if (session.complete) {
64550
+ printReceipt(ctx, opened, session, session.finalizeContentSha256());
64551
+ return;
64552
+ }
64553
+ resumeFrom = scan.completeBytes;
64554
+ }
64555
+ const rows = ctx.client.repo.export(org, repo2, {
64556
+ mode: flags.mode,
64557
+ sinceRepoSeq: requireSequence2(flags["since-repo-seq"], "--since-repo-seq"),
64558
+ atRepoSeq: requireSequence2(flags["at-repo-seq"], "--at-repo-seq"),
64559
+ ...flags.async || flags.token ? {
64560
+ ...flags.token ? { token: flags.token } : { prefer: "async" },
64561
+ pollIntervalMs: POLL_INTERVAL_MS
64562
+ } : {},
64563
+ session,
64564
+ ...ctx.signal ? { signal: ctx.signal } : {}
64565
+ });
64566
+ if (flags.async || flags.token) {
64567
+ ctx.status("Waiting for the export to finish on the server…");
64568
+ }
64569
+ let sink;
64570
+ let headerWritten = resumeFrom !== undefined;
64571
+ const write = async (bytes) => {
64572
+ sink ??= await openExportSink(ctx, output, resumeFrom);
64573
+ await sink.write(bytes);
64574
+ };
64575
+ const writeHeader = async () => {
64576
+ if (headerWritten)
64577
+ return;
64578
+ headerWritten = true;
64579
+ await write(encodeRepositoryExportHeader(requireHeader(session)));
64580
+ };
64581
+ try {
64582
+ for await (const row of rows) {
64583
+ await writeHeader();
64584
+ await write(encodeRepositoryExportRow(row));
64585
+ }
64586
+ await writeHeader();
64587
+ const header = requireHeader(session);
64588
+ const contentSha256 = session.finalizeContentSha256();
64589
+ await write(encodeRepositoryExportTrailer({
64590
+ kind: "trailer",
64591
+ recordCount: session.rowCount,
64592
+ contentSha256,
64593
+ atRepoSeq: header.atRepoSeq
64594
+ }));
64595
+ await sink?.close();
64596
+ if (output === "-") {
64597
+ ctx.status(`Exported ${session.rowCount} records at ${header.atRepoSeq}`);
64598
+ return;
64599
+ }
64600
+ ctx.status(`Wrote repository export to ${output}`);
64601
+ printReceipt(ctx, header, session, contentSha256);
64602
+ } catch (error51) {
64603
+ try {
64604
+ await sink?.close();
64605
+ } catch (closeError) {
64606
+ ctx.status(`Could not flush the partial export: ${closeError instanceof Error ? closeError.message : "unknown error"}`);
64607
+ }
64608
+ exportFailure(error51, {
64609
+ async: flags.async === true,
64610
+ token: flags.token !== undefined,
64611
+ mode: flags.mode ?? "heads"
64612
+ });
64613
+ }
64614
+ };
64615
+ async function prepareExport(ctx, args, flags) {
64616
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx) ?? args[0], ctx.config);
64617
+ let prepared;
64618
+ try {
64619
+ prepared = await ctx.client.repo.exportPrepare(org, repo2, {
64620
+ mode: flags.mode,
64621
+ sinceRepoSeq: requireSequence2(flags["since-repo-seq"], "--since-repo-seq"),
64622
+ atRepoSeq: requireSequence2(flags["at-repo-seq"], "--at-repo-seq"),
64623
+ ...ctx.signal ? { signal: ctx.signal } : {}
64624
+ });
64625
+ } catch (error51) {
64626
+ exportFailure(error51, {
64627
+ async: true,
64628
+ token: false,
64629
+ mode: flags.mode ?? "heads"
64630
+ });
64631
+ }
64632
+ writeOutput(ctx, prepared, () => {
64633
+ ctx.out(`Export token: ${prepared.exportToken}`);
64634
+ ctx.out(`Repository sequence: ${prepared.atRepoSeq}`);
64635
+ });
64636
+ const modeFlag = (flags.mode ?? "heads") === "heads" ? "" : ` --mode ${flags.mode}`;
64637
+ ctx.status(`Download it with: wh repo export ${org}/${repo2} --token ${prepared.exportToken}${modeFlag} --output PATH`);
64638
+ }
64639
+ function requireHeader(session) {
64640
+ const header = session.header;
64641
+ if (!header) {
64642
+ throw new CliError(4 /* Backend */, "BACKEND", "Repository export ended without a header.");
64643
+ }
64644
+ return header;
64645
+ }
64646
+ async function resumeScan(output) {
64647
+ try {
64648
+ return await scanRepositoryExportFile(output, { partial: true });
64649
+ } catch (error51) {
64650
+ if (error51.code === "ENOENT") {
64651
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `No export to resume at '${output}'.`, error51, "Re-run without --resume to start a new export.");
64652
+ }
64653
+ throw error51;
64654
+ }
64655
+ }
64656
+ var handleVerify2 = async (ctx, { args }) => {
64657
+ const file2 = args[0];
64658
+ if (!file2) {
64659
+ usageError("Usage: wh repo verify <file>", "wh repo verify widgets.ndjson");
64660
+ }
64661
+ try {
64662
+ const { session } = await scanRepositoryExportFile(file2);
64663
+ printReceipt(ctx, requireHeader(session), session, session.finalizeContentSha256());
64664
+ } catch (error51) {
64665
+ if (error51 instanceof RepositoryExportError) {
64666
+ throw new CliError(4 /* Backend */, "BACKEND", error51.message, error51);
64667
+ }
64668
+ if (error51.code === "ENOENT") {
64669
+ throw new CliError(4 /* Backend */, "BACKEND", "Repository export file could not be read", error51);
64670
+ }
64671
+ throw error51;
64672
+ }
64673
+ };
64674
+ var EXPORT_VERB = {
64675
+ summary: "Export a repository as verified NDJSON (format v3)",
64676
+ args: "[org/repo]",
64677
+ flags: exportFlags,
64678
+ notes: [
64679
+ "Requires unrestricted repo:read plus repo:checkpoint-read.",
64680
+ "The stream is verified as it arrives: header, canonical rows, row order, record count, and content digest.",
64681
+ "One synchronous export streams per organization at a time; --async queues instead.",
64682
+ "A bare --async prints the export token and exits; --wait downloads it now, --token downloads it later.",
64683
+ "Redeeming a token answers with a short-lived download link for the prepared export, which the CLI then fetches and checks against the record count and digest the server named.",
64684
+ "An interrupted token download restarts from the beginning; re-run the same command, since redeeming a token again is free.",
64685
+ "An interrupted export resumes from the same file with --resume."
64686
+ ],
64687
+ examples: [
64688
+ EXPORT_EXAMPLE,
64689
+ "wh repo export acme/widgets --output delta.ndjson --since-repo-seq 120",
64690
+ ASYNC_EXAMPLE,
64691
+ "wh repo export acme/widgets --output widgets.ndjson --token TOKEN",
64692
+ "wh repo export acme/widgets --output widgets.ndjson --async --wait",
64693
+ "wh repo export acme/widgets --output widgets.ndjson --resume"
64694
+ ],
64695
+ handler: handleExport
64696
+ };
64697
+ var VERIFY_VERB = {
64698
+ summary: "Verify a saved repository export locally",
64699
+ args: "<file>",
64700
+ notes: [
64701
+ "Reads only the named local file: no profile, no authentication, no server."
64702
+ ],
64703
+ examples: ["wh repo verify widgets.ndjson"],
64704
+ handler: handleVerify2
64705
+ };
64706
+
63687
64707
  // ../../packages/warmhub-cli/src/domains/repo/lifecycle.ts
63688
64708
  var confirmFlags2 = {
63689
64709
  yes: flag.boolean({ short: "y", description: "Skip confirmation prompt" })
@@ -64189,6 +65209,8 @@ var REPO_DOMAIN = defineDomain({
64189
65209
  ],
64190
65210
  handler: handleUpdate3
64191
65211
  },
65212
+ export: EXPORT_VERB,
65213
+ verify: VERIFY_VERB,
64192
65214
  archive: {
64193
65215
  summary: "Archive a repo (blocks new commits)",
64194
65216
  args: "<org/repo>",
@@ -68187,6 +69209,9 @@ function isLocalOnlyInvocation(invocation) {
68187
69209
  if (invocation.commandPath[0] === "repo" && invocation.commandPath[1] === "checkpoint" && invocation.commandPath[2] === "verify") {
68188
69210
  return true;
68189
69211
  }
69212
+ if (invocation.commandPath[0] === "repo" && invocation.commandPath[1] === "verify") {
69213
+ return true;
69214
+ }
68190
69215
  return invocation.commandPath[0] === "help" && invocation.positionals[0] === "update";
68191
69216
  }
68192
69217
  function resolveLogLevel(flagLevel, env) {
@@ -68210,7 +69235,7 @@ function resolveLogLevel(flagLevel, env) {
68210
69235
  // package.json
68211
69236
  var package_default3 = {
68212
69237
  name: "@warmhub/cli",
68213
- version: "0.109.0",
69238
+ version: "0.111.0",
68214
69239
  private: false,
68215
69240
  type: "module",
68216
69241
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -68835,5 +69860,5 @@ process.exitCode = interceptedExitCode === undefined ? await runPreparedCli(laun
68835
69860
  version: package_default3.version
68836
69861
  }) : interceptedExitCode;
68837
69862
 
68838
- //# debugId=3345C65A6143D44164756E2164756E21
68839
- //# warmhub-cli-build-info {"cliVersion":"0.109.0","sdkVersion":"0.107.0"}
69863
+ //# debugId=E640C21D1D61CE1764756E2164756E21
69864
+ //# warmhub-cli-build-info {"cliVersion":"0.111.0","sdkVersion":"0.109.0"}