@plasius/schema 1.3.0 → 1.4.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 +235 -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 +51 -13
- package/unicode/feedback-unicode-15.1.0-unassigned.json +13 -0
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,58 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
FEEDBACK_ANALYSIS_MODEL_VERSIONS: () => FEEDBACK_ANALYSIS_MODEL_VERSIONS,
|
|
24
|
+
FEEDBACK_BACKEND_BUCKETS: () => FEEDBACK_BACKEND_BUCKETS,
|
|
25
|
+
FEEDBACK_BUG_COOLDOWN_SECONDS: () => FEEDBACK_BUG_COOLDOWN_SECONDS,
|
|
26
|
+
FEEDBACK_CONTRACT_VERSION: () => FEEDBACK_CONTRACT_VERSION,
|
|
27
|
+
FEEDBACK_FRAME_RATE_BUCKETS: () => FEEDBACK_FRAME_RATE_BUCKETS,
|
|
28
|
+
FEEDBACK_FRAME_TIME_BUCKETS: () => FEEDBACK_FRAME_TIME_BUCKETS,
|
|
29
|
+
FEEDBACK_GAME_COUNTER_CODES: () => FEEDBACK_GAME_COUNTER_CODES,
|
|
30
|
+
FEEDBACK_GAME_COUNTER_MAX_COUNT: () => FEEDBACK_GAME_COUNTER_MAX_COUNT,
|
|
31
|
+
FEEDBACK_GAME_COUNTER_MAX_ITEMS: () => FEEDBACK_GAME_COUNTER_MAX_ITEMS,
|
|
32
|
+
FEEDBACK_GAME_ERROR_CODES: () => FEEDBACK_GAME_ERROR_CODES,
|
|
33
|
+
FEEDBACK_GAME_FEATURE_IDS: () => FEEDBACK_GAME_FEATURE_IDS,
|
|
34
|
+
FEEDBACK_GAME_PROVENANCE_CONTRACTS: () => FEEDBACK_GAME_PROVENANCE_CONTRACTS,
|
|
35
|
+
FEEDBACK_GAME_PROVENANCE_CONTRACT_IDS: () => FEEDBACK_GAME_PROVENANCE_CONTRACT_IDS,
|
|
36
|
+
FEEDBACK_GAME_SURFACE_IDS: () => FEEDBACK_GAME_SURFACE_IDS,
|
|
37
|
+
FEEDBACK_INTENT_IDS: () => FEEDBACK_INTENT_IDS,
|
|
38
|
+
FEEDBACK_ISSUE_TYPES: () => FEEDBACK_ISSUE_TYPES,
|
|
39
|
+
FEEDBACK_PERSISTABLE_ISSUE_TYPES: () => FEEDBACK_PERSISTABLE_ISSUE_TYPES,
|
|
40
|
+
FEEDBACK_PRIVACY_POLICY_VERSIONS: () => FEEDBACK_PRIVACY_POLICY_VERSIONS,
|
|
41
|
+
FEEDBACK_RENDERER_BUCKETS: () => FEEDBACK_RENDERER_BUCKETS,
|
|
42
|
+
FEEDBACK_REVIEW_COOLDOWN_SECONDS: () => FEEDBACK_REVIEW_COOLDOWN_SECONDS,
|
|
43
|
+
FEEDBACK_SATISFACTION_LEVELS: () => FEEDBACK_SATISFACTION_LEVELS,
|
|
44
|
+
FEEDBACK_SENTIMENT_BUCKETS: () => FEEDBACK_SENTIMENT_BUCKETS,
|
|
45
|
+
FEEDBACK_SEVERITY_LEVELS: () => FEEDBACK_SEVERITY_LEVELS,
|
|
46
|
+
FEEDBACK_STRUCTURED_ONLY_REASON_CODES: () => FEEDBACK_STRUCTURED_ONLY_REASON_CODES,
|
|
47
|
+
FEEDBACK_SURFACE_DEFINITIONS: () => FEEDBACK_SURFACE_DEFINITIONS,
|
|
48
|
+
FEEDBACK_SURFACE_IDS: () => FEEDBACK_SURFACE_IDS,
|
|
49
|
+
FEEDBACK_THEME_IDS: () => FEEDBACK_THEME_IDS,
|
|
50
|
+
FEEDBACK_UNICODE_NORMALIZATION_PROFILE: () => FEEDBACK_UNICODE_NORMALIZATION_PROFILE,
|
|
51
|
+
FEEDBACK_VIEWPORT_BUCKETS: () => FEEDBACK_VIEWPORT_BUCKETS,
|
|
52
|
+
FeedbackAcceptanceReceiptSchema: () => FeedbackAcceptanceReceiptSchema,
|
|
53
|
+
FeedbackAnalysisReceiptSchema: () => FeedbackAnalysisReceiptSchema,
|
|
54
|
+
FeedbackBugPacketSchema: () => FeedbackBugPacketSchema,
|
|
55
|
+
FeedbackBugSubmissionRequestSchema: () => FeedbackBugSubmissionRequestSchema,
|
|
56
|
+
FeedbackContextSchema: () => FeedbackContextSchema,
|
|
57
|
+
FeedbackDailySatisfactionReportSchema: () => FeedbackDailySatisfactionReportSchema,
|
|
58
|
+
FeedbackDerivedAnalysisSchema: () => FeedbackDerivedAnalysisSchema,
|
|
59
|
+
FeedbackDraftPacketSchema: () => FeedbackDraftPacketSchema,
|
|
60
|
+
FeedbackDraftReceiptSchema: () => FeedbackDraftReceiptSchema,
|
|
61
|
+
FeedbackDraftUpsertRequestSchema: () => FeedbackDraftUpsertRequestSchema,
|
|
62
|
+
FeedbackEncryptedNarrativeEnvelopeSchema: () => FeedbackEncryptedNarrativeEnvelopeSchema,
|
|
63
|
+
FeedbackGameDiagnosticsSchema: () => FeedbackGameDiagnosticsSchema,
|
|
64
|
+
FeedbackGameReconstructionManifestSchema: () => FeedbackGameReconstructionManifestSchema,
|
|
65
|
+
FeedbackHourlyBugReportSchema: () => FeedbackHourlyBugReportSchema,
|
|
66
|
+
FeedbackMaterializationManifestSchema: () => FeedbackMaterializationManifestSchema,
|
|
67
|
+
FeedbackProcessorCheckpointSchema: () => FeedbackProcessorCheckpointSchema,
|
|
68
|
+
FeedbackPublicSummarySchema: () => FeedbackPublicSummarySchema,
|
|
69
|
+
FeedbackReviewPacketSchema: () => FeedbackReviewPacketSchema,
|
|
70
|
+
FeedbackReviewSubmissionRequestSchema: () => FeedbackReviewSubmissionRequestSchema,
|
|
71
|
+
FeedbackRichTextAstSchema: () => FeedbackRichTextAstSchema,
|
|
72
|
+
FeedbackStructuredOnlyAnalysisResultSchema: () => FeedbackStructuredOnlyAnalysisResultSchema,
|
|
73
|
+
FeedbackSurfaceCatalogSchema: () => FeedbackSurfaceCatalogSchema,
|
|
74
|
+
FeedbackTransientAnalysisRequestSchema: () => FeedbackTransientAnalysisRequestSchema,
|
|
23
75
|
FieldBuilder: () => FieldBuilder,
|
|
24
76
|
IsoLanguageCode: () => IsoLanguageCode,
|
|
25
77
|
PLAYER_SYSTEM_ACHIEVEMENT_TIERS: () => PLAYER_SYSTEM_ACHIEVEMENT_TIERS,
|
|
@@ -28,6 +80,8 @@ __export(index_exports, {
|
|
|
28
80
|
PlayerSystemCuratedSnapshotSchema: () => PlayerSystemCuratedSnapshotSchema,
|
|
29
81
|
PlayerSystemNormalizedEventBatchSchema: () => PlayerSystemNormalizedEventBatchSchema,
|
|
30
82
|
PlayerSystemObservedEventBatchSchema: () => PlayerSystemObservedEventBatchSchema,
|
|
83
|
+
SCHEMA_IDENTITY_POLICIES: () => SCHEMA_IDENTITY_POLICIES,
|
|
84
|
+
SCHEMA_UNKNOWN_FIELDS_POLICIES: () => SCHEMA_UNKNOWN_FIELDS_POLICIES,
|
|
31
85
|
createComponentSchema: () => createComponentSchema,
|
|
32
86
|
createSchema: () => createSchema,
|
|
33
87
|
field: () => field,
|
|
@@ -50,7 +104,10 @@ __export(index_exports, {
|
|
|
50
104
|
validateCountryCode: () => validateCountryCode,
|
|
51
105
|
validateCurrencyCode: () => validateCurrencyCode,
|
|
52
106
|
validateDateTimeISO: () => validateDateTimeISO,
|
|
107
|
+
validateDisplayName: () => validateDisplayName,
|
|
53
108
|
validateEmail: () => validateEmail,
|
|
109
|
+
validateFeedbackGameDiagnostics: () => validateFeedbackGameDiagnostics,
|
|
110
|
+
validateFeedbackTransientAnalysisRequest: () => validateFeedbackTransientAnalysisRequest,
|
|
54
111
|
validateLanguage: () => validateLanguage,
|
|
55
112
|
validateName: () => validateName,
|
|
56
113
|
validatePercentage: () => validatePercentage,
|
|
@@ -818,7 +875,7 @@ function validateRichText(value) {
|
|
|
818
875
|
}
|
|
819
876
|
|
|
820
877
|
// src/validation/name.OWASP.ts
|
|
821
|
-
function
|
|
878
|
+
function validateNameLike(value, pattern) {
|
|
822
879
|
if (typeof value !== "string") return false;
|
|
823
880
|
const trimmed = value.trim();
|
|
824
881
|
if (trimmed.length === 0) return false;
|
|
@@ -827,10 +884,15 @@ function validateName(value) {
|
|
|
827
884
|
const cp = ch.codePointAt(0);
|
|
828
885
|
if (cp >= 0 && cp <= 31 || cp === 127) return false;
|
|
829
886
|
}
|
|
830
|
-
|
|
831
|
-
if (!namePattern.test(trimmed)) return false;
|
|
887
|
+
if (!pattern.test(trimmed)) return false;
|
|
832
888
|
return true;
|
|
833
889
|
}
|
|
890
|
+
function validateName(value) {
|
|
891
|
+
return validateNameLike(value, /^[\p{L}\p{M}'\-. ]+$/u);
|
|
892
|
+
}
|
|
893
|
+
function validateDisplayName(value) {
|
|
894
|
+
return validateNameLike(value, /^[\p{L}\p{M}\p{Nd}'\-. ]+$/u);
|
|
895
|
+
}
|
|
834
896
|
|
|
835
897
|
// src/validation/user.MS-GOOGLE-APPLE.ts
|
|
836
898
|
function validateUserId(value) {
|
|
@@ -1222,6 +1284,16 @@ var field = {
|
|
|
1222
1284
|
)
|
|
1223
1285
|
};
|
|
1224
1286
|
|
|
1287
|
+
// src/types.ts
|
|
1288
|
+
var SCHEMA_UNKNOWN_FIELDS_POLICIES = Object.freeze([
|
|
1289
|
+
"strip",
|
|
1290
|
+
"reject"
|
|
1291
|
+
]);
|
|
1292
|
+
var SCHEMA_IDENTITY_POLICIES = Object.freeze([
|
|
1293
|
+
"compatible",
|
|
1294
|
+
"exact"
|
|
1295
|
+
]);
|
|
1296
|
+
|
|
1225
1297
|
// src/pii.ts
|
|
1226
1298
|
function enforcePIIField(parentKey, key, value, def, enforcement = "none", errors, logger) {
|
|
1227
1299
|
const path = parentKey ? `${parentKey}.${key}` : key;
|
|
@@ -1256,6 +1328,9 @@ function prepareForStorage(shape, input, encryptFn, hashFn) {
|
|
|
1256
1328
|
if (!isMissing) out[key] = null;
|
|
1257
1329
|
return;
|
|
1258
1330
|
}
|
|
1331
|
+
if (isMissing && def.isRequired === false) {
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1259
1334
|
if (def.type === "object" && def._shape) {
|
|
1260
1335
|
const obj = {};
|
|
1261
1336
|
for (const [childKey, childDef] of Object.entries(def._shape)) {
|
|
@@ -1301,6 +1376,7 @@ function prepareForRead(shape, stored, decryptFn) {
|
|
|
1301
1376
|
const readValue = (def, key, container, ctx = {}) => {
|
|
1302
1377
|
if (!def) return container?.[key];
|
|
1303
1378
|
const action = def._pii?.action;
|
|
1379
|
+
const hasValue = container !== void 0 && container !== null && Object.prototype.hasOwnProperty.call(container, key);
|
|
1304
1380
|
if (action === "encrypt") {
|
|
1305
1381
|
const enc = container?.[key + "Encrypted"] ?? container?.[`${ctx.parentKey ?? key}Encrypted`];
|
|
1306
1382
|
return enc === void 0 ? void 0 : decryptFn(enc);
|
|
@@ -1311,11 +1387,17 @@ function prepareForRead(shape, stored, decryptFn) {
|
|
|
1311
1387
|
}
|
|
1312
1388
|
if (action === "clear")
|
|
1313
1389
|
return container?.hasOwnProperty(key) ? null : void 0;
|
|
1390
|
+
if (!hasValue && def.isRequired === false) {
|
|
1391
|
+
return void 0;
|
|
1392
|
+
}
|
|
1314
1393
|
if (def.type === "object" && def._shape) {
|
|
1315
1394
|
const obj = {};
|
|
1316
1395
|
const source = container && Object.prototype.hasOwnProperty.call(container, key) ? container[key] : container ?? {};
|
|
1317
1396
|
for (const [childKey, childDef] of Object.entries(def._shape)) {
|
|
1318
|
-
|
|
1397
|
+
const child = readValue(childDef, childKey, source);
|
|
1398
|
+
if (child !== void 0) {
|
|
1399
|
+
obj[childKey] = child;
|
|
1400
|
+
}
|
|
1319
1401
|
}
|
|
1320
1402
|
return obj;
|
|
1321
1403
|
}
|
|
@@ -1331,7 +1413,10 @@ function prepareForRead(shape, stored, decryptFn) {
|
|
|
1331
1413
|
const refShape = def._shape;
|
|
1332
1414
|
if (refShape) {
|
|
1333
1415
|
for (const [childKey, childDef] of Object.entries(refShape)) {
|
|
1334
|
-
|
|
1416
|
+
const child = readValue(childDef, childKey, ref);
|
|
1417
|
+
if (child !== void 0) {
|
|
1418
|
+
ref[childKey] = child;
|
|
1419
|
+
}
|
|
1335
1420
|
}
|
|
1336
1421
|
}
|
|
1337
1422
|
return ref;
|
|
@@ -1340,13 +1425,19 @@ function prepareForRead(shape, stored, decryptFn) {
|
|
|
1340
1425
|
};
|
|
1341
1426
|
const result = {};
|
|
1342
1427
|
for (const key in shape) {
|
|
1343
|
-
|
|
1428
|
+
const value = readValue(shape[key], key, stored);
|
|
1429
|
+
if (value !== void 0) {
|
|
1430
|
+
result[key] = value;
|
|
1431
|
+
}
|
|
1344
1432
|
}
|
|
1345
1433
|
return result;
|
|
1346
1434
|
}
|
|
1347
1435
|
function sanitizeForLog(shape, data, pseudonymFn) {
|
|
1348
1436
|
const visit = (def, value, ctx = {}) => {
|
|
1349
1437
|
if (!def) return void 0;
|
|
1438
|
+
if ((value === void 0 || value === null) && def.isRequired === false) {
|
|
1439
|
+
return void 0;
|
|
1440
|
+
}
|
|
1350
1441
|
const handling = def._pii?.logHandling;
|
|
1351
1442
|
if (handling === "omit") return void 0;
|
|
1352
1443
|
if (handling === "redact") return "[REDACTED]";
|
|
@@ -1391,18 +1482,37 @@ function sanitizeForLog(shape, data, pseudonymFn) {
|
|
|
1391
1482
|
}
|
|
1392
1483
|
function getPiiAudit(shape) {
|
|
1393
1484
|
const piiFields = [];
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
if (!def) continue;
|
|
1485
|
+
const visit = (def, path) => {
|
|
1486
|
+
if (!def) return;
|
|
1397
1487
|
if (def._pii && def._pii.classification !== "none") {
|
|
1398
1488
|
piiFields.push({
|
|
1399
|
-
field:
|
|
1489
|
+
field: path,
|
|
1400
1490
|
classification: def._pii.classification,
|
|
1401
1491
|
action: def._pii.action,
|
|
1402
1492
|
logHandling: def._pii.logHandling,
|
|
1403
1493
|
purpose: def._pii.purpose
|
|
1404
1494
|
});
|
|
1405
1495
|
}
|
|
1496
|
+
if ((def.type === "object" || def.type === "ref") && def._shape) {
|
|
1497
|
+
for (const [childKey, childDef] of Object.entries(def._shape)) {
|
|
1498
|
+
visit(childDef, `${path}.${childKey}`);
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
if (def.type === "array" && def.itemType) {
|
|
1502
|
+
const itemPath = `${path}[]`;
|
|
1503
|
+
if ((def.itemType.type === "object" || def.itemType.type === "ref") && def.itemType._shape) {
|
|
1504
|
+
for (const [childKey, childDef] of Object.entries(
|
|
1505
|
+
def.itemType._shape
|
|
1506
|
+
)) {
|
|
1507
|
+
visit(childDef, `${itemPath}.${childKey}`);
|
|
1508
|
+
}
|
|
1509
|
+
} else {
|
|
1510
|
+
visit(def.itemType, itemPath);
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
};
|
|
1514
|
+
for (const key in shape) {
|
|
1515
|
+
visit(shape[key], key);
|
|
1406
1516
|
}
|
|
1407
1517
|
return piiFields;
|
|
1408
1518
|
}
|
|
@@ -1635,9 +1745,7 @@ function validateEnum(parentKey, value, enumValues) {
|
|
|
1635
1745
|
if (Array.isArray(value)) {
|
|
1636
1746
|
const invalid = value.filter((v) => !values.includes(v));
|
|
1637
1747
|
if (invalid.length > 0) {
|
|
1638
|
-
return `Field ${parentKey}
|
|
1639
|
-
", "
|
|
1640
|
-
)}`;
|
|
1748
|
+
return `Field ${parentKey} must contain only: ${values.join(", ")}`;
|
|
1641
1749
|
}
|
|
1642
1750
|
} else {
|
|
1643
1751
|
if (!values.includes(value)) {
|
|
@@ -1671,6 +1779,126 @@ function getValidator(def) {
|
|
|
1671
1779
|
function getShape(def) {
|
|
1672
1780
|
return def?._shape ?? def?.shape ?? void 0;
|
|
1673
1781
|
}
|
|
1782
|
+
var MAX_STRICT_VALIDATION_NODES = 1e4;
|
|
1783
|
+
var MAX_STRICT_VALIDATION_DEPTH = 256;
|
|
1784
|
+
var MAX_STRICT_VALIDATION_OBJECTS = MAX_STRICT_VALIDATION_NODES;
|
|
1785
|
+
function strictInputIsWithinComplexityLimit(input) {
|
|
1786
|
+
const pending = [
|
|
1787
|
+
{ value: input, depth: 0 }
|
|
1788
|
+
];
|
|
1789
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
1790
|
+
let visitedNodes = 0;
|
|
1791
|
+
try {
|
|
1792
|
+
while (pending.length > 0) {
|
|
1793
|
+
const current = pending.pop();
|
|
1794
|
+
if (!current) {
|
|
1795
|
+
continue;
|
|
1796
|
+
}
|
|
1797
|
+
visitedNodes += 1;
|
|
1798
|
+
if (visitedNodes > MAX_STRICT_VALIDATION_NODES || current.depth > MAX_STRICT_VALIDATION_DEPTH) {
|
|
1799
|
+
return false;
|
|
1800
|
+
}
|
|
1801
|
+
if (typeof current.value !== "object" || current.value === null) {
|
|
1802
|
+
continue;
|
|
1803
|
+
}
|
|
1804
|
+
if (seen.has(current.value)) {
|
|
1805
|
+
return false;
|
|
1806
|
+
}
|
|
1807
|
+
seen.add(current.value);
|
|
1808
|
+
const keys = Object.keys(current.value);
|
|
1809
|
+
if (visitedNodes + pending.length + keys.length > MAX_STRICT_VALIDATION_NODES) {
|
|
1810
|
+
return false;
|
|
1811
|
+
}
|
|
1812
|
+
const record = current.value;
|
|
1813
|
+
for (const key of keys) {
|
|
1814
|
+
pending.push({
|
|
1815
|
+
value: record[key],
|
|
1816
|
+
depth: current.depth + 1
|
|
1817
|
+
});
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
} catch {
|
|
1821
|
+
return false;
|
|
1822
|
+
}
|
|
1823
|
+
return true;
|
|
1824
|
+
}
|
|
1825
|
+
function strictReferenceShape(def) {
|
|
1826
|
+
return {
|
|
1827
|
+
type: { type: "string" },
|
|
1828
|
+
id: { type: "string" },
|
|
1829
|
+
...getShape(def) ?? {}
|
|
1830
|
+
};
|
|
1831
|
+
}
|
|
1832
|
+
function unknownFieldLocations(value, shape, location = "root", state = {
|
|
1833
|
+
remainingObjects: MAX_STRICT_VALIDATION_OBJECTS,
|
|
1834
|
+
limitExceeded: false
|
|
1835
|
+
}) {
|
|
1836
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
1837
|
+
return [];
|
|
1838
|
+
}
|
|
1839
|
+
if (state.remainingObjects <= 0) {
|
|
1840
|
+
state.limitExceeded = true;
|
|
1841
|
+
return [];
|
|
1842
|
+
}
|
|
1843
|
+
state.remainingObjects -= 1;
|
|
1844
|
+
const record = value;
|
|
1845
|
+
const knownKeys = new Set(Object.keys(shape));
|
|
1846
|
+
const locations = /* @__PURE__ */ new Set();
|
|
1847
|
+
if (Object.keys(record).some((key) => !knownKeys.has(key))) {
|
|
1848
|
+
locations.add(location);
|
|
1849
|
+
}
|
|
1850
|
+
for (const [key, def] of Object.entries(shape)) {
|
|
1851
|
+
const child = record[key];
|
|
1852
|
+
if (child === void 0 || child === null) {
|
|
1853
|
+
continue;
|
|
1854
|
+
}
|
|
1855
|
+
const childLocation = location === "root" ? key : `${location}.${key}`;
|
|
1856
|
+
const childShape = getShape(def);
|
|
1857
|
+
if (def?.type === "object" && childShape) {
|
|
1858
|
+
for (const nestedLocation of unknownFieldLocations(
|
|
1859
|
+
child,
|
|
1860
|
+
childShape,
|
|
1861
|
+
childLocation,
|
|
1862
|
+
state
|
|
1863
|
+
)) {
|
|
1864
|
+
locations.add(nestedLocation);
|
|
1865
|
+
}
|
|
1866
|
+
continue;
|
|
1867
|
+
}
|
|
1868
|
+
const itemType = def?.itemType;
|
|
1869
|
+
if (def?.type === "array" && (itemType?.type === "object" || itemType?.type === "ref") && Array.isArray(child)) {
|
|
1870
|
+
const itemShape = itemType.type === "ref" ? strictReferenceShape(itemType) : getShape(itemType);
|
|
1871
|
+
if (!itemShape) {
|
|
1872
|
+
continue;
|
|
1873
|
+
}
|
|
1874
|
+
for (const [index, item] of child.entries()) {
|
|
1875
|
+
if (state.limitExceeded) {
|
|
1876
|
+
break;
|
|
1877
|
+
}
|
|
1878
|
+
for (const nestedLocation of unknownFieldLocations(
|
|
1879
|
+
item,
|
|
1880
|
+
itemShape,
|
|
1881
|
+
`${childLocation}[${index}]`,
|
|
1882
|
+
state
|
|
1883
|
+
)) {
|
|
1884
|
+
locations.add(nestedLocation);
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
continue;
|
|
1888
|
+
}
|
|
1889
|
+
if (def?.type === "ref") {
|
|
1890
|
+
for (const nestedLocation of unknownFieldLocations(
|
|
1891
|
+
child,
|
|
1892
|
+
strictReferenceShape(def),
|
|
1893
|
+
childLocation,
|
|
1894
|
+
state
|
|
1895
|
+
)) {
|
|
1896
|
+
locations.add(nestedLocation);
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
return [...locations];
|
|
1901
|
+
}
|
|
1674
1902
|
function normalizeValidationIssue(path, issue, defaultCode) {
|
|
1675
1903
|
if (typeof issue === "string") {
|
|
1676
1904
|
return {
|
|
@@ -2131,6 +2359,8 @@ function createSchema(_shape, entityType, options = {
|
|
|
2131
2359
|
table: "",
|
|
2132
2360
|
schemaValidator: () => true,
|
|
2133
2361
|
piiEnforcement: "none",
|
|
2362
|
+
unknownFields: SCHEMA_UNKNOWN_FIELDS_POLICIES[0],
|
|
2363
|
+
identity: SCHEMA_IDENTITY_POLICIES[0],
|
|
2134
2364
|
schemaUpgrade: void 0
|
|
2135
2365
|
}) {
|
|
2136
2366
|
const systemFields = {
|
|
@@ -2157,6 +2387,57 @@ function createSchema(_shape, entityType, options = {
|
|
|
2157
2387
|
if (typeof input !== "object" || input === null) {
|
|
2158
2388
|
return { valid: false, errors: ["Input must be an object"] };
|
|
2159
2389
|
}
|
|
2390
|
+
if (options.unknownFields === "reject") {
|
|
2391
|
+
if (!strictInputIsWithinComplexityLimit(input)) {
|
|
2392
|
+
return {
|
|
2393
|
+
valid: false,
|
|
2394
|
+
errors: ["Strict validation complexity limit exceeded."],
|
|
2395
|
+
issues: [
|
|
2396
|
+
{
|
|
2397
|
+
path: "root",
|
|
2398
|
+
code: "validation_complexity_limit",
|
|
2399
|
+
message: "Strict validation complexity limit exceeded."
|
|
2400
|
+
}
|
|
2401
|
+
]
|
|
2402
|
+
};
|
|
2403
|
+
}
|
|
2404
|
+
const scanState = {
|
|
2405
|
+
remainingObjects: MAX_STRICT_VALIDATION_OBJECTS,
|
|
2406
|
+
limitExceeded: false
|
|
2407
|
+
};
|
|
2408
|
+
const locations = unknownFieldLocations(
|
|
2409
|
+
input,
|
|
2410
|
+
schema._shape,
|
|
2411
|
+
"root",
|
|
2412
|
+
scanState
|
|
2413
|
+
);
|
|
2414
|
+
if (scanState.limitExceeded) {
|
|
2415
|
+
return {
|
|
2416
|
+
valid: false,
|
|
2417
|
+
errors: ["Strict validation complexity limit exceeded."],
|
|
2418
|
+
issues: [
|
|
2419
|
+
{
|
|
2420
|
+
path: "root",
|
|
2421
|
+
code: "validation_complexity_limit",
|
|
2422
|
+
message: "Strict validation complexity limit exceeded."
|
|
2423
|
+
}
|
|
2424
|
+
]
|
|
2425
|
+
};
|
|
2426
|
+
}
|
|
2427
|
+
if (locations.length > 0) {
|
|
2428
|
+
return {
|
|
2429
|
+
valid: false,
|
|
2430
|
+
errors: locations.map(
|
|
2431
|
+
(location) => `Unknown fields are not allowed at ${location}.`
|
|
2432
|
+
),
|
|
2433
|
+
issues: locations.map((location) => ({
|
|
2434
|
+
path: location,
|
|
2435
|
+
code: "unknown_fields",
|
|
2436
|
+
message: `Unknown fields are not allowed at ${location}.`
|
|
2437
|
+
}))
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2160
2441
|
const working = typeof input === "object" && input !== null ? deepClone(input) : { ...input };
|
|
2161
2442
|
if (working.type == null) working.type = entityType;
|
|
2162
2443
|
if (working.version == null) working.version = version;
|
|
@@ -2179,6 +2460,19 @@ function createSchema(_shape, entityType, options = {
|
|
|
2179
2460
|
working.type = entityType;
|
|
2180
2461
|
working.version = toVersion;
|
|
2181
2462
|
}
|
|
2463
|
+
if (options.identity === "exact" && (working.type !== entityType || working.version !== version)) {
|
|
2464
|
+
return {
|
|
2465
|
+
valid: false,
|
|
2466
|
+
errors: ["Schema type or version does not match the contract."],
|
|
2467
|
+
issues: [
|
|
2468
|
+
{
|
|
2469
|
+
path: "root",
|
|
2470
|
+
code: "schema_identity_mismatch",
|
|
2471
|
+
message: "Schema type or version does not match the contract."
|
|
2472
|
+
}
|
|
2473
|
+
]
|
|
2474
|
+
};
|
|
2475
|
+
}
|
|
2182
2476
|
for (const key in schema._shape) {
|
|
2183
2477
|
const def = schema._shape[key];
|
|
2184
2478
|
let value = working[key];
|
|
@@ -2261,7 +2555,11 @@ function createSchema(_shape, entityType, options = {
|
|
|
2261
2555
|
}
|
|
2262
2556
|
if (errors.length === 0 && options.schemaValidator) {
|
|
2263
2557
|
const castValue = result;
|
|
2264
|
-
|
|
2558
|
+
const source = input;
|
|
2559
|
+
const validationContext = Object.freeze({
|
|
2560
|
+
wasProvided: (fieldName) => Object.prototype.hasOwnProperty.call(source, fieldName)
|
|
2561
|
+
});
|
|
2562
|
+
if (!options.schemaValidator(castValue, validationContext)) {
|
|
2265
2563
|
errors.push("Schema-level validation failed.");
|
|
2266
2564
|
}
|
|
2267
2565
|
}
|
|
@@ -2678,8 +2976,1824 @@ var PlayerSystemCuratedSnapshotSchema = createSchema(
|
|
|
2678
2976
|
piiEnforcement: "strict"
|
|
2679
2977
|
}
|
|
2680
2978
|
);
|
|
2979
|
+
|
|
2980
|
+
// src/feedback-contract-version.ts
|
|
2981
|
+
var FEEDBACK_CONTRACT_VERSION = "1.0.0";
|
|
2982
|
+
|
|
2983
|
+
// src/feedback-diagnostics-vocabulary.ts
|
|
2984
|
+
var FEEDBACK_RENDERER_BUCKETS = [
|
|
2985
|
+
"webgl2",
|
|
2986
|
+
"webgpu",
|
|
2987
|
+
"canvas2d",
|
|
2988
|
+
"unknown"
|
|
2989
|
+
];
|
|
2990
|
+
var FEEDBACK_BACKEND_BUCKETS = [
|
|
2991
|
+
"browser",
|
|
2992
|
+
"worker",
|
|
2993
|
+
"unknown"
|
|
2994
|
+
];
|
|
2995
|
+
var FEEDBACK_GAME_SURFACE_IDS = [
|
|
2996
|
+
"site.generator",
|
|
2997
|
+
"site.gpu-demo"
|
|
2998
|
+
];
|
|
2999
|
+
var FEEDBACK_GAME_PROVENANCE_CONTRACTS = [
|
|
3000
|
+
{
|
|
3001
|
+
surfaceId: "site.generator",
|
|
3002
|
+
contractId: "generator.renderer-diagnostics.v1"
|
|
3003
|
+
},
|
|
3004
|
+
{
|
|
3005
|
+
surfaceId: "site.gpu-demo",
|
|
3006
|
+
contractId: "gpu-demo.renderer-diagnostics.v1"
|
|
3007
|
+
}
|
|
3008
|
+
];
|
|
3009
|
+
var FEEDBACK_GAME_PROVENANCE_CONTRACT_IDS = [
|
|
3010
|
+
"generator.renderer-diagnostics.v1",
|
|
3011
|
+
"gpu-demo.renderer-diagnostics.v1"
|
|
3012
|
+
];
|
|
3013
|
+
var FEEDBACK_GAME_FEATURE_IDS = [
|
|
3014
|
+
"renderer.initialisation",
|
|
3015
|
+
"renderer.frame-loop",
|
|
3016
|
+
"renderer.asset-loading",
|
|
3017
|
+
"renderer.input",
|
|
3018
|
+
"renderer.scene-generation",
|
|
3019
|
+
"renderer.post-processing"
|
|
3020
|
+
];
|
|
3021
|
+
var FEEDBACK_GAME_COUNTER_CODES = [
|
|
3022
|
+
"frame-drop",
|
|
3023
|
+
"device-loss",
|
|
3024
|
+
"asset-load-failure",
|
|
3025
|
+
"shader-failure",
|
|
3026
|
+
"fallback-activation"
|
|
3027
|
+
];
|
|
3028
|
+
var FEEDBACK_GAME_COUNTER_MAX_ITEMS = 32;
|
|
3029
|
+
var FEEDBACK_GAME_COUNTER_MAX_COUNT = 1e4;
|
|
3030
|
+
var FEEDBACK_GAME_ERROR_CODES = [
|
|
3031
|
+
"renderer.initialisation-failed",
|
|
3032
|
+
"renderer.device-lost",
|
|
3033
|
+
"renderer.asset-load-failed",
|
|
3034
|
+
"renderer.frame-budget-exceeded",
|
|
3035
|
+
"renderer.shader-failed",
|
|
3036
|
+
"renderer.unknown"
|
|
3037
|
+
];
|
|
3038
|
+
var FEEDBACK_VIEWPORT_BUCKETS = [
|
|
3039
|
+
"small-portrait",
|
|
3040
|
+
"small-landscape",
|
|
3041
|
+
"medium-portrait",
|
|
3042
|
+
"medium-landscape",
|
|
3043
|
+
"large-portrait",
|
|
3044
|
+
"large-landscape",
|
|
3045
|
+
"unknown"
|
|
3046
|
+
];
|
|
3047
|
+
var FEEDBACK_FRAME_RATE_BUCKETS = [
|
|
3048
|
+
"under-15",
|
|
3049
|
+
"15-29",
|
|
3050
|
+
"30-59",
|
|
3051
|
+
"60-plus",
|
|
3052
|
+
"unknown"
|
|
3053
|
+
];
|
|
3054
|
+
var FEEDBACK_FRAME_TIME_BUCKETS = [
|
|
3055
|
+
"under-17ms",
|
|
3056
|
+
"17-33ms",
|
|
3057
|
+
"34-66ms",
|
|
3058
|
+
"over-66ms",
|
|
3059
|
+
"unknown"
|
|
3060
|
+
];
|
|
3061
|
+
for (const vocabulary of [
|
|
3062
|
+
FEEDBACK_RENDERER_BUCKETS,
|
|
3063
|
+
FEEDBACK_BACKEND_BUCKETS,
|
|
3064
|
+
FEEDBACK_GAME_SURFACE_IDS,
|
|
3065
|
+
FEEDBACK_GAME_PROVENANCE_CONTRACTS,
|
|
3066
|
+
FEEDBACK_GAME_PROVENANCE_CONTRACT_IDS,
|
|
3067
|
+
FEEDBACK_GAME_FEATURE_IDS,
|
|
3068
|
+
FEEDBACK_GAME_COUNTER_CODES,
|
|
3069
|
+
FEEDBACK_GAME_ERROR_CODES,
|
|
3070
|
+
FEEDBACK_VIEWPORT_BUCKETS,
|
|
3071
|
+
FEEDBACK_FRAME_RATE_BUCKETS,
|
|
3072
|
+
FEEDBACK_FRAME_TIME_BUCKETS
|
|
3073
|
+
]) {
|
|
3074
|
+
Object.freeze(vocabulary);
|
|
3075
|
+
}
|
|
3076
|
+
for (const entry of FEEDBACK_GAME_PROVENANCE_CONTRACTS) {
|
|
3077
|
+
Object.freeze(entry);
|
|
3078
|
+
}
|
|
3079
|
+
|
|
3080
|
+
// src/feedback-diagnostics.contract.ts
|
|
3081
|
+
var positiveCountField = (maximum) => field.number().validator((value) => Number.isSafeInteger(value)).min(1).max(maximum);
|
|
3082
|
+
var nestedIdentityShape = () => ({
|
|
3083
|
+
type: field.string().enum(["feedback-game-diagnostics"]),
|
|
3084
|
+
version: field.string().enum([FEEDBACK_CONTRACT_VERSION])
|
|
3085
|
+
});
|
|
3086
|
+
var gameCounterShape = () => ({
|
|
3087
|
+
code: field.string().enum(FEEDBACK_GAME_COUNTER_CODES),
|
|
3088
|
+
count: positiveCountField(FEEDBACK_GAME_COUNTER_MAX_COUNT)
|
|
3089
|
+
});
|
|
3090
|
+
var feedbackGameDiagnosticsShape = (includeIdentity = false) => ({
|
|
3091
|
+
...includeIdentity ? nestedIdentityShape() : {},
|
|
3092
|
+
surfaceId: field.string().enum(FEEDBACK_GAME_SURFACE_IDS),
|
|
3093
|
+
consentConfirmed: field.boolean(),
|
|
3094
|
+
provenanceContractId: field.string().enum(FEEDBACK_GAME_PROVENANCE_CONTRACT_IDS),
|
|
3095
|
+
renderer: field.string().enum(FEEDBACK_RENDERER_BUCKETS),
|
|
3096
|
+
backend: field.string().enum(FEEDBACK_BACKEND_BUCKETS),
|
|
3097
|
+
viewportBucket: field.string().enum(FEEDBACK_VIEWPORT_BUCKETS),
|
|
3098
|
+
frameRateBucket: field.string().enum(FEEDBACK_FRAME_RATE_BUCKETS),
|
|
3099
|
+
frameTimeBucket: field.string().enum(FEEDBACK_FRAME_TIME_BUCKETS),
|
|
3100
|
+
featureIds: field.array(field.string().enum(FEEDBACK_GAME_FEATURE_IDS)).max(FEEDBACK_GAME_FEATURE_IDS.length),
|
|
3101
|
+
counters: field.array(field.object(gameCounterShape())).max(FEEDBACK_GAME_COUNTER_MAX_ITEMS),
|
|
3102
|
+
errorCodes: field.array(field.string().enum(FEEDBACK_GAME_ERROR_CODES)).max(FEEDBACK_GAME_ERROR_CODES.length)
|
|
3103
|
+
});
|
|
3104
|
+
var isFeedbackGameDiagnosticsConsistent = (value) => {
|
|
3105
|
+
const featureIds = Array.isArray(value.featureIds) ? value.featureIds : [];
|
|
3106
|
+
const errorCodes = Array.isArray(value.errorCodes) ? value.errorCodes : [];
|
|
3107
|
+
const counters = Array.isArray(value.counters) ? value.counters : [];
|
|
3108
|
+
const provenance = FEEDBACK_GAME_PROVENANCE_CONTRACTS.find(
|
|
3109
|
+
({ surfaceId }) => surfaceId === value.surfaceId
|
|
3110
|
+
);
|
|
3111
|
+
return value.consentConfirmed === true && provenance !== void 0 && provenance.contractId === value.provenanceContractId && new Set(featureIds).size === featureIds.length && new Set(errorCodes).size === errorCodes.length && new Set(
|
|
3112
|
+
counters.map(
|
|
3113
|
+
(counter) => typeof counter === "object" && counter !== null ? counter.code : void 0
|
|
3114
|
+
)
|
|
3115
|
+
).size === counters.length;
|
|
3116
|
+
};
|
|
3117
|
+
var FeedbackGameDiagnosticsSchema = createSchema(
|
|
3118
|
+
feedbackGameDiagnosticsShape(),
|
|
3119
|
+
"feedback-game-diagnostics",
|
|
3120
|
+
{
|
|
3121
|
+
version: FEEDBACK_CONTRACT_VERSION,
|
|
3122
|
+
piiEnforcement: "strict",
|
|
3123
|
+
unknownFields: "reject",
|
|
3124
|
+
identity: "exact",
|
|
3125
|
+
schemaValidator: isFeedbackGameDiagnosticsConsistent
|
|
3126
|
+
}
|
|
3127
|
+
);
|
|
3128
|
+
var validateFeedbackGameDiagnostics = (input) => {
|
|
3129
|
+
const result = FeedbackGameDiagnosticsSchema.validate(input);
|
|
3130
|
+
if (!result.valid || result.value === void 0) {
|
|
3131
|
+
return {
|
|
3132
|
+
valid: false,
|
|
3133
|
+
errors: result.errors ?? ["Game diagnostics validation failed."],
|
|
3134
|
+
...result.issues === void 0 ? {} : { issues: result.issues }
|
|
3135
|
+
};
|
|
3136
|
+
}
|
|
3137
|
+
return {
|
|
3138
|
+
valid: true,
|
|
3139
|
+
value: result.value
|
|
3140
|
+
};
|
|
3141
|
+
};
|
|
3142
|
+
|
|
3143
|
+
// unicode/feedback-unicode-15.1.0-unassigned.json
|
|
3144
|
+
var feedback_unicode_15_1_0_unassigned_default = {
|
|
3145
|
+
profileId: "unicode-15.1.0-nfkc-v1",
|
|
3146
|
+
unicodeVersion: "15.1.0",
|
|
3147
|
+
sourcePackage: "@unicode/unicode-15.1.0",
|
|
3148
|
+
sourcePackageVersion: "1.6.17",
|
|
3149
|
+
sourceProperty: "General_Category/Unassigned",
|
|
3150
|
+
rangeEncoding: "flat-half-open-delta-uleb128-base64url-v1",
|
|
3151
|
+
rangeCount: 707,
|
|
3152
|
+
endpointCount: 1414,
|
|
3153
|
+
codePointCount: 824718,
|
|
3154
|
+
endpointSha256: "591e457524d6b4b988aa7c7687e76c95a78370fea38bbd1b09085be7fd935ef3",
|
|
3155
|
+
payload: "-AYCBgQHAQEBFAGNAwEmAjICAwE3CBsEBguOAgE8AmUOOwIxAg8BHAIBAQsFHwECBuwBAQgCAgIWAQcBAQMEAgkCAgIECAEEAgEFAhkCAwEGBAICFgEHAQIBAgECAgEBBQQCAgMDAQcEAQEHEQoDAQkBAwEWAQcBAgEFAgoBAwEDAgEPBAIMBwcBAwEIAgICFgEHAQIBBQIJAgICAwcDBAIBBQISCgIBBgMDAQQDAgEBAQIDAgMDAwwEBQMDAQQCAQYBDhUFDQEDARcBEAIJAQMBBAcCAQMCAQIEAgoHFgEDARcBCgEFAgkBAwEEBwIGAgEEAgoBAwwNAQMBMwEDAQYEEAIaAQMBEgMYAQkBAQIHAwEEBgEBAQgGCgIDDDoEHSUCAQEBBQEYAQEBFwIFAQEBBwEKAgQgSAEkBCcBJAEPAQ0lxgEBAQUBAvkCAQQCBwEBAQQCKQEEAiEBBAIHAQEBBAIPATkBBAJDAiADGgZWAgYCnQUDWQcWCRgJFAwNAQMBAgxeAgoGCgYaBlkHKwVGCh8BDAQMBAEDKgIFCywEGgYLAz4CQQEdAgsGCgYOAh8xTQMvAXQIPAMPAzwHKwILCCsFlgQCBgImAgYCCAEBAQEBAQEfAjUBDwEOAgYBEwIDAQkBZQEMAhsBDQMhDyEPjAEElwUZCxWUDgIgAd0CBS0BAQUBAjgHAg4YCQcBBwEHAQcBBwEHAQcBBwF-IhoBWQzWARpQAVYCZwUrAV4BVAswAe3kAQM3CdwCFLgBCMsBBQIBAQEFGDsDCgY4CEYIDAZ0Cx4DTgELBCEBNwkOAgoCZxgcCgYCBgIGCQcBBwE8BH4CCgakVwwXBDEE7kQCaiYHDAUFGgEFAQEBAgECAX0QvQMCNgcBICoGMwETAQQEBQGHAQIBAb4BAwYCBgIGAgMDBwEHCgUCDAEaARMBAgEPAg4iewUDBC0DWAENAwEvLoIBHQMxDxwEJAkeBSsFHgElBA4qngECCgYkBCQEKAg0CwwBDwEHAQIBCwEPAQcBAkO3AgkWCggYBgEqAQlFBgIBASwBAgMBAhcBSAgJMBMBAgUhAxsFAUA4BBQCMgECBQgBAwEdAgMECgcJB0AgJwQMCTYDHQIbBRoHBAwHUEk3Mw0zBy4ICqYCHwEqAQMCAksrCCoWGiYcFBcJTgQkCUQKAQIZBwoGNQESCCcJYAEUCxIBLz4HAQEBBAEPAQsGOwUKBgQBCAICAhYBBwECAQUBCgICAgMCAQYBBQcCBwMFiwFcAQUeSAgKpgE2AiYiRQsKBg0TOgYKNhsCDwQXuQE8ZFMMCAIBAggBAgEeAQICDAkKRggCLgILG0gIUw1JBwr2AQkBLQEOCh0DIAIWAQ5JBwECASwDAQECAQkICgYGAQIBJQECAQYHCrYCGQcRASkDHFYBDzINmwdmbwEFC8QBzBRjDdYIqh_HBLlDuQQHHwEKBFEBCgYeAgYKRgoKAQcBFQUTsAVbZUsEOQcRQAULAg74LwjWCSoJ50UEAQcBAgGjAg8BHQMCAQ4ECIwDhBJrBQ0DCQcKAgjcJC4CFwl0PPYBCicCwgEVRnoUDBQMVwkZhwFVAUcBAgIBAgICBAEMAQEBBwFBAQQCCAEHARwBBAEFAQEDBwHUAgKkAgK-BQ8FAQ_QCB8GBtUBBwERAgcBAgEFBT4hAXAtAw4CCgQCwAIfEToFAdADKuYFBwEEAQIBDwHFAQIQKUwECgQCkQZETD3CAQQBGwECAQECAQEKAQQBAQEBBgEEAQEBAQEBAwECAQECAQEBAQEBAQEBAQIBAQIEAQcBBAEEAQEBCgERBQMBBQERNAKOAiwEZAwPAg8BDwElCq4BOB0NLAQJBwIOBpoB2AcEEQMNA3cEXwYMBAEPDAQ4CAoGKAgeAgJO1AIMDgINAwkHLgEHCA4ECQcJB5MBATclCoYI4M0CILogBt4BAoItDrE6D-4EohOeBOILyyYF4CDRuCsBHmCAAfABkPwD_v8DAv7_AwI"
|
|
3156
|
+
};
|
|
3157
|
+
|
|
3158
|
+
// src/feedback-unicode-profile.codec.ts
|
|
3159
|
+
var BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
3160
|
+
var BASE64URL_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
3161
|
+
var MAX_UNICODE_ENDPOINT = 1114112;
|
|
3162
|
+
var MAX_ENCODED_PAYLOAD_CHARACTERS = 8192;
|
|
3163
|
+
var MAX_ULEB128_BYTES = 5;
|
|
3164
|
+
var MAX_PROFILE_RANGE_COUNT = 707;
|
|
3165
|
+
var MAX_PROFILE_ENDPOINT_COUNT = MAX_PROFILE_RANGE_COUNT * 2;
|
|
3166
|
+
var MAX_PROFILE_CODE_POINT_COUNT = MAX_UNICODE_ENDPOINT;
|
|
3167
|
+
var ARTIFACT_KEYS = /* @__PURE__ */ new Set([
|
|
3168
|
+
"profileId",
|
|
3169
|
+
"unicodeVersion",
|
|
3170
|
+
"sourcePackage",
|
|
3171
|
+
"sourcePackageVersion",
|
|
3172
|
+
"sourceProperty",
|
|
3173
|
+
"rangeEncoding",
|
|
3174
|
+
"rangeCount",
|
|
3175
|
+
"endpointCount",
|
|
3176
|
+
"codePointCount",
|
|
3177
|
+
"endpointSha256",
|
|
3178
|
+
"payload"
|
|
3179
|
+
]);
|
|
3180
|
+
function isRecord(value) {
|
|
3181
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3182
|
+
}
|
|
3183
|
+
function hasExpectedMetadata(artifact, expected) {
|
|
3184
|
+
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;
|
|
3185
|
+
}
|
|
3186
|
+
function isBoundedPositiveInteger(value, maximum) {
|
|
3187
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 && value <= maximum;
|
|
3188
|
+
}
|
|
3189
|
+
function hasBoundedCounts(artifact, expected) {
|
|
3190
|
+
return isBoundedPositiveInteger(
|
|
3191
|
+
artifact.rangeCount,
|
|
3192
|
+
MAX_PROFILE_RANGE_COUNT
|
|
3193
|
+
) && isBoundedPositiveInteger(
|
|
3194
|
+
expected.rangeCount,
|
|
3195
|
+
MAX_PROFILE_RANGE_COUNT
|
|
3196
|
+
) && isBoundedPositiveInteger(
|
|
3197
|
+
artifact.endpointCount,
|
|
3198
|
+
MAX_PROFILE_ENDPOINT_COUNT
|
|
3199
|
+
) && isBoundedPositiveInteger(
|
|
3200
|
+
expected.endpointCount,
|
|
3201
|
+
MAX_PROFILE_ENDPOINT_COUNT
|
|
3202
|
+
) && artifact.endpointCount === artifact.rangeCount * 2 && expected.endpointCount === expected.rangeCount * 2 && isBoundedPositiveInteger(
|
|
3203
|
+
artifact.codePointCount,
|
|
3204
|
+
MAX_PROFILE_CODE_POINT_COUNT
|
|
3205
|
+
) && isBoundedPositiveInteger(
|
|
3206
|
+
expected.codePointCount,
|
|
3207
|
+
MAX_PROFILE_CODE_POINT_COUNT
|
|
3208
|
+
);
|
|
3209
|
+
}
|
|
3210
|
+
function decodeCanonicalBase64Url(value) {
|
|
3211
|
+
if (value.length === 0 || value.length > MAX_ENCODED_PAYLOAD_CHARACTERS || value.length % 4 === 1 || !BASE64URL_PATTERN.test(value)) {
|
|
3212
|
+
return void 0;
|
|
3213
|
+
}
|
|
3214
|
+
const finalSextet = BASE64URL_ALPHABET.indexOf(value.at(-1) ?? "");
|
|
3215
|
+
if (finalSextet < 0 || value.length % 4 === 2 && (finalSextet & 15) !== 0 || value.length % 4 === 3 && (finalSextet & 3) !== 0) {
|
|
3216
|
+
return void 0;
|
|
3217
|
+
}
|
|
3218
|
+
const expectedByteCount = Math.floor(value.length * 6 / 8);
|
|
3219
|
+
const output = new Uint8Array(expectedByteCount);
|
|
3220
|
+
let outputIndex = 0;
|
|
3221
|
+
let accumulator = 0;
|
|
3222
|
+
let bitCount = 0;
|
|
3223
|
+
for (const character of value) {
|
|
3224
|
+
const sextet = BASE64URL_ALPHABET.indexOf(character);
|
|
3225
|
+
if (sextet < 0) {
|
|
3226
|
+
return void 0;
|
|
3227
|
+
}
|
|
3228
|
+
accumulator = accumulator << 6 | sextet;
|
|
3229
|
+
bitCount += 6;
|
|
3230
|
+
while (bitCount >= 8) {
|
|
3231
|
+
bitCount -= 8;
|
|
3232
|
+
output[outputIndex] = accumulator >> bitCount & 255;
|
|
3233
|
+
outputIndex += 1;
|
|
3234
|
+
accumulator &= (1 << bitCount) - 1;
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
if (outputIndex !== expectedByteCount || bitCount > 0 && accumulator !== 0) {
|
|
3238
|
+
return void 0;
|
|
3239
|
+
}
|
|
3240
|
+
return output;
|
|
3241
|
+
}
|
|
3242
|
+
function decodeCanonicalEndpointDeltas(bytes, endpointCount) {
|
|
3243
|
+
if (!isBoundedPositiveInteger(
|
|
3244
|
+
endpointCount,
|
|
3245
|
+
MAX_PROFILE_ENDPOINT_COUNT
|
|
3246
|
+
) || endpointCount % 2 !== 0) {
|
|
3247
|
+
return void 0;
|
|
3248
|
+
}
|
|
3249
|
+
const endpoints = new Uint32Array(endpointCount);
|
|
3250
|
+
let byteOffset = 0;
|
|
3251
|
+
let previousEndpoint = 0;
|
|
3252
|
+
for (let endpointIndex = 0; endpointIndex < endpointCount; endpointIndex += 1) {
|
|
3253
|
+
let delta = 0;
|
|
3254
|
+
let multiplier = 1;
|
|
3255
|
+
let byteCount = 0;
|
|
3256
|
+
while (true) {
|
|
3257
|
+
if (byteOffset >= bytes.length || byteCount >= MAX_ULEB128_BYTES) {
|
|
3258
|
+
return void 0;
|
|
3259
|
+
}
|
|
3260
|
+
const byte = bytes[byteOffset];
|
|
3261
|
+
if (byte === void 0) {
|
|
3262
|
+
return void 0;
|
|
3263
|
+
}
|
|
3264
|
+
byteOffset += 1;
|
|
3265
|
+
byteCount += 1;
|
|
3266
|
+
const payload = byte & 127;
|
|
3267
|
+
delta += payload * multiplier;
|
|
3268
|
+
if (!Number.isSafeInteger(delta)) {
|
|
3269
|
+
return void 0;
|
|
3270
|
+
}
|
|
3271
|
+
if ((byte & 128) === 0) {
|
|
3272
|
+
if (byteCount > 1 && payload === 0) {
|
|
3273
|
+
return void 0;
|
|
3274
|
+
}
|
|
3275
|
+
break;
|
|
3276
|
+
}
|
|
3277
|
+
multiplier *= 128;
|
|
3278
|
+
}
|
|
3279
|
+
const endpoint = previousEndpoint + delta;
|
|
3280
|
+
if (delta <= 0 || !Number.isSafeInteger(endpoint) || endpoint > MAX_UNICODE_ENDPOINT) {
|
|
3281
|
+
return void 0;
|
|
3282
|
+
}
|
|
3283
|
+
endpoints[endpointIndex] = endpoint;
|
|
3284
|
+
previousEndpoint = endpoint;
|
|
3285
|
+
}
|
|
3286
|
+
if (byteOffset !== bytes.length) {
|
|
3287
|
+
return void 0;
|
|
3288
|
+
}
|
|
3289
|
+
return endpoints;
|
|
3290
|
+
}
|
|
3291
|
+
function hasExpectedRanges(endpoints, expected) {
|
|
3292
|
+
let previousEnd = -1;
|
|
3293
|
+
let codePointCount = 0;
|
|
3294
|
+
for (let index = 0; index < endpoints.length; index += 2) {
|
|
3295
|
+
const start = endpoints[index];
|
|
3296
|
+
const end = endpoints[index + 1];
|
|
3297
|
+
if (start === void 0 || end === void 0 || start <= previousEnd || end <= start || end > MAX_UNICODE_ENDPOINT) {
|
|
3298
|
+
return false;
|
|
3299
|
+
}
|
|
3300
|
+
codePointCount += end - start;
|
|
3301
|
+
previousEnd = end;
|
|
3302
|
+
}
|
|
3303
|
+
return codePointCount === expected.codePointCount;
|
|
3304
|
+
}
|
|
3305
|
+
function decodeFeedbackUnicodeProfileArtifact(value, expected) {
|
|
3306
|
+
if (!isRecord(value) || !hasBoundedCounts(value, expected) || !hasExpectedMetadata(value, expected) || typeof value.payload !== "string") {
|
|
3307
|
+
return void 0;
|
|
3308
|
+
}
|
|
3309
|
+
const bytes = decodeCanonicalBase64Url(value.payload);
|
|
3310
|
+
if (bytes === void 0) {
|
|
3311
|
+
return void 0;
|
|
3312
|
+
}
|
|
3313
|
+
const endpoints = decodeCanonicalEndpointDeltas(
|
|
3314
|
+
bytes,
|
|
3315
|
+
expected.endpointCount
|
|
3316
|
+
);
|
|
3317
|
+
return endpoints !== void 0 && hasExpectedRanges(endpoints, expected) ? endpoints : void 0;
|
|
3318
|
+
}
|
|
3319
|
+
|
|
3320
|
+
// src/feedback-unicode-profile.ts
|
|
3321
|
+
var FEEDBACK_UNICODE_PROFILE_ID = "unicode-15.1.0-nfkc-v1";
|
|
3322
|
+
var FEEDBACK_UNICODE_PROFILE_ENDPOINT_SHA256 = "591e457524d6b4b988aa7c7687e76c95a78370fea38bbd1b09085be7fd935ef3";
|
|
3323
|
+
var MAX_UNICODE_CODE_POINT = 1114111;
|
|
3324
|
+
var HIGH_SURROGATE_START = 55296;
|
|
3325
|
+
var HIGH_SURROGATE_END = 56319;
|
|
3326
|
+
var LOW_SURROGATE_START = 56320;
|
|
3327
|
+
var LOW_SURROGATE_END = 57343;
|
|
3328
|
+
var UNASSIGNED_RANGE_ENDPOINTS = decodeFeedbackUnicodeProfileArtifact(
|
|
3329
|
+
feedback_unicode_15_1_0_unassigned_default,
|
|
3330
|
+
{
|
|
3331
|
+
profileId: FEEDBACK_UNICODE_PROFILE_ID,
|
|
3332
|
+
unicodeVersion: "15.1.0",
|
|
3333
|
+
sourcePackage: "@unicode/unicode-15.1.0",
|
|
3334
|
+
sourcePackageVersion: "1.6.17",
|
|
3335
|
+
sourceProperty: "General_Category/Unassigned",
|
|
3336
|
+
rangeEncoding: "flat-half-open-delta-uleb128-base64url-v1",
|
|
3337
|
+
rangeCount: 707,
|
|
3338
|
+
endpointCount: 1414,
|
|
3339
|
+
codePointCount: 824718,
|
|
3340
|
+
endpointSha256: FEEDBACK_UNICODE_PROFILE_ENDPOINT_SHA256
|
|
3341
|
+
}
|
|
3342
|
+
);
|
|
3343
|
+
function isFeedbackUnicodeProfileUnassigned(codePoint) {
|
|
3344
|
+
if (UNASSIGNED_RANGE_ENDPOINTS === void 0 || !Number.isInteger(codePoint) || codePoint < 0 || codePoint > MAX_UNICODE_CODE_POINT || codePoint >= HIGH_SURROGATE_START && codePoint <= LOW_SURROGATE_END) {
|
|
3345
|
+
return true;
|
|
3346
|
+
}
|
|
3347
|
+
let lowerRange = 0;
|
|
3348
|
+
let upperRange = UNASSIGNED_RANGE_ENDPOINTS.length / 2 - 1;
|
|
3349
|
+
while (lowerRange <= upperRange) {
|
|
3350
|
+
const rangeIndex = Math.floor((lowerRange + upperRange) / 2);
|
|
3351
|
+
const start = UNASSIGNED_RANGE_ENDPOINTS[rangeIndex * 2];
|
|
3352
|
+
const end = UNASSIGNED_RANGE_ENDPOINTS[rangeIndex * 2 + 1];
|
|
3353
|
+
if (start === void 0 || end === void 0) {
|
|
3354
|
+
return true;
|
|
3355
|
+
}
|
|
3356
|
+
if (codePoint < start) {
|
|
3357
|
+
upperRange = rangeIndex - 1;
|
|
3358
|
+
} else if (codePoint >= end) {
|
|
3359
|
+
lowerRange = rangeIndex + 1;
|
|
3360
|
+
} else {
|
|
3361
|
+
return true;
|
|
3362
|
+
}
|
|
3363
|
+
}
|
|
3364
|
+
return false;
|
|
3365
|
+
}
|
|
3366
|
+
function containsFeedbackUnicodeProfileUnsupportedText(text) {
|
|
3367
|
+
if (typeof text !== "string") {
|
|
3368
|
+
return true;
|
|
3369
|
+
}
|
|
3370
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
3371
|
+
const first = text.charCodeAt(index);
|
|
3372
|
+
let codePoint = first;
|
|
3373
|
+
if (first >= HIGH_SURROGATE_START && first <= HIGH_SURROGATE_END) {
|
|
3374
|
+
const second = text.charCodeAt(index + 1);
|
|
3375
|
+
if (!Number.isInteger(second) || second < LOW_SURROGATE_START || second > LOW_SURROGATE_END) {
|
|
3376
|
+
return true;
|
|
3377
|
+
}
|
|
3378
|
+
codePoint = 65536 + (first - HIGH_SURROGATE_START << 10) + (second - LOW_SURROGATE_START);
|
|
3379
|
+
index += 1;
|
|
3380
|
+
} else if (first >= LOW_SURROGATE_START && first <= LOW_SURROGATE_END) {
|
|
3381
|
+
return true;
|
|
3382
|
+
}
|
|
3383
|
+
if (isFeedbackUnicodeProfileUnassigned(codePoint)) {
|
|
3384
|
+
return true;
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
return false;
|
|
3388
|
+
}
|
|
3389
|
+
|
|
3390
|
+
// src/feedback.ts
|
|
3391
|
+
var FEEDBACK_UNICODE_NORMALIZATION_PROFILE = FEEDBACK_UNICODE_PROFILE_ID;
|
|
3392
|
+
var FEEDBACK_BUG_COOLDOWN_SECONDS = Object.freeze([
|
|
3393
|
+
5 * 60,
|
|
3394
|
+
15 * 60,
|
|
3395
|
+
60 * 60,
|
|
3396
|
+
6 * 60 * 60,
|
|
3397
|
+
24 * 60 * 60
|
|
3398
|
+
]);
|
|
3399
|
+
var FEEDBACK_REVIEW_COOLDOWN_SECONDS = 30 * 24 * 60 * 60;
|
|
3400
|
+
var FEEDBACK_ISSUE_TYPES = [
|
|
3401
|
+
"visual-layout",
|
|
3402
|
+
"functionality",
|
|
3403
|
+
"gameplay",
|
|
3404
|
+
"performance-stability",
|
|
3405
|
+
"accessibility",
|
|
3406
|
+
"content-localisation",
|
|
3407
|
+
"account-access",
|
|
3408
|
+
"privacy-security",
|
|
3409
|
+
"other"
|
|
3410
|
+
];
|
|
3411
|
+
var FEEDBACK_PERSISTABLE_ISSUE_TYPES = FEEDBACK_ISSUE_TYPES.filter(
|
|
3412
|
+
(issueType) => issueType !== "privacy-security"
|
|
3413
|
+
);
|
|
3414
|
+
var FEEDBACK_SEVERITY_LEVELS = [
|
|
3415
|
+
{ value: 1, id: "cosmetic", labelKey: "feedback.severity.cosmetic" },
|
|
3416
|
+
{ value: 2, id: "minor", labelKey: "feedback.severity.minor" },
|
|
3417
|
+
{ value: 3, id: "disruptive", labelKey: "feedback.severity.disruptive" },
|
|
3418
|
+
{ value: 4, id: "blocking", labelKey: "feedback.severity.blocking" },
|
|
3419
|
+
{ value: 5, id: "critical", labelKey: "feedback.severity.critical" }
|
|
3420
|
+
];
|
|
3421
|
+
var FEEDBACK_SATISFACTION_LEVELS = [
|
|
3422
|
+
{ value: 1, id: "very-poor", labelKey: "feedback.satisfaction.very-poor" },
|
|
3423
|
+
{ value: 2, id: "poor", labelKey: "feedback.satisfaction.poor" },
|
|
3424
|
+
{ value: 3, id: "fair", labelKey: "feedback.satisfaction.fair" },
|
|
3425
|
+
{ value: 4, id: "good", labelKey: "feedback.satisfaction.good" },
|
|
3426
|
+
{ value: 5, id: "excellent", labelKey: "feedback.satisfaction.excellent" }
|
|
3427
|
+
];
|
|
3428
|
+
var FEEDBACK_SENTIMENT_BUCKETS = [
|
|
3429
|
+
"very-negative",
|
|
3430
|
+
"negative",
|
|
3431
|
+
"mixed",
|
|
3432
|
+
"neutral",
|
|
3433
|
+
"positive",
|
|
3434
|
+
"very-positive",
|
|
3435
|
+
"not-detected"
|
|
3436
|
+
];
|
|
3437
|
+
var FEEDBACK_INTENT_IDS = [
|
|
3438
|
+
"visual-layout",
|
|
3439
|
+
"functionality",
|
|
3440
|
+
"gameplay",
|
|
3441
|
+
"performance-stability",
|
|
3442
|
+
"accessibility",
|
|
3443
|
+
"content-localisation",
|
|
3444
|
+
"account-access",
|
|
3445
|
+
"other",
|
|
3446
|
+
"praise",
|
|
3447
|
+
"suggestion",
|
|
3448
|
+
"confusion",
|
|
3449
|
+
"frustration"
|
|
3450
|
+
];
|
|
3451
|
+
var FEEDBACK_THEME_IDS = [
|
|
3452
|
+
"navigation",
|
|
3453
|
+
"visual-design",
|
|
3454
|
+
"game-controls",
|
|
3455
|
+
"rendering",
|
|
3456
|
+
"responsiveness",
|
|
3457
|
+
"stability",
|
|
3458
|
+
"accessibility",
|
|
3459
|
+
"localisation",
|
|
3460
|
+
"account-access",
|
|
3461
|
+
"overall-experience",
|
|
3462
|
+
"other"
|
|
3463
|
+
];
|
|
3464
|
+
var FEEDBACK_SURFACE_IDS = [
|
|
3465
|
+
"site.about",
|
|
3466
|
+
"admin.analytics",
|
|
3467
|
+
"admin.capabilities",
|
|
3468
|
+
"admin.feature-flags",
|
|
3469
|
+
"admin.feedback",
|
|
3470
|
+
"admin.moderation",
|
|
3471
|
+
"admin.users",
|
|
3472
|
+
"site.chatbot",
|
|
3473
|
+
"site.generator",
|
|
3474
|
+
"site.gpu-demo",
|
|
3475
|
+
"site.home",
|
|
3476
|
+
"game.player-system",
|
|
3477
|
+
"account.profile",
|
|
3478
|
+
"site.video"
|
|
3479
|
+
];
|
|
3480
|
+
var FEEDBACK_SURFACE_DEFINITIONS = [
|
|
3481
|
+
{
|
|
3482
|
+
id: "site.about",
|
|
3483
|
+
labelKey: "feedback.surface.about",
|
|
3484
|
+
kind: "public",
|
|
3485
|
+
gameDiagnosticsEligible: false
|
|
3486
|
+
},
|
|
3487
|
+
{
|
|
3488
|
+
id: "admin.analytics",
|
|
3489
|
+
labelKey: "feedback.surface.adminAnalytics",
|
|
3490
|
+
kind: "admin",
|
|
3491
|
+
gameDiagnosticsEligible: false
|
|
3492
|
+
},
|
|
3493
|
+
{
|
|
3494
|
+
id: "admin.capabilities",
|
|
3495
|
+
labelKey: "feedback.surface.adminCapabilities",
|
|
3496
|
+
kind: "admin",
|
|
3497
|
+
gameDiagnosticsEligible: false
|
|
3498
|
+
},
|
|
3499
|
+
{
|
|
3500
|
+
id: "admin.feature-flags",
|
|
3501
|
+
labelKey: "feedback.surface.adminFeatureFlags",
|
|
3502
|
+
kind: "admin",
|
|
3503
|
+
gameDiagnosticsEligible: false
|
|
3504
|
+
},
|
|
3505
|
+
{
|
|
3506
|
+
id: "admin.feedback",
|
|
3507
|
+
labelKey: "feedback.surface.adminFeedback",
|
|
3508
|
+
kind: "admin",
|
|
3509
|
+
gameDiagnosticsEligible: false
|
|
3510
|
+
},
|
|
3511
|
+
{
|
|
3512
|
+
id: "admin.moderation",
|
|
3513
|
+
labelKey: "feedback.surface.adminModeration",
|
|
3514
|
+
kind: "admin",
|
|
3515
|
+
gameDiagnosticsEligible: false
|
|
3516
|
+
},
|
|
3517
|
+
{
|
|
3518
|
+
id: "admin.users",
|
|
3519
|
+
labelKey: "feedback.surface.adminUsers",
|
|
3520
|
+
kind: "admin",
|
|
3521
|
+
gameDiagnosticsEligible: false
|
|
3522
|
+
},
|
|
3523
|
+
{
|
|
3524
|
+
id: "site.chatbot",
|
|
3525
|
+
labelKey: "feedback.surface.chatbot",
|
|
3526
|
+
kind: "public",
|
|
3527
|
+
gameDiagnosticsEligible: false
|
|
3528
|
+
},
|
|
3529
|
+
{
|
|
3530
|
+
id: "site.generator",
|
|
3531
|
+
labelKey: "feedback.surface.generator",
|
|
3532
|
+
kind: "game",
|
|
3533
|
+
gameDiagnosticsEligible: true
|
|
3534
|
+
},
|
|
3535
|
+
{
|
|
3536
|
+
id: "site.gpu-demo",
|
|
3537
|
+
labelKey: "feedback.surface.gpuDemo",
|
|
3538
|
+
kind: "game",
|
|
3539
|
+
gameDiagnosticsEligible: true
|
|
3540
|
+
},
|
|
3541
|
+
{
|
|
3542
|
+
id: "site.home",
|
|
3543
|
+
labelKey: "feedback.surface.home",
|
|
3544
|
+
kind: "public",
|
|
3545
|
+
gameDiagnosticsEligible: false
|
|
3546
|
+
},
|
|
3547
|
+
{
|
|
3548
|
+
id: "game.player-system",
|
|
3549
|
+
labelKey: "feedback.surface.playerSystem",
|
|
3550
|
+
kind: "game",
|
|
3551
|
+
gameDiagnosticsEligible: false
|
|
3552
|
+
},
|
|
3553
|
+
{
|
|
3554
|
+
id: "account.profile",
|
|
3555
|
+
labelKey: "feedback.surface.profile",
|
|
3556
|
+
kind: "authenticated",
|
|
3557
|
+
gameDiagnosticsEligible: false
|
|
3558
|
+
},
|
|
3559
|
+
{
|
|
3560
|
+
id: "site.video",
|
|
3561
|
+
labelKey: "feedback.surface.video",
|
|
3562
|
+
kind: "public",
|
|
3563
|
+
gameDiagnosticsEligible: false
|
|
3564
|
+
}
|
|
3565
|
+
];
|
|
3566
|
+
var FEEDBACK_STRUCTURED_ONLY_REASON_CODES = [
|
|
3567
|
+
"analysis-unavailable",
|
|
3568
|
+
"invalid-envelope",
|
|
3569
|
+
"invalid-sensitive-payload",
|
|
3570
|
+
"language-not-enabled",
|
|
3571
|
+
"request-too-large",
|
|
3572
|
+
"length-required"
|
|
3573
|
+
];
|
|
3574
|
+
var FEEDBACK_PRIVACY_POLICY_VERSIONS = [
|
|
3575
|
+
"feedback-privacy-en-v1"
|
|
3576
|
+
];
|
|
3577
|
+
var FEEDBACK_ANALYSIS_MODEL_VERSIONS = [
|
|
3578
|
+
"feedback-en-rules-v1"
|
|
3579
|
+
];
|
|
3580
|
+
for (const vocabulary of [
|
|
3581
|
+
FEEDBACK_BUG_COOLDOWN_SECONDS,
|
|
3582
|
+
FEEDBACK_ISSUE_TYPES,
|
|
3583
|
+
FEEDBACK_PERSISTABLE_ISSUE_TYPES,
|
|
3584
|
+
FEEDBACK_SEVERITY_LEVELS,
|
|
3585
|
+
FEEDBACK_SATISFACTION_LEVELS,
|
|
3586
|
+
FEEDBACK_SENTIMENT_BUCKETS,
|
|
3587
|
+
FEEDBACK_INTENT_IDS,
|
|
3588
|
+
FEEDBACK_THEME_IDS,
|
|
3589
|
+
FEEDBACK_SURFACE_IDS,
|
|
3590
|
+
FEEDBACK_SURFACE_DEFINITIONS,
|
|
3591
|
+
FEEDBACK_STRUCTURED_ONLY_REASON_CODES,
|
|
3592
|
+
FEEDBACK_PRIVACY_POLICY_VERSIONS,
|
|
3593
|
+
FEEDBACK_ANALYSIS_MODEL_VERSIONS
|
|
3594
|
+
]) {
|
|
3595
|
+
Object.freeze(vocabulary);
|
|
3596
|
+
}
|
|
3597
|
+
for (const entry of [
|
|
3598
|
+
...FEEDBACK_SEVERITY_LEVELS,
|
|
3599
|
+
...FEEDBACK_SATISFACTION_LEVELS,
|
|
3600
|
+
...FEEDBACK_SURFACE_DEFINITIONS
|
|
3601
|
+
]) {
|
|
3602
|
+
Object.freeze(entry);
|
|
3603
|
+
}
|
|
3604
|
+
var SAFE_ID_PATTERN = /^[a-z0-9][a-z0-9._:-]*$/i;
|
|
3605
|
+
var INGESTION_KEY_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
3606
|
+
var BASE64URL_PATTERN2 = /^[A-Za-z0-9_-]+$/;
|
|
3607
|
+
var OPAQUE_UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
3608
|
+
var DISALLOWED_NARRATIVE_SYNTAX_PATTERN = /<|>|(?:https?|ftp|mailto|javascript|data|blob|file):|\/\/|www\.|\]\s*\(/i;
|
|
3609
|
+
var DISALLOWED_UNICODE_FORMAT_PATTERN = /\p{Cf}/u;
|
|
3610
|
+
var MAX_NARRATIVE_CHARACTERS = 4e3;
|
|
3611
|
+
var MAX_NARRATIVE_UTF16_CODE_UNITS = 8e3;
|
|
3612
|
+
var MAX_COUNT = 1e9;
|
|
3613
|
+
var BASE64URL_ALPHABET2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
3614
|
+
var BUG_HOUR_WINDOW_PATTERN = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])T(?:[01]\d|2[0-3])$/;
|
|
3615
|
+
var REVIEW_DAY_WINDOW_PATTERN = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/;
|
|
3616
|
+
var RECONCILIATION_WINDOW_PATTERN = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])T(?:[01]\d|2[0-3]):(?:[0-5]\d)$/;
|
|
3617
|
+
var strictOptions = {
|
|
3618
|
+
version: FEEDBACK_CONTRACT_VERSION,
|
|
3619
|
+
piiEnforcement: "strict",
|
|
3620
|
+
unknownFields: "reject",
|
|
3621
|
+
identity: "exact"
|
|
3622
|
+
};
|
|
3623
|
+
var uuidField = () => field.string().validator((value) => OPAQUE_UUID_V4_PATTERN.test(value)).description("Opaque UUID generated for the feedback workflow");
|
|
3624
|
+
var draftIdField = () => field.string().validator((value) => OPAQUE_UUID_V4_PATTERN.test(value)).description("Opaque identifier for one short-lived structured draft").PID({
|
|
3625
|
+
classification: "low",
|
|
3626
|
+
action: "none",
|
|
3627
|
+
logHandling: "omit",
|
|
3628
|
+
purpose: "short-lived feedback draft lookup that must never enter logs"
|
|
3629
|
+
});
|
|
3630
|
+
var safeIdField = (maximum = 128) => field.string().min(1).max(maximum).pattern(SAFE_ID_PATTERN);
|
|
3631
|
+
var ingestionKeyIdField = () => field.string().min(1).max(80).pattern(INGESTION_KEY_ID_PATTERN);
|
|
3632
|
+
var decodeCanonicalBase64Url2 = (value) => {
|
|
3633
|
+
if (!BASE64URL_PATTERN2.test(value) || value.length % 4 === 1) {
|
|
3634
|
+
return void 0;
|
|
3635
|
+
}
|
|
3636
|
+
const finalValue = BASE64URL_ALPHABET2.indexOf(value.at(-1) ?? "");
|
|
3637
|
+
if (finalValue < 0 || value.length % 4 === 2 && (finalValue & 15) !== 0 || value.length % 4 === 3 && (finalValue & 3) !== 0) {
|
|
3638
|
+
return void 0;
|
|
3639
|
+
}
|
|
3640
|
+
const output = [];
|
|
3641
|
+
let accumulator = 0;
|
|
3642
|
+
let bitCount = 0;
|
|
3643
|
+
for (const character of value) {
|
|
3644
|
+
const sextet = BASE64URL_ALPHABET2.indexOf(character);
|
|
3645
|
+
if (sextet < 0) {
|
|
3646
|
+
return void 0;
|
|
3647
|
+
}
|
|
3648
|
+
accumulator = accumulator << 6 | sextet;
|
|
3649
|
+
bitCount += 6;
|
|
3650
|
+
while (bitCount >= 8) {
|
|
3651
|
+
bitCount -= 8;
|
|
3652
|
+
output.push(accumulator >> bitCount & 255);
|
|
3653
|
+
accumulator &= (1 << bitCount) - 1;
|
|
3654
|
+
}
|
|
3655
|
+
}
|
|
3656
|
+
return Uint8Array.from(output);
|
|
3657
|
+
};
|
|
3658
|
+
var isCanonicalRsaModulus = (value) => {
|
|
3659
|
+
const bytes = decodeCanonicalBase64Url2(value);
|
|
3660
|
+
return bytes !== void 0 && (bytes.length === 256 || bytes.length === 384 || bytes.length === 512) && (bytes[0] ?? 0) >= 128 && ((bytes.at(-1) ?? 0) & 1) === 1;
|
|
3661
|
+
};
|
|
3662
|
+
var isCanonicalRsaExponent = (value) => {
|
|
3663
|
+
const bytes = decodeCanonicalBase64Url2(value);
|
|
3664
|
+
if (bytes === void 0 || bytes.length < 1 || bytes.length > 4 || bytes[0] === 0) {
|
|
3665
|
+
return false;
|
|
3666
|
+
}
|
|
3667
|
+
const exponent = bytes.reduce(
|
|
3668
|
+
(total, byte) => total * 256 + byte,
|
|
3669
|
+
0
|
|
3670
|
+
);
|
|
3671
|
+
return exponent >= 3 && exponent % 2 === 1;
|
|
3672
|
+
};
|
|
3673
|
+
var surfaceIdField = () => field.string().enum(FEEDBACK_SURFACE_IDS);
|
|
3674
|
+
var countField = () => field.number().validator((value) => Number.isSafeInteger(value)).min(0).max(MAX_COUNT);
|
|
3675
|
+
var positiveCountField2 = (maximum = MAX_COUNT) => field.number().validator((value) => Number.isSafeInteger(value)).min(1).max(maximum);
|
|
3676
|
+
var redactionCountField = () => field.number().validator((value) => Number.isSafeInteger(value)).min(0).max(MAX_NARRATIVE_CHARACTERS);
|
|
3677
|
+
var revisionField = () => field.number().validator((value) => Number.isSafeInteger(value)).min(0).max(1e6);
|
|
3678
|
+
var ratingField = () => field.number().validator((value) => Number.isInteger(value)).min(1).max(5);
|
|
3679
|
+
var narrativeTextField = () => field.string().validator(
|
|
3680
|
+
(value) => typeof value === "string" && value.length >= 1 && value.length <= MAX_NARRATIVE_UTF16_CODE_UNITS && !containsFeedbackUnicodeProfileUnsupportedText(value) && value.normalize("NFKC") === value && [...value].length <= MAX_NARRATIVE_CHARACTERS && !DISALLOWED_NARRATIVE_SYNTAX_PATTERN.test(value) && !DISALLOWED_UNICODE_FORMAT_PATTERN.test(value) && ![...value].some((character) => {
|
|
3681
|
+
const codePoint = character.codePointAt(0);
|
|
3682
|
+
return codePoint !== void 0 && (codePoint < 32 || codePoint === 127);
|
|
3683
|
+
})
|
|
3684
|
+
).min(1).max(MAX_NARRATIVE_UTF16_CODE_UNITS).PID({
|
|
3685
|
+
classification: "high",
|
|
3686
|
+
action: "clear",
|
|
3687
|
+
logHandling: "omit",
|
|
3688
|
+
purpose: "transient feedback narrative that must be discarded after classification"
|
|
3689
|
+
});
|
|
3690
|
+
var transientCorrelationIdField = () => field.string().validator((value) => OPAQUE_UUID_V4_PATTERN.test(value)).PID({
|
|
3691
|
+
classification: "low",
|
|
3692
|
+
action: "clear",
|
|
3693
|
+
logHandling: "omit",
|
|
3694
|
+
purpose: "one-use transient feedback correlation"
|
|
3695
|
+
});
|
|
3696
|
+
var transientEncryptedField = (minimum, maximum, allowedLengths) => field.string().min(minimum).max(maximum).pattern(BASE64URL_PATTERN2).validator(
|
|
3697
|
+
(value) => {
|
|
3698
|
+
const decoded = decodeCanonicalBase64Url2(value);
|
|
3699
|
+
return decoded !== void 0 && decoded.length > 0 && (allowedLengths === void 0 || allowedLengths.includes(value.length));
|
|
3700
|
+
}
|
|
3701
|
+
).PID({
|
|
3702
|
+
classification: "high",
|
|
3703
|
+
action: "clear",
|
|
3704
|
+
logHandling: "omit",
|
|
3705
|
+
purpose: "encrypted transient feedback narrative material"
|
|
3706
|
+
});
|
|
3707
|
+
var richTextNodeShape = () => ({
|
|
3708
|
+
type: field.string().enum(["text"]),
|
|
3709
|
+
text: narrativeTextField(),
|
|
3710
|
+
marks: field.array(
|
|
3711
|
+
field.string().enum(["bold", "italic", "underline"])
|
|
3712
|
+
).max(3).optional()
|
|
3713
|
+
});
|
|
3714
|
+
var richTextBlockShape = () => ({
|
|
3715
|
+
type: field.string().enum(["paragraph", "listItem"]),
|
|
3716
|
+
depth: field.number().validator((value) => Number.isInteger(value)).min(0).max(4),
|
|
3717
|
+
listType: field.string().enum(["bullet"]).optional(),
|
|
3718
|
+
children: field.array(field.object(richTextNodeShape())).min(1).max(128)
|
|
3719
|
+
});
|
|
3720
|
+
var nestedIdentityShape2 = (type) => ({
|
|
3721
|
+
type: field.string().enum([type]),
|
|
3722
|
+
version: field.string().enum([FEEDBACK_CONTRACT_VERSION])
|
|
3723
|
+
});
|
|
3724
|
+
var envelopeShape = (includeIdentity = false) => ({
|
|
3725
|
+
...includeIdentity ? nestedIdentityShape2("feedback-encrypted-narrative-envelope") : {},
|
|
3726
|
+
schemaVersion: field.string().enum(["1"]),
|
|
3727
|
+
keyId: ingestionKeyIdField(),
|
|
3728
|
+
algorithm: field.string().enum(["RSA-OAEP-256+A256GCM"]),
|
|
3729
|
+
wrappedKey: transientEncryptedField(342, 683, [342, 512, 683]),
|
|
3730
|
+
iv: transientEncryptedField(16, 16, [16]),
|
|
3731
|
+
ciphertext: transientEncryptedField(2, 49152),
|
|
3732
|
+
authenticationTag: transientEncryptedField(22, 22, [22])
|
|
3733
|
+
});
|
|
3734
|
+
var analysisProjectionShape = (includeIdentity = false) => ({
|
|
3735
|
+
...includeIdentity ? nestedIdentityShape2("feedback-derived-analysis") : {},
|
|
3736
|
+
status: field.string().enum(["analyzed", "structured-only"]),
|
|
3737
|
+
sentiment: field.string().enum(FEEDBACK_SENTIMENT_BUCKETS).optional(),
|
|
3738
|
+
intentIds: field.array(field.string().enum(FEEDBACK_INTENT_IDS)).max(8),
|
|
3739
|
+
themeIds: field.array(field.string().enum(FEEDBACK_THEME_IDS)).max(8),
|
|
3740
|
+
confidence: field.string().enum(["low", "medium", "high"]).optional(),
|
|
3741
|
+
policyVersion: field.string().enum(FEEDBACK_PRIVACY_POLICY_VERSIONS),
|
|
3742
|
+
modelVersion: field.string().enum(FEEDBACK_ANALYSIS_MODEL_VERSIONS),
|
|
3743
|
+
deterministicRedactionCount: redactionCountField(),
|
|
3744
|
+
scannerRedactionCount: redactionCountField()
|
|
3745
|
+
});
|
|
3746
|
+
var analysisReceiptShape = () => ({
|
|
3747
|
+
receiptId: transientCorrelationIdField(),
|
|
3748
|
+
...analysisProjectionShape(),
|
|
3749
|
+
analyzedAt: field.dateTimeISO()
|
|
3750
|
+
});
|
|
3751
|
+
var isAnalysisProjectionConsistent = (value) => {
|
|
3752
|
+
const status = value.status;
|
|
3753
|
+
const intentIds = value.intentIds;
|
|
3754
|
+
const themeIds = value.themeIds;
|
|
3755
|
+
if (!Array.isArray(intentIds) || !Array.isArray(themeIds)) {
|
|
3756
|
+
return false;
|
|
3757
|
+
}
|
|
3758
|
+
if (new Set(intentIds).size !== intentIds.length || new Set(themeIds).size !== themeIds.length) {
|
|
3759
|
+
return false;
|
|
3760
|
+
}
|
|
3761
|
+
if (status === "structured-only") {
|
|
3762
|
+
return value.sentiment === void 0 && value.confidence === void 0 && intentIds.length === 0 && themeIds.length === 0;
|
|
3763
|
+
}
|
|
3764
|
+
return status === "analyzed" && value.sentiment !== void 0 && value.confidence !== void 0;
|
|
3765
|
+
};
|
|
3766
|
+
var optionalDraftFields = () => ({
|
|
3767
|
+
surfaceId: surfaceIdField().optional(),
|
|
3768
|
+
issueType: field.string().enum(FEEDBACK_ISSUE_TYPES).optional(),
|
|
3769
|
+
severity: ratingField().optional(),
|
|
3770
|
+
satisfaction: ratingField().optional(),
|
|
3771
|
+
analysisReceiptId: transientCorrelationIdField().optional()
|
|
3772
|
+
});
|
|
3773
|
+
var surfaceEntryShape = () => ({
|
|
3774
|
+
id: surfaceIdField(),
|
|
3775
|
+
labelKey: safeIdField(160),
|
|
3776
|
+
kind: field.string().enum(["public", "authenticated", "admin", "game"]),
|
|
3777
|
+
gameDiagnosticsEligible: field.boolean()
|
|
3778
|
+
});
|
|
3779
|
+
var areSurfacesConsistent = (surfaces) => {
|
|
3780
|
+
if (!Array.isArray(surfaces)) {
|
|
3781
|
+
return false;
|
|
3782
|
+
}
|
|
3783
|
+
const surfaceIds = surfaces.map(
|
|
3784
|
+
(surface) => surface.id
|
|
3785
|
+
);
|
|
3786
|
+
return new Set(surfaceIds).size === surfaceIds.length && surfaces.every(
|
|
3787
|
+
(surface) => {
|
|
3788
|
+
const definition = FEEDBACK_SURFACE_DEFINITIONS.find(
|
|
3789
|
+
({ id }) => id === surface.id
|
|
3790
|
+
);
|
|
3791
|
+
return definition !== void 0 && surface.labelKey === definition.labelKey && surface.kind === definition.kind && surface.gameDiagnosticsEligible === definition.gameDiagnosticsEligible;
|
|
3792
|
+
}
|
|
3793
|
+
);
|
|
3794
|
+
};
|
|
3795
|
+
var isDraftShapeConsistent = (value) => {
|
|
3796
|
+
const hasDirtyField = value.surfaceId !== void 0 || value.issueType !== void 0 || value.severity !== void 0 || value.satisfaction !== void 0 || value.analysisReceiptId !== void 0 || value.analysis !== void 0;
|
|
3797
|
+
if (!hasDirtyField) {
|
|
3798
|
+
return false;
|
|
3799
|
+
}
|
|
3800
|
+
if (value.kind === "bug") {
|
|
3801
|
+
return value.satisfaction === void 0;
|
|
3802
|
+
}
|
|
3803
|
+
if (value.kind === "review") {
|
|
3804
|
+
return value.surfaceId === void 0 && value.issueType === void 0 && value.severity === void 0;
|
|
3805
|
+
}
|
|
3806
|
+
return false;
|
|
3807
|
+
};
|
|
3808
|
+
var isContextConsistent = (value) => {
|
|
3809
|
+
if (!areSurfacesConsistent(value.surfaces)) {
|
|
3810
|
+
return false;
|
|
3811
|
+
}
|
|
3812
|
+
if (value.selectedSurfaceId !== void 0 && !value.surfaces.some(
|
|
3813
|
+
(surface) => surface.id === value.selectedSurfaceId
|
|
3814
|
+
)) {
|
|
3815
|
+
return false;
|
|
3816
|
+
}
|
|
3817
|
+
const hasProjectedSurface = value.surfaces.length > 0;
|
|
3818
|
+
const hasDiagnosticsSurface = value.surfaces.some(
|
|
3819
|
+
(surface) => surface.gameDiagnosticsEligible === true
|
|
3820
|
+
);
|
|
3821
|
+
if (value.eligibility.bugReport && !hasProjectedSurface || value.eligibility.gameDiagnostics && (!value.eligibility.bugReport || !hasDiagnosticsSurface)) {
|
|
3822
|
+
return false;
|
|
3823
|
+
}
|
|
3824
|
+
const generatedAt = Date.parse(String(value.generatedAt));
|
|
3825
|
+
if (!Number.isFinite(generatedAt)) {
|
|
3826
|
+
return false;
|
|
3827
|
+
}
|
|
3828
|
+
const boundedFutureAvailabilityIsValid = (candidate, maximumSeconds) => {
|
|
3829
|
+
if (candidate === void 0) {
|
|
3830
|
+
return true;
|
|
3831
|
+
}
|
|
3832
|
+
const availableAt = Date.parse(String(candidate));
|
|
3833
|
+
return Number.isFinite(availableAt) && availableAt > generatedAt && availableAt - generatedAt <= maximumSeconds * 1e3;
|
|
3834
|
+
};
|
|
3835
|
+
const maximumBugCooldownSeconds = FEEDBACK_BUG_COOLDOWN_SECONDS[FEEDBACK_BUG_COOLDOWN_SECONDS.length - 1] ?? 0;
|
|
3836
|
+
if (!boundedFutureAvailabilityIsValid(
|
|
3837
|
+
value.eligibility.bugAvailableAt,
|
|
3838
|
+
maximumBugCooldownSeconds
|
|
3839
|
+
) || !boundedFutureAvailabilityIsValid(
|
|
3840
|
+
value.eligibility.reviewAvailableAt,
|
|
3841
|
+
FEEDBACK_REVIEW_COOLDOWN_SECONDS
|
|
3842
|
+
)) {
|
|
3843
|
+
return false;
|
|
3844
|
+
}
|
|
3845
|
+
const bugAvailableAt = value.eligibility.bugAvailableAt === void 0 ? void 0 : Date.parse(String(value.eligibility.bugAvailableAt));
|
|
3846
|
+
const bugRetryAfterSeconds = value.eligibility.bugRetryAfterSeconds;
|
|
3847
|
+
const bugCooldownIsConsistent = bugAvailableAt === void 0 && bugRetryAfterSeconds === void 0 || bugAvailableAt !== void 0 && typeof bugRetryAfterSeconds === "number" && bugRetryAfterSeconds === Math.ceil((bugAvailableAt - generatedAt) / 1e3);
|
|
3848
|
+
if (!bugCooldownIsConsistent || value.eligibility.bugReport && (value.eligibility.bugAvailableAt !== void 0 || value.eligibility.bugRetryAfterSeconds !== void 0) || value.eligibility.review && value.eligibility.reviewAvailableAt !== void 0 || value.eligibility.bugReport && !value.flags.bugReport || value.eligibility.review && !value.flags.review || value.eligibility.gameDiagnostics && !value.flags.gameDiagnostics) {
|
|
3849
|
+
return false;
|
|
3850
|
+
}
|
|
3851
|
+
if (!value.flags.transientAnalysis) {
|
|
3852
|
+
return value.ingestionKey === void 0;
|
|
3853
|
+
}
|
|
3854
|
+
if (value.ingestionKey === void 0) {
|
|
3855
|
+
return false;
|
|
3856
|
+
}
|
|
3857
|
+
const expiresAt = Date.parse(String(value.ingestionKey.expiresAt));
|
|
3858
|
+
return Number.isFinite(expiresAt) && expiresAt > generatedAt && expiresAt - generatedAt <= 10 * 60 * 1e3;
|
|
3859
|
+
};
|
|
3860
|
+
var distributionShape = (idField = () => safeIdField(128)) => ({
|
|
3861
|
+
id: idField(),
|
|
3862
|
+
count: countField()
|
|
3863
|
+
});
|
|
3864
|
+
var hasUniqueIds = (values) => Array.isArray(values) && new Set(
|
|
3865
|
+
values.map(
|
|
3866
|
+
(value) => typeof value === "object" && value !== null ? value.id : void 0
|
|
3867
|
+
)
|
|
3868
|
+
).size === values.length;
|
|
3869
|
+
var distributionTotal = (values) => Array.isArray(values) ? values.reduce(
|
|
3870
|
+
(total, value) => total + (typeof value === "object" && value !== null && typeof value.count === "number" ? value.count : 0),
|
|
3871
|
+
0
|
|
3872
|
+
) : 0;
|
|
3873
|
+
var distributionCountsAtMost = (values, maximum) => Array.isArray(values) && values.every(
|
|
3874
|
+
(value) => typeof value === "object" && value !== null && typeof value.count === "number" && value.count <= maximum
|
|
3875
|
+
);
|
|
3876
|
+
var advisoryShape = () => ({
|
|
3877
|
+
code: field.string().enum(
|
|
3878
|
+
[
|
|
3879
|
+
"severity-five",
|
|
3880
|
+
"critical-regression",
|
|
3881
|
+
"satisfaction-drop",
|
|
3882
|
+
"processor-stale"
|
|
3883
|
+
]
|
|
3884
|
+
),
|
|
3885
|
+
level: field.string().enum(["advisory", "critical"]),
|
|
3886
|
+
triggerCount: positiveCountField2(),
|
|
3887
|
+
recommendationIds: field.array(
|
|
3888
|
+
field.string().enum(
|
|
3889
|
+
[
|
|
3890
|
+
"inspect-release",
|
|
3891
|
+
"verify-renderer-health",
|
|
3892
|
+
"review-top-intents",
|
|
3893
|
+
"verify-processor-health"
|
|
3894
|
+
]
|
|
3895
|
+
)
|
|
3896
|
+
).min(1).max(8)
|
|
3897
|
+
});
|
|
3898
|
+
var orderedWindow = (value, durationMilliseconds) => {
|
|
3899
|
+
const start = Date.parse(String(value.windowStart));
|
|
3900
|
+
const end = Date.parse(String(value.windowEnd));
|
|
3901
|
+
const generatedAt = Date.parse(String(value.generatedAt));
|
|
3902
|
+
return Number.isFinite(start) && Number.isFinite(end) && Number.isFinite(generatedAt) && new Date(start).toISOString() === value.windowStart && new Date(end).toISOString() === value.windowEnd && start % durationMilliseconds === 0 && end - start === durationMilliseconds && generatedAt >= end;
|
|
3903
|
+
};
|
|
3904
|
+
var processorWindow = (processor, windowKey) => {
|
|
3905
|
+
let iso;
|
|
3906
|
+
let expectedLength;
|
|
3907
|
+
let duration;
|
|
3908
|
+
if (processor === "bug-hourly") {
|
|
3909
|
+
if (!BUG_HOUR_WINDOW_PATTERN.test(windowKey)) {
|
|
3910
|
+
return void 0;
|
|
3911
|
+
}
|
|
3912
|
+
iso = `${windowKey}:00:00.000Z`;
|
|
3913
|
+
expectedLength = 13;
|
|
3914
|
+
duration = 60 * 60 * 1e3;
|
|
3915
|
+
} else if (processor === "review-daily") {
|
|
3916
|
+
if (!REVIEW_DAY_WINDOW_PATTERN.test(windowKey)) {
|
|
3917
|
+
return void 0;
|
|
3918
|
+
}
|
|
3919
|
+
iso = `${windowKey}T00:00:00.000Z`;
|
|
3920
|
+
expectedLength = 10;
|
|
3921
|
+
duration = 24 * 60 * 60 * 1e3;
|
|
3922
|
+
} else {
|
|
3923
|
+
if (!RECONCILIATION_WINDOW_PATTERN.test(windowKey)) {
|
|
3924
|
+
return void 0;
|
|
3925
|
+
}
|
|
3926
|
+
const minute = Number(windowKey.slice(-2));
|
|
3927
|
+
if (minute % 5 !== 0) {
|
|
3928
|
+
return void 0;
|
|
3929
|
+
}
|
|
3930
|
+
iso = `${windowKey}:00.000Z`;
|
|
3931
|
+
expectedLength = 16;
|
|
3932
|
+
duration = 5 * 60 * 1e3;
|
|
3933
|
+
}
|
|
3934
|
+
const start = Date.parse(iso);
|
|
3935
|
+
if (!Number.isFinite(start) || new Date(start).toISOString().slice(0, expectedLength) !== windowKey) {
|
|
3936
|
+
return void 0;
|
|
3937
|
+
}
|
|
3938
|
+
return { start, duration };
|
|
3939
|
+
};
|
|
3940
|
+
var isProcessorArtifactConsistent = (value, artifact) => {
|
|
3941
|
+
const processor = value.processor;
|
|
3942
|
+
const windowKey = String(value.windowKey);
|
|
3943
|
+
const window = processorWindow(processor, windowKey);
|
|
3944
|
+
if (window === void 0) {
|
|
3945
|
+
return false;
|
|
3946
|
+
}
|
|
3947
|
+
const completedAt = Date.parse(
|
|
3948
|
+
String(
|
|
3949
|
+
artifact === "checkpoint" ? value.completedAt : value.generatedAt
|
|
3950
|
+
)
|
|
3951
|
+
);
|
|
3952
|
+
if (!Number.isFinite(completedAt) || completedAt < window.start + window.duration) {
|
|
3953
|
+
return false;
|
|
3954
|
+
}
|
|
3955
|
+
if (artifact === "checkpoint" && value.checkpointId !== `checkpoint:${processor}:${windowKey}`) {
|
|
3956
|
+
return false;
|
|
3957
|
+
}
|
|
3958
|
+
return true;
|
|
3959
|
+
};
|
|
3960
|
+
var roundRate = (value) => Math.round((value + Number.EPSILON) * 1e6) / 1e6;
|
|
3961
|
+
var rateMatches = (actual, expected) => typeof actual === "number" && actual === roundRate(expected);
|
|
3962
|
+
var distributionCountFor = (values, id) => {
|
|
3963
|
+
if (!Array.isArray(values)) {
|
|
3964
|
+
return 0;
|
|
3965
|
+
}
|
|
3966
|
+
const entry = values.find(
|
|
3967
|
+
(value) => typeof value === "object" && value !== null && value.id === id
|
|
3968
|
+
);
|
|
3969
|
+
return typeof entry === "object" && entry !== null && typeof entry.count === "number" ? entry.count : 0;
|
|
3970
|
+
};
|
|
3971
|
+
var advisoryCodesAreConsistent = (advisories, expected) => {
|
|
3972
|
+
if (!Array.isArray(advisories)) {
|
|
3973
|
+
return false;
|
|
3974
|
+
}
|
|
3975
|
+
const expectedCodes = Object.entries(expected).filter(
|
|
3976
|
+
(entry) => entry[1] !== void 0
|
|
3977
|
+
).map(([code]) => code);
|
|
3978
|
+
const codes = advisories.map(
|
|
3979
|
+
(advisory) => advisory?.code
|
|
3980
|
+
);
|
|
3981
|
+
return new Set(codes).size === codes.length && codes.every(
|
|
3982
|
+
(code) => typeof code === "string" && expectedCodes.includes(code)
|
|
3983
|
+
) && codes.length === expectedCodes.length && expectedCodes.every((code) => codes.includes(code)) && advisories.every((advisory) => {
|
|
3984
|
+
const value = advisory;
|
|
3985
|
+
const code = typeof value.code === "string" ? value.code : void 0;
|
|
3986
|
+
const expectation = code === void 0 ? void 0 : expected[code];
|
|
3987
|
+
if (expectation === void 0 || value.level !== expectation.level || value.triggerCount !== expectation.triggerCount || !Array.isArray(value.recommendationIds) || value.recommendationIds.length !== expectation.recommendationIds.length) {
|
|
3988
|
+
return false;
|
|
3989
|
+
}
|
|
3990
|
+
return value.recommendationIds.every(
|
|
3991
|
+
(recommendation, index) => recommendation === expectation.recommendationIds[index]
|
|
3992
|
+
);
|
|
3993
|
+
});
|
|
3994
|
+
};
|
|
3995
|
+
var FeedbackRichTextAstSchema = createSchema(
|
|
3996
|
+
{
|
|
3997
|
+
schemaVersion: field.string().enum(["1"]),
|
|
3998
|
+
children: field.array(field.object(richTextBlockShape())).min(1).max(128)
|
|
3999
|
+
},
|
|
4000
|
+
"doc",
|
|
4001
|
+
{
|
|
4002
|
+
...strictOptions,
|
|
4003
|
+
schemaValidator: (value) => {
|
|
4004
|
+
const blocks = Array.isArray(value.children) ? value.children : [];
|
|
4005
|
+
const blocksAreConsistent = blocks.every(
|
|
4006
|
+
(block) => {
|
|
4007
|
+
const listShapeIsValid = block.type === "paragraph" && block.listType === void 0 || block.type === "listItem" && block.listType === "bullet";
|
|
4008
|
+
const marksAreUnique = Array.isArray(block.children) && block.children.every(
|
|
4009
|
+
(child) => child.marks === void 0 || Array.isArray(child.marks) && new Set(child.marks).size === child.marks.length
|
|
4010
|
+
);
|
|
4011
|
+
return listShapeIsValid && marksAreUnique;
|
|
4012
|
+
}
|
|
4013
|
+
);
|
|
4014
|
+
const characterCount = blocks.reduce(
|
|
4015
|
+
(blockTotal, block) => blockTotal + (Array.isArray(block.children) ? block.children.reduce(
|
|
4016
|
+
(nodeTotal, node) => nodeTotal + (typeof node.text === "string" ? [...node.text].length : 0),
|
|
4017
|
+
0
|
|
4018
|
+
) : 0),
|
|
4019
|
+
0
|
|
4020
|
+
);
|
|
4021
|
+
const extractedCharacterCount = characterCount + Math.max(0, blocks.length - 1);
|
|
4022
|
+
const nodeCount = blocks.reduce(
|
|
4023
|
+
(total, block) => total + (Array.isArray(block.children) ? block.children.length : 0),
|
|
4024
|
+
0
|
|
4025
|
+
);
|
|
4026
|
+
return value.type === "doc" && value.schemaVersion === "1" && blocksAreConsistent && nodeCount <= 256 && extractedCharacterCount > 0 && extractedCharacterCount <= MAX_NARRATIVE_CHARACTERS;
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4029
|
+
);
|
|
4030
|
+
var FeedbackEncryptedNarrativeEnvelopeSchema = createSchema(
|
|
4031
|
+
envelopeShape(),
|
|
4032
|
+
"feedback-encrypted-narrative-envelope",
|
|
4033
|
+
strictOptions
|
|
4034
|
+
);
|
|
4035
|
+
var FeedbackTransientAnalysisRequestSchema = createSchema(
|
|
4036
|
+
{
|
|
4037
|
+
schemaVersion: field.string().enum(["1"]),
|
|
4038
|
+
requestId: transientCorrelationIdField(),
|
|
4039
|
+
purpose: field.string().enum(["bug", "review"]),
|
|
4040
|
+
surfaceId: surfaceIdField().optional(),
|
|
4041
|
+
deterministicRedactionCount: redactionCountField(),
|
|
4042
|
+
envelope: field.object(envelopeShape(true))
|
|
4043
|
+
},
|
|
4044
|
+
"feedback-transient-analysis-request",
|
|
4045
|
+
{
|
|
4046
|
+
...strictOptions,
|
|
4047
|
+
schemaValidator: (value, context) => {
|
|
4048
|
+
const surfaceWasProvided = context?.wasProvided("surfaceId") ?? Object.prototype.hasOwnProperty.call(value, "surfaceId");
|
|
4049
|
+
return value.purpose === "bug" && value.surfaceId !== void 0 || value.purpose === "review" && !surfaceWasProvided;
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4052
|
+
);
|
|
4053
|
+
var validateFeedbackTransientAnalysisRequest = (input) => {
|
|
4054
|
+
const result = FeedbackTransientAnalysisRequestSchema.validate(input);
|
|
4055
|
+
if (!result.valid || result.value === void 0) {
|
|
4056
|
+
return {
|
|
4057
|
+
valid: false,
|
|
4058
|
+
errors: result.errors ?? ["Transient analysis validation failed."],
|
|
4059
|
+
...result.issues === void 0 ? {} : { issues: result.issues }
|
|
4060
|
+
};
|
|
4061
|
+
}
|
|
4062
|
+
return {
|
|
4063
|
+
valid: true,
|
|
4064
|
+
value: result.value
|
|
4065
|
+
};
|
|
4066
|
+
};
|
|
4067
|
+
var FeedbackAnalysisReceiptSchema = createSchema(
|
|
4068
|
+
analysisReceiptShape(),
|
|
4069
|
+
"feedback-analysis-receipt",
|
|
4070
|
+
{
|
|
4071
|
+
...strictOptions,
|
|
4072
|
+
schemaValidator: (value) => value.status === "analyzed" && isAnalysisProjectionConsistent(value)
|
|
4073
|
+
}
|
|
4074
|
+
);
|
|
4075
|
+
var FeedbackDerivedAnalysisSchema = createSchema(
|
|
4076
|
+
analysisProjectionShape(),
|
|
4077
|
+
"feedback-derived-analysis",
|
|
4078
|
+
{
|
|
4079
|
+
...strictOptions,
|
|
4080
|
+
schemaValidator: isAnalysisProjectionConsistent
|
|
4081
|
+
}
|
|
4082
|
+
);
|
|
4083
|
+
var FeedbackSurfaceCatalogSchema = createSchema(
|
|
4084
|
+
{
|
|
4085
|
+
generatedAt: field.dateTimeISO(),
|
|
4086
|
+
catalogVersion: safeIdField(64),
|
|
4087
|
+
surfaces: field.array(field.object(surfaceEntryShape())).max(256)
|
|
4088
|
+
},
|
|
4089
|
+
"feedback-surface-catalog",
|
|
4090
|
+
{
|
|
4091
|
+
...strictOptions,
|
|
4092
|
+
schemaValidator: (value) => areSurfacesConsistent(value.surfaces)
|
|
4093
|
+
}
|
|
4094
|
+
);
|
|
4095
|
+
var FeedbackContextSchema = createSchema(
|
|
4096
|
+
{
|
|
4097
|
+
generatedAt: field.dateTimeISO(),
|
|
4098
|
+
catalogVersion: safeIdField(64),
|
|
4099
|
+
surfaces: field.array(field.object(surfaceEntryShape())).max(256),
|
|
4100
|
+
selectedSurfaceId: surfaceIdField().optional(),
|
|
4101
|
+
flags: field.object({
|
|
4102
|
+
bugReport: field.boolean(),
|
|
4103
|
+
review: field.boolean(),
|
|
4104
|
+
transientAnalysis: field.boolean(),
|
|
4105
|
+
reporting: field.boolean(),
|
|
4106
|
+
admin: field.boolean(),
|
|
4107
|
+
mcp: field.boolean(),
|
|
4108
|
+
publicHonesty: field.boolean(),
|
|
4109
|
+
gameDiagnostics: field.boolean(),
|
|
4110
|
+
anonymous: field.boolean()
|
|
4111
|
+
}),
|
|
4112
|
+
eligibility: field.object({
|
|
4113
|
+
bugReport: field.boolean(),
|
|
4114
|
+
review: field.boolean(),
|
|
4115
|
+
gameDiagnostics: field.boolean(),
|
|
4116
|
+
bugAvailableAt: field.dateTimeISO().optional(),
|
|
4117
|
+
reviewAvailableAt: field.dateTimeISO().optional(),
|
|
4118
|
+
bugRetryAfterSeconds: positiveCountField2().optional()
|
|
4119
|
+
}),
|
|
4120
|
+
ingestionKey: field.object({
|
|
4121
|
+
keyId: ingestionKeyIdField(),
|
|
4122
|
+
algorithm: field.string().enum(["RSA-OAEP-256"]),
|
|
4123
|
+
publicJwk: field.object({
|
|
4124
|
+
kty: field.string().enum(["RSA"]),
|
|
4125
|
+
alg: field.string().enum(["RSA-OAEP-256"]),
|
|
4126
|
+
use: field.string().enum(["enc"]),
|
|
4127
|
+
key_ops: field.array(field.string().enum(["wrapKey"])).min(1).max(1),
|
|
4128
|
+
n: field.string().min(342).max(683).pattern(BASE64URL_PATTERN2).validator(isCanonicalRsaModulus),
|
|
4129
|
+
e: field.string().min(2).max(6).pattern(BASE64URL_PATTERN2).validator(isCanonicalRsaExponent),
|
|
4130
|
+
ext: field.boolean().validator((value) => value === true)
|
|
4131
|
+
}),
|
|
4132
|
+
expiresAt: field.dateTimeISO()
|
|
4133
|
+
}).optional()
|
|
4134
|
+
},
|
|
4135
|
+
"feedback-context",
|
|
4136
|
+
{
|
|
4137
|
+
...strictOptions,
|
|
4138
|
+
schemaValidator: isContextConsistent
|
|
4139
|
+
}
|
|
4140
|
+
);
|
|
4141
|
+
var FeedbackDraftUpsertRequestSchema = createSchema(
|
|
4142
|
+
{
|
|
4143
|
+
draftId: draftIdField(),
|
|
4144
|
+
kind: field.string().enum(["bug", "review"]),
|
|
4145
|
+
revision: revisionField(),
|
|
4146
|
+
...optionalDraftFields()
|
|
4147
|
+
},
|
|
4148
|
+
"feedback-draft-upsert-request",
|
|
4149
|
+
{
|
|
4150
|
+
...strictOptions,
|
|
4151
|
+
schemaValidator: isDraftShapeConsistent
|
|
4152
|
+
}
|
|
4153
|
+
);
|
|
4154
|
+
var FeedbackDraftPacketSchema = createSchema(
|
|
4155
|
+
{
|
|
4156
|
+
draftId: draftIdField(),
|
|
4157
|
+
kind: field.string().enum(["bug", "review"]),
|
|
4158
|
+
revision: revisionField(),
|
|
4159
|
+
surfaceId: surfaceIdField().optional(),
|
|
4160
|
+
issueType: field.string().enum(FEEDBACK_ISSUE_TYPES).optional(),
|
|
4161
|
+
severity: ratingField().optional(),
|
|
4162
|
+
satisfaction: ratingField().optional(),
|
|
4163
|
+
analysis: field.object(analysisProjectionShape(true)).optional(),
|
|
4164
|
+
serverUpdatedAt: field.dateTimeISO(),
|
|
4165
|
+
expiresAt: field.dateTimeISO()
|
|
4166
|
+
},
|
|
4167
|
+
"feedback-draft-packet",
|
|
4168
|
+
{
|
|
4169
|
+
...strictOptions,
|
|
4170
|
+
schemaValidator: (value) => {
|
|
4171
|
+
if (!isDraftShapeConsistent(value)) {
|
|
4172
|
+
return false;
|
|
4173
|
+
}
|
|
4174
|
+
if (value.analysis !== void 0 && !isAnalysisProjectionConsistent(value.analysis)) {
|
|
4175
|
+
return false;
|
|
4176
|
+
}
|
|
4177
|
+
const updatedAt = Date.parse(String(value.serverUpdatedAt));
|
|
4178
|
+
const expiresAt = Date.parse(String(value.expiresAt));
|
|
4179
|
+
return Number.isFinite(updatedAt) && Number.isFinite(expiresAt) && expiresAt > updatedAt && expiresAt - updatedAt <= 24 * 60 * 60 * 1e3;
|
|
4180
|
+
}
|
|
4181
|
+
}
|
|
4182
|
+
);
|
|
4183
|
+
var FeedbackDraftReceiptSchema = createSchema(
|
|
4184
|
+
{
|
|
4185
|
+
draftId: draftIdField(),
|
|
4186
|
+
revision: revisionField(),
|
|
4187
|
+
savedAt: field.dateTimeISO(),
|
|
4188
|
+
expiresAt: field.dateTimeISO()
|
|
4189
|
+
},
|
|
4190
|
+
"feedback-draft-receipt",
|
|
4191
|
+
{
|
|
4192
|
+
...strictOptions,
|
|
4193
|
+
schemaValidator: (value) => {
|
|
4194
|
+
const savedAt = Date.parse(String(value.savedAt));
|
|
4195
|
+
const expiresAt = Date.parse(String(value.expiresAt));
|
|
4196
|
+
return Number.isFinite(savedAt) && Number.isFinite(expiresAt) && expiresAt > savedAt && expiresAt - savedAt <= 24 * 60 * 60 * 1e3;
|
|
4197
|
+
}
|
|
4198
|
+
}
|
|
4199
|
+
);
|
|
4200
|
+
var FeedbackBugSubmissionRequestSchema = createSchema(
|
|
4201
|
+
{
|
|
4202
|
+
draftId: draftIdField().optional(),
|
|
4203
|
+
surfaceId: surfaceIdField(),
|
|
4204
|
+
issueType: field.string().enum(FEEDBACK_ISSUE_TYPES),
|
|
4205
|
+
severity: ratingField(),
|
|
4206
|
+
analysisReceiptId: transientCorrelationIdField().optional(),
|
|
4207
|
+
gameDiagnostics: field.object(feedbackGameDiagnosticsShape(true)).optional()
|
|
4208
|
+
},
|
|
4209
|
+
"feedback-bug-submission-request",
|
|
4210
|
+
{
|
|
4211
|
+
...strictOptions,
|
|
4212
|
+
schemaValidator: (value) => value.issueType !== "privacy-security" && (value.gameDiagnostics === void 0 || isFeedbackGameDiagnosticsConsistent(value.gameDiagnostics) && value.gameDiagnostics.surfaceId === value.surfaceId)
|
|
4213
|
+
}
|
|
4214
|
+
);
|
|
4215
|
+
var FeedbackReviewSubmissionRequestSchema = createSchema(
|
|
4216
|
+
{
|
|
4217
|
+
draftId: draftIdField().optional(),
|
|
4218
|
+
satisfaction: ratingField(),
|
|
4219
|
+
analysisReceiptId: transientCorrelationIdField().optional()
|
|
4220
|
+
},
|
|
4221
|
+
"feedback-review-submission-request",
|
|
4222
|
+
strictOptions
|
|
4223
|
+
);
|
|
4224
|
+
var FeedbackAcceptanceReceiptSchema = createSchema(
|
|
4225
|
+
{
|
|
4226
|
+
packetId: uuidField(),
|
|
4227
|
+
kind: field.string().enum(["bug", "review"]),
|
|
4228
|
+
acceptedAt: field.dateTimeISO(),
|
|
4229
|
+
nextEligibleAt: field.dateTimeISO()
|
|
4230
|
+
},
|
|
4231
|
+
"feedback-acceptance-receipt",
|
|
4232
|
+
{
|
|
4233
|
+
...strictOptions,
|
|
4234
|
+
schemaValidator: (value) => {
|
|
4235
|
+
const acceptedAt = Date.parse(String(value.acceptedAt));
|
|
4236
|
+
const nextEligibleAt = Date.parse(String(value.nextEligibleAt));
|
|
4237
|
+
const cooldownMilliseconds = nextEligibleAt - acceptedAt;
|
|
4238
|
+
if (!Number.isFinite(acceptedAt) || !Number.isFinite(nextEligibleAt) || cooldownMilliseconds <= 0 || cooldownMilliseconds % 1e3 !== 0) {
|
|
4239
|
+
return false;
|
|
4240
|
+
}
|
|
4241
|
+
const cooldownSeconds = cooldownMilliseconds / 1e3;
|
|
4242
|
+
return value.kind === "review" ? cooldownSeconds === FEEDBACK_REVIEW_COOLDOWN_SECONDS : FEEDBACK_BUG_COOLDOWN_SECONDS.includes(
|
|
4243
|
+
cooldownSeconds
|
|
4244
|
+
);
|
|
4245
|
+
}
|
|
4246
|
+
}
|
|
4247
|
+
);
|
|
4248
|
+
var FeedbackStructuredOnlyAnalysisResultSchema = createSchema(
|
|
4249
|
+
{
|
|
4250
|
+
status: field.string().enum(["structured-only-required"]),
|
|
4251
|
+
reasonCode: field.string().enum(FEEDBACK_STRUCTURED_ONLY_REASON_CODES)
|
|
4252
|
+
},
|
|
4253
|
+
"feedback-structured-only-analysis-result",
|
|
4254
|
+
strictOptions
|
|
4255
|
+
);
|
|
4256
|
+
var FeedbackBugPacketSchema = createSchema(
|
|
4257
|
+
{
|
|
4258
|
+
packetId: uuidField(),
|
|
4259
|
+
acceptedAt: field.dateTimeISO(),
|
|
4260
|
+
surfaceId: surfaceIdField(),
|
|
4261
|
+
issueType: field.string().enum(FEEDBACK_PERSISTABLE_ISSUE_TYPES),
|
|
4262
|
+
severity: ratingField(),
|
|
4263
|
+
releaseId: safeIdField(128),
|
|
4264
|
+
buildId: safeIdField(128),
|
|
4265
|
+
analysis: field.object(analysisProjectionShape(true)).optional(),
|
|
4266
|
+
gameDiagnostics: field.object(feedbackGameDiagnosticsShape(true)).optional()
|
|
4267
|
+
},
|
|
4268
|
+
"feedback-bug-packet",
|
|
4269
|
+
{
|
|
4270
|
+
...strictOptions,
|
|
4271
|
+
schemaValidator: (value) => (value.analysis === void 0 || isAnalysisProjectionConsistent(value.analysis)) && (value.gameDiagnostics === void 0 || isFeedbackGameDiagnosticsConsistent(value.gameDiagnostics) && value.gameDiagnostics.surfaceId === value.surfaceId)
|
|
4272
|
+
}
|
|
4273
|
+
);
|
|
4274
|
+
var FeedbackReviewPacketSchema = createSchema(
|
|
4275
|
+
{
|
|
4276
|
+
packetId: uuidField(),
|
|
4277
|
+
acceptedAt: field.dateTimeISO(),
|
|
4278
|
+
satisfaction: ratingField(),
|
|
4279
|
+
analysis: field.object(analysisProjectionShape(true)).optional()
|
|
4280
|
+
},
|
|
4281
|
+
"feedback-review-packet",
|
|
4282
|
+
{
|
|
4283
|
+
...strictOptions,
|
|
4284
|
+
schemaValidator: (value) => value.analysis === void 0 || isAnalysisProjectionConsistent(value.analysis)
|
|
4285
|
+
}
|
|
4286
|
+
);
|
|
4287
|
+
var FeedbackGameReconstructionManifestSchema = createSchema(
|
|
4288
|
+
{
|
|
4289
|
+
reconstructionId: uuidField(),
|
|
4290
|
+
bugPacketId: uuidField(),
|
|
4291
|
+
createdAt: field.dateTimeISO(),
|
|
4292
|
+
expiresAt: field.dateTimeISO(),
|
|
4293
|
+
curatedAssetSetId: safeIdField(128),
|
|
4294
|
+
noticeKey: safeIdField(160),
|
|
4295
|
+
diagnostics: field.object(feedbackGameDiagnosticsShape(true))
|
|
4296
|
+
},
|
|
4297
|
+
"feedback-game-reconstruction-manifest",
|
|
4298
|
+
{
|
|
4299
|
+
...strictOptions,
|
|
4300
|
+
schemaValidator: (value) => {
|
|
4301
|
+
const createdAt = Date.parse(String(value.createdAt));
|
|
4302
|
+
const expiresAt = Date.parse(String(value.expiresAt));
|
|
4303
|
+
return isFeedbackGameDiagnosticsConsistent(value.diagnostics) && Number.isFinite(createdAt) && Number.isFinite(expiresAt) && expiresAt > createdAt && expiresAt - createdAt <= 30 * 24 * 60 * 60 * 1e3;
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
);
|
|
4307
|
+
var FeedbackHourlyBugReportSchema = createSchema(
|
|
4308
|
+
{
|
|
4309
|
+
reportId: uuidField(),
|
|
4310
|
+
windowStart: field.dateTimeISO(),
|
|
4311
|
+
windowEnd: field.dateTimeISO(),
|
|
4312
|
+
revision: revisionField(),
|
|
4313
|
+
generatedAt: field.dateTimeISO(),
|
|
4314
|
+
acceptedCount: countField(),
|
|
4315
|
+
rejectedCount: countField(),
|
|
4316
|
+
diagnosticsAttachedCount: countField(),
|
|
4317
|
+
deterministicRedactionCount: countField(),
|
|
4318
|
+
scannerRedactionCount: countField(),
|
|
4319
|
+
processorLagSeconds: countField(),
|
|
4320
|
+
rates: field.object({
|
|
4321
|
+
rejectionRate: field.number().min(0).max(1),
|
|
4322
|
+
deterministicRedactionsPerAccepted: field.number().min(0).max(4e3),
|
|
4323
|
+
scannerRedactionsPerAccepted: field.number().min(0).max(4e3)
|
|
4324
|
+
}),
|
|
4325
|
+
traffic: field.object({
|
|
4326
|
+
denominator: countField(),
|
|
4327
|
+
acceptedPerTenThousand: field.number().min(0).max(MAX_COUNT).optional()
|
|
4328
|
+
}),
|
|
4329
|
+
targetDistribution: field.array(field.object(distributionShape(surfaceIdField))).max(256),
|
|
4330
|
+
issueTypeDistribution: field.array(
|
|
4331
|
+
field.object(
|
|
4332
|
+
distributionShape(
|
|
4333
|
+
() => field.string().enum(FEEDBACK_PERSISTABLE_ISSUE_TYPES)
|
|
4334
|
+
)
|
|
4335
|
+
)
|
|
4336
|
+
).max(FEEDBACK_ISSUE_TYPES.length),
|
|
4337
|
+
severityDistribution: field.array(
|
|
4338
|
+
field.object(
|
|
4339
|
+
distributionShape(
|
|
4340
|
+
() => field.string().enum(["1", "2", "3", "4", "5"])
|
|
4341
|
+
)
|
|
4342
|
+
)
|
|
4343
|
+
).max(5),
|
|
4344
|
+
intentDistribution: field.array(
|
|
4345
|
+
field.object(
|
|
4346
|
+
distributionShape(
|
|
4347
|
+
() => field.string().enum(FEEDBACK_INTENT_IDS)
|
|
4348
|
+
)
|
|
4349
|
+
)
|
|
4350
|
+
).max(FEEDBACK_INTENT_IDS.length),
|
|
4351
|
+
buildDistribution: field.array(field.object(distributionShape())).max(128),
|
|
4352
|
+
rendererDistribution: field.array(
|
|
4353
|
+
field.object(
|
|
4354
|
+
distributionShape(
|
|
4355
|
+
() => field.string().enum(FEEDBACK_RENDERER_BUCKETS)
|
|
4356
|
+
)
|
|
4357
|
+
)
|
|
4358
|
+
).max(FEEDBACK_RENDERER_BUCKETS.length),
|
|
4359
|
+
backendDistribution: field.array(
|
|
4360
|
+
field.object(
|
|
4361
|
+
distributionShape(
|
|
4362
|
+
() => field.string().enum(FEEDBACK_BACKEND_BUCKETS)
|
|
4363
|
+
)
|
|
4364
|
+
)
|
|
4365
|
+
).max(FEEDBACK_BACKEND_BUCKETS.length),
|
|
4366
|
+
viewportDistribution: field.array(
|
|
4367
|
+
field.object(
|
|
4368
|
+
distributionShape(
|
|
4369
|
+
() => field.string().enum(FEEDBACK_VIEWPORT_BUCKETS)
|
|
4370
|
+
)
|
|
4371
|
+
)
|
|
4372
|
+
).max(FEEDBACK_VIEWPORT_BUCKETS.length),
|
|
4373
|
+
frameRateDistribution: field.array(
|
|
4374
|
+
field.object(
|
|
4375
|
+
distributionShape(
|
|
4376
|
+
() => field.string().enum(FEEDBACK_FRAME_RATE_BUCKETS)
|
|
4377
|
+
)
|
|
4378
|
+
)
|
|
4379
|
+
).max(FEEDBACK_FRAME_RATE_BUCKETS.length),
|
|
4380
|
+
frameTimeDistribution: field.array(
|
|
4381
|
+
field.object(
|
|
4382
|
+
distributionShape(
|
|
4383
|
+
() => field.string().enum(FEEDBACK_FRAME_TIME_BUCKETS)
|
|
4384
|
+
)
|
|
4385
|
+
)
|
|
4386
|
+
).max(FEEDBACK_FRAME_TIME_BUCKETS.length),
|
|
4387
|
+
diagnosticFeatureDistribution: field.array(
|
|
4388
|
+
field.object(
|
|
4389
|
+
distributionShape(
|
|
4390
|
+
() => field.string().enum(FEEDBACK_GAME_FEATURE_IDS)
|
|
4391
|
+
)
|
|
4392
|
+
)
|
|
4393
|
+
).max(FEEDBACK_GAME_FEATURE_IDS.length),
|
|
4394
|
+
diagnosticCounterDistribution: field.array(
|
|
4395
|
+
field.object(
|
|
4396
|
+
distributionShape(
|
|
4397
|
+
() => field.string().enum(FEEDBACK_GAME_COUNTER_CODES)
|
|
4398
|
+
)
|
|
4399
|
+
)
|
|
4400
|
+
).max(FEEDBACK_GAME_COUNTER_CODES.length),
|
|
4401
|
+
diagnosticErrorDistribution: field.array(
|
|
4402
|
+
field.object(
|
|
4403
|
+
distributionShape(
|
|
4404
|
+
() => field.string().enum(FEEDBACK_GAME_ERROR_CODES)
|
|
4405
|
+
)
|
|
4406
|
+
)
|
|
4407
|
+
).max(FEEDBACK_GAME_ERROR_CODES.length),
|
|
4408
|
+
abuseBlockBands: field.array(
|
|
4409
|
+
field.object(
|
|
4410
|
+
distributionShape(
|
|
4411
|
+
() => field.string().enum(
|
|
4412
|
+
[
|
|
4413
|
+
"five-minutes",
|
|
4414
|
+
"fifteen-minutes",
|
|
4415
|
+
"one-hour",
|
|
4416
|
+
"six-hours",
|
|
4417
|
+
"twenty-four-hours",
|
|
4418
|
+
"fail-closed",
|
|
4419
|
+
"edge-blocked"
|
|
4420
|
+
]
|
|
4421
|
+
)
|
|
4422
|
+
)
|
|
4423
|
+
)
|
|
4424
|
+
).max(16),
|
|
4425
|
+
comparison: field.object({
|
|
4426
|
+
previousHourRatio: field.number().min(0).max(1e3),
|
|
4427
|
+
sevenDaySameHourRatio: field.number().min(0).max(1e3)
|
|
4428
|
+
}),
|
|
4429
|
+
advisories: field.array(field.object(advisoryShape())).max(32)
|
|
4430
|
+
},
|
|
4431
|
+
"feedback-hourly-bug-report",
|
|
4432
|
+
{
|
|
4433
|
+
...strictOptions,
|
|
4434
|
+
schemaValidator: (value) => {
|
|
4435
|
+
const distributions = [
|
|
4436
|
+
value.targetDistribution,
|
|
4437
|
+
value.issueTypeDistribution,
|
|
4438
|
+
value.severityDistribution,
|
|
4439
|
+
value.intentDistribution,
|
|
4440
|
+
value.buildDistribution,
|
|
4441
|
+
value.rendererDistribution,
|
|
4442
|
+
value.backendDistribution,
|
|
4443
|
+
value.viewportDistribution,
|
|
4444
|
+
value.frameRateDistribution,
|
|
4445
|
+
value.frameTimeDistribution,
|
|
4446
|
+
value.diagnosticFeatureDistribution,
|
|
4447
|
+
value.diagnosticCounterDistribution,
|
|
4448
|
+
value.diagnosticErrorDistribution,
|
|
4449
|
+
value.abuseBlockBands
|
|
4450
|
+
];
|
|
4451
|
+
const submittedCount = value.acceptedCount + value.rejectedCount;
|
|
4452
|
+
const expectedRejectionRate = submittedCount === 0 ? 0 : value.rejectedCount / submittedCount;
|
|
4453
|
+
const expectedDeterministicRate = value.acceptedCount === 0 ? 0 : value.deterministicRedactionCount / value.acceptedCount;
|
|
4454
|
+
const expectedScannerRate = value.acceptedCount === 0 ? 0 : value.scannerRedactionCount / value.acceptedCount;
|
|
4455
|
+
const trafficIsConsistent = value.traffic.denominator === 0 && value.traffic.acceptedPerTenThousand === void 0 || value.traffic.denominator > 0 && rateMatches(
|
|
4456
|
+
value.traffic.acceptedPerTenThousand,
|
|
4457
|
+
value.acceptedCount * 1e4 / value.traffic.denominator
|
|
4458
|
+
);
|
|
4459
|
+
const severityFiveCount = distributionCountFor(
|
|
4460
|
+
value.severityDistribution,
|
|
4461
|
+
"5"
|
|
4462
|
+
);
|
|
4463
|
+
const criticalRegression = severityFiveCount >= 3 || value.acceptedCount >= 5 && value.comparison.sevenDaySameHourRatio >= 3;
|
|
4464
|
+
const lagSeconds = Math.floor(
|
|
4465
|
+
(Date.parse(String(value.generatedAt)) - Date.parse(String(value.windowEnd))) / 1e3
|
|
4466
|
+
);
|
|
4467
|
+
return orderedWindow(value, 60 * 60 * 1e3) && value.revision >= 1 && value.processorLagSeconds === lagSeconds && value.diagnosticsAttachedCount <= value.acceptedCount && (value.acceptedCount > 0 || value.deterministicRedactionCount === 0 && value.scannerRedactionCount === 0) && rateMatches(value.rates.rejectionRate, expectedRejectionRate) && rateMatches(
|
|
4468
|
+
value.rates.deterministicRedactionsPerAccepted,
|
|
4469
|
+
expectedDeterministicRate
|
|
4470
|
+
) && rateMatches(
|
|
4471
|
+
value.rates.scannerRedactionsPerAccepted,
|
|
4472
|
+
expectedScannerRate
|
|
4473
|
+
) && trafficIsConsistent && distributions.every(hasUniqueIds) && advisoryCodesAreConsistent(value.advisories, {
|
|
4474
|
+
"severity-five": severityFiveCount > 0 ? {
|
|
4475
|
+
level: "advisory",
|
|
4476
|
+
triggerCount: severityFiveCount,
|
|
4477
|
+
recommendationIds: ["inspect-release"]
|
|
4478
|
+
} : void 0,
|
|
4479
|
+
"critical-regression": criticalRegression ? {
|
|
4480
|
+
level: "critical",
|
|
4481
|
+
triggerCount: severityFiveCount >= 3 ? severityFiveCount : value.acceptedCount,
|
|
4482
|
+
recommendationIds: [
|
|
4483
|
+
"inspect-release",
|
|
4484
|
+
"verify-renderer-health"
|
|
4485
|
+
]
|
|
4486
|
+
} : void 0,
|
|
4487
|
+
"processor-stale": lagSeconds > 10 * 60 ? {
|
|
4488
|
+
level: "critical",
|
|
4489
|
+
triggerCount: lagSeconds,
|
|
4490
|
+
recommendationIds: ["verify-processor-health"]
|
|
4491
|
+
} : void 0
|
|
4492
|
+
}) && distributionTotal(value.targetDistribution) === value.acceptedCount && distributionTotal(value.issueTypeDistribution) === value.acceptedCount && distributionTotal(value.severityDistribution) === value.acceptedCount && distributionCountsAtMost(
|
|
4493
|
+
value.intentDistribution,
|
|
4494
|
+
value.acceptedCount
|
|
4495
|
+
) && distributionTotal(value.intentDistribution) <= value.acceptedCount * 8 && distributionTotal(value.buildDistribution) === value.acceptedCount && distributionTotal(value.rendererDistribution) === value.diagnosticsAttachedCount && distributionTotal(value.backendDistribution) === value.diagnosticsAttachedCount && distributionTotal(value.viewportDistribution) === value.diagnosticsAttachedCount && distributionTotal(value.frameRateDistribution) === value.diagnosticsAttachedCount && distributionTotal(value.frameTimeDistribution) === value.diagnosticsAttachedCount && distributionTotal(value.diagnosticFeatureDistribution) <= value.diagnosticsAttachedCount * FEEDBACK_GAME_FEATURE_IDS.length && distributionCountsAtMost(
|
|
4496
|
+
value.diagnosticFeatureDistribution,
|
|
4497
|
+
value.diagnosticsAttachedCount
|
|
4498
|
+
) && distributionTotal(value.diagnosticCounterDistribution) <= value.diagnosticsAttachedCount * FEEDBACK_GAME_COUNTER_CODES.length * 1e4 && distributionCountsAtMost(
|
|
4499
|
+
value.diagnosticCounterDistribution,
|
|
4500
|
+
value.diagnosticsAttachedCount * 1e4
|
|
4501
|
+
) && distributionTotal(value.diagnosticErrorDistribution) <= value.diagnosticsAttachedCount * FEEDBACK_GAME_ERROR_CODES.length && distributionCountsAtMost(
|
|
4502
|
+
value.diagnosticErrorDistribution,
|
|
4503
|
+
value.diagnosticsAttachedCount
|
|
4504
|
+
);
|
|
4505
|
+
}
|
|
4506
|
+
}
|
|
4507
|
+
);
|
|
4508
|
+
var rollingSatisfactionShape = () => ({
|
|
4509
|
+
period: field.string().enum(["7-days", "30-days", "90-days"]),
|
|
4510
|
+
reviewCount: countField(),
|
|
4511
|
+
meanStars: field.number().min(1).max(5).optional()
|
|
4512
|
+
});
|
|
4513
|
+
var satisfactionStatistics = (distribution, total) => {
|
|
4514
|
+
if (!Array.isArray(distribution) || total <= 0) {
|
|
4515
|
+
return void 0;
|
|
4516
|
+
}
|
|
4517
|
+
const counts = [1, 2, 3, 4, 5].map(
|
|
4518
|
+
(star) => distributionCountFor(distribution, String(star))
|
|
4519
|
+
);
|
|
4520
|
+
const weightedTotal = counts.reduce(
|
|
4521
|
+
(sum, count, index) => sum + count * (index + 1),
|
|
4522
|
+
0
|
|
4523
|
+
);
|
|
4524
|
+
const valueAtPosition = (position) => {
|
|
4525
|
+
let cumulative = 0;
|
|
4526
|
+
for (let index = 0; index < counts.length; index += 1) {
|
|
4527
|
+
cumulative += counts[index] ?? 0;
|
|
4528
|
+
if (cumulative >= position) {
|
|
4529
|
+
return index + 1;
|
|
4530
|
+
}
|
|
4531
|
+
}
|
|
4532
|
+
return 5;
|
|
4533
|
+
};
|
|
4534
|
+
const lower = valueAtPosition(Math.ceil(total / 2));
|
|
4535
|
+
const upper = valueAtPosition(Math.floor(total / 2) + 1);
|
|
4536
|
+
return {
|
|
4537
|
+
mean: Math.round(weightedTotal / total * 10) / 10,
|
|
4538
|
+
median: (lower + upper) / 2
|
|
4539
|
+
};
|
|
4540
|
+
};
|
|
4541
|
+
var FeedbackDailySatisfactionReportSchema = createSchema(
|
|
4542
|
+
{
|
|
4543
|
+
reportId: uuidField(),
|
|
4544
|
+
windowStart: field.dateTimeISO(),
|
|
4545
|
+
windowEnd: field.dateTimeISO(),
|
|
4546
|
+
revision: revisionField(),
|
|
4547
|
+
generatedAt: field.dateTimeISO(),
|
|
4548
|
+
processorLagSeconds: countField(),
|
|
4549
|
+
acceptedReviewCount: countField(),
|
|
4550
|
+
meanStars: field.number().min(1).max(5).optional(),
|
|
4551
|
+
medianStars: field.number().min(1).max(5).optional(),
|
|
4552
|
+
starDistribution: field.array(
|
|
4553
|
+
field.object(
|
|
4554
|
+
distributionShape(
|
|
4555
|
+
() => field.string().enum(["1", "2", "3", "4", "5"])
|
|
4556
|
+
)
|
|
4557
|
+
)
|
|
4558
|
+
).max(5),
|
|
4559
|
+
sentimentDistribution: field.array(
|
|
4560
|
+
field.object(
|
|
4561
|
+
distributionShape(
|
|
4562
|
+
() => field.string().enum(FEEDBACK_SENTIMENT_BUCKETS)
|
|
4563
|
+
)
|
|
4564
|
+
)
|
|
4565
|
+
).max(FEEDBACK_SENTIMENT_BUCKETS.length),
|
|
4566
|
+
intentDistribution: field.array(
|
|
4567
|
+
field.object(
|
|
4568
|
+
distributionShape(
|
|
4569
|
+
() => field.string().enum(FEEDBACK_INTENT_IDS)
|
|
4570
|
+
)
|
|
4571
|
+
)
|
|
4572
|
+
).max(FEEDBACK_INTENT_IDS.length),
|
|
4573
|
+
rollingWindows: field.array(field.object(rollingSatisfactionShape())).max(3),
|
|
4574
|
+
previousPeriodDeltaStars: field.number().min(-4).max(4).optional(),
|
|
4575
|
+
advisories: field.array(field.object(advisoryShape())).max(32)
|
|
4576
|
+
},
|
|
4577
|
+
"feedback-daily-satisfaction-report",
|
|
4578
|
+
{
|
|
4579
|
+
...strictOptions,
|
|
4580
|
+
schemaValidator: (value) => {
|
|
4581
|
+
if (!orderedWindow(value, 24 * 60 * 60 * 1e3)) {
|
|
4582
|
+
return false;
|
|
4583
|
+
}
|
|
4584
|
+
if (value.acceptedReviewCount === 0 && (value.meanStars !== void 0 || value.medianStars !== void 0)) {
|
|
4585
|
+
return false;
|
|
4586
|
+
}
|
|
4587
|
+
if (value.acceptedReviewCount > 0 && (value.meanStars === void 0 || value.medianStars === void 0)) {
|
|
4588
|
+
return false;
|
|
4589
|
+
}
|
|
4590
|
+
const distributions = [
|
|
4591
|
+
value.starDistribution,
|
|
4592
|
+
value.sentimentDistribution,
|
|
4593
|
+
value.intentDistribution
|
|
4594
|
+
];
|
|
4595
|
+
const periods = value.rollingWindows.map(
|
|
4596
|
+
(window) => window.period
|
|
4597
|
+
);
|
|
4598
|
+
const sevenDayWindow = value.rollingWindows.find(
|
|
4599
|
+
(window) => window.period === "7-days"
|
|
4600
|
+
);
|
|
4601
|
+
const thirtyDayWindow = value.rollingWindows.find(
|
|
4602
|
+
(window) => window.period === "30-days"
|
|
4603
|
+
);
|
|
4604
|
+
const ninetyDayWindow = value.rollingWindows.find(
|
|
4605
|
+
(window) => window.period === "90-days"
|
|
4606
|
+
);
|
|
4607
|
+
if (sevenDayWindow === void 0 || thirtyDayWindow === void 0 || ninetyDayWindow === void 0) {
|
|
4608
|
+
return false;
|
|
4609
|
+
}
|
|
4610
|
+
const statistics = satisfactionStatistics(
|
|
4611
|
+
value.starDistribution,
|
|
4612
|
+
value.acceptedReviewCount
|
|
4613
|
+
);
|
|
4614
|
+
const lagSeconds = Math.floor(
|
|
4615
|
+
(Date.parse(String(value.generatedAt)) - Date.parse(String(value.windowEnd))) / 1e3
|
|
4616
|
+
);
|
|
4617
|
+
const satisfactionDrop = sevenDayWindow.reviewCount >= 20 && typeof value.previousPeriodDeltaStars === "number" && value.previousPeriodDeltaStars <= -0.3;
|
|
4618
|
+
return value.revision >= 1 && value.processorLagSeconds === lagSeconds && distributions.every(hasUniqueIds) && distributionTotal(value.starDistribution) === value.acceptedReviewCount && distributionTotal(value.sentimentDistribution) <= value.acceptedReviewCount && distributionCountsAtMost(
|
|
4619
|
+
value.sentimentDistribution,
|
|
4620
|
+
value.acceptedReviewCount
|
|
4621
|
+
) && distributionTotal(value.intentDistribution) <= value.acceptedReviewCount * 8 && distributionCountsAtMost(
|
|
4622
|
+
value.intentDistribution,
|
|
4623
|
+
value.acceptedReviewCount
|
|
4624
|
+
) && periods.length === 3 && new Set(periods).size === 3 && (statistics === void 0 && value.meanStars === void 0 && value.medianStars === void 0 || statistics !== void 0 && value.meanStars === statistics.mean && value.medianStars === statistics.median) && advisoryCodesAreConsistent(value.advisories, {
|
|
4625
|
+
"satisfaction-drop": satisfactionDrop ? {
|
|
4626
|
+
level: "advisory",
|
|
4627
|
+
triggerCount: sevenDayWindow.reviewCount,
|
|
4628
|
+
recommendationIds: ["review-top-intents"]
|
|
4629
|
+
} : void 0,
|
|
4630
|
+
"processor-stale": lagSeconds > 2.5 * 60 * 60 ? {
|
|
4631
|
+
level: "critical",
|
|
4632
|
+
triggerCount: lagSeconds,
|
|
4633
|
+
recommendationIds: ["verify-processor-health"]
|
|
4634
|
+
} : void 0
|
|
4635
|
+
}) && value.rollingWindows.every(
|
|
4636
|
+
(window) => window.reviewCount === 0 && window.meanStars === void 0 || window.reviewCount > 0 && window.meanStars !== void 0
|
|
4637
|
+
) && value.acceptedReviewCount <= sevenDayWindow.reviewCount && sevenDayWindow.reviewCount <= thirtyDayWindow.reviewCount && thirtyDayWindow.reviewCount <= ninetyDayWindow.reviewCount;
|
|
4638
|
+
}
|
|
4639
|
+
}
|
|
4640
|
+
);
|
|
4641
|
+
var publicWeeklyPointShape = () => ({
|
|
4642
|
+
weekStart: field.dateTimeISO(),
|
|
4643
|
+
state: field.string().enum(["published", "suppressed"]),
|
|
4644
|
+
acceptedReviewCount: positiveCountField2().optional(),
|
|
4645
|
+
averageStars: field.number().min(1).max(5).optional()
|
|
4646
|
+
});
|
|
4647
|
+
var publicComparisonShape = () => ({
|
|
4648
|
+
previousAcceptedReviewCount: positiveCountField2(),
|
|
4649
|
+
previousAverageStars: field.number().min(1).max(5),
|
|
4650
|
+
deltaStars: field.number().min(-4).max(4)
|
|
4651
|
+
});
|
|
4652
|
+
var FeedbackPublicSummarySchema = createSchema(
|
|
4653
|
+
{
|
|
4654
|
+
snapshotId: uuidField(),
|
|
4655
|
+
generatedAt: field.dateTimeISO(),
|
|
4656
|
+
asOf: field.dateTimeISO(),
|
|
4657
|
+
freshness: field.string().enum(["fresh", "stale"]),
|
|
4658
|
+
reportAgeSeconds: countField(),
|
|
4659
|
+
rollingWindowDays: field.number().enum([90]),
|
|
4660
|
+
state: field.string().enum(["published", "suppressed"]),
|
|
4661
|
+
acceptedReviewCount: positiveCountField2().optional(),
|
|
4662
|
+
averageStars: field.number().min(1).max(5).optional(),
|
|
4663
|
+
trend: field.string().enum(["up", "flat", "down"]).optional(),
|
|
4664
|
+
comparison: field.object(publicComparisonShape()).optional(),
|
|
4665
|
+
weeklyPoints: field.array(field.object(publicWeeklyPointShape())).min(13).max(13)
|
|
4666
|
+
},
|
|
4667
|
+
"feedback-public-summary",
|
|
4668
|
+
{
|
|
4669
|
+
...strictOptions,
|
|
4670
|
+
schemaValidator: (value) => {
|
|
4671
|
+
const summaryIsSuppressed = value.state === "suppressed" && value.acceptedReviewCount === void 0 && value.averageStars === void 0 && value.trend === void 0 && value.comparison === void 0;
|
|
4672
|
+
const comparisonDelta = value.comparison === void 0 ? void 0 : roundRate(
|
|
4673
|
+
value.averageStars - value.comparison.previousAverageStars
|
|
4674
|
+
);
|
|
4675
|
+
const expectedTrend = comparisonDelta === void 0 ? void 0 : comparisonDelta >= 0.1 ? "up" : comparisonDelta <= -0.1 ? "down" : "flat";
|
|
4676
|
+
const comparisonIsConsistent = value.comparison === void 0 && value.trend === void 0 || value.comparison !== void 0 && value.comparison.previousAcceptedReviewCount >= 10 && value.comparison.deltaStars === comparisonDelta && value.trend === expectedTrend;
|
|
4677
|
+
const summaryIsPublished = value.state === "published" && typeof value.acceptedReviewCount === "number" && value.acceptedReviewCount >= 10 && typeof value.averageStars === "number" && comparisonIsConsistent;
|
|
4678
|
+
if (!summaryIsSuppressed && !summaryIsPublished) {
|
|
4679
|
+
return false;
|
|
4680
|
+
}
|
|
4681
|
+
const weekStarts = value.weeklyPoints.map(
|
|
4682
|
+
(point) => point.weekStart
|
|
4683
|
+
);
|
|
4684
|
+
const asOf = Date.parse(String(value.asOf));
|
|
4685
|
+
const generatedAt = Date.parse(String(value.generatedAt));
|
|
4686
|
+
if (!Number.isFinite(asOf) || !Number.isFinite(generatedAt) || new Date(asOf).toISOString() !== value.asOf || new Date(asOf).getUTCHours() !== 0 || new Date(asOf).getUTCMinutes() !== 0 || new Date(asOf).getUTCSeconds() !== 0 || new Date(asOf).getUTCMilliseconds() !== 0 || generatedAt < asOf || value.reportAgeSeconds !== Math.floor((generatedAt - asOf) / 1e3)) {
|
|
4687
|
+
return false;
|
|
4688
|
+
}
|
|
4689
|
+
const daysSinceMonday = (new Date(asOf).getUTCDay() + 6) % 7;
|
|
4690
|
+
const lastWeekStart = asOf - daysSinceMonday * 24 * 60 * 60 * 1e3;
|
|
4691
|
+
const weeksAreCanonical = weekStarts.every(
|
|
4692
|
+
(weekStart, index) => Date.parse(weekStart) === lastWeekStart - (12 - index) * 7 * 24 * 60 * 60 * 1e3
|
|
4693
|
+
);
|
|
4694
|
+
return new Set(weekStarts).size === weekStarts.length && weeksAreCanonical && (value.state !== "suppressed" || value.weeklyPoints.every(
|
|
4695
|
+
(point) => point.state === "suppressed"
|
|
4696
|
+
)) && value.weeklyPoints.every(
|
|
4697
|
+
(point) => point.state === "suppressed" && point.acceptedReviewCount === void 0 && point.averageStars === void 0 || point.state === "published" && typeof point.acceptedReviewCount === "number" && point.acceptedReviewCount >= 10 && typeof point.averageStars === "number" && (value.state !== "published" || point.acceptedReviewCount <= value.acceptedReviewCount)
|
|
4698
|
+
);
|
|
4699
|
+
}
|
|
4700
|
+
}
|
|
4701
|
+
);
|
|
4702
|
+
var FeedbackProcessorCheckpointSchema = createSchema(
|
|
4703
|
+
{
|
|
4704
|
+
checkpointId: safeIdField(160),
|
|
4705
|
+
processor: field.string().enum(["bug-hourly", "review-daily", "commit-reconciliation"]),
|
|
4706
|
+
windowKey: safeIdField(160),
|
|
4707
|
+
revision: revisionField(),
|
|
4708
|
+
completedAt: field.dateTimeISO(),
|
|
4709
|
+
reportId: uuidField().optional()
|
|
4710
|
+
},
|
|
4711
|
+
"feedback-processor-checkpoint",
|
|
4712
|
+
{
|
|
4713
|
+
...strictOptions,
|
|
4714
|
+
schemaValidator: (value) => isProcessorArtifactConsistent(value, "checkpoint") && value.revision >= 1 && (value.processor === "commit-reconciliation" && value.reportId === void 0 || value.processor !== "commit-reconciliation" && value.reportId !== void 0)
|
|
4715
|
+
}
|
|
4716
|
+
);
|
|
4717
|
+
var FeedbackMaterializationManifestSchema = createSchema(
|
|
4718
|
+
{
|
|
4719
|
+
manifestId: uuidField(),
|
|
4720
|
+
processor: field.string().enum(["bug-hourly", "review-daily", "commit-reconciliation"]),
|
|
4721
|
+
windowKey: safeIdField(160),
|
|
4722
|
+
revision: revisionField(),
|
|
4723
|
+
generatedAt: field.dateTimeISO(),
|
|
4724
|
+
sourcePacketCount: countField(),
|
|
4725
|
+
lateArrivalCount: countField(),
|
|
4726
|
+
outputReportId: uuidField().optional(),
|
|
4727
|
+
status: field.string().enum(["published", "corrected", "no-op"])
|
|
4728
|
+
},
|
|
4729
|
+
"feedback-materialization-manifest",
|
|
4730
|
+
{
|
|
4731
|
+
...strictOptions,
|
|
4732
|
+
schemaValidator: (value) => {
|
|
4733
|
+
if (!isProcessorArtifactConsistent(value, "manifest") || value.lateArrivalCount > value.sourcePacketCount) {
|
|
4734
|
+
return false;
|
|
4735
|
+
}
|
|
4736
|
+
if (value.processor === "commit-reconciliation") {
|
|
4737
|
+
return value.status === "no-op" && value.revision >= 1 && value.outputReportId === void 0 && value.lateArrivalCount === 0;
|
|
4738
|
+
}
|
|
4739
|
+
return value.status === "published" && value.revision === 1 && value.lateArrivalCount === 0 && value.outputReportId !== void 0 || value.status === "corrected" && value.revision >= 2 && value.lateArrivalCount > 0 && value.outputReportId !== void 0;
|
|
4740
|
+
}
|
|
4741
|
+
}
|
|
4742
|
+
);
|
|
2681
4743
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2682
4744
|
0 && (module.exports = {
|
|
4745
|
+
FEEDBACK_ANALYSIS_MODEL_VERSIONS,
|
|
4746
|
+
FEEDBACK_BACKEND_BUCKETS,
|
|
4747
|
+
FEEDBACK_BUG_COOLDOWN_SECONDS,
|
|
4748
|
+
FEEDBACK_CONTRACT_VERSION,
|
|
4749
|
+
FEEDBACK_FRAME_RATE_BUCKETS,
|
|
4750
|
+
FEEDBACK_FRAME_TIME_BUCKETS,
|
|
4751
|
+
FEEDBACK_GAME_COUNTER_CODES,
|
|
4752
|
+
FEEDBACK_GAME_COUNTER_MAX_COUNT,
|
|
4753
|
+
FEEDBACK_GAME_COUNTER_MAX_ITEMS,
|
|
4754
|
+
FEEDBACK_GAME_ERROR_CODES,
|
|
4755
|
+
FEEDBACK_GAME_FEATURE_IDS,
|
|
4756
|
+
FEEDBACK_GAME_PROVENANCE_CONTRACTS,
|
|
4757
|
+
FEEDBACK_GAME_PROVENANCE_CONTRACT_IDS,
|
|
4758
|
+
FEEDBACK_GAME_SURFACE_IDS,
|
|
4759
|
+
FEEDBACK_INTENT_IDS,
|
|
4760
|
+
FEEDBACK_ISSUE_TYPES,
|
|
4761
|
+
FEEDBACK_PERSISTABLE_ISSUE_TYPES,
|
|
4762
|
+
FEEDBACK_PRIVACY_POLICY_VERSIONS,
|
|
4763
|
+
FEEDBACK_RENDERER_BUCKETS,
|
|
4764
|
+
FEEDBACK_REVIEW_COOLDOWN_SECONDS,
|
|
4765
|
+
FEEDBACK_SATISFACTION_LEVELS,
|
|
4766
|
+
FEEDBACK_SENTIMENT_BUCKETS,
|
|
4767
|
+
FEEDBACK_SEVERITY_LEVELS,
|
|
4768
|
+
FEEDBACK_STRUCTURED_ONLY_REASON_CODES,
|
|
4769
|
+
FEEDBACK_SURFACE_DEFINITIONS,
|
|
4770
|
+
FEEDBACK_SURFACE_IDS,
|
|
4771
|
+
FEEDBACK_THEME_IDS,
|
|
4772
|
+
FEEDBACK_UNICODE_NORMALIZATION_PROFILE,
|
|
4773
|
+
FEEDBACK_VIEWPORT_BUCKETS,
|
|
4774
|
+
FeedbackAcceptanceReceiptSchema,
|
|
4775
|
+
FeedbackAnalysisReceiptSchema,
|
|
4776
|
+
FeedbackBugPacketSchema,
|
|
4777
|
+
FeedbackBugSubmissionRequestSchema,
|
|
4778
|
+
FeedbackContextSchema,
|
|
4779
|
+
FeedbackDailySatisfactionReportSchema,
|
|
4780
|
+
FeedbackDerivedAnalysisSchema,
|
|
4781
|
+
FeedbackDraftPacketSchema,
|
|
4782
|
+
FeedbackDraftReceiptSchema,
|
|
4783
|
+
FeedbackDraftUpsertRequestSchema,
|
|
4784
|
+
FeedbackEncryptedNarrativeEnvelopeSchema,
|
|
4785
|
+
FeedbackGameDiagnosticsSchema,
|
|
4786
|
+
FeedbackGameReconstructionManifestSchema,
|
|
4787
|
+
FeedbackHourlyBugReportSchema,
|
|
4788
|
+
FeedbackMaterializationManifestSchema,
|
|
4789
|
+
FeedbackProcessorCheckpointSchema,
|
|
4790
|
+
FeedbackPublicSummarySchema,
|
|
4791
|
+
FeedbackReviewPacketSchema,
|
|
4792
|
+
FeedbackReviewSubmissionRequestSchema,
|
|
4793
|
+
FeedbackRichTextAstSchema,
|
|
4794
|
+
FeedbackStructuredOnlyAnalysisResultSchema,
|
|
4795
|
+
FeedbackSurfaceCatalogSchema,
|
|
4796
|
+
FeedbackTransientAnalysisRequestSchema,
|
|
2683
4797
|
FieldBuilder,
|
|
2684
4798
|
IsoLanguageCode,
|
|
2685
4799
|
PLAYER_SYSTEM_ACHIEVEMENT_TIERS,
|
|
@@ -2688,6 +4802,8 @@ var PlayerSystemCuratedSnapshotSchema = createSchema(
|
|
|
2688
4802
|
PlayerSystemCuratedSnapshotSchema,
|
|
2689
4803
|
PlayerSystemNormalizedEventBatchSchema,
|
|
2690
4804
|
PlayerSystemObservedEventBatchSchema,
|
|
4805
|
+
SCHEMA_IDENTITY_POLICIES,
|
|
4806
|
+
SCHEMA_UNKNOWN_FIELDS_POLICIES,
|
|
2691
4807
|
createComponentSchema,
|
|
2692
4808
|
createSchema,
|
|
2693
4809
|
field,
|
|
@@ -2710,7 +4826,10 @@ var PlayerSystemCuratedSnapshotSchema = createSchema(
|
|
|
2710
4826
|
validateCountryCode,
|
|
2711
4827
|
validateCurrencyCode,
|
|
2712
4828
|
validateDateTimeISO,
|
|
4829
|
+
validateDisplayName,
|
|
2713
4830
|
validateEmail,
|
|
4831
|
+
validateFeedbackGameDiagnostics,
|
|
4832
|
+
validateFeedbackTransientAnalysisRequest,
|
|
2714
4833
|
validateLanguage,
|
|
2715
4834
|
validateName,
|
|
2716
4835
|
validatePercentage,
|