@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.
Files changed (32) hide show
  1. package/README.md +42 -16
  2. package/dist/actions/blueprints/logs.d.ts +7 -0
  3. package/dist/actions/blueprints/logs.js +79 -0
  4. package/dist/actions/blueprints/operations.d.ts +18 -0
  5. package/dist/actions/blueprints/operations.js +52 -0
  6. package/dist/actions/blueprints/read-blueprint.d.ts +6 -1
  7. package/dist/actions/blueprints/read-blueprint.js +35 -9
  8. package/dist/actions/blueprints/stacks.d.ts +33 -5
  9. package/dist/actions/blueprints/stacks.js +53 -17
  10. package/dist/actions/blueprints/stash-asset.d.ts +4 -1
  11. package/dist/actions/blueprints/stash-asset.js +12 -7
  12. package/dist/actions/functions/dev.js +1 -2
  13. package/dist/actions/functions/invoke.js +8 -5
  14. package/dist/commands/blueprints/deploy.js +29 -35
  15. package/dist/commands/blueprints/info.js +45 -39
  16. package/dist/commands/blueprints/logs.d.ts +10 -0
  17. package/dist/commands/blueprints/logs.js +166 -0
  18. package/dist/commands/blueprints/plan.js +10 -23
  19. package/dist/config.js +2 -2
  20. package/dist/server/app.d.ts +1 -2
  21. package/dist/server/app.js +62 -32
  22. package/dist/server/static/vendor/vendor.bundle.js +30 -8
  23. package/dist/utils/display/blueprints-formatting.d.ts +4 -0
  24. package/dist/utils/display/blueprints-formatting.js +42 -0
  25. package/dist/utils/display/colors.d.ts +6 -0
  26. package/dist/utils/display/colors.js +18 -0
  27. package/dist/utils/display/dates.d.ts +2 -0
  28. package/dist/utils/display/dates.js +26 -0
  29. package/dist/utils/invoke-local.js +1 -5
  30. package/dist/utils/types.d.ts +22 -3
  31. package/oclif.manifest.json +45 -1
  32. package/package.json +6 -4
@@ -1,70 +1,64 @@
1
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';
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 { displayName, name, projectId, resources } = readBlueprint();
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
- resource.assetId = result.assetId;
23
- fnSpinner.stop(`✓ ${resource.name} (${result.assetId})`);
24
- this.log(` Source: ${resource.src}`);
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(`✗ Failed to process ${resource.name}`);
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
- // 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'}`);
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
- // Create or update stack
57
- const { ok, stack, error } = existingStack
58
- ? await updateStack(existingStack.id, blueprint)
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 (ok) {
62
- s.stop(`Stack ${existingStack ? 'updated' : 'created'}! (${stack.id})`);
63
- this.log('Use `blueprints info` to check deployment status');
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
- s.stop(`Failed to ${existingStack ? 'update' : 'create'} stack`);
67
- this.log(`Error: ${error || 'Unknown error'}`);
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 readBlueprint from '../../actions/blueprints/read-blueprint.js';
3
- import { getStack, listStacks } from '../../actions/blueprints/stacks.js';
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 { displayName, name, projectId, resources } = readBlueprint();
12
+ const { document } = readBlueprintOnDisk();
13
+ const { displayName, name, projectId } = document;
10
14
  const s = new Spinner();
11
15
  if (!projectId) {
12
- this.log(`No project for Blueprint "${displayName}"`);
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, stacks, error } = await listStacks();
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 (stacks.length === 0) {
24
- s.stop(`No stacks found for Blueprint "${displayName}"`);
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 = 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;
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
- 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
- }
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 (otherResources.length > 0) {
47
- this.log(`└─Other Resources (${otherResources.length})`);
48
- for (const other of otherResources) {
49
- this.log(` ├─ ${other.name || other.src}`);
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
- // 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}`);
57
+ if (operation.createdAt) {
58
+ this.log(` Started : ${formatDate(operation.createdAt)}`);
58
59
  }
59
- if (stack.recentOperation.progress) {
60
- this.log(`Progress: ${stack.recentOperation.progress}`);
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 retrieve info');
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 readBlueprint from '../../actions/blueprints/read-blueprint.js';
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 { 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');
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);
@@ -1,3 +1,2 @@
1
- import { Hono } from 'hono';
2
- declare const app: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
1
+ declare const app: (port: number) => void;
3
2
  export default app;
@@ -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 { serveStatic } from '@hono/node-server/serve-static';
5
- import { Hono } from 'hono';
4
+ import { default as mime } from 'mime-types';
6
5
  import invoke from '../utils/invoke-local.js';
7
- import isDependency from '../utils/is-dependency.js';
8
- function errorResponse(code, message, details = {}) {
9
- return { error: { code, details, message } };
10
- }
11
- function getStaticPath() {
12
- return isDependency('./server/static')
13
- ? './node_modules/@sanity/runtime-cli/dist/server/static'
14
- : './src/server/static';
15
- }
16
- const app = new Hono();
17
- app.use('*', serveStatic({ root: getStaticPath() }));
18
- app.get('/blueprint', async (c) => {
19
- const response = JSON.parse(readFileSync(join(cwd(), './blueprint.json')).toString());
20
- return c.json(response);
21
- });
22
- app.post('/invoke', async (c) => {
23
- const { data = {}, func } = await c.req.json();
24
- const response = await invoke(func, { data: JSON.parse(data) });
25
- return c.json(response);
26
- });
27
- app
28
- .notFound((c) => c.json(errorResponse('NOT_FOUND', 'Not Found', {
29
- method: c.req.method,
30
- path: c.req.path,
31
- }), 404))
32
- .onError((err, c) => c.json(errorResponse('INTERNAL_SERVER_ERROR', 'Internal Server Error', {
33
- error: err.message,
34
- stack: err,
35
- }), 500));
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 = -(bounding.top - rect.top + yMargin);
8790
+ moveY = rect.top - (bounding.top + yMargin);
8791
8791
  if (side > 0 && rect.bottom > bounding.bottom + moveY)
8792
- moveY = rect.bottom - bounding.bottom + moveY + yMargin;
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 = -(bounding.top + moveY - rect.top + yMargin);
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 = -(bounding.left - rect.left + xMargin);
8809
+ moveX = rect.left - (bounding.left + xMargin);
8810
8810
  if (side > 0 && rect.right > bounding.right + moveX)
8811
- moveX = rect.right - bounding.right + moveX + xMargin;
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 = -(bounding.left + moveX - rect.left + xMargin);
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
- "& label": { fontSize: "80%" }
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;