@thomasfosterau/effect-sparql-node 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +220 -2
  3. package/bin/effect-sparql-server.mjs +26 -0
  4. package/dist/Cli-DE0eXMJr.d.mts +143 -0
  5. package/dist/Cli-DFvng1N8.mjs +259 -0
  6. package/dist/Cli-DFvng1N8.mjs.map +1 -0
  7. package/dist/Cli.d.mts +2 -0
  8. package/dist/Cli.mjs +1 -0
  9. package/dist/NodeSparqlServer-1vSrPk3J.d.mts +41 -0
  10. package/dist/NodeSparqlServer-CYAd_6BG.mjs +50 -0
  11. package/dist/NodeSparqlServer-CYAd_6BG.mjs.map +1 -0
  12. package/dist/NodeSparqlServer.d.mts +2 -0
  13. package/dist/NodeSparqlServer.mjs +1 -0
  14. package/dist/SparqlApi-BKE9nIf4.d.mts +488 -0
  15. package/dist/SparqlApi-BuycDkWu.mjs +371 -0
  16. package/dist/SparqlApi-BuycDkWu.mjs.map +1 -0
  17. package/dist/SparqlApi.d.mts +2 -0
  18. package/dist/SparqlApi.mjs +1 -0
  19. package/dist/SparqlApiBuilder-BAMpMy-Z.d.mts +83 -0
  20. package/dist/SparqlApiBuilder-GT7EopBq.mjs +136 -0
  21. package/dist/SparqlApiBuilder-GT7EopBq.mjs.map +1 -0
  22. package/dist/SparqlApiBuilder.d.mts +2 -0
  23. package/dist/SparqlApiBuilder.mjs +1 -0
  24. package/dist/SparqlApiClient-C82RGMEF.d.mts +386 -0
  25. package/dist/SparqlApiClient-CJcoFy5b.mjs +203 -0
  26. package/dist/SparqlApiClient-CJcoFy5b.mjs.map +1 -0
  27. package/dist/SparqlApiClient.d.mts +2 -0
  28. package/dist/SparqlApiClient.mjs +1 -0
  29. package/dist/index.d.mts +6 -0
  30. package/dist/index.mjs +6 -0
  31. package/dist/rolldown-runtime-D8jQpDG7.mjs +12 -0
  32. package/package.json +67 -3
  33. package/src/Cli.ts +373 -0
  34. package/src/NodeSparqlServer.ts +71 -0
  35. package/src/SparqlApi.ts +506 -0
  36. package/src/SparqlApiBuilder.ts +196 -0
  37. package/src/SparqlApiClient.ts +383 -0
  38. package/src/index.ts +20 -0
