@byline/core 3.20.3 → 3.21.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 (45) hide show
  1. package/dist/@types/collection-types.d.ts +28 -3
  2. package/dist/@types/field-data-types.d.ts +8 -10
  3. package/dist/@types/field-data-types.js +1 -1
  4. package/dist/@types/field-data-types.test.node.d.ts +1 -0
  5. package/dist/@types/field-data-types.test.node.js +70 -0
  6. package/dist/@types/index.d.ts +1 -0
  7. package/dist/@types/index.js +1 -0
  8. package/dist/@types/relation-types.d.ts +38 -0
  9. package/dist/@types/relation-types.js +8 -0
  10. package/dist/@types/site-config.d.ts +1 -1
  11. package/dist/codegen/fixtures/all-fields.d.ts +342 -0
  12. package/dist/codegen/fixtures/all-fields.expected.d.ts +120 -0
  13. package/dist/codegen/fixtures/all-fields.expected.js +1 -0
  14. package/dist/codegen/fixtures/all-fields.js +94 -0
  15. package/dist/codegen/index.d.ts +16 -0
  16. package/dist/codegen/index.js +431 -0
  17. package/dist/codegen/index.test.node.d.ts +1 -0
  18. package/dist/codegen/index.test.node.js +230 -0
  19. package/dist/config/validate-collections.d.ts +3 -0
  20. package/dist/config/validate-collections.js +25 -0
  21. package/dist/config/validate-collections.test.node.js +42 -0
  22. package/dist/core.d.ts +1 -1
  23. package/dist/query/parse-where.d.ts +1 -1
  24. package/dist/schemas/zod/builder.js +7 -3
  25. package/dist/schemas/zod/builder.test.node.d.ts +1 -0
  26. package/dist/schemas/zod/builder.test.node.js +49 -0
  27. package/dist/services/collection-bootstrap.d.ts +1 -1
  28. package/dist/services/discover-counter-groups.d.ts +1 -1
  29. package/dist/services/document-lifecycle/create.d.ts +2 -2
  30. package/dist/services/document-lifecycle/create.js +5 -2
  31. package/dist/services/document-lifecycle/update.d.ts +4 -4
  32. package/dist/services/document-lifecycle/update.js +9 -4
  33. package/dist/services/document-lifecycle.test.node.js +66 -0
  34. package/dist/services/index.d.ts +1 -0
  35. package/dist/services/index.js +1 -0
  36. package/dist/services/normalize-numeric-fields.d.ts +23 -0
  37. package/dist/services/normalize-numeric-fields.js +89 -0
  38. package/dist/services/normalize-numeric-fields.test.node.d.ts +8 -0
  39. package/dist/services/normalize-numeric-fields.test.node.js +99 -0
  40. package/dist/services/populate.d.ts +2 -20
  41. package/dist/services/richtext-populate.d.ts +1 -1
  42. package/dist/services/validate-search-config.d.ts +1 -1
  43. package/dist/storage/collection-fingerprint.js +6 -0
  44. package/dist/storage/collection-fingerprint.test.node.js +21 -0
  45. package/package.json +7 -2
@@ -24,6 +24,14 @@ const minimalCollection = {
24
24
  ],
25
25
  },
26
26
  };
27
+ const numericCollection = {
28
+ ...minimalCollection,
29
+ fields: [
30
+ { name: 'quantity', type: 'integer' },
31
+ { name: 'score', type: 'float' },
32
+ { name: 'price', type: 'decimal' },
33
+ ],
34
+ };
27
35
  /** Build a mock IDbAdapter. Returns the adapter plus individual mock fns. */
