@byline/core 6.6.0 → 6.7.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.
Files changed (28) hide show
  1. package/dist/@types/db-types.d.ts +60 -0
  2. package/dist/auth/assert-locale-visibility.d.ts +27 -0
  3. package/dist/auth/assert-locale-visibility.js +43 -0
  4. package/dist/auth/assert-locale-visibility.test.node.js +46 -0
  5. package/dist/auth/index.d.ts +1 -0
  6. package/dist/auth/index.js +1 -0
  7. package/dist/config/resolve-item-view-columns.test.node.js +30 -0
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js +1 -1
  10. package/dist/services/document-lifecycle/internals.js +3 -0
  11. package/dist/services/document-lifecycle.test.node.js +135 -0
  12. package/dist/services/populate.d.ts +9 -1
  13. package/dist/services/populate.js +4 -0
  14. package/dist/services/richtext-populate.d.ts +7 -1
  15. package/dist/services/richtext-populate.js +7 -4
  16. package/dist/storage/index.d.ts +1 -0
  17. package/dist/storage/index.js +1 -0
  18. package/dist/storage/locale-resolution.d.ts +76 -0
  19. package/dist/storage/locale-resolution.js +122 -0
  20. package/dist/storage/locale-resolution.test.node.d.ts +8 -0
  21. package/dist/storage/locale-resolution.test.node.js +245 -0
  22. package/package.json +2 -2
  23. package/dist/schemas/zod/review-comparison-probe.test.node.d.ts +0 -1
  24. package/dist/schemas/zod/review-comparison-probe.test.node.js +0 -26
  25. package/dist/services/restore-review-probe.test.node.js +0 -3397
  26. package/dist/services/review-probes.test.node.js +0 -349
  27. /package/dist/{services/restore-review-probe.test.node.d.ts → auth/assert-locale-visibility.test.node.d.ts} +0 -0
  28. /package/dist/{services/review-probes.test.node.d.ts → config/resolve-item-view-columns.test.node.d.ts} +0 -0
