@sanity/runtime-cli 14.7.2 → 14.8.1

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 (94) hide show
  1. package/README.md +150 -99
  2. package/dist/actions/blueprints/assets.d.ts +4 -3
  3. package/dist/actions/blueprints/assets.js +69 -101
  4. package/dist/actions/blueprints/blueprint.d.ts +2 -2
  5. package/dist/actions/blueprints/blueprint.js +1 -8
  6. package/dist/actions/blueprints/config.d.ts +2 -2
  7. package/dist/actions/blueprints/logs-streaming.d.ts +2 -2
  8. package/dist/actions/blueprints/logs.d.ts +2 -4
  9. package/dist/actions/blueprints/resources.d.ts +3 -3
  10. package/dist/actions/blueprints/resources.js +30 -10
  11. package/dist/actions/blueprints/stacks.d.ts +15 -25
  12. package/dist/actions/functions/dev.d.ts +1 -1
  13. package/dist/actions/functions/env/list.d.ts +1 -1
  14. package/dist/actions/functions/env/remove.d.ts +1 -1
  15. package/dist/actions/functions/env/update.d.ts +1 -1
  16. package/dist/actions/functions/logs.d.ts +3 -3
  17. package/dist/actions/node.d.ts +1 -1
  18. package/dist/actions/sanity/examples.d.ts +2 -2
  19. package/dist/actions/sanity/projects.d.ts +7 -13
  20. package/dist/baseCommands.d.ts +8 -0
  21. package/dist/baseCommands.js +10 -4
  22. package/dist/commands/blueprints/config.d.ts +1 -1
  23. package/dist/commands/blueprints/config.js +5 -13
  24. package/dist/commands/blueprints/deploy.d.ts +1 -1
  25. package/dist/commands/blueprints/deploy.js +2 -1
  26. package/dist/commands/blueprints/destroy.d.ts +1 -1
  27. package/dist/commands/blueprints/destroy.js +5 -7
  28. package/dist/commands/blueprints/doctor.js +2 -2
  29. package/dist/commands/blueprints/info.d.ts +1 -1
  30. package/dist/commands/blueprints/info.js +2 -1
  31. package/dist/commands/blueprints/init.js +3 -11
  32. package/dist/commands/blueprints/plan.d.ts +1 -1
  33. package/dist/commands/blueprints/plan.js +2 -1
  34. package/dist/commands/blueprints/promote.d.ts +0 -1
  35. package/dist/commands/blueprints/promote.js +2 -6
  36. package/dist/commands/blueprints/stacks.d.ts +1 -1
  37. package/dist/commands/blueprints/stacks.js +5 -13
  38. package/dist/commands/functions/build.d.ts +1 -1
  39. package/dist/commands/functions/build.js +2 -1
  40. package/dist/commands/functions/env/add.d.ts +1 -1
  41. package/dist/commands/functions/env/add.js +2 -1
  42. package/dist/commands/functions/env/list.d.ts +1 -1
  43. package/dist/commands/functions/env/list.js +2 -1
  44. package/dist/commands/functions/env/remove.d.ts +1 -1
  45. package/dist/commands/functions/env/remove.js +2 -1
  46. package/dist/commands/functions/logs.d.ts +0 -1
  47. package/dist/commands/functions/logs.js +0 -5
  48. package/dist/commands/functions/test.d.ts +1 -1
  49. package/dist/commands/functions/test.js +5 -13
  50. package/dist/constants.d.ts +2 -1
  51. package/dist/cores/blueprints/config.js +11 -7
  52. package/dist/cores/blueprints/deploy.js +62 -74
  53. package/dist/cores/blueprints/destroy.js +3 -3
  54. package/dist/cores/blueprints/doctor.js +5 -1
  55. package/dist/cores/blueprints/info.js +1 -1
  56. package/dist/cores/blueprints/init.d.ts +4 -3
  57. package/dist/cores/blueprints/plan.js +7 -1
  58. package/dist/cores/blueprints/promote.d.ts +0 -1
  59. package/dist/cores/blueprints/promote.js +4 -4
  60. package/dist/cores/blueprints/stacks.js +6 -2
  61. package/dist/cores/functions/add.d.ts +1 -0
  62. package/dist/cores/functions/add.js +2 -2
  63. package/dist/cores/functions/build.js +2 -2
  64. package/dist/cores/functions/env/add.js +1 -1
  65. package/dist/cores/functions/env/list.js +1 -1
  66. package/dist/cores/functions/env/remove.js +1 -1
  67. package/dist/cores/functions/test.js +4 -4
  68. package/dist/cores/index.d.ts +9 -2
  69. package/dist/cores/index.js +3 -2
  70. package/dist/server/app.d.ts +1 -1
  71. package/dist/server/handlers/invoke.d.ts +1 -1
  72. package/dist/utils/display/prompt.d.ts +2 -2
  73. package/dist/utils/display/prompt.js +1 -1
  74. package/dist/utils/display/resources-formatting.d.ts +2 -2
  75. package/dist/utils/display/resources-formatting.js +1 -1
  76. package/dist/utils/functions/fetch-document.d.ts +2 -2
  77. package/dist/utils/functions/prepare-asset.d.ts +3 -8
  78. package/dist/utils/functions/prepare-asset.js +2 -2
  79. package/dist/utils/functions/should-auto-resolve-deps.js +1 -1
  80. package/dist/utils/functions/should-transpile.js +1 -1
  81. package/dist/utils/invoke-local.d.ts +1 -7
  82. package/dist/utils/invoke-local.js +5 -24
  83. package/dist/utils/logger.d.ts +2 -0
  84. package/dist/utils/logger.js +2 -0
  85. package/dist/utils/other/github.d.ts +1 -1
  86. package/dist/utils/other/npmjs.d.ts +1 -1
  87. package/dist/utils/traced-fetch.d.ts +1 -1
  88. package/dist/utils/types.d.ts +21 -80
  89. package/dist/utils/types.js +6 -14
  90. package/dist/utils/validate/resource.d.ts +0 -3
  91. package/dist/utils/validate/resource.js +0 -270
  92. package/dist/utils/validated-token.d.ts +2 -2
  93. package/oclif.manifest.json +36 -90
  94. package/package.json +2 -2