28
36
  function createMockDb() {
29
37
  const createDocumentVersion = vi.fn().mockResolvedValue({
@@ -235,6 +243,23 @@ describe('Document lifecycle service', () => {
235
243
  const persistedData = createDocumentVersion.mock.calls[0]?.[0].documentData;
236
244
  expect(persistedData.title).toBe('Mutated');
237
245
  });
246
+ it('normalizes numeric values before and after beforeCreate', async () => {
247
+ const { db, createDocumentVersion } = createMockDb();
248
+ const beforeCreate = vi.fn(({ data }) => {
249
+ expect(data).toMatchObject({ quantity: 2, score: 1.5, price: '10.00' });
250
+ data.quantity = '3';
251
+ data.price = 12.5;
252
+ });
253
+ const definition = { ...numericCollection, hooks: { beforeCreate } };
254
+ await createDocument(buildCtx(db, definition), {
255
+ data: { quantity: '2', score: '1.5', price: ' 10.00 ' },
256
+ });
257
+ expect(createDocumentVersion.mock.calls[0]?.[0].documentData).toMatchObject({
258
+ quantity: 3,
259
+ score: 1.5,
260
+ price: '12.5',
261
+ });
262
+ });
238
263
  it('derives path from useAsPath source field via the slugifier', async () => {
239
264
  const { db, createDocumentVersion } = createMockDb();
240
265
  const definition = { ...minimalCollection, useAsPath: 'title' };
@@ -378,6 +403,24 @@ describe('Document lifecycle service', () => {
378
403
  }));
379
404
  expect(createDocumentVersion).toHaveBeenCalledOnce();
380
405
  });
406
+ it('normalizes numeric values before and after beforeUpdate', async () => {
407
+ const { db, getDocumentById, createDocumentVersion } = createMockDb();
408
+ getDocumentById.mockResolvedValue({ fields: { quantity: 1, score: 1, price: '1.0' } });
409
+ const beforeUpdate = vi.fn(({ data }) => {
410
+ expect(data.score).toBe(25);
411
+ data.score = '3.5';
412
+ });
413
+ const definition = { ...numericCollection, hooks: { beforeUpdate } };
414
+ await updateDocument(buildCtx(db, definition), {
415
+ documentId: 'doc-1',
416
+ data: { quantity: '2', score: '2.5e1', price: 4.25 },
417
+ });
418
+ expect(createDocumentVersion.mock.calls[0]?.[0].documentData).toEqual({
419
+ quantity: 2,
420
+ score: 3.5,
421
+ price: '4.25',
422
+ });
423
+ });
381
424
  it('afterUpdate receives documentId and documentVersionId', async () => {
382
425
  const afterUpdate = vi.fn();
383
426
  const { db, getDocumentById } = createMockDb();
@@ -670,6 +713,29 @@ describe('Document lifecycle service', () => {
670
713
  documentVersionId: 'ver-1',
671
714
  }));
672
715
  });
716
+ it('normalizes patched and hook-produced numeric values before persistence', async () => {
717
+ const { db, getDocumentById, createDocumentVersion } = createMockDb();
718
+ getDocumentById.mockResolvedValue({
719
+ fields: { quantity: 1, score: 1, price: '1.00' },
720
+ });
721
+ const beforeUpdate = vi.fn(({ data }) => {
722
+ expect(data.quantity).toBe(7);
723
+ data.price = ' 8.500 ';
724
+ });
725
+ const definition = { ...numericCollection, hooks: { beforeUpdate } };
726
+ await updateDocumentWithPatches(buildCtx(db, definition), {
727
+ documentId: 'doc-1',
728
+ patches: [
729
+ { kind: 'field.set', path: 'quantity', value: '7.0' },
730
+ { kind: 'field.set', path: 'score', value: '2.75' },
731
+ ],
732
+ });
733
+ expect(createDocumentVersion.mock.calls[0]?.[0].documentData).toEqual({
734
+ quantity: 7,
735
+ score: 2.75,
736
+ price: '8.500',
737
+ });
738
+ });
673
739
  });
674
740
  // -----------------------------------------------------------------------
675
741
  // changeDocumentStatus
@@ -9,6 +9,7 @@ export * from './document-read.js';
9
9
  export * from './document-to-markdown.js';
10
10
  export * from './field-upload.js';
11
11
  export { type InterfaceI18nConfig, type TranslationDriftWarning, type ValidateTranslationsResult, validateTranslations, } from './i18n-validator.js';
