npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@render-lab/tasks-render

v0.2.6

Published

Durable Render control-plane tasks for Render Workflows: deploys, provisioning, convergent deletion, diagnostics, and scaling.

Downloads

506

Readme

@render-lab/tasks-render

⚠️ Experimental: proof of concept. This package is part of the Render Tasks POC and is published for testing only. It is not fully tested or production ready. Task names, inputs, outputs, and behavior can change or break in any release. Pin exact versions and expect breaking changes.

Durable Render control-plane tasks for Render Workflows. A first-party pack (ADR-0015) — the workflow runs on Render, so orchestrating Render itself is first-party, not "one cloud provider among many."

Scope is deliberately narrow: the async orchestration verbs that benefit from durability — deploy, scale, suspend/resume, provision, convergent deletion, and bounded deploy diagnostics. This is not an API mirror. Low-level lookup, pagination, log filtering, and resource CRUD stay inside the package's internal RenderPort; they are not registered as one Workflow task per API endpoint.

import {
  triggerDeploy,
  awaitDeploy,
  provisionService,
  deleteResource,
  getDeployDiagnostics,
} from "@render-lab/tasks-render";

| Task | Input | Output | | --- | --- | --- | | render.getService | { serviceId } | ServiceDTO | | render.triggerDeploy | { serviceId, clearCache?, commitId? } | { serviceId, deployId, status } | | render.awaitDeploy | { serviceId, deployId } | { serviceId, deployId, status, live } | | render.scaleService | { serviceId, numInstances?, plan? } | { serviceId, numInstances, plan } | | render.suspendService | { serviceId } | { serviceId, suspended } | | render.resumeService | { serviceId } | { serviceId, suspended } | | render.provisionPostgres | { name, ownerId?, plan?, region?, version?, … } | PostgresDTO | | render.provisionKeyValue | { name, ownerId?, plan?, region?, maxmemoryPolicy? } | KeyValueDTO | | render.createPrivateService | { name, repo? \| image?, branch?, ownerId?, … } | { serviceId, name, status, live, url } | | render.provisionService | discriminated union for web_service, private_service, background_worker, or static_site | { service, created, deployId, status, live } | | render.createProject | { name, ownerId?, environmentName? } | { project: { id, name }, environmentId } | | render.deleteProject | { projectId } | { projectId, deleted, alreadyMissing } | | render.deleteResource | { kind: "service" \| "postgres" \| "keyValue" \| "disk", id } | { kind, id, deleted, alreadyMissing } | | render.getDeployDiagnostics | { serviceId, deployId, maxBytes?, maxLines? } | { deploy, logs, failureReason, truncated, nextStartTime } |

Deploy, then durably wait — the headline pattern

render.triggerDeploy kicks a deploy and returns its deployId; render.awaitDeploy durably polls until it is live (return) or hits a failure terminal (throw a distinct error a human should see). Splitting them keeps the non-idempotent trigger out of the poll loop — the CI/CD "promote, then gate" shape, mirroring github.mergeWhenGreen.

const { deployId } = await triggerDeploy({ serviceId });
await awaitDeploy({ serviceId, deployId }); // throws until live / failed

Provision + wait ready — idempotent by name

provisionPostgres, provisionKeyValue, createPrivateService, and provisionService create a resource and then durably poll until it is ready. Because the durable poll re-runs the whole task, the create is made idempotent by name (find-or-create): a re-run finds the in-flight resource and keeps waiting rather than provisioning a duplicate. Use unique, stable names per environment (e.g. orders-db-pr-42).

provisionService is the general service entry point. Its discriminated union supports web services, private services, background workers, and static sites. Existing services are reused only when immutable fields such as type and runtime are compatible; incompatible matches fail rather than silently changing the resource.

Group resources under a project + environment

createProject is find-or-create by name: it lists the owner's projects, reuses a match, and otherwise creates the project with a single environment (environmentName, default "production"). Because a retried or resumed deploy re-runs the task, matching by name keeps it from duplicating the project. It returns the project plus that environment's id, which you thread into every provision so the resources land inside the environment rather than floating in the workspace:

const { project, environmentId } = await createProject({ name: "acme-pr-42" });
await provisionService({ type: "web_service", name: "api-pr-42", environmentId, /* … */ });
await provisionPostgres({ name: "orders-db-pr-42", environmentId });

environmentId is optional on provisionService, provisionPostgres, and provisionKeyValue; omit it to create a floating workspace resource as before.

deleteProject deletes an empty project and treats a missing one as alreadyMissing: true. It does not cascade — the Render API rejects the delete while any environment still holds resources — so delete the contained services and datastores (via deleteResource) first, then the project last.

Convergent deletion

deleteResource deletes services, Render Postgres instances, Render Key Value instances, and disks by ID. Missing resources are treated as already deleted and returned with alreadyMissing: true, which makes cleanup workflows safe to retry.

Bounded deploy diagnostics

getDeployDiagnostics fetches deploy metadata plus bounded build/runtime log context. The port owns log pagination, filtering, control-character cleanup, and byte/line limits, so the task returns a compact DTO with truncation metadata instead of unbounded logs.

Install

pnpm add @render-lab/tasks-render @renderinc/sdk

@renderinc/sdk is a peer dependency. HTTP goes through @render-lab/tasks-core's shared client — no vendor SDK.

Environment contract

| Variable | Required | Purpose | | --- | --- | --- | | RENDER_API_KEY | yes (at first use) | Render API key. Read lazily on the first call (ADR-0007). | | RENDER_OWNER_ID | for provision* / createPrivateService | Default owner (team/user) id for created resources. Overridable per-input via { ownerId }. |

Durability notes

  • The durable retry re-runs the whole task.
  • triggerDeploy is not idempotent — a retry after a network failure can kick a second deploy. Where exactness matters, trigger once and rely on awaitDeploy to wait rather than on the retry to re-fire the trigger.
  • scaleService, suspendService, resumeService set an absolute target, so retrying is safe.
  • provision*, provisionService, and createPrivateService are idempotent by name (see above), so their create-then-poll retry does not duplicate resources.
  • deleteResource is convergent, so retrying cleanup does not fail on a resource that is already gone.
  • getDeployDiagnostics is read-only and bounded. Use the Dashboard, CLI, or Render MCP for exploratory browsing and unbounded log analysis.