import { CID, CID as CID$1 } from "multiformats/cid"; import { PolkadotSigner } from "polkadot-api"; //#region src/types.d.ts /** * CID codec types supported by Bulletin Chain. * * For custom codecs not listed here, pass the numeric multicodec code directly * wherever a `CidCodec | number` is accepted. */ declare enum CidCodec { /** Raw binary (0x55) */ Raw = 85, /** DAG-PB (0x70) */ DagPb = 112, /** DAG-CBOR (0x71) */ DagCbor = 113 } /** * Hash algorithm types supported by Bulletin Chain */ declare enum HashAlgorithm { /** BLAKE2b-256 (0xb220) */ Blake2b256 = 45600, /** SHA2-256 (0x12) */ Sha2_256 = 18, /** Keccak-256 (0x1b) */ Keccak256 = 27 } /** * Configuration for chunking large data */ interface ChunkerConfig { /** Size of each chunk in bytes (default: 1 MiB) */ chunkSize: number; /** Whether to create a DAG-PB manifest (default: true) */ createManifest: boolean; } /** * Default chunker configuration * * Uses 1 MiB chunk size by default (safe and efficient for most use cases). * Maximum allowed is 2 MiB (MAX_CHUNK_SIZE, Bitswap limit for IPFS compatibility). */ declare const DEFAULT_CHUNKER_CONFIG: ChunkerConfig; /** * A single chunk of data */ interface Chunk { /** The chunk data */ data: Uint8Array; /** The CID of this chunk (calculated after encoding) */ cid?: CID$1; /** Index of this chunk in the sequence */ index: number; /** Total number of chunks */ totalChunks: number; } /** * Transaction confirmation level * * Can be used as a value (`WaitFor.InBlock`) or as a type (`WaitFor`). */ type WaitFor = "in_block" | "finalized"; declare const WaitFor: { InBlock: "in_block"; Finalized: "finalized"; }; /** * Options for storing data */ interface StoreOptions { /** CID codec to use (default: raw). Accepts a `CidCodec` or a custom numeric multicodec code. */ cidCodec?: CidCodec | number; /** Hashing algorithm to use (default: blake2b-256) */ hashingAlgorithm?: HashAlgorithm; /** * What to wait for before returning (default: "in_block") * - "in_block": Return when tx is in a best block (faster, may reorg) * - "finalized": Return when tx is finalized (safer, slower) */ waitFor?: WaitFor; } /** * Default store options */ declare const DEFAULT_STORE_OPTIONS: StoreOptions; /** * Details about chunks in a chunked upload */ interface ChunkDetails { /** CIDs of all stored chunks */ chunkCids: CID$1[]; /** Number of chunks */ numChunks: number; } /** * Result of a storage operation * * This result type works for both single-transaction uploads and chunked uploads. * For chunked uploads, the `cid` field contains the manifest CID, and `chunks` * contains details about the individual chunks. * * When chunked without a manifest (`withManifest(false)`), `cid` is undefined * and the individual chunk CIDs are in `chunks.chunkCids`. */ interface StoreResult { /** The primary CID of the stored data * - For single uploads: CID of the data * - For chunked uploads with manifest: CID of the manifest * - For chunked uploads without manifest: undefined */ cid?: CID$1; /** Size of the stored data in bytes */ size: number; /** Block number where data was stored (if known) */ blockNumber?: number; /** Extrinsic index within the block (required for renew operations) * This value comes from the `Stored` event's `index` field */ extrinsicIndex?: number; /** Chunk details (only present for chunked uploads) */ chunks?: ChunkDetails; } /** * Result of a chunked storage operation */ interface ChunkedStoreResult { /** CIDs of all stored chunks */ chunkCids: CID$1[]; /** The manifest CID (if manifest was created) */ manifestCid?: CID$1; /** Total size of all chunks in bytes */ totalSize: number; /** Number of chunks */ numChunks: number; } /** * Authorization scope types (mirrors the pallet's AuthorizationScope enum) */ declare enum AuthorizationScope { /** Account-based authorization */ Account = "Account", /** Preimage-based authorization (content-addressed) */ Preimage = "Preimage" } /** * Chunk progress event types */ declare enum ChunkStatus { ChunkStarted = "chunk_started", ChunkCompleted = "chunk_completed", ChunkFailed = "chunk_failed", ManifestStarted = "manifest_started", ManifestCreated = "manifest_created", Completed = "completed" } /** * Progress event types for chunked uploads */ type ChunkProgressEvent = { type: ChunkStatus.ChunkStarted; index: number; total: number; } | { type: ChunkStatus.ChunkCompleted; index: number; total: number; cid: CID$1; } | { type: ChunkStatus.ChunkFailed; index: number; total: number; error: Error; } | { type: ChunkStatus.ManifestStarted; } | { type: ChunkStatus.ManifestCreated; cid: CID$1; } | { type: ChunkStatus.Completed; manifestCid?: CID$1; }; /** * Transaction status event types */ declare enum TxStatus { Signed = "signed", Validated = "validated", Broadcasted = "broadcasted", InBlock = "in_block", Finalized = "finalized", NoLongerInBlock = "no_longer_in_block", Invalid = "invalid", Dropped = "dropped" } /** * Transaction status event types (mirrors PAPI's signSubmitAndWatch events) */ type TransactionStatusEvent = { type: TxStatus.Signed; txHash: string; chunkIndex?: number; } | { type: TxStatus.Validated; chunkIndex?: number; } | { type: TxStatus.Broadcasted; chunkIndex?: number; } | { type: TxStatus.InBlock; blockHash: string; blockNumber: number; txIndex?: number; chunkIndex?: number; } | { type: TxStatus.Finalized; blockHash: string; blockNumber: number; txIndex?: number; chunkIndex?: number; } | { type: TxStatus.NoLongerInBlock; chunkIndex?: number; } | { type: TxStatus.Invalid; error: string; chunkIndex?: number; } | { type: TxStatus.Dropped; error: string; chunkIndex?: number; }; /** * Combined progress event types */ type ProgressEvent = ChunkProgressEvent | TransactionStatusEvent; /** * Progress callback type */ type ProgressCallback = (event: ProgressEvent) => void; /** * Error codes for the Bulletin SDK. * * These codes are consistent with the Rust SDK's `Error::code()` method. */ declare enum ErrorCode { EMPTY_DATA = "EMPTY_DATA", DATA_TOO_LARGE = "DATA_TOO_LARGE", CHUNK_TOO_LARGE = "CHUNK_TOO_LARGE", INVALID_CHUNK_SIZE = "INVALID_CHUNK_SIZE", INVALID_CONFIG = "INVALID_CONFIG", INVALID_CID = "INVALID_CID", INVALID_HASH_ALGORITHM = "INVALID_HASH_ALGORITHM", CID_CALCULATION_FAILED = "CID_CALCULATION_FAILED", DAG_ENCODING_FAILED = "DAG_ENCODING_FAILED", INSUFFICIENT_AUTHORIZATION = "INSUFFICIENT_AUTHORIZATION", AUTHORIZATION_FAILED = "AUTHORIZATION_FAILED", TRANSACTION_FAILED = "TRANSACTION_FAILED", CHUNK_FAILED = "CHUNK_FAILED", MISSING_CHUNK = "MISSING_CHUNK", TIMEOUT = "TIMEOUT", UNSUPPORTED_OPERATION = "UNSUPPORTED_OPERATION" } /** * SDK error class */ declare class BulletinError extends Error { readonly code: ErrorCode; readonly cause?: unknown; constructor(message: string, code: ErrorCode, cause?: unknown); /** Whether this error is likely transient and retrying may succeed. */ get retryable(): boolean; /** An actionable recovery suggestion for this error. */ get recoveryHint(): string; } /** * Client configuration */ interface ClientConfig { /** Default chunk size for large files (default: 1 MiB) */ defaultChunkSize?: number; /** Whether to create manifests for chunked uploads (default: true) */ createManifest?: boolean; /** Threshold for automatic chunking (default: 2 MiB). * Data larger than this will be automatically chunked by `store()`. */ chunkingThreshold?: number; /** Defensive timeout in milliseconds per transaction (default: 420_000). * PAPI handles reconnects and mortality, so this should rarely fire. * Set above PAPI's default mortality window (64 blocks ~ 6.4 min at 6s blocks). */ txTimeout?: number; } /** * Default client configuration values. * * Used by AsyncBulletinClient, MockBulletinClient, and BulletinPreparer * so that defaults are defined in one place. */ declare const DEFAULT_CLIENT_CONFIG: Required; /** Merge caller-supplied config with defaults, ignoring undefined values. */ declare function resolveClientConfig(config?: Partial): Required; //#endregion //#region src/utils.d.ts /** * Calculate content hash using the specified algorithm * * Note: For production use, integrate with the pallet's hashing functions * via PAPI to ensure exact compatibility. */ declare function getContentHash(data: Uint8Array, hashAlgorithm: HashAlgorithm): Promise; /** * Create a CID for data with specified codec and hashing algorithm * * Default to raw codec (0x55) with blake2b-256 hash (0xb220) */ declare function calculateCid(data: Uint8Array, cidCodec?: number, hashAlgorithm?: HashAlgorithm): Promise; /** * Convert CID to different codec while keeping the same hash */ declare function convertCid(cid: CID$1, newCodec: number): CID$1; /** * Parse CID from string */ declare function parseCid(cidString: string): CID$1; /** * Parse CID from bytes */ declare function cidFromBytes(bytes: Uint8Array): CID$1; /** * Convert CID to bytes */ declare function cidToBytes(cid: CID$1): Uint8Array; /** * Estimate authorization needed for storing data * * @param dataSize - Total data size in bytes * @param chunkSize - Size of each chunk in bytes * @param createManifest - Whether a DAG-PB manifest will be created */ declare function estimateAuthorization(dataSize: number, chunkSize: number, createManifest: boolean): { transactions: number; bytes: number; }; /** * SCALE variant type for the on-chain HashingAlgorithm enum */ type ScaleHashingAlgorithm = { type: "Blake2b256"; } | { type: "Sha2_256"; } | { type: "Keccak256"; }; declare function validateChunkSize(size: number): void; //#endregion //#region src/async-client.d.ts /** * Minimal interface for a decoded PAPI runtime event. * * PAPI events from chain metadata have the shape: * `{ type: "PalletName", value: { type: "EventName", value: { ...fields } } }` */ interface RuntimeEvent { type: string; value?: { type?: string; value?: { index?: number; }; }; } /** * Minimal interface for PAPI transaction status events * (union of TxSigned, TxBroadcasted, TxBestBlocksState, TxFinalized). */ interface TxStatusEvent { txHash?: string; type?: string; found?: boolean; nPeers?: number; block?: { hash: string; number: number; index?: number; }; events?: RuntimeEvent[]; } /** * Minimal interface for a PAPI transaction. * * Describes the subset of PAPI's `Transaction` type that the SDK uses. * The actual type is generic over chain descriptors; this interface avoids * requiring generated chain types as a dependency. */ interface PapiTransaction { signAndSubmit(signer: PolkadotSigner): Promise<{ block?: { hash: string; number: number; }; txHash: string; events?: RuntimeEvent[]; }>; signSubmitAndWatch(signer: PolkadotSigner): { subscribe(observer: { next: (ev: TxStatusEvent) => void; error: (err: unknown) => void; complete?: () => void; }): { unsubscribe(): void; }; }; /** SCALE-encoded bare (unsigned) transaction ready for broadcasting */ getBareTx(): Promise; decodedCall: unknown; } /** * On-chain `TransactionRef` used by the renewal extrinsics. * * PAPI tagged-enum shape of the runtime's `TransactionRef` enum. `ContentHash` * requires a runtime that ships `TransactionRef`; its value is the 32-byte * content hash as a `0x`-prefixed hex string (PAPI represents fixed-size * binary values as `SizedHex`, and its encoder rejects raw byte arrays). */ type TransactionRef = { type: "Position"; value: { block: number; index: number; }; } | { type: "ContentHash"; value: string; }; /** * Caller-friendly reference to stored data for `renew()`/`forceRenew()`. * * The variant is inferred from the shape: `{ block, index }` becomes * `Position`; a `Uint8Array` content hash becomes `ContentHash`. */ type TransactionRefInput = { block: number; index: number; } | Uint8Array; /** Convert a {@link TransactionRefInput} into the on-chain tagged enum. */ declare function toTransactionRef(ref: TransactionRefInput): TransactionRef; /** * Minimal shape of the pallet namespace carrying the renewal extrinsics, so the * lookup in `renewalPallet` does not need the generated per-pallet types. */ type RenewalPallet = { renew(args: { block: number; index: number; } | { entry: TransactionRef; }): PapiTransaction; force_renew?(args: { entry: TransactionRef; }): PapiTransaction; }; /** * Minimal interface for the PAPI typed API. * * Describes the pallets and extrinsics the SDK interacts with. * Users pass their actual `TypedApi` which satisfies * this interface structurally. */ interface BulletinTypedApi { tx: { TransactionStorage: { store(args: { data: Uint8Array; }): PapiTransaction; store_with_cid_config(args: { cid: { codec: bigint; hashing: ScaleHashingAlgorithm; }; data: Uint8Array; }): PapiTransaction; authorize_account(args: { who: string; transactions: number; bytes: bigint; }): PapiTransaction; authorize_preimage(args: { content_hash: string; max_size: bigint; }): PapiTransaction; renew(args: { block: number; index: number; } | { entry: TransactionRef; }): PapiTransaction; force_renew?(args: { entry: TransactionRef; }): PapiTransaction; remove_expired_account_authorization(args: { who: string; }): PapiTransaction; remove_expired_preimage_authorization(args: { content_hash: string; }): PapiTransaction; refresh_account_authorization(args: { who: string; }): PapiTransaction; refresh_preimage_authorization(args: { content_hash: string; }): PapiTransaction; }; /** * Renewal extrinsics. The renewal split moved `renew` / `force_renew` here * from `TransactionStorage`; absent on pre-split runtimes. */ DataRenewal?: RenewalPallet; Sudo?: { sudo(args: { call: unknown; }): PapiTransaction; }; }; /** Optional query interface for on-chain storage reads (e.g., authorization checks) */ query?: { TransactionStorage: { Authorizations: { getValue(scope: { type: string; value: unknown; }): Promise<{ extent: { transactions: number; /** Newer chains expose the cap separately from consumed counters. */ transactions_allowance?: number; bytes: bigint; /** Newer chains expose the cap separately from consumed counters. */ bytes_allowance?: bigint; }; expiration: number; } | undefined>; }; }; }; } /** * Function type for submitting raw transactions to the chain. * * Matches the signature of `PolkadotClient.submit` from polkadot-api. * Pass `papiClient.submit` directly when constructing the client. */ type SubmitFn = (transaction: Uint8Array, at?: string) => Promise<{ ok: boolean; block: { hash: string; number: number; index: number; }; txHash: string; events: Array<{ type: string; value?: { type?: string; value?: unknown; }; }>; dispatchError?: { type: string; value: unknown; }; }>; /** * Transaction receipt from a successful submission */ interface TransactionReceipt { /** Block hash containing the transaction */ blockHash: string; /** Transaction hash */ txHash: string; /** Block number (if known) */ blockNumber?: number; } /** Options for transaction submission */ interface CallOptions { /** Callback to receive transaction status events */ onProgress?: ProgressCallback; /** What to wait for before returning (default: "in_block") */ waitFor?: WaitFor; } /** Options for authorization calls that may require sudo */ interface AuthCallOptions extends CallOptions { /** Wrap the call in Sudo (for chains where Authorizer origin requires it) */ sudo?: boolean; } /** * Shared interface for Bulletin clients (real and mock). * * Both `AsyncBulletinClient` and `MockBulletinClient` implement this interface. */ interface BulletinClientInterface { /** Store data with options (used internally by StoreBuilder) */ storeWithOptions(data: Uint8Array, options?: StoreOptions, progressCallback?: ProgressCallback, chunkerConfig?: Partial): Promise; /** Store preimage-authorized content as unsigned transaction */ storeWithPreimageAuth?(data: Uint8Array, options?: StoreOptions): Promise; store(data: Uint8Array): StoreBuilder; authorizeAccount(who: string, transactions: number, bytes: bigint): AuthCallBuilder; authorizePreimage(contentHash: Uint8Array, maxSize: bigint): AuthCallBuilder; renew(ref: TransactionRefInput): CallBuilder; forceRenew(ref: TransactionRefInput): CallBuilder; refreshAccountAuthorization(who: string): AuthCallBuilder; refreshPreimageAuthorization(contentHash: Uint8Array): AuthCallBuilder; removeExpiredAccountAuthorization(who: string): CallBuilder; removeExpiredPreimageAuthorization(contentHash: Uint8Array): CallBuilder; estimateAuthorization(dataSize: number): { transactions: number; bytes: number; }; /** Release resources held on behalf of this client (e.g. underlying PAPI client). */ destroy(): Promise; } /** * Builder for store operations with fluent API * * @example * ```typescript * const result = await client * .store(new TextEncoder().encode('Hello')) * .withCodec(CidCodec.DagPb) * .withHashAlgorithm('blake2b-256') * .withCallback((event) => console.log('Progress:', event)) * .send(); * ``` */ declare class StoreBuilder { private executor; private data; private options; private callback?; private chunkerConfig?; constructor(executor: BulletinClientInterface, data: Uint8Array); /** Set the CID codec. Accepts a `CidCodec` or a custom numeric multicodec code. */ withCodec(codec: CidCodec | number): this; /** Set the hash algorithm */ withHashAlgorithm(algorithm: HashAlgorithm): this; /** Set what to wait for before returning */ withWaitFor(waitFor: WaitFor): this; /** Set progress callback for chunked uploads */ withCallback(callback: ProgressCallback): this; /** Set chunk size (forces chunked upload path) */ withChunkSize(chunkSize: number): this; /** Enable or disable DAG-PB manifest creation for chunked uploads (default: true) */ withManifest(enabled: boolean): this; /** Execute the store operation (signed transaction, uses account authorization) */ send(): Promise; /** * Execute store operation as unsigned transaction (for preimage-authorized content) * * Use this when the content has been pre-authorized via `authorizePreimage()`. * Unsigned transactions don't require fees and can be submitted by anyone. * * @example * ```typescript * // First authorize the content hash * const hash = blake2b256(data); * await client.authorizePreimage(hash, BigInt(data.length)); * * // Anyone can now store this content without fees * const result = await client.store(data).sendUnsigned(); * ``` */ sendUnsigned(): Promise; } /** * Builder for calls with `CallOptions` (waitFor + callback) * * Used by: `renew`, `removeExpiredAccountAuthorization`, `removeExpiredPreimageAuthorization` * * @example * ```typescript * const receipt = await client * .renew({ block, index }) * .withWaitFor('finalized') * .withCallback((event) => console.log(event)) * .send(); * ``` */ declare class CallBuilder { private executor; private options; constructor(executor: (options: CallOptions) => Promise); /** Set what to wait for before returning */ withWaitFor(waitFor: WaitFor): this; /** Set progress callback */ withCallback(callback: ProgressCallback): this; /** Submit the transaction */ send(): Promise; } /** * Builder for authorization calls that may require sudo * * Used by: `authorizeAccount`, `authorizePreimage`, `refreshAccountAuthorization`, `refreshPreimageAuthorization` * * @example * ```typescript * const receipt = await client * .authorizeAccount(who, transactions, bytes) * .withSudo() * .withCallback((event) => console.log(event)) * .send(); * ``` */ declare class AuthCallBuilder { private executor; private options; constructor(executor: (options: AuthCallOptions) => Promise); /** Set what to wait for before returning */ withWaitFor(waitFor: WaitFor): this; /** Set progress callback */ withCallback(callback: ProgressCallback): this; /** Wrap the call in Sudo */ withSudo(): this; /** Submit the transaction */ send(): Promise; } /** * Async Bulletin client that submits transactions to the chain * * This client is tightly coupled to PAPI (Polkadot API) for blockchain interaction. * Users must provide a configured PAPI client with appropriate chain metadata. * * @example * ```typescript * import { createClient } from 'polkadot-api'; * import { getWsProvider } from 'polkadot-api/ws'; * import { AsyncBulletinClient } from '@parity/bulletin-sdk'; * * // User sets up PAPI client * const wsProvider = getWsProvider('wss://bulletin-rpc.polkadot.io'); * const client = createClient(wsProvider); * const api = client.getTypedApi(bulletinDescriptor); * * // Create SDK client * const bulletinClient = new AsyncBulletinClient(api, signer, papiClient.submit); * * // Store data * const result = await bulletinClient.store(data).send(); * ``` */ declare class AsyncBulletinClient implements BulletinClientInterface { /** PAPI client for blockchain interaction */ api: BulletinTypedApi; /** Signer for transaction signing */ signer: PolkadotSigner; /** Submit function for broadcasting raw transactions (from PolkadotClient.submit) */ submit: SubmitFn; /** Client configuration */ config: Required; /** Offline operations (chunking, CID calculation, estimation) */ private preparer; /** Optional teardown callback invoked by `destroy()` */ private onDestroy?; /** * Create a new async client with PAPI client and signer * * The PAPI client must be configured with the correct chain metadata * for your Bulletin Chain node. * * @param api - Configured PAPI TypedApi instance * @param signer - Polkadot signer for transaction signing * @param submit - Raw transaction submit function (pass `papiClient.submit`) * @param config - Optional client configuration * @param onDestroy - Optional teardown callback. When provided, `destroy()` * awaits it so callers (e.g. wrappers that own the underlying * `PolkadotClient`) can route cleanup through this client. */ constructor(api: BulletinTypedApi, signer: PolkadotSigner, submit: SubmitFn, config?: Partial, onDestroy?: () => void | Promise); /** * Release resources held on behalf of this client. * * Invokes the optional `onDestroy` callback supplied at construction time. * Without one, this is a no-op — the SDK itself holds no long-lived * resources, so callers that own the underlying `PolkadotClient` (or other * connection) can either tear it down themselves or pass `onDestroy` to * route teardown through here. */ destroy(): Promise; /** * Best-effort authorization check before a store submission. * * Allowances gate transaction *priority*, not acceptance — the chain never * rejects a store for an exhausted boost budget. So this only warns when the * budget looks insufficient and always proceeds. If `api.query` is not * available, the query fails, or returns nothing, it silently proceeds and * lets the chain validate. */ private checkAccountAuthorization; /** * Create a store transaction. * * The chain defaults to Raw (0x55) codec + Blake2b-256 hashing, so the plain * `store()` extrinsic is sufficient for the common case. We only use the heavier * `store_with_cid_config()` extrinsic when the user requests non-default settings. */ private createStoreTx; /** * Sign, submit, and watch a transaction with progress callbacks. * * Uses PAPI's signSubmitAndWatch which provides real-time status updates * as the transaction progresses through the network. * * With "in_block" the promise resolves at first inclusion, but the * transaction stays broadcast and watched in the background until it * finalizes, so a reorg cannot silently drop it. * * Retries once on mortality-era expiry (AncientBirthBlock): the node's * pool can silently lose a broadcast tx around a reorg, surfacing only as * era expiry. Safe: past the finalized era boundary the original * signature can never be included, so re-signing cannot double-store. * * @param tx - The transaction to submit * @param progressCallback - Optional callback to receive transaction status events * @param waitFor - What to wait for: "in_block" (faster) or "finalized" (safer, default) */ private signAndSubmitWithProgress; private signAndSubmitAttempt; /** * Wrap a call in Sudo if requested, otherwise return it as-is */ private maybeSudo; /** * Submit a transaction, returning a receipt on success or throwing a BulletinError on failure. */ private submitTx; /** * Store data on Bulletin Chain using builder pattern * * Returns a builder that allows fluent configuration of store options. * * @param data - Data to store as `Uint8Array` * * @example * ```typescript * const result = await client * .store(new TextEncoder().encode('Hello, Bulletin!')) * .withCodec(CidCodec.DagPb) * .withHashAlgorithm('blake2b-256') * .withCallback((event) => console.log('Progress:', event)) * .send(); * ``` */ store(data: Uint8Array): StoreBuilder; /** * Store data with custom options (internal, used by builder) * * **Note**: This method is public for use by the builder but users should prefer * the builder pattern via `store()`. * * Automatically chunks data if it exceeds the configured threshold. */ storeWithOptions(data: Uint8Array, options?: StoreOptions, progressCallback?: ProgressCallback, chunkerConfig?: Partial): Promise; /** * Internal: Store data in a single transaction (no chunking) */ private storeInternalSingle; /** * Store large data with automatic chunking and manifest creation * * Handles the complete workflow: * 1. Chunk the data * 2. Calculate CIDs for each chunk * 3. Submit each chunk as a separate transaction * 4. Create and submit DAG-PB manifest (if enabled) * 5. Return all CIDs and receipt information * * Note: Chunk submissions are not atomic. If chunk N fails, chunks 0..N-1 * are already stored on-chain and cannot be rolled back. The caller should * check the error and `chunkCids` in the thrown error's context to understand * what was partially uploaded. * * @param data - Data to store as `Uint8Array` */ private storeChunked; /** * Authorize an account to store data * * @param who - Account address to authorize * @param transactions - Number of transactions to authorize * @param bytes - Maximum bytes to authorize */ authorizeAccount(who: string, transactions: number, bytes: bigint): AuthCallBuilder; /** * Authorize a preimage (by content hash) to be stored * * @param contentHash - Blake2b-256 hash of the content to authorize * @param maxSize - Maximum size in bytes for the content */ authorizePreimage(contentHash: Uint8Array, maxSize: bigint): AuthCallBuilder; /** Cached renewal call-shape resolution; a rejected probe is not cached. */ private renewShapePromise?; /** * Pallet holding the renewal extrinsics. The renewal split moved `renew` and * `force_renew` out of `TransactionStorage` into `DataRenewal`; pre-split * runtimes (and hand-rolled mocks) still expose them on the old pallet. */ private get renewalPallet(); /** * Resolve which call shape the runtime's renewal extrinsics take, once per * client. * * On a real PAPI `TypedApi`, `tx.DataRenewal.force_renew` is a proxy * entry that is truthy for *any* name, so presence alone proves nothing; the * entry's `getCompatibilityLevel()` compares descriptors against the live * runtime and returns `CompatibilityLevel.Incompatible` (0) when the runtime * lacks the call. Hand-rolled api objects (tests/mocks) have no such probe — * there, presence of `force_renew` decides. * * A probe failure throws instead of guessing — dispatching the wrong shape * yields an opaque encode error — and is not cached, so the next call * retries. A resolved shape is cached for the client's lifetime; after a * runtime upgrade that changes the renewal call shape, create a new client. */ private resolveRenewShape; /** * Schedule a one-shot renewal of stored data. * * The renewal fires once when the data reaches its retention boundary; it does * not renew synchronously. For immediate renewal use {@link forceRenew}. */ renew(ref: TransactionRefInput): CallBuilder; /** * Immediately renew stored data, extending its retention from the current block. * * Requires a runtime that supports `force_renew`. */ forceRenew(ref: TransactionRefInput): CallBuilder; /** * Refresh an account authorization (extends expiry) * * Requires Authorizer origin on-chain. * * @param who - Account address to refresh authorization for */ refreshAccountAuthorization(who: string): AuthCallBuilder; /** * Refresh a preimage authorization (extends expiry) * * Requires Authorizer origin on-chain. * * @param contentHash - Blake2b-256 hash of the authorized content */ refreshPreimageAuthorization(contentHash: Uint8Array): AuthCallBuilder; /** * Remove an expired account authorization * * Can be called by anyone (no special origin required). * * @param who - Account address with expired authorization */ removeExpiredAccountAuthorization(who: string): CallBuilder; /** * Remove an expired preimage authorization * * Can be called by anyone (no special origin required). * * @param contentHash - Blake2b-256 hash of the expired authorization */ removeExpiredPreimageAuthorization(contentHash: Uint8Array): CallBuilder; /** * Store preimage-authorized content as an unsigned (bare) transaction. * * Use this for content that has been pre-authorized via `authorizePreimage()`. * The transaction is encoded as a bare (unsigned) extrinsic and submitted * via the client's `submit` function (from `PolkadotClient.submit`). * * @param data - The preauthorized content to store * @param options - Store options (codec, hashing algorithm, etc.) * * @example * ```typescript * import { blake2b256 } from '@polkadot-labs/hdkd-helpers'; * * // First, authorize the content hash (requires sudo) * const data = new TextEncoder().encode('Hello, Bulletin!'); * const hash = blake2b256(data); * await sudoClient.authorizePreimage(hash, BigInt(data.length)); * * // Anyone can now submit without fees * const result = await client.store(data).sendUnsigned(); * ``` */ storeWithPreimageAuth(data: Uint8Array, options?: StoreOptions): Promise; /** * Estimate authorization needed for storing data */ estimateAuthorization(dataSize: number): { transactions: number; bytes: number; }; } //#endregion //#region src/chunker.d.ts /** Maximum chunk size allowed (2 MiB, Bitswap compatibility limit) */ declare const MAX_CHUNK_SIZE: number; /** Maximum file size the SDK will chunk in a single operation (64 MiB). * For larger files, split into segments of at most 64 MiB and chunk each independently. */ declare const MAX_FILE_SIZE: number; /** * Fixed-size chunker that splits data into equal-sized chunks */ declare class FixedSizeChunker { private config; constructor(config?: Partial); /** * Split data into chunks */ chunk(data: Uint8Array): Chunk[]; /** * Calculate the number of chunks needed for the given data size */ numChunks(dataSize: number): number; /** * Get the chunk size */ get chunkSize(): number; } /** * Reassemble chunks back into the original data * * Chunks are sorted by index before concatenation to handle out-of-order input. * * @param chunks - Array of chunks to reassemble * @returns The original data as a single Uint8Array */ declare function reassembleChunks(chunks: Chunk[]): Uint8Array; //#endregion //#region src/dag.d.ts /** * DAG-PB manifest representing a file composed of multiple chunks */ interface DagManifest { /** The root CID of the manifest */ rootCid: CID$1; /** CIDs of all chunks in order */ chunkCids: CID$1[]; /** Total size of the file in bytes */ totalSize: number; /** Encoded DAG-PB bytes */ dagBytes: Uint8Array; } /** * UnixFS DAG-PB builder following IPFS UnixFS v1 specification */ declare class UnixFsDagBuilder { /** * Build a UnixFS DAG-PB file node from raw chunks */ build(chunks: Chunk[], hashAlgorithm?: HashAlgorithm): Promise; /** * Parse a DAG-PB manifest back into its components */ parse(dagBytes: Uint8Array): Promise<{ chunkCids: CID$1[]; totalSize: number; }>; } //#endregion //#region src/mock-client.d.ts /** * Configuration for the mock Bulletin client */ interface MockClientConfig extends ClientConfig { /** Simulate authorization failures (for testing error paths) */ simulateAuthFailure?: boolean; /** Simulate storage failures (for testing error paths) */ simulateStorageFailure?: boolean; } /** * Record of a mock operation performed */ type MockOperation = { type: "store"; dataSize: number; cid: string; } | { type: "authorize_account"; who: string; transactions: number; bytes: bigint; } | { type: "authorize_preimage"; contentHash: Uint8Array; maxSize: bigint; } | { type: "refresh_account_authorization"; who: string; } | { type: "refresh_preimage_authorization"; contentHash: Uint8Array; } | { type: "renew"; entry: TransactionRef; } | { type: "force_renew"; entry: TransactionRef; } | { type: "store_preimage_auth"; dataSize: number; cid: string; } | { type: "remove_expired_account_authorization"; who: string; } | { type: "remove_expired_preimage_authorization"; contentHash: Uint8Array; }; /** * Mock Bulletin client for testing * * This client simulates blockchain operations without requiring a running node. * It calculates CIDs correctly and tracks operations but doesn't actually submit * transactions to a chain. * * @example * ```typescript * import { MockBulletinClient } from '@parity/bulletin-sdk'; * * // Create mock client * const client = new MockBulletinClient(); * * // Store data (no blockchain required) * const result = await client.store(data).send(); * console.log('Mock CID:', result.cid.toString()); * * // Check what operations were performed * const ops = client.getOperations(); * expect(ops).toHaveLength(1); * ``` */ declare class MockBulletinClient implements BulletinClientInterface { /** Client configuration */ config: Required & { simulateAuthFailure: boolean; simulateStorageFailure: boolean; }; /** Operations performed (for testing verification) */ private operations; /** * Create a new mock client with optional configuration */ constructor(config?: Partial); /** * Get all operations performed by this client */ getOperations(): MockOperation[]; /** * Clear recorded operations */ clearOperations(): void; /** * No-op for the mock client — present to satisfy `BulletinClientInterface`. */ destroy(): Promise; /** * Store data using builder pattern * * @param data - Data to store as `Uint8Array` */ store(data: Uint8Array): StoreBuilder; /** * Store data with custom options (internal, used by builder) */ storeWithOptions(data: Uint8Array, options?: StoreOptions, _progressCallback?: ProgressCallback, chunkerConfig?: Partial): Promise; private throwIfAuthFailure; authorizeAccount(who: string, transactions: number, bytes: bigint): AuthCallBuilder; authorizePreimage(contentHash: Uint8Array, maxSize: bigint): AuthCallBuilder; refreshAccountAuthorization(who: string): AuthCallBuilder; refreshPreimageAuthorization(contentHash: Uint8Array): AuthCallBuilder; removeExpiredAccountAuthorization(who: string): CallBuilder; removeExpiredPreimageAuthorization(contentHash: Uint8Array): CallBuilder; renew(ref: TransactionRefInput): CallBuilder; forceRenew(ref: TransactionRefInput): CallBuilder; /** * Store preimage-authorized content (mock) */ storeWithPreimageAuth(data: Uint8Array, options?: StoreOptions): Promise; /** * Estimate authorization needed for storing data */ estimateAuthorization(dataSize: number): { transactions: number; bytes: number; }; } //#endregion //#region src/preparer.d.ts /** * Offline data preparer for Bulletin Chain * * Handles CID calculation, chunking, DAG-PB manifest creation, and * authorization estimation without any chain interaction. * Used internally by AsyncBulletinClient and MockBulletinClient. */ declare class BulletinPreparer { private config; constructor(config?: ClientConfig); /** * Prepare a simple store operation (data < 2 MiB) * * Returns the data and its CID. Use PAPI to submit to TransactionStorage.store */ prepareStore(data: Uint8Array, options?: StoreOptions): Promise<{ data: Uint8Array; cid: CID$1; }>; /** * Prepare a chunked store operation for large files * * This chunks the data, calculates CIDs, and optionally creates a DAG-PB manifest. * Returns chunk data and manifest that can be submitted via PAPI. */ prepareStoreChunked(data: Uint8Array, config?: Partial, options?: StoreOptions): Promise<{ chunks: Chunk[]; manifest?: { data: Uint8Array; cid: CID$1; }; }>; /** * Estimate authorization needed for storing data * * Returns (num_transactions, total_bytes) needed for authorization */ estimateAuthorization(dataSize: number): { transactions: number; bytes: number; }; } //#endregion export { AsyncBulletinClient, AuthCallBuilder, type AuthCallOptions, AuthorizationScope, type BulletinClientInterface, BulletinError, BulletinPreparer, type BulletinTypedApi, CID, CallBuilder, type CallOptions, type Chunk, type ChunkDetails, type ChunkProgressEvent, ChunkStatus, type ChunkedStoreResult, type ChunkerConfig, CidCodec, type ClientConfig, DEFAULT_CHUNKER_CONFIG, DEFAULT_CLIENT_CONFIG, DEFAULT_STORE_OPTIONS, type DagManifest, ErrorCode, FixedSizeChunker, HashAlgorithm, MAX_CHUNK_SIZE, MAX_FILE_SIZE, MockBulletinClient, type MockClientConfig, type MockOperation, type ProgressCallback, type ProgressEvent, StoreBuilder, type StoreOptions, type StoreResult, type SubmitFn, type TransactionReceipt, type TransactionRef, type TransactionRefInput, type TransactionStatusEvent, TxStatus, UnixFsDagBuilder, WaitFor, calculateCid, cidFromBytes, cidToBytes, convertCid, estimateAuthorization, getContentHash, parseCid, reassembleChunks, resolveClientConfig, toTransactionRef, validateChunkSize };