Skip to main content

Pohrana datoteka proširenja

Pohrana datoteka proširenja omogućuje omogućenom proširenju prijenos slikovnih datoteka koje pripadaju sesiji zaključanog proširenja.

Koristite ga kada JSON stanja ekstenzije nije dovoljan, na primjer:

  • slike zagonetki
  • generirani pregledi
  • fotografije izazova
  • Mediji specifični za ekstenziju koji bi trebali biti očišćeni pomoću zaključavanja/sesije

Ova pohrana je odvojena od state.*. Za male JSON podatke koristite state.*. Pohranu datoteka koristite samo za binarne medije.

Odnos prema krajnjim točkama stanja

Stanje proširenja je za mali JSON s opsegom sesije. Iz iframea upotrijebite naredbu bridge read umjesto izravnog pozivanja REST-a:

state.get

Ta naredba mosta usmjerava na:

GET /api/extensions/sessions/:sessionId/state

Izravni backend pozivi za pisanje stanja koriste model autentifikacije API-ja instaliranog proširenja:

Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH

Ne šaljite ključeve API-ja razvojnih programera u iframe/kod preglednika.

Koristite stanje napisano u pozadini za trajne reference i podatke korisničkog sučelja, na primjer:

{
"puzzleImageFileId": "file_record_id",
"selectedImageIds": ["file_record_id"],
"lastOpenedTab": "images"
}

Ne pohranjujte binarne podatke, base64 slike, URL-ove preglednika blob: ili dugotrajne kopije signedUrl u stanju. Potpisani URL-ovi istječu i treba ih osvježiti s files.get kada se slika renderira. Zapisivanje stanja ograničeno je veličinom postavke stateMaxBytes aplikacije proširenja, koja je zadana na 64 KiB.

Model pohrane

Chastify pohranjuje datoteke ekstenzija u R2 pohranu kojom upravlja Chastify.

Svaka prenesena datoteka prati se pomoću:

  • scope: "extension"
  • appId
  • sessionId i lockId za datoteke vremena izvođenja/sesije
  • templateId za datoteke koje je zatražio spremljeni predložak zaključavanja
  • staged, draftId i expiresAt za prijenose postavki koji još nisu preuzeti
  • extensionKey
  • purpose

Administratorska vrata i kvote

Postavljanje krajnjih točaka pripreme

Koristite pripremu za postavljanje samo kada se korisničko sučelje za postavljanje pokrene prije nego što postoji sesija proširenja.

Ovo je privremeni tok prijenosa. Postoji za zaslone za postavljanje/konfiguraciju gdje korisnik može prenijeti datoteku, a zatim zatvoriti modalni prozor ili onemogućiti proširenje prije stvaranja zaključavanja/sesije. Pripremljena datoteka nije trajna dok se ne zatraži spremanjem konfiguracije proširenja koja se na nju poziva.

Korisnička sučelja za postavljanje mogu provjeriti dostupnost i trenutnu upotrebu u fazama prije prikazivanja kontrola prijenosa:

GET /api/extensions/apps/:appId/files/capabilities

Odgovor uključuje stagedQuota za neistekle pripremljene datoteke trenutnog korisnika na toj aplikaciji proširenja:

{
"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

Polja obrasca:

  • file: potrebna slikovna datoteka
  • purpose: opcionalni kratki identifikator kao što je jigsaw-config-image
  • draftId: opcionalni ID nacrta postavki; ponovno upotrijebite istu vrijednost dok je otvoren jedan modalni prozor za postavke

Odgovor sadrži stabilan file.id i kratkotrajni potpisani URL za trenutni pregled.

Primjer odgovora:

{
"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
}
}

Za vraćanje postavki nakon osvježavanja stranice, navedite pripremljene datoteke za trenutnog korisnika i aplikaciju proširenja:

GET /api/extensions/apps/:appId/files/staged?purpose=jigsaw-config-image

Neobavezni parametri upita:

  • purpose: vrati samo pripremljene datoteke za jedan slučaj upotrebe postavljanja
  • draftId: vrati samo datoteke iz poznatog nacrta postavki

Ako se izostavi draftId, Chastify vraća neistekle pripremljene datoteke trenutnog korisnika za tu aplikaciju. To je namjerno za korisnička sučelja za postavljanje: korisnik može prenijeti datoteke, ponovno učitati stranicu ili promijeniti uređaj, a zaslon za postavljanje može vratiti te privremene prijenose prije nego što se spremi brava/predložak.

Odgovor s popisa postupaka također uključuje stagedQuota, koji izvještava o neistekloj upotrebi postupaka trenutnog korisnika za tu aplikaciju:

{
"items": [],
"stagedQuota": {
"bytesUsed": 123456,
"fileCount": 1,
"maxBytes": 10485760,
"remainingBytes": 10362304
}
}

Korisnička sučelja za postavljanje također mogu osvježiti ili izbrisati jednu pripremljenu datoteku:

