@sanity/runtime-cli 17.15.0-next.ge190195 → 17.16.0-app-functions.ge0a25ea

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.
Files changed (47) hide show
  1. package/README.md +19 -19
  2. package/dist/actions/blueprints/assets.d.ts +3 -3
  3. package/dist/actions/blueprints/assets.js +3 -3
  4. package/dist/actions/blueprints/pre-deploy.js +3 -3
  5. package/dist/actions/blueprints/process-assets.js +3 -2
  6. package/dist/actions/blueprints/stacks.d.ts +7 -2
  7. package/dist/actions/blueprints/stacks.js +10 -6
  8. package/dist/actions/blueprints/wait-for-operation.d.ts +1 -0
  9. package/dist/actions/blueprints/wait-for-operation.js +1 -1
  10. package/dist/cores/blueprints/deploy.d.ts +8 -0
  11. package/dist/cores/blueprints/deploy.js +12 -4
  12. package/dist/cores/functions/test.js +15 -4
  13. package/dist/functions/artifacts.d.ts +13 -0
  14. package/dist/functions/artifacts.js +26 -0
  15. package/dist/functions/build.d.ts +15 -0
  16. package/dist/functions/build.js +27 -0
  17. package/dist/functions/contractPlugin.d.ts +7 -0
  18. package/dist/functions/contractPlugin.js +32 -0
  19. package/dist/functions/contracts/schema.d.ts +22 -0
  20. package/dist/functions/contracts/schema.js +99 -0
  21. package/dist/functions/contracts/validation.d.ts +3 -0
  22. package/dist/functions/contracts/validation.js +66 -0
  23. package/dist/functions/contracts.d.ts +20 -0
  24. package/dist/functions/contracts.js +119 -0
  25. package/dist/functions/deploy.d.ts +15 -0
  26. package/dist/functions/deploy.js +60 -0
  27. package/dist/functions/stack.d.ts +18 -0
  28. package/dist/functions/stack.js +84 -0
  29. package/dist/server/app.js +2 -2
  30. package/dist/utils/blueprints/group-resources.d.ts +2 -1
  31. package/dist/utils/blueprints/group-resources.js +3 -3
  32. package/dist/utils/blueprints/resolve-deployed-resources.d.ts +2 -2
  33. package/dist/utils/blueprints/resolve-deployed-resources.js +4 -4
  34. package/dist/utils/bundles/prepare-asset.d.ts +3 -3
  35. package/dist/utils/bundles/prepare-asset.js +8 -7
  36. package/dist/utils/functions/child-runtime/durable.js +99 -22
  37. package/dist/utils/functions/child-runtime/step-history.d.ts +15 -0
  38. package/dist/utils/functions/child-runtime/step-history.js +52 -0
  39. package/dist/utils/functions/invoke/local.js +19 -8
  40. package/dist/utils/functions/invoke/resolve-invoke-type.d.ts +2 -2
  41. package/dist/utils/functions/invoke/resolve-invoke-type.js +2 -2
  42. package/dist/utils/functions/transpile/function.d.ts +7 -1
  43. package/dist/utils/functions/transpile/function.js +15 -9
  44. package/dist/utils/types.d.ts +19 -12
  45. package/dist/utils/types.js +1 -1
  46. package/oclif.manifest.json +1 -1
  47. package/package.json +23 -2
package/README.md CHANGED
@@ -90,7 +90,7 @@ EXAMPLES
90
90
  $ sanity-run blueprints add function --name my-function --fn-type document-create --fn-type document-update --lang js
91
91
  ```
92
92
 
93
- _See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/blueprints/add.ts)_
93
+ _See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/blueprints/add.ts)_
94
94
 
95
95
  ## `sanity-run blueprints config`
96
96
 
@@ -127,7 +127,7 @@ EXAMPLES
127
127
  $ sanity-run blueprints config --edit --project-id <projectId> --stack <name-or-id>
128
128
  ```
129
129
 
130
- _See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/blueprints/config.ts)_
130
+ _See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/blueprints/config.ts)_
131
131
 
132
132
  ## `sanity-run blueprints deploy`
133
133
 
@@ -183,7 +183,7 @@ EXAMPLES
183
183
  $ sanity-run blueprints deploy --new-stack-name <new-name>
