@usewhisper/sdk 3.0.0 → 3.1.0

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/README.md CHANGED
@@ -14,7 +14,7 @@ npm install @usewhisper/sdk
14
14
  import { WhisperContext } from '@usewhisper/sdk';
15
15
 
16
16
  const whisper = new WhisperContext({
17
- apiKey: 'wsk_your_api_key_here'
17
+ apiKey: 'wsk_your_api_key_here'
18
18
  });
19
19
 
20
20
  // Create a project
@@ -48,7 +48,7 @@ Get your API key from the [Whisper dashboard](https://usewhisper.dev/dashboard):
48
48
 
49
49
  ```typescript
50
50
  const whisper = new WhisperContext({
51
- apiKey: 'wsk_...', // Your API key
51
+ apiKey: 'wsk_...', // Your API key
52
52
  baseUrl: 'https://context.usewhisper.dev' // Optional, defaults to production
53
53
  });
54
54
  ```
package/index.d.mts CHANGED
@@ -324,6 +324,7 @@ declare class RuntimeClient {
324
324
  private readonly timeouts;
325
325
  private readonly diagnostics;
326
326
  private readonly inFlight;
327
+ private readonly sendApiKeyHeader;
327
328
  constructor(options: RuntimeClientOptions, diagnostics?: DiagnosticsStore);
328
329
  getDiagnosticsStore(): DiagnosticsStore;
329
330
  getCompatMode(): CompatMode;
@@ -332,6 +333,8 @@ declare class RuntimeClient {
332
333
  private shouldRetryStatus;
333
334
  private backoff;
334
335
  private runtimeName;
336
+ private apiKeyOnlyPrefixes;
337
+ private shouldAttachApiKeyHeader;
335
338
  private createRequestFingerprint;
336
339
  request<T>(options: RuntimeRequestOptions): Promise<RuntimeResponse<T>>;
337
340
  private performRequest;
@@ -496,6 +499,9 @@ declare class MemoryModule {
496
499
  memories: Array<Record<string, unknown>>;
497
500
  count: number;
498
501
  }>;
502
+ get(memoryId: string): Promise<{
503
+ memory: Record<string, unknown>;
504
+ }>;
499
505
  update(memoryId: string, params: {
500
506
  content: string;
501
507
  reasoning?: string;
@@ -654,6 +660,9 @@ declare class WhisperClient {
654
660
  add: (params: Parameters<MemoryModule["add"]>[0]) => Promise<MemoryWriteAck$1>;
655
661
  addBulk: (params: Parameters<MemoryModule["addBulk"]>[0]) => Promise<MemoryWriteAck$1>;
656
662
  search: (params: Parameters<MemoryModule["search"]>[0]) => Promise<MemorySearchResponse$1>;
663
+ get: (memoryId: string) => Promise<{
664
+ memory: Record<string, unknown>;
665
+ }>;
657
666
  getUserProfile: (params: Parameters<MemoryModule["getUserProfile"]>[0]) => ReturnType<MemoryModule["getUserProfile"]>;
658
667
  getSessionMemories: (params: Parameters<MemoryModule["getSessionMemories"]>[0]) => ReturnType<MemoryModule["getSessionMemories"]>;
659
668
  update: (memoryId: string, params: {
@@ -996,6 +1005,62 @@ interface Source {
996
1005
  createdAt: string;
997
1006
  updatedAt: string;
998
1007
  }
1008
+ interface VideoSourceMetadata {
1009
+ source_kind: "video";
1010
+ video_url: string;
1011
+ platform: "youtube" | "loom" | "generic";
1012
+ duration_seconds?: number;
1013
+ published_at?: string;
1014
+ channel_or_author?: string;
1015
+ }
1016
+ interface VideoIngestionStatus {
1017
+ source_id: string;
1018
+ status: string;
1019
+ stage: "extracting" | "transcribing" | "segmenting" | "enriching" | "indexing" | "completed" | "failed";
1020
+ sync_job_id?: string | null;
1021
+ progress?: {
1022
+ current: number;
1023
+ total: number;
1024
+ message: string;
1025
+ } | null;
1026
+ duration_seconds?: number | null;
1027
+ chunks_indexed?: number | null;
1028
+ decisions_detected?: number | null;
1029
+ entities_extracted?: string[];
1030
+ last_error?: string | null;
1031
+ updated_at?: string;
1032
+ }
1033
+ type CanonicalSourceType = "github" | "web" | "pdf" | "local" | "slack";
1034
+ interface CanonicalSourceCreateParams {
1035
+ type: CanonicalSourceType;
1036
+ name?: string;
1037
+ auto_index?: boolean;
1038
+ metadata?: Record<string, string>;
1039
+ owner?: string;
1040
+ repo?: string;
1041
+ branch?: string;
1042
+ paths?: string[];
1043
+ url?: string;
1044
+ crawl_depth?: number;
1045
+ include_paths?: string[];
1046
+ exclude_paths?: string[];
1047
+ file_path?: string;
1048
+ path?: string;
1049
+ glob?: string;
1050
+ max_files?: number;
1051
+ workspace_id?: string;
1052
+ channel_ids?: string[];
1053
+ since?: string;
1054
+ token?: string;
1055
+ auth_ref?: string;
1056
+ }
1057
+ interface CanonicalSourceCreateResult {
1058
+ source_id: string;
1059
+ status: "queued" | "indexing" | "ready" | "failed";
1060
+ job_id: string | null;
1061
+ index_started: boolean;
1062
+ warnings: string[];
1063
+ }
999
1064
  interface Memory {
1000
1065
  id: string;
1001
1066
  projectId: string;
@@ -1139,6 +1204,23 @@ declare class WhisperContext {
1139
1204
  sync_schedule?: string;
1140
1205
  }): Promise<Source>;
1141
1206
  syncSource(sourceId: string): Promise<any>;
1207
+ addSourceByType(projectId: string, params: {
1208
+ type: "video";
1209
+ url: string;
1210
+ auto_sync?: boolean;
1211
+ tags?: string[];
1212
+ platform?: "youtube" | "loom" | "generic";
1213
+ language?: string;
1214
+ allow_stt_fallback?: boolean;
1215
+ max_duration_minutes?: number;
1216
+ name?: string;
1217
+ }): Promise<{
1218
+ source_id: string;
1219
+ sync_job_id?: string | null;
1220
+ status: "processing" | "queued" | "created";
1221
+ }>;
1222
+ getSourceStatus(sourceId: string): Promise<VideoIngestionStatus>;
1223
+ createCanonicalSource(project: string, params: CanonicalSourceCreateParams): Promise<CanonicalSourceCreateResult>;
1142
1224
  ingest(projectId: string, documents: Array<{
1143
1225
  id?: string;
1144
1226
  title: string;
@@ -1299,6 +1381,9 @@ declare class WhisperContext {
1299
1381
  memories: any[];
1300
1382
  count: number;
1301
1383
  }>;
1384
+ getMemory(memoryId: string): Promise<{
1385
+ memory: any;
1386
+ }>;
1302
1387
  getMemoryVersions(memoryId: string): Promise<{
1303
1388
  memory_id: string;
1304
1389
  versions: any[];
@@ -1539,8 +1624,25 @@ declare class WhisperContext {
1539
1624
  config: Record<string, any>;
1540
1625
  sync_schedule?: string;
1541
1626
  }) => Promise<Source>;
1627
+ addSource: (projectId: string, params: {
1628
+ type: "video";
1629
+ url: string;
1630
+ auto_sync?: boolean;
1631
+ tags?: string[];
1632
+ platform?: "youtube" | "loom" | "generic";
1633
+ language?: string;
1634
+ allow_stt_fallback?: boolean;
1635
+ max_duration_minutes?: number;
1636
+ name?: string;
1637
+ }) => Promise<{
1638
+ source_id: string;
1639
+ sync_job_id?: string | null;
1640
+ status: "processing" | "queued" | "created";
1641
+ }>;
1542
1642
  sync: (sourceId: string) => Promise<any>;
1543
1643
  syncSource: (sourceId: string) => Promise<any>;
1644
+ status: (sourceId: string) => Promise<VideoIngestionStatus>;
1645
+ getStatus: (sourceId: string) => Promise<VideoIngestionStatus>;
1544
1646
  };
1545
1647
  readonly memory: {
1546
1648
  add: (params: Parameters<WhisperContext["addMemory"]>[0]) => Promise<{
@@ -1574,6 +1676,9 @@ declare class WhisperContext {
1574
1676
  memories: any[];
1575
1677
  count: number;
1576
1678
  }>;
1679
+ get: (memoryId: string) => Promise<{
1680
+ memory: any;
1681
+ }>;
1577
1682
  getVersions: (memoryId: string) => Promise<{
1578
1683
  memory_id: string;
1579
1684
  versions: any[];
@@ -1679,4 +1784,4 @@ declare class WhisperContext {
1679
1784
  };
1680
1785
  }
1681
1786
 
1682
- export { type ExtractedMemory, LangChainMemoryAdapter, LangGraphCheckpointAdapter, type Memory, type MemoryExtractionResult, type MemoryKind, type MemoryLatencyBreakdown, type MemorySearchResponse, type MemoryWriteAck, type Project, type QueryParams, type QueryResult, type Source, Whisper, WhisperAgentMiddleware, WhisperClient, type WhisperConfig, WhisperContext, Whisper as WhisperDefault, WhisperError, type WhisperErrorCode, WhisperClient as WhisperRuntimeClient, createAgentMiddleware, createLangChainMemoryAdapter, createLangGraphCheckpointAdapter, WhisperContext as default, memoryGraphToMermaid };
1787
+ export { type CanonicalSourceCreateParams, type CanonicalSourceCreateResult, type CanonicalSourceType, type ExtractedMemory, LangChainMemoryAdapter, LangGraphCheckpointAdapter, type Memory, type MemoryExtractionResult, type MemoryKind, type MemoryLatencyBreakdown, type MemorySearchResponse, type MemoryWriteAck, type Project, type QueryParams, type QueryResult, type Source, type VideoIngestionStatus, type VideoSourceMetadata, Whisper, WhisperAgentMiddleware, WhisperClient, type WhisperConfig, WhisperContext, Whisper as WhisperDefault, WhisperError, type WhisperErrorCode, WhisperClient as WhisperRuntimeClient, createAgentMiddleware, createLangChainMemoryAdapter, createLangGraphCheckpointAdapter, WhisperContext as default, memoryGraphToMermaid };
package/index.d.ts CHANGED
@@ -324,6 +324,7 @@ declare class RuntimeClient {
324
324
  private readonly timeouts;
325
325
  private readonly diagnostics;
326
326
  private readonly inFlight;
327
+ private readonly sendApiKeyHeader;
327
328
  constructor(options: RuntimeClientOptions, diagnostics?: DiagnosticsStore);
328
329
  getDiagnosticsStore(): DiagnosticsStore;
329
330
  getCompatMode(): CompatMode;
@@ -332,6 +333,8 @@ declare class RuntimeClient {
332
333
  private shouldRetryStatus;
333
334
  private backoff;
334
335
  private runtimeName;
336
+ private apiKeyOnlyPrefixes;
337
+ private shouldAttachApiKeyHeader;
335
338
  private createRequestFingerprint;
336
339
  request<T>(options: RuntimeRequestOptions): Promise<RuntimeResponse<T>>;
337
340
  private performRequest;
@@ -496,6 +499,9 @@ declare class MemoryModule {
496
499
  memories: Array<Record<string, unknown>>;
497
500
  count: number;
498
501
  }>;
502
+ get(memoryId: string): Promise<{
503
+ memory: Record<string, unknown>;
504
+ }>;
499
505
  update(memoryId: string, params: {
500
506
  content: string;
501
507
  reasoning?: string;
@@ -654,6 +660,9 @@ declare class WhisperClient {
654
660
  add: (params: Parameters<MemoryModule["add"]>[0]) => Promise<MemoryWriteAck$1>;
655
661
  addBulk: (params: Parameters<MemoryModule["addBulk"]>[0]) => Promise<MemoryWriteAck$1>;
656
662
  search: (params: Parameters<MemoryModule["search"]>[0]) => Promise<MemorySearchResponse$1>;
663
+ get: (memoryId: string) => Promise<{
664
+ memory: Record<string, unknown>;
665
+ }>;
657
666
  getUserProfile: (params: Parameters<MemoryModule["getUserProfile"]>[0]) => ReturnType<MemoryModule["getUserProfile"]>;
658
667
  getSessionMemories: (params: Parameters<MemoryModule["getSessionMemories"]>[0]) => ReturnType<MemoryModule["getSessionMemories"]>;
659
668
  update: (memoryId: string, params: {
@@ -996,6 +1005,62 @@ interface Source {
996
1005
  createdAt: string;
997
1006
  updatedAt: string;
998
1007
  }
1008
+ interface VideoSourceMetadata {
1009
+ source_kind: "video";
1010
+ video_url: string;
1011
+ platform: "youtube" | "loom" | "generic";
1012
+ duration_seconds?: number;
1013
+ published_at?: string;
1014
+ channel_or_author?: string;
1015
+ }
1016
+ interface VideoIngestionStatus {
1017
+ source_id: string;
1018
+ status: string;
1019
+ stage: "extracting" | "transcribing" | "segmenting" | "enriching" | "indexing" | "completed" | "failed";
1020
+ sync_job_id?: string | null;
1021
+ progress?: {
1022
+ current: number;
1023
+ total: number;
1024
+ message: string;
1025
+ } | null;
1026
+ duration_seconds?: number | null;
1027
+ chunks_indexed?: number | null;
1028
+ decisions_detected?: number | null;
1029
+ entities_extracted?: string[];
1030
+ last_error?: string | null;
1031
+ updated_at?: string;
1032
+ }
1033
+ type CanonicalSourceType = "github" | "web" | "pdf" | "local" | "slack";
1034
+ interface CanonicalSourceCreateParams {
1035
+ type: CanonicalSourceType;
1036
+ name?: string;
1037
+ auto_index?: boolean;
1038
+ metadata?: Record<string, string>;
1039
+ owner?: string;
1040
+ repo?: string;
1041
+ branch?: string;
1042
+ paths?: string[];
1043
+ url?: string;
1044
+ crawl_depth?: number;
1045
+ include_paths?: string[];
1046
+ exclude_paths?: string[];
1047
+ file_path?: string;
1048
+ path?: string;
1049
+ glob?: string;
1050
+ max_files?: number;
1051
+ workspace_id?: string;
1052
+ channel_ids?: string[];
1053
+ since?: string;
1054
+ token?: string;
1055
+ auth_ref?: string;
1056
+ }
1057
+ interface CanonicalSourceCreateResult {
1058
+ source_id: string;
1059
+ status: "queued" | "indexing" | "ready" | "failed";
1060
+ job_id: string | null;
1061
+ index_started: boolean;
1062
+ warnings: string[];
1063
+ }
999
1064
  interface Memory {
1000
1065
  id: string;
1001
1066
  projectId: string;
@@ -1139,6 +1204,23 @@ declare class WhisperContext {
1139
1204
  sync_schedule?: string;
1140
1205
  }): Promise<Source>;
1141
1206
  syncSource(sourceId: string): Promise<any>;
1207
+ addSourceByType(projectId: string, params: {
1208
+ type: "video";
1209
+ url: string;
1210
+ auto_sync?: boolean;
1211
+ tags?: string[];
1212
+ platform?: "youtube" | "loom" | "generic";
1213
+ language?: string;
1214
+ allow_stt_fallback?: boolean;
1215
+ max_duration_minutes?: number;
1216
+ name?: string;
1217
+ }): Promise<{
1218
+ source_id: string;
1219
+ sync_job_id?: string | null;
1220
+ status: "processing" | "queued" | "created";
1221
+ }>;
1222
+ getSourceStatus(sourceId: string): Promise<VideoIngestionStatus>;
1223
+ createCanonicalSource(project: string, params: CanonicalSourceCreateParams): Promise<CanonicalSourceCreateResult>;
1142
1224
  ingest(projectId: string, documents: Array<{
1143
1225
  id?: string;
1144
1226
  title: string;
@@ -1299,6 +1381,9 @@ declare class WhisperContext {
1299
1381
  memories: any[];
1300
1382
  count: number;
1301
1383
  }>;
1384
+ getMemory(memoryId: string): Promise<{
1385
+ memory: any;
1386
+ }>;
1302
1387
  getMemoryVersions(memoryId: string): Promise<{
1303
1388
  memory_id: string;
1304
1389
  versions: any[];
@@ -1539,8 +1624,25 @@ declare class WhisperContext {
1539
1624
  config: Record<string, any>;
1540
1625
  sync_schedule?: string;
1541
1626
  }) => Promise<Source>;
1627
+ addSource: (projectId: string, params: {
1628
+ type: "video";
1629
+ url: string;
1630
+ auto_sync?: boolean;
1631
+ tags?: string[];
1632
+ platform?: "youtube" | "loom" | "generic";
1633
+ language?: string;
1634
+ allow_stt_fallback?: boolean;
1635
+ max_duration_minutes?: number;
1636
+ name?: string;
1637
+ }) => Promise<{
1638
+ source_id: string;
1639
+ sync_job_id?: string | null;
1640
+ status: "processing" | "queued" | "created";
1641
+ }>;
1542
1642
  sync: (sourceId: string) => Promise<any>;
1543
1643
  syncSource: (sourceId: string) => Promise<any>;
1644
+ status: (sourceId: string) => Promise<VideoIngestionStatus>;
1645
+ getStatus: (sourceId: string) => Promise<VideoIngestionStatus>;
1544
1646
  };
1545
1647
  readonly memory: {
1546
1648
  add: (params: Parameters<WhisperContext["addMemory"]>[0]) => Promise<{
@@ -1574,6 +1676,9 @@ declare class WhisperContext {
1574
1676
  memories: any[];
1575
1677
  count: number;
1576
1678
  }>;
1679
+ get: (memoryId: string) => Promise<{
1680
+ memory: any;
1681
+ }>;
1577
1682
  getVersions: (memoryId: string) => Promise<{
1578
1683
  memory_id: string;
1579
1684
  versions: any[];
@@ -1679,4 +1784,4 @@ declare class WhisperContext {
1679
1784
  };
1680
1785
  }
1681
1786
 
1682
- export { type ExtractedMemory, LangChainMemoryAdapter, LangGraphCheckpointAdapter, type Memory, type MemoryExtractionResult, type MemoryKind, type MemoryLatencyBreakdown, type MemorySearchResponse, type MemoryWriteAck, type Project, type QueryParams, type QueryResult, type Source, Whisper, WhisperAgentMiddleware, WhisperClient, type WhisperConfig, WhisperContext, Whisper as WhisperDefault, WhisperError, type WhisperErrorCode, WhisperClient as WhisperRuntimeClient, createAgentMiddleware, createLangChainMemoryAdapter, createLangGraphCheckpointAdapter, WhisperContext as default, memoryGraphToMermaid };
1787
+ export { type CanonicalSourceCreateParams, type CanonicalSourceCreateResult, type CanonicalSourceType, type ExtractedMemory, LangChainMemoryAdapter, LangGraphCheckpointAdapter, type Memory, type MemoryExtractionResult, type MemoryKind, type MemoryLatencyBreakdown, type MemorySearchResponse, type MemoryWriteAck, type Project, type QueryParams, type QueryResult, type Source, type VideoIngestionStatus, type VideoSourceMetadata, Whisper, WhisperAgentMiddleware, WhisperClient, type WhisperConfig, WhisperContext, Whisper as WhisperDefault, WhisperError, type WhisperErrorCode, WhisperClient as WhisperRuntimeClient, createAgentMiddleware, createLangChainMemoryAdapter, createLangGraphCheckpointAdapter, WhisperContext as default, memoryGraphToMermaid };
package/index.js CHANGED
@@ -134,6 +134,7 @@ var DEFAULT_TIMEOUTS = {
134
134
  sessionMs: 2500
135
135
  };
136
136
  var DEFAULT_RETRYABLE_STATUS = [408, 429, 500, 502, 503, 504];
137
+ var DEFAULT_API_KEY_ONLY_PREFIXES = ["/v1/memory", "/v1/context/query"];
137
138
  var DEFAULT_RETRY_ATTEMPTS = {
138
139
  search: 3,
139
140
  writeAck: 2,
@@ -182,6 +183,7 @@ var RuntimeClient = class {
182
183
  timeouts;
183
184
  diagnostics;
184
185
  inFlight = /* @__PURE__ */ new Map();
186
+ sendApiKeyHeader;
185
187
  constructor(options, diagnostics) {
186
188
  if (!options.apiKey) {
187
189
  throw new RuntimeClientError({
@@ -205,6 +207,7 @@ var RuntimeClient = class {
205
207
  ...DEFAULT_TIMEOUTS,
206
208
  ...options.timeouts || {}
207
209
  };
210
+ this.sendApiKeyHeader = process.env.WHISPER_SEND_X_API_KEY === "1";
208
211
  this.diagnostics = diagnostics || new DiagnosticsStore(1e3);
209
212
  }
210
213
  getDiagnosticsStore() {
@@ -248,6 +251,16 @@ var RuntimeClient = class {
248
251
  const maybeWindow = globalThis.window;
249
252
  return maybeWindow && typeof maybeWindow === "object" ? "browser" : "node";
250
253
  }
254
+ apiKeyOnlyPrefixes() {
255
+ const raw = process.env.WHISPER_API_KEY_ONLY_PREFIXES;
256
+ if (!raw || !raw.trim()) return DEFAULT_API_KEY_ONLY_PREFIXES;
257
+ return raw.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
258
+ }
259
+ shouldAttachApiKeyHeader(endpoint) {
260
+ if (this.sendApiKeyHeader) return true;
261
+ const prefixes = this.apiKeyOnlyPrefixes();
262
+ return prefixes.some((prefix) => endpoint === prefix || endpoint.startsWith(`${prefix}/`));
263
+ }
251
264
  createRequestFingerprint(options) {
252
265
  const normalizedEndpoint = normalizeEndpoint(options.endpoint);
253
266
  const authFingerprint = stableHash(this.apiKey.replace(/^Bearer\s+/i, ""));
@@ -314,6 +327,7 @@ var RuntimeClient = class {
314
327
  const controller = new AbortController();
315
328
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
316
329
  try {
330
+ const attachApiKeyHeader = this.shouldAttachApiKeyHeader(normalizedEndpoint);
317
331
  const response = await fetch(`${this.baseUrl}${normalizedEndpoint}`, {
318
332
  method,
319
333
  signal: controller.signal,
@@ -321,7 +335,7 @@ var RuntimeClient = class {
321
335
  headers: {
322
336
  "Content-Type": "application/json",
323
337
  Authorization: this.apiKey.startsWith("Bearer ") ? this.apiKey : `Bearer ${this.apiKey}`,
324
- "X-API-Key": this.apiKey.replace(/^Bearer\s+/i, ""),
338
+ ...attachApiKeyHeader ? { "X-API-Key": this.apiKey.replace(/^Bearer\s+/i, "") } : {},
325
339
  "x-trace-id": traceId,
326
340
  "x-span-id": spanId,
327
341
  "x-sdk-version": this.sdkVersion,
@@ -1318,6 +1332,28 @@ var MemoryModule = class {
1318
1332
  });
1319
1333
  return response.data;
1320
1334
  }
1335
+ async get(memoryId) {
1336
+ try {
1337
+ const response = await this.client.request({
1338
+ endpoint: `/v1/memory/${memoryId}`,
1339
+ method: "GET",
1340
+ operation: "get",
1341
+ idempotent: true
1342
+ });
1343
+ return response.data;
1344
+ } catch (error) {
1345
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1346
+ throw error;
1347
+ }
1348
+ const legacy = await this.client.request({
1349
+ endpoint: `/v1/memories/${memoryId}`,
1350
+ method: "GET",
1351
+ operation: "get",
1352
+ idempotent: true
1353
+ });
1354
+ return legacy.data;
1355
+ }
1356
+ }
1321
1357
  async update(memoryId, params) {
1322
1358
  try {
1323
1359
  await this.client.request({
@@ -1672,6 +1708,7 @@ var WhisperClient = class _WhisperClient {
1672
1708
  add: (params) => this.memoryModule.add(params),
1673
1709
  addBulk: (params) => this.memoryModule.addBulk(params),
1674
1710
  search: (params) => this.memoryModule.search(params),
1711
+ get: (memoryId) => this.memoryModule.get(memoryId),
1675
1712
  getUserProfile: (params) => this.memoryModule.getUserProfile(params),
1676
1713
  getSessionMemories: (params) => this.memoryModule.getSessionMemories(params),
1677
1714
  update: (memoryId, params) => this.memoryModule.update(memoryId, params),
@@ -2345,7 +2382,7 @@ var WhisperContext = class _WhisperContext {
2345
2382
  });
2346
2383
  warnDeprecatedOnce2(
2347
2384
  "whisper_context_class",
2348
- "[Whisper SDK] WhisperContext remains supported in v2 but is legacy. Prefer WhisperClient for runtime features (queue/cache/session/diagnostics)."
2385
+ "[Whisper SDK] WhisperContext is deprecated in v3 and scheduled for removal in v4. Prefer WhisperClient for runtime features and future contract compatibility."
2349
2386
  );
2350
2387
  }
2351
2388
  withProject(project) {
@@ -2589,6 +2626,69 @@ var WhisperContext = class _WhisperContext {
2589
2626
  async syncSource(sourceId) {
2590
2627
  return this.request(`/v1/sources/${sourceId}/sync`, { method: "POST" });
2591
2628
  }
2629
+ async addSourceByType(projectId, params) {
2630
+ const resolvedProjectId = await this.resolveProjectId(projectId);
2631
+ return this.request(`/v1/projects/${resolvedProjectId}/add_source`, {
2632
+ method: "POST",
2633
+ body: JSON.stringify(params)
2634
+ });
2635
+ }
2636
+ async getSourceStatus(sourceId) {
2637
+ return this.request(`/v1/sources/${sourceId}/status`, { method: "GET" });
2638
+ }
2639
+ async createCanonicalSource(project, params) {
2640
+ const connector_type = params.type === "github" ? "github" : params.type === "web" ? "website" : params.type === "pdf" ? "pdf" : params.type === "local" ? "local-folder" : "slack";
2641
+ const config = {};
2642
+ if (params.type === "github") {
2643
+ if (!params.owner || !params.repo) throw new WhisperError({ code: "REQUEST_FAILED", message: "github source requires owner and repo" });
2644
+ config.owner = params.owner;
2645
+ config.repo = params.repo;
2646
+ if (params.branch) config.branch = params.branch;
2647
+ if (params.paths) config.paths = params.paths;
2648
+ } else if (params.type === "web") {
2649
+ if (!params.url) throw new WhisperError({ code: "REQUEST_FAILED", message: "web source requires url" });
2650
+ config.url = params.url;
2651
+ if (params.crawl_depth !== void 0) config.crawl_depth = params.crawl_depth;
2652
+ if (params.include_paths) config.include_paths = params.include_paths;
2653
+ if (params.exclude_paths) config.exclude_paths = params.exclude_paths;
2654
+ } else if (params.type === "pdf") {
2655
+ if (!params.url && !params.file_path) throw new WhisperError({ code: "REQUEST_FAILED", message: "pdf source requires url or file_path" });
2656
+ if (params.url) config.url = params.url;
2657
+ if (params.file_path) config.file_path = params.file_path;
2658
+ } else if (params.type === "local") {
2659
+ if (!params.path) throw new WhisperError({ code: "REQUEST_FAILED", message: "local source requires path" });
2660
+ config.path = params.path;
2661
+ if (params.glob) config.glob = params.glob;
2662
+ if (params.max_files !== void 0) config.max_files = params.max_files;
2663
+ } else {
2664
+ config.channel_ids = params.channel_ids || [];
2665
+ if (params.since) config.since = params.since;
2666
+ if (params.workspace_id) config.workspace_id = params.workspace_id;
2667
+ if (params.token) config.token = params.token;
2668
+ if (params.auth_ref) config.auth_ref = params.auth_ref;
2669
+ }
2670
+ if (params.metadata) config.metadata = params.metadata;
2671
+ config.auto_index = params.auto_index ?? true;
2672
+ const created = await this.addSource(project, {
2673
+ name: params.name || `${params.type}-source-${Date.now()}`,
2674
+ connector_type,
2675
+ config
2676
+ });
2677
+ let status = "queued";
2678
+ let jobId = null;
2679
+ if (params.auto_index ?? true) {
2680
+ const syncRes = await this.syncSource(created.id);
2681
+ status = "indexing";
2682
+ jobId = String(syncRes?.id || syncRes?.job_id || "");
2683
+ }
2684
+ return {
2685
+ source_id: created.id,
2686
+ status,
2687
+ job_id: jobId,
2688
+ index_started: params.auto_index ?? true,
2689
+ warnings: []
2690
+ };
2691
+ }
2592
2692
  async ingest(projectId, documents) {
2593
2693
  const resolvedProjectId = await this.resolveProjectId(projectId);
2594
2694
  return this.request(`/v1/projects/${resolvedProjectId}/ingest`, {
@@ -2884,6 +2984,16 @@ var WhisperContext = class _WhisperContext {
2884
2984
  }
2885
2985
  });
2886
2986
  }
2987
+ async getMemory(memoryId) {
2988
+ try {
2989
+ return await this.request(`/v1/memory/${memoryId}`);
2990
+ } catch (error) {
2991
+ if (!this.isEndpointNotFoundError(error)) {
2992
+ throw error;
2993
+ }
2994
+ return this.request(`/v1/memories/${memoryId}`);
2995
+ }
2996
+ }
2887
2997
  async getMemoryVersions(memoryId) {
2888
2998
  return this.request(`/v1/memory/${memoryId}/versions`);
2889
2999
  }
@@ -3066,8 +3176,11 @@ var WhisperContext = class _WhisperContext {
3066
3176
  };
3067
3177
  sources = {
3068
3178
  add: (projectId, params) => this.addSource(projectId, params),
3179
+ addSource: (projectId, params) => this.addSourceByType(projectId, params),
3069
3180
  sync: (sourceId) => this.syncSource(sourceId),
3070
- syncSource: (sourceId) => this.syncSource(sourceId)
3181
+ syncSource: (sourceId) => this.syncSource(sourceId),
3182
+ status: (sourceId) => this.getSourceStatus(sourceId),
3183
+ getStatus: (sourceId) => this.getSourceStatus(sourceId)
3071
3184
  };
3072
3185
  memory = {
3073
3186
  add: (params) => this.addMemory(params),
@@ -3079,6 +3192,7 @@ var WhisperContext = class _WhisperContext {
3079
3192
  ingestSession: (params) => this.ingestSession(params),
3080
3193
  getSessionMemories: (params) => this.getSessionMemories(params),
3081
3194
  getUserProfile: (params) => this.getUserProfile(params),
3195
+ get: (memoryId) => this.getMemory(memoryId),
3082
3196
  getVersions: (memoryId) => this.getMemoryVersions(memoryId),
3083
3197
  update: (memoryId, params) => this.updateMemory(memoryId, params),
3084
3198
  delete: (memoryId) => this.deleteMemory(memoryId),
package/index.mjs CHANGED
@@ -85,6 +85,7 @@ var DEFAULT_TIMEOUTS = {
85
85
  sessionMs: 2500
86
86
  };
87
87
  var DEFAULT_RETRYABLE_STATUS = [408, 429, 500, 502, 503, 504];
88
+ var DEFAULT_API_KEY_ONLY_PREFIXES = ["/v1/memory", "/v1/context/query"];
88
89
  var DEFAULT_RETRY_ATTEMPTS = {
89
90
  search: 3,
90
91
  writeAck: 2,
@@ -133,6 +134,7 @@ var RuntimeClient = class {
133
134
  timeouts;
134
135
  diagnostics;
135
136
  inFlight = /* @__PURE__ */ new Map();
137
+ sendApiKeyHeader;
136
138
  constructor(options, diagnostics) {
137
139
  if (!options.apiKey) {
138
140
  throw new RuntimeClientError({
@@ -156,6 +158,7 @@ var RuntimeClient = class {
156
158
  ...DEFAULT_TIMEOUTS,
157
159
  ...options.timeouts || {}
158
160
  };
161
+ this.sendApiKeyHeader = process.env.WHISPER_SEND_X_API_KEY === "1";
159
162
  this.diagnostics = diagnostics || new DiagnosticsStore(1e3);
160
163
  }
161
164
  getDiagnosticsStore() {
@@ -199,6 +202,16 @@ var RuntimeClient = class {
199
202
  const maybeWindow = globalThis.window;
200
203
  return maybeWindow && typeof maybeWindow === "object" ? "browser" : "node";
201
204
  }
205
+ apiKeyOnlyPrefixes() {
206
+ const raw = process.env.WHISPER_API_KEY_ONLY_PREFIXES;
207
+ if (!raw || !raw.trim()) return DEFAULT_API_KEY_ONLY_PREFIXES;
208
+ return raw.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
209
+ }
210
+ shouldAttachApiKeyHeader(endpoint) {
211
+ if (this.sendApiKeyHeader) return true;
212
+ const prefixes = this.apiKeyOnlyPrefixes();
213
+ return prefixes.some((prefix) => endpoint === prefix || endpoint.startsWith(`${prefix}/`));
214
+ }
202
215
  createRequestFingerprint(options) {
203
216
  const normalizedEndpoint = normalizeEndpoint(options.endpoint);
204
217
  const authFingerprint = stableHash(this.apiKey.replace(/^Bearer\s+/i, ""));
@@ -265,6 +278,7 @@ var RuntimeClient = class {
265
278
  const controller = new AbortController();
266
279
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
267
280
  try {
281
+ const attachApiKeyHeader = this.shouldAttachApiKeyHeader(normalizedEndpoint);
268
282
  const response = await fetch(`${this.baseUrl}${normalizedEndpoint}`, {
269
283
  method,
270
284
  signal: controller.signal,
@@ -272,7 +286,7 @@ var RuntimeClient = class {
272
286
  headers: {
273
287
  "Content-Type": "application/json",
274
288
  Authorization: this.apiKey.startsWith("Bearer ") ? this.apiKey : `Bearer ${this.apiKey}`,
275
- "X-API-Key": this.apiKey.replace(/^Bearer\s+/i, ""),
289
+ ...attachApiKeyHeader ? { "X-API-Key": this.apiKey.replace(/^Bearer\s+/i, "") } : {},
276
290
  "x-trace-id": traceId,
277
291
  "x-span-id": spanId,
278
292
  "x-sdk-version": this.sdkVersion,
@@ -1269,6 +1283,28 @@ var MemoryModule = class {
1269
1283
  });
1270
1284
  return response.data;
1271
1285
  }
1286
+ async get(memoryId) {
1287
+ try {
1288
+ const response = await this.client.request({
1289
+ endpoint: `/v1/memory/${memoryId}`,
1290
+ method: "GET",
1291
+ operation: "get",
1292
+ idempotent: true
1293
+ });
1294
+ return response.data;
1295
+ } catch (error) {
1296
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1297
+ throw error;
1298
+ }
1299
+ const legacy = await this.client.request({
1300
+ endpoint: `/v1/memories/${memoryId}`,
1301
+ method: "GET",
1302
+ operation: "get",
1303
+ idempotent: true
1304
+ });
1305
+ return legacy.data;
1306
+ }
1307
+ }
1272
1308
  async update(memoryId, params) {
1273
1309
  try {
1274
1310
  await this.client.request({
@@ -1623,6 +1659,7 @@ var WhisperClient = class _WhisperClient {
1623
1659
  add: (params) => this.memoryModule.add(params),
1624
1660
  addBulk: (params) => this.memoryModule.addBulk(params),
1625
1661
  search: (params) => this.memoryModule.search(params),
1662
+ get: (memoryId) => this.memoryModule.get(memoryId),
1626
1663
  getUserProfile: (params) => this.memoryModule.getUserProfile(params),
1627
1664
  getSessionMemories: (params) => this.memoryModule.getSessionMemories(params),
1628
1665
  update: (memoryId, params) => this.memoryModule.update(memoryId, params),
@@ -2296,7 +2333,7 @@ var WhisperContext = class _WhisperContext {
2296
2333
  });
2297
2334
  warnDeprecatedOnce2(
2298
2335
  "whisper_context_class",
2299
- "[Whisper SDK] WhisperContext remains supported in v2 but is legacy. Prefer WhisperClient for runtime features (queue/cache/session/diagnostics)."
2336
+ "[Whisper SDK] WhisperContext is deprecated in v3 and scheduled for removal in v4. Prefer WhisperClient for runtime features and future contract compatibility."
2300
2337
  );
2301
2338
  }
2302
2339
  withProject(project) {
@@ -2540,6 +2577,69 @@ var WhisperContext = class _WhisperContext {
2540
2577
  async syncSource(sourceId) {
2541
2578
  return this.request(`/v1/sources/${sourceId}/sync`, { method: "POST" });
2542
2579
  }
2580
+ async addSourceByType(projectId, params) {
2581
+ const resolvedProjectId = await this.resolveProjectId(projectId);
2582
+ return this.request(`/v1/projects/${resolvedProjectId}/add_source`, {
2583
+ method: "POST",
2584
+ body: JSON.stringify(params)
2585
+ });
2586
+ }
2587
+ async getSourceStatus(sourceId) {
2588
+ return this.request(`/v1/sources/${sourceId}/status`, { method: "GET" });
2589
+ }
2590
+ async createCanonicalSource(project, params) {
2591
+ const connector_type = params.type === "github" ? "github" : params.type === "web" ? "website" : params.type === "pdf" ? "pdf" : params.type === "local" ? "local-folder" : "slack";
2592
+ const config = {};
2593
+ if (params.type === "github") {
2594
+ if (!params.owner || !params.repo) throw new WhisperError({ code: "REQUEST_FAILED", message: "github source requires owner and repo" });
2595
+ config.owner = params.owner;
2596
+ config.repo = params.repo;
2597
+ if (params.branch) config.branch = params.branch;
2598
+ if (params.paths) config.paths = params.paths;
2599
+ } else if (params.type === "web") {
2600
+ if (!params.url) throw new WhisperError({ code: "REQUEST_FAILED", message: "web source requires url" });
2601
+ config.url = params.url;
2602
+ if (params.crawl_depth !== void 0) config.crawl_depth = params.crawl_depth;
2603
+ if (params.include_paths) config.include_paths = params.include_paths;
2604
+ if (params.exclude_paths) config.exclude_paths = params.exclude_paths;
2605
+ } else if (params.type === "pdf") {
2606
+ if (!params.url && !params.file_path) throw new WhisperError({ code: "REQUEST_FAILED", message: "pdf source requires url or file_path" });
2607
+ if (params.url) config.url = params.url;
2608
+ if (params.file_path) config.file_path = params.file_path;
2609
+ } else if (params.type === "local") {
2610
+ if (!params.path) throw new WhisperError({ code: "REQUEST_FAILED", message: "local source requires path" });
2611
+ config.path = params.path;
2612
+ if (params.glob) config.glob = params.glob;
2613
+ if (params.max_files !== void 0) config.max_files = params.max_files;
2614
+ } else {
2615
+ config.channel_ids = params.channel_ids || [];
2616
+ if (params.since) config.since = params.since;
2617
+ if (params.workspace_id) config.workspace_id = params.workspace_id;
2618
+ if (params.token) config.token = params.token;
2619
+ if (params.auth_ref) config.auth_ref = params.auth_ref;
2620
+ }
2621
+ if (params.metadata) config.metadata = params.metadata;
2622
+ config.auto_index = params.auto_index ?? true;
2623
+ const created = await this.addSource(project, {
2624
+ name: params.name || `${params.type}-source-${Date.now()}`,
2625
+ connector_type,
2626
+ config
2627
+ });
2628
+ let status = "queued";
2629
+ let jobId = null;
2630
+ if (params.auto_index ?? true) {
2631
+ const syncRes = await this.syncSource(created.id);
2632
+ status = "indexing";
2633
+ jobId = String(syncRes?.id || syncRes?.job_id || "");
2634
+ }
2635
+ return {
2636
+ source_id: created.id,
2637
+ status,
2638
+ job_id: jobId,
2639
+ index_started: params.auto_index ?? true,
2640
+ warnings: []
2641
+ };
2642
+ }
2543
2643
  async ingest(projectId, documents) {
2544
2644
  const resolvedProjectId = await this.resolveProjectId(projectId);
2545
2645
  return this.request(`/v1/projects/${resolvedProjectId}/ingest`, {
@@ -2835,6 +2935,16 @@ var WhisperContext = class _WhisperContext {
2835
2935
  }
2836
2936
  });
2837
2937
  }
2938
+ async getMemory(memoryId) {
2939
+ try {
2940
+ return await this.request(`/v1/memory/${memoryId}`);
2941
+ } catch (error) {
2942
+ if (!this.isEndpointNotFoundError(error)) {
2943
+ throw error;
2944
+ }
2945
+ return this.request(`/v1/memories/${memoryId}`);
2946
+ }
2947
+ }
2838
2948
  async getMemoryVersions(memoryId) {
2839
2949
  return this.request(`/v1/memory/${memoryId}/versions`);
2840
2950
  }
@@ -3017,8 +3127,11 @@ var WhisperContext = class _WhisperContext {
3017
3127
  };
3018
3128
  sources = {
3019
3129
  add: (projectId, params) => this.addSource(projectId, params),
3130
+ addSource: (projectId, params) => this.addSourceByType(projectId, params),
3020
3131
  sync: (sourceId) => this.syncSource(sourceId),
3021
- syncSource: (sourceId) => this.syncSource(sourceId)
3132
+ syncSource: (sourceId) => this.syncSource(sourceId),
3133
+ status: (sourceId) => this.getSourceStatus(sourceId),
3134
+ getStatus: (sourceId) => this.getSourceStatus(sourceId)
3022
3135
  };
3023
3136
  memory = {
3024
3137
  add: (params) => this.addMemory(params),
@@ -3030,6 +3143,7 @@ var WhisperContext = class _WhisperContext {
3030
3143
  ingestSession: (params) => this.ingestSession(params),
3031
3144
  getSessionMemories: (params) => this.getSessionMemories(params),
3032
3145
  getUserProfile: (params) => this.getUserProfile(params),
3146
+ get: (memoryId) => this.getMemory(memoryId),
3033
3147
  getVersions: (memoryId) => this.getMemoryVersions(memoryId),
3034
3148
  update: (memoryId, params) => this.updateMemory(memoryId, params),
3035
3149
  delete: (memoryId) => this.deleteMemory(memoryId),
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@usewhisper/sdk",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
+ "whisperContractVersion": "2026.03.09",
4
5
  "scripts": {
5
6
  "build": "tsup ../src/sdk/index.ts --format esm,cjs --dts --out-dir .",
6
7
  "prepublishOnly": "npm run build"