@stackbone/sdk 0.1.0-alpha.1 → 0.1.0-alpha.2

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/index.cjs CHANGED
@@ -1793,9 +1793,9 @@ var nanoid = /^[a-zA-Z0-9_-]{21}$/;
1793
1793
  var duration = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/;
1794
1794
  var extendedDuration = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/;
1795
1795
  var guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/;
1796
- var uuid = /* @__PURE__ */ __name((version2) => {
1797
- if (!version2) return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/;
1798
- return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version2}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
1796
+ var uuid = /* @__PURE__ */ __name((version3) => {
1797
+ if (!version3) return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/;
1798
+ return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version3}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
1799
1799
  }, "uuid");
1800
1800
  var uuid4 = /* @__PURE__ */ uuid(4);
1801
1801
  var uuid6 = /* @__PURE__ */ uuid(6);
@@ -14979,10 +14979,10 @@ function fromJSONSchema(schema, params) {
14979
14979
  if (typeof schema === "boolean") {
14980
14980
  return schema ? z.any() : z.never();
14981
14981
  }
14982
- const version2 = detectVersion(schema, params?.defaultTarget);
14982
+ const version3 = detectVersion(schema, params?.defaultTarget);
14983
14983
  const defs = schema.$defs || schema.definitions || {};
14984
14984
  const ctx = {
14985
- version: version2,
14985
+ version: version3,
14986
14986
  defs,
14987
14987
  refs: /* @__PURE__ */ new Map(),
14988
14988
  processing: /* @__PURE__ */ new Set(),
@@ -16651,6 +16651,34 @@ function pickDefinedAsStrings(source) {
16651
16651
  }
16652
16652
  __name(pickDefinedAsStrings, "pickDefinedAsStrings");
16653
16653
 
16654
+ // src/lib/facade-helpers.ts
16655
+ function remapHttpNotFound(code, domainCode, message, meta3) {
16656
+ if (code !== "http_not_found") return null;
16657
+ const error48 = {
16658
+ code: domainCode,
16659
+ message
16660
+ };
16661
+ if (meta3) error48.meta = meta3;
16662
+ return err(error48);
16663
+ }
16664
+ __name(remapHttpNotFound, "remapHttpNotFound");
16665
+ function validateStringArray(values, field, errorCode) {
16666
+ if (!Array.isArray(values) || values.length === 0) {
16667
+ return err({
16668
+ code: errorCode,
16669
+ message: `\`${field}\` must be a non-empty array.`
16670
+ });
16671
+ }
16672
+ if (values.some((v) => typeof v !== "string" || !v.trim())) {
16673
+ return err({
16674
+ code: errorCode,
16675
+ message: `\`${field}[*]\` must be non-empty strings.`
16676
+ });
16677
+ }
16678
+ return null;
16679
+ }
16680
+ __name(validateStringArray, "validateStringArray");
16681
+
16654
16682
  // src/facades/config/config.ts
16655
16683
  var ConfigFacade = class {
16656
16684
  static {
@@ -16672,7 +16700,11 @@ var ConfigFacade = class {
16672
16700
  const gateResult = await this._gate();
16673
16701
  if (gateResult.error) return err(gateResult.error);
16674
16702
  const result = await this._http.get(`/api/config/${encodeURIComponent(key)}`);
16675
- if (result.error) return remapNotFound(result.error.code, key) ?? result;
16703
+ if (result.error) {
16704
+ return remapHttpNotFound(result.error.code, "config_not_found", `Config key \`${key}\` is not set for this agent.`, {
16705
+ key
16706
+ }) ?? result;
16707
+ }
16676
16708
  return ok(result.data.value);
16677
16709
  }
16678
16710
  /**
@@ -16682,18 +16714,8 @@ var ConfigFacade = class {
16682
16714
  * is `Partial<T>`).
16683
16715
  */
16684
16716
  async getMany(keys) {
16685
- if (!Array.isArray(keys) || keys.length === 0) {
16686
- return err({
16687
- code: "config_invalid_request",
16688
- message: "`keys` must be a non-empty array."
16689
- });
16690
- }
16691
- if (keys.some((k) => !k.trim())) {
16692
- return err({
16693
- code: "config_invalid_request",
16694
- message: "`keys[*]` must be non-empty strings."
16695
- });
16696
- }
16717
+ const invalid = validateStringArray(keys, "keys", "config_invalid_request");
16718
+ if (invalid) return invalid;
16697
16719
  const gateResult = await this._gate();
16698
16720
  if (gateResult.error) return err(gateResult.error);
16699
16721
  const result = await this._http.get("/api/config", {
@@ -16712,17 +16734,6 @@ var ConfigFacade = class {
16712
16734
  return ok(values);
16713
16735
  }
16714
16736
  };
16715
- function remapNotFound(code, key) {
16716
- if (code !== "http_not_found") return null;
16717
- return err({
16718
- code: "config_not_found",
16719
- message: `Config key \`${key}\` is not set for this agent.`,
16720
- meta: {
16721
- key
16722
- }
16723
- });
16724
- }
16725
- __name(remapNotFound, "remapNotFound");
16726
16737
 
16727
16738
  // src/facades/connections/connections.ts
16728
16739
  var ConnectionsFacade = class {
@@ -16808,7 +16819,11 @@ var SecretsFacade = class {
16808
16819
  const gateResult = await this._gate();
16809
16820
  if (gateResult.error) return err(gateResult.error);
16810
16821
  const result = await this._http.get(`/api/secrets/${encodeURIComponent(name)}`);
16811
- if (result.error) return remapNotFound2(result.error.code, name) ?? result;
16822
+ if (result.error) {
16823
+ return remapHttpNotFound(result.error.code, "secrets_not_found", `Secret \`${name}\` is not registered for this organization.`, {
16824
+ name
16825
+ }) ?? result;
16826
+ }
16812
16827
  if (typeof result.data.value !== "string") {
16813
16828
  return err({
16814
16829
  code: "secrets_invalid_response",
@@ -16821,23 +16836,13 @@ var SecretsFacade = class {
16821
16836
  return ok(result.data.value);
16822
16837
  }
16823
16838
  /**
16824
- * Names absent from the workspace come back as omissions in the response —
16839
+ * Names absent from the organization come back as omissions in the response —
16825
16840
  * the returned map only contains entries the control plane actually has.
16826
16841
  * Callers that need "all-or-nothing" semantics should diff the keys.
16827
16842
  */
16828
16843
  async getMany(names) {
16829
- if (!Array.isArray(names) || names.length === 0) {
16830
- return err({
16831
- code: "secrets_invalid_request",
16832
- message: "`names` must be a non-empty array."
16833
- });
16834
- }
16835
- if (names.some((n) => !n.trim())) {
16836
- return err({
16837
- code: "secrets_invalid_request",
16838
- message: "`names[*]` must be non-empty strings."
16839
- });
16840
- }
16844
+ const invalid = validateStringArray(names, "names", "secrets_invalid_request");
16845
+ if (invalid) return invalid;
16841
16846
  const gateResult = await this._gate();
16842
16847
  if (gateResult.error) return err(gateResult.error);
16843
16848
  const result = await this._http.get("/api/secrets", {
@@ -16856,17 +16861,6 @@ var SecretsFacade = class {
16856
16861
  return ok(values);
16857
16862
  }
16858
16863
  };
16859
- function remapNotFound2(code, name) {
16860
- if (code !== "http_not_found") return null;
16861
- return err({
16862
- code: "secrets_not_found",
16863
- message: `Secret \`${name}\` is not registered for this workspace.`,
16864
- meta: {
16865
- name
16866
- }
16867
- });
16868
- }
16869
- __name(remapNotFound2, "remapNotFound");
16870
16864
 
16871
16865
  // src/lib/http-client.ts
16872
16866
  var RETRYABLE_STATUS = /* @__PURE__ */ new Set([
@@ -17749,6 +17743,11 @@ async function aggregateRunCost(runId, options) {
17749
17743
  };
17750
17744
  }
17751
17745
  __name(aggregateRunCost, "aggregateRunCost");
17746
+
17747
+ // package.json
17748
+ var version2 = "0.1.0-alpha.2";
17749
+
17750
+ // src/observability/logger.ts
17752
17751
  var LOG_LEVELS = {
17753
17752
  trace: 10,
17754
17753
  debug: 20,
@@ -17962,7 +17961,7 @@ var OtlpHttpDestination = class OtlpHttpDestination2 {
17962
17961
  };
17963
17962
  var SDK_SCOPE = {
17964
17963
  name: "@stackbone/sdk",
17965
- version: "0.0.1"
17964
+ version: version2
17966
17965
  };
17967
17966
  function buildOtlpLogsBody(records, resourceAttributes) {
17968
17967
  return {
@@ -17995,11 +17994,12 @@ function toOtlpLogRecord(record2) {
17995
17994
  };
17996
17995
  }
17997
17996
  __name(toOtlpLogRecord, "toOtlpLogRecord");
17997
+ var SEVERITY_TEXT_BY_LEVEL = Object.fromEntries(Object.entries(LOG_LEVELS).map(([name, value]) => [
17998
+ value,
17999
+ name.toUpperCase()
18000
+ ]));
17998
18001
  function severityText(level) {
17999
- for (const [name, value] of Object.entries(LOG_LEVELS)) {
18000
- if (value === level) return name.toUpperCase();
18001
- }
18002
- return "INFO";
18002
+ return SEVERITY_TEXT_BY_LEVEL[level] ?? "INFO";
18003
18003
  }
18004
18004
  __name(severityText, "severityText");
18005
18005
  function toOtlpAttributes(attrs) {
@@ -18167,11 +18167,11 @@ var RunStepsSpanProcessor = class {
18167
18167
  }
18168
18168
  }
18169
18169
  buildRow(span) {
18170
- const runId = readString(span.attributes[RUN_ID_ATTRIBUTE]);
18171
- if (!runId) return null;
18172
18170
  const spanId = span.spanContext().spanId;
18173
18171
  const stepId = this.stepIdBySpanId.get(spanId) ?? this.newId();
18174
18172
  this.stepIdBySpanId.delete(spanId);
18173
+ const runId = readString(span.attributes[RUN_ID_ATTRIBUTE]);
18174
+ if (!runId) return null;
18175
18175
  const parentSpanId = span.parentSpanContext?.spanId ?? span.parentSpanId ?? null;
18176
18176
  const parentStepId = parentSpanId ? this.stepIdBySpanId.get(parentSpanId) ?? null : null;
18177
18177
  const startedAt = formatHrTime(span.startTime);
@@ -18621,6 +18621,41 @@ function isUnsupportedModelError(error48) {
18621
18621
  }
18622
18622
  __name(isUnsupportedModelError, "isUnsupportedModelError");
18623
18623
 
18624
+ // src/modules/rag/errors.ts
18625
+ var PG_UNDEFINED_TABLE = "42P01";
18626
+ var RAG_SCHEMA_MISSING_HINT = "run `stackbone db migrate add-rag` and `stackbone db migrate up`";
18627
+ function isTaggedError(cause) {
18628
+ return cause instanceof Error;
18629
+ }
18630
+ __name(isTaggedError, "isTaggedError");
18631
+ function toRagError(cause, message, fallbackCode = "rag_error") {
18632
+ if (isTaggedError(cause) && cause.code === PG_UNDEFINED_TABLE) {
18633
+ return {
18634
+ code: "rag_schema_missing",
18635
+ message: `RAG tables are not installed \u2014 ${RAG_SCHEMA_MISSING_HINT}.`,
18636
+ cause,
18637
+ meta: {
18638
+ hint: RAG_SCHEMA_MISSING_HINT
18639
+ }
18640
+ };
18641
+ }
18642
+ if (isTaggedError(cause)) {
18643
+ const error48 = {
18644
+ code: cause.code ?? fallbackCode,
18645
+ message: `${message}: ${cause.message}`,
18646
+ cause
18647
+ };
18648
+ if (cause.meta) error48.meta = cause.meta;
18649
+ return error48;
18650
+ }
18651
+ return {
18652
+ code: fallbackCode,
18653
+ message,
18654
+ cause
18655
+ };
18656
+ }
18657
+ __name(toRagError, "toRagError");
18658
+
18624
18659
  // src/modules/rag/jobs.ts
18625
18660
  function createSqlJobWriter(sql) {
18626
18661
  return {
@@ -18646,7 +18681,7 @@ function createSqlJobWriter(sql) {
18646
18681
  jobId: row.id
18647
18682
  });
18648
18683
  } catch (cause) {
18649
- return err(toJobsError(cause, "Job start failed"));
18684
+ return err(toRagError(cause, "Job start failed", "rag_jobs_error"));
18650
18685
  }
18651
18686
  },
18652
18687
  async progress({ jobId, processedChunks, totalChunks, currentDocument }) {
@@ -18685,7 +18720,7 @@ function createSqlJobWriter(sql) {
18685
18720
  },
18686
18721
  async isCancelled({ jobId }) {
18687
18722
  const rows = await sql`
18688
- SELECT id, status FROM stackbone_rag_jobs WHERE id = ${jobId}
18723
+ SELECT status FROM stackbone_rag_jobs WHERE id = ${jobId} LIMIT 1
18689
18724
  `;
18690
18725
  return rows[0]?.status === "cancelled";
18691
18726
  }
@@ -18693,10 +18728,6 @@ function createSqlJobWriter(sql) {
18693
18728
  }
18694
18729
  __name(createSqlJobWriter, "createSqlJobWriter");
18695
18730
  async function ensureCollection(sql, name) {
18696
- const existing = await sql`
18697
- SELECT id FROM stackbone_rag_collections WHERE name = ${name} LIMIT 1
18698
- `;
18699
- if (existing[0]) return existing[0].id;
18700
18731
  const inserted = await sql`
18701
18732
  INSERT INTO stackbone_rag_collections (name) VALUES (${name})
18702
18733
  ON CONFLICT (name) DO UPDATE SET name = EXCLUDED.name
@@ -18704,37 +18735,11 @@ async function ensureCollection(sql, name) {
18704
18735
  `;
18705
18736
  const row = inserted[0];
18706
18737
  if (!row) {
18707
- throw new Error(`stackbone_rag_collections insert returned no row for ${name}`);
18738
+ throw new Error(`stackbone_rag_collections upsert returned no row for ${name}`);
18708
18739
  }
18709
18740
  return row.id;
18710
18741
  }
18711
18742
  __name(ensureCollection, "ensureCollection");
18712
- function toJobsError(cause, message) {
18713
- if (cause instanceof Error) {
18714
- const tagged = cause;
18715
- if (tagged.code === "42P01") {
18716
- return {
18717
- code: "rag_schema_missing",
18718
- message: "RAG tables are not installed \u2014 run `stackbone db migrate add-rag` and `stackbone db migrate up`.",
18719
- cause,
18720
- meta: {
18721
- hint: "run `stackbone db migrate add-rag` and `stackbone db migrate up`"
18722
- }
18723
- };
18724
- }
18725
- return {
18726
- code: tagged.code ?? "rag_jobs_error",
18727
- message: `${message}: ${cause.message}`,
18728
- cause
18729
- };
18730
- }
18731
- return {
18732
- code: "rag_jobs_error",
18733
- message,
18734
- cause
18735
- };
18736
- }
18737
- __name(toJobsError, "toJobsError");
18738
18743
  var PDF_MIME_TYPES = /* @__PURE__ */ new Set([
18739
18744
  "application/pdf",
18740
18745
  "application/x-pdf"
@@ -18794,10 +18799,12 @@ __name(looksLikePdf, "looksLikePdf");
18794
18799
  var DEFAULT_NAMESPACE = "default";
18795
18800
  var META_KEY_DIMENSIONS = "dimensions";
18796
18801
  var META_KEY_DISTANCE = "distance";
18802
+ var schemaVerifiedDimensions = /* @__PURE__ */ new WeakMap();
18797
18803
  async function ensureSchema(sql, dimensions) {
18798
18804
  if (!Number.isInteger(dimensions) || dimensions <= 0 || dimensions > 8192) {
18799
18805
  throw new Error(`rag.ensureSchema: invalid dimensions ${dimensions}. Must be a positive integer <= 8192.`);
18800
18806
  }
18807
+ if (schemaVerifiedDimensions.get(sql) === dimensions) return;
18801
18808
  const existing = await sql`
18802
18809
  SELECT value::int AS value FROM _rag_meta WHERE key = ${META_KEY_DIMENSIONS}
18803
18810
  `.catch(() => []);
@@ -18812,6 +18819,7 @@ async function ensureSchema(sql, dimensions) {
18812
18819
  };
18813
18820
  throw error48;
18814
18821
  }
18822
+ schemaVerifiedDimensions.set(sql, dimensions);
18815
18823
  return;
18816
18824
  }
18817
18825
  await sql.begin(async (tx) => {
@@ -18831,6 +18839,7 @@ async function ensureSchema(sql, dimensions) {
18831
18839
  ON CONFLICT (key) DO NOTHING
18832
18840
  `;
18833
18841
  });
18842
+ schemaVerifiedDimensions.set(sql, dimensions);
18834
18843
  }
18835
18844
  __name(ensureSchema, "ensureSchema");
18836
18845
  async function reset(sql) {
@@ -18838,29 +18847,31 @@ async function reset(sql) {
18838
18847
  await tx`DROP TABLE IF EXISTS rag_chunks`;
18839
18848
  await tx`DROP TABLE IF EXISTS _rag_meta`;
18840
18849
  });
18850
+ schemaVerifiedDimensions.delete(sql);
18841
18851
  }
18842
18852
  __name(reset, "reset");
18843
- async function ingestDocument(sql, docId, namespace, rows) {
18853
+ async function clearDocument(sql, docId, namespace) {
18854
+ await sql`
18855
+ DELETE FROM rag_chunks
18856
+ WHERE namespace = ${namespace} AND doc_id = ${docId}
18857
+ `;
18858
+ }
18859
+ __name(clearDocument, "clearDocument");
18860
+ async function ingestDocument(sql, rows) {
18844
18861
  if (rows.length === 0) return 0;
18845
- await sql.begin(async (tx) => {
18846
- await tx`
18847
- DELETE FROM rag_chunks
18848
- WHERE namespace = ${namespace} AND doc_id = ${docId}
18849
- `;
18850
- const placeholders = rows.map((_, i) => {
18851
- const base = i * 6;
18852
- return `($${base + 1}, $${base + 2}, $${base + 3}, $${base + 4}, $${base + 5}::vector, $${base + 6}::jsonb)`;
18853
- }).join(",");
18854
- const params = rows.flatMap((row) => [
18855
- row.docId,
18856
- row.chunkIdx,
18857
- row.namespace,
18858
- row.content,
18859
- formatVector(row.embedding),
18860
- JSON.stringify(row.metadata)
18861
- ]);
18862
- await tx.unsafe(`INSERT INTO rag_chunks (doc_id, chunk_idx, namespace, content, embedding, metadata) VALUES ${placeholders}`, params);
18863
- });
18862
+ const placeholders = rows.map((_, i) => {
18863
+ const base = i * 6;
18864
+ return `($${base + 1}, $${base + 2}, $${base + 3}, $${base + 4}, $${base + 5}::vector, $${base + 6}::jsonb)`;
18865
+ }).join(",");
18866
+ const params = rows.flatMap((row) => [
18867
+ row.docId,
18868
+ row.chunkIdx,
18869
+ row.namespace,
18870
+ row.content,
18871
+ formatVector(row.embedding),
18872
+ JSON.stringify(row.metadata)
18873
+ ]);
18874
+ await sql.unsafe(`INSERT INTO rag_chunks (doc_id, chunk_idx, namespace, content, embedding, metadata) VALUES ${placeholders}`, params);
18864
18875
  return rows.length;
18865
18876
  }
18866
18877
  __name(ingestDocument, "ingestDocument");
@@ -18930,8 +18941,6 @@ var CHUNK_INDEXES_DDL = `
18930
18941
 
18931
18942
  // src/modules/rag/pipeline.ts
18932
18943
  var DEFAULT_TOP_K = 5;
18933
- var RAG_SCHEMA_MISSING_HINT = "run `stackbone db migrate add-rag` and `stackbone db migrate up`";
18934
- var PG_UNDEFINED_TABLE = "42P01";
18935
18944
  var RagPipeline = class {
18936
18945
  static {
18937
18946
  __name(this, "RagPipeline");
@@ -18996,19 +19005,16 @@ var RagPipeline = class {
18996
19005
  if (started.error) return err(started.error);
18997
19006
  jobId = started.data.jobId;
18998
19007
  }
18999
- const emit = /* @__PURE__ */ __name(async (event) => {
19000
- if (onProgress) await onProgress(event);
19001
- }, "emit");
19002
- const startEvent = {
19008
+ await onProgress?.({
19003
19009
  type: "started",
19004
19010
  jobId: jobId ?? request.id,
19005
19011
  totalChunks
19006
- };
19007
- await emit(startEvent);
19012
+ });
19008
19013
  try {
19009
19014
  await ensureSchema(sql.data, dimensions);
19010
19015
  const needsBatching = Boolean(writer || onProgress);
19011
19016
  const batchSize = this._progressBatchSize ?? (needsBatching ? 1 : rows.length || 1);
19017
+ await clearDocument(sql.data, request.id, namespace);
19012
19018
  let processed = 0;
19013
19019
  for (let offset = 0; offset < rows.length; offset += batchSize) {
19014
19020
  if (writer && jobId) {
@@ -19028,37 +19034,33 @@ var RagPipeline = class {
19028
19034
  }
19029
19035
  }
19030
19036
  const slice = rows.slice(offset, offset + batchSize);
19031
- await ingestDocument(sql.data, request.id, namespace, slice);
19037
+ await ingestDocument(sql.data, slice);
19032
19038
  processed += slice.length;
19033
- const progressEvent = {
19039
+ const currentDocument = {
19040
+ source: request.id,
19041
+ ordinal: processed - 1
19042
+ };
19043
+ await onProgress?.({
19034
19044
  type: "progress",
19035
19045
  jobId: jobId ?? request.id,
19036
19046
  processedChunks: processed,
19037
19047
  totalChunks,
19038
- currentDocument: {
19039
- source: request.id,
19040
- ordinal: processed - 1
19041
- }
19042
- };
19043
- await emit(progressEvent);
19048
+ currentDocument
19049
+ });
19044
19050
  if (writer && jobId) {
19045
19051
  await writer.progress({
19046
19052
  jobId,
19047
19053
  processedChunks: processed,
19048
19054
  totalChunks,
19049
- currentDocument: {
19050
- source: request.id,
19051
- ordinal: processed - 1
19052
- }
19055
+ currentDocument
19053
19056
  });
19054
19057
  }
19055
19058
  }
19056
- const completedEvent = {
19059
+ await onProgress?.({
19057
19060
  type: "completed",
19058
19061
  jobId: jobId ?? request.id,
19059
19062
  totalChunks
19060
- };
19061
- await emit(completedEvent);
19063
+ });
19062
19064
  if (writer && jobId) await writer.complete({
19063
19065
  jobId,
19064
19066
  totalChunks
@@ -19069,12 +19071,11 @@ var RagPipeline = class {
19069
19071
  });
19070
19072
  } catch (cause) {
19071
19073
  const mapped = toRagError(cause, "Ingest failed");
19072
- const failedEvent = {
19074
+ await onProgress?.({
19073
19075
  type: "failed",
19074
19076
  jobId: jobId ?? request.id,
19075
19077
  error: mapped.message
19076
- };
19077
- await emit(failedEvent);
19078
+ });
19078
19079
  if (writer && jobId) await writer.fail({
19079
19080
  jobId,
19080
19081
  error: mapped.message
@@ -19234,37 +19235,6 @@ function validateIngest(request, hasEmbedder) {
19234
19235
  return ok(true);
19235
19236
  }
19236
19237
  __name(validateIngest, "validateIngest");
19237
- function isTaggedError(cause) {
19238
- return cause instanceof Error;
19239
- }
19240
- __name(isTaggedError, "isTaggedError");
19241
- function toRagError(cause, message) {
19242
- if (isTaggedError(cause) && cause.code === PG_UNDEFINED_TABLE) {
19243
- return {
19244
- code: "rag_schema_missing",
19245
- message: `RAG tables are not installed \u2014 ${RAG_SCHEMA_MISSING_HINT}.`,
19246
- cause,
19247
- meta: {
19248
- hint: RAG_SCHEMA_MISSING_HINT
19249
- }
19250
- };
19251
- }
19252
- if (isTaggedError(cause)) {
19253
- const error48 = {
19254
- code: cause.code ?? "rag_error",
19255
- message: `${message}: ${cause.message}`,
19256
- cause
19257
- };
19258
- if (cause.meta) error48.meta = cause.meta;
19259
- return error48;
19260
- }
19261
- return {
19262
- code: "rag_error",
19263
- message,
19264
- cause
19265
- };
19266
- }
19267
- __name(toRagError, "toRagError");
19268
19238
 
19269
19239
  // src/modules/rag/rag.ts
19270
19240
  var DEFAULT_BATCH_SIZE4 = 128;
@@ -19276,10 +19246,14 @@ var RagModule = class {
19276
19246
  _resolved;
19277
19247
  _getAi;
19278
19248
  _gate;
19279
- constructor(_resolved, _getAi, gate) {
19249
+ _testSqlOverride;
19250
+ _testJobWriterFactory;
19251
+ constructor(_resolved, _getAi, gate, testDeps) {
19280
19252
  this._resolved = _resolved;
19281
19253
  this._getAi = _getAi;
19282
19254
  this._gate = gate ?? createModuleGate("rag", _resolved);
19255
+ if (testDeps?.sqlProvider) this._testSqlOverride = testDeps.sqlProvider;
19256
+ if (testDeps?.jobWriterFactory) this._testJobWriterFactory = testDeps.jobWriterFactory;
19283
19257
  }
19284
19258
  async ingest(request) {
19285
19259
  const gateResult = await this._gate();
@@ -19312,7 +19286,8 @@ var RagModule = class {
19312
19286
  if (gateResult.error) return err(gateResult.error);
19313
19287
  const sql = this._testSqlOverride ? this._testSqlOverride() : this.sql();
19314
19288
  if (sql.error) return err(sql.error);
19315
- const writer = this._testJobWriter ?? createSqlJobWriter(sql.data);
19289
+ const writerFactory = this._testJobWriterFactory ?? createSqlJobWriter;
19290
+ const writer = writerFactory(sql.data);
19316
19291
  const channel = createProgressChannel();
19317
19292
  const resolved = resolveIngestModel(request, this._resolved);
19318
19293
  const requestWithHook = {
@@ -19343,7 +19318,7 @@ var RagModule = class {
19343
19318
  return r;
19344
19319
  }).catch((cause) => {
19345
19320
  channel.close();
19346
- return err(toRagError2(cause, "Ingest failed"));
19321
+ return err(toRagError(cause, "Ingest failed"));
19347
19322
  });
19348
19323
  return ok({
19349
19324
  jobId,
@@ -19351,10 +19326,6 @@ var RagModule = class {
19351
19326
  result
19352
19327
  });
19353
19328
  }
19354
- /** Test-only seam — assigned by `ingest-async.spec.ts`. */
19355
- _testJobWriter;
19356
- /** Test-only seam — assigned by `ingest-async.spec.ts`. */
19357
- _testSqlOverride;
19358
19329
  async delete(ids, options) {
19359
19330
  const gateResult = await this._gate();
19360
19331
  if (gateResult.error) return err(gateResult.error);
@@ -19386,7 +19357,7 @@ var RagModule = class {
19386
19357
  await reset(sql.data);
19387
19358
  return ok(void 0);
19388
19359
  } catch (cause) {
19389
- return err(toRagError2(cause, "Reset failed"));
19360
+ return err(toRagError(cause, "Reset failed"));
19390
19361
  }
19391
19362
  }
19392
19363
  /**
@@ -19414,22 +19385,18 @@ var RagModule = class {
19414
19385
  * `Result.err` with the same `database_not_configured` shape `client.database`
19415
19386
  * raises, instead of throwing through the public surface.
19416
19387
  */
19417
- // `_resolved` is reserved for future per-config overrides (e.g. routing
19418
- // RAG queries through a logical replica). The URL itself is owned by the
19419
- // shared handle.
19420
19388
  sql() {
19421
- void this._resolved;
19422
19389
  try {
19423
19390
  return ok(getDatabaseHandle().$client);
19424
19391
  } catch (cause) {
19425
- if (isTaggedError2(cause) && cause.code === "database_not_configured") {
19392
+ if (isTaggedError(cause) && cause.code === "database_not_configured") {
19426
19393
  return err({
19427
19394
  code: "database_not_configured",
19428
19395
  message: cause.message,
19429
19396
  cause
19430
19397
  });
19431
19398
  }
19432
- return err(toRagError2(cause, "Database handle unavailable"));
19399
+ return err(toRagError(cause, "Database handle unavailable"));
19433
19400
  }
19434
19401
  }
19435
19402
  async withPipeline(embedder, run) {
@@ -19550,27 +19517,6 @@ function resolveRetrieveModel(request, resolved) {
19550
19517
  };
19551
19518
  }
19552
19519
  __name(resolveRetrieveModel, "resolveRetrieveModel");
19553
- function isTaggedError2(cause) {
19554
- return cause instanceof Error;
19555
- }
19556
- __name(isTaggedError2, "isTaggedError");
19557
- function toRagError2(cause, message) {
19558
- if (isTaggedError2(cause)) {
19559
- const error48 = {
19560
- code: cause.code ?? "rag_error",
19561
- message: `${message}: ${cause.message}`,
19562
- cause
19563
- };
19564
- if (cause.meta) error48.meta = cause.meta;
19565
- return error48;
19566
- }
19567
- return {
19568
- code: "rag_error",
19569
- message,
19570
- cause
19571
- };
19572
- }
19573
- __name(toRagError2, "toRagError");
19574
19520
  var DEFAULT_SIGNED_URL_TTL_SECONDS = 3600;
19575
19521
  var StorageModule = class {
19576
19522
  static {
@@ -19772,29 +19718,19 @@ var StorageBucket = class {
19772
19718
  return ok(`${base}/${bucket}/${encodeS3Key(fullKey)}`);
19773
19719
  }
19774
19720
  async getSignedUploadUrl(key, options) {
19775
- const gateResult = await this.gate();
19776
- if (gateResult.error) return err(gateResult.error);
19777
- const resolved = this.resolve(key);
19778
- if (resolved.error) return err(resolved.error);
19779
- const { client, bucket, fullKey } = resolved.data;
19780
- const expiresIn = options?.expiresIn ?? DEFAULT_SIGNED_URL_TTL_SECONDS;
19781
- try {
19782
- const url2 = await s3RequestPresigner.getSignedUrl(client, new clientS3.PutObjectCommand({
19783
- Bucket: bucket,
19784
- Key: fullKey,
19785
- ContentType: options?.contentType
19786
- }), {
19787
- expiresIn
19788
- });
19789
- return ok({
19790
- url: url2,
19791
- expiresAt: new Date(Date.now() + expiresIn * 1e3)
19792
- });
19793
- } catch (cause) {
19794
- return err(toStorageError("Signing upload URL failed", cause));
19795
- }
19721
+ return this.signUrl(key, options, "Signing upload URL failed", ({ bucket, fullKey }) => new clientS3.PutObjectCommand({
19722
+ Bucket: bucket,
19723
+ Key: fullKey,
19724
+ ContentType: options?.contentType
19725
+ }));
19796
19726
  }
19797
19727
  async getSignedDownloadUrl(key, options) {
19728
+ return this.signUrl(key, options, "Signing download URL failed", ({ bucket, fullKey }) => new clientS3.GetObjectCommand({
19729
+ Bucket: bucket,
19730
+ Key: fullKey
19731
+ }));
19732
+ }
19733
+ async signUrl(key, options, failureMessage, buildCommand) {
19798
19734
  const gateResult = await this.gate();
19799
19735
  if (gateResult.error) return err(gateResult.error);
19800
19736
  const resolved = this.resolve(key);
@@ -19802,9 +19738,9 @@ var StorageBucket = class {
19802
19738
  const { client, bucket, fullKey } = resolved.data;
19803
19739
  const expiresIn = options?.expiresIn ?? DEFAULT_SIGNED_URL_TTL_SECONDS;
19804
19740
  try {
19805
- const url2 = await s3RequestPresigner.getSignedUrl(client, new clientS3.GetObjectCommand({
19806
- Bucket: bucket,
19807
- Key: fullKey
19741
+ const url2 = await s3RequestPresigner.getSignedUrl(client, buildCommand({
19742
+ bucket,
19743
+ fullKey
19808
19744
  }), {
19809
19745
  expiresIn
19810
19746
  });
@@ -19813,7 +19749,7 @@ var StorageBucket = class {
19813
19749
  expiresAt: new Date(Date.now() + expiresIn * 1e3)
19814
19750
  });
19815
19751
  } catch (cause) {
19816
- return err(toStorageError("Signing download URL failed", cause));
19752
+ return err(toStorageError(failureMessage, cause));
19817
19753
  }
19818
19754
  }
19819
19755
  /**