@ultimat3/core 20.2.0 → 20.2.1
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/CLAUDE.md +1 -0
- package/package.json +2 -2
- package/src/index.ts +2 -0
- package/src/locale-direction.ts +37 -0
package/CLAUDE.md
CHANGED
|
@@ -139,6 +139,7 @@ shape against a locally declared sample interface for exactly that reason.
|
|
|
139
139
|
| is this `unknown` a keyed record? | `json-object.ts` | `isJsonObject`, which was the same three terms in both those packages' `stable.ts`. A `Date` and a class instance PASS: it narrows a shape, it does not certify provenance |
|
|
140
140
|
| a value that must not be printed | `secret.ts` | redacted by VALUE; `revealSecret()` is the one way out, on purpose greppable |
|
|
141
141
|
| an `Intl` formatter cache, and the screen in front of it | `intl-cache.ts` (`cachedFormatter`, `canonicalLocale`, `assertLocale`, `MAX_CACHED_FORMATTERS`, `MAX_LOCALE_EXCERPT`) | a locale and a zone arrive from a request header, so the tag must be REFUSED when it is not a tag (`X_LOCALE_INVALID`), the key must be canonical AND the cache bounded — never a second copy of any of the three. The refusal is bounded too: the `cause` quotes back at most `MAX_LOCALE_EXCERPT` (35, RFC 5646 §4.4.1) code points and says so when it cut, and the whole tag rides in `meta.locale` — a `cause` reaches the 400 body and the log line, where a value with no key has nothing a redactor can address |
|
|
142
|
+
| the text direction of a locale | `locale-direction.ts` (`directionOf`, `isRtl`, `Direction`) | a script fact, moved here from `@ultimat3/i18n` (which re-exports it) on 2026-09-19: `@ultimat3/ui`'s provider reflects `dir` onto `<html>` from the locale it was handed, and reaching the i18n barrel for that one function put the framework catalog it installs at import into every browser chunk with a `UiProvider` (issue #490) |
|
|
142
143
|
| the committed encrypted values | `secrets.ts` (envelope) + `secrets-store.ts` (files, `installSecrets`) | plaintext is a flat map of ENV NAMES; there is no `secrets.get()` |
|
|
143
144
|
|
|
144
145
|
`installSecrets()` is the ONLY path from `secrets.enc.json` to an app value, and it lands in
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultimat3/core",
|
|
3
|
-
"version": "20.2.
|
|
3
|
+
"version": "20.2.1",
|
|
4
4
|
"description": "Ultimate's foundation: errors, context, env, config, clock, ids, logging, telemetry, lifecycle",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -37,6 +37,6 @@
|
|
|
37
37
|
"test": "bun test"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@ultimat3/schema": "20.2.
|
|
40
|
+
"@ultimat3/schema": "20.2.1"
|
|
41
41
|
}
|
|
42
42
|
}
|
package/src/index.ts
CHANGED
|
@@ -517,6 +517,8 @@ export {
|
|
|
517
517
|
shutdownHookCount,
|
|
518
518
|
} from './lifecycle';
|
|
519
519
|
export { isSelfOrigin, listeningOrigins, markListening, resetListeners } from './listeners';
|
|
520
|
+
export type { Direction } from './locale-direction';
|
|
521
|
+
export { directionOf, isRtl } from './locale-direction';
|
|
520
522
|
export { isMcpExposed, type McpExposureDeclaration } from './mcp-exposure';
|
|
521
523
|
export { nearestName } from './nearest-name';
|
|
522
524
|
export { type CappedBody, readWithinLimit } from './read-capped';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Text direction of a locale — a fact about the locale's script, and nothing about catalogs or
|
|
2
|
+
// requests, which is why it is tier 0 rather than `@ultimat3/i18n`'s: `@ultimat3/ui`'s provider
|
|
3
|
+
// reflects `dir` onto `<html>` from the locale it was handed, and reaching the i18n barrel for
|
|
4
|
+
// that one function put the whole framework catalog into every browser chunk with a `UiProvider`
|
|
5
|
+
// in it (issue #490). i18n re-exports these under the same names, so no caller moved.
|
|
6
|
+
|
|
7
|
+
export type Direction = 'ltr' | 'rtl';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Right-to-left scripts, by primary subtag. A static CLDR-derived set rather than
|
|
11
|
+
* `Intl.Locale.prototype.getTextInfo` so direction is deterministic across runtimes.
|
|
12
|
+
*/
|
|
13
|
+
const RTL_LOCALES: ReadonlySet<string> = new Set([
|
|
14
|
+
'ar',
|
|
15
|
+
'arc',
|
|
16
|
+
'ckb',
|
|
17
|
+
'dv',
|
|
18
|
+
'fa',
|
|
19
|
+
'he',
|
|
20
|
+
'ks',
|
|
21
|
+
'ku',
|
|
22
|
+
'nqo',
|
|
23
|
+
'ps',
|
|
24
|
+
'sd',
|
|
25
|
+
'ug',
|
|
26
|
+
'ur',
|
|
27
|
+
'yi',
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
export function isRtl(locale: string): boolean {
|
|
31
|
+
const primary = locale.split('-')[0]?.toLowerCase() ?? '';
|
|
32
|
+
return RTL_LOCALES.has(primary);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function directionOf(locale: string): Direction {
|
|
36
|
+
return isRtl(locale) ? 'rtl' : 'ltr';
|
|
37
|
+
}
|