12
+ export { type CanonicalNumericFieldType, type CanonicalNumericValue, isCanonicalNumericValue, normalizeNumericFields, normalizeNumericValue, } from './normalize-numeric-fields.js';
12
13
  export { type CycleRelationValue, createReadContext, type PopulatedRelationValue, type PopulateFieldOptions, type PopulateFieldSpec, type PopulateMap, type PopulateOptions, type PopulateSpec, populateDocuments, type ReadContext, resolveIdentityField, type UnresolvedRelationValue, } from './populate.js';
13
14
  export { buildRelationSummaryPopulateMap, type RelationTargetResolver, resolveRelationProjection, } from './relation-projection.js';
14
15
  export { type EmbedRichTextFieldsOptions, embedRichTextFields, resolveEmbedOnSave, } from './richtext-embed.js';
@@ -10,6 +10,7 @@ export * from './document-read.js';
10
10
  export * from './document-to-markdown.js';
11
11
  export * from './field-upload.js';
12
12
  export { validateTranslations, } from './i18n-validator.js';
13
+ export { isCanonicalNumericValue, normalizeNumericFields, normalizeNumericValue, } from './normalize-numeric-fields.js';
13
14
  export { createReadContext, populateDocuments, resolveIdentityField, } from './populate.js';
14
15
  export { buildRelationSummaryPopulateMap, resolveRelationProjection, } from './relation-projection.js';
15
16
  export { embedRichTextFields, resolveEmbedOnSave, } from './richtext-embed.js';
