@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.
- package/README.md +25 -24
- package/dist/actions/blueprints/blueprint.d.ts +5 -4
- package/dist/actions/blueprints/config.d.ts +7 -6
- package/dist/actions/blueprints/config.js +8 -6
- package/dist/actions/blueprints/stacks.d.ts +8 -4
- package/dist/actions/blueprints/stacks.js +6 -32
- package/dist/commands/blueprints/destroy.js +2 -0
- package/dist/commands/blueprints/doctor.d.ts +1 -0
- package/dist/commands/blueprints/doctor.js +4 -0
- package/dist/commands/blueprints/info.js +1 -1
- package/dist/commands/blueprints/init.js +1 -1
- package/dist/commands/blueprints/stacks.js +1 -1
- package/dist/commands/functions/dev.d.ts +2 -2
- package/dist/commands/functions/dev.js +3 -2
- package/dist/config.js +12 -2
- package/dist/constants.d.ts +7 -0
- package/dist/constants.js +7 -0
- package/dist/cores/blueprints/config.js +36 -39
- package/dist/cores/blueprints/doctor.d.ts +1 -0
- package/dist/cores/blueprints/doctor.js +36 -5
- package/dist/cores/blueprints/info.js +2 -2
- package/dist/cores/blueprints/init.d.ts +2 -0
- package/dist/cores/blueprints/init.js +38 -14
- package/dist/cores/functions/env/add.js +2 -2
- package/dist/cores/functions/env/list.js +2 -2
- package/dist/cores/functions/env/remove.js +2 -2
- package/dist/cores/functions/logs.js +2 -2
- package/dist/cores/functions/test.js +31 -23
- package/dist/server/app.js +32 -21
- package/dist/server/handlers/invoke.d.ts +2 -2
- package/dist/server/handlers/invoke.js +2 -2
- package/dist/server/static/components/api-base.js +3 -0
- package/dist/server/static/components/app.css +120 -95
- package/dist/server/static/components/clear-button.js +1 -1
- package/dist/server/static/components/console-panel.js +6 -6
- package/dist/server/static/components/fetch-button.js +1 -1
- package/dist/server/static/components/filter-api-version.js +3 -3
- package/dist/server/static/components/filter-document-id.js +5 -5
- package/dist/server/static/components/filter-with-token.js +4 -4
- package/dist/server/static/components/filters.js +2 -2
- package/dist/server/static/components/function-list.js +14 -5
- package/dist/server/static/components/help-button.js +4 -1
- package/dist/server/static/components/payload-panel.js +9 -9
- package/dist/server/static/components/response-panel.js +8 -8
- package/dist/server/static/components/rule-panel.js +4 -4
- package/dist/server/static/components/run-panel.js +4 -4
- package/dist/server/static/components/select-dropdown.js +5 -25
- package/dist/server/static/index.html +9 -9
- package/dist/server/static/vendor/m-.css +1 -0
- package/dist/server/static/vendor/m-.woff2 +0 -0
- package/dist/utils/display/blueprints-formatting.d.ts +3 -2
- package/dist/utils/display/blueprints-formatting.js +102 -50
- package/dist/utils/display/presenters.d.ts +1 -0
- package/dist/utils/display/presenters.js +3 -0
- package/dist/utils/display/prompt.js +10 -9
- package/dist/utils/display/resources-formatting.d.ts +6 -2
- package/dist/utils/display/resources-formatting.js +71 -17
- package/dist/utils/find-function.d.ts +2 -2
- package/dist/utils/find-function.js +9 -2
- package/dist/utils/invoke-local.d.ts +2 -2
- package/dist/utils/invoke-local.js +27 -16
- package/dist/utils/types.d.ts +46 -22
- package/dist/utils/types.js +25 -2
- package/dist/utils/validate/resource.js +144 -23
- package/dist/utils/validated-token.js +1 -1
- package/oclif.manifest.json +23 -4
- 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,
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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));
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
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
|
|
51
|
-
export declare function isDocumentFunctionResource<T extends
|
|
52
|
-
export declare function isMediaLibraryAssetFunctionResource<T extends
|
|
53
|
-
export declare function
|
|
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
|
-
|
|
57
|
-
export
|
|
58
|
-
export
|
|
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:
|
|
82
|
+
type: typeof SANITY_FUNCTION_DOCUMENT;
|
|
69
83
|
event?: GroqRuleDocumentFunction;
|
|
70
84
|
}
|
|
71
85
|
interface FunctionResourceMediaLibraryAsset extends FunctionResourceBase {
|
|
72
|
-
type:
|
|
86
|
+
type: typeof SANITY_FUNCTION_MEDIA_LIBRARY_ASSET;
|
|
73
87
|
event: GroqRuleMediaLibraryFunction;
|
|
74
88
|
}
|
|
75
|
-
|
|
76
|
-
|
|
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
|
|
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
|
|
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;
|
package/dist/utils/types.js
CHANGED
|
@@ -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 ===
|
|
8
|
+
return r.type === SANITY_FUNCTION_DOCUMENT;
|
|
7
9
|
}
|
|
8
10
|
export function isMediaLibraryAssetFunctionResource(r) {
|
|
9
|
-
return r.type ===
|
|
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 (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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: `
|
|
53
|
+
message: `Server error: "${e.cause}". Try logging in again with \`npx @sanity/cli login\``,
|
|
54
54
|
},
|
|
55
55
|
};
|
|
56
56
|
default:
|
package/oclif.manifest.json
CHANGED
|
@@ -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 %> --
|
|
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
|
|
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
|
|
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
|
|
4
|
+
"version": "12.2.0",
|
|
5
5
|
"author": "Sanity Runtime Team",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
8
|
-
"repository":
|
|
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": "
|
|
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",
|