GET /api/extensions/apps/:appId/files/:fileId
DELETE /api/extensions/apps/:appId/files/staged/:fileId

Naknadno preuzimanje pripremljenih datoteka

Ne postoji zasebna krajnja točka "zahtjeva" na strani preglednika. Pripremljena datoteka se automatski zahtijeva kada Chastify spremi konfiguraciju proširenja brave ili predloška koja referencira pripremljenu datoteku.

Te rute preuzimaju pripremljene datoteke nakon što dokument zaključavanja/predloška dobije ID, a zatim ponovno spremaju konfiguraciju proširenja s referencama preuzetih datoteka. Ako preuzimanje ne uspije, novostvoreni zaključavanje/predložak se poništava kako pripremljene datoteke ne bi ostale pričvršćene na neispravnu konfiguraciju.

Napomena o dijeljenom predlošku: prihvaćeni dijeljeni brave zadržavaju ID izvornog predloška na kloniranom aktivnom bravi. Datoteke za koje je zatražen predložak stoga se čuvaju dok se bilo koja klonirana brava još uvijek referencira na taj predložak. Ako se izvorni predložak izbriše, Chastify odgađa brisanje svojih datoteka proširenja dok se posljednja klonirana brava koja referencira izbrisani predložak ne izbriše ili arhivira.

Da biste omogućili zahtjev za pripremljenu datoteku, pohranite referencu poput ove u konfiguraciji proširenja koju šalje korisničko sučelje za postavljanje:

{
"storageDraftId": "draft_123",
"images": [
{
"id": "file_record_id",
"provider": "chastify_storage",
"fileId": "file_record_id",
"url": "extension-file:file_record_id",
"title": "Puzzle image"
}
]
}

Prilikom spremanja, Chastify skenira konfiguraciju za provider: "chastify_storage" zapise s valjanim fileId, a zatim:

  • provjerava pripada li datoteka trenutnom korisniku i aplikaciji proširenja
  • odbacuje istekle pripremljene datoteke
  • odbacuje datoteke koje je već zatražio drugi kontekst zaključavanja/predloška
  • označava referencirane pripremljene datoteke kao što je navedeno
  • veže zatražene datoteke sa spremljenim zaključavanjem ili predloškom
  • uklanja privremena polja signedUrl, publicUrl i urlExpiresAt prije nego što se konfiguracija sačuva
  • briše nereferencirane pripremljene datoteke iz istog storageDraftId

Napuštene pripremljene datoteke koje se nikada ne spremaju brišu se čišćenjem nakon isteka roka.

Za osvježavanje pregleda postavki za ID datoteke u vlasništvu trenutnog korisnika i aplikacije proširenja:

GET /api/extensions/apps/:appId/files/:fileId

Krajnje točke sesije

Ove krajnje točke zahtijevaju normalnu autorizaciju i opsege sesije proširenja.

Osnovni put:

/api/extensions/sessions/:sessionId/files

Mogućnosti

Provjerite ovo prije renderiranja kontrola prijenosa.

GET /api/extensions/sessions/:sessionId/files/capabilities

Zahtijeva locks:read.

Primjer odgovora:

{
"enabled": true,
"provider": "r2",
"r2Configured": true,
"settings": {
"enabled": true,
"maxFileBytes": 10485760,
"maxBytesPerApp": 524288000,
"maxBytesPerSession": 52428800,
"maxStagedBytesPerUserPerApp": 10485760,
"allowedMimePrefixes": ["image/"]
}
}

Popis datoteka

GET /api/extensions/sessions/:sessionId/files

Zahtijeva locks:read.

Primjer odgovora:

{
"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"
}
]
}

Nabavi jednu datoteku

Koristite ovo kada vaša ekstenzija već ima pohranjeni ID datoteke i potrebna joj je samo nova potpisana R2 veza.

GET /api/extensions/sessions/:sessionId/files/:fileId

Zahtijeva locks:read.

Datoteka mora pripadati istoj aplikaciji, sesiji i bravi s istim proširenjem.

Primjer odgovora:

{
"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"
}
}

Prenesi datoteku

POST /api/extensions/sessions/:sessionId/files
Content-Type: multipart/form-data

Zahtijeva locks:write.

Polja obrasca:

  • file: potrebna slikovna datoteka
  • purpose: opcionalni kratki identifikator kao što je puzzle-image ili preview

Primjer:

curl "https://chastify.net/api/extensions/sessions/SESSION_ID/files" \
-X POST \
-F "purpose=puzzle-image" \

Primjer odgovora:

{
"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"
}
}

Uobičajene pogreške pri prijenosu:

  • extension_file_storage_disabled
  • extension_file_storage_requires_r2
  • file_too_large
  • invalid_file_type
  • extension_app_storage_quota_exceeded
  • extension_session_storage_quota_exceeded
  • extension_staged_user_app_storage_quota_exceeded

Izbriši datoteku

