@sanity/runtime-cli 1.2.0 → 1.3.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 +42 -16
- package/dist/actions/blueprints/logs.d.ts +7 -0
- package/dist/actions/blueprints/logs.js +79 -0
- package/dist/actions/blueprints/operations.d.ts +18 -0
- package/dist/actions/blueprints/operations.js +52 -0
- package/dist/actions/blueprints/read-blueprint.d.ts +6 -1
- package/dist/actions/blueprints/read-blueprint.js +35 -9
- package/dist/actions/blueprints/stacks.d.ts +33 -5
- package/dist/actions/blueprints/stacks.js +53 -17
- package/dist/actions/blueprints/stash-asset.d.ts +4 -1
- package/dist/actions/blueprints/stash-asset.js +12 -7
- package/dist/actions/functions/dev.js +1 -2
- package/dist/actions/functions/invoke.js +8 -5
- package/dist/commands/blueprints/deploy.js +29 -35
- package/dist/commands/blueprints/info.js +45 -39
- package/dist/commands/blueprints/logs.d.ts +10 -0
- package/dist/commands/blueprints/logs.js +166 -0
- package/dist/commands/blueprints/plan.js +10 -23
- package/dist/config.js +2 -2
- package/dist/server/app.d.ts +1 -2
- package/dist/server/app.js +62 -32
- package/dist/server/static/vendor/vendor.bundle.js +30 -8
- package/dist/utils/display/blueprints-formatting.d.ts +4 -0
- package/dist/utils/display/blueprints-formatting.js +42 -0
- package/dist/utils/display/colors.d.ts +6 -0
- package/dist/utils/display/colors.js +18 -0
- package/dist/utils/display/dates.d.ts +2 -0
- package/dist/utils/display/dates.js +26 -0
- package/dist/utils/invoke-local.js +1 -5
- package/dist/utils/types.d.ts +22 -3
- package/oclif.manifest.json +45 -1
- package/package.json +6 -4
|
@@ -1,70 +1,64 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
import
|
|
3
|
-
import { createStack,
|
|
2
|
+
import readBlueprintOnDisk from '../../actions/blueprints/read-blueprint.js';
|
|
3
|
+
import { createStack, getStackByName, updateStack } from '../../actions/blueprints/stacks.js';
|
|
4
4
|
import { stashAsset } from '../../actions/blueprints/stash-asset.js';
|
|
5
|
+
import { green, red, yellow } from '../../utils/display/colors.js';
|
|
5
6
|
import Spinner from '../../utils/spinner.js';
|
|
6
7
|
export default class Deploy extends Command {
|
|
7
8
|
static description = 'Deploy a Blueprint';
|
|
8
9
|
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
9
10
|
async run() {
|
|
10
|
-
const {
|
|
11
|
+
const { document } = readBlueprintOnDisk();
|
|
12
|
+
const { displayName, name, projectId, resources } = document;
|
|
11
13
|
const s = new Spinner();
|
|
12
|
-
s.start('Deploying blueprint...');
|
|
13
14
|
const functionResources = resources.filter((r) => r.kind === 'function');
|
|
14
15
|
// First stash all function assets
|
|
15
16
|
if (functionResources.length > 0) {
|
|
16
|
-
s.stop('Preparing functions...');
|
|
17
17
|
for (const resource of functionResources) {
|
|
18
18
|
const fnSpinner = new Spinner();
|
|
19
19
|
fnSpinner.start(`Processing ${resource.name}...`);
|
|
20
|
-
const result = await stashAsset(resource);
|
|
20
|
+
const result = await stashAsset({ resource, projectId });
|
|
21
21
|
if (result.success) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
const src = resource.src;
|
|
23
|
+
resource.src = result.assetId; // TODO: properly reference asset - for now, the API expects the assetId
|
|
24
|
+
fnSpinner.stop(`${green('✓')} ${resource.name} <${yellow(result.assetId)}>`);
|
|
25
|
+
this.log(` Source: ${src}`);
|
|
25
26
|
}
|
|
26
27
|
else {
|
|
27
|
-
fnSpinner.stop(
|
|
28
|
+
fnSpinner.stop(`${red('✗')} Failed to process ${resource.name}`);
|
|
28
29
|
this.log(` Error: ${result.error}`);
|
|
29
30
|
return;
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
|
-
this.log('│');
|
|
33
|
-
s.start('Looking for existing stack...');
|
|
34
33
|
}
|
|
35
|
-
|
|
36
|
-
const { ok
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
s.start('Looking for existing stack...');
|
|
35
|
+
const { ok, error, stackId: existingStackId, } = await getStackByName({
|
|
36
|
+
name,
|
|
37
|
+
projectId,
|
|
38
|
+
});
|
|
39
|
+
if (!ok) {
|
|
40
|
+
s.stop(`${red('Failed')} to list stacks`);
|
|
41
|
+
this.log(`Error: ${error || 'Unknown error'}`);
|
|
40
42
|
return;
|
|
41
43
|
}
|
|
42
|
-
const existingStack = stacks.find((st) => st.name === name);
|
|
43
44
|
const blueprint = {
|
|
44
45
|
name,
|
|
45
46
|
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
|
-
},
|
|
47
|
+
document: { resources },
|
|
54
48
|
};
|
|
55
49
|
this.debug('BLUEPRINT DOCUMENT:', blueprint);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
: await createStack(blueprint);
|
|
50
|
+
const { ok: deployOk, stack, error: deployError, } = existingStackId
|
|
51
|
+
? await updateStack({ stackId: existingStackId, blueprint, projectId })
|
|
52
|
+
: await createStack({ blueprint, projectId });
|
|
60
53
|
this.debug('STACK RESPONSE:', stack);
|
|
61
|
-
if (
|
|
62
|
-
s.stop(
|
|
63
|
-
this.log('
|
|
54
|
+
if (deployOk) {
|
|
55
|
+
s.stop(`${green('Success!')} Stack ${existingStackId ? 'updated' : 'created'} <${yellow(stack.id)}>`);
|
|
56
|
+
this.log('\nUse `sanity blueprints info` to check deployment status');
|
|
64
57
|
}
|
|
65
58
|
else {
|
|
66
|
-
|
|
67
|
-
|
|
59
|
+
this.debug('STACK ERROR RESPONSE:', stack);
|
|
60
|
+
s.stop(`${red('Failed')} to ${existingStackId ? 'update' : 'create'} stack`);
|
|
61
|
+
this.log(`Error: ${deployError || 'Unknown error'}`);
|
|
68
62
|
}
|
|
69
63
|
}
|
|
70
64
|
}
|
|
@@ -1,68 +1,74 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import readBlueprintOnDisk from '../../actions/blueprints/read-blueprint.js';
|
|
3
|
+
import { getStackByName } from '../../actions/blueprints/stacks.js';
|
|
4
|
+
import { formatResourceTree, formatStacksList, formatTitle, } from '../../utils/display/blueprints-formatting.js';
|
|
5
|
+
import { bold, green, red, yellow } from '../../utils/display/colors.js';
|
|
6
|
+
import { formatDate, formatDuration } from '../../utils/display/dates.js';
|
|
4
7
|
import Spinner from '../../utils/spinner.js';
|
|
5
8
|
export default class Info extends Command {
|
|
6
9
|
static description = 'Show information about a Blueprint';
|
|
7
10
|
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
8
11
|
async run() {
|
|
9
|
-
const {
|
|
12
|
+
const { document } = readBlueprintOnDisk();
|
|
13
|
+
const { displayName, name, projectId } = document;
|
|
10
14
|
const s = new Spinner();
|
|
11
15
|
if (!projectId) {
|
|
12
|
-
this.log(`
|
|
16
|
+
this.log(`Cannot determine project for Blueprint "${displayName}"`);
|
|
13
17
|
return;
|
|
14
18
|
}
|
|
15
19
|
s.start(`Retrieving info for "${displayName}"`);
|
|
16
20
|
try {
|
|
17
|
-
const { ok,
|
|
21
|
+
const { ok, stack, stackId: foundStackId, error, availableStacks, } = await getStackByName({
|
|
22
|
+
name,
|
|
23
|
+
projectId,
|
|
24
|
+
});
|
|
18
25
|
if (!ok) {
|
|
19
|
-
s.stop('Failed to retrieve stacks
|
|
26
|
+
s.stop(`${red('Failed')} to retrieve stacks`);
|
|
20
27
|
this.log(`Error: ${error || 'Unknown error'}`);
|
|
21
28
|
return;
|
|
22
29
|
}
|
|
23
|
-
if (
|
|
24
|
-
s.stop(
|
|
30
|
+
if (!foundStackId || !stack) {
|
|
31
|
+
s.stop(`${red('Failed')} to find Stack for ${formatTitle('Blueprint', displayName)}`);
|
|
32
|
+
if (availableStacks && availableStacks.length > 0) {
|
|
33
|
+
this.log(formatStacksList(availableStacks));
|
|
34
|
+
}
|
|
25
35
|
return;
|
|
26
36
|
}
|
|
27
|
-
const foundStack =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
const foundStack = { id: foundStackId };
|
|
38
|
+
s.stop(`${formatTitle('Blueprint', displayName)} Info\n`);
|
|
39
|
+
this.log(`Stack name: ${bold(stack.name)}`);
|
|
40
|
+
this.log(`Stack ID: ${yellow(foundStack.id)}`);
|
|
41
|
+
if (stack.createdAt) {
|
|
42
|
+
this.log(`Created: ${formatDate(stack.createdAt)}`);
|
|
33
43
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.log(`├─ Functions (${functionResources.length})`);
|
|
42
|
-
for (const fn of functionResources) {
|
|
43
|
-
this.log(`│ ├─ ${fn.name} <${fn.externalId}>`);
|
|
44
|
-
}
|
|
44
|
+
if (stack.updatedAt) {
|
|
45
|
+
this.log(`Updated: ${formatDate(stack.updatedAt)}`);
|
|
46
|
+
}
|
|
47
|
+
if (stack.recentOperation) {
|
|
48
|
+
const operation = stack.recentOperation;
|
|
49
|
+
if (operation.id) {
|
|
50
|
+
this.log(`Recent Operation <${yellow(operation.id)}>:`);
|
|
45
51
|
}
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
52
|
+
if (operation.status) {
|
|
53
|
+
const operationColor = operation.status === 'COMPLETED' ? green : red;
|
|
54
|
+
const status = operation.status || 'UNKNOWN';
|
|
55
|
+
this.log(` Status: ${operationColor(status)}`);
|
|
51
56
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (stack.recentOperation.status !== 'COMPLETED') {
|
|
55
|
-
this.log('\nOperation Details:');
|
|
56
|
-
if (stack.recentOperation.error) {
|
|
57
|
-
this.log(`Error: ${stack.recentOperation.error}`);
|
|
57
|
+
if (operation.createdAt) {
|
|
58
|
+
this.log(` Started : ${formatDate(operation.createdAt)}`);
|
|
58
59
|
}
|
|
59
|
-
if (
|
|
60
|
-
this.log(`
|
|
60
|
+
if (operation.status === 'COMPLETED' && operation.completedAt && operation.createdAt) {
|
|
61
|
+
this.log(` Completed: ${formatDate(operation.completedAt)}`);
|
|
62
|
+
this.log(` Duration: ${yellow(formatDuration(operation.createdAt, operation.completedAt))}`);
|
|
61
63
|
}
|
|
62
64
|
}
|
|
65
|
+
this.log('');
|
|
66
|
+
if (stack?.resources) {
|
|
67
|
+
formatResourceTree(stack.resources, this.log.bind(this));
|
|
68
|
+
}
|
|
63
69
|
}
|
|
64
70
|
catch (err) {
|
|
65
|
-
s.stop('Failed to
|
|
71
|
+
s.stop('Failed to parse Stack info');
|
|
66
72
|
if (err instanceof Error) {
|
|
67
73
|
this.log(`Error: ${err.message}`);
|
|
68
74
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class Logs extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
'stack-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
watch: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import { getLogs, streamLogs } from '../../actions/blueprints/logs.js';
|
|
3
|
+
import readBlueprintOnDisk from '../../actions/blueprints/read-blueprint.js';
|
|
4
|
+
import { getStackByName } from '../../actions/blueprints/stacks.js';
|
|
5
|
+
import config from '../../config.js';
|
|
6
|
+
import { formatStacksList, formatTitle } from '../../utils/display/blueprints-formatting.js';
|
|
7
|
+
import { blue, bold, green, red, yellow } from '../../utils/display/colors.js';
|
|
8
|
+
import Spinner from '../../utils/spinner.js';
|
|
9
|
+
export default class Logs extends Command {
|
|
10
|
+
static description = 'Display logs for a Blueprint stack';
|
|
11
|
+
static examples = [
|
|
12
|
+
'<%= config.bin %> <%= command.id %>',
|
|
13
|
+
'<%= config.bin %> <%= command.id %> --stack-id <stack-id>',
|
|
14
|
+
'<%= config.bin %> <%= command.id %> --watch',
|
|
15
|
+
];
|
|
16
|
+
static flags = {
|
|
17
|
+
'stack-id': Flags.string({
|
|
18
|
+
char: 's',
|
|
19
|
+
description: 'Stack ID to fetch logs for (optional if running in a blueprint directory)',
|
|
20
|
+
required: false,
|
|
21
|
+
}),
|
|
22
|
+
watch: Flags.boolean({
|
|
23
|
+
char: 'w',
|
|
24
|
+
description: 'Watch for new logs (streaming mode)',
|
|
25
|
+
required: false,
|
|
26
|
+
default: false,
|
|
27
|
+
}),
|
|
28
|
+
};
|
|
29
|
+
async run() {
|
|
30
|
+
const { flags } = await this.parse(Logs);
|
|
31
|
+
const s = new Spinner();
|
|
32
|
+
const watchMode = flags.watch;
|
|
33
|
+
try {
|
|
34
|
+
const { document } = readBlueprintOnDisk();
|
|
35
|
+
const { name, displayName, projectId } = document;
|
|
36
|
+
if (!projectId) {
|
|
37
|
+
this.log('Cannot determine project ID for this Blueprint');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
let stackId = flags['stack-id'];
|
|
41
|
+
if (!stackId) {
|
|
42
|
+
s.start(`Finding stack for blueprint "${displayName}"`);
|
|
43
|
+
const { ok, stackId: foundStackId, error, availableStacks, } = await getStackByName({
|
|
44
|
+
name,
|
|
45
|
+
projectId,
|
|
46
|
+
});
|
|
47
|
+
if (!ok) {
|
|
48
|
+
s.stop(`${red('Failed')} to retrieve stacks`);
|
|
49
|
+
this.log(`Error: ${error || 'Unknown error'}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (!foundStackId) {
|
|
53
|
+
s.stop(`${red('Failed')} to find Stack for ${formatTitle('Blueprint', displayName)}`);
|
|
54
|
+
if (availableStacks && availableStacks.length > 0) {
|
|
55
|
+
this.log(formatStacksList(availableStacks));
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
stackId = foundStackId;
|
|
60
|
+
s.stop(`Found stack ${stackId} for blueprint "${displayName}"`);
|
|
61
|
+
}
|
|
62
|
+
if (!stackId) {
|
|
63
|
+
s.stop(`${red('Failed')} to determine stack ID`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (watchMode) {
|
|
67
|
+
// recent logs
|
|
68
|
+
s.start(`Fetching recent logs for stack ${stackId}`);
|
|
69
|
+
const { ok, logs, error } = await getLogs(stackId, projectId, config.token);
|
|
70
|
+
if (!ok) {
|
|
71
|
+
s.stop(`${red('Failed')} to retrieve logs`);
|
|
72
|
+
this.log(`Error: ${error || 'Unknown error'}`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
s.stop(`${formatTitle('Blueprint', displayName)} ${bold('Live')} Logs`);
|
|
76
|
+
if (logs.length > 0) {
|
|
77
|
+
this.log('\nMost recent logs:');
|
|
78
|
+
const sortedLogs = [...logs].sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
79
|
+
const recentLogs = sortedLogs.slice(-10);
|
|
80
|
+
for (const log of recentLogs) {
|
|
81
|
+
const date = new Date(log.timestamp);
|
|
82
|
+
const time = date.toLocaleTimeString();
|
|
83
|
+
const day = date.toLocaleDateString();
|
|
84
|
+
this.log(` ${bold(day)} ${yellow(time)} ${log.message}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
this.log(`No recent logs found for stack ${yellow(stackId)}`);
|
|
89
|
+
}
|
|
90
|
+
const onOpen = () => {
|
|
91
|
+
this.log(`\n${bold('Watching')} for new logs...`);
|
|
92
|
+
this.log(`Press ${bold('Ctrl+C')} to stop\n`);
|
|
93
|
+
};
|
|
94
|
+
let newestTimestamp = 0;
|
|
95
|
+
if (logs.length > 0) {
|
|
96
|
+
for (const log of logs) {
|
|
97
|
+
const timestamp = new Date(log.timestamp).getTime();
|
|
98
|
+
if (timestamp > newestTimestamp) {
|
|
99
|
+
newestTimestamp = timestamp;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const renderLog = (log) => {
|
|
104
|
+
const logTimestamp = new Date(log.timestamp).getTime();
|
|
105
|
+
if (logTimestamp <= newestTimestamp) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
newestTimestamp = logTimestamp;
|
|
109
|
+
const date = new Date(log.timestamp);
|
|
110
|
+
const time = date.toLocaleTimeString();
|
|
111
|
+
const day = date.toLocaleDateString();
|
|
112
|
+
this.log(`${green('>')} ${bold(day)} ${yellow(time)} ${log.message}`);
|
|
113
|
+
};
|
|
114
|
+
this.debug(`${yellow('Debug:')} Connecting to streaming endpoint for stack ${stackId}...`);
|
|
115
|
+
streamLogs(stackId, projectId, config.token, renderLog, onOpen, (error) => this.log(`${red('Error:')} ${error}`));
|
|
116
|
+
return new Promise(() => {
|
|
117
|
+
// hold the line until the user terminates with Ctrl+C
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
s.start(`Fetching logs for stack ${stackId}`);
|
|
121
|
+
const { ok, logs, error } = await getLogs(stackId, projectId, config.token);
|
|
122
|
+
if (!ok) {
|
|
123
|
+
s.stop(`${red('Failed')} to retrieve logs`);
|
|
124
|
+
this.log(`Error: ${error || 'Unknown error'}`);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (logs.length === 0) {
|
|
128
|
+
s.stop(`No logs found for stack ${stackId}`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
s.stop(`${formatTitle('Blueprint', displayName)} Logs`);
|
|
132
|
+
this.log(`Found ${bold(logs.length.toString())} log entries for stack ${yellow(stackId)}\n`);
|
|
133
|
+
const logsByDay = new Map();
|
|
134
|
+
for (const log of logs) {
|
|
135
|
+
const date = new Date(log.timestamp);
|
|
136
|
+
const day = date.toLocaleDateString();
|
|
137
|
+
if (!logsByDay.has(day)) {
|
|
138
|
+
logsByDay.set(day, []);
|
|
139
|
+
}
|
|
140
|
+
logsByDay.get(day)?.push(log);
|
|
141
|
+
}
|
|
142
|
+
const sortedDays = Array.from(logsByDay.keys()).sort((a, b) => {
|
|
143
|
+
return new Date(a).getTime() - new Date(b).getTime();
|
|
144
|
+
});
|
|
145
|
+
for (const day of sortedDays) {
|
|
146
|
+
this.log(`${blue('Date:')} ${bold(day)}`);
|
|
147
|
+
const dayLogs = logsByDay.get(day) || [];
|
|
148
|
+
dayLogs.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
149
|
+
for (const [i, log] of dayLogs.entries()) {
|
|
150
|
+
const date = new Date(log.timestamp);
|
|
151
|
+
const time = date.toLocaleTimeString();
|
|
152
|
+
const isLast = i === dayLogs.length - 1;
|
|
153
|
+
this.log(` ${isLast ? '└─' : '├─'} ${yellow(time)} ${log.message}`);
|
|
154
|
+
}
|
|
155
|
+
// new line between days
|
|
156
|
+
this.log('');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
s.stop('Failed to retrieve logs');
|
|
161
|
+
if (err instanceof Error) {
|
|
162
|
+
this.log(`Error: ${err.message}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -1,31 +1,18 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
import
|
|
2
|
+
import readBlueprintOnDisk from '../../actions/blueprints/read-blueprint.js';
|
|
3
|
+
import { formatResourceTree, formatTitle } from '../../utils/display/blueprints-formatting.js';
|
|
3
4
|
export default class Plan extends Command {
|
|
4
5
|
static description = 'Enumerate resources to be deployed - will not modify any resources';
|
|
5
6
|
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
6
7
|
async run() {
|
|
7
|
-
const {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
this.log('
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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');
|
|
8
|
+
const { document, fileName } = readBlueprintOnDisk();
|
|
9
|
+
const { displayName, name, resources } = document;
|
|
10
|
+
this.log(`${formatTitle('Blueprint', displayName)} Plan\n`);
|
|
11
|
+
this.log(`Blueprint document: "${name}" (${fileName})`);
|
|
12
|
+
this.log('');
|
|
13
|
+
formatResourceTree(resources, this.log.bind(this));
|
|
14
|
+
if (resources.length > 0) {
|
|
15
|
+
this.log('\nRun `sanity blueprints deploy` to deploy these changes');
|
|
29
16
|
}
|
|
30
17
|
}
|
|
31
18
|
}
|
package/dist/config.js
CHANGED
|
@@ -9,8 +9,8 @@ const functionsUrls = {
|
|
|
9
9
|
default: 'http://localhost:4567',
|
|
10
10
|
};
|
|
11
11
|
const blueprintsUrls = {
|
|
12
|
-
production: 'https://api.sanity.io
|
|
13
|
-
staging: 'https://api.sanity.work
|
|
12
|
+
production: 'https://api.sanity.io',
|
|
13
|
+
staging: 'https://api.sanity.work',
|
|
14
14
|
default: 'http://localhost:4567',
|
|
15
15
|
};
|
|
16
16
|
const functionsUrl = new URL(functionsUrls[nodeEnv] ?? functionsUrls.default);
|
package/dist/server/app.d.ts
CHANGED
package/dist/server/app.js
CHANGED
|
@@ -1,36 +1,66 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { cwd } from 'node:process';
|
|
4
|
-
import {
|
|
5
|
-
import { Hono } from 'hono';
|
|
4
|
+
import { default as mime } from 'mime-types';
|
|
6
5
|
import invoke from '../utils/invoke-local.js';
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
6
|
+
import * as http from 'node:http';
|
|
7
|
+
const host = 'localhost';
|
|
8
|
+
const app = (port) => {
|
|
9
|
+
const requestListener = async (req, res) => {
|
|
10
|
+
res.setHeader('Content-Type', 'application/json');
|
|
11
|
+
switch (req.url) {
|
|
12
|
+
case '/blueprint': {
|
|
13
|
+
res.setHeader('Content-Type', 'application/json');
|
|
14
|
+
const blueprint = readFileSync(join(cwd(), './blueprint.json')).toString();
|
|
15
|
+
res.writeHead(200);
|
|
16
|
+
res.end(blueprint);
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
case '/invoke': {
|
|
20
|
+
if (req.method === 'POST') {
|
|
21
|
+
let body = '';
|
|
22
|
+
req.on('data', (data) => {
|
|
23
|
+
body += data;
|
|
24
|
+
});
|
|
25
|
+
req.on('end', async () => {
|
|
26
|
+
const { data, func } = JSON.parse(body);
|
|
27
|
+
res.setHeader('Content-Type', 'application/json');
|
|
28
|
+
try {
|
|
29
|
+
const response = await invoke(func, { data: JSON.parse(data) });
|
|
30
|
+
res.writeHead(200);
|
|
31
|
+
res.end(JSON.stringify(response));
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const response = { logs: '', error: '' };
|
|
35
|
+
if (error instanceof Error) {
|
|
36
|
+
response.logs = error.message;
|
|
37
|
+
}
|
|
38
|
+
res.writeHead(200);
|
|
39
|
+
res.end(JSON.stringify(response));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
default: {
|
|
46
|
+
const requestPath = req.url?.endsWith('/') ? `${req.url}index.html` : req.url;
|
|
47
|
+
const filePath = new URL(`./static${requestPath}`, import.meta.url).pathname;
|
|
48
|
+
if (existsSync(filePath)) {
|
|
49
|
+
const mimeType = mime.lookup(filePath) || 'text/plain';
|
|
50
|
+
res.setHeader('Content-Type', mimeType);
|
|
51
|
+
const content = readFileSync(filePath).toString();
|
|
52
|
+
res.writeHead(200);
|
|
53
|
+
res.end(content);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
res.writeHead(404);
|
|
57
|
+
res.end();
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const server = http.createServer(requestListener);
|
|
64
|
+
server.listen(port, host, () => { });
|
|
65
|
+
};
|
|
36
66
|
export default app;
|
|
@@ -8787,14 +8787,14 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
|
8787
8787
|
let moveX = 0, moveY = 0;
|
|
8788
8788
|
if (y == "nearest") {
|
|
8789
8789
|
if (rect.top < bounding.top) {
|
|
8790
|
-
moveY =
|
|
8790
|
+
moveY = rect.top - (bounding.top + yMargin);
|
|
8791
8791
|
if (side > 0 && rect.bottom > bounding.bottom + moveY)
|
|
8792
|
-
moveY = rect.bottom - bounding.bottom +
|
|
8792
|
+
moveY = rect.bottom - bounding.bottom + yMargin;
|
|
8793
8793
|
}
|
|
8794
8794
|
else if (rect.bottom > bounding.bottom) {
|
|
8795
8795
|
moveY = rect.bottom - bounding.bottom + yMargin;
|
|
8796
8796
|
if (side < 0 && (rect.top - moveY) < bounding.top)
|
|
8797
|
-
moveY =
|
|
8797
|
+
moveY = rect.top - (bounding.top + yMargin);
|
|
8798
8798
|
}
|
|
8799
8799
|
}
|
|
8800
8800
|
else {
|
|
@@ -8806,14 +8806,14 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
|
8806
8806
|
}
|
|
8807
8807
|
if (x == "nearest") {
|
|
8808
8808
|
if (rect.left < bounding.left) {
|
|
8809
|
-
moveX =
|
|
8809
|
+
moveX = rect.left - (bounding.left + xMargin);
|
|
8810
8810
|
if (side > 0 && rect.right > bounding.right + moveX)
|
|
8811
|
-
moveX = rect.right - bounding.right +
|
|
8811
|
+
moveX = rect.right - bounding.right + xMargin;
|
|
8812
8812
|
}
|
|
8813
8813
|
else if (rect.right > bounding.right) {
|
|
8814
8814
|
moveX = rect.right - bounding.right + xMargin;
|
|
8815
8815
|
if (side < 0 && rect.left < bounding.left + moveX)
|
|
8816
|
-
moveX =
|
|
8816
|
+
moveX = rect.left - (bounding.left + xMargin);
|
|
8817
8817
|
}
|
|
8818
8818
|
}
|
|
8819
8819
|
else {
|
|
@@ -8848,6 +8848,10 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
|
8848
8848
|
}
|
|
8849
8849
|
if (top)
|
|
8850
8850
|
break;
|
|
8851
|
+
if (rect.top < bounding.top || rect.bottom > bounding.bottom ||
|
|
8852
|
+
rect.left < bounding.left || rect.right > bounding.right)
|
|
8853
|
+
rect = { left: Math.max(rect.left, bounding.left), right: Math.min(rect.right, bounding.right),
|
|
8854
|
+
top: Math.max(rect.top, bounding.top), bottom: Math.min(rect.bottom, bounding.bottom) };
|
|
8851
8855
|
cur = cur.assignedSlot || cur.parentNode;
|
|
8852
8856
|
}
|
|
8853
8857
|
else if (cur.nodeType == 11) { // A shadow root
|
|
@@ -23360,7 +23364,15 @@ function createLineDialog(view) {
|
|
|
23360
23364
|
event.preventDefault();
|
|
23361
23365
|
go();
|
|
23362
23366
|
}
|
|
23363
|
-
}, crelt("label", view.state.phrase("Go to line"), ": ", input), " ", crelt("button", { class: "cm-button", type: "submit" }, view.state.phrase("go"))
|
|
23367
|
+
}, crelt("label", view.state.phrase("Go to line"), ": ", input), " ", crelt("button", { class: "cm-button", type: "submit" }, view.state.phrase("go")), crelt("button", {
|
|
23368
|
+
name: "close",
|
|
23369
|
+
onclick: () => {
|
|
23370
|
+
view.dispatch({ effects: dialogEffect.of(false) });
|
|
23371
|
+
view.focus();
|
|
23372
|
+
},
|
|
23373
|
+
"aria-label": view.state.phrase("close"),
|
|
23374
|
+
type: "button"
|
|
23375
|
+
}, ["×"]));
|
|
23364
23376
|
function go() {
|
|
23365
23377
|
let match = /^([+-])?(\d+)?(:\d+)?(%)?$/.exec(input.value);
|
|
23366
23378
|
if (!match)
|
|
@@ -23424,7 +23436,17 @@ const gotoLine = view => {
|
|
|
23424
23436
|
const baseTheme$1$1 = /*@__PURE__*/EditorView.baseTheme({
|
|
23425
23437
|
".cm-panel.cm-gotoLine": {
|
|
23426
23438
|
padding: "2px 6px 4px",
|
|
23427
|
-
|
|
23439
|
+
position: "relative",
|
|
23440
|
+
"& label": { fontSize: "80%" },
|
|
23441
|
+
"& [name=close]": {
|
|
23442
|
+
position: "absolute",
|
|
23443
|
+
top: "0", bottom: "0",
|
|
23444
|
+
right: "4px",
|
|
23445
|
+
backgroundColor: "inherit",
|
|
23446
|
+
border: "none",
|
|
23447
|
+
font: "inherit",
|
|
23448
|
+
padding: "0"
|
|
23449
|
+
}
|
|
23428
23450
|
}
|
|
23429
23451
|
});
|
|
23430
23452
|
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BlueprintResource } from '../types.js';
|
|
2
|
+
export declare function formatTitle(title: string, name: string): string;
|
|
3
|
+
export declare function formatStacksList(stacks: string[]): string;
|
|
4
|
+
export declare function formatResourceTree(resources: BlueprintResource[], logger: (msg: string) => void): void;
|