intor 1.0.39 → 2.0.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/dist/index.cjs CHANGED
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var logry = require('logry');
4
- var headers = require('next/headers');
5
3
  var path = require('path');
6
4
  var perf_hooks = require('perf_hooks');
7
5
  var pLimit = require('p-limit');
8
6
  var fs = require('fs/promises');
7
+ var logry = require('logry');
8
+ var Keyv = require('keyv');
9
9
  var intorTranslator = require('intor-translator');
10
10
 
11
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -13,10 +13,25 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
13
  var path__default = /*#__PURE__*/_interopDefault(path);
14
14
  var pLimit__default = /*#__PURE__*/_interopDefault(pLimit);
15
15
  var fs__default = /*#__PURE__*/_interopDefault(fs);
16
+ var Keyv__default = /*#__PURE__*/_interopDefault(Keyv);
17
+
18
+ // src/modules/intor/utils/should-load-messages.ts
19
+ var shouldLoadMessages = (loader) => {
20
+ if (!loader) return false;
21
+ const { type, lazyLoad } = loader;
22
+ if (type === "import") return true;
23
+ if (lazyLoad) return false;
24
+ return true;
25
+ };
16
26
 
17
- // src/modules/intor/intor.ts
27
+ // src/modules/config/constants/cache.constants.ts
28
+ var DEFAULT_CACHE_OPTIONS = {
29
+ enabled: process.env.NODE_ENV === "production",
30
+ ttl: 60 * 60 * 1e3
31
+ // 1 hour
32
+ };
18
33
 
