@noy-db/hub 0.2.0-pre.27 → 0.2.0-pre.28

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 (179) hide show
  1. package/dist/aggregate/index.cjs +7 -0
  2. package/dist/aggregate/index.cjs.map +1 -1
  3. package/dist/aggregate/index.d.cts +2 -2
  4. package/dist/aggregate/index.d.ts +2 -2
  5. package/dist/aggregate/index.js +2 -2
  6. package/dist/attestation/index.cjs.map +1 -1
  7. package/dist/attestation/index.d.cts +3 -3
  8. package/dist/attestation/index.d.ts +3 -3
  9. package/dist/attestation/index.js +4 -4
  10. package/dist/blobs/index.cjs.map +1 -1
  11. package/dist/blobs/index.d.cts +5 -5
  12. package/dist/blobs/index.d.ts +5 -5
  13. package/dist/blobs/index.js +4 -4
  14. package/dist/bundle/index.cjs +83 -5
  15. package/dist/bundle/index.cjs.map +1 -1
  16. package/dist/bundle/index.d.cts +5 -5
  17. package/dist/bundle/index.d.ts +5 -5
  18. package/dist/bundle/index.js +8 -8
  19. package/dist/{chunk-PS6PSEZL.js → chunk-2M62POB5.js} +3 -3
  20. package/dist/{chunk-C7UIT5XY.js → chunk-345PYZD6.js} +2 -2
  21. package/dist/{chunk-KSKKLVPA.js → chunk-3LHTFCU2.js} +113 -41
  22. package/dist/chunk-3LHTFCU2.js.map +1 -0
  23. package/dist/{chunk-KA5A5CSD.js → chunk-42EGY2FQ.js} +3 -3
  24. package/dist/{chunk-7DDTFGXY.js → chunk-4FHKQDHN.js} +2 -2
  25. package/dist/{chunk-KD253AI5.js → chunk-6LD37AMK.js} +22 -3
  26. package/dist/chunk-6LD37AMK.js.map +1 -0
  27. package/dist/{chunk-6H4CAHMQ.js → chunk-7GKDVWMD.js} +2 -2
  28. package/dist/{chunk-6ZKXFMUG.js → chunk-7TBCLM52.js} +2 -2
  29. package/dist/{chunk-VJNV2GRF.js → chunk-AHDQYG7P.js} +3 -3
  30. package/dist/{chunk-RRCRITDM.js → chunk-DCYWBKQ2.js} +2 -2
  31. package/dist/{chunk-K6PCTYAH.js → chunk-DMWUOV7X.js} +2 -2
  32. package/dist/{chunk-CVTPNW2Y.js → chunk-DQ6XF2K2.js} +6 -6
  33. package/dist/{chunk-5EITJMUJ.js → chunk-ENC4C6XW.js} +3 -3
  34. package/dist/{chunk-BOMH3637.js → chunk-GVEUI7VR.js} +2 -2
  35. package/dist/{chunk-WVYL6HM7.js → chunk-HI7FY7QZ.js} +2 -2
  36. package/dist/{chunk-PFKAT4NT.js → chunk-HQ242WNG.js} +3 -3
  37. package/dist/{chunk-HAKEZTA7.js → chunk-IMY4FXYE.js} +3 -3
  38. package/dist/{chunk-SID2NJNF.js → chunk-JEQB2KVI.js} +2 -2
  39. package/dist/{chunk-Z3BJF7SF.js → chunk-M2VZQ24Q.js} +2 -2
  40. package/dist/{chunk-2NYVA6FW.js → chunk-PPF7Z2YQ.js} +2 -2
  41. package/dist/{chunk-IWGVH2RR.js → chunk-QBC2TZHC.js} +3 -3
  42. package/dist/{chunk-AD6RNBAW.js → chunk-QSLIT4JZ.js} +1 -1
  43. package/dist/chunk-QSLIT4JZ.js.map +1 -0
  44. package/dist/{chunk-BMDVFBCL.js → chunk-RG5KLMEU.js} +2 -2
  45. package/dist/{chunk-DONPLWRC.js → chunk-SWGVCSIY.js} +2 -2
  46. package/dist/{chunk-LXA2E3VI.js → chunk-VSL3W2MO.js} +2 -2
  47. package/dist/{chunk-6M5JKTUQ.js → chunk-WH7G2YEE.js} +2 -2
  48. package/dist/{chunk-I2RX62RX.js → chunk-YYLFXX2K.js} +2 -2
  49. package/dist/consent/index.d.cts +4 -4
  50. package/dist/consent/index.d.ts +4 -4
  51. package/dist/{decrypt-partition-CptDdcCx.d.ts → decrypt-partition-BtGtE-19.d.ts} +1 -1
  52. package/dist/{decrypt-partition-DmkeOB4I.d.cts → decrypt-partition-Cqi5gcOl.d.cts} +1 -1
  53. package/dist/derivations/index.d.cts +5 -5
  54. package/dist/derivations/index.d.ts +5 -5
  55. package/dist/{dev-unlock-DUTLA3Sc.d.cts → dev-unlock-Cts_iiVv.d.cts} +1 -1
  56. package/dist/{dev-unlock-Y9znMkQ2.d.ts → dev-unlock-D0p9cQzN.d.ts} +1 -1
  57. package/dist/{executor-BIW4FT5R.js → executor-PJHMRZWJ.js} +4 -4
  58. package/dist/{fanout-sidecar-OC4QVTS2.js → fanout-sidecar-DSBVAR2P.js} +2 -2
  59. package/dist/forget/index.js +2 -2
  60. package/dist/guards/index.d.cts +5 -5
  61. package/dist/guards/index.d.ts +5 -5
  62. package/dist/{hash-Btl9IvQS.d.ts → hash-BtDtwguU.d.ts} +1 -1
  63. package/dist/{hash-DFK7cGdo.d.cts → hash-DA75XwW2.d.cts} +1 -1
  64. package/dist/history/index.cjs.map +1 -1
  65. package/dist/history/index.d.cts +5 -5
  66. package/dist/history/index.d.ts +5 -5
  67. package/dist/history/index.js +3 -3
  68. package/dist/i18n/index.cjs +98 -1
  69. package/dist/i18n/index.cjs.map +1 -1
  70. package/dist/i18n/index.d.cts +4 -4
  71. package/dist/i18n/index.d.ts +4 -4
  72. package/dist/i18n/index.js +83 -4
  73. package/dist/i18n/index.js.map +1 -1
  74. package/dist/{index-wRwJVVJQ.d.ts → index-BidHvmWf.d.ts} +3 -3
  75. package/dist/{index-CqzZml-D.d.cts → index-CP24aYCp.d.cts} +3 -3
  76. package/dist/{index-DoxKSsMj.d.cts → index-CVnt2Qmq.d.cts} +1 -1
  77. package/dist/{index-LaexBi3v.d.ts → index-DxBNV54L.d.ts} +1 -1
  78. package/dist/index.cjs +95 -6
  79. package/dist/index.cjs.map +1 -1
  80. package/dist/index.d.cts +14 -14
  81. package/dist/index.d.ts +14 -14
  82. package/dist/index.js +24 -24
  83. package/dist/{issue-ZZ2XPOGP.js → issue-JSGGSVY4.js} +4 -4
  84. package/dist/kernel/index.d.cts +4 -4
  85. package/dist/kernel/index.d.ts +4 -4
  86. package/dist/kernel/index.js +4 -4
  87. package/dist/{ledger-XQ4KVFQ6.js → ledger-PLMSH7LD.js} +3 -3
  88. package/dist/materialized-views/index.cjs +7 -0
  89. package/dist/materialized-views/index.cjs.map +1 -1
  90. package/dist/materialized-views/index.d.cts +5 -5
  91. package/dist/materialized-views/index.d.ts +5 -5
  92. package/dist/materialized-views/index.js +4 -4
  93. package/dist/{mime-magic-OiPT1qed.d.ts → mime-magic--NcogI82.d.ts} +1 -1
  94. package/dist/{mime-magic-Co4Pyj-O.d.cts → mime-magic-i2VSlkPM.d.cts} +1 -1
  95. package/dist/noydb-PHXA5E6I.js +39 -0
  96. package/dist/overlay-views/index.d.cts +5 -5
  97. package/dist/overlay-views/index.d.ts +5 -5
  98. package/dist/periods/index.cjs.map +1 -1
  99. package/dist/periods/index.d.cts +4 -4
  100. package/dist/periods/index.d.ts +4 -4
  101. package/dist/periods/index.js +3 -3
  102. package/dist/{public-envelope-O6X6AUUS.js → public-envelope-7MTH2PVE.js} +3 -3
  103. package/dist/query/index.cjs +7 -0
  104. package/dist/query/index.cjs.map +1 -1
  105. package/dist/query/index.d.cts +2 -2
  106. package/dist/query/index.d.ts +2 -2
  107. package/dist/query/index.js +3 -3
  108. package/dist/{revoke-QJ2HUM4W.js → revoke-DBAGKIDA.js} +4 -4
  109. package/dist/session/index.d.cts +5 -5
  110. package/dist/session/index.d.ts +5 -5
  111. package/dist/shadow/index.d.cts +4 -4
  112. package/dist/shadow/index.d.ts +4 -4
  113. package/dist/{signer-SCJ6C6HQ.js → signer-ADFJNS5W.js} +3 -3
  114. package/dist/snapshots/index.d.cts +4 -4
  115. package/dist/snapshots/index.d.ts +4 -4
  116. package/dist/snapshots/index.js +3 -3
  117. package/dist/{stale-KKCHF2VB.js → stale-BCIE3SMC.js} +2 -2
  118. package/dist/store/index.d.cts +4 -4
  119. package/dist/store/index.d.ts +4 -4
  120. package/dist/{strategy-YQ1qJWyq.d.ts → strategy-BoITAb2H.d.ts} +20 -1
  121. package/dist/{strategy-D1zjEV3n.d.cts → strategy-DDNvt_UD.d.cts} +20 -1
  122. package/dist/sync/index.cjs.map +1 -1
  123. package/dist/sync/index.d.cts +3 -3
  124. package/dist/sync/index.d.ts +3 -3
  125. package/dist/sync/index.js +2 -2
  126. package/dist/team/index.cjs.map +1 -1
  127. package/dist/team/index.d.cts +4 -4
  128. package/dist/team/index.d.ts +4 -4
  129. package/dist/team/index.js +5 -5
  130. package/dist/{transition-guard-CJmb8O8q.d.ts → transition-guard-BZhOlrFT.d.ts} +1 -1
  131. package/dist/{transition-guard-Dzj68JWC.d.cts → transition-guard-Bekgaxux.d.cts} +1 -1
  132. package/dist/tx/index.d.cts +4 -4
  133. package/dist/tx/index.d.ts +4 -4
  134. package/dist/{types-CkSWJt0H.d.ts → types-84nsWSDF.d.ts} +45 -4
  135. package/dist/{types-CwrTuYFI.d.cts → types-B_eCkuEI.d.cts} +45 -4
  136. package/dist/{with-materialized-view-BVfcPlaE.d.ts → with-materialized-view-CAMGQroY.d.ts} +1 -1
  137. package/dist/{with-materialized-view-dPG213gd.d.cts → with-materialized-view-DKMaZmkJ.d.cts} +1 -1
  138. package/dist/{with-overlayed-view-CJ2UDBol.d.cts → with-overlayed-view--lWXImbV.d.cts} +1 -1
  139. package/dist/{with-overlayed-view-zYPQzGGh.d.ts → with-overlayed-view-FnOf1v6H.d.ts} +1 -1
  140. package/dist/{with-rollup-B_zbRi3f.d.cts → with-rollup-C5875Ad5.d.cts} +1 -1
  141. package/dist/{with-rollup-BvaJefEs.d.ts → with-rollup-xi-mkY6Y.d.ts} +1 -1
  142. package/package.json +3 -3
  143. package/dist/chunk-AD6RNBAW.js.map +0 -1
  144. package/dist/chunk-KD253AI5.js.map +0 -1
  145. package/dist/chunk-KSKKLVPA.js.map +0 -1
  146. package/dist/noydb-EY52NVH4.js +0 -39
  147. /package/dist/{chunk-PS6PSEZL.js.map → chunk-2M62POB5.js.map} +0 -0
  148. /package/dist/{chunk-C7UIT5XY.js.map → chunk-345PYZD6.js.map} +0 -0
  149. /package/dist/{chunk-KA5A5CSD.js.map → chunk-42EGY2FQ.js.map} +0 -0
  150. /package/dist/{chunk-7DDTFGXY.js.map → chunk-4FHKQDHN.js.map} +0 -0
  151. /package/dist/{chunk-6H4CAHMQ.js.map → chunk-7GKDVWMD.js.map} +0 -0
  152. /package/dist/{chunk-6ZKXFMUG.js.map → chunk-7TBCLM52.js.map} +0 -0
  153. /package/dist/{chunk-VJNV2GRF.js.map → chunk-AHDQYG7P.js.map} +0 -0
  154. /package/dist/{chunk-RRCRITDM.js.map → chunk-DCYWBKQ2.js.map} +0 -0
  155. /package/dist/{chunk-K6PCTYAH.js.map → chunk-DMWUOV7X.js.map} +0 -0
  156. /package/dist/{chunk-CVTPNW2Y.js.map → chunk-DQ6XF2K2.js.map} +0 -0
  157. /package/dist/{chunk-5EITJMUJ.js.map → chunk-ENC4C6XW.js.map} +0 -0
  158. /package/dist/{chunk-BOMH3637.js.map → chunk-GVEUI7VR.js.map} +0 -0
  159. /package/dist/{chunk-WVYL6HM7.js.map → chunk-HI7FY7QZ.js.map} +0 -0
  160. /package/dist/{chunk-PFKAT4NT.js.map → chunk-HQ242WNG.js.map} +0 -0
  161. /package/dist/{chunk-HAKEZTA7.js.map → chunk-IMY4FXYE.js.map} +0 -0
  162. /package/dist/{chunk-SID2NJNF.js.map → chunk-JEQB2KVI.js.map} +0 -0
  163. /package/dist/{chunk-Z3BJF7SF.js.map → chunk-M2VZQ24Q.js.map} +0 -0
  164. /package/dist/{chunk-2NYVA6FW.js.map → chunk-PPF7Z2YQ.js.map} +0 -0
  165. /package/dist/{chunk-IWGVH2RR.js.map → chunk-QBC2TZHC.js.map} +0 -0
  166. /package/dist/{chunk-BMDVFBCL.js.map → chunk-RG5KLMEU.js.map} +0 -0
  167. /package/dist/{chunk-DONPLWRC.js.map → chunk-SWGVCSIY.js.map} +0 -0
  168. /package/dist/{chunk-LXA2E3VI.js.map → chunk-VSL3W2MO.js.map} +0 -0
  169. /package/dist/{chunk-6M5JKTUQ.js.map → chunk-WH7G2YEE.js.map} +0 -0
  170. /package/dist/{chunk-I2RX62RX.js.map → chunk-YYLFXX2K.js.map} +0 -0
  171. /package/dist/{executor-BIW4FT5R.js.map → executor-PJHMRZWJ.js.map} +0 -0
  172. /package/dist/{fanout-sidecar-OC4QVTS2.js.map → fanout-sidecar-DSBVAR2P.js.map} +0 -0
  173. /package/dist/{issue-ZZ2XPOGP.js.map → issue-JSGGSVY4.js.map} +0 -0
  174. /package/dist/{ledger-XQ4KVFQ6.js.map → ledger-PLMSH7LD.js.map} +0 -0
  175. /package/dist/{noydb-EY52NVH4.js.map → noydb-PHXA5E6I.js.map} +0 -0
  176. /package/dist/{public-envelope-O6X6AUUS.js.map → public-envelope-7MTH2PVE.js.map} +0 -0
  177. /package/dist/{revoke-QJ2HUM4W.js.map → revoke-DBAGKIDA.js.map} +0 -0
  178. /package/dist/{signer-SCJ6C6HQ.js.map → signer-ADFJNS5W.js.map} +0 -0
  179. /package/dist/{stale-KKCHF2VB.js.map → stale-BCIE3SMC.js.map} +0 -0
