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

@odla-ai/apps

v0.15.2

Published

The odla platform management SDK — create apps, toggle services (db, o11y, blog, ai, calendar), and delete apps via the registry. Control plane only; data-plane SDKs like @odla-ai/db are what running apps link.

Downloads

1,427

Readme

@odla-ai/apps

⚠️ Early access — pre-1.0. Agents work from bounded runbooks; humans approve credentials, production changes, releases, and merges. APIs and exact package availability can change. Review the documented guarantees and limitations; this software is MIT-licensed and provided without warranty.

The odla platform management SDK — the control-plane client for the app registry, the way gcloud is to GCP. Use it from agents, CLIs, and CI to create apps, toggle services (db, o11y, blog, ai, calendar, …), and archive apps. It is not a data-plane SDK: apps talk to their database with @odla-ai/db, emit telemetry with @odla-ai/o11y, and so on — those SDKs are what a running app links; this one is what manages apps.

An app is the platform's project primitive. Services keep their own credentials and data planes; the registry owns app identity, ownership, service enablement, monotonic configuration revisions, and the operation journal. Registration is platform-level and à la carte — an app can enable blog without ever enabling db.

Every app view includes a random incarnation. The appId is the reusable project address; the incarnation is the exact lifetime at that address. Purging and recreating the same id rotates it. Exact project grants, delegated authority, immutable consumption receipts, and service lifecycle requests bind that value, so delayed work from the old project cannot act on the replacement. Wildcard project policy remains intentionally dynamic over projects the manager owns now.

Ask the runbooks first. odla's operational procedures live in a database, not in this file: npx @odla-ai/cli runbook ask "<question>" returns the current steps, and unlike anything written here it cannot be out of date. Use it before searching the web or working from memory. This README and the JSDoc in the shipped .d.ts are the version-matched API reference; a runbook is the procedure. Most tasks need an answer from both.

Install

npm i @odla-ai/apps

Use from a Worker (service binding)

import { createAppsClient } from "@odla-ai/apps";

const apps = createAppsClient({ fetcher: env.APPS, token: env.APPS_TOKEN });
const app = await apps.resolveApp("my-app");
if (!(await apps.isEnabled("my-app", "o11y", { env: "dev" }))) {
  return new Response("o11y not enabled for this app", { status: 403 });
}

Use over HTTP

const apps = createAppsClient({ endpoint: "https://odla-apps.example.workers.dev", token: MACHINE_TOKEN });
const created = await apps.createApp({ name: "My App", appId: "my-app" });
await apps.setService(created.appId, "o11y", true, { env: "dev" });

// Record where each environment's deployment RUNS — shown on the app in
// Studio and readable via the public-config endpoint. Null clears it.
await apps.setLink("my-app", "prod", "https://my-app.example.com");
const app = await apps.resolveApp("my-app");
app?.links.prod; // "https://my-app.example.com/"

// Enable + configure the ai service (non-secret half: provider + default
// model, surfaced on public-config). The provider API KEY goes in the
// platform vault — odla-db tenant secrets — never in the registry.
await apps.setAi("my-app", "prod", { provider: "anthropic", model: "claude-sonnet-5" });

// Configure live Google booking. This call stores non-secret intent only; a
// human opens the returned consentUrl. Event data remains in Google.
await apps.setCalendar("my-app", "dev", {
  provider: "google",
  access: "book",
  bookingCalendarId: "primary",
  availabilityCalendars: ["primary"],
  bookingPageUrl: null,
});
const attempt = await apps.beginGoogleCalendarConnect("my-app", "dev");
console.log(attempt.consentUrl);
const status = await apps.getCalendar("my-app", "dev");

Selective-release review and approval

@odla-ai/apps carries the Registry contract shared by Studio and the CLI. Creating a promotion release plan stores an immutable review document; it does not call a provider or mutate a source or target. Each target includes its validated @odla-ai/promotion bundle, exact before values and digests, explicit identifier mappings, exclusions, precondition observations, and non-secret provider-readiness evidence.

