@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
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# yurucommu migrations
|
|
2
|
+
|
|
3
|
+
SQL migrations for the yurucommu social engine. Deployable product repos
|
|
4
|
+
(`yurucommu` and `yurumeet`) apply these migrations from the published
|
|
5
|
+
`@takosjp/yurucommu-core` package.
|
|
6
|
+
|
|
7
|
+
- **Substrate**: libSQL (single-host) or Cloudflare D1 (managed edge).
|
|
8
|
+
- **Ledger table**: `yurucommu_migrations(name TEXT PRIMARY KEY, applied_at)`.
|
|
9
|
+
This is yurucommu-owned product state; it does **not** carry a checksum
|
|
10
|
+
column.
|
|
11
|
+
- **Runner sources**:
|
|
12
|
+
- `bun run app:activate` in this package for direct migration helper tests
|
|
13
|
+
- `bun run takosumi:release` in a deployable product repo for Takosumi
|
|
14
|
+
activation
|
|
15
|
+
- `wrangler d1 migrations apply` for operator-managed Cloudflare D1 paths
|
|
16
|
+
|
|
17
|
+
## Naming convention
|
|
18
|
+
|
|
19
|
+
Files use a zero-padded 4-digit prefix:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
NNNN_short_description.sql
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Order is determined by lexicographic sort on the prefix. The runner records the
|
|
26
|
+
file name (not the numeric version) in `yurucommu_migrations`.
|
|
27
|
+
|
|
28
|
+
## Operator runbook
|
|
29
|
+
|
|
30
|
+
1. **Apply** (libSQL / single-host):
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
cd yurucommu
|
|
34
|
+
bun run start
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Migrations run lazily on the first DB connect.
|
|
38
|
+
|
|
39
|
+
2. **Apply** (Cloudflare D1):
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
cd yurucommu
|
|
43
|
+
npx wrangler d1 migrations apply <DB-NAME> --env <env>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
3. **Apply migrations only** (Takosumi-compatible helper):
|
|
47
|
+
|
|
48
|
+
`bun run app:activate` is the core package migration helper. Takosumi does
|
|
49
|
+
not parse migrations, talk to the database, or provide a DB-specific API for
|
|
50
|
+
this path; it only records the activation result when a product repo invokes
|
|
51
|
+
the helper through its release hook. The operator activation environment must
|
|
52
|
+
provide the SQL execution command.
|
|
53
|
+
|
|
54
|
+
Prefix mode appends `<resource> <sql>`:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
YURUCOMMU_SQL_COMMAND_JSON='["operator-sql-cli","query"]' \
|
|
58
|
+
YURUCOMMU_SQL_RESOURCE=database \
|
|
59
|
+
bun run app:activate
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Template mode substitutes `{resource}` and `{sql}`:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
YURUCOMMU_SQL_COMMAND_TEMPLATE_JSON='["bunx","wrangler","d1","execute","{resource}","--remote","--json","--command={sql}"]' \
|
|
66
|
+
YURUCOMMU_SQL_WRAP_TRANSACTIONS=false \
|
|
67
|
+
YURUCOMMU_SQL_RESOURCE=DB \
|
|
68
|
+
bun run app:activate
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Remote Cloudflare D1 rejects explicit `BEGIN` / `SAVEPOINT` statements through
|
|
72
|
+
this API, so the Takosumi release path disables transaction wrappers while
|
|
73
|
+
keeping the local/libSQL path wrapped by default.
|
|
74
|
+
|
|
75
|
+
4. **Post-apply activation**:
|
|
76
|
+
|
|
77
|
+
In the OpenTofu-managed Worker path, the product repo's
|
|
78
|
+
`takosumi_release.post_apply` runs
|
|
79
|
+
`bun run takosumi:release -- --migrations-only` as an opaque runner command.
|
|
80
|
+
It reads non-secret outputs from `TAKOSUMI_OUTPUTS_JSON`, writes a temporary
|
|
81
|
+
Wrangler config, and applies these core migrations through
|
|
82
|
+
`wrangler d1 execute` without explicit SQL transaction wrappers. Provider
|
|
83
|
+
credentials come from the same reviewed Provider Connection used by the
|
|
84
|
+
OpenTofu run.
|
|
85
|
+
|
|
86
|
+
In the fallback path where the Worker script is not managed by OpenTofu,
|
|
87
|
+
`takosumi_release.post_apply` runs `bun run takosumi:release` as an opaque
|
|
88
|
+
operator release command. It reads non-secret outputs from `TAKOSUMI_OUTPUTS_JSON`,
|
|
89
|
+
writes a temporary Wrangler config, runs `bun install --frozen-lockfile`,
|
|
90
|
+
runs `bun run build:takos-worker`, applies D1 migrations through
|
|
91
|
+
`wrangler d1 execute` without explicit SQL transaction wrappers, and deploys
|
|
92
|
+
with `wrangler deploy`.
|
|
93
|
+
Provider credentials and app-specific secrets come from the selected
|
|
94
|
+
operator release activator boundary through
|
|
95
|
+
`TAKOSUMI_RELEASE_COMMAND_ENV_ALLOWLIST`.
|
|
96
|
+
|
|
97
|
+
Common operator env names:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
YURUCOMMU_ENCRYPTION_KEY=...
|
|
101
|
+
YURUCOMMU_AUTH_PASSWORD_HASH=...
|
|
102
|
+
TAKOSUMI_ACCOUNTS_ISSUER_URL=https://app.takosumi.com
|
|
103
|
+
TAKOSUMI_ACCOUNTS_CLIENT_ID=...
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
5. **Forensics**:
|
|
107
|
+
|
|
108
|
+
```sql
|
|
109
|
+
SELECT name, applied_at FROM yurucommu_migrations ORDER BY applied_at;
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Product-local ledger note
|
|
113
|
+
|
|
114
|
+
The `yurucommu_migrations` ledger is yurucommu-family product state. The
|
|
115
|
+
Takosumi-managed path invokes product-owned `takosumi_release.post_apply`
|
|
116
|
+
commands and records activation status/logs; it does not expose a Takosumi DB
|
|
117
|
+
migration API. A future core migration may add `checksum TEXT` and store
|
|
118
|
+
`sha256:<hex>` per applied migration, but that requires coordination with
|
|
119
|
+
production data in both yurucommu and Yurumeet installations.
|
|
120
|
+
|
|
121
|
+
For restore / disaster-recovery procedures, see the operator runbooks under
|
|
122
|
+
[`takosumi/docs/operations/`](../../takosumi/docs/operations/).
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@takosjp/yurucommu-core",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"license": "AGPL-3.0-only",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"workspaces": [
|
|
7
|
+
"packages/*"
|
|
8
|
+
],
|
|
9
|
+
"files": [
|
|
10
|
+
"src/backend",
|
|
11
|
+
"src/db",
|
|
12
|
+
"src/plugin",
|
|
13
|
+
"src/runtime",
|
|
14
|
+
"!src/backend/**/__tests__/**",
|
|
15
|
+
"!packages/api/src/**/*.test.ts",
|
|
16
|
+
"scripts/apply-takosumi-migrations.ts",
|
|
17
|
+
"migrations",
|
|
18
|
+
"packages/api/src",
|
|
19
|
+
"packages/api/package.json",
|
|
20
|
+
"packages/api/LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"exports": {
|
|
23
|
+
".": "./src/backend/public.ts",
|
|
24
|
+
"./server": "./src/backend/public.ts",
|
|
25
|
+
"./client-api": "./packages/api/src/index.ts",
|
|
26
|
+
"./migrations": "./scripts/apply-takosumi-migrations.ts",
|
|
27
|
+
"./plugins": "./src/plugin/public.ts"
|
|
28
|
+
},
|
|
29
|
+
"imports": {
|
|
30
|
+
"#test/assert": "./shims/std/assert.ts",
|
|
31
|
+
"#test/mock": "./shims/std/mock.ts",
|
|
32
|
+
"#test/time": "./shims/std/time.ts"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"start": "bun src/backend/server.ts",
|
|
36
|
+
"dev": "bun src/backend/server.ts",
|
|
37
|
+
"dev:server": "bun src/backend/server.ts",
|
|
38
|
+
"check": "tsc --noEmit",
|
|
39
|
+
"test": "bun run build:api && bun test test/ src/backend/ packages/api/src/",
|
|
40
|
+
"test:backend": "bun test src/backend/",
|
|
41
|
+
"build": "bun run build:api",
|
|
42
|
+
"build:api": "cd packages/api && bun run build",
|
|
43
|
+
"pack:core": "npm pack --dry-run",
|
|
44
|
+
"pack:api": "cd packages/api && bun run pack:dry",
|
|
45
|
+
"app:activate": "bun scripts/apply-takosumi-migrations.ts",
|
|
46
|
+
"lint": "bun run check",
|
|
47
|
+
"fmt": "bunx prettier --write src test packages/api",
|
|
48
|
+
"fmt:check": "bunx prettier --check src test packages/api",
|
|
49
|
+
"db:generate": "bunx drizzle-kit generate",
|
|
50
|
+
"db:push": "bunx drizzle-kit push",
|
|
51
|
+
"db:migrate": "bunx drizzle-kit migrate",
|
|
52
|
+
"db:studio": "bunx drizzle-kit studio"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@aws-sdk/client-s3": "^3.971.0",
|
|
56
|
+
"@libsql/client": "^0.17.0",
|
|
57
|
+
"better-sqlite3": "^12.4.1",
|
|
58
|
+
"drizzle-orm": "^0.45.1",
|
|
59
|
+
"fdir": "^6.5.0",
|
|
60
|
+
"hono": "^4.12.9",
|
|
61
|
+
"picomatch": "^4.0.4",
|
|
62
|
+
"tinyglobby": "^0.2.16"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@cloudflare/workers-types": "^4.20260420.1",
|
|
66
|
+
"@types/better-sqlite3": "^7.6.11",
|
|
67
|
+
"@types/bun": "latest",
|
|
68
|
+
"@types/node": "^22.0.0",
|
|
69
|
+
"drizzle-kit": "^0.31.9",
|
|
70
|
+
"typescript": "^5.7.0"
|
|
71
|
+
},
|
|
72
|
+
"publishConfig": {
|
|
73
|
+
"access": "public"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -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>.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@takosjp/yurucommu-api",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Typed client SDK and public API contract for yurucommu-server clients.",
|
|
5
|
+
"license": "AGPL-3.0-only",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"scripts": {
|
|
20
|
+
"check": "tsc --noEmit -p tsconfig.json",
|
|
21
|
+
"build": "rm -rf dist && bun build src/index.ts --target browser --format esm --outfile dist/index.js && bunx tsc -p tsconfig.build.json && bun scripts/rewrite-dts-imports.mjs",
|
|
22
|
+
"pack:dry": "npm pack --dry-run"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"typescript": "^5.7.0"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { apiFetch, apiPost, apiPut, assertOk } from "./fetch.ts";
|
|
2
|
+
|
|
3
|
+
export async function fetchAlsoKnownAs(identifier: string): Promise<string[]> {
|
|
4
|
+
const res = await apiFetch(`/api/actors/${encodeURIComponent(identifier)}`);
|
|
5
|
+
if (!res.ok) return [];
|
|
6
|
+
const data = (await res.json()) as { also_known_as?: unknown };
|
|
7
|
+
return Array.isArray(data.also_known_as)
|
|
8
|
+
? data.also_known_as.filter((a): a is string => typeof a === "string")
|
|
9
|
+
: [];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function setAlsoKnownAs(aliases: string[]): Promise<void> {
|
|
13
|
+
const res = await apiPut("/api/actors/me", { also_known_as: aliases });
|
|
14
|
+
await assertOk(res, "Failed to update aliases");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function moveAccount(target: string): Promise<void> {
|
|
18
|
+
const res = await apiPost("/api/actors/me/move", { target });
|
|
19
|
+
await assertOk(res, "Failed to move account");
|
|
20
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { Actor, Post } from "../../types/index.ts";
|
|
2
|
+
import { normalizeActor, normalizePost } from "./normalize.ts";
|
|
3
|
+
import { apiDelete, apiFetch, apiPost, apiPut, assertOk } from "./fetch.ts";
|
|
4
|
+
|
|
5
|
+
export async function fetchActor(identifier: string): Promise<Actor> {
|
|
6
|
+
const res = await apiFetch(`/api/actors/${encodeURIComponent(identifier)}`);
|
|
7
|
+
await assertOk(res, "Actor not found");
|
|
8
|
+
const data = (await res.json()) as { actor: Actor };
|
|
9
|
+
return normalizeActor(data.actor);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function updateProfile(data: {
|
|
13
|
+
name?: string;
|
|
14
|
+
summary?: string;
|
|
15
|
+
icon_url?: string;
|
|
16
|
+
header_url?: string;
|
|
17
|
+
is_private?: boolean;
|
|
18
|
+
// Structured PropertyValue profile fields. PUT /me replaces the stored set
|
|
19
|
+
// with this array (backend caps it at 4 and sanitizes name/value).
|
|
20
|
+
fields?: { name: string; value: string }[];
|
|
21
|
+
}): Promise<void> {
|
|
22
|
+
const res = await apiPut("/api/actors/me", data);
|
|
23
|
+
await assertOk(res, "Failed to update profile");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ActorPostsPage {
|
|
27
|
+
posts: Post[];
|
|
28
|
+
nextCursor: string | null;
|
|
29
|
+
hasMore: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function fetchActorPosts(
|
|
33
|
+
identifier: string,
|
|
34
|
+
options?: { limit?: number; before?: string },
|
|
35
|
+
): Promise<ActorPostsPage> {
|
|
36
|
+
const params = new URLSearchParams();
|
|
37
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
38
|
+
if (options?.before) params.set("before", options.before);
|
|
39
|
+
const query = params.toString() ? `?${params}` : "";
|
|
40
|
+
const res = await apiFetch(
|
|
41
|
+
`/api/actors/${encodeURIComponent(identifier)}/posts${query}`,
|
|
42
|
+
);
|
|
43
|
+
await assertOk(res, "Failed to fetch actor posts");
|
|
44
|
+
const data = (await res.json()) as {
|
|
45
|
+
posts?: Post[];
|
|
46
|
+
next_cursor?: string | null;
|
|
47
|
+
has_more?: boolean;
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
posts: (data.posts || []).map(normalizePost),
|
|
51
|
+
nextCursor: data.next_cursor ?? null,
|
|
52
|
+
hasMore: data.has_more ?? false,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface FollowListPage {
|
|
57
|
+
actors: Actor[];
|
|
58
|
+
hasMore: boolean;
|
|
59
|
+
total: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function followListQuery(options?: {
|
|
63
|
+
limit?: number;
|
|
64
|
+
offset?: number;
|
|
65
|
+
}): string {
|
|
66
|
+
const params = new URLSearchParams();
|
|
67
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
68
|
+
if (options?.offset) params.set("offset", String(options.offset));
|
|
69
|
+
return params.toString() ? `?${params}` : "";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function fetchFollowers(
|
|
73
|
+
identifier: string,
|
|
74
|
+
options?: { limit?: number; offset?: number },
|
|
75
|
+
): Promise<FollowListPage> {
|
|
76
|
+
const res = await apiFetch(
|
|
77
|
+
`/api/actors/${encodeURIComponent(identifier)}/followers${followListQuery(options)}`,
|
|
78
|
+
);
|
|
79
|
+
await assertOk(res, "Failed to fetch followers");
|
|
80
|
+
const data = (await res.json()) as {
|
|
81
|
+
followers?: Actor[];
|
|
82
|
+
has_more?: boolean;
|
|
83
|
+
total?: number;
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
actors: (data.followers || []).map(normalizeActor),
|
|
87
|
+
hasMore: data.has_more ?? false,
|
|
88
|
+
total: data.total ?? 0,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function fetchFollowing(
|
|
93
|
+
identifier: string,
|
|
94
|
+
options?: { limit?: number; offset?: number },
|
|
95
|
+
): Promise<FollowListPage> {
|
|
96
|
+
const res = await apiFetch(
|
|
97
|
+
`/api/actors/${encodeURIComponent(identifier)}/following${followListQuery(options)}`,
|
|
98
|
+
);
|
|
99
|
+
await assertOk(res, "Failed to fetch following");
|
|
100
|
+
const data = (await res.json()) as {
|
|
101
|
+
following?: Actor[];
|
|
102
|
+
has_more?: boolean;
|
|
103
|
+
total?: number;
|
|
104
|
+
};
|
|
105
|
+
return {
|
|
106
|
+
actors: (data.following || []).map(normalizeActor),
|
|
107
|
+
hasMore: data.has_more ?? false,
|
|
108
|
+
total: data.total ?? 0,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function fetchBlockedUsers(): Promise<Actor[]> {
|
|
113
|
+
const res = await apiFetch("/api/actors/me/blocked");
|
|
114
|
+
await assertOk(res, "Failed to fetch blocked users");
|
|
115
|
+
const data = (await res.json()) as { blocked?: Actor[] };
|
|
116
|
+
return (data.blocked || []).map(normalizeActor);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function blockUser(apId: string): Promise<void> {
|
|
120
|
+
const res = await apiPost("/api/actors/me/blocked", { ap_id: apId });
|
|
121
|
+
await assertOk(res, "Failed to block user");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function unblockUser(apId: string): Promise<void> {
|
|
125
|
+
const res = await apiDelete("/api/actors/me/blocked", { ap_id: apId });
|
|
126
|
+
await assertOk(res, "Failed to unblock user");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function fetchMutedUsers(): Promise<Actor[]> {
|
|
130
|
+
const res = await apiFetch("/api/actors/me/muted");
|
|
131
|
+
await assertOk(res, "Failed to fetch muted users");
|
|
132
|
+
const data = (await res.json()) as { muted?: Actor[] };
|
|
133
|
+
return (data.muted || []).map(normalizeActor);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export async function muteUser(apId: string): Promise<void> {
|
|
137
|
+
const res = await apiPost("/api/actors/me/muted", { ap_id: apId });
|
|
138
|
+
await assertOk(res, "Failed to mute user");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export async function unmuteUser(apId: string): Promise<void> {
|
|
142
|
+
const res = await apiDelete("/api/actors/me/muted", { ap_id: apId });
|
|
143
|
+
await assertOk(res, "Failed to unmute user");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export async function deleteAccount(): Promise<void> {
|
|
147
|
+
const res = await apiPost("/api/actors/me/delete");
|
|
148
|
+
await assertOk(res, "Failed to delete account");
|
|
149
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { apiFetch, apiPost, assertOk } from "./fetch.ts";
|
|
2
|
+
|
|
3
|
+
export async function login(
|
|
4
|
+
password: string,
|
|
5
|
+
): Promise<{ success: boolean; error?: string }> {
|
|
6
|
+
const res = await apiPost("/api/auth/login", { password });
|
|
7
|
+
return (await res.json()) as { success: boolean; error?: string };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function logout(): Promise<void> {
|
|
11
|
+
await apiPost("/api/auth/logout");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface AccountInfo {
|
|
15
|
+
ap_id: string;
|
|
16
|
+
preferred_username: string;
|
|
17
|
+
name: string | null;
|
|
18
|
+
icon_url: string | null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function fetchAccounts(): Promise<{
|
|
22
|
+
accounts: AccountInfo[];
|
|
23
|
+
current_ap_id: string;
|
|
24
|
+
}> {
|
|
25
|
+
const res = await apiFetch("/api/auth/accounts");
|
|
26
|
+
await assertOk(res, "Failed to fetch accounts");
|
|
27
|
+
return (await res.json()) as {
|
|
28
|
+
accounts: AccountInfo[];
|
|
29
|
+
current_ap_id: string;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function switchAccount(apId: string): Promise<void> {
|
|
34
|
+
const res = await apiPost("/api/auth/switch", { ap_id: apId });
|
|
35
|
+
await assertOk(res, "Failed to switch account");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function createAccount(
|
|
39
|
+
username: string,
|
|
40
|
+
name?: string,
|
|
41
|
+
): Promise<AccountInfo> {
|
|
42
|
+
const res = await apiPost("/api/auth/accounts", { username, name });
|
|
43
|
+
await assertOk(res, "Failed to create account");
|
|
44
|
+
const data = (await res.json()) as { account: AccountInfo };
|
|
45
|
+
return data.account;
|
|
46
|
+
}
|