@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.
- package/README.md +140 -0
- package/dist/ConnectorShellModule.d.ts +59 -0
- package/dist/ConnectorShellModule.js +51 -0
- package/dist/ConnectorShellModule.js.map +1 -0
- package/dist/adapterResolver/errors/adapterErrors.d.ts +10 -0
- package/dist/adapterResolver/errors/adapterErrors.js +40 -0
- package/dist/adapterResolver/errors/adapterErrors.js.map +1 -0
- package/dist/adapterResolver/resolveAdapter.d.ts +2 -0
- package/dist/adapterResolver/resolveAdapter.js +16 -0
- package/dist/adapterResolver/resolveAdapter.js.map +1 -0
- package/dist/auth/authController.d.ts +55 -0
- package/dist/auth/authController.js +73 -0
- package/dist/auth/authController.js.map +1 -0
- package/dist/cache/cacheController.d.ts +85 -0
- package/dist/cache/cacheController.js +74 -0
- package/dist/cache/cacheController.js.map +1 -0
- package/dist/commonTypes.d.ts +17 -0
- package/dist/commonTypes.js +2 -0
- package/dist/commonTypes.js.map +1 -0
- package/dist/env/envController.d.ts +49 -0
- package/dist/env/envController.js +34 -0
- package/dist/env/envController.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/itemGroup/ItemGroupController.d.ts +55 -0
- package/dist/itemGroup/ItemGroupController.js +38 -0
- package/dist/itemGroup/ItemGroupController.js.map +1 -0
- package/dist/itemList/ItemListController.d.ts +68 -0
- package/dist/itemList/ItemListController.js +35 -0
- package/dist/itemList/ItemListController.js.map +1 -0
- package/dist/publish/publishController.d.ts +51 -0
- package/dist/publish/publishController.js +44 -0
- package/dist/publish/publishController.js.map +1 -0
- package/dist/translate/translateController.d.ts +77 -0
- package/dist/translate/translateController.js +30 -0
- package/dist/translate/translateController.js.map +1 -0
- 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,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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"}
|