netlify-cli 10.14.0 → 10.15.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/README.md +1 -1
- package/npm-shrinkwrap.json +53 -41
- package/package.json +2 -2
- package/src/commands/graph/graph-edit.js +1 -0
- package/src/commands/graph/graph-init.js +3 -0
- package/src/commands/graph/graph-library.js +15 -1
- package/src/commands/graph/graph-pull.js +8 -8
- package/src/lib/one-graph/cli-client.js +178 -20
package/README.md
CHANGED
|
@@ -165,7 +165,7 @@ Manage netlify functions
|
|
|
165
165
|
| [`graph:init`](/docs/commands/graph.md#graphinit) | Initialize all the resources for Netlify Graph |
|
|
166
166
|
| [`graph:library`](/docs/commands/graph.md#graphlibrary) | Generate the Graph function library |
|
|
167
167
|
| [`graph:operations`](/docs/commands/graph.md#graphoperations) | List all of the locally available operations |
|
|
168
|
-
| [`graph:pull`](/docs/commands/graph.md#graphpull) | Pull
|
|
168
|
+
| [`graph:pull`](/docs/commands/graph.md#graphpull) | Pull your remote Netlify Graph schema locally, and process pending Graph edit events |
|
|
169
169
|
|
|
170
170
|
|
|
171
171
|
### [init](/docs/commands/init.md)
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.15.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "netlify-cli",
|
|
9
|
-
"version": "10.
|
|
9
|
+
"version": "10.15.0",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"multiparty": "^4.2.1",
|
|
82
82
|
"netlify": "^12.0.0",
|
|
83
83
|
"netlify-headers-parser": "^6.0.2",
|
|
84
|
-
"netlify-onegraph-internal": "0.4.
|
|
84
|
+
"netlify-onegraph-internal": "0.4.2",
|
|
85
85
|
"netlify-redirect-parser": "^13.0.5",
|
|
86
86
|
"netlify-redirector": "^0.2.1",
|
|
87
87
|
"node-fetch": "^2.6.0",
|
|
@@ -8194,7 +8194,7 @@
|
|
|
8194
8194
|
"node_modules/cpy/node_modules/glob-parent": {
|
|
8195
8195
|
"version": "3.1.0",
|
|
8196
8196
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
|
|
8197
|
-
"integrity": "
|
|
8197
|
+
"integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
|
|
8198
8198
|
"dependencies": {
|
|
8199
8199
|
"is-glob": "^3.1.0",
|
|
8200
8200
|
"path-dirname": "^1.0.0"
|
|
@@ -11962,9 +11962,9 @@
|
|
|
11962
11962
|
}
|
|
11963
11963
|
},
|
|
11964
11964
|
"node_modules/follow-redirects": {
|
|
11965
|
-
"version": "1.
|
|
11966
|
-
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.
|
|
11967
|
-
"integrity": "sha512
|
|
11965
|
+
"version": "1.15.1",
|
|
11966
|
+
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
|
|
11967
|
+
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
|
|
11968
11968
|
"funding": [
|
|
11969
11969
|
{
|
|
11970
11970
|
"type": "individual",
|
|
@@ -12507,9 +12507,9 @@
|
|
|
12507
12507
|
}
|
|
12508
12508
|
},
|
|
12509
12509
|
"node_modules/got": {
|
|
12510
|
-
"version": "11.8.
|
|
12511
|
-
"resolved": "https://registry.npmjs.org/got/-/got-11.8.
|
|
12512
|
-
"integrity": "sha512-
|
|
12510
|
+
"version": "11.8.5",
|
|
12511
|
+
"resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz",
|
|
12512
|
+
"integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==",
|
|
12513
12513
|
"dev": true,
|
|
12514
12514
|
"dependencies": {
|
|
12515
12515
|
"@sindresorhus/is": "^4.0.0",
|
|
@@ -13312,9 +13312,9 @@
|
|
|
13312
13312
|
}
|
|
13313
13313
|
},
|
|
13314
13314
|
"node_modules/inquirer/node_modules/ansi-regex": {
|
|
13315
|
-
"version": "4.1.
|
|
13316
|
-
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.
|
|
13317
|
-
"integrity": "sha512-
|
|
13315
|
+
"version": "4.1.1",
|
|
13316
|
+
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
|
|
13317
|
+
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
|
|
13318
13318
|
"engines": {
|
|
13319
13319
|
"node": ">=6"
|
|
13320
13320
|
}
|
|
@@ -13391,9 +13391,9 @@
|
|
|
13391
13391
|
}
|
|
13392
13392
|
},
|
|
13393
13393
|
"node_modules/inquirer/node_modules/string-width/node_modules/ansi-regex": {
|
|
13394
|
-
"version": "3.0.
|
|
13395
|
-
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.
|
|
13396
|
-
"integrity": "
|
|
13394
|
+
"version": "3.0.1",
|
|
13395
|
+
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
|
|
13396
|
+
"integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
|
|
13397
13397
|
"engines": {
|
|
13398
13398
|
"node": ">=4"
|
|
13399
13399
|
}
|
|
@@ -14842,9 +14842,9 @@
|
|
|
14842
14842
|
}
|
|
14843
14843
|
},
|
|
14844
14844
|
"node_modules/listr-update-renderer/node_modules/wrap-ansi/node_modules/ansi-regex": {
|
|
14845
|
-
"version": "3.0.
|
|
14846
|
-
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.
|
|
14847
|
-
"integrity": "
|
|
14845
|
+
"version": "3.0.1",
|
|
14846
|
+
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
|
|
14847
|
+
"integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
|
|
14848
14848
|
"engines": {
|
|
14849
14849
|
"node": ">=4"
|
|
14850
14850
|
}
|
|
@@ -16384,12 +16384,13 @@
|
|
|
16384
16384
|
}
|
|
16385
16385
|
},
|
|
16386
16386
|
"node_modules/netlify-onegraph-internal": {
|
|
16387
|
-
"version": "0.4.
|
|
16388
|
-
"resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.4.
|
|
16389
|
-
"integrity": "sha512-
|
|
16387
|
+
"version": "0.4.2",
|
|
16388
|
+
"resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.4.2.tgz",
|
|
16389
|
+
"integrity": "sha512-3TGD/s2FGjx9NcOcMPMMUxamy3IVY9O0ZZ176FuHVDmLAc5l8mj0ZNoUbhdrXfZjes62Gt6/YynCJxGShE6oUA==",
|
|
16390
16390
|
"dependencies": {
|
|
16391
16391
|
"graphql": "16.0.0",
|
|
16392
16392
|
"node-fetch": "^2.6.0",
|
|
16393
|
+
"rusha": "^0.8.14",
|
|
16393
16394
|
"uuid": "^8.3.2"
|
|
16394
16395
|
}
|
|
16395
16396
|
},
|
|
@@ -19977,6 +19978,11 @@
|
|
|
19977
19978
|
"queue-microtask": "^1.2.2"
|
|
19978
19979
|
}
|
|
19979
19980
|
},
|
|
19981
|
+
"node_modules/rusha": {
|
|
19982
|
+
"version": "0.8.14",
|
|
19983
|
+
"resolved": "https://registry.npmjs.org/rusha/-/rusha-0.8.14.tgz",
|
|
19984
|
+
"integrity": "sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA=="
|
|
19985
|
+
},
|
|
19980
19986
|
"node_modules/rxjs": {
|
|
19981
19987
|
"version": "6.6.7",
|
|
19982
19988
|
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
|
|
@@ -29028,7 +29034,7 @@
|
|
|
29028
29034
|
"glob-parent": {
|
|
29029
29035
|
"version": "3.1.0",
|
|
29030
29036
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
|
|
29031
|
-
"integrity": "
|
|
29037
|
+
"integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
|
|
29032
29038
|
"requires": {
|
|
29033
29039
|
"is-glob": "^3.1.0",
|
|
29034
29040
|
"path-dirname": "^1.0.0"
|
|
@@ -31954,9 +31960,9 @@
|
|
|
31954
31960
|
}
|
|
31955
31961
|
},
|
|
31956
31962
|
"follow-redirects": {
|
|
31957
|
-
"version": "1.
|
|
31958
|
-
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.
|
|
31959
|
-
"integrity": "sha512
|
|
31963
|
+
"version": "1.15.1",
|
|
31964
|
+
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
|
|
31965
|
+
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
|
|
31960
31966
|
},
|
|
31961
31967
|
"for-in": {
|
|
31962
31968
|
"version": "1.0.2",
|
|
@@ -32362,9 +32368,9 @@
|
|
|
32362
32368
|
}
|
|
32363
32369
|
},
|
|
32364
32370
|
"got": {
|
|
32365
|
-
"version": "11.8.
|
|
32366
|
-
"resolved": "https://registry.npmjs.org/got/-/got-11.8.
|
|
32367
|
-
"integrity": "sha512-
|
|
32371
|
+
"version": "11.8.5",
|
|
32372
|
+
"resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz",
|
|
32373
|
+
"integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==",
|
|
32368
32374
|
"dev": true,
|
|
32369
32375
|
"requires": {
|
|
32370
32376
|
"@sindresorhus/is": "^4.0.0",
|
|
@@ -32911,9 +32917,9 @@
|
|
|
32911
32917
|
"integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ=="
|
|
32912
32918
|
},
|
|
32913
32919
|
"ansi-regex": {
|
|
32914
|
-
"version": "4.1.
|
|
32915
|
-
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.
|
|
32916
|
-
"integrity": "sha512-
|
|
32920
|
+
"version": "4.1.1",
|
|
32921
|
+
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
|
|
32922
|
+
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="
|
|
32917
32923
|
},
|
|
32918
32924
|
"ansi-styles": {
|
|
32919
32925
|
"version": "3.2.1",
|
|
@@ -32966,9 +32972,9 @@
|
|
|
32966
32972
|
},
|
|
32967
32973
|
"dependencies": {
|
|
32968
32974
|
"ansi-regex": {
|
|
32969
|
-
"version": "3.0.
|
|
32970
|
-
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.
|
|
32971
|
-
"integrity": "
|
|
32975
|
+
"version": "3.0.1",
|
|
32976
|
+
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
|
|
32977
|
+
"integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw=="
|
|
32972
32978
|
},
|
|
32973
32979
|
"strip-ansi": {
|
|
32974
32980
|
"version": "4.0.0",
|
|
@@ -34075,9 +34081,9 @@
|
|
|
34075
34081
|
},
|
|
34076
34082
|
"dependencies": {
|
|
34077
34083
|
"ansi-regex": {
|
|
34078
|
-
"version": "3.0.
|
|
34079
|
-
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.
|
|
34080
|
-
"integrity": "
|
|
34084
|
+
"version": "3.0.1",
|
|
34085
|
+
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
|
|
34086
|
+
"integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw=="
|
|
34081
34087
|
},
|
|
34082
34088
|
"is-fullwidth-code-point": {
|
|
34083
34089
|
"version": "2.0.0",
|
|
@@ -35257,12 +35263,13 @@
|
|
|
35257
35263
|
}
|
|
35258
35264
|
},
|
|
35259
35265
|
"netlify-onegraph-internal": {
|
|
35260
|
-
"version": "0.4.
|
|
35261
|
-
"resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.4.
|
|
35262
|
-
"integrity": "sha512-
|
|
35266
|
+
"version": "0.4.2",
|
|
35267
|
+
"resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.4.2.tgz",
|
|
35268
|
+
"integrity": "sha512-3TGD/s2FGjx9NcOcMPMMUxamy3IVY9O0ZZ176FuHVDmLAc5l8mj0ZNoUbhdrXfZjes62Gt6/YynCJxGShE6oUA==",
|
|
35263
35269
|
"requires": {
|
|
35264
35270
|
"graphql": "16.0.0",
|
|
35265
35271
|
"node-fetch": "^2.6.0",
|
|
35272
|
+
"rusha": "^0.8.14",
|
|
35266
35273
|
"uuid": "^8.3.2"
|
|
35267
35274
|
},
|
|
35268
35275
|
"dependencies": {
|
|
@@ -37945,6 +37952,11 @@
|
|
|
37945
37952
|
"queue-microtask": "^1.2.2"
|
|
37946
37953
|
}
|
|
37947
37954
|
},
|
|
37955
|
+
"rusha": {
|
|
37956
|
+
"version": "0.8.14",
|
|
37957
|
+
"resolved": "https://registry.npmjs.org/rusha/-/rusha-0.8.14.tgz",
|
|
37958
|
+
"integrity": "sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA=="
|
|
37959
|
+
},
|
|
37948
37960
|
"rxjs": {
|
|
37949
37961
|
"version": "6.6.7",
|
|
37950
37962
|
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
3
|
"description": "Netlify command line tool",
|
|
4
|
-
"version": "10.
|
|
4
|
+
"version": "10.15.0",
|
|
5
5
|
"author": "Netlify Inc.",
|
|
6
6
|
"contributors": [
|
|
7
7
|
"Abraham Schilling <AbrahamSchilling@gmail.com> (https://gitlab.com/n4bb12)",
|
|
@@ -291,7 +291,7 @@
|
|
|
291
291
|
"multiparty": "^4.2.1",
|
|
292
292
|
"netlify": "^12.0.0",
|
|
293
293
|
"netlify-headers-parser": "^6.0.2",
|
|
294
|
-
"netlify-onegraph-internal": "0.4.
|
|
294
|
+
"netlify-onegraph-internal": "0.4.2",
|
|
295
295
|
"netlify-redirect-parser": "^13.0.5",
|
|
296
296
|
"netlify-redirector": "^0.2.1",
|
|
297
297
|
"node-fetch": "^2.6.0",
|
|
@@ -5,6 +5,7 @@ const { OneGraphClient } = require('netlify-onegraph-internal')
|
|
|
5
5
|
const { v4: uuidv4 } = require('uuid')
|
|
6
6
|
|
|
7
7
|
const { OneGraphCliClient, ensureCLISession } = require('../../lib/one-graph/cli-client')
|
|
8
|
+
const { getNetlifyGraphConfig } = require('../../lib/one-graph/cli-netlify-graph')
|
|
8
9
|
const { NETLIFYDEVERR, chalk, error, exit, getToken, log } = require('../../utils')
|
|
9
10
|
const { msg } = require('../login/login')
|
|
10
11
|
|
|
@@ -63,11 +64,13 @@ const graphInit = async (options, command) => {
|
|
|
63
64
|
|
|
64
65
|
await ensureAppForSite(netlifyToken, siteId)
|
|
65
66
|
|
|
67
|
+
const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options })
|
|
66
68
|
await ensureCLISession({
|
|
67
69
|
metadata: {},
|
|
68
70
|
netlifyToken,
|
|
69
71
|
site,
|
|
70
72
|
state,
|
|
73
|
+
netlifyGraphConfig,
|
|
71
74
|
})
|
|
72
75
|
|
|
73
76
|
let envChanged = false
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
+
const { readLockfile } = require('../../lib/one-graph/cli-client')
|
|
2
3
|
const {
|
|
3
4
|
buildSchema,
|
|
4
5
|
defaultExampleOperationsDoc,
|
|
@@ -9,7 +10,7 @@ const {
|
|
|
9
10
|
readGraphQLOperationsSourceFile,
|
|
10
11
|
readGraphQLSchemaFile,
|
|
11
12
|
} = require('../../lib/one-graph/cli-netlify-graph')
|
|
12
|
-
const { error, log } = require('../../utils')
|
|
13
|
+
const { NETLIFYDEVERR, chalk, error, log } = require('../../utils')
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Creates the `netlify graph:library` command
|
|
@@ -42,10 +43,23 @@ const graphLibrary = async (options, command) => {
|
|
|
42
43
|
const parsedDoc = parse(currentOperationsDoc)
|
|
43
44
|
const { fragments, functions } = extractFunctionsFromOperationDoc(parsedDoc)
|
|
44
45
|
|
|
46
|
+
const lockfile = readLockfile({ siteRoot: command.netlify.site.root })
|
|
47
|
+
|
|
48
|
+
if (lockfile == null) {
|
|
49
|
+
error(
|
|
50
|
+
`${NETLIFYDEVERR} Error: no lockfile found, unable to run \`netlify graph:library\`. To pull a remote schema (and create a lockfile), run ${chalk.yellow(
|
|
51
|
+
'netlify graph:pull',
|
|
52
|
+
)} `,
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const schemaId = lockfile && lockfile.locked.schemaId
|
|
57
|
+
|
|
45
58
|
generateFunctionsFile({
|
|
46
59
|
logger: log,
|
|
47
60
|
netlifyGraphConfig,
|
|
48
61
|
schema,
|
|
62
|
+
schemaId,
|
|
49
63
|
operationsDoc: currentOperationsDoc,
|
|
50
64
|
functions,
|
|
51
65
|
fragments,
|
|
@@ -34,6 +34,13 @@ const graphPull = async (options, command) => {
|
|
|
34
34
|
const { jwt } = await OneGraphCliClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
|
|
35
35
|
|
|
36
36
|
const oneGraphSessionId = loadCLISession(state)
|
|
37
|
+
if (!oneGraphSessionId) {
|
|
38
|
+
warn(
|
|
39
|
+
'No local Netlify Graph session found, skipping command queue drain. Create a new session by running `netlify graph:edit`.',
|
|
40
|
+
)
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
37
44
|
await refetchAndGenerateFromOneGraph({
|
|
38
45
|
logger: log,
|
|
39
46
|
netlifyGraphConfig,
|
|
@@ -43,13 +50,6 @@ const graphPull = async (options, command) => {
|
|
|
43
50
|
sessionId: oneGraphSessionId,
|
|
44
51
|
})
|
|
45
52
|
|
|
46
|
-
if (!oneGraphSessionId) {
|
|
47
|
-
warn(
|
|
48
|
-
'No local Netlify Graph session found, skipping command queue drain. Create a new session by running `netlify graph:edit`.',
|
|
49
|
-
)
|
|
50
|
-
return
|
|
51
|
-
}
|
|
52
|
-
|
|
53
53
|
const schemaString = readGraphQLSchemaFile(netlifyGraphConfig)
|
|
54
54
|
|
|
55
55
|
let schema
|
|
@@ -106,7 +106,7 @@ const graphPull = async (options, command) => {
|
|
|
106
106
|
const createGraphPullCommand = (program) =>
|
|
107
107
|
program
|
|
108
108
|
.command('graph:pull')
|
|
109
|
-
.description('Pull
|
|
109
|
+
.description('Pull your remote Netlify Graph schema locally, and process pending Graph edit events')
|
|
110
110
|
.action(async (options, command) => {
|
|
111
111
|
await graphPull(options, command)
|
|
112
112
|
})
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
/* eslint-disable eslint-comments/disable-enable-pair */
|
|
3
3
|
/* eslint-disable fp/no-loops */
|
|
4
4
|
const crypto = require('crypto')
|
|
5
|
+
const { readFileSync, writeFileSync } = require('fs')
|
|
5
6
|
const os = require('os')
|
|
6
7
|
const path = require('path')
|
|
7
8
|
|
|
8
9
|
const gitRepoInfo = require('git-repo-info')
|
|
9
10
|
const { GraphQL, InternalConsole, OneGraphClient } = require('netlify-onegraph-internal')
|
|
10
|
-
const { NetlifyGraph } = require('netlify-onegraph-internal')
|
|
11
|
+
const { NetlifyGraph, NetlifyGraphLockfile } = require('netlify-onegraph-internal')
|
|
11
12
|
|
|
12
13
|
// eslint-disable-next-line no-unused-vars
|
|
13
14
|
const { StateConfig, USER_AGENT, chalk, error, execa, log, warn, watchDebounced } = require('../../utils')
|
|
@@ -273,6 +274,33 @@ const regenerateFunctionsFileFromOperationsFile = (input) => {
|
|
|
273
274
|
generateFunctionsFile({ netlifyGraphConfig, schema, operationsDoc: appOperationsDoc, functions, fragments })
|
|
274
275
|
}
|
|
275
276
|
|
|
277
|
+
/**
|
|
278
|
+
* Lockfile Operations
|
|
279
|
+
*/
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Persist the Netlify Graph lockfile on disk
|
|
283
|
+
* @param {object} input
|
|
284
|
+
* @param {string} input.siteRoot The GraphQL schema to use when generating code
|
|
285
|
+
* @param {NetlifyGraphLockfile.V0_format} input.lockfile
|
|
286
|
+
*/
|
|
287
|
+
const writeLockfile = ({ lockfile, siteRoot }) => {
|
|
288
|
+
writeFileSync(path.join(siteRoot, NetlifyGraphLockfile.defaultLockFileName), JSON.stringify(lockfile, null, 2))
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Read the Netlify Graph lockfile from disk, if it exists
|
|
293
|
+
* @param {object} input
|
|
294
|
+
* @param {string} input.siteRoot The GraphQL schema to use when generating code
|
|
295
|
+
* @return {NetlifyGraphLockfile.V0_format | undefined}
|
|
296
|
+
*/
|
|
297
|
+
const readLockfile = ({ siteRoot }) => {
|
|
298
|
+
try {
|
|
299
|
+
const buf = readFileSync(path.join(siteRoot, NetlifyGraphLockfile.defaultLockFileName))
|
|
300
|
+
return JSON.parse(buf.toString('utf8'))
|
|
301
|
+
} catch {}
|
|
302
|
+
}
|
|
303
|
+
|
|
276
304
|
/**
|
|
277
305
|
* Compute a md5 hash of a string
|
|
278
306
|
* @param {string} input String to compute a quick md5 hash for
|
|
@@ -285,7 +313,8 @@ const quickHash = (input) => {
|
|
|
285
313
|
}
|
|
286
314
|
|
|
287
315
|
/**
|
|
288
|
-
* Fetch a persisted operations doc by its id,
|
|
316
|
+
* Fetch a persisted operations doc by its id, normalize it for Netlify Graph
|
|
317
|
+
* and return its contents as a string
|
|
289
318
|
* @param {object} input
|
|
290
319
|
* @param {string} input.siteId The site id to query against
|
|
291
320
|
* @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
|
|
@@ -293,11 +322,11 @@ const quickHash = (input) => {
|
|
|
293
322
|
* @param {(message: string) => void=} input.logger A function that if provided will be used to log messages
|
|
294
323
|
* @param {GraphQL.GraphQLSchema} input.schema The GraphQL schema to use when generating code
|
|
295
324
|
* @param {NetlifyGraph.NetlifyGraphConfig} input.netlifyGraphConfig A standalone config object that contains all the information necessary for Netlify Graph to process events
|
|
296
|
-
* @returns
|
|
325
|
+
* @returns {Promise<string | undefined>}
|
|
297
326
|
*/
|
|
298
|
-
const
|
|
327
|
+
const fetchGraphQLOperationsLibraryFromPersistedDoc = async (input) => {
|
|
299
328
|
try {
|
|
300
|
-
const { docId,
|
|
329
|
+
const { docId, netlifyToken, siteId } = input
|
|
301
330
|
const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
|
|
302
331
|
const persistedDoc = await OneGraphClient.fetchPersistedQuery(jwt, siteId, docId)
|
|
303
332
|
if (!persistedDoc) {
|
|
@@ -308,21 +337,63 @@ const updateGraphQLOperationsFileFromPersistedDoc = async (input) => {
|
|
|
308
337
|
// Sorts the operations stably, prepends the @netlify directive, etc.
|
|
309
338
|
const operationsDocString = normalizeOperationsDoc(persistedDoc.query)
|
|
310
339
|
|
|
311
|
-
|
|
312
|
-
|
|
340
|
+
return operationsDocString
|
|
341
|
+
} catch {
|
|
342
|
+
warn(`Unable to reach Netlify Graph servers in order to update Graph operations file`)
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Fetch a persisted operations doc by its id, write it to the system, and regenerate the library
|
|
348
|
+
* @param {object} input
|
|
349
|
+
* @param {string} input.operationsDocString The contents of the GraphQL operations document
|
|
350
|
+
* @param {(message: string) => void=} input.logger A function that if provided will be used to log messages
|
|
351
|
+
* @param {GraphQL.GraphQLSchema} input.schema The GraphQL schema to use when generating code
|
|
352
|
+
* @param {NetlifyGraph.NetlifyGraphConfig} input.netlifyGraphConfig A standalone config object that contains all the information necessary for Netlify Graph to process events
|
|
353
|
+
* @returns
|
|
354
|
+
*/
|
|
355
|
+
const updateGraphQLOperationsFileFromPersistedDoc = (input) => {
|
|
356
|
+
const { logger, netlifyGraphConfig, operationsDocString, schema } = input
|
|
313
357
|
|
|
314
|
-
|
|
358
|
+
writeGraphQLOperationsSourceFile({ logger, netlifyGraphConfig, operationsDocString })
|
|
359
|
+
regenerateFunctionsFileFromOperationsFile({ netlifyGraphConfig, schema })
|
|
315
360
|
|
|
316
|
-
|
|
361
|
+
const hash = quickHash(operationsDocString)
|
|
317
362
|
|
|
318
|
-
|
|
319
|
-
witnessedIncomingDocumentHashes.shift()
|
|
320
|
-
}
|
|
363
|
+
const relevantHasLength = 10
|
|
321
364
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
warn(`Unable to reach Netlify Graph servers in order to update Graph operations file`)
|
|
365
|
+
if (witnessedIncomingDocumentHashes.length > relevantHasLength) {
|
|
366
|
+
witnessedIncomingDocumentHashes.shift()
|
|
325
367
|
}
|
|
368
|
+
|
|
369
|
+
witnessedIncomingDocumentHashes.push(hash)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Fetch a persisted operations doc by its id, write it to the system, and regenerate the library
|
|
374
|
+
* @param {object} input
|
|
375
|
+
* @param {string} input.siteId The site id to query against
|
|
376
|
+
* @param {string} input.schemaId The schema ID to query against
|
|
377
|
+
* @param {string} input.siteRoot Path to the root of the project
|
|
378
|
+
* @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
|
|
379
|
+
* @param {string} input.docId The GraphQL operations document id to fetch
|
|
380
|
+
* @param {(message: string) => void=} input.logger A function that if provided will be used to log messages
|
|
381
|
+
* @param {GraphQL.GraphQLSchema} input.schema The GraphQL schema to use when generating code
|
|
382
|
+
* @param {NetlifyGraph.NetlifyGraphConfig} input.netlifyGraphConfig A standalone config object that contains all the information necessary for Netlify Graph to process events
|
|
383
|
+
* @returns {Promise<string | undefined>}
|
|
384
|
+
*/
|
|
385
|
+
const handleOperationsLibraryPersistedEvent = async (input) => {
|
|
386
|
+
const { schemaId, siteRoot } = input
|
|
387
|
+
const operationsFileContents = await fetchGraphQLOperationsLibraryFromPersistedDoc(input)
|
|
388
|
+
|
|
389
|
+
if (!operationsFileContents) {
|
|
390
|
+
// `fetch` already warned
|
|
391
|
+
return
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const lockfile = NetlifyGraphLockfile.createLockfile({ operationsFileContents, schemaId })
|
|
395
|
+
writeLockfile({ siteRoot, lockfile })
|
|
396
|
+
updateGraphQLOperationsFileFromPersistedDoc({ ...input, operationsDocString: operationsFileContents })
|
|
326
397
|
}
|
|
327
398
|
|
|
328
399
|
const handleCliSessionEvent = async ({
|
|
@@ -412,12 +483,14 @@ const handleCliSessionEvent = async ({
|
|
|
412
483
|
break
|
|
413
484
|
}
|
|
414
485
|
case 'OneGraphNetlifyCliSessionPersistedLibraryUpdatedEvent':
|
|
415
|
-
await
|
|
486
|
+
await handleOperationsLibraryPersistedEvent({
|
|
416
487
|
netlifyToken,
|
|
417
488
|
docId: payload.docId,
|
|
489
|
+
schemaId: payload.schemaId,
|
|
418
490
|
netlifyGraphConfig,
|
|
419
491
|
schema,
|
|
420
492
|
siteId,
|
|
493
|
+
siteRoot,
|
|
421
494
|
})
|
|
422
495
|
break
|
|
423
496
|
default: {
|
|
@@ -538,6 +611,20 @@ const persistNewOperationsDocForSession = async ({
|
|
|
538
611
|
return
|
|
539
612
|
}
|
|
540
613
|
|
|
614
|
+
const lockfile = readLockfile({ siteRoot })
|
|
615
|
+
|
|
616
|
+
if (!lockfile) {
|
|
617
|
+
warn(
|
|
618
|
+
`can't find a lockfile for the project while running trying to persist operations for session. To pull a remote schema (and create a lockfile), run ${chalk.yellow(
|
|
619
|
+
'netlify graph:pull',
|
|
620
|
+
)} `,
|
|
621
|
+
)
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// NOTE(anmonteiro): We still persist a new operations document because we
|
|
625
|
+
// might be checking out someone else's branch whose session we don't have
|
|
626
|
+
// access to.
|
|
627
|
+
|
|
541
628
|
const { branch } = gitRepoInfo()
|
|
542
629
|
const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
|
|
543
630
|
const persistedResult = await OneGraphClient.executeCreatePersistedQueryMutation(
|
|
@@ -575,6 +662,15 @@ const persistNewOperationsDocForSession = async ({
|
|
|
575
662
|
|
|
576
663
|
if (result.errors) {
|
|
577
664
|
warn(`Unable to update session metadata with updated operations doc ${JSON.stringify(result.errors, null, 2)}`)
|
|
665
|
+
} else if (lockfile != null) {
|
|
666
|
+
// Now that we've persisted the document, lock it in the lockfile
|
|
667
|
+
const currentOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
|
|
668
|
+
|
|
669
|
+
const newLockfile = NetlifyGraphLockfile.createLockfile({
|
|
670
|
+
schemaId: lockfile.locked.schemaId,
|
|
671
|
+
operationsFileContents: currentOperationsDoc,
|
|
672
|
+
})
|
|
673
|
+
writeLockfile({ siteRoot, lockfile: newLockfile })
|
|
578
674
|
}
|
|
579
675
|
}
|
|
580
676
|
|
|
@@ -611,6 +707,7 @@ const startOneGraphCLISession = async (input) => {
|
|
|
611
707
|
site,
|
|
612
708
|
state,
|
|
613
709
|
oneGraphSessionId: input.oneGraphSessionId,
|
|
710
|
+
netlifyGraphConfig,
|
|
614
711
|
})
|
|
615
712
|
|
|
616
713
|
const enabledServices = []
|
|
@@ -718,29 +815,81 @@ const generateSessionName = () => {
|
|
|
718
815
|
return sessionName
|
|
719
816
|
}
|
|
720
817
|
|
|
818
|
+
/**
|
|
819
|
+
* Mark a session as inactive so it doesn't show up in any UI lists, and potentially becomes available to GC later
|
|
820
|
+
* @param {object} input
|
|
821
|
+
* @param {{metadata: {schemaId:string}; id: string; appId: string; name?: string}} input.session The current session
|
|
822
|
+
* @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
|
|
823
|
+
* @param {NetlifyGraphLockfile.V0_format | undefined} input.lockfile A function to call to set/get the current state of the local Netlify project
|
|
824
|
+
*/
|
|
825
|
+
const idempotentlyUpdateSessionSchemaIdFromLockfile = async (input) => {
|
|
826
|
+
const { lockfile, netlifyToken, session } = input
|
|
827
|
+
const sessionSchemaId = session.metadata && session.metadata.schemaId
|
|
828
|
+
const lockfileSchemaId = lockfile && lockfile.locked.schemaId
|
|
829
|
+
|
|
830
|
+
if (lockfileSchemaId != null && sessionSchemaId !== lockfileSchemaId) {
|
|
831
|
+
// Local schema always wins, update the session metadata to reflect that
|
|
832
|
+
const siteId = session.appId
|
|
833
|
+
const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
|
|
834
|
+
|
|
835
|
+
log(`Found new lockfile, overwriting session ${session.name || session.id}`)
|
|
836
|
+
return OneGraphClient.updateCLISessionMetadata(jwt, siteId, session.id, {
|
|
837
|
+
...session.metadata,
|
|
838
|
+
schemaId: lockfileSchemaId,
|
|
839
|
+
})
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
721
843
|
/**
|
|
722
844
|
* Ensures a cli session exists for the current checkout, or errors out if it doesn't and cannot create one.
|
|
845
|
+
* @param {object} input
|
|
846
|
+
* @param {NetlifyGraph.NetlifyGraphConfig} input.netlifyGraphConfig A standalone config object that contains all the information necessary for Netlify Graph to process events
|
|
847
|
+
* @param {object} input.metadata
|
|
848
|
+
* @param {string} input.netlifyToken
|
|
849
|
+
* @param {StateConfig} input.state
|
|
850
|
+
* @param {string} [input.oneGraphSessionId]
|
|
851
|
+
* @param {any} input.site The site object
|
|
723
852
|
*/
|
|
724
853
|
const ensureCLISession = async (input) => {
|
|
725
|
-
const { metadata, netlifyToken, site, state } = input
|
|
854
|
+
const { metadata, netlifyGraphConfig, netlifyToken, site, state } = input
|
|
726
855
|
let oneGraphSessionId = input.oneGraphSessionId ? input.oneGraphSessionId : loadCLISession(state)
|
|
727
856
|
let parentCliSessionId = null
|
|
728
857
|
const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId: site.id, nfToken: netlifyToken })
|
|
729
858
|
|
|
859
|
+
const lockfile = readLockfile({ siteRoot: site.root })
|
|
860
|
+
|
|
730
861
|
// Validate that session still exists and we can access it
|
|
731
862
|
try {
|
|
732
863
|
if (oneGraphSessionId) {
|
|
733
|
-
const
|
|
864
|
+
const { errors, session } = await OneGraphClient.fetchCliSession({
|
|
734
865
|
appId: site.id,
|
|
735
866
|
jwt,
|
|
736
867
|
sessionId: oneGraphSessionId,
|
|
868
|
+
desiredEventCount: 0,
|
|
737
869
|
})
|
|
738
|
-
if (
|
|
739
|
-
warn(`Unable to fetch cli session: ${JSON.stringify(
|
|
870
|
+
if (errors) {
|
|
871
|
+
warn(`Unable to fetch cli session: ${JSON.stringify(errors, null, 2)}`)
|
|
740
872
|
log(`Creating new cli session`)
|
|
741
873
|
parentCliSessionId = oneGraphSessionId
|
|
742
874
|
oneGraphSessionId = null
|
|
743
875
|
}
|
|
876
|
+
|
|
877
|
+
// During the transition to lockfiles, write a lockfile if one isn't
|
|
878
|
+
// found. Later, only handling a 'OneGraphNetlifyCliSessionPersistedLibraryUpdatedEvent'
|
|
879
|
+
// will create or update the lockfile
|
|
880
|
+
// TODO(anmonteiro): remove this in the future?
|
|
881
|
+
if (lockfile == null && session.metadata.schemaId) {
|
|
882
|
+
const currentOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
|
|
883
|
+
log(`Generating Netlify Graph lockfile at ${NetlifyGraphLockfile.defaultLockFileName}`)
|
|
884
|
+
|
|
885
|
+
const newLockfile = NetlifyGraphLockfile.createLockfile({
|
|
886
|
+
schemaId: session.metadata.schemaId,
|
|
887
|
+
operationsFileContents: currentOperationsDoc,
|
|
888
|
+
})
|
|
889
|
+
writeLockfile({ siteRoot: site.root, lockfile: newLockfile })
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
await idempotentlyUpdateSessionSchemaIdFromLockfile({ session, lockfile, netlifyToken })
|
|
744
893
|
}
|
|
745
894
|
} catch (fetchSessionError) {
|
|
746
895
|
warn(`Unable to fetch cli session events: ${JSON.stringify(fetchSessionError, null, 2)}`)
|
|
@@ -752,17 +901,25 @@ const ensureCLISession = async (input) => {
|
|
|
752
901
|
const sessionName = generateSessionName()
|
|
753
902
|
const detectedMetadata = detectLocalCLISessionMetadata({ siteRoot: site.root })
|
|
754
903
|
const newSessionMetadata = parentCliSessionId ? { parentCliSessionId } : {}
|
|
904
|
+
|
|
755
905
|
const sessionMetadata = {
|
|
756
906
|
...detectedMetadata,
|
|
757
907
|
...newSessionMetadata,
|
|
758
908
|
...metadata,
|
|
759
909
|
}
|
|
910
|
+
|
|
911
|
+
if (lockfile != null) {
|
|
912
|
+
log(`Creating new session "${sessionName}" from lockfile`)
|
|
913
|
+
sessionMetadata.schemaId = lockfile.locked.schemaId
|
|
914
|
+
}
|
|
915
|
+
|
|
760
916
|
const oneGraphSession = await createCLISession({
|
|
761
917
|
netlifyToken,
|
|
762
918
|
siteId: site.id,
|
|
763
919
|
sessionName,
|
|
764
920
|
metadata: sessionMetadata,
|
|
765
921
|
})
|
|
922
|
+
|
|
766
923
|
oneGraphSessionId = oneGraphSession.id
|
|
767
924
|
}
|
|
768
925
|
|
|
@@ -808,4 +965,5 @@ module.exports = {
|
|
|
808
965
|
refetchAndGenerateFromOneGraph,
|
|
809
966
|
startOneGraphCLISession,
|
|
810
967
|
upsertMergeCLISessionMetadata,
|
|
968
|
+
readLockfile,
|
|
811
969
|
}
|