@vertesia/client 1.5.0-dev.20260725.083715Z → 1.5.0-dev.20260804.124748Z
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/lib/AccountApi.d.ts +10 -7
- package/lib/AccountApi.d.ts.map +1 -1
- package/lib/AccountApi.js +7 -4
- package/lib/AccountApi.js.map +1 -1
- package/lib/ApiKeysApi.d.ts +3 -3
- package/lib/ApiKeysApi.d.ts.map +1 -1
- package/lib/ApiKeysApi.js.map +1 -1
- package/lib/EnvironmentsApi.d.ts +3 -6
- package/lib/EnvironmentsApi.d.ts.map +1 -1
- package/lib/EnvironmentsApi.js.map +1 -1
- package/lib/GroupsApi.d.ts +2 -0
- package/lib/GroupsApi.d.ts.map +1 -1
- package/lib/GroupsApi.js.map +1 -1
- package/lib/InteractionBase.d.ts +686 -2
- package/lib/InteractionBase.d.ts.map +1 -1
- package/lib/OAuthGrantsApi.d.ts +2 -4
- package/lib/OAuthGrantsApi.d.ts.map +1 -1
- package/lib/OAuthGrantsApi.js.map +1 -1
- package/lib/OAuthProvidersApi.d.ts +6 -1
- package/lib/OAuthProvidersApi.d.ts.map +1 -1
- package/lib/OAuthProvidersApi.js +5 -0
- package/lib/OAuthProvidersApi.js.map +1 -1
- package/lib/PromptsApi.d.ts +19 -30
- package/lib/PromptsApi.d.ts.map +1 -1
- package/lib/PromptsApi.js +1 -1
- package/lib/PromptsApi.js.map +1 -1
- package/lib/client.d.ts +10 -2
- package/lib/client.d.ts.map +1 -1
- package/lib/store/AgentsApi.d.ts.map +1 -1
- package/lib/store/AgentsApi.js +121 -77
- package/lib/store/AgentsApi.js.map +1 -1
- package/lib/store/ObjectsApi.d.ts +3 -8
- package/lib/store/ObjectsApi.d.ts.map +1 -1
- package/lib/store/ObjectsApi.js +2 -2
- package/lib/store/ObjectsApi.js.map +1 -1
- package/lib/store/TaskApi.d.ts +9 -0
- package/lib/store/TaskApi.d.ts.map +1 -1
- package/lib/store/TaskApi.js +11 -16
- package/lib/store/TaskApi.js.map +1 -1
- package/lib/store/TypeCatalogApi.d.ts +21 -7
- package/lib/store/TypeCatalogApi.d.ts.map +1 -1
- package/lib/store/TypeCatalogApi.js +16 -2
- package/lib/store/TypeCatalogApi.js.map +1 -1
- package/lib/store/TypesApi.d.ts +2 -2
- package/lib/store/TypesApi.d.ts.map +1 -1
- package/lib/store/TypesApi.js.map +1 -1
- package/lib/store/version.d.ts +1 -2
- package/lib/store/version.d.ts.map +1 -1
- package/lib/store/version.js +3 -2
- package/lib/store/version.js.map +1 -1
- package/lib/vertesia-client.js +10 -10
- package/lib/vertesia-client.js.map +1 -1
- package/package.json +5 -5
- package/src/AccountApi.test.ts +30 -0
- package/src/AccountApi.ts +10 -8
- package/src/ApiKeysApi.ts +4 -3
- package/src/EnvironmentsApi.ts +3 -11
- package/src/GroupsApi.ts +2 -0
- package/src/OAuthGrantsApi.ts +2 -1
- package/src/OAuthProvidersApi.ts +6 -1
- package/src/PromptsApi.ts +22 -25
- package/src/store/AgentsApi.stream.test.ts +298 -0
- package/src/store/AgentsApi.ts +120 -68
- package/src/store/ObjectsApi.ts +8 -8
- package/src/store/TaskApi.ts +11 -11
- package/src/store/TypeCatalogApi.ts +21 -7
- package/src/store/TypesApi.ts +2 -1
- package/src/store/version.ts +3 -2
package/src/store/AgentsApi.ts
CHANGED
|
@@ -143,8 +143,8 @@ export class AgentsApi extends ApiTopic {
|
|
|
143
143
|
}
|
|
144
144
|
if (query?.interaction) params.interaction = query.interaction;
|
|
145
145
|
if (query?.started_by) params.started_by = query.started_by;
|
|
146
|
-
if (query?.since) params.since = query.since
|
|
147
|
-
if (query?.until) params.until = query.until
|
|
146
|
+
if (query?.since) params.since = query.since;
|
|
147
|
+
if (query?.until) params.until = query.until;
|
|
148
148
|
if (query?.schedule_id) params.schedule_id = query.schedule_id;
|
|
149
149
|
if (query?.type) params.type = query.type;
|
|
150
150
|
if (query?.run_type)
|
|
@@ -172,8 +172,8 @@ export class AgentsApi extends ApiTopic {
|
|
|
172
172
|
if (query?.categories?.length) params.categories = query.categories.join(',');
|
|
173
173
|
if (query?.tags?.length) params.tags = query.tags.join(',');
|
|
174
174
|
if (query?.content_type_name) params.content_type_name = query.content_type_name;
|
|
175
|
-
if (query?.since) params.since = query.since
|
|
176
|
-
if (query?.until) params.until = query.until
|
|
175
|
+
if (query?.since) params.since = query.since;
|
|
176
|
+
if (query?.until) params.until = query.until;
|
|
177
177
|
if (query?.limit) params.limit = String(query.limit);
|
|
178
178
|
if (query?.offset) params.offset = String(query.offset);
|
|
179
179
|
if (query?.sort?.length) params.sort = query.sort.join(',');
|
|
@@ -326,6 +326,10 @@ export class AgentsApi extends ApiTopic {
|
|
|
326
326
|
let currentSse: EventSource | null = null;
|
|
327
327
|
let interval: ReturnType<typeof setInterval> | null = null;
|
|
328
328
|
let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
|
|
329
|
+
let pollTimer: ReturnType<typeof setTimeout> | null = null;
|
|
330
|
+
let sseRetryTimer: ReturnType<typeof setTimeout> | null = null;
|
|
331
|
+
let isPolling = false;
|
|
332
|
+
let consecutivePollFailures = 0;
|
|
329
333
|
let abortHandler: (() => void) | null = null;
|
|
330
334
|
|
|
331
335
|
const maxReconnectAttempts = 10;
|
|
@@ -338,11 +342,24 @@ export class AgentsApi extends ApiTopic {
|
|
|
338
342
|
return exponentialDelay + jitter;
|
|
339
343
|
};
|
|
340
344
|
|
|
345
|
+
const stopPolling = () => {
|
|
346
|
+
isPolling = false;
|
|
347
|
+
if (pollTimer) {
|
|
348
|
+
clearTimeout(pollTimer);
|
|
349
|
+
pollTimer = null;
|
|
350
|
+
}
|
|
351
|
+
if (sseRetryTimer) {
|
|
352
|
+
clearTimeout(sseRetryTimer);
|
|
353
|
+
sseRetryTimer = null;
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
341
357
|
const cleanup = () => {
|
|
342
358
|
if (reconnectTimer) {
|
|
343
359
|
clearTimeout(reconnectTimer);
|
|
344
360
|
reconnectTimer = null;
|
|
345
361
|
}
|
|
362
|
+
stopPolling();
|
|
346
363
|
if (interval) {
|
|
347
364
|
clearInterval(interval);
|
|
348
365
|
interval = null;
|
|
@@ -372,52 +389,101 @@ export class AgentsApi extends ApiTopic {
|
|
|
372
389
|
// for any messages we missed and exit cleanly once the run is terminal,
|
|
373
390
|
// even if the terminal message never streamed.
|
|
374
391
|
const POLL_INTERVAL_MS = 5000;
|
|
392
|
+
// Polling is a degraded mode: retry the real-time channel periodically so a transient
|
|
393
|
+
// outage (proxy restart, expired credentials that the auth callback later refreshes)
|
|
394
|
+
// does not permanently downgrade the stream.
|
|
395
|
+
const SSE_RETRY_INTERVAL_MS = 60000;
|
|
375
396
|
const isTerminalStatus = (status: unknown): boolean =>
|
|
376
397
|
typeof status === 'string' && ['completed', 'failed', 'cancelled'].includes(status);
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
398
|
+
|
|
399
|
+
// Never swallow a poll failure: while polling, it is the only channel left, so a silent
|
|
400
|
+
// catch turns a recoverable error (expired token, network blip) into an endless silence.
|
|
401
|
+
const warnPollFailure = (what: string, error: unknown) => {
|
|
402
|
+
consecutivePollFailures++;
|
|
380
403
|
console.warn(
|
|
381
|
-
`Agent stream ${id}:
|
|
382
|
-
|
|
404
|
+
`Agent stream ${id}: ${what} failed while polling (consecutive failures: ${consecutivePollFailures}); retrying in ${Math.round(POLL_INTERVAL_MS / 1000)}s:`,
|
|
405
|
+
error instanceof Error ? error.message : error,
|
|
383
406
|
);
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
if (isClosed) return;
|
|
403
|
-
// Exit even when no terminal message ever streams, by reading the run record.
|
|
404
|
-
try {
|
|
405
|
-
const run = (await this.get(`/${id}`)) as { status?: unknown };
|
|
406
|
-
if (isTerminalStatus(run?.status)) {
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const pollTick = async () => {
|
|
410
|
+
if (isClosed || !isPolling) return;
|
|
411
|
+
let polledMessages = false;
|
|
412
|
+
try {
|
|
413
|
+
// Resume from the last message we handed to the caller, whether it came from
|
|
414
|
+
// history, SSE, or an earlier poll. The server returns messages with ts > since.
|
|
415
|
+
const recent = await this.retrieveMessages(id, lastMessageTimestamp || undefined);
|
|
416
|
+
polledMessages = true;
|
|
417
|
+
for (const msg of recent) {
|
|
418
|
+
if (isClosed) return;
|
|
419
|
+
const timestamp = msg.timestamp || 0;
|
|
420
|
+
if (timestamp <= lastMessageTimestamp) continue;
|
|
421
|
+
lastMessageTimestamp = timestamp;
|
|
422
|
+
if (onMessage) onMessage(msg, exit);
|
|
423
|
+
if (isClosed) return;
|
|
424
|
+
if (shouldCloseAgentRunStream(msg, id)) {
|
|
407
425
|
exit(null);
|
|
408
426
|
return;
|
|
409
427
|
}
|
|
410
|
-
} catch {
|
|
411
|
-
// ignore — retry next tick
|
|
412
428
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
429
|
+
} catch (err) {
|
|
430
|
+
warnPollFailure('GET /updates', err);
|
|
431
|
+
}
|
|
432
|
+
if (isClosed || !isPolling) return;
|
|
433
|
+
// Exit even when no terminal message ever streams, by reading the run record.
|
|
434
|
+
try {
|
|
435
|
+
const run = (await this.get(`/${id}`)) as { status?: unknown };
|
|
436
|
+
if (isTerminalStatus(run?.status)) {
|
|
437
|
+
exit(null);
|
|
438
|
+
return;
|
|
418
439
|
}
|
|
419
|
-
|
|
420
|
-
|
|
440
|
+
if (polledMessages) consecutivePollFailures = 0;
|
|
441
|
+
} catch (err) {
|
|
442
|
+
warnPollFailure('run status check', err);
|
|
443
|
+
}
|
|
444
|
+
if (isClosed || !isPolling) return;
|
|
445
|
+
pollTimer = setTimeout(() => {
|
|
446
|
+
pollTimer = null;
|
|
447
|
+
void pollTick();
|
|
448
|
+
}, POLL_INTERVAL_MS);
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
const retrySseAfterPolling = () => {
|
|
452
|
+
sseRetryTimer = null;
|
|
453
|
+
if (isClosed || !isPolling) return;
|
|
454
|
+
stopPolling();
|
|
455
|
+
reconnectAttempts = 0;
|
|
456
|
+
console.log(`Agent stream ${id}: retrying the SSE connection after the polling fallback.`);
|
|
457
|
+
void setupStream('resume');
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
const degradeToPolling = (reason: unknown) => {
|
|
461
|
+
if (isClosed || isPolling) return;
|
|
462
|
+
cleanup();
|
|
463
|
+
isPolling = true;
|
|
464
|
+
consecutivePollFailures = 0;
|
|
465
|
+
console.warn(
|
|
466
|
+
`Agent stream ${id}: SSE unavailable after ${maxReconnectAttempts} attempts; falling back to GET /updates polling every ${Math.round(POLL_INTERVAL_MS / 1000)}s (SSE retried every ${Math.round(SSE_RETRY_INTERVAL_MS / 1000)}s).`,
|
|
467
|
+
reason instanceof Error ? reason.message : reason,
|
|
468
|
+
);
|
|
469
|
+
sseRetryTimer = setTimeout(retrySseAfterPolling, SSE_RETRY_INTERVAL_MS);
|
|
470
|
+
void pollTick();
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
// Schedules attempt N of `maxReconnectAttempts`. `reconnectAttempts` holds the number of
|
|
474
|
+
// the attempt about to run, so the announced counter never exceeds the announced maximum.
|
|
475
|
+
const scheduleReconnect = (reason: unknown) => {
|
|
476
|
+
if (isClosed) return;
|
|
477
|
+
if (reconnectAttempts >= maxReconnectAttempts) {
|
|
478
|
+
degradeToPolling(reason);
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
const delay = calculateBackoffDelay(reconnectAttempts);
|
|
482
|
+
reconnectAttempts++;
|
|
483
|
+
reconnectTimer = setTimeout(() => {
|
|
484
|
+
reconnectTimer = null;
|
|
485
|
+
if (!isClosed) void setupStream('reconnect');
|
|
486
|
+
}, delay);
|
|
421
487
|
};
|
|
422
488
|
|
|
423
489
|
if (signal) {
|
|
@@ -468,7 +534,7 @@ export class AgentsApi extends ApiTopic {
|
|
|
468
534
|
}
|
|
469
535
|
|
|
470
536
|
// 2. Connect to SSE for real-time updates
|
|
471
|
-
const setupStream = async (
|
|
537
|
+
const setupStream = async (mode: 'initial' | 'reconnect' | 'resume' = 'initial') => {
|
|
472
538
|
if (isClosed) return;
|
|
473
539
|
try {
|
|
474
540
|
const EventSourceImpl = await EventSourceProvider();
|
|
@@ -481,6 +547,10 @@ export class AgentsApi extends ApiTopic {
|
|
|
481
547
|
}
|
|
482
548
|
streamUrl.searchParams.set('skipHistory', 'true');
|
|
483
549
|
|
|
550
|
+
// Resolve the credential on every attempt (never reuse the one captured when the
|
|
551
|
+
// stream started): a stream can stay open far longer than the access token TTL,
|
|
552
|
+
// so a pinned token makes every reconnect fail with 401/403 until the retry
|
|
553
|
+
// budget is exhausted. The auth callback owns refreshing.
|
|
484
554
|
const bearerToken = client._auth ? await client._auth() : undefined;
|
|
485
555
|
if (isClosed) return;
|
|
486
556
|
if (!bearerToken) {
|
|
@@ -493,9 +563,9 @@ export class AgentsApi extends ApiTopic {
|
|
|
493
563
|
const token = bearerToken.split(' ')[1];
|
|
494
564
|
streamUrl.searchParams.set('access_token', token);
|
|
495
565
|
|
|
496
|
-
if (
|
|
566
|
+
if (mode === 'reconnect') {
|
|
497
567
|
console.log(
|
|
498
|
-
`Reconnecting to agent stream ${id} (attempt ${reconnectAttempts
|
|
568
|
+
`Reconnecting to agent stream ${id} (attempt ${reconnectAttempts}/${maxReconnectAttempts})`,
|
|
499
569
|
);
|
|
500
570
|
}
|
|
501
571
|
|
|
@@ -507,7 +577,7 @@ export class AgentsApi extends ApiTopic {
|
|
|
507
577
|
let connectionOpenedAt = 0;
|
|
508
578
|
|
|
509
579
|
sse.onopen = () => {
|
|
510
|
-
if (
|
|
580
|
+
if (mode !== 'initial') console.log(`Reconnected to agent stream ${id}`);
|
|
511
581
|
connectionOpenedAt = Date.now();
|
|
512
582
|
};
|
|
513
583
|
|
|
@@ -549,35 +619,17 @@ export class AgentsApi extends ApiTopic {
|
|
|
549
619
|
reconnectAttempts = 0;
|
|
550
620
|
}
|
|
551
621
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
reconnectTimer = setTimeout(() => {
|
|
556
|
-
reconnectTimer = null;
|
|
557
|
-
if (!isClosed) void setupStream(true);
|
|
558
|
-
}, delay);
|
|
559
|
-
} else {
|
|
560
|
-
degradeToPolling(
|
|
561
|
-
new Error(`SSE connection failed after ${maxReconnectAttempts} reconnection attempts`),
|
|
562
|
-
);
|
|
563
|
-
}
|
|
622
|
+
scheduleReconnect(
|
|
623
|
+
new Error(`SSE connection failed after ${maxReconnectAttempts} reconnection attempts`),
|
|
624
|
+
);
|
|
564
625
|
};
|
|
565
626
|
} catch (err) {
|
|
566
627
|
if (isClosed) return;
|
|
567
|
-
|
|
568
|
-
const delay = calculateBackoffDelay(reconnectAttempts);
|
|
569
|
-
reconnectAttempts++;
|
|
570
|
-
reconnectTimer = setTimeout(() => {
|
|
571
|
-
reconnectTimer = null;
|
|
572
|
-
if (!isClosed) void setupStream(true);
|
|
573
|
-
}, delay);
|
|
574
|
-
} else {
|
|
575
|
-
degradeToPolling(err);
|
|
576
|
-
}
|
|
628
|
+
scheduleReconnect(err);
|
|
577
629
|
}
|
|
578
630
|
};
|
|
579
631
|
|
|
580
|
-
void setupStream(
|
|
632
|
+
void setupStream('initial');
|
|
581
633
|
return promise;
|
|
582
634
|
}
|
|
583
635
|
|
package/src/store/ObjectsApi.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ApiTopic } from '@vertesia/api-fetch-client';
|
|
2
2
|
import {
|
|
3
|
+
type BulkObjectCreateOptions,
|
|
3
4
|
type BulkObjectCreateResult,
|
|
4
5
|
type BulkObjectDeleteResult,
|
|
6
|
+
type BulkObjectUpdateOptions,
|
|
5
7
|
type BulkObjectUpdateResult,
|
|
6
8
|
type Collection,
|
|
7
9
|
type ComplexSearchPayload,
|
|
@@ -458,23 +460,21 @@ export class ObjectsApi extends ApiTopic {
|
|
|
458
460
|
return this.del(`/${idOrIds}`);
|
|
459
461
|
}
|
|
460
462
|
|
|
461
|
-
bulkUpdate(
|
|
463
|
+
bulkUpdate(
|
|
464
|
+
updates: Record<string, Record<string, unknown>>,
|
|
465
|
+
options?: BulkObjectUpdateOptions,
|
|
466
|
+
): Promise<BulkObjectUpdateResult> {
|
|
462
467
|
const ids = Object.keys(updates);
|
|
463
468
|
return this.client.runOperation({
|
|
464
469
|
name: 'update',
|
|
465
470
|
ids,
|
|
466
|
-
params: updates,
|
|
471
|
+
params: options ? { updates, ...options } : updates,
|
|
467
472
|
}) as Promise<BulkObjectUpdateResult>;
|
|
468
473
|
}
|
|
469
474
|
|
|
470
475
|
bulkCreate(
|
|
471
476
|
objects: CreateContentObjectPayload[],
|
|
472
|
-
options?:
|
|
473
|
-
collection_id?: string;
|
|
474
|
-
/** @deprecated Events are now always emitted. This suppresses the Temporal-backed delivery targets (workflow, agent, and process) — webhook deliveries still fire. */
|
|
475
|
-
skip_workflows?: boolean;
|
|
476
|
-
processing_priority?: ContentObjectProcessingPriority;
|
|
477
|
-
},
|
|
477
|
+
options?: BulkObjectCreateOptions,
|
|
478
478
|
): Promise<BulkObjectCreateResult> {
|
|
479
479
|
return this.client.runOperation({
|
|
480
480
|
name: 'create',
|
package/src/store/TaskApi.ts
CHANGED
|
@@ -6,17 +6,17 @@ export class TaskApi extends ApiTopic {
|
|
|
6
6
|
super(parent, '/api/v1/tasks');
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return this.get('/', { query
|
|
9
|
+
/**
|
|
10
|
+
* Lists tasks.
|
|
11
|
+
*
|
|
12
|
+
* `status` accepts one value or several, and several go out as a repeated key
|
|
13
|
+
* (`status=a&status=b`) — which is what the parameter publishes: `style: form`, `explode: true`.
|
|
14
|
+
* This used to comma-join the array before sending it. Servers still split each occurrence on
|
|
15
|
+
* commas so SDKs pinned to an older version keep working, but that form was never in the spec,
|
|
16
|
+
* so newly published clients send the declared one.
|
|
17
|
+
*/
|
|
18
|
+
list(query: ListTasksQuery = {}): Promise<Task[]> {
|
|
19
|
+
return this.get('/', { query });
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
retrieve(id: string): Promise<Task> {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
|
|
2
|
-
import type { ContentObjectTypeItem, ContentObjectTypeRef } from '@vertesia/common';
|
|
2
|
+
import type { ContentObjectTypeCatalogEntry, ContentObjectTypeItem, ContentObjectTypeRef } from '@vertesia/common';
|
|
3
3
|
|
|
4
4
|
export class TypeCatalogApi extends ApiTopic {
|
|
5
5
|
constructor(parent: ClientBase) {
|
|
@@ -7,18 +7,22 @@ export class TypeCatalogApi extends ApiTopic {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* List all content types (system + app + stored)
|
|
10
|
+
* List all content types (system + app + stored).
|
|
11
|
+
*
|
|
12
|
+
* Returns `ContentObjectTypeCatalogEntry`, not `ContentObjectTypeItem`, for the same reason
|
|
13
|
+
* {@link resolve} does: the listing includes system and app types, which are declared in code
|
|
14
|
+
* rather than authored, so they carry none of the four audit fields.
|
|
11
15
|
*/
|
|
12
16
|
list(
|
|
13
17
|
query: { tag?: string; limit?: number; offset?: number; layout?: boolean; schema?: boolean } = {},
|
|
14
|
-
): Promise<
|
|
18
|
+
): Promise<ContentObjectTypeCatalogEntry[]> {
|
|
15
19
|
return this.get('/', { query });
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
/**
|
|
19
23
|
* List system types only
|
|
20
24
|
*/
|
|
21
|
-
listSysTypes(tag?: string): Promise<
|
|
25
|
+
listSysTypes(tag?: string): Promise<ContentObjectTypeCatalogEntry[]> {
|
|
22
26
|
return this.get('/sys', {
|
|
23
27
|
query: { tag },
|
|
24
28
|
});
|
|
@@ -27,14 +31,17 @@ export class TypeCatalogApi extends ApiTopic {
|
|
|
27
31
|
/**
|
|
28
32
|
* List all app types from all installed apps
|
|
29
33
|
*/
|
|
30
|
-
listAppTypes(tag?: string): Promise<
|
|
34
|
+
listAppTypes(tag?: string): Promise<ContentObjectTypeCatalogEntry[]> {
|
|
31
35
|
return this.get('/apps', {
|
|
32
36
|
query: { tag },
|
|
33
37
|
});
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
/**
|
|
37
|
-
* List stored types only
|
|
41
|
+
* List stored types only.
|
|
42
|
+
*
|
|
43
|
+
* Stored types are real records, so this one does return `ContentObjectTypeItem` with its audit
|
|
44
|
+
* fields required.
|
|
38
45
|
*/
|
|
39
46
|
listStoredTypes(
|
|
40
47
|
query: { tag?: string; limit?: number; offset?: number; layout?: boolean; schema?: boolean } = {},
|
|
@@ -47,9 +54,16 @@ export class TypeCatalogApi extends ApiTopic {
|
|
|
47
54
|
/**
|
|
48
55
|
* Resolve a type to its full definition.
|
|
49
56
|
* Accepts a string (type ID or code) or a ContentObjectTypeRef.
|
|
57
|
+
*
|
|
58
|
+
* Returns a `ContentObjectTypeCatalogEntry`, which is what the endpoint publishes and is NOT
|
|
59
|
+
* `ContentObjectTypeItem`: the catalog resolves in-code types contributed by plugins, which no
|
|
60
|
+
* user created and no user has modified, so its four audit fields are optional. Declaring the
|
|
61
|
+
* stored type here told callers `created_by` was always a string when resolving `sys:Invoice`
|
|
62
|
+
* hands back a record that has none.
|
|
63
|
+
*
|
|
50
64
|
* @param typeOrRef Type identifier string, or a ContentObjectTypeRef from a content object
|
|
51
65
|
*/
|
|
52
|
-
resolve(typeOrRef: string | ContentObjectTypeRef): Promise<
|
|
66
|
+
resolve(typeOrRef: string | ContentObjectTypeRef): Promise<ContentObjectTypeCatalogEntry> {
|
|
53
67
|
const typeId = typeof typeOrRef === 'string' ? typeOrRef : typeOrRef.id;
|
|
54
68
|
return this.get(`/resolve/${typeId}`);
|
|
55
69
|
}
|
package/src/store/TypesApi.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
FindPayload,
|
|
7
7
|
ObjectTypeSearchPayload,
|
|
8
8
|
ObjectTypeSearchQuery,
|
|
9
|
+
UpdateContentObjectTypePayload,
|
|
9
10
|
} from '@vertesia/common';
|
|
10
11
|
import { TypeCatalogApi } from './TypeCatalogApi.js';
|
|
11
12
|
|
|
@@ -58,7 +59,7 @@ export class TypesApi extends ApiTopic {
|
|
|
58
59
|
return this.get(`/name/${typeName}`);
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
update(typeId: string, payload:
|
|
62
|
+
update(typeId: string, payload: UpdateContentObjectTypePayload): Promise<ContentObjectType> {
|
|
62
63
|
return this.put(`/${typeId}`, {
|
|
63
64
|
payload,
|
|
64
65
|
});
|
package/src/store/version.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export const VERSION = '20260319'; // YYYYMMDD, client versioning for API endpoints. Increment manually for breaking changes
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
// Re-exported, not redeclared: the servers read the same constant when deciding how strictly to
|
|
3
|
+
// hold a request to its schema, so a name only this side knew could not stay a negotiation.
|
|
4
|
+
export { APP_VERSION_HEADER, VERSION_HEADER } from '@vertesia/common';
|