@ultimat3/core 24.0.0 → 25.1.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 (77) hide show
  1. package/CLAUDE.md +24 -27
  2. package/README.md +72 -34
  3. package/package.json +4 -7
  4. package/src/actor.ts +21 -0
  5. package/src/address-class.ts +40 -4
  6. package/src/assert.ts +9 -5
  7. package/src/audit.ts +144 -0
  8. package/src/aws-sigv4.ts +275 -0
  9. package/src/backoff.ts +16 -0
  10. package/src/bunfs.ts +17 -0
  11. package/src/client-dispatch.ts +24 -3
  12. package/src/client-flight.ts +68 -13
  13. package/src/client-problem.ts +62 -6
  14. package/src/client-retry-after.ts +47 -0
  15. package/src/client-transport.ts +3 -1
  16. package/src/client-wire.ts +27 -3
  17. package/src/config-ai.ts +32 -0
  18. package/src/config-defaults.ts +18 -11
  19. package/src/config-fixes.ts +0 -10
  20. package/src/config-health.ts +9 -2
  21. package/src/config-jobs.ts +51 -0
  22. package/src/config-keys.ts +170 -0
  23. package/src/config-mail.ts +73 -0
  24. package/src/config-merge.ts +1 -1
  25. package/src/config-navigation.ts +1 -25
  26. package/src/config-pwa.ts +42 -5
  27. package/src/config-removed.ts +131 -0
  28. package/src/config-shape.ts +0 -33
  29. package/src/config.ts +71 -94
  30. package/src/context.ts +16 -12
  31. package/src/cookie.ts +267 -3
  32. package/src/core-error-codes.ts +2 -0
  33. package/src/cursor-page.ts +41 -0
  34. package/src/cursor.ts +23 -5
  35. package/src/deprecation.ts +77 -0
  36. package/src/dev-secrets.ts +18 -7
  37. package/src/drain-deadline.ts +43 -0
  38. package/src/env-example.ts +9 -29
  39. package/src/errors.ts +18 -9
  40. package/src/exports/error-contract.ts +0 -1
  41. package/src/exports/observability.ts +1 -1
  42. package/src/exports/secrets.ts +3 -0
  43. package/src/finite-option.ts +1 -1
  44. package/src/flight-gate.ts +29 -14
  45. package/src/generation-fence.ts +1 -1
  46. package/src/ids.ts +7 -7
  47. package/src/image/canvas.ts +76 -5
  48. package/src/image/pipeline.ts +17 -5
  49. package/src/image/raster.ts +24 -1
  50. package/src/index.ts +90 -35
  51. package/src/iso-date.ts +1 -1
  52. package/src/lifecycle-errors.ts +1 -1
  53. package/src/lifecycle-readiness.ts +60 -2
  54. package/src/lifecycle-signals.ts +27 -2
  55. package/src/lifecycle-types.ts +96 -0
  56. package/src/lifecycle.ts +44 -133
  57. package/src/locale-direction.ts +1 -1
  58. package/src/logger.ts +16 -7
  59. package/src/mcp-exposure.ts +70 -8
  60. package/src/measurement-actor.ts +16 -1
  61. package/src/metric-errors.ts +32 -0
  62. package/src/metric-registry.ts +151 -0
  63. package/src/metric-series.ts +94 -0
  64. package/src/metrics.ts +9 -255
  65. package/src/page.ts +4 -2
  66. package/src/pg-executor.ts +2 -2
  67. package/src/registrar.ts +1 -0
  68. package/src/retry.ts +25 -5
  69. package/src/secrets-key-file.ts +139 -0
  70. package/src/secrets-store.ts +32 -16
  71. package/src/service.ts +5 -5
  72. package/src/single-flight.ts +1 -1
  73. package/src/telemetry.ts +1 -1
  74. package/src/theme-storage.ts +12 -0
  75. package/src/type-pins.ts +51 -1
  76. package/src/image/fixtures.ts +0 -263
  77. package/src/time-zone-name.ts +0 -14
@@ -3,17 +3,17 @@
3
3
  // each value into the process environment, under its own name, only where the real environment has
4
4
  // nothing. `secrets.ts` owns the envelope; this owns the filesystem and `process.env`.
5
5
 
