@sanity/client 3.4.0-beta.esm.1 → 3.4.0-beta.esm.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/client",
3
- "version": "3.4.0-beta.esm.1",
3
+ "version": "3.4.0-beta.esm.2",
4
4
  "description": "Client for retrieving, creating and patching data from Sanity.io",
5
5
  "main": "lib/sanityClient.js",
6
6
  "umd": "umd/sanityClient.min.js",
@@ -17,7 +17,6 @@
17
17
  "files": [
18
18
  "dist",
19
19
  "lib",
20
- "src",
21
20
  "umd",
22
21
  "sanityClient.d.ts"
23
22
  ],
@@ -1,135 +0,0 @@
1
- const assign = require('object-assign')
2
- const {map, filter} = require('../util/observable')
3
- const queryString = require('../http/queryString')
4
- const validators = require('../validators')
5
-
6
- function AssetsClient(client) {
7
- this.client = client
8
- }
9
-
10
- function optionsFromFile(opts, file) {
11
- if (typeof window === 'undefined' || !(file instanceof window.File)) {
12
- return opts
13
- }
14
-
15
- return assign(
16
- {
17
- filename: opts.preserveFilename === false ? undefined : file.name,
18
- contentType: file.type,
19
- },
20
- opts
21
- )
22
- }
23
-
24
- assign(AssetsClient.prototype, {
25
- /**
26
- * Upload an asset
27
- *
28
- * @param {String} assetType `image` or `file`
29
- * @param {File|Blob|Buffer|ReadableStream} body File to upload
30
- * @param {Object} opts Options for the upload
31
- * @param {Boolean} opts.preserveFilename Whether or not to preserve the original filename (default: true)
32
- * @param {String} opts.filename Filename for this file (optional)
33
- * @param {Number} opts.timeout Milliseconds to wait before timing the request out (default: 0)
34
- * @param {String} opts.contentType Mime type of the file
35
- * @param {Array} opts.extract Array of metadata parts to extract from image.
36
- * Possible values: `location`, `exif`, `image`, `palette`
37
- * @param {String} opts.label Label
38
- * @param {String} opts.title Title
39
- * @param {String} opts.description Description
40
- * @param {String} opts.creditLine The credit to person(s) and/or organization(s) required by the supplier of the image to be used when published
41
- * @param {Object} opts.source Source data (when the asset is from an external service)
42
- * @param {String} opts.source.id The (u)id of the asset within the source, i.e. 'i-f323r1E'
43
- * Required if source is defined
44
- * @param {String} opts.source.name The name of the source, i.e. 'unsplash'
45
- * Required if source is defined
46
- * @param {String} opts.source.url A url to where to find the asset, or get more info about it in the source
47
- * Optional
48
- * @return {Promise} Resolves with the created asset document
49
- */
50
- upload(assetType, body, opts = {}) {
51
- validators.validateAssetType(assetType)
52
-
53
- // If an empty array is given, explicitly set `none` to override API defaults
54
- let meta = opts.extract || undefined
55
- if (meta && !meta.length) {
56
- meta = ['none']
57
- }
58
-
59
- const dataset = validators.hasDataset(this.client.clientConfig)
60
- const assetEndpoint = assetType === 'image' ? 'images' : 'files'
61
- const options = optionsFromFile(opts, body)
62
- const {tag, label, title, description, creditLine, filename, source} = options
63
- const query = {
64
- label,
65
- title,
66
- description,
67
- filename,
68
- meta,
69
- creditLine,
70
- }
71
- if (source) {
72
- query.sourceId = source.id
73
- query.sourceName = source.name
74
- query.sourceUrl = source.url
75
- }
76
- const observable = this.client._requestObservable({
77
- tag,
78
- method: 'POST',
79
- timeout: options.timeout || 0,
80
- uri: `/assets/${assetEndpoint}/${dataset}`,
81
- headers: options.contentType ? {'Content-Type': options.contentType} : {},
82
- query,
83
- body,
84
- })
85
-
86
- return this.client.isPromiseAPI()
87
- ? observable
88
- .pipe(
89
- filter((event) => event.type === 'response'),
90
- map((event) => event.body.document)
91
- )
92
- .toPromise()
93
- : observable
94
- },
95
-
96
- delete(type, id) {
97
- // eslint-disable-next-line no-console
98
- console.warn('client.assets.delete() is deprecated, please use client.delete(<document-id>)')
99
-
100
- let docId = id || ''
101
- if (!/^(image|file)-/.test(docId)) {
102
- docId = `${type}-${docId}`
103
- } else if (type._id) {
104
- // We could be passing an entire asset document instead of an ID
105
- docId = type._id
106
- }
107
-
108
- validators.hasDataset(this.client.clientConfig)
109
- return this.client.delete(docId)
110
- },
111
-
112
- getImageUrl(ref, query) {
113
- const id = ref._ref || ref
114
- if (typeof id !== 'string') {
115
- throw new Error(
116
- 'getImageUrl() needs either an object with a _ref, or a string with an asset document ID'
117
- )
118
- }
119
-
120
- if (!/^image-[A-Za-z0-9_]+-\d+x\d+-[a-z]{1,5}$/.test(id)) {
121
- throw new Error(
122
- `Unsupported asset ID "${id}". URL generation only works for auto-generated IDs.`
123
- )
124
- }
125
-
126
- const [, assetId, size, format] = id.split('-')
127
-
128
- validators.hasDataset(this.client.clientConfig)
129
- const {projectId, dataset} = this.client.clientConfig
130
- const qs = query ? queryString(query) : ''
131
- return `https://cdn.sanity.io/images/${projectId}/${dataset}/${assetId}-${size}.${format}${qs}`
132
- },
133
- })
134
-
135
- module.exports = AssetsClient
@@ -1,17 +0,0 @@
1
- const assign = require('object-assign')
2
-
3
- function AuthClient(client) {
4
- this.client = client
5
- }
6
-
7
- assign(AuthClient.prototype, {
8
- getLoginProviders() {
9
- return this.client.request({uri: '/auth/providers'})
10
- },
11
-
12
- logout() {
13
- return this.client.request({uri: '/auth/logout', method: 'POST'})
14
- },
15
- })
16
-
17
- module.exports = AuthClient
package/src/config.js DELETED
@@ -1,96 +0,0 @@
1
- const generateHelpUrl = require('@sanity/generate-help-url').generateHelpUrl
2
- const assign = require('object-assign')
3
- const validate = require('./validators')
4
- const warnings = require('./warnings')
5
-
6
- const defaultCdnHost = 'apicdn.sanity.io'
7
- const defaultConfig = {
8
- apiHost: 'https://api.sanity.io',
9
- apiVersion: '1',
10
- useProjectHostname: true,
11
- isPromiseAPI: true,
12
- }
13
-
14
- const LOCALHOSTS = ['localhost', '127.0.0.1', '0.0.0.0']
15
- const isLocal = (host) => LOCALHOSTS.indexOf(host) !== -1
16
-
17
- exports.defaultConfig = defaultConfig
18
-
19
- // eslint-disable-next-line complexity
20
- exports.initConfig = (config, prevConfig) => {
21
- const specifiedConfig = assign({}, prevConfig, config)
22
- if (!specifiedConfig.apiVersion) {
23
- warnings.printNoApiVersionSpecifiedWarning()
24
- }
25
-
26
- const newConfig = assign({}, defaultConfig, specifiedConfig)
27
- const projectBased = newConfig.useProjectHostname
28
-
29
- if (typeof Promise === 'undefined') {
30
- const helpUrl = generateHelpUrl('js-client-promise-polyfill')
31
- throw new Error(`No native Promise-implementation found, polyfill needed - see ${helpUrl}`)
32
- }
33
-
34
- if (projectBased && !newConfig.projectId) {
35
- throw new Error('Configuration must contain `projectId`')
36
- }
37
-
38
- const isBrowser = typeof window !== 'undefined' && window.location && window.location.hostname
39
- const isLocalhost = isBrowser && isLocal(window.location.hostname)
40
-
41
- if (isBrowser && isLocalhost && newConfig.token && newConfig.ignoreBrowserTokenWarning !== true) {
42
- warnings.printBrowserTokenWarning()
43
- } else if (typeof newConfig.useCdn === 'undefined') {
44
- warnings.printCdnWarning()
45
- }
46
-
47
- if (projectBased) {
48
- validate.projectId(newConfig.projectId)
49
- }
50
-
51
- if (newConfig.dataset) {
52
- validate.dataset(newConfig.dataset)
53
- }
54
-
55
- if ('requestTagPrefix' in newConfig) {
56
- // Allow setting and unsetting request tag prefix
57
- newConfig.requestTagPrefix = newConfig.requestTagPrefix
58
- ? validate.requestTag(newConfig.requestTagPrefix).replace(/\.+$/, '')
59
- : undefined
60
- }
61
-
62
- newConfig.apiVersion = `${newConfig.apiVersion}`.replace(/^v/, '')
63
- newConfig.isDefaultApi = newConfig.apiHost === defaultConfig.apiHost
64
- newConfig.useCdn = Boolean(newConfig.useCdn) && !newConfig.withCredentials
65
-
66
- exports.validateApiVersion(newConfig.apiVersion)
67
-
68
- const hostParts = newConfig.apiHost.split('://', 2)
69
- const protocol = hostParts[0]
70
- const host = hostParts[1]
71
- const cdnHost = newConfig.isDefaultApi ? defaultCdnHost : host
72
-
73
- if (newConfig.useProjectHostname) {
74
- newConfig.url = `${protocol}://${newConfig.projectId}.${host}/v${newConfig.apiVersion}`
75
- newConfig.cdnUrl = `${protocol}://${newConfig.projectId}.${cdnHost}/v${newConfig.apiVersion}`
76
- } else {
77
- newConfig.url = `${newConfig.apiHost}/v${newConfig.apiVersion}`
78
- newConfig.cdnUrl = newConfig.url
79
- }
80
-
81
- return newConfig
82
- }
83
-
84
- exports.validateApiVersion = function validateApiVersion(apiVersion) {
85
- if (apiVersion === '1' || apiVersion === 'X') {
86
- return
87
- }
88
-
89
- const apiDate = new Date(apiVersion)
90
- const apiVersionValid =
91
- /^\d{4}-\d{2}-\d{2}$/.test(apiVersion) && apiDate instanceof Date && apiDate.getTime() > 0
92
-
93
- if (!apiVersionValid) {
94
- throw new Error('Invalid API version string, expected `1` or date in format `YYYY-MM-DD`')
95
- }
96
- }
@@ -1,183 +0,0 @@
1
- const assign = require('object-assign')
2
- const {map, filter} = require('../util/observable')
3
- const validators = require('../validators')
4
- const getSelection = require('../util/getSelection')
5
- const encodeQueryString = require('./encodeQueryString')
6
- const Transaction = require('./transaction')
7
- const Patch = require('./patch')
8
- const listen = require('./listen')
9
-
10
- const excludeFalsey = (param, defValue) => {
11
- const value = typeof param === 'undefined' ? defValue : param
12
- return param === false ? undefined : value
13
- }
14
-
15
- const getMutationQuery = (options = {}) => {
16
- return {
17
- dryRun: options.dryRun,
18
- returnIds: true,
19
- returnDocuments: excludeFalsey(options.returnDocuments, true),
20
- visibility: options.visibility || 'sync',
21
- autoGenerateArrayKeys: options.autoGenerateArrayKeys,
22
- skipCrossDatasetReferenceValidation: options.skipCrossDatasetReferenceValidation,
23
- }
24
- }
25
-
26
- const isResponse = (event) => event.type === 'response'
27
- const getBody = (event) => event.body
28
-
29
- const indexBy = (docs, attr) =>
30
- docs.reduce((indexed, doc) => {
31
- indexed[attr(doc)] = doc
32
- return indexed
33
- }, Object.create(null))
34
-
35
- const toPromise = (observable) => observable.toPromise()
36
-
37
- const getQuerySizeLimit = 11264
38
-
39
- module.exports = {
40
- listen: listen,
41
-
42
- getDataUrl(operation, path) {
43
- const config = this.clientConfig
44
- const catalog = validators.hasDataset(config)
45
- const baseUri = `/${operation}/${catalog}`
46
- const uri = path ? `${baseUri}/${path}` : baseUri
47
- return `/data${uri}`.replace(/\/($|\?)/, '$1')
48
- },
49
-
50
- fetch(query, params, options = {}) {
51
- const mapResponse = options.filterResponse === false ? (res) => res : (res) => res.result
52
-
53
- const observable = this._dataRequest('query', {query, params}, options).pipe(map(mapResponse))
54
- return this.isPromiseAPI() ? toPromise(observable) : observable
55
- },
56
-
57
- getDocument(id, opts = {}) {
58
- const options = {uri: this.getDataUrl('doc', id), json: true, tag: opts.tag}
59
- const observable = this._requestObservable(options).pipe(
60
- filter(isResponse),
61
- map((event) => event.body.documents && event.body.documents[0])
62
- )
63
-
64
- return this.isPromiseAPI() ? toPromise(observable) : observable
65
- },
66
-
67
- getDocuments(ids, opts = {}) {
68
- const options = {uri: this.getDataUrl('doc', ids.join(',')), json: true, tag: opts.tag}
69
- const observable = this._requestObservable(options).pipe(
70
- filter(isResponse),
71
- map((event) => {
72
- const indexed = indexBy(event.body.documents || [], (doc) => doc._id)
73
- return ids.map((id) => indexed[id] || null)
74
- })
75
- )
76
-
77
- return this.isPromiseAPI() ? toPromise(observable) : observable
78
- },
79
-
80
- create(doc, options) {
81
- return this._create(doc, 'create', options)
82
- },
83
-
84
- createIfNotExists(doc, options) {
85
- validators.requireDocumentId('createIfNotExists', doc)
86
- return this._create(doc, 'createIfNotExists', options)
87
- },
88
-
89
- createOrReplace(doc, options) {
90
- validators.requireDocumentId('createOrReplace', doc)
91
- return this._create(doc, 'createOrReplace', options)
92
- },
93
-
94
- patch(selector, operations) {
95
- return new Patch(selector, operations, this)
96
- },
97
-
98
- delete(selection, options) {
99
- return this.dataRequest('mutate', {mutations: [{delete: getSelection(selection)}]}, options)
100
- },
101
-
102
- mutate(mutations, options) {
103
- const mut =
104
- mutations instanceof Patch || mutations instanceof Transaction
105
- ? mutations.serialize()
106
- : mutations
107
-
108
- const muts = Array.isArray(mut) ? mut : [mut]
109
- const transactionId = options && options.transactionId
110
- return this.dataRequest('mutate', {mutations: muts, transactionId}, options)
111
- },
112
-
113
- transaction(operations) {
114
- return new Transaction(operations, this)
115
- },
116
-
117
- dataRequest(endpoint, body, options = {}) {
118
- const request = this._dataRequest(endpoint, body, options)
119
-
120
- return this.isPromiseAPI() ? toPromise(request) : request
121
- },
122
-
123
- _dataRequest(endpoint, body, options = {}) {
124
- const isMutation = endpoint === 'mutate'
125
- const isQuery = endpoint === 'query'
126
-
127
- // Check if the query string is within a configured threshold,
128
- // in which case we can use GET. Otherwise, use POST.
129
- const strQuery = !isMutation && encodeQueryString(body)
130
- const useGet = !isMutation && strQuery.length < getQuerySizeLimit
131
- const stringQuery = useGet ? strQuery : ''
132
- const returnFirst = options.returnFirst
133
- const {timeout, token, tag, headers} = options
134
-
135
- const uri = this.getDataUrl(endpoint, stringQuery)
136
-
137
- const reqOptions = {
138
- method: useGet ? 'GET' : 'POST',
139
- uri: uri,
140
- json: true,
141
- body: useGet ? undefined : body,
142
- query: isMutation && getMutationQuery(options),
143
- timeout,
144
- headers,
145
- token,
146
- tag,
147
- canUseCdn: isQuery,
148
- }
149
-
150
- return this._requestObservable(reqOptions).pipe(
151
- filter(isResponse),
152
- map(getBody),
153
- map((res) => {
154
- if (!isMutation) {
155
- return res
156
- }
157
-
158
- // Should we return documents?
159
- const results = res.results || []
160
- if (options.returnDocuments) {
161
- return returnFirst
162
- ? results[0] && results[0].document
163
- : results.map((mut) => mut.document)
164
- }
165
-
166
- // Return a reduced subset
167
- const key = returnFirst ? 'documentId' : 'documentIds'
168
- const ids = returnFirst ? results[0] && results[0].id : results.map((mut) => mut.id)
169
- return {
170
- transactionId: res.transactionId,
171
- results: results,
172
- [key]: ids,
173
- }
174
- })
175
- )
176
- },
177
-
178
- _create(doc, op, options = {}) {
179
- const mutation = {[op]: doc}
180
- const opts = assign({returnFirst: true, returnDocuments: true}, options)
181
- return this.dataRequest('mutate', {mutations: [mutation]}, opts)
182
- },
183
- }
@@ -1,18 +0,0 @@
1
- const enc = encodeURIComponent
2
-
3
- module.exports = ({query, params = {}, options = {}}) => {
4
- // We generally want tag at the start of the query string
5
- const {tag, ...opts} = options
6
- const q = `query=${enc(query)}`
7
- const base = tag ? `?tag=${enc(tag)}&${q}` : `?${q}`
8
-
9
- const qString = Object.keys(params).reduce(
10
- (qs, param) => `${qs}&${enc(`$${param}`)}=${enc(JSON.stringify(params[param]))}`,
11
- base
12
- )
13
-
14
- return Object.keys(opts).reduce((qs, option) => {
15
- // Only include the option if it is truthy
16
- return options[option] ? `${qs}&${enc(option)}=${enc(options[option])}` : qs
17
- }, qString)
18
- }
@@ -1,160 +0,0 @@
1
- const assign = require('object-assign')
2
- const {Observable} = require('../util/observable')
3
- const polyfilledEventSource = require('@sanity/eventsource')
4
- const pick = require('../util/pick')
5
- const defaults = require('../util/defaults')
6
- const encodeQueryString = require('./encodeQueryString')
7
-
8
- // Limit is 16K for a _request_, eg including headers. Have to account for an
9
- // unknown range of headers, but an average EventSource request from Chrome seems
10
- // to have around 700 bytes of cruft, so let us account for 1.2K to be "safe"
11
- const MAX_URL_LENGTH = 16000 - 1200
12
- const EventSource = polyfilledEventSource
13
-
14
- const possibleOptions = [
15
- 'includePreviousRevision',
16
- 'includeResult',
17
- 'visibility',
18
- 'effectFormat',
19
- 'tag',
20
- ]
21
-
22
- const defaultOptions = {
23
- includeResult: true,
24
- }
25
-
26
- module.exports = function listen(query, params, opts = {}) {
27
- const {url, token, withCredentials, requestTagPrefix} = this.clientConfig
28
- const tag = opts.tag && requestTagPrefix ? [requestTagPrefix, opts.tag].join('.') : opts.tag
29
- const options = {...defaults(opts, defaultOptions), tag}
30
- const listenOpts = pick(options, possibleOptions)
31
- const qs = encodeQueryString({query, params, options: listenOpts, tag})
32
-
33
- const uri = `${url}${this.getDataUrl('listen', qs)}`
34
- if (uri.length > MAX_URL_LENGTH) {
35
- return new Observable((observer) => observer.error(new Error('Query too large for listener')))
36
- }
37
-
38
- const listenFor = options.events ? options.events : ['mutation']
39
- const shouldEmitReconnect = listenFor.indexOf('reconnect') !== -1
40
-
41
- const esOptions = {}
42
- if (token || withCredentials) {
43
- esOptions.withCredentials = true
44
- }
45
-
46
- if (token) {
47
- esOptions.headers = {
48
- Authorization: `Bearer ${token}`,
49
- }
50
- }
51
-
52
- return new Observable((observer) => {
53
- let es = getEventSource()
54
- let reconnectTimer
55
- let stopped = false
56
-
57
- function onError() {
58
- if (stopped) {
59
- return
60
- }
61
-
62
- emitReconnect()
63
-
64
- // Allow event handlers of `emitReconnect` to cancel/close the reconnect attempt
65
- if (stopped) {
66
- return
67
- }
68
-
69
- // Unless we've explicitly stopped the ES (in which case `stopped` should be true),
70
- // we should never be in a disconnected state. By default, EventSource will reconnect
71
- // automatically, in which case it sets readyState to `CONNECTING`, but in some cases
72
- // (like when a laptop lid is closed), it closes the connection. In these cases we need
73
- // to explicitly reconnect.
74
- if (es.readyState === EventSource.CLOSED) {
75
- unsubscribe()
76
- clearTimeout(reconnectTimer)
77
- reconnectTimer = setTimeout(open, 100)
78
- }
79
- }
80
-
81
- function onChannelError(err) {
82
- observer.error(cooerceError(err))
83
- }
84
-
85
- function onMessage(evt) {
86
- const event = parseEvent(evt)
87
- return event instanceof Error ? observer.error(event) : observer.next(event)
88
- }
89
-
90
- function onDisconnect(evt) {
91
- stopped = true
92
- unsubscribe()
93
- observer.complete()
94
- }
95
-
96
- function unsubscribe() {
97
- es.removeEventListener('error', onError, false)
98
- es.removeEventListener('channelError', onChannelError, false)
99
- es.removeEventListener('disconnect', onDisconnect, false)
100
- listenFor.forEach((type) => es.removeEventListener(type, onMessage, false))
101
- es.close()
102
- }
103
-
104
- function emitReconnect() {
105
- if (shouldEmitReconnect) {
106
- observer.next({type: 'reconnect'})
107
- }
108
- }
109
-
110
- function getEventSource() {
111
- const evs = new EventSource(uri, esOptions)
112
- evs.addEventListener('error', onError, false)
113
- evs.addEventListener('channelError', onChannelError, false)
114
- evs.addEventListener('disconnect', onDisconnect, false)
115
- listenFor.forEach((type) => evs.addEventListener(type, onMessage, false))
116
- return evs
117
- }
118
-
119
- function open() {
120
- es = getEventSource()
121
- }
122
-
123
- function stop() {
124
- stopped = true
125
- unsubscribe()
126
- }
127
-
128
- return stop
129
- })
130
- }
131
-
132
- function parseEvent(event) {
133
- try {
134
- const data = (event.data && JSON.parse(event.data)) || {}
135
- return assign({type: event.type}, data)
136
- } catch (err) {
137
- return err
138
- }
139
- }
140
-
141
- function cooerceError(err) {
142
- if (err instanceof Error) {
143
- return err
144
- }
145
-
146
- const evt = parseEvent(err)
147
- return evt instanceof Error ? evt : new Error(extractErrorMessage(evt))
148
- }
149
-
150
- function extractErrorMessage(err) {
151
- if (!err.error) {
152
- return err.message || 'Unknown listener error'
153
- }
154
-
155
- if (err.error.description) {
156
- return err.error.description
157
- }
158
-
159
- return typeof err.error === 'string' ? err.error : JSON.stringify(err.error, null, 2)
160
- }