@open-mercato/shared 0.6.2-develop.3406.1.2b403f40da → 0.6.2-develop.3446.1.bd060c6017
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/dist/lib/version.js +1 -1
- package/dist/lib/version.js.map +1 -1
- package/dist/modules/integrations/types.js +29 -16
- package/dist/modules/integrations/types.js.map +2 -2
- package/package.json +2 -2
- package/src/modules/integrations/__tests__/types.test.ts +46 -0
- package/src/modules/integrations/types.ts +39 -16
package/dist/lib/version.js
CHANGED
package/dist/lib/version.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/version.ts"],
|
|
4
|
-
"sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.6.2-develop.
|
|
4
|
+
"sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.6.2-develop.3446.1.bd060c6017'\nexport const appVersion = APP_VERSION\n"],
|
|
5
5
|
"mappings": "AACO,MAAM,cAAc;AACpB,MAAM,aAAa;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,51 +1,64 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
1
|
+
const GLOBAL_INTEGRATION_REGISTRY_KEY = "__openMercatoIntegrationRegistry__";
|
|
2
|
+
function getIntegrationRegistryState() {
|
|
3
|
+
const globalRegistry = globalThis;
|
|
4
|
+
if (!globalRegistry[GLOBAL_INTEGRATION_REGISTRY_KEY]) {
|
|
5
|
+
globalRegistry[GLOBAL_INTEGRATION_REGISTRY_KEY] = {
|
|
6
|
+
integrations: /* @__PURE__ */ new Map(),
|
|
7
|
+
bundles: /* @__PURE__ */ new Map()
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
return globalRegistry[GLOBAL_INTEGRATION_REGISTRY_KEY];
|
|
11
|
+
}
|
|
3
12
|
function registerIntegration(definition) {
|
|
4
|
-
|
|
13
|
+
getIntegrationRegistryState().integrations.set(definition.id, definition);
|
|
5
14
|
}
|
|
6
15
|
function registerIntegrations(definitions) {
|
|
16
|
+
const registry = getIntegrationRegistryState().integrations;
|
|
7
17
|
for (const definition of definitions) {
|
|
8
|
-
|
|
18
|
+
registry.set(definition.id, definition);
|
|
9
19
|
}
|
|
10
20
|
}
|
|
11
21
|
function registerBundle(bundle) {
|
|
12
|
-
|
|
22
|
+
getIntegrationRegistryState().bundles.set(bundle.id, bundle);
|
|
13
23
|
}
|
|
14
24
|
function registerBundles(bundles) {
|
|
25
|
+
const registry = getIntegrationRegistryState().bundles;
|
|
15
26
|
for (const bundle of bundles) {
|
|
16
|
-
|
|
27
|
+
registry.set(bundle.id, bundle);
|
|
17
28
|
}
|
|
18
29
|
}
|
|
19
30
|
function clearRegisteredIntegrations() {
|
|
20
|
-
|
|
21
|
-
|
|
31
|
+
const registry = getIntegrationRegistryState();
|
|
32
|
+
registry.integrations.clear();
|
|
33
|
+
registry.bundles.clear();
|
|
22
34
|
}
|
|
23
35
|
function getIntegration(integrationId) {
|
|
24
|
-
return
|
|
36
|
+
return getIntegrationRegistryState().integrations.get(integrationId);
|
|
25
37
|
}
|
|
26
38
|
function getAllIntegrations() {
|
|
27
|
-
return Array.from(
|
|
39
|
+
return Array.from(getIntegrationRegistryState().integrations.values());
|
|
28
40
|
}
|
|
29
41
|
function getBundle(bundleId) {
|
|
30
|
-
return
|
|
42
|
+
return getIntegrationRegistryState().bundles.get(bundleId);
|
|
31
43
|
}
|
|
32
44
|
function getAllBundles() {
|
|
33
|
-
return Array.from(
|
|
45
|
+
return Array.from(getIntegrationRegistryState().bundles.values());
|
|
34
46
|
}
|
|
35
47
|
function getBundleIntegrations(bundleId) {
|
|
36
|
-
return Array.from(
|
|
48
|
+
return Array.from(getIntegrationRegistryState().integrations.values()).filter((integration) => integration.bundleId === bundleId);
|
|
37
49
|
}
|
|
38
50
|
function resolveIntegrationCredentialsSchema(integrationId) {
|
|
39
|
-
const
|
|
51
|
+
const registry = getIntegrationRegistryState();
|
|
52
|
+
const definition = registry.integrations.get(integrationId);
|
|
40
53
|
if (!definition) return void 0;
|
|
41
54
|
if (definition.credentials && definition.credentials.fields.length > 0) {
|
|
42
55
|
return definition.credentials;
|
|
43
56
|
}
|
|
44
57
|
if (!definition.bundleId) return definition.credentials;
|
|
45
|
-
return
|
|
58
|
+
return registry.bundles.get(definition.bundleId)?.credentials;
|
|
46
59
|
}
|
|
47
60
|
function getIntegrationTitle(integrationId) {
|
|
48
|
-
return
|
|
61
|
+
return getIntegrationRegistryState().integrations.get(integrationId)?.title ?? integrationId;
|
|
49
62
|
}
|
|
50
63
|
const LEGACY_INTEGRATION_DETAIL_TABS_SPOT_ID = "integrations.detail:tabs";
|
|
51
64
|
function buildIntegrationDetailWidgetSpotId(integrationId) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/integrations/types.ts"],
|
|
4
|
-
"sourcesContent": ["export type IntegrationScope = {\n organizationId: string\n tenantId: string\n}\n\nexport type IntegrationCategory =\n | 'payment'\n | 'shipping'\n | 'data_sync'\n | 'communication'\n | 'webhook'\n | 'storage'\n | 'other'\n\nexport type IntegrationHubId =\n | 'payment_gateways'\n | 'shipping_carriers'\n | 'data_sync'\n | 'communication_channels'\n | 'webhook_endpoints'\n | 'storage_hubs'\n | string\n\nexport type CredentialFieldType =\n | 'text'\n | 'secret'\n | 'select'\n | 'boolean'\n | 'url'\n | 'oauth'\n | 'ssh_keypair'\n\nexport interface CredentialFieldOption {\n value: string\n label: string\n}\n\nexport interface CredentialFieldVisibleWhen {\n field: string\n equals: string | number | boolean\n}\n\nexport interface IntegrationCredentialWebhookHelp {\n kind: 'webhook_setup'\n title: string\n summary: string\n endpointPath: string\n dashboardPathLabel: string\n steps: string[]\n events?: string[]\n localDevelopment?: {\n tunnelCommand: string\n publicUrlExample: string\n note?: string\n }\n}\n\nexport interface IntegrationCredentialFieldBase {\n key: string\n label: string\n required?: boolean\n placeholder?: string\n helpText?: string\n helpDetails?: IntegrationCredentialWebhookHelp\n visibleWhen?: CredentialFieldVisibleWhen\n}\n\nexport interface IntegrationCredentialFieldText extends IntegrationCredentialFieldBase {\n type: Extract<CredentialFieldType, 'text' | 'secret' | 'url'>\n}\n\nexport interface IntegrationCredentialFieldBoolean extends IntegrationCredentialFieldBase {\n type: Extract<CredentialFieldType, 'boolean'>\n}\n\nexport interface IntegrationCredentialFieldSelect extends IntegrationCredentialFieldBase {\n type: Extract<CredentialFieldType, 'select'>\n options: CredentialFieldOption[]\n}\n\nexport interface IntegrationCredentialFieldOauth extends IntegrationCredentialFieldBase {\n type: Extract<CredentialFieldType, 'oauth'>\n authUrl?: string\n tokenUrl?: string\n scopes?: string[]\n clientIdField?: string\n clientSecretField?: string\n}\n\nexport interface IntegrationCredentialFieldSshKeypair extends IntegrationCredentialFieldBase {\n type: Extract<CredentialFieldType, 'ssh_keypair'>\n algorithm?: 'ed25519' | 'rsa'\n rsaBits?: 2048 | 3072 | 4096\n}\n\nexport type IntegrationCredentialField =\n | IntegrationCredentialFieldText\n | IntegrationCredentialFieldBoolean\n | IntegrationCredentialFieldSelect\n | IntegrationCredentialFieldOauth\n | IntegrationCredentialFieldSshKeypair\n\nexport interface IntegrationCredentialsSchema {\n fields: IntegrationCredentialField[]\n}\n\nexport interface IntegrationHealthCheckConfig {\n service: string\n}\n\nexport interface ApiVersionDefinition {\n id: string\n label: string\n status: 'stable' | 'deprecated' | 'experimental'\n default?: boolean\n changelog?: string\n deprecatedAt?: string\n sunsetAt?: string\n migrationGuide?: string\n}\n\nexport interface IntegrationBundle {\n id: string\n title: string\n description: string\n icon?: string\n package?: string\n version?: string\n author?: string\n credentials: IntegrationCredentialsSchema\n healthCheck?: IntegrationHealthCheckConfig\n}\n\nexport interface IntegrationDetailPageConfig {\n /**\n * UMES widget spot rendered on the integration detail page.\n * Widgets registered here can render inline blocks, grouped panels,\n * or additional tabs via `placement.kind`.\n */\n widgetSpotId?: string\n /**\n * Built-in tabs to hide for this integration detail page.\n * Provider modules can replace these with injected tabs using the same spot.\n */\n hiddenTabs?: IntegrationDetailBuiltInTab[]\n}\n\nexport type IntegrationDetailBuiltInTab =\n | 'credentials'\n | 'version'\n | 'health'\n | 'logs'\n | 'data-sync-schedule'\n\nexport interface IntegrationDefaultStateConfig {\n isEnabled?: boolean\n}\n\nexport interface IntegrationDefinition {\n id: string\n title: string\n icon?: string\n buildExternalUrl?: (externalId: string) => string\n bundleId?: string\n apiVersions?: ApiVersionDefinition[]\n description?: string\n category?: IntegrationCategory | string\n hub?: IntegrationHubId\n providerKey?: string\n docsUrl?: string\n package?: string\n version?: string\n author?: string\n company?: string\n license?: string\n tags?: string[]\n detailPage?: IntegrationDetailPageConfig\n defaultState?: IntegrationDefaultStateConfig\n credentials?: IntegrationCredentialsSchema\n healthCheck?: IntegrationHealthCheckConfig\n}\n\nexport interface ExternalIdEnrichment {\n _integrations: Record<string, ExternalIdMapping>\n}\n\nexport interface ExternalIdMapping {\n externalId: string\n externalUrl?: string\n lastSyncedAt?: string\n syncStatus: 'synced' | 'pending' | 'error' | 'not_synced'\n}\n\
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["export type IntegrationScope = {\n organizationId: string\n tenantId: string\n}\n\nexport type IntegrationCategory =\n | 'payment'\n | 'shipping'\n | 'data_sync'\n | 'communication'\n | 'webhook'\n | 'storage'\n | 'other'\n\nexport type IntegrationHubId =\n | 'payment_gateways'\n | 'shipping_carriers'\n | 'data_sync'\n | 'communication_channels'\n | 'webhook_endpoints'\n | 'storage_hubs'\n | string\n\nexport type CredentialFieldType =\n | 'text'\n | 'secret'\n | 'select'\n | 'boolean'\n | 'url'\n | 'oauth'\n | 'ssh_keypair'\n\nexport interface CredentialFieldOption {\n value: string\n label: string\n}\n\nexport interface CredentialFieldVisibleWhen {\n field: string\n equals: string | number | boolean\n}\n\nexport interface IntegrationCredentialWebhookHelp {\n kind: 'webhook_setup'\n title: string\n summary: string\n endpointPath: string\n dashboardPathLabel: string\n steps: string[]\n events?: string[]\n localDevelopment?: {\n tunnelCommand: string\n publicUrlExample: string\n note?: string\n }\n}\n\nexport interface IntegrationCredentialFieldBase {\n key: string\n label: string\n required?: boolean\n placeholder?: string\n helpText?: string\n helpDetails?: IntegrationCredentialWebhookHelp\n visibleWhen?: CredentialFieldVisibleWhen\n}\n\nexport interface IntegrationCredentialFieldText extends IntegrationCredentialFieldBase {\n type: Extract<CredentialFieldType, 'text' | 'secret' | 'url'>\n}\n\nexport interface IntegrationCredentialFieldBoolean extends IntegrationCredentialFieldBase {\n type: Extract<CredentialFieldType, 'boolean'>\n}\n\nexport interface IntegrationCredentialFieldSelect extends IntegrationCredentialFieldBase {\n type: Extract<CredentialFieldType, 'select'>\n options: CredentialFieldOption[]\n}\n\nexport interface IntegrationCredentialFieldOauth extends IntegrationCredentialFieldBase {\n type: Extract<CredentialFieldType, 'oauth'>\n authUrl?: string\n tokenUrl?: string\n scopes?: string[]\n clientIdField?: string\n clientSecretField?: string\n}\n\nexport interface IntegrationCredentialFieldSshKeypair extends IntegrationCredentialFieldBase {\n type: Extract<CredentialFieldType, 'ssh_keypair'>\n algorithm?: 'ed25519' | 'rsa'\n rsaBits?: 2048 | 3072 | 4096\n}\n\nexport type IntegrationCredentialField =\n | IntegrationCredentialFieldText\n | IntegrationCredentialFieldBoolean\n | IntegrationCredentialFieldSelect\n | IntegrationCredentialFieldOauth\n | IntegrationCredentialFieldSshKeypair\n\nexport interface IntegrationCredentialsSchema {\n fields: IntegrationCredentialField[]\n}\n\nexport interface IntegrationHealthCheckConfig {\n service: string\n}\n\nexport interface ApiVersionDefinition {\n id: string\n label: string\n status: 'stable' | 'deprecated' | 'experimental'\n default?: boolean\n changelog?: string\n deprecatedAt?: string\n sunsetAt?: string\n migrationGuide?: string\n}\n\nexport interface IntegrationBundle {\n id: string\n title: string\n description: string\n icon?: string\n package?: string\n version?: string\n author?: string\n credentials: IntegrationCredentialsSchema\n healthCheck?: IntegrationHealthCheckConfig\n}\n\nexport interface IntegrationDetailPageConfig {\n /**\n * UMES widget spot rendered on the integration detail page.\n * Widgets registered here can render inline blocks, grouped panels,\n * or additional tabs via `placement.kind`.\n */\n widgetSpotId?: string\n /**\n * Built-in tabs to hide for this integration detail page.\n * Provider modules can replace these with injected tabs using the same spot.\n */\n hiddenTabs?: IntegrationDetailBuiltInTab[]\n}\n\nexport type IntegrationDetailBuiltInTab =\n | 'credentials'\n | 'version'\n | 'health'\n | 'logs'\n | 'data-sync-schedule'\n\nexport interface IntegrationDefaultStateConfig {\n isEnabled?: boolean\n}\n\nexport interface IntegrationDefinition {\n id: string\n title: string\n icon?: string\n buildExternalUrl?: (externalId: string) => string\n bundleId?: string\n apiVersions?: ApiVersionDefinition[]\n description?: string\n category?: IntegrationCategory | string\n hub?: IntegrationHubId\n providerKey?: string\n docsUrl?: string\n package?: string\n version?: string\n author?: string\n company?: string\n license?: string\n tags?: string[]\n detailPage?: IntegrationDetailPageConfig\n defaultState?: IntegrationDefaultStateConfig\n credentials?: IntegrationCredentialsSchema\n healthCheck?: IntegrationHealthCheckConfig\n}\n\nexport interface ExternalIdEnrichment {\n _integrations: Record<string, ExternalIdMapping>\n}\n\nexport interface ExternalIdMapping {\n externalId: string\n externalUrl?: string\n lastSyncedAt?: string\n syncStatus: 'synced' | 'pending' | 'error' | 'not_synced'\n}\n\ntype IntegrationRegistryState = {\n integrations: Map<string, IntegrationDefinition>\n bundles: Map<string, IntegrationBundle>\n}\n\nconst GLOBAL_INTEGRATION_REGISTRY_KEY = '__openMercatoIntegrationRegistry__' as const\n\ntype GlobalIntegrationRegistry = typeof globalThis & {\n [GLOBAL_INTEGRATION_REGISTRY_KEY]?: IntegrationRegistryState\n}\n\nfunction getIntegrationRegistryState(): IntegrationRegistryState {\n const globalRegistry = globalThis as GlobalIntegrationRegistry\n if (!globalRegistry[GLOBAL_INTEGRATION_REGISTRY_KEY]) {\n globalRegistry[GLOBAL_INTEGRATION_REGISTRY_KEY] = {\n integrations: new Map<string, IntegrationDefinition>(),\n bundles: new Map<string, IntegrationBundle>(),\n }\n }\n return globalRegistry[GLOBAL_INTEGRATION_REGISTRY_KEY]\n}\n\nexport function registerIntegration(definition: IntegrationDefinition): void {\n getIntegrationRegistryState().integrations.set(definition.id, definition)\n}\n\nexport function registerIntegrations(definitions: IntegrationDefinition[]): void {\n const registry = getIntegrationRegistryState().integrations\n for (const definition of definitions) {\n registry.set(definition.id, definition)\n }\n}\n\nexport function registerBundle(bundle: IntegrationBundle): void {\n getIntegrationRegistryState().bundles.set(bundle.id, bundle)\n}\n\nexport function registerBundles(bundles: IntegrationBundle[]): void {\n const registry = getIntegrationRegistryState().bundles\n for (const bundle of bundles) {\n registry.set(bundle.id, bundle)\n }\n}\n\nexport function clearRegisteredIntegrations(): void {\n const registry = getIntegrationRegistryState()\n registry.integrations.clear()\n registry.bundles.clear()\n}\n\nexport function getIntegration(integrationId: string): IntegrationDefinition | undefined {\n return getIntegrationRegistryState().integrations.get(integrationId)\n}\n\nexport function getAllIntegrations(): IntegrationDefinition[] {\n return Array.from(getIntegrationRegistryState().integrations.values())\n}\n\nexport function getBundle(bundleId: string): IntegrationBundle | undefined {\n return getIntegrationRegistryState().bundles.get(bundleId)\n}\n\nexport function getAllBundles(): IntegrationBundle[] {\n return Array.from(getIntegrationRegistryState().bundles.values())\n}\n\nexport function getBundleIntegrations(bundleId: string): IntegrationDefinition[] {\n return Array.from(getIntegrationRegistryState().integrations.values()).filter((integration) => integration.bundleId === bundleId)\n}\n\nexport function resolveIntegrationCredentialsSchema(integrationId: string): IntegrationCredentialsSchema | undefined {\n const registry = getIntegrationRegistryState()\n const definition = registry.integrations.get(integrationId)\n if (!definition) return undefined\n\n if (definition.credentials && definition.credentials.fields.length > 0) {\n return definition.credentials\n }\n\n if (!definition.bundleId) return definition.credentials\n return registry.bundles.get(definition.bundleId)?.credentials\n}\n\nexport function getIntegrationTitle(integrationId: string): string {\n return getIntegrationRegistryState().integrations.get(integrationId)?.title ?? integrationId\n}\n\nexport const LEGACY_INTEGRATION_DETAIL_TABS_SPOT_ID = 'integrations.detail:tabs'\n\nexport function buildIntegrationDetailWidgetSpotId(integrationId: string): string {\n return `integrations.detail:${integrationId}`\n}\n"],
|
|
5
|
+
"mappings": "AAsMA,MAAM,kCAAkC;AAMxC,SAAS,8BAAwD;AAC/D,QAAM,iBAAiB;AACvB,MAAI,CAAC,eAAe,+BAA+B,GAAG;AACpD,mBAAe,+BAA+B,IAAI;AAAA,MAChD,cAAc,oBAAI,IAAmC;AAAA,MACrD,SAAS,oBAAI,IAA+B;AAAA,IAC9C;AAAA,EACF;AACA,SAAO,eAAe,+BAA+B;AACvD;AAEO,SAAS,oBAAoB,YAAyC;AAC3E,8BAA4B,EAAE,aAAa,IAAI,WAAW,IAAI,UAAU;AAC1E;AAEO,SAAS,qBAAqB,aAA4C;AAC/E,QAAM,WAAW,4BAA4B,EAAE;AAC/C,aAAW,cAAc,aAAa;AACpC,aAAS,IAAI,WAAW,IAAI,UAAU;AAAA,EACxC;AACF;AAEO,SAAS,eAAe,QAAiC;AAC9D,8BAA4B,EAAE,QAAQ,IAAI,OAAO,IAAI,MAAM;AAC7D;AAEO,SAAS,gBAAgB,SAAoC;AAClE,QAAM,WAAW,4BAA4B,EAAE;AAC/C,aAAW,UAAU,SAAS;AAC5B,aAAS,IAAI,OAAO,IAAI,MAAM;AAAA,EAChC;AACF;AAEO,SAAS,8BAAoC;AAClD,QAAM,WAAW,4BAA4B;AAC7C,WAAS,aAAa,MAAM;AAC5B,WAAS,QAAQ,MAAM;AACzB;AAEO,SAAS,eAAe,eAA0D;AACvF,SAAO,4BAA4B,EAAE,aAAa,IAAI,aAAa;AACrE;AAEO,SAAS,qBAA8C;AAC5D,SAAO,MAAM,KAAK,4BAA4B,EAAE,aAAa,OAAO,CAAC;AACvE;AAEO,SAAS,UAAU,UAAiD;AACzE,SAAO,4BAA4B,EAAE,QAAQ,IAAI,QAAQ;AAC3D;AAEO,SAAS,gBAAqC;AACnD,SAAO,MAAM,KAAK,4BAA4B,EAAE,QAAQ,OAAO,CAAC;AAClE;AAEO,SAAS,sBAAsB,UAA2C;AAC/E,SAAO,MAAM,KAAK,4BAA4B,EAAE,aAAa,OAAO,CAAC,EAAE,OAAO,CAAC,gBAAgB,YAAY,aAAa,QAAQ;AAClI;AAEO,SAAS,oCAAoC,eAAiE;AACnH,QAAM,WAAW,4BAA4B;AAC7C,QAAM,aAAa,SAAS,aAAa,IAAI,aAAa;AAC1D,MAAI,CAAC,WAAY,QAAO;AAExB,MAAI,WAAW,eAAe,WAAW,YAAY,OAAO,SAAS,GAAG;AACtE,WAAO,WAAW;AAAA,EACpB;AAEA,MAAI,CAAC,WAAW,SAAU,QAAO,WAAW;AAC5C,SAAO,SAAS,QAAQ,IAAI,WAAW,QAAQ,GAAG;AACpD;AAEO,SAAS,oBAAoB,eAA+B;AACjE,SAAO,4BAA4B,EAAE,aAAa,IAAI,aAAa,GAAG,SAAS;AACjF;AAEO,MAAM,yCAAyC;AAE/C,SAAS,mCAAmC,eAA+B;AAChF,SAAO,uBAAuB,aAAa;AAC7C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/shared",
|
|
3
|
-
"version": "0.6.2-develop.
|
|
3
|
+
"version": "0.6.2-develop.3446.1.bd060c6017",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"@mikro-orm/core": "^7.0.15",
|
|
93
93
|
"@mikro-orm/decorators": "^7.0.15",
|
|
94
94
|
"@mikro-orm/postgresql": "^7.0.15",
|
|
95
|
-
"@open-mercato/cache": "0.6.2-develop.
|
|
95
|
+
"@open-mercato/cache": "0.6.2-develop.3446.1.bd060c6017",
|
|
96
96
|
"dotenv": "^17.4.2",
|
|
97
97
|
"rate-limiter-flexible": "^11.1.0",
|
|
98
98
|
"reflect-metadata": "^0.2.2",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type * as IntegrationTypes from '../types'
|
|
2
|
+
|
|
3
|
+
describe('integration registry', () => {
|
|
4
|
+
afterEach(() => {
|
|
5
|
+
jest.requireActual<typeof IntegrationTypes>('../types').clearRegisteredIntegrations()
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
it('shares registrations across isolated module instances', () => {
|
|
9
|
+
let firstRegistry: typeof IntegrationTypes | undefined
|
|
10
|
+
let secondRegistry: typeof IntegrationTypes | undefined
|
|
11
|
+
|
|
12
|
+
jest.isolateModules(() => {
|
|
13
|
+
firstRegistry = jest.requireActual<typeof IntegrationTypes>('../types')
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
firstRegistry?.clearRegisteredIntegrations()
|
|
17
|
+
firstRegistry?.registerIntegration({
|
|
18
|
+
id: 'sync_excel',
|
|
19
|
+
title: 'Excel / CSV Import',
|
|
20
|
+
providerKey: 'excel',
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
jest.isolateModules(() => {
|
|
24
|
+
secondRegistry = jest.requireActual<typeof IntegrationTypes>('../types')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
expect(secondRegistry?.getIntegration('sync_excel')?.providerKey).toBe('excel')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('clears bundles and integrations from the shared registry state', () => {
|
|
31
|
+
const registry = jest.requireActual<typeof IntegrationTypes>('../types')
|
|
32
|
+
|
|
33
|
+
registry.registerIntegration({ id: 'sync_excel', title: 'Excel / CSV Import' })
|
|
34
|
+
registry.registerBundle({
|
|
35
|
+
id: 'bundle_1',
|
|
36
|
+
title: 'Bundle',
|
|
37
|
+
description: 'Bundle description',
|
|
38
|
+
credentials: { fields: [] },
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
registry.clearRegisteredIntegrations()
|
|
42
|
+
|
|
43
|
+
expect(registry.getAllIntegrations()).toEqual([])
|
|
44
|
+
expect(registry.getAllBundles()).toEqual([])
|
|
45
|
+
})
|
|
46
|
+
})
|
|
@@ -191,56 +191,79 @@ export interface ExternalIdMapping {
|
|
|
191
191
|
syncStatus: 'synced' | 'pending' | 'error' | 'not_synced'
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
|
|
195
|
-
|
|
194
|
+
type IntegrationRegistryState = {
|
|
195
|
+
integrations: Map<string, IntegrationDefinition>
|
|
196
|
+
bundles: Map<string, IntegrationBundle>
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const GLOBAL_INTEGRATION_REGISTRY_KEY = '__openMercatoIntegrationRegistry__' as const
|
|
200
|
+
|
|
201
|
+
type GlobalIntegrationRegistry = typeof globalThis & {
|
|
202
|
+
[GLOBAL_INTEGRATION_REGISTRY_KEY]?: IntegrationRegistryState
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function getIntegrationRegistryState(): IntegrationRegistryState {
|
|
206
|
+
const globalRegistry = globalThis as GlobalIntegrationRegistry
|
|
207
|
+
if (!globalRegistry[GLOBAL_INTEGRATION_REGISTRY_KEY]) {
|
|
208
|
+
globalRegistry[GLOBAL_INTEGRATION_REGISTRY_KEY] = {
|
|
209
|
+
integrations: new Map<string, IntegrationDefinition>(),
|
|
210
|
+
bundles: new Map<string, IntegrationBundle>(),
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return globalRegistry[GLOBAL_INTEGRATION_REGISTRY_KEY]
|
|
214
|
+
}
|
|
196
215
|
|
|
197
216
|
export function registerIntegration(definition: IntegrationDefinition): void {
|
|
198
|
-
|
|
217
|
+
getIntegrationRegistryState().integrations.set(definition.id, definition)
|
|
199
218
|
}
|
|
200
219
|
|
|
201
220
|
export function registerIntegrations(definitions: IntegrationDefinition[]): void {
|
|
221
|
+
const registry = getIntegrationRegistryState().integrations
|
|
202
222
|
for (const definition of definitions) {
|
|
203
|
-
|
|
223
|
+
registry.set(definition.id, definition)
|
|
204
224
|
}
|
|
205
225
|
}
|
|
206
226
|
|
|
207
227
|
export function registerBundle(bundle: IntegrationBundle): void {
|
|
208
|
-
|
|
228
|
+
getIntegrationRegistryState().bundles.set(bundle.id, bundle)
|
|
209
229
|
}
|
|
210
230
|
|
|
211
231
|
export function registerBundles(bundles: IntegrationBundle[]): void {
|
|
232
|
+
const registry = getIntegrationRegistryState().bundles
|
|
212
233
|
for (const bundle of bundles) {
|
|
213
|
-
|
|
234
|
+
registry.set(bundle.id, bundle)
|
|
214
235
|
}
|
|
215
236
|
}
|
|
216
237
|
|
|
217
238
|
export function clearRegisteredIntegrations(): void {
|
|
218
|
-
|
|
219
|
-
|
|
239
|
+
const registry = getIntegrationRegistryState()
|
|
240
|
+
registry.integrations.clear()
|
|
241
|
+
registry.bundles.clear()
|
|
220
242
|
}
|
|
221
243
|
|
|
222
244
|
export function getIntegration(integrationId: string): IntegrationDefinition | undefined {
|
|
223
|
-
return
|
|
245
|
+
return getIntegrationRegistryState().integrations.get(integrationId)
|
|
224
246
|
}
|
|
225
247
|
|
|
226
248
|
export function getAllIntegrations(): IntegrationDefinition[] {
|
|
227
|
-
return Array.from(
|
|
249
|
+
return Array.from(getIntegrationRegistryState().integrations.values())
|
|
228
250
|
}
|
|
229
251
|
|
|
230
252
|
export function getBundle(bundleId: string): IntegrationBundle | undefined {
|
|
231
|
-
return
|
|
253
|
+
return getIntegrationRegistryState().bundles.get(bundleId)
|
|
232
254
|
}
|
|
233
255
|
|
|
234
256
|
export function getAllBundles(): IntegrationBundle[] {
|
|
235
|
-
return Array.from(
|
|
257
|
+
return Array.from(getIntegrationRegistryState().bundles.values())
|
|
236
258
|
}
|
|
237
259
|
|
|
238
260
|
export function getBundleIntegrations(bundleId: string): IntegrationDefinition[] {
|
|
239
|
-
return Array.from(
|
|
261
|
+
return Array.from(getIntegrationRegistryState().integrations.values()).filter((integration) => integration.bundleId === bundleId)
|
|
240
262
|
}
|
|
241
263
|
|
|
242
264
|
export function resolveIntegrationCredentialsSchema(integrationId: string): IntegrationCredentialsSchema | undefined {
|
|
243
|
-
const
|
|
265
|
+
const registry = getIntegrationRegistryState()
|
|
266
|
+
const definition = registry.integrations.get(integrationId)
|
|
244
267
|
if (!definition) return undefined
|
|
245
268
|
|
|
246
269
|
if (definition.credentials && definition.credentials.fields.length > 0) {
|
|
@@ -248,11 +271,11 @@ export function resolveIntegrationCredentialsSchema(integrationId: string): Inte
|
|
|
248
271
|
}
|
|
249
272
|
|
|
250
273
|
if (!definition.bundleId) return definition.credentials
|
|
251
|
-
return
|
|
274
|
+
return registry.bundles.get(definition.bundleId)?.credentials
|
|
252
275
|
}
|
|
253
276
|
|
|
254
277
|
export function getIntegrationTitle(integrationId: string): string {
|
|
255
|
-
return
|
|
278
|
+
return getIntegrationRegistryState().integrations.get(integrationId)?.title ?? integrationId
|
|
256
279
|
}
|
|
257
280
|
|
|
258
281
|
export const LEGACY_INTEGRATION_DETAIL_TABS_SPOT_ID = 'integrations.detail:tabs'
|