@sanity/runtime-cli 17.3.0 → 17.3.2-next.ga266544

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 CHANGED
@@ -3,30 +3,17 @@
3
3
 
4
4
  Sanity's Runtime CLI for Blueprints and Functions
5
5
 
6
+ Typically, the `@sanity/runtime-cli` (`sanity-run`) CLI is not used directly by end-users. The main `@sanity/cli` (`sanity`) loads and uses this CLI internally.
7
+ All `sanity-run` commands can also be run as `sanity <command>` when `@sanity/cli` is available.
6
8
 
7
9
  [![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io)
8
10
  [![Version](https://img.shields.io/npm/v/@sanity/runtime-cli.svg)](https://npmjs.org/package/@sanity/runtime-cli)
9
11
  [![Downloads/week](https://img.shields.io/npm/dw/@sanity/runtime-cli.svg)](https://npmjs.org/package/@sanity/runtime-cli)
10
12
 
11
-
12
13
  <!-- toc -->
13
- * [Usage](#usage)
14
14
  * [Commands](#commands)
15
15
  <!-- tocstop -->
16
- # Usage
17
- <!-- usage -->
18
- ```sh-session
19
- $ npm install -g @sanity/runtime-cli
20
- $ sanity-run COMMAND
21
- running command...
22
- $ sanity-run (--version)
23
- @sanity/runtime-cli/17.3.0 linux-x64 node-v24.18.0
24
- $ sanity-run --help [COMMAND]
25
- USAGE
26
- $ sanity-run COMMAND
27
- ...
28
- ```
29
- <!-- usagestop -->
16
+
30
17
  # Commands
31
18
  <!-- commands -->
32
19
  * [`sanity-run blueprints add TYPE`](#sanity-run-blueprints-add-type)
@@ -103,7 +90,7 @@ EXAMPLES
103
90
  $ sanity-run blueprints add function --name my-function --fn-type document-create --fn-type document-update --lang js
104
91
  ```
105
92
 
106
- _See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/blueprints/add.ts)_
93
+ _See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/blueprints/add.ts)_
107
94
 
108
95
  ## `sanity-run blueprints config`
109
96
 
@@ -140,7 +127,7 @@ EXAMPLES
140
127
  $ sanity-run blueprints config --edit --project-id <projectId> --stack <name-or-id>
141
128
  ```
142
129
 
143
- _See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/blueprints/config.ts)_
130
+ _See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/blueprints/config.ts)_
144
131
 
145
132
  ## `sanity-run blueprints deploy`
146
133
 
@@ -194,7 +181,7 @@ EXAMPLES
194
181
  $ sanity-run blueprints deploy --new-stack-name <new-name>
195
182
  ```
196
183
 
197
- _See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/blueprints/deploy.ts)_
184
+ _See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/blueprints/deploy.ts)_
198
185
 
199
186
  ## `sanity-run blueprints destroy`
200
187
 
@@ -232,7 +219,7 @@ EXAMPLES
232
219
  $ sanity-run blueprints destroy --stack <name-or-id> --project-id <projectId> --force --no-wait
233
220
  ```
234
221
 
235
- _See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/blueprints/destroy.ts)_
222
+ _See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/blueprints/destroy.ts)_
236
223
 
237
224
  ## `sanity-run blueprints doctor`
238
225
 
@@ -264,7 +251,7 @@ EXAMPLES
264
251
  $ sanity-run blueprints doctor --fix
265
252
  ```
266
253
 
267
- _See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/blueprints/doctor.ts)_
254
+ _See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/blueprints/doctor.ts)_
268
255
 
269
256
  ## `sanity-run blueprints info`
270
257
 
@@ -301,7 +288,7 @@ EXAMPLES
301
288
  $ sanity-run blueprints info --organization-id <orgId> --stack <name-or-id>
302
289
  ```
303
290
 
304
- _See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/blueprints/info.ts)_
291
+ _See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/blueprints/info.ts)_
305
292
 
306
293
  ## `sanity-run blueprints init [DIR]`
307
294
 
@@ -365,7 +352,7 @@ EXAMPLES
365
352
  $ sanity-run blueprints init old-stack --type <json|js|ts> --project-id <projectId> --stack-id <existingStackId>
366
353
  ```
367
354
 
368
- _See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/blueprints/init.ts)_
355
+ _See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/blueprints/init.ts)_
369
356
 
370
357
  ## `sanity-run blueprints logs`
371
358
 
@@ -411,7 +398,7 @@ EXAMPLES
411
398
  $ sanity-run blueprints logs --before 2026-05-01T00:00:00Z
412
399
  ```
413
400
 
414
- _See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/blueprints/logs.ts)_
401
+ _See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/blueprints/logs.ts)_
415
402
 
