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

@geostack/arc

v0.1.3

Published

Arc SDK and CLI for guarding high-risk AI actions.

Readme

@geostack/arc

Arc makes high-risk AI actions safe with permissions, approvals, signed execution, and audit.

Arc does not run your app logic. Your app owns the action implementation. Arc verifies authority, asks for approval when policy requires it, signs the execution request, delivers it to your app, and records the audit trail.

Define Actions

import { arc } from "@geostack/arc";

export const actions = arc.defineActions({
  issue_refund: {
    name: "Issue refund",
    risk: "high",
    defaultDecision: "ask",
    input: {
      type: "object",
      required: ["amount", "customerId"],
      properties: {
        amount: { type: "number" },
        customerId: { type: "string" }
      }
    }
  }
});

risk must be low, medium, high, or critical. defaultDecision must be allow, ask, or block.

Handle Signed Execution

import express from "express";
import { arc } from "@geostack/arc";
import { actions } from "./actions.js";
import { invocationStore, nonceStore } from "./arc-stores.js";

const app = express();
app.use(express.json());

app.post("/arc/execute", arc.handleAction(actions, {
  issue_refund: async ({ input, appUserId, invocationId }) => {
    // Enforce app-side idempotency by invocationId before side effects.
    // Store the in-progress/completed record in durable storage shared by all app instances.
    if (await refundAlreadyHandled(invocationId)) {
      return getStoredRefundResult(invocationId);
    }

    return issueRefund(appUserId, input);
  }
}, {
  apiUrl: "https://app.geostack.xyz",
  nonceStore,
  invocationStore
}));

handleAction() verifies Arc's ES256 JWS, body hash, timestamp freshness, nonce replay hook, invocation idempotency, and signature claims before dispatching your handler.

For lower-level integrations, call verifyArcRequest(req, { jwks, nonceStore }) directly. The nonce store must return false for replayed nonces. Verification fails with nonce_store_required when no store is supplied.

Invocation idempotency is fail-closed the same way: handleAction() / verifyArcExecution() / validateArcInvocation() require an invocationStore that returns false for already-processed invocation ids, and fail with invocation_store_required when no store is supplied. This matters because Arc's automatic delivery retries re-sign with a fresh nonce but keep the same invocation_id — a nonce store alone cannot stop a retry (or a replayed envelope hitting another instance) from double-executing a refund.

For production, use durable nonce replay and invocation idempotency storage shared by every app instance. The SDK's memory stores are local development helpers only and must be enabled explicitly with unsafeAllowInMemoryNonceStore / unsafeAllowInMemoryInvocationStore. A production app that verifies without durable nonce and invocation storage is not safely integrated with Arc.

Your app should also treat invocation_id as an idempotency key before performing side effects, because Arc may retry delivery after network failures or 5xx responses. A robust handler writes an idempotency row before the side effect and stores the final result when the side effect completes. If the process crashes after the app side effect but before Arc records success, Arc will mark the invocation outcome unknown rather than blindly retrying; your app's idempotency record is the source of truth for reconciliation.

Minimal nonce store contract:

export const nonceStore = {
  async useNonce(nonce: string, expiresAt: Date) {
    // Atomically insert nonce with TTL. Return false when it already exists.
    const result = await redis.set(`arc:nonce:${nonce}`, "1", {
      NX: true,
      PXAT: expiresAt.getTime()
    });

    return result === "OK";
  }
};

Minimal invocation idempotency store contract:

export const invocationStore = {
  async useInvocation(invocationId: string) {
    // Atomically record the invocation id. Return false when it was already processed.
    const result = await redis.set(`arc:invocation:${invocationId}`, "1", { NX: true });

    return result === "OK";
  }
};

Input Schema Validation

Pass inputSchema to verifyArcExecution / validateArcInvocation to validate the signed input against your action's JSON Schema before your handler runs.

The SDK validates the input with full JSON Schema validation via ajv (and ajv-formats), exactly as the Arc server does — so the SDK rejects precisely what the server rejects. Every JSON Schema feature is enforced: nested objects, array items, nested required, deeply nested property type, enum, format, pattern, minimum/maximum, additionalProperties, allOf/anyOf/oneOf, $ref, and so on. There is no lightweight fast-path that could under-validate and silently accept input the server would reject.

ajv and ajv-formats ship as dependencies of this package, so validation works out of the box — there is nothing extra to install. The validator is still lazily imported only when you actually pass an inputSchema, so handlers that never validate input never load it; an empty schema ({}) imposes no constraints and is accepted without loading the validator.

Validation failures throw ArcRequestVerificationError with code invalid_input and never echo the offending input value into the error message; a stored schema that is itself uncompilable throws invalid_action_schema (also fail-closed). In the unlikely event the validator cannot be loaded at all, the SDK fails closed with code schema_validator_unavailable rather than accepting unvalidated input.

await verifyArcExecution(req, {
  jwks,
  nonceStore,
  invocationStore,
  inputSchema: actions.issue_refund.input
});

strictSchema is deprecated and now a no-op: full Ajv validation is always applied to every non-empty schema, so there is nothing left to opt into.

Sync Actions

arc config set --api-url https://app.geostack.xyz
arc app create "Refund App" --execute-url https://your-service.example.com/arc/execute
arc actions sync ./src/actions.ts

The CLI stores local configuration in ~/.arc/config.json. It never stores app API keys. Dev agent tokens are only stored when you create them with arc agent dev-token, and the CLI labels them as local development credentials.

Invoke Locally

arc agent dev-token
arc invoke issue_refund --app refund-app --input '{"amount":480,"customerId":"cus_123"}'
arc approvals list
arc approvals approve <approval_id>
arc audit tail

Allowed invocations are queued for signed delivery. Asked invocations create approvals. Blocked invocations never execute.

Drive the CLI from an AI Agent

Every command is non-interactive (no stdin, no TTY) and supports a global --json flag: stdout carries exactly one JSON object/array, errors go to stderr as {"error":{"code","message"[,"status"]}}, and exit codes are 0 success, 1 usage/validation or 4xx, 2 transport/5xx.

export ARC_API_URL="https://app.geostack.xyz/api"   # hosted API base (or your self-hosted URL)
export ARC_AGENT_TOKEN="arc_agent_..."              # console -> Agents

arc agent whoami --json
arc agent apps --json
arc agent invoke --app <id-or-slug> --action <key> --input '{"amount":50}' --json

arc setup-prompt (alias arc agent-setup) prints a copy-paste prompt that walks Claude Code/Codex through the full setup: install, env vars, guarding your highest-risk action, and verifying one invocation end to end. See AGENTS.md for the machine-oriented guide, and https://geostack.xyz/docs/ai-setup for the docs page.

HTTP Clients

import { ArcDeveloperClient, ArcAgentClient } from "@geostack/arc";

const developer = new ArcDeveloperClient({ baseUrl: "https://app.geostack.xyz" });
await developer.devLogin({ email: "[email protected]" });

const agent = new ArcAgentClient({
  baseUrl: "https://app.geostack.xyz",
  agentToken: "arc_agent_..."
});

The clients return Arc API JSON directly and throw ArcHttpError with status, code, and message for non-2xx responses.

Production Notes

This SDK is V1 developer tooling, not a claim that the whole Arc stack is ready for public production traffic. Before public launch, run Arc with a production signing key, persistent app-side nonce storage, app-side idempotency by invocation_id, observability around failed/unknown executions, and network egress controls. The local Docker stack and its runtime-generated development signing key are for local development only — production config rejects the dev signing-key id and refuses to boot without a real key.