@openrails/contentkit-ui 0.73.0 → 0.75.0

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.
Files changed (47) hide show
  1. package/README.md +28 -0
  2. package/dist/client/client.d.ts +3 -0
  3. package/dist/client/client.js +20 -18
  4. package/dist/client/client.js.map +1 -1
  5. package/dist/client/generated/routes.d.ts +66 -1
  6. package/dist/client/generated/routes.js +85 -0
  7. package/dist/client/generated/routes.js.map +1 -1
  8. package/dist/client/generated/wire.d.ts +30 -0
  9. package/dist/client/generated/wire.js.map +1 -1
  10. package/dist/client/http.d.ts +8 -1
  11. package/dist/client/http.js.map +1 -1
  12. package/dist/client/index.d.ts +1 -0
  13. package/dist/client/notifications.d.ts +23 -0
  14. package/dist/client/notifications.js +46 -0
  15. package/dist/client/notifications.js.map +1 -0
  16. package/dist/client.js +4 -3
  17. package/dist/components/notifications.d.ts +28 -0
  18. package/dist/components/notifications.js +222 -0
  19. package/dist/components/notifications.js.map +1 -0
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.js +3 -2
  22. package/dist/locales/en.d.ts +23 -0
  23. package/dist/locales/social/de.js +23 -0
  24. package/dist/locales/social/de.js.map +1 -1
  25. package/dist/locales/social/en.d.ts +23 -0
  26. package/dist/locales/social/en.js +23 -0
  27. package/dist/locales/social/en.js.map +1 -1
  28. package/dist/locales/social/es.js +23 -0
  29. package/dist/locales/social/es.js.map +1 -1
  30. package/dist/locales/social/ja.js +23 -0
  31. package/dist/locales/social/ja.js.map +1 -1
  32. package/dist/locales/social/ko.js +23 -0
  33. package/dist/locales/social/ko.js.map +1 -1
  34. package/dist/locales/social/zh.js +23 -0
  35. package/dist/locales/social/zh.js.map +1 -1
  36. package/dist/react/context.d.ts +1 -1
  37. package/dist/react/context.js.map +1 -1
  38. package/dist/react/index.d.ts +1 -0
  39. package/dist/react/notifications.d.ts +29 -0
  40. package/dist/react/notifications.js +56 -0
  41. package/dist/react/notifications.js.map +1 -0
  42. package/dist/react/resources.d.ts +1 -0
  43. package/dist/react/resources.js +26 -0
  44. package/dist/react/resources.js.map +1 -1
  45. package/dist/react.js +4 -3
  46. package/dist/styles.css +1 -1
  47. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"wire.js","names":[],"sources":["../../../src/client/generated/wire.ts"],"sourcesContent":["// Generated by `go generate ./internal/contract` from ContentKit's route catalog. Do not edit.\n\nimport type { ErrorCode } from \"./error-codes.js\";\n\nexport type { ErrorCode };\n\n// Upload sizes: one PUT up to MAX_SINGLE_PUT bytes, else multipart parts.\nexport const MAX_SINGLE_PUT = 67108864;\nexport const MIN_PART_SIZE = 8388608;\nexport const MAX_PART_SIZE = 16777216;\n\nexport type OpName = \"put\" | \"edit\" | \"move\" | \"rename\" | \"remove\" | \"attach\" | \"copy\" | \"frame\" | \"meta\" | \"regenerate\";\nexport type Access = \"full\" | \"none\";\nexport type ItemState = \"ready\" | \"processing\" | \"failed\";\nexport type EncodePhase = \"queued\" | \"downloading\" | \"probing\" | \"encoding\" | \"muxing\" | \"uploading\" | \"publishing\" | \"images\";\nexport type PollKind = \"multiple_choice\" | \"free_text\";\nexport type ModerationState = \"approved\" | \"held\" | \"rejected\";\n\nexport interface AdminComment {\n id: string;\n reply_to_id?: string;\n user_id?: string;\n anon_name?: string;\n body: string;\n deleted: boolean;\n likes: number;\n dislikes: number;\n mine: number;\n reply_count: number;\n author?: PublicUser;\n moderation?: ModerationState;\n moderation_reason?: string;\n created_at: string;\n updated_at: string;\n tenant_id: string;\n content_kind: string;\n content_id: string;\n content_version_id?: string;\n deleted_at?: string;\n}\n\nexport interface Anonymous {\n comments: boolean;\n reactions: boolean;\n votes: boolean;\n}\n\nexport interface Assignment {\n tenant_id: string;\n content_kind: string;\n content_id: string;\n content_version_id?: string;\n taxonomy_id: string;\n relation: string;\n state?: \"active\" | \"proposed\";\n source_revision: number;\n}\n\nexport interface AssignmentPage {\n assignments: Assignment[];\n next_cursor?: string;\n}\n\nexport interface AssignmentsWritten {\n assignments: number;\n}\n\nexport interface BanInput {\n reason?: string;\n until?: string;\n}\n\nexport interface BanNotice {\n scope: string;\n reason?: string;\n until?: string;\n}\n\nexport interface Comment {\n id: string;\n reply_to_id?: string;\n user_id?: string;\n anon_name?: string;\n body: string;\n deleted: boolean;\n likes: number;\n dislikes: number;\n mine: number;\n reply_count: number;\n author?: PublicUser;\n moderation?: ModerationState;\n moderation_reason?: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface CommentBan {\n user_id: string;\n user?: PublicUser;\n scope: string;\n reason?: string;\n until?: string;\n banned_by: string;\n banned_at: string;\n expired: boolean;\n}\n\nexport interface CommentEdit {\n body: string;\n}\n\nexport interface CommentInput {\n body: string;\n reply_to_id?: string;\n anon_name?: string;\n}\n\nexport interface CommentStanding {\n can_comment: boolean;\n ban?: BanNotice;\n anonymous: boolean;\n max_length: number;\n user_id?: string;\n moderate: boolean;\n ban_scopes: (\"global\" | \"owner\")[];\n}\n\nexport interface CommitBody {\n ref: RefBody;\n operation_id: string;\n ops: Op[];\n}\n\nexport interface CommitReply {\n files: FileInfo[];\n}\n\nexport interface CompleteReply {\n blob: string;\n type: string;\n size: number;\n}\n\nexport interface Config {\n anonymous: Anonymous;\n comment_max_length: number;\n}\n\nexport interface ContentRef {\n tenant_id: string;\n content_kind: string;\n content_id: string;\n content_version_id?: string;\n}\n\nexport interface CopyFrom {\n id: string;\n path: string;\n}\n\nexport interface Count {\n content_kind: string;\n language: string;\n count: number;\n}\n\nexport interface CountsRebuilt {\n nodes: number;\n}\n\nexport interface Crop {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface Edge {\n from_taxonomy_id: string;\n relation: \"alias_of\" | \"artist_of\" | \"child\" | \"member_of\" | \"parent\" | \"synonym\" | \"voice_of\";\n to_taxonomy_id: string;\n source_revision: number;\n}\n\nexport interface EdgesWritten {\n edges: number;\n}\n\nexport interface Edit {\n crop?: Crop;\n rotate?: number;\n}\n\nexport interface EffectiveTag {\n taxonomy_id: string;\n kind: string;\n slug: string;\n relation: string;\n scope: \"content\" | \"version\";\n}\n\nexport interface EffectiveTagsOf {\n content: ContentRef;\n tags: EffectiveTag[];\n}\n\nexport interface EncodeProgress {\n phase: EncodePhase;\n queue_position?: number;\n segments_done?: number;\n segments_total?: number;\n percent: number;\n speed?: number;\n eta?: number;\n at: number;\n stalled?: boolean;\n stage?: number;\n stages?: number;\n}\n\nexport interface ErrorDetails {\n width?: number;\n height?: number;\n min_width?: number;\n max_pixels?: number;\n type?: string;\n allowed?: string[];\n size?: number;\n max_bytes?: number;\n frames?: number;\n max_frames?: number;\n seconds?: number;\n max_seconds?: number;\n min_aspect?: number;\n max_aspect?: number;\n max?: number;\n}\n\nexport interface ErrorReply {\n error: string;\n code: ErrorCode;\n retry_after?: number;\n action?: \"comment\" | \"comment_reaction\" | \"favorite\" | \"poll_vote\" | \"post_reaction\" | \"reaction\";\n ban?: BanNotice;\n blobs?: string[];\n details?: ErrorDetails;\n}\n\nexport interface Failure {\n of: string;\n message: string;\n code?: ErrorCode;\n details?: ErrorDetails;\n}\n\nexport interface FavoriteItem {\n tenant_id: string;\n content_kind: string;\n content_id: string;\n content_version_id?: string;\n created_at: string;\n}\n\nexport interface FavoriteState {\n favorited: boolean;\n count: number;\n}\n\nexport interface FeedItem {\n id: string;\n reply_to_id?: string;\n user_id?: string;\n anon_name?: string;\n body: string;\n deleted: boolean;\n likes: number;\n dislikes: number;\n mine: number;\n reply_count: number;\n author?: PublicUser;\n moderation?: ModerationState;\n moderation_reason?: string;\n created_at: string;\n updated_at: string;\n tenant_id: string;\n content_kind: string;\n content_id: string;\n content_version_id?: string;\n}\n\nexport interface FileInfo {\n path: string;\n type: string;\n size?: number;\n w?: number;\n h?: number;\n dur?: number;\n download?: string;\n url?: string;\n locked?: boolean;\n upload?: boolean;\n staged?: boolean;\n from?: string;\n edit?: Edit;\n frame?: Frame;\n meta?: Record<string, unknown>;\n unattached?: boolean;\n pending?: string[];\n failed?: Failure;\n editor_url?: string;\n progress?: EncodeProgress;\n}\n\nexport interface Frame {\n t?: number;\n auto?: boolean;\n of?: string;\n}\n\nexport interface Group {\n id: string;\n label: string;\n count: number;\n}\n\nexport interface HeldItem {\n kind: string;\n revision: number;\n id: string;\n ref: ContentRef;\n author_id?: string;\n author?: PublicUser;\n anon_name?: string;\n title?: string;\n body: string;\n reason: string;\n model?: string;\n prompt_version?: string;\n confidence?: number;\n error?: string;\n held_at: string;\n created_at: string;\n}\n\nexport interface HeldPage {\n items: HeldItem[];\n next?: string;\n}\n\nexport interface ImageInput {\n image?: string;\n}\n\nexport interface InlineImage {\n ref: string;\n url: string | null;\n}\n\nexport interface MergeInput {\n into_taxonomy_id: string;\n}\n\nexport interface MergeReport {\n from_taxonomy_id: string;\n into_taxonomy_id: string;\n assignments_moved: number;\n names_moved: number;\n edges_rewritten: number;\n assignments_merged: number;\n}\n\nexport interface MultipartReply {\n ticket: string;\n min_part_size: number;\n max_part_size: number;\n max_parts: number;\n}\n\nexport interface Name {\n language: string;\n kind: \"alias\" | \"name\";\n name: string;\n normalized?: string;\n source_revision: number;\n}\n\nexport interface Node {\n taxonomy_id: string;\n tenant_id: string;\n kind: string;\n slug: string;\n state: \"active\" | \"deleted\" | \"merged\";\n source_revision: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface NodeDetail {\n taxonomy_id: string;\n tenant_id: string;\n kind: string;\n slug: string;\n state: \"active\" | \"deleted\" | \"merged\";\n source_revision: number;\n created_at: string;\n updated_at: string;\n names: Name[];\n edges: Edge[];\n counts: Count[];\n}\n\nexport interface NodeInput {\n taxonomy_id?: string;\n kind: string;\n slug: string;\n names?: Name[];\n source_revision: number;\n}\n\nexport interface NodePage {\n nodes: NodeRow[];\n next_cursor?: string;\n total: number;\n}\n\nexport interface NodeRow {\n taxonomy_id: string;\n tenant_id: string;\n kind: string;\n slug: string;\n state: \"active\" | \"deleted\" | \"merged\";\n source_revision: number;\n created_at: string;\n updated_at: string;\n name?: string;\n name_language?: string;\n count: number;\n}\n\nexport interface NodeUpdate {\n slug?: string;\n state?: \"active\" | \"deleted\" | \"merged\";\n source_revision?: number;\n}\n\nexport interface Op {\n op: OpName;\n path?: string;\n blob?: string;\n create_id?: string;\n index?: number;\n meta?: Record<string, unknown>;\n edit?: Edit;\n unattached?: boolean;\n to?: string;\n from?: CopyFrom;\n t?: number;\n auto?: boolean;\n preset?: string;\n force?: boolean;\n takedown?: boolean;\n}\n\nexport interface PartBody {\n number: number;\n size: number;\n sha256: string;\n}\n\nexport interface PartReply {\n number: number;\n size?: number;\n sha256?: string;\n request?: RequestReply;\n}\n\nexport interface PartsBody {\n ticket: string;\n parts: PartBody[];\n}\n\nexport interface PartsReply {\n parts: PartReply[];\n}\n\nexport interface Poll {\n id: string;\n kind: PollKind;\n question: string;\n language: string;\n is_active: boolean;\n image_url?: string;\n live_at: string;\n closes_at?: string;\n closed: boolean;\n total_votes: number;\n options: PollOption[];\n voted: boolean;\n my_option?: string;\n answer_count?: number;\n groups?: Group[];\n my_answer?: PollAnswer;\n}\n\nexport interface PollAnswer {\n id: string;\n text: string;\n classified: boolean;\n updated_at: string;\n}\n\nexport interface PollAnswerInput {\n text: string;\n}\n\nexport interface PollImage {\n image_url: string | null;\n}\n\nexport interface PollInput {\n kind?: PollKind;\n question: string;\n language: string;\n live_at?: string;\n closes_at?: string;\n options?: PollOptionInput[];\n}\n\nexport interface PollOption {\n id: string;\n label: string;\n image_url?: string;\n position: number;\n vote_count: number;\n}\n\nexport interface PollOptionInput {\n label: string;\n position: number;\n}\n\nexport interface PollOptionPatch {\n label?: string;\n position?: number;\n}\n\nexport interface PollUpdate {\n question?: string;\n is_active?: boolean;\n live_at?: string;\n closes_at?: string | null;\n}\n\nexport interface PollVote {\n option_id: string;\n}\n\nexport interface Post {\n id: string;\n author_id: string;\n title: string;\n slug?: string;\n body: string;\n excerpt?: string;\n cover?: string;\n cover_url?: string;\n images?: Record<string, string>;\n language: string;\n is_draft: boolean;\n live_at?: string;\n total_likes: number;\n total_dislikes: number;\n comment_count: number;\n moderation?: ModerationState;\n moderation_reason?: string;\n code: string;\n url_slug: string;\n created_at: string;\n updated_at: string;\n deleted_at?: string;\n}\n\nexport interface PostCover {\n cover_url: string | null;\n}\n\nexport interface PostInput {\n title?: string;\n body?: string;\n excerpt?: string;\n language?: string;\n slug?: string;\n is_draft?: boolean;\n live_at?: string;\n}\n\nexport interface PresetRule {\n kind: string;\n name: string;\n from: string;\n base: string;\n namespace: string;\n to: string;\n widths: number[];\n aspect?: string;\n min_width?: number;\n first?: number;\n default: boolean;\n}\n\nexport interface PresignBody {\n ref: RefBody;\n path: string;\n type: string;\n size: number;\n sha256: string;\n}\n\nexport interface PresignReply {\n path: string;\n blob: string;\n exists?: boolean;\n put?: RequestReply;\n multipart?: MultipartReply;\n process_on_upload?: boolean;\n}\n\nexport interface PublicImage {\n from: string;\n preset: string;\n renditions: PublicRendition[];\n}\n\nexport interface PublicRendition {\n url: string;\n w: number;\n h: number;\n}\n\nexport interface PublicUser {\n id: string;\n name?: string;\n username: string;\n avatar?: string;\n avatar_srcset?: string;\n}\n\nexport interface ReactionCounts {\n likes: number;\n dislikes: number;\n mine: number;\n}\n\nexport interface ReadResult {\n access: Access;\n expires: number;\n meta?: Record<string, unknown>;\n previews?: string[];\n public?: PublicImage[];\n total: number;\n offset: number;\n limit: number;\n hls?: string[];\n state?: ItemState;\n full?: boolean;\n uploads?: UploadRule[];\n files: FileInfo[];\n}\n\nexport interface RefBody {\n kind: string;\n id: string;\n}\n\nexport interface RequestReply {\n method: string;\n url: string;\n headers: Record<string, string>;\n expires: string;\n}\n\nexport interface ResolveInput {\n decision: \"approve\" | \"reject\" | \"review\";\n revision: number;\n reason?: string;\n}\n\nexport interface Resolved {\n tenant_id: string;\n content_kind: string;\n content_id: string;\n content_version_id?: string;\n code: string;\n slug: string;\n slugs?: Record<string, string>;\n path: string;\n}\n\nexport interface Restored {\n restored: boolean;\n}\n\nexport interface ReviewOutcome {\n decision: \"approve\" | \"reject\" | \"review\";\n}\n\nexport interface TicketBody {\n ticket: string;\n}\n\nexport interface UploadRule {\n path: string;\n types: string[];\n max_bytes: number;\n max?: number;\n named?: boolean;\n frames?: string;\n aspect?: string;\n min_width?: number;\n video?: VideoLimits;\n min_aspect?: number;\n max_aspect?: number;\n}\n\nexport interface VideoLimits {\n max_seconds?: number;\n max_fps?: number;\n max_pixels?: number;\n max_work?: number;\n}\n"],"mappings":";AAOA,IAAa,IAAiB,UACjB,IAAgB,SAChB,IAAgB"}
