From 92d4f0319d2766124a8bfdce019be5412d9e8682 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Fri, 26 Jun 2026 10:20:54 -0400 Subject: [PATCH 01/22] Replace GET/POST with new HTTP QUERY RFC10008 --- lws10-searchindex/index.html | 258 +++++++++++++++++++---------------- 1 file changed, 143 insertions(+), 115 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 89ef9d6..3fd46a9 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -31,6 +31,14 @@ publisher: "W3C", status: "FPWD", }, + "RFC10008": { + title: "The HTTP QUERY Method", + href: "https://www.rfc-editor.org/rfc/rfc10008", + authors: ["J. Reschke", "J. M. Snell", "M. Bishop"], + publisher: "IETF", + status: "Proposed Standard", + date: "June 2026", + }, }, }; @@ -148,7 +156,7 @@

Discovery

The storage description advertises only the service endpoints. In particular, the set of additional indexed relations a server supports is deliberately not - enumerated there or anywhere else; see . + enumerated there or anywhere else; see .

@@ -212,6 +220,11 @@

GET [TypeIndexService]

are opaque to the client. The body lists the unique types of resources that currently exist within the storage and that the authenticated user is authorized to see. This endpoint accepts no query parameters.

+

+ The Type Index takes no filter, so it is retrieved with a GET. The + Type Search Service, which carries a filter, instead uses the HTTP + QUERY method [[!RFC10008]] (see ). +

 HTTP/1.1 200 OK
 Content-Type: application/lws+json
@@ -242,39 +255,62 @@ 

Type Search Service

indexed relations.

-
-

GET [TypeSearchService]

+
+

QUERY [TypeSearchService]

- The type query parameter is OPTIONAL and selects resources by their - rdf:type (as declared via rel="type" Link headers, - server-intrinsic classes, or content; see ). + A client searches by sending an HTTP QUERY request [[!RFC10008]] to the + service endpoint, carrying the filter in the request body as + application/lws+json. The request MUST include a Content-Type of + application/lws+json; per [[!RFC10008]] a server fails the request if the + Content-Type is missing or inconsistent with the body (see + ). Because QUERY is both safe and idempotent + [[!RFC10008]], a search never alters server state and MAY be repeated, retried, or cached. + Because the filter travels in the body rather than the request URI, it is not subject to the + request-URI length limits that constrain a query string.

+ +
+{
+  "@context": "https://www.w3.org/ns/lws/v1",
+  "type": [
+    ["https://schema.org/Person", "http://xmlns.com/foaf/0.1/Person"],
+    "https://www.w3.org/ns/lws#DataResource"
+  ]
+}
+        
+

- A single type parameter MAY carry a comma-separated list of URIs, combined with - logical OR — a resource matches the group if it declares any of the - listed types. Repeating the type parameter combines the groups with logical - AND. The filter is therefore a conjunction of disjunctions: - ?type=A,B&type=C selects resources matching (A OR B) AND C. A - request with no type parameter matches all resources visible to the client. + The type key is OPTIONAL and selects resources by their rdf:type + (as declared via rel="type" Link headers, server-intrinsic + classes, or content; see ). Its value is an array whose + elements are combined with logical AND; each element is either a single + type URI or an array of type URIs combined with logical OR. The example + above selects resources matching + (schema:Person OR foaf:Person) AND lws:DataResource — the filter is a + conjunction of disjunctions, that is, conjunctive normal form. A request whose body has no + type key and no relation keys (or only empty groups) matches all resources + visible to the client.

- This conjunctive-normal-form filter is the complete query expressiveness of the service. - Servers MAY support nesting, negation, comparison, ordering, or text - matching. A type URI that matches no resource yields no results and MUST NOT be treated as an - error; empty or duplicate groups MUST be ignored. + This conjunctive-normal-form filter is the complete query expressiveness the service is + required to provide. A server MAY support nesting, negation, comparison, ordering, or text + matching, but a portable client MUST NOT rely on any of these. A type URI that matches no + resource yields no results and MUST NOT be treated as an error; empty or duplicate groups + MUST be ignored.

- The type parameter is the mandatory baseline and MUST be supported by every server that implements the - TypeSearchService. A server MAY additionally index other descriptive link - relations. Such a relation is filtered by using the relation itself as the query-parameter name - — a registered relation name per [[!RFC8288]] or, for an - extension relation, its URI — with exactly the same conjunctive-normal-form semantics as - type (comma = OR group, repeated parameter = AND group, target values matched against - the link targets the resource declares for that relation). Groups belonging to different relations - are combined with logical AND. Relation targets are derived by the server in the same way as types - (HTTP Link headers, server-intrinsic state, or parsed content) and all sources MUST be - treated identically. + The type key is the mandatory baseline and MUST be supported by every server + that implements the TypeSearchService. A server MAY additionally index other + descriptive link relations. Such a relation is filtered by using the relation + itself as a key alongside type — a registered relation name per + [[!RFC8288]] or, for an extension relation, its URI — with exactly the same + conjunctive-normal-form semantics as type (a nested array is an OR group, + sibling array elements form AND groups, target values matched against the link targets the + resource declares for that relation). Groups belonging to different relations are combined + with logical AND. Relation targets are derived by the server in the same way as types (HTTP + Link headers, server-intrinsic state, or parsed content) and all sources MUST + be treated identically.

The set of additional indexed relations is deliberately NOT enumerated by the server — not in @@ -283,54 +319,41 @@

GET [TypeSearchService]

results for that constraint; it MUST NOT be treated as an error, and the two cases MUST be indistinguishable to the client (consistent with the type-matching rule above). Servers MUST NOT index structural or protocol relations, only descriptive relations are eligible.

-

Clients MUST URL-encode query parameter keys and values.

-

Returns application/lws+json: A paginated ContainerPage whose items describe the matching LWS resources. Aside from type and any additional relation parameters described above, no other parameters are defined.

-

A ContainerPage returned by the TypeSearchService is a synthetic result set, not a representation of a container resource. The ContainerPage media type and pagination model are reused only for client convenience; the response does not identify a container, has no containment relationship to its members, is not retrievable or mutable as a resource, and its membership reflects the query rather than any stored hierarchy. Each item is a resource description carrying at least id and type, mirroring a container member; a server MAY include additional descriptive metadata (such as mediaType, size, or modified) but is not required to. The same applies to the POST form.

-

A single-type query (one URI, no comma) matches a resource that declares that type, even if the resource also declares other types.

-

A type filter always denotes the type the matched resource itself bears; it never denotes the types of a container's members. The native LWS classes https://www.w3.org/ns/lws#DataResource and https://www.w3.org/ns/lws#Container are ordinary type values: filtering on them selects resources that are themselves data resources or containers, respectively (for example ?type=https://www.w3.org/ns/lws%23Container matches container resources, and ?type=https://schema.org/Person&type=https://www.w3.org/ns/lws%23DataResource matches data resources that are also schema:Person).

-
- -
-

POST [TypeSearchService]

- -

MUST support application/lws+json body:

-
-{
-  "@context": "https://www.w3.org/ns/lws/v1",
-  "type": [
-    ["https://schema.org/Person", "http://xmlns.com/foaf/0.1/Person"],
-    "https://www.w3.org/ns/lws#DataResource"
-  ]
-}
-        

- type: an array whose elements are combined with AND. Each element is either a single type URI or an array of type URIs combined with OR. The example above selects resources matching (schema:Person OR foaf:Person) AND lws:DataResource. This is the same conjunctive-normal-form filter as the GET form, with the same expressiveness ceiling: servers MUST NOT be required to support nesting, negation, comparison, ordering, or text matching. + A successful search returns 200 (OK) with an + application/lws+json ContainerPage whose items describe the + matching LWS resources. The result set is paginated following the standard LWS pagination + model defined by [[!LWS-PROTOCOL]]: page URIs are conveyed in Link headers + — not in the response body — are opaque to the client, and are dereferenced to + retrieve subsequent pages. Aside from type and any additional relation keys + described above, no other filter inputs are defined.