@@ -1,12 +1,12 @@
1
- export { I as I18nMap, a as I18nTextDescriptor, b as I18nTextOptions, L as Layer, O as OnMissing, c as OnMissingPolicy, R as ResolveI18nOptions, d as applyI18nLocale, g as getAtPath, i as i18nText, e as isI18nTextDescriptor, r as resolveI18nText, f as resolvePolicy, s as setAtPathInPlace, v as validateI18nTextValue } from '../strategy-D1zjEV3n.cjs';
2
- import { I as I18nStrategy } from '../types-CwrTuYFI.cjs';
3
- export { D as DICT_COLLECTION_PREFIX, a as DictEntry, b as DictKeyDescriptor, c as DictionaryHandle, d as DictionaryOptions, S as ScriptWarning, e as StaticDictDescriptor, f as dictCollectionName, g as dictKey, h as enforceScript, i as inferScripts, j as isDictCollectionName, k as isDictKeyDescriptor, l as isStaticDictDescriptor, s as staticDict } from '../types-CwrTuYFI.cjs';
1
+ export { I as I18nMap, a as I18nTextDescriptor, b as I18nTextOptions, L as Layer, O as OnMissing, c as OnMissingPolicy, R as ResolveI18nOptions, d as applyI18nLocale, g as getAtPath, i as i18nText, e as isI18nTextDescriptor, r as resolveI18nText, f as resolvePolicy, s as setAtPathInPlace, h as stripI18nFilled, v as validateI18nTextValue } from '../strategy-DDNvt_UD.cjs';
2
+ import { I as I18nStrategy } from '../types-B_eCkuEI.cjs';
3
+ export { D as DICT_COLLECTION_PREFIX, a as DictEntry, b as DictKeyDescriptor, c as DictionaryHandle, d as DictionaryOptions, S as ScriptWarning, e as StaticDictDescriptor, f as dictCollectionName, g as dictKey, h as enforceScript, i as inferScripts, j as isDictCollectionName, k as isDictKeyDescriptor, l as isStaticDictDescriptor, s as staticDict } from '../types-B_eCkuEI.cjs';
4
4
  export { D as DictKeyInUseError, a as DictKeyMissingError, L as LocaleNotSpecifiedError, M as MissingTranslationError, R as ReservedCollectionNameError, S as ScriptViolationError, b as StaticDictReadonlyError, T as TranslatorNotConfiguredError, U as UnknownDictCodeError } from '../errors-Dwk2k1xY.cjs';