@@ -0,0 +1,76 @@
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 { LocaleVisibility, MissingLocalePolicy, ReadMode } from '../@types/index.js';
9
+ import type { FlattenedFieldValue } from './storage-row-types.js';
10
+ /**
11
+ * One version's entry in the `byline_document_version_locales` ledger: the
12
+ * concrete locales its content is complete in, or `localeAgnostic` when the
13
+ * version carries only the `'all'` sentinel (no localized content).
14
+ */
15
+ export interface VersionLocaleLedger {
16
+ availableLocales: readonly string[];
17
+ localeAgnostic: boolean;
18
+ }
19
+ /**
20
+ * Derive a completeness ledger from loaded store rows, using the same rule the
21
+ * write path records: a locale is complete when it covers every localized field
22
+ * path the source locale has; a version with no localized rows is
23
+ * locale-agnostic. Used only for versions written before the ledger existed and
24
+ * not yet backfilled. It can only see the rows a read loaded, so a projected
25
+ * read of such a version may still misjudge completeness.
26
+ */
27
+ export declare function deriveVersionLocaleLedger(rows: readonly FlattenedFieldValue[], sourceLocale: string): VersionLocaleLedger;
28
+ /**
29
+ * The per-document facts a locale-eligibility decision needs. `ledger` is the
30
+ * selected version's completeness ledger; `availableLocales` is the document's
31
+ * saved editorial checkbox set; `advertiseLocales` is the collection's opt-in
32
+ * to that control.
33
+ */
34
+ export interface LocaleEligibility {
35
+ visibility: LocaleVisibility;
36
+ sourceLocale: string;
37
+ ledger: VersionLocaleLedger;
38
+ advertiseLocales: boolean;
39
+ availableLocales: readonly string[];
40
+ }
41
+ /**
42
+ * The locale visibility a read uses: an explicit `localeVisibility` wins;
43
+ * otherwise `status: 'any'` implies `'editorial'` and an omitted or
44
+ * `'published'` status implies `'public'`. Resolving visibility never grants
45
+ * access; callers still authorize `'editorial'` separately.
46
+ */
47
+ export declare function resolveLocaleVisibility(status: ReadMode | undefined, explicit?: LocaleVisibility): LocaleVisibility;
48
+ /** The outcome of one read's language decision for one document version. */
49
+ export interface ReadLocaleDecision {
50
+ /** The locale to restore fields in; `undefined` for a multi-locale (`'all'`) read. */
51
+ restoreLocale: string | undefined;
52
+ /** The `resolvedLocale` read metadata: the locale the fields were selected in, or `null`. */
53
+ resolvedLocale: string | null;
54
+ /** `true` when localized values must be withheld and only non-localized values returned. */
55
+ withholdLocalized: boolean;
56
+ }
57
+ /**
58
+ * Decide, for one document version, which locale a read restores, what it
59
+ * reports as `resolvedLocale`, and whether localized values must be withheld.
60
+ * Shared by every storage adapter so the language decision is identical across
61
+ * engines and is made from the whole version, before any field projection.
62
+ *
63
+ * - `locale: 'all'` restores locale maps and reports `null`.
64
+ * - A locale-agnostic version restores the requested locale and reports `null`.
65
+ * - `'fallback'` restores and reports the first eligible chain entry.
66
+ * - `'omit'`, `'empty'` and an omitted policy are exact: an eligible locale is
67
+ * restored and reported. Under `'public'` visibility an ineligible locale
68
+ * withholds localized values and reports `null`; under `'editorial'` the
69
+ * exact locale is restored even when partial.
70
+ */
71
+ export declare function resolveReadLocale(params: {
72
+ locale: string;
73
+ chain: readonly string[];
74
+ onMissingLocale: MissingLocalePolicy | undefined;
75
+ eligibility: LocaleEligibility;
76
+ }): ReadLocaleDecision;
@@ -0,0 +1,122 @@
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
+ /**
9
+ * Derive a completeness ledger from loaded store rows, using the same rule the
10
+ * write path records: a locale is complete when it covers every localized field
11
+ * path the source locale has; a version with no localized rows is
12
+ * locale-agnostic. Used only for versions written before the ledger existed and
13
+ * not yet backfilled. It can only see the rows a read loaded, so a projected
14
+ * read of such a version may still misjudge completeness.
15
+ */
16
+ export function deriveVersionLocaleLedger(rows, sourceLocale) {
17
+ const pathsByLocale = new Map();
18
+ for (const row of rows) {
19
+ if (row.locale === 'all' || row.field_type === 'meta')
20
+ continue;
21
+ let paths = pathsByLocale.get(row.locale);
22
+ if (paths == null) {
23
+ paths = new Set();
24
+ pathsByLocale.set(row.locale, paths);
25
+ }
26
+ paths.add(row.field_path.join('.'));
27
+ }
28
+ if (pathsByLocale.size === 0)
29
+ return { availableLocales: [], localeAgnostic: true };
30
+ const canonical = pathsByLocale.get(sourceLocale) ?? new Set();
31
+ const availableLocales = [];
32
+ for (const [locale, paths] of pathsByLocale) {
33
+ let covers = true;
34
+ for (const path of canonical) {
35
+ if (!paths.has(path)) {
36
+ covers = false;
37
+ break;
38
+ }
39
+ }
40
+ if (covers)
41
+ availableLocales.push(locale);
42
+ }
43
+ return { availableLocales, localeAgnostic: false };
44
+ }
45
+ /**
46
+ * Whether `locale` may be delivered for one document version.
47
+ *
48
+ * - A locale-agnostic version renders identically everywhere: always eligible.
49
+ * - The source locale is always eligible, whatever its checkbox says.
50
+ * - Any other locale must be complete on the selected version.
51
+ * - Under `'public'` visibility in a collection with `advertiseLocales`, it
52
+ * must also be checked in the document's editorial set. An empty set
53
+ * authorizes no additional translation.
54
+ */
55
+ function isLocaleEligible(locale, eligibility) {
56
+ const { visibility, sourceLocale, ledger, advertiseLocales, availableLocales } = eligibility;
57
+ if (ledger.localeAgnostic)
58
+ return true;
59
+ if (locale === sourceLocale)
60
+ return true;
61
+ if (!ledger.availableLocales.includes(locale))
62
+ return false;
63
+ if (visibility === 'editorial' || !advertiseLocales)
64
+ return true;
65
+ return availableLocales.includes(locale);
66
+ }
67
+ /**
68
+ * Walk `chain` (`[requested, …, floor]`) and return the first locale eligible
69
+ * under `eligibility`. Every candidate must pass, so a withheld intermediate
70
+ * locale can never be selected. The floor is terminal and returned when no
71
+ * earlier candidate qualifies.
72
+ */
73
+ function resolveEligibleLocale(chain, eligibility) {
74
+ for (const candidate of chain) {
75
+ if (isLocaleEligible(candidate, eligibility))
76
+ return candidate;
77
+ }
78
+ // biome-ignore lint/style/noNonNullAssertion: a locale chain always has a floor
79
+ return chain[chain.length - 1];
80
+ }
81
+ /**
82
+ * The locale visibility a read uses: an explicit `localeVisibility` wins;
83
+ * otherwise `status: 'any'` implies `'editorial'` and an omitted or
84
+ * `'published'` status implies `'public'`. Resolving visibility never grants
85
+ * access; callers still authorize `'editorial'` separately.
86
+ */
87
+ export function resolveLocaleVisibility(status, explicit) {
88
+ if (explicit != null)
89
+ return explicit;
90
+ return status === 'any' ? 'editorial' : 'public';
91
+ }
92
+ /**
93
+ * Decide, for one document version, which locale a read restores, what it
94
+ * reports as `resolvedLocale`, and whether localized values must be withheld.
95
+ * Shared by every storage adapter so the language decision is identical across
96
+ * engines and is made from the whole version, before any field projection.
97
+ *
98
+ * - `locale: 'all'` restores locale maps and reports `null`.
99
+ * - A locale-agnostic version restores the requested locale and reports `null`.
100
+ * - `'fallback'` restores and reports the first eligible chain entry.
101
+ * - `'omit'`, `'empty'` and an omitted policy are exact: an eligible locale is
102
+ * restored and reported. Under `'public'` visibility an ineligible locale
103
+ * withholds localized values and reports `null`; under `'editorial'` the
104
+ * exact locale is restored even when partial.
105
+ */
106
+ export function resolveReadLocale(params) {
107
+ const { locale, chain, onMissingLocale, eligibility } = params;
108
+ if (locale === 'all') {
109
+ return { restoreLocale: undefined, resolvedLocale: null, withholdLocalized: false };
110
+ }
111
+ if (eligibility.ledger.localeAgnostic) {
112
+ return { restoreLocale: locale, resolvedLocale: null, withholdLocalized: false };
113
+ }
114
+ if (onMissingLocale === 'fallback') {
115
+ const selected = resolveEligibleLocale(chain, eligibility);
116
+ return { restoreLocale: selected, resolvedLocale: selected, withholdLocalized: false };
117
+ }
118
+ if (eligibility.visibility === 'public' && !isLocaleEligible(locale, eligibility)) {
119
+ return { restoreLocale: locale, resolvedLocale: null, withholdLocalized: true };
120
+ }
121
+ return { restoreLocale: locale, resolvedLocale: locale, withholdLocalized: false };
122
+ }
@@ -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,245 @@
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 { deriveVersionLocaleLedger, resolveLocaleVisibility, resolveReadLocale, } from './locale-resolution.js';
10
+ // The eligibility rule and the fallback walk are private to the module; these
11
+ // helpers observe them through `resolveReadLocale`, the only adapter-facing
12
+ // entry point. A locale is eligible exactly when a fallback read toward the
13
+ // source selects it, and the walk's result is the locale that read restores.
14
+ function isLocaleEligible(locale, eligibility) {
15
+ const chain = locale === eligibility.sourceLocale ? [locale] : [locale, eligibility.sourceLocale];
16
+ return (resolveReadLocale({ locale, chain, onMissingLocale: 'fallback', eligibility }).restoreLocale ===
17
+ locale);
18
+ }
19
+ function resolveEligibleLocale(chain, eligibility) {
20
+ const decision = resolveReadLocale({
21
+ locale: chain[0],
22
+ chain,
23
+ onMissingLocale: 'fallback',
24
+ eligibility,
25
+ });
26
+ return decision.restoreLocale;
27
+ }
28
+ describe('deriveVersionLocaleLedger', () => {
29
+ const row = (locale, path, field_type = 'text') => ({ locale, field_path: path.split('.'), field_type });
30
+ it('records the locales that cover every source-locale localized path', () => {
31
+ const ledger = deriveVersionLocaleLedger([
32
+ row('en', 'title'),
33
+ row('en', 'body'),
34
+ row('de', 'title'),
35
+ row('de', 'body'),
36
+ row('fr', 'title'),
37
+ row('all', 'sku'),
38
+ row('all', 'content.0', 'meta'),
39
+ ], 'en');
40
+ expect(ledger).toEqual({ availableLocales: ['en', 'de'], localeAgnostic: false });
41
+ });
42
+ it('marks a version with no localized rows as locale-agnostic', () => {
43
+ expect(deriveVersionLocaleLedger([row('all', 'sku')], 'en')).toEqual({
44
+ availableLocales: [],
45
+ localeAgnostic: true,
46
+ });
47
+ });
48
+ });
49
+ describe('isLocaleEligible', () => {
50
+ const base = {
51
+ visibility: 'public',
52
+ sourceLocale: 'en',
53
+ ledger: { availableLocales: ['en', 'es', 'de'], localeAgnostic: false },
54
+ advertiseLocales: true,
55
+ availableLocales: ['de'],
56
+ };
57
+ it('public: a complete and checked translation is eligible', () => {
58
+ expect(isLocaleEligible('de', base)).toBe(true);
59
+ });
60
+ it('public: a complete but unchecked translation is not eligible', () => {
61
+ expect(isLocaleEligible('es', base)).toBe(false);
62
+ });
63
+ it('public: a checked but incomplete translation is not eligible', () => {
64
+ expect(isLocaleEligible('fr', { ...base, availableLocales: ['fr'] })).toBe(false);
65
+ });
66
+ it('public: the source is eligible even when its checkbox is off', () => {
67
+ expect(isLocaleEligible('en', { ...base, availableLocales: [] })).toBe(true);
68
+ });
69
+ it('public: an empty advertised set authorizes no additional translation', () => {
70
+ expect(isLocaleEligible('de', { ...base, availableLocales: [] })).toBe(false);
71
+ });
72
+ it('public: a collection without advertiseLocales is gated by completeness alone', () => {
73
+ const optOut = { ...base, advertiseLocales: false, availableLocales: [] };
74
+ expect(isLocaleEligible('es', optOut)).toBe(true);
75
+ expect(isLocaleEligible('fr', optOut)).toBe(false);
76
+ });
77
+ it('a locale-agnostic version is eligible in every locale', () => {
78
+ const agnostic = { ...base, ledger: { availableLocales: [], localeAgnostic: true } };
79
+ expect(isLocaleEligible('fr', agnostic)).toBe(true);
80
+ });
81
+ it('editorial: a complete but unchecked translation is eligible', () => {
82
+ expect(isLocaleEligible('es', { ...base, visibility: 'editorial' })).toBe(true);
83
+ });
84
+ it('editorial: completeness is still required', () => {
85
+ expect(isLocaleEligible('fr', { ...base, visibility: 'editorial' })).toBe(false);
86
+ });
87
+ });
88
+ describe('resolveEligibleLocale', () => {
89
+ const base = {
90
+ visibility: 'public',
91
+ sourceLocale: 'en',
92
+ ledger: { availableLocales: ['en', 'es', 'es-MX'], localeAgnostic: false },
93
+ advertiseLocales: true,
94
+ availableLocales: [],
95
+ };
96
+ it('public: an unchecked translation falls back to the source', () => {
97
+ expect(resolveEligibleLocale(['es', 'en'], base)).toBe('en');
98
+ });
99
+ it('editorial: the same unchecked translation is selected', () => {
100
+ expect(resolveEligibleLocale(['es', 'en'], { ...base, visibility: 'editorial' })).toBe('es');
101
+ });
102
+ it('public: a withheld intermediate candidate is skipped', () => {
103
+ // Named fallback chains are not configurable yet; this pins that every
104
+ // candidate must satisfy the policy if they are added later.
105
+ const eligibility = { ...base, availableLocales: ['es'] };
106
+ expect(resolveEligibleLocale(['es-MX', 'es', 'en'], eligibility)).toBe('es');
107
+ expect(resolveEligibleLocale(['es-MX', 'es', 'en'], base)).toBe('en');
108
+ });
109
+ it('returns the floor when nothing earlier qualifies', () => {
110
+ expect(resolveEligibleLocale(['fr', 'en'], base)).toBe('en');
111
+ });
112
+ });
113
+ describe('resolveLocaleVisibility', () => {
114
+ it('defaults to public for an omitted or published status', () => {
115
+ expect(resolveLocaleVisibility(undefined)).toBe('public');
116
+ expect(resolveLocaleVisibility('published')).toBe('public');
117
+ });
118
+ it('defaults to editorial for status any', () => {
119
+ expect(resolveLocaleVisibility('any')).toBe('editorial');
120
+ });
121
+ it('an explicit value wins over the status default', () => {
122
+ expect(resolveLocaleVisibility('published', 'editorial')).toBe('editorial');
123
+ expect(resolveLocaleVisibility('any', 'public')).toBe('public');
124
+ });
125
+ });
126
+ describe('resolveReadLocale — the seven resolvedLocale result types', () => {
127
+ const eligibility = (overrides = {}) => ({
128
+ visibility: 'public',
129
+ sourceLocale: 'en',
130
+ // Spanish complete but unchecked; German partial (not in the ledger).
131
+ ledger: { availableLocales: ['en', 'es'], localeAgnostic: false },
132
+ advertiseLocales: true,
133
+ availableLocales: [],
134
+ ...overrides,
135
+ });
136
+ const chain = (locale) => (locale === 'en' ? ['en'] : [locale, 'en']);
137
+ it('R1: fallback reports the selected permitted locale, including the source', () => {
138
+ expect(resolveReadLocale({
139
+ locale: 'es',
140
+ chain: chain('es'),
141
+ onMissingLocale: 'fallback',
142
+ eligibility: eligibility({ availableLocales: ['es'] }),
143
+ })).toEqual({ restoreLocale: 'es', resolvedLocale: 'es', withholdLocalized: false });
144
+ expect(resolveReadLocale({
145
+ locale: 'es',
146
+ chain: chain('es'),
147
+ onMissingLocale: 'fallback',
148
+ eligibility: eligibility(),
149
+ })).toEqual({ restoreLocale: 'en', resolvedLocale: 'en', withholdLocalized: false });
150
+ expect(resolveReadLocale({
151
+ locale: 'es',
152
+ chain: chain('es'),
153
+ onMissingLocale: 'fallback',
154
+ eligibility: eligibility({ visibility: 'editorial' }),
155
+ })).toEqual({ restoreLocale: 'es', resolvedLocale: 'es', withholdLocalized: false });
156
+ });
157
+ it('R2: omit reports the requested locale', () => {
158
+ expect(resolveReadLocale({
159
+ locale: 'es',
160
+ chain: chain('es'),
161
+ onMissingLocale: 'omit',
162
+ eligibility: eligibility({ availableLocales: ['es'] }),
163
+ })).toEqual({ restoreLocale: 'es', resolvedLocale: 'es', withholdLocalized: false });
164
+ });
165
+ it('R3: public empty with an eligible locale reports it, with no fallback', () => {
166
+ expect(resolveReadLocale({
167
+ locale: 'es',
168
+ chain: chain('es'),
169
+ onMissingLocale: 'empty',
170
+ eligibility: eligibility({ availableLocales: ['es'] }),
171
+ })).toEqual({ restoreLocale: 'es', resolvedLocale: 'es', withholdLocalized: false });
172
+ });
173
+ it('R4: public empty with an unavailable translation withholds values and reports null', () => {
174
+ // Complete but unchecked.
175
+ expect(resolveReadLocale({
176
+ locale: 'es',
177
+ chain: chain('es'),
178
+ onMissingLocale: 'empty',
179
+ eligibility: eligibility(),
180
+ })).toEqual({ restoreLocale: 'es', resolvedLocale: null, withholdLocalized: true });
181
+ // Checked but incomplete.
182
+ expect(resolveReadLocale({
183
+ locale: 'de',
184
+ chain: chain('de'),
185
+ onMissingLocale: 'empty',
186
+ eligibility: eligibility({ availableLocales: ['de'] }),
187
+ })).toEqual({ restoreLocale: 'de', resolvedLocale: null, withholdLocalized: true });
188
+ // An omitted policy is exact, like empty.
189
+ expect(resolveReadLocale({
190
+ locale: 'es',
191
+ chain: chain('es'),
192
+ onMissingLocale: undefined,
193
+ eligibility: eligibility(),
194
+ }).withholdLocalized).toBe(true);
195
+ });
196
+ it('R4: public empty still serves the source even when its checkbox is off', () => {
197
+ expect(resolveReadLocale({
198
+ locale: 'en',
199
+ chain: chain('en'),
200
+ onMissingLocale: 'empty',
201
+ eligibility: eligibility(),
202
+ })).toEqual({ restoreLocale: 'en', resolvedLocale: 'en', withholdLocalized: false });
203
+ });
204
+ it('R5: editorial empty reports the requested locale even when partial', () => {
205
+ expect(resolveReadLocale({
206
+ locale: 'de',
207
+ chain: chain('de'),
208
+ onMissingLocale: 'empty',
209
+ eligibility: eligibility({ visibility: 'editorial' }),
210
+ })).toEqual({ restoreLocale: 'de', resolvedLocale: 'de', withholdLocalized: false });
211
+ });
212
+ it('R6: a multi-locale read reports null and restores locale maps', () => {
213
+ expect(resolveReadLocale({
214
+ locale: 'all',
215
+ chain: ['all'],
216
+ onMissingLocale: 'empty',
217
+ eligibility: eligibility({ visibility: 'editorial' }),
218
+ })).toEqual({ restoreLocale: undefined, resolvedLocale: null, withholdLocalized: false });
219
+ });
220
+ it('R7: a locale-agnostic version reports null under every policy', () => {
221
+ const agnostic = eligibility({ ledger: { availableLocales: [], localeAgnostic: true } });
222
+ for (const onMissingLocale of ['fallback', 'omit', 'empty', undefined]) {
223
+ expect(resolveReadLocale({
224
+ locale: 'es',
225
+ chain: chain('es'),
226
+ onMissingLocale,
227
+ eligibility: agnostic,
228
+ })).toEqual({ restoreLocale: 'es', resolvedLocale: null, withholdLocalized: false });
229
+ }
230
+ });
231
+ it('a non-advertised collection withholds an incomplete translation publicly', () => {
232
+ expect(resolveReadLocale({
233
+ locale: 'de',
234
+ chain: chain('de'),
235
+ onMissingLocale: 'empty',
236
+ eligibility: eligibility({ advertiseLocales: false }),
237
+ }).withholdLocalized).toBe(true);
238
+ expect(resolveReadLocale({
239
+ locale: 'es',
240
+ chain: chain('es'),
241
+ onMissingLocale: 'empty',
242
+ eligibility: eligibility({ advertiseLocales: false }),
243
+ })).toEqual({ restoreLocale: 'es', resolvedLocale: 'es', withholdLocalized: false });
244
+ });
245
+ });
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": "6.6.0",
5
+ "version": "6.7.1",
6
6
  "engines": {
7
7
  "node": ">=20.9.0"
8
8
  },
