@ai-matrx/vault 0.1.55 → 0.1.56
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 +5 -1
- package/dist/index.cjs +51 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +51 -14
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.56
|
|
4
|
+
|
|
5
|
+
- No changes yet.
|
|
6
|
+
|
|
3
7
|
## 0.1.55
|
|
4
8
|
|
|
5
|
-
- Password Health can discover a prior scan when neither request nor execution handle is available, and binds recovered results and progress to the originating health port. Consumer action: custom `HealthPort` implementations must provide `discover(cursor, signal)`; `createApiVaultPort` wires it automatically. Discovery returns authorized request/execution references only.
|
|
9
|
+
- Password Health can discover a prior scan when neither request nor execution handle is available, and binds recovered results and progress to the originating health port. Consumer action: custom `HealthPort` implementations must provide `discover(cursor, signal)`; `createApiVaultPort` wires it automatically. Discovery returns authorized request/execution references only. External request/execution handle changes retire pending work and recover the new address; matching self-written handles preserve the current run.
|
|
6
10
|
|
|
7
11
|
## 0.1.54
|
|
8
12
|
|
package/dist/index.cjs
CHANGED
|
@@ -2702,7 +2702,7 @@ function normalizeWebsite(raw) {
|
|
|
2702
2702
|
}
|
|
2703
2703
|
function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChanged, onAdded, onDone }) {
|
|
2704
2704
|
const confirmed = useConfirmed();
|
|
2705
|
-
const candidates = items.filter((i) => !i.authenticator && !i.deletion && (i.capabilities.canEdit || i.capabilities.canManage)).sort((a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" }));
|
|
2705
|
+
const candidates = items.filter((i) => i.authenticatorState === "known" && !i.authenticator && !i.deletion && (i.capabilities.canEdit || i.capabilities.canManage)).sort((a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" }));
|
|
2706
2706
|
const [input, setInput] = (0, import_react13.useState)("");
|
|
2707
2707
|
const [image, setImage] = (0, import_react13.useState)(null);
|
|
2708
2708
|
const [target, setTarget] = (0, import_react13.useState)(itemId && candidates.some((c) => c.id === itemId) ? itemId : NEW);
|
|
@@ -2741,7 +2741,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2741
2741
|
}
|
|
2742
2742
|
const it = item;
|
|
2743
2743
|
const entry = await confirmed(() => image ? port.authenticator.enrolQrImage(it, image, image.name) : port.authenticator.enrol(it, input));
|
|
2744
|
-
let next = { ...it, authenticator: { digits: entry.digits, period: entry.period, enabled: entry.enabled } };
|
|
2744
|
+
let next = { ...it, authenticatorState: "known", authenticator: { digits: entry.digits, period: entry.period, enabled: entry.enabled } };
|
|
2745
2745
|
const better = authenticatorName(it.name, { issuer: entry.issuer, account: entry.account });
|
|
2746
2746
|
if (!isNew && better !== it.name) {
|
|
2747
2747
|
try {
|
|
@@ -2879,6 +2879,7 @@ function AuthenticatorView({ port, host, items: listed, definitions, query, onOp
|
|
|
2879
2879
|
(0, import_react14.useEffect)(() => {
|
|
2880
2880
|
if (added.size > 0 && [...added.keys()].every((id) => listed.some((i) => i.id === id && i.authenticator))) setAdded(/* @__PURE__ */ new Map());
|
|
2881
2881
|
}, [listed, added]);
|
|
2882
|
+
const [incomplete, setIncomplete] = (0, import_react14.useState)(true);
|
|
2882
2883
|
const [entries, setEntries] = (0, import_react14.useState)(/* @__PURE__ */ new Map());
|
|
2883
2884
|
const [hidden, setHidden] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
|
|
2884
2885
|
const [adding, setAdding] = (0, import_react14.useState)(false);
|
|
@@ -2888,8 +2889,15 @@ function AuthenticatorView({ port, host, items: listed, definitions, query, onOp
|
|
|
2888
2889
|
(0, import_react14.useEffect)(() => {
|
|
2889
2890
|
let live = true;
|
|
2890
2891
|
port.authenticator.list().then(
|
|
2891
|
-
(list) =>
|
|
2892
|
-
|
|
2892
|
+
(list) => {
|
|
2893
|
+
if (live) {
|
|
2894
|
+
setEntries(new Map(list.entries.map((e) => [e.itemId, e])));
|
|
2895
|
+
setIncomplete(list.unavailableScopes.length > 0);
|
|
2896
|
+
}
|
|
2897
|
+
},
|
|
2898
|
+
() => {
|
|
2899
|
+
if (live) setIncomplete(true);
|
|
2900
|
+
}
|
|
2893
2901
|
);
|
|
2894
2902
|
return () => {
|
|
2895
2903
|
live = false;
|
|
@@ -2907,7 +2915,14 @@ function AuthenticatorView({ port, host, items: listed, definitions, query, onOp
|
|
|
2907
2915
|
] }),
|
|
2908
2916
|
total > 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add" }) : null
|
|
2909
2917
|
] }),
|
|
2910
|
-
total
|
|
2918
|
+
total > 0 && incomplete ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "px-4 text-sm text-muted-foreground", children: [
|
|
2919
|
+
"Some codes unavailable ",
|
|
2920
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "quiet", onClick: onChanged, children: "Retry" })
|
|
2921
|
+
] }) : null,
|
|
2922
|
+
total === 0 && (incomplete || items.some((i) => i.authenticatorState !== "known")) ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: [
|
|
2923
|
+
"Codes unavailable ",
|
|
2924
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "quiet", onClick: onChanged, children: "Retry" })
|
|
2925
|
+
] }) : total === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 px-6 pb-12 text-center", children: [
|
|
2911
2926
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "flex size-12 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ShieldGlyph, { className: "size-6" }) }),
|
|
2912
2927
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm font-medium text-foreground", children: "No authenticator codes yet" }),
|
|
2913
2928
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_controls10.Button, { variant: "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add authenticator" })
|
|
@@ -6954,7 +6969,10 @@ function ItemPane(props) {
|
|
|
6954
6969
|
i
|
|
6955
6970
|
)),
|
|
6956
6971
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(AddRow, { label: draft.loginUrls.length === 0 ? "Website" : "", onAdd: () => patch({ loginUrls: [...draft.loginUrls, ""] }), children: draft.loginUrls.length === 0 ? "Add website" : "Add another website" }),
|
|
6957
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
|
|
6972
|
+
!item || item.authenticatorState === "known" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(VaultRow, { label: "Authenticator", children: [
|
|
6973
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-muted-foreground", children: item.authenticatorState === "pending" ? "Loading" : "Unavailable" }),
|
|
6974
|
+
item.authenticatorState === "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", onClick: () => onChanged?.(), children: "Retry" }) : null
|
|
6975
|
+
] }),
|
|
6958
6976
|
item && isLogin && !item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TwoFactorMethodRow, { port, item, onChanged }) : null,
|
|
6959
6977
|
!item && isLogin && draft.authenticator.trim() === "" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(DraftTwoFactorRow, { custom: draft.custom, onCustom: (custom) => patch({ custom }) }) : null,
|
|
6960
6978
|
recoveryEditing ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
@@ -7033,7 +7051,10 @@ function ItemPane(props) {
|
|
|
7033
7051
|
}),
|
|
7034
7052
|
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SecretRow, { port, item, field: f, onTurnOn: turnOnOne(f), extra: fieldSettings(f) }, f.id)),
|
|
7035
7053
|
item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PlainRow, { label: i === 0 ? "Website" : `Website ${i + 1}`, value: u, openUrl: host.openUrl }, `${u}-${i}`)) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(AddRow, { label: "Website", onAdd: canEdit ? () => onMode("edit") : null, children: "Add website" }),
|
|
7036
|
-
item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TotpRow, { port, item, onChanged }) :
|
|
7054
|
+
item.authenticator ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TotpRow, { port, item, onChanged }) : item.authenticatorState !== "known" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(VaultRow, { label: "Authenticator", children: [
|
|
7055
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-muted-foreground", children: item.authenticatorState === "pending" ? "Loading" : "Unavailable" }),
|
|
7056
|
+
item.authenticatorState === "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", onClick: () => onChanged?.(), children: "Retry" }) : null
|
|
7057
|
+
] }) : seedField && !seedField.active ? (
|
|
7037
7058
|
// The secret is still there, only off: turning it on brings the codes back. Never "Set up",
|
|
7038
7059
|
// which would invite replacing a working two-factor secret.
|
|
7039
7060
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(VaultRow, { label: "Authenticator", actions: canTurnOn ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TurnOnButton, { label: "Authenticator", onTurnOn: () => turnOn([seedField]) }) : null, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-muted-foreground", children: "Turned off" }) })
|
|
@@ -9862,7 +9883,7 @@ function createAuthenticatorPort(ctx) {
|
|
|
9862
9883
|
return {
|
|
9863
9884
|
async list() {
|
|
9864
9885
|
const r = await apps.listAuthenticators(api);
|
|
9865
|
-
return (r.entries ?? []).map(entryOf);
|
|
9886
|
+
return { entries: (r.entries ?? []).map(entryOf), unavailableScopes: (r.unavailable_scopes ?? []).map((s) => ({ type: s.type, organizationId: s.organization_id ?? null })) };
|
|
9866
9887
|
},
|
|
9867
9888
|
async get(item) {
|
|
9868
9889
|
try {
|
|
@@ -10076,6 +10097,7 @@ function trashItem(r, ctx) {
|
|
|
10076
10097
|
fields: [],
|
|
10077
10098
|
custom: [],
|
|
10078
10099
|
authenticator: null,
|
|
10100
|
+
authenticatorState: "known",
|
|
10079
10101
|
capabilities: { canUse: false, canEdit: false, canReveal: false, canManage: true },
|
|
10080
10102
|
attachments: [],
|
|
10081
10103
|
uriMatchMode: "host",
|
|
@@ -10432,7 +10454,8 @@ function fieldOf(w, def) {
|
|
|
10432
10454
|
active: w.is_active ?? true
|
|
10433
10455
|
};
|
|
10434
10456
|
}
|
|
10435
|
-
|
|
10457
|
+
var scopeUnavailable = (owner, scopes) => scopes.some((s) => s.type === (owner.kind === "me" ? "user" : owner.kind === "organization" ? "organization" : "shared") && (s.type !== "organization" || !s.organization_id || s.organization_id === owner.organizationId));
|
|
10458
|
+
function itemOf(w, owner, defs, auth, state = "known", unavailable = [], inventoryOwner = owner) {
|
|
10436
10459
|
const def = defs.get(w.definition_key ?? "");
|
|
10437
10460
|
const a = auth.get(w.id);
|
|
10438
10461
|
const cap = w.capabilities ?? {};
|
|
@@ -10450,6 +10473,7 @@ function itemOf(w, owner, defs, auth) {
|
|
|
10450
10473
|
fields: (w.fields ?? []).filter((f) => f.execution_purpose !== "passkey_private").map((f) => fieldOf(f, def)),
|
|
10451
10474
|
custom: (w.non_secret_fields ?? []).map((c) => ({ key: c["key"] ?? "", label: c["label"] ?? humanize(c["key"] ?? ""), value: c["value"] ?? "" })),
|
|
10452
10475
|
authenticator: a ? { digits: a.digits, period: a.period, enabled: a.enabled } : null,
|
|
10476
|
+
authenticatorState: a ? "known" : state === "pending" ? "pending" : state === "unavailable" || scopeUnavailable(inventoryOwner, unavailable) ? "unavailable" : "known",
|
|
10453
10477
|
capabilities: { canUse: cap.can_use ?? false, canEdit: cap.can_edit ?? false, canReveal: cap.can_reveal ?? false, canManage: cap.can_manage ?? false },
|
|
10454
10478
|
attachments: (w.attachments ?? []).map((a2) => ({ id: a2.id, label: a2.label, description: a2.description ?? "", fileName: a2.file_name, mediaType: a2.media_type ?? "application/octet-stream", sizeBytes: a2.size_bytes, handling: handlingOf(a2.handling), createdAt: a2.created_at, updatedAt: a2.updated_at })),
|
|
10455
10479
|
uriMatchMode: MATCH_MODES2.find((m) => m === w.uri_match_mode) ?? "host",
|
|
@@ -10486,6 +10510,9 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10486
10510
|
};
|
|
10487
10511
|
let defs = /* @__PURE__ */ new Map();
|
|
10488
10512
|
let auth = /* @__PURE__ */ new Map();
|
|
10513
|
+
let authState = "pending";
|
|
10514
|
+
let authUnavailable = [];
|
|
10515
|
+
let inventoryOwners = /* @__PURE__ */ new Map();
|
|
10489
10516
|
let orgs = [];
|
|
10490
10517
|
const orgOf = (id, userId, mine) => {
|
|
10491
10518
|
if (id) return { kind: "organization", label: orgs.find((o) => o.id === id)?.name ?? "Organization", organizationId: id };
|
|
@@ -10499,7 +10526,7 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10499
10526
|
};
|
|
10500
10527
|
async function refetch(id, owner) {
|
|
10501
10528
|
const w = await account9.getItem(api, { path: { item_id: id } });
|
|
10502
|
-
return itemOf(w, owner, defs, auth);
|
|
10529
|
+
return itemOf(w, owner, defs, auth, authState, authUnavailable, inventoryOwners.get(id) ?? owner);
|
|
10503
10530
|
}
|
|
10504
10531
|
const visibleCache = /* @__PURE__ */ new Map();
|
|
10505
10532
|
const ctx = {
|
|
@@ -10526,6 +10553,10 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10526
10553
|
fields: createFieldsPort(ctx),
|
|
10527
10554
|
lists: createListsPort(ctx, options.userState),
|
|
10528
10555
|
async load(onProgress) {
|
|
10556
|
+
authState = "pending";
|
|
10557
|
+
auth = /* @__PURE__ */ new Map();
|
|
10558
|
+
authUnavailable = [];
|
|
10559
|
+
inventoryOwners = /* @__PURE__ */ new Map();
|
|
10529
10560
|
const catalogP = retrying(() => apps2.getAppCatalogKind(api, { path: { app: "matrx", kind: "credential_definition" } }));
|
|
10530
10561
|
const authP = retrying(() => apps2.listAuthenticators(api));
|
|
10531
10562
|
const userP = retrying(() => account9.listItems(api, { query: { principal_type: "user" } }));
|
|
@@ -10548,9 +10579,10 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10548
10579
|
const meId = raw.meId ?? mineItems.find((w) => w.user_id)?.user_id ?? null;
|
|
10549
10580
|
const seen = /* @__PURE__ */ new Map();
|
|
10550
10581
|
const deleted = /* @__PURE__ */ new Map();
|
|
10551
|
-
const take = (w, owner) => {
|
|
10582
|
+
const take = (w, owner, inventoryOwner = owner) => {
|
|
10552
10583
|
if (seen.has(w.id) || deleted.has(w.id) || isHiddenItem(w)) return;
|
|
10553
|
-
|
|
10584
|
+
inventoryOwners.set(w.id, inventoryOwner);
|
|
10585
|
+
const item = itemOf(w, owner, defs, auth, authState, authUnavailable, inventoryOwner);
|
|
10554
10586
|
(isDeleted(w) ? deleted : seen).set(w.id, item);
|
|
10555
10587
|
};
|
|
10556
10588
|
for (const w of mineItems) take(w, orgOf(w.organization_id, null, true));
|
|
@@ -10558,7 +10590,7 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10558
10590
|
const via = orgs[i];
|
|
10559
10591
|
for (const w of l?.items ?? []) take(w, ownerInOrgList(w, via, meId));
|
|
10560
10592
|
});
|
|
10561
|
-
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 });
|
|
10593
|
+
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 }, { kind: "shared", label: "Shared with me", organizationId: null });
|
|
10562
10594
|
const pending = done ? [] : [...raw.orgsKnown ? orgs.filter((_, i) => raw.orgLists[i] === void 0).map((o) => o.name) : ["your organizations"], ...raw.shared ? [] : ["Shared with me"]];
|
|
10563
10595
|
return {
|
|
10564
10596
|
unavailable: [...unavailable],
|
|
@@ -10617,9 +10649,14 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10617
10649
|
})();
|
|
10618
10650
|
quiet(orgListsReady);
|
|
10619
10651
|
const authDone = authP.then((a) => {
|
|
10620
|
-
|
|
10652
|
+
authUnavailable = a.unavailable_scopes ?? [];
|
|
10653
|
+
const fresh = new Map((a.entries ?? []).map((e) => [e.credential_item_id, e]));
|
|
10654
|
+
auth = fresh;
|
|
10655
|
+
authState = "known";
|
|
10656
|
+
if (authUnavailable.length) unavailable.push("One-time codes");
|
|
10621
10657
|
progress();
|
|
10622
10658
|
}, () => {
|
|
10659
|
+
authState = "unavailable";
|
|
10623
10660
|
unavailable.push("One-time codes");
|
|
10624
10661
|
});
|
|
10625
10662
|
const sharedDone = sharedP.then((sh) => {
|