@softure-ai/core 0.1.11 → 0.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/CHANGELOG.md +50 -0
- package/README.md +122 -19
- package/dist/calendar-period.d.ts +18 -0
- package/dist/calendar-period.d.ts.map +1 -0
- package/dist/calendar-period.js +44 -0
- package/dist/calendar-period.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/format.d.ts +35 -14
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +30 -16
- package/dist/format.js.map +1 -1
- package/dist/http-json.d.ts +32 -0
- package/dist/http-json.d.ts.map +1 -0
- package/dist/http-json.js +83 -0
- package/dist/http-json.js.map +1 -0
- package/dist/i18n.d.ts +34 -11
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +40 -10
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/local-date-time.d.ts +10 -0
- package/dist/local-date-time.d.ts.map +1 -0
- package/dist/local-date-time.js +25 -0
- package/dist/local-date-time.js.map +1 -0
- package/dist/messages/en.d.ts +5 -15
- package/dist/messages/en.d.ts.map +1 -1
- package/dist/messages/en.js +5 -5
- package/dist/messages/en.js.map +1 -1
- package/dist/messages/index.d.ts +1 -1
- package/dist/messages/index.d.ts.map +1 -1
- package/dist/messages/index.js +2 -3
- package/dist/messages/index.js.map +1 -1
- package/package.json +1 -1
- package/src/calendar-period.ts +54 -0
- package/src/config.ts +2 -2
- package/src/format.ts +61 -25
- package/src/http-json.ts +130 -0
- package/src/i18n.ts +53 -19
- package/src/index.ts +24 -1
- package/src/local-date-time.ts +30 -0
- package/src/messages/en.ts +5 -5
- package/src/messages/index.ts +2 -3
- package/dist/messages/pl.d.ts +0 -3
- package/dist/messages/pl.d.ts.map +0 -1
- package/dist/messages/pl.js +0 -12
- package/dist/messages/pl.js.map +0 -1
- package/src/messages/pl.ts +0 -13
package/dist/format.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import { type Err, type Ok } from "./result.js";
|
|
3
|
+
export type HttpJsonFailureCode = "core.http_unreachable" | "core.http_refused" | "core.http_rate_limited" | "core.http_unavailable" | "core.http_unexpected_answer";
|
|
4
|
+
/** A failed `requestJson`: the code and the HTTP status (`null` when no response arrived). Nothing else. */
|
|
5
|
+
export type HttpJsonFailure = Err<HttpJsonFailureCode> & {
|
|
6
|
+
readonly status: number | null;
|
|
7
|
+
};
|
|
8
|
+
export type FetchFunction = (input: string | URL, init: RequestInit) => Promise<Response>;
|
|
9
|
+
export interface RequestJsonOptions {
|
|
10
|
+
readonly url: string | URL;
|
|
11
|
+
/** Defaults to the global `fetch`; tests pass a fake. */
|
|
12
|
+
readonly fetch?: FetchFunction;
|
|
13
|
+
readonly headers?: HeadersInit;
|
|
14
|
+
/** Milliseconds before the request (body included) gives up. Defaults to 10 000. */
|
|
15
|
+
readonly timeoutMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface RequestJsonSchemaOptions<S extends z.ZodType> extends RequestJsonOptions {
|
|
18
|
+
readonly schema: S;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* GET `url` and read its JSON body. Without a schema the value is `unknown`, for the caller to narrow; with one
|
|
22
|
+
* it is the schema's output. 3xx, 401 and 403 are refused, 429 rate limited, 5xx unavailable, and any other
|
|
23
|
+
* non-2xx status or a body that is not JSON or fails the schema an unexpected answer.
|
|
24
|
+
*/
|
|
25
|
+
export declare function requestJson<S extends z.ZodType>(options: RequestJsonSchemaOptions<S>): Promise<Ok<z.output<S>> | HttpJsonFailure>;
|
|
26
|
+
export declare function requestJson(options: RequestJsonOptions): Promise<Ok<unknown> | HttpJsonFailure>;
|
|
27
|
+
/**
|
|
28
|
+
* The query part of a URL (without `?`) from a flat record, in insertion order. `null` and `undefined` are left
|
|
29
|
+
* out, so optional parameters can be passed as they are.
|
|
30
|
+
*/
|
|
31
|
+
export declare function toQueryString(params: Readonly<Record<string, string | number | boolean | null | undefined>>): string;
|
|
32
|
+
//# sourceMappingURL=http-json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-json.d.ts","sourceRoot":"","sources":["../src/http-json.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAW,KAAK,GAAG,EAAE,KAAK,EAAE,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,MAAM,mBAAmB,GAC3B,uBAAuB,GACvB,mBAAmB,GACnB,wBAAwB,GACxB,uBAAuB,GACvB,6BAA6B,CAAC;AAElC,4GAA4G;AAC5G,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC,mBAAmB,CAAC,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAE5F,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAE1F,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IAC3B,yDAAyD;IACzD,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B,oFAAoF;IACpF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,wBAAwB,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAE,SAAQ,kBAAkB;IACvF,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;CACpB;AAID;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAC7C,OAAO,EAAE,wBAAwB,CAAC,CAAC,CAAC,GACnC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC;AAC9C,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,eAAe,CAAC,CAAC;AAsDjG;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC,GAAG,MAAM,CAQpH"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { err, ok } from "./result.js";
|
|
2
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
3
|
+
export async function requestJson(options) {
|
|
4
|
+
const fetchFunction = options.fetch ?? globalThis.fetch;
|
|
5
|
+
let response;
|
|
6
|
+
try {
|
|
7
|
+
// Inside the try: an invalid header value throws a message that quotes it.
|
|
8
|
+
const headers = new Headers(options.headers);
|
|
9
|
+
if (!headers.has("accept")) {
|
|
10
|
+
headers.set("accept", "application/json");
|
|
11
|
+
}
|
|
12
|
+
response = await fetchFunction(options.url, {
|
|
13
|
+
method: "GET",
|
|
14
|
+
headers,
|
|
15
|
+
redirect: "manual",
|
|
16
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_TIMEOUT_MS),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Network error or timeout. The error's text can quote the URL, so it is dropped on purpose.
|
|
21
|
+
return httpFailure("core.http_unreachable", null);
|
|
22
|
+
}
|
|
23
|
+
const statusFailure = getStatusFailure(response);
|
|
24
|
+
if (statusFailure !== null) {
|
|
25
|
+
// Release the connection; a body that cannot be cancelled changes nothing for the caller.
|
|
26
|
+
await response.body?.cancel().catch(() => undefined);
|
|
27
|
+
return statusFailure;
|
|
28
|
+
}
|
|
29
|
+
let text;
|
|
30
|
+
try {
|
|
31
|
+
text = await response.text();
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// The body broke off, usually the timeout firing mid-body.
|
|
35
|
+
return httpFailure("core.http_unreachable", response.status);
|
|
36
|
+
}
|
|
37
|
+
let body;
|
|
38
|
+
try {
|
|
39
|
+
body = JSON.parse(text);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return httpFailure("core.http_unexpected_answer", response.status);
|
|
43
|
+
}
|
|
44
|
+
if (options.schema === undefined) {
|
|
45
|
+
return ok(body);
|
|
46
|
+
}
|
|
47
|
+
// The schema's issues can quote the body's values, so only the code leaves.
|
|
48
|
+
const parsed = options.schema.safeParse(body);
|
|
49
|
+
return parsed.success ? ok(parsed.data) : httpFailure("core.http_unexpected_answer", response.status);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The query part of a URL (without `?`) from a flat record, in insertion order. `null` and `undefined` are left
|
|
53
|
+
* out, so optional parameters can be passed as they are.
|
|
54
|
+
*/
|
|
55
|
+
export function toQueryString(params) {
|
|
56
|
+
const search = new URLSearchParams();
|
|
57
|
+
for (const [key, value] of Object.entries(params)) {
|
|
58
|
+
if (value !== null && value !== undefined) {
|
|
59
|
+
search.append(key, String(value));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return search.toString();
|
|
63
|
+
}
|
|
64
|
+
function getStatusFailure(response) {
|
|
65
|
+
const { status } = response;
|
|
66
|
+
if (response.type === "opaqueredirect" || (status >= 300 && status < 400) || status === 401 || status === 403) {
|
|
67
|
+
return httpFailure("core.http_refused", status);
|
|
68
|
+
}
|
|
69
|
+
if (status === 429) {
|
|
70
|
+
return httpFailure("core.http_rate_limited", status);
|
|
71
|
+
}
|
|
72
|
+
if (status >= 500) {
|
|
73
|
+
return httpFailure("core.http_unavailable", status);
|
|
74
|
+
}
|
|
75
|
+
if (status < 200 || status >= 300) {
|
|
76
|
+
return httpFailure("core.http_unexpected_answer", status);
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
function httpFailure(code, status) {
|
|
81
|
+
return { ...err(code), status };
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=http-json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-json.js","sourceRoot":"","sources":["../src/http-json.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
export type Locale =
|
|
1
|
+
/** A BCP 47 language tag (`en`, `de-AT`). */
|
|
2
|
+
export type Locale = string;
|
|
3
|
+
/** The language of every built-in dictionary and the fallback for any other locale. */
|
|
4
|
+
export declare const DEFAULT_LOCALE = "en";
|
|
3
5
|
/** A dictionary: nested groups of message strings. */
|
|
4
6
|
export interface MessageTree {
|
|
5
7
|
readonly [key: string]: string | MessageTree;
|
|
@@ -8,10 +10,20 @@ export interface MessageTree {
|
|
|
8
10
|
export type DeepPartial<T> = {
|
|
9
11
|
[K in keyof T]?: T[K] extends string ? string : DeepPartial<T[K]>;
|
|
10
12
|
};
|
|
11
|
-
/**
|
|
12
|
-
export type Dictionaries<T extends MessageTree> =
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
/** A complete `en` dictionary, plus complete dictionaries for any other locales. */
|
|
14
|
+
export type Dictionaries<T extends MessageTree> = {
|
|
15
|
+
readonly en: T;
|
|
16
|
+
} & {
|
|
17
|
+
readonly [locale: string]: T | undefined;
|
|
18
|
+
};
|
|
19
|
+
/** Partial overrides an app passes per locale: a translation for its own locale, or changed English copy. */
|
|
20
|
+
export type MessageOverrides<T extends MessageTree> = {
|
|
21
|
+
readonly [locale: string]: DeepPartial<T> | undefined;
|
|
22
|
+
};
|
|
23
|
+
/** A text an app writes per locale in its options (a plan name, a label); `en` is the fallback. */
|
|
24
|
+
export type LocalizedText = {
|
|
25
|
+
readonly [locale: string]: string | undefined;
|
|
26
|
+
};
|
|
15
27
|
/** Plural forms named after the `Intl.PluralRules` categories; `other` is the fallback. */
|
|
16
28
|
export interface PluralForms {
|
|
17
29
|
readonly zero?: string;
|
|
@@ -21,17 +33,28 @@ export interface PluralForms {
|
|
|
21
33
|
readonly many?: string;
|
|
22
34
|
readonly other: string;
|
|
23
35
|
}
|
|
36
|
+
/** Whether `value` is a well-formed BCP 47 language tag. */
|
|
24
37
|
export declare function isLocale(value: unknown): value is Locale;
|
|
25
38
|
/**
|
|
26
|
-
* The defaults with the overrides applied, per locale
|
|
27
|
-
*
|
|
28
|
-
*
|
|
39
|
+
* The defaults with the overrides applied, per locale: `en` and every locale the defaults or the
|
|
40
|
+
* overrides name. A locale without its own defaults is built on `en`, so a key its override leaves
|
|
41
|
+
* out reads English. Only keys the defaults have are taken, and a group is never replaced by a
|
|
42
|
+
* string, so an override cannot break the dictionary shape. Inputs are not mutated.
|
|
29
43
|
*/
|
|
30
44
|
export declare function mergeMessages<T extends MessageTree>(defaults: Dictionaries<T>, overrides?: MessageOverrides<T>): Dictionaries<T>;
|
|
45
|
+
/**
|
|
46
|
+
* The dictionary for `locale`: its own, else its language's (`pt-BR` reads `pt`), else `en`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function selectMessages<T extends MessageTree>(dictionaries: Dictionaries<T>, locale: Locale): T;
|
|
49
|
+
/** The text for `locale` with `selectMessages`' fallback order, or `fallback` when no locale has one. */
|
|
50
|
+
export declare function pickLocalizedText(text: LocalizedText | undefined, locale: Locale, fallback?: string): string;
|
|
31
51
|
/** Fills `{name}` placeholders. A placeholder without a value stays as written. */
|
|
32
52
|
export declare function formatMessage(template: string, params?: Readonly<Record<string, string | number>>): string;
|
|
33
|
-
/**
|
|
34
|
-
|
|
53
|
+
/**
|
|
54
|
+
* The form for `count` under the plural rules of `locale`, any BCP 47 tag ("1 file", "2 files"). A category the
|
|
55
|
+
* forms leave out falls back to `other`.
|
|
56
|
+
*/
|
|
57
|
+
export declare function selectPlural(locale: string, count: number, forms: PluralForms): string;
|
|
35
58
|
/** The message at a dotted path (`login.title`), or `undefined` when there is no string there. */
|
|
36
59
|
export declare function getMessage(tree: MessageTree, path: string): string | undefined;
|
|
37
60
|
//# sourceMappingURL=i18n.d.ts.map
|
package/dist/i18n.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAIA,6CAA6C;AAC7C,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAE5B,uFAAuF;AACvF,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC,sDAAsD;AACtD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,CAAC;CAC9C;AAED,8DAA8D;AAC9D,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC;AAEnG,oFAAoF;AACpF,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,WAAW,IAAI;IAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAA;CAAE,CAAC;AAEpH,6GAA6G;AAC7G,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,WAAW,IAAI;IAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;CAAE,CAAC;AAEhH,mGAAmG;AACnG,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAE9E,2FAA2F;AAC3F,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,4DAA4D;AAC5D,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAQxD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,WAAW,EACjD,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,EACzB,SAAS,GAAE,gBAAgB,CAAC,CAAC,CAAM,GAClC,YAAY,CAAC,CAAC,CAAC,CAMjB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,WAAW,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,CAEtG;AAED,yGAAyG;AACzG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAK,GAAG,MAAM,CAGxG;AAMD,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAM,GAAG,MAAM,CAK9G;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM,CAOtF;AAED,kGAAkG;AAClG,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAS9E"}
|
package/dist/i18n.js
CHANGED
|
@@ -1,21 +1,48 @@
|
|
|
1
|
-
// Copy and localization (docs/02-module-standard.md §6): every module ships complete `en`
|
|
2
|
-
//
|
|
3
|
-
|
|
1
|
+
// Copy and localization (docs/02-module-standard.md §6): every module ships a complete `en`
|
|
2
|
+
// dictionary, the only built-in language. An app that shows another language passes its own
|
|
3
|
+
// translation as overrides for its locale; a key it leaves out reads English.
|
|
4
|
+
/** The language of every built-in dictionary and the fallback for any other locale. */
|
|
5
|
+
export const DEFAULT_LOCALE = "en";
|
|
6
|
+
/** Whether `value` is a well-formed BCP 47 language tag. */
|
|
4
7
|
export function isLocale(value) {
|
|
5
|
-
|
|
8
|
+
if (typeof value !== "string" || value === "")
|
|
9
|
+
return false;
|
|
10
|
+
try {
|
|
11
|
+
return Intl.getCanonicalLocales(value).length === 1;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
// RangeError: not a well-formed tag.
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
6
17
|
}
|
|
7
18
|
/**
|
|
8
|
-
* The defaults with the overrides applied, per locale
|
|
9
|
-
*
|
|
10
|
-
*
|
|
19
|
+
* The defaults with the overrides applied, per locale: `en` and every locale the defaults or the
|
|
20
|
+
* overrides name. A locale without its own defaults is built on `en`, so a key its override leaves
|
|
21
|
+
* out reads English. Only keys the defaults have are taken, and a group is never replaced by a
|
|
22
|
+
* string, so an override cannot break the dictionary shape. Inputs are not mutated.
|
|
11
23
|
*/
|
|
12
24
|
export function mergeMessages(defaults, overrides = {}) {
|
|
13
25
|
const merged = {};
|
|
14
|
-
for (const locale of
|
|
15
|
-
merged[locale] = mergeTree(defaults[locale], overrides[locale]);
|
|
26
|
+
for (const locale of new Set([DEFAULT_LOCALE, ...Object.keys(defaults), ...Object.keys(overrides)])) {
|
|
27
|
+
merged[locale] = mergeTree(defaults[locale] ?? defaults.en, overrides[locale]);
|
|
16
28
|
}
|
|
17
29
|
return merged;
|
|
18
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* The dictionary for `locale`: its own, else its language's (`pt-BR` reads `pt`), else `en`.
|
|
33
|
+
*/
|
|
34
|
+
export function selectMessages(dictionaries, locale) {
|
|
35
|
+
return dictionaries[locale] ?? dictionaries[getLanguage(locale)] ?? dictionaries.en;
|
|
36
|
+
}
|
|
37
|
+
/** The text for `locale` with `selectMessages`' fallback order, or `fallback` when no locale has one. */
|
|
38
|
+
export function pickLocalizedText(text, locale, fallback = "") {
|
|
39
|
+
if (text === undefined)
|
|
40
|
+
return fallback;
|
|
41
|
+
return text[locale] ?? text[getLanguage(locale)] ?? text.en ?? fallback;
|
|
42
|
+
}
|
|
43
|
+
function getLanguage(locale) {
|
|
44
|
+
return locale.split("-")[0] ?? locale;
|
|
45
|
+
}
|
|
19
46
|
/** Fills `{name}` placeholders. A placeholder without a value stays as written. */
|
|
20
47
|
export function formatMessage(template, params = {}) {
|
|
21
48
|
return template.replace(/\{(\w+)\}/g, (placeholder, name) => {
|
|
@@ -24,7 +51,10 @@ export function formatMessage(template, params = {}) {
|
|
|
24
51
|
});
|
|
25
52
|
}
|
|
26
53
|
const pluralRulesByLocale = new Map();
|
|
27
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* The form for `count` under the plural rules of `locale`, any BCP 47 tag ("1 file", "2 files"). A category the
|
|
56
|
+
* forms leave out falls back to `other`.
|
|
57
|
+
*/
|
|
28
58
|
export function selectPlural(locale, count, forms) {
|
|
29
59
|
let rules = pluralRulesByLocale.get(locale);
|
|
30
60
|
if (rules === undefined) {
|
package/dist/i18n.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export { addCalendarDays, addCalendarMonths, calendarDaysBetween, calendarDaySchema, getCalendarDay, isCalendarDay, toCalendarDay, wholeMonthsBetween, type EndOfMonth, } from "./calendar-day.js";
|
|
2
|
+
export { calendarPeriodSchema, countPeriodDays, doPeriodsOverlap, isDayInPeriod, type CalendarPeriod, } from "./calendar-period.js";
|
|
3
|
+
export { getLocalDay, isLocalDateTime, localDateTimeSchema, type LocalDateTime } from "./local-date-time.js";
|
|
2
4
|
export { CURRENCY_MINOR_UNIT_DIGITS } from "./currency-digits.js";
|
|
3
|
-
export { formatCalendarDay, formatCalendarMonth, formatDuration, formatMoney, formatPercent, isCalendarMonth, type CalendarDayStyle, type CalendarMonthStyle, type FormatMoneyOptions, type FormatPercentOptions, } from "./format.js";
|
|
5
|
+
export { DEFAULT_DURATION_MESSAGES, formatCalendarDay, formatCalendarMonth, formatDuration, formatMoney, formatPercent, isCalendarMonth, type CalendarDayStyle, type CalendarMonthStyle, type DurationMessages, type FormatDurationOptions, type FormatMoneyOptions, type FormatPercentOptions, } from "./format.js";
|
|
6
|
+
export { requestJson, toQueryString, type FetchFunction, type HttpJsonFailure, type HttpJsonFailureCode, type RequestJsonOptions, type RequestJsonSchemaOptions, } from "./http-json.js";
|
|
4
7
|
export { memoizeByContent, type MemoizeByContentOptions, type MemoizedFunction } from "./memoize.js";
|
|
5
8
|
export { createTestClock, systemClock, type Clock, type TestClock } from "./clock.js";
|
|
6
|
-
export { formatMessage, getMessage,
|
|
9
|
+
export { formatMessage, getMessage, DEFAULT_LOCALE, isLocale, mergeMessages, pickLocalizedText, selectMessages, selectPlural, type DeepPartial, type Dictionaries, type Locale, type LocalizedText, type MessageOverrides, type MessageTree, type PluralForms, } from "./i18n.js";
|
|
7
10
|
export { coreMessages, type CoreMessages } from "./messages/index.js";
|
|
8
11
|
export { err, ok, type Err, type ErrorCode, type Ok, type Result } from "./result.js";
|
|
9
12
|
export { errorLogLabel, getPublicMessage, isPublicError, PublicError, safeError, type CoreErrorCode } from "./safe-error.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,KAAK,UAAU,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,aAAa,EACb,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrG,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,KAAK,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACtF,OAAO,EACL,aAAa,EACb,UAAU,EACV,QAAQ,EACR,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,KAAK,UAAU,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,KAAK,cAAc,GACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC7G,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,aAAa,EACb,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,WAAW,EACX,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrG,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,KAAK,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACtF,OAAO,EACL,aAAa,EACb,UAAU,EACV,cAAc,EACd,QAAQ,EACR,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,GAAG,EAAE,KAAK,SAAS,EAAE,KAAK,EAAE,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC7H,OAAO,EACL,mBAAmB,EACnB,SAAS,EACT,yBAAyB,EACzB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,cAAc,EACnB,KAAK,mBAAmB,GACzB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iBAAiB,EACjB,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACvG,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AACpG,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,cAAc,EAAE,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
// Public API of @softure-ai/core: the contract every SOFTURE module stands on
|
|
2
2
|
// (docs/02-module-standard.md). The Next.js registry is a separate entry: `@softure-ai/core/next`.
|
|
3
3
|
export { addCalendarDays, addCalendarMonths, calendarDaysBetween, calendarDaySchema, getCalendarDay, isCalendarDay, toCalendarDay, wholeMonthsBetween, } from "./calendar-day.js";
|
|
4
|
+
export { calendarPeriodSchema, countPeriodDays, doPeriodsOverlap, isDayInPeriod, } from "./calendar-period.js";
|
|
5
|
+
export { getLocalDay, isLocalDateTime, localDateTimeSchema } from "./local-date-time.js";
|
|
4
6
|
export { CURRENCY_MINOR_UNIT_DIGITS } from "./currency-digits.js";
|
|
5
|
-
export { formatCalendarDay, formatCalendarMonth, formatDuration, formatMoney, formatPercent, isCalendarMonth, } from "./format.js";
|
|
7
|
+
export { DEFAULT_DURATION_MESSAGES, formatCalendarDay, formatCalendarMonth, formatDuration, formatMoney, formatPercent, isCalendarMonth, } from "./format.js";
|
|
8
|
+
export { requestJson, toQueryString, } from "./http-json.js";
|
|
6
9
|
export { memoizeByContent } from "./memoize.js";
|
|
7
10
|
export { createTestClock, systemClock } from "./clock.js";
|
|
8
|
-
export { formatMessage, getMessage,
|
|
11
|
+
export { formatMessage, getMessage, DEFAULT_LOCALE, isLocale, mergeMessages, pickLocalizedText, selectMessages, selectPlural, } from "./i18n.js";
|
|
9
12
|
export { coreMessages } from "./messages/index.js";
|
|
10
13
|
export { err, ok } from "./result.js";
|
|
11
14
|
export { errorLogLabel, getPublicMessage, isPublicError, PublicError, safeError } from "./safe-error.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,mGAAmG;AACnG,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,aAAa,EACb,kBAAkB,GAEnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,aAAa,EACb,eAAe,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,mGAAmG;AACnG,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,aAAa,EACb,kBAAkB,GAEnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,aAAa,GAEd,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,mBAAmB,EAAsB,MAAM,sBAAsB,CAAC;AAC7G,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,aAAa,EACb,eAAe,GAOhB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,WAAW,EACX,aAAa,GAMd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAuD,MAAM,cAAc,CAAC;AACrG,OAAO,EAAE,eAAe,EAAE,WAAW,EAA8B,MAAM,YAAY,CAAC;AACtF,OAAO,EACL,aAAa,EACb,UAAU,EACV,cAAc,EACd,QAAQ,EACR,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,YAAY,GAQb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,YAAY,EAAqB,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAkD,MAAM,aAAa,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAsB,MAAM,iBAAiB,CAAC;AAC7H,OAAO,EACL,mBAAmB,EACnB,SAAS,EACT,yBAAyB,GAQ1B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAuB,MAAM,eAAe,CAAC;AAC1E,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,YAAY,GAUb,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iBAAiB,EACjB,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,GAIjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAuC,MAAM,gBAAgB,CAAC;AACvG,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAyC,MAAM,eAAe,CAAC;AACpG,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,cAAc,EAAmC,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** A string checked by `isLocalDateTime` or `localDateTimeSchema`; a plain string is not one. */
|
|
3
|
+
export type LocalDateTime = string & z.$brand<"LocalDateTime">;
|
|
4
|
+
/** Whether `value` is a `YYYY-MM-DDTHH:mm` local date-time on a real day (`2026-02-30T10:00` and `…T24:00` are not). */
|
|
5
|
+
export declare function isLocalDateTime(value: unknown): value is LocalDateTime;
|
|
6
|
+
/** A `YYYY-MM-DDTHH:mm` local date-time in tool and form input, parsed into the branded `LocalDateTime`. */
|
|
7
|
+
export declare const localDateTimeSchema: z.core.$ZodBranded<z.ZodString & z.ZodType<LocalDateTime, string, z.core.$ZodTypeInternals<LocalDateTime, string>>, "LocalDateTime", "out">;
|
|
8
|
+
/** The calendar day (`YYYY-MM-DD`) of a local date-time. Throws a `RangeError` for a malformed value. */
|
|
9
|
+
export declare function getLocalDay(value: LocalDateTime): string;
|
|
10
|
+
//# sourceMappingURL=local-date-time.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-date-time.d.ts","sourceRoot":"","sources":["../src/local-date-time.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,iGAAiG;AACjG,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;AAE/D,wHAAwH;AACxH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAItE;AAED,4GAA4G;AAC5G,eAAO,MAAM,mBAAmB,6IAGL,CAAC;AAE5B,yGAAyG;AACzG,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAKxD"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// A local wall-clock date-time, `YYYY-MM-DDTHH:mm` with no time zone: a time that is local at a place
|
|
2
|
+
// (a departure, a booking slot), independent of the server's zone. Zero-padded, so it sorts as text.
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { isCalendarDay } from "./calendar-day.js";
|
|
5
|
+
const LOCAL_DATE_TIME_PATTERN = /^(\d{4}-\d{2}-\d{2})T([01]\d|2[0-3]):[0-5]\d$/;
|
|
6
|
+
/** Whether `value` is a `YYYY-MM-DDTHH:mm` local date-time on a real day (`2026-02-30T10:00` and `…T24:00` are not). */
|
|
7
|
+
export function isLocalDateTime(value) {
|
|
8
|
+
if (typeof value !== "string")
|
|
9
|
+
return false;
|
|
10
|
+
const match = LOCAL_DATE_TIME_PATTERN.exec(value);
|
|
11
|
+
return match !== null && isCalendarDay(match[1]);
|
|
12
|
+
}
|
|
13
|
+
/** A `YYYY-MM-DDTHH:mm` local date-time in tool and form input, parsed into the branded `LocalDateTime`. */
|
|
14
|
+
export const localDateTimeSchema = z
|
|
15
|
+
.string()
|
|
16
|
+
.refine(isLocalDateTime, "must be a YYYY-MM-DDTHH:mm local date-time on a real day, e.g. 2026-10-04T09:30")
|
|
17
|
+
.brand();
|
|
18
|
+
/** The calendar day (`YYYY-MM-DD`) of a local date-time. Throws a `RangeError` for a malformed value. */
|
|
19
|
+
export function getLocalDay(value) {
|
|
20
|
+
if (!isLocalDateTime(value)) {
|
|
21
|
+
throw new RangeError(`getLocalDay: "${String(value)}" is not a YYYY-MM-DDTHH:mm local date-time`);
|
|
22
|
+
}
|
|
23
|
+
return value.slice(0, "YYYY-MM-DD".length);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=local-date-time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-date-time.js","sourceRoot":"","sources":["../src/local-date-time.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,qGAAqG;AACrG,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,uBAAuB,GAAG,+CAA+C,CAAC;AAKhF,wHAAwH;AACxH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,OAAO,KAAK,KAAK,IAAI,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,4GAA4G;AAC5G,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC;KACjC,MAAM,EAAE;KACR,MAAM,CAAC,eAAe,EAAE,iFAAiF,CAAC;KAC1G,KAAK,EAAmB,CAAC;AAE5B,yGAAyG;AACzG,MAAM,UAAU,WAAW,CAAC,KAAoB;IAC9C,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,UAAU,CAAC,iBAAiB,MAAM,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACpG,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;AAC7C,CAAC"}
|
package/dist/messages/en.d.ts
CHANGED
|
@@ -2,21 +2,11 @@ export declare const en: {
|
|
|
2
2
|
errors: {
|
|
3
3
|
database_failed: string;
|
|
4
4
|
unexpected: string;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
many: string;
|
|
11
|
-
other: string;
|
|
12
|
-
};
|
|
13
|
-
months: {
|
|
14
|
-
one: string;
|
|
15
|
-
few: string;
|
|
16
|
-
many: string;
|
|
17
|
-
other: string;
|
|
18
|
-
};
|
|
19
|
-
both: string;
|
|
5
|
+
http_unreachable: string;
|
|
6
|
+
http_refused: string;
|
|
7
|
+
http_rate_limited: string;
|
|
8
|
+
http_unavailable: string;
|
|
9
|
+
http_unexpected_answer: string;
|
|
20
10
|
};
|
|
21
11
|
};
|
|
22
12
|
//# sourceMappingURL=en.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/messages/en.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/messages/en.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;CAUd,CAAC"}
|
package/dist/messages/en.js
CHANGED
|
@@ -2,11 +2,11 @@ export const en = {
|
|
|
2
2
|
errors: {
|
|
3
3
|
database_failed: "Something went wrong while saving or loading data. Please try again.",
|
|
4
4
|
unexpected: "Something went wrong. Please try again.",
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
http_unreachable: "The service could not be reached. Please try again later.",
|
|
6
|
+
http_refused: "The service refused the request.",
|
|
7
|
+
http_rate_limited: "The service is receiving too many requests. Please try again later.",
|
|
8
|
+
http_unavailable: "The service is unavailable right now. Please try again later.",
|
|
9
|
+
http_unexpected_answer: "The service sent an answer that could not be read.",
|
|
10
10
|
},
|
|
11
11
|
};
|
|
12
12
|
//# sourceMappingURL=en.js.map
|
package/dist/messages/en.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en.js","sourceRoot":"","sources":["../../src/messages/en.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,EAAE,GAAG;IAChB,MAAM,EAAE;QACN,eAAe,EAAE,sEAAsE;QACvF,UAAU,EAAE,yCAAyC;
|
|
1
|
+
{"version":3,"file":"en.js","sourceRoot":"","sources":["../../src/messages/en.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,EAAE,GAAG;IAChB,MAAM,EAAE;QACN,eAAe,EAAE,sEAAsE;QACvF,UAAU,EAAE,yCAAyC;QACrD,gBAAgB,EAAE,2DAA2D;QAC7E,YAAY,EAAE,kCAAkC;QAChD,iBAAiB,EAAE,qEAAqE;QACxF,gBAAgB,EAAE,+DAA+D;QACjF,sBAAsB,EAAE,oDAAoD;KAC7E;CACF,CAAC"}
|
package/dist/messages/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Dictionaries } from "../i18n.js";
|
|
2
2
|
import { en } from "./en.js";
|
|
3
3
|
export type CoreMessages = typeof en;
|
|
4
|
-
/** Copy for core's own error codes (`core.<key>` → `errors.<key>`)
|
|
4
|
+
/** Copy for core's own error codes (`core.<key>` → `errors.<key>`). */
|
|
5
5
|
export declare const coreMessages: Dictionaries<CoreMessages>;
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/messages/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/messages/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B,MAAM,MAAM,YAAY,GAAG,OAAO,EAAE,CAAC;AAErC,uEAAuE;AACvE,eAAO,MAAM,YAAY,EAAE,YAAY,CAAC,YAAY,CAAU,CAAC"}
|
package/dist/messages/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { en } from "./en.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export const coreMessages = { en, pl };
|
|
2
|
+
/** Copy for core's own error codes (`core.<key>` → `errors.<key>`). */
|
|
3
|
+
export const coreMessages = { en };
|
|
5
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/messages/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/messages/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAI7B,uEAAuE;AACvE,MAAM,CAAC,MAAM,YAAY,GAA+B,EAAE,EAAE,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// A calendar period: two calendar days (`YYYY-MM-DD`) with both ends included, so one day is
|
|
2
|
+
// `{ from: d, to: d }`. Zero-padded days sort as text in calendar order, so comparisons work on the strings.
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { calendarDaysBetween, calendarDaySchema, isCalendarDay } from "./calendar-day.js";
|
|
5
|
+
|
|
6
|
+
/** Calendar days from `from` to `to`, both included; `to` never comes before `from`. */
|
|
7
|
+
export interface CalendarPeriod {
|
|
8
|
+
readonly from: string;
|
|
9
|
+
readonly to: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** A `CalendarPeriod` in tool and form input: two calendar days, `to` refused (path `["to"]`) when it comes first. */
|
|
13
|
+
export const calendarPeriodSchema = z
|
|
14
|
+
.object({ from: calendarDaySchema, to: calendarDaySchema })
|
|
15
|
+
// A malformed end already has its own issue, and zod still runs the refinement then: skip it, so the
|
|
16
|
+
// order is checked only between two real days.
|
|
17
|
+
.refine((period) => !isCalendarDay(period.from) || !isCalendarDay(period.to) || period.from <= period.to, {
|
|
18
|
+
message: "must not come before from",
|
|
19
|
+
path: ["to"],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
/** Whether `day` lies in `period`, both ends included. Throws a `RangeError` for a malformed day or period. */
|
|
23
|
+
export function isDayInPeriod(day: string, period: CalendarPeriod): boolean {
|
|
24
|
+
const operation = "isDayInPeriod";
|
|
25
|
+
assertCalendarDay(operation, day);
|
|
26
|
+
assertPeriod(operation, period);
|
|
27
|
+
return period.from <= day && day <= period.to;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Whether `a` and `b` share at least one day; adjacent periods do not. Throws a `RangeError` for a malformed period. */
|
|
31
|
+
export function doPeriodsOverlap(a: CalendarPeriod, b: CalendarPeriod): boolean {
|
|
32
|
+
const operation = "doPeriodsOverlap";
|
|
33
|
+
assertPeriod(operation, a);
|
|
34
|
+
assertPeriod(operation, b);
|
|
35
|
+
return a.from <= b.to && b.from <= a.to;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** The number of days in `period`, both ends included: 1 for a single day. Throws a `RangeError` for a malformed period. */
|
|
39
|
+
export function countPeriodDays(period: CalendarPeriod): number {
|
|
40
|
+
assertPeriod("countPeriodDays", period);
|
|
41
|
+
return calendarDaysBetween(period.from, period.to) + 1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function assertPeriod(operation: string, period: CalendarPeriod): void {
|
|
45
|
+
assertCalendarDay(operation, period.from);
|
|
46
|
+
assertCalendarDay(operation, period.to);
|
|
47
|
+
if (period.to < period.from) {
|
|
48
|
+
throw new RangeError(`${operation}: the period ends ("${period.to}") before it starts ("${period.from}")`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function assertCalendarDay(operation: string, day: string): void {
|
|
53
|
+
if (!isCalendarDay(day)) throw new RangeError(`${operation}: "${String(day)}" is not a YYYY-MM-DD calendar day`);
|
|
54
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { formatIssues, SoftureConfigError } from "./config-error.js";
|
|
5
5
|
import { isDatabaseOptional } from "./database-requirement.js";
|
|
6
|
-
import {
|
|
6
|
+
import { isLocale, type Locale } from "./i18n.js";
|
|
7
7
|
import type { AnySoftureModule } from "./module.js";
|
|
8
8
|
import { err, ok, type Result } from "./result.js";
|
|
9
9
|
import { parseVersionRange, satisfiesRange } from "./version-range.js";
|
|
@@ -102,7 +102,7 @@ const configSchema = z.object({
|
|
|
102
102
|
})
|
|
103
103
|
.nullable()
|
|
104
104
|
.default(null),
|
|
105
|
-
locale: z.
|
|
105
|
+
locale: z.string().refine(isLocale, "must be a BCP 47 language tag, e.g. en or de-AT"),
|
|
106
106
|
timezone: z.string().refine(isTimeZone, "must be an IANA time zone, e.g. Europe/Warsaw"),
|
|
107
107
|
appOrigin: z.string().refine(isOrigin, ORIGIN_MESSAGE),
|
|
108
108
|
landingOrigin: z.string().refine(isOrigin, ORIGIN_MESSAGE).optional(),
|