Hop til hovedindhold

API-eksempler

Brug denne side til at kopiere den rigtige anmodningsform for hvert udvidelsesflow.

  • Eksempler på iframe-broer bruger postMessage-handlinger såsom session.get, state.get og files.get.
  • Privilegerede eksempler bruger din egen udvidelsesbackend med Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY og x-chastify-main-token.
  • Send aldrig en Developer API-nøgle til en iframe eller browserkode.
info

Iframe-broen er til UI-bootstrap og lavrisiko-sessionshandlinger. Brug den til at læse kontekst, gemme udvidelsesejet tilstand og fortolke fil-URL'er.

caution

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 / keyholderLastSeenTimestamp returneres kun, hvis brugeren har showOnlineStatus !== false.
  • Hvis synlighed af onlinestatus er deaktiveret, er disse felter null.

Backend-udvidelsesflows

Disse eksempler viser det sikre produktionsmønster:

  1. Iframen læser mainToken og sessionId fra hash-nyttelasten.
  2. Iframen sender dem til din backend.
  3. Din backend validerer din egen spil-/opgave-/forretningstilstand.
  4. 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.

warning

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.

caution

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:

  • showPageOverlay er som standard false.
  • target er som standard wearer.
  • 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.get til 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:

  • durationSeconds er valgfri.
  • Hvis udeladt, er den nuværende standard 3600 sekunder (1 time).
  • Det accepterede interval er 60 til 86400 sekunder.

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:

  • name skal være pillory.
  • params.durationSeconds er påkrævet.
  • params.reason er 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:

  • name skal være pillory.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:

  • taskText er påkrævet.
  • points er valgfri og clamped på serversiden.
  • verificationRequired er som standard false.
  • durationSeconds er valgfri (0 betyder 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.
  • durationSeconds er 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 unlockBlockers og homeActions.
  • Understøtter homeActions[].intent for 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:
    • homeActionSlug
    • homeAction (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 + intent fra 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.start med parametrene: { durationSeconds, intensityPct, message? }
  • shock.stop
  • vibration.start med parametrene: { durationSeconds, intensityPct, frequencyPct?, message? }
  • vibration.stop
  • all.stop
  • shock.random.set med parametre: { enabled, minIntensityPct?, maxIntensityPct?, message? } (kun Lockink AA-A1012)
  • shock.berserk.set med parametre: { enabled, message? } (kun Lockink AA-A1012)

Anbefalet flow:

  1. Kald session.get ved indlæsning.
  2. Læs enhedsfunktioner fra deviceControl.supportedCommands.
  3. Gengiv kun kontrolelementer for understøttede kommandoer.
  4. Send device.command med validerede værdier.
  5. 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 i 1-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.get og 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.command kræ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, win eller verification.
  • requiredCount: hvor mange betroede hændelser der skal ske i vinduet.
  • cadence.every: intervalstørrelse.
  • cadence.unit: day eller week.
  • Vinduestidszonen opløses af Chastify fra brugerens konfigurerede User.timezone. Udvidelseskonfigurationen bør ikke hardcode en tidszone.
  • punishment.type: none, add_time, freeze eller pillory.
  • punishment.seconds: Strafvarighed for add_time, freeze eller pillory.
  • 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.
  1. Konfigurer extensionRequirements i brugergrænsefladen til opsætning/konfiguration af udvidelsen.
  2. Ved opstart under kørsel skal du kalde session.get og læse den aktive konfigurationsfil.
  3. Færdiggør udvidelsesaktiviteten i brugergrænsefladen.
  4. Send færdiggørelsen til en betroet backend-rute for den pågældende udvidelse.
  5. Lad backend'en validere fremskridtet for begivenheden og registreringskravet.
  6. Opdater den lokale brugergrænseflade med session.get / state.get efter 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.
  1. Kald session.get ved opstart.
  2. Læsetilstand med state.get.
  3. Udfør tilstandsskrivninger fra din backend med PUT/PATCH /state når det er nødvendigt.
  4. Kør kun låse-/enhedshandlinger, når de understøttes og er synlige i brugergrænsefladen.
  5. For kravbaserede aktiviteter skal færdiggørelsen rapporteres til en betroet backend-rute.
  6. Opdater den lokale visning efter vigtige skrivninger/handlinger.