@sanity/runtime-cli 4.3.4 → 4.3.5-bundle.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 +17 -17
- package/dist/actions/blueprints/assets.d.ts +1 -0
- package/dist/actions/blueprints/assets.js +21 -4
- package/dist/actions/functions/test.d.ts +2 -2
- package/dist/actions/functions/test.js +2 -2
- package/dist/commands/blueprints/deploy.js +3 -4
- package/dist/commands/functions/test.js +3 -6
- package/dist/server/app.js +80 -12
- package/dist/server/static/api.js +24 -3
- package/dist/server/static/components/app.css +74 -23
- package/dist/server/static/components/filters.js +1 -1
- package/dist/server/static/components/function-list.js +5 -5
- package/dist/server/static/components/payload-panel.js +4 -3
- package/dist/server/static/components/response-panel.js +37 -35
- package/dist/server/static/index.html +5 -3
- package/dist/server/static/vendor/vendor.bundle.d.ts +2 -2
- package/dist/utils/build-payload.d.ts +1 -1
- package/dist/utils/build-payload.js +3 -3
- package/dist/utils/bundle/bundle-function.d.ts +8 -0
- package/dist/utils/bundle/bundle-function.js +125 -0
- package/dist/utils/bundle/cleanup-source-maps.d.ts +10 -0
- package/dist/utils/bundle/cleanup-source-maps.js +53 -0
- package/dist/utils/bundle/find-up.d.ts +16 -0
- package/dist/utils/bundle/find-up.js +39 -0
- package/dist/utils/bundle/verify-handler.d.ts +2 -0
- package/dist/utils/bundle/verify-handler.js +13 -0
- package/dist/utils/child-process-wrapper.js +8 -6
- package/dist/utils/functions/find-entry-point.d.ts +11 -0
- package/dist/utils/functions/find-entry-point.js +75 -0
- package/dist/utils/functions/should-bundle.d.ts +2 -0
- package/dist/utils/functions/should-bundle.js +23 -0
- package/dist/utils/invoke-local.d.ts +2 -2
- package/dist/utils/invoke-local.js +48 -7
- package/dist/utils/is-record.d.ts +1 -0
- package/dist/utils/is-record.js +3 -0
- package/dist/utils/parse-json-object.d.ts +1 -0
- package/dist/utils/parse-json-object.js +10 -0
- package/dist/utils/types.d.ts +3 -1
- package/oclif.manifest.json +1 -1
- package/package.json +4 -1
- package/dist/utils/is-json.d.ts +0 -1
- package/dist/utils/is-json.js +0 -12
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/4.3.
|
|
23
|
+
@sanity/runtime-cli/4.3.5-bundle.0 darwin-arm64 node-v22.14.0
|
|
24
24
|
$ sanity-run --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ sanity-run COMMAND
|
|
@@ -74,7 +74,7 @@ EXAMPLES
|
|
|
74
74
|
$ sanity-run blueprints add function --name my-function --function-type document-publish
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
_See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
77
|
+
_See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/blueprints/add.ts)_
|
|
78
78
|
|
|
79
79
|
## `sanity-run blueprints config`
|
|
80
80
|
|
|
@@ -103,7 +103,7 @@ EXAMPLES
|
|
|
103
103
|
$ sanity-run blueprints config --edit --project-id <projectId> --stack-id <stackId>
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
_See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
106
|
+
_See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/blueprints/config.ts)_
|
|
107
107
|
|
|
108
108
|
## `sanity-run blueprints deploy`
|
|
109
109
|
|
|
@@ -123,7 +123,7 @@ EXAMPLES
|
|
|
123
123
|
$ sanity-run blueprints deploy
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
-
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
126
|
+
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/blueprints/deploy.ts)_
|
|
127
127
|
|
|
128
128
|
## `sanity-run blueprints destroy`
|
|
129
129
|
|
|
@@ -146,7 +146,7 @@ EXAMPLES
|
|
|
146
146
|
$ sanity-run blueprints destroy --id ST-a1b2c3
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
-
_See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
149
|
+
_See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/blueprints/destroy.ts)_
|
|
150
150
|
|
|
151
151
|
## `sanity-run blueprints info`
|
|
152
152
|
|
|
@@ -168,7 +168,7 @@ EXAMPLES
|
|
|
168
168
|
$ sanity-run blueprints info --id ST-a1b2c3
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
-
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
171
|
+
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/blueprints/info.ts)_
|
|
172
172
|
|
|
173
173
|
## `sanity-run blueprints init`
|
|
174
174
|
|
|
@@ -198,7 +198,7 @@ EXAMPLES
|
|
|
198
198
|
$ sanity-run blueprints init --blueprint-type <json|js|ts> --project-id <projectId> --stack-name <stackName>
|
|
199
199
|
```
|
|
200
200
|
|
|
201
|
-
_See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
201
|
+
_See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/blueprints/init.ts)_
|
|
202
202
|
|
|
203
203
|
## `sanity-run blueprints logs`
|
|
204
204
|
|
|
@@ -220,7 +220,7 @@ EXAMPLES
|
|
|
220
220
|
$ sanity-run blueprints logs --watch
|
|
221
221
|
```
|
|
222
222
|
|
|
223
|
-
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
223
|
+
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/blueprints/logs.ts)_
|
|
224
224
|
|
|
225
225
|
## `sanity-run blueprints plan`
|
|
226
226
|
|
|
@@ -237,7 +237,7 @@ EXAMPLES
|
|
|
237
237
|
$ sanity-run blueprints plan
|
|
238
238
|
```
|
|
239
239
|
|
|
240
|
-
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
240
|
+
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/blueprints/plan.ts)_
|
|
241
241
|
|
|
242
242
|
## `sanity-run blueprints stacks`
|
|
243
243
|
|
|
@@ -259,7 +259,7 @@ EXAMPLES
|
|
|
259
259
|
$ sanity-run blueprints stacks --projectId a1b2c3
|
|
260
260
|
```
|
|
261
261
|
|
|
262
|
-
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
262
|
+
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/blueprints/stacks.ts)_
|
|
263
263
|
|
|
264
264
|
## `sanity-run functions dev`
|
|
265
265
|
|
|
@@ -279,7 +279,7 @@ EXAMPLES
|
|
|
279
279
|
$ sanity-run functions dev --port 8974
|
|
280
280
|
```
|
|
281
281
|
|
|
282
|
-
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
282
|
+
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/functions/dev.ts)_
|
|
283
283
|
|
|
284
284
|
## `sanity-run functions env add NAME KEY VALUE`
|
|
285
285
|
|
|
@@ -301,7 +301,7 @@ EXAMPLES
|
|
|
301
301
|
$ sanity-run functions env add MyFunction API_URL https://api.example.com/
|
|
302
302
|
```
|
|
303
303
|
|
|
304
|
-
_See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
304
|
+
_See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/functions/env/add.ts)_
|
|
305
305
|
|
|
306
306
|
## `sanity-run functions env list NAME`
|
|
307
307
|
|
|
@@ -321,7 +321,7 @@ EXAMPLES
|
|
|
321
321
|
$ sanity-run functions env list MyFunction
|
|
322
322
|
```
|
|
323
323
|
|
|
324
|
-
_See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
324
|
+
_See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/functions/env/list.ts)_
|
|
325
325
|
|
|
326
326
|
## `sanity-run functions env remove NAME KEY`
|
|
327
327
|
|
|
@@ -342,7 +342,7 @@ EXAMPLES
|
|
|
342
342
|
$ sanity-run functions env remove MyFunction API_URL
|
|
343
343
|
```
|
|
344
344
|
|
|
345
|
-
_See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
345
|
+
_See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/functions/env/remove.ts)_
|
|
346
346
|
|
|
347
347
|
## `sanity-run functions invoke NAME`
|
|
348
348
|
|
|
@@ -368,7 +368,7 @@ EXAMPLES
|
|
|
368
368
|
$ sanity-run functions invoke <name> --file 'payload.json'
|
|
369
369
|
```
|
|
370
370
|
|
|
371
|
-
_See code: [src/commands/functions/invoke.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
371
|
+
_See code: [src/commands/functions/invoke.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/functions/invoke.ts)_
|
|
372
372
|
|
|
373
373
|
## `sanity-run functions logs NAME`
|
|
374
374
|
|
|
@@ -400,7 +400,7 @@ EXAMPLES
|
|
|
400
400
|
$ sanity-run functions logs <name> --delete
|
|
401
401
|
```
|
|
402
402
|
|
|
403
|
-
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
403
|
+
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/functions/logs.ts)_
|
|
404
404
|
|
|
405
405
|
## `sanity-run functions test NAME`
|
|
406
406
|
|
|
@@ -433,7 +433,7 @@ EXAMPLES
|
|
|
433
433
|
$ sanity-run functions test <name> --data '{ "id": 1 }' --timeout 60
|
|
434
434
|
```
|
|
435
435
|
|
|
436
|
-
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.
|
|
436
|
+
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v4.3.5-bundle.0/src/commands/functions/test.ts)_
|
|
437
437
|
|
|
438
438
|
## `sanity-run help [COMMAND]`
|
|
439
439
|
|
|
@@ -3,21 +3,35 @@ import path from 'node:path';
|
|
|
3
3
|
import { cwd } from 'node:process';
|
|
4
4
|
import AdmZip from 'adm-zip';
|
|
5
5
|
import config from '../../config.js';
|
|
6
|
+
import { bundleFunction } from '../../utils/bundle/bundle-function.js';
|
|
7
|
+
import { shouldBundleFunction } from '../../utils/functions/should-bundle.js';
|
|
6
8
|
import getHeaders from '../../utils/get-headers.js';
|
|
7
9
|
const { apiUrl } = config;
|
|
8
10
|
export const stashUrl = `${apiUrl}vX/blueprints/assets/stash`;
|
|
9
11
|
export async function stashAsset({ resource, auth, }) {
|
|
10
12
|
if (!resource.src)
|
|
11
13
|
throw new Error('Resource src is required');
|
|
14
|
+
let functionPath = path.join(cwd(), resource.src);
|
|
15
|
+
let cleanup = async () => { };
|
|
16
|
+
const shouldBundle = await shouldBundleFunction(resource);
|
|
17
|
+
if (shouldBundle) {
|
|
18
|
+
try {
|
|
19
|
+
const result = await bundleFunction(resource);
|
|
20
|
+
functionPath = result.outputDir;
|
|
21
|
+
cleanup = result.cleanup;
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
return { success: false, error: err instanceof Error ? err.message : `${err}` };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
12
27
|
try {
|
|
13
|
-
const
|
|
14
|
-
const stats = await fs.promises.stat(sourcePath);
|
|
28
|
+
const stats = await fs.promises.stat(functionPath);
|
|
15
29
|
const zip = new AdmZip();
|
|
16
30
|
if (stats.isDirectory()) {
|
|
17
|
-
zip.addLocalFolder(
|
|
31
|
+
zip.addLocalFolder(functionPath);
|
|
18
32
|
}
|
|
19
33
|
else {
|
|
20
|
-
zip.addLocalFile(
|
|
34
|
+
zip.addLocalFile(functionPath, '', 'index.js');
|
|
21
35
|
}
|
|
22
36
|
const zipBuffer = zip.toBuffer();
|
|
23
37
|
const base64Zip = zipBuffer.toString('base64');
|
|
@@ -41,4 +55,7 @@ export async function stashAsset({ resource, auth, }) {
|
|
|
41
55
|
error = err.message;
|
|
42
56
|
return { success: false, error };
|
|
43
57
|
}
|
|
58
|
+
finally {
|
|
59
|
+
await cleanup();
|
|
60
|
+
}
|
|
44
61
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { InvocationResponse, InvokeContextOptions, InvokePayloadOptions } from '../../utils/types.js';
|
|
2
|
-
export declare function testAction(
|
|
1
|
+
import type { InvocationResponse, InvokeContextOptions, InvokePayloadOptions, LocalFunctionResource } from '../../utils/types.js';
|
|
2
|
+
export declare function testAction(resource: LocalFunctionResource, options: InvokePayloadOptions, context: InvokeContextOptions): Promise<InvocationResponse>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import buildPayload from '../../utils/build-payload.js';
|
|
2
2
|
import invoke from '../../utils/invoke-local.js';
|
|
3
|
-
export async function testAction(
|
|
3
|
+
export async function testAction(resource, options, context) {
|
|
4
4
|
const payload = buildPayload(options);
|
|
5
5
|
const { timeout } = options;
|
|
6
6
|
try {
|
|
7
|
-
const { json, logs } = await invoke(
|
|
7
|
+
const { json, logs } = await invoke(resource, payload, context, timeout);
|
|
8
8
|
return { error: undefined, json, logs };
|
|
9
9
|
}
|
|
10
10
|
catch (error) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { setTimeout } from 'node:timers/promises';
|
|
2
|
+
import { inspect } from 'node:util';
|
|
2
3
|
import { Command, Flags } from '@oclif/core';
|
|
3
4
|
import Spinner from 'yocto-spinner';
|
|
4
5
|
import { stashAsset } from '../../actions/blueprints/assets.js';
|
|
@@ -24,9 +25,7 @@ export default class Deploy extends Command {
|
|
|
24
25
|
const { errors, projectId, stackId, parsedBlueprint: { resources }, deployedStack, } = await readBlueprintOnDisk({ getStack: true, token });
|
|
25
26
|
if (errors.length > 0) {
|
|
26
27
|
// printErrors(errors) // TODO: error printer in formatting
|
|
27
|
-
this.
|
|
28
|
-
console.dir(errors, { depth: null });
|
|
29
|
-
return;
|
|
28
|
+
this.error(`Blueprint parse errors:\n${inspect(errors, { depth: null })}`);
|
|
30
29
|
}
|
|
31
30
|
if (!deployedStack || !stackId || !projectId) {
|
|
32
31
|
this.error('Before deploying, run `sanity blueprints init`');
|
|
@@ -96,7 +95,7 @@ export default class Deploy extends Command {
|
|
|
96
95
|
}
|
|
97
96
|
else {
|
|
98
97
|
this.debug('STACK ERROR RESPONSE:', stack);
|
|
99
|
-
spinner.error(`${red('Failed')} to
|
|
98
|
+
spinner.error(`${red('Failed')} to update stack`);
|
|
100
99
|
this.log(`Error: ${deployError || JSON.stringify(stack, null, 2) || 'Unknown error'}`);
|
|
101
100
|
}
|
|
102
101
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
2
|
import { readBlueprintOnDisk } from '../../actions/blueprints/blueprint.js';
|
|
3
3
|
import { testAction } from '../../actions/functions/test.js';
|
|
4
|
-
import {
|
|
4
|
+
import { findFunctionByName } from '../../utils/find-function.js';
|
|
5
5
|
export default class Test extends Command {
|
|
6
6
|
static args = {
|
|
7
7
|
name: Args.string({ description: 'The name of the Sanity Function', required: true }),
|
|
@@ -42,11 +42,8 @@ export default class Test extends Command {
|
|
|
42
42
|
const { args, flags } = await this.parse(Test);
|
|
43
43
|
const { parsedBlueprint } = await readBlueprintOnDisk({ getStack: false });
|
|
44
44
|
try {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
this.error(`Error: Function ${args.name} has no source code`);
|
|
48
|
-
}
|
|
49
|
-
const { json, logs, error } = await testAction(src, {
|
|
45
|
+
const resource = findFunctionByName(parsedBlueprint, args.name);
|
|
46
|
+
const { json, logs, error } = await testAction(resource, {
|
|
50
47
|
data: flags.data,
|
|
51
48
|
file: flags.file,
|
|
52
49
|
timeout: flags.timeout,
|
package/dist/server/app.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import * as http from 'node:http';
|
|
2
3
|
import { default as mime } from 'mime-types';
|
|
3
4
|
import { readBlueprintOnDisk } from '../actions/blueprints/blueprint.js';
|
|
4
5
|
import config from '../config.js';
|
|
6
|
+
import { findFunctionByName } from '../utils/find-function.js';
|
|
5
7
|
import invoke from '../utils/invoke-local.js';
|
|
6
|
-
import
|
|
8
|
+
import { isRecord } from '../utils/is-record.js';
|
|
7
9
|
const host = 'localhost';
|
|
8
10
|
const app = (port) => {
|
|
9
11
|
const requestListener = async (req, res) => {
|
|
@@ -14,30 +16,40 @@ const app = (port) => {
|
|
|
14
16
|
const { parsedBlueprint } = await readBlueprintOnDisk({ getStack: false });
|
|
15
17
|
res.setHeader('Content-Type', 'application/json');
|
|
16
18
|
res.writeHead(200);
|
|
17
|
-
res.end(JSON.stringify(parsedBlueprint));
|
|
19
|
+
res.end(JSON.stringify(parsedBlueprint)); // Use parsedBlueprint directly
|
|
18
20
|
}
|
|
19
|
-
catch {
|
|
21
|
+
catch (error) {
|
|
20
22
|
res.writeHead(404);
|
|
21
|
-
res.end();
|
|
23
|
+
res.end(JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }));
|
|
22
24
|
}
|
|
23
25
|
break;
|
|
24
26
|
}
|
|
25
27
|
case req.url === '/invoke': {
|
|
26
28
|
if (req.method === 'POST') {
|
|
27
|
-
|
|
28
|
-
req.on('data', (data) =>
|
|
29
|
-
body += data;
|
|
30
|
-
});
|
|
29
|
+
const body = [];
|
|
30
|
+
req.on('data', (data) => body.push(data));
|
|
31
31
|
req.on('end', async () => {
|
|
32
|
-
const { data, func } = JSON.parse(body);
|
|
33
|
-
const { context, event } = data;
|
|
34
32
|
res.setHeader('Content-Type', 'application/json');
|
|
35
33
|
try {
|
|
36
|
-
const
|
|
37
|
-
|
|
34
|
+
const { data, func: functionName } = parseInvokeRequest(Buffer.concat(body));
|
|
35
|
+
const { context, event } = data;
|
|
36
|
+
const start = performance.now();
|
|
37
|
+
const { parsedBlueprint } = await readBlueprintOnDisk({ getStack: false });
|
|
38
|
+
const resource = findFunctionByName(parsedBlueprint, functionName);
|
|
39
|
+
const readBlueprintTime = performance.now() - start;
|
|
40
|
+
const response = await invoke(resource, event, context);
|
|
41
|
+
const timings = { ...response.timings, 'blueprint:read': readBlueprintTime };
|
|
42
|
+
const timingHeaders = [];
|
|
43
|
+
for (const [key, value] of Object.entries(timings)) {
|
|
44
|
+
timingHeaders.push(`${key.replace(/:/g, '-')};dur=${Math.abs(value).toFixed(1)}`);
|
|
45
|
+
}
|
|
46
|
+
if (timingHeaders.length > 0) {
|
|
47
|
+
res.setHeader('Server-Timing', timingHeaders.join(', '));
|
|
48
|
+
}
|
|
38
49
|
res.end(JSON.stringify(response));
|
|
39
50
|
}
|
|
40
51
|
catch (error) {
|
|
52
|
+
console.error(error);
|
|
41
53
|
const response = { logs: '', error: '' };
|
|
42
54
|
if (error instanceof Error) {
|
|
43
55
|
response.logs = error.message;
|
|
@@ -112,4 +124,60 @@ const app = (port) => {
|
|
|
112
124
|
const server = http.createServer(requestListener);
|
|
113
125
|
server.listen(port, host, () => { });
|
|
114
126
|
};
|
|
127
|
+
function parseInvokeRequest(body) {
|
|
128
|
+
let json;
|
|
129
|
+
try {
|
|
130
|
+
json = JSON.parse(body.toString('utf8'));
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
throw new Error('Request body is not valid JSON', { cause: error });
|
|
134
|
+
}
|
|
135
|
+
if (!isRecord(json)) {
|
|
136
|
+
throw new Error('Request body is not valid, must be an object');
|
|
137
|
+
}
|
|
138
|
+
if (!('func' in json)) {
|
|
139
|
+
throw new Error('Request body is not valid, missing `func` field');
|
|
140
|
+
}
|
|
141
|
+
if (!('data' in json)) {
|
|
142
|
+
throw new Error('Request body is not valid, missing `data` field');
|
|
143
|
+
}
|
|
144
|
+
const { data, func } = json;
|
|
145
|
+
if (typeof func !== 'string') {
|
|
146
|
+
throw new Error('Request body is not valid, `func` field is not a string');
|
|
147
|
+
}
|
|
148
|
+
if (!isRecord(data)) {
|
|
149
|
+
throw new Error('Request body is not valid, `data` field is not an object');
|
|
150
|
+
}
|
|
151
|
+
const { context, event } = data;
|
|
152
|
+
if (!isRecord(context)) {
|
|
153
|
+
throw new Error('Request body is not valid, `context` field is not an object');
|
|
154
|
+
}
|
|
155
|
+
if (!isRecord(event)) {
|
|
156
|
+
throw new Error('Request body is not valid, `event` field is not an object');
|
|
157
|
+
}
|
|
158
|
+
if (!('clientOptions' in context)) {
|
|
159
|
+
throw new Error('Request body is not valid, `context.clientOptions` field is missing');
|
|
160
|
+
}
|
|
161
|
+
if (!isRecord(context.clientOptions)) {
|
|
162
|
+
throw new Error('Request body is not valid, `context.clientOptions` field is not an object');
|
|
163
|
+
}
|
|
164
|
+
const { projectId, dataset, apiVersion } = context.clientOptions;
|
|
165
|
+
if (typeof projectId !== 'string' && typeof projectId !== 'undefined') {
|
|
166
|
+
throw new Error('Request body is not valid, `context.clientOptions.projectId` field is not a string');
|
|
167
|
+
}
|
|
168
|
+
if (typeof dataset !== 'string' && typeof dataset !== 'undefined') {
|
|
169
|
+
throw new Error('Request body is not valid, `context.clientOptions.dataset` field is not a string');
|
|
170
|
+
}
|
|
171
|
+
if (typeof apiVersion !== 'string' && typeof apiVersion !== 'undefined') {
|
|
172
|
+
throw new Error('Request body is not valid, `context.clientOptions.apiVersion` field is not a string');
|
|
173
|
+
}
|
|
174
|
+
const clientOptions = {
|
|
175
|
+
...context.clientOptions,
|
|
176
|
+
projectId,
|
|
177
|
+
dataset,
|
|
178
|
+
// Prefer `undefined` over empty string, triggering the right warnings in the client
|
|
179
|
+
apiVersion: apiVersion || undefined,
|
|
180
|
+
};
|
|
181
|
+
return { func, data: { context: { ...context, clientOptions }, event } };
|
|
182
|
+
}
|
|
115
183
|
export default app;
|
|
@@ -30,12 +30,15 @@ function invoke(payloadText = '{}') {
|
|
|
30
30
|
},
|
|
31
31
|
method: 'POST',
|
|
32
32
|
})
|
|
33
|
-
.then((response) =>
|
|
34
|
-
|
|
33
|
+
.then((response) => {
|
|
34
|
+
return response.json().then((data) => ({data, timings: getServerTimings(response)}))
|
|
35
|
+
})
|
|
36
|
+
.then(({data, timings}) => {
|
|
35
37
|
store.inprogress = false
|
|
36
38
|
store.result = {
|
|
37
39
|
...data,
|
|
38
40
|
time: Date.now() - start,
|
|
41
|
+
timings,
|
|
39
42
|
}
|
|
40
43
|
})
|
|
41
44
|
}
|
|
@@ -47,7 +50,7 @@ function blueprint() {
|
|
|
47
50
|
const functions = blueprint?.resources.filter((r) => r.type.startsWith('sanity.function.'))
|
|
48
51
|
|
|
49
52
|
store.functions = functions
|
|
50
|
-
store.selectedIndex = functions[0].
|
|
53
|
+
store.selectedIndex = functions[0].name
|
|
51
54
|
})
|
|
52
55
|
.catch(() => {
|
|
53
56
|
store.functions = []
|
|
@@ -77,3 +80,21 @@ function datasets(selectedProject) {
|
|
|
77
80
|
store.datasets = []
|
|
78
81
|
})
|
|
79
82
|
}
|
|
83
|
+
|
|
84
|
+
function getServerTimings(response) {
|
|
85
|
+
const timings = {}
|
|
86
|
+
const serverTiming = response.headers.get('Server-Timing')
|
|
87
|
+
if (!serverTiming) {
|
|
88
|
+
return timings
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const entry of serverTiming.split(',')) {
|
|
92
|
+
const [name, ...params] = entry.split(';')
|
|
93
|
+
const durationParam = params.find((p) => p.startsWith('dur='))
|
|
94
|
+
if (durationParam) {
|
|
95
|
+
timings[name.trim()] = Number.parseFloat(durationParam.slice(4))
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return timings
|
|
100
|
+
}
|
|
@@ -60,6 +60,8 @@
|
|
|
60
60
|
-webkit-font-smoothing: antialiased;
|
|
61
61
|
-moz-osx-font-smoothing: grayscale;
|
|
62
62
|
font-family: var(--font-family-sans);
|
|
63
|
+
|
|
64
|
+
/* Gutter Gradient Variables */
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
/* ==========================================================================
|
|
@@ -651,12 +653,19 @@
|
|
|
651
653
|
|
|
652
654
|
html {
|
|
653
655
|
color-scheme: light dark;
|
|
656
|
+
min-height: 100dvh;
|
|
657
|
+
max-height: 100dvh;
|
|
658
|
+
height: 100%;
|
|
659
|
+
overflow: hidden;
|
|
654
660
|
}
|
|
655
661
|
|
|
656
662
|
body {
|
|
657
663
|
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', 'Liberation Sans', Helvetica, Arial, system-ui, sans-serif;
|
|
658
664
|
color: var(--text-color) !important;
|
|
659
|
-
min-height:
|
|
665
|
+
min-height: 100dvh;
|
|
666
|
+
max-height: 100dvh;
|
|
667
|
+
height: 100%;
|
|
668
|
+
overflow: hidden;
|
|
660
669
|
display: grid;
|
|
661
670
|
grid-template-areas:
|
|
662
671
|
'header'
|
|
@@ -667,12 +676,6 @@ body {
|
|
|
667
676
|
grid-template-rows: min-content min-content min-content 1fr;
|
|
668
677
|
}
|
|
669
678
|
|
|
670
|
-
body,
|
|
671
|
-
html {
|
|
672
|
-
height: 100%;
|
|
673
|
-
overflow: hidden;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
679
|
/* Utilities */
|
|
677
680
|
.flex {
|
|
678
681
|
display: flex;
|
|
@@ -770,21 +773,7 @@ body > main {
|
|
|
770
773
|
grid-area: main;
|
|
771
774
|
}
|
|
772
775
|
|
|
773
|
-
@media (min-width: 40rem) {
|
|
774
|
-
body {
|
|
775
|
-
grid-template:
|
|
776
|
-
'header header' min-content
|
|
777
|
-
'filters filters' min-content
|
|
778
|
-
'left-sidebar main ' 1fr
|
|
779
|
-
/ minmax(auto, 320px) minmax(var(--layout-min-content-width, 16rem), 1fr);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
|
|
783
776
|
@media (max-width: 40rem) {
|
|
784
|
-
button {
|
|
785
|
-
width: 100%;
|
|
786
|
-
}
|
|
787
|
-
|
|
788
777
|
.block-lg {
|
|
789
778
|
display: block !important;
|
|
790
779
|
}
|
|
@@ -794,6 +783,19 @@ body > main {
|
|
|
794
783
|
}
|
|
795
784
|
}
|
|
796
785
|
|
|
786
|
+
@media (min-width: 40em) {
|
|
787
|
+
body {
|
|
788
|
+
grid-template:
|
|
789
|
+
'header header' min-content
|
|
790
|
+
'filters filters' min-content
|
|
791
|
+
'left-sidebar main ' 1fr
|
|
792
|
+
/ minmax(auto, 320px) 1fr;
|
|
793
|
+
}
|
|
794
|
+
.border-top-none-l {
|
|
795
|
+
border-top: 0;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
797
799
|
header {
|
|
798
800
|
border-bottom: 1px solid var(--card-border-color);
|
|
799
801
|
background: light-dark(white, var(--gray-950));
|
|
@@ -811,7 +813,7 @@ footer {
|
|
|
811
813
|
|
|
812
814
|
.logo-image {
|
|
813
815
|
height: 25px;
|
|
814
|
-
width:
|
|
816
|
+
width: 25px;
|
|
815
817
|
}
|
|
816
818
|
|
|
817
819
|
.logo-image img {
|
|
@@ -842,6 +844,7 @@ footer {
|
|
|
842
844
|
line-height: 1;
|
|
843
845
|
padding: 0px 12px !important;
|
|
844
846
|
height: 24px !important;
|
|
847
|
+
max-width: 160px;
|
|
845
848
|
}
|
|
846
849
|
|
|
847
850
|
.sanity-button:hover {
|
|
@@ -930,7 +933,19 @@ m-tabs {
|
|
|
930
933
|
}
|
|
931
934
|
|
|
932
935
|
.gutter-gradient {
|
|
933
|
-
|
|
936
|
+
--gutter-width: 30px;
|
|
937
|
+
--gutter-border-width: 1px;
|
|
938
|
+
|
|
939
|
+
/* Light mode default gradient */
|
|
940
|
+
background-image: linear-gradient(to right, var(--gray-50) var(--gutter-width), var(--gray-100) var(--gutter-width), var(--gray-100) calc(var(--gutter-width) + var(--gutter-border-width)), transparent calc(var(--gutter-width) + var(--gutter-border-width)));
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/* Apply dark mode gradient override */
|
|
944
|
+
@media (prefers-color-scheme: dark) {
|
|
945
|
+
.gutter-gradient {
|
|
946
|
+
background-image: linear-gradient(to right, var(--gray-900) var(--gutter-width), var(--gray-800) var(--gutter-width), var(--gray-800) calc(var(--gutter-width) + var(--gutter-border-width)), transparent calc(var(--gutter-width) + var(--gutter-border-width)));
|
|
947
|
+
}
|
|
948
|
+
/* Add other dark-mode specific overrides here if needed */
|
|
934
949
|
}
|
|
935
950
|
|
|
936
951
|
.bg {
|
|
@@ -960,6 +975,42 @@ m-tabs {
|
|
|
960
975
|
background-color: light-dark(rgba(0, 0, 0, 0.025), rgba(255, 255, 255, 0.1)) !important;
|
|
961
976
|
}
|
|
962
977
|
|
|
978
|
+
.slab-stat {
|
|
979
|
+
font-family: var(--font-family-mono);
|
|
980
|
+
display: flex;
|
|
981
|
+
align-items: center;
|
|
982
|
+
gap: 0 8px;
|
|
983
|
+
font-size: var(--font-size-text-2);
|
|
984
|
+
margin: 0;
|
|
985
|
+
padding: var(--space-3);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
.slab-stat dt {
|
|
989
|
+
font-weight: 400;
|
|
990
|
+
text-transform: none;
|
|
991
|
+
margin: 0;
|
|
992
|
+
padding: 0;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
.slab-stat dd {
|
|
996
|
+
font-weight: 700;
|
|
997
|
+
text-transform: none;
|
|
998
|
+
margin: 0;
|
|
999
|
+
padding: 0;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
963
1002
|
pre {
|
|
1003
|
+
color: var(--base-text-color) !important;
|
|
964
1004
|
background-color: transparent !important;
|
|
965
1005
|
}
|
|
1006
|
+
|
|
1007
|
+
time {
|
|
1008
|
+
font-family: var(--font-family-mono);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
response-panel,
|
|
1012
|
+
payload-panel {
|
|
1013
|
+
max-height: 100%;
|
|
1014
|
+
height: 100%;
|
|
1015
|
+
overflow: hidden;
|
|
1016
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
class FiltersComponent extends HTMLElement {
|
|
2
2
|
connectedCallback() {
|
|
3
3
|
this.innerHTML = `
|
|
4
|
-
<form style="display:flex; gap: 8px;padding-left:
|
|
4
|
+
<form style="display:flex; gap: 8px;padding-left: var(--space-3); padding-bottom: var(--space-3); border-bottom: 1px solid var(--card-border-color);">
|
|
5
5
|
<dataset-dropdown></dataset-dropdown>
|
|
6
6
|
<fieldset class="mar-t-sm">
|
|
7
7
|
<label class="config-label">
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import {ApiBaseElement} from './api-base.js'
|
|
3
3
|
|
|
4
4
|
const template = `<ol class="hidden-lg" type="content" style="padding:0 16px;"></ol>
|
|
5
|
-
<fieldset class="
|
|
5
|
+
<fieldset class="hidden block-lg" style="padding:0 var(--space-3); margin-bottom: var(--space-3);"><select></select></fieldset>
|
|
6
6
|
`
|
|
7
7
|
|
|
8
8
|
class FunctionList extends ApiBaseElement {
|
|
9
9
|
functionClicked = (event) => {
|
|
10
10
|
// eslint-disable-next-line unicorn/prefer-dom-node-text-content
|
|
11
11
|
const target = this.api.store.functions.find((func) => func.name === event.srcElement.innerText)
|
|
12
|
-
this.api.store.selectedIndex = target.
|
|
12
|
+
this.api.store.selectedIndex = target.name
|
|
13
13
|
}
|
|
14
14
|
functionSelected = (event) => {
|
|
15
15
|
this.api.store.selectedIndex = event.srcElement.value
|
|
@@ -18,14 +18,14 @@ class FunctionList extends ApiBaseElement {
|
|
|
18
18
|
if (this.api.store.functions.length > 0) {
|
|
19
19
|
this.list.innerHTML = this.api.store.functions
|
|
20
20
|
.map((func) => {
|
|
21
|
-
const selected = this.api.store.selectedIndex === func.
|
|
21
|
+
const selected = this.api.store.selectedIndex === func.name ? 'selected' : ''
|
|
22
22
|
return `<li class="function-list-item ${selected}" style="padding: 16px 24px;">${func.name}</li>`
|
|
23
23
|
})
|
|
24
24
|
.join('')
|
|
25
25
|
this.select.innerHTML = this.api.store.functions
|
|
26
26
|
.map((func) => {
|
|
27
|
-
const selected = this.api.store.selectedIndex === func.
|
|
28
|
-
return `<option value="${func.
|
|
27
|
+
const selected = this.api.store.selectedIndex === func.name ? 'selected' : ''
|
|
28
|
+
return `<option value="${func.name}" ${selected}>${func.name}</option>`
|
|
29
29
|
})
|
|
30
30
|
.join('')
|
|
31
31
|
} else {
|