@ai-matrx/vault 0.1.6 → 0.1.8

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.d.cts CHANGED
@@ -122,7 +122,7 @@ declare function locationToParams(loc: VaultLocation): URLSearchParams;
122
122
  /** The one search every list shares: name, type, tags, URLs, then plaintext custom fields. */
123
123
  declare function matchesQuery(item: VaultItem, query: string): boolean;
124
124
  /** An item's website as people read it: `github.com` (no scheme, no `www.`), or "" when it has none. */
125
- declare function siteOf(item: Pick<VaultItem, "loginUrls">): string;
125
+ declare function loginSiteOf(item: Pick<VaultItem, "loginUrls">): string;
126
126
  declare function sortItems(items: readonly VaultItem[], sort: VaultSort): VaultItem[];
127
127
  interface NewSecretField {
128
128
  key: string;
@@ -1240,4 +1240,4 @@ declare function GenerateButton({ onUse, label, limits, disabled }: {
1240
1240
  disabled?: boolean;
1241
1241
  }): react.JSX.Element | null;
1242
1242
 
1243
- export { type ApiVaultPortOptions, CATEGORIES, type CategoryId, type CopyOptions, DEFAULT_LOCATION, type DefinitionField, type FieldHandling, type FieldKind, GenerateButton, type IdentityAccount, type IdentityMethod, type ItemDraft, LOCKED_MESSAGE, type NoticeKind, type Notify, type SaveResult, type SupabaseAuthLike, type TotpReading, type UriMatchMode, type UrlGuess, VaultApp, type VaultAppProps, type VaultAttachment, type VaultAuthenticator, type VaultClipboard, type VaultCustomField, type VaultDefinition, type VaultField, type VaultHostCapabilities, type VaultIdentity, type VaultItem, type VaultItemCapabilities, type VaultKnobs, type VaultLayout, type VaultLocation, type VaultLock, VaultLockedError, type VaultOrganizationRef, type VaultOwner, type VaultPort, type VaultSelection, type VaultSnapshot, type VaultSort, type VaultUserStateDoor, categoryOf, copyValue, createApiVaultPort, createSupabaseIdentity, createVaultKnobs, guardPort, inferFromUrl, locationFromParams, locationToParams, matchesQuery, needsRecentSignIn, parseDefinitions, siteOf, sortItems };
1243
+ export { type ApiVaultPortOptions, CATEGORIES, type CategoryId, type CopyOptions, DEFAULT_LOCATION, type DefinitionField, type FieldHandling, type FieldKind, GenerateButton, type IdentityAccount, type IdentityMethod, type ItemDraft, LOCKED_MESSAGE, type NoticeKind, type Notify, type SaveResult, type SupabaseAuthLike, type TotpReading, type UriMatchMode, type UrlGuess, VaultApp, type VaultAppProps, type VaultAttachment, type VaultAuthenticator, type VaultClipboard, type VaultCustomField, type VaultDefinition, type VaultField, type VaultHostCapabilities, type VaultIdentity, type VaultItem, type VaultItemCapabilities, type VaultKnobs, type VaultLayout, type VaultLocation, type VaultLock, VaultLockedError, type VaultOrganizationRef, type VaultOwner, type VaultPort, type VaultSelection, type VaultSnapshot, type VaultSort, type VaultUserStateDoor, categoryOf, copyValue, createApiVaultPort, createSupabaseIdentity, createVaultKnobs, guardPort, inferFromUrl, locationFromParams, locationToParams, loginSiteOf, matchesQuery, needsRecentSignIn, parseDefinitions, sortItems };
package/dist/index.d.ts CHANGED
@@ -122,7 +122,7 @@ declare function locationToParams(loc: VaultLocation): URLSearchParams;
122
122
  /** The one search every list shares: name, type, tags, URLs, then plaintext custom fields. */
123
123
  declare function matchesQuery(item: VaultItem, query: string): boolean;
124
124
  /** An item's website as people read it: `github.com` (no scheme, no `www.`), or "" when it has none. */
125
- declare function siteOf(item: Pick<VaultItem, "loginUrls">): string;
125
+ declare function loginSiteOf(item: Pick<VaultItem, "loginUrls">): string;
126
126
  declare function sortItems(items: readonly VaultItem[], sort: VaultSort): VaultItem[];
127
127
  interface NewSecretField {
128
128
  key: string;
@@ -1240,4 +1240,4 @@ declare function GenerateButton({ onUse, label, limits, disabled }: {
1240
1240
  disabled?: boolean;
1241
1241
  }): react.JSX.Element | null;
1242
1242
 
1243
- export { type ApiVaultPortOptions, CATEGORIES, type CategoryId, type CopyOptions, DEFAULT_LOCATION, type DefinitionField, type FieldHandling, type FieldKind, GenerateButton, type IdentityAccount, type IdentityMethod, type ItemDraft, LOCKED_MESSAGE, type NoticeKind, type Notify, type SaveResult, type SupabaseAuthLike, type TotpReading, type UriMatchMode, type UrlGuess, VaultApp, type VaultAppProps, type VaultAttachment, type VaultAuthenticator, type VaultClipboard, type VaultCustomField, type VaultDefinition, type VaultField, type VaultHostCapabilities, type VaultIdentity, type VaultItem, type VaultItemCapabilities, type VaultKnobs, type VaultLayout, type VaultLocation, type VaultLock, VaultLockedError, type VaultOrganizationRef, type VaultOwner, type VaultPort, type VaultSelection, type VaultSnapshot, type VaultSort, type VaultUserStateDoor, categoryOf, copyValue, createApiVaultPort, createSupabaseIdentity, createVaultKnobs, guardPort, inferFromUrl, locationFromParams, locationToParams, matchesQuery, needsRecentSignIn, parseDefinitions, siteOf, sortItems };
1243
+ export { type ApiVaultPortOptions, CATEGORIES, type CategoryId, type CopyOptions, DEFAULT_LOCATION, type DefinitionField, type FieldHandling, type FieldKind, GenerateButton, type IdentityAccount, type IdentityMethod, type ItemDraft, LOCKED_MESSAGE, type NoticeKind, type Notify, type SaveResult, type SupabaseAuthLike, type TotpReading, type UriMatchMode, type UrlGuess, VaultApp, type VaultAppProps, type VaultAttachment, type VaultAuthenticator, type VaultClipboard, type VaultCustomField, type VaultDefinition, type VaultField, type VaultHostCapabilities, type VaultIdentity, type VaultItem, type VaultItemCapabilities, type VaultKnobs, type VaultLayout, type VaultLocation, type VaultLock, VaultLockedError, type VaultOrganizationRef, type VaultOwner, type VaultPort, type VaultSelection, type VaultSnapshot, type VaultSort, type VaultUserStateDoor, categoryOf, copyValue, createApiVaultPort, createSupabaseIdentity, createVaultKnobs, guardPort, inferFromUrl, locationFromParams, locationToParams, loginSiteOf, matchesQuery, needsRecentSignIn, parseDefinitions, sortItems };
package/dist/index.js CHANGED
@@ -620,12 +620,7 @@ function formatBytes(n) {
620
620
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(n < 10 * 1024 ? 1 : 0)} KB`;
621
621
  return `${(n / 1024 / 1024).toFixed(1)} MB`;
622
622
  }
623
- function formatDate(iso, withTime = false) {
624
- if (!iso) return "";
625
- const d = new Date(iso);
626
- if (Number.isNaN(d.getTime())) return iso;
627
- return d.toLocaleString(void 0, withTime ? { year: "numeric", month: "short", day: "numeric", hour: "numeric", minute: "2-digit" } : { year: "numeric", month: "short", day: "numeric" });
628
- }
623
+ var DAY_FORMAT = { year: "numeric", month: "short", day: "numeric" };
629
624
 
630
625
  // src/FieldRows.tsx
631
626
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
@@ -765,6 +760,9 @@ function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove }) {
765
760
  );
766
761
  }
767
762
 
763
+ // src/activity/HistoryPanel.tsx
764
+ import { formatAbsoluteDate as formatAbsoluteDate2 } from "@ai-matrx/kit/format";
765
+
768
766
  // src/activity/logic.ts
769
767
  import { formatRelativeTime } from "@ai-matrx/kit/format";
770
768
 
@@ -816,7 +814,7 @@ function matchesQuery(item, query) {
816
814
  return [item.name, item.definitionLabel, ...item.tags, ...item.loginUrls, ...item.custom.map((c) => `${c.label} ${c.value}`)].some((h) => h.toLowerCase().includes(q));
817
815
  }
818
816
  var isAuthenticatorStorage = (key) => key === "totp_seed" || key.startsWith("totp_") || key === "authenticator_last_time_step";
819
- function siteOf(item) {
817
+ function loginSiteOf(item) {
820
818
  const raw = item.loginUrls[0];
821
819
  if (!raw) return "";
822
820
  try {
@@ -830,7 +828,7 @@ function sortItems(items, sort) {
830
828
  const byName = (a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
831
829
  if (sort === "name") return out.sort(byName);
832
830
  if (sort === "website") return out.sort((a, b) => {
833
- const x = siteOf(a), y = siteOf(b);
831
+ const x = loginSiteOf(a), y = loginSiteOf(b);
834
832
  return x && y ? x.localeCompare(y) || byName(a, b) : x ? -1 : y ? 1 : byName(a, b);
835
833
  });
836
834
  if (sort === "updated") return out.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
@@ -1222,6 +1220,7 @@ var HistoryChangedError = class extends Error {
1222
1220
  import { useEffect as useEffect6, useRef as useRef4, useState as useState6 } from "react";
1223
1221
  import { Button as Button3 } from "@ai-matrx/design-system/controls";
1224
1222
  import { cn as cn4 } from "@ai-matrx/design-system";
1223
+ import { formatAbsoluteDate } from "@ai-matrx/kit/format";
1225
1224
  import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1226
1225
  var PAGE = 50;
1227
1226
  var MAX = 500;
@@ -1258,7 +1257,7 @@ function ActivityPanel({ item, port, onClose }) {
1258
1257
  day.entries.map((entry) => ({ entry, s: auditSentence(entry, item, me) })),
1259
1258
  (r) => `${r.s.what}|${r.s.who ?? ""}`
1260
1259
  ).map(({ row: { entry, s }, times }) => {
1261
- return /* @__PURE__ */ jsxs6("div", { className: "flex min-h-9 items-center gap-1.5 px-3 text-sm sm:px-4", title: formatDate(entry.at, true), children: [
1260
+ return /* @__PURE__ */ jsxs6("div", { className: "flex min-h-9 items-center gap-1.5 px-3 text-sm sm:px-4", title: formatAbsoluteDate(entry.at, void 0, ""), children: [
1262
1261
  /* @__PURE__ */ jsx6("span", { className: cn4("truncate", s.refused ? "text-destructive" : "text-foreground"), children: s.what }),
1263
1262
  /* @__PURE__ */ jsxs6("span", { className: "shrink-0 text-muted-foreground", children: [
1264
1263
  times > 1 ? ` \xB7 ${times} times` : "",
@@ -1343,7 +1342,7 @@ function HistoryPanel({ item, port, arg, onClose, onChanged }) {
1343
1342
  page && (page.captureStartedAt || page.incomplete) ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap gap-x-3 gap-y-1 px-1 text-xs", children: [
1344
1343
  page.captureStartedAt ? /* @__PURE__ */ jsxs7("span", { className: "text-muted-foreground", children: [
1345
1344
  "Kept since ",
1346
- formatDate(page.captureStartedAt, true)
1345
+ formatAbsoluteDate2(page.captureStartedAt, void 0, "")
1347
1346
  ] }) : null,
1348
1347
  page.incomplete ? /* @__PURE__ */ jsx7("span", { className: "text-warning", children: "Some changes could not be read" }) : null
1349
1348
  ] }) : null
@@ -1356,7 +1355,7 @@ function HistoryRow({ item, port, page, entry, label, onRestored, onConflict, on
1356
1355
  const secret = useTransientSecret();
1357
1356
  const copyValue2 = useCopy();
1358
1357
  const [busy, setBusy] = useState7(false);
1359
- const when = formatDate(entry.recordedAt, true);
1358
+ const when = formatAbsoluteDate2(entry.recordedAt, void 0, "");
1360
1359
  async function read() {
1361
1360
  if (secret.value !== null) return secret.value;
1362
1361
  setBusy(true);
@@ -1518,11 +1517,11 @@ function authenticatorName(current, parsed) {
1518
1517
  if (name && !PLACEHOLDER_NAMES.includes(name.toLowerCase())) return name;
1519
1518
  return parsed.issuer || parsed.account || name || "One-time password";
1520
1519
  }
1521
- function matchIssuerToSite(issuer, candidates, siteOf2) {
1520
+ function matchIssuerToSite(issuer, candidates, siteOf) {
1522
1521
  const key = (issuer ?? "").toLowerCase().replace(/[^a-z0-9]/g, "");
1523
1522
  if (key.length < 2) return null;
1524
1523
  for (const c of candidates) {
1525
- const host = siteOf2(c).toLowerCase();
1524
+ const host = siteOf(c).toLowerCase();
1526
1525
  if (!host) continue;
1527
1526
  const labels = host.split(".");
1528
1527
  if (labels.some((l) => l.replace(/[^a-z0-9]/g, "") === key)) return c;
@@ -2143,7 +2142,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
2143
2142
  const recognise = (p) => {
2144
2143
  if (!nameTouched) setName((n) => authenticatorName(n, p));
2145
2144
  if (!targetChosen) {
2146
- const match = matchIssuerToSite(p.issuer, candidates, siteOf);
2145
+ const match = matchIssuerToSite(p.issuer, candidates, loginSiteOf);
2147
2146
  setTarget(match ? match.id : NEW);
2148
2147
  }
2149
2148
  };
@@ -2221,7 +2220,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
2221
2220
  value: target,
2222
2221
  disabled: busy || created !== null,
2223
2222
  "aria-label": "Add to",
2224
- options: [{ value: NEW, label: "New login" }, ...candidates.map((c) => ({ value: c.id, label: siteOf(c) ? `${c.name} \xB7 ${siteOf(c)}` : c.name }))],
2223
+ options: [{ value: NEW, label: "New login" }, ...candidates.map((c) => ({ value: c.id, label: loginSiteOf(c) ? `${c.name} \xB7 ${loginSiteOf(c)}` : c.name }))],
2225
2224
  onValueChange: (v) => {
2226
2225
  setTarget(v);
2227
2226
  setTargetChosen(true);
@@ -2383,7 +2382,7 @@ function OtpListRow({ port, item, family, entry, onOpen, onRename, onChanged, on
2383
2382
  const Icon = definitionGlyph(item.definitionKey, family);
2384
2383
  const canManage = item.capabilities.canManage || item.capabilities.canEdit;
2385
2384
  if (a.removed) return null;
2386
- const sub = a.error ?? [entry?.account, siteOf(item) || entry?.issuer].filter((v, i, all) => Boolean(v) && all.indexOf(v) === i).join(" \xB7 ");
2385
+ const sub = a.error ?? [entry?.account, loginSiteOf(item) || entry?.issuer].filter((v, i, all) => Boolean(v) && all.indexOf(v) === i).join(" \xB7 ");
2387
2386
  return /* @__PURE__ */ jsxs12("div", { className: "grid min-h-14 grid-cols-[2rem_minmax(0,1fr)_auto_auto] items-center gap-x-3 rounded-lg px-2 py-1.5 transition-colors hover:bg-accent/50", children: [
2388
2387
  /* @__PURE__ */ jsx12("button", { type: "button", onClick: onOpen, "aria-label": `Open ${item.name}`, tabIndex: -1, className: cn6("flex size-8 items-center justify-center rounded-lg bg-muted", a.enabled ? "text-foreground" : "text-disabled-foreground"), children: /* @__PURE__ */ jsx12(Icon, { className: "size-4" }) }),
2389
2388
  /* @__PURE__ */ jsxs12("button", { type: "button", onClick: onOpen, className: "flex min-w-0 flex-col items-start rounded-md text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [
@@ -5152,7 +5151,7 @@ var MEMBER_ACCESS_LABEL = { none: "No access", use: "Can use", editor: "Can edit
5152
5151
  function levelOf(flags) {
5153
5152
  return flags.can_manage ? "edit" : "use";
5154
5153
  }
5155
- function flagsOf(level) {
5154
+ function shareFlagsOf(level) {
5156
5155
  return { can_use: true, can_manage: level === "edit" };
5157
5156
  }
5158
5157
  function isEmail(value) {
@@ -5202,7 +5201,7 @@ var message = (e, fallback) => {
5202
5201
  const m = e instanceof Error && e.message ? e.message : fallback;
5203
5202
  return copyRefusal(m) ?? m;
5204
5203
  };
5205
- function useAction() {
5204
+ function useConfirmedChange() {
5206
5205
  const confirmed = useConfirmed();
5207
5206
  const [busy, setBusy] = useState23(null);
5208
5207
  const [error, setError] = useState23(null);
@@ -5246,7 +5245,7 @@ import { Button as Button19, Field as Field8, Select as Select7 } from "@ai-matr
5246
5245
  import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
5247
5246
  var NONE = "__none__";
5248
5247
  function MovePanel({ item, port, organizations, onClose, onChanged }) {
5249
- const { busy, error, notice, run, setNotice } = useAction();
5248
+ const { busy, error, notice, run, setNotice } = useConfirmedChange();
5250
5249
  const moves = moveDestinations(item, organizations);
5251
5250
  const copies = copyDestinations(organizations, item);
5252
5251
  const [moveTo, setMoveTo] = useState24("");
@@ -5352,7 +5351,7 @@ function useGrants(port, item) {
5352
5351
  }
5353
5352
  function SharePanel({ item, port, organizations, onClose, onChanged }) {
5354
5353
  const { grants, setGrants, loadError, reload } = useGrants(port, item);
5355
- const { busy, error, notice, run } = useAction();
5354
+ const { busy, error, notice, run } = useConfirmedChange();
5356
5355
  const [email, setEmail] = useState25("");
5357
5356
  const [level, setLevel] = useState25("use");
5358
5357
  const [more, setMore] = useState25(false);
@@ -5475,7 +5474,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
5475
5474
  );
5476
5475
  }
5477
5476
  function IntoOrganization({ item, port, organizations, grants, onShared }) {
5478
- const { busy, error, notice, run } = useAction();
5477
+ const { busy, error, notice, run } = useConfirmedChange();
5479
5478
  const open = organizations.filter((o) => !grants.some((g) => g.organizationId === o.id));
5480
5479
  const [target, setTarget] = useState25("");
5481
5480
  const [level, setLevel] = useState25("use");
@@ -5515,7 +5514,7 @@ var CHOICES = [
5515
5514
  function MemberAccess({ port, organizationId, organizationName }) {
5516
5515
  const [list, setList] = useState25(null);
5517
5516
  const [loadError, setLoadError] = useState25(null);
5518
- const { busy, error, run } = useAction();
5517
+ const { busy, error, run } = useConfirmedChange();
5519
5518
  useEffect15(() => {
5520
5519
  let live = true;
5521
5520
  port.sharing.memberAccess(organizationId).then(
@@ -5566,6 +5565,7 @@ function SharingSummary({ item, port, className }) {
5566
5565
  }
5567
5566
 
5568
5567
  // src/ItemPane.tsx
5568
+ import { formatAbsoluteDate as formatAbsoluteDate3 } from "@ai-matrx/kit/format";
5569
5569
  import { Fragment as Fragment15, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
5570
5570
  var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
5571
5571
  function ItemPane(props) {
@@ -5713,7 +5713,7 @@ function ItemPane(props) {
5713
5713
  const descriptionVisible = showDescription || draft.description !== "";
5714
5714
  const header = /* @__PURE__ */ jsxs24("header", { className: "flex min-h-14 items-center gap-2 border-b border-border px-3 py-2 sm:gap-3 sm:px-5", children: [
5715
5715
  onBack ? /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(ChevronLeftGlyph, {}), "aria-label": "Back", onClick: mode === "new" ? onCancelNew : onBack }) : null,
5716
- /* @__PURE__ */ jsx26(ItemIcon, { definitionKey: definition?.key ?? item?.definitionKey ?? "custom", family: definition?.family ?? "generic", site: item ? siteOf(item) : siteOf({ loginUrls: draft.loginUrls }), size: "lg" }),
5716
+ /* @__PURE__ */ jsx26(ItemIcon, { definitionKey: definition?.key ?? item?.definitionKey ?? "custom", family: definition?.family ?? "generic", site: item ? loginSiteOf(item) : loginSiteOf({ loginUrls: draft.loginUrls }), size: "lg" }),
5717
5717
  /* @__PURE__ */ jsxs24("div", { className: "flex min-w-0 flex-1 flex-col", children: [
5718
5718
  /* @__PURE__ */ jsx26("h2", { className: "truncate text-base font-semibold leading-tight", children: editing ? draft.name || (mode === "new" ? `New ${typeLabel.toLowerCase()}` : item?.name) : item?.name }),
5719
5719
  /* @__PURE__ */ jsxs24("span", { className: "flex min-w-0 items-center gap-1 text-xs text-muted-foreground", children: [
@@ -5946,9 +5946,9 @@ function ItemPane(props) {
5946
5946
  filesProps ? /* @__PURE__ */ jsx26(FilesSection, { ...filesProps, editing: false }) : null,
5947
5947
  /* @__PURE__ */ jsxs24("p", { className: cn12("px-1 text-xs text-muted-foreground"), children: [
5948
5948
  "Modified ",
5949
- formatDate(item.updatedAt),
5949
+ formatAbsoluteDate3(item.updatedAt, DAY_FORMAT, ""),
5950
5950
  " \xB7 Created ",
5951
- formatDate(item.createdAt)
5951
+ formatAbsoluteDate3(item.createdAt, DAY_FORMAT, "")
5952
5952
  ] })
5953
5953
  ] }) : null }) })
5954
5954
  ] }) });
@@ -5963,7 +5963,7 @@ var SORTS2 = [
5963
5963
  { value: "created", label: "Recently added" }
5964
5964
  ];
5965
5965
  function subtitleOf(item, withOwner) {
5966
- const what = siteOf(item) || item.definitionLabel;
5966
+ const what = loginSiteOf(item) || item.definitionLabel;
5967
5967
  return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
5968
5968
  }
5969
5969
  function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header }) {
@@ -6046,7 +6046,7 @@ function ListRow({ item, family, port, on, onSelect, withOwner }) {
6046
6046
  onClick: () => onSelect(item.id),
6047
6047
  className: cn13("flex h-12 w-full items-center gap-3 rounded-lg px-2 text-left", on ? "bg-primary text-primary-foreground" : "hover:bg-accent"),
6048
6048
  children: [
6049
- /* @__PURE__ */ jsx27(ItemIcon, { definitionKey: item.definitionKey, family, site: siteOf(item), inverted: on }),
6049
+ /* @__PURE__ */ jsx27(ItemIcon, { definitionKey: item.definitionKey, family, site: loginSiteOf(item), inverted: on }),
6050
6050
  /* @__PURE__ */ jsxs25("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
6051
6051
  /* @__PURE__ */ jsx27("span", { className: "truncate text-sm font-medium", children: item.name }),
6052
6052
  /* @__PURE__ */ jsx27("span", { className: "truncate text-xs text-muted-foreground", children: subtitleOf(item, withOwner) })
@@ -6064,6 +6064,7 @@ function ListRow({ item, family, port, on, onSelect, withOwner }) {
6064
6064
  // src/lists/TrashView.tsx
6065
6065
  import { useState as useState29 } from "react";
6066
6066
  import { Button as Button24 } from "@ai-matrx/design-system/controls";
6067
+ import { formatAbsoluteDate as formatAbsoluteDate4 } from "@ai-matrx/kit/format";
6067
6068
 
6068
6069
  // src/lists/logic.ts
6069
6070
  var ENTITY_TYPE = "credential_item";
@@ -6074,7 +6075,7 @@ function favoriteIds(data) {
6074
6075
  function recentIds(data, limit = 50) {
6075
6076
  return rowsOf(data).filter((r) => typeof r.last_viewed_at === "string" && r.last_viewed_at !== "").sort((a, b) => Date.parse(b.last_viewed_at) - Date.parse(a.last_viewed_at)).slice(0, limit).map((r) => r.entity_id);
6076
6077
  }
6077
- function matchesQuery2(item, query) {
6078
+ function trashItemMatchesQuery(item, query) {
6078
6079
  const q = query.trim().toLowerCase();
6079
6080
  if (!q) return true;
6080
6081
  return [item.name, item.definitionLabel, item.owner.label, ...item.tags].some((s) => s.toLowerCase().includes(q));
@@ -6206,7 +6207,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
6206
6207
  const confirmed = useConfirmed();
6207
6208
  const [busyId, setBusyId] = useState29(null);
6208
6209
  const [message2, setMessage] = useState29(null);
6209
- const shown = deleted.filter((i) => matchesQuery2(i, query));
6210
+ const shown = deleted.filter((i) => trashItemMatchesQuery(i, query));
6210
6211
  const [restoring, setRestoring] = useState29(null);
6211
6212
  const restore = async (item, deletionId) => {
6212
6213
  setBusyId(item.id);
@@ -6231,7 +6232,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
6231
6232
  /* @__PURE__ */ jsxs27("div", { className: "flex min-h-12 items-center gap-3 px-3 py-1.5 sm:px-4", children: [
6232
6233
  /* @__PURE__ */ jsxs27("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
6233
6234
  /* @__PURE__ */ jsx29("span", { className: "truncate text-sm text-foreground", children: item.name }),
6234
- /* @__PURE__ */ jsx29("span", { className: "truncate text-xs text-muted-foreground", children: [item.deletion?.deletedAt ? `Deleted ${formatDate(item.deletion.deletedAt)}` : null, item.owner.kind !== "me" ? item.owner.label : null].filter(Boolean).join(" \xB7 ") })
6235
+ /* @__PURE__ */ jsx29("span", { className: "truncate text-xs text-muted-foreground", children: [item.deletion?.deletedAt ? `Deleted ${formatAbsoluteDate4(item.deletion.deletedAt, DAY_FORMAT, "")}` : null, item.owner.kind !== "me" ? item.owner.label : null].filter(Boolean).join(" \xB7 ") })
6235
6236
  ] }),
6236
6237
  /* @__PURE__ */ jsx29(Button24, { variant: "outline", icon: /* @__PURE__ */ jsx29(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
6237
6238
  ] }, item.id)
@@ -6318,6 +6319,7 @@ import { useEffect as useEffect19, useRef as useRef16, useState as useState31 }
6318
6319
  import { confirm as confirm10 } from "@ai-matrx/kit/confirm-opener";
6319
6320
  import { Checkbox as Checkbox2 } from "@ai-matrx/design-system";
6320
6321
  import { Badge as Badge8, Button as Button26, Field as Field11, RegionSkeleton as RegionSkeleton2, SegmentedControl as SegmentedControl5, Textarea as Textarea4 } from "@ai-matrx/design-system/controls";
6322
+ import { formatAbsoluteDate as formatAbsoluteDate5 } from "@ai-matrx/kit/format";
6321
6323
 
6322
6324
  // src/sharing/secure-link-logic.ts
6323
6325
  import { formatDurationMinutes } from "@ai-matrx/kit/format";
@@ -6395,7 +6397,7 @@ function sortSent(rows) {
6395
6397
  import { jsx as jsx31, jsxs as jsxs29 } from "react/jsx-runtime";
6396
6398
  function SecureLinkPanel({ item, port, onClose }) {
6397
6399
  const sharing = port.sharing;
6398
- const { busy, error, notice, run, setNotice } = useAction();
6400
+ const { busy, error, notice, run, setNotice } = useConfirmedChange();
6399
6401
  const [remedy, setRemedy] = useState31(null);
6400
6402
  const [options, setOptions] = useState31(null);
6401
6403
  const [optionsError, setOptionsError] = useState31(null);
@@ -6587,7 +6589,7 @@ function SecureLinkPanel({ item, port, onClose }) {
6587
6589
  );
6588
6590
  }
6589
6591
  function sentMeta(row, options) {
6590
- const when = row.status === "pending" ? `Until ${formatDate(row.expiresAt, true)}` : row.status === "viewed" && row.viewedAt ? formatDate(row.viewedAt, true) : formatDate(row.createdAt);
6592
+ const when = row.status === "pending" ? `Until ${formatAbsoluteDate5(row.expiresAt, void 0, "")}` : row.status === "viewed" && row.viewedAt ? formatAbsoluteDate5(row.viewedAt, void 0, "") : formatAbsoluteDate5(row.createdAt, DAY_FORMAT, "");
6591
6593
  const carried = row.fieldKeys.length ? carriedWords(row.fieldKeys, options?.fields ?? []) : "";
6592
6594
  return [when, carried].filter(Boolean).join(" \xB7 ");
6593
6595
  }
@@ -6596,6 +6598,7 @@ function sentMeta(row, options) {
6596
6598
  import { useCallback as useCallback4, useEffect as useEffect20, useState as useState32 } from "react";
6597
6599
  import { confirm as confirm11 } from "@ai-matrx/kit/confirm-opener";
6598
6600
  import { Button as Button27, RegionSkeleton as RegionSkeleton3 } from "@ai-matrx/design-system/controls";
6601
+ import { formatAbsoluteDate as formatAbsoluteDate6 } from "@ai-matrx/kit/format";
6599
6602
 
6600
6603
  // src/devices/logic.ts
6601
6604
  var PASSKEY_RP_ID = "aimatrx.com";
@@ -6725,13 +6728,13 @@ function DevicesPanel({ port, onClose }) {
6725
6728
  Row,
6726
6729
  {
6727
6730
  label: off ? "Turned off" : "Can fill",
6728
- hint: off ? formatDate(device.revokedAt) : void 0,
6731
+ hint: off ? formatAbsoluteDate6(device.revokedAt, DAY_FORMAT, "") : void 0,
6729
6732
  actions: off ? null : /* @__PURE__ */ jsx32(Button27, { variant: "outline", icon: /* @__PURE__ */ jsx32(PowerGlyph, {}), disabled: busyId !== null, onClick: () => void revoke(device), children: "Revoke" }),
6730
6733
  children: /* @__PURE__ */ jsxs30("span", { className: "flex min-w-0 flex-col", children: [
6731
6734
  /* @__PURE__ */ jsx32("span", { className: off ? "truncate text-muted-foreground" : "truncate text-foreground", children: device.label }),
6732
6735
  /* @__PURE__ */ jsxs30("span", { className: "truncate text-xs text-muted-foreground", children: [
6733
- device.lastUsedAt ? `Last used ${formatDate(device.lastUsedAt, true)}` : "Never used",
6734
- device.addedAt ? ` \xB7 added ${formatDate(device.addedAt)}` : ""
6736
+ device.lastUsedAt ? `Last used ${formatAbsoluteDate6(device.lastUsedAt, void 0, "")}` : "Never used",
6737
+ device.addedAt ? ` \xB7 added ${formatAbsoluteDate6(device.addedAt, DAY_FORMAT, "")}` : ""
6735
6738
  ] })
6736
6739
  ] })
6737
6740
  },
@@ -6825,7 +6828,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
6825
6828
  "Return to ",
6826
6829
  where,
6827
6830
  " by ",
6828
- formatDate(approvedUntil, true),
6831
+ formatAbsoluteDate6(approvedUntil, void 0, ""),
6829
6832
  "."
6830
6833
  ] }) }) : !passkeys ? /* @__PURE__ */ jsxs30(Empty, { children: [
6831
6834
  "Approve with your password in ",
@@ -7516,10 +7519,10 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
7516
7519
  setReading(false);
7517
7520
  }
7518
7521
  };
7519
- const subtitle = [item ? siteOf(item) || item.definitionLabel : "", tag].filter(Boolean).join(" \xB7 ");
7522
+ const subtitle = [item ? loginSiteOf(item) || item.definitionLabel : "", tag].filter(Boolean).join(" \xB7 ");
7520
7523
  return /* @__PURE__ */ jsxs35("li", { className: "flex h-12 items-center gap-1 pl-1 pr-2", "data-item": itemId, children: [
7521
7524
  /* @__PURE__ */ jsxs35("button", { type: "button", onClick: () => onOpen(itemId), className: "flex h-11 min-w-0 flex-1 items-center gap-3 rounded-lg px-2 text-left hover:bg-accent", children: [
7522
- /* @__PURE__ */ jsx37(ItemIcon, { definitionKey: item?.definitionKey ?? "website_login", family, site: item ? siteOf(item) : "" }),
7525
+ /* @__PURE__ */ jsx37(ItemIcon, { definitionKey: item?.definitionKey ?? "website_login", family, site: item ? loginSiteOf(item) : "" }),
7523
7526
  /* @__PURE__ */ jsxs35("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
7524
7527
  /* @__PURE__ */ jsx37("span", { className: "truncate text-sm font-medium", children: item?.name ?? "Saved login" }),
7525
7528
  subtitle ? /* @__PURE__ */ jsx37("span", { className: "truncate text-xs text-muted-foreground", children: subtitle }) : null
@@ -8502,7 +8505,7 @@ function createSharingPort(ctx, options = {}) {
8502
8505
  return r.grants.map(grantOf);
8503
8506
  },
8504
8507
  async addPerson(item, email, level) {
8505
- const w = await account6.addGrant(api, { path: { item_id: item.id }, body: { recipient_email: email.trim(), ...flagsOf(level), initiation: "user" } }, ctx.optsFor(item));
8508
+ const w = await account6.addGrant(api, { path: { item_id: item.id }, body: { recipient_email: email.trim(), ...shareFlagsOf(level), initiation: "user" } }, ctx.optsFor(item));
8506
8509
  return grantOf(w);
8507
8510
  },
8508
8511
  async addOrganization(item, organizationId, level) {
@@ -8510,14 +8513,14 @@ function createSharingPort(ctx, options = {}) {
8510
8513
  return grantOf(w);
8511
8514
  },
8512
8515
  async setLevel(item, grant, level) {
8513
- const w = await account6.updateGrant(api, { path: { item_id: item.id, grant_id: grant.id }, body: { ...flagsOf(level), initiation: "user" } }, ctx.optsFor(item));
8516
+ const w = await account6.updateGrant(api, { path: { item_id: item.id, grant_id: grant.id }, body: { ...shareFlagsOf(level), initiation: "user" } }, ctx.optsFor(item));
8514
8517
  return grantOf(w);
8515
8518
  },
8516
8519
  async revoke(item, grant) {
8517
8520
  await account6.removeGrant(api, { path: { item_id: item.id, grant_id: grant.id } }, ctx.optsFor(item));
8518
8521
  },
8519
8522
  async setAccessMode(item, mode, people) {
8520
- const grantees = mode === "restricted" ? people.filter((g) => g.kind === "person" && g.userId).map((g) => ({ user_id: g.userId, ...flagsOf(g.level) })) : [];
8523
+ const grantees = mode === "restricted" ? people.filter((g) => g.kind === "person" && g.userId).map((g) => ({ user_id: g.userId, ...shareFlagsOf(g.level) })) : [];
8521
8524
  await account6.share(api, { path: { item_id: item.id }, body: { access_mode: mode, grantees, initiation: "user" } }, ctx.optsFor(item));
8522
8525
  return ctx.refetch(item.id, item.owner);
8523
8526
  },
@@ -8932,10 +8935,10 @@ export {
8932
8935
  inferFromUrl,
8933
8936
  locationFromParams,
8934
8937
  locationToParams,
8938
+ loginSiteOf,
8935
8939
  matchesQuery,
8936
8940
  needsRecentSignIn,
8937
8941
  parseDefinitions,
8938
- siteOf,
8939
8942
  sortItems
8940
8943
  };
8941
8944
  //# sourceMappingURL=index.js.map