···120 ReadAt *time.Time `json:"readAt,omitempty"`
121}
122000000000123func New(dsn string) (*DB, error) {
124 driver := "sqlite3"
125 if strings.HasPrefix(dsn, "postgres://") || strings.HasPrefix(dsn, "postgresql://") {
···232 )`)
233 db.Exec(`CREATE INDEX IF NOT EXISTS idx_likes_subject_uri ON likes(subject_uri)`)
234 db.Exec(`CREATE INDEX IF NOT EXISTS idx_likes_author_did ON likes(author_did)`)
0235236 db.Exec(`CREATE TABLE IF NOT EXISTS collections (
237 uri TEXT PRIMARY KEY,
···296 db.Exec(`CREATE INDEX IF NOT EXISTS idx_notifications_recipient ON notifications(recipient_did)`)
297 db.Exec(`CREATE INDEX IF NOT EXISTS idx_notifications_created_at ON notifications(created_at DESC)`)
29800000000000299 db.runMigrations()
300301 db.Exec(`CREATE TABLE IF NOT EXISTS cursors (
302 id TEXT PRIMARY KEY,
303- last_cursor INTEGER NOT NULL,
304 updated_at ` + dateType + ` NOT NULL
305 )`)
306···353 db.Exec(`UPDATE annotations SET body_value = text WHERE body_value IS NULL AND text IS NOT NULL`)
354 db.Exec(`UPDATE annotations SET target_title = title WHERE target_title IS NULL AND title IS NOT NULL`)
355 db.Exec(`UPDATE annotations SET motivation = 'commenting' WHERE motivation IS NULL`)
0000356}
357358func (db *DB) Close() error {
···120 ReadAt *time.Time `json:"readAt,omitempty"`
121}
122123+type APIKey struct {
124+ ID string `json:"id"`
125+ OwnerDID string `json:"ownerDid"`
126+ Name string `json:"name"`
127+ KeyHash string `json:"-"`
128+ CreatedAt time.Time `json:"createdAt"`
129+ LastUsedAt *time.Time `json:"lastUsedAt,omitempty"`
130+}
131+132func New(dsn string) (*DB, error) {
133 driver := "sqlite3"
134 if strings.HasPrefix(dsn, "postgres://") || strings.HasPrefix(dsn, "postgresql://") {
···241 )`)
242 db.Exec(`CREATE INDEX IF NOT EXISTS idx_likes_subject_uri ON likes(subject_uri)`)
243 db.Exec(`CREATE INDEX IF NOT EXISTS idx_likes_author_did ON likes(author_did)`)
244+ db.Exec(`CREATE INDEX IF NOT EXISTS idx_likes_author_subject ON likes(author_did, subject_uri)`)
245246 db.Exec(`CREATE TABLE IF NOT EXISTS collections (
247 uri TEXT PRIMARY KEY,
···306 db.Exec(`CREATE INDEX IF NOT EXISTS idx_notifications_recipient ON notifications(recipient_did)`)
307 db.Exec(`CREATE INDEX IF NOT EXISTS idx_notifications_created_at ON notifications(created_at DESC)`)
308309+ db.Exec(`CREATE TABLE IF NOT EXISTS api_keys (
310+ id TEXT PRIMARY KEY,
311+ owner_did TEXT NOT NULL,
312+ name TEXT NOT NULL,
313+ key_hash TEXT NOT NULL,
314+ created_at ` + dateType + ` NOT NULL,
315+ last_used_at ` + dateType + `
316+ )`)
317+ db.Exec(`CREATE INDEX IF NOT EXISTS idx_api_keys_owner ON api_keys(owner_did)`)
318+ db.Exec(`CREATE INDEX IF NOT EXISTS idx_api_keys_hash ON api_keys(key_hash)`)
319+320 db.runMigrations()
321322 db.Exec(`CREATE TABLE IF NOT EXISTS cursors (
323 id TEXT PRIMARY KEY,
324+ last_cursor BIGINT NOT NULL,
325 updated_at ` + dateType + ` NOT NULL
326 )`)
327···374 db.Exec(`UPDATE annotations SET body_value = text WHERE body_value IS NULL AND text IS NOT NULL`)
375 db.Exec(`UPDATE annotations SET target_title = title WHERE target_title IS NULL AND title IS NOT NULL`)
376 db.Exec(`UPDATE annotations SET motivation = 'commenting' WHERE motivation IS NULL`)
377+378+ if db.driver == "postgres" {
379+ db.Exec(`ALTER TABLE cursors ALTER COLUMN last_cursor TYPE BIGINT`)
380+ }
381}
382383func (db *DB) Close() error {
···1-import React from "react";
2import { Link } from "react-router-dom";
3import AnnotationCard, { HighlightCard } from "./AnnotationCard";
4import BookmarkCard from "./BookmarkCard";
···01import { Link } from "react-router-dom";
2import AnnotationCard, { HighlightCard } from "./AnnotationCard";
3import BookmarkCard from "./BookmarkCard";
···156 <BellIcon size={48} />
157 <h3>No notifications yet</h3>
158 <p>
159- When someone likes or replies to your content, you'll see it here
0160 </p>
161 </div>
162 )}
···156 <BellIcon size={48} />
157 <h3>No notifications yet</h3>
158 <p>
159+ When someone likes or replies to your content, you'll see it
160+ here
161 </p>
162 </div>
163 )}
+7-7
web/src/pages/Privacy.jsx
···16 <section>
17 <h2>Overview</h2>
18 <p>
19- Margin ("we", "our", or "us") is a web annotation tool that lets you
20- highlight, annotate, and bookmark any webpage. Your data is stored
21- on the decentralized AT Protocol network, giving you ownership and
22- control over your content.
23 </p>
24 </section>
25···111 <strong>Cookies:</strong> To maintain your logged-in session
112 </li>
113 <li>
114- <strong>Tabs:</strong> To know which page you're viewing
115 </li>
116 </ul>
117 </section>
···121 <p>You can:</p>
122 <ul>
123 <li>
124- Delete any annotation, highlight, or bookmark you've created
125 </li>
126 <li>Delete your collections</li>
127 <li>Export your data from your PDS</li>
128- <li>Revoke the extension's access at any time</li>
129 </ul>
130 </section>
131
···16 <section>
17 <h2>Overview</h2>
18 <p>
19+ Margin ("we", "our", or "us") is a web
20+ annotation tool that lets you highlight, annotate, and bookmark any
21+ webpage. Your data is stored on the decentralized AT Protocol
22+ network, giving you ownership and control over your content.
23 </p>
24 </section>
25···111 <strong>Cookies:</strong> To maintain your logged-in session
112 </li>
113 <li>
114+ <strong>Tabs:</strong> To know which page you're viewing
115 </li>
116 </ul>
117 </section>
···121 <p>You can:</p>
122 <ul>
123 <li>
124+ Delete any annotation, highlight, or bookmark you've created
125 </li>
126 <li>Delete your collections</li>
127 <li>Export your data from your PDS</li>
128+ <li>Revoke the extension's access at any time</li>
129 </ul>
130 </section>
131
···17 <h2>Overview</h2>
18 <p>
19 Margin is an open-source project. By using our service, you agree to
20- these terms ("Terms"). If you do not agree to these Terms, please do
21- not use the Service.
22 </p>
23 </section>
24···26 <h2>Open Source</h2>
27 <p>
28 Margin is open source software. The code is available publicly and
29- is provided "as is", without warranty of any kind, express or
30- implied.
31 </p>
32 </section>
33···62 <section>
63 <h2>Disclaimer</h2>
64 <p>
65- THE SERVICE IS PROVIDED "AS IS" AND "AS AVAILABLE". WE DISCLAIM ALL
66- CONDITIONS, REPRESENTATIONS AND WARRANTIES NOT EXPRESSLY SET OUT IN
67- THESE TERMS.
68 </p>
69 </section>
70
···17 <h2>Overview</h2>
18 <p>
19 Margin is an open-source project. By using our service, you agree to
20+ these terms ("Terms"). If you do not agree to these Terms,
21+ please do not use the Service.
22 </p>
23 </section>
24···26 <h2>Open Source</h2>
27 <p>
28 Margin is open source software. The code is available publicly and
29+ is provided "as is", without warranty of any kind, express
30+ or implied.
31 </p>
32 </section>
33···62 <section>
63 <h2>Disclaimer</h2>
64 <p>
65+ THE SERVICE IS PROVIDED "AS IS" AND "AS
66+ AVAILABLE". WE DISCLAIM ALL CONDITIONS, REPRESENTATIONS AND
67+ WARRANTIES NOT EXPRESSLY SET OUT IN THESE TERMS.
68 </p>
69 </section>
70