@takosjp/yurucommu-core 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +16 -0
- package/README.md +82 -0
- package/migrations/0001_init.sql +495 -0
- package/migrations/0002_social_remote_actor_edges.sql +92 -0
- package/migrations/0003_activity_remote_object_edges.sql +68 -0
- package/migrations/0004_blocklist.sql +26 -0
- package/migrations/0005_story_community_scope.sql +13 -0
- package/migrations/0006_dm_community_read_status.sql +19 -0
- package/migrations/0007_moderation_reports.sql +22 -0
- package/migrations/0008_actor_fields_aka.sql +18 -0
- package/migrations/0009_object_tags.sql +13 -0
- package/migrations/0010_object_recipients_drop_actor_fk.sql +34 -0
- package/migrations/0011_drop_remote_actor_fks.sql +205 -0
- package/migrations/0012_objects_content_fts.sql +39 -0
- package/migrations/0013_efficiency_indexes.sql +13 -0
- package/migrations/0014_inbox_actor_created_idx.sql +15 -0
- package/migrations/0015_community_bans.sql +16 -0
- package/migrations/0016_namespace_takos_oidc_subject.sql +19 -0
- package/migrations/0017_mobile_push_registrations.sql +22 -0
- package/migrations/README.md +122 -0
- package/package.json +75 -0
- package/packages/api/LICENSE +16 -0
- package/packages/api/package.json +30 -0
- package/packages/api/src/index.ts +4 -0
- package/packages/api/src/lib/api/account.ts +20 -0
- package/packages/api/src/lib/api/actors.ts +149 -0
- package/packages/api/src/lib/api/auth.ts +46 -0
- package/packages/api/src/lib/api/communities.ts +329 -0
- package/packages/api/src/lib/api/dm.test.ts +67 -0
- package/packages/api/src/lib/api/dm.ts +236 -0
- package/packages/api/src/lib/api/fetch.ts +111 -0
- package/packages/api/src/lib/api/follow.ts +30 -0
- package/packages/api/src/lib/api/media.ts +100 -0
- package/packages/api/src/lib/api/moderation.ts +98 -0
- package/packages/api/src/lib/api/normalize.ts +71 -0
- package/packages/api/src/lib/api/notifications.test.ts +63 -0
- package/packages/api/src/lib/api/notifications.ts +61 -0
- package/packages/api/src/lib/api/posts.test.ts +110 -0
- package/packages/api/src/lib/api/posts.ts +181 -0
- package/packages/api/src/lib/api/recommendations.ts +22 -0
- package/packages/api/src/lib/api/search.ts +88 -0
- package/packages/api/src/lib/api/stories.ts +80 -0
- package/packages/api/src/lib/api.ts +15 -0
- package/packages/api/src/lib/fetch-with-timeout.ts +42 -0
- package/packages/api/src/lib/transport.ts +40 -0
- package/packages/api/src/social-server.ts +47 -0
- package/packages/api/src/types/index.ts +185 -0
- package/scripts/apply-takosumi-migrations.ts +621 -0
- package/src/backend/federation-helpers.ts +36 -0
- package/src/backend/index.ts +872 -0
- package/src/backend/lib/account-migration.ts +106 -0
- package/src/backend/lib/activitypub-actor-cache.ts +238 -0
- package/src/backend/lib/activitypub-helpers.ts +131 -0
- package/src/backend/lib/activitypub-validators.ts +323 -0
- package/src/backend/lib/ap-context.ts +16 -0
- package/src/backend/lib/ap-ids.ts +101 -0
- package/src/backend/lib/ap-response.ts +30 -0
- package/src/backend/lib/ap-signing.ts +87 -0
- package/src/backend/lib/ap-verify.ts +670 -0
- package/src/backend/lib/auth-lockout.ts +230 -0
- package/src/backend/lib/backend-paths.ts +34 -0
- package/src/backend/lib/base64.ts +30 -0
- package/src/backend/lib/blocklist-purge.ts +109 -0
- package/src/backend/lib/blocklist.ts +279 -0
- package/src/backend/lib/chunk.ts +33 -0
- package/src/backend/lib/client-ip.ts +169 -0
- package/src/backend/lib/community-visibility.ts +230 -0
- package/src/backend/lib/crypto.ts +424 -0
- package/src/backend/lib/delivery/circuit.ts +265 -0
- package/src/backend/lib/delivery/metrics.ts +30 -0
- package/src/backend/lib/delivery/planner.ts +190 -0
- package/src/backend/lib/delivery/queue-batching.ts +626 -0
- package/src/backend/lib/delivery/queue-delivery.ts +641 -0
- package/src/backend/lib/delivery/queue.ts +576 -0
- package/src/backend/lib/delivery/transformers.ts +56 -0
- package/src/backend/lib/delivery/types.ts +139 -0
- package/src/backend/lib/errors.ts +114 -0
- package/src/backend/lib/federation-fetch.ts +296 -0
- package/src/backend/lib/feed-cursor.ts +57 -0
- package/src/backend/lib/feed-exclude.ts +48 -0
- package/src/backend/lib/hex.ts +8 -0
- package/src/backend/lib/log-mask.ts +213 -0
- package/src/backend/lib/logger.ts +285 -0
- package/src/backend/lib/mobile-contract.ts +137 -0
- package/src/backend/lib/oauth-providers.ts +324 -0
- package/src/backend/lib/oauth-utils.ts +148 -0
- package/src/backend/lib/oidc-id-token.ts +151 -0
- package/src/backend/lib/parse-helpers.ts +31 -0
- package/src/backend/lib/post-visibility.ts +190 -0
- package/src/backend/lib/session-actor.ts +61 -0
- package/src/backend/lib/ssrf.ts +428 -0
- package/src/backend/lib/strip-image-metadata.ts +191 -0
- package/src/backend/middleware/bearer-auth.ts +70 -0
- package/src/backend/middleware/body-limit.ts +212 -0
- package/src/backend/middleware/cache.ts +429 -0
- package/src/backend/middleware/csrf.ts +130 -0
- package/src/backend/middleware/error-handler.ts +77 -0
- package/src/backend/middleware/rate-limit.ts +308 -0
- package/src/backend/public.ts +21 -0
- package/src/backend/routes/account-teardown.ts +430 -0
- package/src/backend/routes/activitypub/handlers/actor-inbox-handlers.ts +354 -0
- package/src/backend/routes/activitypub/handlers/inbound-timestamp.ts +29 -0
- package/src/backend/routes/activitypub/handlers/inbox-content-handlers.ts +1634 -0
- package/src/backend/routes/activitypub/handlers/inbox-follow-handlers.ts +547 -0
- package/src/backend/routes/activitypub/handlers/inbox-interaction-handlers.ts +497 -0
- package/src/backend/routes/activitypub/handlers/inbox-shared-helpers.ts +262 -0
- package/src/backend/routes/activitypub/handlers/user-inbox-handlers.ts +35 -0
- package/src/backend/routes/activitypub/inbox-types.ts +74 -0
- package/src/backend/routes/activitypub/inbox.ts +1191 -0
- package/src/backend/routes/activitypub/outbox.ts +0 -0
- package/src/backend/routes/activitypub/query-helpers.ts +227 -0
- package/src/backend/routes/activitypub.ts +616 -0
- package/src/backend/routes/actors-helpers.ts +487 -0
- package/src/backend/routes/actors.ts +1311 -0
- package/src/backend/routes/apps.ts +313 -0
- package/src/backend/routes/auth-helpers.ts +566 -0
- package/src/backend/routes/auth.ts +615 -0
- package/src/backend/routes/communities/membership-invites.ts +208 -0
- package/src/backend/routes/communities/membership-join.ts +335 -0
- package/src/backend/routes/communities/membership-members.ts +539 -0
- package/src/backend/routes/communities/membership-requests.ts +296 -0
- package/src/backend/routes/communities/membership-shared.ts +364 -0
- package/src/backend/routes/communities/messages.ts +479 -0
- package/src/backend/routes/communities/routes.ts +624 -0
- package/src/backend/routes/communities.ts +21 -0
- package/src/backend/routes/dm/contacts.ts +525 -0
- package/src/backend/routes/dm/conversations-helpers.ts +197 -0
- package/src/backend/routes/dm/conversations.ts +25 -0
- package/src/backend/routes/dm/messages.ts +658 -0
- package/src/backend/routes/dm/query-helpers.ts +85 -0
- package/src/backend/routes/dm/read-archive.ts +228 -0
- package/src/backend/routes/dm/requests.ts +222 -0
- package/src/backend/routes/dm/typing.ts +81 -0
- package/src/backend/routes/dm.ts +15 -0
- package/src/backend/routes/follow-helpers.ts +370 -0
- package/src/backend/routes/follow.ts +588 -0
- package/src/backend/routes/media.ts +692 -0
- package/src/backend/routes/mobile.ts +159 -0
- package/src/backend/routes/moderation.ts +373 -0
- package/src/backend/routes/notifications.ts +757 -0
- package/src/backend/routes/posts/delete-cascade.ts +330 -0
- package/src/backend/routes/posts/interactions.ts +795 -0
- package/src/backend/routes/posts/post-helpers.ts +847 -0
- package/src/backend/routes/posts/queries.ts +537 -0
- package/src/backend/routes/posts/routes.ts +865 -0
- package/src/backend/routes/posts/transformers.ts +161 -0
- package/src/backend/routes/posts.ts +17 -0
- package/src/backend/routes/recommendations.ts +88 -0
- package/src/backend/routes/search.ts +730 -0
- package/src/backend/routes/stories/interactions.ts +576 -0
- package/src/backend/routes/stories/query-helpers.ts +482 -0
- package/src/backend/routes/stories/routes.ts +906 -0
- package/src/backend/routes/stories.ts +13 -0
- package/src/backend/routes/takos-tools/dm.ts +249 -0
- package/src/backend/routes/takos-tools/follows.ts +225 -0
- package/src/backend/routes/takos-tools/posts.ts +292 -0
- package/src/backend/routes/takos-tools/search.ts +228 -0
- package/src/backend/routes/takos-tools/timeline.ts +132 -0
- package/src/backend/routes/takos-tools/types.ts +10 -0
- package/src/backend/routes/takos-tools-response.ts +178 -0
- package/src/backend/routes/takos-tools.ts +153 -0
- package/src/backend/routes/timeline.ts +755 -0
- package/src/backend/runtime/bun.ts +620 -0
- package/src/backend/runtime/cloudflare.ts +202 -0
- package/src/backend/runtime/compat-bun/types.ts +44 -0
- package/src/backend/runtime/memory-kv.ts +104 -0
- package/src/backend/runtime/shared.ts +142 -0
- package/src/backend/runtime/types.ts +205 -0
- package/src/backend/server.ts +636 -0
- package/src/backend/types.ts +143 -0
- package/src/db/index.ts +97 -0
- package/src/db/schema/actors.ts +129 -0
- package/src/db/schema/communities.ts +133 -0
- package/src/db/schema/date-utils.ts +17 -0
- package/src/db/schema/index.ts +17 -0
- package/src/db/schema/messaging.ts +241 -0
- package/src/db/schema/mobile.ts +37 -0
- package/src/db/schema/posts.ts +150 -0
- package/src/db/schema/relations.ts +266 -0
- package/src/db/schema/reports.ts +33 -0
- package/src/db/schema/social.ts +106 -0
- package/src/db/schema/stories.ts +70 -0
- package/src/db/schema.ts +15 -0
- package/src/plugin/public.ts +7 -0
- package/src/runtime/site-worker.ts +10 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
|
|
3
|
+
GNU Affero General Public License v3.0 only
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2026 Takos Contributors
|
|
6
|
+
|
|
7
|
+
This program is free software: you can redistribute it and/or modify it under
|
|
8
|
+
the terms of the GNU Affero General Public License as published by the Free
|
|
9
|
+
Software Foundation, version 3 of the License.
|
|
10
|
+
|
|
11
|
+
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
12
|
+
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
13
|
+
PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License along
|
|
16
|
+
with this program. If not, see <https://www.gnu.org/licenses/agpl-3.0.html>.
|
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Yurucommu Core
|
|
2
|
+
|
|
3
|
+
Yurucommu Core is the shared **ActivityPub / API / DB / runtime engine library**
|
|
4
|
+
for the yurucommu family. It is not the installable product repo and it does not
|
|
5
|
+
own an OpenTofu Capsule.
|
|
6
|
+
|
|
7
|
+
The deployable products are separate repositories:
|
|
8
|
+
|
|
9
|
+
- `yurucommu` owns the feed / story / profile fullstack product, `yurucommu.com`,
|
|
10
|
+
its Worker artifact, and its OpenTofu Capsule.
|
|
11
|
+
- `yurumeet` owns the talk-first fullstack product. `yurume` is the short client
|
|
12
|
+
id / abbreviation used in discovery and push registration.
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- **ActivityPub federation** — follow, post, boost, like, and reply across
|
|
17
|
+
servers to link your communities and connections, with HTTP-signature
|
|
18
|
+
verification, SSRF-guarded fetches, and actor/domain blocklists.
|
|
19
|
+
- **Server API** — actor, post, story, DM, community, media, notification, and
|
|
20
|
+
mobile-push routes.
|
|
21
|
+
- **Client contract** — a typed SDK and discovery types for yurucommu,
|
|
22
|
+
Yurumeet, mobile, and alternate clients.
|
|
23
|
+
- **Search, notifications, recommendations** — discover people and content.
|
|
24
|
+
- **Auth** — password, Google / X OAuth, and Takosumi Accounts OIDC consumer.
|
|
25
|
+
- **Bilingual UI** — Japanese / English.
|
|
26
|
+
|
|
27
|
+
## Deployment Boundary
|
|
28
|
+
|
|
29
|
+
Do not install this repo as a Capsule. Install `yurucommu` or `yurumeet`
|
|
30
|
+
instead. Those product repos bundle their own UI with this server engine, publish
|
|
31
|
+
their own Worker artifact, and expose their own plain OpenTofu module.
|
|
32
|
+
|
|
33
|
+
Client implementations should use `@takosjp/yurucommu-api`. Product Worker
|
|
34
|
+
artifacts use `@takosjp/yurucommu-core/server` to create the Hono backend and
|
|
35
|
+
`@takosjp/yurucommu-core/migrations` for D1 migration activation. They should
|
|
36
|
+
not import unpublished source paths from this checkout.
|
|
37
|
+
|
|
38
|
+
## Develop
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
cd yurucommu-core
|
|
42
|
+
bun install
|
|
43
|
+
bun run check # tsc --noEmit
|
|
44
|
+
bun test # bun:test suite
|
|
45
|
+
bun run lint # type check
|
|
46
|
+
bun run fmt # prettier
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The backend engine source lives in `src/backend` (Hono routes, ActivityPub
|
|
50
|
+
federation, delivery pipeline), the shared npm API package in `packages/api`,
|
|
51
|
+
and the database schema and migrations in `src/db/schema` and `migrations/`.
|
|
52
|
+
|
|
53
|
+
API package commands:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
bun run build:api # build @takosjp/yurucommu-api
|
|
57
|
+
bun run pack:api # npm pack --dry-run for the API package
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Yurumeet and mobile clients live in separate repositories. They should depend on
|
|
61
|
+
`@takosjp/yurucommu-api`, discover a server through Capsule outputs or
|
|
62
|
+
`/.well-known/social-server`, and deploy their own static/runtime artifact
|
|
63
|
+
through Takosumi, Cloudflare, or a self-host runtime. Local checkouts can be
|
|
64
|
+
placed under `clients/` for debugging, but that directory is intentionally
|
|
65
|
+
ignored so the server repo stays small.
|
|
66
|
+
|
|
67
|
+
When a client runs on a separate origin, the yurucommu-server must include that
|
|
68
|
+
origin in its CORS / CSRF allowlist.
|
|
69
|
+
|
|
70
|
+
## Boundaries
|
|
71
|
+
|
|
72
|
+
Yurucommu implements its own ActivityPub federation, content distribution, and
|
|
73
|
+
user identity entirely at the app layer — it does not depend on Takos core
|
|
74
|
+
services or on a platform-layer federation mechanism. When installed through
|
|
75
|
+
Takosumi it is a normal Capsule a user can remove, and it is never absorbed into
|
|
76
|
+
Takos core. See [`AGENTS.md`](AGENTS.md) for the full product boundary.
|
|
77
|
+
|
|
78
|
+
## Documentation
|
|
79
|
+
|
|
80
|
+
- [Deployment guide](https://yurucommu.com/help/deployment.html)
|
|
81
|
+
- [Getting started](https://yurucommu.com/help/getting-started.html)
|
|
82
|
+
- [Help site](https://yurucommu.com/help/)
|
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
-- Yurucommu Initial Schema (consolidated from Prisma schema)
|
|
2
|
+
-- Generated 2026-03-07
|
|
3
|
+
|
|
4
|
+
-- ============================================================
|
|
5
|
+
-- ACTORS (Local accounts - Person type)
|
|
6
|
+
-- ============================================================
|
|
7
|
+
CREATE TABLE IF NOT EXISTS actors (
|
|
8
|
+
ap_id TEXT PRIMARY KEY,
|
|
9
|
+
type TEXT NOT NULL DEFAULT 'Person',
|
|
10
|
+
preferred_username TEXT NOT NULL UNIQUE,
|
|
11
|
+
name TEXT,
|
|
12
|
+
summary TEXT,
|
|
13
|
+
icon_url TEXT,
|
|
14
|
+
header_url TEXT,
|
|
15
|
+
inbox TEXT NOT NULL,
|
|
16
|
+
outbox TEXT NOT NULL,
|
|
17
|
+
followers_url TEXT NOT NULL,
|
|
18
|
+
following_url TEXT NOT NULL,
|
|
19
|
+
public_key_pem TEXT NOT NULL,
|
|
20
|
+
private_key_pem TEXT NOT NULL,
|
|
21
|
+
takos_user_id TEXT UNIQUE,
|
|
22
|
+
follower_count INTEGER DEFAULT 0,
|
|
23
|
+
following_count INTEGER DEFAULT 0,
|
|
24
|
+
post_count INTEGER DEFAULT 0,
|
|
25
|
+
is_private INTEGER DEFAULT 0,
|
|
26
|
+
role TEXT DEFAULT 'member',
|
|
27
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
28
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
29
|
+
deleted_at TEXT,
|
|
30
|
+
owner_actor_ap_id TEXT
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
CREATE INDEX IF NOT EXISTS idx_actors_preferred_username ON actors(preferred_username);
|
|
34
|
+
CREATE INDEX IF NOT EXISTS idx_actors_takos_user_id ON actors(takos_user_id);
|
|
35
|
+
CREATE INDEX IF NOT EXISTS idx_actors_deleted_at ON actors(deleted_at);
|
|
36
|
+
|
|
37
|
+
-- ============================================================
|
|
38
|
+
-- ACTOR_CACHE (Remote actors - cached from federation)
|
|
39
|
+
-- ============================================================
|
|
40
|
+
CREATE TABLE IF NOT EXISTS actor_cache (
|
|
41
|
+
ap_id TEXT PRIMARY KEY,
|
|
42
|
+
type TEXT NOT NULL DEFAULT 'Person',
|
|
43
|
+
preferred_username TEXT,
|
|
44
|
+
name TEXT,
|
|
45
|
+
summary TEXT,
|
|
46
|
+
icon_url TEXT,
|
|
47
|
+
inbox TEXT NOT NULL,
|
|
48
|
+
outbox TEXT,
|
|
49
|
+
followers_url TEXT,
|
|
50
|
+
following_url TEXT,
|
|
51
|
+
shared_inbox TEXT,
|
|
52
|
+
public_key_id TEXT,
|
|
53
|
+
public_key_pem TEXT,
|
|
54
|
+
raw_json TEXT NOT NULL,
|
|
55
|
+
last_fetched_at TEXT DEFAULT (datetime('now')),
|
|
56
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
-- ============================================================
|
|
60
|
+
-- COMMUNITIES (must be before objects due to FK reference)
|
|
61
|
+
-- ============================================================
|
|
62
|
+
CREATE TABLE IF NOT EXISTS communities (
|
|
63
|
+
ap_id TEXT PRIMARY KEY,
|
|
64
|
+
type TEXT NOT NULL DEFAULT 'Group',
|
|
65
|
+
preferred_username TEXT NOT NULL UNIQUE,
|
|
66
|
+
name TEXT NOT NULL,
|
|
67
|
+
summary TEXT,
|
|
68
|
+
icon_url TEXT,
|
|
69
|
+
inbox TEXT NOT NULL,
|
|
70
|
+
outbox TEXT NOT NULL,
|
|
71
|
+
followers_url TEXT NOT NULL,
|
|
72
|
+
visibility TEXT DEFAULT 'public',
|
|
73
|
+
join_policy TEXT DEFAULT 'open',
|
|
74
|
+
post_policy TEXT DEFAULT 'members',
|
|
75
|
+
public_key_pem TEXT NOT NULL,
|
|
76
|
+
private_key_pem TEXT NOT NULL,
|
|
77
|
+
created_by TEXT NOT NULL,
|
|
78
|
+
member_count INTEGER DEFAULT 0,
|
|
79
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
80
|
+
last_message_at TEXT,
|
|
81
|
+
deleted_at TEXT
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
CREATE INDEX IF NOT EXISTS idx_communities_deleted_at ON communities(deleted_at);
|
|
85
|
+
CREATE INDEX IF NOT EXISTS idx_communities_visibility ON communities(visibility);
|
|
86
|
+
|
|
87
|
+
-- ============================================================
|
|
88
|
+
-- OBJECTS (All AP objects - Note, Article, etc.)
|
|
89
|
+
-- ============================================================
|
|
90
|
+
CREATE TABLE IF NOT EXISTS objects (
|
|
91
|
+
ap_id TEXT PRIMARY KEY,
|
|
92
|
+
type TEXT NOT NULL DEFAULT 'Note',
|
|
93
|
+
attributed_to TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
94
|
+
content TEXT NOT NULL DEFAULT '',
|
|
95
|
+
summary TEXT,
|
|
96
|
+
attachments_json TEXT DEFAULT '[]',
|
|
97
|
+
in_reply_to TEXT,
|
|
98
|
+
conversation TEXT,
|
|
99
|
+
visibility TEXT DEFAULT 'public',
|
|
100
|
+
to_json TEXT DEFAULT '[]',
|
|
101
|
+
cc_json TEXT DEFAULT '[]',
|
|
102
|
+
audience_json TEXT DEFAULT '[]',
|
|
103
|
+
community_ap_id TEXT REFERENCES communities(ap_id) ON DELETE SET NULL,
|
|
104
|
+
end_time TEXT,
|
|
105
|
+
like_count INTEGER DEFAULT 0,
|
|
106
|
+
reply_count INTEGER DEFAULT 0,
|
|
107
|
+
announce_count INTEGER DEFAULT 0,
|
|
108
|
+
share_count INTEGER DEFAULT 0,
|
|
109
|
+
published TEXT DEFAULT (datetime('now')),
|
|
110
|
+
updated TEXT,
|
|
111
|
+
is_local INTEGER DEFAULT 1,
|
|
112
|
+
raw_json TEXT,
|
|
113
|
+
deleted_at TEXT
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
CREATE INDEX IF NOT EXISTS idx_objects_attributed_to ON objects(attributed_to);
|
|
117
|
+
CREATE INDEX IF NOT EXISTS idx_objects_in_reply_to ON objects(in_reply_to);
|
|
118
|
+
CREATE INDEX IF NOT EXISTS idx_objects_community_ap_id ON objects(community_ap_id);
|
|
119
|
+
CREATE INDEX IF NOT EXISTS idx_objects_published ON objects(published DESC);
|
|
120
|
+
CREATE INDEX IF NOT EXISTS idx_objects_visibility ON objects(visibility);
|
|
121
|
+
CREATE INDEX IF NOT EXISTS idx_objects_end_time ON objects(end_time);
|
|
122
|
+
CREATE INDEX IF NOT EXISTS idx_objects_deleted_at ON objects(deleted_at);
|
|
123
|
+
CREATE INDEX IF NOT EXISTS idx_objects_attributed_to_published ON objects(attributed_to, published DESC);
|
|
124
|
+
CREATE INDEX IF NOT EXISTS idx_objects_visibility_published ON objects(visibility, published DESC);
|
|
125
|
+
CREATE INDEX IF NOT EXISTS idx_objects_type_visibility_published ON objects(type, visibility, published DESC);
|
|
126
|
+
CREATE INDEX IF NOT EXISTS idx_objects_conversation ON objects(conversation);
|
|
127
|
+
CREATE INDEX IF NOT EXISTS idx_objects_community_published ON objects(community_ap_id, published DESC);
|
|
128
|
+
CREATE INDEX IF NOT EXISTS idx_objects_is_local ON objects(is_local);
|
|
129
|
+
|
|
130
|
+
-- ============================================================
|
|
131
|
+
-- FOLLOWS
|
|
132
|
+
-- ============================================================
|
|
133
|
+
CREATE TABLE IF NOT EXISTS follows (
|
|
134
|
+
follower_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
135
|
+
following_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
136
|
+
status TEXT DEFAULT 'pending',
|
|
137
|
+
activity_ap_id TEXT,
|
|
138
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
139
|
+
accepted_at TEXT,
|
|
140
|
+
PRIMARY KEY (follower_ap_id, following_ap_id)
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
CREATE INDEX IF NOT EXISTS idx_follows_follower_status ON follows(follower_ap_id, status);
|
|
144
|
+
CREATE INDEX IF NOT EXISTS idx_follows_following_status ON follows(following_ap_id, status);
|
|
145
|
+
CREATE INDEX IF NOT EXISTS idx_follows_following_created ON follows(following_ap_id, created_at DESC);
|
|
146
|
+
CREATE INDEX IF NOT EXISTS idx_follows_activity ON follows(activity_ap_id);
|
|
147
|
+
|
|
148
|
+
-- ============================================================
|
|
149
|
+
-- LIKES
|
|
150
|
+
-- ============================================================
|
|
151
|
+
CREATE TABLE IF NOT EXISTS likes (
|
|
152
|
+
actor_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
153
|
+
object_ap_id TEXT NOT NULL REFERENCES objects(ap_id) ON DELETE CASCADE,
|
|
154
|
+
activity_ap_id TEXT,
|
|
155
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
156
|
+
PRIMARY KEY (actor_ap_id, object_ap_id)
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
CREATE INDEX IF NOT EXISTS idx_likes_object ON likes(object_ap_id);
|
|
160
|
+
CREATE INDEX IF NOT EXISTS idx_likes_actor ON likes(actor_ap_id);
|
|
161
|
+
CREATE INDEX IF NOT EXISTS idx_likes_actor_object ON likes(actor_ap_id, object_ap_id);
|
|
162
|
+
|
|
163
|
+
-- ============================================================
|
|
164
|
+
-- ANNOUNCES (Reposts/Boosts)
|
|
165
|
+
-- ============================================================
|
|
166
|
+
CREATE TABLE IF NOT EXISTS announces (
|
|
167
|
+
actor_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
168
|
+
object_ap_id TEXT NOT NULL REFERENCES objects(ap_id) ON DELETE CASCADE,
|
|
169
|
+
activity_ap_id TEXT,
|
|
170
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
171
|
+
PRIMARY KEY (actor_ap_id, object_ap_id)
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
CREATE INDEX IF NOT EXISTS idx_announces_object ON announces(object_ap_id);
|
|
175
|
+
CREATE INDEX IF NOT EXISTS idx_announces_actor ON announces(actor_ap_id);
|
|
176
|
+
CREATE INDEX IF NOT EXISTS idx_announces_actor_object ON announces(actor_ap_id, object_ap_id);
|
|
177
|
+
|
|
178
|
+
-- ============================================================
|
|
179
|
+
-- BOOKMARKS
|
|
180
|
+
-- ============================================================
|
|
181
|
+
CREATE TABLE IF NOT EXISTS bookmarks (
|
|
182
|
+
actor_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
183
|
+
object_ap_id TEXT NOT NULL REFERENCES objects(ap_id) ON DELETE CASCADE,
|
|
184
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
185
|
+
PRIMARY KEY (actor_ap_id, object_ap_id)
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
CREATE INDEX IF NOT EXISTS idx_bookmarks_actor ON bookmarks(actor_ap_id);
|
|
189
|
+
|
|
190
|
+
-- ============================================================
|
|
191
|
+
-- BLOCKS
|
|
192
|
+
-- ============================================================
|
|
193
|
+
CREATE TABLE IF NOT EXISTS blocks (
|
|
194
|
+
blocker_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
195
|
+
blocked_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
196
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
197
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
198
|
+
PRIMARY KEY (blocker_ap_id, blocked_ap_id)
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
CREATE INDEX IF NOT EXISTS idx_blocks_blocker ON blocks(blocker_ap_id);
|
|
202
|
+
CREATE INDEX IF NOT EXISTS idx_blocks_blocked ON blocks(blocked_ap_id);
|
|
203
|
+
|
|
204
|
+
-- ============================================================
|
|
205
|
+
-- MUTES
|
|
206
|
+
-- ============================================================
|
|
207
|
+
CREATE TABLE IF NOT EXISTS mutes (
|
|
208
|
+
muter_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
209
|
+
muted_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
210
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
211
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
212
|
+
PRIMARY KEY (muter_ap_id, muted_ap_id)
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
CREATE INDEX IF NOT EXISTS idx_mutes_muter ON mutes(muter_ap_id);
|
|
216
|
+
CREATE INDEX IF NOT EXISTS idx_mutes_muted ON mutes(muted_ap_id);
|
|
217
|
+
|
|
218
|
+
-- ============================================================
|
|
219
|
+
-- ACTIVITIES
|
|
220
|
+
-- ============================================================
|
|
221
|
+
CREATE TABLE IF NOT EXISTS activities (
|
|
222
|
+
ap_id TEXT PRIMARY KEY,
|
|
223
|
+
type TEXT NOT NULL,
|
|
224
|
+
actor_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
225
|
+
object_ap_id TEXT REFERENCES objects(ap_id) ON DELETE SET NULL,
|
|
226
|
+
object_json TEXT,
|
|
227
|
+
target_ap_id TEXT,
|
|
228
|
+
raw_json TEXT NOT NULL,
|
|
229
|
+
direction TEXT,
|
|
230
|
+
processed INTEGER DEFAULT 0,
|
|
231
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
CREATE INDEX IF NOT EXISTS idx_activities_actor ON activities(actor_ap_id);
|
|
235
|
+
CREATE INDEX IF NOT EXISTS idx_activities_object ON activities(object_ap_id);
|
|
236
|
+
CREATE INDEX IF NOT EXISTS idx_activities_type ON activities(type);
|
|
237
|
+
CREATE INDEX IF NOT EXISTS idx_activities_type_created ON activities(type, created_at DESC);
|
|
238
|
+
CREATE INDEX IF NOT EXISTS idx_activities_direction_processed ON activities(direction, processed);
|
|
239
|
+
CREATE INDEX IF NOT EXISTS idx_activities_direction_processed_created ON activities(direction, processed, created_at);
|
|
240
|
+
|
|
241
|
+
-- ============================================================
|
|
242
|
+
-- DELIVERY_QUEUE
|
|
243
|
+
-- ============================================================
|
|
244
|
+
CREATE TABLE IF NOT EXISTS delivery_queue (
|
|
245
|
+
id TEXT PRIMARY KEY,
|
|
246
|
+
activity_ap_id TEXT NOT NULL,
|
|
247
|
+
inbox_url TEXT NOT NULL,
|
|
248
|
+
status TEXT DEFAULT 'pending',
|
|
249
|
+
attempts INTEGER DEFAULT 0,
|
|
250
|
+
last_attempt_at TEXT,
|
|
251
|
+
processing_started_at TEXT,
|
|
252
|
+
next_attempt_at TEXT DEFAULT (datetime('now')),
|
|
253
|
+
delivered_at TEXT,
|
|
254
|
+
error TEXT,
|
|
255
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
CREATE INDEX IF NOT EXISTS idx_delivery_queue_activity ON delivery_queue(activity_ap_id);
|
|
259
|
+
CREATE INDEX IF NOT EXISTS idx_delivery_queue_next ON delivery_queue(next_attempt_at);
|
|
260
|
+
CREATE INDEX IF NOT EXISTS idx_delivery_queue_status_next ON delivery_queue(status, next_attempt_at);
|
|
261
|
+
|
|
262
|
+
-- ============================================================
|
|
263
|
+
-- DELIVERY_CIRCUIT (Circuit breaker state per endpoint)
|
|
264
|
+
-- ============================================================
|
|
265
|
+
CREATE TABLE IF NOT EXISTS delivery_circuit (
|
|
266
|
+
endpoint TEXT PRIMARY KEY,
|
|
267
|
+
state TEXT DEFAULT 'closed',
|
|
268
|
+
consecutive_failures INTEGER DEFAULT 0,
|
|
269
|
+
recent_outcomes_json TEXT DEFAULT '[]',
|
|
270
|
+
open_until TEXT,
|
|
271
|
+
half_open_probe_attempts INTEGER DEFAULT 0,
|
|
272
|
+
half_open_probe_successes INTEGER DEFAULT 0,
|
|
273
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
274
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
CREATE INDEX IF NOT EXISTS idx_delivery_circuit_state ON delivery_circuit(state, updated_at);
|
|
278
|
+
|
|
279
|
+
-- ============================================================
|
|
280
|
+
-- COMMUNITY_MEMBERS
|
|
281
|
+
-- ============================================================
|
|
282
|
+
CREATE TABLE IF NOT EXISTS community_members (
|
|
283
|
+
community_ap_id TEXT NOT NULL REFERENCES communities(ap_id) ON DELETE CASCADE,
|
|
284
|
+
actor_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
285
|
+
role TEXT DEFAULT 'member',
|
|
286
|
+
joined_at TEXT DEFAULT (datetime('now')),
|
|
287
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
288
|
+
PRIMARY KEY (community_ap_id, actor_ap_id)
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
CREATE INDEX IF NOT EXISTS idx_community_members_actor ON community_members(actor_ap_id);
|
|
292
|
+
CREATE INDEX IF NOT EXISTS idx_community_members_role ON community_members(community_ap_id, role, joined_at);
|
|
293
|
+
|
|
294
|
+
-- ============================================================
|
|
295
|
+
-- COMMUNITY_JOIN_REQUESTS
|
|
296
|
+
-- ============================================================
|
|
297
|
+
CREATE TABLE IF NOT EXISTS community_join_requests (
|
|
298
|
+
community_ap_id TEXT NOT NULL REFERENCES communities(ap_id) ON DELETE CASCADE,
|
|
299
|
+
actor_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
300
|
+
status TEXT DEFAULT 'pending',
|
|
301
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
302
|
+
processed_at TEXT,
|
|
303
|
+
PRIMARY KEY (community_ap_id, actor_ap_id)
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
CREATE INDEX IF NOT EXISTS idx_community_join_requests_status ON community_join_requests(community_ap_id, status);
|
|
307
|
+
CREATE INDEX IF NOT EXISTS idx_community_join_requests_actor ON community_join_requests(actor_ap_id);
|
|
308
|
+
|
|
309
|
+
-- ============================================================
|
|
310
|
+
-- COMMUNITY_INVITES
|
|
311
|
+
-- ============================================================
|
|
312
|
+
CREATE TABLE IF NOT EXISTS community_invites (
|
|
313
|
+
id TEXT PRIMARY KEY,
|
|
314
|
+
community_ap_id TEXT NOT NULL REFERENCES communities(ap_id) ON DELETE CASCADE,
|
|
315
|
+
invited_by_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
316
|
+
invited_ap_id TEXT,
|
|
317
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
318
|
+
expires_at TEXT,
|
|
319
|
+
used_at TEXT,
|
|
320
|
+
used_by_ap_id TEXT
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
CREATE INDEX IF NOT EXISTS idx_community_invites_community ON community_invites(community_ap_id);
|
|
324
|
+
CREATE INDEX IF NOT EXISTS idx_community_invites_invited_by ON community_invites(invited_by_ap_id);
|
|
325
|
+
|
|
326
|
+
-- ============================================================
|
|
327
|
+
-- OBJECT_RECIPIENTS
|
|
328
|
+
-- ============================================================
|
|
329
|
+
CREATE TABLE IF NOT EXISTS object_recipients (
|
|
330
|
+
object_ap_id TEXT NOT NULL REFERENCES objects(ap_id) ON DELETE CASCADE,
|
|
331
|
+
recipient_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
332
|
+
type TEXT NOT NULL,
|
|
333
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
334
|
+
PRIMARY KEY (object_ap_id, recipient_ap_id)
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
CREATE INDEX IF NOT EXISTS idx_object_recipients_recipient ON object_recipients(recipient_ap_id, created_at DESC);
|
|
338
|
+
|
|
339
|
+
-- ============================================================
|
|
340
|
+
-- INBOX
|
|
341
|
+
-- ============================================================
|
|
342
|
+
CREATE TABLE IF NOT EXISTS inbox (
|
|
343
|
+
actor_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
344
|
+
activity_ap_id TEXT NOT NULL REFERENCES activities(ap_id) ON DELETE CASCADE,
|
|
345
|
+
read INTEGER DEFAULT 0,
|
|
346
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
347
|
+
PRIMARY KEY (actor_ap_id, activity_ap_id)
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
CREATE INDEX IF NOT EXISTS idx_inbox_actor_read ON inbox(actor_ap_id, read, created_at DESC);
|
|
351
|
+
CREATE INDEX IF NOT EXISTS idx_inbox_activity ON inbox(activity_ap_id);
|
|
352
|
+
|
|
353
|
+
-- ============================================================
|
|
354
|
+
-- SESSIONS
|
|
355
|
+
-- ============================================================
|
|
356
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
357
|
+
id TEXT PRIMARY KEY,
|
|
358
|
+
member_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
359
|
+
access_token TEXT NOT NULL UNIQUE,
|
|
360
|
+
refresh_token TEXT,
|
|
361
|
+
expires_at TEXT NOT NULL,
|
|
362
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
363
|
+
provider TEXT,
|
|
364
|
+
provider_access_token TEXT,
|
|
365
|
+
provider_refresh_token TEXT,
|
|
366
|
+
provider_token_expires_at TEXT
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_member ON sessions(member_id);
|
|
370
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_provider ON sessions(provider);
|
|
371
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_expires ON sessions(expires_at);
|
|
372
|
+
|
|
373
|
+
-- ============================================================
|
|
374
|
+
-- STORY_VIEWS
|
|
375
|
+
-- ============================================================
|
|
376
|
+
CREATE TABLE IF NOT EXISTS story_views (
|
|
377
|
+
actor_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
378
|
+
story_ap_id TEXT NOT NULL REFERENCES objects(ap_id) ON DELETE CASCADE,
|
|
379
|
+
viewed_at TEXT DEFAULT (datetime('now')),
|
|
380
|
+
PRIMARY KEY (actor_ap_id, story_ap_id)
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
CREATE INDEX IF NOT EXISTS idx_story_views_actor ON story_views(actor_ap_id);
|
|
384
|
+
CREATE INDEX IF NOT EXISTS idx_story_views_story ON story_views(story_ap_id);
|
|
385
|
+
|
|
386
|
+
-- ============================================================
|
|
387
|
+
-- STORY_VOTES
|
|
388
|
+
-- ============================================================
|
|
389
|
+
CREATE TABLE IF NOT EXISTS story_votes (
|
|
390
|
+
id TEXT PRIMARY KEY,
|
|
391
|
+
story_ap_id TEXT NOT NULL REFERENCES objects(ap_id) ON DELETE CASCADE,
|
|
392
|
+
actor_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
393
|
+
option_index INTEGER NOT NULL,
|
|
394
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
395
|
+
UNIQUE(story_ap_id, actor_ap_id)
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
CREATE INDEX IF NOT EXISTS idx_story_votes_story ON story_votes(story_ap_id);
|
|
399
|
+
CREATE INDEX IF NOT EXISTS idx_story_votes_actor ON story_votes(actor_ap_id);
|
|
400
|
+
|
|
401
|
+
-- ============================================================
|
|
402
|
+
-- STORY_SHARES
|
|
403
|
+
-- ============================================================
|
|
404
|
+
CREATE TABLE IF NOT EXISTS story_shares (
|
|
405
|
+
id TEXT PRIMARY KEY,
|
|
406
|
+
story_ap_id TEXT NOT NULL REFERENCES objects(ap_id) ON DELETE CASCADE,
|
|
407
|
+
actor_ap_id TEXT NOT NULL REFERENCES actors(ap_id) ON DELETE CASCADE,
|
|
408
|
+
shared_at TEXT DEFAULT (datetime('now')),
|
|
409
|
+
UNIQUE(story_ap_id, actor_ap_id)
|
|
410
|
+
);
|
|
411
|
+
|
|
412
|
+
CREATE INDEX IF NOT EXISTS idx_story_shares_story ON story_shares(story_ap_id);
|
|
413
|
+
CREATE INDEX IF NOT EXISTS idx_story_shares_actor ON story_shares(actor_ap_id);
|
|
414
|
+
|
|
415
|
+
-- ============================================================
|
|
416
|
+
-- NOTIFICATION_ARCHIVED
|
|
417
|
+
-- ============================================================
|
|
418
|
+
CREATE TABLE IF NOT EXISTS notification_archived (
|
|
419
|
+
actor_ap_id TEXT NOT NULL,
|
|
420
|
+
activity_ap_id TEXT NOT NULL,
|
|
421
|
+
archived_at TEXT DEFAULT (datetime('now')),
|
|
422
|
+
PRIMARY KEY (actor_ap_id, activity_ap_id)
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
CREATE INDEX IF NOT EXISTS idx_notification_archived_actor ON notification_archived(actor_ap_id);
|
|
426
|
+
CREATE INDEX IF NOT EXISTS idx_notification_archived_actor_at ON notification_archived(actor_ap_id, archived_at);
|
|
427
|
+
|
|
428
|
+
-- ============================================================
|
|
429
|
+
-- INSTANCE_ACTOR
|
|
430
|
+
-- ============================================================
|
|
431
|
+
CREATE TABLE IF NOT EXISTS instance_actor (
|
|
432
|
+
ap_id TEXT PRIMARY KEY,
|
|
433
|
+
preferred_username TEXT NOT NULL,
|
|
434
|
+
name TEXT,
|
|
435
|
+
summary TEXT,
|
|
436
|
+
public_key_pem TEXT NOT NULL,
|
|
437
|
+
private_key_pem TEXT NOT NULL,
|
|
438
|
+
join_policy TEXT DEFAULT 'open',
|
|
439
|
+
posting_policy TEXT DEFAULT 'members',
|
|
440
|
+
visibility TEXT DEFAULT 'public',
|
|
441
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
442
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
-- ============================================================
|
|
446
|
+
-- DM_TYPING
|
|
447
|
+
-- ============================================================
|
|
448
|
+
CREATE TABLE IF NOT EXISTS dm_typing (
|
|
449
|
+
actor_ap_id TEXT NOT NULL,
|
|
450
|
+
recipient_ap_id TEXT NOT NULL,
|
|
451
|
+
last_typed_at TEXT NOT NULL,
|
|
452
|
+
PRIMARY KEY (actor_ap_id, recipient_ap_id)
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
CREATE INDEX IF NOT EXISTS idx_dm_typing_recipient ON dm_typing(recipient_ap_id, last_typed_at DESC);
|
|
456
|
+
|
|
457
|
+
-- ============================================================
|
|
458
|
+
-- DM_READ_STATUS
|
|
459
|
+
-- ============================================================
|
|
460
|
+
CREATE TABLE IF NOT EXISTS dm_read_status (
|
|
461
|
+
actor_ap_id TEXT NOT NULL,
|
|
462
|
+
conversation_id TEXT NOT NULL,
|
|
463
|
+
last_read_at TEXT DEFAULT (datetime('now')),
|
|
464
|
+
PRIMARY KEY (actor_ap_id, conversation_id)
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
CREATE INDEX IF NOT EXISTS idx_dm_read_status_actor ON dm_read_status(actor_ap_id);
|
|
468
|
+
CREATE INDEX IF NOT EXISTS idx_dm_read_status_actor_at ON dm_read_status(actor_ap_id, last_read_at DESC);
|
|
469
|
+
|
|
470
|
+
-- ============================================================
|
|
471
|
+
-- DM_ARCHIVED_CONVERSATIONS
|
|
472
|
+
-- ============================================================
|
|
473
|
+
CREATE TABLE IF NOT EXISTS dm_archived_conversations (
|
|
474
|
+
actor_ap_id TEXT NOT NULL,
|
|
475
|
+
conversation_id TEXT NOT NULL,
|
|
476
|
+
archived_at TEXT DEFAULT (datetime('now')),
|
|
477
|
+
PRIMARY KEY (actor_ap_id, conversation_id)
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
CREATE INDEX IF NOT EXISTS idx_dm_archived_actor ON dm_archived_conversations(actor_ap_id);
|
|
481
|
+
|
|
482
|
+
-- ============================================================
|
|
483
|
+
-- MEDIA_UPLOADS
|
|
484
|
+
-- ============================================================
|
|
485
|
+
CREATE TABLE IF NOT EXISTS media_uploads (
|
|
486
|
+
id TEXT PRIMARY KEY,
|
|
487
|
+
r2_key TEXT NOT NULL UNIQUE,
|
|
488
|
+
uploader_ap_id TEXT NOT NULL,
|
|
489
|
+
content_type TEXT NOT NULL,
|
|
490
|
+
size INTEGER NOT NULL,
|
|
491
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
CREATE INDEX IF NOT EXISTS idx_media_uploads_uploader ON media_uploads(uploader_ap_id);
|
|
495
|
+
CREATE INDEX IF NOT EXISTS idx_media_uploads_r2_key ON media_uploads(r2_key);
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
-- Social edge tables store ActivityPub actor IDs. Either side can be a
|
|
2
|
+
-- remote actor cached in actor_cache, so physical FKs to local actors block
|
|
3
|
+
-- federation under SQLite/D1 foreign-key enforcement.
|
|
4
|
+
|
|
5
|
+
CREATE TABLE IF NOT EXISTS follows_new (
|
|
6
|
+
follower_ap_id TEXT NOT NULL,
|
|
7
|
+
following_ap_id TEXT NOT NULL,
|
|
8
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
9
|
+
activity_ap_id TEXT,
|
|
10
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
11
|
+
accepted_at TEXT,
|
|
12
|
+
PRIMARY KEY (follower_ap_id, following_ap_id)
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
INSERT OR IGNORE INTO follows_new (
|
|
16
|
+
follower_ap_id,
|
|
17
|
+
following_ap_id,
|
|
18
|
+
status,
|
|
19
|
+
activity_ap_id,
|
|
20
|
+
created_at,
|
|
21
|
+
accepted_at
|
|
22
|
+
)
|
|
23
|
+
SELECT
|
|
24
|
+
follower_ap_id,
|
|
25
|
+
following_ap_id,
|
|
26
|
+
COALESCE(status, 'pending'),
|
|
27
|
+
activity_ap_id,
|
|
28
|
+
COALESCE(created_at, datetime('now')),
|
|
29
|
+
accepted_at
|
|
30
|
+
FROM follows;
|
|
31
|
+
|
|
32
|
+
DROP TABLE follows;
|
|
33
|
+
ALTER TABLE follows_new RENAME TO follows;
|
|
34
|
+
|
|
35
|
+
CREATE INDEX IF NOT EXISTS idx_follows_follower_status ON follows(follower_ap_id, status);
|
|
36
|
+
CREATE INDEX IF NOT EXISTS idx_follows_following_status ON follows(following_ap_id, status);
|
|
37
|
+
CREATE INDEX IF NOT EXISTS idx_follows_following_created ON follows(following_ap_id, created_at DESC);
|
|
38
|
+
CREATE INDEX IF NOT EXISTS idx_follows_activity ON follows(activity_ap_id);
|
|
39
|
+
|
|
40
|
+
CREATE TABLE IF NOT EXISTS blocks_new (
|
|
41
|
+
blocker_ap_id TEXT NOT NULL,
|
|
42
|
+
blocked_ap_id TEXT NOT NULL,
|
|
43
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
44
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
45
|
+
PRIMARY KEY (blocker_ap_id, blocked_ap_id)
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
INSERT OR IGNORE INTO blocks_new (
|
|
49
|
+
blocker_ap_id,
|
|
50
|
+
blocked_ap_id,
|
|
51
|
+
created_at,
|
|
52
|
+
updated_at
|
|
53
|
+
)
|
|
54
|
+
SELECT
|
|
55
|
+
blocker_ap_id,
|
|
56
|
+
blocked_ap_id,
|
|
57
|
+
COALESCE(created_at, datetime('now')),
|
|
58
|
+
updated_at
|
|
59
|
+
FROM blocks;
|
|
60
|
+
|
|
61
|
+
DROP TABLE blocks;
|
|
62
|
+
ALTER TABLE blocks_new RENAME TO blocks;
|
|
63
|
+
|
|
64
|
+
CREATE INDEX IF NOT EXISTS idx_blocks_blocker ON blocks(blocker_ap_id);
|
|
65
|
+
CREATE INDEX IF NOT EXISTS idx_blocks_blocked ON blocks(blocked_ap_id);
|
|
66
|
+
|
|
67
|
+
CREATE TABLE IF NOT EXISTS mutes_new (
|
|
68
|
+
muter_ap_id TEXT NOT NULL,
|
|
69
|
+
muted_ap_id TEXT NOT NULL,
|
|
70
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
71
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
72
|
+
PRIMARY KEY (muter_ap_id, muted_ap_id)
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
INSERT OR IGNORE INTO mutes_new (
|
|
76
|
+
muter_ap_id,
|
|
77
|
+
muted_ap_id,
|
|
78
|
+
created_at,
|
|
79
|
+
updated_at
|
|
80
|
+
)
|
|
81
|
+
SELECT
|
|
82
|
+
muter_ap_id,
|
|
83
|
+
muted_ap_id,
|
|
84
|
+
COALESCE(created_at, datetime('now')),
|
|
85
|
+
updated_at
|
|
86
|
+
FROM mutes;
|
|
87
|
+
|
|
88
|
+
DROP TABLE mutes;
|
|
89
|
+
ALTER TABLE mutes_new RENAME TO mutes;
|
|
90
|
+
|
|
91
|
+
CREATE INDEX IF NOT EXISTS idx_mutes_muter ON mutes(muter_ap_id);
|
|
92
|
+
CREATE INDEX IF NOT EXISTS idx_mutes_muted ON mutes(muted_ap_id);
|