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.envNoYesYes
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).
  • 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

ctx.body (request/response)

  • ctx.body.getText(opts?) -> string
  • ctx.body.getJSON(opts?) -> any
  • ctx.body.getForm(opts?) -> Record<string, 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.

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}>

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[]

ctx.env (request/response)

  • ctx.env.get(name) -> string | undefined
  • ctx.env.list(prefix?) -> Record<string, string>

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:

FieldTypeDescription
headersobjectAdditional response headers
content_typestringContent-Type override
locationstringRedirect location (required for 301/302/303/307/308)

ctx.proxy (request/response)

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

opts:

FieldTypeDescription
use_target_hostboolRewrite Host to target host
timeout_msintPer-request proxy timeout
pathstringOptional path rewrite
querystringOptional query rewrite without ?
on_failstringFailure policy: keep_original or error

Execution Model Constraints

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