@sanity/runtime-cli 14.12.1 → 14.13.1
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 +31 -24
- package/dist/actions/blueprints/logs-polling.d.ts +20 -0
- package/dist/actions/blueprints/logs-polling.js +48 -0
- package/dist/actions/blueprints/logs.d.ts +7 -1
- package/dist/actions/blueprints/logs.js +9 -2
- package/dist/actions/blueprints/stacks.d.ts +6 -2
- package/dist/actions/sanity/projects.d.ts +2 -1
- package/dist/actions/sanity/projects.js +5 -2
- package/dist/commands/blueprints/add.d.ts +4 -1
- package/dist/commands/blueprints/add.js +11 -14
- package/dist/commands/blueprints/stacks.d.ts +1 -0
- package/dist/commands/blueprints/stacks.js +12 -2
- package/dist/cores/blueprints/deploy.js +3 -4
- package/dist/cores/blueprints/destroy.js +11 -9
- package/dist/cores/blueprints/logs.js +7 -6
- package/dist/cores/blueprints/stacks.d.ts +1 -0
- package/dist/cores/blueprints/stacks.js +73 -2
- package/dist/utils/display/resources-formatting.js +7 -5
- package/oclif.manifest.json +21 -6
- package/package.json +3 -1
- package/dist/actions/blueprints/logs-streaming.d.ts +0 -30
- package/dist/actions/blueprints/logs-streaming.js +0 -107
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/14.
|
|
23
|
+
@sanity/runtime-cli/14.13.1 linux-x64 node-v24.14.1
|
|
24
24
|
$ sanity-run --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ sanity-run COMMAND
|
|
@@ -50,7 +50,7 @@ USAGE
|
|
|
50
50
|
|
|
51
51
|
## `sanity-run blueprints add TYPE`
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
[deprecated] Use "functions add" instead
|
|
54
54
|
|
|
55
55
|
```
|
|
56
56
|
USAGE
|
|
@@ -82,12 +82,13 @@ FLAGS
|
|
|
82
82
|
--[no-]validate-resources Validate resources
|
|
83
83
|
|
|
84
84
|
DESCRIPTION
|
|
85
|
-
|
|
85
|
+
[deprecated] Use "functions add" instead
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
(create, update, delete, publish) or media library events.
|
|
87
|
+
This command is deprecated. Use "functions add" instead.
|
|
89
88
|
|
|
90
|
-
|
|
89
|
+
Equivalent usage:
|
|
90
|
+
$ sanity-run functions add
|
|
91
|
+
$ sanity-run functions add --name my-function --type document-create
|
|
91
92
|
|
|
92
93
|
EXAMPLES
|
|
93
94
|
$ sanity-run blueprints add function
|
|
@@ -101,7 +102,7 @@ EXAMPLES
|
|
|
101
102
|
$ sanity-run blueprints add function --name my-function --fn-type document-create --fn-type document-update --lang js
|
|
102
103
|
```
|
|
103
104
|
|
|
104
|
-
_See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
105
|
+
_See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/blueprints/add.ts)_
|
|
105
106
|
|
|
106
107
|
## `sanity-run blueprints config`
|
|
107
108
|
|
|
@@ -140,7 +141,7 @@ EXAMPLES
|
|
|
140
141
|
$ sanity-run blueprints config --edit --project-id <projectId> --stack <name-or-id>
|
|
141
142
|
```
|
|
142
143
|
|
|
143
|
-
_See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
144
|
+
_See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/blueprints/config.ts)_
|
|
144
145
|
|
|
145
146
|
## `sanity-run blueprints deploy`
|
|
146
147
|
|
|
@@ -182,7 +183,7 @@ EXAMPLES
|
|
|
182
183
|
$ sanity-run blueprints deploy --fn-installer npm
|
|
183
184
|
```
|
|
184
185
|
|
|
185
|
-
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
186
|
+
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/blueprints/deploy.ts)_
|
|
186
187
|
|
|
187
188
|
## `sanity-run blueprints destroy`
|
|
188
189
|
|
|
@@ -218,7 +219,7 @@ EXAMPLES
|
|
|
218
219
|
$ sanity-run blueprints destroy --stack <name-or-id> --project-id <projectId> --force --no-wait
|
|
219
220
|
```
|
|
220
221
|
|
|
221
|
-
_See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
222
|
+
_See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/blueprints/destroy.ts)_
|
|
222
223
|
|
|
223
224
|
## `sanity-run blueprints doctor`
|
|
224
225
|
|
|
@@ -250,7 +251,7 @@ EXAMPLES
|
|
|
250
251
|
$ sanity-run blueprints doctor --fix
|
|
251
252
|
```
|
|
252
253
|
|
|
253
|
-
_See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
254
|
+
_See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/blueprints/doctor.ts)_
|
|
254
255
|
|
|
255
256
|
## `sanity-run blueprints info`
|
|
256
257
|
|
|
@@ -285,7 +286,7 @@ EXAMPLES
|
|
|
285
286
|
$ sanity-run blueprints info --project-id <id> --stack <name-or-id>
|
|
286
287
|
```
|
|
287
288
|
|
|
288
|
-
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
289
|
+
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/blueprints/info.ts)_
|
|
289
290
|
|
|
290
291
|
## `sanity-run blueprints init [DIR]`
|
|
291
292
|
|
|
@@ -338,7 +339,7 @@ EXAMPLES
|
|
|
338
339
|
$ sanity-run blueprints init --blueprint-type <json|js|ts> --stack-name <stackName>
|
|
339
340
|
```
|
|
340
341
|
|
|
341
|
-
_See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
342
|
+
_See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/blueprints/init.ts)_
|
|
342
343
|
|
|
343
344
|
## `sanity-run blueprints logs`
|
|
344
345
|
|
|
@@ -369,7 +370,7 @@ EXAMPLES
|
|
|
369
370
|
$ sanity-run blueprints logs --watch
|
|
370
371
|
```
|
|
371
372
|
|
|
372
|
-
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
373
|
+
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/blueprints/logs.ts)_
|
|
373
374
|
|
|
374
375
|
## `sanity-run blueprints plan`
|
|
375
376
|
|
|
@@ -397,7 +398,7 @@ EXAMPLES
|
|
|
397
398
|
$ sanity-run blueprints plan
|
|
398
399
|
```
|
|
399
400
|
|
|
400
|
-
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
401
|
+
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/blueprints/plan.ts)_
|
|
401
402
|
|
|
402
403
|
## `sanity-run blueprints stacks`
|
|
403
404
|
|
|
@@ -405,9 +406,11 @@ List remote Stack deployments for your project or organization
|
|
|
405
406
|
|
|
406
407
|
```
|
|
407
408
|
USAGE
|
|
408
|
-
$ sanity-run blueprints stacks [--json] [--validate-resources] [--project-id <value> | --organization-id <value>
|
|
409
|
+
$ sanity-run blueprints stacks [--json] [--validate-resources] [--project-id <value> | --organization-id <value> |
|
|
410
|
+
--include-projects]
|
|
409
411
|
|
|
410
412
|
FLAGS
|
|
413
|
+
--include-projects Include Stacks from all projects within the organization. Requires --organization-id.
|
|
411
414
|
--json Format output as json
|
|
412
415
|
--organization-id=<value> Sanity organization ID used to scope Blueprint and Stack
|
|
413
416
|
--project-id=<value> Sanity project ID used to scope Blueprint and Stack
|
|
@@ -421,15 +424,19 @@ DESCRIPTION
|
|
|
421
424
|
Use this to discover existing Stacks you can scope a local Blueprint to (using 'blueprints config --edit'), or to
|
|
422
425
|
audit what's deployed across your project.
|
|
423
426
|
|
|
427
|
+
Use --include-projects with --organization-id to also list Stacks from all projects within the organization.
|
|
428
|
+
|
|
424
429
|
EXAMPLES
|
|
425
430
|
$ sanity-run blueprints stacks
|
|
426
431
|
|
|
427
432
|
$ sanity-run blueprints stacks --project-id <projectId>
|
|
428
433
|
|
|
429
434
|
$ sanity-run blueprints stacks --organization-id <organizationId>
|
|
435
|
+
|
|
436
|
+
$ sanity-run blueprints stacks --organization-id <organizationId> --include-projects
|
|
430
437
|
```
|
|
431
438
|
|
|
432
|
-
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
439
|
+
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/blueprints/stacks.ts)_
|
|
433
440
|
|
|
434
441
|
## `sanity-run functions add`
|
|
435
442
|
|
|
@@ -482,7 +489,7 @@ EXAMPLES
|
|
|
482
489
|
$ sanity-run functions add --name my-function --type document-create --type document-update --lang js
|
|
483
490
|
```
|
|
484
491
|
|
|
485
|
-
_See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
492
|
+
_See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/functions/add.ts)_
|
|
486
493
|
|
|
487
494
|
## `sanity-run functions dev`
|
|
488
495
|
|
|
@@ -518,7 +525,7 @@ EXAMPLES
|
|
|
518
525
|
$ sanity-run functions dev --timeout 60
|
|
519
526
|
```
|
|
520
527
|
|
|
521
|
-
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
528
|
+
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/functions/dev.ts)_
|
|
522
529
|
|
|
523
530
|
## `sanity-run functions env add NAME KEY VALUE`
|
|
524
531
|
|
|
@@ -549,7 +556,7 @@ EXAMPLES
|
|
|
549
556
|
$ sanity-run functions env add MyFunction API_URL https://api.example.com/
|
|
550
557
|
```
|
|
551
558
|
|
|
552
|
-
_See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
559
|
+
_See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/functions/env/add.ts)_
|
|
553
560
|
|
|
554
561
|
## `sanity-run functions env list NAME`
|
|
555
562
|
|
|
@@ -577,7 +584,7 @@ EXAMPLES
|
|
|
577
584
|
$ sanity-run functions env list MyFunction
|
|
578
585
|
```
|
|
579
586
|
|
|
580
|
-
_See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
587
|
+
_See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/functions/env/list.ts)_
|
|
581
588
|
|
|
582
589
|
## `sanity-run functions env remove NAME KEY`
|
|
583
590
|
|
|
@@ -607,7 +614,7 @@ EXAMPLES
|
|
|
607
614
|
$ sanity-run functions env remove MyFunction API_URL
|
|
608
615
|
```
|
|
609
616
|
|
|
610
|
-
_See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
617
|
+
_See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/functions/env/remove.ts)_
|
|
611
618
|
|
|
612
619
|
## `sanity-run functions logs [NAME]`
|
|
613
620
|
|
|
@@ -649,7 +656,7 @@ EXAMPLES
|
|
|
649
656
|
$ sanity-run functions logs <name> --delete
|
|
650
657
|
```
|
|
651
658
|
|
|
652
|
-
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
659
|
+
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/functions/logs.ts)_
|
|
653
660
|
|
|
654
661
|
## `sanity-run functions test [NAME]`
|
|
655
662
|
|
|
@@ -707,7 +714,7 @@ EXAMPLES
|
|
|
707
714
|
$ sanity-run functions test <name> --event update --data-before '{ "title": "before" }' --data-after '{ "title": "after" }'
|
|
708
715
|
```
|
|
709
716
|
|
|
710
|
-
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v14.
|
|
717
|
+
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v14.13.1/src/commands/functions/test.ts)_
|
|
711
718
|
|
|
712
719
|
## `sanity-run help [COMMAND]`
|
|
713
720
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Logger } from '../../utils/logger.js';
|
|
2
|
+
import type { AuthParams, BlueprintLog } from '../../utils/types.js';
|
|
3
|
+
export declare const LOG_POLL_INTERVAL_MS = 725;
|
|
4
|
+
export interface LogPollingConfig {
|
|
5
|
+
stackId: string;
|
|
6
|
+
operationId?: string;
|
|
7
|
+
knownIds?: string[];
|
|
8
|
+
auth: AuthParams;
|
|
9
|
+
showBanner?: boolean;
|
|
10
|
+
verbose?: boolean;
|
|
11
|
+
log: Logger;
|
|
12
|
+
onActivity?: () => void;
|
|
13
|
+
onLogEntry?: (log: BlueprintLog) => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Polls the logs list endpoint at a fixed interval and displays new entries.
|
|
17
|
+
* Deduplicates by log ID so no dependency on server timestamps.
|
|
18
|
+
* @returns A cleanup function that stops polling
|
|
19
|
+
*/
|
|
20
|
+
export declare function setupLogPolling(config: LogPollingConfig): () => void;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { formatLogEntry } from '../../utils/display/logs-formatting.js';
|
|
2
|
+
import { styleText } from '../../utils/style-text.js';
|
|
3
|
+
import { getLogs } from './logs.js';
|
|
4
|
+
export const LOG_POLL_INTERVAL_MS = 725;
|
|
5
|
+
/**
|
|
6
|
+
* Polls the logs list endpoint at a fixed interval and displays new entries.
|
|
7
|
+
* Deduplicates by log ID so no dependency on server timestamps.
|
|
8
|
+
* @returns A cleanup function that stops polling
|
|
9
|
+
*/
|
|
10
|
+
export function setupLogPolling(config) {
|
|
11
|
+
const { stackId, operationId, auth, log, showBanner, verbose = false } = config;
|
|
12
|
+
const seenIds = new Set(config.knownIds);
|
|
13
|
+
let previousLog;
|
|
14
|
+
let stopped = false;
|
|
15
|
+
if (showBanner) {
|
|
16
|
+
log(`Watching logs... ${styleText('bold', 'ctrl+c')} to cancel`);
|
|
17
|
+
}
|
|
18
|
+
const fetchAndProcessLogs = async () => {
|
|
19
|
+
if (stopped)
|
|
20
|
+
return;
|
|
21
|
+
try {
|
|
22
|
+
const params = operationId ? { operationId } : { stackId };
|
|
23
|
+
const { ok, logs } = await getLogs(params, auth, log);
|
|
24
|
+
if (!ok || stopped)
|
|
25
|
+
return;
|
|
26
|
+
// API returns newest first; reverse so we display in chronological order
|
|
27
|
+
const newLogs = logs.filter((entry) => !seenIds.has(entry.id)).reverse();
|
|
28
|
+
for (const logEntry of newLogs) {
|
|
29
|
+
seenIds.add(logEntry.id);
|
|
30
|
+
config.onActivity?.();
|
|
31
|
+
config.onLogEntry?.(logEntry);
|
|
32
|
+
log(formatLogEntry(logEntry, verbose, previousLog));
|
|
33
|
+
previousLog = logEntry;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Swallow fetch errors; the operation status poll in callers handles terminal failure.
|
|
38
|
+
// Logging noise here is not useful.
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
// Fire immediately, then on interval
|
|
42
|
+
fetchAndProcessLogs();
|
|
43
|
+
const intervalId = setInterval(fetchAndProcessLogs, LOG_POLL_INTERVAL_MS);
|
|
44
|
+
return () => {
|
|
45
|
+
stopped = true;
|
|
46
|
+
clearInterval(intervalId);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { Logger } from '../../utils/logger.js';
|
|
2
2
|
import type { ActionResponse, AuthParams, BlueprintLog } from '../../utils/types.js';
|
|
3
3
|
export declare const logsUrl: string;
|
|
4
|
-
export
|
|
4
|
+
export interface GetLogsParams {
|
|
5
|
+
stackId?: string;
|
|
6
|
+
operationId?: string;
|
|
7
|
+
limit?: number;
|
|
8
|
+
before?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function getLogs(params: GetLogsParams, auth: AuthParams, logger: Logger): Promise<ActionResponse & {
|
|
5
11
|
logs: BlueprintLog[];
|
|
6
12
|
}>;
|
|
7
13
|
export declare function getRecentLogs(logs: BlueprintLog[], limit?: number): BlueprintLog[];
|
|
@@ -3,10 +3,17 @@ import getHeaders from '../../utils/get-headers.js';
|
|
|
3
3
|
import { createTracedFetch } from '../../utils/traced-fetch.js';
|
|
4
4
|
const { apiUrl } = config;
|
|
5
5
|
export const logsUrl = `${apiUrl}vX/blueprints/logs`;
|
|
6
|
-
export async function getLogs(
|
|
6
|
+
export async function getLogs(params, auth, logger) {
|
|
7
7
|
const fetchFn = createTracedFetch(logger);
|
|
8
8
|
const url = new URL(logsUrl);
|
|
9
|
-
|
|
9
|
+
if (params.stackId)
|
|
10
|
+
url.searchParams.append('stackId', params.stackId);
|
|
11
|
+
if (params.operationId)
|
|
12
|
+
url.searchParams.append('operationId', params.operationId);
|
|
13
|
+
if (params.limit)
|
|
14
|
+
url.searchParams.append('limit', String(params.limit));
|
|
15
|
+
if (params.before)
|
|
16
|
+
url.searchParams.append('before', params.before);
|
|
10
17
|
const response = await fetchFn(url.toString(), {
|
|
11
18
|
headers: getHeaders(auth),
|
|
12
19
|
method: 'GET',
|
|
@@ -37,7 +37,9 @@ export declare function createEmptyStack({ token, scopeType, scopeId, name, logg
|
|
|
37
37
|
logger: Logger;
|
|
38
38
|
}): Promise<Stack>;
|
|
39
39
|
interface UpdateStackResponse extends ActionResponse {
|
|
40
|
-
stack: Stack
|
|
40
|
+
stack: Stack & {
|
|
41
|
+
operationId?: string;
|
|
42
|
+
};
|
|
41
43
|
}
|
|
42
44
|
export declare function updateStack({ stackId, stackMutation, auth, logger, }: {
|
|
43
45
|
stackId: string;
|
|
@@ -96,7 +98,9 @@ export declare function planStack({ stackId, document, auth, logger, }: {
|
|
|
96
98
|
logger: Logger;
|
|
97
99
|
}): Promise<PlanStackResponse>;
|
|
98
100
|
interface DestroyStackResponse extends ActionResponse {
|
|
99
|
-
stack: Stack
|
|
101
|
+
stack: Stack & {
|
|
102
|
+
operationId?: string;
|
|
103
|
+
};
|
|
100
104
|
}
|
|
101
105
|
export declare function resolveStackIdByNameOrId(value: string, auth: AuthParams, logger: Logger): Promise<string>;
|
|
102
106
|
interface PromoteStackResponse extends ActionResponse {
|
|
@@ -17,8 +17,9 @@ export interface Project {
|
|
|
17
17
|
interface ListProjectsResponse extends ActionResponse {
|
|
18
18
|
projects: Project[];
|
|
19
19
|
}
|
|
20
|
-
export declare function listProjects({ token, logger, }: {
|
|
20
|
+
export declare function listProjects({ token, organizationId, logger, }: {
|
|
21
21
|
token: string;
|
|
22
|
+
organizationId?: string;
|
|
22
23
|
logger: Logger;
|
|
23
24
|
}): Promise<ListProjectsResponse>;
|
|
24
25
|
interface GroupedProjectsByOrganizationResponse extends ActionResponse {
|
|
@@ -3,9 +3,12 @@ import { createTracedFetch } from '../../utils/traced-fetch.js';
|
|
|
3
3
|
const { populusApiUrl } = config;
|
|
4
4
|
export const projectsApiPath = `${populusApiUrl}v2021-06-07/projects`;
|
|
5
5
|
export const orgsApiPath = `${populusApiUrl}v2021-06-07/organizations`;
|
|
6
|
-
export async function listProjects({ token, logger, }) {
|
|
6
|
+
export async function listProjects({ token, organizationId, logger, }) {
|
|
7
7
|
const fetchFn = createTracedFetch(logger);
|
|
8
|
-
const
|
|
8
|
+
const url = organizationId
|
|
9
|
+
? `${projectsApiPath}?organizationId=${encodeURIComponent(organizationId)}`
|
|
10
|
+
: projectsApiPath;
|
|
11
|
+
const projectsFetch = await fetchFn(url, {
|
|
9
12
|
method: 'GET',
|
|
10
13
|
headers: {
|
|
11
14
|
Authorization: `Bearer ${token}`,
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file
|
|
3
3
|
* @deprecated Use `functions add` instead.
|
|
4
|
-
* We're in the process of deprecating the `blueprints add` command.
|
|
5
4
|
*/
|
|
6
5
|
import { ResolvedCommand } from '../../baseCommands.js';
|
|
7
6
|
export default class AddCommand extends ResolvedCommand<typeof AddCommand> {
|
|
8
7
|
static needs: readonly ["blueprint"];
|
|
8
|
+
static state: string;
|
|
9
|
+
static deprecationOptions: {
|
|
10
|
+
to: string;
|
|
11
|
+
};
|
|
9
12
|
static summary: string;
|
|
10
13
|
static description: string;
|
|
11
14
|
static examples: string[];
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file
|
|
3
3
|
* @deprecated Use `functions add` instead.
|
|
4
|
-
* We're in the process of deprecating the `blueprints add` command.
|
|
5
4
|
*/
|
|
6
5
|
import { Args, Flags } from '@oclif/core';
|
|
7
6
|
import { ResolvedCommand } from '../../baseCommands.js';
|
|
8
7
|
import { FUNCTION_TYPES } from '../../constants.js';
|
|
9
8
|
import { functionAddCore } from '../../cores/functions/index.js';
|
|
9
|
+
import { warn } from '../../utils/display/presenters.js';
|
|
10
10
|
import { Logger } from '../../utils/logger.js';
|
|
11
11
|
import { INSTALLER_OPTIONS } from '../../utils/types.js';
|
|
12
|
-
// import {warn} from '../../utils/display/presenters.js'
|
|
13
12
|
export default class AddCommand extends ResolvedCommand {
|
|
14
13
|
static needs = ['blueprint'];
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
static summary = '
|
|
20
|
-
static description = `
|
|
14
|
+
static state = 'deprecated';
|
|
15
|
+
static deprecationOptions = {
|
|
16
|
+
to: 'functions add',
|
|
17
|
+
};
|
|
18
|
+
static summary = '[deprecated] Use "functions add" instead';
|
|
19
|
+
static description = `This command is deprecated. Use "functions add" instead.
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
Equivalent usage:
|
|
22
|
+
$ <%= config.bin %> functions add
|
|
23
|
+
$ <%= config.bin %> functions add --name my-function --type document-create`;
|
|
23
24
|
static examples = [
|
|
24
25
|
'<%= config.bin %> <%= command.id %> function',
|
|
25
26
|
'<%= config.bin %> <%= command.id %> function --helpers',
|
|
@@ -84,11 +85,7 @@ After adding a function, use 'functions dev' to test locally, then 'blueprints d
|
|
|
84
85
|
if (resourceType !== 'function') {
|
|
85
86
|
this.error(`Unsupported Resource type: ${resourceType}`);
|
|
86
87
|
}
|
|
87
|
-
|
|
88
|
-
// warn(
|
|
89
|
-
// `\`npx ${bin} blueprints add function\` is deprecated. Use \`npx ${bin} functions add\` instead.`,
|
|
90
|
-
// ),
|
|
91
|
-
// )
|
|
88
|
+
this.log(warn(`"${bin} blueprints add" is deprecated and will be removed in a future release. Use "${bin} functions add" instead.`));
|
|
92
89
|
const result = await functionAddCore({
|
|
93
90
|
bin,
|
|
94
91
|
log: Logger(this.log.bind(this), this.flags),
|
|
@@ -7,6 +7,7 @@ export default class StacksCommand extends ResolvedCommand<typeof StacksCommand>
|
|
|
7
7
|
static flags: {
|
|
8
8
|
'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
9
|
'organization-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'include-projects': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
11
|
};
|
|
11
12
|
run(): Promise<Record<string, unknown> | undefined>;
|
|
12
13
|
}
|
|
@@ -7,15 +7,25 @@ export default class StacksCommand extends ResolvedCommand {
|
|
|
7
7
|
static summary = 'List remote Stack deployments for your project or organization';
|
|
8
8
|
static description = `Shows all Stacks associated with a project or organization. By default, lists Stacks scoped to the local Blueprint.
|
|
9
9
|
|
|
10
|
-
Use this to discover existing Stacks you can scope a local Blueprint to (using 'blueprints config --edit'), or to audit what's deployed across your project
|
|
10
|
+
Use this to discover existing Stacks you can scope a local Blueprint to (using 'blueprints config --edit'), or to audit what's deployed across your project.
|
|
11
|
+
|
|
12
|
+
Use --include-projects with --organization-id to also list Stacks from all projects within the organization.`;
|
|
11
13
|
static examples = [
|
|
12
14
|
'<%= config.bin %> <%= command.id %>',
|
|
13
15
|
'<%= config.bin %> <%= command.id %> --project-id <projectId>',
|
|
14
16
|
'<%= config.bin %> <%= command.id %> --organization-id <organizationId>',
|
|
17
|
+
'<%= config.bin %> <%= command.id %> --organization-id <organizationId> --include-projects',
|
|
15
18
|
];
|
|
16
19
|
static flags = {
|
|
17
|
-
'project-id': Flags.string({
|
|
20
|
+
'project-id': Flags.string({
|
|
21
|
+
...projectIdFlagConfig,
|
|
22
|
+
exclusive: ['organization-id', 'include-projects'],
|
|
23
|
+
}),
|
|
18
24
|
'organization-id': Flags.string({ ...organizationIdFlagConfig, exclusive: ['project-id'] }),
|
|
25
|
+
'include-projects': Flags.boolean({
|
|
26
|
+
description: 'Include Stacks from all projects within the organization. Requires --organization-id.',
|
|
27
|
+
dependsOn: ['organization-id'],
|
|
28
|
+
}),
|
|
19
29
|
};
|
|
20
30
|
async run() {
|
|
21
31
|
const result = await blueprintStacksCore({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
2
2
|
import { stashAsset } from '../../actions/blueprints/assets.js';
|
|
3
|
-
import {
|
|
3
|
+
import { setupLogPolling } from '../../actions/blueprints/logs-polling.js';
|
|
4
4
|
import { getStack, updateStack } from '../../actions/blueprints/stacks.js';
|
|
5
5
|
import { createLogHintCollector } from '../../utils/blueprints/log-hints.js';
|
|
6
6
|
import { niceId } from '../../utils/display/presenters.js';
|
|
@@ -47,7 +47,6 @@ export async function blueprintDeployCore(options) {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
const spinner = log.ora('Deploying...').start();
|
|
50
|
-
const isoNow = new Date().toISOString();
|
|
51
50
|
const { ok: deployOk, stack, error: deployError, } = await updateStack({
|
|
52
51
|
stackId,
|
|
53
52
|
stackMutation: {
|
|
@@ -87,9 +86,9 @@ export async function blueprintDeployCore(options) {
|
|
|
87
86
|
try {
|
|
88
87
|
let lastLogAt = Date.now();
|
|
89
88
|
let idleMessageShown = false;
|
|
90
|
-
logStreamCleanup =
|
|
89
|
+
logStreamCleanup = setupLogPolling({
|
|
91
90
|
stackId: stack.id,
|
|
92
|
-
|
|
91
|
+
operationId: stack.operationId,
|
|
93
92
|
auth,
|
|
94
93
|
log,
|
|
95
94
|
verbose,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
2
2
|
import { confirm } from '@inquirer/prompts';
|
|
3
|
-
import {
|
|
3
|
+
import { setupLogPolling } from '../../actions/blueprints/logs-polling.js';
|
|
4
4
|
import { destroyStack, getStack, resolveStackIdByNameOrId } from '../../actions/blueprints/stacks.js';
|
|
5
5
|
import { createLogHintCollector } from '../../utils/blueprints/log-hints.js';
|
|
6
6
|
import { niceId } from '../../utils/display/presenters.js';
|
|
@@ -25,7 +25,6 @@ export async function blueprintDestroyCore(options) {
|
|
|
25
25
|
}
|
|
26
26
|
const auth = { token, scopeType, scopeId };
|
|
27
27
|
const resolvedId = await resolveStackIdByNameOrId(flagStack, auth, log);
|
|
28
|
-
const isoNow = new Date().toISOString();
|
|
29
28
|
const { ok, error, stack } = await destroyStack({
|
|
30
29
|
stackId: resolvedId,
|
|
31
30
|
auth,
|
|
@@ -40,10 +39,10 @@ export async function blueprintDestroyCore(options) {
|
|
|
40
39
|
return waitForDestruction({
|
|
41
40
|
stackId: stack.id,
|
|
42
41
|
stackName: stack.name,
|
|
42
|
+
operationId: stack.operationId,
|
|
43
43
|
auth,
|
|
44
44
|
log,
|
|
45
45
|
bin,
|
|
46
|
-
since: isoNow,
|
|
47
46
|
});
|
|
48
47
|
}
|
|
49
48
|
const { scopeType, scopeId, stackId } = blueprint;
|
|
@@ -103,8 +102,11 @@ export async function blueprintDestroyCore(options) {
|
|
|
103
102
|
else {
|
|
104
103
|
destroySpinner.start();
|
|
105
104
|
}
|
|
106
|
-
const
|
|
107
|
-
|
|
105
|
+
const { ok, error, stack: destroyedStack, } = await destroyStack({
|
|
106
|
+
stackId: stack.id,
|
|
107
|
+
auth,
|
|
108
|
+
logger: log,
|
|
109
|
+
});
|
|
108
110
|
if (!ok) {
|
|
109
111
|
destroySpinner.fail('Failed to destroy Stack deployment');
|
|
110
112
|
return { success: false, error: error || 'Failed to destroy Stack deployment' };
|
|
@@ -117,10 +119,10 @@ export async function blueprintDestroyCore(options) {
|
|
|
117
119
|
return waitForDestruction({
|
|
118
120
|
stackId: stack.id,
|
|
119
121
|
stackName: stack.name,
|
|
122
|
+
operationId: destroyedStack.operationId,
|
|
120
123
|
auth,
|
|
121
124
|
log,
|
|
122
125
|
bin,
|
|
123
|
-
since: isoNow,
|
|
124
126
|
});
|
|
125
127
|
}
|
|
126
128
|
catch (error) {
|
|
@@ -129,16 +131,16 @@ export async function blueprintDestroyCore(options) {
|
|
|
129
131
|
}
|
|
130
132
|
}
|
|
131
133
|
async function waitForDestruction(options) {
|
|
132
|
-
const { stackId, stackName, auth, log, bin
|
|
134
|
+
const { stackId, stackName, operationId, auth, log, bin } = options;
|
|
133
135
|
log(styleText('dim', 'Stack destruction progress:'));
|
|
134
136
|
const logHints = createLogHintCollector(bin);
|
|
135
137
|
let logStreamCleanup = null;
|
|
136
138
|
try {
|
|
137
139
|
let lastLogAt = Date.now();
|
|
138
140
|
let idleMessageShown = false;
|
|
139
|
-
logStreamCleanup =
|
|
141
|
+
logStreamCleanup = setupLogPolling({
|
|
140
142
|
stackId,
|
|
141
|
-
|
|
143
|
+
operationId,
|
|
142
144
|
auth,
|
|
143
145
|
log,
|
|
144
146
|
onActivity: () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getLogs, getRecentLogs } from '../../actions/blueprints/logs.js';
|
|
2
|
-
import {
|
|
2
|
+
import { setupLogPolling } from '../../actions/blueprints/logs-polling.js';
|
|
3
3
|
import { formatTitle } from '../../utils/display/blueprints-formatting.js';
|
|
4
4
|
import { formatLogEntry, formatLogs } from '../../utils/display/logs-formatting.js';
|
|
5
5
|
import { niceId } from '../../utils/display/presenters.js';
|
|
@@ -10,7 +10,7 @@ export async function blueprintLogsCore(options) {
|
|
|
10
10
|
const spinner = log.ora(`Fetching recent logs for Stack deployment ${niceId(stackId)}`).start();
|
|
11
11
|
try {
|
|
12
12
|
if (watch) {
|
|
13
|
-
const { ok, logs, error } = await getLogs(stackId, auth, log);
|
|
13
|
+
const { ok, logs, error } = await getLogs({ stackId }, auth, log);
|
|
14
14
|
if (!ok) {
|
|
15
15
|
spinner.fail(`${styleText('red', 'Failed')} to retrieve logs`);
|
|
16
16
|
log.error(`Error: ${error || 'Unknown error'}`);
|
|
@@ -30,22 +30,23 @@ export async function blueprintLogsCore(options) {
|
|
|
30
30
|
else {
|
|
31
31
|
log(`No recent logs found for Stack deployment ${niceId(stackId)}`);
|
|
32
32
|
}
|
|
33
|
-
// Set up
|
|
34
|
-
|
|
33
|
+
// Set up polling log display, seeding with already-displayed log IDs
|
|
34
|
+
setupLogPolling({
|
|
35
35
|
stackId,
|
|
36
|
+
knownIds: logs.map((l) => l.id),
|
|
36
37
|
auth,
|
|
37
38
|
log,
|
|
38
39
|
showBanner: true,
|
|
39
40
|
verbose,
|
|
40
41
|
});
|
|
41
|
-
// Return a special key for
|
|
42
|
+
// Return a special key for polling mode
|
|
42
43
|
return {
|
|
43
44
|
success: true,
|
|
44
45
|
streaming: new Promise(() => { }),
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
// Regular non-streaming logs
|
|
48
|
-
const { ok, logs, error } = await getLogs(stackId, auth, log);
|
|
49
|
+
const { ok, logs, error } = await getLogs({ stackId }, auth, log);
|
|
49
50
|
if (!ok) {
|
|
50
51
|
spinner.fail(`${styleText('red', 'Failed')} to retrieve Stack deployment logs`);
|
|
51
52
|
log.error(`Error: ${error || 'Unknown error'}`);
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { listStacks } from '../../actions/blueprints/stacks.js';
|
|
2
|
+
import { listProjects } from '../../actions/sanity/projects.js';
|
|
2
3
|
import { formatStacksListing } from '../../utils/display/blueprints-formatting.js';
|
|
3
|
-
import { capitalize, niceId } from '../../utils/display/presenters.js';
|
|
4
|
+
import { capitalize, niceId, warn } from '../../utils/display/presenters.js';
|
|
4
5
|
import { styleText } from '../../utils/style-text.js';
|
|
6
|
+
/** Max projects to query for stacks during --include-projects */
|
|
7
|
+
const PROJECT_LIMIT = 50;
|
|
5
8
|
export async function blueprintStacksCore(options) {
|
|
6
9
|
const { log, token, blueprint, flags } = options;
|
|
7
10
|
const { scopeType: blueprintScopeType, scopeId: blueprintScopeId, stackId: blueprintStackId, } = blueprint;
|
|
8
|
-
const { 'project-id': flagProjectId, 'organization-id': flagOrganizationId, verbose: _verbose = false, } = flags;
|
|
11
|
+
const { 'project-id': flagProjectId, 'organization-id': flagOrganizationId, 'include-projects': includeProjects = false, verbose: _verbose = false, } = flags;
|
|
9
12
|
if (flagOrganizationId && flagProjectId) {
|
|
10
13
|
log.error('Cannot specify both --organization-id and --project-id');
|
|
11
14
|
return { success: false, error: 'Cannot specify both --organization-id and --project-id' };
|
|
@@ -27,6 +30,9 @@ export async function blueprintStacksCore(options) {
|
|
|
27
30
|
suggestions: ['Run in a Blueprint directory or provide a project with --project-id.'],
|
|
28
31
|
};
|
|
29
32
|
}
|
|
33
|
+
if (includeProjects && scopeType === 'organization') {
|
|
34
|
+
return deepListStacks({ organizationId: scopeId, token, log, blueprintStackId });
|
|
35
|
+
}
|
|
30
36
|
try {
|
|
31
37
|
const spinner = log.ora('Fetching Stacks...').start();
|
|
32
38
|
const { ok, stacks, error } = await listStacks({ token, scopeType, scopeId }, log);
|
|
@@ -57,3 +63,68 @@ export async function blueprintStacksCore(options) {
|
|
|
57
63
|
return { success: false, error: errorMessage };
|
|
58
64
|
}
|
|
59
65
|
}
|
|
66
|
+
async function deepListStacks(options) {
|
|
67
|
+
const { organizationId, token, log, blueprintStackId } = options;
|
|
68
|
+
const allStacks = [];
|
|
69
|
+
const spinner = log.ora('Fetching Stacks...').start();
|
|
70
|
+
try {
|
|
71
|
+
// 1. Org-scoped stacks
|
|
72
|
+
const orgResult = await listStacks({ token, scopeType: 'organization', scopeId: organizationId }, log);
|
|
73
|
+
const orgStacks = orgResult.ok ? orgResult.stacks : [];
|
|
74
|
+
// 2. Get projects in the organization
|
|
75
|
+
const projectsResult = await listProjects({ token, organizationId, logger: log });
|
|
76
|
+
if (!projectsResult.ok) {
|
|
77
|
+
spinner.fail('Failed to list projects');
|
|
78
|
+
return { success: false, error: projectsResult.error || 'Failed to list projects' };
|
|
79
|
+
}
|
|
80
|
+
const projects = projectsResult.projects;
|
|
81
|
+
const totalProjects = projects.length;
|
|
82
|
+
const cappedProjects = projects.slice(0, PROJECT_LIMIT);
|
|
83
|
+
// 3. Fetch stacks for each project
|
|
84
|
+
const projectGroups = [];
|
|
85
|
+
for (let i = 0; i < cappedProjects.length; i++) {
|
|
86
|
+
const project = cappedProjects[i];
|
|
87
|
+
spinner.text = `Fetching Stacks... (project ${i + 1}/${cappedProjects.length})`;
|
|
88
|
+
const result = await listStacks({ token, scopeType: 'project', scopeId: project.id }, log);
|
|
89
|
+
if (result.ok && result.stacks.length > 0) {
|
|
90
|
+
projectGroups.push({
|
|
91
|
+
projectId: project.id,
|
|
92
|
+
displayName: project.displayName,
|
|
93
|
+
stacks: result.stacks,
|
|
94
|
+
});
|
|
95
|
+
allStacks.push(...result.stacks);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
spinner.stop().clear();
|
|
99
|
+
// 4. Print results
|
|
100
|
+
if (orgStacks.length > 0) {
|
|
101
|
+
log(`${styleText('bold', 'Organization')} ${niceId(organizationId)} ${styleText('bold', 'Stacks')}:\n`);
|
|
102
|
+
log(formatStacksListing(orgStacks, blueprintStackId));
|
|
103
|
+
if (projectGroups.length > 0)
|
|
104
|
+
log(''); // blank line between sections
|
|
105
|
+
}
|
|
106
|
+
for (const group of projectGroups) {
|
|
107
|
+
log(`${styleText('bold', 'Project')} "${group.displayName}" ${niceId(group.projectId)} ${styleText('bold', 'Stacks')}:`);
|
|
108
|
+
log(formatStacksListing(group.stacks, blueprintStackId));
|
|
109
|
+
log('');
|
|
110
|
+
}
|
|
111
|
+
if (totalProjects > PROJECT_LIMIT) {
|
|
112
|
+
log(warn(`Organization has ${totalProjects} projects, only checked the first ${PROJECT_LIMIT}.`));
|
|
113
|
+
}
|
|
114
|
+
if (orgStacks.length === 0 && allStacks.length === 0) {
|
|
115
|
+
log('No stacks found');
|
|
116
|
+
return { success: true };
|
|
117
|
+
}
|
|
118
|
+
allStacks.push(...orgStacks);
|
|
119
|
+
return {
|
|
120
|
+
success: true,
|
|
121
|
+
json: { stacks: allStacks, scopeType: 'organization', scopeId: organizationId },
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
spinner.stop().clear();
|
|
126
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
127
|
+
log.error(`Error: ${errorMessage}`);
|
|
128
|
+
return { success: false, error: errorMessage };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -28,11 +28,13 @@ function arrayifyEvent(event) {
|
|
|
28
28
|
if ('projection' in event && event.projection) {
|
|
29
29
|
details.push(formatLabeledValue('projection', event.projection));
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
if (event.resource) {
|
|
32
|
+
details.push(formatLabel('resource'));
|
|
33
|
+
details.push([
|
|
34
|
+
formatLabeledValue('type', event.resource.type),
|
|
35
|
+
formatLabeledValue('id', event.resource.id),
|
|
36
|
+
]);
|
|
37
|
+
}
|
|
36
38
|
}
|
|
37
39
|
return details;
|
|
38
40
|
}
|
package/oclif.manifest.json
CHANGED
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
"required": true
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
-
"
|
|
15
|
+
"deprecationOptions": {
|
|
16
|
+
"to": "functions add"
|
|
17
|
+
},
|
|
18
|
+
"description": "This command is deprecated. Use \"functions add\" instead.\n\nEquivalent usage:\n $ <%= config.bin %> functions add\n $ <%= config.bin %> functions add --name my-function --type document-create",
|
|
16
19
|
"examples": [
|
|
17
20
|
"<%= config.bin %> <%= command.id %> function",
|
|
18
21
|
"<%= config.bin %> <%= command.id %> function --helpers",
|
|
@@ -216,8 +219,9 @@
|
|
|
216
219
|
"pluginAlias": "@sanity/runtime-cli",
|
|
217
220
|
"pluginName": "@sanity/runtime-cli",
|
|
218
221
|
"pluginType": "core",
|
|
222
|
+
"state": "deprecated",
|
|
219
223
|
"strict": true,
|
|
220
|
-
"summary": "
|
|
224
|
+
"summary": "[deprecated] Use \"functions add\" instead",
|
|
221
225
|
"enableJsonFlag": true,
|
|
222
226
|
"needs": [
|
|
223
227
|
"blueprint"
|
|
@@ -1289,11 +1293,12 @@
|
|
|
1289
1293
|
"blueprints:stacks": {
|
|
1290
1294
|
"aliases": [],
|
|
1291
1295
|
"args": {},
|
|
1292
|
-
"description": "Shows all Stacks associated with a project or organization. By default, lists Stacks scoped to the local Blueprint.\n\nUse this to discover existing Stacks you can scope a local Blueprint to (using 'blueprints config --edit'), or to audit what's deployed across your project.",
|
|
1296
|
+
"description": "Shows all Stacks associated with a project or organization. By default, lists Stacks scoped to the local Blueprint.\n\nUse this to discover existing Stacks you can scope a local Blueprint to (using 'blueprints config --edit'), or to audit what's deployed across your project.\n\nUse --include-projects with --organization-id to also list Stacks from all projects within the organization.",
|
|
1293
1297
|
"examples": [
|
|
1294
1298
|
"<%= config.bin %> <%= command.id %>",
|
|
1295
1299
|
"<%= config.bin %> <%= command.id %> --project-id <projectId>",
|
|
1296
|
-
"<%= config.bin %> <%= command.id %> --organization-id <organizationId>"
|
|
1300
|
+
"<%= config.bin %> <%= command.id %> --organization-id <organizationId>",
|
|
1301
|
+
"<%= config.bin %> <%= command.id %> --organization-id <organizationId> --include-projects"
|
|
1297
1302
|
],
|
|
1298
1303
|
"flags": {
|
|
1299
1304
|
"json": {
|
|
@@ -1350,7 +1355,8 @@
|
|
|
1350
1355
|
],
|
|
1351
1356
|
"description": "Sanity project ID used to scope Blueprint and Stack",
|
|
1352
1357
|
"exclusive": [
|
|
1353
|
-
"organization-id"
|
|
1358
|
+
"organization-id",
|
|
1359
|
+
"include-projects"
|
|
1354
1360
|
],
|
|
1355
1361
|
"name": "project-id",
|
|
1356
1362
|
"hasDynamicHelp": false,
|
|
@@ -1371,6 +1377,15 @@
|
|
|
1371
1377
|
"hasDynamicHelp": false,
|
|
1372
1378
|
"multiple": false,
|
|
1373
1379
|
"type": "option"
|
|
1380
|
+
},
|
|
1381
|
+
"include-projects": {
|
|
1382
|
+
"dependsOn": [
|
|
1383
|
+
"organization-id"
|
|
1384
|
+
],
|
|
1385
|
+
"description": "Include Stacks from all projects within the organization. Requires --organization-id.",
|
|
1386
|
+
"name": "include-projects",
|
|
1387
|
+
"allowNo": false,
|
|
1388
|
+
"type": "boolean"
|
|
1374
1389
|
}
|
|
1375
1390
|
},
|
|
1376
1391
|
"hasDynamicHelp": false,
|
|
@@ -2677,5 +2692,5 @@
|
|
|
2677
2692
|
]
|
|
2678
2693
|
}
|
|
2679
2694
|
},
|
|
2680
|
-
"version": "14.
|
|
2695
|
+
"version": "14.13.1"
|
|
2681
2696
|
}
|
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": "14.
|
|
4
|
+
"version": "14.13.1",
|
|
5
5
|
"author": "Sanity Runtime Team",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
"test:api": "cd test/api-types && npm it",
|
|
95
95
|
"test:depmgmt": "vitest run --config ./test-depmgmt/vitest.config.ts",
|
|
96
96
|
"test:vitest": "vitest run",
|
|
97
|
+
"test:coverage": "npm run test:vitest -- --coverage --coverage.include \"runtime-cli/src/**/*\"",
|
|
97
98
|
"typecheck": "tsc --project tsconfig.typecheck.json",
|
|
98
99
|
"watch": "tsc --watch"
|
|
99
100
|
},
|
|
@@ -137,6 +138,7 @@
|
|
|
137
138
|
"@types/node": "20",
|
|
138
139
|
"@types/tar-stream": "^3.1.4",
|
|
139
140
|
"@types/ws": "^8.18.1",
|
|
141
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
140
142
|
"codemirror": "^6.0.2",
|
|
141
143
|
"mentoss": "^0.13.0",
|
|
142
144
|
"oclif": "^4.22.92",
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { Logger } from '../../utils/logger.js';
|
|
2
|
-
import type { AuthParams, BlueprintLog } from '../../utils/types.js';
|
|
3
|
-
export interface LogStreamingConfig {
|
|
4
|
-
stackId: string;
|
|
5
|
-
after?: string;
|
|
6
|
-
auth: AuthParams;
|
|
7
|
-
showBanner?: boolean;
|
|
8
|
-
verbose?: boolean;
|
|
9
|
-
log: Logger;
|
|
10
|
-
onActivity?: () => void;
|
|
11
|
-
onLogEntry?: (log: BlueprintLog) => void;
|
|
12
|
-
}
|
|
13
|
-
export interface StreamLogsOptions {
|
|
14
|
-
stackId: string;
|
|
15
|
-
after?: string;
|
|
16
|
-
auth: AuthParams;
|
|
17
|
-
onLog: (log: BlueprintLog) => void;
|
|
18
|
-
onOpen: () => void;
|
|
19
|
-
onError: (error: string) => void;
|
|
20
|
-
logger: Logger;
|
|
21
|
-
}
|
|
22
|
-
export declare function streamLogs({ stackId, after, auth, onLog, onOpen, onError, logger, }: StreamLogsOptions): () => void;
|
|
23
|
-
/** Check if a log is newer than a given timestamp */
|
|
24
|
-
export declare function isNewerLog(log: BlueprintLog, timestamp: number): boolean;
|
|
25
|
-
/**
|
|
26
|
-
* Sets up log streaming for operations like deploy or destroy with spinner integration
|
|
27
|
-
* @param config Configuration for log streaming
|
|
28
|
-
* @returns A cleanup function for closing the log stream
|
|
29
|
-
*/
|
|
30
|
-
export declare function setupLogStreaming(config: LogStreamingConfig): Promise<() => void>;
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { EventSource } from 'eventsource';
|
|
2
|
-
import { formatLogEntry } from '../../utils/display/logs-formatting.js';
|
|
3
|
-
import getHeaders from '../../utils/get-headers.js';
|
|
4
|
-
import { styleText } from '../../utils/style-text.js';
|
|
5
|
-
import { createTracedFetch } from '../../utils/traced-fetch.js';
|
|
6
|
-
import { logsUrl } from './logs.js';
|
|
7
|
-
export function streamLogs({ stackId, after, auth, onLog, onOpen, onError, logger, }) {
|
|
8
|
-
const fetchFn = createTracedFetch(logger);
|
|
9
|
-
const url = new URL(`${logsUrl}/stream`);
|
|
10
|
-
url.searchParams.append('stackId', stackId);
|
|
11
|
-
if (after)
|
|
12
|
-
url.searchParams.append('after', after);
|
|
13
|
-
const headers = getHeaders(auth);
|
|
14
|
-
const eventSource = new EventSource(url.toString(), {
|
|
15
|
-
fetch: (input, init) => fetchFn(input, {
|
|
16
|
-
...init,
|
|
17
|
-
headers: {
|
|
18
|
-
...init?.headers,
|
|
19
|
-
...headers,
|
|
20
|
-
},
|
|
21
|
-
}),
|
|
22
|
-
});
|
|
23
|
-
eventSource.onopen = onOpen;
|
|
24
|
-
eventSource.onmessage = (event) => {
|
|
25
|
-
try {
|
|
26
|
-
const log = JSON.parse(event.data);
|
|
27
|
-
onLog(log);
|
|
28
|
-
}
|
|
29
|
-
catch (err) {
|
|
30
|
-
onError(`Failed to parse log data: ${err instanceof Error ? err.message : String(err)}`);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
eventSource.addEventListener('logs', (event) => {
|
|
34
|
-
try {
|
|
35
|
-
const logData = JSON.parse(event.data);
|
|
36
|
-
// usually an array
|
|
37
|
-
if (Array.isArray(logData)) {
|
|
38
|
-
for (const log of logData)
|
|
39
|
-
onLog(log);
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
onLog(logData);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
catch (err) {
|
|
46
|
-
console.error('Error parsing logs event:', err);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
eventSource.onerror = () => {
|
|
50
|
-
onError('Connection to log stream failed or was closed');
|
|
51
|
-
if (eventSource.readyState === eventSource.CLOSED) {
|
|
52
|
-
console.log('Connection is CLOSED');
|
|
53
|
-
}
|
|
54
|
-
else if (eventSource.readyState === eventSource.CONNECTING) {
|
|
55
|
-
console.log('Connection is attempting to reconnect...');
|
|
56
|
-
return; // Don't close if trying to reconnect
|
|
57
|
-
}
|
|
58
|
-
eventSource.close();
|
|
59
|
-
};
|
|
60
|
-
return () => {
|
|
61
|
-
eventSource.close();
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
/** Check if a log is newer than a given timestamp */
|
|
65
|
-
export function isNewerLog(log, timestamp) {
|
|
66
|
-
const logTimestamp = new Date(log.timestamp).getTime();
|
|
67
|
-
return logTimestamp > timestamp;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Sets up log streaming for operations like deploy or destroy with spinner integration
|
|
71
|
-
* @param config Configuration for log streaming
|
|
72
|
-
* @returns A cleanup function for closing the log stream
|
|
73
|
-
*/
|
|
74
|
-
export async function setupLogStreaming(config) {
|
|
75
|
-
const { stackId, auth, log, showBanner, verbose = false, after } = config;
|
|
76
|
-
let newestTimestamp = Date.now();
|
|
77
|
-
let previousLog;
|
|
78
|
-
const onLogReceived = (logEntry) => {
|
|
79
|
-
if (!isNewerLog(logEntry, newestTimestamp))
|
|
80
|
-
return;
|
|
81
|
-
newestTimestamp = new Date(logEntry.timestamp).getTime();
|
|
82
|
-
config.onActivity?.();
|
|
83
|
-
config.onLogEntry?.(logEntry);
|
|
84
|
-
log(formatLogEntry(logEntry, verbose, previousLog));
|
|
85
|
-
previousLog = logEntry;
|
|
86
|
-
};
|
|
87
|
-
let alreadyOpened = false;
|
|
88
|
-
const onStreamOpen = () => {
|
|
89
|
-
if (!alreadyOpened && showBanner)
|
|
90
|
-
log(`Streaming logs... ${styleText('bold', 'ctrl+c')} to cancel`);
|
|
91
|
-
if (alreadyOpened)
|
|
92
|
-
log(`${styleText('green', 'Reconnected')}`);
|
|
93
|
-
alreadyOpened = true;
|
|
94
|
-
};
|
|
95
|
-
const onStreamError = (error) => {
|
|
96
|
-
log(`${styleText('red', 'Stream error:')} ${error}`);
|
|
97
|
-
};
|
|
98
|
-
return streamLogs({
|
|
99
|
-
stackId,
|
|
100
|
-
after,
|
|
101
|
-
auth,
|
|
102
|
-
onLog: onLogReceived,
|
|
103
|
-
onOpen: onStreamOpen,
|
|
104
|
-
onError: onStreamError,
|
|
105
|
-
logger: log,
|
|
106
|
-
});
|
|
107
|
-
}
|