@lokalise/connector-shell 1.1.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 (38) hide show
  1. package/README.md +140 -0
  2. package/dist/ConnectorShellModule.d.ts +59 -0
  3. package/dist/ConnectorShellModule.js +51 -0
  4. package/dist/ConnectorShellModule.js.map +1 -0
  5. package/dist/adapterResolver/errors/adapterErrors.d.ts +10 -0
  6. package/dist/adapterResolver/errors/adapterErrors.js +40 -0
  7. package/dist/adapterResolver/errors/adapterErrors.js.map +1 -0
  8. package/dist/adapterResolver/resolveAdapter.d.ts +2 -0
  9. package/dist/adapterResolver/resolveAdapter.js +16 -0
  10. package/dist/adapterResolver/resolveAdapter.js.map +1 -0
  11. package/dist/auth/authController.d.ts +55 -0
  12. package/dist/auth/authController.js +73 -0
  13. package/dist/auth/authController.js.map +1 -0
  14. package/dist/cache/cacheController.d.ts +85 -0
  15. package/dist/cache/cacheController.js +74 -0
  16. package/dist/cache/cacheController.js.map +1 -0
  17. package/dist/commonTypes.d.ts +17 -0
  18. package/dist/commonTypes.js +2 -0
  19. package/dist/commonTypes.js.map +1 -0
  20. package/dist/env/envController.d.ts +49 -0
  21. package/dist/env/envController.js +34 -0
  22. package/dist/env/envController.js.map +1 -0
  23. package/dist/index.d.ts +9 -0
  24. package/dist/index.js +16 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/itemGroup/ItemGroupController.d.ts +55 -0
  27. package/dist/itemGroup/ItemGroupController.js +38 -0
  28. package/dist/itemGroup/ItemGroupController.js.map +1 -0
  29. package/dist/itemList/ItemListController.d.ts +68 -0
  30. package/dist/itemList/ItemListController.js +35 -0
  31. package/dist/itemList/ItemListController.js.map +1 -0
  32. package/dist/publish/publishController.d.ts +51 -0
  33. package/dist/publish/publishController.js +44 -0
  34. package/dist/publish/publishController.js.map +1 -0
  35. package/dist/translate/translateController.d.ts +77 -0
  36. package/dist/translate/translateController.js +30 -0
  37. package/dist/translate/translateController.js.map +1 -0
  38. package/package.json +63 -0
