@ai-matrx/vault 0.1.19 → 0.1.20

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/dist/index.js CHANGED
@@ -671,7 +671,7 @@ var DAY_FORMAT = { year: "numeric", month: "short", day: "numeric" };
671
671
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
672
672
  var MASK = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
673
673
  function SecretText({ value, multiline }) {
674
- if (multiline || value.length > 200) return /* @__PURE__ */ jsx5("span", { className: "whitespace-pre-wrap break-all font-mono text-sm", children: value });
674
+ if (multiline || value.length > 200 || value.includes("\n")) return /* @__PURE__ */ jsx5("span", { className: "whitespace-pre-wrap break-all font-mono text-sm", children: value });
675
675
  return /* @__PURE__ */ jsx5("span", { className: "break-all font-mono text-sm tracking-wide", children: [...value].map((ch, i) => /* @__PURE__ */ jsx5("span", { className: /[0-9]/.test(ch) ? "text-primary" : /[^A-Za-z0-9]/.test(ch) ? "text-warning" : void 0, children: ch }, i)) });
676
676
  }
677
677
  var quietError = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
@@ -807,18 +807,19 @@ function EditRow({ label, hint: hint2, value, onChange, placeholder, secret = fa
807
807
  }
808
808
  );
809
809
  }
810
- function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove, extra, onPasteValue }) {
810
+ function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove, extra, onPasteValue, multiline = false }) {
811
811
  const [shown, setShown] = useState5(false);
812
812
  return /* @__PURE__ */ jsx5(
813
813
  VaultRow,
814
814
  {
815
815
  label: /* @__PURE__ */ jsx5(Field2, { className: "w-full", value: label, onChange: (e) => onLabel(e.target.value), placeholder: "Name", "aria-label": "Field name" }),
816
+ top: multiline,
816
817
  actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
817
- secret && value ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: shown ? /* @__PURE__ */ jsx5(EyeOffGlyph, {}) : /* @__PURE__ */ jsx5(EyeGlyph, {}), "aria-label": shown ? "Hide" : "Show", onClick: () => setShown((x) => !x) }) : null,
818
+ secret && value && !multiline ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: shown ? /* @__PURE__ */ jsx5(EyeOffGlyph, {}) : /* @__PURE__ */ jsx5(EyeGlyph, {}), "aria-label": shown ? "Hide" : "Show", onClick: () => setShown((x) => !x) }) : null,
818
819
  extra,
819
820
  /* @__PURE__ */ jsx5(Button2, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx5(XGlyph, {}), "aria-label": "Remove field", onClick: onRemove })
820
821
  ] }),
