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