@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/dist/index.d.cts
CHANGED
|
@@ -90,6 +90,7 @@ interface VaultItem {
|
|
|
90
90
|
fields: VaultField[];
|
|
91
91
|
custom: VaultCustomField[];
|
|
92
92
|
authenticator: VaultAuthenticator | null;
|
|
93
|
+
authenticatorState: "known" | "pending" | "unavailable";
|
|
93
94
|
capabilities: VaultItemCapabilities;
|
|
94
95
|
attachments: VaultAttachment[];
|
|
95
96
|
uriMatchMode: UriMatchMode;
|
|
@@ -323,7 +324,13 @@ type ItemRef = Pick<VaultItem, "id" | "owner">;
|
|
|
323
324
|
*/
|
|
324
325
|
interface AuthenticatorPort {
|
|
325
326
|
/** Every account the signed-in person holds a one-time password for. */
|
|
326
|
-
list(): Promise<
|
|
327
|
+
list(): Promise<{
|
|
328
|
+
entries: AuthenticatorEntry[];
|
|
329
|
+
unavailableScopes: {
|
|
330
|
+
type: "user" | "organization" | "shared";
|
|
331
|
+
organizationId?: string | null;
|
|
332
|
+
}[];
|
|
333
|
+
}>;
|
|
327
334
|
/** null when the item has none. */
|
|
328
335
|
get(item: ItemRef): Promise<AuthenticatorEntry | null>;
|
|
329
336
|
/** The current code and how long it lives. */
|
package/dist/index.d.ts
CHANGED
|
@@ -90,6 +90,7 @@ interface VaultItem {
|
|
|
90
90
|
fields: VaultField[];
|
|
91
91
|
custom: VaultCustomField[];
|
|
92
92
|
authenticator: VaultAuthenticator | null;
|
|
93
|
+
authenticatorState: "known" | "pending" | "unavailable";
|
|
93
94
|
capabilities: VaultItemCapabilities;
|
|
94
95
|
attachments: VaultAttachment[];
|
|
95
96
|
uriMatchMode: UriMatchMode;
|
|
@@ -323,7 +324,13 @@ type ItemRef = Pick<VaultItem, "id" | "owner">;
|
|
|
323
324
|
*/
|
|
324
325
|
interface AuthenticatorPort {
|
|
325
326
|
/** Every account the signed-in person holds a one-time password for. */
|
|
326
|
-
list(): Promise<
|
|
327
|
+
list(): Promise<{
|
|
328
|
+
entries: AuthenticatorEntry[];
|
|
329
|
+
unavailableScopes: {
|
|
330
|
+
type: "user" | "organization" | "shared";
|
|
331
|
+
organizationId?: string | null;
|
|
332
|
+
}[];
|
|
333
|
+
}>;
|
|
327
334
|
/** null when the item has none. */
|
|
328
335
|
get(item: ItemRef): Promise<AuthenticatorEntry | null>;
|
|
329
336
|
/** The current code and how long it lives. */
|
package/dist/index.js
CHANGED
|
@@ -2166,7 +2166,7 @@ function normalizeWebsite(raw) {
|
|
|
2166
2166
|
}
|
|
2167
2167
|
function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChanged, onAdded, onDone }) {
|
|
2168
2168
|
const confirmed = useConfirmed();
|
|
2169
|
-
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" }));
|
|
2169
|
+
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" }));
|
|
2170
2170
|
const [input, setInput] = useState11("");
|
|
2171
2171
|
const [image, setImage] = useState11(null);
|
|
2172
2172
|
const [target, setTarget] = useState11(itemId && candidates.some((c) => c.id === itemId) ? itemId : NEW);
|
|
@@ -2205,7 +2205,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
|
|
|
2205
2205
|
}
|
|
2206
2206
|
const it = item;
|
|
2207
2207
|
const entry = await confirmed(() => image ? port.authenticator.enrolQrImage(it, image, image.name) : port.authenticator.enrol(it, input));
|
|
2208
|
-
let next = { ...it, authenticator: { digits: entry.digits, period: entry.period, enabled: entry.enabled } };
|
|
2208
|
+
let next = { ...it, authenticatorState: "known", authenticator: { digits: entry.digits, period: entry.period, enabled: entry.enabled } };
|
|
2209
2209
|
const better = authenticatorName(it.name, { issuer: entry.issuer, account: entry.account });
|
|
2210
2210
|
if (!isNew && better !== it.name) {
|
|
2211
2211
|
try {
|
|
@@ -2343,6 +2343,7 @@ function AuthenticatorView({ port, host, items: listed, definitions, query, onOp
|
|
|
2343
2343
|
useEffect10(() => {
|
|
2344
2344
|
if (added.size > 0 && [...added.keys()].every((id) => listed.some((i) => i.id === id && i.authenticator))) setAdded(/* @__PURE__ */ new Map());
|
|
2345
2345
|
}, [listed, added]);
|
|
2346
|
+
const [incomplete, setIncomplete] = useState12(true);
|
|
2346
2347
|
const [entries, setEntries] = useState12(/* @__PURE__ */ new Map());
|
|
2347
2348
|
const [hidden, setHidden] = useState12(/* @__PURE__ */ new Set());
|
|
2348
2349
|
const [adding, setAdding] = useState12(false);
|
|
@@ -2352,8 +2353,15 @@ function AuthenticatorView({ port, host, items: listed, definitions, query, onOp
|
|
|
2352
2353
|
useEffect10(() => {
|
|
2353
2354
|
let live = true;
|
|
2354
2355
|
port.authenticator.list().then(
|
|
2355
|
-
(list) =>
|
|
2356
|
-
|
|
2356
|
+
(list) => {
|
|
2357
|
+
if (live) {
|
|
2358
|
+
setEntries(new Map(list.entries.map((e) => [e.itemId, e])));
|
|
2359
|
+
setIncomplete(list.unavailableScopes.length > 0);
|
|
2360
|
+
}
|
|
2361
|
+
},
|
|
2362
|
+
() => {
|
|
2363
|
+
if (live) setIncomplete(true);
|
|
2364
|
+
}
|
|
2357
2365
|
);
|
|
2358
2366
|
return () => {
|
|
2359
2367
|
live = false;
|
|
@@ -2371,7 +2379,14 @@ function AuthenticatorView({ port, host, items: listed, definitions, query, onOp
|
|
|
2371
2379
|
] }),
|
|
2372
2380
|
total > 0 ? /* @__PURE__ */ jsx11(Button9, { variant: "outline", icon: /* @__PURE__ */ jsx11(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add" }) : null
|
|
2373
2381
|
] }),
|
|
2374
|
-
total
|
|
2382
|
+
total > 0 && incomplete ? /* @__PURE__ */ jsxs10("div", { className: "px-4 text-sm text-muted-foreground", children: [
|
|
2383
|
+
"Some codes unavailable ",
|
|
2384
|
+
/* @__PURE__ */ jsx11(Button9, { variant: "quiet", onClick: onChanged, children: "Retry" })
|
|
2385
|
+
] }) : null,
|
|
2386
|
+
total === 0 && (incomplete || items.some((i) => i.authenticatorState !== "known")) ? /* @__PURE__ */ jsxs10("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: [
|
|
2387
|
+
"Codes unavailable ",
|
|
2388
|
+
/* @__PURE__ */ jsx11(Button9, { variant: "quiet", onClick: onChanged, children: "Retry" })
|
|
2389
|
+
] }) : total === 0 ? /* @__PURE__ */ jsxs10("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 px-6 pb-12 text-center", children: [
|
|
2375
2390
|
/* @__PURE__ */ jsx11("span", { className: "flex size-12 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ jsx11(ShieldGlyph, { className: "size-6" }) }),
|
|
2376
2391
|
/* @__PURE__ */ jsx11("p", { className: "text-sm font-medium text-foreground", children: "No authenticator codes yet" }),
|
|
2377
2392
|
/* @__PURE__ */ jsx11(Button9, { variant: "primary", icon: /* @__PURE__ */ jsx11(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add authenticator" })
|
|
@@ -6421,7 +6436,10 @@ function ItemPane(props) {
|
|
|
6421
6436
|
i
|
|
6422
6437
|
)),
|
|
6423
6438
|
/* @__PURE__ */ jsx25(AddRow, { label: draft.loginUrls.length === 0 ? "Website" : "", onAdd: () => patch({ loginUrls: [...draft.loginUrls, ""] }), children: draft.loginUrls.length === 0 ? "Add website" : "Add another website" }),
|
|
6424
|
-
/* @__PURE__ */ jsx25(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
|
|
6439
|
+
!item || item.authenticatorState === "known" ? /* @__PURE__ */ jsx25(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }) : /* @__PURE__ */ jsxs23(VaultRow, { label: "Authenticator", children: [
|
|
6440
|
+
/* @__PURE__ */ jsx25("span", { className: "text-muted-foreground", children: item.authenticatorState === "pending" ? "Loading" : "Unavailable" }),
|
|
6441
|
+
item.authenticatorState === "unavailable" ? /* @__PURE__ */ jsx25(Button22, { variant: "quiet", onClick: () => onChanged?.(), children: "Retry" }) : null
|
|
6442
|
+
] }),
|
|
6425
6443
|
item && isLogin && !item.authenticator ? /* @__PURE__ */ jsx25(TwoFactorMethodRow, { port, item, onChanged }) : null,
|
|
6426
6444
|
!item && isLogin && draft.authenticator.trim() === "" ? /* @__PURE__ */ jsx25(DraftTwoFactorRow, { custom: draft.custom, onCustom: (custom) => patch({ custom }) }) : null,
|
|
6427
6445
|
recoveryEditing ? /* @__PURE__ */ jsx25(
|
|
@@ -6500,7 +6518,10 @@ function ItemPane(props) {
|
|
|
6500
6518
|
}),
|
|
6501
6519
|
extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ jsx25(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ jsx25(SecretRow, { port, item, field: f, onTurnOn: turnOnOne(f), extra: fieldSettings(f) }, f.id)),
|
|
6502
6520
|
item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */ jsx25(PlainRow, { label: i === 0 ? "Website" : `Website ${i + 1}`, value: u, openUrl: host.openUrl }, `${u}-${i}`)) : /* @__PURE__ */ jsx25(AddRow, { label: "Website", onAdd: canEdit ? () => onMode("edit") : null, children: "Add website" }),
|
|
6503
|
-
item.authenticator ? /* @__PURE__ */ jsx25(TotpRow, { port, item, onChanged }) :
|
|
6521
|
+
item.authenticator ? /* @__PURE__ */ jsx25(TotpRow, { port, item, onChanged }) : item.authenticatorState !== "known" ? /* @__PURE__ */ jsxs23(VaultRow, { label: "Authenticator", children: [
|
|
6522
|
+
/* @__PURE__ */ jsx25("span", { className: "text-muted-foreground", children: item.authenticatorState === "pending" ? "Loading" : "Unavailable" }),
|
|
6523
|
+
item.authenticatorState === "unavailable" ? /* @__PURE__ */ jsx25(Button22, { variant: "quiet", onClick: () => onChanged?.(), children: "Retry" }) : null
|
|
6524
|
+
] }) : seedField && !seedField.active ? (
|
|
6504
6525
|
// The secret is still there, only off: turning it on brings the codes back. Never "Set up",
|
|
6505
6526
|
// which would invite replacing a working two-factor secret.
|
|
6506
6527
|
/* @__PURE__ */ jsx25(VaultRow, { label: "Authenticator", actions: canTurnOn ? /* @__PURE__ */ jsx25(TurnOnButton, { label: "Authenticator", onTurnOn: () => turnOn([seedField]) }) : null, children: /* @__PURE__ */ jsx25("span", { className: "text-muted-foreground", children: "Turned off" }) })
|
|
@@ -9329,7 +9350,7 @@ function createAuthenticatorPort(ctx) {
|
|
|
9329
9350
|
return {
|
|
9330
9351
|
async list() {
|
|
9331
9352
|
const r = await apps.listAuthenticators(api);
|
|
9332
|
-
return (r.entries ?? []).map(entryOf);
|
|
9353
|
+
return { entries: (r.entries ?? []).map(entryOf), unavailableScopes: (r.unavailable_scopes ?? []).map((s) => ({ type: s.type, organizationId: s.organization_id ?? null })) };
|
|
9333
9354
|
},
|
|
9334
9355
|
async get(item) {
|
|
9335
9356
|
try {
|
|
@@ -9543,6 +9564,7 @@ function trashItem(r, ctx) {
|
|
|
9543
9564
|
fields: [],
|
|
9544
9565
|
custom: [],
|
|
9545
9566
|
authenticator: null,
|
|
9567
|
+
authenticatorState: "known",
|
|
9546
9568
|
capabilities: { canUse: false, canEdit: false, canReveal: false, canManage: true },
|
|
9547
9569
|
attachments: [],
|
|
9548
9570
|
uriMatchMode: "host",
|
|
@@ -9899,7 +9921,8 @@ function fieldOf(w, def) {
|
|
|
9899
9921
|
active: w.is_active ?? true
|
|
9900
9922
|
};
|
|
9901
9923
|
}
|
|
9902
|
-
|
|
9924
|
+
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));
|
|
9925
|
+
function itemOf(w, owner, defs, auth, state = "known", unavailable = [], inventoryOwner = owner) {
|
|
9903
9926
|
const def = defs.get(w.definition_key ?? "");
|
|
9904
9927
|
const a = auth.get(w.id);
|
|
9905
9928
|
const cap = w.capabilities ?? {};
|
|
@@ -9917,6 +9940,7 @@ function itemOf(w, owner, defs, auth) {
|
|
|
9917
9940
|
fields: (w.fields ?? []).filter((f) => f.execution_purpose !== "passkey_private").map((f) => fieldOf(f, def)),
|
|
9918
9941
|
custom: (w.non_secret_fields ?? []).map((c) => ({ key: c["key"] ?? "", label: c["label"] ?? humanize(c["key"] ?? ""), value: c["value"] ?? "" })),
|
|
9919
9942
|
authenticator: a ? { digits: a.digits, period: a.period, enabled: a.enabled } : null,
|
|
9943
|
+
authenticatorState: a ? "known" : state === "pending" ? "pending" : state === "unavailable" || scopeUnavailable(inventoryOwner, unavailable) ? "unavailable" : "known",
|
|
9920
9944
|
capabilities: { canUse: cap.can_use ?? false, canEdit: cap.can_edit ?? false, canReveal: cap.can_reveal ?? false, canManage: cap.can_manage ?? false },
|
|
9921
9945
|
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 })),
|
|
9922
9946
|
uriMatchMode: MATCH_MODES2.find((m) => m === w.uri_match_mode) ?? "host",
|
|
@@ -9953,6 +9977,9 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
9953
9977
|
};
|
|
9954
9978
|
let defs = /* @__PURE__ */ new Map();
|
|
9955
9979
|
let auth = /* @__PURE__ */ new Map();
|
|
9980
|
+
let authState = "pending";
|
|
9981
|
+
let authUnavailable = [];
|
|
9982
|
+
let inventoryOwners = /* @__PURE__ */ new Map();
|
|
9956
9983
|
let orgs = [];
|
|
9957
9984
|
const orgOf = (id, userId, mine) => {
|
|
9958
9985
|
if (id) return { kind: "organization", label: orgs.find((o) => o.id === id)?.name ?? "Organization", organizationId: id };
|
|
@@ -9966,7 +9993,7 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
9966
9993
|
};
|
|
9967
9994
|
async function refetch(id, owner) {
|
|
9968
9995
|
const w = await account9.getItem(api, { path: { item_id: id } });
|
|
9969
|
-
return itemOf(w, owner, defs, auth);
|
|
9996
|
+
return itemOf(w, owner, defs, auth, authState, authUnavailable, inventoryOwners.get(id) ?? owner);
|
|
9970
9997
|
}
|
|
9971
9998
|
const visibleCache = /* @__PURE__ */ new Map();
|
|
9972
9999
|
const ctx = {
|
|
@@ -9993,6 +10020,10 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
9993
10020
|
fields: createFieldsPort(ctx),
|
|
9994
10021
|
lists: createListsPort(ctx, options.userState),
|
|
9995
10022
|
async load(onProgress) {
|
|
10023
|
+
authState = "pending";
|
|
10024
|
+
auth = /* @__PURE__ */ new Map();
|
|
10025
|
+
authUnavailable = [];
|
|
10026
|
+
inventoryOwners = /* @__PURE__ */ new Map();
|
|
9996
10027
|
const catalogP = retrying(() => apps2.getAppCatalogKind(api, { path: { app: "matrx", kind: "credential_definition" } }));
|
|
9997
10028
|
const authP = retrying(() => apps2.listAuthenticators(api));
|
|
9998
10029
|
const userP = retrying(() => account9.listItems(api, { query: { principal_type: "user" } }));
|
|
@@ -10015,9 +10046,10 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10015
10046
|
const meId = raw.meId ?? mineItems.find((w) => w.user_id)?.user_id ?? null;
|
|
10016
10047
|
const seen = /* @__PURE__ */ new Map();
|
|
10017
10048
|
const deleted = /* @__PURE__ */ new Map();
|
|
10018
|
-
const take = (w, owner) => {
|
|
10049
|
+
const take = (w, owner, inventoryOwner = owner) => {
|
|
10019
10050
|
if (seen.has(w.id) || deleted.has(w.id) || isHiddenItem(w)) return;
|
|
10020
|
-
|
|
10051
|
+
inventoryOwners.set(w.id, inventoryOwner);
|
|
10052
|
+
const item = itemOf(w, owner, defs, auth, authState, authUnavailable, inventoryOwner);
|
|
10021
10053
|
(isDeleted(w) ? deleted : seen).set(w.id, item);
|
|
10022
10054
|
};
|
|
10023
10055
|
for (const w of mineItems) take(w, orgOf(w.organization_id, null, true));
|
|
@@ -10025,7 +10057,7 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10025
10057
|
const via = orgs[i];
|
|
10026
10058
|
for (const w of l?.items ?? []) take(w, ownerInOrgList(w, via, meId));
|
|
10027
10059
|
});
|
|
10028
|
-
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 });
|
|
10060
|
+
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 });
|
|
10029
10061
|
const pending = done ? [] : [...raw.orgsKnown ? orgs.filter((_, i) => raw.orgLists[i] === void 0).map((o) => o.name) : ["your organizations"], ...raw.shared ? [] : ["Shared with me"]];
|
|
10030
10062
|
return {
|
|
10031
10063
|
unavailable: [...unavailable],
|
|
@@ -10084,9 +10116,14 @@ function createApiVaultPort(hostApi, options = {}) {
|
|
|
10084
10116
|
})();
|
|
10085
10117
|
quiet(orgListsReady);
|
|
10086
10118
|
const authDone = authP.then((a) => {
|
|
10087
|
-
|
|
10119
|
+
authUnavailable = a.unavailable_scopes ?? [];
|
|
10120
|
+
const fresh = new Map((a.entries ?? []).map((e) => [e.credential_item_id, e]));
|
|
10121
|
+
auth = fresh;
|
|
10122
|
+
authState = "known";
|
|
10123
|
+
if (authUnavailable.length) unavailable.push("One-time codes");
|
|
10088
10124
|
progress();
|
|
10089
10125
|
}, () => {
|
|
10126
|
+
authState = "unavailable";
|
|
10090
10127
|
unavailable.push("One-time codes");
|
|
10091
10128
|
});
|
|
10092
10129
|
const sharedDone = sharedP.then((sh) => {
|