@ai-matrx/vault 0.1.12 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -6
- package/dist/index.cjs +21 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +21 -10
- package/dist/index.js.map +1 -1
- package/dist/io/csv-import.worker.js.map +1 -1
- package/dist/io/onepux.worker.js +3 -3
- package/dist/io/onepux.worker.js.map +1 -1
- package/dist/io/proton-pass.worker.js +2 -2
- package/dist/io/proton-pass.worker.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 0.1.14
|
|
4
|
+
|
|
5
|
+
UNVERIFIED: this release has no Unreleased entry and the source comparison could not be made (the caller supplied no source comparison). Whether source changed is unknown; consumer action is unknown.
|
|
6
|
+
Check the package's gitHead on npm against this version's gitHead: `git diff <previous gitHead> <this gitHead> -- apps/shared/vault/src`.
|
|
7
|
+
|
|
8
|
+
## 0.1.13
|
|
9
|
+
|
|
10
|
+
- **Turn on also turns the item on.** A restore leaves the whole item disabled (`status: "disabled"`), not only its fields, so a turned-on field still answered "not found". `VaultItem.turnedOff` reads it; every **Turn on** turns the item on first (`fields.updateItem(item, { active: true })` → `status: "active"`), and turning the one-time password on also re-enables its codes. An off item says "This item is turned off" and its rows read Turned off. Guard: `src/restored-item.test.tsx`, `src/fields/fields.test.ts`. Consumer action: none.
|
|
11
|
+
- **A dead session no longer throws a burst of unhandled rejections**: `load()` answers every part it started, so only the one "You've been signed out" shows. Guard: `src/load-dead-session.test.ts`. Consumer action: none.
|
|
12
|
+
|
|
13
|
+
## 0.1.12
|
|
4
14
|
|
|
5
15
|
- **Restored items are repairable in place.** An item back from Trash says "N fields are turned off" with **Turn on** (all), and each off row has its own **Turn on**; the one-time password reads "Turned off" + Turn on instead of "Set up" (which invited replacing a 2FA secret it still has), and editing it says "Paste a new key to replace". Plain words in settings: "One-time password key" (was "Totp seed"), "Always shown / Hidden / Never shown" (was "Anyone / On request / Sealed"), "Turned on" (was "Active"). Guard: `src/restored-item.test.tsx`. Consumer action: none.
|
|
6
16
|
- **Continue with Google checks who came back.** `createSupabaseIdentity` remembers the person across the provider redirect (`sessionStorage`, `CONFIRM_RETURN_KEY`) and `VaultIdentity.checkReturn()` (run by `IdentityGate` on load) refuses a different account: it is signed out of THIS device through the new `onDifferentPerson(message)` option (default `auth.signOut({ scope: "local" })`) and a "Different account" dialog says so. Guard: `src/auth/identity.test.ts`, `src/auth/identity-gate.test.tsx`. **Consumer action:** web app: pass `onDifferentPerson` running the app's device-scoped sign-out. Extension and desktop: none (they check in place).
|
|
@@ -14,11 +24,6 @@
|
|
|
14
24
|
- **Confirm in place.** `VaultIdentity.withProvider` may resolve `"confirmed"` when the host confirms without leaving the page (the desktop's Touch ID); "Confirm it's you" then closes and runs the refused call again — one confirmation, the value appears. Before, the dialog stayed open and the person had to cancel and press reveal again. Labels for `touch_id` ("Touch ID") and `browser`. Guard: `src/auth/identity-gate.test.tsx` (fails on the old gate). **Consumer action:** Matrx Desktop: return `"confirmed"` from `withProvider` once the confirmation succeeded in place. Web app and extension: none.
|
|
15
25
|
- **`VaultApp look="web"|"desktop"`.** The same screens and features, two skins: `"web"` (default) is the website's and the extension's look, unchanged; `"desktop"` draws the workspace in the desktop standard through `@ai-matrx/design-system`'s `LookScope` — the system font and Apple text styles, AppKit-size controls, System Settings/Passwords grouped boxes (no border, hairlines between rows, bold section titles), the source list's open row in the accent, and every panel as a modal macOS sheet, light and dark. The playground's Desktop host uses it. Guard: `src/look.test.tsx`. **Consumer action:** Matrx Desktop: pass `look="desktop"` to `<VaultApp>` (Account › Vault). Web app and extension: none.
|
|
16
26
|
|
|
17
|
-
## 0.1.12
|
|
18
|
-
|
|
19
|
-
UNVERIFIED: this release has no Unreleased entry and the source comparison could not be made (the caller supplied no source comparison). Whether source changed is unknown; consumer action is unknown.
|
|
20
|
-
Check the package's gitHead on npm against this version's gitHead: `git diff <previous gitHead> <this gitHead> -- apps/shared/vault/src`.
|
|
21
|
-
|
|
22
27
|
## 0.1.11
|
|
23
28
|
|
|
24
29
|
SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
|
package/dist/index.cjs
CHANGED
|
@@ -749,7 +749,7 @@ function SecretRow({ port, item, field, extra, onTurnOn }) {
|
|
|
749
749
|
const [error, setError] = (0, import_react5.useState)(null);
|
|
750
750
|
const sealed = field.handling === "sealed";
|
|
751
751
|
const visible = field.handling === "visible";
|
|
752
|
-
const off = field.active === false;
|
|
752
|
+
const off = field.active === false || item.turnedOff === true;
|
|
753
753
|
const canSee = !sealed && !off && (visible ? item.capabilities.canUse : item.capabilities.canReveal);
|
|
754
754
|
(0, import_react5.useEffect)(() => {
|
|
755
755
|
if (!visible || !canSee) return;
|
|
@@ -4150,7 +4150,7 @@ var import_zip2 = require("@zip.js/zip.js");
|
|
|
4150
4150
|
var safe = (value) => Number.isSafeInteger(value) && value >= 0;
|
|
4151
4151
|
var unsafeName = (name) => /[\\\0-\x1F\x7F-\x9F]/.test(name);
|
|
4152
4152
|
function stopIfCancelled(signal) {
|
|
4153
|
-
if (signal?.aborted) throw new Error("The archive import was
|
|
4153
|
+
if (signal?.aborted) throw new Error("The archive import was canceled.");
|
|
4154
4154
|
}
|
|
4155
4155
|
function hasWarnings(reader, entry) {
|
|
4156
4156
|
return Boolean(reader.warnings?.length || entry.warnings?.length);
|
|
@@ -4251,7 +4251,7 @@ async function openBoundedZip(file, limits, signal) {
|
|
|
4251
4251
|
};
|
|
4252
4252
|
} catch (error) {
|
|
4253
4253
|
await reader.close();
|
|
4254
|
-
if (signal?.aborted) throw new Error("The archive import was
|
|
4254
|
+
if (signal?.aborted) throw new Error("The archive import was canceled.");
|
|
4255
4255
|
throw error;
|
|
4256
4256
|
}
|
|
4257
4257
|
}
|
|
@@ -4290,7 +4290,7 @@ async function readDashlaneCsvArchive(file, limits, signal) {
|
|
|
4290
4290
|
return { credentialsText, omittedCsvCount };
|
|
4291
4291
|
} catch (error) {
|
|
4292
4292
|
credentialsText = void 0;
|
|
4293
|
-
if (signal?.aborted) throw new Error("The Dashlane import was
|
|
4293
|
+
if (signal?.aborted) throw new Error("The Dashlane import was canceled.");
|
|
4294
4294
|
throw error;
|
|
4295
4295
|
} finally {
|
|
4296
4296
|
credentialsText = void 0;
|
|
@@ -4425,7 +4425,7 @@ function hasValidStructuredImportFileNotices(value, maxCount) {
|
|
|
4425
4425
|
}
|
|
4426
4426
|
|
|
4427
4427
|
// src/io/parse-source.ts
|
|
4428
|
-
var cancelled = () => new Error("The import was
|
|
4428
|
+
var cancelled = () => new Error("The import was canceled.");
|
|
4429
4429
|
function parseStructured(source, file, limits, signal) {
|
|
4430
4430
|
const descriptor = structuredImportSource(source);
|
|
4431
4431
|
if (!descriptor) return Promise.reject(new Error("This kind of file cannot be imported."));
|
|
@@ -5832,13 +5832,19 @@ function ItemPane(props) {
|
|
|
5832
5832
|
}
|
|
5833
5833
|
}
|
|
5834
5834
|
const offFields = item ? item.fields.filter((f) => !f.active) : [];
|
|
5835
|
+
const itemOff = item?.turnedOff === true;
|
|
5835
5836
|
const seedField = item?.fields.find((f) => f.key === OTP_SEED_KEY) ?? null;
|
|
5836
5837
|
const canTurnOn = Boolean(item && canEdit);
|
|
5837
5838
|
async function turnOn(fields) {
|
|
5838
|
-
if (!item
|
|
5839
|
+
if (!item) return;
|
|
5839
5840
|
setError(null);
|
|
5840
5841
|
try {
|
|
5842
|
+
if (item.turnedOff) await confirmed(() => port.fields.updateItem(item, { active: true }));
|
|
5841
5843
|
for (const f of fields) await confirmed(() => port.fields.updateField(item, f.id, { active: true }));
|
|
5844
|
+
if (fields.some((f) => f.key === OTP_SEED_KEY)) {
|
|
5845
|
+
const codes = await port.authenticator.get(item);
|
|
5846
|
+
if (codes && !codes.enabled) await confirmed(() => port.authenticator.setEnabled(item, true));
|
|
5847
|
+
}
|
|
5842
5848
|
onChanged();
|
|
5843
5849
|
} catch (e) {
|
|
5844
5850
|
if (!wasCancelled(e)) setError(e instanceof Error ? e.message : "It could not be turned on.");
|
|
@@ -5941,8 +5947,8 @@ function ItemPane(props) {
|
|
|
5941
5947
|
header,
|
|
5942
5948
|
error ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { role: "alert", className: "border-b border-border bg-muted px-5 py-2 text-sm text-destructive", children: error }) : null,
|
|
5943
5949
|
notice && !editing ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { role: "status", className: "border-b border-border bg-muted px-5 py-2 text-sm text-warning", children: notice }) : null,
|
|
5944
|
-
item && !editing && offFields.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-5 py-2 text-sm", children: [
|
|
5945
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "min-w-0 flex-1 truncate text-warning", children: offFields.length === 1 ? "1 field is turned off" : `${offFields.length} fields are turned off` }),
|
|
5950
|
+
item && !editing && (itemOff || offFields.length > 0) ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-5 py-2 text-sm", children: [
|
|
5951
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "min-w-0 flex-1 truncate text-warning", children: offFields.length === 0 ? "This item is turned off" : offFields.length === 1 ? "1 field is turned off" : `${offFields.length} fields are turned off` }),
|
|
5946
5952
|
canTurnOn ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TurnOnButton, { label: "all fields", onTurnOn: () => turnOn(offFields) }) : null
|
|
5947
5953
|
] }) : null,
|
|
5948
5954
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5 px-3 py-4 sm:px-6 sm:py-6", children: editing ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
|
|
@@ -7045,7 +7051,7 @@ var plural2 = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
|
|
|
7045
7051
|
function terminalMessage(s) {
|
|
7046
7052
|
if (s.phase === "completed") return `Imported ${plural2(s.committed, "passkey")}.`;
|
|
7047
7053
|
if (s.phase === "partial") return `${s.committed} imported; ${s.unsupported + s.failed + s.uncertain + s.not_attempted} need attention.`;
|
|
7048
|
-
if (s.phase === "cancelled") return "Import
|
|
7054
|
+
if (s.phase === "cancelled") return "Import canceled. Nothing else will be imported.";
|
|
7049
7055
|
if (s.phase === "unavailable") return "Passkey import is unavailable here.";
|
|
7050
7056
|
if (s.phase === "failed") return "The import did not finish. Recover it before using a new file.";
|
|
7051
7057
|
return s.message;
|
|
@@ -7230,7 +7236,7 @@ function useNativeImport(bridge, stillAllowed, onImported) {
|
|
|
7230
7236
|
present(g, { kind: "status", status: result, message: terminalMessage(result) });
|
|
7231
7237
|
if (!done && ACTIVE_PHASES.has(result.phase)) schedulePoll(active.id);
|
|
7232
7238
|
} catch (e) {
|
|
7233
|
-
keepOperation(g, fail(e, "The import could not be
|
|
7239
|
+
keepOperation(g, fail(e, "The import could not be canceled."));
|
|
7234
7240
|
} finally {
|
|
7235
7241
|
if (current(g)) setBusy(false);
|
|
7236
7242
|
}
|
|
@@ -8522,6 +8528,7 @@ function createFieldsPort(ctx) {
|
|
|
8522
8528
|
if (patch.uriMatchMode !== void 0) body.uri_match_mode = patch.uriMatchMode;
|
|
8523
8529
|
if (patch.browserFillEnabled !== void 0) body.browser_fill_enabled = patch.browserFillEnabled;
|
|
8524
8530
|
if (patch.loginUrls !== void 0) body.login_urls = patch.loginUrls;
|
|
8531
|
+
if (patch.active !== void 0) body.status = patch.active ? "active" : "disabled";
|
|
8525
8532
|
await account3.updateItem(api, { path: { item_id: item.id }, body }, ctx.optsFor(item));
|
|
8526
8533
|
return reread(item);
|
|
8527
8534
|
},
|
|
@@ -8934,6 +8941,7 @@ function itemOf(w, owner, defs, auth) {
|
|
|
8934
8941
|
uriMatchMode: MATCH_MODES2.find((m) => m === w.uri_match_mode) ?? "host",
|
|
8935
8942
|
browserFillEnabled: w.browser_fill_enabled ?? true,
|
|
8936
8943
|
accessMode: w.access_mode ?? null,
|
|
8944
|
+
turnedOff: w.status === "disabled",
|
|
8937
8945
|
ownerUserId: w.user_id ?? null,
|
|
8938
8946
|
deletion: recovery?.state === "deleted" ? { deletionId: typeof recovery.deletion_id === "string" ? recovery.deletion_id : null, deletedAt: typeof recovery.deleted_at === "string" ? recovery.deleted_at : null } : null,
|
|
8939
8947
|
updatedAt: w.updated_at,
|
|
@@ -8993,9 +9001,12 @@ function createApiVaultPort(api, options = {}) {
|
|
|
8993
9001
|
const authP = retrying(() => apps2.listAuthenticators(api));
|
|
8994
9002
|
const userP = retrying(() => account9.listItems(api, { query: { principal_type: "user" } }));
|
|
8995
9003
|
const sharedP = retrying(() => account9.sharedWithMe(api));
|
|
9004
|
+
const quiet = (p) => void p.catch(() => void 0);
|
|
9005
|
+
[catalogP, authP, userP, sharedP].forEach(quiet);
|
|
8996
9006
|
const org = options.organizations ? null : await retrying(() => platform.listMyOrganizations(api));
|
|
8997
9007
|
orgs = [...new Map((options.organizations ?? (org?.organizations ?? []).filter((o) => !o.archived_at).map((o) => ({ id: o.id, name: o.name }))).map((o) => [o.id, o])).values()];
|
|
8998
9008
|
const orgListsP = orgs.map((o) => retrying(() => account9.listItems(api, { query: { principal_type: "organization", organization_id: o.id } }, { organizationId: o.id })));
|
|
9009
|
+
orgListsP.forEach(quiet);
|
|
8999
9010
|
const [catalog, mine] = await Promise.all([catalogP, userP]);
|
|
9000
9011
|
const [authSettled, sharedSettled, ...orgSettled] = await Promise.allSettled([authP, sharedP, ...orgListsP]);
|
|
9001
9012
|
const unavailable = [];
|