1
+ {"version":3,"file":"wire.js","names":[],"sources":["../../../src/client/generated/wire.ts"],"sourcesContent":["// Generated by `go generate ./internal/contract` from ContentKit's route catalog. Do not edit.\n\nimport type { ErrorCode } from \"./error-codes.js\";\n\nexport type { ErrorCode };\n\n// Upload sizes: one PUT up to MAX_SINGLE_PUT bytes, else multipart parts.\nexport const MAX_SINGLE_PUT = 67108864;\nexport const MIN_PART_SIZE = 8388608;\nexport const MAX_PART_SIZE = 16777216;\n\nexport type OpName = \"put\" | \"edit\" | \"move\" | \"rename\" | \"remove\" | \"attach\" | \"copy\" | \"frame\" | \"meta\" | \"regenerate\";\nexport type Access = \"full\" | \"none\";\nexport type ItemState = \"ready\" | \"processing\" | \"failed\";\nexport type EncodePhase = \"queued\" | \"downloading\" | \"probing\" | \"encoding\" | \"muxing\" | \"uploading\" | \"publishing\" | \"images\";\nexport type PollKind = \"multiple_choice\" | \"free_text\";\nexport type ModerationState = \"approved\" | \"held\" | \"rejected\";\n\nexport interface AdminComment {\n id: string;\n reply_to_id?: string;\n user_id?: string;\n anon_name?: string;\n body: string;\n deleted: boolean;\n likes: number;\n dislikes: number;\n mine: number;\n reply_count: number;\n author?: PublicUser;\n moderation?: ModerationState;\n moderation_reason?: string;\n created_at: string;\n updated_at: string;\n tenant_id: string;\n content_kind: string;\n content_id: string;\n content_version_id?: string;\n deleted_at?: string;\n}\n\nexport interface Anonymous {\n comments: boolean;\n reactions: boolean;\n votes: boolean;\n}\n\nexport interface Assignment {\n tenant_id: string;\n content_kind: string;\n content_id: string;\n content_version_id?: string;\n taxonomy_id: string;\n relation: string;\n state?: \"active\" | \"proposed\";\n source_revision: number;\n}\n\nexport interface AssignmentPage {\n assignments: Assignment[];\n next_cursor?: string;\n}\n\nexport interface AssignmentsWritten {\n assignments: number;\n}\n\nexport interface BanInput {\n reason?: string;\n until?: string;\n}\n\nexport interface BanNotice {\n scope: string;\n reason?: string;\n until?: string;\n}\n\nexport interface Comment {\n id: string;\n reply_to_id?: string;\n user_id?: string;\n anon_name?: string;\n body: string;\n deleted: boolean;\n likes: number;\n dislikes: number;\n mine: number;\n reply_count: number;\n author?: PublicUser;\n moderation?: ModerationState;\n moderation_reason?: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface CommentBan {\n user_id: string;\n user?: PublicUser;\n scope: string;\n reason?: string;\n until?: string;\n banned_by: string;\n banned_at: string;\n expired: boolean;\n}\n\nexport interface CommentEdit {\n body: string;\n}\n\nexport interface CommentInput {\n body: string;\n reply_to_id?: string;\n anon_name?: string;\n}\n\nexport interface CommentStanding {\n can_comment: boolean;\n ban?: BanNotice;\n anonymous: boolean;\n max_length: number;\n user_id?: string;\n moderate: boolean;\n ban_scopes: (\"global\" | \"owner\")[];\n}\n\nexport interface CommitBody {\n ref: RefBody;\n operation_id: string;\n ops: Op[];\n}\n\nexport interface CommitReply {\n files: FileInfo[];\n}\n\nexport interface CompleteReply {\n blob: string;\n type: string;\n size: number;\n}\n\nexport interface Config {\n anonymous: Anonymous;\n comment_max_length: number;\n}\n\nexport interface ContentRef {\n tenant_id: string;\n content_kind: string;\n content_id: string;\n content_version_id?: string;\n}\n\nexport interface CopyFrom {\n id: string;\n path: string;\n}\n\nexport interface Count {\n content_kind: string;\n language: string;\n count: number;\n}\n\nexport interface CountsRebuilt {\n nodes: number;\n}\n\nexport interface Crop {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface Edge {\n from_taxonomy_id: string;\n relation: \"alias_of\" | \"artist_of\" | \"child\" | \"member_of\" | \"parent\" | \"synonym\" | \"voice_of\";\n to_taxonomy_id: string;\n source_revision: number;\n}\n\nexport interface EdgesWritten {\n edges: number;\n}\n\nexport interface Edit {\n crop?: Crop;\n rotate?: number;\n}\n\nexport interface EffectiveTag {\n taxonomy_id: string;\n kind: string;\n slug: string;\n relation: string;\n scope: \"content\" | \"version\";\n}\n\nexport interface EffectiveTagsOf {\n content: ContentRef;\n tags: EffectiveTag[];\n}\n\nexport interface EncodeProgress {\n phase: EncodePhase;\n queue_position?: number;\n segments_done?: number;\n segments_total?: number;\n percent: number;\n speed?: number;\n eta?: number;\n at: number;\n stalled?: boolean;\n stage?: number;\n stages?: number;\n}\n\nexport interface ErrorDetails {\n width?: number;\n height?: number;\n min_width?: number;\n max_pixels?: number;\n type?: string;\n allowed?: string[];\n size?: number;\n max_bytes?: number;\n frames?: number;\n max_frames?: number;\n seconds?: number;\n max_seconds?: number;\n min_aspect?: number;\n max_aspect?: number;\n max?: number;\n}\n\nexport interface ErrorReply {\n error: string;\n code: ErrorCode;\n retry_after?: number;\n action?: \"comment\" | \"comment_reaction\" | \"favorite\" | \"poll_vote\" | \"post_reaction\" | \"reaction\";\n ban?: BanNotice;\n blobs?: string[];\n details?: ErrorDetails;\n}\n\nexport interface Failure {\n of: string;\n message: string;\n code?: ErrorCode;\n details?: ErrorDetails;\n}\n\nexport interface FavoriteItem {\n tenant_id: string;\n content_kind: string;\n content_id: string;\n content_version_id?: string;\n created_at: string;\n}\n\nexport interface FavoriteState {\n favorited: boolean;\n count: number;\n}\n\nexport interface FeedItem {\n id: string;\n reply_to_id?: string;\n user_id?: string;\n anon_name?: string;\n body: string;\n deleted: boolean;\n likes: number;\n dislikes: number;\n mine: number;\n reply_count: number;\n author?: PublicUser;\n moderation?: ModerationState;\n moderation_reason?: string;\n created_at: string;\n updated_at: string;\n tenant_id: string;\n content_kind: string;\n content_id: string;\n content_version_id?: string;\n}\n\nexport interface FileInfo {\n path: string;\n type: string;\n size?: number;\n w?: number;\n h?: number;\n dur?: number;\n download?: string;\n url?: string;\n locked?: boolean;\n upload?: boolean;\n staged?: boolean;\n from?: string;\n edit?: Edit;\n frame?: Frame;\n meta?: Record<string, unknown>;\n unattached?: boolean;\n pending?: string[];\n failed?: Failure;\n editor_url?: string;\n progress?: EncodeProgress;\n}\n\nexport interface Frame {\n t?: number;\n auto?: boolean;\n of?: string;\n}\n\nexport interface Group {\n id: string;\n label: string;\n count: number;\n}\n\nexport interface HeldItem {\n kind: string;\n revision: number;\n id: string;\n ref: ContentRef;\n author_id?: string;\n author?: PublicUser;\n anon_name?: string;\n title?: string;\n body: string;\n reason: string;\n model?: string;\n prompt_version?: string;\n confidence?: number;\n error?: string;\n held_at: string;\n created_at: string;\n}\n\nexport interface HeldPage {\n items: HeldItem[];\n next?: string;\n}\n\nexport interface ImageInput {\n image?: string;\n}\n\nexport interface InlineImage {\n ref: string;\n url: string | null;\n}\n\nexport interface Item {\n id: string;\n recipient: Recipient;\n origin: Origin;\n kind: string;\n data: unknown;\n created_at: string;\n status?: string;\n action_requested?: boolean;\n severity?: string;\n read_at: string | null;\n dismissed_at: string | null;\n resolved_at: string | null;\n updated_at: string;\n revision: number;\n}\n\nexport interface MergeInput {\n into_taxonomy_id: string;\n}\n\nexport interface MergeReport {\n from_taxonomy_id: string;\n into_taxonomy_id: string;\n assignments_moved: number;\n names_moved: number;\n edges_rewritten: number;\n assignments_merged: number;\n}\n\nexport interface MultipartReply {\n ticket: string;\n min_part_size: number;\n max_part_size: number;\n max_parts: number;\n}\n\nexport interface Name {\n language: string;\n kind: \"alias\" | \"name\";\n name: string;\n normalized?: string;\n source_revision: number;\n}\n\nexport interface Node {\n taxonomy_id: string;\n tenant_id: string;\n kind: string;\n slug: string;\n state: \"active\" | \"deleted\" | \"merged\";\n source_revision: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface NodeDetail {\n taxonomy_id: string;\n tenant_id: string;\n kind: string;\n slug: string;\n state: \"active\" | \"deleted\" | \"merged\";\n source_revision: number;\n created_at: string;\n updated_at: string;\n names: Name[];\n edges: Edge[];\n counts: Count[];\n}\n\nexport interface NodeInput {\n taxonomy_id?: string;\n kind: string;\n slug: string;\n names?: Name[];\n source_revision: number;\n}\n\nexport interface NodePage {\n nodes: NodeRow[];\n next_cursor?: string;\n total: number;\n}\n\nexport interface NodeRow {\n taxonomy_id: string;\n tenant_id: string;\n kind: string;\n slug: string;\n state: \"active\" | \"deleted\" | \"merged\";\n source_revision: number;\n created_at: string;\n updated_at: string;\n name?: string;\n name_language?: string;\n count: number;\n}\n\nexport interface NodeUpdate {\n slug?: string;\n state?: \"active\" | \"deleted\" | \"merged\";\n source_revision?: number;\n}\n\nexport interface Op {\n op: OpName;\n path?: string;\n blob?: string;\n create_id?: string;\n index?: number;\n meta?: Record<string, unknown>;\n edit?: Edit;\n unattached?: boolean;\n to?: string;\n from?: CopyFrom;\n t?: number;\n auto?: boolean;\n preset?: string;\n force?: boolean;\n takedown?: boolean;\n}\n\nexport interface Origin {\n system: string;\n scope: string;\n id: string;\n subject?: string;\n}\n\nexport interface Page {\n items: Item[];\n next_cursor?: string;\n}\n\nexport interface PartBody {\n number: number;\n size: number;\n sha256: string;\n}\n\nexport interface PartReply {\n number: number;\n size?: number;\n sha256?: string;\n request?: RequestReply;\n}\n\nexport interface PartsBody {\n ticket: string;\n parts: PartBody[];\n}\n\nexport interface PartsReply {\n parts: PartReply[];\n}\n\nexport interface Poll {\n id: string;\n kind: PollKind;\n question: string;\n language: string;\n is_active: boolean;\n image_url?: string;\n live_at: string;\n closes_at?: string;\n closed: boolean;\n total_votes: number;\n options: PollOption[];\n voted: boolean;\n my_option?: string;\n answer_count?: number;\n groups?: Group[];\n my_answer?: PollAnswer;\n}\n\nexport interface PollAnswer {\n id: string;\n text: string;\n classified: boolean;\n updated_at: string;\n}\n\nexport interface PollAnswerInput {\n text: string;\n}\n\nexport interface PollImage {\n image_url: string | null;\n}\n\nexport interface PollInput {\n kind?: PollKind;\n question: string;\n language: string;\n live_at?: string;\n closes_at?: string;\n options?: PollOptionInput[];\n}\n\nexport interface PollOption {\n id: string;\n label: string;\n image_url?: string;\n position: number;\n vote_count: number;\n}\n\nexport interface PollOptionInput {\n label: string;\n position: number;\n}\n\nexport interface PollOptionPatch {\n label?: string;\n position?: number;\n}\n\nexport interface PollUpdate {\n question?: string;\n is_active?: boolean;\n live_at?: string;\n closes_at?: string | null;\n}\n\nexport interface PollVote {\n option_id: string;\n}\n\nexport interface Post {\n id: string;\n author_id: string;\n title: string;\n slug?: string;\n body: string;\n excerpt?: string;\n cover?: string;\n cover_url?: string;\n images?: Record<string, string>;\n language: string;\n is_draft: boolean;\n live_at?: string;\n total_likes: number;\n total_dislikes: number;\n comment_count: number;\n moderation?: ModerationState;\n moderation_reason?: string;\n code: string;\n url_slug: string;\n created_at: string;\n updated_at: string;\n deleted_at?: string;\n}\n\nexport interface PostCover {\n cover_url: string | null;\n}\n\nexport interface PostInput {\n title?: string;\n body?: string;\n excerpt?: string;\n language?: string;\n slug?: string;\n is_draft?: boolean;\n live_at?: string;\n}\n\nexport interface PresetRule {\n kind: string;\n name: string;\n from: string;\n base: string;\n namespace: string;\n to: string;\n widths: number[];\n aspect?: string;\n min_width?: number;\n first?: number;\n default: boolean;\n}\n\nexport interface PresignBody {\n ref: RefBody;\n path: string;\n type: string;\n size: number;\n sha256: string;\n}\n\nexport interface PresignReply {\n path: string;\n blob: string;\n exists?: boolean;\n put?: RequestReply;\n multipart?: MultipartReply;\n process_on_upload?: boolean;\n}\n\nexport interface PublicImage {\n from: string;\n preset: string;\n renditions: PublicRendition[];\n}\n\nexport interface PublicRendition {\n url: string;\n w: number;\n h: number;\n}\n\nexport interface PublicUser {\n id: string;\n name?: string;\n username: string;\n avatar?: string;\n avatar_srcset?: string;\n}\n\nexport interface ReactionCounts {\n likes: number;\n dislikes: number;\n mine: number;\n}\n\nexport interface ReadResult {\n access: Access;\n expires: number;\n meta?: Record<string, unknown>;\n previews?: string[];\n public?: PublicImage[];\n total: number;\n offset: number;\n limit: number;\n hls?: string[];\n state?: ItemState;\n full?: boolean;\n uploads?: UploadRule[];\n files: FileInfo[];\n}\n\nexport interface Recipient {\n audience: string;\n id: string;\n}\n\nexport interface RefBody {\n kind: string;\n id: string;\n}\n\nexport interface RequestReply {\n method: string;\n url: string;\n headers: Record<string, string>;\n expires: string;\n}\n\nexport interface ResolveInput {\n decision: \"approve\" | \"reject\" | \"review\";\n revision: number;\n reason?: string;\n}\n\nexport interface Resolved {\n tenant_id: string;\n content_kind: string;\n content_id: string;\n content_version_id?: string;\n code: string;\n slug: string;\n slugs?: Record<string, string>;\n path: string;\n}\n\nexport interface Restored {\n restored: boolean;\n}\n\nexport interface ReviewOutcome {\n decision: \"approve\" | \"reject\" | \"review\";\n}\n\nexport interface TicketBody {\n ticket: string;\n}\n\nexport interface UploadRule {\n path: string;\n types: string[];\n max_bytes: number;\n max?: number;\n named?: boolean;\n frames?: string;\n aspect?: string;\n min_width?: number;\n video?: VideoLimits;\n min_aspect?: number;\n max_aspect?: number;\n}\n\nexport interface VideoLimits {\n max_seconds?: number;\n max_fps?: number;\n max_pixels?: number;\n max_work?: number;\n}\n"],"mappings":";AAOA,IAAa,IAAiB,UACjB,IAAgB,SAChB,IAAgB"}
@@ -1,5 +1,5 @@
1
1
  import { ContentChange } from './content/types.js';
