import { HttpHandler } from '@solid/community-server'; import type { HttpHandlerInput, HttpRequest, HttpResponse } from '@solid/community-server'; import type { ActivityEmitter, CredentialsExtractor, PermissionReader, Authorizer } from '@solid/community-server'; import { SubgraphQueryEngine } from '../storage/sparql/SubgraphQueryEngine'; import { MixDataAccessor } from '../storage/accessors/MixDataAccessor'; interface SubgraphSparqlHttpHandlerOptions { /** @deprecated Use sidecarPath instead */ resourceSuffix?: string; /** @deprecated Use sidecarPath instead */ containerSuffix?: string; /** Sidecar API path segment, default: '/-/sparql' */ sidecarPath?: string; identityDbUrl?: string; usageDbUrl?: string; defaultAccountBandwidthLimitBps?: number | null; } export interface TrustedSubgraphSparqlHandler { handleTrustedInternalSelect(input: { ownerWebId: string; endpointUrl: string; query: string; request: HttpRequest; response: HttpResponse; }): Promise; handleTrustedInternalUpdate(input: { ownerWebId: string; endpointUrl: string; query: string; request: HttpRequest; response: HttpResponse; }): Promise; } export declare class SubgraphSparqlHttpHandler extends HttpHandler { protected readonly logger: import("global-logger-factory").Logger; private readonly engine; private readonly credentialsExtractor; private readonly permissionReader; private readonly authorizer; private readonly sidecarPath; private readonly podLookup?; private readonly usageRepo?; private readonly defaultBandwidthLimit?; private readonly updateAuthority?; private readonly emitter?; private readonly generator; private static readonly XSD_STRING; constructor(queryEngine: SubgraphQueryEngine, credentialsExtractor: CredentialsExtractor, permissionReader: PermissionReader, authorizer: Authorizer, options?: SubgraphSparqlHttpHandlerOptions, updateAuthority?: MixDataAccessor, emitter?: ActivityEmitter); canHandle({ request }: HttpHandlerInput): Promise; handle({ request, response }: HttpHandlerInput): Promise; /** * Execute the model collection SELECT after InternalPodDataHttpHandler has * verified the signed owner intent. This is deliberately not reachable from * the normal HTTP routing path and performs its own exact owner/endpoint * validation before bypassing caller credentials. */ handleTrustedInternalSelect(input: Parameters[0]): Promise; handleTrustedInternalUpdate(input: Parameters[0]): Promise; private sendErrorResponse; private acceptsJson; private executeSelect; private executeAsk; private executeConstruct; private executeUpdate; /** * Turns the write targets of an update access plan into the activities that should be emitted. * * Only documents actually written by the update (the plan's `writeTargets`) are considered: * one activity per document, never per quad and never for an untouched resource. */ private resolvePendingActivities; /** * Maps the SPARQL update operation applied to one document to the ActivityStream term the * CSS notification generators understand (`MonitoringStore` only forwards `as:Add|Create|Delete|Remove|Update`). * * Mapping (the closest faithful term for each operation): * - `CREATE [SILENT] GRAPH` -> `as:Create` when the document did not exist yet; * a `CREATE` on an existing graph is a silent no-op -> nothing. * - `INSERT DATA` / `INSERT … WHERE` / `LOAD` / * `ADD` / `COPY` target -> `as:Create` when the document did not exist yet, else `as:Update` * (same `exists ? Update : Create` rule CSS uses for PUT). * - `DELETE DATA` / `DELETE WHERE` / * `INSERT … DELETE … WHERE` -> `as:Update` (partial removal; the document itself survives). * - `CLEAR GRAPH` / `DROP GRAPH` / `MOVE` source -> `as:Update`: every triple is gone, but `MixDataAccessor.executeSparqlUpdate` rewrites the graph into an *empty* document instead of removing the resource, so a re-read returns 200-empty rather than 404. That observable result equals a `DELETE DATA` which removes every triple, which maps to `Update`. `as:Delete` is therefore deliberately unused: it becomes correct only once an accessor actually removes the document (a re-read would then be 404). * - delete-only update on a missing document -> nothing (SPARQL no-op). * - `as:Add` / `as:Remove` are deliberately not used: those describe container membership changes * (`DataAccessorBasedStore.addContainerActivity`), and the sidecar writes document graphs only. */ private resolveActivity; /** * Checks whether the document already exists before the update is applied. * * Uses the same accessor that performs the write, so the answer describes the storage the * activity is about. Returns `undefined` when the answer cannot be determined; callers then * fall back to the conservative `Update`/`Delete` terms instead of `Create`. */ private documentExistedBefore; /** * Emits the resolved activities on the injected {@link ActivityEmitter}. * * Mirrors `MonitoringStore.emitChanged` * (node_modules/@solid/community-server/dist/storage/MonitoringStore.js:36-45): for every changed resource * one `changed` event plus the ActivityStream-typed event, with the same metadata shape * `DataAccessorBasedStore.addActivityMetadata` produces (an `urn:npm:solid:community-server:activity:` quad). * `ListeningActivityHandler` (dist/server/notifications/ListeningActivityHandler.js:25) subscribes to `changed` * and derives the notification state by re-reading the store, so no ETag has to be carried here. */ private emitActivities; private sendPayload; private streamWithLimit; private resolveUsageContext; private inferPodIdFromPath; private resolveBandwidthLimit; private recordBandwidth; private normalizeLimit; private normalizeBandwidthDelta; private resolveReadAccessScope; private resolveReadAccessScopeForCredentials; private trustedReadAccessScope; private authorizeFor; private canAuthorizeFor; private authorizeIdentifier; private inspectUpdateGraphs; private inspectQuads; private inspectPatterns; private assertGraphInScope; private assertGraphTermInScope; /** * Registers a graph as written by the update and records which kind of change applies to it. * * Several operations can target the same graph in one request; the flags are accumulated so the graph * still yields at most one activity. This is also the only place write targets are created, which keeps * notification coverage tied to the same plan that drives authorization. */ private addWriteTarget; private readLoadDocument; private rewriteLoadUpdate; private rewriteLoadedDocumentUpdate; private rewriteClearGraphUpdate; private rewriteGraphCopyUpdate; private resourceUrlForGraphValue; /** * Rewrites INSERT/DELETE/INSERT+DELETE that target the default graph (or BGP without GRAPH) * so they write to the resource graph (graphIri). */ private rewriteDefaultGraphUpdates; private refreshUsage; private computeGraphSize; private writeOptions; private extractQuery; private parseUrl; private isContainerSidecarBase; private readBody; private termToJson; private static measureQuad; private static termToNQuads; private static literalToNQuads; private static escapeLiteral; private isInsertDeleteOperation; private isLoadOperation; private isClearGraphOperation; private isDropGraphOperation; private isGraphCopyOperation; private isCreateGraphOperation; private getRequestId; private isSqliteUrl; } export {};