-

- The body MAY also include, alongside type, a key for any other descriptive relation - (a registered relation name per [[!RFC8288]] or an extension relation URI). Each such key takes the same value form as type and the keys are combined with logical AND, exactly as in the GET form. A relation the server does not index yields no results for that constraint and is indistinguishable from a target value that matches nothing; it MUST NOT be treated as an error. +

A ContainerPage returned by the TypeSearchService is a synthetic result set, not a representation of a container resource. The ContainerPage media type and pagination model are reused only for client convenience; the response does not identify a container, has no containment relationship to its members, is not retrievable or mutable as a resource, and its membership reflects the query rather than any stored hierarchy. Each item is a resource description carrying at least id and type, mirroring a container member; a server MAY include additional descriptive metadata (such as mediaType, size, or modified) but is not required to.

+

+ [[!RFC10008]] permits a response to carry a Content-Location header field + identifying a resource that represents the query results. Because a Type Search result set + is synthetic and client-specific (see the note above and + ), this specification does not define such a resource; + a server that nonetheless exposes one MUST subject it to the same authorization filtering on + every access and MUST prevent its reuse across clients.

-

Returns a paginated ContainerPage whose items describe the matching LWS resources. Aside from type and additional relation keys, no other parameters are defined.

+

A single-type query (one URI, not enclosed in an array) matches a resource that declares that type, even if the resource also declares other types.

+

A type filter always denotes the type the matched resource itself bears; it never denotes the types of a container's members. The native LWS classes https://www.w3.org/ns/lws#DataResource and https://www.w3.org/ns/lws#Container are ordinary type values: filtering on them selects resources that are themselves data resources or containers, respectively (for example a type of https://www.w3.org/ns/lws#Container matches container resources, and a filter of https://schema.org/Person AND https://www.w3.org/ns/lws#DataResource matches data resources that are also schema:Person).

-
-

Request Equivalence and Errors

+
+

Errors

-

- A server implementing the TypeSearchService MUST support both the GET and - POST forms. The two forms are equivalent: any filter expressible in one MUST be - expressible in the other, and equivalent GET and POST requests MUST return the same result set. A server MUST NOT impose different expressiveness limits on the two forms, except that GET requests are additionally bounded by practical request-URI length limits. -

Servers indicate request outcomes using standard HTTP status codes. In particular:

  • - A POST body that is not well-formed application/lws+json, or whose + A request body that is not well-formed application/lws+json, or whose type is not an array, or any of whose elements is neither a string nor an array of strings, MUST be rejected with 400 (Bad Request).
  • - A POST request whose entity uses a media type other than application/lws+json MUST be rejected with 415 (Unsupported Media Type). + A request whose entity uses a media type other than application/lws+json MUST be rejected with 415 (Unsupported Media Type); a request that omits the Content-Type header field, which [[!RFC10008]] requires a server to reject, MUST be rejected with 400 (Bad Request).
  • A type value, or any relation target value, that is not a syntactically valid @@ -338,16 +361,22 @@

    Request Equivalence and Errors

    well-formed URI that matches no resource, and from a relation the server does not index, both of which yield no results and are not errors (see above).
  • - A pagination reference (a previously issued next link) that the server no longer recognizes or that has expired MUST result in 404 (Not Found) or 410 (Gone); clients SHOULD restart the query from the first page. + A filter that is well-formed but exceeds the complexity a server chooses to support + (consistent with the expressiveness ceiling above) MUST be rejected with 422 (Unprocessable Content) — the status [[!RFC10008]] designates for query content that is understood but cannot be processed. A server MUST NOT silently truncate or otherwise narrow such a filter, as doing so could return a superset of the intended results.
  • - A filter that exceeds the complexity a server chooses to support (consistent with the - expressiveness ceiling above) MUST be rejected with 400 (Bad Request). A server MUST NOT silently truncate or otherwise narrow such a filter, as doing so could return a superset of the intended results. + A pagination reference (a previously issued next link) that the server no longer recognizes or that has expired MUST result in 404 (Not Found) or 410 (Gone); clients SHOULD restart the query from the first page.

- Error responses MAY include a representation describing the problem; this specification does not - define its format. + Error responses MAY include a representation describing the problem; this specification does + not define its format. +

+

+ A QUERY response is cacheable [[!RFC10008]], and its cache key incorporates the + request body. Because every result set is authorization-filtered and therefore + client-specific, the cross-client caching requirements in + apply.

@@ -356,7 +385,9 @@

Request Equivalence and Errors

Security and Authorization

- Servers MUST enforce authorization. Responses to GET/POST on TypeIndexService or TypeSearchService include only types and resource URIs that the authenticated client is explicitly authorized to read. + Servers MUST enforce authorization. Responses from the TypeIndexService (a + GET) and the TypeSearchService (a QUERY) include only + types and resource URIs that the authenticated client is explicitly authorized to read.

Unauthorized entries MUST be omitted entirely. A client must not be able to discover the existence of a specific resource instance, or that a specific type exists in the storage at all, if they do not have the required authorization. This implicit filtering yields a dynamically generated, client-specific type index and search result. @@ -371,6 +402,14 @@

Security and Authorization

Authorization filtering MUST be evaluated against the requesting client's current access at the time the request is served, not against any cached or precomputed view. Once an authorization (such as an access grant) is revoked or narrowed, the affected types and resource URIs MUST NOT appear in any subsequent response; the eventual-consistency allowance for type and relation derivation MUST NOT be extended to authorization. A server MAY maintain a derived index for performance, but it MUST apply current authorization as a filter over that index on every request.

+

+ Because a QUERY response is cacheable by default [[!RFC10008]] and its cache key + is computed over the request body rather than the requesting client, a server MUST ensure that + an authorization-filtered response is never served from a shared cache to a different client. + A server MUST mark such responses so that they are not reused across clients (for example with + Cache-Control: private or no-store) and MUST vary any cached entry on + the credential that scopes the result. +

@@ -398,15 +437,25 @@

Examples

}
-
+      
 Request
-GET /types/search?type=https://schema.org/Person&type=https://www.w3.org/ns/lws%23DataResource
+QUERY /types/search
+Content-Type: application/lws+json
+
+{
+  "@context": "https://www.w3.org/ns/lws/v1",
+  "type": [
+    "https://schema.org/Person",
+    "https://www.w3.org/ns/lws#DataResource"
+  ]
+}
 
 Response
 HTTP/1.1 200 OK
 Content-Type: application/lws+json
-Link: <https://example.org/types/search?type=https://schema.org/Person&type=https://www.w3.org/ns/lws%23DataResource&page=1>; rel="first"
-Link: <https://example.org/types/search?type=https://schema.org/Person&type=https://www.w3.org/ns/lws%23DataResource&page=2>; rel="next"
+Cache-Control: private
+Link: <https://example.org/types/search?cursor=8f2a1c>; rel="first"
+Link: <https://example.org/types/search?cursor=b71e90>; rel="next"
 
 {
   "@context": "https://www.w3.org/ns/lws/v1",
@@ -420,9 +469,15 @@ 

Examples

}
-
+      
 Request
-GET /types/search?type=https://www.w3.org/ns/lws%23Container
+QUERY /types/search
+Content-Type: application/lws+json
+
+{
+  "@context": "https://www.w3.org/ns/lws/v1",
+  "type": ["https://www.w3.org/ns/lws#Container"]
+}
 
 Matches resources whose type includes lws:Container. This does NOT mean
 "containers that contain something" - the service has no containment query.
@@ -440,38 +495,11 @@ 