2
- import { FileInfo, RefBody } from './generated/wire.js';
2
+ import { FileInfo, Item, RefBody } from './generated/wire.js';
3
3
  /** A module's base URL, or one per item (a host that splits uploads by kind). */
4
4
  export type Mount = string | ((ref: RefBody) => string);
5
5
  /**
@@ -17,6 +17,8 @@ export interface ContentKitMounts {
17
17
  codes?: string;
18
18
  /** Taxonomy. Default `{baseUrl}/taxonomy`. */
19
19
  taxonomy?: string;
20
+ /** User inbox. Default `{baseUrl}/notifications`. */
21
+ notifications?: string;
20
22
  }
21
23
  export type ContentKitModule = keyof ContentKitMounts;
22
24
  /** A mutation made through the client: the host's cache-invalidation hook gets each one. */
@@ -32,6 +34,11 @@ export type ContentKitChange =
32
34
  type: "media.processed";
33
35
  ref: RefBody;
34
36
  file: FileInfo;
37
+ } | {
38
+ type: "notifications.changed";
39
+ } | {
40
+ type: "notifications.updated";
41
+ item: Item;
35
42
  } | ContentChange;
36
43
  export type TokenSource = () => string | null | undefined | Promise<string | null | undefined>;
37
44
  export interface HttpOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","names":[],"sources":["../../src/client/http.ts"],"sourcesContent":["import { ContentKitError, aborted, readContentKitError } from \"./errors.js\";\nimport type { ContentChange } from \"./content/types.js\";\nimport type { FileInfo, RefBody } from \"./generated/wire.js\";\n\n/** A module's base URL, or one per item (a host that splits uploads by kind). */\nexport type Mount = string | ((ref: RefBody) => string);\n\n/**\n * Where each module lives when the host does not serve them all under\n * baseUrl's fixed sub-paths.\n */\nexport interface ContentKitMounts {\n /** Posts, comments, reactions, favorites, polls, bans, moderation. Default baseUrl. */\n content?: string;\n /** Media reads and HLS playlists. Default `{baseUrl}/media`. */\n media?: Mount;\n /** Uploads and commits. Default `{baseUrl}/media/upload`. */\n upload?: Mount;\n /** Content-code lookup. Default `{baseUrl}/codes`. */\n codes?: string;\n /** Taxonomy. Default `{baseUrl}/taxonomy`. */\n taxonomy?: string;\n}\n\nexport type ContentKitModule = keyof ContentKitMounts;\n\n/** A mutation made through the client: the host's cache-invalidation hook gets each one. */\nexport type ContentKitChange =\n /** A commit applied; files are the item's uploads as an editor reads them, without URLs. */\n | { type: \"media.committed\"; ref: RefBody; files: FileInfo[] }\n /** An upload finished processing, as an editor read returns it. */\n | { type: \"media.processed\"; ref: RefBody; file: FileInfo }\n | ContentChange;\n\nexport type TokenSource = () => string | null | undefined | Promise<string | null | undefined>;\n\nexport interface HttpOptions {\n /** Where the host mounts ContentKit, e.g. \"/api/v1/contentkit\". */\n baseUrl: string;\n mounts?: ContentKitMounts;\n /** Transport for API calls; pass an authenticating fetch (auth-ui's authFetch). */\n fetch?: typeof fetch;\n /**\n * Bearer for API calls and for HLS playlists on the API origin (hls.js\n * loads them with XHR, not fetch). An authenticating fetch overrides it.\n */\n token?: TokenSource;\n /** Sent as Accept-Language. */\n language?: () => string | null | undefined;\n /** Extra headers per call (CSRF). */\n headers?: () => HeadersInit | Promise<HeadersInit>;\n /** Default \"same-origin\"; \"include\" also sends cookies with HLS requests. */\n credentials?: RequestCredentials;\n}\n\nexport interface RequestOptions {\n method?: string;\n body?: unknown;\n signal?: AbortSignal;\n /** Read the body as a Blob instead of JSON. */\n blob?: boolean;\n}\n\nconst trim = (u: string) => u.replace(/\\/+$/, \"\");\n\n/** The transport every module shares: mounts, auth, language, errors and change events. */\nexport class Http {\n private readonly listeners = new Set<(change: ContentKitChange, scope: string | null) => void>();\n private readScope = { key: \"{}\" };\n private readonly base: string;\n\n constructor(private readonly o: HttpOptions) {\n if (typeof o.baseUrl !== \"string\") throw new Error(\"contentkit: createContentKitClient needs baseUrl\");\n this.base = trim(o.baseUrl);\n }\n\n /** The module's base URL, without a trailing slash. */\n mount(module: ContentKitModule, ref?: RefBody): string {\n const m = this.o.mounts?.[module];\n if (typeof m === \"function\") {\n if (!ref) throw new Error(`contentkit: the ${module} mount is per item; pass a ref`);\n return trim(m(ref));\n }\n if (m !== undefined) return trim(m);\n switch (module) {\n case \"content\":\n return this.base;\n case \"media\":\n return `${this.base}/media`;\n case \"upload\":\n return `${this.base}/media/upload`;\n default:\n return `${this.base}/${module}`;\n }\n }\n\n async request<T>(url: string, { method, body, signal, blob }: RequestOptions = {}): Promise<T> {\n const f = this.o.fetch ?? fetch;\n const headers = new Headers(await this.o.headers?.());\n if (body !== undefined) headers.set(\"Content-Type\", \"application/json\");\n const token = await this.o.token?.();\n if (token && !headers.has(\"Authorization\")) headers.set(\"Authorization\", `Bearer ${token}`);\n const lang = this.o.language?.();\n if (lang) headers.set(\"Accept-Language\", lang);\n let res: Response;\n try {\n res = await f(url, {\n method: method ?? (body === undefined ? \"GET\" : \"POST\"),\n headers,\n body: body === undefined ? null : JSON.stringify(body),\n credentials: this.o.credentials ?? \"same-origin\",\n signal: signal ?? null,\n });\n } catch (err) {\n if (signal?.aborted) throw aborted(signal);\n throw new ContentKitError(\"network\", `ContentKit API ${new URL(url, \"http://x\").pathname} unreachable`, { cause: err });\n }\n if (!res.ok) throw await readContentKitError(res);\n if (blob) return (await res.blob()) as T;\n return (res.status === 204 ? undefined : await res.json()) as T;\n }\n\n /**\n * hls.js `xhrSetup`: opens the request, sends cookies when credentials is\n * \"include\", and adds the bearer only on the API's origin (never a media host).\n */\n readonly xhrSetup = async (xhr: XMLHttpRequest, url: string): Promise<void> => {\n if (!xhr.readyState) xhr.open(\"GET\", url, true);\n if (this.o.credentials === \"include\") xhr.withCredentials = true;\n if (!this.onApiOrigin(url)) return;\n const token = await this.o.token?.();\n if (token) xhr.setRequestHeader(\"Authorization\", `Bearer ${token}`);\n };\n\n setReadScope(key: string): void {\n if (key !== this.readScope.key) this.readScope = { key };\n }\n\n /** Capture before awaiting a write; null tells caches to refetch after a scope change. */\n captureChanges(): (change: ContentKitChange) => void {\n const scope = this.readScope;\n return (change) => this.emit(change, scope === this.readScope ? scope.key : null);\n }\n\n subscribe(listener: (change: ContentKitChange, scope: string | null) => void): () => void {\n this.listeners.add(listener);\n return () => void this.listeners.delete(listener);\n }\n\n private emit(change: ContentKitChange, scope: string | null): void {\n for (const l of this.listeners) {\n try {\n l(change, scope);\n } catch (e) {\n // A host listener's fault must not fail the mutation that succeeded.\n console.error(\"contentkit: change listener failed\", e);\n }\n }\n }\n\n private onApiOrigin(url: string): boolean {\n const here = typeof location === \"undefined\" ? \"http://localhost\" : location.href;\n try {\n return new URL(url, here).origin === new URL(this.base || \"/\", here).origin;\n } catch {\n return false;\n }\n }\n}\n"],"mappings":";;AA+DA,IAAM,KAAQ,MAAc,EAAE,QAAQ,QAAQ,EAAE,GAGnC,IAAb,MAAkB;CAKa;CAJ7B,4BAA6B,IAAI,IAA8D;CAC/F,YAAoB,EAAE,KAAK,KAAK;CAChC;CAEA,YAAY,GAAiC;EAC3C,IAD2B,KAAA,IAAA,GACvB,OAAO,EAAE,WAAY,UAAU,MAAU,MAAM,kDAAkD;EACrG,KAAK,OAAO,EAAK,EAAE,OAAO;CAC5B;CAGA,MAAM,GAA0B,GAAuB;EACrD,IAAM,IAAI,KAAK,EAAE,SAAS;EAC1B,IAAI,OAAO,KAAM,YAAY;GAC3B,IAAI,CAAC,GAAK,MAAU,MAAM,mBAAmB,EAAO,+BAA+B;GACnF,OAAO,EAAK,EAAE,CAAG,CAAC;EACpB;EACA,IAAI,MAAM,KAAA,GAAW,OAAO,EAAK,CAAC;EAClC,QAAQ,GAAR;GACE,KAAK,WACH,OAAO,KAAK;GACd,KAAK,SACH,OAAO,GAAG,KAAK,KAAK;GACtB,KAAK,UACH,OAAO,GAAG,KAAK,KAAK;GACtB,SACE,OAAO,GAAG,KAAK,KAAK,GAAG;EAC3B;CACF;CAEA,MAAM,QAAW,GAAa,EAAE,WAAQ,SAAM,WAAQ,YAAyB,CAAC,GAAe;EAC7F,IAAM,IAAI,KAAK,EAAE,SAAS,OACpB,IAAU,IAAI,QAAQ,MAAM,KAAK,EAAE,UAAU,CAAC;EACpD,AAAI,MAAS,KAAA,KAAW,EAAQ,IAAI,gBAAgB,kBAAkB;EACtE,IAAM,IAAQ,MAAM,KAAK,EAAE,QAAQ;EACnC,AAAI,KAAS,CAAC,EAAQ,IAAI,eAAe,KAAG,EAAQ,IAAI,iBAAiB,UAAU,GAAO;EAC1F,IAAM,IAAO,KAAK,EAAE,WAAW;EAC/B,AAAI,KAAM,EAAQ,IAAI,mBAAmB,CAAI;EAC7C,IAAI;EACJ,IAAI;GACF,IAAM,MAAM,EAAE,GAAK;IACjB,QAAQ,MAAW,MAAS,KAAA,IAAY,QAAQ;IAChD;IACA,MAAM,MAAS,KAAA,IAAY,OAAO,KAAK,UAAU,CAAI;IACrD,aAAa,KAAK,EAAE,eAAe;IACnC,QAAQ,KAAU;GACpB,CAAC;EACH,SAAS,GAAK;GAEZ,MADI,GAAQ,UAAe,EAAQ,CAAM,IACnC,IAAI,EAAgB,WAAW,kBAAkB,IAAI,IAAI,GAAK,UAAU,CAAC,CAAC,SAAS,eAAe,EAAE,OAAO,EAAI,CAAC;EACxH;EACA,IAAI,CAAC,EAAI,IAAI,MAAM,MAAM,EAAoB,CAAG;EAEhD,OADI,IAAc,MAAM,EAAI,KAAK,IACzB,EAAI,WAAW,MAAM,KAAA,IAAY,MAAM,EAAI,KAAK;CAC1D;CAMA,WAAoB,OAAO,GAAqB,MAA+B;EAG7E,IAFK,EAAI,cAAY,EAAI,KAAK,OAAO,GAAK,EAAI,GAC1C,KAAK,EAAE,gBAAgB,cAAW,EAAI,kBAAkB,KACxD,CAAC,KAAK,YAAY,CAAG,GAAG;EAC5B,IAAM,IAAQ,MAAM,KAAK,EAAE,QAAQ;EACnC,AAAI,KAAO,EAAI,iBAAiB,iBAAiB,UAAU,GAAO;CACpE;CAEA,aAAa,GAAmB;EAC9B,AAAI,MAAQ,KAAK,UAAU,QAAK,KAAK,YAAY,EAAE,OAAI;CACzD;CAGA,iBAAqD;EACnD,IAAM,IAAQ,KAAK;EACnB,QAAQ,MAAW,KAAK,KAAK,GAAQ,MAAU,KAAK,YAAY,EAAM,MAAM,IAAI;CAClF;CAEA,UAAU,GAAgF;EAExF,OADA,KAAK,UAAU,IAAI,CAAQ,SACd,KAAK,KAAK,UAAU,OAAO,CAAQ;CAClD;CAEA,KAAa,GAA0B,GAA4B;EACjE,KAAK,IAAM,KAAK,KAAK,WACnB,IAAI;GACF,EAAE,GAAQ,CAAK;EACjB,SAAS,GAAG;GAEV,QAAQ,MAAM,sCAAsC,CAAC;EACvD;CAEJ;CAEA,YAAoB,GAAsB;EACxC,IAAM,IAAO,OAAO,WAAa,MAAc,qBAAqB,SAAS;EAC7E,IAAI;GACF,OAAO,IAAI,IAAI,GAAK,CAAI,CAAC,CAAC,WAAW,IAAI,IAAI,KAAK,QAAQ,KAAK,CAAI,CAAC,CAAC;EACvE,QAAQ;GACN,OAAO;EACT;CACF;AACF"}
