@ai-matrx/api 0.1.23 → 0.1.25

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 (134) hide show
  1. package/CHANGELOG.md +35 -1
  2. package/dist/account.d.cts +2 -2
  3. package/dist/account.d.ts +2 -2
  4. package/dist/agents.cjs +11 -11
  5. package/dist/agents.d.cts +2 -2
  6. package/dist/agents.d.ts +2 -2
  7. package/dist/agents.js +1 -1
  8. package/dist/ai.cjs +2 -2
  9. package/dist/ai.d.cts +2 -2
  10. package/dist/ai.d.ts +2 -2
  11. package/dist/ai.js +1 -1
  12. package/dist/apps.cjs +5 -5
  13. package/dist/apps.d.cts +2 -2
  14. package/dist/apps.d.ts +2 -2
  15. package/dist/apps.js +1 -1
  16. package/dist/architecture.cjs +93 -41
  17. package/dist/architecture.d.cts +232 -40
  18. package/dist/architecture.d.ts +232 -40
  19. package/dist/architecture.js +72 -29
  20. package/dist/audio.cjs +151 -220
  21. package/dist/audio.d.cts +2 -2
  22. package/dist/audio.d.ts +2 -2
  23. package/dist/audio.js +2 -186
  24. package/dist/chat.cjs +11 -11
  25. package/dist/chat.d.cts +2 -2
  26. package/dist/chat.d.ts +2 -2
  27. package/dist/chat.js +1 -1
  28. package/dist/chunk-3HS6725N.js +186 -0
  29. package/dist/{chunk-ZOZOF5DN.cjs → chunk-HM5A33QV.cjs} +1 -1
  30. package/dist/chunk-HPR4EWCK.cjs +224 -0
  31. package/dist/chunk-OAPV5ZK5.js +1107 -0
  32. package/dist/{chunk-E3PGCGP7.js → chunk-OYD4PTWW.js} +1 -1
  33. package/dist/chunk-PFEPI7C3.js +128 -0
  34. package/dist/chunk-SZMLSYJK.cjs +1334 -0
  35. package/dist/chunk-UOIMSC67.cjs +154 -0
  36. package/dist/code.cjs +6 -6
  37. package/dist/code.d.cts +5 -4
  38. package/dist/code.d.ts +5 -4
  39. package/dist/code.js +1 -1
  40. package/dist/commerce.d.cts +2 -2
  41. package/dist/commerce.d.ts +2 -2
  42. package/dist/communications.cjs +4 -4
  43. package/dist/communications.d.cts +4 -2
  44. package/dist/communications.d.ts +4 -2
  45. package/dist/communications.js +1 -1
  46. package/dist/computer.cjs +4 -4
  47. package/dist/computer.d.cts +2 -2
  48. package/dist/computer.d.ts +2 -2
  49. package/dist/computer.js +1 -1
  50. package/dist/content.cjs +10 -4
  51. package/dist/content.d.cts +14 -3
  52. package/dist/content.d.ts +14 -3
  53. package/dist/content.js +7 -2
  54. package/dist/crm.cjs +2 -2
  55. package/dist/crm.d.cts +2 -2
  56. package/dist/crm.d.ts +2 -2
  57. package/dist/crm.js +1 -1
  58. package/dist/data.cjs +50 -3
  59. package/dist/data.d.cts +199 -3
  60. package/dist/data.d.ts +199 -3
  61. package/dist/data.js +41 -2
  62. package/dist/education.cjs +4 -4
  63. package/dist/education.d.cts +2 -2
  64. package/dist/education.d.ts +2 -2
  65. package/dist/education.js +1 -1
  66. package/dist/files.cjs +907 -1330
  67. package/dist/files.d.cts +2 -2
  68. package/dist/files.d.ts +2 -2
  69. package/dist/files.js +2 -1107
  70. package/dist/human-resources.d.cts +2 -2
  71. package/dist/human-resources.d.ts +2 -2
  72. package/dist/{index-BgjdVvrS.d.cts → index-BluxzzHL.d.cts} +2 -2
  73. package/dist/{index-BgjdVvrS.d.ts → index-BluxzzHL.d.ts} +2 -2
  74. package/dist/index.cjs +63 -67
  75. package/dist/index.d.cts +3 -11
  76. package/dist/index.d.ts +3 -11
  77. package/dist/index.js +8 -12
  78. package/dist/integrations.cjs +51 -5
  79. package/dist/integrations.d.cts +136 -4
  80. package/dist/integrations.d.ts +136 -4
  81. package/dist/integrations.js +42 -4
  82. package/dist/intelligence.cjs +6 -6
  83. package/dist/intelligence.d.cts +2 -2
  84. package/dist/intelligence.d.ts +2 -2
  85. package/dist/intelligence.js +1 -1
  86. package/dist/knowledge.cjs +42 -42
  87. package/dist/knowledge.d.cts +3 -3
  88. package/dist/knowledge.d.ts +3 -3
  89. package/dist/knowledge.js +1 -1
  90. package/dist/legal.cjs +6 -6
  91. package/dist/legal.d.cts +2 -2
  92. package/dist/legal.d.ts +2 -2
  93. package/dist/legal.js +1 -1
  94. package/dist/marketing.cjs +97 -81
  95. package/dist/marketing.d.cts +81 -8
  96. package/dist/marketing.d.ts +81 -8
  97. package/dist/marketing.js +19 -6
  98. package/dist/masterwork.cjs +32 -32
  99. package/dist/masterwork.d.cts +2 -2
  100. package/dist/masterwork.d.ts +2 -2
  101. package/dist/masterwork.js +1 -1
  102. package/dist/media.cjs +11 -11
  103. package/dist/media.d.cts +9 -9
  104. package/dist/media.d.ts +9 -9
  105. package/dist/media.js +1 -1
  106. package/dist/platform.cjs +103 -150
  107. package/dist/platform.d.cts +2 -2
  108. package/dist/platform.d.ts +2 -2
  109. package/dist/platform.js +2 -128
  110. package/dist/publish.cjs +7 -7
  111. package/dist/publish.d.cts +2 -2
  112. package/dist/publish.d.ts +2 -2
  113. package/dist/publish.js +1 -1
  114. package/dist/recording.cjs +278 -0
  115. package/dist/recording.d.cts +44 -0
  116. package/dist/recording.d.ts +44 -0
  117. package/dist/recording.js +275 -0
  118. package/dist/schemas.d.cts +4 -1
  119. package/dist/schemas.d.ts +4 -1
  120. package/dist/stream.cjs +10 -10
  121. package/dist/stream.d.cts +1 -1
  122. package/dist/stream.d.ts +1 -1
  123. package/dist/stream.js +1 -1
  124. package/dist/types.d.cts +735 -32
  125. package/dist/types.d.ts +735 -32
  126. package/dist/web.cjs +26 -26
  127. package/dist/web.d.cts +2 -2
  128. package/dist/web.d.ts +2 -2
  129. package/dist/web.js +1 -1
  130. package/dist/workflows.cjs +32 -14
  131. package/dist/workflows.d.cts +132 -40
  132. package/dist/workflows.d.ts +132 -40
  133. package/dist/workflows.js +18 -3
  134. package/package.json +15 -4
