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

@epicuri/atlas-sdk

v0.1.0

Published

The Atlas SDK provides a thin TypeScript client for executing Atlas Move entry functions and view calls over the Aptos blockchain. Phase 1 focuses on the core client surface – a single `AtlasClient` exposing `entry` and `view` primitives, strongly typed e

Readme

Atlas SDK (Phase 1 Skeleton)

The Atlas SDK provides a thin TypeScript client for executing Atlas Move entry functions and view calls over the Aptos blockchain. Phase 1 focuses on the core client surface – a single AtlasClient exposing entry and view primitives, strongly typed error reporting, and transaction policy controls aligned with the Epicuri Atlas plan.

Installation & Configuration

pnpm install
pnpm --filter @epicuri/atlas-sdk build

Publishing to npm

The package is intended to be public on npm. After merging the desired changes into main, publish with:

  1. Authenticate once via npm login (or ensure your npm token is available).
  2. Run pnpm run release:publish from a clean checkout.

The script builds the SDK and invokes pnpm publish --access public, which uploads the @epicuri/atlas-sdk tarball to the public npm registry.

AtlasClient wraps the official @aptos-labs/ts-sdk. You can pass any AptosSettings when constructing the client, alongside optional defaults for transaction ordering, submission mode, maximum gas, and a default signer.