5
5
  import '../lazy-builder-eYZzLEL1.cjs';
6
6
  import '../predicate-BmhBSPCH.cjs';
7
7
  import '../strategy-BSxFXGzb.cjs';
8
8
  import '../index-BMmajblo.cjs';
9
- import '../index-DoxKSsMj.cjs';
9
+ import '../index-CVnt2Qmq.cjs';
10
10
  import '@noy-db/attestation';
11
11
 
12
12
  /**
@@ -1,12 +1,12 @@
1
- export { I as I18nMap, a as I18nTextDescriptor, b as I18nTextOptions, L as Layer, O as OnMissing, c as OnMissingPolicy, R as ResolveI18nOptions, d as applyI18nLocale, g as getAtPath, i as i18nText, e as isI18nTextDescriptor, r as resolveI18nText, f as resolvePolicy, s as setAtPathInPlace, v as validateI18nTextValue } from '../strategy-YQ1qJWyq.js';
2
- import { I as I18nStrategy } from '../types-CkSWJt0H.js';
3
- export { D as DICT_COLLECTION_PREFIX, a as DictEntry, b as DictKeyDescriptor, c as DictionaryHandle, d as DictionaryOptions, S as ScriptWarning, e as StaticDictDescriptor, f as dictCollectionName, g as dictKey, h as enforceScript, i as inferScripts, j as isDictCollectionName, k as isDictKeyDescriptor, l as isStaticDictDescriptor, s as staticDict } from '../types-CkSWJt0H.js';
1
+ export { I as I18nMap, a as I18nTextDescriptor, b as I18nTextOptions, L as Layer, O as OnMissing, c as OnMissingPolicy, R as ResolveI18nOptions, d as applyI18nLocale, g as getAtPath, i as i18nText, e as isI18nTextDescriptor, r as resolveI18nText, f as resolvePolicy, s as setAtPathInPlace, h as stripI18nFilled, v as validateI18nTextValue } from '../strategy-BoITAb2H.js';
2
+ import { I as I18nStrategy } from '../types-84nsWSDF.js';
3
+ export { D as DICT_COLLECTION_PREFIX, a as DictEntry, b as DictKeyDescriptor, c as DictionaryHandle, d as DictionaryOptions, S as ScriptWarning, e as StaticDictDescriptor, f as dictCollectionName, g as dictKey, h as enforceScript, i as inferScripts, j as isDictCollectionName, k as isDictKeyDescriptor, l as isStaticDictDescriptor, s as staticDict } from '../types-84nsWSDF.js';
4
4
  export { D as DictKeyInUseError, a as DictKeyMissingError, L as LocaleNotSpecifiedError, M as MissingTranslationError, R as ReservedCollectionNameError, S as ScriptViolationError, b as StaticDictReadonlyError, T as TranslatorNotConfiguredError, U as UnknownDictCodeError } from '../errors-Dwk2k1xY.js';
5
5
  import '../lazy-builder-ChSqcF5t.js';
6
6
  import '../predicate-BmhBSPCH.js';
7
7
  import '../strategy-BSxFXGzb.js';
8
8
  import '../index-BMmajblo.js';
9
- import '../index-LaexBi3v.js';
9
+ import '../index-DxBNV54L.js';
10
10
  import '@noy-db/attestation';
11
11
 
12
12
  /**
@@ -7,7 +7,7 @@ import {
7
7
  isDictKeyDescriptor,
8
8
  isStaticDictDescriptor,
9
9
  staticDict
10
- } from "../chunk-PFKAT4NT.js";
10
+ } from "../chunk-HQ242WNG.js";
11
11
  import {
12
12
  applyI18nLocale,
13
13
  enforceScript,
@@ -18,11 +18,12 @@ import {
18
18
  resolveI18nText,
19
19
  resolvePolicy,
20
20
  setAtPathInPlace,
21
+ stripI18nFilled,
21
22
  validateI18nTextValue
22
- } from "../chunk-KD253AI5.js";
23
- import "../chunk-LXA2E3VI.js";
23
+ } from "../chunk-6LD37AMK.js";
24
+ import "../chunk-VSL3W2MO.js";
24
25
  import "../chunk-PDVP3C2I.js";
25
- import "../chunk-AD6RNBAW.js";
26
+ import "../chunk-QSLIT4JZ.js";
26
27
  import "../chunk-7JSP3E67.js";
27
28
  import {
28
29
  DictKeyInUseError,
@@ -36,12 +37,89 @@ import {
36
37
  UnknownDictCodeError
37
38
  } from "../chunk-DDOYOMAD.js";
38
39
 
40
+ // src/i18n/densify.ts
41
+ var MARKER = "_i18nFilled";
42
+ function priorFilled(prior, field) {
43
+ if (!prior) return /* @__PURE__ */ new Set();
44
+ const marker = prior[MARKER];
45
+ return new Set(marker?.[field] ?? []);
46
+ }
47
+ function singleLeaf(record, field) {
48
+ const leaves = getAtPath(record, field);
49
+ if (leaves.length !== 1) return void 0;
50
+ const leaf = leaves[0];
51
+ if (!leaf || typeof leaf !== "object" || Array.isArray(leaf)) return void 0;
52
+ return leaf;
53
+ }
54
+ function computeExemptFills(prior, incoming, fields) {
55
+ const out = /* @__PURE__ */ new Map();
56
+ if (!prior) return out;
57
+ for (const field of Object.keys(fields)) {
58
+ const filled = priorFilled(prior, field);
59
+ if (filled.size === 0) continue;
60
+ const priorLeaf = singleLeaf(prior, field);
61
+ const incLeaf = singleLeaf(incoming, field);
62
+ if (!priorLeaf || !incLeaf) continue;
63
+ const exempt = /* @__PURE__ */ new Set();
64
+ for (const loc of filled) {
65
+ if (incLeaf[loc] !== void 0 && incLeaf[loc] !== "" && incLeaf[loc] === priorLeaf[loc]) {
66
+ exempt.add(loc);
67
+ }
68
+ }
69
+ if (exempt.size > 0) out.set(field, exempt);
70
+ }
71
+ return out;
72
+ }
73
+ function densify(record, prior, fields) {
74
+ let marker = record[MARKER];
75
+ for (const [field, descriptor] of Object.entries(fields)) {
76
+ const leaf = singleLeaf(record, field);
77
+ if (!leaf) continue;
78
+ const { languages, substitute, smartSubstitute } = descriptor.options;
79
+ const filledSet = priorFilled(prior, field);
80
+ const priorLeaf = singleLeaf(prior ?? {}, field);
81
+ const isUnchangedFill = (loc) => filledSet.has(loc) && priorLeaf?.[loc] !== void 0 && leaf[loc] === priorLeaf[loc];
82
+ const authored = {};
83
+ for (const [loc, val] of Object.entries(leaf)) {
84
+ if (typeof val === "string" && val !== "" && !isUnchangedFill(loc)) authored[loc] = val;
85
+ }
86
+ const filled = [];
87
+ for (const loc of languages) {
88
+ if (authored[loc] !== void 0) continue;
89
+ const sub = resolveI18nText(authored, loc, void 0, field, {
90
+ policy: "substitute",
91
+ substitute: substitute ?? ["any"],
92
+ ...smartSubstitute ? { smartSubstitute } : {}
93
+ });
94
+ if (typeof sub === "string" && sub !== "") {
95
+ leaf[loc] = sub;
96
+ filled.push(loc);
97
+ } else if (isUnchangedFill(loc)) {
98
+ delete leaf[loc];
99
+ }
100
+ }
101
+ if (filled.length > 0) {
102
+ marker ??= {};
103
+ marker[field] = filled;
104
+ } else if (marker) {
105
+ delete marker[field];
106
+ }
107
+ }
108
+ if (marker && Object.keys(marker).length > 0) {
109
+ record[MARKER] = marker;
110
+ } else {
111
+ delete record[MARKER];
112
+ }
113
+ }
114
+
39
115
  // src/i18n/active.ts
