@backstage/frontend-app-api 0.14.1 → 0.15.0-next.2
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 +46 -7
- package/config.d.ts +0 -9
- package/dist/frontend-plugin-api/src/wiring/resolveExtensionDefinition.esm.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/tree/instantiateAppNodeTree.esm.js +48 -17
- package/dist/tree/instantiateAppNodeTree.esm.js.map +1 -1
- package/dist/tree/resolveAppNodeSpecs.esm.js +11 -5
- package/dist/tree/resolveAppNodeSpecs.esm.js.map +1 -1
- package/dist/tree/resolveAppTree.esm.js +3 -0
- package/dist/tree/resolveAppTree.esm.js.map +1 -1
- package/dist/wiring/createErrorCollector.esm.js.map +1 -1
- package/dist/wiring/createPluginInfoAttacher.esm.js +4 -1
- package/dist/wiring/createPluginInfoAttacher.esm.js.map +1 -1
- package/dist/wiring/createSpecializedApp.esm.js +10 -6
- package/dist/wiring/createSpecializedApp.esm.js.map +1 -1
- package/package.json +15 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,55 @@
|
|
|
1
1
|
# @backstage/frontend-app-api
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.15.0-next.2
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
- 5683c85: Bump to latest zod to ensure it has the latest features
|
|
7
|
+
- a7e0d50: Prepare for React Router v7 migration by updating to v6.30.2 across all NFS packages and enabling v7 future flags. Convert routes from splat paths to parent/child structure with Outlet components.
|
|
9
8
|
- Updated dependencies
|
|
10
|
-
- @backstage/
|
|
11
|
-
- @backstage/frontend-plugin-api@0.
|
|
12
|
-
- @backstage/
|
|
13
|
-
- @backstage/core-
|
|
9
|
+
- @backstage/core-app-api@1.19.5-next.1
|
|
10
|
+
- @backstage/frontend-plugin-api@0.14.0-next.2
|
|
11
|
+
- @backstage/frontend-defaults@0.4.0-next.2
|
|
12
|
+
- @backstage/core-plugin-api@1.12.3-next.1
|
|
13
|
+
- @backstage/version-bridge@1.0.12-next.0
|
|
14
|
+
|
|
15
|
+
## 0.15.0-next.1
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- 55b2ef6: **BREAKING**: Updated the behavior of the new API override logic to reject the override and block app startup instead of just logging a deprecation warning.
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- 09032d7: Internal update to simplify testing utility implementations.
|
|
24
|
+
- Updated dependencies
|
|
25
|
+
- @backstage/frontend-defaults@0.4.0-next.1
|
|
26
|
+
- @backstage/frontend-plugin-api@0.14.0-next.1
|
|
27
|
+
|
|
28
|
+
## 0.14.1-next.0
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- 17e0eb3: Updated the behavior of the new API override logic to log a deprecation warning instead of rejecting the override and blocking app startup, as was originally intended.
|
|
33
|
+
- 7edb810: Implemented support for the `internal` extension input option.
|
|
34
|
+
- 492503a: Updated error reporting and app tree resolution logic to attribute errors to the correct extension and allow app startup to proceed more optimistically:
|
|
35
|
+
|
|
36
|
+
- If an attachment fails to provide the required input data, the error is now attributed to the attachment rather than the parent extension.
|
|
37
|
+
- Singleton extension inputs will now only forward attachment errors if the input is required.
|
|
38
|
+
- Array extension inputs will now filter out failed attachments instead of failing the entire app tree resolution.
|
|
39
|
+
|
|
40
|
+
- 122d39c: Completely removed support for the deprecated `app.experimental.packages` configuration. Replace existing usage directly with `app.packages`.
|
|
41
|
+
- 9554c36: **DEPRECATED**: Deprecated support for multiple attachment points.
|
|
42
|
+
- 53b6549: Plugins in the new frontend system now have a `pluginId` field rather than `id` to better align with naming conventions used throughout the frontend and backend systems. The old field is still present but marked as deprecated. All internal code has been updated to prefer `pluginId` while maintaining backward compatibility by falling back to `id` when needed.
|
|
43
|
+
- 69d880e: Bump to latest zod to ensure it has the latest features
|
|
44
|
+
- Updated dependencies
|
|
45
|
+
- @backstage/frontend-defaults@0.3.6-next.0
|
|
46
|
+
- @backstage/frontend-plugin-api@0.14.0-next.0
|
|
47
|
+
- @backstage/core-plugin-api@1.12.2-next.0
|
|
48
|
+
- @backstage/core-app-api@1.19.4-next.0
|
|
49
|
+
- @backstage/config@1.3.6
|
|
50
|
+
- @backstage/errors@1.2.7
|
|
51
|
+
- @backstage/types@1.2.2
|
|
52
|
+
- @backstage/version-bridge@1.0.11
|
|
14
53
|
|
|
15
54
|
## 0.14.0
|
|
16
55
|
|
package/config.d.ts
CHANGED
|
@@ -16,15 +16,6 @@
|
|
|
16
16
|
|
|
17
17
|
export interface Config {
|
|
18
18
|
app?: {
|
|
19
|
-
experimental?: {
|
|
20
|
-
/**
|
|
21
|
-
* @visibility frontend
|
|
22
|
-
* @deepVisibility frontend
|
|
23
|
-
* @deprecated This is no longer experimental; use `app.packages` instead.
|
|
24
|
-
*/
|
|
25
|
-
packages?: 'all' | { include?: string[]; exclude?: string[] };
|
|
26
|
-
};
|
|
27
|
-
|
|
28
19
|
/**
|
|
29
20
|
* Controls what packages are loaded by the new frontend system.
|
|
30
21
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveExtensionDefinition.esm.js","sources":["../../../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts"],"sourcesContent":["/*\n * Copyright 2023 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 { ApiHolder, AppNode } from '../apis';\nimport {\n ExtensionDefinitionAttachTo,\n ExtensionDefinition,\n ExtensionDefinitionParameters,\n ResolvedExtensionInputs,\n} from './createExtension';\nimport { PortableSchema } from '../schema';\nimport { ExtensionInput } from './createExtensionInput';\nimport { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport {\n OpaqueExtensionDefinition,\n OpaqueExtensionInput,\n} from '@internal/frontend';\n\n/** @public */\nexport type ExtensionAttachTo =\n | { id: string; input: string }\n | Array<{ id: string; input: string }>;\n\n/**\n * @deprecated Use {@link ExtensionAttachTo} instead.\n * @public\n */\nexport type ExtensionAttachToSpec = ExtensionAttachTo;\n\n/** @public */\nexport interface Extension<TConfig, TConfigInput = TConfig> {\n $$type: '@backstage/Extension';\n readonly id: string;\n readonly attachTo: ExtensionAttachToSpec;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<TConfig, TConfigInput>;\n}\n\n/** @internal */\nexport type InternalExtension<TConfig, TConfigInput> = Extension<\n TConfig,\n TConfigInput\n> &\n (\n | {\n readonly version: 'v1';\n readonly inputs: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: ExtensionDataRef;\n };\n factory(context: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly inputs: { [inputName in string]: ExtensionInput };\n readonly output: Array<ExtensionDataRef>;\n factory(options: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n }\n );\n\n/** @internal */\nexport function toInternalExtension<TConfig, TConfigInput>(\n overrides: Extension<TConfig, TConfigInput>,\n): InternalExtension<TConfig, TConfigInput> {\n const internal = overrides as InternalExtension<TConfig, TConfigInput>;\n if (internal.$$type !== '@backstage/Extension') {\n throw new Error(\n `Invalid extension instance, bad type '${internal.$$type}'`,\n );\n }\n const version = internal.version;\n if (version !== 'v1' && version !== 'v2') {\n throw new Error(`Invalid extension instance, bad version '${version}'`);\n }\n return internal;\n}\n\n/** @ignore */\nexport type ResolveExtensionId<\n TExtension extends ExtensionDefinition,\n TNamespace extends string,\n> = TExtension extends ExtensionDefinition<{\n kind: infer IKind extends string | undefined;\n name: infer IName extends string | undefined;\n params: any;\n}>\n ? [string] extends [IKind | IName]\n ? never\n : (\n undefined extends IName ? TNamespace : `${TNamespace}/${IName}`\n ) extends infer INamePart extends string\n ? IKind extends string\n ? `${IKind}:${INamePart}`\n : INamePart\n : never\n : never;\n\nfunction resolveExtensionId(\n kind?: string,\n namespace?: string,\n name?: string,\n): string {\n const namePart =\n name && namespace ? `${namespace}/${name}` : namespace || name;\n if (!namePart) {\n throw new Error(\n `Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`,\n );\n }\n\n return kind ? `${kind}:${namePart}` : namePart;\n}\n\nfunction resolveAttachTo(\n attachTo: ExtensionDefinitionAttachTo,\n namespace?: string,\n): ExtensionAttachToSpec {\n const resolveSpec = (\n spec:
|
|
1
|
+
{"version":3,"file":"resolveExtensionDefinition.esm.js","sources":["../../../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts"],"sourcesContent":["/*\n * Copyright 2023 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 { ApiHolder, AppNode } from '../apis';\nimport {\n ExtensionDefinitionAttachTo,\n ExtensionDefinition,\n ExtensionDefinitionParameters,\n ResolvedExtensionInputs,\n} from './createExtension';\nimport { PortableSchema } from '../schema';\nimport { ExtensionInput } from './createExtensionInput';\nimport { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport {\n OpaqueExtensionDefinition,\n OpaqueExtensionInput,\n} from '@internal/frontend';\n\n/** @public */\nexport type ExtensionAttachTo =\n | { id: string; input: string }\n | Array<{ id: string; input: string }>;\n\n/**\n * @deprecated Use {@link ExtensionAttachTo} instead.\n * @public\n */\nexport type ExtensionAttachToSpec = ExtensionAttachTo;\n\n/** @public */\nexport interface Extension<TConfig, TConfigInput = TConfig> {\n $$type: '@backstage/Extension';\n readonly id: string;\n readonly attachTo: ExtensionAttachToSpec;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<TConfig, TConfigInput>;\n}\n\n/** @internal */\nexport type InternalExtension<TConfig, TConfigInput> = Extension<\n TConfig,\n TConfigInput\n> &\n (\n | {\n readonly version: 'v1';\n readonly inputs: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: ExtensionDataRef;\n };\n factory(context: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly inputs: { [inputName in string]: ExtensionInput };\n readonly output: Array<ExtensionDataRef>;\n factory(options: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n }\n );\n\n/** @internal */\nexport function toInternalExtension<TConfig, TConfigInput>(\n overrides: Extension<TConfig, TConfigInput>,\n): InternalExtension<TConfig, TConfigInput> {\n const internal = overrides as InternalExtension<TConfig, TConfigInput>;\n if (internal.$$type !== '@backstage/Extension') {\n throw new Error(\n `Invalid extension instance, bad type '${internal.$$type}'`,\n );\n }\n const version = internal.version;\n if (version !== 'v1' && version !== 'v2') {\n throw new Error(`Invalid extension instance, bad version '${version}'`);\n }\n return internal;\n}\n\n/** @ignore */\nexport type ResolveExtensionId<\n TExtension extends ExtensionDefinition,\n TNamespace extends string,\n> = TExtension extends ExtensionDefinition<{\n kind: infer IKind extends string | undefined;\n name: infer IName extends string | undefined;\n params: any;\n}>\n ? [string] extends [IKind | IName]\n ? never\n : (\n undefined extends IName ? TNamespace : `${TNamespace}/${IName}`\n ) extends infer INamePart extends string\n ? IKind extends string\n ? `${IKind}:${INamePart}`\n : INamePart\n : never\n : never;\n\nfunction resolveExtensionId(\n kind?: string,\n namespace?: string,\n name?: string,\n): string {\n const namePart =\n name && namespace ? `${namespace}/${name}` : namespace || name;\n if (!namePart) {\n throw new Error(\n `Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`,\n );\n }\n\n return kind ? `${kind}:${namePart}` : namePart;\n}\n\nfunction resolveAttachTo(\n attachTo: ExtensionDefinitionAttachTo | ExtensionDefinitionAttachTo[],\n namespace?: string,\n): ExtensionAttachToSpec {\n const resolveSpec = (\n spec: ExtensionDefinitionAttachTo,\n ): { id: string; input: string } => {\n if (OpaqueExtensionInput.isType(spec)) {\n const { context } = OpaqueExtensionInput.toInternal(spec);\n if (!context) {\n throw new Error(\n 'Invalid input object without a parent extension used as attachment point',\n );\n }\n return {\n id: resolveExtensionId(context.kind, namespace, context.name),\n input: context.input,\n };\n }\n if ('relative' in spec && spec.relative) {\n return {\n id: resolveExtensionId(\n spec.relative.kind,\n namespace,\n spec.relative.name,\n ),\n input: spec.input,\n };\n }\n if ('id' in spec) {\n return { id: spec.id, input: spec.input };\n }\n throw new Error('Invalid attachment point specification');\n };\n\n if (Array.isArray(attachTo)) {\n return attachTo.map(resolveSpec);\n }\n\n return resolveSpec(attachTo);\n}\n\n/** @internal */\nexport function resolveExtensionDefinition<\n T extends ExtensionDefinitionParameters,\n>(\n definition: ExtensionDefinition<T>,\n context?: { namespace?: string },\n): Extension<T['config'], T['configInput']> {\n const internalDefinition = OpaqueExtensionDefinition.toInternal(definition);\n\n const {\n name,\n kind,\n namespace: internalNamespace,\n override: _skip2,\n attachTo,\n ...rest\n } = internalDefinition;\n\n const namespace = internalNamespace ?? context?.namespace;\n const id = resolveExtensionId(kind, namespace, name);\n\n return {\n ...rest,\n attachTo: resolveAttachTo(attachTo, namespace),\n $$type: '@backstage/Extension',\n version: internalDefinition.version,\n id,\n toString() {\n return `Extension{id=${id}}`;\n },\n } as InternalExtension<T['config'], T['configInput']> & Object;\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -91,6 +91,14 @@ type AppErrorTypes = {
|
|
|
91
91
|
inputName: string;
|
|
92
92
|
};
|
|
93
93
|
};
|
|
94
|
+
EXTENSION_INPUT_INTERNAL_IGNORED: {
|
|
95
|
+
context: {
|
|
96
|
+
node: AppNode;
|
|
97
|
+
inputName: string;
|
|
98
|
+
extensionId: string;
|
|
99
|
+
plugin: FrontendPlugin;
|
|
100
|
+
};
|
|
101
|
+
};
|
|
94
102
|
EXTENSION_ATTACHMENT_CONFLICT: {
|
|
95
103
|
context: {
|
|
96
104
|
node: AppNode;
|
|
@@ -7,21 +7,21 @@ import '../frontend-internal/src/wiring/InternalFrontendPlugin.esm.js';
|
|
|
7
7
|
import '../frontend-internal/src/wiring/InternalSwappableComponentRef.esm.js';
|
|
8
8
|
|
|
9
9
|
const INSTANTIATION_FAILED = new Error("Instantiation failed");
|
|
10
|
-
function mapWithFailures(iterable, callback) {
|
|
10
|
+
function mapWithFailures(iterable, callback, options) {
|
|
11
11
|
let failed = false;
|
|
12
|
-
const results =
|
|
12
|
+
const results = [];
|
|
13
|
+
for (const item of iterable) {
|
|
13
14
|
try {
|
|
14
|
-
|
|
15
|
+
results.push(callback(item));
|
|
15
16
|
} catch (error) {
|
|
16
17
|
if (error === INSTANTIATION_FAILED) {
|
|
17
18
|
failed = true;
|
|
18
19
|
} else {
|
|
19
20
|
throw error;
|
|
20
21
|
}
|
|
21
|
-
return null;
|
|
22
22
|
}
|
|
23
|
-
}
|
|
24
|
-
if (failed) {
|
|
23
|
+
}
|
|
24
|
+
if (failed && !options?.ignoreFailures) {
|
|
25
25
|
throw INSTANTIATION_FAILED;
|
|
26
26
|
}
|
|
27
27
|
return results;
|
|
@@ -55,7 +55,7 @@ function resolveInputDataContainer(extensionData, attachment, inputName, collect
|
|
|
55
55
|
if (value === void 0 && !ref.config.optional) {
|
|
56
56
|
const expected = extensionData.filter((r) => !r.config.optional).map((r) => `'${r.id}'`).join(", ");
|
|
57
57
|
const provided = [...attachment.instance?.getDataRefs() ?? []].map((r) => `'${r.id}'`).join(", ");
|
|
58
|
-
collector.report({
|
|
58
|
+
collector.child({ node: attachment }).report({
|
|
59
59
|
code: "EXTENSION_INPUT_DATA_MISSING",
|
|
60
60
|
message: `extension '${attachment.spec.id}' could not be attached because its output data (${provided}) does not match what the input '${inputName}' requires (${expected})`
|
|
61
61
|
});
|
|
@@ -139,10 +139,26 @@ function resolveV1Inputs(inputMap, attachments) {
|
|
|
139
139
|
})
|
|
140
140
|
);
|
|
141
141
|
}
|
|
142
|
-
function resolveV2Inputs(inputMap, attachments, parentCollector) {
|
|
142
|
+
function resolveV2Inputs(inputMap, attachments, parentCollector, node) {
|
|
143
143
|
return mapValues(inputMap, (input, inputName) => {
|
|
144
|
-
const
|
|
144
|
+
const allAttachedNodes = attachments.get(inputName) ?? [];
|
|
145
145
|
const collector = parentCollector.child({ inputName });
|
|
146
|
+
const inputPluginId = node.spec.plugin.pluginId;
|
|
147
|
+
const attachedNodes = input.config.internal ? allAttachedNodes.filter((attachment) => {
|
|
148
|
+
const attachmentPluginId = attachment.spec.plugin.pluginId;
|
|
149
|
+
if (attachmentPluginId !== inputPluginId) {
|
|
150
|
+
collector.report({
|
|
151
|
+
code: "EXTENSION_INPUT_INTERNAL_IGNORED",
|
|
152
|
+
message: `extension '${attachment.spec.id}' from plugin '${attachmentPluginId}' attached to input '${inputName}' on '${node.spec.id}' was ignored, the input is marked as internal and attached extensions must therefore be provided via an override or a module for the '${inputPluginId}' plugin, not the '${attachmentPluginId}' plugin`,
|
|
153
|
+
context: {
|
|
154
|
+
extensionId: attachment.spec.id,
|
|
155
|
+
plugin: attachment.spec.plugin
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
return true;
|
|
161
|
+
}) : allAttachedNodes;
|
|
146
162
|
if (input.config.singleton) {
|
|
147
163
|
if (attachedNodes.length > 1) {
|
|
148
164
|
const attachedNodeIds = attachedNodes.map((e) => e.spec.id).join("', '");
|
|
@@ -161,12 +177,25 @@ function resolveV2Inputs(inputMap, attachments, parentCollector) {
|
|
|
161
177
|
}
|
|
162
178
|
return void 0;
|
|
163
179
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
180
|
+
try {
|
|
181
|
+
return resolveInputDataContainer(
|
|
182
|
+
input.extensionData,
|
|
183
|
+
attachedNodes[0],
|
|
184
|
+
inputName,
|
|
185
|
+
collector
|
|
186
|
+
);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
if (error === INSTANTIATION_FAILED) {
|
|
189
|
+
if (input.config.optional) {
|
|
190
|
+
return void 0;
|
|
191
|
+
}
|
|
192
|
+
collector.report({
|
|
193
|
+
code: "EXTENSION_ATTACHMENT_MISSING",
|
|
194
|
+
message: `input '${inputName}' is required but it failed to be instantiated`
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
170
199
|
}
|
|
171
200
|
return mapWithFailures(
|
|
172
201
|
attachedNodes,
|
|
@@ -175,7 +204,8 @@ function resolveV2Inputs(inputMap, attachments, parentCollector) {
|
|
|
175
204
|
attachment,
|
|
176
205
|
inputName,
|
|
177
206
|
collector
|
|
178
|
-
)
|
|
207
|
+
),
|
|
208
|
+
{ ignoreFailures: true }
|
|
179
209
|
);
|
|
180
210
|
});
|
|
181
211
|
}
|
|
@@ -228,7 +258,8 @@ function createAppNodeInstance(options) {
|
|
|
228
258
|
inputs: resolveV2Inputs(
|
|
229
259
|
internalExtension.inputs,
|
|
230
260
|
attachments,
|
|
231
|
-
collector
|
|
261
|
+
collector,
|
|
262
|
+
node
|
|
232
263
|
)
|
|
233
264
|
};
|
|
234
265
|
const outputDataValues = options.extensionFactoryMiddleware ? createExtensionDataContainer(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instantiateAppNodeTree.esm.js","sources":["../../src/tree/instantiateAppNodeTree.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {\n ApiHolder,\n ExtensionDataContainer,\n ExtensionDataRef,\n ExtensionFactoryMiddleware,\n ExtensionInput,\n ResolvedExtensionInputs,\n} from '@backstage/frontend-plugin-api';\nimport mapValues from 'lodash/mapValues';\nimport { AppNode, AppNodeInstance } from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { createExtensionDataContainer } from '@internal/frontend';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\nconst INSTANTIATION_FAILED = new Error('Instantiation failed');\n\n/**\n * Like `array.map`, but if `INSTANTIATION_FAILED` is thrown, the iteration will continue but afterwards re-throw `INSTANTIATION_FAILED`\n * @returns\n */\nfunction mapWithFailures<T, U>(\n iterable: Iterable<T>,\n callback: (item: T) => U,\n): U[] {\n let failed = false;\n const results = Array.from(iterable).map(item => {\n try {\n return callback(item);\n } catch (error) {\n if (error === INSTANTIATION_FAILED) {\n failed = true;\n } else {\n throw error;\n }\n return null as any;\n }\n });\n if (failed) {\n throw INSTANTIATION_FAILED;\n }\n return results;\n}\n\ntype Mutable<T> = {\n -readonly [P in keyof T]: T[P];\n};\n\nfunction resolveV1InputDataMap(\n dataMap: {\n [name in string]: ExtensionDataRef;\n },\n attachment: AppNode,\n inputName: string,\n) {\n return Object.fromEntries(\n mapWithFailures(Object.entries(dataMap), ([key, ref]) => {\n const value = attachment.instance?.getData(ref);\n if (value === undefined && !ref.config.optional) {\n const expected = Object.values(dataMap)\n .filter(r => !r.config.optional)\n .map(r => `'${r.id}'`)\n .join(', ');\n\n const provided = [...(attachment.instance?.getDataRefs() ?? [])]\n .map(r => `'${r.id}'`)\n .join(', ');\n\n throw new Error(\n `extension '${attachment.spec.id}' could not be attached because its output data (${provided}) does not match what the input '${inputName}' requires (${expected})`,\n );\n }\n return [key, value];\n }),\n );\n}\n\nfunction resolveInputDataContainer(\n extensionData: Array<ExtensionDataRef>,\n attachment: AppNode,\n inputName: string,\n collector: ErrorCollector<{ node: AppNode; inputName: string }>,\n): { node: AppNode } & ExtensionDataContainer<ExtensionDataRef> {\n const dataMap = new Map<string, unknown>();\n\n mapWithFailures(extensionData, ref => {\n if (dataMap.has(ref.id)) {\n collector.report({\n code: 'EXTENSION_INPUT_DATA_IGNORED',\n message: `Unexpected duplicate input data '${ref.id}'`,\n });\n return;\n }\n\n const value = attachment.instance?.getData(ref);\n if (value === undefined && !ref.config.optional) {\n const expected = extensionData\n .filter(r => !r.config.optional)\n .map(r => `'${r.id}'`)\n .join(', ');\n\n const provided = [...(attachment.instance?.getDataRefs() ?? [])]\n .map(r => `'${r.id}'`)\n .join(', ');\n\n collector.report({\n code: 'EXTENSION_INPUT_DATA_MISSING',\n message: `extension '${attachment.spec.id}' could not be attached because its output data (${provided}) does not match what the input '${inputName}' requires (${expected})`,\n });\n throw INSTANTIATION_FAILED;\n }\n\n dataMap.set(ref.id, value);\n });\n\n return {\n node: attachment,\n get(ref) {\n return dataMap.get(ref.id);\n },\n *[Symbol.iterator]() {\n for (const [id, value] of dataMap) {\n // TODO: Would be better to be able to create a new instance using the ref here instead\n yield {\n $$type: '@backstage/ExtensionDataValue',\n id,\n value,\n };\n }\n },\n } as { node: AppNode } & ExtensionDataContainer<ExtensionDataRef>;\n}\n\nfunction reportUndeclaredAttachments(\n id: string,\n inputMap: { [name in string]: unknown },\n attachments: ReadonlyMap<string, AppNode[]>,\n) {\n const undeclaredAttachments = Array.from(attachments.entries()).filter(\n ([inputName]) => inputMap[inputName] === undefined,\n );\n\n const inputNames = Object.keys(inputMap);\n\n for (const [name, nodes] of undeclaredAttachments) {\n const pl = nodes.length > 1;\n // eslint-disable-next-line no-console\n console.warn(\n [\n `The extension${pl ? 's' : ''} '${nodes\n .map(n => n.spec.id)\n .join(\"', '\")}' ${pl ? 'are' : 'is'}`,\n `attached to the input '${name}' of the extension '${id}', but it`,\n inputNames.length === 0\n ? 'has no inputs'\n : `has no such input (candidates are '${inputNames.join(\"', '\")}')`,\n ].join(' '),\n );\n }\n}\n\nfunction resolveV1Inputs(\n inputMap: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n },\n attachments: ReadonlyMap<string, AppNode[]>,\n) {\n return Object.fromEntries(\n mapWithFailures(Object.entries(inputMap), ([inputName, input]) => {\n const attachedNodes = attachments.get(inputName) ?? [];\n\n if (input.config.singleton) {\n if (attachedNodes.length > 1) {\n const attachedNodeIds = attachedNodes.map(e => e.spec.id);\n throw Error(\n `expected ${\n input.config.optional ? 'at most' : 'exactly'\n } one '${inputName}' input but received multiple: '${attachedNodeIds.join(\n \"', '\",\n )}'`,\n );\n } else if (attachedNodes.length === 0) {\n if (input.config.optional) {\n return [inputName, undefined];\n }\n throw Error(`input '${inputName}' is required but was not received`);\n }\n return [\n inputName,\n {\n node: attachedNodes[0],\n output: resolveV1InputDataMap(\n input.extensionData,\n attachedNodes[0],\n inputName,\n ),\n },\n ];\n }\n\n return [\n inputName,\n attachedNodes.map(attachment => ({\n node: attachment,\n output: resolveV1InputDataMap(\n input.extensionData,\n attachment,\n inputName,\n ),\n })),\n ];\n }),\n ) as {\n [inputName in string]: {\n node: AppNode;\n output: {\n [name in string]: unknown;\n };\n };\n };\n}\n\nfunction resolveV2Inputs(\n inputMap: { [inputName in string]: ExtensionInput },\n attachments: ReadonlyMap<string, AppNode[]>,\n parentCollector: ErrorCollector<{ node: AppNode }>,\n): ResolvedExtensionInputs<{ [inputName in string]: ExtensionInput }> {\n return mapValues(inputMap, (input, inputName) => {\n const attachedNodes = attachments.get(inputName) ?? [];\n const collector = parentCollector.child({ inputName });\n\n if (input.config.singleton) {\n if (attachedNodes.length > 1) {\n const attachedNodeIds = attachedNodes.map(e => e.spec.id).join(\"', '\");\n collector.report({\n code: 'EXTENSION_ATTACHMENT_CONFLICT',\n message: `expected ${\n input.config.optional ? 'at most' : 'exactly'\n } one '${inputName}' input but received multiple: '${attachedNodeIds}'`,\n });\n throw INSTANTIATION_FAILED;\n } else if (attachedNodes.length === 0) {\n if (!input.config.optional) {\n collector.report({\n code: 'EXTENSION_ATTACHMENT_MISSING',\n message: `input '${inputName}' is required but was not received`,\n });\n throw INSTANTIATION_FAILED;\n }\n return undefined;\n }\n return resolveInputDataContainer(\n input.extensionData,\n attachedNodes[0],\n inputName,\n collector,\n );\n }\n\n return mapWithFailures(attachedNodes, attachment =>\n resolveInputDataContainer(\n input.extensionData,\n attachment,\n inputName,\n collector,\n ),\n );\n }) as ResolvedExtensionInputs<{ [inputName in string]: ExtensionInput }>;\n}\n\n/** @internal */\nexport function createAppNodeInstance(options: {\n extensionFactoryMiddleware?: ExtensionFactoryMiddleware;\n node: AppNode;\n apis: ApiHolder;\n attachments: ReadonlyMap<string, AppNode[]>;\n collector: ErrorCollector;\n}): AppNodeInstance | undefined {\n const { node, apis, attachments } = options;\n const collector = options.collector.child({ node });\n const { id, extension, config } = node.spec;\n const extensionData = new Map<string, unknown>();\n const extensionDataRefs = new Set<ExtensionDataRef<unknown>>();\n\n let parsedConfig: { [x: string]: any };\n try {\n parsedConfig = extension.configSchema?.parse(config ?? {}) as {\n [x: string]: any;\n };\n } catch (e) {\n collector.report({\n code: 'EXTENSION_CONFIGURATION_INVALID',\n message: `Invalid configuration for extension '${id}'; caused by ${e}`,\n });\n return undefined;\n }\n\n try {\n const internalExtension = toInternalExtension(extension);\n\n if (process.env.NODE_ENV !== 'production') {\n reportUndeclaredAttachments(id, internalExtension.inputs, attachments);\n }\n\n if (internalExtension.version === 'v1') {\n const namedOutputs = internalExtension.factory({\n node,\n apis,\n config: parsedConfig,\n inputs: resolveV1Inputs(internalExtension.inputs, attachments),\n });\n\n for (const [name, output] of Object.entries(namedOutputs)) {\n const ref = internalExtension.output[name];\n if (!ref) {\n throw new Error(`unknown output provided via '${name}'`);\n }\n if (extensionData.has(ref.id)) {\n throw new Error(\n `duplicate extension data '${ref.id}' received via output '${name}'`,\n );\n }\n extensionData.set(ref.id, output);\n extensionDataRefs.add(ref);\n }\n } else if (internalExtension.version === 'v2') {\n const context = {\n node,\n apis,\n config: parsedConfig,\n inputs: resolveV2Inputs(\n internalExtension.inputs,\n attachments,\n collector,\n ),\n };\n const outputDataValues = options.extensionFactoryMiddleware\n ? createExtensionDataContainer(\n options.extensionFactoryMiddleware(overrideContext => {\n return createExtensionDataContainer(\n internalExtension.factory({\n node: context.node,\n apis: context.apis,\n inputs: context.inputs,\n config: overrideContext?.config ?? context.config,\n }),\n 'extension factory',\n );\n }, context),\n 'extension factory middleware',\n )\n : internalExtension.factory(context);\n\n if (\n typeof outputDataValues !== 'object' ||\n !outputDataValues?.[Symbol.iterator]\n ) {\n throw new Error('extension factory did not provide an iterable object');\n }\n\n const outputDataMap = new Map<string, unknown>();\n mapWithFailures(outputDataValues, value => {\n if (outputDataMap.has(value.id)) {\n collector.report({\n code: 'EXTENSION_OUTPUT_CONFLICT',\n message: `extension factory output duplicate data '${value.id}'`,\n context: {\n dataRefId: value.id,\n },\n });\n throw INSTANTIATION_FAILED;\n } else {\n outputDataMap.set(value.id, value.value);\n }\n });\n\n for (const ref of internalExtension.output) {\n const value = outputDataMap.get(ref.id);\n outputDataMap.delete(ref.id);\n if (value === undefined) {\n if (!ref.config.optional) {\n collector.report({\n code: 'EXTENSION_OUTPUT_MISSING',\n message: `missing required extension data output '${ref.id}'`,\n context: {\n dataRefId: ref.id,\n },\n });\n throw INSTANTIATION_FAILED;\n }\n } else {\n extensionData.set(ref.id, value);\n extensionDataRefs.add(ref);\n }\n }\n\n if (outputDataMap.size > 0) {\n for (const dataRefId of outputDataMap.keys()) {\n // TODO: Make this a warning\n collector.report({\n code: 'EXTENSION_OUTPUT_IGNORED',\n message: `unexpected output '${dataRefId}'`,\n context: {\n dataRefId: dataRefId,\n },\n });\n }\n }\n } else {\n collector.report({\n code: 'EXTENSION_INVALID',\n message: `unexpected extension version '${\n (internalExtension as any).version\n }'`,\n });\n throw INSTANTIATION_FAILED;\n }\n } catch (e) {\n if (e !== INSTANTIATION_FAILED) {\n collector.report({\n code: 'EXTENSION_FACTORY_ERROR',\n message: `Failed to instantiate extension '${id}'${\n e.name === 'Error' ? `, ${e.message}` : `; caused by ${e}`\n }`,\n });\n }\n return undefined;\n }\n\n return {\n getDataRefs() {\n return extensionDataRefs.values();\n },\n getData<T>(ref: ExtensionDataRef<T>): T | undefined {\n return extensionData.get(ref.id) as T | undefined;\n },\n };\n}\n\n/**\n * Starting at the provided node, instantiate all reachable nodes in the tree that have not been disabled.\n * @internal\n */\nexport function instantiateAppNodeTree(\n rootNode: AppNode,\n apis: ApiHolder,\n collector: ErrorCollector,\n extensionFactoryMiddleware?: ExtensionFactoryMiddleware,\n): boolean {\n function createInstance(node: AppNode): AppNodeInstance | undefined {\n if (node.instance) {\n return node.instance;\n }\n if (node.spec.disabled) {\n return undefined;\n }\n\n const instantiatedAttachments = new Map<string, AppNode[]>();\n\n for (const [input, children] of node.edges.attachments) {\n const instantiatedChildren = children.flatMap(child => {\n const childInstance = createInstance(child);\n if (!childInstance) {\n return [];\n }\n return [child];\n });\n if (instantiatedChildren.length > 0) {\n instantiatedAttachments.set(input, instantiatedChildren);\n }\n }\n\n (node as Mutable<AppNode>).instance = createAppNodeInstance({\n extensionFactoryMiddleware,\n node,\n apis,\n attachments: instantiatedAttachments,\n collector,\n });\n\n return node.instance;\n }\n\n return createInstance(rootNode) !== undefined;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"instantiateAppNodeTree.esm.js","sources":["../../src/tree/instantiateAppNodeTree.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {\n ApiHolder,\n ExtensionDataContainer,\n ExtensionDataRef,\n ExtensionFactoryMiddleware,\n ExtensionInput,\n ResolvedExtensionInputs,\n} from '@backstage/frontend-plugin-api';\nimport mapValues from 'lodash/mapValues';\nimport { AppNode, AppNodeInstance } from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { createExtensionDataContainer } from '@internal/frontend';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\nconst INSTANTIATION_FAILED = new Error('Instantiation failed');\n\n/**\n * Like `array.map`, but if `INSTANTIATION_FAILED` is thrown, the iteration will continue but afterwards re-throw `INSTANTIATION_FAILED`\n * @returns\n */\nfunction mapWithFailures<T, U>(\n iterable: Iterable<T>,\n callback: (item: T) => U,\n options?: { ignoreFailures?: boolean },\n): U[] {\n let failed = false;\n const results = [];\n for (const item of iterable) {\n try {\n results.push(callback(item));\n } catch (error) {\n if (error === INSTANTIATION_FAILED) {\n failed = true;\n } else {\n throw error;\n }\n }\n }\n if (failed && !options?.ignoreFailures) {\n throw INSTANTIATION_FAILED;\n }\n return results;\n}\n\ntype Mutable<T> = {\n -readonly [P in keyof T]: T[P];\n};\n\nfunction resolveV1InputDataMap(\n dataMap: {\n [name in string]: ExtensionDataRef;\n },\n attachment: AppNode,\n inputName: string,\n) {\n return Object.fromEntries(\n mapWithFailures(Object.entries(dataMap), ([key, ref]) => {\n const value = attachment.instance?.getData(ref);\n if (value === undefined && !ref.config.optional) {\n const expected = Object.values(dataMap)\n .filter(r => !r.config.optional)\n .map(r => `'${r.id}'`)\n .join(', ');\n\n const provided = [...(attachment.instance?.getDataRefs() ?? [])]\n .map(r => `'${r.id}'`)\n .join(', ');\n\n throw new Error(\n `extension '${attachment.spec.id}' could not be attached because its output data (${provided}) does not match what the input '${inputName}' requires (${expected})`,\n );\n }\n return [key, value];\n }),\n );\n}\n\nfunction resolveInputDataContainer(\n extensionData: Array<ExtensionDataRef>,\n attachment: AppNode,\n inputName: string,\n collector: ErrorCollector<{ node: AppNode; inputName: string }>,\n): { node: AppNode } & ExtensionDataContainer<ExtensionDataRef> {\n const dataMap = new Map<string, unknown>();\n\n mapWithFailures(extensionData, ref => {\n if (dataMap.has(ref.id)) {\n collector.report({\n code: 'EXTENSION_INPUT_DATA_IGNORED',\n message: `Unexpected duplicate input data '${ref.id}'`,\n });\n return;\n }\n\n const value = attachment.instance?.getData(ref);\n if (value === undefined && !ref.config.optional) {\n const expected = extensionData\n .filter(r => !r.config.optional)\n .map(r => `'${r.id}'`)\n .join(', ');\n\n const provided = [...(attachment.instance?.getDataRefs() ?? [])]\n .map(r => `'${r.id}'`)\n .join(', ');\n\n collector.child({ node: attachment }).report({\n code: 'EXTENSION_INPUT_DATA_MISSING',\n message: `extension '${attachment.spec.id}' could not be attached because its output data (${provided}) does not match what the input '${inputName}' requires (${expected})`,\n });\n throw INSTANTIATION_FAILED;\n }\n\n dataMap.set(ref.id, value);\n });\n\n return {\n node: attachment,\n get(ref) {\n return dataMap.get(ref.id);\n },\n *[Symbol.iterator]() {\n for (const [id, value] of dataMap) {\n // TODO: Would be better to be able to create a new instance using the ref here instead\n yield {\n $$type: '@backstage/ExtensionDataValue',\n id,\n value,\n };\n }\n },\n } as { node: AppNode } & ExtensionDataContainer<ExtensionDataRef>;\n}\n\nfunction reportUndeclaredAttachments(\n id: string,\n inputMap: { [name in string]: unknown },\n attachments: ReadonlyMap<string, AppNode[]>,\n) {\n const undeclaredAttachments = Array.from(attachments.entries()).filter(\n ([inputName]) => inputMap[inputName] === undefined,\n );\n\n const inputNames = Object.keys(inputMap);\n\n for (const [name, nodes] of undeclaredAttachments) {\n const pl = nodes.length > 1;\n // eslint-disable-next-line no-console\n console.warn(\n [\n `The extension${pl ? 's' : ''} '${nodes\n .map(n => n.spec.id)\n .join(\"', '\")}' ${pl ? 'are' : 'is'}`,\n `attached to the input '${name}' of the extension '${id}', but it`,\n inputNames.length === 0\n ? 'has no inputs'\n : `has no such input (candidates are '${inputNames.join(\"', '\")}')`,\n ].join(' '),\n );\n }\n}\n\nfunction resolveV1Inputs(\n inputMap: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n },\n attachments: ReadonlyMap<string, AppNode[]>,\n) {\n return Object.fromEntries(\n mapWithFailures(Object.entries(inputMap), ([inputName, input]) => {\n const attachedNodes = attachments.get(inputName) ?? [];\n\n if (input.config.singleton) {\n if (attachedNodes.length > 1) {\n const attachedNodeIds = attachedNodes.map(e => e.spec.id);\n throw Error(\n `expected ${\n input.config.optional ? 'at most' : 'exactly'\n } one '${inputName}' input but received multiple: '${attachedNodeIds.join(\n \"', '\",\n )}'`,\n );\n } else if (attachedNodes.length === 0) {\n if (input.config.optional) {\n return [inputName, undefined];\n }\n throw Error(`input '${inputName}' is required but was not received`);\n }\n return [\n inputName,\n {\n node: attachedNodes[0],\n output: resolveV1InputDataMap(\n input.extensionData,\n attachedNodes[0],\n inputName,\n ),\n },\n ];\n }\n\n return [\n inputName,\n attachedNodes.map(attachment => ({\n node: attachment,\n output: resolveV1InputDataMap(\n input.extensionData,\n attachment,\n inputName,\n ),\n })),\n ];\n }),\n ) as {\n [inputName in string]: {\n node: AppNode;\n output: {\n [name in string]: unknown;\n };\n };\n };\n}\n\nfunction resolveV2Inputs(\n inputMap: { [inputName in string]: ExtensionInput },\n attachments: ReadonlyMap<string, AppNode[]>,\n parentCollector: ErrorCollector<{ node: AppNode }>,\n node: AppNode,\n): ResolvedExtensionInputs<{ [inputName in string]: ExtensionInput }> {\n return mapValues(inputMap, (input, inputName) => {\n const allAttachedNodes = attachments.get(inputName) ?? [];\n const collector = parentCollector.child({ inputName });\n const inputPluginId = node.spec.plugin.pluginId;\n\n const attachedNodes = input.config.internal\n ? allAttachedNodes.filter(attachment => {\n const attachmentPluginId = attachment.spec.plugin.pluginId;\n if (attachmentPluginId !== inputPluginId) {\n collector.report({\n code: 'EXTENSION_INPUT_INTERNAL_IGNORED',\n message:\n `extension '${attachment.spec.id}' from plugin '${attachmentPluginId}' attached to input '${inputName}' on '${node.spec.id}' was ignored, ` +\n `the input is marked as internal and attached extensions must therefore be provided via an override or a module for the '${inputPluginId}' plugin, not the '${attachmentPluginId}' plugin`,\n context: {\n extensionId: attachment.spec.id,\n plugin: attachment.spec.plugin,\n },\n });\n return false;\n }\n return true;\n })\n : allAttachedNodes;\n\n if (input.config.singleton) {\n if (attachedNodes.length > 1) {\n const attachedNodeIds = attachedNodes.map(e => e.spec.id).join(\"', '\");\n collector.report({\n code: 'EXTENSION_ATTACHMENT_CONFLICT',\n message: `expected ${\n input.config.optional ? 'at most' : 'exactly'\n } one '${inputName}' input but received multiple: '${attachedNodeIds}'`,\n });\n throw INSTANTIATION_FAILED;\n } else if (attachedNodes.length === 0) {\n if (!input.config.optional) {\n collector.report({\n code: 'EXTENSION_ATTACHMENT_MISSING',\n message: `input '${inputName}' is required but was not received`,\n });\n throw INSTANTIATION_FAILED;\n }\n return undefined;\n }\n try {\n return resolveInputDataContainer(\n input.extensionData,\n attachedNodes[0],\n inputName,\n collector,\n );\n } catch (error) {\n if (error === INSTANTIATION_FAILED) {\n if (input.config.optional) {\n return undefined;\n }\n collector.report({\n code: 'EXTENSION_ATTACHMENT_MISSING',\n message: `input '${inputName}' is required but it failed to be instantiated`,\n });\n }\n throw error;\n }\n }\n\n return mapWithFailures(\n attachedNodes,\n attachment =>\n resolveInputDataContainer(\n input.extensionData,\n attachment,\n inputName,\n collector,\n ),\n { ignoreFailures: true },\n );\n }) as ResolvedExtensionInputs<{ [inputName in string]: ExtensionInput }>;\n}\n\n/** @internal */\nexport function createAppNodeInstance(options: {\n extensionFactoryMiddleware?: ExtensionFactoryMiddleware;\n node: AppNode;\n apis: ApiHolder;\n attachments: ReadonlyMap<string, AppNode[]>;\n collector: ErrorCollector;\n}): AppNodeInstance | undefined {\n const { node, apis, attachments } = options;\n const collector = options.collector.child({ node });\n const { id, extension, config } = node.spec;\n const extensionData = new Map<string, unknown>();\n const extensionDataRefs = new Set<ExtensionDataRef<unknown>>();\n\n let parsedConfig: { [x: string]: any };\n try {\n parsedConfig = extension.configSchema?.parse(config ?? {}) as {\n [x: string]: any;\n };\n } catch (e) {\n collector.report({\n code: 'EXTENSION_CONFIGURATION_INVALID',\n message: `Invalid configuration for extension '${id}'; caused by ${e}`,\n });\n return undefined;\n }\n\n try {\n const internalExtension = toInternalExtension(extension);\n\n if (process.env.NODE_ENV !== 'production') {\n reportUndeclaredAttachments(id, internalExtension.inputs, attachments);\n }\n\n if (internalExtension.version === 'v1') {\n const namedOutputs = internalExtension.factory({\n node,\n apis,\n config: parsedConfig,\n inputs: resolveV1Inputs(internalExtension.inputs, attachments),\n });\n\n for (const [name, output] of Object.entries(namedOutputs)) {\n const ref = internalExtension.output[name];\n if (!ref) {\n throw new Error(`unknown output provided via '${name}'`);\n }\n if (extensionData.has(ref.id)) {\n throw new Error(\n `duplicate extension data '${ref.id}' received via output '${name}'`,\n );\n }\n extensionData.set(ref.id, output);\n extensionDataRefs.add(ref);\n }\n } else if (internalExtension.version === 'v2') {\n const context = {\n node,\n apis,\n config: parsedConfig,\n inputs: resolveV2Inputs(\n internalExtension.inputs,\n attachments,\n collector,\n node,\n ),\n };\n const outputDataValues = options.extensionFactoryMiddleware\n ? createExtensionDataContainer(\n options.extensionFactoryMiddleware(overrideContext => {\n return createExtensionDataContainer(\n internalExtension.factory({\n node: context.node,\n apis: context.apis,\n inputs: context.inputs,\n config: overrideContext?.config ?? context.config,\n }),\n 'extension factory',\n );\n }, context),\n 'extension factory middleware',\n )\n : internalExtension.factory(context);\n\n if (\n typeof outputDataValues !== 'object' ||\n !outputDataValues?.[Symbol.iterator]\n ) {\n throw new Error('extension factory did not provide an iterable object');\n }\n\n const outputDataMap = new Map<string, unknown>();\n mapWithFailures(outputDataValues, value => {\n if (outputDataMap.has(value.id)) {\n collector.report({\n code: 'EXTENSION_OUTPUT_CONFLICT',\n message: `extension factory output duplicate data '${value.id}'`,\n context: {\n dataRefId: value.id,\n },\n });\n throw INSTANTIATION_FAILED;\n } else {\n outputDataMap.set(value.id, value.value);\n }\n });\n\n for (const ref of internalExtension.output) {\n const value = outputDataMap.get(ref.id);\n outputDataMap.delete(ref.id);\n if (value === undefined) {\n if (!ref.config.optional) {\n collector.report({\n code: 'EXTENSION_OUTPUT_MISSING',\n message: `missing required extension data output '${ref.id}'`,\n context: {\n dataRefId: ref.id,\n },\n });\n throw INSTANTIATION_FAILED;\n }\n } else {\n extensionData.set(ref.id, value);\n extensionDataRefs.add(ref);\n }\n }\n\n if (outputDataMap.size > 0) {\n for (const dataRefId of outputDataMap.keys()) {\n // TODO: Make this a warning\n collector.report({\n code: 'EXTENSION_OUTPUT_IGNORED',\n message: `unexpected output '${dataRefId}'`,\n context: {\n dataRefId: dataRefId,\n },\n });\n }\n }\n } else {\n collector.report({\n code: 'EXTENSION_INVALID',\n message: `unexpected extension version '${\n (internalExtension as any).version\n }'`,\n });\n throw INSTANTIATION_FAILED;\n }\n } catch (e) {\n if (e !== INSTANTIATION_FAILED) {\n collector.report({\n code: 'EXTENSION_FACTORY_ERROR',\n message: `Failed to instantiate extension '${id}'${\n e.name === 'Error' ? `, ${e.message}` : `; caused by ${e}`\n }`,\n });\n }\n return undefined;\n }\n\n return {\n getDataRefs() {\n return extensionDataRefs.values();\n },\n getData<T>(ref: ExtensionDataRef<T>): T | undefined {\n return extensionData.get(ref.id) as T | undefined;\n },\n };\n}\n\n/**\n * Starting at the provided node, instantiate all reachable nodes in the tree that have not been disabled.\n * @internal\n */\nexport function instantiateAppNodeTree(\n rootNode: AppNode,\n apis: ApiHolder,\n collector: ErrorCollector,\n extensionFactoryMiddleware?: ExtensionFactoryMiddleware,\n): boolean {\n function createInstance(node: AppNode): AppNodeInstance | undefined {\n if (node.instance) {\n return node.instance;\n }\n if (node.spec.disabled) {\n return undefined;\n }\n\n const instantiatedAttachments = new Map<string, AppNode[]>();\n\n for (const [input, children] of node.edges.attachments) {\n const instantiatedChildren = children.flatMap(child => {\n const childInstance = createInstance(child);\n if (!childInstance) {\n return [];\n }\n return [child];\n });\n if (instantiatedChildren.length > 0) {\n instantiatedAttachments.set(input, instantiatedChildren);\n }\n }\n\n (node as Mutable<AppNode>).instance = createAppNodeInstance({\n extensionFactoryMiddleware,\n node,\n apis,\n attachments: instantiatedAttachments,\n collector,\n });\n\n return node.instance;\n }\n\n return createInstance(rootNode) !== undefined;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,12 @@ import { isInternalFrontendModule, toInternalFrontendModule } from '../frontend-
|
|
|
3
3
|
import { toInternalExtension } from '../frontend-plugin-api/src/wiring/resolveExtensionDefinition.esm.js';
|
|
4
4
|
import { OpaqueFrontendPlugin } from '../frontend-internal/src/wiring/InternalFrontendPlugin.esm.js';
|
|
5
5
|
|
|
6
|
+
function normalizePlugin(plugin) {
|
|
7
|
+
if (!plugin.pluginId && "id" in plugin && typeof plugin.id === "string") {
|
|
8
|
+
plugin.pluginId = plugin.id;
|
|
9
|
+
}
|
|
10
|
+
return plugin;
|
|
11
|
+
}
|
|
6
12
|
function resolveAppNodeSpecs(options) {
|
|
7
13
|
const {
|
|
8
14
|
builtinExtensions = [],
|
|
@@ -11,13 +17,13 @@ function resolveAppNodeSpecs(options) {
|
|
|
11
17
|
features = [],
|
|
12
18
|
collector
|
|
13
19
|
} = options;
|
|
14
|
-
const plugins = features.filter(OpaqueFrontendPlugin.isType);
|
|
20
|
+
const plugins = features.filter(OpaqueFrontendPlugin.isType).map(normalizePlugin);
|
|
15
21
|
const modules = features.filter(isInternalFrontendModule);
|
|
16
22
|
const filterForbidden = (extension) => {
|
|
17
23
|
if (forbidden.has(extension.id)) {
|
|
18
24
|
collector.report({
|
|
19
25
|
code: "EXTENSION_IGNORED",
|
|
20
|
-
message: `It is forbidden to override the '${extension.id}' extension, attempted by the '${extension.plugin.
|
|
26
|
+
message: `It is forbidden to override the '${extension.id}' extension, attempted by the '${extension.plugin.pluginId}' plugin`,
|
|
21
27
|
context: {
|
|
22
28
|
plugin: extension.plugin,
|
|
23
29
|
extensionId: extension.id
|
|
@@ -35,14 +41,14 @@ function resolveAppNodeSpecs(options) {
|
|
|
35
41
|
});
|
|
36
42
|
const moduleExtensions = modules.flatMap(
|
|
37
43
|
(mod) => toInternalFrontendModule(mod).extensions.flatMap((extension) => {
|
|
38
|
-
const plugin = plugins.find((p) => p.
|
|
44
|
+
const plugin = plugins.find((p) => p.pluginId === mod.pluginId);
|
|
39
45
|
if (!plugin) {
|
|
40
46
|
return [];
|
|
41
47
|
}
|
|
42
48
|
return [{ ...extension, plugin }];
|
|
43
49
|
}).filter(filterForbidden)
|
|
44
50
|
);
|
|
45
|
-
const appPlugin = plugins.find((plugin) => plugin.
|
|
51
|
+
const appPlugin = plugins.find((plugin) => plugin.pluginId === "app") ?? createFrontendPlugin({
|
|
46
52
|
pluginId: "app"
|
|
47
53
|
});
|
|
48
54
|
const configuredExtensions = [
|
|
@@ -101,7 +107,7 @@ function resolveAppNodeSpecs(options) {
|
|
|
101
107
|
if (seenExtensionIds.has(extension.id)) {
|
|
102
108
|
collector.report({
|
|
103
109
|
code: "EXTENSION_IGNORED",
|
|
104
|
-
message: `The '${extension.id}' extension from the '${params.plugin.
|
|
110
|
+
message: `The '${extension.id}' extension from the '${params.plugin.pluginId}' plugin is a duplicate and will be ignored`,
|
|
105
111
|
context: {
|
|
106
112
|
plugin: params.plugin,
|
|
107
113
|
extensionId: extension.id
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveAppNodeSpecs.esm.js","sources":["../../src/tree/resolveAppNodeSpecs.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {\n createFrontendPlugin,\n Extension,\n FrontendFeature,\n FrontendPlugin,\n} from '@backstage/frontend-plugin-api';\nimport { ExtensionParameters } from './readAppExtensionsConfig';\nimport { AppNodeSpec } from '@backstage/frontend-plugin-api';\nimport { OpaqueFrontendPlugin } from '@internal/frontend';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport {\n isInternalFrontendModule,\n toInternalFrontendModule,\n} from '../../../frontend-plugin-api/src/wiring/createFrontendModule';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\n/** @internal */\nexport function resolveAppNodeSpecs(options: {\n features?: FrontendFeature[];\n builtinExtensions?: Extension<any, any>[];\n parameters?: Array<ExtensionParameters>;\n forbidden?: Set<string>;\n collector: ErrorCollector;\n}): AppNodeSpec[] {\n const {\n builtinExtensions = [],\n parameters = [],\n forbidden = new Set(),\n features = [],\n collector,\n } = options;\n\n const plugins = features.filter(OpaqueFrontendPlugin.isType);\n const modules = features.filter(isInternalFrontendModule);\n\n const filterForbidden = (\n extension: Extension<any, any> & { plugin: FrontendPlugin },\n ) => {\n if (forbidden.has(extension.id)) {\n collector.report({\n code: 'EXTENSION_IGNORED',\n message: `It is forbidden to override the '${extension.id}' extension, attempted by the '${extension.plugin.id}' plugin`,\n context: {\n plugin: extension.plugin,\n extensionId: extension.id,\n },\n });\n return false;\n }\n return true;\n };\n\n const pluginExtensions = plugins.flatMap(plugin => {\n return OpaqueFrontendPlugin.toInternal(plugin)\n .extensions.map(extension => ({\n ...extension,\n plugin,\n }))\n .filter(filterForbidden);\n });\n const moduleExtensions = modules.flatMap(mod =>\n toInternalFrontendModule(mod)\n .extensions.flatMap(extension => {\n // Modules for plugins that are not installed are ignored\n const plugin = plugins.find(p => p.id === mod.pluginId);\n if (!plugin) {\n return [];\n }\n\n return [{ ...extension, plugin }];\n })\n .filter(filterForbidden),\n );\n\n const appPlugin =\n plugins.find(plugin => plugin.id === 'app') ??\n createFrontendPlugin({\n pluginId: 'app',\n });\n\n const configuredExtensions = [\n ...pluginExtensions.map(({ plugin, ...extension }) => {\n const internalExtension = toInternalExtension(extension);\n return {\n extension: internalExtension,\n params: {\n plugin,\n source: plugin,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n config: undefined as unknown,\n },\n };\n }),\n ...builtinExtensions.map(extension => {\n const internalExtension = toInternalExtension(extension);\n return {\n extension: internalExtension,\n params: {\n source: appPlugin,\n plugin: appPlugin,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n config: undefined as unknown,\n },\n };\n }),\n ];\n\n // Install all module overrides\n for (const extension of moduleExtensions) {\n const internalExtension = toInternalExtension(extension);\n\n // Check if our override is overriding an extension that already exists\n const index = configuredExtensions.findIndex(\n e => e.extension.id === extension.id,\n );\n if (index !== -1) {\n // Only implementation, attachment point and default disabled status are overridden, the source is kept\n configuredExtensions[index].extension = internalExtension;\n configuredExtensions[index].params.attachTo = internalExtension.attachTo;\n configuredExtensions[index].params.disabled = internalExtension.disabled;\n } else {\n // Add the extension as a new one when not overriding an existing one\n configuredExtensions.push({\n extension: internalExtension,\n params: {\n plugin: extension.plugin,\n source: extension.plugin,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n config: undefined,\n },\n });\n }\n }\n\n const seenExtensionIds = new Set<string>();\n const deduplicatedExtensions = configuredExtensions.filter(\n ({ extension, params }) => {\n if (seenExtensionIds.has(extension.id)) {\n collector.report({\n code: 'EXTENSION_IGNORED',\n message: `The '${extension.id}' extension from the '${params.plugin.id}' plugin is a duplicate and will be ignored`,\n context: {\n plugin: params.plugin,\n extensionId: extension.id,\n },\n });\n return false;\n }\n seenExtensionIds.add(extension.id);\n return true;\n },\n );\n\n const order = new Map<string, (typeof deduplicatedExtensions)[number]>();\n for (const overrideParam of parameters) {\n const extensionId = overrideParam.id;\n\n if (forbidden.has(extensionId)) {\n collector.report({\n code: 'INVALID_EXTENSION_CONFIG_KEY',\n message: `Configuration of the '${extensionId}' extension is forbidden`,\n context: {\n extensionId,\n },\n });\n continue;\n }\n\n const existing = deduplicatedExtensions.find(\n e => e.extension.id === extensionId,\n );\n if (existing) {\n if (overrideParam.attachTo) {\n existing.params.attachTo = overrideParam.attachTo;\n }\n if (overrideParam.config) {\n // TODO: merge config?\n existing.params.config = overrideParam.config;\n }\n if (\n Boolean(existing.params.disabled) !== Boolean(overrideParam.disabled)\n ) {\n existing.params.disabled = Boolean(overrideParam.disabled);\n }\n order.set(extensionId, existing);\n } else {\n collector.report({\n code: 'INVALID_EXTENSION_CONFIG_KEY',\n message: `Extension ${extensionId} does not exist`,\n context: {\n extensionId,\n },\n });\n }\n }\n\n const orderedExtensions = [\n ...order.values(),\n ...deduplicatedExtensions.filter(e => !order.has(e.extension.id)),\n ];\n\n return orderedExtensions.map(param => ({\n id: param.extension.id,\n attachTo: param.params.attachTo,\n extension: param.extension,\n disabled: param.params.disabled,\n plugin: param.params.plugin,\n source: param.params.source,\n config: param.params.config,\n }));\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resolveAppNodeSpecs.esm.js","sources":["../../src/tree/resolveAppNodeSpecs.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {\n createFrontendPlugin,\n Extension,\n FrontendFeature,\n FrontendPlugin,\n} from '@backstage/frontend-plugin-api';\nimport { ExtensionParameters } from './readAppExtensionsConfig';\nimport { AppNodeSpec } from '@backstage/frontend-plugin-api';\nimport { OpaqueFrontendPlugin } from '@internal/frontend';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport {\n isInternalFrontendModule,\n toInternalFrontendModule,\n} from '../../../frontend-plugin-api/src/wiring/createFrontendModule';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\nfunction normalizePlugin(plugin: FrontendPlugin): FrontendPlugin {\n // Ensure pluginId is always set for plugins in the app\n if (!plugin.pluginId && 'id' in plugin && typeof plugin.id === 'string') {\n (plugin as any).pluginId = plugin.id;\n }\n return plugin;\n}\n\n/** @internal */\nexport function resolveAppNodeSpecs(options: {\n features?: FrontendFeature[];\n builtinExtensions?: Extension<any, any>[];\n parameters?: Array<ExtensionParameters>;\n forbidden?: Set<string>;\n collector: ErrorCollector;\n}): AppNodeSpec[] {\n const {\n builtinExtensions = [],\n parameters = [],\n forbidden = new Set(),\n features = [],\n collector,\n } = options;\n\n const plugins = features\n .filter(OpaqueFrontendPlugin.isType)\n .map(normalizePlugin);\n const modules = features.filter(isInternalFrontendModule);\n\n const filterForbidden = (\n extension: Extension<any, any> & { plugin: FrontendPlugin },\n ) => {\n if (forbidden.has(extension.id)) {\n collector.report({\n code: 'EXTENSION_IGNORED',\n message: `It is forbidden to override the '${extension.id}' extension, attempted by the '${extension.plugin.pluginId}' plugin`,\n context: {\n plugin: extension.plugin,\n extensionId: extension.id,\n },\n });\n return false;\n }\n return true;\n };\n\n const pluginExtensions = plugins.flatMap(plugin => {\n return OpaqueFrontendPlugin.toInternal(plugin)\n .extensions.map(extension => ({\n ...extension,\n plugin,\n }))\n .filter(filterForbidden);\n });\n const moduleExtensions = modules.flatMap(mod =>\n toInternalFrontendModule(mod)\n .extensions.flatMap(extension => {\n // Modules for plugins that are not installed are ignored\n const plugin = plugins.find(p => p.pluginId === mod.pluginId);\n if (!plugin) {\n return [];\n }\n\n return [{ ...extension, plugin }];\n })\n .filter(filterForbidden),\n );\n\n const appPlugin =\n plugins.find(plugin => plugin.pluginId === 'app') ??\n createFrontendPlugin({\n pluginId: 'app',\n });\n\n const configuredExtensions = [\n ...pluginExtensions.map(({ plugin, ...extension }) => {\n const internalExtension = toInternalExtension(extension);\n return {\n extension: internalExtension,\n params: {\n plugin,\n source: plugin,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n config: undefined as unknown,\n },\n };\n }),\n ...builtinExtensions.map(extension => {\n const internalExtension = toInternalExtension(extension);\n return {\n extension: internalExtension,\n params: {\n source: appPlugin,\n plugin: appPlugin,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n config: undefined as unknown,\n },\n };\n }),\n ];\n\n // Install all module overrides\n for (const extension of moduleExtensions) {\n const internalExtension = toInternalExtension(extension);\n\n // Check if our override is overriding an extension that already exists\n const index = configuredExtensions.findIndex(\n e => e.extension.id === extension.id,\n );\n if (index !== -1) {\n // Only implementation, attachment point and default disabled status are overridden, the source is kept\n configuredExtensions[index].extension = internalExtension;\n configuredExtensions[index].params.attachTo = internalExtension.attachTo;\n configuredExtensions[index].params.disabled = internalExtension.disabled;\n } else {\n // Add the extension as a new one when not overriding an existing one\n configuredExtensions.push({\n extension: internalExtension,\n params: {\n plugin: extension.plugin,\n source: extension.plugin,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n config: undefined,\n },\n });\n }\n }\n\n const seenExtensionIds = new Set<string>();\n const deduplicatedExtensions = configuredExtensions.filter(\n ({ extension, params }) => {\n if (seenExtensionIds.has(extension.id)) {\n collector.report({\n code: 'EXTENSION_IGNORED',\n message: `The '${extension.id}' extension from the '${params.plugin.pluginId}' plugin is a duplicate and will be ignored`,\n context: {\n plugin: params.plugin,\n extensionId: extension.id,\n },\n });\n return false;\n }\n seenExtensionIds.add(extension.id);\n return true;\n },\n );\n\n const order = new Map<string, (typeof deduplicatedExtensions)[number]>();\n for (const overrideParam of parameters) {\n const extensionId = overrideParam.id;\n\n if (forbidden.has(extensionId)) {\n collector.report({\n code: 'INVALID_EXTENSION_CONFIG_KEY',\n message: `Configuration of the '${extensionId}' extension is forbidden`,\n context: {\n extensionId,\n },\n });\n continue;\n }\n\n const existing = deduplicatedExtensions.find(\n e => e.extension.id === extensionId,\n );\n if (existing) {\n if (overrideParam.attachTo) {\n existing.params.attachTo = overrideParam.attachTo;\n }\n if (overrideParam.config) {\n // TODO: merge config?\n existing.params.config = overrideParam.config;\n }\n if (\n Boolean(existing.params.disabled) !== Boolean(overrideParam.disabled)\n ) {\n existing.params.disabled = Boolean(overrideParam.disabled);\n }\n order.set(extensionId, existing);\n } else {\n collector.report({\n code: 'INVALID_EXTENSION_CONFIG_KEY',\n message: `Extension ${extensionId} does not exist`,\n context: {\n extensionId,\n },\n });\n }\n }\n\n const orderedExtensions = [\n ...order.values(),\n ...deduplicatedExtensions.filter(e => !order.has(e.extension.id)),\n ];\n\n return orderedExtensions.map(param => ({\n id: param.extension.id,\n attachTo: param.params.attachTo,\n extension: param.extension,\n disabled: param.params.disabled,\n plugin: param.params.plugin,\n source: param.params.source,\n config: param.params.config,\n }));\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -92,6 +92,9 @@ function resolveAppTree(rootNodeId, specs, errorCollector) {
|
|
|
92
92
|
if (spec.id === rootNodeId) {
|
|
93
93
|
rootNode = node;
|
|
94
94
|
} else if (Array.isArray(spec.attachTo)) {
|
|
95
|
+
console.warn(
|
|
96
|
+
`Extension '${spec.id}' is using multiple attachment points which is deprecated and will be removed in a future release. Use a Utility API instead to share functionality across multiple locations. See https://backstage.io/docs/frontend-system/architecture/27-sharing-extensions for migration guidance.`
|
|
97
|
+
);
|
|
95
98
|
let foundFirstParent = false;
|
|
96
99
|
for (const origAttachTo of spec.attachTo) {
|
|
97
100
|
let attachTo = origAttachTo;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveAppTree.esm.js","sources":["../../src/tree/resolveAppTree.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {\n AppTree,\n AppNode,\n AppNodeInstance,\n AppNodeSpec,\n} from '@backstage/frontend-plugin-api';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\nfunction indent(str: string) {\n return str.replace(/^/gm, ' ');\n}\n\n/** @internal */\nclass SerializableAppNode implements AppNode {\n public readonly spec: AppNodeSpec;\n public readonly edges = {\n attachedTo: undefined as { node: AppNode; input: string } | undefined,\n attachments: new Map<string, SerializableAppNode[]>(),\n };\n public readonly instance?: AppNodeInstance;\n\n constructor(spec: AppNodeSpec) {\n this.spec = spec;\n }\n\n setParent(parent: SerializableAppNode, input: string) {\n this.edges.attachedTo = { node: parent, input };\n\n const parentInputEdges = parent.edges.attachments.get(input);\n if (parentInputEdges) {\n parentInputEdges.push(this);\n } else {\n parent.edges.attachments.set(input, [this]);\n }\n }\n\n toJSON() {\n const dataRefs = this.instance && [...this.instance.getDataRefs()];\n return {\n id: this.spec.id,\n output:\n dataRefs && dataRefs.length > 0\n ? dataRefs.map(ref => ref.id)\n : undefined,\n attachments:\n this.edges.attachments.size > 0\n ? Object.fromEntries(this.edges.attachments)\n : undefined,\n };\n }\n\n toString(): string {\n const dataRefs = this.instance && [...this.instance.getDataRefs()];\n const out =\n dataRefs && dataRefs.length > 0\n ? ` out=[${[...dataRefs].map(r => r.id).join(', ')}]`\n : '';\n\n if (this.edges.attachments.size === 0) {\n return `<${this.spec.id}${out} />`;\n }\n\n return [\n `<${this.spec.id}${out}>`,\n ...[...this.edges.attachments.entries()].map(([k, v]) =>\n indent([`${k} [`, ...v.map(e => indent(e.toString())), `]`].join('\\n')),\n ),\n `</${this.spec.id}>`,\n ].join('\\n');\n }\n}\n\nfunction makeRedirectKey(attachTo: { id: string; input: string }) {\n return `${attachTo.id}%${attachTo.input}`;\n}\n\nconst isValidAttachmentPoint = (\n attachTo: { id: string; input: string },\n nodes: Map<string, SerializableAppNode>,\n) => {\n if (!nodes.has(attachTo.id)) {\n return false;\n }\n\n return (\n attachTo.input in\n toInternalExtension(nodes.get(attachTo.id)!.spec.extension).inputs\n );\n};\n\n/**\n * Build the app tree by iterating through all node specs and constructing the app\n * tree with all attachments in the same order as they appear in the input specs array.\n * @internal\n */\nexport function resolveAppTree(\n rootNodeId: string,\n specs: AppNodeSpec[],\n errorCollector: ErrorCollector,\n): AppTree {\n const nodes = new Map<string, SerializableAppNode>();\n\n const redirectTargetsByKey = new Map<string, { id: string; input: string }>();\n\n for (const spec of specs) {\n // The main check with a helpful error message happens in resolveAppNodeSpecs\n if (nodes.has(spec.id)) {\n continue;\n }\n\n const node = new SerializableAppNode(spec);\n nodes.set(spec.id, node);\n\n const internal = toInternalExtension(spec.extension);\n for (const [inputName, input] of Object.entries(internal.inputs)) {\n if (input.replaces) {\n for (const replace of input.replaces) {\n const key = makeRedirectKey(replace);\n if (redirectTargetsByKey.has(key)) {\n errorCollector.report({\n code: 'EXTENSION_INPUT_REDIRECT_CONFLICT',\n message: `Duplicate redirect target for input '${inputName}' in extension '${spec.id}'`,\n context: {\n node,\n inputName,\n },\n });\n continue;\n }\n redirectTargetsByKey.set(key, { id: spec.id, input: inputName });\n }\n }\n }\n }\n\n const orphans = new Array<SerializableAppNode>();\n const clones = new Map<string, Array<SerializableAppNode>>();\n\n // A node with the provided rootNodeId must be found in the tree, and it must not be attached to anything\n let rootNode: AppNode | undefined = undefined;\n\n for (const node of nodes.values()) {\n const spec = node.spec;\n\n // TODO: For now we simply ignore the attachTo spec of the root node, but it'd be cleaner if we could avoid defining it\n if (spec.id === rootNodeId) {\n rootNode = node;\n } else if (Array.isArray(spec.attachTo)) {\n let foundFirstParent = false;\n for (const origAttachTo of spec.attachTo) {\n let attachTo = origAttachTo;\n\n if (!isValidAttachmentPoint(attachTo, nodes)) {\n attachTo =\n redirectTargetsByKey.get(makeRedirectKey(attachTo)) ?? attachTo;\n }\n\n const parent = nodes.get(attachTo.id);\n if (parent) {\n const cloneParents = clones.get(attachTo.id) ?? [];\n\n if (!foundFirstParent) {\n foundFirstParent = true;\n node.setParent(parent, attachTo.input);\n } else {\n cloneParents.unshift(parent);\n }\n\n for (const extraParent of cloneParents) {\n const clonedNode = new SerializableAppNode(spec);\n clonedNode.setParent(extraParent, attachTo.input);\n clones.set(\n spec.id,\n clones.get(spec.id)?.concat(clonedNode) ?? [clonedNode],\n );\n }\n }\n }\n if (!foundFirstParent) {\n orphans.push(node);\n }\n } else {\n let attachTo = spec.attachTo;\n if (!isValidAttachmentPoint(attachTo, nodes)) {\n attachTo =\n redirectTargetsByKey.get(makeRedirectKey(attachTo)) ?? attachTo;\n }\n\n const parent = nodes.get(attachTo.id);\n if (parent) {\n node.setParent(parent, attachTo.input);\n } else {\n orphans.push(node);\n }\n }\n }\n\n if (!rootNode) {\n throw new Error(`No root node with id '${rootNodeId}' found in app tree`);\n }\n\n return {\n root: rootNode,\n nodes,\n orphans,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resolveAppTree.esm.js","sources":["../../src/tree/resolveAppTree.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {\n AppTree,\n AppNode,\n AppNodeInstance,\n AppNodeSpec,\n} from '@backstage/frontend-plugin-api';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\nfunction indent(str: string) {\n return str.replace(/^/gm, ' ');\n}\n\n/** @internal */\nclass SerializableAppNode implements AppNode {\n public readonly spec: AppNodeSpec;\n public readonly edges = {\n attachedTo: undefined as { node: AppNode; input: string } | undefined,\n attachments: new Map<string, SerializableAppNode[]>(),\n };\n public readonly instance?: AppNodeInstance;\n\n constructor(spec: AppNodeSpec) {\n this.spec = spec;\n }\n\n setParent(parent: SerializableAppNode, input: string) {\n this.edges.attachedTo = { node: parent, input };\n\n const parentInputEdges = parent.edges.attachments.get(input);\n if (parentInputEdges) {\n parentInputEdges.push(this);\n } else {\n parent.edges.attachments.set(input, [this]);\n }\n }\n\n toJSON() {\n const dataRefs = this.instance && [...this.instance.getDataRefs()];\n return {\n id: this.spec.id,\n output:\n dataRefs && dataRefs.length > 0\n ? dataRefs.map(ref => ref.id)\n : undefined,\n attachments:\n this.edges.attachments.size > 0\n ? Object.fromEntries(this.edges.attachments)\n : undefined,\n };\n }\n\n toString(): string {\n const dataRefs = this.instance && [...this.instance.getDataRefs()];\n const out =\n dataRefs && dataRefs.length > 0\n ? ` out=[${[...dataRefs].map(r => r.id).join(', ')}]`\n : '';\n\n if (this.edges.attachments.size === 0) {\n return `<${this.spec.id}${out} />`;\n }\n\n return [\n `<${this.spec.id}${out}>`,\n ...[...this.edges.attachments.entries()].map(([k, v]) =>\n indent([`${k} [`, ...v.map(e => indent(e.toString())), `]`].join('\\n')),\n ),\n `</${this.spec.id}>`,\n ].join('\\n');\n }\n}\n\nfunction makeRedirectKey(attachTo: { id: string; input: string }) {\n return `${attachTo.id}%${attachTo.input}`;\n}\n\nconst isValidAttachmentPoint = (\n attachTo: { id: string; input: string },\n nodes: Map<string, SerializableAppNode>,\n) => {\n if (!nodes.has(attachTo.id)) {\n return false;\n }\n\n return (\n attachTo.input in\n toInternalExtension(nodes.get(attachTo.id)!.spec.extension).inputs\n );\n};\n\n/**\n * Build the app tree by iterating through all node specs and constructing the app\n * tree with all attachments in the same order as they appear in the input specs array.\n * @internal\n */\nexport function resolveAppTree(\n rootNodeId: string,\n specs: AppNodeSpec[],\n errorCollector: ErrorCollector,\n): AppTree {\n const nodes = new Map<string, SerializableAppNode>();\n\n const redirectTargetsByKey = new Map<string, { id: string; input: string }>();\n\n for (const spec of specs) {\n // The main check with a helpful error message happens in resolveAppNodeSpecs\n if (nodes.has(spec.id)) {\n continue;\n }\n\n const node = new SerializableAppNode(spec);\n nodes.set(spec.id, node);\n\n const internal = toInternalExtension(spec.extension);\n for (const [inputName, input] of Object.entries(internal.inputs)) {\n if (input.replaces) {\n for (const replace of input.replaces) {\n const key = makeRedirectKey(replace);\n if (redirectTargetsByKey.has(key)) {\n errorCollector.report({\n code: 'EXTENSION_INPUT_REDIRECT_CONFLICT',\n message: `Duplicate redirect target for input '${inputName}' in extension '${spec.id}'`,\n context: {\n node,\n inputName,\n },\n });\n continue;\n }\n redirectTargetsByKey.set(key, { id: spec.id, input: inputName });\n }\n }\n }\n }\n\n const orphans = new Array<SerializableAppNode>();\n const clones = new Map<string, Array<SerializableAppNode>>();\n\n // A node with the provided rootNodeId must be found in the tree, and it must not be attached to anything\n let rootNode: AppNode | undefined = undefined;\n\n for (const node of nodes.values()) {\n const spec = node.spec;\n\n // TODO: For now we simply ignore the attachTo spec of the root node, but it'd be cleaner if we could avoid defining it\n if (spec.id === rootNodeId) {\n rootNode = node;\n } else if (Array.isArray(spec.attachTo)) {\n // eslint-disable-next-line no-console\n console.warn(\n `Extension '${spec.id}' is using multiple attachment points which is deprecated and will be removed in a future release. ` +\n `Use a Utility API instead to share functionality across multiple locations. ` +\n `See https://backstage.io/docs/frontend-system/architecture/27-sharing-extensions for migration guidance.`,\n );\n let foundFirstParent = false;\n for (const origAttachTo of spec.attachTo) {\n let attachTo = origAttachTo;\n\n if (!isValidAttachmentPoint(attachTo, nodes)) {\n attachTo =\n redirectTargetsByKey.get(makeRedirectKey(attachTo)) ?? attachTo;\n }\n\n const parent = nodes.get(attachTo.id);\n if (parent) {\n const cloneParents = clones.get(attachTo.id) ?? [];\n\n if (!foundFirstParent) {\n foundFirstParent = true;\n node.setParent(parent, attachTo.input);\n } else {\n cloneParents.unshift(parent);\n }\n\n for (const extraParent of cloneParents) {\n const clonedNode = new SerializableAppNode(spec);\n clonedNode.setParent(extraParent, attachTo.input);\n clones.set(\n spec.id,\n clones.get(spec.id)?.concat(clonedNode) ?? [clonedNode],\n );\n }\n }\n }\n if (!foundFirstParent) {\n orphans.push(node);\n }\n } else {\n let attachTo = spec.attachTo;\n if (!isValidAttachmentPoint(attachTo, nodes)) {\n attachTo =\n redirectTargetsByKey.get(makeRedirectKey(attachTo)) ?? attachTo;\n }\n\n const parent = nodes.get(attachTo.id);\n if (parent) {\n node.setParent(parent, attachTo.input);\n } else {\n orphans.push(node);\n }\n }\n }\n\n if (!rootNode) {\n throw new Error(`No root node with id '${rootNodeId}' found in app tree`);\n }\n\n return {\n root: rootNode,\n nodes,\n orphans,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createErrorCollector.esm.js","sources":["../../src/wiring/createErrorCollector.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 { AppNode, FrontendPlugin } from '@backstage/frontend-plugin-api';\n\n/**\n * @public\n */\nexport type AppErrorTypes = {\n // resolveAppNodeSpecs\n EXTENSION_IGNORED: {\n context: { plugin: FrontendPlugin; extensionId: string };\n };\n INVALID_EXTENSION_CONFIG_KEY: {\n context: { extensionId: string };\n };\n // resolveAppTree\n EXTENSION_INPUT_REDIRECT_CONFLICT: {\n context: { node: AppNode; inputName: string };\n };\n // instantiateAppNodeTree\n EXTENSION_INPUT_DATA_IGNORED: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_INPUT_DATA_MISSING: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_ATTACHMENT_CONFLICT: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_ATTACHMENT_MISSING: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_CONFIGURATION_INVALID: {\n context: { node: AppNode };\n };\n EXTENSION_INVALID: {\n context: { node: AppNode };\n };\n EXTENSION_OUTPUT_CONFLICT: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_OUTPUT_MISSING: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_OUTPUT_IGNORED: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_FACTORY_ERROR: {\n context: { node: AppNode };\n };\n // createSpecializedApp\n API_EXTENSION_INVALID: {\n context: { node: AppNode };\n };\n API_FACTORY_CONFLICT: {\n context: {\n node: AppNode;\n apiRefId: string;\n pluginId: string;\n existingPluginId: string;\n };\n };\n // routing\n ROUTE_DUPLICATE: {\n context: { routeId: string };\n };\n ROUTE_BINDING_INVALID_VALUE: {\n context: { routeId: string };\n };\n ROUTE_NOT_FOUND: {\n context: { routeId: string };\n };\n};\n\n/**\n * @public\n */\nexport type AppError =\n keyof AppErrorTypes extends infer ICode extends keyof AppErrorTypes\n ? ICode extends any\n ? {\n code: ICode;\n message: string;\n context: AppErrorTypes[ICode]['context'];\n }\n : never\n : never;\n\n/** @internal */\nexport interface ErrorCollector<TContext extends {} = {}> {\n report<TCode extends keyof AppErrorTypes>(\n report: Omit<\n AppErrorTypes[TCode]['context'],\n keyof TContext\n > extends infer IContext extends {}\n ? {} extends IContext\n ? {\n code: TCode;\n message: string;\n }\n : {\n code: TCode;\n message: string;\n context: IContext;\n }\n : never,\n ): void;\n child<TAdditionalContext extends {}>(\n context: TAdditionalContext,\n ): ErrorCollector<TContext & TAdditionalContext>;\n collectErrors(): AppError[] | undefined;\n}\n\n/** @internal */\nexport function createErrorCollector(\n context?: Partial<AppError['context']>,\n): ErrorCollector {\n const errors: AppError[] = [];\n const children: ErrorCollector[] = [];\n return {\n report(report: { code: string; message: string; context?: {} }) {\n errors.push({\n ...report,\n context: { ...context, ...report.context },\n } as AppError);\n },\n collectErrors() {\n const allErrors = [\n ...errors,\n ...children.flatMap(child => child.collectErrors() ?? []),\n ];\n errors.length = 0;\n if (allErrors.length === 0) {\n return undefined;\n }\n return allErrors;\n },\n child(childContext) {\n const child = createErrorCollector({ ...context, ...childContext });\n children.push(child);\n return child as ErrorCollector<any>;\n },\n };\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createErrorCollector.esm.js","sources":["../../src/wiring/createErrorCollector.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 { AppNode, FrontendPlugin } from '@backstage/frontend-plugin-api';\n\n/**\n * @public\n */\nexport type AppErrorTypes = {\n // resolveAppNodeSpecs\n EXTENSION_IGNORED: {\n context: { plugin: FrontendPlugin; extensionId: string };\n };\n INVALID_EXTENSION_CONFIG_KEY: {\n context: { extensionId: string };\n };\n // resolveAppTree\n EXTENSION_INPUT_REDIRECT_CONFLICT: {\n context: { node: AppNode; inputName: string };\n };\n // instantiateAppNodeTree\n EXTENSION_INPUT_DATA_IGNORED: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_INPUT_DATA_MISSING: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_INPUT_INTERNAL_IGNORED: {\n context: {\n node: AppNode;\n inputName: string;\n extensionId: string;\n plugin: FrontendPlugin;\n };\n };\n EXTENSION_ATTACHMENT_CONFLICT: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_ATTACHMENT_MISSING: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_CONFIGURATION_INVALID: {\n context: { node: AppNode };\n };\n EXTENSION_INVALID: {\n context: { node: AppNode };\n };\n EXTENSION_OUTPUT_CONFLICT: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_OUTPUT_MISSING: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_OUTPUT_IGNORED: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_FACTORY_ERROR: {\n context: { node: AppNode };\n };\n // createSpecializedApp\n API_EXTENSION_INVALID: {\n context: { node: AppNode };\n };\n API_FACTORY_CONFLICT: {\n context: {\n node: AppNode;\n apiRefId: string;\n pluginId: string;\n existingPluginId: string;\n };\n };\n // routing\n ROUTE_DUPLICATE: {\n context: { routeId: string };\n };\n ROUTE_BINDING_INVALID_VALUE: {\n context: { routeId: string };\n };\n ROUTE_NOT_FOUND: {\n context: { routeId: string };\n };\n};\n\n/**\n * @public\n */\nexport type AppError =\n keyof AppErrorTypes extends infer ICode extends keyof AppErrorTypes\n ? ICode extends any\n ? {\n code: ICode;\n message: string;\n context: AppErrorTypes[ICode]['context'];\n }\n : never\n : never;\n\n/** @internal */\nexport interface ErrorCollector<TContext extends {} = {}> {\n report<TCode extends keyof AppErrorTypes>(\n report: Omit<\n AppErrorTypes[TCode]['context'],\n keyof TContext\n > extends infer IContext extends {}\n ? {} extends IContext\n ? {\n code: TCode;\n message: string;\n }\n : {\n code: TCode;\n message: string;\n context: IContext;\n }\n : never,\n ): void;\n child<TAdditionalContext extends {}>(\n context: TAdditionalContext,\n ): ErrorCollector<TContext & TAdditionalContext>;\n collectErrors(): AppError[] | undefined;\n}\n\n/** @internal */\nexport function createErrorCollector(\n context?: Partial<AppError['context']>,\n): ErrorCollector {\n const errors: AppError[] = [];\n const children: ErrorCollector[] = [];\n return {\n report(report: { code: string; message: string; context?: {} }) {\n errors.push({\n ...report,\n context: { ...context, ...report.context },\n } as AppError);\n },\n collectErrors() {\n const allErrors = [\n ...errors,\n ...children.flatMap(child => child.collectErrors() ?? []),\n ];\n errors.length = 0;\n if (allErrors.length === 0) {\n return undefined;\n }\n return allErrors;\n },\n child(childContext) {\n const child = createErrorCollector({ ...context, ...childContext });\n children.push(child);\n return child as ErrorCollector<any>;\n },\n };\n}\n"],"names":[],"mappings":"AAwIO,SAAS,qBACd,OAAA,EACgB;AAChB,EAAA,MAAM,SAAqB,EAAC;AAC5B,EAAA,MAAM,WAA6B,EAAC;AACpC,EAAA,OAAO;AAAA,IACL,OAAO,MAAA,EAAyD;AAC9D,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,GAAG,MAAA;AAAA,QACH,SAAS,EAAE,GAAG,OAAA,EAAS,GAAG,OAAO,OAAA;AAAQ,OAC9B,CAAA;AAAA,IACf,CAAA;AAAA,IACA,aAAA,GAAgB;AACd,MAAA,MAAM,SAAA,GAAY;AAAA,QAChB,GAAG,MAAA;AAAA,QACH,GAAG,SAAS,OAAA,CAAQ,CAAA,KAAA,KAAS,MAAM,aAAA,EAAc,IAAK,EAAE;AAAA,OAC1D;AACA,MAAA,MAAA,CAAO,MAAA,GAAS,CAAA;AAChB,MAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,QAAA,OAAO,MAAA;AAAA,MACT;AACA,MAAA,OAAO,SAAA;AAAA,IACT,CAAA;AAAA,IACA,MAAM,YAAA,EAAc;AAClB,MAAA,MAAM,QAAQ,oBAAA,CAAqB,EAAE,GAAG,OAAA,EAAS,GAAG,cAAc,CAAA;AAClE,MAAA,QAAA,CAAS,KAAK,KAAK,CAAA;AACnB,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,GACF;AACF;;;;"}
|
|
@@ -27,7 +27,10 @@ function createPluginInfoAttacher(config, infoResolver = async (ctx) => ctx.defa
|
|
|
27
27
|
}
|
|
28
28
|
})
|
|
29
29
|
});
|
|
30
|
-
const infoWithOverrides = applyInfoOverrides(
|
|
30
|
+
const infoWithOverrides = applyInfoOverrides(
|
|
31
|
+
plugin.pluginId,
|
|
32
|
+
resolvedInfo
|
|
33
|
+
);
|
|
31
34
|
return normalizePluginInfo(infoWithOverrides);
|
|
32
35
|
})
|
|
33
36
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPluginInfoAttacher.esm.js","sources":["../../src/wiring/createPluginInfoAttacher.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 { ConfigApi } from '@backstage/core-plugin-api';\nimport {\n FrontendFeature,\n FrontendPluginInfo,\n} from '@backstage/frontend-plugin-api';\nimport { OpaqueFrontendPlugin } from '@internal/frontend';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport once from 'lodash/once';\n// Avoid full dependency on catalog-model\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport {\n parseEntityRef,\n stringifyEntityRef,\n} from '../../../catalog-model/src/entity/ref';\n\n/**\n * A function that resolves plugin info from a plugin manifest and package.json.\n *\n * @public\n */\nexport type FrontendPluginInfoResolver = (ctx: {\n packageJson(): Promise<JsonObject | undefined>;\n manifest(): Promise<JsonObject | undefined>;\n defaultResolver(sources: {\n packageJson: JsonObject | undefined;\n manifest: JsonObject | undefined;\n }): Promise<{ info: FrontendPluginInfo }>;\n}) => Promise<{ info: FrontendPluginInfo }>;\n\nexport function createPluginInfoAttacher(\n config: ConfigApi,\n infoResolver: FrontendPluginInfoResolver = async ctx =>\n ctx.defaultResolver({\n packageJson: await ctx.packageJson(),\n manifest: await ctx.manifest(),\n }),\n): (feature: FrontendFeature) => FrontendFeature {\n const applyInfoOverrides = createPluginInfoOverrider(config);\n\n return (feature: FrontendFeature) => {\n if (!OpaqueFrontendPlugin.isType(feature)) {\n return feature;\n }\n\n const plugin = OpaqueFrontendPlugin.toInternal(feature);\n\n return {\n ...plugin,\n info: once(async () => {\n const manifestLoader = plugin.infoOptions?.manifest;\n const packageJsonLoader = plugin.infoOptions?.packageJson;\n\n const { info: resolvedInfo } = await infoResolver({\n manifest: async () => manifestLoader?.(),\n packageJson: async () => packageJsonLoader?.(),\n defaultResolver: async sources => ({\n info: {\n ...resolvePackageInfo(sources.packageJson),\n ...resolveManifestInfo(sources.manifest),\n },\n }),\n });\n\n const infoWithOverrides = applyInfoOverrides(plugin.id, resolvedInfo);\n return normalizePluginInfo(infoWithOverrides);\n }),\n };\n };\n}\n\nfunction normalizePluginInfo(info: FrontendPluginInfo) {\n return {\n ...info,\n ownerEntityRefs: info.ownerEntityRefs?.map(ref =>\n stringifyEntityRef(\n parseEntityRef(ref, {\n defaultKind: 'Group',\n }),\n ),\n ),\n };\n}\n\nfunction createPluginInfoOverrider(config: ConfigApi) {\n const overrideConfigs =\n config.getOptionalConfigArray('app.pluginOverrides') ?? [];\n\n const overrideMatchers = overrideConfigs.map(overrideConfig => {\n const pluginIdMatcher = makeStringMatcher(\n overrideConfig.getOptionalString('match.pluginId'),\n );\n const packageNameMatcher = makeStringMatcher(\n overrideConfig.getOptionalString('match.packageName'),\n );\n const description = overrideConfig.getOptionalString('info.description');\n const ownerEntityRefs = overrideConfig.getOptionalStringArray(\n 'info.ownerEntityRefs',\n );\n const links = overrideConfig\n .getOptionalConfigArray('info.links')\n ?.map(linkConfig => ({\n title: linkConfig.getString('title'),\n url: linkConfig.getString('url'),\n }));\n\n return {\n test(pluginId: string, packageName?: string) {\n return packageNameMatcher(packageName) && pluginIdMatcher(pluginId);\n },\n info: {\n description,\n ownerEntityRefs,\n links,\n },\n };\n });\n\n return (pluginId: string, info: FrontendPluginInfo) => {\n const { packageName } = info;\n for (const matcher of overrideMatchers) {\n if (matcher.test(pluginId, packageName)) {\n if (matcher.info.description) {\n info.description = matcher.info.description;\n }\n if (matcher.info.ownerEntityRefs) {\n info.ownerEntityRefs = matcher.info.ownerEntityRefs;\n }\n if (matcher.info.links) {\n info.links = matcher.info.links;\n }\n }\n }\n return info;\n };\n}\n\nfunction resolveManifestInfo(manifest?: JsonValue) {\n if (!isJsonObject(manifest) || !isJsonObject(manifest.metadata)) {\n return undefined;\n }\n\n const info: FrontendPluginInfo = {};\n\n if (isJsonObject(manifest.spec) && typeof manifest.spec.owner === 'string') {\n info.ownerEntityRefs = [\n stringifyEntityRef(\n parseEntityRef(manifest.spec.owner, {\n defaultKind: 'Group',\n defaultNamespace: manifest.metadata.namespace?.toString(),\n }),\n ),\n ];\n }\n\n if (Array.isArray(manifest.metadata.links)) {\n info.links = manifest.metadata.links.filter(isJsonObject).map(link => ({\n title: String(link.title),\n url: String(link.url),\n }));\n }\n\n return info;\n}\n\nfunction resolvePackageInfo(packageJson?: JsonObject) {\n if (!packageJson) {\n return undefined;\n }\n\n const info: FrontendPluginInfo = {\n packageName: packageJson?.name?.toString(),\n version: packageJson?.version?.toString(),\n description: packageJson?.description?.toString(),\n };\n\n const links: { title: string; url: string }[] = [];\n\n if (typeof packageJson.homepage === 'string') {\n links.push({\n title: 'Homepage',\n url: packageJson.homepage,\n });\n }\n\n if (\n isJsonObject(packageJson.repository) &&\n typeof packageJson.repository?.url === 'string'\n ) {\n try {\n const url = new URL(packageJson.repository?.url);\n if (url.protocol === 'http:' || url.protocol === 'https:') {\n // TODO(Rugvip): Support more variants\n if (\n url.hostname === 'github.com' &&\n typeof packageJson.repository.directory === 'string'\n ) {\n const path = `${url.pathname}/tree/-/${packageJson.repository.directory}`;\n url.pathname = path.replaceAll('//', '/');\n }\n\n links.push({\n title: 'Repository',\n url: url.toString(),\n });\n }\n } catch {\n /* ignored */\n }\n }\n\n if (links.length > 0) {\n info.links = links;\n }\n return info;\n}\n\nfunction makeStringMatcher(pattern: string | undefined) {\n if (!pattern) {\n return () => true;\n }\n if (pattern.startsWith('/') && pattern.endsWith('/') && pattern.length > 2) {\n const regex = new RegExp(pattern.slice(1, -1));\n return (str?: string) => (str ? regex.test(str) : false);\n }\n\n return (str?: string) => str === pattern;\n}\n\nfunction isJsonObject(value?: JsonValue): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createPluginInfoAttacher.esm.js","sources":["../../src/wiring/createPluginInfoAttacher.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 { ConfigApi } from '@backstage/core-plugin-api';\nimport {\n FrontendFeature,\n FrontendPluginInfo,\n} from '@backstage/frontend-plugin-api';\nimport { OpaqueFrontendPlugin } from '@internal/frontend';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport once from 'lodash/once';\n// Avoid full dependency on catalog-model\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport {\n parseEntityRef,\n stringifyEntityRef,\n} from '../../../catalog-model/src/entity/ref';\n\n/**\n * A function that resolves plugin info from a plugin manifest and package.json.\n *\n * @public\n */\nexport type FrontendPluginInfoResolver = (ctx: {\n packageJson(): Promise<JsonObject | undefined>;\n manifest(): Promise<JsonObject | undefined>;\n defaultResolver(sources: {\n packageJson: JsonObject | undefined;\n manifest: JsonObject | undefined;\n }): Promise<{ info: FrontendPluginInfo }>;\n}) => Promise<{ info: FrontendPluginInfo }>;\n\nexport function createPluginInfoAttacher(\n config: ConfigApi,\n infoResolver: FrontendPluginInfoResolver = async ctx =>\n ctx.defaultResolver({\n packageJson: await ctx.packageJson(),\n manifest: await ctx.manifest(),\n }),\n): (feature: FrontendFeature) => FrontendFeature {\n const applyInfoOverrides = createPluginInfoOverrider(config);\n\n return (feature: FrontendFeature) => {\n if (!OpaqueFrontendPlugin.isType(feature)) {\n return feature;\n }\n\n const plugin = OpaqueFrontendPlugin.toInternal(feature);\n\n return {\n ...plugin,\n info: once(async () => {\n const manifestLoader = plugin.infoOptions?.manifest;\n const packageJsonLoader = plugin.infoOptions?.packageJson;\n\n const { info: resolvedInfo } = await infoResolver({\n manifest: async () => manifestLoader?.(),\n packageJson: async () => packageJsonLoader?.(),\n defaultResolver: async sources => ({\n info: {\n ...resolvePackageInfo(sources.packageJson),\n ...resolveManifestInfo(sources.manifest),\n },\n }),\n });\n\n const infoWithOverrides = applyInfoOverrides(\n plugin.pluginId,\n resolvedInfo,\n );\n return normalizePluginInfo(infoWithOverrides);\n }),\n };\n };\n}\n\nfunction normalizePluginInfo(info: FrontendPluginInfo) {\n return {\n ...info,\n ownerEntityRefs: info.ownerEntityRefs?.map(ref =>\n stringifyEntityRef(\n parseEntityRef(ref, {\n defaultKind: 'Group',\n }),\n ),\n ),\n };\n}\n\nfunction createPluginInfoOverrider(config: ConfigApi) {\n const overrideConfigs =\n config.getOptionalConfigArray('app.pluginOverrides') ?? [];\n\n const overrideMatchers = overrideConfigs.map(overrideConfig => {\n const pluginIdMatcher = makeStringMatcher(\n overrideConfig.getOptionalString('match.pluginId'),\n );\n const packageNameMatcher = makeStringMatcher(\n overrideConfig.getOptionalString('match.packageName'),\n );\n const description = overrideConfig.getOptionalString('info.description');\n const ownerEntityRefs = overrideConfig.getOptionalStringArray(\n 'info.ownerEntityRefs',\n );\n const links = overrideConfig\n .getOptionalConfigArray('info.links')\n ?.map(linkConfig => ({\n title: linkConfig.getString('title'),\n url: linkConfig.getString('url'),\n }));\n\n return {\n test(pluginId: string, packageName?: string) {\n return packageNameMatcher(packageName) && pluginIdMatcher(pluginId);\n },\n info: {\n description,\n ownerEntityRefs,\n links,\n },\n };\n });\n\n return (pluginId: string, info: FrontendPluginInfo) => {\n const { packageName } = info;\n for (const matcher of overrideMatchers) {\n if (matcher.test(pluginId, packageName)) {\n if (matcher.info.description) {\n info.description = matcher.info.description;\n }\n if (matcher.info.ownerEntityRefs) {\n info.ownerEntityRefs = matcher.info.ownerEntityRefs;\n }\n if (matcher.info.links) {\n info.links = matcher.info.links;\n }\n }\n }\n return info;\n };\n}\n\nfunction resolveManifestInfo(manifest?: JsonValue) {\n if (!isJsonObject(manifest) || !isJsonObject(manifest.metadata)) {\n return undefined;\n }\n\n const info: FrontendPluginInfo = {};\n\n if (isJsonObject(manifest.spec) && typeof manifest.spec.owner === 'string') {\n info.ownerEntityRefs = [\n stringifyEntityRef(\n parseEntityRef(manifest.spec.owner, {\n defaultKind: 'Group',\n defaultNamespace: manifest.metadata.namespace?.toString(),\n }),\n ),\n ];\n }\n\n if (Array.isArray(manifest.metadata.links)) {\n info.links = manifest.metadata.links.filter(isJsonObject).map(link => ({\n title: String(link.title),\n url: String(link.url),\n }));\n }\n\n return info;\n}\n\nfunction resolvePackageInfo(packageJson?: JsonObject) {\n if (!packageJson) {\n return undefined;\n }\n\n const info: FrontendPluginInfo = {\n packageName: packageJson?.name?.toString(),\n version: packageJson?.version?.toString(),\n description: packageJson?.description?.toString(),\n };\n\n const links: { title: string; url: string }[] = [];\n\n if (typeof packageJson.homepage === 'string') {\n links.push({\n title: 'Homepage',\n url: packageJson.homepage,\n });\n }\n\n if (\n isJsonObject(packageJson.repository) &&\n typeof packageJson.repository?.url === 'string'\n ) {\n try {\n const url = new URL(packageJson.repository?.url);\n if (url.protocol === 'http:' || url.protocol === 'https:') {\n // TODO(Rugvip): Support more variants\n if (\n url.hostname === 'github.com' &&\n typeof packageJson.repository.directory === 'string'\n ) {\n const path = `${url.pathname}/tree/-/${packageJson.repository.directory}`;\n url.pathname = path.replaceAll('//', '/');\n }\n\n links.push({\n title: 'Repository',\n url: url.toString(),\n });\n }\n } catch {\n /* ignored */\n }\n }\n\n if (links.length > 0) {\n info.links = links;\n }\n return info;\n}\n\nfunction makeStringMatcher(pattern: string | undefined) {\n if (!pattern) {\n return () => true;\n }\n if (pattern.startsWith('/') && pattern.endsWith('/') && pattern.length > 2) {\n const regex = new RegExp(pattern.slice(1, -1));\n return (str?: string) => (str ? regex.test(str) : false);\n }\n\n return (str?: string) => str === pattern;\n}\n\nfunction isJsonObject(value?: JsonValue): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -105,6 +105,7 @@ class RouteResolutionApiProxy {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
function createSpecializedApp(options) {
|
|
108
|
+
const internalOptions = options;
|
|
108
109
|
const config = options?.config ?? new ConfigReader({}, "empty-config");
|
|
109
110
|
const features = deduplicateFeatures(options?.features ?? []).map(
|
|
110
111
|
createPluginInfoAttacher(config, options?.advanced?.pluginInfoResolver)
|
|
@@ -138,7 +139,8 @@ function createSpecializedApp(options) {
|
|
|
138
139
|
createApiFactory(appTreeApiRef, appTreeApi),
|
|
139
140
|
createApiFactory(configApiRef, config),
|
|
140
141
|
createApiFactory(routeResolutionApiRef, routeResolutionApi),
|
|
141
|
-
createApiFactory(identityApiRef, appIdentityProxy)
|
|
142
|
+
createApiFactory(identityApiRef, appIdentityProxy),
|
|
143
|
+
...internalOptions?.__internal?.apiFactoryOverrides ?? []
|
|
142
144
|
]
|
|
143
145
|
});
|
|
144
146
|
const featureFlagApi = apis.get(featureFlagsApiRef);
|
|
@@ -189,7 +191,7 @@ function createApiFactories(options) {
|
|
|
189
191
|
if (apiFactory) {
|
|
190
192
|
const apiRefId = apiFactory.api.id;
|
|
191
193
|
const ownerId = getApiOwnerId(apiRefId);
|
|
192
|
-
const pluginId = apiNode.spec.plugin.
|
|
194
|
+
const pluginId = apiNode.spec.plugin.pluginId ?? "app";
|
|
193
195
|
const existingFactory = factoriesById.get(apiRefId);
|
|
194
196
|
if (existingFactory && existingFactory.pluginId !== pluginId) {
|
|
195
197
|
const shouldReplace = ownerId === pluginId && existingFactory.pluginId !== ownerId;
|
|
@@ -205,11 +207,13 @@ function createApiFactories(options) {
|
|
|
205
207
|
existingPluginId: acceptedPluginId
|
|
206
208
|
}
|
|
207
209
|
});
|
|
208
|
-
if (
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
if (shouldReplace) {
|
|
211
|
+
factoriesById.set(apiRefId, {
|
|
212
|
+
pluginId,
|
|
213
|
+
factory: apiFactory
|
|
214
|
+
});
|
|
212
215
|
}
|
|
216
|
+
continue;
|
|
213
217
|
}
|
|
214
218
|
factoriesById.set(apiRefId, { pluginId, factory: apiFactory });
|
|
215
219
|
} else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createSpecializedApp.esm.js","sources":["../../src/wiring/createSpecializedApp.tsx"],"sourcesContent":["/*\n * Copyright 2023 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 { ConfigReader } from '@backstage/config';\nimport {\n ApiBlueprint,\n AppTree,\n AppTreeApi,\n appTreeApiRef,\n RouteRef,\n ExternalRouteRef,\n SubRouteRef,\n AnyRouteRefParams,\n RouteFunc,\n RouteResolutionApi,\n createApiFactory,\n routeResolutionApiRef,\n AppNode,\n ExtensionFactoryMiddleware,\n FrontendFeature,\n} from '@backstage/frontend-plugin-api';\nimport {\n AnyApiFactory,\n ApiHolder,\n ConfigApi,\n configApiRef,\n featureFlagsApiRef,\n identityApiRef,\n} from '@backstage/core-plugin-api';\nimport { ApiFactoryRegistry, ApiResolver } from '@backstage/core-app-api';\nimport {\n createExtensionDataContainer,\n OpaqueFrontendPlugin,\n} from '@internal/frontend';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport {\n resolveExtensionDefinition,\n toInternalExtension,\n} from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\n\nimport {\n extractRouteInfoFromAppNode,\n RouteInfo,\n} from '../routing/extractRouteInfoFromAppNode';\n\nimport { CreateAppRouteBinder } from '../routing';\nimport { RouteResolver } from '../routing/RouteResolver';\nimport { resolveRouteBindings } from '../routing/resolveRouteBindings';\nimport { collectRouteIds } from '../routing/collectRouteIds';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport {\n toInternalFrontendModule,\n isInternalFrontendModule,\n} from '../../../frontend-plugin-api/src/wiring/createFrontendModule';\nimport { getBasePath } from '../routing/getBasePath';\nimport { Root } from '../extensions/Root';\nimport { resolveAppTree } from '../tree/resolveAppTree';\nimport { resolveAppNodeSpecs } from '../tree/resolveAppNodeSpecs';\nimport { readAppExtensionsConfig } from '../tree/readAppExtensionsConfig';\nimport { instantiateAppNodeTree } from '../tree/instantiateAppNodeTree';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { ApiRegistry } from '../../../core-app-api/src/apis/system/ApiRegistry';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { AppIdentityProxy } from '../../../core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy';\nimport { BackstageRouteObject } from '../routing/types';\nimport { matchRoutes } from 'react-router-dom';\nimport {\n createPluginInfoAttacher,\n FrontendPluginInfoResolver,\n} from './createPluginInfoAttacher';\nimport { createRouteAliasResolver } from '../routing/RouteAliasResolver';\nimport {\n AppError,\n createErrorCollector,\n ErrorCollector,\n} from './createErrorCollector';\n\nfunction deduplicateFeatures(\n allFeatures: FrontendFeature[],\n): FrontendFeature[] {\n // Start by removing duplicates by reference\n const features = Array.from(new Set(allFeatures));\n\n // Plugins are deduplicated by ID, last one wins\n const seenIds = new Set<string>();\n return features\n .reverse()\n .filter(feature => {\n if (!OpaqueFrontendPlugin.isType(feature)) {\n return true;\n }\n if (seenIds.has(feature.id)) {\n return false;\n }\n seenIds.add(feature.id);\n return true;\n })\n .reverse();\n}\n\n// Helps delay callers from reaching out to the API before the app tree has been materialized\nclass AppTreeApiProxy implements AppTreeApi {\n #routeInfo?: RouteInfo;\n private readonly tree: AppTree;\n private readonly appBasePath: string;\n\n constructor(tree: AppTree, appBasePath: string) {\n this.tree = tree;\n this.appBasePath = appBasePath;\n }\n\n private checkIfInitialized() {\n if (!this.#routeInfo) {\n throw new Error(\n `You can't access the AppTreeApi during initialization of the app tree. Please move occurrences of this out of the initialization of the factory`,\n );\n }\n }\n\n getTree() {\n this.checkIfInitialized();\n\n return { tree: this.tree };\n }\n\n getNodesByRoutePath(routePath: string): { nodes: AppNode[] } {\n this.checkIfInitialized();\n\n let path = routePath;\n if (path.startsWith(this.appBasePath)) {\n path = path.slice(this.appBasePath.length);\n }\n\n const matchedRoutes = matchRoutes(this.#routeInfo!.routeObjects, path);\n\n const matchedAppNodes =\n matchedRoutes\n ?.filter(routeObj => !!routeObj.route.appNode)\n .map(routeObj => routeObj.route.appNode!) || [];\n\n return { nodes: matchedAppNodes };\n }\n\n initialize(routeInfo: RouteInfo) {\n this.#routeInfo = routeInfo;\n }\n}\n\n// Helps delay callers from reaching out to the API before the app tree has been materialized\nclass RouteResolutionApiProxy implements RouteResolutionApi {\n #delegate: RouteResolutionApi | undefined;\n #routeObjects: BackstageRouteObject[] | undefined;\n\n private readonly routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>;\n private readonly appBasePath: string;\n\n constructor(\n routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>,\n appBasePath: string,\n ) {\n this.routeBindings = routeBindings;\n this.appBasePath = appBasePath;\n }\n\n resolve<TParams extends AnyRouteRefParams>(\n anyRouteRef:\n | RouteRef<TParams>\n | SubRouteRef<TParams>\n | ExternalRouteRef<TParams>,\n options?: { sourcePath?: string },\n ): RouteFunc<TParams> | undefined {\n if (!this.#delegate) {\n throw new Error(\n `You can't access the RouteResolver during initialization of the app tree. Please move occurrences of this out of the initialization of the factory`,\n );\n }\n\n return this.#delegate.resolve(anyRouteRef, options);\n }\n\n initialize(\n routeInfo: RouteInfo,\n routeRefsById: Map<string, RouteRef | SubRouteRef>,\n ) {\n this.#delegate = new RouteResolver(\n routeInfo.routePaths,\n routeInfo.routeParents,\n routeInfo.routeObjects,\n this.routeBindings,\n this.appBasePath,\n routeInfo.routeAliasResolver,\n routeRefsById,\n );\n this.#routeObjects = routeInfo.routeObjects;\n\n return routeInfo;\n }\n\n getRouteObjects() {\n return this.#routeObjects;\n }\n}\n\n/**\n * Options for {@link createSpecializedApp}.\n *\n * @public\n */\nexport type CreateSpecializedAppOptions = {\n /**\n * The list of features to load.\n */\n features?: FrontendFeature[];\n\n /**\n * The config API implementation to use. For most normal apps, this should be\n * specified.\n *\n * If none is given, a new _empty_ config will be used during startup. In\n * later stages of the app lifecycle, the config API in the API holder will be\n * used.\n */\n config?: ConfigApi;\n\n /**\n * Allows for the binding of plugins' external route refs within the app.\n */\n bindRoutes?(context: { bind: CreateAppRouteBinder }): void;\n\n /**\n * Advanced, more rarely used options.\n */\n advanced?: {\n /**\n * A replacement API holder implementation to use.\n *\n * By default, a new API holder will be constructed automatically based on\n * the other inputs. If you pass in a custom one here, none of that\n * automation will take place - so you will have to take care to supply all\n * those APIs yourself.\n */\n apis?: ApiHolder;\n\n /**\n * If set to true, the system will silently accept and move on if\n * encountering config for extensions that do not exist. The default is to\n * reject such config to help catch simple mistakes.\n *\n * This flag can be useful in some scenarios where you have a dynamic set of\n * extensions enabled at different times, but also increases the risk of\n * accidentally missing e.g. simple typos in your config.\n */\n allowUnknownExtensionConfig?: boolean;\n\n /**\n * Applies one or more middleware on every extension, as they are added to\n * the application.\n *\n * This is an advanced use case for modifying extension data on the fly as\n * it gets emitted by extensions being instantiated.\n */\n extensionFactoryMiddleware?:\n | ExtensionFactoryMiddleware\n | ExtensionFactoryMiddleware[];\n\n /**\n * Allows for customizing how plugin info is retrieved.\n */\n pluginInfoResolver?: FrontendPluginInfoResolver;\n };\n};\n\n/**\n * Creates an empty app without any default features. This is a low-level API is\n * intended for use in tests or specialized setups. Typically you want to use\n * `createApp` from `@backstage/frontend-defaults` instead.\n *\n * @public\n */\nexport function createSpecializedApp(options?: CreateSpecializedAppOptions): {\n apis: ApiHolder;\n tree: AppTree;\n errors?: AppError[];\n} {\n const config = options?.config ?? new ConfigReader({}, 'empty-config');\n const features = deduplicateFeatures(options?.features ?? []).map(\n createPluginInfoAttacher(config, options?.advanced?.pluginInfoResolver),\n );\n\n const collector = createErrorCollector();\n\n const tree = resolveAppTree(\n 'root',\n resolveAppNodeSpecs({\n features,\n builtinExtensions: [\n resolveExtensionDefinition(Root, { namespace: 'root' }),\n ],\n parameters: readAppExtensionsConfig(config),\n forbidden: new Set(['root']),\n collector,\n }),\n collector,\n );\n\n const factories = createApiFactories({ tree, collector });\n const appBasePath = getBasePath(config);\n const appTreeApi = new AppTreeApiProxy(tree, appBasePath);\n\n const routeRefsById = collectRouteIds(features, collector);\n const routeResolutionApi = new RouteResolutionApiProxy(\n resolveRouteBindings(options?.bindRoutes, config, routeRefsById, collector),\n appBasePath,\n );\n\n const appIdentityProxy = new AppIdentityProxy();\n const apis =\n options?.advanced?.apis ??\n createApiHolder({\n factories,\n staticFactories: [\n createApiFactory(appTreeApiRef, appTreeApi),\n createApiFactory(configApiRef, config),\n createApiFactory(routeResolutionApiRef, routeResolutionApi),\n createApiFactory(identityApiRef, appIdentityProxy),\n ],\n });\n\n const featureFlagApi = apis.get(featureFlagsApiRef);\n if (featureFlagApi) {\n for (const feature of features) {\n if (OpaqueFrontendPlugin.isType(feature)) {\n OpaqueFrontendPlugin.toInternal(feature).featureFlags.forEach(flag =>\n featureFlagApi.registerFlag({\n name: flag.name,\n pluginId: feature.id,\n }),\n );\n }\n if (isInternalFrontendModule(feature)) {\n toInternalFrontendModule(feature).featureFlags.forEach(flag =>\n featureFlagApi.registerFlag({\n name: flag.name,\n pluginId: feature.pluginId,\n }),\n );\n }\n }\n }\n\n // Now instantiate the entire tree, which will skip anything that's already been instantiated\n instantiateAppNodeTree(\n tree.root,\n apis,\n collector,\n mergeExtensionFactoryMiddleware(\n options?.advanced?.extensionFactoryMiddleware,\n ),\n );\n\n const routeInfo = extractRouteInfoFromAppNode(\n tree.root,\n createRouteAliasResolver(routeRefsById),\n );\n\n routeResolutionApi.initialize(routeInfo, routeRefsById.routes);\n appTreeApi.initialize(routeInfo);\n\n return { apis, tree, errors: collector.collectErrors() };\n}\n\nfunction createApiFactories(options: {\n tree: AppTree;\n collector: ErrorCollector;\n}): AnyApiFactory[] {\n const emptyApiHolder = ApiRegistry.from([]);\n const factoriesById = new Map<\n string,\n { pluginId: string; factory: AnyApiFactory }\n >();\n\n for (const apiNode of options.tree.root.edges.attachments.get('apis') ?? []) {\n if (!instantiateAppNodeTree(apiNode, emptyApiHolder, options.collector)) {\n continue;\n }\n const apiFactory = apiNode.instance?.getData(ApiBlueprint.dataRefs.factory);\n if (apiFactory) {\n const apiRefId = apiFactory.api.id;\n const ownerId = getApiOwnerId(apiRefId);\n const pluginId = apiNode.spec.plugin.id ?? 'app';\n const existingFactory = factoriesById.get(apiRefId);\n\n // This allows modules to override factories provided by the plugin, but\n // it rejects API overrides from other plugins. In the event of a\n // conflict, the owning plugin is attempted to be inferred from the API\n // reference ID.\n if (existingFactory && existingFactory.pluginId !== pluginId) {\n const shouldReplace =\n ownerId === pluginId && existingFactory.pluginId !== ownerId;\n const acceptedPluginId = shouldReplace\n ? pluginId\n : existingFactory.pluginId;\n const rejectedPluginId = shouldReplace\n ? existingFactory.pluginId\n : pluginId;\n\n options.collector.report({\n code: 'API_FACTORY_CONFLICT',\n message: `API '${apiRefId}' is already provided by plugin '${acceptedPluginId}', cannot also be provided by '${rejectedPluginId}'.`,\n context: {\n node: apiNode,\n apiRefId,\n pluginId: rejectedPluginId,\n existingPluginId: acceptedPluginId,\n },\n });\n if (!shouldReplace) {\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: Plugin '${rejectedPluginId}' is overriding API '${apiRefId}' ` +\n `from plugin '${acceptedPluginId}'. This will be blocked in a future release. ` +\n `Please use a module for plugin '${acceptedPluginId}' instead.`,\n );\n }\n }\n\n factoriesById.set(apiRefId, { pluginId, factory: apiFactory });\n } else {\n options.collector.report({\n code: 'API_EXTENSION_INVALID',\n message: `API extension '${apiNode.spec.id}' did not output an API factory`,\n context: {\n node: apiNode,\n },\n });\n }\n }\n\n return Array.from(factoriesById.values(), entry => entry.factory);\n}\n\n// TODO(Rugvip): It would be good if this was more explicit, but I think that\n// might need to wait for some future update for API factories.\nfunction getApiOwnerId(apiRefId: string): string {\n const [prefix, ...rest] = apiRefId.split('.');\n if (!prefix) {\n return apiRefId;\n }\n if (prefix === 'core') {\n return 'app';\n }\n if (prefix === 'plugin' && rest[0]) {\n return rest[0];\n }\n return prefix;\n}\n\nfunction createApiHolder(options: {\n factories: AnyApiFactory[];\n staticFactories: AnyApiFactory[];\n}): ApiHolder {\n const factoryRegistry = new ApiFactoryRegistry();\n\n for (const factory of options.factories.slice().reverse()) {\n factoryRegistry.register('default', factory);\n }\n\n for (const factory of options.staticFactories) {\n factoryRegistry.register('static', factory);\n }\n\n ApiResolver.validateFactories(factoryRegistry, factoryRegistry.getAllApis());\n\n return new ApiResolver(factoryRegistry);\n}\n\nfunction mergeExtensionFactoryMiddleware(\n middlewares?: ExtensionFactoryMiddleware | ExtensionFactoryMiddleware[],\n): ExtensionFactoryMiddleware | undefined {\n if (!middlewares) {\n return undefined;\n }\n if (!Array.isArray(middlewares)) {\n return middlewares;\n }\n if (middlewares.length <= 1) {\n return middlewares[0];\n }\n return middlewares.reduce((prev, next) => {\n if (!prev || !next) {\n return prev ?? next;\n }\n return (orig, ctx) => {\n const internalExt = toInternalExtension(ctx.node.spec.extension);\n if (internalExt.version !== 'v2') {\n return orig();\n }\n return next(ctxOverrides => {\n return createExtensionDataContainer(\n prev(orig, {\n node: ctx.node,\n apis: ctx.apis,\n config: ctxOverrides?.config ?? ctx.config,\n }),\n 'extension factory middleware',\n );\n }, ctx);\n };\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createSpecializedApp.esm.js","sources":["../../src/wiring/createSpecializedApp.tsx"],"sourcesContent":["/*\n * Copyright 2023 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 { ConfigReader } from '@backstage/config';\nimport {\n ApiBlueprint,\n AppTree,\n AppTreeApi,\n appTreeApiRef,\n RouteRef,\n ExternalRouteRef,\n SubRouteRef,\n AnyRouteRefParams,\n RouteFunc,\n RouteResolutionApi,\n createApiFactory,\n routeResolutionApiRef,\n AppNode,\n ExtensionFactoryMiddleware,\n FrontendFeature,\n} from '@backstage/frontend-plugin-api';\nimport {\n AnyApiFactory,\n ApiHolder,\n ConfigApi,\n configApiRef,\n featureFlagsApiRef,\n identityApiRef,\n} from '@backstage/core-plugin-api';\nimport { ApiFactoryRegistry, ApiResolver } from '@backstage/core-app-api';\nimport {\n createExtensionDataContainer,\n OpaqueFrontendPlugin,\n} from '@internal/frontend';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport {\n resolveExtensionDefinition,\n toInternalExtension,\n} from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\n\nimport {\n extractRouteInfoFromAppNode,\n RouteInfo,\n} from '../routing/extractRouteInfoFromAppNode';\n\nimport { CreateAppRouteBinder } from '../routing';\nimport { RouteResolver } from '../routing/RouteResolver';\nimport { resolveRouteBindings } from '../routing/resolveRouteBindings';\nimport { collectRouteIds } from '../routing/collectRouteIds';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport {\n toInternalFrontendModule,\n isInternalFrontendModule,\n} from '../../../frontend-plugin-api/src/wiring/createFrontendModule';\nimport { getBasePath } from '../routing/getBasePath';\nimport { Root } from '../extensions/Root';\nimport { resolveAppTree } from '../tree/resolveAppTree';\nimport { resolveAppNodeSpecs } from '../tree/resolveAppNodeSpecs';\nimport { readAppExtensionsConfig } from '../tree/readAppExtensionsConfig';\nimport { instantiateAppNodeTree } from '../tree/instantiateAppNodeTree';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { ApiRegistry } from '../../../core-app-api/src/apis/system/ApiRegistry';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { AppIdentityProxy } from '../../../core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy';\nimport { BackstageRouteObject } from '../routing/types';\nimport { matchRoutes } from 'react-router-dom';\nimport {\n createPluginInfoAttacher,\n FrontendPluginInfoResolver,\n} from './createPluginInfoAttacher';\nimport { createRouteAliasResolver } from '../routing/RouteAliasResolver';\nimport {\n AppError,\n createErrorCollector,\n ErrorCollector,\n} from './createErrorCollector';\n\nfunction deduplicateFeatures(\n allFeatures: FrontendFeature[],\n): FrontendFeature[] {\n // Start by removing duplicates by reference\n const features = Array.from(new Set(allFeatures));\n\n // Plugins are deduplicated by ID, last one wins\n const seenIds = new Set<string>();\n return features\n .reverse()\n .filter(feature => {\n if (!OpaqueFrontendPlugin.isType(feature)) {\n return true;\n }\n if (seenIds.has(feature.id)) {\n return false;\n }\n seenIds.add(feature.id);\n return true;\n })\n .reverse();\n}\n\n// Helps delay callers from reaching out to the API before the app tree has been materialized\nclass AppTreeApiProxy implements AppTreeApi {\n #routeInfo?: RouteInfo;\n private readonly tree: AppTree;\n private readonly appBasePath: string;\n\n constructor(tree: AppTree, appBasePath: string) {\n this.tree = tree;\n this.appBasePath = appBasePath;\n }\n\n private checkIfInitialized() {\n if (!this.#routeInfo) {\n throw new Error(\n `You can't access the AppTreeApi during initialization of the app tree. Please move occurrences of this out of the initialization of the factory`,\n );\n }\n }\n\n getTree() {\n this.checkIfInitialized();\n\n return { tree: this.tree };\n }\n\n getNodesByRoutePath(routePath: string): { nodes: AppNode[] } {\n this.checkIfInitialized();\n\n let path = routePath;\n if (path.startsWith(this.appBasePath)) {\n path = path.slice(this.appBasePath.length);\n }\n\n const matchedRoutes = matchRoutes(this.#routeInfo!.routeObjects, path);\n\n const matchedAppNodes =\n matchedRoutes\n ?.filter(routeObj => !!routeObj.route.appNode)\n .map(routeObj => routeObj.route.appNode!) || [];\n\n return { nodes: matchedAppNodes };\n }\n\n initialize(routeInfo: RouteInfo) {\n this.#routeInfo = routeInfo;\n }\n}\n\n// Helps delay callers from reaching out to the API before the app tree has been materialized\nclass RouteResolutionApiProxy implements RouteResolutionApi {\n #delegate: RouteResolutionApi | undefined;\n #routeObjects: BackstageRouteObject[] | undefined;\n\n private readonly routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>;\n private readonly appBasePath: string;\n\n constructor(\n routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>,\n appBasePath: string,\n ) {\n this.routeBindings = routeBindings;\n this.appBasePath = appBasePath;\n }\n\n resolve<TParams extends AnyRouteRefParams>(\n anyRouteRef:\n | RouteRef<TParams>\n | SubRouteRef<TParams>\n | ExternalRouteRef<TParams>,\n options?: { sourcePath?: string },\n ): RouteFunc<TParams> | undefined {\n if (!this.#delegate) {\n throw new Error(\n `You can't access the RouteResolver during initialization of the app tree. Please move occurrences of this out of the initialization of the factory`,\n );\n }\n\n return this.#delegate.resolve(anyRouteRef, options);\n }\n\n initialize(\n routeInfo: RouteInfo,\n routeRefsById: Map<string, RouteRef | SubRouteRef>,\n ) {\n this.#delegate = new RouteResolver(\n routeInfo.routePaths,\n routeInfo.routeParents,\n routeInfo.routeObjects,\n this.routeBindings,\n this.appBasePath,\n routeInfo.routeAliasResolver,\n routeRefsById,\n );\n this.#routeObjects = routeInfo.routeObjects;\n\n return routeInfo;\n }\n\n getRouteObjects() {\n return this.#routeObjects;\n }\n}\n\n/**\n * Options for {@link createSpecializedApp}.\n *\n * @public\n */\nexport type CreateSpecializedAppOptions = {\n /**\n * The list of features to load.\n */\n features?: FrontendFeature[];\n\n /**\n * The config API implementation to use. For most normal apps, this should be\n * specified.\n *\n * If none is given, a new _empty_ config will be used during startup. In\n * later stages of the app lifecycle, the config API in the API holder will be\n * used.\n */\n config?: ConfigApi;\n\n /**\n * Allows for the binding of plugins' external route refs within the app.\n */\n bindRoutes?(context: { bind: CreateAppRouteBinder }): void;\n\n /**\n * Advanced, more rarely used options.\n */\n advanced?: {\n /**\n * A replacement API holder implementation to use.\n *\n * By default, a new API holder will be constructed automatically based on\n * the other inputs. If you pass in a custom one here, none of that\n * automation will take place - so you will have to take care to supply all\n * those APIs yourself.\n */\n apis?: ApiHolder;\n\n /**\n * If set to true, the system will silently accept and move on if\n * encountering config for extensions that do not exist. The default is to\n * reject such config to help catch simple mistakes.\n *\n * This flag can be useful in some scenarios where you have a dynamic set of\n * extensions enabled at different times, but also increases the risk of\n * accidentally missing e.g. simple typos in your config.\n */\n allowUnknownExtensionConfig?: boolean;\n\n /**\n * Applies one or more middleware on every extension, as they are added to\n * the application.\n *\n * This is an advanced use case for modifying extension data on the fly as\n * it gets emitted by extensions being instantiated.\n */\n extensionFactoryMiddleware?:\n | ExtensionFactoryMiddleware\n | ExtensionFactoryMiddleware[];\n\n /**\n * Allows for customizing how plugin info is retrieved.\n */\n pluginInfoResolver?: FrontendPluginInfoResolver;\n };\n};\n\n// Internal options type, not exported in the public API\nexport interface CreateSpecializedAppInternalOptions\n extends CreateSpecializedAppOptions {\n __internal?: {\n apiFactoryOverrides?: AnyApiFactory[];\n };\n}\n\n/**\n * Creates an empty app without any default features. This is a low-level API is\n * intended for use in tests or specialized setups. Typically you want to use\n * `createApp` from `@backstage/frontend-defaults` instead.\n *\n * @public\n */\nexport function createSpecializedApp(options?: CreateSpecializedAppOptions): {\n apis: ApiHolder;\n tree: AppTree;\n errors?: AppError[];\n} {\n const internalOptions = options as CreateSpecializedAppInternalOptions;\n const config = options?.config ?? new ConfigReader({}, 'empty-config');\n const features = deduplicateFeatures(options?.features ?? []).map(\n createPluginInfoAttacher(config, options?.advanced?.pluginInfoResolver),\n );\n\n const collector = createErrorCollector();\n\n const tree = resolveAppTree(\n 'root',\n resolveAppNodeSpecs({\n features,\n builtinExtensions: [\n resolveExtensionDefinition(Root, { namespace: 'root' }),\n ],\n parameters: readAppExtensionsConfig(config),\n forbidden: new Set(['root']),\n collector,\n }),\n collector,\n );\n\n const factories = createApiFactories({ tree, collector });\n const appBasePath = getBasePath(config);\n const appTreeApi = new AppTreeApiProxy(tree, appBasePath);\n\n const routeRefsById = collectRouteIds(features, collector);\n const routeResolutionApi = new RouteResolutionApiProxy(\n resolveRouteBindings(options?.bindRoutes, config, routeRefsById, collector),\n appBasePath,\n );\n\n const appIdentityProxy = new AppIdentityProxy();\n const apis =\n options?.advanced?.apis ??\n createApiHolder({\n factories,\n staticFactories: [\n createApiFactory(appTreeApiRef, appTreeApi),\n createApiFactory(configApiRef, config),\n createApiFactory(routeResolutionApiRef, routeResolutionApi),\n createApiFactory(identityApiRef, appIdentityProxy),\n ...(internalOptions?.__internal?.apiFactoryOverrides ?? []),\n ],\n });\n\n const featureFlagApi = apis.get(featureFlagsApiRef);\n if (featureFlagApi) {\n for (const feature of features) {\n if (OpaqueFrontendPlugin.isType(feature)) {\n OpaqueFrontendPlugin.toInternal(feature).featureFlags.forEach(flag =>\n featureFlagApi.registerFlag({\n name: flag.name,\n pluginId: feature.id,\n }),\n );\n }\n if (isInternalFrontendModule(feature)) {\n toInternalFrontendModule(feature).featureFlags.forEach(flag =>\n featureFlagApi.registerFlag({\n name: flag.name,\n pluginId: feature.pluginId,\n }),\n );\n }\n }\n }\n\n // Now instantiate the entire tree, which will skip anything that's already been instantiated\n instantiateAppNodeTree(\n tree.root,\n apis,\n collector,\n mergeExtensionFactoryMiddleware(\n options?.advanced?.extensionFactoryMiddleware,\n ),\n );\n\n const routeInfo = extractRouteInfoFromAppNode(\n tree.root,\n createRouteAliasResolver(routeRefsById),\n );\n\n routeResolutionApi.initialize(routeInfo, routeRefsById.routes);\n appTreeApi.initialize(routeInfo);\n\n return { apis, tree, errors: collector.collectErrors() };\n}\n\nfunction createApiFactories(options: {\n tree: AppTree;\n collector: ErrorCollector;\n}): AnyApiFactory[] {\n const emptyApiHolder = ApiRegistry.from([]);\n const factoriesById = new Map<\n string,\n { pluginId: string; factory: AnyApiFactory }\n >();\n\n for (const apiNode of options.tree.root.edges.attachments.get('apis') ?? []) {\n if (!instantiateAppNodeTree(apiNode, emptyApiHolder, options.collector)) {\n continue;\n }\n const apiFactory = apiNode.instance?.getData(ApiBlueprint.dataRefs.factory);\n if (apiFactory) {\n const apiRefId = apiFactory.api.id;\n const ownerId = getApiOwnerId(apiRefId);\n const pluginId = apiNode.spec.plugin.pluginId ?? 'app';\n const existingFactory = factoriesById.get(apiRefId);\n\n // This allows modules to override factories provided by the plugin, but\n // it rejects API overrides from other plugins. In the event of a\n // conflict, the owning plugin is attempted to be inferred from the API\n // reference ID.\n if (existingFactory && existingFactory.pluginId !== pluginId) {\n const shouldReplace =\n ownerId === pluginId && existingFactory.pluginId !== ownerId;\n const acceptedPluginId = shouldReplace\n ? pluginId\n : existingFactory.pluginId;\n const rejectedPluginId = shouldReplace\n ? existingFactory.pluginId\n : pluginId;\n\n options.collector.report({\n code: 'API_FACTORY_CONFLICT',\n message: `API '${apiRefId}' is already provided by plugin '${acceptedPluginId}', cannot also be provided by '${rejectedPluginId}'.`,\n context: {\n node: apiNode,\n apiRefId,\n pluginId: rejectedPluginId,\n existingPluginId: acceptedPluginId,\n },\n });\n if (shouldReplace) {\n factoriesById.set(apiRefId, {\n pluginId,\n factory: apiFactory,\n });\n }\n continue;\n }\n\n factoriesById.set(apiRefId, { pluginId, factory: apiFactory });\n } else {\n options.collector.report({\n code: 'API_EXTENSION_INVALID',\n message: `API extension '${apiNode.spec.id}' did not output an API factory`,\n context: {\n node: apiNode,\n },\n });\n }\n }\n\n return Array.from(factoriesById.values(), entry => entry.factory);\n}\n\n// TODO(Rugvip): It would be good if this was more explicit, but I think that\n// might need to wait for some future update for API factories.\nfunction getApiOwnerId(apiRefId: string): string {\n const [prefix, ...rest] = apiRefId.split('.');\n if (!prefix) {\n return apiRefId;\n }\n if (prefix === 'core') {\n return 'app';\n }\n if (prefix === 'plugin' && rest[0]) {\n return rest[0];\n }\n return prefix;\n}\n\nfunction createApiHolder(options: {\n factories: AnyApiFactory[];\n staticFactories: AnyApiFactory[];\n}): ApiHolder {\n const factoryRegistry = new ApiFactoryRegistry();\n\n for (const factory of options.factories.slice().reverse()) {\n factoryRegistry.register('default', factory);\n }\n\n for (const factory of options.staticFactories) {\n factoryRegistry.register('static', factory);\n }\n\n ApiResolver.validateFactories(factoryRegistry, factoryRegistry.getAllApis());\n\n return new ApiResolver(factoryRegistry);\n}\n\nfunction mergeExtensionFactoryMiddleware(\n middlewares?: ExtensionFactoryMiddleware | ExtensionFactoryMiddleware[],\n): ExtensionFactoryMiddleware | undefined {\n if (!middlewares) {\n return undefined;\n }\n if (!Array.isArray(middlewares)) {\n return middlewares;\n }\n if (middlewares.length <= 1) {\n return middlewares[0];\n }\n return middlewares.reduce((prev, next) => {\n if (!prev || !next) {\n return prev ?? next;\n }\n return (orig, ctx) => {\n const internalExt = toInternalExtension(ctx.node.spec.extension);\n if (internalExt.version !== 'v2') {\n return orig();\n }\n return next(ctxOverrides => {\n return createExtensionDataContainer(\n prev(orig, {\n node: ctx.node,\n apis: ctx.apis,\n config: ctxOverrides?.config ?? ctx.config,\n }),\n 'extension factory middleware',\n );\n }, ctx);\n };\n });\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/frontend-app-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0-next.2",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "web-library"
|
|
6
6
|
},
|
|
@@ -32,34 +32,34 @@
|
|
|
32
32
|
"test": "backstage-cli package test"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@backstage/config": "
|
|
36
|
-
"@backstage/core-app-api": "
|
|
37
|
-
"@backstage/core-plugin-api": "
|
|
38
|
-
"@backstage/errors": "
|
|
39
|
-
"@backstage/frontend-defaults": "
|
|
40
|
-
"@backstage/frontend-plugin-api": "
|
|
41
|
-
"@backstage/types": "
|
|
42
|
-
"@backstage/version-bridge": "
|
|
35
|
+
"@backstage/config": "1.3.6",
|
|
36
|
+
"@backstage/core-app-api": "1.19.5-next.1",
|
|
37
|
+
"@backstage/core-plugin-api": "1.12.3-next.1",
|
|
38
|
+
"@backstage/errors": "1.2.7",
|
|
39
|
+
"@backstage/frontend-defaults": "0.4.0-next.2",
|
|
40
|
+
"@backstage/frontend-plugin-api": "0.14.0-next.2",
|
|
41
|
+
"@backstage/types": "1.2.2",
|
|
42
|
+
"@backstage/version-bridge": "1.0.12-next.0",
|
|
43
43
|
"lodash": "^4.17.21",
|
|
44
44
|
"zod": "^3.25.76"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@backstage/cli": "
|
|
48
|
-
"@backstage/frontend-test-utils": "
|
|
49
|
-
"@backstage/plugin-app": "
|
|
50
|
-
"@backstage/test-utils": "
|
|
47
|
+
"@backstage/cli": "0.35.4-next.2",
|
|
48
|
+
"@backstage/frontend-test-utils": "0.5.0-next.2",
|
|
49
|
+
"@backstage/plugin-app": "0.4.0-next.2",
|
|
50
|
+
"@backstage/test-utils": "1.7.15-next.2",
|
|
51
51
|
"@testing-library/jest-dom": "^6.0.0",
|
|
52
52
|
"@testing-library/react": "^16.0.0",
|
|
53
53
|
"@types/react": "^18.0.0",
|
|
54
54
|
"react": "^18.0.2",
|
|
55
55
|
"react-dom": "^18.0.2",
|
|
56
|
-
"react-router-dom": "^6.
|
|
56
|
+
"react-router-dom": "^6.30.2"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@types/react": "^17.0.0 || ^18.0.0",
|
|
60
60
|
"react": "^17.0.0 || ^18.0.0",
|
|
61
61
|
"react-dom": "^17.0.0 || ^18.0.0",
|
|
62
|
-
"react-router-dom": "^6.
|
|
62
|
+
"react-router-dom": "^6.30.2"
|
|
63
63
|
},
|
|
64
64
|
"peerDependenciesMeta": {
|
|
65
65
|
"@types/react": {
|