@backstage/backend-plugin-api 1.7.0 → 1.8.0-next.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @backstage/backend-plugin-api
2
2
 
3
+ ## 1.8.0-next.1
4
+
5
+ ### Minor Changes
6
+
7
+ - 015668c: Added `cancelTask` method to the `SchedulerService` interface and implementation, allowing cancellation of currently running scheduled tasks. For global tasks, the database lock is released and a periodic liveness check aborts the running task function. For local tasks, the task's abort signal is triggered directly. A new `POST /.backstage/scheduler/v1/tasks/:id/cancel` endpoint is also available.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @backstage/cli-common@0.2.0-next.2
13
+ - @backstage/plugin-auth-node@0.6.14-next.2
14
+ - @backstage/plugin-permission-node@0.10.11-next.1
15
+
16
+ ## 1.7.1-next.0
17
+
18
+ ### Patch Changes
19
+
20
+ - 1ee5b28: Adds an alpha `MetricsService` to provide a unified interface for metrics instrumentation across Backstage plugins.
21
+ - Updated dependencies
22
+ - @backstage/cli-common@0.2.0-next.0
23
+ - @backstage/config@1.3.6
24
+ - @backstage/errors@1.2.7
25
+ - @backstage/types@1.2.2
26
+ - @backstage/plugin-auth-node@0.6.14-next.0
27
+ - @backstage/plugin-permission-common@0.9.6
28
+ - @backstage/plugin-permission-node@0.10.11-next.0
29
+
3
30
  ## 1.7.0
4
31
 
5
32
  ### Minor Changes
@@ -12,8 +12,12 @@ const rootSystemMetadataServiceRef = backendPluginApi.createServiceRef({
12
12
  id: "alpha.core.rootSystemMetadata",
13
13
  scope: "root"
14
14
  });
15
+ const metricsServiceRef = backendPluginApi.createServiceRef({
16
+ id: "alpha.core.metrics"
17
+ });
15
18
 
16
19
  exports.actionsRegistryServiceRef = actionsRegistryServiceRef;
17
20
  exports.actionsServiceRef = actionsServiceRef;
21
+ exports.metricsServiceRef = metricsServiceRef;
18
22
  exports.rootSystemMetadataServiceRef = rootSystemMetadataServiceRef;
19
23
  //# sourceMappingURL=refs.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"refs.cjs.js","sources":["../../src/alpha/refs.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createServiceRef } from '@backstage/backend-plugin-api';\n\n/**\n * Service for calling distributed actions\n *\n * See {@link ActionsService}\n * and {@link https://backstage.io/docs/backend-system/core-services/actions | the service docs}\n * for more information.\n *\n * @alpha\n */\nexport const actionsServiceRef = createServiceRef<\n import('./ActionsService').ActionsService\n>({\n id: 'alpha.core.actions',\n});\n\n/**\n * Service for registering and managing distributed actions.\n *\n * See {@link ActionsRegistryService}\n * and {@link https://backstage.io/docs/backend-system/core-services/actions-registry | the service docs}\n * for more information.\n *\n * @alpha\n */\nexport const actionsRegistryServiceRef = createServiceRef<\n import('./ActionsRegistryService').ActionsRegistryService\n>({\n id: 'alpha.core.actionsRegistry',\n});\n\n/**\n * Read information about your current Backstage deployment.\n * @alpha\n */\nexport const rootSystemMetadataServiceRef = createServiceRef<\n import('./RootSystemMetadataService').RootSystemMetadataService\n>({\n id: 'alpha.core.rootSystemMetadata',\n scope: 'root',\n});\n"],"names":["createServiceRef"],"mappings":";;;;AA2BO,MAAM,oBAAoBA,iCAAA,CAE/B;AAAA,EACA,EAAA,EAAI;AACN,CAAC;AAWM,MAAM,4BAA4BA,iCAAA,CAEvC;AAAA,EACA,EAAA,EAAI;AACN,CAAC;AAMM,MAAM,+BAA+BA,iCAAA,CAE1C;AAAA,EACA,EAAA,EAAI,+BAAA;AAAA,EACJ,KAAA,EAAO;AACT,CAAC;;;;;;"}
1
+ {"version":3,"file":"refs.cjs.js","sources":["../../src/alpha/refs.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createServiceRef } from '@backstage/backend-plugin-api';\n\n/**\n * Service for calling distributed actions\n *\n * See {@link ActionsService}\n * and {@link https://backstage.io/docs/backend-system/core-services/actions | the service docs}\n * for more information.\n *\n * @alpha\n */\nexport const actionsServiceRef = createServiceRef<\n import('./ActionsService').ActionsService\n>({\n id: 'alpha.core.actions',\n});\n\n/**\n * Service for registering and managing distributed actions.\n *\n * See {@link ActionsRegistryService}\n * and {@link https://backstage.io/docs/backend-system/core-services/actions-registry | the service docs}\n * for more information.\n *\n * @alpha\n */\nexport const actionsRegistryServiceRef = createServiceRef<\n import('./ActionsRegistryService').ActionsRegistryService\n>({\n id: 'alpha.core.actionsRegistry',\n});\n\n/**\n * Read information about your current Backstage deployment.\n * @alpha\n */\nexport const rootSystemMetadataServiceRef = createServiceRef<\n import('./RootSystemMetadataService').RootSystemMetadataService\n>({\n id: 'alpha.core.rootSystemMetadata',\n scope: 'root',\n});\n\n/**\n * Service for managing metrics.\n *\n * @alpha\n */\nexport const metricsServiceRef = createServiceRef<\n import('./MetricsService').MetricsService\n>({\n id: 'alpha.core.metrics',\n});\n"],"names":["createServiceRef"],"mappings":";;;;AA2BO,MAAM,oBAAoBA,iCAAA,CAE/B;AAAA,EACA,EAAA,EAAI;AACN,CAAC;AAWM,MAAM,4BAA4BA,iCAAA,CAEvC;AAAA,EACA,EAAA,EAAI;AACN,CAAC;AAMM,MAAM,+BAA+BA,iCAAA,CAE1C;AAAA,EACA,EAAA,EAAI,+BAAA;AAAA,EACJ,KAAA,EAAO;AACT,CAAC;AAOM,MAAM,oBAAoBA,iCAAA,CAE/B;AAAA,EACA,EAAA,EAAI;AACN,CAAC;;;;;;;"}
package/dist/alpha.cjs.js CHANGED
@@ -6,5 +6,6 @@ var refs = require('./alpha/refs.cjs.js');
6
6
 
