@dbx-tools/shared-core 0.3.44 → 0.4.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.
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Browser-safe brand contract, defaults, and LLM serialization helpers.
3
+ *
4
+ * Asset values are intentionally strings: they may be relative file paths,
5
+ * package exports, data URLs, or network URLs depending on the consumer.
6
+ *
7
+ * @module
8
+ */
9
+ import { z } from "zod";
10
+ const nonBlankString = z.string().trim().min(1);
11
+ const color = z.string().regex(/^#(?:[\da-f]{3}|[\da-f]{6}|[\da-f]{8})$/i, "Expected a hex color.");
12
+ export const DEFAULT_BRAND_ASSETS = {
13
+ icon: {
14
+ light: "@dbx-tools/ui-branding/assets/icon-light.svg",
15
+ dark: "@dbx-tools/ui-branding/assets/icon-dark.svg",
16
+ },
17
+ logo: {
18
+ light: "@dbx-tools/ui-branding/assets/logo-light.svg",
19
+ dark: "@dbx-tools/ui-branding/assets/logo-dark.svg",
20
+ },
21
+ favicon: "@dbx-tools/ui-branding/assets/icon-light.svg",
22
+ };
23
+ export const BrandAssetSetSchema = z
24
+ .object({
25
+ light: nonBlankString.describe("Asset for light surfaces."),
26
+ dark: nonBlankString.optional().describe("Asset for dark surfaces; light is the fallback."),
27
+ })
28
+ .strict()
29
+ .describe("Theme-aware references to one visual asset.");
30
+ export const BrandColorsSchema = z
31
+ .object({
32
+ primary: color.default("#FF3621").describe("Primary action and identity color."),
33
+ primaryHover: color.default("#D92D18").describe("Primary hover or pressed color."),
34
+ accent: color.default("#2EB88A").describe("Secondary accent color."),
35
+ foreground: color.default("#0B2026").describe("Default text and mark color."),
36
+ background: color.default("#FFFFFF").describe("Default page background."),
37
+ surface: color.default("#F6F7F8").describe("Secondary surface background."),
38
+ muted: color.default("#5F6B70").describe("Muted text color."),
39
+ border: color.default("#DCE2E5").describe("Default border color."),
40
+ })
41
+ .strict()
42
+ .prefault({});
43
+ export const BrandVoiceSchema = z
44
+ .object({
45
+ audience: z
46
+ .array(nonBlankString)
47
+ .default(["Databricks developers", "application engineers", "AI agents"]),
48
+ tone: z.array(nonBlankString).default(["direct", "practical", "technical", "approachable"]),
49
+ principles: z
50
+ .array(nonBlankString)
51
+ .default([
52
+ "Lead with the useful outcome.",
53
+ "Prefer concrete examples and accurate technical language.",
54
+ "Keep product claims specific and defensible.",
55
+ ]),
56
+ avoid: z
57
+ .array(nonBlankString)
58
+ .default(["unsupported superlatives", "vague AI claims", "unnecessary jargon"]),
59
+ })
60
+ .strict()
61
+ .prefault({});
62
+ export const BrandContextSchema = z
63
+ .object({
64
+ schemaVersion: z.literal("1").default("1"),
65
+ name: nonBlankString.default("dbx tools").describe("Canonical display name."),
66
+ shortName: nonBlankString.default("dbx").describe("Compact name for constrained UI."),
67
+ tagline: nonBlankString
68
+ .default("Practical tools for Databricks builders.")
69
+ .describe("Short product line suitable for a header or metadata."),
70
+ description: nonBlankString
71
+ .default("Companion packages for Databricks developers building apps, agents, data workflows, and reusable UI.")
72
+ .describe("Plain-language product description."),
73
+ assets: z
74
+ .object({
75
+ icon: BrandAssetSetSchema.default(DEFAULT_BRAND_ASSETS.icon),
76
+ logo: BrandAssetSetSchema.default(DEFAULT_BRAND_ASSETS.logo),
77
+ favicon: nonBlankString.default(DEFAULT_BRAND_ASSETS.favicon),
78
+ })
79
+ .strict()
80
+ .default(DEFAULT_BRAND_ASSETS),
81
+ colors: BrandColorsSchema,
82
+ typography: z
83
+ .object({
84
+ sans: nonBlankString.default("Inter, ui-sans-serif, system-ui, sans-serif"),
85
+ mono: nonBlankString.default("ui-monospace, SFMono-Regular, Menlo, monospace"),
86
+ })
87
+ .strict()
88
+ .prefault({}),
89
+ voice: BrandVoiceSchema,
90
+ links: z
91
+ .object({
92
+ website: z.string().url().optional(),
93
+ repository: z.string().url().optional(),
94
+ documentation: z.string().url().optional(),
95
+ })
96
+ .strict()
97
+ .default({}),
98
+ extensions: z
99
+ .record(nonBlankString, z.unknown())
100
+ .default({})
101
+ .describe("Namespaced consumer-specific values that do not belong in the portable core."),
102
+ })
103
+ .strict()
104
+ .describe("Portable identity, visual, and voice context for UI, libraries, and LLMs.");
105
+ /** Validate input and fill every dbx tools default. */
106
+ export function parseBrandContext(input = {}) {
107
+ return BrandContextSchema.parse(input);
108
+ }
109
+ export const defaultBrandContext = parseBrandContext();
110
+ /** JSON Schema representation suitable for structured-output and tool definitions. */
111
+ export function brandContextJsonSchema() {
112
+ return z.toJSONSchema(BrandContextSchema);
113
+ }
114
+ /** Stable prompt block for an LLM that needs to write or design in this brand. */
115
+ export function brandContextPrompt(context = defaultBrandContext) {
116
+ return [
117
+ `Use the following ${context.name} brand context for names, visual choices, and writing voice.`,
118
+ "Treat explicit task instructions as higher priority than this context.",
119
+ "",
120
+ JSON.stringify(context, null, 2),
121
+ ].join("\n");
122
+ }
123
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJhbmQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYnJhbmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7R0FPRztBQUNILE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFFeEIsTUFBTSxjQUFjLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNoRCxNQUFNLEtBQUssR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsS0FBSyxDQUFDLDBDQUEwQyxFQUFFLHVCQUF1QixDQUFDLENBQUM7QUFFcEcsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUc7SUFDbEMsSUFBSSxFQUFFO1FBQ0osS0FBSyxFQUFFLDhDQUE4QztRQUNyRCxJQUFJLEVBQUUsNkNBQTZDO0tBQ3BEO0lBQ0QsSUFBSSxFQUFFO1FBQ0osS0FBSyxFQUFFLDhDQUE4QztRQUNyRCxJQUFJLEVBQUUsNkNBQTZDO0tBQ3BEO0lBQ0QsT0FBTyxFQUFFLDhDQUE4QztDQUMvQyxDQUFDO0FBRVgsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQztLQUNqQyxNQUFNLENBQUM7SUFDTixLQUFLLEVBQUUsY0FBYyxDQUFDLFFBQVEsQ0FBQywyQkFBMkIsQ0FBQztJQUMzRCxJQUFJLEVBQUUsY0FBYyxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQyxpREFBaUQsQ0FBQztDQUM1RixDQUFDO0tBQ0QsTUFBTSxFQUFFO0tBQ1IsUUFBUSxDQUFDLDZDQUE2QyxDQUFDLENBQUM7QUFFM0QsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsQ0FBQztLQUMvQixNQUFNLENBQUM7SUFDTixPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxRQUFRLENBQUMsb0NBQW9DLENBQUM7SUFDaEYsWUFBWSxFQUFFLEtBQUssQ0FB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QWtCLENBQTRCLENBQUM7QUFDdkUsQ0FBQztBQUVELGtGQUFrRjtBQUNsRixNQUFNLFVBQVUsa0JBQWtCLENBQUMsVUFBd0IsbUJBQW1CO0lBQzVFLE9BQU87UUFDTCxxQkFBcUIsT0FBTyxDQUFDLElBQUksOERBQThEO1FBQy9GLHdFQUF3RTtRQUN4RSxFQUFFO1FBQ0YsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztLQUNqQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEJyb3dzZXItc2FmZSBicmFuZCBjb250cmFjdCwgZGVmYXVsdHMsIGFuZCBMTE0gc2VyaWFsaXphdGlvbiBoZWxwZXJzLlxuICpcbiAqIEFzc2V0IHZhbHVlcyBhcmUgaW50ZW50aW9uYWxseSBzdHJpbmdzOiB0aGV5IG1heSBiZSByZWxhdGl2ZSBmaWxlIHBhdGhzLFxuICogcGFja2FnZSBleHBvcnRzLCBkYXRhIFVSTHMsIG9yIG5ldHdvcmsgVVJMcyBkZXBlbmRpbmcgb24gdGhlIGNvbnN1bWVyLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIjtcblxuY29uc3Qgbm9uQmxhbmtTdHJpbmcgPSB6LnN0cmluZygpLnRyaW0oKS5taW4oMSk7XG5jb25zdCBjb2xvciA9IHouc3RyaW5nKCkucmVnZXgoL14jKD86W1xcZGEtZl17M318W1xcZGEtZl17Nn18W1xcZGEtZl17OH0pJC9pLCBcIkV4cGVjdGVkIGEgaGV4IGNvbG9yLlwiKTtcblxuZXhwb3J0IGNvbnN0IERFRkFVTFRfQlJBTkRfQVNTRVRTID0ge1xuICBpY29uOiB7XG4gICAgbGlnaHQ6IFwiQGRieC10b29scy91aS1icmFuZGluZy9hc3NldHMvaWNvbi1saWdodC5zdmdcIixcbiAgICBkYXJrOiBcIkBkYngtdG9vbHMvdWktYnJhbmRpbmcvYXNzZXRzL2ljb24tZGFyay5zdmdcIixcbiAgfSxcbiAgbG9nbzoge1xuICAgIGxpZ2h0OiBcIkBkYngtdG9vbHMvdWktYnJhbmRpbmcvYXNzZXRzL2xvZ28tbGlnaHQuc3ZnXCIsXG4gICAgZGFyazogXCJAZGJ4LXRvb2xzL3VpLWJyYW5kaW5nL2Fzc2V0cy9sb2dvLWRhcmsuc3ZnXCIsXG4gIH0sXG4gIGZhdmljb246IFwiQGRieC10b29scy91aS1icmFuZGluZy9hc3NldHMvaWNvbi1saWdodC5zdmdcIixcbn0gYXMgY29uc3Q7XG5cbmV4cG9ydCBjb25zdCBCcmFuZEFzc2V0U2V0U2NoZW1hID0gelxuICAub2JqZWN0KHtcbiAgICBsaWdodDogbm9uQmxhbmtTdHJpbmcuZGVzY3JpYmUoXCJBc3NldCBmb3IgbGlnaHQgc3VyZmFjZXMuXCIpLFxuICAgIGRhcms6IG5vbkJsYW5rU3RyaW5nLm9wdGlvbmFsKCkuZGVzY3JpYmUoXCJBc3NldCBmb3IgZGFyayBzdXJmYWNlczsgbGlnaHQgaXMgdGhlIGZhbGxiYWNrLlwiKSxcbiAgfSlcbiAgLnN0cmljdCgpXG4gIC5kZXNjcmliZShcIlRoZW1lLWF3YXJlIHJlZmVyZW5jZXMgdG8gb25lIHZpc3VhbCBhc3NldC5cIik7XG5cbmV4cG9ydCBjb25zdCBCcmFuZENvbG9yc1NjaGVtYSA9IHpcbiAgLm9iamVjdCh7XG4gICAgcHJpbWFyeTogY29sb3IuZGVmYXVsdChcIiNGRjM2MjFcIikuZGVzY3JpYmUoXCJQcmltYXJ5IGFjdGlvbiBhbmQgaWRlbnRpdHkgY29sb3IuXCIpLFxuICAgIHByaW1hcnlIb3ZlcjogY29sb3IuZGVmYXVsdChcIiNEOTJEMThcIikuZGVzY3JpYmUoXCJQcmltYXJ5IGhvdmVyIG9yIHByZXNzZWQgY29sb3IuXCIpLFxuICAgIGFjY2VudDogY29sb3IuZGVmYXVsdChcIiMyRUI4OEFcIikuZGVzY3JpYmUoXCJTZWNvbmRhcnkgYWNjZW50IGNvbG9yLlwiKSxcbiAgICBmb3JlZ3JvdW5kOiBjb2xvci5kZWZhdWx0KFwiIzBCMjAyNlwiKS5kZXNjcmliZShcIkRlZmF1bHQgdGV4dCBhbmQgbWFyayBjb2xvci5cIiksXG4gICAgYmFja2dyb3VuZDogY29sb3IuZGVmYXVsdChcIiNGRkZGRkZcIikuZGVzY3JpYmUoXCJEZWZhdWx0IHBhZ2UgYmFja2dyb3VuZC5cIiksXG4gICAgc3VyZmFjZTogY29sb3IuZGVmYXVsdChcIiNGNkY3RjhcIikuZGVzY3JpYmUoXCJTZWNvbmRhcnkgc3VyZmFjZSBiYWNrZ3JvdW5kLlwiKSxcbiAgICBtdXRlZDogY29sb3IuZGVmYXVsdChcIiM1RjZCNzBcIikuZGVzY3JpYmUoXCJNdXRlZCB0ZXh0IGNvbG9yLlwiKSxcbiAgICBib3JkZXI6IGNvbG9yLmRlZmF1bHQoXCIjRENFMkU1XCIpLmRlc2NyaWJlKFwiRGVmYXVsdCBib3JkZXIgY29sb3IuXCIpLFxuICB9KVxuICAuc3RyaWN0KClcbiAgLnByZWZhdWx0KHt9KTtcblxuZXhwb3J0IGNvbnN0IEJyYW5kVm9pY2VTY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIGF1ZGllbmNlOiB6XG4gICAgICAuYXJyYXkobm9uQmxhbmtTdHJpbmcpXG4gICAgICAuZGVmYXVsdChbXCJEYXRhYnJpY2tzIGRldmVsb3BlcnNcIiwgXCJhcHBsaWNhdGlvbiBlbmdpbmVlcnNcIiwgXCJBSSBhZ2VudHNcIl0pLFxuICAgIHRvbmU6IHouYXJyYXkobm9uQmxhbmtTdHJpbmcpLmRlZmF1bHQoW1wiZGlyZWN0XCIsIFwicHJhY3RpY2FsXCIsIFwidGVjaG5pY2FsXCIsIFwiYXBwcm9hY2hhYmxlXCJdKSxcbiAgICBwcmluY2lwbGVzOiB6XG4gICAgICAuYXJyYXkobm9uQmxhbmtTdHJpbmcpXG4gICAgICAuZGVmYXVsdChbXG4gICAgICAgIFwiTGVhZCB3aXRoIHRoZSB1c2VmdWwgb3V0Y29tZS5cIixcbiAgICAgICAgXCJQcmVmZXIgY29uY3JldGUgZXhhbXBsZXMgYW5kIGFjY3VyYXRlIHRlY2huaWNhbCBsYW5ndWFnZS5cIixcbiAgICAgICAgXCJLZWVwIHByb2R1Y3QgY2xhaW1zIHNwZWNpZmljIGFuZCBkZWZlbnNpYmxlLlwiLFxuICAgICAgXSksXG4gICAgYXZvaWQ6IHpcbiAgICAgIC5hcnJheShub25CbGFua1N0cmluZylcbiAgICAgIC5kZWZhdWx0KFtcInVuc3VwcG9ydGVkIHN1cGVybGF0aXZlc1wiLCBcInZhZ3VlIEFJIGNsYWltc1wiLCBcInVubmVjZXNzYXJ5IGphcmdvblwiXSksXG4gIH0pXG4gIC5zdHJpY3QoKVxuICAucHJlZmF1bHQoe30pO1xuXG5leHBvcnQgY29uc3QgQnJhbmRDb250ZXh0U2NoZW1hID0gelxuICAub2JqZWN0KHtcbiAgICBzY2hlbWFWZXJzaW9uOiB6LmxpdGVyYWwoXCIxXCIpLmRlZmF1bHQoXCIxXCIpLFxuICAgIG5hbWU6IG5vbkJsYW5rU3RyaW5nLmRlZmF1bHQoXCJkYnggdG9vbHNcIikuZGVzY3JpYmUoXCJDYW5vbmljYWwgZGlzcGxheSBuYW1lLlwiKSxcbiAgICBzaG9ydE5hbWU6IG5vbkJsYW5rU3RyaW5nLmRlZmF1bHQoXCJkYnhcIikuZGVzY3JpYmUoXCJDb21wYWN0IG5hbWUgZm9yIGNvbnN0cmFpbmVkIFVJLlwiKSxcbiAgICB0YWdsaW5lOiBub25CbGFua1N0cmluZ1xuICAgICAgLmRlZmF1bHQoXCJQcmFjdGljYWwgdG9vbHMgZm9yIERhdGFicmlja3MgYnVpbGRlcnMuXCIpXG4gICAgICAuZGVzY3JpYmUoXCJTaG9ydCBwcm9kdWN0IGxpbmUgc3VpdGFibGUgZm9yIGEgaGVhZGVyIG9yIG1ldGFkYXRhLlwiKSxcbiAgICBkZXNjcmlwdGlvbjogbm9uQmxhbmtTdHJpbmdcbiAgICAgIC5kZWZhdWx0KFxuICAgICAgICBcIkNvbXBhbmlvbiBwYWNrYWdlcyBmb3IgRGF0YWJyaWNrcyBkZXZlbG9wZXJzIGJ1aWxkaW5nIGFwcHMsIGFnZW50cywgZGF0YSB3b3JrZmxvd3MsIGFuZCByZXVzYWJsZSBVSS5cIixcbiAgICAgIClcbiAgICAgIC5kZXNjcmliZShcIlBsYWluLWxhbmd1YWdlIHByb2R1Y3QgZGVzY3JpcHRpb24uXCIpLFxuICAgIGFzc2V0czogelxuICAgICAgLm9iamVjdCh7XG4gICAgICAgIGljb246IEJyYW5kQXNzZXRTZXRTY2hlbWEuZGVmYXVsdChERUZBVUxUX0JSQU5EX0FTU0VUUy5pY29uKSxcbiAgICAgICAgbG9nbzogQnJhbmRBc3NldFNldFNjaGVtYS5kZWZhdWx0KERFRkFVTFRfQlJBTkRfQVNTRVRTLmxvZ28pLFxuICAgICAgICBmYXZpY29uOiBub25CbGFua1N0cmluZy5kZWZhdWx0KERFRkFVTFRfQlJBTkRfQVNTRVRTLmZhdmljb24pLFxuICAgICAgfSlcbiAgICAgIC5zdHJpY3QoKVxuICAgICAgLmRlZmF1bHQoREVGQVVMVF9CUkFORF9BU1NFVFMpLFxuICAgIGNvbG9yczogQnJhbmRDb2xvcnNTY2hlbWEsXG4gICAgdHlwb2dyYXBoeTogelxuICAgICAgLm9iamVjdCh7XG4gICAgICAgIHNhbnM6IG5vbkJsYW5rU3RyaW5nLmRlZmF1bHQoXCJJbnRlciwgdWktc2Fucy1zZXJpZiwgc3lzdGVtLXVpLCBzYW5zLXNlcmlmXCIpLFxuICAgICAgICBtb25vOiBub25CbGFua1N0cmluZy5kZWZhdWx0KFwidWktbW9ub3NwYWNlLCBTRk1vbm8tUmVndWxhciwgTWVubG8sIG1vbm9zcGFjZVwiKSxcbiAgICAgIH0pXG4gICAgICAuc3RyaWN0KClcbiAgICAgIC5wcmVmYXVsdCh7fSksXG4gICAgdm9pY2U6IEJyYW5kVm9pY2VTY2hlbWEsXG4gICAgbGlua3M6IHpcbiAgICAgIC5vYmplY3Qoe1xuICAgICAgICB3ZWJzaXRlOiB6LnN0cmluZygpLnVybCgpLm9wdGlvbmFsKCksXG4gICAgICAgIHJlcG9zaXRvcnk6IHouc3RyaW5nKCkudXJsKCkub3B0aW9uYWwoKSxcbiAgICAgICAgZG9jdW1lbnRhdGlvbjogei5zdHJpbmcoKS51cmwoKS5vcHRpb25hbCgpLFxuICAgICAgfSlcbiAgICAgIC5zdHJpY3QoKVxuICAgICAgLmRlZmF1bHQoe30pLFxuICAgIGV4dGVuc2lvbnM6IHpcbiAgICAgIC5yZWNvcmQobm9uQmxhbmtTdHJpbmcsIHoudW5rbm93bigpKVxuICAgICAgLmRlZmF1bHQoe30pXG4gICAgICAuZGVzY3JpYmUoXCJOYW1lc3BhY2VkIGNvbnN1bWVyLXNwZWNpZmljIHZhbHVlcyB0aGF0IGRvIG5vdCBiZWxvbmcgaW4gdGhlIHBvcnRhYmxlIGNvcmUuXCIpLFxuICB9KVxuICAuc3RyaWN0KClcbiAgLmRlc2NyaWJlKFwiUG9ydGFibGUgaWRlbnRpdHksIHZpc3VhbCwgYW5kIHZvaWNlIGNvbnRleHQgZm9yIFVJLCBsaWJyYXJpZXMsIGFuZCBMTE1zLlwiKTtcblxuZXhwb3J0IHR5cGUgQnJhbmRDb250ZXh0ID0gei5vdXRwdXQ8dHlwZW9mIEJyYW5kQ29udGV4dFNjaGVtYT47XG5leHBvcnQgdHlwZSBCcmFuZENvbnRleHRJbnB1dCA9IHouaW5wdXQ8dHlwZW9mIEJyYW5kQ29udGV4dFNjaGVtYT47XG5leHBvcnQgdHlwZSBCcmFuZEFzc2V0U2V0ID0gei5vdXRwdXQ8dHlwZW9mIEJyYW5kQXNzZXRTZXRTY2hlbWE+O1xuXG4vKiogVmFsaWRhdGUgaW5wdXQgYW5kIGZpbGwgZXZlcnkgZGJ4IHRvb2xzIGRlZmF1bHQuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VCcmFuZENvbnRleHQoaW5wdXQ6IHVua25vd24gPSB7fSk6IEJyYW5kQ29udGV4dCB7XG4gIHJldHVybiBCcmFuZENvbnRleHRTY2hlbWEucGFyc2UoaW5wdXQpO1xufVxuXG5leHBvcnQgY29uc3QgZGVmYXVsdEJyYW5kQ29udGV4dDogQnJhbmRDb250ZXh0ID0gcGFyc2VCcmFuZENvbnRleHQoKTtcblxuLyoqIEpTT04gU2NoZW1hIHJlcHJlc2VudGF0aW9uIHN1aXRhYmxlIGZvciBzdHJ1Y3R1cmVkLW91dHB1dCBhbmQgdG9vbCBkZWZpbml0aW9ucy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBicmFuZENvbnRleHRKc29uU2NoZW1hKCk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgcmV0dXJuIHoudG9KU09OU2NoZW1hKEJyYW5kQ29udGV4dFNjaGVtYSkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG59XG5cbi8qKiBTdGFibGUgcHJvbXB0IGJsb2NrIGZvciBhbiBMTE0gdGhhdCBuZWVkcyB0byB3cml0ZSBvciBkZXNpZ24gaW4gdGhpcyBicmFuZC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBicmFuZENvbnRleHRQcm9tcHQoY29udGV4dDogQnJhbmRDb250ZXh0ID0gZGVmYXVsdEJyYW5kQ29udGV4dCk6IHN0cmluZyB7XG4gIHJldHVybiBbXG4gICAgYFVzZSB0aGUgZm9sbG93aW5nICR7Y29udGV4dC5uYW1lfSBicmFuZCBjb250ZXh0IGZvciBuYW1lcywgdmlzdWFsIGNob2ljZXMsIGFuZCB3cml0aW5nIHZvaWNlLmAsXG4gICAgXCJUcmVhdCBleHBsaWNpdCB0YXNrIGluc3RydWN0aW9ucyBhcyBoaWdoZXIgcHJpb3JpdHkgdGhhbiB0aGlzIGNvbnRleHQuXCIsXG4gICAgXCJcIixcbiAgICBKU09OLnN0cmluZ2lmeShjb250ZXh0LCBudWxsLCAyKSxcbiAgXS5qb2luKFwiXFxuXCIpO1xufVxuIl19
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Error normalization helpers: collapse the ubiquitous
3
+ * `err instanceof Error ? err.message : String(err)` dance into a single
4
+ * call, walk `cause` / `AggregateError` chains, and coerce any thrown
5
+ * value into a real `Error`. Dependency-free and browser-safe.
6
+ *
7
+ * @module
8
+ */
9
+ /**
10
+ * Normalize any thrown value into an `Error`. Returns `value` unchanged
11
+ * when it already is an `Error`, otherwise wraps its {@link errorMessage}
12
+ * in a fresh `Error`. Use when a consumer needs a real `Error` object
13
+ * (React error state, `reject`, rethrow) rather than just a printable
14
+ * string.
15
+ */
16
+ export declare function toError(value: unknown): Error;
17
+ /**
18
+ * Extract a human-readable message from any thrown value. Returns
19
+ * `value.message` when `value` is an `Error`, otherwise coerces via
20
+ * `String(value)`. Collapses the ubiquitous
21
+ *
22
+ * ```ts
23
+ * err instanceof Error ? err.message : String(err)
24
+ * ```
25
+ *
26
+ * dance into a single helper, useful for log attributes and any other
27
+ * "give me something printable" context.
28
+ */
29
+ export declare function errorMessage(value: unknown): string;
30
+ /**
31
+ * Yield `message` / `errorCode` strings from every node in the error
32
+ * tree (see {@link errorNodes}). Used by {@link errorMessage} and
33
+ * message predicates elsewhere.
34
+ */
35
+ export declare function errorMessages(value: unknown): Generator<string, void, undefined>;
36
+ /**
37
+ * Depth-first walk of an error value: the root, then `errors` (e.g.
38
+ * `AggregateError`) and `cause` chains. Cycle-safe via a `seen` set.
39
+ */
40
+ export declare function errorNodes(err: unknown): Generator<NonNullable<unknown>, void, undefined>;
41
+ /**
42
+ * Lazy view over a thrown value for HTTP-status + message classification.
43
+ * Status comes from the last positive `statusCode` / `code` on the error tree;
44
+ * messages/tokens come from every `message` / `errorCode` field (including
45
+ * `cause` and `AggregateError.errors`). Build with {@link errorContext}.
46
+ */
47
+ export type ErrorContext = ErrorContextImpl;
48
+ declare class ErrorContextImpl {
49
+ private readonly err;
50
+ private _statusCode;
51
+ private _messages;
52
+ private _messageTokens;
53
+ constructor(err: NonNullable<unknown>);
54
+ /** Last positive `statusCode` / `code` found on the error tree, else `undefined` (0 ignored). */
55
+ get statusCode(): number | undefined;
56
+ /** Every `message` / `errorCode` string in the error tree. */
57
+ get messages(): string[];
58
+ /** Lowercased tokens from {@link messages}. */
59
+ get messageTokens(): string[];
60
+ /** True for any 4xx status or message tokens `not exist` / `not found`. */
61
+ get notAccessible(): boolean;
62
+ /**
63
+ * Match HTTP status. Pass a full code (`404`) or a class (`4` for any 4xx).
64
+ * Extra filters are OR'd. `false` when no status is on the error tree.
65
+ */
66
+ hasStatusCode(statusCodeFilter: number, ...statusCodeFilters: number[]): boolean;
67
+ /**
68
+ * True when every token from the filter phrase(s) appears in
69
+ * {@link messageTokens}. Each argument is tokenized on non-alphanumeric
70
+ * boundaries (e.g. `hasMessage("not", "found")` or `hasMessage("not found")`).
71
+ */
72
+ hasMessage(messageFilter: string, ...messageFilters: string[]): boolean;
73
+ }
74
+ /** Build an {@link ErrorContext} for status + message checks. `null` / `undefined` become `{}`. */
75
+ export declare function errorContext(err: unknown): ErrorContext;
76
+ export {};
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Error normalization helpers: collapse the ubiquitous
3
+ * `err instanceof Error ? err.message : String(err)` dance into a single
4
+ * call, walk `cause` / `AggregateError` chains, and coerce any thrown
5
+ * value into a real `Error`. Dependency-free and browser-safe.
6
+ *
7
+ * @module
8
+ */
9
+ import { tokenizeWithOptions } from "./string.js";
10
+ /**
11
+ * Normalize any thrown value into an `Error`. Returns `value` unchanged
12
+ * when it already is an `Error`, otherwise wraps its {@link errorMessage}
13
+ * in a fresh `Error`. Use when a consumer needs a real `Error` object
14
+ * (React error state, `reject`, rethrow) rather than just a printable
15
+ * string.
16
+ */
17
+ export function toError(value) {
18
+ return value instanceof Error ? value : new Error(errorMessage(value));
19
+ }
20
+ /**
21
+ * Extract a human-readable message from any thrown value. Returns
22
+ * `value.message` when `value` is an `Error`, otherwise coerces via
23
+ * `String(value)`. Collapses the ubiquitous
24
+ *
25
+ * ```ts
26
+ * err instanceof Error ? err.message : String(err)
27
+ * ```
28
+ *
29
+ * dance into a single helper, useful for log attributes and any other
30
+ * "give me something printable" context.
31
+ */
32
+ export function errorMessage(value) {
33
+ const message = errorMessages(value).next().value;
34
+ return message ?? String(value);
35
+ }
36
+ /**
37
+ * Yield `message` / `errorCode` strings from every node in the error
38
+ * tree (see {@link errorNodes}). Used by {@link errorMessage} and
39
+ * message predicates elsewhere.
40
+ */
41
+ export function* errorMessages(value) {
42
+ for (const node of errorNodes(value)) {
43
+ if (typeof node === "object") {
44
+ for (const key of ["message", "errorCode"]) {
45
+ if (key in node) {
46
+ const value = node[key];
47
+ if (typeof value === "string" && value) {
48
+ yield value;
49
+ }
50
+ }
51
+ }
52
+ }
53
+ else if (typeof node === "string" && node) {
54
+ yield node;
55
+ }
56
+ }
57
+ }
58
+ /**
59
+ * Depth-first walk of an error value: the root, then `errors` (e.g.
60
+ * `AggregateError`) and `cause` chains. Cycle-safe via a `seen` set.
61
+ */
62
+ export function* errorNodes(err) {
63
+ const seen = new Set();
64
+ function* visit(node) {
65
+ if (node === undefined || node === null)
66
+ return;
67
+ if (Array.isArray(node)) {
68
+ for (const child of node) {
69
+ yield* visit(child);
70
+ }
71
+ return;
72
+ }
73
+ if (seen.has(node))
74
+ return;
75
+ seen.add(node);
76
+ yield node;
77
+ if (typeof node === "object") {
78
+ for (const key of ["errors", "cause"]) {
79
+ if (key in node) {
80
+ const value = node[key];
81
+ yield* visit(value);
82
+ }
83
+ }
84
+ }
85
+ }
86
+ yield* visit(err);
87
+ }
88
+ class ErrorContextImpl {
89
+ err;
90
+ _statusCode;
91
+ _messages;
92
+ _messageTokens;
93
+ constructor(err) {
94
+ this.err = err;
95
+ }
96
+ /** Last positive `statusCode` / `code` found on the error tree, else `undefined` (0 ignored). */
97
+ get statusCode() {
98
+ if (this._statusCode === undefined) {
99
+ outer: for (const node of errorNodes(this.err)) {
100
+ if (typeof node !== "object" || node === null)
101
+ continue;
102
+ for (const key of ["statusCode", "code"]) {
103
+ if (!(key in node))
104
+ continue;
105
+ const value = node[key];
106
+ if (typeof value === "number" && value > 99 && value < 600) {
107
+ this._statusCode = value;
108
+ break outer;
109
+ }
110
+ }
111
+ }
112
+ if (this._statusCode === undefined) {
113
+ this._statusCode = -1;
114
+ }
115
+ }
116
+ return this._statusCode == -1 ? undefined : this._statusCode;
117
+ }
118
+ /** Every `message` / `errorCode` string in the error tree. */
119
+ get messages() {
120
+ if (this._messages === undefined) {
121
+ this._messages = [...errorMessages(this.err)];
122
+ }
123
+ return this._messages;
124
+ }
125
+ /** Lowercased tokens from {@link messages}. */
126
+ get messageTokens() {
127
+ if (this._messageTokens === undefined) {
128
+ this._messageTokens = [...tokenizeWithOptions({ lowerCase: true }, ...this.messages)];
129
+ }
130
+ return this._messageTokens;
131
+ }
132
+ /** True for any 4xx status or message tokens `not exist` / `not found`. */
133
+ get notAccessible() {
134
+ if (this.hasStatusCode(4))
135
+ return true;
136
+ return this.hasMessage("not", "exist") || this.hasMessage("not", "found");
137
+ }
138
+ /**
139
+ * Match HTTP status. Pass a full code (`404`) or a class (`4` for any 4xx).
140
+ * Extra filters are OR'd. `false` when no status is on the error tree.
141
+ */
142
+ hasStatusCode(statusCodeFilter, ...statusCodeFilters) {
143
+ const code = this.statusCode;
144
+ if (code) {
145
+ for (const filter of [statusCodeFilter, ...statusCodeFilters]) {
146
+ const match = (filter < 100 ? Math.trunc(code / 100) : code) === filter;
147
+ if (match)
148
+ return true;
149
+ }
150
+ }
151
+ return false;
152
+ }
153
+ /**
154
+ * True when every token from the filter phrase(s) appears in
155
+ * {@link messageTokens}. Each argument is tokenized on non-alphanumeric
156
+ * boundaries (e.g. `hasMessage("not", "found")` or `hasMessage("not found")`).
157
+ */
158
+ hasMessage(messageFilter, ...messageFilters) {
159
+ return [messageFilter, ...messageFilters]
160
+ .flatMap((filter) => Array.from(tokenizeWithOptions({ lowerCase: true }, filter)))
161
+ .every((filterToken) => this.messageTokens.includes(filterToken));
162
+ }
163
+ }
164
+ /** Build an {@link ErrorContext} for status + message checks. `null` / `undefined` become `{}`. */
165
+ export function errorContext(err) {
166
+ return new ErrorContextImpl(err ?? {});
167
+ }
168
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZXJyb3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7R0FPRztBQUVILE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUUvQzs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsT0FBTyxDQUFDLEtBQWM7SUFDcEMsT0FBTyxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0FBQ3pFLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7R0FXRztBQUNILE1BQU0sVUFBVSxZQUFZLENBQUMsS0FBYztJQUN6QyxNQUFNLE9BQU8sR0FBRyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsS0FBSyxDQUFDO0lBQ2xELE9BQU8sT0FBTyxJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUNsQyxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sU0FBUyxDQUFDLENBQUMsYUFBYSxDQUFDLEtBQWM7SUFDM0MsS0FBSyxNQUFNLElBQUksSUFBSSxVQUFVLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUNyQyxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzdCLEtBQUssTUFBTSxHQUFHLElBQUksQ0FBQyxTQUFTLEVBQUUsV0FBVyxDQUFDLEVBQUUsQ0FBQztnQkFDM0MsSUFBSSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7b0JBQ2hCLE1BQU0sS0FBSyxHQUFJLElBQWdDLENBQUMsR0FBRyxDQUFDLENBQUM7b0JBQ3JELElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssRUFBRSxDQUFDO3dCQUN2QyxNQUFNLEtBQUssQ0FBQztvQkFDZCxDQUFDO2dCQUNILENBQUM7WUFDSCxD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LENBQUMsSUFBSSxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxNQUFNLENBQUM7Z0JBQ3hFLElBQUksS0FBSztvQkFBRSxPQUFPLElBQUksQ0FBQztZQUN6QixDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxVQUFVLENBQUMsYUFBcUIsRUFBRSxHQUFHLGNBQXdCO1FBQzNELE9BQU8sQ0FBQyxhQUFhLEVBQUUsR0FBRyxjQUFjLENBQUM7YUFDdEMsT0FBTyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7YUFDakYsS0FBSyxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO0lBQ3RFLENBQUM7Q0FDRjtBQUVELG1HQUFtRztBQUNuRyxNQUFNLFVBQVUsWUFBWSxDQUFDLEdBQVk7SUFDdkMsT0FBTyxJQUFJLGdCQUFnQixDQUFDLEdBQUcsSUFBSSxFQUFFLENBQUMsQ0FBQztBQUN6QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBFcnJvciBub3JtYWxpemF0aW9uIGhlbHBlcnM6IGNvbGxhcHNlIHRoZSB1YmlxdWl0b3VzXG4gKiBgZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpYCBkYW5jZSBpbnRvIGEgc2luZ2xlXG4gKiBjYWxsLCB3YWxrIGBjYXVzZWAgLyBgQWdncmVnYXRlRXJyb3JgIGNoYWlucywgYW5kIGNvZXJjZSBhbnkgdGhyb3duXG4gKiB2YWx1ZSBpbnRvIGEgcmVhbCBgRXJyb3JgLiBEZXBlbmRlbmN5LWZyZWUgYW5kIGJyb3dzZXItc2FmZS5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgdG9rZW5pemVXaXRoT3B0aW9ucyB9IGZyb20gXCIuL3N0cmluZ1wiO1xuXG4vKipcbiAqIE5vcm1hbGl6ZSBhbnkgdGhyb3duIHZhbHVlIGludG8gYW4gYEVycm9yYC4gUmV0dXJucyBgdmFsdWVgIHVuY2hhbmdlZFxuICogd2hlbiBpdCBhbHJlYWR5IGlzIGFuIGBFcnJvcmAsIG90aGVyd2lzZSB3cmFwcyBpdHMge0BsaW5rIGVycm9yTWVzc2FnZX1cbiAqIGluIGEgZnJlc2ggYEVycm9yYC4gVXNlIHdoZW4gYSBjb25zdW1lciBuZWVkcyBhIHJlYWwgYEVycm9yYCBvYmplY3RcbiAqIChSZWFjdCBlcnJvciBzdGF0ZSwgYHJlamVjdGAsIHJldGhyb3cpIHJhdGhlciB0aGFuIGp1c3QgYSBwcmludGFibGVcbiAqIHN0cmluZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvRXJyb3IodmFsdWU6IHVua25vd24pOiBFcnJvciB7XG4gIHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIEVycm9yID8gdmFsdWUgOiBuZXcgRXJyb3IoZXJyb3JNZXNzYWdlKHZhbHVlKSk7XG59XG5cbi8qKlxuICogRXh0cmFjdCBhIGh1bWFuLXJlYWRhYmxlIG1lc3NhZ2UgZnJvbSBhbnkgdGhyb3duIHZhbHVlLiBSZXR1cm5zXG4gKiBgdmFsdWUubWVzc2FnZWAgd2hlbiBgdmFsdWVgIGlzIGFuIGBFcnJvcmAsIG90aGVyd2lzZSBjb2VyY2VzIHZpYVxuICogYFN0cmluZyh2YWx1ZSlgLiBDb2xsYXBzZXMgdGhlIHViaXF1aXRvdXNcbiAqXG4gKiBgYGB0c1xuICogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpXG4gKiBgYGBcbiAqXG4gKiBkYW5jZSBpbnRvIGEgc2luZ2xlIGhlbHBlciwgdXNlZnVsIGZvciBsb2cgYXR0cmlidXRlcyBhbmQgYW55IG90aGVyXG4gKiBcImdpdmUgbWUgc29tZXRoaW5nIHByaW50YWJsZVwiIGNvbnRleHQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBlcnJvck1lc3NhZ2UodmFsdWU6IHVua25vd24pOiBzdHJpbmcge1xuICBjb25zdCBtZXNzYWdlID0gZXJyb3JNZXNzYWdlcyh2YWx1ZSkubmV4dCgpLnZhbHVlO1xuICByZXR1cm4gbWVzc2FnZSA/PyBTdHJpbmcodmFsdWUpO1xufVxuXG4vKipcbiAqIFlpZWxkIGBtZXNzYWdlYCAvIGBlcnJvckNvZGVgIHN0cmluZ3MgZnJvbSBldmVyeSBub2RlIGluIHRoZSBlcnJvclxuICogdHJlZSAoc2VlIHtAbGluayBlcnJvck5vZGVzfSkuIFVzZWQgYnkge0BsaW5rIGVycm9yTWVzc2FnZX0gYW5kXG4gKiBtZXNzYWdlIHByZWRpY2F0ZXMgZWxzZXdoZXJlLlxuICovXG5leHBvcnQgZnVuY3Rpb24qIGVycm9yTWVzc2FnZXModmFsdWU6IHVua25vd24pOiBHZW5lcmF0b3I8c3RyaW5nLCB2b2lkLCB1bmRlZmluZWQ+IHtcbiAgZm9yIChjb25zdCBub2RlIG9mIGVycm9yTm9kZXModmFsdWUpKSB7XG4gICAgaWYgKHR5cGVvZiBub2RlID09PSBcIm9iamVjdFwiKSB7XG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBbXCJtZXNzYWdlXCIsIFwiZXJyb3JDb2RlXCJdKSB7XG4gICAgICAgIGlmIChrZXkgaW4gbm9kZSkge1xuICAgICAgICAgIGNvbnN0IHZhbHVlID0gKG5vZGUgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW2tleV07XG4gICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiAmJiB2YWx1ZSkge1xuICAgICAgICAgICAgeWllbGQgdmFsdWU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICh0eXBlb2Ygbm9kZSA9PT0gXCJzdHJpbmdcIiAmJiBub2RlKSB7XG4gICAgICB5aWVsZCBub2RlO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIERlcHRoLWZpcnN0IHdhbGsgb2YgYW4gZXJyb3IgdmFsdWU6IHRoZSByb290LCB0aGVuIGBlcnJvcnNgIChlLmcuXG4gKiBgQWdncmVnYXRlRXJyb3JgKSBhbmQgYGNhdXNlYCBjaGFpbnMuIEN5Y2xlLXNhZmUgdmlhIGEgYHNlZW5gIHNldC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uKiBlcnJvck5vZGVzKGVycjogdW5rbm93bik6IEdlbmVyYXRvcjxOb25OdWxsYWJsZTx1bmtub3duPiwgdm9pZCwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IHNlZW4gPSBuZXcgU2V0PHVua25vd24+KCk7XG5cbiAgZnVuY3Rpb24qIHZpc2l0KG5vZGU6IHVua25vd24pOiBHZW5lcmF0b3I8Tm9uTnVsbGFibGU8dW5rbm93bj4sIHZvaWQsIHVuZGVmaW5lZD4ge1xuICAgIGlmIChub2RlID09PSB1bmRlZmluZWQgfHwgbm9kZSA9PT0gbnVsbCkgcmV0dXJuO1xuICAgIGlmIChBcnJheS5pc0FycmF5KG5vZGUpKSB7XG4gICAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIG5vZGUpIHtcbiAgICAgICAgeWllbGQqIHZpc2l0KGNoaWxkKTtcbiAgICAgIH1cbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHNlZW4uaGFzKG5vZGUpKSByZXR1cm47XG4gICAgc2Vlbi5hZGQobm9kZSk7XG4gICAgeWllbGQgbm9kZTtcbiAgICBpZiAodHlwZW9mIG5vZGUgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIGZvciAoY29uc3Qga2V5IG9mIFtcImVycm9yc1wiLCBcImNhdXNlXCJdKSB7XG4gICAgICAgIGlmIChrZXkgaW4gbm9kZSkge1xuICAgICAgICAgIGNvbnN0IHZhbHVlID0gKG5vZGUgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW2tleV07XG4gICAgICAgICAgeWllbGQqIHZpc2l0KHZhbHVlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuICB5aWVsZCogdmlzaXQoZXJyKTtcbn1cblxuLyoqXG4gKiBMYXp5IHZpZXcgb3ZlciBhIHRocm93biB2YWx1ZSBmb3IgSFRUUC1zdGF0dXMgKyBtZXNzYWdlIGNsYXNzaWZpY2F0aW9uLlxuICogU3RhdHVzIGNvbWVzIGZyb20gdGhlIGxhc3QgcG9zaXRpdmUgYHN0YXR1c0NvZGVgIC8gYGNvZGVgIG9uIHRoZSBlcnJvciB0cmVlO1xuICogbWVzc2FnZXMvdG9rZW5zIGNvbWUgZnJvbSBldmVyeSBgbWVzc2FnZWAgLyBgZXJyb3JDb2RlYCBmaWVsZCAoaW5jbHVkaW5nXG4gKiBgY2F1c2VgIGFuZCBgQWdncmVnYXRlRXJyb3IuZXJyb3JzYCkuIEJ1aWxkIHdpdGgge0BsaW5rIGVycm9yQ29udGV4dH0uXG4gKi9cbmV4cG9ydCB0eXBlIEVycm9yQ29udGV4dCA9IEVycm9yQ29udGV4dEltcGw7XG5cbmNsYXNzIEVycm9yQ29udGV4dEltcGwge1xuICBwcml2YXRlIF9zdGF0dXNDb2RlOiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgX21lc3NhZ2VzOiBzdHJpbmdbXSB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBfbWVzc2FnZVRva2Vuczogc3RyaW5nW10gfCB1bmRlZmluZWQ7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBlcnI6IE5vbk51bGxhYmxlPHVua25vd24+KSB7fVxuXG4gIC8qKiBMYXN0IHBvc2l0aXZlIGBzdGF0dXNDb2RlYCAvIGBjb2RlYCBmb3VuZCBvbiB0aGUgZXJyb3IgdHJlZSwgZWxzZSBgdW5kZWZpbmVkYCAoMCBpZ25vcmVkKS4gKi9cbiAgZ2V0IHN0YXR1c0NvZGUoKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAodGhpcy5fc3RhdHVzQ29kZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBvdXRlcjogZm9yIChjb25zdCBub2RlIG9mIGVycm9yTm9kZXModGhpcy5lcnIpKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygbm9kZSAhPT0gXCJvYmplY3RcIiB8fCBub2RlID09PSBudWxsKSBjb250aW51ZTtcbiAgICAgICAgZm9yIChjb25zdCBrZXkgb2YgW1wic3RhdHVzQ29kZVwiLCBcImNvZGVcIl0gYXMgY29uc3QpIHtcbiAgICAgICAgICBpZiAoIShrZXkgaW4gbm9kZSkpIGNvbnRpbnVlO1xuICAgICAgICAgIGNvbnN0IHZhbHVlID0gKG5vZGUgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW2tleV07XG4gICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJudW1iZXJcIiAmJiB2YWx1ZSA+IDk5ICYmIHZhbHVlIDwgNjAwKSB7XG4gICAgICAgICAgICB0aGlzLl9zdGF0dXNDb2RlID0gdmFsdWU7XG4gICAgICAgICAgICBicmVhayBvdXRlcjtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmICh0aGlzLl9zdGF0dXNDb2RlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5fc3RhdHVzQ29kZSA9IC0xO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fc3RhdHVzQ29kZSA9PSAtMSA/IHVuZGVmaW5lZCA6IHRoaXMuX3N0YXR1c0NvZGU7XG4gIH1cblxuICAvKiogRXZlcnkgYG1lc3NhZ2VgIC8gYGVycm9yQ29kZWAgc3RyaW5nIGluIHRoZSBlcnJvciB0cmVlLiAqL1xuICBnZXQgbWVzc2FnZXMoKTogc3RyaW5nW10ge1xuICAgIGlmICh0aGlzLl9tZXNzYWdlcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLl9tZXNzYWdlcyA9IFsuLi5lcnJvck1lc3NhZ2VzKHRoaXMuZXJyKV07XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9tZXNzYWdlcztcbiAgfVxuXG4gIC8qKiBMb3dlcmNhc2VkIHRva2VucyBmcm9tIHtAbGluayBtZXNzYWdlc30uICovXG4gIGdldCBtZXNzYWdlVG9rZW5zKCk6IHN0cmluZ1tdIHtcbiAgICBpZiAodGhpcy5fbWVzc2FnZVRva2VucyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLl9tZXNzYWdlVG9rZW5zID0gWy4uLnRva2VuaXplV2l0aE9wdGlvbnMoeyBsb3dlckNhc2U6IHRydWUgfSwgLi4udGhpcy5tZXNzYWdlcyldO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fbWVzc2FnZVRva2VucztcbiAgfVxuXG4gIC8qKiBUcnVlIGZvciBhbnkgNHh4IHN0YXR1cyBvciBtZXNzYWdlIHRva2VucyBgbm90IGV4aXN0YCAvIGBub3QgZm91bmRgLiAqL1xuICBnZXQgbm90QWNjZXNzaWJsZSgpOiBib29sZWFuIHtcbiAgICBpZiAodGhpcy5oYXNTdGF0dXNDb2RlKDQpKSByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gdGhpcy5oYXNNZXNzYWdlKFwibm90XCIsIFwiZXhpc3RcIikgfHwgdGhpcy5oYXNNZXNzYWdlKFwibm90XCIsIFwiZm91bmRcIik7XG4gIH1cblxuICAvKipcbiAgICogTWF0Y2ggSFRUUCBzdGF0dXMuIFBhc3MgYSBmdWxsIGNvZGUgKGA0MDRgKSBvciBhIGNsYXNzIChgNGAgZm9yIGFueSA0eHgpLlxuICAgKiBFeHRyYSBmaWx0ZXJzIGFyZSBPUidkLiBgZmFsc2VgIHdoZW4gbm8gc3RhdHVzIGlzIG9uIHRoZSBlcnJvciB0cmVlLlxuICAgKi9cbiAgaGFzU3RhdHVzQ29kZShzdGF0dXNDb2RlRmlsdGVyOiBudW1iZXIsIC4uLnN0YXR1c0NvZGVGaWx0ZXJzOiBudW1iZXJbXSk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGNvZGUgPSB0aGlzLnN0YXR1c0NvZGU7XG4gICAgaWYgKGNvZGUpIHtcbiAgICAgIGZvciAoY29uc3QgZmlsdGVyIG9mIFtzdGF0dXNDb2RlRmlsdGVyLCAuLi5zdGF0dXNDb2RlRmlsdGVyc10pIHtcbiAgICAgICAgY29uc3QgbWF0Y2ggPSAoZmlsdGVyIDwgMTAwID8gTWF0aC50cnVuYyhjb2RlIC8gMTAwKSA6IGNvZGUpID09PSBmaWx0ZXI7XG4gICAgICAgIGlmIChtYXRjaCkgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcnVlIHdoZW4gZXZlcnkgdG9rZW4gZnJvbSB0aGUgZmlsdGVyIHBocmFzZShzKSBhcHBlYXJzIGluXG4gICAqIHtAbGluayBtZXNzYWdlVG9rZW5zfS4gRWFjaCBhcmd1bWVudCBpcyB0b2tlbml6ZWQgb24gbm9uLWFscGhhbnVtZXJpY1xuICAgKiBib3VuZGFyaWVzIChlLmcuIGBoYXNNZXNzYWdlKFwibm90XCIsIFwiZm91bmRcIilgIG9yIGBoYXNNZXNzYWdlKFwibm90IGZvdW5kXCIpYCkuXG4gICAqL1xuICBoYXNNZXNzYWdlKG1lc3NhZ2VGaWx0ZXI6IHN0cmluZywgLi4ubWVzc2FnZUZpbHRlcnM6IHN0cmluZ1tdKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIFttZXNzYWdlRmlsdGVyLCAuLi5tZXNzYWdlRmlsdGVyc11cbiAgICAgIC5mbGF0TWFwKChmaWx0ZXIpID0+IEFycmF5LmZyb20odG9rZW5pemVXaXRoT3B0aW9ucyh7IGxvd2VyQ2FzZTogdHJ1ZSB9LCBmaWx0ZXIpKSlcbiAgICAgIC5ldmVyeSgoZmlsdGVyVG9rZW4pID0+IHRoaXMubWVzc2FnZVRva2Vucy5pbmNsdWRlcyhmaWx0ZXJUb2tlbikpO1xuICB9XG59XG5cbi8qKiBCdWlsZCBhbiB7QGxpbmsgRXJyb3JDb250ZXh0fSBmb3Igc3RhdHVzICsgbWVzc2FnZSBjaGVja3MuIGBudWxsYCAvIGB1bmRlZmluZWRgIGJlY29tZSBge31gLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVycm9yQ29udGV4dChlcnI6IHVua25vd24pOiBFcnJvckNvbnRleHQge1xuICByZXR1cm4gbmV3IEVycm9yQ29udGV4dEltcGwoZXJyID8/IHt9KTtcbn1cbiJdfQ==
@@ -0,0 +1,38 @@
1
+ export interface MemoizeOptions {
2
+ /**
3
+ * Time-to-live in milliseconds. The cached value expires `ttlMs` after
4
+ * it was stored, so the next call past that recomputes; a rejection is
5
+ * also evicted so a later call retries rather than replaying the error.
6
+ * Omitted or `<= 0` means a successful value is cached forever (the default).
7
+ * Errors are never cached - see {@link memoize}.
8
+ *
9
+ * Use for periodically-refreshed data (published IP ranges, feature
10
+ * flags, anything fetched once and reused across requests).
11
+ */
12
+ ttlMs?: number;
13
+ }
14
+ /**
15
+ * Run a zero-argument factory once; later calls return the same result.
16
+ * The memoized function mirrors the factory's sync / async nature: a
17
+ * sync factory yields a sync getter (`() => T`), an async / thenable
18
+ * factory yields a promise-returning getter (`() => Promise<T>`) whose
19
+ * concurrent callers share the one in-flight promise until it settles.
20
+ *
21
+ * Errors are never cached: a sync factory that throws propagates the
22
+ * throw, and an async factory that rejects evicts the cached promise, so
23
+ * in both cases the next call retries. Pass `{ ttlMs }` to also expire
24
+ * and recompute a successful value after a window; without a TTL a
25
+ * success is cached forever.
26
+ *
27
+ * For an async factory the TTL window starts when the promise
28
+ * *resolves*, not when it was created - a slow in-flight request never
29
+ * counts as already-expired, and concurrent callers keep sharing the one
30
+ * pending promise until it settles.
31
+ *
32
+ * @example
33
+ * const ranges = functionModule.memoize(fetchIpRanges, { ttlMs: 24 * 60 * 60 * 1000 });
34
+ * await ranges(); // fetches
35
+ * await ranges(); // cached until 24h later
36
+ */
37
+ export declare function memoize<T>(factory: () => PromiseLike<T>, options?: MemoizeOptions): () => Promise<T>;
38
+ export declare function memoize<T>(factory: () => T, options?: MemoizeOptions): () => T;
@@ -0,0 +1,44 @@
1
+ export function memoize(factory, options) {
2
+ const ttlMs = options?.ttlMs ?? 0;
3
+ let cache;
4
+ return () => {
5
+ if (cache === undefined || (ttlMs > 0 && Date.now() >= cache.expiresAt)) {
6
+ const result = factory();
7
+ if (isThenable(result)) {
8
+ const pending = Promise.resolve(result);
9
+ // `Infinity` keeps the entry unexpired while in flight (so a slow
10
+ // request isn't refetched and concurrent callers share it); the
11
+ // TTL window is stamped from resolution below.
12
+ const entry = { value: pending, expiresAt: Infinity };
13
+ cache = entry;
14
+ void pending.then(() => {
15
+ entry.expiresAt = Date.now() + ttlMs;
16
+ },
17
+ // Never cache a rejection: evict so a later call retries.
18
+ () => {
19
+ if (cache === entry)
20
+ cache = undefined;
21
+ });
22
+ }
23
+ else {
24
+ cache = { value: result, expiresAt: Date.now() + ttlMs };
25
+ }
26
+ }
27
+ return cache.value;
28
+ };
29
+ }
30
+ /** Duck-type any value with a callable `.then` as a thenable. */
31
+ function isThenable(value) {
32
+ if (value !== null) {
33
+ if (value instanceof Promise) {
34
+ return true;
35
+ }
36
+ else if (typeof value === "object" &&
37
+ "then" in value &&
38
+ typeof value.then === "function") {
39
+ return true;
40
+ }
41
+ }
42
+ return false;
43
+ }
44
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnVuY3Rpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZnVuY3Rpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBMkNBLE1BQU0sVUFBVSxPQUFPLENBQ3JCLE9BQWlDLEVBQ2pDLE9BQXdCO0lBRXhCLE1BQU0sS0FBSyxHQUFHLE9BQU8sRUFBRSxLQUFLLElBQUksQ0FBQyxDQUFDO0lBQ2xDLElBQUksS0FBK0QsQ0FBQztJQUNwRSxPQUFPLEdBQUcsRUFBRTtRQUNWLElBQUksS0FBSyxLQUFLLFNBQVMsSUFBSSxDQUFDLEtBQUssR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLEtBQUssQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1lBQ3hFLE1BQU0sTUFBTSxHQUFHLE9BQU8sRUFBRSxDQUFDO1lBQ3pCLElBQUksVUFBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7Z0JBQ3ZCLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ3hDLGtFQUFrRTtnQkFDbEUsZ0VBQWdFO2dCQUNoRSwrQ0FBK0M7Z0JBQy9DLE1BQU0sS0FBSyxHQUFHLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLENBQUM7Z0JBQ3RELEtBQUssR0FBRyxLQUFLLENBQUM7Z0JBQ2QsS0FBSyxPQUFPLENBQUMsSUFBSSxDQUNmLEdBQUcsRUFBRTtvQkFDSCxLQUFLLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxLQUFLLENBQUM7Z0JBQ3ZDLENBQUM7Z0JBQ0QsMERBQTBEO2dCQUMxRCxHQUFHLEVBQUU7b0JBQ0gsSUFBSSxLQUFLLEtBQUssS0FBSzt3QkFBRSxLQUFLLEdBQUcsU0FBUyxDQUFDO2dCQUN6QyxDQUFDLENBQ0YsQ0FBQztZQUNKLENBQUM7aUJBQU0sQ0FBQztnQkFDTixLQUFLLEdBQUcsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsS0FBSyxFQUFFLENBQUM7WUFDM0QsQ0FBQztRQUNILENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQyxLQUFLLENBQUM7SUFDckIsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVELGlFQUFpRTtBQUNqRSxTQUFTLFVBQVUsQ0FBSSxLQUF5QjtJQUM5QyxJQUFJLEtBQUssS0FBSyxJQUFJLEVBQUUsQ0FBQztRQUNuQixJQUFJLEtBQUssWUFBWSxPQUFPLEVBQUUsQ0FBQztZQUM3QixPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7YUFBTSxJQUNMLE9BQU8sS0FBSyxLQUFLLFFBQVE7WUFDekIsTUFBTSxJQUFJLEtBQUs7WUFDZixPQUFRLEtBQXdCLENBQUMsSUFBSSxLQUFLLFVBQVUsRUFDcEQsQ0FBQztZQUNELE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgaW50ZXJmYWNlIE1lbW9pemVPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRpbWUtdG8tbGl2ZSBpbiBtaWxsaXNlY29uZHMuIFRoZSBjYWNoZWQgdmFsdWUgZXhwaXJlcyBgdHRsTXNgIGFmdGVyXG4gICAqIGl0IHdhcyBzdG9yZWQsIHNvIHRoZSBuZXh0IGNhbGwgcGFzdCB0aGF0IHJlY29tcHV0ZXM7IGEgcmVqZWN0aW9uIGlzXG4gICAqIGFsc28gZXZpY3RlZCBzbyBhIGxhdGVyIGNhbGwgcmV0cmllcyByYXRoZXIgdGhhbiByZXBsYXlpbmcgdGhlIGVycm9yLlxuICAgKiBPbWl0dGVkIG9yIGA8PSAwYCBtZWFucyBhIHN1Y2Nlc3NmdWwgdmFsdWUgaXMgY2FjaGVkIGZvcmV2ZXIgKHRoZSBkZWZhdWx0KS5cbiAgICogRXJyb3JzIGFyZSBuZXZlciBjYWNoZWQgLSBzZWUge0BsaW5rIG1lbW9pemV9LlxuICAgKlxuICAgKiBVc2UgZm9yIHBlcmlvZGljYWxseS1yZWZyZXNoZWQgZGF0YSAocHVibGlzaGVkIElQIHJhbmdlcywgZmVhdHVyZVxuICAgKiBmbGFncywgYW55dGhpbmcgZmV0Y2hlZCBvbmNlIGFuZCByZXVzZWQgYWNyb3NzIHJlcXVlc3RzKS5cbiAgICovXG4gIHR0bE1zPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIFJ1biBhIHplcm8tYXJndW1lbnQgZmFjdG9yeSBvbmNlOyBsYXRlciBjYWxscyByZXR1cm4gdGhlIHNhbWUgcmVzdWx0LlxuICogVGhlIG1lbW9pemVkIGZ1bmN0aW9uIG1pcnJvcnMgdGhlIGZhY3RvcnkncyBzeW5jIC8gYXN5bmMgbmF0dXJlOiBhXG4gKiBzeW5jIGZhY3RvcnkgeWllbGRzIGEgc3luYyBnZXR0ZXIgKGAoKSA9PiBUYCksIGFuIGFzeW5jIC8gdGhlbmFibGVcbiAqIGZhY3RvcnkgeWllbGRzIGEgcHJvbWlzZS1yZXR1cm5pbmcgZ2V0dGVyIChgKCkgPT4gUHJvbWlzZTxUPmApIHdob3NlXG4gKiBjb25jdXJyZW50IGNhbGxlcnMgc2hhcmUgdGhlIG9uZSBpbi1mbGlnaHQgcHJvbWlzZSB1bnRpbCBpdCBzZXR0bGVzLlxuICpcbiAqIEVycm9ycyBhcmUgbmV2ZXIgY2FjaGVkOiBhIHN5bmMgZmFjdG9yeSB0aGF0IHRocm93cyBwcm9wYWdhdGVzIHRoZVxuICogdGhyb3csIGFuZCBhbiBhc3luYyBmYWN0b3J5IHRoYXQgcmVqZWN0cyBldmljdHMgdGhlIGNhY2hlZCBwcm9taXNlLCBzb1xuICogaW4gYm90aCBjYXNlcyB0aGUgbmV4dCBjYWxsIHJldHJpZXMuIFBhc3MgYHsgdHRsTXMgfWAgdG8gYWxzbyBleHBpcmVcbiAqIGFuZCByZWNvbXB1dGUgYSBzdWNjZXNzZnVsIHZhbHVlIGFmdGVyIGEgd2luZG93OyB3aXRob3V0IGEgVFRMIGFcbiAqIHN1Y2Nlc3MgaXMgY2FjaGVkIGZvcmV2ZXIuXG4gKlxuICogRm9yIGFuIGFzeW5jIGZhY3RvcnkgdGhlIFRUTCB3aW5kb3cgc3RhcnRzIHdoZW4gdGhlIHByb21pc2VcbiAqICpyZXNvbHZlcyosIG5vdCB3aGVuIGl0IHdhcyBjcmVhdGVkIC0gYSBzbG93IGluLWZsaWdodCByZXF1ZXN0IG5ldmVyXG4gKiBjb3VudHMgYXMgYWxyZWFkeS1leHBpcmVkLCBhbmQgY29uY3VycmVudCBjYWxsZXJzIGtlZXAgc2hhcmluZyB0aGUgb25lXG4gKiBwZW5kaW5nIHByb21pc2UgdW50aWwgaXQgc2V0dGxlcy5cbiAqXG4gKiBAZXhhbXBsZVxuICogY29uc3QgcmFuZ2VzID0gZnVuY3Rpb25Nb2R1bGUubWVtb2l6ZShmZXRjaElwUmFuZ2VzLCB7IHR0bE1zOiAyNCAqIDYwICogNjAgKiAxMDAwIH0pO1xuICogYXdhaXQgcmFuZ2VzKCk7IC8vIGZldGNoZXNcbiAqIGF3YWl0IHJhbmdlcygpOyAvLyBjYWNoZWQgdW50aWwgMjRoIGxhdGVyXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZW1vaXplPFQ+KFxuICBmYWN0b3J5OiAoKSA9PiBQcm9taXNlTGlrZTxUPixcbiAgb3B0aW9ucz86IE1lbW9pemVPcHRpb25zLFxuKTogKCkgPT4gUHJvbWlzZTxUPjtcbmV4cG9ydCBmdW5jdGlvbiBtZW1vaXplPFQ+KGZhY3Rvcnk6ICgpID0+IFQsIG9wdGlvbnM/OiBNZW1vaXplT3B0aW9ucyk6ICgpID0+IFQ7XG5cbmV4cG9ydCBmdW5jdGlvbiBtZW1vaXplPFQ+KFxuICBmYWN0b3J5OiAoKSA9PiBUIHwgUHJvbWlzZUxpa2U8VD4sXG4gIG9wdGlvbnM/OiBNZW1vaXplT3B0aW9ucyxcbik6ICgpID0+IFQgfCBQcm9taXNlPFQ+IHtcbiAgY29uc3QgdHRsTXMgPSBvcHRpb25zPy50dGxNcyA/PyAwO1xuICBsZXQgY2FjaGU6IHsgdmFsdWU6IFQgfCBQcm9taXNlPFQ+OyBleHBpcmVzQXQ6IG51bWJlciB9IHwgdW5kZWZpbmVkO1xuICByZXR1cm4gKCkgPT4ge1xuICAgIGlmIChjYWNoZSA9PT0gdW5kZWZpbmVkIHx8ICh0dGxNcyA+IDAgJiYgRGF0ZS5ub3coKSA+PSBjYWNoZS5leHBpcmVzQXQpKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBmYWN0b3J5KCk7XG4gICAgICBpZiAoaXNUaGVuYWJsZShyZXN1bHQpKSB7XG4gICAgICAgIGNvbnN0IHBlbmRpbmcgPSBQcm9taXNlLnJlc29sdmUocmVzdWx0KTtcbiAgICAgICAgLy8gYEluZmluaXR5YCBrZWVwcyB0aGUgZW50cnkgdW5leHBpcmVkIHdoaWxlIGluIGZsaWdodCAoc28gYSBzbG93XG4gICAgICAgIC8vIHJlcXVlc3QgaXNuJ3QgcmVmZXRjaGVkIGFuZCBjb25jdXJyZW50IGNhbGxlcnMgc2hhcmUgaXQpOyB0aGVcbiAgICAgICAgLy8gVFRMIHdpbmRvdyBpcyBzdGFtcGVkIGZyb20gcmVzb2x1dGlvbiBiZWxvdy5cbiAgICAgICAgY29uc3QgZW50cnkgPSB7IHZhbHVlOiBwZW5kaW5nLCBleHBpcmVzQXQ6IEluZmluaXR5IH07XG4gICAgICAgIGNhY2hlID0gZW50cnk7XG4gICAgICAgIHZvaWQgcGVuZGluZy50aGVuKFxuICAgICAgICAgICgpID0+IHtcbiAgICAgICAgICAgIGVudHJ5LmV4cGlyZXNBdCA9IERhdGUubm93KCkgKyB0dGxNcztcbiAgICAgICAgICB9LFxuICAgICAgICAgIC8vIE5ldmVyIGNhY2hlIGEgcmVqZWN0aW9uOiBldmljdCBzbyBhIGxhdGVyIGNhbGwgcmV0cmllcy5cbiAgICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgICBpZiAoY2FjaGUgPT09IGVudHJ5KSBjYWNoZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICB9LFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY2FjaGUgPSB7IHZhbHVlOiByZXN1bHQsIGV4cGlyZXNBdDogRGF0ZS5ub3coKSArIHR0bE1zIH07XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjYWNoZS52YWx1ZTtcbiAgfTtcbn1cblxuLyoqIER1Y2stdHlwZSBhbnkgdmFsdWUgd2l0aCBhIGNhbGxhYmxlIGAudGhlbmAgYXMgYSB0aGVuYWJsZS4gKi9cbmZ1bmN0aW9uIGlzVGhlbmFibGU8VD4odmFsdWU6IFQgfCBQcm9taXNlTGlrZTxUPik6IHZhbHVlIGlzIFByb21pc2VMaWtlPFQ+IHtcbiAgaWYgKHZhbHVlICE9PSBudWxsKSB7XG4gICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgUHJvbWlzZSkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBlbHNlIGlmIChcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgXCJ0aGVuXCIgaW4gdmFsdWUgJiZcbiAgICAgIHR5cGVvZiAodmFsdWUgYXMgUHJvbWlzZUxpa2U8VD4pLnRoZW4gPT09IFwiZnVuY3Rpb25cIlxuICAgICkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cbiJdfQ==
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Short, deterministic non-cryptographic hashing and id minting.
3
+ *
4
+ * {@link fnvHash} / {@link fnvHashWithOptions} produce a stable FNV-1a
5
+ * digest over arbitrary structured input; {@link toBase32} encodes a
6
+ * 32-bit integer compactly; {@link id} mints v4 UUIDs (or short hex
7
+ * slices). All browser-safe - built on `globalThis.crypto`, no
8
+ * `node:crypto` import. **Never** use these for tokens, signatures, or
9
+ * anything an attacker shouldn't be able to forge.
10
+ *
11
+ * @module
12
+ */
13
+ /**
14
+ * Mint a v4 UUID, or a short hex slice of one when `length` is set.
15
+ *
16
+ * - `id()` returns a full RFC 4122 v4 UUID. Pick this when global
17
+ * uniqueness matters: long-running batches, ids that cross a storage /
18
+ * process boundary, anything that may collide across machines.
19
+ * - `id(length)` returns the first `length` hex chars of a fresh UUID
20
+ * with dashes stripped (e.g. `id(8) -> "a3f1c92b"`). Pick this when the
21
+ * id has to be short / typeable and the scope is bounded - cache keys
22
+ * local to a request, slug suffixes. `length <= 0` throws.
23
+ *
24
+ * Prefers `crypto.randomUUID()`, which covers Node (>= 19) and a browser on
25
+ * a secure origin. Browsers gate `randomUUID` behind a secure context, so a
26
+ * page served over plain http (a LAN dev host) has `crypto` but not that
27
+ * method; this package is browser-safe and its callers mint ids on the
28
+ * render path, so it degrades instead of throwing: `getRandomValues` when
29
+ * present, else `Math.random`. Every branch returns a well-formed v4 UUID -
30
+ * only the entropy source differs.
31
+ *
32
+ * @example
33
+ * id(); // "123e4567-e89b-12d3-a456-426614174000"
34
+ * id(8); // "a3f1c92b"
35
+ */
36
+ export declare function id(length?: number): string;
37
+ /**
38
+ * Short, deterministic FNV-1a hash over one or more values. Wraps
39
+ * {@link fnvHashWithOptions} with all defaults: 6-char Crockford-style
40
+ * base-32 output (digits + lowercase, minus `i`/`l`/`o`/`u`).
41
+ * Browser-safe (no `node:crypto`).
42
+ *
43
+ * Accepts any mix of primitives, arrays, plain objects, `Map`s, and
44
+ * `Set`s; nested structures are walked deterministically so the hash is
45
+ * order-stable for objects / maps / sets and order-sensitive for arrays.
46
+ * Cycles are detected and folded into a `circular:` marker.
47
+ *
48
+ * Use for cache keys, slug suffixes, log correlation ids, and other
49
+ * "give me something short and stable" needs - **never** for tokens or
50
+ * signatures. FNV-1a is a non-cryptographic hash.
51
+ *
52
+ * @example
53
+ * fnvHash("databricks-claude-sonnet-4-6"); // "k3p9q7"
54
+ * fnvHash([1, 2, 3]) !== fnvHash([3, 2, 1]);
55
+ */
56
+ export declare function fnvHash(...values: unknown[]): string;
57
+ /**
58
+ * Configurable counterpart to {@link fnvHash}.
59
+ *
60
+ * Options:
61
+ * - `length` (default `6`): number of base-32 chars to return. Capped
62
+ * at 7 - the underlying digest is 32 bits, which base-32-encodes to
63
+ * at most 7 chars. Output is left-padded with the alphabet's zero
64
+ * character so short digests still hit the requested width.
65
+ * - `alphabet` (default Crockford-style
66
+ * `"0123456789abcdefghjkmnpqrstvwxyz"`): 32 distinct characters used
67
+ * to encode the digest. Throws when not exactly 32 unique chars.
68
+ * - `digest` (default `0x811c9dc5`, the FNV-1a offset basis): the seed
69
+ * the running digest starts from. Useful for namespacing so
70
+ * otherwise-identical inputs hashed under different namespaces never
71
+ * collide, and for chaining hashes across pipeline stages.
72
+ *
73
+ * The hash is **not** stable across changes to the alphabet or `length` -
74
+ * those tune the output, not the digest input.
75
+ *
76
+ * @example
77
+ * fnvHashWithOptions({ length: 4 }, "user@example.com"); // 4 chars
78
+ * fnvHashWithOptions({ digest: nsHash }, key) !== fnvHash(key); // namespaced
79
+ */
80
+ export declare function fnvHashWithOptions(options?: {
81
+ length?: number;
82
+ alphabet?: string;
83
+ digest?: number;
84
+ }, ...values: unknown[]): string;
85
+ /**
86
+ * Encode a 32-bit unsigned integer as base-32 using the default
87
+ * Crockford-style alphabet (or `alphabet` when provided). The encoding
88
+ * has **no** zero-padding by default - `toBase32(0)` returns the
89
+ * alphabet's zero character, otherwise the result is the minimal number
90
+ * of digits that fits the value. Pad / truncate at the call site when you
91
+ * need a fixed width.
92
+ *
93
+ * `disableAlphabetValidation` skips the unique-32-char check for hot
94
+ * paths that have already validated the alphabet. The function still
95
+ * requires `alphabet.length === 32` either way.
96
+ *
97
+ * @example
98
+ * toBase32(0); // "0"
99
+ * toBase32(31); // "z"
100
+ * toBase32(0xdeadbe); // "6vmtw"
101
+ */
102
+ export declare function toBase32(value: number, alphabet?: string, disableAlphabetValidation?: boolean): string;