1
+ {"version":3,"file":"http.js","names":[],"sources":["../../src/client/http.ts"],"sourcesContent":["import { ContentKitError, aborted, readContentKitError } from \"./errors.js\";\nimport type { ContentChange } from \"./content/types.js\";\nimport type { FileInfo, Item, RefBody } from \"./generated/wire.js\";\n\n/** A module's base URL, or one per item (a host that splits uploads by kind). */\nexport type Mount = string | ((ref: RefBody) => string);\n\n/**\n * Where each module lives when the host does not serve them all under\n * baseUrl's fixed sub-paths.\n */\nexport interface ContentKitMounts {\n /** Posts, comments, reactions, favorites, polls, bans, moderation. Default baseUrl. */\n content?: string;\n /** Media reads and HLS playlists. Default `{baseUrl}/media`. */\n media?: Mount;\n /** Uploads and commits. Default `{baseUrl}/media/upload`. */\n upload?: Mount;\n /** Content-code lookup. Default `{baseUrl}/codes`. */\n codes?: string;\n /** Taxonomy. Default `{baseUrl}/taxonomy`. */\n taxonomy?: string;\n /** User inbox. Default `{baseUrl}/notifications`. */\n notifications?: string;\n}\n\nexport type ContentKitModule = keyof ContentKitMounts;\n\n/** A mutation made through the client: the host's cache-invalidation hook gets each one. */\nexport type ContentKitChange =\n /** A commit applied; files are the item's uploads as an editor reads them, without URLs. */\n | { type: \"media.committed\"; ref: RefBody; files: FileInfo[] }\n /** An upload finished processing, as an editor read returns it. */\n | { type: \"media.processed\"; ref: RefBody; file: FileInfo }\n | { type: \"notifications.changed\" }\n | { type: \"notifications.updated\"; item: Item }\n | ContentChange;\n\nexport type TokenSource = () => string | null | undefined | Promise<string | null | undefined>;\n\nexport interface HttpOptions {\n /** Where the host mounts ContentKit, e.g. \"/api/v1/contentkit\". */\n baseUrl: string;\n mounts?: ContentKitMounts;\n /** Transport for API calls; pass an authenticating fetch (auth-ui's authFetch). */\n fetch?: typeof fetch;\n /**\n * Bearer for API calls and for HLS playlists on the API origin (hls.js\n * loads them with XHR, not fetch). An authenticating fetch overrides it.\n */\n token?: TokenSource;\n /** Sent as Accept-Language. */\n language?: () => string | null | undefined;\n /** Extra headers per call (CSRF). */\n headers?: () => HeadersInit | Promise<HeadersInit>;\n /** Default \"same-origin\"; \"include\" also sends cookies with HLS requests. */\n credentials?: RequestCredentials;\n}\n\nexport interface RequestOptions {\n method?: string;\n body?: unknown;\n signal?: AbortSignal;\n /** Read the body as a Blob instead of JSON. */\n blob?: boolean;\n}\n\nconst trim = (u: string) => u.replace(/\\/+$/, \"\");\n\n/** The transport every module shares: mounts, auth, language, errors and change events. */\nexport class Http {\n private readonly listeners = new Set<(change: ContentKitChange, scope: string | null) => void>();\n private readScope = { key: \"{}\" };\n private readonly base: string;\n\n constructor(private readonly o: HttpOptions) {\n if (typeof o.baseUrl !== \"string\") throw new Error(\"contentkit: createContentKitClient needs baseUrl\");\n this.base = trim(o.baseUrl);\n }\n\n /** The module's base URL, without a trailing slash. */\n mount(module: ContentKitModule, ref?: RefBody): string {\n const m = this.o.mounts?.[module];\n if (typeof m === \"function\") {\n if (!ref) throw new Error(`contentkit: the ${module} mount is per item; pass a ref`);\n return trim(m(ref));\n }\n if (m !== undefined) return trim(m);\n switch (module) {\n case \"content\":\n return this.base;\n case \"media\":\n return `${this.base}/media`;\n case \"upload\":\n return `${this.base}/media/upload`;\n default:\n return `${this.base}/${module}`;\n }\n }\n\n async request<T>(url: string, { method, body, signal, blob }: RequestOptions = {}): Promise<T> {\n const f = this.o.fetch ?? fetch;\n const headers = new Headers(await this.o.headers?.());\n if (body !== undefined) headers.set(\"Content-Type\", \"application/json\");\n const token = await this.o.token?.();\n if (token && !headers.has(\"Authorization\")) headers.set(\"Authorization\", `Bearer ${token}`);\n const lang = this.o.language?.();\n if (lang) headers.set(\"Accept-Language\", lang);\n let res: Response;\n try {\n res = await f(url, {\n method: method ?? (body === undefined ? \"GET\" : \"POST\"),\n headers,\n body: body === undefined ? null : JSON.stringify(body),\n credentials: this.o.credentials ?? \"same-origin\",\n signal: signal ?? null,\n });\n } catch (err) {\n if (signal?.aborted) throw aborted(signal);\n throw new ContentKitError(\"network\", `ContentKit API ${new URL(url, \"http://x\").pathname} unreachable`, { cause: err });\n }\n if (!res.ok) throw await readContentKitError(res);\n if (blob) return (await res.blob()) as T;\n return (res.status === 204 ? undefined : await res.json()) as T;\n }\n\n /**\n * hls.js `xhrSetup`: opens the request, sends cookies when credentials is\n * \"include\", and adds the bearer only on the API's origin (never a media host).\n */\n readonly xhrSetup = async (xhr: XMLHttpRequest, url: string): Promise<void> => {\n if (!xhr.readyState) xhr.open(\"GET\", url, true);\n if (this.o.credentials === \"include\") xhr.withCredentials = true;\n if (!this.onApiOrigin(url)) return;\n const token = await this.o.token?.();\n if (token) xhr.setRequestHeader(\"Authorization\", `Bearer ${token}`);\n };\n\n setReadScope(key: string): void {\n if (key !== this.readScope.key) this.readScope = { key };\n }\n\n /** Capture before awaiting a write; null tells caches to refetch after a scope change. */\n captureChanges(): (change: ContentKitChange) => void {\n const scope = this.readScope;\n return (change) => this.emit(change, scope === this.readScope ? scope.key : null);\n }\n\n subscribe(listener: (change: ContentKitChange, scope: string | null) => void): () => void {\n this.listeners.add(listener);\n return () => void this.listeners.delete(listener);\n }\n\n private emit(change: ContentKitChange, scope: string | null): void {\n for (const l of this.listeners) {\n try {\n l(change, scope);\n } catch (e) {\n // A host listener's fault must not fail the mutation that succeeded.\n console.error(\"contentkit: change listener failed\", e);\n }\n }\n }\n\n private onApiOrigin(url: string): boolean {\n const here = typeof location === \"undefined\" ? \"http://localhost\" : location.href;\n try {\n return new URL(url, here).origin === new URL(this.base || \"/\", here).origin;\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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"}
@@ -11,6 +11,7 @@ export { ModerationClient, type HeldQuery } from './content/moderation.js';
11
11
  export { reactionVerb, type BanScope, type ContentChange, type Decision, type HeldKind, type Reaction, type Sort } from './content/types.js';
12
12
  export { TaxonomyClient, type NodeAssignmentQuery, type NodeQuery } from './taxonomy.js';
13
13
  export { CodesClient } from './codes.js';
14
+ export { NotificationsClient, type NotificationItem } from './notifications.js';
14
15
  export { call, routeURL, type CallOptions, type Method, type PageQuery, type PathParams, type RouteQuery, type RoutePath } from './route.js';
15
16
  export { MediaApi, type ReadOptions } from './media/api.js';
16
17
  export { MediaClient, backoff, samePath, stem, type CommitOptions, type CommitSource, type ContentFolders, type MediaOptions, type NamedOptions, type NamedUpload, type PlannedPart, type Progress, type PutOptions, type UploadOptions, type UploadState, type UploadedFile, type WaitOptions, } from './media/client.js';
@@ -0,0 +1,23 @@
1
+ import { Item, Page } from './generated/wire.js';
2
+ import { Http } from './http.js';
3
+ /** One generic notice or tracked work item. */
4
+ export type NotificationItem = Item;
5
+ /** The authenticated person's shared inbox; presentation belongs to the host. */
6
+ export declare class NotificationsClient {
7
+ private readonly http;
8
+ constructor(http: Http);
9
+ /** Active or archived receipts, newest first. Reading never resolves work. */
10
+ list(o?: {
11
+ limit?: number;
12
+ cursor?: string;
13
+ unread?: boolean;
14
+ dismissed?: boolean;
15
+ signal?: AbortSignal;
16
+ }): Promise<Page>;
17
+ /** Refresh mounted inboxes after the host receives a new-event signal. */
18
+ refresh(): void;
19
+ /** Local receipt state with canonical server timestamps and revision. */
20
+ setRead(id: string, read?: boolean, signal?: AbortSignal): Promise<Item>;
21
+ /** Archives or restores a receipt; never resolves source work. */
22
+ setDismissed(id: string, dismissed?: boolean, signal?: AbortSignal): Promise<Item>;
23
+ }
@@ -0,0 +1,46 @@
1
+ import { call as e } from "./route.js";
2
+ //#region src/client/notifications.ts
3
+ var t = class {
4
+ http;
5
+ constructor(e) {
6
+ this.http = e;
7
+ }
8
+ list(t = {}) {
9
+ return e(this.http, "GET", "/inbox", {
10
+ query: {
11
+ limit: t.limit,
12
+ cursor: t.cursor,
13
+ unread: t.unread,
14
+ dismissed: t.dismissed
15
+ },
16
+ signal: t.signal
17
+ });
18
+ }
19
+ refresh() {
20
+ this.http.captureChanges()({ type: "notifications.changed" });
21
+ }
22
+ async setRead(t, n = !0, r) {
23
+ let i = this.http.captureChanges(), a = await e(this.http, n ? "PUT" : "DELETE", "/{id}/read", {
24
+ params: { id: t },
25
+ signal: r
26
+ });
27
+ return i({
28
+ type: "notifications.updated",
29
+ item: a
30
+ }), a;
31
+ }
32
+ async setDismissed(t, n = !0, r) {
33
+ let i = this.http.captureChanges(), a = await e(this.http, n ? "PUT" : "DELETE", "/{id}/dismiss", {
34
+ params: { id: t },
35
+ signal: r
36
+ });
37
+ return i({
38
+ type: "notifications.updated",
39
+ item: a
40
+ }), a;
41
+ }
42
+ };
43
+ //#endregion
44
+ export { t as NotificationsClient };
45
+
46
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.js","names":[],"sources":["../../src/client/notifications.ts"],"sourcesContent":["import type { Item, Page } from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call } from \"./route.js\";\n\n/** One generic notice or tracked work item. */\nexport type NotificationItem = Item;\n\n/** The authenticated person's shared inbox; presentation belongs to the host. */\nexport class NotificationsClient {\n constructor(private readonly http: Http) {}\n\n /** Active or archived receipts, newest first. Reading never resolves work. */\n list(o: { limit?: number; cursor?: string; unread?: boolean; dismissed?: boolean; signal?: AbortSignal } = {}): Promise<Page> {\n return call(this.http, \"GET\", \"/inbox\", { query: { limit: o.limit, cursor: o.cursor, unread: o.unread, dismissed: o.dismissed }, signal: o.signal });\n }\n\n /** Refresh mounted inboxes after the host receives a new-event signal. */\n refresh(): void {\n this.http.captureChanges()({ type: \"notifications.changed\" });\n }\n\n /** Local receipt state with canonical server timestamps and revision. */\n async setRead(id: string, read = true, signal?: AbortSignal): Promise<Item> {\n const changed = this.http.captureChanges();\n const item: Item = await call(this.http, read ? \"PUT\" : \"DELETE\", \"/{id}/read\", { params: { id }, signal });\n changed({ type: \"notifications.updated\", item });\n return item;\n }\n\n /** Archives or restores a receipt; never resolves source work. */\n async setDismissed(id: string, dismissed = true, signal?: AbortSignal): Promise<Item> {\n const changed = this.http.captureChanges();\n const item: Item = await call(this.http, dismissed ? \"PUT\" : \"DELETE\", \"/{id}/dismiss\", { params: { id }, signal });\n changed({ type: \"notifications.updated\", item });\n return item;\n }\n}\n"],"mappings":";;AAQA,IAAa,IAAb,MAAiC;CACF;CAA7B,YAAY,GAA6B;EAAZ,KAAA,OAAA;CAAa;CAG1C,KAAK,IAAsG,CAAC,GAAkB;EAC5H,OAAO,EAAK,KAAK,MAAM,OAAO,UAAU;GAAE,OAAO;IAAE,OAAO,EAAE;IAAO,QAAQ,EAAE;IAAQ,QAAQ,EAAE;IAAQ,WAAW,EAAE;GAAU;GAAG,QAAQ,EAAE;EAAO,CAAC;CACrJ;CAGA,UAAgB;EACd,KAAK,KAAK,eAAe,CAAC,CAAC,EAAE,MAAM,wBAAwB,CAAC;CAC9D;CAGA,MAAM,QAAQ,GAAY,IAAO,IAAM,GAAqC;EAC1E,IAAM,IAAU,KAAK,KAAK,eAAe,GACnC,IAAa,MAAM,EAAK,KAAK,MAAM,IAAO,QAAQ,UAAU,cAAc;GAAE,QAAQ,EAAE,MAAG;GAAG;EAAO,CAAC;EAE1G,OADA,EAAQ;GAAE,MAAM;GAAyB;EAAK,CAAC,GACxC;CACT;CAGA,MAAM,aAAa,GAAY,IAAY,IAAM,GAAqC;EACpF,IAAM,IAAU,KAAK,KAAK,eAAe,GACnC,IAAa,MAAM,EAAK,KAAK,MAAM,IAAY,QAAQ,UAAU,iBAAiB;GAAE,QAAQ,EAAE,MAAG;GAAG;EAAO,CAAC;EAElH,OADA,EAAQ;GAAE,MAAM;GAAyB;EAAK,CAAC,GACxC;CACT;AACF"}
package/dist/client.js CHANGED
@@ -28,6 +28,7 @@ import { ModerationClient as Be } from "./client/content/moderation.js";
28
28
  import { PollsClient as Ve } from "./client/content/polls.js";