7
7
  exports.actionsRegistryServiceRef = refs.actionsRegistryServiceRef;
8
8
  exports.actionsServiceRef = refs.actionsServiceRef;
9
+ exports.metricsServiceRef = refs.metricsServiceRef;
9
10
  exports.rootSystemMetadataServiceRef = refs.rootSystemMetadataServiceRef;
10
11
  //# sourceMappingURL=alpha.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"alpha.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
1
+ {"version":3,"file":"alpha.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
package/dist/alpha.d.ts CHANGED
@@ -84,6 +84,189 @@ interface ActionsService {
84
84
  }>;
85
85
  }
86
86
 
87
+ /**
88
+ * Attribute values that can be attached to metric measurements.
89
+ *
90
+ * @alpha
91
+ */
92
+ type MetricAttributeValue = string | number | boolean | Array<null | undefined | string> | Array<null | undefined | number> | Array<null | undefined | boolean>;
93
+ /**
94
+ * A set of key-value pairs that can be attached to metric measurements.
95
+ *
96
+ * @alpha
97
+ */
98
+ interface MetricAttributes {
99
+ [attributeKey: string]: MetricAttributeValue | undefined;
100
+ }
101
+ /**
102
+ * Advisory options that influence aggregation configuration.
103
+ *
104
+ * @alpha
105
+ */
106
+ interface MetricAdvice {
107
+ /**
108
+ * Hint the explicit bucket boundaries for histogram aggregation.
109
+ */
110
+ explicitBucketBoundaries?: number[];
111
+ }
112
+ /**
113
+ * Options for creating a metric instrument.
114
+ *
115
+ * @alpha
116
+ */
117
+ interface MetricOptions {
118
+ /**
119
+ * The description of the Metric.
120
+ */
121
+ description?: string;
122
+ /**
123
+ * The unit of the Metric values.
124
+ */
125
+ unit?: string;
126
+ /**
127
+ * Advisory options that influence aggregation configuration.
128
+ */
129
+ advice?: MetricAdvice;
130
+ }
131
+ /**
132
+ * A counter metric that only supports non-negative increments.
133
+ *
134
+ * @alpha
135
+ */
136
+ interface MetricsServiceCounter<TAttributes extends MetricAttributes = MetricAttributes> {
137
+ add(value: number, attributes?: TAttributes): void;
138
+ }
139
+ /**
140
+ * A counter metric that supports both positive and negative increments.
141
+ *
142
+ * @alpha
143
+ */
144
+ interface MetricsServiceUpDownCounter<TAttributes extends MetricAttributes = MetricAttributes> {
145
+ add(value: number, attributes?: TAttributes): void;
146
+ }
147
+ /**
148
+ * A histogram metric for recording distributions of values.
149
+ *
150
+ * @alpha
151
+ */
152
+ interface MetricsServiceHistogram<TAttributes extends MetricAttributes = MetricAttributes> {
153
+ record(value: number, attributes?: TAttributes): void;
154
+ }
155
+ /**
156
+ * A gauge metric for recording instantaneous values.
157
+ *
158
+ * @alpha
159
+ */
160
+ interface MetricsServiceGauge<TAttributes extends MetricAttributes = MetricAttributes> {
161
+ record(value: number, attributes?: TAttributes): void;
162
+ }
163
+ /**
164
+ * The result object passed to observable metric callbacks.
165
+ *
166
+ * @alpha
167
+ */
168
+ interface MetricsServiceObservableResult<TAttributes extends MetricAttributes = MetricAttributes> {
169
+ observe(value: number, attributes?: TAttributes): void;
170
+ }
171
+ /**
172
+ * A callback function for observable metrics. Called whenever a metric
173
+ * collection is initiated.
174
+ *
175
+ * @alpha
176
+ */
177
+ type MetricsServiceObservableCallback<TAttributes extends MetricAttributes = MetricAttributes> = (observableResult: MetricsServiceObservableResult<TAttributes>) => void | Promise<void>;
178
+ /**
179
+ * An observable metric instrument that reports values via callbacks.
180
+ *
181
+ * @alpha
182
+ */
183
+ interface MetricsServiceObservable<TAttributes extends MetricAttributes = MetricAttributes> {
184
+ addCallback(callback: MetricsServiceObservableCallback<TAttributes>): void;
185
+ removeCallback(callback: MetricsServiceObservableCallback<TAttributes>): void;
186
+ }
187
+ /**
188
+ * An observable counter metric that reports non-negative sums via callbacks.
189
+ *
190
+ * @alpha
191
+ */
192
+ type MetricsServiceObservableCounter<TAttributes extends MetricAttributes = MetricAttributes> = MetricsServiceObservable<TAttributes>;
193
+ /**
194
+ * An observable counter metric that reports sums that can go up or down
195
+ * via callbacks.
196
+ *
197
+ * @alpha
198
+ */
199
+ type MetricsServiceObservableUpDownCounter<TAttributes extends MetricAttributes = MetricAttributes> = MetricsServiceObservable<TAttributes>;
200
+ /**
201
+ * An observable gauge metric that reports instantaneous values via callbacks.
202
+ *
203
+ * @alpha
204
+ */
205
+ type MetricsServiceObservableGauge<TAttributes extends MetricAttributes = MetricAttributes> = MetricsServiceObservable<TAttributes>;
206
+ /**
207
+ * A service that provides a facility for emitting metrics.
208
+ *
209
+ * @alpha
210
+ */
211
+ interface MetricsService {
212
+ /**
213
+ * Creates a new counter metric.
214
+ *
215
+ * @param name - The name of the metric.
216
+ * @param opts - The options for the metric.
217
+ * @returns The counter metric.
218
+ */
219
+ createCounter<TAttributes extends MetricAttributes = MetricAttributes>(name: string, opts?: MetricOptions): MetricsServiceCounter<TAttributes>;
220
+ /**
221
+ * Creates a new up-down counter metric.
222
+ *
223
+ * @param name - The name of the metric.
224
+ * @param opts - The options for the metric.
225
+ * @returns The up-down counter metric.
226
+ */
227
+ createUpDownCounter<TAttributes extends MetricAttributes = MetricAttributes>(name: string, opts?: MetricOptions): MetricsServiceUpDownCounter<TAttributes>;
228
+ /**
229
+ * Creates a new histogram metric.
230
+ *
231
+ * @param name - The name of the metric.
232
+ * @param opts - The options for the metric.
233
+ * @returns The histogram metric.
234
+ */
235
+ createHistogram<TAttributes extends MetricAttributes = MetricAttributes>(name: string, opts?: MetricOptions): MetricsServiceHistogram<TAttributes>;
236
+ /**
237
+ * Creates a new gauge metric.
238
+ *
239
+ * @param name - The name of the metric.
240
+ * @param opts - The options for the metric.
241
+ * @returns The gauge metric.
242
+ */
243
+ createGauge<TAttributes extends MetricAttributes = MetricAttributes>(name: string, opts?: MetricOptions): MetricsServiceGauge<TAttributes>;
244
+ /**
245
+ * Creates a new observable counter metric.
246
+ *
247
+ * @param name - The name of the metric.
248
+ * @param opts - The options for the metric.
249
+ * @returns The observable counter metric.
250
+ */
251
+ createObservableCounter<TAttributes extends MetricAttributes = MetricAttributes>(name: string, opts?: MetricOptions): MetricsServiceObservableCounter<TAttributes>;
252
+ /**
253
+ * Creates a new observable up-down counter metric.
254
+ *
255
+ * @param name - The name of the metric.
256
+ * @param opts - The options for the metric.
257
+ * @returns The observable up-down counter metric.
258
+ */
259
+ createObservableUpDownCounter<TAttributes extends MetricAttributes = MetricAttributes>(name: string, opts?: MetricOptions): MetricsServiceObservableUpDownCounter<TAttributes>;
260
+ /**
261
+ * Creates a new observable gauge metric.
262
+ *
263
+ * @param name - The name of the metric.
264
+ * @param opts - The options for the metric.
265
+ * @returns The observable gauge metric.
266
+ */
267
+ createObservableGauge<TAttributes extends MetricAttributes = MetricAttributes>(name: string, opts?: MetricOptions): MetricsServiceObservableGauge<TAttributes>;
268
+ }
269
+
87
270
  /**
88
271
  * Service for calling distributed actions
89
272
  *
@@ -109,6 +292,12 @@ declare const actionsRegistryServiceRef: _backstage_backend_plugin_api.ServiceRe
109
292
  * @alpha
110
293
  */
