@ai-matrx/vault 0.1.21 → 0.1.23
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/CHANGELOG.md +19 -2
- package/dist/index.cjs +207 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -2
- package/dist/index.d.ts +38 -2
- package/dist/index.js +207 -76
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -39,6 +39,14 @@ interface VaultOwner {
|
|
|
39
39
|
kind: "me" | "organization" | "shared";
|
|
40
40
|
label: string;
|
|
41
41
|
organizationId: string | null;
|
|
42
|
+
/**
|
|
43
|
+
* An organization's list also holds a member's OWN credential they shared into it: it is
|
|
44
|
+
* attributed to the organization it came through (kind "organization"), never to the viewer,
|
|
45
|
+
* and this says so. Absent on everything else.
|
|
46
|
+
*/
|
|
47
|
+
memberShared?: {
|
|
48
|
+
userId: string | null;
|
|
49
|
+
};
|
|
42
50
|
}
|
|
43
51
|
interface VaultItemCapabilities {
|
|
44
52
|
canUse: boolean;
|
|
@@ -1159,6 +1167,11 @@ interface SaveResult {
|
|
|
1159
1167
|
interface VaultSnapshot {
|
|
1160
1168
|
/** Parts that could not be read this time (an organization, shared items, one-time codes). */
|
|
1161
1169
|
unavailable: readonly string[];
|
|
1170
|
+
/**
|
|
1171
|
+
* Parts still being read (organization names, "Shared with me"): set only on a partial snapshot
|
|
1172
|
+
* handed to `load`'s `onProgress`; the snapshot `load` resolves with never has it.
|
|
1173
|
+
*/
|
|
1174
|
+
pending?: readonly string[];
|
|
1162
1175
|
items: readonly VaultItem[];
|
|
1163
1176
|
/** Items in the trash (deleted, still recoverable). Never mixed into `items`. */
|
|
1164
1177
|
deleted: readonly VaultItem[];
|
|
@@ -1172,7 +1185,11 @@ interface VaultSnapshot {
|
|
|
1172
1185
|
* `sharing`, …) in its own folder.
|
|
1173
1186
|
*/
|
|
1174
1187
|
interface VaultPort {
|
|
1175
|
-
|
|
1188
|
+
/**
|
|
1189
|
+
* The whole vault. `onProgress` (optional) is called with partial snapshots as parts arrive: the
|
|
1190
|
+
* person's own items first, then each organization's list the moment it answers.
|
|
1191
|
+
*/
|
|
1192
|
+
load(onProgress?: (partial: VaultSnapshot) => void): Promise<VaultSnapshot>;
|
|
1176
1193
|
/** The one path to a plaintext value. Audited by the server; handling `sealed` always refuses. */
|
|
1177
1194
|
reveal(item: VaultItem, fieldKey: string): Promise<string>;
|
|
1178
1195
|
/** `organizationId` null = the person's own vault. */
|
|
@@ -1427,4 +1444,23 @@ declare function GenerateButton({ onUse, label, limits, disabled }: {
|
|
|
1427
1444
|
disabled?: boolean;
|
|
1428
1445
|
}): react.JSX.Element | null;
|
|
1429
1446
|
|
|
1430
|
-
|
|
1447
|
+
/**
|
|
1448
|
+
* THE row menu's entries, one source for every menu that offers them: the row's own More button and
|
|
1449
|
+
* right-click menu, and a host's own right-click menu (the website's v3 menu, which wraps the vault
|
|
1450
|
+
* and so cannot render the package's hooks). Each list row registers a reader of its CURRENT entries
|
|
1451
|
+
* on its element; `rowMenuEntriesAt(target)` reads them for whatever a right-click landed on.
|
|
1452
|
+
*/
|
|
1453
|
+
type RowMenuEntryKind = "copy" | "favorite" | "open" | "copy-name" | "host";
|
|
1454
|
+
interface RowMenuEntry {
|
|
1455
|
+
label: string;
|
|
1456
|
+
onSelect: () => void;
|
|
1457
|
+
/** What the entry is, so a host can take only some (the website keeps its own Open and Copy name). */
|
|
1458
|
+
kind?: RowMenuEntryKind;
|
|
1459
|
+
/** Stable key for the entry ("copy:password", "favorite"). */
|
|
1460
|
+
id?: string;
|
|
1461
|
+
disabled?: boolean;
|
|
1462
|
+
}
|
|
1463
|
+
/** The entries of the row a right-click landed on (`[data-item]`), else none. */
|
|
1464
|
+
declare function rowMenuEntriesAt(target: Element | null | undefined): readonly RowMenuEntry[];
|
|
1465
|
+
|
|
1466
|
+
export { type ApiVaultPortOptions, CATEGORIES, CONFIRM_RETURN_KEY, type CategoryId, type Confirmed, type CopyOptions, DEFAULT_LOCATION, type DefinitionField, type FieldHandling, type FieldKind, GenerateButton, HIDDEN_ITEM_TAG, type IdentityAccount, IdentityGate, type IdentityMethod, type ItemDraft, LOCKED_MESSAGE, type NoticeKind, type Notify, type ReturnStore, type RowMenuEntry, type RowMenuEntryKind, type SaveResult, type SupabaseAuthLike, type SupabaseIdentityOptions, type TotpReading, type UriMatchMode, type UrlGuess, type VaultAgentScope, VaultApp, type VaultAppProps, type VaultAttachment, type VaultAuthenticator, type VaultClipboard, type VaultCustomField, type VaultDefinition, type VaultField, type VaultHostCapabilities, type VaultIdentity, type VaultInventory, type VaultItem, type VaultItemCapabilities, type VaultKnobs, type VaultLayout, type VaultLocation, type VaultLock, VaultLockedError, type VaultOrganizationRef, type VaultOwner, type VaultPort, type VaultSelection, type VaultSnapshot, type VaultSort, type VaultUserStateDoor, categoryOf, copyValue, createApiVaultPort, createSupabaseIdentity, createVaultKnobs, guardPort, inferFromUrl, isHiddenItem, itemIdAt, locationFromParams, locationToParams, loginSiteOf, matchesQuery, needsRecentSignIn, parseDefinitions, providerOf, rowMenuEntriesAt, siteDomainOf, sortItems, useConfirmed, vaultInventoryScope, vaultItemFacts, wasCancelled };
|
package/dist/index.d.ts
CHANGED
|
@@ -39,6 +39,14 @@ interface VaultOwner {
|
|
|
39
39
|
kind: "me" | "organization" | "shared";
|
|
40
40
|
label: string;
|
|
41
41
|
organizationId: string | null;
|
|
42
|
+
/**
|
|
43
|
+
* An organization's list also holds a member's OWN credential they shared into it: it is
|
|
44
|
+
* attributed to the organization it came through (kind "organization"), never to the viewer,
|
|
45
|
+
* and this says so. Absent on everything else.
|
|
46
|
+
*/
|
|
47
|
+
memberShared?: {
|
|
48
|
+
userId: string | null;
|
|
49
|
+
};
|
|
42
50
|
}
|
|
43
51
|
interface VaultItemCapabilities {
|
|
44
52
|
canUse: boolean;
|
|
@@ -1159,6 +1167,11 @@ interface SaveResult {
|
|
|
1159
1167
|
interface VaultSnapshot {
|
|
1160
1168
|
/** Parts that could not be read this time (an organization, shared items, one-time codes). */
|
|
1161
1169
|
unavailable: readonly string[];
|
|
1170
|
+
/**
|
|
1171
|
+
* Parts still being read (organization names, "Shared with me"): set only on a partial snapshot
|
|
1172
|
+
* handed to `load`'s `onProgress`; the snapshot `load` resolves with never has it.
|
|
1173
|
+
*/
|
|
1174
|
+
pending?: readonly string[];
|
|
1162
1175
|
items: readonly VaultItem[];
|
|
1163
1176
|
/** Items in the trash (deleted, still recoverable). Never mixed into `items`. */
|
|
1164
1177
|
deleted: readonly VaultItem[];
|
|
@@ -1172,7 +1185,11 @@ interface VaultSnapshot {
|
|
|
1172
1185
|
* `sharing`, …) in its own folder.
|
|
1173
1186
|
*/
|
|
1174
1187
|
interface VaultPort {
|
|
1175
|
-
|
|
1188
|
+
/**
|
|
1189
|
+
* The whole vault. `onProgress` (optional) is called with partial snapshots as parts arrive: the
|
|
1190
|
+
* person's own items first, then each organization's list the moment it answers.
|
|
1191
|
+
*/
|
|
1192
|
+
load(onProgress?: (partial: VaultSnapshot) => void): Promise<VaultSnapshot>;
|
|
1176
1193
|
/** The one path to a plaintext value. Audited by the server; handling `sealed` always refuses. */
|
|
1177
1194
|
reveal(item: VaultItem, fieldKey: string): Promise<string>;
|
|
1178
1195
|
/** `organizationId` null = the person's own vault. */
|
|
@@ -1427,4 +1444,23 @@ declare function GenerateButton({ onUse, label, limits, disabled }: {
|
|
|
1427
1444
|
disabled?: boolean;
|
|
1428
1445
|
}): react.JSX.Element | null;
|
|
1429
1446
|
|
|
1430
|
-
|
|
1447
|
+
/**
|
|
1448
|
+
* THE row menu's entries, one source for every menu that offers them: the row's own More button and
|
|
1449
|
+
* right-click menu, and a host's own right-click menu (the website's v3 menu, which wraps the vault
|
|
1450
|
+
* and so cannot render the package's hooks). Each list row registers a reader of its CURRENT entries
|
|
1451
|
+
* on its element; `rowMenuEntriesAt(target)` reads them for whatever a right-click landed on.
|
|
1452
|
+
*/
|
|
1453
|
+
type RowMenuEntryKind = "copy" | "favorite" | "open" | "copy-name" | "host";
|
|
1454
|
+
interface RowMenuEntry {
|
|
1455
|
+
label: string;
|
|
1456
|
+
onSelect: () => void;
|
|
1457
|
+
/** What the entry is, so a host can take only some (the website keeps its own Open and Copy name). */
|
|
1458
|
+
kind?: RowMenuEntryKind;
|
|
1459
|
+
/** Stable key for the entry ("copy:password", "favorite"). */
|
|
1460
|
+
id?: string;
|
|
1461
|
+
disabled?: boolean;
|
|
1462
|
+
}
|
|
1463
|
+
/** The entries of the row a right-click landed on (`[data-item]`), else none. */
|
|
1464
|
+
declare function rowMenuEntriesAt(target: Element | null | undefined): readonly RowMenuEntry[];
|
|
1465
|
+
|
|
1466
|
+
export { type ApiVaultPortOptions, CATEGORIES, CONFIRM_RETURN_KEY, type CategoryId, type Confirmed, type CopyOptions, DEFAULT_LOCATION, type DefinitionField, type FieldHandling, type FieldKind, GenerateButton, HIDDEN_ITEM_TAG, type IdentityAccount, IdentityGate, type IdentityMethod, type ItemDraft, LOCKED_MESSAGE, type NoticeKind, type Notify, type ReturnStore, type RowMenuEntry, type RowMenuEntryKind, type SaveResult, type SupabaseAuthLike, type SupabaseIdentityOptions, type TotpReading, type UriMatchMode, type UrlGuess, type VaultAgentScope, VaultApp, type VaultAppProps, type VaultAttachment, type VaultAuthenticator, type VaultClipboard, type VaultCustomField, type VaultDefinition, type VaultField, type VaultHostCapabilities, type VaultIdentity, type VaultInventory, type VaultItem, type VaultItemCapabilities, type VaultKnobs, type VaultLayout, type VaultLocation, type VaultLock, VaultLockedError, type VaultOrganizationRef, type VaultOwner, type VaultPort, type VaultSelection, type VaultSnapshot, type VaultSort, type VaultUserStateDoor, categoryOf, copyValue, createApiVaultPort, createSupabaseIdentity, createVaultKnobs, guardPort, inferFromUrl, isHiddenItem, itemIdAt, locationFromParams, locationToParams, loginSiteOf, matchesQuery, needsRecentSignIn, parseDefinitions, providerOf, rowMenuEntriesAt, siteDomainOf, sortItems, useConfirmed, vaultInventoryScope, vaultItemFacts, wasCancelled };
|
package/dist/index.js
CHANGED
|
@@ -849,6 +849,19 @@ import { formatAbsoluteDate as formatAbsoluteDate2 } from "@ai-matrx/kit/format"
|
|
|
849
849
|
import { formatRelativeTime } from "@ai-matrx/kit/format";
|
|
850
850
|
|
|
851
851
|
// src/model.ts
|
|
852
|
+
function manageUnavailableReason(item) {
|
|
853
|
+
if (item.capabilities.canManage) return null;
|
|
854
|
+
if (item.owner.memberShared) return "Only the member who owns it can share, move or delete it";
|
|
855
|
+
if (item.owner.kind === "shared") return "Only its owner can share, move or delete it";
|
|
856
|
+
if (item.owner.kind === "organization") return "Only this organization's vault admins can change that";
|
|
857
|
+
return "You can use this item but not share, move or delete it";
|
|
858
|
+
}
|
|
859
|
+
function ownerDetail(owner) {
|
|
860
|
+
if (owner.memberShared) return `A member's own credential, shared into ${owner.label}`;
|
|
861
|
+
if (owner.kind === "organization") return `Organization: ${owner.label}`;
|
|
862
|
+
if (owner.kind === "shared") return "Shared with you by its owner";
|
|
863
|
+
return "Your own vault";
|
|
864
|
+
}
|
|
852
865
|
var DEFAULT_LOCATION = { vault: "all", view: "all", q: "", sort: "name", itemId: null, mode: "view", kind: null, url: "", panel: null };
|
|
853
866
|
var SORTS = ["name", "name-desc", "website", "updated", "created", "viewed"];
|
|
854
867
|
function locationFromParams(params, itemId = params.get("item")) {
|
|
@@ -5991,6 +6004,7 @@ function ItemPane(props) {
|
|
|
5991
6004
|
const setValue = (key, v) => setDraft((d) => ({ ...d, values: { ...d.values, [key]: v } }));
|
|
5992
6005
|
const canEdit = item ? item.capabilities.canEdit || item.capabilities.canManage : true;
|
|
5993
6006
|
const canManage = item?.capabilities.canManage ?? false;
|
|
6007
|
+
const manageReason = item ? manageUnavailableReason(item) : null;
|
|
5994
6008
|
async function save() {
|
|
5995
6009
|
if (!definition && !item) return;
|
|
5996
6010
|
setBusy(true);
|
|
@@ -6137,7 +6151,8 @@ function ItemPane(props) {
|
|
|
6137
6151
|
/* @__PURE__ */ jsx27("h2", { className: "truncate text-base font-semibold leading-tight", children: editing ? draft.name || (mode === "new" ? `New ${typeLabel.toLowerCase()}` : item?.name) : item?.name }),
|
|
6138
6152
|
/* @__PURE__ */ jsxs25("span", { className: "flex min-w-0 items-center gap-1 text-xs text-muted-foreground", children: [
|
|
6139
6153
|
typeLabel ? /* @__PURE__ */ jsx27("span", { className: "truncate", children: typeLabel }) : null,
|
|
6140
|
-
shownOwner ? /* @__PURE__ */ jsx27(Badge7, { className: "shrink-0", icon: shownOwner.glyph, "aria-label": `Saved in ${shownOwner.label}`, children: shownOwner.label }) : null,
|
|
6154
|
+
shownOwner ? /* @__PURE__ */ jsx27(Badge7, { className: "shrink-0", icon: shownOwner.glyph, "aria-label": `Saved in ${shownOwner.label}`, title: item && mode !== "new" ? ownerDetail(item.owner) : void 0, children: shownOwner.label }) : null,
|
|
6155
|
+
item && mode !== "new" && item.owner.memberShared ? /* @__PURE__ */ jsx27("span", { className: "shrink-0", "data-member-shared": "", children: "\xB7 A member\u2019s own" }) : null,
|
|
6141
6156
|
item && !editing ? /* @__PURE__ */ jsx27(SharingSummary, { item, port, className: "hidden truncate before:mr-1 before:content-['\xB7'] sm:inline" }, `${item.updatedAt}-${refreshKey ?? ""}`) : null
|
|
6142
6157
|
] })
|
|
6143
6158
|
] }),
|
|
@@ -6175,9 +6190,9 @@ function ItemPane(props) {
|
|
|
6175
6190
|
/* @__PURE__ */ jsx27(ShareGlyph, { className: "size-4" }),
|
|
6176
6191
|
"Share"
|
|
6177
6192
|
] }) : null,
|
|
6178
|
-
canManage ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("move"), children: [
|
|
6193
|
+
canManage || item.capabilities.canEdit ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("move"), children: [
|
|
6179
6194
|
/* @__PURE__ */ jsx27(MoveGlyph, { className: "size-4" }),
|
|
6180
|
-
"Move or copy"
|
|
6195
|
+
canManage ? "Move or copy" : "Copy to\u2026"
|
|
6181
6196
|
] }) : null,
|
|
6182
6197
|
item.capabilities.canReveal ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("send"), children: [
|
|
6183
6198
|
/* @__PURE__ */ jsx27(SendGlyph, { className: "size-4" }),
|
|
@@ -6201,6 +6216,17 @@ function ItemPane(props) {
|
|
|
6201
6216
|
/* @__PURE__ */ jsx27(TrashGlyph, { className: "size-4" }),
|
|
6202
6217
|
"Delete"
|
|
6203
6218
|
] })
|
|
6219
|
+
] }) : manageReason ? /* @__PURE__ */ jsxs25(Fragment18, { children: [
|
|
6220
|
+
/* @__PURE__ */ jsx27(DropdownMenuSeparator3, {}),
|
|
6221
|
+
/* @__PURE__ */ jsxs25(DropdownMenuItem3, { disabled: true, children: [
|
|
6222
|
+
/* @__PURE__ */ jsx27(ShareGlyph, { className: "size-4" }),
|
|
6223
|
+
"Share"
|
|
6224
|
+
] }),
|
|
6225
|
+
/* @__PURE__ */ jsxs25(DropdownMenuItem3, { disabled: true, children: [
|
|
6226
|
+
/* @__PURE__ */ jsx27(TrashGlyph, { className: "size-4" }),
|
|
6227
|
+
"Delete"
|
|
6228
|
+
] }),
|
|
6229
|
+
/* @__PURE__ */ jsx27("div", { className: "max-w-64 px-2 py-1.5 text-xs text-muted-foreground", "data-manage-reason": "", children: manageReason })
|
|
6204
6230
|
] }) : null
|
|
6205
6231
|
] })
|
|
6206
6232
|
] })
|
|
@@ -6431,6 +6457,17 @@ function ItemPane(props) {
|
|
|
6431
6457
|
] }) });
|
|
6432
6458
|
}
|
|
6433
6459
|
|
|
6460
|
+
// src/row-menu.ts
|
|
6461
|
+
var readers = /* @__PURE__ */ new WeakMap();
|
|
6462
|
+
function registerRowMenu(el, read) {
|
|
6463
|
+
if (el) readers.set(el, read);
|
|
6464
|
+
}
|
|
6465
|
+
function rowMenuEntriesAt(target) {
|
|
6466
|
+
const row = target?.closest("[data-item]");
|
|
6467
|
+
const read = row ? readers.get(row) : void 0;
|
|
6468
|
+
return read ? read() : [];
|
|
6469
|
+
}
|
|
6470
|
+
|
|
6434
6471
|
// src/ItemList.tsx
|
|
6435
6472
|
import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
6436
6473
|
var RECOVERY_KEYS = /^recovery_codes?$/;
|
|
@@ -6452,7 +6489,7 @@ function subtitleOf(item, withOwner) {
|
|
|
6452
6489
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
6453
6490
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
6454
6491
|
}
|
|
6455
|
-
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner, canSortViewed = false, onRefresh, refreshing = false, rowContextMenu = "package", rowMenuItems }) {
|
|
6492
|
+
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, actions, showOwner, canSortViewed = false, onRefresh, refreshing = false, rowContextMenu = "package", rowMenuItems, stillLoading, favorites, onToggleFavorite }) {
|
|
6456
6493
|
const sorts = SORTS2.filter((s) => canSortViewed || s.value !== "viewed");
|
|
6457
6494
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
6458
6495
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
@@ -6473,20 +6510,29 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6473
6510
|
}
|
|
6474
6511
|
};
|
|
6475
6512
|
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6476
|
-
const row = (i) => /* @__PURE__ */ jsx28(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners, ownContextMenu: rowContextMenu === "package", extra: rowMenuItems }, i.id);
|
|
6513
|
+
const row = (i) => /* @__PURE__ */ jsx28(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners, ownContextMenu: rowContextMenu === "package", extra: rowMenuItems, favorite: onToggleFavorite ? { on: favorites?.has(i.id) ?? false, toggle: () => onToggleFavorite(i.id) } : void 0 }, i.id);
|
|
6477
6514
|
const sortLabel = sorts.find((s) => s.value === sort)?.label ?? "Name A\u2013Z";
|
|
6478
6515
|
return /* @__PURE__ */ jsxs26("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
|
|
6479
6516
|
/* @__PURE__ */ jsxs26("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children: [
|
|
6480
6517
|
header,
|
|
6481
6518
|
/* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2", children: [
|
|
6482
6519
|
/* @__PURE__ */ jsx28(SearchField, { value: query, onChange: (e) => onQuery(e.target.value), onKeyDown, placeholder: `Search ${title}`, className: "min-w-0 flex-1", "aria-label": "Search the vault" }),
|
|
6520
|
+
actions,
|
|
6483
6521
|
/* @__PURE__ */ jsx28(Button23, { variant: "primary", icon: /* @__PURE__ */ jsx28(PlusGlyph, {}), "aria-label": "New item", onClick: onNew })
|
|
6484
6522
|
] }),
|
|
6485
6523
|
/* @__PURE__ */ jsxs26("div", { className: "flex items-center justify-between gap-2 px-1", children: [
|
|
6486
|
-
/* @__PURE__ */ jsxs26("span", { className: "truncate text-xs text-muted-foreground", children: [
|
|
6524
|
+
/* @__PURE__ */ jsxs26("span", { className: "flex min-w-0 items-center gap-1.5 truncate text-xs text-muted-foreground", role: "status", "aria-live": "polite", children: [
|
|
6487
6525
|
items.length,
|
|
6488
6526
|
" ",
|
|
6489
|
-
items.length === 1 ? "item" : "items"
|
|
6527
|
+
items.length === 1 ? "item" : "items",
|
|
6528
|
+
stillLoading && stillLoading.length > 0 ? /* @__PURE__ */ jsxs26("span", { className: "flex min-w-0 items-center gap-1 truncate", title: `Still loading ${stillLoading.join(", ")}`, "data-still-loading": "", children: [
|
|
6529
|
+
/* @__PURE__ */ jsx28(RefreshGlyph, { className: "size-3 shrink-0 animate-spin" }),
|
|
6530
|
+
/* @__PURE__ */ jsxs26("span", { className: "truncate", children: [
|
|
6531
|
+
"loading ",
|
|
6532
|
+
stillLoading.length === 1 ? stillLoading[0] : `${stillLoading.length} more`,
|
|
6533
|
+
"\u2026"
|
|
6534
|
+
] })
|
|
6535
|
+
] }) : null
|
|
6490
6536
|
] }),
|
|
6491
6537
|
/* @__PURE__ */ jsxs26("span", { className: "flex shrink-0 items-center gap-0.5", children: [
|
|
6492
6538
|
onRefresh ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(RefreshGlyph, { className: refreshing ? "animate-spin" : "" }), "aria-label": "Refresh", title: "Refresh the list", disabled: refreshing, onClick: onRefresh }) : null,
|
|
@@ -6498,7 +6544,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6498
6544
|
] })
|
|
6499
6545
|
] }),
|
|
6500
6546
|
/* @__PURE__ */ jsx28("div", { className: "min-h-0 flex-1 overflow-y-auto px-2 pb-3", onKeyDown, children: items.length === 0 ? /* @__PURE__ */ jsxs26("div", { className: "flex flex-col items-center gap-3 px-4 py-12 text-center", children: [
|
|
6501
|
-
/* @__PURE__ */ jsx28("span", { className: "text-sm text-muted-foreground", children: query ? `Nothing matches \u201C${query}\u201D.` : "Nothing here yet." }),
|
|
6547
|
+
/* @__PURE__ */ jsx28("span", { className: "text-sm text-muted-foreground", children: query ? `Nothing matches \u201C${query}\u201D.` : stillLoading && stillLoading.length > 0 ? "Still loading\u2026" : "Nothing here yet." }),
|
|
6502
6548
|
query ? /* @__PURE__ */ jsx28(Button23, { variant: "outline", onClick: () => onQuery(""), children: "Clear search" }) : /* @__PURE__ */ jsx28(Button23, { variant: "outline", icon: /* @__PURE__ */ jsx28(PlusGlyph, {}), onClick: onNew, children: "New item" })
|
|
6503
6549
|
] }) : /* @__PURE__ */ jsxs26("ul", { ref: listRef, className: "flex flex-col gap-px", children: [
|
|
6504
6550
|
pinned.length > 0 ? /* @__PURE__ */ jsx28("li", { className: "px-2 pb-1 pt-1 text-xs font-medium text-muted-foreground", children: "This page" }) : null,
|
|
@@ -6508,7 +6554,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6508
6554
|
] }) })
|
|
6509
6555
|
] });
|
|
6510
6556
|
}
|
|
6511
|
-
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra }) {
|
|
6557
|
+
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra, favorite }) {
|
|
6512
6558
|
const confirmed = useConfirmed();
|
|
6513
6559
|
const copy = useCopy();
|
|
6514
6560
|
const notify = useNotify();
|
|
@@ -6536,9 +6582,32 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6536
6582
|
const others = otherCopyFields(item, user, secret);
|
|
6537
6583
|
const custom = canUse ? item.custom.filter((c) => c.value) : [];
|
|
6538
6584
|
const hostEntries = extra?.(item) ?? [];
|
|
6585
|
+
const copyEntries = [
|
|
6586
|
+
...user ? [{ id: "copy:username", kind: "copy", label: `Copy ${user.label.toLowerCase()}`, onSelect: copyUser }] : [],
|
|
6587
|
+
...secret ? [{ id: "copy:password", kind: "copy", label: "Copy password", onSelect: copyPassword }] : [],
|
|
6588
|
+
...code ? [{ id: "copy:code", kind: "copy", label: "Copy one-time code", onSelect: copyCode }] : [],
|
|
6589
|
+
...others.map((f) => ({ id: `copy:${f.key}`, kind: "copy", label: `Copy ${f.label.toLowerCase()}`, onSelect: () => void run(f.label, () => port.reveal(item, f.key), f.handling !== "visible") })),
|
|
6590
|
+
...custom.map((c) => ({ id: `copy:custom:${c.key}`, kind: "copy", label: `Copy ${c.label.toLowerCase()}`, onSelect: () => void copy(c.value, c.label, { secret: false }) }))
|
|
6591
|
+
];
|
|
6592
|
+
const favoriteEntry = favorite ? { id: "favorite", kind: "favorite", label: favorite.on ? "Remove from favorites" : "Add to favorites", onSelect: favorite.toggle } : null;
|
|
6593
|
+
const entries = [
|
|
6594
|
+
...copyEntries,
|
|
6595
|
+
...favoriteEntry ? [favoriteEntry] : [],
|
|
6596
|
+
{ id: "open", kind: "open", label: "Open", onSelect: () => onSelect(item.id) },
|
|
6597
|
+
{ id: "copy-name", kind: "copy-name", label: "Copy name", onSelect: copyName },
|
|
6598
|
+
...hostEntries.map((h) => ({ ...h, kind: h.kind ?? "host" }))
|
|
6599
|
+
];
|
|
6600
|
+
const entriesRef = useRef15(entries);
|
|
6601
|
+
entriesRef.current = entries;
|
|
6602
|
+
const glyphOf = (e) => e.id === "copy:username" ? /* @__PURE__ */ jsx28(UserGlyph, { className: "size-4" }) : e.id === "copy:password" ? /* @__PURE__ */ jsx28(KeyGlyph, { className: "size-4" }) : e.id === "copy:code" ? /* @__PURE__ */ jsx28(ClockGlyph, { className: "size-4" }) : e.kind === "favorite" ? /* @__PURE__ */ jsx28(StarGlyph, { className: cn13("size-4", favorite?.on && "fill-current text-warning") }) : e.kind === "open" ? /* @__PURE__ */ jsx28(ChevronRightGlyph, { className: "size-4" }) : e.kind === "host" ? null : /* @__PURE__ */ jsx28(CopyIcon7, { className: "size-4" });
|
|
6603
|
+
const menuItem = (e) => /* @__PURE__ */ jsxs26(DropdownMenuItem4, { disabled: e.disabled ?? false, onSelect: e.onSelect, children: [
|
|
6604
|
+
glyphOf(e),
|
|
6605
|
+
e.label
|
|
6606
|
+
] }, e.id ?? e.label);
|
|
6539
6607
|
return /* @__PURE__ */ jsxs26(
|
|
6540
6608
|
"li",
|
|
6541
6609
|
{
|
|
6610
|
+
ref: (el) => registerRowMenu(el, () => entriesRef.current),
|
|
6542
6611
|
className: "group relative",
|
|
6543
6612
|
"data-item": item.id,
|
|
6544
6613
|
onContextMenu: ownContextMenu ? (e) => {
|
|
@@ -6564,7 +6633,8 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6564
6633
|
}
|
|
6565
6634
|
),
|
|
6566
6635
|
/* @__PURE__ */ jsxs26("div", { className: "absolute right-1.5 top-1/2 flex -translate-y-1/2 items-center gap-0.5", "data-surface": on ? "primary" : void 0, children: [
|
|
6567
|
-
user || secret ? /* @__PURE__ */ jsxs26("div", { className: cn13("hidden items-center gap-0.5 rounded-md pl-2 [@media(hover:hover)]:group-hover:flex [@media(hover:hover)]:group-focus-within:flex", on ? "bg-primary" : "bg-accent"), "data-row-quick": "", children: [
|
|
6636
|
+
user || secret || favorite ? /* @__PURE__ */ jsxs26("div", { className: cn13("hidden items-center gap-0.5 rounded-md pl-2 [@media(hover:hover)]:group-hover:flex [@media(hover:hover)]:group-focus-within:flex", on ? "bg-primary" : "bg-accent"), "data-row-quick": "", children: [
|
|
6637
|
+
favorite ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(StarGlyph, { className: favorite.on ? "fill-current text-warning" : "" }), "aria-label": favorite.on ? "Remove from favorites" : "Add to favorites", "aria-pressed": favorite.on, onClick: favorite.toggle }) : null,
|
|
6568
6638
|
user ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(UserGlyph, {}), "aria-label": `Copy ${user.label}`, disabled: busy, onClick: copyUser }) : null,
|
|
6569
6639
|
secret ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: copyPassword }) : null
|
|
6570
6640
|
] }) : null,
|
|
@@ -6580,40 +6650,11 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6580
6650
|
}
|
|
6581
6651
|
) }),
|
|
6582
6652
|
/* @__PURE__ */ jsxs26(DropdownMenuContent4, { align: "end", children: [
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
user.label.toLowerCase()
|
|
6587
|
-
] }) : null,
|
|
6588
|
-
secret ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyPassword, children: [
|
|
6589
|
-
/* @__PURE__ */ jsx28(KeyGlyph, { className: "size-4" }),
|
|
6590
|
-
"Copy password"
|
|
6591
|
-
] }) : null,
|
|
6592
|
-
code ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyCode, children: [
|
|
6593
|
-
/* @__PURE__ */ jsx28(ClockGlyph, { className: "size-4" }),
|
|
6594
|
-
"Copy one-time code"
|
|
6595
|
-
] }) : null,
|
|
6596
|
-
others.map((f) => /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: () => void run(f.label, () => port.reveal(item, f.key), f.handling !== "visible"), children: [
|
|
6597
|
-
/* @__PURE__ */ jsx28(CopyIcon7, { className: "size-4" }),
|
|
6598
|
-
"Copy ",
|
|
6599
|
-
f.label.toLowerCase()
|
|
6600
|
-
] }, f.key)),
|
|
6601
|
-
custom.map((c) => /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: () => void copy(c.value, c.label, { secret: false }), children: [
|
|
6602
|
-
/* @__PURE__ */ jsx28(CopyIcon7, { className: "size-4" }),
|
|
6603
|
-
"Copy ",
|
|
6604
|
-
c.label.toLowerCase()
|
|
6605
|
-
] }, `custom:${c.key}`)),
|
|
6606
|
-
user || secret || code || others.length > 0 || custom.length > 0 ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
|
|
6607
|
-
/* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: () => onSelect(item.id), children: [
|
|
6608
|
-
/* @__PURE__ */ jsx28(ChevronRightGlyph, { className: "size-4" }),
|
|
6609
|
-
"Open"
|
|
6610
|
-
] }),
|
|
6611
|
-
/* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyName, children: [
|
|
6612
|
-
/* @__PURE__ */ jsx28(CopyIcon7, { className: "size-4" }),
|
|
6613
|
-
"Copy name"
|
|
6614
|
-
] }),
|
|
6653
|
+
copyEntries.map(menuItem),
|
|
6654
|
+
copyEntries.length > 0 ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
|
|
6655
|
+
entries.filter((e) => e.kind === "favorite" || e.kind === "open" || e.kind === "copy-name").map(menuItem),
|
|
6615
6656
|
hostEntries.length > 0 ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
|
|
6616
|
-
|
|
6657
|
+
entries.filter((e) => e.kind === "host").map(menuItem)
|
|
6617
6658
|
] })
|
|
6618
6659
|
] })
|
|
6619
6660
|
] })
|
|
@@ -8121,15 +8162,17 @@ import { Select as Select11 } from "@ai-matrx/design-system/controls";
|
|
|
8121
8162
|
import { GlobeIcon as GlobeIcon5 } from "@ai-matrx/design-system/icons";
|
|
8122
8163
|
import { jsx as jsx39, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
8123
8164
|
var AUTHENTICATOR_LABEL = "Authenticator";
|
|
8124
|
-
function vaultChoices(items, organizations,
|
|
8165
|
+
function vaultChoices(items, organizations, _current) {
|
|
8125
8166
|
const n = (f) => items.filter(f).length;
|
|
8126
8167
|
const shared = n((i) => i.owner.kind === "shared");
|
|
8127
8168
|
return [
|
|
8128
8169
|
{ value: "all", label: "All items", count: items.length },
|
|
8129
8170
|
{ value: "mine", label: "Personal", count: n((i) => i.owner.kind === "me") },
|
|
8130
8171
|
...shared > 0 ? [{ value: "shared", label: "Shared with me", count: shared }] : [],
|
|
8131
|
-
//
|
|
8132
|
-
|
|
8172
|
+
// Every organization the person belongs to, empty ones too: an empty vault opens on its own
|
|
8173
|
+
// "Nothing here yet" with New item, so the first credential can go there. (The organization
|
|
8174
|
+
// list carries no role, so who may add is the server's answer to the save, said in place.)
|
|
8175
|
+
...organizations.map((o) => ({ value: o.id, label: o.name, count: n((i) => i.owner.organizationId === o.id) }))
|
|
8133
8176
|
];
|
|
8134
8177
|
}
|
|
8135
8178
|
function VaultSelect({ value, choices, onChange }) {
|
|
@@ -8409,7 +8452,16 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8409
8452
|
const load = useCallback5(() => {
|
|
8410
8453
|
setError(null);
|
|
8411
8454
|
setRefreshError(null);
|
|
8412
|
-
|
|
8455
|
+
let finished = false;
|
|
8456
|
+
port.load((partial) => {
|
|
8457
|
+
if (finished) return;
|
|
8458
|
+
setSnap(partial);
|
|
8459
|
+
setItems(partial.items);
|
|
8460
|
+
setDeleted(partial.deleted);
|
|
8461
|
+
}).then((s) => {
|
|
8462
|
+
finished = true;
|
|
8463
|
+
apply(s);
|
|
8464
|
+
}).catch((e) => {
|
|
8413
8465
|
setSignedOut(e?.status === 401);
|
|
8414
8466
|
setError(e instanceof Error ? e.message : "The vault could not be loaded.");
|
|
8415
8467
|
});
|
|
@@ -8526,9 +8578,11 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8526
8578
|
}
|
|
8527
8579
|
const hasFavorites = port.lists.favorites !== void 0;
|
|
8528
8580
|
const title = loc.vault === "all" && loc.view === "all" ? "All items" : viewLabel(loc.view, views);
|
|
8529
|
-
const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */ jsxs38("div", { className: "grid grid-cols-[
|
|
8581
|
+
const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */ jsxs38("div", { className: "grid grid-cols-[repeat(auto-fit,minmax(11rem,1fr))] gap-2", "data-vault-compact-header": "", children: [
|
|
8530
8582
|
/* @__PURE__ */ jsx40(VaultSelect, { value: loc.vault, choices, onChange: (vault) => go({ vault, itemId: null, panel: null }) }),
|
|
8531
|
-
/* @__PURE__ */ jsx40(Select12, { value: loc.view, onValueChange: (view) => go({ view, itemId: null, panel: null }), options: viewOptions(views, inThisVault.length, deleted.length, hasFavorites, port.lists.recents !== void 0, host.page !== void 0), "aria-label": "Show" })
|
|
8583
|
+
/* @__PURE__ */ jsx40(Select12, { value: loc.view, onValueChange: (view) => go({ view, itemId: null, panel: null }), options: viewOptions(views, inThisVault.length, deleted.length, hasFavorites, port.lists.recents !== void 0, host.page !== void 0), "aria-label": "Show" })
|
|
8584
|
+
] });
|
|
8585
|
+
const compactActions = mode === "full" ? void 0 : /* @__PURE__ */ jsxs38("div", { className: "flex shrink-0 items-center gap-2", "data-vault-compact-actions": "", children: [
|
|
8532
8586
|
/* @__PURE__ */ jsx40(
|
|
8533
8587
|
Button34,
|
|
8534
8588
|
{
|
|
@@ -8537,8 +8591,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8537
8591
|
"aria-label": AUTHENTICATOR_LABEL,
|
|
8538
8592
|
"aria-pressed": loc.view === "authenticator",
|
|
8539
8593
|
title: AUTHENTICATOR_LABEL,
|
|
8540
|
-
onClick: () => go({ view: loc.view === "authenticator" ? "all" : "authenticator", itemId: null, mode: "view", panel: null })
|
|
8541
|
-
children: mode === "split" ? AUTHENTICATOR_LABEL : null
|
|
8594
|
+
onClick: () => go({ view: loc.view === "authenticator" ? "all" : "authenticator", itemId: null, mode: "view", panel: null })
|
|
8542
8595
|
}
|
|
8543
8596
|
),
|
|
8544
8597
|
/* @__PURE__ */ jsxs38(DropdownMenu6, { children: [
|
|
@@ -8581,7 +8634,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8581
8634
|
] });
|
|
8582
8635
|
const viewHeader = /* @__PURE__ */ jsxs38("div", { className: "flex flex-col gap-2", children: [
|
|
8583
8636
|
compactHeader,
|
|
8584
|
-
/* @__PURE__ */
|
|
8637
|
+
/* @__PURE__ */ jsxs38("div", { className: "flex items-center gap-2", children: [
|
|
8638
|
+
/* @__PURE__ */ jsx40(SearchField4, { value: loc.q, onChange: (e) => go({ q: e.target.value }, "replace"), placeholder: `Search ${viewLabel(loc.view, views)}`, "aria-label": `Search ${viewLabel(loc.view, views)}`, className: "min-w-0 flex-1" }),
|
|
8639
|
+
compactActions
|
|
8640
|
+
] })
|
|
8585
8641
|
] });
|
|
8586
8642
|
const viewProps = { port, host, items: inThisVault, deleted, definitions, query: loc.q, onOpen: (id) => go({ view: "all", itemId: id, mode: "view", panel: null }), onChanged: load, header: viewHeader };
|
|
8587
8643
|
const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */ jsx40(
|
|
@@ -8599,7 +8655,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8599
8655
|
onNewForPage: (url) => go({ mode: "new", kind: null, url, itemId: null, panel: null }),
|
|
8600
8656
|
onBrowse: () => go({ view: "all", itemId: null }),
|
|
8601
8657
|
onChanged: load,
|
|
8602
|
-
...compactHeader ? { header:
|
|
8658
|
+
...compactHeader ? { header: /* @__PURE__ */ jsxs38("div", { className: "flex flex-col gap-2", children: [
|
|
8659
|
+
compactHeader,
|
|
8660
|
+
/* @__PURE__ */ jsx40("div", { className: "flex justify-end", children: compactActions })
|
|
8661
|
+
] }) } : {}
|
|
8603
8662
|
}
|
|
8604
8663
|
) : null;
|
|
8605
8664
|
const specialView = pageView ?? (loc.view === "authenticator" ? /* @__PURE__ */ jsx40(AuthenticatorView, { ...viewProps }) : loc.view === "trash" ? /* @__PURE__ */ jsx40(TrashView, { ...viewProps }) : null);
|
|
@@ -8621,10 +8680,13 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8621
8680
|
onNew: () => go({ itemId: null, mode: "new", kind: null, panel: null }),
|
|
8622
8681
|
onRefresh: refresh,
|
|
8623
8682
|
refreshing,
|
|
8683
|
+
...snap.pending && snap.pending.length > 0 ? { stillLoading: snap.pending } : {},
|
|
8684
|
+
...hasFavorites ? { favorites: favorites ?? /* @__PURE__ */ new Set(), onToggleFavorite: toggleFavorite } : {},
|
|
8624
8685
|
rowContextMenu: host.rowContextMenu ?? "package",
|
|
8625
8686
|
...host.rowMenuItems ? { rowMenuItems: host.rowMenuItems } : {},
|
|
8626
8687
|
...matchingIds ? { matchingIds } : {},
|
|
8627
|
-
...compactHeader ? { header: compactHeader } : {}
|
|
8688
|
+
...compactHeader ? { header: compactHeader } : {},
|
|
8689
|
+
...compactActions ? { actions: compactActions } : {}
|
|
8628
8690
|
}
|
|
8629
8691
|
);
|
|
8630
8692
|
const showingDetail = loc.mode === "new" || loc.itemId !== null;
|
|
@@ -9510,6 +9572,12 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9510
9572
|
if (id) return { kind: "organization", label: orgs.find((o) => o.id === id)?.name ?? "Organization", organizationId: id };
|
|
9511
9573
|
return mine || userId ? { kind: "me", label: "Personal", organizationId: null } : { kind: "shared", label: "Shared with me", organizationId: null };
|
|
9512
9574
|
};
|
|
9575
|
+
const ownerInOrgList = (w, via, meId) => {
|
|
9576
|
+
if (w.organization_id) return orgOf(w.organization_id, null, false);
|
|
9577
|
+
if (w.user_id && meId && w.user_id === meId) return { kind: "me", label: "Personal", organizationId: null };
|
|
9578
|
+
if (via) return { kind: "organization", label: via.name, organizationId: via.id, memberShared: { userId: w.user_id ?? null } };
|
|
9579
|
+
return { kind: "shared", label: "Shared with me", organizationId: null };
|
|
9580
|
+
};
|
|
9513
9581
|
async function refetch(id, owner) {
|
|
9514
9582
|
const w = await account9.getItem(api, { path: { item_id: id } });
|
|
9515
9583
|
return itemOf(w, owner, defs, auth);
|
|
@@ -9537,38 +9605,100 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9537
9605
|
io: createIoPort(ctx),
|
|
9538
9606
|
fields: createFieldsPort(ctx),
|
|
9539
9607
|
lists: createListsPort(ctx, options.userState),
|
|
9540
|
-
async load() {
|
|
9608
|
+
async load(onProgress) {
|
|
9541
9609
|
const catalogP = retrying(() => apps2.getAppCatalogKind(api, { path: { app: "matrx", kind: "credential_definition" } }));
|
|
9542
9610
|
const authP = retrying(() => apps2.listAuthenticators(api));
|
|
9543
9611
|
const userP = retrying(() => account9.listItems(api, { query: { principal_type: "user" } }));
|
|
9544
9612
|
const sharedP = retrying(() => account9.sharedWithMe(api));
|
|
9545
9613
|
const quiet = (p) => void p.catch(() => void 0);
|
|
9546
9614
|
[catalogP, authP, userP, sharedP].forEach(quiet);
|
|
9547
|
-
const
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
const [authSettled, sharedSettled, ...orgSettled] = await Promise.allSettled([authP, sharedP, ...orgListsP]);
|
|
9615
|
+
const raw = {
|
|
9616
|
+
orgLists: [],
|
|
9617
|
+
orgsKnown: options.organizations !== void 0,
|
|
9618
|
+
meId: null
|
|
9619
|
+
};
|
|
9553
9620
|
const unavailable = [];
|
|
9554
|
-
|
|
9555
|
-
const
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
|
|
9561
|
-
|
|
9562
|
-
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
if (seen.has(w.id) || deleted.has(w.id) || isHiddenItem(w)) continue;
|
|
9566
|
-
const owner = sharedList ? orgOf(w.organization_id, null, false) : orgOf(w.organization_id, w.user_id, i === 0);
|
|
9567
|
-
const item = itemOf(w, sharedList && !w.organization_id ? { kind: "shared", label: "Shared with me", organizationId: null } : owner, defs, auth);
|
|
9621
|
+
let done = false;
|
|
9622
|
+
const build = () => {
|
|
9623
|
+
const catalog2 = raw.catalog ?? [];
|
|
9624
|
+
defs = new Map(parseDefinitions(catalog2.filter((e) => e.is_active).map((e) => ({ key: e.key, payload: e.payload, sort_order: e.sort_order }))).map((d) => [d.key, d]));
|
|
9625
|
+
const mineItems = raw.mine?.items ?? [];
|
|
9626
|
+
const meId = raw.meId ?? mineItems.find((w) => w.user_id)?.user_id ?? null;
|
|
9627
|
+
const seen = /* @__PURE__ */ new Map();
|
|
9628
|
+
const deleted = /* @__PURE__ */ new Map();
|
|
9629
|
+
const take = (w, owner) => {
|
|
9630
|
+
if (seen.has(w.id) || deleted.has(w.id) || isHiddenItem(w)) return;
|
|
9631
|
+
const item = itemOf(w, owner, defs, auth);
|
|
9568
9632
|
(isDeleted(w) ? deleted : seen).set(w.id, item);
|
|
9633
|
+
};
|
|
9634
|
+
for (const w of mineItems) take(w, orgOf(w.organization_id, null, true));
|
|
9635
|
+
raw.orgLists.forEach((l, i) => {
|
|
9636
|
+
const via = orgs[i];
|
|
9637
|
+
for (const w of l?.items ?? []) take(w, ownerInOrgList(w, via, meId));
|
|
9638
|
+
});
|
|
9639
|
+
for (const w of raw.shared?.items ?? []) take(w, w.organization_id ? orgOf(w.organization_id, null, false) : { kind: "shared", label: "Shared with me", organizationId: null });
|
|
9640
|
+
const pending = done ? [] : [...raw.orgsKnown ? orgs.filter((_, i) => raw.orgLists[i] === void 0).map((o) => o.name) : ["your organizations"], ...raw.shared ? [] : ["Shared with me"]];
|
|
9641
|
+
return {
|
|
9642
|
+
unavailable: [...unavailable],
|
|
9643
|
+
...pending.length > 0 ? { pending } : {},
|
|
9644
|
+
items: [...seen.values()],
|
|
9645
|
+
deleted: [...deleted.values()],
|
|
9646
|
+
organizations: orgs,
|
|
9647
|
+
definitions: [...defs.values()].sort((a, b) => a.sortOrder - b.sortOrder || a.label.localeCompare(b.label))
|
|
9648
|
+
};
|
|
9649
|
+
};
|
|
9650
|
+
const progress = () => {
|
|
9651
|
+
if (!done && onProgress && raw.catalog && raw.mine) onProgress(build());
|
|
9652
|
+
};
|
|
9653
|
+
const orgReportP = options.organizations ? null : retrying(() => platform.listMyOrganizations(api));
|
|
9654
|
+
if (orgReportP) quiet(orgReportP);
|
|
9655
|
+
const orgListsReady = (async () => {
|
|
9656
|
+
const report = orgReportP ? await orgReportP : null;
|
|
9657
|
+
raw.meId = report?.user_id ?? null;
|
|
9658
|
+
orgs = [...new Map((options.organizations ?? (report?.organizations ?? []).filter((o) => !o.archived_at).map((o) => ({ id: o.id, name: o.name }))).map((o) => [o.id, o])).values()];
|
|
9659
|
+
raw.orgLists = orgs.map(() => void 0);
|
|
9660
|
+
raw.orgsKnown = true;
|
|
9661
|
+
progress();
|
|
9662
|
+
return orgs.map((o, i) => {
|
|
9663
|
+
const p = retrying(() => account9.listItems(api, { query: { principal_type: "organization", organization_id: o.id } }, { organizationId: o.id }));
|
|
9664
|
+
const arrived = p.then((l) => {
|
|
9665
|
+
raw.orgLists[i] = l;
|
|
9666
|
+
progress();
|
|
9667
|
+
return l;
|
|
9668
|
+
});
|
|
9669
|
+
quiet(arrived);
|
|
9670
|
+
return arrived;
|
|
9671
|
+
});
|
|
9672
|
+
})();
|
|
9673
|
+
quiet(orgListsReady);
|
|
9674
|
+
const authDone = authP.then((a) => {
|
|
9675
|
+
auth = new Map((a.entries ?? []).map((e) => [e.credential_item_id, e]));
|
|
9676
|
+
progress();
|
|
9677
|
+
}, () => {
|
|
9678
|
+
unavailable.push("One-time codes");
|
|
9679
|
+
});
|
|
9680
|
+
const sharedDone = sharedP.then((sh) => {
|
|
9681
|
+
raw.shared = sh;
|
|
9682
|
+
progress();
|
|
9683
|
+
}, () => {
|
|
9684
|
+
raw.shared = { items: [], count: 0 };
|
|
9685
|
+
unavailable.push("Shared with me");
|
|
9686
|
+
});
|
|
9687
|
+
const [catalog, mine] = await Promise.all([catalogP, userP]);
|
|
9688
|
+
raw.catalog = catalog;
|
|
9689
|
+
raw.mine = mine;
|
|
9690
|
+
progress();
|
|
9691
|
+
const orgPs = await orgListsReady;
|
|
9692
|
+
const orgSettled = await Promise.allSettled(orgPs);
|
|
9693
|
+
orgSettled.forEach((r, i) => {
|
|
9694
|
+
if (r.status === "rejected") {
|
|
9695
|
+
raw.orgLists[i] = { items: [], count: 0 };
|
|
9696
|
+
unavailable.push(orgs[i]?.name ?? "An organization");
|
|
9569
9697
|
}
|
|
9570
9698
|
});
|
|
9571
|
-
|
|
9699
|
+
await Promise.all([authDone, sharedDone]);
|
|
9700
|
+
done = true;
|
|
9701
|
+
return build();
|
|
9572
9702
|
},
|
|
9573
9703
|
async reveal(item, fieldKey2) {
|
|
9574
9704
|
const field = item.fields.find((f) => f.key === fieldKey2);
|
|
@@ -9735,6 +9865,7 @@ export {
|
|
|
9735
9865
|
needsRecentSignIn,
|
|
9736
9866
|
parseDefinitions,
|
|
9737
9867
|
providerOf,
|
|
9868
|
+
rowMenuEntriesAt,
|
|
9738
9869
|
siteDomainOf,
|
|
9739
9870
|
sortItems,
|
|
9740
9871
|
useConfirmed,
|