@ai-matrx/vault 0.1.20 → 0.1.22
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 +18 -0
- package/dist/index.cjs +250 -123
- 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 +250 -123
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.22
|
|
4
|
+
|
|
5
|
+
- **A member's credential shared into an organization is the organization's, never "Personal".** An item in an organization's list is the viewer's own only when the viewer owns it (`platform.list_my_organizations` `user_id`, else the owner of the person's own list); a member's own credential shared into the organization is attributed to that organization (`VaultOwner.memberShared`), counted there, its badge says "A member's own credential, shared into <org>", and Share / Delete show disabled with the reason (`manageUnavailableReason`, `ownerDetail`); Copy stays offered to an editor. Consumer action: none.
|
|
6
|
+
- **The person's own items show first.** `VaultPort.load(onProgress?)` hands partial snapshots (`VaultSnapshot.pending`): the own list and the type catalog open the vault, each organization's list streams in as it answers; the list's count line says "loading <org>…" (no layout jump). A Refresh still applies only the finished read. Consumer action: none (a host with its own `VaultPort` may ignore `onProgress`).
|
|
7
|
+
- **The compact Vault and Show pickers keep a real width** (6rem minimum) at split widths (640–1119px): the Authenticator button beside them is icon-only (its name in the tooltip). Consumer action: none.
|
|
8
|
+
- **The star is on every list row** — the row's hover quick actions and its More / right-click menu (`ItemList` `favorites`, `onToggleFavorite`). Consumer action: none.
|
|
9
|
+
- **Every organization stays in the vault switcher**, empty ones too (count 0); an empty organization opens on "Nothing here yet" with New item saving there. Consumer action: none.
|
|
10
|
+
- **A host's own right-click menu reads the row's entries**: `rowMenuEntriesAt(target)` returns the clicked row's entries (`RowMenuEntry.kind` `copy` / `favorite` / `open` / `copy-name` / `host`) — the same list the row's own menu renders. **Consumer action:** web app (`rowContextMenu: "host"`): add the `copy` and `favorite` entries of `rowMenuEntriesAt(target)` to its v3 menu. Extension and desktop: none.
|
|
11
|
+
|
|
12
|
+
## 0.1.21
|
|
13
|
+
|
|
14
|
+
SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
|
|
15
|
+
so they may include breaking API changes. Consumer action is UNKNOWN: read the diff before upgrading.
|
|
16
|
+
Diff: `git diff 8efbb129f3 4abc64ee28 -- apps/shared/vault/src`
|
|
17
|
+
|
|
18
|
+
Changed shipped source files (1):
|
|
19
|
+
- `apps/shared/vault/src/FieldRows.tsx`
|
|
20
|
+
|
|
3
21
|
## 0.1.20
|
|
4
22
|
|
|
5
23
|
- **A multi-line secret edits as several lines.** A field whose type says multi-line, any field under a notes key (an old **Secure note**, `secure_notes`) and any value that already holds a line break now edit in a multi-line box — a one-line box dropped the line breaks on save. Shown values keep their lines too. Guard: `src/vault-gaps-2026-10-19.test.tsx`. Consumer action: none.
|
package/dist/index.cjs
CHANGED
|
@@ -160,6 +160,7 @@ __export(src_exports, {
|
|
|
160
160
|
needsRecentSignIn: () => needsRecentSignIn,
|
|
161
161
|
parseDefinitions: () => parseDefinitions,
|
|
162
162
|
providerOf: () => providerOf,
|
|
163
|
+
rowMenuEntriesAt: () => rowMenuEntriesAt,
|
|
163
164
|
siteDomainOf: () => siteDomainOf,
|
|
164
165
|
sortItems: () => sortItems,
|
|
165
166
|
useConfirmed: () => useConfirmed,
|
|
@@ -622,6 +623,8 @@ function ConfirmIdentityDialog({ open, identity, onDone, onCancel }) {
|
|
|
622
623
|
var import_react5 = require("react");
|
|
623
624
|
var import_controls2 = require("@ai-matrx/design-system/controls");
|
|
624
625
|
var import_design_system5 = require("@ai-matrx/design-system");
|
|
626
|
+
var import_outbound = require("@ai-matrx/kit/outbound");
|
|
627
|
+
var import_outbound_react = require("@ai-matrx/kit/outbound-react");
|
|
625
628
|
var import_icons2 = require("@ai-matrx/design-system/icons");
|
|
626
629
|
|
|
627
630
|
// src/hooks.ts
|
|
@@ -833,13 +836,13 @@ function PlainRow({ label, value, hint: hint2, openUrl, extra, multiline = false
|
|
|
833
836
|
top: multiline,
|
|
834
837
|
actions: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
835
838
|
extra,
|
|
836
|
-
isUrl && openUrl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExternalGlyph, {}), "aria-label": `Open ${value}`, onClick: () => openUrl(value) }) : null,
|
|
839
|
+
isUrl && openUrl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExternalGlyph, {}), "aria-label": `Open ${value}`, onClick: () => openUrl((0, import_outbound.withReferral)(value)) }) : null,
|
|
837
840
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_controls2.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_icons2.CopyIcon, {}), "aria-label": `Copy ${typeof label === "string" ? label : "value"}`, onClick: () => void copyValue2(value, typeof label === "string" && label ? label : "Value", { secret: false }) })
|
|
838
841
|
] }),
|
|
839
842
|
children: isUrl && openUrl ? (
|
|
840
843
|
// A real link (right-click, copy link address, open in a new tab); a click goes through the host's opener.
|
|
841
844
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
842
|
-
|
|
845
|
+
import_outbound_react.OutboundLink,
|
|
843
846
|
{
|
|
844
847
|
href: value,
|
|
845
848
|
target: "_blank",
|
|
@@ -847,7 +850,7 @@ function PlainRow({ label, value, hint: hint2, openUrl, extra, multiline = false
|
|
|
847
850
|
className: "block max-w-full truncate text-primary hover:underline",
|
|
848
851
|
onClick: (e) => {
|
|
849
852
|
e.preventDefault();
|
|
850
|
-
openUrl(value);
|
|
853
|
+
openUrl((0, import_outbound.withReferral)(value));
|
|
851
854
|
},
|
|
852
855
|
children: value.replace(/^https?:\/\//i, "").replace(/\/$/, "")
|
|
853
856
|
}
|
|
@@ -916,6 +919,19 @@ var import_format3 = require("@ai-matrx/kit/format");
|
|
|
916
919
|
var import_format = require("@ai-matrx/kit/format");
|
|
917
920
|
|
|
918
921
|
// src/model.ts
|
|
922
|
+
function manageUnavailableReason(item) {
|
|
923
|
+
if (item.capabilities.canManage) return null;
|
|
924
|
+
if (item.owner.memberShared) return "Only the member who owns it can share, move or delete it";
|
|
925
|
+
if (item.owner.kind === "shared") return "Only its owner can share, move or delete it";
|
|
926
|
+
if (item.owner.kind === "organization") return "Only this organization's vault admins can change that";
|
|
927
|
+
return "You can use this item but not share, move or delete it";
|
|
928
|
+
}
|
|
929
|
+
function ownerDetail(owner) {
|
|
930
|
+
if (owner.memberShared) return `A member's own credential, shared into ${owner.label}`;
|
|
931
|
+
if (owner.kind === "organization") return `Organization: ${owner.label}`;
|
|
932
|
+
if (owner.kind === "shared") return "Shared with you by its owner";
|
|
933
|
+
return "Your own vault";
|
|
934
|
+
}
|
|
919
935
|
var DEFAULT_LOCATION = { vault: "all", view: "all", q: "", sort: "name", itemId: null, mode: "view", kind: null, url: "", panel: null };
|
|
920
936
|
var SORTS = ["name", "name-desc", "website", "updated", "created", "viewed"];
|
|
921
937
|
function locationFromParams(params, itemId = params.get("item")) {
|
|
@@ -6055,6 +6071,7 @@ function ItemPane(props) {
|
|
|
6055
6071
|
const setValue = (key, v) => setDraft((d) => ({ ...d, values: { ...d.values, [key]: v } }));
|
|
6056
6072
|
const canEdit = item ? item.capabilities.canEdit || item.capabilities.canManage : true;
|
|
6057
6073
|
const canManage = item?.capabilities.canManage ?? false;
|
|
6074
|
+
const manageReason = item ? manageUnavailableReason(item) : null;
|
|
6058
6075
|
async function save() {
|
|
6059
6076
|
if (!definition && !item) return;
|
|
6060
6077
|
setBusy(true);
|
|
@@ -6201,7 +6218,8 @@ function ItemPane(props) {
|
|
|
6201
6218
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { className: "truncate text-base font-semibold leading-tight", children: editing ? draft.name || (mode === "new" ? `New ${typeLabel.toLowerCase()}` : item?.name) : item?.name }),
|
|
6202
6219
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "flex min-w-0 items-center gap-1 text-xs text-muted-foreground", children: [
|
|
6203
6220
|
typeLabel ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "truncate", children: typeLabel }) : null,
|
|
6204
|
-
shownOwner ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Badge, { className: "shrink-0", icon: shownOwner.glyph, "aria-label": `Saved in ${shownOwner.label}`, children: shownOwner.label }) : null,
|
|
6221
|
+
shownOwner ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_controls22.Badge, { 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,
|
|
6222
|
+
item && mode !== "new" && item.owner.memberShared ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "shrink-0", "data-member-shared": "", children: "\xB7 A member\u2019s own" }) : null,
|
|
6205
6223
|
item && !editing ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SharingSummary, { item, port, className: "hidden truncate before:mr-1 before:content-['\xB7'] sm:inline" }, `${item.updatedAt}-${refreshKey ?? ""}`) : null
|
|
6206
6224
|
] })
|
|
6207
6225
|
] }),
|
|
@@ -6239,9 +6257,9 @@ function ItemPane(props) {
|
|
|
6239
6257
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ShareGlyph, { className: "size-4" }),
|
|
6240
6258
|
"Share"
|
|
6241
6259
|
] }) : null,
|
|
6242
|
-
canManage ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: () => onPanel("move"), children: [
|
|
6260
|
+
canManage || item.capabilities.canEdit ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: () => onPanel("move"), children: [
|
|
6243
6261
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MoveGlyph, { className: "size-4" }),
|
|
6244
|
-
"Move or copy"
|
|
6262
|
+
canManage ? "Move or copy" : "Copy to\u2026"
|
|
6245
6263
|
] }) : null,
|
|
6246
6264
|
item.capabilities.canReveal ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { onSelect: () => onPanel("send"), children: [
|
|
6247
6265
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SendGlyph, { className: "size-4" }),
|
|
@@ -6265,6 +6283,17 @@ function ItemPane(props) {
|
|
|
6265
6283
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TrashGlyph, { className: "size-4" }),
|
|
6266
6284
|
"Delete"
|
|
6267
6285
|
] })
|
|
6286
|
+
] }) : manageReason ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
6287
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_design_system17.DropdownMenuSeparator, {}),
|
|
6288
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { disabled: true, children: [
|
|
6289
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ShareGlyph, { className: "size-4" }),
|
|
6290
|
+
"Share"
|
|
6291
|
+
] }),
|
|
6292
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_design_system17.DropdownMenuItem, { disabled: true, children: [
|
|
6293
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TrashGlyph, { className: "size-4" }),
|
|
6294
|
+
"Delete"
|
|
6295
|
+
] }),
|
|
6296
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "max-w-64 px-2 py-1.5 text-xs text-muted-foreground", "data-manage-reason": "", children: manageReason })
|
|
6268
6297
|
] }) : null
|
|
6269
6298
|
] })
|
|
6270
6299
|
] })
|
|
@@ -6495,6 +6524,17 @@ function ItemPane(props) {
|
|
|
6495
6524
|
] }) });
|
|
6496
6525
|
}
|
|
6497
6526
|
|
|
6527
|
+
// src/row-menu.ts
|
|
6528
|
+
var readers = /* @__PURE__ */ new WeakMap();
|
|
6529
|
+
function registerRowMenu(el, read) {
|
|
6530
|
+
if (el) readers.set(el, read);
|
|
6531
|
+
}
|
|
6532
|
+
function rowMenuEntriesAt(target) {
|
|
6533
|
+
const row = target?.closest("[data-item]");
|
|
6534
|
+
const read = row ? readers.get(row) : void 0;
|
|
6535
|
+
return read ? read() : [];
|
|
6536
|
+
}
|
|
6537
|
+
|
|
6498
6538
|
// src/ItemList.tsx
|
|
6499
6539
|
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
6500
6540
|
var RECOVERY_KEYS = /^recovery_codes?$/;
|
|
@@ -6516,7 +6556,7 @@ function subtitleOf(item, withOwner) {
|
|
|
6516
6556
|
const what = loginSiteOf(item) || item.definitionLabel;
|
|
6517
6557
|
return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
|
|
6518
6558
|
}
|
|
6519
|
-
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner, canSortViewed = false, onRefresh, refreshing = false, rowContextMenu = "package", rowMenuItems }) {
|
|
6559
|
+
function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner, canSortViewed = false, onRefresh, refreshing = false, rowContextMenu = "package", rowMenuItems, stillLoading, favorites, onToggleFavorite }) {
|
|
6520
6560
|
const sorts = SORTS2.filter((s) => canSortViewed || s.value !== "viewed");
|
|
6521
6561
|
const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
|
|
6522
6562
|
const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
|
|
@@ -6537,7 +6577,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6537
6577
|
}
|
|
6538
6578
|
};
|
|
6539
6579
|
const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
|
|
6540
|
-
const row = (i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners, ownContextMenu: rowContextMenu === "package", extra: rowMenuItems }, i.id);
|
|
6580
|
+
const row = (i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(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);
|
|
6541
6581
|
const sortLabel = sorts.find((s) => s.value === sort)?.label ?? "Name A\u2013Z";
|
|
6542
6582
|
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
|
|
6543
6583
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children: [
|
|
@@ -6547,10 +6587,18 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6547
6587
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PlusGlyph, {}), "aria-label": "New item", onClick: onNew })
|
|
6548
6588
|
] }),
|
|
6549
6589
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center justify-between gap-2 px-1", children: [
|
|
6550
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "truncate text-xs text-muted-foreground", children: [
|
|
6590
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "flex min-w-0 items-center gap-1.5 truncate text-xs text-muted-foreground", role: "status", "aria-live": "polite", children: [
|
|
6551
6591
|
items.length,
|
|
6552
6592
|
" ",
|
|
6553
|
-
items.length === 1 ? "item" : "items"
|
|
6593
|
+
items.length === 1 ? "item" : "items",
|
|
6594
|
+
stillLoading && stillLoading.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "flex min-w-0 items-center gap-1 truncate", title: `Still loading ${stillLoading.join(", ")}`, "data-still-loading": "", children: [
|
|
6595
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(RefreshGlyph, { className: "size-3 shrink-0 animate-spin" }),
|
|
6596
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "truncate", children: [
|
|
6597
|
+
"loading ",
|
|
6598
|
+
stillLoading.length === 1 ? stillLoading[0] : `${stillLoading.length} more`,
|
|
6599
|
+
"\u2026"
|
|
6600
|
+
] })
|
|
6601
|
+
] }) : null
|
|
6554
6602
|
] }),
|
|
6555
6603
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "flex shrink-0 items-center gap-0.5", children: [
|
|
6556
6604
|
onRefresh ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(RefreshGlyph, { className: refreshing ? "animate-spin" : "" }), "aria-label": "Refresh", title: "Refresh the list", disabled: refreshing, onClick: onRefresh }) : null,
|
|
@@ -6562,7 +6610,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6562
6610
|
] })
|
|
6563
6611
|
] }),
|
|
6564
6612
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto px-2 pb-3", onKeyDown, children: items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col items-center gap-3 px-4 py-12 text-center", children: [
|
|
6565
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-sm text-muted-foreground", children: query ? `Nothing matches \u201C${query}\u201D.` : "Nothing here yet." }),
|
|
6613
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-sm text-muted-foreground", children: query ? `Nothing matches \u201C${query}\u201D.` : stillLoading && stillLoading.length > 0 ? "Still loading\u2026" : "Nothing here yet." }),
|
|
6566
6614
|
query ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "outline", onClick: () => onQuery(""), children: "Clear search" }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PlusGlyph, {}), onClick: onNew, children: "New item" })
|
|
6567
6615
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("ul", { ref: listRef, className: "flex flex-col gap-px", children: [
|
|
6568
6616
|
pinned.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("li", { className: "px-2 pb-1 pt-1 text-xs font-medium text-muted-foreground", children: "This page" }) : null,
|
|
@@ -6572,7 +6620,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
|
|
|
6572
6620
|
] }) })
|
|
6573
6621
|
] });
|
|
6574
6622
|
}
|
|
6575
|
-
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra }) {
|
|
6623
|
+
function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu, extra, favorite }) {
|
|
6576
6624
|
const confirmed = useConfirmed();
|
|
6577
6625
|
const copy = useCopy();
|
|
6578
6626
|
const notify = useNotify();
|
|
@@ -6600,9 +6648,32 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6600
6648
|
const others = otherCopyFields(item, user, secret);
|
|
6601
6649
|
const custom = canUse ? item.custom.filter((c) => c.value) : [];
|
|
6602
6650
|
const hostEntries = extra?.(item) ?? [];
|
|
6651
|
+
const copyEntries = [
|
|
6652
|
+
...user ? [{ id: "copy:username", kind: "copy", label: `Copy ${user.label.toLowerCase()}`, onSelect: copyUser }] : [],
|
|
6653
|
+
...secret ? [{ id: "copy:password", kind: "copy", label: "Copy password", onSelect: copyPassword }] : [],
|
|
6654
|
+
...code ? [{ id: "copy:code", kind: "copy", label: "Copy one-time code", onSelect: copyCode }] : [],
|
|
6655
|
+
...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") })),
|
|
6656
|
+
...custom.map((c) => ({ id: `copy:custom:${c.key}`, kind: "copy", label: `Copy ${c.label.toLowerCase()}`, onSelect: () => void copy(c.value, c.label, { secret: false }) }))
|
|
6657
|
+
];
|
|
6658
|
+
const favoriteEntry = favorite ? { id: "favorite", kind: "favorite", label: favorite.on ? "Remove from favorites" : "Add to favorites", onSelect: favorite.toggle } : null;
|
|
6659
|
+
const entries = [
|
|
6660
|
+
...copyEntries,
|
|
6661
|
+
...favoriteEntry ? [favoriteEntry] : [],
|
|
6662
|
+
{ id: "open", kind: "open", label: "Open", onSelect: () => onSelect(item.id) },
|
|
6663
|
+
{ id: "copy-name", kind: "copy-name", label: "Copy name", onSelect: copyName },
|
|
6664
|
+
...hostEntries.map((h) => ({ ...h, kind: h.kind ?? "host" }))
|
|
6665
|
+
];
|
|
6666
|
+
const entriesRef = (0, import_react29.useRef)(entries);
|
|
6667
|
+
entriesRef.current = entries;
|
|
6668
|
+
const glyphOf = (e) => e.id === "copy:username" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(UserGlyph, { className: "size-4" }) : e.id === "copy:password" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, { className: "size-4" }) : e.id === "copy:code" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ClockGlyph, { className: "size-4" }) : e.kind === "favorite" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(StarGlyph, { className: (0, import_design_system20.cn)("size-4", favorite?.on && "fill-current text-warning") }) : e.kind === "open" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronRightGlyph, { className: "size-4" }) : e.kind === "host" ? null : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_icons12.CopyIcon, { className: "size-4" });
|
|
6669
|
+
const menuItem = (e) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { disabled: e.disabled ?? false, onSelect: e.onSelect, children: [
|
|
6670
|
+
glyphOf(e),
|
|
6671
|
+
e.label
|
|
6672
|
+
] }, e.id ?? e.label);
|
|
6603
6673
|
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
6604
6674
|
"li",
|
|
6605
6675
|
{
|
|
6676
|
+
ref: (el) => registerRowMenu(el, () => entriesRef.current),
|
|
6606
6677
|
className: "group relative",
|
|
6607
6678
|
"data-item": item.id,
|
|
6608
6679
|
onContextMenu: ownContextMenu ? (e) => {
|
|
@@ -6628,7 +6699,8 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6628
6699
|
}
|
|
6629
6700
|
),
|
|
6630
6701
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("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: [
|
|
6631
|
-
user || secret ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: (0, import_design_system20.cn)("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: [
|
|
6702
|
+
user || secret || favorite ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: (0, import_design_system20.cn)("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: [
|
|
6703
|
+
favorite ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(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,
|
|
6632
6704
|
user ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(UserGlyph, {}), "aria-label": `Copy ${user.label}`, disabled: busy, onClick: copyUser }) : null,
|
|
6633
6705
|
secret ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: copyPassword }) : null
|
|
6634
6706
|
] }) : null,
|
|
@@ -6644,40 +6716,11 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
|
|
|
6644
6716
|
}
|
|
6645
6717
|
) }),
|
|
6646
6718
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuContent, { align: "end", children: [
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
user.label.toLowerCase()
|
|
6651
|
-
] }) : null,
|
|
6652
|
-
secret ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: copyPassword, children: [
|
|
6653
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, { className: "size-4" }),
|
|
6654
|
-
"Copy password"
|
|
6655
|
-
] }) : null,
|
|
6656
|
-
code ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: copyCode, children: [
|
|
6657
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ClockGlyph, { className: "size-4" }),
|
|
6658
|
-
"Copy one-time code"
|
|
6659
|
-
] }) : null,
|
|
6660
|
-
others.map((f) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: () => void run(f.label, () => port.reveal(item, f.key), f.handling !== "visible"), children: [
|
|
6661
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_icons12.CopyIcon, { className: "size-4" }),
|
|
6662
|
-
"Copy ",
|
|
6663
|
-
f.label.toLowerCase()
|
|
6664
|
-
] }, f.key)),
|
|
6665
|
-
custom.map((c) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: () => void copy(c.value, c.label, { secret: false }), children: [
|
|
6666
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_icons12.CopyIcon, { className: "size-4" }),
|
|
6667
|
-
"Copy ",
|
|
6668
|
-
c.label.toLowerCase()
|
|
6669
|
-
] }, `custom:${c.key}`)),
|
|
6670
|
-
user || secret || code || others.length > 0 || custom.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6671
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: () => onSelect(item.id), children: [
|
|
6672
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronRightGlyph, { className: "size-4" }),
|
|
6673
|
-
"Open"
|
|
6674
|
-
] }),
|
|
6675
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { onSelect: copyName, children: [
|
|
6676
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_icons12.CopyIcon, { className: "size-4" }),
|
|
6677
|
-
"Copy name"
|
|
6678
|
-
] }),
|
|
6719
|
+
copyEntries.map(menuItem),
|
|
6720
|
+
copyEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6721
|
+
entries.filter((e) => e.kind === "favorite" || e.kind === "open" || e.kind === "copy-name").map(menuItem),
|
|
6679
6722
|
hostEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuSeparator, {}) : null,
|
|
6680
|
-
|
|
6723
|
+
entries.filter((e) => e.kind === "host").map(menuItem)
|
|
6681
6724
|
] })
|
|
6682
6725
|
] })
|
|
6683
6726
|
] })
|
|
@@ -8185,15 +8228,17 @@ var import_controls34 = require("@ai-matrx/design-system/controls");
|
|
|
8185
8228
|
var import_icons16 = require("@ai-matrx/design-system/icons");
|
|
8186
8229
|
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
8187
8230
|
var AUTHENTICATOR_LABEL = "Authenticator";
|
|
8188
|
-
function vaultChoices(items, organizations,
|
|
8231
|
+
function vaultChoices(items, organizations, _current) {
|
|
8189
8232
|
const n = (f) => items.filter(f).length;
|
|
8190
8233
|
const shared = n((i) => i.owner.kind === "shared");
|
|
8191
8234
|
return [
|
|
8192
8235
|
{ value: "all", label: "All items", count: items.length },
|
|
8193
8236
|
{ value: "mine", label: "Personal", count: n((i) => i.owner.kind === "me") },
|
|
8194
8237
|
...shared > 0 ? [{ value: "shared", label: "Shared with me", count: shared }] : [],
|
|
8195
|
-
//
|
|
8196
|
-
|
|
8238
|
+
// Every organization the person belongs to, empty ones too: an empty vault opens on its own
|
|
8239
|
+
// "Nothing here yet" with New item, so the first credential can go there. (The organization
|
|
8240
|
+
// list carries no role, so who may add is the server's answer to the save, said in place.)
|
|
8241
|
+
...organizations.map((o) => ({ value: o.id, label: o.name, count: n((i) => i.owner.organizationId === o.id) }))
|
|
8197
8242
|
];
|
|
8198
8243
|
}
|
|
8199
8244
|
function VaultSelect({ value, choices, onChange }) {
|
|
@@ -8473,7 +8518,16 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8473
8518
|
const load = (0, import_react42.useCallback)(() => {
|
|
8474
8519
|
setError(null);
|
|
8475
8520
|
setRefreshError(null);
|
|
8476
|
-
|
|
8521
|
+
let finished = false;
|
|
8522
|
+
port.load((partial) => {
|
|
8523
|
+
if (finished) return;
|
|
8524
|
+
setSnap(partial);
|
|
8525
|
+
setItems(partial.items);
|
|
8526
|
+
setDeleted(partial.deleted);
|
|
8527
|
+
}).then((s) => {
|
|
8528
|
+
finished = true;
|
|
8529
|
+
apply(s);
|
|
8530
|
+
}).catch((e) => {
|
|
8477
8531
|
setSignedOut(e?.status === 401);
|
|
8478
8532
|
setError(e instanceof Error ? e.message : "The vault could not be loaded.");
|
|
8479
8533
|
});
|
|
@@ -8590,59 +8644,62 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8590
8644
|
}
|
|
8591
8645
|
const hasFavorites = port.lists.favorites !== void 0;
|
|
8592
8646
|
const title = loc.vault === "all" && loc.view === "all" ? "All items" : viewLabel(loc.view, views);
|
|
8593
|
-
const compactHeader = mode === "full" ? void 0 :
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.
|
|
8597
|
-
|
|
8598
|
-
{
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.
|
|
8611
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.
|
|
8612
|
-
|
|
8613
|
-
"
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
"
|
|
8618
|
-
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
"
|
|
8622
|
-
|
|
8623
|
-
|
|
8624
|
-
|
|
8625
|
-
"
|
|
8626
|
-
|
|
8627
|
-
|
|
8628
|
-
|
|
8629
|
-
"
|
|
8630
|
-
|
|
8631
|
-
|
|
8632
|
-
|
|
8633
|
-
"
|
|
8634
|
-
|
|
8635
|
-
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
|
|
8642
|
-
|
|
8647
|
+
const compactHeader = mode === "full" ? void 0 : (
|
|
8648
|
+
// The two pickers keep a real width at every compact size (the list column is 19rem in split
|
|
8649
|
+
// mode): the Authenticator button is icon-only beside them, its name in its tooltip.
|
|
8650
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "grid grid-cols-[minmax(6rem,1fr)_minmax(6rem,1fr)_auto_auto] gap-2", "data-vault-compact-header": "", children: [
|
|
8651
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(VaultSelect, { value: loc.vault, choices, onChange: (vault) => go({ vault, itemId: null, panel: null }) }),
|
|
8652
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.Select, { 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" }),
|
|
8653
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
8654
|
+
import_controls35.Button,
|
|
8655
|
+
{
|
|
8656
|
+
variant: loc.view === "authenticator" ? "outline" : "quiet",
|
|
8657
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(LockGlyph, {}),
|
|
8658
|
+
"aria-label": AUTHENTICATOR_LABEL,
|
|
8659
|
+
"aria-pressed": loc.view === "authenticator",
|
|
8660
|
+
title: AUTHENTICATOR_LABEL,
|
|
8661
|
+
onClick: () => go({ view: loc.view === "authenticator" ? "all" : "authenticator", itemId: null, mode: "view", panel: null })
|
|
8662
|
+
}
|
|
8663
|
+
),
|
|
8664
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenu, { children: [
|
|
8665
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_design_system26.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(MoreGlyph, {}), "aria-label": "Vault actions" }) }),
|
|
8666
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuContent, { align: "end", children: [
|
|
8667
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "import" }), children: [
|
|
8668
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ImportGlyph, { className: "size-4" }),
|
|
8669
|
+
"Import"
|
|
8670
|
+
] }),
|
|
8671
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "export" }), children: [
|
|
8672
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ExportGlyph, { className: "size-4" }),
|
|
8673
|
+
"Export"
|
|
8674
|
+
] }),
|
|
8675
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "backup" }), children: [
|
|
8676
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(SafeGlyph, { className: "size-4" }),
|
|
8677
|
+
"Backup"
|
|
8678
|
+
] }),
|
|
8679
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "devices" }), children: [
|
|
8680
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ShieldGlyph, { className: "size-4" }),
|
|
8681
|
+
"Browsers that fill"
|
|
8682
|
+
] }),
|
|
8683
|
+
host.nativeImport ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => go({ panel: "import-passkeys" }), children: [
|
|
8684
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ImportGlyph, { className: "size-4" }),
|
|
8685
|
+
"Import passkeys"
|
|
8686
|
+
] }) : null,
|
|
8687
|
+
host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: host.nativeProvider.openSetup, children: [
|
|
8688
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ShieldGlyph, { className: "size-4" }),
|
|
8689
|
+
"System AutoFill"
|
|
8690
|
+
] }) : null,
|
|
8691
|
+
host.lock?.lock ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: () => void host.lock?.lock?.(), children: [
|
|
8692
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(LockGlyph, { className: "size-4" }),
|
|
8693
|
+
"Lock"
|
|
8694
|
+
] }) : null,
|
|
8695
|
+
host.openWebVault ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_design_system26.DropdownMenuItem, { onSelect: host.openWebVault, children: [
|
|
8696
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ExternalGlyph, { className: "size-4" }),
|
|
8697
|
+
"Open on the web"
|
|
8698
|
+
] }) : null
|
|
8699
|
+
] })
|
|
8643
8700
|
] })
|
|
8644
8701
|
] })
|
|
8645
|
-
|
|
8702
|
+
);
|
|
8646
8703
|
const viewHeader = /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
8647
8704
|
compactHeader,
|
|
8648
8705
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.SearchField, { value: loc.q, onChange: (e) => go({ q: e.target.value }, "replace"), placeholder: `Search ${viewLabel(loc.view, views)}`, "aria-label": `Search ${viewLabel(loc.view, views)}` })
|
|
@@ -8685,6 +8742,8 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
|
|
|
8685
8742
|
onNew: () => go({ itemId: null, mode: "new", kind: null, panel: null }),
|
|
8686
8743
|
onRefresh: refresh,
|
|
8687
8744
|
refreshing,
|
|
8745
|
+
...snap.pending && snap.pending.length > 0 ? { stillLoading: snap.pending } : {},
|
|
8746
|
+
...hasFavorites ? { favorites: favorites ?? /* @__PURE__ */ new Set(), onToggleFavorite: toggleFavorite } : {},
|
|
8688
8747
|
rowContextMenu: host.rowContextMenu ?? "package",
|
|
8689
8748
|
...host.rowMenuItems ? { rowMenuItems: host.rowMenuItems } : {},
|
|
8690
8749
|
...matchingIds ? { matchingIds } : {},
|
|
@@ -9574,6 +9633,12 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9574
9633
|
if (id) return { kind: "organization", label: orgs.find((o) => o.id === id)?.name ?? "Organization", organizationId: id };
|
|
9575
9634
|
return mine || userId ? { kind: "me", label: "Personal", organizationId: null } : { kind: "shared", label: "Shared with me", organizationId: null };
|
|
9576
9635
|
};
|
|
9636
|
+
const ownerInOrgList = (w, via, meId) => {
|
|
9637
|
+
if (w.organization_id) return orgOf(w.organization_id, null, false);
|
|
9638
|
+
if (w.user_id && meId && w.user_id === meId) return { kind: "me", label: "Personal", organizationId: null };
|
|
9639
|
+
if (via) return { kind: "organization", label: via.name, organizationId: via.id, memberShared: { userId: w.user_id ?? null } };
|
|
9640
|
+
return { kind: "shared", label: "Shared with me", organizationId: null };
|
|
9641
|
+
};
|
|
9577
9642
|
async function refetch(id, owner) {
|
|
9578
9643
|
const w = await account9.getItem(api, { path: { item_id: id } });
|
|
9579
9644
|
return itemOf(w, owner, defs, auth);
|
|
@@ -9601,38 +9666,100 @@ function createApiVaultPort(api, options = {}) {
|
|
|
9601
9666
|
io: createIoPort(ctx),
|
|
9602
9667
|
fields: createFieldsPort(ctx),
|
|
9603
9668
|
lists: createListsPort(ctx, options.userState),
|
|
9604
|
-
async load() {
|
|
9669
|
+
async load(onProgress) {
|
|
9605
9670
|
const catalogP = retrying(() => apps2.getAppCatalogKind(api, { path: { app: "matrx", kind: "credential_definition" } }));
|
|
9606
9671
|
const authP = retrying(() => apps2.listAuthenticators(api));
|
|
9607
9672
|
const userP = retrying(() => account9.listItems(api, { query: { principal_type: "user" } }));
|
|
9608
9673
|
const sharedP = retrying(() => account9.sharedWithMe(api));
|
|
9609
9674
|
const quiet = (p) => void p.catch(() => void 0);
|
|
9610
9675
|
[catalogP, authP, userP, sharedP].forEach(quiet);
|
|
9611
|
-
const
|
|
9612
|
-
|
|
9613
|
-
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
const [authSettled, sharedSettled, ...orgSettled] = await Promise.allSettled([authP, sharedP, ...orgListsP]);
|
|
9676
|
+
const raw = {
|
|
9677
|
+
orgLists: [],
|
|
9678
|
+
orgsKnown: options.organizations !== void 0,
|
|
9679
|
+
meId: null
|
|
9680
|
+
};
|
|
9617
9681
|
const unavailable = [];
|
|
9618
|
-
|
|
9619
|
-
const
|
|
9620
|
-
|
|
9621
|
-
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
|
|
9626
|
-
|
|
9627
|
-
|
|
9628
|
-
|
|
9629
|
-
if (seen.has(w.id) || deleted.has(w.id) || isHiddenItem(w)) continue;
|
|
9630
|
-
const owner = sharedList ? orgOf(w.organization_id, null, false) : orgOf(w.organization_id, w.user_id, i === 0);
|
|
9631
|
-
const item = itemOf(w, sharedList && !w.organization_id ? { kind: "shared", label: "Shared with me", organizationId: null } : owner, defs, auth);
|
|
9682
|
+
let done = false;
|
|
9683
|
+
const build = () => {
|
|
9684
|
+
const catalog2 = raw.catalog ?? [];
|
|
9685
|
+
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]));
|
|
9686
|
+
const mineItems = raw.mine?.items ?? [];
|
|
9687
|
+
const meId = raw.meId ?? mineItems.find((w) => w.user_id)?.user_id ?? null;
|
|
9688
|
+
const seen = /* @__PURE__ */ new Map();
|
|
9689
|
+
const deleted = /* @__PURE__ */ new Map();
|
|
9690
|
+
const take = (w, owner) => {
|
|
9691
|
+
if (seen.has(w.id) || deleted.has(w.id) || isHiddenItem(w)) return;
|
|
9692
|
+
const item = itemOf(w, owner, defs, auth);
|
|
9632
9693
|
(isDeleted(w) ? deleted : seen).set(w.id, item);
|
|
9694
|
+
};
|
|
9695
|
+
for (const w of mineItems) take(w, orgOf(w.organization_id, null, true));
|
|
9696
|
+
raw.orgLists.forEach((l, i) => {
|
|
9697
|
+
const via = orgs[i];
|
|
9698
|
+
for (const w of l?.items ?? []) take(w, ownerInOrgList(w, via, meId));
|
|
9699
|
+
});
|
|
9700
|
+
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 });
|
|
9701
|
+
const pending = done ? [] : [...raw.orgsKnown ? orgs.filter((_, i) => raw.orgLists[i] === void 0).map((o) => o.name) : ["your organizations"], ...raw.shared ? [] : ["Shared with me"]];
|
|
9702
|
+
return {
|
|
9703
|
+
unavailable: [...unavailable],
|
|
9704
|
+
...pending.length > 0 ? { pending } : {},
|
|
9705
|
+
items: [...seen.values()],
|
|
9706
|
+
deleted: [...deleted.values()],
|
|
9707
|
+
organizations: orgs,
|
|
9708
|
+
definitions: [...defs.values()].sort((a, b) => a.sortOrder - b.sortOrder || a.label.localeCompare(b.label))
|
|
9709
|
+
};
|
|
9710
|
+
};
|
|
9711
|
+
const progress = () => {
|
|
9712
|
+
if (!done && onProgress && raw.catalog && raw.mine) onProgress(build());
|
|
9713
|
+
};
|
|
9714
|
+
const orgReportP = options.organizations ? null : retrying(() => platform.listMyOrganizations(api));
|
|
9715
|
+
if (orgReportP) quiet(orgReportP);
|
|
9716
|
+
const orgListsReady = (async () => {
|
|
9717
|
+
const report = orgReportP ? await orgReportP : null;
|
|
9718
|
+
raw.meId = report?.user_id ?? null;
|
|
9719
|
+
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()];
|
|
9720
|
+
raw.orgLists = orgs.map(() => void 0);
|
|
9721
|
+
raw.orgsKnown = true;
|
|
9722
|
+
progress();
|
|
9723
|
+
return orgs.map((o, i) => {
|
|
9724
|
+
const p = retrying(() => account9.listItems(api, { query: { principal_type: "organization", organization_id: o.id } }, { organizationId: o.id }));
|
|
9725
|
+
const arrived = p.then((l) => {
|
|
9726
|
+
raw.orgLists[i] = l;
|
|
9727
|
+
progress();
|
|
9728
|
+
return l;
|
|
9729
|
+
});
|
|
9730
|
+
quiet(arrived);
|
|
9731
|
+
return arrived;
|
|
9732
|
+
});
|
|
9733
|
+
})();
|
|
9734
|
+
quiet(orgListsReady);
|
|
9735
|
+
const authDone = authP.then((a) => {
|
|
9736
|
+
auth = new Map((a.entries ?? []).map((e) => [e.credential_item_id, e]));
|
|
9737
|
+
progress();
|
|
9738
|
+
}, () => {
|
|
9739
|
+
unavailable.push("One-time codes");
|
|
9740
|
+
});
|
|
9741
|
+
const sharedDone = sharedP.then((sh) => {
|
|
9742
|
+
raw.shared = sh;
|
|
9743
|
+
progress();
|
|
9744
|
+
}, () => {
|
|
9745
|
+
raw.shared = { items: [], count: 0 };
|
|
9746
|
+
unavailable.push("Shared with me");
|
|
9747
|
+
});
|
|
9748
|
+
const [catalog, mine] = await Promise.all([catalogP, userP]);
|
|
9749
|
+
raw.catalog = catalog;
|
|
9750
|
+
raw.mine = mine;
|
|
9751
|
+
progress();
|
|
9752
|
+
const orgPs = await orgListsReady;
|
|
9753
|
+
const orgSettled = await Promise.allSettled(orgPs);
|
|
9754
|
+
orgSettled.forEach((r, i) => {
|
|
9755
|
+
if (r.status === "rejected") {
|
|
9756
|
+
raw.orgLists[i] = { items: [], count: 0 };
|
|
9757
|
+
unavailable.push(orgs[i]?.name ?? "An organization");
|
|
9633
9758
|
}
|
|
9634
9759
|
});
|
|
9635
|
-
|
|
9760
|
+
await Promise.all([authDone, sharedDone]);
|
|
9761
|
+
done = true;
|
|
9762
|
+
return build();
|
|
9636
9763
|
},
|
|
9637
9764
|
async reveal(item, fieldKey2) {
|
|
9638
9765
|
const field = item.fields.find((f) => f.key === fieldKey2);
|