@sanity/runtime-cli 12.0.1 → 12.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +25 -24
  2. package/dist/actions/blueprints/blueprint.d.ts +5 -4
  3. package/dist/actions/blueprints/config.d.ts +7 -6
  4. package/dist/actions/blueprints/config.js +8 -6
  5. package/dist/actions/blueprints/stacks.d.ts +8 -4
  6. package/dist/actions/blueprints/stacks.js +6 -32
  7. package/dist/commands/blueprints/destroy.js +2 -0
  8. package/dist/commands/blueprints/doctor.d.ts +1 -0
  9. package/dist/commands/blueprints/doctor.js +4 -0
  10. package/dist/commands/blueprints/info.js +1 -1
  11. package/dist/commands/blueprints/init.js +1 -1
  12. package/dist/commands/blueprints/stacks.js +1 -1
  13. package/dist/commands/functions/dev.d.ts +2 -2
  14. package/dist/commands/functions/dev.js +3 -2
  15. package/dist/config.js +12 -2
  16. package/dist/constants.d.ts +7 -0
  17. package/dist/constants.js +7 -0
  18. package/dist/cores/blueprints/config.js +36 -39
  19. package/dist/cores/blueprints/doctor.d.ts +1 -0
  20. package/dist/cores/blueprints/doctor.js +36 -5
  21. package/dist/cores/blueprints/info.js +2 -2
  22. package/dist/cores/blueprints/init.d.ts +2 -0
  23. package/dist/cores/blueprints/init.js +38 -14
  24. package/dist/cores/functions/env/add.js +2 -2
  25. package/dist/cores/functions/env/list.js +2 -2
  26. package/dist/cores/functions/env/remove.js +2 -2
  27. package/dist/cores/functions/logs.js +2 -2
  28. package/dist/cores/functions/test.js +31 -23
  29. package/dist/server/app.js +32 -21
  30. package/dist/server/handlers/invoke.d.ts +2 -2
  31. package/dist/server/handlers/invoke.js +2 -2
  32. package/dist/server/static/components/api-base.js +3 -0
  33. package/dist/server/static/components/app.css +120 -95
  34. package/dist/server/static/components/clear-button.js +1 -1
  35. package/dist/server/static/components/console-panel.js +6 -6
  36. package/dist/server/static/components/fetch-button.js +1 -1
  37. package/dist/server/static/components/filter-api-version.js +3 -3
  38. package/dist/server/static/components/filter-document-id.js +5 -5
  39. package/dist/server/static/components/filter-with-token.js +4 -4
  40. package/dist/server/static/components/filters.js +2 -2
  41. package/dist/server/static/components/function-list.js +14 -5
  42. package/dist/server/static/components/help-button.js +4 -1
  43. package/dist/server/static/components/payload-panel.js +9 -9
  44. package/dist/server/static/components/response-panel.js +8 -8
  45. package/dist/server/static/components/rule-panel.js +4 -4
  46. package/dist/server/static/components/run-panel.js +4 -4
  47. package/dist/server/static/components/select-dropdown.js +5 -25
  48. package/dist/server/static/index.html +9 -9
  49. package/dist/server/static/vendor/m-.css +1 -0
  50. package/dist/server/static/vendor/m-.woff2 +0 -0
  51. package/dist/utils/display/blueprints-formatting.d.ts +3 -2
  52. package/dist/utils/display/blueprints-formatting.js +102 -50
  53. package/dist/utils/display/presenters.d.ts +1 -0
  54. package/dist/utils/display/presenters.js +3 -0
  55. package/dist/utils/display/prompt.js +10 -9
  56. package/dist/utils/display/resources-formatting.d.ts +6 -2
  57. package/dist/utils/display/resources-formatting.js +71 -17
  58. package/dist/utils/find-function.d.ts +2 -2
  59. package/dist/utils/find-function.js +9 -2
  60. package/dist/utils/invoke-local.d.ts +2 -2
  61. package/dist/utils/invoke-local.js +27 -16
  62. package/dist/utils/types.d.ts +46 -22
  63. package/dist/utils/types.js +25 -2
  64. package/dist/utils/validate/resource.js +144 -23
  65. package/dist/utils/validated-token.js +1 -1
  66. package/oclif.manifest.json +23 -4
  67. package/package.json +7 -4
