@usearete/sdk
v0.2.0
Published
Pure TypeScript SDK for the Arete Solana streaming platform
Downloads
550
Maintainers
Readme
Arete TypeScript SDK
Pure TypeScript SDK for generated stack definitions, program SDKs, prepared operation execution, and chain reads.
Installation
npm install @usearete/sdkQuick Start
import { createSession } from '@usearete/sdk';
import { MY_STACK } from './generated/my-stack';
const session = await createSession({
stacks: { myStack: MY_STACK },
});
for await (const item of session.stacks.myStack.views.MyEntity.list.use()) {
console.log(item);
}SDK Shapes
Mental Model
Think of a generated stack as a cartridge: it packages one domain's typed views, queries, programs, reads, and flows, plus any cross-program addresses, constants, defaults, or math. "Cartridge" is only a mental model; the public API continues to use the existing generated stack objects and types.
An Arete session is the console. Insert one or more generated stacks under session.stacks, optionally add standalone programs, and use the console's shared session.programs, session.chain, and session.execute(...) surfaces. Programs packaged by a stack are automatically promoted to session.programs without creating another connection or runtime.
Every semantic operation has an explicit cardinality:
instruction- exactly one Solana instructiontransaction- exactly one atomic transaction with one or more instructionsflow- one or more sequential transactions
Every semantic operation exposes one pure entrypoint:
.prepare(input)
Every connected client or session exposes one semantic execution entrypoint:
.execute(prepared, options?)
There is no semantic .resolve(), .build(), .stage(), .plan(), or .send() projection surface anymore.
Connected Stack Cartridges
Access a connected generated stack through session.stacks.<name>. Its stable namespaces are:
views- typed streaming, list, and state viewsqueries- stack-level HTTP queriesprograms- owner-scoped program SDKs; the same connected objects are promoted tosession.programsaddresses- domain address derivations, when definedconstants- domain constants and enums, when defineddefaults- reusable domain defaults, when definedmath- pure domain calculations, when definedread- connected, domain-oriented reads, when definedflows- stack-level multi-transaction operations, when defined
These are namespaces on the existing connected stack object; no separate cartridge class or type is introduced.
Program SDKs
Each packaged, attached, or standalone program is canonically available under session.programs.<name> and exposes these stable namespaces. The owner-scoped session.stacks.<name>.programs.<program> path remains available when disambiguation is needed.
programId- the deployed Solana program addressschemas- generated validation schemaspdas- exact generated PDA definitionsaddresses- semantic address derivations, when definedaccounts- typed point reads for program accountsqueries- program-level HTTP queriesraw- exact IDL instruction builders with synchronous.build(...)instructions- semantic one-instruction operations with.prepare(...)transactions- semantic one-transaction operations with.prepare(...)flows- program-local multi-transaction operations with.prepare(...)constants- program constants and enumsdefaults- reusable program defaultsmath- pure protocol calculations
Raw Instructions
Use raw handlers when you want exact wire control and will compose the transaction yourself:
const ix = session.programs.splToken.raw.InitializeMint2.build({
mint,
decimals: 6,
mint_authority: authority,
freeze_authority: null,
});
await session.transaction([ix]);Raw builders are the exact IDL escape hatch. Instruction names, account names, argument names, and nested objects retain the generated IDL shape, including snake_case where the IDL uses it.
Semantic Operations
Use semantic operations for normal application code. Their .prepare(...) methods accept semantic, camelCase object inputs, derive routine addresses, normalize amounts, and return prepared artifacts. Use raw only when you deliberately need the exact IDL surface.
Instruction example:
const prepared = await session.programs.tokenMetadata.instructions.createMetadataAccountV3.prepare({
mint,
mintAuthority,
payer,
updateAuthority,
name,
symbol,
uri,
});
console.log(prepared.kind); // 'instruction'
console.log(prepared.instruction);
console.log(prepared.artifacts);
await session.execute(prepared);Transaction example:
const prepared = await session.programs.cpAmm.transactions.swap.exactIn.prepare({
pool,
payer,
inputTokenMint,
amountIn: { ui: '1.25' },
minimumAmountOut: 1n,
});
console.log(prepared.kind); // 'transaction'
console.log(prepared.transaction.instructions.length);
await session.execute(prepared);Flow example:
const prepared = await session.programs.presale.flows.escrow.depositPermissionless.prepare({
presale,
owner,
maxAmount: { ui: '1000' },
});
console.log(prepared.kind); // 'flow'
console.log(prepared.plan.transactions.length);
await session.execute(prepared);Prepared Shapes
Prepared values are immutable and discriminated:
PreparedInstructionPreparedTransactionPreparedFlow
All prepared values include:
kindnameartifactsplan.transactions
Instruction values also include .instruction, and transaction values include .transaction.
Prepared instructions can be composed directly into a transaction without
extracting .instruction:
const transaction = createPreparedTransaction({
name: 'configureMint',
instructions: [initializeMint, setAuthority],
artifacts: { mint },
});Prepared instructions and prepared transactions can also be flattened into one atomic transaction without reaching into their transaction bodies:
const transaction = createPreparedTransaction({
name: 'createAndConfigureMint',
operations: [createMint, createMetadata, setAuthority],
artifacts: { mint },
});Only single-transaction operations are accepted by operations. A
PreparedFlow must retain its ordered transaction boundaries.
Child signer and error metadata is inherited unless the transaction explicitly
provides requiredSignerAddresses or errors.
Every successful execution receipt exposes its signatures in transaction order:
const receipt = await session.execute(prepared);
console.log(receipt.signatures);Instruction and transaction receipts contain one signature. Flow receipts contain one signature for each executed transaction.
Use describePreparedOperation(prepared) for a typed, JSON-safe description, or
formatPreparedOperation(prepared) for human-readable text.
const description = describePreparedOperation(prepared);
console.log(JSON.stringify(description, null, 2));Sessions
Use a session as the console for one or more generated stack cartridges and/or standalone programs behind one execution surface. Stack programs are promoted by reference; session.programs.presale === session.stacks.presale.programs.presale.
import { createSession, createSignerRegistry } from '@usearete/sdk';
const signerRegistry = createSignerRegistry([
[creatorAddress, creatorSigner],
]);
const session = await createSession(
{
stacks: {
squads: SQUADS_V4_STREAM_STACK,
presale: METEORA_PRESALE_STREAM_STACK,
},
programs: {
splToken: SPL_TOKEN_PROGRAM,
},
},
{
transport: 'http',
endpoints: { http: 'http://127.0.0.1:8081' },
wallet,
signerRegistry,
}
);
const prepared = await session.stacks.squads.flows.vaultProposal.prepare(...);
await session.execute(prepared);
// Signers can also be managed after session creation.
session.signerRegistry.register(memberAddress, memberSigner);Equivalent entrypoints:
createSession(...)Arete.session(...)
Session surface:
session.stacks.<name>- connected generated stackssession.programs.<name>- connected packaged, attached, or standalone programssession.chain- canonical generic chain readssession.signerRegistrysession.transaction(...)session.execute(...)
Prefer these connected paths in application code. Arete.connect(STACK, ...) remains available when a direct single-stack client is more convenient.
If multiple stacks package the same program key, the first stack in the session definition owns the promoted alias and the session emits a warning. Both owner-scoped stack paths remain available. An explicitly declared standalone program always owns its top-level key.
Chain Reads
Generic chain reads use the console-level session.chain surface.
Available reads include:
exists(address)lamports(address)minimumBalanceForRentExemption(space)clock()account(address)mint(address)tokenAccount(address)balance({ owner, mint, tokenProgram? })
Example:
const rentLamports = await session.chain.minimumBalanceForRentExemption(82);
const mintInfo = await session.chain.mint(mintAddress);Streaming Views
Views are still the main streaming surface.
for await (const update of session.stacks.myStack.views.settlementGame.list.watch()) {
if (update.type === 'upsert') {
console.log(update.key, update.data);
}
}
const game = await session.stacks.myStack.views.settlementGame.state.get('game-123');Update Types
type Update<T> =
| { type: 'upsert'; key: string; data: T }
| { type: 'patch'; key: string; data: Partial<T> }
| { type: 'delete'; key: string };
type RichUpdate<T> =
| { type: 'created'; key: string; data: T }
| { type: 'updated'; key: string; before: T; after: T; patch?: unknown }
| { type: 'deleted'; key: string; lastKnown?: T };License
MIT