111
294
  declare const rootSystemMetadataServiceRef: _backstage_backend_plugin_api.ServiceRef<RootSystemMetadataService, "root", "singleton">;
295
+ /**
296
+ * Service for managing metrics.
297
+ *
298
+ * @alpha
299
+ */
300
+ declare const metricsServiceRef: _backstage_backend_plugin_api.ServiceRef<MetricsService, "plugin", "singleton">;
112
301
 
113
- export { actionsRegistryServiceRef, actionsServiceRef, rootSystemMetadataServiceRef };
114
- export type { ActionsRegistryActionContext, ActionsRegistryActionOptions, ActionsRegistryService, ActionsService, ActionsServiceAction, RootSystemMetadataService, RootSystemMetadataServicePluginInfo };
302
+ export { actionsRegistryServiceRef, actionsServiceRef, metricsServiceRef, rootSystemMetadataServiceRef };
303
+ export type { ActionsRegistryActionContext, ActionsRegistryActionOptions, ActionsRegistryService, ActionsService, ActionsServiceAction, MetricAdvice, MetricAttributeValue, MetricAttributes, MetricOptions, MetricsService, MetricsServiceCounter, MetricsServiceGauge, MetricsServiceHistogram, MetricsServiceObservable, MetricsServiceObservableCallback, MetricsServiceObservableCounter, MetricsServiceObservableGauge, MetricsServiceObservableResult, MetricsServiceObservableUpDownCounter, MetricsServiceUpDownCounter, RootSystemMetadataService, RootSystemMetadataServicePluginInfo };
package/dist/index.d.ts CHANGED
@@ -1114,6 +1114,15 @@ interface SchedulerService {
1114
1114
  * @param id - The task ID
1115
1115
  */
1116
1116
  triggerTask(id: string): Promise<void>;
1117
+ /**
1118
+ * Cancels a currently running task by ID, marking it as idle.
1119
+ *
1120
+ * If the task doesn't exist, a NotFoundError is thrown. If the task is
1121
+ * not currently running, a ConflictError is thrown.
1122
+ *
1123
+ * @param id - The task ID
1124
+ */
1125
+ cancelTask(id: string): Promise<void>;
1117
1126
  /**
1118
1127
  * Schedules a task function for recurring runs.
1119
1128
  *
@@ -1 +1 @@
1
- {"version":3,"file":"SchedulerService.cjs.js","sources":["../../../src/services/definitions/SchedulerService.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { HumanDuration, JsonObject } from '@backstage/types';\nimport { Duration } from 'luxon';\n\n/**\n * A function that can be called as a scheduled task.\n *\n * It may optionally accept an abort signal argument. When the signal triggers,\n * processing should abort and return as quickly as possible.\n *\n * @public\n */\nexport type SchedulerServiceTaskFunction =\n | ((abortSignal: AbortSignal) => void | Promise<void>)\n | (() => void | Promise<void>);\n\n/**\n * A semi-opaque type to describe an actively scheduled task.\n *\n * @public\n */\nexport type SchedulerServiceTaskDescriptor = {\n /**\n * The unique identifier of the task.\n */\n id: string;\n /**\n * The scope of the task.\n */\n scope: 'global' | 'local';\n /**\n * The settings that control the task flow. This is a semi-opaque structure\n * that is mainly there for debugging purposes. Do not make any assumptions\n * about the contents of this field.\n */\n settings: { version: number } & JsonObject;\n};\n\n/**\n * Options that control the scheduling of a task.\n *\n * @public\n */\nexport interface SchedulerServiceTaskScheduleDefinition {\n /**\n * How often you want the task to run. The system does its best to avoid\n * overlapping invocations.\n *\n * @remarks\n *\n * This is the best effort value; under some circumstances there can be\n * deviations. For example, if the task runtime is longer than the frequency\n * and the timeout has not been given or not been exceeded yet, the next\n * invocation of this task will be delayed until after the previous one\n * finishes.\n *\n * This is a required field.\n */\n frequency:\n | {\n /**\n * A crontab style string.\n *\n * @remarks\n *\n * Overview:\n *\n * ```\n * ┌────────────── second (0-60, optional)\n * │ ┌──────────── minute (0-59)\n * │ │ ┌────────── hour (0-23)\n * │ │ │ ┌──────── day of month (1-31)\n * │ │ │ │ ┌────── month (1-12)\n * │ │ │ │ │ ┌──── day of week (0-6, 0 is Sunday)\n * │ │ │ │ │ │\n * * * * * * *\n * ```\n */\n cron: string;\n }\n | Duration\n | HumanDuration\n | { trigger: 'manual' };\n\n /**\n * The maximum amount of time that a single task invocation can take, before\n * it's considered timed out and gets \"released\" such that a new invocation\n * is permitted to take place (possibly, then, on a different worker).\n */\n timeout: Duration | HumanDuration;\n\n /**\n * The amount of time that should pass before the first invocation happens.\n *\n * @remarks\n *\n * This can be useful in cold start scenarios to stagger or delay some heavy\n * compute jobs. If no value is given for this field then the first invocation\n * will happen as soon as possible according to the cadence.\n *\n * NOTE: This is a per-worker delay. If you have a cluster of workers all\n * collaborating on a task that has its `scope` field set to `'global'`, then\n * you may still see the task being processed by other long-lived workers,\n * while any given single worker is in its initial sleep delay time e.g. after\n * a deployment. Therefore, this parameter is not useful for \"globally\" pausing\n * work; its main intended use is for individual machines to get a chance to\n * reach some equilibrium at startup before triggering heavy batch workloads.\n */\n initialDelay?: Duration | HumanDuration;\n\n /**\n * Sets the scope of concurrency control / locking to apply for invocations of\n * this task.\n *\n * @remarks\n *\n * When the scope is set to the default value `'global'`, the scheduler will\n * attempt to ensure that only one worker machine runs the task at a time,\n * according to the given cadence. This means that as the number of worker\n * hosts increases, the invocation frequency of this task will not go up.\n * Instead, the load is spread randomly across hosts. This setting is useful\n * for tasks that access shared resources, for example catalog ingestion tasks\n * where you do not want many machines to repeatedly import the same data and\n * trample over each other.\n *\n * When the scope is set to `'local'`, there is no concurrency control across\n * hosts. Each host runs the task according to the given cadence similarly to\n * `setInterval`, but the runtime ensures that there are no overlapping runs.\n *\n * @defaultValue 'global'\n */\n scope?: 'global' | 'local';\n}\n\n/**\n * Config options for {@link SchedulerServiceTaskScheduleDefinition}\n * that control the scheduling of a task.\n *\n * @public\n */\nexport interface SchedulerServiceTaskScheduleDefinitionConfig {\n /**\n * How often you want the task to run. The system does its best to avoid\n * overlapping invocations.\n *\n * @remarks\n *\n * This is the best effort value; under some circumstances there can be\n * deviations. For example, if the task runtime is longer than the frequency\n * and the timeout has not been given or not been exceeded yet, the next\n * invocation of this task will be delayed until after the previous one\n * finishes.\n *\n * This is a required field.\n */\n frequency:\n | {\n /**\n * A crontab style string.\n *\n * @remarks\n *\n * Overview:\n *\n * ```\n * ┌────────────── second (0-60, optional)\n * │ ┌──────────── minute (0-59)\n * │ │ ┌────────── hour (0-23)\n * │ │ │ ┌──────── day of month (1-31)\n * │ │ │ │ ┌────── month (1-12)\n * │ │ │ │ │ ┌──── day of week (0-6, 0 is Sunday)\n * │ │ │ │ │ │\n * * * * * * *\n * ```\n */\n cron: string;\n }\n | string\n | HumanDuration\n /**\n * This task will only run when manually triggered with the `triggerTask` method; no automatic\n * scheduling. This is useful for locking of global tasks that should not be run concurrently.\n */\n | { trigger: 'manual' };\n\n /**\n * The maximum amount of time that a single task invocation can take, before\n * it's considered timed out and gets \"released\" such that a new invocation\n * is permitted to take place (possibly, then, on a different worker).\n */\n timeout: string | HumanDuration;\n\n /**\n * The amount of time that should pass before the first invocation happens.\n *\n * @remarks\n *\n * This can be useful in cold start scenarios to stagger or delay some heavy\n * compute jobs. If no value is given for this field then the first invocation\n * will happen as soon as possible according to the cadence.\n *\n * NOTE: This is a per-worker delay. If you have a cluster of workers all\n * collaborating on a task that has its `scope` field set to `'global'`, then\n * you may still see the task being processed by other long-lived workers,\n * while any given single worker is in its initial sleep delay time e.g. after\n * a deployment. Therefore, this parameter is not useful for \"globally\" pausing\n * work; its main intended use is for individual machines to get a chance to\n * reach some equilibrium at startup before triggering heavy batch workloads.\n */\n initialDelay?: string | HumanDuration;\n\n /**\n * Sets the scope of concurrency control / locking to apply for invocations of\n * this task.\n *\n * @remarks\n *\n * When the scope is set to the default value `'global'`, the scheduler will\n * attempt to ensure that only one worker machine runs the task at a time,\n * according to the given cadence. This means that as the number of worker\n * hosts increases, the invocation frequency of this task will not go up.\n * Instead, the load is spread randomly across hosts. This setting is useful\n * for tasks that access shared resources, for example catalog ingestion tasks\n * where you do not want many machines to repeatedly import the same data and\n * trample over each other.\n *\n * When the scope is set to `'local'`, there is no concurrency control across\n * hosts. Each host runs the task according to the given cadence similarly to\n * `setInterval`, but the runtime ensures that there are no overlapping runs.\n *\n * @defaultValue 'global'\n */\n scope?: 'global' | 'local';\n}\n\n/**\n * Options that apply to the invocation of a given task.\n *\n * @public\n */\nexport interface SchedulerServiceTaskInvocationDefinition {\n /**\n * A unique ID (within the scope of the plugin) for the task.\n */\n id: string;\n\n /**\n * The actual task function to be invoked regularly.\n */\n fn: SchedulerServiceTaskFunction;\n\n /**\n * An abort signal that, when triggered, will stop the recurring execution of\n * the task.\n */\n signal?: AbortSignal;\n}\n\n/**\n * A previously prepared task schedule, ready to be invoked.\n *\n * @public\n */\nexport interface SchedulerServiceTaskRunner {\n /**\n * Takes the schedule and executes an actual task using it.\n *\n * @param task - The actual runtime properties of the task\n */\n run(task: SchedulerServiceTaskInvocationDefinition): Promise<void>;\n}\n\n/**\n * Deals with the scheduling of distributed tasks, for a given plugin.\n *\n * See the {@link https://backstage.io/docs/backend-system/core-services/scheduler | service documentation} for more details.\n *\n * @public\n */\nexport interface SchedulerService {\n /**\n * Manually triggers a task by ID.\n *\n * If the task doesn't exist, a NotFoundError is thrown. If the task is\n * currently running, a ConflictError is thrown.\n *\n * @param id - The task ID\n */\n triggerTask(id: string): Promise<void>;\n\n /**\n * Schedules a task function for recurring runs.\n *\n * @remarks\n *\n * The `scope` task field controls whether to use coordinated exclusive\n * invocation across workers, or to just coordinate within the current worker.\n *\n * This convenience method performs both the scheduling and invocation in one\n * go.\n *\n * @param task - The task definition\n */\n scheduleTask(\n task: SchedulerServiceTaskScheduleDefinition &\n SchedulerServiceTaskInvocationDefinition,\n ): Promise<void>;\n\n /**\n * Creates a scheduled but dormant recurring task, ready to be launched at a\n * later time.\n *\n * @remarks\n *\n * This method is useful for pre-creating a schedule in outer code to be\n * passed into an inner implementation, such that the outer code controls\n * scheduling while inner code controls implementation.\n *\n * @param schedule - The task schedule\n */\n createScheduledTaskRunner(\n schedule: SchedulerServiceTaskScheduleDefinition,\n ): SchedulerServiceTaskRunner;\n\n /**\n * Returns all scheduled tasks registered to this scheduler.\n *\n * @remarks\n *\n * This method is useful for triggering tasks manually using the triggerTask\n * functionality. Note that the returned tasks contain only tasks that have\n * been initialized in this instance of the scheduler.\n *\n * @returns Scheduled tasks\n */\n getScheduledTasks(): Promise<SchedulerServiceTaskDescriptor[]>;\n}\n\nfunction readFrequency(\n config: Config,\n key: string,\n): { cron: string } | HumanDuration | { trigger: 'manual' } {\n const value = config.get(key);\n if (typeof value === 'object' && (value as { cron?: string }).cron) {\n return value as { cron: string };\n }\n if (\n typeof value === 'object' &&\n (value as { trigger?: string }).trigger === 'manual'\n ) {\n return { trigger: 'manual' };\n }\n\n return readDurationFromConfig(config, { key });\n}\n\n/**\n * Reads a {@link SchedulerServiceTaskScheduleDefinition} from config. Expects\n * the config not to be the root config, but the config for the definition.\n *\n * @param config - config for a TaskScheduleDefinition.\n * @public\n */\nexport function readSchedulerServiceTaskScheduleDefinitionFromConfig(\n config: Config,\n): SchedulerServiceTaskScheduleDefinition {\n const frequency = readFrequency(config, 'frequency');\n const timeout = readDurationFromConfig(config, { key: 'timeout' });\n\n const initialDelay = config.has('initialDelay')\n ? readDurationFromConfig(config, { key: 'initialDelay' })\n : undefined;\n\n const scope = config.getOptionalString('scope');\n if (scope && !['global', 'local'].includes(scope)) {\n throw new Error(\n `Only \"global\" or \"local\" are allowed for TaskScheduleDefinition.scope, but got: ${scope}`,\n );\n }\n\n return {\n frequency,\n timeout,\n initialDelay,\n scope: scope as 'global' | 'local' | undefined,\n };\n}\n"],"names":["config","readDurationFromConfig"],"mappings":";;;;AAkWA,SAAS,aAAA,CACPA,UACA,GAAA,EAC0D;AAC1D,EAAA,MAAM,KAAA,GAAQA,QAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAC5B,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAa,KAAA,CAA4B,IAAA,EAAM;AAClE,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,IACE,OAAO,KAAA,KAAU,QAAA,IAChB,KAAA,CAA+B,YAAY,QAAA,EAC5C;AACA,IAAA,OAAO,EAAE,SAAS,QAAA,EAAS;AAAA,EAC7B;AAEA,EAAA,OAAOC,6BAAA,CAAuBD,QAAA,EAAQ,EAAE,GAAA,EAAK,CAAA;AAC/C;AASO,SAAS,qDACdA,QAAA,EACwC;AACxC,EAAA,MAAM,SAAA,GAAY,aAAA,CAAcA,QAAA,EAAQ,WAAW,CAAA;AACnD,EAAA,MAAM,UAAUC,6BAAA,CAAuBD,QAAA,EAAQ,EAAE,GAAA,EAAK,WAAW,CAAA;AAEjE,EAAA,MAAM,YAAA,GAAeA,QAAA,CAAO,GAAA,CAAI,cAAc,CAAA,GAC1CC,6BAAA,CAAuBD,QAAA,EAAQ,EAAE,GAAA,EAAK,cAAA,EAAgB,CAAA,GACtD,MAAA;AAEJ,EAAA,MAAM,KAAA,GAAQA,QAAA,CAAO,iBAAA,CAAkB,OAAO,CAAA;AAC9C,EAAA,IAAI,KAAA,IAAS,CAAC,CAAC,QAAA,EAAU,OAAO,CAAA,CAAE,QAAA,CAAS,KAAK,CAAA,EAAG;AACjD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,mFAAmF,KAAK,CAAA;AAAA,KAC1F;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,SAAA;AAAA,IACA,OAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"SchedulerService.cjs.js","sources":["../../../src/services/definitions/SchedulerService.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { HumanDuration, JsonObject } from '@backstage/types';\nimport { Duration } from 'luxon';\n\n/**\n * A function that can be called as a scheduled task.\n *\n * It may optionally accept an abort signal argument. When the signal triggers,\n * processing should abort and return as quickly as possible.\n *\n * @public\n */\nexport type SchedulerServiceTaskFunction =\n | ((abortSignal: AbortSignal) => void | Promise<void>)\n | (() => void | Promise<void>);\n\n/**\n * A semi-opaque type to describe an actively scheduled task.\n *\n * @public\n */\nexport type SchedulerServiceTaskDescriptor = {\n /**\n * The unique identifier of the task.\n */\n id: string;\n /**\n * The scope of the task.\n */\n scope: 'global' | 'local';\n /**\n * The settings that control the task flow. This is a semi-opaque structure\n * that is mainly there for debugging purposes. Do not make any assumptions\n * about the contents of this field.\n */\n settings: { version: number } & JsonObject;\n};\n\n/**\n * Options that control the scheduling of a task.\n *\n * @public\n */\nexport interface SchedulerServiceTaskScheduleDefinition {\n /**\n * How often you want the task to run. The system does its best to avoid\n * overlapping invocations.\n *\n * @remarks\n *\n * This is the best effort value; under some circumstances there can be\n * deviations. For example, if the task runtime is longer than the frequency\n * and the timeout has not been given or not been exceeded yet, the next\n * invocation of this task will be delayed until after the previous one\n * finishes.\n *\n * This is a required field.\n */\n frequency:\n | {\n /**\n * A crontab style string.\n *\n * @remarks\n *\n * Overview:\n *\n * ```\n * ┌────────────── second (0-60, optional)\n * │ ┌──────────── minute (0-59)\n * │ │ ┌────────── hour (0-23)\n * │ │ │ ┌──────── day of month (1-31)\n * │ │ │ │ ┌────── month (1-12)\n * │ │ │ │ │ ┌──── day of week (0-6, 0 is Sunday)\n * │ │ │ │ │ │\n * * * * * * *\n * ```\n */\n cron: string;\n }\n | Duration\n | HumanDuration\n | { trigger: 'manual' };\n\n /**\n * The maximum amount of time that a single task invocation can take, before\n * it's considered timed out and gets \"released\" such that a new invocation\n * is permitted to take place (possibly, then, on a different worker).\n */\n timeout: Duration | HumanDuration;\n\n /**\n * The amount of time that should pass before the first invocation happens.\n *\n * @remarks\n *\n * This can be useful in cold start scenarios to stagger or delay some heavy\n * compute jobs. If no value is given for this field then the first invocation\n * will happen as soon as possible according to the cadence.\n *\n * NOTE: This is a per-worker delay. If you have a cluster of workers all\n * collaborating on a task that has its `scope` field set to `'global'`, then\n * you may still see the task being processed by other long-lived workers,\n * while any given single worker is in its initial sleep delay time e.g. after\n * a deployment. Therefore, this parameter is not useful for \"globally\" pausing\n * work; its main intended use is for individual machines to get a chance to\n * reach some equilibrium at startup before triggering heavy batch workloads.\n */\n initialDelay?: Duration | HumanDuration;\n\n /**\n * Sets the scope of concurrency control / locking to apply for invocations of\n * this task.\n *\n * @remarks\n *\n * When the scope is set to the default value `'global'`, the scheduler will\n * attempt to ensure that only one worker machine runs the task at a time,\n * according to the given cadence. This means that as the number of worker\n * hosts increases, the invocation frequency of this task will not go up.\n * Instead, the load is spread randomly across hosts. This setting is useful\n * for tasks that access shared resources, for example catalog ingestion tasks\n * where you do not want many machines to repeatedly import the same data and\n * trample over each other.\n *\n * When the scope is set to `'local'`, there is no concurrency control across\n * hosts. Each host runs the task according to the given cadence similarly to\n * `setInterval`, but the runtime ensures that there are no overlapping runs.\n *\n * @defaultValue 'global'\n */\n scope?: 'global' | 'local';\n}\n\n/**\n * Config options for {@link SchedulerServiceTaskScheduleDefinition}\n * that control the scheduling of a task.\n *\n * @public\n */\nexport interface SchedulerServiceTaskScheduleDefinitionConfig {\n /**\n * How often you want the task to run. The system does its best to avoid\n * overlapping invocations.\n *\n * @remarks\n *\n * This is the best effort value; under some circumstances there can be\n * deviations. For example, if the task runtime is longer than the frequency\n * and the timeout has not been given or not been exceeded yet, the next\n * invocation of this task will be delayed until after the previous one\n * finishes.\n *\n * This is a required field.\n */\n frequency:\n | {\n /**\n * A crontab style string.\n *\n * @remarks\n *\n * Overview:\n *\n * ```\n * ┌────────────── second (0-60, optional)\n * │ ┌──────────── minute (0-59)\n * │ │ ┌────────── hour (0-23)\n * │ │ │ ┌──────── day of month (1-31)\n * │ │ │ │ ┌────── month (1-12)\n * │ │ │ │ │ ┌──── day of week (0-6, 0 is Sunday)\n * │ │ │ │ │ │\n * * * * * * *\n * ```\n */\n cron: string;\n }\n | string\n | HumanDuration\n /**\n * This task will only run when manually triggered with the `triggerTask` method; no automatic\n * scheduling. This is useful for locking of global tasks that should not be run concurrently.\n */\n | { trigger: 'manual' };\n\n /**\n * The maximum amount of time that a single task invocation can take, before\n * it's considered timed out and gets \"released\" such that a new invocation\n * is permitted to take place (possibly, then, on a different worker).\n */\n timeout: string | HumanDuration;\n\n /**\n * The amount of time that should pass before the first invocation happens.\n *\n * @remarks\n *\n * This can be useful in cold start scenarios to stagger or delay some heavy\n * compute jobs. If no value is given for this field then the first invocation\n * will happen as soon as possible according to the cadence.\n *\n * NOTE: This is a per-worker delay. If you have a cluster of workers all\n * collaborating on a task that has its `scope` field set to `'global'`, then\n * you may still see the task being processed by other long-lived workers,\n * while any given single worker is in its initial sleep delay time e.g. after\n * a deployment. Therefore, this parameter is not useful for \"globally\" pausing\n * work; its main intended use is for individual machines to get a chance to\n * reach some equilibrium at startup before triggering heavy batch workloads.\n */\n initialDelay?: string | HumanDuration;\n\n /**\n * Sets the scope of concurrency control / locking to apply for invocations of\n * this task.\n *\n * @remarks\n *\n * When the scope is set to the default value `'global'`, the scheduler will\n * attempt to ensure that only one worker machine runs the task at a time,\n * according to the given cadence. This means that as the number of worker\n * hosts increases, the invocation frequency of this task will not go up.\n * Instead, the load is spread randomly across hosts. This setting is useful\n * for tasks that access shared resources, for example catalog ingestion tasks\n * where you do not want many machines to repeatedly import the same data and\n * trample over each other.\n *\n * When the scope is set to `'local'`, there is no concurrency control across\n * hosts. Each host runs the task according to the given cadence similarly to\n * `setInterval`, but the runtime ensures that there are no overlapping runs.\n *\n * @defaultValue 'global'\n */\n scope?: 'global' | 'local';\n}\n\n/**\n * Options that apply to the invocation of a given task.\n *\n * @public\n */\nexport interface SchedulerServiceTaskInvocationDefinition {\n /**\n * A unique ID (within the scope of the plugin) for the task.\n */\n id: string;\n\n /**\n * The actual task function to be invoked regularly.\n */\n fn: SchedulerServiceTaskFunction;\n\n /**\n * An abort signal that, when triggered, will stop the recurring execution of\n * the task.\n */\n signal?: AbortSignal;\n}\n\n/**\n * A previously prepared task schedule, ready to be invoked.\n *\n * @public\n */\nexport interface SchedulerServiceTaskRunner {\n /**\n * Takes the schedule and executes an actual task using it.\n *\n * @param task - The actual runtime properties of the task\n */\n run(task: SchedulerServiceTaskInvocationDefinition): Promise<void>;\n}\n\n/**\n * Deals with the scheduling of distributed tasks, for a given plugin.\n *\n * See the {@link https://backstage.io/docs/backend-system/core-services/scheduler | service documentation} for more details.\n *\n * @public\n */\nexport interface SchedulerService {\n /**\n * Manually triggers a task by ID.\n *\n * If the task doesn't exist, a NotFoundError is thrown. If the task is\n * currently running, a ConflictError is thrown.\n *\n * @param id - The task ID\n */\n triggerTask(id: string): Promise<void>;\n\n /**\n * Cancels a currently running task by ID, marking it as idle.\n *\n * If the task doesn't exist, a NotFoundError is thrown. If the task is\n * not currently running, a ConflictError is thrown.\n *\n * @param id - The task ID\n */\n cancelTask(id: string): Promise<void>;\n\n /**\n * Schedules a task function for recurring runs.\n *\n * @remarks\n *\n * The `scope` task field controls whether to use coordinated exclusive\n * invocation across workers, or to just coordinate within the current worker.\n *\n * This convenience method performs both the scheduling and invocation in one\n * go.\n *\n * @param task - The task definition\n */\n scheduleTask(\n task: SchedulerServiceTaskScheduleDefinition &\n SchedulerServiceTaskInvocationDefinition,\n ): Promise<void>;\n\n /**\n * Creates a scheduled but dormant recurring task, ready to be launched at a\n * later time.\n *\n * @remarks\n *\n * This method is useful for pre-creating a schedule in outer code to be\n * passed into an inner implementation, such that the outer code controls\n * scheduling while inner code controls implementation.\n *\n * @param schedule - The task schedule\n */\n createScheduledTaskRunner(\n schedule: SchedulerServiceTaskScheduleDefinition,\n ): SchedulerServiceTaskRunner;\n\n /**\n * Returns all scheduled tasks registered to this scheduler.\n *\n * @remarks\n *\n * This method is useful for triggering tasks manually using the triggerTask\n * functionality. Note that the returned tasks contain only tasks that have\n * been initialized in this instance of the scheduler.\n *\n * @returns Scheduled tasks\n */\n getScheduledTasks(): Promise<SchedulerServiceTaskDescriptor[]>;\n}\n\nfunction readFrequency(\n config: Config,\n key: string,\n): { cron: string } | HumanDuration | { trigger: 'manual' } {\n const value = config.get(key);\n if (typeof value === 'object' && (value as { cron?: string }).cron) {\n return value as { cron: string };\n }\n if (\n typeof value === 'object' &&\n (value as { trigger?: string }).trigger === 'manual'\n ) {\n return { trigger: 'manual' };\n }\n\n return readDurationFromConfig(config, { key });\n}\n\n/**\n * Reads a {@link SchedulerServiceTaskScheduleDefinition} from config. Expects\n * the config not to be the root config, but the config for the definition.\n *\n * @param config - config for a TaskScheduleDefinition.\n * @public\n */\nexport function readSchedulerServiceTaskScheduleDefinitionFromConfig(\n config: Config,\n): SchedulerServiceTaskScheduleDefinition {\n const frequency = readFrequency(config, 'frequency');\n const timeout = readDurationFromConfig(config, { key: 'timeout' });\n\n const initialDelay = config.has('initialDelay')\n ? readDurationFromConfig(config, { key: 'initialDelay' })\n : undefined;\n\n const scope = config.getOptionalString('scope');\n if (scope && !['global', 'local'].includes(scope)) {\n throw new Error(\n `Only \"global\" or \"local\" are allowed for TaskScheduleDefinition.scope, but got: ${scope}`,\n );\n }\n\n return {\n frequency,\n timeout,\n initialDelay,\n scope: scope as 'global' | 'local' | undefined,\n };\n}\n"],"names":["config","readDurationFromConfig"],"mappings":";;;;AA4WA,SAAS,aAAA,CACPA,UACA,GAAA,EAC0D;AAC1D,EAAA,MAAM,KAAA,GAAQA,QAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAC5B,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAa,KAAA,CAA4B,IAAA,EAAM;AAClE,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,IACE,OAAO,KAAA,KAAU,QAAA,IAChB,KAAA,CAA+B,YAAY,QAAA,EAC5C;AACA,IAAA,OAAO,EAAE,SAAS,QAAA,EAAS;AAAA,EAC7B;AAEA,EAAA,OAAOC,6BAAA,CAAuBD,QAAA,EAAQ,EAAE,GAAA,EAAK,CAAA;AAC/C;AASO,SAAS,qDACdA,QAAA,EACwC;AACxC,EAAA,MAAM,SAAA,GAAY,aAAA,CAAcA,QAAA,EAAQ,WAAW,CAAA;AACnD,EAAA,MAAM,UAAUC,6BAAA,CAAuBD,QAAA,EAAQ,EAAE,GAAA,EAAK,WAAW,CAAA;AAEjE,EAAA,MAAM,YAAA,GAAeA,QAAA,CAAO,GAAA,CAAI,cAAc,CAAA,GAC1CC,6BAAA,CAAuBD,QAAA,EAAQ,EAAE,GAAA,EAAK,cAAA,EAAgB,CAAA,GACtD,MAAA;AAEJ,EAAA,MAAM,KAAA,GAAQA,QAAA,CAAO,iBAAA,CAAkB,OAAO,CAAA;AAC9C,EAAA,IAAI,KAAA,IAAS,CAAC,CAAC,QAAA,EAAU,OAAO,CAAA,CAAE,QAAA,CAAS,KAAK,CAAA,EAAG;AACjD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,mFAAmF,KAAK,CAAA;AAAA,KAC1F;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,SAAA;AAAA,IACA,OAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-plugin-api",
3
- "version": "1.7.0",
3
+ "version": "1.8.0-next.1",
4
4
  "description": "Core API used by Backstage backend plugins",
5
5
  "backstage": {
6
6
  "role": "node-library"
@@ -65,13 +65,13 @@
65
65
  "test": "backstage-cli package test"
66
66
  },
67
67
  "dependencies": {
68
- "@backstage/cli-common": "^0.1.18",
69
- "@backstage/config": "^1.3.6",
70
- "@backstage/errors": "^1.2.7",
71
- "@backstage/plugin-auth-node": "^0.6.13",
72
- "@backstage/plugin-permission-common": "^0.9.6",
73
- "@backstage/plugin-permission-node": "^0.10.10",
74
- "@backstage/types": "^1.2.2",
68
+ "@backstage/cli-common": "0.2.0-next.2",
69
+ "@backstage/config": "1.3.6",
70
+ "@backstage/errors": "1.2.7",
71
+ "@backstage/plugin-auth-node": "0.6.14-next.2",
72
+ "@backstage/plugin-permission-common": "0.9.6",
73
+ "@backstage/plugin-permission-node": "0.10.11-next.1",
74
+ "@backstage/types": "1.2.2",
75
75
  "@types/express": "^4.17.6",
76
76
  "@types/json-schema": "^7.0.6",
77
77
  "@types/luxon": "^3.0.0",
@@ -81,8 +81,8 @@
81
81
  "zod": "^3.25.76"
82
82
  },
83
83
  "devDependencies": {
84
- "@backstage/backend-test-utils": "^1.11.0",
85
- "@backstage/cli": "^0.35.4"
84
+ "@backstage/backend-test-utils": "1.11.1-next.2",
85
+ "@backstage/cli": "0.36.0-next.2"
86
86
  },
87
87
  "configSchema": "config.d.ts"
88
88
  }