Speicher für Erweiterungsdateien
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.
Die Speicherung von Erweiterungsdateien ermöglicht es einer aktivierten Erweiterung, Bilddateien hochzuladen, die zu einer Sperrerweiterungssitzung gehören.
Verwenden Sie es, wenn der JSON-Status der Erweiterung nicht ausreicht, zum Beispiel:
- Puzzlebilder
- generierte Vorschauen
- Challenge-Fotos
- Erweiterungsspezifische Medien, die mit der Sperre/Sitzung bereinigt werden sollten.
Dieser Speicher ist von state.* getrennt. Verwenden Sie state.* für kleine JSON-Daten. Verwenden Sie den Dateispeicher ausschließlich für Binärdaten.
Beziehung zu Zustandsendpunkten
Der Erweiterungsstatus ist für kleine, sitzungsbezogene JSON-Daten vorgesehen. Verwenden Sie aus einem iFrame heraus den Bridge-Read-Befehl anstelle eines direkten REST-Aufrufs.
state.get
Dieser Brückenbefehl leitet weiter zu:
GET /api/extensions/sessions/:sessionId/state
Direkte Backend-Aufrufe zum Schreiben des Status verwenden das Authentifizierungsmodell der installierten Erweiterungs-API:
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Senden Sie keine Entwickler-API-Schlüssel an iFrame-/Browsercode.
Verwenden Sie im Backend geschriebene Zustände für dauerhafte Referenzen und UI-Daten, zum Beispiel:
{
"puzzleImageFileId": "file_record_id",
"selectedImageIds": ["file_record_id"],
"lastOpenedTab": "images"
}
Speichern Sie keine Binärdaten, Base64-Bilder, Browser-URLs (blob:) oder langlebige Kopien von signedUrl im Status. Signierte URLs laufen ab und sollten beim Rendern des Bildes mit files.get aktualisiert werden. Die Größe von Status-Schreibvorgängen ist durch die stateMaxBytes-Einstellung der Erweiterungs-App begrenzt und beträgt standardmäßig 64 KiB.
Speichermodell
Chastify speichert Erweiterungsdateien im von Chastify verwalteten R2-Speicher.
Jede hochgeladene Datei wird wie folgt verfolgt:
scope: "extension"appIdsessionIdundlockIdfür Laufzeit-/SitzungsdateientemplateIdfür Dateien, die von einer gespeicherten Sperrvorlage beansprucht werdenstaged,draftIdundexpiresAtfür Setup-Uploads, die noch nicht beansprucht wurdenextensionKeypurpose
Admin-Gate und Kontingente
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.
Staging-Endpunkte einrichten
Verwenden Sie die Setup-Staging-Umgebung nur dann, wenn eine Setup-UI ausgeführt wird, bevor eine Erweiterungssitzung existiert.
Dies ist ein temporärer Upload-Prozess. Er dient der Einrichtung und Konfiguration von Dateien, auf denen der Benutzer eine Datei hochladen und anschließend das Modal schließen oder die Erweiterung deaktivieren kann, bevor eine Sperre/Sitzung erstellt wird. Eine zwischengespeicherte Datei ist erst dann dauerhaft, wenn sie durch Speichern der zugehörigen Erweiterungskonfiguration beansprucht wird.
Die Setup-Benutzeroberflächen können die Verfügbarkeit und die aktuelle Nutzung der Staging-Bereiche prüfen, bevor die Upload-Steuerelemente angezeigt werden:
GET /api/extensions/apps/:appId/files/capabilities
Die Antwort enthält stagedQuota für die nicht abgelaufenen, zwischengespeicherten Dateien des aktuellen Benutzers in dieser Erweiterungs-App:
{
"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
Formularfelder:
file: erforderliche Bilddateipurpose: optionale Kurzkennung wie z. B.jigsaw-config-imagedraftId: Optionale Entwurfs-ID für die Einrichtung; derselbe Wert kann wiederverwendet werden, solange ein Einrichtungsdialog geöffnet ist.
Die Antwort enthält einen stabilen file.id und eine kurzlebige signierte URL zur sofortigen Vorschau.
Beispielantwort:
{
"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
}
}
Um die Setup-Uploads nach einem Seitenneuladen wiederherzustellen, listen Sie die bereitgestellten Dateien für den aktuellen Benutzer und die Erweiterungs-App auf:
GET /api/extensions/apps/:appId/files/staged?purpose=jigsaw-config-image
Optionale Abfrageparameter:
purpose: Gibt nur die bereitgestellten Dateien für einen Setup-Anwendungsfall zurückdraftId: Gibt nur Dateien aus einem bekannten Setup-Entwurf zurück
Wird draftId weggelassen, gibt Chastify die noch gültigen, zwischengespeicherten Dateien des aktuellen Benutzers für diese App zurück. Dies ist für Setup-Benutzeroberflächen beabsichtigt: Ein Benutzer kann Dateien hochladen, die Seite neu laden oder das Gerät wechseln, und der Setup-Bildschirm kann diese temporären Uploads wiederherstellen, bevor die Sperre/Vorlage gespeichert wird.
Die Antwort der Staging-Liste enthält auch stagedQuota, was die noch nicht abgelaufene Staging-Nutzung des aktuellen Benutzers für diese App angibt:
{
"items": [],
"stagedQuota": {
"bytesUsed": 123456,
"fileCount": 1,
"maxBytes": 10485760,
"remainingBytes": 10362304
}
}
Die Setup-Benutzeroberflächen können auch eine bereitgestellte Datei aktualisieren oder löschen:
GET /api/extensions/apps/:appId/files/:fileId
DELETE /api/extensions/apps/:appId/files/staged/:fileId
Spätere Behauptung, dass inszenierte Dateien
Es gibt keinen separaten browserseitigen „Claim“-Endpunkt. Eine bereitgestellte Datei wird automatisch beansprucht, wenn Chastify eine Sperr- oder Vorlagenerweiterungskonfiguration speichert, die auf die bereitgestellte Datei verweist.
Diese Routen greifen auf bereitgestellte Dateien zu, nachdem dem Sperr-/Vorlagendokument eine ID zugewiesen wurde, und speichern anschließend die Erweiterungskonfiguration erneut mit den zugewiesenen Dateireferenzen. Schlägt die Zuweisung fehl, wird die neu erstellte Sperr-/Vorlage zurückgesetzt, sodass bereitgestellte Dateien nicht an eine fehlerhafte Konfiguration angehängt bleiben.
Hinweis zu gemeinsam genutzten Vorlagen: Akzeptierte gemeinsam genutzte Sperren behalten die Quellvorlagen-ID in der geklonten aktiven Sperre bei. Vorlagenbezogene Dateien bleiben daher erhalten, solange eine geklonte Sperre auf diese Vorlage verweist. Wird die Quellvorlage gelöscht, verzögert Chastify das Löschen ihrer Erweiterungsdateien, bis die letzte geklonte Sperre, die auf die gelöschte Vorlage verweist, gelöscht oder archiviert wurde.
Um eine bereitgestellte Datei für den Zugriff verfügbar zu machen, speichern Sie eine Referenz wie diese in der Erweiterungskonfiguration, die von der Setup-Benutzeroberfläche übermittelt wird:
{
"storageDraftId": "draft_123",
"images": [
{
"id": "file_record_id",
"provider": "chastify_storage",
"fileId": "file_record_id",
"url": "extension-file:file_record_id",
"title": "Puzzle image"
}
]
}
Beim Speichern durchsucht Chastify die Konfiguration nach provider: "chastify_storage"-Einträgen mit einem gültigen fileId und führt dann folgende Schritte aus:
- überprüft, ob die Datei dem aktuellen Benutzer und der Erweiterungs-App gehört.
- Lehnt abgelaufene bereitgestellte Dateien ab
- Lehnt Dateien ab, die bereits von einem anderen Sperr-/Vorlagenkontext beansprucht werden.
- Die Angaben beziehen sich auf die bereitgestellten Dateien, wie behauptet.
- Bindet beanspruchte Dateien an die gespeicherte Sperre oder Vorlage.
- Entfernt temporäre
signedUrl-,publicUrl- undurlExpiresAt-Felder, bevor die Konfiguration gespeichert wird. - Löscht nicht referenzierte, bereitgestellte Dateien aus demselben
storageDraftId
Nicht gespeicherte, zwischengespeicherte Dateien werden nach Ablauf ihrer Gültigkeitsdauer automatisch gelöscht.
So aktualisieren Sie die Setup-Vorschau für eine Datei-ID, die dem aktuellen Benutzer und der Erweiterungs-App gehört:
GET /api/extensions/apps/:appId/files/:fileId
Sitzungsendpunkte
Diese Endpunkte erfordern die normale Autorisierung und die entsprechenden Bereiche für Erweiterungssitzungen.
Basispfad:
/api/extensions/sessions/:sessionId/files
Fähigkeiten
Prüfen Sie dies, bevor Sie die Upload-Steuerelemente rendern.
GET /api/extensions/sessions/:sessionId/files/capabilities
Erfordert locks:read.
Beispielantwort:
{
"enabled": true,
"provider": "r2",
"r2Configured": true,
"settings": {
"enabled": true,
"maxFileBytes": 10485760,
"maxBytesPerApp": 524288000,
"maxBytesPerSession": 52428800,
"maxStagedBytesPerUserPerApp": 10485760,
"allowedMimePrefixes": ["image/"]
}
}
Listendateien
GET /api/extensions/sessions/:sessionId/files
Erfordert locks:read.
Beispielantwort:
{
"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"
}
]
}
Eine Datei herunterladen
Verwenden Sie diese Option, wenn Ihre Erweiterung bereits eine gespeicherte Datei-ID besitzt und nur einen neuen signierten R2-Link benötigt.
GET /api/extensions/sessions/:sessionId/files/:fileId
Erfordert locks:read.
Die Datei muss zur selben Erweiterungs-App, Sitzung und Sperre gehören.
Beispielantwort:
{
"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"
}
}
Datei hochladen
POST /api/extensions/sessions/:sessionId/files
Content-Type: multipart/form-data
Erfordert locks:write.
Formularfelder:
file: erforderliche Bilddateipurpose: optionale Kurzkennung wie z. B.puzzle-imageoderpreview
Beispiel:
curl "https://chastify.net/api/extensions/sessions/SESSION_ID/files" \
-X POST \
-F "purpose=puzzle-image" \
-F "[email protected]"
Beispielantwort:
{
"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"
}
}
Häufige Upload-Fehler:
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
Datei löschen
DELETE /api/extensions/sessions/:sessionId/files/:fileId
Erfordert locks:write.
Die Datei muss zur selben Erweiterungs-App, Sitzung und Sperre gehören.
Iframe-Brückenaktionen
Iframe-Erweiterungen können die übergeordnete Webbrücke für Laufzeit-Dateizugriffe nutzen. Laufzeit-Datei-Uploads und -Löschungen sind Sitzungsänderungen und sollten von Ihrem Backend mit einem anwendungsbezogenen Entwickler-API-Schlüssel plus x-chastify-main-token durchgeführt werden.
const capabilities = await bridge.request("files.capabilities", {});
const refreshed = await bridge.request("files.get", {
fileId: "file_record_id"
});
image.src = refreshed.file.signedUrl;
Unterstützte Brückenaktionen:
files.capabilities-> Prüfen Sie, ob die Dateispeicherung aktiviert ist und welche Quoten gelten.files.list-> Listet die Dateien auf, die der aktuellen Erweiterungssitzung gehörenfiles.get-> Aktualisiere eine signierte R2-URL anhand einer gespeicherten Datei-ID
Setup-Iframes können zusätzliche Bridge-Namen verwenden, bevor eine Laufzeitsitzung beendet wird. Im Setup-Modus erstellt files.upload bereitgestellte Dateien, files.list/files.staged.list listet die nicht abgelaufenen bereitgestellten Dateien für den aktuellen Benutzer und die Anwendung auf, und files.delete löscht eine bereitgestellte Datei. Der Setup-Initialisierungskontext enthält storageDraftId; fügen Sie diesen Wert als storageDraftId in Ihre gespeicherte Konfiguration ein, wenn Chastify beim Speichern nicht referenzierte Dateien aus demselben Entwurf sofort löschen soll.
Setup files.upload akzeptiert auch dataUrl für einfache iFrame-Clients:
await bridge.request("files.upload", {
dataUrl: canvas.toDataURL("image/webp", 0.9),
filename: "preview.webp",
purpose: "preview"
}, 60000);
Bevorzugen Sie nach Möglichkeit Uploads mit File oder Blob. Verwenden Sie dataUrl nur für kleine generierte Bilder, da Base64-Payloads mehr Speicherplatz benötigen.
Signierte Links
Die stabile Dateikennung lautet id.
Verwenden Sie signedUrl, um die Datei anzuzeigen oder herunterzuladen. Signierte Links sind kurzlebige R2-URLs vom Typ GetObject, die von Chastify generiert werden. publicUrl dient als Kompatibilitätsalias und enthält derzeit dieselbe signierte URL.
Wenn ein signierter Link abläuft, rufen Sie GET /api/extensions/sessions/:sessionId/files/:fileId auf, um einen neuen Link für eine gespeicherte Datei zu erhalten, oder GET /api/extensions/sessions/:sessionId/files, um alle Sitzungsdateilinks zu aktualisieren.
Reinigungslebenszyklus
Erweiterungsdateien werden über eine BullMQ-gestützte Bereinigungswarteschlange gelöscht.
Die Reinigung ist geplant, wenn:
- Eine Erweiterungs-App wird gelöscht
- Sperr-/Sitzungserweiterungsdokumente werden beim Entfernen von Sperren/Bereinigungen von Archiven gelöscht.
- Eine Datei wird explizit über den Sitzungsdatei-Endpunkt gelöscht.
Die Warteschlange verhindert, dass aufwändige R2-Löschungen und Datenbankbereinigungen während des Anfrageprozesses durchgeführt werden. Schlägt das Einreihen in die Warteschlange fehl, greift der Server auf die prozessinterne Bereinigung nach der Antwort zurück, sofern ein Anfragekontext vorhanden ist, oder führt eine direkte, bestmögliche Bereinigung im Rahmen der Lebenszyklusbereinigung durch.
Aufführungsnotizen
- Die Funktionsprüfung sollte vor der Anzeige der Upload-Benutzeroberfläche erfolgen.
- Für Uploads gelten Beschränkungen pro Datei, pro Sitzung und pro Anwendung.
- Bei Quotenprüfungen werden indizierte
UserFile-Metadaten fürscope + appId,scope + sessionIdundscope + lockIdverwendet. - Bereinigen Sie Datenströme, die mit Dateidatensätzen übereinstimmen, anstatt alle URLs in den Speicher zu laden.
- Hochgeladene Rasterbilder werden verarbeitet und als optimierte Webbilder gespeichert.
Sicherheitshinweise
- Betrachten Sie die von der Erweiterung bereitgestellten Bild-URLs nicht als verlässlichen Vervollständigungsnachweis.
- Speichern Sie nur Dateien mit der Endung Chastify als vertrauenswürdige Dateiendungen.
- Bindet Dateidatensätze an
appId,sessionIdundlockId. locks:writefür Uploads und Löschvorgänge erzwingen.- MIME-Typ prüfen und SVG ablehnen.
- Bevor Sie die breite öffentliche Nutzung zulassen, sollten die vom Administrator festgelegten Quoten aktiviert bleiben.
- Verwenden Sie serverseitige Validierung für jeden Workflow, der von hochgeladenen Dateien abhängt.
Direkte Routen vs. Brücke
Verwenden Sie die iFrame-Bridge, wenn Ihre Erweiterung innerhalb von Chastify ausgeführt wird. Dadurch bleibt die Chastify-Authentifizierung auf der übergeordneten Seite erhalten und Routendetails werden nicht an den iFrame weitergegeben.
Verwenden Sie direkte Sitzungsrouten nur von der Chastify-Benutzeroberfläche des Herstellers oder von vertrauenswürdigen Backend-Abläufen, die bereits über eine gültige Autorisierung der Erweiterungssitzung verfügen.