@@ -87,7 +87,7 @@
87
87
  "sharp": "^0.35.4",
88
88
  "uuid": "^14.0.2",
89
89
  "zod": "^4.6.5",
90
- "@byline/auth": "6.6.0"
90
+ "@byline/auth": "6.7.1"
91
91
  },
92
92
  "devDependencies": {
93
93
  "@biomejs/biome": "2.5.14",
@@ -1,26 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { defineCollection } from '../../@types/collection-types.js';
3
- import { createCollectionSchemas } from './builder.js';
4
- const collection = defineCollection({
5
- path: 'review-probe', labels: { singular: 'Probe', plural: 'Probes' },
6
- fields: [{ name: 'choice', type: 'select', options: [{ label: 'A', value: 'a' }] }],
7
- });
8
- const schemas = createCollectionSchemas(collection);
9
- const doc = {
10
- id: '550e8400-e29b-41d4-a716-446655440000', status: 'draft',
11
- createdAt: '2026-09-16T12:00:00.000Z', updatedAt: '2026-09-16T12:00:00.000Z',
12
- fields: { choice: 'a' },
13
- };
14
- const response = {
15
- docs: [doc], meta: { page: 1, pageSize: 10, total: 1, totalPages: 1 },
16
- included: { collection: { id: 'review-probe', path: collection.path, labels: collection.labels } },
17
- };
18
- describe('review comparison: invalid values reject a read response', () => {
19
- it('accepts a valid response', () => expect(schemas.list.safeParse(response).success).toBe(true));
20
- it('rejects the response if one document has an invalid select', () => {
21
- expect(schemas.list.safeParse({ ...response, docs: [doc, { ...doc, fields: { choice: 'bogus' } }] }).success).toBe(false);
22
- });
23
- it('rejects the response if one document has an invalid status', () => {
24
- expect(schemas.list.safeParse({ ...response, docs: [doc, { ...doc, status: 'bogus' }] }).success).toBe(false);
25
- });
26
- });