@rmdes/indiekit-endpoint-webmention-io 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,270 @@
1
+ # @rmdes/indiekit-endpoint-webmention-io
2
+
3
+ Webmention moderation endpoint for [Indiekit](https://getindiekit.com). Syncs webmentions from webmention.io into MongoDB with delete, block, and privacy removal capabilities.
4
+
5
+ ## Features
6
+
7
+ - **Background Sync**: Automatically fetches webmentions from webmention.io every 15 minutes (configurable)
8
+ - **Moderation Dashboard**: Admin UI for hiding/unhiding webmentions
9
+ - **Domain Blocking**: Block spam domains (hides all mentions, blocks future ones)
10
+ - **Privacy Removal**: GDPR-compliant permanent deletion with domain blocking
11
+ - **Public JSON API**: Drop-in replacement for webmention.io API with server-side caching
12
+ - **MongoDB Storage**: Persistent storage with indexes for fast queries
13
+ - **Incremental Sync**: Only fetches new webmentions since last sync (efficient)
14
+ - **Full Re-sync**: Option to clear and re-import all webmentions
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @rmdes/indiekit-endpoint-webmention-io
20
+ ```
21
+
22
+ ## Configuration
23
+
24
+ ```javascript
25
+ // indiekit.config.js
26
+ export default {
27
+ plugins: [
28
+ "@rmdes/indiekit-endpoint-webmention-io",
29
+ ],
30
+
31
+ "@rmdes/indiekit-endpoint-webmention-io": {
32
+ mountPath: "/webmentions", // Optional, default "/webmentions"
33
+ token: process.env.WEBMENTION_IO_TOKEN, // REQUIRED: webmention.io API token
34
+ domain: "example.com", // REQUIRED: domain to fetch webmentions for
35
+ syncInterval: 900_000, // Optional, default 15 minutes (in ms)
36
+ cacheTtl: 60, // Optional, default 60 seconds (public API cache)
37
+ },
38
+ };
39
+ ```
40
+
41
+ ### Getting Your Webmention.io Token
42
+
43
+ 1. Sign up at [webmention.io](https://webmention.io)
44
+ 2. Add your domain
45
+ 3. Find your token in the dashboard
46
+ 4. Store it in your `.env` file:
47
+ ```bash
48
+ WEBMENTION_IO_TOKEN=your_token_here
49
+ ```
50
+
51
+ ## Usage
52
+
53
+ ### Admin Dashboard
54
+
55
+ Visit `/webmentions` in your Indiekit admin panel to:
56
+
57
+ - View all webmentions (paginated)
58
+ - Filter by visibility (all/visible/hidden)
59
+ - Filter by type (likes/replies/reposts/mentions)
60
+ - Hide/unhide individual webmentions
61
+ - Block spam domains
62
+ - Remove mentions for privacy requests (GDPR)
63
+
64
+ ### Manual Sync
65
+
66
+ Trigger sync via admin dashboard buttons:
67
+ - **Sync Now**: Incremental sync (fetch only new mentions since last sync)
68
+ - **Full Re-sync**: Delete all and re-import everything from webmention.io
69
+
70
+ Or via POST requests:
71
+ ```bash
72
+ # Incremental sync
73
+ curl -X POST https://your-site.com/webmentions/sync
74
+
75
+ # Full re-sync (destructive!)
76
+ curl -X POST https://your-site.com/webmentions/sync/full
77
+ ```
78
+
79
+ ### Public JSON API
80
+
81
+ The plugin exposes a public JSON API at `/webmentions/api/mentions` that can replace direct calls to webmention.io:
82
+
83
+ **Fetch all webmentions:**
84
+ ```javascript
85
+ fetch('/webmentions/api/mentions?page=0&per-page=50')
86
+ ```
87
+
88
+ **Filter by target URL:**
89
+ ```javascript
90
+ fetch('/webmentions/api/mentions?target=https://example.com/post')
91
+ ```
92
+
93
+ **Filter by type:**
94
+ ```javascript
95
+ fetch('/webmentions/api/mentions?wm-property=like-of')
96
+ ```
97
+
98
+ **Response format (JF2):**
99
+ ```json
100
+ {
101
+ "type": "feed",
102
+ "name": "Webmentions",
103
+ "children": [
104
+ {
105
+ "type": "entry",
106
+ "wm-id": 12345,
107
+ "wm-received": "2025-02-13T10:00:00.000Z",
108
+ "wm-property": "in-reply-to",
109
+ "wm-target": "https://example.com/post",
110
+ "author": {
111
+ "type": "card",
112
+ "name": "Author Name",
113
+ "url": "https://author.site/",
114
+ "photo": "https://author.site/photo.jpg"
115
+ },
116
+ "url": "https://source.site/post",
117
+ "published": "2025-02-13T09:00:00.000Z",
118
+ "content": {
119
+ "html": "<p>Reply text...</p>",
120
+ "text": "Reply text..."
121
+ }
122
+ }
123
+ ]
124
+ }
125
+ ```
126
+
127
+ ### Moderation Workflows
128
+
129
+ #### Hide a webmention
130
+ ```bash
131
+ POST /webmentions/:wmId/hide
132
+ ```
133
+ Marks the webmention as hidden (won't appear in public API).
134
+
135
+ #### Unhide a webmention
136
+ ```bash
137
+ POST /webmentions/:wmId/unhide
138
+ ```
139
+ Restores a hidden webmention.
140
+
141
+ #### Block a domain
142
+ ```bash
143
+ POST /webmentions/block
144
+ Body: domain=spam.example.com
145
+ ```
146
+ - Hides all existing mentions from the domain
147
+ - Adds domain to blocklist
148
+ - Future mentions from this domain are filtered during sync
149
+
150
+ #### Privacy removal (GDPR)
151
+ ```bash
152
+ POST /webmentions/privacy-remove
153
+ Body: domain=user-request.example.com
154
+ ```
155
+ - **Permanently deletes** all mentions from the domain
156
+ - Adds domain to blocklist with reason="privacy"
157
+ - Irreversible - use for GDPR/privacy requests only
158
+
159
+ #### Unblock a domain
160
+ ```bash
161
+ POST /webmentions/blocklist/:domain/delete
162
+ ```
163
+ - Removes domain from blocklist
164
+ - Unhides mentions that were hidden by the blocklist (not manual or privacy)
165
+
166
+ ## API Reference
167
+
168
+ ### Query Parameters
169
+
170
+ | Parameter | Type | Description |
171
+ |-----------|------|-------------|
172
+ | `page` | number | Page number (0-indexed, default: 0) |
173
+ | `per-page` | number | Items per page (max 10,000, default: 50) |
174
+ | `target` | string | Filter by target URL (with/without trailing slash) |
175
+ | `wm-property` | string | Filter by type: `in-reply-to`, `like-of`, `repost-of`, `mention-of`, `bookmark-of`, `rsvp` |
176
+
177
+ ### Webmention Types
178
+
179
+ - `in-reply-to` - Replies
180
+ - `like-of` - Likes
181
+ - `repost-of` - Reposts/boosts
182
+ - `mention-of` - General mentions
183
+ - `bookmark-of` - Bookmarks
184
+ - `rsvp` - RSVP responses
185
+
186
+ ## MongoDB Schema
187
+
188
+ The plugin creates two MongoDB collections:
189
+
190
+ ### `webmentions`
191
+
192
+ ```javascript
193
+ {
194
+ wmId: 12345, // Webmention ID (unique)
195
+ wmReceived: "2025-02-13T10:00:00.000Z",
196
+ wmProperty: "in-reply-to",
197
+ wmTarget: "https://example.com/post",
198
+ authorName: "Author Name",
199
+ authorUrl: "https://author.site/",
200
+ authorPhoto: "https://author.site/photo.jpg",
201
+ sourceUrl: "https://source.site/post",
202
+ sourceDomain: "source.site",
203
+ published: "2025-02-13T09:00:00.000Z",
204
+ contentHtml: "<p>Reply text...</p>",
205
+ contentText: "Reply text...",
206
+ name: "Post title",
207
+ hidden: false,
208
+ hiddenAt: null,
209
+ hiddenReason: null, // "manual", "blocklist", "privacy"
210
+ syncedAt: "2025-02-13T10:00:00.000Z",
211
+ raw: { ... } // Original JF2 entry
212
+ }
213
+ ```
214
+
215
+ ### `webmentionBlocklist`
216
+
217
+ ```javascript
218
+ {
219
+ domain: "spam.example.com",
220
+ reason: "spam", // "spam", "privacy", "manual"
221
+ blockedAt: "2025-02-13T10:00:00.000Z",
222
+ mentionsHidden: 5
223
+ }
224
+ ```
225
+
226
+ ## How It Works
227
+
228
+ 1. **Background Sync**: Runs every 15 minutes (configurable)
229
+ 2. **Incremental Fetching**: Uses `since_id` to only fetch new mentions
230
+ 3. **Blocklist Filtering**: Mentions from blocked domains are never stored
231
+ 4. **Pagination**: Fetches 100 mentions per page from webmention.io
232
+ 5. **Rate Limiting**: 500ms delay between pages to avoid rate limits
233
+ 6. **Caching**: Public API responses cached for 60 seconds (configurable)
234
+
235
+ ## HTML Sanitization
236
+
237
+ All webmention HTML content is sanitized:
238
+ - Strips empty bridgy links
239
+ - Strips empty paragraphs
240
+ - Downgrades heading levels (h1→h3, h2→h4)
241
+ - Normalizes line breaks to paragraph breaks
242
+
243
+ ## Comparison with Other Plugins
244
+
245
+ | Plugin | Purpose | Storage | API |
246
+ |--------|---------|---------|-----|
247
+ | **@rmdes/indiekit-endpoint-webmention-io** | Full moderation + public API | MongoDB | JF2 JSON |
248
+ | `@rmdes/indiekit-endpoint-webmentions-proxy` | Simple proxy (no moderation) | None | JF2 JSON |
249
+ | `@indiekit/endpoint-webmention` (upstream) | Admin dashboard only | None | HTML only |
250
+
251
+ Use this plugin if you need:
252
+ - Moderation capabilities
253
+ - Domain blocking
254
+ - Privacy removal (GDPR)
255
+ - Public API with caching
256
+ - Persistent storage
257
+
258
+ Use `@rmdes/indiekit-endpoint-webmentions-proxy` if you only need a simple public API without moderation.
259
+
260
+ ## License
261
+
262
+ MIT
263
+
264
+ ## Author
265
+
266
+ Ricardo Mendes - [rmendes.net](https://rmendes.net)
267
+
268
+ ## Repository
269
+
270
+ [https://github.com/rmdes/indiekit-endpoint-webmention-io](https://github.com/rmdes/indiekit-endpoint-webmention-io)
@@ -0,0 +1,75 @@
1
+ {
2
+ "webmention-io": {
3
+ "title": "Webmentions",
4
+ "webmentions": {
5
+ "none": "Keine Webmentions gefunden. Versuchen Sie eine Synchronisierung."
6
+ },
7
+ "mention": {
8
+ "bookmark-of": "hat %s mit einem Lesezeichen versehen",
9
+ "in-reply-to": "hat auf %s geantwortet",
10
+ "like-of": "gefällt %s",
11
+ "mention-of": "hat %s erwähnt",
12
+ "repost-of": "hat %s geteilt",
13
+ "rsvp": "hat auf %s geantwortet"
14
+ },
15
+ "sync": {
16
+ "now": "Jetzt synchronisieren",
17
+ "full": "Vollständige Neusynchronisierung",
18
+ "lastSync": "Zuletzt synchronisiert",
19
+ "never": "Nie synchronisiert",
20
+ "synced": "Synchronisierung abgeschlossen",
21
+ "added": "neue Erwähnungen hinzugefügt",
22
+ "inProgress": "Synchronisierung läuft…"
23
+ },
24
+ "filter": {
25
+ "all": "Alle",
26
+ "visible": "Sichtbar",
27
+ "hidden": "Versteckt",
28
+ "show": "Anzeigen",
29
+ "type": "Typ",
30
+ "likes": "Gefällt mir",
31
+ "replies": "Antworten",
32
+ "reposts": "Geteilte Beiträge",
33
+ "mentions": "Erwähnungen"
34
+ },
35
+ "actions": {
36
+ "hide": "Verstecken",
37
+ "unhide": "Einblenden",
38
+ "block": "Blockieren",
39
+ "hidden": "Versteckt",
40
+ "reasonManual": "manuell",
41
+ "reasonBlocklist": "Sperrliste",
42
+ "reasonPrivacy": "Datenschutz"
43
+ },
44
+ "blocklist": {
45
+ "title": "Webmention-Sperrliste",
46
+ "description": "Blockierte Domains werden nicht in Webmentions angezeigt. Vorhandene Erwähnungen von blockierten Domains werden automatisch ausgeblendet.",
47
+ "add": "Domain blockieren",
48
+ "domainLabel": "Domain",
49
+ "domainPlaceholder": "spam.example.com",
50
+ "reasonLabel": "Grund",
51
+ "reasonSpam": "Spam",
52
+ "reasonManual": "Manuell",
53
+ "blockButton": "Domain blockieren",
54
+ "unblock": "Entsperren",
55
+ "empty": "Keine Domains blockiert.",
56
+ "privacy": {
57
+ "title": "Datenschutzentfernung",
58
+ "description": "Alle Webmentions von einer Domain dauerhaft löschen und zukünftige blockieren. Verwenden Sie dies für GDPR- oder persönliche Entfernungsanfragen.",
59
+ "domainLabel": "Zu entfernende Domain",
60
+ "removeButton": "Entfernen & Blockieren"
61
+ },
62
+ "blocked": "Domain blockiert",
63
+ "unblocked": "Domain entsperrt",
64
+ "removed": "Erwähnungen dauerhaft gelöscht",
65
+ "unhidden": "Erwähnungen wiederhergestellt",
66
+ "mentionsHidden": "Erwähnungen ausgeblendet",
67
+ "blockedAt": "Blockiert"
68
+ },
69
+ "counts": {
70
+ "total": "gesamt",
71
+ "hidden": "versteckt",
72
+ "visible": "sichtbar"
73
+ }
74
+ }
75
+ }
@@ -0,0 +1,75 @@
1
+ {
2
+ "webmention-io": {
3
+ "title": "Webmentions",
4
+ "webmentions": {
5
+ "none": "No se encontraron webmentions. Intentá ejecutar una sincronización."
6
+ },
7
+ "mention": {
8
+ "bookmark-of": "marcó %s",
9
+ "in-reply-to": "respondió a %s",
10
+ "like-of": "le gustó %s",
11
+ "mention-of": "mencionó %s",
12
+ "repost-of": "compartió %s",
13
+ "rsvp": "respondió a %s"
14
+ },
15
+ "sync": {
16
+ "now": "Sincronizar ahora",
17
+ "full": "Resincronización completa",
18
+ "lastSync": "Última sincronización",
19
+ "never": "Nunca sincronizado",
20
+ "synced": "Sincronización completada",
21
+ "added": "nuevas menciones agregadas",
22
+ "inProgress": "Sincronización en curso…"
23
+ },
24
+ "filter": {
25
+ "all": "Todos",
26
+ "visible": "Visible",
27
+ "hidden": "Oculto",
28
+ "show": "Mostrar",
29
+ "type": "Tipo",
30
+ "likes": "Me gusta",
31
+ "replies": "Respuestas",
32
+ "reposts": "Compartidos",
33
+ "mentions": "Menciones"
34
+ },
35
+ "actions": {
36
+ "hide": "Ocultar",
37
+ "unhide": "Mostrar",
38
+ "block": "Bloquear",
39
+ "hidden": "Oculto",
40
+ "reasonManual": "manual",
41
+ "reasonBlocklist": "lista de bloqueo",
42
+ "reasonPrivacy": "privacidad"
43
+ },
44
+ "blocklist": {
45
+ "title": "Lista de bloqueo de Webmentions",
46
+ "description": "Los dominios bloqueados no aparecerán en webmentions. Las menciones existentes de dominios bloqueados se ocultan automáticamente.",
47
+ "add": "Bloquear un dominio",
48
+ "domainLabel": "Dominio",
49
+ "domainPlaceholder": "spam.example.com",
50
+ "reasonLabel": "Motivo",
51
+ "reasonSpam": "Spam",
52
+ "reasonManual": "Manual",
53
+ "blockButton": "Bloquear dominio",
54
+ "unblock": "Desbloquear",
55
+ "empty": "No hay dominios bloqueados.",
56
+ "privacy": {
57
+ "title": "Eliminación por privacidad",
58
+ "description": "Eliminar permanentemente todos los webmentions de un dominio y bloquear futuros. Usar para solicitudes GDPR o de eliminación personal.",
59
+ "domainLabel": "Dominio a eliminar",
60
+ "removeButton": "Eliminar y bloquear"
61
+ },
62
+ "blocked": "Dominio bloqueado",
63
+ "unblocked": "Dominio desbloqueado",
64
+ "removed": "menciones eliminadas permanentemente",
65
+ "unhidden": "menciones restauradas",
66
+ "mentionsHidden": "menciones ocultas",
67
+ "blockedAt": "Bloqueado"
68
+ },
69
+ "counts": {
70
+ "total": "total",
71
+ "hidden": "oculto",
72
+ "visible": "visible"
73
+ }
74
+ }
75
+ }
@@ -0,0 +1,75 @@
1
+ {
2
+ "webmention-io": {
3
+ "title": "Webmentions",
4
+ "webmentions": {
5
+ "none": "No se han encontrado webmentions. Intente ejecutar una sincronización."
6
+ },
7
+ "mention": {
8
+ "bookmark-of": "marcó %s",
9
+ "in-reply-to": "respondió a %s",
10
+ "like-of": "le gustó %s",
11
+ "mention-of": "mencionó %s",
12
+ "repost-of": "reenvió %s",
13
+ "rsvp": "respondió a %s"
14
+ },
15
+ "sync": {
16
+ "now": "Sincronizar ahora",
17
+ "full": "Resincronización completa",
18
+ "lastSync": "Última sincronización",
19
+ "never": "Nunca sincronizado",
20
+ "synced": "Sincronización completada",
21
+ "added": "nuevas menciones añadidas",
22
+ "inProgress": "Sincronización en curso…"
23
+ },
24
+ "filter": {
25
+ "all": "Todos",
26
+ "visible": "Visible",
27
+ "hidden": "Oculto",
28
+ "show": "Mostrar",
29
+ "type": "Tipo",
30
+ "likes": "Me gusta",
31
+ "replies": "Respuestas",
32
+ "reposts": "Reenvíos",
33
+ "mentions": "Menciones"
34
+ },
35
+ "actions": {
36
+ "hide": "Ocultar",
37
+ "unhide": "Mostrar",
38
+ "block": "Bloquear",
39
+ "hidden": "Oculto",
40
+ "reasonManual": "manual",
41
+ "reasonBlocklist": "lista de bloqueo",
42
+ "reasonPrivacy": "privacidad"
43
+ },
44
+ "blocklist": {
45
+ "title": "Lista de bloqueo de Webmentions",
46
+ "description": "Los dominios bloqueados no aparecerán en webmentions. Las menciones existentes de dominios bloqueados se ocultan automáticamente.",
47
+ "add": "Bloquear un dominio",
48
+ "domainLabel": "Dominio",
49
+ "domainPlaceholder": "spam.example.com",
50
+ "reasonLabel": "Motivo",
51
+ "reasonSpam": "Spam",
52
+ "reasonManual": "Manual",
53
+ "blockButton": "Bloquear dominio",
54
+ "unblock": "Desbloquear",
55
+ "empty": "No hay dominios bloqueados.",
56
+ "privacy": {
57
+ "title": "Eliminación por privacidad",
58
+ "description": "Eliminar permanentemente todos los webmentions de un dominio y bloquear futuros. Usar para solicitudes GDPR o de eliminación personal.",
59
+ "domainLabel": "Dominio a eliminar",
60
+ "removeButton": "Eliminar y bloquear"
61
+ },
62
+ "blocked": "Dominio bloqueado",
63
+ "unblocked": "Dominio desbloqueado",
64
+ "removed": "menciones eliminadas permanentemente",
65
+ "unhidden": "menciones restauradas",
66
+ "mentionsHidden": "menciones ocultas",
67
+ "blockedAt": "Bloqueado"
68
+ },
69
+ "counts": {
70
+ "total": "total",
71
+ "hidden": "oculto",
72
+ "visible": "visible"
73
+ }
74
+ }
75
+ }
@@ -0,0 +1,75 @@
1
+ {
2
+ "webmention-io": {
3
+ "title": "Webmentions",
4
+ "webmentions": {
5
+ "none": "Aucun webmention trouvé. Essayez d'exécuter une synchronisation."
6
+ },
7
+ "mention": {
8
+ "bookmark-of": "a mis %s en signet",
9
+ "in-reply-to": "a répondu à %s",
10
+ "like-of": "a aimé %s",
11
+ "mention-of": "a mentionné %s",
12
+ "repost-of": "a repartagé %s",
13
+ "rsvp": "a répondu à %s"
14
+ },
15
+ "sync": {
16
+ "now": "Synchroniser maintenant",
17
+ "full": "Resynchronisation complète",
18
+ "lastSync": "Dernière synchronisation",
19
+ "never": "Jamais synchronisé",
20
+ "synced": "Synchronisation terminée",
21
+ "added": "nouvelles mentions ajoutées",
22
+ "inProgress": "Synchronisation en cours…"
23
+ },
24
+ "filter": {
25
+ "all": "Tous",
26
+ "visible": "Visible",
27
+ "hidden": "Masqué",
28
+ "show": "Afficher",
29
+ "type": "Type",
30
+ "likes": "J'aime",
31
+ "replies": "Réponses",
32
+ "reposts": "Repartages",
33
+ "mentions": "Mentions"
34
+ },
35
+ "actions": {
36
+ "hide": "Masquer",
37
+ "unhide": "Afficher",
38
+ "block": "Bloquer",
39
+ "hidden": "Masqué",
40
+ "reasonManual": "manuel",
41
+ "reasonBlocklist": "liste de blocage",
42
+ "reasonPrivacy": "confidentialité"
43
+ },
44
+ "blocklist": {
45
+ "title": "Liste de blocage Webmention",
46
+ "description": "Les domaines bloqués n'apparaîtront pas dans les webmentions. Les mentions existantes de domaines bloqués sont automatiquement masquées.",
47
+ "add": "Bloquer un domaine",
48
+ "domainLabel": "Domaine",
49
+ "domainPlaceholder": "spam.example.com",
50
+ "reasonLabel": "Raison",
51
+ "reasonSpam": "Spam",
52
+ "reasonManual": "Manuel",
53
+ "blockButton": "Bloquer le domaine",
54
+ "unblock": "Débloquer",
55
+ "empty": "Aucun domaine bloqué.",
56
+ "privacy": {
57
+ "title": "Suppression pour confidentialité",
58
+ "description": "Supprimer définitivement tous les webmentions d'un domaine et bloquer les futurs. À utiliser pour les demandes GDPR ou de suppression personnelle.",
59
+ "domainLabel": "Domaine à supprimer",
60
+ "removeButton": "Supprimer et bloquer"
61
+ },
62
+ "blocked": "Domaine bloqué",
63
+ "unblocked": "Domaine débloqué",
64
+ "removed": "mentions supprimées définitivement",
65
+ "unhidden": "mentions restaurées",
66
+ "mentionsHidden": "mentions masquées",
67
+ "blockedAt": "Bloqué"
68
+ },
69
+ "counts": {
70
+ "total": "total",
71
+ "hidden": "masqué",
72
+ "visible": "visible"
73
+ }
74
+ }
75
+ }
@@ -0,0 +1,75 @@
1
+ {
2
+ "webmention-io": {
3
+ "title": "Webmentions",
4
+ "webmentions": {
5
+ "none": "कोई webmention नहीं मिला। सिंक चलाने का प्रयास करें।"
6
+ },
7
+ "mention": {
8
+ "bookmark-of": "%s को बुकमार्क किया",
9
+ "in-reply-to": "%s का जवाब दिया",
10
+ "like-of": "%s को पसंद किया",
11
+ "mention-of": "%s का उल्लेख किया",
12
+ "repost-of": "%s को रीपोस्ट किया",
13
+ "rsvp": "%s का जवाब दिया"
14
+ },
15
+ "sync": {
16
+ "now": "अभी सिंक करें",
17
+ "full": "पूर्ण पुनः सिंक",
18
+ "lastSync": "अंतिम सिंक",
19
+ "never": "कभी सिंक नहीं किया",
20
+ "synced": "सिंक पूरा हुआ",
21
+ "added": "नए उल्लेख जोड़े गए",
22
+ "inProgress": "सिंक प्रगति में है…"
23
+ },
24
+ "filter": {
25
+ "all": "सभी",
26
+ "visible": "दृश्यमान",
27
+ "hidden": "छिपा हुआ",
28
+ "show": "दिखाएं",
29
+ "type": "प्रकार",
30
+ "likes": "पसंद",
31
+ "replies": "जवाब",
32
+ "reposts": "रीपोस्ट",
33
+ "mentions": "उल्लेख"
34
+ },
35
+ "actions": {
36
+ "hide": "छिपाएं",
37
+ "unhide": "दिखाएं",
38
+ "block": "ब्लॉक करें",
39
+ "hidden": "छिपा हुआ",
40
+ "reasonManual": "मैनुअल",
41
+ "reasonBlocklist": "ब्लॉक सूची",
42
+ "reasonPrivacy": "गोपनीयता"
43
+ },
44
+ "blocklist": {
45
+ "title": "Webmention ब्लॉक सूची",
46
+ "description": "ब्लॉक किए गए डोमेन webmention में दिखाई नहीं देंगे। ब्लॉक किए गए डोमेन के मौजूदा उल्लेख स्वचालित रूप से छिपा दिए जाते हैं।",
47
+ "add": "एक डोमेन ब्लॉक करें",
48
+ "domainLabel": "डोमेन",
49
+ "domainPlaceholder": "spam.example.com",
50
+ "reasonLabel": "कारण",
51
+ "reasonSpam": "स्पैम",
52
+ "reasonManual": "मैनुअल",
53
+ "blockButton": "डोमेन ब्लॉक करें",
54
+ "unblock": "अनब्लॉक करें",
55
+ "empty": "कोई डोमेन ब्लॉक नहीं किया गया।",
56
+ "privacy": {
57
+ "title": "गोपनीयता हटाना",
58
+ "description": "किसी डोमेन से सभी webmention स्थायी रूप से हटाएं और भविष्य के को ब्लॉक करें। GDPR या व्यक्तिगत हटाने के अनुरोधों के लिए उपयोग करें।",
59
+ "domainLabel": "हटाने के लिए डोमेन",
60
+ "removeButton": "हटाएं और ब्लॉक करें"
61
+ },
62
+ "blocked": "डोमेन ब्लॉक किया गया",
63
+ "unblocked": "डोमेन अनब्लॉक किया गया",
64
+ "removed": "उल्लेख स्थायी रूप से हटा दिए गए",
65
+ "unhidden": "उल्लेख पुनर्स्थापित किए गए",
66
+ "mentionsHidden": "उल्लेख छिपाए गए",
67
+ "blockedAt": "ब्लॉक किया गया"
68
+ },
69
+ "counts": {
70
+ "total": "कुल",
71
+ "hidden": "छिपा हुआ",
72
+ "visible": "दृश्यमान"
73
+ }
74
+ }
75
+ }