@speakspec/astro 0.0.2 → 0.0.4
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.
|
@@ -26,10 +26,22 @@ export interface CacheStorage {
|
|
|
26
26
|
export declare function invalidateEntityCache(storage: CacheStorage, slug: string): Promise<void>;
|
|
27
27
|
export declare function invalidateContentCache(storage: CacheStorage, slug: string, contentId: string): Promise<void>;
|
|
28
28
|
/**
|
|
29
|
-
* Build a JSON Response with cache headers
|
|
30
|
-
* when the inbound `If-None-Match` matches the
|
|
31
|
-
* AIDP §8.7 + RFC 7232 §2.3.2 weak comparison via
|
|
29
|
+
* Build a JSON Response with cache headers per AIDP §8.3 + §11.6,
|
|
30
|
+
* short-circuiting to 304 when the inbound `If-None-Match` matches the
|
|
31
|
+
* response ETag (per AIDP §8.7 + RFC 7232 §2.3.2 weak comparison via
|
|
32
|
+
* `etagMatches`).
|
|
32
33
|
*
|
|
33
|
-
* 304 responses still carry ETag + Cache-Control per RFC 7232 §4.1
|
|
34
|
+
* 304 responses still carry ETag + Cache-Control per RFC 7232 §4.1, and
|
|
35
|
+
* we keep CORS on them so browser-side agents can revalidate cross-origin.
|
|
34
36
|
*/
|
|
35
37
|
export declare function respondWithCache<T>(etag: string, payload: T, cacheControl: string, inboundIfNoneMatch: string | undefined | null): Response;
|
|
38
|
+
/**
|
|
39
|
+
* Project `directives.access_control` to an AIPREF-compatible
|
|
40
|
+
* `Content-Usage` header value per AIDP §11.6.
|
|
41
|
+
*
|
|
42
|
+
* Returns null when the payload is not an AIDP envelope (e.g. the
|
|
43
|
+
* directory listing has no `directives` field) or when `access_control`
|
|
44
|
+
* has no actionable flags — callers MUST NOT emit the header in that
|
|
45
|
+
* case rather than emitting an empty value.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildContentUsage(payload: unknown): string | null;
|
|
@@ -55,26 +55,62 @@ export async function invalidateContentCache(storage, slug, contentId) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
|
-
* Build a JSON Response with cache headers
|
|
59
|
-
* when the inbound `If-None-Match` matches the
|
|
60
|
-
* AIDP §8.7 + RFC 7232 §2.3.2 weak comparison via
|
|
58
|
+
* Build a JSON Response with cache headers per AIDP §8.3 + §11.6,
|
|
59
|
+
* short-circuiting to 304 when the inbound `If-None-Match` matches the
|
|
60
|
+
* response ETag (per AIDP §8.7 + RFC 7232 §2.3.2 weak comparison via
|
|
61
|
+
* `etagMatches`).
|
|
61
62
|
*
|
|
62
|
-
* 304 responses still carry ETag + Cache-Control per RFC 7232 §4.1
|
|
63
|
+
* 304 responses still carry ETag + Cache-Control per RFC 7232 §4.1, and
|
|
64
|
+
* we keep CORS on them so browser-side agents can revalidate cross-origin.
|
|
63
65
|
*/
|
|
64
66
|
export function respondWithCache(etag, payload, cacheControl, inboundIfNoneMatch) {
|
|
65
67
|
const headers = {
|
|
66
68
|
'cache-control': cacheControl,
|
|
69
|
+
'access-control-allow-origin': '*',
|
|
67
70
|
};
|
|
68
71
|
if (etag)
|
|
69
72
|
headers.etag = etag;
|
|
70
73
|
if (etagMatches(inboundIfNoneMatch, etag)) {
|
|
71
74
|
return new Response(null, { status: 304, headers });
|
|
72
75
|
}
|
|
76
|
+
const usage = buildContentUsage(payload);
|
|
77
|
+
if (usage)
|
|
78
|
+
headers['content-usage'] = usage;
|
|
73
79
|
return new Response(JSON.stringify(payload), {
|
|
74
80
|
status: 200,
|
|
75
81
|
headers: {
|
|
76
82
|
...headers,
|
|
77
|
-
'content-type': 'application/json
|
|
83
|
+
'content-type': 'application/aidp+json',
|
|
78
84
|
},
|
|
79
85
|
});
|
|
80
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Project `directives.access_control` to an AIPREF-compatible
|
|
89
|
+
* `Content-Usage` header value per AIDP §11.6.
|
|
90
|
+
*
|
|
91
|
+
* Returns null when the payload is not an AIDP envelope (e.g. the
|
|
92
|
+
* directory listing has no `directives` field) or when `access_control`
|
|
93
|
+
* has no actionable flags — callers MUST NOT emit the header in that
|
|
94
|
+
* case rather than emitting an empty value.
|
|
95
|
+
*/
|
|
96
|
+
export function buildContentUsage(payload) {
|
|
97
|
+
if (!payload || typeof payload !== 'object')
|
|
98
|
+
return null;
|
|
99
|
+
const directives = payload.directives;
|
|
100
|
+
if (!directives || typeof directives !== 'object')
|
|
101
|
+
return null;
|
|
102
|
+
const ac = directives.access_control;
|
|
103
|
+
if (!ac || typeof ac !== 'object')
|
|
104
|
+
return null;
|
|
105
|
+
const flags = ac;
|
|
106
|
+
const parts = [];
|
|
107
|
+
if (flags.allow_training === true)
|
|
108
|
+
parts.push('train-ai=y');
|
|
109
|
+
else if (flags.allow_training === false)
|
|
110
|
+
parts.push('train-ai=n');
|
|
111
|
+
if (flags.allow_derivative === true)
|
|
112
|
+
parts.push('search=y');
|
|
113
|
+
else if (flags.allow_derivative === false)
|
|
114
|
+
parts.push('search=n');
|
|
115
|
+
return parts.length > 0 ? parts.join(', ') : null;
|
|
116
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const SDK_VERSION: "0.0.
|
|
1
|
+
export declare const SDK_VERSION: "0.0.4";
|
|
2
2
|
export declare const SDK_USER_AGENT: string;
|
package/dist/runtime/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const SDK_VERSION = "0.0.
|
|
1
|
+
export const SDK_VERSION = "0.0.4";
|
|
2
2
|
export const SDK_USER_AGENT = `@speakspec/astro/${SDK_VERSION}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@speakspec/astro",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "AIDP 0.3 publishing channel for Astro 5 — exposes /.well-known/aidp.json and friends, fetches signed content + pointer payloads from SpeakSpec, receives §8.10 cache-invalidation webhooks.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|