@nshipster/sosumi 1.0.7 → 1.0.9
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.
- package/package.json +6 -7
- package/public/index.html +3 -1
- package/public/robots.txt +2 -0
- package/src/index.ts +188 -10
- package/src/lib/a2a.ts +676 -5
- package/src/lib/ard.ts +77 -0
- package/src/lib/auth.ts +105 -0
- package/src/lib/did.ts +40 -0
- package/src/lib/identity.ts +4 -0
- package/src/lib/mcp.ts +2 -1
- package/src/lib/webbotauth.ts +19 -120
- package/wrangler.jsonc +11 -1
package/src/lib/ard.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { PUBLISHER_DID, PUBLISHER_DOMAIN } from "./identity"
|
|
2
|
+
import { SKILL_NAME } from "./skill"
|
|
3
|
+
|
|
4
|
+
export const AI_CATALOG_MEDIA_TYPE = "application/ai-catalog+json"
|
|
5
|
+
|
|
6
|
+
export interface AiCatalogEntry {
|
|
7
|
+
identifier: string
|
|
8
|
+
displayName: string
|
|
9
|
+
type: string
|
|
10
|
+
url: string
|
|
11
|
+
description: string
|
|
12
|
+
representativeQueries: string[]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AiCatalog {
|
|
16
|
+
specVersion: string
|
|
17
|
+
host: {
|
|
18
|
+
displayName: string
|
|
19
|
+
identifier: string
|
|
20
|
+
documentationUrl: string
|
|
21
|
+
}
|
|
22
|
+
entries: AiCatalogEntry[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Build the ARD capability manifest for the origin serving the request. */
|
|
26
|
+
export function buildAiCatalog(origin: string): AiCatalog {
|
|
27
|
+
return {
|
|
28
|
+
specVersion: "1.0",
|
|
29
|
+
host: {
|
|
30
|
+
displayName: PUBLISHER_DOMAIN,
|
|
31
|
+
identifier: PUBLISHER_DID,
|
|
32
|
+
documentationUrl: `${origin}/`,
|
|
33
|
+
},
|
|
34
|
+
entries: [
|
|
35
|
+
{
|
|
36
|
+
identifier: `urn:air:${PUBLISHER_DOMAIN}:server:mcp`,
|
|
37
|
+
displayName: "Sosumi MCP Server",
|
|
38
|
+
type: "application/mcp-server-card+json",
|
|
39
|
+
url: `${origin}/.well-known/mcp/server-card.json`,
|
|
40
|
+
description:
|
|
41
|
+
"Searches and fetches Apple Developer documentation, Human Interface Guidelines, WWDC transcripts, and public Swift-DocC pages.",
|
|
42
|
+
representativeQueries: [
|
|
43
|
+
"Search Apple Developer documentation for URLSession",
|
|
44
|
+
"Fetch the SwiftUI View documentation as Markdown",
|
|
45
|
+
"Get the transcript for a WWDC session",
|
|
46
|
+
"Read a public Swift-DocC documentation page",
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
identifier: `urn:air:${PUBLISHER_DOMAIN}:agent:documentation`,
|
|
51
|
+
displayName: "Sosumi Documentation Agent",
|
|
52
|
+
type: "application/a2a-agent-card+json",
|
|
53
|
+
url: `${origin}/.well-known/agent-card.json`,
|
|
54
|
+
description:
|
|
55
|
+
"An A2A agent for searching and fetching Apple and Swift-DocC documentation as Markdown.",
|
|
56
|
+
representativeQueries: [
|
|
57
|
+
"Find Apple documentation about Swift actors",
|
|
58
|
+
"Fetch /documentation/swiftui/view as Markdown",
|
|
59
|
+
"Fetch the transcript for /videos/play/wwdc2021/10133",
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
identifier: `urn:air:${PUBLISHER_DOMAIN}:skill:${SKILL_NAME}`,
|
|
64
|
+
displayName: "Sosumi Agent Skill",
|
|
65
|
+
type: 'text/markdown; profile="urn:air:agent-skills"',
|
|
66
|
+
url: `${origin}/.well-known/agent-skills/${SKILL_NAME}/SKILL.md`,
|
|
67
|
+
description:
|
|
68
|
+
"Instructions for using Sosumi to research Apple APIs, design guidance, videos, and Swift-DocC documentation.",
|
|
69
|
+
representativeQueries: [
|
|
70
|
+
"Research an Apple framework API before writing code",
|
|
71
|
+
"Look up current SwiftUI documentation",
|
|
72
|
+
"Find Apple's design guidance for an interface",
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
}
|
|
77
|
+
}
|
package/src/lib/auth.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { jwkToKeyID, type Signer } from "web-bot-auth"
|
|
2
|
+
import { helpers, signerFromJWK } from "web-bot-auth/crypto"
|
|
3
|
+
|
|
4
|
+
/** The public half of the application's Ed25519 signing key. */
|
|
5
|
+
export interface PublicSigningKey {
|
|
6
|
+
kty: "OKP"
|
|
7
|
+
crv: "Ed25519"
|
|
8
|
+
x: string
|
|
9
|
+
kid: string
|
|
10
|
+
use: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface SigningKeyConfig {
|
|
14
|
+
signer: Signer
|
|
15
|
+
publicKey: PublicSigningKey
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Ed25519PrivateJwk {
|
|
19
|
+
kty: "OKP"
|
|
20
|
+
crv: "Ed25519"
|
|
21
|
+
x: string
|
|
22
|
+
d: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let cache: { key: string; config: Promise<SigningKeyConfig> } | null = null
|
|
26
|
+
|
|
27
|
+
/** Configure the application-wide signing key from a serialized private JWK. */
|
|
28
|
+
export function configureSigningKey(serializedKey?: string): void {
|
|
29
|
+
const key = serializedKey?.trim()
|
|
30
|
+
if (!key) {
|
|
31
|
+
cache = null
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (cache?.key === key) {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
cache = { key, config: buildSigningKeyConfig(key) }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Return the configured signer and public key, or null if unavailable. */
|
|
43
|
+
export async function currentSigningKey(): Promise<SigningKeyConfig | null> {
|
|
44
|
+
const entry = cache
|
|
45
|
+
if (!entry) {
|
|
46
|
+
return null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
return await entry.config
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error("auth: failed to load signing key", error)
|
|
53
|
+
if (cache === entry) {
|
|
54
|
+
cache = null
|
|
55
|
+
}
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Return a copy of the configured public signing key, if available. */
|
|
61
|
+
export async function currentPublicSigningKey(): Promise<PublicSigningKey | null> {
|
|
62
|
+
const config = await currentSigningKey()
|
|
63
|
+
return config ? { ...config.publicKey } : null
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function parseSigningJwk(key: string): Ed25519PrivateJwk {
|
|
67
|
+
let jwk: JsonWebKey
|
|
68
|
+
try {
|
|
69
|
+
jwk = JSON.parse(key) as JsonWebKey
|
|
70
|
+
} catch (error) {
|
|
71
|
+
throw new Error(`WEB_BOT_AUTH_KEY is not valid JSON: ${(error as Error).message}`)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (
|
|
75
|
+
jwk.kty !== "OKP" ||
|
|
76
|
+
jwk.crv !== "Ed25519" ||
|
|
77
|
+
typeof jwk.x !== "string" ||
|
|
78
|
+
jwk.x.length === 0 ||
|
|
79
|
+
typeof jwk.d !== "string" ||
|
|
80
|
+
jwk.d.length === 0
|
|
81
|
+
) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
"WEB_BOT_AUTH_KEY must be an Ed25519 private JSON Web Key (kty=OKP, crv=Ed25519, with x and d).",
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { kty: jwk.kty, crv: jwk.crv, x: jwk.x, d: jwk.d }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function buildSigningKeyConfig(key: string): Promise<SigningKeyConfig> {
|
|
91
|
+
const jwk = parseSigningJwk(key)
|
|
92
|
+
const signer = await signerFromJWK(jwk)
|
|
93
|
+
const kid = await jwkToKeyID(jwk, helpers.WEBCRYPTO_SHA256, helpers.BASE64URL_DECODE)
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
signer,
|
|
97
|
+
publicKey: {
|
|
98
|
+
kty: jwk.kty,
|
|
99
|
+
crv: jwk.crv,
|
|
100
|
+
x: jwk.x,
|
|
101
|
+
kid,
|
|
102
|
+
use: "sig",
|
|
103
|
+
},
|
|
104
|
+
}
|
|
105
|
+
}
|
package/src/lib/did.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { currentPublicSigningKey } from "./auth"
|
|
2
|
+
import { PUBLISHER_DID, PUBLISHER_ORIGIN } from "./identity"
|
|
3
|
+
|
|
4
|
+
export const DID_DOCUMENT_MEDIA_TYPE = "application/did+ld+json"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Build the did:web document for Sosumi's stable publisher identity.
|
|
8
|
+
* The verification method reuses the public half of the application signing
|
|
9
|
+
* key, which is configured out of band and never committed. Returns `null`
|
|
10
|
+
* rather than publishing an unverifiable identity when that key is unavailable.
|
|
11
|
+
*/
|
|
12
|
+
export async function buildDidDocument() {
|
|
13
|
+
const publicKey = await currentPublicSigningKey()
|
|
14
|
+
if (!publicKey) {
|
|
15
|
+
return null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const verificationMethodId = `${PUBLISHER_DID}#${publicKey.kid}`
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
"@context": ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/jws-2020/v1"],
|
|
22
|
+
id: PUBLISHER_DID,
|
|
23
|
+
alsoKnownAs: [PUBLISHER_ORIGIN],
|
|
24
|
+
verificationMethod: [
|
|
25
|
+
{
|
|
26
|
+
id: verificationMethodId,
|
|
27
|
+
type: "JsonWebKey2020",
|
|
28
|
+
controller: PUBLISHER_DID,
|
|
29
|
+
publicKeyJwk: {
|
|
30
|
+
kty: publicKey.kty,
|
|
31
|
+
crv: publicKey.crv,
|
|
32
|
+
x: publicKey.x,
|
|
33
|
+
kid: publicKey.kid,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
authentication: [verificationMethodId],
|
|
38
|
+
assertionMethod: [verificationMethodId],
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/lib/mcp.ts
CHANGED
|
@@ -4,13 +4,14 @@ import { z } from "zod"
|
|
|
4
4
|
import type { ExternalPolicyEnv } from "./external"
|
|
5
5
|
import { fetchExternalDocumentationMarkdown } from "./external"
|
|
6
6
|
import { fetchHIGPageData, renderHIGFromJSON } from "./hig"
|
|
7
|
+
import { PUBLISHER_DOMAIN } from "./identity"
|
|
7
8
|
import { fetchJSONData, renderFromJSON } from "./reference"
|
|
8
9
|
import { searchAppleDeveloperDocs } from "./search"
|
|
9
10
|
import { generateAppleDocUrl, normalizeDocumentationPath } from "./url"
|
|
10
11
|
import { fetchVideoTranscriptMarkdown } from "./video"
|
|
11
12
|
|
|
12
13
|
export const MCP_SERVER_INFO = {
|
|
13
|
-
name:
|
|
14
|
+
name: PUBLISHER_DOMAIN,
|
|
14
15
|
version: "1.0.0",
|
|
15
16
|
} as const
|
|
16
17
|
|
package/src/lib/webbotauth.ts
CHANGED
|
@@ -22,12 +22,11 @@
|
|
|
22
22
|
import {
|
|
23
23
|
directoryResponseHeaders,
|
|
24
24
|
HTTP_MESSAGE_SIGNATURES_DIRECTORY,
|
|
25
|
-
jwkToKeyID,
|
|
26
25
|
MediaType,
|
|
27
|
-
type Signer,
|
|
28
26
|
signatureHeaders,
|
|
29
27
|
} from "web-bot-auth"
|
|
30
|
-
import {
|
|
28
|
+
import { configureSigningKey, currentSigningKey, type PublicSigningKey } from "./auth"
|
|
29
|
+
import { PUBLISHER_ORIGIN } from "./identity"
|
|
31
30
|
|
|
32
31
|
export interface WebBotAuthEnv {
|
|
33
32
|
/**
|
|
@@ -45,7 +44,7 @@ export const DIRECTORY_PATH = HTTP_MESSAGE_SIGNATURES_DIRECTORY
|
|
|
45
44
|
/** Content type for the key directory response. */
|
|
46
45
|
export const DIRECTORY_MEDIA_TYPE = MediaType.HTTP_MESSAGE_SIGNATURES_DIRECTORY
|
|
47
46
|
|
|
48
|
-
const DEFAULT_SIGNATURE_AGENT =
|
|
47
|
+
const DEFAULT_SIGNATURE_AGENT = PUBLISHER_ORIGIN
|
|
49
48
|
|
|
50
49
|
/**
|
|
51
50
|
* How long an outbound request signature stays valid.
|
|
@@ -56,28 +55,7 @@ const OUTBOUND_SIGNATURE_TTL_MS = 5 * 60 * 1000
|
|
|
56
55
|
/** How long the directory self-signature stays valid. */
|
|
57
56
|
const DIRECTORY_SIGNATURE_TTL_MS = 60 * 60 * 1000
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
export interface DirectoryKey {
|
|
61
|
-
kty?: string
|
|
62
|
-
crv?: string
|
|
63
|
-
x?: string
|
|
64
|
-
kid: string
|
|
65
|
-
use: string
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
interface WebBotAuthConfig {
|
|
69
|
-
signer: Signer
|
|
70
|
-
publicKey: DirectoryKey
|
|
71
|
-
agent: string
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Cached, parsed configuration.
|
|
76
|
-
* The signing key is application-global (the same for every request),
|
|
77
|
-
* so it is memoized across requests in the isolate
|
|
78
|
-
* and only rebuilt when the underlying secret or agent changes.
|
|
79
|
-
*/
|
|
80
|
-
let cache: { key: string; agent: string; config: Promise<WebBotAuthConfig> } | null = null
|
|
58
|
+
let signatureAgent: string | null = null
|
|
81
59
|
|
|
82
60
|
/**
|
|
83
61
|
* Prime the signing configuration from the environment.
|
|
@@ -86,91 +64,8 @@ let cache: { key: string; agent: string; config: Promise<WebBotAuthConfig> } | n
|
|
|
86
64
|
*/
|
|
87
65
|
export function configureWebBotAuth(env: WebBotAuthEnv): void {
|
|
88
66
|
const key = env.WEB_BOT_AUTH_KEY?.trim()
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const agent = env.SIGNATURE_AGENT?.trim() || DEFAULT_SIGNATURE_AGENT
|
|
95
|
-
if (cache && cache.key === key && cache.agent === agent) {
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
cache = { key, agent, config: buildConfig(key, agent) }
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
interface Ed25519PrivateJwk {
|
|
103
|
-
kty: "OKP"
|
|
104
|
-
crv: "Ed25519"
|
|
105
|
-
x: string
|
|
106
|
-
d: string
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Parse and validate the signing secret as an Ed25519 OKP private JWK.
|
|
111
|
-
* Fails closed on anything malformed
|
|
112
|
-
* so a misconfigured `WEB_BOT_AUTH_KEY` never yields a broken directory key
|
|
113
|
-
* or unverifiable signatures.
|
|
114
|
-
*/
|
|
115
|
-
function parseSigningJwk(key: string): Ed25519PrivateJwk {
|
|
116
|
-
let jwk: JsonWebKey
|
|
117
|
-
try {
|
|
118
|
-
jwk = JSON.parse(key) as JsonWebKey
|
|
119
|
-
} catch (error) {
|
|
120
|
-
throw new Error(`WEB_BOT_AUTH_KEY is not valid JSON: ${(error as Error).message}`)
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (
|
|
124
|
-
jwk.kty !== "OKP" ||
|
|
125
|
-
jwk.crv !== "Ed25519" ||
|
|
126
|
-
typeof jwk.x !== "string" ||
|
|
127
|
-
jwk.x.length === 0 ||
|
|
128
|
-
typeof jwk.d !== "string" ||
|
|
129
|
-
jwk.d.length === 0
|
|
130
|
-
) {
|
|
131
|
-
throw new Error(
|
|
132
|
-
"WEB_BOT_AUTH_KEY must be an Ed25519 private JSON Web Key (kty=OKP, crv=Ed25519, with x and d).",
|
|
133
|
-
)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return { kty: jwk.kty, crv: jwk.crv, x: jwk.x, d: jwk.d }
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
async function buildConfig(key: string, agent: string): Promise<WebBotAuthConfig> {
|
|
140
|
-
const jwk = parseSigningJwk(key)
|
|
141
|
-
const signer = await signerFromJWK(jwk)
|
|
142
|
-
const kid = await jwkToKeyID(jwk, helpers.WEBCRYPTO_SHA256, helpers.BASE64URL_DECODE)
|
|
143
|
-
|
|
144
|
-
// Publish only the public half of the key (never the `d` parameter).
|
|
145
|
-
const publicKey: DirectoryKey = {
|
|
146
|
-
kty: jwk.kty,
|
|
147
|
-
crv: jwk.crv,
|
|
148
|
-
x: jwk.x,
|
|
149
|
-
kid,
|
|
150
|
-
use: "sig",
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return { signer, publicKey, agent }
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async function currentConfig(): Promise<WebBotAuthConfig | null> {
|
|
157
|
-
const entry = cache
|
|
158
|
-
if (!entry) {
|
|
159
|
-
return null
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
try {
|
|
163
|
-
return await entry.config
|
|
164
|
-
} catch (error) {
|
|
165
|
-
console.error("web-bot-auth: failed to load signing key", error)
|
|
166
|
-
// Drop the failed config so the next request rebuilds it,
|
|
167
|
-
// rather than serving the cached rejection until the isolate restarts.
|
|
168
|
-
// Guard against clobbering a newer config set by a concurrent reconfigure.
|
|
169
|
-
if (cache === entry) {
|
|
170
|
-
cache = null
|
|
171
|
-
}
|
|
172
|
-
return null
|
|
173
|
-
}
|
|
67
|
+
configureSigningKey(key)
|
|
68
|
+
signatureAgent = key ? env.SIGNATURE_AGENT?.trim() || DEFAULT_SIGNATURE_AGENT : null
|
|
174
69
|
}
|
|
175
70
|
|
|
176
71
|
/** Serialize a value as an RFC 8941 structured-field string (a quoted string). */
|
|
@@ -179,7 +74,7 @@ function structuredString(value: string): string {
|
|
|
179
74
|
}
|
|
180
75
|
|
|
181
76
|
export interface DirectoryResponse {
|
|
182
|
-
body: { keys:
|
|
77
|
+
body: { keys: PublicSigningKey[] }
|
|
183
78
|
headers: Record<string, string>
|
|
184
79
|
}
|
|
185
80
|
|
|
@@ -193,8 +88,8 @@ export interface DirectoryResponse {
|
|
|
193
88
|
* demonstrating control of the published key.
|
|
194
89
|
*/
|
|
195
90
|
export async function webBotAuthDirectory(requestUrl: string): Promise<DirectoryResponse | null> {
|
|
196
|
-
const
|
|
197
|
-
if (!
|
|
91
|
+
const signingKey = await currentSigningKey()
|
|
92
|
+
if (!signingKey) {
|
|
198
93
|
return null
|
|
199
94
|
}
|
|
200
95
|
|
|
@@ -205,10 +100,13 @@ export async function webBotAuthDirectory(requestUrl: string): Promise<Directory
|
|
|
205
100
|
request: { method: "GET", url: requestUrl, headers: {} as Record<string, string> },
|
|
206
101
|
}
|
|
207
102
|
|
|
208
|
-
const signature = await directoryResponseHeaders(message, [
|
|
103
|
+
const signature = await directoryResponseHeaders(message, [signingKey.signer], {
|
|
104
|
+
created,
|
|
105
|
+
expires,
|
|
106
|
+
})
|
|
209
107
|
|
|
210
108
|
return {
|
|
211
|
-
body: { keys: [
|
|
109
|
+
body: { keys: [signingKey.publicKey] },
|
|
212
110
|
headers: {
|
|
213
111
|
"Content-Type": DIRECTORY_MEDIA_TYPE,
|
|
214
112
|
Signature: signature.Signature,
|
|
@@ -228,13 +126,14 @@ export async function webBotAuthHeaders(
|
|
|
228
126
|
method: string,
|
|
229
127
|
url: string | URL,
|
|
230
128
|
): Promise<Record<string, string>> {
|
|
231
|
-
const
|
|
232
|
-
|
|
129
|
+
const signingKey = await currentSigningKey()
|
|
130
|
+
const agentValue = signatureAgent
|
|
131
|
+
if (!signingKey || !agentValue) {
|
|
233
132
|
return {}
|
|
234
133
|
}
|
|
235
134
|
|
|
236
135
|
try {
|
|
237
|
-
const agent = structuredString(
|
|
136
|
+
const agent = structuredString(agentValue)
|
|
238
137
|
// `signature-agent` must be present on the message
|
|
239
138
|
// so it is covered by the signature;
|
|
240
139
|
// the same value is returned for the outbound request.
|
|
@@ -245,7 +144,7 @@ export async function webBotAuthHeaders(
|
|
|
245
144
|
const expires = new Date(created.getTime() + OUTBOUND_SIGNATURE_TTL_MS)
|
|
246
145
|
const signature = await signatureHeaders(
|
|
247
146
|
{ method, url: url.toString(), headers },
|
|
248
|
-
|
|
147
|
+
signingKey.signer,
|
|
249
148
|
{ created, expires },
|
|
250
149
|
)
|
|
251
150
|
|
package/wrangler.jsonc
CHANGED
|
@@ -17,7 +17,17 @@
|
|
|
17
17
|
"assets": {
|
|
18
18
|
"binding": "ASSETS",
|
|
19
19
|
"directory": "./public",
|
|
20
|
-
"run_worker_first": [
|
|
20
|
+
"run_worker_first": [
|
|
21
|
+
"/",
|
|
22
|
+
"/.well-known/agent-card.json",
|
|
23
|
+
"/.well-known/agent-skills/*",
|
|
24
|
+
"/.well-known/security.txt",
|
|
25
|
+
"/message:send",
|
|
26
|
+
"/message:stream",
|
|
27
|
+
"/tasks",
|
|
28
|
+
"/tasks/*",
|
|
29
|
+
"/extendedAgentCard"
|
|
30
|
+
]
|
|
21
31
|
},
|
|
22
32
|
"observability": {
|
|
23
33
|
"enabled": true
|