@@ -0,0 +1,371 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D8jQpDG7.mjs";
2
+ import * as Schema from "effect/Schema";
3
+ import * as ServerFormats from "@thomasfosterau/effect-rdf/sparql/ServerFormats";
4
+ import * as Arr from "effect/Array";
5
+ import * as SchemaTransformation from "effect/SchemaTransformation";
6
+ import * as HttpApi from "effect/http-api/HttpApi";
7
+ import * as HttpApiEndpoint from "effect/http-api/HttpApiEndpoint";
8
+ import * as HttpApiGroup from "effect/http-api/HttpApiGroup";
9
+ import * as HttpApiMiddleware from "effect/http-api/HttpApiMiddleware";
10
+ import * as HttpApiSchema from "effect/http-api/HttpApiSchema";
11
+ import * as OpenApi from "effect/http-api/OpenApi";
12
+ import * as Results from "@thomasfosterau/effect-rdf/sparql/Results";
13
+ import * as ProtocolErrors from "@thomasfosterau/effect-rdf/sparql/ProtocolErrors";
14
+ import * as Protocol from "@thomasfosterau/effect-rdf/sparql/Protocol";
15
+ // src/SparqlApi.ts
16
+ /**
17
+ * The SPARQL 1.1 Protocol and Graph Store HTTP Protocol as an Effect
18
+ * `HttpApi` definition: the endpoints, their parameters, request media types,
19
+ * response media types and error statuses, shared by the server
20
+ * (`SparqlApiBuilder`), the derived client
21
+ * (`SparqlApiClient`) and the OpenAPI document
22
+ * (`openApi`).
23
+ *
24
+ * The API has two groups:
25
+ *
26
+ * - `sparql`: `query` (`GET` with `?query=`, or without it for the service
27
+ * description) and `post` (`POST` with an
28
+ * `application/x-www-form-urlencoded`, `application/sparql-query` or
29
+ * `application/sparql-update` body);
30
+ * - `graphStore`: `get`, `head`, `put`, `post` and `delete` on the graph store
31
+ * with `?graph=<iri>` or `?default`, with RDF bodies under every media type
32
+ * of the default `Formats`.
33
+ *
34
+ * Content negotiation (`Accept`) and `405 Method Not Allowed` are not part of
35
+ * the definition: the server's handlers negotiate with the same code as
36
+ * `SparqlServer`, and `SparqlApiBuilder` answers the methods the API does not
37
+ * declare. A request whose parameters the API's schemas reject (a repeated
38
+ * `query` or `graph`, say) is handed to the protocol handler too, by the
39
+ * `SchemaFallback` middleware, so it gets the protocol's own `400` and
40
+ * message. Error bodies are `text/plain` messages decoded into
41
+ * `ProtocolErrors.ProtocolError`.
42
+ *
43
+ * This module only describes the API, so a client can import it without the
44
+ * server. `effect/http-api` is `@stability unstable` in Effect 4, and this
45
+ * definition follows it.
46
+ *
47
+ * @since 0.1.0
48
+ */
49
+ var SparqlApi_exports = /* @__PURE__ */ __exportAll({
50
+ AcceptHeader: () => AcceptHeader,
51
+ DatasetParams: () => DatasetParams,
52
+ DirectQueryBody: () => DirectQueryBody,
53
+ DirectUpdateBody: () => DirectUpdateBody,
54
+ FormBody: () => FormBody,
55
+ GraphParams: () => GraphParams,
56
+ ProtocolErrorResponse: () => ProtocolErrorResponse,
57
+ QueryParams: () => QueryParams,
58
+ QueryResponse: () => QueryResponse,
59
+ RdfDocumentBody: () => RdfDocumentBody,
60
+ RdfResponse: () => RdfResponse,
61
+ SchemaFallback: () => SchemaFallback,
62
+ SparqlApi: () => SparqlApi,
63
+ make: () => make,
64
+ openApi: () => openApi,
65
+ queryMediaTypes: () => queryMediaTypes,
66
+ rdfMediaTypes: () => rdfMediaTypes,
67
+ resultsMediaTypes: () => resultsMediaTypes
68
+ });
69
+ /**
70
+ * The media types of the default RDF formats (`ServerFormats.codecs`), in order of
71
+ * preference: Graph Store bodies and `CONSTRUCT` / `DESCRIBE` / service
72
+ * description responses.
73
+ *
74
+ * @since 0.1.0
75
+ * @category media types
76
+ */
77
+ const rdfMediaTypes = Arr.dedupe(Arr.flatMap(ServerFormats.codecs, (codec) => codec.format.mediaTypes));
78
+ /**
79
+ * The media types of SPARQL results (`Results.codecs`): JSON, XML, CSV and
80
+ * TSV, in order of preference.
81
+ *
82
+ * @since 0.1.0
83
+ * @category media types
84
+ */
85
+ const resultsMediaTypes = Arr.dedupe(Arr.flatMap(Results.codecs, (codec) => codec.format.mediaTypes));
86
+ /**
87
+ * Every media type a query response can have: the results formats for
88
+ * `SELECT` / `ASK`, then the RDF formats for `CONSTRUCT` / `DESCRIBE` and the
89
+ * service description.
90
+ *
91
+ * @since 0.1.0
92
+ * @category media types
93
+ */
94
+ const queryMediaTypes = Arr.dedupe(Arr.appendAll(resultsMediaTypes, rdfMediaTypes));
95
+ /**
96
+ * A query response body: a byte stream under any of `queryMediaTypes`.
97
+ *
98
+ * @since 0.1.0
99
+ * @category schemas
100
+ */
101
+ const QueryResponse = HttpApiSchema.StreamUint8Array({ contentType: queryMediaTypes });
102
+ /**
103
+ * An RDF document response body: a byte stream under any of `rdfMediaTypes`.
104
+ *
105
+ * @since 0.1.0
106
+ * @category schemas
107
+ */
108
+ const RdfResponse = HttpApiSchema.StreamUint8Array({ contentType: rdfMediaTypes });
109
+ const iris = Schema.optionalKey(Schema.Array(Schema.String));
110
+ /**
111
+ * The `Accept` request header, which selects the response format.
112
+ *
113
+ * @since 0.1.0
114
+ * @category schemas
115
+ */
116
+ const AcceptHeader = Schema.Struct({ accept: Schema.optionalKey(Schema.String) });
117
+ /**
118
+ * The query string of a query: the query and its protocol dataset.
119
+ *
120
+ * @since 0.1.0
121
+ * @category schemas
122
+ */
123
+ const QueryParams = Schema.Struct({
124
+ query: Schema.optionalKey(Schema.String),
125
+ "default-graph-uri": iris,
126
+ "named-graph-uri": iris
127
+ });
128
+ /**
129
+ * The query string of a `POST`: the protocol dataset of a query
130
+ * (`default-graph-uri` / `named-graph-uri`) or of an update
131
+ * (`using-graph-uri` / `using-named-graph-uri`).
132
+ *
133
+ * @since 0.1.0
134
+ * @category schemas
135
+ */
136
+ const DatasetParams = Schema.Struct({
137
+ "default-graph-uri": iris,
138
+ "named-graph-uri": iris,
139
+ "using-graph-uri": iris,
140
+ "using-named-graph-uri": iris
141
+ });
142
+ /**
143
+ * An `application/x-www-form-urlencoded` `POST` body holding a `query` or an
144
+ * `update` and its protocol dataset.
145
+ *
146
+ * @since 0.1.0
147
+ * @category schemas
148
+ */
149
+ const FormBody = Schema.Struct({
150
+ query: Schema.optionalKey(Schema.String),
151
+ update: Schema.optionalKey(Schema.String),
152
+ "default-graph-uri": iris,
153
+ "named-graph-uri": iris,
154
+ "using-graph-uri": iris,
155
+ "using-named-graph-uri": iris
156
+ }).pipe(HttpApiSchema.asFormUrlEncoded());
157
+ /**
158
+ * An `application/sparql-query` `POST` body, decoded as
159
+ * `{ _tag: 'DirectQuery', query }`.
160
+ *
161
+ * @since 0.1.0
162
+ * @category schemas
163
+ */
164
+ const DirectQueryBody = Schema.String.pipe(Schema.decodeTo(Schema.TaggedStruct("DirectQuery", { query: Schema.String }), SchemaTransformation.transform({
165
+ decode: (query) => ({
166
+ _tag: "DirectQuery",
167
+ query
168
+ }),
169
+ encode: (body) => body.query
170
+ })), HttpApiSchema.asText({ contentType: Protocol.SPARQL_QUERY }));
171
+ /**
172
+ * An `application/sparql-update` `POST` body, decoded as
173
+ * `{ _tag: 'DirectUpdate', update }`.
174
+ *
175
+ * @since 0.1.0
176
+ * @category schemas
177
+ */
178
+ const DirectUpdateBody = Schema.String.pipe(Schema.decodeTo(Schema.TaggedStruct("DirectUpdate", { update: Schema.String }), SchemaTransformation.transform({
179
+ decode: (update) => ({
180
+ _tag: "DirectUpdate",
181
+ update
182
+ }),
183
+ encode: (body) => body.update
184
+ })), HttpApiSchema.asText({ contentType: Protocol.SPARQL_UPDATE }));
185
+ const rdfDocument = (mediaType) => Schema.String.pipe(Schema.decodeTo(Schema.Struct({
186
+ mediaType: Schema.Literal(mediaType),
187
+ document: Schema.String
188
+ }), SchemaTransformation.transform({
189
+ decode: (document) => ({
190
+ mediaType,
191
+ document
192
+ }),
193
+ encode: (body) => body.document
194
+ })), HttpApiSchema.asText({ contentType: mediaType }));
195
+ /**
196
+ * Graph Store request bodies: an RDF document under one of `rdfMediaTypes`,
197
+ * decoded as `{ mediaType, document }` (the media type selects the request's
198
+ * `Content-Type`).
199
+ *
200
+ * @since 0.1.0
201
+ * @category schemas
202
+ */
203
+ const RdfDocumentBody = Arr.map(rdfMediaTypes, rdfDocument);
204
+ /**
205
+ * The query string of a Graph Store request: `graph=<iri>` (indirect
206
+ * identification) or `default` (the default graph).
207
+ *
208
+ * @since 0.1.0
209
+ * @category schemas
210
+ */
211
+ const GraphParams = Schema.Struct({
212
+ graph: Schema.optionalKey(Schema.String),
213
+ default: Schema.optionalKey(Schema.String)
214
+ });
215
+ /**
216
+ * The error response of a status: a `text/plain` message, decoded as an
217
+ * `ProtocolErrors.ProtocolError` with that status.
218
+ *
219
+ * @since 0.1.0
220
+ * @category schemas
221
+ */
222
+ const ProtocolErrorResponse = (status) => Schema.String.pipe(Schema.decodeTo(ProtocolErrors.ProtocolError.pipe(Schema.check(Schema.makeFilter((error) => error.status === status, {
223
+ identifier: `ProtocolError${status}`,
224
+ title: `ProtocolError (${status})`,
225
+ description: `A protocol error with status ${status}`
226
+ }))), SchemaTransformation.transform({
227
+ decode: (message) => ({
228
+ _tag: "ProtocolError",
229
+ status,
230
+ message: message.trimEnd()
231
+ }),
232
+ encode: (error) => `${error.message}\n`
233
+ })), HttpApiSchema.asText({ contentType: "text/plain" }), HttpApiSchema.status(status));
234
+ const BadRequest = ProtocolErrorResponse(400);
235
+ const Forbidden = ProtocolErrorResponse(403);
236
+ const NotFound = ProtocolErrorResponse(404);
237
+ const MethodNotAllowed = ProtocolErrorResponse(405);
238
+ const NotAcceptable = ProtocolErrorResponse(406);
239
+ const UnsupportedMediaType = ProtocolErrorResponse(415);
240
+ const InternalServerError = ProtocolErrorResponse(500);
241
+ const ServiceUnavailable = ProtocolErrorResponse(503);
242
+ /**
243
+ * Middleware on every endpoint that answers a request whose parameters or
244
+ * headers fail the API's schemas with the protocol handler instead of an
245
+ * empty `400` (see `SparqlApiBuilder.layerSchemaFallback`). It needs the
246
+ * server's services and nothing on the client side.
247
+ *
248
+ * @since 0.1.0
249
+ * @category middleware
250
+ */
251
+ var SchemaFallback = class extends HttpApiMiddleware.Service()("@thomasfosterau/effect-sparql-node/SparqlApi/SchemaFallback") {};
252
+ const sparqlGroup = (path) => HttpApiGroup.make("sparql").add(HttpApiEndpoint.get("query", path, {
253
+ query: QueryParams,
254
+ headers: AcceptHeader,
255
+ success: QueryResponse,
256
+ error: [
257
+ BadRequest,
258
+ NotAcceptable,
259
+ InternalServerError,
260
+ ServiceUnavailable
261
+ ]
262
+ }).annotateMerge(OpenApi.annotations({
263
+ summary: "Query, or read the service description",
264
+ description: "A SPARQL query in `query`, with its dataset in `default-graph-uri` / `named-graph-uri`. Without `query`, answers the service description. The response format is negotiated from `Accept`."
265
+ })), HttpApiEndpoint.post("post", path, {
266
+ query: DatasetParams,
267
+ headers: AcceptHeader,
268
+ payload: [
269
+ DirectQueryBody,
270
+ DirectUpdateBody,
271
+ FormBody
272
+ ],
273
+ success: [QueryResponse, HttpApiSchema.NoContent],
274
+ error: [
275
+ BadRequest,
276
+ Forbidden,
277
+ NotAcceptable,
278
+ UnsupportedMediaType,
279
+ InternalServerError,
280
+ ServiceUnavailable
281
+ ]
282
+ }).annotateMerge(OpenApi.annotations({
283
+ summary: "Query or update",
284
+ description: "A query (`200` with the results) or an update (`204`), as a form or as an `application/sparql-query` / `application/sparql-update` body. A read-only endpoint answers updates with `403`."
285
+ }))).annotateMerge(OpenApi.annotations({
286
+ title: "SPARQL",
287
+ description: "The SPARQL 1.1 Protocol"
288
+ }));
289
+ const writeErrors = [
290
+ BadRequest,
291
+ NotFound,
292
+ MethodNotAllowed,
293
+ UnsupportedMediaType,
294
+ InternalServerError
295
+ ];
296
+ const graphStoreGroup = (path) => HttpApiGroup.make("graphStore").add(HttpApiEndpoint.get("get", path, {
297
+ query: GraphParams,
298
+ headers: AcceptHeader,
299
+ success: RdfResponse,
300
+ error: [
301
+ BadRequest,
302
+ NotFound,
303
+ NotAcceptable,
304
+ InternalServerError
305
+ ]
306
+ }).annotateMerge(OpenApi.annotations({ summary: "Read a graph" })), HttpApiEndpoint.head("head", path, {
307
+ query: GraphParams,
308
+ headers: AcceptHeader,
309
+ success: HttpApiSchema.Empty(200),
310
+ error: [
311
+ BadRequest,
312
+ NotFound,
313
+ NotAcceptable,
314
+ InternalServerError
315
+ ]
316
+ }).annotateMerge(OpenApi.annotations({ summary: "Check that a graph exists" })), HttpApiEndpoint.put("put", path, {
317
+ query: GraphParams,
318
+ payload: RdfDocumentBody,
319
+ success: [HttpApiSchema.NoContent, HttpApiSchema.Created],
320
+ error: writeErrors
321
+ }).annotateMerge(OpenApi.annotations({
322
+ summary: "Replace a graph",
323
+ description: "`201` when the graph is new, `204` when it existed."
324
+ })), HttpApiEndpoint.post("post", path, {
325
+ query: GraphParams,
326
+ payload: RdfDocumentBody,
327
+ success: [HttpApiSchema.NoContent, HttpApiSchema.Created],
328
+ error: writeErrors
329
+ }).annotateMerge(OpenApi.annotations({
330
+ summary: "Add to a graph, or create one",
331
+ description: "Merges the document into the graph (`201` when it is new). Without `graph` or `default`, creates a new graph and answers `201` with its IRI in `Location`."
332
+ })), HttpApiEndpoint.delete("delete", path, {
333
+ query: GraphParams,
334
+ success: HttpApiSchema.NoContent,
335
+ error: [
336
+ BadRequest,
337
+ NotFound,
338
+ MethodNotAllowed,
339
+ InternalServerError
340
+ ]
341
+ }).annotateMerge(OpenApi.annotations({ summary: "Delete a graph" }))).annotateMerge(OpenApi.annotations({
342
+ title: "Graph Store",
343
+ description: "The SPARQL 1.1 Graph Store HTTP Protocol (indirect identification; URLs below the graph store identify graphs directly)"
344
+ }));
345
+ /**
346
+ * Builds the API at the given paths.
347
+ *
348
+ * @since 0.1.0
349
+ * @category constructors
350
+ */
351
+ const make = (paths) => HttpApi.make("effect-sparql-node").add(sparqlGroup(paths?.path ?? "/sparql")).add(graphStoreGroup(paths?.graphStorePath ?? "/rdf-graph-store")).middleware(SchemaFallback).annotateMerge(OpenApi.annotations({
352
+ title: "SPARQL 1.1 Protocol and Graph Store HTTP Protocol",
353
+ description: "Every response format is negotiated from `Accept`; methods an endpoint does not support are answered with `405` and `Allow`."
354
+ }));
355
+ /**
356
+ * The API at the default paths, `/sparql` and `/rdf-graph-store`.
357
+ *
358
+ * @since 0.1.0
359
+ * @category api
360
+ */
361
+ const SparqlApi = make();
362
+ /**
363
+ * The OpenAPI document of an API (the default one when omitted).
364
+ *
365
+ * @since 0.1.0
366
+ * @category openapi
367
+ */
368
+ const openApi = (api = SparqlApi) => OpenApi.fromApi(api);
369
+ export { queryMediaTypes as _, FormBody as a, QueryParams as c, RdfResponse as d, SchemaFallback as f, openApi as g, make as h, DirectUpdateBody as i, QueryResponse as l, SparqlApi_exports as m, DatasetParams as n, GraphParams as o, SparqlApi as p, DirectQueryBody as r, ProtocolErrorResponse as s, AcceptHeader as t, RdfDocumentBody as u, rdfMediaTypes as v, resultsMediaTypes as y };
370
+
371
+ //# sourceMappingURL=SparqlApi-BuycDkWu.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SparqlApi-BuycDkWu.mjs","names":[],"sources":["../src/SparqlApi.ts"],"sourcesContent":["/**\n * The SPARQL 1.1 Protocol and Graph Store HTTP Protocol as an Effect\n * `HttpApi` definition: the endpoints, their parameters, request media types,\n * response media types and error statuses, shared by the server\n * (`SparqlApiBuilder`), the derived client\n * (`SparqlApiClient`) and the OpenAPI document\n * (`openApi`).\n *\n * The API has two groups:\n *\n * - `sparql`: `query` (`GET` with `?query=`, or without it for the service\n * description) and `post` (`POST` with an\n * `application/x-www-form-urlencoded`, `application/sparql-query` or\n * `application/sparql-update` body);\n * - `graphStore`: `get`, `head`, `put`, `post` and `delete` on the graph store\n * with `?graph=<iri>` or `?default`, with RDF bodies under every media type\n * of the default `Formats`.\n *\n * Content negotiation (`Accept`) and `405 Method Not Allowed` are not part of\n * the definition: the server's handlers negotiate with the same code as\n * `SparqlServer`, and `SparqlApiBuilder` answers the methods the API does not\n * declare. A request whose parameters the API's schemas reject (a repeated\n * `query` or `graph`, say) is handed to the protocol handler too, by the\n * `SchemaFallback` middleware, so it gets the protocol's own `400` and\n * message. Error bodies are `text/plain` messages decoded into\n * `ProtocolErrors.ProtocolError`.\n *\n * This module only describes the API, so a client can import it without the\n * server. `effect/http-api` is `@stability unstable` in Effect 4, and this\n * definition follows it.\n *\n * @since 0.1.0\n */\nimport * as Arr from 'effect/Array';\nimport * as Schema from 'effect/Schema';\nimport * as SchemaTransformation from 'effect/SchemaTransformation';\nimport * as HttpApi from 'effect/http-api/HttpApi';\nimport * as HttpApiEndpoint from 'effect/http-api/HttpApiEndpoint';\nimport * as HttpApiGroup from 'effect/http-api/HttpApiGroup';\nimport * as HttpApiMiddleware from 'effect/http-api/HttpApiMiddleware';\nimport * as HttpApiSchema from 'effect/http-api/HttpApiSchema';\nimport * as OpenApi from 'effect/http-api/OpenApi';\nimport type * as Serialization from '@thomasfosterau/effect-rdf/Serialization';\nimport type * as Engine from '@thomasfosterau/effect-rdf/sparql/Engine';\nimport * as Results from '@thomasfosterau/effect-rdf/sparql/Results';\nimport type * as Store from '@thomasfosterau/effect-rdf/sparql/Store';\nimport * as ProtocolErrors from '@thomasfosterau/effect-rdf/sparql/ProtocolErrors';\nimport * as ServerFormats from '@thomasfosterau/effect-rdf/sparql/ServerFormats';\nimport * as Protocol from '@thomasfosterau/effect-rdf/sparql/Protocol';\n\n// -----------------------------------------------------------------------------\n// Media types\n// -----------------------------------------------------------------------------\n\n/**\n * The media types of the default RDF formats (`ServerFormats.codecs`), in order of\n * preference: Graph Store bodies and `CONSTRUCT` / `DESCRIBE` / service\n * description responses.\n *\n * @since 0.1.0\n * @category media types\n */\nexport const rdfMediaTypes: ReadonlyArray<string> = Arr.dedupe(\n Arr.flatMap(ServerFormats.codecs, (codec) => codec.format.mediaTypes),\n);\n\n/**\n * The media types of SPARQL results (`Results.codecs`): JSON, XML, CSV and\n * TSV, in order of preference.\n *\n * @since 0.1.0\n * @category media types\n */\nexport const resultsMediaTypes: ReadonlyArray<string> = Arr.dedupe(\n Arr.flatMap(Results.codecs, (codec) => codec.format.mediaTypes),\n);\n\n/**\n * Every media type a query response can have: the results formats for\n * `SELECT` / `ASK`, then the RDF formats for `CONSTRUCT` / `DESCRIBE` and the\n * service description.\n *\n * @since 0.1.0\n * @category media types\n */\nexport const queryMediaTypes: ReadonlyArray<string> = Arr.dedupe(\n Arr.appendAll(resultsMediaTypes, rdfMediaTypes),\n);\n\n// -----------------------------------------------------------------------------\n// Schemas\n// -----------------------------------------------------------------------------\n\n/**\n * A query response body: a byte stream under any of `queryMediaTypes`.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport const QueryResponse: HttpApiSchema.StreamUint8Array = HttpApiSchema.StreamUint8Array({\n contentType: queryMediaTypes,\n});\n\n/**\n * An RDF document response body: a byte stream under any of `rdfMediaTypes`.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport const RdfResponse: HttpApiSchema.StreamUint8Array = HttpApiSchema.StreamUint8Array({\n contentType: rdfMediaTypes,\n});\n\nconst iris = Schema.optionalKey(Schema.Array(Schema.String));\n\n/**\n * The `Accept` request header, which selects the response format.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport const AcceptHeader = Schema.Struct({ accept: Schema.optionalKey(Schema.String) });\n\n/**\n * The decoded type of `AcceptHeader`.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport type AcceptHeader = typeof AcceptHeader.Type;\n\n/**\n * The query string of a query: the query and its protocol dataset.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport const QueryParams = Schema.Struct({\n query: Schema.optionalKey(Schema.String),\n 'default-graph-uri': iris,\n 'named-graph-uri': iris,\n});\n\n/**\n * The decoded type of `QueryParams`.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport type QueryParams = typeof QueryParams.Type;\n\n/**\n * The query string of a `POST`: the protocol dataset of a query\n * (`default-graph-uri` / `named-graph-uri`) or of an update\n * (`using-graph-uri` / `using-named-graph-uri`).\n *\n * @since 0.1.0\n * @category schemas\n */\nexport const DatasetParams = Schema.Struct({\n 'default-graph-uri': iris,\n 'named-graph-uri': iris,\n 'using-graph-uri': iris,\n 'using-named-graph-uri': iris,\n});\n\n/**\n * The decoded type of `DatasetParams`.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport type DatasetParams = typeof DatasetParams.Type;\n\n/**\n * An `application/x-www-form-urlencoded` `POST` body holding a `query` or an\n * `update` and its protocol dataset.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport const FormBody = Schema.Struct({\n query: Schema.optionalKey(Schema.String),\n update: Schema.optionalKey(Schema.String),\n 'default-graph-uri': iris,\n 'named-graph-uri': iris,\n 'using-graph-uri': iris,\n 'using-named-graph-uri': iris,\n}).pipe(HttpApiSchema.asFormUrlEncoded());\n\n/**\n * The decoded type of `FormBody`.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport type FormBody = typeof FormBody.Type;\n\n/**\n * An `application/sparql-query` `POST` body, decoded as\n * `{ _tag: 'DirectQuery', query }`.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport const DirectQueryBody = Schema.String.pipe(\n Schema.decodeTo(\n Schema.TaggedStruct('DirectQuery', { query: Schema.String }),\n SchemaTransformation.transform({\n decode: (query) => ({ _tag: 'DirectQuery' as const, query }),\n encode: (body) => body.query,\n }),\n ),\n HttpApiSchema.asText({ contentType: Protocol.SPARQL_QUERY }),\n);\n\n/**\n * The decoded type of `DirectQueryBody`.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport type DirectQueryBody = typeof DirectQueryBody.Type;\n\n/**\n * An `application/sparql-update` `POST` body, decoded as\n * `{ _tag: 'DirectUpdate', update }`.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport const DirectUpdateBody = Schema.String.pipe(\n Schema.decodeTo(\n Schema.TaggedStruct('DirectUpdate', { update: Schema.String }),\n SchemaTransformation.transform({\n decode: (update) => ({ _tag: 'DirectUpdate' as const, update }),\n encode: (body) => body.update,\n }),\n ),\n HttpApiSchema.asText({ contentType: Protocol.SPARQL_UPDATE }),\n);\n\n/**\n * The decoded type of `DirectUpdateBody`.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport type DirectUpdateBody = typeof DirectUpdateBody.Type;\n\nconst rdfDocument = (mediaType: string) =>\n Schema.String.pipe(\n Schema.decodeTo(\n Schema.Struct({ mediaType: Schema.Literal(mediaType), document: Schema.String }),\n SchemaTransformation.transform({\n decode: (document) => ({ mediaType, document }),\n encode: (body) => body.document,\n }),\n ),\n HttpApiSchema.asText({ contentType: mediaType }),\n );\n\n/**\n * Graph Store request bodies: an RDF document under one of `rdfMediaTypes`,\n * decoded as `{ mediaType, document }` (the media type selects the request's\n * `Content-Type`).\n *\n * @since 0.1.0\n * @category schemas\n */\nexport const RdfDocumentBody = Arr.map(rdfMediaTypes, rdfDocument);\n\n/**\n * The query string of a Graph Store request: `graph=<iri>` (indirect\n * identification) or `default` (the default graph).\n *\n * @since 0.1.0\n * @category schemas\n */\nexport const GraphParams = Schema.Struct({\n graph: Schema.optionalKey(Schema.String),\n default: Schema.optionalKey(Schema.String),\n});\n\n/**\n * The decoded type of `GraphParams`.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport type GraphParams = typeof GraphParams.Type;\n\n/**\n * The error response of a status: a `text/plain` message, decoded as an\n * `ProtocolErrors.ProtocolError` with that status.\n *\n * @since 0.1.0\n * @category schemas\n */\nexport const ProtocolErrorResponse = (status: number) =>\n Schema.String.pipe(\n Schema.decodeTo(\n ProtocolErrors.ProtocolError.pipe(\n Schema.check(\n Schema.makeFilter((error: ProtocolErrors.ProtocolError) => error.status === status, {\n identifier: `ProtocolError${status}`,\n title: `ProtocolError (${status})`,\n description: `A protocol error with status ${status}`,\n }),\n ),\n ),\n SchemaTransformation.transform({\n decode: (message) => ({\n _tag: 'ProtocolError' as const,\n status,\n message: message.trimEnd(),\n }),\n encode: (error) => `${error.message}\\n`,\n }),\n ),\n HttpApiSchema.asText({ contentType: 'text/plain' }),\n HttpApiSchema.status(status),\n );\n\nconst BadRequest = ProtocolErrorResponse(400);\nconst Forbidden = ProtocolErrorResponse(403);\nconst NotFound = ProtocolErrorResponse(404);\nconst MethodNotAllowed = ProtocolErrorResponse(405);\nconst NotAcceptable = ProtocolErrorResponse(406);\nconst UnsupportedMediaType = ProtocolErrorResponse(415);\nconst InternalServerError = ProtocolErrorResponse(500);\nconst ServiceUnavailable = ProtocolErrorResponse(503);\n\n// -----------------------------------------------------------------------------\n// The API\n// -----------------------------------------------------------------------------\n\n/**\n * Middleware on every endpoint that answers a request whose parameters or\n * headers fail the API's schemas with the protocol handler instead of an\n * empty `400` (see `SparqlApiBuilder.layerSchemaFallback`). It needs the\n * server's services and nothing on the client side.\n *\n * @since 0.1.0\n * @category middleware\n */\nexport class SchemaFallback extends HttpApiMiddleware.Service<\n SchemaFallback,\n { requires: Engine.SparqlEngine | Store.QuadStore | Serialization.Formats }\n>()('@thomasfosterau/effect-sparql-node/SparqlApi/SchemaFallback') {}\n\n/**\n * The paths an API is served at.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface Paths {\n /** The SPARQL endpoint, for queries and updates (default `/sparql`). */\n readonly path?: `/${string}` | undefined;\n /** The Graph Store endpoint (default `/rdf-graph-store`). */\n readonly graphStorePath?: `/${string}` | undefined;\n}\n\nconst sparqlGroup = (path: `/${string}`) =>\n HttpApiGroup.make('sparql')\n .add(\n HttpApiEndpoint.get('query', path, {\n query: QueryParams,\n headers: AcceptHeader,\n success: QueryResponse,\n error: [BadRequest, NotAcceptable, InternalServerError, ServiceUnavailable],\n }).annotateMerge(\n OpenApi.annotations({\n summary: 'Query, or read the service description',\n description:\n 'A SPARQL query in `query`, with its dataset in `default-graph-uri` / `named-graph-uri`. Without `query`, answers the service description. The response format is negotiated from `Accept`.',\n }),\n ),\n HttpApiEndpoint.post('post', path, {\n query: DatasetParams,\n headers: AcceptHeader,\n payload: [DirectQueryBody, DirectUpdateBody, FormBody],\n success: [QueryResponse, HttpApiSchema.NoContent],\n error: [\n BadRequest,\n Forbidden,\n NotAcceptable,\n UnsupportedMediaType,\n InternalServerError,\n ServiceUnavailable,\n ],\n }).annotateMerge(\n OpenApi.annotations({\n summary: 'Query or update',\n description:\n 'A query (`200` with the results) or an update (`204`), as a form or as an `application/sparql-query` / `application/sparql-update` body. A read-only endpoint answers updates with `403`.',\n }),\n ),\n )\n .annotateMerge(\n OpenApi.annotations({ title: 'SPARQL', description: 'The SPARQL 1.1 Protocol' }),\n );\n\nconst writeErrors = [\n BadRequest,\n NotFound,\n MethodNotAllowed,\n UnsupportedMediaType,\n InternalServerError,\n] as const;\n\nconst graphStoreGroup = (path: `/${string}`) =>\n HttpApiGroup.make('graphStore')\n .add(\n HttpApiEndpoint.get('get', path, {\n query: GraphParams,\n headers: AcceptHeader,\n success: RdfResponse,\n error: [BadRequest, NotFound, NotAcceptable, InternalServerError],\n }).annotateMerge(OpenApi.annotations({ summary: 'Read a graph' })),\n HttpApiEndpoint.head('head', path, {\n query: GraphParams,\n headers: AcceptHeader,\n success: HttpApiSchema.Empty(200),\n error: [BadRequest, NotFound, NotAcceptable, InternalServerError],\n }).annotateMerge(OpenApi.annotations({ summary: 'Check that a graph exists' })),\n HttpApiEndpoint.put('put', path, {\n query: GraphParams,\n payload: RdfDocumentBody,\n success: [HttpApiSchema.NoContent, HttpApiSchema.Created],\n error: writeErrors,\n }).annotateMerge(\n OpenApi.annotations({\n summary: 'Replace a graph',\n description: '`201` when the graph is new, `204` when it existed.',\n }),\n ),\n HttpApiEndpoint.post('post', path, {\n query: GraphParams,\n payload: RdfDocumentBody,\n success: [HttpApiSchema.NoContent, HttpApiSchema.Created],\n error: writeErrors,\n }).annotateMerge(\n OpenApi.annotations({\n summary: 'Add to a graph, or create one',\n description:\n 'Merges the document into the graph (`201` when it is new). Without `graph` or `default`, creates a new graph and answers `201` with its IRI in `Location`.',\n }),\n ),\n HttpApiEndpoint.delete('delete', path, {\n query: GraphParams,\n success: HttpApiSchema.NoContent,\n error: [BadRequest, NotFound, MethodNotAllowed, InternalServerError],\n }).annotateMerge(OpenApi.annotations({ summary: 'Delete a graph' })),\n )\n .annotateMerge(\n OpenApi.annotations({\n title: 'Graph Store',\n description:\n 'The SPARQL 1.1 Graph Store HTTP Protocol (indirect identification; URLs below the graph store identify graphs directly)',\n }),\n );\n\n/**\n * Builds the API at the given paths.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport const make = (paths?: Paths) =>\n HttpApi.make('effect-sparql-node')\n .add(sparqlGroup(paths?.path ?? '/sparql'))\n .add(graphStoreGroup(paths?.graphStorePath ?? '/rdf-graph-store'))\n .middleware(SchemaFallback)\n .annotateMerge(\n OpenApi.annotations({\n title: 'SPARQL 1.1 Protocol and Graph Store HTTP Protocol',\n description:\n 'Every response format is negotiated from `Accept`; methods an endpoint does not support are answered with `405` and `Allow`.',\n }),\n );\n\n/**\n * The type of an API built by `make`.\n *\n * @since 0.1.0\n * @category models\n */\nexport type Api = ReturnType<typeof make>;\n\n/**\n * The API at the default paths, `/sparql` and `/rdf-graph-store`.\n *\n * @since 0.1.0\n * @category api\n */\nexport const SparqlApi: Api = make();\n\n/**\n * The OpenAPI document of an API (the default one when omitted).\n *\n * @since 0.1.0\n * @category openapi\n */\nexport const openApi = (api: Api = SparqlApi): OpenApi.OpenAPISpec => OpenApi.fromApi(api);\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { _ as make, a as DirectUpdateBody, b as rdfMediaTypes, c as Paths, d as QueryResponse, f as RdfDocumentBody, h as SparqlApi, i as DirectQueryBody, l as ProtocolErrorResponse, m as SchemaFallback, n as Api, o as FormBody, p as RdfResponse, r as DatasetParams, s as GraphParams, t as AcceptHeader, u as QueryParams, v as openApi, x as resultsMediaTypes, y as queryMediaTypes } from "./SparqlApi-BKE9nIf4.mjs";
2
+ export { AcceptHeader, Api, DatasetParams, DirectQueryBody, DirectUpdateBody, FormBody, GraphParams, Paths, ProtocolErrorResponse, QueryParams, QueryResponse, RdfDocumentBody, RdfResponse, SchemaFallback, SparqlApi, make, openApi, queryMediaTypes, rdfMediaTypes, resultsMediaTypes };
@@ -0,0 +1 @@
1
+ export { t as AcceptHeader, n as DatasetParams, r as DirectQueryBody, i as DirectUpdateBody, a as FormBody, o as GraphParams, s as ProtocolErrorResponse, c as QueryParams, l as QueryResponse, u as RdfDocumentBody, d as RdfResponse, f as SchemaFallback, p as SparqlApi, h as make, g as openApi, _ as queryMediaTypes, v as rdfMediaTypes, y as resultsMediaTypes } from "./SparqlApi-BuycDkWu.mjs";
@@ -0,0 +1,83 @@
1
+ import { c as Paths, m as SchemaFallback } from "./SparqlApi-BKE9nIf4.mjs";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Layer from "effect/Layer";
4
+ import * as SparqlServer from "@thomasfosterau/effect-rdf/sparql/SparqlServer";
5
+ import * as HttpApiMiddleware from "effect/http-api/HttpApiMiddleware";
6
+ import * as Scope from "effect/Scope";
7
+ import * as HttpRouter from "effect/http/HttpRouter";
8
+ import * as HttpServer from "effect/http/HttpServer";
9
+ import * as Options from "@thomasfosterau/effect-rdf/sparql/Options";
10
+ import * as HttpClient from "effect/http/HttpClient";
11
+ declare namespace SparqlApiBuilder_d_exports {
12
+ export { ApiOptions, layerFallback, layerHandlers, layerRoutes, layerSchemaFallback, layerServe, makeTestClient };
13
+ }
14
+ /**
15
+ * Options of the API server: the server options, with the endpoint paths of
16
+ * the API (the update endpoint is the query endpoint) and where to serve the
17
+ * OpenAPI document.
18
+ *
19
+ * @since 0.1.0
20
+ * @category models
21
+ */
22
+ interface ApiOptions extends Omit<Options.Options, 'path' | 'updatePath' | 'graphStorePath'>, Paths {
23
+ /** Serves the OpenAPI document (`SparqlApi.openApi`) as JSON at this path. */
24
+ readonly openapiPath?: `/${string}` | undefined;
25
+ }
26
+ /**
27
+ * The handlers of both API groups (`sparql` and `graphStore`) for the API at
28
+ * the options' paths, using the server's services from the context.
29
+ *
30
+ * @since 0.1.0
31
+ * @category layers
32
+ */
33
+ declare const layerHandlers: (options?: ApiOptions) => Layer.Layer<import("effect/http-api/HttpApiGroup").Service<"effect-sparql-node", "sparql"> | import("effect/http-api/HttpApiGroup").Service<"effect-sparql-node", "graphStore">, never, HttpRouter.Request<"Requires", import("@thomasfosterau/effect-rdf/sparql/Engine").SparqlEngine> | (SchemaFallback | HttpApiMiddleware.ApplyServices<SchemaFallback, never> | HttpRouter.Request<"Requires", import("@thomasfosterau/effect-rdf/sparql/Store").QuadStore> | HttpRouter.Request<"Requires", import("@thomasfosterau/effect-rdf/Serialization").Formats>)>;
34
+ /**
35
+ * The `SparqlApi.SchemaFallback` middleware: a request whose parameters or
36
+ * headers fail the API's schemas is answered by `SparqlServer.handler`, so
37
+ * it gets the protocol's own status and message (e.g. `400` "Exactly one
38
+ * 'query' parameter is allowed"). Response encoding failures stay `500`.
39
+ *
40
+ * @since 0.1.0
41
+ * @category layers
42
+ */
43
+ declare const layerSchemaFallback: (options?: ApiOptions) => Layer.Layer<SchemaFallback>;
44
+ /**
45
+ * The fallback routes: every method on `<path>*` and `<graphStorePath>*`
46
+ * that the API does not declare, answered by `SparqlServer.handler` (`405`
47
+ * with `Allow`, CORS preflights, direct graph identification, `404` for
48
+ * other paths).
49
+ *
50
+ * @since 0.1.0
51
+ * @category layers
52
+ */
53
+ declare const layerFallback: (options?: ApiOptions) => Layer.Layer<never, never, HttpRouter.HttpRouter | HttpRouter.Request.From<"Requires", SparqlServer.Requirements>>;
54
+ /**
55
+ * Registers the API on the `HttpRouter`: the `HttpApiBuilder` routes with
56
+ * their handlers and the `SchemaFallback` middleware, the fallback routes and, with `openapiPath`, the OpenAPI
57
+ * document.
58
+ *
59
+ * @since 0.1.0
60
+ * @category layers
61
+ */
62
+ declare const layerRoutes: (options?: ApiOptions) => Layer.Layer<never, never, HttpApiMiddleware.ApplyServices<SchemaFallback, never> | HttpRouter.Request<"Requires", import("@thomasfosterau/effect-rdf/sparql/Engine").SparqlEngine> | HttpRouter.Request<"Requires", import("@thomasfosterau/effect-rdf/sparql/Store").QuadStore> | HttpRouter.Request<"Requires", import("@thomasfosterau/effect-rdf/Serialization").Formats> | HttpRouter.HttpRouter | import("effect/http/Etag").Generator | import("effect/FileSystem").FileSystem | import("effect/http/HttpPlatform").HttpPlatform | import("effect/Path").Path>;
63
+ /**
64
+ * Serves the API routes with `HttpRouter.serve` on an `HttpServer` from the
65
+ * context (logging requests unless `logging: false`); the server layer (such
66
+ * as `NodeHttpServer.layer`) also provides the platform services
67
+ * `HttpApiBuilder` needs.
68
+ *
69
+ * @since 0.1.0
70
+ * @category layers
71
+ */
72
+ declare const layerServe: (options?: ApiOptions) => Layer.Layer<never, never, HttpApiMiddleware.ApplyServices<SchemaFallback, never> | import("effect/http/Etag").Generator | import("effect/FileSystem").FileSystem | import("effect/http/HttpPlatform").HttpPlatform | import("effect/Path").Path | HttpServer.HttpServer>;
73
+ /**
74
+ * In-process testing: builds a client for the `SparqlApi` routes
75
+ * (`layerRoutes(options)`) using the server's services from
76
+ * the context. The routes live as long as the surrounding scope.
77
+ *
78
+ * @since 0.1.0
79
+ * @category constructors
80
+ */
81
+ declare const makeTestClient: (options?: ApiOptions) => Effect.Effect<HttpClient.HttpClient, never, SparqlServer.Requirements | Scope.Scope>;
82
+ export { layerRoutes as a, makeTestClient as c, layerHandlers as i, SparqlApiBuilder_d_exports as n, layerSchemaFallback as o, layerFallback as r, layerServe as s, ApiOptions as t };
83
+ //# sourceMappingURL=SparqlApiBuilder-BAMpMy-Z.d.mts.map
@@ -0,0 +1,136 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D8jQpDG7.mjs";
2
+ import { f as SchemaFallback, h as make } from "./SparqlApi-BuycDkWu.mjs";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Layer from "effect/Layer";
5
+ import * as SparqlServer from "@thomasfosterau/effect-rdf/sparql/SparqlServer";
6
+ import * as HttpApiMiddleware from "effect/http-api/HttpApiMiddleware";
7
+ import * as Scope from "effect/Scope";
8
+ import * as HttpRouter from "effect/http/HttpRouter";
9
+ import * as HttpServer from "effect/http/HttpServer";
10
+ import * as HttpServerError from "effect/http/HttpServerError";
11
+ import * as HttpApiBuilder from "effect/http-api/HttpApiBuilder";
12
+ import * as Testing from "@thomasfosterau/effect-rdf/sparql/Testing";
13
+ // src/SparqlApiBuilder.ts
14
+ /**
15
+ * Serves the `SparqlApi` definition with `HttpApiBuilder`.
16
+ *
17
+ * Every endpoint is implemented with a raw handler (`handleRaw`) that runs
18
+ * the same code as `SparqlServer`: the request body, `Accept` and
19
+ * `Content-Type` are read by the protocol internals, so responses, statuses
20
+ * and error messages are those of `SparqlServer.handler`. Routes the API does
21
+ * not declare (other methods on the endpoints, which get `405` with
22
+ * `Allow`; `OPTIONS` preflights when CORS is on; graphs identified directly
23
+ * by a URL below the graph store) are registered as plain `HttpRouter`
24
+ * fallback routes to `SparqlServer.handler`.
25
+ *
26
+ * `effect/http-api` is `@stability unstable` in Effect 4.
27
+ *
28
+ * @since 0.1.0
29
+ */
30
+ var SparqlApiBuilder_exports = /* @__PURE__ */ __exportAll({
31
+ layerFallback: () => layerFallback,
32
+ layerHandlers: () => layerHandlers,
33
+ layerRoutes: () => layerRoutes,
34
+ layerSchemaFallback: () => layerSchemaFallback,
35
+ layerServe: () => layerServe,
36
+ makeTestClient: () => makeTestClient
37
+ });
38
+ const serverOptions = (options) => {
39
+ const path = options?.path ?? "/sparql";
40
+ return {
41
+ ...options,
42
+ path,
43
+ updatePath: path,
44
+ graphStorePath: options?.graphStorePath ?? "/rdf-graph-store"
45
+ };
46
+ };
47
+ const handlersFor = (api, options) => {
48
+ const sparql = SparqlServer.sparqlHandler(options);
49
+ const graphStore = SparqlServer.graphStoreHandler(options);
50
+ return Layer.mergeAll(HttpApiBuilder.group(api, "sparql", (handlers) => handlers.handleRaw("query", () => sparql).handleRaw("post", () => sparql)), HttpApiBuilder.group(api, "graphStore", (handlers) => handlers.handleRaw("get", () => graphStore).handleRaw("head", () => graphStore).handleRaw("put", () => graphStore).handleRaw("post", () => graphStore).handleRaw("delete", () => graphStore)));
51
+ };
52
+ /**
53
+ * The handlers of both API groups (`sparql` and `graphStore`) for the API at
54
+ * the options' paths, using the server's services from the context.
55
+ *
56
+ * @since 0.1.0
57
+ * @category layers
58
+ */
59
+ const layerHandlers = (options) => {
60
+ const resolved = serverOptions(options);
61
+ return handlersFor(make(resolved), resolved);
62
+ };
63
+ /**
64
+ * The `SparqlApi.SchemaFallback` middleware: a request whose parameters or
65
+ * headers fail the API's schemas is answered by `SparqlServer.handler`, so
66
+ * it gets the protocol's own status and message (e.g. `400` "Exactly one
67
+ * 'query' parameter is allowed"). Response encoding failures stay `500`.
68
+ *
69
+ * @since 0.1.0
70
+ * @category layers
71
+ */
72
+ const layerSchemaFallback = (options) => {
73
+ const app = SparqlServer.handler(serverOptions(options));
74
+ return HttpApiMiddleware.layerSchemaErrorTransform(SchemaFallback, (error) => error.kind === "Body" || error.kind === "ResponseHeaders" ? Effect.fail(error) : app);
75
+ };
76
+ /**
77
+ * The fallback routes: every method on `<path>*` and `<graphStorePath>*`
78
+ * that the API does not declare, answered by `SparqlServer.handler` (`405`
79
+ * with `Allow`, CORS preflights, direct graph identification, `404` for
80
+ * other paths).
81
+ *
82
+ * @since 0.1.0
83
+ * @category layers
84
+ */
85
+ const layerFallback = (options) => {
86
+ const resolved = serverOptions(options);
87
+ const app = SparqlServer.handler(resolved);
88
+ return HttpRouter.use((router) => Effect.gen(function* () {
89
+ yield* router.add("*", `${resolved.path}*`, app);
90
+ yield* router.add("*", `${resolved.graphStorePath}*`, app);
91
+ }));
92
+ };
93
+ /**
94
+ * Registers the API on the `HttpRouter`: the `HttpApiBuilder` routes with
95
+ * their handlers and the `SchemaFallback` middleware, the fallback routes and, with `openapiPath`, the OpenAPI
96
+ * document.
97
+ *
98
+ * @since 0.1.0
99
+ * @category layers
100
+ */
101
+ const layerRoutes = (options) => {
102
+ const resolved = serverOptions(options);
103
+ const api = make(resolved);
104
+ const schemaFallback = layerSchemaFallback(options);
105
+ return Layer.mergeAll(HttpApiBuilder.layer(api, { openapiPath: options?.openapiPath }).pipe(Layer.provide(handlersFor(api, resolved).pipe(Layer.provide(schemaFallback)))), layerFallback(options));
106
+ };
107
+ /**
108
+ * Serves the API routes with `HttpRouter.serve` on an `HttpServer` from the
109
+ * context (logging requests unless `logging: false`); the server layer (such
110
+ * as `NodeHttpServer.layer`) also provides the platform services
111
+ * `HttpApiBuilder` needs.
112
+ *
113
+ * @since 0.1.0
114
+ * @category layers
115
+ */
116
+ const layerServe = (options) => HttpRouter.serve(layerRoutes({
117
+ ...options,
118
+ logging: false
119
+ }), { disableLogger: options?.logging === false });
120
+ /**
121
+ * In-process testing: builds a client for the `SparqlApi` routes
122
+ * (`layerRoutes(options)`) using the server's services from
123
+ * the context. The routes live as long as the surrounding scope.
124
+ *
125
+ * @since 0.1.0
126
+ * @category constructors
127
+ */
128
+ const makeTestClient = (options) => Effect.gen(function* () {
129
+ const scope = yield* Scope.Scope;
130
+ const context = yield* Effect.context();
131
+ const app = yield* HttpRouter.toHttpEffect(layerRoutes(options).pipe(Layer.provide(HttpServer.layerServices)));
132
+ return Testing.fromApp(app.pipe(Effect.catchCause((cause) => Effect.map(HttpServerError.causeResponse(cause), ([response]) => response)), Effect.provideService(Scope.Scope, scope), Effect.provideContext(context)));
133
+ });
134
+ export { layerSchemaFallback as a, layerRoutes as i, layerFallback as n, layerServe as o, layerHandlers as r, makeTestClient as s, SparqlApiBuilder_exports as t };
135
+
136
+ //# sourceMappingURL=SparqlApiBuilder-GT7EopBq.mjs.map