@sanity/runtime-cli 17.1.0-next.gcfbd613 → 17.2.0-next.ga4b9ae7
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/assets.js +15 -24
- package/dist/actions/blueprints/pre-deploy.d.ts +29 -0
- package/dist/actions/blueprints/pre-deploy.js +164 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/cores/blueprints/deploy.js +16 -64
- package/dist/utils/functions/child-process-wrapper.js +13 -171
- package/dist/utils/functions/child-runtime/console.d.ts +1 -0
- package/dist/utils/functions/child-runtime/console.js +50 -0
- package/dist/utils/functions/child-runtime/invoke.d.ts +4 -0
- package/dist/utils/functions/child-runtime/invoke.js +47 -0
- package/dist/utils/functions/child-runtime/resources.d.ts +4 -0
- package/dist/utils/functions/child-runtime/resources.js +59 -0
- package/dist/utils/studios/prepare-asset.d.ts +6 -0
- package/dist/utils/studios/prepare-asset.js +139 -0
- package/dist/utils/types.d.ts +4 -7
- package/dist/utils/types.js +2 -3
- package/oclif.manifest.json +1 -1
- package/package.json +9 -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/17.
|
|
23
|
+
@sanity/runtime-cli/17.2.0-next.ga4b9ae7 linux-x64 node-v24.18.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/v17.
|
|
106
|
+
_See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/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/v17.
|
|
143
|
+
_See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/blueprints/config.ts)_
|
|
144
144
|
|
|
145
145
|
## `sanity-run blueprints deploy`
|
|
146
146
|
|
|
@@ -194,7 +194,7 @@ EXAMPLES
|
|
|
194
194
|
$ sanity-run blueprints deploy --new-stack-name <new-name>
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
197
|
+
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/blueprints/deploy.ts)_
|
|
198
198
|
|
|
199
199
|
## `sanity-run blueprints destroy`
|
|
200
200
|
|
|
@@ -232,7 +232,7 @@ EXAMPLES
|
|
|
232
232
|
$ sanity-run blueprints destroy --stack <name-or-id> --project-id <projectId> --force --no-wait
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
-
_See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
235
|
+
_See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/blueprints/destroy.ts)_
|
|
236
236
|
|
|
237
237
|
## `sanity-run blueprints doctor`
|
|
238
238
|
|
|
@@ -264,7 +264,7 @@ EXAMPLES
|
|
|
264
264
|
$ sanity-run blueprints doctor --fix
|
|
265
265
|
```
|
|
266
266
|
|
|
267
|
-
_See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
267
|
+
_See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/blueprints/doctor.ts)_
|
|
268
268
|
|
|
269
269
|
## `sanity-run blueprints info`
|
|
270
270
|
|
|
@@ -301,7 +301,7 @@ EXAMPLES
|
|
|
301
301
|
$ sanity-run blueprints info --organization-id <orgId> --stack <name-or-id>
|
|
302
302
|
```
|
|
303
303
|
|
|
304
|
-
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
304
|
+
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/blueprints/info.ts)_
|
|
305
305
|
|
|
306
306
|
## `sanity-run blueprints init [DIR]`
|
|
307
307
|
|
|
@@ -365,7 +365,7 @@ EXAMPLES
|
|
|
365
365
|
$ sanity-run blueprints init old-stack --type <json|js|ts> --project-id <projectId> --stack-id <existingStackId>
|
|
366
366
|
```
|
|
367
367
|
|
|
368
|
-
_See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
368
|
+
_See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/blueprints/init.ts)_
|
|
369
369
|
|
|
370
370
|
## `sanity-run blueprints logs`
|
|
371
371
|
|
|
@@ -411,7 +411,7 @@ EXAMPLES
|
|
|
411
411
|
$ sanity-run blueprints logs --before 2026-05-01T00:00:00Z
|
|
412
412
|
```
|
|
413
413
|
|
|
414
|
-
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
414
|
+
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/blueprints/logs.ts)_
|
|
415
415
|
|
|
416
416
|
## `sanity-run blueprints mint-deploy-token`
|
|
417
417
|
|
|
@@ -456,7 +456,7 @@ EXAMPLES
|
|
|
456
456
|
$ sanity-run blueprints mint-deploy-token --organization-id <orgId>
|
|
457
457
|
```
|
|
458
458
|
|
|
459
|
-
_See code: [src/commands/blueprints/mint-deploy-token.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
459
|
+
_See code: [src/commands/blueprints/mint-deploy-token.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/blueprints/mint-deploy-token.ts)_
|
|
460
460
|
|
|
461
461
|
## `sanity-run blueprints plan`
|
|
462
462
|
|
|
@@ -489,7 +489,7 @@ EXAMPLES
|
|
|
489
489
|
$ sanity-run blueprints plan --organization-id <orgId> --stack <name-or-id>
|
|
490
490
|
```
|
|
491
491
|
|
|
492
|
-
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
492
|
+
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/blueprints/plan.ts)_
|
|
493
493
|
|
|
494
494
|
## `sanity-run blueprints promote`
|
|
495
495
|
|
|
@@ -525,7 +525,7 @@ EXAMPLES
|
|
|
525
525
|
$ sanity-run blueprints promote --new-stack-name <new-name>
|
|
526
526
|
```
|
|
527
527
|
|
|
528
|
-
_See code: [src/commands/blueprints/promote.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
528
|
+
_See code: [src/commands/blueprints/promote.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/blueprints/promote.ts)_
|
|
529
529
|
|
|
530
530
|
## `sanity-run blueprints stacks`
|
|
531
531
|
|
|
@@ -561,7 +561,7 @@ EXAMPLES
|
|
|
561
561
|
$ sanity-run blueprints stacks --organization-id <organizationId> --include-projects
|
|
562
562
|
```
|
|
563
563
|
|
|
564
|
-
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
564
|
+
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/blueprints/stacks.ts)_
|
|
565
565
|
|
|
566
566
|
## `sanity-run functions add`
|
|
567
567
|
|
|
@@ -613,7 +613,7 @@ EXAMPLES
|
|
|
613
613
|
$ sanity-run functions add --name my-function --type document-create --type document-update --lang js
|
|
614
614
|
```
|
|
615
615
|
|
|
616
|
-
_See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
616
|
+
_See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/functions/add.ts)_
|
|
617
617
|
|
|
618
618
|
## `sanity-run functions dev`
|
|
619
619
|
|
|
@@ -648,7 +648,7 @@ EXAMPLES
|
|
|
648
648
|
$ sanity-run functions dev --timeout 60
|
|
649
649
|
```
|
|
650
650
|
|
|
651
|
-
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
651
|
+
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/functions/dev.ts)_
|
|
652
652
|
|
|
653
653
|
## `sanity-run functions env add NAME KEY VALUE`
|
|
654
654
|
|
|
@@ -678,7 +678,7 @@ EXAMPLES
|
|
|
678
678
|
$ sanity-run functions env add MyFunction API_URL https://api.example.com/
|
|
679
679
|
```
|
|
680
680
|
|
|
681
|
-
_See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
681
|
+
_See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/functions/env/add.ts)_
|
|
682
682
|
|
|
683
683
|
## `sanity-run functions env list NAME`
|
|
684
684
|
|
|
@@ -705,7 +705,7 @@ EXAMPLES
|
|
|
705
705
|
$ sanity-run functions env list MyFunction
|
|
706
706
|
```
|
|
707
707
|
|
|
708
|
-
_See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
708
|
+
_See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/functions/env/list.ts)_
|
|
709
709
|
|
|
710
710
|
## `sanity-run functions env remove NAME KEY`
|
|
711
711
|
|
|
@@ -734,7 +734,7 @@ EXAMPLES
|
|
|
734
734
|
$ sanity-run functions env remove MyFunction API_URL
|
|
735
735
|
```
|
|
736
736
|
|
|
737
|
-
_See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
737
|
+
_See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/functions/env/remove.ts)_
|
|
738
738
|
|
|
739
739
|
## `sanity-run functions logs [NAME]`
|
|
740
740
|
|
|
@@ -774,7 +774,7 @@ EXAMPLES
|
|
|
774
774
|
$ sanity-run functions logs <name> --delete
|
|
775
775
|
```
|
|
776
776
|
|
|
777
|
-
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
777
|
+
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/functions/logs.ts)_
|
|
778
778
|
|
|
779
779
|
## `sanity-run functions test [NAME]`
|
|
780
780
|
|
|
@@ -831,7 +831,7 @@ EXAMPLES
|
|
|
831
831
|
$ sanity-run functions test <name> --event update --data-before '{ "title": "before" }' --data-after '{ "title": "after" }'
|
|
832
832
|
```
|
|
833
833
|
|
|
834
|
-
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
834
|
+
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v17.2.0-next.ga4b9ae7/src/commands/functions/test.ts)_
|
|
835
835
|
|
|
836
836
|
## `sanity-run help [COMMAND]`
|
|
837
837
|
|
|
@@ -1,48 +1,52 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
3
4
|
import AdmZip from 'adm-zip';
|
|
4
5
|
import { blueprintsUrl } from '../../config.js';
|
|
5
6
|
import { CONVERT_BYTES_TO_MB, MAX_ASSET_SIZE } from '../../constants.js';
|
|
6
7
|
import { prepareAsset as prepareFunctionAsset } from '../../utils/functions/prepare-asset.js';
|
|
7
8
|
import getHeaders from '../../utils/get-headers.js';
|
|
9
|
+
import { prepareStudioAsset } from '../../utils/studios/prepare-asset.js';
|
|
8
10
|
import { createTracedFetch } from '../../utils/traced-fetch.js';
|
|
9
11
|
import { isLocalFunctionResource, isStudioResource } from '../../utils/types.js';
|
|
10
12
|
const assetsUrl = blueprintsUrl('assets');
|
|
11
13
|
export const assetCheckUrl = `${assetsUrl}/check`;
|
|
12
14
|
export const assetStashUrl = `${assetsUrl}/stash`;
|
|
13
15
|
export async function stashAsset({ resource, auth, blueprintFileDir, logger, installer, }) {
|
|
16
|
+
let cleanup = async () => { };
|
|
14
17
|
try {
|
|
15
18
|
let b64;
|
|
16
19
|
let hash;
|
|
17
20
|
let extension;
|
|
18
|
-
let cleanup;
|
|
19
21
|
if (isLocalFunctionResource(resource)) {
|
|
20
22
|
const prepResult = await prepareFunctionAsset({ resource, blueprintFileDir, installer });
|
|
21
23
|
if (prepResult.success === false) {
|
|
24
|
+
await prepResult.cleanup();
|
|
22
25
|
return {
|
|
23
26
|
success: false,
|
|
24
27
|
error: prepResult.error,
|
|
25
28
|
};
|
|
26
29
|
}
|
|
30
|
+
cleanup = prepResult.cleanup;
|
|
27
31
|
const zipResult = await pathToB64ZipHash(prepResult.outputPath);
|
|
28
32
|
b64 = zipResult.b64;
|
|
29
33
|
hash = zipResult.hash;
|
|
30
34
|
extension = 'zip';
|
|
31
|
-
cleanup = prepResult.cleanup;
|
|
32
35
|
}
|
|
33
36
|
else if (isStudioResource(resource)) {
|
|
34
|
-
const prepResult = await prepareStudioAsset({ resource });
|
|
37
|
+
const prepResult = await prepareStudioAsset({ resource, blueprintFileDir });
|
|
35
38
|
if (prepResult.success === false) {
|
|
39
|
+
await prepResult.cleanup();
|
|
36
40
|
return {
|
|
37
41
|
success: false,
|
|
38
42
|
error: prepResult.error,
|
|
39
43
|
};
|
|
40
44
|
}
|
|
41
|
-
|
|
45
|
+
cleanup = prepResult.cleanup;
|
|
46
|
+
const buffer = await readFile(prepResult.outputPath);
|
|
42
47
|
b64 = buffer.toString('base64');
|
|
43
48
|
hash = hashBuffer(buffer);
|
|
44
49
|
extension = 'tar.gz';
|
|
45
|
-
cleanup = prepResult.cleanup;
|
|
46
50
|
}
|
|
47
51
|
else {
|
|
48
52
|
return {
|
|
@@ -61,28 +65,15 @@ export async function stashAsset({ resource, auth, blueprintFileDir, logger, ins
|
|
|
61
65
|
});
|
|
62
66
|
}
|
|
63
67
|
catch (err) {
|
|
68
|
+
try {
|
|
69
|
+
await cleanup();
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// ignore clean up errors
|
|
73
|
+
}
|
|
64
74
|
return { success: false, error: err instanceof Error ? err.message : `${err}` };
|
|
65
75
|
}
|
|
66
76
|
}
|
|
67
|
-
async function prepareStudioAsset({ resource, }) {
|
|
68
|
-
if (!fs.existsSync(resource.src)) {
|
|
69
|
-
return {
|
|
70
|
-
success: false,
|
|
71
|
-
async cleanup() {
|
|
72
|
-
// no op
|
|
73
|
-
},
|
|
74
|
-
error: `Property 'src' on resource with type '${resource.type}' must be a directory`,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
return {
|
|
78
|
-
success: true,
|
|
79
|
-
async cleanup() {
|
|
80
|
-
// no op
|
|
81
|
-
},
|
|
82
|
-
// studio must be pre built (e.g. with `npm run build`) and tarred/gzipped
|
|
83
|
-
outputPath: resource.src,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
77
|
async function stashSingleAsset({ b64, hash, cleanup, resource, auth, logger, extension = 'zip', }) {
|
|
87
78
|
const fetchFn = createTracedFetch(logger);
|
|
88
79
|
try {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { BlueprintResource } from '@sanity/blueprints';
|
|
2
|
+
import type { Logger } from '../../utils/logger.js';
|
|
3
|
+
import { type AuthParams, type InstallerType, type ScopeType } from '../../utils/types.js';
|
|
4
|
+
type PreDeployResult = {
|
|
5
|
+
success: false;
|
|
6
|
+
error: string;
|
|
7
|
+
code?: string;
|
|
8
|
+
exitCode?: number;
|
|
9
|
+
suggestions?: string[];
|
|
10
|
+
} | {
|
|
11
|
+
success: true;
|
|
12
|
+
};
|
|
13
|
+
type PreDeployResourceOptions = {
|
|
14
|
+
auth: AuthParams;
|
|
15
|
+
blueprintFileDir: string;
|
|
16
|
+
installer: InstallerType;
|
|
17
|
+
log: Logger;
|
|
18
|
+
};
|
|
19
|
+
type PreDeployOptions = {
|
|
20
|
+
scopeType: ScopeType;
|
|
21
|
+
scopeId: string;
|
|
22
|
+
resources: BlueprintResource[];
|
|
23
|
+
stackId: string;
|
|
24
|
+
stackName: string;
|
|
25
|
+
bin: string;
|
|
26
|
+
verbose: boolean | undefined;
|
|
27
|
+
} & PreDeployResourceOptions;
|
|
28
|
+
export declare function preDeploy(options: PreDeployOptions): Promise<PreDeployResult>;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { env } from 'node:process';
|
|
2
|
+
import { resolveDeployedResources } from '../../utils/blueprints/resolve-deployed-resources.js';
|
|
3
|
+
import { niceId } from '../../utils/display/presenters.js';
|
|
4
|
+
import { CODE_OPERATION_UNCONFIRMED, EXIT_OPERATION_UNCONFIRMED } from '../../utils/exit-codes.js';
|
|
5
|
+
import { styleText } from '../../utils/style-text.js';
|
|
6
|
+
import { isAssetResource, } from '../../utils/types.js';
|
|
7
|
+
import { stashAsset } from './assets.js';
|
|
8
|
+
import { updateStack } from './stacks.js';
|
|
9
|
+
import { waitForOperation } from './wait-for-operation.js';
|
|
10
|
+
const DEFAULT_ASSET_TIMEOUT = 180;
|
|
11
|
+
const assetTimeoutS = Number(process.env.SANITY_ASSET_TIMEOUT) || DEFAULT_ASSET_TIMEOUT;
|
|
12
|
+
const assetTimeoutMs = assetTimeoutS * 1000;
|
|
13
|
+
const warnTimeoutMs = assetTimeoutMs / 3;
|
|
14
|
+
export async function preDeploy(options) {
|
|
15
|
+
const { resources, stackId, auth, blueprintFileDir, installer, log } = options;
|
|
16
|
+
const hasAssetResources = resources.some(isAssetResource);
|
|
17
|
+
if (hasAssetResources) {
|
|
18
|
+
let assetResources;
|
|
19
|
+
if (env.SANITY_BLUEPRINTS_PRE_DEPLOY_ENABLED === 'true') {
|
|
20
|
+
const preDeployStackResult = await preDeployStack(options);
|
|
21
|
+
if (!preDeployStackResult.success) {
|
|
22
|
+
return preDeployStackResult;
|
|
23
|
+
}
|
|
24
|
+
/** Look up resources from the back-end and attach the externalId if possible */
|
|
25
|
+
const resolvedResources = await resolveDeployedResources({
|
|
26
|
+
resources,
|
|
27
|
+
stackId,
|
|
28
|
+
auth,
|
|
29
|
+
logger: log,
|
|
30
|
+
});
|
|
31
|
+
assetResources = resolvedResources.filter(isAssetResource);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
assetResources = resources.filter(isAssetResource);
|
|
35
|
+
}
|
|
36
|
+
log('Processing assets...');
|
|
37
|
+
for (const resource of assetResources) {
|
|
38
|
+
const preDeployResult = await preDeployResource(resource, {
|
|
39
|
+
auth,
|
|
40
|
+
blueprintFileDir,
|
|
41
|
+
installer,
|
|
42
|
+
log,
|
|
43
|
+
});
|
|
44
|
+
if (!preDeployResult.success)
|
|
45
|
+
return preDeployResult;
|
|
46
|
+
const idx = resources.findIndex((r) => r.name === resource.name);
|
|
47
|
+
if (idx === -1)
|
|
48
|
+
throw new Error('Unable to update resource asset');
|
|
49
|
+
resources[idx] = preDeployResult.resource;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { success: true };
|
|
53
|
+
}
|
|
54
|
+
async function preDeployStack(options) {
|
|
55
|
+
const { scopeType, scopeId, stackId, stackName, resources, auth, log, bin, verbose } = options;
|
|
56
|
+
const spinner = log.ora('Starting pre-deploy...').start();
|
|
57
|
+
const stackMutation = {
|
|
58
|
+
scopeType,
|
|
59
|
+
scopeId,
|
|
60
|
+
name: stackName,
|
|
61
|
+
preDeploy: true,
|
|
62
|
+
document: { resources },
|
|
63
|
+
};
|
|
64
|
+
const { ok: deployOk, stack, error: deployError, } = await updateStack({ stackId, stackMutation, auth, logger: log });
|
|
65
|
+
if (!deployOk) {
|
|
66
|
+
spinner.fail(`${styleText('red', 'Failed')} to complete Stack pre-deployment`);
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
error: deployError || 'Failed to complete Stack pre-deployment',
|
|
70
|
+
suggestions: [
|
|
71
|
+
`Run \`npx ${bin} blueprints plan\` to preview changes before deploying.`,
|
|
72
|
+
`Run \`npx ${bin} blueprints doctor\` to check your configuration.`,
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
spinner.stop().clear();
|
|
77
|
+
log(styleText('dim', 'Stack deployment progress:'));
|
|
78
|
+
log('');
|
|
79
|
+
const outcome = await waitForOperation({
|
|
80
|
+
stackId,
|
|
81
|
+
operationId: stack.operationId,
|
|
82
|
+
auth,
|
|
83
|
+
log,
|
|
84
|
+
bin,
|
|
85
|
+
verbose,
|
|
86
|
+
progressNoun: 'pre-deployment',
|
|
87
|
+
});
|
|
88
|
+
if (outcome.type === 'completed') {
|
|
89
|
+
log(styleText(['bold', 'green'], 'Stack pre-deployment completed!'));
|
|
90
|
+
}
|
|
91
|
+
else if (outcome.type === 'unconfirmed') {
|
|
92
|
+
return {
|
|
93
|
+
success: false,
|
|
94
|
+
error: `Stack pre-deployment was accepted but completion could not be confirmed${outcome.error ? ` (${outcome.error})` : ''}.`,
|
|
95
|
+
code: CODE_OPERATION_UNCONFIRMED,
|
|
96
|
+
exitCode: EXIT_OPERATION_UNCONFIRMED,
|
|
97
|
+
suggestions: [
|
|
98
|
+
'The pre-deployment may or may not have finished on Sanity servers.',
|
|
99
|
+
`Run \`npx ${bin} blueprints info\` to check status.`,
|
|
100
|
+
`Run \`npx ${bin} blueprints logs --watch\` to keep streaming logs.`,
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
return {
|
|
106
|
+
success: false,
|
|
107
|
+
error: 'Stack pre-deployment failed',
|
|
108
|
+
suggestions: [
|
|
109
|
+
...outcome.logHints,
|
|
110
|
+
'Review the pre-deployment output above for error details.',
|
|
111
|
+
`Run \`npx ${bin} blueprints logs --verbose\` for more context.`,
|
|
112
|
+
`Run \`npx ${bin} blueprints plan\` to identify issues with your Blueprint.`,
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return { success: true };
|
|
117
|
+
}
|
|
118
|
+
async function preDeployResource(resource, options) {
|
|
119
|
+
const { auth, blueprintFileDir, installer, log } = options;
|
|
120
|
+
const fnSpinner = log.ora({ text: `Processing ${resource.name}...`, prefixText: ' ' }).start();
|
|
121
|
+
const warnTimer = setTimeout(() => {
|
|
122
|
+
fnSpinner.text = `Still processing ${resource.name}, this can take a moment...`;
|
|
123
|
+
}, warnTimeoutMs);
|
|
124
|
+
let assetTimeoutTimer;
|
|
125
|
+
let result;
|
|
126
|
+
try {
|
|
127
|
+
result = await Promise.race([
|
|
128
|
+
stashAsset({ resource, blueprintFileDir, auth, logger: log, installer }),
|
|
129
|
+
new Promise((_, reject) => {
|
|
130
|
+
assetTimeoutTimer = setTimeout(() => {
|
|
131
|
+
reject(new Error(`Processing ${resource.name} timed out after ${assetTimeoutS}s`));
|
|
132
|
+
}, assetTimeoutMs);
|
|
133
|
+
}),
|
|
134
|
+
]);
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
138
|
+
fnSpinner.fail(msg);
|
|
139
|
+
return { success: false, error: msg };
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
clearTimeout(warnTimer);
|
|
143
|
+
clearTimeout(assetTimeoutTimer);
|
|
144
|
+
}
|
|
145
|
+
if (result.success && result.assetId) {
|
|
146
|
+
const updatedResource = { ...resource, src: result.assetId };
|
|
147
|
+
fnSpinner.succeed(`${updatedResource.name} ${niceId(result.assetId)}`);
|
|
148
|
+
log(` Source: ${updatedResource.src}`);
|
|
149
|
+
if (result.hash) {
|
|
150
|
+
if (result.hash.length > 24) {
|
|
151
|
+
log.verbose(` Hash: ${result.hash.slice(0, 8)}...${result.hash.slice(-12)}`);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
log.verbose(` Hash: ${result.hash}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (result.exists)
|
|
158
|
+
log.verbose(' Asset unchanged');
|
|
159
|
+
return { success: true, resource: updatedResource };
|
|
160
|
+
}
|
|
161
|
+
const errorMsg = `Failed uploading ${resource.name} asset, deploy has stopped`;
|
|
162
|
+
fnSpinner.fail(errorMsg);
|
|
163
|
+
return { success: false, error: result.error || 'Failed to process asset' };
|
|
164
|
+
}
|
package/dist/constants.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export declare const SANITY_PROJECT = "sanity.project";
|
|
|
9
9
|
export declare const SANITY_PROJECT_CORS = "sanity.project.cors";
|
|
10
10
|
export declare const SANITY_PROJECT_DATASET = "sanity.project.dataset";
|
|
11
11
|
export declare const SANITY_PROJECT_WEBHOOK = "sanity.project.webhook";
|
|
12
|
+
export declare const SANITY_STUDIO = "sanity.studio";
|
|
12
13
|
export declare const EVENT_DOCUMENT_PUBLISH = "document-publish";
|
|
13
14
|
export declare const EVENT_DOCUMENT_CREATE = "document-create";
|
|
14
15
|
export declare const EVENT_DOCUMENT_UPDATE = "document-update";
|
package/dist/constants.js
CHANGED
|
@@ -9,6 +9,7 @@ export const SANITY_PROJECT = 'sanity.project';
|
|
|
9
9
|
export const SANITY_PROJECT_CORS = 'sanity.project.cors';
|
|
10
10
|
export const SANITY_PROJECT_DATASET = 'sanity.project.dataset';
|
|
11
11
|
export const SANITY_PROJECT_WEBHOOK = 'sanity.project.webhook';
|
|
12
|
+
export const SANITY_STUDIO = 'sanity.studio';
|
|
12
13
|
export const EVENT_DOCUMENT_PUBLISH = 'document-publish';
|
|
13
14
|
export const EVENT_DOCUMENT_CREATE = 'document-create';
|
|
14
15
|
export const EVENT_DOCUMENT_UPDATE = 'document-update';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { dirname } from 'node:path';
|
|
2
|
-
import {
|
|
2
|
+
import { preDeploy } from '../../actions/blueprints/pre-deploy.js';
|
|
3
3
|
import { getStack, updateStack } from '../../actions/blueprints/stacks.js';
|
|
4
4
|
import { waitForOperation } from '../../actions/blueprints/wait-for-operation.js';
|
|
5
5
|
import { checkUserPermission } from '../../actions/sanity/access.js';
|
|
@@ -7,12 +7,7 @@ import { createHintCollector } from '../../utils/blueprints/hints.js';
|
|
|
7
7
|
import { niceId } from '../../utils/display/presenters.js';
|
|
8
8
|
import { CODE_OPERATION_UNCONFIRMED, EXIT_OPERATION_UNCONFIRMED } from '../../utils/exit-codes.js';
|
|
9
9
|
import { styleText } from '../../utils/style-text.js';
|
|
10
|
-
import { isAssetResource } from '../../utils/types.js';
|
|
11
10
|
import { getWarnings } from '../../utils/warnings.js';
|
|
12
|
-
const DEFAULT_ASSET_TIMEOUT = 60;
|
|
13
|
-
const assetTimeoutS = Number(process.env.SANITY_ASSET_TIMEOUT) || DEFAULT_ASSET_TIMEOUT;
|
|
14
|
-
const assetTimeoutMs = assetTimeoutS * 1000;
|
|
15
|
-
const warnTimeoutMs = assetTimeoutMs / 2;
|
|
16
11
|
export async function blueprintDeployCore(options) {
|
|
17
12
|
const { bin = 'sanity', log, auth, stackId, scopeType, scopeId, deployedStack, blueprint, flags, } = options;
|
|
18
13
|
const { verbose } = flags;
|
|
@@ -39,17 +34,21 @@ export async function blueprintDeployCore(options) {
|
|
|
39
34
|
};
|
|
40
35
|
}
|
|
41
36
|
const resources = [...blueprint.resources];
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
37
|
+
const preDeployResult = await preDeploy({
|
|
38
|
+
scopeType,
|
|
39
|
+
scopeId,
|
|
40
|
+
resources,
|
|
41
|
+
stackId,
|
|
42
|
+
stackName,
|
|
43
|
+
auth,
|
|
44
|
+
blueprintFileDir,
|
|
45
|
+
installer,
|
|
46
|
+
log,
|
|
47
|
+
bin,
|
|
48
|
+
verbose,
|
|
49
|
+
});
|
|
50
|
+
if (!preDeployResult?.success) {
|
|
51
|
+
return preDeployResult;
|
|
53
52
|
}
|
|
54
53
|
const spinner = log.ora('Deploying...').start();
|
|
55
54
|
const { ok: deployOk, stack, error: deployError, } = await updateStack({
|
|
@@ -152,53 +151,6 @@ export async function blueprintDeployCore(options) {
|
|
|
152
151
|
return { success: false, error: errorMessage };
|
|
153
152
|
}
|
|
154
153
|
}
|
|
155
|
-
async function preDeploy(resource, options) {
|
|
156
|
-
const { auth, blueprintFileDir, installer, log } = options;
|
|
157
|
-
const fnSpinner = log.ora({ text: `Processing ${resource.name}...`, prefixText: ' ' }).start();
|
|
158
|
-
const warnTimer = setTimeout(() => {
|
|
159
|
-
fnSpinner.text = `Still processing ${resource.name}, this can take a moment...`;
|
|
160
|
-
}, warnTimeoutMs);
|
|
161
|
-
let assetTimeoutTimer;
|
|
162
|
-
let result;
|
|
163
|
-
try {
|
|
164
|
-
result = await Promise.race([
|
|
165
|
-
stashAsset({ resource, blueprintFileDir, auth, logger: log, installer }),
|
|
166
|
-
new Promise((_, reject) => {
|
|
167
|
-
assetTimeoutTimer = setTimeout(() => {
|
|
168
|
-
reject(new Error(`Processing ${resource.name} timed out after ${assetTimeoutS}s`));
|
|
169
|
-
}, assetTimeoutMs);
|
|
170
|
-
}),
|
|
171
|
-
]);
|
|
172
|
-
}
|
|
173
|
-
catch (err) {
|
|
174
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
175
|
-
fnSpinner.fail(msg);
|
|
176
|
-
return { success: false, error: msg };
|
|
177
|
-
}
|
|
178
|
-
finally {
|
|
179
|
-
clearTimeout(warnTimer);
|
|
180
|
-
clearTimeout(assetTimeoutTimer);
|
|
181
|
-
}
|
|
182
|
-
if (result.success && result.assetId) {
|
|
183
|
-
const updatedResource = { ...resource, src: result.assetId };
|
|
184
|
-
fnSpinner.succeed(`${updatedResource.name} ${niceId(result.assetId)}`);
|
|
185
|
-
log(` Source: ${updatedResource.src}`);
|
|
186
|
-
if (result.hash) {
|
|
187
|
-
if (result.hash.length > 24) {
|
|
188
|
-
log.verbose(` Hash: ${result.hash.slice(0, 8)}...${result.hash.slice(-12)}`);
|
|
189
|
-
}
|
|
190
|
-
else {
|
|
191
|
-
log.verbose(` Hash: ${result.hash}`);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
if (result.exists)
|
|
195
|
-
log.verbose(' Asset unchanged');
|
|
196
|
-
return { success: true, resource: updatedResource };
|
|
197
|
-
}
|
|
198
|
-
const errorMsg = `Failed uploading ${resource.name} asset, deploy has stopped`;
|
|
199
|
-
fnSpinner.fail(errorMsg);
|
|
200
|
-
return { success: false, error: result.error || 'Failed to process asset' };
|
|
201
|
-
}
|
|
202
154
|
const CHECK_LEGACY_DEPLOY_PERMISSION = false;
|
|
203
155
|
const BLUEPRINTS_PERMISSION_ENFORCEMENT_DATE = 'July 1, 2026';
|
|
204
156
|
async function checkLegacyDeployPermission({ auth, scopeType, scopeId, log, }) {
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import {table as renderTable} from 'node:console'
|
|
2
1
|
import {existsSync, statSync} from 'node:fs'
|
|
3
2
|
import {isAbsolute, join} from 'node:path'
|
|
4
3
|
import process from 'node:process'
|
|
5
4
|
import {pathToFileURL} from 'node:url'
|
|
6
|
-
import {
|
|
5
|
+
import {installConsole} from './child-runtime/console.js'
|
|
6
|
+
import {createInvoker} from './child-runtime/invoke.js'
|
|
7
|
+
import {createResourcesApi} from './child-runtime/resources.js'
|
|
8
|
+
|
|
9
|
+
installConsole()
|
|
10
|
+
const invoker = createInvoker()
|
|
7
11
|
|
|
8
12
|
export function getFunctionSource(src) {
|
|
9
13
|
const pathToCheck = isAbsolute(src) ? src : join(process.cwd(), src)
|
|
@@ -18,91 +22,6 @@ export function getFunctionSource(src) {
|
|
|
18
22
|
return pathToFileURL(pathToCheck).href
|
|
19
23
|
}
|
|
20
24
|
|
|
21
|
-
// Monkey patch console menthods to have logs match server log format
|
|
22
|
-
function logPrefix(level, ...args) {
|
|
23
|
-
const date = new Date()
|
|
24
|
-
const shouldUseColors = process.env.FORCE_COLOR === '1'
|
|
25
|
-
const message = args
|
|
26
|
-
.map((arg) =>
|
|
27
|
-
typeof arg === 'string' ? arg : inspect(arg, {depth: null, colors: shouldUseColors}),
|
|
28
|
-
)
|
|
29
|
-
.join(' ')
|
|
30
|
-
return `${date.toLocaleDateString()} ${date.toLocaleTimeString()} ${level.toUpperCase()} ${message}`
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
console.log = (...args) => {
|
|
34
|
-
process.stdout.write(`${logPrefix('info', ...args)}\n`)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
console.info = (...args) => {
|
|
38
|
-
process.stdout.write(`${logPrefix('info', ...args)}\n`)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
console.dir = (obj, options) => {
|
|
42
|
-
const shouldUseColors = process.env.FORCE_COLOR === '1'
|
|
43
|
-
const inspectOptions = {...options, colors: shouldUseColors}
|
|
44
|
-
process.stdout.write(`${logPrefix('info', inspect(obj, inspectOptions))}\n`)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
console.table = (data, columns) => {
|
|
48
|
-
const prefix = logPrefix('info')
|
|
49
|
-
|
|
50
|
-
// Capture table output
|
|
51
|
-
const originalWrite = process.stdout.write.bind(process.stdout)
|
|
52
|
-
let buffer = ''
|
|
53
|
-
|
|
54
|
-
process.stdout.write = (chunk, _encoding, callback) => {
|
|
55
|
-
buffer += chunk
|
|
56
|
-
if (typeof callback === 'function') callback()
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
renderTable(data, columns)
|
|
60
|
-
|
|
61
|
-
// Restore and print
|
|
62
|
-
process.stdout.write = originalWrite
|
|
63
|
-
for (const line of buffer.split('\n')) {
|
|
64
|
-
if (line.trim()) {
|
|
65
|
-
const message = `${!line.startsWith(prefix) ? `${prefix} ${line}` : line}`.trim()
|
|
66
|
-
process.stdout.write(`${message}\n`)
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
console.warn = (...args) => {
|
|
72
|
-
process.stdout.write(`${logPrefix('warn', ...args)}\n`)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
console.error = (...args) => {
|
|
76
|
-
process.stdout.write(`${logPrefix('error', ...args)}\n`)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Pending nested `context.invoke` calls, keyed by correlation id. Each entry
|
|
81
|
-
* holds the resolve/reject of the Promise returned to the user's handler; it is
|
|
82
|
-
* settled when the matching `invoke-response` arrives from the parent.
|
|
83
|
-
* @type {Map<string, {resolve: (value: unknown) => void, reject: (reason: Error) => void}>}
|
|
84
|
-
*/
|
|
85
|
-
const pendingInvokes = new Map()
|
|
86
|
-
let invokeSeq = 0
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* `context.invoke(name, payload)` — ask the parent to execute another blueprint
|
|
90
|
-
* function and resolve with its return value. Sent over IPC and correlated by id.
|
|
91
|
-
* @param {string} name
|
|
92
|
-
* @param {Record<string, unknown>} [payload]
|
|
93
|
-
* @returns {Promise<unknown>}
|
|
94
|
-
*/
|
|
95
|
-
function invokeFunction(name, payload = {}) {
|
|
96
|
-
if (typeof name !== 'string' || name.length === 0) {
|
|
97
|
-
return Promise.reject(new Error('context.invoke requires a function name'))
|
|
98
|
-
}
|
|
99
|
-
const id = String(++invokeSeq)
|
|
100
|
-
return new Promise((resolve, reject) => {
|
|
101
|
-
pendingInvokes.set(id, {resolve, reject})
|
|
102
|
-
process.send(JSON.stringify({type: 'invoke-request', id, name, payload}))
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
|
|
106
25
|
// Listen for IPC messages from the parent process.
|
|
107
26
|
process.on('message', async (data) => {
|
|
108
27
|
let jsonData = null
|
|
@@ -115,18 +34,7 @@ process.on('message', async (data) => {
|
|
|
115
34
|
|
|
116
35
|
// Response to a nested context.invoke() — route to the awaiting Promise and stop.
|
|
117
36
|
if (jsonData?.type === 'invoke-response') {
|
|
118
|
-
|
|
119
|
-
if (!pending) return
|
|
120
|
-
pendingInvokes.delete(jsonData.id)
|
|
121
|
-
if (jsonData.ok) {
|
|
122
|
-
pending.resolve(jsonData.result?.json)
|
|
123
|
-
} else {
|
|
124
|
-
const {message, stack, name} = jsonData.error ?? {}
|
|
125
|
-
const error = new Error(message ?? 'Nested invoke failed')
|
|
126
|
-
if (stack) error.stack = stack
|
|
127
|
-
if (name) error.name = name
|
|
128
|
-
pending.reject(error)
|
|
129
|
-
}
|
|
37
|
+
invoker.handleResponse(jsonData)
|
|
130
38
|
return
|
|
131
39
|
}
|
|
132
40
|
|
|
@@ -160,25 +68,20 @@ process.on('message', async (data) => {
|
|
|
160
68
|
try {
|
|
161
69
|
// Import the function code
|
|
162
70
|
const entry = await import(getFunctionSource(srcPath))
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
throw new Error(
|
|
167
|
-
'No valid handler found. Please provide a default export or a named export, "handler"',
|
|
168
|
-
)
|
|
71
|
+
const handler = entry.handler || entry.default
|
|
72
|
+
if (typeof handler !== 'function') {
|
|
73
|
+
throw new Error('No valid handler found. Provide a default export or a named "handler".')
|
|
169
74
|
}
|
|
170
75
|
|
|
171
76
|
// Replace resources JSON with Resources API
|
|
172
77
|
context.resources = createResourcesApi(context.resources)
|
|
173
78
|
|
|
174
79
|
// Allow the handler to invoke other blueprint functions by name.
|
|
175
|
-
context.invoke =
|
|
176
|
-
|
|
177
|
-
json = await eventHandler({
|
|
80
|
+
context.invoke = invoker.invoke
|
|
81
|
+
json = await handler({
|
|
178
82
|
context,
|
|
179
83
|
event,
|
|
180
|
-
|
|
181
|
-
done: async (_tags) => new Response(null, {status: 204}),
|
|
84
|
+
done: async () => new Response(null, {status: 204}),
|
|
182
85
|
})
|
|
183
86
|
|
|
184
87
|
// Restore streams
|
|
@@ -191,7 +94,6 @@ process.on('message', async (data) => {
|
|
|
191
94
|
// Restore streams on error
|
|
192
95
|
process.stdout.write = originalStdoutWrite
|
|
193
96
|
process.stderr.write = originalStderrWrite
|
|
194
|
-
|
|
195
97
|
const errorInfo = {
|
|
196
98
|
type: 'result',
|
|
197
99
|
json: null,
|
|
@@ -207,63 +109,3 @@ process.on('message', async (data) => {
|
|
|
207
109
|
process.exit(1)
|
|
208
110
|
}
|
|
209
111
|
})
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* The returned proxy wraps a function so the API itself is callable.
|
|
213
|
-
* @param {Record<string, ResourceEntry[]>} resources
|
|
214
|
-
* @returns {ResourcesApi}
|
|
215
|
-
*/
|
|
216
|
-
export function createResourcesApi(resources) {
|
|
217
|
-
const findByName = (name) => {
|
|
218
|
-
for (const group of Object.values(resources)) {
|
|
219
|
-
const found = group.find((r) => r.name === name)
|
|
220
|
-
if (found) return found
|
|
221
|
-
}
|
|
222
|
-
return undefined
|
|
223
|
-
}
|
|
224
|
-
let allCache
|
|
225
|
-
const all = () => (allCache ??= Object.values(resources).flat())
|
|
226
|
-
|
|
227
|
-
return /** @type {ResourcesApi} */ (
|
|
228
|
-
/** @type {unknown} */ (
|
|
229
|
-
/*
|
|
230
|
-
* The Proxy target is `findByName`, so invoking the API as a function —
|
|
231
|
-
* `context.resources('my-proj')` — bypasses the `get` trap entirely and
|
|
232
|
-
* calls `findByName` directly for a cross-type lookup by name.
|
|
233
|
-
*/
|
|
234
|
-
new Proxy(findByName, {
|
|
235
|
-
get: (_target, prop) => {
|
|
236
|
-
// context.resources.all() — flat array of every resource across types
|
|
237
|
-
if (prop === 'all') return all
|
|
238
|
-
// [...context.resources] / for (const r of context.resources) — iterate all
|
|
239
|
-
if (prop === Symbol.iterator) {
|
|
240
|
-
return function* () {
|
|
241
|
-
yield* all()
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Symbol property access (other than iterator above) and `then`
|
|
247
|
-
* lookups return undefined. The `then` guard prevents the API from
|
|
248
|
-
* looking like a thenable, so `await context.resources` resolves to
|
|
249
|
-
* the proxy itself rather than hanging or unwrapping unexpectedly.
|
|
250
|
-
*/
|
|
251
|
-
if (typeof prop !== 'string' || prop === 'then') {
|
|
252
|
-
return undefined
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* context.resources.<type>(name) — per-type lookup,
|
|
257
|
-
* e.g. context.resources.project('my-proj').
|
|
258
|
-
* Returns a function so the caller supplies the name;
|
|
259
|
-
* unknown types yield a function that always returns undefined.
|
|
260
|
-
*/
|
|
261
|
-
return (/** @type {string} */ name) =>
|
|
262
|
-
Object.hasOwn(resources, prop)
|
|
263
|
-
? resources[prop].find((r) => r.name === name)
|
|
264
|
-
: undefined
|
|
265
|
-
},
|
|
266
|
-
})
|
|
267
|
-
)
|
|
268
|
-
)
|
|
269
|
-
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function installConsole(): void
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {table as renderTable} from 'node:console'
|
|
2
|
+
import process from 'node:process'
|
|
3
|
+
import {inspect} from 'node:util'
|
|
4
|
+
|
|
5
|
+
// Monkey patch console methods to have logs match server log format
|
|
6
|
+
function logPrefix(level, ...args) {
|
|
7
|
+
const date = new Date()
|
|
8
|
+
const shouldUseColors = process.env.FORCE_COLOR === '1'
|
|
9
|
+
const message = args
|
|
10
|
+
.map((arg) =>
|
|
11
|
+
typeof arg === 'string' ? arg : inspect(arg, {depth: null, colors: shouldUseColors}),
|
|
12
|
+
)
|
|
13
|
+
.join(' ')
|
|
14
|
+
return `${date.toLocaleDateString()} ${date.toLocaleTimeString()} ${level.toUpperCase()} ${message}`
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function installConsole() {
|
|
18
|
+
console.log = (...args) => process.stdout.write(`${logPrefix('info', ...args)}\n`)
|
|
19
|
+
console.info = (...args) => process.stdout.write(`${logPrefix('info', ...args)}\n`)
|
|
20
|
+
console.warn = (...args) => process.stdout.write(`${logPrefix('warn', ...args)}\n`)
|
|
21
|
+
console.error = (...args) => process.stdout.write(`${logPrefix('error', ...args)}\n`)
|
|
22
|
+
console.dir = (obj, options) => {
|
|
23
|
+
const shouldUseColors = process.env.FORCE_COLOR === '1'
|
|
24
|
+
const inspectOptions = {...options, colors: shouldUseColors}
|
|
25
|
+
process.stdout.write(`${logPrefix('info', inspect(obj, inspectOptions))}\n`)
|
|
26
|
+
}
|
|
27
|
+
console.table = (data, columns) => {
|
|
28
|
+
const prefix = logPrefix('info')
|
|
29
|
+
|
|
30
|
+
// Capture table output
|
|
31
|
+
const originalWrite = process.stdout.write.bind(process.stdout)
|
|
32
|
+
let buffer = ''
|
|
33
|
+
|
|
34
|
+
process.stdout.write = (chunk, _encoding, callback) => {
|
|
35
|
+
buffer += chunk
|
|
36
|
+
if (typeof callback === 'function') callback()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
renderTable(data, columns)
|
|
40
|
+
|
|
41
|
+
// Restore and print
|
|
42
|
+
process.stdout.write = originalWrite
|
|
43
|
+
for (const line of buffer.split('\n')) {
|
|
44
|
+
if (line.trim()) {
|
|
45
|
+
const message = `${!line.startsWith(prefix) ? `${prefix} ${line}` : line}`.trim()
|
|
46
|
+
process.stdout.write(`${message}\n`)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import process from 'node:process'
|
|
2
|
+
|
|
3
|
+
export function createInvoker() {
|
|
4
|
+
/**
|
|
5
|
+
* Pending nested `context.invoke` calls, keyed by correlation id. Each entry
|
|
6
|
+
* holds the resolve/reject of the Promise returned to the user's handler; it is
|
|
7
|
+
* settled when the matching `invoke-response` arrives from the parent.
|
|
8
|
+
* @type {Map<string, {resolve: (value: unknown) => void, reject: (reason: Error) => void}>}
|
|
9
|
+
*/
|
|
10
|
+
const pending = new Map()
|
|
11
|
+
let invokeSeq = 0
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* `context.invoke(name, payload)` — ask the parent to execute another blueprint
|
|
15
|
+
* function and resolve with its return value. Sent over IPC and correlated by id.
|
|
16
|
+
* @param {string} name
|
|
17
|
+
* @param {Record<string, unknown>} [payload]
|
|
18
|
+
* @returns {Promise<unknown>}
|
|
19
|
+
*/
|
|
20
|
+
function invoke(name, payload = {}) {
|
|
21
|
+
if (typeof name !== 'string' || name.length === 0) {
|
|
22
|
+
return Promise.reject(new Error('context.invoke requires a function name'))
|
|
23
|
+
}
|
|
24
|
+
const id = String(++invokeSeq)
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
pending.set(id, {resolve, reject})
|
|
27
|
+
process.send(JSON.stringify({type: 'invoke-request', id, name, payload}))
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function handleResponse(msg) {
|
|
32
|
+
const pendingEntry = pending.get(msg.id)
|
|
33
|
+
if (!pendingEntry) return
|
|
34
|
+
pending.delete(msg.id)
|
|
35
|
+
if (msg.ok) {
|
|
36
|
+
pendingEntry.resolve(msg.result?.json)
|
|
37
|
+
} else {
|
|
38
|
+
const {message, stack, name} = msg.error ?? {}
|
|
39
|
+
const err = new Error(message ?? 'Nested invoke failed')
|
|
40
|
+
if (stack) err.stack = stack
|
|
41
|
+
if (name) err.name = name
|
|
42
|
+
pendingEntry.reject(err)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {invoke, handleResponse}
|
|
47
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The returned proxy wraps a function so the API itself is callable.
|
|
3
|
+
* @param {Record<string, ResourceEntry[]>} resources
|
|
4
|
+
* @returns {ResourcesApi}
|
|
5
|
+
*/
|
|
6
|
+
export function createResourcesApi(resources) {
|
|
7
|
+
const findByName = (name) => {
|
|
8
|
+
for (const group of Object.values(resources)) {
|
|
9
|
+
const found = group.find((r) => r.name === name)
|
|
10
|
+
if (found) return found
|
|
11
|
+
}
|
|
12
|
+
return undefined
|
|
13
|
+
}
|
|
14
|
+
let allCache
|
|
15
|
+
const all = () => (allCache ??= Object.values(resources).flat())
|
|
16
|
+
|
|
17
|
+
return /** @type {ResourcesApi} */ (
|
|
18
|
+
/** @type {unknown} */ (
|
|
19
|
+
/*
|
|
20
|
+
* The Proxy target is `findByName`, so invoking the API as a function —
|
|
21
|
+
* `context.resources('my-proj')` — bypasses the `get` trap entirely and
|
|
22
|
+
* calls `findByName` directly for a cross-type lookup by name.
|
|
23
|
+
*/
|
|
24
|
+
new Proxy(findByName, {
|
|
25
|
+
get: (_target, prop) => {
|
|
26
|
+
// context.resources.all() — flat array of every resource across types
|
|
27
|
+
if (prop === 'all') return all
|
|
28
|
+
// [...context.resources] / for (const r of context.resources) — iterate all
|
|
29
|
+
if (prop === Symbol.iterator) {
|
|
30
|
+
return function* () {
|
|
31
|
+
yield* all()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Symbol property access (other than iterator above) and `then`
|
|
37
|
+
* lookups return undefined. The `then` guard prevents the API from
|
|
38
|
+
* looking like a thenable, so `await context.resources` resolves to
|
|
39
|
+
* the proxy itself rather than hanging or unwrapping unexpectedly.
|
|
40
|
+
*/
|
|
41
|
+
if (typeof prop !== 'string' || prop === 'then') {
|
|
42
|
+
return undefined
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* context.resources.<type>(name) — per-type lookup,
|
|
47
|
+
* e.g. context.resources.project('my-proj').
|
|
48
|
+
* Returns a function so the caller supplies the name;
|
|
49
|
+
* unknown types yield a function that always returns undefined.
|
|
50
|
+
*/
|
|
51
|
+
return (/** @type {string} */ name) =>
|
|
52
|
+
Object.hasOwn(resources, prop)
|
|
53
|
+
? resources[prop].find((r) => r.name === name)
|
|
54
|
+
: undefined
|
|
55
|
+
},
|
|
56
|
+
})
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { BlueprintStudioResource } from '@sanity/blueprints';
|
|
2
|
+
import type { AssetPrepResult } from '../types.js';
|
|
3
|
+
export declare function prepareStudioAsset({ blueprintFileDir, resource, }: {
|
|
4
|
+
blueprintFileDir: string;
|
|
5
|
+
resource: BlueprintStudioResource;
|
|
6
|
+
}): Promise<AssetPrepResult>;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { createWriteStream } from 'node:fs';
|
|
2
|
+
import { mkdtemp, rm, stat } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import path, { basename, dirname, join } from 'node:path';
|
|
5
|
+
import { pipeline } from 'node:stream/promises';
|
|
6
|
+
import { createGzip } from 'node:zlib';
|
|
7
|
+
import { buildStudio, compareDependencyVersions } from '@sanity/cli-build/_internal/build';
|
|
8
|
+
import { pack } from 'tar-fs';
|
|
9
|
+
export async function prepareStudioAsset({ blueprintFileDir, resource, }) {
|
|
10
|
+
// validate resource has an externalId
|
|
11
|
+
if (!('externalId' in resource) ||
|
|
12
|
+
typeof resource.externalId !== 'string' ||
|
|
13
|
+
!resource.externalId) {
|
|
14
|
+
return {
|
|
15
|
+
success: false,
|
|
16
|
+
async cleanup() {
|
|
17
|
+
// no op
|
|
18
|
+
},
|
|
19
|
+
error: `Unable to determine appId for sanity.studio resource '${resource.name}'`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
let cleanup = async () => {
|
|
23
|
+
// no op
|
|
24
|
+
};
|
|
25
|
+
const studioPath = path.resolve(blueprintFileDir, resource.src);
|
|
26
|
+
try {
|
|
27
|
+
const studioPathStat = await stat(studioPath);
|
|
28
|
+
if (!studioPathStat.isDirectory()) {
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
cleanup,
|
|
32
|
+
error: `Property 'src' on resource with type '${resource.type}' must be a directory`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
cleanup,
|
|
41
|
+
error: `Unable to read given 'src' on resource with type '${resource.type}': ${msg}`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const outDir = await mkdtemp(join(tmpdir(), `studio-build-`));
|
|
46
|
+
const outFile = `${outDir}.tar.gz`;
|
|
47
|
+
cleanup = async () => {
|
|
48
|
+
await rm(outDir, { force: true, recursive: true });
|
|
49
|
+
await rm(outFile, { force: true });
|
|
50
|
+
};
|
|
51
|
+
const appId = resource.externalId;
|
|
52
|
+
try {
|
|
53
|
+
await buildStudio({
|
|
54
|
+
appId,
|
|
55
|
+
autoUpdatesEnabled: resource.autoUpdates.enabled,
|
|
56
|
+
checkAppId() { },
|
|
57
|
+
async compareDependencyVersions(packages) {
|
|
58
|
+
return compareDependencyVersions(packages, studioPath, { appId });
|
|
59
|
+
},
|
|
60
|
+
determineBasePath() {
|
|
61
|
+
return resource.basePath ?? '/';
|
|
62
|
+
},
|
|
63
|
+
isApp: false,
|
|
64
|
+
isWorkbenchApp: false,
|
|
65
|
+
minify: resource.minify ?? true,
|
|
66
|
+
outDir,
|
|
67
|
+
output: createSilentOutput(),
|
|
68
|
+
reactCompiler: resource.reactCompiler || false,
|
|
69
|
+
schemaExtraction: undefined,
|
|
70
|
+
sourceMap: resource.sourceMap ?? false,
|
|
71
|
+
stats: false,
|
|
72
|
+
unattendedMode: true,
|
|
73
|
+
// TODO pass in vite config from the studio resource
|
|
74
|
+
vite: undefined,
|
|
75
|
+
workDir: studioPath,
|
|
76
|
+
eventListener: {
|
|
77
|
+
onBuildFail({ message }) {
|
|
78
|
+
throw new Error(message);
|
|
79
|
+
},
|
|
80
|
+
onInvalidStyledComponentsVersionRange({ message }) {
|
|
81
|
+
throw new Error(message);
|
|
82
|
+
},
|
|
83
|
+
onNoDeclaredStyledComponentsVersion({ message }) {
|
|
84
|
+
throw new Error(message);
|
|
85
|
+
},
|
|
86
|
+
onNoInstalledSanityVersion({ message }) {
|
|
87
|
+
throw new Error(message);
|
|
88
|
+
},
|
|
89
|
+
onNoInstalledStyledComponentsVersion({ message }) {
|
|
90
|
+
throw new Error(message);
|
|
91
|
+
},
|
|
92
|
+
onPreReleaseInNonInteractiveAutoUpdate({ message }) {
|
|
93
|
+
throw new Error(message);
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
cleanup,
|
|
103
|
+
error: message,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// tar/gzip/write the built output
|
|
107
|
+
await pipeline(pack(dirname(outDir), { entries: [basename(outDir)] }), createGzip(), createWriteStream(outFile));
|
|
108
|
+
return {
|
|
109
|
+
success: true,
|
|
110
|
+
cleanup,
|
|
111
|
+
// studio must be pre built (e.g. with `npm run build`) and tarred/gzipped
|
|
112
|
+
outputPath: outFile,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
return {
|
|
117
|
+
success: false,
|
|
118
|
+
cleanup,
|
|
119
|
+
error: error instanceof Error ? error.message : String(error),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function createSilentOutput() {
|
|
124
|
+
return {
|
|
125
|
+
error(input, options) {
|
|
126
|
+
if (typeof options?.exit === 'number') {
|
|
127
|
+
if (input instanceof Error) {
|
|
128
|
+
throw input;
|
|
129
|
+
}
|
|
130
|
+
throw new Error(input);
|
|
131
|
+
}
|
|
132
|
+
return undefined;
|
|
133
|
+
},
|
|
134
|
+
log() { },
|
|
135
|
+
warn(input) {
|
|
136
|
+
return input;
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type BlueprintCorsOriginResource, type BlueprintDatasetResource, type BlueprintDocumentFunctionResource, type BlueprintDocumentWebhookResource, type BlueprintMediaLibraryAssetFunctionResource, type BlueprintProjectResource, type BlueprintResource, type BlueprintRobotResource, type BlueprintRoleResource, type BlueprintScheduledFunctionResource, type BlueprintSyncTagInvalidateFunctionResource } from '@sanity/blueprints';
|
|
1
|
+
import { type BlueprintCorsOriginResource, type BlueprintDatasetResource, type BlueprintDocumentFunctionResource, type BlueprintDocumentWebhookResource, type BlueprintMediaLibraryAssetFunctionResource, type BlueprintProjectResource, type BlueprintResource, type BlueprintRobotResource, type BlueprintRoleResource, type BlueprintScheduledFunctionResource, type BlueprintStudioResource, type BlueprintSyncTagInvalidateFunctionResource } from '@sanity/blueprints';
|
|
2
2
|
export type ScopeType = 'organization' | 'project';
|
|
3
3
|
/** Result utility type */
|
|
4
4
|
export type Result<T, E = string> = {
|
|
@@ -16,12 +16,8 @@ export interface ActionResponse {
|
|
|
16
16
|
/** @internal */
|
|
17
17
|
export type FunctionGroqResource = BlueprintDocumentFunctionResource | BlueprintMediaLibraryAssetFunctionResource;
|
|
18
18
|
export type FunctionResource = FunctionGroqResource | BlueprintScheduledFunctionResource | BlueprintSyncTagInvalidateFunctionResource;
|
|
19
|
-
export interface StudioResource extends BlueprintResource {
|
|
20
|
-
type: 'sanity.studio';
|
|
21
|
-
src: string;
|
|
22
|
-
}
|
|
23
19
|
/** Resource types that carry a deployable asset (have src: string) */
|
|
24
|
-
export type AssetResource = FunctionResource |
|
|
20
|
+
export type AssetResource = FunctionResource | BlueprintStudioResource;
|
|
25
21
|
/** @internal */
|
|
26
22
|
export interface AuthParams {
|
|
27
23
|
token: string;
|
|
@@ -46,7 +42,7 @@ export declare function isProjectResource(r: unknown): r is BlueprintProjectReso
|
|
|
46
42
|
export declare function isRobotResource(r: unknown): r is BlueprintRobotResource;
|
|
47
43
|
export declare function isRoleResource(r: unknown): r is BlueprintRoleResource;
|
|
48
44
|
export declare function isDatasetResource(r: unknown): r is BlueprintDatasetResource;
|
|
49
|
-
export declare function isStudioResource(r: BlueprintResource): r is
|
|
45
|
+
export declare function isStudioResource(r: BlueprintResource): r is BlueprintStudioResource;
|
|
50
46
|
export declare function isAssetResource(r: BlueprintResource): r is AssetResource;
|
|
51
47
|
export declare function isWebhookResource(r: unknown): r is BlueprintDocumentWebhookResource;
|
|
52
48
|
interface StackBase {
|
|
@@ -84,6 +80,7 @@ export interface StackMutation {
|
|
|
84
80
|
resources?: BlueprintResource[];
|
|
85
81
|
};
|
|
86
82
|
userMessage?: string;
|
|
83
|
+
preDeploy?: boolean;
|
|
87
84
|
}
|
|
88
85
|
/** @internal */
|
|
89
86
|
export interface BuildPayloadOptions {
|
package/dist/utils/types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { validateCorsOrigin, validateDataset, validateDocumentWebhook, validateProject, validateRobot, validateRole, } from '@sanity/blueprints';
|
|
2
|
-
import { SANITY_FUNCTION_PREFIX } from '../constants.js';
|
|
2
|
+
import { SANITY_FUNCTION_PREFIX, SANITY_STUDIO } from '../constants.js';
|
|
3
3
|
export function isLocalFunctionResource(r) {
|
|
4
4
|
return r.type.startsWith(SANITY_FUNCTION_PREFIX);
|
|
5
5
|
}
|
|
@@ -22,9 +22,8 @@ export function isRoleResource(r) {
|
|
|
22
22
|
export function isDatasetResource(r) {
|
|
23
23
|
return validateDataset(r).length === 0;
|
|
24
24
|
}
|
|
25
|
-
// TODO: update to use blueprints helpers once available
|
|
26
25
|
export function isStudioResource(r) {
|
|
27
|
-
return r.type ===
|
|
26
|
+
return r.type === SANITY_STUDIO;
|
|
28
27
|
}
|
|
29
28
|
export function isAssetResource(r) {
|
|
30
29
|
return isLocalFunctionResource(r) || isStudioResource(r);
|
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": "17.
|
|
4
|
+
"version": "17.2.0-next.ga4b9ae7",
|
|
5
5
|
"author": "Sanity Runtime Team",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
@@ -40,7 +40,9 @@
|
|
|
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": "
|
|
43
|
+
"copy:wrapper": "npm run copy:wrapper:entry && npm run copy:wrapper:modules",
|
|
44
|
+
"copy:wrapper:entry": "shx cp ./src/utils/functions/child-process-wrapper.js ./dist/utils/functions/child-process-wrapper.js",
|
|
45
|
+
"copy:wrapper:modules": "shx rm -rf ./dist/utils/functions/child-runtime && shx cp -r ./src/utils/functions/child-runtime ./dist/utils/functions/child-runtime",
|
|
44
46
|
"lint": "biome ci",
|
|
45
47
|
"lint:write": "biome check --write",
|
|
46
48
|
"lint:fix": "npm run lint:write",
|
|
@@ -64,8 +66,10 @@
|
|
|
64
66
|
"@oclif/core": "^4.11.14",
|
|
65
67
|
"@oclif/plugin-help": "^6.2.53",
|
|
66
68
|
"@sanity-labs/design-tokens": "^0.0.2-alpha.2",
|
|
67
|
-
"@sanity/blueprints": "^0.
|
|
69
|
+
"@sanity/blueprints": "^0.23.0",
|
|
68
70
|
"@sanity/blueprints-parser": "^0.4.0",
|
|
71
|
+
"@sanity/cli-build": "^5.0.0",
|
|
72
|
+
"@sanity/cli-core": "^2.5.1",
|
|
69
73
|
"@sanity/client": "^7.23.1",
|
|
70
74
|
"adm-zip": "^0.6.0",
|
|
71
75
|
"array-treeify": "^0.1.5",
|
|
@@ -78,6 +82,7 @@
|
|
|
78
82
|
"ora": "^9.4.1",
|
|
79
83
|
"signal-exit": "^4.1.0",
|
|
80
84
|
"strip-ansi": "^7.2.0",
|
|
85
|
+
"tar-fs": "^3.1.3",
|
|
81
86
|
"tar-stream": "^3.2.0",
|
|
82
87
|
"vite": "^8.1.4",
|
|
83
88
|
"ws": "^8.21.1",
|
|
@@ -97,6 +102,7 @@
|
|
|
97
102
|
"@types/cardinal": "^2.1.1",
|
|
98
103
|
"@types/mime-types": "^3.0.1",
|
|
99
104
|
"@types/node": "^22",
|
|
105
|
+
"@types/tar-fs": "^2.0.4",
|
|
100
106
|
"@types/tar-stream": "^3.1.4",
|
|
101
107
|
"@types/ws": "^8.18.1",
|
|
102
108
|
"@vitest/coverage-v8": "4.1.10",
|