@absolutejs/voice 0.0.22-beta.422 → 0.0.22-beta.424

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/audit.d.ts CHANGED
@@ -34,6 +34,7 @@ export type VoiceAuditEventFilter = {
34
34
  beforeOrAt?: number;
35
35
  limit?: number;
36
36
  outcome?: VoiceAuditOutcome | VoiceAuditOutcome[];
37
+ readWindow?: 'recent';
37
38
  resourceId?: string;
38
39
  resourceType?: string;
39
40
  sessionId?: string;
package/dist/index.js CHANGED
@@ -28724,7 +28724,15 @@ var createVoicePhoneAgent = (options) => {
28724
28724
  };
28725
28725
  };
28726
28726
  // src/fileStore.ts
28727
- import { mkdir as mkdir3, readFile, readdir, rename, rm, writeFile } from "fs/promises";
28727
+ import {
28728
+ mkdir as mkdir3,
28729
+ readFile,
28730
+ readdir,
28731
+ rename,
28732
+ rm,
28733
+ stat,
28734
+ writeFile
28735
+ } from "fs/promises";
28728
28736
  import { join as join2 } from "path";
28729
28737
  var listJsonFiles = async (directory) => {
28730
28738
  try {
@@ -28739,6 +28747,74 @@ var listJsonFiles = async (directory) => {
28739
28747
  throw error;
28740
28748
  }
28741
28749
  };
28750
+ var listRecentJsonFiles = async (directory, limit) => {
28751
+ if (limit === 0) {
28752
+ return [];
28753
+ }
28754
+ const indexedFiles = await readRecentJsonFileIndex(directory);
28755
+ if (indexedFiles.length >= limit) {
28756
+ return indexedFiles.slice(0, limit).map((entry) => entry.path);
28757
+ }
28758
+ return (await rebuildRecentJsonFileIndex(directory)).slice(0, limit).map((entry) => entry.path);
28759
+ };
28760
+ var recentJsonFileIndexPath = (directory) => join2(directory, ".recent-index");
28761
+ var sortRecentJsonFileIndexEntries = (entries) => entries.sort((left, right) => right.updatedAt - left.updatedAt);
28762
+ var readRecentJsonFileIndex = async (directory) => {
28763
+ try {
28764
+ const payload = await readJsonFile(recentJsonFileIndexPath(directory)) ?? { files: [] };
28765
+ return sortRecentJsonFileIndexEntries(Array.isArray(payload.files) ? payload.files : []);
28766
+ } catch (error) {
28767
+ if (error.code === "ENOENT") {
28768
+ return [];
28769
+ }
28770
+ throw error;
28771
+ }
28772
+ };
28773
+ var writeRecentJsonFileIndex = async (directory, files) => {
28774
+ await mkdir3(directory, {
28775
+ recursive: true
28776
+ });
28777
+ await writeFile(recentJsonFileIndexPath(directory), JSON.stringify({
28778
+ files: sortRecentJsonFileIndexEntries(files).slice(0, 5000),
28779
+ version: 1
28780
+ }));
28781
+ };
28782
+ var rebuildRecentJsonFileIndex = async (directory) => {
28783
+ const files = await listJsonFiles(directory);
28784
+ const candidates = await Promise.all(files.map(async (path) => {
28785
+ try {
28786
+ return {
28787
+ path,
28788
+ updatedAt: (await stat(path)).mtimeMs
28789
+ };
28790
+ } catch (error) {
28791
+ if (error.code === "ENOENT") {
28792
+ return;
28793
+ }
28794
+ throw error;
28795
+ }
28796
+ }));
28797
+ const entries = sortRecentJsonFileIndexEntries(candidates.filter((candidate) => Boolean(candidate)));
28798
+ await writeRecentJsonFileIndex(directory, entries);
28799
+ return entries;
28800
+ };
28801
+ var updateRecentJsonFileIndex = async (directory, path) => {
28802
+ const files = (await readRecentJsonFileIndex(directory)).filter((entry) => entry.path !== path);
28803
+ files.push({
28804
+ path,
28805
+ updatedAt: Date.now()
28806
+ });
28807
+ await writeRecentJsonFileIndex(directory, files);
28808
+ };
28809
+ var removeRecentJsonFileIndexEntry = async (directory, path) => {
28810
+ const files = (await readRecentJsonFileIndex(directory)).filter((entry) => entry.path !== path);
28811
+ await writeRecentJsonFileIndex(directory, files);
28812
+ };
28813
+ var shouldUseRecentReadWindow = (filter) => filter.readWindow === "recent" && typeof filter.limit === "number" && filter.limit >= 0;
28814
+ var omitReadWindow = (filter) => {
28815
+ const { readWindow: _readWindow, ...next } = filter;
28816
+ return next;
28817
+ };
28742
28818
  var encodeStoreId = (id) => `${encodeURIComponent(id)}.json`;
28743
28819
  var resolveFilePath = (directory, id) => join2(directory, encodeStoreId(id));
28744
28820
  var createMemoryStoreId = (input) => `${input.assistantId}:${input.namespace}:${input.key}`;
@@ -28932,7 +29008,9 @@ var createVoiceFileExternalObjectMapStore = (options) => {
28932
29008
  var createVoiceFileTraceEventStore = (options) => {
28933
29009
  const append = async (event) => {
28934
29010
  const stored = createVoiceTraceEvent(event);
28935
- await writeJsonFile(resolveFilePath(options.directory, stored.id), stored, options);
29011
+ const path = resolveFilePath(options.directory, stored.id);
29012
+ await writeJsonFile(path, stored, options);
29013
+ await updateRecentJsonFileIndex(options.directory, path);
28936
29014
  return stored;
28937
29015
  };
28938
29016
  const get = async (id) => {
@@ -28947,14 +29025,16 @@ var createVoiceFileTraceEventStore = (options) => {
28947
29025
  }
28948
29026
  };
28949
29027
  const list = async (filter = {}) => {
28950
- const files = await listJsonFiles(options.directory);
29028
+ const files = shouldUseRecentReadWindow(filter) ? await listRecentJsonFiles(options.directory, filter.limit) : await listJsonFiles(options.directory);
28951
29029
  const events = await Promise.all(files.map((file) => readJsonFile(file)));
28952
- return filterVoiceTraceEvents(events, filter);
29030
+ return filterVoiceTraceEvents(events, omitReadWindow(filter));
28953
29031
  };
28954
29032
  const remove = async (id) => {
28955
- await rm(resolveFilePath(options.directory, id), {
29033
+ const path = resolveFilePath(options.directory, id);
29034
+ await rm(path, {
28956
29035
  force: true
28957
29036
  });
29037
+ await removeRecentJsonFileIndexEntry(options.directory, path);
28958
29038
  };
28959
29039
  return { append, get, list, remove };
28960
29040
  };
@@ -29002,13 +29082,16 @@ var createVoiceFileAuditEventStore = (options) => {
29002
29082
  };
29003
29083
  const append = async (event) => {
29004
29084
  const stored = createVoiceAuditEvent(event);
29005
- await writeJsonFile(resolveFilePath(options.directory, stored.id), stored, options);
29085
+ const path = resolveFilePath(options.directory, stored.id);
29086
+ await writeJsonFile(path, stored, options);
29087
+ await updateRecentJsonFileIndex(options.directory, path);
29006
29088
  return stored;
29007
29089
  };
29008
29090
  const list = async (filter) => {
29009
- const files = await listJsonFiles(options.directory);
29091
+ const resolvedFilter = filter ?? {};
29092
+ const files = shouldUseRecentReadWindow(resolvedFilter) ? await listRecentJsonFiles(options.directory, resolvedFilter.limit) : await listJsonFiles(options.directory);
29010
29093
  const events = await Promise.all(files.map((file) => readJsonFile(file)));
29011
- return filterVoiceAuditEvents(events, filter);
29094
+ return filterVoiceAuditEvents(events, omitReadWindow(resolvedFilter));
29012
29095
  };
29013
29096
  return { append, get, list };
29014
29097
  };
@@ -32162,7 +32245,7 @@ var createVoiceOpsRecoveryRoutes = (options = {}) => {
32162
32245
  import { Elysia as Elysia55 } from "elysia";
32163
32246
  import { Database as Database4 } from "bun:sqlite";
32164
32247
  import { createHash } from "crypto";
32165
- import { mkdir as mkdir4, readFile as readFile2, stat, unlink } from "fs/promises";
32248
+ import { mkdir as mkdir4, readFile as readFile2, stat as stat2, unlink } from "fs/promises";
32166
32249
  import { join as join3 } from "path";
32167
32250
  var voiceObservabilityExportSchemaVersion = "1.0.0";
32168
32251
  var voiceObservabilityExportSchemaId = "com.absolutejs.voice.observability-export";
@@ -33097,7 +33180,7 @@ var verifyArtifact = async (artifact, options) => {
33097
33180
  }
33098
33181
  const filePath = stripArtifactPathAnchor(artifact.path);
33099
33182
  try {
33100
- const file = await stat(filePath);
33183
+ const file = await stat2(filePath);
33101
33184
  const generatedAt = artifact.generatedAt ?? file.mtimeMs;
33102
33185
  const generatedAtMs = toEpochMs(generatedAt);
33103
33186
  const ageMs = generatedAtMs === undefined ? undefined : now - generatedAtMs;
package/dist/trace.d.ts CHANGED
@@ -16,6 +16,7 @@ export type StoredVoiceTraceEvent<TPayload extends Record<string, unknown> = Rec
16
16
  };
17
17
  export type VoiceTraceEventFilter = {
18
18
  limit?: number;
19
+ readWindow?: 'recent';
19
20
  scenarioId?: string;
20
21
  sessionId?: string;
21
22
  traceId?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.422",
3
+ "version": "0.0.22-beta.424",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",