Skip to content

inject.ctx

inject.ctx defines runtime context fields and helper APIs available to inject scripts.

This page describes interface-level specifications only.

Applicable Phases

  • browser: script runs in browser runtime.
  • request: script runs before upstream forwarding.
  • response: script runs after upstream response.

Common Fields (All Phases)

FieldTypeDescription
ctx.idstringCurrent inject id
ctx.srcstringCurrent script source (src)
ctx.phasestringCurrent phase: browser/request/response
ctx.paramsobjectResolved script params (after $persist)
ctx.safe_uidstringPlatform user ID (SAFE_UID)
ctx.request.hoststringRequest host
ctx.request.pathstringRequest path
ctx.request.raw_querystringRaw query without ?

Notes:

  • When auth_required=false and no valid login exists, ctx.safe_uid can be empty string.

ctx.params Resolution Rules

Source:

  • ctx.params comes from inject.do[].params.
  • Final result is always an object.

Static values:

  • Values without $persist marker are passed through as-is.

Dynamic values ($persist):

  • Marker forms: { $persist: "<key>" } or { $persist: "<key>", default: <any> }
  • Dynamic resolution applies only when marker is explicitly used.
  • If persist key exists, use persisted value.
  • If key missing and default exists, use default.
  • If key missing and no default, use null.

Resolution timing:

  • browser: re-resolved on each runtime trigger (page load, route/hash changes, etc.).
  • request/response: re-resolved before each script execution.

Fallback:

  • If resolved params is not an object, ctx.params becomes {}.

ctx.request Field Semantics

Common fields:

FieldTypeDescription
ctx.request.hoststringHost without scheme
ctx.request.pathstringPath (starts with /)
ctx.request.raw_querystringRaw query without ?

Phase-specific fields:

FieldPhaseTypeDescription
ctx.request.hashbrowserstringURL hash without #
ctx.request.methodrequest/responsestringHTTP method in uppercase

ctx.runtime Fields (browser)

FieldTypeDescription
ctx.runtime.executedBeforeboolWhether executed before in current page lifecycle
ctx.runtime.executionCountintExecution count in current page lifecycle (starts from 1)
ctx.runtime.triggerstringTrigger source (for example load, hashchange)

ctx.status Field

FieldPhaseTypeDescription
ctx.statusresponseintCurrent response status code

Helper Matrix

Helperbrowserrequestresponse
ctx.base64YesYesYes
ctx.persistYesYesYes
ctx.headersNoYesYes
ctx.bodyNoYesYes
ctx.flowNoYesYes
ctx.fsNoYesYes
ctx.clientNoYesYes
ctx.devNoYesYes
ctx.netNoYesYes
ctx.dumpNoYesYes
ctx.responseNoYesYes
ctx.proxyNoYesYes

ctx.base64

  • ctx.base64.encode(text) -> string
  • ctx.base64.decode(text) -> string

ctx.persist

Persisted key/value storage isolated by SAFE_UID.

request/response:

  • ctx.persist.get(key) -> any
  • ctx.persist.set(key, value) -> void
  • ctx.persist.del(key) -> void
  • ctx.persist.list(prefix?) -> Array<{key: string, value: any}>

browser (async):

  • ctx.persist.get(key) -> Promise<any | undefined>
  • ctx.persist.set(key, value) -> Promise<void>
  • ctx.persist.del(key) -> Promise<void>
  • ctx.persist.list(prefix?) -> Promise<Array<{key: string, value: any}>>

Constraints:

  • list returns full results sorted by key (ascending).
  • ctx.safe_uid must be non-empty to access ctx.persist.
  • key/prefix are trimmed. Empty key cannot be used for get/set/del.
  • Values passed to set must be JSON-serializable.
  • No extra app-layer encryption is provided.

ctx.headers (request/response)

  • ctx.headers.get(name) -> string
  • ctx.headers.getValues(name) -> string[]
  • ctx.headers.getAll() -> Record<string, string[]>
  • ctx.headers.set(name, value) -> void
  • ctx.headers.add(name, value) -> void
  • ctx.headers.del(name) -> void

Notes:

  • ctx.headers.set(name, null) or ctx.headers.set(name, undefined) deletes the header.
  • ctx.headers.set(name, array) deletes existing values first, then adds each array item as a separate header value.
  • ctx.headers.add(name, value) appends one stringified value. null/undefined is ignored.

ctx.body (request/response)

  • ctx.body.getText(opts?) -> string
  • ctx.body.getJSON(opts?) -> any
  • ctx.body.getForm(opts?) -> Record<string, string[]>
  • ctx.body.set(body, opts?) -> void

opts:

