@atproto/lex-schema 0.0.17 → 0.0.19
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 +20 -0
- package/dist/core/string-format.d.ts +10 -16
- package/dist/core/string-format.d.ts.map +1 -1
- package/dist/core/string-format.js +21 -11
- package/dist/core/string-format.js.map +1 -1
- package/dist/schema/blob.d.ts +6 -20
- package/dist/schema/blob.d.ts.map +1 -1
- package/dist/schema/blob.js +23 -28
- package/dist/schema/blob.js.map +1 -1
- package/package.json +3 -3
- package/src/core/string-format.ts +24 -20
- package/src/schema/blob.test.ts +223 -263
- package/src/schema/blob.ts +27 -46
package/src/schema/blob.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BlobRef,
|
|
3
3
|
LegacyBlobRef,
|
|
4
|
+
TypedBlobRef,
|
|
5
|
+
getBlobSize,
|
|
4
6
|
isBlobRef,
|
|
5
7
|
isLegacyBlobRef,
|
|
6
|
-
|
|
8
|
+
isTypedBlobRef,
|
|
7
9
|
} from '@atproto/lex-data'
|
|
8
10
|
import { Schema, ValidationContext } from '../core.js'
|
|
9
11
|
import { memoizedOptions } from '../util/memoize.js'
|
|
@@ -12,14 +14,6 @@ import { memoizedOptions } from '../util/memoize.js'
|
|
|
12
14
|
* Configuration options for blob schema validation.
|
|
13
15
|
*/
|
|
14
16
|
export type BlobSchemaOptions = {
|
|
15
|
-
/**
|
|
16
|
-
* Whether to allow legacy blob references format
|
|
17
|
-
*
|
|
18
|
-
* @default false
|
|
19
|
-
* @see {@link LegacyBlobRef}
|
|
20
|
-
*/
|
|
21
|
-
allowLegacy?: boolean
|
|
22
|
-
|
|
23
17
|
/**
|
|
24
18
|
* List of accepted MIME types (supports wildcards like 'image/*' or '*\/*')
|
|
25
19
|
*
|
|
@@ -35,8 +29,8 @@ export type BlobSchemaOptions = {
|
|
|
35
29
|
maxSize?: number
|
|
36
30
|
}
|
|
37
31
|
|
|
38
|
-
export type { BlobRef, LegacyBlobRef }
|
|
39
|
-
export { isBlobRef, isLegacyBlobRef }
|
|
32
|
+
export type { BlobRef, LegacyBlobRef, TypedBlobRef }
|
|
33
|
+
export { isBlobRef, isLegacyBlobRef, isTypedBlobRef }
|
|
40
34
|
|
|
41
35
|
/**
|
|
42
36
|
* Schema for validating blob references in AT Protocol.
|
|
@@ -55,9 +49,7 @@ export { isBlobRef, isLegacyBlobRef }
|
|
|
55
49
|
*/
|
|
56
50
|
export class BlobSchema<
|
|
57
51
|
const TOptions extends BlobSchemaOptions = NonNullable<unknown>,
|
|
58
|
-
> extends Schema<
|
|
59
|
-
TOptions extends { allowLegacy: true } ? BlobRef | LegacyBlobRef : BlobRef
|
|
60
|
-
> {
|
|
52
|
+
> extends Schema<BlobRef> {
|
|
61
53
|
readonly type = 'blob' as const
|
|
62
54
|
|
|
63
55
|
constructor(readonly options?: TOptions) {
|
|
@@ -65,23 +57,29 @@ export class BlobSchema<
|
|
|
65
57
|
}
|
|
66
58
|
|
|
67
59
|
validateInContext(input: unknown, ctx: ValidationContext) {
|
|
68
|
-
const blob = parseValue.call(ctx, input
|
|
69
|
-
|
|
60
|
+
const blob = parseValue.call(ctx, input)
|
|
70
61
|
if (!blob) {
|
|
71
62
|
return ctx.issueUnexpectedType(input, 'blob')
|
|
72
63
|
}
|
|
73
64
|
|
|
74
65
|
// In non-strict mode, we allow blob refs to pass through without MIME
|
|
75
66
|
// type or size checks.
|
|
76
|
-
if (ctx.options.strict) {
|
|
77
|
-
const accept = this.options
|
|
67
|
+
if (ctx.options.strict && this.options != null) {
|
|
68
|
+
const { accept } = this.options
|
|
78
69
|
if (accept && !matchesMime(blob.mimeType, accept)) {
|
|
79
70
|
return ctx.issueInvalidPropertyValue(blob, 'mimeType', accept)
|
|
80
71
|
}
|
|
81
72
|
|
|
82
|
-
const maxSize = this.options
|
|
83
|
-
if (maxSize != null
|
|
84
|
-
|
|
73
|
+
const { maxSize } = this.options
|
|
74
|
+
if (maxSize != null) {
|
|
75
|
+
const size = getBlobSize(blob)
|
|
76
|
+
if (size === undefined) {
|
|
77
|
+
// Unable to enforce size constraint if size is not available (legacy
|
|
78
|
+
// blob ref), so we treat it as a validation failure in strict mode.
|
|
79
|
+
return ctx.issueInvalidPropertyType(blob, 'size' as any, 'integer')
|
|
80
|
+
} else if (size > maxSize) {
|
|
81
|
+
return ctx.issueTooBig(blob, 'blob', maxSize, size)
|
|
82
|
+
}
|
|
85
83
|
}
|
|
86
84
|
}
|
|
87
85
|
|
|
@@ -95,33 +93,19 @@ export class BlobSchema<
|
|
|
95
93
|
}
|
|
96
94
|
}
|
|
97
95
|
|
|
98
|
-
function parseValue(
|
|
99
|
-
|
|
100
|
-
input: unknown,
|
|
101
|
-
options?: BlobSchemaOptions,
|
|
102
|
-
): BlobRef | LegacyBlobRef | null {
|
|
103
|
-
// If there is a $type property, we treat if as a potential BlobRef and
|
|
96
|
+
function parseValue(this: ValidationContext, input: unknown): BlobRef | null {
|
|
97
|
+
// If there is a $type property, we treat if as a potential TypedBlobRef and
|
|
104
98
|
// validate accordingly.
|
|
105
99
|
if ((input as any)?.$type !== undefined) {
|
|
106
100
|
// Use the context's option for the "strict" check
|
|
107
|
-
return
|
|
101
|
+
return isTypedBlobRef(input, this.options) ? input : null
|
|
108
102
|
}
|
|
109
103
|
|
|
110
104
|
// If there is no $type property, we may be dealing with a legacy blob ref. If
|
|
111
|
-
// legacy refs are allowed,
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (options?.allowLegacy) {
|
|
116
|
-
if (isLegacyBlobRef(input)) {
|
|
117
|
-
return input
|
|
118
|
-
}
|
|
119
|
-
} else if (!this.options.strict && this.options.mode === 'parse') {
|
|
120
|
-
if (isLegacyBlobRef(input)) {
|
|
121
|
-
const { cid, mimeType } = input
|
|
122
|
-
const ref = parseCidSafe(cid)
|
|
123
|
-
if (ref) return { $type: 'blob', ref, mimeType, size: -1 }
|
|
124
|
-
}
|
|
105
|
+
// legacy refs are allowed (non-strict mode), we check if the input matches
|
|
106
|
+
// the legacy format.
|
|
107
|
+
if (!this.options.strict) {
|
|
108
|
+
if (isLegacyBlobRef(input, this.options)) return input
|
|
125
109
|
}
|
|
126
110
|
|
|
127
111
|
return null
|
|
@@ -157,13 +141,10 @@ function matchesMime(mime: string, accepted: string[]): boolean {
|
|
|
157
141
|
*
|
|
158
142
|
* // Any image type with size limit
|
|
159
143
|
* const avatarSchema = l.blob({ accept: ['image/*'], maxSize: 1000000 })
|
|
160
|
-
*
|
|
161
|
-
* // Allow legacy format
|
|
162
|
-
* const legacySchema = l.blob({ allowLegacy: true })
|
|
163
144
|
* ```
|
|
164
145
|
*/
|
|
165
146
|
export const blob = /*#__PURE__*/ memoizedOptions(function <
|
|
166
|
-
O extends BlobSchemaOptions =
|
|
147
|
+
O extends BlobSchemaOptions = NonNullable<unknown>,
|
|
167
148
|
>(options?: O) {
|
|
168
149
|
return new BlobSchema(options)
|
|
169
150
|
})
|