@canton-network/core-acs-reader
Advanced tools
| import { LRUCacheOptions } from 'typescript-lru-cache'; | ||
| import { PaginatedResolvedAcsOptions, ResolvedAcsOptions } from '../../service'; | ||
| import { AbstractLedgerProvider } from '@canton-network/core-provider-ledger'; | ||
| import { LedgerCommonSchemas } from '@canton-network/core-ledger-client-types'; | ||
| import { ACSCache, BaseACSCache, PaginatedACSCache } from '../item'; | ||
| export type ACSCacheCollectionOptions = Pick<LRUCacheOptions<string, BaseACSCache>, 'maxSize' | 'entryExpirationTimeInMS'>; | ||
| export declare abstract class BaseCacheCollection<Cache extends ACSCache | PaginatedACSCache, Options extends ResolvedAcsOptions | PaginatedResolvedAcsOptions = Cache extends ACSCache ? ResolvedAcsOptions : PaginatedResolvedAcsOptions> { | ||
| protected readonly ledger: AbstractLedgerProvider; | ||
| private readonly options; | ||
| private readonly collection; | ||
| constructor(ledger: AbstractLedgerProvider, options?: ACSCacheCollectionOptions); | ||
| /** | ||
| * Reads the active contract set from the ledger with caching. | ||
| * Resolves party references and constructs cache keys from the provided template and interface IDs. | ||
| * Queries are deduplicated and cached per party-template-interface combination. | ||
| */ | ||
| readFromCache(options: Options): Promise<LedgerCommonSchemas['JsGetActiveContractsResponse'][]>; | ||
| protected abstract createCache(): Cache; | ||
| private getCache; | ||
| /** | ||
| * Updates the cached active contract set for a specific key and returns contracts at the requested offset. | ||
| * If the cache is outdated, fetches updates from the ledger and applies them incrementally. | ||
| */ | ||
| private updateCache; | ||
| /** | ||
| * Queries multiple cache keys in parallel and combines the results. | ||
| * Each key represents a unique party-template-interface combination to be queried independently. | ||
| */ | ||
| private query; | ||
| private serializeKey; | ||
| } | ||
| //# sourceMappingURL=base.d.ts.map |
| {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/cache/collection/base.ts"],"names":[],"mappings":"AAGA,OAAO,EAAY,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAEhE,OAAO,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAC/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAA;AAC7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAC9E,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEnE,MAAM,MAAM,yBAAyB,GAAG,IAAI,CACxC,eAAe,CAAC,MAAM,EAAE,YAAY,CAAC,EACrC,SAAS,GAAG,yBAAyB,CACxC,CAAA;AAED,8BAAsB,mBAAmB,CACrC,KAAK,SAAS,QAAQ,GAAG,iBAAiB,EAC1C,OAAO,SAAS,kBAAkB,GAAG,2BAA2B,GAC5D,KAAK,SAAS,QAAQ,GAChB,kBAAkB,GAClB,2BAA2B;IAKjC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,sBAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;gBAG7B,MAAM,EAAE,sBAAsB,EAChC,OAAO,GAAE,yBAGzB;IAKL;;;;OAIG;IACU,aAAa,CACtB,OAAO,EAAE,OAAO,GACjB,OAAO,CAAC,mBAAmB,CAAC,8BAA8B,CAAC,EAAE,CAAC;IAkBjE,SAAS,CAAC,QAAQ,CAAC,WAAW,IAAI,KAAK;IAEvC,OAAO,CAAC,QAAQ;IAWhB;;;OAGG;YACW,WAAW;IASzB;;;OAGG;YACW,KAAK;IAcnB,OAAO,CAAC,YAAY;CAGvB"} |
| import { BaseCacheCollection } from './base'; | ||
| import { ACSCache, PaginatedACSCache } from '../item'; | ||
| export declare class ACSCacheCollection extends BaseCacheCollection<ACSCache> { | ||
| protected createCache(): ACSCache; | ||
| } | ||
| export declare class PaginatedACSCacheCollection extends BaseCacheCollection<PaginatedACSCache> { | ||
| protected createCache(): PaginatedACSCache; | ||
| } | ||
| //# sourceMappingURL=collection.d.ts.map |
| {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../../../src/cache/collection/collection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAErD,qBAAa,kBAAmB,SAAQ,mBAAmB,CAAC,QAAQ,CAAC;IACjE,SAAS,CAAC,WAAW,IAAI,QAAQ;CAGpC;AAED,qBAAa,2BAA4B,SAAQ,mBAAmB,CAAC,iBAAiB,CAAC;IACnF,SAAS,CAAC,WAAW,IAAI,iBAAiB;CAG7C"} |
| export type * from './base'; | ||
| export * from './collection'; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cache/collection/index.ts"],"names":[],"mappings":"AAGA,mBAAmB,QAAQ,CAAA;AAC3B,cAAc,cAAc,CAAA"} |
| import { ACEvent, ACSState, PaginatedACSState } from '../../types'; | ||
| import { AbstractLedgerProvider } from '@canton-network/core-provider-ledger'; | ||
| import { LedgerCommonSchemas } from '@canton-network/core-ledger-client-types'; | ||
| import pino from 'pino'; | ||
| import { ResolvedAcsOptions, AcsService, PaginatedResolvedAcsOptions } from '../../service'; | ||
| export declare const logger: pino.Logger<never, boolean>; | ||
| /** | ||
| * Checks if an event represents a contract creation. | ||
| * Used to distinguish between created and archived events when processing cache updates. | ||
| */ | ||
| export declare function isCreatedEvent(event: ACEvent): event is ACEvent & { | ||
| archived: false; | ||
| event: LedgerCommonSchemas['CreatedEvent']; | ||
| }; | ||
| export type BaseCache<Paginated extends boolean> = { | ||
| State: Paginated extends true ? PaginatedACSState : ACSState; | ||
| Options: Paginated extends true ? PaginatedResolvedAcsOptions : ResolvedAcsOptions; | ||
| ReturnValue: ReturnType<AcsService[Paginated extends true ? 'getPaginatedActiveContracts' : 'getActiveContracts']>; | ||
| }; | ||
| export declare abstract class BaseACSCache<Paginated extends boolean = false> { | ||
| protected readonly ledger: AbstractLedgerProvider; | ||
| protected abstract readonly state: BaseCache<Paginated>['State']; | ||
| protected readonly service: AcsService; | ||
| constructor(ledger: AbstractLedgerProvider); | ||
| /** | ||
| * Updates the cache to include ledger changes up to the specified offset. | ||
| * Fetches and applies incremental updates from the ledger, initializing the cache if needed. | ||
| * Automatically prunes old events when the update buffer exceeds configured thresholds (when not in pagination mode). | ||
| */ | ||
| abstract update(options: BaseCache<Paginated>['Options']): Promise<void>; | ||
| /** | ||
| * Calculates the active contract set at a specific ledger offset. | ||
| * Applies cached updates to the initial snapshot and filters out archived contracts. | ||
| * Throws an error if the cache is not initialized or the requested offset is too old. | ||
| */ | ||
| abstract calculateAt(offset: number): LedgerCommonSchemas['JsGetActiveContractsResponse'][]; | ||
| } | ||
| //# sourceMappingURL=base.d.ts.map |
| {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/cache/item/base.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAA;AAC7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAC9E,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EACH,kBAAkB,EAClB,UAAU,EACV,2BAA2B,EAC9B,MAAM,eAAe,CAAA;AAEtB,eAAO,MAAM,MAAM,6BAAqC,CAAA;AAExD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,GAAG;IAC/D,QAAQ,EAAE,KAAK,CAAA;IACf,KAAK,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;CAC7C,CAEA;AAED,MAAM,MAAM,SAAS,CAAC,SAAS,SAAS,OAAO,IAAI;IAC/C,KAAK,EAAE,SAAS,SAAS,IAAI,GAAG,iBAAiB,GAAG,QAAQ,CAAA;IAC5D,OAAO,EAAE,SAAS,SAAS,IAAI,GACzB,2BAA2B,GAC3B,kBAAkB,CAAA;IACxB,WAAW,EAAE,UAAU,CACnB,UAAU,CAAC,SAAS,SAAS,IAAI,GAC3B,6BAA6B,GAC7B,oBAAoB,CAAC,CAC9B,CAAA;CACJ,CAAA;AAED,8BAAsB,YAAY,CAAC,SAAS,SAAS,OAAO,GAAG,KAAK;IAKpD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,sBAAsB;IAJ7D,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAA;IAEhE,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;gBAEP,MAAM,EAAE,sBAAsB;IAI7D;;;;OAIG;aACa,MAAM,CAClB,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,GACzC,OAAO,CAAC,IAAI,CAAC;IAEhB;;;;OAIG;aACa,WAAW,CACvB,MAAM,EAAE,MAAM,GACf,mBAAmB,CAAC,8BAA8B,CAAC,EAAE;CAC3D"} |
| export type * from './base'; | ||
| export * from './item'; | ||
| export * from './paginatedItem'; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cache/item/index.ts"],"names":[],"mappings":"AAGA,mBAAmB,QAAQ,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,iBAAiB,CAAA"} |
| import { ACSState } from '../../types'; | ||
| import { ResolvedAcsOptions } from '../../service'; | ||
| import { BaseACSCache } from './base'; | ||
| export declare class ACSCache extends BaseACSCache { | ||
| protected readonly state: ACSState; | ||
| /** | ||
| * Returns the initial snapshot of the active contract set. | ||
| * Contains the base state captured at a specific ledger offset. | ||
| */ | ||
| private get initial(); | ||
| /** | ||
| * Returns the incremental updates applied after the initial snapshot. | ||
| * Contains created and archived events that occurred since the initial state. | ||
| */ | ||
| private get updates(); | ||
| update(options: ResolvedAcsOptions): Promise<void>; | ||
| calculateAt(offset: number): ({ | ||
| workflowId?: string; | ||
| contractEntry?: import("../../../../ledger-client-types/dist/generated-clients/openapi-3.4.12").components["schemas"]["JsContractEntry"]; | ||
| } & { | ||
| workflowId?: string; | ||
| contractEntry?: import("../../../../ledger-client-types/dist/generated-clients/openapi-3.5.1").components["schemas"]["JsContractEntry"]; | ||
| streamContinuationToken?: string; | ||
| })[]; | ||
| /** | ||
| * Initializes the cache state by fetching the active contract set at the specified offset. | ||
| * Clears any existing updates and archived contract tracking. | ||
| */ | ||
| private initState; | ||
| /** | ||
| * Compacts the cache by moving the initial snapshot forward to a more recent offset. | ||
| * Applies accumulated updates to create a new initial state and discards old events. | ||
| * Improves performance by reducing the number of updates to process on each query. | ||
| */ | ||
| private prune; | ||
| /** | ||
| * Fetches ledger updates between two offsets. | ||
| * Queries the ledger API for transactions containing contract create and archive events. | ||
| */ | ||
| private fetchUpdates; | ||
| /** | ||
| * Extracts contract creation and archival events from raw ledger updates. | ||
| * Processes transaction and checkpoint updates to build a list of relevant contract events. | ||
| * Tracks the highest offset seen across all updates. | ||
| */ | ||
| private extractEvents; | ||
| } | ||
| //# sourceMappingURL=item.d.ts.map |
| {"version":3,"file":"item.d.ts","sourceRoot":"","sources":["../../../src/cache/item/item.ts"],"names":[],"mappings":"AAGA,OAAO,EAA8B,QAAQ,EAAE,MAAM,aAAa,CAAA;AAGlE,OAAO,EAAE,kBAAkB,EAA6B,MAAM,eAAe,CAAA;AAE7E,OAAO,EAAE,YAAY,EAA0B,MAAM,QAAQ,CAAA;AAE7D,qBAAa,QAAS,SAAQ,YAAY;IACtC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAUjC;IAED;;;OAGG;IACH,OAAO,KAAK,OAAO,GAElB;IAED;;;OAGG;IACH,OAAO,KAAK,OAAO,GAElB;IAEY,MAAM,CAAC,OAAO,EAAE,kBAAkB;IAqCxC,WAAW,CAAC,MAAM,EAAE,MAAM;;wBAqMy8yH,qGAAsB;;;wBAAm6xB,oGAAsB;;;IAtJz7kJ;;;OAGG;YACW,SAAS;IAavB;;;;OAIG;IACH,OAAO,CAAC,KAAK;IAoBb;;;OAGG;YACW,YAAY;IAmC1B;;;;OAIG;IACH,OAAO,CAAC,aAAa;CA+DxB"} |
| import { PaginatedResolvedAcsOptions } from '../../service'; | ||
| import { PaginatedACSState } from '../../types'; | ||
| import { BaseACSCache } from './base'; | ||
| export declare class PaginatedACSCache extends BaseACSCache<true> { | ||
| static readonly FIRST_PAGE_TOKEN = ""; | ||
| protected readonly state: PaginatedACSState; | ||
| /** | ||
| * Token for fetching pages of active contracts. will loop over pages until desired offset is reached. When last obtained page was the last one it is `undefined` | ||
| */ | ||
| private nextPageToken; | ||
| update(options: PaginatedResolvedAcsOptions): Promise<void>; | ||
| calculateAt(offset: number): { | ||
| workflowId?: string; | ||
| contractEntry?: import("../../../../ledger-client-types/dist/generated-clients/openapi-3.5.1").components["schemas"]["JsContractEntry"]; | ||
| streamContinuationToken?: string; | ||
| }[]; | ||
| /** | ||
| * Retrieves a specific page from the cache using the page token. | ||
| */ | ||
| getPage(pageToken: string): { | ||
| activeContracts: import("../../../../ledger-client-types/dist/generated-clients/openapi-3.5.1").components["schemas"]["JsGetActiveContractsResponse"][]; | ||
| activeAtOffset: number; | ||
| nextPageToken?: string; | ||
| }; | ||
| /** | ||
| * Initializes the cache state by fetching the first page of active contracts. | ||
| */ | ||
| private initState; | ||
| } | ||
| //# sourceMappingURL=paginatedItem.d.ts.map |
| {"version":3,"file":"paginatedItem.d.ts","sourceRoot":"","sources":["../../../src/cache/item/paginatedItem.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAErC,qBAAa,iBAAkB,SAAQ,YAAY,CAAC,IAAI,CAAC;IACrD,gBAAuB,gBAAgB,MAAK;IAC5C,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAS1C;IAED;;OAEG;IACH,OAAO,CAAC,aAAa,CACiB;IAEzB,MAAM,CAAC,OAAO,EAAE,2BAA2B;IA6BjD,WAAW,CAAC,MAAM,EAAE,MAAM;;wBAoCs4xJ,oGAAsB;;;IAnB77xJ;;OAEG;IACI,OAAO,CAAC,SAAS,EAAE,MAAM;yBAgBswvJ,oGAAsB;;;;IAZ5zvJ;;OAEG;YACW,SAAS;CAQ1B"} |
| import { AbstractLedgerProvider } from '@canton-network/core-provider-ledger'; | ||
| import { ACSCacheCollection, PaginatedACSCacheCollection } from '../cache/collection/collection'; | ||
| import { AcsOptions, AcsService, PaginatedAcsOptions, PaginatedResolvedAcsOptions, ResolvedAcsOptions } from '../service'; | ||
| import { ACSCacheCollectionOptions } from '../cache/collection'; | ||
| export declare abstract class BaseReader<Options extends AcsOptions | PaginatedAcsOptions> { | ||
| protected readonly ledger: AbstractLedgerProvider; | ||
| protected readonly cacheOptions?: ACSCacheCollectionOptions | undefined; | ||
| protected cacheCollection: ACSCacheCollection | PaginatedACSCacheCollection; | ||
| protected service: AcsService; | ||
| constructor(ledger: AbstractLedgerProvider, cacheOptions?: ACSCacheCollectionOptions | undefined); | ||
| /** | ||
| * Creates the appropriate cache collection for this reader. | ||
| * | ||
| * @internal For internal use only. | ||
| * @returns The cache collection instance | ||
| */ | ||
| protected abstract createCacheCollection(): ACSCacheCollection | PaginatedACSCacheCollection; | ||
| /** | ||
| * Reads active contracts from the cache. | ||
| */ | ||
| read(options: Options): Promise<({ | ||
| workflowId?: string; | ||
| contractEntry?: import("../../../ledger-client-types/dist/generated-clients/openapi-3.4.12").components["schemas"]["JsContractEntry"]; | ||
| } & { | ||
| workflowId?: string; | ||
| contractEntry?: import("../../../ledger-client-types/dist/generated-clients/openapi-3.5.1").components["schemas"]["JsContractEntry"]; | ||
| streamContinuationToken?: string; | ||
| })[]>; | ||
| /** | ||
| * Convenience method that returns active contracts as JS contract objects. | ||
| */ | ||
| readJsContracts(options: Options): Promise<{ | ||
| synchronizerId: string; | ||
| offset: number; | ||
| nodeId: number; | ||
| contractId: string; | ||
| templateId: string; | ||
| contractKey?: unknown; | ||
| createArgument: unknown; | ||
| createdEventBlob?: string; | ||
| interfaceViews?: { | ||
| interfaceId: string; | ||
| viewStatus: import("../../../ledger-client-types/dist/generated-clients/openapi-3.4.12").components["schemas"]["JsStatus"]; | ||
| viewValue?: unknown; | ||
| }[] & { | ||
| interfaceId: string; | ||
| viewStatus: import("../../../ledger-client-types/dist/generated-clients/openapi-3.5.1").components["schemas"]["JsStatus"]; | ||
| viewValue?: unknown; | ||
| implementationPackageId?: string; | ||
| }[]; | ||
| witnessParties: string[]; | ||
| signatories: string[]; | ||
| observers?: string[]; | ||
| createdAt: string; | ||
| packageName: string; | ||
| representativePackageId: string; | ||
| acsDelta: boolean; | ||
| contractKeyHash?: string; | ||
| }[]>; | ||
| /** | ||
| * Extracts active contracts from various output formats (single page, array of pages, or array of responses). | ||
| */ | ||
| private getActiveContracts; | ||
| /** | ||
| * Transforms active contracts output into JS contract objects with created event details and synchronizer ID. | ||
| */ | ||
| private readJsContractsWith; | ||
| /** | ||
| * Resolves ACS options by ensuring an offset is present, fetching the current ledger end if needed. | ||
| */ | ||
| protected resolveAcsOptions(options: Options): Promise<Options extends PaginatedAcsOptions ? PaginatedResolvedAcsOptions : ResolvedAcsOptions>; | ||
| } | ||
| //# sourceMappingURL=base.d.ts.map |
| {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/reader/base.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,sBAAsB,EAEzB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EACH,kBAAkB,EAClB,2BAA2B,EAC9B,MAAM,gCAAgC,CAAA;AACvC,OAAO,EACH,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,2BAA2B,EAC3B,kBAAkB,EACrB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAE/D,8BAAsB,UAAU,CAC5B,OAAO,SAAS,UAAU,GAAG,mBAAmB;IAK5C,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,sBAAsB;IACjD,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,yBAAyB;IAJ/D,SAAS,CAAC,eAAe,EAAE,kBAAkB,GAAG,2BAA2B,CAAA;IAC3E,SAAS,CAAC,OAAO,EAAE,UAAU,CAAA;gBAEN,MAAM,EAAE,sBAAsB,EAC9B,YAAY,CAAC,EAAE,yBAAyB,YAAA;IAM/D;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,qBAAqB,IAClC,kBAAkB,GAClB,2BAA2B;IAEjC;;OAEG;IACU,IAAI,CAAC,OAAO,EAAE,OAAO;;wBA4F0t9H,kGAAsB;;;wBAAm6xB,iGAAsB;;;IAvF3svJ;;OAEG;IACU,eAAe,CAAC,OAAO,EAAE,OAAO;;;;;;;;;;;wBAoFs+kI,kGAAsB;;;;wBAA2y1B,iGAAsB;;;;;;;;;;;;;IAhF126J;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA0B1B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAuB3B;;OAEG;cACa,iBAAiB,CAC7B,OAAO,EAAE,OAAO,GACjB,OAAO,CACN,OAAO,SAAS,mBAAmB,GAC7B,2BAA2B,GAC3B,kBAAkB,CAC3B;CAeJ"} |
| export type * from './base'; | ||
| export * from './reader'; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reader/index.ts"],"names":[],"mappings":"AAGA,mBAAmB,QAAQ,CAAA;AAC3B,cAAc,UAAU,CAAA"} |
| import { AbstractLedgerProvider } from '@canton-network/core-provider-ledger'; | ||
| import { AcsOptions, PaginatedAcsOptions } from '../service'; | ||
| import { BaseReader } from './base'; | ||
| import { ACSCacheCollection, ACSCacheCollectionOptions, PaginatedACSCacheCollection } from '../cache/collection'; | ||
| import { LedgerCommonSchemas } from '@canton-network/core-ledger-client-types'; | ||
| declare class RawReader extends BaseReader<AcsOptions> { | ||
| protected readonly ledger: AbstractLedgerProvider; | ||
| protected readonly cacheOptions?: ACSCacheCollectionOptions | undefined; | ||
| private readonly paginated?; | ||
| constructor(ledger: AbstractLedgerProvider, cacheOptions?: ACSCacheCollectionOptions | undefined, paginated?: boolean | undefined); | ||
| read(options: AcsOptions): Promise<LedgerCommonSchemas['JsGetActiveContractsResponse'][]>; | ||
| protected createCacheCollection(): ACSCacheCollection | PaginatedACSCacheCollection; | ||
| } | ||
| declare class PaginatedReader extends BaseReader<PaginatedAcsOptions> { | ||
| protected readonly ledger: AbstractLedgerProvider; | ||
| protected readonly cacheOptions?: ACSCacheCollectionOptions | undefined; | ||
| readonly raw: RawReader; | ||
| constructor(ledger: AbstractLedgerProvider, cacheOptions?: ACSCacheCollectionOptions | undefined); | ||
| protected createCacheCollection(): PaginatedACSCacheCollection; | ||
| } | ||
| export declare class ACSReader extends BaseReader<AcsOptions> { | ||
| protected readonly ledger: AbstractLedgerProvider; | ||
| protected readonly cacheOptions?: ACSCacheCollectionOptions | undefined; | ||
| readonly raw: RawReader; | ||
| readonly paginated: PaginatedReader; | ||
| constructor(ledger: AbstractLedgerProvider, cacheOptions?: ACSCacheCollectionOptions | undefined); | ||
| protected createCacheCollection(): ACSCacheCollection; | ||
| } | ||
| export {}; | ||
| //# sourceMappingURL=reader.d.ts.map |
| {"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../src/reader/reader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAA;AAC7E,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EACH,kBAAkB,EAClB,yBAAyB,EACzB,2BAA2B,EAC9B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAQ9E,cAAM,SAAU,SAAQ,UAAU,CAAC,UAAU,CAAC;IAEtC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,sBAAsB;IACjD,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,yBAAyB;IAC3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAFR,MAAM,EAAE,sBAAsB,EAC9B,YAAY,CAAC,EAAE,yBAAyB,YAAA,EAC1C,SAAS,CAAC,EAAE,OAAO,YAAA;IAK3B,IAAI,CACb,OAAO,EAAE,UAAU,GACpB,OAAO,CAAC,mBAAmB,CAAC,8BAA8B,CAAC,EAAE,CAAC;IAkBjE,SAAS,CAAC,qBAAqB;CAKlC;AAED,cAAM,eAAgB,SAAQ,UAAU,CAAC,mBAAmB,CAAC;IAIrD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,sBAAsB;IACjD,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,yBAAyB;IAJ/D,SAAgB,GAAG,EAAE,SAAS,CAAA;gBAGP,MAAM,EAAE,sBAAsB,EAC9B,YAAY,CAAC,EAAE,yBAAyB,YAAA;IAO/D,SAAS,CAAC,qBAAqB;CAGlC;AAED,qBAAa,SAAU,SAAQ,UAAU,CAAC,UAAU,CAAC;IAK7C,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,sBAAsB;IACjD,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,yBAAyB;IAL/D,SAAgB,GAAG,EAAE,SAAS,CAAA;IAC9B,SAAgB,SAAS,EAAE,eAAe,CAAA;gBAGnB,MAAM,EAAE,sBAAsB,EAC9B,YAAY,CAAC,EAAE,yBAAyB,YAAA;IAO/D,SAAS,CAAC,qBAAqB;CAGlC"} |
+439
-263
| 'use strict'; | ||
| var pino = require('pino'); | ||
| var typescriptLruCache = require('typescript-lru-cache'); | ||
| var pino = require('pino'); | ||
@@ -16,10 +16,301 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } | ||
| var ACS_UPDATE_CONFIG = { | ||
| // How many events do we accumulate before we prune (compact) the ACS history - set to 0 to enable to compact all events, which is more efficient as long as application always ask for increasing (or equal) offsets | ||
| maxEventsBeforePrune: 150, | ||
| // When we compact the ACS history, we keep all events within this offset delta of the last seen update offset - set 0 to allow to compact everything | ||
| safeOffsetDeltaForPrune: 200, | ||
| // How many updates do we fetch at once when fetching updates - if there are more updates, we will fetch again until we have caught up (returned data is always complete to the requested endInclusive offset - even if that means multiple fetches) | ||
| maxUpdatesToFetch: 100 | ||
| }; | ||
| var logger = pino__default.default({ name: "acs-reader/cache" }); | ||
| function isCreatedEvent(event) { | ||
| return !event.archived; | ||
| } | ||
| var BaseACSCache = class { | ||
| constructor(ledger) { | ||
| this.ledger = ledger; | ||
| __publicField(this, "service"); | ||
| this.service = new AcsService(ledger); | ||
| } | ||
| }; | ||
| // src/cache/item/item.ts | ||
| var ACSCache = class extends BaseACSCache { | ||
| constructor() { | ||
| super(...arguments); | ||
| __publicField(this, "state", { | ||
| initial: { | ||
| offset: 0, | ||
| acs: [] | ||
| }, | ||
| updates: { | ||
| offset: 0, | ||
| acs: [] | ||
| }, | ||
| archivedACs: /* @__PURE__ */ new Set() | ||
| }); | ||
| } | ||
| /** | ||
| * Returns the initial snapshot of the active contract set. | ||
| * Contains the base state captured at a specific ledger offset. | ||
| */ | ||
| get initial() { | ||
| return this.state.initial; | ||
| } | ||
| /** | ||
| * Returns the incremental updates applied after the initial snapshot. | ||
| * Contains created and archived events that occurred since the initial state. | ||
| */ | ||
| get updates() { | ||
| return this.state.updates; | ||
| } | ||
| async update(options) { | ||
| if (!this.initial.acs.length || this.initial.offset > options.offset) { | ||
| await this.initState(options); | ||
| } | ||
| const builtFilter = buildActiveContractFilter(options); | ||
| const updates = await this.fetchUpdates({ | ||
| beginExclusive: this.updates.offset, | ||
| endInclusive: options.offset, | ||
| eventFormat: { | ||
| verbose: Boolean(builtFilter.verbose), | ||
| ...builtFilter.filter | ||
| } | ||
| }); | ||
| if (updates.length >= ACS_UPDATE_CONFIG.maxUpdatesToFetch) | ||
| void this.update(options); | ||
| const { newEvents, newOffset } = this.extractEvents({ | ||
| offset: this.updates.offset, | ||
| updates | ||
| }); | ||
| if (newOffset > this.updates.offset) { | ||
| this.updates.offset = newOffset; | ||
| this.updates.acs = this.updates.acs.concat(newEvents); | ||
| } else this.updates.offset = options.offset; | ||
| if (this.updates.acs.length >= ACS_UPDATE_CONFIG.maxEventsBeforePrune) { | ||
| this.prune(); | ||
| } | ||
| } | ||
| calculateAt(offset) { | ||
| if (!this.initial.acs) | ||
| throw Error("No ACS initialized. Call `.update()` first"); | ||
| if (this.initial.offset > offset) | ||
| throw Error("Provided offset cannot be smaller than ACS offset"); | ||
| const newContracts = []; | ||
| const newArchivedContracts = /* @__PURE__ */ new Set(); | ||
| this.updates.acs.filter((ac) => ac.offset <= offset).map((ac) => { | ||
| if (isCreatedEvent(ac)) { | ||
| newContracts.push({ | ||
| workflowId: ac.workflowId ?? "", | ||
| contractEntry: { | ||
| JsActiveContract: { | ||
| createdEvent: ac.event, | ||
| synchronizerId: ac.synchronizerId ?? "", | ||
| reassignmentCounter: 0 | ||
| } | ||
| } | ||
| }); | ||
| } else { | ||
| newArchivedContracts.add( | ||
| ac.event.contractId | ||
| ); | ||
| } | ||
| }); | ||
| const allContracts = this.initial.acs.concat(newContracts); | ||
| this.state.archivedACs = this.state.archivedACs.union(newArchivedContracts); | ||
| return allContracts.filter(({ contractEntry }) => { | ||
| if (!contractEntry) return false; | ||
| const id = "JsActiveContract" in contractEntry ? contractEntry.JsActiveContract.createdEvent.contractId : ""; | ||
| return !this.state.archivedACs.has(id); | ||
| }); | ||
| } | ||
| /** | ||
| * Initializes the cache state by fetching the active contract set at the specified offset. | ||
| * Clears any existing updates and archived contract tracking. | ||
| */ | ||
| async initState(options) { | ||
| const initialAcs = await this.service.getActiveContracts(options); | ||
| this.state.initial = { | ||
| offset: options.offset, | ||
| acs: initialAcs | ||
| }; | ||
| this.state.updates = { | ||
| offset: options.offset, | ||
| acs: [] | ||
| }; | ||
| this.state.archivedACs = /* @__PURE__ */ new Set(); | ||
| } | ||
| /** | ||
| * Compacts the cache by moving the initial snapshot forward to a more recent offset. | ||
| * Applies accumulated updates to create a new initial state and discards old events. | ||
| * Improves performance by reducing the number of updates to process on each query. | ||
| */ | ||
| prune() { | ||
| const newOffset = Math.max( | ||
| this.initial.offset, | ||
| this.updates.offset - ACS_UPDATE_CONFIG.safeOffsetDeltaForPrune | ||
| ); | ||
| if (newOffset > this.initial.offset) { | ||
| const responses = this.calculateAt(newOffset); | ||
| this.state.initial = { | ||
| offset: newOffset, | ||
| acs: responses | ||
| }; | ||
| this.state.updates = { | ||
| offset: this.updates.offset, | ||
| acs: this.updates.acs.filter((ac) => ac.offset > newOffset) | ||
| }; | ||
| } | ||
| } | ||
| /** | ||
| * Fetches ledger updates between two offsets. | ||
| * Queries the ledger API for transactions containing contract create and archive events. | ||
| */ | ||
| async fetchUpdates(args) { | ||
| const { beginExclusive, endInclusive, eventFormat, filter } = args; | ||
| const updateFormat = { | ||
| includeTransactions: { | ||
| eventFormat, | ||
| transactionShape: "TRANSACTION_SHAPE_ACS_DELTA" | ||
| } | ||
| }; | ||
| return await this.ledger.request({ | ||
| method: "ledgerApi", | ||
| params: { | ||
| resource: "/v2/updates", | ||
| requestMethod: "post", | ||
| body: { | ||
| beginExclusive, | ||
| endInclusive, | ||
| updateFormat, | ||
| verbose: false, | ||
| ...filter ? { filter } : {} | ||
| }, | ||
| query: { | ||
| limit: ACS_UPDATE_CONFIG.maxUpdatesToFetch, | ||
| stream_idle_timeout_ms: 1e3 | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Extracts contract creation and archival events from raw ledger updates. | ||
| * Processes transaction and checkpoint updates to build a list of relevant contract events. | ||
| * Tracks the highest offset seen across all updates. | ||
| */ | ||
| extractEvents(args) { | ||
| const { updates, offset } = args; | ||
| const newEvents = []; | ||
| let newOffset = offset; | ||
| updates.forEach((update) => { | ||
| if (!update || !update.update) { | ||
| return; | ||
| } | ||
| if ("Transaction" in update.update) { | ||
| const transaction = update.update.Transaction; | ||
| const trOffset = transaction?.value?.offset; | ||
| if (trOffset && trOffset > newOffset) { | ||
| const events = transaction?.value?.events ?? []; | ||
| events.forEach((event) => { | ||
| if (!event) { | ||
| return; | ||
| } | ||
| if ("CreatedEvent" in event || "ArchivedEvent" in event) { | ||
| const eventData = "CreatedEvent" in event ? event.CreatedEvent : event.ArchivedEvent; | ||
| const acUpdate = { | ||
| event: eventData, | ||
| offset: trOffset, | ||
| workflowId: transaction?.value?.workflowId ?? null, | ||
| synchronizerId: transaction?.value?.synchronizerId ?? null, | ||
| ..."ArchivedEvent" in event && { | ||
| archived: true | ||
| } | ||
| }; | ||
| newEvents.push(acUpdate); | ||
| newOffset = trOffset; | ||
| } | ||
| }); | ||
| } | ||
| } else if ("OffsetCheckpoint" in update.update) { | ||
| const checkpoint = update.update.OffsetCheckpoint; | ||
| const offset2 = checkpoint?.value?.offset; | ||
| if (offset2) { | ||
| newOffset = offset2; | ||
| } | ||
| } else { | ||
| logger.warn( | ||
| { | ||
| value: JSON.stringify(update.update) | ||
| }, | ||
| "ACS update got unknown update type" | ||
| ); | ||
| } | ||
| }); | ||
| return { newEvents, newOffset }; | ||
| } | ||
| }; | ||
| // src/cache/item/paginatedItem.ts | ||
| var _PaginatedACSCache = class _PaginatedACSCache extends BaseACSCache { | ||
| constructor() { | ||
| super(...arguments); | ||
| __publicField(this, "state", { | ||
| pages: { | ||
| [_PaginatedACSCache.FIRST_PAGE_TOKEN]: { | ||
| activeContracts: [], | ||
| activeAtOffset: 0, | ||
| nextPageToken: "" | ||
| } | ||
| }, | ||
| offset: 0 | ||
| }); | ||
| /** | ||
| * Token for fetching pages of active contracts. will loop over pages until desired offset is reached. When last obtained page was the last one it is `undefined` | ||
| */ | ||
| __publicField(this, "nextPageToken", _PaginatedACSCache.FIRST_PAGE_TOKEN); | ||
| } | ||
| async update(options) { | ||
| if (!this.state.pages[_PaginatedACSCache.FIRST_PAGE_TOKEN].activeContracts.length && !this.state.pages[_PaginatedACSCache.FIRST_PAGE_TOKEN].nextPageToken) { | ||
| await this.initState(options); | ||
| } | ||
| if (options.pageToken) { | ||
| this.state.pages[options.pageToken] = await this.service.getPaginatedActiveContracts(options); | ||
| this.nextPageToken = this.state.pages[options.pageToken].nextPageToken; | ||
| } else { | ||
| while (this.nextPageToken && options.offset > this.state.offset) { | ||
| this.state.pages[this.nextPageToken] = await this.service.getPaginatedActiveContracts({ | ||
| ...options, | ||
| pageToken: this.nextPageToken | ||
| }); | ||
| this.state.offset = this.state.pages[this.nextPageToken].activeAtOffset; | ||
| this.nextPageToken = this.state.pages[this.nextPageToken].nextPageToken; | ||
| } | ||
| } | ||
| } | ||
| calculateAt(offset) { | ||
| const activeContracts = Object.values(this.state.pages).flatMap( | ||
| (page) => page.activeContracts | ||
| ); | ||
| if (!activeContracts.length) | ||
| throw Error("No ACS initialized. Call `.update()` first"); | ||
| return activeContracts.filter((ac) => { | ||
| const event = ac.contractEntry && "JsActiveContract" in ac.contractEntry ? ac.contractEntry.JsActiveContract.createdEvent : void 0; | ||
| return event && event.offset <= offset; | ||
| }); | ||
| } | ||
| /** | ||
| * Retrieves a specific page from the cache using the page token. | ||
| */ | ||
| getPage(pageToken) { | ||
| return this.state.pages[pageToken]; | ||
| } | ||
| /** | ||
| * Initializes the cache state by fetching the first page of active contracts. | ||
| */ | ||
| async initState(options) { | ||
| const firstPage = await this.service.getPaginatedActiveContracts(options); | ||
| this.state.pages[_PaginatedACSCache.FIRST_PAGE_TOKEN] = firstPage; | ||
| this.state.offset = firstPage.activeAtOffset; | ||
| this.nextPageToken = firstPage.nextPageToken; | ||
| } | ||
| }; | ||
| __publicField(_PaginatedACSCache, "FIRST_PAGE_TOKEN", ""); | ||
| var PaginatedACSCache = _PaginatedACSCache; | ||
| // src/service.ts | ||
@@ -32,2 +323,48 @@ var COMPLETIONS_LIMIT = "100"; | ||
| } | ||
| async getPaginatedActiveContracts(options) { | ||
| const { continueUntilCompletion, ...baseArgs } = options; | ||
| const { maxPageSize, pageToken } = baseArgs; | ||
| const { activeAtOffset, filter } = buildActiveContractFilter(options); | ||
| if (continueUntilCompletion) { | ||
| const results = []; | ||
| let shouldContinue = true; | ||
| while (shouldContinue) { | ||
| const pageToken2 = results.length ? results[results.length - 1].nextPageToken : PaginatedACSCache.FIRST_PAGE_TOKEN; | ||
| const result = await this.getPaginatedActiveContracts({ | ||
| ...baseArgs, | ||
| continueUntilCompletion: false, | ||
| ...pageToken2 ? { pageToken: pageToken2 } : {} | ||
| }); | ||
| results.push(result); | ||
| shouldContinue = Boolean(result.nextPageToken); | ||
| } | ||
| return results; | ||
| } | ||
| const body = { | ||
| eventFormat: {}, | ||
| activeAtOffset | ||
| }; | ||
| if (filter?.filtersByParty) { | ||
| body.eventFormat.filtersByParty = filter.filtersByParty; | ||
| } | ||
| if (filter?.filtersForAnyParty) { | ||
| body.eventFormat.filtersForAnyParty = filter.filtersForAnyParty; | ||
| } | ||
| if (maxPageSize !== void 0) { | ||
| body.maxPageSize = maxPageSize; | ||
| } | ||
| if (pageToken !== void 0) { | ||
| body.pageToken = pageToken; | ||
| } | ||
| return await this.ledgerProvider.request( | ||
| { | ||
| method: "ledgerApi", | ||
| params: { | ||
| requestMethod: "get", | ||
| resource: "/v2/state/active-contracts-page", | ||
| body | ||
| } | ||
| } | ||
| ); | ||
| } | ||
| async getActiveContracts(options) { | ||
@@ -277,236 +614,71 @@ const { limit, continueUntilCompletion } = options; | ||
| // src/cache/cache.ts | ||
| var logger = pino__default.default({ name: "acs-reader/cache" }); | ||
| var ACSCache = class { | ||
| constructor(ledger) { | ||
| // src/reader/base.ts | ||
| var BaseReader = class { | ||
| constructor(ledger, cacheOptions) { | ||
| this.ledger = ledger; | ||
| __publicField(this, "state", { | ||
| initial: { | ||
| offset: 0, | ||
| acs: [] | ||
| }, | ||
| updates: { | ||
| offset: 0, | ||
| acs: [] | ||
| }, | ||
| archivedACs: /* @__PURE__ */ new Set() | ||
| }); | ||
| this.cacheOptions = cacheOptions; | ||
| __publicField(this, "cacheCollection"); | ||
| __publicField(this, "service"); | ||
| this.cacheCollection = this.createCacheCollection(); | ||
| this.service = new AcsService(ledger); | ||
| } | ||
| /** | ||
| * Returns the initial snapshot of the active contract set. | ||
| * Contains the base state captured at a specific ledger offset. | ||
| * Reads active contracts from the cache. | ||
| */ | ||
| get initial() { | ||
| return this.state.initial; | ||
| async read(options) { | ||
| const resolvedOptions = await this.resolveAcsOptions(options); | ||
| return await this.cacheCollection.readFromCache(resolvedOptions); | ||
| } | ||
| /** | ||
| * Returns the incremental updates applied after the initial snapshot. | ||
| * Contains created and archived events that occurred since the initial state. | ||
| * Convenience method that returns active contracts as JS contract objects. | ||
| */ | ||
| get updates() { | ||
| return this.state.updates; | ||
| async readJsContracts(options) { | ||
| return this.readJsContractsWith(await this.read(options)); | ||
| } | ||
| /** | ||
| * Updates the cache to include ledger changes up to the specified offset. | ||
| * Fetches and applies incremental updates from the ledger, initializing the cache if needed. | ||
| * Automatically prunes old events when the update buffer exceeds configured thresholds. | ||
| * Extracts active contracts from various output formats (single page, array of pages, or array of responses). | ||
| */ | ||
| async update(options) { | ||
| if (!this.initial.acs.length || this.initial.offset > options.offset) { | ||
| await this.initState(options); | ||
| getActiveContracts(output) { | ||
| if (!Array.isArray(output)) { | ||
| return "activeContracts" in output ? output.activeContracts : []; | ||
| } | ||
| const builtFilter = buildActiveContractFilter(options); | ||
| const updates = await this.fetchUpdates({ | ||
| beginExclusive: this.updates.offset, | ||
| endInclusive: options.offset, | ||
| eventFormat: { | ||
| verbose: Boolean(builtFilter.verbose), | ||
| ...builtFilter.filter | ||
| } | ||
| }); | ||
| if (updates.length >= ACS_UPDATE_CONFIG.maxUpdatesToFetch) | ||
| void this.update(options); | ||
| const { newEvents, newOffset } = this.extractEvents({ | ||
| offset: this.updates.offset, | ||
| updates | ||
| }); | ||
| if (newOffset > this.updates.offset) { | ||
| this.updates.offset = newOffset; | ||
| this.updates.acs = this.updates.acs.concat(newEvents); | ||
| } else this.updates.offset = options.offset; | ||
| if (this.updates.acs.length >= ACS_UPDATE_CONFIG.maxEventsBeforePrune) { | ||
| this.prune(); | ||
| if (output.length > 0 && "activeContracts" in output[0]) { | ||
| return output.flatMap( | ||
| (page) => "activeContracts" in page ? page.activeContracts : [] | ||
| ); | ||
| } | ||
| return output.filter( | ||
| (item) => !("activeContracts" in item) | ||
| ); | ||
| } | ||
| /** | ||
| * Calculates the active contract set at a specific ledger offset. | ||
| * Applies cached updates to the initial snapshot and filters out archived contracts. | ||
| * Throws an error if the cache is not initialized or the requested offset is too old. | ||
| * Transforms active contracts output into JS contract objects with created event details and synchronizer ID. | ||
| */ | ||
| calculateAt(offset) { | ||
| if (!this.initial.acs) | ||
| throw Error("No ACS initialized. Call `.update()` first"); | ||
| if (this.initial.offset > offset) | ||
| throw Error("Provided offset cannot be smaller than ACS offset"); | ||
| const newContracts = []; | ||
| const newArchivedContracts = /* @__PURE__ */ new Set(); | ||
| this.updates.acs.filter((ac) => ac.offset <= offset).map((ac) => { | ||
| if (isCreatedEvent(ac)) { | ||
| newContracts.push({ | ||
| workflowId: ac.workflowId ?? "", | ||
| contractEntry: { | ||
| JsActiveContract: { | ||
| createdEvent: ac.event, | ||
| synchronizerId: ac.synchronizerId ?? "", | ||
| reassignmentCounter: 0 | ||
| } | ||
| } | ||
| }); | ||
| } else { | ||
| newArchivedContracts.add( | ||
| ac.event.contractId | ||
| ); | ||
| } | ||
| readJsContractsWith(output) { | ||
| const contracts = this.getActiveContracts(output); | ||
| return contracts.filter( | ||
| (acs) => acs.contractEntry != null && "JsActiveContract" in acs.contractEntry | ||
| ).map((acs) => { | ||
| const jsActiveContract = acs.contractEntry.JsActiveContract; | ||
| return { | ||
| ...jsActiveContract.createdEvent, | ||
| synchronizerId: jsActiveContract.synchronizerId | ||
| }; | ||
| }); | ||
| const allContracts = this.initial.acs.concat(newContracts); | ||
| this.state.archivedACs = this.state.archivedACs.union(newArchivedContracts); | ||
| return allContracts.filter(({ contractEntry }) => { | ||
| if (!contractEntry) return false; | ||
| const id = "JsActiveContract" in contractEntry ? contractEntry.JsActiveContract.createdEvent.contractId : ""; | ||
| return !this.state.archivedACs.has(id); | ||
| }); | ||
| } | ||
| /** | ||
| * Initializes the cache state by fetching the active contract set at the specified offset. | ||
| * Clears any existing updates and archived contract tracking. | ||
| * Resolves ACS options by ensuring an offset is present, fetching the current ledger end if needed. | ||
| */ | ||
| async initState(options) { | ||
| const initialAcs = await this.service.getActiveContracts(options); | ||
| this.state.initial = { | ||
| offset: options.offset, | ||
| acs: initialAcs | ||
| }; | ||
| this.state.updates = { | ||
| offset: options.offset, | ||
| acs: [] | ||
| }; | ||
| this.state.archivedACs = /* @__PURE__ */ new Set(); | ||
| } | ||
| /** | ||
| * Compacts the cache by moving the initial snapshot forward to a more recent offset. | ||
| * Applies accumulated updates to create a new initial state and discards old events. | ||
| * Improves performance by reducing the number of updates to process on each query. | ||
| */ | ||
| prune() { | ||
| const newOffset = Math.max( | ||
| this.initial.offset, | ||
| this.updates.offset - ACS_UPDATE_CONFIG.safeOffsetDeltaForPrune | ||
| ); | ||
| if (newOffset > this.initial.offset) { | ||
| const responses = this.calculateAt(newOffset); | ||
| this.state.initial = { | ||
| offset: newOffset, | ||
| acs: responses | ||
| }; | ||
| this.state.updates = { | ||
| offset: this.updates.offset, | ||
| acs: this.updates.acs.filter((ac) => ac.offset > newOffset) | ||
| }; | ||
| } | ||
| } | ||
| /** | ||
| * Fetches ledger updates between two offsets. | ||
| * Queries the ledger API for transactions containing contract create and archive events. | ||
| */ | ||
| async fetchUpdates(args) { | ||
| const { beginExclusive, endInclusive, eventFormat, filter } = args; | ||
| const updateFormat = { | ||
| includeTransactions: { | ||
| eventFormat, | ||
| transactionShape: "TRANSACTION_SHAPE_ACS_DELTA" | ||
| } | ||
| }; | ||
| return await this.ledger.request({ | ||
| async resolveAcsOptions(options) { | ||
| const offset = options.offset ?? (await this.ledger.request({ | ||
| method: "ledgerApi", | ||
| params: { | ||
| resource: "/v2/updates", | ||
| requestMethod: "post", | ||
| body: { | ||
| beginExclusive, | ||
| endInclusive, | ||
| updateFormat, | ||
| verbose: false, | ||
| ...filter ? { filter } : {} | ||
| }, | ||
| query: { | ||
| limit: ACS_UPDATE_CONFIG.maxUpdatesToFetch, | ||
| stream_idle_timeout_ms: 1e3 | ||
| } | ||
| resource: "/v2/state/ledger-end", | ||
| requestMethod: "get" | ||
| } | ||
| }); | ||
| })).offset; | ||
| return { ...options, offset }; | ||
| } | ||
| /** | ||
| * Extracts contract creation and archival events from raw ledger updates. | ||
| * Processes transaction and checkpoint updates to build a list of relevant contract events. | ||
| * Tracks the highest offset seen across all updates. | ||
| */ | ||
| extractEvents(args) { | ||
| const { updates, offset } = args; | ||
| const newEvents = []; | ||
| let newOffset = offset; | ||
| updates.forEach((update) => { | ||
| if (!update || !update.update) { | ||
| return; | ||
| } | ||
| if ("Transaction" in update.update) { | ||
| const transaction = update.update.Transaction; | ||
| const trOffset = transaction?.value?.offset; | ||
| if (trOffset && trOffset > newOffset) { | ||
| const events = transaction?.value?.events ?? []; | ||
| events.forEach((event) => { | ||
| if (!event) { | ||
| return; | ||
| } | ||
| if ("CreatedEvent" in event || "ArchivedEvent" in event) { | ||
| const eventData = "CreatedEvent" in event ? event.CreatedEvent : event.ArchivedEvent; | ||
| const acUpdate = { | ||
| event: eventData, | ||
| offset: trOffset, | ||
| workflowId: transaction?.value?.workflowId ?? null, | ||
| synchronizerId: transaction?.value?.synchronizerId ?? null, | ||
| ..."ArchivedEvent" in event && { | ||
| archived: true | ||
| } | ||
| }; | ||
| newEvents.push(acUpdate); | ||
| newOffset = trOffset; | ||
| } | ||
| }); | ||
| } | ||
| } else if ("OffsetCheckpoint" in update.update) { | ||
| const checkpoint = update.update.OffsetCheckpoint; | ||
| const offset2 = checkpoint?.value?.offset; | ||
| if (offset2) { | ||
| newOffset = offset2; | ||
| } | ||
| } else { | ||
| logger.warn( | ||
| { | ||
| value: JSON.stringify(update.update) | ||
| }, | ||
| "ACS update got unknown update type" | ||
| ); | ||
| } | ||
| }); | ||
| return { newEvents, newOffset }; | ||
| } | ||
| }; | ||
| function isCreatedEvent(event) { | ||
| return !event.archived; | ||
| } | ||
| // src/cache/collection.ts | ||
| var ACSCacheCollection = class { | ||
| var BaseCacheCollection = class { | ||
| constructor(ledger, options = { | ||
@@ -525,5 +697,2 @@ maxSize: 100, | ||
| * Queries are deduplicated and cached per party-template-interface combination. | ||
| * | ||
| * @override | ||
| * @see {@link ACSReader.readRaw} | ||
| */ | ||
@@ -546,3 +715,3 @@ async readFromCache(options) { | ||
| if (existingCache) return existingCache; | ||
| const newCache = new ACSCache(this.ledger); | ||
| const newCache = this.createCache(); | ||
| this.collection.set(serializedKey, newCache); | ||
@@ -577,59 +746,66 @@ return newCache; | ||
| // src/reader.ts | ||
| var ACSReader = class { | ||
| constructor(ledger, cacheOptions) { | ||
| // src/cache/collection/collection.ts | ||
| var ACSCacheCollection = class extends BaseCacheCollection { | ||
| createCache() { | ||
| return new ACSCache(this.ledger); | ||
| } | ||
| }; | ||
| var PaginatedACSCacheCollection = class extends BaseCacheCollection { | ||
| createCache() { | ||
| return new PaginatedACSCache(this.ledger); | ||
| } | ||
| }; | ||
| // src/reader/reader.ts | ||
| function isPageResponse(obj) { | ||
| return typeof obj === "object" && obj !== null && "activeContracts" in obj; | ||
| } | ||
| var RawReader = class extends BaseReader { | ||
| constructor(ledger, cacheOptions, paginated) { | ||
| super(ledger, cacheOptions); | ||
| this.ledger = ledger; | ||
| this.cacheOptions = cacheOptions; | ||
| __publicField(this, "cacheCollection"); | ||
| __publicField(this, "service"); | ||
| /** | ||
| * Provides direct access to the ACS without using the cache. | ||
| */ | ||
| __publicField(this, "raw", { | ||
| read: async (options) => { | ||
| const resolvedOptions = await this.resolveAcsOptions(options); | ||
| return await this.service.getActiveContracts(resolvedOptions); | ||
| }, | ||
| readJsContracts: async (options) => { | ||
| return this.readJsContractsWith(await this.raw.read(options)); | ||
| } | ||
| }); | ||
| this.cacheCollection = new ACSCacheCollection(ledger, cacheOptions); | ||
| this.service = new AcsService(ledger); | ||
| this.paginated = paginated; | ||
| } | ||
| /** | ||
| * Reads active contracts from the cache. | ||
| */ | ||
| async read(options) { | ||
| const resolvedOptions = await this.resolveAcsOptions(options); | ||
| return await this.cacheCollection.readFromCache(resolvedOptions); | ||
| const output = await (this.paginated ? this.service.getPaginatedActiveContracts(resolvedOptions) : this.service.getActiveContracts(resolvedOptions)); | ||
| if (!Array.isArray(output)) { | ||
| return isPageResponse(output) ? output.activeContracts : []; | ||
| } | ||
| const first = output[0]; | ||
| return first && isPageResponse(first) ? output.flatMap( | ||
| (page) => isPageResponse(page) ? page.activeContracts : [] | ||
| ) : output; | ||
| } | ||
| /** | ||
| * Convenience method that returns active contracts as JS contract objects. | ||
| */ | ||
| async readJsContracts(options) { | ||
| return this.readJsContractsWith(await this.read(options)); | ||
| createCacheCollection() { | ||
| return this.paginated ? new PaginatedACSCacheCollection(this.ledger, this.cacheOptions) : new ACSCacheCollection(this.ledger, this.cacheOptions); | ||
| } | ||
| readJsContractsWith(output) { | ||
| return output.filter( | ||
| (acs) => acs.contractEntry != null && "JsActiveContract" in acs.contractEntry | ||
| ).map((acs) => { | ||
| const jsActiveContract = acs.contractEntry.JsActiveContract; | ||
| return { | ||
| ...jsActiveContract.createdEvent, | ||
| synchronizerId: jsActiveContract.synchronizerId | ||
| }; | ||
| }); | ||
| }; | ||
| var PaginatedReader = class extends BaseReader { | ||
| constructor(ledger, cacheOptions) { | ||
| super(ledger, cacheOptions); | ||
| this.ledger = ledger; | ||
| this.cacheOptions = cacheOptions; | ||
| __publicField(this, "raw"); | ||
| this.raw = new RawReader(ledger, cacheOptions, true); | ||
| } | ||
| async resolveAcsOptions(options) { | ||
| const offset = options.offset ?? (await this.ledger.request({ | ||
| method: "ledgerApi", | ||
| params: { | ||
| resource: "/v2/state/ledger-end", | ||
| requestMethod: "get" | ||
| } | ||
| })).offset; | ||
| return { ...options, offset }; | ||
| createCacheCollection() { | ||
| return new PaginatedACSCacheCollection(this.ledger, this.cacheOptions); | ||
| } | ||
| }; | ||
| var ACSReader = class extends BaseReader { | ||
| constructor(ledger, cacheOptions) { | ||
| super(ledger, cacheOptions); | ||
| this.ledger = ledger; | ||
| this.cacheOptions = cacheOptions; | ||
| __publicField(this, "raw"); | ||
| __publicField(this, "paginated"); | ||
| this.raw = new RawReader(ledger, cacheOptions); | ||
| this.paginated = new PaginatedReader(ledger, cacheOptions); | ||
| } | ||
| createCacheCollection() { | ||
| return new ACSCacheCollection(this.ledger, this.cacheOptions); | ||
| } | ||
| }; | ||
@@ -636,0 +812,0 @@ exports.ACSReader = ACSReader; |
+1
-1
@@ -1,3 +0,3 @@ | ||
| export * from './reader.js'; | ||
| export * from './reader/reader.js'; | ||
| export * from './service.js'; | ||
| //# sourceMappingURL=index.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,oBAAoB,CAAA;AAClC,cAAc,cAAc,CAAA"} |
+439
-263
@@ -0,3 +1,3 @@ | ||
| import pino from 'pino'; | ||
| import { LRUCache } from 'typescript-lru-cache'; | ||
| import pino from 'pino'; | ||
@@ -10,10 +10,301 @@ var __defProp = Object.defineProperty; | ||
| var ACS_UPDATE_CONFIG = { | ||
| // How many events do we accumulate before we prune (compact) the ACS history - set to 0 to enable to compact all events, which is more efficient as long as application always ask for increasing (or equal) offsets | ||
| maxEventsBeforePrune: 150, | ||
| // When we compact the ACS history, we keep all events within this offset delta of the last seen update offset - set 0 to allow to compact everything | ||
| safeOffsetDeltaForPrune: 200, | ||
| // How many updates do we fetch at once when fetching updates - if there are more updates, we will fetch again until we have caught up (returned data is always complete to the requested endInclusive offset - even if that means multiple fetches) | ||
| maxUpdatesToFetch: 100 | ||
| }; | ||
| var logger = pino({ name: "acs-reader/cache" }); | ||
| function isCreatedEvent(event) { | ||
| return !event.archived; | ||
| } | ||
| var BaseACSCache = class { | ||
| constructor(ledger) { | ||
| this.ledger = ledger; | ||
| __publicField(this, "service"); | ||
| this.service = new AcsService(ledger); | ||
| } | ||
| }; | ||
| // src/cache/item/item.ts | ||
| var ACSCache = class extends BaseACSCache { | ||
| constructor() { | ||
| super(...arguments); | ||
| __publicField(this, "state", { | ||
| initial: { | ||
| offset: 0, | ||
| acs: [] | ||
| }, | ||
| updates: { | ||
| offset: 0, | ||
| acs: [] | ||
| }, | ||
| archivedACs: /* @__PURE__ */ new Set() | ||
| }); | ||
| } | ||
| /** | ||
| * Returns the initial snapshot of the active contract set. | ||
| * Contains the base state captured at a specific ledger offset. | ||
| */ | ||
| get initial() { | ||
| return this.state.initial; | ||
| } | ||
| /** | ||
| * Returns the incremental updates applied after the initial snapshot. | ||
| * Contains created and archived events that occurred since the initial state. | ||
| */ | ||
| get updates() { | ||
| return this.state.updates; | ||
| } | ||
| async update(options) { | ||
| if (!this.initial.acs.length || this.initial.offset > options.offset) { | ||
| await this.initState(options); | ||
| } | ||
| const builtFilter = buildActiveContractFilter(options); | ||
| const updates = await this.fetchUpdates({ | ||
| beginExclusive: this.updates.offset, | ||
| endInclusive: options.offset, | ||
| eventFormat: { | ||
| verbose: Boolean(builtFilter.verbose), | ||
| ...builtFilter.filter | ||
| } | ||
| }); | ||
| if (updates.length >= ACS_UPDATE_CONFIG.maxUpdatesToFetch) | ||
| void this.update(options); | ||
| const { newEvents, newOffset } = this.extractEvents({ | ||
| offset: this.updates.offset, | ||
| updates | ||
| }); | ||
| if (newOffset > this.updates.offset) { | ||
| this.updates.offset = newOffset; | ||
| this.updates.acs = this.updates.acs.concat(newEvents); | ||
| } else this.updates.offset = options.offset; | ||
| if (this.updates.acs.length >= ACS_UPDATE_CONFIG.maxEventsBeforePrune) { | ||
| this.prune(); | ||
| } | ||
| } | ||
| calculateAt(offset) { | ||
| if (!this.initial.acs) | ||
| throw Error("No ACS initialized. Call `.update()` first"); | ||
| if (this.initial.offset > offset) | ||
| throw Error("Provided offset cannot be smaller than ACS offset"); | ||
| const newContracts = []; | ||
| const newArchivedContracts = /* @__PURE__ */ new Set(); | ||
| this.updates.acs.filter((ac) => ac.offset <= offset).map((ac) => { | ||
| if (isCreatedEvent(ac)) { | ||
| newContracts.push({ | ||
| workflowId: ac.workflowId ?? "", | ||
| contractEntry: { | ||
| JsActiveContract: { | ||
| createdEvent: ac.event, | ||
| synchronizerId: ac.synchronizerId ?? "", | ||
| reassignmentCounter: 0 | ||
| } | ||
| } | ||
| }); | ||
| } else { | ||
| newArchivedContracts.add( | ||
| ac.event.contractId | ||
| ); | ||
| } | ||
| }); | ||
| const allContracts = this.initial.acs.concat(newContracts); | ||
| this.state.archivedACs = this.state.archivedACs.union(newArchivedContracts); | ||
| return allContracts.filter(({ contractEntry }) => { | ||
| if (!contractEntry) return false; | ||
| const id = "JsActiveContract" in contractEntry ? contractEntry.JsActiveContract.createdEvent.contractId : ""; | ||
| return !this.state.archivedACs.has(id); | ||
| }); | ||
| } | ||
| /** | ||
| * Initializes the cache state by fetching the active contract set at the specified offset. | ||
| * Clears any existing updates and archived contract tracking. | ||
| */ | ||
| async initState(options) { | ||
| const initialAcs = await this.service.getActiveContracts(options); | ||
| this.state.initial = { | ||
| offset: options.offset, | ||
| acs: initialAcs | ||
| }; | ||
| this.state.updates = { | ||
| offset: options.offset, | ||
| acs: [] | ||
| }; | ||
| this.state.archivedACs = /* @__PURE__ */ new Set(); | ||
| } | ||
| /** | ||
| * Compacts the cache by moving the initial snapshot forward to a more recent offset. | ||
| * Applies accumulated updates to create a new initial state and discards old events. | ||
| * Improves performance by reducing the number of updates to process on each query. | ||
| */ | ||
| prune() { | ||
| const newOffset = Math.max( | ||
| this.initial.offset, | ||
| this.updates.offset - ACS_UPDATE_CONFIG.safeOffsetDeltaForPrune | ||
| ); | ||
| if (newOffset > this.initial.offset) { | ||
| const responses = this.calculateAt(newOffset); | ||
| this.state.initial = { | ||
| offset: newOffset, | ||
| acs: responses | ||
| }; | ||
| this.state.updates = { | ||
| offset: this.updates.offset, | ||
| acs: this.updates.acs.filter((ac) => ac.offset > newOffset) | ||
| }; | ||
| } | ||
| } | ||
| /** | ||
| * Fetches ledger updates between two offsets. | ||
| * Queries the ledger API for transactions containing contract create and archive events. | ||
| */ | ||
| async fetchUpdates(args) { | ||
| const { beginExclusive, endInclusive, eventFormat, filter } = args; | ||
| const updateFormat = { | ||
| includeTransactions: { | ||
| eventFormat, | ||
| transactionShape: "TRANSACTION_SHAPE_ACS_DELTA" | ||
| } | ||
| }; | ||
| return await this.ledger.request({ | ||
| method: "ledgerApi", | ||
| params: { | ||
| resource: "/v2/updates", | ||
| requestMethod: "post", | ||
| body: { | ||
| beginExclusive, | ||
| endInclusive, | ||
| updateFormat, | ||
| verbose: false, | ||
| ...filter ? { filter } : {} | ||
| }, | ||
| query: { | ||
| limit: ACS_UPDATE_CONFIG.maxUpdatesToFetch, | ||
| stream_idle_timeout_ms: 1e3 | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Extracts contract creation and archival events from raw ledger updates. | ||
| * Processes transaction and checkpoint updates to build a list of relevant contract events. | ||
| * Tracks the highest offset seen across all updates. | ||
| */ | ||
| extractEvents(args) { | ||
| const { updates, offset } = args; | ||
| const newEvents = []; | ||
| let newOffset = offset; | ||
| updates.forEach((update) => { | ||
| if (!update || !update.update) { | ||
| return; | ||
| } | ||
| if ("Transaction" in update.update) { | ||
| const transaction = update.update.Transaction; | ||
| const trOffset = transaction?.value?.offset; | ||
| if (trOffset && trOffset > newOffset) { | ||
| const events = transaction?.value?.events ?? []; | ||
| events.forEach((event) => { | ||
| if (!event) { | ||
| return; | ||
| } | ||
| if ("CreatedEvent" in event || "ArchivedEvent" in event) { | ||
| const eventData = "CreatedEvent" in event ? event.CreatedEvent : event.ArchivedEvent; | ||
| const acUpdate = { | ||
| event: eventData, | ||
| offset: trOffset, | ||
| workflowId: transaction?.value?.workflowId ?? null, | ||
| synchronizerId: transaction?.value?.synchronizerId ?? null, | ||
| ..."ArchivedEvent" in event && { | ||
| archived: true | ||
| } | ||
| }; | ||
| newEvents.push(acUpdate); | ||
| newOffset = trOffset; | ||
| } | ||
| }); | ||
| } | ||
| } else if ("OffsetCheckpoint" in update.update) { | ||
| const checkpoint = update.update.OffsetCheckpoint; | ||
| const offset2 = checkpoint?.value?.offset; | ||
| if (offset2) { | ||
| newOffset = offset2; | ||
| } | ||
| } else { | ||
| logger.warn( | ||
| { | ||
| value: JSON.stringify(update.update) | ||
| }, | ||
| "ACS update got unknown update type" | ||
| ); | ||
| } | ||
| }); | ||
| return { newEvents, newOffset }; | ||
| } | ||
| }; | ||
| // src/cache/item/paginatedItem.ts | ||
| var _PaginatedACSCache = class _PaginatedACSCache extends BaseACSCache { | ||
| constructor() { | ||
| super(...arguments); | ||
| __publicField(this, "state", { | ||
| pages: { | ||
| [_PaginatedACSCache.FIRST_PAGE_TOKEN]: { | ||
| activeContracts: [], | ||
| activeAtOffset: 0, | ||
| nextPageToken: "" | ||
| } | ||
| }, | ||
| offset: 0 | ||
| }); | ||
| /** | ||
| * Token for fetching pages of active contracts. will loop over pages until desired offset is reached. When last obtained page was the last one it is `undefined` | ||
| */ | ||
| __publicField(this, "nextPageToken", _PaginatedACSCache.FIRST_PAGE_TOKEN); | ||
| } | ||
| async update(options) { | ||
| if (!this.state.pages[_PaginatedACSCache.FIRST_PAGE_TOKEN].activeContracts.length && !this.state.pages[_PaginatedACSCache.FIRST_PAGE_TOKEN].nextPageToken) { | ||
| await this.initState(options); | ||
| } | ||
| if (options.pageToken) { | ||
| this.state.pages[options.pageToken] = await this.service.getPaginatedActiveContracts(options); | ||
| this.nextPageToken = this.state.pages[options.pageToken].nextPageToken; | ||
| } else { | ||
| while (this.nextPageToken && options.offset > this.state.offset) { | ||
| this.state.pages[this.nextPageToken] = await this.service.getPaginatedActiveContracts({ | ||
| ...options, | ||
| pageToken: this.nextPageToken | ||
| }); | ||
| this.state.offset = this.state.pages[this.nextPageToken].activeAtOffset; | ||
| this.nextPageToken = this.state.pages[this.nextPageToken].nextPageToken; | ||
| } | ||
| } | ||
| } | ||
| calculateAt(offset) { | ||
| const activeContracts = Object.values(this.state.pages).flatMap( | ||
| (page) => page.activeContracts | ||
| ); | ||
| if (!activeContracts.length) | ||
| throw Error("No ACS initialized. Call `.update()` first"); | ||
| return activeContracts.filter((ac) => { | ||
| const event = ac.contractEntry && "JsActiveContract" in ac.contractEntry ? ac.contractEntry.JsActiveContract.createdEvent : void 0; | ||
| return event && event.offset <= offset; | ||
| }); | ||
| } | ||
| /** | ||
| * Retrieves a specific page from the cache using the page token. | ||
| */ | ||
| getPage(pageToken) { | ||
| return this.state.pages[pageToken]; | ||
| } | ||
| /** | ||
| * Initializes the cache state by fetching the first page of active contracts. | ||
| */ | ||
| async initState(options) { | ||
| const firstPage = await this.service.getPaginatedActiveContracts(options); | ||
| this.state.pages[_PaginatedACSCache.FIRST_PAGE_TOKEN] = firstPage; | ||
| this.state.offset = firstPage.activeAtOffset; | ||
| this.nextPageToken = firstPage.nextPageToken; | ||
| } | ||
| }; | ||
| __publicField(_PaginatedACSCache, "FIRST_PAGE_TOKEN", ""); | ||
| var PaginatedACSCache = _PaginatedACSCache; | ||
| // src/service.ts | ||
@@ -26,2 +317,48 @@ var COMPLETIONS_LIMIT = "100"; | ||
| } | ||
| async getPaginatedActiveContracts(options) { | ||
| const { continueUntilCompletion, ...baseArgs } = options; | ||
| const { maxPageSize, pageToken } = baseArgs; | ||
| const { activeAtOffset, filter } = buildActiveContractFilter(options); | ||
| if (continueUntilCompletion) { | ||
| const results = []; | ||
| let shouldContinue = true; | ||
| while (shouldContinue) { | ||
| const pageToken2 = results.length ? results[results.length - 1].nextPageToken : PaginatedACSCache.FIRST_PAGE_TOKEN; | ||
| const result = await this.getPaginatedActiveContracts({ | ||
| ...baseArgs, | ||
| continueUntilCompletion: false, | ||
| ...pageToken2 ? { pageToken: pageToken2 } : {} | ||
| }); | ||
| results.push(result); | ||
| shouldContinue = Boolean(result.nextPageToken); | ||
| } | ||
| return results; | ||
| } | ||
| const body = { | ||
| eventFormat: {}, | ||
| activeAtOffset | ||
| }; | ||
| if (filter?.filtersByParty) { | ||
| body.eventFormat.filtersByParty = filter.filtersByParty; | ||
| } | ||
| if (filter?.filtersForAnyParty) { | ||
| body.eventFormat.filtersForAnyParty = filter.filtersForAnyParty; | ||
| } | ||
| if (maxPageSize !== void 0) { | ||
| body.maxPageSize = maxPageSize; | ||
| } | ||
| if (pageToken !== void 0) { | ||
| body.pageToken = pageToken; | ||
| } | ||
| return await this.ledgerProvider.request( | ||
| { | ||
| method: "ledgerApi", | ||
| params: { | ||
| requestMethod: "get", | ||
| resource: "/v2/state/active-contracts-page", | ||
| body | ||
| } | ||
| } | ||
| ); | ||
| } | ||
| async getActiveContracts(options) { | ||
@@ -271,236 +608,71 @@ const { limit, continueUntilCompletion } = options; | ||
| // src/cache/cache.ts | ||
| var logger = pino({ name: "acs-reader/cache" }); | ||
| var ACSCache = class { | ||
| constructor(ledger) { | ||
| // src/reader/base.ts | ||
| var BaseReader = class { | ||
| constructor(ledger, cacheOptions) { | ||
| this.ledger = ledger; | ||
| __publicField(this, "state", { | ||
| initial: { | ||
| offset: 0, | ||
| acs: [] | ||
| }, | ||
| updates: { | ||
| offset: 0, | ||
| acs: [] | ||
| }, | ||
| archivedACs: /* @__PURE__ */ new Set() | ||
| }); | ||
| this.cacheOptions = cacheOptions; | ||
| __publicField(this, "cacheCollection"); | ||
| __publicField(this, "service"); | ||
| this.cacheCollection = this.createCacheCollection(); | ||
| this.service = new AcsService(ledger); | ||
| } | ||
| /** | ||
| * Returns the initial snapshot of the active contract set. | ||
| * Contains the base state captured at a specific ledger offset. | ||
| * Reads active contracts from the cache. | ||
| */ | ||
| get initial() { | ||
| return this.state.initial; | ||
| async read(options) { | ||
| const resolvedOptions = await this.resolveAcsOptions(options); | ||
| return await this.cacheCollection.readFromCache(resolvedOptions); | ||
| } | ||
| /** | ||
| * Returns the incremental updates applied after the initial snapshot. | ||
| * Contains created and archived events that occurred since the initial state. | ||
| * Convenience method that returns active contracts as JS contract objects. | ||
| */ | ||
| get updates() { | ||
| return this.state.updates; | ||
| async readJsContracts(options) { | ||
| return this.readJsContractsWith(await this.read(options)); | ||
| } | ||
| /** | ||
| * Updates the cache to include ledger changes up to the specified offset. | ||
| * Fetches and applies incremental updates from the ledger, initializing the cache if needed. | ||
| * Automatically prunes old events when the update buffer exceeds configured thresholds. | ||
| * Extracts active contracts from various output formats (single page, array of pages, or array of responses). | ||
| */ | ||
| async update(options) { | ||
| if (!this.initial.acs.length || this.initial.offset > options.offset) { | ||
| await this.initState(options); | ||
| getActiveContracts(output) { | ||
| if (!Array.isArray(output)) { | ||
| return "activeContracts" in output ? output.activeContracts : []; | ||
| } | ||
| const builtFilter = buildActiveContractFilter(options); | ||
| const updates = await this.fetchUpdates({ | ||
| beginExclusive: this.updates.offset, | ||
| endInclusive: options.offset, | ||
| eventFormat: { | ||
| verbose: Boolean(builtFilter.verbose), | ||
| ...builtFilter.filter | ||
| } | ||
| }); | ||
| if (updates.length >= ACS_UPDATE_CONFIG.maxUpdatesToFetch) | ||
| void this.update(options); | ||
| const { newEvents, newOffset } = this.extractEvents({ | ||
| offset: this.updates.offset, | ||
| updates | ||
| }); | ||
| if (newOffset > this.updates.offset) { | ||
| this.updates.offset = newOffset; | ||
| this.updates.acs = this.updates.acs.concat(newEvents); | ||
| } else this.updates.offset = options.offset; | ||
| if (this.updates.acs.length >= ACS_UPDATE_CONFIG.maxEventsBeforePrune) { | ||
| this.prune(); | ||
| if (output.length > 0 && "activeContracts" in output[0]) { | ||
| return output.flatMap( | ||
| (page) => "activeContracts" in page ? page.activeContracts : [] | ||
| ); | ||
| } | ||
| return output.filter( | ||
| (item) => !("activeContracts" in item) | ||
| ); | ||
| } | ||
| /** | ||
| * Calculates the active contract set at a specific ledger offset. | ||
| * Applies cached updates to the initial snapshot and filters out archived contracts. | ||
| * Throws an error if the cache is not initialized or the requested offset is too old. | ||
| * Transforms active contracts output into JS contract objects with created event details and synchronizer ID. | ||
| */ | ||
| calculateAt(offset) { | ||
| if (!this.initial.acs) | ||
| throw Error("No ACS initialized. Call `.update()` first"); | ||
| if (this.initial.offset > offset) | ||
| throw Error("Provided offset cannot be smaller than ACS offset"); | ||
| const newContracts = []; | ||
| const newArchivedContracts = /* @__PURE__ */ new Set(); | ||
| this.updates.acs.filter((ac) => ac.offset <= offset).map((ac) => { | ||
| if (isCreatedEvent(ac)) { | ||
| newContracts.push({ | ||
| workflowId: ac.workflowId ?? "", | ||
| contractEntry: { | ||
| JsActiveContract: { | ||
| createdEvent: ac.event, | ||
| synchronizerId: ac.synchronizerId ?? "", | ||
| reassignmentCounter: 0 | ||
| } | ||
| } | ||
| }); | ||
| } else { | ||
| newArchivedContracts.add( | ||
| ac.event.contractId | ||
| ); | ||
| } | ||
| readJsContractsWith(output) { | ||
| const contracts = this.getActiveContracts(output); | ||
| return contracts.filter( | ||
| (acs) => acs.contractEntry != null && "JsActiveContract" in acs.contractEntry | ||
| ).map((acs) => { | ||
| const jsActiveContract = acs.contractEntry.JsActiveContract; | ||
| return { | ||
| ...jsActiveContract.createdEvent, | ||
| synchronizerId: jsActiveContract.synchronizerId | ||
| }; | ||
| }); | ||
| const allContracts = this.initial.acs.concat(newContracts); | ||
| this.state.archivedACs = this.state.archivedACs.union(newArchivedContracts); | ||
| return allContracts.filter(({ contractEntry }) => { | ||
| if (!contractEntry) return false; | ||
| const id = "JsActiveContract" in contractEntry ? contractEntry.JsActiveContract.createdEvent.contractId : ""; | ||
| return !this.state.archivedACs.has(id); | ||
| }); | ||
| } | ||
| /** | ||
| * Initializes the cache state by fetching the active contract set at the specified offset. | ||
| * Clears any existing updates and archived contract tracking. | ||
| * Resolves ACS options by ensuring an offset is present, fetching the current ledger end if needed. | ||
| */ | ||
| async initState(options) { | ||
| const initialAcs = await this.service.getActiveContracts(options); | ||
| this.state.initial = { | ||
| offset: options.offset, | ||
| acs: initialAcs | ||
| }; | ||
| this.state.updates = { | ||
| offset: options.offset, | ||
| acs: [] | ||
| }; | ||
| this.state.archivedACs = /* @__PURE__ */ new Set(); | ||
| } | ||
| /** | ||
| * Compacts the cache by moving the initial snapshot forward to a more recent offset. | ||
| * Applies accumulated updates to create a new initial state and discards old events. | ||
| * Improves performance by reducing the number of updates to process on each query. | ||
| */ | ||
| prune() { | ||
| const newOffset = Math.max( | ||
| this.initial.offset, | ||
| this.updates.offset - ACS_UPDATE_CONFIG.safeOffsetDeltaForPrune | ||
| ); | ||
| if (newOffset > this.initial.offset) { | ||
| const responses = this.calculateAt(newOffset); | ||
| this.state.initial = { | ||
| offset: newOffset, | ||
| acs: responses | ||
| }; | ||
| this.state.updates = { | ||
| offset: this.updates.offset, | ||
| acs: this.updates.acs.filter((ac) => ac.offset > newOffset) | ||
| }; | ||
| } | ||
| } | ||
| /** | ||
| * Fetches ledger updates between two offsets. | ||
| * Queries the ledger API for transactions containing contract create and archive events. | ||
| */ | ||
| async fetchUpdates(args) { | ||
| const { beginExclusive, endInclusive, eventFormat, filter } = args; | ||
| const updateFormat = { | ||
| includeTransactions: { | ||
| eventFormat, | ||
| transactionShape: "TRANSACTION_SHAPE_ACS_DELTA" | ||
| } | ||
| }; | ||
| return await this.ledger.request({ | ||
| async resolveAcsOptions(options) { | ||
| const offset = options.offset ?? (await this.ledger.request({ | ||
| method: "ledgerApi", | ||
| params: { | ||
| resource: "/v2/updates", | ||
| requestMethod: "post", | ||
| body: { | ||
| beginExclusive, | ||
| endInclusive, | ||
| updateFormat, | ||
| verbose: false, | ||
| ...filter ? { filter } : {} | ||
| }, | ||
| query: { | ||
| limit: ACS_UPDATE_CONFIG.maxUpdatesToFetch, | ||
| stream_idle_timeout_ms: 1e3 | ||
| } | ||
| resource: "/v2/state/ledger-end", | ||
| requestMethod: "get" | ||
| } | ||
| }); | ||
| })).offset; | ||
| return { ...options, offset }; | ||
| } | ||
| /** | ||
| * Extracts contract creation and archival events from raw ledger updates. | ||
| * Processes transaction and checkpoint updates to build a list of relevant contract events. | ||
| * Tracks the highest offset seen across all updates. | ||
| */ | ||
| extractEvents(args) { | ||
| const { updates, offset } = args; | ||
| const newEvents = []; | ||
| let newOffset = offset; | ||
| updates.forEach((update) => { | ||
| if (!update || !update.update) { | ||
| return; | ||
| } | ||
| if ("Transaction" in update.update) { | ||
| const transaction = update.update.Transaction; | ||
| const trOffset = transaction?.value?.offset; | ||
| if (trOffset && trOffset > newOffset) { | ||
| const events = transaction?.value?.events ?? []; | ||
| events.forEach((event) => { | ||
| if (!event) { | ||
| return; | ||
| } | ||
| if ("CreatedEvent" in event || "ArchivedEvent" in event) { | ||
| const eventData = "CreatedEvent" in event ? event.CreatedEvent : event.ArchivedEvent; | ||
| const acUpdate = { | ||
| event: eventData, | ||
| offset: trOffset, | ||
| workflowId: transaction?.value?.workflowId ?? null, | ||
| synchronizerId: transaction?.value?.synchronizerId ?? null, | ||
| ..."ArchivedEvent" in event && { | ||
| archived: true | ||
| } | ||
| }; | ||
| newEvents.push(acUpdate); | ||
| newOffset = trOffset; | ||
| } | ||
| }); | ||
| } | ||
| } else if ("OffsetCheckpoint" in update.update) { | ||
| const checkpoint = update.update.OffsetCheckpoint; | ||
| const offset2 = checkpoint?.value?.offset; | ||
| if (offset2) { | ||
| newOffset = offset2; | ||
| } | ||
| } else { | ||
| logger.warn( | ||
| { | ||
| value: JSON.stringify(update.update) | ||
| }, | ||
| "ACS update got unknown update type" | ||
| ); | ||
| } | ||
| }); | ||
| return { newEvents, newOffset }; | ||
| } | ||
| }; | ||
| function isCreatedEvent(event) { | ||
| return !event.archived; | ||
| } | ||
| // src/cache/collection.ts | ||
| var ACSCacheCollection = class { | ||
| var BaseCacheCollection = class { | ||
| constructor(ledger, options = { | ||
@@ -519,5 +691,2 @@ maxSize: 100, | ||
| * Queries are deduplicated and cached per party-template-interface combination. | ||
| * | ||
| * @override | ||
| * @see {@link ACSReader.readRaw} | ||
| */ | ||
@@ -540,3 +709,3 @@ async readFromCache(options) { | ||
| if (existingCache) return existingCache; | ||
| const newCache = new ACSCache(this.ledger); | ||
| const newCache = this.createCache(); | ||
| this.collection.set(serializedKey, newCache); | ||
@@ -571,59 +740,66 @@ return newCache; | ||
| // src/reader.ts | ||
| var ACSReader = class { | ||
| constructor(ledger, cacheOptions) { | ||
| // src/cache/collection/collection.ts | ||
| var ACSCacheCollection = class extends BaseCacheCollection { | ||
| createCache() { | ||
| return new ACSCache(this.ledger); | ||
| } | ||
| }; | ||
| var PaginatedACSCacheCollection = class extends BaseCacheCollection { | ||
| createCache() { | ||
| return new PaginatedACSCache(this.ledger); | ||
| } | ||
| }; | ||
| // src/reader/reader.ts | ||
| function isPageResponse(obj) { | ||
| return typeof obj === "object" && obj !== null && "activeContracts" in obj; | ||
| } | ||
| var RawReader = class extends BaseReader { | ||
| constructor(ledger, cacheOptions, paginated) { | ||
| super(ledger, cacheOptions); | ||
| this.ledger = ledger; | ||
| this.cacheOptions = cacheOptions; | ||
| __publicField(this, "cacheCollection"); | ||
| __publicField(this, "service"); | ||
| /** | ||
| * Provides direct access to the ACS without using the cache. | ||
| */ | ||
| __publicField(this, "raw", { | ||
| read: async (options) => { | ||
| const resolvedOptions = await this.resolveAcsOptions(options); | ||
| return await this.service.getActiveContracts(resolvedOptions); | ||
| }, | ||
| readJsContracts: async (options) => { | ||
| return this.readJsContractsWith(await this.raw.read(options)); | ||
| } | ||
| }); | ||
| this.cacheCollection = new ACSCacheCollection(ledger, cacheOptions); | ||
| this.service = new AcsService(ledger); | ||
| this.paginated = paginated; | ||
| } | ||
| /** | ||
| * Reads active contracts from the cache. | ||
| */ | ||
| async read(options) { | ||
| const resolvedOptions = await this.resolveAcsOptions(options); | ||
| return await this.cacheCollection.readFromCache(resolvedOptions); | ||
| const output = await (this.paginated ? this.service.getPaginatedActiveContracts(resolvedOptions) : this.service.getActiveContracts(resolvedOptions)); | ||
| if (!Array.isArray(output)) { | ||
| return isPageResponse(output) ? output.activeContracts : []; | ||
| } | ||
| const first = output[0]; | ||
| return first && isPageResponse(first) ? output.flatMap( | ||
| (page) => isPageResponse(page) ? page.activeContracts : [] | ||
| ) : output; | ||
| } | ||
| /** | ||
| * Convenience method that returns active contracts as JS contract objects. | ||
| */ | ||
| async readJsContracts(options) { | ||
| return this.readJsContractsWith(await this.read(options)); | ||
| createCacheCollection() { | ||
| return this.paginated ? new PaginatedACSCacheCollection(this.ledger, this.cacheOptions) : new ACSCacheCollection(this.ledger, this.cacheOptions); | ||
| } | ||
| readJsContractsWith(output) { | ||
| return output.filter( | ||
| (acs) => acs.contractEntry != null && "JsActiveContract" in acs.contractEntry | ||
| ).map((acs) => { | ||
| const jsActiveContract = acs.contractEntry.JsActiveContract; | ||
| return { | ||
| ...jsActiveContract.createdEvent, | ||
| synchronizerId: jsActiveContract.synchronizerId | ||
| }; | ||
| }); | ||
| }; | ||
| var PaginatedReader = class extends BaseReader { | ||
| constructor(ledger, cacheOptions) { | ||
| super(ledger, cacheOptions); | ||
| this.ledger = ledger; | ||
| this.cacheOptions = cacheOptions; | ||
| __publicField(this, "raw"); | ||
| this.raw = new RawReader(ledger, cacheOptions, true); | ||
| } | ||
| async resolveAcsOptions(options) { | ||
| const offset = options.offset ?? (await this.ledger.request({ | ||
| method: "ledgerApi", | ||
| params: { | ||
| resource: "/v2/state/ledger-end", | ||
| requestMethod: "get" | ||
| } | ||
| })).offset; | ||
| return { ...options, offset }; | ||
| createCacheCollection() { | ||
| return new PaginatedACSCacheCollection(this.ledger, this.cacheOptions); | ||
| } | ||
| }; | ||
| var ACSReader = class extends BaseReader { | ||
| constructor(ledger, cacheOptions) { | ||
| super(ledger, cacheOptions); | ||
| this.ledger = ledger; | ||
| this.cacheOptions = cacheOptions; | ||
| __publicField(this, "raw"); | ||
| __publicField(this, "paginated"); | ||
| this.raw = new RawReader(ledger, cacheOptions); | ||
| this.paginated = new PaginatedReader(ledger, cacheOptions); | ||
| } | ||
| createCacheCollection() { | ||
| return new ACSCacheCollection(this.ledger, this.cacheOptions); | ||
| } | ||
| }; | ||
@@ -630,0 +806,0 @@ export { ACSReader, AcsService, awaitCompletion, buildActiveContractFilter, defaultRetryableOptions, promiseWithTimeout }; |
+11
-1
@@ -17,8 +17,18 @@ import { AbstractLedgerProvider, Ops } from '@canton-network/core-provider-ledger'; | ||
| }; | ||
| export type ResolvedAcsOptions = Omit<AcsOptions, 'offset'> & { | ||
| export type PaginatedAcsOptions = Omit<AcsOptions, 'limit'> & Pick<Types['GetActiveContractsPageRequest'], 'pageToken' | 'maxPageSize'>; | ||
| type ResolvedOptions<Options> = Omit<Options, 'offset'> & { | ||
| offset: number; | ||
| }; | ||
| export type ResolvedAcsOptions = ResolvedOptions<AcsOptions>; | ||
| export type PaginatedResolvedAcsOptions = ResolvedOptions<PaginatedAcsOptions>; | ||
| export declare class AcsService { | ||
| private readonly ledgerProvider; | ||
| constructor(ledgerProvider: AbstractLedgerProvider); | ||
| getPaginatedActiveContracts(options: Omit<PaginatedResolvedAcsOptions, 'continueUntilCompletion'> & { | ||
| continueUntilCompletion: true; | ||
| }): Promise<Types['JsGetActiveContractsPageResponse'][]>; | ||
| getPaginatedActiveContracts(options: Omit<PaginatedResolvedAcsOptions, 'continueUntilCompletion'> & { | ||
| continueUntilCompletion: false; | ||
| }): Promise<Types['JsGetActiveContractsPageResponse']>; | ||
| getPaginatedActiveContracts(options: Omit<PaginatedResolvedAcsOptions, 'continueUntilCompletion'>): Promise<Types['JsGetActiveContractsPageResponse']>; | ||
| getActiveContracts(options: ResolvedAcsOptions): Promise<Array<Types['JsGetActiveContractsResponse']>>; | ||
@@ -25,0 +35,0 @@ private fetchActiveContractsUntilComplete; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,sBAAsB,EACtB,GAAG,EACN,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAEnF,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAEpD,KAAK,KAAK,GAAG,mBAAmB,CAAA;AAEhC,KAAK,UAAU,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAA;AAC9C,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAAA;AACtD,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,eAAe,CAAC,CAAA;AAKlD,MAAM,MAAM,UAAU,GAAG;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uBAAuB,CAAC,EAAE,OAAO,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEhF,qBAAa,UAAU;IACP,OAAO,CAAC,QAAQ,CAAC,cAAc;gBAAd,cAAc,EAAE,sBAAsB;IAEtD,kBAAkB,CAC3B,OAAO,EAAE,kBAAkB,GAC5B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC,CAAC;YA0B1C,iCAAiC;CAwIlD;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IAC/C,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;CACjB,GA8EoB,GAAG,CAAC,0BAA0B,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CACjF;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACjC,cAAc,EAAE,sBAAsB,EACtC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,uBAAuB,EAAE,MAAM,GAChC,OAAO,CAAC,UAAU,CAAC,CAoErB;AAED,wBAAsB,kBAAkB,CAAC,CAAC,EACtC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACrB,OAAO,CAAC,CAAC,CAAC,CAaZ;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,EAAE,CAAA;CAC5B,CAAA;AACD,eAAO,MAAM,uBAAuB,EAAE,gBAWrC,CAAA"} | ||
| {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,sBAAsB,EACtB,GAAG,EACN,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAEnF,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAGpD,KAAK,KAAK,GAAG,mBAAmB,CAAA;AAEhC,KAAK,UAAU,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAA;AAC9C,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAAA;AACtD,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,eAAe,CAAC,CAAA;AAKlD,MAAM,MAAM,UAAU,GAAG;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uBAAuB,CAAC,EAAE,OAAO,CAAA;CACpC,CAAA;AACD,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,GACvD,IAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC,CAAA;AAE7E,KAAK,eAAe,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5E,MAAM,MAAM,kBAAkB,GAAG,eAAe,CAAC,UAAU,CAAC,CAAA;AAC5D,MAAM,MAAM,2BAA2B,GAAG,eAAe,CAAC,mBAAmB,CAAC,CAAA;AAE9E,qBAAa,UAAU;IACP,OAAO,CAAC,QAAQ,CAAC,cAAc;gBAAd,cAAc,EAAE,sBAAsB;IAEtD,2BAA2B,CACpC,OAAO,EAAE,IAAI,CACT,2BAA2B,EAC3B,yBAAyB,CAC5B,GAAG;QACA,uBAAuB,EAAE,IAAI,CAAA;KAChC,GACF,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,EAAE,CAAC;IAC1C,2BAA2B,CACpC,OAAO,EAAE,IAAI,CACT,2BAA2B,EAC3B,yBAAyB,CAC5B,GAAG;QACA,uBAAuB,EAAE,KAAK,CAAA;KACjC,GACF,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACxC,2BAA2B,CACpC,OAAO,EAAE,IAAI,CAAC,2BAA2B,EAAE,yBAAyB,CAAC,GACtE,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;IA6DxC,kBAAkB,CAC3B,OAAO,EAAE,kBAAkB,GAC5B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC,CAAC;YA0B1C,iCAAiC;CAwIlD;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IAC/C,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;CACjB,GA8EoB,GAAG,CAAC,0BAA0B,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CACjF;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACjC,cAAc,EAAE,sBAAsB,EACtC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,uBAAuB,EAAE,MAAM,GAChC,OAAO,CAAC,UAAU,CAAC,CAoErB;AAED,wBAAsB,kBAAkB,CAAC,CAAC,EACtC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACrB,OAAO,CAAC,CAAC,CAAC,CAaZ;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,EAAE,CAAA;CAC5B,CAAA;AACD,eAAO,MAAM,uBAAuB,EAAE,gBAWrC,CAAA"} |
+11
-0
@@ -24,2 +24,13 @@ import { LedgerCommonSchemas } from '@canton-network/core-ledger-client-types'; | ||
| }; | ||
| export type PaginatedACSState = { | ||
| pages: Record<NonNullable<LedgerCommonSchemas['JsGetActiveContractsPageResponse']['nextPageToken']>, LedgerCommonSchemas['JsGetActiveContractsPageResponse']>; | ||
| offset: number; | ||
| }; | ||
| /** | ||
| * Configuration for ACS (Active Contract Set) update behavior. | ||
| * | ||
| * @property maxEventsBeforePrune - How many events do we accumulate before we prune (compact) the ACS history. Set to 0 to enable to compact all events, which is more efficient as long as application always asks for increasing (or equal) offsets. | ||
| * @property safeOffsetDeltaForPrune - When we compact the ACS history, we keep all events within this offset delta of the last seen update offset. Set 0 to allow to compact everything. | ||
| * @property maxUpdatesToFetch - How many updates do we fetch at once when fetching updates. If there are more updates, we will fetch again until we have caught up (returned data is always complete to the requested endInclusive offset - even if that means multiple fetches). | ||
| */ | ||
| export declare const ACS_UPDATE_CONFIG: { | ||
@@ -26,0 +37,0 @@ readonly maxEventsBeforePrune: 150; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAC9E,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAEhE,MAAM,MAAM,MAAM,GAAG,OAAO,CAAC;IACzB,KAAK,EAAE,OAAO,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACtB,CAAC,CAAA;AAEF,MAAM,MAAM,OAAO,GAAG;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EACC,mBAAmB,CAAC,cAAc,CAAC,GACnC,mBAAmB,CAAC,eAAe,CAAC,CAAA;IAC1C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACnB,OAAO,EAAE,iBAAiB,CACtB,mBAAmB,CAAC,8BAA8B,CAAC,CACtD,CAAA;IACD,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAA;IACnC,WAAW,EAAE,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;CACvC,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;CAOpB,CAAA"} | ||
| {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAC9E,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAEhE,MAAM,MAAM,MAAM,GAAG,OAAO,CAAC;IACzB,KAAK,EAAE,OAAO,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACtB,CAAC,CAAA;AAEF,MAAM,MAAM,OAAO,GAAG;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EACC,mBAAmB,CAAC,cAAc,CAAC,GACnC,mBAAmB,CAAC,eAAe,CAAC,CAAA;IAC1C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACnB,OAAO,EAAE,iBAAiB,CACtB,mBAAmB,CAAC,8BAA8B,CAAC,CACtD,CAAA;IACD,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAA;IACnC,WAAW,EAAE,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;CACvC,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC5B,KAAK,EAAE,MAAM,CACT,WAAW,CACP,mBAAmB,CAAC,kCAAkC,CAAC,CAAC,eAAe,CAAC,CAC3E,EACD,mBAAmB,CAAC,kCAAkC,CAAC,CAC1D,CAAA;IACD,MAAM,EAAE,MAAM,CAAA;CACjB,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB;;;;CAIpB,CAAA"} |
+4
-4
| { | ||
| "name": "@canton-network/core-acs-reader", | ||
| "version": "1.12.0", | ||
| "version": "1.13.0", | ||
| "type": "module", | ||
@@ -39,5 +39,5 @@ "description": "Reader for active contract set (ACS) data from the Canton ledger, providing functions to retrieve and process active contract information for specified filters.", | ||
| "dependencies": { | ||
| "@canton-network/core-ledger-client-types": "^1.4.0", | ||
| "@canton-network/core-provider-ledger": "^1.4.0", | ||
| "@canton-network/core-types": "^1.4.0", | ||
| "@canton-network/core-ledger-client-types": "^1.5.0", | ||
| "@canton-network/core-provider-ledger": "^1.5.0", | ||
| "@canton-network/core-types": "^1.5.0", | ||
| "bignumber.js": "^9.3.1", | ||
@@ -44,0 +44,0 @@ "dayjs": "^1.11.19", |
+208
-1
@@ -1,1 +0,208 @@ | ||
| # acs-reader | ||
| # @canton-network/core-acs-reader | ||
| ## Overview | ||
| The ACS Reader abstracts the complexity of querying and managing active contracts from the Canton ledger. It offers both standard and paginated access patterns, with intelligent caching to minimize network overhead and improve application performance. | ||
| ## Installation | ||
| ```bash | ||
| yarn add @canton-network/core-acs-reader | ||
| ``` | ||
| ## Quick Start | ||
| ```typescript | ||
| import { ACSReader } from '@canton-network/core-acs-reader' | ||
| import { ledgerProvider } from './your-ledger-setup' | ||
| // Initialize the reader | ||
| const reader = new ACSReader(ledgerProvider) | ||
| // Read active contracts with filtering | ||
| const contracts = await reader.read({ | ||
| templateIds: ['templateId'], | ||
| parties: ['partyId'], | ||
| offset: 0, | ||
| }) | ||
| // Get JavaScript contract objects (convenience method) | ||
| const jsContracts = await reader.readJsContracts({ | ||
| templateIds: ['templateId'], | ||
| parties: ['partyId'], | ||
| }) | ||
| ``` | ||
| ## Core Concepts | ||
| ### ACS Reader | ||
| The `ACSReader` class is the primary interface for querying active contracts. It maintains an internal cache and provides methods for both raw and processed contract data. | ||
| ### Options | ||
| **Standard Options** (`AcsOptions`): | ||
| - `offset`: Ledger offset to query from (automatically resolved if omitted) | ||
| - `templateIds`: Array of template IDs to filter by | ||
| - `interfaceIds`: Array of interface IDs to filter by | ||
| - `parties`: Array of party IDs to filter by | ||
| - `filterByParty`: Enable party-based filtering | ||
| - `limit`: Maximum number of results to return | ||
| - `continueUntilCompletion`: Continue fetching until all data is retrieved | ||
| **Paginated Options** (`PaginatedAcsOptions`): | ||
| Same as standard options, plus: | ||
| - `pageToken`: Token for fetching specific pages | ||
| - `maxPageSize`: Maximum number of contracts per page | ||
| ### Cache Configuration | ||
| Configure cache behavior with `ACSCacheCollectionOptions`: | ||
| ```typescript | ||
| const reader = new ACSReader(ledgerProvider, { | ||
| maxEventsBeforePrune: 1000, // Events before compaction | ||
| safeOffsetDeltaForPrune: 100, // Offset window to preserve | ||
| }) | ||
| ``` | ||
| ## Usage Examples | ||
| ### Basic Contract Retrieval | ||
| ```typescript | ||
| const reader = new ACSReader(ledgerProvider) | ||
| // Fetch all active contracts | ||
| const allContracts = await reader.read({}) | ||
| // Filter by template ID | ||
| const tokenContracts = await reader.read({ | ||
| templateIds: ['templateId'], | ||
| }) | ||
| // Filter by multiple parties | ||
| const partyContracts = await reader.read({ | ||
| parties: ['partyId', 'partyId2'], | ||
| filterByParty: true, | ||
| }) | ||
| ``` | ||
| ### Working with JavaScript Contracts | ||
| The `readJsContracts` method returns contract data in a more accessible format: | ||
| ```typescript | ||
| const jsContracts = await reader.readJsContracts({ | ||
| templateIds: ['templateId'], | ||
| parties: ['partyId'], | ||
| }) | ||
| // Each contract includes: | ||
| // - All fields from createdEvent | ||
| // - synchronizerId | ||
| jsContracts.forEach((contract) => { | ||
| console.log(contract.contractId, contract.templateId) | ||
| console.log(contract.createArgument) | ||
| }) | ||
| ``` | ||
| ### Paginated Access | ||
| For large datasets, use the paginated reader: | ||
| ```typescript | ||
| const reader = new ACSReader(ledgerProvider) | ||
| // Fetch first page | ||
| const firstPage = await reader.paginated.read({ | ||
| templateIds: ['templateId'], | ||
| maxPageSize: 100, | ||
| }) | ||
| // Fetch next page using token | ||
| const nextPage = await reader.paginated.read({ | ||
| templateIds: ['templateId'], | ||
| pageToken: firstPage.nextPageToken, | ||
| maxPageSize: 100, | ||
| }) | ||
| // Or fetch all pages at once | ||
| const allPages = await reader.paginated.read({ | ||
| templateIds: ['templateId'], | ||
| continueUntilCompletion: true, | ||
| }) | ||
| ``` | ||
| ### Raw Data Access | ||
| Access raw contract responses without caching: | ||
| ```typescript | ||
| const reader = new ACSReader(ledgerProvider) | ||
| // Standard raw access | ||
| const rawContracts = await reader.raw.read({ | ||
| templateIds: ['templateId'], | ||
| }) | ||
| // Paginated raw access | ||
| const rawPage = await reader.paginated.raw.read({ | ||
| templateIds: ['templateId'], | ||
| maxPageSize: 100, | ||
| }) | ||
| ``` | ||
| ### Continuous Fetching | ||
| Fetch all available data in a single call: | ||
| ```typescript | ||
| const contracts = await reader.read({ | ||
| templateIds: ['templateId'], | ||
| continueUntilCompletion: true, | ||
| limit: 200, // Batch size for each query | ||
| }) | ||
| ``` | ||
| ## API Reference | ||
| ### `ACSReader` | ||
| Main class for reading active contracts. | ||
| #### Constructor | ||
| ```typescript | ||
| new ACSReader( | ||
| ledger: AbstractLedgerProvider, | ||
| cacheOptions?: ACSCacheCollectionOptions | ||
| ) | ||
| ``` | ||
| ## Configuration | ||
| ### Cache Options (not applicable for pagination mode) | ||
| ```typescript | ||
| interface ACSCacheCollectionOptions { | ||
| // Compact history after this many events | ||
| maxEventsBeforePrune?: number | ||
| // Preserve events within this offset window | ||
| safeOffsetDeltaForPrune?: number | ||
| } | ||
| ``` | ||
| - Set `maxEventsBeforePrune` to `0` for immediate compaction (efficient for monotonically increasing offsets) | ||
| - Set `safeOffsetDeltaForPrune` to `0` to compact everything outside the current window | ||
| ## Best Practices | ||
| 1. **Reuse Reader Instances**: Create one reader instance and reuse it to benefit from caching | ||
| 2. **Filter Early**: Apply template and party filters to reduce data transfer and processing | ||
| 3. **Use Pagination**: For large datasets, use paginated access to control memory usage | ||
| 4. **Configure Cache**: Tune cache settings based on your query patterns | ||
| 5. **Handle Offsets**: Let the reader resolve offsets automatically unless you need specific points in time |
| import { AbstractLedgerProvider } from '@canton-network/core-provider-ledger'; | ||
| import { LRUCacheOptions } from 'typescript-lru-cache'; | ||
| import { ResolvedAcsOptions } from '../service'; | ||
| export type ACSCacheOptions = Pick<LRUCacheOptions<string, ACSCache>, 'maxSize' | 'entryExpirationTimeInMS'>; | ||
| export declare class ACSCache { | ||
| private readonly ledger; | ||
| private readonly state; | ||
| private readonly service; | ||
| constructor(ledger: AbstractLedgerProvider); | ||
| /** | ||
| * Returns the initial snapshot of the active contract set. | ||
| * Contains the base state captured at a specific ledger offset. | ||
| */ | ||
| private get initial(); | ||
| /** | ||
| * Returns the incremental updates applied after the initial snapshot. | ||
| * Contains created and archived events that occurred since the initial state. | ||
| */ | ||
| private get updates(); | ||
| /** | ||
| * Updates the cache to include ledger changes up to the specified offset. | ||
| * Fetches and applies incremental updates from the ledger, initializing the cache if needed. | ||
| * Automatically prunes old events when the update buffer exceeds configured thresholds. | ||
| */ | ||
| update(options: ResolvedAcsOptions): Promise<void>; | ||
| /** | ||
| * Calculates the active contract set at a specific ledger offset. | ||
| * Applies cached updates to the initial snapshot and filters out archived contracts. | ||
| * Throws an error if the cache is not initialized or the requested offset is too old. | ||
| */ | ||
| calculateAt(offset: number): ({ | ||
| workflowId?: string; | ||
| contractEntry?: import("../../../ledger-client-types/dist/generated-clients/openapi-3.4.12").components["schemas"]["JsContractEntry"]; | ||
| } & { | ||
| workflowId?: string; | ||
| contractEntry?: import("../../../ledger-client-types/dist/generated-clients/openapi-3.5.1").components["schemas"]["JsContractEntry"]; | ||
| streamContinuationToken?: string; | ||
| })[]; | ||
| /** | ||
| * Initializes the cache state by fetching the active contract set at the specified offset. | ||
| * Clears any existing updates and archived contract tracking. | ||
| */ | ||
| private initState; | ||
| /** | ||
| * Compacts the cache by moving the initial snapshot forward to a more recent offset. | ||
| * Applies accumulated updates to create a new initial state and discards old events. | ||
| * Improves performance by reducing the number of updates to process on each query. | ||
| */ | ||
| private prune; | ||
| /** | ||
| * Fetches ledger updates between two offsets. | ||
| * Queries the ledger API for transactions containing contract create and archive events. | ||
| */ | ||
| private fetchUpdates; | ||
| /** | ||
| * Extracts contract creation and archival events from raw ledger updates. | ||
| * Processes transaction and checkpoint updates to build a list of relevant contract events. | ||
| * Tracks the highest offset seen across all updates. | ||
| */ | ||
| private extractEvents; | ||
| } | ||
| //# sourceMappingURL=cache.d.ts.map |
| {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/cache/cache.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,sBAAsB,EAEzB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAGtD,OAAO,EACH,kBAAkB,EAGrB,MAAM,YAAY,CAAA;AAGnB,MAAM,MAAM,eAAe,GAAG,IAAI,CAC9B,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,EACjC,SAAS,GAAG,yBAAyB,CACxC,CAAA;AAID,qBAAa,QAAQ;IAcL,OAAO,CAAC,QAAQ,CAAC,MAAM;IAbnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAUrB;IACD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAY;gBAEP,MAAM,EAAE,sBAAsB;IAI3D;;;OAGG;IACH,OAAO,KAAK,OAAO,GAElB;IAED;;;OAGG;IACH,OAAO,KAAK,OAAO,GAElB;IAED;;;;OAIG;IACU,MAAM,CAAC,OAAO,EAAE,kBAAkB;IAmC/C;;;;OAIG;IACI,WAAW,CAAC,MAAM,EAAE,MAAM;;wBAgNmwwH,kGAAsB;;;wBAAm6xB,iGAAsB;;;IAjKnviJ;;;OAGG;YACW,SAAS;IAavB;;;;OAIG;IACH,OAAO,CAAC,KAAK;IAoBb;;;OAGG;YACW,YAAY;IAmC1B;;;;OAIG;IACH,OAAO,CAAC,aAAa;CA+DxB"} |
| import { ACSCacheOptions } from './cache'; | ||
| import { ResolvedAcsOptions } from '../service'; | ||
| import { LedgerCommonSchemas } from '@canton-network/core-ledger-client-types'; | ||
| import { AbstractLedgerProvider } from '@canton-network/core-provider-ledger'; | ||
| export declare class ACSCacheCollection { | ||
| private readonly ledger; | ||
| private readonly options; | ||
| private readonly collection; | ||
| constructor(ledger: AbstractLedgerProvider, options?: ACSCacheOptions); | ||
| /** | ||
| * Reads the active contract set from the ledger with caching. | ||
| * Resolves party references and constructs cache keys from the provided template and interface IDs. | ||
| * Queries are deduplicated and cached per party-template-interface combination. | ||
| * | ||
| * @override | ||
| * @see {@link ACSReader.readRaw} | ||
| */ | ||
| readFromCache(options: ResolvedAcsOptions): Promise<Array<LedgerCommonSchemas['JsGetActiveContractsResponse']>>; | ||
| private getCache; | ||
| /** | ||
| * Updates the cached active contract set for a specific key and returns contracts at the requested offset. | ||
| * If the cache is outdated, fetches updates from the ledger and applies them incrementally. | ||
| */ | ||
| private updateCache; | ||
| /** | ||
| * Queries multiple cache keys in parallel and combines the results. | ||
| * Each key represents a unique party-template-interface combination to be queried independently. | ||
| */ | ||
| private query; | ||
| private serializeKey; | ||
| } | ||
| //# sourceMappingURL=collection.d.ts.map |
| {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../../src/cache/collection.ts"],"names":[],"mappings":"AAIA,OAAO,EAAY,eAAe,EAAE,MAAM,SAAS,CAAA;AAEnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAC9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAA;AAE7E,qBAAa,kBAAkB;IAIvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4B;gBAGlC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,GAAE,eAGzB;IAKL;;;;;;;OAOG;IACU,aAAa,CACtB,OAAO,EAAE,kBAAkB,GAC5B,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,8BAA8B,CAAC,CAAC,CAAC;IAkBtE,OAAO,CAAC,QAAQ;IAWhB;;;OAGG;YACW,WAAW;IASzB;;;OAGG;YACW,KAAK;IAcnB,OAAO,CAAC,YAAY;CAGvB"} |
| import { AbstractLedgerProvider } from '@canton-network/core-provider-ledger'; | ||
| import { AcsOptions } from './service'; | ||
| import { ACSCacheOptions } from './cache/cache'; | ||
| import { LedgerCommonSchemas } from '@canton-network/core-ledger-client-types'; | ||
| type Reader = { | ||
| read: (options: AcsOptions) => Promise<Array<LedgerCommonSchemas['JsGetActiveContractsResponse']>>; | ||
| readJsContracts: (options: AcsOptions) => Promise<Array<LedgerCommonSchemas['JsActiveContract']['createdEvent'] & { | ||
| synchronizerId: LedgerCommonSchemas['JsActiveContract']['synchronizerId']; | ||
| }>>; | ||
| }; | ||
| export declare class ACSReader implements Reader { | ||
| private readonly ledger; | ||
| private readonly cacheOptions?; | ||
| private cacheCollection; | ||
| private service; | ||
| constructor(ledger: AbstractLedgerProvider, cacheOptions?: ACSCacheOptions | undefined); | ||
| /** | ||
| * Provides direct access to the ACS without using the cache. | ||
| */ | ||
| raw: Reader; | ||
| /** | ||
| * Reads active contracts from the cache. | ||
| */ | ||
| read(options: AcsOptions): Promise<({ | ||
| workflowId?: string; | ||
| contractEntry?: import("../../ledger-client-types/dist/generated-clients/openapi-3.4.12").components["schemas"]["JsContractEntry"]; | ||
| } & { | ||
| workflowId?: string; | ||
| contractEntry?: import("../../ledger-client-types/dist/generated-clients/openapi-3.5.1").components["schemas"]["JsContractEntry"]; | ||
| streamContinuationToken?: string; | ||
| })[]>; | ||
| /** | ||
| * Convenience method that returns active contracts as JS contract objects. | ||
| */ | ||
| readJsContracts(options: AcsOptions): Promise<{ | ||
| synchronizerId: string; | ||
| offset: number; | ||
| nodeId: number; | ||
| contractId: string; | ||
| templateId: string; | ||
| contractKey?: unknown; | ||
| createArgument: unknown; | ||
| createdEventBlob?: string; | ||
| interfaceViews?: { | ||
| interfaceId: string; | ||
| viewStatus: import("../../ledger-client-types/dist/generated-clients/openapi-3.4.12").components["schemas"]["JsStatus"]; | ||
| viewValue?: unknown; | ||
| }[] & { | ||
| interfaceId: string; | ||
| viewStatus: import("../../ledger-client-types/dist/generated-clients/openapi-3.5.1").components["schemas"]["JsStatus"]; | ||
| viewValue?: unknown; | ||
| implementationPackageId?: string; | ||
| }[]; | ||
| witnessParties: string[]; | ||
| signatories: string[]; | ||
| observers?: string[]; | ||
| createdAt: string; | ||
| packageName: string; | ||
| representativePackageId: string; | ||
| acsDelta: boolean; | ||
| contractKeyHash?: string; | ||
| }[]>; | ||
| private readJsContractsWith; | ||
| private resolveAcsOptions; | ||
| } | ||
| export {}; | ||
| //# sourceMappingURL=reader.d.ts.map |
| {"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../src/reader.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,sBAAsB,EAEzB,MAAM,sCAAsC,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAkC,MAAM,WAAW,CAAA;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAE9E,KAAK,MAAM,GAAG;IACV,IAAI,EAAE,CACF,OAAO,EAAE,UAAU,KAClB,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,8BAA8B,CAAC,CAAC,CAAC,CAAA;IACxE,eAAe,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,OAAO,CAC7C,KAAK,CACD,mBAAmB,CAAC,kBAAkB,CAAC,CAAC,cAAc,CAAC,GAAG;QACtD,cAAc,EAAE,mBAAmB,CAAC,kBAAkB,CAAC,CAAC,gBAAgB,CAAC,CAAA;KAC5E,CACJ,CACJ,CAAA;CACJ,CAAA;AAED,qBAAa,SAAU,YAAW,MAAM;IAKhC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IALlC,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,OAAO,CAAY;gBAGN,MAAM,EAAE,sBAAsB,EAC9B,YAAY,CAAC,EAAE,eAAe,YAAA;IAMnD;;OAEG;IACI,GAAG,EAAE,MAAM,CAQjB;IAED;;OAEG;IACU,IAAI,CAAC,OAAO,EAAE,UAAU;;wBAmD80/H,+FAAsB;;;wBAAm6xB,8FAAsB;;;IA9Cl0xJ;;OAEG;IACU,eAAe,CAAC,OAAO,EAAE,UAAU;;;;;;;;;;;wBA2C0lnI,+FAAsB;;;;wBAA2y1B,8FAAsB;;;;;;;;;;;;;IAvCj+8J,OAAO,CAAC,mBAAmB;YAqBb,iBAAiB;CAiBlC"} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
235770
41.78%32
77.78%1950
31.85%209
10350%1
Infinity%