@sanity/runtime-cli 11.0.3 → 11.1.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 +30 -26
- package/dist/actions/blueprints/blueprint.d.ts +3 -3
- package/dist/actions/blueprints/resources.d.ts +2 -2
- package/dist/actions/blueprints/resources.js +3 -4
- package/dist/commands/blueprints/add.js +9 -1
- package/dist/commands/functions/add.js +9 -1
- package/dist/commands/functions/test.d.ts +1 -0
- package/dist/commands/functions/test.js +6 -0
- package/dist/cores/blueprints/doctor.d.ts +2 -2
- package/dist/cores/blueprints/index.d.ts +2 -0
- package/dist/cores/blueprints/index.js +1 -0
- package/dist/cores/functions/add.js +31 -9
- package/dist/cores/functions/index.d.ts +9 -3
- package/dist/cores/functions/test.d.ts +1 -0
- package/dist/cores/functions/test.js +37 -7
- package/dist/server/app.js +99 -3
- package/dist/server/static/api.js +48 -2
- package/dist/server/static/components/app.css +16 -1
- package/dist/server/static/components/fetch-button.js +14 -5
- package/dist/server/static/components/filter-api-version.js +14 -0
- package/dist/server/static/components/filter-document-id.js +26 -0
- package/dist/server/static/components/filter-with-token.js +21 -0
- package/dist/server/static/components/filters.js +47 -42
- package/dist/server/static/components/function-list.js +15 -5
- package/dist/server/static/components/run-panel.js +11 -2
- package/dist/server/static/index.html +3 -0
- package/dist/utils/display/blueprints-formatting.d.ts +1 -1
- package/dist/utils/display/blueprints-formatting.js +4 -3
- package/dist/utils/display/resources-formatting.d.ts +2 -2
- package/dist/utils/functions/fetch-document.d.ts +2 -0
- package/dist/utils/functions/fetch-document.js +15 -0
- package/dist/utils/invoke-local.d.ts +2 -2
- package/dist/utils/invoke-local.js +11 -5
- package/dist/utils/types.d.ts +41 -5
- package/dist/utils/types.js +8 -0
- package/dist/utils/validate/resource.js +55 -30
- package/oclif.manifest.json +24 -3
- package/package.json +2 -2
|
@@ -45,11 +45,17 @@ export async function applyGroqRule(resource, data, before, after, projectId, da
|
|
|
45
45
|
const hasProjection = event.projection?.length;
|
|
46
46
|
const projection = hasProjection ? `${event?.projection}` : '';
|
|
47
47
|
const query = `*[${event?.filter}]${projection}`;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
try {
|
|
49
|
+
const rule = groq.parse(query, { mode: 'delta' });
|
|
50
|
+
const sanity = projectId && dataset ? { projectId, dataset } : undefined;
|
|
51
|
+
const queryResults = await groq.evaluate(rule, { dataset: [data], before, after, sanity });
|
|
52
|
+
const currentFunctionDocumentSet = await queryResults.get();
|
|
53
|
+
return currentFunctionDocumentSet[0];
|
|
54
|
+
}
|
|
55
|
+
catch (groqErr) {
|
|
56
|
+
const detail = groqErr instanceof Error && `; ${groqErr.message}`;
|
|
57
|
+
throw new Error(`Invalid rule configuration: ${query}${detail}`, { cause: groqErr });
|
|
58
|
+
}
|
|
53
59
|
}
|
|
54
60
|
// default groq rule so just return the data
|
|
55
61
|
return data;
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -15,17 +15,26 @@ export interface AuthParams {
|
|
|
15
15
|
scopeId: string;
|
|
16
16
|
}
|
|
17
17
|
/** @internal */
|
|
18
|
-
export
|
|
18
|
+
export type GroqRule = GroqRuleDocumentFunction | GroqRuleMediaLibraryFunction;
|
|
19
|
+
export interface GroqRuleBase {
|
|
19
20
|
on: Array<string>;
|
|
20
21
|
filter?: string;
|
|
22
|
+
projection?: string;
|
|
23
|
+
}
|
|
24
|
+
interface GroqRuleDocumentFunction extends GroqRuleBase {
|
|
21
25
|
includeDrafts?: boolean;
|
|
22
26
|
includeAllVersions?: boolean;
|
|
23
|
-
projection?: string;
|
|
24
27
|
resource?: {
|
|
25
28
|
type: 'dataset';
|
|
26
29
|
id: string;
|
|
27
30
|
};
|
|
28
31
|
}
|
|
32
|
+
interface GroqRuleMediaLibraryFunction extends GroqRuleBase {
|
|
33
|
+
resource: {
|
|
34
|
+
type: 'media-library';
|
|
35
|
+
id: string;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
29
38
|
/** @internal */
|
|
30
39
|
export interface Resource {
|
|
31
40
|
name: string;
|
|
@@ -38,16 +47,27 @@ export interface DeployedResource extends Resource {
|
|
|
38
47
|
id: string;
|
|
39
48
|
externalId: string;
|
|
40
49
|
}
|
|
41
|
-
export declare function isLocalFunctionResource(r:
|
|
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;
|
|
42
53
|
/** @internal */
|
|
43
|
-
export
|
|
54
|
+
export type FunctionResource = FunctionResourceDocument | FunctionResourceMediaLibraryAsset | FunctionResourceBase;
|
|
55
|
+
export interface FunctionResourceBase extends Resource {
|
|
44
56
|
src?: string;
|
|
45
57
|
autoResolveDeps?: boolean;
|
|
46
58
|
transpile?: boolean;
|
|
47
59
|
memory?: number;
|
|
48
60
|
timeout?: number;
|
|
49
61
|
env?: Record<string, string>;
|
|
50
|
-
event?:
|
|
62
|
+
event?: GroqRuleBase;
|
|
63
|
+
}
|
|
64
|
+
interface FunctionResourceDocument extends FunctionResourceBase {
|
|
65
|
+
type: 'sanity.function.document';
|
|
66
|
+
event?: GroqRuleDocumentFunction;
|
|
67
|
+
}
|
|
68
|
+
interface FunctionResourceMediaLibraryAsset extends FunctionResourceBase {
|
|
69
|
+
type: 'sanity.function.media-library.asset';
|
|
70
|
+
event: GroqRuleMediaLibraryFunction;
|
|
51
71
|
}
|
|
52
72
|
export interface CorsResource extends Resource {
|
|
53
73
|
origin?: string;
|
|
@@ -102,6 +122,14 @@ export interface InvokeContextOptions {
|
|
|
102
122
|
organizationId?: string;
|
|
103
123
|
token?: string;
|
|
104
124
|
};
|
|
125
|
+
/** The resource type of the event source; resource type that invoked the function. */
|
|
126
|
+
eventResourceType: string;
|
|
127
|
+
/** The resource ID of the event source; resource ID that invoked the function. */
|
|
128
|
+
eventResourceId: string;
|
|
129
|
+
/** The resource type of the function container; resource type that houses the function. */
|
|
130
|
+
functionResourceType: string;
|
|
131
|
+
/** The resource ID of the function container; resource ID that houses the function. */
|
|
132
|
+
functionResourceId: string;
|
|
105
133
|
}
|
|
106
134
|
/** @internal */
|
|
107
135
|
export interface InvokeExecutionOptions {
|
|
@@ -152,3 +180,11 @@ export interface BlueprintParserError {
|
|
|
152
180
|
message: string;
|
|
153
181
|
type: string;
|
|
154
182
|
}
|
|
183
|
+
/** @internal */
|
|
184
|
+
export declare interface FetchConfig {
|
|
185
|
+
mediaLibraryId?: string;
|
|
186
|
+
token?: string;
|
|
187
|
+
apiHost?: string;
|
|
188
|
+
apiVersion?: string;
|
|
189
|
+
}
|
|
190
|
+
export {};
|
package/dist/utils/types.js
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
export function isLocalFunctionResource(r) {
|
|
2
2
|
return r.type.startsWith('sanity.function.');
|
|
3
3
|
}
|
|
4
|
+
// annoyed that checking for equality on `type` isnt sufficient to narrow down to a specific type from a union
|
|
5
|
+
// instead need to use these type predicated
|
|
6
|
+
export function isDocumentFunctionResource(r) {
|
|
7
|
+
return r.type === 'sanity.function.document';
|
|
8
|
+
}
|
|
9
|
+
export function isMediaLibraryAssetFunctionResource(r) {
|
|
10
|
+
return r.type === 'sanity.function.media-library.asset';
|
|
11
|
+
}
|
|
4
12
|
export function isEventType(arg) {
|
|
5
13
|
return ['create', 'update', 'delete'].includes(arg);
|
|
6
14
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BlueprintParserErrorType } from '../types.js';
|
|
1
|
+
import { BlueprintParserErrorType, isDocumentFunctionResource, isMediaLibraryAssetFunctionResource, } 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);
|
|
@@ -44,35 +44,6 @@ export function validateFunctionResource(resource) {
|
|
|
44
44
|
type: BlueprintParserErrorType.InvalidType,
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
|
-
if (resource.event?.includeDrafts && typeof resource.event.includeDrafts !== 'boolean') {
|
|
48
|
-
errors.push({
|
|
49
|
-
message: `${msgPrefix} event.includeDrafts must be a boolean`,
|
|
50
|
-
type: BlueprintParserErrorType.InvalidType,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
if (resource.event?.includeAllVersions &&
|
|
54
|
-
typeof resource.event.includeAllVersions !== 'boolean') {
|
|
55
|
-
errors.push({
|
|
56
|
-
message: `${msgPrefix} event.includeAllVersions must be a boolean`,
|
|
57
|
-
type: BlueprintParserErrorType.InvalidType,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
if (resource.event?.resource) {
|
|
61
|
-
if (!resource.event.resource.type || resource.event.resource.type !== 'dataset') {
|
|
62
|
-
errors.push({
|
|
63
|
-
message: `${msgPrefix} event.resource.type must be "dataset"`,
|
|
64
|
-
type: BlueprintParserErrorType.InvalidType,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
// Ensure exactly one period is passed into the ID to conform to the format <projectId>.<datasetName>
|
|
68
|
-
if (!resource.event.resource.id || resource.event.resource.id.split('.').length !== 2) {
|
|
69
|
-
errors.push({
|
|
70
|
-
message: `${msgPrefix} event.resource.id must be of the form <projectId>.<datasetName>. <datasetName> can be "*" to signify "all datasets in project with ID <projectId>."`,
|
|
71
|
-
type: BlueprintParserErrorType.InvalidFormat,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
// TODO: validate the project ID and dataset names exist by making an API call?
|
|
75
|
-
}
|
|
76
47
|
if (resource.memory !== undefined) {
|
|
77
48
|
if (!Number.isInteger(resource.memory)) {
|
|
78
49
|
errors.push({
|
|
@@ -123,5 +94,59 @@ export function validateFunctionResource(resource) {
|
|
|
123
94
|
}
|
|
124
95
|
}
|
|
125
96
|
}
|
|
97
|
+
if (resource.event && 'resource' in resource.event && resource.event.resource) {
|
|
98
|
+
if (!resource.event.resource.type) {
|
|
99
|
+
errors.push({
|
|
100
|
+
message: `${msgPrefix} event.resource.type must be defined`,
|
|
101
|
+
type: BlueprintParserErrorType.MissingRequiredProperty,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (!resource.event.resource.id) {
|
|
105
|
+
errors.push({
|
|
106
|
+
message: `${msgPrefix} event.resource.id must be defined`,
|
|
107
|
+
type: BlueprintParserErrorType.MissingRequiredProperty,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (isMediaLibraryAssetFunctionResource(resource)) {
|
|
112
|
+
if (resource.event.resource.type !== 'media-library') {
|
|
113
|
+
errors.push({
|
|
114
|
+
message: `${msgPrefix} event.resource.type must be "media-library"`,
|
|
115
|
+
type: BlueprintParserErrorType.InvalidType,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (isDocumentFunctionResource(resource) && resource.event) {
|
|
120
|
+
if (resource.event.includeDrafts && typeof resource.event.includeDrafts !== 'boolean') {
|
|
121
|
+
errors.push({
|
|
122
|
+
message: `${msgPrefix} event.includeDrafts must be a boolean`,
|
|
123
|
+
type: BlueprintParserErrorType.InvalidType,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
if (resource.event.includeAllVersions &&
|
|
127
|
+
typeof resource.event.includeAllVersions !== 'boolean') {
|
|
128
|
+
errors.push({
|
|
129
|
+
message: `${msgPrefix} event.includeAllVersions must be a boolean`,
|
|
130
|
+
type: BlueprintParserErrorType.InvalidType,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (resource.event.resource) {
|
|
134
|
+
if (!resource.event.resource.type || resource.event.resource.type !== 'dataset') {
|
|
135
|
+
errors.push({
|
|
136
|
+
message: `${msgPrefix} event.resource.type must be "dataset"`,
|
|
137
|
+
type: BlueprintParserErrorType.InvalidType,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
// Ensure exactly one period is passed into the ID to conform to the format <projectId>.<datasetName>
|
|
141
|
+
if (!resource.event.resource.id || resource.event.resource.id.split('.').length !== 2) {
|
|
142
|
+
errors.push({
|
|
143
|
+
message: `${msgPrefix} event.resource.id must be of the form <projectId>.<datasetName>. <datasetName> can be "*" to signify "all datasets in project with ID <projectId>."`,
|
|
144
|
+
type: BlueprintParserErrorType.InvalidFormat,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// TODO: validate the project ID and dataset names exist by making an API call?
|
|
148
|
+
// NB: this is done by the functions service
|
|
149
|
+
}
|
|
150
|
+
}
|
|
126
151
|
return errors;
|
|
127
152
|
}
|
package/oclif.manifest.json
CHANGED
|
@@ -69,7 +69,10 @@
|
|
|
69
69
|
"document-create",
|
|
70
70
|
"document-delete",
|
|
71
71
|
"document-update",
|
|
72
|
-
"document-publish"
|
|
72
|
+
"document-publish",
|
|
73
|
+
"media-library-asset-create",
|
|
74
|
+
"media-library-asset-update",
|
|
75
|
+
"media-library-asset-delete"
|
|
73
76
|
],
|
|
74
77
|
"type": "option"
|
|
75
78
|
},
|
|
@@ -778,7 +781,10 @@
|
|
|
778
781
|
"document-create",
|
|
779
782
|
"document-delete",
|
|
780
783
|
"document-update",
|
|
781
|
-
"document-publish"
|
|
784
|
+
"document-publish",
|
|
785
|
+
"media-library-asset-create",
|
|
786
|
+
"media-library-asset-update",
|
|
787
|
+
"media-library-asset-delete"
|
|
782
788
|
],
|
|
783
789
|
"type": "option"
|
|
784
790
|
},
|
|
@@ -1236,6 +1242,21 @@
|
|
|
1236
1242
|
"name": "with-user-token",
|
|
1237
1243
|
"allowNo": false,
|
|
1238
1244
|
"type": "boolean"
|
|
1245
|
+
},
|
|
1246
|
+
"media-library-id": {
|
|
1247
|
+
"aliases": [
|
|
1248
|
+
"media"
|
|
1249
|
+
],
|
|
1250
|
+
"description": "Sanity Media Library ID to use",
|
|
1251
|
+
"exclusive": [
|
|
1252
|
+
"project-id",
|
|
1253
|
+
"dataset"
|
|
1254
|
+
],
|
|
1255
|
+
"name": "media-library-id",
|
|
1256
|
+
"required": false,
|
|
1257
|
+
"hasDynamicHelp": false,
|
|
1258
|
+
"multiple": false,
|
|
1259
|
+
"type": "option"
|
|
1239
1260
|
}
|
|
1240
1261
|
},
|
|
1241
1262
|
"hasDynamicHelp": false,
|
|
@@ -1387,5 +1408,5 @@
|
|
|
1387
1408
|
]
|
|
1388
1409
|
}
|
|
1389
1410
|
},
|
|
1390
|
-
"version": "11.0
|
|
1411
|
+
"version": "11.1.0"
|
|
1391
1412
|
}
|
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": "11.0
|
|
4
|
+
"version": "11.1.0",
|
|
5
5
|
"author": "Sanity Runtime Team",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"copy:wrapper": "shx cp ./src/utils/child-process-wrapper.js ./dist/utils/child-process-wrapper.js",
|
|
66
66
|
"lint": "biome ci",
|
|
67
67
|
"lint:write": "biome check --write",
|
|
68
|
-
"
|
|
68
|
+
"prepare": "npm run build",
|
|
69
69
|
"postpack": "shx rm -f oclif.manifest.json",
|
|
70
70
|
"test": "vitest run && npm run lint",
|
|
71
71
|
"test:depmgmt": "vitest run --config ./test-depmgmt/vitest.config.ts",
|