6
- // `node:fs` sync, by necessity twice over: Bun.write takes no mode, and a world-readable master key
7
- // is the whole failure this file exists to prevent — and `installSecrets()` runs once, at boot,
8
- // before the process is serving anything, so there is nothing for an async read to overlap with.
9
- // `renameSync` because Bun has no atomic-replace primitive, and `rmSync` to clear the temp file.
10
- import { existsSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
6
+ // why: Bun has no synchronous file read or exists check, and `installSecrets()` runs once, at boot,
7
+ // before the process serves anything, so an async read has nothing to overlap with. Writing the
8
+ // key is `secrets-key-file.ts`'s.
9
+ import { existsSync, readFileSync } from 'node:fs';
11
10
  // Bun exposes no path-join primitive.
12
11
  import { join } from 'node:path';
13
12
  import { isUltimateError } from './errors';
14
13
  import type { SecretValues } from './secrets';
15
14
  import { masterKeyId, openSecrets, parseMasterKey, sealSecrets } from './secrets';
16
15
  import { SecretsFileMissingError, SecretsKeyMissingError } from './secrets-errors';
16
+ import { OWNER_ONLY_MODE, renameOver, writeOwnerOnlyFile } from './secrets-key-file';
17
17
 
18
18
  /** Committed. Encrypted at rest, diffable, and the only file `x secrets` writes into the repo. */
19
19
  export const SECRETS_FILE = 'secrets.enc.json';
@@ -21,8 +21,11 @@ export const SECRETS_FILE = 'secrets.enc.json';
21
21
  export const SECRETS_KEY_FILE = '.secrets.key';
22
22
  /** Read first, so a container gets its key from the platform's secret store and never from a file. */
23
23
  export const SECRETS_KEY_ENV = 'ULTIMATE_SECRETS_KEY';
24
- /** Owner read/write. A key file the rest of the box can read is a key file that has leaked. */
25
- export const SECRETS_KEY_MODE = 0o600;
24
+ /**
25
+ * Owner read/write. A key file the rest of the box can read is a key file that has leaked. On
26
+ * Windows the mode is not what keeps other accounts out — the ACL is, and the writers set it.
27
+ */
28
+ export const SECRETS_KEY_MODE = OWNER_ONLY_MODE;
26
29
 
27
30
  export type MasterKeySource = 'env' | 'file';
28
31
 
@@ -118,7 +121,9 @@ export async function writeSecretsFile(
118
121
  }
119
122
 
120
123
  /**
121
- * Write the master key at 0600. Callers must have made the ignore rule true first.
124
+ * Write the master key at 0600 — on Windows, with an ACL granting the current account alone
125
+ * (`X_SECRETS_KEY_ACL_FAILED` when `icacls` refuses). Callers must have made the ignore rule true
126
+ * first.
122
127
  *
123
128
  * Through a fresh temp file renamed over the target, never a write in place: `mode` applies only
124
129
  * when a write CREATES the file, so rotating over a key that was 0644 left the new key 0644. The
@@ -126,14 +131,25 @@ export async function writeSecretsFile(
126
131
  */
127
132
  export function writeMasterKeyFile(root: string, keyHex: string): string {
128
133
  const path = masterKeyPath(root);
129
- const temp = `${path}.${crypto.randomUUID()}.tmp`;
130
- try {
131
- writeFileSync(temp, `${keyHex}\n`, { encoding: 'utf-8', mode: SECRETS_KEY_MODE, flag: 'wx' });
132
- renameSync(temp, path);
133
- } catch (error) {
134
- rmSync(temp, { force: true });
135
- throw error;
136
- }
134
+ writeOwnerOnlyFile(path, `${keyHex}\n`);
135
+ return path;
136
+ }
137
+
138
+ /** Stage a rotation's new key at `stagedMasterKeyPath`, owner-only like the live one. */
139
+ export function stageMasterKeyFile(root: string, keyHex: string): string {
140
+ const path = stagedMasterKeyPath(root);
141
+ writeOwnerOnlyFile(path, `${keyHex}\n`);
142
+ return path;
143
+ }
144
+
145
+ /**
146
+ * Make a staged key live: rename it over the key file. Retried briefly when Windows refuses the
147
+ * rename because something holds the old key open (EPERM/EBUSY) — the last step of a rotation is
148
+ * the wrong one to lose to an editor or a virus scan.
149
+ */
150
+ export function promoteStagedMasterKey(root: string): string {
151
+ const path = masterKeyPath(root);
152
+ renameOver(stagedMasterKeyPath(root), path);
137
153
  return path;
138
154
  }
139
155
 
package/src/service.ts CHANGED
@@ -1,20 +1,20 @@
1
- // Single responsibility: named service factories that `createContext` installs automatically,
1
+ // Single responsibility: named service factories that `ctxOf` installs automatically,
2
2
  // bound to the exact ctx (actor, clock, tz) they were built for.
3
3
  //
4
4
  // A service closes over the `ctx` it was constructed with — `ctx.actor.orgId` inside it means
5
5
  // "the actor this service was built for", not "whoever is calling right now". So a factory
6
- // cannot be built once and cached: it has to run again every time `createContext` produces a
6
+ // cannot be built once and cached: it has to run again every time `ctxOf` produces a
7
7
  // ctx with a different actor, or an impersonated call would read the wrong tenant. Registering
8
- // with `defineService` is what lets `createContext` do that automatically instead of every
8
+ // with `defineService` is what lets `ctxOf` do that automatically instead of every
9
9
  // caller wiring `services: { posts: postsService(ctx) }` by hand at every call site.
10
10
 
11
11
  import type { CtxFacts, ServiceBag } from './context';
12
12
  import { UltimateError } from './errors';
13
13
 
14
14
  /**
15
- * `CtxFacts` and not `Ctx`: this factory runs INSIDE `createContext`, against a preview that
15
+ * `CtxFacts` and not `Ctx`: this factory runs INSIDE `ctxOf`, against a preview that
16
16
  * carries no other registered service — which the paragraph above has always said and the type
17
- * now enforces. It is also what lets `createContext` build that preview without an assertion.
17
+ * now enforces. It is also what lets `ctxOf` build that preview without an assertion.
18
18
  */
19
19
  export type ServiceFactory<T = unknown> = (ctx: CtxFacts) => T;
20
20
 
@@ -56,7 +56,7 @@ const defaultScheduler: Scheduler = (fn, ms) => {
56
56
  };
57
57
  };
