@madewithremy/admin 0.1.13 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/prod.js CHANGED
@@ -3017,33 +3017,48 @@ async function waitForIngest(ctx, params) {
3017
3017
  documents: tracked.map(summarize)
3018
3018
  };
3019
3019
  }
3020
+ var FAILURES_PAGE = 50;
3020
3021
  async function waitForCandidate(ctx, params) {
3021
3022
  const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;
3022
- const pendingOf = (docs2) => docs2.filter((d) => d.status === "processing");
3023
3023
  const outcome = await pollUntil(
3024
- () => allDocuments(ctx, { slug: params.slug, candidate: true }),
3025
- (docs2) => pendingOf(docs2).length === 0,
3024
+ async () => {
3025
+ const { dataSources } = await list8(ctx);
3026
+ const source = dataSources.find((s) => s.slug === params.slug);
3027
+ if (!source) {
3028
+ throw new Error(`Data source "${params.slug}" not found.`);
3029
+ }
3030
+ return source.candidate?.progress ?? null;
3031
+ },
3032
+ (progress2) => progress2 === null || progress2.processing === 0,
3026
3033
  {
3027
3034
  timeoutMs,
3028
3035
  pollMs: POLL_MS2,
3029
- describe: (docs2, start2) => `rebuilding\u2026 ${docs2.length - pendingOf(docs2).length}/${docs2.length} done (${elapsedSeconds(start2)}s)`,
3036
+ describe: (progress2, start2) => progress2 ? `rebuilding\u2026 ${progress2.done}/${progress2.total} done (${elapsedSeconds(start2)}s)` : `rebuilding\u2026 (${elapsedSeconds(start2)}s)`,
3030
3037
  onProgress: params.onProgress
3031
3038
  }
3032
3039
  );
3033
- const docs = outcome.value;
3040
+ const counts = outcome.value;
3041
+ const failed = counts && counts.error > 0 ? (await documents(ctx, {
3042
+ slug: params.slug,
3043
+ candidate: true,
3044
+ status: "error",
3045
+ limit: FAILURES_PAGE
3046
+ })).documents.map(summarize) : [];
3034
3047
  if (!outcome.settled) {
3035
3048
  return {
3036
3049
  status: "timeout",
3037
- documents: docs.map(summarize),
3050
+ counts,
3051
+ documents: failed,
3038
3052
  error: timedOut(
3039
3053
  timeoutMs,
3040
- `with ${pendingOf(docs).length} document(s) still building`
3054
+ `with ${counts?.processing ?? 0} document(s) still building`
3041
3055
  )
3042
3056
  };
3043
3057
  }
3044
3058
  return {
3045
- status: docs.some((d) => d.status === "error") ? "error" : "ready",
3046
- documents: docs.map(summarize)
3059
+ status: counts && counts.error > 0 ? "error" : "ready",
3060
+ counts,
3061
+ documents: failed
3047
3062
  };
3048
3063
  }
3049
3064
  var DOCUMENTS_IDS_MAX = 200;
@@ -3056,7 +3071,10 @@ function documents(ctx, params) {
3056
3071
  candidate: params.candidate || void 0,
3057
3072
  ids: params.ids?.length ? params.ids.join(",") : void 0,
3058
3073
  limit: params.limit,
3059
- cursor: params.cursor
3074
+ cursor: params.cursor,
3075
+ order: params.order,
3076
+ status: params.status,
3077
+ filename: params.filename
3060
3078
  })}`
3061
3079
  );
3062
3080
  }
@@ -3074,7 +3092,10 @@ async function allDocuments(ctx, params) {
3074
3092
  candidate: params.candidate,
3075
3093
  ids,
3076
3094
  limit: 1e3,
3077
- cursor
3095
+ cursor,
3096
+ order: params.order,
3097
+ status: params.status,
3098
+ filename: params.filename
3078
3099
  });
3079
3100
  out2.push(...page.documents ?? []);
3080
3101
  cursor = page.nextCursor ?? void 0;
@@ -3669,7 +3690,7 @@ function hydrate(ctx, params) {
3669
3690
  ctx,
3670
3691
  "POST",
3671
3692
  `${base4(ctx.appId)}/hydrate`,
3672
- { slug: params.slug }
3693
+ { slug: params.slug, ...params.since ? { since: params.since } : {} }
3673
3694
  );
3674
3695
  }
3675
3696
  function reindex(ctx, params) {
@@ -3883,9 +3904,10 @@ async function waitForSet(ctx, params) {
3883
3904
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3884
3905
  var dataSourceEvalsSpecs = {
3885
3906
  "datasources hydrate": {
3886
- usage: "Usage: remy-admin datasources hydrate [--source <slug>] [--wait] [--timeout <sec>]",
3907
+ usage: "Usage: remy-admin datasources hydrate [--source <slug>] [--since <iso>] [--wait] [--timeout <sec>]",
3887
3908
  flags: {
3888
3909
  source: { type: "string" },
3910
+ since: { type: "string" },
3889
3911
  wait: { type: "boolean" },
3890
3912
  timeout: { type: "string" }
3891
3913
  }
@@ -4056,7 +4078,14 @@ function selectorFromFlag(raw) {
4056
4078
  }
4057
4079
  async function hydrate2(ctx, a) {
4058
4080
  const slug = a.str("source") || DEFAULT_SOURCE;
4059
- const started = await hydrate(ctx, { slug });
4081
+ const since = a.str("since");
4082
+ if (since && Number.isNaN(Date.parse(since))) {
4083
+ fatal("--since must be an ISO 8601 timestamp, e.g. 2026-09-08T15:17:00Z.");
4084
+ }
4085
+ const started = await hydrate(ctx, {
4086
+ slug,
4087
+ ...since ? { since: new Date(since).toISOString() } : {}
4088
+ });
4060
4089
  if (started.resident || !a.bool("wait")) {
4061
4090
  out({
4062
4091
  dataSource: slug,
@@ -4351,7 +4380,7 @@ var dataSourceEvalsHandlers = {
4351
4380
  };
4352
4381
  var dataSourceEvalsHelp = `