184
184
  ```
185
185
 
186
- _See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/blueprints/deploy.ts)_
186
+ _See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/blueprints/deploy.ts)_
187
187
 
188
188
  ## `sanity-run blueprints destroy`
189
189
 
@@ -221,7 +221,7 @@ EXAMPLES
221
221
  $ sanity-run blueprints destroy --stack <name-or-id> --project-id <projectId> --force --no-wait
222
222
  ```
223
223
 
224
- _See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/blueprints/destroy.ts)_
224
+ _See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/blueprints/destroy.ts)_
225
225
 
226
226
  ## `sanity-run blueprints doctor`
227
227
 
@@ -253,7 +253,7 @@ EXAMPLES
253
253
  $ sanity-run blueprints doctor --fix
254
254
  ```
255
255
 
256
- _See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/blueprints/doctor.ts)_
256
+ _See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/blueprints/doctor.ts)_
257
257
 
258
258
  ## `sanity-run blueprints info`
259
259
 
@@ -291,7 +291,7 @@ EXAMPLES
291
291
  $ sanity-run blueprints info --organization-id <orgId> --stack <name-or-id>
292
292
  ```
293
293
 
294
- _See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/blueprints/info.ts)_
294
+ _See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/blueprints/info.ts)_
295
295
 
296
296
  ## `sanity-run blueprints init [DIR]`
297
297
 
@@ -355,7 +355,7 @@ EXAMPLES
355
355
  $ sanity-run blueprints init old-stack --type <json|js|ts> --project-id <projectId> --stack-id <existingStackId>
356
356
  ```
357
357
 
358
- _See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/blueprints/init.ts)_
358
+ _See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/blueprints/init.ts)_
359
359
 
360
360
  ## `sanity-run blueprints logs`
361
361
 
@@ -401,7 +401,7 @@ EXAMPLES
401
401
  $ sanity-run blueprints logs --before 2026-05-01T00:00:00Z
402
402
  ```
403
403
 
404
- _See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/blueprints/logs.ts)_
404
+ _See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/blueprints/logs.ts)_
405
405
 
406
406
  ## `sanity-run blueprints mint-deploy-token`
407
407
 
@@ -446,7 +446,7 @@ EXAMPLES
446
446
  $ sanity-run blueprints mint-deploy-token --organization-id <orgId>
447
447
  ```
448
448
 
449
- _See code: [src/commands/blueprints/mint-deploy-token.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/blueprints/mint-deploy-token.ts)_
449
+ _See code: [src/commands/blueprints/mint-deploy-token.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/blueprints/mint-deploy-token.ts)_
450
450
 
451
451
  ## `sanity-run blueprints plan`
452
452
 
@@ -479,7 +479,7 @@ EXAMPLES
479
479
  $ sanity-run blueprints plan --organization-id <orgId> --stack <name-or-id>
480
480
  ```
481
481
 
482
- _See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/blueprints/plan.ts)_
482
+ _See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/blueprints/plan.ts)_
483
483
 
484
484
  ## `sanity-run blueprints promote`
485
485
 
@@ -515,7 +515,7 @@ EXAMPLES
515
515
  $ sanity-run blueprints promote --new-stack-name <new-name>
516
516
  ```
517
517
 
518
- _See code: [src/commands/blueprints/promote.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/blueprints/promote.ts)_
518
+ _See code: [src/commands/blueprints/promote.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/blueprints/promote.ts)_
519
519
 
520
520
  ## `sanity-run blueprints stacks`
521
521
 
@@ -556,7 +556,7 @@ EXAMPLES
556
556
  $ sanity-run blueprints stacks --organization-id <organizationId> --include-projects
557
557
  ```
558
558
 
559
- _See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/blueprints/stacks.ts)_
559
+ _See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/blueprints/stacks.ts)_
560
560
 
561
561
  ## `sanity-run functions add`
562
562
 
@@ -608,7 +608,7 @@ EXAMPLES
608
608
  $ sanity-run functions add --name my-function --type document-create --type document-update --lang js