@@ -0,0 +1,278 @@
1
+ 'use strict';
2
+
3
+ var chunkUOIMSC67_cjs = require('./chunk-UOIMSC67.cjs');
4
+ var chunkSZMLSYJK_cjs = require('./chunk-SZMLSYJK.cjs');
5
+ var chunkHPR4EWCK_cjs = require('./chunk-HPR4EWCK.cjs');
6
+ var chunkHM5A33QV_cjs = require('./chunk-HM5A33QV.cjs');
7
+ require('./chunk-2SXAAKGV.cjs');
8
+
9
+ // src/recording.ts
10
+ var MatrxAudioClient = class {
11
+ #api;
12
+ #getAccessToken;
13
+ #getOrganizationId;
14
+ #requestTimeoutMs;
15
+ #journalFolder;
16
+ #fullAudioUploads = /* @__PURE__ */ new Map();
17
+ #organizationToken = null;
18
+ #organizationPromise = null;
19
+ constructor(options) {
20
+ const baseUrl = options.baseUrl.replace(/\/$/, "");
21
+ this.#getAccessToken = options.getAccessToken ?? (() => null);
22
+ this.#getOrganizationId = options.getOrganizationId;
23
+ this.#requestTimeoutMs = options.requestTimeoutMs ?? 3e4;
24
+ this.#journalFolder = options.journalFolder ?? "Transcripts/Browser Audio";
25
+ this.#api = chunkHM5A33QV_cjs.createApi({
26
+ credentials: async () => {
27
+ const accessToken = await this.#getAccessToken();
28
+ return accessToken ? { kind: "user", accessToken } : null;
29
+ },
30
+ // One host-supplied origin answers every deployment.
31
+ resolveBaseUrl: () => baseUrl,
32
+ connectTimeoutMs: this.#requestTimeoutMs,
33
+ totalTimeoutMs: this.#requestTimeoutMs
34
+ });
35
+ }
36
+ async #resolveOrganizationId(token) {
37
+ const supplied = await this.#getOrganizationId?.();
38
+ if (supplied) return supplied;
39
+ if (this.#getOrganizationId) {
40
+ throw new Error(
41
+ "Audio recovery requires an authenticated organization scope."
42
+ );
43
+ }
44
+ if (this.#organizationToken !== token || !this.#organizationPromise) {
45
+ this.#organizationToken = token;
46
+ const organizationPromise = (async () => {
47
+ const identity = await chunkUOIMSC67_cjs.whoami(this.#api);
48
+ if (!identity.authenticated || !identity.organization_id) {
49
+ throw new Error(
50
+ "Audio recovery requires an authenticated organization scope."
51
+ );
52
+ }
53
+ return identity.organization_id;
54
+ })();
55
+ const cachedPromise = organizationPromise.catch((error) => {
56
+ if (this.#organizationPromise === cachedPromise) {
57
+ this.#organizationPromise = null;
58
+ }
59
+ throw error;
60
+ });
61
+ this.#organizationPromise = cachedPromise;
62
+ }
63
+ return this.#organizationPromise;
64
+ }
65
+ /** Per-call options: the organization this signed-in person acts in. */
66
+ async #call(signal) {
67
+ const token = await this.#getAccessToken();
68
+ const options = signal ? { signal } : {};
69
+ if (token) options.organizationId = await this.#resolveOrganizationId(token);
70
+ return options;
71
+ }
72
+ async transcribe(file, signal) {
73
+ const form = new FormData();
74
+ form.append("file", file);
75
+ const result = await chunkHPR4EWCK_cjs.transcribeUpload(
76
+ this.#api,
77
+ { body: form },
78
+ await this.#call(signal)
79
+ );
80
+ return { ...result, text: result.text.trim() };
81
+ }
82
+ async transcribeFull(file, options) {
83
+ const recordingId = options?.recordingId ?? file.name.replace(/\.[^.]+$/, "");
84
+ const uploaded = await this.#upload(
85
+ file,
86
+ `${this.#journalFolder}/${recordingId}--recording.${file.name.split(".").pop() ?? "webm"}`,
87
+ {
88
+ audio_input_stage: "fallback",
89
+ recording_id: recordingId,
90
+ recording_origin: options?.origin,
91
+ ephemeral: false
92
+ }
93
+ );
94
+ this.#fullAudioUploads.set(recordingId, uploaded);
95
+ const result = await chunkHPR4EWCK_cjs.transcribeFile(
96
+ this.#api,
97
+ { body: { file_id: uploaded.file_id } },
98
+ await this.#call(options?.signal)
99
+ );
100
+ return { ...result, text: result.text.trim() };
101
+ }
102
+ async #upload(file, filePath, metadata) {
103
+ const form = new FormData();
104
+ form.append("file", file);
105
+ form.append("file_path", filePath);
106
+ form.append("published_to_web", "false");
107
+ form.append("shown_to", "only_me");
108
+ form.append("visibility", "personal");
109
+ form.append("metadata_json", JSON.stringify({ origin: "transcripts", ...metadata }));
110
+ return chunkSZMLSYJK_cjs.uploadFile(this.#api, { body: form }, await this.#call());
111
+ }
112
+ async journalChunk(input) {
113
+ const index = String(input.chunkIndex).padStart(4, "0");
114
+ const uploaded = await this.#upload(
115
+ input.file,
116
+ `${this.#journalFolder}/${input.recordingId}--chunk-${index}.${input.file.name.split(".").pop() ?? "webm"}`,
117
+ {
118
+ audio_input_stage: "chunk",
119
+ recording_id: input.recordingId,
120
+ chunk_index: input.chunkIndex,
121
+ recording_origin: input.origin,
122
+ ephemeral: true
123
+ }
124
+ );
125
+ try {
126
+ const journal = await chunkHPR4EWCK_cjs.createRecordingJournalChunk(
127
+ this.#api,
128
+ {
129
+ body: {
130
+ recording_id: input.recordingId,
131
+ chunk_index: input.chunkIndex,
132
+ file_id: uploaded.file_id,
133
+ mime_type: input.file.type,
134
+ size_bytes: input.file.size,
135
+ ...input.origin ? { origin: { ...input.origin } } : {}
136
+ }
137
+ },
138
+ await this.#call()
139
+ );
140
+ if (journal.replaced_file_id) {
141
+ await this.#deleteFile(journal.replaced_file_id);
142
+ }
143
+ } catch (error) {
144
+ await this.#deleteFile(uploaded.file_id);
145
+ throw error;
146
+ }
147
+ }
148
+ async finalize(input) {
149
+ const audioResult = this.#fullAudioUploads.get(input.recordingId) ?? await this.#upload(
150
+ input.audio,
151
+ `${this.#journalFolder}/${input.recordingId}--recording.${input.audio.name.split(".").pop() ?? "webm"}`,
152
+ {
153
+ audio_input_stage: "complete",
154
+ recording_id: input.recordingId,
155
+ recording_origin: input.origin,
156
+ ephemeral: false
157
+ }
158
+ );
159
+ const completion = await chunkHPR4EWCK_cjs.completeRecordingJournal(
160
+ this.#api,
161
+ {
162
+ path: { recording_id: input.recordingId },
163
+ body: {
164
+ transcript: input.transcript,
165
+ audio_file_id: audioResult.file_id,
166
+ duration_ms: input.durationMs,
167
+ ...input.origin ? { origin: { ...input.origin } } : {}
168
+ }
169
+ },
170
+ await this.#call()
171
+ );
172
+ const manifest = new File(
173
+ [
174
+ JSON.stringify({
175
+ recording_id: input.recordingId,
176
+ transcript: input.transcript,
177
+ audio_file_id: audioResult.file_id,
178
+ transcript_id: completion.transcript_id,
179
+ origin: input.origin,
180
+ completed_at: (/* @__PURE__ */ new Date()).toISOString()
181
+ })
182
+ ],
183
+ `${input.recordingId}--complete.json`,
184
+ { type: "application/json" }
185
+ );
186
+ await this.#upload(
187
+ manifest,
188
+ `${this.#journalFolder}/${manifest.name}`,
189
+ {
190
+ audio_input_stage: "manifest",
191
+ recording_id: input.recordingId,
192
+ ephemeral: false
193
+ }
194
+ );
195
+ this.#fullAudioUploads.delete(input.recordingId);
196
+ }
197
+ async listRecoverable() {
198
+ if (!await this.#getAccessToken()) return [];
199
+ const recordings = await chunkHPR4EWCK_cjs.getRecordingJournals(
200
+ this.#api,
201
+ void 0,
202
+ await this.#call()
203
+ );
204
+ return recordings.map((recording) => ({
205
+ recordingId: recording.recording_id,
206
+ updatedAt: Date.parse(recording.updated_at)
207
+ }));
208
+ }
209
+ async loadRecoverable(recordingId) {
210
+ const journal = await chunkHPR4EWCK_cjs.getRecordingJournal(
211
+ this.#api,
212
+ { path: { recording_id: recordingId } },
213
+ await this.#call()
214
+ );
215
+ const chunks = [...journal];
216
+ if (chunks.length === 0) return null;
217
+ chunks.sort((a, b) => a.chunk_index - b.chunk_index);
218
+ const parts = [];
219
+ const missingChunkIndices = [];
220
+ const highestIndex = chunks.at(-1)?.chunk_index ?? -1;
221
+ const journaledIndices = new Set(chunks.map((chunk) => chunk.chunk_index));
222
+ for (let index = 0; index <= highestIndex; index += 1) {
223
+ if (!journaledIndices.has(index)) missingChunkIndices.push(index);
224
+ }
225
+ for (const chunk of chunks) {
226
+ let blob;
227
+ try {
228
+ const response = await chunkSZMLSYJK_cjs.downloadFile(
229
+ this.#api,
230
+ { path: { file_id: chunk.file_id }, query: { inline: true } },
231
+ await this.#call()
232
+ );
233
+ blob = await response.blob();
234
+ } catch (error) {
235
+ if (!(error instanceof chunkHM5A33QV_cjs.MatrxApiError)) throw error;
236
+ missingChunkIndices.push(chunk.chunk_index);
237
+ continue;
238
+ }
239
+ if (blob.size === 0) {
240
+ missingChunkIndices.push(chunk.chunk_index);
241
+ continue;
242
+ }
243
+ parts.push(blob);
244
+ }
245
+ if (parts.length === 0) return null;
246
+ return {
247
+ blob: new Blob(parts, { type: chunks[0]?.mime_type || "audio/webm" }),
248
+ missingChunkIndices: [...new Set(missingChunkIndices)].sort((a, b) => a - b)
249
+ };
250
+ }
251
+ async discard(recordingId) {
252
+ const result = await chunkHPR4EWCK_cjs.deleteRecordingJournal(
253
+ this.#api,
254
+ { path: { recording_id: recordingId } },
255
+ await this.#call()
256
+ );
257
+ for (const fileId of result.file_ids) {
258
+ await this.#deleteFile(fileId);
259
+ }
260
+ }
261
+ /** Best-effort cleanup of an orphaned file; a failed delete never masks the real outcome. */
262
+ async #deleteFile(fileId) {
263
+ try {
264
+ await chunkSZMLSYJK_cjs.filesDeleteFile(
265
+ this.#api,
266
+ { path: { file_id: fileId } },
267
+ await this.#call()
268
+ );
269
+ } catch {
270
+ }
271
+ }
272
+ };
273
+ function createMatrxAudioClient(options) {
274
+ return new MatrxAudioClient(options);
275
+ }
276
+
277
+ exports.MatrxAudioClient = MatrxAudioClient;
278
+ exports.createMatrxAudioClient = createMatrxAudioClient;
@@ -0,0 +1,44 @@
1
+ import { TranscriptionTransport, DurableAudioPersistence, TranscriptionResult, RecordingOrigin } from '@ai-matrx/browser-audio/core';
2
+
3
+ interface MatrxAudioClientOptions {
4
+ baseUrl: string;
5
+ getAccessToken?: () => string | null | Promise<string | null>;
6
+ getOrganizationId?: () => string | null | Promise<string | null>;
7
+ requestTimeoutMs?: number;
8
+ journalFolder?: string;
9
+ }
10
+ declare class MatrxAudioClient implements TranscriptionTransport, DurableAudioPersistence {
11
+ #private;
12
+ constructor(options: MatrxAudioClientOptions);
13
+ transcribe(file: File, signal?: AbortSignal): Promise<TranscriptionResult>;
14
+ transcribeFull(file: File, options?: {
15
+ recordingId?: string;
16
+ origin?: RecordingOrigin;
17
+ signal?: AbortSignal;
18
+ }): Promise<TranscriptionResult>;
19
+ journalChunk(input: {
20
+ recordingId: string;
21
+ chunkIndex: number;
22
+ file: File;
23
+ origin?: RecordingOrigin;
24
+ }): Promise<void>;
25
+ finalize(input: {
26
+ recordingId: string;
27
+ audio: File;
28
+ transcript: string;
29
+ durationMs: number;
30
+ origin?: RecordingOrigin;
31
+ }): Promise<void>;
32
+ listRecoverable(): Promise<Array<{
33
+ recordingId: string;
34
+ updatedAt: number;
35
+ }>>;
36
+ loadRecoverable(recordingId: string): Promise<{
37
+ blob: Blob;
38
+ missingChunkIndices: number[];
39
+ } | null>;
40
+ discard(recordingId: string): Promise<void>;
41
+ }
42
+ declare function createMatrxAudioClient(options: MatrxAudioClientOptions): MatrxAudioClient;
43
+
44
+ export { MatrxAudioClient, type MatrxAudioClientOptions, createMatrxAudioClient };
@@ -0,0 +1,44 @@
1
+ import { TranscriptionTransport, DurableAudioPersistence, TranscriptionResult, RecordingOrigin } from '@ai-matrx/browser-audio/core';
2
+
3
+ interface MatrxAudioClientOptions {
4
+ baseUrl: string;
5
+ getAccessToken?: () => string | null | Promise<string | null>;
6
+ getOrganizationId?: () => string | null | Promise<string | null>;
7
+ requestTimeoutMs?: number;
8
+ journalFolder?: string;
9
+ }
10
+ declare class MatrxAudioClient implements TranscriptionTransport, DurableAudioPersistence {
11
+ #private;
12
+ constructor(options: MatrxAudioClientOptions);
13
+ transcribe(file: File, signal?: AbortSignal): Promise<TranscriptionResult>;
14
+ transcribeFull(file: File, options?: {
15
+ recordingId?: string;
16
+ origin?: RecordingOrigin;
17
+ signal?: AbortSignal;
18
+ }): Promise<TranscriptionResult>;
19
+ journalChunk(input: {
20
+ recordingId: string;
21
+ chunkIndex: number;
22
+ file: File;
23
+ origin?: RecordingOrigin;
24
+ }): Promise<void>;
25
+ finalize(input: {
26
+ recordingId: string;
27
+ audio: File;
28
+ transcript: string;
29
+ durationMs: number;
30
+ origin?: RecordingOrigin;
31
+ }): Promise<void>;
32
+ listRecoverable(): Promise<Array<{
33
+ recordingId: string;
34
+ updatedAt: number;
35
+ }>>;
36
+ loadRecoverable(recordingId: string): Promise<{
37
+ blob: Blob;
38
+ missingChunkIndices: number[];
39
+ } | null>;
40
+ discard(recordingId: string): Promise<void>;
41
+ }
42
+ declare function createMatrxAudioClient(options: MatrxAudioClientOptions): MatrxAudioClient;
43
+
44
+ export { MatrxAudioClient, type MatrxAudioClientOptions, createMatrxAudioClient };
@@ -0,0 +1,275 @@
1
+ import { whoami } from './chunk-PFEPI7C3.js';
2
+ import { uploadFile, downloadFile, filesDeleteFile } from './chunk-OAPV5ZK5.js';
3
+ import { transcribeUpload, transcribeFile, createRecordingJournalChunk, completeRecordingJournal, getRecordingJournals, getRecordingJournal, deleteRecordingJournal } from './chunk-3HS6725N.js';
4
+ import { createApi, MatrxApiError } from './chunk-OYD4PTWW.js';
5
+ import './chunk-KIEAFMKB.js';
6
+
7
+ // src/recording.ts
8
+ var MatrxAudioClient = class {
9
+ #api;
10
+ #getAccessToken;
11
+ #getOrganizationId;
12
+ #requestTimeoutMs;
13
+ #journalFolder;
14
+ #fullAudioUploads = /* @__PURE__ */ new Map();
15
+ #organizationToken = null;
16
+ #organizationPromise = null;
17
+ constructor(options) {
18
+ const baseUrl = options.baseUrl.replace(/\/$/, "");
19
+ this.#getAccessToken = options.getAccessToken ?? (() => null);
20
+ this.#getOrganizationId = options.getOrganizationId;
21
+ this.#requestTimeoutMs = options.requestTimeoutMs ?? 3e4;
22
+ this.#journalFolder = options.journalFolder ?? "Transcripts/Browser Audio";
23
+ this.#api = createApi({
24
+ credentials: async () => {
25
+ const accessToken = await this.#getAccessToken();
26
+ return accessToken ? { kind: "user", accessToken } : null;
27
+ },
28
+ // One host-supplied origin answers every deployment.
29
+ resolveBaseUrl: () => baseUrl,
30
+ connectTimeoutMs: this.#requestTimeoutMs,
31
+ totalTimeoutMs: this.#requestTimeoutMs
32
+ });
33
+ }
34
+ async #resolveOrganizationId(token) {
35
+ const supplied = await this.#getOrganizationId?.();
36
+ if (supplied) return supplied;
37
+ if (this.#getOrganizationId) {
38
+ throw new Error(
39
+ "Audio recovery requires an authenticated organization scope."
40
+ );
41
+ }
42
+ if (this.#organizationToken !== token || !this.#organizationPromise) {
43
+ this.#organizationToken = token;
44
+ const organizationPromise = (async () => {
45
+ const identity = await whoami(this.#api);
46
+ if (!identity.authenticated || !identity.organization_id) {
47
+ throw new Error(
48
+ "Audio recovery requires an authenticated organization scope."
49
+ );
50
+ }
51
+ return identity.organization_id;
52
+ })();
53
+ const cachedPromise = organizationPromise.catch((error) => {
54
+ if (this.#organizationPromise === cachedPromise) {
55
+ this.#organizationPromise = null;
56
+ }
57
+ throw error;
58
+ });
59
+ this.#organizationPromise = cachedPromise;
60
+ }
61
+ return this.#organizationPromise;
62
+ }
63
+ /** Per-call options: the organization this signed-in person acts in. */
64
+ async #call(signal) {
65
+ const token = await this.#getAccessToken();
66
+ const options = signal ? { signal } : {};
67
+ if (token) options.organizationId = await this.#resolveOrganizationId(token);
68
+ return options;
69
+ }
70
+ async transcribe(file, signal) {
71
+ const form = new FormData();
72
+ form.append("file", file);
73
+ const result = await transcribeUpload(
74
+ this.#api,
75
+ { body: form },
76
+ await this.#call(signal)
77
+ );
78
+ return { ...result, text: result.text.trim() };
79
+ }
80
+ async transcribeFull(file, options) {
81
+ const recordingId = options?.recordingId ?? file.name.replace(/\.[^.]+$/, "");
82
+ const uploaded = await this.#upload(
83
+ file,
84
+ `${this.#journalFolder}/${recordingId}--recording.${file.name.split(".").pop() ?? "webm"}`,
85
+ {
86
+ audio_input_stage: "fallback",
87
+ recording_id: recordingId,
88
+ recording_origin: options?.origin,
89
+ ephemeral: false
90
+ }
91
+ );
92
+ this.#fullAudioUploads.set(recordingId, uploaded);
93
+ const result = await transcribeFile(
94
+ this.#api,
95
+ { body: { file_id: uploaded.file_id } },
96
+ await this.#call(options?.signal)
97
+ );
98
+ return { ...result, text: result.text.trim() };
99
+ }
100
+ async #upload(file, filePath, metadata) {
101
+ const form = new FormData();
102
+ form.append("file", file);
103
+ form.append("file_path", filePath);
104
+ form.append("published_to_web", "false");
105
+ form.append("shown_to", "only_me");
106
+ form.append("visibility", "personal");
107
+ form.append("metadata_json", JSON.stringify({ origin: "transcripts", ...metadata }));
108
+ return uploadFile(this.#api, { body: form }, await this.#call());
109
+ }
110
+ async journalChunk(input) {
111
+ const index = String(input.chunkIndex).padStart(4, "0");
112
+ const uploaded = await this.#upload(
113
+ input.file,
114
+ `${this.#journalFolder}/${input.recordingId}--chunk-${index}.${input.file.name.split(".").pop() ?? "webm"}`,
115
+ {
116
+ audio_input_stage: "chunk",
117
+ recording_id: input.recordingId,
118
+ chunk_index: input.chunkIndex,
119
+ recording_origin: input.origin,
120
+ ephemeral: true
121
+ }
122
+ );
123
+ try {
124
+ const journal = await createRecordingJournalChunk(
125
+ this.#api,
126
+ {
127
+ body: {
128
+ recording_id: input.recordingId,
129
+ chunk_index: input.chunkIndex,
130
+ file_id: uploaded.file_id,
131
+ mime_type: input.file.type,
132
+ size_bytes: input.file.size,
133
+ ...input.origin ? { origin: { ...input.origin } } : {}
134
+ }
135
+ },
136
+ await this.#call()
137
+ );
138
+ if (journal.replaced_file_id) {
139
+ await this.#deleteFile(journal.replaced_file_id);
140
+ }
141
+ } catch (error) {
142
+ await this.#deleteFile(uploaded.file_id);
143
+ throw error;
144
+ }
145
+ }
146
+ async finalize(input) {
147
+ const audioResult = this.#fullAudioUploads.get(input.recordingId) ?? await this.#upload(
148
+ input.audio,
149
+ `${this.#journalFolder}/${input.recordingId}--recording.${input.audio.name.split(".").pop() ?? "webm"}`,
150
+ {
151
+ audio_input_stage: "complete",
152
+ recording_id: input.recordingId,
153
+ recording_origin: input.origin,
154
+ ephemeral: false
155
+ }
156
+ );
157
+ const completion = await completeRecordingJournal(
158
+ this.#api,
159
+ {
160
+ path: { recording_id: input.recordingId },
161
+ body: {
162
+ transcript: input.transcript,
163
+ audio_file_id: audioResult.file_id,
164
+ duration_ms: input.durationMs,
165
+ ...input.origin ? { origin: { ...input.origin } } : {}
166
+ }
167
+ },
168
+ await this.#call()
169
+ );
170
+ const manifest = new File(
171
+ [
172
+ JSON.stringify({
173
+ recording_id: input.recordingId,
174
+ transcript: input.transcript,
175
+ audio_file_id: audioResult.file_id,
176
+ transcript_id: completion.transcript_id,
177
+ origin: input.origin,
178
+ completed_at: (/* @__PURE__ */ new Date()).toISOString()
179
+ })
180
+ ],
181
+ `${input.recordingId}--complete.json`,
182
+ { type: "application/json" }
183
+ );
184
+ await this.#upload(
185
+ manifest,
186
+ `${this.#journalFolder}/${manifest.name}`,
187
+ {
188
+ audio_input_stage: "manifest",
189
+ recording_id: input.recordingId,
190
+ ephemeral: false
191
+ }
192
+ );
193
+ this.#fullAudioUploads.delete(input.recordingId);
194
+ }
195
+ async listRecoverable() {
196
+ if (!await this.#getAccessToken()) return [];
197
+ const recordings = await getRecordingJournals(
198
+ this.#api,
199
+ void 0,
200
+ await this.#call()
201
+ );
202
+ return recordings.map((recording) => ({
203
+ recordingId: recording.recording_id,
204
+ updatedAt: Date.parse(recording.updated_at)
205
+ }));
206
+ }
207
+ async loadRecoverable(recordingId) {
208
+ const journal = await getRecordingJournal(
209
+ this.#api,
210
+ { path: { recording_id: recordingId } },
211
+ await this.#call()
212
+ );
213
+ const chunks = [...journal];
214
+ if (chunks.length === 0) return null;
215
+ chunks.sort((a, b) => a.chunk_index - b.chunk_index);
216
+ const parts = [];
217
+ const missingChunkIndices = [];
218
+ const highestIndex = chunks.at(-1)?.chunk_index ?? -1;
219
+ const journaledIndices = new Set(chunks.map((chunk) => chunk.chunk_index));
220
+ for (let index = 0; index <= highestIndex; index += 1) {
221
+ if (!journaledIndices.has(index)) missingChunkIndices.push(index);
222
+ }
223
+ for (const chunk of chunks) {
224
+ let blob;
225
+ try {
226
+ const response = await downloadFile(
227
+ this.#api,
228
+ { path: { file_id: chunk.file_id }, query: { inline: true } },
229
+ await this.#call()
230
+ );
231
+ blob = await response.blob();
232
+ } catch (error) {
233
+ if (!(error instanceof MatrxApiError)) throw error;
234
+ missingChunkIndices.push(chunk.chunk_index);
235
+ continue;
236
+ }
237
+ if (blob.size === 0) {
238
+ missingChunkIndices.push(chunk.chunk_index);
239
+ continue;
240
+ }
241
+ parts.push(blob);
242
+ }
243
+ if (parts.length === 0) return null;
244
+ return {
245
+ blob: new Blob(parts, { type: chunks[0]?.mime_type || "audio/webm" }),
246
+ missingChunkIndices: [...new Set(missingChunkIndices)].sort((a, b) => a - b)
247
+ };
248
+ }
249
+ async discard(recordingId) {
250
+ const result = await deleteRecordingJournal(
251
+ this.#api,
252
+ { path: { recording_id: recordingId } },
253
+ await this.#call()
254
+ );
255
+ for (const fileId of result.file_ids) {
256
+ await this.#deleteFile(fileId);
257
+ }
258
+ }
259
+ /** Best-effort cleanup of an orphaned file; a failed delete never masks the real outcome. */
260
+ async #deleteFile(fileId) {
261
+ try {
262
+ await filesDeleteFile(
263
+ this.#api,
264
+ { path: { file_id: fileId } },
265
+ await this.#call()
266
+ );
267
+ } catch {
268
+ }
269
+ }
270
+ };
271
+ function createMatrxAudioClient(options) {
272
+ return new MatrxAudioClient(options);
273
+ }
274
+
275
+ export { MatrxAudioClient, createMatrxAudioClient };
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * GENERATED by @ai-matrx/api scripts/generate.mjs from aidream/api-contract — never edit by hand.
3
- * CONTRACT_SHA256 a7cc7154fd90de65bc0e3e819210f0337696cb50814b5a366e64ecb1b00412e4
3
+ * CONTRACT_SHA256 118778e288a723f4114c0f189d3f0d25d8f399fdb49d9bbac475b5fcb9d808f6
4
4
  */
