Hook-Referenz: Daten
In Hooks sprichst du diese fünf Pakete über context an, z. B. context.db.find(...) oder context.request(). Die Signaturen stammen aus den // args:- bzw. // JS signature:-Kommentaren in internal/hook/context_*.go im tibi-server; wo so ein Kommentar fehlt, ist die Signatur aus Funktionsrumpf und _test-Datei abgeleitet und entsprechend markiert. Jede Funktion zeigt genau einen Fehlerfall mit dem originalen Error-Text aus Code oder Tests (Status-Code aus den Hook-Tests, meist 500).
db – Collections lesen und schreiben
Abschnitt betitelt „db – Collections lesen und schreiben“Quelle: context_db.go, registriert per RegisterPackageFunctions("db", ...) mit find, count, create, update, delete, deleteMany, updateMany.
db.find
Abschnitt betitelt „db.find“Signatur: db.find(collectionName: string, options?: object): Array — aus // args: collectionName:string, options:map[string]interface{} (context_db.go:42). options kennt filter, selector (oder projection), offset, limit und sort.
Leeres Ergebnis ist kein Fehler: db.find liefert dann ein leeres Array.
;(function () { const rows = context.db.find("content", { filter: { active: true }, sort: ["-publishAt"], limit: 10 }) throw { status: 200, json: { count: rows.length, rows: rows } }})()Fehlerfall (Error): Ohne Collection-Namen brichst du mit missing collection name argument in db.find ab (context_db.go:53); eine unbekannte Collection liefert den Config-Error und endet im Hook-Test mit Status 500 (error - find invalid collection, context_db_test.go:228).
db.count
Abschnitt betitelt „db.count“Signatur: db.count(collectionName: string, options?: { filter?: object }): number — aus // args: collectionName:string, options:map[string]interface{} (context_db.go:186).
;(function () { const n = context.db.count("content", { filter: { active: true } }) throw { status: 200, json: { count: n } }})()Fehlerfall (Error): Ein filter vom falschen Typ (z. B. String statt Objekt) scheitert mit invalid type for options.filter in db.count (context_db.go:222).
db.create
Abschnitt betitelt „db.create“Signatur: db.create(collectionName: string, data: object): object — aus // args: collectionName:string, data:map[string]interface{} (context_db.go:260). Gibt das gespeicherte Dokument inklusive id zurück.
;(function () { const doc = context.db.create("content", { title: "Neu", active: false }) throw { status: 200, json: { id: doc.id, title: doc.title } }})()Fehlerfall (Error): Fehlende data melden die Tests belegt: missing collection name and/or data argument in db.create, Status 500 (error - create missing data, context_db_test.go:239).
db.update
Abschnitt betitelt „db.update“Signatur: db.update(collectionName: string, id: string, data: object, options?: { raw?: boolean }): object — aus // args: collectionName:string, id:string(ObjectID hex), data:map[string]interface{} (context_db.go:313). data versteht Feld-Operatoren wie {"price": {"$inc": 10}}; mit { raw: true } übergibst du ein rohes Mongo-Update-Dokument.
;(function () { const id = context.request().query("id") const doc = context.db.update("content", id, { title: "Korrigiert" }) throw { status: 200, json: { id: doc.id, title: doc.title } }})()Fehlerfall (Error): Eine ID, die kein ObjectID-Hex ist, liefert invalid object id string in db.update (context_db.go:365).
db.delete
Abschnitt betitelt „db.delete“Signatur: db.delete(collectionName: string, id: string): object — aus // args: collectionName:string, id:string(ObjectId Hex) (context_db.go:453). Gibt { message: "ok" } zurück und räumt Datei-Felder des Dokuments weg.
;(function () { const id = context.request().query("id") const res = context.db.delete("content", id) throw { status: 200, json: { deleted: id, message: res.message } }})()Fehlerfall (Error): Ungültige ID: invalid object id string in db.delete (context_db.go:479); fehlende Argumente: missing collection name and/or id in db.delete.
db.deleteMany
Abschnitt betitelt „db.deleteMany“Signatur: db.deleteMany(collectionName: string, options?: { filter?: object }): object — aus // args: collectionName:string, options:map[string]interface{} (context_db.go:533). Antwortet mit { message: "ok", removed: <Anzahl> }.
;(function () { const res = context.db.deleteMany("content", { filter: { active: false } }) throw { status: 200, json: { removed: res.removed } }})()Fehlerfall (Error): options als String statt Objekt scheitert mit options must be object in db.deleteMany (context_db.go:552).
db.updateMany
Abschnitt betitelt „db.updateMany“Signatur: db.updateMany(collectionName: string, options: { filter?: object, changes?: object, update?: object }): object — aus // args: collectionName:string, options:map[string]interface{} (context_db.go:628). Entweder changes (einfache Werte, werden $set) oder update (rohe Operatoren wie $inc, $unset) ist Pflicht; update gewinnt bei beiden.
;(function () { const res = context.db.updateMany("content", { filter: { active: false }, changes: { reviewed: true } }) throw { status: 200, json: { modified: res.modified } }})()Fehlerfall (Error): Ohne changes und ohne update: options.changes or options.update is required in db.updateMany (context_db.go:711).
cache – Hook-lokaler Zwischenspeicher
Abschnitt betitelt „cache – Hook-lokaler Zwischenspeicher“Quelle: context_cache.go, registriert per RegisterPackageFunctions("cache", ...) mit set, get, has, delete, clear, count. Der Cache ist projektweit (project-scoped), nicht pro Request.
cache.set
Abschnitt betitelt „cache.set“Signatur: cache.set(key: string, value: any, ttlMs?: number): void — aus // JS signature: cache.set(key: string, value: any, ttlMs?: number): void (context_cache.go:23).
;(function () { context.cache.set("content:teaser", { title: "Start" }, 60000) throw { status: 200, json: { cached: true } }})()Fehlerfall (Error): Weniger als zwei Argumente: cache.set requires at least key and value (context_cache.go:30); leerer Schlüssel: cache.set: key must be a non-empty string (context_cache.go:34).
cache.get
Abschnitt betitelt „cache.get“Signatur: cache.get(key: string): any | null — aus // JS signature: cache.get(key: string): any | null (context_cache.go:48). Unbekannte Schlüssel liefern null, keinen Error.
;(function () { const teaser = context.cache.get("content:teaser") throw { status: 200, json: { hit: teaser !== null, teaser: teaser } }})()Fehlerfall (Error): Aufruf ohne Schlüssel: cache.get requires a key (context_cache.go:55).
cache.has
Abschnitt betitelt „cache.has“Signatur: cache.has(key: string): boolean — aus // JS signature: cache.has(key: string): boolean (context_cache.go:70).
;(function () { const hit = context.cache.has("content:teaser") throw { status: 200, json: { hit: hit } }})()Fehlerfall (Error): Aufruf ohne Schlüssel: cache.has requires a key (context_cache.go:77).
cache.delete
Abschnitt betitelt „cache.delete“Signatur: cache.delete(key: string): boolean — aus // JS signature: cache.delete(key: string): boolean (context_cache.go:88). Gibt zurück, ob der Schlüssel existierte.
;(function () { const gone = context.cache.delete("content:teaser") throw { status: 200, json: { deleted: gone } }})()Fehlerfall (Error): Aufruf ohne Schlüssel: cache.delete requires a key (context_cache.go:95).
cache.clear
Abschnitt betitelt „cache.clear“Signatur: cache.clear(): void — aus // JS signature: cache.clear(): void (context_cache.go:106). Räumt alle Einträge des Projekt-Caches weg.
;(function () { context.cache.clear() throw { status: 200, json: { cleared: true } }})()Fehlerfall (Error): Ohne initialisierten Projekt-Cache meldet der Code cache.clear: cache not available (context_cache.go:110).
cache.count
Abschnitt betitelt „cache.count“Signatur: cache.count(): number — aus // JS signature: cache.count(): number (context_cache.go:118). Zählt nur lebende (nicht abgelaufene) Einträge.
;(function () { const n = context.cache.count() throw { status: 200, json: { entries: n } }})()Fehlerfall (Error): Ohne initialisierten Projekt-Cache meldet der Code cache.count: cache not available (context_cache.go:122).
request – Aktuellen Request lesen
Abschnitt betitelt „request – Aktuellen Request lesen“request ist kein Paket, sondern eine direkt registrierte Funktion (Register("request", ...) in context_request.go:12). Signatur aus Code und Tests abgeleitet (kein args:-Kommentar, context_request.go:15): request(): { method, remoteAddr, clientIp, host, url, path, param(), query(), header(), bodyBytes(), body() }. method ist kleingeschrieben, query, header und param sind Funktionen.
request
Abschnitt betitelt „request“Signatur (abgeleitet): request(): object — Felder und Helfer siehe oben, belegt durch FuncRequest (context_request.go:16) und test_request.js (Methode, Pfad, Query, Header, Host, URL, Remote-Adresse).
;(function () { const req = context.request() const out = { method: req.method, path: req.path, filter: req.query("filter"), token: req.header("X-Custom-Test") } throw { status: 200, json: out }})()Fehlerfall (Error): Außerhalb von Hooks (kein HTTP-Kontext, z. B. in Jobs ohne Request) scheitert der Aufruf mit request functions only valid in hooks (context_request.go:19).
response – Antwort steuern
Abschnitt betitelt „response – Antwort steuern“Quelle: context_response.go, registriert per RegisterPackageFunctions("response", ...) mit header, writeHeader, write, flush, writeSSE. Alle Funktionen brauchen einen Hook-HTTP-Kontext. Muster: test_response.js im tibi-server.
response.header
Abschnitt betitelt „response.header“Signatur aus Kommentar (context_response.go:21, // header:string content:string): response.header(name: string, content: string): void — setzt einen Antwort-Header.
;(function () { context.response.header("X-SSR-Cache", "hit") context.response.header("Cache-Control", "public, max-age=60") throw { status: 200, json: { headers: "set" } }})()Fehlerfall (Error): Weniger als zwei Argumente: missing header name and/or value in reponse.header function — so wörtlich im Code, inklusive Tippfehler (context_response.go:29).
response.writeHeader
Abschnitt betitelt „response.writeHeader“Signatur: response.writeHeader(status: number): void — aus // args: status:int (context_response.go:43). Muss vor write kommen; belegt durch write_header_and_body in test_response.js (Status 201).
;(function () { context.response.header("Content-Type", "text/plain") context.response.writeHeader(201) context.response.write("Angelegt") return { stop: true }})()Fehlerfall (Error): Nicht-numerischer Status: status must be a number in response.writeHeader function (context_response.go:61); ohne writeHeader sendet das erste write implizit Status 200 (context_response.go:68).
response.write
Abschnitt betitelt „response.write“Signatur: response.write(data: string | []byte): void — aus // args: data:string|[]byte (context_response.go:70). Schreibt direkt in den Antwort-Body.
;(function () { context.response.header("Content-Type", "application/json") context.response.writeHeader(200) context.response.write(JSON.stringify({ custom: true })) return { stop: true }})()Fehlerfall (Error): Aufruf ohne Daten: missing data in response.write function (context_response.go:78).
response.flush
Abschnitt betitelt „response.flush“Signatur ohne args:-Kommentar, aus Rumpf und Tests abgeleitet (context_response.go:101): response.flush(): void — schiebt gepufferte Daten sofort zum Client, wichtig für Streaming.
;(function () { context.response.header("Content-Type", "text/plain") context.response.writeHeader(200) context.response.write("part1") context.response.flush() context.response.write("part2") return { stop: true }})()Fehlerfall (Error): Außerhalb von Hooks (ohne HTTP-Kontext) scheitert der Aufruf mit response functions only valid in hooks (context_response.go:104); kann der Writer nicht flushen, ist flush still wirkungslos.
response.writeSSE
Abschnitt betitelt „response.writeSSE“Signatur: response.writeSSE(event: string, data: string): void — aus // args: event:string, data:string (context_response.go:115). Schreibt event: {event}\ndata: {data}\n\n und flusht sofort; mit nur einem Argument wird es als data ohne Event-Name gesendet.
;(function () { context.response.header("Content-Type", "text/event-stream") context.response.writeHeader(200) context.response.writeSSE("tick", "event-data-1") return { stop: true }})()Fehlerfall (Error): Aufruf ohne Argumente: missing data in response.writeSSE function (context_response.go:129).
fs – Dateien im Config-Verzeichnis
Abschnitt betitelt „fs – Dateien im Config-Verzeichnis“Quelle: context_fs.go, registriert per RegisterPackageFunctions("fs", ...) mit configDir, readFile, writeFile, stat, readDir, mkDir, remove, copy. Alle Pfade sind relativ und werden per CleanFilePath gegen das Config-Verzeichnis aufgelöst. Muster: test_fs.js im tibi-server.
fs.configDir
Abschnitt betitelt „fs.configDir“Signatur ohne args:-Kommentar, aus dem Rumpf abgeleitet (context_fs.go:27): fs.configDir(): string — liefert das Config-Verzeichnis, nimmt keine Argumente.
;(function () { const dir = context.fs.configDir() throw { status: 200, json: { hasDir: dir !== null && dir !== undefined } }})()Fehlerfall: Kein Fehlerfall — configDir nimmt keine Argumente und wirft keinen Pfad-Fehler (dokumentierte Abwesenheit, kein Versäumnis).
fs.readFile
Abschnitt betitelt „fs.readFile“Signatur: fs.readFile(path: string, options?: { bytes?: boolean }): string — aus // args: path:string (context_fs.go:31); mit { bytes: true } kommen Bytes statt String zurück.
;(function () { const content = context.fs.readFile("snippets/hint.txt") throw { status: 200, json: { content: content } }})()Fehlerfall (Error): Ohne Pfad: missing path in fs.readFile function mit Status 500; eine fehlende Datei liefert ebenfalls Status 500 mit $.error — beides belegt in context_fs_test.go:109 („error - missing path”).
fs.writeFile
Abschnitt betitelt „fs.writeFile“Signatur: fs.writeFile(path: string, data: string | []byte): void — aus // args: path:string data:[]bytes|string (context_fs.go:79).
;(function () { context.fs.writeFile("tmp/note.txt", "Hallo Hook") const back = context.fs.readFile("tmp/note.txt") context.fs.remove("tmp/note.txt") throw { status: 200, json: { content: back } }})()Fehlerfall (Error): Ohne Daten: missing data in fs.writeFile function (context_fs.go:85); ein Pfad außerhalb des Config-Verzeichnisses scheitert in CleanFilePath mit einem Error ... in fs.writeFile.
fs.stat
Abschnitt betitelt „fs.stat“Signatur: fs.stat(path: string): object — aus // args: path:string (context_fs.go:120). Antwortet mit { name, isDir, size, modTime }.
;(function () { const info = context.fs.stat("tmp/note.txt") throw { status: 200, json: { name: info.name, size: info.size } }})()Fehlerfall (Error): Fehlende Datei: Error ... in fs.stat aus os.Stat (context_fs.go:147); ohne Pfad: missing path in fs.stat function.
fs.readDir
Abschnitt betitelt „fs.readDir“Signatur: fs.readDir(path: string): Array — aus // args: path:string (context_fs.go:158). Liefert pro Eintrag { name, isDir, size, modTime }.
;(function () { const files = context.fs.readDir("tmp") throw { status: 200, json: { count: files.length, files: files } }})()Fehlerfall (Error): Unbekanntes Verzeichnis: Error ... in fs.readDir aus os.ReadDir (context_fs.go:182); ohne Pfad: missing path in fs.readDir function.
fs.mkDir
Abschnitt betitelt „fs.mkDir“Signatur: fs.mkDir(path: string): void — aus // args: path:string (context_fs.go:203). Nutzt MkdirAll, legt also auch fehlende Elternverzeichnisse an.
;(function () { context.fs.mkDir("tmp/export") context.fs.writeFile("tmp/export/a.txt", "eins") throw { status: 200, json: { created: true } }})()Fehlerfall (Error): Ohne Pfad: missing path in fs.mkDir function (context_fs.go:206).
fs.remove
Abschnitt betitelt „fs.remove“Signatur: fs.remove(path: string): void — aus // args: path:string (context_fs.go:230).
;(function () { context.fs.writeFile("tmp/alt.txt", "weg") context.fs.remove("tmp/alt.txt") throw { status: 200, json: { removed: true } }})()Fehlerfall (Error): Fehlende Datei: Error ... in fs.remove aus os.Remove (context_fs.go:251); ohne Pfad: missing path in fs.remove function.
fs.copy
Abschnitt betitelt „fs.copy“Signatur: fs.copy(src: string, dest: string): void — aus // args: src:string dest:string (context_fs.go:257).
;(function () { context.fs.copy("tmp/export/a.txt", "tmp/export/b.txt") throw { status: 200, json: { copied: true } }})()Fehlerfall (Error): Ohne Quelle: missing src in fs.copy function, ohne Ziel: missing dest in fs.copy function (context_fs.go:260).
Weiter: Hook-Kontexte als Paket-Index, Hooks schreiben für Lifecycle und Starter-Muster.
Verifiziert am 68b4278 2026-10-16 (tibi-server)