416
403
  ## `sanity-run blueprints mint-deploy-token`
417
404
 
@@ -456,7 +443,7 @@ EXAMPLES
456
443
  $ sanity-run blueprints mint-deploy-token --organization-id <orgId>
457
444
  ```
458
445
 
459
- _See code: [src/commands/blueprints/mint-deploy-token.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/blueprints/mint-deploy-token.ts)_
446
+ _See code: [src/commands/blueprints/mint-deploy-token.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/blueprints/mint-deploy-token.ts)_
460
447
 
461
448
  ## `sanity-run blueprints plan`
462
449
 
@@ -489,7 +476,7 @@ EXAMPLES
489
476
  $ sanity-run blueprints plan --organization-id <orgId> --stack <name-or-id>
490
477
  ```
491
478
 
492
- _See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/blueprints/plan.ts)_
479
+ _See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/blueprints/plan.ts)_
493
480
 
494
481
  ## `sanity-run blueprints promote`
495
482
 
@@ -525,7 +512,7 @@ EXAMPLES
525
512
  $ sanity-run blueprints promote --new-stack-name <new-name>
526
513
  ```
527
514
 
528
- _See code: [src/commands/blueprints/promote.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/blueprints/promote.ts)_
515
+ _See code: [src/commands/blueprints/promote.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/blueprints/promote.ts)_
529
516
 
530
517
  ## `sanity-run blueprints stacks`
531
518
 
@@ -561,7 +548,7 @@ EXAMPLES
561
548
  $ sanity-run blueprints stacks --organization-id <organizationId> --include-projects
562
549
  ```
563
550
 
564
- _See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/blueprints/stacks.ts)_
551
+ _See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/blueprints/stacks.ts)_
565
552
 
566
553
  ## `sanity-run functions add`
567
554
 
@@ -613,7 +600,7 @@ EXAMPLES
613
600
  $ sanity-run functions add --name my-function --type document-create --type document-update --lang js
614
601
  ```
615
602
 
616
- _See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/functions/add.ts)_
603
+ _See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/functions/add.ts)_
617
604
 
618
605
  ## `sanity-run functions dev`
619
606
 
@@ -648,7 +635,7 @@ EXAMPLES
648
635
  $ sanity-run functions dev --timeout 60
649
636
  ```
650
637
 
651
- _See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/functions/dev.ts)_
638
+ _See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/functions/dev.ts)_
652
639
 
653
640
  ## `sanity-run functions env add NAME KEY VALUE`
654
641
 
@@ -681,7 +668,7 @@ EXAMPLES
681
668
  $ sanity-run functions env add --stack <name-or-id> MyFunction API_URL https://api.example.com/
682
669
  ```
683
670
 
684
- _See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/functions/env/add.ts)_
671
+ _See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/functions/env/add.ts)_
685
672
 
686
673
  ## `sanity-run functions env list NAME`
687
674
 
@@ -711,7 +698,7 @@ EXAMPLES
711
698
  $ sanity-run functions env list --stack <name-or-id> MyFunction
712
699
  ```
713
700
 
714
- _See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/functions/env/list.ts)_
701
+ _See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/functions/env/list.ts)_
715
702
 
716
703
  ## `sanity-run functions env remove NAME KEY`
717
704
 
@@ -743,7 +730,7 @@ EXAMPLES
743
730
  $ sanity-run functions env remove --stack <name-or-id> MyFunction API_URL
744
731
  ```
745
732
 
746
- _See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/functions/env/remove.ts)_
733
+ _See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/functions/env/remove.ts)_
747
734
 
748
735
  ## `sanity-run functions logs [NAME]`
749
736
 
@@ -783,7 +770,7 @@ EXAMPLES
783
770
  $ sanity-run functions logs <name> --delete
784
771
  ```
