@sanity/runtime-cli 15.1.3 → 15.1.5
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 +26 -20
- package/dist/actions/blueprints/blueprint.js +1 -1
- package/dist/actions/blueprints/operations.d.ts +30 -0
- package/dist/actions/blueprints/operations.js +50 -0
- package/dist/actions/blueprints/stacks.d.ts +2 -2
- package/dist/actions/blueprints/wait-for-operation.d.ts +30 -0
- package/dist/actions/blueprints/wait-for-operation.js +88 -0
- package/dist/actions/functions/test.js +1 -1
- package/dist/actions/node.js +1 -1
- package/dist/actions/sanity/examples.js +1 -1
- package/dist/baseCommands.js +1 -0
- package/dist/commands/blueprints/deploy.js +3 -1
- package/dist/commands/blueprints/destroy.js +3 -1
- package/dist/cores/blueprints/deploy.js +43 -78
- package/dist/cores/blueprints/destroy.js +41 -57
- package/dist/cores/functions/add.js +1 -1
- package/dist/cores/functions/build.js +1 -1
- 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 +13 -3
- package/dist/cores/index.d.ts +2 -0
- package/dist/server/handlers/invoke.js +17 -5
- package/dist/utils/blueprints/group-resources.d.ts +8 -0
- package/dist/utils/blueprints/group-resources.js +29 -0
- package/dist/utils/blueprints/resolve-deployed-resources.d.ts +17 -0
- package/dist/utils/blueprints/resolve-deployed-resources.js +29 -0
- package/dist/utils/{validate/index.d.ts → blueprints/validate-resources.d.ts} +0 -1
- package/dist/utils/{validate/index.js → blueprints/validate-resources.js} +0 -1
- package/dist/utils/exit-codes.d.ts +15 -0
- package/dist/utils/exit-codes.js +15 -0
- package/dist/utils/{build-payload.d.ts → functions/build-payload.d.ts} +1 -1
- package/dist/utils/{build-payload.js → functions/build-payload.js} +1 -1
- package/dist/utils/{child-process-wrapper.js → functions/child-process-wrapper.js} +63 -0
- package/dist/utils/{find-function.d.ts → functions/find.d.ts} +1 -1
- package/dist/utils/{find-function.js → functions/find.js} +2 -2
- package/dist/utils/{invoke-local.d.ts → functions/invoke-local.d.ts} +1 -1
- package/dist/utils/{invoke-local.js → functions/invoke-local.js} +10 -8
- package/dist/utils/functions/prepare-asset.js +2 -2
- package/dist/utils/{transpile/transpile-function.d.ts → functions/transpile/function.d.ts} +1 -1
- package/dist/utils/{transpile/transpile-function.js → functions/transpile/function.js} +3 -3
- package/dist/utils/types.d.ts +4 -0
- package/oclif.manifest.json +3 -3
- package/package.json +2 -2
- /package/dist/utils/{other → external}/github.d.ts +0 -0
- /package/dist/utils/{other → external}/github.js +0 -0
- /package/dist/utils/{other → external}/npmjs.d.ts +0 -0
- /package/dist/utils/{other → external}/npmjs.js +0 -0
- /package/dist/utils/functions/{getFolderSize.d.ts → get-folder-size.d.ts} +0 -0
- /package/dist/utils/functions/{getFolderSize.js → get-folder-size.js} +0 -0
- /package/dist/utils/functions/{packageJsonUtils.d.ts → package-json.d.ts} +0 -0
- /package/dist/utils/functions/{packageJsonUtils.js → package-json.js} +0 -0
- /package/dist/utils/functions/{resolve-function-auth.d.ts → resolve-auth.d.ts} +0 -0
- /package/dist/utils/functions/{resolve-function-auth.js → resolve-auth.js} +0 -0
- /package/dist/utils/{transpile → functions/transpile}/cleanup-source-maps.d.ts +0 -0
- /package/dist/utils/{transpile → functions/transpile}/cleanup-source-maps.js +0 -0
- /package/dist/utils/{transpile → functions/transpile}/find-up.d.ts +0 -0
- /package/dist/utils/{transpile → functions/transpile}/find-up.js +0 -0
- /package/dist/utils/{pnpm.d.ts → functions/transpile/pnpm.d.ts} +0 -0
- /package/dist/utils/{pnpm.js → functions/transpile/pnpm.js} +0 -0
- /package/dist/utils/{transpile → functions/transpile}/verify-handler.d.ts +0 -0
- /package/dist/utils/{transpile → functions/transpile}/verify-handler.js +0 -0
- /package/dist/utils/{validate/resource.d.ts → functions/validate-name.d.ts} +0 -0
- /package/dist/utils/{validate/resource.js → functions/validate-name.js} +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
2
2
|
import { confirm } from '@inquirer/prompts';
|
|
3
3
|
import { patchConfigFile } from '../../actions/blueprints/config.js';
|
|
4
|
-
import { setupLogPolling } from '../../actions/blueprints/logs-polling.js';
|
|
5
4
|
import { destroyStack, getStack, resolveStackIdByNameOrId } from '../../actions/blueprints/stacks.js';
|
|
6
|
-
import {
|
|
5
|
+
import { waitForOperation } from '../../actions/blueprints/wait-for-operation.js';
|
|
7
6
|
import { niceId } from '../../utils/display/presenters.js';
|
|
7
|
+
import { CODE_OPERATION_UNCONFIRMED, EXIT_OPERATION_UNCONFIRMED } from '../../utils/exit-codes.js';
|
|
8
8
|
import { styleText } from '../../utils/style-text.js';
|
|
9
9
|
export async function blueprintDestroyCore(options) {
|
|
10
10
|
const { bin = 'sanity', log, token, blueprint, flags } = options;
|
|
11
|
-
const { force = false, 'project-id': flagProjectId, 'organization-id': flagOrganizationId, stack: flagStack, 'no-wait': noWait = false, verbose
|
|
11
|
+
const { force = false, 'project-id': flagProjectId, 'organization-id': flagOrganizationId, stack: flagStack, 'no-wait': noWait = false, verbose = false, } = flags;
|
|
12
12
|
// 3-flag combo: destroy without needing a local blueprint config
|
|
13
13
|
if ((flagProjectId || flagOrganizationId) && flagStack && force) {
|
|
14
14
|
let scopeType;
|
|
@@ -45,6 +45,7 @@ export async function blueprintDestroyCore(options) {
|
|
|
45
45
|
auth,
|
|
46
46
|
log,
|
|
47
47
|
bin,
|
|
48
|
+
verbose,
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
const { scopeType, scopeId, stackId } = blueprint;
|
|
@@ -126,6 +127,7 @@ export async function blueprintDestroyCore(options) {
|
|
|
126
127
|
auth,
|
|
127
128
|
log,
|
|
128
129
|
bin,
|
|
130
|
+
verbose,
|
|
129
131
|
});
|
|
130
132
|
}
|
|
131
133
|
catch (error) {
|
|
@@ -147,62 +149,44 @@ function clearLocalStackIdFromConfig(blueprint, destroyedStackId, log) {
|
|
|
147
149
|
}
|
|
148
150
|
}
|
|
149
151
|
async function waitForDestruction(options) {
|
|
150
|
-
const { stackId, stackName, operationId, auth, log, bin } = options;
|
|
152
|
+
const { stackId, stackName, operationId, auth, log, bin, verbose = false } = options;
|
|
151
153
|
log(styleText('dim', 'Stack destruction progress:'));
|
|
152
154
|
log('');
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
onLogEntry: (logEntry) => logHints.inspectLog(logEntry),
|
|
167
|
-
});
|
|
168
|
-
while (true) {
|
|
169
|
-
const { ok, stack: currentStack } = await getStack({ stackId, auth, logger: log });
|
|
170
|
-
const operation = currentStack?.recentOperation;
|
|
171
|
-
if (!ok || !operation || operation?.status === 'COMPLETED') {
|
|
172
|
-
// Operation is also marked destroyed when stack is deleted;
|
|
173
|
-
// it's possible that the operation is "gone" or available and "COMPLETED"
|
|
174
|
-
if (logStreamCleanup)
|
|
175
|
-
logStreamCleanup();
|
|
176
|
-
log('');
|
|
177
|
-
log(styleText(['bold', 'magenta'], 'Stack destruction completed!'));
|
|
178
|
-
return { success: true, json: { stackId, stackName } };
|
|
179
|
-
}
|
|
180
|
-
if (operation.status === 'FAILED') {
|
|
181
|
-
if (logStreamCleanup)
|
|
182
|
-
logStreamCleanup();
|
|
183
|
-
log('');
|
|
184
|
-
return {
|
|
185
|
-
success: false,
|
|
186
|
-
error: 'Stack destruction failed',
|
|
187
|
-
suggestions: [
|
|
188
|
-
...logHints.getSuggestions(),
|
|
189
|
-
'Review the destruction output above for error details.',
|
|
190
|
-
`Run \`npx ${bin} blueprints logs --verbose\` for more context.`,
|
|
191
|
-
`Run \`npx ${bin} blueprints info\` to view current Stack status.`,
|
|
192
|
-
],
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
if (!idleMessageShown && Date.now() - lastLogAt > 60_000) {
|
|
196
|
-
log(`No new activity for 60 seconds. The destruction is still running on Sanity servers.`);
|
|
197
|
-
log(`You can safely exit and check status later with \`npx ${bin} blueprints info\`.`);
|
|
198
|
-
idleMessageShown = true;
|
|
199
|
-
}
|
|
200
|
-
await sleep(1500);
|
|
201
|
-
}
|
|
155
|
+
const outcome = await waitForOperation({
|
|
156
|
+
stackId,
|
|
157
|
+
operationId,
|
|
158
|
+
auth,
|
|
159
|
+
log,
|
|
160
|
+
bin,
|
|
161
|
+
verbose,
|
|
162
|
+
includeDestroyed: true,
|
|
163
|
+
progressNoun: 'destruction',
|
|
164
|
+
});
|
|
165
|
+
if (outcome.type === 'completed') {
|
|
166
|
+
log(styleText(['bold', 'magenta'], 'Stack destruction completed!'));
|
|
167
|
+
return { success: true, json: { stackId, stackName } };
|
|
202
168
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
169
|
+
if (outcome.type === 'unconfirmed') {
|
|
170
|
+
return {
|
|
171
|
+
success: false,
|
|
172
|
+
error: `Stack destruction was accepted but completion could not be confirmed${outcome.error ? ` (${outcome.error})` : ''}.`,
|
|
173
|
+
code: CODE_OPERATION_UNCONFIRMED,
|
|
174
|
+
exitCode: EXIT_OPERATION_UNCONFIRMED,
|
|
175
|
+
suggestions: [
|
|
176
|
+
'The destruction may or may not have finished on Sanity servers.',
|
|
177
|
+
`Run \`npx ${bin} blueprints info\` to view current Stack status.`,
|
|
178
|
+
`Run \`npx ${bin} blueprints logs --watch\` to keep streaming logs.`,
|
|
179
|
+
],
|
|
180
|
+
};
|
|
207
181
|
}
|
|
182
|
+
return {
|
|
183
|
+
success: false,
|
|
184
|
+
error: 'Stack destruction failed',
|
|
185
|
+
suggestions: [
|
|
186
|
+
...outcome.logHints,
|
|
187
|
+
'Review the destruction output above for error details.',
|
|
188
|
+
`Run \`npx ${bin} blueprints logs --verbose\` for more context.`,
|
|
189
|
+
`Run \`npx ${bin} blueprints info\` to view current Stack status.`,
|
|
190
|
+
],
|
|
191
|
+
};
|
|
208
192
|
}
|
|
@@ -7,8 +7,8 @@ import { createFunctionResource } from '../../actions/blueprints/resources.js';
|
|
|
7
7
|
import { verifyExampleExists, writeExample } from '../../actions/sanity/examples.js';
|
|
8
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';
|
|
9
9
|
import { check, indent, warn } from '../../utils/display/presenters.js';
|
|
10
|
+
import { validateFunctionName } from '../../utils/functions/validate-name.js';
|
|
10
11
|
import { styleText } from '../../utils/style-text.js';
|
|
11
|
-
import { validateFunctionName } from '../../utils/validate/resource.js';
|
|
12
12
|
export const generateFunctionBlueprintResourceTemplate = (fnName, eventNames) => {
|
|
13
13
|
const functionType = MAP_EVENT_TO_FUNCTION_TYPE[eventNames[0]];
|
|
14
14
|
let definer = '';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { pathToZip } from '../../actions/blueprints/assets.js';
|
|
4
|
-
import { findFunctionInResources } from '../../utils/find
|
|
4
|
+
import { findFunctionInResources } from '../../utils/functions/find.js';
|
|
5
5
|
import { prepareAsset } from '../../utils/functions/prepare-asset.js';
|
|
6
6
|
import { isLocalFunctionResource } from '../../utils/types.js';
|
|
7
7
|
export async function functionBuildCore(options) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { update } from '../../../actions/functions/env/update.js';
|
|
2
|
-
import { findFunctionInStack } from '../../../utils/find
|
|
3
|
-
import { resolveFunctionAuth } from '../../../utils/functions/resolve-
|
|
2
|
+
import { findFunctionInStack } from '../../../utils/functions/find.js';
|
|
3
|
+
import { resolveFunctionAuth } from '../../../utils/functions/resolve-auth.js';
|
|
4
4
|
import { styleText } from '../../../utils/style-text.js';
|
|
5
5
|
export async function functionEnvAddCore(options) {
|
|
6
6
|
const { args, log } = options;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { list } from '../../../actions/functions/env/list.js';
|
|
2
|
-
import { findFunctionInStack } from '../../../utils/find
|
|
3
|
-
import { resolveFunctionAuth } from '../../../utils/functions/resolve-
|
|
2
|
+
import { findFunctionInStack } from '../../../utils/functions/find.js';
|
|
3
|
+
import { resolveFunctionAuth } from '../../../utils/functions/resolve-auth.js';
|
|
4
4
|
export async function functionEnvListCore(options) {
|
|
5
5
|
const { args, log } = options;
|
|
6
6
|
const spinner = log.ora(`Listing environment variables for "${args.name}"`).start();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { remove } from '../../../actions/functions/env/remove.js';
|
|
2
|
-
import { findFunctionInStack } from '../../../utils/find
|
|
3
|
-
import { resolveFunctionAuth } from '../../../utils/functions/resolve-
|
|
2
|
+
import { findFunctionInStack } from '../../../utils/functions/find.js';
|
|
3
|
+
import { resolveFunctionAuth } from '../../../utils/functions/resolve-auth.js';
|
|
4
4
|
import { styleText } from '../../../utils/style-text.js';
|
|
5
5
|
export async function functionEnvRemoveCore(options) {
|
|
6
6
|
const { args, log } = options;
|
|
@@ -2,8 +2,8 @@ import { confirm } from '@inquirer/prompts';
|
|
|
2
2
|
import { deleteLogs as deleteLogsAction, logs as getLogsAction, streamLogs as streamLogsAction, } from '../../actions/functions/logs.js';
|
|
3
3
|
import { formatTitle } from '../../utils/display/blueprints-formatting.js';
|
|
4
4
|
import { niceId } from '../../utils/display/presenters.js';
|
|
5
|
-
import { findFunctionInStack, getFunctionNames } from '../../utils/find
|
|
6
|
-
import { resolveFunctionAuth } from '../../utils/functions/resolve-
|
|
5
|
+
import { findFunctionInStack, getFunctionNames } from '../../utils/functions/find.js';
|
|
6
|
+
import { resolveFunctionAuth } from '../../utils/functions/resolve-auth.js';
|
|
7
7
|
import { styleText } from '../../utils/style-text.js';
|
|
8
8
|
export async function functionLogsCore(options) {
|
|
9
9
|
const { args, flags, log, error, deployedStack, blueprint, helpText } = options;
|
|
@@ -4,9 +4,10 @@ import { cwd } from 'node:process';
|
|
|
4
4
|
import { testAction } from '../../actions/functions/test.js';
|
|
5
5
|
import config from '../../config.js';
|
|
6
6
|
import { SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET } from '../../constants.js';
|
|
7
|
-
import
|
|
8
|
-
import
|
|
7
|
+
import { resolveDeployedResources } from '../../utils/blueprints/resolve-deployed-resources.js';
|
|
8
|
+
import buildPayload from '../../utils/functions/build-payload.js';
|
|
9
9
|
import { fetchAsset, fetchDocument } from '../../utils/functions/fetch-document.js';
|
|
10
|
+
import { findFunctionInResources, getFunctionNames } from '../../utils/functions/find.js';
|
|
10
11
|
import { parseJsonObject } from '../../utils/parse-json-object.js';
|
|
11
12
|
import { isEventType, } from '../../utils/types.js';
|
|
12
13
|
export async function functionTestCore(options) {
|
|
@@ -40,6 +41,14 @@ export async function functionTestCore(options) {
|
|
|
40
41
|
const resource = findFunctionInResources(blueprint.resources, fnName); // throws if not found
|
|
41
42
|
const docFunction = resource.type === SANITY_FUNCTION_DOCUMENT;
|
|
42
43
|
const mediaFunction = resource.type === SANITY_FUNCTION_MEDIA_LIBRARY_ASSET;
|
|
44
|
+
const resolvedResources = await resolveDeployedResources({
|
|
45
|
+
resources: blueprint.resources,
|
|
46
|
+
stackId: blueprint.stackId,
|
|
47
|
+
auth: config.token && blueprint.scopeType && blueprint.scopeId
|
|
48
|
+
? { token: config.token, scopeType: blueprint.scopeType, scopeId: blueprint.scopeId }
|
|
49
|
+
: undefined,
|
|
50
|
+
logger: log,
|
|
51
|
+
});
|
|
43
52
|
const contextOptions = docFunction || mediaFunction
|
|
44
53
|
? {
|
|
45
54
|
clientOptions: {
|
|
@@ -52,8 +61,9 @@ export async function functionTestCore(options) {
|
|
|
52
61
|
eventResourceId: (docFunction ? `${projectId}.${dataset}` : mediaLibraryId) || '',
|
|
53
62
|
functionResourceType: 'project',
|
|
54
63
|
functionResourceId: projectId || '',
|
|
64
|
+
resources: resolvedResources,
|
|
55
65
|
}
|
|
56
|
-
: { clientOptions: {} };
|
|
66
|
+
: { clientOptions: {}, resources: resolvedResources };
|
|
57
67
|
// If the user sets the flag to use the real token set it in our options
|
|
58
68
|
if (withUserToken) {
|
|
59
69
|
contextOptions.clientOptions.token = config.token || undefined;
|
package/dist/cores/index.d.ts
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import { readLocalBlueprint } from '../../actions/blueprints/blueprint.js';
|
|
2
|
+
import config from '../../config.js';
|
|
3
|
+
import { resolveDeployedResources } from '../../utils/blueprints/resolve-deployed-resources.js';
|
|
4
|
+
import { findFunctionInResources } from '../../utils/functions/find.js';
|
|
5
|
+
import invoke from '../../utils/functions/invoke-local.js';
|
|
6
|
+
import { Logger } from '../../utils/logger.js';
|
|
7
|
+
const silentLogger = Logger(() => { });
|
|
4
8
|
export async function handleInvokeRequest(functionName, event, metadata, context, validateResources, executionOptions) {
|
|
5
9
|
const start = performance.now();
|
|
6
|
-
const { resources } = await
|
|
10
|
+
const { resources, stackId, scopeType, scopeId } = await readLocalBlueprint(silentLogger, {
|
|
11
|
+
resources: validateResources,
|
|
12
|
+
});
|
|
7
13
|
const resource = findFunctionInResources(resources, functionName);
|
|
8
14
|
const readBlueprintTime = performance.now() - start;
|
|
15
|
+
const resolvedResources = await resolveDeployedResources({
|
|
16
|
+
resources,
|
|
17
|
+
stackId,
|
|
18
|
+
auth: config.token && scopeType && scopeId ? { token: config.token, scopeType, scopeId } : undefined,
|
|
19
|
+
logger: silentLogger,
|
|
20
|
+
});
|
|
9
21
|
const payload = {
|
|
10
22
|
payload: event,
|
|
11
23
|
...metadata,
|
|
12
24
|
};
|
|
13
|
-
const response = await invoke(resource, payload, context, {
|
|
25
|
+
const response = await invoke(resource, payload, { ...context, resources: resolvedResources }, {
|
|
14
26
|
forceColor: executionOptions?.forceColor ?? false,
|
|
15
27
|
timeout: executionOptions?.timeout ?? resource.timeout,
|
|
16
28
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BlueprintResource } from '@sanity/blueprints';
|
|
2
|
+
export type GroupedBlueprintResource = {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
type: string;
|
|
6
|
+
};
|
|
7
|
+
export type GroupedBlueprintResources = Record<string, GroupedBlueprintResource[]>;
|
|
8
|
+
export declare function groupBlueprintResources(blueprintResources: BlueprintResource[]): GroupedBlueprintResources;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const BLUEPRINT_TYPE_TO_KEY = {
|
|
2
|
+
'sanity.project.webhook': 'webhook',
|
|
3
|
+
'sanity.project.cors': 'cors',
|
|
4
|
+
'sanity.project.origin': 'cors',
|
|
5
|
+
'sanity.access.role': 'role',
|
|
6
|
+
'sanity.project.dataset': 'dataset',
|
|
7
|
+
'sanity.project': 'project',
|
|
8
|
+
};
|
|
9
|
+
export function groupBlueprintResources(blueprintResources) {
|
|
10
|
+
const grouped = {};
|
|
11
|
+
for (const resource of blueprintResources) {
|
|
12
|
+
if (resource.type === 'sanity.access.robot')
|
|
13
|
+
continue;
|
|
14
|
+
const key = (resource.type?.startsWith('sanity.function.')
|
|
15
|
+
? 'function'
|
|
16
|
+
: BLUEPRINT_TYPE_TO_KEY[resource.type]) ?? resource.type?.split('.').pop();
|
|
17
|
+
if (!key)
|
|
18
|
+
continue;
|
|
19
|
+
if (!grouped[key])
|
|
20
|
+
grouped[key] = [];
|
|
21
|
+
const externalId = resource.externalId;
|
|
22
|
+
grouped[key].push({
|
|
23
|
+
id: externalId || 'not-deployed',
|
|
24
|
+
name: resource.name,
|
|
25
|
+
type: resource.type,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return grouped;
|
|
29
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BlueprintResource } from '@sanity/blueprints';
|
|
2
|
+
import type { Logger } from '../logger.js';
|
|
3
|
+
import type { AuthParams } from '../types.js';
|
|
4
|
+
interface ResolveOptions {
|
|
5
|
+
resources: BlueprintResource[];
|
|
6
|
+
stackId?: string;
|
|
7
|
+
auth?: AuthParams;
|
|
8
|
+
logger: Logger;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Returns the local blueprint resources, annotated with externalIds from the
|
|
12
|
+
* deployed stack where a match is found (by name + type). Locally-added
|
|
13
|
+
* resources that aren't yet deployed are preserved without an externalId.
|
|
14
|
+
* Any failure to fetch the stack falls back to the raw local resources.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveDeployedResources({ resources, stackId, auth, logger, }: ResolveOptions): Promise<BlueprintResource[]>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getStack } from '../../actions/blueprints/stacks.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the local blueprint resources, annotated with externalIds from the
|
|
4
|
+
* deployed stack where a match is found (by name + type). Locally-added
|
|
5
|
+
* resources that aren't yet deployed are preserved without an externalId.
|
|
6
|
+
* Any failure to fetch the stack falls back to the raw local resources.
|
|
7
|
+
*/
|
|
8
|
+
export async function resolveDeployedResources({ resources, stackId, auth, logger, }) {
|
|
9
|
+
if (!stackId || !auth?.token || !auth.scopeType || !auth.scopeId)
|
|
10
|
+
return resources;
|
|
11
|
+
try {
|
|
12
|
+
const response = await getStack({ stackId, auth, logger });
|
|
13
|
+
if (!response.ok || !Array.isArray(response.stack?.resources))
|
|
14
|
+
return resources;
|
|
15
|
+
const deployedByKey = new Map();
|
|
16
|
+
for (const deployed of response.stack.resources) {
|
|
17
|
+
if (deployed.externalId) {
|
|
18
|
+
deployedByKey.set(`${deployed.type}:${deployed.name}`, deployed.externalId);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return resources.map((resource) => {
|
|
22
|
+
const externalId = deployedByKey.get(`${resource.type}:${resource.name}`);
|
|
23
|
+
return externalId ? { ...resource, externalId } : resource;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return resources;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { validateCorsOrigin, validateDataset, validateDocumentFunction, validateDocumentWebhook, validateMediaLibraryAssetFunction, validateProject, validateRole, validateScheduledFunction, } from '@sanity/blueprints';
|
|
2
2
|
import { SANITY_ACCESS_ROLE, SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_SCHEDULED, SANITY_PROJECT, SANITY_PROJECT_CORS, SANITY_PROJECT_DATASET, SANITY_PROJECT_WEBHOOK, } from '../../constants.js';
|
|
3
|
-
export * as validate from './resource.js';
|
|
4
3
|
const RESOURCE_VALIDATORS = {
|
|
5
4
|
[SANITY_ACCESS_ROLE]: {
|
|
6
5
|
validate: validateRole,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process exit codes used by the CLI.
|
|
3
|
+
*
|
|
4
|
+
* oclif exits 0 on success and 2 on error by default. Codes defined here are
|
|
5
|
+
* deliberate, documented signals for scripts/CI to branch on.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* A deploy/destroy was accepted but the CLI could not confirm completion
|
|
9
|
+
* (e.g. the operation status endpoint was unavailable). The operation may or
|
|
10
|
+
* may not have finished; rerun `blueprints info` to check. Mirrors EX_TEMPFAIL
|
|
11
|
+
* from sysexits.h ("temporary failure; the user is invited to retry").
|
|
12
|
+
*/
|
|
13
|
+
export declare const EXIT_OPERATION_UNCONFIRMED = 75;
|
|
14
|
+
/** Machine-readable error code paired with {@link EXIT_OPERATION_UNCONFIRMED}. */
|
|
15
|
+
export declare const CODE_OPERATION_UNCONFIRMED = "OPERATION_UNCONFIRMED";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process exit codes used by the CLI.
|
|
3
|
+
*
|
|
4
|
+
* oclif exits 0 on success and 2 on error by default. Codes defined here are
|
|
5
|
+
* deliberate, documented signals for scripts/CI to branch on.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* A deploy/destroy was accepted but the CLI could not confirm completion
|
|
9
|
+
* (e.g. the operation status endpoint was unavailable). The operation may or
|
|
10
|
+
* may not have finished; rerun `blueprints info` to check. Mirrors EX_TEMPFAIL
|
|
11
|
+
* from sysexits.h ("temporary failure; the user is invited to retry").
|
|
12
|
+
*/
|
|
13
|
+
export const EXIT_OPERATION_UNCONFIRMED = 75;
|
|
14
|
+
/** Machine-readable error code paired with {@link EXIT_OPERATION_UNCONFIRMED}. */
|
|
15
|
+
export const CODE_OPERATION_UNCONFIRMED = 'OPERATION_UNCONFIRMED';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { BuildPayloadOptions } from '
|
|
1
|
+
import type { BuildPayloadOptions } from '../types.js';
|
|
2
2
|
export default function buildPayload(options: BuildPayloadOptions): Record<string, unknown>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { cwd } from 'node:process';
|
|
4
|
-
import { parseJsonObject } from '
|
|
4
|
+
import { parseJsonObject } from '../parse-json-object.js';
|
|
5
5
|
export default function buildPayload(options) {
|
|
6
6
|
const { data, file } = options;
|
|
7
7
|
let payload = {};
|
|
@@ -117,6 +117,9 @@ process.on('message', async (data) => {
|
|
|
117
117
|
)
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
// Replace resources JSON with Resources API
|
|
121
|
+
context.resources = createResourcesApi(context.resources)
|
|
122
|
+
|
|
120
123
|
json = await eventHandler({
|
|
121
124
|
context,
|
|
122
125
|
event,
|
|
@@ -149,3 +152,63 @@ process.on('message', async (data) => {
|
|
|
149
152
|
process.exit(1)
|
|
150
153
|
}
|
|
151
154
|
})
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The returned proxy wraps a function so the API itself is callable.
|
|
158
|
+
* @param {Record<string, ResourceEntry[]>} resources
|
|
159
|
+
* @returns {ResourcesApi}
|
|
160
|
+
*/
|
|
161
|
+
export function createResourcesApi(resources) {
|
|
162
|
+
const findByName = (name) => {
|
|
163
|
+
for (const group of Object.values(resources)) {
|
|
164
|
+
const found = group.find((r) => r.name === name)
|
|
165
|
+
if (found) return found
|
|
166
|
+
}
|
|
167
|
+
return undefined
|
|
168
|
+
}
|
|
169
|
+
let allCache
|
|
170
|
+
const all = () => (allCache ??= Object.values(resources).flat())
|
|
171
|
+
|
|
172
|
+
return /** @type {ResourcesApi} */ (
|
|
173
|
+
/** @type {unknown} */ (
|
|
174
|
+
/*
|
|
175
|
+
* The Proxy target is `findByName`, so invoking the API as a function —
|
|
176
|
+
* `context.resources('my-proj')` — bypasses the `get` trap entirely and
|
|
177
|
+
* calls `findByName` directly for a cross-type lookup by name.
|
|
178
|
+
*/
|
|
179
|
+
new Proxy(findByName, {
|
|
180
|
+
get: (_target, prop) => {
|
|
181
|
+
// context.resources.all() — flat array of every resource across types
|
|
182
|
+
if (prop === 'all') return all
|
|
183
|
+
// [...context.resources] / for (const r of context.resources) — iterate all
|
|
184
|
+
if (prop === Symbol.iterator) {
|
|
185
|
+
return function* () {
|
|
186
|
+
yield* all()
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Symbol property access (other than iterator above) and `then`
|
|
192
|
+
* lookups return undefined. The `then` guard prevents the API from
|
|
193
|
+
* looking like a thenable, so `await context.resources` resolves to
|
|
194
|
+
* the proxy itself rather than hanging or unwrapping unexpectedly.
|
|
195
|
+
*/
|
|
196
|
+
if (typeof prop !== 'string' || prop === 'then') {
|
|
197
|
+
return undefined
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* context.resources.<type>(name) — per-type lookup,
|
|
202
|
+
* e.g. context.resources.project('my-proj').
|
|
203
|
+
* Returns a function so the caller supplies the name;
|
|
204
|
+
* unknown types yield a function that always returns undefined.
|
|
205
|
+
*/
|
|
206
|
+
return (/** @type {string} */ name) =>
|
|
207
|
+
Object.hasOwn(resources, prop)
|
|
208
|
+
? resources[prop].find((r) => r.name === name)
|
|
209
|
+
: undefined
|
|
210
|
+
},
|
|
211
|
+
})
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BlueprintResource } from '@sanity/blueprints';
|
|
2
|
-
import { type DeployedResource, type FunctionResource, type Stack } from '
|
|
2
|
+
import { type DeployedResource, type FunctionResource, type Stack } from '../types.js';
|
|
3
3
|
export declare function getFunctionNames(resources: BlueprintResource[] | undefined): string[];
|
|
4
4
|
export declare function findFunctionInResources(resources: BlueprintResource[], name: string): FunctionResource;
|
|
5
5
|
/** @deprecated Use findFunctionInResources instead */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SANITY_FUNCTION_PREFIX } from '
|
|
2
|
-
import { isLocalFunctionResource, } from '
|
|
1
|
+
import { SANITY_FUNCTION_PREFIX } from '../../constants.js';
|
|
2
|
+
import { isLocalFunctionResource, } from '../types.js';
|
|
3
3
|
export function getFunctionNames(resources) {
|
|
4
4
|
return (resources
|
|
5
5
|
?.filter((r) => r.type.startsWith(SANITY_FUNCTION_PREFIX))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type FunctionGroqResource, type FunctionResource, type InvocationResponse, type InvokeContextOptions, type InvokeExecutionOptions, type InvokeGroqPayloadOptions, type InvokePayloadOptions } from '
|
|
1
|
+
import { type FunctionGroqResource, type FunctionResource, type InvocationResponse, type InvokeContextOptions, type InvokeExecutionOptions, type InvokeGroqPayloadOptions, type InvokePayloadOptions } from '../types.js';
|
|
2
2
|
export declare function sanitizeLogs(logs: string): string;
|
|
3
3
|
export declare function applyGroqRule(resource: FunctionGroqResource, payload: InvokeGroqPayloadOptions, projectId: string | undefined, dataset: string | undefined): Promise<any>;
|
|
4
4
|
export default function invoke(resource: FunctionResource, payload: InvokePayloadOptions, context: InvokeContextOptions, options: InvokeExecutionOptions): Promise<InvocationResponse>;
|
|
@@ -4,14 +4,15 @@ import { cwd } from 'node:process';
|
|
|
4
4
|
import { setTimeout } from 'node:timers';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import * as groq from 'groq-js';
|
|
7
|
-
import config from '
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
7
|
+
import config from '../../config.js';
|
|
8
|
+
import { groupBlueprintResources } from '../blueprints/group-resources.js';
|
|
9
|
+
import { isGroqContextOptions, } from '../types.js';
|
|
10
|
+
import { findFunctionEntryPoint } from './find-entry-point.js';
|
|
11
|
+
import { cleanupTempPackageJson, createTempPackageJson, doesPackageJsonExists, } from './package-json.js';
|
|
12
|
+
import { resolveResourceDependencies } from './resolve-dependencies.js';
|
|
13
|
+
import { shouldAutoResolveDependencies } from './should-auto-resolve-deps.js';
|
|
14
|
+
import { shouldTranspileFunction } from './should-transpile.js';
|
|
15
|
+
import { transpileFunction } from './transpile/function.js';
|
|
15
16
|
function getChildProcessWrapperPath() {
|
|
16
17
|
return fileURLToPath(new URL('./child-process-wrapper.js', import.meta.url));
|
|
17
18
|
}
|
|
@@ -157,6 +158,7 @@ export default async function invoke(resource, payload, context, options) {
|
|
|
157
158
|
context: {
|
|
158
159
|
...context,
|
|
159
160
|
local: true,
|
|
161
|
+
resources: groupBlueprintResources(context.resources ?? []),
|
|
160
162
|
...(isGroqContextOptions(context) && {
|
|
161
163
|
clientOptions: {
|
|
162
164
|
...context.clientOptions,
|
|
@@ -3,12 +3,12 @@ import { rm, stat } from 'node:fs/promises';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { cwd } from 'node:process';
|
|
5
5
|
import { MAX_ASSET_SIZE } from '../../constants.js';
|
|
6
|
-
import { transpileFunction } from '../transpile/transpile-function.js';
|
|
7
6
|
import { detectNativeModules, errorMessage } from './detect-native-modules.js';
|
|
8
|
-
import { getFolderSize } from './
|
|
7
|
+
import { getFolderSize } from './get-folder-size.js';
|
|
9
8
|
import { resolveResourceDependencies } from './resolve-dependencies.js';
|
|
10
9
|
import { shouldAutoResolveDependencies } from './should-auto-resolve-deps.js';
|
|
11
10
|
import { shouldTranspileFunction } from './should-transpile.js';
|
|
11
|
+
import { transpileFunction } from './transpile/function.js';
|
|
12
12
|
export async function prepareAsset({ resource, }, { installer } = {}) {
|
|
13
13
|
if (!resource.src)
|
|
14
14
|
throw new Error('Resource src is required');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FunctionResource, InstallerType } from '
|
|
1
|
+
import type { FunctionResource, InstallerType } from '../../types.js';
|
|
2
2
|
export declare const resolveViteRoot: (entry: string) => string;
|
|
3
3
|
export declare function transpileFunction(resource: FunctionResource, { installer }?: {
|
|
4
4
|
installer?: InstallerType;
|
|
@@ -5,10 +5,10 @@ import { cwd } from 'node:process';
|
|
|
5
5
|
import * as find from 'empathic/find';
|
|
6
6
|
import { build as viteBuild } from 'vite';
|
|
7
7
|
import tsConfigPaths from 'vite-tsconfig-paths';
|
|
8
|
-
import { detectNativeModulesPlugin } from '../
|
|
9
|
-
import { findFunctionEntryPoint } from '../
|
|
10
|
-
import { createPnpmRequire } from '../pnpm.js';
|
|
8
|
+
import { detectNativeModulesPlugin } from '../detect-native-modules.js';
|
|
9
|
+
import { findFunctionEntryPoint } from '../find-entry-point.js';
|
|
11
10
|
import { cleanupSourceMaps } from './cleanup-source-maps.js';
|
|
11
|
+
import { createPnpmRequire } from './pnpm.js';
|
|
12
12
|
import { verifyHandler } from './verify-handler.js';
|
|
13
13
|
export const resolveViteRoot = (entry) => {
|
|
14
14
|
const nodeModulesDir = find.dir('node_modules', { cwd: entry });
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -123,12 +123,16 @@ export interface InvokeGroqContextOptions {
|
|
|
123
123
|
functionResourceType: string;
|
|
124
124
|
/** The resource ID of the function container; resource ID that houses the function. */
|
|
125
125
|
functionResourceId: string;
|
|
126
|
+
/** All resources declared by the blueprint, used to populate `context.resources` at invoke time. */
|
|
127
|
+
resources?: BlueprintResource[];
|
|
126
128
|
}
|
|
127
129
|
/** @internal */
|
|
128
130
|
export interface InvokeScheduleContextOptions {
|
|
129
131
|
clientOptions: {
|
|
130
132
|
token?: string;
|
|
131
133
|
};
|
|
134
|
+
/** All resources declared by the blueprint, used to populate `context.resources` at invoke time. */
|
|
135
|
+
resources?: BlueprintResource[];
|
|
132
136
|
}
|
|
133
137
|
export type InvokeContextOptions = InvokeGroqContextOptions | InvokeScheduleContextOptions;
|
|
134
138
|
export declare function isGroqContextOptions(context: InvokeContextOptions): context is InvokeGroqContextOptions;
|