managarten/packages/shared-privacy/src/index.ts
Till JS 5501f472ae feat(shared-privacy): M8.2 — unlisted-client + SharedLinkControls
Second milestone of the unlisted-share rollout. Backend endpoints
from M8.1 are now callable from the client, and a reusable
SharedLinkControls component is available for the detail views that
wire up in M8.3/M8.4.

Scope: shared primitives only. No module store integrates them yet —
that's the next step per module.

Changes:
- @mana/shared-privacy/unlisted-client.ts:
    publishUnlistedSnapshot(opts) → { token, url }
      Idempotent per (collection, recordId) — server reuses token on
      re-publish, so store code can call on every edit without caring
      whether it's first publish or refresh.
    revokeUnlistedSnapshot(opts)
      Idempotent — resolves silently even on { revoked: 0 }.
    buildShareUrl(origin, token)
      Convenience for UIs that already know the token.
    UnlistedApiError
      Thrown on non-2xx. Carries { status, code } so callers can
      distinguish 400 COLLECTION_NOT_ALLOWED vs 410 REVOKED vs
      500 UNKNOWN.
- @mana/shared-privacy/SharedLinkControls.svelte:
    Dumb presentational component. Props: token, url, expiresAt,
    onRegenerate, onRevoke, onExpiryChange (optional), disabled.
    Renders URL + copy, regenerate with confirm dialog, revoke,
    optional datetime-local expiry picker, debug token fingerprint.
    Clipboard-API fallback to prompt() for unsecure origins.
    QR-code button deferred to M8.5 polish.
- Exports added to index.ts: functions, error class, both types,
  SharedLinkControls component.
- 10 new unit tests (25 total): publish URL shape, headers, body,
  expiresAt serialisation, 4xx/5xx handling, trailing-slash
  trimming on apiUrl, revoke idempotence, buildShareUrl join.

Verified:
- pnpm --filter @mana/shared-privacy test: 25/25 green
- pnpm --filter @mana/shared-privacy check: 0 errors
- pnpm --filter @mana/web check: 7531 files, 0 errors

Next: M8.3 — wire Calendar through the new client.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 17:18:56 +02:00

46 lines
1.5 KiB
TypeScript

/**
* @mana/shared-privacy
*
* Unified visibility/privacy primitives for every Mana module. Provides:
*
* - VisibilityLevel enum: 'private' | 'space' | 'unlisted' | 'public'
* - Zod schema for validation at the record/schema layer
* - Default helper (derives private vs space from the active space type)
* - Predicates for publish-time gating (canEmbedOnWebsite, …)
* - Unlisted-token generator (32-char base64url, CSPRNG)
* - <VisibilityPicker> Svelte component for the consistent UI control
*
* Design + rollout: docs/plans/visibility-system.md.
*
* Import path stays flat:
* import {
* VisibilityLevelSchema,
* canEmbedOnWebsite,
* VisibilityPicker,
* } from '@mana/shared-privacy';
*/
export type { VisibilityLevel, VisibilityMeta, VisibilityChangedPayload } from './types';
export { VISIBILITY_LEVELS, VISIBILITY_METADATA } from './types';
export { VisibilityLevelSchema, UnlistedTokenSchema } from './schema';
export { defaultVisibilityFor } from './defaults';
export {
canEmbedOnWebsite,
isReachableByLink,
isVisibleToSpaceMember,
canAiAccessCrossUser,
} from './predicates';
export { generateUnlistedToken } from './tokens';
export {
publishUnlistedSnapshot,
revokeUnlistedSnapshot,
buildShareUrl,
UnlistedApiError,
type PublishUnlistedOptions,
type PublishUnlistedResult,
type RevokeUnlistedOptions,
} from './unlisted-client';
export { default as VisibilityPicker } from './VisibilityPicker.svelte';
export { default as SharedLinkControls } from './SharedLinkControls.svelte';