785
772
 
786
- _See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/functions/logs.ts)_
773
+ _See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/functions/logs.ts)_
787
774
 
788
775
  ## `sanity-run functions test [NAME]`
789
776
 
@@ -840,7 +827,7 @@ EXAMPLES
840
827
  $ sanity-run functions test <name> --event update --data-before '{ "title": "before" }' --data-after '{ "title": "after" }'
841
828
  ```
842
829
 
843
- _See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0/src/commands/functions/test.ts)_
830
+ _See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.2-next.ga266544/src/commands/functions/test.ts)_
844
831
 
845
832
  ## `sanity-run help [COMMAND]`
846
833
 
@@ -860,5 +847,5 @@ DESCRIPTION
860
847
  Display help for sanity-run.
861
848
  ```
862
849
 
863
- _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/6.2.53/src/commands/help.ts)_
850
+ _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/6.2.55/src/commands/help.ts)_
864
851
  <!-- commandsstop -->
@@ -0,0 +1,34 @@
1
+ import type { Logger } from '../../utils/logger.js';
2
+ import type { AuthParams } from '../../utils/types.js';
3
+ /** A deployed function returned by the Functions API. */
4
+ export interface DeployedFunction {
5
+ id: string;
6
+ name: string | null;
7
+ displayName: string | null;
8
+ type: string | null;
9
+ runtime: string | null;
10
+ status: string | null;
11
+ memory: number | null;
12
+ storage: number | null;
13
+ timeout: number | null;
14
+ resourceType: string | null;
15
+ resourceId: string | null;
16
+ robotId: string | null;
17
+ url: string | null;
18
+ eventRule?: unknown;
19
+ contentSub?: Record<string, unknown> | null;
20
+ createdAt: string | null;
21
+ updatedAt: string | null;
22
+ deletedAt?: string | null;
23
+ }
24
+ type ListFunctionsResponse = {
25
+ ok: true;
26
+ error: null;
27
+ functions: DeployedFunction[];
28
+ } | {
29
+ ok: false;
30
+ error: string;
31
+ functions: [];
32
+ };
33
+ export declare function listFunctions(auth: AuthParams, logger: Logger): Promise<ListFunctionsResponse>;
34
+ export {};
@@ -0,0 +1,33 @@
1
+ import config from '../../config.js';
2
+ import getHeaders from '../../utils/get-headers.js';
3
+ import { createTracedFetch } from '../../utils/traced-fetch.js';
4
+ const { apiUrl } = config;
5
+ export async function listFunctions(auth, logger) {
6
+ try {
7
+ const fetchFn = createTracedFetch(logger);
8
+ const response = await fetchFn(`${apiUrl}v2025-07-30/functions/`, {
9
+ headers: getHeaders(auth),
10
+ method: 'GET',
11
+ });
12
+ const payload = (await response.json());
13
+ if (!response.ok) {
14
+ return {
15
+ ok: false,
16
+ error: payload.error?.message ?? payload.message ?? 'Failed to list functions',
17
+ functions: [],
18
+ };
19
+ }
20
+ return {
21
+ ok: true,
22
+ error: null,
23
+ functions: Array.isArray(payload.functions) ? payload.functions : [],
24
+ };
25
+ }
26
+ catch (error) {
27
+ return {
28
+ ok: false,
29
+ error: error instanceof Error ? error.message : String(error),
30
+ functions: [],
31
+ };
32
+ }
33
+ }
@@ -138,5 +138,7 @@ export declare abstract class ResolvedCommand<T extends typeof Command> extends
138
138
  protected blueprintConfig?: LocatedBlueprintsConfig | null;
139
139
  protected auth: AuthParams;
140
140
  protected deployedStack: Stack;
141
+ /** Runs after flag parsing and before declared command context is resolved. */
142
+ protected preResolve(): Promise<void>;
141
143
  init(): Promise<void>;
142
144
  }
