UNPKG

@mochabug/adapt-plugin-toolkit

Version:

The API toolkit to facilitate mochabug adapt plugin development

1,241 lines (1,240 loc) 65.9 kB
import { JsonValue } from '@bufbuild/protobuf'; import { ValueJson } from '@bufbuild/protobuf/wkt'; import { Client, Code, ConnectError } from '@connectrpc/connect'; import { SignalData } from './genproto/mochabugapis/adapt/graph/signal_data_pb'; import { SignalFormatJson } from './genproto/mochabugapis/adapt/graph/signal_format_pb'; import { VertexMetadataJson } from './genproto/mochabugapis/adapt/graph/vertex_metadata_pb'; import { ConfiguratorService, ExchangeOperation, ExecutorService, ListIncomingSignalsResponseJson, NamespaceJson, PluginService, Token } from './genproto/mochabugapis/adapt/runtime/v1/runtime_pb'; import { GetValue, SelectOpJson, WriteOperation } from './genproto/mochabugapis/adapt/runtime/v1/store_pb'; import { ConfiguratorEnvironment, Environment, ExecutorEnvironment } from './types'; export * from './genproto/mochabugapis/adapt/automations/v1/automations_pb'; export * from './genproto/mochabugapis/adapt/graph/exchange_pb'; export * from './genproto/mochabugapis/adapt/graph/jtd_schema_pb'; export * from './genproto/mochabugapis/adapt/graph/receiver_pb'; export * from './genproto/mochabugapis/adapt/graph/signal_binding_pb'; export * from './genproto/mochabugapis/adapt/graph/signal_data_pb'; export * from './genproto/mochabugapis/adapt/graph/signal_descriptor_pb'; export * from './genproto/mochabugapis/adapt/graph/signal_format_pb'; export * from './genproto/mochabugapis/adapt/graph/transceiver_pb'; export * from './genproto/mochabugapis/adapt/graph/transmitter_pb'; export * from './genproto/mochabugapis/adapt/graph/vertex_metadata_pb'; export * from './genproto/mochabugapis/adapt/runtime/v1/incoming_pb'; export * from './genproto/mochabugapis/adapt/runtime/v1/runtime_pb'; export * from './genproto/mochabugapis/adapt/runtime/v1/store_pb'; export * from './types'; export { Code, ConnectError }; export type { ValueJson }; /** * Array representing asset directories. */ export type AssetDirectory = { /** * Name of the asset directory. */ name: string; /** * Type of the asset (file or directory). */ type: 'file' | 'directory'; }[]; /** * Represents the content of an asset file. */ export type AssetFile = { /** * Content of the asset file as a readable stream. */ content: ReadableStream; /** * MIME type of the asset file. */ mime: string; }; /** * Base class for API interactions. Extended by specific API implementations. * Not intended for direct use. */ export declare class ApiBase { protected env: Environment; protected pluginService: Client<typeof PluginService>; protected pluginToken: string; /** * Initializes the ApiBase instance with environment settings and a plugin token. * * @param env - Environment configuration for API communication. * @param pluginToken - Token for plugin authentication. */ constructor(env: Environment, pluginToken: string); /** * Retrieves a single plugin-scoped variable by its name. * Supports dot notation for nested variable names (e.g., 'api.credentials.key'). * * @param name - The name of the variable (1-100 chars, pattern: ^[_$a-zA-Z][_$a-zA-Z0-9]*(?:\.[_$a-zA-Z][_$a-zA-Z0-9]*)*$). * @returns A promise that resolves with the variable value (undefined if not found). * * @example * ```typescript * const apiUrl = await api.getSystemVariable<string>('api.url'); * const nested = await api.getSystemVariable<string>('config.database.host'); * ``` */ getSystemVariable<T = ValueJson>(name: string): Promise<T>; /** * Retrieves multiple plugin-scoped variables by their names with full type safety. * Supports dot notation for nested variable names. * * @template T - Record type mapping variable names to their expected types. * @param keys - Names of the variables to retrieve (1-100 unique names, each 1-100 chars). * @returns A promise that resolves with an object mapping variable names to their typed values. * @throws {ConnectError} Code.InvalidArgument if keys array is empty or exceeds 100 items. * * @example * ```typescript * const vars = await api.getSystemVariables<{ * 'api.url': string; * 'api.timeout': number; * 'api.enabled': boolean; * }>('api.url', 'api.timeout', 'api.enabled'); * * // Fully typed! * vars['api.url']; // string * vars['api.timeout']; // number * vars['api.enabled']; // boolean * ``` */ getSystemVariables<T extends Record<string, any>>(...keys: Array<keyof T & string>): Promise<T>; /** * Retrieves a single user-scoped variable by its name. * Supports dot notation for nested variable names (e.g., 'user.preferences.theme'). * * @param name - The name of the variable (1-100 chars, pattern: ^[_$a-zA-Z][_$a-zA-Z0-9]*(?:\.[_$a-zA-Z][_$a-zA-Z0-9]*)*$). * @returns A promise that resolves with the user variable value (undefined if not found). * * @example * ```typescript * const theme = await api.getUserVariable<string>('user.preferences.theme'); * const email = await api.getUserVariable<string>('user.email'); * ``` */ getUserVariable<T = ValueJson>(name: string): Promise<T>; /** * Retrieves multiple user-scoped variables by their names with full type safety. * Supports dot notation for nested variable names. * * @template T - Record type mapping variable names to their expected types. * @param keys - Names of the user variables to retrieve (1-100 unique names, each 1-100 chars). * @returns A promise that resolves with an object mapping variable names to their typed values. * @throws {ConnectError} Code.InvalidArgument if keys array is empty or exceeds 100 items. * * @example * ```typescript * const vars = await api.getUserVariables<{ * 'user.email': string; * 'user.age': number; * 'user.verified': boolean; * }>('user.email', 'user.age', 'user.verified'); * * // Fully typed! * vars['user.email']; // string * vars['user.age']; // number * vars['user.verified']; // boolean * ``` */ getUserVariables<T extends Record<string, any>>(...keys: Array<keyof T & string>): Promise<T>; /** * Retrieves a single user OAuth2 bearer token by its name. * Returns a Token object containing the access token, type (typically 'Bearer'), and expiration timestamp. * * @param name - The name of the user token (1-100 chars, pattern: ^[_$a-zA-Z][_$a-zA-Z0-9]*(?:\.[_$a-zA-Z][_$a-zA-Z0-9]*)*$). * @returns A promise that resolves with the Token object (undefined if not found). * Token contains: { name, token, type, expires } * * @example * ```typescript * const githubToken = await api.getUserToken('github'); * if (githubToken) { * console.log(githubToken.token, githubToken.type, githubToken.expires); * } * ``` */ getUserToken(name: string): Promise<Token>; /** * Retrieves multiple user OAuth2 bearer tokens by their names. * Each Token contains the access token, type (typically 'Bearer'), and expiration timestamp. * * @param names - Names of the user tokens to retrieve (1-100 unique names, each 1-100 chars). * @returns A promise that resolves with an object mapping token names to their Token objects. * Each Token contains: { name, token, type, expires } * @throws {ConnectError} Code.InvalidArgument if names array is empty or exceeds 100 items. * * @example * ```typescript * const tokens = await api.getUserTokens('github', 'google'); * * tokens['github']; // Token | undefined * tokens['google']; // Token | undefined * ``` */ getUserTokens(...names: string[]): Promise<Record<string, Token>>; /** * Retrieves a single plugin OAuth2 bearer token from a service account by its name. * Returns a Token object containing the access token, type (typically 'Bearer'), and expiration timestamp. * * @param name - The name of the plugin token (1-100 chars, pattern: ^[_$a-zA-Z][_$a-zA-Z0-9]*(?:\.[_$a-zA-Z][_$a-zA-Z0-9]*)*$). * @returns A promise that resolves with the Token object (undefined if not found). * Token contains: { name, token, type, expires } * * @example * ```typescript * const serviceToken = await api.getSystemToken('service_account'); * if (serviceToken) { * console.log(serviceToken.token, serviceToken.expires); * } * ``` */ getSystemToken(name: string): Promise<Token>; /** * Retrieves multiple plugin OAuth2 bearer tokens from service accounts by their names. * Each Token contains the access token, type (typically 'Bearer'), and expiration timestamp. * * @param names - Names of the plugin tokens to retrieve (1-100 unique names, each 1-100 chars). * @returns A promise that resolves with an object mapping token names to their Token objects. * Each Token contains: { name, token, type, expires } * @throws {ConnectError} Code.InvalidArgument if names array is empty or exceeds 100 items. * * @example * ```typescript * const tokens = await api.getSystemTokens('service_account', 'backup_service'); * * tokens['service_account']; // Token | undefined * tokens['backup_service']; // Token | undefined * ``` */ getSystemTokens(...names: string[]): Promise<Record<string, Token>>; /** * Creates a fetch function for user-level HTTP proxy requests. * * User services are vertex-level configurations where each user can provide * their own certificates, API keys, and credentials. * * @param name - The service name defined in vertex user_services * @returns A fetch function configured with HTTP proxy headers * * @example * ```typescript * const fetch = api.userHttpProxy("stripe_api"); * const res = await fetch("https://api.stripe.com/v1/charges"); * ``` */ userHttpProxy(name: string): typeof fetch; /** * Creates a fetch function for system-level HTTP proxy requests. * * System services are plugin-wide configurations shared across all vertices. * Configured once by plugin administrators. * * @param name - The service name defined in manifest system_services * @returns A fetch function configured with HTTP proxy headers * * @example * ```typescript * const fetch = api.systemHttpProxy("internal_api"); * const res = await fetch("https://internal.example.com/data"); * ``` */ systemHttpProxy(name: string): typeof fetch; /** * Validates an access token to ensure it's authorized for the current plugin and execution context. * The authorization check verifies the token has the required scopes for plugin operations. * * @param token - The access token to validate (max 10000 chars). * @returns A promise that resolves when the token is successfully validated. * @throws {ConnectError} Code.Unauthenticated if the token is invalid or Code.PermissionDenied if unauthorized. * * @example * ```typescript * try { * await api.authorize(userProvidedToken); * // Token is valid, proceed with operations * } catch (error) { * // Token is invalid or lacks permissions * } * ``` */ authorize(token: string): Promise<void>; /** * Get information about configured system services. * System services are plugin-wide configurations shared across all vertices. * * @returns A promise that resolves with a map of configured services where keys are service paths * (using dot notation for nested services) and values indicate if the service is configured. * * @example * ```typescript * const services = await api.getSystemServices(); * // Returns { "http_service": true, "oneof_service.option_a": true, "grouped.nested": true } * ``` */ getSystemServices(): Promise<{ [key: string]: boolean; }>; /** * Reads a file from the plugin's assets directory. * * @param path - The file path relative to the assets directory. * @returns A promise that resolves with the file content and MIME type. * @throws {ConnectError} If the file is not found or is actually a directory. */ readFile(path: string): Promise<AssetFile>; /** * Reads a directory listing from the plugin's assets directory. * * @param path - The directory path relative to the assets directory. * @returns A promise that resolves with the directory content as an array of assets. * @throws {ConnectError} If the directory is not found or is actually a file. */ readDirectory(path: string): Promise<AssetDirectory>; } /** * Represents the result of a batch read operation from the store. * Keys that were not found in the store are not present in the result. */ export declare class BatchReadResult { readonly result: Record<string, GetValue>; /** * Constructs a BatchReadResult from the store's batch read response. * @param result - Map of keys to their retrieved values (keys not found are excluded). * @internal */ constructor(result: Record<string, GetValue>); /** * Retrieves the result of a specific read operation by its key as JSON. * * @param key - The key to retrieve from the batch result. * @returns The value and metadata, or undefined if the key was not found in the store. * - value: The parsed JSON value * - ttl: Remaining TTL in seconds (0 = no expiration) * - lastModified: When the value was last modified * - etag: Entity tag for concurrency control * * @example * ```typescript * const result = await store.readBatch(['user:1', 'user:2', 'user:3']); * const user1 = result.get<User>('user:1'); * if (user1) { * console.log(user1.value.name, 'TTL:', user1.ttl); * } * ``` */ get<T = any>(key: string): { value: T; ttl: number; lastModified: Date; etag: string; } | undefined; /** * Retrieves the result of a specific read operation by its key as raw binary. * * @param key - The key to retrieve from the batch result. * @returns The raw binary value and metadata, or undefined if the key was not found in the store. * - value: The raw binary data as Uint8Array * - ttl: Remaining TTL in seconds (0 = no expiration) * - lastModified: When the value was last modified * - etag: Entity tag for concurrency control * * @example * ```typescript * const result = await store.readBatch(['asset:1', 'asset:2']); * const asset1 = result.getBinary('asset:1'); * if (asset1) { * console.log('Size:', asset1.value.length, 'bytes'); * } * ``` */ getBinary(key: string): { ttl: number; value: Uint8Array; lastModified: Date; etag: string; } | undefined; } /** * Utility class for constructing batch write operations for the KV store. * Provides a fluent interface for building write batches. * * Note: Batch operations do not support preconditions. Use Store.insert() and Store.delete() * methods directly for conditional writes. */ export declare class WriteBatchBuilder { private ops; /** * Adds an insert operation to the batch for JSON data or raw binary data. * * @param key - The key to insert (max 4096 characters). * @param value - The value to store (will be JSON-serialized unless it's Uint8Array). * @param ttl - Optional time-to-live in seconds (0 = no expiration). * @returns The current instance of the builder for chaining. * * @example * ```typescript * const batch = new WriteBatchBuilder() * .insert('user:1', { name: 'Alice' }, 3600) * .insert('user:2', { name: 'Bob' }) * .build(); * ``` */ insert<T = any>(key: string, value: T, ttl?: number): this; /** * Adds a delete operation to the batch. * * @param key - The key to delete (max 4096 characters). * @returns The current instance of the builder for chaining. * * @example * ```typescript * const batch = new WriteBatchBuilder() * .delete('temp:cache:1') * .delete('temp:cache:2') * .build(); * ``` */ delete(key: string): this; /** * Adds a range delete operation to the batch (lexicographic comparison). * * Range delete works like SelectOp for defining the range. Not setting any start or end will * delete the entire store when this batch is executed. * * @param start - The start key of the range. If omitted, deletes from the empty key. * @param end - The end key of the range. If omitted, deletes to the end. * @param startInclusive - Include start (>= vs >). Defaults to `false`. * @param endInclusive - Include end (<= vs <). Defaults to `false`. * @returns The current instance for method chaining. * * @example * ```typescript * // Delete all keys with prefix "user/" * builder.rangeDelete('user/', 'user/~'); * * // Delete logs for a specific month * builder.rangeDelete('logs/2024-01/', 'logs/2024-02/'); * ``` */ rangeDelete(start?: string, end?: string, startInclusive?: boolean, endInclusive?: boolean): this; /** * Finalizes the batch and returns the array of write operations. * * @returns The array of WriteOperation objects ready to be executed. */ build(): WriteOperation[]; } /** * Options for lock operations. */ export interface LockOptions { /** * Maximum number of retries if the lock is not acquired immediately. Defaults to 5. */ maxRetries?: number; /** * Initial delay before retrying in milliseconds. Defaults to 50ms. */ initialDelay?: number; /** * Maximum delay between retries in milliseconds. Defaults to 2000ms. */ maxDelay?: number; } /** * Preconditions for conditional insert operations. * Used for implementing locks and optimistic concurrency control. * * IMPORTANT CONSTRAINTS (from proto validation): * - failIfExists CANNOT be combined with etagEquals, timestampEquals, or timestampRange * - When failIfExists is true, all other fields must be undefined * - etagEquals and timestamp conditions can be used together */ export interface InsertCondition { /** * Fail the insert if the key already exists. * When true, this cannot be combined with any other conditions. * Useful for acquiring locks atomically. */ failIfExists?: boolean; /** * Only insert if the current etag matches this value. * Cannot be used with failIfExists. */ etagEquals?: string; /** * Only insert if last_modified exactly matches this timestamp. * Cannot be used with failIfExists or timestampRange. */ timestampEquals?: Date; /** * Only insert if last_modified falls within this time range. * Cannot be used with failIfExists or timestampEquals. */ timestampRange: { /** * Start * * @generated from field: google.protobuf.Timestamp start = 1; */ start?: Date; /** * End * * @generated from field: google.protobuf.Timestamp end = 2; */ end?: Date; /** * Include start (>= vs >) * * @generated from field: bool start_inclusive = 3; */ startInclusive: boolean; /** * Include end (<= vs <) * * @generated from field: bool end_inclusive = 4; */ endInclusive: boolean; }; } /** * Preconditions for conditional delete operations. * Used for safe deletion with verification. * * IMPORTANT CONSTRAINTS (from proto validation): * - mustExists CANNOT be combined with etagEquals, timestampEquals, or timestampRange * - When mustExists is true, all other fields must be undefined * - etagEquals and timestamp conditions can be used together */ export interface DeleteCondition { /** * Fail the delete if the key doesn't exist. * When true, this cannot be combined with any other conditions. */ mustExists?: boolean; /** * Only delete if the current etag matches this value. * Cannot be used with mustExists. */ etagEquals?: string; /** * Only delete if last_modified exactly matches this timestamp. * Cannot be used with mustExists or timestampRange. */ timestampEquals?: Date; /** * Only delete if last_modified falls within this time range. * Cannot be used with mustExists or timestampEquals. */ timestampRange: { /** * Start * * @generated from field: google.protobuf.Timestamp start = 1; */ start?: Date; /** * End * * @generated from field: google.protobuf.Timestamp end = 2; */ end?: Date; /** * Include start (>= vs >) * * @generated from field: bool start_inclusive = 3; */ startInclusive: boolean; /** * Include end (<= vs <) * * @generated from field: bool end_inclusive = 4; */ endInclusive: boolean; }; } /** * Metadata returned from store write operations. */ export interface StoreMetadata { /** * Remaining time-to-live in seconds. * 0 means no expiration (the value will not expire). */ ttl: number; /** * Timestamp when the value was last modified. * All operations in a write batch share the same timestamp. */ lastModified: Date; /** * Entity tag for optimistic concurrency control. * Changes with each modification of the value. */ etag: string; } /** * Internal type for store service clients * @internal */ type StoreServiceClient = Client<typeof ExecutorService> | Client<typeof ConfiguratorService>; /** * Represents a store in a specific namespace, providing key-value storage operations. * Stores can be scoped to different namespaces with different lifetimes: * - NAMESPACE_VERTEX: Lives as long as the plugin in the project (vertex scope) * - NAMESPACE_PLUGIN: Lives as long as the plugin in the project (plugin-wide scope) * - NAMESPACE_VERTEX_INSTANCE: Lives as long as the instance (vertex scope, session storage) * - NAMESPACE_PLUGIN_INSTANCE: Lives as long as the instance (plugin-wide scope, session storage) */ export declare class Store { private service; private namespace; /** * Constructs a Store instance for a specific namespace. * @param service - The gRPC service client (ExecutorService or ConfiguratorService). * @param namespace - The namespace determining the store's scope and lifetime. * @internal */ constructor(service: StoreServiceClient, namespace: NamespaceJson); /** * Inserts or updates a key-value pair in the store with JSON data. * Supports conditional writes for implementing locks and optimistic concurrency control. * * @param key - The key to insert (max 4096 characters). * @param value - The JSON value to store (will be JSON-serialized). * @param ttl - Optional time-to-live in seconds (0 = no expiration). * @param condition - Optional preconditions for the write: * - failIfExists: Fail if key already exists (cannot be combined with other conditions) * - etagEquals: Only write if current etag matches * - timestampEquals: Only write if last_modified exactly matches * - timestampRange: Only write if last_modified falls within range * @returns A promise that resolves with metadata (ttl, lastModified, etag) when the operation completes. * @throws {ConnectError} Code.FailedPrecondition if precondition fails, Code.InvalidArgument for invalid inputs. * * @example * ```typescript * // Simple insert * await store.insert('user:123', { name: 'Alice' }, 3600); * * // Conditional insert - fail if exists (for locks) * await store.insert('lock:resource', { owner: 'process-1' }, 30, { failIfExists: true }); * * // Optimistic concurrency with etag * const data = await store.get('counter'); * await store.insert('counter', data.data + 1, undefined, { etagEquals: data.etag }); * ``` */ insert<T = any>(key: string, value: T, ttl?: number, condition?: InsertCondition): Promise<StoreMetadata>; /** * Deletes a key-value pair from the store. * Supports conditional deletes for safe removal operations. * * @param key - The key to delete (max 4096 characters). * @param condition - Optional preconditions for the delete: * - mustExists: Fail if key doesn't exist (cannot be combined with other conditions) * - etagEquals: Only delete if current etag matches * - timestampEquals: Only delete if last_modified exactly matches * - timestampRange: Only delete if last_modified falls within range * @returns A promise that resolves when the operation completes. * @throws {ConnectError} Code.FailedPrecondition if precondition fails. * * @example * ```typescript * // Simple delete * await store.delete('temp:data'); * * // Conditional delete - only if exists * await store.delete('lock:resource', { mustExists: true }); * * // Delete with etag verification * const data = await store.get('config'); * await store.delete('config', { etagEquals: data.etag }); * ``` */ delete(key: string, condition?: DeleteCondition): Promise<void>; /** * Deletes all items within a specified key range from the store (lexicographic comparison). * * Range delete works like SelectOp for defining the range. Not setting any start or end will * delete the entire store. * * Note: Range delete operations do not support preconditions. For conditional deletes, * use the {@link delete} method. * * @param start - The start key of the range. If omitted, deletes from the empty key. * @param end - The end key of the range. If omitted, deletes to the end. * @param startInclusive - Include start (>= vs >). Defaults to `false`. * @param endInclusive - Include end (<= vs <). Defaults to `false`. * @returns A promise that resolves when the range delete operation completes. * * @example * ```typescript * // Delete all keys with prefix "user/" * await store.rangeDelete('user/', 'user/~'); * * // Delete logs for a specific month * await store.rangeDelete('logs/2024-01/', 'logs/2024-02/'); * * // Delete all items in the store * await store.rangeDelete(); * ``` */ rangeDelete(start?: string, end?: string, startInclusive?: boolean, endInclusive?: boolean): Promise<void>; /** * Retrieves a value by its key from the store as JSON. * * @param key - The key to retrieve (max 4096 characters). * @returns A promise that resolves with the retrieved JSON value and metadata, or undefined if key not found. * - data: The parsed JSON value * - ttl: Remaining TTL in seconds (0 = no expiration) * - etag: The ETag for optimistic concurrency control * - lastModified: Timestamp of last modification * * @example * ```typescript * const user = await store.get<User>('user:123'); * if (user) { * console.log(user.data.name, 'expires in', user.ttl, 'seconds'); * } * ``` */ get<T = any>(key: string): Promise<{ data: T; ttl: number; etag: string; lastModified: Date; } | undefined>; /** * Retrieves a value by its key from the store as raw binary. * * @param key - The key to retrieve (max 4096 characters). * @returns A promise that resolves with the retrieved binary value and metadata, or undefined if key not found. * - data: The raw binary value as Uint8Array * - ttl: Remaining TTL in seconds (0 = no expiration) * - etag: The ETag for optimistic concurrency control * - lastModified: Timestamp of last modification * * @example * ```typescript * const asset = await store.getBinary('asset:image.png'); * if (asset) { * console.log('Image size:', asset.data.length, 'bytes'); * } * ``` */ getBinary(key: string): Promise<{ data: Uint8Array<ArrayBufferLike>; ttl: number; etag: string; lastModified: Date; } | undefined>; /** * Performs a range query on keys using lexicographic comparison, returning parsed JSON data. * * Range queries allow scanning keys within a specific range. For example: * - "user/" to "user/~" - all keys starting with "user/" * - "logs/2024-01/" to "logs/2024-02/" - all logs from January 2024 * * Not setting start or end will scan the entire store. * Results are always returned in ascending order by key. * * @param select - The select operation specifying: * - start: Optional start key (max 4096 chars). Omit to start from empty key * - end: Optional end key (max 4096 chars) * - startInclusive: Whether to include start key (>= vs >) * - endInclusive: Whether to include end key (<= vs <) * - limit: Max results (1-1000) * - pageToken: Optional token to continue from previous query * @returns A promise that resolves to an object containing: * - items: Array of values with metadata (value as JSON type T, TTL, etag, lastModified) * - nextToken: Optional pagination token to continue the query * * @example * ```typescript * // Get all user keys * const result = await store.selectRange<User>({ * start: 'user/', * end: 'user/~', * startInclusive: true, * endInclusive: false, * limit: 100 * }); * * // Continue pagination * if (result.nextToken) { * const next = await store.selectRange({ * start: 'user/', * end: 'user/~', * startInclusive: true, * endInclusive: false, * limit: 100, * pageToken: result.nextToken * }); * } * ``` */ selectRange<T = JsonValue>(select: SelectOpJson): Promise<{ nextToken?: string; items: { key: string; value: T; ttl: number; etag: string; lastModified: Date; }[]; }>; /** * Performs a range query on keys using lexicographic comparison, returning raw binary data. * * Range queries allow scanning keys within a specific range. For example: * - "user/" to "user/~" - all keys starting with "user/" * - "logs/2024-01/" to "logs/2024-02/" - all logs from January 2024 * * Not setting start or end will scan the entire store. * Results are always returned in ascending order by key. * * @param select - The select operation specifying: * - start: Optional start key (max 4096 chars). Omit to start from empty key * - end: Optional end key (max 4096 chars) * - startInclusive: Whether to include start key (>= vs >) * - endInclusive: Whether to include end key (<= vs <) * - limit: Max results (1-1000) * - pageToken: Optional token to continue from previous query * @returns A promise that resolves to an object containing: * - items: Array of values with metadata (value as Uint8Array, TTL, etag, lastModified) * - nextToken: Optional pagination token to continue the query * * @example * ```typescript * // Get all binary assets * const result = await store.selectRangeBinary({ * start: 'assets/', * end: 'assets/~', * startInclusive: true, * endInclusive: false, * limit: 50 * }); * * // Continue pagination * if (result.nextToken) { * const next = await store.selectRangeBinary({ * start: 'assets/', * end: 'assets/~', * startInclusive: true, * endInclusive: false, * limit: 50, * pageToken: result.nextToken * }); * } * ``` */ selectRangeBinary(select: SelectOpJson): Promise<{ nextToken?: string; items: { value: Uint8Array<ArrayBufferLike>; ttl: number; etag: string; lastModified: Date; }[]; }>; /** * Executes a batch of write operations on the store. * All operations are atomic - either all succeed or all fail. * All operations in a batch share the same timestamp. * Interfering operations on the same key have undefined order. * * Note: Batch operations do not support preconditions. Use the single insert/delete * methods for conditional writes. * * @param ops - The write operations to execute (1-500 operations). Use WriteBatchBuilder to construct. * @returns A promise that resolves with metadata for each inserted key (deletes don't return metadata). * @throws {ConnectError} Code.InvalidArgument if invalid operations or limits exceeded. * * @example * ```typescript * const ops = new WriteBatchBuilder() * .insert('user:1', { name: 'Alice' }, 3600) * .insert('user:2', { name: 'Bob' }, 3600) * .delete('temp:old') * .build(); * * const metadata = await store.writeBatch(ops); * console.log('Insert metadata:', metadata); * ``` */ writeBatch(ops: WriteOperation[]): Promise<{ [key: string]: StoreMetadata; }>; /** * Executes a batch of read operations on the store. * Keys not found are ignored (not present in the result). * * @param keys - The keys to read (1-10000 keys, each max 4096 characters). * @returns A promise that resolves with a BatchReadResult containing found items. * * @example * ```typescript * const result = await store.readBatch(['user:1', 'user:2', 'user:3']); * const user1 = result.get<User>('user:1'); * if (user1) { * console.log(user1.value.name); * } * ``` */ readBatch(keys: string[]): Promise<BatchReadResult>; /** * Attempts to acquire a lock for a specified duration. * Uses an atomic insert operation with failIfExists precondition that fails if the key already exists. * * @param locker - The unique identifier for the lock (max 4096 chars). * @param ttl - Time-to-live in seconds (defaults to 5 seconds if not specified). * @returns A promise that resolves with true if the lock was acquired, false if already held. * * @example * ```typescript * // Try to acquire lock with default 5 second TTL * const acquired = await store.acquire('resource_lock'); * if (acquired) { * // Lock acquired, perform work * } * * // Acquire lock with custom TTL * const acquired2 = await store.acquire('long_operation', 30); * ``` */ acquire(locker: string, ttl?: number): Promise<boolean>; /** * Releases a previously acquired lock by deleting the lock key. * * @param locker - The unique identifier for the lock (max 4096 chars). * @returns A promise that resolves when the lock is released. * * @example * ```typescript * await store.release('resource_lock'); * ``` */ release(locker: string): Promise<void>; /** * Acquires a lock and executes a critical section of code with exponential backoff retry logic. * Automatically releases the lock after the section completes or fails. * * The retry mechanism uses exponential backoff: * - Delay = min(initialDelay * 2^attempt, maxDelay) * - Default: 50ms, 100ms, 200ms, 400ms, 800ms (capped at maxDelay) * * @template T - The return type of the critical section function. * @param key - The unique identifier for the lock (max 4096 chars). * @param section - The critical section to execute once the lock is acquired. * @param options - Optional lock options: * - maxRetries: Maximum retry attempts (default: 5) * - initialDelay: Initial delay in ms before first retry (default: 50ms) * - maxDelay: Maximum delay in ms between retries (default: 2000ms) * @returns A promise that resolves with the result of the critical section. * @throws {Error} If the lock cannot be acquired after maxRetries attempts. * * @example * ```typescript * const result = await store.lock('counter_lock', async () => { * const counter = await store.get<number>('counter'); * await store.insert('counter', (counter?.data ?? 0) + 1); * return counter?.data ?? 0; * }); * * // With custom options * const result2 = await store.lock('resource', async () => { * // critical work * }, { maxRetries: 10, initialDelay: 100, maxDelay: 5000 }); * ``` */ lock<T>(key: string, section: () => Promise<T>, options?: LockOptions): Promise<T>; } /** * Provides access to the least privileged Executor API, without session capabilities. * This API allows plugins to interact with vertex configuration and local storage. */ export declare class ExecutorApi extends ApiBase { protected executor: Client<typeof ExecutorService>; /** * Initializes an instance of ExecutorApi. * * @param env - The executor environment configuration. * @param pluginToken - The plugin token for authorization. */ constructor(env: ExecutorEnvironment, pluginToken: string); /** * Get vertex configuration with JSON-parsed config field. * Optionally specify which fields to include in the response. * * @template T - Type of the config object (defaults to any) * @param fields - Optional field names to include. If not specified, returns all fields. * @returns Object containing the requested fields with config as parsed JSON (type T). * * @example * ```typescript * // Get all fields (all fields are guaranteed to be present) * const {config, metadata, services} = await api.getConfig<Settings>(); * * // Get only config with type - result type is { config: Settings } * const {config} = await api.getConfig<Settings>('config'); * * // Get config and metadata - result type is { config: Settings; metadata: VertexMetadataJson } * const {config, metadata} = await api.getConfig<Settings>('config', 'metadata'); * ``` */ getConfig<T = any>(): Promise<{ config: T; metadata: VertexMetadataJson; configuredServices: { [key: string]: boolean; }; }>; getConfig<T = any, K extends 'config' | 'metadata' | 'configuredServices' = 'config' | 'metadata' | 'configuredServices'>(...fields: K[]): Promise<Pick<{ config: T; metadata: VertexMetadataJson; configuredServices: { [key: string]: boolean; }; }, K>>; /** * Get vertex configuration with binary config field (Uint8Array). * Optionally specify which fields to include in the response. * * @param fields - Optional field names to include. If not specified, returns all fields. * @returns Object containing the requested fields with config as raw Uint8Array. * * @example * ```typescript * // Get all fields with binary config (all guaranteed present) * const {config, metadata, services} = await api.getConfigBinary(); * * // Get only binary config - result type is { config: Uint8Array } * const {config} = await api.getConfigBinary('config'); * ``` */ getConfigBinary(): Promise<{ config: Uint8Array; metadata: VertexMetadataJson; configuredServices: { [key: string]: boolean; }; }>; getConfigBinary<K extends 'config' | 'metadata' | 'configuredServices' = 'config' | 'metadata' | 'configuredServices'>(...fields: K[]): Promise<Pick<{ config: Uint8Array; metadata: VertexMetadataJson; configuredServices: { [key: string]: boolean; }; }, K>>; /** * Provides access to a local store instance, scoped by namespace. * * Namespace lifetimes: * - 'vertex' (NAMESPACE_VERTEX): Vertex-scoped, lives as long as the plugin in the project * - 'plugin' (NAMESPACE_PLUGIN): Plugin-wide scope, lives as long as the plugin in the project * * Access scopes: * - NAMESPACE_VERTEX: runtimeapi/executor.store.vertex.app, runtimeapi/executor.store.vertex.app:read * - NAMESPACE_PLUGIN: runtimeapi/executor.store.plugin.app, runtimeapi/executor.store.plugin.app:read * * @param namespace - The namespace for the store, either 'vertex' or 'plugin'. * @returns An instance of Store configured for the specified namespace. */ getLocalStore(namespace: 'vertex' | 'plugin'): Store; /** * Retrieves a session-scoped API with the provided authorization header. * Session APIs have additional capabilities like sending signals and managing exchanges. * * @param authHeader - The authorization header to use for the session API (e.g., 'Bearer <access-token>'). * @returns An instance of SessionExecutorApi configured with the provided auth header. */ getSessionApi(authHeader: string): SessionExecutorApi; } /** * Provides an API with session storage capabilities, specifically for use when a session is stopping. * This API allows access to session-scoped stores that persist for the lifetime of the instance. */ export declare class StopExecutorApi extends ExecutorApi { /** * The session authorization header for session-based operations. */ protected sessionAuthHeader: string; /** * Initializes an instance of StopExecutorApi. * * @param env - The executor environment configuration. * @param pluginToken - The plugin token for authorization. * @param sessionAuthHeader - The authorization header for session-based operations. */ constructor(env: ExecutorEnvironment, pluginToken: string, sessionAuthHeader: string); /** * Retrieves the session authorization header used for this API instance. * This header contains the session access token and can be used to create * additional session-scoped API instances or for custom authorization needs. * * @returns The session authorization header (format: 'Bearer <token>'). * * @example * ```typescript * const authHeader = api.getAuthHeader(); * // Use for creating another session API or custom requests * ``` */ getAuthHeader(): string; /** * Retrieves a session-specific store instance based on the provided namespace. * Session stores persist for the lifetime of the instance (the running session). * * Namespace lifetimes: * - 'vertex' (NAMESPACE_VERTEX_INSTANCE): Vertex-scoped, lives as long as the instance * - 'plugin' (NAMESPACE_PLUGIN_INSTANCE): Plugin-wide scope, lives as long as the instance * * Access scopes: * - NAMESPACE_VERTEX_INSTANCE: runtimeapi/executor.store.vertex.instance, runtimeapi/executor.store.vertex.instance:read * - NAMESPACE_PLUGIN_INSTANCE: runtimeapi/executor.store.plugin.instance, runtimeapi/executor.store.plugin.instance:read * * @param namespace - The namespace for the store, either 'vertex' or 'plugin'. * @returns An instance of Store configured for the session's namespace. */ getSessionStore(namespace: 'vertex' | 'plugin'): Store; } /** * Options for listing bound receiver signals. */ export interface ListSignalsOptions { /** * Number of signals per page (max 500, defaults to 50 if not specified). */ pageSize?: number; /** * Whether to order signals in descending order. */ orderDescending?: boolean; /** * Cursor for pagination (max 500 chars). * Used internally by continueListSignals - typically you don't set this directly. * @internal */ cursor?: string; } /** * Provides access to the Privileged Executor API, allowing session-based operations. * This API enables sending signals, managing exchanges, and accessing receiver signals. */ export declare class SessionExecutorApi extends StopExecutorApi { /** * Initializes an instance of SessionExecutorApi. * * @param env - The executor environment configuration. * @param pluginToken - The plugin token for authorization. * @param sessionAuthHeader - The authorization header for session access. */ constructor(env: ExecutorEnvironment, pluginToken: string, sessionAuthHeader: string); /** * Lists signals bound to the receiver that activated this vertex, returning parsed JSON data. * * Signal retrieval is always scoped to the specific receiver that triggered * the vertex execution, providing access to the contextual data that initiated * this workflow. * * IMPORTANT: The response payload is limited to a maximum of 16MB. * If the total size of all signals would exceed this limit, the response * will be truncated and a cursor will be provided to continue fetching * the remaining signals in subsequent requests. * * @param options - Optional listing options: * - pageSize: Number of signals per page (max 500, defaults to 50) * - orderDescending: Whether to order signals in descending order * @returns A promise that resolves to the list of signals, receiver name, and a cursor for pagination. * * @example * ```typescript * const result = await api.listSignals({ pageSize: 10 }); * result.signals // Record<string, ValueJson> * ``` */ listSignals(options?: ListSignalsOptions): Promise<{ signals: Record<string, ValueJson>; receiver: string; cursor?: string; }>; /** * Lists signals bound to the receiver that activated this vertex, returning raw binary data. * * Signal retrieval is always scoped to the specific receiver that triggered * the vertex execution, providing access to the contextual data that initiated * this workflow. * * IMPORTANT: The response payload is limited to a maximum of 16MB. * If the total size of all signals would exceed this limit, the response * will be truncated and a cursor will be provided to continue fetching * the remaining signals in subsequent requests. * * @param options - Optional listing options: * - pageSize: Number of signals per page (max 500, defaults to 50) * - orderDescending: Whether to order signals in descending order * @returns A promise that resolves to the list of binary signals, receiver name, and a cursor for pagination. * * @example * ```typescript * const result = await api.listSignalsBinary({ pageSize: 10 }); * result.signals // Record<string, SignalData> * ``` */ listSignalsBinary(options?: ListSignalsOptions): Promise<{ signals: Record<string, SignalData>; receiver: string; cursor?: string; }>; /** * Continues listing signals bound to the receiver that activated this vertex from a given cursor, returning parsed JSON data. * * Signal retrieval is always scoped to the specific receiver that triggered * the vertex execution, providing access to the contextual data that initiated * this workflow. * * @param cursor - The cursor to continue from. * @returns A promise that resolves to the next set of signals, receiver name, and a new cursor for further pagination. * * @example * ```typescript * const result = await api.continueListSignals(cursor); * result.signals // Record<string, ValueJson> * ``` */ continueListSignals(cursor: string): Promise<{ signals: Record<string, ValueJson>; receiver: string; cursor?: string; }>; /** * Continues listing signals bound to the receiver that activated this vertex from a given cursor, returning raw binary data. * * Signal retrieval is always scoped to the specific receiver that triggered * the vertex execution, providing access to the contextual data that initiated * this workflow. * * @param cursor - The cursor to continue from. * @returns A promise that resolves to the next set of binary signals, receiver name, and a new cursor for further pagination. * * @example * ```typescript * const result = await api.continueListSignalsBinary(cursor); * result.signals // Record<string, Uint8Array<ArrayBufferLike>> * ``` */ continueListSignalsBinary(cursor: string): Promise<{ signals: Record<string, SignalData>; receiver: string; cursor?: string; }>; /** * Retrieves a signal bound to the receiver that activated this vertex, returning parsed JSON data. * * Signal retrieval is always scoped to the specific receiver that triggered * the vertex execution, providing access to the contextual data that initiated