@sanity/runtime-cli 17.4.0 → 17.6.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 +55 -52
- package/SKILL.md +59 -0
- package/dist/actions/blueprints/blueprint.js +2 -1
- package/dist/actions/blueprints/pre-deploy.d.ts +15 -6
- package/dist/actions/blueprints/pre-deploy.js +29 -70
- package/dist/actions/blueprints/process-assets.d.ts +29 -0
- package/dist/actions/blueprints/process-assets.js +80 -0
- package/dist/actions/blueprints/resources.js +17 -1
- package/dist/commands/blueprints/deploy.js +3 -1
- package/dist/commands/blueprints/destroy.js +1 -1
- package/dist/commands/blueprints/info.d.ts +1 -0
- package/dist/commands/blueprints/info.js +5 -0
- package/dist/commands/blueprints/init.js +1 -2
- package/dist/commands/blueprints/logs.js +1 -0
- package/dist/commands/functions/add.js +3 -3
- package/dist/commands/functions/dev.js +2 -2
- package/dist/commands/functions/logs.d.ts +1 -1
- package/dist/commands/functions/logs.js +3 -0
- package/dist/constants.d.ts +5 -0
- package/dist/constants.js +6 -0
- package/dist/cores/blueprints/deploy.js +71 -19
- package/dist/cores/blueprints/plan.js +2 -0
- package/dist/cores/functions/add.js +11 -8
- package/dist/server/static/components/api-base.js +1 -0
- package/dist/server/static/components/filters.js +4 -2
- package/dist/server/static/components/payload-panel.js +3 -0
- package/dist/utils/blueprints/extract-durable-config.d.ts +8 -0
- package/dist/utils/blueprints/extract-durable-config.js +60 -0
- package/dist/utils/blueprints/validate-resources.js +5 -2
- package/dist/utils/display/blueprints-formatting.js +8 -4
- package/dist/utils/display/resources-formatting.js +2 -2
- package/dist/utils/style-text.js +1 -0
- package/dist/utils/types.d.ts +8 -2
- package/dist/utils/types.js +8 -2
- package/oclif.manifest.json +22 -15
- package/package.json +29 -15
- package/skills/_functions-build.md +23 -0
- package/skills/_functions-list.md +28 -0
- package/skills/blueprints-add.md +8 -0
- package/skills/blueprints-config.md +33 -0
- package/skills/blueprints-deploy.md +36 -0
- package/skills/blueprints-destroy.md +30 -0
- package/skills/blueprints-doctor.md +31 -0
- package/skills/blueprints-info.md +23 -0
- package/skills/blueprints-init.md +48 -0
- package/skills/blueprints-logs.md +33 -0
- package/skills/blueprints-mint-deploy-token.md +25 -0
- package/skills/blueprints-plan.md +28 -0
- package/skills/blueprints-promote.md +31 -0
- package/skills/blueprints-stacks.md +28 -0
- package/skills/functions-add.md +35 -0
- package/skills/functions-dev.md +21 -0
- package/skills/functions-env-add.md +29 -0
- package/skills/functions-env-list.md +21 -0
- package/skills/functions-env-remove.md +22 -0
- package/skills/functions-logs.md +39 -0
- package/skills/functions-test.md +31 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { env } from 'node:process';
|
|
2
|
+
import { stashAsset } from './assets.js';
|
|
3
|
+
const DEFAULT_ASSET_CONCURRENCY = 4;
|
|
4
|
+
const DEFAULT_ASSET_TIMEOUT = 180;
|
|
5
|
+
const assetTimeoutS = Number(env.SANITY_ASSET_TIMEOUT) || DEFAULT_ASSET_TIMEOUT;
|
|
6
|
+
const assetTimeoutMs = assetTimeoutS * 1000;
|
|
7
|
+
const warnTimeoutMs = assetTimeoutMs / 3;
|
|
8
|
+
export async function processAssets(options) {
|
|
9
|
+
const { assetResources, onProgress, onResult } = options;
|
|
10
|
+
const total = assetResources.length;
|
|
11
|
+
const processedAssets = [];
|
|
12
|
+
const concurrency = getAssetConcurrency();
|
|
13
|
+
let completed = 0;
|
|
14
|
+
let slow = false;
|
|
15
|
+
const reportProgress = () => onProgress?.({ completed, total, slow });
|
|
16
|
+
reportProgress();
|
|
17
|
+
const warnTimer = setTimeout(() => {
|
|
18
|
+
slow = true;
|
|
19
|
+
reportProgress();
|
|
20
|
+
}, warnTimeoutMs);
|
|
21
|
+
try {
|
|
22
|
+
for (let start = 0; start < total; start += concurrency) {
|
|
23
|
+
const batch = assetResources.slice(start, start + concurrency);
|
|
24
|
+
const batchResults = await Promise.all(batch.map(async (resource) => {
|
|
25
|
+
const result = await processAsset(resource, options);
|
|
26
|
+
completed += 1;
|
|
27
|
+
reportProgress();
|
|
28
|
+
onResult?.(result);
|
|
29
|
+
return result;
|
|
30
|
+
}));
|
|
31
|
+
processedAssets.push(...batchResults);
|
|
32
|
+
if (batchResults.some((result) => !result.success))
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
clearTimeout(warnTimer);
|
|
38
|
+
}
|
|
39
|
+
return processedAssets;
|
|
40
|
+
}
|
|
41
|
+
function getAssetConcurrency() {
|
|
42
|
+
const configured = Number(env.SANITY_ASSET_CONCURRENCY);
|
|
43
|
+
return Number.isSafeInteger(configured) && configured > 0 ? configured : DEFAULT_ASSET_CONCURRENCY;
|
|
44
|
+
}
|
|
45
|
+
async function processAsset(resource, options) {
|
|
46
|
+
const { auth, blueprintFileDir, installer, logger } = options;
|
|
47
|
+
let assetTimeoutTimer;
|
|
48
|
+
let result;
|
|
49
|
+
try {
|
|
50
|
+
result = await Promise.race([
|
|
51
|
+
stashAsset({ resource, blueprintFileDir, auth, logger, installer }),
|
|
52
|
+
new Promise((_, reject) => {
|
|
53
|
+
assetTimeoutTimer = setTimeout(() => {
|
|
54
|
+
reject(new Error(`Processing ${resource.name} timed out after ${assetTimeoutS}s`));
|
|
55
|
+
}, assetTimeoutMs);
|
|
56
|
+
}),
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
61
|
+
return { success: false, resource, error: msg, failureKind: 'processing' };
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
clearTimeout(assetTimeoutTimer);
|
|
65
|
+
}
|
|
66
|
+
if (result.success && result.assetId) {
|
|
67
|
+
return {
|
|
68
|
+
success: true,
|
|
69
|
+
resource: { ...resource, src: result.assetId },
|
|
70
|
+
hash: result.hash,
|
|
71
|
+
exists: result.exists,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
success: false,
|
|
76
|
+
resource,
|
|
77
|
+
error: result.error || 'Failed to process asset',
|
|
78
|
+
failureKind: 'upload',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -2,7 +2,7 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import { cwd } from 'node:process';
|
|
5
|
-
import { MAP_EVENT_TO_FUNCTION_TYPE, SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_SCHEDULED, SANITY_FUNCTION_SYNC_TAG_INVALIDATE, } from '../../constants.js';
|
|
5
|
+
import { MAP_EVENT_TO_FUNCTION_TYPE, SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_PUBSUB, SANITY_FUNCTION_SCHEDULED, SANITY_FUNCTION_SYNC_TAG_INVALIDATE, } from '../../constants.js';
|
|
6
6
|
import { styleText } from '../../utils/style-text.js';
|
|
7
7
|
import { writeOrUpdateNodeDependency } from '../node.js';
|
|
8
8
|
import { addResourceToBlueprint } from './blueprint.js';
|
|
@@ -36,6 +36,12 @@ export const handler = syncTagInvalidateEventHandler(async ({ context, event, do
|
|
|
36
36
|
console.error('Error invoking Sanity invalidation done endpoint!', e)
|
|
37
37
|
}
|
|
38
38
|
})`;
|
|
39
|
+
const DEFAULT_PUBSUB_HELPER_FUNCTION_TEMPLATE = /*ts*/ `import { pubSubEventHandler } from '@sanity/functions'
|
|
40
|
+
|
|
41
|
+
export const handler = pubSubEventHandler(async ({ context, event }) => {
|
|
42
|
+
const time = new Date().toLocaleTimeString()
|
|
43
|
+
console.log(\`Your pubsub Sanity Function was called at \${time}\`)
|
|
44
|
+
})`;
|
|
39
45
|
/**
|
|
40
46
|
* Creates a new function resource file and adds it to the blueprint
|
|
41
47
|
*/
|
|
@@ -68,6 +74,9 @@ export async function createFunctionResource(options, logger) {
|
|
|
68
74
|
let template = DEFAULT_FUNCTION_TEMPLATE;
|
|
69
75
|
if (addHelpers) {
|
|
70
76
|
switch (functionType) {
|
|
77
|
+
case SANITY_FUNCTION_PUBSUB:
|
|
78
|
+
template = DEFAULT_PUBSUB_HELPER_FUNCTION_TEMPLATE;
|
|
79
|
+
break;
|
|
71
80
|
case SANITY_FUNCTION_SCHEDULED:
|
|
72
81
|
template = DEFAULT_SCHEDULED_HELPER_FUNCTION_TEMPLATE;
|
|
73
82
|
break;
|
|
@@ -119,6 +128,13 @@ export async function createFunctionResource(options, logger) {
|
|
|
119
128
|
},
|
|
120
129
|
};
|
|
121
130
|
break;
|
|
131
|
+
case SANITY_FUNCTION_PUBSUB:
|
|
132
|
+
resourceJson = {
|
|
133
|
+
name,
|
|
134
|
+
src: `functions/${name}`,
|
|
135
|
+
type: SANITY_FUNCTION_PUBSUB,
|
|
136
|
+
};
|
|
137
|
+
break;
|
|
122
138
|
case SANITY_FUNCTION_SCHEDULED:
|
|
123
139
|
resourceJson = {
|
|
124
140
|
name,
|
|
@@ -14,7 +14,9 @@ Use --no-wait to queue the deployment and return immediately without waiting for
|
|
|
14
14
|
|
|
15
15
|
Use --fn-installer to force which package manager to use when deploying functions.
|
|
16
16
|
|
|
17
|
-
Set SANITY_ASSET_TIMEOUT (seconds) to override the
|
|
17
|
+
Set SANITY_ASSET_TIMEOUT (seconds) to override the 180-second timeout for processing resource assets.
|
|
18
|
+
|
|
19
|
+
Set SANITY_ASSET_CONCURRENCY to override how many resource assets are processed at once (default 4).
|
|
18
20
|
|
|
19
21
|
Exit codes: 0 deployed, 2 deployment failed, 75 deployment accepted but completion could not be confirmed (rerun 'blueprints info' to check).`;
|
|
20
22
|
static examples = [
|
|
@@ -19,7 +19,7 @@ Exit codes: 0 destroyed, 2 destruction failed, 75 destruction accepted but compl
|
|
|
19
19
|
static flags = {
|
|
20
20
|
force: Flags.boolean({
|
|
21
21
|
description: 'Force Stack destruction (skip confirmation)',
|
|
22
|
-
|
|
22
|
+
char: 'f',
|
|
23
23
|
default: false,
|
|
24
24
|
}),
|
|
25
25
|
'project-id': Flags.string({
|
|
@@ -8,6 +8,7 @@ export default class InfoCommand extends ResolvedCommand<typeof InfoCommand> {
|
|
|
8
8
|
stack: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
9
|
'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
'organization-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
12
|
};
|
|
12
13
|
run(): Promise<Record<string, unknown> | undefined>;
|
|
13
14
|
}
|
|
@@ -23,6 +23,11 @@ Run 'blueprints stacks' to see all available Stacks in your project or organizat
|
|
|
23
23
|
}),
|
|
24
24
|
'project-id': Flags.string({ ...projectIdFlagConfig }),
|
|
25
25
|
'organization-id': Flags.string({ ...organizationIdFlagConfig }),
|
|
26
|
+
verbose: Flags.boolean({
|
|
27
|
+
char: 'v',
|
|
28
|
+
description: 'Show resource and external IDs',
|
|
29
|
+
default: false,
|
|
30
|
+
}),
|
|
26
31
|
};
|
|
27
32
|
async run() {
|
|
28
33
|
const result = await blueprintInfoCore({
|
|
@@ -6,10 +6,9 @@ import { validTokenOrErrorMessage } from '../../utils/validated-token.js';
|
|
|
6
6
|
export default class InitCommand extends RuntimeCommand {
|
|
7
7
|
static summary = 'Initialize a Blueprint and create a remote Stack';
|
|
8
8
|
static description = `A Blueprint is your local infrastructure-as-code configuration that defines Sanity resources (datasets, functions, etc.). A Stack is the remote deployment target where your Blueprint is applied.
|
|
9
|
-
[NOTE: Currently, accounts are limited to three (3) Stacks per project scope.]
|
|
10
9
|
|
|
11
10
|
This is typically the first command you run in a new project. It creates a local Blueprint manifest file (sanity.blueprint.ts, .js, or .json) and provisions a new remote Stack.
|
|
12
|
-
Additionally, a Blueprint configuration file is created in .sanity/ containing the scope and Stack IDs.
|
|
11
|
+
Additionally, a Blueprint configuration file is created in .sanity/ containing the scope and Stack IDs. A .gitignore covering node_modules, .env, and Function build output is created or updated; the .sanity/ config itself is not ignored.
|
|
13
12
|
|
|
14
13
|
After initialization, use 'blueprints plan' to preview changes, then 'blueprints deploy' to apply them.
|
|
15
14
|
|
|
@@ -23,7 +23,7 @@ After adding, use 'functions dev' to test locally, then 'blueprints deploy' to p
|
|
|
23
23
|
example: Flags.string({
|
|
24
24
|
description: 'Example to use for the Function',
|
|
25
25
|
aliases: ['recipe'],
|
|
26
|
-
exclusive: ['name', '
|
|
26
|
+
exclusive: ['name', 'type', 'language', 'javascript', 'helpers', 'installer', 'install'],
|
|
27
27
|
}),
|
|
28
28
|
name: Flags.string({
|
|
29
29
|
description: 'Name of the Function to add',
|
|
@@ -56,9 +56,9 @@ After adding, use 'functions dev' to test locally, then 'blueprints deploy' to p
|
|
|
56
56
|
options: ['skip', ...INSTALLER_OPTIONS],
|
|
57
57
|
}),
|
|
58
58
|
install: Flags.boolean({
|
|
59
|
-
description: 'Shortcut for --
|
|
59
|
+
description: 'Shortcut for --installer npm',
|
|
60
60
|
char: 'i',
|
|
61
|
-
exclusive: ['
|
|
61
|
+
exclusive: ['installer'],
|
|
62
62
|
}),
|
|
63
63
|
};
|
|
64
64
|
async run() {
|
|
@@ -9,11 +9,11 @@ export default class DevCommand extends ResolvedCommand {
|
|
|
9
9
|
|
|
10
10
|
Open the emulator in your browser to interactively test your functions with the payload editor.
|
|
11
11
|
|
|
12
|
-
Optionally, set the host and port with the --host and --port flags. Function timeout can be configured with the --timeout flag.
|
|
12
|
+
Optionally, set the host and port with the --host and --port flags. Port 8974 is reserved for the emulator's live-reload WebSocket server. Function timeout can be configured with the --timeout flag.
|
|
13
13
|
|
|
14
14
|
To invoke a function with the CLI, use 'functions test'.`;
|
|
15
15
|
static examples = [
|
|
16
|
-
'<%= config.bin %> <%= command.id %> --host 127.0.0.1 --port
|
|
16
|
+
'<%= config.bin %> <%= command.id %> --host 127.0.0.1 --port 3333',
|
|
17
17
|
'<%= config.bin %> <%= command.id %> --timeout 60',
|
|
18
18
|
];
|
|
19
19
|
static flags = {
|
|
@@ -15,5 +15,5 @@ export default class LogsCommand extends ResolvedCommand<typeof LogsCommand> {
|
|
|
15
15
|
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
16
|
watch: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
17
17
|
};
|
|
18
|
-
run(): Promise<Record<string, unknown
|
|
18
|
+
run(): Promise<void | Record<string, unknown>>;
|
|
19
19
|
}
|
|
@@ -46,6 +46,7 @@ Use --watch (-w) to stream logs in real-time. Use --delete to clear all logs for
|
|
|
46
46
|
char: 'w',
|
|
47
47
|
description: 'Watch for new logs (streaming mode)',
|
|
48
48
|
aliases: ['follow'],
|
|
49
|
+
exclusive: ['json'],
|
|
49
50
|
}),
|
|
50
51
|
};
|
|
51
52
|
async run() {
|
|
@@ -67,6 +68,8 @@ Use --watch (-w) to stream logs in real-time. Use --delete to clear all logs for
|
|
|
67
68
|
});
|
|
68
69
|
if (!result.success)
|
|
69
70
|
this.coreError(result);
|
|
71
|
+
if (result.streaming)
|
|
72
|
+
return result.streaming;
|
|
70
73
|
return result.json;
|
|
71
74
|
}
|
|
72
75
|
}
|
package/dist/constants.d.ts
CHANGED
|
@@ -3,8 +3,10 @@ export declare const SANITY_ACCESS_ROBOT = "sanity.access.robot";
|
|
|
3
3
|
export declare const SANITY_FUNCTION_PREFIX = "sanity.function.";
|
|
4
4
|
export declare const SANITY_FUNCTION_DOCUMENT = "sanity.function.document";
|
|
5
5
|
export declare const SANITY_FUNCTION_MEDIA_LIBRARY_ASSET = "sanity.function.media-library.asset";
|
|
6
|
+
export declare const SANITY_FUNCTION_PUBSUB = "sanity.function.pubsub";
|
|
6
7
|
export declare const SANITY_FUNCTION_SCHEDULED = "sanity.function.cron";
|
|
7
8
|
export declare const SANITY_FUNCTION_SYNC_TAG_INVALIDATE = "sanity.function.sync-tag-invalidate";
|
|
9
|
+
export declare const SANITY_FUNCTION_DURABLE = "sanity.function.durable";
|
|
8
10
|
export declare const SANITY_PROJECT = "sanity.project";
|
|
9
11
|
export declare const SANITY_PROJECT_CORS = "sanity.project.cors";
|
|
10
12
|
export declare const SANITY_PROJECT_DATASET = "sanity.project.dataset";
|
|
@@ -17,6 +19,7 @@ export declare const EVENT_DOCUMENT_DELETE = "document-delete";
|
|
|
17
19
|
export declare const EVENT_MEDIA_LIBRARY_ASSET_CREATE = "media-library-asset-create";
|
|
18
20
|
export declare const EVENT_MEDIA_LIBRARY_ASSET_UPDATE = "media-library-asset-update";
|
|
19
21
|
export declare const EVENT_MEDIA_LIBRARY_ASSET_DELETE = "media-library-asset-delete";
|
|
22
|
+
export declare const EVENT_PUBSUB = "pub-sub";
|
|
20
23
|
export declare const EVENT_SCHEDULED = "scheduled-function";
|
|
21
24
|
export declare const EVENT_SYNC_TAG_INVALIDATE = "sync-tag-invalidate";
|
|
22
25
|
export declare const MAP_EVENT_TO_FUNCTION_TYPE: {
|
|
@@ -27,6 +30,7 @@ export declare const MAP_EVENT_TO_FUNCTION_TYPE: {
|
|
|
27
30
|
readonly "media-library-asset-create": "sanity.function.media-library.asset";
|
|
28
31
|
readonly "media-library-asset-delete": "sanity.function.media-library.asset";
|
|
29
32
|
readonly "media-library-asset-update": "sanity.function.media-library.asset";
|
|
33
|
+
readonly "pub-sub": "sanity.function.pubsub";
|
|
30
34
|
readonly "scheduled-function": "sanity.function.cron";
|
|
31
35
|
readonly "sync-tag-invalidate": "sanity.function.sync-tag-invalidate";
|
|
32
36
|
};
|
|
@@ -42,6 +46,7 @@ export declare const LABEL_DOCUMENT_DELETE = "Document Delete";
|
|
|
42
46
|
export declare const LABEL_MEDIA_LIBRARY_ASSET_CREATE = "Media Library Asset Create";
|
|
43
47
|
export declare const LABEL_MEDIA_LIBRARY_ASSET_UPDATE = "Media Library Asset Update";
|
|
44
48
|
export declare const LABEL_MEDIA_LIBRARY_ASSET_DELETE = "Media Library Asset Delete";
|
|
49
|
+
export declare const LABEL_PUBSUB = "PubSub";
|
|
45
50
|
export declare const LABEL_SCHEDULED = "Scheduled";
|
|
46
51
|
export declare const LABEL_SYNC_TAG_INVALIDATE = "Sync Tag Invalidate";
|
|
47
52
|
export declare const CI_SETUP_DOCS_URL = "https://www.sanity.io/docs/blueprints/deploy-blueprints-from-ci";
|
package/dist/constants.js
CHANGED
|
@@ -3,8 +3,10 @@ export const SANITY_ACCESS_ROBOT = 'sanity.access.robot';
|
|
|
3
3
|
export const SANITY_FUNCTION_PREFIX = 'sanity.function.';
|
|
4
4
|
export const SANITY_FUNCTION_DOCUMENT = 'sanity.function.document';
|
|
5
5
|
export const SANITY_FUNCTION_MEDIA_LIBRARY_ASSET = 'sanity.function.media-library.asset';
|
|
6
|
+
export const SANITY_FUNCTION_PUBSUB = 'sanity.function.pubsub';
|
|
6
7
|
export const SANITY_FUNCTION_SCHEDULED = 'sanity.function.cron';
|
|
7
8
|
export const SANITY_FUNCTION_SYNC_TAG_INVALIDATE = 'sanity.function.sync-tag-invalidate';
|
|
9
|
+
export const SANITY_FUNCTION_DURABLE = 'sanity.function.durable';
|
|
8
10
|
export const SANITY_PROJECT = 'sanity.project';
|
|
9
11
|
export const SANITY_PROJECT_CORS = 'sanity.project.cors';
|
|
10
12
|
export const SANITY_PROJECT_DATASET = 'sanity.project.dataset';
|
|
@@ -17,6 +19,7 @@ export const EVENT_DOCUMENT_DELETE = 'document-delete';
|
|
|
17
19
|
export const EVENT_MEDIA_LIBRARY_ASSET_CREATE = 'media-library-asset-create';
|
|
18
20
|
export const EVENT_MEDIA_LIBRARY_ASSET_UPDATE = 'media-library-asset-update';
|
|
19
21
|
export const EVENT_MEDIA_LIBRARY_ASSET_DELETE = 'media-library-asset-delete';
|
|
22
|
+
export const EVENT_PUBSUB = 'pub-sub';
|
|
20
23
|
export const EVENT_SCHEDULED = 'scheduled-function';
|
|
21
24
|
export const EVENT_SYNC_TAG_INVALIDATE = 'sync-tag-invalidate';
|
|
22
25
|
export const MAP_EVENT_TO_FUNCTION_TYPE = {
|
|
@@ -27,6 +30,7 @@ export const MAP_EVENT_TO_FUNCTION_TYPE = {
|
|
|
27
30
|
[EVENT_MEDIA_LIBRARY_ASSET_CREATE]: SANITY_FUNCTION_MEDIA_LIBRARY_ASSET,
|
|
28
31
|
[EVENT_MEDIA_LIBRARY_ASSET_DELETE]: SANITY_FUNCTION_MEDIA_LIBRARY_ASSET,
|
|
29
32
|
[EVENT_MEDIA_LIBRARY_ASSET_UPDATE]: SANITY_FUNCTION_MEDIA_LIBRARY_ASSET,
|
|
33
|
+
[EVENT_PUBSUB]: SANITY_FUNCTION_PUBSUB,
|
|
30
34
|
[EVENT_SCHEDULED]: SANITY_FUNCTION_SCHEDULED,
|
|
31
35
|
[EVENT_SYNC_TAG_INVALIDATE]: SANITY_FUNCTION_SYNC_TAG_INVALIDATE,
|
|
32
36
|
};
|
|
@@ -35,6 +39,7 @@ export const PROJECT_SCOPED_FUNCTION_TYPES = new Set([
|
|
|
35
39
|
SANITY_FUNCTION_DOCUMENT,
|
|
36
40
|
SANITY_FUNCTION_MEDIA_LIBRARY_ASSET,
|
|
37
41
|
SANITY_FUNCTION_SYNC_TAG_INVALIDATE,
|
|
42
|
+
SANITY_FUNCTION_DURABLE,
|
|
38
43
|
]);
|
|
39
44
|
export const ORGANIZATION_SCOPED_FUNCTION_TYPES = new Set([
|
|
40
45
|
SANITY_FUNCTION_SCHEDULED,
|
|
@@ -47,6 +52,7 @@ export const LABEL_DOCUMENT_DELETE = 'Document Delete';
|
|
|
47
52
|
export const LABEL_MEDIA_LIBRARY_ASSET_CREATE = 'Media Library Asset Create';
|
|
48
53
|
export const LABEL_MEDIA_LIBRARY_ASSET_UPDATE = 'Media Library Asset Update';
|
|
49
54
|
export const LABEL_MEDIA_LIBRARY_ASSET_DELETE = 'Media Library Asset Delete';
|
|
55
|
+
export const LABEL_PUBSUB = 'PubSub';
|
|
50
56
|
export const LABEL_SCHEDULED = 'Scheduled';
|
|
51
57
|
export const LABEL_SYNC_TAG_INVALIDATE = 'Sync Tag Invalidate';
|
|
52
58
|
export const CI_SETUP_DOCS_URL = 'https://www.sanity.io/docs/blueprints/deploy-blueprints-from-ci';
|
|
@@ -3,22 +3,23 @@ import { preDeploy } from '../../actions/blueprints/pre-deploy.js';
|
|
|
3
3
|
import { getStack, updateStack } from '../../actions/blueprints/stacks.js';
|
|
4
4
|
import { waitForOperation } from '../../actions/blueprints/wait-for-operation.js';
|
|
5
5
|
import { checkUserPermission } from '../../actions/sanity/access.js';
|
|
6
|
+
import { extractDurableConfig } from '../../utils/blueprints/extract-durable-config.js';
|
|
6
7
|
import { createHintCollector } from '../../utils/blueprints/hints.js';
|
|
7
|
-
import { niceId } from '../../utils/display/presenters.js';
|
|
8
|
+
import { check, niceId, severe } from '../../utils/display/presenters.js';
|
|
8
9
|
import { CODE_OPERATION_UNCONFIRMED, EXIT_OPERATION_UNCONFIRMED } from '../../utils/exit-codes.js';
|
|
9
10
|
import { styleText } from '../../utils/style-text.js';
|
|
10
11
|
import { getWarnings } from '../../utils/warnings.js';
|
|
11
12
|
export async function blueprintDeployCore(options) {
|
|
12
|
-
const { bin = 'sanity', log, auth, stackId, scopeType, scopeId, deployedStack, blueprint, flags, } = options;
|
|
13
|
+
const { bin = 'sanity', log: logger, auth, stackId, scopeType, scopeId, deployedStack, blueprint, flags, } = options;
|
|
13
14
|
const { verbose } = flags;
|
|
14
15
|
const noWait = flags['no-wait'] || false;
|
|
15
16
|
const stackName = flags['new-stack-name'] ?? deployedStack.name;
|
|
16
17
|
const installer = flags['fn-installer'] || undefined;
|
|
17
18
|
const blueprintFileDir = dirname(blueprint.fileInfo.blueprintFilePath);
|
|
18
19
|
const workspaceWarnings = getWarnings({ dir: blueprintFileDir });
|
|
19
|
-
|
|
20
|
+
logger(`Deploying "${stackName}" ${niceId(deployedStack.id)}...`);
|
|
20
21
|
try {
|
|
21
|
-
const { ok: checkOk, stack: currentStack } = await getStack({ stackId, auth, logger
|
|
22
|
+
const { ok: checkOk, stack: currentStack } = await getStack({ stackId, auth, logger });
|
|
22
23
|
if (!checkOk) {
|
|
23
24
|
return { success: false, error: 'Failed to check current Stack status' };
|
|
24
25
|
}
|
|
@@ -34,23 +35,24 @@ export async function blueprintDeployCore(options) {
|
|
|
34
35
|
};
|
|
35
36
|
}
|
|
36
37
|
const resources = [...blueprint.resources];
|
|
38
|
+
await extractDurableConfig(resources, blueprintFileDir);
|
|
37
39
|
const preDeployResult = await preDeploy({
|
|
38
40
|
scopeType,
|
|
39
41
|
scopeId,
|
|
40
|
-
resources,
|
|
42
|
+
resources, // mutated by preDeploy
|
|
41
43
|
stackId,
|
|
42
44
|
stackName,
|
|
43
45
|
auth,
|
|
44
46
|
blueprintFileDir,
|
|
45
47
|
installer,
|
|
46
|
-
|
|
48
|
+
logger,
|
|
47
49
|
bin,
|
|
48
50
|
verbose,
|
|
51
|
+
onAssetEvent: createAssetEventHandler(logger),
|
|
49
52
|
});
|
|
50
|
-
if (!preDeployResult?.success)
|
|
53
|
+
if (!preDeployResult?.success)
|
|
51
54
|
return preDeployResult;
|
|
52
|
-
|
|
53
|
-
const spinner = log.ora('Deploying...').start();
|
|
55
|
+
const deploySpinner = logger.ora('Deploying...').start();
|
|
54
56
|
const { ok: deployOk, stack, error: deployError, } = await updateStack({
|
|
55
57
|
stackId,
|
|
56
58
|
stackMutation: {
|
|
@@ -61,10 +63,10 @@ export async function blueprintDeployCore(options) {
|
|
|
61
63
|
userMessage: flags.message,
|
|
62
64
|
},
|
|
63
65
|
auth,
|
|
64
|
-
logger
|
|
66
|
+
logger,
|
|
65
67
|
});
|
|
66
68
|
if (!deployOk) {
|
|
67
|
-
|
|
69
|
+
deploySpinner.fail(`${styleText('red', 'Failed')} to update Stack deployment`);
|
|
68
70
|
const hints = createHintCollector(bin);
|
|
69
71
|
if (deployError) {
|
|
70
72
|
hints.inspectMessage(deployError);
|
|
@@ -79,18 +81,18 @@ export async function blueprintDeployCore(options) {
|
|
|
79
81
|
],
|
|
80
82
|
};
|
|
81
83
|
}
|
|
82
|
-
|
|
84
|
+
deploySpinner.stop().clear();
|
|
83
85
|
const legacyPermissionsNoticePromise = CHECK_LEGACY_DEPLOY_PERMISSION
|
|
84
86
|
? checkLegacyDeployPermission({
|
|
85
87
|
auth,
|
|
86
88
|
scopeType,
|
|
87
89
|
scopeId,
|
|
88
|
-
log,
|
|
90
|
+
log: logger,
|
|
89
91
|
})
|
|
90
92
|
: Promise.resolve(null);
|
|
91
93
|
if (noWait) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
+
logger(styleText(['bold', 'green'], 'Stack deployment started!'));
|
|
95
|
+
logger(`Use \`npx ${bin} blueprints info\` to check status`);
|
|
94
96
|
const legacyWarning = await legacyPermissionsNoticePromise;
|
|
95
97
|
const warnings = [...(legacyWarning ? [legacyWarning] : []), ...workspaceWarnings];
|
|
96
98
|
return {
|
|
@@ -100,19 +102,19 @@ export async function blueprintDeployCore(options) {
|
|
|
100
102
|
warnings: warnings.length ? warnings : undefined,
|
|
101
103
|
};
|
|
102
104
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
logger(styleText('dim', 'Stack deployment progress:'));
|
|
106
|
+
logger('');
|
|
105
107
|
const outcome = await waitForOperation({
|
|
106
108
|
stackId,
|
|
107
109
|
operationId: stack.operationId,
|
|
108
110
|
auth,
|
|
109
|
-
log,
|
|
111
|
+
log: logger,
|
|
110
112
|
bin,
|
|
111
113
|
verbose,
|
|
112
114
|
progressNoun: 'deployment',
|
|
113
115
|
});
|
|
114
116
|
if (outcome.type === 'completed') {
|
|
115
|
-
|
|
117
|
+
logger(styleText(['bold', 'green'], 'Stack deployment completed!'));
|
|
116
118
|
const legacyWarning = await legacyPermissionsNoticePromise;
|
|
117
119
|
const warnings = [...(legacyWarning ? [legacyWarning] : []), ...workspaceWarnings];
|
|
118
120
|
return {
|
|
@@ -151,6 +153,56 @@ export async function blueprintDeployCore(options) {
|
|
|
151
153
|
return { success: false, error: errorMessage };
|
|
152
154
|
}
|
|
153
155
|
}
|
|
156
|
+
function createAssetEventHandler(logger) {
|
|
157
|
+
let spinner;
|
|
158
|
+
const results = [];
|
|
159
|
+
return (event) => {
|
|
160
|
+
switch (event.type) {
|
|
161
|
+
case 'progress': {
|
|
162
|
+
const { completed, total, slow } = event.progress;
|
|
163
|
+
const text = [
|
|
164
|
+
`Processing assets (${completed}/${total})`,
|
|
165
|
+
slow ? ', this can take a moment' : '',
|
|
166
|
+
].join('');
|
|
167
|
+
if (spinner)
|
|
168
|
+
spinner.text = text;
|
|
169
|
+
else
|
|
170
|
+
spinner = logger.ora(text).start();
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
case 'result': {
|
|
174
|
+
results.push(event.result);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
case 'complete': {
|
|
178
|
+
spinner?.stop();
|
|
179
|
+
spinner = undefined;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// done. print report
|
|
184
|
+
for (const result of results) {
|
|
185
|
+
const { resource } = result;
|
|
186
|
+
if (!result.success) {
|
|
187
|
+
const summary = result.failureKind === 'upload'
|
|
188
|
+
? `Failed uploading ${resource.name} asset`
|
|
189
|
+
: `Failed processing ${resource.name} asset`;
|
|
190
|
+
logger(` ${severe(summary)}`);
|
|
191
|
+
logger.error(` ${result.error}`);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
logger(` ${check(`${resource.name} ${niceId(resource.src)}`)}`);
|
|
195
|
+
logger(` Source: ${resource.src}`);
|
|
196
|
+
if (result.hash) {
|
|
197
|
+
const hash = result.hash;
|
|
198
|
+
const h = hash.length > 24 ? `${hash.slice(0, 8)}...${hash.slice(-12)}` : hash;
|
|
199
|
+
logger.verbose(` Hash: ${h}`);
|
|
200
|
+
}
|
|
201
|
+
if (result.exists)
|
|
202
|
+
logger.verbose(' Asset unchanged');
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
154
206
|
const CHECK_LEGACY_DEPLOY_PERMISSION = false;
|
|
155
207
|
const BLUEPRINTS_PERMISSION_ENFORCEMENT_DATE = 'July 1, 2026';
|
|
156
208
|
async function checkLegacyDeployPermission({ auth, scopeType, scopeId, log, }) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { dirname } from 'node:path';
|
|
2
2
|
import { planStack, resolveStackIdByNameOrId } from '../../actions/blueprints/stacks.js';
|
|
3
|
+
import { extractDurableConfig } from '../../utils/blueprints/extract-durable-config.js';
|
|
3
4
|
import { createHintCollector } from '../../utils/blueprints/hints.js';
|
|
4
5
|
import { formatDeploymentPlan, formatResourceTree, hasActionableChanges, } from '../../utils/display/blueprints-formatting.js';
|
|
5
6
|
import { styleText } from '../../utils/style-text.js';
|
|
@@ -9,6 +10,7 @@ export async function blueprintPlanCore(options) {
|
|
|
9
10
|
const { verbose: _verbose = false } = flags;
|
|
10
11
|
const { scopeType, scopeId, stackId: blueprintStackId, parsedBlueprint, resources, fileInfo, } = blueprint;
|
|
11
12
|
log(`${styleText(['bold', 'blueBright'], 'Local Blueprint')} ${styleText('dim', `(${fileInfo.fileName})`)}`);
|
|
13
|
+
await extractDurableConfig(resources, dirname(fileInfo.blueprintFilePath));
|
|
12
14
|
log(formatResourceTree(resources));
|
|
13
15
|
if (!token || !scopeType || !scopeId) {
|
|
14
16
|
log(styleText('dim', 'Unable to retrieve live Stack deployment for comparison'));
|
|
@@ -5,7 +5,7 @@ import { checkbox, confirm, input, select } from '@inquirer/prompts';
|
|
|
5
5
|
import { highlight } from 'cardinal';
|
|
6
6
|
import { createFunctionResource } from '../../actions/blueprints/resources.js';
|
|
7
7
|
import { verifyExampleExists, writeExample } from '../../actions/sanity/examples.js';
|
|
8
|
-
import { EVENT_DOCUMENT_CREATE, EVENT_DOCUMENT_DELETE, EVENT_DOCUMENT_UPDATE, EVENT_MEDIA_LIBRARY_ASSET_CREATE, EVENT_MEDIA_LIBRARY_ASSET_DELETE, EVENT_MEDIA_LIBRARY_ASSET_UPDATE, EVENT_SCHEDULED, EVENT_SYNC_TAG_INVALIDATE, FUNCTION_TYPES, LABEL_DOCUMENT_CREATE, LABEL_DOCUMENT_DELETE, LABEL_DOCUMENT_UPDATE, LABEL_MEDIA_LIBRARY_ASSET_CREATE, LABEL_MEDIA_LIBRARY_ASSET_DELETE, LABEL_MEDIA_LIBRARY_ASSET_UPDATE, LABEL_SCHEDULED, LABEL_SYNC_TAG_INVALIDATE, MAP_EVENT_TO_FUNCTION_TYPE, SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_SCHEDULED, SANITY_FUNCTION_SYNC_TAG_INVALIDATE, } from '../../constants.js';
|
|
8
|
+
import { EVENT_DOCUMENT_CREATE, EVENT_DOCUMENT_DELETE, EVENT_DOCUMENT_UPDATE, EVENT_MEDIA_LIBRARY_ASSET_CREATE, EVENT_MEDIA_LIBRARY_ASSET_DELETE, EVENT_MEDIA_LIBRARY_ASSET_UPDATE, EVENT_PUBSUB, EVENT_SCHEDULED, EVENT_SYNC_TAG_INVALIDATE, FUNCTION_TYPES, LABEL_DOCUMENT_CREATE, LABEL_DOCUMENT_DELETE, LABEL_DOCUMENT_UPDATE, LABEL_MEDIA_LIBRARY_ASSET_CREATE, LABEL_MEDIA_LIBRARY_ASSET_DELETE, LABEL_MEDIA_LIBRARY_ASSET_UPDATE, LABEL_PUBSUB, LABEL_SCHEDULED, LABEL_SYNC_TAG_INVALIDATE, MAP_EVENT_TO_FUNCTION_TYPE, SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_PUBSUB, SANITY_FUNCTION_SCHEDULED, SANITY_FUNCTION_SYNC_TAG_INVALIDATE, } from '../../constants.js';
|
|
9
9
|
import { check, indent, warn } from '../../utils/display/presenters.js';
|
|
10
10
|
import { validateFunctionName } from '../../utils/functions/validate-name.js';
|
|
11
11
|
import { styleText } from '../../utils/style-text.js';
|
|
@@ -21,6 +21,9 @@ export const generateFunctionBlueprintResourceTemplate = (fnName, eventNames) =>
|
|
|
21
21
|
case SANITY_FUNCTION_MEDIA_LIBRARY_ASSET:
|
|
22
22
|
definer = `defineMediaLibraryAssetFunction({name: '${fnName}', event: {on: [${eventOns.join(', ')}], resource: {type: 'media-library', id: 'my-media-library-id'}}}), // ← add this line`;
|
|
23
23
|
break;
|
|
24
|
+
case SANITY_FUNCTION_PUBSUB:
|
|
25
|
+
definer = `definePubSubFunction({name: '${fnName}'}), // ← add this line`;
|
|
26
|
+
break;
|
|
24
27
|
case SANITY_FUNCTION_SCHEDULED:
|
|
25
28
|
definer = `defineScheduledFunction({name: '${fnName}', event: {expression: '0 0 * * *'}}), // ← add this line`;
|
|
26
29
|
break;
|
|
@@ -158,7 +161,7 @@ export async function functionAddCore(options) {
|
|
|
158
161
|
}
|
|
159
162
|
const eventSources = new Set(fnTypes.map((t) => t.substring(0, t.lastIndexOf('-'))));
|
|
160
163
|
if (eventSources.size > 1) {
|
|
161
|
-
throw new Error('Invalid function type. Cannot mix document-*, media-library-asset-*, sync-tag-* and/or scheduled-* types.');
|
|
164
|
+
throw new Error('Invalid function type. Cannot mix document-*, media-library-asset-*, pub-sub, sync-tag-* and/or scheduled-* types.');
|
|
162
165
|
}
|
|
163
166
|
let addHelpers;
|
|
164
167
|
let installCommand;
|
|
@@ -224,7 +227,7 @@ async function promptForFunctionName() {
|
|
|
224
227
|
const functionName = await input({
|
|
225
228
|
message: 'Enter function name:',
|
|
226
229
|
validate: (input) => validateFunctionName(input) ||
|
|
227
|
-
'Invalid function name. Must be
|
|
230
|
+
'Invalid function name. Must be 3+ characters, no special characters, no spaces',
|
|
228
231
|
});
|
|
229
232
|
return functionName;
|
|
230
233
|
}
|
|
@@ -242,6 +245,7 @@ async function promptForFunctionType() {
|
|
|
242
245
|
{ name: LABEL_MEDIA_LIBRARY_ASSET_CREATE, value: EVENT_MEDIA_LIBRARY_ASSET_CREATE },
|
|
243
246
|
{ name: LABEL_MEDIA_LIBRARY_ASSET_UPDATE, value: EVENT_MEDIA_LIBRARY_ASSET_UPDATE },
|
|
244
247
|
{ name: LABEL_MEDIA_LIBRARY_ASSET_DELETE, value: EVENT_MEDIA_LIBRARY_ASSET_DELETE },
|
|
248
|
+
{ name: LABEL_PUBSUB, value: EVENT_PUBSUB },
|
|
245
249
|
{ name: LABEL_SCHEDULED, value: EVENT_SCHEDULED },
|
|
246
250
|
{ name: LABEL_SYNC_TAG_INVALIDATE, value: EVENT_SYNC_TAG_INVALIDATE },
|
|
247
251
|
],
|
|
@@ -249,11 +253,10 @@ async function promptForFunctionType() {
|
|
|
249
253
|
if (choices.length === 0) {
|
|
250
254
|
return 'You must choose at least one function type / document change event';
|
|
251
255
|
}
|
|
252
|
-
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
return 'You cannot mix Document, Media Library Asset, and Scheduled events together in one Function';
|
|
256
|
+
// same grouping as the check in functionAddCore, so the prompt cannot drift from it
|
|
257
|
+
const eventSources = new Set(choices.map((c) => String(c.value).substring(0, String(c.value).lastIndexOf('-'))));
|
|
258
|
+
if (eventSources.size > 1) {
|
|
259
|
+
return 'You cannot mix Document, Media Library Asset, PubSub, Scheduled, and Sync Tag Invalidate events together in one Function';
|
|
257
260
|
}
|
|
258
261
|
return true;
|
|
259
262
|
},
|
|
@@ -9,6 +9,7 @@ export class ApiBaseElement extends HTMLElement {
|
|
|
9
9
|
this.api = api
|
|
10
10
|
this.SANITY_FUNCTION_DOCUMENT = 'sanity.function.document'
|
|
11
11
|
this.SANITY_FUNCTION_MEDIA_LIBRARY_ASSET = 'sanity.function.media-library.asset'
|
|
12
|
+
this.SANITY_FUNCTION_PUBSUB = 'sanity.function.pubsub'
|
|
12
13
|
this.SANITY_FUNCTION_SCHEDULED = 'sanity.function.cron'
|
|
13
14
|
this.SANITY_FUNCTION_SYNC_TAG_INVALIDATE = 'sanity.function.sync-tag-invalidate'
|
|
14
15
|
}
|
|
@@ -79,6 +79,7 @@ class FiltersComponent extends ApiBaseElement {
|
|
|
79
79
|
const mediaFunction = this.api.store.selectedFunctionType?.startsWith(
|
|
80
80
|
this.SANITY_FUNCTION_MEDIA_LIBRARY_ASSET,
|
|
81
81
|
)
|
|
82
|
+
const pubsubFunction = this.api.store.selectedFunctionType === this.SANITY_FUNCTION_PUBSUB
|
|
82
83
|
const scheduleFunction = this.api.store.selectedFunctionType === this.SANITY_FUNCTION_SCHEDULED
|
|
83
84
|
const stiFunction =
|
|
84
85
|
this.api.store.selectedFunctionType === this.SANITY_FUNCTION_SYNC_TAG_INVALIDATE
|
|
@@ -89,15 +90,16 @@ class FiltersComponent extends ApiBaseElement {
|
|
|
89
90
|
mediaFunction,
|
|
90
91
|
scheduleFunction,
|
|
91
92
|
stiFunction,
|
|
93
|
+
pubsubFunction,
|
|
92
94
|
)
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
buildFilters = (docFunction, mediaFunction, scheduleFunction, stiFunction) => {
|
|
97
|
+
buildFilters = (docFunction, mediaFunction, scheduleFunction, stiFunction, pubsubFunction) => {
|
|
96
98
|
return `
|
|
97
99
|
<legend class="config-label">Client Options</legend>
|
|
98
100
|
<div id="dynamic-dropdowns" class="flex gap-2">
|
|
99
101
|
${
|
|
100
|
-
docFunction || scheduleFunction || stiFunction
|
|
102
|
+
docFunction || scheduleFunction || stiFunction || pubsubFunction
|
|
101
103
|
? `<select-dropdown
|
|
102
104
|
label="Project"
|
|
103
105
|
store-key="projects"
|
|
@@ -164,6 +164,9 @@ class PayloadPanel extends ApiBaseElement {
|
|
|
164
164
|
const payloadTitle = this.shadowRoot.querySelector('#payloadTitle')
|
|
165
165
|
let title = 'Document'
|
|
166
166
|
switch (selectedFunctionType) {
|
|
167
|
+
case this.SANITY_FUNCTION_PUBSUB:
|
|
168
|
+
title = 'PubSub Payload'
|
|
169
|
+
break
|
|
167
170
|
case this.SANITY_FUNCTION_SYNC_TAG_INVALIDATE:
|
|
168
171
|
title = 'Sync Tag Payload'
|
|
169
172
|
break
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type BlueprintResource } from '@sanity/blueprints';
|
|
2
|
+
/**
|
|
3
|
+
* Extracts the blueprint config from the function source code and mutates it to the resource object.
|
|
4
|
+
* This is used for durable functions that may not have a config defined in the blueprint.
|
|
5
|
+
* @param resources
|
|
6
|
+
* @param blueprintFileDir
|
|
7
|
+
*/
|
|
8
|
+
export declare const extractDurableConfig: (resources: BlueprintResource[], blueprintFileDir: string) => Promise<void>;
|