@sanity/client 3.2.2 → 4.0.0-alpha.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/README.md +43 -26
- package/dist/browser/sanityClient.js +956 -0
- package/dist/node/sanityClient.js +969 -0
- package/lib/assets/assetsClient.js +132 -106
- package/lib/auth/authClient.js +38 -19
- package/lib/config.js +25 -13
- package/lib/data/dataMethods.js +35 -30
- package/lib/data/encodeQueryString.js +8 -2
- package/lib/data/listen.js +25 -21
- package/lib/data/patch.js +169 -118
- package/lib/data/transaction.js +134 -88
- package/lib/datasets/datasetsClient.js +63 -32
- package/lib/http/browserMiddleware.js +6 -1
- package/lib/http/errors.js +12 -8
- package/lib/http/nodeMiddleware.js +16 -9
- package/lib/http/queryString.js +9 -2
- package/lib/http/request.js +27 -24
- package/lib/http/requestOptions.js +10 -6
- package/lib/projects/projectsClient.js +37 -18
- package/lib/sanityClient.js +143 -105
- package/lib/users/usersClient.js +28 -11
- package/lib/util/defaults.js +12 -4
- package/lib/util/getSelection.js +7 -2
- package/lib/util/observable.js +24 -13
- package/lib/util/once.js +9 -2
- package/lib/util/pick.js +9 -2
- package/lib/validators.js +38 -15
- package/lib/warnings.js +14 -6
- package/package.json +22 -3
- package/sanityClient.d.ts +3 -13
- package/src/assets/assetsClient.js +132 -0
- package/src/auth/authClient.js +13 -0
- package/src/config.js +93 -0
- package/src/data/dataMethods.js +182 -0
- package/src/data/encodeQueryString.js +18 -0
- package/src/data/listen.js +159 -0
- package/src/data/patch.js +119 -0
- package/src/data/transaction.js +103 -0
- package/src/datasets/datasetsClient.js +28 -0
- package/src/http/browserMiddleware.js +1 -0
- package/src/http/errors.js +53 -0
- package/src/http/nodeMiddleware.js +11 -0
- package/src/http/queryString.js +10 -0
- package/src/http/request.js +50 -0
- package/src/http/requestOptions.js +29 -0
- package/src/projects/projectsClient.js +13 -0
- package/src/sanityClient.js +124 -0
- package/src/users/usersClient.js +9 -0
- package/src/util/defaults.js +9 -0
- package/src/util/getSelection.js +17 -0
- package/src/util/observable.js +6 -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 +188 -41
- package/test/encodeQueryString.test.js +3 -1
- package/test/helpers/sseServer.js +2 -1
- package/test/listen.test.js +4 -2
- package/test/warnings.test.disabled.js +8 -4
- package/umd/sanityClient.js +38 -38
- package/umd/sanityClient.min.js +1 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const VALID_ASSET_TYPES = ['image', 'file']
|
|
2
|
+
const VALID_INSERT_LOCATIONS = ['before', 'after', 'replace']
|
|
3
|
+
|
|
4
|
+
export const 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
|
+
export const 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
|
+
export const 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
|
+
export const 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
|
+
export const validateDocumentId = (op, id) => {
|
|
31
|
+
if (typeof id !== 'string' || !/^[a-z0-9_.-]+$/i.test(id)) {
|
|
32
|
+
throw new Error(`${op}(): "${id}" is not a valid document ID`)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const requireDocumentId = (op, doc) => {
|
|
37
|
+
if (!doc._id) {
|
|
38
|
+
throw new Error(`${op}() requires that the document contains an ID ("_id" property)`)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
validateDocumentId(op, doc._id)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const 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
|
+
export const 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
|
+
export const 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
|
+
import {generateHelpUrl} from '@sanity/generate-help-url'
|
|
2
|
+
import {once} from './util/once'
|
|
3
|
+
|
|
4
|
+
const createWarningPrinter = (message) =>
|
|
5
|
+
// eslint-disable-next-line no-console
|
|
6
|
+
once((...args) => console.warn(message.join(' '), ...args))
|
|
7
|
+
|
|
8
|
+
export const 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
|
+
export const 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
|
+
export const printNoApiVersionSpecifiedWarning = createWarningPrinter([
|
|
23
|
+
'Using the Sanity client without specifying an API version is deprecated.',
|
|
24
|
+
`See ${generateHelpUrl('js-client-api-version')}`,
|
|
25
|
+
])
|
package/test/client.test.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// eslint-disable-next-line no-global-assign -- we know what we're doing ESlint ;)
|
|
2
|
+
require = require('esm')(module)
|
|
1
3
|
const test = require('tape')
|
|
2
4
|
const nock = require('nock')
|
|
3
5
|
const assign = require('xtend')
|
|
@@ -6,9 +8,7 @@ const fs = require('fs')
|
|
|
6
8
|
const validators = require('../src/validators')
|
|
7
9
|
const observableOf = require('rxjs').of
|
|
8
10
|
const {filter} = require('rxjs/operators')
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const SanityClient = sanityClient
|
|
11
|
+
const {createClient, SanityClient} = require('../src/sanityClient')
|
|
12
12
|
const noop = () => {
|
|
13
13
|
/* intentional noop */
|
|
14
14
|
}
|
|
@@ -26,7 +26,7 @@ const clientConfig = {
|
|
|
26
26
|
useCdn: false,
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const getClient = (conf) =>
|
|
29
|
+
const getClient = (conf) => createClient(assign({}, clientConfig, conf || {}))
|
|
30
30
|
const fixture = (name) => path.join(__dirname, 'fixtures', name)
|
|
31
31
|
const ifError = (t) => (err) => {
|
|
32
32
|
t.ifError(err)
|
|
@@ -38,20 +38,20 @@ const ifError = (t) => (err) => {
|
|
|
38
38
|
/*****************
|
|
39
39
|
* BASE CLIENT *
|
|
40
40
|
*****************/
|
|
41
|
-
test('can
|
|
41
|
+
test('can create a client with new keyword', (t) => {
|
|
42
42
|
const client = new SanityClient({projectId: 'abc123'})
|
|
43
43
|
t.equal(client.config().projectId, 'abc123', 'constructor opts are set')
|
|
44
44
|
t.end()
|
|
45
45
|
})
|
|
46
46
|
|
|
47
47
|
test('can construct client without new keyword', (t) => {
|
|
48
|
-
const client =
|
|
48
|
+
const client = createClient({projectId: 'abc123'})
|
|
49
49
|
t.equal(client.config().projectId, 'abc123', 'constructor opts are set')
|
|
50
50
|
t.end()
|
|
51
51
|
})
|
|
52
52
|
|
|
53
53
|
test('can get and set config', (t) => {
|
|
54
|
-
const client =
|
|
54
|
+
const client = createClient({projectId: 'abc123'})
|
|
55
55
|
t.equal(client.config().projectId, 'abc123', 'constructor opts are set')
|
|
56
56
|
t.equal(client.config({projectId: 'def456'}), client, 'returns client on set')
|
|
57
57
|
t.equal(client.config().projectId, 'def456', 'new config is set')
|
|
@@ -59,7 +59,7 @@ test('can get and set config', (t) => {
|
|
|
59
59
|
})
|
|
60
60
|
|
|
61
61
|
test('config getter returns a cloned object', (t) => {
|
|
62
|
-
const client =
|
|
62
|
+
const client = createClient({projectId: 'abc123'})
|
|
63
63
|
t.equal(client.config().projectId, 'abc123', 'constructor opts are set')
|
|
64
64
|
const config = client.config()
|
|
65
65
|
config.projectId = 'def456'
|
|
@@ -68,7 +68,7 @@ test('config getter returns a cloned object', (t) => {
|
|
|
68
68
|
})
|
|
69
69
|
|
|
70
70
|
test('calling config() reconfigures observable API too', (t) => {
|
|
71
|
-
const client =
|
|
71
|
+
const client = createClient({projectId: 'abc123'})
|
|
72
72
|
|
|
73
73
|
client.config({projectId: 'def456'})
|
|
74
74
|
t.equal(client.observable.config().projectId, 'def456', 'Observable API gets reconfigured')
|
|
@@ -76,7 +76,7 @@ test('calling config() reconfigures observable API too', (t) => {
|
|
|
76
76
|
})
|
|
77
77
|
|
|
78
78
|
test('can clone client', (t) => {
|
|
79
|
-
const client =
|
|
79
|
+
const client = createClient({projectId: 'abc123'})
|
|
80
80
|
t.equal(client.config().projectId, 'abc123', 'constructor opts are set')
|
|
81
81
|
|
|
82
82
|
const client2 = client.clone()
|
|
@@ -87,7 +87,7 @@ test('can clone client', (t) => {
|
|
|
87
87
|
})
|
|
88
88
|
|
|
89
89
|
test('can clone client with new config', (t) => {
|
|
90
|
-
const client =
|
|
90
|
+
const client = createClient({projectId: 'abc123', apiVersion: 'v2021-03-25'})
|
|
91
91
|
t.equal(client.config().projectId, 'abc123', 'constructor opts are set')
|
|
92
92
|
t.equal(client.config().apiVersion, '2021-03-25', 'constructor opts are set')
|
|
93
93
|
|
|
@@ -101,18 +101,18 @@ test('can clone client with new config', (t) => {
|
|
|
101
101
|
})
|
|
102
102
|
|
|
103
103
|
test('throws if no projectId is set', (t) => {
|
|
104
|
-
t.throws(
|
|
104
|
+
t.throws(createClient, /projectId/)
|
|
105
105
|
t.end()
|
|
106
106
|
})
|
|
107
107
|
|
|
108
108
|
test('throws on invalid project ids', (t) => {
|
|
109
|
-
t.throws(() =>
|
|
109
|
+
t.throws(() => createClient({projectId: '*foo*'}), /projectId.*?can only contain/i)
|
|
110
110
|
t.end()
|
|
111
111
|
})
|
|
112
112
|
|
|
113
113
|
test('throws on invalid dataset names', (t) => {
|
|
114
114
|
t.throws(
|
|
115
|
-
() =>
|
|
115
|
+
() => createClient({projectId: 'abc123', dataset: '*foo*'}),
|
|
116
116
|
/Datasets can only contain/i
|
|
117
117
|
)
|
|
118
118
|
t.end()
|
|
@@ -120,7 +120,7 @@ test('throws on invalid dataset names', (t) => {
|
|
|
120
120
|
|
|
121
121
|
test('throws on invalid request tag prefix', (t) => {
|
|
122
122
|
t.throws(
|
|
123
|
-
() =>
|
|
123
|
+
() => createClient({projectId: 'abc123', dataset: 'foo', requestTagPrefix: 'no#shot'}),
|
|
124
124
|
/tag can only contain alphanumeric/i
|
|
125
125
|
)
|
|
126
126
|
t.end()
|
|
@@ -128,7 +128,7 @@ test('throws on invalid request tag prefix', (t) => {
|
|
|
128
128
|
|
|
129
129
|
test('accepts alias in dataset field', (t) => {
|
|
130
130
|
t.doesNotThrow(
|
|
131
|
-
() =>
|
|
131
|
+
() => createClient({projectId: 'abc123', dataset: '~alias'}),
|
|
132
132
|
/Datasets can only contain/i
|
|
133
133
|
)
|
|
134
134
|
t.end()
|
|
@@ -244,7 +244,7 @@ test('can request list of projects', (t) => {
|
|
|
244
244
|
.get('/v1/projects')
|
|
245
245
|
.reply(200, [{projectId: 'foo'}, {projectId: 'bar'}])
|
|
246
246
|
|
|
247
|
-
const client =
|
|
247
|
+
const client = createClient({useProjectHostname: false, apiHost: `https://${apiHost}`})
|
|
248
248
|
client.projects
|
|
249
249
|
.list()
|
|
250
250
|
.then((projects) => {
|
|
@@ -260,7 +260,7 @@ test('can request list of projects (custom api version)', (t) => {
|
|
|
260
260
|
.get('/v2019-01-29/projects')
|
|
261
261
|
.reply(200, [{projectId: 'foo'}, {projectId: 'bar'}])
|
|
262
262
|
|
|
263
|
-
const client =
|
|
263
|
+
const client = createClient({
|
|
264
264
|
useProjectHostname: false,
|
|
265
265
|
apiHost: `https://${apiHost}`,
|
|
266
266
|
apiVersion: '2019-01-29',
|
|
@@ -291,7 +291,7 @@ test('can request project by id', (t) => {
|
|
|
291
291
|
|
|
292
292
|
nock(`https://${apiHost}`).get('/v1/projects/n1f7y').reply(200, doc)
|
|
293
293
|
|
|
294
|
-
const client =
|
|
294
|
+
const client = createClient({useProjectHostname: false, apiHost: `https://${apiHost}`})
|
|
295
295
|
client.projects
|
|
296
296
|
.getById('n1f7y')
|
|
297
297
|
.then((project) => t.deepEqual(project, doc))
|
|
@@ -627,7 +627,7 @@ test('populates response body on errors', (t) => {
|
|
|
627
627
|
|
|
628
628
|
test('throws if trying to perform data request without dataset', (t) => {
|
|
629
629
|
t.throws(
|
|
630
|
-
() =>
|
|
630
|
+
() => createClient({projectId: 'foo'}).fetch('blah'),
|
|
631
631
|
Error,
|
|
632
632
|
/dataset.*?must be provided/
|
|
633
633
|
)
|
|
@@ -748,6 +748,64 @@ test('can tell create() to use non-default visibility mode', (t) => {
|
|
|
748
748
|
.then(t.end)
|
|
749
749
|
})
|
|
750
750
|
|
|
751
|
+
test('can tell create() to auto-generate array keys', (t) => {
|
|
752
|
+
const doc = {
|
|
753
|
+
_id: 'abc123',
|
|
754
|
+
name: 'Dromaeosauridae',
|
|
755
|
+
genus: [{_type: 'dino', name: 'Velociraptor'}],
|
|
756
|
+
}
|
|
757
|
+
nock(projectHost())
|
|
758
|
+
.post(
|
|
759
|
+
'/v1/data/mutate/foo?returnIds=true&returnDocuments=true&autoGenerateArrayKeys=true&visibility=sync',
|
|
760
|
+
{
|
|
761
|
+
mutations: [{create: doc}],
|
|
762
|
+
}
|
|
763
|
+
)
|
|
764
|
+
.reply(200, {
|
|
765
|
+
transactionId: 'abc123',
|
|
766
|
+
results: [
|
|
767
|
+
{
|
|
768
|
+
id: 'abc123',
|
|
769
|
+
document: {...doc, genus: [{...doc.genus[0], _key: 'r4p70r'}]},
|
|
770
|
+
operation: 'create',
|
|
771
|
+
},
|
|
772
|
+
],
|
|
773
|
+
})
|
|
774
|
+
|
|
775
|
+
getClient()
|
|
776
|
+
.create(doc, {autoGenerateArrayKeys: true})
|
|
777
|
+
.then((res) => {
|
|
778
|
+
t.equal(res._id, 'abc123', 'document id returned')
|
|
779
|
+
t.equal(res.genus[0]._key, 'r4p70r', 'array keys generated returned')
|
|
780
|
+
})
|
|
781
|
+
.catch(t.ifError)
|
|
782
|
+
.then(t.end)
|
|
783
|
+
})
|
|
784
|
+
|
|
785
|
+
test('can tell create() to do a dry-run', (t) => {
|
|
786
|
+
const doc = {_id: 'abc123', name: 'Dromaeosauridae'}
|
|
787
|
+
nock(projectHost())
|
|
788
|
+
.post('/v1/data/mutate/foo?dryRun=true&returnIds=true&returnDocuments=true&visibility=sync', {
|
|
789
|
+
mutations: [{create: doc}],
|
|
790
|
+
})
|
|
791
|
+
.reply(200, {
|
|
792
|
+
transactionId: 'abc123',
|
|
793
|
+
results: [
|
|
794
|
+
{
|
|
795
|
+
id: 'abc123',
|
|
796
|
+
document: doc,
|
|
797
|
+
operation: 'create',
|
|
798
|
+
},
|
|
799
|
+
],
|
|
800
|
+
})
|
|
801
|
+
|
|
802
|
+
getClient()
|
|
803
|
+
.create(doc, {dryRun: true})
|
|
804
|
+
.then((res) => t.equal(res._id, 'abc123', 'document id returned'))
|
|
805
|
+
.catch(t.ifError)
|
|
806
|
+
.then(t.end)
|
|
807
|
+
})
|
|
808
|
+
|
|
751
809
|
test('createIfNotExists() sends correct mutation', (t) => {
|
|
752
810
|
const doc = {_id: 'abc123', name: 'Raptor'}
|
|
753
811
|
const expectedBody = {mutations: [{createIfNotExists: doc}]}
|
|
@@ -940,7 +998,52 @@ test('mutate() accepts request tag', (t) => {
|
|
|
940
998
|
.then(() => t.end())
|
|
941
999
|
})
|
|
942
1000
|
|
|
943
|
-
test('mutate() accepts
|
|
1001
|
+
test('mutate() accepts `autoGenerateArrayKeys`', (t) => {
|
|
1002
|
+
const mutations = [
|
|
1003
|
+
{
|
|
1004
|
+
create: {
|
|
1005
|
+
_id: 'abc123',
|
|
1006
|
+
_type: 'post',
|
|
1007
|
+
items: [{_type: 'block', children: [{_type: 'span', text: 'Hello there'}]}],
|
|
1008
|
+
},
|
|
1009
|
+
},
|
|
1010
|
+
]
|
|
1011
|
+
|
|
1012
|
+
nock(projectHost())
|
|
1013
|
+
.post(
|
|
1014
|
+
'/v1/data/mutate/foo?returnIds=true&returnDocuments=true&visibility=sync&autoGenerateArrayKeys=true',
|
|
1015
|
+
{mutations}
|
|
1016
|
+
)
|
|
1017
|
+
.reply(200, {
|
|
1018
|
+
transactionId: 'foo',
|
|
1019
|
+
results: [{id: 'abc123', operation: 'create', document: {_id: 'abc123'}}],
|
|
1020
|
+
})
|
|
1021
|
+
|
|
1022
|
+
getClient()
|
|
1023
|
+
.mutate(mutations, {autoGenerateArrayKeys: true})
|
|
1024
|
+
.catch(t.ifError)
|
|
1025
|
+
.then(() => t.end())
|
|
1026
|
+
})
|
|
1027
|
+
|
|
1028
|
+
test('mutate() accepts `dryRun`', (t) => {
|
|
1029
|
+
const mutations = [{create: {_id: 'abc123', _type: 'post'}}]
|
|
1030
|
+
|
|
1031
|
+
nock(projectHost())
|
|
1032
|
+
.post('/v1/data/mutate/foo?dryRun=true&returnIds=true&returnDocuments=true&visibility=sync', {
|
|
1033
|
+
mutations,
|
|
1034
|
+
})
|
|
1035
|
+
.reply(200, {
|
|
1036
|
+
transactionId: 'foo',
|
|
1037
|
+
results: [{id: 'abc123', operation: 'create', document: {_id: 'abc123'}}],
|
|
1038
|
+
})
|
|
1039
|
+
|
|
1040
|
+
getClient()
|
|
1041
|
+
.mutate(mutations, {dryRun: true})
|
|
1042
|
+
.catch(t.ifError)
|
|
1043
|
+
.then(() => t.end())
|
|
1044
|
+
})
|
|
1045
|
+
|
|
1046
|
+
test('mutate() accepts `skipCrossDatasetReferenceValidation`', (t) => {
|
|
944
1047
|
const mutations = [{delete: {id: 'abc123'}}]
|
|
945
1048
|
|
|
946
1049
|
nock(projectHost())
|
|
@@ -959,6 +1062,29 @@ test('mutate() accepts skipCrossDatasetReferenceValidation', (t) => {
|
|
|
959
1062
|
.then(() => t.end())
|
|
960
1063
|
})
|
|
961
1064
|
|
|
1065
|
+
test('mutate() skips/falls back to defaults on undefined but known properties', (t) => {
|
|
1066
|
+
const mutations = [{delete: {id: 'abc123'}}]
|
|
1067
|
+
|
|
1068
|
+
nock(projectHost())
|
|
1069
|
+
.post('/v1/data/mutate/foo?tag=foobar&returnIds=true&returnDocuments=true&visibility=sync', {
|
|
1070
|
+
mutations,
|
|
1071
|
+
})
|
|
1072
|
+
.reply(200, {
|
|
1073
|
+
transactionId: 'foo',
|
|
1074
|
+
results: [{id: 'abc123', operation: 'delete', document: {_id: 'abc123'}}],
|
|
1075
|
+
})
|
|
1076
|
+
|
|
1077
|
+
getClient()
|
|
1078
|
+
.mutate(mutations, {
|
|
1079
|
+
tag: 'foobar',
|
|
1080
|
+
skipCrossDatasetReferenceValidation: undefined,
|
|
1081
|
+
returnDocuments: undefined,
|
|
1082
|
+
autoGenerateArrayKeys: undefined,
|
|
1083
|
+
})
|
|
1084
|
+
.catch(t.ifError)
|
|
1085
|
+
.then(() => t.end())
|
|
1086
|
+
})
|
|
1087
|
+
|
|
962
1088
|
test('uses GET for queries below limit', (t) => {
|
|
963
1089
|
// Please dont ever do this. Just... don't.
|
|
964
1090
|
const clause = []
|
|
@@ -1054,7 +1180,7 @@ test('uses POST for long queries, but puts request tag as query param', (t) => {
|
|
|
1054
1180
|
})
|
|
1055
1181
|
|
|
1056
1182
|
test('uses POST for long queries also towards CDN', (t) => {
|
|
1057
|
-
const client =
|
|
1183
|
+
const client = createClient({projectId: 'abc123', dataset: 'foo', useCdn: true})
|
|
1058
1184
|
|
|
1059
1185
|
const clause = []
|
|
1060
1186
|
const params = {}
|
|
@@ -1316,6 +1442,25 @@ test('executes patch with request tag when commit() is called with tag', (t) =>
|
|
|
1316
1442
|
.then(t.end)
|
|
1317
1443
|
})
|
|
1318
1444
|
|
|
1445
|
+
test('executes patch with auto generate key option if specified commit()', (t) => {
|
|
1446
|
+
const expectedPatch = {patch: {id: 'abc123', set: {visited: true}}}
|
|
1447
|
+
nock(projectHost())
|
|
1448
|
+
.post('/v1/data/mutate/foo?returnIds=true&autoGenerateArrayKeys=true&visibility=sync', {
|
|
1449
|
+
mutations: [expectedPatch],
|
|
1450
|
+
})
|
|
1451
|
+
.reply(200, {transactionId: 'blatti'})
|
|
1452
|
+
|
|
1453
|
+
getClient()
|
|
1454
|
+
.patch('abc123')
|
|
1455
|
+
.set({visited: true})
|
|
1456
|
+
.commit({returnDocuments: false, autoGenerateArrayKeys: true})
|
|
1457
|
+
.then((res) => {
|
|
1458
|
+
t.equal(res.transactionId, 'blatti', 'applies given patch')
|
|
1459
|
+
})
|
|
1460
|
+
.catch(t.ifError)
|
|
1461
|
+
.then(t.end)
|
|
1462
|
+
})
|
|
1463
|
+
|
|
1319
1464
|
test('executes patch with given token override commit() is called', (t) => {
|
|
1320
1465
|
const expectedPatch = {patch: {id: 'abc123', inc: {count: 1}, set: {visited: true}}}
|
|
1321
1466
|
nock(projectHost(), {reqheaders: {Authorization: 'Bearer abc123'}})
|
|
@@ -1424,7 +1569,7 @@ test('patch has toJSON() which serializes patch', (t) => {
|
|
|
1424
1569
|
})
|
|
1425
1570
|
|
|
1426
1571
|
test('Patch is available on client and can be used without instantiated client', (t) => {
|
|
1427
|
-
const patch = new
|
|
1572
|
+
const patch = new createClient.Patch('foo.bar')
|
|
1428
1573
|
t.deepEqual(
|
|
1429
1574
|
patch.inc({foo: 1}).dec({bar: 2}).serialize(),
|
|
1430
1575
|
{id: 'foo.bar', inc: {foo: 1}, dec: {bar: 2}},
|
|
@@ -1434,7 +1579,7 @@ test('Patch is available on client and can be used without instantiated client',
|
|
|
1434
1579
|
})
|
|
1435
1580
|
|
|
1436
1581
|
test('patch commit() throws if called without a client', (t) => {
|
|
1437
|
-
const patch = new
|
|
1582
|
+
const patch = new createClient.Patch('foo.bar')
|
|
1438
1583
|
t.throws(() => patch.dec({bar: 2}).commit(), /client.*mutate/i)
|
|
1439
1584
|
t.end()
|
|
1440
1585
|
})
|
|
@@ -1646,7 +1791,7 @@ test('transaction has toJSON() which serializes patch', (t) => {
|
|
|
1646
1791
|
})
|
|
1647
1792
|
|
|
1648
1793
|
test('Transaction is available on client and can be used without instantiated client', (t) => {
|
|
1649
|
-
const trans = new
|
|
1794
|
+
const trans = new createClient.Transaction()
|
|
1650
1795
|
t.deepEqual(
|
|
1651
1796
|
trans.delete('barfoo').serialize(),
|
|
1652
1797
|
[{delete: {id: 'barfoo'}}],
|
|
@@ -1656,7 +1801,7 @@ test('Transaction is available on client and can be used without instantiated cl
|
|
|
1656
1801
|
})
|
|
1657
1802
|
|
|
1658
1803
|
test('transaction can be created without client and passed to mutate()', (t) => {
|
|
1659
|
-
const trx = new
|
|
1804
|
+
const trx = new createClient.Transaction()
|
|
1660
1805
|
trx.delete('foo')
|
|
1661
1806
|
|
|
1662
1807
|
const mutations = [{delete: {id: 'foo'}}]
|
|
@@ -1671,7 +1816,7 @@ test('transaction can be created without client and passed to mutate()', (t) =>
|
|
|
1671
1816
|
})
|
|
1672
1817
|
|
|
1673
1818
|
test('transaction commit() throws if called without a client', (t) => {
|
|
1674
|
-
const trans = new
|
|
1819
|
+
const trans = new createClient.Transaction()
|
|
1675
1820
|
t.throws(() => trans.delete('foo.bar').commit(), /client.*mutate/i)
|
|
1676
1821
|
t.end()
|
|
1677
1822
|
})
|
|
@@ -2193,7 +2338,7 @@ test('can retrieve user by id', (t) => {
|
|
|
2193
2338
|
* CDN API USAGE *
|
|
2194
2339
|
*****************/
|
|
2195
2340
|
test('will use live API by default', (t) => {
|
|
2196
|
-
const client =
|
|
2341
|
+
const client = createClient({projectId: 'abc123', dataset: 'foo'})
|
|
2197
2342
|
|
|
2198
2343
|
const response = {result: []}
|
|
2199
2344
|
nock('https://abc123.api.sanity.io').get('/v1/data/query/foo?query=*').reply(200, response)
|
|
@@ -2208,7 +2353,7 @@ test('will use live API by default', (t) => {
|
|
|
2208
2353
|
})
|
|
2209
2354
|
|
|
2210
2355
|
test('will use CDN API if told to', (t) => {
|
|
2211
|
-
const client =
|
|
2356
|
+
const client = createClient({projectId: 'abc123', dataset: 'foo', useCdn: true})
|
|
2212
2357
|
|
|
2213
2358
|
const response = {result: []}
|
|
2214
2359
|
nock('https://abc123.apicdn.sanity.io').get('/v1/data/query/foo?query=*').reply(200, response)
|
|
@@ -2223,7 +2368,7 @@ test('will use CDN API if told to', (t) => {
|
|
|
2223
2368
|
})
|
|
2224
2369
|
|
|
2225
2370
|
test('will use live API for mutations', (t) => {
|
|
2226
|
-
const client =
|
|
2371
|
+
const client = createClient({projectId: 'abc123', dataset: 'foo', useCdn: true})
|
|
2227
2372
|
|
|
2228
2373
|
nock('https://abc123.api.sanity.io')
|
|
2229
2374
|
.post('/v1/data/mutate/foo?returnIds=true&returnDocuments=true&visibility=sync')
|
|
@@ -2233,7 +2378,7 @@ test('will use live API for mutations', (t) => {
|
|
|
2233
2378
|
})
|
|
2234
2379
|
|
|
2235
2380
|
test('will use cdn for queries even when with token specified', (t) => {
|
|
2236
|
-
const client =
|
|
2381
|
+
const client = createClient({
|
|
2237
2382
|
projectId: 'abc123',
|
|
2238
2383
|
dataset: 'foo',
|
|
2239
2384
|
useCdn: true,
|
|
@@ -2249,8 +2394,7 @@ test('will use cdn for queries even when with token specified', (t) => {
|
|
|
2249
2394
|
})
|
|
2250
2395
|
|
|
2251
2396
|
test('allows overriding headers', (t) => {
|
|
2252
|
-
|
|
2253
|
-
const client = sanityClient({
|
|
2397
|
+
const client = createClient({
|
|
2254
2398
|
projectId: 'abc123',
|
|
2255
2399
|
dataset: 'foo',
|
|
2256
2400
|
token: 'foo',
|
|
@@ -2261,12 +2405,15 @@ test('allows overriding headers', (t) => {
|
|
|
2261
2405
|
.get('/v1/data/query/foo?query=*')
|
|
2262
2406
|
.reply(200, {result: []})
|
|
2263
2407
|
|
|
2264
|
-
client
|
|
2265
|
-
|
|
2408
|
+
client
|
|
2409
|
+
.fetch('*', {}, {headers: {foo: 'bar'}})
|
|
2410
|
+
.then(noop)
|
|
2411
|
+
.catch(t.ifError)
|
|
2412
|
+
.then(t.end)
|
|
2266
2413
|
})
|
|
2267
2414
|
|
|
2268
2415
|
test('will use live API if withCredentials is set to true', (t) => {
|
|
2269
|
-
const client =
|
|
2416
|
+
const client = createClient({
|
|
2270
2417
|
withCredentials: true,
|
|
2271
2418
|
projectId: 'abc123',
|
|
2272
2419
|
dataset: 'foo',
|
|
@@ -2371,24 +2518,24 @@ test('ServerError includes message in stack', (t) => {
|
|
|
2371
2518
|
})
|
|
2372
2519
|
|
|
2373
2520
|
test('exposes ClientError', (t) => {
|
|
2374
|
-
t.equal(typeof
|
|
2521
|
+
t.equal(typeof createClient.ClientError, 'function')
|
|
2375
2522
|
const error = new SanityClient.ClientError({statusCode: 400, headers: {}, body: {}})
|
|
2376
2523
|
t.ok(error instanceof Error)
|
|
2377
|
-
t.ok(error instanceof
|
|
2524
|
+
t.ok(error instanceof createClient.ClientError)
|
|
2378
2525
|
t.end()
|
|
2379
2526
|
})
|
|
2380
2527
|
|
|
2381
2528
|
test('exposes ServerError', (t) => {
|
|
2382
|
-
t.equal(typeof
|
|
2529
|
+
t.equal(typeof createClient.ServerError, 'function')
|
|
2383
2530
|
const error = new SanityClient.ServerError({statusCode: 500, headers: {}, body: {}})
|
|
2384
2531
|
t.ok(error instanceof Error)
|
|
2385
|
-
t.ok(error instanceof
|
|
2532
|
+
t.ok(error instanceof createClient.ServerError)
|
|
2386
2533
|
t.end()
|
|
2387
2534
|
})
|
|
2388
2535
|
|
|
2389
2536
|
// Don't rely on this unless you're working at Sanity Inc ;)
|
|
2390
2537
|
test('exposes default requester', (t) => {
|
|
2391
|
-
t.equal(typeof
|
|
2538
|
+
t.equal(typeof createClient.requester, 'function')
|
|
2392
2539
|
t.end()
|
|
2393
2540
|
})
|
|
2394
2541
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
// eslint-disable-next-line no-global-assign -- we know what we're doing ESlint ;)
|
|
2
|
+
require = require('esm')(module)
|
|
1
3
|
const test = require('tape')
|
|
2
|
-
const encode = require('../src/data/encodeQueryString')
|
|
4
|
+
const {encodeQueryString: encode} = require('../src/data/encodeQueryString')
|
|
3
5
|
|
|
4
6
|
test('can encode basic query without parameters', (t) => {
|
|
5
7
|
const query = 'gamedb.game[maxPlayers == 64]'
|
package/test/listen.test.js
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
// (Node 4 compat)
|
|
3
3
|
|
|
4
4
|
'use strict'
|
|
5
|
+
// eslint-disable-next-line no-global-assign -- we know what we're doing ESlint ;)
|
|
6
|
+
require = require('esm')(module)
|
|
5
7
|
|
|
6
8
|
const test = require('tape')
|
|
7
9
|
const assign = require('xtend')
|
|
8
|
-
const
|
|
10
|
+
const {createClient} = require('../src/sanityClient')
|
|
9
11
|
const sseServer = require('./helpers/sseServer')
|
|
10
12
|
|
|
11
13
|
const getClient = (options) =>
|
|
12
|
-
|
|
14
|
+
createClient(
|
|
13
15
|
assign(
|
|
14
16
|
{
|
|
15
17
|
dataset: 'prod',
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// eslint-disable-next-line no-global-assign -- we know what we're doing ESlint ;)
|
|
2
|
+
require = require('esm')(module)
|
|
1
3
|
// This test suite fails using tape but should pass if running with as a node script
|
|
2
4
|
const test = require('tape')
|
|
3
5
|
const nock = require('nock')
|
|
@@ -11,10 +13,12 @@ const stub = (target, prop, stubbed) => {
|
|
|
11
13
|
}
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
const combine =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const combine =
|
|
17
|
+
(...fns) =>
|
|
18
|
+
() => {
|
|
19
|
+
const [head, ...tail] = fns
|
|
20
|
+
return tail.reduce((acc, fn) => fn(acc), head())
|
|
21
|
+
}
|
|
18
22
|
|
|
19
23
|
/**************************
|
|
20
24
|
* CLIENT CONFIG WARNINGS *
|