Lagring af filudvidelser
TLDR: store the file id, render with a signed URL.
When an extension uploads a file, Chastify returns a stable id and a short-lived signedUrl. Store the id in your extension config, state, or own database.
When your extension page loads later, call bridge.request("files.get", { fileId }) or GET /api/extensions/sessions/:sessionId/files/:fileId with the stored id. Chastify verifies that the file belongs to the same extension app, session, and lock, then returns a fresh signed R2 URL.
Render the image with <img src={file.signedUrl} />. Do not store signed URLs long-term because they expire.
Lagring af udvidelsesfiler tillader en aktiveret udvidelse at uploade billedfiler, der tilhører en låst udvidelsessession.
Brug det, når udvidelsestilstanden JSON ikke er tilstrækkelig, for eksempel:
- puslespilbilleder
- genererede forhåndsvisninger
- udfordringsbilleder
- udvidelsesspecifikke medier, der skal ryddes op med låsen/sessionen
Denne lagring er adskilt fra state.*. Brug state.* til små JSON-data. Brug kun fillagring til binære medier.
Forhold til tilstandsslutpunkter
Udvidelsestilstanden er for JSON med lille sessionsomfang. Brug kommandoen bridge read fra en iframe i stedet for at kalde REST direkte:
state.get
Den brokommando ruter til:
GET /api/extensions/sessions/:sessionId/state
Direkte backend-kald til skrivetilstand bruger API-godkendelsesmodellen for installerede udvidelser:
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Send ikke Developer API-nøgler til iframe/browserkode.
Brug backend-skrevet tilstand til varige referencer og brugergrænsefladedata, for eksempel:
{
"puzzleImageFileId": "file_record_id",
"selectedImageIds": ["file_record_id"],
"lastOpenedTab": "images"
}
Gem ikke binære data, base64-billeder, browser-blob:-URL'er eller langlivede kopier af signedUrl i tilstanden. Signerede URL'er udløber og bør opdateres med files.get, når billedet gengives. Tilstandsskrivninger er størrelsesbegrænset af udvidelsesappens stateMaxBytes-indstilling, som som standard er 64 KiB.
Lagringsmodel
Chastify gemmer udvidelsesfiler i Chastify-administreret R2-lager.
Hver uploadet fil spores med:
scope: "extension"appIdsessionIdoglockIdfor runtime-/sessionsfilertemplateIdfor filer, der er gjort krav på af en gemt låseskabelonstaged,draftIdogexpiresAtfor opsætningsuploads, der endnu ikke er gjort krav påextensionKeypurpose
Admin Gate og kvoter
Admin controlled
Extension file storage is disabled by default.
Admins can enable it and configure:
- maximum bytes per file
- maximum total bytes per extension app
- maximum total bytes per active extension session
- maximum staged bytes per user and extension app
- allowed MIME prefixes
The first implementation is image-focused and should use image/* uploads. SVG is not accepted by the storage service.
If storage is disabled or R2 is not configured, upload requests fail before the server reads the multipart file body.
Staged setup uploads count toward the current user's per-app staged quota until they are claimed. Claimed files count toward the per-extension app quota. Runtime files with a session id also count toward the per-session quota.
Opsæt staging-slutpunkter
Brug kun opsætningstaging, når en opsætningsgrænseflade kører, før en udvidelsessession findes.
Dette er et midlertidigt uploadflow. Det findes til opsætnings-/konfigurationsskærme, hvor brugeren kan uploade en fil og derefter lukke modalen eller deaktivere udvidelsen, før der oprettes en lås/session. En staged-fil er ikke holdbar, før den gøres krav på ved at gemme den udvidelseskonfiguration, der refererer til den.
Opsætningsgrænseflader kan kontrollere tilgængelighed og aktuel faset brug, før uploadkontroller gengives:
GET /api/extensions/apps/:appId/files/capabilities
Svaret inkluderer stagedQuota for den aktuelle brugers ikke-udløbne, mellemlagde filer på den pågældende udvidelsesapp:
{
"enabled": true,
"provider": "r2",
"r2Configured": true,
"supportsStagedSetupFiles": true,
"stagedQuota": {
"bytesUsed": 123456,
"fileCount": 1,
"maxBytes": 10485760,
"remainingBytes": 10362304
}
}
POST /api/extensions/apps/:appId/files/stage
Content-Type: multipart/form-data
Formularfelter:
file: påkrævet billedfilpurpose: valgfri kort identifikator såsomjigsaw-config-imagedraftId: valgfrit opsætningsudkast-id; genbrug den samme værdi, mens én opsætningsmodal er åben
Svaret indeholder en stabil file.id og en kortvarig signeret URL til øjeblikkelig forhåndsvisning.
Eksempel på svar:
{
"file": {
"id": "file_record_id",
"signedUrl": "https://chastify.<account-id>.r2.cloudflarestorage.com/extensions/abc.webp?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Signature=...",
"publicUrl": "https://chastify.<account-id>.r2.cloudflarestorage.com/extensions/abc.webp?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Signature=...",
"urlExpiresAt": "2026-05-28T12:10:00.000Z",
"sizeBytes": 123456,
"originalName": "puzzle.jpg",
"mimeType": "image/webp",
"purpose": "jigsaw-config-image",
"uploadedAt": "2026-05-28T12:00:00.000Z"
},
"stagedQuota": {
"bytesUsed": 123456,
"fileCount": 1,
"maxBytes": 10485760,
"remainingBytes": 10362304
}
}
For at gendanne opsætningsuploads efter en sideopdatering skal du angive de fasede filer for den aktuelle bruger og udvidelsesappen:
GET /api/extensions/apps/:appId/files/staged?purpose=jigsaw-config-image
Valgfrie forespørgselsparametre:
purpose: returner kun staged-filer for én opsætnings-use casedraftId: returner kun filer fra et kendt opsætningsudkast
Hvis draftId udelades, returnerer Chastify den aktuelle brugers ikke-udløbne, staged-filer for den pågældende app. Dette er bevidst for opsætningsgrænseflader: en bruger kan uploade filer, genindlæse siden eller skifte enhed, og opsætningsskærmen kan gendanne disse midlertidige uploads, før låsen/skabelonen gemmes.
Svaret på den trinvise liste inkluderer også stagedQuota, som rapporterer den aktuelle brugers ikke-udløbne trinvise brug af den pågældende app:
{
"items": [],
"stagedQuota": {
"bytesUsed": 123456,
"fileCount": 1,
"maxBytes": 10485760,
"remainingBytes": 10362304
}
}
Opsætningsgrænseflader kan også opdatere eller slette én faseopdelt fil:
GET /api/extensions/apps/:appId/files/:fileId
DELETE /api/extensions/apps/:appId/files/staged/:fileId
Gør krav på iscenesatte filer senere
Der er ikke et separat "krav"-slutpunkt på browsersiden. En staged-fil gøres automatisk krav på, når Chastify gemmer en lås- eller skabelonudvidelseskonfiguration, der refererer til den staged-fil.
Disse ruter gør krav på staged-filer, efter at låse-/skabelondokumentet har et id, og gemmer derefter udvidelseskonfigurationen igen med de påståede filreferencer. Hvis kravet mislykkes, rulles den nyoprettede låse-/skabelon tilbage, så staged-filer ikke forbliver knyttet til en defekt konfiguration.
Bemærkning om delt skabelon: Accepterede delte låse beholder kildeskabelon-id'et på den klonede aktive lås. Skabelonpåberåbte filer bevares derfor, mens enhver klonet lås stadig refererer til den skabelon. Hvis kildeskabelonen slettes, forsinker Chastify sletningen af dens udvidelsesfiler, indtil den sidste klonede lås, der refererer til den slettede skabelon, er slettet eller arkiveret.
For at gøre en staged fil mulig at gøre krav på, skal du gemme en reference som denne i udvidelseskonfigurationen, der indsendes af opsætningsgrænsefladen:
{
"storageDraftId": "draft_123",
"images": [
{
"id": "file_record_id",
"provider": "chastify_storage",
"fileId": "file_record_id",
"url": "extension-file:file_record_id",
"title": "Puzzle image"
}
]
}
Ved lagring scanner Chastify konfigurationen for provider: "chastify_storage"-poster med en gyldig fileId og gør derefter følgende:
- bekræfter, at filen tilhører den aktuelle bruger og udvidelsesappen
- afviser udløbne, fasede filer
- afviser filer, der allerede er gjort krav på af en anden lås/skabelon-kontekst
- markerer refererede iscenesatte filer som påstået
- binder påståede filer til den gemte lås eller skabelon
- fjerner de midlertidige felter
signedUrl,publicUrlogurlExpiresAt, før konfigurationen gemmes - sletter ikke-refererede, mellemlagrede filer fra den samme
storageDraftId
Forladte, mellemlagde filer, der aldrig gemmes, slettes ved oprydning efter deres udløb.
Sådan opdaterer du en opsætningsforhåndsvisning for et fil-id, der ejes af den aktuelle bruger og udvidelsesappen:
GET /api/extensions/apps/:appId/files/:fileId
Sessionsslutpunkter
Disse slutpunkter kræver normal godkendelse og omfang for udvidelsessessioner.
Basissti:
/api/extensions/sessions/:sessionId/files
Evner
Tjek dette, før du gengiver uploadkontroller.
GET /api/extensions/sessions/:sessionId/files/capabilities
Kræver locks:read.
Eksempel på svar:
{
"enabled": true,
"provider": "r2",
"r2Configured": true,
"settings": {
"enabled": true,
"maxFileBytes": 10485760,
"maxBytesPerApp": 524288000,
"maxBytesPerSession": 52428800,
"maxStagedBytesPerUserPerApp": 10485760,
"allowedMimePrefixes": ["image/"]
}
}
Liste over filer
GET /api/extensions/sessions/:sessionId/files
Kræver locks:read.
Eksempel på svar:
{
"items": [
{
"id": "file_record_id",
"signedUrl": "https://chastify.<account-id>.r2.cloudflarestorage.com/extensions/abc.webp?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Signature=...",
"publicUrl": "https://chastify.<account-id>.r2.cloudflarestorage.com/extensions/abc.webp?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Signature=...",
"urlExpiresAt": "2026-05-28T12:10:00.000Z",
"sizeBytes": 123456,
"originalName": "puzzle.jpg",
"mimeType": "image/webp",
"purpose": "puzzle-image",
"uploadedAt": "2026-05-28T12:00:00.000Z"
}
]
}
Hent én fil
Brug dette, når din udvidelse allerede har et gemt fil-id og kun behøver et nyt signeret R2-link.
GET /api/extensions/sessions/:sessionId/files/:fileId
Kræver locks:read.
Filen skal tilhøre den samme udvidelsesapp, session og lås.
Eksempel på svar:
{
"file": {
"id": "file_record_id",
"signedUrl": "https://chastify.<account-id>.r2.cloudflarestorage.com/extensions/abc.webp?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Signature=...",
"publicUrl": "https://chastify.<account-id>.r2.cloudflarestorage.com/extensions/abc.webp?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Signature=...",
"urlExpiresAt": "2026-05-28T12:10:00.000Z",
"sizeBytes": 123456,
"originalName": "puzzle.jpg",
"mimeType": "image/webp",
"purpose": "puzzle-image",
"uploadedAt": "2026-05-28T12:00:00.000Z"
}
}
Upload fil
POST /api/extensions/sessions/:sessionId/files
Content-Type: multipart/form-data
Kræver locks:write.
Formularfelter:
file: påkrævet billedfilpurpose: valgfri kort identifikator såsompuzzle-imageellerpreview
Eksempel:
curl "https://chastify.net/api/extensions/sessions/SESSION_ID/files" \
-X POST \
-F "purpose=puzzle-image" \
-F "[email protected]"
Eksempel på svar:
{
"file": {
"id": "file_record_id",
"signedUrl": "https://chastify.<account-id>.r2.cloudflarestorage.com/extensions/abc.webp?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Signature=...",
"publicUrl": "https://chastify.<account-id>.r2.cloudflarestorage.com/extensions/abc.webp?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Signature=...",
"urlExpiresAt": "2026-05-28T12:10:00.000Z",
"sizeBytes": 123456,
"originalName": "puzzle.jpg",
"mimeType": "image/webp",
"purpose": "puzzle-image",
"uploadedAt": "2026-05-28T12:00:00.000Z"
}
}
Almindelige uploadfejl:
extension_file_storage_disabledextension_file_storage_requires_r2file_too_largeinvalid_file_typeextension_app_storage_quota_exceededextension_session_storage_quota_exceededextension_staged_user_app_storage_quota_exceeded
Slet fil
DELETE /api/extensions/sessions/:sessionId/files/:fileId
Kræver locks:write.
Filen skal tilhøre den samme udvidelsesapp, session og lås.
Iframe Bridge-handlinger
Iframe-udvidelser kan bruge den overordnede webbro til læsning af runtime-filer. Upload og sletning af runtime-filer er sessionsmutationer og bør udføres af din backend med en app-scoped Developer API-nøgle plus x-chastify-main-token.
const capabilities = await bridge.request("files.capabilities", {});
const refreshed = await bridge.request("files.get", {
fileId: "file_record_id"
});
image.src = refreshed.file.signedUrl;
Understøttede brohandlinger:
files.capabilities-> tjek om fillagring er aktiveret, og hvilke kvoter der gælderfiles.list-> liste filer ejet af den aktuelle udvidelsessessionfiles.get-> opdater én signeret R2 URL fra et gemt fil-id
Opsætnings-iframes kan bruge yderligere bronavne, før en runtime-session eksisterer. I opsætningstilstand opretter files.upload staged filer, files.list/files.staged.list viser ikke-udløbne staged filer for den aktuelle bruger og app, og files.delete sletter en staged fil. Opsætnings-init-konteksten inkluderer storageDraftId; inkluder denne værdi i din gemte konfiguration som storageDraftId, hvis du vil have, at Chastify skal rense ikke-refererede filer fra den samme kladde med det samme, når den gemmes.
Opsætningen files.upload accepterer også dataUrl for simple iframe-klienter:
await bridge.request("files.upload", {
dataUrl: canvas.toDataURL("image/webp", 0.9),
filename: "preview.webp",
purpose: "preview"
}, 60000);
Foretræk uploads af File eller Blob, når det er muligt. Brug kun dataUrl til små genererede billeder, da base64-nyttelaster er større i hukommelsen.
Signerede links
Den stabile fil-id er id.
Brug signedUrl til at vise eller downloade filen. Signerede links er kortlivede R2 GetObject URL'er genereret af Chastify. publicUrl gemmes som et kompatibilitetsalias og indeholder i øjeblikket den samme signerede URL.
Når et signeret link udløber, skal du kalde GET /api/extensions/sessions/:sessionId/files/:fileId for at modtage et nyt link til én gemt fil, eller GET /api/extensions/sessions/:sessionId/files for at opdatere alle sessionsfillinks.
Oprydningslivscyklus
Udvidelsesfiler ryddes op via en BullMQ-backed oprydningskø.
Oprydning er planlagt når:
- en udvidelsesapp er slettet
- Dokumenter med lås/sessionsudvidelse slettes under fjernelse af lås/arkivoprydning
- en fil slettes eksplicit via sessionsfilens slutpunkt
Køen holder dyr R2-sletning og databaseoprydning ude af anmodningsstien. Hvis køoprydning mislykkes, vender serveren tilbage til oprydning i processen efter svaret, hvor en anmodningskontekst findes, eller direkte oprydning efter bedste evne i livscyklusoprydning på lavere niveau.
Ydelsesnoter
- Funktionstjek bør udføres, før upload-brugergrænsefladen vises.
- Uploads er begrænset af grænser pr. fil, pr. session og pr. app.
- Kvotekontroller bruger indekserede
UserFile-metadata forscope + appId,scope + sessionIdogscope + lockId. - Ryd op i streams, der matcher filposter, i stedet for at indlæse alle URL'er i hukommelsen.
- Uploadede rasterbilleder behandles og gemmes som optimerede webbilleder.
Sikkerhedsnoter
- Behandl ikke billed-URL'er fra udvidelser som pålideligt bevis på færdiggørelse.
- Gem kun Chastify-udstedte filposter som betroede filudvidelser.
- Bind filposter til
appId,sessionIdoglockId. - Håndhæv
locks:writefor uploads og sletninger. - Valider MIME-typen og afvis SVG.
- Hold administratorkontrollerede kvoter aktiveret, før du tillader bred offentlig brug.
- Brug serversidevalidering til alle arbejdsgange, der er afhængige af uploadede filer.
Direkte ruter vs. bro
Brug iframe-broen, når din udvidelse kører inde i Chastify. Den bevarer Chastify-godkendelsen på den overordnede side og undgår at eksponere rutedetaljer for iframen.
Brug kun direkte sessionsruter fra førsteparts Chastify-brugergrænsefladen eller betroede backend-flows, der allerede har gyldig autorisation til udvidelsessessioner.