@ultimat3/schema 8.0.0 → 10.0.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.
package/CLAUDE.md CHANGED
@@ -43,6 +43,14 @@ carries a duplicate of these titles and registers them unconditionally, so every
43
43
  real titles just by importing core. Add a code here **and** update that duplicate in the same
44
44
  change — `schema-error-codes-pin.test.ts` in `@ultimat3/cli` fails the build if they disagree.
45
45
 
46
+ `ERROR_DOCS_URL` in `errors.ts` is the third deliberate tier-0 duplicate, beside `singleLine` and
47
+ `ULTIMATE_ERROR_BRAND` — one URL, spelled out, because `SchemaError` cannot import
48
+ `@ultimat3/core`'s constant. There is no per-code URL anywhere in the framework: codes live in
49
+ `wiki/Error-Codes.md` as table ROWS and a table row has no anchor, so
50
+ `https://ultimate.dev/errors/<code>` was a 404 on every error and was deleted `As of 2026-08-23`. Change it
51
+ here and in `packages/core/src/error-codes.ts` in the same edit. **There is no pin test yet** —
52
+ one belongs in `@ultimat3/cli` beside `single-line-pin.test.ts`, which may legally import both.
53
+
46
54
  `MoneyValue` in `money-value.ts` — its own file, because it is the only builtin whose *shape* other
47
55
  packages alias — is the framework's **one** declaration of a money value. Tier 0 is
48
56
  the only tier every package may import, and `@ultimat3/money`'s `Money` and `@ultimat3/entity`'s
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/schema",
3
- "version": "8.0.0",
3
+ "version": "10.0.0",
4
4
  "description": "Ultimate's validation seam: Standard Schema interface, the t namespace, JSON Schema output",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/errors.ts CHANGED
@@ -23,6 +23,10 @@ const ESCAPES: Readonly<Record<string, string>> = {
23
23
  '\b': String.raw`\b`,
24
24
  '\f': String.raw`\f`,
25
25
  };
26
+ // `ESCAPES[char]` is a computed read on a plain object and is safe by DOMAIN, not by luck: the
27
+ // key is whatever `CONTROL` matched, so it is exactly one control character — and no
28
+ // `Object.prototype` member has a single-character name. Every other computed read in this file
29
+ // goes through `Object.hasOwn`.
26
30
  const singleLine = (text: string): string =>
27
31
  text.replace(
28
32
  CONTROL,
@@ -32,6 +36,18 @@ const singleLine = (text: string): string =>
32
36
  /** Same well-known symbol `@ultimat3/core` brands with. Keep in sync, never rename. */
33
37
  export const ULTIMATE_ERROR_BRAND: unique symbol = Symbol.for('ultimate.error');
34
38
 
39
+ /**
40
+ * The same one URL `@ultimat3/core`'s `ERROR_DOCS_URL` holds. **Keep in sync**, and read the
41
+ * reason there — briefly: `wiki/` is the only public documentation surface, codes live on that
42
+ * page in table ROWS, and a table row has no anchor, so there is no per-code URL to build.
43
+ *
44
+ * Spelled out rather than imported for the same reason `singleLine` and the brand symbol above
45
+ * are: `schema` and `core` are both tier 0, so `schema` may not import `core` (imports go DOWN,
46
+ * never sideways). Neither tier-0 package can check the copy against its source, so the pin
47
+ * belongs in `@ultimat3/cli` beside `single-line-pin.test.ts` — it is NOT written yet.
48
+ */
49
+ const ERROR_DOCS_URL = 'https://github.com/developerz-ai/ultimate/wiki/Error-Codes';
50
+
35
51
  export interface SchemaErrorCodeDeclaration {
36
52
  readonly title: string;
37
53
  readonly docs?: string | undefined;
@@ -100,7 +116,13 @@ export class SchemaError extends Error {
100
116
  // A schema cause is the one most likely to carry a hostile string: it describes the value that
101
117
  // failed validation, which is the request body.
102
118
  const code = singleLine(init.code);
103
- const title = singleLine(TITLES[init.code] ?? humanize(init.code));
119
+ // `Object.hasOwn`, never the read alone: `init.code` is a bare string an app or a provider
120
+ // chose, so `TITLES['constructor']` answered with the `Object` FUNCTION and `singleLine` then
121
+ // called `.replace` on it — the error that reports a bad value died reporting it, and the
122
+ // caller got a `TypeError` in place of its own failure. Same discriminator as
123
+ // `@ultimat3/action`'s `IRREGULAR[word]`.
124
+ const declared = Object.hasOwn(TITLES, init.code) ? TITLES[init.code] : undefined;
125
+ const title = singleLine(declared ?? humanize(init.code));
104
126
  const cause = singleLine(init.cause);
105
127
  // The cause is in `message` for the reason `UltimateError`'s constructor gives: `message` is
106
128
  // the ONLY field a runtime prints when an error escapes uncaught — a worker log, a CI
@@ -112,7 +134,7 @@ export class SchemaError extends Error {
112
134
  this.code = code;
113
135
  this.title = title;
114
136
  this.fix = singleLine(init.fix);
115
- this.docs = singleLine(init.docs ?? `https://ultimate.dev/errors/${init.code}`);
137
+ this.docs = singleLine(init.docs ?? ERROR_DOCS_URL);
116
138
  this.meta = init.meta;
117
139
  }
118
140
 
@@ -75,10 +75,19 @@ const FORMAT_MAP: Readonly<Record<string, string>> = Object.freeze({
75
75
  cursor: 'ultimate-cursor',
76
76
  });
77
77
 
78
+ /**
79
+ * `Object.hasOwn`, never the read alone: `node.format` comes from a schema PROVIDER's IR, so
80
+ * `FORMAT_MAP['constructor']` answered with the `Object` function and `?? node.format` could not
81
+ * rescue it — `JSON.stringify` then dropped `format` from the published document in silence.
82
+ * Same discriminator as `@ultimat3/action`'s `BY_FORMAT[node.format]`, one package up.
83
+ */
84
+ const publishedFormat = (format: string): string =>
85
+ Object.hasOwn(FORMAT_MAP, format) ? (FORMAT_MAP[format] ?? format) : format;
86
+
78
87
  function stringNode(node: SchemaNode): JsonSchema {
79
88
  return {
80
89
  type: 'string',
81
- ...(node.format === undefined ? {} : { format: FORMAT_MAP[node.format] ?? node.format }),
90
+ ...(node.format === undefined ? {} : { format: publishedFormat(node.format) }),
82
91
  ...(node.minLength === undefined ? {} : { minLength: node.minLength }),
83
92
  ...(node.maxLength === undefined ? {} : { maxLength: node.maxLength }),
84
93
  ...(node.pattern === undefined ? {} : { pattern: node.pattern }),