@covia/covia-sdk 1.0.0 → 1.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/dist/index.js CHANGED
@@ -4,19 +4,20 @@ var didResolver = require('did-resolver');
4
4
  var webDidResolver = require('web-did-resolver');
5
5
 
6
6
  // src/types.ts
7
- var RunStatus = /* @__PURE__ */ ((RunStatus2) => {
8
- RunStatus2["COMPLETE"] = "COMPLETE";
9
- RunStatus2["FAILED"] = "FAILED";
10
- RunStatus2["PENDING"] = "PENDING";
11
- RunStatus2["STARTED"] = "STARTED";
12
- RunStatus2["CANCELLED"] = "CANCELLED";
13
- RunStatus2["TIMEOUT"] = "TIMEOUT";
14
- RunStatus2["REJECTED"] = "REJECTED";
15
- RunStatus2["INPUT_REQUIRED"] = "INPUT_REQUIRED";
16
- RunStatus2["AUTH_REQUIRED"] = "AUTH_REQUIRED";
17
- RunStatus2["PAUSED"] = "PAUSED";
18
- return RunStatus2;
7
+ var RunStatus = /* @__PURE__ */ ((RunStatus3) => {
8
+ RunStatus3["COMPLETE"] = "COMPLETE";
9
+ RunStatus3["FAILED"] = "FAILED";
10
+ RunStatus3["PENDING"] = "PENDING";
11
+ RunStatus3["STARTED"] = "STARTED";
12
+ RunStatus3["CANCELLED"] = "CANCELLED";
13
+ RunStatus3["TIMEOUT"] = "TIMEOUT";
14
+ RunStatus3["REJECTED"] = "REJECTED";
15
+ RunStatus3["INPUT_REQUIRED"] = "INPUT_REQUIRED";
16
+ RunStatus3["AUTH_REQUIRED"] = "AUTH_REQUIRED";
17
+ RunStatus3["PAUSED"] = "PAUSED";
18
+ return RunStatus3;
19
19
  })(RunStatus || {});
20
+ var JobStatus = RunStatus;
20
21
  var CoviaError = class extends Error {
21
22
  constructor(message, code = null) {
22
23
  super(message);
@@ -25,8 +26,96 @@ var CoviaError = class extends Error {
25
26
  this.message = message;
26
27
  }
27
28
  };
29
+ var GridError = class extends CoviaError {
30
+ constructor(statusCode, message, responseBody = null) {
31
+ super(`HTTP ${statusCode}: ${message}`, statusCode);
32
+ this.name = "GridError";
33
+ this.statusCode = statusCode;
34
+ this.responseBody = responseBody;
35
+ }
36
+ };
37
+ var CoviaConnectionError = class extends CoviaError {
38
+ constructor(message) {
39
+ super(message);
40
+ this.name = "CoviaConnectionError";
41
+ }
42
+ };
43
+ var CoviaTimeoutError = class extends CoviaError {
44
+ constructor(message) {
45
+ super(message);
46
+ this.name = "CoviaTimeoutError";
47
+ }
48
+ };
49
+ var JobFailedError = class extends CoviaError {
50
+ constructor(jobData) {
51
+ const id = jobData.id ?? "unknown";
52
+ const status = jobData.status ?? "unknown";
53
+ let msg = `Job ${id} ${status}`;
54
+ if (jobData.output?.error) {
55
+ msg += `: ${jobData.output.error}`;
56
+ }
57
+ super(msg);
58
+ this.name = "JobFailedError";
59
+ this.jobData = jobData;
60
+ }
61
+ };
62
+ var NotFoundError = class extends GridError {
63
+ constructor(message) {
64
+ super(404, message);
65
+ this.name = "NotFoundError";
66
+ }
67
+ };
68
+ var AssetNotFoundError = class extends NotFoundError {
69
+ constructor(assetId) {
70
+ super(`Asset not found: ${assetId}`);
71
+ this.name = "AssetNotFoundError";
72
+ this.assetId = assetId;
73
+ }
74
+ };
75
+ var JobNotFoundError = class extends NotFoundError {
76
+ constructor(jobId) {
77
+ super(`Job not found: ${jobId}`);
78
+ this.name = "JobNotFoundError";
79
+ this.jobId = jobId;
80
+ }
81
+ };
28
82
 
29
83
  // src/Credentials.ts
84
+ var Auth = class {
85
+ };
86
+ var NoAuth = class extends Auth {
87
+ apply(_headers) {
88
+ }
89
+ };
90
+ var BearerAuth = class extends Auth {
91
+ constructor(token) {
92
+ super();
93
+ this._token = token;
94
+ }
95
+ apply(headers) {
96
+ headers["Authorization"] = `Bearer ${this._token}`;
97
+ }
98
+ };
99
+ var BasicAuth = class extends Auth {
100
+ constructor(username, password) {
101
+ super();
102
+ this._encoded = btoa(`${username}:${password}`);
103
+ }
104
+ apply(headers) {
105
+ headers["Authorization"] = `Basic ${this._encoded}`;
106
+ }
107
+ };
108
+ var CoviaUserAuth = class extends Auth {
109
+ constructor(userId) {
110
+ super();
111
+ this._userId = userId;
112
+ }
113
+ apply(headers) {
114
+ if (this._userId && this._userId !== "") {
115
+ headers["X-Covia-User"] = this._userId;
116
+ }
117
+ }
118
+ };
30
119
  var CredentialsHTTP = class {
31
120
  constructor(venueId, apiKey, userId) {
32
121
  this.venueId = venueId;
@@ -35,26 +124,86 @@ var CredentialsHTTP = class {
35
124
  }
36
125
  };
37
126
 
127
+ // src/Logger.ts
128
+ var defaultHandler = (_level, message) => {
129
+ console.debug(`[covia] ${message}`);
130
+ };
131
+ var logger = {
132
+ level: "none",
133
+ handler: defaultHandler,
134
+ debug(message) {
135
+ if (this.level === "debug") {
136
+ this.handler("debug", message);
137
+ }
138
+ }
139
+ };
140
+
38
141
  // src/Utils.ts
39
- function fetchWithError(url, options) {
40
- return fetch(url, options).then((response) => {
41
- if (!response.ok) {
42
- throw new CoviaError(`Request failed! status: ${response.status}`);
142
+ async function parseErrorBody(response) {
143
+ let body = null;
144
+ let message = `Request failed with status ${response.status}`;
145
+ try {
146
+ body = await response.json();
147
+ if (body?.error) {
148
+ message = body.error;
43
149
  }
44
- return response.json();
45
- }).catch((error) => {
46
- throw error instanceof CoviaError ? error : new CoviaError(`Request failed: ${error.message}`);
47
- });
48
- }
49
- function fetchStreamWithError(url, options) {
50
- return fetch(url, options).then((response) => {
51
- if (!response.ok) {
52
- throw new CoviaError(`Request failed! status: ${response.status}`);
150
+ } catch {
151
+ try {
152
+ const text = await response.text();
153
+ if (text) message = text;
154
+ } catch {
53
155
  }
54
- return response;
55
- }).catch((error) => {
56
- throw error instanceof CoviaError ? error : new CoviaError(`Request failed: ${error.message}`);
57
- });
156
+ }
157
+ return { message, body };
158
+ }
159
+ async function throwHttpError(response) {
160
+ const { message, body } = await parseErrorBody(response);
161
+ if (response.status === 404) {
162
+ throw new NotFoundError(message);
163
+ }
164
+ throw new GridError(response.status, message, body);
165
+ }
166
+ function wrapError(error) {
167
+ if (error instanceof CoviaError) return error;
168
+ const msg = error.message ?? String(error);
169
+ if (error instanceof TypeError) {
170
+ return new CoviaConnectionError(msg);
171
+ }
172
+ return new CoviaError(`Request failed: ${msg}`);
173
+ }
174
+ async function fetchWithError(url, options) {
175
+ const method = options?.method ?? "GET";
176
+ logger.debug(`${method} ${url}`);
177
+ let response;
178
+ try {
179
+ response = await fetch(url, options);
180
+ } catch (error) {
181
+ const msg = error.message ?? String(error);
182
+ logger.debug(`Connection failed: ${method} ${url} \u2014 ${msg}`);
183
+ throw wrapError(error);
184
+ }
185
+ logger.debug(`${method} ${url} \u2192 ${response.status}`);
186
+ if (!response.ok) {
187
+ await throwHttpError(response);
188
+ }
189
+ return response.json();
190
+ }
191
+ async function fetchStreamWithError(url, options) {
192
+ const method = options?.method ?? "GET";
193
+ logger.debug(`${method} ${url}`);
194
+ let response;
195
+ try {
196
+ response = await fetch(url, options);
197
+ } catch (error) {
198
+ const msg = error.message ?? String(error);
199
+ logger.debug(`Connection failed: ${method} ${url} \u2014 ${msg}`);
200
+ throw wrapError(error);
201
+ }
202
+ logger.debug(`${method} ${url} \u2192 ${response.status}`);
203
+ if (!response.ok) {
204
+ await throwHttpError(response);
205
+ }
206
+ return response;
58
207
  }
59
208
  function isJobComplete(jobStatus) {
60
209
  if (jobStatus == null)
@@ -64,7 +213,7 @@ function isJobComplete(jobStatus) {
64
213
  function isJobPaused(jobStatus) {
65
214
  if (jobStatus == null)
66
215
  return false;
67
- return jobStatus == "PAUSED" /* PAUSED */ ? true : false;
216
+ return jobStatus == "PAUSED" /* PAUSED */ || jobStatus == "INPUT_REQUIRED" /* INPUT_REQUIRED */ || jobStatus == "AUTH_REQUIRED" /* AUTH_REQUIRED */;
68
217
  }
69
218
  function isJobFinished(jobStatus) {
70
219
  if (jobStatus == null)
@@ -73,6 +222,7 @@ function isJobFinished(jobStatus) {
73
222
  if (jobStatus == "FAILED" /* FAILED */) return true;
74
223
  if (jobStatus == "REJECTED" /* REJECTED */) return true;
75
224
  if (jobStatus == "CANCELLED" /* CANCELLED */) return true;
225
+ if (jobStatus == "TIMEOUT" /* TIMEOUT */) return true;
76
226
  return false;
77
227
  }
78
228
  function getParsedAssetId(assetId) {
@@ -89,6 +239,87 @@ function getAssetIdFromPath(assetHex, assetPath) {
89
239
  function getAssetIdFromVenueId(assetHex, venueId) {
90
240
  return venueId + "/a/" + assetHex;
91
241
  }
242
+ function createSSEEvent(fields) {
243
+ const data = fields.data ?? "";
244
+ return {
245
+ event: fields.event || null,
246
+ data,
247
+ id: fields.id || null,
248
+ retry: fields.retry ?? null,
249
+ json() {
250
+ return JSON.parse(data);
251
+ }
252
+ };
253
+ }
254
+ async function* parseSSEStream(response) {
255
+ const reader = response.body?.getReader();
256
+ if (!reader) return;
257
+ const decoder = new TextDecoder();
258
+ let buffer = "";
259
+ let event;
260
+ let data = [];
261
+ let id;
262
+ let retry;
263
+ try {
264
+ while (true) {
265
+ const { done, value } = await reader.read();
266
+ if (done) break;
267
+ buffer += decoder.decode(value, { stream: true });
268
+ const lines = buffer.split("\n");
269
+ buffer = lines.pop() ?? "";
270
+ for (const line of lines) {
271
+ if (line === "") {
272
+ if (data.length > 0 || event !== void 0) {
273
+ yield createSSEEvent({
274
+ event,
275
+ data: data.join("\n"),
276
+ id,
277
+ retry
278
+ });
279
+ event = void 0;
280
+ data = [];
281
+ id = void 0;
282
+ retry = void 0;
283
+ }
284
+ continue;
285
+ }
286
+ if (line.startsWith(":")) continue;
287
+ const colonIdx = line.indexOf(":");
288
+ let field;
289
+ let val;
290
+ if (colonIdx === -1) {
291
+ field = line;
292
+ val = "";
293
+ } else {
294
+ field = line.slice(0, colonIdx);
295
+ val = line.slice(colonIdx + 1);
296
+ if (val.startsWith(" ")) val = val.slice(1);
297
+ }
298
+ switch (field) {
299
+ case "event":
300
+ event = val;
301
+ break;
302
+ case "data":
303
+ data.push(val);
304
+ break;
305
+ case "id":
306
+ id = val;
307
+ break;
308
+ case "retry": {
309
+ const n = parseInt(val, 10);
310
+ if (!isNaN(n)) retry = n;
311
+ break;
312
+ }
313
+ }
314
+ }
315
+ }
316
+ if (data.length > 0 || event !== void 0) {
317
+ yield createSSEEvent({ event, data: data.join("\n"), id, retry });
318
+ }
319
+ } finally {
320
+ reader.releaseLock();
321
+ }
322
+ }
92
323
 
93
324
  // src/Asset.ts
94
325
  var cache = /* @__PURE__ */ new Map();
@@ -121,12 +352,12 @@ var Asset = class {
121
352
  return this.readStream(reader);
122
353
  }
123
354
  /**
124
- * Upload content to asset
355
+ * Put content to asset
125
356
  * @param content - Content to upload
126
357
  * @returns {Promise<ReadableStream<Uint8Array> | null>}
127
358
  */
128
- uploadContent(content) {
129
- return this.venue.uploadContent(this.id, content);
359
+ putContent(content) {
360
+ return this.venue.putContent(this.id, content);
130
361
  }
131
362
  /**
132
363
  * Get asset content
@@ -179,6 +410,9 @@ var DataAsset = class extends Asset {
179
410
  };
180
411
 
181
412
  // src/Job.ts
413
+ var INITIAL_POLL_DELAY = 300;
414
+ var BACKOFF_FACTOR = 1.5;
415
+ var MAX_POLL_DELAY = 1e4;
182
416
  var Job = class {
183
417
  constructor(id, venue, metadata) {
184
418
  this.id = id;
@@ -186,9 +420,85 @@ var Job = class {
186
420
  this.metadata = metadata;
187
421
  }
188
422
  /**
189
- * Cancels the execution of the job
190
- * @returns {Promise<number>}
191
- */
423
+ * Whether the job has reached a terminal state
424
+ */
425
+ get isFinished() {
426
+ return this.metadata.status != null && isJobFinished(this.metadata.status);
427
+ }
428
+ /**
429
+ * Whether the job completed successfully
430
+ */
431
+ get isComplete() {
432
+ return this.metadata.status != null && isJobComplete(this.metadata.status);
433
+ }
434
+ /**
435
+ * The job output.
436
+ * @throws {Error} If the job has not finished yet.
437
+ * @throws {JobFailedError} If the job finished with a non-COMPLETE status.
438
+ */
439
+ get output() {
440
+ if (!this.isFinished) {
441
+ throw new Error(`Job is not finished (status: ${this.metadata.status})`);
442
+ }
443
+ if (!this.isComplete) {
444
+ throw new JobFailedError(this.metadata);
445
+ }
446
+ return this.metadata.output;
447
+ }
448
+ /**
449
+ * Poll the venue for the latest job status.
450
+ * @throws {Error} If the job has no ID.
451
+ */
452
+ async refresh() {
453
+ if (!this.id) {
454
+ throw new Error("Cannot refresh a job with no ID");
455
+ }
456
+ const job = await this.venue.getJob(this.id);
457
+ this.metadata = job.metadata;
458
+ }
459
+ /**
460
+ * Wait until the job reaches a terminal state.
461
+ * Uses exponential backoff polling (initial 300ms, factor 1.5, max 10s).
462
+ * @param options.timeout - Maximum milliseconds to wait. Undefined waits indefinitely.
463
+ * @throws {CoviaTimeoutError} If timeout is exceeded.
464
+ */
465
+ async wait(options) {
466
+ if (this.isFinished) return;
467
+ let delay = INITIAL_POLL_DELAY;
468
+ const start = Date.now();
469
+ logger.debug(`Polling job ${this.id} (status: ${this.metadata.status})`);
470
+ while (!this.isFinished) {
471
+ if (options?.timeout !== void 0 && Date.now() - start > options.timeout) {
472
+ throw new CoviaTimeoutError(`Job ${this.id} did not finish within ${options.timeout}ms`);
473
+ }
474
+ await new Promise((resolve) => setTimeout(resolve, delay));
475
+ await this.refresh();
476
+ logger.debug(`Job ${this.id} polled \u2192 ${this.metadata.status} (delay=${(delay / 1e3).toFixed(1)}s)`);
477
+ delay = Math.min(delay * BACKOFF_FACTOR, MAX_POLL_DELAY);
478
+ }
479
+ }
480
+ /**
481
+ * Wait for the job to complete and return its output.
482
+ * @param options.timeout - Maximum milliseconds to wait.
483
+ * @returns The job output.
484
+ * @throws {JobFailedError} If the job finishes with a non-COMPLETE status.
485
+ * @throws {CoviaTimeoutError} If timeout is exceeded.
486
+ */
487
+ async result(options) {
488
+ await this.wait(options);
489
+ return this.output;
490
+ }
491
+ /**
492
+ * Stream server-sent events for this job.
493
+ * @returns AsyncGenerator yielding SSEEvent objects
494
+ */
495
+ async *stream() {
496
+ yield* this.venue.streamJobEvents(this.id);
497
+ }
498
+ /**
499
+ * Cancels the execution of the job
500
+ * @returns {Promise<number>}
501
+ */
192
502
  async cancelJob() {
193
503
  return this.venue.cancelJob(this.id);
194
504
  }
@@ -209,7 +519,7 @@ var Venue = class _Venue {
209
519
  constructor(options = {}) {
210
520
  this.baseUrl = options.baseUrl || "";
211
521
  this.venueId = options.venueId || "";
212
- this.credentials = options.credentials || new CredentialsHTTP(this.venueId, "", "");
522
+ this.auth = options.auth || new NoAuth();
213
523
  this.metadata = {
214
524
  name: options.name || "default",
215
525
  description: options.description || ""
@@ -221,13 +531,13 @@ var Venue = class _Venue {
221
531
  * @param credentials - Optional credentials for venue authentication
222
532
  * @returns {Promise<Venue>} A new Venue instance configured appropriately
223
533
  */
224
- static async connect(venueId, credentials) {
534
+ static async connect(venueId, auth) {
225
535
  if (venueId instanceof _Venue) {
226
536
  return new _Venue({
227
537
  baseUrl: venueId.baseUrl,
228
538
  venueId: venueId.venueId,
229
539
  name: venueId.metadata.name,
230
- credentials
540
+ auth
231
541
  });
232
542
  }
233
543
  if (typeof venueId === "string") {
@@ -254,20 +564,20 @@ var Venue = class _Venue {
254
564
  baseUrl,
255
565
  venueId: data.did,
256
566
  name: data.name,
257
- credentials
567
+ auth
258
568
  });
259
569
  }
260
570
  throw new CoviaError("Invalid venue ID parameter. Must be a string (URL/DNS) or Venue instance.");
261
571
  }
262
572
  /**
263
- * Create a new asset
573
+ * Register a new asset
264
574
  * @param assetData - Asset configuration
265
575
  * @returns {Promise<Asset>}
266
576
  */
267
- async createAsset(assetData) {
577
+ async register(assetData) {
268
578
  return fetchWithError(`${this.baseUrl}/api/v1/assets/`, {
269
579
  method: "POST",
270
- headers: this.setCredentialsInHeader(),
580
+ headers: this._buildHeaders(),
271
581
  body: JSON.stringify(assetData)
272
582
  }).then((response) => {
273
583
  return this.getAsset(response);
@@ -298,32 +608,40 @@ var Venue = class _Venue {
298
608
  } else {
299
609
  return new DataAsset(assetId, this, cachedData);
300
610
  }
301
- } else {
302
- return fetchWithError(`${this.baseUrl}/api/v1/assets/${assetId}`).then((data) => {
303
- cache2.set(assetId, data);
304
- if (data.metadata?.operation) {
305
- return new Operation(assetId, this, data);
306
- } else {
307
- return new DataAsset(assetId, this, data);
308
- }
309
- });
611
+ }
612
+ try {
613
+ const data = await fetchWithError(`${this.baseUrl}/api/v1/assets/${assetId}`);
614
+ cache2.set(assetId, data);
615
+ if (data.metadata?.operation) {
616
+ return new Operation(assetId, this, data);
617
+ } else {
618
+ return new DataAsset(assetId, this, data);
619
+ }
620
+ } catch (error) {
621
+ if (error instanceof NotFoundError) {
622
+ throw new AssetNotFoundError(assetId);
623
+ }
624
+ throw error;
310
625
  }
311
626
  }
312
627
  /**
313
- * Get all assets
314
- * @returns {Promise<Asset[]>}
628
+ * List assets with pagination support
629
+ * @param options - Pagination options (offset, limit)
630
+ * @returns {Promise<AssetList>} Paginated list of asset IDs with metadata
315
631
  */
316
- getAssets() {
317
- return fetchWithError(`${this.baseUrl}/api/v1/assets/`).then((assetIds) => {
318
- const assetPromises = assetIds.items.map((assetId) => this.getAsset(assetId));
319
- return Promise.all(assetPromises);
320
- });
632
+ async listAssets(options = {}) {
633
+ const params = new URLSearchParams();
634
+ params.set("offset", String(options.offset ?? 0));
635
+ if (options.limit !== void 0) {
636
+ params.set("limit", String(options.limit));
637
+ }
638
+ return fetchWithError(`${this.baseUrl}/api/v1/assets/?${params.toString()}`);
321
639
  }
322
640
  /**
323
- * Get all jobs
641
+ * List all jobs
324
642
  * @returns {Promise<string[]>}
325
643
  */
326
- async getJobs() {
644
+ async listJobs() {
327
645
  return fetchWithError(`${this.baseUrl}/api/v1/jobs`);
328
646
  }
329
647
  /**
@@ -332,9 +650,15 @@ var Venue = class _Venue {
332
650
  * @returns {Promise<Job>}
333
651
  */
334
652
  async getJob(jobId) {
335
- return fetchWithError(`${this.baseUrl}/api/v1/jobs/${jobId}`).then((data) => {
653
+ try {
654
+ const data = await fetchWithError(`${this.baseUrl}/api/v1/jobs/${jobId}`);
336
655
  return new Job(jobId, this, data);
337
- });
656
+ } catch (error) {
657
+ if (error instanceof NotFoundError) {
658
+ throw new JobNotFoundError(jobId);
659
+ }
660
+ throw error;
661
+ }
338
662
  }
339
663
  /**
340
664
  * Cancel job by ID
@@ -342,9 +666,15 @@ var Venue = class _Venue {
342
666
  * @returns {Promise<number>}
343
667
  */
344
668
  async cancelJob(jobId) {
345
- return fetchStreamWithError(`${this.baseUrl}/api/v1/jobs/${jobId}/cancel`, { method: "PUT" }).then((response) => {
669
+ try {
670
+ const response = await fetchStreamWithError(`${this.baseUrl}/api/v1/jobs/${jobId}/cancel`, { method: "PUT" });
346
671
  return response.status;
347
- });
672
+ } catch (error) {
673
+ if (error instanceof NotFoundError) {
674
+ throw new JobNotFoundError(jobId);
675
+ }
676
+ throw error;
677
+ }
348
678
  }
349
679
  /**
350
680
  * Delete job by ID
@@ -352,44 +682,107 @@ var Venue = class _Venue {
352
682
  * @returns {Promise<number>}
353
683
  */
354
684
  async deleteJob(jobId) {
355
- return fetchStreamWithError(`${this.baseUrl}/api/v1/jobs/${jobId}/delete`, { method: "PUT" }).then((response) => {
685
+ try {
686
+ const response = await fetchStreamWithError(`${this.baseUrl}/api/v1/jobs/${jobId}/delete`, { method: "PUT" });
356
687
  return response.status;
357
- });
688
+ } catch (error) {
689
+ if (error instanceof NotFoundError) {
690
+ throw new JobNotFoundError(jobId);
691
+ }
692
+ throw error;
693
+ }
358
694
  }
359
695
  /**
360
- * Get the DID (Decentralized Identifier) for this venue
361
- * @returns {string} DID in the format did:web:domain
362
- */
363
- getStats() {
696
+ * Get venue status
697
+ * @returns {Promise<StatusData>}
698
+ */
699
+ status() {
364
700
  return fetchWithError(`${this.baseUrl}/api/v1/status`);
365
701
  }
702
+ /**
703
+ * List all named operations available on this venue
704
+ * @returns {Promise<OperationInfo[]>}
705
+ */
706
+ async listOperations() {
707
+ return fetchWithError(`${this.baseUrl}/api/v1/operations`);
708
+ }
709
+ /**
710
+ * Get details of a named operation
711
+ * @param name - Operation name (e.g., "test:echo")
712
+ * @returns {Promise<OperationInfo>}
713
+ */
714
+ async getOperation(name) {
715
+ return fetchWithError(`${this.baseUrl}/api/v1/operations/${name}`);
716
+ }
717
+ /**
718
+ * Get the full DID document for this venue
719
+ * @returns {Promise<DIDDocument>}
720
+ */
721
+ async didDocument() {
722
+ return fetchWithError(`${this.baseUrl}/.well-known/did.json`);
723
+ }
724
+ /**
725
+ * Get MCP (Model Context Protocol) discovery information
726
+ * @returns {Promise<MCPDiscovery>}
727
+ */
728
+ async mcpDiscovery() {
729
+ return fetchWithError(`${this.baseUrl}/.well-known/mcp`);
730
+ }
731
+ /**
732
+ * Get the A2A (Agent-to-Agent) agent card
733
+ * @returns {Promise<AgentCard>}
734
+ */
735
+ async agentCard() {
736
+ return fetchWithError(`${this.baseUrl}/.well-known/agent-card.json`);
737
+ }
366
738
  /**
367
739
  * Get asset metadata
368
740
  * @returns {Promise<AssetMetadata>}
369
741
  */
370
742
  async getMetadata(assetId) {
371
- return await fetchWithError(`${this.baseUrl}/api/v1/assets/${assetId}`);
743
+ try {
744
+ return await fetchWithError(`${this.baseUrl}/api/v1/assets/${assetId}`);
745
+ } catch (error) {
746
+ if (error instanceof NotFoundError) {
747
+ throw new AssetNotFoundError(assetId);
748
+ }
749
+ throw error;
750
+ }
372
751
  }
373
752
  /**
374
- * Upload content to asset
375
- * @param content - Content to upload
376
- * @returns {Promise<ReadableStream<Uint8Array> | null>}
377
- */
378
- async uploadContent(assetId, content) {
379
- const response = await fetchStreamWithError(`${this.baseUrl}/api/v1/assets/${assetId}/content`, {
380
- method: "PUT",
381
- headers: this.setCredentialsInHeader(),
382
- body: content
383
- });
384
- return response.body;
753
+ * Put content to asset
754
+ * @param content - Content to upload
755
+ * @returns {Promise<ReadableStream<Uint8Array> | null>}
756
+ */
757
+ async putContent(assetId, content) {
758
+ try {
759
+ const response = await fetchStreamWithError(`${this.baseUrl}/api/v1/assets/${assetId}/content`, {
760
+ method: "PUT",
761
+ headers: this._buildHeaders(),
762
+ body: content
763
+ });
764
+ return response.body;
765
+ } catch (error) {
766
+ if (error instanceof NotFoundError) {
767
+ throw new AssetNotFoundError(assetId);
768
+ }
769
+ throw error;
770
+ }
385
771
  }
386
772
  /**
387
773
  * Get asset content
388
774
  * @returns {Promise<ReadableStream<Uint8Array> | null>}
389
775
  */
390
776
  async getContent(assetId) {
391
- const response = await fetchStreamWithError(`${this.baseUrl}/api/v1/assets/${assetId}/content`);
392
- return response.body;
777
+ try {
778
+ const response = await fetchStreamWithError(`${this.baseUrl}/api/v1/assets/${assetId}/content`);
779
+ return response.body;
780
+ } catch (error) {
781
+ if (error instanceof NotFoundError) {
782
+ throw new AssetNotFoundError(assetId);
783
+ }
784
+ throw error;
785
+ }
393
786
  }
394
787
  /**
395
788
  * Execute the operation
@@ -404,7 +797,7 @@ var Venue = class _Venue {
404
797
  try {
405
798
  const response = await fetchWithError(`${this.baseUrl}/api/v1/invoke/`, {
406
799
  method: "POST",
407
- headers: this.setCredentialsInHeader(),
800
+ headers: this._buildHeaders(),
408
801
  body: JSON.stringify(payload)
409
802
  });
410
803
  return response?.output;
@@ -425,7 +818,7 @@ var Venue = class _Venue {
425
818
  try {
426
819
  const response = await fetchWithError(`${this.baseUrl}/api/v1/invoke/`, {
427
820
  method: "POST",
428
- headers: this.setCredentialsInHeader(),
821
+ headers: this._buildHeaders(),
429
822
  body: JSON.stringify(payload)
430
823
  });
431
824
  return new Job(response?.id, this, response);
@@ -433,15 +826,34 @@ var Venue = class _Venue {
433
826
  throw error;
434
827
  }
435
828
  }
436
- setCredentialsInHeader() {
437
- if (this.credentials.userId && this.credentials.userId != "") {
438
- return {
439
- "Content-Type": "application/json",
440
- "X-Covia-User": this.credentials.userId
441
- };
442
- } else {
443
- return { "Content-Type": "application/json" };
444
- }
829
+ /**
830
+ * Stream server-sent events for a job.
831
+ * @param jobId - Job identifier
832
+ * @returns AsyncGenerator yielding SSEEvent objects
833
+ */
834
+ async *streamJobEvents(jobId) {
835
+ const response = await fetchStreamWithError(`${this.baseUrl}/api/v1/jobs/${jobId}/sse`, {
836
+ headers: { ...this._buildHeaders(), "Accept": "text/event-stream" }
837
+ });
838
+ yield* parseSSEStream(response);
839
+ }
840
+ /**
841
+ * Close the venue and release resources.
842
+ * Clears cached asset data for this venue.
843
+ */
844
+ close() {
845
+ cache2.clear();
846
+ }
847
+ /**
848
+ * Disposable support — allows `using venue = await Grid.connect(...)` in TS 5.2+.
849
+ */
850
+ [Symbol.dispose]() {
851
+ this.close();
852
+ }
853
+ _buildHeaders() {
854
+ const headers = { "Content-Type": "application/json" };
855
+ this.auth.apply(headers);
856
+ return headers;
445
857
  }
446
858
  };
447
859
 
@@ -451,26 +863,41 @@ var Grid = class {
451
863
  /**
452
864
  * Static method to connect to a venue
453
865
  * @param venueId - Can be a HTTP base URL, DNS name, or existing Venue instance
866
+ * @param auth - Optional authentication provider (BearerAuth, BasicAuth, etc.)
454
867
  * @returns {Promise<Venue>} A new Venue instance configured appropriately
455
868
  */
456
- static async connect(venueId, credentials) {
869
+ static async connect(venueId, auth) {
457
870
  if (cache3.has(venueId))
458
871
  return Promise.resolve(cache3.get(venueId));
459
- const connectedVenue = await Venue.connect(venueId, credentials);
872
+ const connectedVenue = await Venue.connect(venueId, auth);
460
873
  cache3.set(venueId, connectedVenue);
461
874
  return Promise.resolve(connectedVenue);
462
875
  }
463
876
  };
464
877
 
465
878
  exports.Asset = Asset;
879
+ exports.AssetNotFoundError = AssetNotFoundError;
880
+ exports.Auth = Auth;
881
+ exports.BasicAuth = BasicAuth;
882
+ exports.BearerAuth = BearerAuth;
883
+ exports.CoviaConnectionError = CoviaConnectionError;
466
884
  exports.CoviaError = CoviaError;
885
+ exports.CoviaTimeoutError = CoviaTimeoutError;
886
+ exports.CoviaUserAuth = CoviaUserAuth;
467
887
  exports.CredentialsHTTP = CredentialsHTTP;
468
888
  exports.DataAsset = DataAsset;
469
889
  exports.Grid = Grid;
890
+ exports.GridError = GridError;
470
891
  exports.Job = Job;
892
+ exports.JobFailedError = JobFailedError;
893
+ exports.JobNotFoundError = JobNotFoundError;
894
+ exports.JobStatus = JobStatus;
895
+ exports.NoAuth = NoAuth;
896
+ exports.NotFoundError = NotFoundError;
471
897
  exports.Operation = Operation;
472
898
  exports.RunStatus = RunStatus;
473
899
  exports.Venue = Venue;
900
+ exports.createSSEEvent = createSSEEvent;
474
901
  exports.fetchStreamWithError = fetchStreamWithError;
475
902
  exports.fetchWithError = fetchWithError;
476
903
  exports.getAssetIdFromPath = getAssetIdFromPath;
@@ -479,3 +906,5 @@ exports.getParsedAssetId = getParsedAssetId;
479
906
  exports.isJobComplete = isJobComplete;
480
907
  exports.isJobFinished = isJobFinished;
481
908
  exports.isJobPaused = isJobPaused;
909
+ exports.logger = logger;
910
+ exports.parseSSEStream = parseSSEStream;