@sanity/runtime-cli 15.1.2 → 15.1.4
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 +20 -20
- package/dist/actions/blueprints/blueprint.js +1 -1
- package/dist/actions/functions/test.js +1 -1
- package/dist/actions/node.js +1 -1
- package/dist/actions/sanity/access.d.ts +11 -0
- package/dist/actions/sanity/access.js +25 -1
- package/dist/actions/sanity/examples.js +1 -1
- package/dist/commands/blueprints/deploy.js +2 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +5 -1
- package/dist/cores/blueprints/deploy.js +46 -0
- package/dist/cores/functions/add.js +1 -1
- package/dist/cores/functions/build.js +1 -1
- package/dist/cores/functions/env/add.js +2 -2
- package/dist/cores/functions/env/list.js +2 -2
- package/dist/cores/functions/env/remove.js +2 -2
- package/dist/cores/functions/logs.js +2 -2
- package/dist/cores/functions/test.js +13 -3
- package/dist/server/handlers/invoke.js +17 -5
- package/dist/utils/blueprints/group-resources.d.ts +8 -0
- package/dist/utils/blueprints/group-resources.js +29 -0
- package/dist/utils/blueprints/resolve-deployed-resources.d.ts +17 -0
- package/dist/utils/blueprints/resolve-deployed-resources.js +29 -0
- package/dist/utils/{validate/index.d.ts → blueprints/validate-resources.d.ts} +0 -1
- package/dist/utils/{validate/index.js → blueprints/validate-resources.js} +0 -1
- package/dist/utils/display/logs-formatting.js +22 -7
- package/dist/utils/{build-payload.d.ts → functions/build-payload.d.ts} +1 -1
- package/dist/utils/{build-payload.js → functions/build-payload.js} +1 -1
- package/dist/utils/{child-process-wrapper.js → functions/child-process-wrapper.js} +63 -0
- package/dist/utils/{find-function.d.ts → functions/find.d.ts} +1 -1
- package/dist/utils/{find-function.js → functions/find.js} +2 -2
- package/dist/utils/{invoke-local.d.ts → functions/invoke-local.d.ts} +1 -1
- package/dist/utils/{invoke-local.js → functions/invoke-local.js} +10 -8
- package/dist/utils/functions/prepare-asset.js +2 -2
- package/dist/utils/{transpile/transpile-function.d.ts → functions/transpile/function.d.ts} +1 -1
- package/dist/utils/{transpile/transpile-function.js → functions/transpile/function.js} +3 -3
- package/dist/utils/get-headers.js +2 -3
- package/dist/utils/types.d.ts +4 -0
- package/oclif.manifest.json +1 -1
- package/package.json +2 -2
- /package/dist/utils/{other → external}/github.d.ts +0 -0
- /package/dist/utils/{other → external}/github.js +0 -0
- /package/dist/utils/{other → external}/npmjs.d.ts +0 -0
- /package/dist/utils/{other → external}/npmjs.js +0 -0
- /package/dist/utils/functions/{getFolderSize.d.ts → get-folder-size.d.ts} +0 -0
- /package/dist/utils/functions/{getFolderSize.js → get-folder-size.js} +0 -0
- /package/dist/utils/functions/{packageJsonUtils.d.ts → package-json.d.ts} +0 -0
- /package/dist/utils/functions/{packageJsonUtils.js → package-json.js} +0 -0
- /package/dist/utils/functions/{resolve-function-auth.d.ts → resolve-auth.d.ts} +0 -0
- /package/dist/utils/functions/{resolve-function-auth.js → resolve-auth.js} +0 -0
- /package/dist/utils/{transpile → functions/transpile}/cleanup-source-maps.d.ts +0 -0
- /package/dist/utils/{transpile → functions/transpile}/cleanup-source-maps.js +0 -0
- /package/dist/utils/{transpile → functions/transpile}/find-up.d.ts +0 -0
- /package/dist/utils/{transpile → functions/transpile}/find-up.js +0 -0
- /package/dist/utils/{pnpm.d.ts → functions/transpile/pnpm.d.ts} +0 -0
- /package/dist/utils/{pnpm.js → functions/transpile/pnpm.js} +0 -0
- /package/dist/utils/{transpile → functions/transpile}/verify-handler.d.ts +0 -0
- /package/dist/utils/{transpile → functions/transpile}/verify-handler.js +0 -0
- /package/dist/utils/{validate/resource.d.ts → functions/validate-name.d.ts} +0 -0
- /package/dist/utils/{validate/resource.js → functions/validate-name.js} +0 -0
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/15.1.
|
|
23
|
+
@sanity/runtime-cli/15.1.4 linux-x64 node-v24.16.0
|
|
24
24
|
$ sanity-run --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ sanity-run COMMAND
|
|
@@ -103,7 +103,7 @@ EXAMPLES
|
|
|
103
103
|
$ sanity-run blueprints add function --name my-function --fn-type document-create --fn-type document-update --lang js
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
_See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
106
|
+
_See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/blueprints/add.ts)_
|
|
107
107
|
|
|
108
108
|
## `sanity-run blueprints config`
|
|
109
109
|
|
|
@@ -140,7 +140,7 @@ EXAMPLES
|
|
|
140
140
|
$ sanity-run blueprints config --edit --project-id <projectId> --stack <name-or-id>
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
-
_See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
143
|
+
_See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/blueprints/config.ts)_
|
|
144
144
|
|
|
145
145
|
## `sanity-run blueprints deploy`
|
|
146
146
|
|
|
@@ -191,7 +191,7 @@ EXAMPLES
|
|
|
191
191
|
$ sanity-run blueprints deploy --new-stack-name <new-name>
|
|
192
192
|
```
|
|
193
193
|
|
|
194
|
-
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
194
|
+
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/blueprints/deploy.ts)_
|
|
195
195
|
|
|
196
196
|
## `sanity-run blueprints destroy`
|
|
197
197
|
|
|
@@ -226,7 +226,7 @@ EXAMPLES
|
|
|
226
226
|
$ sanity-run blueprints destroy --stack <name-or-id> --project-id <projectId> --force --no-wait
|
|
227
227
|
```
|
|
228
228
|
|
|
229
|
-
_See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
229
|
+
_See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/blueprints/destroy.ts)_
|
|
230
230
|
|
|
231
231
|
## `sanity-run blueprints doctor`
|
|
232
232
|
|
|
@@ -257,7 +257,7 @@ EXAMPLES
|
|
|
257
257
|
$ sanity-run blueprints doctor --fix
|
|
258
258
|
```
|
|
259
259
|
|
|
260
|
-
_See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
260
|
+
_See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/blueprints/doctor.ts)_
|
|
261
261
|
|
|
262
262
|
## `sanity-run blueprints info`
|
|
263
263
|
|
|
@@ -294,7 +294,7 @@ EXAMPLES
|
|
|
294
294
|
$ sanity-run blueprints info --organization-id <orgId> --stack <name-or-id>
|
|
295
295
|
```
|
|
296
296
|
|
|
297
|
-
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
297
|
+
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/blueprints/info.ts)_
|
|
298
298
|
|
|
299
299
|
## `sanity-run blueprints init [DIR]`
|
|
300
300
|
|
|
@@ -353,7 +353,7 @@ EXAMPLES
|
|
|
353
353
|
$ sanity-run blueprints init old-stack --type <json|js|ts> --project-id <projectId> --stack-id <existingStackId>
|
|
354
354
|
```
|
|
355
355
|
|
|
356
|
-
_See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
356
|
+
_See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/blueprints/init.ts)_
|
|
357
357
|
|
|
358
358
|
## `sanity-run blueprints logs`
|
|
359
359
|
|
|
@@ -399,7 +399,7 @@ EXAMPLES
|
|
|
399
399
|
$ sanity-run blueprints logs --before 2026-05-01T00:00:00Z
|
|
400
400
|
```
|
|
401
401
|
|
|
402
|
-
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
402
|
+
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/blueprints/logs.ts)_
|
|
403
403
|
|
|
404
404
|
## `sanity-run blueprints mint-deploy-token`
|
|
405
405
|
|
|
@@ -444,7 +444,7 @@ EXAMPLES
|
|
|
444
444
|
$ sanity-run blueprints mint-deploy-token --organization-id <orgId>
|
|
445
445
|
```
|
|
446
446
|
|
|
447
|
-
_See code: [src/commands/blueprints/mint-deploy-token.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
447
|
+
_See code: [src/commands/blueprints/mint-deploy-token.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/blueprints/mint-deploy-token.ts)_
|
|
448
448
|
|
|
449
449
|
## `sanity-run blueprints plan`
|
|
450
450
|
|
|
@@ -477,7 +477,7 @@ EXAMPLES
|
|
|
477
477
|
$ sanity-run blueprints plan --organization-id <orgId> --stack <name-or-id>
|
|
478
478
|
```
|
|
479
479
|
|
|
480
|
-
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
480
|
+
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/blueprints/plan.ts)_
|
|
481
481
|
|
|
482
482
|
## `sanity-run blueprints promote`
|
|
483
483
|
|
|
@@ -513,7 +513,7 @@ EXAMPLES
|
|
|
513
513
|
$ sanity-run blueprints promote --new-stack-name <new-name>
|
|
514
514
|
```
|
|
515
515
|
|
|
516
|
-
_See code: [src/commands/blueprints/promote.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
516
|
+
_See code: [src/commands/blueprints/promote.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/blueprints/promote.ts)_
|
|
517
517
|
|
|
518
518
|
## `sanity-run blueprints stacks`
|
|
519
519
|
|
|
@@ -549,7 +549,7 @@ EXAMPLES
|
|
|
549
549
|
$ sanity-run blueprints stacks --organization-id <organizationId> --include-projects
|
|
550
550
|
```
|
|
551
551
|
|
|
552
|
-
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
552
|
+
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/blueprints/stacks.ts)_
|
|
553
553
|
|
|
554
554
|
## `sanity-run functions add`
|
|
555
555
|
|
|
@@ -601,7 +601,7 @@ EXAMPLES
|
|
|
601
601
|
$ sanity-run functions add --name my-function --type document-create --type document-update --lang js
|
|
602
602
|
```
|
|
603
603
|
|
|
604
|
-
_See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
604
|
+
_See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/functions/add.ts)_
|
|
605
605
|
|
|
606
606
|
## `sanity-run functions dev`
|
|
607
607
|
|
|
@@ -636,7 +636,7 @@ EXAMPLES
|
|
|
636
636
|
$ sanity-run functions dev --timeout 60
|
|
637
637
|
```
|
|
638
638
|
|
|
639
|
-
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
639
|
+
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/functions/dev.ts)_
|
|
640
640
|
|
|
641
641
|
## `sanity-run functions env add NAME KEY VALUE`
|
|
642
642
|
|
|
@@ -666,7 +666,7 @@ EXAMPLES
|
|
|
666
666
|
$ sanity-run functions env add MyFunction API_URL https://api.example.com/
|
|
667
667
|
```
|
|
668
668
|
|
|
669
|
-
_See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
669
|
+
_See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/functions/env/add.ts)_
|
|
670
670
|
|
|
671
671
|
## `sanity-run functions env list NAME`
|
|
672
672
|
|
|
@@ -693,7 +693,7 @@ EXAMPLES
|
|
|
693
693
|
$ sanity-run functions env list MyFunction
|
|
694
694
|
```
|
|
695
695
|
|
|
696
|
-
_See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
696
|
+
_See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/functions/env/list.ts)_
|
|
697
697
|
|
|
698
698
|
## `sanity-run functions env remove NAME KEY`
|
|
699
699
|
|
|
@@ -722,7 +722,7 @@ EXAMPLES
|
|
|
722
722
|
$ sanity-run functions env remove MyFunction API_URL
|
|
723
723
|
```
|
|
724
724
|
|
|
725
|
-
_See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
725
|
+
_See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/functions/env/remove.ts)_
|
|
726
726
|
|
|
727
727
|
## `sanity-run functions logs [NAME]`
|
|
728
728
|
|
|
@@ -762,7 +762,7 @@ EXAMPLES
|
|
|
762
762
|
$ sanity-run functions logs <name> --delete
|
|
763
763
|
```
|
|
764
764
|
|
|
765
|
-
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
765
|
+
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/functions/logs.ts)_
|
|
766
766
|
|
|
767
767
|
## `sanity-run functions test [NAME]`
|
|
768
768
|
|
|
@@ -819,7 +819,7 @@ EXAMPLES
|
|
|
819
819
|
$ sanity-run functions test <name> --event update --data-before '{ "title": "before" }' --data-after '{ "title": "after" }'
|
|
820
820
|
```
|
|
821
821
|
|
|
822
|
-
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.
|
|
822
|
+
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v15.1.4/src/commands/functions/test.ts)_
|
|
823
823
|
|
|
824
824
|
## `sanity-run help [COMMAND]`
|
|
825
825
|
|
|
@@ -6,7 +6,7 @@ import blueprintParserValidator from '@sanity/blueprints-parser';
|
|
|
6
6
|
import * as find from 'empathic/find';
|
|
7
7
|
import { createJiti } from 'jiti';
|
|
8
8
|
import { SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_SCHEDULED, } from '../../constants.js';
|
|
9
|
-
import { validateResources } from '../../utils/validate
|
|
9
|
+
import { validateResources } from '../../utils/blueprints/validate-resources.js';
|
|
10
10
|
import { backfillProjectBasedStackId, readConfigFile, } from './config.js';
|
|
11
11
|
import { resolveIds } from './resolve.js';
|
|
12
12
|
const SUPPORTED_FILE_EXTENSIONS = ['.json', '.js', '.mjs', '.ts'];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import invoke from '../../utils/invoke-local.js';
|
|
1
|
+
import invoke from '../../utils/functions/invoke-local.js';
|
|
2
2
|
export async function testAction(resource, payload, context, options) {
|
|
3
3
|
try {
|
|
4
4
|
const { json, logs, error } = await invoke(resource, payload, context, options);
|
package/dist/actions/node.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, extname, join } from 'node:path';
|
|
3
|
-
import { getLatestNpmVersion } from '../utils/
|
|
3
|
+
import { getLatestNpmVersion } from '../utils/external/npmjs.js';
|
|
4
4
|
export async function writeOrUpdateNodeDependency(nearFilePath, dependency, logger) {
|
|
5
5
|
const dir = dirname(nearFilePath);
|
|
6
6
|
const extension = extname(nearFilePath);
|
|
@@ -35,4 +35,15 @@ export declare function createRobotToken({ auth, resourceType, resourceId, body,
|
|
|
35
35
|
body: CreateRobotInput;
|
|
36
36
|
logger: Logger;
|
|
37
37
|
}): Promise<CreateRobotResponse>;
|
|
38
|
+
export interface CheckUserPermissionResponse extends ActionResponse {
|
|
39
|
+
hasPermission: boolean;
|
|
40
|
+
}
|
|
41
|
+
/** Check whether the token's user holds a specific permission on a project or organization. */
|
|
42
|
+
export declare function checkUserPermission({ auth, resourceType, resourceId, permission, logger, }: {
|
|
43
|
+
auth: AuthParams;
|
|
44
|
+
resourceType: ScopeType;
|
|
45
|
+
resourceId: string;
|
|
46
|
+
permission: string;
|
|
47
|
+
logger: Logger;
|
|
48
|
+
}): Promise<CheckUserPermissionResponse>;
|
|
38
49
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import config from '../../config.js';
|
|
1
|
+
import config, { RUNTIME_CLI_USER_AGENT } from '../../config.js';
|
|
2
2
|
import getHeaders from '../../utils/get-headers.js';
|
|
3
3
|
import { createTracedFetch } from '../../utils/traced-fetch.js';
|
|
4
4
|
const { apiUrl } = config;
|
|
@@ -21,3 +21,27 @@ export async function createRobotToken({ auth, resourceType, resourceId, body, l
|
|
|
21
21
|
}
|
|
22
22
|
return { ok: true, error: null, robot: raw };
|
|
23
23
|
}
|
|
24
|
+
/** Check whether the token's user holds a specific permission on a project or organization. */
|
|
25
|
+
export async function checkUserPermission({ auth, resourceType, resourceId, permission, logger, }) {
|
|
26
|
+
const fetchFn = createTracedFetch(logger);
|
|
27
|
+
const url = `${accessApiPath}/${resourceType}/${encodeURIComponent(resourceId)}/user-permissions/me/check?permissions=${encodeURIComponent(permission)}`;
|
|
28
|
+
const response = await fetchFn(url, {
|
|
29
|
+
method: 'GET',
|
|
30
|
+
headers: {
|
|
31
|
+
Accept: 'application/json',
|
|
32
|
+
Authorization: `Bearer ${auth.token}`,
|
|
33
|
+
'User-Agent': RUNTIME_CLI_USER_AGENT,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const raw = await response.json().catch(() => null);
|
|
37
|
+
const body = (raw && typeof raw === 'object' ? raw : {});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
const errMessage = body.message || body.error?.message || response.statusText;
|
|
40
|
+
return { ok: false, error: errMessage, hasPermission: false };
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
ok: true,
|
|
44
|
+
error: null,
|
|
45
|
+
hasPermission: body.data?.[permission] === true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -4,7 +4,7 @@ import { dirname, join } from 'node:path';
|
|
|
4
4
|
import { pipeline } from 'node:stream/promises';
|
|
5
5
|
import { createGunzip } from 'node:zlib';
|
|
6
6
|
import { extract } from 'tar-stream';
|
|
7
|
-
import { gitHubRequest } from '../../utils/
|
|
7
|
+
import { gitHubRequest } from '../../utils/external/github.js';
|
|
8
8
|
export const EXAMPLES_CACHE_DIR = join(tmpdir(), 'sanity-examples');
|
|
9
9
|
const EXAMPLE_TYPES = {
|
|
10
10
|
blueprint: { repo: 'sanity-io/sanity', dir: 'examples/blueprints' },
|
package/dist/config.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export declare const BLUEPRINT_CONFIG_VERSION = "v2025-05-08";
|
|
2
2
|
export declare const BLUEPRINT_CONFIG_DIR = ".sanity";
|
|
3
3
|
export declare const BLUEPRINT_CONFIG_FILE = "blueprint.config.json";
|
|
4
|
+
export declare const RUNTIME_CLI_NAME = "@sanity/runtime-cli";
|
|
4
5
|
export declare let RUNTIME_CLI_VERSION: string | undefined;
|
|
6
|
+
export declare const RUNTIME_CLI_USER_AGENT: string;
|
|
5
7
|
declare const _default: {
|
|
6
8
|
isTest: boolean;
|
|
7
9
|
isLive: boolean;
|
package/dist/config.js
CHANGED
|
@@ -6,17 +6,21 @@ import getToken from './utils/get-token.js';
|
|
|
6
6
|
export const BLUEPRINT_CONFIG_VERSION = 'v2025-05-08';
|
|
7
7
|
export const BLUEPRINT_CONFIG_DIR = '.sanity';
|
|
8
8
|
export const BLUEPRINT_CONFIG_FILE = 'blueprint.config.json';
|
|
9
|
+
export const RUNTIME_CLI_NAME = '@sanity/runtime-cli';
|
|
9
10
|
export let RUNTIME_CLI_VERSION;
|
|
10
11
|
try {
|
|
11
12
|
const packageJsonPath = pkg.up({ cwd: fileURLToPath(new URL('.', import.meta.url)) });
|
|
12
13
|
if (packageJsonPath) {
|
|
13
14
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
14
|
-
if (packageJson.name ===
|
|
15
|
+
if (packageJson.name === RUNTIME_CLI_NAME) {
|
|
15
16
|
RUNTIME_CLI_VERSION = packageJson.version;
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
catch { }
|
|
21
|
+
export const RUNTIME_CLI_USER_AGENT = RUNTIME_CLI_VERSION
|
|
22
|
+
? `${RUNTIME_CLI_NAME}@${RUNTIME_CLI_VERSION}`
|
|
23
|
+
: RUNTIME_CLI_NAME;
|
|
20
24
|
const nodeEnv = env.NODE_ENV?.toLowerCase() ?? 'production';
|
|
21
25
|
const isTest = nodeEnv === 'test';
|
|
22
26
|
const sanityEnv = env.SANITY_INTERNAL_ENV?.toLowerCase() ?? 'production';
|
|
@@ -2,6 +2,7 @@ import { setTimeout as sleep } from 'node:timers/promises';
|
|
|
2
2
|
import { stashAsset } from '../../actions/blueprints/assets.js';
|
|
3
3
|
import { setupLogPolling } from '../../actions/blueprints/logs-polling.js';
|
|
4
4
|
import { getStack, updateStack } from '../../actions/blueprints/stacks.js';
|
|
5
|
+
import { checkUserPermission } from '../../actions/sanity/access.js';
|
|
5
6
|
import { createHintCollector } from '../../utils/blueprints/hints.js';
|
|
6
7
|
import { niceId } from '../../utils/display/presenters.js';
|
|
7
8
|
import { styleText } from '../../utils/style-text.js';
|
|
@@ -76,13 +77,23 @@ export async function blueprintDeployCore(options) {
|
|
|
76
77
|
};
|
|
77
78
|
}
|
|
78
79
|
spinner.stop().clear();
|
|
80
|
+
const legacyPermissionsNoticePromise = CHECK_LEGACY_DEPLOY_PERMISSION
|
|
81
|
+
? checkLegacyDeployPermission({
|
|
82
|
+
auth,
|
|
83
|
+
scopeType,
|
|
84
|
+
scopeId,
|
|
85
|
+
log,
|
|
86
|
+
})
|
|
87
|
+
: Promise.resolve(null);
|
|
79
88
|
if (noWait) {
|
|
80
89
|
log(styleText(['bold', 'green'], 'Stack deployment started!'));
|
|
81
90
|
log(`Use \`npx ${bin} blueprints info\` to check status`);
|
|
91
|
+
const legacyWarning = await legacyPermissionsNoticePromise;
|
|
82
92
|
return {
|
|
83
93
|
success: true,
|
|
84
94
|
json: { stackId: stack.id, resources },
|
|
85
95
|
data: { resources },
|
|
96
|
+
warnings: legacyWarning ? [legacyWarning] : undefined,
|
|
86
97
|
};
|
|
87
98
|
}
|
|
88
99
|
log(styleText('dim', 'Stack deployment progress:'));
|
|
@@ -143,10 +154,12 @@ export async function blueprintDeployCore(options) {
|
|
|
143
154
|
logStreamCleanup();
|
|
144
155
|
log('');
|
|
145
156
|
log(styleText(['bold', 'green'], 'Stack deployment completed!'));
|
|
157
|
+
const legacyWarning = await legacyPermissionsNoticePromise;
|
|
146
158
|
return {
|
|
147
159
|
success: true,
|
|
148
160
|
json: { stackId: stack.id, resources },
|
|
149
161
|
data: { resources },
|
|
162
|
+
warnings: legacyWarning ? [legacyWarning] : undefined,
|
|
150
163
|
};
|
|
151
164
|
}
|
|
152
165
|
if (!idleMessageShown && Date.now() - lastLogAt > 60_000) {
|
|
@@ -215,3 +228,36 @@ async function preDeploy(resource, options) {
|
|
|
215
228
|
fnSpinner.fail(errorMsg);
|
|
216
229
|
return { success: false, error: result.error || 'Failed to process asset' };
|
|
217
230
|
}
|
|
231
|
+
const CHECK_LEGACY_DEPLOY_PERMISSION = false;
|
|
232
|
+
const BLUEPRINTS_PERMISSION_ENFORCEMENT_DATE = 'July 1, 2026';
|
|
233
|
+
async function checkLegacyDeployPermission({ auth, scopeType, scopeId, log, }) {
|
|
234
|
+
const requiredPermission = scopeType === 'organization' ? 'sanity.blueprints.deploy' : 'sanity.project.blueprints.deploy';
|
|
235
|
+
try {
|
|
236
|
+
const result = await checkUserPermission({
|
|
237
|
+
auth,
|
|
238
|
+
resourceType: scopeType,
|
|
239
|
+
resourceId: scopeId,
|
|
240
|
+
permission: requiredPermission,
|
|
241
|
+
logger: log,
|
|
242
|
+
});
|
|
243
|
+
if (!result.ok) {
|
|
244
|
+
log.verbose(`Failed to check ${requiredPermission}: ${result.error ?? 'unknown error'}`);
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
if (result.hasPermission)
|
|
248
|
+
return null;
|
|
249
|
+
return {
|
|
250
|
+
label: 'Legacy deploy permission',
|
|
251
|
+
suggestions: [
|
|
252
|
+
`This deploy used a legacy permission. Starting ${BLUEPRINTS_PERMISSION_ENFORCEMENT_DATE}, deploys will require the "${requiredPermission}" permission.`,
|
|
253
|
+
scopeType === 'project'
|
|
254
|
+
? 'Ask a project administrator to add you to a role with Blueprint deploy access: Administrator, Developer, or Blueprints Deployer. For CI, use a Blueprints Deployer API token.'
|
|
255
|
+
: 'Ask an organization administrator to grant you the Administrator role. For CI, use a Blueprints Deployer API token created by someone with access to this organization.',
|
|
256
|
+
],
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
log.verbose(`Failed to check ${requiredPermission}: ${err instanceof Error ? err.message : String(err)}`);
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -7,8 +7,8 @@ import { createFunctionResource } from '../../actions/blueprints/resources.js';
|
|
|
7
7
|
import { verifyExampleExists, writeExample } from '../../actions/sanity/examples.js';
|
|
8
8
|
import { EVENT_DOCUMENT_CREATE, EVENT_DOCUMENT_DELETE, EVENT_DOCUMENT_UPDATE, EVENT_MEDIA_LIBRARY_ASSET_CREATE, EVENT_MEDIA_LIBRARY_ASSET_DELETE, EVENT_MEDIA_LIBRARY_ASSET_UPDATE, EVENT_SCHEDULED, EVENT_SYNC_TAG_INVALIDATE, FUNCTION_TYPES, LABEL_DOCUMENT_CREATE, LABEL_DOCUMENT_DELETE, LABEL_DOCUMENT_UPDATE, LABEL_MEDIA_LIBRARY_ASSET_CREATE, LABEL_MEDIA_LIBRARY_ASSET_DELETE, LABEL_MEDIA_LIBRARY_ASSET_UPDATE, LABEL_SCHEDULED, LABEL_SYNC_TAG_INVALIDATE, MAP_EVENT_TO_FUNCTION_TYPE, SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_SCHEDULED, SANITY_FUNCTION_SYNC_TAG_INVALIDATE, } from '../../constants.js';
|
|
9
9
|
import { check, indent, warn } from '../../utils/display/presenters.js';
|
|
10
|
+
import { validateFunctionName } from '../../utils/functions/validate-name.js';
|
|
10
11
|
import { styleText } from '../../utils/style-text.js';
|
|
11
|
-
import { validateFunctionName } from '../../utils/validate/resource.js';
|
|
12
12
|
export const generateFunctionBlueprintResourceTemplate = (fnName, eventNames) => {
|
|
13
13
|
const functionType = MAP_EVENT_TO_FUNCTION_TYPE[eventNames[0]];
|
|
14
14
|
let definer = '';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { pathToZip } from '../../actions/blueprints/assets.js';
|
|
4
|
-
import { findFunctionInResources } from '../../utils/find
|
|
4
|
+
import { findFunctionInResources } from '../../utils/functions/find.js';
|
|
5
5
|
import { prepareAsset } from '../../utils/functions/prepare-asset.js';
|
|
6
6
|
import { isLocalFunctionResource } from '../../utils/types.js';
|
|
7
7
|
export async function functionBuildCore(options) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { update } from '../../../actions/functions/env/update.js';
|
|
2
|
-
import { findFunctionInStack } from '../../../utils/find
|
|
3
|
-
import { resolveFunctionAuth } from '../../../utils/functions/resolve-
|
|
2
|
+
import { findFunctionInStack } from '../../../utils/functions/find.js';
|
|
3
|
+
import { resolveFunctionAuth } from '../../../utils/functions/resolve-auth.js';
|
|
4
4
|
import { styleText } from '../../../utils/style-text.js';
|
|
5
5
|
export async function functionEnvAddCore(options) {
|
|
6
6
|
const { args, log } = options;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { list } from '../../../actions/functions/env/list.js';
|
|
2
|
-
import { findFunctionInStack } from '../../../utils/find
|
|
3
|
-
import { resolveFunctionAuth } from '../../../utils/functions/resolve-
|
|
2
|
+
import { findFunctionInStack } from '../../../utils/functions/find.js';
|
|
3
|
+
import { resolveFunctionAuth } from '../../../utils/functions/resolve-auth.js';
|
|
4
4
|
export async function functionEnvListCore(options) {
|
|
5
5
|
const { args, log } = options;
|
|
6
6
|
const spinner = log.ora(`Listing environment variables for "${args.name}"`).start();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { remove } from '../../../actions/functions/env/remove.js';
|
|
2
|
-
import { findFunctionInStack } from '../../../utils/find
|
|
3
|
-
import { resolveFunctionAuth } from '../../../utils/functions/resolve-
|
|
2
|
+
import { findFunctionInStack } from '../../../utils/functions/find.js';
|
|
3
|
+
import { resolveFunctionAuth } from '../../../utils/functions/resolve-auth.js';
|
|
4
4
|
import { styleText } from '../../../utils/style-text.js';
|
|
5
5
|
export async function functionEnvRemoveCore(options) {
|
|
6
6
|
const { args, log } = options;
|
|
@@ -2,8 +2,8 @@ import { confirm } from '@inquirer/prompts';
|
|
|
2
2
|
import { deleteLogs as deleteLogsAction, logs as getLogsAction, streamLogs as streamLogsAction, } from '../../actions/functions/logs.js';
|
|
3
3
|
import { formatTitle } from '../../utils/display/blueprints-formatting.js';
|
|
4
4
|
import { niceId } from '../../utils/display/presenters.js';
|
|
5
|
-
import { findFunctionInStack, getFunctionNames } from '../../utils/find
|
|
6
|
-
import { resolveFunctionAuth } from '../../utils/functions/resolve-
|
|
5
|
+
import { findFunctionInStack, getFunctionNames } from '../../utils/functions/find.js';
|
|
6
|
+
import { resolveFunctionAuth } from '../../utils/functions/resolve-auth.js';
|
|
7
7
|
import { styleText } from '../../utils/style-text.js';
|
|
8
8
|
export async function functionLogsCore(options) {
|
|
9
9
|
const { args, flags, log, error, deployedStack, blueprint, helpText } = options;
|
|
@@ -4,9 +4,10 @@ import { cwd } from 'node:process';
|
|
|
4
4
|
import { testAction } from '../../actions/functions/test.js';
|
|
5
5
|
import config from '../../config.js';
|
|
6
6
|
import { SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET } from '../../constants.js';
|
|
7
|
-
import
|
|
8
|
-
import
|
|
7
|
+
import { resolveDeployedResources } from '../../utils/blueprints/resolve-deployed-resources.js';
|
|
8
|
+
import buildPayload from '../../utils/functions/build-payload.js';
|
|
9
9
|
import { fetchAsset, fetchDocument } from '../../utils/functions/fetch-document.js';
|
|
10
|
+
import { findFunctionInResources, getFunctionNames } from '../../utils/functions/find.js';
|
|
10
11
|
import { parseJsonObject } from '../../utils/parse-json-object.js';
|
|
11
12
|
import { isEventType, } from '../../utils/types.js';
|
|
12
13
|
export async function functionTestCore(options) {
|
|
@@ -40,6 +41,14 @@ export async function functionTestCore(options) {
|
|
|
40
41
|
const resource = findFunctionInResources(blueprint.resources, fnName); // throws if not found
|
|
41
42
|
const docFunction = resource.type === SANITY_FUNCTION_DOCUMENT;
|
|
42
43
|
const mediaFunction = resource.type === SANITY_FUNCTION_MEDIA_LIBRARY_ASSET;
|
|
44
|
+
const resolvedResources = await resolveDeployedResources({
|
|
45
|
+
resources: blueprint.resources,
|
|
46
|
+
stackId: blueprint.stackId,
|
|
47
|
+
auth: config.token && blueprint.scopeType && blueprint.scopeId
|
|
48
|
+
? { token: config.token, scopeType: blueprint.scopeType, scopeId: blueprint.scopeId }
|
|
49
|
+
: undefined,
|
|
50
|
+
logger: log,
|
|
51
|
+
});
|
|
43
52
|
const contextOptions = docFunction || mediaFunction
|
|
44
53
|
? {
|
|
45
54
|
clientOptions: {
|
|
@@ -52,8 +61,9 @@ export async function functionTestCore(options) {
|
|
|
52
61
|
eventResourceId: (docFunction ? `${projectId}.${dataset}` : mediaLibraryId) || '',
|
|
53
62
|
functionResourceType: 'project',
|
|
54
63
|
functionResourceId: projectId || '',
|
|
64
|
+
resources: resolvedResources,
|
|
55
65
|
}
|
|
56
|
-
: { clientOptions: {} };
|
|
66
|
+
: { clientOptions: {}, resources: resolvedResources };
|
|
57
67
|
// If the user sets the flag to use the real token set it in our options
|
|
58
68
|
if (withUserToken) {
|
|
59
69
|
contextOptions.clientOptions.token = config.token || undefined;
|
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import { readLocalBlueprint } from '../../actions/blueprints/blueprint.js';
|
|
2
|
+
import config from '../../config.js';
|
|
3
|
+
import { resolveDeployedResources } from '../../utils/blueprints/resolve-deployed-resources.js';
|
|
4
|
+
import { findFunctionInResources } from '../../utils/functions/find.js';
|
|
5
|
+
import invoke from '../../utils/functions/invoke-local.js';
|
|
6
|
+
import { Logger } from '../../utils/logger.js';
|
|
7
|
+
const silentLogger = Logger(() => { });
|
|
4
8
|
export async function handleInvokeRequest(functionName, event, metadata, context, validateResources, executionOptions) {
|
|
5
9
|
const start = performance.now();
|
|
6
|
-
const { resources } = await
|
|
10
|
+
const { resources, stackId, scopeType, scopeId } = await readLocalBlueprint(silentLogger, {
|
|
11
|
+
resources: validateResources,
|
|
12
|
+
});
|
|
7
13
|
const resource = findFunctionInResources(resources, functionName);
|
|
8
14
|
const readBlueprintTime = performance.now() - start;
|
|
15
|
+
const resolvedResources = await resolveDeployedResources({
|
|
16
|
+
resources,
|
|
17
|
+
stackId,
|
|
18
|
+
auth: config.token && scopeType && scopeId ? { token: config.token, scopeType, scopeId } : undefined,
|
|
19
|
+
logger: silentLogger,
|
|
20
|
+
});
|
|
9
21
|
const payload = {
|
|
10
22
|
payload: event,
|
|
11
23
|
...metadata,
|
|
12
24
|
};
|
|
13
|
-
const response = await invoke(resource, payload, context, {
|
|
25
|
+
const response = await invoke(resource, payload, { ...context, resources: resolvedResources }, {
|
|
14
26
|
forceColor: executionOptions?.forceColor ?? false,
|
|
15
27
|
timeout: executionOptions?.timeout ?? resource.timeout,
|
|
16
28
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BlueprintResource } from '@sanity/blueprints';
|
|
2
|
+
export type GroupedBlueprintResource = {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
type: string;
|
|
6
|
+
};
|
|
7
|
+
export type GroupedBlueprintResources = Record<string, GroupedBlueprintResource[]>;
|
|
8
|
+
export declare function groupBlueprintResources(blueprintResources: BlueprintResource[]): GroupedBlueprintResources;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const BLUEPRINT_TYPE_TO_KEY = {
|
|
2
|
+
'sanity.project.webhook': 'webhook',
|
|
3
|
+
'sanity.project.cors': 'cors',
|
|
4
|
+
'sanity.project.origin': 'cors',
|
|
5
|
+
'sanity.access.role': 'role',
|
|
6
|
+
'sanity.project.dataset': 'dataset',
|
|
7
|
+
'sanity.project': 'project',
|
|
8
|
+
};
|
|
9
|
+
export function groupBlueprintResources(blueprintResources) {
|
|
10
|
+
const grouped = {};
|
|
11
|
+
for (const resource of blueprintResources) {
|
|
12
|
+
if (resource.type === 'sanity.access.robot')
|
|
13
|
+
continue;
|
|
14
|
+
const key = (resource.type?.startsWith('sanity.function.')
|
|
15
|
+
? 'function'
|
|
16
|
+
: BLUEPRINT_TYPE_TO_KEY[resource.type]) ?? resource.type?.split('.').pop();
|
|
17
|
+
if (!key)
|
|
18
|
+
continue;
|
|
19
|
+
if (!grouped[key])
|
|
20
|
+
grouped[key] = [];
|
|
21
|
+
const externalId = resource.externalId;
|
|
22
|
+
grouped[key].push({
|
|
23
|
+
id: externalId || 'not-deployed',
|
|
24
|
+
name: resource.name,
|
|
25
|
+
type: resource.type,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return grouped;
|
|
29
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BlueprintResource } from '@sanity/blueprints';
|
|
2
|
+
import type { Logger } from '../logger.js';
|
|
3
|
+
import type { AuthParams } from '../types.js';
|
|
4
|
+
interface ResolveOptions {
|
|
5
|
+
resources: BlueprintResource[];
|
|
6
|
+
stackId?: string;
|
|
7
|
+
auth?: AuthParams;
|
|
8
|
+
logger: Logger;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Returns the local blueprint resources, annotated with externalIds from the
|
|
12
|
+
* deployed stack where a match is found (by name + type). Locally-added
|
|
13
|
+
* resources that aren't yet deployed are preserved without an externalId.
|
|
14
|
+
* Any failure to fetch the stack falls back to the raw local resources.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveDeployedResources({ resources, stackId, auth, logger, }: ResolveOptions): Promise<BlueprintResource[]>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getStack } from '../../actions/blueprints/stacks.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the local blueprint resources, annotated with externalIds from the
|
|
4
|
+
* deployed stack where a match is found (by name + type). Locally-added
|
|
5
|
+
* resources that aren't yet deployed are preserved without an externalId.
|
|
6
|
+
* Any failure to fetch the stack falls back to the raw local resources.
|
|
7
|
+
*/
|
|
8
|
+
export async function resolveDeployedResources({ resources, stackId, auth, logger, }) {
|
|
9
|
+
if (!stackId || !auth?.token || !auth.scopeType || !auth.scopeId)
|
|
10
|
+
return resources;
|
|
11
|
+
try {
|
|
12
|
+
const response = await getStack({ stackId, auth, logger });
|
|
13
|
+
if (!response.ok || !Array.isArray(response.stack?.resources))
|
|
14
|
+
return resources;
|
|
15
|
+
const deployedByKey = new Map();
|
|
16
|
+
for (const deployed of response.stack.resources) {
|
|
17
|
+
if (deployed.externalId) {
|
|
18
|
+
deployedByKey.set(`${deployed.type}:${deployed.name}`, deployed.externalId);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return resources.map((resource) => {
|
|
22
|
+
const externalId = deployedByKey.get(`${resource.type}:${resource.name}`);
|
|
23
|
+
return externalId ? { ...resource, externalId } : resource;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return resources;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { validateCorsOrigin, validateDataset, validateDocumentFunction, validateDocumentWebhook, validateMediaLibraryAssetFunction, validateProject, validateRole, validateScheduledFunction, } from '@sanity/blueprints';
|
|
2
2
|
import { SANITY_ACCESS_ROLE, SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_SCHEDULED, SANITY_PROJECT, SANITY_PROJECT_CORS, SANITY_PROJECT_DATASET, SANITY_PROJECT_WEBHOOK, } from '../../constants.js';
|
|
3
|
-
export * as validate from './resource.js';
|
|
4
3
|
const RESOURCE_VALIDATORS = {
|
|
5
4
|
[SANITY_ACCESS_ROLE]: {
|
|
6
5
|
validate: validateRole,
|
|
@@ -8,11 +8,15 @@ const GUTTER_LEVEL_WIDTH = 6;
|
|
|
8
8
|
function isNewOperation(log, previousLog) {
|
|
9
9
|
return !!previousLog && log.operationId !== previousLog.operationId;
|
|
10
10
|
}
|
|
11
|
-
function
|
|
11
|
+
function isErrorLevel(log) {
|
|
12
|
+
const level = log.level?.toUpperCase();
|
|
13
|
+
return level === 'ERROR' || level === 'FATAL';
|
|
14
|
+
}
|
|
15
|
+
function logGutter(log, useLevel, previousLog) {
|
|
12
16
|
const operationIsNew = isNewOperation(log, previousLog);
|
|
13
17
|
const level = log.level.toUpperCase();
|
|
14
|
-
const isError =
|
|
15
|
-
if (
|
|
18
|
+
const isError = isErrorLevel(log);
|
|
19
|
+
if (useLevel) {
|
|
16
20
|
const color = isError ? errorStyle : operationIsNew ? newOperationStyle : 'dim';
|
|
17
21
|
return styleText(color, level.padEnd(GUTTER_LEVEL_WIDTH));
|
|
18
22
|
}
|
|
@@ -49,12 +53,23 @@ export function formatLogEntry(log, verbose = false, previousLog) {
|
|
|
49
53
|
const date = new Date(log.timestamp);
|
|
50
54
|
const time = formatTime(date);
|
|
51
55
|
const day = formatDate(date);
|
|
52
|
-
const
|
|
56
|
+
const errorLog = isErrorLevel(log);
|
|
57
|
+
// error/fatal auto-expand details; verbose expands everything
|
|
58
|
+
const showDetails = verbose || errorLog;
|
|
59
|
+
// only verbose swaps the compact gutter for a level label
|
|
60
|
+
const useLevelGutter = verbose;
|
|
61
|
+
const gutter = logGutter(log, useLevelGutter, previousLog);
|
|
53
62
|
let line = `${day} ${time} ${gutter}${singleLine(log.message)}`;
|
|
54
|
-
if (
|
|
63
|
+
if (showDetails) {
|
|
55
64
|
const timestampWidth = `${day} ${time} `.length;
|
|
56
|
-
const
|
|
57
|
-
|
|
65
|
+
const gutterWidth = useLevelGutter ? GUTTER_LEVEL_WIDTH : GUTTER_SYMBOL_WIDTH;
|
|
66
|
+
const pad = ' '.repeat(timestampWidth + gutterWidth);
|
|
67
|
+
const detailLines = formatMetadataLines(log);
|
|
68
|
+
// auto-expanded error/fatal: show the level above the metadata since the gutter is just a symbol
|
|
69
|
+
if (errorLog && !verbose) {
|
|
70
|
+
detailLines.unshift(`${styleText('dim', 'level:')} ${styleText(errorStyle, log.level.toUpperCase())}`);
|
|
71
|
+
}
|
|
72
|
+
for (const metaLine of detailLines) {
|
|
58
73
|
line += `\n${pad}${metaLine}`;
|
|
59
74
|
}
|
|
60
75
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { BuildPayloadOptions } from '
|
|
1
|
+
import type { BuildPayloadOptions } from '../types.js';
|
|
2
2
|
export default function buildPayload(options: BuildPayloadOptions): Record<string, unknown>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { cwd } from 'node:process';
|
|
4
|
-
import { parseJsonObject } from '
|
|
4
|
+
import { parseJsonObject } from '../parse-json-object.js';
|
|
5
5
|
export default function buildPayload(options) {
|
|
6
6
|
const { data, file } = options;
|
|
7
7
|
let payload = {};
|
|
@@ -117,6 +117,9 @@ process.on('message', async (data) => {
|
|
|
117
117
|
)
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
// Replace resources JSON with Resources API
|
|
121
|
+
context.resources = createResourcesApi(context.resources)
|
|
122
|
+
|
|
120
123
|
json = await eventHandler({
|
|
121
124
|
context,
|
|
122
125
|
event,
|
|
@@ -149,3 +152,63 @@ process.on('message', async (data) => {
|
|
|
149
152
|
process.exit(1)
|
|
150
153
|
}
|
|
151
154
|
})
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The returned proxy wraps a function so the API itself is callable.
|
|
158
|
+
* @param {Record<string, ResourceEntry[]>} resources
|
|
159
|
+
* @returns {ResourcesApi}
|
|
160
|
+
*/
|
|
161
|
+
export function createResourcesApi(resources) {
|
|
162
|
+
const findByName = (name) => {
|
|
163
|
+
for (const group of Object.values(resources)) {
|
|
164
|
+
const found = group.find((r) => r.name === name)
|
|
165
|
+
if (found) return found
|
|
166
|
+
}
|
|
167
|
+
return undefined
|
|
168
|
+
}
|
|
169
|
+
let allCache
|
|
170
|
+
const all = () => (allCache ??= Object.values(resources).flat())
|
|
171
|
+
|
|
172
|
+
return /** @type {ResourcesApi} */ (
|
|
173
|
+
/** @type {unknown} */ (
|
|
174
|
+
/*
|
|
175
|
+
* The Proxy target is `findByName`, so invoking the API as a function —
|
|
176
|
+
* `context.resources('my-proj')` — bypasses the `get` trap entirely and
|
|
177
|
+
* calls `findByName` directly for a cross-type lookup by name.
|
|
178
|
+
*/
|
|
179
|
+
new Proxy(findByName, {
|
|
180
|
+
get: (_target, prop) => {
|
|
181
|
+
// context.resources.all() — flat array of every resource across types
|
|
182
|
+
if (prop === 'all') return all
|
|
183
|
+
// [...context.resources] / for (const r of context.resources) — iterate all
|
|
184
|
+
if (prop === Symbol.iterator) {
|
|
185
|
+
return function* () {
|
|
186
|
+
yield* all()
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Symbol property access (other than iterator above) and `then`
|
|
192
|
+
* lookups return undefined. The `then` guard prevents the API from
|
|
193
|
+
* looking like a thenable, so `await context.resources` resolves to
|
|
194
|
+
* the proxy itself rather than hanging or unwrapping unexpectedly.
|
|
195
|
+
*/
|
|
196
|
+
if (typeof prop !== 'string' || prop === 'then') {
|
|
197
|
+
return undefined
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* context.resources.<type>(name) — per-type lookup,
|
|
202
|
+
* e.g. context.resources.project('my-proj').
|
|
203
|
+
* Returns a function so the caller supplies the name;
|
|
204
|
+
* unknown types yield a function that always returns undefined.
|
|
205
|
+
*/
|
|
206
|
+
return (/** @type {string} */ name) =>
|
|
207
|
+
Object.hasOwn(resources, prop)
|
|
208
|
+
? resources[prop].find((r) => r.name === name)
|
|
209
|
+
: undefined
|
|
210
|
+
},
|
|
211
|
+
})
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BlueprintResource } from '@sanity/blueprints';
|
|
2
|
-
import { type DeployedResource, type FunctionResource, type Stack } from '
|
|
2
|
+
import { type DeployedResource, type FunctionResource, type Stack } from '../types.js';
|
|
3
3
|
export declare function getFunctionNames(resources: BlueprintResource[] | undefined): string[];
|
|
4
4
|
export declare function findFunctionInResources(resources: BlueprintResource[], name: string): FunctionResource;
|
|
5
5
|
/** @deprecated Use findFunctionInResources instead */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SANITY_FUNCTION_PREFIX } from '
|
|
2
|
-
import { isLocalFunctionResource, } from '
|
|
1
|
+
import { SANITY_FUNCTION_PREFIX } from '../../constants.js';
|
|
2
|
+
import { isLocalFunctionResource, } from '../types.js';
|
|
3
3
|
export function getFunctionNames(resources) {
|
|
4
4
|
return (resources
|
|
5
5
|
?.filter((r) => r.type.startsWith(SANITY_FUNCTION_PREFIX))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type FunctionGroqResource, type FunctionResource, type InvocationResponse, type InvokeContextOptions, type InvokeExecutionOptions, type InvokeGroqPayloadOptions, type InvokePayloadOptions } from '
|
|
1
|
+
import { type FunctionGroqResource, type FunctionResource, type InvocationResponse, type InvokeContextOptions, type InvokeExecutionOptions, type InvokeGroqPayloadOptions, type InvokePayloadOptions } from '../types.js';
|
|
2
2
|
export declare function sanitizeLogs(logs: string): string;
|
|
3
3
|
export declare function applyGroqRule(resource: FunctionGroqResource, payload: InvokeGroqPayloadOptions, projectId: string | undefined, dataset: string | undefined): Promise<any>;
|
|
4
4
|
export default function invoke(resource: FunctionResource, payload: InvokePayloadOptions, context: InvokeContextOptions, options: InvokeExecutionOptions): Promise<InvocationResponse>;
|
|
@@ -4,14 +4,15 @@ import { cwd } from 'node:process';
|
|
|
4
4
|
import { setTimeout } from 'node:timers';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import * as groq from 'groq-js';
|
|
7
|
-
import config from '
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
7
|
+
import config from '../../config.js';
|
|
8
|
+
import { groupBlueprintResources } from '../blueprints/group-resources.js';
|
|
9
|
+
import { isGroqContextOptions, } from '../types.js';
|
|
10
|
+
import { findFunctionEntryPoint } from './find-entry-point.js';
|
|
11
|
+
import { cleanupTempPackageJson, createTempPackageJson, doesPackageJsonExists, } from './package-json.js';
|
|
12
|
+
import { resolveResourceDependencies } from './resolve-dependencies.js';
|
|
13
|
+
import { shouldAutoResolveDependencies } from './should-auto-resolve-deps.js';
|
|
14
|
+
import { shouldTranspileFunction } from './should-transpile.js';
|
|
15
|
+
import { transpileFunction } from './transpile/function.js';
|
|
15
16
|
function getChildProcessWrapperPath() {
|
|
16
17
|
return fileURLToPath(new URL('./child-process-wrapper.js', import.meta.url));
|
|
17
18
|
}
|
|
@@ -157,6 +158,7 @@ export default async function invoke(resource, payload, context, options) {
|
|
|
157
158
|
context: {
|
|
158
159
|
...context,
|
|
159
160
|
local: true,
|
|
161
|
+
resources: groupBlueprintResources(context.resources ?? []),
|
|
160
162
|
...(isGroqContextOptions(context) && {
|
|
161
163
|
clientOptions: {
|
|
162
164
|
...context.clientOptions,
|
|
@@ -3,12 +3,12 @@ import { rm, stat } from 'node:fs/promises';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { cwd } from 'node:process';
|
|
5
5
|
import { MAX_ASSET_SIZE } from '../../constants.js';
|
|
6
|
-
import { transpileFunction } from '../transpile/transpile-function.js';
|
|
7
6
|
import { detectNativeModules, errorMessage } from './detect-native-modules.js';
|
|
8
|
-
import { getFolderSize } from './
|
|
7
|
+
import { getFolderSize } from './get-folder-size.js';
|
|
9
8
|
import { resolveResourceDependencies } from './resolve-dependencies.js';
|
|
10
9
|
import { shouldAutoResolveDependencies } from './should-auto-resolve-deps.js';
|
|
11
10
|
import { shouldTranspileFunction } from './should-transpile.js';
|
|
11
|
+
import { transpileFunction } from './transpile/function.js';
|
|
12
12
|
export async function prepareAsset({ resource, }, { installer } = {}) {
|
|
13
13
|
if (!resource.src)
|
|
14
14
|
throw new Error('Resource src is required');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FunctionResource, InstallerType } from '
|
|
1
|
+
import type { FunctionResource, InstallerType } from '../../types.js';
|
|
2
2
|
export declare const resolveViteRoot: (entry: string) => string;
|
|
3
3
|
export declare function transpileFunction(resource: FunctionResource, { installer }?: {
|
|
4
4
|
installer?: InstallerType;
|
|
@@ -5,10 +5,10 @@ import { cwd } from 'node:process';
|
|
|
5
5
|
import * as find from 'empathic/find';
|
|
6
6
|
import { build as viteBuild } from 'vite';
|
|
7
7
|
import tsConfigPaths from 'vite-tsconfig-paths';
|
|
8
|
-
import { detectNativeModulesPlugin } from '../
|
|
9
|
-
import { findFunctionEntryPoint } from '../
|
|
10
|
-
import { createPnpmRequire } from '../pnpm.js';
|
|
8
|
+
import { detectNativeModulesPlugin } from '../detect-native-modules.js';
|
|
9
|
+
import { findFunctionEntryPoint } from '../find-entry-point.js';
|
|
11
10
|
import { cleanupSourceMaps } from './cleanup-source-maps.js';
|
|
11
|
+
import { createPnpmRequire } from './pnpm.js';
|
|
12
12
|
import { verifyHandler } from './verify-handler.js';
|
|
13
13
|
export const resolveViteRoot = (entry) => {
|
|
14
14
|
const nodeModulesDir = find.dir('node_modules', { cwd: entry });
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
const userAgent = `${pkg.name}@${pkg.version}`;
|
|
1
|
+
import { RUNTIME_CLI_USER_AGENT } from '../config.js';
|
|
3
2
|
export default function getHeaders({ token, scopeId, scopeType }) {
|
|
4
3
|
return {
|
|
5
4
|
Accept: 'application/json',
|
|
@@ -7,6 +6,6 @@ export default function getHeaders({ token, scopeId, scopeType }) {
|
|
|
7
6
|
Authorization: `Bearer ${token}`,
|
|
8
7
|
'X-Sanity-Scope-Type': scopeType,
|
|
9
8
|
'X-Sanity-Scope-Id': scopeId,
|
|
10
|
-
'User-Agent':
|
|
9
|
+
'User-Agent': RUNTIME_CLI_USER_AGENT,
|
|
11
10
|
};
|
|
12
11
|
}
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -123,12 +123,16 @@ export interface InvokeGroqContextOptions {
|
|
|
123
123
|
functionResourceType: string;
|
|
124
124
|
/** The resource ID of the function container; resource ID that houses the function. */
|
|
125
125
|
functionResourceId: string;
|
|
126
|
+
/** All resources declared by the blueprint, used to populate `context.resources` at invoke time. */
|
|
127
|
+
resources?: BlueprintResource[];
|
|
126
128
|
}
|
|
127
129
|
/** @internal */
|
|
128
130
|
export interface InvokeScheduleContextOptions {
|
|
129
131
|
clientOptions: {
|
|
130
132
|
token?: string;
|
|
131
133
|
};
|
|
134
|
+
/** All resources declared by the blueprint, used to populate `context.resources` at invoke time. */
|
|
135
|
+
resources?: BlueprintResource[];
|
|
132
136
|
}
|
|
133
137
|
export type InvokeContextOptions = InvokeGroqContextOptions | InvokeScheduleContextOptions;
|
|
134
138
|
export declare function isGroqContextOptions(context: InvokeContextOptions): context is InvokeGroqContextOptions;
|
package/oclif.manifest.json
CHANGED
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": "15.1.
|
|
4
|
+
"version": "15.1.4",
|
|
5
5
|
"author": "Sanity Runtime Team",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"clean": "shx rm -rf dist oclif.manifest.json",
|
|
41
41
|
"copy:design-tokens": "shx rm -rf ./src/server/static/vendor/design-tokens && shx cp -r ./node_modules/@sanity-labs/design-tokens/dist/css ./src/server/static/vendor/design-tokens",
|
|
42
42
|
"copy:server": "shx cp -r ./src/server/static ./dist/server",
|
|
43
|
-
"copy:wrapper": "shx cp ./src/utils/child-process-wrapper.js ./dist/utils/child-process-wrapper.js",
|
|
43
|
+
"copy:wrapper": "shx cp ./src/utils/functions/child-process-wrapper.js ./dist/utils/functions/child-process-wrapper.js",
|
|
44
44
|
"lint": "biome ci",
|
|
45
45
|
"lint:write": "biome check --write",
|
|
46
46
|
"lint:fix": "npm run lint:write",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|