@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.
@@ -1,9 +1,11 @@
1
1
  import {
2
2
  BlobRef,
3
3
  LegacyBlobRef,
4
+ TypedBlobRef,
5
+ getBlobSize,
4
6
  isBlobRef,
5
7
  isLegacyBlobRef,
6
- parseCidSafe,
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, this.options)
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?.accept
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?.maxSize
83
- if (maxSize != null && 'size' in blob && blob.size > maxSize) {
84
- return ctx.issueTooBig(blob, 'blob', maxSize, blob.size)
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
- this: ValidationContext,
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 isBlobRef(input, this.options) ? input : null
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, validate against the legacy format. If not
112
- // allowed, but we are in non-strict "parse" mode, coerce legacy refs into
113
- // standard BlobRef format for backward compatibility. Otherwise, reject the
114
- // value.
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 = { allowLegacy?: false },
147
+ O extends BlobSchemaOptions = NonNullable<unknown>,
167
148
  >(options?: O) {
168
149
  return new BlobSchema(options)
169
150
  })