API-exempel
Använd den här sidan för att kopiera rätt begärandeform för varje tilläggsflöde.
- Exempel på iframe-bryggor använder
postMessage-åtgärder somsession.get,state.getochfiles.get. - Privilegierade exempel använder din egen tilläggs-backend med
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEYochx-chastify-main-token. - Skicka aldrig en Developer API-nyckel till iframe eller webbläsarkod.
Iframe-bryggan är till för UI-bootstrap och sessionsåtgärder med låg risk. Använd den för att läsa kontext, lagra tilläggsägt tillstånd och matcha fil-URL:er.
Webbläsarens iframe-kod styrs av användaren. Använd inte iframe-bryggförfrågningar för att tillämpa/ta bort tid, slutföra uppgifter, rensa upplåsningsblockerare, ladda upp/ta bort runtime-filer, skicka aviseringar, skriva loggar eller styra enheter.
Format för begäran och svar
Säkra iframe-bryggåtgärder skickas inuti detta bryggförfrågningskuvert:
{
"type": "chastify:ext:req", // required
"v": 1, // protocol version
"id": "req-123", // your unique request id
"nonce": "from-iframe-hash",
"action": "session.get",
"payload": {}
}
Och du får:
{
"type": "chastify:ext:resp",
"v": 1,
"id": "req-123", // same id you sent
"ok": true,
"data": {}
}
Om ok är false, markera error.code och error.message.
Exempel som endast används i backend använder vanliga HTTPS-förfrågningar från din server. De skickas inte via iframe-bryggan.
Session och kontext
session.get
Använd detta först i nästan varje tilläggsflöde.
Vad den gör:
- Verifierar att din brygganslutning fungerar.
- Returnerar sessionskontext (låst tillstånd, roll, tilläggskonfiguration, funktioner).
- Returnerar information om enhetsfunktioner som ditt användargränssnitt kan använda innan din backend ber att anropa
device.command.
Vad det används till:
- Bootstrapping av ditt användargränssnitt.
- Aktivera/inaktivera funktioner baserat på roll och behörigheter.
- Kontrollerar enhetskommandon som stöds innan enhetskontroller renderas.
Exempel på åtgärdsnyttolast:
{
"action": "session.get",
"payload": {}
}
Exempel på session.get-svarsutdrag (låsdata vid körning):
{
"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
}
}
}
Sekretessmeddelanden:
wearerLastSeenTimestamp/keyholderLastSeenTimestampreturneras endast om användaren harshowOnlineStatus !== false.- Om synligheten av onlinestatus är inaktiverad är dessa fält
null.
Flöden för backend-tillägg
Dessa exempel visar det säkra produktionsmönstret:
- Iframe-rutan läser
mainTokenochsessionIdfrån hash-nyttolasten. - Iframen skickar dem till din backend.
- Din backend validerar ditt eget spel-/uppgifts-/verksamhetsstatus.
- Din backend anropar Chastify med en app-scope-baserad Developer API-nyckel plus
x-chastify-main-token.
Använd inte enbart sessionId som autentisering. Behandla mainToken som en startkontext som är synlig för webbläsaren och behandla din Developer API-nyckel som en hemlighet endast för backend.
Din backend måste validera sitt eget spel-/uppgiftsstatus innan Chastify anropas. Att skicka mainToken och sessionId från iframe identifierar endast den öppnade tilläggssessionen; det bevisar inte att användaren har slutfört en utmaning.
Hämta sessionskontext säkert
Din iframe kan använda den säkra bryggan session.get för UI-bootstrap. Om din backend behöver samma kontext innan en privilegierad åtgärd tillämpas, hämta den från din backend med båda autentiseringsuppgifterna.
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
});
});
Tillämpa tid från en tilläggsbackend
Webbläsaren kan be din server att tillämpa en belöning eller ett straff, men webbläsaren får inte avgöra om åtgärden är giltig. Verifiera åtgärden på serversidan först.
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());
});
Använd add_time för straff och remove_time för belöningar.
Serververifierad spelavslutning
För spel som Simon Says, lita inte på en klientrapporterad vinst. Skapa körningen på serversidan, lagra den förväntade sekvensen eller en hash av den och verifiera den inskickade indatan innan du anropar Chastify.
Ett minnesspel som är synligt i webbläsaren kan inte bevisa att en människa spelat ärligt, eftersom webbläsaren måste ta emot sekvensen för att rendera spelet. Serververifiering förhindrar fortfarande förfalskade Chastify-mutationer och låter din backend tillämpa kör-ID:n, utgångstid, svårighetsgrad, kadens, poängsättning och omspelningsskydd innan belöningar eller straff tillämpas.
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 exakta schemat för körlagring är ditt. verifySessionLaunch ska anropa Chastify med din app-scope Developer API-nyckel och x-chastify-main-token innan sessionId litas på. Den viktiga regeln är att Chastify-mutationer endast sker efter att din backend har verifierat starten och resultatet.
Schemalagda krav
Din backend äger scheman, kadenskontroller och bevisvalidering. Använd Chastify endast för att registrera betrodda framsteg eller uppdatera upplåsningsblockerare efter att din backend har bestämt att kravet är uppfyllt.
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
})
});
}
Nuvarande installerade API:er för sessioner med tillägg kräver en giltig iframe-starttoken i x-chastify-main-token; starttokens upphör för närvarande att gälla efter 10 timmar. För schemalagda jobb som körs efter att den token upphör att gälla, lagra ditt eget väntande bevis och skicka in förloppet vid nästa giltiga tilläggsstart, eller använd ett förstaparts-/inbyggt serverflöde som är utformat för obevakat bakgrundsarbete.
Behandla inte schemalagda jobb som betrodda bara för att de körs på din server. Jobbet behöver fortfarande serversidesbekräftelse, kadenskontroller, replayskydd och en giltig Chastify-auktoriseringssökväg innan kravförloppet registreras.
Aviseringar
notifications.custom
Använd detta från din tilläggsserver för att skicka en anpassad tilläggsavisering till bäraren, nyckelinnehavaren eller båda.
Slutpunkt:
POST /api/extensions/sessions/:sessionId/notifications/custom
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Exempel på brödtext:
{
"title": "Extension Reminder",
"message": "Your next challenge is ready.",
"showPageOverlay": false,
"target": "both"
}
Anteckningar:
showPageOverlayär som standardfalse.targetär som standardwearer.- API:et skapar aviseringstypen
extension_app_message.
Tilläggsstatus
Tilläggets status är dina tilläggsägda JSON-data för den aktuella låssessionen.
Tillståndsskrivningar är endast för backend-servern och kräver en app-scope Developer API-nyckel plus sessionen mainToken. Iframes kan läsa tillstånd med state.get, men de kan inte skriva tillstånd direkt.
state.put
Vad den gör:
- Ersätter hela tillståndsobjektet med det nya
data-objektet. - Kräver backend-inloggningsuppgifter.
När ska man använda:
- Första sparningen.
- Fullständig överskrivning när du redan har det helt nya tillståndet.
Exempel:
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"
}
}'
Fältanteckningar:
payload.data: valfritt giltigt JSON-värde/objekt som ditt tillägg behöver.- Avoid Mongo-unsafe key names (
$prefix or keys containing.). - Tillståndet är sessionsbaserat och storleksbegränsat av tilläggsappens
stateMaxBytes, med standardinställningen 64 KiB. - Lagra fil-ID:n i tillstånd, inte binära filer eller signerade URL:er. Använd
files.getför att uppdatera signerade URL:er innan media renderas.
state.patch
Vad den gör:
- Tillämpar en JSON-sammanslagningspatch på befintligt tillstånd.
- Endast ändrade nycklar behöver skickas.
- Kräver backend-inloggningsuppgifter.
När ska man använda:
- Stegvisa uppdateringar från användarinteraktioner.
- Uppdaterar ett fält utan att skicka allt om.
Exempel:
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
Vad den gör:
- Läser det aktuella tillståndet för tillägget.
- Tillgänglig via iframe-bryggan.
När ska man använda:
- Vid inläsning av iframe.
- Efter skrivningar, om du vill synkronisera det lokala användargränssnittet igen.
Exempel:
{
"action": "state.get",
"payload": {}
}
Fillagring
Använd files.* för binära medier som pusselbilder, genererade förhandsvisningar eller utmaningsfoton. Lagra den returnerade file.id i backend-skrivet tillstånd eller i din egen databas. Rendera med file.signedUrl och uppdatera den signerade URL:en med files.get när iframe-filen laddas senare.
Installationsskärmar som körs innan ett lås/en session existerar använder etappvisa uppladdningar istället för files.upload. Etappvisa filer är tillfälliga tills tilläggskonfigurationen sparas med en provider: "chastify_storage"- och fileId-referens. Chastify gör anspråk på dessa filer automatiskt vid sparning av lås/mall; det finns inget separat anspråksanrop på webbläsarsidan.
Exempel på delningsläge/fil från 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"
}
}'
Lös sedan upp bilden innan 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
Kontrollera detta innan du visar uppladdningskontroller.
{
"action": "files.capabilities",
"payload": {}
}
Körtid files.upload
Uppladdning av runtime-filer muterar tilläggssessionsdata, så det är inte ett iframe-bryggkommando. Ladda upp runtime-filer från din backend med en app-scoped Developer API-nyckel och x-chastify-main-token.
files.get
Uppdatera en signerad R2-URL från ett stabilt fil-ID.
{
"action": "files.get",
"payload": {
"fileId": "file_record_id"
}
}
files.list
{
"action": "files.list",
"payload": {}
}
Runtime files.delete är också endast backend-baserad av samma anledning som uppladdning.
Låsåtgärder
Lägg till tid
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Vad den gör:
- Lägger till eller tar bort tid från låsnedräkningen beroende på
deltaSeconds.
När ska man använda:
- Belönings-/straffknappar.
- Matchresultat (vinst lägger till tid, förlust lägger till tid).
Exempel:
{
"name": "add_time",
"params": 300 // +300 sec = +5 minutes
}
Fältanteckningar:
- Positivt värde ger mer tid.
- Negativt värde tar bort tid (om det är tillåtet enligt serverreglerna).
Frysa
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Vad den gör:
- Fryser låsprogressionen under en viss tid.
När ska man använda:
- Nedkylningsmekanik.
- Belöningskontrollpunkter.
Exempel:
{
"name": "freeze",
"params": { "durationSeconds": 120 }
}
Du kan också anropa det utan durationSeconds:
{
"name": "freeze",
"params": {}
}
Fältanteckningar:
durationSecondsär valfritt.- Om det utelämnas är standardvärdet
3600sekunder (1 timme). - Det accepterade intervallet är
60till86400sekunder.
Tina upp
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Vad den gör:
- Avslutar aktiv frysning och återgår till normalt timerbeteende.
När ska man använda:
- Manuell åsidosättning i tilläggsarbetsflöden.
- Kontrollerna för "Avbryt frysning".
Exempel:
{
"name": "unfreeze",
"params": {}
}
Skampålen
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Vad den gör:
- Startar en skampåleperiod för den aktiva låssessionen.
När ska man använda:
- Straffmekanik efter misslyckade uppgifter/utmaningar.
- Eskaleringsflöden som tillfälligt begränsar låsinteraktion.
Exempel:
{
"name": "pillory",
"params": {
"durationSeconds": 600,
"reason": "Missed scheduled check-in"
}
}
Fältanteckningar:
namemåste varapillory.params.durationSecondskrävs.params.reasonär valfritt.- Kräver att skampålen är aktiverad i sessionskonfigurationen.
Ändskalpen
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Vad den gör:
- Avslutar den aktuella aktiva skampålssessionen omedelbart.
Exempel:
{
"name": "pillory.end",
"params": {}
}
Fältanteckningar:
namemåste varapillory.end.- Misslyckas med
pillory_not_activeom låset inte för närvarande är i skampålen.
Tilldela uppgift
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Vad den gör:
- Skapar en aktiv uppgift som körs för bäraren från tilläggslogik.
- Kan åsidosätta en redan öppen uppgiftskörning.
Exempel:
{
"name": "task.assign",
"params": {
"taskText": "Clean your room",
"points": 10,
"verificationRequired": true,
"durationSeconds": 1800
}
}
Fältanteckningar:
taskTextkrävs.pointsär valfritt och clampat på serversidan.verificationRequiredär som standardfalse.durationSecondsär valfritt (0betyder att ingen timer krävs).- Kräver att modulen Uppgifter är aktiverad på låset.
Starta uppgiftstimern
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Vad den gör:
- Startar eller startar om nedräkningsfönstret för den aktiva tidsinställda uppgiften.
Exempel:
{
"name": "task.start_timer",
"params": {}
}
Fältanteckningar:
- Kräver en aktiv uppgiftskörning.
- Misslyckas om den aktuella uppgiften inte har någon konfigurerad varaktighet.
Slutför uppgiften
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Vad den gör:
- Markerar den aktiva uppgiftskörningen som slutförd eller misslyckad.
Exempel (framgång):
{
"name": "task.complete",
"params": {
"successful": true
}
}
Exempel (misslyckad):
{
"name": "task.complete",
"params": {
"successful": false,
"reason": "Did not finish in time"
}
}
Utlös tillfällig öppning
Slutpunkt: POST /api/extensions/sessions/:sessionId/action
Vad den gör:
- Startar ett tillfälligt hygienöppningsfönster från tilläggslogik.
Exempel:
{
"name": "hygienic_unlock.start",
"params": {
"durationSeconds": 900
}
}
Fältanteckningar:
- Kräver att hygienisk öppning är aktiverad på låset.
- Misslyckas om en hygienöppning redan pågår.
durationSecondsär valfritt; låsstandard används när det utelämnas.
Metadata och startåtgärder
metadata.patch
Vad den gör:
- Lagrar tilläggsmetadata som används av låssidans användargränssnitt.
- Stöder
unlockBlockersochhomeActions. - Stöder
homeActions[].intentför djuplänksbeteende när tillägget öppnas.
När ska man använda:
- Tillämpa upplåsningsvillkor för låssessioner som ägs av din anknytning.
- Lägg till snabba åtgärder på låssidan som öppnar ditt tillägg med avsikt.
- Leda användare direkt till en specifik skärm/arbetsflöde när de klickar på en startåtgärd.
Slutpunkt:
PATCH /api/extensions/sessions/:sessionId/metadata
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Exempel på brödtext:
{
"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"
}
}
}
]
}
Fältanteckningar:
unlockBlockers: lista över aktiva blockerare för upplåsning av låssessioner från din anknytning.- Du kan inkludera flera blockerare samtidigt (upp till 25), en per ouppfyllt villkor.
- Upplåsningen förblir blockerad så länge det finns blockeringar för aktiverade tillägg.
- Chastify aggregerar blockerare från alla tillägg för låssessionen.
- Ditt tillägg ska bara lägga till/ta bort sina egna blockerare i sina egna metadata.
- Rensa inte blockerare från andra tillägg; rensa din array endast när dina egna villkor är uppfyllda.
homeActions: snabbknappar visas i låsfunktionen.homeActions[].slug: stabilt ID för din åtgärd.homeActions[].title: användarvänd etikett.homeActions[].description: valfri hjälptext.homeActions[].intent: valfri djuplänksinstruktion skickas till din anknytning när den öppnas.- I tilläggskortets användargränssnitt visas dessa åtgärder som en meny/lista efter åtgärdstitel (internt knappad med slug).
- När en användare klickar på en, öppnar Chastify tillägget och skickar:
homeActionSlughomeAction(vald åtgärdsobjekt)intent(normaliserat intent-objekt) så att ditt tillägg omedelbart kan dirigera till rätt vy/åtgärd vid laddning.
Intents: exempel på utvecklarapp
Använd det här mönstret i din tilläggsapp för att reagera på menyklicksintentioner vid laddning.
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");
Vad det här exemplet gör:
- Läser
homeActionSlug+intentfrån iframe-hashnyttolasten. - Hanterar varje klick endast en gång per lås-/åtgärdsslug.
- Dirigerar till en panel när avsikten är
open_panel. - Återgår till att visa ett intent-meddelande för anpassade intent-typer.
Enhetskommando
device.command
Vad den gör:
- Skickar ett enhetskontrollkommando (om det stöds för den sessionen/enheten).
- Låter din förlängning utlösa standardiserade stöt-/vibrationsåtgärder via Chastify.
När ska man använda:
- Utlöser stöt-/vibrationskommandon som stöds från tilläggslogik.
- Bygga interaktiva tilläggsfunktioner (spel, straff, belöningar, rutiner).
Slutpunkt:
POST /api/extensions/sessions/:sessionId/device-command
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Exempel på brödtext:
{
"command": "shock.start",
"params": {
"durationSeconds": 30,
"intensityPct": 50
}
}
Vanliga kommandon:
shock.startmed parametrarna:{ durationSeconds, intensityPct, message? }shock.stopvibration.startmed parametrarna:{ durationSeconds, intensityPct, frequencyPct?, message? }vibration.stopall.stopshock.random.setmed parametrarna:{ enabled, minIntensityPct?, maxIntensityPct?, message? }(endast Lockink AA-A1012)shock.berserk.setmed parametrarna:{ enabled, message? }(endast Lockink AA-A1012)
Rekommenderat flöde:
- Anropa
session.getvid laddning. - Läs enhetsfunktioner från
deviceControl.supportedCommands. - Rendera endast kontroller för kommandon som stöds.
- Skicka
device.commandmed validerade värden. - Uppdatera eller lita på svaret
active-flaggor för live UI-tillstånd.
Parametervägledning:
durationSeconds: servern når säkra gränser (nuvarande maxgräns för policyn är 300s).intensityPct: förväntat procentvärde (indata i1-100-stil, låst på serversidan).frequencyPct: förväntat procentvärde (1-100) för vibrationsflöden (fastlåst på serversidan).- För slumpmässigt läge, se till att
minIntensityPct <= maxIntensityPctär aktiverat.
Exempel på säkrare UI-mö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 }
});
}
Viktig:
- Anropa först
session.getoch läs de kommandon som stöds. - Visa endast kontroller för kommandon som stöds i den aktuella sessionen.
- Validera användarinmatningar innan du skickar kommandoparametrar.
device.commandkräver skrivbehörighet (locks:write) för tilläggssessionen.- Hantera brygg-/serverfel på ett smidigt sätt (
insufficient_scope, kommando som inte stöds, valideringsfel).
Krav för förlängning
Tilläggskrav låter ett tillägg definiera återkommande slutföranderegler som visas i låsets användargränssnitt för dagens framsteg och kan tillämpa en påföljd när bäraren missar ett fönster.
Använd detta för serverbetrodda tilläggsaktiviteter som:
- Lös 1 pussel per dag.
- Gör 3 incheckningar varannan dag.
- Slutför 5 förlängningsåtgärder per vecka.
Konfigurationsform
Kravet lagras i tilläggssessionskonfigurationen under extensionRequirements:
{
"extensionRequirements": {
"enabled": true,
"metric": "completion",
"requiredCount": 1,
"cadence": {
"every": 1,
"unit": "day"
},
"punishment": {
"type": "add_time",
"seconds": 900,
"reason": "Missed extension requirement"
}
}
}
Fält:
enabled: slår på/av det återkommande kravet.metric: stabilt räknarnamn. Använd enkla namn somcompletion,winellerverification.requiredCount: hur många betrodda händelser som måste inträffa i fönstret.cadence.every: intervallstorlek.cadence.unit:dayellerweek.- Fönstertidszonen löses av Chastify från bärarens konfigurerade
User.timezone. Tilläggskonfigurationen bör inte hårdkoda en tidszon. punishment.type:none,add_time,freezeellerpillory.punishment.seconds: strafftid föradd_time,freezeellerpillory.punishment.reason: valfri orsak till granskning/felsökning.
Framstegsmodell
Kravförloppet är betrott serversidestillstånd, inte iframe-lokalt tillstånd.
Använd inte state.patch / state.put för att markera ett krav som slutfört. Dessa åtgärder är generella tillståndsskrivningar endast för backend, inte API:er för kravförlopp. Kravförloppet får endast registreras efter att servern validerar händelsen som ska räknas.
Till exempel:
- Ett pusseltillägg bör endast registrera förlopp efter att servern validerar den signerade pusselkörningen och slutfört tillstånd.
- En verifieringsförlängning bör endast registrera förlopp efter att servern har accepterat det inskickade beviset.
- Ett speltillägg bör endast registrera framsteg efter att backend-systemet validerar spelresultatet eller den betrodda slutförandehändelsen.
Körningsbeteende
När det är konfigurerat:
- Låsinstrumentpanelen kan visa kravet i Dagens framsteg.
- Chastify spårar framsteg per förlängningssession och per kadensfönster.
- Det schemalagda kravjobbet utvärderar slutförda fönster och tillämpar den konfigurerade straffen en gång per missat fönster.
- Straff är idempotenta per fönster, så återförsök staplar inte dubbla straff.
Rekommenderat kravflöde
- Konfigurera
extensionRequirementsi användargränssnittet för tilläggets installations-/konfigurationsgränssnitt. - Vid körtidsstart, anropa
session.getoch läs den aktiva konfigurationsfilen. - Slutför tilläggsaktiviteten i användargränssnittet.
- Skicka kompletteringen till en betrodd backend-rutt för det tillägget.
- Låt backend-systemet validera händelse- och registreringskravets förlopp.
- Uppdatera det lokala användargränssnittet med
session.get/state.getefter att det är klart.
Viktig:
- Behandla
state.*endast som tilläggsägd lagring. Använd dedikerade betrodda API:er för framsteg, försök, belöningar och straff. - Lita inte på klientens flaggor för slutförande av krav.
- Håll
metric-namnen stabila; om du ändrar måttenheten börjar räknas in i en annan kategori. - Chastify använder bärarens konfigurerade tidszon för kadensfönster. Om ingen tidszon är tillgänglig för användaren återgår servern till
UTC. - Håll straffen begränsade och förklarliga i granskningsloggarna.
Rekommenderad åtgärdsordning
- Anropa
session.getvid uppstart. - Lässtatus med
state.get. - Utför tillståndsskrivningar från din backend med
PUT/PATCH /statevid behov. - Kör endast lås-/enhetsåtgärder när det stöds och är synligt i användargränssnittet.
- För kravbaserade aktiviteter, rapportera slutförande till en betrodd backend-rutt.
- Uppdatera den lokala vyn efter viktiga skrivningar/åtgärder.