609
609
  ```
610
610
 
611
- _See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/functions/add.ts)_
611
+ _See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/functions/add.ts)_
612
612
 
613
613
  ## `sanity-run functions dev`
614
614
 
@@ -643,7 +643,7 @@ EXAMPLES
643
643
  $ sanity-run functions dev --timeout 60
644
644
  ```
645
645
 
646
- _See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/functions/dev.ts)_
646
+ _See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/functions/dev.ts)_
647
647
 
648
648
  ## `sanity-run functions env add NAME KEY VALUE`
649
649
 
@@ -676,7 +676,7 @@ EXAMPLES
676
676
  $ sanity-run functions env add --stack <name-or-id> MyFunction API_URL https://api.example.com/
677
677
  ```
678
678
 
679
- _See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/functions/env/add.ts)_
679
+ _See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/functions/env/add.ts)_
680
680
 
681
681
  ## `sanity-run functions env list NAME`
682
682
 
@@ -706,7 +706,7 @@ EXAMPLES
706
706
  $ sanity-run functions env list --stack <name-or-id> MyFunction
707
707
  ```
708
708
 
709
- _See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/functions/env/list.ts)_
709
+ _See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/functions/env/list.ts)_
710
710
 
711
711
  ## `sanity-run functions env remove NAME KEY`
712
712
 
@@ -738,7 +738,7 @@ EXAMPLES
738
738
  $ sanity-run functions env remove --stack <name-or-id> MyFunction API_URL
739
739
  ```
740
740
 
741
- _See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/functions/env/remove.ts)_
741
+ _See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/functions/env/remove.ts)_
742
742
 
743
743
  ## `sanity-run functions logs [NAME]`
744
744
 
@@ -778,7 +778,7 @@ EXAMPLES
778
778
  $ sanity-run functions logs <name> --delete
779
779
  ```
780
780
 
781
- _See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/functions/logs.ts)_
781
+ _See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/functions/logs.ts)_
782
782
 
783
783
  ## `sanity-run functions test [NAME]`
784
784
 
@@ -836,7 +836,7 @@ EXAMPLES
836
836
  $ sanity-run functions test <name> --event update --data-before '{ "title": "before" }' --data-after '{ "title": "after" }'