821
- children: /* @__PURE__ */ jsx5(
822
+ children: multiline ? /* @__PURE__ */ jsx5(Textarea, { className: "w-full", value, onChange: (e) => onValue(e.target.value), rows: 4, placeholder: secret ? "Encrypted, hidden until shown" : "Value", autoComplete: "off", spellCheck: !secret, "aria-label": label ? `${label} value` : "Field value" }) : /* @__PURE__ */ jsx5(
822
823
  Field2,
823
824
  {
824
825
  className: "w-full",
@@ -937,6 +938,7 @@ function sortItems(items, sort, recents) {
937
938
  if (sort === "updated") return out.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
938
939
  return out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
939
940
  }
941
+ var SECURE_NOTE_KEY = "secure_notes";
940
942
  function draftOf(item) {
941
943
  return {
942
944
  name: item?.name ?? "",
@@ -987,7 +989,9 @@ function rebaseDraft(oldBase, newBase, draft) {
987
989
  secrets: draft.secrets,
988
990
  custom,
989
991
  removed: draft.removed,
990
- authenticator: draft.authenticator
992
+ authenticator: draft.authenticator,
993
+ ...draft.browser ? { browser: draft.browser } : {},
994
+ ...draft.fieldSettings ? { fieldSettings: draft.fieldSettings } : {}
991
995
  };
992
996
  }
993
997
  function panesShown(mode, specialView, showingDetail) {
@@ -1015,7 +1019,8 @@ var FAMILY_LABELS = {
1015
1019
  signing_files: "Signing & files"
1016
1020
  };
1017
1021
  var COMMON_DEFINITION_KEYS = ["website_login", "username_password", "api_key", "env_value", "database_login", "custom"];
1018
- var MULTILINE = /(json|pem|private_key|certificate|cert|bundle|document|recovery_codes)/;
1022
+ var MULTILINE = /(json|pem|private_key|certificate|cert|bundle|document|recovery_codes|(^|_)notes?($|_))/;
1023
+ var isMultilineKey = (key) => MULTILINE.test(key);
1019
1024
  var SECRET = /(password|secret|token|api_key|private|passphrase|credential|seed|key$|_key)/;
1020
1025
  var URLISH = /(url|uri|endpoint|webhook|hook)/;
1021
1026
  function humanize(key) {
@@ -2229,7 +2234,7 @@ function normalizeWebsite(raw) {
2229
2234
  return null;
2230
2235
  }
2231
2236
  }
2232
- function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChanged, onDone }) {
2237
+ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChanged, onAdded, onDone }) {
2233
2238
  const confirmed = useConfirmed();
2234
2239
  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" }));
2235
2240
  const [input, setInput] = useState12("");
@@ -2282,6 +2287,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
2282
2287
  setInput("");
2283
2288
  setImage(null);
2284
2289
  setSaved(next);
2290
+ onAdded?.(next);
2285
2291
  onChanged();
2286
2292
  } catch (e) {
2287
2293
  setError(wasCancelled(e) ? "Not confirmed, so nothing was added." : otpActionError(e, "add it"));
@@ -2390,7 +2396,23 @@ function otpGroups(items, entries, query, hidden = /* @__PURE__ */ new Set()) {
2390
2396
  const rank = (k) => k === "me" ? 0 : k === "shared" ? 2 : 1;
2391
2397
  return [...groups.entries()].sort(([a, x], [b, y]) => rank(a) - rank(b) || x.label.localeCompare(y.label)).map(([key, g]) => ({ key, ...g }));
2392
2398
  }
2393
- function AuthenticatorView({ port, host, items, definitions, query, onOpen, onChanged, header }) {
2399
+ function withAdded(items, added) {
2400
+ if (added.size === 0) return items;
2401
+ const seen = /* @__PURE__ */ new Set();
2402
+ const out = items.map((i) => {
2403
+ seen.add(i.id);
2404
+ const mine = added.get(i.id);
2405
+ return mine && !i.authenticator ? { ...i, authenticator: mine.authenticator, name: mine.name } : i;
2406
+ });
2407
+ for (const [id, a] of added) if (!seen.has(id)) out.push(a);
2408
+ return out;
2409
+ }
2410
+ function AuthenticatorView({ port, host, items: listed, definitions, query, onOpen, onChanged, header }) {
2411
+ const [added, setAdded] = useState13(/* @__PURE__ */ new Map());
2412
+ const items = withAdded(listed, added);
2413
+ useEffect11(() => {
2414
+ if (added.size > 0 && [...added.keys()].every((id) => listed.some((i) => i.id === id && i.authenticator))) setAdded(/* @__PURE__ */ new Map());
2415
+ }, [listed, added]);
2394
2416
  const [entries, setEntries] = useState13(/* @__PURE__ */ new Map());
2395
2417
  const [hidden, setHidden] = useState13(/* @__PURE__ */ new Set());
2396
2418
  const [adding, setAdding] = useState13(false);
@@ -2406,7 +2428,7 @@ function AuthenticatorView({ port, host, items, definitions, query, onOpen, onCh
2406
2428
  return () => {
2407
2429
  live = false;
2408
2430
  };
2409
- }, [port, items]);
2431
+ }, [port, listed, added]);
2410
2432
  const groups = otpGroups(items, entries, query, hidden);
2411
2433
  const total = items.filter((i) => i.authenticator && !i.deletion && !hidden.has(i.id)).length;
2412
2434
  const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
@@ -2452,6 +2474,7 @@ function AuthenticatorView({ port, host, items, definitions, query, onOpen, onCh
2452
2474
  definitions,
2453
2475
  onClose: () => setAdding(false),
2454
2476
  onChanged,
2477
+ onAdded: (item) => setAdded((cur) => new Map(cur).set(item.id, item)),
2455
2478
  onDone: (id) => {
2456
2479
  setAdding(false);
2457
2480
  onOpen(id);
@@ -4797,7 +4820,7 @@ import { Button as Button23, SearchField } from "@ai-matrx/design-system/control
4797
4820
  import { CopyIcon as CopyIcon7 } from "@ai-matrx/design-system/icons";
4798
4821
 
4799
4822
  // src/ItemPane.tsx
4800
- import { useEffect as useEffect16, useMemo as useMemo3, useRef as useRef14, useState as useState27 } from "react";
4823
+ import { Fragment as Fragment17, useEffect as useEffect16, useMemo as useMemo3, useRef as useRef14, useState as useState27 } from "react";
4801
4824
  import { DropdownMenu as DropdownMenu3, DropdownMenuContent as DropdownMenuContent3, DropdownMenuItem as DropdownMenuItem3, DropdownMenuSeparator as DropdownMenuSeparator3, DropdownMenuTrigger as DropdownMenuTrigger3 } from "@ai-matrx/design-system";
4802
4825
  import { cn as cn12 } from "@ai-matrx/design-system";
4803
4826
  import { Badge as Badge7, Button as Button22, CONTROLS_CONTAINER_CLASS, OptionCombobox, Switch as Switch6 } from "@ai-matrx/design-system/controls";
@@ -5179,14 +5202,12 @@ import { confirm as confirm7 } from "@ai-matrx/kit/confirm-opener";
5179
5202
  import { Fragment as Fragment15, jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
5180
5203
  var HANDLINGS = ["visible", "revealable", "sealed"];
5181
5204
  var hint = (text, tone = "muted") => /* @__PURE__ */ jsx22("span", { className: tone === "destructive" ? "text-destructive" : void 0, title: text, children: text });
5182
- var hasSecretSettings = (s) => Boolean(s.envKey?.trim() || s.injectIntoSandbox || s.handling && s.handling !== "revealable");
5183
- function SecretBuilderRow({ field, onChange, onRemove }) {
5184
- const [open, setOpen] = useState22(hasSecretSettings(field));
5185
- const env = field.envKey ?? "";
5205
+ var saysMore = (s, defaultHandling) => Boolean(s.envKey?.trim() || s.injectIntoSandbox || s.handling && s.handling !== defaultHandling);
5206
+ function FieldSettingsRows({ name, value, defaultHandling = "revealable", onChange }) {
5207
+ const env = value.envKey ?? "";
5186
5208
  const envProblem = envKeyProblem(env);
5187
5209
  const envOk = env.trim() !== "" && !envProblem;
5188
- const handling = field.handling ?? "revealable";
5189
- const name = field.label.trim() || "Secret";
5210
+ const handling = value.handling ?? defaultHandling;
5190
5211
  const chooseHandling = async (next) => {
5191
5212
  if (next === handling) return;
5192
5213
  if (next === "sealed") {
@@ -5200,6 +5221,38 @@ function SecretBuilderRow({ field, onChange, onRemove }) {
5200
5221
  }
5201
5222
  onChange({ handling: next });
5202
5223
  };
5224
+ return /* @__PURE__ */ jsxs21(Fragment15, { children: [
5225
+ /* @__PURE__ */ jsx22(VaultRow, { label: "Env key", hint: envProblem ? hint(envProblem, "destructive") : hint("The name sandboxes and workflows use"), children: /* @__PURE__ */ jsx22(
5226
+ Field8,
5227
+ {
5228
+ className: "w-full font-mono",
5229
+ "aria-label": `${name} env key`,
5230
+ "aria-invalid": Boolean(envProblem),
5231
+ placeholder: "e.g. GITHUB_TOKEN",
5232
+ autoComplete: "off",
5233
+ spellCheck: false,
5234
+ value: env,
5235
+ onChange: (e) => onChange({ envKey: e.target.value, ...e.target.value.trim() ? {} : { injectIntoSandbox: false } })
5236
+ }
5237
+ ) }),
5238
+ /* @__PURE__ */ jsx22(VaultRow, { label: "Who can see it", hint: hint(HANDLING_WORDS[handling].hint), children: /* @__PURE__ */ jsx22(
5239
+ SegmentedControl5,
5240
+ {
5241
+ "aria-label": `Who can see ${name}`,
5242
+ value: handling,
5243
+ onValueChange: (v) => void chooseHandling(v),
5244
+ data: HANDLINGS.map((h) => ({ value: h, label: HANDLING_WORDS[h].label, title: HANDLING_WORDS[h].hint }))
5245
+ }
5246
+ ) }),
5247
+ /* @__PURE__ */ jsx22(VaultRow, { label: "Use in sandbox", hint: envOk ? hint("Sandboxes get it as an env variable") : hint("Needs an env key"), children: /* @__PURE__ */ jsx22(Switch5, { "aria-label": `Use ${name} in sandbox`, checked: envOk && value.injectIntoSandbox === true, disabled: !envOk, onCheckedChange: (v) => onChange({ injectIntoSandbox: v }) }) })
5248
+ ] });
5249
+ }
5250
+ var hasSecretSettings = (s) => saysMore(s, "revealable");
5251
+ var hasDeclaredSettings = (s, defaultHandling) => Boolean(s && saysMore(s, defaultHandling));
5252
+ function SecretBuilderRow({ field, onChange, onRemove }) {
5253
+ const [open, setOpen] = useState22(hasSecretSettings(field));
5254
+ const handling = field.handling ?? "revealable";
5255
+ const name = field.label.trim() || "Secret";
5203
5256
  return /* @__PURE__ */ jsxs21(Fragment15, { children: [
5204
5257
  /* @__PURE__ */ jsx22(
5205
5258
  CustomEditRow,
@@ -5207,47 +5260,26 @@ function SecretBuilderRow({ field, onChange, onRemove }) {
5207
5260
  label: field.label,
5208
5261
  value: field.value,
5209
5262
  secret: true,
5263
+ multiline: field.multiline === true,
5210
5264
  onLabel: (v) => onChange({ label: v }),
5211
5265
  onValue: (v) => onChange({ value: v }),
5212
5266
  onRemove,
5213
- onPasteValue: (text) => {
5214
- const a = parseEnvAssignment(text);
5215
- if (!a) return false;
5216
- onChange({ envKey: a.key, value: a.value, ...field.label.trim() ? {} : { label: labelFromEnvKey(a.key) } });
5217
- setOpen(true);
5218
- return true;
5267
+ ...field.multiline ? {} : {
5268
+ onPasteValue: (text) => {
5269
+ const a = parseEnvAssignment(text);
5270
+ if (!a) return false;
5271
+ onChange({ envKey: a.key, value: a.value, ...field.label.trim() ? {} : { label: labelFromEnvKey(a.key) } });
5272
+ setOpen(true);
5273
+ return true;
5274
+ }
5219
5275
  },
5220
5276
  extra: /* @__PURE__ */ jsxs21(Fragment15, { children: [
5221
- handling !== "sealed" ? /* @__PURE__ */ jsx22(GenerateButton, { onUse: (v) => onChange({ value: v }) }) : null,
5277
+ handling !== "sealed" && !field.multiline ? /* @__PURE__ */ jsx22(GenerateButton, { onUse: (v) => onChange({ value: v }) }) : null,
5222
5278
  /* @__PURE__ */ jsx22(Button18, { variant: "quiet", icon: /* @__PURE__ */ jsx22(SlidersGlyph, {}), "aria-label": `${name} settings`, pressed: open, onClick: () => setOpen((o) => !o) })
5223
5279
  ] })
5224
5280
  }
5225
5281
  ),
5226
- open ? /* @__PURE__ */ jsxs21(Fragment15, { children: [
5227
- /* @__PURE__ */ jsx22(VaultRow, { label: "Env key", hint: envProblem ? hint(envProblem, "destructive") : hint("The name sandboxes and workflows use"), children: /* @__PURE__ */ jsx22(
5228
- Field8,
5229
- {
5230
- className: "w-full font-mono",
5231
- "aria-label": `${name} env key`,
5232
- "aria-invalid": Boolean(envProblem),
5233
- placeholder: "e.g. GITHUB_TOKEN",
5234
- autoComplete: "off",
5235
- spellCheck: false,
5236
- value: env,
5237
- onChange: (e) => onChange({ envKey: e.target.value, ...e.target.value.trim() ? {} : { injectIntoSandbox: false } })
5238
- }
5239
- ) }),
5240
- /* @__PURE__ */ jsx22(VaultRow, { label: "Who can see it", hint: hint(HANDLING_WORDS[handling].hint), children: /* @__PURE__ */ jsx22(
5241
- SegmentedControl5,
5242
- {
5243
- "aria-label": `Who can see ${name}`,
5244
- value: handling,
5245
- onValueChange: (v) => void chooseHandling(v),
5246
- data: HANDLINGS.map((h) => ({ value: h, label: HANDLING_WORDS[h].label, title: HANDLING_WORDS[h].hint }))
5247
- }
5248
- ) }),
5249
- /* @__PURE__ */ jsx22(VaultRow, { label: "Use in sandbox", hint: envOk ? hint("Sandboxes get it as an env variable") : hint("Needs an env key"), children: /* @__PURE__ */ jsx22(Switch5, { "aria-label": `Use ${name} in sandbox`, checked: envOk && field.injectIntoSandbox === true, disabled: !envOk, onCheckedChange: (v) => onChange({ injectIntoSandbox: v }) }) })
5250
- ] }) : null
5282
+ open ? /* @__PURE__ */ jsx22(FieldSettingsRows, { name, value: field, onChange }) : null
5251
5283
  ] });
5252
5284
  }
5253
5285
  function withMfaMethod(custom, v) {
@@ -5876,7 +5908,9 @@ function SharingSummary({ item, port, className }) {
5876
5908
 
5877
5909
  // src/ItemPane.tsx
5878
5910
  import { formatAbsoluteDate as formatAbsoluteDate3 } from "@ai-matrx/kit/format";
5879
- import { Fragment as Fragment17, jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
5911
+ import { Fragment as Fragment18, jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
5912
+ var ENV_VALUE_KEY = "env_value";
5913
+ var secureNoteDraft = () => ({ key: SECURE_NOTE_KEY, label: "Secure note", value: "", multiline: true, description: "Encrypted notes" });
5880
5914
  var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
5881
5915
  function ItemPane(props) {
5882
5916
  const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
@@ -6067,6 +6101,16 @@ function ItemPane(props) {
6067
6101
  const fieldSettings = (f) => canEdit ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SlidersGlyph, {}), "aria-label": `${f.label} settings`, title: `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) }) : null;
6068
6102
  const turnOnOne = canTurnOn ? (f) => () => turnOn([f]) : () => void 0;
6069
6103
  const declaredKeys = new Set(declared.map((f) => f.key));
6104
+ const hasSecureNote = declaredKeys.has(SECURE_NOTE_KEY) || Boolean(item?.fields.some((f) => f.key === SECURE_NOTE_KEY)) || draft.secrets.some((x) => x.key === SECURE_NOTE_KEY);
6105
+ const [settingsToggled, setSettingsToggled] = useState27(/* @__PURE__ */ new Set());
6106
+ const settingsOpen = (f) => settingsToggled.has(f.key) !== (definition?.key === ENV_VALUE_KEY || hasDeclaredSettings(draft.fieldSettings?.[f.key], f.handling));
6107
+ const toggleSettings = (key) => setSettingsToggled((cur) => {
6108
+ const next = new Set(cur);
6109
+ if (next.has(key)) next.delete(key);
6110
+ else next.add(key);
6111
+ return next;
6112
+ });
6113
+ const patchFieldSettings = (key, p) => setDraft((d) => ({ ...d, fieldSettings: { ...d.fieldSettings, [key]: { ...d.fieldSettings?.[key], ...p } } }));
6070
6114
  const extraFields = (item?.fields ?? []).filter((f) => !declaredKeys.has(f.key) && !draft.removed.includes(f.id) && !isAuthenticatorStorage(f.key));
6071
6115
  const metaValue = (key) => draft.values[key] ?? item?.custom.find((c) => c.key === key)?.value ?? "";
6072
6116
  const extraCustom = draft.custom.filter((c) => !declaredKeys.has(c.key) && c.key !== MFA_METHOD_KEY && !isAuthenticatorStorage(c.key));
@@ -6149,7 +6193,7 @@ function ItemPane(props) {
6149
6193
  /* @__PURE__ */ jsx27(SettingsIcon, { className: "size-4" }),
6150
6194
  "Settings"
6151
6195
  ] }) : null,
6152
- canManage ? /* @__PURE__ */ jsxs25(Fragment17, { children: [
6196
+ canManage ? /* @__PURE__ */ jsxs25(Fragment18, { children: [
6153
6197
  /* @__PURE__ */ jsx27(DropdownMenuSeparator3, {}),
6154
6198
  /* @__PURE__ */ jsxs25(DropdownMenuItem3, { className: "text-destructive", disabled: busy, onSelect: () => void remove(), children: [
6155
6199
  /* @__PURE__ */ jsx27(TrashGlyph, { className: "size-4" }),
@@ -6169,7 +6213,7 @@ function ItemPane(props) {
6169
6213
  /* @__PURE__ */ jsx27("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` }),
6170
6214
  canTurnOn ? /* @__PURE__ */ jsx27(TurnOnButton, { label: "all fields", onTurnOn: () => turnOn(offFields) }) : null
6171
6215
  ] }) : null,
6172
- /* @__PURE__ */ jsx27("div", { className: "min-h-0 flex-1 overflow-y-auto", children: sent ? /* @__PURE__ */ jsx27(AssignResult, { sent, onAnother: createAnother, onDone: onCancelNew }) : /* @__PURE__ */ jsx27("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__ */ jsxs25(Fragment17, { children: [
6216
+ /* @__PURE__ */ jsx27("div", { className: "min-h-0 flex-1 overflow-y-auto", children: sent ? /* @__PURE__ */ jsx27(AssignResult, { sent, onAnother: createAnother, onDone: onCancelNew }) : /* @__PURE__ */ jsx27("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__ */ jsxs25(Fragment18, { children: [
6173
6217
  /* @__PURE__ */ jsxs25(VaultSection, { children: [
6174
6218
  mode === "new" ? /* @__PURE__ */ jsx27(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx27(
6175
6219
  OptionCombobox,
@@ -6190,7 +6234,7 @@ function ItemPane(props) {
6190
6234
  }
6191
6235
  ) }) : null,
6192
6236
  /* @__PURE__ */ jsx27(EditRow, { label: "Name", value: draft.name, onChange: (v) => patch({ name: v }), placeholder: "Name", autoFocus: mode === "new" }),
6193
- mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs25(Fragment17, { children: [
6237
+ mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs25(Fragment18, { children: [
6194
6238
  /* @__PURE__ */ jsx27(EditRow, { label: "Their email", value: recipient, placeholder: "name@company.com", inputMode: "email", onChange: setRecipient }),
6195
6239
  declared.some((f) => f.storage === "encrypted" && f.kind === "secret") ? /* @__PURE__ */ jsx27(VaultRow, { label: "Password", hint: "You never see it", children: /* @__PURE__ */ jsx27(Switch6, { checked: generatePrivately, onCheckedChange: setGeneratePrivately, "aria-label": "Generate the password privately" }) }) : null
6196
6240
  ] }) : null,
@@ -6199,24 +6243,29 @@ function ItemPane(props) {
6199
6243
  const secretKind = f.storage === "encrypted" && f.kind === "secret";
6200
6244
  const value = f.storage === "metadata" ? metaValue(f.key) : draft.values[f.key] ?? "";
6201
6245
  const hidden = existing && existing.handling !== "visible" && !(f.key in loaded);
6202
- return /* @__PURE__ */ jsx27(
6203
- EditRow,
6204
- {
6205
- label: f.label,
6206
- value,
6207
- placeholder: hidden ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : f.required ? "Required" : isRecoveryCodesField(f) ? "Backup codes, one per line" : "",
6208
- secret: secretKind,
6209
- multiline: f.kind === "multiline",
6210
- inputMode: f.kind === "url" ? "url" : USERNAME_KEYS.test(f.key) ? "email" : "text",
6211
- onChange: (v) => setValue(f.key, v),
6212
- actions: /* @__PURE__ */ jsxs25(Fragment17, { children: [
6213
- hidden && existing?.handling === "revealable" && item?.capabilities.canReveal ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
6214
- secretKind ? /* @__PURE__ */ jsx27(GenerateButton, { onUse: (v) => setValue(f.key, v) }) : null,
6215
- existing ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${existing.id}`) }) : null
6216
- ] })
6217
- },
6218
- f.key
6219
- );
6246
+ const newSecret = mode === "new" && f.storage === "encrypted" && owner !== "person";
6247
+ const open = newSecret && settingsOpen(f);
6248
+ return /* @__PURE__ */ jsxs25(Fragment17, { children: [
6249
+ /* @__PURE__ */ jsx27(
6250
+ EditRow,
6251
+ {
6252
+ label: f.label,
6253
+ value,
6254
+ placeholder: hidden ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : f.required ? "Required" : isRecoveryCodesField(f) ? "Backup codes, one per line" : "",
6255
+ secret: secretKind,
6256
+ multiline: f.kind === "multiline" || value.includes("\n"),
6257
+ inputMode: f.kind === "url" ? "url" : USERNAME_KEYS.test(f.key) ? "email" : "text",
6258
+ onChange: (v) => setValue(f.key, v),
6259
+ actions: /* @__PURE__ */ jsxs25(Fragment18, { children: [
6260
+ hidden && existing?.handling === "revealable" && item?.capabilities.canReveal ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
6261
+ secretKind ? /* @__PURE__ */ jsx27(GenerateButton, { onUse: (v) => setValue(f.key, v) }) : null,
6262
+ existing ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${existing.id}`) }) : null,
6263
+ newSecret ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SlidersGlyph, {}), "aria-label": `${f.label} settings`, pressed: open, onClick: () => toggleSettings(f.key) }) : null
6264
+ ] })
6265
+ }
6266
+ ),
6267
+ open ? /* @__PURE__ */ jsx27(FieldSettingsRows, { name: f.label, value: draft.fieldSettings?.[f.key] ?? {}, defaultHandling: f.handling, onChange: (p) => patchFieldSettings(f.key, p) }) : null
6268
+ ] }, f.key);
6220
6269
  }),
6221
6270
  extraFields.map((f) => /* @__PURE__ */ jsx27(
6222
6271
  EditRow,
@@ -6225,11 +6274,11 @@ function ItemPane(props) {
6225
6274
  value: draft.values[f.key] ?? "",
6226
6275
  placeholder: f.handling === "visible" || f.key in loaded ? "" : "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
6227
6276
  secret: f.handling !== "visible" && !isRecoveryCodesField(f),
6228
- multiline: isRecoveryCodesField(f),
6277
+ multiline: f.kind === "multiline" || isRecoveryCodesField(f) || (draft.values[f.key] ?? "").includes("\n"),
6229
6278
  onChange: (v) => setValue(f.key, v),
6230
6279
  onRemove: () => patch({ removed: [...draft.removed, f.id] }),
6231
6280
  removeLabel: `Delete ${f.label}`,
6232
- actions: /* @__PURE__ */ jsxs25(Fragment17, { children: [
6281
+ actions: /* @__PURE__ */ jsxs25(Fragment18, { children: [
6233
6282
  f.handling === "revealable" && !(f.key in loaded) && item?.capabilities.canReveal ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
6234
6283
  /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) })
6235
6284
  ] })
@@ -6294,6 +6343,7 @@ function ItemPane(props) {
6294
6343
  /* @__PURE__ */ jsx27(DropdownMenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(PlusGlyph, {}), children: "Add" }) }),
6295
6344
  /* @__PURE__ */ jsxs25(DropdownMenuContent3, { align: "end", children: [
6296
6345
  /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => patch({ secrets: [...draft.secrets, { key: "", label: "", value: "" }] }), children: "Secret field" }),
6346
+ !hasSecureNote ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => patch({ secrets: [...draft.secrets, secureNoteDraft()] }), children: "Secure note" }) : null,
6297
6347
  /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => patch({ custom: [...draft.custom, { key: `custom_${draft.custom.length + 1}_${Date.now() % 1e5}`, label: "", value: "" }] }), children: "Text field" }),
6298
6348
  !tagsVisible ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => setShowTags(true), children: "Tags" }) : null,
6299
6349
  !descriptionVisible ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => setShowDescription(true), children: "Description" }) : null,
@@ -6326,7 +6376,7 @@ function ItemPane(props) {
6326
6376
  }
6327
6377
  ),
6328
6378
  filesProps ? /* @__PURE__ */ jsx27(FilesSection, { ...filesProps, editing: true }) : mode === "new" && owner !== "person" ? /* @__PURE__ */ jsx27(DraftFilesSection, { files: queuedFiles, onFiles: setQueuedFiles }) : null
6329
- ] }) : item ? /* @__PURE__ */ jsxs25(Fragment17, { children: [
6379
+ ] }) : item ? /* @__PURE__ */ jsxs25(Fragment18, { children: [
6330
6380
  /* @__PURE__ */ jsxs25(VaultSection, { children: [
6331
6381
  declared.map((f) => {
6332
6382
  if (f.storage === "metadata") {
@@ -6647,7 +6697,7 @@ function refusalText(reason) {
6647
6697
  // src/lists/RestorePanel.tsx
6648
6698
  import { useEffect as useEffect18, useState as useState29 } from "react";
6649
6699
  import { Button as Button24 } from "@ai-matrx/design-system/controls";
6650
- import { Fragment as Fragment18, jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
6700
+ import { Fragment as Fragment19, jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
6651
6701
  var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
6652
6702
  function RestorePanel({ lists, item, restore, onClose }) {
6653
6703
  const [preview, setPreview] = useState29(null);
@@ -6692,7 +6742,7 @@ function RestorePanel({ lists, item, restore, onClose }) {
6692
6742
  title: `Restore "${item.name}"`,
6693
6743
  size: "md",
6694
6744
  onClose,
6695
- footer: /* @__PURE__ */ jsxs27(Fragment18, { children: [
6745
+ footer: /* @__PURE__ */ jsxs27(Fragment19, { children: [
6696
6746
  /* @__PURE__ */ jsx29(Button24, { variant: "quiet", onClick: onClose, children: refused ? "Close" : "Cancel" }),
6697
6747
  refused ? null : /* @__PURE__ */ jsx29(Button24, { variant: "primary", icon: /* @__PURE__ */ jsx29(RestoreGlyph, {}), disabled: busy || loading || lists.preview !== void 0 && preview === null, onClick: () => void run(), children: busy ? "Restoring\u2026" : "Restore" })
6698
6748
  ] }),
@@ -7190,7 +7240,7 @@ function addPasskeyFailure(message2) {
7190
7240
  var isRevoked = (d) => d.revokedAt !== null;
7191
7241
 
7192
7242
  // src/devices/DevicesPanel.tsx
7193
- import { Fragment as Fragment19, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
7243
+ import { Fragment as Fragment20, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
7194
7244
  var messageOf3 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
7195
7245
  function ErrorLine2({ text }) {
7196
7246
  return text ? /* @__PURE__ */ jsx33("p", { role: "alert", className: "px-1 text-sm text-destructive", children: text }) : null;
@@ -7321,7 +7371,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
7321
7371
  };
7322
7372
  const canApprove = Boolean(key && passkeys && here && methods?.passkey && !approvedUntil);
7323
7373
  const title = isMac ? "Approve this Mac" : name ? `Approve ${name}` : "Approve this browser";
7324
- const footer = approvedUntil ? /* @__PURE__ */ jsx33(Button28, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs31(Fragment19, { children: [
7374
+ const footer = approvedUntil ? /* @__PURE__ */ jsx33(Button28, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs31(Fragment20, { children: [
7325
7375
  /* @__PURE__ */ jsx33(Button28, { variant: "quiet", disabled: busy !== null, onClick: refuse, children: key ? "Refuse" : "Close" }),
7326
7376
  canApprove ? /* @__PURE__ */ jsx33(Button28, { variant: "primary", icon: /* @__PURE__ */ jsx33(FingerprintGlyph, {}), disabled: busy !== null, onClick: () => void approve(), children: busy === "approve" ? "Approving\u2026" : "Approve with passkey" }) : null
7327
7377
  ] });
@@ -7329,7 +7379,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
7329
7379
  "This link names no key. Start again from ",
7330
7380
  where,
7331
7381
  "."
7332
- ] }) }) : /* @__PURE__ */ jsxs31(Fragment19, { children: [
7382
+ ] }) }) : /* @__PURE__ */ jsxs31(Fragment20, { children: [
7333
7383
  /* @__PURE__ */ jsxs31(VaultSection, { title: "What is asking", children: [
7334
7384
  /* @__PURE__ */ jsx33(VaultRow, { label: "Asking", hint: "Approve only if you just asked", children: asker }),
7335
7385
  name ? /* @__PURE__ */ jsx33(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx33("span", { className: "block truncate", children: name }) }) : null,
@@ -7629,7 +7679,7 @@ function useNativeImport(bridge, stillAllowed, onImported) {
7629
7679
  }
7630
7680
 
7631
7681
  // src/native/NativeImportPanel.tsx
7632
- import { Fragment as Fragment20, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
7682
+ import { Fragment as Fragment21, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
7633
7683
  var TONE = {
7634
7684
  eligible: "success",
7635
7685
  committed: "success",
@@ -7673,16 +7723,16 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
7673
7723
  const yes = await confirm13({ title: `Add ${plural2(ready, "passkey")} to ${orgName}?`, description: "Passkeys already there are skipped.", confirmLabel: "Import" });
7674
7724
  if (yes) await flow.confirm();
7675
7725
  };
7676
- const footer = preview ? /* @__PURE__ */ jsxs32(Fragment20, { children: [
7726
+ const footer = preview ? /* @__PURE__ */ jsxs32(Fragment21, { children: [
7677
7727
  /* @__PURE__ */ jsx34(Button29, { variant: "quiet", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel" }),
7678
7728
  /* @__PURE__ */ jsxs32(Button29, { variant: "primary", icon: /* @__PURE__ */ jsx34(ImportGlyph, { className: "size-4" }), disabled: busy || ready === 0, onClick: () => void importNow(), children: [
7679
7729
  "Import ",
7680
7730
  ready
7681
7731
  ] })
7682
- ] }) : status ? active ? /* @__PURE__ */ jsxs32(Fragment20, { children: [
7732
+ ] }) : status ? active ? /* @__PURE__ */ jsxs32(Fragment21, { children: [
7683
7733
  /* @__PURE__ */ jsx34(Button29, { variant: "outline", disabled: busy, onClick: () => void flow.refresh(), children: "Refresh" }),
7684
7734
  /* @__PURE__ */ jsx34(Button29, { variant: "outline", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel import" })
7685
- ] }) : /* @__PURE__ */ jsxs32(Fragment20, { children: [
7735
+ ] }) : /* @__PURE__ */ jsxs32(Fragment21, { children: [
7686
7736
  /* @__PURE__ */ jsx34(Button29, { variant: "quiet", onClick: flow.reset, children: "New file" }),
7687
7737
  /* @__PURE__ */ jsx34(Button29, { variant: "primary", onClick: onClose, children: "Done" })
7688
7738
  ] }) : /* @__PURE__ */ jsx34(Button29, { variant: "quiet", onClick: onClose, children: "Close" });
@@ -7721,7 +7771,7 @@ import { GlobeIcon as GlobeIcon4 } from "@ai-matrx/design-system/icons";
7721
7771
  // src/extension/CaptureCard.tsx
7722
7772
  import { useState as useState36, useSyncExternalStore as useSyncExternalStore3 } from "react";
7723
7773
  import { Button as Button30, SearchField as SearchField3 } from "@ai-matrx/design-system/controls";
7724
- import { Fragment as Fragment21, jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
7774
+ import { Fragment as Fragment22, jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
7725
7775
  var SEARCH_FROM = 4;
7726
7776
  function CaptureCard({ capture, onChanged }) {
7727
7777
  const prompt = useSyncExternalStore3(capture.subscribe, capture.get, capture.get);
@@ -7754,7 +7804,7 @@ function CaptureCard({ capture, onChanged }) {
7754
7804
  ] }),
7755
7805
  /* @__PURE__ */ jsx35(Button30, { variant: "quiet", icon: /* @__PURE__ */ jsx35(XGlyph, {}), "aria-label": "Not now", disabled: busy, onClick: () => void decide({ action: "dismiss" }) })
7756
7806
  ] }),
7757
- prompt.unavailable ? /* @__PURE__ */ jsx35("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ jsxs33(Fragment21, { children: [
7807
+ prompt.unavailable ? /* @__PURE__ */ jsx35("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ jsxs33(Fragment22, { children: [
7758
7808
  existing.length > 0 ? /* @__PURE__ */ jsxs33("div", { className: "flex flex-col gap-1", children: [
7759
7809
  existing.length >= SEARCH_FROM ? /* @__PURE__ */ jsx35(SearchField3, { value: q, onChange: (e) => setQ(e.target.value), placeholder: "Search logins", "aria-label": "Search logins to update" }) : null,
7760
7810
  /* @__PURE__ */ jsxs33("ul", { className: "flex max-h-36 flex-col gap-px overflow-y-auto", children: [
@@ -7860,7 +7910,7 @@ import { useState as useState38 } from "react";
7860
7910
  import { Popover as Popover2, PopoverContent as PopoverContent2, PopoverTrigger as PopoverTrigger2 } from "@ai-matrx/design-system";
7861
7911
  import { Button as Button32 } from "@ai-matrx/design-system/controls";
7862
7912
  import { CopyIcon as CopyIcon8 } from "@ai-matrx/design-system/icons";
7863
- import { Fragment as Fragment22, jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
7913
+ import { Fragment as Fragment23, jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
7864
7914
  var HOLD_MS = 6e4;
7865
7915
  function PageGenerator({ fields }) {
7866
7916
  const limits = useGeneratorLimitsSource();
@@ -7911,12 +7961,12 @@ function PageGenerator({ fields }) {
7911
7961
  }
7912
7962
  };
7913
7963
  const value = held.value;
7914
- return /* @__PURE__ */ jsxs35(Fragment22, { children: [
7964
+ return /* @__PURE__ */ jsxs35(Fragment23, { children: [
7915
7965
  /* @__PURE__ */ jsx37(
7916
7966
  VaultRow,
7917
7967
  {
7918
7968
  label: "New password",
7919
- actions: /* @__PURE__ */ jsxs35(Fragment22, { children: [
7969
+ actions: /* @__PURE__ */ jsxs35(Fragment23, { children: [
7920
7970
  value ? /* @__PURE__ */ jsx37(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx37(CopyIcon8, {}), "aria-label": "Copy password", onClick: () => void copy(value, "Password") }) : null,
7921
7971
  /* @__PURE__ */ jsxs35(Popover2, { open, onOpenChange: setOpen, children: [
7922
7972
  /* @__PURE__ */ jsx37(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx37(Button32, { variant: "outline", icon: /* @__PURE__ */ jsx37(KeyGlyph, {}), disabled: busy, children: "Generate" }) }),
@@ -9062,6 +9112,28 @@ function trashItem(r, ctx) {
9062
9112
  createdAt: ""
9063
9113
  };
9064
9114
  }
9115
+ async function withTypes(items, door, ctx) {
9116
+ if (!door.schema || items.length === 0) return items;
9117
+ const keys = /* @__PURE__ */ new Map();
9118
+ const CHUNK = 100;
9119
+ try {
9120
+ for (let i = 0; i < items.length; i += CHUNK) {
9121
+ const ids = items.slice(i, i + CHUNK).map((x) => x.id);
9122
+ const { data, error } = await door.schema("users").from("credential_items").select("id,definition_key").in("id", ids);
9123
+ if (error) throw new Error(error.message || "credential_items read failed");
9124
+ for (const r of Array.isArray(data) ? data : []) {
9125
+ if (typeof r.id === "string" && typeof r.definition_key === "string" && r.definition_key) keys.set(r.id, r.definition_key);
9126
+ }
9127
+ }
9128
+ } catch (e) {
9129
+ console.warn("[vault] Trash item types could not be read; rows say Credential", e);
9130
+ return items;
9131
+ }
9132
+ return items.map((it) => {
9133
+ const key = keys.get(it.id);
9134
+ return key ? { ...it, definitionKey: key, definitionLabel: ctx.definition(key)?.label ?? humanize(key) } : it;
9135
+ });
9136
+ }
9065
9137
  var previewOf = async (door, id) => parseRecoveryPreview(await call(door, "vault_recovery_preview", { p_id: id }));
9066
9138
  function createListsPort(ctx, door) {
9067
9139
  return {
@@ -9094,7 +9166,8 @@ function createListsPort(ctx, door) {
9094
9166
  if (rows.length < PAGE2) break;
9095
9167
  }
9096
9168
  const items = all.map((r) => trashItem(r, ctx)).filter((i) => i !== null);
9097
- return [...new Map(items.map((i) => [i.id, i])).values()];
9169
+ const unique = [...new Map(items.map((i) => [i.id, i])).values()];
9170
+ return withTypes(unique, door, ctx);
9098
9171
  }
9099
9172
  },
9100
9173
  favorites: {
@@ -9117,16 +9190,25 @@ function createListsPort(ctx, door) {
9117
9190
  import * as account6 from "@ai-matrx/api/account";
9118
9191
 
9119
9192
  // src/secret-field-in.ts
9120
- function secretFieldIn(s) {
9193
+ function settingsIn(s) {
9121
9194
  const envKey = s.envKey?.trim() || null;
9122
9195
  return {
9123
- field_key: fieldKeyOf(s.label),
9124
- value: s.value,
9125
- handling: s.handling ?? "revealable",
9126
9196
  ...envKey ? { env_key: envKey } : {},
9127
9197
  ...envKey && s.injectIntoSandbox ? { inject_into_sandbox: true } : {}
9128
9198
  };
9129
9199
  }
9200
+ function secretFieldIn(s) {
9201
+ return {
9202
+ field_key: s.key.trim() || fieldKeyOf(s.label),
9203
+ value: s.value,
9204
+ handling: s.handling ?? "revealable",
9205
+ ...s.description ? { description: s.description } : {},
9206
+ ...settingsIn(s)
9207
+ };
9208
+ }
9209
+ function declaredFieldIn(f, value, settings) {
9210
+ return { field_key: f.key, value, handling: settings?.handling ?? f.handling, ...settingsIn(settings ?? {}) };
9211
+ }
9130
9212
 
9131
9213
  // src/sharing/api.ts
9132
9214
  function grantOf(w) {
@@ -9227,7 +9309,7 @@ function createSharingPort(ctx, options = {}) {
9227
9309
  initiation: "user",
9228
9310
  non_secret_fields: [...meta.map((f) => ({ key: f.key, label: f.label, value: draft.values[f.key] ?? "" })), ...draft.custom.filter((c) => c.label.trim() !== "").map((c) => ({ key: c.key || fieldKeyOf(c.label), label: c.label, value: c.value }))],
9229
9311
  fields: [
9230
- ...encrypted.map((f) => ({ field_key: f.key, value: draft.values[f.key] ?? "", handling: f.handling })),
9312
+ ...encrypted.map((f) => declaredFieldIn(f, draft.values[f.key] ?? "", draft.fieldSettings?.[f.key])),
9231
9313
  ...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(secretFieldIn)
9232
9314
  ]
9233
9315
  }
@@ -9356,7 +9438,7 @@ async function readNativeImportLimits(api, organizationId) {
9356
9438
  var recoveryOf = (w) => w.lifecycle?.vault_recovery;
9357
9439
  var isDeleted = (w) => recoveryOf(w)?.state === "deleted";
9358
9440
  var MATCH_MODES2 = ["host", "domain", "exact", "never"];
9359
- var FIELD_WORDS = { totp_seed: "One-time password key", authenticator_last_time_step: "Last code used" };
9441
+ var FIELD_WORDS = { secure_notes: "Secure note", totp_seed: "One-time password key", authenticator_last_time_step: "Last code used" };
9360
9442
  var handlingOf = (v) => v === "visible" || v === "sealed" ? v : "revealable";
9361
9443
  function fieldOf(w, def) {
9362
9444
  const declared = def?.fields.find((f) => f.key === w.field_key);
@@ -9365,7 +9447,8 @@ function fieldOf(w, def) {
9365
9447
  id: w.id,
9366
9448
  key: w.field_key,
9367
9449
  label: declared?.label ?? FIELD_WORDS[w.field_key] ?? humanize(w.field_key),
9368
- kind: declared?.kind ?? (handling === "visible" ? "text" : "secret"),
9450
+ // A field no type declares still edits as several lines when its key says so (an old "Secure note").
9451
+ kind: declared?.kind ?? (isMultilineKey(w.field_key) ? "multiline" : handling === "visible" ? "text" : "secret"),
9369
9452
  handling,
9370
9453
  editable: w.editable ?? true,
9371
9454
  envKey: w.env_key ?? null,
@@ -9520,7 +9603,7 @@ function createApiVaultPort(api, options = {}) {
9520
9603
  initiation: "user",
9521
9604
  non_secret_fields: [...meta.map((f) => ({ key: f.key, label: f.label, value: draft.values[f.key] ?? "" })), ...draft.custom.filter((c) => c.label.trim() !== "").map((c) => ({ key: c.key || fieldKeyOf(c.label), label: c.label, value: c.value }))],
9522
9605
  fields: [
9523
- ...encrypted.map((f) => ({ field_key: f.key, value: draft.values[f.key] ?? "", handling: f.handling })),
9606
+ ...encrypted.map((f) => declaredFieldIn(f, draft.values[f.key] ?? "", draft.fieldSettings?.[f.key])),
9524
9607
  ...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(secretFieldIn),
9525
9608
  // Backup codes on a type that does not declare them (a website login): their own encrypted field.
9526
9609
  ...!declared.some((f) => f.key === RECOVERY_CODES_KEY) && (draft.values[RECOVERY_CODES_KEY] ?? "").trim() !== "" ? [{ field_key: RECOVERY_CODES_KEY, value: parseRecoveryCodes(draft.values[RECOVERY_CODES_KEY] ?? "").join("\n"), handling: "revealable", description: "One-time account recovery codes" }] : []