oasis_test_v2 2.2.119 → 2.2.120

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/index.js +355 -14
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -138818,7 +138818,7 @@ ${block}
138818
138818
  }
138819
138819
  return out;
138820
138820
  }
138821
- var DEFAULT_BATCH = {
138821
+ var DEFAULT_BATCH2 = {
138822
138822
  delayMs: 600,
138823
138823
  longThresholdChars: 1e3,
138824
138824
  longDelayMs: 2e3,
@@ -138837,11 +138837,11 @@ ${block}
138837
138837
  var _a2, _b, _c5, _d, _e5, _f, _g;
138838
138838
  const t = (_b = (_a2 = cfg === null || cfg === void 0 ? void 0 : cfg.batch) === null || _a2 === void 0 ? void 0 : _a2.text) !== null && _b !== void 0 ? _b : {};
138839
138839
  return {
138840
- delayMs: (_c5 = t.delayMs) !== null && _c5 !== void 0 ? _c5 : DEFAULT_BATCH.delayMs,
138841
- longThresholdChars: (_d = t.longThresholdChars) !== null && _d !== void 0 ? _d : DEFAULT_BATCH.longThresholdChars,
138842
- longDelayMs: (_e5 = t.longDelayMs) !== null && _e5 !== void 0 ? _e5 : DEFAULT_BATCH.longDelayMs,
138843
- maxMessages: (_f = t.maxMessages) !== null && _f !== void 0 ? _f : DEFAULT_BATCH.maxMessages,
138844
- maxChars: (_g = t.maxChars) !== null && _g !== void 0 ? _g : DEFAULT_BATCH.maxChars
138840
+ delayMs: (_c5 = t.delayMs) !== null && _c5 !== void 0 ? _c5 : DEFAULT_BATCH2.delayMs,
138841
+ longThresholdChars: (_d = t.longThresholdChars) !== null && _d !== void 0 ? _d : DEFAULT_BATCH2.longThresholdChars,
138842
+ longDelayMs: (_e5 = t.longDelayMs) !== null && _e5 !== void 0 ? _e5 : DEFAULT_BATCH2.longDelayMs,
138843
+ maxMessages: (_f = t.maxMessages) !== null && _f !== void 0 ? _f : DEFAULT_BATCH2.maxMessages,
138844
+ maxChars: (_g = t.maxChars) !== null && _g !== void 0 ? _g : DEFAULT_BATCH2.maxChars
138845
138845
  };
138846
138846
  }
138847
138847
  var SeenCache = class {
@@ -279920,7 +279920,7 @@ async function drainToBuffer(body2) {
279920
279920
  for await (const chunk of body2) parts.push(chunk);
279921
279921
  return new Uint8Array(Buffer.concat(parts));
279922
279922
  }
279923
- var import_node_crypto87, fs36, BLOB_NAME2, ExternalizedBlobStore, ObjectBlobStore;
279923
+ var import_node_crypto87, fs36, BLOB_NAME2, MIGRATION_SELECTORS, ExternalizedBlobStore, ObjectBlobStore;
279924
279924
  var init_externalized_blobs = __esm({
279925
279925
  "../storage/src/externalized-blobs.ts"() {
279926
279926
  "use strict";
@@ -279930,6 +279930,12 @@ var init_externalized_blobs = __esm({
279930
279930
  init_blob_object_backend();
279931
279931
  init_postgres();
279932
279932
  BLOB_NAME2 = /^[0-9a-f]{64}$/;
279933
+ MIGRATION_SELECTORS = {
279934
+ pg: `location = 'pg'`,
279935
+ ext: `location = 'ext'`,
279936
+ "ext-with-bytes": `location = 'ext' AND bytes IS NOT NULL`,
279937
+ internalize: `location = 'ext' OR bytes IS NULL`
279938
+ };
279933
279939
  ExternalizedBlobStore = class _ExternalizedBlobStore {
279934
279940
  constructor(pool, t, namespace, backend, opts) {
279935
279941
  this.pool = pool;
@@ -280137,13 +280143,45 @@ var init_externalized_blobs = __esm({
280137
280143
  }
280138
280144
  /** 列出待处理的 hash(分批、按 hash 升序,便于中断续跑)。 */
280139
280145
  async listHashes(where, after, limit) {
280140
- const cond = where === "pg" ? `location = 'pg'` : where === "ext" ? `location = 'ext'` : `location = 'ext' AND bytes IS NOT NULL`;
280141
280146
  const res = await this.pool.query(
280142
- `SELECT hash FROM ${this.t} WHERE ${cond} AND hash > $1 ORDER BY hash LIMIT $2`,
280147
+ `SELECT hash FROM ${this.t} WHERE (${MIGRATION_SELECTORS[where]}) AND hash > $1 ORDER BY hash LIMIT $2`,
280143
280148
  [after, limit]
280144
280149
  );
280145
280150
  return res.rows.map((r5) => r5.hash);
280146
280151
  }
280152
+ /** 待处理的行数与字节数(`oasis blobs … --dry-run` 与进度分母)。 */
280153
+ async pendingStats(where) {
280154
+ const res = await this.pool.query(
280155
+ `SELECT count(*)::bigint AS rows, coalesce(sum(size), 0)::bigint AS bytes FROM ${this.t} WHERE ${MIGRATION_SELECTORS[where]}`
280156
+ );
280157
+ const r5 = res.rows[0] ?? {};
280158
+ return { rows: Number(r5.rows ?? 0), bytes: Number(r5.bytes ?? 0) };
280159
+ }
280160
+ /**
280161
+ * 清空给定行的 bytea(§6.2 第 6 步 `--purge-pg-bytes` 的一批):**先确认对象在后端、大小与行一致**,
280162
+ * 只清这些——bytea 是清掉前最后一份副本,对象丢了(误删、恢复不全)时宁可留着。
280163
+ * 返回清掉的行数、这些行的字节数与未通过核对的 hash。
280164
+ */
280165
+ async purgePgBytesVerified(hashes) {
280166
+ if (hashes.length === 0) return { purged: 0, bytes: 0, unverified: [] };
280167
+ const res = await this.pool.query(
280168
+ `SELECT hash, size FROM ${this.t} WHERE hash = ANY($1::text[]) AND location = 'ext' AND bytes IS NOT NULL`,
280169
+ [hashes]
280170
+ );
280171
+ const ok3 = [];
280172
+ const unverified = [];
280173
+ for (const row of res.rows) {
280174
+ const head = await this.backend.head(this.key(row.hash));
280175
+ if (head && head.size === Number(row.size)) ok3.push(row.hash);
280176
+ else unverified.push(row.hash);
280177
+ }
280178
+ if (ok3.length === 0) return { purged: 0, bytes: 0, unverified };
280179
+ const upd = await this.pool.query(
280180
+ `UPDATE ${this.t} SET bytes = NULL WHERE hash = ANY($1::text[]) AND location = 'ext' AND bytes IS NOT NULL RETURNING size`,
280181
+ [ok3]
280182
+ );
280183
+ return { purged: upd.rowCount ?? 0, bytes: upd.rows.reduce((n3, r5) => n3 + Number(r5.size), 0), unverified };
280184
+ }
280147
280185
  /** 观察期后清空已外部化行的 bytea(§6.2 第 6 步),一批一条语句。返回本批清掉的行数。 */
280148
280186
  async purgePgBytes(limit) {
280149
280187
  const res = await this.pool.query(
@@ -320180,7 +320218,7 @@ var s3_object_backend_exports = {};
320180
320218
  __export(s3_object_backend_exports, {
320181
320219
  S3ObjectBackend: () => S3ObjectBackend
320182
320220
  });
320183
- var fs37, import_client_s3, import_lib_storage, import_s3_request_presigner, MULTIPART_THRESHOLD, isNotFound, S3ObjectBackend;
320221
+ var fs37, import_client_s3, import_lib_storage, import_s3_request_presigner, MULTIPART_THRESHOLD, MULTIPART_PART_SIZE, MULTIPART_QUEUE_SIZE, isNotFound, S3ObjectBackend;
320184
320222
  var init_s3_object_backend = __esm({
320185
320223
  "../storage/src/s3-object-backend.ts"() {
320186
320224
  "use strict";
@@ -320191,6 +320229,8 @@ var init_s3_object_backend = __esm({
320191
320229
  init_blob_object_backend();
320192
320230
  init_blob_backend_config();
320193
320231
  MULTIPART_THRESHOLD = 16 * 1024 * 1024;
320232
+ MULTIPART_PART_SIZE = 8 * 1024 * 1024;
320233
+ MULTIPART_QUEUE_SIZE = 2;
320194
320234
  isNotFound = (err) => {
320195
320235
  const e5 = err;
320196
320236
  return e5?.name === "NotFound" || e5?.name === "NoSuchKey" || e5?.$metadata?.httpStatusCode === 404;
@@ -320289,8 +320329,8 @@ var init_s3_object_backend = __esm({
320289
320329
  await new import_lib_storage.Upload({
320290
320330
  client: this.client,
320291
320331
  params: { Bucket: this.bucket, Key, Body: fs37.createReadStream(staged.file), ContentType, ChecksumAlgorithm: "SHA256" },
320292
- partSize: MULTIPART_THRESHOLD,
320293
- queueSize: 2,
320332
+ partSize: MULTIPART_PART_SIZE,
320333
+ queueSize: MULTIPART_QUEUE_SIZE,
320294
320334
  leavePartsOnError: false
320295
320335
  }).done();
320296
320336
  }
@@ -320476,6 +320516,99 @@ var init_blob_backend_config = __esm({
320476
320516
  }
320477
320517
  });
320478
320518
 
320519
+ // ../storage/src/blob-migration.ts
320520
+ async function migrateBlobs(store, op2, opts) {
320521
+ const selector = SELECTOR[op2];
320522
+ const pending = await store.pendingStats(selector);
320523
+ const report = {
320524
+ op: op2,
320525
+ dryRun: opts.dryRun === true,
320526
+ interrupted: false,
320527
+ batches: 0,
320528
+ candidateRows: pending.rows,
320529
+ candidateBytes: pending.bytes,
320530
+ rows: 0,
320531
+ bytes: 0,
320532
+ failed: 0,
320533
+ failures: [],
320534
+ counts: { pg: 0, ext: 0, extWithBytes: 0 }
320535
+ };
320536
+ const fail = (hash3, err) => {
320537
+ report.failed++;
320538
+ if (report.failures.length < MAX_FAILURES_KEPT) {
320539
+ const cause = err instanceof Error && err.cause instanceof Error ? `\uFF1A${err.cause.message}` : "";
320540
+ report.failures.push({ hash: hash3, error: `${err instanceof Error ? err.message : String(err)}${cause}` });
320541
+ }
320542
+ };
320543
+ const stop = () => opts.shouldStop?.() === true;
320544
+ const sleep7 = opts.sleep ?? defaultSleep2;
320545
+ const batch = Math.max(1, Math.floor(opts.batch));
320546
+ if (!report.dryRun) {
320547
+ let after = "";
320548
+ for (; ; ) {
320549
+ if (stop()) {
320550
+ report.interrupted = true;
320551
+ break;
320552
+ }
320553
+ const hashes = await store.listHashes(selector, after, batch);
320554
+ if (hashes.length === 0) break;
320555
+ if (op2 === "purge-pg-bytes") {
320556
+ const r5 = await store.purgePgBytesVerified(hashes);
320557
+ report.rows += r5.purged;
320558
+ report.bytes += r5.bytes;
320559
+ for (const h5 of r5.unverified) fail(h5, new Error("\u5BF9\u8C61\u4E0D\u5728\u540E\u7AEF\u6216\u5927\u5C0F\u4E0E\u884C\u4E0D\u7B26\uFF0Cbytea \u4FDD\u7559"));
320560
+ after = hashes[hashes.length - 1];
320561
+ } else {
320562
+ for (const hash3 of hashes) {
320563
+ if (stop()) {
320564
+ report.interrupted = true;
320565
+ break;
320566
+ }
320567
+ try {
320568
+ const n3 = op2 === "externalize" ? await store.externalizeOne(hash3) : await store.internalizeOne(hash3);
320569
+ report.rows++;
320570
+ report.bytes += n3;
320571
+ } catch (err) {
320572
+ fail(hash3, err);
320573
+ }
320574
+ after = hash3;
320575
+ }
320576
+ }
320577
+ report.batches++;
320578
+ opts.onProgress?.(progressOf(report));
320579
+ if (report.interrupted || hashes.length < batch) break;
320580
+ if (opts.pauseMs > 0) await sleep7(opts.pauseMs);
320581
+ }
320582
+ }
320583
+ report.counts = await store.locationCounts();
320584
+ return report;
320585
+ }
320586
+ function progressOf(r5) {
320587
+ return { batches: r5.batches, candidateRows: r5.candidateRows, candidateBytes: r5.candidateBytes, rows: r5.rows, bytes: r5.bytes, failed: r5.failed };
320588
+ }
320589
+ async function listBlobSchemas(pool) {
320590
+ const res = await pool.query(
320591
+ `SELECT table_schema AS s FROM information_schema.tables
320592
+ WHERE table_name = 'blobs' AND table_type = 'BASE TABLE'
320593
+ AND table_schema NOT IN ('pg_catalog', 'information_schema')
320594
+ ORDER BY table_schema`
320595
+ );
320596
+ return res.rows.map((r5) => r5.s);
320597
+ }
320598
+ var SELECTOR, MAX_FAILURES_KEPT, defaultSleep2;
320599
+ var init_blob_migration = __esm({
320600
+ "../storage/src/blob-migration.ts"() {
320601
+ "use strict";
320602
+ SELECTOR = {
320603
+ externalize: "pg",
320604
+ "purge-pg-bytes": "ext-with-bytes",
320605
+ internalize: "internalize"
320606
+ };
320607
+ MAX_FAILURES_KEPT = 50;
320608
+ defaultSleep2 = (ms) => new Promise((r5) => setTimeout(r5, ms));
320609
+ }
320610
+ });
320611
+
320479
320612
  // ../storage/src/index.ts
320480
320613
  var src_exports = {};
320481
320614
  __export(src_exports, {
@@ -320608,10 +320741,12 @@ __export(src_exports, {
320608
320741
  inventoryZeroTenantTables: () => inventoryZeroTenantTables,
320609
320742
  isUniqueViolation: () => isUniqueViolation2,
320610
320743
  legacyTurnId: () => legacyTurnId,
320744
+ listBlobSchemas: () => listBlobSchemas,
320611
320745
  listChatItemsSchemas: () => listChatItemsSchemas,
320612
320746
  listTenancyCompanies: () => listTenancyCompanies,
320613
320747
  loadKnownCompanies: () => loadKnownCompanies,
320614
320748
  maxGate: () => maxGate,
320749
+ migrateBlobs: () => migrateBlobs,
320615
320750
  missingTypeNames: () => missingTypeNames,
320616
320751
  moveDefaultCompanySchema: () => moveDefaultCompanySchema,
320617
320752
  moveTenancyRows: () => moveTenancyRows,
@@ -320702,6 +320837,7 @@ var init_src10 = __esm({
320702
320837
  init_blob_object_backend();
320703
320838
  init_externalized_blobs();
320704
320839
  init_blob_backend_config();
320840
+ init_blob_migration();
320705
320841
  }
320706
320842
  });
320707
320843
 
@@ -323213,6 +323349,146 @@ var init_usage_ledger_backfill_command = __esm({
323213
323349
  }
323214
323350
  });
323215
323351
 
323352
+ // ../cli/src/blobs-command.ts
323353
+ var blobs_command_exports = {};
323354
+ __export(blobs_command_exports, {
323355
+ BLOBS_USAGE: () => BLOBS_USAGE,
323356
+ BlobsArgError: () => BlobsArgError,
323357
+ parseBlobsArgs: () => parseBlobsArgs,
323358
+ runBlobs: () => runBlobs
323359
+ });
323360
+ function parseBlobsArgs(positional, flags) {
323361
+ const on = (k6) => flags.has(k6) && flags.get(k6) !== "false";
323362
+ const sub = positional[0];
323363
+ if (sub !== "externalize" && sub !== "internalize") throw new BlobsArgError("\u5B50\u547D\u4EE4\u5FC5\u987B\u662F externalize \u6216 internalize");
323364
+ if (on("purge-pg-bytes") && sub !== "externalize") throw new BlobsArgError("--purge-pg-bytes \u53EA\u914D externalize");
323365
+ const op2 = on("purge-pg-bytes") ? "purge-pg-bytes" : sub;
323366
+ const schema = flags.get("schema");
323367
+ const all2 = on("all-schemas");
323368
+ if (schema !== void 0 && all2) throw new BlobsArgError("--schema \u4E0E --all-schemas \u53EA\u80FD\u9009\u4E00\u4E2A");
323369
+ if (schema === void 0 && !all2) throw new BlobsArgError("\u5FC5\u987B\u6307\u5B9A --schema <schema> \u6216 --all-schemas");
323370
+ if (schema !== void 0 && (schema === "" || schema === "true")) throw new BlobsArgError("--schema \u9700\u8981 schema \u540D\uFF08\u5982 company_oasis-prod\u3001public\uFF09");
323371
+ const int2 = (k6, dflt, min2) => {
323372
+ const raw = flags.get(k6);
323373
+ if (raw === void 0) return dflt;
323374
+ const n3 = Number(raw);
323375
+ if (!Number.isInteger(n3) || n3 < min2) throw new BlobsArgError(`--${k6} \u9700\u8981\u4E0D\u5C0F\u4E8E ${min2} \u7684\u6574\u6570`);
323376
+ return n3;
323377
+ };
323378
+ return {
323379
+ op: op2,
323380
+ scope: schema !== void 0 ? { schema } : { all: true },
323381
+ batch: int2("batch", DEFAULT_BATCH[op2], 1),
323382
+ pauseMs: int2("pause-ms", DEFAULT_PAUSE_MS, 0),
323383
+ dryRun: on("dry-run")
323384
+ };
323385
+ }
323386
+ async function runBlobs(positional, flags, io) {
323387
+ let args;
323388
+ try {
323389
+ args = parseBlobsArgs(positional, flags);
323390
+ } catch (err) {
323391
+ if (!(err instanceof BlobsArgError)) throw err;
323392
+ io.err(`${err.message}
323393
+ ${BLOBS_USAGE}`);
323394
+ return 2;
323395
+ }
323396
+ const tag = `[blobs ${args.op}]`;
323397
+ const pgDsn = io.env["OASIS_PG_DSN"] ?? io.env["DATABASE_URL"];
323398
+ if (!pgDsn) {
323399
+ io.err(`${tag} \u9700\u8981 OASIS_PG_DSN\uFF08\u6216 DATABASE_URL\uFF09\u2014\u2014\u8BF7\u4EE5 serve \u7684\u73AF\u5883\u6267\u884C\u672C\u547D\u4EE4\u3002`);
323400
+ return 2;
323401
+ }
323402
+ const storage = await Promise.resolve().then(() => (init_src10(), src_exports));
323403
+ let config2;
323404
+ try {
323405
+ config2 = storage.readBlobBackendConfig(io.env, { hasPg: true, dataDir: io.dir });
323406
+ } catch (err) {
323407
+ io.err(`${tag} \u5BF9\u8C61\u540E\u7AEF\u914D\u7F6E\u6709\u8BEF\uFF1A${err instanceof Error ? err.message : String(err)}`);
323408
+ return 2;
323409
+ }
323410
+ if (config2.kind === "pg") {
323411
+ io.err(`${tag} \u5F53\u524D OASIS_BLOB_BACKEND=pg\uFF08\u6216\u672A\u8BBE\uFF09\uFF1A\u672C\u547D\u4EE4\u8981\u4E0E serve \u540C\u4E00\u4E2A\u5BF9\u8C61\u540E\u7AEF\uFF08fs / s3\uFF09\u3002` + (args.op === "internalize" ? "\u56DE\u6EDA\u987B\u5728\u5207\u56DE pg \u4E4B\u524D\u3001\u4ECD\u662F fs / s3 \u914D\u7F6E\u65F6\u6267\u884C\uFF08ADR 0638 \xA76.3\uFF09\u3002" : ""));
323412
+ return 2;
323413
+ }
323414
+ if (args.op === "purge-pg-bytes" && config2.dualWrite && !args.dryRun) {
323415
+ io.err(`${tag} OASIS_BLOB_PG_DUAL_WRITE=on\uFF1A\u89C2\u5BDF\u671F\u8FD8\u6CA1\u7ED3\u675F\u3002\u5148\u5173\u53CC\u5199\u5E76\u91CD\u542F serve\uFF0C\u518D\u6E05 bytea\uFF08ADR 0638 \xA76.2 \u7B2C 6 \u6B65\uFF09\u3002`);
323416
+ return 2;
323417
+ }
323418
+ if (args.op === "internalize" && !config2.dualWrite) {
323419
+ io.out(`${tag} \u63D0\u793A\uFF1AOASIS_BLOB_PG_DUAL_WRITE \u672A\u5F00\u3002\u56DE\u6EDA\u671F\u95F4 serve \u65B0\u5199\u5165\u7684\u6587\u4EF6\u53EA\u5728\u5BF9\u8C61\u540E\u7AEF\uFF0C\u5207\u56DE pg \u540E\u4F1A\u8BFB\u4E0D\u5230\uFF1B\u5EFA\u8BAE\u5148\u5F00\u53CC\u5199\u5E76\u91CD\u542F serve\uFF0C\u518D\u8DD1\u672C\u547D\u4EE4\uFF08\u89C1 docs/oasis-dev-storage.md \xA72.5.4\uFF09\u3002`);
323420
+ }
323421
+ const pool = storage.createPgPool(pgDsn);
323422
+ try {
323423
+ const existing = await storage.listBlobSchemas(pool);
323424
+ let schemas;
323425
+ if ("schema" in args.scope) {
323426
+ if (!existing.includes(args.scope.schema)) {
323427
+ io.err(`${tag} schema ${args.scope.schema} \u6CA1\u6709 blobs \u8868\u3002\u6709 blobs \u8868\u7684 schema\uFF1A${existing.join(" ") || "\uFF08\u65E0\uFF09"}`);
323428
+ return 2;
323429
+ }
323430
+ schemas = [args.scope.schema];
323431
+ } else {
323432
+ schemas = existing;
323433
+ }
323434
+ const backend = await storage.createObjectBackend(config2);
323435
+ if (!backend) throw new Error("\u5BF9\u8C61\u540E\u7AEF\u88C5\u914D\u5931\u8D25");
323436
+ io.out(`${tag} \u540E\u7AEF ${storage.describeBlobBackend(config2)}\uFF1B${schemas.length} \u4E2A schema\uFF1A${schemas.join(" ")}\uFF1B\u6BCF\u6279 ${args.batch} \u884C\u3001\u6279\u95F4 ${args.pauseMs}ms${args.dryRun ? "\uFF1Bdry-run\uFF08\u4E00\u884C\u4E0D\u52A8\uFF09" : ""}`);
323437
+ const total = { rows: 0, bytes: 0, failed: 0 };
323438
+ for (const schema of schemas) {
323439
+ const store = await storage.ExternalizedBlobStore.open(pool, schema, backend, { dualWrite: config2.dualWrite });
323440
+ const r5 = await storage.migrateBlobs(store, args.op, {
323441
+ batch: args.batch,
323442
+ pauseMs: args.pauseMs,
323443
+ dryRun: args.dryRun,
323444
+ ...io.shouldStop ? { shouldStop: io.shouldStop } : {},
323445
+ ...io.sleep ? { sleep: io.sleep } : {},
323446
+ onProgress: (p4) => io.out(`${tag} ${schema} \u7B2C ${p4.batches} \u6279\uFF1A\u5DF2\u5904\u7406 ${p4.rows}/${p4.candidateRows} \u884C\u3001${fmtBytes(p4.bytes)}/${fmtBytes(p4.candidateBytes)}\uFF0C\u5931\u8D25 ${p4.failed}`)
323447
+ });
323448
+ const c5 = r5.counts;
323449
+ const tail = `\uFF08location\uFF1Apg ${c5.pg}\u3001ext ${c5.ext}\uFF0C\u5176\u4E2D bytea \u672A\u6E05 ${c5.extWithBytes}\uFF09`;
323450
+ if (r5.dryRun) {
323451
+ io.out(`${tag} ${schema} dry-run\uFF1A\u5F85\u5904\u7406 ${r5.candidateRows} \u884C\u3001${fmtBytes(r5.candidateBytes)}${tail}`);
323452
+ } else {
323453
+ io.out(`${tag} ${schema} ${r5.interrupted ? "\u5DF2\u4E2D\u65AD" : "\u5B8C\u6210"}\uFF1A\u5904\u7406 ${r5.rows} \u884C\u3001${fmtBytes(r5.bytes)}\uFF0C\u5931\u8D25 ${r5.failed}${tail}`);
323454
+ for (const f6 of r5.failures) io.out(` \u2717 ${f6.hash}\uFF1A${f6.error}`);
323455
+ if (r5.failed > r5.failures.length) io.out(` \u2026\u53E6\u6709 ${r5.failed - r5.failures.length} \u6761\u5931\u8D25\u672A\u5217\u51FA`);
323456
+ }
323457
+ total.rows += r5.rows;
323458
+ total.bytes += r5.bytes;
323459
+ total.failed += r5.failed;
323460
+ if (r5.interrupted) {
323461
+ io.err(`${tag} \u5DF2\u4E2D\u65AD\uFF1A\u5DF2\u5904\u7406\u7684\u884C\u4E0D\u4F1A\u91CD\u505A\uFF0C\u91CD\u8DD1\u540C\u4E00\u6761\u547D\u4EE4\u4ECE\u5269\u4E0B\u7684\u63A5\u7740\u505A\u3002`);
323462
+ return 130;
323463
+ }
323464
+ }
323465
+ if (!args.dryRun) {
323466
+ io.out(`${tag} \u5408\u8BA1\uFF1A\u5904\u7406 ${total.rows} \u884C\u3001${fmtBytes(total.bytes)}\uFF0C\u5931\u8D25 ${total.failed}\u3002` + (total.failed > 0 ? "\u5931\u8D25\u7684\u884C\u4FDD\u6301\u539F\u72B6\uFF0C\u6392\u67E5\u540E\u91CD\u8DD1\u540C\u4E00\u547D\u4EE4\u53EA\u91CD\u8BD5\u5B83\u4EEC\u3002" : ""));
323467
+ }
323468
+ return total.failed > 0 ? 1 : 0;
323469
+ } finally {
323470
+ await pool.end().catch(() => void 0);
323471
+ }
323472
+ }
323473
+ var BLOBS_USAGE, BlobsArgError, DEFAULT_BATCH, DEFAULT_PAUSE_MS, MB, fmtBytes;
323474
+ var init_blobs_command = __esm({
323475
+ "../cli/src/blobs-command.ts"() {
323476
+ "use strict";
323477
+ BLOBS_USAGE = [
323478
+ "\u7528\u6CD5\uFF1A",
323479
+ " oasis blobs externalize (--schema <s> | --all-schemas) [--batch 50] [--pause-ms 200] [--dry-run]",
323480
+ " oasis blobs externalize --purge-pg-bytes (--schema <s> | --all-schemas) [--batch 500] [--pause-ms 200] [--dry-run]",
323481
+ " oasis blobs internalize (--schema <s> | --all-schemas) [--batch 50] [--pause-ms 200] [--dry-run]"
323482
+ ].join("\n");
323483
+ BlobsArgError = class extends Error {
323484
+ };
323485
+ DEFAULT_BATCH = { externalize: 50, "purge-pg-bytes": 500, internalize: 50 };
323486
+ DEFAULT_PAUSE_MS = 200;
323487
+ MB = 1024 * 1024;
323488
+ fmtBytes = (n3) => n3 >= MB ? `${(n3 / MB).toFixed(1)} MiB` : `${n3} B`;
323489
+ }
323490
+ });
323491
+
323216
323492
  // src/index.ts
323217
323493
  var fs55 = __toESM(require("node:fs"));
323218
323494
  init_src();
@@ -337190,6 +337466,46 @@ var COMMAND_DECLS = {
337190
337466
  "oasis usage-ledger-backfill --all --verify"
337191
337467
  ]
337192
337468
  },
337469
+ blobs: {
337470
+ group: "\u57FA\u7840\u8BBE\u65BD",
337471
+ usage: "oasis blobs <externalize|internalize> (--schema <s> | --all-schemas) ...",
337472
+ description: "\u4E8B\u5B9E\u67DC bytea \u8FC1\u51FA / \u6E05\u7A7A / \u56DE\u6EDA\uFF08ADR 0638 \xA76.2\u3001\xA76.3\uFF09\u3002\u4EE5 serve \u7684\u73AF\u5883\u5728\u90E8\u7F72\u673A\u4E0A\u6267\u884C\uFF0C\u5BF9\u8C61\u540E\u7AEF\u4E0E serve \u540C\u4E00\u5957\u88C5\u914D\u3002",
337473
+ subCommands: ["blobs externalize", "blobs internalize"]
337474
+ },
337475
+ "blobs externalize": {
337476
+ group: "\u57FA\u7840\u8BBE\u65BD",
337477
+ usage: "oasis blobs externalize [--purge-pg-bytes] (--schema <s> | --all-schemas) [--batch 50] [--pause-ms 200] [--dry-run]",
337478
+ description: "\u628A location='pg' \u7684\u884C\u9010\u4E2A\u5199\u8FDB\u5BF9\u8C61\u540E\u7AEF\uFF08\u8BFB\u56DE\u6821\u9A8C sha256 \u540E\u6539 location='ext'\uFF0C\u4FDD\u7559 bytea\uFF09\uFF1B\u5E26 --purge-pg-bytes \u65F6\u6539\u4E3A\u5206\u6279\u6E05\u7A7A\u5DF2\u5916\u90E8\u5316\u884C\u7684 bytea\uFF08\u5148\u6838\u5BF9\u5BF9\u8C61\u5728\u4E14\u5927\u5C0F\u4E00\u81F4\uFF09\u3002\u5206\u6279\u3001\u6279\u95F4\u9650\u901F\u3001\u6BCF\u6279\u8F93\u51FA\u8FDB\u5EA6\uFF1BCtrl-C \u5904\u7406\u5B8C\u5F53\u524D\u4E00\u884C\u518D\u505C\uFF0C\u91CD\u8DD1\u540C\u4E00\u547D\u4EE4\u7EED\u8DD1\u3002\u9000\u51FA\u7801\uFF1A0 \u5B8C\u6210\u30011 \u6709\u884C\u5931\u8D25\u30012 \u53C2\u6570/\u73AF\u5883\u9519\u8BEF\u3001130 \u88AB\u4E2D\u65AD\u3002",
337479
+ flags: [
337480
+ { name: "schema", desc: "\u53EA\u5904\u7406\u8FD9\u4E2A schema\uFF08\u5982 company_oasis-prod\u3001public\uFF09\uFF1B\u987B\u5DF2\u6709 blobs \u8868" },
337481
+ { name: "all-schemas", desc: "\u6240\u6709\u6709 blobs \u8868\u7684 schema\uFF0C\u542B\u5171\u4EAB schema public", boolean: true },
337482
+ { name: "purge-pg-bytes", desc: "\u6E05\u7A7A\u5DF2\u5916\u90E8\u5316\u884C\u7684 bytea\uFF08\u89C2\u5BDF\u671F\u7ED3\u675F\u3001\u5173\u53CC\u5199\u5E76\u91CD\u542F serve \u4E4B\u540E\uFF1B\u53CC\u5199\u5F00\u7740\u65F6\u62D2\u7EDD\uFF09", boolean: true },
337483
+ { name: "batch", desc: "\u6BCF\u6279\u884C\u6570\uFF08\u7F3A\u7701 50\uFF1B--purge-pg-bytes \u7F3A\u7701 500\uFF09" },
337484
+ { name: "pause-ms", desc: "\u6279\u95F4\u505C\u987F\u6BEB\u79D2\u6570\uFF08\u7F3A\u7701 200\uFF09" },
337485
+ { name: "dry-run", desc: "\u53EA\u62A5\u6BCF\u4E2A schema \u5F85\u5904\u7406\u7684\u884C\u6570\u548C\u5B57\u8282\u6570\uFF0C\u4E00\u884C\u4E0D\u52A8", boolean: true }
337486
+ ],
337487
+ examples: [
337488
+ "oasis blobs externalize --all-schemas --dry-run",
337489
+ "oasis blobs externalize --schema company_oasis-prod --batch 50",
337490
+ "oasis blobs externalize --purge-pg-bytes --all-schemas"
337491
+ ]
337492
+ },
337493
+ "blobs internalize": {
337494
+ group: "\u57FA\u7840\u8BBE\u65BD",
337495
+ usage: "oasis blobs internalize (--schema <s> | --all-schemas) [--batch 50] [--pause-ms 200] [--dry-run]",
337496
+ description: "\u56DE\u6EDA\uFF1A\u628A\u5BF9\u8C61\u5199\u56DE bytea\uFF08\u6821\u9A8C sha256\uFF09\u5E76\u6539 location='pg'\u3002\u987B\u5728\u5207\u56DE OASIS_BLOB_BACKEND=pg \u4E4B\u524D\u3001\u4ECD\u662F fs / s3 \u914D\u7F6E\u65F6\u6267\u884C\uFF1B\u5EFA\u8BAE\u5148\u5F00\u53CC\u5199\u5E76\u91CD\u542F serve\u3002\u5206\u6279\u3001\u9650\u901F\u3001\u8FDB\u5EA6\u3001\u53EF\u4E2D\u65AD\u7EED\u8DD1\uFF0C\u9000\u51FA\u7801\u540C externalize\u3002",
337497
+ flags: [
337498
+ { name: "schema", desc: "\u53EA\u5904\u7406\u8FD9\u4E2A schema\uFF1B\u987B\u5DF2\u6709 blobs \u8868" },
337499
+ { name: "all-schemas", desc: "\u6240\u6709\u6709 blobs \u8868\u7684 schema\uFF0C\u542B\u5171\u4EAB schema public", boolean: true },
337500
+ { name: "batch", desc: "\u6BCF\u6279\u884C\u6570\uFF08\u7F3A\u7701 50\uFF09" },
337501
+ { name: "pause-ms", desc: "\u6279\u95F4\u505C\u987F\u6BEB\u79D2\u6570\uFF08\u7F3A\u7701 200\uFF09" },
337502
+ { name: "dry-run", desc: "\u53EA\u62A5\u5F85\u5199\u56DE\u7684\u884C\u6570\u548C\u5B57\u8282\u6570\uFF0C\u4E00\u884C\u4E0D\u52A8", boolean: true }
337503
+ ],
337504
+ examples: [
337505
+ "oasis blobs internalize --all-schemas --dry-run",
337506
+ "oasis blobs internalize --all-schemas"
337507
+ ]
337508
+ },
337193
337509
  kb: {
337194
337510
  group: "\u77E5\u8BC6\u5E93",
337195
337511
  usage: "oasis kb <ask|ingest|status|maintain|lint> ...",
@@ -339615,7 +339931,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback2) {
339615
339931
  }
339616
339932
  }
339617
339933
  }
339618
- var CLI_VERSION = "2.2.119" ? "2.2.119" : "dev";
339934
+ var CLI_VERSION = "2.2.120" ? "2.2.120" : "dev";
339619
339935
  function apiHeaders(token2, company) {
339620
339936
  const headers = {
339621
339937
  authorization: `Bearer ${token2}`,
@@ -339977,6 +340293,31 @@ async function runCli(argv, println = console.log, progressln = console.error) {
339977
340293
  });
339978
340294
  return;
339979
340295
  }
340296
+ if (command6 === "blobs") {
340297
+ const { runBlobs: runBlobs2 } = await Promise.resolve().then(() => (init_blobs_command(), blobs_command_exports));
340298
+ let stopRequested = false;
340299
+ const onSignal = () => {
340300
+ if (stopRequested) process.exit(130);
340301
+ stopRequested = true;
340302
+ process.stderr.write("[blobs] \u6536\u5230\u4E2D\u65AD\uFF1A\u5904\u7406\u5B8C\u5F53\u524D\u8FD9\u4E00\u884C\u540E\u505C\u6B62\uFF08\u518D\u6309\u4E00\u6B21\u7ACB\u5373\u9000\u51FA\uFF09\n");
340303
+ };
340304
+ process.on("SIGINT", onSignal);
340305
+ process.on("SIGTERM", onSignal);
340306
+ try {
340307
+ process.exitCode = await runBlobs2(positional, flags, {
340308
+ out: (line2) => println(line2),
340309
+ err: (line2) => process.stderr.write(`${line2}
340310
+ `),
340311
+ env: process.env,
340312
+ dir,
340313
+ shouldStop: () => stopRequested
340314
+ });
340315
+ } finally {
340316
+ process.off("SIGINT", onSignal);
340317
+ process.off("SIGTERM", onSignal);
340318
+ }
340319
+ return;
340320
+ }
339980
340321
  if (command6 === "node-token") {
339981
340322
  const store = createNodeTokenStore(path42.join(dir, "node-tokens.json"));
339982
340323
  const sub = positional[0];
@@ -343793,7 +344134,7 @@ function shimScript() {
343793
344134
  }
343794
344135
 
343795
344136
  // src/index.ts
343796
- var PKG_VERSION = true ? "2.2.119" : "dev";
344137
+ var PKG_VERSION = true ? "2.2.120" : "dev";
343797
344138
  var LOCAL_BIN = localBin();
343798
344139
  var NPM_PREFIX = npmPrefix();
343799
344140
  var INSTANCE = DEFAULT_INSTANCE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test_v2",
3
- "version": "2.2.119",
3
+ "version": "2.2.120",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"
@@ -26,6 +26,6 @@
26
26
  "node": ">=20"
27
27
  },
28
28
  "oasisRelease": {
29
- "sourceHead": "4f51168d5c54f729336eeef57637cda2fa6372b8"
29
+ "sourceHead": "5cbcb042286da9da2e41e738c8d76bfbe2324d57"
30
30
  }
31
31
  }