@@ -220,8 +220,11 @@ export class ResolvedCommand extends RuntimeCommand {
220
220
  blueprintConfig;
221
221
  auth;
222
222
  deployedStack;
223
+ /** Runs after flag parsing and before declared command context is resolved. */
224
+ async preResolve() { }
223
225
  async init() {
224
226
  await super.init(); // RuntimeCommand: parse flags + args
227
+ await this.preResolve();
225
228
  const needs = new Set(this.constructor.needs);
226
229
  if (needs.size === 0)
227
230
  return;
@@ -11,7 +11,9 @@ export default class DeployCommand extends ResolvedCommand<typeof DeployCommand>
11
11
  message: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
12
  'fn-installer': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
13
  'no-wait': import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ configure: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
15
  'new-stack-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
16
  };
17
+ protected preResolve(): Promise<void>;
16
18
  run(): Promise<Record<string, unknown> | undefined>;
17
19
  }
@@ -21,6 +21,7 @@ Exit codes: 0 deployed, 2 deployment failed, 75 deployment accepted but completi
21
21
  '<%= config.bin %> <%= command.id %>',
22
22
  '<%= config.bin %> <%= command.id %> --message "Enable staging dataset"',
23
23
  '<%= config.bin %> <%= command.id %> --no-wait',
24
+ // '<%= config.bin %> <%= command.id %> --configure',
24
25
  '<%= config.bin %> <%= command.id %> --fn-installer npm',
25
26
  '<%= config.bin %> <%= command.id %> --stack <name-or-id>',
26
27
  '<%= config.bin %> <%= command.id %> --organization-id <orgId> --stack <name-or-id>',
@@ -44,10 +45,28 @@ Exit codes: 0 deployed, 2 deployment failed, 75 deployment accepted but completi
44
45
  description: 'Do not wait for Stack deployment to complete',
45
46
  default: false,
46
47
  }),
48
+ configure: Flags.boolean({
49
+ description: 'Configure the local Blueprint interactively before deploying',
50
+ aliases: ['config', 'init'],
51
+ default: false,
52
+ hidden: true,
53
+ }),
47
54
  'new-stack-name': Flags.string({
48
55
  description: 'Set a new name for the Stack',
49
56
  }),
50
57
  };
