livelocale 0.8.0 → 0.9.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/README.md +230 -5
- package/dist/client/index.cjs +178 -70
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +36 -22
- package/dist/client/index.d.ts +36 -22
- package/dist/client/index.js +177 -70
- package/dist/client/index.js.map +1 -1
- package/dist/codemod/index.cjs +3057 -152
- package/dist/codemod/index.cjs.map +1 -1
- package/dist/codemod/index.js +3058 -153
- package/dist/codemod/index.js.map +1 -1
- package/dist/react/index.cjs +185 -77
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +185 -77
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +108 -66
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +13 -3
- package/dist/server/index.d.ts +13 -3
- package/dist/server/index.js +107 -66
- package/dist/server/index.js.map +1 -1
- package/dist/studio/assets/index-Bvbtkry-.css +1 -0
- package/dist/studio/assets/index-DC_jRsox.js +13 -0
- package/dist/studio/assets/inter-latin-300-normal-BVlfKGgI.woff2 +0 -0
- package/dist/studio/assets/inter-latin-300-normal-i8F0SvXL.woff +0 -0
- package/dist/studio/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/dist/studio/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- package/dist/studio/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- package/dist/studio/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/dist/studio/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
- package/dist/studio/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
- package/dist/studio/assets/inter-latin-700-normal-BLAVimhd.woff +0 -0
- package/dist/studio/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
- package/dist/studio/assets/outfit-latin-400-normal-BGsTXAXT.woff2 +0 -0
- package/dist/studio/assets/outfit-latin-400-normal-DMwTpYkH.woff +0 -0
- package/dist/studio/assets/outfit-latin-500-normal-ClnHRwRh.woff +0 -0
- package/dist/studio/assets/outfit-latin-500-normal-DKnIMDSk.woff2 +0 -0
- package/dist/studio/assets/outfit-latin-600-normal-B7SfZ07L.woff2 +0 -0
- package/dist/studio/assets/outfit-latin-600-normal-BEfTtDA7.woff +0 -0
- package/dist/studio/assets/outfit-latin-700-normal-Cu9v6i1X.woff2 +0 -0
- package/dist/studio/assets/outfit-latin-700-normal-D4itBLBr.woff +0 -0
- package/dist/studio/index.html +3 -6
- package/dist/vite/index.cjs +739 -77
- package/dist/vite/index.cjs.map +1 -1
- package/dist/vite/index.d.cts +22 -2
- package/dist/vite/index.d.ts +22 -2
- package/dist/vite/index.js +738 -77
- package/dist/vite/index.js.map +1 -1
- package/dist/{wrap-CsOtHp8r.d.cts → wrap-2qVxLN9Q.d.cts} +10 -18
- package/dist/{wrap-CsOtHp8r.d.ts → wrap-2qVxLN9Q.d.ts} +10 -18
- package/package.json +4 -1
- package/dist/studio/assets/index-D7ifnqy5.js +0 -10
- package/dist/studio/assets/index-Zh0KtFUH.css +0 -2
package/dist/server/index.d.cts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
export { W as WrapOptions, d as decodeKey, e as encodeKey, h as hasWatermark, s as sanitizeZeroWidth, a as stripWatermark, u as unwrap, w as wrapNextIntl, b as wrapTranslationEngine } from '../wrap-
|
|
1
|
+
export { W as WrapOptions, d as decodeKey, e as encodeKey, h as hasWatermark, r as removeWatermarks, s as sanitizeZeroWidth, a as stripWatermark, u as unwrap, w as wrapNextIntl, b as wrapTranslationEngine } from '../wrap-2qVxLN9Q.cjs';
|
|
2
2
|
|
|
3
|
+
interface FileMutatorOptions {
|
|
4
|
+
/** Refuse to run unless LiveLocale is enabled. Default true; only CLI tooling passes false. */
|
|
5
|
+
requireEnabled?: boolean;
|
|
6
|
+
/** Skip the console line each `updateLocaleKey` write prints. Default false. */
|
|
7
|
+
quiet?: boolean;
|
|
8
|
+
}
|
|
3
9
|
declare class FileMutator {
|
|
4
10
|
private fileLocks;
|
|
5
|
-
private
|
|
11
|
+
private readonly requireEnabled;
|
|
12
|
+
private readonly quiet;
|
|
13
|
+
private readonly scanner;
|
|
14
|
+
constructor(options?: FileMutatorOptions);
|
|
15
|
+
private assertEnabled;
|
|
6
16
|
/**
|
|
7
17
|
* Helper to serialize execution per file path
|
|
8
18
|
*/
|
|
@@ -359,4 +369,4 @@ declare function getLiveLocaleMode(): LiveLocaleMode;
|
|
|
359
369
|
/** True when watermarking, the mutation API, and the client scanner should run. */
|
|
360
370
|
declare function isLiveLocaleEnabled(): boolean;
|
|
361
371
|
|
|
362
|
-
export { type CreateTranslationsOptions, FileMutator, type GitChange, GitClient, type GitGateway, type GitHubGateway, type GitHubGatewayConfig, type GitStatus, type HandlerConfig, KeyScanner, type LiveLocaleMode, type MutationGateway, type MutationRouter, createGitHubGateway, createLiveLocaleHandler, createMutationRouter, createTranslations, getLiveLocaleMode, isLiveLocaleEnabled };
|
|
372
|
+
export { type CreateTranslationsOptions, FileMutator, type FileMutatorOptions, type GitChange, GitClient, type GitGateway, type GitHubGateway, type GitHubGatewayConfig, type GitStatus, type HandlerConfig, KeyScanner, type LiveLocaleMode, type MutationGateway, type MutationRouter, createGitHubGateway, createLiveLocaleHandler, createMutationRouter, createTranslations, getLiveLocaleMode, isLiveLocaleEnabled };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
export { W as WrapOptions, d as decodeKey, e as encodeKey, h as hasWatermark, s as sanitizeZeroWidth, a as stripWatermark, u as unwrap, w as wrapNextIntl, b as wrapTranslationEngine } from '../wrap-
|
|
1
|
+
export { W as WrapOptions, d as decodeKey, e as encodeKey, h as hasWatermark, r as removeWatermarks, s as sanitizeZeroWidth, a as stripWatermark, u as unwrap, w as wrapNextIntl, b as wrapTranslationEngine } from '../wrap-2qVxLN9Q.js';
|
|
2
2
|
|
|
3
|
+
interface FileMutatorOptions {
|
|
4
|
+
/** Refuse to run unless LiveLocale is enabled. Default true; only CLI tooling passes false. */
|
|
5
|
+
requireEnabled?: boolean;
|
|
6
|
+
/** Skip the console line each `updateLocaleKey` write prints. Default false. */
|
|
7
|
+
quiet?: boolean;
|
|
8
|
+
}
|
|
3
9
|
declare class FileMutator {
|
|
4
10
|
private fileLocks;
|
|
5
|
-
private
|
|
11
|
+
private readonly requireEnabled;
|
|
12
|
+
private readonly quiet;
|
|
13
|
+
private readonly scanner;
|
|
14
|
+
constructor(options?: FileMutatorOptions);
|
|
15
|
+
private assertEnabled;
|
|
6
16
|
/**
|
|
7
17
|
* Helper to serialize execution per file path
|
|
8
18
|
*/
|
|
@@ -359,4 +369,4 @@ declare function getLiveLocaleMode(): LiveLocaleMode;
|
|
|
359
369
|
/** True when watermarking, the mutation API, and the client scanner should run. */
|
|
360
370
|
declare function isLiveLocaleEnabled(): boolean;
|
|
361
371
|
|
|
362
|
-
export { type CreateTranslationsOptions, FileMutator, type GitChange, GitClient, type GitGateway, type GitHubGateway, type GitHubGatewayConfig, type GitStatus, type HandlerConfig, KeyScanner, type LiveLocaleMode, type MutationGateway, type MutationRouter, createGitHubGateway, createLiveLocaleHandler, createMutationRouter, createTranslations, getLiveLocaleMode, isLiveLocaleEnabled };
|
|
372
|
+
export { type CreateTranslationsOptions, FileMutator, type FileMutatorOptions, type GitChange, GitClient, type GitGateway, type GitHubGateway, type GitHubGatewayConfig, type GitStatus, type HandlerConfig, KeyScanner, type LiveLocaleMode, type MutationGateway, type MutationRouter, createGitHubGateway, createLiveLocaleHandler, createMutationRouter, createTranslations, getLiveLocaleMode, isLiveLocaleEnabled };
|
package/dist/server/index.js
CHANGED
|
@@ -540,14 +540,6 @@ var KeyScanner = class {
|
|
|
540
540
|
};
|
|
541
541
|
|
|
542
542
|
// src/server/file-mutator.ts
|
|
543
|
-
function assertEnabled(component) {
|
|
544
|
-
const reason = getDisabledReason();
|
|
545
|
-
if (reason !== null) {
|
|
546
|
-
throw new Error(
|
|
547
|
-
`[livelocale] ${component} can only be executed in development mode (${reason}).`
|
|
548
|
-
);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
543
|
var FileMutex = class {
|
|
552
544
|
queue = Promise.resolve();
|
|
553
545
|
async acquire(fn) {
|
|
@@ -563,7 +555,23 @@ var FileMutex = class {
|
|
|
563
555
|
};
|
|
564
556
|
var FileMutator = class {
|
|
565
557
|
fileLocks = /* @__PURE__ */ new Map();
|
|
566
|
-
|
|
558
|
+
requireEnabled;
|
|
559
|
+
quiet;
|
|
560
|
+
scanner;
|
|
561
|
+
constructor(options = {}) {
|
|
562
|
+
this.requireEnabled = options.requireEnabled ?? true;
|
|
563
|
+
this.quiet = options.quiet ?? false;
|
|
564
|
+
this.scanner = new KeyScanner({ requireEnabled: this.requireEnabled });
|
|
565
|
+
}
|
|
566
|
+
assertEnabled() {
|
|
567
|
+
if (!this.requireEnabled) return;
|
|
568
|
+
const reason = getDisabledReason();
|
|
569
|
+
if (reason !== null) {
|
|
570
|
+
throw new Error(
|
|
571
|
+
`[livelocale] FileMutator can only be executed in development mode (${reason}).`
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
567
575
|
/**
|
|
568
576
|
* Helper to serialize execution per file path
|
|
569
577
|
*/
|
|
@@ -581,7 +589,7 @@ var FileMutator = class {
|
|
|
581
589
|
* structural JSON validation, and concurrency serialization.
|
|
582
590
|
*/
|
|
583
591
|
async updateLocaleKey(basePath, locale, keyPath, newValue) {
|
|
584
|
-
assertEnabled(
|
|
592
|
+
this.assertEnabled();
|
|
585
593
|
if (!isSafeLocaleSegment(locale)) {
|
|
586
594
|
throw new Error(
|
|
587
595
|
`[livelocale] Path traversal attempt detected in locale identifier: "${locale}"`
|
|
@@ -684,7 +692,9 @@ var FileMutator = class {
|
|
|
684
692
|
`[livelocale] Failed to rename temp file to target at ${filePath}. Operation: rename. Original error: ${err.message}`
|
|
685
693
|
);
|
|
686
694
|
}
|
|
687
|
-
|
|
695
|
+
if (!this.quiet) {
|
|
696
|
+
console.log(`[livelocale] Updated key '${keyPath}' in locale '${locale}'`);
|
|
697
|
+
}
|
|
688
698
|
});
|
|
689
699
|
}
|
|
690
700
|
/**
|
|
@@ -692,7 +702,7 @@ var FileMutator = class {
|
|
|
692
702
|
* `*.json` inside the `{locale}/` folder merged under its namespace.
|
|
693
703
|
*/
|
|
694
704
|
async readLocale(basePath, locale) {
|
|
695
|
-
assertEnabled(
|
|
705
|
+
this.assertEnabled();
|
|
696
706
|
const localePath = path3.resolve(basePath, locale);
|
|
697
707
|
let isDir = false;
|
|
698
708
|
try {
|
|
@@ -719,7 +729,7 @@ var FileMutator = class {
|
|
|
719
729
|
* Lists all locale codes dynamically scanned from the locales directory.
|
|
720
730
|
*/
|
|
721
731
|
async listLocales(basePath) {
|
|
722
|
-
assertEnabled(
|
|
732
|
+
this.assertEnabled();
|
|
723
733
|
const resolvedBasePath = path3.resolve(basePath);
|
|
724
734
|
const items = await fs2.readdir(resolvedBasePath, { withFileTypes: true });
|
|
725
735
|
const localesSet = /* @__PURE__ */ new Set();
|
|
@@ -741,7 +751,7 @@ var FileMutator = class {
|
|
|
741
751
|
* Adds a new locale directory/file based on current repository structure.
|
|
742
752
|
*/
|
|
743
753
|
async addLocale(basePath, locale) {
|
|
744
|
-
assertEnabled(
|
|
754
|
+
this.assertEnabled();
|
|
745
755
|
if (!isSafeLocaleSegment(locale)) {
|
|
746
756
|
throw new Error(
|
|
747
757
|
`[livelocale] Path traversal attempt detected in locale identifier: "${locale}"`
|
|
@@ -797,7 +807,7 @@ var FileMutator = class {
|
|
|
797
807
|
* Renames an existing locale (directory or file) to a new name.
|
|
798
808
|
*/
|
|
799
809
|
async renameLocale(basePath, oldLocale, newLocale) {
|
|
800
|
-
assertEnabled(
|
|
810
|
+
this.assertEnabled();
|
|
801
811
|
if (!isSafeLocaleSegment(oldLocale) || !isSafeLocaleSegment(newLocale)) {
|
|
802
812
|
throw new Error("[livelocale] Path traversal attempt detected");
|
|
803
813
|
}
|
|
@@ -855,7 +865,7 @@ var FileMutator = class {
|
|
|
855
865
|
* Deletes an existing locale (directory or file).
|
|
856
866
|
*/
|
|
857
867
|
async deleteLocale(basePath, locale) {
|
|
858
|
-
assertEnabled(
|
|
868
|
+
this.assertEnabled();
|
|
859
869
|
if (!isSafeLocaleSegment(locale)) {
|
|
860
870
|
throw new Error("[livelocale] Path traversal attempt detected");
|
|
861
871
|
}
|
|
@@ -1646,6 +1656,67 @@ function validateMessageSyntax(message) {
|
|
|
1646
1656
|
return parseIcu(prepared).error;
|
|
1647
1657
|
}
|
|
1648
1658
|
|
|
1659
|
+
// src/core/save-rules.ts
|
|
1660
|
+
var reject = (status, code, error) => ({
|
|
1661
|
+
ok: false,
|
|
1662
|
+
status,
|
|
1663
|
+
code,
|
|
1664
|
+
error
|
|
1665
|
+
});
|
|
1666
|
+
function validateWrite(input, options = {}) {
|
|
1667
|
+
const { locale, key, value } = input;
|
|
1668
|
+
if (!isValidLocaleFormat(locale)) {
|
|
1669
|
+
return reject(400, "INVALID_LOCALE_FORMAT", "Invalid locale string parameter.");
|
|
1670
|
+
}
|
|
1671
|
+
if (!isValidKeyFormat(key)) {
|
|
1672
|
+
return reject(
|
|
1673
|
+
400,
|
|
1674
|
+
"INVALID_KEY_FORMAT",
|
|
1675
|
+
"Invalid key path. Must be 1-200 characters containing alphanumeric, dots, underscores, or hyphens."
|
|
1676
|
+
);
|
|
1677
|
+
}
|
|
1678
|
+
if (!isSafeKeyPath(key)) {
|
|
1679
|
+
return reject(
|
|
1680
|
+
400,
|
|
1681
|
+
"INVALID_KEY_FORMAT",
|
|
1682
|
+
"Forbidden key path: segments like __proto__, constructor, or prototype are not allowed."
|
|
1683
|
+
);
|
|
1684
|
+
}
|
|
1685
|
+
if (!isValidValueFormat(value)) {
|
|
1686
|
+
return reject(
|
|
1687
|
+
400,
|
|
1688
|
+
"INVALID_VALUE_FORMAT",
|
|
1689
|
+
"Invalid value. Must be a string less than 10000 characters."
|
|
1690
|
+
);
|
|
1691
|
+
}
|
|
1692
|
+
const accepted = {
|
|
1693
|
+
ok: true,
|
|
1694
|
+
locale,
|
|
1695
|
+
key,
|
|
1696
|
+
value
|
|
1697
|
+
};
|
|
1698
|
+
if (options.force === true) return accepted;
|
|
1699
|
+
const syntaxError = validateMessageSyntax(accepted.value);
|
|
1700
|
+
if (syntaxError) {
|
|
1701
|
+
return reject(422, "MESSAGE_SYNTAX", `Message syntax: ${syntaxError}.`);
|
|
1702
|
+
}
|
|
1703
|
+
const comparison = comparePlaceholders(options.reference, accepted.value);
|
|
1704
|
+
if (!comparison.ok) {
|
|
1705
|
+
const parts = [];
|
|
1706
|
+
if (comparison.missing.length) parts.push(`missing ${comparison.missing.join(", ")}`);
|
|
1707
|
+
if (comparison.extra.length) parts.push(`unexpected ${comparison.extra.join(", ")}`);
|
|
1708
|
+
return {
|
|
1709
|
+
...reject(
|
|
1710
|
+
422,
|
|
1711
|
+
"PLACEHOLDER_MISMATCH",
|
|
1712
|
+
`Placeholders differ from the reference: ${parts.join("; ")}.`
|
|
1713
|
+
),
|
|
1714
|
+
details: { missing: comparison.missing, extra: comparison.extra }
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
return accepted;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1649
1720
|
// src/server/router.ts
|
|
1650
1721
|
var DEFAULT_ALLOWED_ORIGINS = ["http://localhost:3010", "http://127.0.0.1:3010"];
|
|
1651
1722
|
var MAX_BODY_BYTES = 1e6;
|
|
@@ -1833,53 +1904,18 @@ function createMutationRouter(mutator, options) {
|
|
|
1833
1904
|
await mutator.deleteLocale(basePath, locale);
|
|
1834
1905
|
return json(200, headers, { success: true, locale });
|
|
1835
1906
|
}
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
code: "INVALID_KEY_FORMAT"
|
|
1846
|
-
});
|
|
1847
|
-
}
|
|
1848
|
-
if (!isSafeKeyPath(key)) {
|
|
1849
|
-
return json(400, headers, {
|
|
1850
|
-
error: "Forbidden key path: segments like __proto__, constructor, or prototype are not allowed.",
|
|
1851
|
-
code: "INVALID_KEY_FORMAT"
|
|
1852
|
-
});
|
|
1853
|
-
}
|
|
1854
|
-
if (!isValidValueFormat(value)) {
|
|
1855
|
-
return json(400, headers, {
|
|
1856
|
-
error: "Invalid value. Must be a string less than 10000 characters.",
|
|
1857
|
-
code: "INVALID_VALUE_FORMAT"
|
|
1907
|
+
const verdict = validateWrite(
|
|
1908
|
+
{ locale, key, value },
|
|
1909
|
+
{ reference: typeof reference === "string" ? reference : null, force: force === true }
|
|
1910
|
+
);
|
|
1911
|
+
if (!verdict.ok) {
|
|
1912
|
+
return json(verdict.status, headers, {
|
|
1913
|
+
error: verdict.error,
|
|
1914
|
+
code: verdict.code,
|
|
1915
|
+
details: verdict.details
|
|
1858
1916
|
});
|
|
1859
1917
|
}
|
|
1860
|
-
|
|
1861
|
-
const syntaxError = validateMessageSyntax(value);
|
|
1862
|
-
if (syntaxError) {
|
|
1863
|
-
return json(422, headers, {
|
|
1864
|
-
error: `Message syntax: ${syntaxError}.`,
|
|
1865
|
-
code: "MESSAGE_SYNTAX"
|
|
1866
|
-
});
|
|
1867
|
-
}
|
|
1868
|
-
if (typeof reference === "string") {
|
|
1869
|
-
const comparison = comparePlaceholders(reference, value);
|
|
1870
|
-
if (!comparison.ok) {
|
|
1871
|
-
const parts = [];
|
|
1872
|
-
if (comparison.missing.length) parts.push(`missing ${comparison.missing.join(", ")}`);
|
|
1873
|
-
if (comparison.extra.length) parts.push(`unexpected ${comparison.extra.join(", ")}`);
|
|
1874
|
-
return json(422, headers, {
|
|
1875
|
-
error: `Placeholders differ from the reference: ${parts.join("; ")}.`,
|
|
1876
|
-
code: "PLACEHOLDER_MISMATCH",
|
|
1877
|
-
details: { missing: comparison.missing, extra: comparison.extra }
|
|
1878
|
-
});
|
|
1879
|
-
}
|
|
1880
|
-
}
|
|
1881
|
-
}
|
|
1882
|
-
await mutator.updateLocaleKey(basePath, locale, key, value);
|
|
1918
|
+
await mutator.updateLocaleKey(basePath, verdict.locale, verdict.key, verdict.value);
|
|
1883
1919
|
return json(200, headers, { success: true, key, locale });
|
|
1884
1920
|
}
|
|
1885
1921
|
return {
|
|
@@ -1953,7 +1989,7 @@ var BodyTooLargeError = class extends Error {
|
|
|
1953
1989
|
}
|
|
1954
1990
|
};
|
|
1955
1991
|
function readNodeBody(req, maxBytes) {
|
|
1956
|
-
return new Promise((resolve5,
|
|
1992
|
+
return new Promise((resolve5, reject2) => {
|
|
1957
1993
|
let bodyText = "";
|
|
1958
1994
|
let settled = false;
|
|
1959
1995
|
req.on("data", (chunk) => {
|
|
@@ -1961,7 +1997,7 @@ function readNodeBody(req, maxBytes) {
|
|
|
1961
1997
|
bodyText += chunk.toString();
|
|
1962
1998
|
if (Buffer.byteLength(bodyText, "utf-8") > maxBytes) {
|
|
1963
1999
|
settled = true;
|
|
1964
|
-
|
|
2000
|
+
reject2(new BodyTooLargeError());
|
|
1965
2001
|
req.destroy?.();
|
|
1966
2002
|
}
|
|
1967
2003
|
});
|
|
@@ -1973,7 +2009,7 @@ function readNodeBody(req, maxBytes) {
|
|
|
1973
2009
|
req.on("error", (err) => {
|
|
1974
2010
|
if (settled) return;
|
|
1975
2011
|
settled = true;
|
|
1976
|
-
|
|
2012
|
+
reject2(err);
|
|
1977
2013
|
});
|
|
1978
2014
|
});
|
|
1979
2015
|
}
|
|
@@ -2073,10 +2109,11 @@ import { readdirSync, statSync as statSync2 } from "fs";
|
|
|
2073
2109
|
import { join as join4 } from "path";
|
|
2074
2110
|
|
|
2075
2111
|
// src/client/watermark.ts
|
|
2076
|
-
var DELIM = "\
|
|
2112
|
+
var DELIM = "\u200C";
|
|
2077
2113
|
var BIT_0 = "\u200B";
|
|
2078
|
-
var BIT_1 = "\
|
|
2114
|
+
var BIT_1 = "\u200D";
|
|
2079
2115
|
var ZW_RE = /[\u200B\u200C\u200D]/g;
|
|
2116
|
+
var WATERMARK_RE = /\u200C(?:[\u200B\u200D]{8})+\u200C/g;
|
|
2080
2117
|
function encodeKey(text, key) {
|
|
2081
2118
|
const bytes = new TextEncoder().encode(key);
|
|
2082
2119
|
let bits = "";
|
|
@@ -2123,6 +2160,9 @@ function stripWatermark(text) {
|
|
|
2123
2160
|
function sanitizeZeroWidth(text) {
|
|
2124
2161
|
return text.replace(ZW_RE, "");
|
|
2125
2162
|
}
|
|
2163
|
+
function removeWatermarks(text) {
|
|
2164
|
+
return text.replace(WATERMARK_RE, "");
|
|
2165
|
+
}
|
|
2126
2166
|
function hasWatermark(text) {
|
|
2127
2167
|
return text.startsWith(DELIM);
|
|
2128
2168
|
}
|
|
@@ -2372,6 +2412,7 @@ export {
|
|
|
2372
2412
|
getLiveLocaleMode,
|
|
2373
2413
|
hasWatermark,
|
|
2374
2414
|
isLiveLocaleEnabled,
|
|
2415
|
+
removeWatermarks,
|
|
2375
2416
|
sanitizeZeroWidth,
|
|
2376
2417
|
stripWatermark,
|
|
2377
2418
|
unwrap,
|