Úložiště souborů rozšíření
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.
Úložiště souborů rozšíření umožňuje povolenému rozšíření nahrávat obrazové soubory, které patří k relaci rozšíření zámku.
Použijte ho, když JSON stavu rozšíření nestačí, například:
- obrázky puzzle
- vygenerované náhledy
- fotografie výzev
- média specifická pro rozšíření, která by měla být vyčištěna pomocí zámku/relace
Toto úložiště je oddělené od state.*. Pro malá data JSON použijte state.*. Úložiště souborů používejte pouze pro binární média.
Vztah ke koncovým bodům stavu
Stav rozšíření je pro malé JSON s rozsahem relace. Z iframe použijte příkaz bridge read namísto přímého volání REST:
state.get
Tento příkaz mostu směruje na:
GET /api/extensions/sessions/:sessionId/state
Přímá volání backendu pro zápis stavu používají model ověřování API nainstalovaného rozšíření:
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Neosílejte klíče vývojářského API do kódu iframe/prohlížeče.
Pro trvalé reference a data uživatelského rozhraní použijte například stav napsaný v backendu:
{
"puzzleImageFileId": "file_record_id",
"selectedImageIds": ["file_record_id"],
"lastOpenedTab": "images"
}
Neukládejte binární data, obrázky base64, adresy URL prohlížeče blob: ani dlouhodobé kopie signedUrl ve stavu. Podepsané adresy URL vyprší a měly by být obnoveny pomocí files.get při vykreslení obrázku. Velikost zápisů stavu je omezena nastavením stateMaxBytes rozšiřující aplikace, výchozí hodnota je 64 KiB.
Model úložiště
Chastify ukládá rozšiřující soubory do úložiště R2 spravovaného Chastify.
Každý nahraný soubor je sledován pomocí:
scope: "extension"appIdsessionIdalockIdpro běhové/session souborytemplateIdpro soubory nárokované uloženou šablonou zámkustaged,draftIdaexpiresAtpro nahrané nastavení, které dosud nebyly nárokoványextensionKeypurpose
Administrační brána a kvóty
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.
Nastavení koncových bodů pro přípravu
Použijte fázování instalace pouze v případě, že uživatelské rozhraní instalace běží před existencí rozšiřující relace.
Toto je dočasný proces nahrávání. Existuje pro obrazovky nastavení/konfigurace, kde může uživatel nahrát soubor a poté zavřít modální okno nebo zakázat rozšíření před vytvořením zámku/relace. Připravený soubor není trvalý, dokud není vyzvednut uložením konfigurace rozšíření, která na něj odkazuje.
Uživatelská rozhraní nastavení mohou před vykreslením ovládacích prvků nahrávání zkontrolovat dostupnost a aktuální využití ve fázích:
GET /api/extensions/apps/:appId/files/capabilities
Odpověď obsahuje stagedQuota pro soubory připravené k použití aktuálního uživatele v dané rozšiřující aplikaci, jejichž platnost nevypršela:
{
"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
Pole formuláře:
file: požadovaný obrazový souborpurpose: volitelný krátký identifikátor, napříkladjigsaw-config-imagedraftId: volitelné ID konceptu nastavení; znovu použijte stejnou hodnotu, když je otevřeno jedno modální okno nastavení
Odpověď obsahuje stabilní kód file.id a krátkodobou podepsanou URL adresu pro okamžitý náhled.
Příklad odpovědi:
{
"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
}
}
Chcete-li po aktualizaci stránky obnovit nahrané soubory nastavení, vypište připravené soubory pro aktuálního uživatele a rozšiřující aplikaci:
GET /api/extensions/apps/:appId/files/staged?purpose=jigsaw-config-image
Volitelné parametry dotazu:
purpose: vrací pouze připravené soubory pro jeden případ použití nastavenídraftId: vrátit pouze soubory ze známého návrhu nastavení
Pokud je parametr draftId vynechán, Chastify vrátí aktuální uživatelské soubory pro danou aplikaci, jejichž platnost nevypršela. Toto je záměrné pro uživatelská rozhraní nastavení: uživatel může nahrávat soubory, znovu načíst stránku nebo přepnout zařízení a obrazovka nastavení může tyto dočasné nahrané soubory obnovit před uložením zámku/šablony.
Odpověď ze seznamu připravených aplikací obsahuje také stagedQuota, který hlásí nevypršelou dobu připraveného používání dané aplikace aktuálním uživatelem:
{
"items": [],
"stagedQuota": {
"bytesUsed": 123456,
"fileCount": 1,
"maxBytes": 10485760,
"remainingBytes": 10362304
}
}
Uživatelská rozhraní instalace mohou také aktualizovat nebo odstranit jeden připravený soubor:
GET /api/extensions/apps/:appId/files/:fileId
DELETE /api/extensions/apps/:appId/files/staged/:fileId
Pozdější nárokování připravených souborů
Neexistuje žádný samostatný koncový bod pro „nárok“ na straně prohlížeče. Přípravný soubor je nárokován automaticky, když Chastify uloží konfiguraci zámku nebo rozšíření šablony, která odkazuje na připravený soubor.
Tyto trasy si nárokují připravené soubory poté, co dokument zámku/šablony získá ID, a poté znovu ukládají konfiguraci rozšíření s nárokovanými odkazy na soubory. Pokud se nárokování nezdaří, nově vytvořený zámek/šablona se vrátí zpět, aby připravené soubory nezůstaly připojeny k poškozené konfiguraci.
Poznámka ke sdílené šabloně: akceptované sdílené zámky uchovávají ID zdrojové šablony na klonovaném aktivním zámku. Soubory deklarované šablonou se proto uchovávají, dokud jakýkoli klonovaný zámek stále odkazuje na danou šablonu. Pokud je zdrojová šablona odstraněna, Chastify odloží odstranění jejích rozšiřujících souborů, dokud nebude odstraněn nebo archivován poslední klonovaný zámek, který odkazuje na odstraněnou šablonu.
Chcete-li, aby byl připravený soubor k uplatnění, uložte do konfigurace rozšíření, kterou odešle uživatelské rozhraní instalace, odkaz podobný tomuto:
{
"storageDraftId": "draft_123",
"images": [
{
"id": "file_record_id",
"provider": "chastify_storage",
"fileId": "file_record_id",
"url": "extension-file:file_record_id",
"title": "Puzzle image"
}
]
}
Při ukládání Chastify prohledá konfiguraci a vyhledá záznamy provider: "chastify_storage" s platným fileId a poté:
- ověří, zda soubor patří aktuálnímu uživateli a rozšiřující aplikaci
- odmítá soubory s vypršenou platností
- odmítá soubory, které již byly nárokovány jiným kontextem zámku/šablony
- označí odkazované stagingované soubory jako deklarované
- váže deklarované soubory k uloženému zámku nebo šabloně
- Odstraní dočasná pole
signedUrl,publicUrlaurlExpiresAtpřed uložením konfigurace. - smaže neodkazované stagingované soubory ze stejného
storageDraftId
Opuštěné připravené soubory, které se nikdy neuloží, jsou po vypršení platnosti smazány funkcí čištění.
Chcete-li obnovit náhled nastavení pro ID souboru, které vlastní aktuální uživatel a rozšiřující aplikace:
GET /api/extensions/apps/:appId/files/:fileId
Koncové body relace
Tyto koncové body vyžadují normální autorizaci a rozsahy relace rozšíření.
Základní cesta:
/api/extensions/sessions/:sessionId/files
Schopnosti
Před vykreslením ovládacích prvků nahrávání to zkontrolujte.
GET /api/extensions/sessions/:sessionId/files/capabilities
Vyžaduje locks:read.
Příklad odpovědi:
{
"enabled": true,
"provider": "r2",
"r2Configured": true,
"settings": {
"enabled": true,
"maxFileBytes": 10485760,
"maxBytesPerApp": 524288000,
"maxBytesPerSession": 52428800,
"maxStagedBytesPerUserPerApp": 10485760,
"allowedMimePrefixes": ["image/"]
}
}
Seznam souborů
GET /api/extensions/sessions/:sessionId/files
Vyžaduje locks:read.
Příklad odpovědi:
{
"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"
}
]
}
Získat jeden soubor
Použijte to, pokud vaše rozšíření již má uložené ID souboru a potřebuje pouze nově podepsaný odkaz R2.
GET /api/extensions/sessions/:sessionId/files/:fileId
Vyžaduje locks:read.
Soubor musí patřit ke stejné aplikaci, relaci a zámku se stejnou rozšiřující funkcí.
Příklad odpovědi:
{
"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"
}
}
Nahrát soubor
POST /api/extensions/sessions/:sessionId/files
Content-Type: multipart/form-data
Vyžaduje locks:write.
Pole formuláře:
file: požadovaný obrazový souborpurpose: volitelný krátký identifikátor, napříkladpuzzle-imagenebopreview
Příklad:
curl "https://chastify.net/api/extensions/sessions/SESSION_ID/files" \
-X POST \
-F "purpose=puzzle-image" \
-F "[email protected]"
Příklad odpovědi:
{
"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"
}
}
Časté chyby při nahrávání:
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
Smazat soubor
DELETE /api/extensions/sessions/:sessionId/files/:fileId
Vyžaduje locks:write.
Soubor musí patřit ke stejné aplikaci, relaci a zámku se stejnou rozšiřující funkcí.
Akce mostu iframe
Rozšíření iframe mohou pro čtení souborů za běhu používat nadřazený webový most. Nahrávání a mazání souborů za běhu jsou mutace relace a měly by být prováděny vaším backendem s klíčem API pro vývojáře s rozsahem aplikace a kódem 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;
Podporované mostní akce:
files.capabilities-> zkontrolujte, zda je povoleno ukládání souborů a jaké kvóty platífiles.list-> vypsat soubory vlastněné aktuální relací rozšířenífiles.get-> aktualizovat jednu podepsanou URL adresu R2 z uloženého ID souboru
Prvky iframe nastavení mohou používat další názvy mostů před existencí běhového prostředí. V režimu nastavení files.upload vytváří připravené soubory, files.list/files.staged.list vypíše nevypršené připravené soubory pro aktuálního uživatele a aplikaci a files.delete připravovaný soubor smaže. Inicializační kontext nastavení obsahuje storageDraftId; tuto hodnotu zahrňte do uložené konfigurace jako storageDraftId, pokud chcete, aby Chastify ihned po uložení vyčistil neodkazované soubory ze stejného konceptu.
Nastavení files.upload akceptuje také dataUrl pro jednoduché klienty iframe:
await bridge.request("files.upload", {
dataUrl: canvas.toDataURL("image/webp", 0.9),
filename: "preview.webp",
purpose: "preview"
}, 60000);
Pokud je to možné, preferujte nahrávání File nebo Blob. dataUrl používejte pouze pro malé generované obrázky, protože datové zátěže base64 jsou v paměti větší.
Podepsané odkazy
Stabilní identifikátor souboru je id.
Pro zobrazení nebo stažení souboru použijte signedUrl. Podepsané odkazy jsou krátkodobé URL adresy R2 GetObject generované parametrem Chastify. publicUrl je uchováván jako alias kompatibility a aktuálně obsahuje stejnou podepsanou URL adresu.
Po vypršení platnosti podepsaného odkazu zavolejte GET /api/extensions/sessions/:sessionId/files/:fileId pro získání nového odkazu pro jeden uložený soubor nebo GET /api/extensions/sessions/:sessionId/files pro obnovení všech odkazů na soubory relace.
Životní cyklus čištění
Soubory rozšíření se čistí pomocí fronty čištění podporované BullMQ.
Úklid je naplánován, když:
- rozšiřující aplikace je smazána
- Dokumenty o rozšíření zámku/relace jsou smazány během odemčení zámku/vyčištění archivu.
- soubor je explicitně smazán prostřednictvím koncového bodu souboru relace
Fronta zabraňuje nákladnému mazání R2 a čištění databáze v cestě požadavku. Pokud selže zařazení do fronty, server se po odpovědi, kde existuje kontext požadavku, vrátí k čištění v procesu nebo k přímému čištění s maximálním úsilím v rámci čištění na nižší úrovni životního cyklu.
Poznámky k výkonu
- Před zobrazením uživatelského rozhraní pro nahrávání by měly proběhnout kontroly schopností.
- Nahrávání je omezeno limity pro jednotlivé soubory, relace a aplikace.
- Kontroly kvót používají indexovaná metadata
UserFileproscope + appId,scope + sessionIdascope + lockId. - Čisticí streamy odpovídají záznamům souborů namísto načítání všech URL adres do paměti.
- Nahrané rastrové obrázky jsou zpracovány a uloženy jako optimalizované webové obrázky.
Bezpečnostní poznámky
- Nepovažujte adresy URL obrázků poskytnuté rozšířením za důvěryhodný důkaz dokončení.
- Ukládejte pouze záznamy souborů vydaných Chastify jako důvěryhodné soubory s příponou.
- Propojit záznamy souborů s kódy
appId,sessionIdalockId. - Vynutit
locks:writepro nahrávání a mazání. - Ověřit typ MIME a odmítnout SVG.
- Před povolením širokého veřejného používání ponechte povolené kvóty řízené administrátorem.
- Pro jakýkoli pracovní postup, který závisí na nahraných souborech, použijte ověření na straně serveru.
Přímé trasy vs. most
Pokud je vaše rozšíření spuštěno uvnitř Chastify, použijte most iframe. Tím se zachová ověřování Chastify na nadřazené stránce a zabrání se odhalení podrobností o trase v prvku iframe.
Používejte přímé trasy relací pouze z uživatelského rozhraní Chastify první strany nebo z důvěryhodných toků backendu, které již mají platnou autorizaci rozšiřující relace.