@sanity/runtime-cli 9.1.2 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -25
- package/dist/actions/functions/dev.js +1 -1
- package/dist/commands/functions/test.d.ts +1 -0
- package/dist/commands/functions/test.js +13 -1
- package/dist/cores/functions/test.d.ts +1 -0
- package/dist/cores/functions/test.js +19 -5
- package/dist/server/app.d.ts +7 -1
- package/dist/server/app.js +51 -1
- package/dist/server/static/api.d.ts +6 -0
- package/dist/server/static/api.js +12 -0
- package/dist/server/static/components/api-base.d.ts +5 -0
- package/dist/server/static/components/fetch-button.d.ts +7 -0
- package/dist/server/static/components/fetch-button.js +80 -0
- package/dist/server/static/components/filters.js +13 -1
- package/dist/server/static/components/help-button.d.ts +3 -0
- package/dist/server/static/components/help-button.js +59 -0
- package/dist/server/static/components/payload-panel.js +20 -1
- package/dist/server/static/index.html +2 -0
- package/dist/utils/functions/fetch-document.d.ts +2 -0
- package/dist/utils/functions/fetch-document.js +9 -0
- package/oclif.manifest.json +25 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ $ npm install -g @sanity/runtime-cli
|
|
|
20
20
|
$ sanity-run COMMAND
|
|
21
21
|
running command...
|
|
22
22
|
$ sanity-run (--version)
|
|
23
|
-
@sanity/runtime-cli/
|
|
23
|
+
@sanity/runtime-cli/10.0.0 linux-x64 node-v22.17.0
|
|
24
24
|
$ sanity-run --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ sanity-run COMMAND
|
|
@@ -86,7 +86,7 @@ EXAMPLES
|
|
|
86
86
|
$ sanity-run blueprints add function --name my-function --fn-type document-publish --lang js
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
_See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
89
|
+
_See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/blueprints/add.ts)_
|
|
90
90
|
|
|
91
91
|
## `sanity-run blueprints config`
|
|
92
92
|
|
|
@@ -117,7 +117,7 @@ EXAMPLES
|
|
|
117
117
|
$ sanity-run blueprints config --edit --project-id <projectId> --stack-id <stackId>
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
_See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
120
|
+
_See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/blueprints/config.ts)_
|
|
121
121
|
|
|
122
122
|
## `sanity-run blueprints deploy`
|
|
123
123
|
|
|
@@ -139,7 +139,7 @@ EXAMPLES
|
|
|
139
139
|
$ sanity-run blueprints deploy --no-wait
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
142
|
+
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/blueprints/deploy.ts)_
|
|
143
143
|
|
|
144
144
|
## `sanity-run blueprints destroy`
|
|
145
145
|
|
|
@@ -164,7 +164,7 @@ EXAMPLES
|
|
|
164
164
|
$ sanity-run blueprints destroy --stack-id <stackId> --project-id <projectId> --force --no-wait
|
|
165
165
|
```
|
|
166
166
|
|
|
167
|
-
_See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
167
|
+
_See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/blueprints/destroy.ts)_
|
|
168
168
|
|
|
169
169
|
## `sanity-run blueprints info`
|
|
170
170
|
|
|
@@ -186,7 +186,7 @@ EXAMPLES
|
|
|
186
186
|
$ sanity-run blueprints info --stack-id <stackId>
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
-
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
189
|
+
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/blueprints/info.ts)_
|
|
190
190
|
|
|
191
191
|
## `sanity-run blueprints init [DIR]`
|
|
192
192
|
|
|
@@ -224,7 +224,7 @@ EXAMPLES
|
|
|
224
224
|
$ sanity-run blueprints init --blueprint-type <json|js|ts> --stack-name <stackName>
|
|
225
225
|
```
|
|
226
226
|
|
|
227
|
-
_See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
227
|
+
_See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/blueprints/init.ts)_
|
|
228
228
|
|
|
229
229
|
## `sanity-run blueprints logs`
|
|
230
230
|
|
|
@@ -246,7 +246,7 @@ EXAMPLES
|
|
|
246
246
|
$ sanity-run blueprints logs --watch
|
|
247
247
|
```
|
|
248
248
|
|
|
249
|
-
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
249
|
+
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/blueprints/logs.ts)_
|
|
250
250
|
|
|
251
251
|
## `sanity-run blueprints plan`
|
|
252
252
|
|
|
@@ -263,7 +263,7 @@ EXAMPLES
|
|
|
263
263
|
$ sanity-run blueprints plan
|
|
264
264
|
```
|
|
265
265
|
|
|
266
|
-
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
266
|
+
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/blueprints/plan.ts)_
|
|
267
267
|
|
|
268
268
|
## `sanity-run blueprints stacks`
|
|
269
269
|
|
|
@@ -285,7 +285,7 @@ EXAMPLES
|
|
|
285
285
|
$ sanity-run blueprints stacks --project-id <projectId>
|
|
286
286
|
```
|
|
287
287
|
|
|
288
|
-
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
288
|
+
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/blueprints/stacks.ts)_
|
|
289
289
|
|
|
290
290
|
## `sanity-run functions dev`
|
|
291
291
|
|
|
@@ -305,7 +305,7 @@ EXAMPLES
|
|
|
305
305
|
$ sanity-run functions dev --port 8974
|
|
306
306
|
```
|
|
307
307
|
|
|
308
|
-
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
308
|
+
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/functions/dev.ts)_
|
|
309
309
|
|
|
310
310
|
## `sanity-run functions env add NAME KEY VALUE`
|
|
311
311
|
|
|
@@ -327,7 +327,7 @@ EXAMPLES
|
|
|
327
327
|
$ sanity-run functions env add MyFunction API_URL https://api.example.com/
|
|
328
328
|
```
|
|
329
329
|
|
|
330
|
-
_See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
330
|
+
_See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/functions/env/add.ts)_
|
|
331
331
|
|
|
332
332
|
## `sanity-run functions env list NAME`
|
|
333
333
|
|
|
@@ -347,7 +347,7 @@ EXAMPLES
|
|
|
347
347
|
$ sanity-run functions env list MyFunction
|
|
348
348
|
```
|
|
349
349
|
|
|
350
|
-
_See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
350
|
+
_See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/functions/env/list.ts)_
|
|
351
351
|
|
|
352
352
|
## `sanity-run functions env remove NAME KEY`
|
|
353
353
|
|
|
@@ -368,7 +368,7 @@ EXAMPLES
|
|
|
368
368
|
$ sanity-run functions env remove MyFunction API_URL
|
|
369
369
|
```
|
|
370
370
|
|
|
371
|
-
_See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
371
|
+
_See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/functions/env/remove.ts)_
|
|
372
372
|
|
|
373
373
|
## `sanity-run functions logs NAME`
|
|
374
374
|
|
|
@@ -402,7 +402,7 @@ EXAMPLES
|
|
|
402
402
|
$ sanity-run functions logs <name> --delete
|
|
403
403
|
```
|
|
404
404
|
|
|
405
|
-
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
405
|
+
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/functions/logs.ts)_
|
|
406
406
|
|
|
407
407
|
## `sanity-run functions test NAME`
|
|
408
408
|
|
|
@@ -410,20 +410,21 @@ Invoke a local Sanity Function
|
|
|
410
410
|
|
|
411
411
|
```
|
|
412
412
|
USAGE
|
|
413
|
-
$ sanity-run functions test NAME [-d <value>
|
|
414
|
-
[--project-id <value>] [--with-user-token]
|
|
413
|
+
$ sanity-run functions test NAME [-d <value> | -f <value> | --document-id <value>] [-t <value>] [-a <value>]
|
|
414
|
+
[--dataset <value>] [--project-id <value>] [--with-user-token]
|
|
415
415
|
|
|
416
416
|
ARGUMENTS
|
|
417
417
|
NAME The name of the Sanity Function
|
|
418
418
|
|
|
419
419
|
FLAGS
|
|
420
|
-
-a, --api=<value>
|
|
421
|
-
-d, --data=<value>
|
|
422
|
-
-f, --file=<value>
|
|
423
|
-
-t, --timeout=<value>
|
|
424
|
-
--dataset=<value>
|
|
425
|
-
--
|
|
426
|
-
--
|
|
420
|
+
-a, --api=<value> Sanity API Version to use
|
|
421
|
+
-d, --data=<value> Data to send to the function
|
|
422
|
+
-f, --file=<value> Read data from file and send to the function
|
|
423
|
+
-t, --timeout=<value> Execution timeout value in seconds
|
|
424
|
+
--dataset=<value> The Sanity dataset to use
|
|
425
|
+
--document-id=<value> Document to fetch and send to function
|
|
426
|
+
--project-id=<value> Sanity Project ID to use
|
|
427
|
+
--with-user-token Prime access token from CLI config
|
|
427
428
|
|
|
428
429
|
DESCRIPTION
|
|
429
430
|
Invoke a local Sanity Function
|
|
@@ -436,7 +437,7 @@ EXAMPLES
|
|
|
436
437
|
$ sanity-run functions test <name> --data '{ "id": 1 }' --timeout 60
|
|
437
438
|
```
|
|
438
439
|
|
|
439
|
-
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/
|
|
440
|
+
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v10.0.0/src/commands/functions/test.ts)_
|
|
440
441
|
|
|
441
442
|
## `sanity-run help [COMMAND]`
|
|
442
443
|
|
|
@@ -12,6 +12,7 @@ export default class TestCommand extends BlueprintCommand<typeof TestCommand> {
|
|
|
12
12
|
api: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
13
|
dataset: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
14
|
'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
'document-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
16
|
'with-user-token': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
17
|
};
|
|
17
18
|
run(): Promise<void>;
|
|
@@ -12,10 +12,16 @@ export default class TestCommand extends BlueprintCommand {
|
|
|
12
12
|
`<%= config.bin %> <%= command.id %> <name> --data '{ "id": 1 }' --timeout 60`,
|
|
13
13
|
];
|
|
14
14
|
static flags = {
|
|
15
|
-
data: Flags.string({
|
|
15
|
+
data: Flags.string({
|
|
16
|
+
char: 'd',
|
|
17
|
+
description: 'Data to send to the function',
|
|
18
|
+
exclusive: ['file', 'document-id'],
|
|
19
|
+
required: false,
|
|
20
|
+
}),
|
|
16
21
|
file: Flags.string({
|
|
17
22
|
char: 'f',
|
|
18
23
|
description: 'Read data from file and send to the function',
|
|
24
|
+
exclusive: ['data', 'document-id'],
|
|
19
25
|
required: false,
|
|
20
26
|
}),
|
|
21
27
|
timeout: Flags.integer({
|
|
@@ -37,6 +43,12 @@ export default class TestCommand extends BlueprintCommand {
|
|
|
37
43
|
aliases: ['project', 'projectId'],
|
|
38
44
|
required: false,
|
|
39
45
|
}),
|
|
46
|
+
'document-id': Flags.string({
|
|
47
|
+
description: 'Document to fetch and send to function',
|
|
48
|
+
aliases: ['doc', 'documentId'],
|
|
49
|
+
exclusive: ['data', 'file'],
|
|
50
|
+
required: false,
|
|
51
|
+
}),
|
|
40
52
|
'with-user-token': Flags.boolean({
|
|
41
53
|
description: 'Prime access token from CLI config',
|
|
42
54
|
default: false,
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
1
2
|
import { testAction } from '../../actions/functions/test.js';
|
|
2
3
|
import config from '../../config.js';
|
|
3
4
|
import buildPayload from '../../utils/build-payload.js';
|
|
4
5
|
import { findFunctionByName } from '../../utils/find-function.js';
|
|
6
|
+
import { fetchDocument } from '../../utils/functions/fetch-document.js';
|
|
5
7
|
export async function functionTestCore(options) {
|
|
6
8
|
const { blueprint, log, args, flags } = options;
|
|
7
9
|
const { name: fnName } = args;
|
|
8
|
-
const { data, file, timeout, api, dataset, 'with-user-token': withUserToken } = flags;
|
|
10
|
+
const { data, file, timeout, api, dataset, 'document-id': documentId, 'with-user-token': withUserToken, } = flags;
|
|
9
11
|
let { 'project-id': projectId } = flags;
|
|
10
12
|
const { parsedBlueprint } = blueprint;
|
|
11
13
|
if (!projectId && blueprint?.projectId) {
|
|
@@ -13,10 +15,6 @@ export async function functionTestCore(options) {
|
|
|
13
15
|
}
|
|
14
16
|
try {
|
|
15
17
|
const resource = findFunctionByName(parsedBlueprint, fnName); // throws if not found
|
|
16
|
-
const invokeOptions = {
|
|
17
|
-
payload: buildPayload({ data, file }),
|
|
18
|
-
timeout: timeout ? timeout : resource.timeout,
|
|
19
|
-
};
|
|
20
18
|
const contextOptions = {
|
|
21
19
|
clientOptions: {
|
|
22
20
|
apiVersion: api,
|
|
@@ -28,13 +26,29 @@ export async function functionTestCore(options) {
|
|
|
28
26
|
if (withUserToken) {
|
|
29
27
|
contextOptions.clientOptions.token = config.token || undefined;
|
|
30
28
|
}
|
|
29
|
+
const payload = documentId
|
|
30
|
+
? await fetchDocument(documentId, {
|
|
31
|
+
projectId,
|
|
32
|
+
dataset,
|
|
33
|
+
apiVersion: api,
|
|
34
|
+
apiHost: config.apiUrl,
|
|
35
|
+
token: config.token || undefined,
|
|
36
|
+
})
|
|
37
|
+
: buildPayload({ data, file });
|
|
38
|
+
const invokeOptions = {
|
|
39
|
+
payload,
|
|
40
|
+
timeout: timeout ? timeout : resource.timeout,
|
|
41
|
+
};
|
|
42
|
+
const spinner = ora('Executing function...').start();
|
|
31
43
|
const { json, logs, error } = await testAction(resource, invokeOptions, contextOptions);
|
|
32
44
|
if (error) {
|
|
45
|
+
spinner.fail('Function execution failed.');
|
|
33
46
|
return {
|
|
34
47
|
success: false,
|
|
35
48
|
error: error.toString(),
|
|
36
49
|
};
|
|
37
50
|
}
|
|
51
|
+
spinner.succeed('Function execution succeeded.');
|
|
38
52
|
log('Logs:');
|
|
39
53
|
log(logs || '');
|
|
40
54
|
if (json) {
|
package/dist/server/app.d.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
declare const app: (port: number) => void;
|
|
2
|
-
|
|
2
|
+
declare function parseDocumentUrl(url: string): {
|
|
3
|
+
projectId: string;
|
|
4
|
+
dataset: string;
|
|
5
|
+
docId: string;
|
|
6
|
+
} | null;
|
|
7
|
+
declare function buildApiUrl(projectId: string, dataset: string, docId: string, apiUrl: string): string;
|
|
8
|
+
export { app, parseDocumentUrl, buildApiUrl };
|
package/dist/server/app.js
CHANGED
|
@@ -112,6 +112,36 @@ const app = (port) => {
|
|
|
112
112
|
}
|
|
113
113
|
break;
|
|
114
114
|
}
|
|
115
|
+
case req.url?.startsWith('/document'): {
|
|
116
|
+
const url = req.url || '';
|
|
117
|
+
const parsed = parseDocumentUrl(url);
|
|
118
|
+
if (parsed) {
|
|
119
|
+
const { projectId, dataset, docId } = parsed;
|
|
120
|
+
res.setHeader('Content-Type', 'application/json');
|
|
121
|
+
try {
|
|
122
|
+
let json = {};
|
|
123
|
+
const url = buildApiUrl(projectId, dataset, docId, config.apiUrl);
|
|
124
|
+
if (docId) {
|
|
125
|
+
const response = await fetch(url, {
|
|
126
|
+
headers: {
|
|
127
|
+
Authorization: `Bearer ${config.token}`,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
const queryResponse = await response.json();
|
|
131
|
+
if (queryResponse?.result[0]) {
|
|
132
|
+
json = queryResponse?.result[0];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
res.writeHead(200);
|
|
136
|
+
res.end(JSON.stringify(json));
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
res.writeHead(200);
|
|
140
|
+
res.end(JSON.stringify([]));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
115
145
|
default: {
|
|
116
146
|
const requestPath = req.url?.endsWith('/') ? `${req.url}index.html` : req.url;
|
|
117
147
|
const filePath = new URL(`./static${requestPath}`, import.meta.url).pathname;
|
|
@@ -141,6 +171,26 @@ const app = (port) => {
|
|
|
141
171
|
});
|
|
142
172
|
});
|
|
143
173
|
};
|
|
174
|
+
// Helper function to test URL parsing and document fetching logic
|
|
175
|
+
function parseDocumentUrl(url) {
|
|
176
|
+
const matches = url.match(/[?&]project=([^&]+).*?[&]dataset=([^&]+).*?[&]doc=([^&]+)/) || [];
|
|
177
|
+
if (matches && matches.length === 4) {
|
|
178
|
+
const [, projectId, dataset, docId] = matches;
|
|
179
|
+
// Ensure all parameters are present and non-empty
|
|
180
|
+
if (projectId && dataset && docId) {
|
|
181
|
+
return { projectId, dataset, docId };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
// Helper function to build expected API URL
|
|
187
|
+
function buildApiUrl(projectId, dataset, docId, apiUrl) {
|
|
188
|
+
const encodedQuery = encodeURIComponent(`*[_id == "${docId}"]`);
|
|
189
|
+
const baseUrl = apiUrl === 'https://api.sanity.io/'
|
|
190
|
+
? `https://${projectId}.api.sanity.io/`
|
|
191
|
+
: `https://${projectId}.api.sanity.work/`;
|
|
192
|
+
return `${baseUrl}v1/data/query/${dataset}?query=${encodedQuery}`;
|
|
193
|
+
}
|
|
144
194
|
function parseInvokeRequest(body) {
|
|
145
195
|
let json;
|
|
146
196
|
try {
|
|
@@ -197,4 +247,4 @@ function parseInvokeRequest(body) {
|
|
|
197
247
|
};
|
|
198
248
|
return { func, data: { context: { ...context, clientOptions }, event } };
|
|
199
249
|
}
|
|
200
|
-
export
|
|
250
|
+
export { app, parseDocumentUrl, buildApiUrl };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export default function API(): {
|
|
2
2
|
blueprint: typeof blueprint;
|
|
3
|
+
document: typeof document;
|
|
3
4
|
invoke: typeof invoke;
|
|
4
5
|
projects: typeof projects;
|
|
5
6
|
datasets: typeof datasets;
|
|
@@ -8,6 +9,11 @@ export default function API(): {
|
|
|
8
9
|
unsubscribe: any;
|
|
9
10
|
};
|
|
10
11
|
declare function blueprint(): void;
|
|
12
|
+
declare function document({ projectId, dataset, docId }: {
|
|
13
|
+
projectId: any;
|
|
14
|
+
dataset: any;
|
|
15
|
+
docId: any;
|
|
16
|
+
}): Promise<void>;
|
|
11
17
|
declare function invoke(payloadText?: string): void;
|
|
12
18
|
declare function projects(): void;
|
|
13
19
|
declare function datasets(selectedProject: any): void;
|
|
@@ -7,6 +7,7 @@ const store = Store()
|
|
|
7
7
|
export default function API() {
|
|
8
8
|
return {
|
|
9
9
|
blueprint,
|
|
10
|
+
document,
|
|
10
11
|
invoke,
|
|
11
12
|
projects,
|
|
12
13
|
datasets,
|
|
@@ -85,6 +86,17 @@ function datasets(selectedProject) {
|
|
|
85
86
|
})
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
function document({projectId, dataset, docId}) {
|
|
90
|
+
return fetch(`/document?project=${projectId}&dataset=${dataset}&doc=${docId}`)
|
|
91
|
+
.then((response) => response.json())
|
|
92
|
+
.then((doc) => {
|
|
93
|
+
store.document = doc
|
|
94
|
+
})
|
|
95
|
+
.catch(() => {
|
|
96
|
+
store.document = {}
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
88
100
|
function getServerTimings(response) {
|
|
89
101
|
const timings = {}
|
|
90
102
|
const serverTiming = response.headers.get('Server-Timing')
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export class ApiBaseElement extends HTMLElement {
|
|
2
2
|
api: {
|
|
3
3
|
blueprint: () => void;
|
|
4
|
+
document: ({ projectId, dataset, docId }: {
|
|
5
|
+
projectId: any;
|
|
6
|
+
dataset: any;
|
|
7
|
+
docId: any;
|
|
8
|
+
}) => Promise<void>;
|
|
4
9
|
invoke: (payloadText?: string) => void;
|
|
5
10
|
projects: () => void;
|
|
6
11
|
datasets: (selectedProject: any) => void;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* globals customElements document */
|
|
2
|
+
import {ApiBaseElement} from './api-base.js'
|
|
3
|
+
|
|
4
|
+
const template = document.createElement('template')
|
|
5
|
+
template.innerHTML = `
|
|
6
|
+
<style>
|
|
7
|
+
button {
|
|
8
|
+
height: 2.5rem;
|
|
9
|
+
width: 2.5rem;
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
padding: 0;
|
|
14
|
+
border: none;
|
|
15
|
+
background: none;
|
|
16
|
+
border: 1px solid light-dark(var(--gray-200), var(--gray-800));
|
|
17
|
+
color: var(--text-color);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
button:hover {
|
|
21
|
+
color: light-dark(var(--gray-950), var(--gray-200));
|
|
22
|
+
background-color: light-dark(var(--gray-50), var(--gray-900));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
button svg {
|
|
26
|
+
width: 1.25rem;
|
|
27
|
+
height: 1.25rem;
|
|
28
|
+
display: block;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
</style>
|
|
32
|
+
<button aria-label="Fetch Document" title="Fetch Document" type="button">
|
|
33
|
+
<svg width="800px" height="800px" viewBox="0 0 21 21" xmlns="http://www.w3.org/2000/svg">
|
|
34
|
+
<g fill="none" fill-rule="evenodd" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" transform="translate(4 2)">
|
|
35
|
+
<path d="m4.5 1.5h-2.00245461c-1.1045695 0-2 .8954305-2 2v10c0 1.1045695.8954305 2 2 2h8.00000001c1.1043778-.000491 1.9997288-.8956223 2.0004909-2l.0019637-8-4-4"/>
|
|
36
|
+
<path d="m9.5 8.586-3 2.914-3-2.914"/>
|
|
37
|
+
<path d="m6.5.5v11"/>
|
|
38
|
+
</g>
|
|
39
|
+
</svg>
|
|
40
|
+
</button>
|
|
41
|
+
`
|
|
42
|
+
|
|
43
|
+
export class FetchButton extends ApiBaseElement {
|
|
44
|
+
constructor() {
|
|
45
|
+
super()
|
|
46
|
+
this.attachShadow({mode: 'open'}).appendChild(template.content.cloneNode(true))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
connectedCallback() {
|
|
50
|
+
this.button = this.shadowRoot.querySelector('button')
|
|
51
|
+
this.addEventListener('click', this.fetchDoc)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
disconnectedCallback() {
|
|
55
|
+
this.removeEventListener('click', this.fetchDoc)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fetchDoc = async () => {
|
|
59
|
+
const docId = document.querySelector('#docid').value.trim()
|
|
60
|
+
|
|
61
|
+
if (docId) {
|
|
62
|
+
const originalContent = this.button.innerHTML
|
|
63
|
+
this.button.innerHTML = '<network-spinner></network-spinner>'
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
await this.api.document({
|
|
67
|
+
projectId: this.api.store.selectedProject,
|
|
68
|
+
dataset: this.api.store.selectedDataset,
|
|
69
|
+
docId,
|
|
70
|
+
})
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.error('Error fetching document:', err)
|
|
73
|
+
} finally {
|
|
74
|
+
this.button.innerHTML = originalContent
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
customElements.define('fetch-button', FetchButton)
|
|
@@ -23,7 +23,7 @@ class FiltersComponent extends HTMLElement {
|
|
|
23
23
|
<fieldset class="mar-t-sm">
|
|
24
24
|
<label class="slab-text">
|
|
25
25
|
<span style="display: block; margin-bottom: var(--space-1);">API Version</span>
|
|
26
|
-
<input name="apiVersion" id="apiversion" style="background: transparent; border-color: light-dark(var(--gray-200), var(--gray-700)); height: 2.5rem;">
|
|
26
|
+
<input name="apiVersion" id="apiversion" style="background: transparent; border-color: light-dark(var(--gray-200), var(--gray-700)); height: 2.5rem; color: light-dark(var(--gray-950), var(--gray-300));">
|
|
27
27
|
</label>
|
|
28
28
|
</fieldset>
|
|
29
29
|
|
|
@@ -32,6 +32,18 @@ class FiltersComponent extends HTMLElement {
|
|
|
32
32
|
<toggle-switch toggle-key="withToken" style="display: flex; height: 2.5rem;"></toggle-switch>
|
|
33
33
|
</fieldset>
|
|
34
34
|
|
|
35
|
+
<fieldset class="mar-t-sm" style="margin-top: 12px !important;">
|
|
36
|
+
<label class="slab-text">
|
|
37
|
+
<span style="display: block; margin-bottom: var(--space-1);">
|
|
38
|
+
<span style="display: flex; align-items: center;">Document ID <help-button></help-button></span>
|
|
39
|
+
</span>
|
|
40
|
+
<div style="display: flex; flex-direction: row; gap: var(--space-2);">
|
|
41
|
+
<input name="docid" id="docid" style="background: transparent; border-color: light-dark(var(--gray-200), var(--gray-700)); height: 2.5rem; color: light-dark(var(--gray-950), var(--gray-300));">
|
|
42
|
+
<fetch-button></fetch-button>
|
|
43
|
+
</div>
|
|
44
|
+
</label>
|
|
45
|
+
</fieldset>
|
|
46
|
+
|
|
35
47
|
</form>
|
|
36
48
|
`
|
|
37
49
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* globals customElements document */
|
|
2
|
+
import {ApiBaseElement} from './api-base.js'
|
|
3
|
+
|
|
4
|
+
const template = document.createElement('template')
|
|
5
|
+
template.innerHTML = `
|
|
6
|
+
<style>
|
|
7
|
+
button {
|
|
8
|
+
anchor-name: --button;
|
|
9
|
+
background-color: transparent;
|
|
10
|
+
border-color: transparent;
|
|
11
|
+
display: flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
}
|
|
14
|
+
div[popover] {
|
|
15
|
+
position-anchor: --button;
|
|
16
|
+
max-width: 15rem;
|
|
17
|
+
left: anchor(left);
|
|
18
|
+
top: anchor(bottom);
|
|
19
|
+
display: block;
|
|
20
|
+
margin: 0;
|
|
21
|
+
opacity: 0;
|
|
22
|
+
transform: scale(0.95);
|
|
23
|
+
transform-origin: top left;
|
|
24
|
+
visibility: hidden;
|
|
25
|
+
transition:
|
|
26
|
+
opacity 500ms,
|
|
27
|
+
transform 500ms,
|
|
28
|
+
visibility 500ms;
|
|
29
|
+
border-width: var(--gutter-border-width);
|
|
30
|
+
border-color: light-dark(var(--gray-200), var(--gray-800));
|
|
31
|
+
border-radius: 0.375rem;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
[popover]:popover-open {
|
|
35
|
+
transform: scale(1);
|
|
36
|
+
opacity: 1;
|
|
37
|
+
visibility: visible;
|
|
38
|
+
}
|
|
39
|
+
</style>
|
|
40
|
+
<button title="Info" popovertarget="popover-el">
|
|
41
|
+
<svg data-sanity-icon="help-circle" width="1em" height="1em" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12.5 13C12.5 11 14 11.5 14 10C14 9.34375 13.5 8.5 12.5 8.5C11.5 8.5 11 9 10.5 9.5M12.5 16V14.5M20.5 12.5C20.5 16.9183 16.9183 20.5 12.5 20.5C8.08172 20.5 4.5 16.9183 4.5 12.5C4.5 8.08172 8.08172 4.5 12.5 4.5C16.9183 4.5 20.5 8.08172 20.5 12.5Z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"></path></svg>
|
|
42
|
+
</button>
|
|
43
|
+
<div popover="" id="popover-el">
|
|
44
|
+
<div style="padding: 0.75rem;">
|
|
45
|
+
<p>Fill out "Document ID" text field and then click the "Fetch Document" button to pre-populate the Document panel.</p>
|
|
46
|
+
<p>The Document panel is an editable text field so you can edit the fetched document or replace it with any JSON data you want.</p>
|
|
47
|
+
<p>When you click the "Run" button the contents of the Document panel will be evaluated against your filter/projection and sent to your function as the event part of the payload.</p>
|
|
48
|
+
<div>
|
|
49
|
+
</div>
|
|
50
|
+
`
|
|
51
|
+
|
|
52
|
+
export class HelpButton extends ApiBaseElement {
|
|
53
|
+
constructor() {
|
|
54
|
+
super()
|
|
55
|
+
this.attachShadow({mode: 'open'}).appendChild(template.content.cloneNode(true))
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
customElements.define('help-button', HelpButton)
|
|
@@ -7,7 +7,7 @@ import {ApiBaseElement} from './api-base.js'
|
|
|
7
7
|
const template = `<div class="gutter-gradient relative h-100 max-h-100 y-scroll border-top border-top-none-l">
|
|
8
8
|
<div class="bg gutter-gradient sticky top-0 right-0 left-0 z-100">
|
|
9
9
|
<div class="flex items-center space-between" style="padding: 8px 20px 8px 48px;">
|
|
10
|
-
<h2 class="config-label mar-t-0 mar-b-0">
|
|
10
|
+
<h2 class="config-label mar-t-0 mar-b-0">Document</h2>
|
|
11
11
|
</div>
|
|
12
12
|
<hr class='hr-border' style='margin-left: 31px; ' />
|
|
13
13
|
</div>
|
|
@@ -15,6 +15,18 @@ const template = `<div class="gutter-gradient relative h-100 max-h-100 y-scroll
|
|
|
15
15
|
</div>
|
|
16
16
|
`
|
|
17
17
|
class PayloadPanel extends ApiBaseElement {
|
|
18
|
+
updatePayload = ({document}) => {
|
|
19
|
+
if (!document) return
|
|
20
|
+
|
|
21
|
+
const transaction = this.api.store.payload.state.update({
|
|
22
|
+
changes: {
|
|
23
|
+
from: 0,
|
|
24
|
+
insert: JSON.stringify(document, null, 2),
|
|
25
|
+
to: this.api.store.payload.state.doc.length,
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
this.api.store.payload.dispatch(transaction)
|
|
29
|
+
}
|
|
18
30
|
connectedCallback() {
|
|
19
31
|
this.innerHTML = template
|
|
20
32
|
this.payload = this.querySelector('#payload')
|
|
@@ -24,6 +36,13 @@ class PayloadPanel extends ApiBaseElement {
|
|
|
24
36
|
extensions: [basicSetup, json(), sanityCodeMirrorTheme],
|
|
25
37
|
parent: this.payload,
|
|
26
38
|
})
|
|
39
|
+
|
|
40
|
+
this.api.subscribe(this.updatePayload, ['document'])
|
|
41
|
+
}
|
|
42
|
+
disconnectedCallback() {
|
|
43
|
+
if (this.api) {
|
|
44
|
+
this.api.unsubscribe(this.updatePayload)
|
|
45
|
+
}
|
|
27
46
|
}
|
|
28
47
|
}
|
|
29
48
|
|
|
@@ -56,6 +56,8 @@
|
|
|
56
56
|
<script src="./components/run-panel.js" type="module"></script>
|
|
57
57
|
<script src="./components/toggle-switch.js" type="module"></script>
|
|
58
58
|
<script src="./components/clear-button.js" type="module"></script>
|
|
59
|
+
<script src="./components/help-button.js" type="module"></script>
|
|
60
|
+
<script src="./components/fetch-button.js" type="module"></script>
|
|
59
61
|
<script src="./hot-reload.js" type="module"></script>
|
|
60
62
|
</body>
|
|
61
63
|
</html>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createClient } from '@sanity/client';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
export async function fetchDocument(documentId, { projectId, dataset, useCdn = true, apiVersion = '2025-02-06', apiHost, token }) {
|
|
4
|
+
const spinner = ora(`Fetching document ID ${documentId}...`).start();
|
|
5
|
+
const client = createClient({ projectId, dataset, useCdn, apiVersion, apiHost, token });
|
|
6
|
+
const data = await client.fetch(`*[_id == "${documentId}"]`);
|
|
7
|
+
spinner.stop();
|
|
8
|
+
return data[0] ? data[0] : undefined;
|
|
9
|
+
}
|
package/oclif.manifest.json
CHANGED
|
@@ -696,6 +696,10 @@
|
|
|
696
696
|
"data": {
|
|
697
697
|
"char": "d",
|
|
698
698
|
"description": "Data to send to the function",
|
|
699
|
+
"exclusive": [
|
|
700
|
+
"file",
|
|
701
|
+
"document-id"
|
|
702
|
+
],
|
|
699
703
|
"name": "data",
|
|
700
704
|
"required": false,
|
|
701
705
|
"hasDynamicHelp": false,
|
|
@@ -705,6 +709,10 @@
|
|
|
705
709
|
"file": {
|
|
706
710
|
"char": "f",
|
|
707
711
|
"description": "Read data from file and send to the function",
|
|
712
|
+
"exclusive": [
|
|
713
|
+
"data",
|
|
714
|
+
"document-id"
|
|
715
|
+
],
|
|
708
716
|
"name": "file",
|
|
709
717
|
"required": false,
|
|
710
718
|
"hasDynamicHelp": false,
|
|
@@ -749,6 +757,22 @@
|
|
|
749
757
|
"multiple": false,
|
|
750
758
|
"type": "option"
|
|
751
759
|
},
|
|
760
|
+
"document-id": {
|
|
761
|
+
"aliases": [
|
|
762
|
+
"doc",
|
|
763
|
+
"documentId"
|
|
764
|
+
],
|
|
765
|
+
"description": "Document to fetch and send to function",
|
|
766
|
+
"exclusive": [
|
|
767
|
+
"data",
|
|
768
|
+
"file"
|
|
769
|
+
],
|
|
770
|
+
"name": "document-id",
|
|
771
|
+
"required": false,
|
|
772
|
+
"hasDynamicHelp": false,
|
|
773
|
+
"multiple": false,
|
|
774
|
+
"type": "option"
|
|
775
|
+
},
|
|
752
776
|
"with-user-token": {
|
|
753
777
|
"description": "Prime access token from CLI config",
|
|
754
778
|
"name": "with-user-token",
|
|
@@ -877,5 +901,5 @@
|
|
|
877
901
|
]
|
|
878
902
|
}
|
|
879
903
|
},
|
|
880
|
-
"version": "
|
|
904
|
+
"version": "10.0.0"
|
|
881
905
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/runtime-cli",
|
|
3
3
|
"description": "Sanity's Runtime CLI for Blueprints and Functions",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "10.0.0",
|
|
5
5
|
"author": "Sanity Runtime Team",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"engines": {
|
|
48
|
-
"node": ">=20.
|
|
48
|
+
"node": ">=20.19"
|
|
49
49
|
},
|
|
50
50
|
"files": [
|
|
51
51
|
"./bin",
|
|
@@ -79,6 +79,7 @@
|
|
|
79
79
|
"@architect/inventory": "^4.0.9",
|
|
80
80
|
"@oclif/core": "^4.3.0",
|
|
81
81
|
"@oclif/plugin-help": "^6.2.28",
|
|
82
|
+
"@sanity/client": "^7.3.0",
|
|
82
83
|
"adm-zip": "^0.5.16",
|
|
83
84
|
"array-treeify": "^0.1.5",
|
|
84
85
|
"cardinal": "^2.1.1",
|
|
@@ -106,7 +107,6 @@
|
|
|
106
107
|
"@playwright/test": "^1.52.0",
|
|
107
108
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
108
109
|
"@sanity/blueprints": "^0.1.0",
|
|
109
|
-
"@sanity/client": "^7.3.0",
|
|
110
110
|
"@sanity/functions": "^1.0.3",
|
|
111
111
|
"@types/adm-zip": "^0.5.7",
|
|
112
112
|
"@types/cardinal": "^2.1.1",
|