API-voorbeelden
Gebruik deze pagina om de juiste aanvraagvorm voor elke extensiestroom te kopiëren.
- Iframe bridge-voorbeelden gebruiken
postMessage-acties zoalssession.get,state.getenfiles.get. - Voor de voorbeelden met beheerdersrechten kunt u uw eigen extensie-backend gebruiken met
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEYenx-chastify-main-token. - Verstuur nooit een API-sleutel voor ontwikkelaars naar iframe- of browsercode.
De iframe-brug is bedoeld voor het opstarten van de gebruikersinterface en sessiebewerkingen met een laag risico. Gebruik hem voor het lezen van contextinformatie, het opslaan van extensie-eigendomsstatus en het oplossen van bestands-URL's.
De code van browser-iframes wordt door de gebruiker beheerd. Gebruik geen iframe-bridgeverzoeken om tijd toe te passen/verwijderen, taken te voltooien, ontgrendelingsblokkeringen op te heffen, runtimebestanden te uploaden/verwijderen, meldingen te verzenden, logboeken te schrijven of apparaten aan te sturen.
Formaat van verzoek en antwoord
Veilige iframe-brugacties worden verzonden binnen deze brugverzoek-envelop:
{
"type": "chastify:ext:req", // required
"v": 1, // protocol version
"id": "req-123", // your unique request id
"nonce": "from-iframe-hash",
"action": "session.get",
"payload": {}
}
En u ontvangt:
{
"type": "chastify:ext:resp",
"v": 1,
"id": "req-123", // same id you sent
"ok": true,
"data": {}
}
Als ok gelijk is aan false, controleer dan error.code en error.message.
Voorbeelden die alleen de backend gebruiken, maken gebruik van normale HTTPS-verzoeken vanaf uw server. Deze worden niet via de iframe-brug verzonden.
Sessie en context
session.get
Gebruik dit als eerste in vrijwel elke uitbreidingsworkflow.
Wat het doet:
- Hiermee wordt gecontroleerd of uw bridgeverbinding werkt.
- Retourneert de sessiecontext (vergrendelingsstatus, rol, extensieconfiguratie, mogelijkheden).
- Geeft informatie over de mogelijkheden van het apparaat terug die uw gebruikersinterface kan gebruiken voordat uw backend wordt gevraagd om
device.commandaan te roepen.
Waarvoor het gebruikt wordt:
- Je gebruikersinterface opstarten.
- Functies in- of uitschakelen op basis van rol en machtigingen.
- Controleren of de apparaatcommando's worden ondersteund voordat de apparaatbesturingselementen worden weergegeven.
Voorbeeld van een actiepayload:
{
"action": "session.get",
"payload": {}
}
Voorbeeld van een session.get-antwoordfragment (runtime-vergrendelingsgegevens):
{
"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
}
}
}
Privacyverklaring:
wearerLastSeenTimestamp/keyholderLastSeenTimestampworden alleen geretourneerd als die gebruikershowOnlineStatus !== falseheeft.- Als de online status niet zichtbaar is, zijn deze velden
null.
Backend-uitbreidingsworkflows
Deze voorbeelden illustreren het veilige productieproces:
- De iframe leest
mainTokenensessionIduit de hash-payload. - De iframe stuurt ze door naar je backend.
- Je backend valideert je eigen spel-/taak-/bedrijfsstatus.
- Uw backend roept Chastify aan met een app-specifieke Developer API-sleutel plus
x-chastify-main-token.
Gebruik sessionId niet als enige authenticatiemethode. Beschouw mainToken als een in de browser zichtbare opstartcontext en beschouw uw API-sleutel voor ontwikkelaars als een geheim dat alleen voor de backend toegankelijk is.
Uw backend moet de eigen spel-/taakstatus valideren voordat Chastify wordt aangeroepen. Het doorgeven van mainToken en sessionId vanuit de iframe identificeert alleen de geopende extensiesessie; het bewijst niet dat de gebruiker een uitdaging heeft voltooid.
Haal de sessiecontext veilig op
Je iframe kan de veilige bridge session.get gebruiken voor het opstarten van de gebruikersinterface. Als je backend dezelfde context nodig heeft voordat een geprivilegieerde actie wordt uitgevoerd, haal deze dan op bij je backend met beide referenties.
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
})
});
Jouw 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
});
});
Tijd toepassen vanuit een extensie-backend
De browser kan uw backend vragen om een beloning of straf toe te passen, maar de browser mag niet bepalen of de actie geldig is. Controleer de actie eerst aan de serverzijde.
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());
});
Gebruik add_time voor straffen en remove_time voor beloningen.
Door de server geverifieerde spelvoltooiing
Bij spellen zoals Simon Says moet je niet vertrouwen op een winst die door de client wordt gemeld. Maak de run aan de serverzijde aan, sla de verwachte reeks of een hash ervan op en controleer de ingediende invoer voordat je Chastify aanroept.
Een in de browser zichtbaar geheugenspel kan niet bewijzen dat een mens eerlijk heeft gespeeld, omdat de browser de reeks moet ontvangen om het spel weer te geven. Serververificatie voorkomt nog steeds vervalste Chastify-mutaties en stelt uw backend in staat om run-ID's, vervaldatum, moeilijkheidsgraad, tempo, score en replay-bescherming af te dwingen voordat beloningen of straffen worden toegepast.
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 });
});
Het exacte schema voor het opslaan van de uitvoeringsgegevens bepaalt u zelf. verifySessionLaunch moet Chastify aanroepen met uw app-specifieke Developer API-sleutel en x-chastify-main-token voordat sessionId wordt vertrouwd. De belangrijkste regel is dat mutaties in Chastify pas plaatsvinden nadat uw backend de lancering en het resultaat heeft geverifieerd.
Geplande vereisten
Uw backend beheert de planning, de cadanscontroles en de bewijsvalidatie. Gebruik Chastify alleen om betrouwbare voortgang vast te leggen of ontgrendelingsblokkeringen bij te werken nadat uw backend heeft vastgesteld dat aan de vereiste is voldaan.
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
})
});
}
De huidige API's voor geïnstalleerde extensies vereisen een geldig iframe-starttoken in x-chastify-main-token; starttokens verlopen momenteel na 10 uur. Voor geplande taken die na het verlopen van dat token worden uitgevoerd, kunt u uw eigen bewijs van lopende taken opslaan en de voortgang indienen bij de volgende geldige extensiestart, of een ingebouwde serverflow gebruiken die is ontworpen voor onbeheerde achtergrondtaken.
Beschouw geplande taken niet als betrouwbaar alleen omdat ze op uw server worden uitgevoerd. De taak heeft nog steeds servervalidatie, frequentiecontroles, bescherming tegen herhaling en een geldig Chastify-autorisatiepad nodig voordat de voortgang van de vereisten kan worden vastgelegd.
Meldingen
notifications.custom
Gebruik dit vanuit de backend van je extensie om een aangepaste extensienotificatie te sturen naar de drager, de sleutelhouder of beiden.
Eindpunt:
POST /api/extensions/sessions/:sessionId/notifications/custom
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Voorbeeldtekst:
{
"title": "Extension Reminder",
"message": "Your next challenge is ready.",
"showPageOverlay": false,
"target": "both"
}
Opmerkingen:
showPageOverlaywordt standaard ingesteld opfalse.targetwordt standaard ingesteld opwearer.- De API maakt een notificatietype aan met de waarde
extension_app_message.
Uitbreidingsstaat
De extensiestatus is de JSON-data die eigendom is van uw extensie voor de huidige vergrendelingssessie.
Het schrijven naar de status is alleen mogelijk via de backend en vereist een app-specifieke Developer API-sleutel plus de sessiecode mainToken. Iframes kunnen de status lezen met state.get, maar ze kunnen de status niet rechtstreeks schrijven.
state.put
Wat het doet:
- Vervangt het volledige statusobject door het nieuwe
data-object. - Vereist backend-inloggegevens.
Wanneer te gebruiken:
- Eerste opslag.
- Volledige overschrijving wanneer je al de volledig nieuwe status hebt.
Voorbeeld:
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"
}
}'
Veldnotities:
payload.data: elke geldige JSON-waarde/elk geldig object dat uw extensie nodig heeft.- Avoid Mongo-unsafe key names (
$prefix or keys containing.). - De status is sessiegebonden en de grootte ervan wordt beperkt door de
stateMaxBytesvan de extensie-app, met een standaardwaarde van 64 KiB. - Sla bestands-ID's op in de status, niet binaire bestanden of ondertekende URL's. Gebruik
files.getom ondertekende URL's te vernieuwen voordat de media worden weergegeven.
state.patch
Wat het doet:
- Past een JSON-mergepatch toe op de bestaande status.
- Alleen gewijzigde sleutels hoeven te worden verzonden.
- Vereist backend-inloggegevens.
Wanneer te gebruiken:
- Geleidelijke updates op basis van gebruikersinteracties.
- Een veld bijwerken zonder alles opnieuw te verzenden.
Voorbeeld:
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
Wat het doet:
- Leest de huidige status van de extensie.
- Beschikbaar via de iframe bridge.
Wanneer te gebruiken:
- Bij het laden van de iframe.
- Als je na het schrijven de lokale gebruikersinterface opnieuw wilt synchroniseren, kan dat.
Voorbeeld:
{
"action": "state.get",
"payload": {}
}
Bestandsopslag
Gebruik files.* voor binaire media zoals puzzelafbeeldingen, gegenereerde voorbeelden of foto's van uitdagingen. Sla de geretourneerde file.id op in de backend-status of in uw eigen database. Render met file.signedUrl en vernieuw de ondertekende URL met files.get wanneer de iframe later wordt geladen.
Instelschermen die worden uitgevoerd voordat een vergrendeling/sessie bestaat, gebruiken gefaseerde uploads in plaats van files.upload. Gefaseerde bestanden zijn tijdelijk totdat de extensieconfiguratie wordt opgeslagen met een verwijzing naar provider: "chastify_storage" en fileId. Chastify claimt deze bestanden automatisch bij het opslaan van de vergrendeling/sjabloon; er is geen aparte claimoproep aan de browserzijde nodig.
Voorbeeld van het splitsen van status/bestand vanuit uw 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"
}
}'
Los het beeld later op voordat het wordt weergegeven:
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
Controleer dit voordat u de uploadopties weergeeft.
{
"action": "files.capabilities",
"payload": {}
}
Runtime files.upload
Het uploaden van bestanden tijdens runtime wijzigt de sessiegegevens van de extensie, dus het is geen iframe-brugopdracht. Upload runtime-bestanden vanuit uw backend met een app-specifieke Developer API-sleutel en x-chastify-main-token.
files.get
Vernieuw een ondertekende R2-URL met een stabiele bestands-ID.
{
"action": "files.get",
"payload": {
"fileId": "file_record_id"
}
}
files.list
{
"action": "files.list",
"payload": {}
}
Runtime files.delete is om dezelfde reden als upload ook alleen voor de backend beschikbaar.
Vergrendelingsacties
Voeg tijd toe
Eindpunt: POST /api/extensions/sessions/:sessionId/action
Wat het doet:
- Voegt tijd toe aan of verwijdert tijd van de vergrendelingsaftelling, afhankelijk van
deltaSeconds.
Wanneer te gebruiken:
- Belonings-/strafknoppen.
- Uitkomst van het spel (winnen levert extra speeltijd op, verliezen kost extra speeltijd).
Voorbeeld:
{
"name": "add_time",
"params": 300 // +300 sec = +5 minutes
}
Veldnotities:
- Positieve waarde voegt tijd toe.
- Een negatieve waarde verwijdert de tijd (indien toegestaan door de serverregels).
Bevriezen
Eindpunt: POST /api/extensions/sessions/:sessionId/action
Wat het doet:
- Door bevriezing wordt de voortgang gedurende een bepaalde tijd geblokkeerd.
Wanneer te gebruiken:
- Afkoelingsmechanismen.
- Beloningscontrolepunten.
Voorbeeld:
{
"name": "freeze",
"params": { "durationSeconds": 120 }
}
Je kunt het ook aanroepen zonder durationSeconds:
{
"name": "freeze",
"params": {}
}
Veldnotities:
durationSecondsis optioneel.- Indien weggelaten, is de huidige standaardwaarde
3600seconden (1 uur). - Het geaccepteerde tijdsbereik is
60tot86400seconden.
Ontdooien
Eindpunt: POST /api/extensions/sessions/:sessionId/action
Wat het doet:
- De actieve bevriezing wordt beëindigd en het normale timergedrag wordt hervat.
Wanneer te gebruiken:
- Handmatige overschrijving in extensieworkflows.
- Bedieningselementen voor "bevriezing annuleren".
Voorbeeld:
{
"name": "unfreeze",
"params": {}
}
Schandpaal
Eindpunt: POST /api/extensions/sessions/:sessionId/action
Wat het doet:
- Hiermee begint een periode van wantrouwen voor de actieve vergrendelingssessie.
Wanneer te gebruiken:
- Strafmaatregelen na mislukte taken/uitdagingen.
- Escalatiestromen die de interactie met sloten tijdelijk beperken.
Voorbeeld:
{
"name": "pillory",
"params": {
"durationSeconds": 600,
"reason": "Missed scheduled check-in"
}
}
Veldnotities:
namemoetpilloryzijn.params.durationSecondsis vereist.params.reasonis optioneel.- Vereist dat de schandpaalfunctie is ingeschakeld in de sessieconfiguratie.
Einde van de schandpaal
Eindpunt: POST /api/extensions/sessions/:sessionId/action
Wat het doet:
- Beëindigt de huidige actieve schandpaalzitting onmiddellijk.
Voorbeeld:
{
"name": "pillory.end",
"params": {}
}
Veldnotities:
namemoetpillory.endzijn.- Foutmelding
pillory_not_activeals het slot zich niet in de schandpaal bevindt.
Taak toewijzen
Eindpunt: POST /api/extensions/sessions/:sessionId/action
Wat het doet:
- Hiermee wordt een actieve taakuitvoering voor de gebruiker gestart op basis van de extensielogica.
- Kan een reeds gestarte taak overschrijven.
Voorbeeld:
{
"name": "task.assign",
"params": {
"taskText": "Clean your room",
"points": 10,
"verificationRequired": true,
"durationSeconds": 1800
}
}
Veldnotities:
taskTextis vereist.pointsis optioneel en wordt aan de serverzijde beperkt.verificationRequiredwordt standaard ingesteld opfalse.durationSecondsis optioneel (0betekent dat er geen timer nodig is).- Vereist dat de takenmodule is ingeschakeld op het slot.
Start taaktimer
Eindpunt: POST /api/extensions/sessions/:sessionId/action
Wat het doet:
- Start of herstart het aftelvenster voor de momenteel actieve getimede taak.
Voorbeeld:
{
"name": "task.start_timer",
"params": {}
}
Veldnotities:
- Vereist een actieve taakuitvoering.
- Mislukt als er voor de huidige taak geen duur is ingesteld.
Voltooi de taak
Eindpunt: POST /api/extensions/sessions/:sessionId/action
Wat het doet:
- Geeft aan of de actieve taak is voltooid of mislukt.
Voorbeeld (succes):
{
"name": "task.complete",
"params": {
"successful": true
}
}
Voorbeeld (mislukt):
{
"name": "task.complete",
"params": {
"successful": false,
"reason": "Did not finish in time"
}
}
Tijdelijke opening activeren
Eindpunt: POST /api/extensions/sessions/:sessionId/action
Wat het doet:
- Start een tijdelijk hygiënevenster op basis van de uitbreidingslogica.
Voorbeeld:
{
"name": "hygienic_unlock.start",
"params": {
"durationSeconds": 900
}
}
Veldnotities:
- Vereist dat de functie 'Hygiënisch openen' op het slot is ingeschakeld.
- Mislukt als er al een hygiëne-opening gaande is.
durationSecondsis optioneel; indien weggelaten, wordt de standaardvergrendeling gebruikt.
Metagegevens en acties op de startpagina
metadata.patch
Wat het doet:
- Slaat extensiemetadata op die door de gebruikersinterface van de vergrendelpagina worden gebruikt.
- Ondersteunt
unlockBlockersenhomeActions. - Ondersteunt
homeActions[].intentvoor deep-link gedrag bij het openen van de extensie.
Wanneer te gebruiken:
- Dwing de ontgrendelingsvoorwaarden van de vergrendelingssessie af die van toepassing zijn op uw extensie.
- Voeg snelle acties toe aan de vergrendelpagina die uw extensie openen met een specifieke intentie.
- Leid gebruikers direct naar een specifiek scherm/workflow wanneer ze op een home-actie klikken.
Eindpunt:
PATCH /api/extensions/sessions/:sessionId/metadata
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Voorbeeldtekst:
{
"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"
}
}
}
]
}
Veldnotities:
unlockBlockers: lijst met actieve blokkeringen voor het ontgrendelen van vergrendelingssessies van uw extensie.- Je kunt meerdere blokkers tegelijk toevoegen (tot 25), één per onvervulde voorwaarde.
- Ontgrendelen blijft geblokkeerd zolang er een blokkering actief is op ingeschakelde extensies.
- Chastify bundelt blokkeringen van alle extensies voor de vergrendelingssessie.
- Je extensie mag alleen in de eigen metadata blokkeringen toevoegen of verwijderen.
- Verwijder geen blokkeringen van andere extensies; wis je array alleen wanneer aan je eigen voorwaarden is voldaan.
homeActions: sneltoetsen die worden weergegeven in de vergrendelingsinterface.homeActions[].slug: stabiele ID voor uw actie.homeActions[].title: label voor de gebruiker.homeActions[].description: optionele hulptekst.homeActions[].intent: optionele deep-link instructie die aan uw extensie wordt doorgegeven wanneer deze wordt geopend.- In de gebruikersinterface van de extensiekaart worden deze acties weergegeven als een menu/lijst op basis van de actietitel (intern gekoppeld aan de slug).
- Wanneer een gebruiker op een van beide klikt, opent Chastify de extensie en geeft het volgende door:
homeActionSlughomeAction(geselecteerd actieobject)intent(genormaliseerd intentieobject) zodat uw extensie bij het laden direct naar de juiste weergave/actie kan worden doorgestuurd.
Intents: voorbeeld van een ontwikkelaarsapp
Gebruik dit patroon in je extensie-app om te reageren op menuklik-intents bij het laden.
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");
Wat dit voorbeeld doet:
- Leest
homeActionSlug+intentuit de hash-payload van het iframe. - Verwerkt elke klik slechts één keer per vergrendelings-/actie-slug.
- Routeert naar een paneel wanneer de intentie
open_panelis. - Valt terug op het weergeven van een intentiebericht voor aangepaste intentietypen.
Apparaatopdracht
device.command
Wat het doet:
- Verzendt een apparaatbesturingsopdracht (indien ondersteund voor die sessie/dat apparaat).
- Hiermee kan uw extensie gestandaardiseerde schok-/trillingsacties activeren via Chastify.
Wanneer te gebruiken:
- Het activeren van ondersteunde schok-/trillingscommando's vanuit de uitbreidingslogica.
- Het ontwikkelen van interactieve uitbreidingsfuncties (spelletjes, straffen, beloningen, routines).
Eindpunt:
POST /api/extensions/sessions/:sessionId/device-command
Authorization: Bearer YOUR_APP_SCOPED_DEVELOPER_KEY
x-chastify-main-token: MAIN_TOKEN_FROM_IFRAME_HASH
Voorbeeldtekst:
{
"command": "shock.start",
"params": {
"durationSeconds": 30,
"intensityPct": 50
}
}
Veelgebruikte commando's:
shock.startmet parameters:{ durationSeconds, intensityPct, message? }shock.stopvibration.startmet parameters:{ durationSeconds, intensityPct, frequencyPct?, message? }vibration.stopall.stopshock.random.setmet parameters:{ enabled, minIntensityPct?, maxIntensityPct?, message? }(alleen Lockink AA-A1012)shock.berserk.setmet parameters:{ enabled, message? }(alleen Lockink AA-A1012)
Aanbevolen workflow:
- Roep
session.getaan bij het laden. - Lees de apparaatmogelijkheden uit
deviceControl.supportedCommands. - Geef alleen besturingselementen weer voor ondersteunde opdrachten.
- Verzend
device.commandmet gevalideerde waarden. - Vernieuw of vertrouw de respons
active-vlaggen voor de live UI-status.
Parameterrichtlijnen:
durationSeconds: server beperkt de tijd tot veilige limieten (huidige beleidslimiet is 300s).intensityPct: verwachte percentagewaarde (invoer in de stijl van1-100, begrensd aan de serverzijde).frequencyPct: verwachte percentagewaarde (1-100) voor trillingsstromen (beperkt aan de serverzijde).- Voor de willekeurige modus moet u ervoor zorgen dat
minIntensityPct <= maxIntensityPctis ingeschakeld.
Voorbeeld van een veiliger UI-patroon:
// 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 }
});
}
Belangrijk:
- Roep eerst
session.getaan en lees de ondersteunde commando's. - Toon alleen de besturingselementen voor opdrachten die in de huidige sessie worden ondersteund.
- Valideer de gebruikersinvoer voordat u de opdrachtparameters verzendt.
device.commandvereist schrijfrechten (locks:write) voor de extensiesessie.- Behandel bridge-/serverfouten op een nette manier (
insufficient_scope, niet-ondersteunde opdracht, validatiefouten).
Vereisten voor verlenging
Met de vereisten van een extensie kunnen gebruikers terugkerende voltooiingsregels definiëren die worden weergegeven in de 'Vandaag voortgang'-interface van het slot en een straf kunnen opleggen wanneer de gebruiker een venster mist.
Gebruik dit voor serververtrouwde extensieactiviteiten zoals:
- Maak elke dag één puzzel.
- Voltooi elke twee dagen 3 check-ins.
- Voltooi wekelijks 5 uitbreidingsacties.
Configuratievorm
De vereiste is opgeslagen in de extensiesessieconfiguratie onder extensionRequirements:
{
"extensionRequirements": {
"enabled": true,
"metric": "completion",
"requiredCount": 1,
"cadence": {
"every": 1,
"unit": "day"
},
"punishment": {
"type": "add_time",
"seconds": 900,
"reason": "Missed extension requirement"
}
}
}
Velden:
enabled: schakelt de terugkerende vereiste in/uit.metric: stabiele tellernaam. Gebruik eenvoudige namen zoalscompletion,winofverification.requiredCount: hoeveel vertrouwde gebeurtenissen moeten er in het venster plaatsvinden.cadence.every: intervalgrootte.cadence.unit:dayofweek.- De tijdzone van het venster wordt bepaald door Chastify op basis van de geconfigureerde
User.timezonevan de drager. De extensieconfiguratie mag geen tijdzone hardcoderen. punishment.type:none,add_time,freezeofpillory.punishment.seconds: duur van de straf vooradd_time,freezeofpillory.punishment.reason: optionele reden voor audit/debug.
Voortgangsmodel
De voortgang van de vereisten wordt op de server opgeslagen, niet lokaal in de iframe.
Gebruik state.patch / state.put niet om een vereiste als voltooid te markeren. Deze acties zijn alleen voor de backend bedoeld om de algemene status te wijzigen, niet voor API's die de voortgang van een vereiste bijhouden. De voortgang van een vereiste mag pas worden geregistreerd nadat de server de gebeurtenis heeft gevalideerd die meetelt.
Bijvoorbeeld:
- Een puzzeluitbreiding mag de voortgang pas registreren nadat de server de ondertekende puzzeluitvoering en de voltooide status heeft gevalideerd.
- Een verificatie-extensie mag de voortgang pas registreren nadat de server het ingediende bewijs heeft geaccepteerd.
- Een game-extensie mag de voortgang pas registreren nadat de backend het spelresultaat of de betrouwbare voltooiingsgebeurtenis heeft gevalideerd.
Runtimegedrag
Wanneer geconfigureerd:
- Het dashboard voor vergrendelingen kan de vereiste in de huidige voortgang weergeven.
- Chastify registreert de voortgang per extensiesessie en per cadansvenster.
- De geplande taak evalueert voltooide vensters en past de geconfigureerde sanctie eenmaal per gemist venster toe.
- De straffen zijn idempotent per venster, dus herhaalde pogingen leiden niet tot dubbele straffen.
Aanbevolen vereistenstroom
- Configureer
extensionRequirementsin de extensie-instellingen/configuratie-interface. - Roep bij het opstarten van de runtime
session.getaan en lees de actieve configuratie. - Voltooi de uitbreidingsactiviteit in de gebruikersinterface.
- Stuur de voltooiing door naar een vertrouwde backend-route voor die extensie.
- Laat de backend de gebeurtenis valideren en de voortgang van de vereisten vastleggen.
- Vernieuw de lokale gebruikersinterface met
session.get/state.getna voltooiing.
Belangrijk:
- Beschouw
state.*uitsluitend als opslagruimte die eigendom is van de extensie. Gebruik specifieke, vertrouwde API's voor voortgang, pogingen, beloningen en straffen. - Vertrouw niet op voltooiingsvlaggen die alleen aan de clientzijde worden weergegeven voor vereisten.
- Houd de
metric-namen stabiel; het wijzigen van de meeteenheid zorgt ervoor dat er in een andere categorie wordt meegeteld. - Chastify gebruikt de door de gebruiker ingestelde tijdzone voor de cadansvensters. Als er geen tijdzone beschikbaar is voor de gebruiker, schakelt de server terug naar
UTC. - Houd straffen afgebakend en verklaarbaar in auditlogboeken.
Aanbevolen actievolgorde
- Roep
session.getaan bij het opstarten. - Lees de status met
state.get. - Voer indien nodig statuswijzigingen uit vanuit uw backend met
PUT/PATCH /state. - Voer vergrendelings-/apparaatacties alleen uit wanneer dit wordt ondersteund en zichtbaar is in de gebruikersinterface.
- Voor activiteiten die aan specifieke vereisten zijn gekoppeld, dient u de voltooiing te melden aan een betrouwbare backend-route.
- Vernieuw de lokale weergave na belangrijke schrijfbewerkingen/acties.