@alienplatform/bindings
v3.3.11
Published
Direct TypeScript bindings for Alien storage, kv, queue, vault, and postgres over an in-process napi-rs addon
Maintainers
Readme
@alienplatform/bindings
Direct TypeScript bindings for Alien storage, kv, queue, vault, linked-container
discovery, and Postgres over an
in-process napi-rs addon. The addon itself lives in the Rust
crate crates/alien-bindings-node; this package is the published JavaScript
wrapper that loads it.
Remote Storage
Use Bindings.forRemoteDeployment from a trusted backend to access a Storage
resource in an existing deployment. Never put the Alien API token in browser,
mobile, or other client-side code. The token must have write access to the
deployment; read-only tokens cannot resolve cloud credentials.
import { Bindings } from "@alienplatform/bindings"
const bindings = await Bindings.forRemoteDeployment({
deploymentId: process.env.ALIEN_DEPLOYMENT_ID!,
token: process.env.ALIEN_API_TOKEN!,
})
const archive = bindings.storage("archive")
const write = await archive.put("reports/latest.json", Buffer.from(JSON.stringify({ ready: true })), {
attributes: {
contentType: "application/json",
cacheControl: "private, max-age=60",
metadata: { schema: "report-v1" },
},
})
const head = await archive.head("reports/latest.json")
const object = await archive.get("reports/latest.json")
const report = JSON.parse(object.data.toString())
console.log(write.eTag, head.meta, head.attributes, report)
const reports = await archive.list("reports/")
await archive.delete("reports/latest.json")Cloud storage providers persist these object attributes. The local filesystem
provider rejects attribute-bearing writes because it cannot represent them.
GCS also rejects contentEncoding: "gzip": its decompressive transcoding omits
the response length required for byte-exact reads. Other GCS encodings, such as
br, are preserved.
Remote Storage exposes get, put, head, list, and delete. It does not
expose copy or signed URLs. The same Bindings and Storage handles remain valid
while the native client refreshes short-lived cloud credentials and periodically
rediscovers the deployment's assigned manager. Rotating the Alien API token
requires constructing a new Bindings value. Pass apiBaseUrl only when
targeting a non-default Alien API endpoint; plain HTTP is accepted only on a
loopback address for local development.
The named resource must be a Running, Frozen S3, GCS, or Azure Blob Storage resource with remote access enabled. Enabling remote access adds concrete object read/write/list/delete access for that bucket or container to the deployment's dedicated Remote Bindings identity. Generate and apply updated customer setup when enabling it on an existing deployment. The endpoint returns a short-lived lease for that Remote Bindings identity only after it validates the named resource, so the Alien token and all returned provider credentials must be treated as backend secrets.
Linked containers
The same factories are re-exported by @alienplatform/sdk for Worker apps.
Long-running Container and Daemon apps can import this package directly. A
linked container is read-only service discovery:
import { container } from "@alienplatform/bindings"
const database = container("database")
const internalUrl = await database.getInternalUrl()
const publicUrl = await database.getPublicUrl() // string | nullUse the internal URL for calls between resources in the same deployment. Use the public URL only when the caller is outside that private network.
Postgres
Postgres is connection-only: every backend speaks the same wire protocol, so the binding hands back connection details and your app connects with its own driver. Resolving a managed cloud backend (Aurora, Cloud SQL, Flexible Server) reads the password from that cloud's secret store using the workload's own identity — the binding itself only ever carries a locator for it.
import { Client } from "pg"
import { postgres } from "@alienplatform/bindings"
const conn = await postgres("my-db").connection()
// Field style: node-postgres parses a URL's sslmode and would override `ssl`, so
// pass the fields when you need `conn.ssl` to take effect.
const client = new Client({
host: conn.host,
port: conn.port,
database: conn.database,
user: conn.username,
password: conn.password,
ssl: conn.ssl,
})
await client.connect()conn.connectionString is the same details as a postgres:// URL, with the
credentials percent-encoded, for drivers that take one.
External (BYO) Postgres bindings use verified TLS by default. Their sslMode
policy is deliberately limited to "verify-full" and "disable" because
node-postgres cannot represent libpq's opportunistic prefer fallback without
owning the connection attempt. Use "disable" only as an explicit compatibility
opt-out for a plaintext-only server; missing legacy configuration defaults to
"verify-full".
Native addon resolution
Importing the package never loads the addon, so the package remains
sideEffects: false. Environment-backed factories load it on the first binding
operation. Bindings.forRemoteDeployment loads it immediately because manager
discovery is part of that async constructor. src/loader.ts resolves it in
order:
ALIEN_BINDINGS_ADDON_PATH— an explicit path to a.nodefile. A dev/test escape hatch only; never set in a published install.- The per-platform prebuild package
@alienplatform/bindings-<triple>, pulled in as anoptionalDependency. This is how end users get the addon:npm/buninstalls only the package matching the hostos/cpu/libc. TheoptionalDependenciesblock exists only in the published manifest — it is injected at publish time by the release pipeline, so a workspace checkout carries none. - Dev fallback: a locally-built addon at
crates/alien-bindings-node/alien-bindings-node.<triple>.node, found by walking up from the installed package. Loaded only if itsversion()matches this package's version (a stale build is warned about and rejected).
Local development
Build the addon for your host once, then run anything that imports the package:
bun run build:addon # or: pnpm -C packages/bindings run build:addonbuild:addon runs napi build --platform --release against
crates/alien-bindings-node and drops the .node next to the crate, where the
loader's dev fallback (step 3 above) finds it. Rebuild after changing any Rust
in alien-bindings or alien-bindings-node. The built .node is gitignored.
build:addon only builds for the host triple; on a Mac, cross-building the
other mac triple (e.g. darwin-x64 from an arm64 host) needs an explicit
napi build --release --target x86_64-apple-darwin --cwd
../../crates/alien-bindings-node.
To point the loader at an addon somewhere else, set ALIEN_BINDINGS_ADDON_PATH
to its path (step 1).
Prebuild packages (npm/)
npm/<triple>/ holds the skeleton for each published per-platform package
(darwin-arm64, darwin-x64, linux-x64-gnu, linux-arm64-gnu). Each carries
a package.json (name/os/cpu/libc/main/files) and a README; the
.node is staged in at build time and is never committed. There is no musl
target: the deployment base images are glibc (chainguard/wolfi-base), not Alpine.
The release pipeline builds each addon on its native runner, stages it into the
matching npm/<triple>/ dir, rewrites the placeholder 0.0.0 versions to the
release version, injects the exact-version optionalDependencies into this
package's published manifest, and publishes the platform packages before the
wrapper. Pinning the exact version is what guarantees a published wrapper only
ever loads the matching-version platform addon.
