Compare commits
	
		
			No commits in common. "3f93d8cabfe02a3981df3871f721b4f495cc8abd" and "1abfd74ec7114e5d8e2411f7a4fa10bdce97e277" have entirely different histories.
		
	
	
		
			3f93d8cabf
			...
			1abfd74ec7
		
	
		
							
								
								
									
										5
									
								
								.changeset/lucky-sloths-tie.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/lucky-sloths-tie.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
"@atproto/crypto": patch
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
Update noble crypto libraries
 | 
			
		||||
@ -30,10 +30,6 @@
 | 
			
		||||
                "type": "ref",
 | 
			
		||||
                "ref": "app.bsky.actor.defs#profileView"
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            "recId": {
 | 
			
		||||
              "type": "integer",
 | 
			
		||||
              "description": "Snowflake for this recommendation, use when submitting recommendation events."
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -29,10 +29,6 @@
 | 
			
		||||
              "type": "boolean",
 | 
			
		||||
              "description": "If true, response has fallen-back to generic results, and is not scoped using relativeToDid",
 | 
			
		||||
              "default": false
 | 
			
		||||
            },
 | 
			
		||||
            "recId": {
 | 
			
		||||
              "type": "integer",
 | 
			
		||||
              "description": "Snowflake for this recommendation, use when submitting recommendation events."
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -45,10 +45,6 @@
 | 
			
		||||
              "type": "string",
 | 
			
		||||
              "format": "did",
 | 
			
		||||
              "description": "DID of the account these suggestions are relative to. If this is returned undefined, suggestions are based on the viewer."
 | 
			
		||||
            },
 | 
			
		||||
            "recId": {
 | 
			
		||||
              "type": "integer",
 | 
			
		||||
              "description": "Snowflake for this recommendation, use when submitting recommendation events."
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,5 @@
 | 
			
		||||
# @atproto/api
 | 
			
		||||
 | 
			
		||||
## 0.13.27
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- [#3364](https://github.com/bluesky-social/atproto/pull/3364) [`e277158f7`](https://github.com/bluesky-social/atproto/commit/e277158f70a831b04fde3ec84b3c1eaa6ce82e9d) Thanks [@iwsmith](https://github.com/iwsmith)! - add recId to getSuggestions
 | 
			
		||||
 | 
			
		||||
## 0.13.26
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/api",
 | 
			
		||||
  "version": "0.13.27",
 | 
			
		||||
  "version": "0.13.26",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "Client library for atproto and Bluesky",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -12359,7 +12359,7 @@ export const schemaDict = {
 | 
			
		||||
              items: {
 | 
			
		||||
                type: 'string',
 | 
			
		||||
                description:
 | 
			
		||||
                  'If specified, only events where the action policies match any of the given policies are returned',
 | 
			
		||||
                  'If specified, only events where the policy matches the given policy are returned',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            cursor: {
 | 
			
		||||
 | 
			
		||||
@ -18,8 +18,6 @@ export type InputSchema = undefined
 | 
			
		||||
export interface OutputSchema {
 | 
			
		||||
  cursor?: string
 | 
			
		||||
  actors: AppBskyActorDefs.ProfileView[]
 | 
			
		||||
  /** Snowflake for this recommendation, use when submitting recommendation events. */
 | 
			
		||||
  recId?: number
 | 
			
		||||
  [k: string]: unknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -18,8 +18,6 @@ export interface OutputSchema {
 | 
			
		||||
  suggestions: AppBskyActorDefs.ProfileView[]
 | 
			
		||||
  /** If true, response has fallen-back to generic results, and is not scoped using relativeToDid */
 | 
			
		||||
  isFallback: boolean
 | 
			
		||||
  /** Snowflake for this recommendation, use when submitting recommendation events. */
 | 
			
		||||
  recId?: number
 | 
			
		||||
  [k: string]: unknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -24,8 +24,6 @@ export interface OutputSchema {
 | 
			
		||||
  actors: AppBskyUnspeccedDefs.SkeletonSearchActor[]
 | 
			
		||||
  /** DID of the account these suggestions are relative to. If this is returned undefined, suggestions are based on the viewer. */
 | 
			
		||||
  relativeToDid?: string
 | 
			
		||||
  /** Snowflake for this recommendation, use when submitting recommendation events. */
 | 
			
		||||
  recId?: number
 | 
			
		||||
  [k: string]: unknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,5 @@
 | 
			
		||||
# @atproto/aws
 | 
			
		||||
 | 
			
		||||
## 0.2.12
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`1abfd74ec`](https://github.com/bluesky-social/atproto/commit/1abfd74ec7114e5d8e2411f7a4fa10bdce97e277)]:
 | 
			
		||||
  - @atproto/crypto@0.4.3
 | 
			
		||||
  - @atproto/repo@0.6.2
 | 
			
		||||
 | 
			
		||||
## 0.2.11
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/aws",
 | 
			
		||||
  "version": "0.2.12",
 | 
			
		||||
  "version": "0.2.11",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "Shared AWS cloud API helpers for atproto services",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,25 +1,5 @@
 | 
			
		||||
# @atproto/bsky
 | 
			
		||||
 | 
			
		||||
## 0.0.106
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`e277158f7`](https://github.com/bluesky-social/atproto/commit/e277158f70a831b04fde3ec84b3c1eaa6ce82e9d)]:
 | 
			
		||||
  - @atproto/api@0.13.27
 | 
			
		||||
  - @atproto-labs/fetch-node@0.1.5
 | 
			
		||||
 | 
			
		||||
## 0.0.105
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`1abfd74ec`](https://github.com/bluesky-social/atproto/commit/1abfd74ec7114e5d8e2411f7a4fa10bdce97e277)]:
 | 
			
		||||
  - @atproto/crypto@0.4.3
 | 
			
		||||
  - @atproto/identity@0.4.5
 | 
			
		||||
  - @atproto/repo@0.6.2
 | 
			
		||||
  - @atproto/xrpc-server@0.7.6
 | 
			
		||||
  - @atproto/sync@0.1.9
 | 
			
		||||
  - @atproto-labs/xrpc-utils@0.0.2
 | 
			
		||||
 | 
			
		||||
## 0.0.104
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/bsky",
 | 
			
		||||
  "version": "0.0.106",
 | 
			
		||||
  "version": "0.0.104",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "Reference implementation of app.bsky App View (Bluesky API)",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -71,7 +71,6 @@ const skeleton = async (input: {
 | 
			
		||||
    return {
 | 
			
		||||
      dids: res.data.actors.map((a) => a.did),
 | 
			
		||||
      cursor: res.data.cursor,
 | 
			
		||||
      recId: res.data.recId,
 | 
			
		||||
      resHeaders: res.headers,
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
@ -130,7 +129,6 @@ const presentation = (input: {
 | 
			
		||||
  return {
 | 
			
		||||
    actors,
 | 
			
		||||
    cursor: skeleton.cursor,
 | 
			
		||||
    recId: skeleton.recId,
 | 
			
		||||
    resHeaders: skeleton.resHeaders,
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -150,6 +148,5 @@ type Params = QueryParams & {
 | 
			
		||||
type Skeleton = {
 | 
			
		||||
  dids: string[]
 | 
			
		||||
  cursor?: string
 | 
			
		||||
  recId?: number
 | 
			
		||||
  resHeaders?: Record<string, string>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -73,7 +73,6 @@ const skeleton = async (input: SkeletonFnInput<Context, Params>) => {
 | 
			
		||||
    return {
 | 
			
		||||
      isFallback: !res.data.relativeToDid,
 | 
			
		||||
      suggestedDids: res.data.actors.map((a) => a.did),
 | 
			
		||||
      recId: res.data.recId,
 | 
			
		||||
      headers: res.headers,
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
@ -116,12 +115,7 @@ const presentation = (
 | 
			
		||||
  const suggestions = mapDefined(suggestedDids, (did) =>
 | 
			
		||||
    ctx.views.profileDetailed(did, hydration),
 | 
			
		||||
  )
 | 
			
		||||
  return {
 | 
			
		||||
    isFallback: skeleton.isFallback,
 | 
			
		||||
    suggestions,
 | 
			
		||||
    recId: skeleton.recId,
 | 
			
		||||
    headers,
 | 
			
		||||
  }
 | 
			
		||||
  return { isFallback: skeleton.isFallback, suggestions, headers }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Context = {
 | 
			
		||||
@ -139,6 +133,5 @@ type Params = QueryParams & {
 | 
			
		||||
type SkeletonState = {
 | 
			
		||||
  isFallback: boolean
 | 
			
		||||
  suggestedDids: string[]
 | 
			
		||||
  recId?: number
 | 
			
		||||
  headers?: Record<string, string>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,8 +19,6 @@ export type InputSchema = undefined
 | 
			
		||||
export interface OutputSchema {
 | 
			
		||||
  cursor?: string
 | 
			
		||||
  actors: AppBskyActorDefs.ProfileView[]
 | 
			
		||||
  /** Snowflake for this recommendation, use when submitting recommendation events. */
 | 
			
		||||
  recId?: number
 | 
			
		||||
  [k: string]: unknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,8 +19,6 @@ export interface OutputSchema {
 | 
			
		||||
  suggestions: AppBskyActorDefs.ProfileView[]
 | 
			
		||||
  /** If true, response has fallen-back to generic results, and is not scoped using relativeToDid */
 | 
			
		||||
  isFallback?: boolean
 | 
			
		||||
  /** Snowflake for this recommendation, use when submitting recommendation events. */
 | 
			
		||||
  recId?: number
 | 
			
		||||
  [k: string]: unknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -25,8 +25,6 @@ export interface OutputSchema {
 | 
			
		||||
  actors: AppBskyUnspeccedDefs.SkeletonSearchActor[]
 | 
			
		||||
  /** DID of the account these suggestions are relative to. If this is returned undefined, suggestions are based on the viewer. */
 | 
			
		||||
  relativeToDid?: string
 | 
			
		||||
  /** Snowflake for this recommendation, use when submitting recommendation events. */
 | 
			
		||||
  recId?: number
 | 
			
		||||
  [k: string]: unknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,5 @@
 | 
			
		||||
# @atproto/crypto
 | 
			
		||||
 | 
			
		||||
## 0.4.3
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- [#3335](https://github.com/bluesky-social/atproto/pull/3335) [`1abfd74ec`](https://github.com/bluesky-social/atproto/commit/1abfd74ec7114e5d8e2411f7a4fa10bdce97e277) Thanks [@dholms](https://github.com/dholms)! - Update noble crypto libraries
 | 
			
		||||
 | 
			
		||||
## 0.4.2
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/crypto",
 | 
			
		||||
  "version": "0.4.3",
 | 
			
		||||
  "version": "0.4.2",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "Library for cryptographic keys and signing in atproto",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,30 +1,5 @@
 | 
			
		||||
# @atproto/dev-env
 | 
			
		||||
 | 
			
		||||
## 0.3.76
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- [#3344](https://github.com/bluesky-social/atproto/pull/3344) [`48a0e9d60`](https://github.com/bluesky-social/atproto/commit/48a0e9d6060c2dc93899f13f2fc7cc76c04fbcd9) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Properly dispose of unused http responses
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`48a0e9d60`](https://github.com/bluesky-social/atproto/commit/48a0e9d6060c2dc93899f13f2fc7cc76c04fbcd9), [`e277158f7`](https://github.com/bluesky-social/atproto/commit/e277158f70a831b04fde3ec84b3c1eaa6ce82e9d)]:
 | 
			
		||||
  - @atproto/ozone@0.1.67
 | 
			
		||||
  - @atproto/api@0.13.27
 | 
			
		||||
  - @atproto/bsky@0.0.106
 | 
			
		||||
  - @atproto/pds@0.4.84
 | 
			
		||||
 | 
			
		||||
## 0.3.75
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`1abfd74ec`](https://github.com/bluesky-social/atproto/commit/1abfd74ec7114e5d8e2411f7a4fa10bdce97e277)]:
 | 
			
		||||
  - @atproto/crypto@0.4.3
 | 
			
		||||
  - @atproto/bsky@0.0.105
 | 
			
		||||
  - @atproto/identity@0.4.5
 | 
			
		||||
  - @atproto/ozone@0.1.66
 | 
			
		||||
  - @atproto/pds@0.4.83
 | 
			
		||||
  - @atproto/xrpc-server@0.7.6
 | 
			
		||||
  - @atproto/sync@0.1.9
 | 
			
		||||
 | 
			
		||||
## 0.3.74
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/dev-env",
 | 
			
		||||
  "version": "0.3.76",
 | 
			
		||||
  "version": "0.3.74",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "Local development environment helper for atproto development",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -45,7 +45,7 @@ export const mockResolvers = (idResolver: IdResolver, pds: TestPds) => {
 | 
			
		||||
    try {
 | 
			
		||||
      const res = await request(url, { headers: { host: handle } })
 | 
			
		||||
      if (res.statusCode !== 200) {
 | 
			
		||||
        await res.body.dump()
 | 
			
		||||
        res.body.destroy()
 | 
			
		||||
        return undefined
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,5 @@
 | 
			
		||||
# @atproto/identity
 | 
			
		||||
 | 
			
		||||
## 0.4.5
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`1abfd74ec`](https://github.com/bluesky-social/atproto/commit/1abfd74ec7114e5d8e2411f7a4fa10bdce97e277)]:
 | 
			
		||||
  - @atproto/crypto@0.4.3
 | 
			
		||||
 | 
			
		||||
## 0.4.4
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/identity",
 | 
			
		||||
  "version": "0.4.5",
 | 
			
		||||
  "version": "0.4.4",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "Library for decentralized identities in atproto using DIDs and handles",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,5 @@
 | 
			
		||||
# @atproto-labs/did-resolver
 | 
			
		||||
 | 
			
		||||
## 0.1.8
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`5ece8c6ae`](https://github.com/bluesky-social/atproto/commit/5ece8c6aeab9c5c3f51295d93ed6e27c3c6095c2), [`5ece8c6ae`](https://github.com/bluesky-social/atproto/commit/5ece8c6aeab9c5c3f51295d93ed6e27c3c6095c2)]:
 | 
			
		||||
  - @atproto-labs/fetch@0.2.0
 | 
			
		||||
 | 
			
		||||
## 0.1.7
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto-labs/did-resolver",
 | 
			
		||||
  "version": "0.1.8",
 | 
			
		||||
  "version": "0.1.7",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "DID resolution and verification library",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,5 @@
 | 
			
		||||
# @atproto-labs/fetch-node
 | 
			
		||||
 | 
			
		||||
## 0.1.5
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`5ece8c6ae`](https://github.com/bluesky-social/atproto/commit/5ece8c6aeab9c5c3f51295d93ed6e27c3c6095c2), [`5ece8c6ae`](https://github.com/bluesky-social/atproto/commit/5ece8c6aeab9c5c3f51295d93ed6e27c3c6095c2)]:
 | 
			
		||||
  - @atproto-labs/fetch@0.2.0
 | 
			
		||||
 | 
			
		||||
## 0.1.4
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto-labs/fetch-node",
 | 
			
		||||
  "version": "0.1.5",
 | 
			
		||||
  "version": "0.1.4",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "SSRF protection for fetch() in Node.js",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,5 @@
 | 
			
		||||
# @atproto-labs/fetch
 | 
			
		||||
 | 
			
		||||
## 0.2.0
 | 
			
		||||
 | 
			
		||||
### Minor Changes
 | 
			
		||||
 | 
			
		||||
- [#3343](https://github.com/bluesky-social/atproto/pull/3343) [`5ece8c6ae`](https://github.com/bluesky-social/atproto/commit/5ece8c6aeab9c5c3f51295d93ed6e27c3c6095c2) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Fix typo in `ResponseTranformer` and `fetchResponseJsonTranformer`
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- [#3343](https://github.com/bluesky-social/atproto/pull/3343) [`5ece8c6ae`](https://github.com/bluesky-social/atproto/commit/5ece8c6aeab9c5c3f51295d93ed6e27c3c6095c2) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Response mime type check is now case-insensitive (as per rfc2616)
 | 
			
		||||
 | 
			
		||||
## 0.1.2
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto-labs/fetch",
 | 
			
		||||
  "version": "0.2.0",
 | 
			
		||||
  "version": "0.1.2",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "Isomorphic wrapper utilities for fetch API",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -14,24 +14,7 @@ import {
 | 
			
		||||
  logCancellationError,
 | 
			
		||||
} from './util.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * media-type     = type "/" subtype *( ";" parameter )
 | 
			
		||||
 * type           = token
 | 
			
		||||
 * subtype        = token
 | 
			
		||||
 * token          = 1*<any CHAR except CTLs or separators>
 | 
			
		||||
 * separators     = "(" | ")" | "<" | ">" | "@"
 | 
			
		||||
 *                | "," | ";" | ":" | "\" | <">
 | 
			
		||||
 *                | "/" | "[" | "]" | "?" | "="
 | 
			
		||||
 *                | "{" | "}" | SP | HT
 | 
			
		||||
 * CTL            = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
 | 
			
		||||
 * SP             = <US-ASCII SP, space (32)>
 | 
			
		||||
 * HT             = <US-ASCII HT, horizontal-tab (9)>
 | 
			
		||||
 * @note The type, subtype, and parameter attribute names are case-insensitive.
 | 
			
		||||
 * @see {@link https://datatracker.ietf.org/doc/html/rfc2616#autoid-23}
 | 
			
		||||
 */
 | 
			
		||||
const JSON_MIME = /^application\/(?:[^()<>@,;:/[\]\\?={} \t]+\+)?json$/i
 | 
			
		||||
 | 
			
		||||
export type ResponseTransformer = Transformer<Response>
 | 
			
		||||
export type ResponseTranformer = Transformer<Response>
 | 
			
		||||
export type ResponseMessageGetter = Transformer<Response, string | undefined>
 | 
			
		||||
 | 
			
		||||
export class FetchResponseError extends FetchError {
 | 
			
		||||
@ -68,7 +51,7 @@ const extractResponseMessage: ResponseMessageGetter = async (response) => {
 | 
			
		||||
  try {
 | 
			
		||||
    if (mimeType === 'text/plain') {
 | 
			
		||||
      return await response.text()
 | 
			
		||||
    } else if (JSON_MIME.test(mimeType)) {
 | 
			
		||||
    } else if (/^application\/(?:[^+]+\+)?json$/i.test(mimeType)) {
 | 
			
		||||
      const json: unknown = await response.json()
 | 
			
		||||
 | 
			
		||||
      if (typeof json === 'string') return json
 | 
			
		||||
@ -172,7 +155,7 @@ export function cancelBodyOnError<T>(
 | 
			
		||||
 | 
			
		||||
export function fetchOkProcessor(
 | 
			
		||||
  customMessage?: string | ResponseMessageGetter,
 | 
			
		||||
): ResponseTransformer {
 | 
			
		||||
): ResponseTranformer {
 | 
			
		||||
  return cancelBodyOnError((response) => {
 | 
			
		||||
    return fetchOkTransformer(response, customMessage)
 | 
			
		||||
  })
 | 
			
		||||
@ -186,7 +169,7 @@ export async function fetchOkTransformer(
 | 
			
		||||
  throw await FetchResponseError.from(response, customMessage)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function fetchMaxSizeProcessor(maxBytes: number): ResponseTransformer {
 | 
			
		||||
export function fetchMaxSizeProcessor(maxBytes: number): ResponseTranformer {
 | 
			
		||||
  if (maxBytes === Infinity) return (response) => response
 | 
			
		||||
  if (!Number.isFinite(maxBytes) || maxBytes < 0) {
 | 
			
		||||
    throw new TypeError('maxBytes must be a 0, Infinity or a positive number')
 | 
			
		||||
@ -217,7 +200,7 @@ export type MimeTypeCheck = string | RegExp | MimeTypeCheckFn
 | 
			
		||||
export function fetchTypeProcessor(
 | 
			
		||||
  expectedMime: MimeTypeCheck,
 | 
			
		||||
  contentTypeRequired = true,
 | 
			
		||||
): ResponseTransformer {
 | 
			
		||||
): ResponseTranformer {
 | 
			
		||||
  const isExpected: MimeTypeCheckFn =
 | 
			
		||||
    typeof expectedMime === 'string'
 | 
			
		||||
      ? (mimeType) => mimeType === expectedMime
 | 
			
		||||
@ -237,7 +220,7 @@ export async function fetchResponseTypeChecker(
 | 
			
		||||
): Promise<Response> {
 | 
			
		||||
  const mimeType = extractMime(response)
 | 
			
		||||
  if (mimeType) {
 | 
			
		||||
    if (!isExpectedMime(mimeType.toLowerCase())) {
 | 
			
		||||
    if (!isExpectedMime(mimeType)) {
 | 
			
		||||
      throw await FetchResponseError.from(
 | 
			
		||||
        response,
 | 
			
		||||
        `Unexpected response Content-Type (${mimeType})`,
 | 
			
		||||
@ -260,7 +243,7 @@ export type ParsedJsonResponse<T = Json> = {
 | 
			
		||||
  json: T
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function fetchResponseJsonTransformer<T = Json>(
 | 
			
		||||
export async function fetchResponseJsonTranformer<T = Json>(
 | 
			
		||||
  response: Response,
 | 
			
		||||
): Promise<ParsedJsonResponse<T>> {
 | 
			
		||||
  try {
 | 
			
		||||
@ -277,12 +260,12 @@ export async function fetchResponseJsonTransformer<T = Json>(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function fetchJsonProcessor<T = Json>(
 | 
			
		||||
  expectedMime: MimeTypeCheck = JSON_MIME,
 | 
			
		||||
  expectedMime: MimeTypeCheck = /^application\/(?:[^+]+\+)?json$/,
 | 
			
		||||
  contentTypeRequired = true,
 | 
			
		||||
): Transformer<Response, ParsedJsonResponse<T>> {
 | 
			
		||||
  return pipe(
 | 
			
		||||
    fetchTypeProcessor(expectedMime, contentTypeRequired),
 | 
			
		||||
    cancelBodyOnError(fetchResponseJsonTransformer<T>),
 | 
			
		||||
    cancelBodyOnError(fetchResponseJsonTranformer<T>),
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,5 @@
 | 
			
		||||
# @atproto-labs/handle-resolver-node
 | 
			
		||||
 | 
			
		||||
## 0.1.10
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies []:
 | 
			
		||||
  - @atproto-labs/fetch-node@0.1.5
 | 
			
		||||
 | 
			
		||||
## 0.1.9
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto-labs/handle-resolver-node",
 | 
			
		||||
  "version": "0.1.10",
 | 
			
		||||
  "version": "0.1.9",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "Node specific ATProto handle to DID resolver",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,5 @@
 | 
			
		||||
# @atproto-labs/identity-resolver
 | 
			
		||||
 | 
			
		||||
## 0.1.10
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies []:
 | 
			
		||||
  - @atproto-labs/did-resolver@0.1.8
 | 
			
		||||
 | 
			
		||||
## 0.1.9
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto-labs/identity-resolver",
 | 
			
		||||
  "version": "0.1.10",
 | 
			
		||||
  "version": "0.1.9",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "A library resolving ATPROTO identities",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,5 @@
 | 
			
		||||
# @atproto-labs/xrpc-utils
 | 
			
		||||
 | 
			
		||||
## 0.0.2
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies []:
 | 
			
		||||
  - @atproto/xrpc-server@0.7.6
 | 
			
		||||
 | 
			
		||||
## 0.0.1
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto-labs/xrpc-utils",
 | 
			
		||||
  "version": "0.0.2",
 | 
			
		||||
  "version": "0.0.1",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "XRPC server utilities for Node.JS",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,16 +1,5 @@
 | 
			
		||||
# @atproto/jwk-jose
 | 
			
		||||
 | 
			
		||||
## 0.1.3
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- [#2879](https://github.com/bluesky-social/atproto/pull/2879) [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Improve compatibility with runtimes relying on webcrypto (by explicit JOSE's importJWK() "alg" argument).
 | 
			
		||||
 | 
			
		||||
- [#2879](https://github.com/bluesky-social/atproto/pull/2879) [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Remove unsafe type casting during JWT verification
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0)]:
 | 
			
		||||
  - @atproto/jwk@0.1.2
 | 
			
		||||
 | 
			
		||||
## 0.1.2
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/jwk-jose",
 | 
			
		||||
  "version": "0.1.3",
 | 
			
		||||
  "version": "0.1.2",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "`jose` based implementation of @atproto/jwk Key's",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,19 +1,4 @@
 | 
			
		||||
import {
 | 
			
		||||
  Jwk,
 | 
			
		||||
  JwkError,
 | 
			
		||||
  JwtCreateError,
 | 
			
		||||
  JwtHeader,
 | 
			
		||||
  JwtPayload,
 | 
			
		||||
  JwtVerifyError,
 | 
			
		||||
  Key,
 | 
			
		||||
  RequiredKey,
 | 
			
		||||
  SignedJwt,
 | 
			
		||||
  VerifyOptions,
 | 
			
		||||
  VerifyResult,
 | 
			
		||||
  jwkValidator,
 | 
			
		||||
  jwtHeaderSchema,
 | 
			
		||||
  jwtPayloadSchema,
 | 
			
		||||
} from '@atproto/jwk'
 | 
			
		||||
import { JwtVerifyError } from '@atproto/jwk'
 | 
			
		||||
import {
 | 
			
		||||
  SignJWT,
 | 
			
		||||
  errors,
 | 
			
		||||
@ -29,6 +14,19 @@ import {
 | 
			
		||||
  type KeyLike,
 | 
			
		||||
} from 'jose'
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  Jwk,
 | 
			
		||||
  JwkError,
 | 
			
		||||
  JwtCreateError,
 | 
			
		||||
  JwtHeader,
 | 
			
		||||
  JwtPayload,
 | 
			
		||||
  Key,
 | 
			
		||||
  SignedJwt,
 | 
			
		||||
  VerifyOptions,
 | 
			
		||||
  VerifyPayload,
 | 
			
		||||
  VerifyResult,
 | 
			
		||||
  jwkValidator,
 | 
			
		||||
} from '@atproto/jwk'
 | 
			
		||||
import { either } from './util'
 | 
			
		||||
 | 
			
		||||
const { JOSEError } = errors
 | 
			
		||||
@ -37,97 +35,53 @@ export type Importable = string | KeyLike | Jwk
 | 
			
		||||
 | 
			
		||||
export type { GenerateKeyPairOptions, GenerateKeyPairResult }
 | 
			
		||||
 | 
			
		||||
export class JoseKey<J extends Jwk = Jwk> extends Key<J> {
 | 
			
		||||
  /**
 | 
			
		||||
   * Some runtimes (e.g. Bun) require an `alg` second argument to be set when
 | 
			
		||||
   * invoking `importJWK`. In order to be compatible with these runtimes, we
 | 
			
		||||
   * provide the following method to ensure the `alg` is always set. We also
 | 
			
		||||
   * take the opportunity to ensure that the `alg` is compatible with this key.
 | 
			
		||||
   */
 | 
			
		||||
  protected async getKeyObj(alg: string) {
 | 
			
		||||
    if (!this.algorithms.includes(alg)) {
 | 
			
		||||
      throw new JwkError(`Key cannot be used with algorithm "${alg}"`)
 | 
			
		||||
    }
 | 
			
		||||
export class JoseKey extends Key {
 | 
			
		||||
  #keyObj?: KeyLike | Uint8Array
 | 
			
		||||
 | 
			
		||||
  protected async getKey() {
 | 
			
		||||
    try {
 | 
			
		||||
      return await importJWK(this.jwk as JWK, alg)
 | 
			
		||||
      return (this.#keyObj ||= await importJWK(this.jwk as JWK))
 | 
			
		||||
    } catch (cause) {
 | 
			
		||||
      throw new JwkError('Failed to import JWK', undefined, { cause })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async createJwt(header: JwtHeader, payload: JwtPayload): Promise<SignedJwt> {
 | 
			
		||||
    try {
 | 
			
		||||
      const { kid } = header
 | 
			
		||||
      if (kid && kid !== this.kid) {
 | 
			
		||||
        throw new JwtCreateError(
 | 
			
		||||
          `Invalid "kid" (${kid}) used to sign with key "${this.kid}"`,
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const { alg } = header
 | 
			
		||||
      if (!alg) {
 | 
			
		||||
        throw new JwtCreateError('Missing "alg" in JWT header')
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const keyObj = await this.getKeyObj(alg)
 | 
			
		||||
      const jwtBuilder = new SignJWT(payload).setProtectedHeader({
 | 
			
		||||
        ...header,
 | 
			
		||||
        alg,
 | 
			
		||||
        kid: this.kid,
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      const signedJwt = await jwtBuilder.sign(keyObj)
 | 
			
		||||
 | 
			
		||||
      return signedJwt as SignedJwt
 | 
			
		||||
    } catch (cause) {
 | 
			
		||||
      if (cause instanceof JOSEError) {
 | 
			
		||||
        throw new JwtCreateError(cause.message, cause.code, { cause })
 | 
			
		||||
      } else {
 | 
			
		||||
        throw JwtCreateError.from(cause)
 | 
			
		||||
      }
 | 
			
		||||
  async createJwt(header: JwtHeader, payload: JwtPayload) {
 | 
			
		||||
    if (header.kid && header.kid !== this.kid) {
 | 
			
		||||
      throw new JwtCreateError(
 | 
			
		||||
        `Invalid "kid" (${header.kid}) used to sign with key "${this.kid}"`,
 | 
			
		||||
      )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!header.alg || !this.algorithms.includes(header.alg)) {
 | 
			
		||||
      throw new JwtCreateError(
 | 
			
		||||
        `Invalid "alg" (${header.alg}) used to sign with key "${this.kid}"`,
 | 
			
		||||
      )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const keyObj = await this.getKey()
 | 
			
		||||
    return new SignJWT(payload)
 | 
			
		||||
      .setProtectedHeader({ ...header, kid: this.kid })
 | 
			
		||||
      .sign(keyObj) as Promise<SignedJwt>
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async verifyJwt<C extends string = never>(
 | 
			
		||||
    token: SignedJwt,
 | 
			
		||||
    options?: VerifyOptions<C>,
 | 
			
		||||
  ): Promise<VerifyResult<C>> {
 | 
			
		||||
  async verifyJwt<
 | 
			
		||||
    P extends VerifyPayload = JwtPayload,
 | 
			
		||||
    C extends string = string,
 | 
			
		||||
  >(token: SignedJwt, options?: VerifyOptions<C>): Promise<VerifyResult<P, C>> {
 | 
			
		||||
    try {
 | 
			
		||||
      const result = await jwtVerify(
 | 
			
		||||
        token,
 | 
			
		||||
        async ({ alg }) => this.getKeyObj(alg),
 | 
			
		||||
        { ...options, algorithms: this.algorithms } as JWTVerifyOptions,
 | 
			
		||||
      )
 | 
			
		||||
      const keyObj = await this.getKey()
 | 
			
		||||
      const result = await jwtVerify(token, keyObj, {
 | 
			
		||||
        ...options,
 | 
			
		||||
        algorithms: this.algorithms,
 | 
			
		||||
      } as JWTVerifyOptions)
 | 
			
		||||
 | 
			
		||||
      // @NOTE if all tokens are signed exclusively through createJwt(), then
 | 
			
		||||
      // there should be no need to parse the payload and headers here. But
 | 
			
		||||
      // since the JWT could have been signed with the same key from somewhere
 | 
			
		||||
      // else, let's parse it to ensure the integrity (and type safety) of the
 | 
			
		||||
      // data.
 | 
			
		||||
      const headerParsed = jwtHeaderSchema.safeParse(result.protectedHeader)
 | 
			
		||||
      if (!headerParsed.success) {
 | 
			
		||||
        throw new JwtVerifyError('Invalid JWT header', undefined, {
 | 
			
		||||
          cause: headerParsed.error,
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const payloadParsed = jwtPayloadSchema.safeParse(result.payload)
 | 
			
		||||
      if (!payloadParsed.success) {
 | 
			
		||||
        throw new JwtVerifyError('Invalid JWT payload', undefined, {
 | 
			
		||||
          cause: payloadParsed.error,
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
        protectedHeader: headerParsed.data,
 | 
			
		||||
        // "requiredClaims" enforced by jwtVerify()
 | 
			
		||||
        payload: payloadParsed.data as RequiredKey<JwtPayload, C>,
 | 
			
		||||
      }
 | 
			
		||||
    } catch (cause) {
 | 
			
		||||
      if (cause instanceof JOSEError) {
 | 
			
		||||
        throw new JwtVerifyError(cause.message, cause.code, { cause })
 | 
			
		||||
      return result as VerifyResult<P, C>
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      if (error instanceof JOSEError) {
 | 
			
		||||
        throw new JwtVerifyError(error.message, error.code, { cause: error })
 | 
			
		||||
      } else {
 | 
			
		||||
        throw JwtVerifyError.from(cause)
 | 
			
		||||
        throw JwtVerifyError.from(error)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,5 @@
 | 
			
		||||
# @atproto/jwk-webcrypto
 | 
			
		||||
 | 
			
		||||
## 0.1.3
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0)]:
 | 
			
		||||
  - @atproto/jwk@0.1.2
 | 
			
		||||
  - @atproto/jwk-jose@0.1.3
 | 
			
		||||
 | 
			
		||||
## 0.1.2
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/jwk-webcrypto",
 | 
			
		||||
  "version": "0.1.3",
 | 
			
		||||
  "version": "0.1.2",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "Webcrypto based implementation of @atproto/jwk Key's",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
@ -25,8 +25,7 @@
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@atproto/jwk": "workspace:*",
 | 
			
		||||
    "@atproto/jwk-jose": "workspace:*",
 | 
			
		||||
    "zod": "^3.23.8"
 | 
			
		||||
    "@atproto/jwk-jose": "workspace:*"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "typescript": "^5.6.3"
 | 
			
		||||
 | 
			
		||||
@ -1,20 +1,9 @@
 | 
			
		||||
import { JwkError, jwkSchema } from '@atproto/jwk'
 | 
			
		||||
import { Jwk, jwkSchema } from '@atproto/jwk'
 | 
			
		||||
import { GenerateKeyPairOptions, JoseKey } from '@atproto/jwk-jose'
 | 
			
		||||
import z from 'zod'
 | 
			
		||||
 | 
			
		||||
import { fromSubtleAlgorithm, isCryptoKeyPair } from './util.js'
 | 
			
		||||
 | 
			
		||||
// Webcrypto keys are bound to a single algorithm
 | 
			
		||||
export const jwkWithAlgSchema = z.intersection(
 | 
			
		||||
  jwkSchema,
 | 
			
		||||
  z.object({ alg: z.string() }),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
export type JwkWithAlg = z.infer<typeof jwkWithAlgSchema>
 | 
			
		||||
 | 
			
		||||
export class WebcryptoKey<
 | 
			
		||||
  J extends JwkWithAlg = JwkWithAlg,
 | 
			
		||||
> extends JoseKey<J> {
 | 
			
		||||
export class WebcryptoKey extends JoseKey {
 | 
			
		||||
  // We need to override the static method generate from JoseKey because
 | 
			
		||||
  // the browser needs both the private and public keys
 | 
			
		||||
  static override async generate(
 | 
			
		||||
@ -37,35 +26,29 @@ export class WebcryptoKey<
 | 
			
		||||
    // > The "use" and "key_ops" JWK members SHOULD NOT be used together; [...]
 | 
			
		||||
    // > Applications should specify which of these members they use.
 | 
			
		||||
 | 
			
		||||
    const {
 | 
			
		||||
      key_ops,
 | 
			
		||||
      use,
 | 
			
		||||
      alg = fromSubtleAlgorithm(cryptoKeyPair.privateKey.algorithm),
 | 
			
		||||
      ...jwk
 | 
			
		||||
    } = await crypto.subtle.exportKey(
 | 
			
		||||
    const { key_ops: _, ...jwk } = await crypto.subtle.exportKey(
 | 
			
		||||
      'jwk',
 | 
			
		||||
      cryptoKeyPair.privateKey.extractable
 | 
			
		||||
        ? cryptoKeyPair.privateKey
 | 
			
		||||
        : cryptoKeyPair.publicKey,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    if (use && use !== 'sig') {
 | 
			
		||||
      throw new TypeError(`Unsupported JWK use "${use}"`)
 | 
			
		||||
    }
 | 
			
		||||
    const use = jwk.use ?? 'sig'
 | 
			
		||||
    const alg =
 | 
			
		||||
      jwk.alg ?? fromSubtleAlgorithm(cryptoKeyPair.privateKey.algorithm)
 | 
			
		||||
 | 
			
		||||
    if (key_ops && !key_ops.some((o) => o === 'sign' || o === 'verify')) {
 | 
			
		||||
      // Make sure that "key_ops", if present, is compatible with "use"
 | 
			
		||||
      throw new TypeError(`Invalid key_ops "${key_ops}" for "sig" use`)
 | 
			
		||||
    if (use !== 'sig') {
 | 
			
		||||
      throw new TypeError('Unsupported JWK use')
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return new WebcryptoKey(
 | 
			
		||||
      jwkWithAlgSchema.parse({ ...jwk, kid, alg, use: 'sig' }),
 | 
			
		||||
      jwkSchema.parse({ ...jwk, use, kid, alg }),
 | 
			
		||||
      cryptoKeyPair,
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    jwk: Readonly<J>,
 | 
			
		||||
    jwk: Jwk,
 | 
			
		||||
    readonly cryptoKeyPair: CryptoKeyPair,
 | 
			
		||||
  ) {
 | 
			
		||||
    super(jwk)
 | 
			
		||||
@ -75,15 +58,12 @@ export class WebcryptoKey<
 | 
			
		||||
    return true
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get privateJwk(): Readonly<J> | undefined {
 | 
			
		||||
  get privateJwk(): Jwk | undefined {
 | 
			
		||||
    if (super.isPrivate) return this.jwk
 | 
			
		||||
    throw new Error('Private Webcrypto Key not exportable')
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected override async getKeyObj(alg: string) {
 | 
			
		||||
    if (this.jwk.alg !== alg) {
 | 
			
		||||
      throw new JwkError(`Key cannot be used with algorithm "${alg}"`)
 | 
			
		||||
    }
 | 
			
		||||
  protected override async getKey() {
 | 
			
		||||
    return this.cryptoKeyPair.privateKey
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,17 +1,5 @@
 | 
			
		||||
# @atproto/jwk
 | 
			
		||||
 | 
			
		||||
## 0.1.2
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- [#2879](https://github.com/bluesky-social/atproto/pull/2879) [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Mark jwk key fields as readonly
 | 
			
		||||
 | 
			
		||||
- [#2879](https://github.com/bluesky-social/atproto/pull/2879) [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Remove unsafe type casting during JWT verification
 | 
			
		||||
 | 
			
		||||
- [#2879](https://github.com/bluesky-social/atproto/pull/2879) [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Allow (passthrough) unknown properties in JWT payload & headers
 | 
			
		||||
 | 
			
		||||
- [#2879](https://github.com/bluesky-social/atproto/pull/2879) [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Expose ValidationError to allow for proper error handling
 | 
			
		||||
 | 
			
		||||
## 0.1.1
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/jwk",
 | 
			
		||||
  "version": "0.1.2",
 | 
			
		||||
  "version": "0.1.1",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "A library for working with JSON Web Keys (JWKs) in TypeScript. This is meant to be extended by environment-specific libraries like @atproto/jwk-jose.",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,3 @@
 | 
			
		||||
// Since we expose zod schemas, let's expose ZodError (under a generic name) so
 | 
			
		||||
// that dependents can catch schema parsing errors without requiring an explicit
 | 
			
		||||
// dependency on zod, or risking a conflict in case of mismatching zob versions.
 | 
			
		||||
export { ZodError as ValidationError } from 'zod'
 | 
			
		||||
 | 
			
		||||
export * from './alg.js'
 | 
			
		||||
export * from './errors.js'
 | 
			
		||||
export * from './jwk.js'
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { JwtHeader, JwtPayload } from './jwt.js'
 | 
			
		||||
import { RequiredKey } from './util.js'
 | 
			
		||||
 | 
			
		||||
export type VerifyOptions<C extends string = never> = {
 | 
			
		||||
export type VerifyOptions<C extends string = string> = {
 | 
			
		||||
  audience?: string | readonly string[]
 | 
			
		||||
  /** in seconds */
 | 
			
		||||
  clockTolerance?: number
 | 
			
		||||
@ -14,7 +14,9 @@ export type VerifyOptions<C extends string = never> = {
 | 
			
		||||
  requiredClaims?: readonly C[]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type VerifyResult<C extends string = never> = {
 | 
			
		||||
  payload: RequiredKey<JwtPayload, C>
 | 
			
		||||
export type VerifyPayload = Record<string, unknown>
 | 
			
		||||
 | 
			
		||||
export type VerifyResult<P extends VerifyPayload, C extends string> = {
 | 
			
		||||
  payload: RequiredKey<P & JwtPayload, C>
 | 
			
		||||
  protectedHeader: JwtHeader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -24,154 +24,150 @@ export const isUnsignedJwt = (data: unknown): data is UnsignedJwt =>
 | 
			
		||||
/**
 | 
			
		||||
 * @see {@link https://www.rfc-editor.org/rfc/rfc7515.html#section-4}
 | 
			
		||||
 */
 | 
			
		||||
export const jwtHeaderSchema = z
 | 
			
		||||
  .object({
 | 
			
		||||
    /** "alg" (Algorithm) Header Parameter */
 | 
			
		||||
    alg: z.string(),
 | 
			
		||||
    /** "jku" (JWK Set URL) Header Parameter */
 | 
			
		||||
    jku: z.string().url().optional(),
 | 
			
		||||
    /** "jwk" (JSON Web Key) Header Parameter */
 | 
			
		||||
    jwk: z
 | 
			
		||||
      .object({
 | 
			
		||||
        kty: z.string(),
 | 
			
		||||
        crv: z.string().optional(),
 | 
			
		||||
        x: z.string().optional(),
 | 
			
		||||
        y: z.string().optional(),
 | 
			
		||||
        e: z.string().optional(),
 | 
			
		||||
        n: z.string().optional(),
 | 
			
		||||
      })
 | 
			
		||||
      .optional(),
 | 
			
		||||
    /** "kid" (Key ID) Header Parameter */
 | 
			
		||||
    kid: z.string().optional(),
 | 
			
		||||
    /** "x5u" (X.509 URL) Header Parameter */
 | 
			
		||||
    x5u: z.string().optional(),
 | 
			
		||||
    /** "x5c" (X.509 Certificate Chain) Header Parameter */
 | 
			
		||||
    x5c: z.array(z.string()).optional(),
 | 
			
		||||
    /** "x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter */
 | 
			
		||||
    x5t: z.string().optional(),
 | 
			
		||||
    /** "x5t#S256" (X.509 Certificate SHA-256 Thumbprint) Header Parameter */
 | 
			
		||||
    'x5t#S256': z.string().optional(),
 | 
			
		||||
    /** "typ" (Type) Header Parameter */
 | 
			
		||||
    typ: z.string().optional(),
 | 
			
		||||
    /** "cty" (Content Type) Header Parameter */
 | 
			
		||||
    cty: z.string().optional(),
 | 
			
		||||
    /** "crit" (Critical) Header Parameter */
 | 
			
		||||
    crit: z.array(z.string()).optional(),
 | 
			
		||||
  })
 | 
			
		||||
  .passthrough()
 | 
			
		||||
export const jwtHeaderSchema = z.object({
 | 
			
		||||
  /** "alg" (Algorithm) Header Parameter */
 | 
			
		||||
  alg: z.string(),
 | 
			
		||||
  /** "jku" (JWK Set URL) Header Parameter */
 | 
			
		||||
  jku: z.string().url().optional(),
 | 
			
		||||
  /** "jwk" (JSON Web Key) Header Parameter */
 | 
			
		||||
  jwk: z
 | 
			
		||||
    .object({
 | 
			
		||||
      kty: z.string(),
 | 
			
		||||
      crv: z.string().optional(),
 | 
			
		||||
      x: z.string().optional(),
 | 
			
		||||
      y: z.string().optional(),
 | 
			
		||||
      e: z.string().optional(),
 | 
			
		||||
      n: z.string().optional(),
 | 
			
		||||
    })
 | 
			
		||||
    .optional(),
 | 
			
		||||
  /** "kid" (Key ID) Header Parameter */
 | 
			
		||||
  kid: z.string().optional(),
 | 
			
		||||
  /** "x5u" (X.509 URL) Header Parameter */
 | 
			
		||||
  x5u: z.string().optional(),
 | 
			
		||||
  /** "x5c" (X.509 Certificate Chain) Header Parameter */
 | 
			
		||||
  x5c: z.array(z.string()).optional(),
 | 
			
		||||
  /** "x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter */
 | 
			
		||||
  x5t: z.string().optional(),
 | 
			
		||||
  /** "x5t#S256" (X.509 Certificate SHA-256 Thumbprint) Header Parameter */
 | 
			
		||||
  'x5t#S256': z.string().optional(),
 | 
			
		||||
  /** "typ" (Type) Header Parameter */
 | 
			
		||||
  typ: z.string().optional(),
 | 
			
		||||
  /** "cty" (Content Type) Header Parameter */
 | 
			
		||||
  cty: z.string().optional(),
 | 
			
		||||
  /** "crit" (Critical) Header Parameter */
 | 
			
		||||
  crit: z.array(z.string()).optional(),
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export type JwtHeader = z.infer<typeof jwtHeaderSchema>
 | 
			
		||||
 | 
			
		||||
// https://www.iana.org/assignments/jwt/jwt.xhtml
 | 
			
		||||
export const jwtPayloadSchema = z
 | 
			
		||||
  .object({
 | 
			
		||||
    iss: z.string().optional(),
 | 
			
		||||
    aud: z.union([z.string(), z.array(z.string()).nonempty()]).optional(),
 | 
			
		||||
    sub: z.string().optional(),
 | 
			
		||||
    exp: z.number().int().optional(),
 | 
			
		||||
    nbf: z.number().int().optional(),
 | 
			
		||||
    iat: z.number().int().optional(),
 | 
			
		||||
    jti: z.string().optional(),
 | 
			
		||||
    htm: z.string().optional(),
 | 
			
		||||
    htu: z.string().optional(),
 | 
			
		||||
    ath: z.string().optional(),
 | 
			
		||||
    acr: z.string().optional(),
 | 
			
		||||
    azp: z.string().optional(),
 | 
			
		||||
    amr: z.array(z.string()).optional(),
 | 
			
		||||
    // https://datatracker.ietf.org/doc/html/rfc7800
 | 
			
		||||
    cnf: z
 | 
			
		||||
      .object({
 | 
			
		||||
        kid: z.string().optional(), // Key ID
 | 
			
		||||
        jwk: jwkPubSchema.optional(), // JWK
 | 
			
		||||
        jwe: z.string().optional(), // Encrypted key
 | 
			
		||||
        jku: z.string().url().optional(), // JWK Set URI ("kid" should also be provided)
 | 
			
		||||
export const jwtPayloadSchema = z.object({
 | 
			
		||||
  iss: z.string().optional(),
 | 
			
		||||
  aud: z.union([z.string(), z.array(z.string()).nonempty()]).optional(),
 | 
			
		||||
  sub: z.string().optional(),
 | 
			
		||||
  exp: z.number().int().optional(),
 | 
			
		||||
  nbf: z.number().int().optional(),
 | 
			
		||||
  iat: z.number().int().optional(),
 | 
			
		||||
  jti: z.string().optional(),
 | 
			
		||||
  htm: z.string().optional(),
 | 
			
		||||
  htu: z.string().optional(),
 | 
			
		||||
  ath: z.string().optional(),
 | 
			
		||||
  acr: z.string().optional(),
 | 
			
		||||
  azp: z.string().optional(),
 | 
			
		||||
  amr: z.array(z.string()).optional(),
 | 
			
		||||
  // https://datatracker.ietf.org/doc/html/rfc7800
 | 
			
		||||
  cnf: z
 | 
			
		||||
    .object({
 | 
			
		||||
      kid: z.string().optional(), // Key ID
 | 
			
		||||
      jwk: jwkPubSchema.optional(), // JWK
 | 
			
		||||
      jwe: z.string().optional(), // Encrypted key
 | 
			
		||||
      jku: z.string().url().optional(), // JWK Set URI ("kid" should also be provided)
 | 
			
		||||
 | 
			
		||||
        // https://datatracker.ietf.org/doc/html/rfc9449#section-6.1
 | 
			
		||||
        jkt: z.string().optional(),
 | 
			
		||||
      // https://datatracker.ietf.org/doc/html/rfc9449#section-6.1
 | 
			
		||||
      jkt: z.string().optional(),
 | 
			
		||||
 | 
			
		||||
        // https://datatracker.ietf.org/doc/html/rfc8705
 | 
			
		||||
        'x5t#S256': z.string().optional(), // X.509 Certificate SHA-256 Thumbprint
 | 
			
		||||
      // https://datatracker.ietf.org/doc/html/rfc8705
 | 
			
		||||
      'x5t#S256': z.string().optional(), // X.509 Certificate SHA-256 Thumbprint
 | 
			
		||||
 | 
			
		||||
        // https://datatracker.ietf.org/doc/html/rfc9203
 | 
			
		||||
        osc: z.string().optional(), // OSCORE_Input_Material carrying the parameters for using OSCORE per-message security with implicit key confirmation
 | 
			
		||||
      })
 | 
			
		||||
      .optional(),
 | 
			
		||||
      // https://datatracker.ietf.org/doc/html/rfc9203
 | 
			
		||||
      osc: z.string().optional(), // OSCORE_Input_Material carrying the parameters for using OSCORE per-message security with implicit key confirmation
 | 
			
		||||
    })
 | 
			
		||||
    .optional(),
 | 
			
		||||
 | 
			
		||||
    client_id: z.string().optional(),
 | 
			
		||||
  client_id: z.string().optional(),
 | 
			
		||||
 | 
			
		||||
    scope: z.string().optional(),
 | 
			
		||||
    nonce: z.string().optional(),
 | 
			
		||||
  scope: z.string().optional(),
 | 
			
		||||
  nonce: z.string().optional(),
 | 
			
		||||
 | 
			
		||||
    at_hash: z.string().optional(),
 | 
			
		||||
    c_hash: z.string().optional(),
 | 
			
		||||
    s_hash: z.string().optional(),
 | 
			
		||||
    auth_time: z.number().int().optional(),
 | 
			
		||||
  at_hash: z.string().optional(),
 | 
			
		||||
  c_hash: z.string().optional(),
 | 
			
		||||
  s_hash: z.string().optional(),
 | 
			
		||||
  auth_time: z.number().int().optional(),
 | 
			
		||||
 | 
			
		||||
    // https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
 | 
			
		||||
  // https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
 | 
			
		||||
 | 
			
		||||
    // OpenID: "profile" scope
 | 
			
		||||
    name: z.string().optional(),
 | 
			
		||||
    family_name: z.string().optional(),
 | 
			
		||||
    given_name: z.string().optional(),
 | 
			
		||||
    middle_name: z.string().optional(),
 | 
			
		||||
    nickname: z.string().optional(),
 | 
			
		||||
    preferred_username: z.string().optional(),
 | 
			
		||||
    gender: z.string().optional(), // OpenID only defines "male" and "female" without forbidding other values
 | 
			
		||||
    picture: z.string().url().optional(),
 | 
			
		||||
    profile: z.string().url().optional(),
 | 
			
		||||
    website: z.string().url().optional(),
 | 
			
		||||
    birthdate: z
 | 
			
		||||
      .string()
 | 
			
		||||
      .regex(/\d{4}-\d{2}-\d{2}/) // YYYY-MM-DD
 | 
			
		||||
      .optional(),
 | 
			
		||||
    zoneinfo: z
 | 
			
		||||
      .string()
 | 
			
		||||
      .regex(/^[A-Za-z0-9_/]+$/)
 | 
			
		||||
      .optional(),
 | 
			
		||||
    locale: z
 | 
			
		||||
      .string()
 | 
			
		||||
      .regex(/^[a-z]{2}(-[A-Z]{2})?$/)
 | 
			
		||||
      .optional(),
 | 
			
		||||
    updated_at: z.number().int().optional(),
 | 
			
		||||
  // OpenID: "profile" scope
 | 
			
		||||
  name: z.string().optional(),
 | 
			
		||||
  family_name: z.string().optional(),
 | 
			
		||||
  given_name: z.string().optional(),
 | 
			
		||||
  middle_name: z.string().optional(),
 | 
			
		||||
  nickname: z.string().optional(),
 | 
			
		||||
  preferred_username: z.string().optional(),
 | 
			
		||||
  gender: z.string().optional(), // OpenID only defines "male" and "female" without forbidding other values
 | 
			
		||||
  picture: z.string().url().optional(),
 | 
			
		||||
  profile: z.string().url().optional(),
 | 
			
		||||
  website: z.string().url().optional(),
 | 
			
		||||
  birthdate: z
 | 
			
		||||
    .string()
 | 
			
		||||
    .regex(/\d{4}-\d{2}-\d{2}/) // YYYY-MM-DD
 | 
			
		||||
    .optional(),
 | 
			
		||||
  zoneinfo: z
 | 
			
		||||
    .string()
 | 
			
		||||
    .regex(/^[A-Za-z0-9_/]+$/)
 | 
			
		||||
    .optional(),
 | 
			
		||||
  locale: z
 | 
			
		||||
    .string()
 | 
			
		||||
    .regex(/^[a-z]{2}(-[A-Z]{2})?$/)
 | 
			
		||||
    .optional(),
 | 
			
		||||
  updated_at: z.number().int().optional(),
 | 
			
		||||
 | 
			
		||||
    // OpenID: "email" scope
 | 
			
		||||
    email: z.string().optional(),
 | 
			
		||||
    email_verified: z.boolean().optional(),
 | 
			
		||||
  // OpenID: "email" scope
 | 
			
		||||
  email: z.string().optional(),
 | 
			
		||||
  email_verified: z.boolean().optional(),
 | 
			
		||||
 | 
			
		||||
    // OpenID: "phone" scope
 | 
			
		||||
    phone_number: z.string().optional(),
 | 
			
		||||
    phone_number_verified: z.boolean().optional(),
 | 
			
		||||
  // OpenID: "phone" scope
 | 
			
		||||
  phone_number: z.string().optional(),
 | 
			
		||||
  phone_number_verified: z.boolean().optional(),
 | 
			
		||||
 | 
			
		||||
    // OpenID: "address" scope
 | 
			
		||||
    // https://openid.net/specs/openid-connect-core-1_0.html#AddressClaim
 | 
			
		||||
    address: z
 | 
			
		||||
      .object({
 | 
			
		||||
        formatted: z.string().optional(),
 | 
			
		||||
        street_address: z.string().optional(),
 | 
			
		||||
        locality: z.string().optional(),
 | 
			
		||||
        region: z.string().optional(),
 | 
			
		||||
        postal_code: z.string().optional(),
 | 
			
		||||
        country: z.string().optional(),
 | 
			
		||||
      })
 | 
			
		||||
      .optional(),
 | 
			
		||||
  // OpenID: "address" scope
 | 
			
		||||
  // https://openid.net/specs/openid-connect-core-1_0.html#AddressClaim
 | 
			
		||||
  address: z
 | 
			
		||||
    .object({
 | 
			
		||||
      formatted: z.string().optional(),
 | 
			
		||||
      street_address: z.string().optional(),
 | 
			
		||||
      locality: z.string().optional(),
 | 
			
		||||
      region: z.string().optional(),
 | 
			
		||||
      postal_code: z.string().optional(),
 | 
			
		||||
      country: z.string().optional(),
 | 
			
		||||
    })
 | 
			
		||||
    .optional(),
 | 
			
		||||
 | 
			
		||||
    // https://datatracker.ietf.org/doc/html/rfc9396#section-14.2
 | 
			
		||||
    authorization_details: z
 | 
			
		||||
      .array(
 | 
			
		||||
        z
 | 
			
		||||
          .object({
 | 
			
		||||
            type: z.string(),
 | 
			
		||||
            // https://datatracker.ietf.org/doc/html/rfc9396#section-2.2
 | 
			
		||||
            locations: z.array(z.string()).optional(),
 | 
			
		||||
            actions: z.array(z.string()).optional(),
 | 
			
		||||
            datatypes: z.array(z.string()).optional(),
 | 
			
		||||
            identifier: z.string().optional(),
 | 
			
		||||
            privileges: z.array(z.string()).optional(),
 | 
			
		||||
          })
 | 
			
		||||
          .passthrough(),
 | 
			
		||||
      )
 | 
			
		||||
      .optional(),
 | 
			
		||||
  })
 | 
			
		||||
  .passthrough()
 | 
			
		||||
  // https://datatracker.ietf.org/doc/html/rfc9396#section-14.2
 | 
			
		||||
  authorization_details: z
 | 
			
		||||
    .array(
 | 
			
		||||
      z
 | 
			
		||||
        .object({
 | 
			
		||||
          type: z.string(),
 | 
			
		||||
          // https://datatracker.ietf.org/doc/html/rfc9396#section-2.2
 | 
			
		||||
          locations: z.array(z.string()).optional(),
 | 
			
		||||
          actions: z.array(z.string()).optional(),
 | 
			
		||||
          datatypes: z.array(z.string()).optional(),
 | 
			
		||||
          identifier: z.string().optional(),
 | 
			
		||||
          privileges: z.array(z.string()).optional(),
 | 
			
		||||
        })
 | 
			
		||||
        .passthrough(),
 | 
			
		||||
    )
 | 
			
		||||
    .optional(),
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export type JwtPayload = z.infer<typeof jwtPayloadSchema>
 | 
			
		||||
 | 
			
		||||
@ -1,14 +1,12 @@
 | 
			
		||||
import { jwkAlgorithms } from './alg.js'
 | 
			
		||||
import { JwkError } from './errors.js'
 | 
			
		||||
import { Jwk, jwkSchema } from './jwk.js'
 | 
			
		||||
import { VerifyOptions, VerifyResult } from './jwt-verify.js'
 | 
			
		||||
import { VerifyOptions, VerifyPayload, VerifyResult } from './jwt-verify.js'
 | 
			
		||||
import { JwtHeader, JwtPayload, SignedJwt } from './jwt.js'
 | 
			
		||||
import { cachedGetter } from './util.js'
 | 
			
		||||
 | 
			
		||||
const jwkSchemaReadonly = jwkSchema.readonly()
 | 
			
		||||
 | 
			
		||||
export abstract class Key<J extends Jwk = Jwk> {
 | 
			
		||||
  constructor(protected readonly jwk: Readonly<J>) {
 | 
			
		||||
export abstract class Key {
 | 
			
		||||
  constructor(protected readonly jwk: Readonly<Jwk>) {
 | 
			
		||||
    // A key should always be used either for signing or encryption.
 | 
			
		||||
    if (!jwk.use) throw new JwkError('Missing "use" Parameter value')
 | 
			
		||||
  }
 | 
			
		||||
@ -26,28 +24,25 @@ export abstract class Key<J extends Jwk = Jwk> {
 | 
			
		||||
    return false
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get privateJwk(): Readonly<J> | undefined {
 | 
			
		||||
  get privateJwk(): Jwk | undefined {
 | 
			
		||||
    return this.isPrivate ? this.jwk : undefined
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @cachedGetter
 | 
			
		||||
  get publicJwk():
 | 
			
		||||
    | Readonly<Exclude<J, { kty: 'oct' }> & { d?: never }>
 | 
			
		||||
    | undefined {
 | 
			
		||||
  get publicJwk(): Jwk | undefined {
 | 
			
		||||
    if (this.isSymetric) return undefined
 | 
			
		||||
 | 
			
		||||
    return jwkSchemaReadonly.parse({
 | 
			
		||||
      ...this.jwk,
 | 
			
		||||
      d: undefined,
 | 
			
		||||
      k: undefined,
 | 
			
		||||
    }) as Exclude<J, { kty: 'oct' }> & { d?: never }
 | 
			
		||||
    if (this.isPrivate) {
 | 
			
		||||
      const { d: _, ...jwk } = this.jwk as any
 | 
			
		||||
      return jwk
 | 
			
		||||
    }
 | 
			
		||||
    return this.jwk
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @cachedGetter
 | 
			
		||||
  get bareJwk(): Readonly<Jwk> | undefined {
 | 
			
		||||
  get bareJwk(): Jwk | undefined {
 | 
			
		||||
    if (this.isSymetric) return undefined
 | 
			
		||||
    const { kty, crv, e, n, x, y } = this.jwk as any
 | 
			
		||||
    return jwkSchemaReadonly.parse({ crv, e, kty, n, x, y })
 | 
			
		||||
    return jwkSchema.parse({ crv, e, kty, n, x, y })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get use() {
 | 
			
		||||
@ -69,7 +64,7 @@ export abstract class Key<J extends Jwk = Jwk> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get crv() {
 | 
			
		||||
    return (this.jwk as { crv: undefined } | Extract<J, { crv: unknown }>).crv
 | 
			
		||||
    return (this.jwk as { crv: undefined } | Extract<Jwk, { crv: unknown }>).crv
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -78,7 +73,7 @@ export abstract class Key<J extends Jwk = Jwk> {
 | 
			
		||||
   */
 | 
			
		||||
  @cachedGetter
 | 
			
		||||
  get algorithms(): readonly string[] {
 | 
			
		||||
    return Object.freeze(Array.from(jwkAlgorithms(this.jwk)))
 | 
			
		||||
    return Array.from(jwkAlgorithms(this.jwk))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -91,8 +86,8 @@ export abstract class Key<J extends Jwk = Jwk> {
 | 
			
		||||
   *
 | 
			
		||||
   * @throws {JwtVerifyError} if the JWT is invalid
 | 
			
		||||
   */
 | 
			
		||||
  abstract verifyJwt<C extends string = never>(
 | 
			
		||||
    token: SignedJwt,
 | 
			
		||||
    options?: VerifyOptions<C>,
 | 
			
		||||
  ): Promise<VerifyResult<C>>
 | 
			
		||||
  abstract verifyJwt<
 | 
			
		||||
    P extends VerifyPayload = JwtPayload,
 | 
			
		||||
    C extends string = string,
 | 
			
		||||
  >(token: SignedJwt, options?: VerifyOptions<C>): Promise<VerifyResult<P, C>>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -213,10 +213,13 @@ export class Keyset<K extends Key = Key> implements Iterable<K> {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async verifyJwt<C extends string = never>(
 | 
			
		||||
  async verifyJwt<
 | 
			
		||||
    P extends Record<string, unknown> = JwtPayload,
 | 
			
		||||
    C extends string = string,
 | 
			
		||||
  >(
 | 
			
		||||
    token: SignedJwt,
 | 
			
		||||
    options?: VerifyOptions<C>,
 | 
			
		||||
  ): Promise<VerifyResult<C> & { key: K }> {
 | 
			
		||||
  ): Promise<VerifyResult<P, C> & { key: K }> {
 | 
			
		||||
    const { header } = unsafeDecodeJwt(token)
 | 
			
		||||
    const { kid, alg } = header
 | 
			
		||||
 | 
			
		||||
@ -224,7 +227,7 @@ export class Keyset<K extends Key = Key> implements Iterable<K> {
 | 
			
		||||
 | 
			
		||||
    for (const key of this.list({ kid, alg })) {
 | 
			
		||||
      try {
 | 
			
		||||
        const result = await key.verifyJwt<C>(token, options)
 | 
			
		||||
        const result = await key.verifyJwt<P, C>(token, options)
 | 
			
		||||
        return { ...result, key }
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        errors.push(err)
 | 
			
		||||
 | 
			
		||||
@ -5,12 +5,12 @@ import { RefinementCtx, ZodIssueCode } from 'zod'
 | 
			
		||||
export type Simplify<T> = { [K in keyof T]: T[K] } & {}
 | 
			
		||||
export type Override<T, V> = Simplify<V & Omit<T, keyof V>>
 | 
			
		||||
 | 
			
		||||
export type RequiredKey<T, K extends keyof T = never> = Simplify<
 | 
			
		||||
  T & {
 | 
			
		||||
    [L in K]-?: unknown extends T[L]
 | 
			
		||||
      ? NonNullable<unknown> | null
 | 
			
		||||
      : Exclude<T[L], undefined>
 | 
			
		||||
  }
 | 
			
		||||
export type RequiredKey<T, K extends string> = Simplify<
 | 
			
		||||
  string extends K
 | 
			
		||||
    ? T
 | 
			
		||||
    : {
 | 
			
		||||
        [L in K]: Exclude<L extends keyof T ? T[L] : unknown, undefined>
 | 
			
		||||
      } & Omit<T, K>
 | 
			
		||||
>
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line @typescript-eslint/ban-types
 | 
			
		||||
 | 
			
		||||
@ -1,16 +1,5 @@
 | 
			
		||||
# @atproto/oauth-client-browser
 | 
			
		||||
 | 
			
		||||
## 0.3.7
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0)]:
 | 
			
		||||
  - @atproto/jwk@0.1.2
 | 
			
		||||
  - @atproto/jwk-webcrypto@0.1.3
 | 
			
		||||
  - @atproto/oauth-client@0.3.7
 | 
			
		||||
  - @atproto/oauth-types@0.2.2
 | 
			
		||||
  - @atproto-labs/did-resolver@0.1.8
 | 
			
		||||
 | 
			
		||||
## 0.3.6
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/oauth-client-browser",
 | 
			
		||||
  "version": "0.3.7",
 | 
			
		||||
  "version": "0.3.6",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "ATPROTO OAuth client for the browser (relies on WebCrypto & Indexed DB)",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,5 @@
 | 
			
		||||
# @atproto/oauth-client-node
 | 
			
		||||
 | 
			
		||||
## 0.2.7
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0)]:
 | 
			
		||||
  - @atproto/jwk@0.1.2
 | 
			
		||||
  - @atproto/jwk-jose@0.1.3
 | 
			
		||||
  - @atproto/jwk-webcrypto@0.1.3
 | 
			
		||||
  - @atproto/oauth-client@0.3.7
 | 
			
		||||
  - @atproto/oauth-types@0.2.2
 | 
			
		||||
  - @atproto-labs/did-resolver@0.1.8
 | 
			
		||||
  - @atproto-labs/handle-resolver-node@0.1.10
 | 
			
		||||
 | 
			
		||||
## 0.2.6
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/oauth-client-node",
 | 
			
		||||
  "version": "0.2.7",
 | 
			
		||||
  "version": "0.2.6",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "ATPROTO OAuth client for the NodeJS",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,16 +1,5 @@
 | 
			
		||||
# @atproto/oauth-client
 | 
			
		||||
 | 
			
		||||
## 0.3.7
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`5ece8c6ae`](https://github.com/bluesky-social/atproto/commit/5ece8c6aeab9c5c3f51295d93ed6e27c3c6095c2), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`5ece8c6ae`](https://github.com/bluesky-social/atproto/commit/5ece8c6aeab9c5c3f51295d93ed6e27c3c6095c2)]:
 | 
			
		||||
  - @atproto/jwk@0.1.2
 | 
			
		||||
  - @atproto-labs/fetch@0.2.0
 | 
			
		||||
  - @atproto/oauth-types@0.2.2
 | 
			
		||||
  - @atproto-labs/did-resolver@0.1.8
 | 
			
		||||
  - @atproto-labs/identity-resolver@0.1.10
 | 
			
		||||
 | 
			
		||||
## 0.3.6
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/oauth-client",
 | 
			
		||||
  "version": "0.3.7",
 | 
			
		||||
  "version": "0.3.6",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "OAuth client for ATPROTO PDS. This package serves as common base for environment-specific implementations (NodeJS, Browser, React-Native).",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,16 +1,5 @@
 | 
			
		||||
# @atproto/oauth-provider
 | 
			
		||||
 | 
			
		||||
## 0.2.12
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`5ece8c6ae`](https://github.com/bluesky-social/atproto/commit/5ece8c6aeab9c5c3f51295d93ed6e27c3c6095c2), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`5ece8c6ae`](https://github.com/bluesky-social/atproto/commit/5ece8c6aeab9c5c3f51295d93ed6e27c3c6095c2)]:
 | 
			
		||||
  - @atproto/jwk@0.1.2
 | 
			
		||||
  - @atproto/jwk-jose@0.1.3
 | 
			
		||||
  - @atproto-labs/fetch@0.2.0
 | 
			
		||||
  - @atproto/oauth-types@0.2.2
 | 
			
		||||
  - @atproto-labs/fetch-node@0.1.5
 | 
			
		||||
 | 
			
		||||
## 0.2.11
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/oauth-provider",
 | 
			
		||||
  "version": "0.2.12",
 | 
			
		||||
  "version": "0.2.11",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "Generic OAuth2 and OpenID Connect provider for Node.js. Currently only supports features needed for Atproto.",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -27,8 +27,7 @@ export const signedTokenPayloadSchema = z.intersection(
 | 
			
		||||
      jti: tokenIdSchema,
 | 
			
		||||
      sub: subSchema,
 | 
			
		||||
      client_id: clientIdSchema,
 | 
			
		||||
    })
 | 
			
		||||
    .passthrough(),
 | 
			
		||||
    }),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
export type SignedTokenPayload = Simplify<
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ import {
 | 
			
		||||
  signedTokenPayloadSchema,
 | 
			
		||||
} from './signed-token-payload.js'
 | 
			
		||||
 | 
			
		||||
export type SignPayload = JwtPayload & { iss?: never }
 | 
			
		||||
export type SignPayload = Omit<JwtPayload, 'iss'>
 | 
			
		||||
 | 
			
		||||
export class Signer {
 | 
			
		||||
  constructor(
 | 
			
		||||
@ -27,11 +27,11 @@ export class Signer {
 | 
			
		||||
    public readonly keyset: Keyset,
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  async verify<C extends string = never>(
 | 
			
		||||
  async verify<P extends Record<string, unknown> = JwtPayload>(
 | 
			
		||||
    token: SignedJwt,
 | 
			
		||||
    options?: Omit<VerifyOptions<C>, 'issuer'>,
 | 
			
		||||
    options?: Omit<VerifyOptions, 'issuer'>,
 | 
			
		||||
  ) {
 | 
			
		||||
    return this.keyset.verifyJwt<C>(token, {
 | 
			
		||||
    return this.keyset.verifyJwt<P>(token, {
 | 
			
		||||
      ...options,
 | 
			
		||||
      issuer: [this.issuer],
 | 
			
		||||
    })
 | 
			
		||||
@ -84,16 +84,18 @@ export class Signer {
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async verifyAccessToken<C extends string = never>(
 | 
			
		||||
    token: SignedJwt,
 | 
			
		||||
    options?: Omit<VerifyOptions<C>, 'issuer' | 'typ'>,
 | 
			
		||||
  ) {
 | 
			
		||||
    const result = await this.verify<C>(token, { ...options, typ: 'at+jwt' })
 | 
			
		||||
    type Payload = typeof result.payload // RequiredKey<JwtPayload, C>
 | 
			
		||||
    return {
 | 
			
		||||
      protectedHeader: result.protectedHeader,
 | 
			
		||||
      payload: signedTokenPayloadSchema.parse(result.payload) as Payload &
 | 
			
		||||
        SignedTokenPayload,
 | 
			
		||||
    }
 | 
			
		||||
  async verifyAccessToken(token: SignedJwt) {
 | 
			
		||||
    const result = await this.verify<SignedTokenPayload>(token, {
 | 
			
		||||
      typ: 'at+jwt',
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    // The result is already type casted as an AccessTokenPayload, but we need
 | 
			
		||||
    // to actually verify this. That should already be covered by the fact that
 | 
			
		||||
    // we don't sign 'at+jwt' tokens without a valid token ID. Let's double
 | 
			
		||||
    // check in case another version/implementation was used to generate the
 | 
			
		||||
    // token.
 | 
			
		||||
    signedTokenPayloadSchema.parse(result.payload)
 | 
			
		||||
 | 
			
		||||
    return result
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -462,7 +462,6 @@ export class TokenManager {
 | 
			
		||||
      case isSignedJwt(token): {
 | 
			
		||||
        const { payload } = await this.signer.verify(token, {
 | 
			
		||||
          clockTolerance: Infinity,
 | 
			
		||||
          requiredClaims: ['jti'],
 | 
			
		||||
        })
 | 
			
		||||
        const tokenId = tokenIdSchema.parse(payload.jti)
 | 
			
		||||
        await this.store.deleteToken(tokenId)
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,5 @@
 | 
			
		||||
# @atproto/oauth-types
 | 
			
		||||
 | 
			
		||||
## 0.2.2
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0)]:
 | 
			
		||||
  - @atproto/jwk@0.1.2
 | 
			
		||||
 | 
			
		||||
## 0.2.1
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/oauth-types",
 | 
			
		||||
  "version": "0.2.2",
 | 
			
		||||
  "version": "0.2.1",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "OAuth typing & validation library",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,23 +1,5 @@
 | 
			
		||||
# @atproto/ozone
 | 
			
		||||
 | 
			
		||||
## 0.1.67
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- [#3344](https://github.com/bluesky-social/atproto/pull/3344) [`48a0e9d60`](https://github.com/bluesky-social/atproto/commit/48a0e9d6060c2dc93899f13f2fc7cc76c04fbcd9) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Properly dispose of unused http responses
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`e277158f7`](https://github.com/bluesky-social/atproto/commit/e277158f70a831b04fde3ec84b3c1eaa6ce82e9d)]:
 | 
			
		||||
  - @atproto/api@0.13.27
 | 
			
		||||
 | 
			
		||||
## 0.1.66
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`1abfd74ec`](https://github.com/bluesky-social/atproto/commit/1abfd74ec7114e5d8e2411f7a4fa10bdce97e277)]:
 | 
			
		||||
  - @atproto/crypto@0.4.3
 | 
			
		||||
  - @atproto/identity@0.4.5
 | 
			
		||||
  - @atproto/xrpc-server@0.7.6
 | 
			
		||||
 | 
			
		||||
## 0.1.65
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/ozone",
 | 
			
		||||
  "version": "0.1.67",
 | 
			
		||||
  "version": "0.1.65",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "Backend service for moderating the Bluesky network.",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -46,7 +46,7 @@ export class BlobDiverter {
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
    if (blobResponse.statusCode !== 200) {
 | 
			
		||||
      await blobResponse.body.dump()
 | 
			
		||||
      blobResponse.body.destroy()
 | 
			
		||||
      throw new XRPCError(
 | 
			
		||||
        blobResponse.statusCode,
 | 
			
		||||
        undefined,
 | 
			
		||||
@ -72,7 +72,7 @@ export class BlobDiverter {
 | 
			
		||||
      }
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      // Typically un-supported content encoding
 | 
			
		||||
      await blobResponse.body.dump()
 | 
			
		||||
      blobResponse.body.destroy()
 | 
			
		||||
      throw err
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@ -99,7 +99,7 @@ export class BlobDiverter {
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
    if (result.statusCode !== 200) {
 | 
			
		||||
      await result.body.dump()
 | 
			
		||||
      result.body.destroy()
 | 
			
		||||
      throw new XRPCError(
 | 
			
		||||
        result.statusCode,
 | 
			
		||||
        undefined,
 | 
			
		||||
 | 
			
		||||
@ -12359,7 +12359,7 @@ export const schemaDict = {
 | 
			
		||||
              items: {
 | 
			
		||||
                type: 'string',
 | 
			
		||||
                description:
 | 
			
		||||
                  'If specified, only events where the action policies match any of the given policies are returned',
 | 
			
		||||
                  'If specified, only events where the policy matches the given policy are returned',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            cursor: {
 | 
			
		||||
 | 
			
		||||
@ -19,8 +19,6 @@ export type InputSchema = undefined
 | 
			
		||||
export interface OutputSchema {
 | 
			
		||||
  cursor?: string
 | 
			
		||||
  actors: AppBskyActorDefs.ProfileView[]
 | 
			
		||||
  /** Snowflake for this recommendation, use when submitting recommendation events. */
 | 
			
		||||
  recId?: number
 | 
			
		||||
  [k: string]: unknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,8 +19,6 @@ export interface OutputSchema {
 | 
			
		||||
  suggestions: AppBskyActorDefs.ProfileView[]
 | 
			
		||||
  /** If true, response has fallen-back to generic results, and is not scoped using relativeToDid */
 | 
			
		||||
  isFallback?: boolean
 | 
			
		||||
  /** Snowflake for this recommendation, use when submitting recommendation events. */
 | 
			
		||||
  recId?: number
 | 
			
		||||
  [k: string]: unknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -25,8 +25,6 @@ export interface OutputSchema {
 | 
			
		||||
  actors: AppBskyUnspeccedDefs.SkeletonSearchActor[]
 | 
			
		||||
  /** DID of the account these suggestions are relative to. If this is returned undefined, suggestions are based on the viewer. */
 | 
			
		||||
  relativeToDid?: string
 | 
			
		||||
  /** Snowflake for this recommendation, use when submitting recommendation events. */
 | 
			
		||||
  recId?: number
 | 
			
		||||
  [k: string]: unknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,26 +1,5 @@
 | 
			
		||||
# @atproto/pds
 | 
			
		||||
 | 
			
		||||
## 0.4.84
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`e277158f7`](https://github.com/bluesky-social/atproto/commit/e277158f70a831b04fde3ec84b3c1eaa6ce82e9d)]:
 | 
			
		||||
  - @atproto/api@0.13.27
 | 
			
		||||
  - @atproto/oauth-provider@0.2.12
 | 
			
		||||
  - @atproto-labs/fetch-node@0.1.5
 | 
			
		||||
 | 
			
		||||
## 0.4.83
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`1abfd74ec`](https://github.com/bluesky-social/atproto/commit/1abfd74ec7114e5d8e2411f7a4fa10bdce97e277)]:
 | 
			
		||||
  - @atproto/crypto@0.4.3
 | 
			
		||||
  - @atproto/aws@0.2.12
 | 
			
		||||
  - @atproto/identity@0.4.5
 | 
			
		||||
  - @atproto/repo@0.6.2
 | 
			
		||||
  - @atproto/xrpc-server@0.7.6
 | 
			
		||||
  - @atproto-labs/xrpc-utils@0.0.2
 | 
			
		||||
 | 
			
		||||
## 0.4.82
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/pds",
 | 
			
		||||
  "version": "0.4.84",
 | 
			
		||||
  "version": "0.4.82",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "Reference implementation of atproto Personal Data Server (PDS)",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -12359,7 +12359,7 @@ export const schemaDict = {
 | 
			
		||||
              items: {
 | 
			
		||||
                type: 'string',
 | 
			
		||||
                description:
 | 
			
		||||
                  'If specified, only events where the action policies match any of the given policies are returned',
 | 
			
		||||
                  'If specified, only events where the policy matches the given policy are returned',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            cursor: {
 | 
			
		||||
 | 
			
		||||
@ -19,8 +19,6 @@ export type InputSchema = undefined
 | 
			
		||||
export interface OutputSchema {
 | 
			
		||||
  cursor?: string
 | 
			
		||||
  actors: AppBskyActorDefs.ProfileView[]
 | 
			
		||||
  /** Snowflake for this recommendation, use when submitting recommendation events. */
 | 
			
		||||
  recId?: number
 | 
			
		||||
  [k: string]: unknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,8 +19,6 @@ export interface OutputSchema {
 | 
			
		||||
  suggestions: AppBskyActorDefs.ProfileView[]
 | 
			
		||||
  /** If true, response has fallen-back to generic results, and is not scoped using relativeToDid */
 | 
			
		||||
  isFallback?: boolean
 | 
			
		||||
  /** Snowflake for this recommendation, use when submitting recommendation events. */
 | 
			
		||||
  recId?: number
 | 
			
		||||
  [k: string]: unknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -25,8 +25,6 @@ export interface OutputSchema {
 | 
			
		||||
  actors: AppBskyUnspeccedDefs.SkeletonSearchActor[]
 | 
			
		||||
  /** DID of the account these suggestions are relative to. If this is returned undefined, suggestions are based on the viewer. */
 | 
			
		||||
  relativeToDid?: string
 | 
			
		||||
  /** Snowflake for this recommendation, use when submitting recommendation events. */
 | 
			
		||||
  recId?: number
 | 
			
		||||
  [k: string]: unknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,6 @@ import { CID } from 'multiformats/cid'
 | 
			
		||||
import { Server } from 'node:http'
 | 
			
		||||
import { AddressInfo } from 'node:net'
 | 
			
		||||
import { FeedViewPost } from '../src/lexicon/types/app/bsky/feed/defs'
 | 
			
		||||
import { ToolsOzoneModerationDefs } from '@atproto/api'
 | 
			
		||||
 | 
			
		||||
// Swap out identifiers and dates with stable
 | 
			
		||||
// values for the purpose of snapshot testing
 | 
			
		||||
@ -203,21 +202,3 @@ export async function stopServer(server: Server) {
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const normalizeSubjectStatus = (
 | 
			
		||||
  subject: ToolsOzoneModerationDefs.SubjectStatusView,
 | 
			
		||||
) => {
 | 
			
		||||
  return { ...subject, tags: subject.tags?.sort() }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const forSubjectStatusSnapshot = (
 | 
			
		||||
  status:
 | 
			
		||||
    | ToolsOzoneModerationDefs.SubjectStatusView
 | 
			
		||||
    | ToolsOzoneModerationDefs.SubjectStatusView[],
 | 
			
		||||
) => {
 | 
			
		||||
  if (Array.isArray(status)) {
 | 
			
		||||
    return forSnapshot(status.map(normalizeSubjectStatus))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return forSnapshot(normalizeSubjectStatus(status))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { AtpAgent, ComAtprotoModerationDefs } from '@atproto/api'
 | 
			
		||||
import { SeedClient, TestNetwork } from '@atproto/dev-env'
 | 
			
		||||
import { forSubjectStatusSnapshot } from './_util'
 | 
			
		||||
import { forSnapshot } from './_util'
 | 
			
		||||
import { ids } from '../src/lexicon/lexicons'
 | 
			
		||||
 | 
			
		||||
describe('appeal account takedown', () => {
 | 
			
		||||
@ -35,7 +35,6 @@ describe('appeal account takedown', () => {
 | 
			
		||||
      email: 'jeff@test.com',
 | 
			
		||||
      password: 'password',
 | 
			
		||||
    })
 | 
			
		||||
    await network.processAll()
 | 
			
		||||
 | 
			
		||||
    // Emit a takedown event
 | 
			
		||||
    await network.ozone.getModClient().performTakedown({
 | 
			
		||||
@ -98,9 +97,7 @@ describe('appeal account takedown', () => {
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    expect(result.subjectStatuses[0].appealed).toBe(true)
 | 
			
		||||
    expect(
 | 
			
		||||
      forSubjectStatusSnapshot(result.subjectStatuses[0]),
 | 
			
		||||
    ).toMatchSnapshot()
 | 
			
		||||
    expect(forSnapshot(result.subjectStatuses[0])).toMatchSnapshot()
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('takendown actor is not allowed to create reports.', async () => {
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,5 @@
 | 
			
		||||
# @atproto/repo
 | 
			
		||||
 | 
			
		||||
## 0.6.2
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`1abfd74ec`](https://github.com/bluesky-social/atproto/commit/1abfd74ec7114e5d8e2411f7a4fa10bdce97e277)]:
 | 
			
		||||
  - @atproto/crypto@0.4.3
 | 
			
		||||
 | 
			
		||||
## 0.6.1
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/repo",
 | 
			
		||||
  "version": "0.6.2",
 | 
			
		||||
  "version": "0.6.1",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "atproto repo and MST implementation",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,14 +1,5 @@
 | 
			
		||||
# @atproto/sync
 | 
			
		||||
 | 
			
		||||
## 0.1.9
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies []:
 | 
			
		||||
  - @atproto/identity@0.4.5
 | 
			
		||||
  - @atproto/repo@0.6.2
 | 
			
		||||
  - @atproto/xrpc-server@0.7.6
 | 
			
		||||
 | 
			
		||||
## 0.1.8
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/sync",
 | 
			
		||||
  "version": "0.1.9",
 | 
			
		||||
  "version": "0.1.8",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "atproto sync library",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,5 @@
 | 
			
		||||
# @atproto/xrpc-server
 | 
			
		||||
 | 
			
		||||
## 0.7.6
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`1abfd74ec`](https://github.com/bluesky-social/atproto/commit/1abfd74ec7114e5d8e2411f7a4fa10bdce97e277)]:
 | 
			
		||||
  - @atproto/crypto@0.4.3
 | 
			
		||||
 | 
			
		||||
## 0.7.5
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@atproto/xrpc-server",
 | 
			
		||||
  "version": "0.7.6",
 | 
			
		||||
  "version": "0.7.5",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "description": "atproto HTTP API (XRPC) server library",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
@ -37,7 +37,7 @@
 | 
			
		||||
    "@atproto/crypto": "workspace:^",
 | 
			
		||||
    "@types/express": "^4.17.13",
 | 
			
		||||
    "@types/express-serve-static-core": "^4.17.36",
 | 
			
		||||
    "@types/http-errors": "^2.0.4",
 | 
			
		||||
    "@types/http-errors": "^2.0.1",
 | 
			
		||||
    "@types/ws": "^8.5.4",
 | 
			
		||||
    "get-port": "^6.1.2",
 | 
			
		||||
    "jest": "^28.1.2",
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										15
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							@ -201,7 +201,7 @@ importers:
 | 
			
		||||
        version: 0.0.1
 | 
			
		||||
      '@types/http-errors':
 | 
			
		||||
        specifier: ^2.0.1
 | 
			
		||||
        version: 2.0.4
 | 
			
		||||
        version: 2.0.1
 | 
			
		||||
      compression:
 | 
			
		||||
        specifier: ^1.7.4
 | 
			
		||||
        version: 1.7.4
 | 
			
		||||
@ -812,9 +812,6 @@ importers:
 | 
			
		||||
      '@atproto/jwk-jose':
 | 
			
		||||
        specifier: workspace:*
 | 
			
		||||
        version: link:../jwk-jose
 | 
			
		||||
      zod:
 | 
			
		||||
        specifier: ^3.23.8
 | 
			
		||||
        version: 3.23.8
 | 
			
		||||
    devDependencies:
 | 
			
		||||
      typescript:
 | 
			
		||||
        specifier: ^5.6.3
 | 
			
		||||
@ -1569,8 +1566,8 @@ importers:
 | 
			
		||||
        specifier: ^4.17.36
 | 
			
		||||
        version: 4.17.36
 | 
			
		||||
      '@types/http-errors':
 | 
			
		||||
        specifier: ^2.0.4
 | 
			
		||||
        version: 2.0.4
 | 
			
		||||
        specifier: ^2.0.1
 | 
			
		||||
        version: 2.0.1
 | 
			
		||||
      '@types/ws':
 | 
			
		||||
        specifier: ^8.5.4
 | 
			
		||||
        version: 8.5.4
 | 
			
		||||
@ -6313,8 +6310,8 @@ packages:
 | 
			
		||||
      '@types/node': 18.19.67
 | 
			
		||||
    dev: true
 | 
			
		||||
 | 
			
		||||
  /@types/http-errors@2.0.4:
 | 
			
		||||
    resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
 | 
			
		||||
  /@types/http-errors@2.0.1:
 | 
			
		||||
    resolution: {integrity: sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==}
 | 
			
		||||
 | 
			
		||||
  /@types/is-ci@3.0.0:
 | 
			
		||||
    resolution: {integrity: sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==}
 | 
			
		||||
@ -6450,7 +6447,7 @@ packages:
 | 
			
		||||
  /@types/serve-static@1.15.2:
 | 
			
		||||
    resolution: {integrity: sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==}
 | 
			
		||||
    dependencies:
 | 
			
		||||
      '@types/http-errors': 2.0.4
 | 
			
		||||
      '@types/http-errors': 2.0.1
 | 
			
		||||
      '@types/mime': 3.0.1
 | 
			
		||||
      '@types/node': 18.19.67
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user