40
116
  function withI18n() {
41
117
  return {
42
118
  applyI18nLocale,
43
119
  validateI18nTextValue,
44
120
  enforceScript,
121
+ computeExemptFills,
122
+ densify,
45
123
  buildDictionaryHandle(opts) {
46
124
  return new DictionaryHandle(
47
125
  opts.adapter,
@@ -85,6 +163,7 @@ export {
85
163
  resolvePolicy,
86
164
  setAtPathInPlace,
87
165
  staticDict,
166
+ stripI18nFilled,
88
167
  validateI18nTextValue,
89
168
  withI18n
90
169
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/i18n/active.ts"],"sourcesContent":["/**\n * Active i18n strategy — `withI18n()` returns the real implementation\n * that wires multi-locale resolution, i18nText validation, and the\n * `DictionaryHandle` for `dictKey` fields into the core read/write\n * paths.\n *\n * Consumers opt in by:\n *\n * ```ts\n * import { createNoydb } from '@noy-db/hub'\n * import { withI18n } from '@noy-db/hub/i18n'\n *\n * const db = await createNoydb({\n * store: ...,\n * user: ...,\n * i18nStrategy: withI18n(),\n * })\n * ```\n *\n * The factory delegates to the existing `core.ts` and `dictionary.ts`\n * modules. Splitting the import chain through this file is what lets\n * tsup tree-shake the `~854 LOC` of dictionary + locale resolution\n * out of the default bundle when no `withI18n()` import is present.\n *\n * @public\n */\n\nimport type { I18nStrategy, BuildDictionaryHandleOptions } from './strategy.js'\nimport { applyI18nLocale, validateI18nTextValue } from './core.js'\nimport { enforceScript } from './script.js'\nimport { DictionaryHandle } from './dictionary.js'\n\nexport function withI18n(): I18nStrategy {\n return {\n applyI18nLocale,\n validateI18nTextValue,\n enforceScript,\n buildDictionaryHandle<Keys extends string = string>(\n opts: BuildDictionaryHandleOptions<Keys>,\n ): DictionaryHandle<Keys> {\n return new DictionaryHandle<Keys>(\n opts.adapter,\n opts.compartmentName,\n opts.dictionaryName,\n opts.keyring,\n opts.getDEK,\n opts.encrypted,\n opts.ledger,\n opts.options,\n opts.findAndUpdateReferences,\n opts.emitter,\n )\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCO,SAAS,WAAyB;AACvC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,sBACE,MACwB;AACxB,aAAO,IAAI;AAAA,QACT,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/i18n/densify.ts","../../src/i18n/active.ts"],"sourcesContent":["/**\n * #435 v1.x densifyOnWrite — eager-fill empty i18n slots from each field's\n * substitute chain at write time, recording provenance in the internal\n * `_i18nFilled` marker (decision A: dense map + prior-read).\n *\n * Pure functions over plain records; all DB wiring lives in collection.ts.\n * Only single-leaf i18n fields are supported (array-wildcard paths are\n * skipped, mirroring auto-translate).\n */\nimport { getAtPath, resolveI18nText } from './core.js'\nimport type { I18nTextDescriptor } from './core.js'\n\nconst MARKER = '_i18nFilled'\n\ntype Leaf = Record<string, string>\n\n/** Locales recorded as densify-filled on the prior record for `field`. */\nfunction priorFilled(prior: Record<string, unknown> | undefined, field: string): Set<string> {\n if (!prior) return new Set()\n const marker = prior[MARKER] as Record<string, string[]> | undefined\n return new Set(marker?.[field] ?? [])\n}\n\n/** The single leaf map for `field`, or undefined for absent / array-wildcard / non-object. */\nfunction singleLeaf(record: Record<string, unknown>, field: string): Leaf | undefined {\n const leaves = getAtPath(record, field)\n if (leaves.length !== 1) return undefined\n const leaf = leaves[0]\n if (!leaf || typeof leaf !== 'object' || Array.isArray(leaf)) return undefined\n return leaf as Leaf\n}\n\n/**\n * Per field, the locales that are UNCHANGED round-tripped densify fills — i.e.\n * marked filled on the prior record AND identical in the incoming record.\n * These are exempt from write-time script enforcement (they are derived copies,\n * not authored text). Slots the user changed are NOT exempt (validated as authored).\n */\nexport function computeExemptFills(\n prior: Record<string, unknown> | undefined,\n incoming: Record<string, unknown>,\n fields: Record<string, I18nTextDescriptor>,\n): Map<string, Set<string>> {\n const out = new Map<string, Set<string>>()\n if (!prior) return out\n for (const field of Object.keys(fields)) {\n const filled = priorFilled(prior, field)\n if (filled.size === 0) continue\n const priorLeaf = singleLeaf(prior, field)\n const incLeaf = singleLeaf(incoming, field)\n if (!priorLeaf || !incLeaf) continue\n const exempt = new Set<string>()\n for (const loc of filled) {\n if (incLeaf[loc] !== undefined && incLeaf[loc] !== '' && incLeaf[loc] === priorLeaf[loc]) {\n exempt.add(loc)\n }\n }\n if (exempt.size > 0) out.set(field, exempt)\n }\n return out\n}\n\n/**\n * Mutate `record` in place: fill empty declared-language slots for each\n * densify-enabled field from the field's substitute chain, recompute unchanged\n * prior fills, clear marks for slots that became authored, and write the\n * resulting `_i18nFilled` marker (removed when empty).\n *\n * `prior` is read-only — it is never mutated.\n *\n * Provenance uses value-equality (decision A): a slot counts as an unchanged\n * fill when it was prior-marked AND its value still equals the prior value. A\n * consequence is that re-authoring a value byte-identical to the existing fill\n * keeps it classified as a fill (the visible value is unchanged either way; the\n * slot stays script-exempt and will auto-refresh if its source later changes).\n * This is inherent to value-equality provenance, not a bug.\n */\nexport function densify(\n record: Record<string, unknown>,\n prior: Record<string, unknown> | undefined,\n fields: Record<string, I18nTextDescriptor>,\n): void {\n let marker = record[MARKER] as Record<string, string[]> | undefined\n\n for (const [field, descriptor] of Object.entries(fields)) {\n const leaf = singleLeaf(record, field)\n if (!leaf) continue\n const { languages, substitute, smartSubstitute } = descriptor.options\n const filledSet = priorFilled(prior, field)\n const priorLeaf = singleLeaf(prior ?? {}, field)\n const isUnchangedFill = (loc: string): boolean =>\n filledSet.has(loc) && priorLeaf?.[loc] !== undefined && leaf[loc] === priorLeaf[loc]\n\n // Authored source = present, non-empty, NOT an unchanged prior fill.\n const authored: Leaf = {}\n for (const [loc, val] of Object.entries(leaf)) {\n if (typeof val === 'string' && val !== '' && !isUnchangedFill(loc)) authored[loc] = val\n }\n\n const filled: string[] = []\n for (const loc of languages) {\n if (authored[loc] !== undefined) continue // real value present → not a fill\n const sub = resolveI18nText(authored, loc, undefined, field, {\n policy: 'substitute',\n substitute: substitute ?? ['any'],\n ...(smartSubstitute ? { smartSubstitute } : {}),\n })\n if (typeof sub === 'string' && sub !== '') {\n leaf[loc] = sub\n filled.push(loc)\n } else if (isUnchangedFill(loc)) {\n delete leaf[loc] // stale fill with no source left → drop it\n }\n }\n\n if (filled.length > 0) {\n marker ??= {}\n marker[field] = filled\n } else if (marker) {\n delete marker[field]\n }\n }\n\n if (marker && Object.keys(marker).length > 0) {\n record[MARKER] = marker\n } else {\n delete record[MARKER]\n }\n}\n","/**\n * Active i18n strategy — `withI18n()` returns the real implementation\n * that wires multi-locale resolution, i18nText validation, and the\n * `DictionaryHandle` for `dictKey` fields into the core read/write\n * paths.\n *\n * Consumers opt in by:\n *\n * ```ts\n * import { createNoydb } from '@noy-db/hub'\n * import { withI18n } from '@noy-db/hub/i18n'\n *\n * const db = await createNoydb({\n * store: ...,\n * user: ...,\n * i18nStrategy: withI18n(),\n * })\n * ```\n *\n * The factory delegates to the existing `core.ts` and `dictionary.ts`\n * modules. Splitting the import chain through this file is what lets\n * tsup tree-shake the `~854 LOC` of dictionary + locale resolution\n * out of the default bundle when no `withI18n()` import is present.\n *\n * @public\n */\n\nimport type { I18nStrategy, BuildDictionaryHandleOptions } from './strategy.js'\nimport { applyI18nLocale, validateI18nTextValue } from './core.js'\nimport { enforceScript } from './script.js'\nimport { computeExemptFills, densify } from './densify.js'\nimport { DictionaryHandle } from './dictionary.js'\n\nexport function withI18n(): I18nStrategy {\n return {\n applyI18nLocale,\n validateI18nTextValue,\n enforceScript,\n computeExemptFills,\n densify,\n buildDictionaryHandle<Keys extends string = string>(\n opts: BuildDictionaryHandleOptions<Keys>,\n ): DictionaryHandle<Keys> {\n return new DictionaryHandle<Keys>(\n opts.adapter,\n opts.compartmentName,\n opts.dictionaryName,\n opts.keyring,\n opts.getDEK,\n opts.encrypted,\n opts.ledger,\n opts.options,\n opts.findAndUpdateReferences,\n opts.emitter,\n )\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,9 +1,9 @@
1
1
  import './predicate-BmhBSPCH.js';
2
- import './strategy-YQ1qJWyq.js';
2
+ import './strategy-BoITAb2H.js';
3
3
  import './ulid-DRH25k3y.js';
4
- import './types-CkSWJt0H.js';
4
+ import './types-84nsWSDF.js';
5
5
  import './errors-Dwk2k1xY.js';
6
- import './index-LaexBi3v.js';
6
+ import './index-DxBNV54L.js';
7
7
 
8
8
  interface EncryptResult {
9
9
  iv: string;
@@ -1,9 +1,9 @@
1
1
  import './predicate-BmhBSPCH.cjs';
2
- import './strategy-D1zjEV3n.cjs';
2
+ import './strategy-DDNvt_UD.cjs';
3
3
  import './ulid-DRH25k3y.cjs';
4
- import './types-CwrTuYFI.cjs';
4
+ import './types-B_eCkuEI.cjs';
5
5
  import './errors-Dwk2k1xY.cjs';
6
- import './index-DoxKSsMj.cjs';
6
+ import './index-CVnt2Qmq.cjs';
7
7
 
8
8
  interface EncryptResult {
9
9
  iv: string;
@@ -1,6 +1,6 @@
1
1
  import { C as CollectionIndexes, a as Clause, O as Operator } from './predicate-BmhBSPCH.cjs';
2
2
  import { N as NoydbError } from './errors-Dwk2k1xY.cjs';
3
- import { a as I18nTextDescriptor, N as MoneyDescriptor, A as AggregateStrategy, j as AggregateSpec, k as Aggregation, h as AggregateResult, o as GroupedQuery, p as GroupedQueryN } from './strategy-D1zjEV3n.cjs';
3
+ import { a as I18nTextDescriptor, P as MoneyDescriptor, A as AggregateStrategy, k as AggregateSpec, l as Aggregation, j as AggregateResult, p as GroupedQuery, q as GroupedQueryN } from './strategy-DDNvt_UD.cjs';
4
4
 
5
5
  /**
6
6
  * Foreign-key references — the soft-FK mechanism.
@@ -1,6 +1,6 @@
1
1
  import { C as CollectionIndexes, a as Clause, O as Operator } from './predicate-BmhBSPCH.js';
2
2
  import { N as NoydbError } from './errors-Dwk2k1xY.js';
3
- import { a as I18nTextDescriptor, N as MoneyDescriptor, A as AggregateStrategy, j as AggregateSpec, k as Aggregation, h as AggregateResult, o as GroupedQuery, p as GroupedQueryN } from './strategy-YQ1qJWyq.js';
3
+ import { a as I18nTextDescriptor, P as MoneyDescriptor, A as AggregateStrategy, k as AggregateSpec, l as Aggregation, j as AggregateResult, p as GroupedQuery, q as GroupedQueryN } from './strategy-BoITAb2H.js';
4
4
 
5
5
  /**
6
6
  * Foreign-key references — the soft-FK mechanism.
package/dist/index.cjs CHANGED
@@ -7578,13 +7578,14 @@ function stripDisallowed(str, scripts) {
7578
7578
  for (const ch of str) if (ok.test(ch)) out += ch;
7579
7579
  return out;
7580
7580
  }
7581
- function enforceScript(value, field, descriptor) {
7581
+ function enforceScript(value, field, descriptor, exempt) {
7582
7582
  const opt = descriptor.options;
7583
7583
  if (!opt.script) return { value, warnings: [] };
7584
7584
  const mode = opt.onScriptViolation ?? "reject";
7585
7585
  const warnings = [];
7586
7586
  let out = value;
7587
7587
  for (const [locale, raw] of Object.entries(value)) {
7588
+ if (exempt?.has(locale)) continue;
7588
7589
  if (typeof raw !== "string") continue;
7589
7590
  const allowed = allowedFor(descriptor, locale);
7590
7591
  if (fullMatcher(allowed).test(raw)) continue;
@@ -7675,8 +7676,18 @@ var init_script = __esm({
7675
7676
 
7676
7677
  // src/i18n/core.ts
7677
7678
  function i18nText(options) {
7679
+ if (options.densifyOnWrite === true && hasThrowPolicy(options.onMissing)) {
7680
+ throw new Error(
7681
+ `i18nText: densifyOnWrite cannot be combined with an explicit onMissing 'throw' policy \u2014 densify fills every empty slot, so a 'throw' would be unreachable. Remove the 'throw' policy or disable densifyOnWrite.`
7682
+ );
7683
+ }
7678
7684
  return { _noydbI18nText: true, options };
7679
7685
  }
7686
+ function hasThrowPolicy(onMissing) {
7687
+ if (onMissing === void 0) return false;
7688
+ if (typeof onMissing === "string") return onMissing === "throw";
7689
+ return Object.values(onMissing).includes("throw");
7690
+ }
7680
7691
  function isI18nTextDescriptor(x) {
7681
7692
  return typeof x === "object" && x !== null && x._noydbI18nText === true;
7682
7693
  }
@@ -7874,8 +7885,15 @@ function applyI18nLocale(record, i18nFields, locale, fallback, layer = "read") {
7874
7885
  };
7875
7886
  result = applyAtPath(result, field, locale, fallback, opts);
7876
7887
  }
7888
+ result = stripI18nFilled(result);
7877
7889
  return result;
7878
7890
  }
7891
+ function stripI18nFilled(record) {
7892
+ if (!Object.prototype.hasOwnProperty.call(record, "_i18nFilled")) return record;
7893
+ const rest = { ...record };
7894
+ delete rest._i18nFilled;
7895
+ return rest;
7896
+ }
7879
7897
  var init_core = __esm({
7880
7898
  "src/i18n/core.ts"() {
7881
7899
  "use strict";
@@ -8905,6 +8923,11 @@ var init_strategy2 = __esm({
8905
8923
  enforceScript(value) {
8906
8924
  return { value, warnings: [] };
8907
8925
  },
8926
+ computeExemptFills() {
8927
+ return /* @__PURE__ */ new Map();
8928
+ },
8929
+ densify() {
8930
+ },
8908
8931
  buildDictionaryHandle() {
8909
8932
  throw notEnabled("vault.dictionary()");
8910
8933
  }
@@ -13868,6 +13891,12 @@ var init_collection = __esm({
13868
13891
  * Declared via the `i18nFields` collection option.
13869
13892
  */
13870
13893
  i18nFields;
13894
+ /**
13895
+ * #435 — the densify-enabled subset of {@link i18nFields} (fields whose
13896
+ * descriptor opts in via `densifyOnWrite: true`). `undefined` when none opt
13897
+ * in, so the write path skips all densify work for ordinary collections.
13898
+ */
13899
+ i18nDensifyFields;
13871
13900
  /**
13872
13901
  * Map of field name → `DictKeyDescriptor` for fields declared with
13873
13902
  * `dictKey()`. Used by `get()`/`list()` to add `<field>Label` virtual
@@ -14054,6 +14083,10 @@ var init_collection = __esm({
14054
14083
  this.refEnforcer = opts.refEnforcer;
14055
14084
  this.joinResolver = opts.joinResolver;
14056
14085
  this.i18nFields = opts.i18nFields;
14086
+ const densifyFields = opts.i18nFields ? Object.fromEntries(
14087
+ Object.entries(opts.i18nFields).filter(([, d]) => d.options.densifyOnWrite === true)
14088
+ ) : {};
14089
+ this.i18nDensifyFields = Object.keys(densifyFields).length > 0 ? densifyFields : void 0;
14057
14090
  this.dictKeyFields = opts.dictKeyFields;
14058
14091
  if (opts.moneyFields) validateMoneyFieldPaths(opts.moneyFields);
14059
14092
  this.moneyFields = opts.moneyFields;
@@ -14373,6 +14406,32 @@ var init_collection = __esm({
14373
14406
  if (busAfterPut) await this.subsystemBus.dispatch("afterPut", event);
14374
14407
  }
14375
14408
  }
14409
+ /**
14410
+ * #435 — resolve the prior stored record (with its `_i18nFilled` marker) for
14411
+ * densify. Eager: in-memory cache; lazy: LRU then adapter. undefined if absent.
14412
+ */
14413
+ async resolveDensifyPrior(id) {
14414
+ if (this.lazy && this.lru) {
14415
+ const cached = this.lru.get(id);
14416
+ if (cached) return cached.record;
14417
+ const env = await this.adapter.get(this.vault, this.name, id);
14418
+ if (!env) return void 0;
14419
+ const rec = await this.decryptRecord(env);
14420
+ return rec === null ? void 0 : rec;
14421
+ }
14422
+ await this.ensureHydrated();
14423
+ return this.cache.get(id)?.record;
14424
+ }
14425
+ /**
14426
+ * #435 — densify provenance for a record: which i18n slots were auto-filled,
14427
+ * e.g. `{ name: ['en'] }`. undefined when nothing was filled. The marker is
14428
+ * stripped from ordinary reads; this is the sanctioned audit accessor.
14429
+ */
14430
+ async i18nProvenance(id) {
14431
+ const prior = await this.resolveDensifyPrior(id);
14432
+ const marker = prior?.["_i18nFilled"];
14433
+ return marker && Object.keys(marker).length > 0 ? marker : void 0;
14434
+ }
14376
14435
  /**
14377
14436
  * Validate a record against this collection's schema WITHOUT writing it.
14378
14437
  * Returns the (possibly coerced) record on success; throws
@@ -14487,6 +14546,16 @@ var init_collection = __esm({
14487
14546
  setAtPathInPlace(obj, field, translated);
14488
14547
  }
14489
14548
  }
14549
+ let densifyPrior;
14550
+ let exemptFills;
14551
+ if (this.i18nDensifyFields) {
14552
+ densifyPrior = await this.resolveDensifyPrior(id);
14553
+ exemptFills = this.i18nStrategy.computeExemptFills(
14554
+ densifyPrior,
14555
+ record,
14556
+ this.i18nDensifyFields
14557
+ );
14558
+ }
14490
14559
  if (this.i18nFields) {
14491
14560
  const obj = record;
14492
14561
  for (const [field, descriptor] of Object.entries(this.i18nFields)) {
@@ -14494,18 +14563,38 @@ var init_collection = __esm({
14494
14563
  for (const leaf of getAtPath(obj, field)) {
14495
14564
  if (!leaf || typeof leaf !== "object" || Array.isArray(leaf)) continue;
14496
14565
  const leafMap = leaf;
14497
- const { value: cleaned } = this.i18nStrategy.enforceScript(
14566
+ const { value: cleaned, warnings } = this.i18nStrategy.enforceScript(
14498
14567
  leafMap,
14499
14568
  field,
14500
- descriptor
14569
+ descriptor,
14570
+ exemptFills?.get(field)
14501
14571
  );
14502
14572
  if (cleaned !== leafMap) Object.assign(leafMap, cleaned);
14573
+ const mode = descriptor.options.onScriptViolation;
14574
+ if (mode === "warn" || mode === "filter") {
14575
+ for (const w of warnings) {
14576
+ this.emitter.emit("i18n:script-violation", {
14577
+ vault: this.vault,
14578
+ collection: this.name,
14579
+ id,
14580
+ mode,
14581
+ warning: w
14582
+ });
14583
+ }
14584
+ }
14503
14585
  }
14504
14586
  }
14505
14587
  }
14506
14588
  if (this.i18nPutValidator !== void 0) {
14507
14589
  this.i18nPutValidator(record);
14508
14590
  }
14591
+ if (this.i18nDensifyFields) {
14592
+ this.i18nStrategy.densify(
14593
+ record,
14594
+ densifyPrior,
14595
+ this.i18nDensifyFields
14596
+ );
14597
+ }
14509
14598
  if (this.refEnforcer !== void 0) {
14510
14599
  await this.refEnforcer.enforceRefsOnPut(this.name, record);
14511
14600
  }
@@ -15359,7 +15448,7 @@ var init_collection = __esm({
15359
15448
  }
15360
15449
  await this.ensureHydrated();
15361
15450
  const entries = [];
15362
- for (const [id, e] of this.cache) entries.push({ id, record: e.record });
15451
+ for (const [id, e] of this.cache) entries.push({ id, record: stripI18nFilled(e.record) });
15363
15452
  return searchScan(entries, field, query, opts);
15364
15453
  }
15365
15454
  // ─── Bulk operations ─────────────────────────────────────
@@ -16273,7 +16362,7 @@ var init_collection = __esm({
16273
16362
  const hasStaticDisplay = hasDict && this.dictKeyFields !== void 0 && Object.values(this.dictKeyFields).some(
16274
16363
  (d) => isStaticDictDescriptor(d) && d.displayLocale !== void 0
16275
16364
  );
16276
- if (!locale && !hasStaticDisplay) return result;
16365
+ if (!locale && !hasStaticDisplay) return stripI18nFilled(result);
16277
16366
  const layer = localeOpts?._layer ?? "read";
16278
16367
  if (locale && hasI18n && this.i18nFields) {
16279
16368
  result = this.i18nStrategy.applyI18nLocale(result, this.i18nFields, locale, localeOpts?.fallback, layer);
@@ -16340,7 +16429,7 @@ var init_collection = __esm({
16340
16429
  }
16341
16430
  result = withLabels;
16342
16431
  }
16343
- return result;
16432
+ return stripI18nFilled(result);
16344
16433
  }
16345
16434
  /**
16346
16435
  * Low-level: encrypt a pre-serialised JSON string into an EncryptedEnvelope.