@lokalise/connector-shell
v2.1.0
Published
Connector shell module with controllers for Lokalise Content Engine connectors
Readme
@lokalise/connector-shell
A drop-in module for opinionated-machine services that provides the connector shell infrastructure for Lokalise Content Engine connectors.
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.
Features
- Drop-in Integration: Add to your modules list alongside adapter modules
- Automatic Adapter Discovery: Finds adapters via DI tags (
ADAPTER_LABEL = 'connectorAdapter') - Complete Controller Suite: All 7 standard controllers included
- Type-Safe: Full TypeScript support
Installation
npm install @lokalise/connector-shellQuick Start
// modules.ts
export const ALL_MODULES = [
new CommonModule(), // Provides required dependencies
new YourAdapterModule(), // Registers adapters with ADAPTER_LABEL tag
new ConnectorShellModule(), // Discovers adapters, registers controllers
]Required Dependencies
Your CommonModule must provide:
import { ADAPTER_LABEL } from '@lokalise/connector-adapter-common'
import type { ProtectedRouteMetadataMapperFactory } from '@lokalise/connector-shell'
export class CommonModule extends AbstractModule<CommonDependencies> {
resolveDependencies() {
return {
awilixManager: asSingletonFunction((deps) => deps.app?.awilixManager),
protectedRouteMetadataMapperFactory: asSingletonFunction(
(): ProtectedRouteMetadataMapperFactory => PROTECTED_ROUTE_METADATA_MAPPER
),
}
}
}
export interface CommonDependencies {
awilixManager: AwilixManager
protectedRouteMetadataMapperFactory: ProtectedRouteMetadataMapperFactory
}Example prehandler:
// prehandlers/integrationConfigPrehandler.ts
export const PROTECTED_ROUTE_METADATA_MAPPER = (requireAuthConfig = true) =>
(() => ({
preHandler: (req, res, done) => {
// Decode ce-config and ce-auth headers, attach to req
done()
}
})) satisfies ApiContractMetadataToRouteMapperAdapter Discovery
Adapters are discovered via the ADAPTER_LABEL tag:
import { ADAPTER_LABEL, type Adapter } from '@lokalise/connector-adapter-common'
import { AbstractModule, asSingletonClass } from 'opinionated-machine'
export class YourAdapterModule extends AbstractModule<YourDependencies> {
resolveDependencies() {
return {
yourApiClient: asSingletonClass(YourApiClient),
yourAdapter: asSingletonClass(YourAdapter, {
tags: [ADAPTER_LABEL], // <-- Required for discovery
}),
}
}
}How it works:
ADAPTER_LABEL = 'connectorAdapter'(constant from@lokalise/connector-adapter-common)- ConnectorShellModule queries
awilixManager.getWithTags([ADAPTER_LABEL])to find all adapters - Adapters are keyed by
adapter.getConnectorName()value - Controllers resolve adapters per-request via
ce-connector-idheader
Creating Your ConnectorShellModule
import {
ConnectorShellModule as BaseConnectorShellModule,
type ConnectorShellBaseDependencies,
} from '@lokalise/connector-shell'
export type SupportedConnectors =
| typeof YourAdapter.connectorName
| 'another-connector'
export type ConnectorShellInjectableDependencies =
ConnectorShellBaseDependencies &
CommonDependencies &
YourAdapterPublicDependencies
export class ConnectorShellModule extends BaseConnectorShellModule<
ConnectorShellInjectableDependencies,
ExternalDependencies
> {}Bootstrap
import { DIContext } from 'opinionated-machine'
import { ALL_MODULES } from './modules'
const diContext = new DIContext(diContainer, options)
diContext.registerDependencies({ modules: ALL_MODULES }, externalDependencies)
app.after(() => {
diContext.registerRoutes(app) // Controllers auto-register
})Adding a New Adapter
- Create adapter implementing
Adapterinterface - Register with
ADAPTER_LABELtag:yourAdapter: asSingletonClass(YourAdapter, { tags: [ADAPTER_LABEL], })
