AT protocol bookmarking platforms in obsidian

initial commit

+1197 -100
+19
lex.config.js
··· 1 + // file: lex.config.js 2 + import { defineLexiconConfig } from '@atcute/lex-cli'; 3 + 4 + export default defineLexiconConfig({ 5 + files: ['lexicons/**/*.json'], 6 + outdir: 'src/lexicons/', 7 + pull: { 8 + outdir: 'lexicons/', 9 + clean: true, 10 + sources: [ 11 + { 12 + type: 'git', 13 + remote: 'https://github.com/cosmik-network/semble.git', 14 + ref: 'main', 15 + pattern: ['src/modules/atproto/infrastructure/lexicons/**/*.json'], 16 + }, 17 + ], 18 + }, 19 + });
+6
lexicons/README.md
··· 1 + # lexicon sources 2 + 3 + this directory contains lexicon documents pulled from the following sources: 4 + 5 + - https://github.com/cosmik-network/semble.git (ref: main) 6 + - commit: 6a806594dd7411268299e3467ed09fd173c8f478
+21
lexicons/com/atproto/repo/strongRef.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.strongRef", 4 + "description": "A URI with a content-hash fingerprint.", 5 + "defs": { 6 + "main": { 7 + "type": "object", 8 + "required": ["uri", "cid"], 9 + "properties": { 10 + "cid": { 11 + "type": "string", 12 + "format": "cid" 13 + }, 14 + "uri": { 15 + "type": "string", 16 + "format": "at-uri" 17 + } 18 + } 19 + } 20 + } 21 + }
+131
lexicons/network/cosmik/card.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "network.cosmik.card", 4 + "description": "A single record type for all cards.", 5 + "defs": { 6 + "main": { 7 + "type": "record", 8 + "description": "A record representing a card with content.", 9 + "key": "tid", 10 + "record": { 11 + "type": "object", 12 + "required": ["type", "content"], 13 + "properties": { 14 + "type": { 15 + "type": "string", 16 + "description": "The type of card", 17 + "knownValues": ["URL", "NOTE"] 18 + }, 19 + "content": { 20 + "type": "union", 21 + "description": "The specific content of the card, determined by the card type.", 22 + "refs": ["#urlContent", "#noteContent"] 23 + }, 24 + "url": { 25 + "type": "string", 26 + "format": "uri", 27 + "description": "Optional URL associated with the card. Required for URL cards, optional for NOTE cards." 28 + }, 29 + "parentCard": { 30 + "type": "ref", 31 + "description": "Optional strong reference to a parent card (for NOTE cards).", 32 + "ref": "com.atproto.repo.strongRef" 33 + }, 34 + "createdAt": { 35 + "type": "string", 36 + "format": "datetime", 37 + "description": "Timestamp when this card was created (usually set by PDS)." 38 + }, 39 + "originalCard": { 40 + "type": "ref", 41 + "description": "Optional strong reference to the original card (for NOTE cards).", 42 + "ref": "com.atproto.repo.strongRef" 43 + }, 44 + "provenance": { 45 + "type": "ref", 46 + "description": "Optional provenance information for this card.", 47 + "ref": "network.cosmik.defs#provenance" 48 + } 49 + } 50 + } 51 + }, 52 + "urlContent": { 53 + "type": "object", 54 + "description": "Content structure for a URL card.", 55 + "required": ["url"], 56 + "properties": { 57 + "url": { 58 + "type": "string", 59 + "format": "uri", 60 + "description": "The URL being saved" 61 + }, 62 + "metadata": { 63 + "type": "ref", 64 + "ref": "#urlMetadata", 65 + "description": "Optional metadata about the URL" 66 + } 67 + } 68 + }, 69 + "noteContent": { 70 + "type": "object", 71 + "description": "Content structure for a note card.", 72 + "required": ["text"], 73 + "properties": { 74 + "text": { 75 + "type": "string", 76 + "description": "The note text content", 77 + "maxLength": 10000 78 + } 79 + } 80 + }, 81 + "urlMetadata": { 82 + "type": "object", 83 + "description": "Metadata about a URL.", 84 + "properties": { 85 + "title": { 86 + "type": "string", 87 + "description": "Title of the page" 88 + }, 89 + "description": { 90 + "type": "string", 91 + "description": "Description of the page" 92 + }, 93 + "author": { 94 + "type": "string", 95 + "description": "Author of the content" 96 + }, 97 + "publishedDate": { 98 + "type": "string", 99 + "format": "datetime", 100 + "description": "When the content was published" 101 + }, 102 + "siteName": { 103 + "type": "string", 104 + "description": "Name of the site" 105 + }, 106 + "imageUrl": { 107 + "type": "string", 108 + "format": "uri", 109 + "description": "URL of a representative image" 110 + }, 111 + "type": { 112 + "type": "string", 113 + "description": "Type of content (e.g., 'video', 'article')" 114 + }, 115 + "retrievedAt": { 116 + "type": "string", 117 + "format": "datetime", 118 + "description": "When the metadata was retrieved" 119 + }, 120 + "doi": { 121 + "type": "string", 122 + "description": "Digital Object Identifier (DOI) for academic content" 123 + }, 124 + "isbn": { 125 + "type": "string", 126 + "description": "International Standard Book Number (ISBN) for books" 127 + } 128 + } 129 + } 130 + } 131 + }
+51
lexicons/network/cosmik/collection.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "network.cosmik.collection", 4 + "description": "A single record type for collections of cards.", 5 + "defs": { 6 + "main": { 7 + "type": "record", 8 + "description": "A record representing a collection of cards.", 9 + "key": "tid", 10 + "record": { 11 + "type": "object", 12 + "required": ["name", "accessType"], 13 + "properties": { 14 + "name": { 15 + "type": "string", 16 + "description": "Name of the collection", 17 + "maxLength": 100 18 + }, 19 + "description": { 20 + "type": "string", 21 + "description": "Description of the collection", 22 + "maxLength": 500 23 + }, 24 + "accessType": { 25 + "type": "string", 26 + "description": "Access control for the collection", 27 + "knownValues": ["OPEN", "CLOSED"] 28 + }, 29 + "collaborators": { 30 + "type": "array", 31 + "description": "List of collaborator DIDs who can add cards to closed collections", 32 + "items": { 33 + "type": "string", 34 + "description": "DID of a collaborator" 35 + } 36 + }, 37 + "createdAt": { 38 + "type": "string", 39 + "format": "datetime", 40 + "description": "Timestamp when this collection was created (usually set by PDS)." 41 + }, 42 + "updatedAt": { 43 + "type": "string", 44 + "format": "datetime", 45 + "description": "Timestamp when this collection was last updated." 46 + } 47 + } 48 + } 49 + } 50 + } 51 + }
+52
lexicons/network/cosmik/collectionLink.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "network.cosmik.collectionLink", 4 + "description": "A record that links a card to a collection.", 5 + "defs": { 6 + "main": { 7 + "type": "record", 8 + "description": "A record representing the relationship between a card and a collection.", 9 + "key": "tid", 10 + "record": { 11 + "type": "object", 12 + "required": ["collection", "card", "addedBy", "addedAt"], 13 + "properties": { 14 + "collection": { 15 + "type": "ref", 16 + "description": "Strong reference to the collection record.", 17 + "ref": "com.atproto.repo.strongRef" 18 + }, 19 + "card": { 20 + "type": "ref", 21 + "description": "Strong reference to the card record in the users library.", 22 + "ref": "com.atproto.repo.strongRef" 23 + }, 24 + "originalCard": { 25 + "type": "ref", 26 + "description": "Strong reference to the original card record (may be in another library).", 27 + "ref": "com.atproto.repo.strongRef" 28 + }, 29 + "addedBy": { 30 + "type": "string", 31 + "description": "DID of the user who added the card to the collection" 32 + }, 33 + "addedAt": { 34 + "type": "string", 35 + "format": "datetime", 36 + "description": "Timestamp when the card was added to the collection." 37 + }, 38 + "createdAt": { 39 + "type": "string", 40 + "format": "datetime", 41 + "description": "Timestamp when this link record was created (usually set by PDS)." 42 + }, 43 + "provenance": { 44 + "type": "ref", 45 + "description": "Optional provenance information for this link.", 46 + "ref": "network.cosmik.defs#provenance" 47 + } 48 + } 49 + } 50 + } 51 + } 52 + }
+18
lexicons/network/cosmik/defs.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "network.cosmik.defs", 4 + "description": "Common definitions for annotation types and references", 5 + "defs": { 6 + "provenance": { 7 + "type": "object", 8 + "description": "Represents the provenance or source of a record.", 9 + "properties": { 10 + "via": { 11 + "type": "ref", 12 + "description": "Strong reference to the card that led to this record.", 13 + "ref": "com.atproto.repo.strongRef" 14 + } 15 + } 16 + } 17 + } 18 + }
+364 -9
package-lock.json
··· 9 9 "version": "1.0.0", 10 10 "license": "0-BSD", 11 11 "dependencies": { 12 + "@atcute/atproto": "^3.1.10", 13 + "@atcute/bluesky": "^3.2.15", 14 + "@atcute/client": "^4.2.1", 15 + "@atcute/lex-cli": "^2.5.2", 16 + "@atcute/oauth-browser-client": "^2.0.3", 12 17 "obsidian": "latest" 13 18 }, 14 19 "devDependencies": { ··· 23 28 "typescript-eslint": "8.35.1" 24 29 } 25 30 }, 31 + "node_modules/@atcute/atproto": { 32 + "version": "3.1.10", 33 + "resolved": "https://registry.npmjs.org/@atcute/atproto/-/atproto-3.1.10.tgz", 34 + "integrity": "sha512-+GKZpOc0PJcdWMQEkTfg/rSNDAAHxmAUGBl60g2az15etqJn5WaUPNGFE2sB7hKpwi5Ue2h/L0OacINcE/JDDQ==", 35 + "license": "0BSD", 36 + "dependencies": { 37 + "@atcute/lexicons": "^1.2.6" 38 + } 39 + }, 40 + "node_modules/@atcute/bluesky": { 41 + "version": "3.2.15", 42 + "resolved": "https://registry.npmjs.org/@atcute/bluesky/-/bluesky-3.2.15.tgz", 43 + "integrity": "sha512-H4RW3WffjfdKvOZ9issEUQnuSR4KfuAwwJnYu0fclA9VDa99JTJ+pa8tTl9lFeBV9DINtWJAx7rdIbICoVCstQ==", 44 + "license": "0BSD", 45 + "dependencies": { 46 + "@atcute/atproto": "^3.1.10", 47 + "@atcute/lexicons": "^1.2.6" 48 + } 49 + }, 50 + "node_modules/@atcute/car": { 51 + "version": "5.1.0", 52 + "resolved": "https://registry.npmjs.org/@atcute/car/-/car-5.1.0.tgz", 53 + "integrity": "sha512-W9axHVrwIkZJaeN/VQ1LyyU3b95wHBjQnrREouxygvmvWd1lmjFvF8Si8b0AG0VkWJ6h7h6qhOeUATynBzBFIg==", 54 + "license": "0BSD", 55 + "dependencies": { 56 + "@atcute/cbor": "^2.3.0", 57 + "@atcute/cid": "^2.4.0", 58 + "@atcute/uint8array": "^1.0.6", 59 + "@atcute/varint": "^1.0.3" 60 + } 61 + }, 62 + "node_modules/@atcute/cbor": { 63 + "version": "2.3.0", 64 + "resolved": "https://registry.npmjs.org/@atcute/cbor/-/cbor-2.3.0.tgz", 65 + "integrity": "sha512-7G2AndkfYzIXMBOBqUPUWP6oIJJm77KY5nYzS4Mr5NNxnmnrBrXEQqp+seCE3X5TV8FUSWQK5YRTU87uPjafMQ==", 66 + "license": "0BSD", 67 + "dependencies": { 68 + "@atcute/cid": "^2.4.0", 69 + "@atcute/multibase": "^1.1.6", 70 + "@atcute/uint8array": "^1.0.6" 71 + } 72 + }, 73 + "node_modules/@atcute/cid": { 74 + "version": "2.4.0", 75 + "resolved": "https://registry.npmjs.org/@atcute/cid/-/cid-2.4.0.tgz", 76 + "integrity": "sha512-6+5u9MpUrgSRQ94z7vaIX4BYk8fYr2KXUBS+rrr2NhlPy8xam8nbTlmd3hvBbtpSwShbhRAE4tA5Ab7eYUp2Yw==", 77 + "license": "0BSD", 78 + "dependencies": { 79 + "@atcute/multibase": "^1.1.6", 80 + "@atcute/uint8array": "^1.0.6" 81 + } 82 + }, 83 + "node_modules/@atcute/client": { 84 + "version": "4.2.1", 85 + "resolved": "https://registry.npmjs.org/@atcute/client/-/client-4.2.1.tgz", 86 + "integrity": "sha512-ZBFM2pW075JtgGFu5g7HHZBecrClhlcNH8GVP9Zz1aViWR+cjjBsTpeE63rJs+FCOHFYlirUyo5L8SGZ4kMINw==", 87 + "license": "0BSD", 88 + "dependencies": { 89 + "@atcute/identity": "^1.1.3", 90 + "@atcute/lexicons": "^1.2.6" 91 + } 92 + }, 93 + "node_modules/@atcute/crypto": { 94 + "version": "2.3.0", 95 + "resolved": "https://registry.npmjs.org/@atcute/crypto/-/crypto-2.3.0.tgz", 96 + "integrity": "sha512-w5pkJKCjbNMQu+F4JRHbR3ROQyhi1wbn+GSC6WDQamcYHkZmEZk1/eoI354bIQOOfkEM6aFLv718iskrkon4GQ==", 97 + "license": "0BSD", 98 + "dependencies": { 99 + "@atcute/multibase": "^1.1.6", 100 + "@atcute/uint8array": "^1.0.6", 101 + "@noble/secp256k1": "^3.0.0" 102 + } 103 + }, 104 + "node_modules/@atcute/identity": { 105 + "version": "1.1.3", 106 + "resolved": "https://registry.npmjs.org/@atcute/identity/-/identity-1.1.3.tgz", 107 + "integrity": "sha512-oIqPoI8TwWeQxvcLmFEZLdN2XdWcaLVtlm8pNk0E72As9HNzzD9pwKPrLr3rmTLRIoULPPFmq9iFNsTeCIU9ng==", 108 + "license": "0BSD", 109 + "peer": true, 110 + "dependencies": { 111 + "@atcute/lexicons": "^1.2.4", 112 + "@badrap/valita": "^0.4.6" 113 + } 114 + }, 115 + "node_modules/@atcute/identity-resolver": { 116 + "version": "1.2.2", 117 + "resolved": "https://registry.npmjs.org/@atcute/identity-resolver/-/identity-resolver-1.2.2.tgz", 118 + "integrity": "sha512-eUh/UH4bFvuXS0X7epYCeJC/kj4rbBXfSRumLEH4smMVwNOgTo7cL/0Srty+P/qVPoZEyXdfEbS0PHJyzoXmHw==", 119 + "license": "0BSD", 120 + "peer": true, 121 + "dependencies": { 122 + "@atcute/lexicons": "^1.2.6", 123 + "@atcute/util-fetch": "^1.0.5", 124 + "@badrap/valita": "^0.4.6" 125 + }, 126 + "peerDependencies": { 127 + "@atcute/identity": "^1.0.0" 128 + } 129 + }, 130 + "node_modules/@atcute/lex-cli": { 131 + "version": "2.5.2", 132 + "resolved": "https://registry.npmjs.org/@atcute/lex-cli/-/lex-cli-2.5.2.tgz", 133 + "integrity": "sha512-u3xeu7uF7mAgAErYpXvdUaH2bxpthGWLg+vUf20cejWZHBH/dAzL4ixLRjw/39WwoVmmCQDTde79WTPoBjuhpg==", 134 + "license": "0BSD", 135 + "dependencies": { 136 + "@atcute/identity": "^1.1.3", 137 + "@atcute/identity-resolver": "^1.2.0", 138 + "@atcute/lexicon-doc": "^2.0.5", 139 + "@atcute/lexicon-resolver": "^0.1.5", 140 + "@atcute/lexicons": "^1.2.5", 141 + "@badrap/valita": "^0.4.6", 142 + "@optique/core": "^0.6.3", 143 + "@optique/run": "^0.6.3", 144 + "picocolors": "^1.1.1", 145 + "prettier": "^3.7.1" 146 + }, 147 + "bin": { 148 + "lex-cli": "cli.mjs" 149 + } 150 + }, 151 + "node_modules/@atcute/lexicon-doc": { 152 + "version": "2.0.6", 153 + "resolved": "https://registry.npmjs.org/@atcute/lexicon-doc/-/lexicon-doc-2.0.6.tgz", 154 + "integrity": "sha512-iDYJkuom+tIw3zIvU1ggCEVFfReXKfOUtIhpY2kEg2kQeSfMB75F+8k1QOpeAQBetyWYmjsHqBuSUX9oQS6L1Q==", 155 + "license": "0BSD", 156 + "dependencies": { 157 + "@atcute/identity": "^1.1.3", 158 + "@atcute/lexicons": "^1.2.6", 159 + "@atcute/uint8array": "^1.0.6", 160 + "@atcute/util-text": "^0.0.1", 161 + "@badrap/valita": "^0.4.6" 162 + } 163 + }, 164 + "node_modules/@atcute/lexicon-resolver": { 165 + "version": "0.1.6", 166 + "resolved": "https://registry.npmjs.org/@atcute/lexicon-resolver/-/lexicon-resolver-0.1.6.tgz", 167 + "integrity": "sha512-wJC/ChmpP7k+ywpOd07CMvioXjIGaFpF3bDwXLi/086LYjSWHOvtW6pyC+mqP5wLhjyH2hn4wmi77Buew1l1aw==", 168 + "license": "0BSD", 169 + "dependencies": { 170 + "@atcute/crypto": "^2.3.0", 171 + "@atcute/lexicon-doc": "^2.0.6", 172 + "@atcute/lexicons": "^1.2.6", 173 + "@atcute/repo": "^0.1.1", 174 + "@atcute/util-fetch": "^1.0.5", 175 + "@badrap/valita": "^0.4.6" 176 + }, 177 + "peerDependencies": { 178 + "@atcute/identity": "^1.1.0", 179 + "@atcute/identity-resolver": "^1.1.3" 180 + } 181 + }, 182 + "node_modules/@atcute/lexicons": { 183 + "version": "1.2.6", 184 + "resolved": "https://registry.npmjs.org/@atcute/lexicons/-/lexicons-1.2.6.tgz", 185 + "integrity": "sha512-s76UQd8D+XmHIzrjD9CJ9SOOeeLPHc+sMmcj7UFakAW/dDFXc579fcRdRfuUKvXBL5v1Gs2VgDdlh/IvvQZAwA==", 186 + "license": "0BSD", 187 + "dependencies": { 188 + "@atcute/uint8array": "^1.0.6", 189 + "@atcute/util-text": "^0.0.1", 190 + "@standard-schema/spec": "^1.1.0", 191 + "esm-env": "^1.2.2" 192 + } 193 + }, 194 + "node_modules/@atcute/mst": { 195 + "version": "0.1.2", 196 + "resolved": "https://registry.npmjs.org/@atcute/mst/-/mst-0.1.2.tgz", 197 + "integrity": "sha512-Oz5CZTjqauEJLT9B+zkoy/mjl216DrjCxJFrguRV3N+1NkIbCfAcSRf3UDSNjfzDzBkJvC1WjA/3oQkm83duPg==", 198 + "license": "0BSD", 199 + "dependencies": { 200 + "@atcute/cbor": "^2.3.0", 201 + "@atcute/cid": "^2.4.0", 202 + "@atcute/uint8array": "^1.0.6" 203 + } 204 + }, 205 + "node_modules/@atcute/multibase": { 206 + "version": "1.1.6", 207 + "resolved": "https://registry.npmjs.org/@atcute/multibase/-/multibase-1.1.6.tgz", 208 + "integrity": "sha512-HBxuCgYLKPPxETV0Rot4VP9e24vKl8JdzGCZOVsDaOXJgbRZoRIF67Lp0H/OgnJeH/Xpva8Z5ReoTNJE5dn3kg==", 209 + "license": "0BSD", 210 + "dependencies": { 211 + "@atcute/uint8array": "^1.0.5" 212 + } 213 + }, 214 + "node_modules/@atcute/oauth-browser-client": { 215 + "version": "2.0.3", 216 + "resolved": "https://registry.npmjs.org/@atcute/oauth-browser-client/-/oauth-browser-client-2.0.3.tgz", 217 + "integrity": "sha512-rzUjwhjE4LRRKdQnCFQag/zXRZMEAB1hhBoLfnoQuHwWbmDUCL7fzwC3jRhDPp3om8XaYNDj8a/iqRip0wRqoQ==", 218 + "license": "0BSD", 219 + "dependencies": { 220 + "@atcute/client": "^4.1.1", 221 + "@atcute/identity-resolver": "^1.2.0", 222 + "@atcute/lexicons": "^1.2.5", 223 + "@atcute/multibase": "^1.1.6", 224 + "@atcute/uint8array": "^1.0.6", 225 + "nanoid": "^5.1.6" 226 + } 227 + }, 228 + "node_modules/@atcute/repo": { 229 + "version": "0.1.1", 230 + "resolved": "https://registry.npmjs.org/@atcute/repo/-/repo-0.1.1.tgz", 231 + "integrity": "sha512-P5aWjt3bvcquUkUmGPslF0naAfLGRHse5Qdz9/RJYrFuoH0iiEMyRnW6M+3ksOe20GPsMnbq71WbzzFkRFPBtg==", 232 + "license": "0BSD", 233 + "dependencies": { 234 + "@atcute/car": "^5.0.0", 235 + "@atcute/cbor": "^2.2.8", 236 + "@atcute/cid": "^2.2.6", 237 + "@atcute/crypto": "^2.3.0", 238 + "@atcute/lexicons": "^1.2.5", 239 + "@atcute/mst": "^0.1.0", 240 + "@atcute/uint8array": "^1.0.6" 241 + } 242 + }, 243 + "node_modules/@atcute/uint8array": { 244 + "version": "1.0.6", 245 + "resolved": "https://registry.npmjs.org/@atcute/uint8array/-/uint8array-1.0.6.tgz", 246 + "integrity": "sha512-ucfRBQc7BFT8n9eCyGOzDHEMKF/nZwhS2pPao4Xtab1ML3HdFYcX2DM1tadCzas85QTGxHe5urnUAAcNKGRi9A==", 247 + "license": "0BSD" 248 + }, 249 + "node_modules/@atcute/util-fetch": { 250 + "version": "1.0.5", 251 + "resolved": "https://registry.npmjs.org/@atcute/util-fetch/-/util-fetch-1.0.5.tgz", 252 + "integrity": "sha512-qjHj01BGxjSjIFdPiAjSARnodJIIyKxnCMMEcXMESo9TAyND6XZQqrie5fia+LlYWVXdpsTds8uFQwc9jdKTig==", 253 + "license": "0BSD", 254 + "dependencies": { 255 + "@badrap/valita": "^0.4.6" 256 + } 257 + }, 258 + "node_modules/@atcute/util-text": { 259 + "version": "0.0.1", 260 + "resolved": "https://registry.npmjs.org/@atcute/util-text/-/util-text-0.0.1.tgz", 261 + "integrity": "sha512-t1KZqvn0AYy+h2KcJyHnKF9aEqfRfMUmyY8j1ELtAEIgqN9CxINAjxnoRCJIFUlvWzb+oY3uElQL/Vyk3yss0g==", 262 + "license": "0BSD", 263 + "dependencies": { 264 + "unicode-segmenter": "^0.14.4" 265 + } 266 + }, 267 + "node_modules/@atcute/varint": { 268 + "version": "1.0.3", 269 + "resolved": "https://registry.npmjs.org/@atcute/varint/-/varint-1.0.3.tgz", 270 + "integrity": "sha512-fdvMPyBB+McDT+Ai5e9RwEbwYV4yjZ60S2Dn5PTjGqUyxvoCH1z42viuheDZRUDkmfQehXJTZ5az7dSozVNtog==", 271 + "license": "0BSD" 272 + }, 273 + "node_modules/@badrap/valita": { 274 + "version": "0.4.6", 275 + "resolved": "https://registry.npmjs.org/@badrap/valita/-/valita-0.4.6.tgz", 276 + "integrity": "sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg==", 277 + "license": "MIT", 278 + "engines": { 279 + "node": ">= 18" 280 + } 281 + }, 26 282 "node_modules/@codemirror/state": { 27 283 "version": "6.5.0", 28 284 "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.0.tgz", ··· 584 840 "integrity": "sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==", 585 841 "dev": true, 586 842 "license": "MIT", 843 + "peer": true, 587 844 "engines": { 588 845 "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 589 846 }, ··· 676 933 "integrity": "sha512-KWiFQpSAqEIyrTXko3hFNLeQvSK8zXlJQzhhxsyVn58WFRYXST99b3Nqnu+ttOtjds2Pl2grUHGpe2NzhPynuQ==", 677 934 "dev": true, 678 935 "license": "Apache-2.0", 679 - "peer": true, 680 936 "engines": { 681 937 "node": ">=18" 682 938 } ··· 699 955 "version": "1.0.2", 700 956 "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", 701 957 "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", 702 - "license": "MIT", 703 - "peer": true 958 + "license": "MIT" 704 959 }, 705 960 "node_modules/@microsoft/eslint-plugin-sdl": { 706 961 "version": "1.1.0", ··· 740 995 "ret": "~0.1.10" 741 996 } 742 997 }, 998 + "node_modules/@noble/secp256k1": { 999 + "version": "3.0.0", 1000 + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-3.0.0.tgz", 1001 + "integrity": "sha512-NJBaR352KyIvj3t6sgT/+7xrNyF9Xk9QlLSIqUGVUYlsnDTAUqY8LOmwpcgEx4AMJXRITQ5XEVHD+mMaPfr3mg==", 1002 + "license": "MIT", 1003 + "funding": { 1004 + "url": "https://paulmillr.com/funding/" 1005 + } 1006 + }, 743 1007 "node_modules/@nodelib/fs.scandir": { 744 1008 "version": "2.1.5", 745 1009 "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", ··· 778 1042 "node": ">= 8" 779 1043 } 780 1044 }, 1045 + "node_modules/@optique/core": { 1046 + "version": "0.6.11", 1047 + "resolved": "https://registry.npmjs.org/@optique/core/-/core-0.6.11.tgz", 1048 + "integrity": "sha512-GVLFihzBA1j78NFlkU5N1Lu0jRqET0k6Z66WK8VQKG/a3cxmCInVGSKMIdQG8i6pgC8wD5OizF6Y3QMztmhAxg==", 1049 + "funding": [ 1050 + "https://github.com/sponsors/dahlia" 1051 + ], 1052 + "license": "MIT", 1053 + "engines": { 1054 + "bun": ">=1.2.0", 1055 + "deno": ">=2.3.0", 1056 + "node": ">=20.0.0" 1057 + } 1058 + }, 1059 + "node_modules/@optique/run": { 1060 + "version": "0.6.11", 1061 + "resolved": "https://registry.npmjs.org/@optique/run/-/run-0.6.11.tgz", 1062 + "integrity": "sha512-tsXBEygGSzNpFK2gjsRlXBn7FiScUeLFWIZNpoAZ8iG85Km0/3K9xgqlQAXoQ+uEZBe4XplnzyCDvmEgbyNT8w==", 1063 + "funding": [ 1064 + "https://github.com/sponsors/dahlia" 1065 + ], 1066 + "license": "MIT", 1067 + "dependencies": { 1068 + "@optique/core": "0.6.11" 1069 + }, 1070 + "engines": { 1071 + "bun": ">=1.2.0", 1072 + "deno": ">=2.3.0", 1073 + "node": ">=20.0.0" 1074 + } 1075 + }, 781 1076 "node_modules/@pkgr/core": { 782 1077 "version": "0.1.2", 783 1078 "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.2.tgz", ··· 798 1093 "dev": true, 799 1094 "license": "MIT" 800 1095 }, 1096 + "node_modules/@standard-schema/spec": { 1097 + "version": "1.1.0", 1098 + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", 1099 + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", 1100 + "license": "MIT" 1101 + }, 801 1102 "node_modules/@types/codemirror": { 802 1103 "version": "5.60.8", 803 1104 "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz", ··· 900 1201 "integrity": "sha512-3MyiDfrfLeK06bi/g9DqJxP5pV74LNv4rFTyvGDmT3x2p1yp1lOd+qYZfiRPIOf/oON+WRZR5wxxuF85qOar+w==", 901 1202 "dev": true, 902 1203 "license": "MIT", 1204 + "peer": true, 903 1205 "dependencies": { 904 1206 "@typescript-eslint/scope-manager": "8.35.1", 905 1207 "@typescript-eslint/types": "8.35.1", ··· 1130 1432 "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", 1131 1433 "dev": true, 1132 1434 "license": "MIT", 1435 + "peer": true, 1133 1436 "bin": { 1134 1437 "acorn": "bin/acorn" 1135 1438 }, ··· 1512 1815 "version": "1.0.6", 1513 1816 "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", 1514 1817 "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", 1515 - "license": "MIT", 1516 - "peer": true 1818 + "license": "MIT" 1517 1819 }, 1518 1820 "node_modules/cross-spawn": { 1519 1821 "version": "7.0.6", ··· 1934 2236 "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", 1935 2237 "dev": true, 1936 2238 "license": "MIT", 2239 + "peer": true, 1937 2240 "dependencies": { 1938 2241 "@eslint-community/eslint-utils": "^4.8.0", 1939 2242 "@eslint-community/regexpp": "^4.12.1", ··· 2491 2794 "url": "https://eslint.org/donate" 2492 2795 } 2493 2796 }, 2797 + "node_modules/esm-env": { 2798 + "version": "1.2.2", 2799 + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", 2800 + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", 2801 + "license": "MIT" 2802 + }, 2494 2803 "node_modules/espree": { 2495 2804 "version": "10.4.0", 2496 2805 "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", ··· 3480 3789 "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", 3481 3790 "dev": true, 3482 3791 "license": "MIT", 3792 + "peer": true, 3483 3793 "bin": { 3484 3794 "jiti": "lib/jiti-cli.mjs" 3485 3795 } ··· 3791 4101 "dev": true, 3792 4102 "license": "MIT" 3793 4103 }, 4104 + "node_modules/nanoid": { 4105 + "version": "5.1.6", 4106 + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", 4107 + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", 4108 + "funding": [ 4109 + { 4110 + "type": "github", 4111 + "url": "https://github.com/sponsors/ai" 4112 + } 4113 + ], 4114 + "license": "MIT", 4115 + "bin": { 4116 + "nanoid": "bin/nanoid.js" 4117 + }, 4118 + "engines": { 4119 + "node": "^18 || >=20" 4120 + } 4121 + }, 3794 4122 "node_modules/natural-compare": { 3795 4123 "version": "1.4.0", 3796 4124 "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", ··· 4043 4371 "dev": true, 4044 4372 "license": "MIT" 4045 4373 }, 4374 + "node_modules/picocolors": { 4375 + "version": "1.1.1", 4376 + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 4377 + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 4378 + "license": "ISC" 4379 + }, 4046 4380 "node_modules/picomatch": { 4047 4381 "version": "2.3.1", 4048 4382 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", ··· 4076 4410 "node": ">= 0.8.0" 4077 4411 } 4078 4412 }, 4413 + "node_modules/prettier": { 4414 + "version": "3.8.1", 4415 + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", 4416 + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", 4417 + "license": "MIT", 4418 + "bin": { 4419 + "prettier": "bin/prettier.cjs" 4420 + }, 4421 + "engines": { 4422 + "node": ">=14" 4423 + }, 4424 + "funding": { 4425 + "url": "https://github.com/prettier/prettier?sponsor=1" 4426 + } 4427 + }, 4079 4428 "node_modules/prop-types": { 4080 4429 "version": "15.8.1", 4081 4430 "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", ··· 4659 5008 "version": "4.1.3", 4660 5009 "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", 4661 5010 "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", 4662 - "license": "MIT", 4663 - "peer": true 5011 + "license": "MIT" 4664 5012 }, 4665 5013 "node_modules/supports-color": { 4666 5014 "version": "7.2.0", ··· 4911 5259 "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", 4912 5260 "dev": true, 4913 5261 "license": "Apache-2.0", 5262 + "peer": true, 4914 5263 "bin": { 4915 5264 "tsc": "bin/tsc", 4916 5265 "tsserver": "bin/tsserver" ··· 4925 5274 "integrity": "sha512-xslJjFzhOmHYQzSB/QTeASAHbjmxOGEP6Coh93TXmUBFQoJ1VU35UHIDmG06Jd6taf3wqqC1ntBnCMeymy5Ovw==", 4926 5275 "dev": true, 4927 5276 "license": "MIT", 5277 + "peer": true, 4928 5278 "dependencies": { 4929 5279 "@typescript-eslint/eslint-plugin": "8.35.1", 4930 5280 "@typescript-eslint/parser": "8.35.1", ··· 4968 5318 "dev": true, 4969 5319 "license": "MIT" 4970 5320 }, 5321 + "node_modules/unicode-segmenter": { 5322 + "version": "0.14.5", 5323 + "resolved": "https://registry.npmjs.org/unicode-segmenter/-/unicode-segmenter-0.14.5.tgz", 5324 + "integrity": "sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g==", 5325 + "license": "MIT" 5326 + }, 4971 5327 "node_modules/uri-js": { 4972 5328 "version": "4.4.1", 4973 5329 "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", ··· 4982 5338 "version": "2.2.8", 4983 5339 "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", 4984 5340 "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", 4985 - "license": "MIT", 4986 - "peer": true 5341 + "license": "MIT" 4987 5342 }, 4988 5343 "node_modules/which": { 4989 5344 "version": "2.0.2",
+8 -3
package.json
··· 13 13 "keywords": [], 14 14 "license": "0-BSD", 15 15 "devDependencies": { 16 + "@eslint/js": "9.30.1", 16 17 "@types/node": "^16.11.6", 17 18 "esbuild": "0.25.5", 18 19 "eslint-plugin-obsidianmd": "0.1.9", 19 20 "globals": "14.0.0", 21 + "jiti": "2.6.1", 20 22 "tslib": "2.4.0", 21 23 "typescript": "^5.8.3", 22 - "typescript-eslint": "8.35.1", 23 - "@eslint/js": "9.30.1", 24 - "jiti": "2.6.1" 24 + "typescript-eslint": "8.35.1" 25 25 }, 26 26 "dependencies": { 27 + "@atcute/atproto": "^3.1.10", 28 + "@atcute/bluesky": "^3.2.15", 29 + "@atcute/client": "^4.2.1", 30 + "@atcute/lex-cli": "^2.5.2", 31 + "@atcute/oauth-browser-client": "^2.0.3", 27 32 "obsidian": "latest" 28 33 } 29 34 }
+18
src/auth.ts
··· 1 + import { Client, CredentialManager, simpleFetchHandler } from "@atcute/client"; 2 + 3 + const DEFAULT_PDS = "https://bsky.social"; 4 + 5 + export interface Credentials { 6 + identifier: string; 7 + password: string; 8 + } 9 + 10 + export async function createAuthenticatedClient(creds: Credentials): Promise<Client> { 11 + const manager = new CredentialManager({ service: DEFAULT_PDS }); 12 + await manager.login(creds); 13 + return new Client({ handler: manager }); 14 + } 15 + 16 + export function createPublicClient(): Client { 17 + return new Client({ handler: simpleFetchHandler({ service: DEFAULT_PDS }) }); 18 + }
+2
src/env.d.ts
··· 1 + /// <reference types="@atcute/bluesky" /> 2 + /// <reference types="@atcute/atproto" />
+5
src/lexicons/index.ts
··· 1 + export * as ComAtprotoRepoStrongRef from "./types/com/atproto/repo/strongRef.js"; 2 + export * as NetworkCosmikCard from "./types/network/cosmik/card.js"; 3 + export * as NetworkCosmikCollection from "./types/network/cosmik/collection.js"; 4 + export * as NetworkCosmikCollectionLink from "./types/network/cosmik/collectionLink.js"; 5 + export * as NetworkCosmikDefs from "./types/network/cosmik/defs.js";
+18
src/lexicons/types/com/atproto/repo/strongRef.ts
··· 1 + import type {} from "@atcute/lexicons"; 2 + import * as v from "@atcute/lexicons/validations"; 3 + 4 + const _mainSchema = /*#__PURE__*/ v.object({ 5 + $type: /*#__PURE__*/ v.optional( 6 + /*#__PURE__*/ v.literal("com.atproto.repo.strongRef"), 7 + ), 8 + cid: /*#__PURE__*/ v.cidString(), 9 + uri: /*#__PURE__*/ v.resourceUriString(), 10 + }); 11 + 12 + type main$schematype = typeof _mainSchema; 13 + 14 + export interface mainSchema extends main$schematype {} 15 + 16 + export const mainSchema = _mainSchema as mainSchema; 17 + 18 + export interface Main extends v.InferInput<typeof mainSchema> {}
+146
src/lexicons/types/network/cosmik/card.ts
··· 1 + import type {} from "@atcute/lexicons"; 2 + import * as v from "@atcute/lexicons/validations"; 3 + import type {} from "@atcute/lexicons/ambient"; 4 + import * as ComAtprotoRepoStrongRef from "../../com/atproto/repo/strongRef.js"; 5 + import * as NetworkCosmikDefs from "./defs.js"; 6 + 7 + const _mainSchema = /*#__PURE__*/ v.record( 8 + /*#__PURE__*/ v.tidString(), 9 + /*#__PURE__*/ v.object({ 10 + $type: /*#__PURE__*/ v.literal("network.cosmik.card"), 11 + /** 12 + * The specific content of the card, determined by the card type. 13 + */ 14 + get content() { 15 + return /*#__PURE__*/ v.variant([noteContentSchema, urlContentSchema]); 16 + }, 17 + /** 18 + * Timestamp when this card was created (usually set by PDS). 19 + */ 20 + createdAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()), 21 + /** 22 + * Optional strong reference to the original card (for NOTE cards). 23 + */ 24 + get originalCard() { 25 + return /*#__PURE__*/ v.optional(ComAtprotoRepoStrongRef.mainSchema); 26 + }, 27 + /** 28 + * Optional strong reference to a parent card (for NOTE cards). 29 + */ 30 + get parentCard() { 31 + return /*#__PURE__*/ v.optional(ComAtprotoRepoStrongRef.mainSchema); 32 + }, 33 + /** 34 + * Optional provenance information for this card. 35 + */ 36 + get provenance() { 37 + return /*#__PURE__*/ v.optional(NetworkCosmikDefs.provenanceSchema); 38 + }, 39 + /** 40 + * The type of card 41 + */ 42 + type: /*#__PURE__*/ v.string<"NOTE" | "URL" | (string & {})>(), 43 + /** 44 + * Optional URL associated with the card. Required for URL cards, optional for NOTE cards. 45 + */ 46 + url: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.genericUriString()), 47 + }), 48 + ); 49 + const _noteContentSchema = /*#__PURE__*/ v.object({ 50 + $type: /*#__PURE__*/ v.optional( 51 + /*#__PURE__*/ v.literal("network.cosmik.card#noteContent"), 52 + ), 53 + /** 54 + * The note text content 55 + * @maxLength 10000 56 + */ 57 + text: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [ 58 + /*#__PURE__*/ v.stringLength(0, 10000), 59 + ]), 60 + }); 61 + const _urlContentSchema = /*#__PURE__*/ v.object({ 62 + $type: /*#__PURE__*/ v.optional( 63 + /*#__PURE__*/ v.literal("network.cosmik.card#urlContent"), 64 + ), 65 + /** 66 + * Optional metadata about the URL 67 + */ 68 + get metadata() { 69 + return /*#__PURE__*/ v.optional(urlMetadataSchema); 70 + }, 71 + /** 72 + * The URL being saved 73 + */ 74 + url: /*#__PURE__*/ v.genericUriString(), 75 + }); 76 + const _urlMetadataSchema = /*#__PURE__*/ v.object({ 77 + $type: /*#__PURE__*/ v.optional( 78 + /*#__PURE__*/ v.literal("network.cosmik.card#urlMetadata"), 79 + ), 80 + /** 81 + * Author of the content 82 + */ 83 + author: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()), 84 + /** 85 + * Description of the page 86 + */ 87 + description: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()), 88 + /** 89 + * Digital Object Identifier (DOI) for academic content 90 + */ 91 + doi: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()), 92 + /** 93 + * URL of a representative image 94 + */ 95 + imageUrl: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.genericUriString()), 96 + /** 97 + * International Standard Book Number (ISBN) for books 98 + */ 99 + isbn: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()), 100 + /** 101 + * When the content was published 102 + */ 103 + publishedDate: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()), 104 + /** 105 + * When the metadata was retrieved 106 + */ 107 + retrievedAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()), 108 + /** 109 + * Name of the site 110 + */ 111 + siteName: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()), 112 + /** 113 + * Title of the page 114 + */ 115 + title: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()), 116 + /** 117 + * Type of content (e.g., 'video', 'article') 118 + */ 119 + type: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()), 120 + }); 121 + 122 + type main$schematype = typeof _mainSchema; 123 + type noteContent$schematype = typeof _noteContentSchema; 124 + type urlContent$schematype = typeof _urlContentSchema; 125 + type urlMetadata$schematype = typeof _urlMetadataSchema; 126 + 127 + export interface mainSchema extends main$schematype {} 128 + export interface noteContentSchema extends noteContent$schematype {} 129 + export interface urlContentSchema extends urlContent$schematype {} 130 + export interface urlMetadataSchema extends urlMetadata$schematype {} 131 + 132 + export const mainSchema = _mainSchema as mainSchema; 133 + export const noteContentSchema = _noteContentSchema as noteContentSchema; 134 + export const urlContentSchema = _urlContentSchema as urlContentSchema; 135 + export const urlMetadataSchema = _urlMetadataSchema as urlMetadataSchema; 136 + 137 + export interface Main extends v.InferInput<typeof mainSchema> {} 138 + export interface NoteContent extends v.InferInput<typeof noteContentSchema> {} 139 + export interface UrlContent extends v.InferInput<typeof urlContentSchema> {} 140 + export interface UrlMetadata extends v.InferInput<typeof urlMetadataSchema> {} 141 + 142 + declare module "@atcute/lexicons/ambient" { 143 + interface Records { 144 + "network.cosmik.card": mainSchema; 145 + } 146 + }
+58
src/lexicons/types/network/cosmik/collection.ts
··· 1 + import type {} from "@atcute/lexicons"; 2 + import * as v from "@atcute/lexicons/validations"; 3 + import type {} from "@atcute/lexicons/ambient"; 4 + 5 + const _mainSchema = /*#__PURE__*/ v.record( 6 + /*#__PURE__*/ v.tidString(), 7 + /*#__PURE__*/ v.object({ 8 + $type: /*#__PURE__*/ v.literal("network.cosmik.collection"), 9 + /** 10 + * Access control for the collection 11 + */ 12 + accessType: /*#__PURE__*/ v.string<"CLOSED" | "OPEN" | (string & {})>(), 13 + /** 14 + * List of collaborator DIDs who can add cards to closed collections 15 + */ 16 + collaborators: /*#__PURE__*/ v.optional( 17 + /*#__PURE__*/ v.array(/*#__PURE__*/ v.string()), 18 + ), 19 + /** 20 + * Timestamp when this collection was created (usually set by PDS). 21 + */ 22 + createdAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()), 23 + /** 24 + * Description of the collection 25 + * @maxLength 500 26 + */ 27 + description: /*#__PURE__*/ v.optional( 28 + /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [ 29 + /*#__PURE__*/ v.stringLength(0, 500), 30 + ]), 31 + ), 32 + /** 33 + * Name of the collection 34 + * @maxLength 100 35 + */ 36 + name: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [ 37 + /*#__PURE__*/ v.stringLength(0, 100), 38 + ]), 39 + /** 40 + * Timestamp when this collection was last updated. 41 + */ 42 + updatedAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()), 43 + }), 44 + ); 45 + 46 + type main$schematype = typeof _mainSchema; 47 + 48 + export interface mainSchema extends main$schematype {} 49 + 50 + export const mainSchema = _mainSchema as mainSchema; 51 + 52 + export interface Main extends v.InferInput<typeof mainSchema> {} 53 + 54 + declare module "@atcute/lexicons/ambient" { 55 + interface Records { 56 + "network.cosmik.collection": mainSchema; 57 + } 58 + }
+62
src/lexicons/types/network/cosmik/collectionLink.ts
··· 1 + import type {} from "@atcute/lexicons"; 2 + import * as v from "@atcute/lexicons/validations"; 3 + import type {} from "@atcute/lexicons/ambient"; 4 + import * as ComAtprotoRepoStrongRef from "../../com/atproto/repo/strongRef.js"; 5 + import * as NetworkCosmikDefs from "./defs.js"; 6 + 7 + const _mainSchema = /*#__PURE__*/ v.record( 8 + /*#__PURE__*/ v.tidString(), 9 + /*#__PURE__*/ v.object({ 10 + $type: /*#__PURE__*/ v.literal("network.cosmik.collectionLink"), 11 + /** 12 + * Timestamp when the card was added to the collection. 13 + */ 14 + addedAt: /*#__PURE__*/ v.datetimeString(), 15 + /** 16 + * DID of the user who added the card to the collection 17 + */ 18 + addedBy: /*#__PURE__*/ v.string(), 19 + /** 20 + * Strong reference to the card record in the users library. 21 + */ 22 + get card() { 23 + return ComAtprotoRepoStrongRef.mainSchema; 24 + }, 25 + /** 26 + * Strong reference to the collection record. 27 + */ 28 + get collection() { 29 + return ComAtprotoRepoStrongRef.mainSchema; 30 + }, 31 + /** 32 + * Timestamp when this link record was created (usually set by PDS). 33 + */ 34 + createdAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()), 35 + /** 36 + * Strong reference to the original card record (may be in another library). 37 + */ 38 + get originalCard() { 39 + return /*#__PURE__*/ v.optional(ComAtprotoRepoStrongRef.mainSchema); 40 + }, 41 + /** 42 + * Optional provenance information for this link. 43 + */ 44 + get provenance() { 45 + return /*#__PURE__*/ v.optional(NetworkCosmikDefs.provenanceSchema); 46 + }, 47 + }), 48 + ); 49 + 50 + type main$schematype = typeof _mainSchema; 51 + 52 + export interface mainSchema extends main$schematype {} 53 + 54 + export const mainSchema = _mainSchema as mainSchema; 55 + 56 + export interface Main extends v.InferInput<typeof mainSchema> {} 57 + 58 + declare module "@atcute/lexicons/ambient" { 59 + interface Records { 60 + "network.cosmik.collectionLink": mainSchema; 61 + } 62 + }
+23
src/lexicons/types/network/cosmik/defs.ts
··· 1 + import type {} from "@atcute/lexicons"; 2 + import * as v from "@atcute/lexicons/validations"; 3 + import * as ComAtprotoRepoStrongRef from "../../com/atproto/repo/strongRef.js"; 4 + 5 + const _provenanceSchema = /*#__PURE__*/ v.object({ 6 + $type: /*#__PURE__*/ v.optional( 7 + /*#__PURE__*/ v.literal("network.cosmik.defs#provenance"), 8 + ), 9 + /** 10 + * Strong reference to the card that led to this record. 11 + */ 12 + get via() { 13 + return /*#__PURE__*/ v.optional(ComAtprotoRepoStrongRef.mainSchema); 14 + }, 15 + }); 16 + 17 + type provenance$schematype = typeof _provenanceSchema; 18 + 19 + export interface provenanceSchema extends provenance$schematype {} 20 + 21 + export const provenanceSchema = _provenanceSchema as provenanceSchema; 22 + 23 + export interface Provenance extends v.InferInput<typeof provenanceSchema> {}
+28
src/lib.ts
··· 1 + import type { Client } from "@atcute/client"; 2 + import type { ActorIdentifier, Nsid } from "@atcute/lexicons"; 3 + 4 + export async function getProfile(client: Client, actor: string) { 5 + return await client.get("app.bsky.actor.getProfile", { 6 + params: { actor: actor as ActorIdentifier }, 7 + }); 8 + } 9 + 10 + export async function getCollections(client: Client, repo: string) { 11 + return await client.get("com.atproto.repo.listRecords", { 12 + params: { 13 + repo: repo as ActorIdentifier, 14 + collection: "network.cosmik.collection" as Nsid, 15 + limit: 100, 16 + }, 17 + }); 18 + } 19 + 20 + export async function getCards(client: Client, repo: string) { 21 + return await client.get("com.atproto.repo.listRecords", { 22 + params: { 23 + repo: repo as ActorIdentifier, 24 + collection: "network.cosmik.card" as Nsid, 25 + limit: 100, 26 + }, 27 + }); 28 + }
+82 -68
src/main.ts
··· 1 - import {App, Editor, MarkdownView, Modal, Notice, Plugin} from 'obsidian'; 2 - import {DEFAULT_SETTINGS, MyPluginSettings, SampleSettingTab} from "./settings"; 3 - 4 - // Remember to rename these classes and interfaces! 1 + import { Notice, Plugin, WorkspaceLeaf } from "obsidian"; 2 + import type { Client } from "@atcute/client"; 3 + import { DEFAULT_SETTINGS, AtProtoSettings, SettingTab } from "./settings"; 4 + import { createAuthenticatedClient, createPublicClient } from "./auth"; 5 + import { getCollections } from "./lib"; 6 + import { SembleCollectionsView, VIEW_TYPE_SEMBLE_COLLECTIONS } from "views/collections"; 5 7 6 8 export default class MyPlugin extends Plugin { 7 - settings: MyPluginSettings; 9 + settings: AtProtoSettings = DEFAULT_SETTINGS; 10 + client: Client | null = null; 8 11 9 12 async onload() { 10 13 await this.loadSettings(); 14 + await this.initClient(); 11 15 12 - // This creates an icon in the left ribbon. 13 - this.addRibbonIcon('dice', 'Sample', (evt: MouseEvent) => { 14 - // Called when the user clicks the icon. 15 - new Notice('This is a notice!'); 16 + this.registerView(VIEW_TYPE_SEMBLE_COLLECTIONS, (leaf) => { 17 + return new SembleCollectionsView(leaf, this); 16 18 }); 17 19 18 - // This adds a status bar item to the bottom of the app. Does not work on mobile apps. 19 - const statusBarItemEl = this.addStatusBarItem(); 20 - statusBarItemEl.setText('Status bar text'); 21 20 22 - // This adds a simple command that can be triggered anywhere 23 21 this.addCommand({ 24 - id: 'open-modal-simple', 25 - name: 'Open modal (simple)', 26 - callback: () => { 27 - new SampleModal(this.app).open(); 28 - } 22 + id: "list-collections", 23 + name: "List Collections", 24 + callback: () => this.listCollections(), 29 25 }); 30 - // This adds an editor command that can perform some operation on the current editor instance 26 + 31 27 this.addCommand({ 32 - id: 'replace-selected', 33 - name: 'Replace selected content', 34 - editorCallback: (editor: Editor, view: MarkdownView) => { 35 - editor.replaceSelection('Sample editor command'); 36 - } 28 + id: "view-semble-collections", 29 + name: "View Semble Collections", 30 + callback: () => this.activateView(VIEW_TYPE_SEMBLE_COLLECTIONS), 37 31 }); 38 - // This adds a complex command that can check whether the current state of the app allows execution of the command 39 - this.addCommand({ 40 - id: 'open-modal-complex', 41 - name: 'Open modal (complex)', 42 - checkCallback: (checking: boolean) => { 43 - // Conditions to check 44 - const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView); 45 - if (markdownView) { 46 - // If checking is true, we're simply "checking" if the command can be run. 47 - // If checking is false, then we want to actually perform the operation. 48 - if (!checking) { 49 - new SampleModal(this.app).open(); 50 - } 32 + 33 + this.addSettingTab(new SettingTab(this.app, this)); 34 + } 35 + 51 36 52 - // This command will only show up in Command Palette when the check function returns true 53 - return true; 54 - } 55 - return false; 37 + private async initClient() { 38 + const { identifier, appPassword } = this.settings; 39 + if (identifier && appPassword) { 40 + try { 41 + this.client = await createAuthenticatedClient({ identifier, password: appPassword }); 42 + new Notice("Connected to Bluesky"); 43 + } catch (e) { 44 + new Notice(`Auth failed: ${e}`); 45 + this.client = createPublicClient(); 56 46 } 57 - }); 47 + } else { 48 + this.client = createPublicClient(); 49 + } 50 + } 58 51 59 - // This adds a settings tab so the user can configure various aspects of the plugin 60 - this.addSettingTab(new SampleSettingTab(this.app, this)); 52 + async refreshClient() { 53 + await this.initClient(); 54 + } 61 55 62 - // If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin) 63 - // Using this function will automatically remove the event listener when this plugin is disabled. 64 - this.registerDomEvent(document, 'click', (evt: MouseEvent) => { 65 - new Notice("Click"); 66 - }); 56 + private async listCollections() { 57 + if (!this.client) return; 67 58 68 - // When registering intervals, this function will automatically clear the interval when the plugin is disabled. 69 - this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000)); 59 + const repo = this.settings.identifier 70 60 61 + try { 62 + const resp = await getCollections(this.client, repo); 63 + if (!resp.ok) { 64 + new Notice(`Failed: ${resp.data?.error}`); 65 + return; 66 + } 67 + if (resp.data.records.length === 0) { 68 + new Notice("No collections found"); 69 + return; 70 + } 71 + console.log("Collections:", resp.data.records); 72 + new Notice(`Found ${resp.data.records.length} collections`); 73 + } catch (e) { 74 + new Notice(`Failed: ${e}`); 75 + } 71 76 } 72 77 73 - onunload() { 78 + async activateView(v: string) { 79 + const { workspace } = this.app; 80 + 81 + let leaf: WorkspaceLeaf | null = null; 82 + const leaves = workspace.getLeavesOfType(v); 83 + 84 + if (leaves.length > 0) { 85 + console.log("Found existing leaves:", leaves); 86 + // A leaf with our view already exists, use that 87 + leaf = leaves[0] as WorkspaceLeaf; 88 + workspace.revealLeaf(leaf); 89 + return; 90 + } 91 + 92 + // Our view could not be found in the workspace, create a new leaf 93 + // in the right sidebar for it 94 + // leaf = workspace.getRightLeaf(false); 95 + leaf = workspace.getMostRecentLeaf() 96 + await leaf?.setViewState({ type: v, active: true }); 97 + 98 + // "Reveal" the leaf in case it is in a collapsed sidebar 99 + if (leaf) { 100 + workspace.revealLeaf(leaf); 101 + } 74 102 } 75 103 76 104 async loadSettings() { 77 - this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData() as Partial<MyPluginSettings>); 105 + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); 78 106 } 79 107 80 108 async saveSettings() { 81 109 await this.saveData(this.settings); 82 110 } 83 - } 84 111 85 - class SampleModal extends Modal { 86 - constructor(app: App) { 87 - super(app); 88 - } 89 - 90 - onOpen() { 91 - let {contentEl} = this; 92 - contentEl.setText('Woah!'); 93 - } 94 - 95 - onClose() { 96 - const {contentEl} = this; 97 - contentEl.empty(); 98 - } 112 + onunload() { } 99 113 }
+36 -19
src/settings.ts
··· 1 - import {App, PluginSettingTab, Setting} from "obsidian"; 2 - import MyPlugin from "./main"; 1 + import { App, PluginSettingTab, Setting } from "obsidian"; 2 + import type MyPlugin from "./main"; 3 3 4 - export interface MyPluginSettings { 5 - mySetting: string; 4 + export interface AtProtoSettings { 5 + identifier: string; 6 + appPassword: string; 6 7 } 7 8 8 - export const DEFAULT_SETTINGS: MyPluginSettings = { 9 - mySetting: 'default' 10 - } 9 + export const DEFAULT_SETTINGS: AtProtoSettings = { 10 + identifier: "", 11 + appPassword: "", 12 + }; 11 13 12 - export class SampleSettingTab extends PluginSettingTab { 14 + export class SettingTab extends PluginSettingTab { 13 15 plugin: MyPlugin; 14 16 15 17 constructor(app: App, plugin: MyPlugin) { ··· 18 20 } 19 21 20 22 display(): void { 21 - const {containerEl} = this; 23 + const { containerEl } = this; 24 + containerEl.empty(); 22 25 23 - containerEl.empty(); 26 + new Setting(containerEl) 27 + .setName("Handle or DID") 28 + .setDesc("Your Bluesky handle (e.g., user.bsky.social) or DID") 29 + .addText((text) => 30 + text 31 + .setPlaceholder("user.bsky.social") 32 + .setValue(this.plugin.settings.identifier) 33 + .onChange(async (value) => { 34 + this.plugin.settings.identifier = value; 35 + await this.plugin.saveSettings(); 36 + }) 37 + ); 24 38 25 39 new Setting(containerEl) 26 - .setName('Settings #1') 27 - .setDesc('It\'s a secret') 28 - .addText(text => text 29 - .setPlaceholder('Enter your secret') 30 - .setValue(this.plugin.settings.mySetting) 31 - .onChange(async (value) => { 32 - this.plugin.settings.mySetting = value; 33 - await this.plugin.saveSettings(); 34 - })); 40 + .setName("App Password") 41 + .setDesc("Create one at Settings → Privacy and Security → App Passwords") 42 + .addText((text) => { 43 + text.inputEl.type = "password"; 44 + text 45 + .setPlaceholder("xxxx-xxxx-xxxx-xxxx") 46 + .setValue(this.plugin.settings.appPassword) 47 + .onChange(async (value) => { 48 + this.plugin.settings.appPassword = value; 49 + await this.plugin.saveSettings(); 50 + }); 51 + }); 35 52 } 36 53 }
+47
src/views/collections.ts
··· 1 + import { ItemView, WorkspaceLeaf } from "obsidian"; 2 + import type MyPlugin from "../main"; 3 + import { getCollections } from "../lib"; 4 + import type { Main as Collection } from "../lexicons/types/network/cosmik/collection"; 5 + 6 + export const VIEW_TYPE_SEMBLE_COLLECTIONS = "semble-collections-view"; 7 + 8 + interface CollectionRecord { 9 + uri: string; 10 + value: Collection; 11 + } 12 + 13 + export class SembleCollectionsView extends ItemView { 14 + plugin: MyPlugin; 15 + 16 + constructor(leaf: WorkspaceLeaf, plugin: MyPlugin) { 17 + super(leaf); 18 + this.plugin = plugin; 19 + } 20 + 21 + getViewType() { 22 + return VIEW_TYPE_SEMBLE_COLLECTIONS; 23 + } 24 + 25 + getDisplayText() { 26 + return "Semble Collections"; 27 + } 28 + 29 + getIcon() { 30 + return "layout-grid"; 31 + } 32 + 33 + async onOpen() { 34 + await this.render(); 35 + } 36 + 37 + async render() { 38 + const container = this.contentEl; 39 + container.empty(); 40 + container.addClass("semble-collections-view"); 41 + 42 + container.createEl("h4", { text: "Collections" }); 43 + 44 + } 45 + 46 + async onClose() {} 47 + }
+2 -1
tsconfig.json
··· 9 9 "noImplicitAny": true, 10 10 "noImplicitThis": true, 11 11 "noImplicitReturns": true, 12 - "moduleResolution": "node", 12 + "moduleResolution": "bundler", 13 13 "importHelpers": true, 14 14 "noUncheckedIndexedAccess": true, 15 15 "isolatedModules": true, ··· 17 17 "strictBindCallApply": true, 18 18 "allowSyntheticDefaultImports": true, 19 19 "useUnknownInCatchVariables": true, 20 + "types": ["@atcute/bluesky", "@atcute/atproto", "node"], 20 21 "lib": [ 21 22 "DOM", 22 23 "ES5",