const plan = await apps.createPromotionReleasePlan("built-not-found", input);
const status = await apps.getPromotionReleaseStatus("built-not-found", plan.planId);

A directly signed-in human may call approvePromotionRelease for either apply or rollback. The approval is short-lived and binds the action, plan digest, and complete target set. requestPromotionReleaseOperation accepts that approval only from an enrolled-device session; an ordinary agent token, a human session, a changed digest, a changed app lifetime, a blocked plan, or an expired approval fails closed. A repeated device idempotency key returns the same durable operation. The operation is a dependency-ordered journal: an enrolled device leases one exact target step with claimPromotionReleaseWork, performs only that bounded payload, and commits evidence with recordPromotionReleaseWork. An expired lease is safely reclaimed after a follower exits; a retry or target rejection remains visible per app. activate_revision is always last and accepts only a receipt proving the planned higher revision. Cancellation is allowed before activation; after any target activates, recovery requires a separately approved rollback operation, which also publishes a higher revision instead of rewriting history.

Every plan resolves target-local tenant, route, worker, service bindings, Stripe mode and target Price IDs, and calendar mode before approval. Dev targets require test Stripe and sandbox calendar identities. Source provider IDs and unknown resolution fields fail closed instead of being copied across modes.

App-service catalog

APP_SERVICE_CATALOG is the versioned, content-free vocabulary shared by the Registry, Studio, and CLI. Each entry separates its product kind, same-env dependencies, lifecycle controller, and Studio management behavior from the app's mutable enabled value. Services that own a first-class app workspace also declare its canonical id, label, icon, and ordering here:

import {
  APP_SERVICE_CATALOG_SCHEMA_VERSION,
  appServiceDefinition,
} from "@odla-ai/apps";

console.log(APP_SERVICE_CATALOG_SCHEMA_VERSION); // odla.app-services/v2
console.log(appServiceDefinition("chat")?.requires); // ["db"]
console.log(appServiceDefinition("code")?.workspace?.id); // code

Unknown ids fail closed in Registry and project-config validation. Add a new enableable service here first; consumers derive their inventories and dependency checks from this catalog instead of carrying local lists.

Studio handoff URLs

Use studioAppSettingsPath when an SDK, CLI, readiness check, or operation receipt needs to send an operator to the setting that owns an action:

import { studioAppSettingsPath } from "@odla-ai/apps";

studioAppSettingsPath("my-app", "dev"); // /studio/apps/my-app/dev/settings/environment
studioAppSettingsPath("my-app", "prod", "app"); // /studio/apps/my-app/prod/settings/app
studioAppSettingsPath("my-app", "prod", "backups"); // /studio/apps/my-app/prod/settings/backups

The explicit final segment is intentional. Environment settings own services, Code defaults, end-user auth, AI configuration, and the deployment link. App settings own repository binding, name, owners, category, lifecycle, and the danger zone. The selected environment remains in an app-settings URL as return context; it does not make those controls environment-scoped. Backups settings own the selected environment's restore points and portable database snapshots, plus app-wide repository archive limits when Harness is enabled.

For an interactive chooser, call beginGoogleCalendarConnect(appId, env) and poll the returned attempt. A healthy result has connected === true, writable === true, and state === "healthy". Use listGoogleCalendars to choose the booking calendar and one through ten availability calendars, then persist that non-secret intent with setCalendar.

Calendar OAuth is a separate human checkpoint. The management SDK receives only an opaque attempt and authorization URL; Google codes, access tokens, and refresh tokens stay inside the platform connector. Use listGoogleCalendars and disconnectCalendar for the owner-safe lifecycle. The optional public booking-page URL is a legacy fallback, not a credential.

This management surface owns connection and non-secret configuration, not event data. Trusted app backends use @odla-ai/calendar for live FreeBusy, upcoming-event reads, and idempotent create/reschedule/cancel operations. Google is the single source of truth; there is no sync, resync, retention workflow, or event mirror. Passing { purge: true } to disconnectCalendar is rejected; public config exposes only aggregate connection/bookability state.

