@sanity/client 3.3.0 → 3.4.0-beta.esm.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/README.md +3 -5
- package/dist/sanityClient.browser.mjs +4317 -0
- package/dist/sanityClient.browser.mjs.map +7 -0
- package/dist/sanityClient.node.js +1129 -0
- package/dist/sanityClient.node.js.map +7 -0
- package/package.json +26 -6
- package/sanityClient.d.ts +3 -2
- package/src/assets/assetsClient.js +135 -0
- package/src/auth/authClient.js +17 -0
- package/src/config.js +96 -0
- package/src/data/dataMethods.js +183 -0
- package/src/data/encodeQueryString.js +18 -0
- package/src/data/listen.js +160 -0
- package/src/data/patch.js +124 -0
- package/src/data/transaction.js +106 -0
- package/src/datasets/datasetsClient.js +31 -0
- package/src/http/browserMiddleware.js +1 -0
- package/src/http/errors.js +57 -0
- package/src/http/nodeMiddleware.js +13 -0
- package/src/http/queryString.js +10 -0
- package/src/http/request.js +54 -0
- package/src/http/requestOptions.js +31 -0
- package/src/projects/projectsClient.js +17 -0
- package/src/sanityClient.js +119 -0
- package/src/users/usersClient.js +13 -0
- package/src/util/defaults.js +8 -0
- package/src/util/getSelection.js +17 -0
- package/src/util/observable.js +11 -0
- package/src/util/once.js +12 -0
- package/src/util/pick.js +9 -0
- package/src/validators.js +76 -0
- package/src/warnings.js +25 -0
- package/test/client.test.js +0 -2561
- package/test/encodeQueryString.test.js +0 -36
- package/test/fixtures/horsehead-nebula.jpg +0 -0
- package/test/fixtures/pdf-sample.pdf +0 -0
- package/test/helpers/sseServer.js +0 -26
- package/test/listen.test.js +0 -205
- package/test/warnings.test.disabled.js +0 -80
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/* eslint-disable no-empty-function, no-process-env */
|
|
2
|
+
const getIt = require('get-it')
|
|
3
|
+
const assign = require('object-assign')
|
|
4
|
+
const observable = require('get-it/lib/middleware/observable')
|
|
5
|
+
const jsonRequest = require('get-it/lib/middleware/jsonRequest')
|
|
6
|
+
const jsonResponse = require('get-it/lib/middleware/jsonResponse')
|
|
7
|
+
const progress = require('get-it/lib/middleware/progress')
|
|
8
|
+
const {Observable} = require('../util/observable')
|
|
9
|
+
const {ClientError, ServerError} = require('./errors')
|
|
10
|
+
|
|
11
|
+
const httpError = {
|
|
12
|
+
onResponse: (res) => {
|
|
13
|
+
if (res.statusCode >= 500) {
|
|
14
|
+
throw new ServerError(res)
|
|
15
|
+
} else if (res.statusCode >= 400) {
|
|
16
|
+
throw new ClientError(res)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return res
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const printWarnings = {
|
|
24
|
+
onResponse: (res) => {
|
|
25
|
+
const warn = res.headers['x-sanity-warning']
|
|
26
|
+
const warnings = Array.isArray(warn) ? warn : [warn]
|
|
27
|
+
warnings.filter(Boolean).forEach((msg) => console.warn(msg)) // eslint-disable-line no-console
|
|
28
|
+
return res
|
|
29
|
+
},
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Environment-specific middleware.
|
|
33
|
+
const envSpecific = require('./nodeMiddleware')
|
|
34
|
+
|
|
35
|
+
const middleware = envSpecific.concat([
|
|
36
|
+
printWarnings,
|
|
37
|
+
jsonRequest(),
|
|
38
|
+
jsonResponse(),
|
|
39
|
+
progress(),
|
|
40
|
+
httpError,
|
|
41
|
+
observable({implementation: Observable}),
|
|
42
|
+
])
|
|
43
|
+
|
|
44
|
+
const request = getIt(middleware)
|
|
45
|
+
|
|
46
|
+
function httpRequest(options, requester = request) {
|
|
47
|
+
return requester(assign({maxRedirects: 0}, options))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
httpRequest.defaultRequester = request
|
|
51
|
+
httpRequest.ClientError = ClientError
|
|
52
|
+
httpRequest.ServerError = ServerError
|
|
53
|
+
|
|
54
|
+
module.exports = httpRequest
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const assign = require('object-assign')
|
|
2
|
+
|
|
3
|
+
const projectHeader = 'X-Sanity-Project-ID'
|
|
4
|
+
|
|
5
|
+
module.exports = (config, overrides = {}) => {
|
|
6
|
+
const headers = {}
|
|
7
|
+
|
|
8
|
+
const token = overrides.token || config.token
|
|
9
|
+
if (token) {
|
|
10
|
+
headers.Authorization = `Bearer ${token}`
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!overrides.useGlobalApi && !config.useProjectHostname && config.projectId) {
|
|
14
|
+
headers[projectHeader] = config.projectId
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const withCredentials = Boolean(
|
|
18
|
+
typeof overrides.withCredentials === 'undefined'
|
|
19
|
+
? config.token || config.withCredentials
|
|
20
|
+
: overrides.withCredentials
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const timeout = typeof overrides.timeout === 'undefined' ? config.timeout : overrides.timeout
|
|
24
|
+
return assign({}, overrides, {
|
|
25
|
+
headers: assign({}, headers, overrides.headers || {}),
|
|
26
|
+
timeout: typeof timeout === 'undefined' ? 5 * 60 * 1000 : timeout,
|
|
27
|
+
proxy: overrides.proxy || config.proxy,
|
|
28
|
+
json: true,
|
|
29
|
+
withCredentials,
|
|
30
|
+
})
|
|
31
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const assign = require('object-assign')
|
|
2
|
+
|
|
3
|
+
function ProjectsClient(client) {
|
|
4
|
+
this.client = client
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
assign(ProjectsClient.prototype, {
|
|
8
|
+
list() {
|
|
9
|
+
return this.client.request({uri: '/projects'})
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
getById(id) {
|
|
13
|
+
return this.client.request({uri: `/projects/${id}`})
|
|
14
|
+
},
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
module.exports = ProjectsClient
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const assign = require('object-assign')
|
|
2
|
+
const {Observable, map, filter} = require('./util/observable')
|
|
3
|
+
const Patch = require('./data/patch')
|
|
4
|
+
const Transaction = require('./data/transaction')
|
|
5
|
+
const dataMethods = require('./data/dataMethods')
|
|
6
|
+
const DatasetsClient = require('./datasets/datasetsClient')
|
|
7
|
+
const ProjectsClient = require('./projects/projectsClient')
|
|
8
|
+
const AssetsClient = require('./assets/assetsClient')
|
|
9
|
+
const UsersClient = require('./users/usersClient')
|
|
10
|
+
const AuthClient = require('./auth/authClient')
|
|
11
|
+
const httpRequest = require('./http/request')
|
|
12
|
+
const getRequestOptions = require('./http/requestOptions')
|
|
13
|
+
const {defaultConfig, initConfig} = require('./config')
|
|
14
|
+
const validate = require('./validators')
|
|
15
|
+
|
|
16
|
+
const toPromise = (observable) => observable.toPromise()
|
|
17
|
+
|
|
18
|
+
function SanityClient(config = defaultConfig) {
|
|
19
|
+
if (!(this instanceof SanityClient)) {
|
|
20
|
+
return new SanityClient(config)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this.config(config)
|
|
24
|
+
|
|
25
|
+
this.assets = new AssetsClient(this)
|
|
26
|
+
this.datasets = new DatasetsClient(this)
|
|
27
|
+
this.projects = new ProjectsClient(this)
|
|
28
|
+
this.users = new UsersClient(this)
|
|
29
|
+
this.auth = new AuthClient(this)
|
|
30
|
+
|
|
31
|
+
if (this.clientConfig.isPromiseAPI) {
|
|
32
|
+
const observableConfig = assign({}, this.clientConfig, {isPromiseAPI: false})
|
|
33
|
+
this.observable = new SanityClient(observableConfig)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
assign(SanityClient.prototype, dataMethods)
|
|
38
|
+
assign(SanityClient.prototype, {
|
|
39
|
+
clone() {
|
|
40
|
+
return new SanityClient(this.config())
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
config(newConfig) {
|
|
44
|
+
if (typeof newConfig === 'undefined') {
|
|
45
|
+
return assign({}, this.clientConfig)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (this.observable) {
|
|
49
|
+
const observableConfig = assign({}, newConfig, {isPromiseAPI: false})
|
|
50
|
+
this.observable.config(observableConfig)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this.clientConfig = initConfig(newConfig, this.clientConfig || {})
|
|
54
|
+
return this
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
withConfig(newConfig) {
|
|
58
|
+
return this.clone().config(newConfig)
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
getUrl(uri, useCdn = false) {
|
|
62
|
+
const base = useCdn ? this.clientConfig.cdnUrl : this.clientConfig.url
|
|
63
|
+
return `${base}/${uri.replace(/^\//, '')}`
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
isPromiseAPI() {
|
|
67
|
+
return this.clientConfig.isPromiseAPI
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
_requestObservable(options) {
|
|
71
|
+
const uri = options.url || options.uri
|
|
72
|
+
|
|
73
|
+
// If the `canUseCdn`-option is not set we detect it automatically based on the method + URL.
|
|
74
|
+
// Only the /data endpoint is currently available through API-CDN.
|
|
75
|
+
const canUseCdn =
|
|
76
|
+
typeof options.canUseCdn === 'undefined'
|
|
77
|
+
? ['GET', 'HEAD'].indexOf(options.method || 'GET') >= 0 && uri.indexOf('/data/') === 0
|
|
78
|
+
: options.canUseCdn
|
|
79
|
+
|
|
80
|
+
const useCdn = this.clientConfig.useCdn && canUseCdn
|
|
81
|
+
|
|
82
|
+
const tag =
|
|
83
|
+
options.tag && this.clientConfig.requestTagPrefix
|
|
84
|
+
? [this.clientConfig.requestTagPrefix, options.tag].join('.')
|
|
85
|
+
: options.tag || this.clientConfig.requestTagPrefix
|
|
86
|
+
|
|
87
|
+
if (tag) {
|
|
88
|
+
options.query = {tag: validate.requestTag(tag), ...options.query}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const reqOptions = getRequestOptions(
|
|
92
|
+
this.clientConfig,
|
|
93
|
+
assign({}, options, {
|
|
94
|
+
url: this.getUrl(uri, useCdn),
|
|
95
|
+
})
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
return new Observable((subscriber) =>
|
|
99
|
+
httpRequest(reqOptions, this.clientConfig.requester).subscribe(subscriber)
|
|
100
|
+
)
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
request(options) {
|
|
104
|
+
const observable = this._requestObservable(options).pipe(
|
|
105
|
+
filter((event) => event.type === 'response'),
|
|
106
|
+
map((event) => event.body)
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return this.isPromiseAPI() ? toPromise(observable) : observable
|
|
110
|
+
},
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
SanityClient.Patch = Patch
|
|
114
|
+
SanityClient.Transaction = Transaction
|
|
115
|
+
SanityClient.ClientError = httpRequest.ClientError
|
|
116
|
+
SanityClient.ServerError = httpRequest.ServerError
|
|
117
|
+
SanityClient.requester = httpRequest.defaultRequester
|
|
118
|
+
|
|
119
|
+
module.exports = SanityClient
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module.exports = function getSelection(sel) {
|
|
2
|
+
if (typeof sel === 'string' || Array.isArray(sel)) {
|
|
3
|
+
return {id: sel}
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
if (sel && sel.query) {
|
|
7
|
+
return 'params' in sel ? {query: sel.query, params: sel.params} : {query: sel.query}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const selectionOpts = [
|
|
11
|
+
'* Document ID (<docId>)',
|
|
12
|
+
'* Array of document IDs',
|
|
13
|
+
'* Object containing `query`',
|
|
14
|
+
].join('\n')
|
|
15
|
+
|
|
16
|
+
throw new Error(`Unknown selection - must be one of:\n\n${selectionOpts}`)
|
|
17
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Since `@sanity/client` doesn't offer ESM exports (yet) const {filter} = require('rxjs/operators') will cause the the whole of rxjs to be included in the bundle.
|
|
2
|
+
// The internal import paths here is a stop-gap measure and will become less of a problem when @sanity/client export tree-shakeable esm bundles
|
|
3
|
+
const {Observable} = require('rxjs/internal/Observable')
|
|
4
|
+
const {filter} = require('rxjs/internal/operators/filter')
|
|
5
|
+
const {map} = require('rxjs/internal/operators/map')
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
Observable,
|
|
9
|
+
filter,
|
|
10
|
+
map,
|
|
11
|
+
}
|
package/src/util/once.js
ADDED
package/src/util/pick.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const VALID_ASSET_TYPES = ['image', 'file']
|
|
2
|
+
const VALID_INSERT_LOCATIONS = ['before', 'after', 'replace']
|
|
3
|
+
|
|
4
|
+
exports.dataset = (name) => {
|
|
5
|
+
if (!/^(~[a-z0-9]{1}[-\w]{0,63}|[a-z0-9]{1}[-\w]{0,63})$/.test(name)) {
|
|
6
|
+
throw new Error(
|
|
7
|
+
'Datasets can only contain lowercase characters, numbers, underscores and dashes, and start with tilde, and be maximum 64 characters'
|
|
8
|
+
)
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
exports.projectId = (id) => {
|
|
13
|
+
if (!/^[-a-z0-9]+$/i.test(id)) {
|
|
14
|
+
throw new Error('`projectId` can only contain only a-z, 0-9 and dashes')
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
exports.validateAssetType = (type) => {
|
|
19
|
+
if (VALID_ASSET_TYPES.indexOf(type) === -1) {
|
|
20
|
+
throw new Error(`Invalid asset type: ${type}. Must be one of ${VALID_ASSET_TYPES.join(', ')}`)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
exports.validateObject = (op, val) => {
|
|
25
|
+
if (val === null || typeof val !== 'object' || Array.isArray(val)) {
|
|
26
|
+
throw new Error(`${op}() takes an object of properties`)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
exports.requireDocumentId = (op, doc) => {
|
|
31
|
+
if (!doc._id) {
|
|
32
|
+
throw new Error(`${op}() requires that the document contains an ID ("_id" property)`)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
exports.validateDocumentId(op, doc._id)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
exports.validateDocumentId = (op, id) => {
|
|
39
|
+
if (typeof id !== 'string' || !/^[a-z0-9_.-]+$/i.test(id)) {
|
|
40
|
+
throw new Error(`${op}(): "${id}" is not a valid document ID`)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
exports.validateInsert = (at, selector, items) => {
|
|
45
|
+
const signature = 'insert(at, selector, items)'
|
|
46
|
+
if (VALID_INSERT_LOCATIONS.indexOf(at) === -1) {
|
|
47
|
+
const valid = VALID_INSERT_LOCATIONS.map((loc) => `"${loc}"`).join(', ')
|
|
48
|
+
throw new Error(`${signature} takes an "at"-argument which is one of: ${valid}`)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (typeof selector !== 'string') {
|
|
52
|
+
throw new Error(`${signature} takes a "selector"-argument which must be a string`)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!Array.isArray(items)) {
|
|
56
|
+
throw new Error(`${signature} takes an "items"-argument which must be an array`)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
exports.hasDataset = (config) => {
|
|
61
|
+
if (!config.dataset) {
|
|
62
|
+
throw new Error('`dataset` must be provided to perform queries')
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return config.dataset || ''
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
exports.requestTag = (tag) => {
|
|
69
|
+
if (typeof tag !== 'string' || !/^[a-z0-9._-]{1,75}$/i.test(tag)) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Tag can only contain alphanumeric characters, underscores, dashes and dots, and be between one and 75 characters long.`
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return tag
|
|
76
|
+
}
|
package/src/warnings.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const generateHelpUrl = require('@sanity/generate-help-url').generateHelpUrl
|
|
2
|
+
const once = require('./util/once')
|
|
3
|
+
|
|
4
|
+
const createWarningPrinter = (message) =>
|
|
5
|
+
// eslint-disable-next-line no-console
|
|
6
|
+
once((...args) => console.warn(message.join(' '), ...args))
|
|
7
|
+
|
|
8
|
+
exports.printCdnWarning = createWarningPrinter([
|
|
9
|
+
'You are not using the Sanity CDN. That means your data is always fresh, but the CDN is faster and',
|
|
10
|
+
`cheaper. Think about it! For more info, see ${generateHelpUrl('js-client-cdn-configuration')}.`,
|
|
11
|
+
'To hide this warning, please set the `useCdn` option to either `true` or `false` when creating',
|
|
12
|
+
'the client.',
|
|
13
|
+
])
|
|
14
|
+
|
|
15
|
+
exports.printBrowserTokenWarning = createWarningPrinter([
|
|
16
|
+
'You have configured Sanity client to use a token in the browser. This may cause unintentional security issues.',
|
|
17
|
+
`See ${generateHelpUrl(
|
|
18
|
+
'js-client-browser-token'
|
|
19
|
+
)} for more information and how to hide this warning.`,
|
|
20
|
+
])
|
|
21
|
+
|
|
22
|
+
exports.printNoApiVersionSpecifiedWarning = createWarningPrinter([
|
|
23
|
+
'Using the Sanity client without specifying an API version is deprecated.',
|
|
24
|
+
`See ${generateHelpUrl('js-client-api-version')}`,
|
|
25
|
+
])
|