import { Alepha, Async, KIND, Primitive, Static } from "alepha";
import { ActionPrimitive, ClientRequestEntry, ClientRequestOptions, ClientRequestResponse, FetchResponse, HttpClient, RequestConfigSchema, ServerRequest, ServerRequestConfigEntry, ServerResponseBody, ServerTimingProvider, SseConfigSchema, SseEventData, SsePrimitive, SseRequestEntry, SseStream } from "alepha/server";
import { ProxyPrimitiveOptions, ServerProxyProvider } from "alepha/server/proxy";
import { SecureOptions, SecurityProvider, ServiceAccountPrimitive, UserAccountToken } from "alepha/security";
//#region ../../src/server/links/schemas/apiLinksResponseSchema.d.ts
declare const apiActionSchema: import("zod").ZodObject<{
  path: import("zod").ZodString;
  method: import("zod").ZodOptional<import("zod").ZodString>;
  contentType: import("zod").ZodOptional<import("zod").ZodString>;
  kind: import("zod").ZodOptional<import("zod").ZodString>;
  service: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>;
declare const apiRegistryResponseSchema: import("zod").ZodObject<{
  prefix: import("zod").ZodOptional<import("zod").ZodString>;
  actions: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodObject<{
    path: import("zod").ZodString;
    method: import("zod").ZodOptional<import("zod").ZodString>;
    contentType: import("zod").ZodOptional<import("zod").ZodString>;
    kind: import("zod").ZodOptional<import("zod").ZodString>;
    service: import("zod").ZodOptional<import("zod").ZodString>;
  }, import("zod/v4/core").$strip>>;
  permissions: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
}, import("zod/v4/core").$strip>;
type ApiRegistryResponse = Static<typeof apiRegistryResponseSchema>;
type ApiAction = Static<typeof apiActionSchema>;
/**
 * @deprecated Use `apiRegistryResponseSchema` and `ApiRegistryResponse` instead.
 */
declare const apiLinksResponseSchema: import("zod").ZodObject<{
  prefix: import("zod").ZodOptional<import("zod").ZodString>;
  actions: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodObject<{
    path: import("zod").ZodString;
    method: import("zod").ZodOptional<import("zod").ZodString>;
    contentType: import("zod").ZodOptional<import("zod").ZodString>;
    kind: import("zod").ZodOptional<import("zod").ZodString>;
    service: import("zod").ZodOptional<import("zod").ZodString>;
  }, import("zod/v4/core").$strip>>;
  permissions: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
}, import("zod/v4/core").$strip>;
/**
 * @deprecated Use `ApiRegistryResponse` instead.
 */
type ApiLinksResponse = ApiRegistryResponse;
/**
 * @deprecated Use `ApiAction` instead.
 */
type ApiLink = ApiAction;
//#endregion
//#region ../../src/server/links/atoms/apiLinksAtom.d.ts
declare const apiLinksAtom: import("alepha").Atom<import("zod").ZodOptional<import("zod").ZodObject<{
  prefix: import("zod").ZodOptional<import("zod").ZodString>;
  actions: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodObject<{
    path: import("zod").ZodString;
    method: import("zod").ZodOptional<import("zod").ZodString>;
    contentType: import("zod").ZodOptional<import("zod").ZodString>;
    kind: import("zod").ZodOptional<import("zod").ZodString>;
    service: import("zod").ZodOptional<import("zod").ZodString>;
  }, import("zod/v4/core").$strip>>;
  permissions: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
}, import("zod/v4/core").$strip>>, "alepha.server.request.apiLinks">;
//#endregion
//#region ../../src/server/links/atoms/linkOptionsAtom.d.ts
declare const linkOptionsAtom: import("alepha").Atom<import("zod").ZodObject<{
  batch: import("zod").ZodDefault<import("zod").ZodBoolean>;
}, import("zod/v4/core").$strip>, "alepha.server.links.options">;
//#endregion
//#region ../../src/server/links/services/BatchCollector.d.ts
/**
 * Collects browser-side action calls within a microtask and
 * sends them as a single `POST /api/_batch` request.
 *
 * Key behaviors:
 * - Single call in the window → direct HTTP call (no batch overhead)
 * - Multiple calls → coalesced into one batch request
 * - Same action + same params/query/body → deduplicated, result shared
 * - Exceeding MAX_BATCH_SIZE → split into multiple batch calls
 * - Transport failure → all pending promises reject
 */
declare class BatchCollector {
  protected static readonly MAX_BATCH_SIZE = 20;
  protected readonly log: import("alepha/logger").Logger;
  protected readonly httpClient: HttpClient;
  protected pending: PendingBatchEntry[];
  protected scheduled: boolean;
  /**
   * Add an action call to the batch. Returns the result when the batch resolves.
   */
  add(entry: BatchEntry): Promise<any>;
  protected flush(): Promise<void>;
  protected dedupe(batch: PendingBatchEntry[]): {
    unique: PendingBatchEntry[];
    indexMap: number[];
  };
  protected hasBinaryBody(body: unknown): boolean;
  protected chunk<T>(arr: T[], size: number): T[][];
}
interface BatchEntry {
  action: string;
  params?: Record<string, any>;
  query?: Record<string, any>;
  body?: Record<string, any>;
  directCall: () => Promise<any>;
}
interface PendingBatchEntry {
  entry: BatchEntry;
  resolve: (value: any) => void;
  reject: (reason: any) => void;
}
//#endregion
//#region ../../src/server/links/providers/LinkProvider.d.ts
/**
 * Browser, SSR friendly, service to handle links.
 */
declare class LinkProvider {
  static path: {
    apiLinks: string;
  };
  protected readonly log: import("alepha/logger").Logger;
  protected readonly alepha: Alepha;
  protected readonly httpClient: HttpClient;
  protected serverLinkMap: Map<string, HttpClientLink>;
  protected actionMap: Map<string, HttpClientLink>;
  protected permissions: Set<string>;
  protected lastLoadedRegistry: ApiRegistryResponse | null;
  protected batchCollector?: BatchCollector;
  protected readonly options: Readonly<{
    batch: boolean;
  }>;
  /**
   * Get applicative links registered on the server.
   * This does not include lazy-loaded remote links.
   */
  getServerLinks(): HttpClientLink[];
  /**
   * Register a new link for the application.
   */
  registerLink(link: HttpClientLink): void;
  /**
   * Load the registry response into internal stores (actionMap, permissions, definitions).
   * Called when storing from atom/fetch/SSR.
   */
  protected loadRegistry(registry: ApiRegistryResponse): void;
  get links(): HttpClientLink[];
  /**
   * Force browser to refresh links from the server.
   */
  fetchLinks(): Promise<HttpClientLink[]>;
  /**
   * Create a virtual client that can be used to call actions.
   *
   * Use js Proxy under the hood.
   */
  client<T extends object>(scope?: ClientScope): HttpVirtualClient<T>;
  /**
   * Check if a link with the given name exists or a permission matches.
   *
   * Action names never contain colons. Permission names always do.
   * - `can("getUsers")` → O(1) map lookup
   * - `can("admin:*")` → wildcard match against permissions set
   * - `can("admin:user:read")` → O(1) set lookup
   */
  can(name: string): boolean;
  /**
   * Resolve a link by its name and call it.
   * - If link is local, it will call the local handler.
   * - If link is remote, it will make a fetch request to the remote server.
   */
  follow(name: string, config?: Partial<ServerRequestConfigEntry>, options?: ClientRequestOptions & ClientScope): Promise<any>;
  protected createVirtualAction<T extends RequestConfigSchema>(name: string, scope?: ClientScope): VirtualAction<T>;
  protected followRemote(link: HttpClientLink, config?: Partial<ServerRequestConfigEntry>, options?: ClientRequestOptions): Promise<FetchResponse>;
  protected getLinkByName(name: string, options?: ClientScope): Promise<HttpClientLink>;
}
interface HttpClientLink {
  name: string;
  path: string;
  method?: string;
  kind?: string;
  contentType?: string;
  service?: string;
  secured?: boolean | SecureOptions;
  prefix?: string;
  group?: string;
  host?: string;
  schema?: RequestConfigSchema;
  handler?: (request: ServerRequest, options: ClientRequestOptions) => Async<ServerResponseBody>;
}
interface ClientScope {
  service?: string;
  hostname?: string;
}
type HttpVirtualClient<T> = { [K in keyof T as T[K] extends ActionPrimitive<RequestConfigSchema> ? K : never]: T[K] extends ActionPrimitive<infer Schema> ? VirtualAction<Schema> : never; } & { [K in keyof T as T[K] extends SsePrimitive<SseConfigSchema> ? K : never]: T[K] extends SsePrimitive<infer Schema> ? VirtualSse<Schema> : never; };
interface VirtualAction<T extends RequestConfigSchema> extends Pick<ActionPrimitive<T>, "name" | "run" | "fetch"> {
  (config?: ClientRequestEntry<T>, opts?: ClientRequestOptions): Promise<ClientRequestResponse<T>>;
  can: () => boolean;
}
interface VirtualSse<T extends SseConfigSchema> {
  (config?: SseRequestEntry<T>): Promise<SseStream<SseEventData<T>>>;
  name: string;
  can: () => boolean;
}
//#endregion
//#region ../../src/server/links/primitives/$client.d.ts
/**
 * Create a new client.
 */
declare const $client: {
  <T extends object>(scope?: ClientScope): HttpVirtualClient<T>;
  [KIND]: string;
};
//#endregion
//#region ../../src/server/links/primitives/$remote.d.ts
/**
 * $remote is a primitive that allows you to define remote service access.
 *
 * Use it only when you have 2 or more services that need to communicate with each other.
 *
 * All remote services can be exposed as actions, ... or not.
 *
 * You can add a service account if you want to use a security layer.
 */
declare const $remote: {
  (options: RemotePrimitiveOptions): RemotePrimitive;
  [KIND]: typeof RemotePrimitive;
};
interface RemotePrimitiveOptions {
  /**
   * The URL of the remote service.
   * You can use a function to generate the URL dynamically.
   * You probably should use $env(env) to get the URL from the environment.
   *
   * @example
   * ```ts
   * import { $remote } from "alepha/server";
   * import { $inject, z } from "alepha";
   *
   * class App {
   *   env = $env(z.object({
   *     REMOTE_URL: z.text({default: "http://localhost:3000"}),
   *   }));
   *   remote = $remote({
   *     url: this.env.REMOTE_URL,
   *   });
   * }
   * ```
   */
  url: string | (() => string);
  /**
   * The name of the remote service.
   *
   * @default Member of the class containing the remote service.
   */
  name?: string;
  /**
   * If true, all methods of the remote service will be exposed as actions in this context.
   * > Note: Proxy will never use the service account, it just... proxies the request.
   */
  proxy?: boolean | Partial<ProxyPrimitiveOptions & {
    /**
     * If true, the remote service won't be available internally, only through the proxy.
     */
    noInternal: boolean;
  }>;
  /**
   * For communication between the server and the remote service with a security layer.
   * This will be used for internal communication and will not be exposed to the client.
   */
  serviceAccount?: ServiceAccountPrimitive;
}
declare class RemotePrimitive extends Primitive<RemotePrimitiveOptions> {
  get name(): string;
}
//#endregion
//#region ../../src/server/links/providers/RemotePrimitiveProvider.d.ts
declare class RemotePrimitiveProvider {
  protected readonly serverApi: Readonly<{
    prefix: string;
  }>;
  protected readonly alepha: Alepha;
  protected readonly proxyProvider: ServerProxyProvider;
  protected readonly linkProvider: LinkProvider;
  protected readonly remotes: Array<ServerRemote>;
  protected readonly log: import("alepha/logger").Logger;
  getRemotes(): ServerRemote[];
  readonly configure: import("alepha").HookPrimitive<"configure">;
  readonly start: import("alepha").HookPrimitive<"start">;
  registerRemote(value: RemotePrimitive): Promise<void>;
  protected readonly fetchLinks: import("alepha").PipelinePrimitiveFn<(opts: FetchLinksOptions) => Promise<ApiRegistryResponse>>;
}
interface FetchLinksOptions {
  /**
   * Name of the remote service.
   */
  service: string;
  /**
   * URL to fetch links from.
   */
  url: string;
  /**
   * Authorization header containing access token.
   */
  authorization?: string;
}
interface ServerRemote {
  /**
   * URL of the remote service.
   */
  url: string;
  /**
   * Name of the remote service.
   */
  name: string;
  /**
   * Expose links as endpoint. It's not only internal.
   */
  proxy: boolean;
  /**
   * It's only used inside the application.
   */
  internal: boolean;
  /**
   * Links fetcher.
   */
  links: (args: {
    authorization?: string;
  }) => Promise<ApiRegistryResponse>;
  /**
   * Fetches schema for the remote service.
   */
  schema: (args: {
    name: string;
    authorization?: string;
  }) => Promise<any>;
  /**
   * Force a default access token provider when not provided.
   */
  serviceAccount?: ServiceAccountPrimitive;
  /**
   * Prefix for the remote service links.
   */
  prefix: string;
}
//#endregion
//#region ../../src/server/links/providers/ServerLinksProvider.d.ts
declare class ServerLinksProvider {
  protected readonly serverApi: Readonly<{
    prefix: string;
  }>;
  protected readonly alepha: Alepha;
  protected readonly linkProvider: LinkProvider;
  protected readonly remoteProvider: RemotePrimitiveProvider;
  protected readonly serverTimingProvider: ServerTimingProvider;
  protected readonly log: import("alepha/logger").Logger;
  /**
   * Resolved once on start. Undefined when alepha/security is not loaded.
   */
  protected securityProvider: SecurityProvider | undefined;
  /**
   * Cache of serialized JSON by role key.
   * Key = sorted roles joined by comma (empty string for unauthenticated).
   */
  protected registryCache: Map<string, RegistryCacheEntry>;
  get prefix(): string;
  readonly onRoute: import("alepha").HookPrimitive<"configure">;
  protected readonly onStart: import("alepha").HookPrimitive<"start">;
  /**
   * API registry endpoint — returns all available actions for the user.
   *
   * Response is filtered by the user's permissions.
   * Cached by role set with ETag support.
   */
  readonly links: import("alepha/server").RoutePrimitive<RequestConfigSchema>;
  /**
   * On-demand schemas endpoint — returns JSON Schemas for requested actions.
   *
   * Schemas are filtered by the user's permissions (same logic as the registry).
   */
  readonly schemas: import("alepha/server").RoutePrimitive<{
    body: import("zod").ZodObject<{
      actions: import("zod").ZodArray<import("zod").ZodString>;
    }, import("zod/v4/core").$strip>;
    response: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodObject<{
      body: import("zod").ZodOptional<import("zod").ZodString>;
      response: import("zod").ZodOptional<import("zod").ZodString>;
    }, import("zod/v4/core").$strip>>;
  }>;
  /**
   * Batch endpoint — execute multiple actions in a single HTTP request.
   * Each sub-request is independent: errors in one don't affect others.
   */
  readonly batch: import("alepha/server").RoutePrimitive<{
    body: import("zod").ZodArray<import("zod").ZodObject<{
      action: import("zod").ZodString;
      params: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>>;
      query: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>>;
      body: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>>;
    }, import("zod/v4/core").$strip>>;
    response: import("zod").ZodArray<import("zod").ZodObject<{
      action: import("zod").ZodString;
      status: import("zod").ZodInt;
      data: import("zod").ZodOptional<import("zod").ZodAny>;
      error: import("zod").ZodOptional<import("zod").ZodString>;
    }, import("zod/v4/core").$strip>>;
  }>;
  protected static readonly MAX_BATCH_SIZE = 20;
  /**
   * Retrieves API registry for the user based on their permissions.
   * Will check on local links and remote links.
   */
  getUserApiLinks(options: GetApiLinksOptions): Promise<ApiRegistryResponse>;
  /**
   * Check if a link is accessible by the given user based on security rules.
   */
  protected isLinkAccessible(link: HttpClientLink, user?: UserAccountToken): boolean;
}
interface GetApiLinksOptions {
  user?: UserAccountToken;
  authorization?: string;
}
interface RegistryCacheEntry {
  json: string;
  etag: string;
}
//#endregion
//#region ../../src/server/links/index.d.ts
declare module "alepha" {
  interface State {
    /**
     * API registry attached to the server request state.
     *
     * @see {@link ApiRegistryResponse}
     * @internal
     */
    "alepha.server.request.apiLinks"?: ApiRegistryResponse;
    /**
     * Configuration options for the links module.
     */
    "alepha.server.links.options": {
      batch: boolean;
    };
  }
}
/**
 * Type-safe API client with request deduplication.
 *
 * **Features:**
 * - Virtual HTTP client for type-safe API calls
 * - Remote action definitions
 * - Type inference from action schemas
 * - Request deduplication
 * - Automatic error handling
 *
 * @module alepha.server.links
 */
declare const AlephaServerLinks: import("alepha").Service<import("alepha").Module>;
//#endregion
export { $client, $remote, AlephaServerLinks, ApiAction, ApiLink, ApiLinksResponse, ApiRegistryResponse, BatchCollector, BatchEntry, ClientScope, FetchLinksOptions, GetApiLinksOptions, HttpClientLink, HttpVirtualClient, LinkProvider, RemotePrimitive, RemotePrimitiveOptions, RemotePrimitiveProvider, ServerLinksProvider, ServerRemote, VirtualAction, VirtualSse, apiActionSchema, apiLinksAtom, apiLinksResponseSchema, apiRegistryResponseSchema, linkOptionsAtom };
//# sourceMappingURL=index.d.ts.map