29
29
  import { IMAGE_SCHEME as He, PostsClient as Ue, imageRef as We, imageRefs as Ge } from "./client/content/posts.js";
30
30
  import { ReactionsClient as Ke } from "./client/content/reactions.js";
31
- import { TaxonomyClient as qe } from "./client/taxonomy.js";
32
- import { createContentKitClient as Je } from "./client/client.js";
33
- export { le as ABR_DEFAULTS, Ie as BansClient, i as CLIENT_ERROR_CODES, Fe as CodesClient, Re as CommentsClient, a as ContentKitError, e as DEFAULT_DENSITY, o as ERROR_CODES, ze as FavoritesClient, He as IMAGE_SCHEME, te as ItemUploadQueue, S as MAX_PART_SIZE, C as MAX_SINGLE_PUT, w as MIN_PART_SIZE, x as MediaApi, A as MediaClient, Be as ModerationClient, ue as NETWORK_FAILURES_BEFORE_ERROR, ke as PLAYBACK_SPEEDS, Ae as PLAYER_TRACKS_KEY, je as PLAYER_VOLUME_KEY, E as Pacer, Ve as PollsClient, Ue as PostsClient, ie as READ_CHUNK, de as REFRESH_BEFORE_EXPIRY, Ke as ReactionsClient, qe as TaxonomyClient, fe as abrHlsConfig, P as acceptOf, h as aspectOf, j as backoff, _ as call, pe as capRung, G as centeredCrop, y as checkRef, ae as chunkOffsets, me as classifyHlsError, he as classifyMediaError, K as constrainCrop, Je as createContentKitClient, ne as decodeImage, F as defaultImage, D as defaultTransport, t as densityFor, q as editOf, J as editedSize, ee as encodeRemaining, ge as expiryDelay, s as failureError, O as fetchTransport, I as filesFor, d as fill, Se as formatDuration, Y as fromRotated, Ce as galleryItems, _e as hlsConfig, We as imageRef, Ge as imageRefs, ve as initialEstimate, re as isAnimatedImage, we as isAudioType, b as isContentId, c as isContentKitError, Te as isImageType, L as isPattern, oe as isProcessing, Ee as isSubtitleType, De as isVideoType, se as mergeReads, Me as parseSpriteVtt, n as pickRendition, Ne as playerKeyAction, ce as processing, f as publicRenditions, p as publicURL, g as ratio, R as ratioLabel, Le as reactionVerb, l as readContentKitError, ye as refreshable, Pe as resumeAt, X as rotation, v as routeURL, z as ruleDir, B as ruleFor, Z as sameEdit, M as samePath, V as screenFiles, T as sha256Hex, r as sortRenditions, m as srcSet, Oe as stageAspect, be as startRung, xe as statusKind, N as stem, u as toContentKitError, Q as toOriginal, $ as toRotated, H as uniqueName, U as uploadRules, W as withMediaType, k as xhrTransport };
31
+ import { NotificationsClient as qe } from "./client/notifications.js";
32
+ import { TaxonomyClient as Je } from "./client/taxonomy.js";
33
+ import { createContentKitClient as Ye } from "./client/client.js";
34
+ export { le as ABR_DEFAULTS, Ie as BansClient, i as CLIENT_ERROR_CODES, Fe as CodesClient, Re as CommentsClient, a as ContentKitError, e as DEFAULT_DENSITY, o as ERROR_CODES, ze as FavoritesClient, He as IMAGE_SCHEME, te as ItemUploadQueue, S as MAX_PART_SIZE, C as MAX_SINGLE_PUT, w as MIN_PART_SIZE, x as MediaApi, A as MediaClient, Be as ModerationClient, ue as NETWORK_FAILURES_BEFORE_ERROR, qe as NotificationsClient, ke as PLAYBACK_SPEEDS, Ae as PLAYER_TRACKS_KEY, je as PLAYER_VOLUME_KEY, E as Pacer, Ve as PollsClient, Ue as PostsClient, ie as READ_CHUNK, de as REFRESH_BEFORE_EXPIRY, Ke as ReactionsClient, Je as TaxonomyClient, fe as abrHlsConfig, P as acceptOf, h as aspectOf, j as backoff, _ as call, pe as capRung, G as centeredCrop, y as checkRef, ae as chunkOffsets, me as classifyHlsError, he as classifyMediaError, K as constrainCrop, Ye as createContentKitClient, ne as decodeImage, F as defaultImage, D as defaultTransport, t as densityFor, q as editOf, J as editedSize, ee as encodeRemaining, ge as expiryDelay, s as failureError, O as fetchTransport, I as filesFor, d as fill, Se as formatDuration, Y as fromRotated, Ce as galleryItems, _e as hlsConfig, We as imageRef, Ge as imageRefs, ve as initialEstimate, re as isAnimatedImage, we as isAudioType, b as isContentId, c as isContentKitError, Te as isImageType, L as isPattern, oe as isProcessing, Ee as isSubtitleType, De as isVideoType, se as mergeReads, Me as parseSpriteVtt, n as pickRendition, Ne as playerKeyAction, ce as processing, f as publicRenditions, p as publicURL, g as ratio, R as ratioLabel, Le as reactionVerb, l as readContentKitError, ye as refreshable, Pe as resumeAt, X as rotation, v as routeURL, z as ruleDir, B as ruleFor, Z as sameEdit, M as samePath, V as screenFiles, T as sha256Hex, r as sortRenditions, m as srcSet, Oe as stageAspect, be as startRung, xe as statusKind, N as stem, u as toContentKitError, Q as toOriginal, $ as toRotated, H as uniqueName, U as uploadRules, W as withMediaType, k as xhrTransport };
@@ -0,0 +1,28 @@
1
+ import { ReactNode } from 'react';
2
+ import { ContentKitUiAppearance } from '../appearance.js';
3
+ import { ContentKitClient } from '../client/client.js';
4
+ import { Item } from '../client/generated/wire.js';
5
+ import { ContentKitErrorHandler } from '../react/context.js';
6
+ import { UseNotificationsOptions } from '../react/notifications.js';
7
+ export interface NotificationInboxProps {
8
+ /** Host-owned rendering for every kind, including unknown future kinds. */
9
+ renderItem: (item: Item) => ReactNode;
10
+ /** Domain actions/links; the inbox itself never executes a source's workflow. */
11
+ renderActions?: (item: Item) => ReactNode;
12
+ client?: ContentKitClient;
13
+ pageSize?: number;
14
+ initialFilter?: "all" | "unread" | "archived";
15
+ refreshInterval?: UseNotificationsOptions["refreshInterval"];
16
+ onSignIn?: () => void;
17
+ onError?: ContentKitErrorHandler;
18
+ appearance?: ContentKitUiAppearance;
19
+ className?: string;
20
+ }
21
+ /** A user inbox with cursor pagination and independent local read state. */
22
+ export declare function NotificationInbox({ renderItem, renderActions, client, pageSize, initialFilter, refreshInterval, onSignIn, onError, appearance, className }: NotificationInboxProps): import('react').JSX.Element;
23
+ export interface NotificationBellProps extends NotificationInboxProps {
24
+ /** Unread indicator refresh. Default 30 seconds while the page is visible. */
25
+ unreadRefreshInterval?: UseNotificationsOptions["refreshInterval"];
26
+ }
27
+ /** A keyboard-accessible inbox popover. Its dot means unread items exist, not a guessed count. */
28
+ export declare function NotificationBell({ appearance, className, unreadRefreshInterval, ...inbox }: NotificationBellProps): import('react').JSX.Element;
@@ -0,0 +1,222 @@
1
+ import { useMessages as e } from "../i18n/context.js";
2
+ import { ContentKitUiRoot as t, useScopeProps as n } from "../scope.js";
3
+ import { useErrorReporter as r } from "../react/context.js";
4
+ import { Button as i } from "../ui/button.js";
5
+ import { useContentScope as a } from "../react/use-resource.js";
6
+ import { Badge as o } from "../ui/badge.js";
7
+ import { Skeleton as s } from "../ui/skeleton.js";
8
+ import { ErrorLine as c, RelativeTime as l, useAction as u } from "./social/parts.js";
9
+ import { useNotificationUnread as d, useNotifications as f } from "../react/notifications.js";
10
+ import { useEffect as p, useId as m, useRef as h, useState as g } from "react";
11
+ import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
12
+ import { cn as b } from "cn";
13
+ import { Notification01Icon as x, RefreshIcon as S } from "@hugeicons/core-free-icons";
14
+ import { HugeiconsIcon as C } from "@hugeicons/react";
15
+ import { Popover as w } from "@base-ui/react/popover";
16
+ //#region src/components/notifications.tsx
17
+ function T({ renderItem: n, renderActions: o, client: l, pageSize: u, initialFilter: d = "all", refreshInterval: x, onSignIn: w, onError: T, appearance: D, className: O }) {
18
+ let { t: k } = e(), A = m(), [j, M] = g(d), N = f({
19
+ client: l,
20
+ pageSize: u,
21
+ unread: j === "unread",
22
+ dismissed: j === "archived",
23
+ refreshInterval: x
24
+ }), { onSignIn: P } = a(l), F = w ?? P, I = h(null), L = r(T);
25
+ return p(() => {
26
+ N.error && L(N.error, "notifications.load");
27
+ }, [N.error, L]), /* @__PURE__ */ y(t, {
28
+ appearance: D,
29
+ className: b("grid gap-4 text-sm", O),
30
+ "data-ckui": "notification-inbox",
31
+ role: "region",
32
+ "aria-labelledby": A,
33
+ children: [/* @__PURE__ */ y("header", {
34
+ className: "flex items-center justify-between gap-3",
35
+ children: [/* @__PURE__ */ v("h2", {
36
+ id: A,
37
+ className: "text-base font-semibold",
38
+ children: k("notifications.title")
39
+ }), !N.signedOut && /* @__PURE__ */ v(i, {
40
+ size: "icon-sm",
41
+ variant: "ghost",
42
+ "aria-label": k("notifications.refresh"),
43
+ disabled: N.loading,
44
+ onClick: N.reload,
45
+ children: /* @__PURE__ */ v(C, {
46
+ icon: S,
47
+ strokeWidth: 2
48
+ })
49
+ })]
50
+ }), N.signedOut ? /* @__PURE__ */ y("div", {
51
+ className: "grid justify-items-start gap-3 py-4 text-muted-foreground",
52
+ children: [/* @__PURE__ */ v("p", { children: k("notifications.signInHint") }), F && /* @__PURE__ */ v(i, {
53
+ variant: "outline",
54
+ onClick: F,
55
+ children: k("notifications.signIn")
56
+ })]
57
+ }) : /* @__PURE__ */ y(_, { children: [
58
+ /* @__PURE__ */ v("div", {
59
+ className: "flex gap-1",
60
+ role: "group",
61
+ "aria-label": k("notifications.filter"),
62
+ children: [
63
+ "all",
64
+ "unread",
65
+ "archived"
66
+ ].map((e) => /* @__PURE__ */ v(i, {
67
+ ref: j === e ? I : void 0,
68
+ size: "sm",
69
+ variant: j === e ? "secondary" : "ghost",
70
+ "aria-pressed": j === e,
71
+ onClick: () => M(e),
72
+ children: k(`notifications.${e}`)
73
+ }, e))
74
+ }),
75
+ N.error && /* @__PURE__ */ y("div", {
76
+ className: "grid justify-items-start gap-2",
77
+ children: [/* @__PURE__ */ v(c, { children: k("notifications.loadFailed") }), /* @__PURE__ */ v(i, {
78
+ size: "sm",
79
+ variant: "outline",
80
+ onClick: N.reload,
81
+ children: k("common.retry")
82
+ })]
83
+ }),
84
+ N.loading && !N.items.length ? /* @__PURE__ */ y("div", {
85
+ role: "status",
86
+ "aria-label": k("notifications.loading"),
87
+ className: "grid gap-3",
88
+ children: [/* @__PURE__ */ v(s, { className: "h-20 w-full" }), /* @__PURE__ */ v(s, { className: "h-20 w-full" })]
89
+ }) : !N.items.length && !N.error ? /* @__PURE__ */ v("p", {
90
+ role: "status",
91
+ className: "py-8 text-center text-muted-foreground",
92
+ children: k(j === "unread" ? "notifications.emptyUnread" : "notifications.empty")
93
+ }) : /* @__PURE__ */ v("ul", {
94
+ className: "grid divide-y divide-border overflow-hidden rounded-lg border border-border",
95
+ "aria-busy": N.loading,
96
+ children: N.items.map((e) => /* @__PURE__ */ v(E, {
97
+ item: e,
98
+ renderItem: n,
99
+ renderActions: o,
100
+ onRead: async (e, t) => {
101
+ let n = await N.setRead(e, t);
102
+ return j === "unread" && t && I.current?.focus(), n;
103
+ },
104
+ onDismiss: async (e, t) => {
105
+ let n = await N.setDismissed(e, t);
106
+ return I.current?.focus(), n;
107
+ },
108
+ onError: T
109
+ }, e.id))
110
+ }),
111
+ N.hasMore && /* @__PURE__ */ v(i, {
112
+ variant: "outline",
113
+ disabled: N.loadingMore || N.loading,
114
+ onClick: () => void N.loadMore(),
115
+ children: k(N.loadingMore ? "notifications.loading" : "notifications.loadMore")
116
+ })
117
+ ] })]
118
+ });
119
+ }
120
+ function E({ item: t, renderItem: n, renderActions: r, onRead: a, onDismiss: s, onError: d }) {
121
+ let { t: f } = e(), p = u("notifications.read", d), h = u("notifications.dismiss", d), g = m(), _ = t.status === "open" ? f("notifications.open") : t.status === "resolved" ? f("notifications.resolved") : t.status === "dismissed" ? f("notifications.dismissed") : void 0;
122
+ return /* @__PURE__ */ y("li", {
123
+ className: b("grid gap-3 p-4", !t.read_at && "bg-primary/5"),
124
+ "data-ckui": "notification-item",
125
+ "data-unread": !t.read_at,
126
+ children: [
127
+ /* @__PURE__ */ y("div", {
128
+ className: "flex items-center gap-2 text-xs text-muted-foreground",
129
+ children: [
130
+ !t.read_at && /* @__PURE__ */ v(o, {
131
+ variant: "secondary",
132
+ children: f("notifications.unread")
133
+ }),
134
+ _ && /* @__PURE__ */ v(o, {
135
+ variant: t.status === "open" ? "outline" : "secondary",
136
+ children: _
137
+ }),
138
+ /* @__PURE__ */ v(l, { at: t.created_at })
139
+ ]
140
+ }),
141
+ /* @__PURE__ */ v("div", {
142
+ id: g,
143
+ className: "min-w-0 break-words",
144
+ children: n(t)
145
+ }),
146
+ /* @__PURE__ */ y("div", {
147
+ className: "flex flex-wrap items-center gap-2",
148
+ children: [
149
+ r?.(t),
150
+ /* @__PURE__ */ v(i, {
151
+ size: "sm",
152
+ variant: "ghost",
153
+ "aria-describedby": g,
154
+ disabled: p.pending || h.pending,
155
+ onClick: () => void p.run(() => a(t.id, !t.read_at)),
156
+ children: f(t.read_at ? "notifications.markUnread" : "notifications.markRead")
157
+ }),
158
+ /* @__PURE__ */ v(i, {
159
+ size: "sm",
160
+ variant: "ghost",
161
+ "aria-describedby": g,
162
+ disabled: p.pending || h.pending,
163
+ onClick: () => void h.run(() => s(t.id, !t.dismissed_at)),
164
+ children: f(t.dismissed_at ? "notifications.restore" : "notifications.dismiss")
165
+ })
166
+ ]
167
+ }),
168
+ /* @__PURE__ */ v(c, { error: p.error ?? h.error })
169
+ ]
170
+ });
171
+ }
172
+ function D({ appearance: a, className: o, unreadRefreshInterval: s, ...c }) {
173
+ let { t: l } = e(), u = d({
174
+ client: c.client,
175
+ refreshInterval: s
176
+ }), f = n(a), m = r(c.onError);
177
+ return p(() => {
178
+ u.error && m(u.error, "notifications.load");
179
+ }, [u.error, m]), /* @__PURE__ */ y(w.Root, {
180
+ onOpenChange: (e) => {
181
+ e && u.reload();
182
+ },
183
+ children: [/* @__PURE__ */ v(t, {
184
+ appearance: a,
185
+ className: b("inline-flex", o),
186
+ "data-ckui": "notification-bell",
187
+ children: /* @__PURE__ */ y(w.Trigger, {
188
+ render: /* @__PURE__ */ v(i, {
189
+ variant: "ghost",
190
+ size: "icon"
191
+ }),
192
+ "aria-label": l(u.unread ? "notifications.unreadLabel" : "notifications.title"),
193
+ className: "relative",
194
+ children: [/* @__PURE__ */ v(C, {
195
+ icon: x,
196
+ strokeWidth: 2
197
+ }), u.unread && /* @__PURE__ */ v("span", {
198
+ className: "absolute right-1.5 top-1.5 size-2 rounded-full bg-primary ring-2 ring-background",
199
+ "aria-hidden": "true",
200
+ "data-ckui": "notification-unread"
201
+ })]
202
+ })
203
+ }), /* @__PURE__ */ v(w.Portal, { children: /* @__PURE__ */ v(w.Positioner, {
204
+ ...f,
205
+ className: b(f.className, "z-50"),
206
+ sideOffset: 8,
207
+ align: "end",
208
+ children: /* @__PURE__ */ v(w.Popup, {
209
+ className: "max-h-[min(80vh,40rem)] w-[min(26rem,calc(100vw-2rem))] overflow-auto rounded-xl border border-border bg-background p-4 text-foreground shadow-lg outline-none",
210
+ "aria-label": l("notifications.title"),
211
+ children: /* @__PURE__ */ v(T, {
212
+ ...c,
213
+ appearance: a
214
+ })
215
+ })
216
+ }) })]
217
+ });
218
+ }
219
+ //#endregion
220
+ export { D as NotificationBell, T as NotificationInbox };
221
+
222
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.js","names":[],"sources":["../../src/components/notifications.tsx"],"sourcesContent":["import { Popover } from \"@base-ui/react/popover\";\nimport { Notification01Icon, RefreshIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useEffect, useId, useRef, useState, type ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../appearance.js\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { Item } from \"../client/generated/wire.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport { useErrorReporter, type ContentKitErrorHandler } from \"../react/context.js\";\nimport { useNotificationUnread, useNotifications, type UseNotificationsOptions } from \"../react/notifications.js\";\nimport { useContentScope } from \"../react/use-resource.js\";\nimport { ContentKitUiRoot, useScopeProps } from \"../scope.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { ErrorLine, RelativeTime, useAction } from \"./social/parts.js\";\n\nexport interface NotificationInboxProps {\n /** Host-owned rendering for every kind, including unknown future kinds. */\n renderItem: (item: Item) => ReactNode;\n /** Domain actions/links; the inbox itself never executes a source's workflow. */\n renderActions?: (item: Item) => ReactNode;\n client?: ContentKitClient;\n pageSize?: number;\n initialFilter?: \"all\" | \"unread\" | \"archived\";\n refreshInterval?: UseNotificationsOptions[\"refreshInterval\"];\n onSignIn?: () => void;\n onError?: ContentKitErrorHandler;\n appearance?: ContentKitUiAppearance;\n className?: string;\n}\n\n/** A user inbox with cursor pagination and independent local read state. */\nexport function NotificationInbox({ renderItem, renderActions, client, pageSize, initialFilter = \"all\", refreshInterval, onSignIn, onError, appearance, className }: NotificationInboxProps) {\n const { t } = useMessages();\n const heading = useId();\n const [filter, setFilter] = useState(initialFilter);\n const inbox = useNotifications({ client, pageSize, unread: filter === \"unread\", dismissed: filter === \"archived\", refreshInterval });\n const { onSignIn: providerSignIn } = useContentScope(client);\n const signIn = onSignIn ?? providerSignIn;\n const filterButton = useRef<HTMLButtonElement>(null);\n const report = useErrorReporter(onError);\n useEffect(() => {\n if (inbox.error) report(inbox.error, \"notifications.load\");\n }, [inbox.error, report]);\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"grid gap-4 text-sm\", className)} data-ckui=\"notification-inbox\" role=\"region\" aria-labelledby={heading}>\n <header className=\"flex items-center justify-between gap-3\">\n <h2 id={heading} className=\"text-base font-semibold\">{t(\"notifications.title\")}</h2>\n {!inbox.signedOut && <Button size=\"icon-sm\" variant=\"ghost\" aria-label={t(\"notifications.refresh\")} disabled={inbox.loading} onClick={inbox.reload}><HugeiconsIcon icon={RefreshIcon} strokeWidth={2} /></Button>}\n </header>\n {inbox.signedOut ? (\n <div className=\"grid justify-items-start gap-3 py-4 text-muted-foreground\">\n <p>{t(\"notifications.signInHint\")}</p>\n {signIn && <Button variant=\"outline\" onClick={signIn}>{t(\"notifications.signIn\")}</Button>}\n </div>\n ) : <>\n <div className=\"flex gap-1\" role=\"group\" aria-label={t(\"notifications.filter\")}>\n {([\"all\", \"unread\", \"archived\"] as const).map((value) => <Button key={value} ref={filter === value ? filterButton : undefined} size=\"sm\" variant={filter === value ? \"secondary\" : \"ghost\"} aria-pressed={filter === value} onClick={() => setFilter(value)}>{t(`notifications.${value}`)}</Button>)}\n </div>\n {inbox.error && <div className=\"grid justify-items-start gap-2\"><ErrorLine>{t(\"notifications.loadFailed\")}</ErrorLine><Button size=\"sm\" variant=\"outline\" onClick={inbox.reload}>{t(\"common.retry\")}</Button></div>}\n {inbox.loading && !inbox.items.length ? <div role=\"status\" aria-label={t(\"notifications.loading\")} className=\"grid gap-3\"><Skeleton className=\"h-20 w-full\" /><Skeleton className=\"h-20 w-full\" /></div> : !inbox.items.length && !inbox.error ? <p role=\"status\" className=\"py-8 text-center text-muted-foreground\">{t(filter === \"unread\" ? \"notifications.emptyUnread\" : \"notifications.empty\")}</p> : (\n <ul className=\"grid divide-y divide-border overflow-hidden rounded-lg border border-border\" aria-busy={inbox.loading}>\n {inbox.items.map((item) => <NotificationRow key={item.id} item={item} renderItem={renderItem} renderActions={renderActions} onRead={async (id, read) => { const item = await inbox.setRead(id, read); if (filter === \"unread\" && read) filterButton.current?.focus(); return item; }} onDismiss={async (id, dismissed) => { const item = await inbox.setDismissed(id, dismissed); filterButton.current?.focus(); return item; }} onError={onError} />)}\n </ul>\n )}\n {inbox.hasMore && <Button variant=\"outline\" disabled={inbox.loadingMore || inbox.loading} onClick={() => void inbox.loadMore()}>{t(inbox.loadingMore ? \"notifications.loading\" : \"notifications.loadMore\")}</Button>}\n </>}\n </ContentKitUiRoot>\n );\n}\n\nfunction NotificationRow({ item, renderItem, renderActions, onRead, onDismiss, onError }: Pick<NotificationInboxProps, \"renderItem\" | \"renderActions\" | \"onError\"> & { item: Item; onRead: (id: string, read: boolean) => Promise<Item>; onDismiss: (id: string, dismissed: boolean) => Promise<Item> }) {\n const { t } = useMessages();\n const read = useAction(\"notifications.read\", onError);\n const dismiss = useAction(\"notifications.dismiss\", onError);\n const label = useId();\n const status = item.status === \"open\" ? t(\"notifications.open\") : item.status === \"resolved\" ? t(\"notifications.resolved\") : item.status === \"dismissed\" ? t(\"notifications.dismissed\") : undefined;\n return (\n <li className={cn(\"grid gap-3 p-4\", !item.read_at && \"bg-primary/5\")} data-ckui=\"notification-item\" data-unread={!item.read_at}>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n {!item.read_at && <Badge variant=\"secondary\">{t(\"notifications.unread\")}</Badge>}\n {status && <Badge variant={item.status === \"open\" ? \"outline\" : \"secondary\"}>{status}</Badge>}\n <RelativeTime at={item.created_at} />\n </div>\n <div id={label} className=\"min-w-0 break-words\">{renderItem(item)}</div>\n <div className=\"flex flex-wrap items-center gap-2\">\n {renderActions?.(item)}\n <Button size=\"sm\" variant=\"ghost\" aria-describedby={label} disabled={read.pending || dismiss.pending} onClick={() => void read.run(() => onRead(item.id, !item.read_at))}>{t(item.read_at ? \"notifications.markUnread\" : \"notifications.markRead\")}</Button>\n <Button size=\"sm\" variant=\"ghost\" aria-describedby={label} disabled={read.pending || dismiss.pending} onClick={() => void dismiss.run(() => onDismiss(item.id, !item.dismissed_at))}>{t(item.dismissed_at ? \"notifications.restore\" : \"notifications.dismiss\")}</Button>\n </div>\n <ErrorLine error={read.error ?? dismiss.error} />\n </li>\n );\n}\n\nexport interface NotificationBellProps extends NotificationInboxProps {\n /** Unread indicator refresh. Default 30 seconds while the page is visible. */\n unreadRefreshInterval?: UseNotificationsOptions[\"refreshInterval\"];\n}\n\n/** A keyboard-accessible inbox popover. Its dot means unread items exist, not a guessed count. */\nexport function NotificationBell({ appearance, className, unreadRefreshInterval, ...inbox }: NotificationBellProps) {\n const { t } = useMessages();\n const unread = useNotificationUnread({ client: inbox.client, refreshInterval: unreadRefreshInterval });\n const scope = useScopeProps(appearance);\n const report = useErrorReporter(inbox.onError);\n useEffect(() => {\n if (unread.error) report(unread.error, \"notifications.load\");\n }, [unread.error, report]);\n return (\n <Popover.Root onOpenChange={(open) => { if (open) unread.reload(); }}>\n <ContentKitUiRoot appearance={appearance} className={cn(\"inline-flex\", className)} data-ckui=\"notification-bell\">\n <Popover.Trigger render={<Button variant=\"ghost\" size=\"icon\" />} aria-label={t(unread.unread ? \"notifications.unreadLabel\" : \"notifications.title\")} className=\"relative\">\n <HugeiconsIcon icon={Notification01Icon} strokeWidth={2} />\n {unread.unread && <span className=\"absolute right-1.5 top-1.5 size-2 rounded-full bg-primary ring-2 ring-background\" aria-hidden=\"true\" data-ckui=\"notification-unread\" />}\n </Popover.Trigger>\n </ContentKitUiRoot>\n <Popover.Portal>\n <Popover.Positioner {...scope} className={cn(scope.className, \"z-50\")} sideOffset={8} align=\"end\">\n <Popover.Popup className=\"max-h-[min(80vh,40rem)] w-[min(26rem,calc(100vw-2rem))] overflow-auto rounded-xl border border-border bg-background p-4 text-foreground shadow-lg outline-none\" aria-label={t(\"notifications.title\")}>\n <NotificationInbox {...inbox} appearance={appearance} />\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -29,3 +29,4 @@ export { NoAccess, Pager, useConfirm, type AdminFlowProps, type AdminRouteProps,
29
29
  export type { AdminNavigation, ContentKitAuth, StaffAccess, StaffArea } from './react/admin.js';
30
30
  export { createTranslator, defaultMessages, defineMessages, resolveMessages, type MessageKey, type MessageVars, type Translator, type ContentKitUiMessageBundle, type ContentKitUiMessages, type ContentKitUiTranslate, } from './i18n/messages.js';
31
31
  export { useMessages } from './i18n/context.js';
32
+ export { NotificationInbox, NotificationBell, type NotificationInboxProps, type NotificationBellProps } from './components/notifications.js';