58
+ async preResolve() {
59
+ if (!this.flags.configure)
60
+ return;
61
+ const args = ['--edit'];
62
+ if (this.flags.path)
63
+ args.push('--path', this.flags.path);
64
+ if (!this.flags['validate-resources'])
65
+ args.push('--no-validate-resources');
66
+ if (this.flags.verbose)
67
+ args.push('--verbose');
68
+ await this.config.runCommand('blueprints:config', args);
69
+ }
51
70
  async run() {
52
71
  const result = await blueprintDeployCore({
53
72
  bin: this.config.bin,
@@ -0,0 +1,14 @@
1
+ import { ResolvedCommand } from '../../baseCommands.js';
2
+ export default class FunctionsListCommand extends ResolvedCommand<typeof FunctionsListCommand> {
3
+ static needs: readonly ['scope'];
4
+ static hidden: boolean;
5
+ static summary: string;
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ 'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ 'organization-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ };
13
+ run(): Promise<Record<string, unknown> | undefined>;
14
+ }
@@ -0,0 +1,38 @@
1
+ import { Flags } from '@oclif/core';
2
+ import { organizationIdFlagConfig, projectIdFlagConfig, ResolvedCommand } from '../../baseCommands.js';
3
+ import { functionListCore } from '../../cores/functions/list.js';
4
+ import { Logger } from '../../utils/logger.js';
5
+ export default class FunctionsListCommand extends ResolvedCommand {
6
+ static needs = ['scope'];
7
+ static hidden = true;
8
+ static summary = 'List deployed Sanity Functions';
9
+ static description = `Lists functions deployed directly in the selected project or organization scope. The local Blueprint config supplies the scope by default.
10
+
11
+ Use --project-id or --organization-id to select a scope without a local Blueprint. Organization results include organization-scoped functions only.`;
12
+ static examples = [
13
+ '<%= config.bin %> <%= command.id %>',
14
+ '<%= config.bin %> <%= command.id %> --verbose',
15
+ '<%= config.bin %> <%= command.id %> --project-id <projectId>',
16
+ '<%= config.bin %> <%= command.id %> --organization-id <organizationId>',
17
+ '<%= config.bin %> <%= command.id %> --project-id <projectId> --json',
18
+ ];
19
+ static flags = {
20
+ 'project-id': Flags.string({ ...projectIdFlagConfig }),
21
+ 'organization-id': Flags.string({ ...organizationIdFlagConfig }),
22
+ verbose: Flags.boolean({
23
+ char: 'v',
24
+ description: 'Show function configuration details',
25
+ default: false,
26
+ }),
27
+ };
28
+ async run() {
29
+ const result = await functionListCore({
30
+ log: Logger(this.log.bind(this), this.flags),
31
+ auth: this.auth,
32
+ flags: this.flags,
33
+ });
34
+ if (!result.success)
35
+ this.coreError(result);
36
+ return result.json;
37
+ }
38
+ }
package/dist/config.js CHANGED
@@ -30,7 +30,6 @@ const isTest = nodeEnv === 'test';
30
30
  const sanityEnv = env.SANITY_INTERNAL_ENV?.toLowerCase() ?? 'production';
31
31
  const sanityProd = sanityEnv === 'production';
32
32
  const isLive = sanityProd || sanityEnv === 'staging';
33
- const isPublishing = isTrueish(env?.PUBLISHING);
34
33
  // https://github.com/sanity-io/cli/blob/adf90ea6691ee6c36849e426de9729533706f47f/packages/%40sanity/cli-core/src/util/isCi.ts
35
34
  const isCi =
36
35
  // Travis CI, CircleCI, Gitlab CI, Appveyor, CodeShip, Travis CI, Jenkins, TeamCity
@@ -55,7 +54,7 @@ export function blueprintsUrl(path, version = BLUEPRINTS_API_VERSION) {
55
54
  let _token;
56
55
  function loadToken() {
57
56
  let token = null;
58
- if (isTest || isPublishing) {
57
+ if (isTest) {
59
58
  token = 'token';
60
59
  }
61
60
  else {
@@ -0,0 +1,10 @@
1
+ import type { AuthParams } from '../../utils/types.js';
2
+ import type { CoreConfig, CoreResult } from '../index.js';
3
+ export interface FunctionListOptions extends Pick<CoreConfig, 'log'> {
4
+ auth: AuthParams;
5
+ flags: {
6
+ json?: boolean;
7
+ verbose?: boolean;
8
+ };
9
+ }
10
+ export declare function functionListCore(options: FunctionListOptions): Promise<CoreResult>;
@@ -0,0 +1,34 @@
1
+ import { listFunctions } from '../../actions/functions/list.js';
2
+ import { formatFunctionsList } from '../../utils/display/functions-formatting.js';
3
+ import { capitalize, niceId } from '../../utils/display/presenters.js';
4
+ import { styleText } from '../../utils/style-text.js';
5
+ export async function functionListCore(options) {
6
+ const { auth, flags, log } = options;
7
+ const { scopeId, scopeType } = auth;
8
+ const spinner = flags.json ? undefined : log.ora('Fetching functions...').start();
9
+ const result = await listFunctions(auth, log);
10
+ if (!result.ok) {
11
+ spinner?.fail('Failed to list functions');
12
+ const suggestions = /access|permission|forbidden/i.test(result.error)
13
+ ? [
14
+ `Verify you have access to ${scopeType} "${scopeId}".`,
15
+ 'Try a different scope with --project-id or --organization-id.',
16
+ ]
17
+ : undefined;
18
+ return { success: false, error: result.error, suggestions };
19
+ }
20
+ spinner?.stop().clear();
21
+ if (!flags.json) {
22
+ if (result.functions.length === 0) {
23
+ log(`No functions found for ${scopeType} ${niceId(scopeId)}`);
24
+ }
25
+ else {
26
+ log(`${styleText('bold', capitalize(scopeType))} ${niceId(scopeId)} ${styleText('bold', 'Functions')} [${result.functions.length}]:`);
27
+ log(formatFunctionsList(result.functions, { verbose: flags.verbose }));
28
+ }
29
+ }
30
+ return {
31
+ success: true,
32
+ json: { functions: result.functions, scopeType, scopeId },
33
+ };
34
+ }
@@ -27598,25 +27598,21 @@ function prettyBytes(number, options) {
27598
27598
  }
27599
27599
 
27600
27600
  const localeOptions = buildLocaleOptions(options);
27601
- let result;
27602
27601
 
27603
- if (number < 1) {
27604
- const numberString = toLocaleString(number, options.locale, localeOptions);
27605
- result = prefix + numberString + separator + UNITS[0];
27606
- } else {
27607
- const exponent = Math.min(Math.floor(options.binary ? log(number) / Math.log(1024) : log10(number) / 3), UNITS.length - 1);
27608
- number = divide(number, (options.binary ? 1024 : 1000) ** exponent);
27602
+ let exponent = 0;
27603
+ if (number >= 1) {
27604
+ exponent = Math.min(Math.floor(options.binary ? log(number) / Math.log(1024) : log10(number) / 3), UNITS.length - 1);
27605
+ }
27609
27606
 
27610
- if (!localeOptions) {
27611
- const minPrecision = Math.max(3, Math.floor(number).toString().length);
27612
- number = number.toPrecision(minPrecision);
27613
- }
27607
+ number = divide(number, (options.binary ? 1024 : 1000) ** exponent);
27614
27608
 
27615
- const numberString = toLocaleString(Number(number), options.locale, localeOptions);
27616
- const unit = UNITS[exponent];
27617
- result = prefix + numberString + separator + unit;
27609
+ if (!localeOptions) {
27610
+ const minPrecision = Math.max(3, Math.floor(number).toString().length);
27611
+ number = Number(number.toPrecision(minPrecision));
27618
27612
  }
27619
27613
 
27614
+ const numberString = toLocaleString(number, options.locale, localeOptions);
27615
+ const result = prefix + numberString + separator + UNITS[exponent];
27620
27616
  return applyFixedWidth(result, options.fixedWidth);
27621
27617
  }
27622
27618
 
@@ -0,0 +1,7 @@
1
+ import type { DeployedFunction } from '../../actions/functions/list.js';
2
+ export declare function formatFunctionsList(functions: DeployedFunction[], options?: {
3
+ verbose?: boolean;
4
+ }): string;
5
+ export declare function formatFunction(fn: DeployedFunction, options?: {
6
+ verbose?: boolean;
7
+ }): string;
@@ -0,0 +1,95 @@
1
+ import { SANITY_FUNCTION_PREFIX } from '../../constants.js';
2
+ import { styleText } from '../style-text.js';
3
+ import { formatDateTime } from './dates.js';
4
+ import { niceId, renderSection } from './presenters.js';
5
+ export function formatFunctionsList(functions, options = {}) {
6
+ if (!options.verbose)
7
+ return formatCompactList(functions);
8
+ return functions.map((fn) => formatFunction(fn, options)).join('\n');
9
+ }
10
+ export function formatFunction(fn, options = {}) {
11
+ if (!options.verbose)
12
+ return formatCompactList([fn]);
13
+ const rows = [];
14
+ if (fn.type)
15
+ rows.push(['Type', shortType(fn.type)]);
16
+ if (fn.updatedAt) {
17
+ const updatedAt = formatDateTime(fn.updatedAt);
18
+ if (updatedAt)
19
+ rows.push(['Updated', updatedAt]);
20
+ }
21
+ if (typeof fn.memory === 'number')
22
+ rows.push(['Memory', `${fn.memory} MB`]);
23
+ if (typeof fn.timeout === 'number')
24
+ rows.push(['Timeout', `${fn.timeout}s`]);
25
+ const rule = formatEventRule(fn.eventRule);
26
+ if (rule)
27
+ rows.push(['Rule', rule]);
28
+ return renderSection(formatTitle(fn), rows);
29
+ }
30
+ function formatCompactList(functions) {
31
+ const titles = functions.map(plainTitle);
32
+ const ids = functions.map((fn) => `<${fn.id}>`);
33
+ const types = functions.map((fn) => (fn.type ? shortType(fn.type) : '-'));
34
+ const updated = functions.map((fn) => (fn.updatedAt ? formatDateTime(fn.updatedAt) || '-' : '-'));
35
+ const titlePad = Math.max(...titles.map((title) => title.length));
36
+ const idPad = Math.max(...ids.map((id) => id.length));
37
+ const typePad = Math.max(...types.map((type) => type.length));
38
+ return functions
39
+ .map((fn, index) => {
40
+ const title = formatIdentity(fn) + ' '.repeat(titlePad - titles[index].length);
41
+ const id = niceId(fn.id) + ' '.repeat(idPad - ids[index].length);
42
+ const type = styleText('dim', types[index].padEnd(typePad));
43
+ const timestamp = styleText('dim', updated[index]);
44
+ return ` ${title} ${id} ${type} ${timestamp}`;
45
+ })
46
+ .join('\n');
47
+ }
48
+ function formatTitle(fn) {
49
+ return `${formatIdentity(fn)} ${niceId(fn.id)}`;
50
+ }
51
+ function formatIdentity(fn) {
52
+ const parts = [];
53
+ if (fn.name)
54
+ parts.push(styleText('bold', fn.name));
55
+ if (fn.displayName && fn.displayName !== fn.name) {
56
+ parts.push(styleText('green', `"${fn.displayName}"`));
57
+ }
58
+ if (parts.length === 0)
59
+ parts.push(styleText('bold', 'Unnamed'));
60
+ return parts.join(' ');
61
+ }
62
+ function plainTitle(fn) {
63
+ const parts = [];
64
+ if (fn.name)
65
+ parts.push(fn.name);
66
+ if (fn.displayName && fn.displayName !== fn.name)
67
+ parts.push(`"${fn.displayName}"`);
68
+ return parts.length > 0 ? parts.join(' ') : 'Unnamed';
69
+ }
70
+ function shortType(type) {
71
+ return type.startsWith(SANITY_FUNCTION_PREFIX) ? type.slice(SANITY_FUNCTION_PREFIX.length) : type;
72
+ }
73
+ function formatEventRule(rule) {
74
+ if (rule === null || rule === undefined)
75
+ return undefined;
76
+ if (typeof rule !== 'object')
77
+ return String(rule);
78
+ if (Array.isArray(rule))
79
+ return rule.map(formatRuleValue).join(', ');
80
+ const entries = Object.entries(rule);
81
+ if (entries.length === 0)
82
+ return undefined;
83
+ return entries.map(([key, value]) => `${key}: ${formatRuleValue(value)}`).join(' · ');
84
+ }
85
+ function formatRuleValue(value) {
86
+ if (typeof value === 'string')
87
+ return value;
88
+ if (value === null || value === undefined)
89
+ return String(value);
90
+ if (Array.isArray(value))
91
+ return value.map(formatRuleValue).join(', ');
92
+ if (typeof value === 'object')
93
+ return JSON.stringify(value);
94
+ return String(value);
95
+ }
@@ -15,7 +15,7 @@ function arrayifyEvent(event) {
15
15
  details.push(formatLabeledValue('expression', event.expression));
16
16
  }
17
17
  else {
18
- details.push(formatLabeledValue('expression', `${event.minute} ${event.hour} ${event.dayOfWeek} ${event.month} ${event.dayOfMonth}`));
18
+ details.push(formatLabeledValue('expression', `${event.minute} ${event.hour} ${event.dayOfMonth} ${event.month} ${event.dayOfWeek}`));
19
19
  }
20
20
  }
21
21
  else {
@@ -37,12 +37,16 @@ export function Logger(log, flags = {}) {
37
37
  if (flags.json)
38
38
  return createOraLineLoggingWrapper(opts, logger);
39
39
  if (level >= LogLevel.INFO)
40
- return withTerminalProgress(ora(opts));
40
+ return withTerminalProgress(ora(keepStdinInterruptible(opts)));
41
41
  return createOraLineLoggingWrapper(opts, logger);
42
42
  };
43
43
  logger.ora = oraWrapper;
44
44
  return logger;
45
45
  }
46
+ function keepStdinInterruptible(opts) {
47
+ const options = typeof opts === 'string' ? { text: opts } : opts;
48
+ return { discardStdin: false, ...options };
49
+ }
46
50
  function withTerminalProgress(spinner) {
47
51
  const wrap = (name, effect) => {
48
52
  if (typeof spinner[name] !== 'function')