@@ -11,30 +11,13 @@ import { resolveResourceDependencies } from './functions/resolve-dependencies.js
11
11
  import { shouldAutoResolveDependencies } from './functions/should-auto-resolve-deps.js';
12
12
  import { shouldTranspileFunction } from './functions/should-transpile.js';
13
13
  import { transpileFunction } from './transpile/transpile-function.js';
14
- import { isDocumentFunctionResource, isGroqContextOptions, isMediaLibraryAssetFunctionResource, } from './types.js';
14
+ import { isGroqContextOptions, } from './types.js';
15
15
  function getChildProcessWrapperPath() {
16
16
  return fileURLToPath(new URL('./child-process-wrapper.js', import.meta.url));
17
17
  }
18
18
  export function sanitizeLogs(logs) {
19
19
  return logs.replace(/([a-zA-Z0-9]{10})[a-zA-Z0-9]{65,}/g, '$1**********');
20
20
  }
21
- export const DEFAULT_GROQ_RULE = { on: ['publish'], filter: '', projection: '' };
22
- export function isDefaultGROQRule(rule) {
23
- if (!rule)
24
- return true;
25
- return (Array.isArray(rule.on) &&
26
- rule.on.length === DEFAULT_GROQ_RULE.on.length &&
27
- rule.on.every((v) => DEFAULT_GROQ_RULE.on.includes(v)) &&
28
- rule.filter === DEFAULT_GROQ_RULE.filter &&
29
- rule.projection === DEFAULT_GROQ_RULE.projection);
30
- }
31
- function getEvent(rule) {
32
- return {
33
- on: rule.on || DEFAULT_GROQ_RULE.on,
34
- filter: rule.filter || DEFAULT_GROQ_RULE.filter,
35
- projection: rule.projection || DEFAULT_GROQ_RULE.projection,
36
- };
37
- }
38
21
  export async function applyGroqRule(resource, payload, projectId, dataset) {
39
22
  const { before, after, payload: data = null } = payload;
40
23
  // If there is no rule set return everything
@@ -42,11 +25,8 @@ export async function applyGroqRule(resource, payload, projectId, dataset) {
42
25
  return data;
43
26
  // default groq rule is: gimme full doc content. otherwise, parse + eval custom rule
44
27
  // applying the GROQ filter may result in a slimmer set of documents
45
- const event = getEvent(resource.event);
46
- if (!isDefaultGROQRule(event)) {
47
- const hasProjection = event.projection?.length;
48
- const projection = hasProjection ? `${event?.projection}` : '';
49
- const query = `*[${event?.filter}]${projection}`;
28
+ if (resource.event.filter || resource.event.projection) {
29
+ const query = `*[${resource.event.filter || ''}]${resource.event.projection || ''}`;
50
30
  try {
51
31
  const rule = groq.parse(query, { mode: 'delta' });
52
32
  const sanity = projectId && dataset ? { projectId, dataset } : undefined;
@@ -91,7 +71,8 @@ export default async function invoke(resource, payload, context, options) {
91
71
  }
92
72
  const { forceColor = true, timeout = 10 } = options;
93
73
  let filteredData = {};
94
- if (isDocumentFunctionResource(resource) || isMediaLibraryAssetFunctionResource(resource)) {
74
+ if (resource.type === 'sanity.function.document' ||
75
+ resource.type === 'sanity.function.media-library.asset') {
95
76
  if (!isGroqContextOptions(context)) {
96
77
  throw new Error('GROQ-based functions require a context with clientOptions');
97
78
  }
@@ -2,6 +2,7 @@ import ora from 'ora';
2
2
  export declare function Logger(log: (msg: string) => void, flags?: {
3
3
  verbose?: boolean;
4
4
  trace?: boolean;
5
+ json?: boolean;
5
6
  }): {
6
7
  (msg: string): void;
7
8
  trace(formatter: unknown, ...args: unknown[]): false | void;
@@ -11,3 +12,4 @@ export declare function Logger(log: (msg: string) => void, flags?: {
11
12
  error(formatter: unknown, ...args: unknown[]): false | void;
12
13
  ora: typeof ora;
13
14
  };
15
+ export type Logger = ReturnType<typeof Logger>;
@@ -19,6 +19,8 @@ export function Logger(log, flags = {}) {
19
19
  logger.warn = (formatter, ...args) => level <= LogLevel.WARN && logger(format(formatter, ...args));
20
20
  logger.error = (formatter, ...args) => level <= LogLevel.ERROR && logger(format(formatter, ...args));
21
21
  const oraWrapper = (opts) => {
22
+ if (flags.json)
23
+ return createOraLineLoggingWrapper(opts, logger);
22
24
  if (level >= LogLevel.INFO)
23
25
  return ora(opts);
24
26
  return createOraLineLoggingWrapper(opts, logger);
@@ -1,3 +1,3 @@
1
1
  import type { Logger } from '../logger.js';
2
2
  export declare const GITHUB_API_URL = "https://api.github.com";
3
- export declare function gitHubRequest(path: string, logger: ReturnType<typeof Logger>): Promise<Response>;
3
+ export declare function gitHubRequest(path: string, logger: Logger): Promise<Response>;
@@ -1,2 +1,2 @@
1
1
  import type { Logger } from '../logger.js';
2
- export declare function getLatestNpmVersion(pkg: string, logger: ReturnType<typeof Logger>): Promise<string>;
2
+ export declare function getLatestNpmVersion(pkg: string, logger: Logger): Promise<string>;
@@ -32,4 +32,4 @@ export interface TracedFetchOptions {
32
32
  * const response = await tracedFetch('https://api.example.com/data')
33
33
  * ```
34
34
  */
35
- export declare function createTracedFetch(logger: ReturnType<typeof Logger>, options?: TracedFetchOptions): typeof fetch;
35
+ export declare function createTracedFetch(logger: Logger, options?: TracedFetchOptions): typeof fetch;
@@ -1,6 +1,5 @@
1
- import { type BlueprintCorsOriginResource, type BlueprintDatasetResource, type BlueprintDocumentWebhookResource, type BlueprintProjectResource, type BlueprintResource, type BlueprintRobotResource, type BlueprintRoleResource } from '@sanity/blueprints';
1
+ import { type BlueprintCorsOriginResource, type BlueprintDatasetResource, type BlueprintDocumentFunctionResource, type BlueprintDocumentWebhookResource, type BlueprintMediaLibraryAssetFunctionResource, type BlueprintProjectResource, type BlueprintResource, type BlueprintRobotResource, type BlueprintRoleResource, type BlueprintScheduledFunctionResource } from '@sanity/blueprints';
2
2
  import type { Blueprint } from '@sanity/blueprints-parser';
3
- import { SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_SCHEDULED } from '../constants.js';
4
3
  export type ScopeType = 'organization' | 'project';
5
4
  /** Result utility type */
6
5
  export type Result<T, E = string> = {
@@ -10,6 +9,14 @@ export type Result<T, E = string> = {
10
9
  ok: false;
11
10
  error: E;
12
11
  };
12
+ /** Base shape for API action responses */
13
+ export interface ActionResponse {
14
+ ok: boolean;
15
+ error: string | null;
16
+ }
17
+ /** @internal */
18
+ export type FunctionGroqResource = BlueprintDocumentFunctionResource | BlueprintMediaLibraryAssetFunctionResource;
19
+ export type FunctionResource = FunctionGroqResource | BlueprintScheduledFunctionResource;
13
20
  /** @internal */
14
21
  export interface AuthParams {
15
22
  token: string;
@@ -17,37 +24,6 @@ export interface AuthParams {
17
24
  scopeId: string;
18
25
  }
19
26
  /** @internal */
20
- export type GroqRule = GroqRuleDocumentFunction | GroqRuleMediaLibraryFunction;
21
- export interface GroqRuleBase {
22
- on: Array<string>;
23
- filter?: string;
24
- projection?: string;
25
- }
26
- interface GroqRuleDocumentFunction extends GroqRuleBase {
27
- includeDrafts?: boolean;
28
- includeAllVersions?: boolean;
29
- resource?: {
30
- type: 'dataset';
31
- id: string;
32
- };
33
- }
34
- interface GroqRuleMediaLibraryFunction extends GroqRuleBase {
35
- resource: {
36
- type: 'media-library';
37
- id: string;
38
- };
39
- }
40
- export interface FunctionResourceScheduleExplicitEvent {
41
- minute: string;
42
- hour: string;
43
- dayOfMonth: string;
44
- month: string;
45
- dayOfWeek: string;
46
- }
47
- interface FunctionResourceScheduleExpressionEvent {
48
- expression: string;
49
- }
50
- type FunctionResourceScheduleEvent = FunctionResourceScheduleExplicitEvent | FunctionResourceScheduleExpressionEvent;
51
27
  /** The Blueprint resource as represented in the Blueprints API database */
52
28
  export interface BlueprintResourceRecord extends BlueprintResource {
53
29
  id: string;
@@ -58,60 +34,16 @@ export interface BlueprintResourceRecord extends BlueprintResource {
58
34
  export interface DeployedResource extends BlueprintResourceRecord {
59
35
  externalId: string;
60
36
  }
61
- export declare function isLocalFunctionResource(r: BlueprintResource): r is FunctionResourceBase;
62
- export declare function isDocumentFunctionResource<T extends BlueprintResource>(r: T): r is T & FunctionResourceDocument;
63
- export declare function isMediaLibraryAssetFunctionResource<T extends BlueprintResource>(r: T): r is T & FunctionResourceMediaLibraryAsset;
64
- export declare function isScheduleFunctionResource<T extends BlueprintResource>(r: T): r is T & FunctionResourceSchedule;
65
- export declare function isLocalFunctionCollection<T extends BlueprintResource>(r: T): r is T & FunctionsCollection;
66
- export declare function isScheduleEvent(e: unknown): e is FunctionResourceScheduleEvent;
37
+ export declare function isLocalFunctionResource(r: BlueprintResource): r is FunctionResource;
38
+ export declare function isScheduleEvent(e: unknown): e is BlueprintScheduledFunctionResource['event'];
67
39
  export declare function isCorsOriginResource(r: unknown): r is BlueprintCorsOriginResource;
68
40
  export declare function isProjectResource(r: unknown): r is BlueprintProjectResource;
69
41
  export declare function isRobotResource(r: unknown): r is BlueprintRobotResource;
70
42
  export declare function isRoleResource(r: unknown): r is BlueprintRoleResource;
71
43
  export declare function isDatasetResource(r: unknown): r is BlueprintDatasetResource;
44
+ export declare function isStudioResource(r: unknown): boolean;
72
45
  export declare function isWebhookResource(r: unknown): r is BlueprintDocumentWebhookResource;
73
46
  /** @internal */
74
- export type FunctionResource = FunctionResourceDocument | FunctionResourceMediaLibraryAsset | FunctionResourceSchedule | FunctionResourceBase;
75
- export type FunctionGroqResource = FunctionResourceDocument | FunctionResourceMediaLibraryAsset;
76
- export interface FunctionResourceBase extends BlueprintResource {
77
- displayName?: string;
78
- src?: string;
79
- autoResolveDeps?: boolean;
80
- transpile?: boolean;
81
- memory?: number;
82
- timeout?: number;
83
- env?: Record<string, string>;
84
- event?: GroqRuleBase | FunctionResourceScheduleEvent;
85
- }
86
- interface FunctionResourceDocument extends FunctionResourceBase {
87
- type: typeof SANITY_FUNCTION_DOCUMENT;
88
- event?: GroqRuleDocumentFunction;
89
- }
90
- interface FunctionResourceMediaLibraryAsset extends FunctionResourceBase {
91
- type: typeof SANITY_FUNCTION_MEDIA_LIBRARY_ASSET;
92
- event: GroqRuleMediaLibraryFunction;
93
- }
94
- interface FunctionResourceSchedule extends FunctionResourceBase {
95
- type: typeof SANITY_FUNCTION_SCHEDULED;
96
- event: FunctionResourceScheduleEvent;
97
- }
98
- export interface CollectionFunction {
99
- type: typeof SANITY_FUNCTION_DOCUMENT | typeof SANITY_FUNCTION_SCHEDULED | typeof SANITY_FUNCTION_MEDIA_LIBRARY_ASSET;
100
- src: string;
101
- name: string;
102
- displayName?: string;
103
- event?: GroqRuleBase | FunctionResourceScheduleEvent;
104
- memory?: number;
105
- timeout?: number;
106
- env?: Record<string, string>;
107
- }
108
- /** @internal */
109
- export interface FunctionsCollection extends BlueprintResource {
110
- type: 'sanity.experimental.functions-collection';
111
- name: string;
112
- src?: string;
113
- functions: Array<FunctionResourceBase>;
114
- }
115
47
  export interface CorsResource extends BlueprintResource {
116
48
  origin?: string;
117
49
  }
@@ -258,4 +190,13 @@ export declare interface FetchConfig {
258
190
  }
259
191
  export declare const INSTALLER_OPTIONS: readonly ["npm", "pnpm", "yarn"];
260
192
  export type InstallerType = 'npm' | 'pnpm' | 'yarn';
193
+ export type AssetPrepResult = {
194
+ success: true;
195
+ outputPath: string;
196
+ cleanup: () => Promise<void>;
197
+ } | {
198
+ success: false;
199
+ cleanup: () => Promise<void>;
200
+ error: string;
201
+ };
261
202
  export {};
@@ -1,21 +1,9 @@
1
1
  import { validateCorsOrigin, validateDataset, validateDocumentWebhook, validateProject, validateRobot, validateRole, } from '@sanity/blueprints';
2
- import { SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_PREFIX, SANITY_FUNCTION_SCHEDULED, } from '../constants.js';
3
- // type narrowing with predicate functions
2
+ import { SANITY_FUNCTION_PREFIX } from '../constants.js';
4
3
  export function isLocalFunctionResource(r) {
5
4
  return r.type.startsWith(SANITY_FUNCTION_PREFIX);
6
5
  }
7
- export function isDocumentFunctionResource(r) {
8
- return r.type === SANITY_FUNCTION_DOCUMENT;
9
- }
10
- export function isMediaLibraryAssetFunctionResource(r) {
11
- return r.type === SANITY_FUNCTION_MEDIA_LIBRARY_ASSET;
12
- }
13
- export function isScheduleFunctionResource(r) {
14
- return r.type === SANITY_FUNCTION_SCHEDULED;
15
- }
16
- export function isLocalFunctionCollection(r) {
17
- return r.type === 'sanity.experimental.functions-collection';
18
- }
6
+ // type narrowing with predicate functions
19
7
  export function isScheduleEvent(e) {
20
8
  return e !== null && typeof e === 'object' && ('hour' in e || 'expression' in e);
21
9
  }
@@ -34,6 +22,10 @@ export function isRoleResource(r) {
34
22
  export function isDatasetResource(r) {
35
23
  return validateDataset(r).length === 0;
36
24
  }
25
+ // TODO: update to use blueprints helpers once available
26
+ export function isStudioResource(r) {
27
+ return !!r && typeof r === 'object' && 'type' in r && r.type === 'sanity.studio';
28
+ }
37
29
  export function isWebhookResource(r) {
38
30
  return validateDocumentWebhook(r).length === 0;
39
31
  }
@@ -1,4 +1 @@
1
- import type { FunctionResource } from '../types.js';
2
- import { type BlueprintParserError } from '../types.js';
3
1
  export declare function validateFunctionName(name: string): boolean;
4
- export declare function validateFunctionResource(resource: FunctionResource): BlueprintParserError[];
@@ -1,274 +1,4 @@
1
- import { SANITY_FUNCTION_PREFIX } from '../../constants.js';
2
- import { BlueprintParserErrorType, isDocumentFunctionResource, isMediaLibraryAssetFunctionResource, isScheduleEvent, } from '../types.js';
3
1
  export function validateFunctionName(name) {
4
2
  // must be 3+ characters, no special characters, no spaces, allow _ and -
5
3
  return /^[a-zA-Z0-9][a-zA-Z0-9_-]{2,}$/.test(name);
6
4
  }
7
- const validFunctionEventNames = ['publish', 'create', 'update', 'delete'];
8
- export function validateFunctionResource(resource) {
9
- const { name: fnName } = resource;
10
- const msgPrefix = `Function "${fnName}":`;
11
- const errors = [];
12
- if (!validateFunctionName(resource.name)) {
13
- errors.push({
14
- message: `${msgPrefix} Function name must be at least 3 characters, start with a letter or number, and only contain letters, numbers, _ or -`,
15
- type: BlueprintParserErrorType.InvalidProperty,
16
- });
17
- }
18
- if (!resource.type.startsWith(SANITY_FUNCTION_PREFIX)) {
19
- errors.push({
20
- message: `${msgPrefix} Resource type must start with "${SANITY_FUNCTION_PREFIX}"`,
21
- type: BlueprintParserErrorType.InvalidType,
22
- });
23
- }
24
- if (isScheduleEvent(resource.event)) {
25
- const event = resource.event;
26
- const hasExpression = 'expression' in event;
27
- const hasExplicitFields = 'minute' in event ||
28
- 'hour' in event ||
29
- 'dayOfMonth' in event ||
30
- 'month' in event ||
31
- 'dayOfWeek' in event;
32
- if (hasExpression && hasExplicitFields) {
33
- errors.push({
34
- type: BlueprintParserErrorType.InvalidFormat,
35
- message: 'Cannot specify both `expression` and explicit cron fields (`minute`, `hour`, `dayOfMonth`, `month`, `dayOfWeek`)',
36
- });
37
- }
38
- else if (!hasExpression && !hasExplicitFields) {
39
- errors.push({
40
- type: BlueprintParserErrorType.MissingRequiredProperty,
41
- message: 'Either `expression` or explicit cron fields (`minute`, `hour`, `dayOfMonth`, `month`, `dayOfWeek`) must be provided',
42
- });
43
- }
44
- else if (hasExpression) {
45
- const expressionParts = event.expression.split(' ');
46
- if (expressionParts.length !== 5) {
47
- errors.push({
48
- type: BlueprintParserErrorType.InvalidFormat,
49
- message: 'Invalid `expression` format. Cron fields (`minute`, `hour`, `dayOfMonth`, `month`, `dayOfWeek`) must be provided',
50
- });
51
- }
52
- else {
53
- const [minute, hour, dayOfWeek, month, dayOfMonth] = expressionParts;
54
- errors.push(...validateScheduleEvent(msgPrefix, { minute, hour, dayOfWeek, month, dayOfMonth }));
55
- }
56
- }
57
- else if (hasExplicitFields) {
58
- errors.push(...validateScheduleEvent(msgPrefix, event));
59
- }
60
- }
61
- else {
62
- if (!resource.event || !Array.isArray(resource.event.on) || resource.event.on.length === 0) {
63
- errors.push({
64
- message: `${msgPrefix} event.on must be a non-empty array`,
65
- type: BlueprintParserErrorType.MissingRequiredProperty,
66
- });
67
- }
68
- else if (!resource.event.on.every((evt) => validFunctionEventNames.includes(evt))) {
69
- errors.push({
70
- message: `${msgPrefix} event.on values must be one of ${validFunctionEventNames.map((e) => `"${e}"`).join(', ')}`,
71
- type: BlueprintParserErrorType.InvalidValue,
72
- });
73
- }
74
- if (resource.event?.filter && typeof resource.event.filter !== 'string') {
75
- errors.push({
76
- message: `${msgPrefix} event.filter must be a string`,
77
- type: BlueprintParserErrorType.InvalidType,
78
- });
79
- }
80
- if (resource.event?.projection && typeof resource.event.projection !== 'string') {
81
- errors.push({
82
- message: `${msgPrefix} event.projection must be a string`,
83
- type: BlueprintParserErrorType.InvalidType,
84
- });
85
- }
86
- }
87
- if (resource.memory !== undefined) {
88
- if (!Number.isInteger(resource.memory)) {
89
- errors.push({
90
- message: `${msgPrefix} memory must be an integer`,
91
- type: BlueprintParserErrorType.InvalidType,
92
- });
93
- }
94
- else if (resource.memory < 1 || resource.memory > 10) {
95
- errors.push({
96
- message: `${msgPrefix} memory must be between 1 and 10 (GB)`,
97
- type: BlueprintParserErrorType.InvalidValue,
98
- });
99
- }
100
- }
101
- if (resource.timeout !== undefined) {
102
- if (!Number.isInteger(resource.timeout)) {
103
- errors.push({
104
- message: `${msgPrefix} timeout must be an integer`,
105
- type: BlueprintParserErrorType.InvalidType,
106
- });
107
- }
108
- else if (resource.timeout < 1 || resource.timeout > 900) {
109
- errors.push({
110
- message: `${msgPrefix} timeout must be between 1 and 900 (seconds)`,
111
- type: BlueprintParserErrorType.InvalidValue,
112
- });
113
- }
114
- }
115
- if (resource.env !== undefined) {
116
- if (typeof resource.env !== 'object') {
117
- errors.push({
118
- message: `${msgPrefix} env must be an object`,
119
- type: BlueprintParserErrorType.InvalidType,
120
- });
121
- }
122
- else {
123
- if (!Object.keys(resource.env).every((key) => typeof key === 'string')) {
124
- errors.push({
125
- message: `${msgPrefix} All env keys must be strings`,
126
- type: BlueprintParserErrorType.InvalidFormat,
127
- });
128
- }
129
- if (!Object.values(resource.env).every((value) => typeof value === 'string')) {
130
- errors.push({
131
- message: `${msgPrefix} All env values must be strings`,
132
- type: BlueprintParserErrorType.InvalidFormat,
133
- });
134
- }
135
- }
136
- }
137
- if (resource.event && 'resource' in resource.event && resource.event.resource) {
138
- if (!resource.event.resource.type) {
139
- errors.push({
140
- message: `${msgPrefix} event.resource.type must be defined`,
141
- type: BlueprintParserErrorType.MissingRequiredProperty,
142
- });
143
- }
144
- if (!resource.event.resource.id) {
145
- errors.push({
146
- message: `${msgPrefix} event.resource.id must be defined`,
147
- type: BlueprintParserErrorType.MissingRequiredProperty,
148
- });
149
- }
150
- }
151
- if (isMediaLibraryAssetFunctionResource(resource)) {
152
- if (resource.event.resource.type !== 'media-library') {
153
- errors.push({
154
- message: `${msgPrefix} event.resource.type must be "media-library"`,
155
- type: BlueprintParserErrorType.InvalidType,
156
- });
157
- }
158
- }
159
- if (isDocumentFunctionResource(resource) && resource.event) {
160
- if (resource.event.includeDrafts && typeof resource.event.includeDrafts !== 'boolean') {
161
- errors.push({
162
- message: `${msgPrefix} event.includeDrafts must be a boolean`,
163
- type: BlueprintParserErrorType.InvalidType,
164
- });
165
- }
166
- if (resource.event.includeAllVersions &&
167
- typeof resource.event.includeAllVersions !== 'boolean') {
168
- errors.push({
169
- message: `${msgPrefix} event.includeAllVersions must be a boolean`,
170
- type: BlueprintParserErrorType.InvalidType,
171
- });
172
- }
173
- if (resource.event.resource) {
174
- if (!resource.event.resource.type || resource.event.resource.type !== 'dataset') {
175
- errors.push({
176
- message: `${msgPrefix} event.resource.type must be "dataset"`,
177
- type: BlueprintParserErrorType.InvalidType,
178
- });
179
- }
180
- // Ensure exactly one period is passed into the ID to conform to the format <projectId>.<datasetName>
181
- if (!resource.event.resource.id || resource.event.resource.id.split('.').length !== 2) {
182
- errors.push({
183
- message: `${msgPrefix} event.resource.id must be of the form <projectId>.<datasetName>. <datasetName> can be "*" to signify "all datasets in project with ID <projectId>."`,
184
- type: BlueprintParserErrorType.InvalidFormat,
185
- });
186
- }
187
- // TODO: validate the project ID and dataset names exist by making an API call?
188
- // NB: this is done by the functions service
189
- }
190
- }
191
- return errors;
192
- }
193
- function validateScheduleEvent(msgPrefix, event) {
194
- const errors = [];
195
- const properties = [
196
- { name: 'minute', regex: MINUTES },
197
- { name: 'hour', regex: HOURS },
198
- { name: 'dayOfMonth', regex: DAY_OF_MONTH },
199
- { name: 'month', regex: MONTH },
200
- { name: 'dayOfWeek', regex: DAY_OF_WEEK },
201
- ];
202
- properties.forEach((prop) => {
203
- const { name, regex } = prop;
204
- if (!(name in event)) {
205
- errors.push({
206
- type: BlueprintParserErrorType.MissingRequiredProperty,
207
- message: `${msgPrefix} '${name}' must be provided`,
208
- });
209
- return;
210
- }
211
- const value = event[name];
212
- if (typeof value !== 'string') {
213
- errors.push({
214
- type: BlueprintParserErrorType.InvalidType,
215
- message: `${msgPrefix} '${name}' must be a string`,
216
- });
217
- return;
218
- }
219
- if (!isValidCronPart(regex, value)) {
220
- errors.push({
221
- type: BlueprintParserErrorType.InvalidValue,
222
- message: `${msgPrefix} ${name} field contains invalid value: ${value}`,
223
- });
224
- }
225
- });
226
- return errors;
227
- }
228
- /**
229
- * Validates that each cron part adheres to it's rules
230
- *
231
- * @param {RegExp} regex the regular expression that corresponds to the part of the cron expression you are testing
232
- * @param {string} value the string value of part of the cron expression you are testing
233
- * @returns {boolean} whether or not the cron part is valid
234
- */
235
- function isValidCronPart(regex, value) {
236
- return regex.test(value) && checkAscendingRanges(value) && checkNoZeroStep(value);
237
- }
238
- const MINUTES = /^(\*(\/([1-5]?\d))?|([0-5]?\d)(-[0-5]?\d)?(\/([1-5]?\d))?)(,(\*(\/([1-5]?\d))?|([0-5]?\d)(-[0-5]?\d)?(\/([1-5]?\d))?))*$/;
239
- const HOURS = /^(\*(\/([1-9]|1\d|2[0-3]))?|([01]?\d|2[0-3])(-([01]?\d|2[0-3]))?(\/([1-9]|1\d|2[0-3]))?)(,(\*(\/([1-9]|1\d|2[0-3]))?|([01]?\d|2[0-3])(-([01]?\d|2[0-3]))?(\/([1-9]|1\d|2[0-3]))?))*$/;
240
- const DAY_OF_MONTH = /^(\*(\/([1-9]|[12]\d|3[01]))?|([1-9]|[12]\d|3[01])(-([1-9]|[12]\d|3[01]))?(\/([1-9]|[12]\d|3[01]))?)(,(\*(\/([1-9]|[12]\d|3[01]))?|([1-9]|[12]\d|3[01])(-([1-9]|[12]\d|3[01]))?(\/([1-9]|[12]\d|3[01]))?))*$/;
241
- const MONTH = /^(\*(\/([1-9]|1[0-2]))?|([1-9]|1[0-2]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-([1-9]|1[0-2]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(\/([1-9]|1[0-2]))?)(,(\*(\/([1-9]|1[0-2]))?|([1-9]|1[0-2]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-([1-9]|1[0-2]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(\/([1-9]|1[0-2]))?))*$/i;
242
- const DAY_OF_WEEK = /^(\*(\/([0-7]))?|([0-7]|SUN|MON|TUE|WED|THU|FRI|SAT)(-([0-7]|SUN|MON|TUE|WED|THU|FRI|SAT))?(\/([0-7]))?)(,(\*(\/([0-7]))?|([0-7]|SUN|MON|TUE|WED|THU|FRI|SAT)(-([0-7]|SUN|MON|TUE|WED|THU|FRI|SAT))?(\/([0-7]))?))*$/i;
243
- /**
244
- *
245
- * @param {string} value the string value of part of the cron expression you are testing
246
- * @returns {boolean} returns true if the range is valid
247
- */
248
- function checkAscendingRanges(value) {
249
- for (const part of value.split(',')) {
250
- if (part.includes('-')) {
251
- const [start, right] = part.split('-');
252
- const end = right.split('/')[0]; // remove /step
253
- const s = Number(start);
254
- const e = Number(end);
255
- if (s > e)
256
- return false;
257
- }
258
- }
259
- return true;
260
- }
261
- /**
262
- * @param {string} value the string value of part of the cron expression you are testing
263
- * @returns {boolean} makes sure we are not trying to divide by zero
264
- */
265
- function checkNoZeroStep(value) {
266
- for (const part of value.split(',')) {
267
- if (part.includes('/')) {
268
- const step = Number(part.split('/')[1]);
269
- if (step === 0)
270
- return false;
271
- }
272
- }
273
- return true;
274
- }
@@ -1,7 +1,7 @@
1
1
  import type { Logger } from './logger.js';
2
2
  import type { Result } from './types.js';
3
- export declare function validToken(logger: ReturnType<typeof Logger>, maybeToken?: string): Promise<string>;
4
- export declare function validTokenOrErrorMessage(logger: ReturnType<typeof Logger>, maybeToken?: string): Promise<Result<string, {
3
+ export declare function validToken(logger: Logger, maybeToken?: string): Promise<string>;
4
+ export declare function validTokenOrErrorMessage(logger: Logger, maybeToken?: string): Promise<Result<string, {
5
5
  e: Error | unknown;
6
6
  message: string;
7
7
  }>>;