@ewanc26/svelte-standard-site 0.2.2 → 0.2.4

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 (69) hide show
  1. package/dist/components/ActionBar.svelte +85 -0
  2. package/dist/components/ActionBar.svelte.d.ts +13 -0
  3. package/dist/components/Avatar.svelte +104 -0
  4. package/dist/components/Avatar.svelte.d.ts +19 -0
  5. package/dist/components/Comment.svelte +172 -0
  6. package/dist/components/Comment.svelte.d.ts +22 -0
  7. package/dist/components/CommentsSection.svelte +89 -0
  8. package/dist/components/DocumentCard.svelte +126 -56
  9. package/dist/components/DocumentCard.svelte.d.ts +51 -0
  10. package/dist/components/Footnotes.svelte +72 -0
  11. package/dist/components/Footnotes.svelte.d.ts +13 -0
  12. package/dist/components/RecommendButton.svelte +153 -0
  13. package/dist/components/RecommendButton.svelte.d.ts +17 -0
  14. package/dist/components/ThemeProvider.svelte +92 -0
  15. package/dist/components/ThemeProvider.svelte.d.ts +13 -0
  16. package/dist/components/Toast.svelte +177 -0
  17. package/dist/components/Toast.svelte.d.ts +32 -0
  18. package/dist/components/Watermark.svelte +100 -0
  19. package/dist/components/Watermark.svelte.d.ts +17 -0
  20. package/dist/components/common/ThemedCard.svelte +15 -15
  21. package/dist/components/common/ThemedCard.svelte.d.ts +5 -0
  22. package/dist/components/document/BlockRenderer.svelte +3 -0
  23. package/dist/components/document/DocumentRenderer.svelte +41 -1
  24. package/dist/components/document/RichText.svelte +87 -2
  25. package/dist/components/document/RichText.svelte.d.ts +2 -0
  26. package/dist/components/document/blocks/OrderedListBlock.svelte +152 -0
  27. package/dist/components/document/blocks/UnorderedListBlock.svelte +1 -1
  28. package/dist/components/index.d.ts +28 -0
  29. package/dist/components/index.js +30 -0
  30. package/dist/index.d.ts +5 -4
  31. package/dist/index.js +6 -4
  32. package/dist/publisher.d.ts +73 -0
  33. package/dist/publisher.js +185 -0
  34. package/dist/schemas.d.ts +1162 -2
  35. package/dist/schemas.js +316 -0
  36. package/dist/types.d.ts +393 -2
  37. package/dist/types.js +1 -1
  38. package/dist/utils/native-comments.d.ts +68 -0
  39. package/dist/utils/native-comments.js +149 -0
  40. package/dist/utils/theme-helpers.d.ts +41 -1
  41. package/dist/utils/theme-helpers.js +98 -1
  42. package/dist/utils/theme.d.ts +48 -1
  43. package/dist/utils/theme.js +158 -0
  44. package/package.json +62 -65
  45. package/src/lib/components/ActionBar.svelte +85 -0
  46. package/src/lib/components/Avatar.svelte +104 -0
  47. package/src/lib/components/Comment.svelte +172 -0
  48. package/src/lib/components/CommentsSection.svelte +89 -0
  49. package/src/lib/components/DocumentCard.svelte +126 -56
  50. package/src/lib/components/Footnotes.svelte +72 -0
  51. package/src/lib/components/RecommendButton.svelte +153 -0
  52. package/src/lib/components/ThemeProvider.svelte +92 -0
  53. package/src/lib/components/Toast.svelte +177 -0
  54. package/src/lib/components/Watermark.svelte +100 -0
  55. package/src/lib/components/common/ThemedCard.svelte +15 -15
  56. package/src/lib/components/document/BlockRenderer.svelte +3 -0
  57. package/src/lib/components/document/DocumentRenderer.svelte +41 -1
  58. package/src/lib/components/document/RichText.svelte +87 -2
  59. package/src/lib/components/document/blocks/OrderedListBlock.svelte +152 -0
  60. package/src/lib/components/document/blocks/UnorderedListBlock.svelte +1 -1
  61. package/src/lib/components/index.ts +32 -0
  62. package/src/lib/index.ts +119 -5
  63. package/src/lib/publisher.ts +251 -0
  64. package/src/lib/schemas.ts +411 -0
  65. package/src/lib/types.ts +506 -2
  66. package/src/lib/utils/native-comments.ts +197 -0
  67. package/src/lib/utils/theme-helpers.ts +136 -3
  68. package/src/lib/utils/theme.ts +189 -1
  69. package/dist/components/document/blocks/UnorderedListBlock.svelte.d.ts +0 -9