disconnectCalendar stops watches and deletes only that app/environment connection's encrypted platform token, cursors, and connector state. It does not revoke the shared user-to-Google-OAuth-project grant, because a project-wide revoke could invalidate the user's other odla connections. A future explicitly global revoke operation would need cross-connection accounting and warning.

New automation should always name the environment. For backward compatibility, passing services to createApp enables them in both default environments, and omitting env from setService/isEnabled targets the legacy prod alias. Those shortcuts are intentionally not the dev-first golden path.

Conditional configuration operations

App.configRevision is the Registry compare-and-set revision (registry:<positive integer>). Every managed name, service, auth, link, category, and lifecycle write advances it. A reconciler freezes that revision, desired/observed content digests, and ordered actions into a plan before calling applyConfigOperation:

const app = await apps.resolveApp("my-app");
if (!app?.configRevision) throw new Error("Registry does not support conditional config");

const receipt = await apps.applyConfigOperation("my-app", {
  schemaVersion: "odla.config-operation-request/v1",
  expectedRevision: app.configRevision,
  desiredRevision: plan.desiredRevision,
  observedRevision: plan.observedRevision,
  planDigest: plan.planDigest,
  idempotencyKey: "deploy-2026-07-29-my-app",
  source: { kind: "api", version: "reconciler-1" },
  actions: plan.actions,
});

Do not hand-author actions: consume a frozen odla.config-plan/v2 document. The server verifies that the plan digest binds both content revisions, the Registry revision, and every ordered action. Reservation happens before any effect. A stale revision, another running app operation, or reuse of an idempotency key for different bytes fails with a stable conflict.

getConfigOperation(appId, operationId) reads the same journal without replaying effects. Retrying applyConfigOperation with the same app, idempotency key, and plan resumes the first incomplete step; a step whose effect committed before its progress update is recovered from Registry state. A terminal operation returns the same digest-authenticated receipt on every retry.

This release conditionally applies app display-name changes, non-destructive service enable/configure actions, and deployment links when their frozen plan does not require a human checkpoint. Production actions, app creation, auth propagation, service disablement, archive/purge, and every secret or credential remain outside this endpoint. Approval-marked, high-risk, and Studio actions are rejected before an operation is reserved.

Credential caveats (agents provisioning with a dev token)

  • A developer token authenticates one named agent principal. It does not inherit its manager's projects: ordinary Studio approval grants project metadata access, PM execution/Backlog proposals, discussion participation, and brand-candidate editing on selected exact projects only. PM planning/Ready approval, app administration, brand approval, and ambient owner access are excluded. CRM reference reads are also excluded by default; the approving owner may explicitly select the unchecked read-only crm.read option for those exact projects.
  • The provisioning CLI deliberately requests optional app.manage for its one exact app. Once the owner approves that immutable request, the agent may create a reserved missing app, configure its services, auth, and link, and administer that app's sibling-service tenants. Ownership, rename/category, and lifecycle mutations remain direct-human operations.
  • Reusing the same agent-requested, human-approved handle reconnects a fresh ordinary handshake to the existing agent principal. The handle is covered by the immutable request digest; approval cannot rewrite it. Approval leaves the current credential live; it also leaves the current grant set unchanged. Successful replacement collection atomically retires older collected ordinary-handshake credentials and replaces the principal's manager-issued grants with the reviewed exact project set. Newly selected projects are unavailable before collection and omitted projects are revoked during the switch. Manually minted and separately scoped credentials remain explicit inventory items.
  • Baseline agents cannot create arbitrary projects, administer tenants, or mint durable app credentials. A provision handshake is the narrow exception: its owner-reviewed app.manage grant and exact-id bootstrap reservation authorize only the selected app lifetime. Other authority-expanding effects still need a signed-in human or a consumed one-action approval receipt.
  • Pre-principal developer tokens are migrated without project grants and fail closed (legacy_reenrollment_required). Re-enroll each automation as a named agent and select its exact projects; the migration never guesses ambient authority from historical ownership.
  • resolveApp() returns only projects visible to the authenticated principal; null means absent or unauthorized and deliberately does not reveal which.
  • Minting a db key (POST /admin/apps/:tenant/keys) is additive: existing keys keep working, so provisioning reruns never break deployed Workers.
  • setAuth(appId, env, { publishableKey }) needs only the Clerk publishable key; the issuer is derived and applied to that env's db tenant. Workers should fetch the resulting public-config at runtime (short cache) instead of baking auth into env vars — key rotation then needs no redeploy.

