@calimero-network/mero-js 27.0.1 → 27.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 +5 -2
- package/dist/cloud-v2/approvals.d.ts +344 -0
- package/dist/cloud-v2/approvals.js +170 -0
- package/dist/cloud-v2/capabilities.d.ts +8 -1
- package/dist/cloud-v2/capabilities.js +8 -1
- package/dist/cloud-v2/client.d.ts +114 -7
- package/dist/cloud-v2/client.js +149 -6
- package/dist/cloud-v2/errors.d.ts +23 -0
- package/dist/cloud-v2/errors.js +31 -0
- package/dist/cloud-v2/index.d.ts +4 -2
- package/dist/cloud-v2/index.js +2 -1
- package/dist/index.browser.mjs +7 -3
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +294 -8
- package/dist/index.cjs.map +4 -4
- package/dist/index.mjs +294 -8
- package/dist/index.mjs.map +4 -4
- package/package.json +1 -1
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { type AttestationDoc, type CloudPolicy } from './attestation.js';
|
|
13
13
|
import { type PasskeyProvider } from './passkey.js';
|
|
14
|
-
|
|
14
|
+
import { type AppsReport, type ConsentRequest, type ConsentResult, type ConsentStarted, type OpsAppsReport, type OpsOrgsReport, type PageOptions, type PendingApprovals, type PublisherBindingInfo, type PublisherProof, type ReleaseRules } from './approvals.js';
|
|
15
|
+
export { AppError, ArgsTooLarge, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, ReleaseDeadlineError, TrapError, UnavailableError, errorFrom, } from './errors.js';
|
|
15
16
|
export type { Committed } from './errors.js';
|
|
16
17
|
export interface CalimeroSession {
|
|
17
18
|
accountId: string;
|
|
@@ -112,6 +113,23 @@ export interface OrgUpgradeTarget {
|
|
|
112
113
|
cascade?: boolean;
|
|
113
114
|
migrate?: string;
|
|
114
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* `GET /orgs/{org}`: the organization as the caller sees it. Besides its
|
|
118
|
+
* members, teams and metadata, who may approve its releases, the package
|
|
119
|
+
* signing keys it publishes, and whether a passed release deadline has
|
|
120
|
+
* stopped new work on its own set.
|
|
121
|
+
*/
|
|
122
|
+
export interface OrgInfo extends Record<string, unknown> {
|
|
123
|
+
/** Accounts holding `APPROVE_RELEASES` there (owner and admins included). */
|
|
124
|
+
releaseApprovers: string[];
|
|
125
|
+
/** The signer ids (`did:key`) bound to it as publisher. */
|
|
126
|
+
publishes: string[];
|
|
127
|
+
/** `null` unless a deadline stopped new work: approve `release` (or newer) to lift it. */
|
|
128
|
+
newWorkStopped: {
|
|
129
|
+
release: string;
|
|
130
|
+
after: string;
|
|
131
|
+
} | null;
|
|
132
|
+
}
|
|
115
133
|
/**
|
|
116
134
|
* How a call or a view is sent again while the node is unavailable (D70): with
|
|
117
135
|
* the same key, after a backoff that starts at `baseDelayMs` and doubles up to
|
|
@@ -266,8 +284,11 @@ export declare class CalimeroClient {
|
|
|
266
284
|
* Move an app to another release of its package (`{ version }`), another
|
|
267
285
|
* package, or a bundle hash, running its migration. Answers the upgrade's
|
|
268
286
|
* entry; a failed migration rejects with code `UPGRADE_FAILED` (422).
|
|
269
|
-
* Where
|
|
270
|
-
* (`412 CONFIRM_REQUIRED`), which
|
|
287
|
+
* Where owners hold app upgrades, the node asks for the approval of
|
|
288
|
+
* whoever the package's manifest names (`412 CONFIRM_REQUIRED`), which
|
|
289
|
+
* `passkey` gives. Refused (`403`) to a session opened on an app's
|
|
290
|
+
* frontend: an app asks its user with {@link requestConsent} instead. Past
|
|
291
|
+
* a release deadline its approver has not met: {@link ReleaseDeadlineError}.
|
|
271
292
|
*/
|
|
272
293
|
upgradeApp(app: string, target: {
|
|
273
294
|
version?: string;
|
|
@@ -346,7 +367,7 @@ export declare class CalimeroClient {
|
|
|
346
367
|
deleteAlias(alias: string): Promise<void>;
|
|
347
368
|
createOrg(name: string): Promise<string>;
|
|
348
369
|
/** The organization, with the teams this caller reaches or manages. */
|
|
349
|
-
getOrg(org: string): Promise<
|
|
370
|
+
getOrg(org: string): Promise<OrgInfo>;
|
|
350
371
|
/**
|
|
351
372
|
* Delete an organization with its teams, invites and apps (its owner only).
|
|
352
373
|
* The node asks for the owner's passkey (`412 CONFIRM_REQUIRED`), which `passkey` gives.
|
|
@@ -370,8 +391,11 @@ export declare class CalimeroClient {
|
|
|
370
391
|
/**
|
|
371
392
|
* Approve a mero-tee release to hold the apps of `org`, or of this account
|
|
372
393
|
* outside any organization (`org` `null`); `approved: false` withdraws it.
|
|
373
|
-
* Until then, nodes on that release get none of those apps' data.
|
|
374
|
-
* approves with `passkey
|
|
394
|
+
* Until then, nodes on that release get none of those apps' data. For an
|
|
395
|
+
* organization, a member holding `APPROVE_RELEASES` approves with `passkey`;
|
|
396
|
+
* the node binds the release's measurements itself. Refused (`403`) to a
|
|
397
|
+
* session opened on an app's frontend: an app asks its user with
|
|
398
|
+
* {@link requestConsent} instead.
|
|
375
399
|
*/
|
|
376
400
|
approveRelease(org: string | null, version: string, passkey: PasskeyProvider, approved?: boolean): Promise<Record<string, unknown>>;
|
|
377
401
|
/**
|
|
@@ -379,12 +403,95 @@ export declare class CalimeroClient {
|
|
|
379
403
|
* `org`'s apps or this account's own (`org` `null`). `prefixes` `'manifest'`
|
|
380
404
|
* (the default) approves every prefix the package's latest release declares;
|
|
381
405
|
* `replace` sets exactly `prefixes`, which is how one is revoked. Approved
|
|
382
|
-
* with `passkey`.
|
|
406
|
+
* with `passkey`. Refused (`403`) to a session opened on an app's frontend:
|
|
407
|
+
* an app asks with {@link requestConsent} (`kind: 'outbound'`) instead.
|
|
383
408
|
*/
|
|
384
409
|
approveOutbound(org: string | null, pkg: string, passkey: PasskeyProvider, options?: {
|
|
385
410
|
prefixes?: string[] | 'manifest';
|
|
386
411
|
replace?: boolean;
|
|
387
412
|
}): Promise<Record<string, unknown>>;
|
|
413
|
+
/**
|
|
414
|
+
* One page of the report of a scope's apps: an organization's (any member;
|
|
415
|
+
* `404` to anyone else) or, with `org` `null`, the account's own outside any
|
|
416
|
+
* organization (a session bound to an app's frontend: that package's apps).
|
|
417
|
+
* The governance, the scope's approved releases, the releases the cluster's
|
|
418
|
+
* nodes run and whether each is approved, and per app its release, newer
|
|
419
|
+
* releases it may move to, last upgrade and replicas.
|
|
420
|
+
*/
|
|
421
|
+
appsReport(org: string | null, page?: PageOptions): Promise<AppsReport>;
|
|
422
|
+
/** {@link appsReport}, every page, with the apps of all of them in `apps`. */
|
|
423
|
+
appsReportAll(org: string | null): Promise<AppsReport>;
|
|
424
|
+
/** `GET /releases`: the cluster's governance and every release deadline. Public. */
|
|
425
|
+
releaseRules(): Promise<ReleaseRules>;
|
|
426
|
+
/**
|
|
427
|
+
* What waits for a decision in a scope (`org`, or the account's own apps
|
|
428
|
+
* with `null`): mero-tee releases the cluster's nodes run that the scope has
|
|
429
|
+
* not approved, apps with newer releases of their package, and whether a
|
|
430
|
+
* passed deadline stops new work. Read over the sealed channel; act on an
|
|
431
|
+
* item by sending the user to the consent page ({@link requestConsent},
|
|
432
|
+
* `releaseConsent`, `upgradeConsent`).
|
|
433
|
+
*/
|
|
434
|
+
pendingApprovals(org?: string | null): Promise<PendingApprovals>;
|
|
435
|
+
/**
|
|
436
|
+
* Ask the node to ask the user: a release, upgrade or outbound approval
|
|
437
|
+
* that only the account holder may make, decided on the node's own consent
|
|
438
|
+
* page, never in the app. Needs a passkey session (a session bound to the
|
|
439
|
+
* app's frontend is fine). Send the person to the answer's `url`; the page
|
|
440
|
+
* sends them back to `returnTo?request_id=…&result=approved|declined`
|
|
441
|
+
* (`consentReturn`), and {@link consentResult} confirms the decision.
|
|
442
|
+
*/
|
|
443
|
+
requestConsent(request: ConsentRequest): Promise<ConsentStarted>;
|
|
444
|
+
/**
|
|
445
|
+
* {@link requestConsent}, then send the browser to the consent page
|
|
446
|
+
* (`navigate`, by default `window.location.assign`). Answers the request
|
|
447
|
+
* once `navigate` returns: with a popup (`url => window.open(url)`), poll it
|
|
448
|
+
* with {@link waitForConsent}.
|
|
449
|
+
*/
|
|
450
|
+
openConsentPage(request: ConsentRequest, navigate?: (url: string) => void): Promise<ConsentStarted>;
|
|
451
|
+
/** The decision on a consent request (any node answers, for the account that asked). */
|
|
452
|
+
consentResult(requestId: string): Promise<ConsentResult>;
|
|
453
|
+
/**
|
|
454
|
+
* Poll {@link consentResult} until the request is decided, every
|
|
455
|
+
* `intervalMs` (2 s), until `signal` aborts or `expiresAt` (Unix seconds)
|
|
456
|
+
* passes, when it answers the last `pending` result.
|
|
457
|
+
*/
|
|
458
|
+
waitForConsent(requestId: string, options?: {
|
|
459
|
+
intervalMs?: number;
|
|
460
|
+
signal?: AbortSignal;
|
|
461
|
+
expiresAt?: number;
|
|
462
|
+
}): Promise<ConsentResult>;
|
|
463
|
+
/** `GET /publishers/{signerId}`: the cluster name and binding generation a key signs to bind it next. */
|
|
464
|
+
publisherBinding(signerId: string): Promise<PublisherBindingInfo>;
|
|
465
|
+
/**
|
|
466
|
+
* Bind a package signing key to `org`, which then approves the node images
|
|
467
|
+
* every instance of the key's packages runs on, and upgrades those whose
|
|
468
|
+
* package declares `upgrades: publisher`. `proof` is the key's signature
|
|
469
|
+
* over `publisherBindingMessage(cluster, org, signerId, generation)`; a
|
|
470
|
+
* member holding `APPROVE_RELEASES` sends it with `passkey`.
|
|
471
|
+
*/
|
|
472
|
+
bindPublisher(org: string, proof: PublisherProof, passkey: PasskeyProvider): Promise<Record<string, unknown>>;
|
|
473
|
+
/**
|
|
474
|
+
* Upgrade every instance of `pkg` whose release declares `upgrades:
|
|
475
|
+
* publisher`, whoever owns it, as its publisher `org` (a
|
|
476
|
+
* `MANAGE_APPLICATION` holder there), with one passkey approval. Answers
|
|
477
|
+
* the run, kept on the publisher.
|
|
478
|
+
*/
|
|
479
|
+
upgradePublished(org: string, pkg: string, target: {
|
|
480
|
+
version: string;
|
|
481
|
+
migrate?: string;
|
|
482
|
+
}, passkey: PasskeyProvider): Promise<UpgradeRun>;
|
|
483
|
+
/** `GET /ops/apps`: what every app runs, without names or accounts. Operator token (`useApiKey`). */
|
|
484
|
+
opsApps(page?: PageOptions): Promise<OpsAppsReport>;
|
|
485
|
+
/** `GET /ops/orgs`: each organization's approved releases. Operator token. */
|
|
486
|
+
opsOrgs(page?: PageOptions): Promise<OpsOrgsReport>;
|
|
487
|
+
/**
|
|
488
|
+
* Announce when work on images older than `version` ends: from `after` on,
|
|
489
|
+
* a scope that has not approved it (or newer) starts no new work. Operator
|
|
490
|
+
* token.
|
|
491
|
+
*/
|
|
492
|
+
setReleaseDeadline(version: string, after: Date | string): Promise<void>;
|
|
493
|
+
/** Lift a release's deadline. Operator token. */
|
|
494
|
+
liftReleaseDeadline(version: string): Promise<void>;
|
|
388
495
|
/** Add a member, or change their role. */
|
|
389
496
|
setMember(org: string, account: string, role: 'guest' | 'member' | 'admin' | 'owner'): Promise<void>;
|
|
390
497
|
removeMember(org: string, account: string): Promise<Record<string, unknown>>;
|
package/dist/cloud-v2/client.js
CHANGED
|
@@ -13,7 +13,8 @@ import { SealedTransportError, createSealedFetch } from '../sealed/sealed.js';
|
|
|
13
13
|
import { fetchAttestedKey } from './attestation.js';
|
|
14
14
|
import { CalimeroError, ConfirmCancelled, ConfirmRequired, UnavailableError, errorFrom } from './errors.js';
|
|
15
15
|
import { b64url, fromB64url } from './passkey.js';
|
|
16
|
-
|
|
16
|
+
import { pageQuery, pendingApprovalsFrom, } from './approvals.js';
|
|
17
|
+
export { AppError, ArgsTooLarge, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, ReleaseDeadlineError, TrapError, UnavailableError, errorFrom, } from './errors.js';
|
|
17
18
|
/** One URL path segment, so an id cannot reach another route. */
|
|
18
19
|
function seg(value) {
|
|
19
20
|
return encodeURIComponent(value);
|
|
@@ -399,8 +400,11 @@ export class CalimeroClient {
|
|
|
399
400
|
* Move an app to another release of its package (`{ version }`), another
|
|
400
401
|
* package, or a bundle hash, running its migration. Answers the upgrade's
|
|
401
402
|
* entry; a failed migration rejects with code `UPGRADE_FAILED` (422).
|
|
402
|
-
* Where
|
|
403
|
-
* (`412 CONFIRM_REQUIRED`), which
|
|
403
|
+
* Where owners hold app upgrades, the node asks for the approval of
|
|
404
|
+
* whoever the package's manifest names (`412 CONFIRM_REQUIRED`), which
|
|
405
|
+
* `passkey` gives. Refused (`403`) to a session opened on an app's
|
|
406
|
+
* frontend: an app asks its user with {@link requestConsent} instead. Past
|
|
407
|
+
* a release deadline its approver has not met: {@link ReleaseDeadlineError}.
|
|
404
408
|
*/
|
|
405
409
|
upgradeApp(app, target, passkey) {
|
|
406
410
|
const path = `apps/${seg(app)}/upgrade`;
|
|
@@ -578,8 +582,11 @@ export class CalimeroClient {
|
|
|
578
582
|
/**
|
|
579
583
|
* Approve a mero-tee release to hold the apps of `org`, or of this account
|
|
580
584
|
* outside any organization (`org` `null`); `approved: false` withdraws it.
|
|
581
|
-
* Until then, nodes on that release get none of those apps' data.
|
|
582
|
-
* approves with `passkey
|
|
585
|
+
* Until then, nodes on that release get none of those apps' data. For an
|
|
586
|
+
* organization, a member holding `APPROVE_RELEASES` approves with `passkey`;
|
|
587
|
+
* the node binds the release's measurements itself. Refused (`403`) to a
|
|
588
|
+
* session opened on an app's frontend: an app asks its user with
|
|
589
|
+
* {@link requestConsent} instead.
|
|
583
590
|
*/
|
|
584
591
|
async approveRelease(org, version, passkey, approved = true) {
|
|
585
592
|
const path = org === null ? 'auth/releases' : `orgs/${seg(org)}/releases`;
|
|
@@ -590,12 +597,148 @@ export class CalimeroClient {
|
|
|
590
597
|
* `org`'s apps or this account's own (`org` `null`). `prefixes` `'manifest'`
|
|
591
598
|
* (the default) approves every prefix the package's latest release declares;
|
|
592
599
|
* `replace` sets exactly `prefixes`, which is how one is revoked. Approved
|
|
593
|
-
* with `passkey`.
|
|
600
|
+
* with `passkey`. Refused (`403`) to a session opened on an app's frontend:
|
|
601
|
+
* an app asks with {@link requestConsent} (`kind: 'outbound'`) instead.
|
|
594
602
|
*/
|
|
595
603
|
async approveOutbound(org, pkg, passkey, options = {}) {
|
|
596
604
|
const path = org === null ? 'auth/outbound' : `orgs/${seg(org)}/outbound`;
|
|
597
605
|
return this.postConfirmed(path, { package: pkg, prefixes: options.prefixes ?? 'manifest', replace: options.replace ?? false }, passkey);
|
|
598
606
|
}
|
|
607
|
+
// ---------------------------------------------------------------- approvals
|
|
608
|
+
/**
|
|
609
|
+
* One page of the report of a scope's apps: an organization's (any member;
|
|
610
|
+
* `404` to anyone else) or, with `org` `null`, the account's own outside any
|
|
611
|
+
* organization (a session bound to an app's frontend: that package's apps).
|
|
612
|
+
* The governance, the scope's approved releases, the releases the cluster's
|
|
613
|
+
* nodes run and whether each is approved, and per app its release, newer
|
|
614
|
+
* releases it may move to, last upgrade and replicas.
|
|
615
|
+
*/
|
|
616
|
+
appsReport(org, page = {}) {
|
|
617
|
+
const path = org === null ? 'auth/apps' : `orgs/${seg(org)}/apps`;
|
|
618
|
+
return this.get(`${path}${pageQuery(page)}`);
|
|
619
|
+
}
|
|
620
|
+
/** {@link appsReport}, every page, with the apps of all of them in `apps`. */
|
|
621
|
+
async appsReportAll(org) {
|
|
622
|
+
const first = await this.appsReport(org);
|
|
623
|
+
const apps = [...first.apps];
|
|
624
|
+
let next = first.next;
|
|
625
|
+
while (next !== null) {
|
|
626
|
+
const page = await this.appsReport(org, { after: next });
|
|
627
|
+
apps.push(...page.apps);
|
|
628
|
+
next = page.next;
|
|
629
|
+
}
|
|
630
|
+
return { ...first, apps, next: null };
|
|
631
|
+
}
|
|
632
|
+
/** `GET /releases`: the cluster's governance and every release deadline. Public. */
|
|
633
|
+
releaseRules() {
|
|
634
|
+
return this.get('releases');
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* What waits for a decision in a scope (`org`, or the account's own apps
|
|
638
|
+
* with `null`): mero-tee releases the cluster's nodes run that the scope has
|
|
639
|
+
* not approved, apps with newer releases of their package, and whether a
|
|
640
|
+
* passed deadline stops new work. Read over the sealed channel; act on an
|
|
641
|
+
* item by sending the user to the consent page ({@link requestConsent},
|
|
642
|
+
* `releaseConsent`, `upgradeConsent`).
|
|
643
|
+
*/
|
|
644
|
+
async pendingApprovals(org = null) {
|
|
645
|
+
const [report, rules] = await Promise.all([this.appsReportAll(org), this.releaseRules()]);
|
|
646
|
+
return pendingApprovalsFrom(report, rules);
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Ask the node to ask the user: a release, upgrade or outbound approval
|
|
650
|
+
* that only the account holder may make, decided on the node's own consent
|
|
651
|
+
* page, never in the app. Needs a passkey session (a session bound to the
|
|
652
|
+
* app's frontend is fine). Send the person to the answer's `url`; the page
|
|
653
|
+
* sends them back to `returnTo?request_id=…&result=approved|declined`
|
|
654
|
+
* (`consentReturn`), and {@link consentResult} confirms the decision.
|
|
655
|
+
*/
|
|
656
|
+
requestConsent(request) {
|
|
657
|
+
return this.post('consent/requests', request);
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* {@link requestConsent}, then send the browser to the consent page
|
|
661
|
+
* (`navigate`, by default `window.location.assign`). Answers the request
|
|
662
|
+
* once `navigate` returns: with a popup (`url => window.open(url)`), poll it
|
|
663
|
+
* with {@link waitForConsent}.
|
|
664
|
+
*/
|
|
665
|
+
async openConsentPage(request, navigate = (url) => {
|
|
666
|
+
const w = globalThis.window;
|
|
667
|
+
if (!w)
|
|
668
|
+
throw new Error('no window to open the consent page in; pass `navigate`');
|
|
669
|
+
w.location.assign(url);
|
|
670
|
+
}) {
|
|
671
|
+
const started = await this.requestConsent(request);
|
|
672
|
+
navigate(started.url);
|
|
673
|
+
return started;
|
|
674
|
+
}
|
|
675
|
+
/** The decision on a consent request (any node answers, for the account that asked). */
|
|
676
|
+
consentResult(requestId) {
|
|
677
|
+
return this.get(`consent/${seg(requestId)}/result`);
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Poll {@link consentResult} until the request is decided, every
|
|
681
|
+
* `intervalMs` (2 s), until `signal` aborts or `expiresAt` (Unix seconds)
|
|
682
|
+
* passes, when it answers the last `pending` result.
|
|
683
|
+
*/
|
|
684
|
+
async waitForConsent(requestId, options = {}) {
|
|
685
|
+
const interval = options.intervalMs ?? 2000;
|
|
686
|
+
for (;;) {
|
|
687
|
+
const result = await this.consentResult(requestId);
|
|
688
|
+
if (result.status !== 'pending')
|
|
689
|
+
return result;
|
|
690
|
+
if (options.signal?.aborted)
|
|
691
|
+
return result;
|
|
692
|
+
if (options.expiresAt !== undefined && Date.now() / 1000 >= options.expiresAt)
|
|
693
|
+
return result;
|
|
694
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
/** `GET /publishers/{signerId}`: the cluster name and binding generation a key signs to bind it next. */
|
|
698
|
+
publisherBinding(signerId) {
|
|
699
|
+
return this.get(`publishers/${seg(signerId)}`);
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Bind a package signing key to `org`, which then approves the node images
|
|
703
|
+
* every instance of the key's packages runs on, and upgrades those whose
|
|
704
|
+
* package declares `upgrades: publisher`. `proof` is the key's signature
|
|
705
|
+
* over `publisherBindingMessage(cluster, org, signerId, generation)`; a
|
|
706
|
+
* member holding `APPROVE_RELEASES` sends it with `passkey`.
|
|
707
|
+
*/
|
|
708
|
+
bindPublisher(org, proof, passkey) {
|
|
709
|
+
return this.postConfirmed(`orgs/${seg(org)}/publishers`, { ...proof }, passkey);
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Upgrade every instance of `pkg` whose release declares `upgrades:
|
|
713
|
+
* publisher`, whoever owns it, as its publisher `org` (a
|
|
714
|
+
* `MANAGE_APPLICATION` holder there), with one passkey approval. Answers
|
|
715
|
+
* the run, kept on the publisher.
|
|
716
|
+
*/
|
|
717
|
+
upgradePublished(org, pkg, target, passkey) {
|
|
718
|
+
return this.postConfirmed(`orgs/${seg(org)}/packages/${seg(pkg)}/upgrade`, { ...target }, passkey);
|
|
719
|
+
}
|
|
720
|
+
// ---------------------------------------------------------------- operator
|
|
721
|
+
/** `GET /ops/apps`: what every app runs, without names or accounts. Operator token (`useApiKey`). */
|
|
722
|
+
opsApps(page = {}) {
|
|
723
|
+
return this.get(`ops/apps${pageQuery(page)}`);
|
|
724
|
+
}
|
|
725
|
+
/** `GET /ops/orgs`: each organization's approved releases. Operator token. */
|
|
726
|
+
opsOrgs(page = {}) {
|
|
727
|
+
return this.get(`ops/orgs${pageQuery(page)}`);
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Announce when work on images older than `version` ends: from `after` on,
|
|
731
|
+
* a scope that has not approved it (or newer) starts no new work. Operator
|
|
732
|
+
* token.
|
|
733
|
+
*/
|
|
734
|
+
async setReleaseDeadline(version, after) {
|
|
735
|
+
const at = typeof after === 'string' ? after : after.toISOString();
|
|
736
|
+
await this.post(`ops/releases/${seg(version)}/deadline`, { after: at });
|
|
737
|
+
}
|
|
738
|
+
/** Lift a release's deadline. Operator token. */
|
|
739
|
+
async liftReleaseDeadline(version) {
|
|
740
|
+
await this.delete(`ops/releases/${seg(version)}/deadline`);
|
|
741
|
+
}
|
|
599
742
|
/** Add a member, or change their role. */
|
|
600
743
|
async setMember(org, account, role) {
|
|
601
744
|
await this.post(`orgs/${seg(org)}/members`, { account, role });
|
|
@@ -52,6 +52,29 @@ export declare class ArgsTooLarge extends CalimeroError {
|
|
|
52
52
|
export declare class IdempotencyMismatch extends CalimeroError {
|
|
53
53
|
constructor(message: string, details?: Record<string, unknown>);
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* `409 RELEASE_DEADLINE`: a mero-tee release's deadline has passed and the
|
|
57
|
+
* set that governs this work (the app's publisher's, or its owner's) has not
|
|
58
|
+
* approved it or a newer one, so new work (creating an app, installing a
|
|
59
|
+
* release, upgrading an app) is refused. Apps already running keep running.
|
|
60
|
+
* Approving `release` lifts it at once.
|
|
61
|
+
*/
|
|
62
|
+
export declare class ReleaseDeadlineError extends CalimeroError {
|
|
63
|
+
/** The release to approve. */
|
|
64
|
+
readonly release: string;
|
|
65
|
+
/** Its deadline, RFC 3339 (`''` when the node did not say). */
|
|
66
|
+
readonly after: string;
|
|
67
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* `409 CONSENT_STALE`: what a consent page showed (the app's bundle, the
|
|
71
|
+
* target release, the release's measurements) changed before the person
|
|
72
|
+
* approved. Nothing was approved; ask for a new consent request so they see
|
|
73
|
+
* the new facts.
|
|
74
|
+
*/
|
|
75
|
+
export declare class ConsentStale extends CalimeroError {
|
|
76
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
77
|
+
}
|
|
55
78
|
/**
|
|
56
79
|
* `422 APP_ERROR`: the app refused the call. `appCode` is the app's declared
|
|
57
80
|
* error (`Taken`, `Forbidden`, ...) and `fields` its named fields. The call was
|
package/dist/cloud-v2/errors.js
CHANGED
|
@@ -73,6 +73,33 @@ export class IdempotencyMismatch extends CalimeroError {
|
|
|
73
73
|
this.name = 'IdempotencyMismatch';
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* `409 RELEASE_DEADLINE`: a mero-tee release's deadline has passed and the
|
|
78
|
+
* set that governs this work (the app's publisher's, or its owner's) has not
|
|
79
|
+
* approved it or a newer one, so new work (creating an app, installing a
|
|
80
|
+
* release, upgrading an app) is refused. Apps already running keep running.
|
|
81
|
+
* Approving `release` lifts it at once.
|
|
82
|
+
*/
|
|
83
|
+
export class ReleaseDeadlineError extends CalimeroError {
|
|
84
|
+
constructor(message, details = {}) {
|
|
85
|
+
super(409, 'RELEASE_DEADLINE', message, details);
|
|
86
|
+
this.name = 'ReleaseDeadlineError';
|
|
87
|
+
this.release = typeof details.release === 'string' ? details.release : '';
|
|
88
|
+
this.after = typeof details.after === 'string' ? details.after : '';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* `409 CONSENT_STALE`: what a consent page showed (the app's bundle, the
|
|
93
|
+
* target release, the release's measurements) changed before the person
|
|
94
|
+
* approved. Nothing was approved; ask for a new consent request so they see
|
|
95
|
+
* the new facts.
|
|
96
|
+
*/
|
|
97
|
+
export class ConsentStale extends CalimeroError {
|
|
98
|
+
constructor(message, details = {}) {
|
|
99
|
+
super(409, 'CONSENT_STALE', message, details);
|
|
100
|
+
this.name = 'ConsentStale';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
76
103
|
/**
|
|
77
104
|
* `422 APP_ERROR`: the app refused the call. `appCode` is the app's declared
|
|
78
105
|
* error (`Taken`, `Forbidden`, ...) and `fields` its named fields. The call was
|
|
@@ -151,6 +178,10 @@ export function errorFrom(status, body, retryAfterHeader) {
|
|
|
151
178
|
return new NotFound(message, details);
|
|
152
179
|
case '409 IDEMPOTENCY_MISMATCH':
|
|
153
180
|
return new IdempotencyMismatch(message, details);
|
|
181
|
+
case '409 RELEASE_DEADLINE':
|
|
182
|
+
return new ReleaseDeadlineError(message, details);
|
|
183
|
+
case '409 CONSENT_STALE':
|
|
184
|
+
return new ConsentStale(message, details);
|
|
154
185
|
case '412 CONFIRM_REQUIRED':
|
|
155
186
|
return new ConfirmRequired(message, details);
|
|
156
187
|
case '413 ARGS_TOO_LARGE':
|
package/dist/cloud-v2/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
export { CalimeroClient } from './client.js';
|
|
2
|
-
export { AppError, ArgsTooLarge, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, NotFound, TrapError, UnavailableError, errorFrom, } from './errors.js';
|
|
2
|
+
export { AppError, ArgsTooLarge, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, ReleaseDeadlineError, TrapError, UnavailableError, errorFrom, } from './errors.js';
|
|
3
3
|
export type { Committed } from './errors.js';
|
|
4
|
-
export type { AppInfo, BlobInfo, CallResult, CalimeroClientOptions, CloudEvent, CalimeroSession, PackageInfo, PackageInstalled, CloudRetryOptions, OrgUpgradeTarget, PresenceEntry, UpgradeRun, ViewResult, } from './client.js';
|
|
4
|
+
export type { AppInfo, BlobInfo, CallResult, CalimeroClientOptions, CloudEvent, CalimeroSession, PackageInfo, PackageInstalled, CloudRetryOptions, OrgInfo, OrgUpgradeTarget, PresenceEntry, UpgradeRun, ViewResult, } from './client.js';
|
|
5
5
|
export { claimedRelease, fetchAttestedKey, MOCK_QUOTE_HEADER } from './attestation.js';
|
|
6
6
|
export type { AttestationDoc, CloudPolicy, CloudReleasePolicy } from './attestation.js';
|
|
7
7
|
export { browserPasskey, b64url, fromB64url } from './passkey.js';
|
|
8
8
|
export type { AssertionJSON, PasskeyProvider, RegistrationJSON } from './passkey.js';
|
|
9
|
+
export { MAX_REPORT_PAGE, RELEASE_VERIFIER, compareVersions, consentReturn, pageQuery, pendingApprovalsFrom, publisherBindingBytes, publisherBindingMessage, releaseConsent, releaseNotesUrl, stalledBy, upgradeConsent, verifyReleaseUrl, withdrawConsent, } from './approvals.js';
|
|
10
|
+
export type { ActorKind, AppsReport, Authority, ClusterRelease, ConsentReleaseModel, ConsentRequest, ConsentResult, ConsentScope, ConsentStarted, ConsentStatus, Governance, LastUpgrade, OpsAppsReport, OpsOrgsReport, PageOptions, PendingApprovals, PendingRelease, PendingUpgrade, PublisherBindingInfo, PublisherProof, ReleaseDeadline, ReleaseRules, ReportScope, ReportedApp, ReportedBundle, ReportedRelease, ReportedReplica, UpgradeAuthority, } from './approvals.js';
|
|
9
11
|
export { DEFAULT_ORG_CAPABILITIES, ORG_CAPABILITIES, orgCapabilities } from './capabilities.js';
|
|
10
12
|
export type { OrgCapability } from './capabilities.js';
|
package/dist/cloud-v2/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { CalimeroClient } from './client.js';
|
|
2
|
-
export { AppError, ArgsTooLarge, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, NotFound, TrapError, UnavailableError, errorFrom, } from './errors.js';
|
|
2
|
+
export { AppError, ArgsTooLarge, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, ReleaseDeadlineError, TrapError, UnavailableError, errorFrom, } from './errors.js';
|
|
3
3
|
export { claimedRelease, fetchAttestedKey, MOCK_QUOTE_HEADER } from './attestation.js';
|
|
4
4
|
export { browserPasskey, b64url, fromB64url } from './passkey.js';
|
|
5
|
+
export { MAX_REPORT_PAGE, RELEASE_VERIFIER, compareVersions, consentReturn, pageQuery, pendingApprovalsFrom, publisherBindingBytes, publisherBindingMessage, releaseConsent, releaseNotesUrl, stalledBy, upgradeConsent, verifyReleaseUrl, withdrawConsent, } from './approvals.js';
|
|
5
6
|
export { DEFAULT_ORG_CAPABILITIES, ORG_CAPABILITIES, orgCapabilities } from './capabilities.js';
|