import { AtlasClient } from "@epicuri/atlas-sdk";
import { AptosConfig, Account, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({ network: Network.DEVNET });
const alice = Account.generate();

const client = new AtlasClient({
  aptos: config,
  signer: alice,
  txOrdering: "ordered",
});

Entry Calls

entry executes Move entry functions using the official Aptos transaction pipeline. It returns a Result that either contains a submitted transaction or a simulation result, or an AtlasError variant when something goes wrong.

const result = await client.entry(
  "0x1::aptos_account::transfer",
  [],
  ["0x2", 1_000_000],
);

if (result.ok) {
  console.log("Submitted", result.value.hash);
} else {
  console.error("Entry failed", result.error);
}

SubmitOpts

SubmitOpts can be provided per call to override the client defaults:

  • txOrdering: 'ordered' | 'nonordered' (defaults to the client setting). When 'nonordered', the SDK injects a cryptographically strong random u64 replay protection nonce generated from 8 secure random bytes.
  • mode: 'submit' | 'simulate' (defaults to 'submit'). 'simulate' builds and simulates the transaction without submitting it.
  • maxGas: Optional bigint that limits the maximum gas amount.
  • signer: Overrides the signer used to build and sign the transaction.
  • feePayerAddress/feePayerSigner: Provide a sponsored transaction configuration. When mode='submit', both fields must be set and the signer’s address must match the provided fee payer address.
  • settlement: 'committed' | 'pending' (defaults to 'committed'). 'committed' waits for execution and surfaces the committed transaction, including events and gas usage. 'pending' returns immediately after submission (legacy behavior).
  • waitTimeoutMs: Maximum time in milliseconds to wait for commitment when settlement='committed' (default 30000).
  • pollIntervalMs: Interval in milliseconds between status checks while waiting for commitment (default 500).

When settlement='committed' (the default), AtlasClient.entry polls the fullnode and resolves once the transaction is finalized. The returned SubmittedTx carries the pending response and the committed transaction payload, making emitted events immediately available. If the timeout elapses before commitment, the client returns SettlementTimeout { hash, waitedMs }.

const result = await client.entry(
  "0x1::aptos_account::transfer",
  [],
  ["0x2", 1_000_000],
  { signer: alice },
);

if (result.ok && result.value.settlement === "committed") {
  console.log("Events", result.value.committed.events);
}

Switch back to the legacy pending handle if you want to manage settlement yourself:

const pending = await client.entry(
  "0x1::aptos_account::transfer",
  [],
  ["0x2", 1_000_000],
  { signer: alice, settlement: "pending" },
);

if (pending.ok) {
  console.log("Pending hash", pending.value.hash);
}

Example fee-payer flow covering both simulation and submission:

const alice = Account.generate();
const sponsor = Account.generate();

// Dry-run the transaction (no on-chain submission) while validating sponsor data.
await client.entry(
  "0x1::aptos_account::transfer",
  [],
  ["0x2", 1_000_000],
  {
    mode: "simulate",
    signer: alice,
    feePayerAddress: sponsor.accountAddress.toString(),
    feePayerSigner: sponsor,
  },
);

// After reviewing simulation results, submit using the same sponsor.
await client.entry(
  "0x1::aptos_account::transfer",
  [],
  ["0x2", 1_000_000],
  {
    mode: "submit",
    signer: alice,
    feePayerAddress: sponsor.accountAddress.toString(),
    feePayerSigner: sponsor,
  },
);

Transaction Ordering

  • Ordered (default) – Transactions rely on the on-chain sequence number. The SDK lets the Aptos TS SDK discover the current sequence during build.
  • Non-ordered – Atlas generates a secure random u64 replay protection nonce. Aptos’ orderless pipeline accepts the transaction without advancing the sender’s sequence number, enabling parallel submissions.

View Calls

view proxies to aptos.view and always returns a Result containing the raw Move values returned by the chain. Any simulate flag in the optional argument is ignored (views are read-only by definition per SPEC).

const viewResult = await client.view("0x1::coin::balance", ["0x1::aptos_coin::AptosCoin"], [alice.accountAddress.toString()]);

if (viewResult.ok) {
  const [balance] = viewResult.value;
  console.log(balance);
}

Error Model

All failures surface through the AtlasError discriminated union:

  • MissingSigner, MissingFeePayerSigner, and FeePayerSignerMismatch capture user configuration issues.
  • Abort normalizes Move aborts (module, code, message) from simulations or submissions.
  • SdkError categorizes common Aptos SDK failures (api, network, serialization, timeout, input, unknown).
  • Unknown preserves any unexpected inputs for later debugging.

Successful responses wrap either SubmittedTx (pending or committed submission metadata) or SimulationResult (an array of simulated user transactions) inside the shared Result<T, E> helpers (ok, err).

Phase 1 Scope

This package intentionally omits higher-level module wrappers, domain helpers, tests, or CI wiring. Future phases will layer additional ergonomics and coverage in line with the published Atlas development plan.

Testing and Guarantees

  • pnpm build validates the TypeScript build output matches what ships from src/**.
  • pnpm run abi:check (automatically invoked from pnpm test) compares the on-chain ABI at 0x9531…1557 with the wrapper expectations listed in docs/contracts/ABI_TABLE.md.
  • pnpm test compiles the test tree (tsconfig.tests.json) and runs the Node test runner across unit, wrapper, domain, and localnet smoke suites. The localnet tests assume a running fullnode at http://127.0.0.1:8080/v1 with a faucet at http://127.0.0.1:8083 and the Atlas modules published to 0x95314e637120178029aa8541f24336d2061ccfe84b5d64af6372322d09cf1557.
  • The funded signer used by the tests is managed in tests/support/localnet.ts; update that file only when rotating credentials. Do not edit production sources under src/** to satisfy tests—raise an escalation if the implementation and spec disagree.
  • Whenever a test highlights an ambiguity or regression, stop and clarify expectations with the spec owner rather than patching the runtime code. The runtime remains the source of truth; the test suite enforces that contract without redefining it.

Module Wrappers (Phase 2)

Phase 2 layers thin TypeScript wrappers over every public entry and view in the Atlas core modules. Each wrapper:

  • accepts an AtlasClient instance and a single atlasModuleAddress in the constructor, reusing that address to build fully qualified function names;
  • exposes camel-cased methods that mirror the Move entry/view name (for example append_stepappendStep);
  • expects an args object as the first parameter, followed by optional typeArgs (forwarded unchanged) and the usual SubmitOpts for entries;
  • returns a Result so the caller can pattern-match on .ok/.error without throwing;
  • reshapes frequent view payloads: option::Option<T> becomes T | null, SimpleMap<String, String> becomes Record<string, string>, and vector<Object<...>> becomes an array of object addresses (string[]).

Constructing wrappers

import { AtlasClient, ActionModule } from "@epicuri/atlas-sdk";

const client = new AtlasClient({ signer: aliceAccount });
const atlasModuleAddress = "0x42...";

const action = new ActionModule(client, atlasModuleAddress);

Instantiate whichever module classes you need and keep them alongside your configured AtlasClient for reuse.

Module quickstart

Each snippet below shows one entry call and one view call per module. Replace sample addresses with live object addresses and supply the precise generic type arguments your Move function requires.

import {
  ActionModule,
  CapabilityModule,
  DescriptorModule,
  EdgeModule,
  EntityModule,
  FunctionModule,
  ListenerModule,
  MessageModule,
  NamespaceModule,
  RelationshipModule,
  TagModule,
  TopicModule,
  SubscriptionModule,
} from "@epicuri/atlas-sdk";

const atlasModuleAddress = "0x42...";

const action = new ActionModule(client, atlasModuleAddress);
await action.appendStep(
  {
    action: "0xa11ce",
    name: "ingest",
    description: "Pull raw payload",
    functionObject: "0xf001",
  },
  ["0x1::atlas::Source", "0x1::atlas::Target"],
  { signer: aliceAccount },
);
const actionTags = await action.tags({ action: "0xa11ce" }, ["0x1::atlas::Source", "0x1::atlas::Target"]);

const capability = new CapabilityModule(client, atlasModuleAddress);
await capability.updateRequestSchema(
  { capability: "0xcap", schema: "{"type":"object"}" },
  { signer: aliceAccount },
);
const capabilityDescription = await capability.description({ capability: "0xcap" });

const descriptor = new DescriptorModule(client, atlasModuleAddress);
await descriptor.addTag(
  { descriptor: "0xdesc", tag: "0xtag" },
  ["0x1::atlas::Schema"],
  { signer: aliceAccount },
);
const descriptorTags = await descriptor.getSupportedTags({ descriptor: "0xdesc" }, ["0x1::atlas::Schema"]);

const edge = new EdgeModule(client, atlasModuleAddress);
await edge.setStatusFlat(
  { edge: "0xed9e", status: 1 },
  ["0x1::atlas::Source", "0x1::atlas::Target"],
  { signer: aliceAccount },
);
const edgeNamespace = await edge.namespace({ edge: "0xed9e" }, ["0x1::atlas::Source", "0x1::atlas::Target"]);

const entity = new EntityModule(client, atlasModuleAddress);
await entity.addPublishedTopic(
  { entity: "0xent", topic: "0xt0pic" },
  { signer: aliceAccount },
);
const entitySlug = await entity.slugName({ entity: "0xent" });

const func = new FunctionModule(client, atlasModuleAddress);
await func.setStatus(
  { functionObject: "0xfunc", retire: true },
  { signer: aliceAccount },
);
const funcOwner = await func.owner({ functionObject: "0xfunc" });

const listener = new ListenerModule(client, atlasModuleAddress);
await listener.upsertParameter(
  { listener: "0x1ist", key: "region", value: "eu-west" },
  { signer: aliceAccount },
);
const listenerParams = await listener.parameters({ listener: "0x1ist" });

const message = new MessageModule(client, atlasModuleAddress);
await message.publishMessage(
  {
    listener: "0x1ist",
    entity: "0x3nt1ty",
    payloadObject: "0xpay10ad",
    correlationId: "corr-123",
  },
  ["0x1::atlas::Schema"],
  { signer: aliceAccount },
);
const occurredAt = await message.occurredAt({ message: "0xm3ss" }, ["0x1::atlas::Schema"]);

const namespace = new NamespaceModule(client, atlasModuleAddress);
await namespace.verifyNamespace({ namespace: "0xns" }, { signer: aliceAccount });
const namespaceOwner = await namespace.owner({ namespace: "0xns" });

const relationship = new RelationshipModule(client, atlasModuleAddress);
await relationship.addTag(
  { relationship: "0xrel", tag: "0xtag" },
  ["0x1::atlas::Source", "0x1::atlas::Target"],
  { signer: aliceAccount },
);
const relationshipEdge = await relationship.getEdge({ relationship: "0xrel" }, ["0x1::atlas::Source", "0x1::atlas::Target"]);

const tag = new TagModule(client, atlasModuleAddress);
await tag.updateStatus(
  { tag: "0xtag", newStatus: 1 },
  { signer: aliceAccount },
);
const promoted = await tag.promoteTag({ tag: "0xtag" }, { signer: aliceAccount });
// Tag module has no public views in this branch.

const topic = new TopicModule(client, atlasModuleAddress);
await topic.addMessageSchemaVersion(
  { topic: "0xt0pic", schema: "{"version":2}" },
  { signer: aliceAccount },
);
const topicStatus = await topic.status({ topic: "0xt0pic" });

const subscription = new SubscriptionModule(client, atlasModuleAddress);
await subscription.addTag(
  { subscription: "0xsub", tag: "0xtag" },
  { signer: aliceAccount },
);
const subscriptionTags = await subscription.allTags({ subscription: "0xsub" });

if (actionTags.ok) {
  console.log("Action tags", actionTags.value);
}

The result helper utilities (isOk, isErr, etc.) remain available for callers that prefer guard-style handling. Options surface as null, map results become standard objects, and lists of Move Object<T> values always hydrate as a vector of canonical string addresses.

Domain Layer (Phase 3)

Phase 3 introduces optional domain services that compose the one-to-one wrappers into higher level workflows. Each service accepts an AtlasClient plus the Atlas module address so the underlying wrappers remain fully transparent.

import {
  AtlasClient,
  EntitiesService,
  MessagesService,
} from "@epicuri/atlas-sdk";

const atlasModuleAddress = "0x42...";
const client = new AtlasClient({ signer: aliceAccount });

const entities = new EntitiesService(client, { atlasModuleAddress });
const messages = new MessagesService(client, { atlasModuleAddress });

Strategies and DomainOpts

Domain methods accept an optional DomainOpts object:

type DomainOpts = {
  strategy?: "all_or_nothing" | "best_effort"; // default is "all_or_nothing"
  opts?: SubmitOpts; // forwarded verbatim to every wrapper invocation in the sequence
};
  • all_or_nothing (default) stops at the first failing step and sets failedAt to the zero-based index.
  • best_effort runs the full sequence and records individual failures while leaving failedAt as null.

Pass the same SubmitOpts you would use with the wrappers – the domain layer never mutates them. When SubmitOpts.mode === 'simulate' every step stays in simulation mode.

EntitiesService Example

const result = await entities.createWithSetup(
  {
    slugName: "atlas_operator",
    displayName: "Atlas Operator",
    description: "Primary operator entity",
    tags: ["0xTAG1", "0xTAG2"],
    descriptor: "0xDESC",
    descriptorSchema: "0xSCHEMA",
    listener: { address: "0xLISTENER" },
  },
  {
    strategy: "all_or_nothing",
    opts: { signer: aliceAccount },
  },
  ["0x1::atlas::Schema"],
);

if (!result.steps.at(-1)?.result.ok) {
  console.error("Entity setup failed", result);
}

descriptorTypeArgs and descriptorSchema are required whenever descriptor is supplied. The domain method derives the created entity’s object address and fans out tag/listener calls for you while preserving the original SubmitOpts.

MessagesService Example

const publish = await messages.publish(
  {
    listener: "0xLISTENER",
    entity: "0xENTITY",
    payloadObject: "0xPAYLOAD",
    correlationId: "1234-5678",
  },
  {
    strategy: "best_effort",
    opts: { mode: "simulate", signer: aliceAccount },
  },
  ["0x1::atlas::Schema"],
);

if (publish.steps[0].result.ok) {
  console.log("Message published", publish.steps[0].result.value);
}

Inspecting DomainBatchResult

Every domain call returns a DomainBatchResult:

type DomainBatchResult = {
  strategy: "all_or_nothing" | "best_effort";
  steps: Array<{
    fqfn: string;
    typeArgs: string[];
    args: unknown[];
    result: Result<SubmittedTx | SimulationResult | unknown, AtlasError>;
  }>;
  failedAt: number | null;
};

Use steps to audit each wrapper call, including the fully qualified function name, the exact arguments forwarded, and the raw Result from the underlying module. This lets you handle partial success (e.g., in best_effort mode) without sacrificing detailed error reporting.