@sanity/export 5.0.1 → 6.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/AssetHandler.d.ts +47 -0
- package/dist/AssetHandler.d.ts.map +1 -0
- package/dist/AssetHandler.js +384 -0
- package/dist/AssetHandler.js.map +1 -0
- package/dist/constants.d.ts +45 -0
- package/dist/constants.d.ts.map +1 -0
- package/{src → dist}/constants.js +13 -18
- package/dist/constants.js.map +1 -0
- package/dist/debug.d.ts +3 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/debug.js +3 -0
- package/dist/debug.js.map +1 -0
- package/dist/export.d.ts +43 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +269 -0
- package/dist/export.js.map +1 -0
- package/dist/filterDocumentTypes.d.ts +3 -0
- package/dist/filterDocumentTypes.d.ts.map +1 -0
- package/dist/filterDocumentTypes.js +16 -0
- package/dist/filterDocumentTypes.js.map +1 -0
- package/dist/filterDocuments.d.ts +3 -0
- package/dist/filterDocuments.d.ts.map +1 -0
- package/dist/filterDocuments.js +36 -0
- package/dist/filterDocuments.js.map +1 -0
- package/dist/getDocumentCursorStream.d.ts +4 -0
- package/dist/getDocumentCursorStream.d.ts.map +1 -0
- package/dist/getDocumentCursorStream.js +85 -0
- package/dist/getDocumentCursorStream.js.map +1 -0
- package/dist/getDocumentsStream.d.ts +5 -0
- package/dist/getDocumentsStream.d.ts.map +1 -0
- package/dist/getDocumentsStream.js +28 -0
- package/dist/getDocumentsStream.js.map +1 -0
- package/dist/getUserAgent.d.ts +2 -0
- package/dist/getUserAgent.d.ts.map +1 -0
- package/dist/getUserAgent.js +12 -0
- package/dist/getUserAgent.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/logFirstChunk.d.ts +3 -0
- package/dist/logFirstChunk.d.ts.map +1 -0
- package/dist/logFirstChunk.js +14 -0
- package/dist/logFirstChunk.js.map +1 -0
- package/dist/options.d.ts +14 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +97 -0
- package/dist/options.js.map +1 -0
- package/dist/rejectOnApiError.d.ts +3 -0
- package/dist/rejectOnApiError.d.ts.map +1 -0
- package/dist/rejectOnApiError.js +35 -0
- package/dist/rejectOnApiError.js.map +1 -0
- package/dist/requestStream.d.ts +3 -0
- package/dist/requestStream.d.ts.map +1 -0
- package/dist/requestStream.js +48 -0
- package/dist/requestStream.js.map +1 -0
- package/dist/stringifyStream.d.ts +3 -0
- package/dist/stringifyStream.d.ts.map +1 -0
- package/dist/stringifyStream.js +5 -0
- package/dist/stringifyStream.js.map +1 -0
- package/dist/tryParseJson.d.ts +10 -0
- package/dist/tryParseJson.d.ts.map +1 -0
- package/dist/tryParseJson.js +36 -0
- package/dist/tryParseJson.js.map +1 -0
- package/dist/types.d.ts +241 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/util/delay.d.ts +2 -0
- package/dist/util/delay.d.ts.map +1 -0
- package/dist/util/delay.js +4 -0
- package/dist/util/delay.js.map +1 -0
- package/dist/util/extractFirstError.d.ts +2 -0
- package/dist/util/extractFirstError.d.ts.map +1 -0
- package/dist/util/extractFirstError.js +22 -0
- package/dist/util/extractFirstError.js.map +1 -0
- package/dist/util/friendlyError.d.ts +2 -0
- package/dist/util/friendlyError.d.ts.map +1 -0
- package/dist/util/friendlyError.js +49 -0
- package/dist/util/friendlyError.js.map +1 -0
- package/dist/util/streamHelpers.d.ts +10 -0
- package/dist/util/streamHelpers.d.ts.map +1 -0
- package/dist/util/streamHelpers.js +99 -0
- package/dist/util/streamHelpers.js.map +1 -0
- package/package.json +22 -7
- package/src/{AssetHandler.js → AssetHandler.ts} +174 -99
- package/src/constants.ts +50 -0
- package/src/debug.ts +3 -0
- package/src/{export.js → export.ts} +110 -70
- package/src/filterDocumentTypes.ts +21 -0
- package/src/filterDocuments.ts +55 -0
- package/src/{getDocumentCursorStream.js → getDocumentCursorStream.ts} +37 -18
- package/src/{getDocumentsStream.js → getDocumentsStream.ts} +16 -6
- package/src/{getUserAgent.js → getUserAgent.ts} +8 -3
- package/src/index.ts +11 -0
- package/src/{logFirstChunk.js → logFirstChunk.ts} +6 -4
- package/src/options.ts +138 -0
- package/src/rejectOnApiError.ts +62 -0
- package/src/requestStream.ts +81 -0
- package/src/stringifyStream.ts +7 -0
- package/src/{tryParseJson.js → tryParseJson.ts} +29 -17
- package/src/types.ts +274 -0
- package/src/util/{delay.js → delay.ts} +1 -1
- package/src/util/extractFirstError.ts +31 -0
- package/src/util/friendlyError.ts +75 -0
- package/src/util/{streamHelpers.js → streamHelpers.ts} +35 -18
- package/src/debug.js +0 -3
- package/src/filterDocumentTypes.js +0 -18
- package/src/filterDocuments.js +0 -33
- package/src/rejectOnApiError.js +0 -31
- package/src/requestStream.js +0 -64
- package/src/stringifyStream.js +0 -5
- package/src/util/extractFirstError.js +0 -14
- package/src/util/friendlyError.js +0 -58
- package/src/validateOptions.js +0 -113
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
interface ErrorWithResponse {
|
|
2
|
+
response: {
|
|
3
|
+
body: NodeJS.ReadableStream
|
|
4
|
+
headers: Record<string, string>
|
|
5
|
+
statusCode?: number
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface ErrorBody {
|
|
10
|
+
error?: string
|
|
11
|
+
message?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isRecord(thing: unknown): thing is Record<string, unknown> {
|
|
15
|
+
return typeof thing === 'object' && thing !== null && !Array.isArray(thing)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isErrorWithResponse(err: unknown): err is ErrorWithResponse {
|
|
19
|
+
if (!isRecord(err)) {
|
|
20
|
+
return false
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!('response' in err) || !isRecord(err.response)) {
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const response = err.response
|
|
28
|
+
return (
|
|
29
|
+
'body' in response &&
|
|
30
|
+
isRecord(response.body) &&
|
|
31
|
+
'pipe' in response.body &&
|
|
32
|
+
'headers' in response &&
|
|
33
|
+
isRecord(response.headers)
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function readBody(req: NodeJS.ReadableStream): Promise<Buffer> {
|
|
38
|
+
const chunks: Buffer[] = []
|
|
39
|
+
for await (const chunk of req) {
|
|
40
|
+
chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : Buffer.from(chunk as Uint8Array))
|
|
41
|
+
}
|
|
42
|
+
return Buffer.concat(chunks)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function readBodyJson(req: NodeJS.ReadableStream): Promise<unknown> {
|
|
46
|
+
return JSON.parse((await readBody(req)).toString('utf8'))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function tryThrowFriendlyError(err: unknown): Promise<null> {
|
|
50
|
+
if (!isErrorWithResponse(err)) {
|
|
51
|
+
return null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const contentType = err.response.headers['content-type']
|
|
55
|
+
if (typeof contentType !== 'string' || !contentType.includes('application/json')) {
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const body = await readBodyJson(err.response.body)
|
|
60
|
+
|
|
61
|
+
if (!isRecord(body)) {
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const typedBody = body as ErrorBody
|
|
66
|
+
const status =
|
|
67
|
+
typeof err.response.statusCode === 'number' ? `HTTP ${err.response.statusCode}` : undefined
|
|
68
|
+
const error = typeof typedBody.error === 'string' ? typedBody.error : undefined
|
|
69
|
+
const message = typeof typedBody.message === 'string' ? typedBody.message : undefined
|
|
70
|
+
if (!error && !message) {
|
|
71
|
+
return null
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
throw new Error(['Export', status, error, message].filter(Boolean).join(': '))
|
|
75
|
+
}
|
|
@@ -1,63 +1,80 @@
|
|
|
1
|
-
import {Transform} from 'node:stream'
|
|
1
|
+
import {Transform, type TransformCallback, type Writable} from 'node:stream'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
type TransformFunction = (
|
|
4
|
+
chunk: Buffer,
|
|
5
|
+
encoding: BufferEncoding,
|
|
6
|
+
callback: TransformCallback,
|
|
7
|
+
) => void
|
|
8
|
+
|
|
9
|
+
type TransformObjFunction<T, R> = (
|
|
10
|
+
chunk: T,
|
|
11
|
+
encoding: BufferEncoding,
|
|
12
|
+
callback: TransformCallback,
|
|
13
|
+
) => R
|
|
14
|
+
|
|
15
|
+
export function through(transformFn: TransformFunction): Transform {
|
|
4
16
|
return new Transform({
|
|
5
|
-
transform(chunk, encoding, callback) {
|
|
17
|
+
transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback) {
|
|
6
18
|
transformFn(chunk, encoding, callback)
|
|
7
19
|
},
|
|
8
20
|
})
|
|
9
21
|
}
|
|
10
22
|
|
|
11
|
-
export function throughObj(
|
|
23
|
+
export function throughObj<T = unknown, R = void>(
|
|
24
|
+
transformFn: TransformObjFunction<T, R>,
|
|
25
|
+
): Transform {
|
|
12
26
|
return new Transform({
|
|
13
27
|
objectMode: true,
|
|
14
|
-
transform(chunk, encoding, callback) {
|
|
28
|
+
transform(chunk: T, encoding: BufferEncoding, callback: TransformCallback) {
|
|
15
29
|
transformFn(chunk, encoding, callback)
|
|
16
30
|
},
|
|
17
31
|
})
|
|
18
32
|
}
|
|
19
33
|
|
|
20
|
-
export function isWritableStream(val) {
|
|
34
|
+
export function isWritableStream(val: unknown): val is Writable {
|
|
21
35
|
return (
|
|
22
36
|
val !== null &&
|
|
23
37
|
typeof val === 'object' &&
|
|
38
|
+
'pipe' in val &&
|
|
24
39
|
typeof val.pipe === 'function' &&
|
|
40
|
+
'_write' in val &&
|
|
25
41
|
typeof val._write === 'function' &&
|
|
42
|
+
'_writableState' in val &&
|
|
26
43
|
typeof val._writableState === 'object'
|
|
27
44
|
)
|
|
28
45
|
}
|
|
29
46
|
|
|
30
|
-
export function concat(onData) {
|
|
31
|
-
const chunks = []
|
|
47
|
+
export function concat(onData: (chunks: unknown[]) => void): Transform {
|
|
48
|
+
const chunks: unknown[] = []
|
|
32
49
|
return new Transform({
|
|
33
50
|
objectMode: true,
|
|
34
|
-
transform(chunk,
|
|
51
|
+
transform(chunk: unknown, _encoding: BufferEncoding, callback: TransformCallback) {
|
|
35
52
|
chunks.push(chunk)
|
|
36
53
|
callback()
|
|
37
54
|
},
|
|
38
|
-
flush(callback) {
|
|
55
|
+
flush(callback: TransformCallback) {
|
|
39
56
|
try {
|
|
40
57
|
onData(chunks)
|
|
41
58
|
callback()
|
|
42
59
|
} catch (err) {
|
|
43
|
-
callback(err)
|
|
60
|
+
callback(err as Error)
|
|
44
61
|
}
|
|
45
62
|
},
|
|
46
63
|
})
|
|
47
64
|
}
|
|
48
65
|
|
|
49
|
-
export
|
|
66
|
+
export function split(transformFn?: (line: string) => unknown): Transform {
|
|
50
67
|
let buffer = ''
|
|
51
68
|
const splitRegex = /\r?\n/
|
|
52
69
|
|
|
53
70
|
return new Transform({
|
|
54
|
-
objectMode:
|
|
55
|
-
transform(chunk,
|
|
71
|
+
objectMode: Boolean(transformFn),
|
|
72
|
+
transform(chunk: Buffer, _encoding: BufferEncoding, callback: TransformCallback) {
|
|
56
73
|
buffer += chunk.toString()
|
|
57
74
|
const lines = buffer.split(splitRegex)
|
|
58
75
|
|
|
59
76
|
// Keep the last line in buffer as it might be incomplete
|
|
60
|
-
buffer = lines.pop()
|
|
77
|
+
buffer = lines.pop() ?? ''
|
|
61
78
|
|
|
62
79
|
for (const line of lines) {
|
|
63
80
|
if (line.length === 0) continue
|
|
@@ -69,7 +86,7 @@ export const split = (transformFn) => {
|
|
|
69
86
|
this.push(result)
|
|
70
87
|
}
|
|
71
88
|
} catch (err) {
|
|
72
|
-
callback(err)
|
|
89
|
+
callback(err as Error)
|
|
73
90
|
return
|
|
74
91
|
}
|
|
75
92
|
} else {
|
|
@@ -78,7 +95,7 @@ export const split = (transformFn) => {
|
|
|
78
95
|
}
|
|
79
96
|
callback()
|
|
80
97
|
},
|
|
81
|
-
flush(callback) {
|
|
98
|
+
flush(callback: TransformCallback) {
|
|
82
99
|
if (buffer.length === 0) {
|
|
83
100
|
callback()
|
|
84
101
|
return
|
|
@@ -96,7 +113,7 @@ export const split = (transformFn) => {
|
|
|
96
113
|
}
|
|
97
114
|
callback()
|
|
98
115
|
} catch (err) {
|
|
99
|
-
callback(err)
|
|
116
|
+
callback(err as Error)
|
|
100
117
|
}
|
|
101
118
|
},
|
|
102
119
|
})
|
package/src/debug.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import {throughObj} from './util/streamHelpers.js'
|
|
2
|
-
|
|
3
|
-
export function filterDocumentTypes(allowedTypes) {
|
|
4
|
-
if (!allowedTypes || allowedTypes.length === 0) {
|
|
5
|
-
// Pass-through
|
|
6
|
-
return throughObj((doc, enc, callback) => callback(null, doc))
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
return throughObj(function docTypesFilter(doc, enc, callback) {
|
|
10
|
-
const type = doc && doc._type
|
|
11
|
-
if (allowedTypes.includes(type)) {
|
|
12
|
-
callback(null, doc)
|
|
13
|
-
return
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
callback()
|
|
17
|
-
})
|
|
18
|
-
}
|
package/src/filterDocuments.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import {debug} from './debug.js'
|
|
2
|
-
import {throughObj} from './util/streamHelpers.js'
|
|
3
|
-
|
|
4
|
-
const isDraftOrVersion = (doc) =>
|
|
5
|
-
doc && doc._id && (doc._id.indexOf('drafts.') === 0 || doc._id.indexOf('versions.') === 0)
|
|
6
|
-
|
|
7
|
-
const isSystemDocument = (doc) => doc && doc._id && doc._id.indexOf('_.') === 0
|
|
8
|
-
const isReleaseDocument = (doc) => doc && doc._id && doc._id.indexOf('_.releases.') === 0
|
|
9
|
-
const isCursor = (doc) => doc && !doc._id && doc.nextCursor !== undefined
|
|
10
|
-
|
|
11
|
-
export function filterDocuments(drafts) {
|
|
12
|
-
return throughObj(function filterDocs(doc, enc, callback) {
|
|
13
|
-
if (isCursor(doc)) {
|
|
14
|
-
debug('%o is a cursor, skipping', doc)
|
|
15
|
-
return callback()
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (!drafts && isDraftOrVersion(doc)) {
|
|
19
|
-
debug('%s is a draft or version, skipping', doc && doc._id)
|
|
20
|
-
return callback()
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (isSystemDocument(doc)) {
|
|
24
|
-
if (drafts && isReleaseDocument(doc)) {
|
|
25
|
-
return callback(null, doc)
|
|
26
|
-
}
|
|
27
|
-
debug('%s is a system document, skipping', doc && doc._id)
|
|
28
|
-
return callback()
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return callback(null, doc)
|
|
32
|
-
})
|
|
33
|
-
}
|
package/src/rejectOnApiError.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {throughObj} from './util/streamHelpers.js'
|
|
2
|
-
|
|
3
|
-
export function rejectOnApiError() {
|
|
4
|
-
return throughObj((doc, enc, callback) => {
|
|
5
|
-
// check if the document passed contains a document attribtue first, and return early.
|
|
6
|
-
if (doc._id) {
|
|
7
|
-
callback(null, doc)
|
|
8
|
-
return
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
if (doc.error) {
|
|
12
|
-
// if we got a statusCode we can decorate the error with it
|
|
13
|
-
if (doc.statusCode) {
|
|
14
|
-
callback(
|
|
15
|
-
new Error(
|
|
16
|
-
['Export', `HTTP ${doc.statusCode}`, doc.error, doc.message]
|
|
17
|
-
.filter((part) => typeof part === 'string')
|
|
18
|
-
.join(': '),
|
|
19
|
-
),
|
|
20
|
-
)
|
|
21
|
-
return
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// no statusCode, just serialize and return the error
|
|
25
|
-
callback(new Error(doc.error.description || doc.error.message || JSON.stringify(doc)))
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
callback(null, doc)
|
|
30
|
-
})
|
|
31
|
-
}
|
package/src/requestStream.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import {getIt} from 'get-it'
|
|
2
|
-
import {keepAlive, promise} from 'get-it/middleware'
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
DEFAULT_RETRY_DELAY,
|
|
6
|
-
DOCUMENT_STREAM_MAX_RETRIES,
|
|
7
|
-
REQUEST_READ_TIMEOUT,
|
|
8
|
-
} from './constants.js'
|
|
9
|
-
import {debug} from './debug.js'
|
|
10
|
-
import {delay} from './util/delay.js'
|
|
11
|
-
import {extractFirstError} from './util/extractFirstError.js'
|
|
12
|
-
import {tryThrowFriendlyError} from './util/friendlyError.js'
|
|
13
|
-
|
|
14
|
-
const request = getIt([keepAlive(), promise({onlyBody: true})])
|
|
15
|
-
|
|
16
|
-
const CONNECTION_TIMEOUT = 15 * 1000 // 15 seconds
|
|
17
|
-
|
|
18
|
-
/* eslint-disable no-await-in-loop, max-depth */
|
|
19
|
-
export async function requestStream(options) {
|
|
20
|
-
const maxRetries =
|
|
21
|
-
typeof options.maxRetries === 'number' ? options.maxRetries : DOCUMENT_STREAM_MAX_RETRIES
|
|
22
|
-
|
|
23
|
-
const readTimeout =
|
|
24
|
-
typeof options.readTimeout === 'number' ? options.readTimeout : REQUEST_READ_TIMEOUT
|
|
25
|
-
|
|
26
|
-
const retryDelayMs =
|
|
27
|
-
typeof options.retryDelayMs === 'number' ? options.retryDelayMs : DEFAULT_RETRY_DELAY
|
|
28
|
-
|
|
29
|
-
let error
|
|
30
|
-
|
|
31
|
-
let i = 0
|
|
32
|
-
do {
|
|
33
|
-
i++
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
return await request({
|
|
37
|
-
...options,
|
|
38
|
-
stream: true,
|
|
39
|
-
maxRedirects: 0,
|
|
40
|
-
timeout: {connect: CONNECTION_TIMEOUT, socket: readTimeout},
|
|
41
|
-
})
|
|
42
|
-
} catch (err) {
|
|
43
|
-
error = extractFirstError(err) || err
|
|
44
|
-
|
|
45
|
-
if (maxRetries === 0) {
|
|
46
|
-
throw error
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (err.response && err.response.statusCode && err.response.statusCode < 500) {
|
|
50
|
-
break
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (i < maxRetries) {
|
|
54
|
-
debug('Error, retrying after %d ms: %s', retryDelayMs, error.message)
|
|
55
|
-
await delay(retryDelayMs)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
} while (i < maxRetries)
|
|
59
|
-
|
|
60
|
-
await tryThrowFriendlyError(error)
|
|
61
|
-
|
|
62
|
-
error.message = `Export: Failed to fetch ${options.url}: ${error.message}`
|
|
63
|
-
throw error
|
|
64
|
-
}
|
package/src/stringifyStream.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export function extractFirstError(err) {
|
|
2
|
-
if (
|
|
3
|
-
// eslint-disable-next-line no-undef
|
|
4
|
-
((typeof AggregateError !== 'undefined' && err instanceof AggregateError) ||
|
|
5
|
-
('name' in err && err.name === 'AggregateError')) &&
|
|
6
|
-
Array.isArray(err.errors) &&
|
|
7
|
-
err.errors.length > 0 &&
|
|
8
|
-
'message' in err.errors[0]
|
|
9
|
-
) {
|
|
10
|
-
return err.errors[0]
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return err
|
|
14
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
export async function tryThrowFriendlyError(err) {
|
|
2
|
-
if (!isRecord(err)) {
|
|
3
|
-
return null
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
if (!('response' in err) || !isRecord(err.response)) {
|
|
7
|
-
return null
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
if (
|
|
11
|
-
!('body' in err.response) ||
|
|
12
|
-
!('pipe' in err.response.body) ||
|
|
13
|
-
!('headers' in err.response) ||
|
|
14
|
-
!isRecord(err.response.headers)
|
|
15
|
-
) {
|
|
16
|
-
return null
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (
|
|
20
|
-
typeof err.response.headers['content-type'] !== 'string' ||
|
|
21
|
-
!err.response.headers['content-type'].includes('application/json')
|
|
22
|
-
) {
|
|
23
|
-
return null
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const body = await readBodyJson(err.response.body)
|
|
27
|
-
|
|
28
|
-
if (!isRecord(body)) {
|
|
29
|
-
return null
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Look for Sanity API(ish) standard error shape
|
|
33
|
-
const status =
|
|
34
|
-
typeof err.response.statusCode === 'number' ? `HTTP ${err.response.statusCode}` : undefined
|
|
35
|
-
const error = typeof body.error === 'string' ? body.error : undefined
|
|
36
|
-
const message = typeof body.message === 'string' ? body.message : undefined
|
|
37
|
-
if (!error && !message) {
|
|
38
|
-
return null
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
throw new Error(['Export', status, error, message].filter(Boolean).join(': '))
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function isRecord(thing) {
|
|
45
|
-
return typeof thing === 'object' && thing !== null && !Array.isArray(thing)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function readBody(req) {
|
|
49
|
-
const chunks = []
|
|
50
|
-
for await (const chunk of req) {
|
|
51
|
-
chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk)
|
|
52
|
-
}
|
|
53
|
-
return Buffer.concat(chunks)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async function readBodyJson(req) {
|
|
57
|
-
return JSON.parse((await readBody(req)).toString('utf8'))
|
|
58
|
-
}
|
package/src/validateOptions.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ASSET_DOWNLOAD_MAX_RETRIES,
|
|
3
|
-
DOCUMENT_STREAM_MAX_RETRIES,
|
|
4
|
-
MODE_CURSOR,
|
|
5
|
-
MODE_STREAM,
|
|
6
|
-
REQUEST_READ_TIMEOUT,
|
|
7
|
-
} from './constants.js'
|
|
8
|
-
|
|
9
|
-
const clientMethods = ['getUrl', 'config']
|
|
10
|
-
const booleanFlags = ['assets', 'raw', 'compress', 'drafts']
|
|
11
|
-
const numberFlags = ['maxAssetRetries', 'maxRetries', 'assetConcurrency', 'readTimeout']
|
|
12
|
-
const exportDefaults = {
|
|
13
|
-
compress: true,
|
|
14
|
-
drafts: true,
|
|
15
|
-
assets: true,
|
|
16
|
-
assetsMap: true,
|
|
17
|
-
raw: false,
|
|
18
|
-
mode: MODE_STREAM,
|
|
19
|
-
maxRetries: DOCUMENT_STREAM_MAX_RETRIES,
|
|
20
|
-
maxAssetRetries: ASSET_DOWNLOAD_MAX_RETRIES,
|
|
21
|
-
readTimeout: REQUEST_READ_TIMEOUT,
|
|
22
|
-
filterDocument: () => true,
|
|
23
|
-
transformDocument: (doc) => doc,
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function validateOptions(opts) {
|
|
27
|
-
const options = {...exportDefaults, ...opts}
|
|
28
|
-
|
|
29
|
-
const resources = [options.dataset, options.mediaLibraryId].filter(
|
|
30
|
-
(resource) => typeof resource === 'string' && resource.length !== 0,
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
if (resources.length === 0) {
|
|
34
|
-
throw new Error(
|
|
35
|
-
'either `options.dataset` or `options.mediaLibraryId` must be specified, got neither',
|
|
36
|
-
)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (resources.length === 2) {
|
|
40
|
-
throw new Error(
|
|
41
|
-
'either `options.dataset` or `options.mediaLibraryId` must be specified, got both',
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
typeof options.mode !== 'string' ||
|
|
47
|
-
(options.mode !== MODE_STREAM && options.mode !== MODE_CURSOR)
|
|
48
|
-
) {
|
|
49
|
-
throw new Error(
|
|
50
|
-
`options.mode must be either "${MODE_STREAM}" or "${MODE_CURSOR}", got "${options.mode}"`,
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (options.onProgress && typeof options.onProgress !== 'function') {
|
|
55
|
-
throw new Error(`options.onProgress must be a function`)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (!options.client) {
|
|
59
|
-
throw new Error('`options.client` must be set to an instance of @sanity/client')
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const missing = clientMethods.find((key) => typeof options.client[key] !== 'function')
|
|
63
|
-
if (missing) {
|
|
64
|
-
throw new Error(
|
|
65
|
-
`\`options.client\` is not a valid @sanity/client instance - no "${missing}" method found`,
|
|
66
|
-
)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const clientConfig = options.client.config()
|
|
70
|
-
if (!clientConfig.token) {
|
|
71
|
-
throw new Error('Client is not instantiated with a `token`')
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
booleanFlags.forEach((flag) => {
|
|
75
|
-
if (typeof options[flag] !== 'boolean') {
|
|
76
|
-
throw new Error(`Flag ${flag} must be a boolean (true/false)`)
|
|
77
|
-
}
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
numberFlags.forEach((flag) => {
|
|
81
|
-
if (typeof options[flag] !== 'undefined' && typeof options[flag] !== 'number') {
|
|
82
|
-
throw new Error(`Flag ${flag} must be a number if specified`)
|
|
83
|
-
}
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
if (!options.outputPath) {
|
|
87
|
-
throw new Error('outputPath must be specified (- for stdout)')
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (options.assetConcurrency && (options.assetConcurrency < 1 || options.assetConcurrency > 24)) {
|
|
91
|
-
throw new Error('`assetConcurrency` must be between 1 and 24')
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
typeof options.filterDocument !== 'undefined' &&
|
|
96
|
-
typeof options.filterDocument !== 'function'
|
|
97
|
-
) {
|
|
98
|
-
throw new Error('`filterDocument` must be a function')
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (
|
|
102
|
-
typeof options.transformDocument !== 'undefined' &&
|
|
103
|
-
typeof options.transformDocument !== 'function'
|
|
104
|
-
) {
|
|
105
|
-
throw new Error('`transformDocument` must be a function')
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (typeof assetsMap !== 'undefined' && typeof assetsMap !== 'boolean') {
|
|
109
|
-
throw new Error('`assetsMap` must be a boolean')
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return options
|
|
113
|
-
}
|