@@ -11,6 +11,7 @@ import { resolveResourceDependencies } from './functions/resolve-dependencies.js
11
11
  import { shouldAutoResolveDependencies } from './functions/should-auto-resolve-deps.js';
12
12
  import { shouldTranspileFunction } from './functions/should-transpile.js';
13
13
  import { transpileFunction } from './transpile/transpile-function.js';
14
+ import { isDocumentFunctionResource, isGroqContextOptions, isMediaLibraryAssetFunctionResource, } from './types.js';
14
15
  function getChildProcessWrapperPath() {
15
16
  return fileURLToPath(new URL('./child-process-wrapper.js', import.meta.url));
16
17
  }
@@ -34,7 +35,8 @@ function getEvent(rule) {
34
35
  projection: rule.projection || DEFAULT_GROQ_RULE.projection,
35
36
  };
36
37
  }
37
- export async function applyGroqRule(resource, data, before, after, projectId, dataset) {
38
+ export async function applyGroqRule(resource, payload, projectId, dataset) {
39
+ const { before, after, payload: data = null } = payload;
38
40
  // If there is no rule set return everything
39
41
  if (!resource.event)
40
42
  return data;
@@ -64,17 +66,6 @@ export default async function invoke(resource, payload, context, options) {
64
66
  if (!resource.src) {
65
67
  throw new Error(`Function resource "${resource.name}" is missing the 'src' property.`);
66
68
  }
67
- const { before, after, payload: data = null } = payload;
68
- const { forceColor = true, timeout = 10 } = options;
69
- const { projectId, dataset } = context.clientOptions;
70
- const filteredData = await applyGroqRule(resource, data, before, after, projectId, dataset);
71
- if (typeof filteredData === 'undefined') {
72
- return {
73
- logs: `⚠️ Filter "${resource.event?.filter}" returned an empty result. Skipping invoke.`,
74
- error: undefined,
75
- json: undefined,
76
- };
77
- }
78
69
  let cleanupBundle = async () => { };
79
70
  let functionPath = '';
80
71
  let bundleTimings;
@@ -98,6 +89,24 @@ export default async function invoke(resource, payload, context, options) {
98
89
  if (!existingPackageJson) {
99
90
  createTempPackageJson(functionPath);
100
91
  }
92
+ const { forceColor = true, timeout = 10 } = options;
93
+ let filteredData = {};
94
+ if (isDocumentFunctionResource(resource) || isMediaLibraryAssetFunctionResource(resource)) {
95
+ if (!isGroqContextOptions(context)) {
96
+ throw new Error('GROQ-based functions require a context with clientOptions');
97
+ }
98
+ const { projectId, dataset } = context.clientOptions;
99
+ if ('before' in payload) {
100
+ filteredData = await applyGroqRule(resource, payload, projectId, dataset);
101
+ if (typeof filteredData === 'undefined') {
102
+ return {
103
+ logs: `⚠️ Filter "${resource.event?.filter}" returned an empty result. Skipping invoke.`,
104
+ error: undefined,
105
+ json: undefined,
106
+ };
107
+ }
108
+ }
109
+ }
101
110
  return new Promise((resolve, reject) => {
102
111
  let child;
103
112
  let timer;
@@ -167,10 +176,12 @@ export default async function invoke(resource, payload, context, options) {
167
176
  context: {
168
177
  ...context,
169
178
  local: true,
170
- clientOptions: {
171
- ...context.clientOptions,
172
- apiHost: config.apiUrl,
173
- },
179
+ ...(isGroqContextOptions(context) && {
180
+ clientOptions: {
181
+ ...context.clientOptions,
182
+ apiHost: config.apiUrl,
183
+ },
184
+ }),
174
185
  },
175
186
  };
176
187
  child.send(JSON.stringify({ srcPath: functionPath, payload }, null, 2));
@@ -1,4 +1,6 @@
1
+ import { type BlueprintCorsOriginResource, type BlueprintDatasetResource, type BlueprintDocumentWebhookResource, type BlueprintResource, type BlueprintRoleResource } from '@sanity/blueprints';
1
2
  import type { Blueprint } from '@sanity/blueprints-parser';
3
+ import { SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_SCHEDULE } from '../constants.js';
2
4
  export type ScopeType = 'organization' | 'project';
3
5
  /** Result utility type */
4
6
  export type Result<T, E = string> = {
@@ -35,45 +37,58 @@ interface GroqRuleMediaLibraryFunction extends GroqRuleBase {
35
37
  id: string;
36
38
  };
37
39
  }
38
- /** @internal */
39
- export interface Resource {
40
- name: string;
41
- type: string;
42
- id?: string;
43
- externalId?: string;
44
- displayName?: string;
40
+ export interface FunctionResourceScheduleExplicitEvent {
41
+ minute: string;
42
+ hour: string;
43
+ dayOfMonth: string;
44
+ month: string;
45
+ dayOfWeek: string;
46
+ }
47
+ interface FunctionResourceScheduleExpressionEvent {
48
+ expression: string;
45
49
  }
46
- export interface DeployedResource extends Resource {
50
+ type FunctionResourceScheduleEvent = FunctionResourceScheduleExplicitEvent | FunctionResourceScheduleExpressionEvent;
51
+ export interface DeployedResource extends BlueprintResource {
47
52
  id: string;
48
53
  externalId: string;
54
+ parameters: Record<string, unknown>;
49
55
  }
50
- export declare function isLocalFunctionResource<T extends Resource>(r: T): r is T & FunctionResourceBase;
51
- export declare function isDocumentFunctionResource<T extends Resource>(r: T): r is T & FunctionResourceDocument;
52
- export declare function isMediaLibraryAssetFunctionResource<T extends Resource>(r: T): r is T & FunctionResourceMediaLibraryAsset;
53
- export declare function isLocalFunctionCollection<T extends Resource>(r: T): r is T & {
56
+ export declare function isLocalFunctionResource(r: BlueprintResource): r is FunctionResourceBase;
57
+ export declare function isDocumentFunctionResource<T extends BlueprintResource>(r: T): r is T & FunctionResourceDocument;
58
+ export declare function isMediaLibraryAssetFunctionResource<T extends BlueprintResource>(r: T): r is T & FunctionResourceMediaLibraryAsset;
59
+ export declare function isScheduleFunctionResource<T extends BlueprintResource>(r: T): r is T & FunctionResourceSchedule;
60
+ export declare function isLocalFunctionCollection<T extends BlueprintResource>(r: T): r is T & {
54
61
  functions: Array<FunctionResourceBase>;
55
62
  };
56
- /** @internal */
57
- export type FunctionResource = FunctionResourceDocument | FunctionResourceMediaLibraryAsset | FunctionResourceBase;
58
- export interface FunctionResourceBase extends Resource {
63
+ export declare function isScheduleEvent(e: unknown): e is FunctionResourceScheduleEvent;
64
+ export declare function isCorsOriginResource(r: unknown): r is BlueprintCorsOriginResource;
65
+ export declare function isRoleResource(r: unknown): r is BlueprintRoleResource;
66
+ export declare function isDatasetResource(r: unknown): r is BlueprintDatasetResource;
67
+ export declare function isWebhookResource(r: unknown): r is BlueprintDocumentWebhookResource;
68
+ /** @internal */
69
+ export type FunctionResource = FunctionResourceDocument | FunctionResourceMediaLibraryAsset | FunctionResourceSchedule | FunctionResourceBase;
70
+ export type FunctionGroqResource = FunctionResourceDocument | FunctionResourceMediaLibraryAsset;
71
+ export interface FunctionResourceBase extends BlueprintResource {
72
+ displayName?: string;
59
73
  src?: string;
60
74
  autoResolveDeps?: boolean;
61
75
  transpile?: boolean;
62
76
  memory?: number;
63
77
  timeout?: number;
64
78
  env?: Record<string, string>;
65
- event?: GroqRuleBase;
79
+ event?: GroqRuleBase | FunctionResourceScheduleEvent;
66
80
  }
67
81
  interface FunctionResourceDocument extends FunctionResourceBase {
68
- type: 'sanity.function.document';
82
+ type: typeof SANITY_FUNCTION_DOCUMENT;
69
83
  event?: GroqRuleDocumentFunction;
70
84
  }
71
85
  interface FunctionResourceMediaLibraryAsset extends FunctionResourceBase {
72
- type: 'sanity.function.media-library.asset';
86
+ type: typeof SANITY_FUNCTION_MEDIA_LIBRARY_ASSET;
73
87
  event: GroqRuleMediaLibraryFunction;
74
88
  }
75
- export interface CorsResource extends Resource {
76
- origin?: string;
89
+ interface FunctionResourceSchedule extends FunctionResourceBase {
90
+ type: typeof SANITY_FUNCTION_SCHEDULE;
91
+ event: FunctionResourceScheduleEvent;
77
92
  }
78
93
  export interface Stack {
79
94
  id: string;
@@ -107,16 +122,22 @@ export interface BuildPayloadOptions {
107
122
  timeout?: number;
108
123
  }
109
124
  /** @internal */
110
- export interface InvokePayloadOptions {
125
+ export interface InvokeGroqPayloadOptions {
111
126
  payload?: Record<string, unknown>;
112
127
  event: EventType;
113
128
  before: Record<string, unknown> | null;
114
129
  after: Record<string, unknown> | null;
115
130
  }
131
+ export interface InvokeSchedulePayloadOptions {
132
+ payload?: Record<string, unknown>;
133
+ event: 'schedule';
134
+ }
135
+ export type InvokePayloadOptions = InvokeGroqPayloadOptions | InvokeSchedulePayloadOptions;
136
+ export type InvokePayloadMetadata = Pick<InvokeGroqPayloadOptions, 'event' | 'before' | 'after'> | Pick<InvokeSchedulePayloadOptions, 'event'>;
116
137
  export type EventType = 'create' | 'update' | 'delete';
117
138
  export declare function isEventType(arg: string): arg is EventType;
118
139
  /** @internal */
119
- export interface InvokeContextOptions {
140
+ export interface InvokeGroqContextOptions {
120
141
  clientOptions: {
121
142
  apiVersion?: string;
122
143
  dataset?: string;
@@ -133,6 +154,9 @@ export interface InvokeContextOptions {
133
154
  /** The resource ID of the function container; resource ID that houses the function. */
134
155
  functionResourceId: string;
135
156
  }
157
+ export type InvokeScheduleContextOptions = Record<string, never>;
158
+ export type InvokeContextOptions = InvokeGroqContextOptions | InvokeScheduleContextOptions;
159
+ export declare function isGroqContextOptions(context: InvokeContextOptions): context is InvokeGroqContextOptions;
136
160
  /** @internal */
137
161
  export interface InvokeExecutionOptions {
138
162
  forceColor?: boolean;
@@ -1,19 +1,42 @@
1
+ import { validateCorsOrigin, validateDataset, validateDocumentWebhook, validateRole, } from '@sanity/blueprints';
2
+ import { SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_SCHEDULE, } from '../constants.js';
1
3
  // type narrowing with predicate functions
2
4
  export function isLocalFunctionResource(r) {
3
5
  return r.type.startsWith('sanity.function.');
4
6
  }
5
7
  export function isDocumentFunctionResource(r) {
6
- return r.type === 'sanity.function.document';
8
+ return r.type === SANITY_FUNCTION_DOCUMENT;
7
9
  }
8
10
  export function isMediaLibraryAssetFunctionResource(r) {
9
- return r.type === 'sanity.function.media-library.asset';
11
+ return r.type === SANITY_FUNCTION_MEDIA_LIBRARY_ASSET;
12
+ }
13
+ export function isScheduleFunctionResource(r) {
14
+ return r.type === SANITY_FUNCTION_SCHEDULE;
10
15
  }
11
16
  export function isLocalFunctionCollection(r) {
12
17
  return r.type === 'sanity.experimental.functions-collection';
13
18
  }
19
+ export function isScheduleEvent(e) {
20
+ return e !== null && typeof e === 'object' && ('hour' in e || 'expression' in e);
21
+ }
22
+ export function isCorsOriginResource(r) {
23
+ return validateCorsOrigin(r).length === 0;
24
+ }
25
+ export function isRoleResource(r) {
26
+ return validateRole(r).length === 0;
27
+ }
28
+ export function isDatasetResource(r) {
29
+ return validateDataset(r).length === 0;
30
+ }
31
+ export function isWebhookResource(r) {
32
+ return validateDocumentWebhook(r).length === 0;
33
+ }
14
34
  export function isEventType(arg) {
15
35
  return ['create', 'update', 'delete'].includes(arg);
16
36
  }
37
+ export function isGroqContextOptions(context) {
38
+ return 'clientOptions' in context;
39
+ }
17
40
  /** @internal */
18
41
  export var BlueprintParserErrorType;
19
42
  (function (BlueprintParserErrorType) {
@@ -1,4 +1,4 @@
1
- import { BlueprintParserErrorType, isDocumentFunctionResource, isMediaLibraryAssetFunctionResource, } from '../types.js';
1
+ import { BlueprintParserErrorType, isDocumentFunctionResource, isMediaLibraryAssetFunctionResource, isScheduleEvent, } from '../types.js';
2
2
  export function validateFunctionName(name) {
3
3
  // must be 3+ characters, no special characters, no spaces, allow _ and -
4
4
  return /^[a-zA-Z0-9][a-zA-Z0-9_-]{2,}$/.test(name);
@@ -20,29 +20,68 @@ export function validateFunctionResource(resource) {
20
20
  type: BlueprintParserErrorType.InvalidType,
21
21
  });
22
22
  }
23
- if (!resource.event || !Array.isArray(resource.event.on) || resource.event.on.length === 0) {
24
- errors.push({
25
- message: `${msgPrefix} event.on must be a non-empty array`,
26
- type: BlueprintParserErrorType.MissingRequiredProperty,
27
- });
28
- }
29
- else if (!resource.event.on.every((evt) => validFunctionEventNames.includes(evt))) {
30
- errors.push({
31
- message: `${msgPrefix} event.on values must be one of ${validFunctionEventNames.map((e) => `"${e}"`).join(', ')}`,
32
- type: BlueprintParserErrorType.InvalidValue,
33
- });
34
- }
35
- if (resource.event?.filter && typeof resource.event.filter !== 'string') {
36
- errors.push({
37
- message: `${msgPrefix} event.filter must be a string`,
38
- type: BlueprintParserErrorType.InvalidType,
39
- });
23
+ if (isScheduleEvent(resource.event)) {
24
+ const event = resource.event;
25
+ const hasExpression = 'expression' in event;
26
+ const hasExplicitFields = 'minute' in event ||
27
+ 'hour' in event ||
28
+ 'dayOfMonth' in event ||
29
+ 'month' in event ||
30
+ 'dayOfWeek' in event;
31
+ if (hasExpression && hasExplicitFields) {
32
+ errors.push({
33
+ type: BlueprintParserErrorType.InvalidFormat,
34
+ message: 'Cannot specify both `expression` and explicit cron fields (`minute`, `hour`, `dayOfMonth`, `month`, `dayOfWeek`)',
35
+ });
36
+ }
37
+ else if (!hasExpression && !hasExplicitFields) {
38
+ errors.push({
39
+ type: BlueprintParserErrorType.MissingRequiredProperty,
40
+ message: 'Either `expression` or explicit cron fields (`minute`, `hour`, `dayOfMonth`, `month`, `dayOfWeek`) must be provided',
41
+ });
42
+ }
43
+ else if (hasExpression) {
44
+ const expressionParts = event.expression.split(' ');
45
+ if (expressionParts.length !== 5) {
46
+ errors.push({
47
+ type: BlueprintParserErrorType.InvalidFormat,
48
+ message: 'Invalid `expression` format. Cron fields (`minute`, `hour`, `dayOfMonth`, `month`, `dayOfWeek`) must be provided',
49
+ });
50
+ }
51
+ else {
52
+ const [minute, hour, dayOfWeek, month, dayOfMonth] = expressionParts;
53
+ errors.push(...validateScheduleEvent(msgPrefix, { minute, hour, dayOfWeek, month, dayOfMonth }));
54
+ }
55
+ }
56
+ else if (hasExplicitFields) {
57
+ errors.push(...validateScheduleEvent(msgPrefix, event));
58
+ }
40
59
  }
41
- if (resource.event?.projection && typeof resource.event.projection !== 'string') {
42
- errors.push({
43
- message: `${msgPrefix} event.projection must be a string`,
44
- type: BlueprintParserErrorType.InvalidType,
45
- });
60
+ else {
61
+ if (!resource.event || !Array.isArray(resource.event.on) || resource.event.on.length === 0) {
62
+ errors.push({
63
+ message: `${msgPrefix} event.on must be a non-empty array`,
64
+ type: BlueprintParserErrorType.MissingRequiredProperty,
65
+ });
66
+ }
67
+ else if (!resource.event.on.every((evt) => validFunctionEventNames.includes(evt))) {
68
+ errors.push({
69
+ message: `${msgPrefix} event.on values must be one of ${validFunctionEventNames.map((e) => `"${e}"`).join(', ')}`,
70
+ type: BlueprintParserErrorType.InvalidValue,
71
+ });
72
+ }
73
+ if (resource.event?.filter && typeof resource.event.filter !== 'string') {
74
+ errors.push({
75
+ message: `${msgPrefix} event.filter must be a string`,
76
+ type: BlueprintParserErrorType.InvalidType,
77
+ });
78
+ }
79
+ if (resource.event?.projection && typeof resource.event.projection !== 'string') {
80
+ errors.push({
81
+ message: `${msgPrefix} event.projection must be a string`,
82
+ type: BlueprintParserErrorType.InvalidType,
83
+ });
84
+ }
46
85
  }
47
86
  if (resource.memory !== undefined) {
48
87
  if (!Number.isInteger(resource.memory)) {
@@ -150,3 +189,85 @@ export function validateFunctionResource(resource) {
150
189
  }
151
190
  return errors;
152
191
  }
192
+ function validateScheduleEvent(msgPrefix, event) {
193
+ const errors = [];
194
+ const properties = [
195
+ { name: 'minute', regex: MINUTES },
196
+ { name: 'hour', regex: HOURS },
197
+ { name: 'dayOfMonth', regex: DAY_OF_MONTH },
198
+ { name: 'month', regex: MONTH },
199
+ { name: 'dayOfWeek', regex: DAY_OF_WEEK },
200
+ ];
201
+ properties.forEach((prop) => {
202
+ const { name, regex } = prop;
203
+ if (!(name in event)) {
204
+ errors.push({
205
+ type: BlueprintParserErrorType.MissingRequiredProperty,
206
+ message: `${msgPrefix} '${name}' must be provided`,
207
+ });
208
+ return;
209
+ }
210
+ const value = event[name];
211
+ if (typeof value !== 'string') {
212
+ errors.push({
213
+ type: BlueprintParserErrorType.InvalidType,
214
+ message: `${msgPrefix} '${name}' must be a string`,
215
+ });
216
+ return;
217
+ }
218
+ if (!isValidCronPart(regex, value)) {
219
+ errors.push({
220
+ type: BlueprintParserErrorType.InvalidValue,
221
+ message: `${msgPrefix} ${name} field contains invalid value: ${value}`,
222
+ });
223
+ }
224
+ });
225
+ return errors;
226
+ }
227
+ /**
228
+ * Validates that each cron part adheres to it's rules
229
+ *
230
+ * @param {RegExp} regex the regular expression that corresponds to the part of the cron expression you are testing
231
+ * @param {string} value the string value of part of the cron expression you are testing
232
+ * @returns {boolean} whether or not the cron part is valid
233
+ */
234
+ function isValidCronPart(regex, value) {
235
+ return regex.test(value) && checkAscendingRanges(value) && checkNoZeroStep(value);
236
+ }
237
+ const MINUTES = /^(\*(\/([1-5]?\d))?|([0-5]?\d)(-[0-5]?\d)?(\/([1-5]?\d))?)(,(\*(\/([1-5]?\d))?|([0-5]?\d)(-[0-5]?\d)?(\/([1-5]?\d))?))*$/;
238
+ const HOURS = /^(\*(\/([1-9]|1\d|2[0-3]))?|([01]?\d|2[0-3])(-([01]?\d|2[0-3]))?(\/([1-9]|1\d|2[0-3]))?)(,(\*(\/([1-9]|1\d|2[0-3]))?|([01]?\d|2[0-3])(-([01]?\d|2[0-3]))?(\/([1-9]|1\d|2[0-3]))?))*$/;
239
+ const DAY_OF_MONTH = /^(\*(\/([1-9]|[12]\d|3[01]))?|([1-9]|[12]\d|3[01])(-([1-9]|[12]\d|3[01]))?(\/([1-9]|[12]\d|3[01]))?)(,(\*(\/([1-9]|[12]\d|3[01]))?|([1-9]|[12]\d|3[01])(-([1-9]|[12]\d|3[01]))?(\/([1-9]|[12]\d|3[01]))?))*$/;
240
+ const MONTH = /^(\*(\/([1-9]|1[0-2]))?|([1-9]|1[0-2]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-([1-9]|1[0-2]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(\/([1-9]|1[0-2]))?)(,(\*(\/([1-9]|1[0-2]))?|([1-9]|1[0-2]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-([1-9]|1[0-2]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(\/([1-9]|1[0-2]))?))*$/i;
241
+ const DAY_OF_WEEK = /^(\*(\/([0-7]))?|([0-7]|SUN|MON|TUE|WED|THU|FRI|SAT)(-([0-7]|SUN|MON|TUE|WED|THU|FRI|SAT))?(\/([0-7]))?)(,(\*(\/([0-7]))?|([0-7]|SUN|MON|TUE|WED|THU|FRI|SAT)(-([0-7]|SUN|MON|TUE|WED|THU|FRI|SAT))?(\/([0-7]))?))*$/i;
242
+ /**
243
+ *
244
+ * @param {string} value the string value of part of the cron expression you are testing
245
+ * @returns {boolean} returns true if the range is valid
246
+ */
247
+ function checkAscendingRanges(value) {
248
+ for (const part of value.split(',')) {
249
+ if (part.includes('-')) {
250
+ const [start, right] = part.split('-');
251
+ const end = right.split('/')[0]; // remove /step
252
+ const s = Number(start);
253
+ const e = Number(end);
254
+ if (s > e)
255
+ return false;
256
+ }
257
+ }
258
+ return true;
259
+ }
260
+ /**
261
+ * @param {string} value the string value of part of the cron expression you are testing
262
+ * @returns {boolean} makes sure we are not trying to divide by zero
263
+ */
264
+ function checkNoZeroStep(value) {
265
+ for (const part of value.split(',')) {
266
+ if (part.includes('/')) {
267
+ const step = Number(part.split('/')[1]);
268
+ if (step === 0)
269
+ return false;
270
+ }
271
+ }
272
+ return true;
273
+ }
@@ -50,7 +50,7 @@ export async function validTokenOrErrorMessage(maybeToken) {
50
50
  ok: false,
51
51
  error: {
52
52
  e,
53
- message: `Authentication server error: "${e.cause}". Try again later`,
53
+ message: `Server error: "${e.cause}". Try logging in again with \`npx @sanity/cli login\``,
54
54
  },
55
55
  };
56
56
  default:
@@ -318,6 +318,9 @@
318
318
  "force"
319
319
  ],
320
320
  "description": "Project associated with the Stack",
321
+ "exclusive": [
322
+ "organization-id"
323
+ ],
321
324
  "name": "project-id",
322
325
  "hasDynamicHelp": false,
323
326
  "multiple": false,
@@ -334,6 +337,9 @@
334
337
  "force"
335
338
  ],
336
339
  "description": "Organization associated with the Stack",
340
+ "exclusive": [
341
+ "project-id"
342
+ ],
337
343
  "name": "organization-id",
338
344
  "hasDynamicHelp": false,
339
345
  "multiple": false,
@@ -391,6 +397,12 @@
391
397
  "hasDynamicHelp": false,
392
398
  "multiple": false,
393
399
  "type": "option"
400
+ },
401
+ "fix": {
402
+ "description": "Interactively fix configuration issues",
403
+ "name": "fix",
404
+ "allowNo": false,
405
+ "type": "boolean"
394
406
  }
395
407
  },
396
408
  "hasDynamicHelp": false,
@@ -415,7 +427,7 @@
415
427
  "description": "Show information about a Blueprint Stack deployment",
416
428
  "examples": [
417
429
  "<%= config.bin %> <%= command.id %>",
418
- "<%= config.bin %> <%= command.id %> --stack-id <stackId>"
430
+ "<%= config.bin %> <%= command.id %> --id <stackId>"
419
431
  ],
420
432
  "flags": {
421
433
  "verbose": {
@@ -457,7 +469,7 @@
457
469
  "name": "dir"
458
470
  }
459
471
  },
460
- "description": "Initialize a new Blueprint",
472
+ "description": "Initialize a new Blueprint Stack deployment",
461
473
  "examples": [
462
474
  "<%= config.bin %> <%= command.id %>",
463
475
  "<%= config.bin %> <%= command.id %> [directory]",
@@ -657,7 +669,7 @@
657
669
  "blueprints:stacks": {
658
670
  "aliases": [],
659
671
  "args": {},
660
- "description": "List all Blueprint stacks",
672
+ "description": "List all Blueprint Stacks",
661
673
  "examples": [
662
674
  "<%= config.bin %> <%= command.id %>",
663
675
  "<%= config.bin %> <%= command.id %> --project-id <projectId>",
@@ -862,6 +874,13 @@
862
874
  "<%= config.bin %> <%= command.id %> --host 127.0.0.1 --port 8974"
863
875
  ],
864
876
  "flags": {
877
+ "verbose": {
878
+ "description": "Verbose output",
879
+ "hidden": true,
880
+ "name": "verbose",
881
+ "allowNo": false,
882
+ "type": "boolean"
883
+ },
865
884
  "host": {
866
885
  "char": "h",
867
886
  "description": "The local network interface at which to listen. [default: \"localhost\"]",
@@ -1410,5 +1429,5 @@
1410
1429
  ]
1411
1430
  }
1412
1431
  },
1413
- "version": "12.0.1"
1432
+ "version": "12.2.0"
1414
1433
  }
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "@sanity/runtime-cli",
3
3
  "description": "Sanity's Runtime CLI for Blueprints and Functions",
4
- "version": "12.0.1",
4
+ "version": "12.2.0",
5
5
  "author": "Sanity Runtime Team",
6
6
  "type": "module",
7
7
  "license": "MIT",
8
- "repository": "sanity-io/runtime-cli",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/sanity-io/runtime-cli.git"
11
+ },
9
12
  "bugs": "https://github.com/sanity-io/runtime-cli/issues",
10
13
  "homepage": "https://github.com/sanity-io/runtime-cli",
11
14
  "main": "dist/index.js",
@@ -53,7 +56,7 @@
53
56
  "./oclif.manifest.json"
54
57
  ],
55
58
  "bin": {
56
- "sanity-run": "./bin/run.js"
59
+ "sanity-run": "bin/run.js"
57
60
  },
58
61
  "scripts": {
59
62
  "build": "rollup -c && npm run build:ts && npm run build:static && npm run build:oclif",
@@ -80,6 +83,7 @@
80
83
  "@inquirer/prompts": "^8.0.1",
81
84
  "@oclif/core": "^4.8.0",
82
85
  "@oclif/plugin-help": "^6.2.36",
86
+ "@sanity/blueprints": "^0.7.0",
83
87
  "@sanity/blueprints-parser": "^0.3.0",
84
88
  "@sanity/client": "^7.13.0",
85
89
  "adm-zip": "^0.5.16",
@@ -109,7 +113,6 @@
109
113
  "@oclif/test": "^4.1.15",
110
114
  "@playwright/test": "^1.56.1",
111
115
  "@rollup/plugin-node-resolve": "^16.0.3",
112
- "@sanity/blueprints": "^0.6.0",
113
116
  "@sanity/functions": "^1.1.0",
114
117
  "@types/adm-zip": "^0.5.7",
115
118
  "@types/cardinal": "^2.1.1",