@atproto/common-web 0.2.4 → 0.3.1
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/CHANGELOG.md +16 -0
- package/dist/arrays.d.ts +1 -0
- package/dist/arrays.d.ts.map +1 -0
- package/dist/arrays.js +22 -0
- package/dist/arrays.js.map +1 -0
- package/dist/async.d.ts +2 -1
- package/dist/async.d.ts.map +1 -0
- package/dist/async.js +187 -0
- package/dist/async.js.map +1 -0
- package/dist/check.d.ts +3 -2
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +20 -0
- package/dist/check.js.map +1 -0
- package/dist/did-doc.d.ts +6 -5
- package/dist/did-doc.d.ts.map +1 -0
- package/dist/did-doc.js +157 -0
- package/dist/did-doc.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -14274
- package/dist/index.js.map +1 -7
- package/dist/ipld.d.ts +1 -0
- package/dist/ipld.d.ts.map +1 -0
- package/dist/ipld.js +119 -0
- package/dist/ipld.js.map +1 -0
- package/dist/retry.d.ts +1 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +46 -0
- package/dist/retry.js.map +1 -0
- package/dist/strings.d.ts +1 -0
- package/dist/strings.d.ts.map +1 -0
- package/dist/strings.js +74 -0
- package/dist/strings.js.map +1 -0
- package/dist/tid.d.ts +1 -0
- package/dist/tid.d.ts.map +1 -0
- package/dist/tid.js +100 -0
- package/dist/tid.js.map +1 -0
- package/dist/times.d.ts +1 -0
- package/dist/times.d.ts.map +1 -0
- package/dist/times.js +19 -0
- package/dist/times.js.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +42 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +2 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +120 -0
- package/dist/util.js.map +1 -0
- package/jest.config.js +3 -3
- package/package.json +8 -7
- package/src/arrays.ts +7 -4
- package/src/check.ts +8 -2
- package/src/did-doc.ts +83 -39
- package/src/util.ts +15 -0
- package/tsconfig.build.json +6 -2
- package/tsconfig.json +5 -7
- package/tsconfig.tests.json +7 -0
- package/babel.config.js +0 -1
- package/build.js +0 -15
package/jest.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/common-web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Shared web-platform-friendly code for atproto libraries",
|
|
6
6
|
"keywords": [
|
|
@@ -13,17 +13,18 @@
|
|
|
13
13
|
"directory": "packages/common-web"
|
|
14
14
|
},
|
|
15
15
|
"main": "dist/index.js",
|
|
16
|
+
"types": "dist/index.d.ts",
|
|
16
17
|
"dependencies": {
|
|
17
18
|
"graphemer": "^1.4.0",
|
|
18
19
|
"multiformats": "^9.9.0",
|
|
19
20
|
"uint8arrays": "3.0.0",
|
|
20
|
-
"zod": "^3.
|
|
21
|
+
"zod": "^3.23.8"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"jest": "^28.1.2"
|
|
21
25
|
},
|
|
22
26
|
"scripts": {
|
|
23
27
|
"test": "jest",
|
|
24
|
-
"build": "
|
|
25
|
-
|
|
26
|
-
"update-main-to-dist": "node ../../update-main-to-dist.js packages/common-web"
|
|
27
|
-
},
|
|
28
|
-
"types": "dist/index.d.ts"
|
|
28
|
+
"build": "tsc --build tsconfig.build.json"
|
|
29
|
+
}
|
|
29
30
|
}
|
package/src/arrays.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export const keyBy = <T>(arr: T[], key: string): Record<string, T> => {
|
|
2
|
-
return arr.reduce(
|
|
3
|
-
acc
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
return arr.reduce(
|
|
3
|
+
(acc, cur) => {
|
|
4
|
+
acc[cur[key]] = cur
|
|
5
|
+
return acc
|
|
6
|
+
},
|
|
7
|
+
{} as Record<string, T>,
|
|
8
|
+
)
|
|
6
9
|
}
|
|
7
10
|
|
|
8
11
|
export const mapDefined = <T, S>(
|
package/src/check.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
// Explicitly not using "zod" types here to avoid mismatching types due to
|
|
2
|
+
// version differences.
|
|
2
3
|
|
|
3
4
|
export interface Checkable<T> {
|
|
4
5
|
parse: (obj: unknown) => T
|
|
5
6
|
safeParse: (
|
|
6
7
|
obj: unknown,
|
|
7
|
-
) => { success: true; data: T } | { success: false; error:
|
|
8
|
+
) => { success: true; data: T } | { success: false; error: Error }
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export interface Def<T> {
|
|
@@ -16,6 +17,11 @@ export const is = <T>(obj: unknown, def: Checkable<T>): obj is T => {
|
|
|
16
17
|
return def.safeParse(obj).success
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
export const create =
|
|
21
|
+
<T>(def: Checkable<T>) =>
|
|
22
|
+
(v: unknown): v is T =>
|
|
23
|
+
def.safeParse(v).success
|
|
24
|
+
|
|
19
25
|
export const assure = <T>(def: Checkable<T>, obj: unknown): T => {
|
|
20
26
|
return def.parse(obj)
|
|
21
27
|
}
|
package/src/did-doc.ts
CHANGED
|
@@ -17,11 +17,16 @@ export const getDid = (doc: DidDocument): string => {
|
|
|
17
17
|
|
|
18
18
|
export const getHandle = (doc: DidDocument): string | undefined => {
|
|
19
19
|
const aka = doc.alsoKnownAs
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
if (aka) {
|
|
21
|
+
for (let i = 0; i < aka.length; i++) {
|
|
22
|
+
const alias = aka[i]
|
|
23
|
+
if (alias.startsWith('at://')) {
|
|
24
|
+
// strip off "at://" prefix
|
|
25
|
+
return alias.slice(5)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return undefined
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
// @NOTE we parse to type/publicKeyMultibase to avoid the dependency on @atproto/crypto
|
|
@@ -35,20 +40,20 @@ export const getVerificationMaterial = (
|
|
|
35
40
|
doc: DidDocument,
|
|
36
41
|
keyId: string,
|
|
37
42
|
): { type: string; publicKeyMultibase: string } | undefined => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
// /!\ Hot path
|
|
44
|
+
|
|
45
|
+
const key = findItemById(doc, 'verificationMethod', `#${keyId}`)
|
|
46
|
+
if (!key) {
|
|
47
|
+
return undefined
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!key.publicKeyMultibase) {
|
|
51
|
+
return undefined
|
|
44
52
|
}
|
|
45
|
-
|
|
46
|
-
(key) => key.id === `#${keyId}` || key.id === `${did}#${keyId}`,
|
|
47
|
-
)
|
|
48
|
-
if (!found?.publicKeyMultibase) return undefined
|
|
53
|
+
|
|
49
54
|
return {
|
|
50
|
-
type:
|
|
51
|
-
publicKeyMultibase:
|
|
55
|
+
type: key.type,
|
|
56
|
+
publicKeyMultibase: key.publicKeyMultibase,
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
|
|
@@ -83,43 +88,82 @@ export const getServiceEndpoint = (
|
|
|
83
88
|
doc: DidDocument,
|
|
84
89
|
opts: { id: string; type?: string },
|
|
85
90
|
) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
services = [services]
|
|
91
|
+
// /!\ Hot path
|
|
92
|
+
|
|
93
|
+
const service = findItemById(doc, 'service', opts.id)
|
|
94
|
+
if (!service) {
|
|
95
|
+
return undefined
|
|
92
96
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
)
|
|
96
|
-
if (!found) return undefined
|
|
97
|
-
if (opts.type && found.type !== opts.type) {
|
|
97
|
+
|
|
98
|
+
if (opts.type && service.type !== opts.type) {
|
|
98
99
|
return undefined
|
|
99
100
|
}
|
|
100
|
-
|
|
101
|
+
|
|
102
|
+
if (typeof service.serviceEndpoint !== 'string') {
|
|
101
103
|
return undefined
|
|
102
104
|
}
|
|
103
|
-
|
|
105
|
+
|
|
106
|
+
return validateUrl(service.serviceEndpoint)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function findItemById<
|
|
110
|
+
D extends DidDocument,
|
|
111
|
+
T extends 'verificationMethod' | 'service',
|
|
112
|
+
>(doc: D, type: T, id: string): NonNullable<D[T]>[number] | undefined
|
|
113
|
+
function findItemById(
|
|
114
|
+
doc: DidDocument,
|
|
115
|
+
type: 'verificationMethod' | 'service',
|
|
116
|
+
id: string,
|
|
117
|
+
) {
|
|
118
|
+
// /!\ Hot path
|
|
119
|
+
|
|
120
|
+
const items = doc[type]
|
|
121
|
+
if (items) {
|
|
122
|
+
for (let i = 0; i < items.length; i++) {
|
|
123
|
+
const item = items[i]
|
|
124
|
+
const itemId = item.id
|
|
125
|
+
|
|
126
|
+
if (
|
|
127
|
+
itemId[0] === '#'
|
|
128
|
+
? itemId === id
|
|
129
|
+
: // Optimized version of: itemId === `${doc.id}${id}`
|
|
130
|
+
itemId.length === doc.id.length + id.length &&
|
|
131
|
+
itemId[doc.id.length] === '#' &&
|
|
132
|
+
itemId.endsWith(id) &&
|
|
133
|
+
itemId.startsWith(doc.id) // <== We could probably skip this check
|
|
134
|
+
) {
|
|
135
|
+
return item
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return undefined
|
|
104
140
|
}
|
|
105
141
|
|
|
106
142
|
// Check protocol and hostname to prevent potential SSRF
|
|
107
143
|
const validateUrl = (urlStr: string): string | undefined => {
|
|
108
|
-
|
|
109
|
-
try {
|
|
110
|
-
url = new URL(urlStr)
|
|
111
|
-
} catch {
|
|
144
|
+
if (!urlStr.startsWith('http://') && !urlStr.startsWith('https://')) {
|
|
112
145
|
return undefined
|
|
113
146
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
} else if (!url.hostname) {
|
|
147
|
+
|
|
148
|
+
if (!canParseUrl(urlStr)) {
|
|
117
149
|
return undefined
|
|
118
|
-
} else {
|
|
119
|
-
return urlStr
|
|
120
150
|
}
|
|
151
|
+
|
|
152
|
+
return urlStr
|
|
121
153
|
}
|
|
122
154
|
|
|
155
|
+
const canParseUrl =
|
|
156
|
+
URL.canParse ??
|
|
157
|
+
// URL.canParse is not available in Node.js < 18.17.0
|
|
158
|
+
((urlStr: string): boolean => {
|
|
159
|
+
try {
|
|
160
|
+
new URL(urlStr)
|
|
161
|
+
return true
|
|
162
|
+
} catch {
|
|
163
|
+
return false
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
|
|
123
167
|
// Types
|
|
124
168
|
// --------
|
|
125
169
|
|
package/src/util.ts
CHANGED
|
@@ -9,6 +9,21 @@ export const noUndefinedVals = <T>(
|
|
|
9
9
|
return obj as Record<string, T>
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
export function omit<
|
|
13
|
+
T extends undefined | Record<string, unknown>,
|
|
14
|
+
K extends keyof NonNullable<T>,
|
|
15
|
+
>(obj: T, keys: readonly K[]): T extends undefined ? undefined : Omit<T, K>
|
|
16
|
+
export function omit(
|
|
17
|
+
obj: Record<string, unknown>,
|
|
18
|
+
keys: readonly string[],
|
|
19
|
+
): undefined | Record<string, unknown> {
|
|
20
|
+
if (!obj) return obj
|
|
21
|
+
|
|
22
|
+
return Object.fromEntries(
|
|
23
|
+
Object.entries(obj).filter((entry) => !keys.includes(entry[0])),
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
12
27
|
export const jitter = (maxMs: number) => {
|
|
13
28
|
return Math.round((Math.random() - 0.5) * maxMs * 2)
|
|
14
29
|
}
|
package/tsconfig.build.json
CHANGED
package/tsconfig.json
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
},
|
|
8
|
-
"include": ["./src", "__tests__/**/**.ts"]
|
|
2
|
+
"include": [],
|
|
3
|
+
"references": [
|
|
4
|
+
{ "path": "./tsconfig.build.json" },
|
|
5
|
+
{ "path": "./tsconfig.tests.json" }
|
|
6
|
+
]
|
|
9
7
|
}
|
package/babel.config.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = require('../../babel.config.js')
|
package/build.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
const { nodeExternalsPlugin } = require('esbuild-node-externals')
|
|
2
|
-
|
|
3
|
-
const buildShallow =
|
|
4
|
-
process.argv.includes('--shallow') || process.env.ATP_BUILD_SHALLOW === 'true'
|
|
5
|
-
|
|
6
|
-
require('esbuild').build({
|
|
7
|
-
logLevel: 'info',
|
|
8
|
-
entryPoints: ['src/index.ts'],
|
|
9
|
-
bundle: true,
|
|
10
|
-
sourcemap: true,
|
|
11
|
-
outdir: 'dist',
|
|
12
|
-
platform: 'browser',
|
|
13
|
-
format: 'cjs',
|
|
14
|
-
plugins: buildShallow ? [nodeExternalsPlugin()] : [],
|
|
15
|
-
})
|