FieldTypeDefaultDescription
max_bytesint1048576Max bytes for get* read
content_typestringemptyOverride Content-Type on set

Notes:

  • ctx.body.set(...) updates Content-Length and clears Content-Encoding and ETag.
  • In ctx.body.set(body, ...), string values are written as-is, null/undefined writes an empty body, and other values are JSON-encoded before writing.

ctx.flow (request/response)

  • ctx.flow.get(key) -> any
  • ctx.flow.set(key, value) -> void
  • ctx.flow.del(key) -> void
  • ctx.flow.list(prefix?) -> Array<{key: string, value: any}>

Constraints:

  • key/prefix are trimmed. Empty key cannot be used for get/set/del.
  • Values passed to set must be JSON-serializable.
  • list returns full results sorted by key (ascending).

ctx.fs (request/response)

  • ctx.fs.exists(path) -> bool
  • ctx.fs.readText(path, opts?) -> string
  • ctx.fs.readJSON(path, opts?) -> any
  • ctx.fs.stat(path) -> object
  • ctx.fs.list(path) -> string[]

Parameter constraints:

  • path must be absolute.
  • ctx.fs.readText(...) and ctx.fs.readJSON(...) read at most max_bytes bytes. If the file exceeds the limit, an error is thrown.
  • ctx.fs.readJSON(...) parses file content as JSON and returns the decoded value.
  • ctx.fs.list(...) returns direct child names only, without parent paths, sorted by name in ascending order.

opts:

FieldTypeDefaultDescription
max_bytesint1048576Max bytes for readText/readJSON file read

ctx.fs.stat(path) returns:

FieldTypeDescription
is_fileboolWhether the path is a regular file
is_dirboolWhether the path is a directory
sizeintFile size in bytes
mod_time_unixintModification time as a Unix timestamp in seconds
modeintFile mode value

ctx.client (request/response)

  • ctx.client.id -> string
  • ctx.client.id comes from the current client identity injected by ingress. It may be empty when no client context is attached.

ctx.dev (request/response)

  • ctx.dev.id -> string
  • ctx.dev.online() -> bool

Notes:

  • ctx.dev.id is currently read from /lzcapp/var/_lzc_ext/dev.id.
  • ctx.dev.online() reads cached status only. The cache is refreshed in background by lzcinit for the current request UID.

ctx.net (request/response)

  • ctx.net.joinHost(host, port) -> string
  • ctx.net.via.local() -> object
  • ctx.net.via.host() -> object
  • ctx.net.via.client(id) -> object
  • ctx.net.reachable(protocol, host, port, via?) -> bool

Notes:

  • protocol currently supports tcp, tcp4, and tcp6.
  • host accepts either a container-reachable hostname or an IP literal.
  • ctx.net.via.local() returns { type: "local" }, meaning the current container network.
  • ctx.net.via.host() means accessing the lzcos host network through remotesocket.
  • ctx.net.via.client(id) means accessing a specific client node network through remotesocket.
  • reachable(...) performs a live network probe with a default timeout of about 1200ms.
  • via is optional; when omitted, the current container network is used.

ctx.dump (request/response)

  • ctx.dump.request(opts?) -> string
  • ctx.dump.response(opts?) -> string

opts:

FieldTypeDefaultDescription
include_bodyboolfalseInclude body text
max_body_bytesint4096Max bytes for dumped body

ctx.response (request/response)

  • ctx.response.send(status, body?, opts?) -> void

opts:

FieldTypeDefaultDescription
headersobjectemptyAdditional response headers
content_typestringtext/html; charset=utf-8Content-Type override
locationstringemptyRedirect location (required for 301/302/303/307/308)

Notes:

  • headers values can be single values or arrays. Arrays add multiple values for the same header.
  • Header fields with null values are not written.

ctx.proxy (request/response)

  • ctx.proxy.to(url, opts?) -> void

opts:

FieldTypeDefaultDescription
use_target_hostboolfalseRewrite Host to target host
timeout_msint5000Per-request proxy timeout in milliseconds
pathstringemptyOptional path rewrite
querystringemptyOptional query rewrite without ?
viaobjectemptyOptional network path object, usually from ctx.net.via.local(), ctx.net.via.host(), or ctx.net.via.client(id)
on_failstringkeep_originalFailure policy: keep_original or error

Notes:

  • url must include scheme and host.
  • If path is not set, the target URL path is used first. If the target URL has no path, the original request path is kept.
  • If query is not set, the target URL query is used first. If the target URL has no query, the original request query is kept.

Execution Model Constraints

  • request/response phases are synchronous (no Promise / async support).
  • browser can use async APIs (for example ctx.persist Promise methods).