19
- // src/modules/intor-error/intor-error.ts
34
+ // src/shared/error/intor-error.ts
20
35
  var IntorError = class extends Error {
21
36
  constructor({ message, code, id }) {
22
37
  const fullMessage = id ? `[${id}] ${message}` : message;
@@ -28,218 +43,95 @@ var IntorError = class extends Error {
28
43
  }
29
44
  };
30
45
 
31
- // src/modules/intor-error/intor-error-types.ts
32
- var IntorErrorCode = /* @__PURE__ */ ((IntorErrorCode2) => {
33
- IntorErrorCode2["MISSING_DEFAULT_LOCALE"] = "INTOR_MISSING_DEFAULT_LOCALE";
34
- IntorErrorCode2["UNSUPPORTED_DEFAULT_LOCALE"] = "INTOR_UNSUPPORTED_DEFAULT_LOCALE";
35
- IntorErrorCode2["MISSING_SUPPORTED_LOCALES"] = "INTOR_MISSING_SUPPORTED_LOCALES";
36
- IntorErrorCode2["UNSUPPORTED_ADAPTER"] = "INTOR_UNSUPPORTED_ADAPTER";
37
- IntorErrorCode2["ADAPTER_RUNTIME_LOAD_FAILED"] = "INTOR_ADAPTER_RUNTIME_LOAD_FAILED";
38
- IntorErrorCode2["UNKNOWN_LOADER_TYPE"] = "INTOR_UNKNOWN_LOADER_TYPE";
39
- return IntorErrorCode2;
40
- })(IntorErrorCode || {});
41
-
42
- // src/adapters/next-client/constants/header-key-constants.ts
43
- var DEFAULT_PATHNAME_HEADER_NAME = "x-intor-pathname";
44
-
45
- // src/shared/utils/locale/normalize-locale.ts
46
- var normalizeLocale = (locale = "", supportedLocales = []) => {
47
- if (!locale || supportedLocales.length === 0) return void 0;
48
- const toCanonical = (input) => {
49
- try {
50
- return Intl.getCanonicalLocales(input)[0]?.toLowerCase();
51
- } catch {
52
- return void 0;
53
- }
54
- };
55
- const canonicalLocale = toCanonical(locale);
56
- if (!canonicalLocale) return void 0;
57
- const supportedCanonicalMap = /* @__PURE__ */ new Map();
58
- for (const l of supportedLocales) {
59
- const normalized = toCanonical(l);
60
- if (normalized) {
61
- supportedCanonicalMap.set(normalized, l);
62
- }
63
- }
64
- if (supportedCanonicalMap.has(canonicalLocale)) {
65
- return supportedCanonicalMap.get(canonicalLocale);
66
- }
67
- const baseLang = canonicalLocale.split("-")[0];
68
- for (const [key, original] of supportedCanonicalMap) {
69
- const supportedBase = key.split("-")[0];
70
- if (supportedBase === baseLang) {
71
- return original;
72
- }
73
- }
74
- return void 0;
75
- };
76
-
77
- // src/shared/utils/locale/resolve-preferred-locale.ts
78
- var resolvePreferredLocale = (acceptLanguageHeader, supportedLocales) => {
79
- if (!acceptLanguageHeader || !supportedLocales || supportedLocales.length === 0) {
80
- return;
81
- }
82
- const supportedLocalesSet = new Set(supportedLocales);
83
- const preferred = acceptLanguageHeader.split(",").map((part) => {
84
- const [lang, qValue] = part.split(";");
85
- const q = qValue ? parseFloat(qValue.split("=")[1]) : 1;
86
- if (isNaN(q)) {
87
- return { lang: lang.trim(), q: 0 };
88
- }
89
- return { lang: lang.trim(), q };
90
- }).sort((a, b) => b.q - a.q).find(({ lang }) => supportedLocalesSet.has(lang))?.lang;
91
- return preferred;
92
- };
93
-
94
- // src/adapters/next-client/next-client-runtime/next-client-runtime.ts
95
- var nextClientRuntime = async ({
96
- config
97
- }) => {
98
- const cookiesStore = await headers.cookies();
99
- const headersStore = await headers.headers();
100
- const logger = logry.logry({ id: config.id, scope: "nextClientRuntime" });
101
- const { defaultLocale, supportedLocales = [], cookie, routing } = config;
102
- let locale;
103
- if (!cookie.disabled) {
104
- const localeFromCookie = cookiesStore.get(cookie.name)?.value;
105
- locale = normalizeLocale(localeFromCookie, supportedLocales);
106
- if (locale) {
107
- logger.debug("Get locale from cookie:", { locale });
108
- }
109
- }
110
- if (!locale && routing.firstVisit.localeSource === "browser") {
111
- const aLHeader = headersStore.get("accept-language") || void 0;
112
- const preferredLocale = resolvePreferredLocale(aLHeader, supportedLocales);
113
- locale = normalizeLocale(preferredLocale, supportedLocales);
114
- logger.debug("Get locale from browser:", { locale });
115
- }
116
- const pathname = headersStore.get(DEFAULT_PATHNAME_HEADER_NAME);
117
- if (pathname) {
118
- logger.debug("Get pathname from next headers:", { pathname });
119
- }
120
- return {
121
- locale: locale || defaultLocale,
122
- pathname: pathname || ""
123
- };
124
- };
125
- var nextServerRuntime = async ({
126
- config,
127
- request
128
- }) => {
129
- const cookiesStore = await headers.cookies();
130
- const headersStore = await headers.headers();
131
- const logger = logry.logry({ id: config.id, scope: "nextServerRuntime" });
132
- const { defaultLocale, supportedLocales = [], cookie, routing } = config;
133
- let locale;
134
- if (!cookie.disabled) {
135
- const localeFromCookie = cookiesStore.get(cookie.name)?.value;
136
- locale = normalizeLocale(localeFromCookie, supportedLocales);
137
- if (locale) {
138
- logger.debug("Get locale from cookie:", { locale });
139
- }
140
- }
141
- if (!locale && routing.firstVisit.localeSource === "browser") {
142
- const aLHeader = headersStore.get("accept-language") || void 0;
143
- const preferredLocale = resolvePreferredLocale(aLHeader, supportedLocales);
144
- locale = normalizeLocale(preferredLocale, supportedLocales);
145
- logger.debug("Get locale from browser:", { locale });
146
- }
147
- let pathname = "";
148
- if (request && typeof request === "object" && "nextUrl" in request) {
149
- pathname = request.nextUrl.pathname;
150
- if (pathname) {
151
- logger.debug("Get pathname from next request:", { pathname });
152
- }
153
- }
154
- if (!pathname) {
155
- pathname = headersStore.get(DEFAULT_PATHNAME_HEADER_NAME);
156
- if (pathname) {
157
- logger.debug("Get pathname from next headers:", { pathname });
158
- }
159
- }
160
- if (!cookie.disabled && cookie.autoSetCookie) {
161
- cookiesStore.set({
162
- name: cookie.name,
163
- value: locale || defaultLocale,
164
- ...cookie.domain ? { domain: cookie.domain } : {},
165
- path: cookie.path,
166
- maxAge: cookie.maxAge,
167
- httpOnly: cookie.httpOnly,
168
- secure: cookie.secure,
169
- sameSite: cookie.sameSite
170
- });
171
- logger.debug("Set locale to cookie:", {
172
- cookie: { name: cookie.name, value: locale || defaultLocale }
173
- });
174
- }
175
- return {
176
- locale: locale || defaultLocale,
177
- pathname: pathname || ""
178
- };
179
- };
180
-
181
- // src/modules/intor-adapter/resolve-adapter-runtime-loader.ts
182
- var resolceAdapterRuntimeLoader = async ({
183
- config
184
- }) => {
185
- const { adapter } = config;
186
- let loadedRuntime;
187
- if (adapter === "next-client") {
188
- loadedRuntime = nextClientRuntime;
189
- } else if (adapter === "next-server") {
190
- loadedRuntime = nextServerRuntime;
191
- }
192
- return loadedRuntime;
193
- };
194
-
195
- // src/modules/intor-config/types/intor-adapter-types.ts
196
- var intorAdapters = ["next-client", "next-server"];
197
- var readMessageRecordFile = async (filePath) => {
46
+ // src/modules/messages/load-local-messages/utils/read-message-record-file.ts
47
+ var readMessageRecordFile = async (filePath, loggerOptions) => {
198
48
  const fileName = path__default.default.basename(filePath, ".json");
199
49
  const content = await fs__default.default.readFile(filePath, "utf-8");
200
50
  const parsed = JSON.parse(content);
201
51
  if (typeof parsed !== "object" || parsed === null) {
202
- throw new Error(`Invalid message format`);
52
+ throw new IntorError({
53
+ id: loggerOptions.id,
54
+ code: "INTOR_INVALID_MESSAGE_FORMAT" /* INVALID_MESSAGE_FORMAT */,
55
+ message: "Invalid message format"
56
+ });
203
57
  }
204
58
  return { fileName, content: parsed };
205
59
  };
206
60
 
207
- // src/modules/intor-messages-loader/load-local-messages/load-namespace-group/parse-message-file.ts
61
+ // src/shared/logger/global-logger-pool.ts
62
+ function getGlobalLoggerPool() {
63
+ if (!globalThis.__INTOR_LOGGER_POOL__) {
64
+ globalThis.__INTOR_LOGGER_POOL__ = /* @__PURE__ */ new Map();
65
+ }
66
+ return globalThis.__INTOR_LOGGER_POOL__;
67
+ }
68
+ function clearLoggerPool() {
69
+ const pool = getGlobalLoggerPool();
70
+ pool.clear();
71
+ }
72
+
73
+ // src/shared/logger/get-logger.ts
74
+ var DEFAULT_FORMATTER_CONFIG = {
75
+ node: { meta: { compact: true }, lineBreaksAfter: 1 }
76
+ };
77
+ function getLogger({
78
+ id,
79
+ formatterConfig = DEFAULT_FORMATTER_CONFIG,
80
+ ...options
81
+ }) {
82
+ const pool = getGlobalLoggerPool();
83
+ let logger = pool.get(id);
84
+ if (!logger) {
85
+ logger = logry.logry({ id, formatterConfig, ...options });
86
+ pool.set(id, logger);
87
+ if (pool.size > 1e3) {
88
+ const keys = Array.from(pool.keys());
89
+ for (const key of keys.slice(0, 200)) pool.delete(key);
90
+ }
91
+ }
92
+ return logger;
93
+ }
94
+
95
+ // src/modules/messages/load-local-messages/load-namespace-group/parse-message-file.ts
208
96
  var MAX_PATH_LENGTH = 260;
209
- var parseMessageFile = async (filePath, loggerId) => {
210
- const logger = logry.logry({ id: loggerId, scope: "parseMessageFile" });
97
+ var parseMessageFile = async (filePath, loggerOptions) => {
98
+ const baseLogger = getLogger({ ...loggerOptions });
99
+ const logger = baseLogger.child({ scope: "parse-message-file" });
211
100
  const trimmedPath = filePath.trim();
212
101
  if (!trimmedPath) {
213
- logger?.warn("Invalid file path provided.", { filePath: trimmedPath });
102
+ logger.warn("File path is empty.", { filePath: trimmedPath });
214
103
  return null;
215
104
  }
216
105
  if (trimmedPath.length > MAX_PATH_LENGTH) {
217
- logger?.warn("Invalid file path provided.", { filePath: trimmedPath });
106
+ logger.warn("File path exceeds maximum length.", { filePath: trimmedPath });
218
107
  return null;
219
108
  }
220
109
  const fileName = path__default.default.basename(trimmedPath);
221
110
  if (!fileName.toLowerCase().endsWith(".json")) {
222
- logger?.debug(`Skipped non-JSON file.`, { filePath: trimmedPath });
111
+ logger.trace("Skipped non-JSON file.", { filePath: trimmedPath });
223
112
  return null;
224
113
  }
225
114
  try {
226
- const { content } = await readMessageRecordFile(trimmedPath);
227
- logger?.debug(`Loaded a file.`, { filePath: trimmedPath });
115
+ const { content } = await readMessageRecordFile(trimmedPath, loggerOptions);
116
+ logger.trace(`Message file loaded.`, { filePath: trimmedPath });
228
117
  return content;
229
118
  } catch (error) {
230
- logger?.warn(`Failed to load file.`, { filePath: trimmedPath, error });
119
+ logger.warn("Failed to parse message file.", {
120
+ filePath: trimmedPath,
121
+ error
122
+ });
231
123
  return null;
232
124
  }
233
125
  };
234
126
 
235
- // src/modules/intor-messages-loader/load-local-messages/load-namespace-group/merge-namespace-messages.ts
236
- var mergeNamespaceMessages = async (filePaths, isAtRoot, loggerId) => {
127
+ // src/modules/messages/load-local-messages/load-namespace-group/merge-namespace-messages.ts
128
+ var mergeNamespaceMessages = async (filePaths, isAtRoot, loggerOptions) => {
237
129
  const baseContent = {};
238
130
  const subEntries = {};
239
131
  await Promise.all(
240
132
  filePaths.map(async (filePath) => {
241
133
  const fileName = path__default.default.basename(filePath);
242
- const content = await parseMessageFile(filePath, loggerId);
134
+ const content = await parseMessageFile(filePath, loggerOptions);
243
135
  if (!content) {
244
136
  return;
245
137
  }
@@ -254,20 +146,21 @@ var mergeNamespaceMessages = async (filePaths, isAtRoot, loggerId) => {
254
146
  return { base: baseContent, sub: subEntries };
255
147
  };
256
148
 
257
- // src/modules/intor-messages-loader/load-local-messages/load-namespace-group/load-namespace-group.ts
149
+ // src/modules/messages/load-local-messages/load-namespace-group/load-namespace-group.ts
258
150
  var loadNamespaceGroup = async ({
259
151
  locale,
260
152
  namespace,
261
153
  messages,
262
154
  namespaceGroupValue,
263
155
  limit,
264
- loggerId
156
+ logger: loggerOptions = { id: "default" }
265
157
  }) => {
266
- const logger = logry.logry({ id: loggerId, scope: "loadNamespaceGroup" });
158
+ const baseLogger = getLogger({ ...loggerOptions });
159
+ const logger = baseLogger.child({ scope: "load-namespace-group" });
267
160
  const { isAtRoot, filePaths } = namespaceGroupValue;
268
161
  if (filePaths.length === 0) {
269
- logger?.debug?.(
270
- `Skipped merging [${locale}][${namespace}] because filePaths is empty`
162
+ logger.trace(
163
+ `Skipped merging ${locale}/${namespace} because filePaths is empty`
271
164
  );
272
165
  return;
273
166
  }
@@ -275,15 +168,19 @@ var loadNamespaceGroup = async ({
275
168
  const { base, sub } = await mergeNamespaceMessages(
276
169
  filePaths,
277
170
  isAtRoot,
278
- loggerId
171
+ loggerOptions
279
172
  );
280
173
  if (!messages[locale]) {
281
174
  messages[locale] = {};
282
175
  }
176
+ if (isAtRoot && filePaths.length === 1 && path__default.default.basename(filePaths[0]) === "index.json") {
177
+ messages[locale] = { ...messages[locale], ...base };
178
+ return;
179
+ }
283
180
  const finalContent = isAtRoot ? base : { ...base, ...sub };
284
181
  messages[locale][namespace] = finalContent;
285
182
  if (!isAtRoot && Object.keys(finalContent).length > 0) {
286
- logger?.debug(
183
+ logger.trace(
287
184
  `Merged ${locale}/${namespace} from ${filePaths.length} file(s)`,
288
185
  { namespace }
289
186
  );
@@ -316,15 +213,17 @@ var addToNamespaceGroup = ({
316
213
  }
317
214
  };
318
215
 
319
- // src/modules/intor-messages-loader/load-local-messages/prepare-namespace-groups/traverse-directory.ts
216
+ // src/modules/messages/load-local-messages/prepare-namespace-groups/traverse-directory.ts
320
217
  var traverseDirectory = async ({
321
218
  options,
322
219
  currentDirPath,
323
220
  namespaceGroups,
324
221
  namespacePathSegments
325
222
  }) => {
326
- const { limit, loggerId } = options;
327
- const logger = logry.logry({ id: loggerId, scope: "traverseDirectory" });
223
+ const { limit } = options;
224
+ const loggerOptions = options.logger || { id: "default" };
225
+ const baseLogger = getLogger({ ...loggerOptions });
226
+ const logger = baseLogger.child({ scope: "traverse-directory" });
328
227
  try {
329
228
  const dirents = await fs__default.default.readdir(currentDirPath, { withFileTypes: true });
330
229
  const dirPromises = dirents.map(
@@ -360,7 +259,7 @@ var traverseDirectory = async ({
360
259
  }
361
260
  };
362
261
 
363
- // src/modules/intor-messages-loader/load-local-messages/prepare-namespace-groups/prepare-namespace-groups.ts
262
+ // src/modules/messages/load-local-messages/prepare-namespace-groups/prepare-namespace-groups.ts
364
263
  var prepareNamespaceGroups = async (options) => {
365
264
  const { basePath } = options;
366
265
  const namespaceGroups = /* @__PURE__ */ new Map();
@@ -373,16 +272,17 @@ var prepareNamespaceGroups = async (options) => {
373
272
  return namespaceGroups;
374
273
  };
375
274
 
376
- // src/modules/intor-messages-loader/load-local-messages/load-single-locale/load-single-locale.ts
275
+ // src/modules/messages/load-local-messages/load-single-locale/load-single-locale.ts
377
276
  var loadSingleLocale = async ({
378
277
  basePath,
379
278
  locale,
380
279
  namespaces,
381
280
  messages,
382
281
  limit,
383
- loggerId
282
+ logger: loggerOptions = { id: "default" }
384
283
  }) => {
385
- const logger = logry.logry({ id: loggerId, scope: "loadSingleLocale" });
284
+ const baseLogger = getLogger({ ...loggerOptions });
285
+ const logger = baseLogger.child({ scope: "load-single-locale" });
386
286
  const localePath = path__default.default.join(basePath, locale);
387
287
  const validNamespaces = [];
388
288
  try {
@@ -395,14 +295,14 @@ var loadSingleLocale = async ({
395
295
  return;
396
296
  }
397
297
  } catch (error) {
398
- logger.warn("Error checking locale path:", { locale, error });
298
+ logger.warn("Error checking locale path.", { locale, error });
399
299
  return;
400
300
  }
401
301
  const namespaceGroups = await prepareNamespaceGroups({
402
302
  basePath: localePath,
403
303
  limit,
404
304
  namespaces: new Set(namespaces || []),
405
- loggerId
305
+ logger: loggerOptions
406
306
  });
407
307
  if (namespaceGroups.size === 0) {
408
308
  logger.warn("No namespace groups found.", {
@@ -412,7 +312,7 @@ var loadSingleLocale = async ({
412
312
  });
413
313
  return;
414
314
  }
415
- logger.debug("Prepared namespace groups from scanning local files:", {
315
+ logger.trace("Prepared namespace groups from scanning local files.", {
416
316
  namespaceGroups: [...namespaceGroups.entries()].map(([ns, val]) => ({
417
317
  namespace: ns,
418
318
  isAtRoot: val.isAtRoot,
@@ -428,14 +328,14 @@ var loadSingleLocale = async ({
428
328
  messages,
429
329
  namespaceGroupValue,
430
330
  limit,
431
- loggerId
331
+ logger: loggerOptions
432
332
  }).then(() => validNamespaces.push(namespace))
433
333
  );
434
334
  await Promise.all(namespaceGroupTasks);
435
335
  return validNamespaces;
436
336
  };
437
337
 
438
- // src/modules/intor-messages-loader/load-local-messages/load-locale-with-fallback/load-locale-with-fallback.ts
338
+ // src/modules/messages/load-local-messages/load-locale-with-fallback/load-locale-with-fallback.ts
439
339
  var loadLocaleWithFallback = async ({
440
340
  basePath,
441
341
  locale: targetLocale,
@@ -443,9 +343,10 @@ var loadLocaleWithFallback = async ({
443
343
  namespaces,
444
344
  messages,
445
345
  limit,
446
- loggerId
346
+ logger: loggerOptions = { id: "default" }
447
347
  }) => {
448
- const logger = logry.logry({ id: loggerId, scope: "loadLocaleWithFallback" });
348
+ const baseLogger = getLogger({ ...loggerOptions });
349
+ const logger = baseLogger.child({ scope: "load-locale-with-fallback" });
449
350
  const localesToTry = [targetLocale, ...fallbackLocales];
450
351
  for (const locale of localesToTry) {
451
352
  try {
@@ -455,7 +356,7 @@ var loadLocaleWithFallback = async ({
455
356
  namespaces,
456
357
  messages,
457
358
  limit,
458
- loggerId
359
+ logger: loggerOptions
459
360
  });
460
361
  return validNamespaces;
461
362
  } catch (error) {
@@ -468,14 +369,155 @@ var loadLocaleWithFallback = async ({
468
369
  logger.warn("All fallback locales failed.", {
469
370
  attemptedLocales: localesToTry
470
371
  });
471
- return void 0;
372
+ return;
373
+ };
374
+ function getGlobalMessagesPool() {
375
+ if (!globalThis.__INTOR_MESSAGES_POOL__) {
376
+ globalThis.__INTOR_MESSAGES_POOL__ = new Keyv__default.default();
377
+ }
378
+ return globalThis.__INTOR_MESSAGES_POOL__;
379
+ }
380
+ function clearMessagesPool() {
381
+ const pool = getGlobalMessagesPool();
382
+ pool.clear();
383
+ }
384
+
385
+ // src/shared/utils/merge-messages.ts
386
+ var mergeMessages = (staticMessages = {}, loadedMessages = {}) => {
387
+ const result = Object.keys(staticMessages).length ? { ...staticMessages } : {};
388
+ for (const locale in loadedMessages) {
389
+ const loaded = loadedMessages[locale];
390
+ if (!result[locale]) {
391
+ result[locale] = loaded;
392
+ continue;
393
+ }
394
+ result[locale] = {
395
+ ...result[locale],
396
+ ...loaded
397
+ };
398
+ }
399
+ return result;
400
+ };
401
+
402
+ // src/shared/utils/normalize-cache-key.ts
403
+ var CACHE_KEY_DELIMITER = "|";
404
+ var sanitize = (k) => k.replaceAll(/[\u200B-\u200D\uFEFF]/g, "").replaceAll(/[\r\n]/g, "").trim();
405
+ var normalizeCacheKey = (key, delimiter = CACHE_KEY_DELIMITER) => {
406
+ if (!key) return null;
407
+ if (Array.isArray(key)) {
408
+ if (key.length === 0) return null;
409
+ const normalized = key.map((k) => {
410
+ if (k === null) return "__null";
411
+ if (k === void 0) return "__undefined";
412
+ if (typeof k === "boolean") return k ? "__true" : "__false";
413
+ return sanitize(String(k));
414
+ });
415
+ return normalized.join(delimiter);
416
+ }
417
+ if (typeof key === "boolean") return key ? "__true" : "__false";
418
+ return String(key);
419
+ };
420
+
421
+ // src/shared/constants/prefix-placeholder.ts
422
+ var PREFIX_PLACEHOLDER = "{locale}";
423
+
424
+ // src/shared/utils/resolve-namespaces.ts
425
+ var resolveNamespaces = ({
426
+ config,
427
+ pathname
428
+ }) => {
429
+ const { loader } = config;
430
+ const {
431
+ routeNamespaces = {},
432
+ namespaces: fallbackNamespaces
433
+ } = loader;
434
+ const { unprefixedPathname } = extractPathname({ config, pathname });
435
+ const standardizedPathname = standardizePathname({
436
+ config,
437
+ pathname: unprefixedPathname
438
+ });
439
+ const placeholderRemovedPathname = standardizedPathname.replace(
440
+ `/${PREFIX_PLACEHOLDER}`,
441
+ ""
442
+ );
443
+ const defaultNamespaces = routeNamespaces.default ?? [];
444
+ const exactMatchNamespaces = routeNamespaces[standardizedPathname] ?? routeNamespaces[placeholderRemovedPathname];
445
+ if (exactMatchNamespaces) {
446
+ return [...defaultNamespaces, ...exactMatchNamespaces];
447
+ }
448
+ let bestMatch = "";
449
+ let bestNamespaces;
450
+ const prefixPatterns = Object.keys(routeNamespaces).filter(
451
+ (pattern) => pattern.endsWith("/*")
452
+ );
453
+ for (const pattern of prefixPatterns) {
454
+ const basePath = pattern.replace(/\/\*$/, "");
455
+ if (standardizedPathname.startsWith(basePath)) {
456
+ if (basePath.length > bestMatch.length) {
457
+ bestMatch = basePath;
458
+ bestNamespaces = routeNamespaces[pattern];
459
+ }
460
+ }
461
+ }
462
+ const matchedNamespaces = bestNamespaces ?? routeNamespaces["/*"] ?? fallbackNamespaces ?? [];
463
+ if (matchedNamespaces.length > 0) {
464
+ return [...defaultNamespaces, ...matchedNamespaces];
465
+ } else {
466
+ return [...defaultNamespaces];
467
+ }
468
+ };
469
+
470
+ // src/shared/utils/locale/normalize-locale.ts
471
+ var normalizeLocale = (locale = "", supportedLocales = []) => {
472
+ if (!locale || supportedLocales.length === 0) return;
473
+ const toCanonical = (input) => {
474
+ try {
475
+ return Intl.getCanonicalLocales(input)[0]?.toLowerCase();
476
+ } catch {
477
+ return;
478
+ }
479
+ };
480
+ const canonicalLocale = toCanonical(locale);
481
+ if (!canonicalLocale) return;
482
+ const supportedCanonicalMap = /* @__PURE__ */ new Map();
483
+ for (const l of supportedLocales) {
484
+ const normalized = toCanonical(l);
485
+ if (normalized) {
486
+ supportedCanonicalMap.set(normalized, l);
487
+ }
488
+ }
489
+ if (supportedCanonicalMap.has(canonicalLocale)) {
490
+ return supportedCanonicalMap.get(canonicalLocale);
491
+ }
492
+ const baseLang = canonicalLocale.split("-")[0];
493
+ for (const [key, original] of supportedCanonicalMap) {
494
+ const supportedBase = key.split("-")[0];
495
+ if (supportedBase === baseLang) {
496
+ return original;
497
+ }
498
+ }
499
+ return;
500
+ };
501
+
502
+ // src/shared/utils/locale/resolve-preferred-locale.ts
503
+ var resolvePreferredLocale = (acceptLanguageHeader, supportedLocales) => {
504
+ if (!acceptLanguageHeader || !supportedLocales || supportedLocales.length === 0) {
505
+ return;
506
+ }
507
+ const supportedLocalesSet = new Set(supportedLocales);
508
+ const preferred = acceptLanguageHeader.split(",").map((part) => {
509
+ const [lang, qValue] = part.split(";");
510
+ const q = qValue ? parseFloat(qValue.split("=")[1]) : 1;
511
+ if (isNaN(q)) {
512
+ return { lang: lang.trim(), q: 0 };
513
+ }
514
+ return { lang: lang.trim(), q };
515
+ }).sort((a, b) => b.q - a.q).find(({ lang }) => supportedLocalesSet.has(lang))?.lang;
516
+ return preferred;
472
517
  };
473
518
 
474
519
  // src/shared/utils/pathname/normalize-pathname.ts
475
520
  var normalizePathname = (rawPathname, options = {}) => {
476
- if (typeof rawPathname !== "string") {
477
- throw new TypeError("Expected rawPathname to be a string");
478
- }
479
521
  const length = rawPathname.length;
480
522
  let start = 0;
481
523
  let end = length - 1;
@@ -505,33 +547,101 @@ var normalizePathname = (rawPathname, options = {}) => {
505
547
  return result || "/";
506
548
  };
507
549
 
508
- // src/modules/intor-messages-loader/load-local-messages/load-local-messages.ts
550
+ // src/shared/utils/pathname/extract-pathname.ts
551
+ var extractPathname = ({
552
+ config,
553
+ pathname: rawPathname
554
+ }) => {
555
+ const { routing, defaultLocale } = config;
556
+ const { basePath, prefix } = routing;
557
+ const normalizedPathname = normalizePathname(rawPathname);
558
+ let prefixedPathname = normalizedPathname;
559
+ if (basePath && normalizedPathname.startsWith(basePath + "/")) {
560
+ prefixedPathname = normalizedPathname.slice(basePath.length) || "/";
561
+ } else if (basePath && normalizedPathname === basePath) {
562
+ prefixedPathname = "/";
563
+ }
564
+ const pathParts = prefixedPathname.split("/").filter(Boolean);
565
+ const maybeLocale = pathParts[0] || "";
566
+ const isLocalePrefixed = config.supportedLocales?.includes(maybeLocale);
567
+ let unprefixedPathname = prefixedPathname;
568
+ if (prefix === "all") {
569
+ if (isLocalePrefixed) {
570
+ unprefixedPathname = prefixedPathname.slice(maybeLocale.length + 1) || "/";
571
+ }
572
+ } else if (prefix === "except-default") {
573
+ if (maybeLocale && maybeLocale !== defaultLocale && isLocalePrefixed) {
574
+ unprefixedPathname = prefixedPathname.slice(maybeLocale.length + 1) || "/";
575
+ }
576
+ }
577
+ return {
578
+ basePath,
579
+ prefixedPathname,
580
+ unprefixedPathname,
581
+ maybeLocale,
582
+ isLocalePrefixed: Boolean(isLocalePrefixed)
583
+ };
584
+ };
585
+
586
+ // src/shared/utils/pathname/standardize-pathname.ts
587
+ var standardizePathname = ({
588
+ config,
589
+ pathname
590
+ }) => {
591
+ const { routing } = config;
592
+ const { basePath } = routing;
593
+ const parts = [
594
+ normalizePathname(basePath),
595
+ PREFIX_PLACEHOLDER,
596
+ normalizePathname(pathname)
597
+ ];
598
+ const standardizedPathname = parts.join("/").replace(/\/{2,}/g, "/");
599
+ return normalizePathname(standardizedPathname);
600
+ };
601
+
602
+ // src/modules/messages/load-local-messages/load-local-messages.ts
509
603
  var loadLocalMessages = async ({
510
- basePath = "messages",
604
+ basePath,
511
605
  locale,
512
606
  fallbackLocales,
513
607
  namespaces,
514
608
  concurrency = 10,
515
- loggerId
609
+ cache = DEFAULT_CACHE_OPTIONS,
610
+ logger: loggerOptions = { id: "default" }
516
611
  }) => {
517
- if (!locale || locale.trim() === "") {
518
- return {};
519
- }
520
- const logger = logry.logry({ id: loggerId, scope: "loadLocalMessages" });
612
+ basePath = basePath ?? "messages";
613
+ if (!locale || locale.trim() === "") return {};
614
+ const baseLogger = getLogger({ ...loggerOptions });
615
+ const logger = baseLogger.child({ scope: "load-locale-messages" });
616
+ const messages = {};
521
617
  const resolvedBasePath = path__default.default.resolve(
522
618
  process.cwd(),
523
619
  normalizePathname(basePath, { removeLeadingSlash: true })
524
620
  );
525
- const messages = {};
526
- const limit = pLimit__default.default(concurrency);
527
621
  const start = perf_hooks.performance.now();
528
- logger.debug("Starting to load local messages with configuration:", {
622
+ logger.trace("Starting to load local messages with configuration.", {
529
623
  path: { basePath, resolvedBasePath },
530
624
  locale,
531
625
  fallbackLocales,
532
- namespaces: namespaces && namespaces.length > 0 ? { count: namespaces?.length, list: [...namespaces] } : "All",
626
+ namespaces: namespaces && namespaces.length > 0 ? { count: namespaces?.length, list: [...namespaces] } : "All Namespaces",
533
627
  concurrency
534
628
  });
629
+ const pool = getGlobalMessagesPool();
630
+ const key = normalizeCacheKey([
631
+ loggerOptions.id,
632
+ resolvedBasePath,
633
+ locale,
634
+ [...fallbackLocales ?? []].sort().join(","),
635
+ [...namespaces ?? []].sort().join(",")
636
+ ]);
637
+ if (cache.enabled && key) {
638
+ const cached = await pool.get(key);
639
+ if (cached) {
640
+ logger.debug("Messages cache hit.", { key });
641
+ return cached;
642
+ }
643
+ }
644
+ const limit = pLimit__default.default(concurrency);
535
645
  const validNamespaces = await loadLocaleWithFallback({
536
646
  basePath: resolvedBasePath,
537
647
  locale,
@@ -539,430 +649,260 @@ var loadLocalMessages = async ({
539
649
  namespaces,
540
650
  messages,
541
651
  limit,
542
- loggerId
652
+ logger: loggerOptions
543
653
  });
654
+ if (cache.enabled && key) {
655
+ await pool.set(key, messages, cache.ttl);
656
+ }
544
657
  const end = perf_hooks.performance.now();
545
658
  const duration = Math.round(end - start);
546
- if (validNamespaces && validNamespaces?.length > 0) {
547
- logger.info("Finished loading local messages.", {
548
- locale,
549
- namespaces: validNamespaces,
550
- duration: `${duration} ms`
551
- });
552
- } else {
553
- logger.warn("No valid namespaces found for the locale.", {
554
- locale,
555
- namespaces: validNamespaces,
556
- duration: `${duration} ms`
557
- });
558
- }
659
+ logger.trace("Finished loading local messages.", {
660
+ locale,
661
+ validNamespaces,
662
+ duration: `${duration} ms`
663
+ });
559
664
  return messages;
560
665
  };
561
666
 
562
- // src/modules/intor-messages-loader/create-local-messages-loader/create-local-messages-loader.ts
563
- var createLocalMessagesLoader = (basePath) => {
667
+ // src/modules/messages/create-load-local-messages.ts
668
+ var createLoadLocalMessages = (basePath) => {
564
669
  return (options) => loadLocalMessages({ basePath, ...options });
565
670
  };
566
671
 
567
- // src/modules/intor-messages-loader/fetch-api-messages/build-search-params.ts
568
- var buildSearchParams = (params) => {
569
- const searchParams = new URLSearchParams();
570
- const appendParam = (key, value) => {
571
- if (value === void 0 || value === null) {
572
- return;
573
- }
574
- if (Array.isArray(value) && value.length > 0) {
575
- value.forEach((v) => v && searchParams.append(key, v));
576
- } else {
577
- searchParams.append(key, value);
578
- }
579
- };
580
- Object.entries(params).forEach(([key, value]) => {
581
- appendParam(key, value);
582
- });
583
- return searchParams;
584
- };
585
- var fetcher = async ({
672
+ // src/modules/messages/load-api-messages/fetch-messages.ts
673
+ var fetchMessages = async ({
586
674
  apiUrl,
675
+ apiHeaders,
587
676
  locale,
588
677
  searchParams,
589
- loggerId
678
+ logger: loggerOptions = { id: "default" }
590
679
  }) => {
591
- const logger = logry.logry({ id: loggerId, scope: "fetcher" });
680
+ const baseLogger = getLogger({ ...loggerOptions });
681
+ const logger = baseLogger.child({ scope: "fetch-messages" });
592
682
  try {
593
683
  const params = new URLSearchParams(searchParams);
594
684
  params.append("locale", locale);
595
685
  const url = `${apiUrl}?${params.toString()}`;
686
+ const headers = {
687
+ "Content-Type": "application/json",
688
+ ...apiHeaders
689
+ };
596
690
  const response = await fetch(url, {
597
691
  method: "GET",
598
- headers: { "Content-Type": "application/json" },
692
+ headers,
599
693
  cache: "no-store"
600
694
  });
601
695
  if (!response.ok) {
602
- throw new Error(
603
- `Fetch failed for locale "${locale}" at URL: ${url} - ${response.status} ${response.statusText}`
604
- );
696
+ throw new Error(`Fetch failed: ${locale} (${response.status})`);
605
697
  }
606
698
  const data = await response.json();
607
699
  if (data == null || typeof data === "object" && Object.keys(data).length === 0) {
608
- throw new Error(
609
- `Missing or invalid messages for locale "${locale}" at URL: ${url}`
610
- );
700
+ throw new Error(`Invalid messages: ${locale}`);
611
701
  }
612
702
  return data;
613
- } catch {
703
+ } catch (error) {
614
704
  logger.warn(`Failed to fetch messages for locale "${locale}".`, {
615
705
  locale,
616
706
  apiUrl,
617
- searchParams: decodeURIComponent(searchParams.toString())
707
+ searchParams: decodeURIComponent(searchParams.toString()),
708
+ error
618
709
  });
619
- return void 0;
710
+ return;
620
711
  }
621
712
  };
622
713
 
623
- // src/modules/intor-messages-loader/fetch-api-messages/fetch-fallback-messages.ts
624
- var fetchFallbackMessages = async (apiUrl, searchParams, fallbackLocales, loggerId) => {
714
+ // src/modules/messages/load-api-messages/fetch-fallback-messages.ts
715
+ var fetchFallbackMessages = async ({
716
+ apiUrl,
717
+ apiHeaders,
718
+ searchParams,
719
+ fallbackLocales,
720
+ logger
721
+ }) => {
625
722
  for (const fallbackLocale of fallbackLocales) {
626
- const result = await fetcher({
723
+ const result = await fetchMessages({
627
724
  apiUrl,
628
725
  searchParams,
629
726
  locale: fallbackLocale,
630
- loggerId
727
+ apiHeaders,
728
+ logger
631
729
  });
632
730
  if (result) {
633
731
  return { locale: fallbackLocale, messages: result };
634
732
  }
635
733
  }
636
- return void 0;
734
+ return;
735
+ };
736
+
737
+ // src/modules/messages/load-api-messages/utils/build-search-params.ts
738
+ var buildSearchParams = (params) => {
739
+ const searchParams = new URLSearchParams();
740
+ const appendParam = (key, value) => {
741
+ if (value === void 0 || value === null) return;
742
+ if (Array.isArray(value) && value.length === 0) return;
743
+ if (Array.isArray(value)) {
744
+ value.forEach((v) => v && searchParams.append(key, v));
745
+ } else {
746
+ searchParams.append(key, value);
747
+ }
748
+ };
749
+ Object.entries(params).forEach(([key, value]) => {
750
+ appendParam(key, value);
751
+ });
752
+ return searchParams;
637
753
  };
638
754
 
639
- // src/modules/intor-messages-loader/fetch-api-messages/fetch-api-messages.ts
640
- var fetchApiMessages = async ({
755
+ // src/modules/messages/load-api-messages/load-api-messages.ts
756
+ var loadApiMessages = async ({
641
757
  apiUrl,
758
+ apiHeaders,
642
759
  basePath,
643
760
  locale,
644
761
  fallbackLocales = [],
645
762
  namespaces = [],
646
- loggerId
763
+ cache = DEFAULT_CACHE_OPTIONS,
764
+ logger: loggerOptions = { id: "default" }
647
765
  }) => {
648
- const logger = logry.logry({ id: loggerId, scope: "fetchApiMessages" });
766
+ const baseLogger = getLogger({ ...loggerOptions });
767
+ const logger = baseLogger.child({ scope: "load-api-messages" });
649
768
  if (!apiUrl) {
650
- logger.warn("No apiUrl provided for fetchApiMessages. Skipping fetch.");
651
- return void 0;
769
+ logger.warn("No apiUrl provided. Skipping fetch.");
770
+ return;
652
771
  }
653
- const searchParams = buildSearchParams({
772
+ const pool = getGlobalMessagesPool();
773
+ const key = normalizeCacheKey([
774
+ loggerOptions.id,
654
775
  basePath,
655
- loggerId,
656
- namespaces
657
- });
658
- const messages = await fetcher({
776
+ locale,
777
+ [...fallbackLocales ?? []].sort().join(","),
778
+ [...namespaces ?? []].sort().join(",")
779
+ ]);
780
+ if (cache.enabled && key) {
781
+ const cached = await pool.get(key);
782
+ if (cached) {
783
+ logger.debug("Messages cache hit.", { key });
784
+ return cached;
785
+ }
786
+ }
787
+ const searchParams = buildSearchParams({ basePath, namespaces });
788
+ const messages = await fetchMessages({
659
789
  apiUrl,
790
+ apiHeaders,
660
791
  searchParams,
661
792
  locale,
662
- loggerId
793
+ logger: loggerOptions
663
794
  });
664
795
  if (messages) {
796
+ if (cache.enabled && key) {
797
+ await pool.set(key, messages, cache.ttl);
798
+ }
665
799
  return messages;
666
800
  }
667
- const fallbackResult = await fetchFallbackMessages(
801
+ const fallbackResult = await fetchFallbackMessages({
668
802
  apiUrl,
803
+ apiHeaders,
669
804
  searchParams,
670
805
  fallbackLocales,
671
- loggerId
672
- );
806
+ logger: loggerOptions
807
+ });
673
808
  if (fallbackResult) {
674
809
  logger.info("Fallback locale succeeded.", {
675
810
  usedLocale: fallbackResult.locale,
676
811
  apiUrl,
677
812
  searchParams: decodeURIComponent(searchParams.toString())
678
813
  });
814
+ if (cache.enabled && key) {
815
+ await pool.set(key, fallbackResult.messages, cache.ttl);
816
+ }
679
817
  return fallbackResult.messages;
680
818
  }
681
819
  logger.warn("Failed to fetch messages for all locales.", {
682
820
  locale,
683
821
  fallbackLocales
684
822
  });
685
- return void 0;
823
+ return;
686
824
  };
687
825
 
688
- // src/shared/utils/pathname/extract-pathname.ts
689
- var extractPathname = ({
690
- config,
691
- pathname: rawPathname
692
- }) => {
693
- const { routing, defaultLocale } = config;
694
- const { basePath, prefix } = routing;
695
- const normalizedPathname = normalizePathname(rawPathname);
696
- let prefixedPathname = normalizedPathname;
697
- if (basePath && normalizedPathname.startsWith(basePath + "/")) {
698
- prefixedPathname = normalizedPathname.slice(basePath.length) || "/";
699
- } else if (basePath && normalizedPathname === basePath) {
700
- prefixedPathname = "/";
701
- }
702
- const pathParts = prefixedPathname.split("/").filter(Boolean);
703
- const maybeLocale = pathParts[0] || "";
704
- const isLocalePrefixed = config.supportedLocales?.includes(maybeLocale);
705
- let unprefixedPathname = prefixedPathname;
706
- if (prefix === "all") {
707
- if (isLocalePrefixed) {
708
- unprefixedPathname = prefixedPathname.slice(maybeLocale.length + 1) || "/";
709
- }
710
- } else if (prefix === "except-default") {
711
- if (maybeLocale && maybeLocale !== defaultLocale && isLocalePrefixed) {
712
- unprefixedPathname = prefixedPathname.slice(maybeLocale.length + 1) || "/";
713
- }
714
- }
715
- return {
716
- basePath,
717
- prefixedPathname,
718
- unprefixedPathname,
719
- maybeLocale,
720
- isLocalePrefixed: Boolean(isLocalePrefixed)
721
- };
722
- };
723
-
724
- // src/shared/utils/pathname/standardize-pathname.ts
725
- var standardizePathname = ({
726
- config,
727
- pathname
728
- }) => {
729
- const { routing, prefixPlaceHolder } = config;
730
- const { basePath } = routing;
731
- const parts = [
732
- normalizePathname(basePath),
733
- normalizePathname(prefixPlaceHolder),
734
- normalizePathname(pathname)
735
- ];
736
- const standardizedPathname = parts.join("/").replace(/\/{2,}/g, "/");
737
- return normalizePathname(standardizedPathname);
738
- };
739
-
740
- // src/shared/utils/resolve-namespaces.ts
741
- var resolveNamespaces = ({
742
- config,
743
- pathname
744
- }) => {
745
- const { loaderOptions, prefixPlaceHolder } = config;
746
- const {
747
- routeNamespaces = {},
748
- namespaces: fallbackNamespaces
749
- } = loaderOptions;
750
- const { unprefixedPathname } = extractPathname({ config, pathname });
751
- const standardizedPathname = standardizePathname({
752
- config,
753
- pathname: unprefixedPathname
754
- });
755
- const placeholderRemovedPathname = standardizedPathname.replace(
756
- `/${prefixPlaceHolder}`,
757
- ""
758
- );
759
- const defaultNamespaces = routeNamespaces.default ?? [];
760
- const exactMatchNamespaces = routeNamespaces[standardizedPathname] ?? routeNamespaces[placeholderRemovedPathname];
761
- if (exactMatchNamespaces) {
762
- return [...defaultNamespaces, ...exactMatchNamespaces];
763
- }
764
- let bestMatch = "";
765
- let bestNamespaces;
766
- const prefixPatterns = Object.keys(routeNamespaces).filter(
767
- (pattern) => pattern.endsWith("/*")
768
- );
769
- for (const pattern of prefixPatterns) {
770
- const basePath = pattern.replace(/\/\*$/, "");
771
- if (standardizedPathname.startsWith(basePath)) {
772
- if (basePath.length > bestMatch.length) {
773
- bestMatch = basePath;
774
- bestNamespaces = routeNamespaces[pattern];
775
- }
776
- }
777
- }
778
- const matchedNamespaces = bestNamespaces ?? routeNamespaces["/*"] ?? fallbackNamespaces ?? [];
779
- if (matchedNamespaces.length > 0) {
780
- return [...defaultNamespaces, ...matchedNamespaces];
781
- } else {
782
- return [...defaultNamespaces];
783
- }
784
- };
785
-
786
- // src/modules/intor-messages-loader/intor-messages-loader.ts
787
- var intorMessagesLoader = async ({
826
+ // src/modules/messages/get-messages.ts
827
+ var getMessages = async ({
788
828
  config,
789
829
  locale,
790
830
  pathname
791
831
  }) => {
792
- const logger = logry.logry({ id: config.id, scope: "intorMessagesLoader" });
793
- const loaderOptions = config.loaderOptions;
832
+ const baseLogger = getLogger({ id: config.id });
833
+ const logger = baseLogger.child({ scope: "messages-loader" });
834
+ const loaderOptions = config.loader;
794
835
  const fallbackLocales = config.fallbackLocales[locale] || [];
795
836
  const namespaces = resolveNamespaces({ config, pathname });
796
- let dynamicMessages;
797
- logger.info("Namespaces ready for loading:", {
798
- namespaces: namespaces.length > 0 ? { count: namespaces.length, list: [...namespaces] } : "All"
799
- });
800
- logger.debug("Loader type selected:", {
801
- loaderType: loaderOptions.type
837
+ logger.debug("Namespaces ready for loading.", {
838
+ namespaces: namespaces.length > 0 ? { count: namespaces.length, list: [...namespaces] } : "All Namespaces"
802
839
  });
840
+ logger.debug("Loader type selected.", { loaderType: loaderOptions.type });
841
+ let loadedMessages;
803
842
  if (loaderOptions.type === "import") {
804
- const loadLocalMessages2 = createLocalMessagesLoader(loaderOptions.basePath);
805
- dynamicMessages = await loadLocalMessages2({
843
+ const loadLocalMessages2 = createLoadLocalMessages(loaderOptions.basePath);
844
+ loadedMessages = await loadLocalMessages2({
806
845
  ...loaderOptions,
807
846
  locale,
808
847
  fallbackLocales,
809
848
  namespaces,
810
- loggerId: config.id
849
+ cache: config.cache,
850
+ logger: { id: config.id }
811
851
  });
812
852
  } else if (loaderOptions.type === "api") {
813
- dynamicMessages = await fetchApiMessages({
853
+ loadedMessages = await loadApiMessages({
814
854
  ...loaderOptions,
815
855
  locale,
816
856
  fallbackLocales,
817
857
  namespaces,
818
- loggerId: config.id
819
- });
820
- } else {
821
- logger.error("Unknown loader type.", {
822
- type: loaderOptions.type
823
- });
824
- throw new IntorError({
825
- id: config.id,
826
- code: "INTOR_UNKNOWN_LOADER_TYPE" /* UNKNOWN_LOADER_TYPE */,
827
- message: `Unknown loader type: ${loaderOptions.type}`
858
+ logger: { id: config.id }
828
859
  });
829
860
  }
830
- if (!dynamicMessages || Object.keys(dynamicMessages).length === 0) {
861
+ if (!loadedMessages || Object.keys(loadedMessages).length === 0) {
831
862
  logger.warn("No messages found.", { locale, namespaces });
832
863
  }
833
- return dynamicMessages;
834
- };
835
-
836
- // src/modules/intor-runtime/utils/should-load-dynamic-messages.ts
837
- var shouldLoadDynamicMessages = (loaderOptions, adapter) => {
838
- if (!loaderOptions) {
839
- return false;
840
- }
841
- const { type, lazyLoad } = loaderOptions;
842
- if (type === "import") {
843
- return true;
844
- }
845
- if (type === "api") {
846
- if (adapter === "next-client" && lazyLoad) {
847
- return false;
848
- }
849
- return true;
850
- }
851
- return false;
852
- };
853
-
854
- // src/shared/utils/merge-static-and-dynamic-messages.ts
855
- var mergeStaticAndDynamicMessages = (staticMessages = {}, dynamicMessages = {}) => {
856
- const result = Object.keys(staticMessages).length ? { ...staticMessages } : {};
857
- for (const locale in dynamicMessages) {
858
- const dynamic = dynamicMessages[locale];
859
- if (!result[locale]) {
860
- result[locale] = dynamic;
861
- continue;
862
- }
863
- result[locale] = {
864
- ...result[locale],
865
- ...dynamic
866
- };
867
- }
868
- return result;
864
+ return loadedMessages;
869
865
  };
870
866
 
871
- // src/modules/intor-runtime/intor-runtime.ts
872
- var intorRuntime = async ({
873
- request,
874
- config
867
+ // src/modules/intor/intor.ts
868
+ var intor = async ({
869
+ config,
870
+ adapter,
871
+ adapterRuntime
875
872
  }) => {
876
- const logger = logry.logry({ id: config.id, scope: "intorRuntime" });
877
- const {
878
- messages: staticMessages,
879
- // Static messages defined from config
880
- loaderOptions,
881
- adapter
882
- } = config;
883
- if (!intorAdapters.includes(adapter)) {
884
- logger.error("Unsupported adapter:", { adapter });
885
- throw new IntorError({
886
- id: config.id,
887
- code: "INTOR_UNSUPPORTED_ADAPTER" /* UNSUPPORTED_ADAPTER */,
888
- message: `Unsupported adapter: ${adapter}`
889
- });
890
- }
891
- const adapterRuntime = await resolceAdapterRuntimeLoader({ config });
892
- const { locale, pathname } = await adapterRuntime({ config, request });
893
- logger.info("Initialized locale and pathname:", { locale, pathname });
894
- let dynamicMessages;
895
- if (shouldLoadDynamicMessages(loaderOptions, adapter)) {
896
- dynamicMessages = await intorMessagesLoader({ config, locale, pathname });
873
+ const baseLogger = getLogger({ id: config.id, ...config.logger });
874
+ const logger = baseLogger.child({ scope: "intor" });
875
+ logger.info("Start Intor initialization.");
876
+ const { messages, loader } = config;
877
+ let runtime;
878
+ if (adapter) {
879
+ runtime = await adapter(config);
880
+ } else {
881
+ runtime = {
882
+ locale: adapterRuntime?.locale || config.defaultLocale,
883
+ pathname: adapterRuntime?.pathname || ""
884
+ };
897
885
  }
898
- const messages = mergeStaticAndDynamicMessages(
899
- staticMessages,
900
- dynamicMessages
901
- );
902
- logger.info("Loaded messages:", {
903
- staticMessages: {
904
- fromConfig: !!staticMessages
886
+ const { locale, pathname } = runtime;
887
+ logger.debug("Runtime resolved via adapter/fallback", runtime);
888
+ let loadedMessages;
889
+ if (shouldLoadMessages(loader)) {
890
+ loadedMessages = await getMessages({ config, locale, pathname });
891
+ }
892
+ const mergedMessages = mergeMessages(messages, loadedMessages);
893
+ logger.info("Messages initialized.", {
894
+ staticMessages: { enabled: !!messages },
895
+ loadedMessages: {
896
+ enabled: !!loadedMessages,
897
+ ...loader ? { loaderType: loader.type, lazyLoad: !!loader.lazyLoad } : null
905
898
  },
906
- dynamicMessages: {
907
- fromLoader: !!dynamicMessages,
908
- ...loaderOptions ? {
909
- loaderType: loaderOptions.type,
910
- lazyLoad: !!loaderOptions.lazyLoad
911
- } : null
912
- },
913
- mergedMessages: messages
899
+ mergedMessages
914
900
  });
915
901
  return {
916
902
  config,
917
903
  initialLocale: locale,
918
904
  pathname,
919
- messages
920
- };
921
- };
922
-
923
- // src/modules/intor/intor.ts
924
- var intor = async ({
925
- request,
926
- config
927
- }) => {
928
- const logger = logry.logry({
929
- id: config.id,
930
- scope: "intor",
931
- ...config.logger
932
- });
933
- logger.info("Starting Intor initialization:", {
934
- adapter: config.adapter
935
- });
936
- const runtime = await intorRuntime({ config, request });
937
- switch (config.adapter) {
938
- case "next-server": {
939
- return runtime;
940
- }
941
- case "next-client": {
942
- return runtime;
943
- }
944
- default: {
945
- logger.error("Unsupported adapter:", { adapter: config.adapter });
946
- throw new IntorError({
947
- id: config.id,
948
- code: "INTOR_UNSUPPORTED_ADAPTER" /* UNSUPPORTED_ADAPTER */,
949
- message: `Unsupported adapter: ${config.adapter}`
950
- });
951
- }
952
- }
953
- };
954
- var createIntor = (config, translateHandlers) => {
955
- return async (request) => {
956
- const { initialLocale, messages } = await intor({ config, request });
957
- const translator = new intorTranslator.Translator({
958
- locale: initialLocale,
959
- messages,
960
- fallbackLocales: config.fallbackLocales,
961
- loadingMessage: config.translator?.loadingMessage,
962
- placeholder: config.translator?.placeholder,
963
- handlers: translateHandlers
964
- });
965
- return translator;
905
+ messages: mergedMessages
966
906
  };
967
907
  };
968
908
 
@@ -970,14 +910,16 @@ Object.defineProperty(exports, "Translator", {
970
910
  enumerable: true,
971
911
  get: function () { return intorTranslator.Translator; }
972
912
  });
973
- exports.IntorError = IntorError;
974
- exports.IntorErrorCode = IntorErrorCode;
975
- exports.createIntor = createIntor;
913
+ exports.PREFIX_PLACEHOLDER = PREFIX_PLACEHOLDER;
914
+ exports.clearLoggerPool = clearLoggerPool;
915
+ exports.clearMessagesPool = clearMessagesPool;
976
916
  exports.extractPathname = extractPathname;
977
- exports.fetchApiMessages = fetchApiMessages;
917
+ exports.getMessages = getMessages;
978
918
  exports.intor = intor;
919
+ exports.loadApiMessages = loadApiMessages;
979
920
  exports.loadLocalMessages = loadLocalMessages;
980
- exports.mergeStaticAndDynamicMessages = mergeStaticAndDynamicMessages;
921
+ exports.mergeMessages = mergeMessages;
922
+ exports.normalizeCacheKey = normalizeCacheKey;
981
923
  exports.normalizeLocale = normalizeLocale;
982
924
  exports.normalizePathname = normalizePathname;
983
925
  exports.resolveNamespaces = resolveNamespaces;