5
5
  /** Every schema reached from more than one domain (119). Types only — importing this costs nothing at runtime. */
6
6
  /** ActionNeeded */
@@ -896,6 +896,8 @@ type SandboxBindingRequest = {
896
896
  access_token: string;
897
897
  /** Workspace root inside the sandbox */
898
898
  root_path?: string;
899
+ /** local_machine: the computer's app_instances id (who the binding reaches), carried, never parsed from base_url. */
900
+ device_id?: string | null;
899
901
  /** Semantic filesystem namespace. This is explicit so routing never guesses the target OS or machine kind from path syntax. */
900
902
  target_kind?: "sandbox" | "local_machine";
901
903
  };
@@ -1219,6 +1221,7 @@ type UserOverrides = {
1219
1221
  remove?: string[];
1220
1222
  apply_policy?: ("auto" | "ask" | "off") | null;
1221
1223
  auto_tools?: boolean | null;
1224
+ search_types?: string[];
1222
1225
  };
1223
1226
  /** UserVideoMediaPart */
1224
1227
  type UserVideoMediaPart = {
package/dist/schemas.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * GENERATED by @ai-matrx/api scripts/generate.mjs from aidream/api-contract — never edit by hand.
3
- * CONTRACT_SHA256 a7cc7154fd90de65bc0e3e819210f0337696cb50814b5a366e64ecb1b00412e4
3
+ * CONTRACT_SHA256 118778e288a723f4114c0f189d3f0d25d8f399fdb49d9bbac475b5fcb9d808f6
4
4
  */
5
5
  /** Every schema reached from more than one domain (119). Types only — importing this costs nothing at runtime. */
6
6
  /** ActionNeeded */
@@ -896,6 +896,8 @@ type SandboxBindingRequest = {
896
896
  access_token: string;
897
897
  /** Workspace root inside the sandbox */
898
898
  root_path?: string;
899
+ /** local_machine: the computer's app_instances id (who the binding reaches), carried, never parsed from base_url. */
900
+ device_id?: string | null;
899
901
  /** Semantic filesystem namespace. This is explicit so routing never guesses the target OS or machine kind from path syntax. */
900
902
  target_kind?: "sandbox" | "local_machine";
901
903
  };
@@ -1219,6 +1221,7 @@ type UserOverrides = {
1219
1221
  remove?: string[];
1220
1222
  apply_policy?: ("auto" | "ask" | "off") | null;
1221
1223
  auto_tools?: boolean | null;
1224
+ search_types?: string[];
1222
1225
  };
1223
1226
  /** UserVideoMediaPart */
1224
1227
  type UserVideoMediaPart = {