@softure-ai/core 0.1.10 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +77 -12
  3. package/dist/calendar-day.d.ts +3 -0
  4. package/dist/calendar-day.d.ts.map +1 -1
  5. package/dist/calendar-day.js +5 -0
  6. package/dist/calendar-day.js.map +1 -1
  7. package/dist/config.d.ts +7 -0
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +4 -2
  10. package/dist/config.js.map +1 -1
  11. package/dist/format.d.ts +51 -7
  12. package/dist/format.d.ts.map +1 -1
  13. package/dist/format.js +98 -12
  14. package/dist/format.js.map +1 -1
  15. package/dist/i18n.d.ts +34 -11
  16. package/dist/i18n.d.ts.map +1 -1
  17. package/dist/i18n.js +40 -10
  18. package/dist/i18n.js.map +1 -1
  19. package/dist/index.d.ts +4 -3
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +4 -3
  22. package/dist/index.js.map +1 -1
  23. package/dist/memoize.d.ts +16 -0
  24. package/dist/memoize.d.ts.map +1 -0
  25. package/dist/memoize.js +81 -0
  26. package/dist/memoize.js.map +1 -0
  27. package/dist/messages/index.d.ts.map +1 -1
  28. package/dist/messages/index.js +1 -2
  29. package/dist/messages/index.js.map +1 -1
  30. package/dist/og/index.d.ts +2 -0
  31. package/dist/og/index.d.ts.map +1 -0
  32. package/dist/og/index.js +4 -0
  33. package/dist/og/index.js.map +1 -0
  34. package/dist/og/og-fonts.d.ts +37 -0
  35. package/dist/og/og-fonts.d.ts.map +1 -0
  36. package/dist/og/og-fonts.js +95 -0
  37. package/dist/og/og-fonts.js.map +1 -0
  38. package/package.json +6 -1
  39. package/src/calendar-day.ts +4 -0
  40. package/src/config.ts +11 -2
  41. package/src/format.ts +131 -17
  42. package/src/i18n.ts +53 -19
  43. package/src/index.ts +21 -2
  44. package/src/memoize.ts +89 -0
  45. package/src/messages/index.ts +1 -2
  46. package/src/og/index.ts +12 -0
  47. package/src/og/og-fonts.ts +127 -0
  48. package/dist/messages/pl.d.ts +0 -3
  49. package/dist/messages/pl.d.ts.map +0 -1
  50. package/dist/messages/pl.js +0 -7
  51. package/dist/messages/pl.js.map +0 -1
  52. package/src/messages/pl.ts +0 -8
