Job-side TypeScript runtime SDK for PROOF Applications that run on Acurast and are bootstrapped by Liskov.
This package is the code that a job imports before its Application starts. It is not a Liskov server SDK, deployment tool, control-plane client, wallet library, or executor library. It runs inside the customer job's Acurast runtime and provides the default Liskov boot path:
- Acurast environment and
_STD_lookup. - Acurast runtime identity, signing, and decrypt helpers.
- Liskov runtime-env fetch and refresh.
- Managed runtime secrets.
- Built-in encrypted Liskov logging.
- Bounded Liskov runtime diagnostics and health events.
- Runtime readiness/status and test hooks.
SDK v0.3.39 exposes a read-only snapshot from signed bootstrap:
const runtime = await bootstrapSlipwayRuntime();
const applicationUid = runtime.context?.application.uid;
const updatedContext = await runtime.refreshRuntimeContext();context is undefined when the server omits it. application.uid is the
stable key; name and displayName are labels. The WAN IP and IP-derived
geography describe this job's observed network; check the geolocation status
before treating it as current. Refresh makes one signed request and replaces
the snapshot only on success. It starts no polling or backoff and never logs
the context. LiskovRuntimeContextRefusedError carries code, status, and
retryable (429/503 are retryable; replay 409 is not). A refresh requires
a signed bootstrap binding; otherwise it throws SlipwayRuntimeNotReadyError.
The first supported dependency source is the public GitHub release tag:
{
"dependencies": {
"@proof-computer/liskov-runtime": "github:proof-computer/liskov-runtime-js#v0.3.39"
}
}npmjs publication is a separate release step and is not required for the initial runtime cutover.
The package tarball intentionally contains only dist, LICENSE,
README.md, SECURITY.md, and package metadata. Example source and tests
stay in the repository.
Runtime v0.3.21 opts Liskov-owned POST requests into the server response tunnel
used by Acurast processors that omit successful httpPOST response bodies. The
adapter unwraps the original 2xx status and JSON before bootstrap, secrets, or
logging callers see it; ordinary fetch transports and servers that do not
recognize the opt-in header retain their existing behavior.
The next release runs on Acurast's iOS processor. There httpPOST is
deprecated and the global fetch fails, so on process.platform === "ios" the
SDK sends its own requests over Node's http/https modules
(defaultRuntimeFetch()), and createAcurastRuntimeFetch() gives a job the same
choice: Node's modules on iOS, otherwise the httpPOST adapter, else the global
fetch. The choice is by platform, so a request is never sent twice. iOS also
answers an empty string from environment(name) for an unset name; the SDK
treats an empty value as unset, so the job and processor ids come from
_STD_.job.getId() and _STD_.device.getAddress().
Runtime v0.3.22 adds identity-bound v2 diagnostics and a terminal application
boundary. handle.diagnostics.report(...) sends ordinary signed events, while
handle.diagnostics.fatal(...) is first-call-wins, closes health and logging,
and makes one bounded signed attempt before the caller terminates. Applications
can install installLiskovRuntimeProcessFailureHandlers(...), attach the handle
immediately after bootstrap, and choose an explicit "continue" or "exit"
policy for unhandled rejections. Bootstrap failures after identity resolution
are reported even when bootstrap never returns a handle.
Runtime v0.3.23 treats each process boot within an Acurast registration as a
distinct runtime instance. The SDK creates and signs one runtime-bootstrap
nonce per process and reuses it across HTTP retries. New backends return that
nonce as runtimeInstanceId, which the SDK binds into signed
proof.liskov.runtime-diagnostic.v3 events; older responses remain supported
through the v2 diagnostic fallback.
Runtime v0.3.24 makes the canonical Application UID authoritative for new first-party runtime sessions while preserving the legacy Application ID in every compatibility surface. Runtime bootstrap v2 carries both identifiers; signed Runtime Environment v2, secret request/response/encrypted-payload v2, logging config v2, and runtime diagnostics v4 bind them where applicable. A UID-bearing request fails closed on a missing UID, binding mismatch, or protocol downgrade; v1-v3 contracts remain available for previously published jobs.
Runtime v0.3.25 makes a successful signed bootstrap authoritative over legacy bootstrap configuration delivered in the initial environment. This preserves the UID from the v2 response for Runtime Environment v2, secrets protocol v2, and runtime diagnostics v4 instead of silently continuing on the legacy identifier-only configuration.
Runtime v0.3.26 propagates that authenticated UID into the optional
status().applicationUid field, runtime-start capability attributes, and the
base structured log record. Legacy v1 inputs continue to omit the field; the
SDK never derives a UID from an Application slug.
Runtime v0.3.27 exposes cooperative cease through the supported bootstrap API.
Registering onCease advertises cooperative_cease.v1 on UID-bound V4
diagnostics; older V2/V3 paths do not advertise a command they cannot receive.
The SDK validates the identity-bound command, invokes the asynchronous handler
at most once per command in each process, and retries the signed outcome on a
later check-in if acknowledgement delivery was lost. A new process may handle
a still-pending command after restart.
Version 0.3.39 adds opt-in application readiness on signed V4 diagnostics.
Enable applicationReadiness: true at bootstrap, then call
runtime.applicationReady() once the application can serve. This is separate
from SDK readiness (whenReady() / status().ready).
Use bootstrapSlipwayRuntime() before importing Application code:
import { bootstrapSlipwayRuntime } from "@proof-computer/liskov-runtime";
const runtime = await bootstrapSlipwayRuntime({
component: "worker",
revision: process.env.APP_REVISION
});
try {
await runtime.log("app.boot");
await runtime.whenReady();
await import("./app.js");
} finally {
await runtime.flush();
runtime.stop();
}whenReady() is a fail-fast check, not a long polling loop. It resolves with
the current status when every required capability is ready, and throws
SlipwayRuntimeNotReadyError with the current status when a required
capability is pending, failed, or blocked.
Opt in when the application needs time to load or initialize after SDK bootstrap:
const runtime = await bootstrapSlipwayRuntime({ applicationReadiness: true });
await runtime.whenReady(); // Required SDK capabilities are ready.
await startApplication(); // Resolves once the application can serve.
runtime.applicationReady();With the option, every signed V4 diagnostic, including runtime.start and
runtime.health, carries applicationReadiness: "pending" until
applicationReady() is called, then "ready" on every later diagnostic.
The method is synchronous, idempotent, never throws, and sends no immediate
check-in. It does not change whenReady() or status().ready; those describe
the SDK's required capabilities, which can be ready while the application is
still pending. Without the option, the method has no effect and the SDK adds
no readiness attribute. V1, V2 and V3 diagnostics never add it.
Release and tag the SDK and deploy the server readiness changes before relying on this signal to delay predecessor shutdown.
bootstrapSlipwayRuntime() returns:
interface BootstrapSlipwayRuntimeHandle {
readonly home: string;
readonly env: {
get(name: string): string | undefined;
require(name: string): string;
};
status(): SlipwayRuntimeStatus;
whenReady(): Promise<SlipwayRuntimeStatus>;
applicationReady(): void;
log(
event: string,
details?: Record<string, unknown>,
options?: { severity?: "debug" | "info" | "warn" | "error"; labels?: Record<string, string> }
): Promise<void>;
flush(): Promise<{ ok: boolean; state: string; flushed: number; pending: number; dropped: number; message?: string }>;
refreshNow(): Promise<SlipwayRuntimeEnvLoadResult | undefined>;
stop(): void;
}Additional readback fields are present for diagnostics and tests:
runtimeEnv, lockbox (the secrets readback, under its compatibility key), and
runtimeHealth. They are diagnostic fields, not the product API; application
code should normally use env, status, whenReady, applicationReady, log, flush,
refreshNow, and stop.
stop() is synchronous and idempotent for the current handle shape. It cancels
runtime-env refresh, runtime-health timers, and background secret retries. Call
flush() first when a one-shot job needs to give logging a final chance.
The top-level options are intentionally small and testable:
await bootstrapSlipwayRuntime({
appId: "application-id",
component: "worker",
revision: "git-or-artifact-revision",
home: "/runtime/.slipway",
secrets: { mode: "required" },
logging: { mode: "background", earlyBufferMaxRecords: 100 },
runtimeHealth: { intervalMs: 30_000, initialDelayMs: 30_000 },
onCease: async (command) => {
await stopApplicationWork(command.reason);
},
diagnostics: (event) => console.error(JSON.stringify(event))
});Common options:
appId,component,revision: metadata added to status, diagnostics, and logging records where available.home: explicit state root. Defaults toLISKOV_HOME, then$HOME/.slipway, then/tmp/slipway.secrets.mode:required,background, oroff.secrets.retry: background retry budget. Defaults areinitialDelayMs=0,intervalMs=5000,maxElapsedMs=60000, andmaxAttempts=12.logging.mode:required,background, oroff. The default isbackground.logging.earlyBufferMaxRecords: in-memory log records to keep before logging config is available. Default:100.logging.spoolMode:auto,disk, ormemory.logging.spoolDir: override the logging spool directory.logging.timeoutMs: network timeout for logging writes.logging.onError: observes logging failures without breaking the runtime wrapper.diagnostics: local callback for redacted runtime diagnostics.diagnosticSendTimeoutMs,diagnosticRemoteBackoffMs: bounds for remote runtime-diagnostic delivery.runtimeHealth: optional interval/initial-delay/send-timeout overrides forruntime.healthdiagnostics.applicationReadiness: opt in withtrueto report application readiness on signed V4 diagnostics. Defaults to off; callapplicationReady()once the application can serve.onCease: asynchronous cooperative application-work shutdown. Registering it advertisescooperative_cease.v1on UID-bound V4 diagnostics; Liskov never stops the paid on-chain job.
Test hooks:
env: process-env replacement.std: Acurast_STD_replacement.environment: Acurastenvironment(name)replacement.identityProvider: fake identity/sign/decrypt provider.fetchImpl: fake network implementation.nowMs,randomBytes: deterministic clock and nonce/digest inputs.setTimeoutImpl,clearTimeoutImpl: deterministic timer harness.
Runtime values are resolved from:
- The supplied
options.env, orprocess.env. - Acurast
_STD_.env. - Acurast
environment(name).
Use the runtime accessor after bootstrap because runtime-env and secrets may install values during startup:
const webhookUrl = runtime.env.require("WEBHOOK_URL");
const optionalMode = runtime.env.get("FEATURE_MODE") ?? "default";require() throws Liskov runtime env <NAME> is required when the value is
absent.
Liskov jobs receive compact public bootstrap config through
LISKOV_BOOTSTRAP (the legacy PROOF_SLIPWAY_BOOTSTRAP and
PROOF_SLIPWAY_URL names are no longer read):
{
"v": 1,
"u": "https://slipway.example",
"a": "application-id",
"p": "64-character-policy-digest",
"d": "deployment-id",
"x": {
"t": "diagnostics-token",
"h": { "i": 30000, "d": 30000, "to": 1500 }
}
}Expanded keys such as slipwayUrl, applicationId, policyDigest,
deploymentId, diagnostics.token, and diagnostics.health are also
accepted.
When the bootstrap is present, the runtime signs a
proof.slipway.runtime-env-request.v1 request and POSTs it to
/api/jobs/runtime-env. The response must bind the same application id,
policy digest, deployment id, job id, and processor id. Returned values are
installed into runtime env before managed secrets are requested.
refreshNow() forces an immediate runtime-env refresh when the bootstrap
config exists, then performs one deduped secrets attempt if
background secrets are still pending, then refreshes logging. The current v0
periodic runtime-env refresh is internal; Applications should use
refreshNow() when they need an explicit reload.
The signed runtime bootstrap is sent to /api/jobs/runtime-bootstrap on the
core URL, compiled in as https://runtime.liskov.proof.computer;
LISKOV_CORE_URL overrides the compiled-in core URL.
Managed secrets are a built-in Liskov runtime capability. Jobs receive compact
secret bootstrap config through LISKOV_LOCKBOX_BOOTSTRAP:
{
"v": 1,
"u": "https://secrets.liskov.proof.computer",
"a": "application-id",
"g": "grant-id",
"p": "64-character-policy-digest",
"d": "deployment-id",
"s": ["secret-id"]
}Lockbox is the internal name of the managed-secrets service; it survives only in compatibility identifiers such as this environment name and the diagnostic stage ids below, which Applications read or set but never need to learn as a product.
Required mode is the default when secret bootstrap config exists:
const runtime = await bootstrapSlipwayRuntime({
secrets: { mode: "required" }
});Bootstrap waits for the secret request, verifies the encrypted payload, installs returned env/file secrets, and fails closed if the request is rejected or the payload does not verify.
Background mode is for Applications that can boot in a locked or degraded mode:
const runtime = await bootstrapSlipwayRuntime({
secrets: {
mode: "background",
retry: {
initialDelayMs: 0,
intervalMs: 5_000,
maxElapsedMs: 60_000,
maxAttempts: 12
}
}
});Bootstrap returns before the first secret request. The secrets capability
reports pending, degraded, failed, or ready, but it is not a readiness
blocker because it is not required. refreshNow() performs one immediate
attempt while the retry budget is still open. stop() cancels scheduled
background retries.
Use secrets: { mode: "off" } for jobs that intentionally ignore secret
bootstrap values.
Env secrets are installed into runtime env by name. An authenticated signed
bootstrap is authoritative for its current job and replaces ambient values
left by a reused runtime. An env-delivered bootstrap keeps existing values.
When a signed grant owns blackbox-log-config, logging buffers until that
current config is installed; it never attaches an older job's ambient sink
config.
File secrets require the compact bootstrap's file-base field, f. File
targets are written below that directory with mode 0600; path traversal
outside the base directory is rejected.
The secret request carries the processor's response encryption key, read from
_STD_.job.getEncryptionKeys(). The runtime accepts two encrypted-payload
envelopes:
| Processor key | version |
curveName |
Decrypted through |
|---|---|---|---|
| P-256 | acurast-p256-hkdf-aes-256-gcm-v1 (-v2 on the v2 payload domain) |
secp256r1 |
_STD_.signers.secp256r1.decrypt |
| secp256k1 | acurast-secp256k1-hkdf-aes-256-gcm-v1 |
secp256k1 |
_STD_.signers.secp256k1.decrypt |
A P-256 key is always preferred. The secp256k1 key is used only when the
processor exposes no P-256 key, which matches the key Acurast selects for the
processor's acknowledgement. A version paired with the other curve's name is
refused. When the processor exposes neither key, bootstrap fails with
lockbox_response_key_missing.
Liskov logging is the runtime's built-in encrypted log capability. Blackbox is
its internal name, which survives only in the BLACKBOX_* compatibility
values below. Application code should call runtime.log() instead of
constructing a log writer:
await runtime.log("worker.tick", { processed: 12 }, {
severity: "info",
labels: { component: "worker" }
});
const result = await runtime.flush();The runtime validates and attaches logging after runtime-env and secret
installation. If a log is written before logging config is available, the
runtime keeps it in the early in-memory buffer. When config appears later,
refreshNow() or the next log() drains the buffer into encrypted log
records.
The default background logging mode never blocks readiness. Use
logging: { mode: "required" } only when missing or invalid logging config
must make the Application non-ready. Use logging: { mode: "off" } to drop
runtime logs intentionally.
Accepted config shapes:
- Pre-bound sink:
sinkId+jobId+writeUrl+dek, with an optionalresumeUrl. This remains the preferred production provisioning mode. Older configs derive/resumeonly whenwriteUrlends in/events. - Factory token:
factoryToken+baseUrl+dek. The writer self-registers the job-bound sink on first flush and receives the same write, resume, and canonical-chain contract as a pre-bound sink.
Both shapes can be supplied as BLACKBOX_LOG_CONFIG JSON or expanded
BLACKBOX_* env values. Records are encrypted locally before upload and
posted batches contain no plaintext log messages. Disk spool state defaults to:
$LISKOV_HOME/logging/spool
Every config defaults to the hkdf-sha256-ed25519-v1 writer derivation; newly
provisioned configs also record that value explicitly as writerKeyDerivation.
Every invocation therefore derives the same Ed25519 request writer from the
protected 32-byte log DEK: HKDF-SHA256 uses UTF-8 salt
proof.liskov.blackbox.writer-key.v1, UTF-8 info Ed25519, and a 32-byte
output interpreted as an Ed25519 seed. This keeps sibling invocations on one
canonical append chain while separating the writer key from record encryption.
Low-level callers can still supply an explicit signer for an unmarked config;
the managed runtime does not use that compatibility override.
When disk spool is unavailable in auto mode, the writer falls back to memory.
Before constructing a new batch, the runtime resolves the server's canonical
head in either provisioning mode. If another writer advances the sink between
that resolution and upload, the runtime consumes the conflict response's head
and retries the encrypted pending batch with at most three sequence rebases.
The encrypted records themselves are unchanged. Invalid or inconsistent
resume, success, or conflict heads fail closed through logging.onError while
the spool remains intact. Some Acurast runtimes omit the body of a successful
201 callback: after an accepted write the SDK resolves the signed server head,
and after a created factory registration it performs one idempotent replay.
Both paths keep the server authoritative and leave the spool intact if the
follow-up cannot prove the committed position.
Unknown config shapes report through diagnostics and logging.onError; they do
not silently degrade to a no-op.
Runtime diagnostics are best-effort and bounded. When
Liskov bootstrap is available and the runtime can authenticate with either a
diagnostics token or the Acurast runtime identity provider, diagnostics are
POSTed to /api/jobs/runtime-diagnostics as
proof.slipway.runtime-diagnostic.v1. Signed-bootstrap jobs do not need a
diagnostics token; the request carries a runtime signature, job id, and
processor address when identity is available.
Useful stages include:
runtime.startslipway.runtime_env.identityslipway.runtime_env.signedslipway.runtime_env.fetchslipway.runtime_env.responseslipway.runtime_env.appliedlockbox.secret_request.identitylockbox.secret_request.signedlockbox.secret_request.fetchlockbox.secret_request.responselockbox.secret_request.decryptedlockbox.secret_request.installedlockbox.secret_request.retryslipway.logging.attachslipway.logging.writeslipway.logging.bufferruntime.health
Local diagnostic callbacks and remote diagnostic sends use a 1.5 second default timeout. Remote diagnostic failures pause further remote diagnostic attempts for 30 seconds so startup, runtime-env, and secret-request flows cannot be blocked by observability.
Health diagnostics start under the same authentication rule as other remote
diagnostics. Defaults are a 30 second initial delay and 30 second interval.
Compact bootstrap health fields x.h.i, x.h.d, and x.h.to, or the
matching expanded fields, override interval, initial delay, and send timeout.
Diagnostics redact string fields that look like tokens, secrets, private keys, signatures, passwords, or authorization values. Count and boolean presence fields are retained.
Use status() for redacted readback:
const status = runtime.status();
if (!status.ready) {
console.error(status.blockers);
}Status shape:
interface SlipwayRuntimeStatus {
ok: boolean;
ready: boolean;
home: string;
applicationUid?: string;
applicationId?: string;
deploymentId?: string;
revision?: string;
blockers: Array<{ capability: string; code: string; message: string }>;
capabilities: {
runtimeEnv: CapabilityStatus;
secrets: CapabilityStatus;
logging: CapabilityStatus;
diagnostics: CapabilityStatus;
switchboard: CapabilityStatus;
};
}Capability states are off, pending, ready, degraded, failed, or
blocked. A capability blocks readiness only when required=true and
state !== "ready".
Current v0 behavior:
runtimeEnvis required when the bootstrap config is present under either name.secretsis required only in required mode.loggingis required only in required mode.diagnosticsis non-fatal and reports ready once the local emitter exists.switchboardis reported as off by this package; Switchboard readiness lives in@proof-computer/slipway-switchboard.
The runtime does not call _STD_.net.addAllowedHostnames() implicitly.
Acurast only admits hosts to the unrestricted outbound whitelist when the
deployment owner has configured the required forward and reverse _acu.* DNS
TXT proofs for each hostname/IP. Until Liskov owns and documents those records
for a host, the runtime must make ordinary network requests and report any
network failure through diagnostics.
The runtime is designed to be tested without live Acurast spend:
const env: Record<string, string | undefined> = {
LISKOV_BOOTSTRAP: JSON.stringify({
v: 1,
u: "https://slipway.test",
a: "app",
p: "1".repeat(64),
d: "42"
})
};
const runtime = await bootstrapSlipwayRuntime({
env,
identityProvider: fakeIdentityProvider,
fetchImpl: fakeFetch,
nowMs: () => 1_000,
logging: { spoolMode: "memory" },
setTimeoutImpl: fakeSetTimeout,
clearTimeoutImpl: fakeClearTimeout
});Use logging.spoolMode: "memory" in deterministic unit tests. Use
secrets.mode: "background" plus fake timers to prove pending/degraded/ready
state without sleeping. Use the local diagnostics callback for redacted event
assertions.
The repository tests prove runtime-env, required/background/off secrets, factory-token logging, early buffer drain, config refresh, diagnostics, health, DNS-gated no-allowlist behavior, and source-only Acurast examples without artifact pins or live deployment.
Source-only example ports live under examples/:
examples/acurast-env-vars: reads runtime-env values, posts only a redacted env summary, and writes throughruntime.log().examples/acurast-fetch: fetches a price payload, posts a webhook payload, and writes a Liskov runtime log.
The Switchboard webserver example lives in
public_repos/slipway-switchboard-js/examples/acurast-webserver because
Switchboard ingress is optional and stays in a separate adapter package.
These examples are complete for the current no-spend documentation baseline. The next package-cleanup boundary is server-side Turn 6 factory-token product flow alignment, not more selected Acurast example ports.
- Do not put Liskov server control tokens in runtime env or diagnostics.
- Do not put plaintext runtime secrets in Liskov runtime-env.
- Runtime secrets must come from the managed-secrets service and be encrypted to the job response encryption key.
- HTTPS is required for Liskov, secrets, and logging URLs outside local/test hosts unless an explicit insecure override is supplied.
- Signed runtime-env and secrets protocol v2 requests bind Application UID, compatibility application id, policy digest, deployment id, job id, processor id, nonce, and expiry.
- Managed-secret encrypted payloads must bind payload digest, request/response fields, and requested secret ids before installation.
- File-target secrets are written only under the configured base directory.
@proof-computer/liskov-runtimeruns inside the job TEE. Liskov control plane services, the managed-secrets and logging services, and CLI/server workflows are separate off-TEE systems.- This package does not make Switchboard a required dependency. Use
@proof-computer/slipway-switchboardonly for Liskov-managed Switchboard ingress jobs.
See SECURITY.md for the release checklist.
Run the release gates before tagging:
pnpm install --frozen-lockfile
pnpm typecheck
pnpm test
pnpm build
pnpm pack:dry-runThe ./encrypted-code export verifies an AES-256-GCM payload before loading a
self-contained CommonJS module that exports async start(runtime). The caller
first completes bootstrapSlipwayRuntime and passes that same handle; the
payload must not bootstrap a second runtime. startEncryptedApplication
requires a matching, installed, UID/deployment-bound managed secret named by the
public descriptor, delivered to LISKOV_CODE_KEY. An ordinary environment value
alone is refused. Keys use canonical standard base64 encoding of 32 random bytes.
The processor also needs a working response key for its secret grant: P-256,
or secp256k1 when it exposes no P-256 key (see Response Encryption Key).
The Android implementation requires Android 12 or later for P-256; a DataEncryption
advertisement alone does not establish P-256 support. lockbox_response_key_missing
identifies this processor key, while LISKOV_CODE_KEY is the separate application
AES key. Follow the encrypted JavaScript guide
for processor selection, paused setup and runtime verification.
The non-secret descriptor and encrypted payload belong in the immutable public
bootstrap ZIP. The ZIP's attested digest is the authority for both. Ciphertext
and plaintext SHA-256 digests, a 12-byte IV, a 16-byte authentication tag, and
AAD binding the protocol domain, secret id and plaintext digest are verified
before execution. Source is written exclusively in a fresh private directory,
loaded through the CommonJS loader, and removed after start returns or fails.
The runtime home is created privately when absent, and the loaded module is
removed from the CommonJS cache during cleanup. No shared
plaintext cache or network code URL is accepted. Do not put secrets or plaintext
application code in the public bootstrap or ZIP extras.
Failures emit a bounded application.encrypted_code.refused.<phase> diagnostic
before the stable encrypted_code_start_failed fatal event. Exception text,
private source and key material are never included in those diagnostics.
Runtime 0.3.30 and Actions v1.3.2 completed the production encrypted path
on 6 September 2026: job 160393 verified its managed grant, loaded the payload,
and emitted signed application completion. Actions supplies a runtime home
inside the processor job directory, where filesystem access is permitted.
The capability matrix
retains the separate registered V5 public-release boundary.
The existing managed-secrets trust boundary still applies:
PROOF can access the code key during managed release. This is not a claim of
operator-blind execution or a Cargo private-image capability.
Version 0.3.31 supports authenticated absolute file destinations as well as
legacy relative names below fileBaseDir. The default Node installer stages the
file group, uses private 0600 files, rejects symlinks and traversal, and recovers
interrupted replacements. It applies environment values after successful file
installation. File contents preserve whitespace and newlines.
Custom RuntimeFileWriter implementations must provide installGroup(files)
with commit-or-rollback behavior for absolute destinations. Existing relative
custom writers remain supported. Rebuild deployed artifacts to upgrade the SDK.
SDK 0.3.32 also consumes the optional v2 secrets.customerRequired hint.
Required customer groups block readiness; optional-only groups are discovered
and loaded in background mode by default, and an absent optional grant does not
block startup. An explicit caller secret mode still takes precedence.
SDK 0.3.33 keeps the signed runtime.health loop for a job whose bootstrap
delivers no environment (runtimeEnv.enabled: false). Earlier versions
dropped the whole runtime config in that case and never checked in after
bootstrap, so core reported every such runtime as contact lost. The
runtime-env refresh stays off for those jobs; only the check-ins run.
From v0.3.34, this package is licensed under the
Functional Source License, Version 1.1, ALv2 Future License
(SPDX FSL-1.1-Apache-2.0). The licensor is Moose Labs Ltd. You may use,
copy, modify, and redistribute the SDK for any purpose other than a Competing
Use, as the license defines it. Building and running your own Applications on
it is a Permitted Purpose. Each version becomes available under the
Apache License, Version 2.0 on the second anniversary of the date it was
released.
The change applies from v0.3.34 onward only. Release tags up to and including
v0.3.33 remain as they shipped: their package.json declares MIT.
collectNetworkSample measures the same bounded network ladder as the Cargo
runtime against https://liskov-network-prober.fly.dev. Use the challenge token
from the probe's authorization; it is sent as the t query parameter. The
sample runs for at most 30 seconds, with UDP before streaming downloads and
fixed-length zero uploads, then the prober receipt. Transfers do not retain the
download body in memory. The URL is pinned; a different proberUrl returns
invalid_response evidence.
import { collectNetworkSample, networkSampleOutcomes } from "@proof-computer/liskov-runtime";
const networkSample = await collectNetworkSample({
token: authorization.challenge,
startedAtMs: Date.now()
});
const outcomes = networkSampleOutcomes(networkSample);Collection resolves to the existing NetworkSampleV1 contract with derived
metrics. Network failures and unavailable Node modules become failed or
unreachable steps; HTTP sampling continues when UDP is unavailable. A sample
without a usable receipt still carries its measured legs at low confidence.
networkSampleOutcomes returns exactly bandwidth-download, bandwidth-upload
and udp-path, including failed-leg bytes and errors, for coverage admission.
For offline tests, inject a NetworkTransport with elapsedUs, prepare,
udp, download, upload and receipt methods and optional close cleanup.
The optional now function supplies monotonic milliseconds to the default
transport. This API uses node:https, node:dns/promises and node:dgram;
it does not require the global fetch function.