@endora-commerce/mod-currencies 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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -0
  3. package/dist/backend/entities/currency.entity.d.ts +22 -0
  4. package/dist/backend/entities/currency.entity.d.ts.map +1 -0
  5. package/dist/backend/entities/currency.entity.js +77 -0
  6. package/dist/backend/entities/currency.entity.js.map +1 -0
  7. package/dist/backend/index.d.ts +53 -0
  8. package/dist/backend/index.d.ts.map +1 -0
  9. package/dist/backend/index.js +108 -0
  10. package/dist/backend/index.js.map +1 -0
  11. package/dist/backend/routes.d.ts +36 -0
  12. package/dist/backend/routes.d.ts.map +1 -0
  13. package/dist/backend/routes.js +43 -0
  14. package/dist/backend/routes.js.map +1 -0
  15. package/dist/backend/services/currency-ports.d.ts +23 -0
  16. package/dist/backend/services/currency-ports.d.ts.map +1 -0
  17. package/dist/backend/services/currency-ports.js +63 -0
  18. package/dist/backend/services/currency-ports.js.map +1 -0
  19. package/dist/backend/services/currency-reference-registry.d.ts +30 -0
  20. package/dist/backend/services/currency-reference-registry.d.ts.map +1 -0
  21. package/dist/backend/services/currency-reference-registry.js +54 -0
  22. package/dist/backend/services/currency-reference-registry.js.map +1 -0
  23. package/dist/backend/services/currency-seed-service.d.ts +21 -0
  24. package/dist/backend/services/currency-seed-service.d.ts.map +1 -0
  25. package/dist/backend/services/currency-seed-service.js +41 -0
  26. package/dist/backend/services/currency-seed-service.js.map +1 -0
  27. package/dist/backend/services/currency-service.d.ts +94 -0
  28. package/dist/backend/services/currency-service.d.ts.map +1 -0
  29. package/dist/backend/services/currency-service.js +269 -0
  30. package/dist/backend/services/currency-service.js.map +1 -0
  31. package/dist/manifest.d.ts +169 -0
  32. package/dist/manifest.d.ts.map +1 -0
  33. package/dist/manifest.js +83 -0
  34. package/dist/manifest.js.map +1 -0
  35. package/docs/currencies.md +59 -0
  36. package/package.json +62 -0
