API-eksempler
Brug denne side til at kopiere den rigtige anmodningsform for hvert udvidelsesflow.
- Eksempler på iframe-broer bruger
postMessage-handlinger såsomsession.get,state.getogfiles.get. - Privilegerede eksempler bruger din egen udvidelsesbackend med
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEYogx-chastify-main-token. - Send aldrig en Developer API-nøgle til en iframe eller browserkode.
Iframe-broen er til UI-bootstrap og lavrisiko-sessionshandlinger. Brug den til at læse kontekst, gemme udvidelsesejet tilstand og fortolke fil-URL'er.
Browserens iframe-kode er brugerstyret. Brug ikke iframe-bridge-anmodninger til at anvende/fjerne tid, fuldføre opgaver, rydde oplåsningsblokkere, uploade/slette runtime-filer, sende notifikationer, skrive logfiler eller kommandere enheder.
Anmodning og svarformat
Sikre iframe-brohandlinger sendes i denne broanmodningskuvert:
{
"type": "chastify:ext:req", // required
"v": 1, // protocol version
"id": "req-123", // your unique request id
"nonce": "from-iframe-hash",
"action": "session.get",
"payload": {}
}
Og du modtager:
{
"type": "chastify:ext:resp",
"v": 1,
"id": "req-123", // same id you sent
"ok": true,
"data": {}
}
Hvis ok er false, skal du markere error.code og error.message.
Eksempler, der kun er baseret på backend, bruger normale HTTPS-anmodninger fra din server. De sendes ikke via iframe-broen.
Session og kontekst
session.get
Brug dette først i næsten alle udvidelsesflow.
Hvad den gør:
- Bekræfter, at din bridge-forbindelse fungerer.
- Returnerer sessionskontekst (låsestatus, rolle, udvidelseskonfiguration, muligheder).
- Returnerer oplysninger om enhedsfunktioner, som din brugergrænseflade kan bruge, før din backend bliver bedt om at kalde
device.command.
Hvad det bruges til:
- Bootstrapping af din brugergrænseflade.
- Aktivering/deaktivering af funktioner baseret på rolle og tilladelser.
- Kontrol af understøttede enhedskommandoer før gengivelse af enhedskontroller.
Eksempel på handlingsnyttelast:
{
"action": "session.get",
"payload": {}
}
Eksempel på session.get-svaruddrag (kørselstidslåsdata):
{
"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
}
}
}
Privatlivsnoter:
wearerLastSeenTimestamp/keyholderLastSeenTimestampreturneres kun, hvis brugeren harshowOnlineStatus !== false.- Hvis synlighed af onlinestatus er deaktiveret, er disse felter
null.
Backend-udvidelsesflows
Disse eksempler viser det sikre produktionsmønster:
- Iframen læser
mainTokenogsessionIdfra hash-nyttelasten. - Iframen sender dem til din backend.
- Din backend validerer din egen spil-/opgave-/forretningstilstand.
- Din backend kalder Chastify med en app-scoped Developer API-nøgle plus
x-chastify-main-token.
Brug ikke sessionId alene som godkendelse. Behandl mainToken som en browser-synlig startkontekst, og behandl din Developer API-nøgle som en backend-kun-hemmelighed.
Din backend skal validere sin egen spil-/opgavetilstand, før Chastify kaldes. At sende mainToken og sessionId fra iframen identificerer kun den åbnede udvidelsessession; det beviser ikke, at brugeren har gennemført en udfordring.
Hent sessionskontekst sikkert
Din iframe kan bruge den sikre bro session.get til UI-bootstrap. Hvis din backend har brug for den samme kontekst, før en privilegeret handling anvendes, skal du hente den fra din backend med begge legitimationsoplysninger.
Iframe:
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
})
});
Din 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
});
});
Anvend tid fra en udvidelsesbackend
Browseren kan bede din backend om at anvende en belønning eller straf, men browseren må ikke afgøre, om handlingen er gyldig. Bekræft først handlingen på serversiden.
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());
});
Brug add_time til straffe og remove_time til belønninger.
Serververificeret spilfuldførelse
I spil som Simon Says skal du ikke stole på en klientrapporteret gevinst. Opret kørslen på serversiden, gem den forventede sekvens eller en hash af den, og verificer det indsendte input, før du kalder Chastify.
Et browser-synligt hukommelsesspil kan ikke bevise, at et menneske har spillet ærligt, fordi browseren skal modtage sekvensen for at gengive spillet. Serververifikation forhindrer stadig forfalskede Chastify-mutationer og lader din backend håndhæve løbs-id'er, udløb, sværhedsgrad, kadence, pointgivning og genspilningsbeskyttelse, før der anvendes belønninger eller straffe.
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 });
});
Det præcise skema til kørselslagring er dit. verifySessionLaunch skal kalde Chastify med din app-scopede Developer API-nøgle og x-chastify-main-token, før der gives tillid til sessionId. Den vigtige regel er, at Chastify-mutationer først sker, efter at din backend har verificeret opstarten og resultatet.
Planlagte krav
Din backend ejer tidsplaner, kadencetjek og bevisvalidering. Brug kun Chastify til at registrere betroede fremskridt eller opdatere oplåsningsblokkere, når din backend har besluttet, at kravet er opfyldt.
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
})
});
}
Aktuelle API'er til installerede udvidelser kræver et gyldigt iframe-starttoken i x-chastify-main-token; starttokens udløber i øjeblikket efter 10 timer. For planlagte job, der kører efter at det pågældende token udløber, skal du gemme dit eget ventende bevis og indsende status ved den næste gyldige udvidelsesstart, eller bruge et førsteparts-/indbygget serverflow designet til uovervåget baggrundsarbejde.
Behandl ikke planlagte job som betroede, bare fordi de kører på din server. Jobbet skal stadig have serversidebevis, kadencetjek, afspilningsbeskyttelse og en gyldig Chastify-godkendelsessti, før kravstatus registreres.
Notifikationer
notifications.custom
Brug dette fra din udvidelses backend til at sende en brugerdefineret udvidelsesnotifikation til bæreren, nøgleholderen eller begge.
Endepunkt:
POST /api/extensions/sessions/:sessionId/notifications/custom
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Eksempel på brødtekst:
{
"title": "Extension Reminder",
"message": "Your next challenge is ready.",
"showPageOverlay": false,
"target": "both"
}
Noter:
showPageOverlayer som standardfalse.targeter som standardwearer.- API'en opretter notifikationstypen
extension_app_message.
Udvidelsesstatus
Udvidelsesstatus er dine udvidelsesejede JSON-data for den aktuelle låsesession.
Tilstandsskrivninger er kun til backend og kræver en app-scoped Developer API-nøgle plus sessionen mainToken. Iframes kan læse tilstand med state.get, men de kan ikke skrive tilstand direkte.
state.put
Hvad den gør:
- Erstatter hele tilstandsobjektet med det nye
data-objekt. - Kræver backend-legitimationsoplysninger.
Hvornår skal det bruges:
- Første lagring.
- Fuld overskrivning, når du allerede har den komplette nye tilstand.
Eksempel:
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"
}
}'
Feltnoter:
payload.data: enhver gyldig JSON-værdi/objekt, som din udvidelse har brug for.- Avoid Mongo-unsafe key names (
$prefix or keys containing.). - Tilstanden er sessionsbegrænset og størrelsesbegrænset af udvidelsesappens
stateMaxBytes, som standard er 64 KiB. - Gem fil-id'er i tilstand, ikke binære filer eller signerede URL'er. Brug
files.gettil at opdatere signerede URL'er, før medier gengives.
state.patch
Hvad den gør:
- Anvender en JSON-fletningsrettelse på den eksisterende tilstand.
- Kun ændrede nøgler skal sendes.
- Kræver backend-legitimationsoplysninger.
Hvornår skal det bruges:
- Trinvise opdateringer fra brugerinteraktioner.
- Opdaterer ét felt uden at sende alt igen.
Eksempel:
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
Hvad den gør:
- Læser den aktuelle udvidelsesstatus.
- Tilgængelig via iframe-broen.
Hvornår skal det bruges:
- Ved indlæsning af iframe.
- Efter skrivninger, hvis du vil synkronisere den lokale brugergrænseflade igen.
Eksempel:
{
"action": "state.get",
"payload": {}
}
Fillagring
Brug files.* til binære medier såsom puslespilbilleder, genererede forhåndsvisninger eller udfordringsbilleder. Gem den returnerede file.id i backend-skrevet tilstand eller i din egen database. Render med file.signedUrl, og opdater den signerede URL med files.get, når iframen indlæses senere.
Opsætningsskærme, der kører før en lås/session eksisterer, bruger trinvise uploads i stedet for files.upload. Trinvise filer er midlertidige, indtil udvidelseskonfigurationen gemmes med en provider: "chastify_storage"- og fileId-reference. Chastify gør automatisk krav på disse filer ved lås/skabelonlagring; der er intet separat kravkald på browsersiden.
Eksempel på opdeling af tilstand/fil fra din backend:
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"
}
}'
Senere, løs billedet før visning:
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
Tjek dette, før du viser uploadkontroller.
{
"action": "files.capabilities",
"payload": {}
}
Køretid files.upload
Upload af runtime-filer ændrer sessionsdata for udvidelser, så det er ikke en iframe-bridge-kommando. Upload runtime-filer fra din backend med en app-scoped Developer API-nøgle og x-chastify-main-token.
files.get
Opdater én signeret R2-URL fra et stabilt fil-id.
{
"action": "files.get",
"payload": {
"fileId": "file_record_id"
}
}
files.list
{
"action": "files.list",
"payload": {}
}
Runtime files.delete er også kun til backend af samme grund som upload.
Lås handlinger
Tilføj tid
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Hvad den gør:
- Tilføjer eller fjerner tid fra nedtællingen til låsen afhængigt af
deltaSeconds.
Hvornår skal det bruges:
- Belønnings-/strafknapper.
- Spilresultater (sejr tilføjer tid, tab fjerner tid).
Eksempel:
{
"name": "add_time",
"params": 300 // +300 sec = +5 minutes
}
Feltnoter:
- Positiv værdi tilføjer tid.
- Negativ værdi fjerner tid (hvis det er tilladt af serverreglerne).
Fryse
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Hvad den gør:
- Fryser låseprogressionen i en periode.
Hvornår skal det bruges:
- Nedkølingsmekanik.
- Belønningskontrolpunkter.
Eksempel:
{
"name": "freeze",
"params": { "durationSeconds": 120 }
}
Du kan også kalde det uden durationSeconds:
{
"name": "freeze",
"params": {}
}
Feltnoter:
durationSecondser valgfri.- Hvis udeladt, er den nuværende standard
3600sekunder (1 time). - Det accepterede interval er
60til86400sekunder.
Optø
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Hvad den gør:
- Afslutter aktiv frysning og genoptager normal timerfunktion.
Hvornår skal det bruges:
- Manuel tilsidesættelse i udvidelsesarbejdsgange.
- "Annuller frysning"-kontroller.
Eksempel:
{
"name": "unfreeze",
"params": {}
}
Gabestok
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Hvad den gør:
- Starter en gabestokperiode for den aktive låsesession.
Hvornår skal det bruges:
- Strafmekanismer efter mislykkede opgaver/udfordringer.
- Eskaleringsflows, der midlertidigt begrænser låseinteraktion.
Eksempel:
{
"name": "pillory",
"params": {
"durationSeconds": 600,
"reason": "Missed scheduled check-in"
}
}
Feltnoter:
nameskal værepillory.params.durationSecondser påkrævet.params.reasoner valgfri.- Kræver at gabestok aktiveres i sessionskonfigurationen.
Endegabestok
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Hvad den gør:
- Afslutter den aktuelle aktive gabestoksession med det samme.
Eksempel:
{
"name": "pillory.end",
"params": {}
}
Feltnoter:
nameskal værepillory.end.- Fejler med
pillory_not_active, hvis låsen ikke i øjeblikket er i gabestok.
Tildel opgave
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Hvad den gør:
- Opretter en aktiv opgavekørsel for brugeren fra udvidelseslogik.
- Kan tilsidesætte en allerede åben opgavekørsel.
Eksempel:
{
"name": "task.assign",
"params": {
"taskText": "Clean your room",
"points": 10,
"verificationRequired": true,
"durationSeconds": 1800
}
}
Feltnoter:
taskTexter påkrævet.pointser valgfri og clamped på serversiden.verificationRequireder som standardfalse.durationSecondser valgfri (0betyder intet timerkrav).- Kræver at Opgaver-modulet er aktiveret på låsen.
Start opgavetimeren
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Hvad den gør:
- Starter eller genstarter nedtællingsvinduet for den aktuelt aktive tidsbestemte opgave.
Eksempel:
{
"name": "task.start_timer",
"params": {}
}
Feltnoter:
- Kræver en aktiv opgavekørsel.
- Mislykkes, hvis den aktuelle opgave ikke har nogen konfigureret varighed.
Færdiggør opgaven
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Hvad den gør:
- Markerer den aktive opgavekørsel som fuldført eller mislykket.
Eksempel (succes):
{
"name": "task.complete",
"params": {
"successful": true
}
}
Eksempel (fejl):
{
"name": "task.complete",
"params": {
"successful": false,
"reason": "Did not finish in time"
}
}
Udløs midlertidig åbning
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Hvad den gør:
- Starter et midlertidigt hygiejneåbningsvindue fra udvidelseslogik.
Eksempel:
{
"name": "hygienic_unlock.start",
"params": {
"durationSeconds": 900
}
}
Feltnoter:
- Kræver at Hygiejnisk åbning er aktiveret på låsen.
- Mislykkes, hvis en hygiejneåbning allerede er i gang.
durationSecondser valgfri; standardlås bruges, når den udelades.
Metadata og starthandlinger
metadata.patch
Hvad den gør:
- Gemmer udvidelsesmetadata, der bruges af låsesidens brugergrænseflade.
- Understøtter
unlockBlockersoghomeActions. - Understøtter
homeActions[].intentfor dybe links, når udvidelsen åbnes.
Hvornår skal det bruges:
- Håndhæv oplåsningsbetingelser for låsesessioner, der ejes af din udvidelse.
- Tilføj hurtige handlinger på låsesiden, der åbner din udvidelse med vilje.
- Send brugere direkte til en bestemt skærm/arbejdsgang, når de klikker på en handling på startsiden.
Endepunkt:
PATCH /api/extensions/sessions/:sessionId/metadata
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Eksempel på brødtekst:
{
"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"
}
}
}
]
}
Feltnoter:
unlockBlockers: liste over aktive blokeringer af låsesessioner fra din lokalnummer.- Du kan inkludere flere blokkere på én gang (op til 25), én pr. udefyldt betingelse.
- Oplåsning forbliver blokeret, så længe der findes en blokering på tværs af aktiverede udvidelser.
- Chastify samler blokkere fra alle udvidelser for låsesessionen.
- Din udvidelse bør kun tilføje/fjerne sine egne blokkere i sine egne metadata.
- Fjern ikke blokkere fra andre udvidelser; fjern kun dit array, når dine egne betingelser er opfyldt.
homeActions: Hurtigfunktionsknapper vises i låseoplevelsen.homeActions[].slug: stabilt id for din handling.homeActions[].title: brugervendt etiket.homeActions[].description: valgfri hjælpetekst.homeActions[].intent: valgfri instruktion til dybt link sendt til din udvidelse ved åbning.- I brugergrænsefladen på udvidelseskortet vises disse handlinger som en menu/liste efter handlingstitel (internt indtastet af en slug).
- Når en bruger klikker på en, åbner Chastify udvidelsen og sender:
homeActionSlughomeAction(valgt handlingsobjekt)intent(normaliseret intent-objekt) så din udvidelse straks kan dirigere til den korrekte visning/handling ved indlæsning.
Intents: eksempel på udviklerapp
Brug dette mønster i din udvidelsesapp til at reagere på menuklik-intentioner ved indlæsning.
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");
Hvad dette eksempel gør:
- Læser
homeActionSlug+intentfra iframe hash-nyttelasten. - Håndterer hvert klik kun én gang pr. lås/handlingsslug.
- Ruter til et panel, når intentionen er
open_panel. - Går tilbage til at vise en intent-meddelelse for brugerdefinerede intent-typer.
Enhedskommando
device.command
Hvad den gør:
- Sender en enhedskontrolkommando (hvis det understøttes for den pågældende session/enhed).
- Lader din udvidelse udløse standardiserede stød-/vibrationshandlinger via Chastify.
Hvornår skal det bruges:
- Udløser understøttede stød-/vibrationskommandoer fra udvidelseslogik.
- Opbygning af interaktive udvidelsesfunktioner (spil, straffe, belønninger, rutiner).
Endepunkt:
POST /api/extensions/sessions/:sessionId/device-command
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Eksempel på brødtekst:
{
"command": "shock.start",
"params": {
"durationSeconds": 30,
"intensityPct": 50
}
}
Almindelige kommandoer:
shock.startmed parametrene:{ durationSeconds, intensityPct, message? }shock.stopvibration.startmed parametrene:{ durationSeconds, intensityPct, frequencyPct?, message? }vibration.stopall.stopshock.random.setmed parametre:{ enabled, minIntensityPct?, maxIntensityPct?, message? }(kun Lockink AA-A1012)shock.berserk.setmed parametre:{ enabled, message? }(kun Lockink AA-A1012)
Anbefalet flow:
- Kald
session.getved indlæsning. - Læs enhedsfunktioner fra
deviceControl.supportedCommands. - Gengiv kun kontrolelementer for understøttede kommandoer.
- Send
device.commandmed validerede værdier. - Opdater eller tillidssvar
active-flag for live UI-tilstand.
Parametervejledning:
durationSeconds: Serveren begrænser sig til sikre grænser (nuværende politikmaksimum er 300 sekunder).intensityPct: forventet procentværdi (input i1-100-stil, begrænset på serversiden).frequencyPct: forventet procentværdi (1-100) for vibrationsflows (fastklemt på serversiden).- For tilfældig tilstand, sørg for
minIntensityPct <= maxIntensityPct.
Eksempel på et sikrere brugergrænseflademønster:
// 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 }
});
}
Vigtig:
- Kald først
session.getog læs understøttede kommandoer. - Vis kun kontrolelementer for kommandoer, der understøttes i den aktuelle session.
- Valider brugerinput før afsendelse af kommandoparametre.
device.commandkræver skrivetilladelse (locks:write) til udvidelsessessionen.- Håndter bro-/serverfejl korrekt (
insufficient_scope, ikke-understøttet kommando, valideringsfejl).
Krav til forlængelse
Udvidelseskrav lader en udvidelse definere tilbagevendende fuldførelsesregler, der vises i låsens Today Progress UI, og kan anvende en straf, når brugeren misser et vindue.
Brug dette til server-tillid til udvidelsesaktiviteter såsom:
- Løs 1 puslespil om dagen.
- Udfør 3 check-ins hver 2. dag.
- Udfør 5 forlængelseshandlinger om ugen.
Konfigurationsform
Kravet er gemt i konfigurationen af udvidelsessessionen under extensionRequirements:
{
"extensionRequirements": {
"enabled": true,
"metric": "completion",
"requiredCount": 1,
"cadence": {
"every": 1,
"unit": "day"
},
"punishment": {
"type": "add_time",
"seconds": 900,
"reason": "Missed extension requirement"
}
}
}
Felter:
enabled: aktiverer/deaktiverer det tilbagevendende krav.metric: Stabilt tællernavn. Brug simple navne som f.eks.completion,winellerverification.requiredCount: hvor mange betroede hændelser der skal ske i vinduet.cadence.every: intervalstørrelse.cadence.unit:dayellerweek.- Vinduestidszonen opløses af Chastify fra brugerens konfigurerede
User.timezone. Udvidelseskonfigurationen bør ikke hardcode en tidszone. punishment.type:none,add_time,freezeellerpillory.punishment.seconds: Strafvarighed foradd_time,freezeellerpillory.punishment.reason: valgfri revisions-/fejlfindingsårsag.
Fremskridtsmodel
Kravstatus er den betroede serversidetilstand, ikke den lokale iframe-tilstand.
Brug ikke state.patch / state.put til at markere et krav som fuldført. Disse handlinger er kun generelle tilstandsskrivninger til backend, ikke API'er til kravstatus. Kravstatus må først registreres, når serveren validerer den hændelse, der skal tælle.
For eksempel:
- En puslespiludvidelse bør først registrere fremskridt, når serveren har valideret den signerede puslespilskørsel og fuldført tilstand.
- En verifikationsudvidelse bør først registrere status, når serveren accepterer det indsendte bevis.
- En spiludvidelse bør kun registrere fremskridt, efter at backend'en validerer spilresultatet eller den betroede fuldførelseshændelse.
Køretidsadfærd
Når konfigureret:
- Låsedashboardet kan vise kravet i Dagens status.
- Chastify sporer fremskridt pr. forlængelsessession og pr. kadencevindue.
- Det planlagte kravjob evaluerer fuldførte vinduer og anvender den konfigurerede straf én gang pr. mistet vindue.
- Straffe er idempotente pr. vindue, så genforsøg stabler ikke duplikerede straffe.
Anbefalet kravflow
- Konfigurer
extensionRequirementsi brugergrænsefladen til opsætning/konfiguration af udvidelsen. - Ved opstart under kørsel skal du kalde
session.getog læse den aktive konfigurationsfil. - Færdiggør udvidelsesaktiviteten i brugergrænsefladen.
- Send færdiggørelsen til en betroet backend-rute for den pågældende udvidelse.
- Lad backend'en validere fremskridtet for begivenheden og registreringskravet.
- Opdater den lokale brugergrænseflade med
session.get/state.getefter færdiggørelse.
Vigtig:
- Behandl
state.*kun som udvidelsesejet lagerplads. Brug dedikerede, betroede API'er til fremskridt, forsøg, belønninger og straffe. - Stol ikke på klientens fuldførelsesflag for krav.
- Hold
metric-navnene stabile; ændring af metrikken begynder at tælle i en anden kategori. - Chastify bruger brugerens konfigurerede tidszone til kadencevinduer. Hvis der ikke er nogen tidszone tilgængelig for brugeren, vender serveren tilbage til
UTC. - Hold straffe begrænsede og forklarlige i revisionslogge.
Anbefalet handlingsrækkefølge
- Kald
session.getved opstart. - Læsetilstand med
state.get. - Udfør tilstandsskrivninger fra din backend med
PUT/PATCH /statenår det er nødvendigt. - Kør kun låse-/enhedshandlinger, når de understøttes og er synlige i brugergrænsefladen.
- For kravbaserede aktiviteter skal færdiggørelsen rapporteres til en betroet backend-rute.
- Opdater den lokale visning efter vigtige skrivninger/handlinger.