package/dist/i18n.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- export declare const LOCALES: readonly ["en", "pl"];
2
- export type Locale = (typeof LOCALES)[number];
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
- /** One complete dictionary per locale. */
12
- export type Dictionaries<T extends MessageTree> = Readonly<Record<Locale, T>>;
13
- /** Partial overrides an app passes for some locales. */
14
- export type MessageOverrides<T extends MessageTree> = Partial<Record<Locale, DeepPartial<T>>>;
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. Only keys the defaults have are taken,
27
- * and a group is never replaced by a string, so an override cannot break the dictionary shape.
28
- * Inputs are not mutated.
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
- /** The form for `count` under the plural rules of `locale` ("1 file", "2 files"). */
34
- export declare function selectPlural(locale: Locale, count: number, forms: PluralForms): string;
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
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,uBAAwB,CAAC;AAE7C,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9C,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,0CAA0C;AAC1C,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;AAE9E,wDAAwD;AACxD,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9F,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,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAExD;AAED;;;;GAIG;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,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,qFAAqF;AACrF,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"}
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` and
2
- // `pl` dictionaries, and the app passes partial overrides per locale.
3
- export const LOCALES = ["en", "pl"];
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
- return LOCALES.some((locale) => locale === value);
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. Only keys the defaults have are taken,
9
- * and a group is never replaced by a string, so an override cannot break the dictionary shape.
10
- * Inputs are not mutated.
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 LOCALES) {
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
- /** The form for `count` under the plural rules of `locale` ("1 file", "2 files"). */
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":"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"}
1
+ {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- export { addCalendarDays, addCalendarMonths, calendarDaysBetween, getCalendarDay, isCalendarDay, toCalendarDay, wholeMonthsBetween, type EndOfMonth, } from "./calendar-day.js";
1
+ export { addCalendarDays, addCalendarMonths, calendarDaysBetween, calendarDaySchema, getCalendarDay, isCalendarDay, toCalendarDay, wholeMonthsBetween, type EndOfMonth, } from "./calendar-day.js";
2
2
  export { CURRENCY_MINOR_UNIT_DIGITS } from "./currency-digits.js";
3
- export { formatCalendarDay, formatMoney, formatPercent, type CalendarDayStyle, type FormatMoneyOptions } from "./format.js";
3
+ 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";
4
+ export { memoizeByContent, type MemoizeByContentOptions, type MemoizedFunction } from "./memoize.js";
4
5
  export { createTestClock, systemClock, type Clock, type TestClock } from "./clock.js";
5
- export { formatMessage, getMessage, isLocale, LOCALES, mergeMessages, selectPlural, type DeepPartial, type Dictionaries, type Locale, type MessageOverrides, type MessageTree, type PluralForms, } from "./i18n.js";
6
+ 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";
6
7
  export { coreMessages, type CoreMessages } from "./messages/index.js";
7
8
  export { err, ok, type Err, type ErrorCode, type Ok, type Result } from "./result.js";
8
9
  export { errorLogLabel, getPublicMessage, isPublicError, PublicError, safeError, type CoreErrorCode } from "./safe-error.js";
@@ -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,cAAc,EACd,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,KAAK,UAAU,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC5H,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,KAAK,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACtF,OAAO,EACL,aAAa,EACb,UAAU,EACV,QAAQ,EACR,OAAO,EACP,aAAa,EACb,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,MAAM,EACX,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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,10 +1,11 @@
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
- export { addCalendarDays, addCalendarMonths, calendarDaysBetween, getCalendarDay, isCalendarDay, toCalendarDay, wholeMonthsBetween, } from "./calendar-day.js";
3
+ export { addCalendarDays, addCalendarMonths, calendarDaysBetween, calendarDaySchema, getCalendarDay, isCalendarDay, toCalendarDay, wholeMonthsBetween, } from "./calendar-day.js";
4
4
  export { CURRENCY_MINOR_UNIT_DIGITS } from "./currency-digits.js";
5
- export { formatCalendarDay, formatMoney, formatPercent } from "./format.js";
5
+ export { DEFAULT_DURATION_MESSAGES, formatCalendarDay, formatCalendarMonth, formatDuration, formatMoney, formatPercent, isCalendarMonth, } from "./format.js";
6
+ export { memoizeByContent } from "./memoize.js";
6
7
  export { createTestClock, systemClock } from "./clock.js";
7
- export { formatMessage, getMessage, isLocale, LOCALES, mergeMessages, selectPlural, } from "./i18n.js";
8
+ export { formatMessage, getMessage, DEFAULT_LOCALE, isLocale, mergeMessages, pickLocalizedText, selectMessages, selectPlural, } from "./i18n.js";
8
9
  export { coreMessages } from "./messages/index.js";
9
10
  export { err, ok } from "./result.js";
10
11
  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,cAAc,EACd,aAAa,EACb,aAAa,EACb,kBAAkB,GAEnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,aAAa,EAAkD,MAAM,aAAa,CAAC;AAC5H,OAAO,EAAE,eAAe,EAAE,WAAW,EAA8B,MAAM,YAAY,CAAC;AACtF,OAAO,EACL,aAAa,EACb,UAAU,EACV,QAAQ,EACR,OAAO,EACP,aAAa,EACb,YAAY,GAOb,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"}
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,yBAAyB,EACzB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,aAAa,EACb,eAAe,GAOhB,MAAM,aAAa,CAAC;AACrB,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,16 @@
1
+ export interface MemoizeByContentOptions {
2
+ /** The most entries kept; the least recently used one goes first. */
3
+ readonly max: number;
4
+ }
5
+ /** `fn` with a cache, plus `clear()` to empty it. */
6
+ export type MemoizedFunction<Args extends readonly unknown[], Value> = ((...args: Args) => Value) & {
7
+ readonly clear: () => void;
8
+ };
9
+ /**
10
+ * `fn` cached by the content of its arguments: primitives, arrays, `Date`s and plain objects (key order does not
11
+ * matter). An argument holding anything else (a function, a `Map`, a class instance, a cycle) throws a `TypeError`.
12
+ * A promise that rejects is dropped, so the next call tries again. Throws a `RangeError` for a `max` that is not a
13
+ * positive whole number.
14
+ */
15
+ export declare function memoizeByContent<Args extends readonly unknown[], Value>(fn: (...args: Args) => Value, options: MemoizeByContentOptions): MemoizedFunction<Args, Value>;
16
+ //# sourceMappingURL=memoize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoize.d.ts","sourceRoot":"","sources":["../src/memoize.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,qDAAqD;AACrD,MAAM,MAAM,gBAAgB,CAAC,IAAI,SAAS,SAAS,OAAO,EAAE,EAAE,KAAK,IAAI,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,KAAK,CAAC,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC;AAEnI;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,SAAS,SAAS,OAAO,EAAE,EAAE,KAAK,EACrE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,KAAK,EAC5B,OAAO,EAAE,uBAAuB,GAC/B,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CA4B/B"}
@@ -0,0 +1,81 @@
1
+ // A cache for pure functions of plain data: the arguments' content is the key, so two equal objects built apart hit
2
+ // the same entry. Least recently used entries go beyond `max`; nothing expires by time.
3
+ /**
4
+ * `fn` cached by the content of its arguments: primitives, arrays, `Date`s and plain objects (key order does not
5
+ * matter). An argument holding anything else (a function, a `Map`, a class instance, a cycle) throws a `TypeError`.
6
+ * A promise that rejects is dropped, so the next call tries again. Throws a `RangeError` for a `max` that is not a
7
+ * positive whole number.
8
+ */
9
+ export function memoizeByContent(fn, options) {
10
+ const { max } = options;
11
+ if (!Number.isSafeInteger(max) || max < 1)
12
+ throw new RangeError(`memoizeByContent: max must be a positive whole number, got ${String(max)}`);
13
+ const cache = new Map();
14
+ const memoized = (...args) => {
15
+ const key = toContentKey(args, new Set());
16
+ if (cache.has(key)) {
17
+ // Not `?? fn(...)`: a cached `undefined` is a hit too.
18
+ const hit = cache.get(key);
19
+ cache.delete(key);
20
+ cache.set(key, hit);
21
+ return hit;
22
+ }
23
+ const value = fn(...args);
24
+ cache.set(key, value);
25
+ if (cache.size > max) {
26
+ const oldest = cache.keys().next();
27
+ if (oldest.done !== true)
28
+ cache.delete(oldest.value);
29
+ }
30
+ if (value instanceof Promise) {
31
+ value.catch(() => {
32
+ if (cache.get(key) === value)
33
+ cache.delete(key);
34
+ });
35
+ }
36
+ return value;
37
+ };
38
+ return Object.assign(memoized, { clear: () => cache.clear() });
39
+ }
40
+ function toContentKey(value, path) {
41
+ switch (typeof value) {
42
+ case "undefined":
43
+ return "u";
44
+ case "boolean":
45
+ return value ? "t" : "f";
46
+ case "number":
47
+ return `n${Object.is(value, -0) ? "-0" : String(value)}`;
48
+ case "bigint":
49
+ return `b${String(value)}`;
50
+ case "string":
51
+ return JSON.stringify(value);
52
+ case "object":
53
+ return value === null ? "null" : toObjectKey(value, path);
54
+ default:
55
+ throw new TypeError(`memoizeByContent: an argument holds a ${typeof value}, which has no content key`);
56
+ }
57
+ }
58
+ function toObjectKey(value, path) {
59
+ if (value instanceof Date)
60
+ return `d${String(value.getTime())}`;
61
+ if (path.has(value))
62
+ throw new TypeError("memoizeByContent: an argument holds a cycle");
63
+ path.add(value);
64
+ let key;
65
+ if (Array.isArray(value)) {
66
+ key = `[${value.map((item) => toContentKey(item, path)).join(",")}]`;
67
+ }
68
+ else {
69
+ const prototype = Object.getPrototypeOf(value);
70
+ if (prototype !== Object.prototype && prototype !== null) {
71
+ throw new TypeError(`memoizeByContent: an argument holds a ${value.constructor.name}, which has no content key`);
72
+ }
73
+ const entries = Object.keys(value)
74
+ .sort()
75
+ .map((name) => `${JSON.stringify(name)}:${toContentKey(value[name], path)}`);
76
+ key = `{${entries.join(",")}}`;
77
+ }
78
+ path.delete(value);
79
+ return key;
80
+ }
81
+ //# sourceMappingURL=memoize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoize.js","sourceRoot":"","sources":["../src/memoize.ts"],"names":[],"mappings":"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"}
@@ -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;AAG7B,MAAM,MAAM,YAAY,GAAG,OAAO,EAAE,CAAC;AAErC,uEAAuE;AACvE,eAAO,MAAM,YAAY,EAAE,YAAY,CAAC,YAAY,CAAc,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"}
@@ -1,5 +1,4 @@
1
1
  import { en } from "./en.js";
2
- import { pl } from "./pl.js";
3
2
  /** Copy for core's own error codes (`core.<key>` → `errors.<key>`). */
4
- export const coreMessages = { en, pl };
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;AAC7B,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAI7B,uEAAuE;AACvE,MAAM,CAAC,MAAM,YAAY,GAA+B,EAAE,EAAE,EAAE,EAAE,EAAE,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"}
@@ -0,0 +1,2 @@
1
+ export { createOgFontLoader, loadOgFonts, OG_FONT_WEIGHTS, type OgFont, type OgFontLoaderOptions, type OgFontSource, type OgFontsResult, type OgFontWeight, } from "./og-fonts.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/og/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,KAAK,MAAM,EACX,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,eAAe,CAAC"}
@@ -0,0 +1,4 @@
1
+ // The OG card font loader: server only (it reads files), no `next/*` imports. `@softure-ai/seo/server` re-exports it
2
+ // for an app's own `opengraph-image` routes, the blog for its article card.
3
+ export { createOgFontLoader, loadOgFonts, OG_FONT_WEIGHTS, } from "./og-fonts.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/og/index.ts"],"names":[],"mappings":"AAAA,qHAAqH;AACrH,4EAA4E;AAC5E,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,eAAe,GAMhB,MAAM,eAAe,CAAC"}
@@ -0,0 +1,37 @@
1
+ /** The weights Satori (`next/og`) draws: static fonts only, in steps of 100. */
2
+ export declare const OG_FONT_WEIGHTS: readonly [100, 200, 300, 400, 500, 600, 700, 800, 900];
3
+ export type OgFontWeight = (typeof OG_FONT_WEIGHTS)[number];
4
+ /** A font to read: a path (from the loader's root, or absolute) or an https URL, and how the card names it. */
5
+ export interface OgFontSource {
6
+ readonly name: string;
7
+ readonly src: string;
8
+ readonly weight?: OgFontWeight;
9
+ readonly style?: "normal" | "italic";
10
+ }
11
+ /** A font for the card, as `ImageResponse` takes it. */
12
+ export interface OgFont {
13
+ readonly name: string;
14
+ readonly data: ArrayBuffer;
15
+ readonly weight?: OgFontWeight;
16
+ readonly style?: "normal" | "italic";
17
+ }
18
+ export type OgFontsResult = {
19
+ readonly ok: true;
20
+ readonly fonts: readonly OgFont[];
21
+ } | {
22
+ readonly ok: false;
23
+ readonly error: string;
24
+ };
25
+ export interface OgFontLoaderOptions {
26
+ /** Where a relative path starts: the app's root. */
27
+ readonly root: string;
28
+ readonly readFile?: (path: string) => Promise<Uint8Array>;
29
+ readonly fetchImpl?: typeof fetch;
30
+ /** What a message names the list by, before `[index]`. Default: `OG card: fonts`. */
31
+ readonly label?: string;
32
+ }
33
+ /** A loader with its own cache, keyed by the resolved path or URL. */
34
+ export declare function createOgFontLoader(options: OgFontLoaderOptions): (fonts: readonly OgFontSource[]) => Promise<OgFontsResult>;
35
+ /** The fonts for an app's own OG card, read from the working directory (the app's root, where Next runs) and cached for the process. */
36
+ export declare function loadOgFonts(fonts: readonly OgFontSource[]): Promise<OgFontsResult>;
37
+ //# sourceMappingURL=og-fonts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"og-fonts.d.ts","sourceRoot":"","sources":["../../src/og/og-fonts.ts"],"names":[],"mappings":"AAOA,gFAAgF;AAChF,eAAO,MAAM,eAAe,wDAAyD,CAAC;AAEtF,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,+GAA+G;AAC/G,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACtC;AAED,wDAAwD;AACxD,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACtC;AAED,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAItI,MAAM,WAAW,mBAAmB;IAClC,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AA0BD,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,KAAK,OAAO,CAAC,aAAa,CAAC,CAoD3H;AAID,wIAAwI;AACxI,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAGlF"}
@@ -0,0 +1,95 @@
1
+ // The loader of an OG card's fonts: each source is read once, checked to be a font Satori draws (.ttf,
2
+ // .otf, .woff; not .woff2), and kept for the life of the loader. A failed read is not kept, so a fixed
3
+ // file is picked up by the next call. It imports no Next code, so a command-line check can run it too.
4
+ // `@softure-ai/seo/server` and the blog re-export it.
5
+ import { readFile } from "node:fs/promises";
6
+ import { isAbsolute, resolve } from "node:path";
7
+ /** The weights Satori (`next/og`) draws: static fonts only, in steps of 100. */
8
+ export const OG_FONT_WEIGHTS = [100, 200, 300, 400, 500, 600, 700, 800, 900];
9
+ const DEFAULT_LABEL = "OG card: fonts";
10
+ /** The first four bytes of each font format Satori parses. */
11
+ const FONT_SIGNATURES = ["wOFF", "OTTO", "\u0000\u0001\u0000\u0000", "true"];
12
+ const WOFF2_SIGNATURE = "wOF2";
13
+ function toArrayBuffer(bytes) {
14
+ const copy = new Uint8Array(bytes.byteLength);
15
+ copy.set(bytes);
16
+ return copy.buffer;
17
+ }
18
+ function checkFontBytes(bytes) {
19
+ const signature = String.fromCharCode(...bytes.subarray(0, 4));
20
+ if (signature === WOFF2_SIGNATURE)
21
+ return { ok: false, reason: "a .woff2 font, which the card cannot read; use the .woff or .ttf file" };
22
+ if (!FONT_SIGNATURES.includes(signature))
23
+ return { ok: false, reason: "not a .ttf, .otf or .woff font" };
24
+ return { ok: true, data: toArrayBuffer(bytes) };
25
+ }
26
+ function getErrorCode(error) {
27
+ if (typeof error === "object" && error !== null && "code" in error && typeof error.code === "string")
28
+ return error.code;
29
+ return error instanceof Error ? error.message : String(error);
30
+ }
31
+ /** A loader with its own cache, keyed by the resolved path or URL. */
32
+ export function createOgFontLoader(options) {
33
+ const read = options.readFile ?? readFile;
34
+ const fetchImpl = options.fetchImpl ?? fetch;
35
+ const label = options.label ?? DEFAULT_LABEL;
36
+ const cache = new Map();
37
+ async function readSource(location, isUrl) {
38
+ if (!isUrl) {
39
+ try {
40
+ return checkFontBytes(await read(location));
41
+ }
42
+ catch (error) {
43
+ return { ok: false, reason: `the file cannot be read (${getErrorCode(error)})` };
44
+ }
45
+ }
46
+ let response;
47
+ try {
48
+ response = await fetchImpl(location);
49
+ }
50
+ catch (error) {
51
+ return { ok: false, reason: `the request failed (${getErrorCode(error)})` };
52
+ }
53
+ if (!response.ok)
54
+ return { ok: false, reason: `the server answered ${response.status}` };
55
+ try {
56
+ return checkFontBytes(new Uint8Array(await response.arrayBuffer()));
57
+ }
58
+ catch (error) {
59
+ return { ok: false, reason: `the answer could not be read (${getErrorCode(error)})` };
60
+ }
61
+ }
62
+ function getBytes(location, isUrl) {
63
+ const cached = cache.get(location);
64
+ if (cached !== undefined)
65
+ return cached;
66
+ const pending = readSource(location, isUrl).then((result) => {
67
+ if (!result.ok)
68
+ cache.delete(location);
69
+ return result;
70
+ });
71
+ cache.set(location, pending);
72
+ return pending;
73
+ }
74
+ return async (fonts) => {
75
+ const located = fonts.map((font) => {
76
+ const isUrl = font.src.startsWith("https://");
77
+ return { font, isUrl, location: isUrl || isAbsolute(font.src) ? font.src : resolve(options.root, font.src) };
78
+ });
79
+ const results = await Promise.all(located.map(async (entry) => ({ ...entry, result: await getBytes(entry.location, entry.isUrl) })));
80
+ const loaded = [];
81
+ for (const [index, { font, location, result }] of results.entries()) {
82
+ if (!result.ok)
83
+ return { ok: false, error: `${label}[${index}] "${font.src}": ${result.reason} (${location}).` };
84
+ loaded.push({ name: font.name, data: result.data, weight: font.weight, style: font.style });
85
+ }
86
+ return { ok: true, fonts: loaded };
87
+ };
88
+ }
89
+ let loadFromWorkingDirectory;
90
+ /** The fonts for an app's own OG card, read from the working directory (the app's root, where Next runs) and cached for the process. */
91
+ export function loadOgFonts(fonts) {
92
+ loadFromWorkingDirectory ??= createOgFontLoader({ root: process.cwd() });
93
+ return loadFromWorkingDirectory(fonts);
94
+ }
95
+ //# sourceMappingURL=og-fonts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"og-fonts.js","sourceRoot":"","sources":["../../src/og/og-fonts.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softure-ai/core",
3
- "version": "0.1.10",
3
+ "version": "0.2.0",
4
4
  "description": "The SOFTURE AI module contract: app config, module definitions, Result, Clock and messages.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,6 +39,11 @@