@@ -0,0 +1,83 @@
1
+ import { defineModuleManifest } from '@endora-commerce/contracts';
2
+ /**
3
+ * Currencies module — manifest backfill (Module Lifecycle, feature 018).
4
+ *
5
+ * Predates the lifecycle system; this manifest is the static record
6
+ * required so the module participates in the registry. No install /
7
+ * uninstall hook today — the module's schema is owned by earlier
8
+ * platform-wide migrations.
9
+ */
10
+ export const manifest = defineModuleManifest({
11
+ id: 'currencies',
12
+ docs: { dir: 'docs' },
13
+ name: 'Currencies',
14
+ description: 'Currency reference data and per-channel currency configuration.',
15
+ version: '1.0.0',
16
+ // `auth` owns the `requireAdmin` port the admin routes added on 2026-08-29
17
+ // are gated by. It is the only entry, and the list stays otherwise empty for
18
+ // its original reason: `currencies` announces a change on the EventBus and
19
+ // `dictionaries` reacts by dropping its caches — a **notification**, not a
20
+ // query, which `contracts/module-context.md` says needs no dependency edge.
21
+ // Declaring one produced a real cycle (dictionaries → currencies →
22
+ // dictionaries) and the cycle was the design telling us the direction was
23
+ // wrong: a currency has no business knowing a dictionary cache exists.
24
+ dependencies: ['auth'],
25
+ /**
26
+ * The module's own authority (2026-08-29).
27
+ *
28
+ * `/api/v1/admin/currencies`, `/:code`, `/:code/default` and the delete were
29
+ * registered by `languages` and enforced `catalog:write` — all four, the list
30
+ * read included. So whoever could edit a product description could add a
31
+ * currency, deactivate one, delete one and **promote one to the shop's
32
+ * default**, which is the denomination every price, cart, order and invoice
33
+ * is stated in.
34
+ *
35
+ * Nothing could see it. `catalog:write` is real, declared and enforced, so
36
+ * the permission inventory's two directions were clean; D-173's `foreign-gate`
37
+ * sweep passes the site deliberately, because `catalog` is `nonDeactivatable`
38
+ * and the availability coupling that sweep asks about can never bite; and
39
+ * `check:action-route-permissions` never looked at all, neither this module
40
+ * nor `languages` declaring a manifest action. None of them asks whether
41
+ * `catalog:write` is the right authority for changing what a shop charges in,
42
+ * which is a judgement rather than a derivation, so the answer is pinned in a
43
+ * contract test rather than in a new check.
44
+ *
45
+ * A pair and no third code, spelled `<module id>:<read|write>` like
46
+ * `payment_methods`, `delivery_methods`, `taxes`, `returns` and `invoices`. A
47
+ * prefix that is not its owner's id is the mistake `PERMISSION_CATALOGUE`
48
+ * comments on twice (`integrations:manage`, `audit_log:read`), both frozen
49
+ * because they are persisted in role rows; getting it right on a code that
50
+ * does not exist yet is free.
51
+ *
52
+ * The read half is a capability that did not exist rather than a rename of
53
+ * one: every one of the four routes carried the write code, so listing the
54
+ * currencies required the authority to delete one.
55
+ *
56
+ * The **other** door to this table is `dictionaries`'
57
+ * `/api/v1/admin/dictionary/currencies/*`, gated on `dictionary.write`. It is
58
+ * out of this repair's scope and is reported rather than changed: that is the
59
+ * screen an operator actually uses, it is a code `dictionaries` owns rather
60
+ * than a borrowed one, and re-gating it is the same question asked of the
61
+ * whole reference-data registry (countries and languages alike) rather than
62
+ * of currencies.
63
+ *
64
+ * No data migration: see `test/contract/currencies/permission-authority.test.ts`.
65
+ */
66
+ permissions: [
67
+ { code: 'currencies:read', label: 'View currencies' },
68
+ { code: 'currencies:write', label: 'Configure currencies' },
69
+ ],
70
+ // Feature 074 (Constitution XVII), test C3 — platform primitive. The
71
+ // declaration used to carry the manifest graph as its second half ("and
72
+ // `dictionaries` declares this module, two edges from the tenancy root");
73
+ // ruling 2 withdraws that, and the business half was always the real one and
74
+ // stands alone. Denomination is not a business decision anyone takes: there
75
+ // is no price, cart, order or invoice without a currency, and no client for
76
+ // whom "no currencies" is a smaller platform rather than a broken one.
77
+ activation: {
78
+ nonDeactivatable: true,
79
+ reason: 'Every amount is denominated; there is no price, cart, order or invoice without a ' +
80
+ 'currency.',
81
+ },
82
+ });
83
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,oBAAoB,CAAC;IAC3C,EAAE,EAAE,YAAY;IAChB,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE;IACrB,IAAI,EAAE,YAAY;IAClB,WAAW,EACT,iEAAiE;IACnE,OAAO,EAAE,OAAO;IAChB,2EAA2E;IAC3E,6EAA6E;IAC7E,2EAA2E;IAC3E,2EAA2E;IAC3E,4EAA4E;IAC5E,mEAAmE;IACnE,0EAA0E;IAC1E,uEAAuE;IACvE,YAAY,EAAE,CAAC,MAAM,CAAC;IACtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAwCG;IACH,WAAW,EAAE;QACX,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,iBAAiB,EAAE;QACrD,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,sBAAsB,EAAE;KAC5D;IACD,qEAAqE;IACrE,wEAAwE;IACxE,0EAA0E;IAC1E,6EAA6E;IAC7E,4EAA4E;IAC5E,4EAA4E;IAC5E,uEAAuE;IACvE,UAAU,EAAE;QACV,gBAAgB,EAAE,IAAI;QACtB,MAAM,EACJ,mFAAmF;YACnF,WAAW;KACd;CACF,CAAC,CAAC"}
@@ -0,0 +1,59 @@
1
+ ---
2
+ title: currencies
3
+ description: Pool of accepted ISO 4217 currencies + default
4
+ ---
5
+
6
+ # `currencies`
7
+
8
+ The installation-wide pool of accepted ISO 4217 currency codes. Mirrors the
9
+ `languages` module.
10
+
11
+ ## Public surface
12
+
13
+ | Verb + Path | Permission | Purpose |
14
+ | --- | --- | --- |
15
+ | `GET /api/v1/admin/currencies` | `currencies:read` | Full list |
16
+ | `PUT /api/v1/admin/currencies/:code` | `currencies:write` | Upsert |
17
+ | `POST /api/v1/admin/currencies/:code/default` | `currencies:write` | Promote to default (atomically demotes the prior default) |
18
+ | `DELETE /api/v1/admin/currencies/:code` | `currencies:write` | Remove (rejected for the default) |
19
+
20
+ `GET /api/v1/i18n/config` also answers with the active currencies and the
21
+ default, and is **`languages`'** route rather than this module's: it composes
22
+ both catalogues into one public payload and reads this module's half over
23
+ `currencyReadPort`. See [languages](./languages.md).
24
+
25
+ ## Permissions
26
+
27
+ `currencies:read` and `currencies:write`, this module's own since 2026-08-29.
28
+
29
+ The four routes above lived in `languages` until then and enforced
30
+ `catalog:write` — all four, the list read included — so whoever could edit a
31
+ product description could add a currency, deactivate one, delete one and
32
+ promote one to the shop's default. Nothing in this repository calls these
33
+ routes: the admin currency screen is `dictionaries`'
34
+ (`/api/v1/admin/dictionary/currencies/*`, gated on `dictionary.write`), which is
35
+ a second door to this table and a separate question.
36
+
37
+ `test/contract/currencies/permission-authority.test.ts` pins both directions —
38
+ a role holding the catalogue codes is refused, a role holding the pair is
39
+ served — and asserts that the in-process `currencyReadPort` every other module
40
+ reads a currency through is untouched by the move.
41
+
42
+ ## Defaults
43
+
44
+ Same partial-unique-index pattern as `languages`. The migration bootstrap
45
+ seeds `PLN` (default) and `EUR`; symbol values are stored via Postgres
46
+ Unicode literals so the migration source stays ASCII.
47
+
48
+ ## Entities
49
+
50
+ `Currency` — natural primary key on the ISO 4217 code; `label`,
51
+ `symbol`, `isDefault`, `isActive`, `sortOrder`.
52
+
53
+ ## Extension points
54
+
55
+ - **Per-Sales-Channel default** — when a Sales Channel ships its own
56
+ currency, gate `priceFor(cart)` in the orders module on the channel's
57
+ configured currency rather than the global default.
58
+ - **Exchange-rate provider** — out of scope here; integrate via the
59
+ `integrations` module when a real adapter is needed.
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@endora-commerce/mod-currencies",
3
+ "version": "0.100.0",
4
+ "type": "module",
5
+ "sideEffects": false,
6
+ "description": "Currency reference data and per-channel currency configuration.",
7
+ "license": "MIT",
8
+ "endora": {
9
+ "type": "module",
10
+ "id": "currencies"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/endora-commerce/endora-commerce.git",
15
+ "directory": "packages/modules/currencies"
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
+ "./package.json": "./package.json"
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "docs"
34
+ ],
35
+ "engines": {
36
+ "node": ">=22.18.0"
37
+ },
38
+ "peerDependencies": {
39
+ "@mikro-orm/core": "^6",
40
+ "@mikro-orm/postgresql": "^6",
41
+ "fastify": "^5",
42
+ "@endora-commerce/contracts": "0.100.0",
43
+ "@endora-commerce/platform": "0.100.0"
44
+ },
45
+ "devDependencies": {
46
+ "@fastify/type-provider-zod": "^1.0.0",
47
+ "@mikro-orm/core": "^6.6.13",
48
+ "@mikro-orm/postgresql": "^6.6.13",
49
+ "@types/node": "^22.9.0",
50
+ "fastify": "^5.12.5",
51
+ "typescript": "^5.9.3",
52
+ "vitest": "^4.1.11",
53
+ "@endora-commerce/contracts": "0.100.0",
54
+ "@endora-commerce/platform": "0.100.0"
55
+ },
56
+ "scripts": {
57
+ "build": "tsc -p tsconfig.build.json",
58
+ "typecheck": "tsc -p tsconfig.json",
59
+ "lint": "eslint src",
60
+ "test": "vitest run"
61
+ }
62
+ }