sanity-plugin-media 4.3.5 → 5.0.0
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/dist/index.d.ts +190 -413
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2532 -3564
- package/dist/index.js.map +1 -1
- package/package.json +29 -35
- package/dist/index.cjs +0 -5753
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -462
- package/sanity.json +0 -8
- package/src/__tests__/fixtures/createEpicTestStore.ts +0 -28
- package/src/__tests__/fixtures/listenMock.ts +0 -9
- package/src/__tests__/fixtures/mockSanityClient.ts +0 -84
- package/src/__tests__/fixtures/renderWithProviders.tsx +0 -55
- package/src/__tests__/fixtures/rootState.ts +0 -27
- package/src/__tests__/fixtures/withinDialog.ts +0 -28
- package/src/components/AssetGridVirtualized/index.tsx +0 -94
- package/src/components/AssetMetadata/index.tsx +0 -122
- package/src/components/AssetTableVirtualized/index.tsx +0 -73
- package/src/components/AutoTagInputWrapper/index.tsx +0 -87
- package/src/components/Browser/Browser.test.tsx +0 -45
- package/src/components/Browser/index.tsx +0 -90
- package/src/components/Browser/useBrowserInit.ts +0 -126
- package/src/components/ButtonAssetCopy/index.tsx +0 -65
- package/src/components/ButtonViewGroup/index.tsx +0 -39
- package/src/components/CardAsset/CardAsset.test.tsx +0 -323
- package/src/components/CardAsset/index.tsx +0 -290
- package/src/components/CardUpload/index.tsx +0 -161
- package/src/components/Controls/index.tsx +0 -136
- package/src/components/DebugControls/index.tsx +0 -80
- package/src/components/Dialog/index.tsx +0 -11
- package/src/components/DialogAssetEdit/Details.tsx +0 -181
- package/src/components/DialogAssetEdit/DialogAssetEdit.test.tsx +0 -216
- package/src/components/DialogAssetEdit/index.tsx +0 -492
- package/src/components/DialogConfirm/index.tsx +0 -88
- package/src/components/DialogSearchFacets/index.tsx +0 -42
- package/src/components/DialogTagCreate/DialogTagCreate.test.tsx +0 -121
- package/src/components/DialogTagCreate/index.tsx +0 -103
- package/src/components/DialogTagEdit/DialogTagEdit.test.tsx +0 -165
- package/src/components/DialogTagEdit/index.tsx +0 -190
- package/src/components/DialogTags/index.tsx +0 -45
- package/src/components/Dialogs/index.tsx +0 -76
- package/src/components/DocumentList/index.tsx +0 -62
- package/src/components/FileAssetPreview/index.tsx +0 -37
- package/src/components/FileIcon/index.tsx +0 -43
- package/src/components/FormBuilderTool/FormBuilderTool.test.tsx +0 -63
- package/src/components/FormBuilderTool/index.tsx +0 -69
- package/src/components/FormFieldInputLabel/index.tsx +0 -66
- package/src/components/FormFieldInputTags/index.tsx +0 -98
- package/src/components/FormFieldInputText/index.tsx +0 -41
- package/src/components/FormFieldInputTextarea/index.tsx +0 -43
- package/src/components/FormSubmitButton/index.tsx +0 -59
- package/src/components/Header/index.tsx +0 -80
- package/src/components/Image/index.tsx +0 -41
- package/src/components/Items/index.tsx +0 -68
- package/src/components/Notifications/index.tsx +0 -24
- package/src/components/OrderSelect/index.tsx +0 -66
- package/src/components/PickedBar/index.tsx +0 -77
- package/src/components/Progress/index.tsx +0 -38
- package/src/components/ReduxProvider/index.tsx +0 -96
- package/src/components/SearchFacet/index.tsx +0 -66
- package/src/components/SearchFacetNumber/index.tsx +0 -133
- package/src/components/SearchFacetSelect/index.tsx +0 -110
- package/src/components/SearchFacetString/index.tsx +0 -88
- package/src/components/SearchFacetTags/index.tsx +0 -121
- package/src/components/SearchFacets/index.tsx +0 -72
- package/src/components/SearchFacetsControl/index.tsx +0 -140
- package/src/components/TableHeader/index.tsx +0 -110
- package/src/components/TableHeaderItem/index.tsx +0 -61
- package/src/components/TableRowAsset/index.tsx +0 -420
- package/src/components/TableRowUpload/index.tsx +0 -164
- package/src/components/Tag/index.tsx +0 -200
- package/src/components/TagIcon/index.tsx +0 -22
- package/src/components/TagView/index.tsx +0 -39
- package/src/components/TagViewHeader/index.tsx +0 -70
- package/src/components/TagsPanel/index.tsx +0 -40
- package/src/components/TagsVirtualized/index.tsx +0 -160
- package/src/components/TextInputNumber/index.tsx +0 -32
- package/src/components/TextInputSearch/index.tsx +0 -60
- package/src/components/Tool/index.tsx +0 -13
- package/src/components/UploadDropzone/UploadDropzone.test.tsx +0 -40
- package/src/components/UploadDropzone/index.tsx +0 -173
- package/src/config/orders.ts +0 -28
- package/src/config/searchFacets.ts +0 -312
- package/src/constants.ts +0 -87
- package/src/contexts/AssetSourceDispatchContext.tsx +0 -37
- package/src/contexts/DropzoneDispatchContext.tsx +0 -34
- package/src/contexts/ToolOptionsContext.tsx +0 -65
- package/src/formSchema/index.test.ts +0 -56
- package/src/formSchema/index.ts +0 -39
- package/src/hooks/useBreakpointIndex.ts +0 -49
- package/src/hooks/useKeyPress.ts +0 -39
- package/src/hooks/useOnScreen.ts +0 -34
- package/src/hooks/usePortalPopoverProps.ts +0 -13
- package/src/hooks/useTypedSelector.ts +0 -7
- package/src/hooks/useVersionedClient.ts +0 -6
- package/src/index.ts +0 -5
- package/src/modules/assets/actions.ts +0 -42
- package/src/modules/assets/deleteAndUpdateEpics.test.ts +0 -87
- package/src/modules/assets/fetchEpic.test.ts +0 -73
- package/src/modules/assets/index.ts +0 -825
- package/src/modules/assets/reducer.test.ts +0 -91
- package/src/modules/assets/tagsAndListenerEpics.test.ts +0 -206
- package/src/modules/debug/index.ts +0 -28
- package/src/modules/dialog/actions.ts +0 -10
- package/src/modules/dialog/epics.test.ts +0 -168
- package/src/modules/dialog/index.ts +0 -238
- package/src/modules/dialog/reducer.test.ts +0 -185
- package/src/modules/index.ts +0 -124
- package/src/modules/notifications/epics.test.ts +0 -374
- package/src/modules/notifications/index.ts +0 -199
- package/src/modules/notifications/reducer.test.ts +0 -54
- package/src/modules/search/index.test.ts +0 -36
- package/src/modules/search/index.ts +0 -167
- package/src/modules/selected/index.ts +0 -22
- package/src/modules/selectors.test.ts +0 -21
- package/src/modules/selectors.ts +0 -17
- package/src/modules/tags/epics.test.ts +0 -96
- package/src/modules/tags/index.test.ts +0 -42
- package/src/modules/tags/index.ts +0 -540
- package/src/modules/types.ts +0 -3
- package/src/modules/uploads/actions.ts +0 -13
- package/src/modules/uploads/epics.test.ts +0 -109
- package/src/modules/uploads/index.test.ts +0 -59
- package/src/modules/uploads/index.ts +0 -282
- package/src/operators/checkTagName.test.ts +0 -29
- package/src/operators/checkTagName.ts +0 -33
- package/src/operators/debugThrottle.ts +0 -25
- package/src/plugin.tsx +0 -54
- package/src/schemas/tag.ts +0 -28
- package/src/styled/GlobalStyles/index.tsx +0 -40
- package/src/styled/react-select/creatable.tsx +0 -184
- package/src/styled/react-select/single.tsx +0 -184
- package/src/types/index.ts +0 -379
- package/src/types/sanity-ui.d.ts +0 -6
- package/src/utils/applyMediaTags.ts +0 -87
- package/src/utils/blocksToText.test.ts +0 -43
- package/src/utils/blocksToText.ts +0 -27
- package/src/utils/constructFilter.test.ts +0 -120
- package/src/utils/constructFilter.ts +0 -98
- package/src/utils/generatePreviewBlobUrl.test.ts +0 -70
- package/src/utils/generatePreviewBlobUrl.ts +0 -53
- package/src/utils/getAssetResolution.test.ts +0 -13
- package/src/utils/getAssetResolution.ts +0 -7
- package/src/utils/getDocumentAssetIds.test.ts +0 -50
- package/src/utils/getDocumentAssetIds.ts +0 -35
- package/src/utils/getSchemeColor.test.ts +0 -12
- package/src/utils/getSchemeColor.ts +0 -43
- package/src/utils/getTagSelectOptions.test.ts +0 -44
- package/src/utils/getTagSelectOptions.ts +0 -16
- package/src/utils/getUniqueDocuments.test.ts +0 -26
- package/src/utils/getUniqueDocuments.ts +0 -15
- package/src/utils/imageDprUrl.test.ts +0 -46
- package/src/utils/imageDprUrl.ts +0 -27
- package/src/utils/isSupportedAssetType.test.ts +0 -16
- package/src/utils/isSupportedAssetType.ts +0 -15
- package/src/utils/mediaField.ts +0 -73
- package/src/utils/sanitizeFormData.test.ts +0 -59
- package/src/utils/sanitizeFormData.ts +0 -26
- package/src/utils/typeGuards.test.ts +0 -18
- package/src/utils/typeGuards.ts +0 -9
- package/src/utils/uploadSanityAsset.test.ts +0 -29
- package/src/utils/uploadSanityAsset.ts +0 -97
- package/src/utils/withMaxConcurrency.test.ts +0 -43
- package/src/utils/withMaxConcurrency.ts +0 -55
- package/src/utils/zodFormResolver.ts +0 -17
- package/v2-incompatible.js +0 -11
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
// @vitest-environment node
|
|
2
|
-
|
|
3
|
-
import {describe, expect, it} from 'vitest'
|
|
4
|
-
|
|
5
|
-
import sanitizeFormData from './sanitizeFormData'
|
|
6
|
-
|
|
7
|
-
describe('sanitizeFormData', () => {
|
|
8
|
-
it('maps empty string, undefined, and empty array to null', () => {
|
|
9
|
-
expect(
|
|
10
|
-
sanitizeFormData({
|
|
11
|
-
a: '',
|
|
12
|
-
b: undefined,
|
|
13
|
-
c: [],
|
|
14
|
-
}),
|
|
15
|
-
).toEqual({
|
|
16
|
-
a: null,
|
|
17
|
-
b: null,
|
|
18
|
-
c: null,
|
|
19
|
-
})
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
it('trims non-empty strings', () => {
|
|
23
|
-
expect(sanitizeFormData({title: ' hello '})).toEqual({title: 'hello'})
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
it('recurses into plain objects', () => {
|
|
27
|
-
expect(
|
|
28
|
-
sanitizeFormData({
|
|
29
|
-
opt: {
|
|
30
|
-
media: {
|
|
31
|
-
tags: [],
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
}),
|
|
35
|
-
).toEqual({
|
|
36
|
-
opt: {
|
|
37
|
-
media: {
|
|
38
|
-
tags: null,
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
})
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('preserves null and non-empty arrays', () => {
|
|
45
|
-
expect(
|
|
46
|
-
sanitizeFormData({
|
|
47
|
-
kept: null,
|
|
48
|
-
tags: [{_ref: 't1'}],
|
|
49
|
-
}),
|
|
50
|
-
).toEqual({
|
|
51
|
-
kept: null,
|
|
52
|
-
tags: [{_ref: 't1'}],
|
|
53
|
-
})
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('preserves numbers and booleans', () => {
|
|
57
|
-
expect(sanitizeFormData({n: 0, ok: false})).toEqual({n: 0, ok: false})
|
|
58
|
-
})
|
|
59
|
-
})
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// Recursively sanitize form data:
|
|
2
|
-
// - convert empty strings, undefined values and empty arrays to null (to correctly unset / delete fields)
|
|
3
|
-
// - trim whitespace on string fleids
|
|
4
|
-
|
|
5
|
-
type FormData = Record<string, any>
|
|
6
|
-
|
|
7
|
-
const sanitizeFormData = (formData: FormData): FormData => {
|
|
8
|
-
return Object.keys(formData).reduce((acc: FormData, key) => {
|
|
9
|
-
const val = formData[key]
|
|
10
|
-
|
|
11
|
-
// TODO: refactor
|
|
12
|
-
if (typeof val === 'object' && val !== null && val.constructor !== Array) {
|
|
13
|
-
acc[key] = sanitizeFormData(val)
|
|
14
|
-
} else if (val === '' || typeof val === 'undefined' || val?.length === 0) {
|
|
15
|
-
acc[key] = null
|
|
16
|
-
} else if (typeof val === 'string' && val) {
|
|
17
|
-
acc[key] = formData[key].trim()
|
|
18
|
-
} else {
|
|
19
|
-
acc[key] = formData[key]
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return acc
|
|
23
|
-
}, {})
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default sanitizeFormData
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import {describe, expect, it} from 'vitest'
|
|
2
|
-
|
|
3
|
-
import type {Asset} from '../types'
|
|
4
|
-
import {isFileAsset, isImageAsset} from './typeGuards'
|
|
5
|
-
|
|
6
|
-
describe('typeGuards', () => {
|
|
7
|
-
it('isFileAsset narrows sanity.fileAsset', () => {
|
|
8
|
-
const file = {_type: 'sanity.fileAsset'} as Asset
|
|
9
|
-
expect(isFileAsset(file)).toBe(true)
|
|
10
|
-
expect(isImageAsset(file)).toBe(false)
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('isImageAsset narrows sanity.imageAsset', () => {
|
|
14
|
-
const image = {_type: 'sanity.imageAsset'} as Asset
|
|
15
|
-
expect(isImageAsset(image)).toBe(true)
|
|
16
|
-
expect(isFileAsset(image)).toBe(false)
|
|
17
|
-
})
|
|
18
|
-
})
|
package/src/utils/typeGuards.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type {Asset, FileAsset, ImageAsset} from '../types'
|
|
2
|
-
|
|
3
|
-
export const isFileAsset = (asset: Asset): asset is FileAsset => {
|
|
4
|
-
return (asset as FileAsset)._type === 'sanity.fileAsset'
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export const isImageAsset = (asset: Asset): asset is ImageAsset => {
|
|
8
|
-
return (asset as ImageAsset)._type === 'sanity.imageAsset'
|
|
9
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import {firstValueFrom} from 'rxjs'
|
|
2
|
-
import {afterEach, describe, expect, it} from 'vitest'
|
|
3
|
-
|
|
4
|
-
import {hashFile$} from './uploadSanityAsset'
|
|
5
|
-
|
|
6
|
-
describe('hashFile$', () => {
|
|
7
|
-
const cryptoRef = globalThis.crypto
|
|
8
|
-
|
|
9
|
-
afterEach(() => {
|
|
10
|
-
Object.defineProperty(globalThis, 'crypto', {
|
|
11
|
-
value: cryptoRef,
|
|
12
|
-
configurable: true,
|
|
13
|
-
writable: true,
|
|
14
|
-
})
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it('errors when Web Crypto is unavailable', async () => {
|
|
18
|
-
Object.defineProperty(globalThis, 'crypto', {
|
|
19
|
-
value: undefined,
|
|
20
|
-
configurable: true,
|
|
21
|
-
writable: true,
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
await expect(firstValueFrom(hashFile$(new File(['x'], 'blob.bin')))).rejects.toMatchObject({
|
|
25
|
-
message: expect.stringMatching(/secure contexts/i),
|
|
26
|
-
statusCode: 500,
|
|
27
|
-
})
|
|
28
|
-
})
|
|
29
|
-
})
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// Sourced from:
|
|
2
|
-
// https://github.com/sanity-io/sanity/blob/ccb777e115a8cdf20d81a9a2bc9d8c228568faff/packages/%40sanity/form-builder/src/sanity/inputs/client-adapters/assets.ts
|
|
3
|
-
|
|
4
|
-
import type {SanityAssetDocument, SanityClient, SanityImageAssetDocument} from '@sanity/client'
|
|
5
|
-
import {Observable, of, throwError} from 'rxjs'
|
|
6
|
-
import {map, mergeMap} from 'rxjs/operators'
|
|
7
|
-
|
|
8
|
-
import type {HttpError} from '../types'
|
|
9
|
-
import {withMaxConcurrency} from './withMaxConcurrency'
|
|
10
|
-
|
|
11
|
-
const fetchExisting$ = (client: SanityClient, type: string, hash: string) => {
|
|
12
|
-
return client.observable.fetch('*[_type == $documentType && sha1hash == $hash][0]', {
|
|
13
|
-
documentType: type,
|
|
14
|
-
hash,
|
|
15
|
-
})
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const readFile$ = (file: File): Observable<ArrayBuffer> => {
|
|
19
|
-
return new Observable((subscriber) => {
|
|
20
|
-
const reader = new FileReader()
|
|
21
|
-
reader.onload = () => {
|
|
22
|
-
subscriber.next(reader.result as ArrayBuffer)
|
|
23
|
-
subscriber.complete()
|
|
24
|
-
}
|
|
25
|
-
reader.onerror = (err) => {
|
|
26
|
-
subscriber.error(err)
|
|
27
|
-
}
|
|
28
|
-
reader.readAsArrayBuffer(file)
|
|
29
|
-
return () => {
|
|
30
|
-
reader.abort()
|
|
31
|
-
}
|
|
32
|
-
})
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const hexFromBuffer = (buffer: ArrayBuffer): string => {
|
|
36
|
-
return Array.prototype.map
|
|
37
|
-
.call(new Uint8Array(buffer), (x) => `00${x.toString(16)}`.slice(-2))
|
|
38
|
-
.join('')
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export const hashFile$ = (file: File): Observable<string> => {
|
|
42
|
-
if (!window.crypto || !window.crypto.subtle || !window.FileReader) {
|
|
43
|
-
return throwError({
|
|
44
|
-
message: 'Unable to generate hash: uploads are only allowed in secure contexts',
|
|
45
|
-
statusCode: 500,
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
return readFile$(file).pipe(
|
|
49
|
-
mergeMap((arrayBuffer) => window.crypto.subtle.digest('SHA-1', arrayBuffer)),
|
|
50
|
-
map(hexFromBuffer),
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const uploadSanityAsset$ = (
|
|
55
|
-
client: SanityClient,
|
|
56
|
-
assetType: 'file' | 'image',
|
|
57
|
-
file: File,
|
|
58
|
-
hash: string,
|
|
59
|
-
) => {
|
|
60
|
-
return of(null).pipe(
|
|
61
|
-
// NOTE: the sanity api will still dedupe unique files, but this saves us from uploading the asset file entirely
|
|
62
|
-
mergeMap(() => fetchExisting$(client, `sanity.${assetType}Asset`, hash)),
|
|
63
|
-
// Cancel if the asset already exists
|
|
64
|
-
mergeMap((existingAsset: SanityAssetDocument | SanityImageAssetDocument | null) => {
|
|
65
|
-
if (existingAsset) {
|
|
66
|
-
return throwError({
|
|
67
|
-
message: 'Asset already exists',
|
|
68
|
-
statusCode: 409,
|
|
69
|
-
} as HttpError)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return of(null)
|
|
73
|
-
}),
|
|
74
|
-
mergeMap(() => {
|
|
75
|
-
// Begin upload if no existing asset found
|
|
76
|
-
return client.observable.assets
|
|
77
|
-
.upload(assetType, file, {
|
|
78
|
-
extract: ['blurhash', 'exif', 'location', 'lqip', 'palette'],
|
|
79
|
-
preserveFilename: true,
|
|
80
|
-
})
|
|
81
|
-
.pipe(
|
|
82
|
-
map((event) =>
|
|
83
|
-
event.type === 'response'
|
|
84
|
-
? {
|
|
85
|
-
// rewrite to a 'complete' event
|
|
86
|
-
asset: event.body.document,
|
|
87
|
-
id: event.body.document._id,
|
|
88
|
-
type: 'complete',
|
|
89
|
-
}
|
|
90
|
-
: event,
|
|
91
|
-
),
|
|
92
|
-
)
|
|
93
|
-
}),
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export const uploadAsset$ = withMaxConcurrency(uploadSanityAsset$)
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import {Observable, firstValueFrom} from 'rxjs'
|
|
2
|
-
import {describe, expect, it} from 'vitest'
|
|
3
|
-
|
|
4
|
-
import {createThrottler, withMaxConcurrency} from './withMaxConcurrency'
|
|
5
|
-
|
|
6
|
-
describe('createThrottler', () => {
|
|
7
|
-
it('never runs more observables concurrently than the limit', async () => {
|
|
8
|
-
let active = 0
|
|
9
|
-
let maxActive = 0
|
|
10
|
-
const request = createThrottler(2)
|
|
11
|
-
|
|
12
|
-
const mk = () =>
|
|
13
|
-
new Observable<number>((sub) => {
|
|
14
|
-
active++
|
|
15
|
-
maxActive = Math.max(maxActive, active)
|
|
16
|
-
queueMicrotask(() => {
|
|
17
|
-
active--
|
|
18
|
-
sub.next(1)
|
|
19
|
-
sub.complete()
|
|
20
|
-
})
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
await Promise.all([
|
|
24
|
-
firstValueFrom(request(mk())),
|
|
25
|
-
firstValueFrom(request(mk())),
|
|
26
|
-
firstValueFrom(request(mk())),
|
|
27
|
-
])
|
|
28
|
-
|
|
29
|
-
expect(maxActive).toBe(2)
|
|
30
|
-
})
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
describe('withMaxConcurrency', () => {
|
|
34
|
-
it('wraps a function so each call returns a single-value observable', async () => {
|
|
35
|
-
const fn = (n: number) =>
|
|
36
|
-
new Observable<number>((sub) => {
|
|
37
|
-
sub.next(n)
|
|
38
|
-
sub.complete()
|
|
39
|
-
})
|
|
40
|
-
const wrapped = withMaxConcurrency(fn, 4)
|
|
41
|
-
await expect(firstValueFrom(wrapped(7))).resolves.toBe(7)
|
|
42
|
-
})
|
|
43
|
-
})
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import {Subject, Subscription, Observable, from} from 'rxjs'
|
|
2
|
-
// Takes a observable-returning function and returns a new function that limits on the number of
|
|
3
|
-
// concurrent observables.
|
|
4
|
-
import {first, mergeMap} from 'rxjs/operators'
|
|
5
|
-
|
|
6
|
-
const DEFAULT_CONCURRENCY = 4
|
|
7
|
-
|
|
8
|
-
function remove<T>(array: Array<T>, item: T): Array<T> {
|
|
9
|
-
const index = array.indexOf(item)
|
|
10
|
-
if (index > -1) {
|
|
11
|
-
array.splice(index, 1)
|
|
12
|
-
}
|
|
13
|
-
return array
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const createThrottler = (concurrency: number = DEFAULT_CONCURRENCY) => {
|
|
17
|
-
const currentSubscriptions: Array<Subscription> = []
|
|
18
|
-
const pendingObservables: Array<Observable<any>> = []
|
|
19
|
-
const ready$ = new Subject()
|
|
20
|
-
|
|
21
|
-
function request(observable: Observable<any>): Observable<any> {
|
|
22
|
-
return new Observable((observer) => {
|
|
23
|
-
if (currentSubscriptions.length >= concurrency) {
|
|
24
|
-
return scheduleAndWait$(observable)
|
|
25
|
-
.pipe(mergeMap(request)) //
|
|
26
|
-
.subscribe(observer)
|
|
27
|
-
}
|
|
28
|
-
const subscription = observable.subscribe(observer)
|
|
29
|
-
currentSubscriptions.push(subscription)
|
|
30
|
-
return () => {
|
|
31
|
-
remove(currentSubscriptions, subscription)
|
|
32
|
-
remove(pendingObservables, observable)
|
|
33
|
-
subscription.unsubscribe()
|
|
34
|
-
while (pendingObservables.length > 0 && currentSubscriptions.length < concurrency) {
|
|
35
|
-
ready$.next(pendingObservables.shift())
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function scheduleAndWait$(observable: Observable<any>): Observable<any> {
|
|
42
|
-
pendingObservables.push(observable)
|
|
43
|
-
return ready$.asObservable().pipe(first((obs) => obs === observable))
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return request
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export const withMaxConcurrency = (
|
|
50
|
-
func: (...args: any[]) => Observable<any>,
|
|
51
|
-
concurrency: number = DEFAULT_CONCURRENCY,
|
|
52
|
-
) => {
|
|
53
|
-
const throttler = createThrottler(concurrency)
|
|
54
|
-
return (...args: Array<any>) => from(throttler(func(...args)))
|
|
55
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import {zodResolver} from '@hookform/resolvers/zod'
|
|
2
|
-
import type {FieldValues, Resolver} from 'react-hook-form'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* `@hookform/resolvers/zod` resolves its own `zod` typings through dependency
|
|
6
|
-
* hoisting, which in this monorepo lands on zod v4, while this plugin authors its
|
|
7
|
-
* form schemas with zod v3. The resolver accepts v3 schema instances correctly at
|
|
8
|
-
* runtime, so this thin wrapper only bridges the type-only v3/v4 mismatch. The
|
|
9
|
-
* react-hook-form field types stay fully checked at the call sites.
|
|
10
|
-
*/
|
|
11
|
-
export default function zodFormResolver<TFieldValues extends FieldValues>(
|
|
12
|
-
schema: unknown,
|
|
13
|
-
): Resolver<TFieldValues> {
|
|
14
|
-
return zodResolver(
|
|
15
|
-
schema as Parameters<typeof zodResolver>[0],
|
|
16
|
-
) as unknown as Resolver<TFieldValues>
|
|
17
|
-
}
|
package/v2-incompatible.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
const {showIncompatiblePluginDialog} = require('@sanity/incompatible-plugin')
|
|
2
|
-
const {name, version} = require('./package.json')
|
|
3
|
-
|
|
4
|
-
export default showIncompatiblePluginDialog({
|
|
5
|
-
name: name,
|
|
6
|
-
versions: {
|
|
7
|
-
v3: version,
|
|
8
|
-
v2: '^1.4.13',
|
|
9
|
-
},
|
|
10
|
-
sanityExchangeUrl: 'https://www.sanity.io/plugins/sanity-plugin-media',
|
|
11
|
-
})
|