@sanity/runtime-cli 17.9.0 → 17.10.0-next.g5e0bba6
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 +21 -20
- package/dist/actions/blueprints/blueprint.js +1 -1
- package/dist/actions/blueprints/pre-deploy.js +9 -6
- package/dist/actions/blueprints/stacks.d.ts +1 -0
- package/dist/actions/blueprints/wait-for-operation.js +2 -1
- package/dist/commands/functions/test.d.ts +1 -0
- package/dist/commands/functions/test.js +5 -0
- package/dist/cores/blueprints/config.js +18 -8
- package/dist/cores/blueprints/deploy.js +9 -8
- package/dist/cores/blueprints/destroy.js +7 -6
- package/dist/cores/blueprints/doctor.js +15 -2
- package/dist/cores/blueprints/init.d.ts +2 -0
- package/dist/cores/blueprints/init.js +56 -20
- package/dist/cores/blueprints/plan.js +11 -6
- package/dist/cores/blueprints/promote.js +3 -2
- package/dist/cores/functions/add.js +11 -7
- package/dist/cores/functions/logs.js +50 -6
- package/dist/cores/functions/test.js +41 -26
- package/dist/cores/index.d.ts +5 -0
- package/dist/utils/blueprints/hints.js +8 -3
- package/dist/utils/display/prompt.d.ts +15 -2
- package/dist/utils/display/prompt.js +70 -8
- package/dist/utils/functions/child-process-wrapper.js +3 -2
- package/dist/utils/functions/child-runtime/durable.d.ts +2 -2
- package/dist/utils/functions/child-runtime/durable.js +70 -3
- package/dist/utils/functions/durable-logs.d.ts +16 -0
- package/dist/utils/functions/durable-logs.js +52 -0
- package/dist/utils/functions/invoke/local.js +2 -1
- package/dist/utils/package-manager.d.ts +20 -0
- package/dist/utils/package-manager.js +63 -0
- package/dist/utils/types.d.ts +27 -4
- package/oclif.manifest.json +8 -1
- package/package.json +2 -2
|
@@ -5,6 +5,13 @@ import { styleText } from '../style-text.js';
|
|
|
5
5
|
import { niceId } from './presenters.js';
|
|
6
6
|
// --- Wizard infrastructure ---
|
|
7
7
|
export const BACK = Symbol('back');
|
|
8
|
+
/** Thrown when the user picks "Cancel" in a prompt. Cores translate it to a clean result. */
|
|
9
|
+
export class CancelledError extends Error {
|
|
10
|
+
constructor(message = 'Cancelled by user.') {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'CancelledError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
8
15
|
/**
|
|
9
16
|
* Runs a sequence of prompt steps with back-navigation support.
|
|
10
17
|
* Each step can return BACK to go to the previous non-skipped step.
|
|
@@ -57,13 +64,53 @@ function withBackChoice(choices, allowBack) {
|
|
|
57
64
|
];
|
|
58
65
|
}
|
|
59
66
|
// --- Standalone prompts ---
|
|
67
|
+
/**
|
|
68
|
+
* Ask where a new Blueprint should go.
|
|
69
|
+
* Returns the chosen directory, or null to use the current one.
|
|
70
|
+
* @throws CancelledError when the user cancels.
|
|
71
|
+
*/
|
|
72
|
+
export async function promptForInitLocation(currentDir) {
|
|
73
|
+
const HERE = 'here';
|
|
74
|
+
const ELSEWHERE = 'elsewhere';
|
|
75
|
+
const CANCEL = 'cancel';
|
|
76
|
+
const choice = await select({
|
|
77
|
+
message: 'Where should the Blueprint go?',
|
|
78
|
+
choices: [
|
|
79
|
+
{ name: 'Here', value: HERE, description: currentDir },
|
|
80
|
+
{ name: 'In a new folder', value: ELSEWHERE, description: 'Name a folder to create' },
|
|
81
|
+
{ name: 'Cancel', value: CANCEL, description: 'Stop here and change nothing' },
|
|
82
|
+
],
|
|
83
|
+
default: HERE,
|
|
84
|
+
});
|
|
85
|
+
if (choice === CANCEL)
|
|
86
|
+
throw new CancelledError();
|
|
87
|
+
if (choice === HERE)
|
|
88
|
+
return null;
|
|
89
|
+
const folder = await input({
|
|
90
|
+
message: 'Folder name:',
|
|
91
|
+
validate: (val) => val.trim().length > 0 || 'A folder name is required',
|
|
92
|
+
});
|
|
93
|
+
return folder.trim();
|
|
94
|
+
}
|
|
60
95
|
export async function promptForBlueprintType() {
|
|
61
96
|
return await select({
|
|
62
97
|
message: 'Choose a Blueprint file type:',
|
|
63
98
|
choices: [
|
|
64
|
-
{
|
|
65
|
-
|
|
66
|
-
|
|
99
|
+
{
|
|
100
|
+
name: 'TypeScript',
|
|
101
|
+
value: 'ts',
|
|
102
|
+
description: 'Editor completion and type checks. Adds @sanity/blueprints.',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'JavaScript',
|
|
106
|
+
value: 'js',
|
|
107
|
+
description: 'The same define* helpers, without type checks. Adds @sanity/blueprints.',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: 'JSON',
|
|
111
|
+
value: 'json',
|
|
112
|
+
description: 'No dependency and no install step. Write each resource by hand.',
|
|
113
|
+
},
|
|
67
114
|
],
|
|
68
115
|
default: 'ts',
|
|
69
116
|
});
|
|
@@ -203,7 +250,7 @@ export async function promptForProjectInOrg({ projects, knownProjectId, logger,
|
|
|
203
250
|
* Prompt the user for a Stack after scope has been determined.
|
|
204
251
|
* Can create a new Stack or select an existing one.
|
|
205
252
|
*/
|
|
206
|
-
export async function promptForStack({ scopeType, scopeId, token, logger, allowBack = false, }) {
|
|
253
|
+
export async function promptForStack({ scopeType, scopeId, token, logger, allowBack = false, suggestedName, }) {
|
|
207
254
|
if (!scopeId) {
|
|
208
255
|
throw new Error(`Cannot list Stacks: no ${scopeType} ID provided. ` +
|
|
209
256
|
'Provide --project-id or --organization-id, or select a scope in the wizard.');
|
|
@@ -247,16 +294,30 @@ export async function promptForStack({ scopeType, scopeId, token, logger, allowB
|
|
|
247
294
|
pickedStackId = answer;
|
|
248
295
|
}
|
|
249
296
|
else if (allowBack) {
|
|
297
|
+
const CANCEL = 'cancel';
|
|
250
298
|
const proceed = await select({
|
|
251
|
-
message: '
|
|
252
|
-
choices: withBackChoice([
|
|
299
|
+
message: 'This scope has no Stacks yet:',
|
|
300
|
+
choices: withBackChoice([
|
|
301
|
+
{
|
|
302
|
+
name: 'Create the first Stack',
|
|
303
|
+
value: NEW_STACK_ID,
|
|
304
|
+
description: 'A Blueprint needs a Stack before it can deploy',
|
|
305
|
+
},
|
|
306
|
+
{ name: 'Cancel', value: CANCEL, description: 'Stop here and change nothing' },
|
|
307
|
+
], allowBack),
|
|
253
308
|
});
|
|
254
309
|
if (proceed === BACK)
|
|
255
310
|
return BACK;
|
|
311
|
+
if (proceed === CANCEL)
|
|
312
|
+
throw new CancelledError();
|
|
256
313
|
}
|
|
257
314
|
if (pickedStackId === NEW_STACK_ID) {
|
|
315
|
+
// only suggest a free name; the API rejects a duplicate within a scope
|
|
316
|
+
const isTaken = stacks.some((s) => s.name === suggestedName);
|
|
317
|
+
logger(styleText('dim', 'The name is a label. Sanity assigns the Stack ID.'));
|
|
258
318
|
const stackName = await input({
|
|
259
|
-
message: '
|
|
319
|
+
message: 'Name your new Stack:',
|
|
320
|
+
default: isTaken ? undefined : suggestedName,
|
|
260
321
|
validate: (val) => val.length > 0 || 'Stack name is required',
|
|
261
322
|
});
|
|
262
323
|
const stack = await createEmptyStack({
|
|
@@ -277,7 +338,7 @@ export async function promptForStack({ scopeType, scopeId, token, logger, allowB
|
|
|
277
338
|
* Full wizard: Organization -> Scope -> Project (if project-scoped) -> Stack.
|
|
278
339
|
* Supports back-navigation between steps.
|
|
279
340
|
*/
|
|
280
|
-
export async function runScopeAndStackWizard({ token, knownOrganizationId, knownProjectId, logger, }) {
|
|
341
|
+
export async function runScopeAndStackWizard({ token, knownOrganizationId, knownProjectId, logger, suggestedStackName, }) {
|
|
281
342
|
const steps = [
|
|
282
343
|
{
|
|
283
344
|
key: 'organization',
|
|
@@ -336,6 +397,7 @@ export async function runScopeAndStackWizard({ token, knownOrganizationId, known
|
|
|
336
397
|
token,
|
|
337
398
|
logger,
|
|
338
399
|
allowBack: true,
|
|
400
|
+
suggestedName: suggestedStackName,
|
|
339
401
|
});
|
|
340
402
|
},
|
|
341
403
|
},
|
|
@@ -41,7 +41,7 @@ process.on('message', async (data) => {
|
|
|
41
41
|
|
|
42
42
|
// Otherwise this is the initial start message. Support the legacy untyped
|
|
43
43
|
// `{srcPath, payload}` shape as well as the new `{type: 'start', ...}`.
|
|
44
|
-
const {srcPath, payload, isDurable} = jsonData
|
|
44
|
+
const {srcPath, payload, isDurable, noWait} = jsonData
|
|
45
45
|
const {context, ...event} = payload
|
|
46
46
|
|
|
47
47
|
let logs = ''
|
|
@@ -83,9 +83,10 @@ process.on('message', async (data) => {
|
|
|
83
83
|
if (isDurable) {
|
|
84
84
|
json = await runDurable(
|
|
85
85
|
handler,
|
|
86
|
-
{context, event
|
|
86
|
+
{context, event},
|
|
87
87
|
{
|
|
88
88
|
emit: (e) => process.send(JSON.stringify({type: 'step-event', event: e})),
|
|
89
|
+
wait: (ms) => new Promise((resolve) => setTimeout(resolve, noWait ? 0 : ms)),
|
|
89
90
|
},
|
|
90
91
|
)
|
|
91
92
|
} else {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {DurableContext, DurableHandler, DurableLogger, GenericEvent} from '@sanity/functions'
|
|
2
|
-
import type {
|
|
2
|
+
import type {DurableRuntimeEvent} from '../../types.js'
|
|
3
3
|
|
|
4
4
|
type RunDurableArgs = {
|
|
5
5
|
context: DurableContext
|
|
@@ -8,7 +8,7 @@ type RunDurableArgs = {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
type DurableIO = {
|
|
11
|
-
emit: (event:
|
|
11
|
+
emit: (event: DurableRuntimeEvent) => void
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function runDurable(
|
|
@@ -1,17 +1,60 @@
|
|
|
1
1
|
import {performance} from 'node:perf_hooks'
|
|
2
|
+
import {inspect} from 'node:util'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param duration
|
|
7
|
+
* @return {number}
|
|
8
|
+
*/
|
|
9
|
+
const durationToMs = (duration = {}) => {
|
|
10
|
+
const {days = 0, hours = 0, minutes = 0, seconds = 0} = duration
|
|
11
|
+
return (((days * 24 + hours) * 60 + minutes) * 60 + seconds) * 1000
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @param args
|
|
17
|
+
*/
|
|
18
|
+
const formatArgs = (args) =>
|
|
19
|
+
args.map((a) => (typeof a === 'string' ? a : inspect(a, {depth: null}))).join(' ')
|
|
2
20
|
|
|
3
21
|
/**
|
|
4
22
|
* Runs a durable function handler
|
|
5
23
|
* @param handler - callback being run
|
|
6
24
|
* @param context - data to send to the operation
|
|
7
25
|
* @param event - the step being run
|
|
8
|
-
* @param logger
|
|
9
26
|
* @param io
|
|
10
27
|
*/
|
|
11
|
-
export async function runDurable(handler, {context, event
|
|
28
|
+
export async function runDurable(handler, {context, event}, io) {
|
|
29
|
+
let currentStep = null
|
|
30
|
+
const streamLog = (level, args) => {
|
|
31
|
+
const date = new Date()
|
|
32
|
+
const timestamp = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`
|
|
33
|
+
|
|
34
|
+
return io.emit({
|
|
35
|
+
timestamp,
|
|
36
|
+
kind: 'log',
|
|
37
|
+
phase: 'log',
|
|
38
|
+
step: currentStep,
|
|
39
|
+
level,
|
|
40
|
+
message: formatArgs(args),
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// @todo: need to throw error for use of `console.log` in a durable function
|
|
45
|
+
const logger = {
|
|
46
|
+
log: (...a) => streamLog('info', a),
|
|
47
|
+
info: (...a) => streamLog('info', a),
|
|
48
|
+
warn: (...a) => streamLog('warn', a),
|
|
49
|
+
error: (...a) => streamLog('error', a),
|
|
50
|
+
}
|
|
51
|
+
|
|
12
52
|
const track = async (name, kind, produce) => {
|
|
13
53
|
io.emit({name, kind, phase: 'start'})
|
|
14
54
|
const startedAt = performance.now()
|
|
55
|
+
const prev = currentStep
|
|
56
|
+
currentStep = name
|
|
57
|
+
|
|
15
58
|
try {
|
|
16
59
|
const value = await produce()
|
|
17
60
|
io.emit({
|
|
@@ -35,11 +78,35 @@ export async function runDurable(handler, {context, event, logger}, io) {
|
|
|
35
78
|
durationMs: performance.now() - startedAt,
|
|
36
79
|
})
|
|
37
80
|
throw err
|
|
81
|
+
} finally {
|
|
82
|
+
currentStep = prev
|
|
38
83
|
}
|
|
39
84
|
}
|
|
40
85
|
|
|
41
86
|
const step = {
|
|
42
|
-
run: ({name, handler: fn}) => track(name || '
|
|
87
|
+
run: ({name, handler: fn}) => track(name || '', 'run', () => fn({logger, attempt: 1})),
|
|
88
|
+
wait: ({name, duration}) =>
|
|
89
|
+
track(name || '', 'wait', async () => {
|
|
90
|
+
await io.wait(durationToMs(duration))
|
|
91
|
+
return undefined
|
|
92
|
+
}),
|
|
93
|
+
waitForCondition: ({name, initial, poller, next}) =>
|
|
94
|
+
track(name || '', 'wait-for-condition', async () => {
|
|
95
|
+
let state = initial
|
|
96
|
+
let attempt = 1
|
|
97
|
+
let polling = true
|
|
98
|
+
while (polling) {
|
|
99
|
+
state = await poller(state, {logger, attempt})
|
|
100
|
+
const decision = next(state, {attempt})
|
|
101
|
+
if (decision.shouldRetry) {
|
|
102
|
+
await io.wait(durationToMs(decision.delay))
|
|
103
|
+
attempt += 1
|
|
104
|
+
} else {
|
|
105
|
+
polling = false
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return state
|
|
109
|
+
}),
|
|
43
110
|
}
|
|
44
111
|
|
|
45
112
|
return handler({context, event, step, logger})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DurableLogEvent, DurableRuntimeEvent, DurableStepEvent } from '../types.js';
|
|
2
|
+
type DurableLogLine = Pick<DurableLogEvent, 'level' | 'message'>;
|
|
3
|
+
type DurableJsonStep = DurableStepEvent & {
|
|
4
|
+
logs: DurableLogLine[];
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Records a durable log event
|
|
8
|
+
*/
|
|
9
|
+
export declare const createDurableJsonCollector: () => {
|
|
10
|
+
record: (event: DurableRuntimeEvent) => void;
|
|
11
|
+
result: () => {
|
|
12
|
+
steps: DurableJsonStep[];
|
|
13
|
+
logs: DurableLogLine[];
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Records a durable log event
|
|
3
|
+
*/
|
|
4
|
+
export const createDurableJsonCollector = () => {
|
|
5
|
+
const steps = [];
|
|
6
|
+
const logLines = [];
|
|
7
|
+
const activeSteps = new Map();
|
|
8
|
+
function record(event) {
|
|
9
|
+
if (event.kind === 'log') {
|
|
10
|
+
const logLine = {
|
|
11
|
+
level: event.level,
|
|
12
|
+
message: event.message,
|
|
13
|
+
};
|
|
14
|
+
if (event.step === null) {
|
|
15
|
+
logLines.push(logLine);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const step = activeSteps.get(event.step);
|
|
19
|
+
if (step) {
|
|
20
|
+
step.logs.push(logLine);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
logLines.push(logLine);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (event.phase === 'start') {
|
|
27
|
+
const step = {
|
|
28
|
+
...event,
|
|
29
|
+
logs: [],
|
|
30
|
+
};
|
|
31
|
+
steps.push(step);
|
|
32
|
+
activeSteps.set(event.name, step);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const step = activeSteps.get(event.name);
|
|
36
|
+
if (!step)
|
|
37
|
+
return;
|
|
38
|
+
step.phase = event.phase;
|
|
39
|
+
step.durationMs = event.durationMs;
|
|
40
|
+
if (event.phase === 'complete') {
|
|
41
|
+
step.output = event.output;
|
|
42
|
+
}
|
|
43
|
+
if (event.phase === 'error') {
|
|
44
|
+
step.error = event.error;
|
|
45
|
+
}
|
|
46
|
+
activeSteps.delete(event.name);
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
record,
|
|
50
|
+
result: () => ({ steps, logs: logLines }),
|
|
51
|
+
};
|
|
52
|
+
};
|
|
@@ -47,7 +47,7 @@ export default async function invoke(resource, payload, context, options) {
|
|
|
47
47
|
if (!resource.src) {
|
|
48
48
|
throw new Error(`Function resource "${resource.name}" is missing the 'src' property.`);
|
|
49
49
|
}
|
|
50
|
-
const { forceColor = true, timeout = 10, onNestedInvoke, depth = 0, callStack = [], onStepEvent = () => { }, } = options;
|
|
50
|
+
const { forceColor = true, timeout = 10, onNestedInvoke, depth = 0, callStack = [], onStepEvent = () => { }, noWait = false, } = options;
|
|
51
51
|
// `payload.payload` is the event body for every function type: the document for
|
|
52
52
|
// GROQ-based events, whatever the producer sent for the rest. The handler always
|
|
53
53
|
// receives it as `event.data` (see the `payload` built in `start()` below).
|
|
@@ -306,6 +306,7 @@ export default async function invoke(resource, payload, context, options) {
|
|
|
306
306
|
srcPath: functionPath,
|
|
307
307
|
payload,
|
|
308
308
|
isDurable: resource.type === SANITY_FUNCTION_DURABLE,
|
|
309
|
+
noWait,
|
|
309
310
|
};
|
|
310
311
|
child.send(JSON.stringify(startMessage));
|
|
311
312
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Package managers this CLI can name in the commands it prints. */
|
|
2
|
+
export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
|
|
3
|
+
/**
|
|
4
|
+
* Detect the package manager for a project.
|
|
5
|
+
*
|
|
6
|
+
* `npm_config_user_agent` is first then lockfile detection.
|
|
7
|
+
*/
|
|
8
|
+
export declare function detectPackageManager(dir?: string): PackageManager | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* The command that runs this CLI, matched to the detected package manager.
|
|
11
|
+
* Falls back to `npx`
|
|
12
|
+
*
|
|
13
|
+
* Yarn is weird: detected from a lockfile alone also falls bac
|
|
14
|
+
* lockfile name does not differentiate Yarn 1 vs Yarn 2+
|
|
15
|
+
*/
|
|
16
|
+
export declare function runCommand(bin: string, dir?: string): string;
|
|
17
|
+
/** The command that installs dependencies, matched to the detected package manager. */
|
|
18
|
+
export declare function installCommand(dir?: string): string;
|
|
19
|
+
/** Clear the lockfile lookup cache. Tests use this after they move fixtures. */
|
|
20
|
+
export declare function resetPackageManagerCache(): void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { basename } from 'node:path';
|
|
2
|
+
import { getBinCommand, getRunningPackageManager } from '@sanity/cli-core/package-manager';
|
|
3
|
+
import * as find from 'empathic/find';
|
|
4
|
+
/**
|
|
5
|
+
* Lockfile names in priority order
|
|
6
|
+
*/
|
|
7
|
+
const LOCKFILES = {
|
|
8
|
+
'pnpm-lock.yaml': 'pnpm',
|
|
9
|
+
'yarn.lock': 'yarn',
|
|
10
|
+
'bun.lock': 'bun',
|
|
11
|
+
'bun.lockb': 'bun',
|
|
12
|
+
'package-lock.json': 'npm',
|
|
13
|
+
};
|
|
14
|
+
const LOCKFILE_NAMES = Object.keys(LOCKFILES);
|
|
15
|
+
/** Minimal user agents, so the lockfile path reuses the same command mapping. */
|
|
16
|
+
const SYNTHETIC_USER_AGENTS = {
|
|
17
|
+
npm: 'npm/0',
|
|
18
|
+
pnpm: 'pnpm/0',
|
|
19
|
+
yarn: 'yarn/0',
|
|
20
|
+
bun: 'bun/0',
|
|
21
|
+
};
|
|
22
|
+
const lockfileCache = new Map();
|
|
23
|
+
/** Find the package manager a lockfile at or above `dir` implies. */
|
|
24
|
+
function detectFromLockfile(dir) {
|
|
25
|
+
if (lockfileCache.has(dir))
|
|
26
|
+
return lockfileCache.get(dir);
|
|
27
|
+
const found = find.any(LOCKFILE_NAMES, { cwd: dir });
|
|
28
|
+
const manager = found ? LOCKFILES[basename(found)] : undefined;
|
|
29
|
+
lockfileCache.set(dir, manager);
|
|
30
|
+
return manager;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Detect the package manager for a project.
|
|
34
|
+
*
|
|
35
|
+
* `npm_config_user_agent` is first then lockfile detection.
|
|
36
|
+
*/
|
|
37
|
+
export function detectPackageManager(dir = process.cwd()) {
|
|
38
|
+
return getRunningPackageManager() ?? detectFromLockfile(dir);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The command that runs this CLI, matched to the detected package manager.
|
|
42
|
+
* Falls back to `npx`
|
|
43
|
+
*
|
|
44
|
+
* Yarn is weird: detected from a lockfile alone also falls bac
|
|
45
|
+
* lockfile name does not differentiate Yarn 1 vs Yarn 2+
|
|
46
|
+
*/
|
|
47
|
+
export function runCommand(bin, dir) {
|
|
48
|
+
const running = getRunningPackageManager();
|
|
49
|
+
if (running)
|
|
50
|
+
return getBinCommand({ bin });
|
|
51
|
+
const fromLockfile = detectFromLockfile(dir ?? process.cwd());
|
|
52
|
+
if (!fromLockfile || fromLockfile === 'yarn')
|
|
53
|
+
return `npx ${bin}`;
|
|
54
|
+
return getBinCommand({ bin, userAgent: SYNTHETIC_USER_AGENTS[fromLockfile] });
|
|
55
|
+
}
|
|
56
|
+
/** The command that installs dependencies, matched to the detected package manager. */
|
|
57
|
+
export function installCommand(dir) {
|
|
58
|
+
return `${detectPackageManager(dir) ?? 'npm'} install`;
|
|
59
|
+
}
|
|
60
|
+
/** Clear the lockfile lookup cache. Tests use this after they move fixtures. */
|
|
61
|
+
export function resetPackageManagerCache() {
|
|
62
|
+
lockfileCache.clear();
|
|
63
|
+
}
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -162,7 +162,9 @@ export interface InvokeExecutionOptions {
|
|
|
162
162
|
/** Function names already on the invoke call stack (innermost last), used to detect cycles. @internal */
|
|
163
163
|
callStack?: string[];
|
|
164
164
|
/** Stream a durable step transition to the caller. @internal */
|
|
165
|
-
onStepEvent?: (event:
|
|
165
|
+
onStepEvent?: (event: DurableRuntimeEvent) => void;
|
|
166
|
+
/** Don't wait the full duration during a wait durable event @internal */
|
|
167
|
+
noWait?: boolean;
|
|
166
168
|
}
|
|
167
169
|
/**
|
|
168
170
|
* Re-entrant callback that executes a named function from the blueprint on behalf
|
|
@@ -181,6 +183,7 @@ export type ParentToChildMessage = {
|
|
|
181
183
|
srcPath: string;
|
|
182
184
|
payload: unknown;
|
|
183
185
|
isDurable?: boolean;
|
|
186
|
+
noWait?: boolean;
|
|
184
187
|
} | {
|
|
185
188
|
type: 'invoke-response';
|
|
186
189
|
id: string;
|
|
@@ -195,7 +198,7 @@ export type ParentToChildMessage = {
|
|
|
195
198
|
error: InvocationError;
|
|
196
199
|
} | {
|
|
197
200
|
type: 'step-event';
|
|
198
|
-
event:
|
|
201
|
+
event: DurableRuntimeEvent;
|
|
199
202
|
};
|
|
200
203
|
/**
|
|
201
204
|
* IPC messages sent from a function child process back up to the parent.
|
|
@@ -217,7 +220,7 @@ export type ChildToParentMessage = {
|
|
|
217
220
|
error?: InvocationError;
|
|
218
221
|
} | {
|
|
219
222
|
type: 'step-event';
|
|
220
|
-
event:
|
|
223
|
+
event: DurableRuntimeEvent;
|
|
221
224
|
};
|
|
222
225
|
/** @internal */
|
|
223
226
|
export interface InvocationResponse {
|
|
@@ -259,8 +262,17 @@ export interface FunctionLog {
|
|
|
259
262
|
requestId: string;
|
|
260
263
|
level: string;
|
|
261
264
|
message: string;
|
|
265
|
+
operationName?: string;
|
|
266
|
+
attempt?: number;
|
|
267
|
+
operationId?: string;
|
|
268
|
+
executionArn?: string;
|
|
262
269
|
}
|
|
263
270
|
/** @internal */
|
|
271
|
+
export type FunctionLogJson = Omit<FunctionLog, 'executionArn' | 'operationId' | 'operationName'> & {
|
|
272
|
+
durableContext?: 'handler' | 'step';
|
|
273
|
+
step?: string;
|
|
274
|
+
};
|
|
275
|
+
/** @internal */
|
|
264
276
|
export declare enum BlueprintParserErrorType {
|
|
265
277
|
InvalidProperty = "invalid_property",
|
|
266
278
|
InvalidVersion = "invalid_version",
|
|
@@ -301,7 +313,7 @@ export type Warning = {
|
|
|
301
313
|
suggestions: string[];
|
|
302
314
|
};
|
|
303
315
|
/** @internal */
|
|
304
|
-
export type DurableOperationSteps = 'run';
|
|
316
|
+
export type DurableOperationSteps = 'run' | 'wait' | 'waitForCondition';
|
|
305
317
|
/** @internal */
|
|
306
318
|
export type DurableStepPhase = 'start' | 'complete' | 'error';
|
|
307
319
|
/**
|
|
@@ -315,6 +327,15 @@ export interface DurableStepEvent {
|
|
|
315
327
|
error?: InvocationError;
|
|
316
328
|
durationMs?: number;
|
|
317
329
|
}
|
|
330
|
+
export interface DurableLogEvent {
|
|
331
|
+
kind: 'log';
|
|
332
|
+
phase: 'log';
|
|
333
|
+
step: string | null;
|
|
334
|
+
level: 'info' | 'warn' | 'error';
|
|
335
|
+
message: string;
|
|
336
|
+
timestamp?: string;
|
|
337
|
+
}
|
|
338
|
+
export type DurableRuntimeEvent = DurableStepEvent | DurableLogEvent;
|
|
318
339
|
export interface FunctionTestFlags {
|
|
319
340
|
data?: string;
|
|
320
341
|
event?: string;
|
|
@@ -333,5 +354,7 @@ export interface FunctionTestFlags {
|
|
|
333
354
|
'document-id-before'?: string;
|
|
334
355
|
'document-id-after'?: string;
|
|
335
356
|
'media-library-id'?: string;
|
|
357
|
+
'no-wait'?: boolean;
|
|
358
|
+
json?: boolean;
|
|
336
359
|
}
|
|
337
360
|
export {};
|
package/oclif.manifest.json
CHANGED
|
@@ -2755,6 +2755,13 @@
|
|
|
2755
2755
|
"hasDynamicHelp": false,
|
|
2756
2756
|
"multiple": false,
|
|
2757
2757
|
"type": "option"
|
|
2758
|
+
},
|
|
2759
|
+
"no-wait": {
|
|
2760
|
+
"description": "Skip durable wait delays instead of sleeping",
|
|
2761
|
+
"name": "no-wait",
|
|
2762
|
+
"required": false,
|
|
2763
|
+
"allowNo": false,
|
|
2764
|
+
"type": "boolean"
|
|
2758
2765
|
}
|
|
2759
2766
|
},
|
|
2760
2767
|
"hasDynamicHelp": false,
|
|
@@ -3141,5 +3148,5 @@
|
|
|
3141
3148
|
]
|
|
3142
3149
|
}
|
|
3143
3150
|
},
|
|
3144
|
-
"version": "17.
|
|
3151
|
+
"version": "17.10.0-next.g5e0bba6"
|
|
3145
3152
|
}
|
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": "17.
|
|
4
|
+
"version": "17.10.0-next.g5e0bba6",
|
|
5
5
|
"author": "Sanity Runtime Team",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"@oclif/test": "^4.1.22",
|
|
101
101
|
"@playwright/test": "^1.62.1",
|
|
102
102
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
103
|
-
"@sanity/functions": "^1.
|
|
103
|
+
"@sanity/functions": "^1.7.1",
|
|
104
104
|
"@types/adm-zip": "^0.5.8",
|
|
105
105
|
"@types/cardinal": "^2.1.1",
|
|
106
106
|
"@types/mime-types": "^3.0.1",
|