@backstage/backend-test-utils 1.7.1-next.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/alpha/services/ActionsRegistryServiceMock.cjs.js.map +1 -1
  3. package/dist/alpha/services/ActionsServiceMock.cjs.js.map +1 -1
  4. package/dist/alpha/services/MockActionsRegistry.cjs.js.map +1 -1
  5. package/dist/alpha/services/simpleMock.cjs.js.map +1 -1
  6. package/dist/backend-app-api/src/lib/DependencyGraph.cjs.js.map +1 -1
  7. package/dist/backend-app-api/src/wiring/ServiceRegistry.cjs.js.map +1 -1
  8. package/dist/cache/TestCaches.cjs.js.map +1 -1
  9. package/dist/cache/memcache.cjs.js.map +1 -1
  10. package/dist/cache/redis.cjs.js.map +1 -1
  11. package/dist/cache/types.cjs.js.map +1 -1
  12. package/dist/cache/valkey.cjs.js.map +1 -1
  13. package/dist/database/TestDatabases.cjs.js.map +1 -1
  14. package/dist/database/mysql.cjs.js.map +1 -1
  15. package/dist/database/postgres.cjs.js.map +1 -1
  16. package/dist/database/sqlite.cjs.js.map +1 -1
  17. package/dist/database/types.cjs.js.map +1 -1
  18. package/dist/filesystem/MockDirectory.cjs.js.map +1 -1
  19. package/dist/index.d.ts +15 -4
  20. package/dist/msw/registerMswTestHooks.cjs.js.map +1 -1
  21. package/dist/services/MockAuthService.cjs.js.map +1 -1
  22. package/dist/services/MockEventsService.cjs.js.map +1 -1
  23. package/dist/services/MockHttpAuthService.cjs.js.map +1 -1
  24. package/dist/services/MockPermissionsService.cjs.js.map +1 -1
  25. package/dist/services/MockRootLoggerService.cjs.js.map +1 -1
  26. package/dist/services/MockSchedulerService.cjs.js +123 -0
  27. package/dist/services/MockSchedulerService.cjs.js.map +1 -0
  28. package/dist/services/MockUserInfoService.cjs.js.map +1 -1
  29. package/dist/services/mockCredentials.cjs.js.map +1 -1
  30. package/dist/services/mockServices.cjs.js +7 -3
  31. package/dist/services/mockServices.cjs.js.map +1 -1
  32. package/dist/services/simpleMock.cjs.js.map +1 -1
  33. package/dist/util/errorHandler.cjs.js +1 -1
  34. package/dist/util/errorHandler.cjs.js.map +1 -1
  35. package/dist/util/getDockerImageForName.cjs.js.map +1 -1
  36. package/dist/util/isDockerDisabledForTests.cjs.js.map +1 -1
  37. package/dist/wiring/ServiceFactoryTester.cjs.js.map +1 -1
  38. package/dist/wiring/TestBackend.cjs.js.map +1 -1
  39. package/package.json +11 -11
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @backstage/backend-test-utils
2
2
 
3
+ ## 1.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - dffaf70: Switched out `mockServices.scheduler` to use a mocked implementation instead of the default scheduler implementation. This implementation runs any scheduled tasks immediately on startup, as long as they don't have an initial delay or a manual trigger. After the initial run, the tasks are never run again unless manually triggered.
8
+
9
+ ### Patch Changes
10
+
11
+ - 279e1f7: Updated the type definition of `mockErrorHandler` to ensure that it is used correctly.
12
+
13
+ ```ts
14
+ // This is wrong and will now result in a type error
15
+ app.use(mockErrorHandler);
16
+
17
+ // This is the correct usage
18
+ app.use(mockErrorHandler());
19
+ ```
20
+
21
+ - 3a7dad9: Updated `better-sqlite3` to v12
22
+ - Updated dependencies
23
+ - @backstage/backend-defaults@0.12.0
24
+ - @backstage/backend-app-api@1.2.6
25
+ - @backstage/plugin-auth-node@0.6.6
26
+ - @backstage/backend-plugin-api@1.4.2
27
+ - @backstage/plugin-events-node@0.4.14
28
+
3
29
  ## 1.7.1-next.0
4
30
 