package/README.md ADDED
@@ -0,0 +1,140 @@
1
+ # @lokalise/connector-shell
2
+
3
+ A drop-in module for [opinionated-machine](https://github.com/lokalise/opinionated-machine) services that provides the connector shell infrastructure for Lokalise Content Engine connectors.
4
+
5
+ This package provides the generic connector shell with all standard controllers (Auth, Cache, Env, ItemList, ItemGroup, Publish, Translate) and routing logic. It's designed to work with any set of adapters through automatic adapter discovery via dependency injection tags.
6
+
7
+ ## Features
8
+
9
+ - **Drop-in Integration**: Add to your modules list alongside adapter modules
10
+ - **Automatic Adapter Discovery**: Finds adapters via DI tags (`ADAPTER_LABEL = 'connectorAdapter'`)
11
+ - **Complete Controller Suite**: All 7 standard controllers included
12
+ - **Type-Safe**: Full TypeScript support
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @lokalise/connector-shell
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ```typescript
23
+ // modules.ts
24
+ export const ALL_MODULES = [
25
+ new CommonModule(), // Provides required dependencies
26
+ new YourAdapterModule(), // Registers adapters with ADAPTER_LABEL tag
27
+ new ConnectorShellModule(), // Discovers adapters, registers controllers
28
+ ]
29
+ ```
30
+
31
+ ## Required Dependencies
32
+
33
+ Your `CommonModule` must provide:
34
+
35
+ ```typescript
36
+ import { ADAPTER_LABEL } from '@lokalise/connector-adapter-common'
37
+ import type { ProtectedRouteMetadataMapperFactory } from '@lokalise/connector-shell'
38
+
39
+ export class CommonModule extends AbstractModule<CommonDependencies> {
40
+ resolveDependencies() {
41
+ return {
42
+ awilixManager: asSingletonFunction((deps) => deps.app?.awilixManager),
43
+ protectedRouteMetadataMapperFactory: asSingletonFunction(
44
+ (): ProtectedRouteMetadataMapperFactory => PROTECTED_ROUTE_METADATA_MAPPER
45
+ ),
46
+ }
47
+ }
48
+ }
49
+
50
+ export interface CommonDependencies {
51
+ awilixManager: AwilixManager
52
+ protectedRouteMetadataMapperFactory: ProtectedRouteMetadataMapperFactory
53
+ }
54
+ ```
55
+
56
+ **Example prehandler:**
57
+
58
+ ```typescript
59
+ // prehandlers/integrationConfigPrehandler.ts
60
+ export const PROTECTED_ROUTE_METADATA_MAPPER = (requireAuthConfig = true) =>
61
+ (() => ({
62
+ preHandler: (req, res, done) => {
63
+ // Decode ce-config and ce-auth headers, attach to req
64
+ done()
65
+ }
66
+ })) satisfies ApiContractMetadataToRouteMapper
67
+ ```
68
+
69
+ ## Adapter Discovery
70
+
71
+ Adapters are discovered via the `ADAPTER_LABEL` tag:
72
+
73
+ ```typescript
74
+ import { ADAPTER_LABEL, type Adapter } from '@lokalise/connector-adapter-common'
75
+ import { AbstractModule, asSingletonClass } from 'opinionated-machine'
76
+
77
+ export class YourAdapterModule extends AbstractModule<YourDependencies> {
78
+ resolveDependencies() {
79
+ return {
80
+ yourApiClient: asSingletonClass(YourApiClient),
81
+ yourAdapter: asSingletonClass(YourAdapter, {
82
+ tags: [ADAPTER_LABEL], // <-- Required for discovery
83
+ }),
84
+ }
85
+ }
86
+ }
87
+ ```
88
+
89
+ **How it works:**
90
+ - `ADAPTER_LABEL = 'connectorAdapter'` (constant from `@lokalise/connector-adapter-common`)
91
+ - ConnectorShellModule queries `awilixManager.getWithTags([ADAPTER_LABEL])` to find all adapters
92
+ - Adapters are keyed by `adapter.getConnectorName()` value
93
+ - Controllers resolve adapters per-request via `ce-connector-id` header
94
+
95
+ ## Creating Your ConnectorShellModule
96
+
97
+ ```typescript
98
+ import {
99
+ ConnectorShellModule as BaseConnectorShellModule,
100
+ type ConnectorShellBaseDependencies,
101
+ } from '@lokalise/connector-shell'
102
+
103
+ export type SupportedConnectors =
104
+ | typeof YourAdapter.connectorName
105
+ | 'another-connector'
106
+
107
+ export type ConnectorShellInjectableDependencies =
108
+ ConnectorShellBaseDependencies &
109
+ CommonDependencies &
110
+ YourAdapterPublicDependencies
111
+
112
+ export class ConnectorShellModule extends BaseConnectorShellModule<
113
+ ConnectorShellInjectableDependencies,
114
+ ExternalDependencies
115
+ > {}
116
+ ```
117
+
118
+ ## Bootstrap
119
+
120
+ ```typescript
121
+ import { DIContext } from 'opinionated-machine'
122
+ import { ALL_MODULES } from './modules'
123
+
124
+ const diContext = new DIContext(diContainer, options)
125
+ diContext.registerDependencies({ modules: ALL_MODULES }, externalDependencies)
126
+
127
+ app.after(() => {
128
+ diContext.registerRoutes(app) // Controllers auto-register
129
+ })
130
+ ```
131
+
132
+ ## Adding a New Adapter
133
+
134
+ 1. Create adapter implementing `Adapter` interface
135
+ 2. Register with `ADAPTER_LABEL` tag:
136
+ ```typescript
137
+ yourAdapter: asSingletonClass(YourAdapter, {
138
+ tags: [ADAPTER_LABEL],
139
+ })
140
+ ```
@@ -0,0 +1,59 @@
1
+ import { type Adapter } from '@lokalise/connector-adapter-common';
2
+ import type { ApiContractMetadataToRouteMapper } from '@lokalise/fastify-api-contracts';
3
+ import { AbstractModule, type DependencyInjectionOptions, type MandatoryNameAndRegistrationPair } from 'opinionated-machine';
4
+ /**
5
+ * Factory function that creates a metadata mapper for protected routes.
6
+ * The metadata mapper is responsible for adding prehandlers to routes.
7
+ * Applications should provide their own implementation.
8
+ */
9
+ export type ProtectedRouteMetadataMapperFactory = (requireAuthConfig?: boolean) => ApiContractMetadataToRouteMapper;
10
+ /**
11
+ * Base dependencies required by ConnectorShellModule.
12
+ * Applications should extend this with their own CommonDependencies and adapter public dependencies.
13
+ */
14
+ export interface ConnectorShellBaseDependencies {
15
+ awilixManager: {
16
+ getWithTags: (tags: string[]) => Record<string, unknown>;
17
+ };
18
+ /**
19
+ * Factory function for creating protected route metadata mappers.
20
+ * This must be provided by the application.
21
+ */
22
+ protectedRouteMetadataMapperFactory: ProtectedRouteMetadataMapperFactory;
23
+ }
24
+ /**
25
+ * Dependencies that ConnectorShellModule creates
26
+ */
27
+ interface ConnectorShellCreatedDependencies {
28
+ adapters: Record<string, Adapter>;
29
+ }
30
+ /**
31
+ * Generic ConnectorShellModule that works with any set of adapters.
32
+ * No hardcoded adapter imports - adapters are discovered at runtime via ADAPTER_LABEL tag.
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * // In your application
37
+ * export type ConnectorShellInjectableDependencies =
38
+ * ConnectorShellBaseDependencies &
39
+ * YourCommonDependencies &
40
+ * YourAdapterPublicDependencies
41
+ *
42
+ * export type SupportedConnectors =
43
+ * | typeof YourAdapter1.connectorName
44
+ * | typeof YourAdapter2.connectorName
45
+ * ```
46
+ */
47
+ export declare class ConnectorShellModule<TDependencies extends ConnectorShellBaseDependencies = ConnectorShellBaseDependencies, TExternalDependencies = unknown> extends AbstractModule<ConnectorShellCreatedDependencies, TExternalDependencies> {
48
+ resolveDependencies(_diOptions: DependencyInjectionOptions, _externalDependencies: TExternalDependencies): {
49
+ adapters: import("awilix").BuildResolver<Record<string, Adapter>> & import("awilix").DisposableResolver<Record<string, Adapter>>;
50
+ };
51
+ resolveControllers(): MandatoryNameAndRegistrationPair<unknown>;
52
+ }
53
+ /**
54
+ * Dependencies provided by ConnectorShellModule (includes both created and required dependencies)
55
+ */
56
+ export type ConnectorShellDependencies = ConnectorShellCreatedDependencies & {
57
+ protectedRouteMetadataMapperFactory: ProtectedRouteMetadataMapperFactory;
58
+ };
59
+ export {};
@@ -0,0 +1,51 @@
1
+ import { ADAPTER_LABEL } from '@lokalise/connector-adapter-common';
2
+ import { AbstractModule, asControllerClass, asSingletonFunction, } from 'opinionated-machine';
3
+ import { AuthController } from "./auth/authController.js";
4
+ import { CacheController } from "./cache/cacheController.js";
5
+ import { EnvController } from "./env/envController.js";
6
+ import { ItemGroupController } from "./itemGroup/ItemGroupController.js";
7
+ import { ItemListController } from "./itemList/ItemListController.js";
8
+ import { PublishController } from "./publish/publishController.js";
9
+ import { TranslateController } from "./translate/translateController.js";
10
+ /**
11
+ * Generic ConnectorShellModule that works with any set of adapters.
12
+ * No hardcoded adapter imports - adapters are discovered at runtime via ADAPTER_LABEL tag.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * // In your application
17
+ * export type ConnectorShellInjectableDependencies =
18
+ * ConnectorShellBaseDependencies &
19
+ * YourCommonDependencies &
20
+ * YourAdapterPublicDependencies
21
+ *
22
+ * export type SupportedConnectors =
23
+ * | typeof YourAdapter1.connectorName
24
+ * | typeof YourAdapter2.connectorName
25
+ * ```
26
+ */
27
+ export class ConnectorShellModule extends AbstractModule {
28
+ resolveDependencies(_diOptions, _externalDependencies) {
29
+ return {
30
+ adapters: asSingletonFunction((dependencies) => {
31
+ const adapterMap = dependencies.awilixManager.getWithTags([ADAPTER_LABEL]);
32
+ return Object.values(adapterMap).reduce((acc, adapter) => {
33
+ acc[adapter.getConnectorName()] = adapter;
34
+ return acc;
35
+ }, {});
36
+ }),
37
+ };
38
+ }
39
+ resolveControllers() {
40
+ return {
41
+ authController: asControllerClass(AuthController),
42
+ cacheController: asControllerClass(CacheController),
43
+ publishController: asControllerClass(PublishController),
44
+ itemListController: asControllerClass(ItemListController),
45
+ itemGroupController: asControllerClass(ItemGroupController),
46
+ translateController: asControllerClass(TranslateController),
47
+ envController: asControllerClass(EnvController),
48
+ };
49
+ }
50
+ }
51
+ //# sourceMappingURL=ConnectorShellModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectorShellModule.js","sourceRoot":"","sources":["../src/ConnectorShellModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAgB,MAAM,oCAAoC,CAAA;AAEhF,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,mBAAmB,GAGpB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AAiCxE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,oBAGX,SAAQ,cAAwE;IAChF,mBAAmB,CACjB,UAAsC,EACtC,qBAA4C;QAE5C,OAAO;YACL,QAAQ,EAAE,mBAAmB,CAAC,CAAC,YAA2B,EAA2B,EAAE;gBACrF,MAAM,UAAU,GAAG,YAAY,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,aAAa,CAAC,CAGxE,CAAA;gBACD,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CACrC,CAAC,GAAG,EAAE,OAAgB,EAAE,EAAE;oBACxB,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,GAAG,OAAO,CAAA;oBACzC,OAAO,GAAG,CAAA;gBACZ,CAAC,EACD,EAAE,CACH,CAAA;YACH,CAAC,CAAC;SACH,CAAA;IACH,CAAC;IAED,kBAAkB;QAChB,OAAO;YACL,cAAc,EAAE,iBAAiB,CAAC,cAAc,CAAC;YACjD,eAAe,EAAE,iBAAiB,CAAC,eAAe,CAAC;YACnD,iBAAiB,EAAE,iBAAiB,CAAC,iBAAiB,CAAC;YACvD,kBAAkB,EAAE,iBAAiB,CAAC,kBAAkB,CAAC;YACzD,mBAAmB,EAAE,iBAAiB,CAAC,mBAAmB,CAAC;YAC3D,mBAAmB,EAAE,iBAAiB,CAAC,mBAAmB,CAAC;YAC3D,aAAa,EAAE,iBAAiB,CAAC,aAAa,CAAC;SAChD,CAAA;IACH,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import { PublicNonRecoverableError } from '@lokalise/node-core';
2
+ export declare class ConnectorNotSupportedError extends PublicNonRecoverableError {
3
+ constructor(connectorId: string);
4
+ }
5
+ export declare class ConnectorNotProvidedError extends PublicNonRecoverableError {
6
+ constructor();
7
+ }
8
+ export declare class MultipleConnectorsProvidedError extends PublicNonRecoverableError {
9
+ constructor(connectorIds: string[]);
10
+ }
@@ -0,0 +1,40 @@
1
+ import { CONNECTOR_ID_HEADER } from '@lokalise/connector-api-contracts';
2
+ import { PublicNonRecoverableError } from '@lokalise/node-core';
3
+ export class ConnectorNotSupportedError extends PublicNonRecoverableError {
4
+ constructor(connectorId) {
5
+ super({
6
+ message: 'Connector not supported',
7
+ errorCode: 'CONNECTOR_NOT_SUPPORTED',
8
+ httpStatusCode: 400,
9
+ details: {
10
+ connectorId,
11
+ },
12
+ });
13
+ }
14
+ }
15
+ export class ConnectorNotProvidedError extends PublicNonRecoverableError {
16
+ constructor() {
17
+ super({
18
+ message: 'Connector not provided',
19
+ errorCode: 'CONNECTOR_NOT_PROVIDED',
20
+ httpStatusCode: 400,
21
+ details: {
22
+ hint: `Make sure you provide connector id under ${CONNECTOR_ID_HEADER} header`,
23
+ },
24
+ });
25
+ }
26
+ }
27
+ export class MultipleConnectorsProvidedError extends PublicNonRecoverableError {
28
+ constructor(connectorIds) {
29
+ super({
30
+ message: 'Multiple connectors provided',
31
+ errorCode: 'MULTIPLE_CONNECTORS_PROVIDED',
32
+ httpStatusCode: 400,
33
+ details: {
34
+ providedConnectorIds: connectorIds,
35
+ hint: `Make sure you provide only one ${CONNECTOR_ID_HEADER} header value`,
36
+ },
37
+ });
38
+ }
39
+ }
40
+ //# sourceMappingURL=adapterErrors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapterErrors.js","sourceRoot":"","sources":["../../../src/adapterResolver/errors/adapterErrors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAA;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAE/D,MAAM,OAAO,0BAA2B,SAAQ,yBAAyB;IACvE,YAAY,WAAmB;QAC7B,KAAK,CAAC;YACJ,OAAO,EAAE,yBAAyB;YAClC,SAAS,EAAE,yBAAyB;YACpC,cAAc,EAAE,GAAG;YACnB,OAAO,EAAE;gBACP,WAAW;aACZ;SACF,CAAC,CAAA;IACJ,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,yBAAyB;IACtE;QACE,KAAK,CAAC;YACJ,OAAO,EAAE,wBAAwB;YACjC,SAAS,EAAE,wBAAwB;YACnC,cAAc,EAAE,GAAG;YACnB,OAAO,EAAE;gBACP,IAAI,EAAE,4CAA4C,mBAAmB,SAAS;aAC/E;SACF,CAAC,CAAA;IACJ,CAAC;CACF;AAED,MAAM,OAAO,+BAAgC,SAAQ,yBAAyB;IAC5E,YAAY,YAAsB;QAChC,KAAK,CAAC;YACJ,OAAO,EAAE,8BAA8B;YACvC,SAAS,EAAE,8BAA8B;YACzC,cAAc,EAAE,GAAG;YACnB,OAAO,EAAE;gBACP,oBAAoB,EAAE,YAAY;gBAClC,IAAI,EAAE,kCAAkC,mBAAmB,eAAe;aAC3E;SACF,CAAC,CAAA;IACJ,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ import type { Adapter } from '@lokalise/connector-adapter-common';
2
+ export declare const resolveAdapter: (adapters: Record<string, Adapter>, connectorId: string | string[] | undefined) => Adapter;
@@ -0,0 +1,16 @@
1
+ import { ConnectorNotProvidedError, ConnectorNotSupportedError, MultipleConnectorsProvidedError, } from "./errors/adapterErrors.js";
2
+ export const resolveAdapter = (adapters, connectorId) => {
3
+ if (!connectorId) {
4
+ throw new ConnectorNotProvidedError();
5
+ }
6
+ if (Array.isArray(connectorId) && connectorId.length !== 1) {
7
+ throw new MultipleConnectorsProvidedError(connectorId);
8
+ }
9
+ const singleConnectorId = (Array.isArray(connectorId) ? connectorId[0] : connectorId);
10
+ const adapter = adapters[singleConnectorId];
11
+ if (!adapter) {
12
+ throw new ConnectorNotSupportedError(singleConnectorId);
13
+ }
14
+ return adapter;
15
+ };
16
+ //# sourceMappingURL=resolveAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveAdapter.js","sourceRoot":"","sources":["../../src/adapterResolver/resolveAdapter.ts"],"names":[],"mappings":"AACA,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,+BAA+B,GAChC,MAAM,2BAA2B,CAAA;AAElC,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,QAAiC,EACjC,WAA0C,EACjC,EAAE;IACX,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,yBAAyB,EAAE,CAAA;IACvC,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,+BAA+B,CAAC,WAAW,CAAC,CAAA;IACxD,CAAC;IAED,MAAM,iBAAiB,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAW,CAAA;IAE/F,MAAM,OAAO,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAAA;IAE3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,0BAA0B,CAAC,iBAAiB,CAAC,CAAA;IACzD,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
@@ -0,0 +1,55 @@
1
+ import { AbstractController, type BuildRoutesReturnType } from 'opinionated-machine';
2
+ import type { ConnectorShellDependencies } from '../ConnectorShellModule.ts';
3
+ import '../commonTypes.ts';
4
+ type AuthControllerContractsType = typeof AuthController.contracts;
5
+ export declare class AuthController extends AbstractController<AuthControllerContractsType> {
6
+ static contracts: {
7
+ readonly postAuth: import("@lokalise/api-contracts").PayloadRouteDefinition<import("zod/v4").ZodUnion<readonly [import("zod/v4").ZodObject<{
8
+ redirectUrl: import("zod/v4").ZodString;
9
+ state: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
10
+ }, import("zod/v4/core").$strip>, import("zod/v4").ZodOptional<import("zod/v4").ZodNull>]>, import("zod/v4").ZodObject<{}, import("zod/v4/core").$loose>, undefined, undefined, import("zod/v4").ZodObject<{
11
+ 'ce-config': import("zod/v4").ZodString;
12
+ "x-connector-id": import("zod/v4").ZodString;
13
+ }, import("zod/v4/core").$strip>, undefined, false, false, {
14
+ 200: import("zod/v4").ZodObject<{}, import("zod/v4/core").$loose>;
15
+ 403: import("zod/v4").ZodObject<{
16
+ message: import("zod/v4").ZodString;
17
+ statusCode: import("zod/v4").ZodNumber;
18
+ }, import("zod/v4/core").$strip>;
19
+ }>;
20
+ readonly postAuthRefresh: import("@lokalise/api-contracts").PayloadRouteDefinition<import("zod/v4").ZodOptional<import("zod/v4").ZodNull>, import("zod/v4").ZodObject<{}, import("zod/v4/core").$loose>, undefined, undefined, import("zod/v4").ZodObject<{
21
+ 'ce-config': import("zod/v4").ZodString;
22
+ 'ce-auth': import("zod/v4").ZodString;
23
+ "x-connector-id": import("zod/v4").ZodString;
24
+ }, import("zod/v4/core").$strip>, undefined, false, false, {
25
+ 200: import("zod/v4").ZodObject<{}, import("zod/v4/core").$loose>;
26
+ 403: import("zod/v4").ZodObject<{
27
+ message: import("zod/v4").ZodString;
28
+ statusCode: import("zod/v4").ZodNumber;
29
+ }, import("zod/v4/core").$strip>;
30
+ }>;
31
+ readonly postAuthResponse: import("@lokalise/api-contracts").PayloadRouteDefinition<import("zod/v4").ZodObject<{
32
+ query: import("zod/v4").ZodObject<{}, import("zod/v4/core").$loose>;
33
+ body: import("zod/v4").ZodOptional<import("zod/v4").ZodObject<{}, import("zod/v4/core").$loose>>;
34
+ redirectUrl: import("zod/v4").ZodString;
35
+ }, import("zod/v4/core").$strip>, import("zod/v4").ZodObject<{}, import("zod/v4/core").$loose>, undefined, undefined, import("zod/v4").ZodObject<{
36
+ 'ce-config': import("zod/v4").ZodString;
37
+ "x-connector-id": import("zod/v4").ZodString;
38
+ }, import("zod/v4/core").$strip>, undefined, false, false, {
39
+ 200: import("zod/v4").ZodObject<{}, import("zod/v4/core").$loose>;
40
+ 403: import("zod/v4").ZodObject<{
41
+ message: import("zod/v4").ZodString;
42
+ errorCode: import("zod/v4").ZodNumber;
43
+ details: import("zod/v4").ZodObject<{}, import("zod/v4/core").$loose>;
44
+ }, import("zod/v4/core").$strip>;
45
+ }>;
46
+ };
47
+ private readonly adapters;
48
+ private readonly protectedRouteMetadataMapper;
49
+ constructor(dependencies: ConnectorShellDependencies);
50
+ private get postAuth();
51
+ private get postAuthRefresh();
52
+ private get postAuthResponse();
53
+ buildRoutes(): BuildRoutesReturnType<AuthControllerContractsType>;
54
+ }
55
+ export {};
@@ -0,0 +1,73 @@
1
+ import { OAuthNotSupportedError } from '@lokalise/connector-adapter-common';
2
+ import { CONNECTOR_ID_HEADER, postAuthContract, postAuthRefreshContract, postAuthResponseContract, } from '@lokalise/connector-api-contracts';
3
+ import { buildFastifyPayloadRoute } from '@lokalise/fastify-api-contracts';
4
+ import { InternalError } from '@lokalise/node-core';
5
+ import { AbstractController } from 'opinionated-machine';
6
+ import { resolveAdapter } from "../adapterResolver/resolveAdapter.js";
7
+ import "../commonTypes.js";
8
+ export class AuthController extends AbstractController {
9
+ static contracts = {
10
+ postAuth: postAuthContract,
11
+ postAuthRefresh: postAuthRefreshContract,
12
+ postAuthResponse: postAuthResponseContract,
13
+ };
14
+ adapters;
15
+ protectedRouteMetadataMapper;
16
+ constructor(dependencies) {
17
+ super();
18
+ this.adapters = dependencies.adapters;
19
+ this.protectedRouteMetadataMapper = dependencies.protectedRouteMetadataMapperFactory;
20
+ }
21
+ get postAuth() {
22
+ return buildFastifyPayloadRoute(postAuthContract, async (req, reply) => {
23
+ const adapter = resolveAdapter(this.adapters, req.headers[CONNECTOR_ID_HEADER]);
24
+ if (adapter.authServiceAPIKey) {
25
+ const authConfig = await adapter.authServiceAPIKey.validate(req.integrationConfig, req.reqContext);
26
+ return reply.send(authConfig);
27
+ }
28
+ if (adapter.authServiceOAuth) {
29
+ const authorizationUrl = await adapter.authServiceOAuth.generateAuthorizationUrl(req.integrationConfig, req.body, req.reqContext);
30
+ return reply.send({
31
+ url: authorizationUrl,
32
+ });
33
+ }
34
+ throw new InternalError({
35
+ message: 'No auth service defined for connector',
36
+ errorCode: 'NO_AUTH_SERVICE_DEFINED',
37
+ details: {
38
+ connectorName: adapter.getConnectorName(),
39
+ },
40
+ });
41
+ }, this.protectedRouteMetadataMapper(false));
42
+ }
43
+ get postAuthRefresh() {
44
+ return buildFastifyPayloadRoute(postAuthRefreshContract, async (req, reply) => {
45
+ const adapter = resolveAdapter(this.adapters, req.headers[CONNECTOR_ID_HEADER]);
46
+ const resolvedAuthService = adapter.authServiceOAuth;
47
+ if (!resolvedAuthService) {
48
+ throw new OAuthNotSupportedError(adapter.getConnectorName());
49
+ }
50
+ const authConfig = await resolvedAuthService.refresh(req.integrationConfig, req.authConfig, req.reqContext);
51
+ return reply.send(authConfig);
52
+ }, this.protectedRouteMetadataMapper());
53
+ }
54
+ get postAuthResponse() {
55
+ return buildFastifyPayloadRoute(postAuthResponseContract, async (req, reply) => {
56
+ const adapter = resolveAdapter(this.adapters, req.headers[CONNECTOR_ID_HEADER]);
57
+ const resolvedAuthService = adapter.authServiceOAuth;
58
+ if (!resolvedAuthService) {
59
+ throw new OAuthNotSupportedError(adapter.getConnectorName());
60
+ }
61
+ const credentials = await resolvedAuthService.getAuthCredentials(req.body, req.reqContext);
62
+ return reply.send(credentials);
63
+ }, this.protectedRouteMetadataMapper(false));
64
+ }
65
+ buildRoutes() {
66
+ return {
67
+ postAuth: this.postAuth,
68
+ postAuthRefresh: this.postAuthRefresh,
69
+ postAuthResponse: this.postAuthResponse,
70
+ };
71
+ }
72
+ }
73
+ //# sourceMappingURL=authController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authController.js","sourceRoot":"","sources":["../../src/auth/authController.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import { AbstractController, type BuildRoutesReturnType } from 'opinionated-machine';
2
+ import type { ConnectorShellDependencies } from '../ConnectorShellModule.ts';
3
+ import '../commonTypes.ts';
4
+ type CacheControllerContractsType = typeof CacheController.contracts;
5
+ export declare class CacheController extends AbstractController<CacheControllerContractsType> {
6
+ static contracts: {
7
+ readonly getCache: import("@lokalise/api-contracts").GetRouteDefinition<import("zod/v4").ZodObject<{
8
+ items: import("zod/v4").ZodArray<import("zod/v4").ZodObject<{
9
+ uniqueId: import("zod/v4").ZodString;
10
+ groupId: import("zod/v4").ZodString;
11
+ metadata: import("zod/v4").ZodRecord<import("zod/v4").ZodAny, import("zod/v4").ZodAny>;
12
+ }, import("zod/v4/core").$strip>>;
13
+ next: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
14
+ hasMore: import("zod/v4").ZodOptional<import("zod/v4").ZodBoolean>;
15
+ nextCursor: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
16
+ }, import("zod/v4/core").$strip>, undefined, import("zod/v4").ZodObject<{
17
+ next: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
18
+ maxItems: import("zod/v4").ZodOptional<import("zod/v4").ZodNumber>;
19
+ cursor: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
20
+ }, import("zod/v4/core").$strip>, import("zod/v4").ZodObject<{
21
+ 'ce-config': import("zod/v4").ZodString;
22
+ 'ce-auth': import("zod/v4").ZodString;
23
+ "x-connector-id": import("zod/v4").ZodString;
24
+ }, import("zod/v4/core").$strip>, import("zod/v4").ZodObject<{
25
+ 'x-continue-after': import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
26
+ }, import("zod/v4/core").$strip>, false, false, {
27
+ 200: import("zod/v4").ZodObject<{
28
+ items: import("zod/v4").ZodArray<import("zod/v4").ZodObject<{
29
+ uniqueId: import("zod/v4").ZodString;
30
+ groupId: import("zod/v4").ZodString;
31
+ metadata: import("zod/v4").ZodRecord<import("zod/v4").ZodAny, import("zod/v4").ZodAny>;
32
+ }, import("zod/v4/core").$strip>>;
33
+ next: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
34
+ hasMore: import("zod/v4").ZodOptional<import("zod/v4").ZodBoolean>;
35
+ nextCursor: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
36
+ }, import("zod/v4/core").$strip>;
37
+ }>;
38
+ readonly postCacheItems: import("@lokalise/api-contracts").PayloadRouteDefinition<import("zod/v4").ZodObject<{
39
+ items: import("zod/v4").ZodOptional<import("zod/v4").ZodArray<import("zod/v4").ZodObject<{
40
+ uniqueId: import("zod/v4").ZodString;
41
+ groupId: import("zod/v4").ZodString;
42
+ metadata: import("zod/v4").ZodRecord<import("zod/v4").ZodAny, import("zod/v4").ZodAny>;
43
+ }, import("zod/v4/core").$strip>>>;
44
+ maxItems: import("zod/v4").ZodOptional<import("zod/v4").ZodNumber>;
45
+ cursor: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
46
+ }, import("zod/v4/core").$strip>, import("zod/v4").ZodObject<{
47
+ items: import("zod/v4").ZodArray<import("zod/v4").ZodObject<{
48
+ uniqueId: import("zod/v4").ZodString;
49
+ groupId: import("zod/v4").ZodString;
50
+ metadata: import("zod/v4").ZodRecord<import("zod/v4").ZodAny, import("zod/v4").ZodAny>;
51
+ fields: import("zod/v4").ZodObject<{}, import("zod/v4/core").$loose>;
52
+ title: import("zod/v4").ZodString;
53
+ groupTitle: import("zod/v4").ZodString;
54
+ }, import("zod/v4/core").$strip>>;
55
+ hasMore: import("zod/v4").ZodOptional<import("zod/v4").ZodBoolean>;
56
+ nextCursor: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
57
+ }, import("zod/v4/core").$strip>, undefined, undefined, import("zod/v4").ZodObject<{
58
+ 'ce-config': import("zod/v4").ZodString;
59
+ 'ce-auth': import("zod/v4").ZodString;
60
+ "x-connector-id": import("zod/v4").ZodString;
61
+ }, import("zod/v4/core").$strip>, import("zod/v4").ZodObject<{
62
+ 'x-continue-after': import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
63
+ }, import("zod/v4/core").$strip>, false, false, {
64
+ 200: import("zod/v4").ZodObject<{
65
+ items: import("zod/v4").ZodArray<import("zod/v4").ZodObject<{
66
+ uniqueId: import("zod/v4").ZodString;
67
+ groupId: import("zod/v4").ZodString;
68
+ metadata: import("zod/v4").ZodRecord<import("zod/v4").ZodAny, import("zod/v4").ZodAny>;
69
+ fields: import("zod/v4").ZodObject<{}, import("zod/v4/core").$loose>;
70
+ title: import("zod/v4").ZodString;
71
+ groupTitle: import("zod/v4").ZodString;
72
+ }, import("zod/v4/core").$strip>>;
73
+ hasMore: import("zod/v4").ZodOptional<import("zod/v4").ZodBoolean>;
74
+ nextCursor: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
75
+ }, import("zod/v4/core").$strip>;
76
+ }>;
77
+ };
78
+ private readonly adapters;
79
+ private readonly protectedRouteMetadataMapper;
80
+ constructor(dependencies: ConnectorShellDependencies);
81
+ private get getCache();
82
+ private get getCacheItems();
83
+ buildRoutes(): BuildRoutesReturnType<CacheControllerContractsType>;
84
+ }
85
+ export {};
@@ -0,0 +1,74 @@
1
+ import { EnhancedCacheFlowNotSupportedError, StandardCacheFlowNotSupportedError, } from '@lokalise/connector-adapter-common';
2
+ import { CONNECTOR_ID_HEADER, getCacheContract, postCacheItemsContract, } from '@lokalise/connector-api-contracts';
3
+ import { buildFastifyNoPayloadRoute, buildFastifyPayloadRoute, } from '@lokalise/fastify-api-contracts';
4
+ import { AbstractController } from 'opinionated-machine';
5
+ import { resolveAdapter } from "../adapterResolver/resolveAdapter.js";
6
+ import "../commonTypes.js";
7
+ export class CacheController extends AbstractController {
8
+ static contracts = {
9
+ getCache: getCacheContract,
10
+ postCacheItems: postCacheItemsContract,
11
+ };
12
+ adapters;
13
+ protectedRouteMetadataMapper;
14
+ constructor(dependencies) {
15
+ super();
16
+ this.adapters = dependencies.adapters;
17
+ this.protectedRouteMetadataMapper = dependencies.protectedRouteMetadataMapperFactory;
18
+ }
19
+ get getCache() {
20
+ return buildFastifyNoPayloadRoute(getCacheContract, async (req, reply) => {
21
+ const adapter = resolveAdapter(this.adapters, req.headers[CONNECTOR_ID_HEADER]);
22
+ if (!adapter.cacheService) {
23
+ throw new StandardCacheFlowNotSupportedError(adapter.getConnectorName());
24
+ }
25
+ const { items, nextCursor } = await adapter.cacheService.listItems(req.integrationConfig, req.authConfig, req.reqContext, req.query.next);
26
+ await reply.send({
27
+ items,
28
+ next: nextCursor,
29
+ });
30
+ }, this.protectedRouteMetadataMapper());
31
+ }
32
+ get getCacheItems() {
33
+ return buildFastifyPayloadRoute(postCacheItemsContract, async (req, reply) => {
34
+ const adapter = resolveAdapter(this.adapters, req.headers[CONNECTOR_ID_HEADER]);
35
+ /**
36
+ * postCacheItemsContract contract supports 2 cache refresh flows:
37
+ * - Standard flow with IDs prefetching and passing item IDs in the request body.
38
+ * - Enhanced flow without IDs prefetching, where item IDs are not passed in the request body,
39
+ * instead cursor-based pagination is used.
40
+ *
41
+ * The decision what flow to use is made based on the presence of items in the request body.
42
+ */
43
+ const isEnhancedFlow = req.body.items === undefined;
44
+ if (isEnhancedFlow) {
45
+ // Enhanced flow: cursor-based pagination without ID prefetching
46
+ if (!adapter.cacheServiceEnhanced) {
47
+ throw new EnhancedCacheFlowNotSupportedError(adapter.getConnectorName());
48
+ }
49
+ const result = await adapter.cacheServiceEnhanced.getItems(req.integrationConfig, req.authConfig, {
50
+ cursor: req.body.cursor,
51
+ }, req.reqContext);
52
+ await reply.send(result);
53
+ }
54
+ else {
55
+ // Standard flow: with item IDs prefetching
56
+ if (!adapter.cacheService) {
57
+ throw new StandardCacheFlowNotSupportedError(adapter.getConnectorName());
58
+ }
59
+ const items = await adapter.cacheService.getItems(req.integrationConfig, req.authConfig, req.body.items, // It's safe to assume that items are defined as we're in the standard flow
60
+ req.reqContext);
61
+ await reply.send({
62
+ items,
63
+ });
64
+ }
65
+ }, this.protectedRouteMetadataMapper());
66
+ }
67
+ buildRoutes() {
68
+ return {
69
+ getCache: this.getCache,
70
+ postCacheItems: this.getCacheItems,
71
+ };
72
+ }
73
+ }
74
+ //# sourceMappingURL=cacheController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cacheController.js","sourceRoot":"","sources":["../../src/cache/cacheController.ts"],"names":[],"mappings":"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"}