@cardstack/boxel-cli 0.12.0-unstable.12 → 0.12.0-unstable.14
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/bundled-test-harness/assets/{ai-module-creation-test-D9FuBmi8.js → ai-module-creation-test-BuOdKEfn.js} +1 -1
- package/bundled-test-harness/assets/{app-B6ALqYQD.js → app-DFQ4JqlP.js} +2 -2
- package/bundled-test-harness/assets/{binary-upload-dedupe-test-eI1yGxdL.js → binary-upload-dedupe-test-jbrJQUz0.js} +1 -1
- package/bundled-test-harness/assets/{can-invoke-test-5enpsRYF.js → can-invoke-test-DoWzbZ8k.js} +1 -1
- package/bundled-test-harness/assets/{card-chooser-paging-test-CdtsXIpu.js → card-chooser-paging-test-VRmsX6sY.js} +1 -1
- package/bundled-test-harness/assets/{card-chooser-test-CpUK3_Su.js → card-chooser-test-CgrV_vWi.js} +1 -1
- package/bundled-test-harness/assets/{card-def-field-def-relationships-test-Z1O-t73y.js → card-def-field-def-relationships-test-BHQoFm4_.js} +1 -1
- package/bundled-test-harness/assets/{card-delete-test-DI16JAzu.js → card-delete-test-DCmoRd03.js} +1 -1
- package/bundled-test-harness/assets/{codeblocks-test-DEaQeMcn.js → codeblocks-test-DQU6dnQH.js} +1 -1
- package/bundled-test-harness/assets/{compaction-test-DliwzHTd.js → compaction-test-B7JuwjQ7.js} +1 -1
- package/bundled-test-harness/assets/{container-BHHKErdI.js → container-CwRfjGxi.js} +1 -1
- package/bundled-test-harness/assets/{create-listing-modal-test-BZiD6UL9.js → create-listing-modal-test-CxkuYwnv.js} +1 -1
- package/bundled-test-harness/assets/{debug-message-test-D7VEbny3.js → debug-message-test-CyrcsddQ.js} +1 -1
- package/bundled-test-harness/assets/{fallback-banner-live-delete-test-DwXohU1S.js → fallback-banner-live-delete-test-Bxxt9EBl.js} +1 -1
- package/bundled-test-harness/assets/{fallback-banner-test-jEmNTOeh.js → fallback-banner-test-BzmDOq0F.js} +1 -1
- package/bundled-test-harness/assets/{fallback-models-test-BfgkQJ8l.js → fallback-models-test-mZvUg3zI.js} +1 -1
- package/bundled-test-harness/assets/{file-attachment-test-CaX44AfG.js → file-attachment-test-ybs1HRMC.js} +1 -1
- package/bundled-test-harness/assets/{general-test-zz1QVTIv.js → general-test-jB4EQTh8.js} +1 -1
- package/bundled-test-harness/assets/{main-CYiHxOxo.js → main-uvgWNg1U.js} +1 -1
- package/bundled-test-harness/assets/{model-cost-tier-test-DcEeQJwF.js → model-cost-tier-test-BPCl0EeO.js} +1 -1
- package/bundled-test-harness/assets/{operator-mode-card-chooser-test-DYSf_9jJ.js → operator-mode-card-chooser-test-D8RfBsEc.js} +1 -1
- package/bundled-test-harness/assets/{operator-mode-links-test-BA3gjmzY.js → operator-mode-links-test-DmpvnpHI.js} +1 -1
- package/bundled-test-harness/assets/{operator-mode-test-C6iSqlfM.js → operator-mode-test-BeCWE8qH.js} +1 -1
- package/bundled-test-harness/assets/{operator-mode-ui-test-BFGw2suP.js → operator-mode-ui-test-D0k0pr1Z.js} +1 -1
- package/bundled-test-harness/assets/{overlay-menu-items-test-Ch351wNL.js → overlay-menu-items-test-l4-oOOi5.js} +1 -1
- package/bundled-test-harness/assets/{panel-B8BaMllL.js → panel-8nNZbvzg.js} +16 -4
- package/bundled-test-harness/assets/{past-sessions-test-DoVlENnJ.js → past-sessions-test-DrJ_h58w.js} +1 -1
- package/bundled-test-harness/assets/{permission-checking-realm-test-BrBeo81O.js → permission-checking-realm-test-CL_nySH1.js} +1 -1
- package/bundled-test-harness/assets/{quick-look-test-InFXyTqv.js → quick-look-test-DMfAGvgd.js} +1 -1
- package/bundled-test-harness/assets/{realm-api-keys-test-Bgg-gi56.js → realm-api-keys-test-DVkuepc8.js} +1 -1
- package/bundled-test-harness/assets/{realm-config-policy-standing-test-BIEwUQYA.js → realm-config-policy-standing-test-DXS8kYVC.js} +1 -1
- package/bundled-test-harness/assets/{realm-config-routing-rule-edit-test-CDj8rdvZ.js → realm-config-routing-rule-edit-test-CPTifvXx.js} +1 -1
- package/bundled-test-harness/assets/{realm-config-settings-test-Csi-H8bJ.js → realm-config-settings-test-Civ3ZVxT.js} +1 -1
- package/bundled-test-harness/assets/{reasoning-test-MNcXjMV3.js → reasoning-test-DYSQdtDZ.js} +1 -1
- package/bundled-test-harness/assets/{room-message-test-DxMyOu8L.js → room-message-test-CSbclniG.js} +1 -1
- package/bundled-test-harness/assets/{run-realm-code-test-DTXPkVu_.js → run-realm-code-test-B9KJIaYx.js} +81 -0
- package/bundled-test-harness/assets/{scrolling-test-6-Soq39G.js → scrolling-test-nDHEhgzp.js} +2 -2
- package/bundled-test-harness/assets/{sending-test-DXOw4MlE.js → sending-test-CjrOIeGV.js} +1 -1
- package/bundled-test-harness/assets/{skills-test-BiUE1x5l.js → skills-test-Be4crUyO.js} +1 -1
- package/bundled-test-harness/assets/{store-test-Cbf2xZ40.js → store-test-BCyLVXZY.js} +1 -1
- package/bundled-test-harness/assets/{tests-Blos5s0A.js → tests-DbU4zMsp.js} +43 -43
- package/bundled-test-harness/assets/{text-input-validator-test-BxG8Dc2i.js → text-input-validator-test-DZuVdEKj.js} +1 -1
- package/bundled-test-harness/assets/{to-device-streaming-test-CGuKaubC.js → to-device-streaming-test-C3i5WmnX.js} +1 -1
- package/bundled-test-harness/assets/{token-usage-test-DJJmXyD8.js → token-usage-test-1AWgVaXO.js} +1 -1
- package/bundled-test-harness/assets/{tools-test-DxDvBhPf.js → tools-test-BSmxEyfO.js} +1 -1
- package/bundled-test-harness/assets/{turn-settling-test-Co2Dmnzm.js → turn-settling-test-S3ROiZu9.js} +1 -1
- package/bundled-test-harness/index.html +5 -5
- package/bundled-test-harness/tests/index.html +5 -5
- package/bundled-types/host-app/lib/secure-sign-in.ts +5 -3
- package/bundled-types/host-app/services/matrix-service.ts +3 -2
- package/bundled-types/host-app/services/tool-service.ts +36 -5
- package/dist/index.js +290 -290
- package/package.json +1 -1
- package/src/commands/keys/approve.ts +2 -1
- package/src/commands/keys/index.ts +48 -3
- package/src/commands/keys/manage.ts +257 -21
- package/src/lib/key-bindings.ts +2 -1
- package/src/lib/user-keys.ts +174 -4
package/src/lib/user-keys.ts
CHANGED
|
@@ -95,13 +95,40 @@ export interface UserKeyMetadata {
|
|
|
95
95
|
oauth?: OAuthKeyDescription;
|
|
96
96
|
// Only a google-service-account key has one.
|
|
97
97
|
serviceAccount?: ServiceAccountDetails;
|
|
98
|
+
// The limits in force, defaults filled in.
|
|
99
|
+
limits?: KeyLimits;
|
|
98
100
|
createdAt: string;
|
|
99
101
|
updatedAt: string;
|
|
100
102
|
// Whether its owner lets people who aren't signed in use it, wherever a
|
|
101
|
-
// realm's policy lets them make the call, and the optional
|
|
102
|
-
// calls a day, all together, in every realm it is shared into.
|
|
103
|
+
// realm's policy lets them make the call, and the optional caps on their
|
|
104
|
+
// calls a day and a month, all together, in every realm it is shared into.
|
|
103
105
|
anonymous?: boolean;
|
|
104
106
|
anonymousDailyCap?: number | null;
|
|
107
|
+
anonymousMonthlyCap?: number | null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// A key's anonymous caps as a clause that ends a sentence about people who
|
|
111
|
+
// aren't signed in: ", up to 100 calls a day and 1000 a month all together",
|
|
112
|
+
// or nothing where the key has neither.
|
|
113
|
+
export function anonymousCapsClause({
|
|
114
|
+
anonymousDailyCap,
|
|
115
|
+
anonymousMonthlyCap,
|
|
116
|
+
}: {
|
|
117
|
+
anonymousDailyCap?: number | null;
|
|
118
|
+
anonymousMonthlyCap?: number | null;
|
|
119
|
+
}): string {
|
|
120
|
+
let daily = anonymousDailyCap ?? null;
|
|
121
|
+
let monthly = anonymousMonthlyCap ?? null;
|
|
122
|
+
if (daily === null && monthly === null) {
|
|
123
|
+
return '';
|
|
124
|
+
}
|
|
125
|
+
let caps =
|
|
126
|
+
daily !== null && monthly !== null
|
|
127
|
+
? `${daily} calls a day and ${monthly} a month`
|
|
128
|
+
: daily !== null
|
|
129
|
+
? `${daily} calls a day`
|
|
130
|
+
: `${monthly} calls a month`;
|
|
131
|
+
return `, up to ${caps} all together`;
|
|
105
132
|
}
|
|
106
133
|
|
|
107
134
|
export interface KeyShare {
|
|
@@ -118,6 +145,9 @@ export interface KeyShare {
|
|
|
118
145
|
suspensionReason: string | null;
|
|
119
146
|
suspendedBy: string | null;
|
|
120
147
|
suspendedAt: string | null;
|
|
148
|
+
// The limits in force, defaults filled in; listed for the key's owner and
|
|
149
|
+
// the realm's direct writers.
|
|
150
|
+
limits?: KeyLimits;
|
|
121
151
|
createdAt: string;
|
|
122
152
|
updatedAt: string;
|
|
123
153
|
// In a realm's listing: the operations the share is approved for there,
|
|
@@ -125,6 +155,22 @@ export interface KeyShare {
|
|
|
125
155
|
operations?: KeyShareOperation[];
|
|
126
156
|
}
|
|
127
157
|
|
|
158
|
+
// How much of a key interactive calls may spend: a token bucket per caller
|
|
159
|
+
// (`rateBurst` calls at once, refilled at `rateRefillPerMinute`) and the calls
|
|
160
|
+
// the share or key serves in a UTC day and month, across every caller.
|
|
161
|
+
export interface KeyLimits {
|
|
162
|
+
rateBurst: number;
|
|
163
|
+
rateRefillPerMinute: number;
|
|
164
|
+
dailyBudget: number;
|
|
165
|
+
monthlyBudget: number;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// A change to some of a key's limits: a limit left out keeps what it was, and
|
|
169
|
+
// null puts it back to the platform's default.
|
|
170
|
+
export type KeyLimitChanges = Partial<{
|
|
171
|
+
[limit in keyof KeyLimits]: number | null;
|
|
172
|
+
}>;
|
|
173
|
+
|
|
128
174
|
export interface KeyShareOperation {
|
|
129
175
|
bindingId: string;
|
|
130
176
|
type: { module: string; name: string };
|
|
@@ -135,6 +181,50 @@ export interface KeyShareOperation {
|
|
|
135
181
|
destination?: string;
|
|
136
182
|
}
|
|
137
183
|
|
|
184
|
+
// What a share or a personal key has served, as the realm server records it.
|
|
185
|
+
// The counts cover `since` (the start of the UTC month) until now; the
|
|
186
|
+
// budgets' `used` is what the limits count, interactive calls charged this
|
|
187
|
+
// UTC day and month.
|
|
188
|
+
export interface KeyUsage {
|
|
189
|
+
id: string;
|
|
190
|
+
limits: KeyLimits;
|
|
191
|
+
budgets: {
|
|
192
|
+
day: KeyBudgetUse;
|
|
193
|
+
month: KeyBudgetUse;
|
|
194
|
+
};
|
|
195
|
+
since: string;
|
|
196
|
+
calls: number;
|
|
197
|
+
lastUse: {
|
|
198
|
+
at: string;
|
|
199
|
+
caller: string | null;
|
|
200
|
+
operation: string;
|
|
201
|
+
outcome: 'sent' | 'refused' | 'failed';
|
|
202
|
+
// Set when the caller is someone the reader can't see in the realm.
|
|
203
|
+
withheld?: boolean;
|
|
204
|
+
} | null;
|
|
205
|
+
// A null caller is a call with no session; one marked `withheld` is every
|
|
206
|
+
// caller the reader can't see in the realm, counted together.
|
|
207
|
+
topCallers: { caller: string | null; calls: number; withheld?: boolean }[];
|
|
208
|
+
refusals: { code: string; count: number }[];
|
|
209
|
+
vendorOutcomes: { status: number; count: number; outcome?: string }[];
|
|
210
|
+
grants: {
|
|
211
|
+
id: string;
|
|
212
|
+
host: string;
|
|
213
|
+
destination: string;
|
|
214
|
+
state: 'active' | 'rejected';
|
|
215
|
+
rejectedAt: string | null;
|
|
216
|
+
lastForbiddenAt: string | null;
|
|
217
|
+
}[];
|
|
218
|
+
// Whether the reader may change the limits: only the key's owner may.
|
|
219
|
+
canEditLimits: boolean;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export interface KeyBudgetUse {
|
|
223
|
+
used: number;
|
|
224
|
+
budget: number;
|
|
225
|
+
resetsAt: string;
|
|
226
|
+
}
|
|
227
|
+
|
|
138
228
|
export interface KeyWriteTarget {
|
|
139
229
|
action: KeyWriteAction;
|
|
140
230
|
keyId?: string;
|
|
@@ -246,6 +336,7 @@ export async function addUserKey(
|
|
|
246
336
|
ticket,
|
|
247
337
|
anonymous,
|
|
248
338
|
anonymousDailyCap,
|
|
339
|
+
anonymousMonthlyCap,
|
|
249
340
|
...entered
|
|
250
341
|
}: {
|
|
251
342
|
name: string;
|
|
@@ -253,6 +344,7 @@ export async function addUserKey(
|
|
|
253
344
|
ticket?: string;
|
|
254
345
|
anonymous?: boolean;
|
|
255
346
|
anonymousDailyCap?: number;
|
|
347
|
+
anonymousMonthlyCap?: number;
|
|
256
348
|
} & EnteredValue,
|
|
257
349
|
fetchFn: FetchFn = fetch,
|
|
258
350
|
): Promise<UserKeyMetadata> {
|
|
@@ -275,6 +367,7 @@ export async function addUserKey(
|
|
|
275
367
|
...valueAttributes(entered),
|
|
276
368
|
...(anonymous ? { anonymous: true } : {}),
|
|
277
369
|
...(anonymousDailyCap !== undefined ? { anonymousDailyCap } : {}),
|
|
370
|
+
...(anonymousMonthlyCap !== undefined ? { anonymousMonthlyCap } : {}),
|
|
278
371
|
},
|
|
279
372
|
},
|
|
280
373
|
meta: { ticket },
|
|
@@ -311,7 +404,8 @@ export async function realmOpensToAnonymous(
|
|
|
311
404
|
}
|
|
312
405
|
|
|
313
406
|
// Sets whether people who aren't signed in may use one of the user's keys,
|
|
314
|
-
// and the optional
|
|
407
|
+
// and the optional caps on their calls a day and a month. A cap left out is
|
|
408
|
+
// kept, and null removes it. Takes a secure session.
|
|
315
409
|
export async function setUserKeyAnonymousUse(
|
|
316
410
|
realmServerUrl: string,
|
|
317
411
|
token: string,
|
|
@@ -319,7 +413,14 @@ export async function setUserKeyAnonymousUse(
|
|
|
319
413
|
keyId,
|
|
320
414
|
anonymous,
|
|
321
415
|
anonymousDailyCap,
|
|
322
|
-
|
|
416
|
+
anonymousMonthlyCap,
|
|
417
|
+
}: {
|
|
418
|
+
keyId: string;
|
|
419
|
+
anonymous: boolean;
|
|
420
|
+
// A cap left out is kept, and null removes it.
|
|
421
|
+
anonymousDailyCap?: number | null;
|
|
422
|
+
anonymousMonthlyCap?: number | null;
|
|
423
|
+
},
|
|
323
424
|
fetchFn: FetchFn = fetch,
|
|
324
425
|
): Promise<UserKeyMetadata> {
|
|
325
426
|
let json = await realmServerRequest(
|
|
@@ -335,6 +436,9 @@ export async function setUserKeyAnonymousUse(
|
|
|
335
436
|
attributes: {
|
|
336
437
|
anonymous,
|
|
337
438
|
...(anonymousDailyCap !== undefined ? { anonymousDailyCap } : {}),
|
|
439
|
+
...(anonymousMonthlyCap !== undefined
|
|
440
|
+
? { anonymousMonthlyCap }
|
|
441
|
+
: {}),
|
|
338
442
|
},
|
|
339
443
|
},
|
|
340
444
|
},
|
|
@@ -629,3 +733,69 @@ export async function completeOAuthConnect(
|
|
|
629
733
|
);
|
|
630
734
|
return json.data.attributes;
|
|
631
735
|
}
|
|
736
|
+
|
|
737
|
+
// The user's own share labelled `label` in `realm`, or else the realm's share
|
|
738
|
+
// of that label, for a direct writer of the realm to read or to be refused
|
|
739
|
+
// changing.
|
|
740
|
+
export async function findShare(
|
|
741
|
+
realmServerUrl: string,
|
|
742
|
+
token: string,
|
|
743
|
+
{ realm, label }: { realm: string; label: string },
|
|
744
|
+
fetchFn: FetchFn = fetch,
|
|
745
|
+
): Promise<KeyShare> {
|
|
746
|
+
let canonical = canonicalRealmUrl(realm);
|
|
747
|
+
let own = (await listOwnShares(realmServerUrl, token, {}, fetchFn)).find(
|
|
748
|
+
(share) => share.realm === canonical && share.label === label,
|
|
749
|
+
);
|
|
750
|
+
if (own) {
|
|
751
|
+
return own;
|
|
752
|
+
}
|
|
753
|
+
return findByLabel(
|
|
754
|
+
await listRealmShares(realmServerUrl, token, realm, fetchFn),
|
|
755
|
+
realm,
|
|
756
|
+
label,
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// Sets some of a share's or a personal key's limits, which only the key's
|
|
761
|
+
// owner may, with a session signed in on the secure origin. Answers the
|
|
762
|
+
// limits in force afterwards, defaults filled in.
|
|
763
|
+
export async function setKeyLimits(
|
|
764
|
+
realmServerUrl: string,
|
|
765
|
+
token: string,
|
|
766
|
+
target: { shareId: string } | { keyId: string },
|
|
767
|
+
changes: KeyLimitChanges,
|
|
768
|
+
fetchFn: FetchFn = fetch,
|
|
769
|
+
): Promise<KeyLimits> {
|
|
770
|
+
let path =
|
|
771
|
+
'shareId' in target
|
|
772
|
+
? `_key-shares/${encodeURIComponent(target.shareId)}/limits`
|
|
773
|
+
: `_user-keys/${encodeURIComponent(target.keyId)}/limits`;
|
|
774
|
+
let json = await realmServerRequest(realmServerUrl, path, {
|
|
775
|
+
method: 'PUT',
|
|
776
|
+
token,
|
|
777
|
+
fetchFn,
|
|
778
|
+
body: { data: { type: 'key-limits', attributes: changes } },
|
|
779
|
+
});
|
|
780
|
+
return json.data.attributes as KeyLimits;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// What a share or a personal key has served. A share's usage is for the
|
|
784
|
+
// realm's direct writers, a personal key's for its owner; anyone else is
|
|
785
|
+
// answered 404, as for no such share or key.
|
|
786
|
+
export async function getKeyUsage(
|
|
787
|
+
realmServerUrl: string,
|
|
788
|
+
token: string,
|
|
789
|
+
target: { shareId: string } | { keyId: string },
|
|
790
|
+
fetchFn: FetchFn = fetch,
|
|
791
|
+
): Promise<KeyUsage> {
|
|
792
|
+
let path =
|
|
793
|
+
'shareId' in target
|
|
794
|
+
? `_key-shares/${encodeURIComponent(target.shareId)}/usage`
|
|
795
|
+
: `_user-keys/${encodeURIComponent(target.keyId)}/usage`;
|
|
796
|
+
let json = await realmServerRequest(realmServerUrl, path, {
|
|
797
|
+
token,
|
|
798
|
+
fetchFn,
|
|
799
|
+
});
|
|
800
|
+
return fromResource<KeyUsage>(json.data);
|
|
801
|
+
}
|