Příklady API
Použijte tuto stránku ke zkopírování správného tvaru požadavku pro každý tok rozšíření.
- Příklady mostů iframe používají akce
postMessage, jako napříkladsession.get,state.getafiles.get. - Privilegované příklady používají váš vlastní rozšiřující backend s kódy
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEYax-chastify-main-token. - Nikdy neposílejte klíč vývojářského API do iframe ani do kódu prohlížeče.
Most iframe je určen pro bootstrap uživatelského rozhraní a operace s nízkým rizikem relací. Používejte jej pro čtení kontextu, ukládání stavu vlastněného rozšířením a rozpoznávání URL adres souborů.
Kód iframe prohlížeče je řízen uživatelem. Nepoužívejte požadavky iframe bridge k přidávání/odebírání času, dokončování úloh, mazání blokátorů odemykání, nahrávání/mazání běhových souborů, odesílání oznámení, zápisu protokolů ani ovládání zařízení.
Formát požadavku a odpovědi
Bezpečné akce mostu iframe jsou odesílány uvnitř této obálky požadavku na most:
{
"type": "chastify:ext:req", // required
"v": 1, // protocol version
"id": "req-123", // your unique request id
"nonce": "from-iframe-hash",
"action": "session.get",
"payload": {}
}
A vy obdržíte:
{
"type": "chastify:ext:resp",
"v": 1,
"id": "req-123", // same id you sent
"ok": true,
"data": {}
}
Pokud je ok rovné false, zkontrolujte error.code a error.message.
Příklady pouze pro backend používají běžné HTTPS požadavky z vašeho serveru. Nejsou odesílány přes most iframe.
Relace a kontext
session.get
Použijte to jako první v téměř každém rozšiřujícím toku.
Co to dělá:
- Ověřuje, zda vaše mostní připojení funguje.
- Vrátí kontext relace (stav zámku, role, konfigurace rozšíření, možnosti).
- Vrátí informace o možnostech zařízení, které může vaše uživatelské rozhraní použít, než požádá backend o volání
device.command.
K čemu se používá:
- Bootstrapping vašeho uživatelského rozhraní.
- Povolení/zakázání funkcí na základě role a oprávnění.
- Kontrola podporovaných příkazů zařízení před vykreslením ovládacích prvků zařízení.
Příklad datové části akce:
{
"action": "session.get",
"payload": {}
}
Příklad výňatku odpovědi session.get (data běhového zámku):
{
"ok": true,
"data": {
"lockData": {
"frozen": false,
"unlockable": false,
"trusted": true,
"taskAssigned": true,
"timeLockedSeconds": 1420,
"timeRemainingSeconds": 27800,
"maxTimeRemainingSeconds": 86400,
"taskPoints": 12,
"taskPointsRequired": 20,
"lockTitle": "Weekend Challenge",
"wearerUsername": "alice",
"keyholderUsername": "kh_bob",
"wearerLastSeenTimestamp": 1739640505123,
"keyholderLastSeenTimestamp": null
}
}
}
Poznámky k ochraně osobních údajů:
wearerLastSeenTimestamp/keyholderLastSeenTimestampse vrátí pouze v případě, že daný uživatel máshowOnlineStatus !== false.- Pokud je viditelnost online stavu zakázána, tato pole mají hodnotu
null.
Toky rozšíření backendu
Tyto příklady ukazují bezpečný výrobní vzorec:
- iframe čte z datové části hash
mainTokenasessionId. - Prvek iframe je odešle do vašeho backendu.
- Váš backend ověřuje stav vaší vlastní hry/úkolu/obchodu.
- Váš backend volá Chastify s klíčem vývojářského API v rozsahu aplikace a
x-chastify-main-token.
Nepoužívejte sessionId samostatně pro ověřování. mainToken považujte za spouštěcí kontext viditelný v prohlížeči a klíč vývojářského API považujte pouze za tajný klíč pro backend.
Váš backend musí před voláním Chastify ověřit stav své hry/úlohy. Předání mainToken a sessionId z iframe pouze identifikuje otevřenou relaci rozšíření; nedokazuje, že uživatel dokončil výzvu.
Bezpečné načtení kontextu relace
Váš iframe může pro UI bootstrap používat bezpečný most session.get. Pokud váš backend potřebuje stejný kontext před použitím privilegované akce, načtěte ho z backendu s oběma přihlašovacími údaji.
V rámečku:
const hash = JSON.parse(decodeURIComponent(window.location.hash.slice(1)));
await fetch("/api/my-extension/session-context", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
mainToken: hash.mainToken,
sessionId: hash.sessionId
})
});
Váš backend:
app.post("/api/my-extension/session-context", async (req, res) => {
const { mainToken, sessionId } = req.body;
const response = await fetch(
`https://chastify.net/api/extensions/sessions/${encodeURIComponent(sessionId)}`,
{
headers: {
Authorization: `Bearer ${process.env.CHASTIFY_APP_DEVELOPER_KEY}`,
"x-chastify-main-token": mainToken
}
}
);
if (!response.ok) {
return res.status(response.status).json(await response.json());
}
const context = await response.json();
res.json({
role: context.role,
config: context.extensionConfig,
lockData: context.lockData
});
});
Použít čas z backendu rozšíření
Prohlížeč může požádat váš backend o uplatnění odměny nebo trestu, ale prohlížeč nesmí rozhodovat o tom, zda je akce platná. Nejprve ověřte akci na straně serveru.
app.post("/api/my-extension/apply-reward", async (req, res) => {
const { mainToken, sessionId, runId } = req.body;
const run = await db.gameRuns.findUnique({ where: { id: runId } });
if (!run || run.sessionId !== sessionId || !run.serverVerifiedWin) {
return res.status(403).json({ error: "game_not_verified" });
}
const response = await fetch(
`https://chastify.net/api/extensions/sessions/${encodeURIComponent(sessionId)}/action`,
{
method: "POST",
headers: {
"content-type": "application/json",
Authorization: `Bearer ${process.env.CHASTIFY_APP_DEVELOPER_KEY}`,
"x-chastify-main-token": mainToken
},
body: JSON.stringify({
name: "remove_time",
params: 300
})
}
);
if (!response.ok) {
return res.status(response.status).json(await response.json());
}
res.json(await response.json());
});
Pro tresty použijte add_time a pro odměny remove_time.
Dokončení hry ověřené serverem
U her jako Simon Says nedůvěřujte výhře hlášené klientem. Vytvořte běh na straně serveru, uložte očekávanou sekvenci nebo její hash a ověřte odeslaný vstup před voláním Chastify.
Hra s pamětí viditelná v prohlížeči nemůže dokázat, že ji hrál člověk poctivě, protože prohlížeč musí pro vykreslení hry obdržet sekvenci. Ověření serveru stále zabraňuje padělaným mutacím Chastify a umožňuje vašemu backendu vynutit ID běhů, platnost, obtížnost, kadenci, skóre a ochranu před opakovaným přehráváním před použitím odměn nebo trestů.
app.post("/api/simon/runs", async (req, res) => {
const { mainToken, sessionId } = req.body;
await verifySessionLaunch({ mainToken, sessionId });
const sequence = createSimonSequence();
const run = await db.simonRuns.create({
data: {
sessionId,
sequenceHash: hashSequence(sequence),
expiresAt: new Date(Date.now() + 5 * 60_000)
}
});
res.json({
runId: run.id,
sequence
});
});
app.post("/api/simon/runs/:runId/complete", async (req, res) => {
const { mainToken, sessionId, input } = req.body;
await verifySessionLaunch({ mainToken, sessionId });
const run = await db.simonRuns.findUnique({ where: { id: req.params.runId } });
if (!run || run.sessionId !== sessionId || run.expiresAt < new Date()) {
return res.status(403).json({ error: "run_invalid" });
}
const won = hashSequence(input) === run.sequenceHash;
await db.simonRuns.update({
where: { id: run.id },
data: { completedAt: new Date(), serverVerifiedWin: won }
});
if (won) {
await fetch(`https://chastify.net/api/extensions/sessions/${encodeURIComponent(sessionId)}/requirements/progress`, {
method: "POST",
headers: {
"content-type": "application/json",
Authorization: `Bearer ${process.env.CHASTIFY_APP_DEVELOPER_KEY}`,
"x-chastify-main-token": mainToken
},
body: JSON.stringify({
key: "simon_says_wins",
amount: 1
})
});
}
res.json({ won });
});
Přesné schéma úložiště běhů je vaše. verifySessionLaunch by měl volat Chastify s vaším klíčem API pro vývojáře v rozsahu aplikace a x-chastify-main-token, než začne důvěřovat sessionId. Důležité pravidlo je, že mutace Chastify proběhnou až poté, co váš backend ověří spuštění a výsledek.
Plánované požadavky
Váš backend vlastní plány, kontroly kadence a validaci důkazů. Chastify používejte pouze k zaznamenávání důvěryhodného průběhu nebo k aktualizaci blokátorů odemknutí poté, co váš backend rozhodne, že je požadavek splněn.
async function recordDailyRequirementProgress({ sessionId, mainToken, userId }) {
const completed = await db.dailyCheckins.exists({
where: {
userId,
day: new Date().toISOString().slice(0, 10),
verified: true
}
});
if (!completed) return;
await fetch(`https://chastify.net/api/extensions/sessions/${encodeURIComponent(sessionId)}/requirements/progress`, {
method: "POST",
headers: {
"content-type": "application/json",
Authorization: `Bearer ${process.env.CHASTIFY_APP_DEVELOPER_KEY}`,
"x-chastify-main-token": mainToken
},
body: JSON.stringify({
key: "daily_checkin",
amount: 1
})
});
}
Aktuální API relací nainstalovaného rozšíření vyžadují platný spouštěcí token iframe v x-chastify-main-token; spouštěcí tokeny v současné době vyprší po 10 hodinách. Pro plánované úlohy, které se spustí po vypršení platnosti tohoto tokenu, uložte si vlastní čekající důkaz a odešlete průběh při dalším platném spuštění rozšíření, nebo použijte tok serveru první strany/vestavěný server určený pro bezobslužnou práci na pozadí.
Nepovažujte naplánované úlohy za důvěryhodné jen proto, že běží na vašem serveru. Úloha stále potřebuje ochranu na straně serveru, kontroly kadence, ochranu proti přehrávání a platnou autorizační cestu Chastify před zaznamenáním průběhu požadavků.
Oznámení
notifications.custom
Použijte toto z backendu vašeho rozšíření k odeslání vlastního oznámení o rozšíření uživateli, držiteli klíče nebo oběma.
Koncový bod:
POST /api/extensions/sessions/:sessionId/notifications/custom
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Příklad těla:
{
"title": "Extension Reminder",
"message": "Your next challenge is ready.",
"showPageOverlay": false,
"target": "both"
}
Poznámky:
showPageOverlaymá výchozí hodnotufalse.targetmá výchozí hodnotuwearer.- API vytváří typ oznámení
extension_app_message.
Stav rozšíření
Stav rozšíření jsou data JSON vlastněná vaším rozšířením pro aktuální relaci uzamčení.
Zápisy stavu jsou pouze pro backend a vyžadují klíč vývojářského API s rozsahem aplikace a relaci mainToken. Prvky iframe mohou číst stav s parametrem state.get, ale nemohou jej přímo zapisovat.
state.put
Co to dělá:
- Nahradí celý objekt stavu novým objektem
data. - Vyžaduje přihlašovací údaje backendu.
Kdy použít:
- Počáteční uložení.
- Úplné přepsání, pokud již máte kompletně nový stav.
Příklad:
curl -X PUT "https://chastify.net/api/extensions/sessions/$SESSION_ID/state" \
-H "Authorization: Bearer $DEVELOPER_KEY" \
-H "x-chastify-main-token: $MAIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": {
"counter": 1,
"notes": "first test"
}
}'
Poznámky z terénu:
payload.data: libovolná platná hodnota/objekt JSON, který vaše rozšíření potřebuje.- Avoid Mongo-unsafe key names (
$prefix or keys containing.). - Stav je omezen na úrovni relace a velikost je omezena parametrem
stateMaxBytesrozšiřující aplikace, výchozí hodnota je 64 KiB. - Ukládejte ID souborů ve stavu, nikoli binární soubory nebo podepsané URL. Pro obnovení podepsaných URL před vykreslením médií použijte
files.get.
state.patch
Co to dělá:
- Aplikuje opravu sloučení JSON na existující stav.
- Je třeba zaslat pouze změněné klíče.
- Vyžaduje přihlašovací údaje backendu.
Kdy použít:
- Přírůstkové aktualizace z interakcí uživatelů.
- Aktualizace jednoho pole bez opětovného odeslání všeho.
Příklad:
curl -X PATCH "https://chastify.net/api/extensions/sessions/$SESSION_ID/state" \
-H "Authorization: Bearer $DEVELOPER_KEY" \
-H "x-chastify-main-token: $MAIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": {
"counter": 2
}
}'
state.get
Co to dělá:
- Přečte aktuální stav rozšíření.
- K dispozici přes most iframe.
Kdy použít:
- Při načtení iframe.
- Po zápisu, pokud chcete znovu synchronizovat místní uživatelské rozhraní.
Příklad:
{
"action": "state.get",
"payload": {}
}
Úložiště souborů
Pro binární média, jako jsou obrázky puzzle, generované náhledy nebo fotografie z výzev, použijte files.*. Vrácený file.id uložte ve stavu napsaném na backendu nebo do své vlastní databáze. Vykreslete pomocí file.signedUrl a při pozdějším načtení iframe obnovte podepsanou URL pomocí files.get.
Nastavení obrazovky, které se spustí před existencí zámku/relace, používají namísto files.upload fázované nahrávání. Soubory fázované nahrávání jsou dočasné, dokud není konfigurace rozšíření uložena s odkazem provider: "chastify_storage" a fileId. Chastify si tyto soubory automaticky nárokuje při ukládání zámku/šablony; neexistuje žádné samostatné volání nároku na straně prohlížeče.
Příklad rozdělení stavu/souboru z vašeho backendu:
curl -X PATCH "https://chastify.net/api/extensions/sessions/$SESSION_ID/state" \
-H "Authorization: Bearer $DEVELOPER_KEY" \
-H "x-chastify-main-token: $MAIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": {
"puzzleImageFileId": "file_record_id"
}
}'
Později vyřešte obrázek před zobrazením:
const state = await bridge.request("state.get", {});
const file = await bridge.request("files.get", {
fileId: state.data.puzzleImageFileId
});
image.src = file.file.signedUrl;
files.capabilities
Před zobrazením ovládacích prvků nahrávání to zkontrolujte.
{
"action": "files.capabilities",
"payload": {}
}
Běhové prostředí files.upload
Nahrávání souborů za běhu mutuje data relace rozšíření, takže se nejedná o příkaz iframe bridge. Nahrajte soubory za běhu z backendu pomocí klíče API pro vývojáře s rozsahem aplikace a kódu x-chastify-main-token.
files.get
Obnovte jednu podepsanou URL adresu R2 ze stabilního ID souboru.
{
"action": "files.get",
"payload": {
"fileId": "file_record_id"
}
}
files.list
{
"action": "files.list",
"payload": {}
}
Běhové prostředí files.delete je také pouze pro backend ze stejného důvodu jako upload.
Akce zámku
Přidat čas
Koncový bod: POST /api/extensions/sessions/:sessionId/action
Co to dělá:
- Přidá nebo odebere čas z odpočítávání zámku v závislosti na
deltaSeconds.
Kdy použít:
- Tlačítka odměn/trestů.
- Výsledky her (výhra přidává čas, prohra čas ubírá).
Příklad:
{
"name": "add_time",
"params": 300 // +300 sec = +5 minutes
}
Poznámky z terénu:
- Pozitivní hodnota přidává čas.
- Záporná hodnota odebere čas (pokud to pravidla serveru dovolují).
Zmrazit
Koncový bod: POST /api/extensions/sessions/:sessionId/action
Co to dělá:
- Zmrazí postup na určitou dobu.
Kdy použít:
- Mechanika ochlazování.
- Kontrolní body za odměny.
Příklad:
{
"name": "freeze",
"params": { "durationSeconds": 120 }
}
Můžete to také zavolat bez durationSeconds:
{
"name": "freeze",
"params": {}
}
Poznámky z terénu:
durationSecondsje volitelný.- Pokud je vynechán, aktuální výchozí hodnota je
3600sekund (1 hodina). - Akceptovaný rozsah je
60až86400sekund.
Uvolnit
Koncový bod: POST /api/extensions/sessions/:sessionId/action
Co to dělá:
- Ukončí aktivní zmrazení a obnoví normální chování časovače.
Kdy použít:
- Ruční přepsání v pracovních postupech rozšíření.
- Ovládací prvky „Zrušit zmrazení“.
Příklad:
{
"name": "unfreeze",
"params": {}
}
Pranýř
Koncový bod: POST /api/extensions/sessions/:sessionId/action
Co to dělá:
- Zahájí období pranýře pro aktivní relaci zámku.
Kdy použít:
- Mechanika penalizací po neúspěšných úkolech/výzvách.
- Eskalační toky, které dočasně omezují interakci zámků.
Příklad:
{
"name": "pillory",
"params": {
"durationSeconds": 600,
"reason": "Missed scheduled check-in"
}
}
Poznámky z terénu:
namemusí býtpillory.- Je vyžadován kód
params.durationSeconds. params.reasonje volitelný.- Vyžaduje, aby byl v konfiguraci relace povolen pranýř.
Konec pranýře
Koncový bod: POST /api/extensions/sessions/:sessionId/action
Co to dělá:
- Okamžitě ukončí aktuální aktivní relaci pranýře.
Příklad:
{
"name": "pillory.end",
"params": {}
}
Poznámky z terénu:
namemusí býtpillory.end.- Selže s kódem
pillory_not_active, pokud zámek není aktuálně v pranýři.
Přiřadit úkol
Koncový bod: POST /api/extensions/sessions/:sessionId/action
Co to dělá:
- Vytvoří aktivní spuštění úlohy pro uživatele z logiky rozšíření.
- Může přepsat již otevřené spuštění úlohy.
Příklad:
{
"name": "task.assign",
"params": {
"taskText": "Clean your room",
"points": 10,
"verificationRequired": true,
"durationSeconds": 1800
}
}
Poznámky z terénu:
- Je vyžadován kód
taskText. pointsje volitelný a je omezen na straně serveru.verificationRequiredmá výchozí hodnotufalse.durationSecondsje volitelný (0znamená, že časovač není vyžadován).- Vyžaduje povolený modul Úkoly na zámku.
Spustit časovač úkolu
Koncový bod: POST /api/extensions/sessions/:sessionId/action
Co to dělá:
- Spustí nebo restartuje odpočítávání pro aktuálně aktivní časově omezenou úlohu.
Příklad:
{
"name": "task.start_timer",
"params": {}
}
Poznámky z terénu:
- Vyžaduje aktivní spuštění úlohy.
- Selže, pokud aktuální úloha nemá nakonfigurovanou dobu trvání.
Dokončit úkol
Koncový bod: POST /api/extensions/sessions/:sessionId/action
Co to dělá:
- Označí aktivní spuštění úlohy jako dokončené nebo neúspěšné.
Příklad (úspěch):
{
"name": "task.complete",
"params": {
"successful": true
}
}
Příklad (selhání):
{
"name": "task.complete",
"params": {
"successful": false,
"reason": "Did not finish in time"
}
}
Spustit dočasné otevření
Koncový bod: POST /api/extensions/sessions/:sessionId/action
Co to dělá:
- Spustí dočasné okno pro zahájení hygieny z logiky rozšíření.
Příklad:
{
"name": "hygienic_unlock.start",
"params": {
"durationSeconds": 900
}
}
Poznámky z terénu:
- Vyžaduje, aby byl na zámku povolen hygienický způsob otevírání.
- Selže, pokud již probíhá hygienické otevírání.
durationSecondsje volitelný; pokud je vynechán, použije se výchozí nastavení zámku.
Metadata a akce na domovské stránce
metadata.patch
Co to dělá:
- Ukládá metadata rozšíření používaná uživatelským rozhraním uzamčené stránky.
- Podporuje
unlockBlockersahomeActions. - Podporuje
homeActions[].intentpro chování hlubokých odkazů při otevření rozšíření.
Kdy použít:
- Vynutit podmínky odemknutí uzamčení relace, které vlastní vaše rozšíření.
- Přidejte na uzamykatelnou stránku rychlé akce, které otevírají vaše rozšíření s úmyslem.
- Směrujte uživatele přímo na konkrétní obrazovku/pracovní postup, když kliknou na akci Domů.
Koncový bod:
PATCH /api/extensions/sessions/:sessionId/metadata
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Příklad těla:
{
"unlockBlockers": ["Finish extension task"],
"homeActions": [
{
"slug": "tasks",
"title": "Tasks",
"description": "Open tasks panel",
"intent": {
"type": "open_panel",
"title": "Tasks",
"message": "Open tasks panel",
"payload": {
"panel": "regular-actions"
}
}
}
]
}
Poznámky z terénu:
unlockBlockers: seznam aktivních blokátorů odemčení relace uzamčení z vaší pobočky.- Můžete zahrnout více blokátorů najednou (až 25), jeden na každou nesplněnou podmínku.
- Odemknutí zůstává blokováno, dokud existuje jakýkoli blokátor napříč povolenými rozšířeními.
- Chastify agreguje blokátory ze všech rozšíření pro relaci uzamčení.
- Vaše rozšíření by mělo přidávat/odebírat vlastní blokátory pouze ve vlastních metadatech.
- Neodstraňujte blokátory z jiných rozšíření; své pole vymažte pouze tehdy, když jsou splněny vaše vlastní podmínky.
homeActions: tlačítka pro rychlé akce zobrazená v prostředí zámku.homeActions[].slug: stabilní ID pro vaši akci.homeActions[].title: štítek orientovaný pro uživatele.homeActions[].description: volitelný pomocný text.homeActions[].intent: Volitelná instrukce pro deeplink předaná vašemu rozšíření při otevření.- V uživatelském rozhraní rozšiřující karty se tyto akce zobrazují jako nabídka/seznam podle názvu akce (interně zadaného pomocí slug).
- Když uživatel na něj klikne, Chastify otevře rozšíření a předá:
homeActionSlughomeAction(vybraný objekt akce)intent(normalizovaný objekt záměru) takže vaše rozšíření může při načtení okamžitě přesměrovat na správné zobrazení/akci.
Intents: příklad vývojářské aplikace
Použijte tento vzor ve své rozšiřující aplikaci k reakci na intenty kliknutí na nabídku při načítání.
import { useEffect, useRef } from "react";
import { parseHashPayload, type IframeHashPayload } from "../lib/ChastifyBridge";
export function useHomeActionIntent(
payload: IframeHashPayload,
routeToPanel: (panel: string) => void,
showToast: (message: string) => void,
) {
const handledRef = useRef<string>("");
useEffect(() => {
const homeActionSlug = payload?.homeActionSlug ?? null;
if (!homeActionSlug) return;
// Prevent duplicate handling if component re-renders.
const key = `${payload.lockId || "lock"}:${homeActionSlug}`;
if (handledRef.current === key) return;
handledRef.current = key;
const intent = payload?.intent ?? payload?.homeAction?.intent ?? null;
if (!intent) return;
if (intent.type === "open_panel") {
const panel = String(intent.payload?.panel || "");
if (panel) routeToPanel(panel);
return;
}
if (intent.message) {
showToast(String(intent.message));
}
}, [payload, routeToPanel, showToast]);
}
// Example app bootstrap
const payload = parseHashPayload();
if (!payload) throw new Error("Missing iframe hash payload");
Co dělá tento příklad:
- Načte
homeActionSlug+intentz datové části hash iframe. - Zpracuje každé kliknutí pouze jednou na jeden slug zámku/akce.
- Směruje k panelu, pokud je záměr
open_panel. - U vlastních typů záměrů se vrací k zobrazení zprávy o záměru.
Příkaz zařízení
device.command
Co to dělá:
- Odešle příkaz pro řízení zařízení (pokud je pro danou relaci/zařízení podporován).
- Umožňuje vašemu rozšíření spouštět standardizované akce rázů/vibrací pomocí Chastify.
Kdy použít:
- Spouštění podporovaných příkazů pro rázy/vibrace z rozšiřující logiky.
- Vytváření interaktivních rozšiřujících prvků (hry, tresty, odměny, rutiny).
Koncový bod:
POST /api/extensions/sessions/:sessionId/device-command
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Příklad těla:
{
"command": "shock.start",
"params": {
"durationSeconds": 30,
"intensityPct": 50
}
}
Běžné příkazy:
shock.starts parametry:{ durationSeconds, intensityPct, message? }shock.stopvibration.starts parametry:{ durationSeconds, intensityPct, frequencyPct?, message? }vibration.stopall.stopshock.random.sets parametry:{ enabled, minIntensityPct?, maxIntensityPct?, message? }(pouze Lockink AA-A1012)shock.berserk.sets parametry:{ enabled, message? }(pouze Lockink AA-A1012)
Doporučený průtok:
- Při načítání zavolejte
session.get. - Načíst schopnosti zařízení z kódu
deviceControl.supportedCommands. - Vykreslovat pouze ovládací prvky pro podporované příkazy.
- Odešlete
device.commands ověřenými hodnotami. - Příznaky
activepro obnovení nebo důvěřování v odpovědi pro stav aktivního uživatelského rozhraní.
Pokyny k parametrům:
durationSeconds: server se přizpůsobuje bezpečným limitům (aktuální maximum zásad je 300 s).intensityPct: očekávaná procentuální hodnota (vstup ve stylu1-100, omezeno na straně serveru).frequencyPct: očekávaná procentuální hodnota (1-100) pro vibrační toky (uzavřená na straně serveru).- Pro náhodný režim zajistěte
minIntensityPct <= maxIntensityPct.
Příklad vzoru bezpečnějšího uživatelského rozhraní:
// 1) Get capabilities first
const session = await bridge.request("session.get", {});
const supported = new Set(session?.deviceControl?.supportedCommands ?? []);
// 2) Only call command if supported
if (supported.has("shock.start")) {
await bridge.request("device.command", {
command: "shock.start",
params: { durationSeconds: 30, intensityPct: 50 }
});
}
Důležité:
- Nejprve zavolejte
session.geta přečtěte si podporované příkazy. - Zobrazit ovládací prvky pouze pro příkazy, které jsou podporovány v aktuální relaci.
- Před odesláním parametrů příkazu ověřte vstupy uživatele.
device.commandvyžaduje oprávnění k zápisu (locks:write) pro rozšiřující relaci.- Elegantně zpracovat chyby mostu/serveru (
insufficient_scope, nepodporovaný příkaz, chyby validace).
Požadavky na rozšíření
Požadavky na rozšíření umožňují rozšíření definovat opakující se pravidla pro dokončení, která se zobrazují v uživatelském rozhraní dnešního postupu zámku, a mohou uvalit penalizaci, když nositel mine jedno okno.
Použijte to pro aktivity rozšíření důvěryhodných pro server, jako například:
- Dokončete 1 hádanku denně.
- Dokončete 3 kontroly každé 2 dny.
- Dokončete 5 rozšiřujících akcí týdně.
Konfigurační tvar
Požadavek je uložen v konfiguraci rozšiřující relace pod extensionRequirements:
{
"extensionRequirements": {
"enabled": true,
"metric": "completion",
"requiredCount": 1,
"cadence": {
"every": 1,
"unit": "day"
},
"punishment": {
"type": "add_time",
"seconds": 900,
"reason": "Missed extension requirement"
}
}
}
Pole:
enabled: zapíná/vypíná opakující se požadavek.metric: stabilní název čítače. Používejte jednoduché názvy, napříkladcompletion,winneboverification.requiredCount: kolik důvěryhodných událostí se musí v daném okně odehrát.cadence.every: velikost intervalu.cadence.unit:dayneboweek.- Časové pásmo okna je rozpoznáno parametrem Chastify z nakonfigurovaného
User.timezoneuživatele. Konfigurace rozšíření by neměla časové pásmo pevně zakódovat. punishment.type:none,add_time,freezenebopillory.punishment.seconds: délka trestu proadd_time,freezenebopillory.punishment.reason: volitelný důvod auditu/ladění.
Model pokroku
Průběh požadavku je důvěryhodný stav na straně serveru, nikoli stav lokálního iframe.
Nepoužívejte state.patch / state.put k označení požadavku jako dokončeného. Tyto akce jsou zápisy obecného stavu pouze na straně backendu, nikoli rozhraní API pro sledování průběhu požadavků. Průběh požadavku musí být zaznamenán až poté, co server ověří událost, která by se měla započítat.
Například:
- Rozšíření pro hádanku by mělo zaznamenávat průběh až poté, co server ověří podepsané spuštění a stav dokončení hádanky.
- Rozšíření ověření by mělo zaznamenávat průběh až poté, co server přijme odeslaný důkaz.
- Herní rozšíření by mělo zaznamenávat postup až poté, co backend ověří výsledek hry nebo důvěryhodnou událost dokončení.
Chování za běhu
Po konfiguraci:
- Na panelu zámků se může požadavek zobrazit v části Dnes v průběhu.
- Chastify sleduje pokrok v každé prodloužení a v každém kadenčním oknu.
- Úloha plánovaných požadavků vyhodnocuje dokončená okna a na každé zmeškané okno aplikuje nakonfigurovaný trest.
- Tresty jsou idempotentní pro každé okno, takže opakované pokusy nesčítají duplicitní tresty.
Doporučený tok požadavků
- Nakonfigurujte
extensionRequirementsv uživatelském rozhraní pro nastavení/konfiguraci rozšíření. - Při spuštění za běhu zavolejte
session.geta přečtěte si aktivní konfiguraci. - Dokončete aktivitu rozšíření v uživatelském rozhraní.
- Odešlete dokončení na důvěryhodnou backendovou trasu pro dané rozšíření.
- Nechte backend ověřit událost a zaznamenat průběh požadavků.
- Po dokončení aktualizujte lokální uživatelské rozhraní pomocí
session.get/state.get.
Důležité:
state.*považovat pouze za úložiště vlastněné rozšířením. Pro postup, pokusy, odměny a tresty používat vyhrazená důvěryhodná API.- Nedůvěřujte pouze příznaky dokončení klienta pro požadavky.
- Udržujte názvy
metricstabilní; změna metriky začne započítávat do jiného segmentu. - Chastify používá pro okna kadence nakonfigurované časové pásmo uživatele. Pokud u uživatele není k dispozici žádné časové pásmo, server se vrátí na
UTC. - Udržujte tresty v auditních protokolech omezené a vysvětlitelné.
Doporučené pořadí akcí
- Při spuštění zavolejte
session.get. - Stav se přečte pomocí
state.get. - V případě potřeby provádějte zápisy stavu z backendu pomocí
PUT/PATCH /state. - Spouštět akce zámku/zařízení pouze tehdy, pokud jsou podporovány a viditelné v uživatelském rozhraní.
- U aktivit podložených požadavky nahlaste dokončení důvěryhodné backendové trase.
- Obnovit lokální zobrazení po důležitých zápisech/akcích.