Examples

}
-
-Request
-POST /types/search
-Request Body
-{
-  "@context": "https://www.w3.org/ns/lws/v1",
-  "type": [
-    "https://schema.org/Person",
-    "https://www.w3.org/ns/lws#DataResource"
-  ]
-}
-
-Response
-{
-  "@context": "https://www.w3.org/ns/lws/v1",
-  "type": "ContainerPage",
-  "totalItems": 3,
-  "items": [
-    { "type": ["DataResource", "https://schema.org/Person"], "id": "https://example.org/data/person-4872" },
-    { "type": ["DataResource", "https://schema.org/Person"], "id": "https://example.org/data/person-9341" },
-    { "type": ["DataResource", "https://schema.org/Person"], "id": "https://example.org/data/person-1123" }
-  ]
-}
-      
-
-Request (GET form: comma = OR, repeated parameter = AND)
-GET /types/search?type=https://schema.org/Person,http://xmlns.com/foaf/0.1/Person&type=https://www.w3.org/ns/lws%23DataResource
+Request (nested array = OR group, outer array = AND)
+QUERY /types/search
+Content-Type: application/lws+json
 
-Equivalent Request (POST form: nested array = OR group, outer array = AND)
-POST /types/search
-Request Body
 {
   "@context": "https://www.w3.org/ns/lws/v1",
   "type": [
@@ -480,7 +508,7 @@ 

Examples

] } -Both select resources matching (schema:Person OR foaf:Person) AND lws:DataResource. +Selects resources matching (schema:Person OR foaf:Person) AND lws:DataResource. Response { @@ -495,12 +523,10 @@

Examples

-Request (GET: type AND a 'describedby' relation; relation name used as the parameter)
-GET /types/search?type=https://schema.org/Person&describedby=https://shapes.example/PersonShape
+Request (type AND a 'describedby' relation, the relation name used as a key)
+QUERY /types/search
+Content-Type: application/lws+json
 
-Equivalent Request (POST)
-POST /types/search
-Request Body
 {
   "@context": "https://www.w3.org/ns/lws/v1",
   "type": ["https://schema.org/Person"],
@@ -548,15 +574,17 @@ 

Security Considerations

Resource Exhaustion: Conjunctive filters across multiple types and indexed relations can be expensive to evaluate. Servers are encouraged to bound filter complexity and page sizes and to apply rate limiting, rejecting over-limit - filters with 400 as required by - rather than narrowing them. + filters with 422 as required by + rather than narrowing them.
  • - Shared Caches: Responses are client-specific by construction. - Serving them through shared caches risks delivering one client's - authorization-filtered view to another. Implementations are encouraged to include - cache directives (such as Cache-Control: private or - no-store) that prevent reuse across clients. + Shared Caches: Responses are client-specific by construction, yet a + QUERY response is cacheable by default [[RFC10008]] and its cache key is + computed over the request body rather than the requesting client. Serving such a response + through a shared cache therefore risks delivering one client's authorization-filtered view + to another. The cache requirements in exist to + prevent this, and deserve particular attention when a shared cache sits in front of the + service.
  • From ab7a3807597b0d0b36f4a5c0bcb24746429475ce Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Fri, 26 Jun 2026 10:49:00 -0400 Subject: [PATCH 02/22] relax 415 on other query types --- lws10-searchindex/index.html | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 3fd46a9..530c7b3 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -260,11 +260,14 @@

    QUERY [TypeSearchService]

    A client searches by sending an HTTP QUERY request [[!RFC10008]] to the - service endpoint, carrying the filter in the request body as - application/lws+json. The request MUST include a Content-Type of - application/lws+json; per [[!RFC10008]] a server fails the request if the - Content-Type is missing or inconsistent with the body (see - ). Because QUERY is both safe and idempotent + service endpoint, carrying the filter in the request body. The query format is identified + by the request's Content-Type header field, which MUST be present; per + [[!RFC10008]] a server fails the request if the Content-Type is missing or + inconsistent with the body (see ). Every server MUST + support the application/lws+json filter defined here as its baseline query + format; a server MAY additionally accept other query formats, each identified by its own + media type, and the authorization requirements of + apply regardless of the format used. Because QUERY is both safe and idempotent [[!RFC10008]], a search never alters server state and MAY be repeated, retried, or cached. Because the filter travels in the body rather than the request URI, it is not subject to the request-URI length limits that constrain a query string. @@ -353,7 +356,7 @@

    Errors

    type is not an array, or any of whose elements is neither a string nor an array of strings, MUST be rejected with 400 (Bad Request).
  • - A request whose entity uses a media type other than application/lws+json MUST be rejected with 415 (Unsupported Media Type); a request that omits the Content-Type header field, which [[!RFC10008]] requires a server to reject, MUST be rejected with 400 (Bad Request). + A request whose Content-Type identifies a query format the server does not support MUST be rejected with 415 (Unsupported Media Type); every server supports at least application/lws+json (see ). A request that omits the Content-Type header field, which [[!RFC10008]] requires a server to reject, MUST be rejected with 400 (Bad Request).
  • A type value, or any relation target value, that is not a syntactically valid From 7e27cbfb5b5c995fe1678df3c7e2fb60be6705f7 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Fri, 26 Jun 2026 10:51:42 -0400 Subject: [PATCH 03/22] augment Security and Authorization to cover alternate query mechanisms --- lws10-searchindex/index.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 530c7b3..5e5b56f 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -413,6 +413,13 @@

    Security and Authorization

    Cache-Control: private or no-store) and MUST vary any cached entry on the credential that scopes the result.

    +

    + Any extension query mechanism a server exposes over the storage — for example an + alternative query format accepted by the TypeSearchService, or a separate query + service — MUST uphold these authorization-filtering requirements and the + indistinguishability requirements of this specification, so that no extension can become a + discovery oracle for resources or types the client is not authorized to read. +

    From 68dece42e358e3c05138d2287ab4a54f918b2980 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Fri, 26 Jun 2026 11:02:42 -0400 Subject: [PATCH 04/22] allow Accept-Query format discovery --- lws10-searchindex/index.html | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 5e5b56f..2decc2b 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -273,6 +273,18 @@

    QUERY [TypeSearchService]

    request-URI length limits that constrain a query string.

    +

    + A server SHOULD advertise the query formats it accepts using the + Accept-Query response header field [[!RFC10008]] — for example in + response to an OPTIONS request on the service endpoint, whose Allow + header also signals that the QUERY method is supported. Accept-Query + enumerates only the query-format media types the server understands; it MUST NOT be used to + disclose which indexed relations or filter capabilities a server supports, which + remain deliberately unobservable (see ). A client that + receives a 415 (Unsupported Media Type) response MAY consult its + Accept-Query value to select a supported format. +

    +
     {
       "@context": "https://www.w3.org/ns/lws/v1",
    @@ -356,7 +368,7 @@ 

    Errors

    type is not an array, or any of whose elements is neither a string nor an array of strings, MUST be rejected with 400 (Bad Request).
  • - A request whose Content-Type identifies a query format the server does not support MUST be rejected with 415 (Unsupported Media Type); every server supports at least application/lws+json (see ). A request that omits the Content-Type header field, which [[!RFC10008]] requires a server to reject, MUST be rejected with 400 (Bad Request). + A request whose Content-Type identifies a query format the server does not support MUST be rejected with 415 (Unsupported Media Type), and such a response SHOULD include an Accept-Query header field [[!RFC10008]] listing the query formats the server does accept; every server supports at least application/lws+json (see ). A request that omits the Content-Type header field, which [[!RFC10008]] requires a server to reject, MUST be rejected with 400 (Bad Request).
  • A type value, or any relation target value, that is not a syntactically valid @@ -447,6 +459,19 @@

    Examples

    }
  • +
    +Request
    +OPTIONS /types/search
    +
    +Response
    +HTTP/1.1 204 No Content
    +Allow: OPTIONS, QUERY
    +Accept-Query: application/lws+json
    +
    +A server that also accepted other query formats would list them in Accept-Query,
    +for example: Accept-Query: application/lws+json, application/sparql-query
    +      
    +
     Request
     QUERY /types/search
    
    From e76a7705353eb61b331e84f38e39c5eaa2c7ddf2 Mon Sep 17 00:00:00 2001
    From: Erich Bremer 
    Date: Fri, 26 Jun 2026 11:09:00 -0400
    Subject: [PATCH 05/22] allow alternate formats for other query types
    
    ---
     lws10-searchindex/index.html | 23 +++++++++++++++++------
     1 file changed, 17 insertions(+), 6 deletions(-)
    
    diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html
    index 2decc2b..588b56f 100644
    --- a/lws10-searchindex/index.html
    +++ b/lws10-searchindex/index.html
    @@ -335,13 +335,21 @@ 

    QUERY [TypeSearchService]

    indistinguishable to the client (consistent with the type-matching rule above). Servers MUST NOT index structural or protocol relations, only descriptive relations are eligible.

    - A successful search returns 200 (OK) with an + A successful search returns 200 (OK). The default response is an application/lws+json ContainerPage whose items describe the - matching LWS resources. The result set is paginated following the standard LWS pagination - model defined by [[!LWS-PROTOCOL]]: page URIs are conveyed in Link headers - — not in the response body — are opaque to the client, and are dereferenced to - retrieve subsequent pages. Aside from type and any additional relation keys - described above, no other filter inputs are defined. + matching LWS resources, and every server MUST be able to produce it: a request that sends + no Accept header field, or one that admits application/lws+json, + receives this representation. A server MAY honor an Accept header field that + requests a different response media type and return the result set in that format instead + [[!RFC10008]]; if it can satisfy none of the media types the request finds acceptable, it + responds 406 (Not Acceptable) (see ). +

    +

    + Whatever the response format, the result set is paginated following the standard LWS + pagination model defined by [[!LWS-PROTOCOL]]: page URIs are conveyed in Link + headers — not in the response body — are opaque to the client, and are + dereferenced to retrieve subsequent pages. Aside from type and any additional + relation keys described above, no other filter inputs are defined.

    A ContainerPage returned by the TypeSearchService is a synthetic result set, not a representation of a container resource. The ContainerPage media type and pagination model are reused only for client convenience; the response does not identify a container, has no containment relationship to its members, is not retrievable or mutable as a resource, and its membership reflects the query rather than any stored hierarchy. Each item is a resource description carrying at least id and type, mirroring a container member; a server MAY include additional descriptive metadata (such as mediaType, size, or modified) but is not required to.

    @@ -370,6 +378,9 @@

    Errors

  • A request whose Content-Type identifies a query format the server does not support MUST be rejected with 415 (Unsupported Media Type), and such a response SHOULD include an Accept-Query header field [[!RFC10008]] listing the query formats the server does accept; every server supports at least application/lws+json (see ). A request that omits the Content-Type header field, which [[!RFC10008]] requires a server to reject, MUST be rejected with 400 (Bad Request).
  • +
  • + A request whose Accept header field excludes every response media type the server can produce for the result set MUST be rejected with 406 (Not Acceptable) [[!RFC10008]]. Because every server can produce the application/lws+json ContainerPage, a request that omits Accept or admits that media type never results in 406. +
  • A type value, or any relation target value, that is not a syntactically valid absolute URI MUST be rejected with 400 (Bad Request). This is distinct from a From d868aba345d529a546ee15401a8f6e670a2db536 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Fri, 26 Jun 2026 13:43:18 -0400 Subject: [PATCH 06/22] Clarify QUERY cache key and Vary: Accept --- lws10-searchindex/index.html | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 588b56f..cd5b373 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -399,10 +399,14 @@

    Errors

    not define its format.

    - A QUERY response is cacheable [[!RFC10008]], and its cache key incorporates the - request body. Because every result set is authorization-filtered and therefore - client-specific, the cross-client caching requirements in - apply. + A QUERY response is cacheable [[!RFC10008]]. Because the filter travels in the + request body, it forms part of the cache key itself ([[!RFC10008]], Section 2.7) and cannot + be conveyed through the Vary header field, which names only request header + fields. A server that negotiates the response representation on Accept (see + ) MUST list Accept in Vary so that + caches do not reuse a representation across response formats. Because every result set is + authorization-filtered and therefore client-specific, the cross-client caching requirements + in also apply.

    From 19d48cd8b14e50524428e23f9e3ab6a2ca4f3286 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Fri, 26 Jun 2026 13:49:09 -0400 Subject: [PATCH 07/22] add normative 9110 reference --- lws10-searchindex/index.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index cd5b373..302b6ce 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -267,8 +267,9 @@

    QUERY [TypeSearchService]

    support the application/lws+json filter defined here as its baseline query format; a server MAY additionally accept other query formats, each identified by its own media type, and the authorization requirements of - apply regardless of the format used. Because QUERY is both safe and idempotent - [[!RFC10008]], a search never alters server state and MAY be repeated, retried, or cached. + apply regardless of the format used. Because the QUERY method is both safe and + idempotent [[!RFC9110]], a property [[!RFC10008]] requires of every QUERY + request, a search never alters server state and MAY be repeated, retried, or cached. Because the filter travels in the body rather than the request URI, it is not subject to the request-URI length limits that constrain a query string.

    @@ -368,7 +369,7 @@

    QUERY [TypeSearchService]

    Errors

    - Servers indicate request outcomes using standard HTTP status codes. In particular: + Servers indicate request outcomes using standard HTTP status codes [[!RFC9110]]. In particular:

    • From bb671983b38b6a50ad844d66198c4df499e115e7 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Sat, 27 Jun 2026 20:49:33 -0400 Subject: [PATCH 08/22] Update lws10-searchindex/index.html Co-authored-by: Ted Thibodeau Jr --- lws10-searchindex/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 302b6ce..d457785 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -268,7 +268,7 @@

      QUERY [TypeSearchService]

      format; a server MAY additionally accept other query formats, each identified by its own media type, and the authorization requirements of apply regardless of the format used. Because the QUERY method is both safe and - idempotent [[!RFC9110]], a property [[!RFC10008]] requires of every QUERY + idempotent [[!RFC9110]], a property [[!RFC10008]] required of every QUERY request, a search never alters server state and MAY be repeated, retried, or cached. Because the filter travels in the body rather than the request URI, it is not subject to the request-URI length limits that constrain a query string. From 5fdc69e293897bf68edf1dc4566dfb1eb5dea31b Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Wed, 1 Jul 2026 22:18:14 -0400 Subject: [PATCH 09/22] cache privacy no longer covers the TypeIndex --- lws10-searchindex/index.html | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 302b6ce..9d00598 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -228,6 +228,7 @@

      GET [TypeIndexService]

       HTTP/1.1 200 OK
       Content-Type: application/lws+json
      +Cache-Control: private
       Link: <https://example.org/types/index?page=1>; rel="first"
       Link: <https://example.org/types/index?page=2>; rel="next"
       Link: <https://example.org/types/index?page=4>; rel="last"
      @@ -434,12 +435,15 @@ 

      Security and Authorization

      Authorization filtering MUST be evaluated against the requesting client's current access at the time the request is served, not against any cached or precomputed view. Once an authorization (such as an access grant) is revoked or narrowed, the affected types and resource URIs MUST NOT appear in any subsequent response; the eventual-consistency allowance for type and relation derivation MUST NOT be extended to authorization. A server MAY maintain a derived index for performance, but it MUST apply current authorization as a filter over that index on every request.

      - Because a QUERY response is cacheable by default [[!RFC10008]] and its cache key - is computed over the request body rather than the requesting client, a server MUST ensure that - an authorization-filtered response is never served from a shared cache to a different client. - A server MUST mark such responses so that they are not reused across clients (for example with - Cache-Control: private or no-store) and MUST vary any cached entry on - the credential that scopes the result. + Responses from both services are authorization-filtered and therefore client-specific, yet + both are cacheable by default: a TypeIndexService response under the ordinary + HTTP caching rules for GET [[!RFC9110]], and a TypeSearchService + response per [[!RFC10008]], whose cache key is computed over the request body rather than + the requesting client. A server MUST ensure that an authorization-filtered response from + either service is never served from a shared cache to a different client. A server MUST mark + such responses so that they are not reused across clients (for example with + Cache-Control: private or no-store) and MUST vary any cached entry + on the credential that scopes the result.

      Any extension query mechanism a server exposes over the storage — for example an @@ -460,6 +464,7 @@

      Examples

      Response HTTP/1.1 200 OK Content-Type: application/lws+json +Cache-Control: private Link: <https://example.org/types/index?page=1>; rel="first" Link: <https://example.org/types/index?page=2>; rel="next" Link: <https://example.org/types/index?page=4>; rel="last" @@ -629,12 +634,14 @@

      Security Considerations

      rather than narrowing them.
    • - Shared Caches: Responses are client-specific by construction, yet a - QUERY response is cacheable by default [[RFC10008]] and its cache key is - computed over the request body rather than the requesting client. Serving such a response - through a shared cache therefore risks delivering one client's authorization-filtered view - to another. The cache requirements in exist to - prevent this, and deserve particular attention when a shared cache sits in front of the + Shared Caches: Responses from both services are client-specific by + construction, yet both are cacheable by default: a TypeIndexService + GET response under the ordinary HTTP caching rules [[RFC9110]], and a + TypeSearchService QUERY response per [[RFC10008]], whose cache + key is computed over the request body rather than the requesting client. Serving either + through a shared cache risks delivering one client's authorization-filtered view to + another. The cache requirements in exist to prevent + this, and deserve particular attention when a shared cache sits in front of either service.
    From 84683b953f034927b5f57e9794fc77efdfb2f094 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Wed, 1 Jul 2026 22:21:23 -0400 Subject: [PATCH 10/22] clarify that server-issued opaque page URIs may carry whatever they like --- lws10-searchindex/index.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 9d00598..92f94e1 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -219,7 +219,11 @@

    GET [TypeIndexService]

    are conveyed in Link headers—not in the response body—and are opaque to the client. The body lists the unique types of resources that currently exist within the storage and that the authenticated user is authorized to - see. This endpoint accepts no query parameters.

    + see. This specification defines no query parameters for the endpoint: a client + requests the advertised serviceEndpoint URI as-is, and any parameters + appearing in server-issued pagination URIs (such as ?page= in the + example below) are server-internal parts of those opaque URIs, not part of this + interface.

    The Type Index takes no filter, so it is retrieved with a GET. The Type Search Service, which carries a filter, instead uses the HTTP From 96c113c588ea7565b121b10930ce50d28197badf Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Wed, 1 Jul 2026 22:23:07 -0400 Subject: [PATCH 11/22] fix grammer --- lws10-searchindex/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 92f94e1..369b7dc 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -272,9 +272,9 @@

    QUERY [TypeSearchService]

    support the application/lws+json filter defined here as its baseline query format; a server MAY additionally accept other query formats, each identified by its own media type, and the authorization requirements of - apply regardless of the format used. Because the QUERY method is both safe and - idempotent [[!RFC9110]], a property [[!RFC10008]] requires of every QUERY - request, a search never alters server state and MAY be repeated, retried, or cached. + apply regardless of the format used. The QUERY method is both safe and + idempotent [[!RFC10008]], in the sense those terms are defined by [[!RFC9110]]: a + search never alters server state and MAY be repeated, retried, or cached. Because the filter travels in the body rather than the request URI, it is not subject to the request-URI length limits that constrain a query string.

    From bd19131596d90c3a0a7cab8b89ff13e508408e47 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Wed, 1 Jul 2026 22:26:41 -0400 Subject: [PATCH 12/22] adjust 422 claim --- lws10-searchindex/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 369b7dc..77e2370 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -394,7 +394,7 @@

    Errors

  • A filter that is well-formed but exceeds the complexity a server chooses to support - (consistent with the expressiveness ceiling above) MUST be rejected with 422 (Unprocessable Content) — the status [[!RFC10008]] designates for query content that is understood but cannot be processed. A server MUST NOT silently truncate or otherwise narrow such a filter, as doing so could return a superset of the intended results. + (consistent with the expressiveness ceiling above) MUST be rejected with 422 (Unprocessable Content), the status [[!RFC9110]] defines and [[!RFC10008]] suggests for a query that is understood but cannot be processed due to its actual contents. A server MUST NOT silently truncate or otherwise narrow such a filter, as doing so could return a superset of the intended results.
  • A pagination reference (a previously issued next link) that the server no longer recognizes or that has expired MUST result in 404 (Not Found) or 410 (Gone); clients SHOULD restart the query from the first page. From 6487d3165b808a614177b60c8a96c46db2cc6de0 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Wed, 1 Jul 2026 22:33:25 -0400 Subject: [PATCH 13/22] add Authroization header to examples --- lws10-searchindex/index.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 77e2370..ee2cdc2 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -230,6 +230,11 @@

    GET [TypeIndexService]

    QUERY method [[!RFC10008]] (see ).

    +Request
    +GET /types/index
    +Authorization: Bearer <token>
    +
    +Response
     HTTP/1.1 200 OK
     Content-Type: application/lws+json
     Cache-Control: private
    @@ -464,6 +469,7 @@ 

    Examples

     Request
     GET /types/index
    +Authorization: Bearer <token>
     
     Response
     HTTP/1.1 200 OK
    @@ -500,6 +506,7 @@ 

    Examples

     Request
     QUERY /types/search
    +Authorization: Bearer <token>
     Content-Type: application/lws+json
     
     {
    @@ -532,6 +539,7 @@ 

    Examples

     Request
     QUERY /types/search
    +Authorization: Bearer <token>
     Content-Type: application/lws+json
     
     {
    @@ -558,6 +566,7 @@ 

    Examples

     Request (nested array = OR group, outer array = AND)
     QUERY /types/search
    +Authorization: Bearer <token>
     Content-Type: application/lws+json
     
     {
    @@ -585,6 +594,7 @@ 

    Examples

     Request (type AND a 'describedby' relation, the relation name used as a key)
     QUERY /types/search
    +Authorization: Bearer <token>
     Content-Type: application/lws+json
     
     {
    
    From 4ca89dffc2d067af4502f5e277b7d5c4a1daea06 Mon Sep 17 00:00:00 2001
    From: Erich Bremer 
    Date: Wed, 1 Jul 2026 22:38:17 -0400
    Subject: [PATCH 14/22] fix shortname
    
    ---
     lws10-searchindex/index.html | 16 ++++++++--------
     1 file changed, 8 insertions(+), 8 deletions(-)
    
    diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html
    index ee2cdc2..806d071 100644
    --- a/lws10-searchindex/index.html
    +++ b/lws10-searchindex/index.html
    @@ -25,9 +25,9 @@
             group: "lws",
             maxTocLevel: 3,
             localBiblio: {
    -          "LWS-PROTOCOL": {
    -            title: "LWS Protocol",
    -            href: "https://www.w3.org/TR/lws-core/",
    +          "LWS10-CORE": {
    +            title: "Linked Web Storage Protocol 1.0",
    +            href: "https://www.w3.org/TR/lws10-core/",
                 publisher: "W3C",
                 status: "FPWD",
               },
    @@ -65,7 +65,7 @@
           

    Introduction

    - The [[!LWS-PROTOCOL|Linked Web Storage]] protocol defines a resource-centric storage + The [[!LWS10-CORE|Linked Web Storage]] protocol defines a resource-centric storage system built on HTTP. While the core protocol supports creating, reading, updating, and deleting resources, and containers enumerate the resources they contain, it does not define a mechanism for a client to learn which kinds of resources exist within a @@ -89,7 +89,7 @@

    Terminology

    The terms "storage", "storage description resource", "container", "data resource", - "resource manager", and "requesting agent" are defined by [[!LWS-PROTOCOL]]. + "resource manager", and "requesting agent" are defined by [[!LWS10-CORE]].

    @@ -215,7 +215,7 @@

    Type Index Service

    GET [TypeIndexService]

    Returns a paginated TypeIndex as application/lws+json, - following the standard LWS pagination model defined by [[!LWS-PROTOCOL]]: page URIs + following the standard LWS pagination model defined by [[!LWS10-CORE]]: page URIs are conveyed in Link headers—not in the response body—and are opaque to the client. The body lists the unique types of resources that currently exist within the storage and that the authenticated user is authorized to @@ -357,7 +357,7 @@

    QUERY [TypeSearchService]

    Whatever the response format, the result set is paginated following the standard LWS - pagination model defined by [[!LWS-PROTOCOL]]: page URIs are conveyed in Link + pagination model defined by [[!LWS10-CORE]]: page URIs are conveyed in Link headers — not in the response body — are opaque to the client, and are dereferenced to retrieve subsequent pages. Aside from type and any additional relation keys described above, no other filter inputs are defined. @@ -724,7 +724,7 @@

    Vocabulary

    This document also uses the terms Storage, ContainerPage, service, serviceEndpoint, totalItems, and - items defined by [[!LWS-PROTOCOL]] and the LWS JSON-LD context. + items defined by [[!LWS10-CORE]] and the LWS JSON-LD context.

    From 03d9b1a78d039fbee6891558dcf0575cc15065dd Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Wed, 1 Jul 2026 22:51:51 -0400 Subject: [PATCH 15/22] change query type to application/lws-query+json --- lws10-searchindex/index.html | 90 ++++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 15 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 806d071..4837aa3 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -274,7 +274,7 @@

    QUERY [TypeSearchService]

    by the request's Content-Type header field, which MUST be present; per [[!RFC10008]] a server fails the request if the Content-Type is missing or inconsistent with the body (see ). Every server MUST - support the application/lws+json filter defined here as its baseline query + support the application/lws-query+json filter format defined here as its baseline query format; a server MAY additionally accept other query formats, each identified by its own media type, and the authorization requirements of apply regardless of the format used. The QUERY method is both safe and @@ -284,6 +284,22 @@

    QUERY [TypeSearchService]

    request-URI length limits that constrain a query string.

    +

    + The baseline filter format is identified by the media type + application/lws-query+json, registered in + . A filter document is a single JSON object + [[!RFC8259]] whose members express constraints: the type member and, + optionally, one member per filtered link relation, each carrying the + conjunctive-normal-form value grammar defined below. Unlike the + application/lws+json representations defined by [[!LWS10-CORE]] — + which this service still uses for its responses — a filter document is + plain JSON rather than JSON-LD: it carries no @context, its member names + are not JSON-LD terms, and its nested-array groups are not subject to JSON-LD + constraints on @type values. A member whose name begins with + @ (a JSON-LD keyword such as @context) MUST be ignored; it + is neither a constraint nor a relation key. +

    +

    A server SHOULD advertise the query formats it accepts using the Accept-Query response header field [[!RFC10008]] — for example in @@ -296,9 +312,8 @@

    QUERY [TypeSearchService]

    Accept-Query value to select a supported format.

    -
    +        
     {
    -  "@context": "https://www.w3.org/ns/lws/v1",
       "type": [
         ["https://schema.org/Person", "http://xmlns.com/foaf/0.1/Person"],
         "https://www.w3.org/ns/lws#DataResource"
    @@ -383,11 +398,11 @@ 

    Errors

    • - A request body that is not well-formed application/lws+json, or whose + A request body that is not well-formed application/lws-query+json, or whose type is not an array, or any of whose elements is neither a string nor an array of strings, MUST be rejected with 400 (Bad Request).
    • - A request whose Content-Type identifies a query format the server does not support MUST be rejected with 415 (Unsupported Media Type), and such a response SHOULD include an Accept-Query header field [[!RFC10008]] listing the query formats the server does accept; every server supports at least application/lws+json (see ). A request that omits the Content-Type header field, which [[!RFC10008]] requires a server to reject, MUST be rejected with 400 (Bad Request). + A request whose Content-Type identifies a query format the server does not support MUST be rejected with 415 (Unsupported Media Type), and such a response SHOULD include an Accept-Query header field [[!RFC10008]] listing the query formats the server does accept; every server supports at least application/lws-query+json (see ). A request that omits the Content-Type header field, which [[!RFC10008]] requires a server to reject, MUST be rejected with 400 (Bad Request).
    • A request whose Accept header field excludes every response media type the server can produce for the result set MUST be rejected with 406 (Not Acceptable) [[!RFC10008]]. Because every server can produce the application/lws+json ContainerPage, a request that omits Accept or admits that media type never results in 406. @@ -497,20 +512,19 @@

      Examples

      Response HTTP/1.1 204 No Content Allow: OPTIONS, QUERY -Accept-Query: application/lws+json +Accept-Query: application/lws-query+json A server that also accepted other query formats would list them in Accept-Query, -for example: Accept-Query: application/lws+json, application/sparql-query +for example: Accept-Query: application/lws-query+json, application/sparql-query
     Request
     QUERY /types/search
     Authorization: Bearer <token>
    -Content-Type: application/lws+json
    +Content-Type: application/lws-query+json
     
     {
    -  "@context": "https://www.w3.org/ns/lws/v1",
       "type": [
         "https://schema.org/Person",
         "https://www.w3.org/ns/lws#DataResource"
    @@ -540,10 +554,9 @@ 

    Examples

    Request QUERY /types/search Authorization: Bearer <token> -Content-Type: application/lws+json +Content-Type: application/lws-query+json { - "@context": "https://www.w3.org/ns/lws/v1", "type": ["https://www.w3.org/ns/lws#Container"] } @@ -567,10 +580,9 @@

    Examples

    Request (nested array = OR group, outer array = AND) QUERY /types/search Authorization: Bearer <token> -Content-Type: application/lws+json +Content-Type: application/lws-query+json { - "@context": "https://www.w3.org/ns/lws/v1", "type": [ ["https://schema.org/Person", "http://xmlns.com/foaf/0.1/Person"], "https://www.w3.org/ns/lws#DataResource" @@ -595,10 +607,9 @@

    Examples

    Request (type AND a 'describedby' relation, the relation name used as a key) QUERY /types/search Authorization: Bearer <token> -Content-Type: application/lws+json +Content-Type: application/lws-query+json { - "@context": "https://www.w3.org/ns/lws/v1", "type": ["https://schema.org/Person"], "describedby": ["https://shapes.example/PersonShape"] } @@ -727,5 +738,54 @@

    Vocabulary

    items defined by [[!LWS10-CORE]] and the LWS JSON-LD context.

    + +
    +

    IANA Considerations

    + +
    +

    The application/lws-query+json Media Type

    + +

    + This specification registers the application/lws-query+json media type, + identifying the baseline Type Search filter format defined in + . +

    + +
      +
    • Type name: application
    • +
    • Subtype name: lws-query+json
    • +
    • Required parameters: N/A
    • +
    • Optional parameters: N/A
    • +
    • Encoding considerations: Resources that use the application/lws-query+json + media type are required to conform to all of the requirements for the + application/json media type and are therefore subject to the same encoding + considerations specified in Section 11 of [[RFC8259]].
    • +
    • Security considerations: As defined in this specification. A filter document is a + declarative constraint expression and contains no executable content; see + and .
    • +
    • Interoperability considerations: A filter document is plain JSON, not JSON-LD; members + whose names begin with @ are ignored (see + ).
    • +
    • Published specification: This document.
    • +
    • Applications that use this media type: Clients and servers implementing the Linked Web + Storage Type Search Service.
    • +
    • Fragment identifier considerations: N/A
    • +
    • Additional information: +
        +
      • Magic number(s): N/A
      • +
      • File extension(s): N/A
      • +
      • Macintosh file type code(s): N/A
      • +
      +
    • +
    • Person & email address to contact for further information: W3C Linked Web Storage + Working Group <public-lws-wg@w3.org>
    • +
    • Intended usage: COMMON
    • +
    • Restrictions on usage: N/A. This media type is intended for use as the request content + of HTTP QUERY messages, but is not restricted to that context.
    • +
    • Author: W3C Linked Web Storage Working Group
    • +
    • Change controller: W3C
    • +
    +
    +
    From d98993bf8b55d25b474c9508c0529bda8c94eb16 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Wed, 1 Jul 2026 23:14:19 -0400 Subject: [PATCH 16/22] throw 400 for empty group --- lws10-searchindex/index.html | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 4837aa3..100f4df 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -330,15 +330,19 @@

    QUERY [TypeSearchService]

    above selects resources matching (schema:Person OR foaf:Person) AND lws:DataResource — the filter is a conjunction of disjunctions, that is, conjunctive normal form. A request whose body has no - type key and no relation keys (or only empty groups) matches all resources - visible to the client. + type key and no relation keys (or only keys whose values are empty arrays) + matches all resources visible to the client.

    This conjunctive-normal-form filter is the complete query expressiveness the service is required to provide. A server MAY support nesting, negation, comparison, ordering, or text matching, but a portable client MUST NOT rely on any of these. A type URI that matches no - resource yields no results and MUST NOT be treated as an error; empty or duplicate groups - MUST be ignored. + resource yields no results and MUST NOT be treated as an error, and duplicate groups MUST + be ignored. An empty group — an empty array appearing as an element of a filter + key's value — MUST be rejected with 400 (Bad Request): an empty + disjunction can match nothing, so ignoring it would silently broaden the query beyond its + logical meaning (see ). A filter key whose entire value + is an empty array expresses no constraint and is treated as if the key were absent.

    The type key is the mandatory baseline and MUST be supported by every server @@ -399,7 +403,7 @@

    Errors

    • A request body that is not well-formed application/lws-query+json, or whose - type is not an array, or any of whose elements is neither a string nor an array of strings, MUST be rejected with 400 (Bad Request). + type is not an array, or any of whose elements is neither a string nor a non-empty array of strings, MUST be rejected with 400 (Bad Request). In particular, an empty group is rejected, not ignored (see ).
    • A request whose Content-Type identifies a query format the server does not support MUST be rejected with 415 (Unsupported Media Type), and such a response SHOULD include an Accept-Query header field [[!RFC10008]] listing the query formats the server does accept; every server supports at least application/lws-query+json (see ). A request that omits the Content-Type header field, which [[!RFC10008]] requires a server to reject, MUST be rejected with 400 (Bad Request). From d878c412ab58868b96c5436cadc2d1d64ae6193e Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Mon, 6 Jul 2026 09:37:49 -0400 Subject: [PATCH 17/22] contradicts array rule --- lws10-searchindex/index.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 100f4df..b5bfeab 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -333,6 +333,12 @@

      QUERY [TypeSearchService]

      type key and no relation keys (or only keys whose values are empty arrays) matches all resources visible to the client.

      +

      + A single-type query — a type value containing one URI and no OR group, + for example {"type": ["https://schema.org/Person"]} — matches every + resource that declares that type, even if the resource also declares other types. +

      +

      A type filter always denotes the type the matched resource itself bears; it never denotes the types of a container's members. The native LWS classes https://www.w3.org/ns/lws#DataResource and https://www.w3.org/ns/lws#Container are ordinary type values: filtering on them selects resources that are themselves data resources or containers, respectively (for example a type of https://www.w3.org/ns/lws#Container matches container resources, and a filter of https://schema.org/Person AND https://www.w3.org/ns/lws#DataResource matches data resources that are also schema:Person).

      This conjunctive-normal-form filter is the complete query expressiveness the service is required to provide. A server MAY support nesting, negation, comparison, ordering, or text @@ -390,8 +396,6 @@

      QUERY [TypeSearchService]

      a server that nonetheless exposes one MUST subject it to the same authorization filtering on every access and MUST prevent its reuse across clients.

      -

      A single-type query (one URI, not enclosed in an array) matches a resource that declares that type, even if the resource also declares other types.

      -

      A type filter always denotes the type the matched resource itself bears; it never denotes the types of a container's members. The native LWS classes https://www.w3.org/ns/lws#DataResource and https://www.w3.org/ns/lws#Container are ordinary type values: filtering on them selects resources that are themselves data resources or containers, respectively (for example a type of https://www.w3.org/ns/lws#Container matches container resources, and a filter of https://schema.org/Person AND https://www.w3.org/ns/lws#DataResource matches data resources that are also schema:Person).

      From 27aa1c39ce8f6e7d8cd24625e71e1f1b30fbbc3c Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Mon, 6 Jul 2026 09:42:22 -0400 Subject: [PATCH 18/22] capitalization --- lws10-searchindex/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index b5bfeab..3fe170f 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -454,7 +454,7 @@

      Security and Authorization

      types and resource URIs that the authenticated client is explicitly authorized to read.

      - Unauthorized entries MUST be omitted entirely. A client must not be able to discover the existence of a specific resource instance, or that a specific type exists in the storage at all, if they do not have the required authorization. This implicit filtering yields a dynamically generated, client-specific type index and search result. + Unauthorized entries MUST be omitted entirely. A server MUST NOT allow a client to discover, from the responses of these services, the existence of a specific resource instance, or that a specific type exists in the storage at all, without the required authorization. This implicit filtering yields a dynamically generated, client-specific type index and search result.

      Any count a response exposes, including totalItems, MUST be computed over this From 59745d75e7d4db07431f9dd9256021b9d9432ba6 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Mon, 6 Jul 2026 09:48:03 -0400 Subject: [PATCH 19/22] MUST's living inside notes --- lws10-searchindex/index.html | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 3fe170f..091da38 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -363,12 +363,18 @@

      QUERY [TypeSearchService]

      Link headers, server-intrinsic state, or parsed content) and all sources MUST be treated identically.

      +

      + A server MUST NOT enumerate its set of additional indexed relations — not in + the storage description nor elsewhere. A relation the server does not index, like a target + value that matches nothing, yields no results for that constraint: this MUST NOT be treated + as an error, and the two cases MUST be indistinguishable to the client (consistent with the + type-matching rule above). Only descriptive relations are eligible for indexing; + servers MUST NOT index structural or protocol relations. +

      - The set of additional indexed relations is deliberately NOT enumerated by the server — not in - the storage description nor elsewhere — so that it cannot serve as a discovery oracle. A - relation the server does not index, like a target value that matches nothing, simply yields no - results for that constraint; it MUST NOT be treated as an error, and the two cases MUST be - indistinguishable to the client (consistent with the type-matching rule above). Servers MUST NOT index structural or protocol relations, only descriptive relations are eligible. + Withholding the set of indexed relations keeps the filter interface from serving as a + discovery oracle for the server's configuration; see + .

      A successful search returns 200 (OK). The default response is an @@ -380,6 +386,12 @@

      QUERY [TypeSearchService]

      [[!RFC10008]]; if it can satisfy none of the media types the request finds acceptable, it responds 406 (Not Acceptable) (see ).

      +

      + Each item in a ContainerPage result MUST carry at least the matched + resource's id and its type, mirroring a container member; a + server MAY include additional descriptive metadata (such as mediaType, + size, or modified) but is not required to. +

      Whatever the response format, the result set is paginated following the standard LWS pagination model defined by [[!LWS10-CORE]]: page URIs are conveyed in Link @@ -387,8 +399,8 @@

      QUERY [TypeSearchService]

      dereferenced to retrieve subsequent pages. Aside from type and any additional relation keys described above, no other filter inputs are defined.

      -

      A ContainerPage returned by the TypeSearchService is a synthetic result set, not a representation of a container resource. The ContainerPage media type and pagination model are reused only for client convenience; the response does not identify a container, has no containment relationship to its members, is not retrievable or mutable as a resource, and its membership reflects the query rather than any stored hierarchy. Each item is a resource description carrying at least id and type, mirroring a container member; a server MAY include additional descriptive metadata (such as mediaType, size, or modified) but is not required to.

      -

      +

      A ContainerPage returned by the TypeSearchService is a synthetic result set, not a representation of a container resource. The ContainerPage media type and pagination model are reused only for client convenience; the response does not identify a container, has no containment relationship to its members, is not retrievable or mutable as a resource, and its membership reflects the query rather than any stored hierarchy.

      +

      [[!RFC10008]] permits a response to carry a Content-Location header field identifying a resource that represents the query results. Because a Type Search result set is synthetic and client-specific (see the note above and @@ -429,10 +441,10 @@

      Errors

    - Error responses MAY include a representation describing the problem; this specification does + Error responses may include a representation describing the problem; this specification does not define its format.

    -

    +

    A QUERY response is cacheable [[!RFC10008]]. Because the filter travels in the request body, it forms part of the cache key itself ([[!RFC10008]], Section 2.7) and cannot be conveyed through the Vary header field, which names only request header From 426e05d890e100c072790ce4d4918334f6764bb7 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Mon, 6 Jul 2026 10:10:13 -0400 Subject: [PATCH 20/22] absolute URI contradiction. Change URI to IRI. --- lws10-searchindex/index.html | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 091da38..4648716 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -326,7 +326,7 @@

    QUERY [TypeSearchService]

    (as declared via rel="type" Link headers, server-intrinsic classes, or content; see ). Its value is an array whose elements are combined with logical AND; each element is either a single - type URI or an array of type URIs combined with logical OR. The example + type IRI [[!RFC3987]] or an array of type IRIs combined with logical OR. The example above selects resources matching (schema:Person OR foaf:Person) AND lws:DataResource — the filter is a conjunction of disjunctions, that is, conjunctive normal form. A request whose body has no @@ -334,7 +334,7 @@

    QUERY [TypeSearchService]

    matches all resources visible to the client.

    - A single-type query — a type value containing one URI and no OR group, + A single-type query — a type value containing one IRI and no OR group, for example {"type": ["https://schema.org/Person"]} — matches every resource that declares that type, even if the resource also declares other types.

    @@ -342,7 +342,7 @@

    QUERY [TypeSearchService]

    This conjunctive-normal-form filter is the complete query expressiveness the service is required to provide. A server MAY support nesting, negation, comparison, ordering, or text - matching, but a portable client MUST NOT rely on any of these. A type URI that matches no + matching, but a portable client MUST NOT rely on any of these. A type IRI that matches no resource yields no results and MUST NOT be treated as an error, and duplicate groups MUST be ignored. An empty group — an empty array appearing as an element of a filter key's value — MUST be rejected with 400 (Bad Request): an empty @@ -428,9 +428,11 @@

    Errors

    A request whose Accept header field excludes every response media type the server can produce for the result set MUST be rejected with 406 (Not Acceptable) [[!RFC10008]]. Because every server can produce the application/lws+json ContainerPage, a request that omits Accept or admits that media type never results in 406.
  • - A type value, or any relation target value, that is not a syntactically valid - absolute URI MUST be rejected with 400 (Bad Request). This is distinct from a - well-formed URI that matches no resource, and from a relation the server does not index, both of which yield no results and are not errors (see above). + A type value, or any relation target value, that does not match the + IRI production of [[!RFC3987]] — an absolute IRI, optionally carrying + a fragment identifier, the form of every IRI in the RDF abstract syntax + [[rdf11-concepts]] — MUST be rejected with 400 (Bad Request). This is distinct from a + well-formed IRI that matches no resource, and from a relation the server does not index, both of which yield no results and are not errors (see above).
  • A filter that is well-formed but exceeds the complexity a server chooses to support From ccc9c2006b3aa2e25d3b0e6154c4f1024363beda Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Mon, 6 Jul 2026 10:26:59 -0400 Subject: [PATCH 21/22] contradiction fix --- lws10-searchindex/index.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index 4648716..c6ef42e 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -341,8 +341,12 @@

    QUERY [TypeSearchService]

    A type filter always denotes the type the matched resource itself bears; it never denotes the types of a container's members. The native LWS classes https://www.w3.org/ns/lws#DataResource and https://www.w3.org/ns/lws#Container are ordinary type values: filtering on them selects resources that are themselves data resources or containers, respectively (for example a type of https://www.w3.org/ns/lws#Container matches container resources, and a filter of https://schema.org/Person AND https://www.w3.org/ns/lws#DataResource matches data resources that are also schema:Person).

    This conjunctive-normal-form filter is the complete query expressiveness the service is - required to provide. A server MAY support nesting, negation, comparison, ordering, or text - matching, but a portable client MUST NOT rely on any of these. A type IRI that matches no + required to provide. It is also the complete expressiveness of the + application/lws-query+json format itself: a server MUST NOT extend this + grammar. Richer expressiveness — such as nesting, negation, comparison, ordering, or + text matching — is offered only through an alternate query format identified by its + own media type and advertised in Accept-Query, and a portable client MUST NOT + rely on any query format beyond this baseline. A type IRI that matches no resource yields no results and MUST NOT be treated as an error, and duplicate groups MUST be ignored. An empty group — an empty array appearing as an element of a filter key's value — MUST be rejected with 400 (Bad Request): an empty From 11abea4261e27ac81f0349b8eec39dfc661e21b4 Mon Sep 17 00:00:00 2001 From: Erich Bremer Date: Mon, 6 Jul 2026 10:31:33 -0400 Subject: [PATCH 22/22] Pagination-expiry rule exists only for search --- lws10-searchindex/index.html | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lws10-searchindex/index.html b/lws10-searchindex/index.html index c6ef42e..58da740 100644 --- a/lws10-searchindex/index.html +++ b/lws10-searchindex/index.html @@ -223,7 +223,9 @@

    GET [TypeIndexService]

    requests the advertised serviceEndpoint URI as-is, and any parameters appearing in server-issued pagination URIs (such as ?page= in the example below) are server-internal parts of those opaque URIs, not part of this - interface.

    + interface. A page reference may expire or cease to be recognized; the + pagination-expiry rule of applies to + TypeIndex pages as it does to search result pages.

    The Type Index takes no filter, so it is retrieved with a GET. The Type Search Service, which carries a filter, instead uses the HTTP @@ -443,7 +445,12 @@

    Errors

    (consistent with the expressiveness ceiling above) MUST be rejected with 422 (Unprocessable Content), the status [[!RFC9110]] defines and [[!RFC10008]] suggests for a query that is understood but cannot be processed due to its actual contents. A server MUST NOT silently truncate or otherwise narrow such a filter, as doing so could return a superset of the intended results.
  • - A pagination reference (a previously issued next link) that the server no longer recognizes or that has expired MUST result in 404 (Not Found) or 410 (Gone); clients SHOULD restart the query from the first page. + A pagination reference (a previously issued page link) that the server no longer + recognizes or that has expired MUST result in 404 (Not Found) or + 410 (Gone). This rule applies to the pages of both services: those of a + Type Search Service result set and those of a Type Index Service listing + alike. Clients SHOULD restart — a search by re-sending the QUERY + request, a type index listing by re-requesting the service endpoint.