@@ -0,0 +1,23 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import type { FieldSet } from '../@types/index.js';
9
+ export type CanonicalNumericFieldType = 'integer' | 'float' | 'decimal';
10
+ export type CanonicalNumericValue = number | string;
11
+ /** Return whether a value already has the storage-facing canonical type and shape. */
12
+ export declare function isCanonicalNumericValue(fieldType: CanonicalNumericFieldType, value: unknown): value is CanonicalNumericValue;
13
+ /**
14
+ * Convert a tolerant numeric write value to its canonical representation.
15
+ * `undefined` means the value was empty and should be removed.
16
+ */
17
+ export declare function normalizeNumericValue(fieldType: CanonicalNumericFieldType, value: unknown, path: string): CanonicalNumericValue | undefined;
18
+ /**
19
+ * Normalize every user-writable numeric leaf in a schema-shaped data tree.
20
+ * Mutates `data` in place. Counter fields are deliberately excluded because
21
+ * their values are supplied by the lifecycle allocator.
22
+ */
23
+ export declare function normalizeNumericFields(fields: FieldSet, data: Record<string, any>): void;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import { ERR_VALIDATION } from '../lib/errors.js';
9
+ import { walkFieldTree } from './walk-field-tree.js';
10
+ const NUMERIC_LITERAL_RE = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/;
11
+ /** Return whether a value already has the storage-facing canonical type and shape. */
12
+ export function isCanonicalNumericValue(fieldType, value) {
13
+ if (fieldType === 'decimal') {
14
+ return typeof value === 'string' && value.trim() === value && NUMERIC_LITERAL_RE.test(value);
15
+ }
16
+ return (typeof value === 'number' &&
17
+ Number.isFinite(value) &&
18
+ (fieldType !== 'integer' || Number.isInteger(value)));
19
+ }
20
+ /**
21
+ * Convert a tolerant numeric write value to its canonical representation.
22
+ * `undefined` means the value was empty and should be removed.
23
+ */
24
+ export function normalizeNumericValue(fieldType, value, path) {
25
+ if (typeof value === 'string') {
26
+ const trimmed = value.trim();
27
+ if (trimmed === '')
28
+ return undefined;
29
+ if (!NUMERIC_LITERAL_RE.test(trimmed))
30
+ throwNumericValidation(fieldType, value, path);
31
+ if (fieldType === 'decimal')
32
+ return trimmed;
33
+ const numberValue = Number(trimmed);
34
+ if (!Number.isFinite(numberValue))
35
+ throwNumericValidation(fieldType, value, path);
36
+ if (fieldType === 'integer' && !Number.isInteger(numberValue)) {
37
+ throwNumericValidation(fieldType, value, path);
38
+ }
39
+ return numberValue;
40
+ }
41
+ if (typeof value === 'number') {
42
+ if (!Number.isFinite(value))
43
+ throwNumericValidation(fieldType, value, path);
44
+ if (fieldType === 'integer' && !Number.isInteger(value)) {
45
+ throwNumericValidation(fieldType, value, path);
46
+ }
47
+ return fieldType === 'decimal' ? String(value) : value;
48
+ }
49
+ throwNumericValidation(fieldType, value, path);
50
+ }
51
+ /**
52
+ * Normalize every user-writable numeric leaf in a schema-shaped data tree.
53
+ * Mutates `data` in place. Counter fields are deliberately excluded because
54
+ * their values are supplied by the lifecycle allocator.
55
+ */
56
+ export function normalizeNumericFields(fields, data) {
57
+ for (const leaf of walkFieldTree(fields, data)) {
58
+ if (!isWritableNumericType(leaf.field.type))
59
+ continue;
60
+ if (leaf.field.localized === true && isLocaleMap(leaf.value)) {
61
+ for (const [locale, localeValue] of Object.entries(leaf.value)) {
62
+ normalizeLeafValue(leaf.field.type, leaf.value, locale, localeValue, `${leaf.fieldPath}.${locale}`);
63
+ }
64
+ continue;
65
+ }
66
+ normalizeLeafValue(leaf.field.type, leaf.parent, leaf.key, leaf.value, leaf.fieldPath);
67
+ }
68
+ }
69
+ function normalizeLeafValue(fieldType, parent, key, value, path) {
70
+ const normalized = normalizeNumericValue(fieldType, value, path);
71
+ if (normalized === undefined) {
72
+ delete parent[key];
73
+ }
74
+ else {
75
+ parent[key] = normalized;
76
+ }
77
+ }
78
+ function isWritableNumericType(type) {
79
+ return type === 'integer' || type === 'float' || type === 'decimal';
80
+ }
81
+ function isLocaleMap(value) {
82
+ return value != null && typeof value === 'object' && !Array.isArray(value);
83
+ }
84
+ function throwNumericValidation(fieldType, value, path) {
85
+ throw ERR_VALIDATION({
86
+ message: `invalid ${fieldType} value at '${path}'`,
87
+ details: { path, fieldType, value },
88
+ });
89
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ export {};
@@ -0,0 +1,99 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import { describe, expect, it } from 'vitest';
9
+ import { BylineError, ErrorCodes } from '../lib/errors.js';
10
+ import { normalizeNumericFields, normalizeNumericValue } from './normalize-numeric-fields.js';
11
+ const fields = [
12
+ { name: 'count', type: 'integer' },
13
+ { name: 'ratio', type: 'float' },
14
+ { name: 'price', type: 'decimal' },
15
+ { name: 'sequence', type: 'counter', group: 'test' },
16
+ {
17
+ name: 'settings',
18
+ type: 'group',
19
+ fields: [{ name: 'threshold', type: 'float' }],
20
+ },
21
+ {
22
+ name: 'rows',
23
+ type: 'array',
24
+ fields: [{ name: 'quantity', type: 'integer' }],
25
+ },
26
+ {
27
+ name: 'content',
28
+ type: 'blocks',
29
+ blocks: [
30
+ {
31
+ blockType: 'amount',
32
+ fields: [{ name: 'value', type: 'decimal' }],
33
+ },
34
+ ],
35
+ },
36
+ ];
37
+ describe('normalizeNumericFields', () => {
38
+ it('normalizes numeric leaves through groups, arrays, and blocks while leaving counters alone', () => {
39
+ const data = {
40
+ count: '12',
41
+ ratio: ' 1.25e2 ',
42
+ price: ' 001.2300 ',
43
+ sequence: 'caller-owned-value',
44
+ settings: { threshold: 2 },
45
+ rows: [{ quantity: '3.0' }, { quantity: 4 }],
46
+ content: [{ _type: 'amount', value: 5.5 }],
47
+ };
48
+ normalizeNumericFields(fields, data);
49
+ expect(data).toEqual({
50
+ count: 12,
51
+ ratio: 125,
52
+ price: '001.2300',
53
+ sequence: 'caller-owned-value',
54
+ settings: { threshold: 2 },
55
+ rows: [{ quantity: 3 }, { quantity: 4 }],
56
+ content: [{ _type: 'amount', value: '5.5' }],
57
+ });
58
+ normalizeNumericFields(fields, data);
59
+ expect(data.price).toBe('001.2300');
60
+ });
61
+ it('removes empty and whitespace-only values', () => {
62
+ const data = { count: '', ratio: ' ', price: '\t' };
63
+ normalizeNumericFields(fields, data);
64
+ expect(data).toEqual({});
65
+ });
66
+ it('normalizes all-locale value maps and reports the locale-qualified path', () => {
67
+ const localizedFields = [
68
+ { name: 'amount', type: 'decimal', localized: true },
69
+ ];
70
+ const data = { amount: { en: ' 1.20 ', fr: 'not-a-number', de: '' } };
71
+ expect(() => normalizeNumericFields(localizedFields, data)).toThrowError(expect.objectContaining({
72
+ code: ErrorCodes.VALIDATION,
73
+ details: expect.objectContaining({ path: 'amount.fr' }),
74
+ }));
75
+ expect(data.amount.en).toBe('1.20');
76
+ });
77
+ it.each([
78
+ ['integer', '1.2'],
79
+ ['integer', Number.NaN],
80
+ ['float', Number.POSITIVE_INFINITY],
81
+ ['float', '1e'],
82
+ ['decimal', '--1'],
83
+ ])('rejects invalid %s input', (fieldType, value) => {
84
+ expect(() => normalizeNumericValue(fieldType, value, 'nested.2.value')).toThrowError(expect.objectContaining({
85
+ code: ErrorCodes.VALIDATION,
86
+ details: expect.objectContaining({ path: 'nested.2.value' }),
87
+ }));
88
+ });
89
+ it('throws a BylineError with ERR_VALIDATION', () => {
90
+ try {
91
+ normalizeNumericValue('integer', {}, 'count');
92
+ expect.fail('expected ERR_VALIDATION');
93
+ }
94
+ catch (error) {
95
+ expect(error).toBeInstanceOf(BylineError);
96
+ expect(error).toMatchObject({ code: ErrorCodes.VALIDATION });
97
+ }
98
+ });
99
+ });
@@ -134,10 +134,11 @@ export type { ReadContext } from '../@types/index.js';
134
134
  /** Build a fresh ReadContext. */
135
135
  export declare function createReadContext(overrides?: Partial<ReadContext>): ReadContext;
136
136
  export type { PopulateFieldOptions, PopulateFieldSpec, PopulateMap, PopulateSpec, } from '../@types/populate-types.js';
137
+ export type { CycleRelationValue, PopulatedRelationValue, RelationFieldReadValue, RelationReadValue, UnpopulatedRelationValue, UnresolvedRelationValue, } from '../@types/relation-types.js';
137
138
  export interface PopulateOptions {
138
139
  db: IDbAdapter;
139
140
  /** Every collection definition in the app — needed to resolve target fields. */
140
- collections: CollectionDefinition[];
141
+ collections: readonly CollectionDefinition[];
141
142
  /** The source collection id for `documents`. */
142
143
  collectionId: string;
143
144
  /**
@@ -204,25 +205,6 @@ export interface PopulateOptions {
204
205
  */
205
206
  richTextPopulate?: import('../@types/index.js').RichTextPopulateFn;
206
207
  }
207
- /** Marker placed in a relation leaf when the target was already materialised earlier in this request. */
208
- export interface CycleRelationValue extends RelatedDocumentValue {
209
- _resolved: true;
210
- _cycle: true;
211
- }
212
- /** Marker placed in a relation leaf when the target was not found (deleted). */
213
- export interface UnresolvedRelationValue extends RelatedDocumentValue {
214
- _resolved: false;
215
- }
216
- /**
217
- * Envelope placed in a relation leaf when populate successfully fetched
218
- * the target document. The `document` field carries the raw storage-shape
219
- * doc (`@byline/client` then reshapes it to `ClientDocument` during
220
- * response shaping).
221
- */
222
- export interface PopulatedRelationValue extends RelatedDocumentValue {
223
- _resolved: true;
224
- document: Record<string, any>;
225
- }
226
208
  /**
227
209
  * Populate relation leaves in `opts.documents` in place, one DB
228
210
  * round-trip per depth level per target collection.
@@ -102,4 +102,4 @@ export interface RichTextAdapterPresence {
102
102
  * Called once at `initBylineCore()` time. Fail-fast at boot is the right
103
103
  * posture; the alternative is a silent broken renderer at request time.
104
104
  */
105
- export declare function validateRichTextFieldFlags(collections: CollectionDefinition[], adapters: RichTextAdapterPresence): void;
105
+ export declare function validateRichTextFieldFlags(collections: readonly CollectionDefinition[], adapters: RichTextAdapterPresence): void;
@@ -25,4 +25,4 @@ export interface SearchProviderPresence {
25
25
  * actually opts in. Installations that don't use search leave
26
26
  * `ServerConfig.search` unset and pass cleanly.
27
27
  */
28
- export declare function validateSearchConfig(collections: CollectionDefinition[], adapters: SearchProviderPresence): void;
28
+ export declare function validateSearchConfig(collections: readonly CollectionDefinition[], adapters: SearchProviderPresence): void;
@@ -33,6 +33,12 @@ function canonicalField(field) {
33
33
  base.targetCollection = field.targetCollection;
34
34
  if (field.displayField !== undefined)
35
35
  base.displayField = field.displayField;
36
+ if (field.hasMany === true)
37
+ base.hasMany = true;
38
+ if (field.minItems !== undefined)
39
+ base.minItems = field.minItems;
40
+ if (field.maxItems !== undefined)
41
+ base.maxItems = field.maxItems;
36
42
  return base;
37
43
  case 'datetime':
38
44
  if (field.mode !== undefined)
@@ -145,6 +145,27 @@ describe('fingerprintCollection', () => {
145
145
  rel.targetCollection = 'tags';
146
146
  expect(await fingerprintCollection(b)).not.toBe(a);
147
147
  });
148
+ it('changes when a relation becomes hasMany', async () => {
149
+ const a = await fingerprintCollection(baseCollection());
150
+ const b = baseCollection();
151
+ const rel = b.fields.find((f) => f.name === 'category');
152
+ rel.hasMany = true;
153
+ expect(await fingerprintCollection(b)).not.toBe(a);
154
+ });
155
+ it.each([
156
+ 'minItems',
157
+ 'maxItems',
158
+ ])('changes when relation %s changes', async (constraint) => {
159
+ const a = baseCollection();
160
+ const aRel = a.fields.find((f) => f.name === 'category');
161
+ aRel.hasMany = true;
162
+ aRel[constraint] = 1;
163
+ const b = baseCollection();
164
+ const bRel = b.fields.find((f) => f.name === 'category');
165
+ bRel.hasMany = true;
166
+ bRel[constraint] = 2;
167
+ expect(await fingerprintCollection(b)).not.toBe(await fingerprintCollection(a));
168
+ });
148
169
  it('changes when a block variant is renamed', async () => {
149
170
  const a = await fingerprintCollection(baseCollection());
150
171
  const b = baseCollection();
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@byline/core",
3
3
  "private": false,
4
4
  "license": "MPL-2.0",
5
- "version": "3.20.3",
5
+ "version": "3.21.0",
6
6
  "engines": {
7
7
  "node": ">=20.9.0"
8
8
  },
@@ -31,6 +31,11 @@
31
31
  "import": "./dist/index.js",
32
32
  "require": "./dist/index.js"
33
33
  },
34
+ "./codegen": {
35
+ "types": "./dist/codegen/index.d.ts",
36
+ "import": "./dist/codegen/index.js",
37
+ "require": "./dist/codegen/index.js"
38
+ },
34
39
  "./zod-schemas": {
35
40
  "types": "./dist/schemas/zod/index.d.ts",
36
41
  "import": "./dist/schemas/zod/index.js",
@@ -76,7 +81,7 @@
76
81
  "pino": "^10.3.1",
77
82
  "sharp": "^0.35.3",
78
83
  "zod": "^4.4.3",
79
- "@byline/auth": "3.20.3"
84
+ "@byline/auth": "3.21.0"
80
85
  },
81
86
  "devDependencies": {
82
87
  "@biomejs/biome": "2.5.2",