@endora-commerce/mod-erp-connector 0.100.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/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/backend/entities/erp-connector-activation-lock.entity.d.ts +11 -0
- package/dist/backend/entities/erp-connector-activation-lock.entity.d.ts.map +1 -0
- package/dist/backend/entities/erp-connector-activation-lock.entity.js +42 -0
- package/dist/backend/entities/erp-connector-activation-lock.entity.js.map +1 -0
- package/dist/backend/index.d.ts +5 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +74 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/services/erp-connector-registry.service.d.ts +45 -0
- package/dist/backend/services/erp-connector-registry.service.d.ts.map +1 -0
- package/dist/backend/services/erp-connector-registry.service.js +108 -0
- package/dist/backend/services/erp-connector-registry.service.js.map +1 -0
- package/dist/manifest.d.ts +162 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +34 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260911T120000_erp_connector_init.d.ts +7 -0
- package/dist/migrations/20260911T120000_erp_connector_init.d.ts.map +1 -0
- package/dist/migrations/20260911T120000_erp_connector_init.js +25 -0
- package/dist/migrations/20260911T120000_erp_connector_init.js.map +1 -0
- package/dist/migrations/index.d.ts +4 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +4 -0
- package/dist/migrations/index.js.map +1 -0
- package/i18n/en.json +5 -0
- package/i18n/pl.json +5 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Endora sp. z o.o. and the Endora Commerce contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<!-- Generated by `pnpm --filter backend run manifests:generate`. Delete this line to take the file over; a README without it is never regenerated. -->
|
|
2
|
+
|
|
3
|
+
# @endora-commerce/mod-erp-connector
|
|
4
|
+
|
|
5
|
+
Shared operator behaviours for ERP connectors: mutual exclusion and sync job vocabulary.
|
|
6
|
+
|
|
7
|
+
## What this is
|
|
8
|
+
|
|
9
|
+
An **Endora Commerce module package**. Its module id is `erp_connector` — the identity of record in the platform's registries, in its migrations and in its setting, permission and translation codes.
|
|
10
|
+
|
|
11
|
+
A module is not imported by application code. The platform discovers the extension packages an instance has installed, reads the manifest on the root subpath and composes the module from it, so installing this package and starting the instance is the whole integration.
|
|
12
|
+
|
|
13
|
+
## Entry points
|
|
14
|
+
|
|
15
|
+
| Import | Contents |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `@endora-commerce/mod-erp-connector` | the module manifest — its id, version, dependencies, settings and activation |
|
|
18
|
+
| `@endora-commerce/mod-erp-connector/backend` | the composition root the platform calls, with the entities, services, routes and workers it registers |
|
|
19
|
+
| `@endora-commerce/mod-erp-connector/migrations` | the module’s own schema migrations, in the order the platform runs them |
|
|
20
|
+
|
|
21
|
+
## Depends on
|
|
22
|
+
|
|
23
|
+
Everything below is a **peer** dependency, so the application resolves exactly one copy of each — two copies of a host or of React are a runtime failure rather than a type error. An entry marked *optional* is needed only by the layers that use it.
|
|
24
|
+
|
|
25
|
+
**Endora packages**
|
|
26
|
+
|
|
27
|
+
- `@endora-commerce/contracts`
|
|
28
|
+
- `@endora-commerce/platform`
|
|
29
|
+
|
|
30
|
+
**Third-party**
|
|
31
|
+
|
|
32
|
+
- `@mikro-orm/core` ^6
|
|
33
|
+
- `@mikro-orm/migrations` ^6
|
|
34
|
+
- `@mikro-orm/postgresql` ^6
|
|
35
|
+
|
|
36
|
+
## What the tarball carries
|
|
37
|
+
|
|
38
|
+
- `dist/` — the compiled JavaScript and its type declarations
|
|
39
|
+
- `i18n/` — the translation bundles this package ships (`en`, `pl`), loaded by the platform
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pnpm add @endora-commerce/mod-erp-connector
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Licence
|
|
48
|
+
|
|
49
|
+
MIT — the text is in `LICENSE`, beside this file.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { OptionalProps } from '@mikro-orm/core';
|
|
2
|
+
/** Fixed primary key — one diagnostic row per deployment (feature 119, data-model.md). */
|
|
3
|
+
export declare const ERP_CONNECTOR_ACTIVATION_LOCK_SINGLETON_ID = "00000000-0000-4000-8000-000000000002";
|
|
4
|
+
export declare class ErpConnectorActivationLock {
|
|
5
|
+
[OptionalProps]?: 'updatedAt';
|
|
6
|
+
id: string;
|
|
7
|
+
activeModuleId?: string | null;
|
|
8
|
+
updatedAt: Date;
|
|
9
|
+
updatedByAdminId?: string | null;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=erp-connector-activation-lock.entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"erp-connector-activation-lock.entity.d.ts","sourceRoot":"","sources":["../../../src/backend/entities/erp-connector-activation-lock.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,aAAa,EAAwB,MAAM,iBAAiB,CAAC;AAG9E,0FAA0F;AAC1F,eAAO,MAAM,0CAA0C,yCACf,CAAC;AAEzC,qBAEa,0BAA0B;IACrC,CAAC,aAAa,CAAC,CAAC,EAAE,WAAW,CAAC;IAG9B,EAAE,EAAE,MAAM,CAA8C;IAGxD,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG/B,SAAS,EAAE,IAAI,CAAc;IAG7B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { Entity, OptionalProps, PrimaryKey, Property } from '@mikro-orm/core';
|
|
11
|
+
import { GlobalEntity } from '@endora-commerce/platform/tenancy';
|
|
12
|
+
/** Fixed primary key — one diagnostic row per deployment (feature 119, data-model.md). */
|
|
13
|
+
export const ERP_CONNECTOR_ACTIVATION_LOCK_SINGLETON_ID = '00000000-0000-4000-8000-000000000002';
|
|
14
|
+
let ErpConnectorActivationLock = class ErpConnectorActivationLock {
|
|
15
|
+
[OptionalProps];
|
|
16
|
+
id = ERP_CONNECTOR_ACTIVATION_LOCK_SINGLETON_ID;
|
|
17
|
+
activeModuleId;
|
|
18
|
+
updatedAt = new Date();
|
|
19
|
+
updatedByAdminId;
|
|
20
|
+
};
|
|
21
|
+
__decorate([
|
|
22
|
+
PrimaryKey({ type: 'uuid' }),
|
|
23
|
+
__metadata("design:type", String)
|
|
24
|
+
], ErpConnectorActivationLock.prototype, "id", void 0);
|
|
25
|
+
__decorate([
|
|
26
|
+
Property({ type: 'varchar', length: 64, fieldName: 'active_module_id', nullable: true }),
|
|
27
|
+
__metadata("design:type", Object)
|
|
28
|
+
], ErpConnectorActivationLock.prototype, "activeModuleId", void 0);
|
|
29
|
+
__decorate([
|
|
30
|
+
Property({ type: 'timestamptz', fieldName: 'updated_at' }),
|
|
31
|
+
__metadata("design:type", Date)
|
|
32
|
+
], ErpConnectorActivationLock.prototype, "updatedAt", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
Property({ type: 'uuid', fieldName: 'updated_by_admin_id', nullable: true }),
|
|
35
|
+
__metadata("design:type", Object)
|
|
36
|
+
], ErpConnectorActivationLock.prototype, "updatedByAdminId", void 0);
|
|
37
|
+
ErpConnectorActivationLock = __decorate([
|
|
38
|
+
GlobalEntity(),
|
|
39
|
+
Entity({ tableName: 'erp_connector_activation_lock' })
|
|
40
|
+
], ErpConnectorActivationLock);
|
|
41
|
+
export { ErpConnectorActivationLock };
|
|
42
|
+
//# sourceMappingURL=erp-connector-activation-lock.entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"erp-connector-activation-lock.entity.js","sourceRoot":"","sources":["../../../src/backend/entities/erp-connector-activation-lock.entity.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEjE,0FAA0F;AAC1F,MAAM,CAAC,MAAM,0CAA0C,GACrD,sCAAsC,CAAC;AAIlC,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;IACrC,CAAC,aAAa,CAAC,CAAe;IAG9B,EAAE,GAAW,0CAA0C,CAAC;IAGxD,cAAc,CAAiB;IAG/B,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;IAG7B,gBAAgB,CAAiB;CAClC,CAAA;AAVC;IADC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;sDAC2B;AAGxD;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;kEAC1D;AAG/B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;8BAChD,IAAI;6DAAc;AAG7B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,qBAAqB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;oEAC5C;AAbtB,0BAA0B;IAFtC,YAAY,EAAE;IACd,MAAM,CAAC,EAAE,SAAS,EAAE,+BAA+B,EAAE,CAAC;GAC1C,0BAA0B,CActC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ModuleContext } from '@endora-commerce/platform/kernel';
|
|
2
|
+
import { ErpConnectorActivationLock } from './entities/erp-connector-activation-lock.entity.js';
|
|
3
|
+
export declare function registerModule(ctx: ModuleContext): void;
|
|
4
|
+
export declare const entities: (typeof ErpConnectorActivationLock)[];
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAGtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oDAAoD,CAAC;AA+ChG,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA6CvD;AAED,eAAO,MAAM,QAAQ,uCAA+B,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { effectiveState, lazyPort } from '@endora-commerce/platform/kernel';
|
|
2
|
+
import { CAPABILITY_KEYS } from '@endora-commerce/contracts';
|
|
3
|
+
import { ErpConnectorActivationLock } from './entities/erp-connector-activation-lock.entity.js';
|
|
4
|
+
import { ErpConnectorRegistryService } from './services/erp-connector-registry.service.js';
|
|
5
|
+
/**
|
|
6
|
+
* Feature 132 (T027) — family membership, derived and read when it is asked.
|
|
7
|
+
*
|
|
8
|
+
* This was a union type and a module-level `Set`, both built from
|
|
9
|
+
* `ERP_CONNECTOR_MODULES` at import time. The union was the sharper problem: it
|
|
10
|
+
* made "is this module an ERP connector" a **compile-time** question, so a
|
|
11
|
+
* connector installed from npm or shipped by a deployment's overlay could not be
|
|
12
|
+
* one — which is exactly the population the exclusion has to cover.
|
|
13
|
+
*
|
|
14
|
+
* **Declared** membership, not effective: on a *deactivation* the member is already
|
|
15
|
+
* absent, and an effective-presence test would drop the event that clears the lock.
|
|
16
|
+
*/
|
|
17
|
+
function isErpConnectorModuleId(moduleId) {
|
|
18
|
+
return effectiveState
|
|
19
|
+
.declaredMembersOfCapability(CAPABILITY_KEYS.ERP_CONNECTOR)
|
|
20
|
+
.includes(moduleId);
|
|
21
|
+
}
|
|
22
|
+
function moduleActivationRequest(input) {
|
|
23
|
+
const moduleId = input.params !== null && typeof input.params === 'object' && 'id' in input.params
|
|
24
|
+
? String(input.params.id)
|
|
25
|
+
: '';
|
|
26
|
+
const active = input.body !== null &&
|
|
27
|
+
typeof input.body === 'object' &&
|
|
28
|
+
'active' in input.body &&
|
|
29
|
+
input.body.active === true;
|
|
30
|
+
if (!moduleId || !active || !isErpConnectorModuleId(moduleId))
|
|
31
|
+
return null;
|
|
32
|
+
return { moduleId, active };
|
|
33
|
+
}
|
|
34
|
+
export function registerModule(ctx) {
|
|
35
|
+
ctx.di.providePort('erpConnectorRegistryPort', ctx
|
|
36
|
+
.asFunction(({ emFactory }) => new ErpConnectorRegistryService(emFactory))
|
|
37
|
+
.singleton());
|
|
38
|
+
/**
|
|
39
|
+
* Feature 119 / FR-006 — mutual exclusion on the operator-activation axis for
|
|
40
|
+
* every `erpConnector: true` module. Owned here (always present) so the check
|
|
41
|
+
* runs while any connector is operator-deactivated — exactly when an activation
|
|
42
|
+
* attempt arrives.
|
|
43
|
+
*/
|
|
44
|
+
ctx.interceptors([
|
|
45
|
+
{
|
|
46
|
+
id: 'refuse-when-sibling-erp-active',
|
|
47
|
+
target: 'POST /api/v1/admin/modules/:id/activation',
|
|
48
|
+
phase: 'pre',
|
|
49
|
+
handler: async (interceptorCtx) => {
|
|
50
|
+
const request = moduleActivationRequest(interceptorCtx);
|
|
51
|
+
if (!request)
|
|
52
|
+
return;
|
|
53
|
+
await lazyPort(ctx, 'erpConnectorRegistryPort').assertCanActivate(request.moduleId);
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
]);
|
|
57
|
+
ctx.subscribe('module.activation.changed', async (payload) => {
|
|
58
|
+
const event = payload;
|
|
59
|
+
if (!event.moduleId ||
|
|
60
|
+
typeof event.active !== 'boolean' ||
|
|
61
|
+
!isErpConnectorModuleId(event.moduleId)) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const registry = lazyPort(ctx, 'erpConnectorRegistryPort');
|
|
65
|
+
if (event.active) {
|
|
66
|
+
await registry.recordActive(event.moduleId, null);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
await registry.clearActive(event.moduleId);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export const entities = [ErpConnectorActivationLock];
|
|
74
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAiC,MAAM,4BAA4B,CAAC;AAC5F,OAAO,EAAE,0BAA0B,EAAE,MAAM,oDAAoD,CAAC;AAChG,OAAO,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAW3F;;;;;;;;;;;GAWG;AACH,SAAS,sBAAsB,CAAC,QAAgB;IAC9C,OAAO,cAAc;SAClB,2BAA2B,CAAC,eAAe,CAAC,aAAa,CAAC;SAC1D,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,uBAAuB,CAAC,KAGhC;IACC,MAAM,QAAQ,GACZ,KAAK,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,IAAI,KAAK,CAAC,MAAM;QAC/E,CAAC,CAAC,MAAM,CAAE,KAAK,CAAC,MAA0B,CAAC,EAAE,CAAC;QAC9C,CAAC,CAAC,EAAE,CAAC;IACT,MAAM,MAAM,GACV,KAAK,CAAC,IAAI,KAAK,IAAI;QACnB,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QAC9B,QAAQ,IAAI,KAAK,CAAC,IAAI;QACrB,KAAK,CAAC,IAA4B,CAAC,MAAM,KAAK,IAAI,CAAC;IACtD,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAkB;IAC/C,GAAG,CAAC,EAAE,CAAC,WAAW,CAChB,0BAA0B,EAC1B,GAAG;SACA,UAAU,CAAC,CAAC,EAAE,SAAS,EAAsB,EAAE,EAAE,CAAC,IAAI,2BAA2B,CAAC,SAAS,CAAC,CAAC;SAC7F,SAAS,EAAE,CACf,CAAC;IAEF;;;;;OAKG;IACH,GAAG,CAAC,YAAY,CAAC;QACf;YACE,EAAE,EAAE,gCAAgC;YACpC,MAAM,EAAE,2CAA2C;YACnD,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE,KAAK,EAAE,cAAkD,EAAiB,EAAE;gBACnF,MAAM,OAAO,GAAG,uBAAuB,CAAC,cAAc,CAAC,CAAC;gBACxD,IAAI,CAAC,OAAO;oBAAE,OAAO;gBACrB,MAAM,QAAQ,CAA2B,GAAG,EAAE,0BAA0B,CAAC,CAAC,iBAAiB,CACzF,OAAO,CAAC,QAAQ,CACjB,CAAC;YACJ,CAAC;SACF;KACF,CAAC,CAAC;IAEH,GAAG,CAAC,SAAS,CAAC,2BAA2B,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAC3D,MAAM,KAAK,GAAG,OAAyC,CAAC;QACxD,IACE,CAAC,KAAK,CAAC,QAAQ;YACf,OAAO,KAAK,CAAC,MAAM,KAAK,SAAS;YACjC,CAAC,sBAAsB,CAAC,KAAK,CAAC,QAAQ,CAAC,EACvC,CAAC;YACD,OAAO;QACT,CAAC;QACD,MAAM,QAAQ,GAAG,QAAQ,CAA2B,GAAG,EAAE,0BAA0B,CAAC,CAAC;QACrF,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,0BAA0B,CAAC,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import { type ErpConnectorRegistryPort } from '@endora-commerce/contracts';
|
|
3
|
+
export interface ErpActivationPresenceReader {
|
|
4
|
+
isOperatorActivated(moduleId: string): boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The ERP family, from the members' own manifest declarations.
|
|
8
|
+
*
|
|
9
|
+
* This was `ERP_CONNECTOR_MODULES` in `@endora-commerce/contracts`, and this family
|
|
10
|
+
* is the one whose array carried a live Principle XV violation: an **overlay**
|
|
11
|
+
* module of the `example` deployment had to be written into that core file to join,
|
|
12
|
+
* because there was no other way in. It declares `capabilities` in its own manifest
|
|
13
|
+
* now and core is untouched.
|
|
14
|
+
*/
|
|
15
|
+
export declare function declaredErpConnectorModules(): ReadonlyArray<{
|
|
16
|
+
id: string;
|
|
17
|
+
}>;
|
|
18
|
+
export declare class ErpConnectorRegistryService implements ErpConnectorRegistryPort {
|
|
19
|
+
private readonly emFactory;
|
|
20
|
+
private readonly presence;
|
|
21
|
+
/**
|
|
22
|
+
* A **function**, because the derived family is re-installed by every
|
|
23
|
+
* `b2b:module:state-changed` refresh and a list captured when this singleton was
|
|
24
|
+
* built would answer for the deployment as it was then.
|
|
25
|
+
*/
|
|
26
|
+
private readonly modules;
|
|
27
|
+
constructor(emFactory: () => EntityManager, presence?: ErpActivationPresenceReader,
|
|
28
|
+
/**
|
|
29
|
+
* A **function**, because the derived family is re-installed by every
|
|
30
|
+
* `b2b:module:state-changed` refresh and a list captured when this singleton was
|
|
31
|
+
* built would answer for the deployment as it was then.
|
|
32
|
+
*/
|
|
33
|
+
modules?: ReadonlyArray<{
|
|
34
|
+
id: string;
|
|
35
|
+
}> | (() => ReadonlyArray<{
|
|
36
|
+
id: string;
|
|
37
|
+
}>));
|
|
38
|
+
private connectorModules;
|
|
39
|
+
assertCanActivate(moduleId: string): Promise<void>;
|
|
40
|
+
recordActive(moduleId: string, adminId: string | null): Promise<void>;
|
|
41
|
+
clearActive(moduleId: string): Promise<void>;
|
|
42
|
+
getActiveModuleId(): Promise<string | null>;
|
|
43
|
+
private findActiveSibling;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=erp-connector-registry.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"erp-connector-registry.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/erp-connector-registry.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,4BAA4B,CAAC;AAQpC,MAAM,WAAW,2BAA2B;IAC1C,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;CAChD;AAgBD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,IAAI,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAI3E;AAED,qBAAa,2BAA4B,YAAW,wBAAwB;IAExE,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAPP,SAAS,EAAE,MAAM,aAAa,EAC9B,QAAQ,GAAE,2BAAmD;IAC9E;;;;OAIG;IACc,OAAO,GACpB,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,GAC7B,CAAC,MAAM,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAA+B;IAGzE,OAAO,CAAC,gBAAgB;IAIlB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYlD,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBrE,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5C,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAQjD,OAAO,CAAC,iBAAiB;CAS1B"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { CAPABILITY_KEYS, ERROR_CODES, } from '@endora-commerce/contracts';
|
|
2
|
+
import { effectiveState } from '@endora-commerce/platform/kernel';
|
|
3
|
+
import { HttpError } from '@endora-commerce/platform/http';
|
|
4
|
+
import { ERP_CONNECTOR_ACTIVATION_LOCK_SINGLETON_ID, ErpConnectorActivationLock, } from '../entities/erp-connector-activation-lock.entity.js';
|
|
5
|
+
/**
|
|
6
|
+
* Feature 132 (T027) — **effective** presence, not the activation Setting alone.
|
|
7
|
+
*
|
|
8
|
+
* `presence(moduleId)?.operatorActivated` answers `true` for a module whose
|
|
9
|
+
* platform availability is off, so a connector the deployment never installed held
|
|
10
|
+
* a claim that refused another. `isPresent` is the conjunction Principle XVII
|
|
11
|
+
* means and the one place the two axes are combined (spec FR-012).
|
|
12
|
+
*/
|
|
13
|
+
const defaultPresenceReader = {
|
|
14
|
+
isOperatorActivated(moduleId) {
|
|
15
|
+
return effectiveState.isPresent(moduleId);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* The ERP family, from the members' own manifest declarations.
|
|
20
|
+
*
|
|
21
|
+
* This was `ERP_CONNECTOR_MODULES` in `@endora-commerce/contracts`, and this family
|
|
22
|
+
* is the one whose array carried a live Principle XV violation: an **overlay**
|
|
23
|
+
* module of the `example` deployment had to be written into that core file to join,
|
|
24
|
+
* because there was no other way in. It declares `capabilities` in its own manifest
|
|
25
|
+
* now and core is untouched.
|
|
26
|
+
*/
|
|
27
|
+
export function declaredErpConnectorModules() {
|
|
28
|
+
return effectiveState
|
|
29
|
+
.declaredMembersOfCapability(CAPABILITY_KEYS.ERP_CONNECTOR)
|
|
30
|
+
.map((id) => ({ id }));
|
|
31
|
+
}
|
|
32
|
+
export class ErpConnectorRegistryService {
|
|
33
|
+
emFactory;
|
|
34
|
+
presence;
|
|
35
|
+
modules;
|
|
36
|
+
constructor(emFactory, presence = defaultPresenceReader,
|
|
37
|
+
/**
|
|
38
|
+
* A **function**, because the derived family is re-installed by every
|
|
39
|
+
* `b2b:module:state-changed` refresh and a list captured when this singleton was
|
|
40
|
+
* built would answer for the deployment as it was then.
|
|
41
|
+
*/
|
|
42
|
+
modules = declaredErpConnectorModules) {
|
|
43
|
+
this.emFactory = emFactory;
|
|
44
|
+
this.presence = presence;
|
|
45
|
+
this.modules = modules;
|
|
46
|
+
}
|
|
47
|
+
connectorModules() {
|
|
48
|
+
return typeof this.modules === 'function' ? this.modules() : this.modules;
|
|
49
|
+
}
|
|
50
|
+
async assertCanActivate(moduleId) {
|
|
51
|
+
const activeSibling = this.findActiveSibling(moduleId);
|
|
52
|
+
if (activeSibling !== null) {
|
|
53
|
+
throw new HttpError(409, ERROR_CODES.ERP_CONNECTOR_ALREADY_ACTIVE, `Another ERP connector is already active: ${activeSibling}`, { activeModuleId: activeSibling });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async recordActive(moduleId, adminId) {
|
|
57
|
+
const em = this.emFactory();
|
|
58
|
+
let row = await em.findOne(ErpConnectorActivationLock, {
|
|
59
|
+
id: ERP_CONNECTOR_ACTIVATION_LOCK_SINGLETON_ID,
|
|
60
|
+
});
|
|
61
|
+
if (row === null) {
|
|
62
|
+
// command-coverage-ignore: mutual-exclusion bookkeeping mirrors operator activation.
|
|
63
|
+
row = em.create(ErpConnectorActivationLock, {
|
|
64
|
+
id: ERP_CONNECTOR_ACTIVATION_LOCK_SINGLETON_ID,
|
|
65
|
+
activeModuleId: moduleId,
|
|
66
|
+
updatedByAdminId: adminId,
|
|
67
|
+
updatedAt: new Date(),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
row.activeModuleId = moduleId;
|
|
72
|
+
row.updatedByAdminId = adminId;
|
|
73
|
+
row.updatedAt = new Date();
|
|
74
|
+
}
|
|
75
|
+
await em.flush();
|
|
76
|
+
}
|
|
77
|
+
async clearActive(moduleId) {
|
|
78
|
+
const em = this.emFactory();
|
|
79
|
+
const row = await em.findOne(ErpConnectorActivationLock, {
|
|
80
|
+
id: ERP_CONNECTOR_ACTIVATION_LOCK_SINGLETON_ID,
|
|
81
|
+
});
|
|
82
|
+
if (row === null || row.activeModuleId !== moduleId) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// command-coverage-ignore: mutual-exclusion bookkeeping clears the lock on deactivation.
|
|
86
|
+
row.activeModuleId = null;
|
|
87
|
+
row.updatedAt = new Date();
|
|
88
|
+
await em.flush();
|
|
89
|
+
}
|
|
90
|
+
async getActiveModuleId() {
|
|
91
|
+
const em = this.emFactory();
|
|
92
|
+
const row = await em.findOne(ErpConnectorActivationLock, {
|
|
93
|
+
id: ERP_CONNECTOR_ACTIVATION_LOCK_SINGLETON_ID,
|
|
94
|
+
});
|
|
95
|
+
return row?.activeModuleId ?? null;
|
|
96
|
+
}
|
|
97
|
+
findActiveSibling(exceptModuleId) {
|
|
98
|
+
for (const sibling of this.connectorModules()) {
|
|
99
|
+
if (sibling.id === exceptModuleId)
|
|
100
|
+
continue;
|
|
101
|
+
if (this.presence.isOperatorActivated(sibling.id)) {
|
|
102
|
+
return sibling.id;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=erp-connector-registry.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"erp-connector-registry.service.js","sourceRoot":"","sources":["../../../src/backend/services/erp-connector-registry.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/** Shared ERP connector infrastructure — feature 119. */
|
|
2
|
+
export declare const manifest: {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
version: string;
|
|
6
|
+
dependencies: string[];
|
|
7
|
+
description?: string | undefined;
|
|
8
|
+
acknowledgedDependencies?: {
|
|
9
|
+
moduleId: string;
|
|
10
|
+
port: string;
|
|
11
|
+
reason: string;
|
|
12
|
+
}[] | undefined;
|
|
13
|
+
nonBindingDependencies?: {
|
|
14
|
+
moduleId: string;
|
|
15
|
+
name: string;
|
|
16
|
+
kind: "contributes-to" | "degrades-without" | "refuses-without";
|
|
17
|
+
reason: string;
|
|
18
|
+
whenAbsent?: string | undefined;
|
|
19
|
+
}[] | undefined;
|
|
20
|
+
activation?: {
|
|
21
|
+
settingCode: string;
|
|
22
|
+
default: boolean;
|
|
23
|
+
} | {
|
|
24
|
+
nonDeactivatable: true;
|
|
25
|
+
reason: string;
|
|
26
|
+
} | undefined;
|
|
27
|
+
settings?: {
|
|
28
|
+
moduleCode: string;
|
|
29
|
+
groups: {
|
|
30
|
+
code: string;
|
|
31
|
+
name: string;
|
|
32
|
+
salesChannelCodes?: string[] | undefined;
|
|
33
|
+
isSystemProtected?: boolean | undefined;
|
|
34
|
+
}[];
|
|
35
|
+
settings: {
|
|
36
|
+
code: string;
|
|
37
|
+
name: string;
|
|
38
|
+
valueType: "string" | "number" | "boolean" | "json" | "string_list" | "secret" | "credential_ref";
|
|
39
|
+
defaultValue: unknown;
|
|
40
|
+
description?: string | undefined;
|
|
41
|
+
groupCode?: string | undefined;
|
|
42
|
+
previousDefaultValues?: unknown[] | undefined;
|
|
43
|
+
salesChannelCodes?: string[] | undefined;
|
|
44
|
+
enumOptions?: string[] | undefined;
|
|
45
|
+
configurationType?: string | undefined;
|
|
46
|
+
hidden?: boolean | undefined;
|
|
47
|
+
}[];
|
|
48
|
+
} | undefined;
|
|
49
|
+
i18n?: {
|
|
50
|
+
bundlesDir: string;
|
|
51
|
+
} | undefined;
|
|
52
|
+
docs?: false | {
|
|
53
|
+
dir: string;
|
|
54
|
+
} | undefined;
|
|
55
|
+
demo?: false | {
|
|
56
|
+
summary: string;
|
|
57
|
+
seed: (context: import("@endora-commerce/contracts").ModuleDemoContext<never>) => Promise<import("@endora-commerce/contracts").DemoSeedResult>;
|
|
58
|
+
reset: (context: import("@endora-commerce/contracts").ModuleDemoContext<never>) => Promise<import("@endora-commerce/contracts").DemoResetResult>;
|
|
59
|
+
after?: readonly string[] | undefined;
|
|
60
|
+
package?: string | undefined;
|
|
61
|
+
} | undefined;
|
|
62
|
+
actions?: {
|
|
63
|
+
id: string;
|
|
64
|
+
labelKey: string;
|
|
65
|
+
icon: "Plus" | "Sparkles" | "Settings" | "Search" | "Boxes" | "Layers" | "Menu" | "PlusCircle" | "PlusSquare" | "FilePlus" | "FolderPlus" | "Upload" | "FileUp" | "CloudUpload" | "Download" | "FileDown" | "FileText" | "BookOpen" | "Rss" | "Package" | "Tag" | "ShoppingCart" | "Receipt" | "CreditCard" | "Users" | "UserPlus" | "Inbox" | "ListChecks" | "ClipboardList" | "Image" | "Video" | "LayoutDashboard" | "PanelLeft" | "KeyRound" | "ShieldCheck" | "Edit" | "Archive" | "Box" | "Truck" | "CircleDollarSign" | "Activity" | "LineChart" | "Smartphone" | "Webhook" | "Scale" | "PlugZap" | "PercentDiamond" | "Newspaper" | "Languages" | "Eraser" | "Warehouse" | "TrendingDown" | "Bell" | "PackageOpen" | "Building2" | "Store" | "ClipboardCheck";
|
|
66
|
+
targetRoute: string;
|
|
67
|
+
keywords: string[];
|
|
68
|
+
weight: number;
|
|
69
|
+
descriptionKey?: string | undefined;
|
|
70
|
+
requiredPermission?: string | undefined;
|
|
71
|
+
}[] | undefined;
|
|
72
|
+
permissions?: {
|
|
73
|
+
code: string;
|
|
74
|
+
label: string;
|
|
75
|
+
module?: string | undefined;
|
|
76
|
+
description?: string | undefined;
|
|
77
|
+
requires?: string[] | undefined;
|
|
78
|
+
}[] | undefined;
|
|
79
|
+
transactionalEmails?: {
|
|
80
|
+
code: string;
|
|
81
|
+
name: string;
|
|
82
|
+
variables: {
|
|
83
|
+
key: string;
|
|
84
|
+
label: string;
|
|
85
|
+
sampleValue?: string | undefined;
|
|
86
|
+
description?: string | undefined;
|
|
87
|
+
}[];
|
|
88
|
+
description?: string | undefined;
|
|
89
|
+
group?: string | undefined;
|
|
90
|
+
}[] | undefined;
|
|
91
|
+
capabilities?: string[] | undefined;
|
|
92
|
+
exclusiveCapabilities?: {
|
|
93
|
+
key: string;
|
|
94
|
+
errorCode: string;
|
|
95
|
+
}[] | undefined;
|
|
96
|
+
errorCodes?: {
|
|
97
|
+
code: string;
|
|
98
|
+
tokens?: string[] | undefined;
|
|
99
|
+
}[] | undefined;
|
|
100
|
+
blocks?: {
|
|
101
|
+
name: string;
|
|
102
|
+
labelKey: string;
|
|
103
|
+
category: string;
|
|
104
|
+
contexts: ("invoice" | "email" | "cms" | "newsletter")[];
|
|
105
|
+
fields: Record<string, {
|
|
106
|
+
type: "number" | "object" | "array" | "text" | "textarea" | "select" | "radio" | "external" | "uuid" | "richtext";
|
|
107
|
+
label?: string | undefined;
|
|
108
|
+
required?: boolean | undefined;
|
|
109
|
+
options?: {
|
|
110
|
+
label: string;
|
|
111
|
+
value: string | number;
|
|
112
|
+
}[] | undefined;
|
|
113
|
+
refKind?: string | undefined;
|
|
114
|
+
}>;
|
|
115
|
+
descriptionKey?: string | undefined;
|
|
116
|
+
defaultProps?: Record<string, unknown> | undefined;
|
|
117
|
+
responsiveFields?: string[] | undefined;
|
|
118
|
+
previewIcon?: string | undefined;
|
|
119
|
+
weight?: number | undefined;
|
|
120
|
+
}[] | undefined;
|
|
121
|
+
blockCategories?: {
|
|
122
|
+
key: string;
|
|
123
|
+
titleKey: string;
|
|
124
|
+
contexts: ("invoice" | "email" | "cms" | "newsletter")[];
|
|
125
|
+
weight?: number | undefined;
|
|
126
|
+
visible?: boolean | undefined;
|
|
127
|
+
}[] | undefined;
|
|
128
|
+
env?: {
|
|
129
|
+
name: string;
|
|
130
|
+
describes: {
|
|
131
|
+
en: string;
|
|
132
|
+
pl: string;
|
|
133
|
+
};
|
|
134
|
+
requirement: {
|
|
135
|
+
kind: "required";
|
|
136
|
+
} | {
|
|
137
|
+
kind: "requiredWhen";
|
|
138
|
+
input: string;
|
|
139
|
+
equals: string;
|
|
140
|
+
} | {
|
|
141
|
+
kind: "optional";
|
|
142
|
+
without: {
|
|
143
|
+
en: string;
|
|
144
|
+
pl: string;
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
secret: boolean;
|
|
148
|
+
generable: boolean;
|
|
149
|
+
owner: {
|
|
150
|
+
kind: "platform";
|
|
151
|
+
} | {
|
|
152
|
+
kind: "application";
|
|
153
|
+
application: "admin" | "backend" | "storefront";
|
|
154
|
+
} | {
|
|
155
|
+
kind: "module";
|
|
156
|
+
moduleId: string;
|
|
157
|
+
};
|
|
158
|
+
consumers: ("admin" | "backend" | "storefront")[];
|
|
159
|
+
addressOf: "admin" | "backend" | "storefront" | null;
|
|
160
|
+
}[] | undefined;
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAEA,yDAAyD;AAEzD,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCnB,CAAC"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { CAPABILITY_KEYS, defineModuleManifest } from '@endora-commerce/contracts';
|
|
2
|
+
/** Shared ERP connector infrastructure — feature 119. */
|
|
3
|
+
export const manifest = defineModuleManifest({
|
|
4
|
+
id: 'erp_connector',
|
|
5
|
+
name: 'ERP connector shared layer',
|
|
6
|
+
description: 'Shared operator behaviours for ERP connectors: mutual exclusion and sync job vocabulary.',
|
|
7
|
+
version: '1.0.0',
|
|
8
|
+
dependencies: ['settings', 'admin_users'],
|
|
9
|
+
activation: {
|
|
10
|
+
nonDeactivatable: true,
|
|
11
|
+
reason: 'The shared ERP connector registry must stay available so operator activation of an ERP connector can be refused when another is already active.',
|
|
12
|
+
},
|
|
13
|
+
i18n: { bundlesDir: 'i18n' },
|
|
14
|
+
docs: false,
|
|
15
|
+
/**
|
|
16
|
+
* Feature 132 — this module **owns** the ERP connector capability and declares it
|
|
17
|
+
* mutually exclusive (`contracts/module-capabilities.md` R3.1).
|
|
18
|
+
*
|
|
19
|
+
* This is the family whose old shape carried a live Principle XV violation: one
|
|
20
|
+
* of its members is a per-deployment **overlay** module, and it had to be written
|
|
21
|
+
* into `packages/contracts/src/erp-connector.ts` — a core file the deployment does
|
|
22
|
+
* not own — to be seen by the exclusion at all. There was no other way in. After
|
|
23
|
+
* this, it declares membership in its own manifest and core is untouched, which
|
|
24
|
+
* `backend/test/integration/erp_connector/overlay-joins.test.ts` asserts directly.
|
|
25
|
+
*/
|
|
26
|
+
exclusiveCapabilities: [
|
|
27
|
+
{
|
|
28
|
+
key: CAPABILITY_KEYS.ERP_CONNECTOR,
|
|
29
|
+
errorCode: 'ERP_CONNECTOR_ALREADY_ACTIVE',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
errorCodes: [{ code: 'ERP_CONNECTOR_ALREADY_ACTIVE' }],
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEnF,yDAAyD;AAEzD,MAAM,CAAC,MAAM,QAAQ,GAAG,oBAAoB,CAAC;IAC3C,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,4BAA4B;IAClC,WAAW,EACT,0FAA0F;IAC5F,OAAO,EAAE,OAAO;IAChB,YAAY,EAAE,CAAC,UAAU,EAAE,aAAa,CAAC;IACzC,UAAU,EAAE;QACV,gBAAgB,EAAE,IAAI;QACtB,MAAM,EACJ,iJAAiJ;KACpJ;IACD,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE;IAC5B,IAAI,EAAE,KAAK;IACX;;;;;;;;;;OAUG;IACH,qBAAqB,EAAE;QACrB;YACE,GAAG,EAAE,eAAe,CAAC,aAAa;YAClC,SAAS,EAAE,8BAA8B;SAC1C;KACF;IACD,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,8BAA8B,EAAE,CAAC;CACvD,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
/** Feature 119 — `erp_connector` shared layer (init). */
|
|
3
|
+
export declare class Migration20260911T120000ErpConnectorInit extends Migration {
|
|
4
|
+
up(): Promise<void>;
|
|
5
|
+
down(): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=20260911T120000_erp_connector_init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260911T120000_erp_connector_init.d.ts","sourceRoot":"","sources":["../../src/migrations/20260911T120000_erp_connector_init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,yDAAyD;AACzD,qBAAa,wCAAyC,SAAQ,SAAS;IACtD,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGrC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
/** Feature 119 — `erp_connector` shared layer (init). */
|
|
3
|
+
export class Migration20260911T120000ErpConnectorInit extends Migration {
|
|
4
|
+
async up() {
|
|
5
|
+
this.addSql(`
|
|
6
|
+
create table "erp_connector_activation_lock" (
|
|
7
|
+
"id" uuid not null,
|
|
8
|
+
"active_module_id" varchar(64) null,
|
|
9
|
+
"updated_at" timestamptz not null,
|
|
10
|
+
"updated_by_admin_id" uuid null,
|
|
11
|
+
constraint "erp_connector_activation_lock_pkey" primary key ("id")
|
|
12
|
+
);
|
|
13
|
+
`);
|
|
14
|
+
this.addSql(`
|
|
15
|
+
alter table "erp_connector_activation_lock"
|
|
16
|
+
add constraint "erp_connector_activation_lock_updated_by_admin_id_foreign"
|
|
17
|
+
foreign key ("updated_by_admin_id") references "admin_users" ("id")
|
|
18
|
+
on update cascade on delete set null;
|
|
19
|
+
`);
|
|
20
|
+
}
|
|
21
|
+
async down() {
|
|
22
|
+
this.addSql(`drop table if exists "erp_connector_activation_lock" cascade;`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=20260911T120000_erp_connector_init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260911T120000_erp_connector_init.js","sourceRoot":"","sources":["../../src/migrations/20260911T120000_erp_connector_init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,yDAAyD;AACzD,MAAM,OAAO,wCAAyC,SAAQ,SAAS;IAC5D,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CAAC;;;;;;;;KAQX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC;;;;;KAKX,CAAC,CAAC;IACL,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC,+DAA+D,CAAC,CAAC;IAC/E,CAAC;CACF"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Migration20260911T120000ErpConnectorInit } from './20260911T120000_erp_connector_init.js';
|
|
2
|
+
export declare const migrations: (typeof Migration20260911T120000ErpConnectorInit)[];
|
|
3
|
+
export { Migration20260911T120000ErpConnectorInit };
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wCAAwC,EAAE,MAAM,yCAAyC,CAAC;AAEnG,eAAO,MAAM,UAAU,qDAA6C,CAAC;AAErE,OAAO,EAAE,wCAAwC,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wCAAwC,EAAE,MAAM,yCAAyC,CAAC;AAEnG,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,wCAAwC,CAAC,CAAC;AAErE,OAAO,EAAE,wCAAwC,EAAE,CAAC"}
|
package/i18n/en.json
ADDED
package/i18n/pl.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@endora-commerce/mod-erp-connector",
|
|
3
|
+
"version": "0.100.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"description": "Shared operator behaviours for ERP connectors: mutual exclusion and sync job vocabulary.",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"endora": {
|
|
9
|
+
"type": "module",
|
|
10
|
+
"id": "erp_connector"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/endora-commerce/endora-commerce.git",
|
|
15
|
+
"directory": "packages/modules/erp_connector"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/manifest.d.ts",
|
|
23
|
+
"default": "./dist/manifest.js"
|
|
24
|
+
},
|
|
25
|
+
"./backend": {
|
|
26
|
+
"types": "./dist/backend/index.d.ts",
|
|
27
|
+
"default": "./dist/backend/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./migrations": {
|
|
30
|
+
"types": "./dist/migrations/index.d.ts",
|
|
31
|
+
"default": "./dist/migrations/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./package.json": "./package.json"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"i18n"
|
|
38
|
+
],
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=22.18.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@mikro-orm/core": "^6",
|
|
44
|
+
"@mikro-orm/migrations": "^6",
|
|
45
|
+
"@mikro-orm/postgresql": "^6",
|
|
46
|
+
"@endora-commerce/contracts": "0.100.0",
|
|
47
|
+
"@endora-commerce/platform": "0.100.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@mikro-orm/core": "^6.6.13",
|
|
51
|
+
"@mikro-orm/migrations": "^6.6.13",
|
|
52
|
+
"@mikro-orm/postgresql": "^6.6.13",
|
|
53
|
+
"@types/node": "^22.9.0",
|
|
54
|
+
"typescript": "^5.9.3",
|
|
55
|
+
"vitest": "^4.1.11",
|
|
56
|
+
"@endora-commerce/contracts": "0.100.0",
|
|
57
|
+
"@endora-commerce/platform": "0.100.0"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "tsc -p tsconfig.build.json",
|
|
61
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
62
|
+
"lint": "eslint src",
|
|
63
|
+
"test": "vitest run"
|
|
64
|
+
}
|
|
65
|
+
}
|