39
39
  "@softure-ai/source": "./src/cli/index.ts",
40
40
  "types": "./dist/cli/index.d.ts",
41
41
  "default": "./dist/cli/index.js"
42
+ },
43
+ "./og": {
44
+ "@softure-ai/source": "./src/og/index.ts",
45
+ "types": "./dist/og/index.d.ts",
46
+ "default": "./dist/og/index.js"
42
47
  }
43
48
  },
44
49
  "scripts": {
@@ -1,5 +1,6 @@
1
1
  // The calendar day of an instant in a given IANA time zone, as `YYYY-MM-DD`. "Today" computed in the
2
2
  // process zone is a classic date bug: on a server in UTC, an evening in New York is already tomorrow.
3
+ import { z } from "zod";
3
4
  import type { Clock } from "./clock.js";
4
5
 
5
6
  const formatters = new Map<string, Intl.DateTimeFormat>();
@@ -59,6 +60,9 @@ export function isCalendarDay(value: unknown): value is string {
59
60
  return typeof value === "string" && parseCivilDate(value) !== null;
60
61
  }
61
62
 
63
+ /** A `YYYY-MM-DD` calendar day in tool and form input: `isCalendarDay` as a zod schema. */
64
+ export const calendarDaySchema = z.string().refine(isCalendarDay, "must be a YYYY-MM-DD calendar day, e.g. 2026-10-04");
65
+
62
66
  /** `day` moved by `days` calendar days (negative goes back). Throws a `RangeError` for a malformed day or count. */
63
67
  export function addCalendarDays(day: string, days: number): string {
64
68
  const operation = "addCalendarDays";
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 { LOCALES, type Locale } from "./i18n.js";
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";
@@ -63,6 +63,11 @@ export interface SoftureConfig {
63
63
  readonly timezone: string;
64
64
  /** Scheme, host and port of the app, without a path: `https://app.example.com`. */
65
65
  readonly appOrigin: string;
66
+ /**
67
+ * The public landing site (`https://example.com`) when the app lives on a subdomain beside it; `appOrigin` when
68
+ * the app does not name one. For links from the app to its marketing pages, not for the app's own URLs.
69
+ */
70
+ readonly landingOrigin: string;
66
71
  /** Every origin the app is served under besides `appOrigin`, read by `resolveAppOrigin`. */
67
72
  readonly origins: SoftureOrigins;
68
73
  /** Enabled modules, in the order the app listed them. */
@@ -75,6 +80,8 @@ export interface SoftureConfigInput {
75
80
  readonly locale: Locale;
76
81
  readonly timezone: string;
77
82
  readonly appOrigin: string;
83
+ /** The public landing site beside the app; defaults to `appOrigin`. */
84
+ readonly landingOrigin?: string;
78
85
  readonly origins?: SoftureOriginsInput;
79
86
  readonly modules: readonly AnySoftureModule[];
80
87
  }
@@ -95,9 +102,10 @@ const configSchema = z.object({
95
102
  })
96
103
  .nullable()
97
104
  .default(null),
98
- locale: z.enum(LOCALES),
105
+ locale: z.string().refine(isLocale, "must be a BCP 47 language tag, e.g. en or de-AT"),
99
106
  timezone: z.string().refine(isTimeZone, "must be an IANA time zone, e.g. Europe/Warsaw"),
100
107
  appOrigin: z.string().refine(isOrigin, ORIGIN_MESSAGE),
108
+ landingOrigin: z.string().refine(isOrigin, ORIGIN_MESSAGE).optional(),
101
109
  origins: z
102
110
  .strictObject({
103
111
  trustedOrigins: z.array(z.string().refine(isOrigin, ORIGIN_MESSAGE)).max(16, "takes at most 16 origins").default([]),
@@ -126,6 +134,7 @@ export function defineSoftureConfig(input: SoftureConfigInput): SoftureConfig {
126
134
 
127
135
  return Object.freeze({
128
136
  ...config,
137
+ landingOrigin: config.landingOrigin ?? config.appOrigin,
129
138
  database: config.database === null ? null : Object.freeze({ ...config.database }),
130
139
  origins: Object.freeze({ ...config.origins, trustedOrigins: Object.freeze([...config.origins.trustedOrigins]) }),
131
140
  modules: Object.freeze([...config.modules]),