DELETE /api/extensions/sessions/:sessionId/files/:fileId

Zahtijeva locks:write.

Datoteka mora pripadati istoj aplikaciji, sesiji i bravi s istim proširenjem.

Radnje mosta Iframe

Iframe ekstenzije mogu koristiti nadređeni web most za čitanje datoteka tijekom izvođenja. Prijenos i brisanje datoteka tijekom izvođenja su mutacije sesije i trebao bi ih izvoditi vaš backend s ključem API-ja razvojnog programera s opsegom aplikacije i 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;

Podržane radnje mosta:

  • files.capabilities -> provjeri je li omogućeno pohranjivanje datoteka i koje se kvote primjenjuju
  • files.list -> popis datoteka u vlasništvu trenutne sesije proširenja
  • files.get -> osvježi jedan potpisani R2 URL iz pohranjenog ID-a datoteke

iframeovi za postavljanje mogu koristiti dodatna imena mostova prije nego što postoji sesija izvođenja. U načinu rada za postavljanje, files.upload stvara pripremljene datoteke, files.list/files.staged.list navodi neistekle pripremljene datoteke za trenutnog korisnika i aplikaciju, a files.delete briše pripremljenu datoteku. Početni kontekst postavljanja uključuje storageDraftId; uključite tu vrijednost u spremljenu konfiguraciju kao storageDraftId ako želite da Chastify odmah prilikom spremanja očisti nereferencirane datoteke iz istog nacrta.

Postavljanje files.upload također prihvaća dataUrl za jednostavne iframe klijente:

await bridge.request("files.upload", {
dataUrl: canvas.toDataURL("image/webp", 0.9),
filename: "preview.webp",
purpose: "preview"
}, 60000);

Kad god je moguće, preferirajte prijenose File ili Blob. dataUrl koristite samo za male generirane slike jer su base64 korisni sadržaji veći u memoriji.

Stabilni identifikator datoteke je id.

Za prikaz ili preuzimanje datoteke koristite signedUrl. Potpisane veze su kratkotrajni R2 GetObject URL-ovi generirani od strane Chastify. publicUrl se čuva kao pseudonim kompatibilnosti i trenutno sadrži isti potpisani URL.

Kada potpisana veza istekne, pozovite GET /api/extensions/sessions/:sessionId/files/:fileId za primanje nove veze za jednu pohranjenu datoteku ili GET /api/extensions/sessions/:sessionId/files za osvježavanje svih veza datoteka sesije.

Životni ciklus čišćenja

Datoteke proširenja čiste se putem reda za čišćenje koji podržava BullMQ.

Čišćenje je planirano kada:

  • aplikacija proširenja je izbrisana
  • Dokumenti o proširenju zaključavanja/sesije brišu se tijekom uklanjanja zaključavanja/čišćenja arhive
  • datoteka se eksplicitno briše putem krajnje točke datoteke sesije

Red čekanja sprječava skupo brisanje R2 i čišćenje baze podataka u putanji zahtjeva. Ako stavljanje u red čekanja ne uspije, poslužitelj se vraća na čišćenje unutar procesa nakon odgovora gdje postoji kontekst zahtjeva ili izravno čišćenje u najboljem mogućem smjeru u čišćenju životnog ciklusa niže razine.

Bilješke o izvedbi

  • Provjere mogućnosti trebale bi se provesti prije prikaza korisničkog sučelja za prijenos.
  • Prijenosi su ograničeni po datoteci, po sesiji i po aplikaciji.
  • Provjere kvota koriste indeksirane metapodatke UserFile za scope + appId, scope + sessionId i scope + lockId.
  • Čišćenje tokova podudaranja zapisa datoteka umjesto učitavanja svih URL-ova u memoriju.
  • Prenesene rasterske slike obrađuju se i pohranjuju kao optimizirane web slike.

Sigurnosne napomene

  • Ne tretirajte URL-ove slika koje pruža proširenje kao pouzdani dokaz dovršetka.
  • Pohrani samo zapise datoteka izdanih od strane Chastify kao pouzdane datoteke ekstenzija.
  • Poveži zapise datoteke sa appId, sessionId i lockId.
  • Primijeni locks:write za prijenose i brisanja.
  • Validiraj MIME tip i odbaci SVG.
  • Ostavite administratorski kontrolirane kvote omogućenima prije nego što dopustite široku javnu upotrebu.
  • Koristite validaciju na strani poslužitelja za bilo koji tijek rada koji ovisi o prenesenim datotekama.

Izravne rute u odnosu na most

Koristite iframe most kada se vaše proširenje izvršava unutar Chastify. To zadržava Chastify autentifikaciju na nadređenoj stranici i izbjegava izlaganje detalja rute iframeu.

Koristite izravne rute sesije samo iz korisničkog sučelja Chastify prve strane ili pouzdanih pozadinskih tokova koji već imaju valjanu autorizaciju proširenja sesije.