@endora-commerce/mod-dictionaries 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 +60 -0
- package/dist/admin/api/client.d.ts +76 -0
- package/dist/admin/api/client.d.ts.map +1 -0
- package/dist/admin/api/client.js +87 -0
- package/dist/admin/api/client.js.map +1 -0
- package/dist/admin/components/EntryStatusBadges.d.ts +9 -0
- package/dist/admin/components/EntryStatusBadges.d.ts.map +1 -0
- package/dist/admin/components/EntryStatusBadges.js +8 -0
- package/dist/admin/components/EntryStatusBadges.js.map +1 -0
- package/dist/admin/components/LanguagePicker.d.ts +8 -0
- package/dist/admin/components/LanguagePicker.d.ts.map +1 -0
- package/dist/admin/components/LanguagePicker.js +30 -0
- package/dist/admin/components/LanguagePicker.js.map +1 -0
- package/dist/admin/components/TranslationsDrawer.d.ts +10 -0
- package/dist/admin/components/TranslationsDrawer.d.ts.map +1 -0
- package/dist/admin/components/TranslationsDrawer.js +90 -0
- package/dist/admin/components/TranslationsDrawer.js.map +1 -0
- package/dist/admin/index.d.ts +48 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +82 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/AuditPage.d.ts +9 -0
- package/dist/admin/pages/AuditPage.d.ts.map +1 -0
- package/dist/admin/pages/AuditPage.js +80 -0
- package/dist/admin/pages/AuditPage.js.map +1 -0
- package/dist/admin/pages/DictionaryPage.d.ts +9 -0
- package/dist/admin/pages/DictionaryPage.d.ts.map +1 -0
- package/dist/admin/pages/DictionaryPage.js +38 -0
- package/dist/admin/pages/DictionaryPage.js.map +1 -0
- package/dist/admin/tabs/CountriesTab.d.ts +3 -0
- package/dist/admin/tabs/CountriesTab.d.ts.map +1 -0
- package/dist/admin/tabs/CountriesTab.js +233 -0
- package/dist/admin/tabs/CountriesTab.js.map +1 -0
- package/dist/admin/tabs/CurrenciesTab.d.ts +3 -0
- package/dist/admin/tabs/CurrenciesTab.d.ts.map +1 -0
- package/dist/admin/tabs/CurrenciesTab.js +209 -0
- package/dist/admin/tabs/CurrenciesTab.js.map +1 -0
- package/dist/admin/tabs/LanguagesTab.d.ts +3 -0
- package/dist/admin/tabs/LanguagesTab.d.ts.map +1 -0
- package/dist/admin/tabs/LanguagesTab.js +268 -0
- package/dist/admin/tabs/LanguagesTab.js.map +1 -0
- package/dist/backend/entities/country.entity.d.ts +35 -0
- package/dist/backend/entities/country.entity.d.ts.map +1 -0
- package/dist/backend/entities/country.entity.js +107 -0
- package/dist/backend/entities/country.entity.js.map +1 -0
- package/dist/backend/entities/dictionary-translation.entity.d.ts +25 -0
- package/dist/backend/entities/dictionary-translation.entity.d.ts.map +1 -0
- package/dist/backend/entities/dictionary-translation.entity.js +65 -0
- package/dist/backend/entities/dictionary-translation.entity.js.map +1 -0
- package/dist/backend/entities/language-country.entity.d.ts +17 -0
- package/dist/backend/entities/language-country.entity.d.ts.map +1 -0
- package/dist/backend/entities/language-country.entity.js +49 -0
- package/dist/backend/entities/language-country.entity.js.map +1 -0
- package/dist/backend/index.d.ts +85 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +155 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +39 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +317 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.storefront.d.ts +7 -0
- package/dist/backend/routes.storefront.d.ts.map +1 -0
- package/dist/backend/routes.storefront.js +34 -0
- package/dist/backend/routes.storefront.js.map +1 -0
- package/dist/backend/seed/countries.d.ts +28 -0
- package/dist/backend/seed/countries.d.ts.map +1 -0
- package/dist/backend/seed/countries.js +121 -0
- package/dist/backend/seed/countries.js.map +1 -0
- package/dist/backend/seed/currencies.d.ts +9 -0
- package/dist/backend/seed/currencies.d.ts.map +1 -0
- package/dist/backend/seed/currencies.js +76 -0
- package/dist/backend/seed/currencies.js.map +1 -0
- package/dist/backend/seed/language-countries.d.ts +7 -0
- package/dist/backend/seed/language-countries.d.ts.map +1 -0
- package/dist/backend/seed/language-countries.js +19 -0
- package/dist/backend/seed/language-countries.js.map +1 -0
- package/dist/backend/seed/translations.pl-PL.d.ts +10 -0
- package/dist/backend/seed/translations.pl-PL.d.ts.map +1 -0
- package/dist/backend/seed/translations.pl-PL.js +74 -0
- package/dist/backend/seed/translations.pl-PL.js.map +1 -0
- package/dist/backend/services/country-currency-reference.d.ts +13 -0
- package/dist/backend/services/country-currency-reference.d.ts.map +1 -0
- package/dist/backend/services/country-currency-reference.js +25 -0
- package/dist/backend/services/country-currency-reference.js.map +1 -0
- package/dist/backend/services/country-reference-registry.d.ts +30 -0
- package/dist/backend/services/country-reference-registry.d.ts.map +1 -0
- package/dist/backend/services/country-reference-registry.js +54 -0
- package/dist/backend/services/country-reference-registry.js.map +1 -0
- package/dist/backend/services/country-service.d.ts +69 -0
- package/dist/backend/services/country-service.d.ts.map +1 -0
- package/dist/backend/services/country-service.js +193 -0
- package/dist/backend/services/country-service.js.map +1 -0
- package/dist/backend/services/dictionary-cache.d.ts +27 -0
- package/dist/backend/services/dictionary-cache.d.ts.map +1 -0
- package/dist/backend/services/dictionary-cache.js +57 -0
- package/dist/backend/services/dictionary-cache.js.map +1 -0
- package/dist/backend/services/dictionary-read-service.d.ts +36 -0
- package/dist/backend/services/dictionary-read-service.d.ts.map +1 -0
- package/dist/backend/services/dictionary-read-service.js +232 -0
- package/dist/backend/services/dictionary-read-service.js.map +1 -0
- package/dist/backend/services/dictionary-validator.d.ts +26 -0
- package/dist/backend/services/dictionary-validator.d.ts.map +1 -0
- package/dist/backend/services/dictionary-validator.js +72 -0
- package/dist/backend/services/dictionary-validator.js.map +1 -0
- package/dist/backend/services/dispatch-validator-mode.d.ts +19 -0
- package/dist/backend/services/dispatch-validator-mode.d.ts.map +1 -0
- package/dist/backend/services/dispatch-validator-mode.js +19 -0
- package/dist/backend/services/dispatch-validator-mode.js.map +1 -0
- package/dist/backend/services/label-resolver.d.ts +57 -0
- package/dist/backend/services/label-resolver.d.ts.map +1 -0
- package/dist/backend/services/label-resolver.js +116 -0
- package/dist/backend/services/label-resolver.js.map +1 -0
- package/dist/backend/services/language-country-service.d.ts +26 -0
- package/dist/backend/services/language-country-service.d.ts.map +1 -0
- package/dist/backend/services/language-country-service.js +108 -0
- package/dist/backend/services/language-country-service.js.map +1 -0
- package/dist/backend/services/seed-reconciler.d.ts +22 -0
- package/dist/backend/services/seed-reconciler.d.ts.map +1 -0
- package/dist/backend/services/seed-reconciler.js +149 -0
- package/dist/backend/services/seed-reconciler.js.map +1 -0
- package/dist/backend/services/translation-service.d.ts +29 -0
- package/dist/backend/services/translation-service.d.ts.map +1 -0
- package/dist/backend/services/translation-service.js +99 -0
- package/dist/backend/services/translation-service.js.map +1 -0
- package/dist/manifest.d.ts +174 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +178 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260506T112634_dictionaries_dictionary_init.d.ts +33 -0
- package/dist/migrations/20260506T112634_dictionaries_dictionary_init.d.ts.map +1 -0
- package/dist/migrations/20260506T112634_dictionaries_dictionary_init.js +157 -0
- package/dist/migrations/20260506T112634_dictionaries_dictionary_init.js.map +1 -0
- package/dist/migrations/index.d.ts +27 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +29 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/dictionaries/index.md +89 -0
- package/i18n/en.json +88 -0
- package/i18n/pl.json +88 -0
- package/package.json +99 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed-reconciler.js","sourceRoot":"","sources":["../../../src/backend/services/seed-reconciler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import { type CurrencyReadPort, type DictionaryEntryType, type LanguageReadPort } from '@endora-commerce/contracts';
|
|
3
|
+
import { DictionaryTranslation } from '../entities/dictionary-translation.entity.js';
|
|
4
|
+
import type { AuditPort } from '@endora-commerce/platform/kernel';
|
|
5
|
+
export interface UpsertTranslationInput {
|
|
6
|
+
entryType: DictionaryEntryType;
|
|
7
|
+
entryCode: string;
|
|
8
|
+
languageCode: string;
|
|
9
|
+
label: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class TranslationService {
|
|
12
|
+
private readonly emFactory;
|
|
13
|
+
private readonly currencies;
|
|
14
|
+
private readonly languages;
|
|
15
|
+
private readonly invalidateDictionaryCache?;
|
|
16
|
+
private readonly auditLog?;
|
|
17
|
+
/**
|
|
18
|
+
* Feature 075, Phase C — a translation's parent may be a country (this
|
|
19
|
+
* module's row), a currency or a language (not). The two that are not are
|
|
20
|
+
* read through their owners' ports, so a translation cannot be attached to a
|
|
21
|
+
* parent the platform is no longer serving.
|
|
22
|
+
*/
|
|
23
|
+
constructor(emFactory: () => EntityManager, currencies: CurrencyReadPort, languages: LanguageReadPort, invalidateDictionaryCache?: (() => Promise<void>) | undefined, auditLog?: AuditPort | undefined);
|
|
24
|
+
upsert(input: UpsertTranslationInput): Promise<DictionaryTranslation>;
|
|
25
|
+
remove(entryType: DictionaryEntryType, entryCode: string, languageCode: string): Promise<void>;
|
|
26
|
+
listForEntry(entryType: DictionaryEntryType, entryCode: string): Promise<DictionaryTranslation[]>;
|
|
27
|
+
private assertParentExists;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=translation-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translation-service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/translation-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACtB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AAErF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAElE,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,mBAAmB,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,kBAAkB;IAQ3B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAX5B;;;;;OAKG;gBAEgB,SAAS,EAAE,MAAM,aAAa,EAC9B,UAAU,EAAE,gBAAgB,EAC5B,SAAS,EAAE,gBAAgB,EAC3B,yBAAyB,CAAC,GAAE,MAAM,OAAO,CAAC,IAAI,CAAC,aAAA,EAC/C,QAAQ,CAAC,EAAE,SAAS,YAAA;IAGjC,MAAM,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IA2CrE,MAAM,CACV,SAAS,EAAE,mBAAmB,EAC9B,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC;IAiBV,YAAY,CAChB,SAAS,EAAE,mBAAmB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,EAAE,CAAC;YAMrB,kBAAkB;CAajC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ERROR_CODES, } from '@endora-commerce/contracts';
|
|
2
|
+
import { HttpError } from '@endora-commerce/platform/http';
|
|
3
|
+
import { Country } from '../entities/country.entity.js';
|
|
4
|
+
import { DictionaryTranslation } from '../entities/dictionary-translation.entity.js';
|
|
5
|
+
import { recordAuditFromContext } from '@endora-commerce/platform/commands';
|
|
6
|
+
export class TranslationService {
|
|
7
|
+
emFactory;
|
|
8
|
+
currencies;
|
|
9
|
+
languages;
|
|
10
|
+
invalidateDictionaryCache;
|
|
11
|
+
auditLog;
|
|
12
|
+
/**
|
|
13
|
+
* Feature 075, Phase C — a translation's parent may be a country (this
|
|
14
|
+
* module's row), a currency or a language (not). The two that are not are
|
|
15
|
+
* read through their owners' ports, so a translation cannot be attached to a
|
|
16
|
+
* parent the platform is no longer serving.
|
|
17
|
+
*/
|
|
18
|
+
constructor(emFactory, currencies, languages, invalidateDictionaryCache, auditLog) {
|
|
19
|
+
this.emFactory = emFactory;
|
|
20
|
+
this.currencies = currencies;
|
|
21
|
+
this.languages = languages;
|
|
22
|
+
this.invalidateDictionaryCache = invalidateDictionaryCache;
|
|
23
|
+
this.auditLog = auditLog;
|
|
24
|
+
}
|
|
25
|
+
async upsert(input) {
|
|
26
|
+
const em = this.emFactory();
|
|
27
|
+
await this.assertParentExists(em, input.entryType, input.entryCode);
|
|
28
|
+
const language = await this.languages.findByCode(input.languageCode);
|
|
29
|
+
if (!language)
|
|
30
|
+
throw notFound('language', input.languageCode);
|
|
31
|
+
if (!language.isActive) {
|
|
32
|
+
throw new HttpError(409, ERROR_CODES.DICTIONARY_ENTRY_INACTIVE, `Language ${input.languageCode} is inactive.`);
|
|
33
|
+
}
|
|
34
|
+
let row = await em.findOne(DictionaryTranslation, {
|
|
35
|
+
entryType: input.entryType,
|
|
36
|
+
entryCode: input.entryCode,
|
|
37
|
+
languageCode: input.languageCode,
|
|
38
|
+
});
|
|
39
|
+
if (!row) {
|
|
40
|
+
row = em.create(DictionaryTranslation, {
|
|
41
|
+
entryType: input.entryType,
|
|
42
|
+
entryCode: input.entryCode,
|
|
43
|
+
languageCode: input.languageCode,
|
|
44
|
+
label: input.label,
|
|
45
|
+
});
|
|
46
|
+
em.persist(row);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
row.label = input.label;
|
|
50
|
+
}
|
|
51
|
+
if (this.auditLog) {
|
|
52
|
+
recordAuditFromContext(this.auditLog, em, {
|
|
53
|
+
action: 'dictionary_translation.upsert',
|
|
54
|
+
objectType: 'dictionary_translation',
|
|
55
|
+
objectId: `${input.entryType}:${input.entryCode}:${input.languageCode}`,
|
|
56
|
+
stateBefore: null,
|
|
57
|
+
stateAfter: { label: input.label },
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
await em.flush();
|
|
61
|
+
await this.invalidateDictionaryCache?.();
|
|
62
|
+
return row;
|
|
63
|
+
}
|
|
64
|
+
async remove(entryType, entryCode, languageCode) {
|
|
65
|
+
const em = this.emFactory();
|
|
66
|
+
const row = await em.findOne(DictionaryTranslation, { entryType, entryCode, languageCode });
|
|
67
|
+
if (!row)
|
|
68
|
+
throw notFound(entryType, entryCode);
|
|
69
|
+
if (this.auditLog) {
|
|
70
|
+
recordAuditFromContext(this.auditLog, em, {
|
|
71
|
+
action: 'dictionary_translation.delete',
|
|
72
|
+
objectType: 'dictionary_translation',
|
|
73
|
+
objectId: `${entryType}:${entryCode}:${languageCode}`,
|
|
74
|
+
stateBefore: { label: row.label },
|
|
75
|
+
stateAfter: null,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
await em.removeAndFlush(row);
|
|
79
|
+
await this.invalidateDictionaryCache?.();
|
|
80
|
+
}
|
|
81
|
+
async listForEntry(entryType, entryCode) {
|
|
82
|
+
const em = this.emFactory();
|
|
83
|
+
await this.assertParentExists(em, entryType, entryCode);
|
|
84
|
+
return em.find(DictionaryTranslation, { entryType, entryCode }, { orderBy: { languageCode: 'asc' } });
|
|
85
|
+
}
|
|
86
|
+
async assertParentExists(em, entryType, entryCode) {
|
|
87
|
+
const exists = entryType === 'country'
|
|
88
|
+
? await em.findOne(Country, { code: entryCode })
|
|
89
|
+
: entryType === 'currency'
|
|
90
|
+
? await this.currencies.findByCode(entryCode)
|
|
91
|
+
: await this.languages.findByCode(entryCode);
|
|
92
|
+
if (!exists)
|
|
93
|
+
throw notFound(entryType, entryCode);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function notFound(entryType, entryCode) {
|
|
97
|
+
return new HttpError(404, ERROR_CODES.DICTIONARY_ENTRY_NOT_FOUND, `Dictionary ${entryType} ${entryCode} not found.`);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=translation-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translation-service.js","sourceRoot":"","sources":["../../../src/backend/services/translation-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
export declare const DICTIONARY_PERMISSIONS: {
|
|
2
|
+
readonly WRITE: "dictionary.write";
|
|
3
|
+
};
|
|
4
|
+
export type DictionaryPermission = (typeof DICTIONARY_PERMISSIONS)[keyof typeof DICTIONARY_PERMISSIONS];
|
|
5
|
+
/**
|
|
6
|
+
* Module-lifecycle manifest (feature 018) — Pass B retrofit. The
|
|
7
|
+
* `dictionaries` schema is platform-foundational (migration 038),
|
|
8
|
+
* owned cross-cuttingly rather than by an install hook, so this entry
|
|
9
|
+
* declares no `installHook`. Its purpose is to register the module's
|
|
10
|
+
* presence in the static registry so other modules (notably `inventory`
|
|
11
|
+
* and `blog`) can declare `dictionaries` as a dependency without the
|
|
12
|
+
* registry warning "depends on … which is not in the static registry".
|
|
13
|
+
*/
|
|
14
|
+
export declare const manifest: {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
version: string;
|
|
18
|
+
dependencies: string[];
|
|
19
|
+
description?: string | undefined;
|
|
20
|
+
acknowledgedDependencies?: {
|
|
21
|
+
moduleId: string;
|
|
22
|
+
port: string;
|
|
23
|
+
reason: string;
|
|
24
|
+
}[] | undefined;
|
|
25
|
+
nonBindingDependencies?: {
|
|
26
|
+
moduleId: string;
|
|
27
|
+
name: string;
|
|
28
|
+
kind: "contributes-to" | "degrades-without" | "refuses-without";
|
|
29
|
+
reason: string;
|
|
30
|
+
whenAbsent?: string | undefined;
|
|
31
|
+
}[] | undefined;
|
|
32
|
+
activation?: {
|
|
33
|
+
settingCode: string;
|
|
34
|
+
default: boolean;
|
|
35
|
+
} | {
|
|
36
|
+
nonDeactivatable: true;
|
|
37
|
+
reason: string;
|
|
38
|
+
} | undefined;
|
|
39
|
+
settings?: {
|
|
40
|
+
moduleCode: string;
|
|
41
|
+
groups: {
|
|
42
|
+
code: string;
|
|
43
|
+
name: string;
|
|
44
|
+
salesChannelCodes?: string[] | undefined;
|
|
45
|
+
isSystemProtected?: boolean | undefined;
|
|
46
|
+
}[];
|
|
47
|
+
settings: {
|
|
48
|
+
code: string;
|
|
49
|
+
name: string;
|
|
50
|
+
valueType: "string" | "number" | "boolean" | "json" | "string_list" | "secret" | "credential_ref";
|
|
51
|
+
defaultValue: unknown;
|
|
52
|
+
description?: string | undefined;
|
|
53
|
+
groupCode?: string | undefined;
|
|
54
|
+
previousDefaultValues?: unknown[] | undefined;
|
|
55
|
+
salesChannelCodes?: string[] | undefined;
|
|
56
|
+
enumOptions?: string[] | undefined;
|
|
57
|
+
configurationType?: string | undefined;
|
|
58
|
+
hidden?: boolean | undefined;
|
|
59
|
+
}[];
|
|
60
|
+
} | undefined;
|
|
61
|
+
i18n?: {
|
|
62
|
+
bundlesDir: string;
|
|
63
|
+
} | undefined;
|
|
64
|
+
docs?: false | {
|
|
65
|
+
dir: string;
|
|
66
|
+
} | undefined;
|
|
67
|
+
demo?: false | {
|
|
68
|
+
summary: string;
|
|
69
|
+
seed: (context: import("@endora-commerce/contracts").ModuleDemoContext<never>) => Promise<import("@endora-commerce/contracts").DemoSeedResult>;
|
|
70
|
+
reset: (context: import("@endora-commerce/contracts").ModuleDemoContext<never>) => Promise<import("@endora-commerce/contracts").DemoResetResult>;
|
|
71
|
+
after?: readonly string[] | undefined;
|
|
72
|
+
package?: string | undefined;
|
|
73
|
+
} | undefined;
|
|
74
|
+
actions?: {
|
|
75
|
+
id: string;
|
|
76
|
+
labelKey: string;
|
|
77
|
+
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";
|
|
78
|
+
targetRoute: string;
|
|
79
|
+
keywords: string[];
|
|
80
|
+
weight: number;
|
|
81
|
+
descriptionKey?: string | undefined;
|
|
82
|
+
requiredPermission?: string | undefined;
|
|
83
|
+
}[] | undefined;
|
|
84
|
+
permissions?: {
|
|
85
|
+
code: string;
|
|
86
|
+
label: string;
|
|
87
|
+
module?: string | undefined;
|
|
88
|
+
description?: string | undefined;
|
|
89
|
+
requires?: string[] | undefined;
|
|
90
|
+
}[] | undefined;
|
|
91
|
+
transactionalEmails?: {
|
|
92
|
+
code: string;
|
|
93
|
+
name: string;
|
|
94
|
+
variables: {
|
|
95
|
+
key: string;
|
|
96
|
+
label: string;
|
|
97
|
+
sampleValue?: string | undefined;
|
|
98
|
+
description?: string | undefined;
|
|
99
|
+
}[];
|
|
100
|
+
description?: string | undefined;
|
|
101
|
+
group?: string | undefined;
|
|
102
|
+
}[] | undefined;
|
|
103
|
+
capabilities?: string[] | undefined;
|
|
104
|
+
exclusiveCapabilities?: {
|
|
105
|
+
key: string;
|
|
106
|
+
errorCode: string;
|
|
107
|
+
}[] | undefined;
|
|
108
|
+
errorCodes?: {
|
|
109
|
+
code: string;
|
|
110
|
+
tokens?: string[] | undefined;
|
|
111
|
+
}[] | undefined;
|
|
112
|
+
blocks?: {
|
|
113
|
+
name: string;
|
|
114
|
+
labelKey: string;
|
|
115
|
+
category: string;
|
|
116
|
+
contexts: ("invoice" | "email" | "cms" | "newsletter")[];
|
|
117
|
+
fields: Record<string, {
|
|
118
|
+
type: "number" | "object" | "array" | "text" | "textarea" | "select" | "radio" | "external" | "uuid" | "richtext";
|
|
119
|
+
label?: string | undefined;
|
|
120
|
+
required?: boolean | undefined;
|
|
121
|
+
options?: {
|
|
122
|
+
label: string;
|
|
123
|
+
value: string | number;
|
|
124
|
+
}[] | undefined;
|
|
125
|
+
refKind?: string | undefined;
|
|
126
|
+
}>;
|
|
127
|
+
descriptionKey?: string | undefined;
|
|
128
|
+
defaultProps?: Record<string, unknown> | undefined;
|
|
129
|
+
responsiveFields?: string[] | undefined;
|
|
130
|
+
previewIcon?: string | undefined;
|
|
131
|
+
weight?: number | undefined;
|
|
132
|
+
}[] | undefined;
|
|
133
|
+
blockCategories?: {
|
|
134
|
+
key: string;
|
|
135
|
+
titleKey: string;
|
|
136
|
+
contexts: ("invoice" | "email" | "cms" | "newsletter")[];
|
|
137
|
+
weight?: number | undefined;
|
|
138
|
+
visible?: boolean | undefined;
|
|
139
|
+
}[] | undefined;
|
|
140
|
+
env?: {
|
|
141
|
+
name: string;
|
|
142
|
+
describes: {
|
|
143
|
+
en: string;
|
|
144
|
+
pl: string;
|
|
145
|
+
};
|
|
146
|
+
requirement: {
|
|
147
|
+
kind: "required";
|
|
148
|
+
} | {
|
|
149
|
+
kind: "requiredWhen";
|
|
150
|
+
input: string;
|
|
151
|
+
equals: string;
|
|
152
|
+
} | {
|
|
153
|
+
kind: "optional";
|
|
154
|
+
without: {
|
|
155
|
+
en: string;
|
|
156
|
+
pl: string;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
secret: boolean;
|
|
160
|
+
generable: boolean;
|
|
161
|
+
owner: {
|
|
162
|
+
kind: "platform";
|
|
163
|
+
} | {
|
|
164
|
+
kind: "application";
|
|
165
|
+
application: "admin" | "backend" | "storefront";
|
|
166
|
+
} | {
|
|
167
|
+
kind: "module";
|
|
168
|
+
moduleId: string;
|
|
169
|
+
};
|
|
170
|
+
consumers: ("admin" | "backend" | "storefront")[];
|
|
171
|
+
addressOf: "admin" | "backend" | "storefront" | null;
|
|
172
|
+
}[] | undefined;
|
|
173
|
+
};
|
|
174
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,sBAAsB;;CAEzB,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAC9B,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,OAAO,sBAAsB,CAAC,CAAC;AAEvE;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0JnB,CAAC"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Dictionary module manifest — feature 017 / R10 / T012.
|
|
2
|
+
//
|
|
3
|
+
// Single contribution: the `dictionary.write` permission code, used by
|
|
4
|
+
// every admin endpoint under `/api/v1/admin/dictionary/**`. The bootstrap
|
|
5
|
+
// "Platform Administrator" role holds the wildcard `*` permission and
|
|
6
|
+
// therefore auto-inherits this code; operators who need a narrower role
|
|
7
|
+
// can add `dictionary.write` to a custom role via the existing
|
|
8
|
+
// `/api/v1/admin/admin-roles` surface (feature 003).
|
|
9
|
+
//
|
|
10
|
+
// Reads of the Dictionary registry — both storefront (`/api/v1/dictionary`)
|
|
11
|
+
// and the cross-module DictionaryValidator port — DO NOT require this
|
|
12
|
+
// permission. They are public service surfaces.
|
|
13
|
+
import { defineModuleManifest } from '@endora-commerce/contracts';
|
|
14
|
+
export const DICTIONARY_PERMISSIONS = {
|
|
15
|
+
WRITE: 'dictionary.write',
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Module-lifecycle manifest (feature 018) — Pass B retrofit. The
|
|
19
|
+
* `dictionaries` schema is platform-foundational (migration 038),
|
|
20
|
+
* owned cross-cuttingly rather than by an install hook, so this entry
|
|
21
|
+
* declares no `installHook`. Its purpose is to register the module's
|
|
22
|
+
* presence in the static registry so other modules (notably `inventory`
|
|
23
|
+
* and `blog`) can declare `dictionaries` as a dependency without the
|
|
24
|
+
* registry warning "depends on … which is not in the static registry".
|
|
25
|
+
*/
|
|
26
|
+
export const manifest = defineModuleManifest({
|
|
27
|
+
id: 'dictionaries',
|
|
28
|
+
name: 'Dictionary',
|
|
29
|
+
description: 'Cross-module registry of countries, languages, and currencies — backs every dropdown, validator, and address-form picker on the storefront and admin.',
|
|
30
|
+
version: '1.0.0',
|
|
31
|
+
// `auth` owns the `requireAdmin` port the admin routes are gated by. Feature
|
|
32
|
+
// 072 made it a container resolution rather than an optional argument that
|
|
33
|
+
// decided whether the admin surface existed at all.
|
|
34
|
+
dependencies: ['currencies', 'languages', 'auth'],
|
|
35
|
+
i18n: { bundlesDir: 'i18n' },
|
|
36
|
+
docs: { dir: 'docs' },
|
|
37
|
+
permissions: [{ code: DICTIONARY_PERMISSIONS.WRITE, label: 'Manage dictionary registry' }],
|
|
38
|
+
/**
|
|
39
|
+
* Feature 090 Phase 3 — the eight error codes the incumbent prefix chain
|
|
40
|
+
* routes to `dictionaries`, copied from the frozen capture
|
|
41
|
+
* (`backend/test/fixtures/error-code-routing/chain-answers.ts`, the chain's
|
|
42
|
+
* *answer* at `49f3c6817`) rather than judged. The list is not curated: the
|
|
43
|
+
* migration is answer-preserving over all 289 codes, so a code is here
|
|
44
|
+
* because the chain put it here.
|
|
45
|
+
*
|
|
46
|
+
* **Six of the eight are raised outside this package, and one of those is
|
|
47
|
+
* raised nowhere inside it** — D-95.2 working as intended, since ownership
|
|
48
|
+
* follows the domain noun and never the thrower. `dictionaries` is a screen
|
|
49
|
+
* over other modules' catalogues rather than the owner of their rows: the
|
|
50
|
+
* `currencies` and `languages` services raise
|
|
51
|
+
* `DICTIONARY_DEFAULT_CANNOT_BE_DEACTIVATED`, `DICTIONARY_LAST_ACTIVE_ENTRY`,
|
|
52
|
+
* `DICTIONARY_ENTRY_HAS_DEPENDENTS`, `DICTIONARY_ENTRY_NOT_FOUND` and — for
|
|
53
|
+
* `DICTIONARY_FALLBACK_CYCLE`, whose only three raise sites are in
|
|
54
|
+
* `languages` — all of them. `DICTIONARY_ENTRY_INACTIVE` is raised once here
|
|
55
|
+
* and nine times by consumer modules (`addresses`, `blog` twice, `inventory`,
|
|
56
|
+
* `megamenu`, `organizations`, `promotions`, `sales_channels`, `taxes`),
|
|
57
|
+
* which translate a caught `DictionaryReferenceError` into
|
|
58
|
+
* `new HttpError(409, err.code, …)` — the code is computed there, so the
|
|
59
|
+
* literal never appears as the second argument.
|
|
60
|
+
*
|
|
61
|
+
* **The inverse holds too, and it is a decision an earlier feature made**
|
|
62
|
+
* (trap T2). `UNKNOWN_CURRENCY_CODE` and `UNKNOWN_LANGUAGE_CODE` read like
|
|
63
|
+
* this module's and route to `sales_channels`, which declared them in !1125;
|
|
64
|
+
* feature 017 superseded both with `DICTIONARY_ENTRY_NOT_FOUND`, so the
|
|
65
|
+
* sentences that answer today are here and the ownership of the legacy codes
|
|
66
|
+
* is not. `CURRENCY_MISMATCH` routes to `core`. None of the three is declared
|
|
67
|
+
* here, and re-routing is out of scope
|
|
68
|
+
* (`specs/090-module-owned-error-codes/` §6.5).
|
|
69
|
+
*
|
|
70
|
+
* **Two of the eight are raised by nothing**, searched in both spellings
|
|
71
|
+
* (`ERROR_CODES.<CODE>` and the bare quoted literal) over `backend/src` and
|
|
72
|
+
* `packages`, test files excluded. They are declared anyway — ownership
|
|
73
|
+
* follows the capture (trap T10) — and what happens instead was established
|
|
74
|
+
* rather than classified:
|
|
75
|
+
*
|
|
76
|
+
* - `DICTIONARY_TRANSLATION_LANGUAGE_INACTIVE` — the rule is built and
|
|
77
|
+
* enforced. `TranslationService.upsert` refuses a translation whose
|
|
78
|
+
* language is inactive, in that exact condition, under the coarser
|
|
79
|
+
* `DICTIONARY_ENTRY_INACTIVE`. The specific sentence is unreachable
|
|
80
|
+
* because a live successor answers first, and the two agree about what
|
|
81
|
+
* happened.
|
|
82
|
+
* - `DICTIONARY_CODE_IMMUTABLE` — nothing refuses, because nothing can ask.
|
|
83
|
+
* No write path anywhere renames an entry: `updateCountryRequestSchema`,
|
|
84
|
+
* `updateDictionaryCurrencyRequestSchema` and
|
|
85
|
+
* `updateDictionaryLanguageRequestSchema` carry no `code` field, the three
|
|
86
|
+
* `Update*Input` types carry none either, and the entry code comes off the
|
|
87
|
+
* URL parameter. The schemas are non-strict `z.object()`s, so a `code` in
|
|
88
|
+
* the body is dropped silently — not refused as `VALIDATION_FAILED`. The
|
|
89
|
+
* immutability is structural and the refusal has no occasion to fire.
|
|
90
|
+
*
|
|
91
|
+
* No `tokens`: no code here carries a refusal discriminator. `refusalToken`
|
|
92
|
+
* reads `details.code` and nothing else, and no `new HttpError` raising one
|
|
93
|
+
* of these eight passes a fourth argument with a `code` member. Three of them
|
|
94
|
+
* do pass a fourth argument — all three `DICTIONARY_ENTRY_HAS_DEPENDENTS`
|
|
95
|
+
* sites pass the Zod-style `Array<{ path, issue }>`, which `refusalToken`
|
|
96
|
+
* ignores by construction. The runbook's §5 raise-site scan attributes the
|
|
97
|
+
* tree's ten token-carrying codes to `core`, `invoices` and `carts` and names
|
|
98
|
+
* none of these; the bundles hold no `errors.<CODE>.<token>` key in the other
|
|
99
|
+
* direction.
|
|
100
|
+
*/
|
|
101
|
+
errorCodes: [
|
|
102
|
+
{ code: 'DICTIONARY_CODE_IMMUTABLE' },
|
|
103
|
+
{ code: 'DICTIONARY_DEFAULT_CANNOT_BE_DEACTIVATED' },
|
|
104
|
+
{ code: 'DICTIONARY_ENTRY_HAS_DEPENDENTS' },
|
|
105
|
+
{ code: 'DICTIONARY_ENTRY_INACTIVE' },
|
|
106
|
+
{ code: 'DICTIONARY_ENTRY_NOT_FOUND' },
|
|
107
|
+
{ code: 'DICTIONARY_FALLBACK_CYCLE' },
|
|
108
|
+
{ code: 'DICTIONARY_LAST_ACTIVE_ENTRY' },
|
|
109
|
+
{ code: 'DICTIONARY_TRANSLATION_LANGUAGE_INACTIVE' },
|
|
110
|
+
],
|
|
111
|
+
/**
|
|
112
|
+
* Feature 091, Phase 4 batch 10 — the two palette entries this module has
|
|
113
|
+
* always advertised, declared where the server can filter them.
|
|
114
|
+
*
|
|
115
|
+
* `AppShell.tsx`'s `PALETTE_ITEMS` carried a hand-written *Navigate* row for
|
|
116
|
+
* each of these two screens, and a hand-written palette row is a copy the
|
|
117
|
+
* server was never asked about: it kept advertising the screens whatever the
|
|
118
|
+
* effective enabled-set said. Both arrive here instead, with the
|
|
119
|
+
* destinations, the code and the keywords those rows carried, so nothing an
|
|
120
|
+
* operator can see changes and the advertisement is now gated the way every
|
|
121
|
+
* other one is.
|
|
122
|
+
*
|
|
123
|
+
* **Both declare `dictionary.write`, which is the only code this module has.**
|
|
124
|
+
* All 23 registrations under `/api/v1/admin/dictionary/*` enforce it, reads
|
|
125
|
+
* included — the registry screen is an editing surface and this module never
|
|
126
|
+
* split read from write — so the action, the route and the API are one code
|
|
127
|
+
* and the palette never advertises a 403.
|
|
128
|
+
*/
|
|
129
|
+
actions: [
|
|
130
|
+
{
|
|
131
|
+
id: 'open-dictionary',
|
|
132
|
+
labelKey: 'actions.openDictionary.label',
|
|
133
|
+
descriptionKey: 'actions.openDictionary.description',
|
|
134
|
+
icon: 'Languages',
|
|
135
|
+
targetRoute: '/dictionary',
|
|
136
|
+
requiredPermission: DICTIONARY_PERMISSIONS.WRITE,
|
|
137
|
+
keywords: [
|
|
138
|
+
'dictionary',
|
|
139
|
+
'countries',
|
|
140
|
+
'currencies',
|
|
141
|
+
'languages',
|
|
142
|
+
'i18n',
|
|
143
|
+
'słownik',
|
|
144
|
+
'kraje',
|
|
145
|
+
'waluty',
|
|
146
|
+
'języki',
|
|
147
|
+
],
|
|
148
|
+
weight: 250,
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
id: 'open-dictionary-audit',
|
|
152
|
+
labelKey: 'actions.openDictionaryAudit.label',
|
|
153
|
+
descriptionKey: 'actions.openDictionaryAudit.description',
|
|
154
|
+
icon: 'ListChecks',
|
|
155
|
+
// The `/admin`-prefixed spelling, which is the one the sidebar row
|
|
156
|
+
// advertised and the one this module's nav contribution declares. The
|
|
157
|
+
// unprefixed `/dictionaries/audit` route still resolves and is
|
|
158
|
+
// deliberately not advertised twice.
|
|
159
|
+
targetRoute: '/admin/dictionaries/audit',
|
|
160
|
+
requiredPermission: DICTIONARY_PERMISSIONS.WRITE,
|
|
161
|
+
keywords: ['dictionary', 'audit', 'orphan', 'references', 'audyt', 'słownika'],
|
|
162
|
+
weight: 251,
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
// Feature 074 (Constitution XVII), test C3 — platform primitive. The flag
|
|
166
|
+
// used to rest on `organizations` declaring this module; ruling 2 withdraws
|
|
167
|
+
// a dependent's authority to impose the lock, so the ground is now this
|
|
168
|
+
// module's own. It is the shared reference-data primitive — countries,
|
|
169
|
+
// units, document types — that every other module validates and renders
|
|
170
|
+
// against. There is no business decision underneath it: nobody chooses to
|
|
171
|
+
// stop having countries.
|
|
172
|
+
activation: {
|
|
173
|
+
nonDeactivatable: true,
|
|
174
|
+
reason: 'The shared reference-data primitive — countries, units, document types — that every ' +
|
|
175
|
+
'other surface validates and renders against.',
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,EAAE;AACF,uEAAuE;AACvE,0EAA0E;AAC1E,sEAAsE;AACtE,wEAAwE;AACxE,+DAA+D;AAC/D,qDAAqD;AACrD,EAAE;AACF,4EAA4E;AAC5E,sEAAsE;AACtE,gDAAgD;AAEhD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,KAAK,EAAE,kBAAkB;CACjB,CAAC;AAKX;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,oBAAoB,CAAC;IAC3C,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,YAAY;IAClB,WAAW,EACT,uJAAuJ;IACzJ,OAAO,EAAE,OAAO;IAChB,6EAA6E;IAC7E,2EAA2E;IAC3E,oDAAoD;IACpD,YAAY,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC;IACjD,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE;IAC5B,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE;IACrB,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,sBAAsB,CAAC,KAAK,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC;IAE1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8DG;IACH,UAAU,EAAE;QACV,EAAE,IAAI,EAAE,2BAA2B,EAAE;QACrC,EAAE,IAAI,EAAE,0CAA0C,EAAE;QACpD,EAAE,IAAI,EAAE,iCAAiC,EAAE;QAC3C,EAAE,IAAI,EAAE,2BAA2B,EAAE;QACrC,EAAE,IAAI,EAAE,4BAA4B,EAAE;QACtC,EAAE,IAAI,EAAE,2BAA2B,EAAE;QACrC,EAAE,IAAI,EAAE,8BAA8B,EAAE;QACxC,EAAE,IAAI,EAAE,0CAA0C,EAAE;KACrD;IACD;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,EAAE;QACP;YACE,EAAE,EAAE,iBAAiB;YACrB,QAAQ,EAAE,8BAA8B;YACxC,cAAc,EAAE,oCAAoC;YACpD,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,aAAa;YAC1B,kBAAkB,EAAE,sBAAsB,CAAC,KAAK;YAChD,QAAQ,EAAE;gBACR,YAAY;gBACZ,WAAW;gBACX,YAAY;gBACZ,WAAW;gBACX,MAAM;gBACN,SAAS;gBACT,OAAO;gBACP,QAAQ;gBACR,QAAQ;aACT;YACD,MAAM,EAAE,GAAG;SACZ;QACD;YACE,EAAE,EAAE,uBAAuB;YAC3B,QAAQ,EAAE,mCAAmC;YAC7C,cAAc,EAAE,yCAAyC;YACzD,IAAI,EAAE,YAAY;YAClB,mEAAmE;YACnE,sEAAsE;YACtE,+DAA+D;YAC/D,qCAAqC;YACrC,WAAW,EAAE,2BAA2B;YACxC,kBAAkB,EAAE,sBAAsB,CAAC,KAAK;YAChD,QAAQ,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,CAAC;YAC9E,MAAM,EAAE,GAAG;SACZ;KACF;IACD,0EAA0E;IAC1E,4EAA4E;IAC5E,wEAAwE;IACxE,uEAAuE;IACvE,wEAAwE;IACxE,0EAA0E;IAC1E,yBAAyB;IACzB,UAAU,EAAE;QACV,gBAAgB,EAAE,IAAI;QACtB,MAAM,EACJ,sFAAsF;YACtF,8CAA8C;KACjD;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
/**
|
|
3
|
+
* Dictionary module — feature 017 / data-model.md.
|
|
4
|
+
*
|
|
5
|
+
* Schema changes (one atomic migration):
|
|
6
|
+
* - new tables: countries, dictionary_translations, language_countries.
|
|
7
|
+
* - ALTER `languages` ADD COLUMN native_label, is_rtl, fallback_code (self-FK).
|
|
8
|
+
* - ALTER `currencies` ADD COLUMN symbol_position, decimal_places (CHECKs).
|
|
9
|
+
* - partial unique index `uniq_countries_one_default` for the "exactly one
|
|
10
|
+
* default" invariant (mirrors the analogous indexes on languages and
|
|
11
|
+
* currencies introduced by migration 012).
|
|
12
|
+
* - partial unique index `uniq_language_countries_primary_per_country`
|
|
13
|
+
* for the "at most one primary language per country" invariant.
|
|
14
|
+
* - btree indexes: `idx_countries_active`, `idx_countries_sort`,
|
|
15
|
+
* `idx_dict_translations_lang`, `idx_language_countries_country`.
|
|
16
|
+
* - FK `countries.default_currency_code` → `currencies(code)` ON DELETE
|
|
17
|
+
* SET NULL — added LAST (after seed inserts run via the runtime
|
|
18
|
+
* SeedReconciler) so the constraint is satisfied for every seeded row
|
|
19
|
+
* without the migration carrying ~250 inline INSERTs.
|
|
20
|
+
*
|
|
21
|
+
* No seed rows in this migration. The countries seed, the Polish
|
|
22
|
+
* translations seed, the en-US/pl-PL language↔country primary associations,
|
|
23
|
+
* and the back-fill of `currencies.symbol_position` / `decimal_places`
|
|
24
|
+
* and `languages.native_label` / `is_rtl` are inserted by the runtime
|
|
25
|
+
* `SeedReconciler` in `services/seed-reconciler.ts` so admin edits across
|
|
26
|
+
* deploys stay safe (R6 + R8). The reconciler is idempotent and runs on
|
|
27
|
+
* every backend boot via the dictionaries module plugin.
|
|
28
|
+
*/
|
|
29
|
+
export declare class Migration20260506T112634DictionariesDictionaryInit extends Migration {
|
|
30
|
+
up(): Promise<void>;
|
|
31
|
+
down(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=20260506T112634_dictionaries_dictionary_init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260506T112634_dictionaries_dictionary_init.d.ts","sourceRoot":"","sources":["../../src/migrations/20260506T112634_dictionaries_dictionary_init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,kDAAmD,SAAQ,SAAS;IAChE,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAgInB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAcrC"}
|