Connect to a private database
In this example, we are going to build a connector for a database that your hosted product cannot reach directly. A Worker reads the database connection from Vault and exposes named operations as Commands.
The Worker runs in the same environment as the database. Your product sends an operation and receives its result; it does not need network access to the database or a copy of its password.
Your product invokes a named database operation. A Worker in the customer environment reads the connection from Vault, queries the private database, and returns the result.
We will describe the Worker, Vault, and KV cache in alien.ts. Then we will read the connection and implement the database operations in src/index.ts.
Describe the connector in alien.ts
const credentials = new alien.Vault("credentials").build()
const cache = new alien.Kv("cache").build()
const connector = new alien.Worker("connector")
.code({ type: "source", src: "./", toolchain: { type: "typescript" } })
.commandsEnabled(true)
.link(credentials)
.link(cache)
.permissions("execution")
.build()Vault is secret storage created in the deployment. .link(credentials) makes its binding available only to the connector, and the permission profile grants the connector the specific Vault and KV operations listed by the stack.
Read the connection where it is used
async function getConnectionConfig() {
const credentials = await vault("credentials")
const raw = await credentials.get("database")
return JSON.parse(raw)
}Your product calls the Command and receives its result. It does not need the database connection itself.
Choose the operations your product can call
command("test-connection", async () => {
const config = await getConnectionConfig()
return { connected: true, database: config.database, host: config.host }
})
command("query", querySchema, async ({ sql, useCache }) => {
await getConnectionConfig()
return runQuery(sql, { useCache })
})The example uses sample data locally. Replace runQuery with your database client. For a production connector, prefer specific operations over accepting arbitrary SQL.
Run it locally
alien init data-connector-ts
alien dev
alien dev commands invoke --deployment default --command test-connection --params '{}'The complete source includes the Vault setup, cache, input validation, and sample data.
Put the connector beside the database
alien releasePublishes a version. Nothing is deployed for a customer yet.
alien onboard acme-corpCreates a deployment link for that customer.
The customer opens the link and deploys into their environment.
After the customer provides the Vault value, your control plane can invoke test-connection and the other named Commands without a route to the database itself.
What you built
You built a narrow API around a private database. The customer keeps the connection in Vault, the Worker opens it locally, and your control plane receives operation results rather than database credentials or general network access. Operations that make several database calls keep those calls on the customer's network, which can also reduce latency and data transfer.
Source: examples/data-connector-ts.