4353
4382
  Warming and sampling:
4354
- remy-admin datasources hydrate [--source <slug>] [--wait]
4383
+ remy-admin datasources hydrate [--source <slug>] [--since <iso>] [--wait]
4355
4384
  remy-admin datasources sample --source <slug> --size <n> [--as <slug>] [--filter <k=v,...|json>] [--stratify <key>] [--placement <id|shared>] [--wait]
4356
4385
 
4357
4386
  A large source whose index was evicted (the shared pool holds a working set,
@@ -4361,6 +4390,14 @@ Warming and sampling:
4361
4390
  \`--wait\` blocks until the index is back. \`datasources list\` shows the
4362
4391
  reload's progress under \`hydration\`.
4363
4392
 
4393
+ \`hydrate --since <iso>\` is a refill rather than a warm-up: it copies every
4394
+ document built at or after that time into the index whether or not the index
4395
+ is resident. Dedicated capacity that restored from a snapshot is missing
4396
+ everything written after the snapshot was taken; the platform starts this
4397
+ refill itself when it sees the restore, and \`infra logs\` shows it. Use the
4398
+ flag for a restore that predates that, with the snapshot's time from the
4399
+ resource log.
4400
+
4364
4401
  \`sample\` draws documents from a source into a new one that shares its
4365
4402
  exact pinned config, so what you measure on the sample says something about
4366
4403
  the parent. Uniform by default; --stratify <metadata key> takes each value
@@ -5074,8 +5111,12 @@ var dataSourcesSpecs = {
5074
5111
  usage: "Usage: remy-admin datasources list"
5075
5112
  },
5076
5113
  "datasources status": {
5077
- usage: "Usage: remy-admin datasources status [--source <slug>]",
5078
- flags: { source: { type: "string" } }
5114
+ usage: "Usage: remy-admin datasources status [--source <slug>] [--status error] [--all]",
5115
+ flags: {
5116
+ source: { type: "string" },
5117
+ status: { type: "string" },
5118
+ all: { type: "boolean" }
5119
+ }
5079
5120
  },
5080
5121
  "datasources rm": {
5081
5122
  usage: "Usage: remy-admin datasources rm [--source <slug>] (--document <id> | --filter <k=v,...|json>)",
@@ -5216,10 +5257,42 @@ async function dataSourcesList(ctx) {
5216
5257
  }
5217
5258
  async function dataSourcesStatus(ctx, a) {
5218
5259
  const slug = sourceOf(a);
5219
- const documents2 = await allDocuments(ctx, { slug });
5260
+ const status2 = a.str("status");
5261
+ if (status2 !== void 0 && status2 !== "error") {
5262
+ fatal("--status can only be 'error'.");
5263
+ }
5264
+ if (a.bool("all")) {
5265
+ const documents2 = await allDocuments(ctx, {
5266
+ slug,
5267
+ ...status2 ? { status: "error" } : {}
5268
+ });
5269
+ out({
5270
+ dataSource: slug,
5271
+ documents: documents2.map(summarize)
5272
+ });
5273
+ return;
5274
+ }
5275
+ const { dataSources: sources2 } = await list8(ctx);
5276
+ const source = sources2.find((s) => s.slug === slug);
5277
+ if (!source) {
5278
+ out({ dataSource: slug, exists: false });
5279
+ return;
5280
+ }
5281
+ const failures = status2 === "error" || source.counts.error > 0 ? await documents(ctx, {
5282
+ slug,
5283
+ status: "error",
5284
+ limit: FAILURES_PAGE
5285
+ }) : null;
5220
5286
  out({
5221
5287
  dataSource: slug,
5222
- documents: documents2.map(summarize)
5288
+ counts: source.counts,
5289
+ chunkCount: source.chunkCount,
5290
+ lastIngestedAt: source.lastIngestedAt,
5291
+ activeVersion: source.activeVersion,
5292
+ candidate: source.candidate,
5293
+ job: source.job,
5294
+ failures: (failures?.documents ?? []).map(summarize),
5295
+ moreFailures: !!failures?.nextCursor
5223
5296
  });
5224
5297
  }
5225
5298
  async function dataSourcesRm(ctx, a) {
@@ -5515,7 +5588,8 @@ async function dataSourcesRevectorize(ctx, a) {
5515
5588
  dataSource: slug,
5516
5589
  candidateVersion: started.candidateVersion,
5517
5590
  status: result.status,
5518
- documents: result.documents,
5591
+ counts: result.counts,
5592
+ failures: result.documents,
5519
5593
  note: result.status === "error" ? "Some documents failed. Promote with --force to accept, or fix and re-run." : "Run `promote` to make this version live."
5520
5594
  });
5521
5595
  if (result.status === "error") {
@@ -5561,7 +5635,7 @@ matching passages with a citation pointing back at the source document.
5561
5635
  Subcommands:
5562
5636
  add Add one or more documents (skips unchanged files)
5563
5637
  list List data sources with document counts
5564
- status Show per-document ingest state
5638
+ status Show a source's counts and its failed documents (--all walks every document)
5565
5639
  rm Remove a document, or every document matching a filter
5566
5640
  search Query a corpus \u2014 useful to sanity-check one you just built
5567
5641
  create Create an empty source, optionally on dedicated capacity
@@ -5588,7 +5662,7 @@ Subcommands:
5588
5662
  Usage:
5589
5663
  remy-admin datasources add [--source <slug>] [--metadata <k=v,...>] [--wait] [--timeout <sec>] <file...>
5590
5664
  remy-admin datasources list
5591
- remy-admin datasources status [--source <slug>]
5665
+ remy-admin datasources status [--source <slug>] [--status error] [--all]
5592
5666
  remy-admin datasources rm [--source <slug>] (--document <id> | --filter <k=v,...|json>)
5593
5667
  remy-admin datasources search [--source <slug>] [search options] <query>
5594
5668
  remy-admin datasources create --source <slug> [--name <name>] [--placement <resource-id|shared>] [rebuild settings...]
@@ -7501,6 +7575,21 @@ function get10(ctx, params) {
7501
7575
  `${base6(ctx.appId)}/${encodeURIComponent(params.id)}`
7502
7576
  );
7503
7577
  }
7578
+ function logs(ctx, params) {
7579
+ const query3 = new URLSearchParams();
7580
+ if (params.after) {
7581
+ query3.set("after", params.after);
7582
+ }
7583
+ if (params.limit) {
7584
+ query3.set("limit", String(params.limit));
7585
+ }
7586
+ const search2 = query3.toString();
7587
+ return call(
7588
+ ctx,
7589
+ "GET",
7590
+ `${base6(ctx.appId)}/${encodeURIComponent(params.id)}/logs${search2 ? `?${search2}` : ""}`
7591
+ );
7592
+ }
7504
7593
  function provision(ctx, params) {
7505
7594
  return call(ctx, "POST", base6(ctx.appId), {
7506
7595
  offeringId: params.offeringId,
@@ -7586,6 +7675,11 @@ var infraSpecs = {
7586
7675
  usage: "Usage: remy-admin infra get <id>",
7587
7676
  positionals: [{ name: "id", required: true }]
7588
7677
  },
7678
+ "infra logs": {
7679
+ usage: "Usage: remy-admin infra logs <id> [--follow] [--limit <n>]",
7680
+ positionals: [{ name: "id", required: true }],
7681
+ flags: { follow: { type: "boolean" }, limit: { type: "string" } }
7682
+ },
7589
7683
  "infra provision": {
7590
7684
  usage: "Usage: remy-admin infra provision --offering <id> [--name <name>] [--wait] [--timeout <sec>]",
7591
7685
  flags: {
@@ -7657,6 +7751,30 @@ async function infraList(ctx, a) {
7657
7751
  async function infraGet(ctx, a) {
7658
7752
  out(await get10(ctx, { id: a.req("id") }));
7659
7753
  }
7754
+ var FOLLOW_POLL_MS = 4e3;
7755
+ async function infraLogs(ctx, a) {
7756
+ const id = a.req("id");
7757
+ const limitRaw = a.str("limit");
7758
+ const limit = limitRaw ? Number(limitRaw) : void 0;
7759
+ let { logs: logs2 } = await logs(ctx, { id, ...limit ? { limit } : {} });
7760
+ out({ logs: logs2 });
7761
+ if (!a.bool("follow")) {
7762
+ return;
7763
+ }
7764
+ let after = logs2.length > 0 ? logs2[logs2.length - 1].id : void 0;
7765
+ while (true) {
7766
+ await new Promise((resolve2) => setTimeout(resolve2, FOLLOW_POLL_MS));
7767
+ ({ logs: logs2 } = await logs(ctx, {
7768
+ id,
7769
+ ...after ? { after } : {},
7770
+ limit: 500
7771
+ }));
7772
+ if (logs2.length > 0) {
7773
+ out({ logs: logs2 });
7774
+ after = logs2[logs2.length - 1].id;
7775
+ }
7776
+ }
7777
+ }
7660
7778
  function pricingOf(resource) {
7661
7779
  const offering = resource.offering;
7662
7780
  if (!offering) {
@@ -7755,6 +7873,7 @@ async function infraResize(ctx, a) {
7755
7873
  var infraHandlers = {
7756
7874
  "infra list": infraList,
7757
7875
  "infra get": infraGet,
7876
+ "infra logs": infraLogs,
7758
7877
  "infra provision": infraProvision,
7759
7878
  "infra hibernate": infraHibernate,
7760
7879
  "infra resume": infraResume,
@@ -7776,7 +7895,8 @@ the price it committed to. Every action below is audited.
7776
7895
 
7777
7896
  Subcommands:
7778
7897
  list Resources on this app, plus the offerings you can provision
7779
- get One resource with its state timeline and attached sources
7898
+ get One resource: billing to date, state timeline, recent log, attached sources
7899
+ logs The platform's log for a resource (--follow to keep reading)
7780
7900
  provision Lease a new resource (needs a month's credits; prints the price)
7781
7901
  hibernate Park it: data kept, searches paused, compute charge stops
7782
7902
  resume Bring a hibernated resource back
@@ -7787,6 +7907,7 @@ Subcommands:
7787
7907
  Usage:
7788
7908
  remy-admin infra list [--include-destroyed]
7789
7909
  remy-admin infra get <id>
7910
+ remy-admin infra logs <id> [--follow] [--limit <n>]
7790
7911
  remy-admin infra provision --offering <id> [--name <name>] [--wait] [--timeout <sec>]
7791
7912
  remy-admin infra hibernate <id> [--wait] [--timeout <sec>]
7792
7913
  remy-admin infra resume <id> [--wait] [--timeout <sec>]
@@ -7829,6 +7950,19 @@ Phases and timing:
7829
7950
  takes about two minutes, more with more data: snapshots and restores scale
7830
7951
  with the collection. --wait defaults to 600s; pass --timeout for a large one.
7831
7952
 
7953
+ Billing and the log:
7954
+ \`infra get\` reports resource.billing: what the resource has actually been
7955
+ charged to date (from the ledger, exact across resizes), the hours at each
7956
+ rate, and when it was last billed. Rates are on resource.offering.
7957
+
7958
+ The log is the platform's narration of the resource, not the instance's
7959
+ stdout: each step a transition went through ("Waiting for capacity",
7960
+ "Restoring collections 2/3"), each failed attempt, and each failure with the
7961
+ pod's recent Kubernetes events and the warnings-and-errors tail of the
7962
+ instance log at that moment (line.data). \`infra get\` includes the newest
7963
+ 200 lines; \`infra logs\` pages the rest and, with --follow, prints new lines
7964
+ every few seconds as their own JSON document until interrupted.
7965
+
7832
7966
  --wait exit codes: 0 reached the target phase \xB7 1 the platform reported failure \xB7
7833
7967
  2 still transitioning when --timeout elapsed (default 600s).`;
7834
7968
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@madewithremy/admin",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Admin SDK + CLI for managing production Remy apps",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",