@plasius/schema 1.3.0 → 1.3.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.
- package/README.md +188 -1
- package/THIRD_PARTY_NOTICES.md +75 -0
- package/dist/chunk-6FE4FLKF.js +254 -0
- package/dist/chunk-6FE4FLKF.js.map +1 -0
- package/dist/chunk-AG2NAPDC.js +117 -0
- package/dist/chunk-AG2NAPDC.js.map +1 -0
- package/dist/chunk-UQHPDQZX.js +2606 -0
- package/dist/chunk-UQHPDQZX.js.map +1 -0
- package/dist/feedback-diagnostics-BaniQAFS.d.cts +353 -0
- package/dist/feedback-diagnostics-CnsI0B9-.d.ts +353 -0
- package/dist/feedback-diagnostics-vocabulary.cjs +156 -0
- package/dist/feedback-diagnostics-vocabulary.cjs.map +1 -0
- package/dist/feedback-diagnostics-vocabulary.d.cts +70 -0
- package/dist/feedback-diagnostics-vocabulary.d.ts +70 -0
- package/dist/feedback-diagnostics-vocabulary.js +33 -0
- package/dist/feedback-diagnostics-vocabulary.js.map +1 -0
- package/dist/feedback-diagnostics.cjs +2696 -0
- package/dist/feedback-diagnostics.cjs.map +1 -0
- package/dist/feedback-diagnostics.d.cts +2 -0
- package/dist/feedback-diagnostics.d.ts +2 -0
- package/dist/feedback-diagnostics.js +39 -0
- package/dist/feedback-diagnostics.js.map +1 -0
- package/dist/feedback-unicode-profile.cjs +283 -0
- package/dist/feedback-unicode-profile.cjs.map +1 -0
- package/dist/feedback-unicode-profile.d.cts +28 -0
- package/dist/feedback-unicode-profile.d.ts +28 -0
- package/dist/feedback-unicode-profile.js +13 -0
- package/dist/feedback-unicode-profile.js.map +1 -0
- package/dist/index.cjs +2133 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +879 -286
- package/dist/index.d.ts +879 -286
- package/dist/index.js +1516 -2300
- package/dist/index.js.map +1 -1
- package/package.json +36 -12
- package/unicode/feedback-unicode-15.1.0-unassigned.json +13 -0
package/README.md
CHANGED
|
@@ -20,6 +20,23 @@ Apache-2.0. ESM + CJS builds. TypeScript types included.
|
|
|
20
20
|
npm install @plasius/schema
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
## Personal names and display names
|
|
24
|
+
|
|
25
|
+
Use `validateName` for first, middle, and last names. It accepts Unicode
|
|
26
|
+
letters and combining marks together with common name punctuation, but it does
|
|
27
|
+
not accept digits. Use `validateDisplayName` for public display names, where
|
|
28
|
+
Unicode decimal digits are also valid:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { validateDisplayName, validateName } from "@plasius/schema";
|
|
32
|
+
|
|
33
|
+
validateDisplayName("Player 2"); // true
|
|
34
|
+
validateName("Player 2"); // false
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Both validators reject empty values, control characters, unsupported symbols,
|
|
38
|
+
and values longer than 256 characters.
|
|
39
|
+
|
|
23
40
|
## Packaging policy (template baseline)
|
|
24
41
|
|
|
25
42
|
`@plasius/schema` is the baseline template for new `@plasius/*` packages.
|
|
@@ -49,6 +66,152 @@ Only the stable `playerId` is treated as a personal identifier. It is retained
|
|
|
49
66
|
for storage partitioning and pseudonymized by `sanitizeForLog`; unknown fields
|
|
50
67
|
and hidden server truth are excluded by schema serialization.
|
|
51
68
|
|
|
69
|
+
## Privacy-safe feedback contracts
|
|
70
|
+
|
|
71
|
+
The package exports closed, versioned contracts for feedback intake and
|
|
72
|
+
reporting:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import {
|
|
76
|
+
FeedbackBugPacketSchema,
|
|
77
|
+
FeedbackPublicSummarySchema,
|
|
78
|
+
FeedbackRichTextAstSchema,
|
|
79
|
+
FeedbackReviewPacketSchema,
|
|
80
|
+
FeedbackTransientAnalysisRequestSchema,
|
|
81
|
+
validateFeedbackTransientAnalysisRequest,
|
|
82
|
+
} from "@plasius/schema";
|
|
83
|
+
import type {
|
|
84
|
+
FeedbackBugTransientAnalysisRequest,
|
|
85
|
+
FeedbackReviewTransientAnalysisRequest,
|
|
86
|
+
} from "@plasius/schema";
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Renderer and browser packages that need only the game-diagnostics vocabulary
|
|
90
|
+
should import `@plasius/schema/feedback-diagnostics-vocabulary`. This
|
|
91
|
+
lightweight entrypoint exports the canonical surface/provenance pairs, buckets,
|
|
92
|
+
feature/counter/error allowlists, bounds, and discriminated type without
|
|
93
|
+
loading the schema builder. Server validation and analysis tools should import
|
|
94
|
+
`@plasius/schema/feedback-diagnostics`, which adds the canonical runtime schema.
|
|
95
|
+
Both entrypoints derive from the same source definitions and preserve
|
|
96
|
+
structural parity in ESM and CommonJS builds, so consumers cannot maintain a
|
|
97
|
+
second diagnostics dialect. Use `validateFeedbackGameDiagnostics()` when a
|
|
98
|
+
consumer needs a validation result whose `value` retains the correlated
|
|
99
|
+
`FeedbackGameDiagnostics` TypeScript type.
|
|
100
|
+
|
|
101
|
+
Free-form feedback exists only in `FeedbackRichTextAstSchema`, which is
|
|
102
|
+
intended for a transient no-retention scanner. Its text nodes are marked
|
|
103
|
+
high-PII, clear-on-storage, and omit-from-logs. The interoperable document is
|
|
104
|
+
rooted at
|
|
105
|
+
`{ type: "doc", version: "1.0.0", schemaVersion: "1", children }`; it permits
|
|
106
|
+
only paragraph and bullet-list-item blocks with bounded indentation and text
|
|
107
|
+
nodes with bold, italic, and underline marks. Narrative must already be NFKC
|
|
108
|
+
normalised against the exported `unicode-15.1.0-nfkc-v1` profile before
|
|
109
|
+
validation. Assignment is checked against the original code units before host
|
|
110
|
+
NFKC is invoked. Its 4,000-character ceiling counts Unicode code points and
|
|
111
|
+
inter-block newlines consistently with the private scanner, with a separate
|
|
112
|
+
8,000 UTF-16-unit safety ceiling. HTML, Markdown links, protocol-relative
|
|
113
|
+
links, and `http`, `https`, `ftp`, `mailto`, `javascript`, `data`, `blob`, and
|
|
114
|
+
`file` schemes are rejected.
|
|
115
|
+
|
|
116
|
+
`FeedbackTransientAnalysisRequestSchema` is closed and discriminated by
|
|
117
|
+
`purpose`. A bug analysis request must carry a closed `surfaceId`; the service
|
|
118
|
+
must verify it against the caller's capability-projected catalog before
|
|
119
|
+
handing ciphertext to the private scanner. A review analysis request must omit
|
|
120
|
+
`surfaceId`. The exported bug/review request types preserve the same
|
|
121
|
+
discriminator for TypeScript consumers;
|
|
122
|
+
`validateFeedbackTransientAnalysisRequest()` preserves that union on
|
|
123
|
+
successful runtime validation.
|
|
124
|
+
|
|
125
|
+
Final bug and review JSON bodies deliberately contain no `submissionId`.
|
|
126
|
+
Consuming HTTP APIs require `Idempotency-Key` as the sole final-submission
|
|
127
|
+
correlation mechanism and keep it in the isolated abuse/idempotency control
|
|
128
|
+
plane. It must never be copied into a draft, accepted packet, report, log, or
|
|
129
|
+
public/Admin/MCP projection.
|
|
130
|
+
|
|
131
|
+
The complete Unicode 15.1 unassigned corpus is shipped independently of the
|
|
132
|
+
host runtime:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import {
|
|
136
|
+
FEEDBACK_UNICODE_PROFILE_ENDPOINT_SHA256,
|
|
137
|
+
FEEDBACK_UNICODE_PROFILE_ID,
|
|
138
|
+
containsFeedbackUnicodeProfileUnsupportedText,
|
|
139
|
+
isFeedbackUnicodeProfileUnassigned,
|
|
140
|
+
} from "@plasius/schema/feedback-unicode-profile";
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`containsFeedbackUnicodeProfileUnsupportedText` rejects every code point
|
|
144
|
+
unassigned in Unicode 15.1 and every lone UTF-16 surrogate. The code-point
|
|
145
|
+
helper decodes canonical, delta ULEB128/base64url once and uses binary search
|
|
146
|
+
over 707 half-open ranges. Non-JavaScript scanners can consume the same
|
|
147
|
+
language-neutral corpus from
|
|
148
|
+
`@plasius/schema/unicode/feedback-unicode-15.1.0-unassigned.json` and verify
|
|
149
|
+
its published endpoint digest. The corpus is generated from the exact
|
|
150
|
+
build-time dependency `@unicode/unicode-15.1.0@1.6.17`; run
|
|
151
|
+
`npm run unicode:check` to prove the checked-in artifact is current. See
|
|
152
|
+
[ADR-0007](./docs/adrs/adr-0007-pinned-unicode-feedback-profile.md) and
|
|
153
|
+
[third-party notices](./THIRD_PARTY_NOTICES.md).
|
|
154
|
+
|
|
155
|
+
Validated reusable fragments retain exact `type` and `version` metadata when
|
|
156
|
+
embedded in parent contracts. This makes the output of the encrypted-envelope,
|
|
157
|
+
derived-analysis, and game-diagnostics schemas directly composable into their
|
|
158
|
+
request or packet schemas without a metadata-stripping step.
|
|
159
|
+
|
|
160
|
+
Accepted packet, diagnostics, report, checkpoint, and public-summary schemas
|
|
161
|
+
cannot express narrative, reporter identity or pseudonyms, network/client
|
|
162
|
+
metadata, arbitrary URLs, pixels, quotes, summaries, embeddings, content
|
|
163
|
+
hashes, or model traces. Game surfaces, provenance contracts, features,
|
|
164
|
+
counters, and error codes are closed enums rather than attacker-controlled
|
|
165
|
+
safe-looking strings. The public summary omits counts, averages, and trends
|
|
166
|
+
entirely when the ten-review privacy threshold is not met and always carries
|
|
167
|
+
13 canonical UTC week slots, using suppressed gaps where a week is below the
|
|
168
|
+
same threshold. A trend is emitted only with a preceding 90-day comparison
|
|
169
|
+
that independently meets the ten-review threshold; the schema derives its
|
|
170
|
+
delta and enforces `up`/`down` only at a change of at least 0.1 stars.
|
|
171
|
+
|
|
172
|
+
Hourly reports bind targets to the closed surface registry and include
|
|
173
|
+
renderer/backend/viewport/frame-rate/frame-time plus closed diagnostic
|
|
174
|
+
feature/counter/error distributions. Release IDs and build IDs are
|
|
175
|
+
server-registry values: intake clients never submit them, and consumers must
|
|
176
|
+
resolve them from trusted deployment metadata before packet construction.
|
|
177
|
+
Advisory trigger counts and ordered recommendation IDs are derived exactly
|
|
178
|
+
from the report distributions and processor lag rather than accepted as
|
|
179
|
+
free-standing claims. Feedback context caps remaining bug cooldown at 24
|
|
180
|
+
hours and review suppression at 30 days; acceptance receipts distinguish bugs
|
|
181
|
+
from reviews and accept only the five-step bug ladder or exact 30-day review
|
|
182
|
+
period.
|
|
183
|
+
|
|
184
|
+
All feedback contracts opt in to recursive unknown-field rejection, including
|
|
185
|
+
direct references and arrays of references. Unshaped references admit only
|
|
186
|
+
`type` and `id`; shaped references admit only those keys plus their declared
|
|
187
|
+
fields. Closed feedback vocabularies and definition objects are runtime frozen
|
|
188
|
+
before schemas capture them. Before recursive cloning, strict validation also
|
|
189
|
+
performs an iterative whole-value node/depth budget so malformed containers
|
|
190
|
+
hidden under scalar fields cannot exhaust the call stack. The
|
|
191
|
+
general schema default remains backwards-compatible stripping:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
const ClosedPacket = createSchema(fields, "closed-packet", {
|
|
195
|
+
version: "1.0.0",
|
|
196
|
+
piiEnforcement: "strict",
|
|
197
|
+
unknownFields: "reject",
|
|
198
|
+
identity: "exact",
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Schema-level validators receive an optional, frozen
|
|
203
|
+
`SchemaValidationContext` with only `wasProvided(fieldName)`. This lets a
|
|
204
|
+
closed discriminator distinguish omission from an explicit `null` without
|
|
205
|
+
giving validation hooks access to raw field values.
|
|
206
|
+
|
|
207
|
+
Unknown-field errors name only the schema-owned container and never echo an
|
|
208
|
+
untrusted key or value. Exact identity rejects a mismatched contract type or
|
|
209
|
+
version. The schemas constrain data shape; consumers must still
|
|
210
|
+
perform the documented private PII scan, discard narrative immediately, and
|
|
211
|
+
validate again before every storage write. See the
|
|
212
|
+
[feedback contract design](./docs/design/feedback-contracts.md) and
|
|
213
|
+
[ADR-0006](./docs/adrs/adr-0006-privacy-safe-feedback-contract-boundaries.md).
|
|
214
|
+
|
|
52
215
|
## Demo
|
|
53
216
|
|
|
54
217
|
```bash
|
|
@@ -62,7 +225,7 @@ See `demo/README.md` for the local sanity-check scaffold.
|
|
|
62
225
|
|
|
63
226
|
## Node.js Version
|
|
64
227
|
|
|
65
|
-
This project uses Node.js **
|
|
228
|
+
This project uses Node.js **24** by default. The version is pinned in the [`.nvmrc`](./.nvmrc) file.
|
|
66
229
|
|
|
67
230
|
If you use [nvm](https://github.com/nvm-sh/nvm), simply run:
|
|
68
231
|
|
|
@@ -303,3 +466,27 @@ We welcome contributions! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for gu
|
|
|
303
466
|
## License
|
|
304
467
|
|
|
305
468
|
Licensed under the [Apache-2.0 License](./LICENSE).
|
|
469
|
+
|
|
470
|
+
<!-- BEGIN PLASIUS RELEASE INTEGRITY -->
|
|
471
|
+
## Release integrity
|
|
472
|
+
|
|
473
|
+
CI keeps the administrative contributor registry outside Git and npm package
|
|
474
|
+
artifacts using exact, case-normalised path checks. Pull requests run on
|
|
475
|
+
GitHub-hosted runners after same-repository admission; protected `main` CI uses
|
|
476
|
+
the workflow-restricted self-hosted group. Release preparation and npm
|
|
477
|
+
publication use GitHub-hosted runners with Node.js 24.18.0 LTS.
|
|
478
|
+
|
|
479
|
+
Dispatch `cd.yml` from protected `main` with `phase: prepare`. Release metadata
|
|
480
|
+
lands through a unique pull request. After successful push-triggered CI for the
|
|
481
|
+
exact merge SHA, the workflow dispatches a separate `publish` run from that
|
|
482
|
+
same SHA. Publication fails closed if `main`, CI evidence, the version, tag,
|
|
483
|
+
prerelease identity, artifact digests, or npm registry integrity differ.
|
|
484
|
+
|
|
485
|
+
The read-only validation job installs dependencies, validates the package,
|
|
486
|
+
builds an SBOM, and seals an immutable tarball. The `production` job runs no
|
|
487
|
+
package lifecycle or dependency code; it verifies the exact artifact hand-off
|
|
488
|
+
and publishes that tarball through npm OIDC with provenance. No npm write token
|
|
489
|
+
or fallback is configured. The trusted publisher must be bound to
|
|
490
|
+
`Plasius-LTD/schema`, `cd.yml`, `production`, and `npm publish`. Rollback is to
|
|
491
|
+
disable `cd.yml`; never restore token-based publication.
|
|
492
|
+
<!-- END PLASIUS RELEASE INTEGRITY -->
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Third-Party Notices
|
|
2
|
+
|
|
3
|
+
The distributed projection
|
|
4
|
+
`unicode/feedback-unicode-15.1.0-unassigned.json` is generated from
|
|
5
|
+
`@unicode/unicode-15.1.0` version `1.6.17`, specifically its
|
|
6
|
+
`General_Category/Unassigned` ranges. The pinned package metadata identifies
|
|
7
|
+
Mathias Bynens as the author and declares the MIT license. Its data is derived
|
|
8
|
+
from Unicode data files. Both applicable notices are reproduced below.
|
|
9
|
+
|
|
10
|
+
## `@unicode/unicode-15.1.0` — MIT License
|
|
11
|
+
|
|
12
|
+
Copyright Mathias Bynens <https://mathiasbynens.be/>
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
15
|
+
a copy of this software and associated documentation files (the
|
|
16
|
+
"Software"), to deal in the Software without restriction, including
|
|
17
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
18
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
19
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
20
|
+
the following conditions:
|
|
21
|
+
|
|
22
|
+
The above copyright notice and this permission notice shall be
|
|
23
|
+
included in all copies or substantial portions of the Software.
|
|
24
|
+
|
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
26
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
27
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
28
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
29
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
30
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
31
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
32
|
+
|
|
33
|
+
## Unicode License V3
|
|
34
|
+
|
|
35
|
+
UNICODE LICENSE V3
|
|
36
|
+
|
|
37
|
+
COPYRIGHT AND PERMISSION NOTICE
|
|
38
|
+
|
|
39
|
+
Copyright © 2016-2025 Unicode, Inc.
|
|
40
|
+
|
|
41
|
+
NOTICE TO USER: Carefully read the following legal agreement. BY
|
|
42
|
+
DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
|
|
43
|
+
SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
|
|
44
|
+
TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
|
|
45
|
+
DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
|
|
46
|
+
|
|
47
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
|
48
|
+
copy of data files and any associated documentation (the "Data Files") or
|
|
49
|
+
software and any associated documentation (the "Software") to deal in the
|
|
50
|
+
Data Files or Software without restriction, including without limitation
|
|
51
|
+
the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
|
52
|
+
copies of the Data Files or Software, and to permit persons to whom the
|
|
53
|
+
Data Files or Software are furnished to do so, provided that either (a)
|
|
54
|
+
this copyright and permission notice appear with all copies of the Data
|
|
55
|
+
Files or Software, or (b) this copyright and permission notice appear in
|
|
56
|
+
associated Documentation.
|
|
57
|
+
|
|
58
|
+
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
|
59
|
+
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
60
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
61
|
+
THIRD PARTY RIGHTS.
|
|
62
|
+
|
|
63
|
+
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
|
|
64
|
+
BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
|
|
65
|
+
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
66
|
+
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
|
67
|
+
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
|
|
68
|
+
FILES OR SOFTWARE.
|
|
69
|
+
|
|
70
|
+
Except as contained in this notice, the name of a copyright holder shall
|
|
71
|
+
not be used in advertising or otherwise to promote the sale, use or other
|
|
72
|
+
dealings in these Data Files or Software without prior written
|
|
73
|
+
authorization of the copyright holder.
|
|
74
|
+
|
|
75
|
+
SPDX-License-Identifier: Unicode-3.0
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// unicode/feedback-unicode-15.1.0-unassigned.json
|
|
2
|
+
var feedback_unicode_15_1_0_unassigned_default = {
|
|
3
|
+
profileId: "unicode-15.1.0-nfkc-v1",
|
|
4
|
+
unicodeVersion: "15.1.0",
|
|
5
|
+
sourcePackage: "@unicode/unicode-15.1.0",
|
|
6
|
+
sourcePackageVersion: "1.6.17",
|
|
7
|
+
sourceProperty: "General_Category/Unassigned",
|
|
8
|
+
rangeEncoding: "flat-half-open-delta-uleb128-base64url-v1",
|
|
9
|
+
rangeCount: 707,
|
|
10
|
+
endpointCount: 1414,
|
|
11
|
+
codePointCount: 824718,
|
|
12
|
+
endpointSha256: "591e457524d6b4b988aa7c7687e76c95a78370fea38bbd1b09085be7fd935ef3",
|
|
13
|
+
payload: "-AYCBgQHAQEBFAGNAwEmAjICAwE3CBsEBguOAgE8AmUOOwIxAg8BHAIBAQsFHwECBuwBAQgCAgIWAQcBAQMEAgkCAgIECAEEAgEFAhkCAwEGBAICFgEHAQIBAgECAgEBBQQCAgMDAQcEAQEHEQoDAQkBAwEWAQcBAgEFAgoBAwEDAgEPBAIMBwcBAwEIAgICFgEHAQIBBQIJAgICAwcDBAIBBQISCgIBBgMDAQQDAgEBAQIDAgMDAwwEBQMDAQQCAQYBDhUFDQEDARcBEAIJAQMBBAcCAQMCAQIEAgoHFgEDARcBCgEFAgkBAwEEBwIGAgEEAgoBAwwNAQMBMwEDAQYEEAIaAQMBEgMYAQkBAQIHAwEEBgEBAQgGCgIDDDoEHSUCAQEBBQEYAQEBFwIFAQEBBwEKAgQgSAEkBCcBJAEPAQ0lxgEBAQUBAvkCAQQCBwEBAQQCKQEEAiEBBAIHAQEBBAIPATkBBAJDAiADGgZWAgYCnQUDWQcWCRgJFAwNAQMBAgxeAgoGCgYaBlkHKwVGCh8BDAQMBAEDKgIFCywEGgYLAz4CQQEdAgsGCgYOAh8xTQMvAXQIPAMPAzwHKwILCCsFlgQCBgImAgYCCAEBAQEBAQEfAjUBDwEOAgYBEwIDAQkBZQEMAhsBDQMhDyEPjAEElwUZCxWUDgIgAd0CBS0BAQUBAjgHAg4YCQcBBwEHAQcBBwEHAQcBBwF-IhoBWQzWARpQAVYCZwUrAV4BVAswAe3kAQM3CdwCFLgBCMsBBQIBAQEFGDsDCgY4CEYIDAZ0Cx4DTgELBCEBNwkOAgoCZxgcCgYCBgIGCQcBBwE8BH4CCgakVwwXBDEE7kQCaiYHDAUFGgEFAQEBAgECAX0QvQMCNgcBICoGMwETAQQEBQGHAQIBAb4BAwYCBgIGAgMDBwEHCgUCDAEaARMBAgEPAg4iewUDBC0DWAENAwEvLoIBHQMxDxwEJAkeBSsFHgElBA4qngECCgYkBCQEKAg0CwwBDwEHAQIBCwEPAQcBAkO3AgkWCggYBgEqAQlFBgIBASwBAgMBAhcBSAgJMBMBAgUhAxsFAUA4BBQCMgECBQgBAwEdAgMECgcJB0AgJwQMCTYDHQIbBRoHBAwHUEk3Mw0zBy4ICqYCHwEqAQMCAksrCCoWGiYcFBcJTgQkCUQKAQIZBwoGNQESCCcJYAEUCxIBLz4HAQEBBAEPAQsGOwUKBgQBCAICAhYBBwECAQUBCgICAgMCAQYBBQcCBwMFiwFcAQUeSAgKpgE2AiYiRQsKBg0TOgYKNhsCDwQXuQE8ZFMMCAIBAggBAgEeAQICDAkKRggCLgILG0gIUw1JBwr2AQkBLQEOCh0DIAIWAQ5JBwECASwDAQECAQkICgYGAQIBJQECAQYHCrYCGQcRASkDHFYBDzINmwdmbwEFC8QBzBRjDdYIqh_HBLlDuQQHHwEKBFEBCgYeAgYKRgoKAQcBFQUTsAVbZUsEOQcRQAULAg74LwjWCSoJ50UEAQcBAgGjAg8BHQMCAQ4ECIwDhBJrBQ0DCQcKAgjcJC4CFwl0PPYBCicCwgEVRnoUDBQMVwkZhwFVAUcBAgIBAgICBAEMAQEBBwFBAQQCCAEHARwBBAEFAQEDBwHUAgKkAgK-BQ8FAQ_QCB8GBtUBBwERAgcBAgEFBT4hAXAtAw4CCgQCwAIfEToFAdADKuYFBwEEAQIBDwHFAQIQKUwECgQCkQZETD3CAQQBGwECAQECAQEKAQQBAQEBBgEEAQEBAQEBAwECAQECAQEBAQEBAQEBAQIBAQIEAQcBBAEEAQEBCgERBQMBBQERNAKOAiwEZAwPAg8BDwElCq4BOB0NLAQJBwIOBpoB2AcEEQMNA3cEXwYMBAEPDAQ4CAoGKAgeAgJO1AIMDgINAwkHLgEHCA4ECQcJB5MBATclCoYI4M0CILogBt4BAoItDrE6D-4EohOeBOILyyYF4CDRuCsBHmCAAfABkPwD_v8DAv7_AwI"
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/feedback-unicode-profile.codec.ts
|
|
17
|
+
var BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
18
|
+
var BASE64URL_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
19
|
+
var MAX_UNICODE_ENDPOINT = 1114112;
|
|
20
|
+
var MAX_ENCODED_PAYLOAD_CHARACTERS = 8192;
|
|
21
|
+
var MAX_ULEB128_BYTES = 5;
|
|
22
|
+
var MAX_PROFILE_RANGE_COUNT = 707;
|
|
23
|
+
var MAX_PROFILE_ENDPOINT_COUNT = MAX_PROFILE_RANGE_COUNT * 2;
|
|
24
|
+
var MAX_PROFILE_CODE_POINT_COUNT = MAX_UNICODE_ENDPOINT;
|
|
25
|
+
var ARTIFACT_KEYS = /* @__PURE__ */ new Set([
|
|
26
|
+
"profileId",
|
|
27
|
+
"unicodeVersion",
|
|
28
|
+
"sourcePackage",
|
|
29
|
+
"sourcePackageVersion",
|
|
30
|
+
"sourceProperty",
|
|
31
|
+
"rangeEncoding",
|
|
32
|
+
"rangeCount",
|
|
33
|
+
"endpointCount",
|
|
34
|
+
"codePointCount",
|
|
35
|
+
"endpointSha256",
|
|
36
|
+
"payload"
|
|
37
|
+
]);
|
|
38
|
+
function isRecord(value) {
|
|
39
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40
|
+
}
|
|
41
|
+
function hasExpectedMetadata(artifact, expected) {
|
|
42
|
+
return Object.keys(artifact).length === ARTIFACT_KEYS.size && Object.keys(artifact).every((key) => ARTIFACT_KEYS.has(key)) && artifact.profileId === expected.profileId && artifact.unicodeVersion === expected.unicodeVersion && artifact.sourcePackage === expected.sourcePackage && artifact.sourcePackageVersion === expected.sourcePackageVersion && artifact.sourceProperty === expected.sourceProperty && artifact.rangeEncoding === expected.rangeEncoding && artifact.rangeCount === expected.rangeCount && artifact.endpointCount === expected.endpointCount && artifact.codePointCount === expected.codePointCount && artifact.endpointSha256 === expected.endpointSha256;
|
|
43
|
+
}
|
|
44
|
+
function isBoundedPositiveInteger(value, maximum) {
|
|
45
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 && value <= maximum;
|
|
46
|
+
}
|
|
47
|
+
function hasBoundedCounts(artifact, expected) {
|
|
48
|
+
return isBoundedPositiveInteger(
|
|
49
|
+
artifact.rangeCount,
|
|
50
|
+
MAX_PROFILE_RANGE_COUNT
|
|
51
|
+
) && isBoundedPositiveInteger(
|
|
52
|
+
expected.rangeCount,
|
|
53
|
+
MAX_PROFILE_RANGE_COUNT
|
|
54
|
+
) && isBoundedPositiveInteger(
|
|
55
|
+
artifact.endpointCount,
|
|
56
|
+
MAX_PROFILE_ENDPOINT_COUNT
|
|
57
|
+
) && isBoundedPositiveInteger(
|
|
58
|
+
expected.endpointCount,
|
|
59
|
+
MAX_PROFILE_ENDPOINT_COUNT
|
|
60
|
+
) && artifact.endpointCount === artifact.rangeCount * 2 && expected.endpointCount === expected.rangeCount * 2 && isBoundedPositiveInteger(
|
|
61
|
+
artifact.codePointCount,
|
|
62
|
+
MAX_PROFILE_CODE_POINT_COUNT
|
|
63
|
+
) && isBoundedPositiveInteger(
|
|
64
|
+
expected.codePointCount,
|
|
65
|
+
MAX_PROFILE_CODE_POINT_COUNT
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
function decodeCanonicalBase64Url(value) {
|
|
69
|
+
if (value.length === 0 || value.length > MAX_ENCODED_PAYLOAD_CHARACTERS || value.length % 4 === 1 || !BASE64URL_PATTERN.test(value)) {
|
|
70
|
+
return void 0;
|
|
71
|
+
}
|
|
72
|
+
const finalSextet = BASE64URL_ALPHABET.indexOf(value.at(-1) ?? "");
|
|
73
|
+
if (finalSextet < 0 || value.length % 4 === 2 && (finalSextet & 15) !== 0 || value.length % 4 === 3 && (finalSextet & 3) !== 0) {
|
|
74
|
+
return void 0;
|
|
75
|
+
}
|
|
76
|
+
const expectedByteCount = Math.floor(value.length * 6 / 8);
|
|
77
|
+
const output = new Uint8Array(expectedByteCount);
|
|
78
|
+
let outputIndex = 0;
|
|
79
|
+
let accumulator = 0;
|
|
80
|
+
let bitCount = 0;
|
|
81
|
+
for (const character of value) {
|
|
82
|
+
const sextet = BASE64URL_ALPHABET.indexOf(character);
|
|
83
|
+
if (sextet < 0) {
|
|
84
|
+
return void 0;
|
|
85
|
+
}
|
|
86
|
+
accumulator = accumulator << 6 | sextet;
|
|
87
|
+
bitCount += 6;
|
|
88
|
+
while (bitCount >= 8) {
|
|
89
|
+
bitCount -= 8;
|
|
90
|
+
output[outputIndex] = accumulator >> bitCount & 255;
|
|
91
|
+
outputIndex += 1;
|
|
92
|
+
accumulator &= (1 << bitCount) - 1;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (outputIndex !== expectedByteCount || bitCount > 0 && accumulator !== 0) {
|
|
96
|
+
return void 0;
|
|
97
|
+
}
|
|
98
|
+
return output;
|
|
99
|
+
}
|
|
100
|
+
function decodeCanonicalEndpointDeltas(bytes, endpointCount) {
|
|
101
|
+
if (!isBoundedPositiveInteger(
|
|
102
|
+
endpointCount,
|
|
103
|
+
MAX_PROFILE_ENDPOINT_COUNT
|
|
104
|
+
) || endpointCount % 2 !== 0) {
|
|
105
|
+
return void 0;
|
|
106
|
+
}
|
|
107
|
+
const endpoints = new Uint32Array(endpointCount);
|
|
108
|
+
let byteOffset = 0;
|
|
109
|
+
let previousEndpoint = 0;
|
|
110
|
+
for (let endpointIndex = 0; endpointIndex < endpointCount; endpointIndex += 1) {
|
|
111
|
+
let delta = 0;
|
|
112
|
+
let multiplier = 1;
|
|
113
|
+
let byteCount = 0;
|
|
114
|
+
while (true) {
|
|
115
|
+
if (byteOffset >= bytes.length || byteCount >= MAX_ULEB128_BYTES) {
|
|
116
|
+
return void 0;
|
|
117
|
+
}
|
|
118
|
+
const byte = bytes[byteOffset];
|
|
119
|
+
if (byte === void 0) {
|
|
120
|
+
return void 0;
|
|
121
|
+
}
|
|
122
|
+
byteOffset += 1;
|
|
123
|
+
byteCount += 1;
|
|
124
|
+
const payload = byte & 127;
|
|
125
|
+
delta += payload * multiplier;
|
|
126
|
+
if (!Number.isSafeInteger(delta)) {
|
|
127
|
+
return void 0;
|
|
128
|
+
}
|
|
129
|
+
if ((byte & 128) === 0) {
|
|
130
|
+
if (byteCount > 1 && payload === 0) {
|
|
131
|
+
return void 0;
|
|
132
|
+
}
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
multiplier *= 128;
|
|
136
|
+
}
|
|
137
|
+
const endpoint = previousEndpoint + delta;
|
|
138
|
+
if (delta <= 0 || !Number.isSafeInteger(endpoint) || endpoint > MAX_UNICODE_ENDPOINT) {
|
|
139
|
+
return void 0;
|
|
140
|
+
}
|
|
141
|
+
endpoints[endpointIndex] = endpoint;
|
|
142
|
+
previousEndpoint = endpoint;
|
|
143
|
+
}
|
|
144
|
+
if (byteOffset !== bytes.length) {
|
|
145
|
+
return void 0;
|
|
146
|
+
}
|
|
147
|
+
return endpoints;
|
|
148
|
+
}
|
|
149
|
+
function hasExpectedRanges(endpoints, expected) {
|
|
150
|
+
let previousEnd = -1;
|
|
151
|
+
let codePointCount = 0;
|
|
152
|
+
for (let index = 0; index < endpoints.length; index += 2) {
|
|
153
|
+
const start = endpoints[index];
|
|
154
|
+
const end = endpoints[index + 1];
|
|
155
|
+
if (start === void 0 || end === void 0 || start <= previousEnd || end <= start || end > MAX_UNICODE_ENDPOINT) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
codePointCount += end - start;
|
|
159
|
+
previousEnd = end;
|
|
160
|
+
}
|
|
161
|
+
return codePointCount === expected.codePointCount;
|
|
162
|
+
}
|
|
163
|
+
function decodeFeedbackUnicodeProfileArtifact(value, expected) {
|
|
164
|
+
if (!isRecord(value) || !hasBoundedCounts(value, expected) || !hasExpectedMetadata(value, expected) || typeof value.payload !== "string") {
|
|
165
|
+
return void 0;
|
|
166
|
+
}
|
|
167
|
+
const bytes = decodeCanonicalBase64Url(value.payload);
|
|
168
|
+
if (bytes === void 0) {
|
|
169
|
+
return void 0;
|
|
170
|
+
}
|
|
171
|
+
const endpoints = decodeCanonicalEndpointDeltas(
|
|
172
|
+
bytes,
|
|
173
|
+
expected.endpointCount
|
|
174
|
+
);
|
|
175
|
+
return endpoints !== void 0 && hasExpectedRanges(endpoints, expected) ? endpoints : void 0;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/feedback-unicode-profile.ts
|
|
179
|
+
var FEEDBACK_UNICODE_PROFILE_ID = "unicode-15.1.0-nfkc-v1";
|
|
180
|
+
var FEEDBACK_UNICODE_PROFILE_ENDPOINT_SHA256 = "591e457524d6b4b988aa7c7687e76c95a78370fea38bbd1b09085be7fd935ef3";
|
|
181
|
+
var MAX_UNICODE_CODE_POINT = 1114111;
|
|
182
|
+
var HIGH_SURROGATE_START = 55296;
|
|
183
|
+
var HIGH_SURROGATE_END = 56319;
|
|
184
|
+
var LOW_SURROGATE_START = 56320;
|
|
185
|
+
var LOW_SURROGATE_END = 57343;
|
|
186
|
+
var UNASSIGNED_RANGE_ENDPOINTS = decodeFeedbackUnicodeProfileArtifact(
|
|
187
|
+
feedback_unicode_15_1_0_unassigned_default,
|
|
188
|
+
{
|
|
189
|
+
profileId: FEEDBACK_UNICODE_PROFILE_ID,
|
|
190
|
+
unicodeVersion: "15.1.0",
|
|
191
|
+
sourcePackage: "@unicode/unicode-15.1.0",
|
|
192
|
+
sourcePackageVersion: "1.6.17",
|
|
193
|
+
sourceProperty: "General_Category/Unassigned",
|
|
194
|
+
rangeEncoding: "flat-half-open-delta-uleb128-base64url-v1",
|
|
195
|
+
rangeCount: 707,
|
|
196
|
+
endpointCount: 1414,
|
|
197
|
+
codePointCount: 824718,
|
|
198
|
+
endpointSha256: FEEDBACK_UNICODE_PROFILE_ENDPOINT_SHA256
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
function isFeedbackUnicodeProfileUnassigned(codePoint) {
|
|
202
|
+
if (UNASSIGNED_RANGE_ENDPOINTS === void 0 || !Number.isInteger(codePoint) || codePoint < 0 || codePoint > MAX_UNICODE_CODE_POINT || codePoint >= HIGH_SURROGATE_START && codePoint <= LOW_SURROGATE_END) {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
let lowerRange = 0;
|
|
206
|
+
let upperRange = UNASSIGNED_RANGE_ENDPOINTS.length / 2 - 1;
|
|
207
|
+
while (lowerRange <= upperRange) {
|
|
208
|
+
const rangeIndex = Math.floor((lowerRange + upperRange) / 2);
|
|
209
|
+
const start = UNASSIGNED_RANGE_ENDPOINTS[rangeIndex * 2];
|
|
210
|
+
const end = UNASSIGNED_RANGE_ENDPOINTS[rangeIndex * 2 + 1];
|
|
211
|
+
if (start === void 0 || end === void 0) {
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
if (codePoint < start) {
|
|
215
|
+
upperRange = rangeIndex - 1;
|
|
216
|
+
} else if (codePoint >= end) {
|
|
217
|
+
lowerRange = rangeIndex + 1;
|
|
218
|
+
} else {
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
function containsFeedbackUnicodeProfileUnsupportedText(text) {
|
|
225
|
+
if (typeof text !== "string") {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
229
|
+
const first = text.charCodeAt(index);
|
|
230
|
+
let codePoint = first;
|
|
231
|
+
if (first >= HIGH_SURROGATE_START && first <= HIGH_SURROGATE_END) {
|
|
232
|
+
const second = text.charCodeAt(index + 1);
|
|
233
|
+
if (!Number.isInteger(second) || second < LOW_SURROGATE_START || second > LOW_SURROGATE_END) {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
codePoint = 65536 + (first - HIGH_SURROGATE_START << 10) + (second - LOW_SURROGATE_START);
|
|
237
|
+
index += 1;
|
|
238
|
+
} else if (first >= LOW_SURROGATE_START && first <= LOW_SURROGATE_END) {
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
if (isFeedbackUnicodeProfileUnassigned(codePoint)) {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export {
|
|
249
|
+
FEEDBACK_UNICODE_PROFILE_ID,
|
|
250
|
+
FEEDBACK_UNICODE_PROFILE_ENDPOINT_SHA256,
|
|
251
|
+
isFeedbackUnicodeProfileUnassigned,
|
|
252
|
+
containsFeedbackUnicodeProfileUnsupportedText
|
|
253
|
+
};
|
|
254
|
+
//# sourceMappingURL=chunk-6FE4FLKF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../unicode/feedback-unicode-15.1.0-unassigned.json","../src/feedback-unicode-profile.codec.ts","../src/feedback-unicode-profile.ts"],"sourcesContent":["{\n \"profileId\": \"unicode-15.1.0-nfkc-v1\",\n \"unicodeVersion\": \"15.1.0\",\n \"sourcePackage\": \"@unicode/unicode-15.1.0\",\n \"sourcePackageVersion\": \"1.6.17\",\n \"sourceProperty\": \"General_Category/Unassigned\",\n \"rangeEncoding\": \"flat-half-open-delta-uleb128-base64url-v1\",\n \"rangeCount\": 707,\n \"endpointCount\": 1414,\n \"codePointCount\": 824718,\n \"endpointSha256\": \"591e457524d6b4b988aa7c7687e76c95a78370fea38bbd1b09085be7fd935ef3\",\n \"payload\": \"-AYCBgQHAQEBFAGNAwEmAjICAwE3CBsEBguOAgE8AmUOOwIxAg8BHAIBAQsFHwECBuwBAQgCAgIWAQcBAQMEAgkCAgIECAEEAgEFAhkCAwEGBAICFgEHAQIBAgECAgEBBQQCAgMDAQcEAQEHEQoDAQkBAwEWAQcBAgEFAgoBAwEDAgEPBAIMBwcBAwEIAgICFgEHAQIBBQIJAgICAwcDBAIBBQISCgIBBgMDAQQDAgEBAQIDAgMDAwwEBQMDAQQCAQYBDhUFDQEDARcBEAIJAQMBBAcCAQMCAQIEAgoHFgEDARcBCgEFAgkBAwEEBwIGAgEEAgoBAwwNAQMBMwEDAQYEEAIaAQMBEgMYAQkBAQIHAwEEBgEBAQgGCgIDDDoEHSUCAQEBBQEYAQEBFwIFAQEBBwEKAgQgSAEkBCcBJAEPAQ0lxgEBAQUBAvkCAQQCBwEBAQQCKQEEAiEBBAIHAQEBBAIPATkBBAJDAiADGgZWAgYCnQUDWQcWCRgJFAwNAQMBAgxeAgoGCgYaBlkHKwVGCh8BDAQMBAEDKgIFCywEGgYLAz4CQQEdAgsGCgYOAh8xTQMvAXQIPAMPAzwHKwILCCsFlgQCBgImAgYCCAEBAQEBAQEfAjUBDwEOAgYBEwIDAQkBZQEMAhsBDQMhDyEPjAEElwUZCxWUDgIgAd0CBS0BAQUBAjgHAg4YCQcBBwEHAQcBBwEHAQcBBwF-IhoBWQzWARpQAVYCZwUrAV4BVAswAe3kAQM3CdwCFLgBCMsBBQIBAQEFGDsDCgY4CEYIDAZ0Cx4DTgELBCEBNwkOAgoCZxgcCgYCBgIGCQcBBwE8BH4CCgakVwwXBDEE7kQCaiYHDAUFGgEFAQEBAgECAX0QvQMCNgcBICoGMwETAQQEBQGHAQIBAb4BAwYCBgIGAgMDBwEHCgUCDAEaARMBAgEPAg4iewUDBC0DWAENAwEvLoIBHQMxDxwEJAkeBSsFHgElBA4qngECCgYkBCQEKAg0CwwBDwEHAQIBCwEPAQcBAkO3AgkWCggYBgEqAQlFBgIBASwBAgMBAhcBSAgJMBMBAgUhAxsFAUA4BBQCMgECBQgBAwEdAgMECgcJB0AgJwQMCTYDHQIbBRoHBAwHUEk3Mw0zBy4ICqYCHwEqAQMCAksrCCoWGiYcFBcJTgQkCUQKAQIZBwoGNQESCCcJYAEUCxIBLz4HAQEBBAEPAQsGOwUKBgQBCAICAhYBBwECAQUBCgICAgMCAQYBBQcCBwMFiwFcAQUeSAgKpgE2AiYiRQsKBg0TOgYKNhsCDwQXuQE8ZFMMCAIBAggBAgEeAQICDAkKRggCLgILG0gIUw1JBwr2AQkBLQEOCh0DIAIWAQ5JBwECASwDAQECAQkICgYGAQIBJQECAQYHCrYCGQcRASkDHFYBDzINmwdmbwEFC8QBzBRjDdYIqh_HBLlDuQQHHwEKBFEBCgYeAgYKRgoKAQcBFQUTsAVbZUsEOQcRQAULAg74LwjWCSoJ50UEAQcBAgGjAg8BHQMCAQ4ECIwDhBJrBQ0DCQcKAgjcJC4CFwl0PPYBCicCwgEVRnoUDBQMVwkZhwFVAUcBAgIBAgICBAEMAQEBBwFBAQQCCAEHARwBBAEFAQEDBwHUAgKkAgK-BQ8FAQ_QCB8GBtUBBwERAgcBAgEFBT4hAXAtAw4CCgQCwAIfEToFAdADKuYFBwEEAQIBDwHFAQIQKUwECgQCkQZETD3CAQQBGwECAQECAQEKAQQBAQEBBgEEAQEBAQEBAwECAQECAQEBAQEBAQEBAQIBAQIEAQcBBAEEAQEBCgERBQMBBQERNAKOAiwEZAwPAg8BDwElCq4BOB0NLAQJBwIOBpoB2AcEEQMNA3cEXwYMBAEPDAQ4CAoGKAgeAgJO1AIMDgINAwkHLgEHCA4ECQcJB5MBATclCoYI4M0CILogBt4BAoItDrE6D-4EohOeBOILyyYF4CDRuCsBHmCAAfABkPwD_v8DAv7_AwI\"\n}\n","const BASE64URL_ALPHABET =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\";\nconst BASE64URL_PATTERN = /^[A-Za-z0-9_-]+$/;\nconst MAX_UNICODE_ENDPOINT = 0x110000;\nconst MAX_ENCODED_PAYLOAD_CHARACTERS = 8_192;\nconst MAX_ULEB128_BYTES = 5;\nconst MAX_PROFILE_RANGE_COUNT = 707;\nconst MAX_PROFILE_ENDPOINT_COUNT = MAX_PROFILE_RANGE_COUNT * 2;\nconst MAX_PROFILE_CODE_POINT_COUNT = MAX_UNICODE_ENDPOINT;\nconst ARTIFACT_KEYS = new Set([\n \"profileId\",\n \"unicodeVersion\",\n \"sourcePackage\",\n \"sourcePackageVersion\",\n \"sourceProperty\",\n \"rangeEncoding\",\n \"rangeCount\",\n \"endpointCount\",\n \"codePointCount\",\n \"endpointSha256\",\n \"payload\",\n]);\n\nexport interface FeedbackUnicodeProfileExpectation {\n readonly profileId: string;\n readonly unicodeVersion: string;\n readonly sourcePackage: string;\n readonly sourcePackageVersion: string;\n readonly sourceProperty: string;\n readonly rangeEncoding: string;\n readonly rangeCount: number;\n readonly endpointCount: number;\n readonly codePointCount: number;\n readonly endpointSha256: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasExpectedMetadata(\n artifact: Record<string, unknown>,\n expected: FeedbackUnicodeProfileExpectation,\n): boolean {\n return (\n Object.keys(artifact).length === ARTIFACT_KEYS.size &&\n Object.keys(artifact).every((key) => ARTIFACT_KEYS.has(key)) &&\n artifact.profileId === expected.profileId &&\n artifact.unicodeVersion === expected.unicodeVersion &&\n artifact.sourcePackage === expected.sourcePackage &&\n artifact.sourcePackageVersion === expected.sourcePackageVersion &&\n artifact.sourceProperty === expected.sourceProperty &&\n artifact.rangeEncoding === expected.rangeEncoding &&\n artifact.rangeCount === expected.rangeCount &&\n artifact.endpointCount === expected.endpointCount &&\n artifact.codePointCount === expected.codePointCount &&\n artifact.endpointSha256 === expected.endpointSha256\n );\n}\n\nfunction isBoundedPositiveInteger(\n value: unknown,\n maximum: number,\n): value is number {\n return (\n typeof value === \"number\" &&\n Number.isSafeInteger(value) &&\n value > 0 &&\n value <= maximum\n );\n}\n\nfunction hasBoundedCounts(\n artifact: Record<string, unknown>,\n expected: FeedbackUnicodeProfileExpectation,\n): boolean {\n return (\n isBoundedPositiveInteger(\n artifact.rangeCount,\n MAX_PROFILE_RANGE_COUNT,\n ) &&\n isBoundedPositiveInteger(\n expected.rangeCount,\n MAX_PROFILE_RANGE_COUNT,\n ) &&\n isBoundedPositiveInteger(\n artifact.endpointCount,\n MAX_PROFILE_ENDPOINT_COUNT,\n ) &&\n isBoundedPositiveInteger(\n expected.endpointCount,\n MAX_PROFILE_ENDPOINT_COUNT,\n ) &&\n artifact.endpointCount === artifact.rangeCount * 2 &&\n expected.endpointCount === expected.rangeCount * 2 &&\n isBoundedPositiveInteger(\n artifact.codePointCount,\n MAX_PROFILE_CODE_POINT_COUNT,\n ) &&\n isBoundedPositiveInteger(\n expected.codePointCount,\n MAX_PROFILE_CODE_POINT_COUNT,\n )\n );\n}\n\nfunction decodeCanonicalBase64Url(value: string): Uint8Array | undefined {\n if (\n value.length === 0 ||\n value.length > MAX_ENCODED_PAYLOAD_CHARACTERS ||\n value.length % 4 === 1 ||\n !BASE64URL_PATTERN.test(value)\n ) {\n return undefined;\n }\n\n const finalSextet = BASE64URL_ALPHABET.indexOf(value.at(-1) ?? \"\");\n if (\n finalSextet < 0 ||\n (value.length % 4 === 2 && (finalSextet & 0b1111) !== 0) ||\n (value.length % 4 === 3 && (finalSextet & 0b11) !== 0)\n ) {\n return undefined;\n }\n\n const expectedByteCount = Math.floor((value.length * 6) / 8);\n const output = new Uint8Array(expectedByteCount);\n let outputIndex = 0;\n let accumulator = 0;\n let bitCount = 0;\n\n for (const character of value) {\n const sextet = BASE64URL_ALPHABET.indexOf(character);\n if (sextet < 0) {\n return undefined;\n }\n accumulator = (accumulator << 6) | sextet;\n bitCount += 6;\n while (bitCount >= 8) {\n bitCount -= 8;\n output[outputIndex] = (accumulator >> bitCount) & 0xff;\n outputIndex += 1;\n accumulator &= (1 << bitCount) - 1;\n }\n }\n\n if (\n outputIndex !== expectedByteCount ||\n (bitCount > 0 && accumulator !== 0)\n ) {\n return undefined;\n }\n return output;\n}\n\nfunction decodeCanonicalEndpointDeltas(\n bytes: Uint8Array,\n endpointCount: number,\n): Uint32Array | undefined {\n if (\n !isBoundedPositiveInteger(\n endpointCount,\n MAX_PROFILE_ENDPOINT_COUNT,\n ) ||\n endpointCount % 2 !== 0\n ) {\n return undefined;\n }\n const endpoints = new Uint32Array(endpointCount);\n let byteOffset = 0;\n let previousEndpoint = 0;\n\n for (let endpointIndex = 0; endpointIndex < endpointCount; endpointIndex += 1) {\n let delta = 0;\n let multiplier = 1;\n let byteCount = 0;\n\n while (true) {\n if (byteOffset >= bytes.length || byteCount >= MAX_ULEB128_BYTES) {\n return undefined;\n }\n const byte = bytes[byteOffset];\n if (byte === undefined) {\n return undefined;\n }\n byteOffset += 1;\n byteCount += 1;\n\n const payload = byte & 0x7f;\n delta += payload * multiplier;\n if (!Number.isSafeInteger(delta)) {\n return undefined;\n }\n\n if ((byte & 0x80) === 0) {\n if (byteCount > 1 && payload === 0) {\n return undefined;\n }\n break;\n }\n multiplier *= 128;\n }\n\n const endpoint = previousEndpoint + delta;\n if (\n delta <= 0 ||\n !Number.isSafeInteger(endpoint) ||\n endpoint > MAX_UNICODE_ENDPOINT\n ) {\n return undefined;\n }\n endpoints[endpointIndex] = endpoint;\n previousEndpoint = endpoint;\n }\n\n if (byteOffset !== bytes.length) {\n return undefined;\n }\n return endpoints;\n}\n\nfunction hasExpectedRanges(\n endpoints: Uint32Array,\n expected: FeedbackUnicodeProfileExpectation,\n): boolean {\n let previousEnd = -1;\n let codePointCount = 0;\n\n for (let index = 0; index < endpoints.length; index += 2) {\n const start = endpoints[index];\n const end = endpoints[index + 1];\n if (\n start === undefined ||\n end === undefined ||\n start <= previousEnd ||\n end <= start ||\n end > MAX_UNICODE_ENDPOINT\n ) {\n return false;\n }\n codePointCount += end - start;\n previousEnd = end;\n }\n\n return codePointCount === expected.codePointCount;\n}\n\n/**\n * Decodes and validates the checked-in Unicode profile artifact.\n *\n * This is an internal supply-boundary helper. It deliberately returns no\n * partial data: malformed base64url, non-shortest ULEB128, overflow, range\n * disorder, count mismatch, trailing bytes, or metadata drift all fail\n * closed.\n */\nexport function decodeFeedbackUnicodeProfileArtifact(\n value: unknown,\n expected: FeedbackUnicodeProfileExpectation,\n): Uint32Array | undefined {\n if (\n !isRecord(value) ||\n !hasBoundedCounts(value, expected) ||\n !hasExpectedMetadata(value, expected) ||\n typeof value.payload !== \"string\"\n ) {\n return undefined;\n }\n\n const bytes = decodeCanonicalBase64Url(value.payload);\n if (bytes === undefined) {\n return undefined;\n }\n const endpoints = decodeCanonicalEndpointDeltas(\n bytes,\n expected.endpointCount,\n );\n return endpoints !== undefined && hasExpectedRanges(endpoints, expected)\n ? endpoints\n : undefined;\n}\n","import profileArtifact from \"../unicode/feedback-unicode-15.1.0-unassigned.json\" with {\n type: \"json\",\n};\nimport { decodeFeedbackUnicodeProfileArtifact } from \"./feedback-unicode-profile.codec.js\";\n\n/** Canonical Unicode and normalization profile for transient feedback text. */\nexport const FEEDBACK_UNICODE_PROFILE_ID =\n \"unicode-15.1.0-nfkc-v1\" as const;\n\n/**\n * SHA-256 of the flattened half-open range endpoints encoded as unsigned\n * 32-bit big-endian integers.\n */\nexport const FEEDBACK_UNICODE_PROFILE_ENDPOINT_SHA256 =\n \"591e457524d6b4b988aa7c7687e76c95a78370fea38bbd1b09085be7fd935ef3\" as const;\n\nconst MAX_UNICODE_CODE_POINT = 0x10ffff;\nconst HIGH_SURROGATE_START = 0xd800;\nconst HIGH_SURROGATE_END = 0xdbff;\nconst LOW_SURROGATE_START = 0xdc00;\nconst LOW_SURROGATE_END = 0xdfff;\n\nconst UNASSIGNED_RANGE_ENDPOINTS = decodeFeedbackUnicodeProfileArtifact(\n profileArtifact,\n {\n profileId: FEEDBACK_UNICODE_PROFILE_ID,\n unicodeVersion: \"15.1.0\",\n sourcePackage: \"@unicode/unicode-15.1.0\",\n sourcePackageVersion: \"1.6.17\",\n sourceProperty: \"General_Category/Unassigned\",\n rangeEncoding: \"flat-half-open-delta-uleb128-base64url-v1\",\n rangeCount: 707,\n endpointCount: 1_414,\n codePointCount: 824_718,\n endpointSha256: FEEDBACK_UNICODE_PROFILE_ENDPOINT_SHA256,\n },\n);\n\n/**\n * Reports whether a numeric code point is unsupported by the pinned feedback\n * profile.\n *\n * Unicode 15.1 `General_Category=Unassigned` values return `true`. Invalid\n * numeric values and surrogate code points also return `true` so validation\n * callers fail closed.\n */\nexport function isFeedbackUnicodeProfileUnassigned(\n codePoint: number,\n): boolean {\n if (\n UNASSIGNED_RANGE_ENDPOINTS === undefined ||\n !Number.isInteger(codePoint) ||\n codePoint < 0 ||\n codePoint > MAX_UNICODE_CODE_POINT ||\n (codePoint >= HIGH_SURROGATE_START &&\n codePoint <= LOW_SURROGATE_END)\n ) {\n return true;\n }\n\n let lowerRange = 0;\n let upperRange = UNASSIGNED_RANGE_ENDPOINTS.length / 2 - 1;\n\n while (lowerRange <= upperRange) {\n const rangeIndex = Math.floor((lowerRange + upperRange) / 2);\n const start = UNASSIGNED_RANGE_ENDPOINTS[rangeIndex * 2];\n const end = UNASSIGNED_RANGE_ENDPOINTS[rangeIndex * 2 + 1];\n\n if (start === undefined || end === undefined) {\n return true;\n }\n if (codePoint < start) {\n upperRange = rangeIndex - 1;\n } else if (codePoint >= end) {\n lowerRange = rangeIndex + 1;\n } else {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Reports whether text contains a Unicode 15.1-unassigned code point or a\n * lone UTF-16 surrogate.\n *\n * The scan uses code units deliberately so malformed strings cannot be\n * silently replaced or normalized before profile enforcement. Callers must\n * apply their own UTF-16 length bound before passing untrusted text; this\n * generic helper intentionally does not impose a product-specific limit.\n */\nexport function containsFeedbackUnicodeProfileUnsupportedText(\n text: string,\n): boolean {\n if (typeof text !== \"string\") {\n return true;\n }\n\n for (let index = 0; index < text.length; index += 1) {\n const first = text.charCodeAt(index);\n let codePoint = first;\n\n if (first >= HIGH_SURROGATE_START && first <= HIGH_SURROGATE_END) {\n const second = text.charCodeAt(index + 1);\n if (\n !Number.isInteger(second) ||\n second < LOW_SURROGATE_START ||\n second > LOW_SURROGATE_END\n ) {\n return true;\n }\n codePoint =\n 0x10000 +\n ((first - HIGH_SURROGATE_START) << 10) +\n (second - LOW_SURROGATE_START);\n index += 1;\n } else if (first >= LOW_SURROGATE_START && first <= LOW_SURROGATE_END) {\n return true;\n }\n\n if (isFeedbackUnicodeProfileUnassigned(codePoint)) {\n return true;\n }\n }\n\n return false;\n}\n"],"mappings":"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","names":[]}
|