837
837
  ```
838
838
 
839
- _See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v17.15.0-next.ge190195/src/commands/functions/test.ts)_
839
+ _See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v17.16.0-app-functions.ge0a25ea/src/commands/functions/test.ts)_
840
840
 
841
841
  ## `sanity-run help [COMMAND]`
842
842
 
@@ -1,5 +1,5 @@
1
1
  import type { BlueprintResource } from '@sanity/blueprints';
2
- import type { AuthParams, InstallerType, PrepAssetFn } from '../../utils/types.js';
2
+ import type { AuthParams, InstallerType, PrepAssetFn, ResolvedResource } from '../../utils/types.js';
3
3
  export declare const assetCheckUrl: string;
4
4
  export declare const assetStashUrl: string;
5
5
  export type StashAssetResult = {
@@ -18,8 +18,8 @@ export type StashAssetResult = {
18
18
  success: false;
19
19
  error: string;
20
20
  };
21
- export declare function stashAsset<R extends BlueprintResource>({ resource, prepAsset, auth, blueprintFileDir, fetchFn, installer, }: {
22
- resource: R;
21
+ export declare function stashAsset<R extends BlueprintResource>({ resolvedResource, prepAsset, auth, blueprintFileDir, fetchFn, installer, }: {
22
+ resolvedResource: ResolvedResource<R>;
23
23
  prepAsset: PrepAssetFn<R>;
24
24
  auth: AuthParams;
25
25
  blueprintFileDir: string;
@@ -4,10 +4,10 @@ import getHeaders from '../../utils/get-headers.js';
4
4
  const assetsUrl = blueprintsUrl('assets');
5
5
  export const assetCheckUrl = `${assetsUrl}/check`;
6
6
  export const assetStashUrl = `${assetsUrl}/stash`;
7
- export async function stashAsset({ resource, prepAsset, auth, blueprintFileDir, fetchFn, installer, }) {
7
+ export async function stashAsset({ resolvedResource, prepAsset, auth, blueprintFileDir, fetchFn, installer, }) {
8
8
  let cleanup = async () => { };
9
9
  try {
10
- const prepResult = await prepAsset({ resource, blueprintFileDir, installer });
10
+ const prepResult = await prepAsset({ resolvedResource, blueprintFileDir, installer });
11
11
  if (prepResult.success === false) {
12
12
  await prepResult.cleanup();
13
13
  return {
@@ -26,7 +26,7 @@ export async function stashAsset({ resource, prepAsset, auth, blueprintFileDir,
26
26
  assetParameter: prepResult.assetParameter,
27
27
  metadata: prepResult.metadata,
28
28
  cleanup,
29
- resourceName: resource.name,
29
+ resourceName: resolvedResource.resource.name,
30
30
  auth,
31
31
  fetchFn,
32
32
  });
@@ -18,7 +18,7 @@ const preDeployConfigs = [
18
18
  resourceType: (type) => type in BUNDLE_SPECS,
19
19
  async prepareAsset(options) {
20
20
  return prepareBundleAsset({
21
- resource: options.resource,
21
+ resolvedResource: options.resolvedResource,
22
22
  blueprintFileDir: options.blueprintFileDir,
23
23
  });
24
24
  },
@@ -30,7 +30,7 @@ const preDeployConfigs = [
30
30
  resourceType: (type) => type.startsWith(SANITY_FUNCTION_PREFIX),
31
31
  async prepareAsset(options) {
32
32
  return prepareFunctionAsset({
33
- resource: options.resource,
33
+ resource: options.resolvedResource.resource,
34
34
  blueprintFileDir: options.blueprintFileDir,
35
35
  installer: options.installer,
36
36
  });
@@ -74,7 +74,7 @@ export async function preDeploy(options) {
74
74
  });
75
75
  const assetResources = [];
76
76
  for (const r of resolvedResources) {
77
- const config = getPredeployConfig(r);
77
+ const config = getPredeployConfig(r.resource);
78
78
  if (typeof config !== 'undefined' && typeof config.prepareAsset === 'function') {
79
79
  assetResources.push({ resource: r, prepareAsset: config.prepareAsset });
80
80
  }
@@ -42,13 +42,14 @@ function getAssetConcurrency() {
42
42
  const configured = Number(env.SANITY_ASSET_CONCURRENCY);
43
43
  return Number.isSafeInteger(configured) && configured > 0 ? configured : DEFAULT_ASSET_CONCURRENCY;
44
44
  }
45
- async function processAsset(resource, prepAsset, options) {
45
+ async function processAsset(resolvedResource, prepAsset, options) {
46
+ const { resource } = resolvedResource;
46
47
  const { auth, blueprintFileDir, installer, fetchFn } = options;
47
48
  let assetTimeoutTimer;
48
49
  let result;
49
50
  try {
50
51
  result = await Promise.race([
51
- stashAsset({ resource, prepAsset, blueprintFileDir, auth, fetchFn, installer }),
52
+ stashAsset({ resolvedResource, prepAsset, blueprintFileDir, auth, fetchFn, installer }),
52
53
  new Promise((_, reject) => {
53
54
  assetTimeoutTimer = setTimeout(() => {
54
55
  reject(new Error(`Processing ${resource.name} timed out after ${assetTimeoutS}s`));
@@ -13,7 +13,11 @@ type ListStacksResponse = {
13
13
  stacks?: unknown;
14
14
  response?: Response;
15
15
  };
16
- export declare function listStacks(auth: AuthParams, logger: Logger): Promise<ListStacksResponse>;
16
+ export declare function listStacks(auth: AuthParams, logger: Logger, options?: {
17
+ fetchFn?: typeof fetch;
18
+ cursor?: string;
19
+ limit?: number;
20
+ }): Promise<ListStacksResponse>;
17
21
  type GetStackResponse = {
18
22
  ok: true;
19
23
  error: null;
@@ -31,10 +35,11 @@ export declare function getStack({ stackId, auth, fetchFn, }: {
31
35
  fetchFn: typeof fetch;
32
36
  }): Promise<GetStackResponse>;
33
37
  type CreateStackResponse = GetStackResponse;
34
- export declare function createStack({ stackMutation, auth, logger, }: {
38
+ export declare function createStack({ stackMutation, auth, logger, fetchFn, }: {
35
39
  stackMutation: StackMutation;
36
40
  auth: AuthParams;
37
41
  logger: Logger;
42
+ fetchFn?: typeof fetch;
38
43
  }): Promise<CreateStackResponse>;
39
44
  export declare function createEmptyStack({ token, scopeType, scopeId, name, logger, }: {
40
45
  token: string;
@@ -3,10 +3,15 @@ import getHeaders from '../../utils/get-headers.js';
3
3
  import { getRequestId } from '../../utils/request-id.js';
4
4
  import { createTracedFetch } from '../../utils/traced-fetch.js';
5
5
  export const stacksUrl = blueprintsUrl('stacks');
6
- export async function listStacks(auth, logger) {
7
- const fetchFn = createTracedFetch(logger);
6
+ export async function listStacks(auth, logger, options = {}) {
7
+ const fetchFn = options.fetchFn ?? createTracedFetch(logger);
8
+ const url = new URL(stacksUrl);
9
+ if (options.cursor)
10
+ url.searchParams.set('cursor', options.cursor);
11
+ if (options.limit !== undefined)
12
+ url.searchParams.set('limit', String(options.limit));
8
13
  try {
9
- const response = await fetchFn(stacksUrl, {
14
+ const response = await fetchFn(url.toString(), {
10
15
  method: 'GET',
11
16
  headers: getHeaders(auth),
12
17
  });
@@ -27,7 +32,7 @@ export async function listStacks(auth, logger) {
27
32
  }
28
33
  export async function getStack({ stackId, auth, fetchFn, }) {
29
34
  try {
30
- const response = await fetchFn(`${stacksUrl}/${stackId}`, {
35
+ const response = await fetchFn(`${stacksUrl}/${encodeURIComponent(stackId)}`, {
31
36
  method: 'GET',
32
37
  headers: getHeaders(auth),
33
38
  });
@@ -46,9 +51,8 @@ export async function getStack({ stackId, auth, fetchFn, }) {
46
51
  };
47
52
  }
48
53
  }
49
- export async function createStack({ stackMutation, auth, logger, }) {
54
+ export async function createStack({ stackMutation, auth, logger, fetchFn = createTracedFetch(logger), }) {
50
55
  try {
51
- const fetchFn = createTracedFetch(logger);
52
56
  const response = await fetchFn(stacksUrl, {
53
57
  method: 'POST',
54
58
  headers: getHeaders(auth),
@@ -8,6 +8,7 @@ export interface WaitForOperationOptions {
8
8
  log: Logger;
9
9
  bin: string;
10
10
  verbose?: boolean;
11
+ fetchFn?: typeof fetch;
11
12
  /** Keep the operation queryable after the stack is gone (destroy). */
12
13
  includeDestroyed?: boolean;
13
14
  /** Noun for the idle message, e.g. "deployment" or "destruction". */
@@ -9,7 +9,7 @@ import { classifyOperationPoll, getOperation } from './operations.js';
9
9
  */
10
10
  export async function waitForOperation(options) {
11
11
  const { stackId, operationId, auth, log, bin, verbose = false, includeDestroyed, progressNoun, } = options;
12
- const fetchFn = createTracedFetch(log);
12
+ const fetchFn = options.fetchFn ?? createTracedFetch(log);
13
13
  const waitFor = createWaitFor({
14
14
  bin,
15
15
  log,
@@ -1,3 +1,4 @@
1
+ import type { BlueprintResource } from '@sanity/blueprints';
1
2
  import type { ReadBlueprintResult } from '../../actions/blueprints/blueprint.js';
2
3
  import type { AuthParams, ScopeType, Stack } from '../../utils/types.js';
3
4
  import type { CoreConfig, CoreResult } from '../index.js';
@@ -19,3 +20,10 @@ export interface BlueprintDeployOptions extends CoreConfig {
19
20
  };
20
21
  }
21
22
  export declare function blueprintDeployCore(options: BlueprintDeployOptions): Promise<CoreResult>;
23
+ export interface ResourceDeployOptions extends Omit<BlueprintDeployOptions, 'blueprint'> {
24
+ resources: BlueprintResource[];
25
+ workDir: string;
26
+ fetchFn?: typeof fetch;
27
+ }
28
+ /** Deploy an in-memory resource list using the same pipeline as a Blueprint file. */
29
+ export declare function deployResourcesCore(options: ResourceDeployOptions): Promise<CoreResult>;
@@ -14,16 +14,23 @@ import { styleText } from '../../utils/style-text.js';
14
14
  import { createTracedFetch } from '../../utils/traced-fetch.js';
15
15
  import { getWarnings } from '../../utils/warnings.js';
16
16
  export async function blueprintDeployCore(options) {
17
- const { bin = 'sanity', log: logger, auth, stackId, scopeType, scopeId, deployedStack, blueprint, cliVersion, flags, } = options;
17
+ return deployResourcesCore({
18
+ ...options,
19
+ resources: options.blueprint.resources,
20
+ workDir: dirname(options.blueprint.fileInfo.blueprintFilePath),
21
+ });
22
+ }
23
+ /** Deploy an in-memory resource list using the same pipeline as a Blueprint file. */
24
+ export async function deployResourcesCore(options) {
25
+ const { bin = 'sanity', log: logger, auth, stackId, scopeType, scopeId, deployedStack, workDir: blueprintFileDir, cliVersion, flags, } = options;
18
26
  const { verbose } = flags;
19
27
  const noWait = flags['no-wait'] || false;
20
28
  const stackName = flags['new-stack-name'] ?? deployedStack.name;
21
29
  const installer = flags['fn-installer'] || undefined;
22
- const blueprintFileDir = dirname(blueprint.fileInfo.blueprintFilePath);
23
30
  const workspaceWarnings = getWarnings({ dir: blueprintFileDir });
24
31
  logger(`Deploying "${stackName}" ${niceId(deployedStack.id)}...`);
25
32
  try {
26
- const fetchFn = createTracedFetch(logger);
33
+ const fetchFn = options.fetchFn ?? createTracedFetch(logger);
27
34
  const { ok: checkOk, stack: currentStack } = await getStack({ stackId, auth, fetchFn });
28
35
  if (!checkOk) {
29
36
  return { success: false, error: 'Failed to check current Stack status' };
@@ -39,7 +46,7 @@ export async function blueprintDeployCore(options) {
39
46
  ],
40
47
  };
41
48
  }
42
- const resources = [...blueprint.resources];
49
+ const resources = [...options.resources];
43
50
  let spinner;
44
51
  const preDeployResult = await preDeploy({
45
52
  scopeType,
@@ -143,6 +150,7 @@ export async function blueprintDeployCore(options) {
143
150
  bin,
144
151
  verbose,
145
152
  progressNoun: 'deployment',
153
+ fetchFn,
146
154
  });
147
155
  if (outcome.type === 'completed') {
148
156
  logger(styleText(['bold', 'green'], 'Stack deployment completed!'));
@@ -55,7 +55,7 @@ export async function functionTestCore(options) {
55
55
  apiHost: config.apiUrl,
56
56
  token: config.token || undefined,
57
57
  withUserToken,
58
- resources: resolvedResources,
58
+ resolvedResources,
59
59
  blueprintFileDir: dirname(blueprint.fileInfo.blueprintFilePath),
60
60
  log,
61
61
  };
@@ -116,7 +116,9 @@ export async function functionTestCore(options) {
116
116
  }
117
117
  };
118
118
  const logNestedRuns = () => {
119
- for (const run of [...nestedRuns].sort((a, b) => a.order - b.order)) {
119
+ // Remove buffered logs for durable runs
120
+ const runs = plan.isDurable ? nestedRuns.splice(0) : [...nestedRuns];
121
+ for (const run of runs.sort((a, b) => a.order - b.order)) {
120
122
  // Skip if is Durable so log ordering is retained
121
123
  if (run.isLiveDurable)
122
124
  continue;
@@ -155,10 +157,19 @@ export async function functionTestCore(options) {
155
157
  if (event.kind === 'delegate') {
156
158
  logNestedRuns();
157
159
  }
158
- const glyph = STEP_PHASE_GLYPH[event.phase] ?? '•';
160
+ const willRetry = event.phase === 'error' && typeof event.retryDelayMs === 'number';
161
+ const glyph = willRetry ? '⟳' : (STEP_PHASE_GLYPH[event.phase] ?? '•');
159
162
  const duration = typeof event.durationMs === 'number' ? ` (${Math.round(event.durationMs)}ms)` : '';
163
+ const retriesPerformed = (event.attempt ?? 1) - 1;
164
+ let retryNote = '';
165
+ if (willRetry) {
166
+ retryNote = ` retry ${event.attempt} of ${event.maxAttempts}`;
167
+ }
168
+ else if (event.phase === 'error' && retriesPerformed > 0) {
169
+ retryNote = ` failed after ${retriesPerformed} retries`;
170
+ }
160
171
  const detail = event.phase === 'error' && event.error ? ` ${event.error.message}` : '';
161
- lines.push(` ${glyph} ${event.name} [${event.kind}]${duration}${detail}`);
172
+ lines.push(` ${glyph} ${event.name} [${event.kind}]${duration}${detail}${retryNote}`);
162
173
  }
163
174
  return lines;
164
175
  }
@@ -0,0 +1,13 @@
1
+ export declare const functionOutputFileName = "index.js";
2
+ /** Metadata for a compiled function, resolved without loading its handler. */
3
+ export interface FunctionBuild {
4
+ name: string;
5
+ src: string;
6
+ entryPoint: string;
7
+ }
8
+ /** Validate artifacts produced by buildFunction before packaging or deployment. */
9
+ export declare function readFunctionBuild(options: {
10
+ name: string;
11
+ src: string;
12
+ workDir: string;
13
+ }): Promise<FunctionBuild>;
@@ -0,0 +1,26 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { findFunctionEntryPoint } from '../utils/functions/find-entry-point.js';
4
+ export const functionOutputFileName = 'index.js';
5
+ /** Validate artifacts produced by buildFunction before packaging or deployment. */
6
+ export async function readFunctionBuild(options) {
7
+ const { name, workDir } = options;
8
+ const src = path.resolve(workDir, options.src);
9
+ try {
10
+ const pkg = JSON.parse(await readFile(path.join(src, 'package.json'), 'utf8'));
11
+ if (!pkg ||
12
+ typeof pkg !== 'object' ||
13
+ !('main' in pkg) ||
14
+ pkg.main !== functionOutputFileName ||
15
+ !('type' in pkg) ||
16
+ pkg.type !== 'module')
17
+ throw new Error('The function package metadata does not match its build format.');
18
+ const entryPoint = await findFunctionEntryPoint(src, name);
19
+ if (entryPoint !== path.join(src, functionOutputFileName))
20
+ throw new Error(`The compiled entry ${functionOutputFileName} is missing.`);
21
+ return { name, src, entryPoint };
22
+ }
23
+ catch (error) {
24
+ throw new Error(`Function "${name}" is not built. Run sanity build first.`, { cause: error });
25
+ }
26
+ }
@@ -0,0 +1,15 @@
1
+ import { type FunctionContract } from './contracts.js';
2
+ export interface BuildFunctionOptions {
3
+ name: string;
4
+ contract?: FunctionContract;
5
+ /** Function directory or entry file, relative to workDir. */
6
+ src: string;
7
+ workDir: string;
8
+ /** Build output directory, relative to workDir. Its contents are replaced. */
9
+ outDir: string;
10
+ }
11
+ /** Build a standalone ESM function bundle without a blueprint, stack, or ZIP. */
12
+ export declare function buildFunction({ name, src, workDir, outDir, contract, }: BuildFunctionOptions): Promise<{
13
+ outputDir: string;
14
+ }>;
15
+ export { type FunctionBuild, readFunctionBuild } from './artifacts.js';
@@ -0,0 +1,27 @@
1
+ import path from 'node:path';
2
+ import { findFunctionEntryPoint } from '../utils/functions/find-entry-point.js';
3
+ import { transpileFunction } from '../utils/functions/transpile/function.js';
4
+ import { functionOutputFileName } from './artifacts.js';
5
+ import { functionContractPlugin } from './contractPlugin.js';
6
+ import { generateFunctionContracts } from './contracts.js';
7
+ /** Build a standalone ESM function bundle without a blueprint, stack, or ZIP. */
8
+ export async function buildFunction({ name, src, workDir, outDir, contract, }) {
9
+ const functionPath = path.resolve(workDir, src);
10
+ const entryPoint = await findFunctionEntryPoint(functionPath, name);
11
+ const resolvedContract = contract ?? (await generateFunctionContracts({ workDir, functions: [{ name, src }] }))[0];
12
+ if (resolvedContract.entryPoint !== entryPoint || resolvedContract.name !== name)
13
+ throw new Error(`Function contract does not match "${name}".`);
14
+ const validation = functionContractPlugin(resolvedContract);
15
+ const result = await transpileFunction({
16
+ resource: { name, src, type: 'sanity.function.pubsub' },
17
+ functionPath,
18
+ entryPoint: validation.entryPoint,
19
+ plugins: [validation.plugin],
20
+ workDir,
21
+ outDir: path.resolve(workDir, outDir),
22
+ outputFileName: functionOutputFileName,
23
+ bundle: true,
24
+ });
25
+ return { outputDir: result.outputDir };
26
+ }
27
+ export { readFunctionBuild } from './artifacts.js';
@@ -0,0 +1,7 @@
1
+ import type { Plugin } from 'vite';
2
+ import type { FunctionContract } from './contracts.js';
3
+ /** Build a validating PubSub entry around the original handler. */
4
+ export declare function functionContractPlugin(contract: FunctionContract): {
5
+ entryPoint: string;
6
+ plugin: Plugin;
7
+ };
@@ -0,0 +1,32 @@
1
+ import { jsonGuard, validatorSource } from './contracts/validation.js';
2
+ /** Build a validating PubSub entry around the original handler. */
3
+ export function functionContractPlugin(contract) {
4
+ const entryPoint = `virtual:sanity-function-contract:${contract.name}`;
5
+ const resolvedId = `\0${entryPoint}`;
6
+ const source = `import {handler as implementation} from ${JSON.stringify(contract.entryPoint.replaceAll('\\', '/'))}
7
+ ${jsonGuard}
8
+ const validateInput = ${validatorSource(contract.input)}
9
+ const validateOutput = ${validatorSource(contract.output)}
10
+ export async function handler(envelope) {
11
+ let input = envelope?.event?.data
12
+ ${contract.input.kind === 'void' ? "if (input !== null && typeof input === 'object' && !Array.isArray(input) && Object.keys(input).length === 0) input = undefined" : ''}
13
+ if (!validateInput(input)) throw new TypeError(${JSON.stringify(`Invalid input for function "${contract.name}". Match its declared input type.`)})
14
+ const result = await implementation(envelope)
15
+ if (!validateOutput(result)) throw new TypeError(${JSON.stringify(`Function "${contract.name}" returned data that does not match its declared return type.`)})
16
+ return result
17
+ }`;
18
+ return {
19
+ entryPoint,
20
+ plugin: {
21
+ name: 'sanity/function-contract',
22
+ resolveId(id) {
23
+ if (id === entryPoint)
24
+ return resolvedId;
25
+ },
26
+ load(id) {
27
+ if (id === resolvedId)
28
+ return source;
29
+ },
30
+ },
31
+ };
32
+ }
@@ -0,0 +1,22 @@
1
+ import ts from 'typescript-compiler';
2
+ export type ContractSchema = {
3
+ kind: 'string' | 'number' | 'boolean' | 'null' | 'void' | 'never';
4
+ } | {
5
+ kind: 'literal';
6
+ value: string | number | boolean;
7
+ } | {
8
+ kind: 'array';
9
+ items: ContractSchema;
10
+ } | {
11
+ kind: 'union';
12
+ variants: ContractSchema[];
13
+ } | {
14
+ kind: 'object';
15
+ properties: Record<string, {
16
+ optional: boolean;
17
+ schema: ContractSchema;
18
+ }>;
19
+ additional?: ContractSchema;
20
+ };
21
+ export declare function schemaFromType(checker: ts.TypeChecker, type: ts.Type, location: string, allowVoid?: boolean, parents?: Set<ts.Type>): ContractSchema;
22
+ export declare function contractType(schema: ContractSchema): string;