@sanity/runtime-cli 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -5
- package/dist/actions/blueprints/read-blueprint.d.ts +2 -0
- package/dist/actions/blueprints/read-blueprint.js +17 -0
- package/dist/actions/blueprints/stacks.d.ts +22 -0
- package/dist/actions/blueprints/stacks.js +57 -0
- package/dist/actions/blueprints/stash-asset.d.ts +10 -0
- package/dist/actions/blueprints/stash-asset.js +42 -0
- package/dist/actions/functions/invoke.js +2 -2
- package/dist/actions/functions/logs.js +2 -2
- package/dist/commands/blueprints/deploy.d.ts +6 -0
- package/dist/commands/blueprints/deploy.js +70 -0
- package/dist/commands/blueprints/info.d.ts +6 -0
- package/dist/commands/blueprints/info.js +71 -0
- package/dist/commands/blueprints/plan.d.ts +6 -0
- package/dist/commands/blueprints/plan.js +31 -0
- package/dist/config.d.ts +2 -1
- package/dist/config.js +16 -3
- package/dist/server/app.js +1 -1
- package/dist/utils/get-token.d.ts +1 -1
- package/dist/utils/get-token.js +3 -2
- package/dist/utils/spinner.d.ts +9 -0
- package/dist/utils/spinner.js +25 -0
- package/dist/utils/types.d.ts +48 -0
- package/oclif.manifest.json +73 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ $ npm install -g @sanity/runtime-cli
|
|
|
20
20
|
$ sanity COMMAND
|
|
21
21
|
running command...
|
|
22
22
|
$ sanity (--version)
|
|
23
|
-
@sanity/runtime-cli/1.
|
|
23
|
+
@sanity/runtime-cli/1.2.0 linux-x64 node-v22.14.0
|
|
24
24
|
$ sanity --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ sanity COMMAND
|
|
@@ -29,6 +29,9 @@ USAGE
|
|
|
29
29
|
<!-- usagestop -->
|
|
30
30
|
# Commands
|
|
31
31
|
<!-- commands -->
|
|
32
|
+
* [`sanity blueprints deploy`](#sanity-blueprints-deploy)
|
|
33
|
+
* [`sanity blueprints info`](#sanity-blueprints-info)
|
|
34
|
+
* [`sanity blueprints plan`](#sanity-blueprints-plan)
|
|
32
35
|
* [`sanity functions dev`](#sanity-functions-dev)
|
|
33
36
|
* [`sanity functions invoke ID`](#sanity-functions-invoke-id)
|
|
34
37
|
* [`sanity functions logs ID`](#sanity-functions-logs-id)
|
|
@@ -45,6 +48,57 @@ USAGE
|
|
|
45
48
|
* [`sanity plugins unlink [PLUGIN]`](#sanity-plugins-unlink-plugin)
|
|
46
49
|
* [`sanity plugins update`](#sanity-plugins-update)
|
|
47
50
|
|
|
51
|
+
## `sanity blueprints deploy`
|
|
52
|
+
|
|
53
|
+
Deploy a Blueprint
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
USAGE
|
|
57
|
+
$ sanity blueprints deploy
|
|
58
|
+
|
|
59
|
+
DESCRIPTION
|
|
60
|
+
Deploy a Blueprint
|
|
61
|
+
|
|
62
|
+
EXAMPLES
|
|
63
|
+
$ sanity blueprints deploy
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v1.2.0/src/commands/blueprints/deploy.ts)_
|
|
67
|
+
|
|
68
|
+
## `sanity blueprints info`
|
|
69
|
+
|
|
70
|
+
Show information about a Blueprint
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
USAGE
|
|
74
|
+
$ sanity blueprints info
|
|
75
|
+
|
|
76
|
+
DESCRIPTION
|
|
77
|
+
Show information about a Blueprint
|
|
78
|
+
|
|
79
|
+
EXAMPLES
|
|
80
|
+
$ sanity blueprints info
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v1.2.0/src/commands/blueprints/info.ts)_
|
|
84
|
+
|
|
85
|
+
## `sanity blueprints plan`
|
|
86
|
+
|
|
87
|
+
Enumerate resources to be deployed - will not modify any resources
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
USAGE
|
|
91
|
+
$ sanity blueprints plan
|
|
92
|
+
|
|
93
|
+
DESCRIPTION
|
|
94
|
+
Enumerate resources to be deployed - will not modify any resources
|
|
95
|
+
|
|
96
|
+
EXAMPLES
|
|
97
|
+
$ sanity blueprints plan
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v1.2.0/src/commands/blueprints/plan.ts)_
|
|
101
|
+
|
|
48
102
|
## `sanity functions dev`
|
|
49
103
|
|
|
50
104
|
Start the Sanity Function emulator
|
|
@@ -63,7 +117,7 @@ EXAMPLES
|
|
|
63
117
|
$ sanity functions dev --port 8974
|
|
64
118
|
```
|
|
65
119
|
|
|
66
|
-
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
120
|
+
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v1.2.0/src/commands/functions/dev.ts)_
|
|
67
121
|
|
|
68
122
|
## `sanity functions invoke ID`
|
|
69
123
|
|
|
@@ -89,7 +143,7 @@ EXAMPLES
|
|
|
89
143
|
$ sanity functions invoke <ID> --file 'payload.json'
|
|
90
144
|
```
|
|
91
145
|
|
|
92
|
-
_See code: [src/commands/functions/invoke.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
146
|
+
_See code: [src/commands/functions/invoke.ts](https://github.com/sanity-io/runtime-cli/blob/v1.2.0/src/commands/functions/invoke.ts)_
|
|
93
147
|
|
|
94
148
|
## `sanity functions logs ID`
|
|
95
149
|
|
|
@@ -109,7 +163,7 @@ EXAMPLES
|
|
|
109
163
|
$ sanity functions logs <ID>
|
|
110
164
|
```
|
|
111
165
|
|
|
112
|
-
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
166
|
+
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v1.2.0/src/commands/functions/logs.ts)_
|
|
113
167
|
|
|
114
168
|
## `sanity functions test PATH`
|
|
115
169
|
|
|
@@ -138,7 +192,7 @@ EXAMPLES
|
|
|
138
192
|
$ sanity functions test ./test.ts --data '{ "id": 1 }' --timeout 60
|
|
139
193
|
```
|
|
140
194
|
|
|
141
|
-
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
195
|
+
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v1.2.0/src/commands/functions/test.ts)_
|
|
142
196
|
|
|
143
197
|
## `sanity help [COMMAND]`
|
|
144
198
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { cwd } from 'node:process';
|
|
4
|
+
export default function readBlueprint() {
|
|
5
|
+
try {
|
|
6
|
+
const blueprintPath = join(cwd(), 'blueprint.json');
|
|
7
|
+
if (!existsSync(blueprintPath)) {
|
|
8
|
+
throw Error('Could not find blueprint.json');
|
|
9
|
+
}
|
|
10
|
+
const readBlueprint = readFileSync(blueprintPath, 'utf8').toString();
|
|
11
|
+
const blueprintJson = JSON.parse(readBlueprint);
|
|
12
|
+
return blueprintJson;
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
throw Error('Unable to parse blueprint.json');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BlueprintJob } from '../../utils/types.js';
|
|
2
|
+
declare function listStacks(): Promise<{
|
|
3
|
+
ok: boolean;
|
|
4
|
+
error: any;
|
|
5
|
+
stacks: any;
|
|
6
|
+
}>;
|
|
7
|
+
declare function getStack(stackId: string): Promise<{
|
|
8
|
+
ok: boolean;
|
|
9
|
+
error: any;
|
|
10
|
+
stack: any;
|
|
11
|
+
}>;
|
|
12
|
+
declare function createStack(blueprint: BlueprintJob): Promise<{
|
|
13
|
+
ok: boolean;
|
|
14
|
+
error: any;
|
|
15
|
+
stack: any;
|
|
16
|
+
}>;
|
|
17
|
+
declare function updateStack(stackId: string, blueprint: BlueprintJob): Promise<{
|
|
18
|
+
ok: boolean;
|
|
19
|
+
error: any;
|
|
20
|
+
stack: any;
|
|
21
|
+
}>;
|
|
22
|
+
export { listStacks, getStack, createStack, updateStack };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import config from '../../config.js';
|
|
2
|
+
const { blueprints } = config.server;
|
|
3
|
+
const HEADERS = {
|
|
4
|
+
Authorization: `Bearer ${config.token}`,
|
|
5
|
+
'Content-Type': 'application/json',
|
|
6
|
+
};
|
|
7
|
+
async function listStacks() {
|
|
8
|
+
const response = await fetch(`${blueprints}/vX/stacks`, {
|
|
9
|
+
method: 'GET',
|
|
10
|
+
headers: HEADERS,
|
|
11
|
+
});
|
|
12
|
+
const stacks = await response.json();
|
|
13
|
+
return {
|
|
14
|
+
ok: response.ok,
|
|
15
|
+
error: response.ok ? null : stacks.message,
|
|
16
|
+
stacks,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
async function getStack(stackId) {
|
|
20
|
+
const response = await fetch(`${blueprints}/vX/stacks/${stackId}`, {
|
|
21
|
+
method: 'GET',
|
|
22
|
+
headers: HEADERS,
|
|
23
|
+
});
|
|
24
|
+
const stack = await response.json();
|
|
25
|
+
return {
|
|
26
|
+
ok: response.ok,
|
|
27
|
+
error: response.ok ? null : stack.message,
|
|
28
|
+
stack,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async function createStack(blueprint) {
|
|
32
|
+
const response = await fetch(`${blueprints}/vX/stacks`, {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: HEADERS,
|
|
35
|
+
body: JSON.stringify(blueprint),
|
|
36
|
+
});
|
|
37
|
+
const stack = await response.json();
|
|
38
|
+
return {
|
|
39
|
+
ok: response.ok,
|
|
40
|
+
error: response.ok ? null : stack.message,
|
|
41
|
+
stack,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async function updateStack(stackId, blueprint) {
|
|
45
|
+
const response = await fetch(`${blueprints}/vX/stacks/${stackId}`, {
|
|
46
|
+
method: 'PUT',
|
|
47
|
+
headers: HEADERS,
|
|
48
|
+
body: JSON.stringify(blueprint),
|
|
49
|
+
});
|
|
50
|
+
const stack = await response.json();
|
|
51
|
+
return {
|
|
52
|
+
ok: response.ok,
|
|
53
|
+
error: response.ok ? null : stack.message,
|
|
54
|
+
stack,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export { listStacks, getStack, createStack, updateStack };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BlueprintResource } from '../../utils/types.js';
|
|
2
|
+
export declare function stashAsset(resource: BlueprintResource): Promise<{
|
|
3
|
+
success: boolean;
|
|
4
|
+
assetId: any;
|
|
5
|
+
error?: undefined;
|
|
6
|
+
} | {
|
|
7
|
+
success: boolean;
|
|
8
|
+
error: any;
|
|
9
|
+
assetId?: undefined;
|
|
10
|
+
}>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { cwd } from 'node:process';
|
|
4
|
+
import JSZip from 'jszip';
|
|
5
|
+
import config from '../../config.js';
|
|
6
|
+
const { blueprints } = config.server;
|
|
7
|
+
export async function stashAsset(resource) {
|
|
8
|
+
try {
|
|
9
|
+
// Read the function source
|
|
10
|
+
const source = await fs.readFileSync(path.join(cwd(), resource.src), 'utf8');
|
|
11
|
+
// Create zip with function source
|
|
12
|
+
const zip = new JSZip();
|
|
13
|
+
zip.file('index.js', source);
|
|
14
|
+
const zipBuffer = await zip.generateAsync({ type: 'nodebuffer' });
|
|
15
|
+
const base64Zip = zipBuffer.toString('base64');
|
|
16
|
+
// Stash the asset
|
|
17
|
+
const assetResponse = await fetch(`${blueprints}/assets/stash`, {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: {
|
|
20
|
+
Authorization: `Bearer ${config.token}`,
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
file: base64Zip,
|
|
25
|
+
filename: `${resource.name}.zip`,
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
const assetJson = await assetResponse.json();
|
|
29
|
+
console.debug('ASSET RESPONSE:', assetJson);
|
|
30
|
+
if (assetResponse.ok) {
|
|
31
|
+
return { success: true, assetId: assetJson.id };
|
|
32
|
+
}
|
|
33
|
+
return { success: false, error: assetJson.message || 'Unknown error' };
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
let error = '';
|
|
37
|
+
if (err instanceof Error) {
|
|
38
|
+
error = err.message;
|
|
39
|
+
}
|
|
40
|
+
return { success: false, error };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import config from '../../config.js';
|
|
2
2
|
import buildPayload from '../../utils/build-payload.js';
|
|
3
|
-
const {
|
|
3
|
+
const { functions } = config.server;
|
|
4
4
|
export async function invoke(id, options) {
|
|
5
5
|
const payload = buildPayload(options);
|
|
6
6
|
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
7
|
-
const response = await fetch(`${
|
|
7
|
+
const response = await fetch(`${functions}/vX/functions/${id}/invoke`, {
|
|
8
8
|
body: JSON.stringify({ data: payload }),
|
|
9
9
|
headers: {
|
|
10
10
|
Accept: 'application/json',
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import config from '../../config.js';
|
|
2
|
-
const {
|
|
2
|
+
const { functions } = config.server;
|
|
3
3
|
export async function logs(id, token) {
|
|
4
4
|
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
5
|
-
const response = await fetch(`${
|
|
5
|
+
const response = await fetch(`${functions}/vX/functions/${id}/logs`, {
|
|
6
6
|
headers: {
|
|
7
7
|
Accept: 'application/json',
|
|
8
8
|
'Content-Type': 'application/json',
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import readBlueprint from '../../actions/blueprints/read-blueprint.js';
|
|
3
|
+
import { createStack, listStacks, updateStack } from '../../actions/blueprints/stacks.js';
|
|
4
|
+
import { stashAsset } from '../../actions/blueprints/stash-asset.js';
|
|
5
|
+
import Spinner from '../../utils/spinner.js';
|
|
6
|
+
export default class Deploy extends Command {
|
|
7
|
+
static description = 'Deploy a Blueprint';
|
|
8
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
9
|
+
async run() {
|
|
10
|
+
const { displayName, name, projectId, resources } = readBlueprint();
|
|
11
|
+
const s = new Spinner();
|
|
12
|
+
s.start('Deploying blueprint...');
|
|
13
|
+
const functionResources = resources.filter((r) => r.kind === 'function');
|
|
14
|
+
// First stash all function assets
|
|
15
|
+
if (functionResources.length > 0) {
|
|
16
|
+
s.stop('Preparing functions...');
|
|
17
|
+
for (const resource of functionResources) {
|
|
18
|
+
const fnSpinner = new Spinner();
|
|
19
|
+
fnSpinner.start(`Processing ${resource.name}...`);
|
|
20
|
+
const result = await stashAsset(resource);
|
|
21
|
+
if (result.success) {
|
|
22
|
+
resource.assetId = result.assetId;
|
|
23
|
+
fnSpinner.stop(`✓ ${resource.name} (${result.assetId})`);
|
|
24
|
+
this.log(` Source: ${resource.src}`);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
fnSpinner.stop(`✗ Failed to process ${resource.name}`);
|
|
28
|
+
this.log(` Error: ${result.error}`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
this.log('│');
|
|
33
|
+
s.start('Looking for existing stack...');
|
|
34
|
+
}
|
|
35
|
+
// Check for existing stack
|
|
36
|
+
const { ok: stacksOk, stacks, error: stacksError } = await listStacks();
|
|
37
|
+
if (!stacksOk) {
|
|
38
|
+
s.stop('Failed to list stacks');
|
|
39
|
+
this.log(`Error: ${stacksError || 'Unknown error'}`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const existingStack = stacks.find((st) => st.name === name);
|
|
43
|
+
const blueprint = {
|
|
44
|
+
name,
|
|
45
|
+
projectId,
|
|
46
|
+
document: {
|
|
47
|
+
resources: resources.map((r) => {
|
|
48
|
+
if (r.kind === 'function') {
|
|
49
|
+
return { ...r, src: r.assetId };
|
|
50
|
+
}
|
|
51
|
+
return r;
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
this.debug('BLUEPRINT DOCUMENT:', blueprint);
|
|
56
|
+
// Create or update stack
|
|
57
|
+
const { ok, stack, error } = existingStack
|
|
58
|
+
? await updateStack(existingStack.id, blueprint)
|
|
59
|
+
: await createStack(blueprint);
|
|
60
|
+
this.debug('STACK RESPONSE:', stack);
|
|
61
|
+
if (ok) {
|
|
62
|
+
s.stop(`Stack ${existingStack ? 'updated' : 'created'}! (${stack.id})`);
|
|
63
|
+
this.log('Use `blueprints info` to check deployment status');
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
s.stop(`Failed to ${existingStack ? 'update' : 'create'} stack`);
|
|
67
|
+
this.log(`Error: ${error || 'Unknown error'}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import readBlueprint from '../../actions/blueprints/read-blueprint.js';
|
|
3
|
+
import { getStack, listStacks } from '../../actions/blueprints/stacks.js';
|
|
4
|
+
import Spinner from '../../utils/spinner.js';
|
|
5
|
+
export default class Info extends Command {
|
|
6
|
+
static description = 'Show information about a Blueprint';
|
|
7
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
8
|
+
async run() {
|
|
9
|
+
const { displayName, name, projectId, resources } = readBlueprint();
|
|
10
|
+
const s = new Spinner();
|
|
11
|
+
if (!projectId) {
|
|
12
|
+
this.log(`No project for Blueprint "${displayName}"`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
s.start(`Retrieving info for "${displayName}"`);
|
|
16
|
+
try {
|
|
17
|
+
const { ok, stacks, error } = await listStacks();
|
|
18
|
+
if (!ok) {
|
|
19
|
+
s.stop('Failed to retrieve stacks');
|
|
20
|
+
this.log(`Error: ${error || 'Unknown error'}`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (stacks.length === 0) {
|
|
24
|
+
s.stop(`No stacks found for Blueprint "${displayName}"`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const foundStack = stacks.find((st) => st.name === name);
|
|
28
|
+
const { ok: stackOk, stack, error: stackError } = await getStack(foundStack.id);
|
|
29
|
+
if (!stackOk) {
|
|
30
|
+
s.stop('Failed to retrieve stack');
|
|
31
|
+
this.log(`Error: ${stackError || 'Unknown error'}`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
s.stop(`Stack "${stack.name}" (${stack.recentOperation.status})`);
|
|
35
|
+
// Show resources
|
|
36
|
+
if (stack?.resources) {
|
|
37
|
+
const { resources: stackResources } = stack;
|
|
38
|
+
const functionResources = stackResources.filter((r) => r.kind === 'function');
|
|
39
|
+
const otherResources = stackResources.filter((r) => r.kind !== 'function');
|
|
40
|
+
if (functionResources.length > 0) {
|
|
41
|
+
this.log(`├─ Functions (${functionResources.length})`);
|
|
42
|
+
for (const fn of functionResources) {
|
|
43
|
+
this.log(`│ ├─ ${fn.name} <${fn.externalId}>`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (otherResources.length > 0) {
|
|
47
|
+
this.log(`└─Other Resources (${otherResources.length})`);
|
|
48
|
+
for (const other of otherResources) {
|
|
49
|
+
this.log(` ├─ ${other.name || other.src}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Show operation details if not completed
|
|
54
|
+
if (stack.recentOperation.status !== 'COMPLETED') {
|
|
55
|
+
this.log('\nOperation Details:');
|
|
56
|
+
if (stack.recentOperation.error) {
|
|
57
|
+
this.log(`Error: ${stack.recentOperation.error}`);
|
|
58
|
+
}
|
|
59
|
+
if (stack.recentOperation.progress) {
|
|
60
|
+
this.log(`Progress: ${stack.recentOperation.progress}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
s.stop('Failed to retrieve info');
|
|
66
|
+
if (err instanceof Error) {
|
|
67
|
+
this.log(`Error: ${err.message}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import readBlueprint from '../../actions/blueprints/read-blueprint.js';
|
|
3
|
+
export default class Plan extends Command {
|
|
4
|
+
static description = 'Enumerate resources to be deployed - will not modify any resources';
|
|
5
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
6
|
+
async run() {
|
|
7
|
+
const { displayName, resources } = readBlueprint();
|
|
8
|
+
this.log(`Blueprint: "${displayName}"`);
|
|
9
|
+
const functionResources = resources.filter((r) => r.kind === 'function');
|
|
10
|
+
const otherResources = resources.filter((r) => r.kind === 'test');
|
|
11
|
+
this.log('Tracked resources:');
|
|
12
|
+
if (functionResources.length > 0) {
|
|
13
|
+
this.log(`├─ Functions (${functionResources.length})`);
|
|
14
|
+
for (const fn of functionResources) {
|
|
15
|
+
this.log(`│ ├─ ${fn.name}: ${fn.src}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (otherResources.length > 0) {
|
|
19
|
+
this.log(`└─Other (${otherResources.length})`);
|
|
20
|
+
for (const other of otherResources) {
|
|
21
|
+
this.log(` ├─ ${other.name}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (resources.length === 0) {
|
|
25
|
+
this.log('No resources to deploy');
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
this.log('\nRun `blueprints deploy` to deploy these changes');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -2,10 +2,23 @@ import { env } from 'node:process';
|
|
|
2
2
|
import getToken from './utils/get-token.js';
|
|
3
3
|
const nodeEnv = env.NODE_ENV ?? 'development';
|
|
4
4
|
const isDev = nodeEnv === 'development';
|
|
5
|
-
const
|
|
5
|
+
const isProd = nodeEnv === 'production';
|
|
6
|
+
const functionsUrls = {
|
|
7
|
+
production: 'https://api.sanity.io/',
|
|
8
|
+
staging: 'https://api.sanity.work/',
|
|
9
|
+
default: 'http://localhost:4567',
|
|
10
|
+
};
|
|
11
|
+
const blueprintsUrls = {
|
|
12
|
+
production: 'https://api.sanity.io/',
|
|
13
|
+
staging: 'https://api.sanity.work/',
|
|
14
|
+
default: 'http://localhost:4567',
|
|
15
|
+
};
|
|
16
|
+
const functionsUrl = new URL(functionsUrls[nodeEnv] ?? functionsUrls.default);
|
|
17
|
+
const blueprintsUrl = new URL(blueprintsUrls[nodeEnv] ?? blueprintsUrls.default);
|
|
6
18
|
export default {
|
|
7
|
-
token: isDev ? 'token' : getToken(),
|
|
19
|
+
token: isDev ? 'token' : getToken(isProd),
|
|
8
20
|
server: {
|
|
9
|
-
|
|
21
|
+
functions: functionsUrl,
|
|
22
|
+
blueprints: blueprintsUrl,
|
|
10
23
|
},
|
|
11
24
|
};
|
package/dist/server/app.js
CHANGED
|
@@ -16,7 +16,7 @@ function getStaticPath() {
|
|
|
16
16
|
const app = new Hono();
|
|
17
17
|
app.use('*', serveStatic({ root: getStaticPath() }));
|
|
18
18
|
app.get('/blueprint', async (c) => {
|
|
19
|
-
const response = JSON.parse(readFileSync(join(cwd(), './
|
|
19
|
+
const response = JSON.parse(readFileSync(join(cwd(), './blueprint.json')).toString());
|
|
20
20
|
return c.json(response);
|
|
21
21
|
});
|
|
22
22
|
app.post('/invoke', async (c) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export default function getToken(): string;
|
|
1
|
+
export default function getToken(isProd: boolean): string;
|
package/dist/utils/get-token.js
CHANGED
|
@@ -2,10 +2,11 @@ import { readFileSync } from 'node:fs';
|
|
|
2
2
|
import { tmpdir, userInfo } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { xdgConfig } from 'xdg-basedir';
|
|
5
|
-
export default function getToken() {
|
|
5
|
+
export default function getToken(isProd) {
|
|
6
|
+
const environmentDir = isProd ? 'sanity' : 'sanity-staging';
|
|
6
7
|
const user = (userInfo().username || 'user').replace(/\\/g, '');
|
|
7
8
|
const configDir = xdgConfig || join(tmpdir(), user, '.config');
|
|
8
|
-
const configPath = join(configDir,
|
|
9
|
+
const configPath = join(configDir, environmentDir, 'config.json');
|
|
9
10
|
const config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
10
11
|
return config.authToken;
|
|
11
12
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export default class Spinner {
|
|
2
|
+
frames;
|
|
3
|
+
interval;
|
|
4
|
+
currentFrame;
|
|
5
|
+
text;
|
|
6
|
+
constructor() {
|
|
7
|
+
this.frames = ['✶', '✸', '✹', '✺', '✹', '✷'];
|
|
8
|
+
this.interval = undefined;
|
|
9
|
+
this.currentFrame = 0;
|
|
10
|
+
this.text = '';
|
|
11
|
+
}
|
|
12
|
+
start(message) {
|
|
13
|
+
this.text = message;
|
|
14
|
+
this.interval = setInterval(() => {
|
|
15
|
+
const frame = this.frames[this.currentFrame];
|
|
16
|
+
process.stdout.write(`\r${frame} ${this.text}`);
|
|
17
|
+
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
18
|
+
}, 80);
|
|
19
|
+
}
|
|
20
|
+
stop(message) {
|
|
21
|
+
clearInterval(this.interval);
|
|
22
|
+
process.stdout.write(`\r${' '.repeat(this.text.length + 3)}`);
|
|
23
|
+
process.stdout.write(`\r${message}\n`);
|
|
24
|
+
}
|
|
25
|
+
}
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -14,3 +14,51 @@ export interface InvocationResponse {
|
|
|
14
14
|
json: object | undefined;
|
|
15
15
|
logs: string | undefined;
|
|
16
16
|
}
|
|
17
|
+
type LogFunction = (input: string) => void;
|
|
18
|
+
/**
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export interface BlueprintsContext {
|
|
22
|
+
log: LogFunction;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export interface Blueprint {
|
|
28
|
+
displayName: string;
|
|
29
|
+
name: string;
|
|
30
|
+
projectId: string;
|
|
31
|
+
resources: Array<BlueprintResource>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
export interface BlueprintDocument {
|
|
37
|
+
resources: Array<BlueprintResource>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
export interface BlueprintJob {
|
|
43
|
+
name: string;
|
|
44
|
+
projectId: string;
|
|
45
|
+
document: BlueprintDocument;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @internal
|
|
49
|
+
*/
|
|
50
|
+
export interface BlueprintResource {
|
|
51
|
+
name: string;
|
|
52
|
+
kind: string;
|
|
53
|
+
src: string;
|
|
54
|
+
assetId: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
export interface BlueprintStack {
|
|
60
|
+
name: string;
|
|
61
|
+
kind: string;
|
|
62
|
+
src: string;
|
|
63
|
+
}
|
|
64
|
+
export {};
|
package/oclif.manifest.json
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
{
|
|
2
2
|
"commands": {
|
|
3
|
+
"blueprints:deploy": {
|
|
4
|
+
"aliases": [],
|
|
5
|
+
"args": {},
|
|
6
|
+
"description": "Deploy a Blueprint",
|
|
7
|
+
"examples": [
|
|
8
|
+
"<%= config.bin %> <%= command.id %>"
|
|
9
|
+
],
|
|
10
|
+
"flags": {},
|
|
11
|
+
"hasDynamicHelp": false,
|
|
12
|
+
"hiddenAliases": [],
|
|
13
|
+
"id": "blueprints:deploy",
|
|
14
|
+
"pluginAlias": "@sanity/runtime-cli",
|
|
15
|
+
"pluginName": "@sanity/runtime-cli",
|
|
16
|
+
"pluginType": "core",
|
|
17
|
+
"strict": true,
|
|
18
|
+
"enableJsonFlag": false,
|
|
19
|
+
"isESM": true,
|
|
20
|
+
"relativePath": [
|
|
21
|
+
"dist",
|
|
22
|
+
"commands",
|
|
23
|
+
"blueprints",
|
|
24
|
+
"deploy.js"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"blueprints:info": {
|
|
28
|
+
"aliases": [],
|
|
29
|
+
"args": {},
|
|
30
|
+
"description": "Show information about a Blueprint",
|
|
31
|
+
"examples": [
|
|
32
|
+
"<%= config.bin %> <%= command.id %>"
|
|
33
|
+
],
|
|
34
|
+
"flags": {},
|
|
35
|
+
"hasDynamicHelp": false,
|
|
36
|
+
"hiddenAliases": [],
|
|
37
|
+
"id": "blueprints:info",
|
|
38
|
+
"pluginAlias": "@sanity/runtime-cli",
|
|
39
|
+
"pluginName": "@sanity/runtime-cli",
|
|
40
|
+
"pluginType": "core",
|
|
41
|
+
"strict": true,
|
|
42
|
+
"enableJsonFlag": false,
|
|
43
|
+
"isESM": true,
|
|
44
|
+
"relativePath": [
|
|
45
|
+
"dist",
|
|
46
|
+
"commands",
|
|
47
|
+
"blueprints",
|
|
48
|
+
"info.js"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"blueprints:plan": {
|
|
52
|
+
"aliases": [],
|
|
53
|
+
"args": {},
|
|
54
|
+
"description": "Enumerate resources to be deployed - will not modify any resources",
|
|
55
|
+
"examples": [
|
|
56
|
+
"<%= config.bin %> <%= command.id %>"
|
|
57
|
+
],
|
|
58
|
+
"flags": {},
|
|
59
|
+
"hasDynamicHelp": false,
|
|
60
|
+
"hiddenAliases": [],
|
|
61
|
+
"id": "blueprints:plan",
|
|
62
|
+
"pluginAlias": "@sanity/runtime-cli",
|
|
63
|
+
"pluginName": "@sanity/runtime-cli",
|
|
64
|
+
"pluginType": "core",
|
|
65
|
+
"strict": true,
|
|
66
|
+
"enableJsonFlag": false,
|
|
67
|
+
"isESM": true,
|
|
68
|
+
"relativePath": [
|
|
69
|
+
"dist",
|
|
70
|
+
"commands",
|
|
71
|
+
"blueprints",
|
|
72
|
+
"plan.js"
|
|
73
|
+
]
|
|
74
|
+
},
|
|
3
75
|
"functions:dev": {
|
|
4
76
|
"aliases": [],
|
|
5
77
|
"args": {},
|
|
@@ -175,5 +247,5 @@
|
|
|
175
247
|
]
|
|
176
248
|
}
|
|
177
249
|
},
|
|
178
|
-
"version": "1.
|
|
250
|
+
"version": "1.2.0"
|
|
179
251
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/runtime-cli",
|
|
3
3
|
"description": "A new CLI generated with oclif",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"author": "Sanity Runtime Team",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"@oclif/plugin-help": "^6",
|
|
41
41
|
"@oclif/plugin-plugins": "^5",
|
|
42
42
|
"hono": "^4.7.2",
|
|
43
|
+
"jszip": "^3.10.1",
|
|
43
44
|
"xdg-basedir": "^5.1.0"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|