5
31
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"ActionsRegistryServiceMock.cjs.js","sources":["../../../src/alpha/services/ActionsRegistryServiceMock.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 */\nimport { mockServices } from '../../services';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { MockActionsRegistry } from './MockActionsRegistry';\nimport { simpleMock } from './simpleMock';\nimport {\n ActionsRegistryService,\n actionsRegistryServiceRef,\n} from '@backstage/backend-plugin-api/alpha';\nimport { actionsRegistryServiceFactory } from '@backstage/backend-defaults/alpha';\n\n/**\n * @alpha\n */\nexport function actionsRegistryServiceMock(options?: {\n logger: LoggerService;\n}): MockActionsRegistry {\n return MockActionsRegistry.create({\n logger: options?.logger ?? mockServices.logger.mock(),\n });\n}\n\n/**\n * @alpha\n */\nexport namespace actionsRegistryServiceMock {\n export const factory = () => actionsRegistryServiceFactory;\n\n export const mock = simpleMock<ActionsRegistryService>(\n actionsRegistryServiceRef,\n () => ({\n register: jest.fn(),\n }),\n );\n}\n"],"names":["MockActionsRegistry","mockServices","actionsRegistryServiceMock","actionsRegistryServiceFactory","simpleMock","actionsRegistryServiceRef"],"mappings":";;;;;;;;;AA4BO,SAAS,2BAA2B,OAEnB,EAAA;AACtB,EAAA,OAAOA,wCAAoB,MAAO,CAAA;AAAA,IAChC,MAAQ,EAAA,OAAA,EAAS,MAAU,IAAAC,yBAAA,CAAa,OAAO,IAAK;AAAA,GACrD,CAAA;AACH;AAAA,CAKO,CAAUC,2BAAV,KAAA;AACE,EAAMA,2BAAAA,CAAA,UAAU,MAAMC,mCAAA;AAEtB,EAAMD,4BAAA,IAAO,GAAAE,qBAAA;AAAA,IAClBC,iCAAA;AAAA,IACA,OAAO;AAAA,MACL,QAAA,EAAU,KAAK,EAAG;AAAA,KACpB;AAAA,GACF;AAAA,CARe,EAAA,0BAAA,KAAA,0BAAA,GAAA,EAAA,CAAA,CAAA;;;;"}
1
+ {"version":3,"file":"ActionsRegistryServiceMock.cjs.js","sources":["../../../src/alpha/services/ActionsRegistryServiceMock.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 */\nimport { mockServices } from '../../services';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { MockActionsRegistry } from './MockActionsRegistry';\nimport { simpleMock } from './simpleMock';\nimport {\n ActionsRegistryService,\n actionsRegistryServiceRef,\n} from '@backstage/backend-plugin-api/alpha';\nimport { actionsRegistryServiceFactory } from '@backstage/backend-defaults/alpha';\n\n/**\n * @alpha\n */\nexport function actionsRegistryServiceMock(options?: {\n logger: LoggerService;\n}): MockActionsRegistry {\n return MockActionsRegistry.create({\n logger: options?.logger ?? mockServices.logger.mock(),\n });\n}\n\n/**\n * @alpha\n */\nexport namespace actionsRegistryServiceMock {\n export const factory = () => actionsRegistryServiceFactory;\n\n export const mock = simpleMock<ActionsRegistryService>(\n actionsRegistryServiceRef,\n () => ({\n register: jest.fn(),\n }),\n );\n}\n"],"names":["MockActionsRegistry","mockServices","actionsRegistryServiceMock","actionsRegistryServiceFactory","simpleMock","actionsRegistryServiceRef"],"mappings":";;;;;;;;;AA4BO,SAAS,2BAA2B,OAAA,EAEnB;AACtB,EAAA,OAAOA,wCAAoB,MAAA,CAAO;AAAA,IAChC,MAAA,EAAQ,OAAA,EAAS,MAAA,IAAUC,yBAAA,CAAa,OAAO,IAAA;AAAK,GACrD,CAAA;AACH;AAAA,CAKO,CAAUC,2BAAAA,KAAV;AACE,EAAMA,2BAAAA,CAAA,UAAU,MAAMC,mCAAA;AAEtB,EAAMD,4BAAA,IAAA,GAAOE,qBAAA;AAAA,IAClBC,iCAAA;AAAA,IACA,OAAO;AAAA,MACL,QAAA,EAAU,KAAK,EAAA;AAAG,KACpB;AAAA,GACF;AAAA,CAAA,EARe,0BAAA,KAAA,0BAAA,GAAA,EAAA,CAAA,CAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"ActionsServiceMock.cjs.js","sources":["../../../src/alpha/services/ActionsServiceMock.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 { simpleMock } from './simpleMock';\nimport {\n ActionsService,\n actionsServiceRef,\n} from '@backstage/backend-plugin-api/alpha';\nimport { actionsServiceFactory } from '@backstage/backend-defaults/alpha';\n\n/**\n * @alpha\n */\nexport namespace actionsServiceMock {\n export const factory = () => actionsServiceFactory;\n\n export const mock = simpleMock<ActionsService>(actionsServiceRef, () => ({\n invoke: jest.fn(),\n list: jest.fn(),\n }));\n}\n"],"names":["actionsServiceMock","actionsServiceFactory","simpleMock","actionsServiceRef"],"mappings":";;;;;;AA0BiBA;AAAA,CAAV,CAAUA,mBAAV,KAAA;AACE,EAAMA,mBAAAA,CAAA,UAAU,MAAMC,2BAAA;AAEtB,EAAMD,mBAAA,CAAA,IAAA,GAAOE,qBAA2B,CAAAC,yBAAA,EAAmB,OAAO;AAAA,IACvE,MAAA,EAAQ,KAAK,EAAG,EAAA;AAAA,IAChB,IAAA,EAAM,KAAK,EAAG;AAAA,GACd,CAAA,CAAA;AAAA,CANa,EAAAH,0BAAA,KAAAA,0BAAA,GAAA,EAAA,CAAA,CAAA;;"}
1
+ {"version":3,"file":"ActionsServiceMock.cjs.js","sources":["../../../src/alpha/services/ActionsServiceMock.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 { simpleMock } from './simpleMock';\nimport {\n ActionsService,\n actionsServiceRef,\n} from '@backstage/backend-plugin-api/alpha';\nimport { actionsServiceFactory } from '@backstage/backend-defaults/alpha';\n\n/**\n * @alpha\n */\nexport namespace actionsServiceMock {\n export const factory = () => actionsServiceFactory;\n\n export const mock = simpleMock<ActionsService>(actionsServiceRef, () => ({\n invoke: jest.fn(),\n list: jest.fn(),\n }));\n}\n"],"names":["actionsServiceMock","actionsServiceFactory","simpleMock","actionsServiceRef"],"mappings":";;;;;;AA0BiBA;AAAA,CAAV,CAAUA,mBAAAA,KAAV;AACE,EAAMA,mBAAAA,CAAA,UAAU,MAAMC,2BAAA;AAEtB,EAAMD,mBAAAA,CAAA,IAAA,GAAOE,qBAAA,CAA2BC,yBAAA,EAAmB,OAAO;AAAA,IACvE,MAAA,EAAQ,KAAK,EAAA,EAAG;AAAA,IAChB,IAAA,EAAM,KAAK,EAAA;AAAG,GAChB,CAAE,CAAA;AAAA,CAAA,EANaH,0BAAA,KAAAA,0BAAA,GAAA,EAAA,CAAA,CAAA;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"MockActionsRegistry.cjs.js","sources":["../../../src/alpha/services/MockActionsRegistry.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 */\nimport {\n BackstageCredentials,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { ForwardedError, InputError, NotFoundError } from '@backstage/errors';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport { z, AnyZodObject } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { mockCredentials } from '../../services';\nimport {\n ActionsRegistryActionOptions,\n ActionsRegistryService,\n ActionsService,\n ActionsServiceAction,\n} from '@backstage/backend-plugin-api/alpha';\n\n/**\n * A mock implementation of the ActionsRegistryService and ActionsService that can be used in tests.\n *\n * This is useful for testing actions that are registered with the ActionsRegistryService and ActionsService.\n *\n * The plugin ID is hardcoded to `testing` in the mock implementation.\n *\n * @example\n * ```ts\n * const actionsRegistry = mockServices.actionsRegistry();\n *\n * actionsRegistry.register({\n * name: 'test',\n * title: 'Test',\n * description: 'Test',\n * schema: {\n * input: z.object({ name: z.string() }),\n * output: z.object({ name: z.string() }),\n * },\n * action: async ({ input }) => ({ output: { name: input.name } }),\n * });\n *\n *\n * const result = await actionsRegistry.invoke({\n * id: 'testing:test',\n * input: { name: 'test' },\n * });\n *\n * expect(result).toEqual({ output: { name: 'test' } });\n * ```\n *\n * @alpha\n */\nexport class MockActionsRegistry\n implements ActionsRegistryService, ActionsService\n{\n private constructor(private readonly logger: LoggerService) {}\n\n static create(opts: { logger: LoggerService }) {\n return new MockActionsRegistry(opts.logger);\n }\n\n readonly actions: Map<string, ActionsRegistryActionOptions<any, any>> =\n new Map();\n\n async list(): Promise<{ actions: ActionsServiceAction[] }> {\n return {\n actions: Array.from(this.actions.entries()).map(([id, action]) => ({\n id,\n name: action.name,\n title: action.title,\n description: action.description,\n attributes: {\n destructive: action.attributes?.destructive ?? true,\n idempotent: action.attributes?.idempotent ?? false,\n readOnly: action.attributes?.readOnly ?? false,\n },\n schema: {\n input: action.schema?.input\n ? zodToJsonSchema(action.schema.input(z))\n : zodToJsonSchema(z.object({})),\n output: action.schema?.output\n ? zodToJsonSchema(action.schema.output(z))\n : zodToJsonSchema(z.object({})),\n } as ActionsServiceAction['schema'],\n })),\n };\n }\n\n async invoke(opts: {\n id: string;\n input?: JsonObject;\n credentials?: BackstageCredentials;\n }): Promise<{ output: JsonValue }> {\n const action = this.actions.get(opts.id);\n\n if (!action) {\n const availableActionIds = Array.from(this.actions.keys()).join(', ');\n throw new NotFoundError(\n `Action \"${opts.id}\" not found, available actions: ${\n availableActionIds ? `\"${availableActionIds}\"` : 'none'\n }`,\n );\n }\n\n const input = action.schema?.input\n ? action.schema.input(z).safeParse(opts.input)\n : ({ success: true, data: undefined } as const);\n\n if (!input.success) {\n throw new InputError(`Invalid input to action \"${opts.id}\"`, input.error);\n }\n\n try {\n const result = await action.action({\n input: input.data,\n credentials: opts.credentials ?? mockCredentials.none(),\n logger: this.logger,\n });\n\n const output = action.schema?.output\n ? action.schema.output(z).safeParse(result?.output)\n : ({ success: true, data: result?.output } as const);\n\n if (!output.success) {\n throw new InputError(\n `Invalid output from action \"${opts.id}\"`,\n output.error,\n );\n }\n\n return { output: output.data };\n } catch (error) {\n throw new ForwardedError(\n `Failed execution of action \"${opts.id}\"`,\n error,\n );\n }\n }\n\n register<\n TInputSchema extends AnyZodObject,\n TOutputSchema extends AnyZodObject,\n >(options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>): void {\n // hardcode test: prefix similar to how the default actions registry does it\n // and other places around the testing ecosystem:\n // https://github.com/backstage/backstage/blob/a9219496d5c073aaa0b8caf32ece10455cf65e61/packages/backend-test-utils/src/next/services/mockServices.ts#L321\n // https://github.com/backstage/backstage/blob/861f162b4a39117b824669d67a951ed1db142e3d/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts#L99\n const id = `test:${options.name}`;\n\n if (this.actions.has(id)) {\n throw new Error(`Action with id \"${id}\" is already registered`);\n }\n\n this.actions.set(id, options);\n }\n}\n"],"names":["zodToJsonSchema","z","NotFoundError","InputError","mockCredentials","ForwardedError"],"mappings":";;;;;;;;;;;;AAgEO,MAAM,mBAEb,CAAA;AAAA,EACU,YAA6B,MAAuB,EAAA;AAAvB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA;AAAwB,EAE7D,OAAO,OAAO,IAAiC,EAAA;AAC7C,IAAO,OAAA,IAAI,mBAAoB,CAAA,IAAA,CAAK,MAAM,CAAA;AAAA;AAC5C,EAES,OAAA,uBACH,GAAI,EAAA;AAAA,EAEV,MAAM,IAAqD,GAAA;AACzD,IAAO,OAAA;AAAA,MACL,OAAS,EAAA,KAAA,CAAM,IAAK,CAAA,IAAA,CAAK,OAAQ,CAAA,OAAA,EAAS,CAAA,CAAE,GAAI,CAAA,CAAC,CAAC,EAAA,EAAI,MAAM,CAAO,MAAA;AAAA,QACjE,EAAA;AAAA,QACA,MAAM,MAAO,CAAA,IAAA;AAAA,QACb,OAAO,MAAO,CAAA,KAAA;AAAA,QACd,aAAa,MAAO,CAAA,WAAA;AAAA,QACpB,UAAY,EAAA;AAAA,UACV,WAAA,EAAa,MAAO,CAAA,UAAA,EAAY,WAAe,IAAA,IAAA;AAAA,UAC/C,UAAA,EAAY,MAAO,CAAA,UAAA,EAAY,UAAc,IAAA,KAAA;AAAA,UAC7C,QAAA,EAAU,MAAO,CAAA,UAAA,EAAY,QAAY,IAAA;AAAA,SAC3C;AAAA,QACA,MAAQ,EAAA;AAAA,UACN,OAAO,MAAO,CAAA,MAAA,EAAQ,KAClB,GAAAA,gCAAA,CAAgB,OAAO,MAAO,CAAA,KAAA,CAAMC,KAAC,CAAC,IACtCD,gCAAgB,CAAAC,KAAA,CAAE,MAAO,CAAA,EAAE,CAAC,CAAA;AAAA,UAChC,QAAQ,MAAO,CAAA,MAAA,EAAQ,MACnB,GAAAD,gCAAA,CAAgB,OAAO,MAAO,CAAA,MAAA,CAAOC,KAAC,CAAC,IACvCD,gCAAgB,CAAAC,KAAA,CAAE,MAAO,CAAA,EAAE,CAAC;AAAA;AAClC,OACA,CAAA;AAAA,KACJ;AAAA;AACF,EAEA,MAAM,OAAO,IAIsB,EAAA;AACjC,IAAA,MAAM,MAAS,GAAA,IAAA,CAAK,OAAQ,CAAA,GAAA,CAAI,KAAK,EAAE,CAAA;AAEvC,IAAA,IAAI,CAAC,MAAQ,EAAA;AACX,MAAM,MAAA,kBAAA,GAAqB,MAAM,IAAK,CAAA,IAAA,CAAK,QAAQ,IAAK,EAAC,CAAE,CAAA,IAAA,CAAK,IAAI,CAAA;AACpE,MAAA,MAAM,IAAIC,oBAAA;AAAA,QACR,CAAA,QAAA,EAAW,KAAK,EAAE,CAAA,gCAAA,EAChB,qBAAqB,CAAI,CAAA,EAAA,kBAAkB,MAAM,MACnD,CAAA;AAAA,OACF;AAAA;AAGF,IAAA,MAAM,QAAQ,MAAO,CAAA,MAAA,EAAQ,KACzB,GAAA,MAAA,CAAO,OAAO,KAAM,CAAAD,KAAC,CAAE,CAAA,SAAA,CAAU,KAAK,KAAK,CAAA,GAC1C,EAAE,OAAS,EAAA,IAAA,EAAM,MAAM,KAAU,CAAA,EAAA;AAEtC,IAAI,IAAA,CAAC,MAAM,OAAS,EAAA;AAClB,MAAA,MAAM,IAAIE,iBAAW,CAAA,CAAA,yBAAA,EAA4B,KAAK,EAAE,CAAA,CAAA,CAAA,EAAK,MAAM,KAAK,CAAA;AAAA;AAG1E,IAAI,IAAA;AACF,MAAM,MAAA,MAAA,GAAS,MAAM,MAAA,CAAO,MAAO,CAAA;AAAA,QACjC,OAAO,KAAM,CAAA,IAAA;AAAA,QACb,WAAa,EAAA,IAAA,CAAK,WAAe,IAAAC,+BAAA,CAAgB,IAAK,EAAA;AAAA,QACtD,QAAQ,IAAK,CAAA;AAAA,OACd,CAAA;AAED,MAAA,MAAM,SAAS,MAAO,CAAA,MAAA,EAAQ,SAC1B,MAAO,CAAA,MAAA,CAAO,OAAOH,KAAC,CAAA,CAAE,SAAU,CAAA,MAAA,EAAQ,MAAM,CAC/C,GAAA,EAAE,SAAS,IAAM,EAAA,IAAA,EAAM,QAAQ,MAAO,EAAA;AAE3C,MAAI,IAAA,CAAC,OAAO,OAAS,EAAA;AACnB,QAAA,MAAM,IAAIE,iBAAA;AAAA,UACR,CAAA,4BAAA,EAA+B,KAAK,EAAE,CAAA,CAAA,CAAA;AAAA,UACtC,MAAO,CAAA;AAAA,SACT;AAAA;AAGF,MAAO,OAAA,EAAE,MAAQ,EAAA,MAAA,CAAO,IAAK,EAAA;AAAA,aACtB,KAAO,EAAA;AACd,MAAA,MAAM,IAAIE,qBAAA;AAAA,QACR,CAAA,4BAAA,EAA+B,KAAK,EAAE,CAAA,CAAA,CAAA;AAAA,QACtC;AAAA,OACF;AAAA;AACF;AACF,EAEA,SAGE,OAA0E,EAAA;AAK1E,IAAM,MAAA,EAAA,GAAK,CAAQ,KAAA,EAAA,OAAA,CAAQ,IAAI,CAAA,CAAA;AAE/B,IAAA,IAAI,IAAK,CAAA,OAAA,CAAQ,GAAI,CAAA,EAAE,CAAG,EAAA;AACxB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAmB,gBAAA,EAAA,EAAE,CAAyB,uBAAA,CAAA,CAAA;AAAA;AAGhE,IAAK,IAAA,CAAA,OAAA,CAAQ,GAAI,CAAA,EAAA,EAAI,OAAO,CAAA;AAAA;AAEhC;;;;"}
1
+ {"version":3,"file":"MockActionsRegistry.cjs.js","sources":["../../../src/alpha/services/MockActionsRegistry.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 */\nimport {\n BackstageCredentials,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { ForwardedError, InputError, NotFoundError } from '@backstage/errors';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport { z, AnyZodObject } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { mockCredentials } from '../../services';\nimport {\n ActionsRegistryActionOptions,\n ActionsRegistryService,\n ActionsService,\n ActionsServiceAction,\n} from '@backstage/backend-plugin-api/alpha';\n\n/**\n * A mock implementation of the ActionsRegistryService and ActionsService that can be used in tests.\n *\n * This is useful for testing actions that are registered with the ActionsRegistryService and ActionsService.\n *\n * The plugin ID is hardcoded to `testing` in the mock implementation.\n *\n * @example\n * ```ts\n * const actionsRegistry = mockServices.actionsRegistry();\n *\n * actionsRegistry.register({\n * name: 'test',\n * title: 'Test',\n * description: 'Test',\n * schema: {\n * input: z.object({ name: z.string() }),\n * output: z.object({ name: z.string() }),\n * },\n * action: async ({ input }) => ({ output: { name: input.name } }),\n * });\n *\n *\n * const result = await actionsRegistry.invoke({\n * id: 'testing:test',\n * input: { name: 'test' },\n * });\n *\n * expect(result).toEqual({ output: { name: 'test' } });\n * ```\n *\n * @alpha\n */\nexport class MockActionsRegistry\n implements ActionsRegistryService, ActionsService\n{\n private constructor(private readonly logger: LoggerService) {}\n\n static create(opts: { logger: LoggerService }) {\n return new MockActionsRegistry(opts.logger);\n }\n\n readonly actions: Map<string, ActionsRegistryActionOptions<any, any>> =\n new Map();\n\n async list(): Promise<{ actions: ActionsServiceAction[] }> {\n return {\n actions: Array.from(this.actions.entries()).map(([id, action]) => ({\n id,\n name: action.name,\n title: action.title,\n description: action.description,\n attributes: {\n destructive: action.attributes?.destructive ?? true,\n idempotent: action.attributes?.idempotent ?? false,\n readOnly: action.attributes?.readOnly ?? false,\n },\n schema: {\n input: action.schema?.input\n ? zodToJsonSchema(action.schema.input(z))\n : zodToJsonSchema(z.object({})),\n output: action.schema?.output\n ? zodToJsonSchema(action.schema.output(z))\n : zodToJsonSchema(z.object({})),\n } as ActionsServiceAction['schema'],\n })),\n };\n }\n\n async invoke(opts: {\n id: string;\n input?: JsonObject;\n credentials?: BackstageCredentials;\n }): Promise<{ output: JsonValue }> {\n const action = this.actions.get(opts.id);\n\n if (!action) {\n const availableActionIds = Array.from(this.actions.keys()).join(', ');\n throw new NotFoundError(\n `Action \"${opts.id}\" not found, available actions: ${\n availableActionIds ? `\"${availableActionIds}\"` : 'none'\n }`,\n );\n }\n\n const input = action.schema?.input\n ? action.schema.input(z).safeParse(opts.input)\n : ({ success: true, data: undefined } as const);\n\n if (!input.success) {\n throw new InputError(`Invalid input to action \"${opts.id}\"`, input.error);\n }\n\n try {\n const result = await action.action({\n input: input.data,\n credentials: opts.credentials ?? mockCredentials.none(),\n logger: this.logger,\n });\n\n const output = action.schema?.output\n ? action.schema.output(z).safeParse(result?.output)\n : ({ success: true, data: result?.output } as const);\n\n if (!output.success) {\n throw new InputError(\n `Invalid output from action \"${opts.id}\"`,\n output.error,\n );\n }\n\n return { output: output.data };\n } catch (error) {\n throw new ForwardedError(\n `Failed execution of action \"${opts.id}\"`,\n error,\n );\n }\n }\n\n register<\n TInputSchema extends AnyZodObject,\n TOutputSchema extends AnyZodObject,\n >(options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>): void {\n // hardcode test: prefix similar to how the default actions registry does it\n // and other places around the testing ecosystem:\n // https://github.com/backstage/backstage/blob/a9219496d5c073aaa0b8caf32ece10455cf65e61/packages/backend-test-utils/src/next/services/mockServices.ts#L321\n // https://github.com/backstage/backstage/blob/861f162b4a39117b824669d67a951ed1db142e3d/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts#L99\n const id = `test:${options.name}`;\n\n if (this.actions.has(id)) {\n throw new Error(`Action with id \"${id}\" is already registered`);\n }\n\n this.actions.set(id, options);\n }\n}\n"],"names":["zodToJsonSchema","z","NotFoundError","InputError","mockCredentials","ForwardedError"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"simpleMock.cjs.js","sources":["../../../src/alpha/services/simpleMock.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 */\nimport {\n createServiceFactory,\n ServiceFactory,\n ServiceRef,\n} from '@backstage/backend-plugin-api';\n\n/** @alpha */\nexport type ServiceMock<TService> = {\n factory: ServiceFactory<TService>;\n} & {\n [Key in keyof TService]: TService[Key] extends (\n ...args: infer Args\n ) => infer Return\n ? TService[Key] & jest.MockInstance<Return, Args>\n : TService[Key];\n};\n\n/** @internal */\nexport function simpleMock<TService>(\n ref: ServiceRef<TService, any>,\n mockFactory: () => jest.Mocked<TService>,\n): (partialImpl?: Partial<TService>) => ServiceMock<TService> {\n return partialImpl => {\n const mock = mockFactory();\n if (partialImpl) {\n for (const [key, impl] of Object.entries(partialImpl)) {\n if (typeof impl === 'function') {\n (mock as any)[key].mockImplementation(impl);\n } else {\n (mock as any)[key] = impl;\n }\n }\n }\n return Object.assign(mock, {\n factory: createServiceFactory({\n service: ref,\n deps: {},\n factory: () => mock,\n }),\n }) as ServiceMock<TService>;\n };\n}\n"],"names":["createServiceFactory"],"mappings":";;;;AAiCgB,SAAA,UAAA,CACd,KACA,WAC4D,EAAA;AAC5D,EAAA,OAAO,CAAe,WAAA,KAAA;AACpB,IAAA,MAAM,OAAO,WAAY,EAAA;AACzB,IAAA,IAAI,WAAa,EAAA;AACf,MAAA,KAAA,MAAW,CAAC,GAAK,EAAA,IAAI,KAAK,MAAO,CAAA,OAAA,CAAQ,WAAW,CAAG,EAAA;AACrD,QAAI,IAAA,OAAO,SAAS,UAAY,EAAA;AAC9B,UAAC,IAAa,CAAA,GAAG,CAAE,CAAA,kBAAA,CAAmB,IAAI,CAAA;AAAA,SACrC,MAAA;AACL,UAAC,IAAA,CAAa,GAAG,CAAI,GAAA,IAAA;AAAA;AACvB;AACF;AAEF,IAAO,OAAA,MAAA,CAAO,OAAO,IAAM,EAAA;AAAA,MACzB,SAASA,qCAAqB,CAAA;AAAA,QAC5B,OAAS,EAAA,GAAA;AAAA,QACT,MAAM,EAAC;AAAA,QACP,SAAS,MAAM;AAAA,OAChB;AAAA,KACF,CAAA;AAAA,GACH;AACF;;;;"}
1
+ {"version":3,"file":"simpleMock.cjs.js","sources":["../../../src/alpha/services/simpleMock.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 */\nimport {\n createServiceFactory,\n ServiceFactory,\n ServiceRef,\n} from '@backstage/backend-plugin-api';\n\n/** @alpha */\nexport type ServiceMock<TService> = {\n factory: ServiceFactory<TService>;\n} & {\n [Key in keyof TService]: TService[Key] extends (\n ...args: infer Args\n ) => infer Return\n ? TService[Key] & jest.MockInstance<Return, Args>\n : TService[Key];\n};\n\n/** @internal */\nexport function simpleMock<TService>(\n ref: ServiceRef<TService, any>,\n mockFactory: () => jest.Mocked<TService>,\n): (partialImpl?: Partial<TService>) => ServiceMock<TService> {\n return partialImpl => {\n const mock = mockFactory();\n if (partialImpl) {\n for (const [key, impl] of Object.entries(partialImpl)) {\n if (typeof impl === 'function') {\n (mock as any)[key].mockImplementation(impl);\n } else {\n (mock as any)[key] = impl;\n }\n }\n }\n return Object.assign(mock, {\n factory: createServiceFactory({\n service: ref,\n deps: {},\n factory: () => mock,\n }),\n }) as ServiceMock<TService>;\n };\n}\n"],"names":["createServiceFactory"],"mappings":";;;;AAiCO,SAAS,UAAA,CACd,KACA,WAAA,EAC4D;AAC5D,EAAA,OAAO,CAAA,WAAA,KAAe;AACpB,IAAA,MAAM,OAAO,WAAA,EAAY;AACzB,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,KAAA,MAAW,CAAC,GAAA,EAAK,IAAI,KAAK,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,EAAG;AACrD,QAAA,IAAI,OAAO,SAAS,UAAA,EAAY;AAC9B,UAAC,IAAA,CAAa,GAAG,CAAA,CAAE,kBAAA,CAAmB,IAAI,CAAA;AAAA,QAC5C,CAAA,MAAO;AACL,UAAC,IAAA,CAAa,GAAG,CAAA,GAAI,IAAA;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AACA,IAAA,OAAO,MAAA,CAAO,OAAO,IAAA,EAAM;AAAA,MACzB,SAASA,qCAAA,CAAqB;AAAA,QAC5B,OAAA,EAAS,GAAA;AAAA,QACT,MAAM,EAAC;AAAA,QACP,SAAS,MAAM;AAAA,OAChB;AAAA,KACF,CAAA;AAAA,EACH,CAAA;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"DependencyGraph.cjs.js","sources":["../../../../../backend-app-api/src/lib/DependencyGraph.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\ninterface NodeInput<T> {\n value: T;\n consumes?: Iterable<string>;\n provides?: Iterable<string>;\n}\n\n/** @internal */\nclass Node<T> {\n static from<T>(input: NodeInput<T>) {\n return new Node<T>(\n input.value,\n input.consumes ? new Set(input.consumes) : new Set(),\n input.provides ? new Set(input.provides) : new Set(),\n );\n }\n\n private constructor(\n readonly value: T,\n readonly consumes: Set<string>,\n readonly provides: Set<string>,\n ) {}\n}\n\n/** @internal */\nclass CycleKeySet<T> {\n static from<T>(nodes: Array<Node<T>>) {\n return new CycleKeySet<T>(nodes);\n }\n\n #nodeIds: Map<T, number>;\n #cycleKeys: Set<string>;\n\n private constructor(nodes: Array<Node<T>>) {\n this.#nodeIds = new Map(nodes.map((n, i) => [n.value, i]));\n this.#cycleKeys = new Set<string>();\n }\n\n tryAdd(path: T[]): boolean {\n const cycleKey = this.#getCycleKey(path);\n if (this.#cycleKeys.has(cycleKey)) {\n return false;\n }\n this.#cycleKeys.add(cycleKey);\n return true;\n }\n\n #getCycleKey(path: T[]): string {\n return path\n .map(n => this.#nodeIds.get(n)!)\n .sort()\n .join(',');\n }\n}\n\n/**\n * Internal helper to help validate and traverse a dependency graph.\n * @internal\n */\nexport class DependencyGraph<T> {\n static fromMap(\n nodes: Record<string, Omit<NodeInput<unknown>, 'value'>>,\n ): DependencyGraph<string> {\n return this.fromIterable(\n Object.entries(nodes).map(([key, node]) => ({\n value: String(key),\n ...node,\n })),\n );\n }\n\n static fromIterable<T>(\n nodeInputs: Iterable<NodeInput<T>>,\n ): DependencyGraph<T> {\n const nodes = new Array<Node<T>>();\n for (const nodeInput of nodeInputs) {\n nodes.push(Node.from(nodeInput));\n }\n\n return new DependencyGraph(nodes);\n }\n\n #nodes: Array<Node<T>>;\n #allProvided: Set<string>;\n\n private constructor(nodes: Array<Node<T>>) {\n this.#nodes = nodes;\n this.#allProvided = new Set();\n\n for (const node of this.#nodes.values()) {\n for (const produced of node.provides) {\n this.#allProvided.add(produced);\n }\n }\n }\n\n /**\n * Find all nodes that consume dependencies that are not provided by any other node.\n */\n findUnsatisfiedDeps(): Array<{ value: T; unsatisfied: string[] }> {\n const unsatisfiedDependencies = [];\n for (const node of this.#nodes.values()) {\n const unsatisfied = Array.from(node.consumes).filter(\n id => !this.#allProvided.has(id),\n );\n if (unsatisfied.length > 0) {\n unsatisfiedDependencies.push({ value: node.value, unsatisfied });\n }\n }\n return unsatisfiedDependencies;\n }\n\n /**\n * Detect the first circular dependency within the graph, returning the path of nodes that\n * form a cycle, with the same node as the first and last element of the array.\n */\n detectCircularDependency(): T[] | undefined {\n return this.detectCircularDependencies().next().value;\n }\n\n /**\n * Detect circular dependencies within the graph, returning the path of nodes that\n * form a cycle, with the same node as the first and last element of the array.\n */\n *detectCircularDependencies(): Generator<T[], undefined> {\n const cycleKeys = CycleKeySet.from(this.#nodes);\n\n for (const startNode of this.#nodes) {\n const visited = new Set<Node<T>>();\n const stack = new Array<[node: Node<T>, path: T[]]>([\n startNode,\n [startNode.value],\n ]);\n\n while (stack.length > 0) {\n const [node, path] = stack.pop()!;\n if (visited.has(node)) {\n continue;\n }\n visited.add(node);\n for (const consumed of node.consumes) {\n const providerNodes = this.#nodes.filter(other =>\n other.provides.has(consumed),\n );\n for (const provider of providerNodes) {\n if (provider === startNode) {\n if (cycleKeys.tryAdd(path)) {\n yield [...path, startNode.value];\n }\n\n break;\n }\n if (!visited.has(provider)) {\n stack.push([provider, [...path, provider.value]]);\n }\n }\n }\n }\n }\n return undefined;\n }\n\n /**\n * Traverses the dependency graph in topological order, calling the provided\n * function for each node and waiting for it to resolve.\n *\n * The nodes are traversed in parallel, but in such a way that no node is\n * visited before all of its dependencies.\n *\n * Dependencies of nodes that are not produced by any other nodes will be ignored.\n */\n async parallelTopologicalTraversal<TResult>(\n fn: (value: T) => Promise<TResult>,\n ): Promise<TResult[]> {\n const allProvided = this.#allProvided;\n const waiting = new Set(this.#nodes.values());\n const visited = new Set<Node<T>>();\n const results = new Array<TResult>();\n let inFlight = 0; // Keep track of how many callbacks are in flight, so that we know if we got stuck\n\n // This keeps track of a counter of how many providers there are still left\n // to be visited for each dependency. This needs to be a counter instead of\n // a flag for the special case where there are several providers of a given\n // value, even though there may be only one consumer of it.\n const producedRemaining = new Map<string, number>();\n for (const node of this.#nodes) {\n for (const provided of node.provides) {\n producedRemaining.set(\n provided,\n (producedRemaining.get(provided) ?? 0) + 1,\n );\n }\n }\n\n // Find all nodes that have no dependencies that have not already been produced by visited nodes\n async function processMoreNodes() {\n if (waiting.size === 0) {\n return;\n }\n const nodesToProcess = [];\n for (const node of waiting) {\n let ready = true;\n for (const consumed of node.consumes) {\n if (\n allProvided.has(consumed) &&\n producedRemaining.get(consumed) !== 0\n ) {\n ready = false;\n continue;\n }\n }\n if (ready) {\n nodesToProcess.push(node);\n }\n }\n\n for (const node of nodesToProcess) {\n waiting.delete(node);\n }\n\n if (nodesToProcess.length === 0 && inFlight === 0) {\n // We expect the caller to check for circular dependencies before\n // traversal, so this error should never happen\n throw new Error('Circular dependency detected');\n }\n\n await Promise.all(nodesToProcess.map(processNode));\n }\n\n // Process an individual node, and then add its produced dependencies to the set of available products\n async function processNode(node: Node<T>) {\n visited.add(node);\n inFlight += 1;\n\n const result = await fn(node.value);\n results.push(result);\n\n node.provides.forEach(produced => {\n const remaining = producedRemaining.get(produced);\n if (!remaining) {\n // This should be impossible, if the code that generates the map is correct\n throw new Error(\n `Internal error: Node provided superfluous dependency '${produced}'`,\n );\n }\n producedRemaining.set(produced, remaining - 1);\n });\n\n inFlight -= 1;\n await processMoreNodes();\n }\n\n await processMoreNodes();\n\n return results;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DependencyGraph.cjs.js","sources":["../../../../../backend-app-api/src/lib/DependencyGraph.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\ninterface NodeInput<T> {\n value: T;\n consumes?: Iterable<string>;\n provides?: Iterable<string>;\n}\n\n/** @internal */\nclass Node<T> {\n static from<T>(input: NodeInput<T>) {\n return new Node<T>(\n input.value,\n input.consumes ? new Set(input.consumes) : new Set(),\n input.provides ? new Set(input.provides) : new Set(),\n );\n }\n\n private constructor(\n readonly value: T,\n readonly consumes: Set<string>,\n readonly provides: Set<string>,\n ) {}\n}\n\n/** @internal */\nclass CycleKeySet<T> {\n static from<T>(nodes: Array<Node<T>>) {\n return new CycleKeySet<T>(nodes);\n }\n\n #nodeIds: Map<T, number>;\n #cycleKeys: Set<string>;\n\n private constructor(nodes: Array<Node<T>>) {\n this.#nodeIds = new Map(nodes.map((n, i) => [n.value, i]));\n this.#cycleKeys = new Set<string>();\n }\n\n tryAdd(path: T[]): boolean {\n const cycleKey = this.#getCycleKey(path);\n if (this.#cycleKeys.has(cycleKey)) {\n return false;\n }\n this.#cycleKeys.add(cycleKey);\n return true;\n }\n\n #getCycleKey(path: T[]): string {\n return path\n .map(n => this.#nodeIds.get(n)!)\n .sort()\n .join(',');\n }\n}\n\n/**\n * Internal helper to help validate and traverse a dependency graph.\n * @internal\n */\nexport class DependencyGraph<T> {\n static fromMap(\n nodes: Record<string, Omit<NodeInput<unknown>, 'value'>>,\n ): DependencyGraph<string> {\n return this.fromIterable(\n Object.entries(nodes).map(([key, node]) => ({\n value: String(key),\n ...node,\n })),\n );\n }\n\n static fromIterable<T>(\n nodeInputs: Iterable<NodeInput<T>>,\n ): DependencyGraph<T> {\n const nodes = new Array<Node<T>>();\n for (const nodeInput of nodeInputs) {\n nodes.push(Node.from(nodeInput));\n }\n\n return new DependencyGraph(nodes);\n }\n\n #nodes: Array<Node<T>>;\n #allProvided: Set<string>;\n\n private constructor(nodes: Array<Node<T>>) {\n this.#nodes = nodes;\n this.#allProvided = new Set();\n\n for (const node of this.#nodes.values()) {\n for (const produced of node.provides) {\n this.#allProvided.add(produced);\n }\n }\n }\n\n /**\n * Find all nodes that consume dependencies that are not provided by any other node.\n */\n findUnsatisfiedDeps(): Array<{ value: T; unsatisfied: string[] }> {\n const unsatisfiedDependencies = [];\n for (const node of this.#nodes.values()) {\n const unsatisfied = Array.from(node.consumes).filter(\n id => !this.#allProvided.has(id),\n );\n if (unsatisfied.length > 0) {\n unsatisfiedDependencies.push({ value: node.value, unsatisfied });\n }\n }\n return unsatisfiedDependencies;\n }\n\n /**\n * Detect the first circular dependency within the graph, returning the path of nodes that\n * form a cycle, with the same node as the first and last element of the array.\n */\n detectCircularDependency(): T[] | undefined {\n return this.detectCircularDependencies().next().value;\n }\n\n /**\n * Detect circular dependencies within the graph, returning the path of nodes that\n * form a cycle, with the same node as the first and last element of the array.\n */\n *detectCircularDependencies(): Generator<T[], undefined> {\n const cycleKeys = CycleKeySet.from(this.#nodes);\n\n for (const startNode of this.#nodes) {\n const visited = new Set<Node<T>>();\n const stack = new Array<[node: Node<T>, path: T[]]>([\n startNode,\n [startNode.value],\n ]);\n\n while (stack.length > 0) {\n const [node, path] = stack.pop()!;\n if (visited.has(node)) {\n continue;\n }\n visited.add(node);\n for (const consumed of node.consumes) {\n const providerNodes = this.#nodes.filter(other =>\n other.provides.has(consumed),\n );\n for (const provider of providerNodes) {\n if (provider === startNode) {\n if (cycleKeys.tryAdd(path)) {\n yield [...path, startNode.value];\n }\n\n break;\n }\n if (!visited.has(provider)) {\n stack.push([provider, [...path, provider.value]]);\n }\n }\n }\n }\n }\n return undefined;\n }\n\n /**\n * Traverses the dependency graph in topological order, calling the provided\n * function for each node and waiting for it to resolve.\n *\n * The nodes are traversed in parallel, but in such a way that no node is\n * visited before all of its dependencies.\n *\n * Dependencies of nodes that are not produced by any other nodes will be ignored.\n */\n async parallelTopologicalTraversal<TResult>(\n fn: (value: T) => Promise<TResult>,\n ): Promise<TResult[]> {\n const allProvided = this.#allProvided;\n const waiting = new Set(this.#nodes.values());\n const visited = new Set<Node<T>>();\n const results = new Array<TResult>();\n let inFlight = 0; // Keep track of how many callbacks are in flight, so that we know if we got stuck\n\n // This keeps track of a counter of how many providers there are still left\n // to be visited for each dependency. This needs to be a counter instead of\n // a flag for the special case where there are several providers of a given\n // value, even though there may be only one consumer of it.\n const producedRemaining = new Map<string, number>();\n for (const node of this.#nodes) {\n for (const provided of node.provides) {\n producedRemaining.set(\n provided,\n (producedRemaining.get(provided) ?? 0) + 1,\n );\n }\n }\n\n // Find all nodes that have no dependencies that have not already been produced by visited nodes\n async function processMoreNodes() {\n if (waiting.size === 0) {\n return;\n }\n const nodesToProcess = [];\n for (const node of waiting) {\n let ready = true;\n for (const consumed of node.consumes) {\n if (\n allProvided.has(consumed) &&\n producedRemaining.get(consumed) !== 0\n ) {\n ready = false;\n continue;\n }\n }\n if (ready) {\n nodesToProcess.push(node);\n }\n }\n\n for (const node of nodesToProcess) {\n waiting.delete(node);\n }\n\n if (nodesToProcess.length === 0 && inFlight === 0) {\n // We expect the caller to check for circular dependencies before\n // traversal, so this error should never happen\n throw new Error('Circular dependency detected');\n }\n\n await Promise.all(nodesToProcess.map(processNode));\n }\n\n // Process an individual node, and then add its produced dependencies to the set of available products\n async function processNode(node: Node<T>) {\n visited.add(node);\n inFlight += 1;\n\n const result = await fn(node.value);\n results.push(result);\n\n node.provides.forEach(produced => {\n const remaining = producedRemaining.get(produced);\n if (!remaining) {\n // This should be impossible, if the code that generates the map is correct\n throw new Error(\n `Internal error: Node provided superfluous dependency '${produced}'`,\n );\n }\n producedRemaining.set(produced, remaining - 1);\n });\n\n inFlight -= 1;\n await processMoreNodes();\n }\n\n await processMoreNodes();\n\n return results;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceRegistry.cjs.js","sources":["../../../../../backend-app-api/src/wiring/ServiceRegistry.ts"],"sourcesContent":["/*\n * Copyright 2022 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 ServiceFactory,\n ServiceRef,\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { ConflictError, stringifyError } from '@backstage/errors';\n// Direct internal import to avoid duplication\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { InternalServiceFactory } from '../../../backend-plugin-api/src/services/system/types';\nimport { DependencyGraph } from '../lib/DependencyGraph';\n/**\n * Keep in sync with `@backstage/backend-plugin-api/src/services/system/types.ts`\n * @internal\n */\nexport type InternalServiceRef = ServiceRef<unknown> & {\n __defaultFactory?: (\n service: ServiceRef<unknown>,\n ) => Promise<ServiceFactory | (() => ServiceFactory)>;\n};\n\nfunction toInternalServiceFactory<TService, TScope extends 'plugin' | 'root'>(\n factory: ServiceFactory<TService, TScope>,\n): InternalServiceFactory<TService, TScope> {\n const f = factory as InternalServiceFactory<TService, TScope>;\n if (f.$$type !== '@backstage/BackendFeature') {\n throw new Error(`Invalid service factory, bad type '${f.$$type}'`);\n }\n if (f.version !== 'v1') {\n throw new Error(`Invalid service factory, bad version '${f.version}'`);\n }\n return f;\n}\n\nfunction createPluginMetadataServiceFactory(pluginId: string) {\n return createServiceFactory({\n service: coreServices.pluginMetadata,\n deps: {},\n factory: async () => ({ getId: () => pluginId }),\n });\n}\n\nexport class ServiceRegistry {\n static create(factories: Array<ServiceFactory>): ServiceRegistry {\n const factoryMap = new Map<string, InternalServiceFactory[]>();\n for (const factory of factories) {\n if (factory.service.multiton) {\n const existing = factoryMap.get(factory.service.id) ?? [];\n factoryMap.set(\n factory.service.id,\n existing.concat(toInternalServiceFactory(factory)),\n );\n } else {\n factoryMap.set(factory.service.id, [toInternalServiceFactory(factory)]);\n }\n }\n const registry = new ServiceRegistry(factoryMap);\n registry.checkForCircularDeps();\n return registry;\n }\n\n readonly #providedFactories: Map<string, InternalServiceFactory[]>;\n readonly #loadedDefaultFactories: Map<\n Function,\n Promise<InternalServiceFactory>\n >;\n readonly #implementations: Map<\n InternalServiceFactory,\n {\n context: Promise<unknown>;\n byPlugin: Map<string, Promise<unknown>>;\n }\n >;\n readonly #rootServiceImplementations = new Map<\n InternalServiceFactory,\n Promise<unknown>\n >();\n readonly #addedFactoryIds = new Set<string>();\n readonly #instantiatedFactories = new Set<string>();\n\n private constructor(factories: Map<string, InternalServiceFactory[]>) {\n this.#providedFactories = factories;\n this.#loadedDefaultFactories = new Map();\n this.#implementations = new Map();\n }\n\n #resolveFactory(\n ref: ServiceRef<unknown>,\n pluginId: string,\n ): Promise<InternalServiceFactory[]> | undefined {\n // Special case handling of the plugin metadata service, generating a custom factory for it each time\n if (ref.id === coreServices.pluginMetadata.id) {\n return Promise.resolve([\n toInternalServiceFactory(createPluginMetadataServiceFactory(pluginId)),\n ]);\n }\n\n let resolvedFactory:\n | Promise<InternalServiceFactory[]>\n | InternalServiceFactory[]\n | undefined = this.#providedFactories.get(ref.id);\n const { __defaultFactory: defaultFactory } = ref as InternalServiceRef;\n if (!resolvedFactory && !defaultFactory) {\n return undefined;\n }\n\n if (!resolvedFactory) {\n let loadedFactory = this.#loadedDefaultFactories.get(defaultFactory!);\n if (!loadedFactory) {\n loadedFactory = Promise.resolve()\n .then(() => defaultFactory!(ref))\n .then(f =>\n toInternalServiceFactory(typeof f === 'function' ? f() : f),\n );\n this.#loadedDefaultFactories.set(defaultFactory!, loadedFactory);\n }\n resolvedFactory = loadedFactory.then(\n factory => [factory],\n error => {\n throw new Error(\n `Failed to instantiate service '${\n ref.id\n }' because the default factory loader threw an error, ${stringifyError(\n error,\n )}`,\n );\n },\n );\n }\n\n return Promise.resolve(resolvedFactory);\n }\n\n #checkForMissingDeps(factory: InternalServiceFactory, pluginId: string) {\n const missingDeps = Object.values(factory.deps).filter(ref => {\n if (ref.id === coreServices.pluginMetadata.id) {\n return false;\n }\n if (this.#providedFactories.get(ref.id)) {\n return false;\n }\n if (ref.multiton) {\n return false;\n }\n\n return !(ref as InternalServiceRef).__defaultFactory;\n });\n\n if (missingDeps.length) {\n const missing = missingDeps.map(r => `'${r.id}'`).join(', ');\n throw new Error(\n `Failed to instantiate service '${factory.service.id}' for '${pluginId}' because the following dependent services are missing: ${missing}`,\n );\n }\n }\n\n checkForCircularDeps(): void {\n const graph = DependencyGraph.fromIterable(\n Array.from(this.#providedFactories).map(([serviceId, factories]) => ({\n value: serviceId,\n provides: [serviceId],\n consumes: factories.flatMap(factory =>\n Object.values(factory.deps).map(d => d.id),\n ),\n })),\n );\n const circularDependencies = Array.from(graph.detectCircularDependencies());\n\n if (circularDependencies.length) {\n const cycles = circularDependencies\n .map(c => c.map(id => `'${id}'`).join(' -> '))\n .join('\\n ');\n\n throw new ConflictError(`Circular dependencies detected:\\n ${cycles}`);\n }\n }\n\n hasBeenAdded(ref: ServiceRef<any>) {\n if (ref.id === coreServices.pluginMetadata.id) {\n return true;\n }\n return this.#addedFactoryIds.has(ref.id);\n }\n\n add(factory: ServiceFactory) {\n const factoryId = factory.service.id;\n if (factoryId === coreServices.pluginMetadata.id) {\n throw new Error(\n `The ${coreServices.pluginMetadata.id} service cannot be overridden`,\n );\n }\n\n if (this.#instantiatedFactories.has(factoryId)) {\n throw new Error(\n `Unable to set service factory with id ${factoryId}, service has already been instantiated`,\n );\n }\n\n if (factory.service.multiton) {\n const newFactories = (\n this.#providedFactories.get(factoryId) ?? []\n ).concat(toInternalServiceFactory(factory));\n this.#providedFactories.set(factoryId, newFactories);\n } else {\n if (this.#addedFactoryIds.has(factoryId)) {\n throw new Error(\n `Duplicate service implementations provided for ${factoryId}`,\n );\n }\n\n this.#addedFactoryIds.add(factoryId);\n this.#providedFactories.set(factoryId, [\n toInternalServiceFactory(factory),\n ]);\n }\n }\n\n async initializeEagerServicesWithScope(\n scope: 'root' | 'plugin',\n pluginId: string = 'root',\n ) {\n for (const [factory] of this.#providedFactories.values()) {\n if (factory.service.scope === scope) {\n // Root-scoped services are eager by default, plugin-scoped are lazy by default\n if (scope === 'root' && factory.initialization !== 'lazy') {\n await this.get(factory.service, pluginId);\n } else if (scope === 'plugin' && factory.initialization === 'always') {\n await this.get(factory.service, pluginId);\n }\n }\n }\n }\n\n get<T, TInstances extends 'singleton' | 'multiton'>(\n ref: ServiceRef<T, 'plugin' | 'root', TInstances>,\n pluginId: string,\n ): Promise<TInstances extends 'multiton' ? T[] : T> | undefined {\n this.#instantiatedFactories.add(ref.id);\n\n const resolvedFactory = this.#resolveFactory(ref, pluginId);\n\n if (!resolvedFactory) {\n return ref.multiton\n ? (Promise.resolve([]) as\n | Promise<TInstances extends 'multiton' ? T[] : T>\n | undefined)\n : undefined;\n }\n\n return resolvedFactory\n .then(factories => {\n return Promise.all(\n factories.map(factory => {\n if (factory.service.scope === 'root') {\n let existing = this.#rootServiceImplementations.get(factory);\n if (!existing) {\n this.#checkForMissingDeps(factory, pluginId);\n const rootDeps = new Array<\n Promise<[name: string, impl: unknown]>\n >();\n\n for (const [name, serviceRef] of Object.entries(factory.deps)) {\n if (serviceRef.scope !== 'root') {\n throw new Error(\n `Failed to instantiate 'root' scoped service '${ref.id}' because it depends on '${serviceRef.scope}' scoped service '${serviceRef.id}'.`,\n );\n }\n const target = this.get(serviceRef, pluginId)!;\n rootDeps.push(target.then(impl => [name, impl]));\n }\n\n existing = Promise.all(rootDeps).then(entries =>\n factory.factory(Object.fromEntries(entries), undefined),\n );\n this.#rootServiceImplementations.set(factory, existing);\n }\n return existing as Promise<T>;\n }\n\n let implementation = this.#implementations.get(factory);\n if (!implementation) {\n this.#checkForMissingDeps(factory, pluginId);\n const rootDeps = new Array<\n Promise<[name: string, impl: unknown]>\n >();\n\n for (const [name, serviceRef] of Object.entries(factory.deps)) {\n if (serviceRef.scope === 'root') {\n const target = this.get(serviceRef, pluginId)!;\n rootDeps.push(target.then(impl => [name, impl]));\n }\n }\n\n implementation = {\n context: Promise.all(rootDeps)\n .then(entries =>\n factory.createRootContext?.(Object.fromEntries(entries)),\n )\n .catch(error => {\n const cause = stringifyError(error);\n throw new Error(\n `Failed to instantiate service '${ref.id}' because createRootContext threw an error, ${cause}`,\n );\n }),\n byPlugin: new Map(),\n };\n\n this.#implementations.set(factory, implementation);\n }\n\n let result = implementation.byPlugin.get(pluginId) as Promise<any>;\n if (!result) {\n const allDeps = new Array<\n Promise<[name: string, impl: unknown]>\n >();\n\n for (const [name, serviceRef] of Object.entries(factory.deps)) {\n const target = this.get(serviceRef, pluginId)!;\n allDeps.push(target.then(impl => [name, impl]));\n }\n\n result = implementation.context\n .then(context =>\n Promise.all(allDeps).then(entries =>\n factory.factory(Object.fromEntries(entries), context),\n ),\n )\n .catch(error => {\n const cause = stringifyError(error);\n throw new Error(\n `Failed to instantiate service '${ref.id}' for '${pluginId}' because the factory function threw an error, ${cause}`,\n );\n });\n implementation.byPlugin.set(pluginId, result);\n }\n return result;\n }),\n );\n })\n .then(results => (ref.multiton ? results : results[0]));\n }\n}\n"],"names":["createServiceFactory","coreServices","stringifyError","DependencyGraph","ConflictError"],"mappings":"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"}
1
+ {"version":3,"file":"ServiceRegistry.cjs.js","sources":["../../../../../backend-app-api/src/wiring/ServiceRegistry.ts"],"sourcesContent":["/*\n * Copyright 2022 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 ServiceFactory,\n ServiceRef,\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { ConflictError, stringifyError } from '@backstage/errors';\n// Direct internal import to avoid duplication\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { InternalServiceFactory } from '../../../backend-plugin-api/src/services/system/types';\nimport { DependencyGraph } from '../lib/DependencyGraph';\n/**\n * Keep in sync with `@backstage/backend-plugin-api/src/services/system/types.ts`\n * @internal\n */\nexport type InternalServiceRef = ServiceRef<unknown> & {\n __defaultFactory?: (\n service: ServiceRef<unknown>,\n ) => Promise<ServiceFactory | (() => ServiceFactory)>;\n};\n\nfunction toInternalServiceFactory<TService, TScope extends 'plugin' | 'root'>(\n factory: ServiceFactory<TService, TScope>,\n): InternalServiceFactory<TService, TScope> {\n const f = factory as InternalServiceFactory<TService, TScope>;\n if (f.$$type !== '@backstage/BackendFeature') {\n throw new Error(`Invalid service factory, bad type '${f.$$type}'`);\n }\n if (f.version !== 'v1') {\n throw new Error(`Invalid service factory, bad version '${f.version}'`);\n }\n return f;\n}\n\nfunction createPluginMetadataServiceFactory(pluginId: string) {\n return createServiceFactory({\n service: coreServices.pluginMetadata,\n deps: {},\n factory: async () => ({ getId: () => pluginId }),\n });\n}\n\nexport class ServiceRegistry {\n static create(factories: Array<ServiceFactory>): ServiceRegistry {\n const factoryMap = new Map<string, InternalServiceFactory[]>();\n for (const factory of factories) {\n if (factory.service.multiton) {\n const existing = factoryMap.get(factory.service.id) ?? [];\n factoryMap.set(\n factory.service.id,\n existing.concat(toInternalServiceFactory(factory)),\n );\n } else {\n factoryMap.set(factory.service.id, [toInternalServiceFactory(factory)]);\n }\n }\n const registry = new ServiceRegistry(factoryMap);\n registry.checkForCircularDeps();\n return registry;\n }\n\n readonly #providedFactories: Map<string, InternalServiceFactory[]>;\n readonly #loadedDefaultFactories: Map<\n Function,\n Promise<InternalServiceFactory>\n >;\n readonly #implementations: Map<\n InternalServiceFactory,\n {\n context: Promise<unknown>;\n byPlugin: Map<string, Promise<unknown>>;\n }\n >;\n readonly #rootServiceImplementations = new Map<\n InternalServiceFactory,\n Promise<unknown>\n >();\n readonly #addedFactoryIds = new Set<string>();\n readonly #instantiatedFactories = new Set<string>();\n\n private constructor(factories: Map<string, InternalServiceFactory[]>) {\n this.#providedFactories = factories;\n this.#loadedDefaultFactories = new Map();\n this.#implementations = new Map();\n }\n\n #resolveFactory(\n ref: ServiceRef<unknown>,\n pluginId: string,\n ): Promise<InternalServiceFactory[]> | undefined {\n // Special case handling of the plugin metadata service, generating a custom factory for it each time\n if (ref.id === coreServices.pluginMetadata.id) {\n return Promise.resolve([\n toInternalServiceFactory(createPluginMetadataServiceFactory(pluginId)),\n ]);\n }\n\n let resolvedFactory:\n | Promise<InternalServiceFactory[]>\n | InternalServiceFactory[]\n | undefined = this.#providedFactories.get(ref.id);\n const { __defaultFactory: defaultFactory } = ref as InternalServiceRef;\n if (!resolvedFactory && !defaultFactory) {\n return undefined;\n }\n\n if (!resolvedFactory) {\n let loadedFactory = this.#loadedDefaultFactories.get(defaultFactory!);\n if (!loadedFactory) {\n loadedFactory = Promise.resolve()\n .then(() => defaultFactory!(ref))\n .then(f =>\n toInternalServiceFactory(typeof f === 'function' ? f() : f),\n );\n this.#loadedDefaultFactories.set(defaultFactory!, loadedFactory);\n }\n resolvedFactory = loadedFactory.then(\n factory => [factory],\n error => {\n throw new Error(\n `Failed to instantiate service '${\n ref.id\n }' because the default factory loader threw an error, ${stringifyError(\n error,\n )}`,\n );\n },\n );\n }\n\n return Promise.resolve(resolvedFactory);\n }\n\n #checkForMissingDeps(factory: InternalServiceFactory, pluginId: string) {\n const missingDeps = Object.values(factory.deps).filter(ref => {\n if (ref.id === coreServices.pluginMetadata.id) {\n return false;\n }\n if (this.#providedFactories.get(ref.id)) {\n return false;\n }\n if (ref.multiton) {\n return false;\n }\n\n return !(ref as InternalServiceRef).__defaultFactory;\n });\n\n if (missingDeps.length) {\n const missing = missingDeps.map(r => `'${r.id}'`).join(', ');\n throw new Error(\n `Failed to instantiate service '${factory.service.id}' for '${pluginId}' because the following dependent services are missing: ${missing}`,\n );\n }\n }\n\n checkForCircularDeps(): void {\n const graph = DependencyGraph.fromIterable(\n Array.from(this.#providedFactories).map(([serviceId, factories]) => ({\n value: serviceId,\n provides: [serviceId],\n consumes: factories.flatMap(factory =>\n Object.values(factory.deps).map(d => d.id),\n ),\n })),\n );\n const circularDependencies = Array.from(graph.detectCircularDependencies());\n\n if (circularDependencies.length) {\n const cycles = circularDependencies\n .map(c => c.map(id => `'${id}'`).join(' -> '))\n .join('\\n ');\n\n throw new ConflictError(`Circular dependencies detected:\\n ${cycles}`);\n }\n }\n\n hasBeenAdded(ref: ServiceRef<any>) {\n if (ref.id === coreServices.pluginMetadata.id) {\n return true;\n }\n return this.#addedFactoryIds.has(ref.id);\n }\n\n add(factory: ServiceFactory) {\n const factoryId = factory.service.id;\n if (factoryId === coreServices.pluginMetadata.id) {\n throw new Error(\n `The ${coreServices.pluginMetadata.id} service cannot be overridden`,\n );\n }\n\n if (this.#instantiatedFactories.has(factoryId)) {\n throw new Error(\n `Unable to set service factory with id ${factoryId}, service has already been instantiated`,\n );\n }\n\n if (factory.service.multiton) {\n const newFactories = (\n this.#providedFactories.get(factoryId) ?? []\n ).concat(toInternalServiceFactory(factory));\n this.#providedFactories.set(factoryId, newFactories);\n } else {\n if (this.#addedFactoryIds.has(factoryId)) {\n throw new Error(\n `Duplicate service implementations provided for ${factoryId}`,\n );\n }\n\n this.#addedFactoryIds.add(factoryId);\n this.#providedFactories.set(factoryId, [\n toInternalServiceFactory(factory),\n ]);\n }\n }\n\n async initializeEagerServicesWithScope(\n scope: 'root' | 'plugin',\n pluginId: string = 'root',\n ) {\n for (const [factory] of this.#providedFactories.values()) {\n if (factory.service.scope === scope) {\n // Root-scoped services are eager by default, plugin-scoped are lazy by default\n if (scope === 'root' && factory.initialization !== 'lazy') {\n await this.get(factory.service, pluginId);\n } else if (scope === 'plugin' && factory.initialization === 'always') {\n await this.get(factory.service, pluginId);\n }\n }\n }\n }\n\n get<T, TInstances extends 'singleton' | 'multiton'>(\n ref: ServiceRef<T, 'plugin' | 'root', TInstances>,\n pluginId: string,\n ): Promise<TInstances extends 'multiton' ? T[] : T> | undefined {\n this.#instantiatedFactories.add(ref.id);\n\n const resolvedFactory = this.#resolveFactory(ref, pluginId);\n\n if (!resolvedFactory) {\n return ref.multiton\n ? (Promise.resolve([]) as\n | Promise<TInstances extends 'multiton' ? T[] : T>\n | undefined)\n : undefined;\n }\n\n return resolvedFactory\n .then(factories => {\n return Promise.all(\n factories.map(factory => {\n if (factory.service.scope === 'root') {\n let existing = this.#rootServiceImplementations.get(factory);\n if (!existing) {\n this.#checkForMissingDeps(factory, pluginId);\n const rootDeps = new Array<\n Promise<[name: string, impl: unknown]>\n >();\n\n for (const [name, serviceRef] of Object.entries(factory.deps)) {\n if (serviceRef.scope !== 'root') {\n throw new Error(\n `Failed to instantiate 'root' scoped service '${ref.id}' because it depends on '${serviceRef.scope}' scoped service '${serviceRef.id}'.`,\n );\n }\n const target = this.get(serviceRef, pluginId)!;\n rootDeps.push(target.then(impl => [name, impl]));\n }\n\n existing = Promise.all(rootDeps).then(entries =>\n factory.factory(Object.fromEntries(entries), undefined),\n );\n this.#rootServiceImplementations.set(factory, existing);\n }\n return existing as Promise<T>;\n }\n\n let implementation = this.#implementations.get(factory);\n if (!implementation) {\n this.#checkForMissingDeps(factory, pluginId);\n const rootDeps = new Array<\n Promise<[name: string, impl: unknown]>\n >();\n\n for (const [name, serviceRef] of Object.entries(factory.deps)) {\n if (serviceRef.scope === 'root') {\n const target = this.get(serviceRef, pluginId)!;\n rootDeps.push(target.then(impl => [name, impl]));\n }\n }\n\n implementation = {\n context: Promise.all(rootDeps)\n .then(entries =>\n factory.createRootContext?.(Object.fromEntries(entries)),\n )\n .catch(error => {\n const cause = stringifyError(error);\n throw new Error(\n `Failed to instantiate service '${ref.id}' because createRootContext threw an error, ${cause}`,\n );\n }),\n byPlugin: new Map(),\n };\n\n this.#implementations.set(factory, implementation);\n }\n\n let result = implementation.byPlugin.get(pluginId) as Promise<any>;\n if (!result) {\n const allDeps = new Array<\n Promise<[name: string, impl: unknown]>\n >();\n\n for (const [name, serviceRef] of Object.entries(factory.deps)) {\n const target = this.get(serviceRef, pluginId)!;\n allDeps.push(target.then(impl => [name, impl]));\n }\n\n result = implementation.context\n .then(context =>\n Promise.all(allDeps).then(entries =>\n factory.factory(Object.fromEntries(entries), context),\n ),\n )\n .catch(error => {\n const cause = stringifyError(error);\n throw new Error(\n `Failed to instantiate service '${ref.id}' for '${pluginId}' because the factory function threw an error, ${cause}`,\n );\n });\n implementation.byPlugin.set(pluginId, result);\n }\n return result;\n }),\n );\n })\n .then(results => (ref.multiton ? results : results[0]));\n }\n}\n"],"names":["createServiceFactory","coreServices","stringifyError","DependencyGraph","ConflictError"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TestCaches.cjs.js","sources":["../../src/cache/TestCaches.ts"],"sourcesContent":["/*\n * Copyright 2024 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 Keyv from 'keyv';\nimport { isDockerDisabledForTests } from '../util/isDockerDisabledForTests';\nimport { connectToExternalMemcache, startMemcachedContainer } from './memcache';\nimport { connectToExternalRedis, startRedisContainer } from './redis';\nimport { Instance, TestCacheId, TestCacheProperties, allCaches } from './types';\nimport { connectToExternalValkey, startValkeyContainer } from './valkey';\n\n/**\n * Encapsulates the creation of ephemeral test cache instances for use inside\n * unit or integration tests.\n *\n * @public\n */\nexport class TestCaches {\n private readonly instanceById: Map<string, Instance>;\n private readonly supportedIds: TestCacheId[];\n private static defaultIds?: TestCacheId[];\n\n /**\n * Creates an empty `TestCaches` instance, and sets up Jest to clean up all of\n * its acquired resources after all tests finish.\n *\n * You typically want to create just a single instance like this at the top of\n * your test file or `describe` block, and then call `init` many times on that\n * instance inside the individual tests. Spinning up a \"physical\" cache\n * instance takes a considerable amount of time, slowing down tests. But\n * wiping the contents of an instance using `init` is very fast.\n */\n static create(options?: {\n ids?: TestCacheId[];\n disableDocker?: boolean;\n }): TestCaches {\n const ids = options?.ids;\n const disableDocker = options?.disableDocker ?? isDockerDisabledForTests();\n\n let testCacheIds: TestCacheId[];\n if (ids) {\n testCacheIds = ids;\n } else if (TestCaches.defaultIds) {\n testCacheIds = TestCaches.defaultIds;\n } else {\n testCacheIds = Object.keys(allCaches) as TestCacheId[];\n }\n\n const supportedIds = testCacheIds.filter(id => {\n const properties = allCaches[id];\n if (!properties) {\n return false;\n }\n // If the caller has set up the env with an explicit connection string,\n // we'll assume that this target will work\n if (\n properties.connectionStringEnvironmentVariableName &&\n process.env[properties.connectionStringEnvironmentVariableName]\n ) {\n return true;\n }\n // If the cache doesn't require docker at all, there's nothing to worry\n // about\n if (!properties.dockerImageName) {\n return true;\n }\n // If the cache requires docker, but docker is disabled, we will fail.\n if (disableDocker) {\n return false;\n }\n return true;\n });\n\n const caches = new TestCaches(supportedIds);\n\n if (supportedIds.length > 0) {\n afterAll(async () => {\n await caches.shutdown();\n });\n }\n\n return caches;\n }\n\n static setDefaults(options: { ids?: TestCacheId[] }) {\n TestCaches.defaultIds = options.ids;\n }\n\n private constructor(supportedIds: TestCacheId[]) {\n this.instanceById = new Map();\n this.supportedIds = supportedIds;\n }\n\n supports(id: TestCacheId): boolean {\n return this.supportedIds.includes(id);\n }\n\n eachSupportedId(): [TestCacheId][] {\n return this.supportedIds.map(id => [id]);\n }\n\n /**\n * Returns a fresh, empty cache for the given driver.\n *\n * @param id - The ID of the cache to use, e.g. 'REDIS_7'\n * @returns Cache connection properties\n */\n async init(\n id: TestCacheId,\n ): Promise<{ store: string; connection: string; keyv: Keyv }> {\n const properties = allCaches[id];\n if (!properties) {\n const candidates = Object.keys(allCaches).join(', ');\n throw new Error(\n `Unknown test cache ${id}, possible values are ${candidates}`,\n );\n }\n if (!this.supportedIds.includes(id)) {\n const candidates = this.supportedIds.join(', ');\n throw new Error(\n `Unsupported test cache ${id} for this environment, possible values are ${candidates}`,\n );\n }\n\n // Ensure that a testcontainers instance is up for this ID\n let instance: Instance | undefined = this.instanceById.get(id);\n if (!instance) {\n instance = await this.initAny(properties);\n this.instanceById.set(id, instance);\n }\n\n // Ensure that it's cleared of data from previous tests\n await instance.keyv.clear();\n\n return {\n store: instance.store,\n connection: instance.connection,\n keyv: instance.keyv,\n };\n }\n\n private async initAny(properties: TestCacheProperties): Promise<Instance> {\n switch (properties.store) {\n case 'memcache':\n return this.initMemcached(properties);\n case 'redis':\n return this.initRedis(properties);\n case 'valkey':\n return this.initValkey(properties);\n case 'memory':\n return {\n store: 'memory',\n connection: 'memory',\n keyv: new Keyv(),\n stop: async () => {},\n };\n default:\n throw new Error(`Unknown cache store '${properties.store}'`);\n }\n }\n\n private async initMemcached(\n properties: TestCacheProperties,\n ): Promise<Instance> {\n // Use the connection string if provided\n const envVarName = properties.connectionStringEnvironmentVariableName;\n if (envVarName) {\n const connectionString = process.env[envVarName];\n if (connectionString) {\n return connectToExternalMemcache(connectionString);\n }\n }\n\n return await startMemcachedContainer(properties.dockerImageName!);\n }\n\n private async initRedis(properties: TestCacheProperties): Promise<Instance> {\n // Use the connection string if provided\n const envVarName = properties.connectionStringEnvironmentVariableName;\n if (envVarName) {\n const connectionString = process.env[envVarName];\n if (connectionString) {\n return connectToExternalRedis(connectionString);\n }\n }\n\n return await startRedisContainer(properties.dockerImageName!);\n }\n\n private async initValkey(properties: TestCacheProperties): Promise<Instance> {\n // Use the connection string if provided\n const envVarName = properties.connectionStringEnvironmentVariableName;\n if (envVarName) {\n const connectionString = process.env[envVarName];\n if (connectionString) {\n return connectToExternalValkey(connectionString);\n }\n }\n\n return await startValkeyContainer(properties.dockerImageName!);\n }\n\n private async shutdown() {\n const instances = [...this.instanceById.values()];\n this.instanceById.clear();\n await Promise.all(\n instances.map(({ stop }) =>\n stop().catch(error => {\n console.warn(`TestCaches: Failed to stop container`, { error });\n }),\n ),\n );\n }\n}\n"],"names":["isDockerDisabledForTests","allCaches","Keyv","connectToExternalMemcache","startMemcachedContainer","connectToExternalRedis","startRedisContainer","connectToExternalValkey","startValkeyContainer"],"mappings":"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"}
1
+ {"version":3,"file":"TestCaches.cjs.js","sources":["../../src/cache/TestCaches.ts"],"sourcesContent":["/*\n * Copyright 2024 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 Keyv from 'keyv';\nimport { isDockerDisabledForTests } from '../util/isDockerDisabledForTests';\nimport { connectToExternalMemcache, startMemcachedContainer } from './memcache';\nimport { connectToExternalRedis, startRedisContainer } from './redis';\nimport { Instance, TestCacheId, TestCacheProperties, allCaches } from './types';\nimport { connectToExternalValkey, startValkeyContainer } from './valkey';\n\n/**\n * Encapsulates the creation of ephemeral test cache instances for use inside\n * unit or integration tests.\n *\n * @public\n */\nexport class TestCaches {\n private readonly instanceById: Map<string, Instance>;\n private readonly supportedIds: TestCacheId[];\n private static defaultIds?: TestCacheId[];\n\n /**\n * Creates an empty `TestCaches` instance, and sets up Jest to clean up all of\n * its acquired resources after all tests finish.\n *\n * You typically want to create just a single instance like this at the top of\n * your test file or `describe` block, and then call `init` many times on that\n * instance inside the individual tests. Spinning up a \"physical\" cache\n * instance takes a considerable amount of time, slowing down tests. But\n * wiping the contents of an instance using `init` is very fast.\n */\n static create(options?: {\n ids?: TestCacheId[];\n disableDocker?: boolean;\n }): TestCaches {\n const ids = options?.ids;\n const disableDocker = options?.disableDocker ?? isDockerDisabledForTests();\n\n let testCacheIds: TestCacheId[];\n if (ids) {\n testCacheIds = ids;\n } else if (TestCaches.defaultIds) {\n testCacheIds = TestCaches.defaultIds;\n } else {\n testCacheIds = Object.keys(allCaches) as TestCacheId[];\n }\n\n const supportedIds = testCacheIds.filter(id => {\n const properties = allCaches[id];\n if (!properties) {\n return false;\n }\n // If the caller has set up the env with an explicit connection string,\n // we'll assume that this target will work\n if (\n properties.connectionStringEnvironmentVariableName &&\n process.env[properties.connectionStringEnvironmentVariableName]\n ) {\n return true;\n }\n // If the cache doesn't require docker at all, there's nothing to worry\n // about\n if (!properties.dockerImageName) {\n return true;\n }\n // If the cache requires docker, but docker is disabled, we will fail.\n if (disableDocker) {\n return false;\n }\n return true;\n });\n\n const caches = new TestCaches(supportedIds);\n\n if (supportedIds.length > 0) {\n afterAll(async () => {\n await caches.shutdown();\n });\n }\n\n return caches;\n }\n\n static setDefaults(options: { ids?: TestCacheId[] }) {\n TestCaches.defaultIds = options.ids;\n }\n\n private constructor(supportedIds: TestCacheId[]) {\n this.instanceById = new Map();\n this.supportedIds = supportedIds;\n }\n\n supports(id: TestCacheId): boolean {\n return this.supportedIds.includes(id);\n }\n\n eachSupportedId(): [TestCacheId][] {\n return this.supportedIds.map(id => [id]);\n }\n\n /**\n * Returns a fresh, empty cache for the given driver.\n *\n * @param id - The ID of the cache to use, e.g. 'REDIS_7'\n * @returns Cache connection properties\n */\n async init(\n id: TestCacheId,\n ): Promise<{ store: string; connection: string; keyv: Keyv }> {\n const properties = allCaches[id];\n if (!properties) {\n const candidates = Object.keys(allCaches).join(', ');\n throw new Error(\n `Unknown test cache ${id}, possible values are ${candidates}`,\n );\n }\n if (!this.supportedIds.includes(id)) {\n const candidates = this.supportedIds.join(', ');\n throw new Error(\n `Unsupported test cache ${id} for this environment, possible values are ${candidates}`,\n );\n }\n\n // Ensure that a testcontainers instance is up for this ID\n let instance: Instance | undefined = this.instanceById.get(id);\n if (!instance) {\n instance = await this.initAny(properties);\n this.instanceById.set(id, instance);\n }\n\n // Ensure that it's cleared of data from previous tests\n await instance.keyv.clear();\n\n return {\n store: instance.store,\n connection: instance.connection,\n keyv: instance.keyv,\n };\n }\n\n private async initAny(properties: TestCacheProperties): Promise<Instance> {\n switch (properties.store) {\n case 'memcache':\n return this.initMemcached(properties);\n case 'redis':\n return this.initRedis(properties);\n case 'valkey':\n return this.initValkey(properties);\n case 'memory':\n return {\n store: 'memory',\n connection: 'memory',\n keyv: new Keyv(),\n stop: async () => {},\n };\n default:\n throw new Error(`Unknown cache store '${properties.store}'`);\n }\n }\n\n private async initMemcached(\n properties: TestCacheProperties,\n ): Promise<Instance> {\n // Use the connection string if provided\n const envVarName = properties.connectionStringEnvironmentVariableName;\n if (envVarName) {\n const connectionString = process.env[envVarName];\n if (connectionString) {\n return connectToExternalMemcache(connectionString);\n }\n }\n\n return await startMemcachedContainer(properties.dockerImageName!);\n }\n\n private async initRedis(properties: TestCacheProperties): Promise<Instance> {\n // Use the connection string if provided\n const envVarName = properties.connectionStringEnvironmentVariableName;\n if (envVarName) {\n const connectionString = process.env[envVarName];\n if (connectionString) {\n return connectToExternalRedis(connectionString);\n }\n }\n\n return await startRedisContainer(properties.dockerImageName!);\n }\n\n private async initValkey(properties: TestCacheProperties): Promise<Instance> {\n // Use the connection string if provided\n const envVarName = properties.connectionStringEnvironmentVariableName;\n if (envVarName) {\n const connectionString = process.env[envVarName];\n if (connectionString) {\n return connectToExternalValkey(connectionString);\n }\n }\n\n return await startValkeyContainer(properties.dockerImageName!);\n }\n\n private async shutdown() {\n const instances = [...this.instanceById.values()];\n this.instanceById.clear();\n await Promise.all(\n instances.map(({ stop }) =>\n stop().catch(error => {\n console.warn(`TestCaches: Failed to stop container`, { error });\n }),\n ),\n );\n }\n}\n"],"names":["isDockerDisabledForTests","allCaches","Keyv","connectToExternalMemcache","startMemcachedContainer","connectToExternalRedis","startRedisContainer","connectToExternalValkey","startValkeyContainer"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"memcache.cjs.js","sources":["../../src/cache/memcache.ts"],"sourcesContent":["/*\n * Copyright 2024 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 Keyv from 'keyv';\nimport KeyvMemcache from '@keyv/memcache';\nimport { v4 as uuid } from 'uuid';\nimport { Instance } from './types';\n\nasync function attemptMemcachedConnection(connection: string): Promise<Keyv> {\n const startTime = Date.now();\n\n for (;;) {\n try {\n const store = new KeyvMemcache(connection);\n const keyv = new Keyv({ store });\n const value = uuid();\n await keyv.set('test', value);\n if ((await keyv.get('test')) === value) {\n return keyv;\n }\n } catch (e) {\n if (Date.now() - startTime > 30_000) {\n throw new Error(\n `Timed out waiting for memcached to be ready for connections, ${e}`,\n );\n }\n }\n\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n}\n\nexport async function connectToExternalMemcache(\n connection: string,\n): Promise<Instance> {\n const keyv = await attemptMemcachedConnection(connection);\n return {\n store: 'memcache',\n connection,\n keyv,\n stop: async () => await keyv.disconnect(),\n };\n}\n\nexport async function startMemcachedContainer(\n image: string,\n): Promise<Instance> {\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } =\n require('testcontainers') as typeof import('testcontainers');\n\n const container = await new GenericContainer(image)\n .withExposedPorts(11211)\n .start();\n\n const host = container.getHost();\n const port = container.getMappedPort(11211);\n const connection = `${host}:${port}`;\n\n const keyv = await attemptMemcachedConnection(connection);\n\n return {\n store: 'memcache',\n connection,\n keyv,\n stop: async () => {\n await keyv.disconnect();\n await container.stop({ timeout: 10_000 });\n },\n };\n}\n"],"names":["KeyvMemcache","Keyv","uuid"],"mappings":";;;;;;;;;;;AAqBA,eAAe,2BAA2B,UAAmC,EAAA;AAC3E,EAAM,MAAA,SAAA,GAAY,KAAK,GAAI,EAAA;AAE3B,EAAS,WAAA;AACP,IAAI,IAAA;AACF,MAAM,MAAA,KAAA,GAAQ,IAAIA,6BAAA,CAAa,UAAU,CAAA;AACzC,MAAA,MAAM,IAAO,GAAA,IAAIC,qBAAK,CAAA,EAAE,OAAO,CAAA;AAC/B,MAAA,MAAM,QAAQC,OAAK,EAAA;AACnB,MAAM,MAAA,IAAA,CAAK,GAAI,CAAA,MAAA,EAAQ,KAAK,CAAA;AAC5B,MAAA,IAAK,MAAM,IAAA,CAAK,GAAI,CAAA,MAAM,MAAO,KAAO,EAAA;AACtC,QAAO,OAAA,IAAA;AAAA;AACT,aACO,CAAG,EAAA;AACV,MAAA,IAAI,IAAK,CAAA,GAAA,EAAQ,GAAA,SAAA,GAAY,GAAQ,EAAA;AACnC,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,gEAAgE,CAAC,CAAA;AAAA,SACnE;AAAA;AACF;AAGF,IAAA,MAAM,IAAI,OAAQ,CAAA,CAAA,OAAA,KAAW,UAAW,CAAA,OAAA,EAAS,GAAG,CAAC,CAAA;AAAA;AAEzD;AAEA,eAAsB,0BACpB,UACmB,EAAA;AACnB,EAAM,MAAA,IAAA,GAAO,MAAM,0BAAA,CAA2B,UAAU,CAAA;AACxD,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,UAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAM,EAAA,YAAY,MAAM,IAAA,CAAK,UAAW;AAAA,GAC1C;AACF;AAEA,eAAsB,wBACpB,KACmB,EAAA;AAEnB,EAAA,MAAM,EAAE,gBAAA,EACN,GAAA,OAAA,CAAQ,gBAAgB,CAAA;AAE1B,EAAM,MAAA,SAAA,GAAY,MAAM,IAAI,gBAAA,CAAiB,KAAK,CAC/C,CAAA,gBAAA,CAAiB,KAAK,CAAA,CACtB,KAAM,EAAA;AAET,EAAM,MAAA,IAAA,GAAO,UAAU,OAAQ,EAAA;AAC/B,EAAM,MAAA,IAAA,GAAO,SAAU,CAAA,aAAA,CAAc,KAAK,CAAA;AAC1C,EAAA,MAAM,UAAa,GAAA,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AAElC,EAAM,MAAA,IAAA,GAAO,MAAM,0BAAA,CAA2B,UAAU,CAAA;AAExD,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,UAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAM,YAAY;AAChB,MAAA,MAAM,KAAK,UAAW,EAAA;AACtB,MAAA,MAAM,SAAU,CAAA,IAAA,CAAK,EAAE,OAAA,EAAS,KAAQ,CAAA;AAAA;AAC1C,GACF;AACF;;;;;"}
1
+ {"version":3,"file":"memcache.cjs.js","sources":["../../src/cache/memcache.ts"],"sourcesContent":["/*\n * Copyright 2024 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 Keyv from 'keyv';\nimport KeyvMemcache from '@keyv/memcache';\nimport { v4 as uuid } from 'uuid';\nimport { Instance } from './types';\n\nasync function attemptMemcachedConnection(connection: string): Promise<Keyv> {\n const startTime = Date.now();\n\n for (;;) {\n try {\n const store = new KeyvMemcache(connection);\n const keyv = new Keyv({ store });\n const value = uuid();\n await keyv.set('test', value);\n if ((await keyv.get('test')) === value) {\n return keyv;\n }\n } catch (e) {\n if (Date.now() - startTime > 30_000) {\n throw new Error(\n `Timed out waiting for memcached to be ready for connections, ${e}`,\n );\n }\n }\n\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n}\n\nexport async function connectToExternalMemcache(\n connection: string,\n): Promise<Instance> {\n const keyv = await attemptMemcachedConnection(connection);\n return {\n store: 'memcache',\n connection,\n keyv,\n stop: async () => await keyv.disconnect(),\n };\n}\n\nexport async function startMemcachedContainer(\n image: string,\n): Promise<Instance> {\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } =\n require('testcontainers') as typeof import('testcontainers');\n\n const container = await new GenericContainer(image)\n .withExposedPorts(11211)\n .start();\n\n const host = container.getHost();\n const port = container.getMappedPort(11211);\n const connection = `${host}:${port}`;\n\n const keyv = await attemptMemcachedConnection(connection);\n\n return {\n store: 'memcache',\n connection,\n keyv,\n stop: async () => {\n await keyv.disconnect();\n await container.stop({ timeout: 10_000 });\n },\n };\n}\n"],"names":["KeyvMemcache","Keyv","uuid"],"mappings":";;;;;;;;;;;AAqBA,eAAe,2BAA2B,UAAA,EAAmC;AAC3E,EAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,EAAA,WAAS;AACP,IAAA,IAAI;AACF,MAAA,MAAM,KAAA,GAAQ,IAAIA,6BAAA,CAAa,UAAU,CAAA;AACzC,MAAA,MAAM,IAAA,GAAO,IAAIC,qBAAA,CAAK,EAAE,OAAO,CAAA;AAC/B,MAAA,MAAM,QAAQC,OAAA,EAAK;AACnB,MAAA,MAAM,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,KAAK,CAAA;AAC5B,MAAA,IAAK,MAAM,IAAA,CAAK,GAAA,CAAI,MAAM,MAAO,KAAA,EAAO;AACtC,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF,SAAS,CAAA,EAAG;AACV,MAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA,GAAY,GAAA,EAAQ;AACnC,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,gEAAgE,CAAC,CAAA;AAAA,SACnE;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAM,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,GAAG,CAAC,CAAA;AAAA,EACvD;AACF;AAEA,eAAsB,0BACpB,UAAA,EACmB;AACnB,EAAA,MAAM,IAAA,GAAO,MAAM,0BAAA,CAA2B,UAAU,CAAA;AACxD,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,UAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA,EAAM,YAAY,MAAM,IAAA,CAAK,UAAA;AAAW,GAC1C;AACF;AAEA,eAAsB,wBACpB,KAAA,EACmB;AAEnB,EAAA,MAAM,EAAE,gBAAA,EAAiB,GACvB,OAAA,CAAQ,gBAAgB,CAAA;AAE1B,EAAA,MAAM,SAAA,GAAY,MAAM,IAAI,gBAAA,CAAiB,KAAK,CAAA,CAC/C,gBAAA,CAAiB,KAAK,CAAA,CACtB,KAAA,EAAM;AAET,EAAA,MAAM,IAAA,GAAO,UAAU,OAAA,EAAQ;AAC/B,EAAA,MAAM,IAAA,GAAO,SAAA,CAAU,aAAA,CAAc,KAAK,CAAA;AAC1C,EAAA,MAAM,UAAA,GAAa,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AAElC,EAAA,MAAM,IAAA,GAAO,MAAM,0BAAA,CAA2B,UAAU,CAAA;AAExD,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,UAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAM,YAAY;AAChB,MAAA,MAAM,KAAK,UAAA,EAAW;AACtB,MAAA,MAAM,SAAA,CAAU,IAAA,CAAK,EAAE,OAAA,EAAS,KAAQ,CAAA;AAAA,IAC1C;AAAA,GACF;AACF;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"redis.cjs.js","sources":["../../src/cache/redis.ts"],"sourcesContent":["/*\n * Copyright 2024 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 Keyv from 'keyv';\nimport KeyvRedis from '@keyv/redis';\nimport { v4 as uuid } from 'uuid';\nimport { Instance } from './types';\n\nasync function attemptRedisConnection(connection: string): Promise<Keyv> {\n const startTime = Date.now();\n\n for (;;) {\n try {\n const store = new KeyvRedis(connection);\n const keyv = new Keyv({ store });\n const value = uuid();\n await keyv.set('test', value);\n if ((await keyv.get('test')) === value) {\n return keyv;\n }\n } catch (e) {\n if (Date.now() - startTime > 30_000) {\n throw new Error(\n `Timed out waiting for redis to be ready for connections, ${e}`,\n );\n }\n }\n\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n}\n\nexport async function connectToExternalRedis(\n connection: string,\n): Promise<Instance> {\n const keyv = await attemptRedisConnection(connection);\n return {\n store: 'redis',\n connection,\n keyv,\n stop: async () => await keyv.disconnect(),\n };\n}\n\nexport async function startRedisContainer(image: string): Promise<Instance> {\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } =\n require('testcontainers') as typeof import('testcontainers');\n\n const container = await new GenericContainer(image)\n .withExposedPorts(6379)\n .start();\n\n const host = container.getHost();\n const port = container.getMappedPort(6379);\n const connection = `redis://${host}:${port}`;\n\n const keyv = await attemptRedisConnection(connection);\n\n return {\n store: 'redis',\n connection,\n keyv,\n stop: async () => {\n await keyv.disconnect();\n await container.stop({ timeout: 10_000 });\n },\n };\n}\n"],"names":["KeyvRedis","Keyv","uuid"],"mappings":";;;;;;;;;;;AAqBA,eAAe,uBAAuB,UAAmC,EAAA;AACvE,EAAM,MAAA,SAAA,GAAY,KAAK,GAAI,EAAA;AAE3B,EAAS,WAAA;AACP,IAAI,IAAA;AACF,MAAM,MAAA,KAAA,GAAQ,IAAIA,0BAAA,CAAU,UAAU,CAAA;AACtC,MAAA,MAAM,IAAO,GAAA,IAAIC,qBAAK,CAAA,EAAE,OAAO,CAAA;AAC/B,MAAA,MAAM,QAAQC,OAAK,EAAA;AACnB,MAAM,MAAA,IAAA,CAAK,GAAI,CAAA,MAAA,EAAQ,KAAK,CAAA;AAC5B,MAAA,IAAK,MAAM,IAAA,CAAK,GAAI,CAAA,MAAM,MAAO,KAAO,EAAA;AACtC,QAAO,OAAA,IAAA;AAAA;AACT,aACO,CAAG,EAAA;AACV,MAAA,IAAI,IAAK,CAAA,GAAA,EAAQ,GAAA,SAAA,GAAY,GAAQ,EAAA;AACnC,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,4DAA4D,CAAC,CAAA;AAAA,SAC/D;AAAA;AACF;AAGF,IAAA,MAAM,IAAI,OAAQ,CAAA,CAAA,OAAA,KAAW,UAAW,CAAA,OAAA,EAAS,GAAG,CAAC,CAAA;AAAA;AAEzD;AAEA,eAAsB,uBACpB,UACmB,EAAA;AACnB,EAAM,MAAA,IAAA,GAAO,MAAM,sBAAA,CAAuB,UAAU,CAAA;AACpD,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,OAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAM,EAAA,YAAY,MAAM,IAAA,CAAK,UAAW;AAAA,GAC1C;AACF;AAEA,eAAsB,oBAAoB,KAAkC,EAAA;AAE1E,EAAA,MAAM,EAAE,gBAAA,EACN,GAAA,OAAA,CAAQ,gBAAgB,CAAA;AAE1B,EAAM,MAAA,SAAA,GAAY,MAAM,IAAI,gBAAA,CAAiB,KAAK,CAC/C,CAAA,gBAAA,CAAiB,IAAI,CAAA,CACrB,KAAM,EAAA;AAET,EAAM,MAAA,IAAA,GAAO,UAAU,OAAQ,EAAA;AAC/B,EAAM,MAAA,IAAA,GAAO,SAAU,CAAA,aAAA,CAAc,IAAI,CAAA;AACzC,EAAA,MAAM,UAAa,GAAA,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AAE1C,EAAM,MAAA,IAAA,GAAO,MAAM,sBAAA,CAAuB,UAAU,CAAA;AAEpD,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,OAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAM,YAAY;AAChB,MAAA,MAAM,KAAK,UAAW,EAAA;AACtB,MAAA,MAAM,SAAU,CAAA,IAAA,CAAK,EAAE,OAAA,EAAS,KAAQ,CAAA;AAAA;AAC1C,GACF;AACF;;;;;"}
1
+ {"version":3,"file":"redis.cjs.js","sources":["../../src/cache/redis.ts"],"sourcesContent":["/*\n * Copyright 2024 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 Keyv from 'keyv';\nimport KeyvRedis from '@keyv/redis';\nimport { v4 as uuid } from 'uuid';\nimport { Instance } from './types';\n\nasync function attemptRedisConnection(connection: string): Promise<Keyv> {\n const startTime = Date.now();\n\n for (;;) {\n try {\n const store = new KeyvRedis(connection);\n const keyv = new Keyv({ store });\n const value = uuid();\n await keyv.set('test', value);\n if ((await keyv.get('test')) === value) {\n return keyv;\n }\n } catch (e) {\n if (Date.now() - startTime > 30_000) {\n throw new Error(\n `Timed out waiting for redis to be ready for connections, ${e}`,\n );\n }\n }\n\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n}\n\nexport async function connectToExternalRedis(\n connection: string,\n): Promise<Instance> {\n const keyv = await attemptRedisConnection(connection);\n return {\n store: 'redis',\n connection,\n keyv,\n stop: async () => await keyv.disconnect(),\n };\n}\n\nexport async function startRedisContainer(image: string): Promise<Instance> {\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } =\n require('testcontainers') as typeof import('testcontainers');\n\n const container = await new GenericContainer(image)\n .withExposedPorts(6379)\n .start();\n\n const host = container.getHost();\n const port = container.getMappedPort(6379);\n const connection = `redis://${host}:${port}`;\n\n const keyv = await attemptRedisConnection(connection);\n\n return {\n store: 'redis',\n connection,\n keyv,\n stop: async () => {\n await keyv.disconnect();\n await container.stop({ timeout: 10_000 });\n },\n };\n}\n"],"names":["KeyvRedis","Keyv","uuid"],"mappings":";;;;;;;;;;;AAqBA,eAAe,uBAAuB,UAAA,EAAmC;AACvE,EAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,EAAA,WAAS;AACP,IAAA,IAAI;AACF,MAAA,MAAM,KAAA,GAAQ,IAAIA,0BAAA,CAAU,UAAU,CAAA;AACtC,MAAA,MAAM,IAAA,GAAO,IAAIC,qBAAA,CAAK,EAAE,OAAO,CAAA;AAC/B,MAAA,MAAM,QAAQC,OAAA,EAAK;AACnB,MAAA,MAAM,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,KAAK,CAAA;AAC5B,MAAA,IAAK,MAAM,IAAA,CAAK,GAAA,CAAI,MAAM,MAAO,KAAA,EAAO;AACtC,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF,SAAS,CAAA,EAAG;AACV,MAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA,GAAY,GAAA,EAAQ;AACnC,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,4DAA4D,CAAC,CAAA;AAAA,SAC/D;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAM,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,GAAG,CAAC,CAAA;AAAA,EACvD;AACF;AAEA,eAAsB,uBACpB,UAAA,EACmB;AACnB,EAAA,MAAM,IAAA,GAAO,MAAM,sBAAA,CAAuB,UAAU,CAAA;AACpD,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,OAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA,EAAM,YAAY,MAAM,IAAA,CAAK,UAAA;AAAW,GAC1C;AACF;AAEA,eAAsB,oBAAoB,KAAA,EAAkC;AAE1E,EAAA,MAAM,EAAE,gBAAA,EAAiB,GACvB,OAAA,CAAQ,gBAAgB,CAAA;AAE1B,EAAA,MAAM,SAAA,GAAY,MAAM,IAAI,gBAAA,CAAiB,KAAK,CAAA,CAC/C,gBAAA,CAAiB,IAAI,CAAA,CACrB,KAAA,EAAM;AAET,EAAA,MAAM,IAAA,GAAO,UAAU,OAAA,EAAQ;AAC/B,EAAA,MAAM,IAAA,GAAO,SAAA,CAAU,aAAA,CAAc,IAAI,CAAA;AACzC,EAAA,MAAM,UAAA,GAAa,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AAE1C,EAAA,MAAM,IAAA,GAAO,MAAM,sBAAA,CAAuB,UAAU,CAAA;AAEpD,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,OAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAM,YAAY;AAChB,MAAA,MAAM,KAAK,UAAA,EAAW;AACtB,MAAA,MAAM,SAAA,CAAU,IAAA,CAAK,EAAE,OAAA,EAAS,KAAQ,CAAA;AAAA,IAC1C;AAAA,GACF;AACF;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.cjs.js","sources":["../../src/cache/types.ts"],"sourcesContent":["/*\n * Copyright 2024 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 Keyv from 'keyv';\nimport { getDockerImageForName } from '../util/getDockerImageForName';\n\n/**\n * The possible caches to test against.\n *\n * @public\n */\nexport type TestCacheId = 'MEMORY' | 'REDIS_7' | 'VALKEY_8' | 'MEMCACHED_1';\n\nexport type TestCacheProperties = {\n name: string;\n store: string;\n dockerImageName?: string;\n connectionStringEnvironmentVariableName?: string;\n};\n\nexport type Instance = {\n store: string;\n connection: string;\n keyv: Keyv;\n stop: () => Promise<void>;\n};\n\nexport const allCaches: Record<TestCacheId, TestCacheProperties> =\n Object.freeze({\n REDIS_7: {\n name: 'Redis 7.x',\n store: 'redis',\n dockerImageName: getDockerImageForName('redis:7'),\n connectionStringEnvironmentVariableName:\n 'BACKSTAGE_TEST_CACHE_REDIS7_CONNECTION_STRING',\n },\n MEMCACHED_1: {\n name: 'Memcached 1.x',\n store: 'memcache',\n dockerImageName: getDockerImageForName('memcached:1'),\n connectionStringEnvironmentVariableName:\n 'BACKSTAGE_TEST_CACHE_MEMCACHED1_CONNECTION_STRING',\n },\n MEMORY: {\n name: 'In-memory',\n store: 'memory',\n },\n VALKEY_8: {\n name: 'Valkey 8.x',\n store: 'valkey',\n dockerImageName: getDockerImageForName('valkey/valkey:8'),\n connectionStringEnvironmentVariableName:\n 'BACKSTAGE_TEST_CACHE_VALKEY8_CONNECTION_STRING',\n },\n });\n"],"names":["getDockerImageForName"],"mappings":";;;;AAwCa,MAAA,SAAA,GACX,OAAO,MAAO,CAAA;AAAA,EACZ,OAAS,EAAA;AAAA,IACP,IAAM,EAAA,WAAA;AAAA,IACN,KAAO,EAAA,OAAA;AAAA,IACP,eAAA,EAAiBA,4CAAsB,SAAS,CAAA;AAAA,IAChD,uCACE,EAAA;AAAA,GACJ;AAAA,EACA,WAAa,EAAA;AAAA,IACX,IAAM,EAAA,eAAA;AAAA,IACN,KAAO,EAAA,UAAA;AAAA,IACP,eAAA,EAAiBA,4CAAsB,aAAa,CAAA;AAAA,IACpD,uCACE,EAAA;AAAA,GACJ;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,WAAA;AAAA,IACN,KAAO,EAAA;AAAA,GACT;AAAA,EACA,QAAU,EAAA;AAAA,IACR,IAAM,EAAA,YAAA;AAAA,IACN,KAAO,EAAA,QAAA;AAAA,IACP,eAAA,EAAiBA,4CAAsB,iBAAiB,CAAA;AAAA,IACxD,uCACE,EAAA;AAAA;AAEN,CAAC;;;;"}
1
+ {"version":3,"file":"types.cjs.js","sources":["../../src/cache/types.ts"],"sourcesContent":["/*\n * Copyright 2024 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 Keyv from 'keyv';\nimport { getDockerImageForName } from '../util/getDockerImageForName';\n\n/**\n * The possible caches to test against.\n *\n * @public\n */\nexport type TestCacheId = 'MEMORY' | 'REDIS_7' | 'VALKEY_8' | 'MEMCACHED_1';\n\nexport type TestCacheProperties = {\n name: string;\n store: string;\n dockerImageName?: string;\n connectionStringEnvironmentVariableName?: string;\n};\n\nexport type Instance = {\n store: string;\n connection: string;\n keyv: Keyv;\n stop: () => Promise<void>;\n};\n\nexport const allCaches: Record<TestCacheId, TestCacheProperties> =\n Object.freeze({\n REDIS_7: {\n name: 'Redis 7.x',\n store: 'redis',\n dockerImageName: getDockerImageForName('redis:7'),\n connectionStringEnvironmentVariableName:\n 'BACKSTAGE_TEST_CACHE_REDIS7_CONNECTION_STRING',\n },\n MEMCACHED_1: {\n name: 'Memcached 1.x',\n store: 'memcache',\n dockerImageName: getDockerImageForName('memcached:1'),\n connectionStringEnvironmentVariableName:\n 'BACKSTAGE_TEST_CACHE_MEMCACHED1_CONNECTION_STRING',\n },\n MEMORY: {\n name: 'In-memory',\n store: 'memory',\n },\n VALKEY_8: {\n name: 'Valkey 8.x',\n store: 'valkey',\n dockerImageName: getDockerImageForName('valkey/valkey:8'),\n connectionStringEnvironmentVariableName:\n 'BACKSTAGE_TEST_CACHE_VALKEY8_CONNECTION_STRING',\n },\n });\n"],"names":["getDockerImageForName"],"mappings":";;;;AAwCO,MAAM,SAAA,GACX,OAAO,MAAA,CAAO;AAAA,EACZ,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,WAAA;AAAA,IACN,KAAA,EAAO,OAAA;AAAA,IACP,eAAA,EAAiBA,4CAAsB,SAAS,CAAA;AAAA,IAChD,uCAAA,EACE;AAAA,GACJ;AAAA,EACA,WAAA,EAAa;AAAA,IACX,IAAA,EAAM,eAAA;AAAA,IACN,KAAA,EAAO,UAAA;AAAA,IACP,eAAA,EAAiBA,4CAAsB,aAAa,CAAA;AAAA,IACpD,uCAAA,EACE;AAAA,GACJ;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,WAAA;AAAA,IACN,KAAA,EAAO;AAAA,GACT;AAAA,EACA,QAAA,EAAU;AAAA,IACR,IAAA,EAAM,YAAA;AAAA,IACN,KAAA,EAAO,QAAA;AAAA,IACP,eAAA,EAAiBA,4CAAsB,iBAAiB,CAAA;AAAA,IACxD,uCAAA,EACE;AAAA;AAEN,CAAC;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"valkey.cjs.js","sources":["../../src/cache/valkey.ts"],"sourcesContent":["/*\n * Copyright 2024 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 Keyv from 'keyv';\nimport KeyvValkey from '@keyv/valkey';\nimport { v4 as uuid } from 'uuid';\nimport { Instance } from './types';\n\nasync function attemptValkeyConnection(connection: string): Promise<Keyv> {\n const startTime = Date.now();\n\n for (;;) {\n try {\n const store = new KeyvValkey(connection);\n const keyv = new Keyv({ store });\n const value = uuid();\n await keyv.set('test', value);\n if ((await keyv.get('test')) === value) {\n return keyv;\n }\n } catch (e) {\n if (Date.now() - startTime > 30_000) {\n throw new Error(\n `Timed out waiting for valkey to be ready for connections, ${e}`,\n );\n }\n }\n\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n}\n\nexport async function connectToExternalValkey(\n connection: string,\n): Promise<Instance> {\n const keyv = await attemptValkeyConnection(connection);\n return {\n store: 'valkey',\n connection,\n keyv,\n stop: async () => await keyv.disconnect(),\n };\n}\n\nexport async function startValkeyContainer(image: string): Promise<Instance> {\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } =\n require('testcontainers') as typeof import('testcontainers');\n\n const container = await new GenericContainer(image)\n .withExposedPorts(6379)\n .start();\n\n const host = container.getHost();\n const port = container.getMappedPort(6379);\n const connection = `redis://${host}:${port}`;\n\n const keyv = await attemptValkeyConnection(connection);\n\n return {\n store: 'valkey',\n connection,\n keyv,\n stop: async () => {\n await keyv.disconnect();\n await container.stop({ timeout: 10_000 });\n },\n };\n}\n"],"names":["KeyvValkey","Keyv","uuid"],"mappings":";;;;;;;;;;;AAqBA,eAAe,wBAAwB,UAAmC,EAAA;AACxE,EAAM,MAAA,SAAA,GAAY,KAAK,GAAI,EAAA;AAE3B,EAAS,WAAA;AACP,IAAI,IAAA;AACF,MAAM,MAAA,KAAA,GAAQ,IAAIA,2BAAA,CAAW,UAAU,CAAA;AACvC,MAAA,MAAM,IAAO,GAAA,IAAIC,qBAAK,CAAA,EAAE,OAAO,CAAA;AAC/B,MAAA,MAAM,QAAQC,OAAK,EAAA;AACnB,MAAM,MAAA,IAAA,CAAK,GAAI,CAAA,MAAA,EAAQ,KAAK,CAAA;AAC5B,MAAA,IAAK,MAAM,IAAA,CAAK,GAAI,CAAA,MAAM,MAAO,KAAO,EAAA;AACtC,QAAO,OAAA,IAAA;AAAA;AACT,aACO,CAAG,EAAA;AACV,MAAA,IAAI,IAAK,CAAA,GAAA,EAAQ,GAAA,SAAA,GAAY,GAAQ,EAAA;AACnC,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,6DAA6D,CAAC,CAAA;AAAA,SAChE;AAAA;AACF;AAGF,IAAA,MAAM,IAAI,OAAQ,CAAA,CAAA,OAAA,KAAW,UAAW,CAAA,OAAA,EAAS,GAAG,CAAC,CAAA;AAAA;AAEzD;AAEA,eAAsB,wBACpB,UACmB,EAAA;AACnB,EAAM,MAAA,IAAA,GAAO,MAAM,uBAAA,CAAwB,UAAU,CAAA;AACrD,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,QAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAM,EAAA,YAAY,MAAM,IAAA,CAAK,UAAW;AAAA,GAC1C;AACF;AAEA,eAAsB,qBAAqB,KAAkC,EAAA;AAE3E,EAAA,MAAM,EAAE,gBAAA,EACN,GAAA,OAAA,CAAQ,gBAAgB,CAAA;AAE1B,EAAM,MAAA,SAAA,GAAY,MAAM,IAAI,gBAAA,CAAiB,KAAK,CAC/C,CAAA,gBAAA,CAAiB,IAAI,CAAA,CACrB,KAAM,EAAA;AAET,EAAM,MAAA,IAAA,GAAO,UAAU,OAAQ,EAAA;AAC/B,EAAM,MAAA,IAAA,GAAO,SAAU,CAAA,aAAA,CAAc,IAAI,CAAA;AACzC,EAAA,MAAM,UAAa,GAAA,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AAE1C,EAAM,MAAA,IAAA,GAAO,MAAM,uBAAA,CAAwB,UAAU,CAAA;AAErD,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,QAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAM,YAAY;AAChB,MAAA,MAAM,KAAK,UAAW,EAAA;AACtB,MAAA,MAAM,SAAU,CAAA,IAAA,CAAK,EAAE,OAAA,EAAS,KAAQ,CAAA;AAAA;AAC1C,GACF;AACF;;;;;"}
1
+ {"version":3,"file":"valkey.cjs.js","sources":["../../src/cache/valkey.ts"],"sourcesContent":["/*\n * Copyright 2024 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 Keyv from 'keyv';\nimport KeyvValkey from '@keyv/valkey';\nimport { v4 as uuid } from 'uuid';\nimport { Instance } from './types';\n\nasync function attemptValkeyConnection(connection: string): Promise<Keyv> {\n const startTime = Date.now();\n\n for (;;) {\n try {\n const store = new KeyvValkey(connection);\n const keyv = new Keyv({ store });\n const value = uuid();\n await keyv.set('test', value);\n if ((await keyv.get('test')) === value) {\n return keyv;\n }\n } catch (e) {\n if (Date.now() - startTime > 30_000) {\n throw new Error(\n `Timed out waiting for valkey to be ready for connections, ${e}`,\n );\n }\n }\n\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n}\n\nexport async function connectToExternalValkey(\n connection: string,\n): Promise<Instance> {\n const keyv = await attemptValkeyConnection(connection);\n return {\n store: 'valkey',\n connection,\n keyv,\n stop: async () => await keyv.disconnect(),\n };\n}\n\nexport async function startValkeyContainer(image: string): Promise<Instance> {\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } =\n require('testcontainers') as typeof import('testcontainers');\n\n const container = await new GenericContainer(image)\n .withExposedPorts(6379)\n .start();\n\n const host = container.getHost();\n const port = container.getMappedPort(6379);\n const connection = `redis://${host}:${port}`;\n\n const keyv = await attemptValkeyConnection(connection);\n\n return {\n store: 'valkey',\n connection,\n keyv,\n stop: async () => {\n await keyv.disconnect();\n await container.stop({ timeout: 10_000 });\n },\n };\n}\n"],"names":["KeyvValkey","Keyv","uuid"],"mappings":";;;;;;;;;;;AAqBA,eAAe,wBAAwB,UAAA,EAAmC;AACxE,EAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,EAAA,WAAS;AACP,IAAA,IAAI;AACF,MAAA,MAAM,KAAA,GAAQ,IAAIA,2BAAA,CAAW,UAAU,CAAA;AACvC,MAAA,MAAM,IAAA,GAAO,IAAIC,qBAAA,CAAK,EAAE,OAAO,CAAA;AAC/B,MAAA,MAAM,QAAQC,OAAA,EAAK;AACnB,MAAA,MAAM,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,KAAK,CAAA;AAC5B,MAAA,IAAK,MAAM,IAAA,CAAK,GAAA,CAAI,MAAM,MAAO,KAAA,EAAO;AACtC,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF,SAAS,CAAA,EAAG;AACV,MAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA,GAAY,GAAA,EAAQ;AACnC,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,6DAA6D,CAAC,CAAA;AAAA,SAChE;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAM,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,GAAG,CAAC,CAAA;AAAA,EACvD;AACF;AAEA,eAAsB,wBACpB,UAAA,EACmB;AACnB,EAAA,MAAM,IAAA,GAAO,MAAM,uBAAA,CAAwB,UAAU,CAAA;AACrD,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,QAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA,EAAM,YAAY,MAAM,IAAA,CAAK,UAAA;AAAW,GAC1C;AACF;AAEA,eAAsB,qBAAqB,KAAA,EAAkC;AAE3E,EAAA,MAAM,EAAE,gBAAA,EAAiB,GACvB,OAAA,CAAQ,gBAAgB,CAAA;AAE1B,EAAA,MAAM,SAAA,GAAY,MAAM,IAAI,gBAAA,CAAiB,KAAK,CAAA,CAC/C,gBAAA,CAAiB,IAAI,CAAA,CACrB,KAAA,EAAM;AAET,EAAA,MAAM,IAAA,GAAO,UAAU,OAAA,EAAQ;AAC/B,EAAA,MAAM,IAAA,GAAO,SAAA,CAAU,aAAA,CAAc,IAAI,CAAA;AACzC,EAAA,MAAM,UAAA,GAAa,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AAE1C,EAAA,MAAM,IAAA,GAAO,MAAM,uBAAA,CAAwB,UAAU,CAAA;AAErD,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,QAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAM,YAAY;AAChB,MAAA,MAAM,KAAK,UAAA,EAAW;AACtB,MAAA,MAAM,SAAA,CAAU,IAAA,CAAK,EAAE,OAAA,EAAS,KAAQ,CAAA;AAAA,IAC1C;AAAA,GACF;AACF;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"TestDatabases.cjs.js","sources":["../../src/database/TestDatabases.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { isDockerDisabledForTests } from '../util/isDockerDisabledForTests';\nimport { MysqlEngine } from './mysql';\nimport { PostgresEngine } from './postgres';\nimport { SqliteEngine } from './sqlite';\nimport {\n Engine,\n TestDatabaseId,\n TestDatabaseProperties,\n allDatabases,\n} from './types';\n\n/**\n * Encapsulates the creation of ephemeral test database instances for use\n * inside unit or integration tests.\n *\n * @public\n */\nexport class TestDatabases {\n private readonly engineFactoryByDriver: Record<\n string,\n (properties: TestDatabaseProperties) => Promise<Engine>\n > = {\n pg: PostgresEngine.create,\n mysql: MysqlEngine.create,\n mysql2: MysqlEngine.create,\n 'better-sqlite3': SqliteEngine.create,\n sqlite3: SqliteEngine.create,\n };\n private readonly engineByTestDatabaseId: Map<string, Engine>;\n private readonly supportedIds: TestDatabaseId[];\n private static defaultIds?: TestDatabaseId[];\n\n /**\n * Creates an empty `TestDatabases` instance, and sets up Jest to clean up\n * all of its acquired resources after all tests finish.\n *\n * You typically want to create just a single instance like this at the top\n * of your test file or `describe` block, and then call `init` many times on\n * that instance inside the individual tests. Spinning up a \"physical\"\n * database instance takes a considerable amount of time, slowing down tests.\n * But initializing a new logical database inside that instance using `init`\n * is very fast.\n */\n static create(options?: {\n ids?: TestDatabaseId[];\n disableDocker?: boolean;\n }): TestDatabases {\n const ids = options?.ids;\n const disableDocker = options?.disableDocker ?? isDockerDisabledForTests();\n\n let testDatabaseIds: TestDatabaseId[];\n if (ids) {\n testDatabaseIds = ids;\n } else if (TestDatabases.defaultIds) {\n testDatabaseIds = TestDatabases.defaultIds;\n } else {\n testDatabaseIds = Object.keys(allDatabases) as TestDatabaseId[];\n }\n\n const supportedIds = testDatabaseIds.filter(id => {\n const properties = allDatabases[id];\n if (!properties) {\n return false;\n }\n // If the caller has set up the env with an explicit connection string,\n // we'll assume that this database will work\n if (\n properties.connectionStringEnvironmentVariableName &&\n process.env[properties.connectionStringEnvironmentVariableName]\n ) {\n return true;\n }\n // If the database doesn't require docker at all, there's nothing to worry\n // about\n if (!properties.dockerImageName) {\n return true;\n }\n // If the database requires docker, but docker is disabled, we will fail.\n if (disableDocker) {\n return false;\n }\n return true;\n });\n\n const databases = new TestDatabases(supportedIds);\n\n if (supportedIds.length > 0) {\n afterAll(async () => {\n await databases.shutdown();\n });\n }\n\n return databases;\n }\n\n static setDefaults(options: { ids?: TestDatabaseId[] }) {\n TestDatabases.defaultIds = options.ids;\n }\n\n private constructor(supportedIds: TestDatabaseId[]) {\n this.engineByTestDatabaseId = new Map();\n this.supportedIds = supportedIds;\n }\n\n supports(id: TestDatabaseId): boolean {\n return this.supportedIds.includes(id);\n }\n\n eachSupportedId(): [TestDatabaseId][] {\n return this.supportedIds.map(id => [id]);\n }\n\n /**\n * Returns a fresh, unique, empty logical database on an instance of the\n * given database ID platform.\n *\n * @param id - The ID of the database platform to use, e.g. 'POSTGRES_13'\n * @returns A `Knex` connection object\n */\n async init(id: TestDatabaseId): Promise<Knex> {\n const properties = allDatabases[id];\n if (!properties) {\n const candidates = Object.keys(allDatabases).join(', ');\n throw new Error(\n `Unknown test database ${id}, possible values are ${candidates}`,\n );\n }\n if (!this.supportedIds.includes(id)) {\n const candidates = this.supportedIds.join(', ');\n throw new Error(\n `Unsupported test database ${id} for this environment, possible values are ${candidates}`,\n );\n }\n\n let engine = this.engineByTestDatabaseId.get(id);\n if (!engine) {\n const factory = this.engineFactoryByDriver[properties.driver];\n if (!factory) {\n throw new Error(`Unknown database driver ${properties.driver}`);\n }\n engine = await factory(properties);\n this.engineByTestDatabaseId.set(id, engine);\n }\n\n return await engine.createDatabaseInstance();\n }\n\n private async shutdown() {\n const engines = [...this.engineByTestDatabaseId.values()];\n this.engineByTestDatabaseId.clear();\n\n for (const engine of engines) {\n try {\n await engine.shutdown();\n } catch (error) {\n console.warn(`TestDatabases: Failed to shutdown engine`, {\n engine,\n error,\n });\n }\n }\n }\n}\n"],"names":["PostgresEngine","MysqlEngine","SqliteEngine","isDockerDisabledForTests","allDatabases"],"mappings":"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"}
1
+ {"version":3,"file":"TestDatabases.cjs.js","sources":["../../src/database/TestDatabases.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { isDockerDisabledForTests } from '../util/isDockerDisabledForTests';\nimport { MysqlEngine } from './mysql';\nimport { PostgresEngine } from './postgres';\nimport { SqliteEngine } from './sqlite';\nimport {\n Engine,\n TestDatabaseId,\n TestDatabaseProperties,\n allDatabases,\n} from './types';\n\n/**\n * Encapsulates the creation of ephemeral test database instances for use\n * inside unit or integration tests.\n *\n * @public\n */\nexport class TestDatabases {\n private readonly engineFactoryByDriver: Record<\n string,\n (properties: TestDatabaseProperties) => Promise<Engine>\n > = {\n pg: PostgresEngine.create,\n mysql: MysqlEngine.create,\n mysql2: MysqlEngine.create,\n 'better-sqlite3': SqliteEngine.create,\n sqlite3: SqliteEngine.create,\n };\n private readonly engineByTestDatabaseId: Map<string, Engine>;\n private readonly supportedIds: TestDatabaseId[];\n private static defaultIds?: TestDatabaseId[];\n\n /**\n * Creates an empty `TestDatabases` instance, and sets up Jest to clean up\n * all of its acquired resources after all tests finish.\n *\n * You typically want to create just a single instance like this at the top\n * of your test file or `describe` block, and then call `init` many times on\n * that instance inside the individual tests. Spinning up a \"physical\"\n * database instance takes a considerable amount of time, slowing down tests.\n * But initializing a new logical database inside that instance using `init`\n * is very fast.\n */\n static create(options?: {\n ids?: TestDatabaseId[];\n disableDocker?: boolean;\n }): TestDatabases {\n const ids = options?.ids;\n const disableDocker = options?.disableDocker ?? isDockerDisabledForTests();\n\n let testDatabaseIds: TestDatabaseId[];\n if (ids) {\n testDatabaseIds = ids;\n } else if (TestDatabases.defaultIds) {\n testDatabaseIds = TestDatabases.defaultIds;\n } else {\n testDatabaseIds = Object.keys(allDatabases) as TestDatabaseId[];\n }\n\n const supportedIds = testDatabaseIds.filter(id => {\n const properties = allDatabases[id];\n if (!properties) {\n return false;\n }\n // If the caller has set up the env with an explicit connection string,\n // we'll assume that this database will work\n if (\n properties.connectionStringEnvironmentVariableName &&\n process.env[properties.connectionStringEnvironmentVariableName]\n ) {\n return true;\n }\n // If the database doesn't require docker at all, there's nothing to worry\n // about\n if (!properties.dockerImageName) {\n return true;\n }\n // If the database requires docker, but docker is disabled, we will fail.\n if (disableDocker) {\n return false;\n }\n return true;\n });\n\n const databases = new TestDatabases(supportedIds);\n\n if (supportedIds.length > 0) {\n afterAll(async () => {\n await databases.shutdown();\n });\n }\n\n return databases;\n }\n\n static setDefaults(options: { ids?: TestDatabaseId[] }) {\n TestDatabases.defaultIds = options.ids;\n }\n\n private constructor(supportedIds: TestDatabaseId[]) {\n this.engineByTestDatabaseId = new Map();\n this.supportedIds = supportedIds;\n }\n\n supports(id: TestDatabaseId): boolean {\n return this.supportedIds.includes(id);\n }\n\n eachSupportedId(): [TestDatabaseId][] {\n return this.supportedIds.map(id => [id]);\n }\n\n /**\n * Returns a fresh, unique, empty logical database on an instance of the\n * given database ID platform.\n *\n * @param id - The ID of the database platform to use, e.g. 'POSTGRES_13'\n * @returns A `Knex` connection object\n */\n async init(id: TestDatabaseId): Promise<Knex> {\n const properties = allDatabases[id];\n if (!properties) {\n const candidates = Object.keys(allDatabases).join(', ');\n throw new Error(\n `Unknown test database ${id}, possible values are ${candidates}`,\n );\n }\n if (!this.supportedIds.includes(id)) {\n const candidates = this.supportedIds.join(', ');\n throw new Error(\n `Unsupported test database ${id} for this environment, possible values are ${candidates}`,\n );\n }\n\n let engine = this.engineByTestDatabaseId.get(id);\n if (!engine) {\n const factory = this.engineFactoryByDriver[properties.driver];\n if (!factory) {\n throw new Error(`Unknown database driver ${properties.driver}`);\n }\n engine = await factory(properties);\n this.engineByTestDatabaseId.set(id, engine);\n }\n\n return await engine.createDatabaseInstance();\n }\n\n private async shutdown() {\n const engines = [...this.engineByTestDatabaseId.values()];\n this.engineByTestDatabaseId.clear();\n\n for (const engine of engines) {\n try {\n await engine.shutdown();\n } catch (error) {\n console.warn(`TestDatabases: Failed to shutdown engine`, {\n engine,\n error,\n });\n }\n }\n }\n}\n"],"names":["PostgresEngine","MysqlEngine","SqliteEngine","isDockerDisabledForTests","allDatabases"],"mappings":"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"}