Principals and project authority

The registry resolves the actor from the bearer credential. Its exported Operator keeps two identities separate:

  • developerId is the accountable human account used for app ownership.
  • principalId, principalKind, displayName, and handle identify the human, agent, or service that actually used the credential.
  • credentialId / credentialKind identify that credential.
  • managerPrincipalId is organizational metadata only. It never grants an agent access to a manager's projects.
  • delegatedByPrincipalId, grantId, and grantVersion preserve the revocable authority used for the action.

Project grants are resolved server-side from the live registry immediately before an action. Clients supply a bearer credential, not a principal, manager, or grant claim. A revoked grant therefore denies the next action, and changing an agent's display label cannot change either its identity or its authority. An exact grant also binds the app incarnation; a same-id recreation does not revive it. Historical receipts remain audit evidence but cannot replay as current authority in a later incarnation. Here, immutable means append-only through the Registry contract and read-only through its public SQL view. Registry code and operators holding the underlying D1 binding remain trusted; receipts are not cryptographic tamper evidence against a compromised control-plane writer.

This remains true for a shared project run by three humans: each person can manage a friendly named agent, but every agent keeps its own credential and only the exact project grants that a human approved. Neither co-ownership nor manager attribution permits impersonation. An authority-expanding effect must consume a one-action approval receipt bound to the resource, actor, credential, live grant revision, expiry, and idempotency key.

Signed-in human owners approve one exact change through consumeHumanExactAuthority(appId, input). The SDK sends only the capability, project capability, effect, exact resource, action digest, and retry key. The registry derives the Clerk-bound human identity, short-lived self-grant, and immutable receipt; callers cannot submit an actor, grant, expiry, or evidence. An identical retry returns the original receipt, while reusing the retry key for a different action fails. This is the approval boundary for changes such as accepting an agent's brand proposal—not a switch that disables unused features.

A provisioned app normally has a different Clerk issuer and subject namespace from odla Studio. It must not send that local bearer to verifyOperator or persist or exchange either Clerk session. A machine-authenticated service-binding client calls verifyAppHuman(appId, env, appToken) for the owner projection and consumeAppHumanExactAuthority(appId, env, appToken, input) for an exact approval receipt. The service credential is transport authority only: every call verifies the local JWT against the exact configured issuer and audience, normalizes its signed canonical email, requires exactly one active platform human with that email, and rechecks the app/auth lifetime and current ownership. Missing, invalid, unmatched, or ambiguous emails, backend keys, agents, devices, removed owners, and stale app/auth configuration remain denied. Never log or persist the Clerk bearer.

Provisioning contract

Service Workers implement POST /svc/enablement (PROVISION_PATH); the registry calls it when an operator toggles the service for an app, and stores the returned service-owned config (e.g. an o11y serviceId). Hosted services are enabled only after their controller acknowledges the operation. Missing bindings/credentials and unknown services fail closed; ai and blog are registry-owned capabilities, as declared by APP_SERVICE_CATALOG. Deletion calls destroy for every provisioned environment, including disabled services whose data was retained. Partial failures leave the app record in place and return structured operation status so an idempotent retry can finish cleanup. Every controller request carries app.incarnation; service controllers keep their physical tenant or Durable Object incarnation separate and compare the Registry lifetime before suspend, resume, destroy, backup-policy, or delayed sink work. calendar is a registry-owned connector: enablement stores non-secret intent, disable suspends booking access while retaining connector state, and destroy deletes that app/environment's encrypted token and state without revoking the shared Google project grant. There are no odla-db event-mirror rows to purge. The SDK preserves structured failures on AppsError.details.