58
58
 
59
- export function createSingleFlight(options?: SingleFlightOptions): SingleFlight {
59
+ export function singleFlight(options?: SingleFlightOptions): SingleFlight {
60
60
  const inflight = new Map<string, Flight>();
61
61
  const schedule = options?.schedule ?? defaultScheduler;
62
62
  const deadlineMs = options?.deadlineMs;
package/src/telemetry.ts CHANGED
@@ -340,7 +340,7 @@ const TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;
340
340
 
341
341
  /**
342
342
  * Round-trips with `traceId()` / `spanId()` from `ids.ts` and with nothing else. A context whose
343
- * `traceId` came from `uuid()` renders a 36-character dashed header here that `parseTraceparent`
343
+ * `traceId` came from `uuidV7()` renders a 36-character dashed header here that `parseTraceparent`
344
344
  * — and every OTLP collector — rejects, so mint the pair with those two generators.
345
345
  */
346
346
  export function traceparent(context: SpanContext): string {
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The `localStorage` key a visitor's light/dark choice lives under. Tier 0 because the WRITER is
3
+ * `@ultimat3/ui`'s `ThemeToggle` and the READER is `@ultimat3/render`'s inlined boot script — two
4
+ * tier-4 packages that cannot import each other.
5
+ */
6
+
7
+ /**
8
+ * One declaration, imported by both. Until 25.0.0 each package carried its own literal, pinned
9
+ * equal by a test: the two disagreeing was exactly the bug — the boot read one key, the toggle
10
+ * wrote another, and a visitor's choice never survived a reload.
11
+ */
12
+ export const THEME_STORAGE_KEY = 'ultimate.theme';
package/src/type-pins.ts CHANGED
@@ -6,8 +6,16 @@
6
6
 
7
7
  import type { Actor, ActorFactMap, FactKeysOf, FactMapOf } from './actor';
8
8
  import type { CacheTierName } from './cache-vocabulary';
9
- import type { AppConfigInput, CacheConfig, DatabaseConfig, RealtimeConfig } from './config';
9
+ import type {
10
+ AppConfig,
11
+ AppConfigInput,
12
+ CacheConfig,
13
+ DatabaseConfig,
14
+ RealtimeConfig,
15
+ ThemeConfig,
16
+ } from './config';
10
17
  import type { CtxPatch } from './context';
18
+ import type { Page } from './cursor-page';
11
19
  import type { HydrateStrategy, OfflineStrategy, RenderMode } from './route-vocabulary';
12
20
 
13
21
  /** Fails to compile when `T` is anything but `true`. The whole mechanism. */
@@ -102,6 +110,29 @@ type _DatabaseInputCarriesNoDeadField = Assert<
102
110
  : false
103
111
  >;
104
112
 
113
+ /**
114
+ * The five keys deleted in 25.0.0 stay deleted — on the config an app reads AND the input it
115
+ * writes. `defineConfig` refuses each by name at run time (`config-removed.ts`); this is the build
116
+ * error, so re-declaring one fails `tsc -b` before any test runs. `locales` / `defaultLocale` were
117
+ * a second declaration of `defineCatalogs({ default })`; `defaultTimeZone` / `defaultCurrency`
118
+ * and `theme.tokens` were read by nothing.
119
+ */
120
+ type RemovedTopLevelKey = 'locales' | 'defaultLocale' | 'defaultTimeZone' | 'defaultCurrency';
121
+
122
+ type _AppConfigCarriesNoRemovedKey = Assert<
123
+ Extract<keyof AppConfig, RemovedTopLevelKey> extends never ? true : false
124
+ >;
125
+
126
+ type _AppConfigInputCarriesNoRemovedKey = Assert<
127
+ Extract<keyof AppConfigInput, RemovedTopLevelKey> extends never ? true : false
128
+ >;
129
+
130
+ type _ThemeConfigIsDefaultModeAlone = Assert<Exact<keyof ThemeConfig, 'defaultMode'>>;
131
+
132
+ type _ThemeInputCarriesNoTokens = Assert<
133
+ 'tokens' extends keyof NonNullable<AppConfigInput['theme']> ? false : true
134
+ >;
135
+
105
136
  /**
106
137
  * The two `config.cache` fields deleted 2026-08-22, held down for the reason the `database` three
107
138
  * are: `cache.tiers` is what BUILDS the ladder, so `driver: 'redis'` was a second selector that
@@ -219,3 +250,22 @@ type _CacheConfigNamesTheLadder = Assert<Exact<CacheConfig['tiers'], readonly Ca
219
250
  type _CacheInputNamesTheLadder = Assert<
220
251
  Exact<NonNullable<AppConfigInput['cache']>['tiers'], readonly CacheTierName[] | undefined>
221
252
  >;
253
+
254
+ // The one page shape (`cursor-page.ts`): the two facts cannot disagree in a value that
255
+ // typechecks, and `hasMore` narrows `nextCursor`.
256
+
257
+ // @ts-expect-error — `hasMore: true` with no cursor is not a page: "more" must say where.
258
+ export const _MoreWithoutCursor: Page<number> = { rows: [], nextCursor: null, hasMore: true };
259
+
260
+ // @ts-expect-error — a cursor on the last page is not a page: it would continue a `while` loop.
261
+ export const _LastWithCursor: Page<number> = { rows: [], nextCursor: 'c', hasMore: false };
262
+
263
+ /** On the `hasMore` side `nextCursor` is a `string` — a loop passes it on with no `?? ''`. */
264
+ export type _HasMoreNarrowsCursor = Assert<
265
+ Extract<Page<number>, { readonly hasMore: true }>['nextCursor'] extends string ? true : false
266
+ >;
267
+
268
+ /** On the last page it is exactly `null` — `while (page.nextCursor !== null)` is the same loop. */
269
+ export type _LastPageHasNoCursor = Assert<
270
+ Extract<Page<number>, { readonly hasMore: false }>['nextCursor'] extends null ? true : false
271
+ >;
@@ -1,263 +0,0 @@
1
- // Single responsibility: byte-exact image fixtures produced by an INDEPENDENT encoder
2
- // (Pillow 10.2 and ffmpeg), plus the pixels they must decode to. A codec that only
3
- // round-trips against itself proves nothing — these bytes are the outside reference, so a
4
- // decoder bug shows up as a pixel mismatch rather than a mutually agreed hallucination.
5
-
6
- export interface ImageFixture {
7
- /** The encoded file, base64. */
8
- readonly base64: string;
9
- readonly width: number;
10
- readonly height: number;
11
- /** Expected RGBA decode, row-major. Omitted for probe-only and lossy fixtures. */
12
- readonly pixels?: readonly number[] | undefined;
13
- }
14
-
15
- export const fixtureBytes = (fixture: ImageFixture): Uint8Array =>
16
- Uint8Array.from(atob(fixture.base64), (c) => c.charCodeAt(0));
17
-
18
- /** Truecolour + alpha (PNG colour type 6), including fully transparent and premature zeros. */
19
- export const PNG_RGBA_4X4: ImageFixture = {
20
- base64:
21
- 'iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAQUlEQVR4nAXBKQGAABAAweU5Po1GE4I4hEBeCpIQ' +
22
- 'gjjoM8sMgIJIgqC6rNv+3qdN2/VkpoqookREVFUd1/PN0zj84AIej7U060EAAAAASUVORK5CYII=',
23
- width: 4,
24
- height: 4,
25
- pixels: [
26
- 0, 0, 0, 255, 255, 0, 0, 255, 0, 255, 0, 128, 0, 0, 255, 0, 255, 255, 255, 255, 10, 20, 30, 40,
27
- 200, 150, 100, 255, 1, 2, 3, 4, 128, 128, 128, 255, 255, 255, 0, 255, 0, 255, 255, 255, 255, 0,
28
- 255, 255, 5, 5, 5, 5, 250, 250, 250, 250, 60, 120, 180, 240, 9, 8, 7, 6,
29
- ],
30
- };
31
-
32
- /** Truecolour, no alpha (colour type 2) — alpha must be synthesised as 255. */
33
- export const PNG_RGB_3X2: ImageFixture = {
34
- base64:
35
- 'iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAIAAAASFvFNAAAAF0lEQVR4nGP4z8DAAMFcInInUowYGBgANh8EmGKC' +
36
- 'N2kAAAAASUVORK5CYII=',
37
- width: 3,
38
- height: 2,
39
- pixels: [
40
- 255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 10, 20, 30, 255, 200, 100, 50, 255, 0, 0, 0,
41
- 255,
42
- ],
43
- };
44
-
45
- /** Greyscale (colour type 0) — one channel replicated across RGB. */
46
- export const PNG_GRAY_2X2: ImageFixture = {
47
- base64:
48
- 'iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAAAAABX3VL4AAAADklEQVR4nGNgCGVY9R8AA60B/2f7ygkAAAAASUVO' +
49
- 'RK5CYII=',
50
- width: 2,
51
- height: 2,
52
- pixels: [0, 0, 0, 255, 85, 85, 85, 255, 170, 170, 170, 255, 255, 255, 255, 255],
53
- };
54
-
55
- /** Indexed colour (type 3) with a `tRNS` alpha table — the entry PNG readers forget. */
56
- export const PNG_PALETTE_4X1: ImageFixture = {
57
- base64:
58
- 'iVBORw0KGgoAAAANSUhEUgAAAAQAAAABCAMAAADO4v//AAADAFBMVEX/AAAA/wAAAP///wAAAAAAAAAAAAAAAAAA' +
59
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
60
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
61
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
62
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
63
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
64
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
65
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
66
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
67
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
68
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
69
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
70
- 'AAAAAAAAAAAAAAAAAAAAAAAX3fWLAAAABHRSTlP/gAD/oaGUZgAAAA1JREFUeJxjYGBkYgYAAA8AB4SOmW0AAAAA' +
71
- 'SUVORK5CYII=',
72
- width: 4,
73
- height: 1,
74
- pixels: [255, 0, 0, 255, 0, 255, 0, 128, 0, 0, 255, 0, 255, 255, 0, 255],
75
- };
76
-
77
- /** Greyscale + alpha (colour type 4). */
78
- export const PNG_GRAY_ALPHA_2X2: ImageFixture = {
79
- base64:
80
- 'iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAQAAADYv8WvAAAAEklEQVR4nGNk+N/QyHCC4b8DABPwBAkrfI8bAAAA' +
81
- 'AElFTkSuQmCC',
82
- width: 2,
83
- height: 2,
84
- pixels: [0, 0, 0, 255, 128, 128, 128, 128, 200, 200, 200, 0, 255, 255, 255, 64],
85
- };
86
-
87
- /** 16 bits per channel — must be reduced to 8 by taking the high byte. */
88
- export const PNG_GRAY16_2X2: ImageFixture = {
89
- base64:
90
- 'iVBORw0KGgoAAAANSUhEUgAAAAIAAAACEAAAAAAHTY67AAAAEklEQVR4nGNgYHBgYGhg+P8fAAbHAr89RY6RAAAA' +
91
- 'AElFTkSuQmCC',
92
- width: 2,
93
- height: 2,
94
- pixels: [0, 0, 0, 255, 64, 64, 64, 255, 128, 128, 128, 255, 255, 255, 255, 255],
95
- };
96
-
97
- /** Big enough that Pillow picks a different row filter per scanline — all five must work. */
98
- export const PNG_GRADIENT_32X24: ImageFixture = {
99
- base64:
100
- 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAYCAIAAAAUMWhjAAAAuklEQVR4nLXSyw6DIBCF4WNrr/aiaNHamL7/W3aB' +
101
- 'GFDEgQ7JtxjGxR/UDMAppRwFgCydKbBLxAzsU5gFcnbLwIGXM3BktBZg+1E9gTMLf+Dyv83ANdagBkqgCNHPNsTA' +
102
- 'jaBz7umB+zrpeRoUeCw0rqUlNPA01PbRLSJQAiUg9LAhLlDRRQQEUAGC5hsaqPUNBFB7DWoICjTGK1KBxuVjHqO/' +
103
- 'wRR42frZhh6Q6wGpvY15xHIDCbRAB7RLPwPnHDcTUr+XAAAAAElFTkSuQmCC',
104
- width: 32,
105
- height: 24,
106
- };
107
-
108
- /** The exact source of `PNG_GRADIENT_32X24` and the JPEG fixtures, as a formula. */
109
- export const gradientPixel = (x: number, y: number): readonly [number, number, number] => [
110
- (x * 7) % 256,
111
- (y * 11) % 256,
112
- (x * y) % 256,
113
- ];
114
-
115
- /**
116
- * A genuine Adam7 interlaced PNG (written by ImageMagick — Pillow's writer silently ignores
117
- * `interlace=True`, which is why this one is not generated with the others). The pipeline
118
- * refuses it with a coded error rather than garbling it.
119
- */
120
- export const PNG_INTERLACED_8X8: ImageFixture = {
121
- base64:
122
- 'iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAAE8ahlKAAAAS0lEQVQI12NgYGBgqGFQYWQoUalhUGGwYxDaxWDG' +
123
- 'wlCiwsCgwshgJWTHAEUQMSEIYpRn4ESSsRKCy+DmMDLIcsozYEEQVZyYiHQJAE1EC4Be7arJAAAAAElFTkSuQmCC',
124
- width: 8,
125
- height: 8,
126
- };
127
-
128
- /** Baseline JPEG, 4:4:4, quality 95 — the closest a lossy codec gets to exact. */
129
- export const JPEG_444_16X16: ImageFixture = {
130
- base64:
131
- '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYFBgYGBwkIBgcJ' +
132
- 'BwYGCAsICQoKCgoKBggLDAsKDAkKCgr/2wBDAQICAgICAgUDAwUKBwYHCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoK' +
133
- 'CgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgr/wAARCAAQABADAREAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAA' +
134
- 'AAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAk' +
135
- 'M2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKT' +
136
- 'lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QA' +
137
- 'HwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdh' +
138
- 'cRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp' +
139
- 'anN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk' +
140
- '5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD83/gx+yH/AKr/AIlfp/BRg8Z5h4eeIfwe+fW3wX/ZDz5X/Er9' +
141
- 'P4K+qweM21P7r8PPEP4PfPpT4L/sh48r/iV+n8FfleDxm2p/hT4eeIfwe+fW3wY/ZD/1X/Er9P4K+qweM8z+6/Dz' +
142
- 'xD+D3z//2Q==',
143
- width: 16,
144
- height: 16,
145
- };
146
-
147
- /** Baseline JPEG, 4:2:0 — chroma is half resolution and must be upsampled. */
148
- export const JPEG_420_16X16: ImageFixture = {
149
- base64:
150
- '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4R' +
151
- 'DgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU' +
152
- 'FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAAQABADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAA' +
153
- 'AAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAk' +
154
- 'M2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKT' +
155
- 'lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QA' +
156
- 'HwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdh' +
157
- 'cRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp' +
158
- 'anN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk' +
159
- '5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD4/wDBfwh/1f7j9K958F/CH/V/uP0r2PwX8If9X+4/SvefBfwh' +
160
- '/wBX+4/SjB4zbUPDzxD+D3z/2Q==',
161
- width: 16,
162
- height: 16,
163
- };
164
-
165
- /** The exact source of the 16x16 JPEG fixtures, as a formula. */
166
- export const jpegPixel = (x: number, y: number): readonly [number, number, number] => [
167
- (x * 16) % 256,
168
- (y * 16) % 256,
169
- ((x + y) * 8) % 256,
170
- ];
171
-
172
- /** Odd dimensions with 4:2:0: the last MCU column and row are padded and must be cropped. */
173
- export const JPEG_420_ODD_33X17: ImageFixture = {
174
- base64:
175
- '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAQDAwMDAgQDAwMEBAQFBgoGBgUFBgwICQcKDgwPDg4MDQ0PERYTDxAV' +
176
- 'EQ0NExoTFRcYGRkZDxIbHRsYHRYYGRj/2wBDAQQEBAYFBgsGBgsYEA0QGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgY' +
177
- 'GBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBj/wAARCAARACEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAA' +
178
- 'AAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAk' +
179
- 'M2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKT' +
180
- 'lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QA' +
181
- 'HwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdh' +
182
- 'cRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp' +
183
- 'anN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk' +
184
- '5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5Q0fwT5u39z+ld1pvw/iSISTIqL6nvXp/h3weiW/nSRfKoyeO' +
185
- 'tdhpvg/di6uot8jcJGBjPsPQf561rgMVg4YSnWrQU5zV9X7sY931d3oktZO6Tvv4XDfG0nJJTPLNO8D2h4hs5JTx' +
186
- 'g7dqn+v6VR+JHgq2Hgu0AtIUYX6AgkyEfu5OwGRX0dZeEGLhZ4ix2gmJDtRQOef59/5VQ+InhLb4LtDs+UXyZ8v5' +
187
- 'F/1cnAPU9OlZ0M4w6xkI8kY66+7HTfpZyVutpuS+0lu/1vNuNH/q7ivf+x380fHP/CERf8+8H/fl6K96/wCEIi/5' +
188
- '94P+/L0V9J/bf/Til/4Gfz7/AK6f32eh6N/yA3/4D/6EK7LTv+Qlb/8AXIfzNFFfmMP4OE/wUv8A0uofC8M7/f8A' +
189
- 'kjpNG/5Ab/8AAf8A0IVB8RP+QBp3/XxH/wCgy0UV8/k/8bAf4aX/AKXUP2DOf+Sexv8Ahf6HjNFFFfmh+Hn/2Q==',
190
- width: 33,
191
- height: 17,
192
- };
193
-
194
- /** The exact source of `JPEG_420_ODD_33X17`, as a formula. */
195
- export const oddJpegPixel = (x: number, y: number): readonly [number, number, number] => [
196
- (x * 9) % 256,
197
- (y * 13) % 256,
198
- (x * y * 3) % 256,
199
- ];
200
-
201
- /** Single-component (greyscale) JPEG. */
202
- export const JPEG_GRAY_16X16: ImageFixture = {
203
- base64:
204
- '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsO' +
205
- 'CwkJDRENDg8QEBEQCgwSExIQEw8QEBD/wAALCAAQABABAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcI' +
206
- 'CQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcY' +
207
- 'GRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKj' +
208
- 'pKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APzK' +
209
- '8P8Ah/8AtXb8mc+1el+H/gt/au3/AETOf9mj4LeH/wC1fI+TOcdq+9fgt8Fv7V8j/RM5x/DX/9k=',
210
- width: 16,
211
- height: 16,
212
- };
213
-
214
- /** Progressive JPEG — refused with a coded error, never decoded as noise. */
215
- export const JPEG_PROGRESSIVE_16X16: ImageFixture = {
216
- base64:
217
- '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4R' +
218
- 'DgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU' +
219
- 'FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAA' +
220
- 'Bgf/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGPvGTw/8QAFhAAAwAAAAAAAAAAAAAAAAAAAAQF' +
221
- '/9oACAEBAAEFAkpAlIEpAlIP/8QAFxEBAAMAAAAAAAAAAAAAAAAABgAhMf/aAAgBAwEBPwE8hy5//8QAFREBAQAA' +
222
- 'AAAAAAAAAAAAAAAAAwD/2gAIAQIBAT8BFr//xAAWEAADAAAAAAAAAAAAAAAAAAAAASH/2gAIAQEABj8CUFBQUP/E' +
223
- 'ABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEAAT8hCqq//9oADAMBAAIAAwAAABBT/8QAFBEBAAAAAAAAAAAAAAAA' +
224
- 'AAAAAP/aAAgBAwEBPxB//8QAFhEAAwAAAAAAAAAAAAAAAAAAACEx/9oACAECAQE/EIM//8QAFRABAQAAAAAAAAAA' +
225
- 'AAAAAAAAAPH/2gAIAQEAAT8QgoKCgv/Z',
226
- width: 16,
227
- height: 16,
228
- };
229
-
230
- /** Probe-only: GIF87a/89a header. */
231
- export const GIF_5X7: ImageFixture = {
232
- base64: 'R0lGODdhBQAHAIEAAAAAAAAAAAAAAAAAACwAAAAABQAHAAAIDAABCBxIsKDBgwcDAgA7',
233
- width: 5,
234
- height: 7,
235
- };
236
-
237
- /** Probe-only: lossy VP8 inside RIFF/WEBP. */
238
- export const WEBP_9X11: ImageFixture = {
239
- base64: 'UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoJAAsAAUAmJaQAA3AA/v02aAA=',
240
- width: 9,
241
- height: 11,
242
- };
243
-
244
- /** Probe-only: AVIF, dimensions read from the `ispe` property box. */
245
- export const AVIF_12X16: ImageFixture = {
246
- base64:
247
- 'AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAAD5bWV0YQAAAAAAAAAvaGRscgAAAAAAAAAAcGljdAAA' +
248
- 'AAAAAAAAAAAAAFBpY3R1cmVIYW5kbGVyAAAAAA5waXRtAAAAAAABAAAAHmlsb2MAAAAARAAAAQABAAAAAQAAASEA' +
249
- 'AAAiAAAAKGlpbmYAAAAAAAEAAAAaaW5mZQIAAAAAAQAAYXYwMUNvbG9yAAAAAGppcHJwAAAAS2lwY28AAAAUaXNw' +
250
- 'ZQAAAAAAAAAMAAAAEAAAABBwaXhpAAAAAAMICAgAAAAMYXYxQ4EADAAAAAATY29scm5jbHgAAgACAAIAAAAAF2lw' +
251
- 'bWEAAAAAAAAAAQABBAECgwQAAAAqbWRhdAoKAAAAAZ35//MAgDIUEADAAAACgAAAAKmObLaqsca2hUA=',
252
- width: 12,
253
- height: 16,
254
- };
255
-
256
- /** Probe-only: SVG is vector — it has a declared box but no raster to decode. */
257
- export const SVG_120X45: ImageFixture = {
258
- base64:
259
- 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iNDUiIHZp' +
260
- 'ZXdCb3g9IjAgMCAxMjAgNDUiPjwvc3ZnPg==',
261
- width: 120,
262
- height: 45,
263
- };
@@ -1,14 +0,0 @@
1
- // Single responsibility: re-export `@ultimat3/schema`'s IANA zone-name predicate, so `app.config.ts`
2
- // and `t.timezone` judge a zone with ONE function.
3
- //
4
- // This file held a character-for-character copy of it until 2026-08-27 — `core` and `schema` are
5
- // both tier 0 and neither could import the other — kept equal by a 123-line pin test in
6
- // `@ultimat3/cli`, a tier-5 package pinning a tier-0 invariant that no rule required to exist.
7
- // `core -> schema` is now a declared edge (`scripts/lib/tiers.ts`), so the copy is gone.
8
- //
9
- // The rule itself, and why a bare `new Intl.DateTimeFormat(…)` probe is not it — ICU 78 resolves
10
- // `CET`, `EST`, `Japan`, `GMT` and `Zulu`, so `defaultTimeZone: 'CET'` passed validation at boot
11
- // and threw `X_TIMEZONE_INVALID` on the first `format` call (issue #257) — is written down in
12
- // `packages/schema/src/time-zone-name.ts` and in `packages/time/src/zone-canonical.ts`.
13
-
14
- export { isIanaZoneName } from '@ultimat3/schema';