@@ -0,0 +1,152 @@
1
+ <script lang="ts">
2
+ import RichText from '../RichText.svelte';
3
+ import OrderedListBlock from './OrderedListBlock.svelte';
4
+ import UnorderedListBlock from './UnorderedListBlock.svelte';
5
+ import HeaderBlock from './HeaderBlock.svelte';
6
+ import ImageBlock from './ImageBlock.svelte';
7
+
8
+ interface OrderedListContent {
9
+ plaintext: string;
10
+ facets?: any[];
11
+ textSize?: 'default' | 'small' | 'large';
12
+ level?: number;
13
+ image?: {
14
+ $type?: 'blob';
15
+ ref?: { $link: string };
16
+ mimeType?: string;
17
+ size?: number;
18
+ };
19
+ alt?: string;
20
+ aspectRatio?: { width: number; height: number };
21
+ }
22
+
23
+ interface OrderedListItem {
24
+ content?: OrderedListContent;
25
+ checked?: boolean;
26
+ children?: OrderedListItem[];
27
+ unorderedListChildren?: {
28
+ children: Array<{
29
+ content?: { plaintext: string; facets?: any[] };
30
+ children?: OrderedListItem[];
31
+ }>;
32
+ };
33
+ }
34
+
35
+ interface Props {
36
+ block: {
37
+ children: OrderedListItem[];
38
+ startIndex?: number;
39
+ };
40
+ hasTheme?: boolean;
41
+ did?: string;
42
+ pds?: string;
43
+ }
44
+
45
+ const { block, hasTheme = false, did = '', pds = '' }: Props = $props();
46
+
47
+ function isTextContent(content: OrderedListContent): boolean {
48
+ return !!(content?.plaintext && content.level === undefined && !content.image);
49
+ }
50
+
51
+ function isHeaderContent(content: OrderedListContent): boolean {
52
+ return !!(content?.level !== undefined);
53
+ }
54
+
55
+ function isImageContent(content: OrderedListContent): boolean {
56
+ return !!(content?.image);
57
+ }
58
+ </script>
59
+
60
+ <ol class="ordered-list pb-2" start={block.startIndex}>
61
+ {#each block.children as item, i}
62
+ <li class="flex flex-row gap-2 pb-0">
63
+ {#if item.checked !== undefined}
64
+ <!-- Checklist item -->
65
+ <div
66
+ class="checkbox-marker z-1 mx-2 mt-3.5 h-4 w-4 shrink-0 rounded border-2 flex items-center justify-center"
67
+ class:themed={hasTheme}
68
+ class:checked={item.checked}
69
+ >
70
+ {#if item.checked}
71
+ <svg class="h-3 w-3" viewBox="0 0 12 12" fill="currentColor">
72
+ <path d="M10.28 2.28L4.5 8.06 1.72 5.28 1 6l3.5 3.5 6.5-6.5-.72-.72z" />
73
+ </svg>
74
+ {/if}
75
+ </div>
76
+ {:else}
77
+ <!-- Regular numbered item -->
78
+ <div
79
+ class="list-number z-1 mx-2 mt-1 h-6 w-6 shrink-0 flex items-center justify-center text-sm font-medium"
80
+ class:themed={hasTheme}
81
+ >
82
+ {(block.startIndex || 1) + i}
83
+ </div>
84
+ {/if}
85
+
86
+ <div class="flex w-full flex-col">
87
+ {#if item.content}
88
+ <div class="textBlock mt-1 mb-2">
89
+ {#if isTextContent(item.content)}
90
+ <RichText plaintext={item.content.plaintext} facets={item.content.facets} {hasTheme} />
91
+ {:else if isHeaderContent(item.content)}
92
+ <HeaderBlock block={item.content as any} {hasTheme} />
93
+ {:else if isImageContent(item.content)}
94
+ <ImageBlock block={item.content as any} {did} {pds} {hasTheme} />
95
+ {/if}
96
+ </div>
97
+ {/if}
98
+
99
+ {#if item.children && item.children.length > 0}
100
+ <OrderedListBlock block={{ children: item.children }} {hasTheme} {did} {pds} />
101
+ {/if}
102
+
103
+ {#if item.unorderedListChildren && item.unorderedListChildren.children.length > 0}
104
+ <UnorderedListBlock block={{ children: item.unorderedListChildren.children }} {hasTheme} />
105
+ {/if}
106
+ </div>
107
+ </li>
108
+ {/each}
109
+ </ol>
110
+
111
+ <style>
112
+ .ordered-list {
113
+ list-style: none;
114
+ padding-left: 0;
115
+ margin-left: -1px;
116
+ counter-reset: item;
117
+ }
118
+
119
+ @media (min-width: 640px) {
120
+ .ordered-list {
121
+ margin-left: 9px;
122
+ }
123
+ }
124
+
125
+ .list-number {
126
+ color: rgb(107 114 128);
127
+ }
128
+
129
+ .list-number.themed {
130
+ color: var(--theme-accent);
131
+ }
132
+
133
+ .checkbox-marker {
134
+ border-color: rgb(107 114 128);
135
+ background-color: transparent;
136
+ }
137
+
138
+ .checkbox-marker.themed {
139
+ border-color: var(--theme-accent);
140
+ }
141
+
142
+ .checkbox-marker.checked {
143
+ background-color: rgb(107 114 128);
144
+ border-color: rgb(107 114 128);
145
+ color: white;
146
+ }
147
+
148
+ .checkbox-marker.checked.themed {
149
+ background-color: var(--theme-accent);
150
+ border-color: var(--theme-accent);
151
+ }
152
+ </style>
@@ -2,7 +2,7 @@
2
2
  import RichText from '../RichText.svelte';
3
3
  import UnorderedListBlock from './UnorderedListBlock.svelte';
4
4
 
5
- export interface ListItem {
5
+ interface ListItem {
6
6
  content?: {
7
7
  plaintext: string;
8
8
  facets?: any[];
@@ -13,3 +13,35 @@ export { default as ThemedCard } from './common/ThemedCard.svelte';
13
13
  // Document rendering
14
14
  export { default as DocumentRenderer } from './document/DocumentRenderer.svelte';
15
15
  export { default as MarkdownRenderer } from './document/MarkdownRenderer.svelte';
16
+ export { default as LinearDocumentRenderer } from './document/LinearDocumentRenderer.svelte';
17
+ export { default as CanvasRenderer } from './document/CanvasRenderer.svelte';
18
+ export { default as BlockRenderer } from './document/BlockRenderer.svelte';
19
+ export { default as RichText } from './document/RichText.svelte';
20
+
21
+ // Block components
22
+ export { default as TextBlock } from './document/blocks/TextBlock.svelte';
23
+ export { default as HeaderBlock } from './document/blocks/HeaderBlock.svelte';
24
+ export { default as BlockquoteBlock } from './document/blocks/BlockquoteBlock.svelte';
25
+ export { default as ImageBlock } from './document/blocks/ImageBlock.svelte';
26
+ export { default as CodeBlock } from './document/blocks/CodeBlock.svelte';
27
+ export { default as MathBlock } from './document/blocks/MathBlock.svelte';
28
+ export { default as UnorderedListBlock } from './document/blocks/UnorderedListBlock.svelte';
29
+ export { default as OrderedListBlock } from './document/blocks/OrderedListBlock.svelte';
30
+ export { default as HorizontalRuleBlock } from './document/blocks/HorizontalRuleBlock.svelte';
31
+ export { default as IframeBlock } from './document/blocks/IframeBlock.svelte';
32
+ export { default as WebsiteBlock } from './document/blocks/WebsiteBlock.svelte';
33
+ export { default as ButtonBlock } from './document/blocks/ButtonBlock.svelte';
34
+ export { default as BskyPostBlock } from './document/blocks/BskyPostBlock.svelte';
35
+ export { default as PollBlock } from './document/blocks/PollBlock.svelte';
36
+ export { default as PageBlock } from './document/blocks/PageBlock.svelte';
37
+
38
+ // UI components
39
+ export { default as Avatar } from './Avatar.svelte';
40
+ export { default as Toast } from './Toast.svelte';
41
+ export { default as Watermark } from './Watermark.svelte';
42
+ export { default as ActionBar } from './ActionBar.svelte';
43
+ export { default as RecommendButton } from './RecommendButton.svelte';
44
+ export { default as ThemeProvider } from './ThemeProvider.svelte';
45
+ export { default as Footnotes } from './Footnotes.svelte';
46
+ export { default as Comment } from './Comment.svelte';
47
+ export { default as CommentsSection } from './CommentsSection.svelte';
package/src/lib/index.ts CHANGED
@@ -14,7 +14,35 @@ export {
14
14
  ThemedText,
15
15
  ThemedCard,
16
16
  DocumentRenderer,
17
- MarkdownRenderer
17
+ MarkdownRenderer,
18
+ LinearDocumentRenderer,
19
+ CanvasRenderer,
20
+ BlockRenderer,
21
+ RichText,
22
+ TextBlock,
23
+ HeaderBlock,
24
+ BlockquoteBlock,
25
+ ImageBlock,
26
+ CodeBlock,
27
+ MathBlock,
28
+ UnorderedListBlock,
29
+ OrderedListBlock,
30
+ HorizontalRuleBlock,
31
+ IframeBlock,
32
+ WebsiteBlock,
33
+ ButtonBlock,
34
+ BskyPostBlock,
35
+ PollBlock,
36
+ PageBlock,
37
+ Avatar,
38
+ Toast,
39
+ Watermark,
40
+ ActionBar,
41
+ RecommendButton,
42
+ ThemeProvider,
43
+ Footnotes,
44
+ Comment,
45
+ CommentsSection
18
46
  } from './components/index.js';
19
47
 
20
48
  // Comments component
@@ -28,13 +56,66 @@ export type {
28
56
  AtProtoBlob,
29
57
  StrongRef,
30
58
  RGBColor,
59
+ RGBAColor,
60
+ Color,
61
+ BackgroundImage,
31
62
  BasicTheme,
63
+ ExtendedTheme,
32
64
  PublicationPreferences,
33
65
  Publication,
34
66
  Document,
35
67
  AtProtoRecord,
36
68
  ResolvedIdentity,
37
- SiteStandardConfig
69
+ SiteStandardConfig,
70
+ // Rich text types
71
+ ByteSlice,
72
+ LinkFeature,
73
+ DidMentionFeature,
74
+ AtMentionFeature,
75
+ CodeFeature,
76
+ HighlightFeature,
77
+ UnderlineFeature,
78
+ StrikethroughFeature,
79
+ BoldFeature,
80
+ ItalicFeature,
81
+ IdFeature,
82
+ FootnoteFeature,
83
+ FacetFeature,
84
+ Facet,
85
+ // Block types
86
+ TextBlock,
87
+ HeaderBlock,
88
+ BlockquoteBlock,
89
+ ImageBlock,
90
+ CodeBlock,
91
+ MathBlock,
92
+ OrderedListItem,
93
+ OrderedListBlock,
94
+ UnorderedListItem,
95
+ UnorderedListBlock,
96
+ HorizontalRuleBlock,
97
+ IframeBlock,
98
+ WebsiteBlock,
99
+ ButtonBlock,
100
+ BskyPostBlock,
101
+ PollBlock,
102
+ PageBlock,
103
+ Block,
104
+ // Content types
105
+ Position,
106
+ Quote,
107
+ LinearDocumentPage,
108
+ CanvasPage,
109
+ Content,
110
+ // Comment types
111
+ LinearDocumentQuote,
112
+ CommentReplyRef,
113
+ CommentRecord,
114
+ // Interaction types
115
+ RecommendRecord,
116
+ // Graph types
117
+ SubscriptionRecord,
118
+ LeafletSubscriptionRecord
38
119
  } from './types.js';
39
120
 
40
121
  // Schema exports
@@ -53,7 +134,21 @@ export { resolveIdentity, buildPdsBlobUrl } from './utils/agents.js';
53
134
 
54
135
  export { cache } from './utils/cache.js';
55
136
 
56
- export { rgbToCSS, rgbToHex, getThemeVars } from './utils/theme.js';
137
+ export {
138
+ rgbToCSS,
139
+ rgbaToCSS,
140
+ colorToCSS,
141
+ rgbToHex,
142
+ rgbaToHex,
143
+ getThemeVars,
144
+ isRGBA,
145
+ basicThemeToCssVars,
146
+ extendedThemeToCssVars,
147
+ themeToCssVars as anyThemeToCssVars,
148
+ getFontFamilyCSS,
149
+ getGoogleFontsUrl,
150
+ getAllThemeVars
151
+ } from './utils/theme.js';
57
152
 
58
153
  export {
59
154
  mixThemeColor,
@@ -61,7 +156,14 @@ export {
61
156
  getThemedBackground,
62
157
  getThemedBorder,
63
158
  getThemedAccent,
64
- themeToCssVars
159
+ getThemedPageBackground,
160
+ getBackgroundImageStyles,
161
+ getFontStyles,
162
+ getHeadingFontStyles,
163
+ getPageWidthStyles,
164
+ themeToCssVars,
165
+ extendedThemeToCssVars,
166
+ anyThemeToCssVars
65
167
  } from './utils/theme-helpers.js';
66
168
 
67
169
  export {
@@ -83,11 +185,23 @@ export {
83
185
 
84
186
  export type { TransformOptions, TransformResult } from './utils/content.js';
85
187
 
86
- // Comments exports
188
+ // Comments exports (Bluesky replies)
87
189
  export { fetchComments, fetchMentionComments, formatRelativeTime } from './utils/comments.js';
88
190
 
89
191
  export type { Comment, CommentAuthor, FetchCommentsOptions } from './utils/comments.js';
90
192
 
193
+ // Native comments exports
194
+ export {
195
+ COMMENTS_COLLECTION,
196
+ createCommentRecord,
197
+ parseCommentUri,
198
+ buildCommentUri,
199
+ fetchComments as fetchNativeComments,
200
+ organizeCommentsIntoThreads,
201
+ countThreadComments,
202
+ extractQuotedText
203
+ } from './utils/native-comments.js';
204
+
91
205
  // Verification exports
92
206
  export {
93
207
  generatePublicationWellKnown,
@@ -484,6 +484,257 @@ export class StandardSitePublisher {
484
484
  getAtpAgent(): AtpAgent {
485
485
  return this.getAgent();
486
486
  }
487
+
488
+ // ============================================
489
+ // Comment Methods (pub.leaflet.comment)
490
+ // ============================================
491
+
492
+ /**
493
+ * Publish a comment on a document
494
+ */
495
+ async publishComment(input: {
496
+ /** AT-URI of the document being commented on */
497
+ subject: string;
498
+ /** Comment text */
499
+ plaintext: string;
500
+ /** Facets for rich text */
501
+ facets?: any[];
502
+ /** Parent comment AT-URI if replying */
503
+ parent?: string;
504
+ /** Page ID if commenting on a specific page */
505
+ onPage?: string;
506
+ /** Quote attachment */
507
+ attachment?: {
508
+ document: string;
509
+ quote?: {
510
+ start: { block: number[]; offset: number };
511
+ end: { block: number[]; offset: number };
512
+ };
513
+ };
514
+ }): Promise<PublishResult> {
515
+ const did = this.getDid();
516
+ const agent = this.getAgent();
517
+
518
+ const record: any = {
519
+ $type: 'pub.leaflet.comment',
520
+ subject: input.subject,
521
+ plaintext: input.plaintext,
522
+ createdAt: new Date().toISOString()
523
+ };
524
+
525
+ if (input.parent) {
526
+ record.reply = {
527
+ $type: 'pub.leaflet.comment#replyRef',
528
+ parent: input.parent
529
+ };
530
+ }
531
+
532
+ if (input.facets) {
533
+ record.facets = input.facets;
534
+ }
535
+
536
+ if (input.onPage) {
537
+ record.onPage = input.onPage;
538
+ }
539
+
540
+ if (input.attachment) {
541
+ record.attachment = {
542
+ $type: 'pub.leaflet.comment#linearDocumentQuote',
543
+ ...input.attachment
544
+ };
545
+ }
546
+
547
+ const rkey = generateTid();
548
+
549
+ const response = await agent.api.com.atproto.repo.createRecord({
550
+ repo: did,
551
+ collection: 'pub.leaflet.comment',
552
+ rkey,
553
+ record
554
+ });
555
+
556
+ return {
557
+ uri: response.data.uri,
558
+ cid: response.data.cid
559
+ };
560
+ }
561
+
562
+ /**
563
+ * Delete a comment
564
+ */
565
+ async deleteComment(rkey: string): Promise<void> {
566
+ const did = this.getDid();
567
+ const agent = this.getAgent();
568
+
569
+ await agent.api.com.atproto.repo.deleteRecord({
570
+ repo: did,
571
+ collection: 'pub.leaflet.comment',
572
+ rkey
573
+ });
574
+ }
575
+
576
+ // ============================================
577
+ // Recommend Methods (pub.leaflet.interactions.recommend)
578
+ // ============================================
579
+
580
+ /**
581
+ * Recommend a document
582
+ */
583
+ async recommendDocument(subject: string): Promise<PublishResult> {
584
+ const did = this.getDid();
585
+ const agent = this.getAgent();
586
+
587
+ const record = {
588
+ $type: 'pub.leaflet.interactions.recommend',
589
+ subject,
590
+ createdAt: new Date().toISOString()
591
+ };
592
+
593
+ const rkey = generateTid();
594
+
595
+ const response = await agent.api.com.atproto.repo.createRecord({
596
+ repo: did,
597
+ collection: 'pub.leaflet.interactions.recommend',
598
+ rkey,
599
+ record
600
+ });
601
+
602
+ return {
603
+ uri: response.data.uri,
604
+ cid: response.data.cid
605
+ };
606
+ }
607
+
608
+ /**
609
+ * Remove a recommendation
610
+ */
611
+ async unrecommendDocument(rkey: string): Promise<void> {
612
+ const did = this.getDid();
613
+ const agent = this.getAgent();
614
+
615
+ await agent.api.com.atproto.repo.deleteRecord({
616
+ repo: did,
617
+ collection: 'pub.leaflet.interactions.recommend',
618
+ rkey
619
+ });
620
+ }
621
+
622
+ /**
623
+ * Check if the current user has recommended a document
624
+ */
625
+ async hasRecommended(subject: string): Promise<{ recommended: boolean; rkey?: string }> {
626
+ const did = this.getDid();
627
+ const agent = this.getAgent();
628
+
629
+ const response = await agent.api.com.atproto.repo.listRecords({
630
+ repo: did,
631
+ collection: 'pub.leaflet.interactions.recommend',
632
+ limit: 100
633
+ });
634
+
635
+ const record = response.data.records.find(
636
+ (r: any) => r.value?.subject === subject
637
+ );
638
+
639
+ if (record) {
640
+ const rkey = record.uri.split('/').pop();
641
+ return { recommended: true, rkey };
642
+ }
643
+
644
+ return { recommended: false };
645
+ }
646
+
647
+ // ============================================
648
+ // Subscription Methods (site.standard.graph.subscription)
649
+ // ============================================
650
+
651
+ /**
652
+ * Subscribe to a publication
653
+ */
654
+ async subscribeToPublication(publication: string): Promise<PublishResult> {
655
+ const did = this.getDid();
656
+ const agent = this.getAgent();
657
+
658
+ const record = {
659
+ $type: 'site.standard.graph.subscription',
660
+ publication
661
+ };
662
+
663
+ const rkey = generateTid();
664
+
665
+ const response = await agent.api.com.atproto.repo.createRecord({
666
+ repo: did,
667
+ collection: 'site.standard.graph.subscription',
668
+ rkey,
669
+ record
670
+ });
671
+
672
+ return {
673
+ uri: response.data.uri,
674
+ cid: response.data.cid
675
+ };
676
+ }
677
+
678
+ /**
679
+ * Unsubscribe from a publication
680
+ */
681
+ async unsubscribeFromPublication(rkey: string): Promise<void> {
682
+ const did = this.getDid();
683
+ const agent = this.getAgent();
684
+
685
+ await agent.api.com.atproto.repo.deleteRecord({
686
+ repo: did,
687
+ collection: 'site.standard.graph.subscription',
688
+ rkey
689
+ });
690
+ }
691
+
692
+ /**
693
+ * List subscriptions for the current user
694
+ */
695
+ async listSubscriptions(
696
+ limit = 100
697
+ ): Promise<Array<{ uri: string; cid: string; value: { publication: string } }>> {
698
+ const did = this.getDid();
699
+ const agent = this.getAgent();
700
+
701
+ const response = await agent.api.com.atproto.repo.listRecords({
702
+ repo: did,
703
+ collection: 'site.standard.graph.subscription',
704
+ limit
705
+ });
706
+
707
+ return response.data.records.map((r) => ({
708
+ uri: r.uri,
709
+ cid: r.cid,
710
+ value: r.value as { publication: string }
711
+ }));
712
+ }
713
+
714
+ /**
715
+ * Check if subscribed to a publication
716
+ */
717
+ async isSubscribed(publication: string): Promise<{ subscribed: boolean; rkey?: string }> {
718
+ const did = this.getDid();
719
+ const agent = this.getAgent();
720
+
721
+ const response = await agent.api.com.atproto.repo.listRecords({
722
+ repo: did,
723
+ collection: 'site.standard.graph.subscription',
724
+ limit: 100
725
+ });
726
+
727
+ const record = response.data.records.find(
728
+ (r: any) => r.value?.publication === publication
729
+ );
730
+
731
+ if (record) {
732
+ const rkey = record.uri.split('/').pop();
733
+ return { subscribed: true, rkey };
734
+ }
735
+
736
+ return { subscribed: false };
737
+ }
487
738
  }
488
739
 
489
740
  export type { PublisherConfig };