Something went wrong. Try again.
leaflet fork for copy edit / bug fixes forked from leaflet.pub/leaflet
Something went wrong. Try again.
TypeScript
at ghost-import
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495import type { SQL } from "drizzle-orm";import { v7 } from "uuid";import { supabaseServerClient } from "supabase/serverClient";import { markTitleBlockAsCopy } from "src/utils/markTitleBlockAsCopy";import { insertLeaflet } from "src/utils/insertLeaflet";import type { Fact } from "src/replicache";import type { Attribute } from "src/replicache/attributes";
const ASSET_BUCKET = "minilink-user-assets";const REFERENCE_TYPES = ["reference", "ordered-reference", "spatial-reference"];
/** * Deep-copy a leaflet's contents into a brand new entity set and permission * token: every fact reachable from `rootEntity`, with entity ids remapped and * uploaded assets duplicated in storage so neither copy can disturb the * other's images. * */export async function copyLeafletContents({ rootEntity, title, description, markAsCopy, tailCte,}: { rootEntity: string; title?: string | null; description?: string | null; // Write a "(Copy)" marker into the leaflet's title block, for copies whose // title lives in the document itself rather than in metadata. markAsCopy?: boolean; tailCte?: (ids: { permTokenId: string; rootEntityId: string }) => SQL;}): Promise<{ permTokenId: string; rootEntityId: string }> { let { data } = await supabaseServerClient.rpc("get_facts", { root: rootEntity, }); let sourceFacts = (data as unknown as Fact<Attribute>[]) || []; if (markAsCopy) sourceFacts = markTitleBlockAsCopy(sourceFacts, rootEntity);
// Map reference targets as well as fact subjects: an entity that has no // facts of its own is still referenced, and leaving it unmapped would point // the copy back into the source's entity set. let entityIDMap: { [oldID: string]: string } = { [rootEntity]: v7() }; let mapEntity = (id: string) => { if (!entityIDMap[id]) entityIDMap[id] = v7(); return entityIDMap[id]; }; for (let fact of sourceFacts) { mapEntity(fact.entity); if (REFERENCE_TYPES.includes(fact.data.type)) mapEntity((fact.data as { value: string }).value); }
let newFacts = await Promise.all( sourceFacts.map(async (fact) => { let data = { ...fact.data }; if (REFERENCE_TYPES.includes(data.type)) (data as { value: string }).value = entityIDMap[(data as { value: string }).value]; if (data.type === "image") data.src = await copyAsset(data.src); return { entity: entityIDMap[fact.entity], attribute: fact.attribute, data, }; }), );
const rootEntityId = entityIDMap[rootEntity]; const { permTokenId } = await insertLeaflet({ rootEntityId, entityIds: Object.values(entityIDMap), facts: newFacts, title, description, tailCte, }); return { permTokenId, rootEntityId };}
// Duplicate the storage object an image fact points at and return the rewritten// url. Falls back to the original url if the copy fails — a shared asset still// renders, a url pointing at an object that was never created would not.async function copyAsset(src: string) { let [path, query] = src.split("?"); let segments = path.split("/"); let newID = v7(); let { error } = await supabaseServerClient.storage .from(ASSET_BUCKET) .copy(segments[segments.length - 1], newID); if (error) return src; segments[segments.length - 1] = newID; return segments.join("/") + (query ? `?${query}` : "");}