@takosjp/yurucommu-core 3.4.5 → 4.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/package.json +1 -1
- package/packages/api/package.json +1 -1
- package/src/backend/lib/blocklist-purge.ts +6 -6
- package/src/backend/public.ts +9 -4
- package/src/backend/routes/account-teardown.ts +2 -2
- package/src/backend/routes/apps.ts +4 -5
- package/src/backend/routes/media.ts +4 -5
- package/src/backend/routes/posts/delete-cascade.ts +7 -7
- package/src/backend/routes/stories/query-helpers.ts +2 -2
- package/src/backend/routes/stories/routes.ts +2 -5
- package/src/backend/runtime/bun.ts +655 -320
- package/src/backend/runtime/cloudflare.ts +20 -58
- package/src/backend/runtime/managed-runtime.ts +117 -139
- package/src/backend/runtime/s3-fetch.ts +380 -0
- package/src/backend/runtime/types.ts +29 -61
- package/src/backend/types.ts +4 -4
package/package.json
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
storyVotes,
|
|
25
25
|
} from "../../db/index.ts";
|
|
26
26
|
import type { Database } from "../../db/index.ts";
|
|
27
|
-
import type {
|
|
27
|
+
import type { ObjectStore } from "../runtime/types.ts";
|
|
28
28
|
import { chunkForInClause, D1_IN_CHUNK } from "./chunk.ts";
|
|
29
29
|
import { normalizeDomain } from "./blocklist.ts";
|
|
30
30
|
import { isSameActivityPubActor } from "./activitypub-actor-identity.ts";
|
|
@@ -112,7 +112,7 @@ function activityPubUrlHostMatchesDomain(
|
|
|
112
112
|
async function purgeObjects(
|
|
113
113
|
db: Database,
|
|
114
114
|
apIds: string[],
|
|
115
|
-
media?:
|
|
115
|
+
media?: ObjectStore,
|
|
116
116
|
): Promise<void> {
|
|
117
117
|
if (apIds.length === 0) return;
|
|
118
118
|
const parentRows = await db
|
|
@@ -544,7 +544,7 @@ async function purgeActorInteractionEdges(
|
|
|
544
544
|
async function purgeMatchingObjects(
|
|
545
545
|
db: Database,
|
|
546
546
|
where: SQL,
|
|
547
|
-
media?:
|
|
547
|
+
media?: ObjectStore,
|
|
548
548
|
onPageDeleted?: (count: number) => void,
|
|
549
549
|
): Promise<void> {
|
|
550
550
|
let cursor: string | undefined;
|
|
@@ -604,7 +604,7 @@ async function purgeMatchingActivities(
|
|
|
604
604
|
async function purgeActorObjects(
|
|
605
605
|
db: Database,
|
|
606
606
|
blockedApId: string,
|
|
607
|
-
media?:
|
|
607
|
+
media?: ObjectStore,
|
|
608
608
|
onPageDeleted?: (count: number) => void,
|
|
609
609
|
): Promise<void> {
|
|
610
610
|
let cursor: string | undefined;
|
|
@@ -666,7 +666,7 @@ async function purgeActorActivities(
|
|
|
666
666
|
export async function purgeActorContent(
|
|
667
667
|
db: Database,
|
|
668
668
|
blockedApId: string,
|
|
669
|
-
media?:
|
|
669
|
+
media?: ObjectStore,
|
|
670
670
|
): Promise<BlocklistContentPurgeResult> {
|
|
671
671
|
let deletedObjects = 0;
|
|
672
672
|
let deletedActivities = 0;
|
|
@@ -704,7 +704,7 @@ export async function purgeActorContent(
|
|
|
704
704
|
export async function purgeDomainContent(
|
|
705
705
|
db: Database,
|
|
706
706
|
domainOrUrl: string,
|
|
707
|
-
media?:
|
|
707
|
+
media?: ObjectStore,
|
|
708
708
|
): Promise<BlocklistContentPurgeResult> {
|
|
709
709
|
const domain = normalizeDomain(domainOrUrl);
|
|
710
710
|
if (!domain) {
|
package/src/backend/public.ts
CHANGED
|
@@ -38,11 +38,16 @@ export {
|
|
|
38
38
|
} from "./runtime/managed-relational.ts";
|
|
39
39
|
export type {
|
|
40
40
|
IKeyValueStore,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
ObjectStore,
|
|
42
|
+
ObjectStoreBody,
|
|
43
|
+
ObjectStoreObject,
|
|
44
|
+
ObjectStorePutOptions,
|
|
45
45
|
} from "./runtime/types.ts";
|
|
46
|
+
export {
|
|
47
|
+
createS3FetchObjectStore,
|
|
48
|
+
S3FetchObjectStoreError,
|
|
49
|
+
type S3ObjectFetcher,
|
|
50
|
+
} from "./runtime/s3-fetch.ts";
|
|
46
51
|
export type {
|
|
47
52
|
IQueueBatch,
|
|
48
53
|
IQueueMessage,
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
} from "../../db/index.ts";
|
|
48
48
|
import type { Database } from "../../db/index.ts";
|
|
49
49
|
import type { Env } from "../types.ts";
|
|
50
|
-
import type {
|
|
50
|
+
import type { ObjectStore } from "../runtime/types.ts";
|
|
51
51
|
import { activityApId, generateId } from "../federation-helpers.ts";
|
|
52
52
|
import { chunkForInClause } from "../lib/chunk.ts";
|
|
53
53
|
import { snapshotAndEnqueueFollowerDeliveries } from "../lib/delivery/queue-batching.ts";
|
|
@@ -80,7 +80,7 @@ interface BatchableDb {
|
|
|
80
80
|
*/
|
|
81
81
|
export async function purgeActorMediaUploads(
|
|
82
82
|
db: Database,
|
|
83
|
-
media:
|
|
83
|
+
media: ObjectStore | undefined,
|
|
84
84
|
apId: string,
|
|
85
85
|
): Promise<void> {
|
|
86
86
|
const uploads = await db
|
|
@@ -230,7 +230,7 @@ appsApiRoutes.post(
|
|
|
230
230
|
}
|
|
231
231
|
const r2Key = `${appPrefix}${normalizedPath}`;
|
|
232
232
|
await media.put(r2Key, contentBytes, {
|
|
233
|
-
|
|
233
|
+
contentType,
|
|
234
234
|
});
|
|
235
235
|
|
|
236
236
|
results.push({ path: normalizedPath, status: "uploaded" });
|
|
@@ -276,14 +276,13 @@ appsServeRoutes.get("/:clientId/:appName/*", async (c) => {
|
|
|
276
276
|
|
|
277
277
|
const object = await media.get(r2Key);
|
|
278
278
|
if (object) {
|
|
279
|
-
const contentType =
|
|
280
|
-
object.httpMetadata?.contentType ?? inferContentType(filePath);
|
|
279
|
+
const contentType = object.contentType ?? inferContentType(filePath);
|
|
281
280
|
const headers = createHostedHeaders(
|
|
282
281
|
contentType,
|
|
283
282
|
filePath.includes("/assets/")
|
|
284
283
|
? "public, max-age=31536000, immutable"
|
|
285
284
|
: "public, max-age=3600",
|
|
286
|
-
object.
|
|
285
|
+
object.etag,
|
|
287
286
|
);
|
|
288
287
|
return new Response(object.body, { headers });
|
|
289
288
|
}
|
|
@@ -296,7 +295,7 @@ appsServeRoutes.get("/:clientId/:appName/*", async (c) => {
|
|
|
296
295
|
const headers = createHostedHeaders(
|
|
297
296
|
"text/html; charset=utf-8",
|
|
298
297
|
"no-cache",
|
|
299
|
-
indexObject.
|
|
298
|
+
indexObject.etag,
|
|
300
299
|
);
|
|
301
300
|
return new Response(indexObject.body, { headers });
|
|
302
301
|
}
|
|
@@ -235,7 +235,7 @@ media.post("/upload", async (c) => {
|
|
|
235
235
|
// memory budget.
|
|
236
236
|
if (isVideo) {
|
|
237
237
|
await media.put(r2Key, file, {
|
|
238
|
-
|
|
238
|
+
contentType,
|
|
239
239
|
});
|
|
240
240
|
} else {
|
|
241
241
|
const original = new Uint8Array(await file.arrayBuffer());
|
|
@@ -247,7 +247,7 @@ media.post("/upload", async (c) => {
|
|
|
247
247
|
cleaned.byteOffset + cleaned.byteLength,
|
|
248
248
|
) as ArrayBuffer;
|
|
249
249
|
await media.put(r2Key, cleanedBuffer, {
|
|
250
|
-
|
|
250
|
+
contentType,
|
|
251
251
|
});
|
|
252
252
|
}
|
|
253
253
|
|
|
@@ -579,13 +579,12 @@ async function serveMediaByR2Key(c: MediaContext, r2Key: string) {
|
|
|
579
579
|
const object = await media.get(r2Key);
|
|
580
580
|
if (!object) return c.notFound();
|
|
581
581
|
|
|
582
|
-
const contentType =
|
|
583
|
-
object.httpMetadata?.contentType || "application/octet-stream";
|
|
582
|
+
const contentType = object.contentType || "application/octet-stream";
|
|
584
583
|
const cacheScope = authResult.isPublic ? "public" : "private";
|
|
585
584
|
const maxAge = contentType.startsWith("video/")
|
|
586
585
|
? CACHE_MAX_AGE_VIDEO
|
|
587
586
|
: CACHE_MAX_AGE_IMAGE;
|
|
588
|
-
const etag = object.
|
|
587
|
+
const etag = object.etag;
|
|
589
588
|
|
|
590
589
|
if (!object.body) {
|
|
591
590
|
return c.body(null, 200, {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
import { and, asc, eq, gt, inArray, isNull, or, sql } from "drizzle-orm";
|
|
23
23
|
import type { D1Statement, Database } from "../../../db/index.ts";
|
|
24
|
-
import type {
|
|
24
|
+
import type { ObjectStore } from "../../runtime/types.ts";
|
|
25
25
|
import {
|
|
26
26
|
activities,
|
|
27
27
|
actors,
|
|
@@ -80,7 +80,7 @@ async function deleteAttachedMediaUploadsForObject(
|
|
|
80
80
|
db: Database,
|
|
81
81
|
obj: CascadeObject,
|
|
82
82
|
removedObjectApIds: ReadonlySet<string>,
|
|
83
|
-
media?:
|
|
83
|
+
media?: ObjectStore,
|
|
84
84
|
): Promise<{
|
|
85
85
|
mediaKeys: string[];
|
|
86
86
|
mediaUploadIds: string[];
|
|
@@ -191,7 +191,7 @@ async function deleteAttachedMediaUploadsForObject(
|
|
|
191
191
|
* system's already-accepted media failure mode.
|
|
192
192
|
*/
|
|
193
193
|
export async function purgeMediaBlobs(
|
|
194
|
-
media:
|
|
194
|
+
media: ObjectStore | undefined,
|
|
195
195
|
keys: string[],
|
|
196
196
|
): Promise<void> {
|
|
197
197
|
if (!media || keys.length === 0) return;
|
|
@@ -220,7 +220,7 @@ export async function reapReplacedMediaUrl(
|
|
|
220
220
|
db: Database,
|
|
221
221
|
oldUrl: string | null | undefined,
|
|
222
222
|
uploaderApId: string,
|
|
223
|
-
media?:
|
|
223
|
+
media?: ObjectStore,
|
|
224
224
|
): Promise<void> {
|
|
225
225
|
try {
|
|
226
226
|
if (!oldUrl || !oldUrl.startsWith("/media/")) return;
|
|
@@ -303,7 +303,7 @@ export async function reapReplacedMediaUrl(
|
|
|
303
303
|
export async function deleteObjectCascade(
|
|
304
304
|
db: Database,
|
|
305
305
|
objectApId: string,
|
|
306
|
-
media?:
|
|
306
|
+
media?: ObjectStore,
|
|
307
307
|
): Promise<string[]> {
|
|
308
308
|
return await deleteObjectsCascade(db, [objectApId], media);
|
|
309
309
|
}
|
|
@@ -316,7 +316,7 @@ export async function deleteObjectCascade(
|
|
|
316
316
|
export async function prepareObjectDeleteCascade(
|
|
317
317
|
db: Database,
|
|
318
318
|
objectApId: string,
|
|
319
|
-
media?:
|
|
319
|
+
media?: ObjectStore,
|
|
320
320
|
): Promise<{
|
|
321
321
|
mediaKeys: string[];
|
|
322
322
|
statements: readonly [D1Statement, ...D1Statement[]];
|
|
@@ -392,7 +392,7 @@ export async function prepareObjectDeleteCascade(
|
|
|
392
392
|
export async function deleteObjectsCascade(
|
|
393
393
|
db: Database,
|
|
394
394
|
objectApIds: string[],
|
|
395
|
-
media?:
|
|
395
|
+
media?: ObjectStore,
|
|
396
396
|
): Promise<string[]> {
|
|
397
397
|
const uniqueApIds = [...new Set(objectApIds)];
|
|
398
398
|
if (uniqueApIds.length === 0) return [];
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
objects,
|
|
9
9
|
storyVotes,
|
|
10
10
|
} from "../../../db/index.ts";
|
|
11
|
-
import type {
|
|
11
|
+
import type { ObjectStore } from "../../runtime/types.ts";
|
|
12
12
|
import {
|
|
13
13
|
formatUsername,
|
|
14
14
|
objectApId,
|
|
@@ -314,7 +314,7 @@ export function buildAuthor(
|
|
|
314
314
|
|
|
315
315
|
export async function cleanupExpiredStories(
|
|
316
316
|
db: Database,
|
|
317
|
-
media?:
|
|
317
|
+
media?: ObjectStore,
|
|
318
318
|
): Promise<number> {
|
|
319
319
|
const now = new Date().toISOString();
|
|
320
320
|
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
purgeMediaBlobs,
|
|
19
19
|
} from "../posts/delete-cascade.ts";
|
|
20
20
|
import type { Env, Variables } from "../../types.ts";
|
|
21
|
-
import type {
|
|
21
|
+
import type { ObjectStore } from "../../runtime/types.ts";
|
|
22
22
|
import {
|
|
23
23
|
activityApId,
|
|
24
24
|
actorApId,
|
|
@@ -61,10 +61,7 @@ const stories = new Hono<{ Bindings: Env; Variables: Variables }>();
|
|
|
61
61
|
// at most one fallback pass runs at a time per isolate.
|
|
62
62
|
let expiredStoryCleanupInFlight = false;
|
|
63
63
|
|
|
64
|
-
function maybeCleanupExpiredStories(
|
|
65
|
-
db: Database,
|
|
66
|
-
media?: IObjectStorage,
|
|
67
|
-
): void {
|
|
64
|
+
function maybeCleanupExpiredStories(db: Database, media?: ObjectStore): void {
|
|
68
65
|
if (expiredStoryCleanupInFlight) return;
|
|
69
66
|
if (Math.random() >= 0.01) return; // ~1% of feed requests per isolate
|
|
70
67
|
|