velocious 1.0.474 → 1.0.476

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +10 -2
  2. package/build/configuration-types.js +39 -1
  3. package/build/configuration.js +46 -1
  4. package/build/database/drivers/base.js +67 -3
  5. package/build/database/drivers/mssql/index.js +13 -0
  6. package/build/database/drivers/mssql/sql/remove-index.js +6 -0
  7. package/build/database/drivers/mysql/index.js +87 -7
  8. package/build/database/drivers/mysql/sql/remove-index.js +6 -0
  9. package/build/database/drivers/pgsql/index.js +13 -0
  10. package/build/database/drivers/pgsql/sql/remove-index.js +6 -0
  11. package/build/database/drivers/sqlite/base.js +13 -0
  12. package/build/database/drivers/sqlite/connection-sql-js.js +16 -5
  13. package/build/database/drivers/sqlite/index.web.js +29 -15
  14. package/build/database/drivers/sqlite/sql/remove-index.js +6 -0
  15. package/build/database/drivers/sqlite/web-persistence.js +521 -0
  16. package/build/database/migration/index.js +44 -0
  17. package/build/database/pool/base-methods-forward.js +1 -0
  18. package/build/database/query/remove-index-base.js +39 -0
  19. package/build/database/record/index.js +25 -9
  20. package/build/environment-handlers/node/cli/commands/generate/base-models.js +36 -0
  21. package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +63 -0
  22. package/build/frontend-model-controller.js +401 -4
  23. package/build/frontend-model-resource/base-resource.js +5 -1
  24. package/build/frontend-models/base.js +146 -2
  25. package/build/frontend-models/query.js +3 -3
  26. package/build/frontend-models/resource-definition.js +304 -2
  27. package/build/routes/hooks/frontend-model-command-route-hook.js +16 -0
  28. package/build/src/configuration-types.d.ts +118 -2
  29. package/build/src/configuration-types.d.ts.map +1 -1
  30. package/build/src/configuration-types.js +36 -2
  31. package/build/src/configuration.d.ts +18 -1
  32. package/build/src/configuration.d.ts.map +1 -1
  33. package/build/src/configuration.js +42 -2
  34. package/build/src/database/drivers/base.d.ts +50 -0
  35. package/build/src/database/drivers/base.d.ts.map +1 -1
  36. package/build/src/database/drivers/base.js +62 -4
  37. package/build/src/database/drivers/mssql/index.d.ts.map +1 -1
  38. package/build/src/database/drivers/mssql/index.js +12 -1
  39. package/build/src/database/drivers/mssql/sql/remove-index.d.ts +4 -0
  40. package/build/src/database/drivers/mssql/sql/remove-index.d.ts.map +1 -0
  41. package/build/src/database/drivers/mssql/sql/remove-index.js +5 -0
  42. package/build/src/database/drivers/mysql/index.d.ts +32 -3
  43. package/build/src/database/drivers/mysql/index.d.ts.map +1 -1
  44. package/build/src/database/drivers/mysql/index.js +76 -7
  45. package/build/src/database/drivers/mysql/sql/remove-index.d.ts +4 -0
  46. package/build/src/database/drivers/mysql/sql/remove-index.d.ts.map +1 -0
  47. package/build/src/database/drivers/mysql/sql/remove-index.js +5 -0
  48. package/build/src/database/drivers/pgsql/index.d.ts.map +1 -1
  49. package/build/src/database/drivers/pgsql/index.js +12 -1
  50. package/build/src/database/drivers/pgsql/sql/remove-index.d.ts +4 -0
  51. package/build/src/database/drivers/pgsql/sql/remove-index.d.ts.map +1 -0
  52. package/build/src/database/drivers/pgsql/sql/remove-index.js +5 -0
  53. package/build/src/database/drivers/sqlite/base.d.ts.map +1 -1
  54. package/build/src/database/drivers/sqlite/base.js +12 -1
  55. package/build/src/database/drivers/sqlite/connection-sql-js.d.ts +8 -1
  56. package/build/src/database/drivers/sqlite/connection-sql-js.d.ts.map +1 -1
  57. package/build/src/database/drivers/sqlite/connection-sql-js.js +15 -6
  58. package/build/src/database/drivers/sqlite/index.web.d.ts +5 -5
  59. package/build/src/database/drivers/sqlite/index.web.d.ts.map +1 -1
  60. package/build/src/database/drivers/sqlite/index.web.js +27 -13
  61. package/build/src/database/drivers/sqlite/sql/remove-index.d.ts +4 -0
  62. package/build/src/database/drivers/sqlite/sql/remove-index.d.ts.map +1 -0
  63. package/build/src/database/drivers/sqlite/sql/remove-index.js +5 -0
  64. package/build/src/database/drivers/sqlite/web-persistence.d.ts +77 -0
  65. package/build/src/database/drivers/sqlite/web-persistence.d.ts.map +1 -0
  66. package/build/src/database/drivers/sqlite/web-persistence.js +464 -0
  67. package/build/src/database/migration/index.d.ts +25 -0
  68. package/build/src/database/migration/index.d.ts.map +1 -1
  69. package/build/src/database/migration/index.js +39 -1
  70. package/build/src/database/pool/base-methods-forward.d.ts.map +1 -1
  71. package/build/src/database/pool/base-methods-forward.js +2 -1
  72. package/build/src/database/query/remove-index-base.d.ts +35 -0
  73. package/build/src/database/query/remove-index-base.d.ts.map +1 -0
  74. package/build/src/database/query/remove-index-base.js +34 -0
  75. package/build/src/database/record/index.d.ts +11 -0
  76. package/build/src/database/record/index.d.ts.map +1 -1
  77. package/build/src/database/record/index.js +26 -11
  78. package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts +15 -0
  79. package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
  80. package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +33 -1
  81. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +30 -0
  82. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
  83. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +53 -1
  84. package/build/src/frontend-model-controller.d.ts +96 -0
  85. package/build/src/frontend-model-controller.d.ts.map +1 -1
  86. package/build/src/frontend-model-controller.js +359 -5
  87. package/build/src/frontend-model-resource/base-resource.d.ts +4 -2
  88. package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
  89. package/build/src/frontend-model-resource/base-resource.js +7 -2
  90. package/build/src/frontend-models/base.d.ts +29 -0
  91. package/build/src/frontend-models/base.d.ts.map +1 -1
  92. package/build/src/frontend-models/base.js +131 -3
  93. package/build/src/frontend-models/query.js +4 -4
  94. package/build/src/frontend-models/resource-definition.d.ts +6 -0
  95. package/build/src/frontend-models/resource-definition.d.ts.map +1 -1
  96. package/build/src/frontend-models/resource-definition.js +272 -3
  97. package/build/src/routes/hooks/frontend-model-command-route-hook.d.ts.map +1 -1
  98. package/build/src/routes/hooks/frontend-model-command-route-hook.js +15 -1
  99. package/build/src/sync/device-identity.d.ts +240 -0
  100. package/build/src/sync/device-identity.d.ts.map +1 -0
  101. package/build/src/sync/device-identity.js +454 -0
  102. package/build/src/sync/local-mutation-log.d.ts +212 -0
  103. package/build/src/sync/local-mutation-log.d.ts.map +1 -0
  104. package/build/src/sync/local-mutation-log.js +404 -0
  105. package/build/src/sync/offline-grant.d.ts +157 -0
  106. package/build/src/sync/offline-grant.d.ts.map +1 -0
  107. package/build/src/sync/offline-grant.js +292 -0
  108. package/build/sync/device-identity.js +503 -0
  109. package/build/sync/local-mutation-log.js +448 -0
  110. package/build/sync/offline-grant.js +327 -0
  111. package/build/tsconfig.tsbuildinfo +1 -1
  112. package/package.json +3 -3
  113. package/src/configuration-types.js +39 -1
  114. package/src/configuration.js +46 -1
  115. package/src/database/drivers/base.js +67 -3
  116. package/src/database/drivers/mssql/index.js +13 -0
  117. package/src/database/drivers/mssql/sql/remove-index.js +6 -0
  118. package/src/database/drivers/mysql/index.js +87 -7
  119. package/src/database/drivers/mysql/sql/remove-index.js +6 -0
  120. package/src/database/drivers/pgsql/index.js +13 -0
  121. package/src/database/drivers/pgsql/sql/remove-index.js +6 -0
  122. package/src/database/drivers/sqlite/base.js +13 -0
  123. package/src/database/drivers/sqlite/connection-sql-js.js +16 -5
  124. package/src/database/drivers/sqlite/index.web.js +29 -15
  125. package/src/database/drivers/sqlite/sql/remove-index.js +6 -0
  126. package/src/database/drivers/sqlite/web-persistence.js +521 -0
  127. package/src/database/migration/index.js +44 -0
  128. package/src/database/pool/base-methods-forward.js +1 -0
  129. package/src/database/query/remove-index-base.js +39 -0
  130. package/src/database/record/index.js +25 -9
  131. package/src/environment-handlers/node/cli/commands/generate/base-models.js +36 -0
  132. package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +63 -0
  133. package/src/frontend-model-controller.js +401 -4
  134. package/src/frontend-model-resource/base-resource.js +5 -1
  135. package/src/frontend-models/base.js +146 -2
  136. package/src/frontend-models/query.js +3 -3
  137. package/src/frontend-models/resource-definition.js +304 -2
  138. package/src/routes/hooks/frontend-model-command-route-hook.js +16 -0
  139. package/src/sync/device-identity.js +503 -0
  140. package/src/sync/local-mutation-log.js +448 -0
  141. package/src/sync/offline-grant.js +327 -0
@@ -0,0 +1,292 @@
1
+ // @ts-check
2
+ const OFFLINE_GRANT_SIGNATURE_ALGORITHM = "HS256";
3
+ const OFFLINE_GRANT_SIGNATURE_PREFIX = "hmac-sha256-";
4
+ /**
5
+ * Signed offline grant envelope.
6
+ * @typedef {object} SignedOfflineGrant
7
+ * @property {"HS256"} algorithm - Signature algorithm.
8
+ * @property {OfflineGrant} grant - Signed grant payload.
9
+ * @property {string} keyId - Signing key id.
10
+ * @property {string} signature - Hex HMAC signature with a hmac-sha256 prefix.
11
+ */
12
+ /**
13
+ * Backend-issued offline grant payload.
14
+ * @typedef {object} OfflineGrant
15
+ * @property {string} deviceId - Device id allowed to use the grant.
16
+ * @property {string} expiresAt - ISO timestamp after which replay must reject the grant.
17
+ * @property {string} grantId - Stable grant id.
18
+ * @property {string} issuedAt - ISO timestamp when the backend issued the grant.
19
+ * @property {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} resources - Sync manifest/materialized resource metadata.
20
+ * @property {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} scopes - Materialized grant scopes.
21
+ * @property {string} userId - Actor user id allowed to use the grant.
22
+ */
23
+ /**
24
+ * Offline grant signing key.
25
+ * @typedef {object} OfflineGrantSigningKey
26
+ * @property {boolean} [current] - Whether this is the active key for new grants.
27
+ * @property {string} id - Public key id included in signed grant envelopes.
28
+ * @property {string} secret - Private HMAC secret. Never expose this to clients.
29
+ */
30
+ /**
31
+ * Creates a signed offline grant envelope.
32
+ * @param {object} args - Arguments.
33
+ * @param {OfflineGrant} args.grant - Grant payload.
34
+ * @param {OfflineGrantSigningKey} args.signingKey - Current signing key.
35
+ * @returns {Promise<SignedOfflineGrant>} - Signed grant envelope.
36
+ */
37
+ export async function createOfflineGrant({ grant, signingKey }) {
38
+ const normalizedGrant = normalizeOfflineGrant(grant);
39
+ const normalizedSigningKey = normalizeOfflineGrantSigningKey(signingKey);
40
+ const signatureInput = offlineGrantSignatureInput({
41
+ algorithm: OFFLINE_GRANT_SIGNATURE_ALGORITHM,
42
+ grant: normalizedGrant,
43
+ keyId: normalizedSigningKey.id
44
+ });
45
+ return {
46
+ algorithm: OFFLINE_GRANT_SIGNATURE_ALGORITHM,
47
+ grant: normalizedGrant,
48
+ keyId: normalizedSigningKey.id,
49
+ signature: await hmacSha256Hex({ message: signatureInput, secret: normalizedSigningKey.secret })
50
+ };
51
+ }
52
+ /**
53
+ * Verifies a signed offline grant and returns the trusted grant payload.
54
+ * @param {object} args - Arguments.
55
+ * @param {Date} [args.now] - Verification time. Defaults to current time.
56
+ * @param {SignedOfflineGrant} args.signedGrant - Signed grant envelope.
57
+ * @param {OfflineGrantSigningKey[]} args.signingKeys - Candidate verification keys.
58
+ * @returns {Promise<OfflineGrant>} - Verified grant payload.
59
+ */
60
+ export async function verifyOfflineGrant({ now = new Date(), signedGrant, signingKeys }) {
61
+ const normalizedSignedGrant = normalizeSignedOfflineGrant(signedGrant);
62
+ if (normalizedSignedGrant.algorithm !== OFFLINE_GRANT_SIGNATURE_ALGORITHM) {
63
+ throw new Error(`Unsupported offline grant signature algorithm '${normalizedSignedGrant.algorithm}'`);
64
+ }
65
+ const signingKey = signingKeys
66
+ .map((key) => normalizeOfflineGrantSigningKey(key))
67
+ .find((key) => key.id === normalizedSignedGrant.keyId);
68
+ if (!signingKey)
69
+ throw new Error(`No offline grant signing key for key id '${normalizedSignedGrant.keyId}'`);
70
+ const expectedSignature = await hmacSha256Hex({
71
+ message: offlineGrantSignatureInput(normalizedSignedGrant),
72
+ secret: signingKey.secret
73
+ });
74
+ if (expectedSignature !== normalizedSignedGrant.signature) {
75
+ throw new Error("Offline grant signature did not match");
76
+ }
77
+ if (Number.isNaN(now.getTime()))
78
+ throw new Error("Invalid offline grant verification time");
79
+ if (new Date(normalizedSignedGrant.grant.expiresAt).getTime() <= now.getTime())
80
+ throw new Error("Offline grant expired");
81
+ return normalizedSignedGrant.grant;
82
+ }
83
+ /**
84
+ * Builds a signed grant from bootstrap request inputs.
85
+ * @param {object} args - Arguments.
86
+ * @param {string} args.deviceId - Device id.
87
+ * @param {string | undefined} [args.grantId] - Optional deterministic grant id for tests/custom callers.
88
+ * @param {number | undefined} [args.grantTtlMs] - Grant TTL in milliseconds.
89
+ * @param {Date} args.now - Issue time.
90
+ * @param {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} args.resources - Resource sync manifest.
91
+ * @param {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} args.scopes - Grant scopes.
92
+ * @param {OfflineGrantSigningKey} args.signingKey - Current signing key.
93
+ * @param {string} args.userId - Actor user id.
94
+ * @returns {Promise<SignedOfflineGrant>} - Signed grant.
95
+ */
96
+ export async function createOfflineGrantFromBootstrap({ deviceId, grantId, grantTtlMs, now, resources, scopes, signingKey, userId }) {
97
+ const issuedAt = isoDateString(now, "issuedAt");
98
+ const ttlMs = grantTtlMs === undefined ? 24 * 60 * 60 * 1000 : grantTtlMs;
99
+ if (!Number.isInteger(ttlMs) || ttlMs <= 0)
100
+ throw new Error("Offline grant TTL must be a positive integer number of milliseconds");
101
+ return await createOfflineGrant({
102
+ grant: {
103
+ deviceId,
104
+ expiresAt: new Date(now.getTime() + ttlMs).toISOString(),
105
+ grantId: grantId || randomGrantId(),
106
+ issuedAt,
107
+ resources,
108
+ scopes,
109
+ userId
110
+ },
111
+ signingKey
112
+ });
113
+ }
114
+ /**
115
+ * Normalizes signed grant signature input.
116
+ * @param {{algorithm: "HS256", grant: OfflineGrant, keyId: string}} signedGrant - Grant signature fields.
117
+ * @returns {string} - Stable signature input.
118
+ */
119
+ function offlineGrantSignatureInput(signedGrant) {
120
+ return stableJsonStringify({
121
+ algorithm: signedGrant.algorithm,
122
+ grant: signedGrant.grant,
123
+ keyId: signedGrant.keyId
124
+ });
125
+ }
126
+ /**
127
+ * Normalizes a signed offline grant envelope.
128
+ * @param {SignedOfflineGrant} signedGrant - Signed grant.
129
+ * @returns {SignedOfflineGrant} - Normalized signed grant.
130
+ */
131
+ function normalizeSignedOfflineGrant(signedGrant) {
132
+ if (!signedGrant || typeof signedGrant !== "object" || Array.isArray(signedGrant))
133
+ throw new Error("Expected signed offline grant object");
134
+ if (signedGrant.algorithm !== OFFLINE_GRANT_SIGNATURE_ALGORITHM)
135
+ throw new Error(`Unsupported offline grant signature algorithm '${String(signedGrant.algorithm)}'`);
136
+ if (typeof signedGrant.keyId !== "string" || signedGrant.keyId.length < 1)
137
+ throw new Error("Expected offline grant key id");
138
+ if (typeof signedGrant.signature !== "string" || !signedGrant.signature.match(/^hmac-sha256-[a-f0-9]{64}$/))
139
+ throw new Error("Expected offline grant signature");
140
+ return {
141
+ algorithm: signedGrant.algorithm,
142
+ grant: normalizeOfflineGrant(signedGrant.grant),
143
+ keyId: signedGrant.keyId,
144
+ signature: signedGrant.signature
145
+ };
146
+ }
147
+ /**
148
+ * Normalizes an offline grant payload.
149
+ * @param {OfflineGrant} grant - Grant payload.
150
+ * @returns {OfflineGrant} - Normalized grant payload.
151
+ */
152
+ function normalizeOfflineGrant(grant) {
153
+ if (!grant || typeof grant !== "object" || Array.isArray(grant))
154
+ throw new Error("Expected offline grant object");
155
+ return {
156
+ deviceId: requiredString(grant.deviceId, "deviceId"),
157
+ expiresAt: isoDateString(new Date(requiredString(grant.expiresAt, "expiresAt")), "expiresAt"),
158
+ grantId: requiredString(grant.grantId, "grantId"),
159
+ issuedAt: isoDateString(new Date(requiredString(grant.issuedAt, "issuedAt")), "issuedAt"),
160
+ resources: deterministicJsonObject({ label: "resources", value: grant.resources }),
161
+ scopes: deterministicJsonObject({ label: "scopes", value: grant.scopes }),
162
+ userId: requiredString(grant.userId, "userId")
163
+ };
164
+ }
165
+ /**
166
+ * Normalizes an offline grant signing key.
167
+ * @param {OfflineGrantSigningKey} signingKey - Signing key.
168
+ * @returns {OfflineGrantSigningKey} - Normalized signing key.
169
+ */
170
+ export function normalizeOfflineGrantSigningKey(signingKey) {
171
+ if (!signingKey || typeof signingKey !== "object" || Array.isArray(signingKey))
172
+ throw new Error("Expected offline grant signing key object");
173
+ return {
174
+ current: signingKey.current === true,
175
+ id: requiredString(signingKey.id, "signingKey.id"),
176
+ secret: requiredString(signingKey.secret, "signingKey.secret")
177
+ };
178
+ }
179
+ /**
180
+ * Returns the current key used to sign new grants.
181
+ * @param {OfflineGrantSigningKey[]} signingKeys - Configured signing keys.
182
+ * @returns {OfflineGrantSigningKey} - Current signing key.
183
+ */
184
+ export function currentOfflineGrantSigningKey(signingKeys) {
185
+ const normalizedKeys = signingKeys.map((key) => normalizeOfflineGrantSigningKey(key));
186
+ const currentKeys = normalizedKeys.filter((key) => key.current === true);
187
+ if (normalizedKeys.length < 1)
188
+ throw new Error("At least one offline grant signing key is required");
189
+ if (currentKeys.length > 1)
190
+ throw new Error("Only one offline grant signing key can be current");
191
+ return currentKeys[0] || normalizedKeys[0];
192
+ }
193
+ /**
194
+ * Signs a message using HMAC-SHA256 and returns a prefixed hex signature.
195
+ * @param {object} args - Arguments.
196
+ * @param {string} args.message - Message to sign.
197
+ * @param {string} args.secret - HMAC secret.
198
+ * @returns {Promise<string>} - Prefixed hex signature.
199
+ */
200
+ async function hmacSha256Hex({ message, secret }) {
201
+ const cryptoProvider = globalThis.crypto;
202
+ if (!cryptoProvider?.subtle)
203
+ throw new Error("WebCrypto subtle API is required for offline grant signing");
204
+ const key = await cryptoProvider.subtle.importKey("raw", new TextEncoder().encode(secret), { hash: "SHA-256", name: "HMAC" }, false, ["sign"]);
205
+ const signature = await cryptoProvider.subtle.sign("HMAC", key, new TextEncoder().encode(message));
206
+ return `${OFFLINE_GRANT_SIGNATURE_PREFIX}${hex(new Uint8Array(signature))}`;
207
+ }
208
+ /**
209
+ * Converts bytes to lower-case hex.
210
+ * @param {Uint8Array} bytes - Bytes.
211
+ * @returns {string} - Hex string.
212
+ */
213
+ function hex(bytes) {
214
+ return Array.from(bytes).map((byte) => byte.toString(16).padStart(2, "0")).join("");
215
+ }
216
+ /**
217
+ * Requires a non-empty string field.
218
+ * @param {unknown} value - Value.
219
+ * @param {string} name - Field name.
220
+ * @returns {string} - String value.
221
+ */
222
+ function requiredString(value, name) {
223
+ if (typeof value !== "string" || value.length < 1)
224
+ throw new Error(`Expected offline grant ${name}`);
225
+ return value;
226
+ }
227
+ /**
228
+ * Normalizes a Date to an ISO timestamp.
229
+ * @param {Date} date - Date value.
230
+ * @param {string} label - Field label.
231
+ * @returns {string} - ISO timestamp.
232
+ */
233
+ function isoDateString(date, label) {
234
+ if (Number.isNaN(date.getTime()))
235
+ throw new Error(`Invalid offline grant ${label}`);
236
+ return date.toISOString();
237
+ }
238
+ /**
239
+ * Generates a fallback random grant id.
240
+ * @returns {string} - Grant id.
241
+ */
242
+ function randomGrantId() {
243
+ return globalThis.crypto?.randomUUID ? globalThis.crypto.randomUUID() : `grant-${Date.now()}-${Math.random().toString(16).slice(2)}`;
244
+ }
245
+ /**
246
+ * Stable JSON stringifier with sorted object keys.
247
+ * @param {unknown} value - Value.
248
+ * @returns {string} - JSON string.
249
+ */
250
+ function stableJsonStringify(value) {
251
+ return JSON.stringify(deterministicJson({ label: "root", value }));
252
+ }
253
+ /**
254
+ * Normalizes a value as a JSON object.
255
+ * @param {object} args - Arguments.
256
+ * @param {string} args.label - Diagnostic label.
257
+ * @param {unknown} args.value - Value.
258
+ * @returns {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} - JSON object.
259
+ */
260
+ function deterministicJsonObject({ label, value }) {
261
+ const normalized = deterministicJson({ label, value });
262
+ if (!normalized || typeof normalized !== "object" || Array.isArray(normalized))
263
+ throw new Error(`Expected offline grant ${label} object`);
264
+ return /** @type {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} */ (normalized);
265
+ }
266
+ /**
267
+ * Normalizes deterministic JSON with sorted object keys.
268
+ * @param {object} args - Arguments.
269
+ * @param {string} args.label - Diagnostic label.
270
+ * @param {unknown} args.value - Value.
271
+ * @returns {import("../configuration-types.js").FrontendModelSyncJsonValue} - Normalized JSON value.
272
+ */
273
+ function deterministicJson({ label, value }) {
274
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean")
275
+ return value;
276
+ if (Array.isArray(value)) {
277
+ return value.map((entry, index) => deterministicJson({ label: `${label}/${index}`, value: entry }));
278
+ }
279
+ if (value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
280
+ /** @type {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} */
281
+ const normalized = {};
282
+ for (const key of Object.keys(value).sort()) {
283
+ const childValue = /** @type {Record<string, unknown>} */ (value)[key];
284
+ if (childValue === undefined)
285
+ continue;
286
+ normalized[key] = deterministicJson({ label: `${label}/${key}`, value: childValue });
287
+ }
288
+ return normalized;
289
+ }
290
+ throw new Error(`Offline grant ${label} must be deterministic JSON`);
291
+ }
292
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2ZmbGluZS1ncmFudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zeW5jL29mZmxpbmUtZ3JhbnQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE1BQU0saUNBQWlDLEdBQUcsT0FBTyxDQUFBO0FBQ2pELE1BQU0sOEJBQThCLEdBQUcsY0FBYyxDQUFBO0FBRXJEOzs7Ozs7O0dBT0c7QUFFSDs7Ozs7Ozs7OztHQVVHO0FBRUg7Ozs7OztHQU1HO0FBRUg7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxrQkFBa0IsQ0FBQyxFQUFDLEtBQUssRUFBRSxVQUFVLEVBQUM7SUFDMUQsTUFBTSxlQUFlLEdBQUcscUJBQXFCLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDcEQsTUFBTSxvQkFBb0IsR0FBRywrQkFBK0IsQ0FBQyxVQUFVLENBQUMsQ0FBQTtJQUN4RSxNQUFNLGNBQWMsR0FBRywwQkFBMEIsQ0FBQztRQUNoRCxTQUFTLEVBQUUsaUNBQWlDO1FBQzVDLEtBQUssRUFBRSxlQUFlO1FBQ3RCLEtBQUssRUFBRSxvQkFBb0IsQ0FBQyxFQUFFO0tBQy9CLENBQUMsQ0FBQTtJQUVGLE9BQU87UUFDTCxTQUFTLEVBQUUsaUNBQWlDO1FBQzVDLEtBQUssRUFBRSxlQUFlO1FBQ3RCLEtBQUssRUFBRSxvQkFBb0IsQ0FBQyxFQUFFO1FBQzlCLFNBQVMsRUFBRSxNQUFNLGFBQWEsQ0FBQyxFQUFDLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLG9CQUFvQixDQUFDLE1BQU0sRUFBQyxDQUFDO0tBQy9GLENBQUE7QUFDSCxDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsa0JBQWtCLENBQUMsRUFBQyxHQUFHLEdBQUcsSUFBSSxJQUFJLEVBQUUsRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFDO0lBQ25GLE1BQU0scUJBQXFCLEdBQUcsMkJBQTJCLENBQUMsV0FB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QUFJLEtBQUssRUFBRSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUMsQ0FBQyxDQUFDLENBQUE7SUFDbkcsQ0FBQztJQUVELElBQUksS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxNQUFNLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxLQUFLLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUM1Riw2RkFBNkY7UUFDN0YsTUFBTSxVQUFVLEdBQUcsRUFBRSxDQUFBO1FBRXJCLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDO1lBQzVDLE1BQU0sVUFBVSxHQUFHLHNDQUFzQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUE7WUFFdEUsSUFBSSxVQUFVLEtBQUssU0FBUztnQkFBRSxTQUFRO1lBQ3RDLFVBQVUsQ0FBQyxHQUFHLENBQUMsR0FBRyxpQkFBaUIsQ0FBQyxFQUFDLEtBQUssRUFBRSxHQUFHLEtBQUssSUFBSSxHQUFHLEVBQUUsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFDLENBQUMsQ0FBQTtRQUNwRixDQUFDO1FBRUQsT0FBTyxVQUFVLENBQUE7SUFDbkIsQ0FBQztJQUVELE1BQU0sSUFBSSxLQUFLLENBQUMsaUJBQWlCLEtBQUssNkJBQTZCLENBQUMsQ0FBQTtBQUN0RSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmNvbnN0IE9GRkxJTkVfR1JBTlRfU0lHTkFUVVJFX0FMR09SSVRITSA9IFwiSFMyNTZcIlxuY29uc3QgT0ZGTElORV9HUkFOVF9TSUdOQVRVUkVfUFJFRklYID0gXCJobWFjLXNoYTI1Ni1cIlxuXG4vKipcbiAqIFNpZ25lZCBvZmZsaW5lIGdyYW50IGVudmVsb3BlLlxuICogQHR5cGVkZWYge29iamVjdH0gU2lnbmVkT2ZmbGluZUdyYW50XG4gKiBAcHJvcGVydHkge1wiSFMyNTZcIn0gYWxnb3JpdGhtIC0gU2lnbmF0dXJlIGFsZ29yaXRobS5cbiAqIEBwcm9wZXJ0eSB7T2ZmbGluZUdyYW50fSBncmFudCAtIFNpZ25lZCBncmFudCBwYXlsb2FkLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGtleUlkIC0gU2lnbmluZyBrZXkgaWQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gc2lnbmF0dXJlIC0gSGV4IEhNQUMgc2lnbmF0dXJlIHdpdGggYSBobWFjLXNoYTI1NiBwcmVmaXguXG4gKi9cblxuLyoqXG4gKiBCYWNrZW5kLWlzc3VlZCBvZmZsaW5lIGdyYW50IHBheWxvYWQuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBPZmZsaW5lR3JhbnRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBkZXZpY2VJZCAtIERldmljZSBpZCBhbGxvd2VkIHRvIHVzZSB0aGUgZ3JhbnQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gZXhwaXJlc0F0IC0gSVNPIHRpbWVzdGFtcCBhZnRlciB3aGljaCByZXBsYXkgbXVzdCByZWplY3QgdGhlIGdyYW50LlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGdyYW50SWQgLSBTdGFibGUgZ3JhbnQgaWQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gaXNzdWVkQXQgLSBJU08gdGltZXN0YW1wIHdoZW4gdGhlIGJhY2tlbmQgaXNzdWVkIHRoZSBncmFudC5cbiAqIEBwcm9wZXJ0eSB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59IHJlc291cmNlcyAtIFN5bmMgbWFuaWZlc3QvbWF0ZXJpYWxpemVkIHJlc291cmNlIG1ldGFkYXRhLlxuICogQHByb3BlcnR5IHtSZWNvcmQ8c3RyaW5nLCBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkZyb250ZW5kTW9kZWxTeW5jSnNvblZhbHVlPn0gc2NvcGVzIC0gTWF0ZXJpYWxpemVkIGdyYW50IHNjb3Blcy5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB1c2VySWQgLSBBY3RvciB1c2VyIGlkIGFsbG93ZWQgdG8gdXNlIHRoZSBncmFudC5cbiAqL1xuXG4vKipcbiAqIE9mZmxpbmUgZ3JhbnQgc2lnbmluZyBrZXkuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBPZmZsaW5lR3JhbnRTaWduaW5nS2V5XG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IFtjdXJyZW50XSAtIFdoZXRoZXIgdGhpcyBpcyB0aGUgYWN0aXZlIGtleSBmb3IgbmV3IGdyYW50cy5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBpZCAtIFB1YmxpYyBrZXkgaWQgaW5jbHVkZWQgaW4gc2lnbmVkIGdyYW50IGVudmVsb3Blcy5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBzZWNyZXQgLSBQcml2YXRlIEhNQUMgc2VjcmV0LiBOZXZlciBleHBvc2UgdGhpcyB0byBjbGllbnRzLlxuICovXG5cbi8qKlxuICogQ3JlYXRlcyBhIHNpZ25lZCBvZmZsaW5lIGdyYW50IGVudmVsb3BlLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBBcmd1bWVudHMuXG4gKiBAcGFyYW0ge09mZmxpbmVHcmFudH0gYXJncy5ncmFudCAtIEdyYW50IHBheWxvYWQuXG4gKiBAcGFyYW0ge09mZmxpbmVHcmFudFNpZ25pbmdLZXl9IGFyZ3Muc2lnbmluZ0tleSAtIEN1cnJlbnQgc2lnbmluZyBrZXkuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxTaWduZWRPZmZsaW5lR3JhbnQ+fSAtIFNpZ25lZCBncmFudCBlbnZlbG9wZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZU9mZmxpbmVHcmFudCh7Z3JhbnQsIHNpZ25pbmdLZXl9KSB7XG4gIGNvbnN0IG5vcm1hbGl6ZWRHcmFudCA9IG5vcm1hbGl6ZU9mZmxpbmVHcmFudChncmFudClcbiAgY29uc3Qgbm9ybWFsaXplZFNpZ25pbmdLZXkgPSBub3JtYWxpemVPZmZsaW5lR3JhbnRTaWduaW5nS2V5KHNpZ25pbmdLZXkpXG4gIGNvbnN0IHNpZ25hdHVyZUlucHV0ID0gb2ZmbGluZUdyYW50U2lnbmF0dXJlSW5wdXQoe1xuICAgIGFsZ29yaXRobTogT0ZGTElORV9HUkFOVF9TSUdOQVRVUkVfQUxHT1JJVEhNLFxuICAgIGdyYW50OiBub3JtYWxpemVkR3JhbnQsXG4gICAga2V5SWQ6IG5vcm1hbGl6ZWRTaWduaW5nS2V5LmlkXG4gIH0pXG5cbiAgcmV0dXJuIHtcbiAgICBhbGdvcml0aG06IE9GRkxJTkVfR1JBTlRfU0lHTkFUVVJFX0FMR09SSVRITSxcbiAgICBncmFudDogbm9ybWFsaXplZEdyYW50LFxuICAgIGtleUlkOiBub3JtYWxpemVkU2lnbmluZ0tleS5pZCxcbiAgICBzaWduYXR1cmU6IGF3YWl0IGhtYWNTaGEyNTZIZXgoe21lc3NhZ2U6IHNpZ25hdHVyZUlucHV0LCBzZWNyZXQ6IG5vcm1hbGl6ZWRTaWduaW5nS2V5LnNlY3JldH0pXG4gIH1cbn1cblxuLyoqXG4gKiBWZXJpZmllcyBhIHNpZ25lZCBvZmZsaW5lIGdyYW50IGFuZCByZXR1cm5zIHRoZSB0cnVzdGVkIGdyYW50IHBheWxvYWQuXG4gKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIEFyZ3VtZW50cy5cbiAqIEBwYXJhbSB7RGF0ZX0gW2FyZ3Mubm93XSAtIFZlcmlmaWNhdGlvbiB0aW1lLiBEZWZhdWx0cyB0byBjdXJyZW50IHRpbWUuXG4gKiBAcGFyYW0ge1NpZ25lZE9mZmxpbmVHcmFudH0gYXJncy5zaWduZWRHcmFudCAtIFNpZ25lZCBncmFudCBlbnZlbG9wZS5cbiAqIEBwYXJhbSB7T2ZmbGluZUdyYW50U2lnbmluZ0tleVtdfSBhcmdzLnNpZ25pbmdLZXlzIC0gQ2FuZGlkYXRlIHZlcmlmaWNhdGlvbiBrZXlzLlxuICogQHJldHVybnMge1Byb21pc2U8T2ZmbGluZUdyYW50Pn0gLSBWZXJpZmllZCBncmFudCBwYXlsb2FkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdmVyaWZ5T2ZmbGluZUdyYW50KHtub3cgPSBuZXcgRGF0ZSgpLCBzaWduZWRHcmFudCwgc2lnbmluZ0tleXN9KSB7XG4gIGNvbnN0IG5vcm1hbGl6ZWRTaWduZWRHcmFudCA9IG5vcm1hbGl6ZVNpZ25lZE9mZmxpbmVHcmFudChzaWduZWRHcmFudClcblxuICBpZiAobm9ybWFsaXplZFNpZ25lZEdyYW50LmFsZ29yaXRobSAhPT0gT0ZGTElORV9HUkFOVF9TSUdOQVRVUkVfQUxHT1JJVEhNKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBvZmZsaW5lIGdyYW50IHNpZ25hdHVyZSBhbGdvcml0aG0gJyR7bm9ybWFsaXplZFNpZ25lZEdyYW50LmFsZ29yaXRobX0nYClcbiAgfVxuXG4gIGNvbnN0IHNpZ25pbmdLZXkgPSBzaWduaW5nS2V5c1xuICAgIC5tYXAoKGtleSkgPT4gbm9ybWFsaXplT2ZmbGluZUdyYW50U2lnbmluZ0tleShrZXkpKVxuICAgIC5maW5kKChrZXkpID0+IGtleS5pZCA9PT0gbm9ybWFsaXplZFNpZ25lZEdyYW50LmtleUlkKVxuXG4gIGlmICghc2lnbmluZ0tleSkgdGhyb3cgbmV3IEVycm9yKGBObyBvZmZsaW5lIGdyYW50IHNpZ25pbmcga2V5IGZvciBrZXkgaWQgJyR7bm9ybWFsaXplZFNpZ25lZEdyYW50LmtleUlkfSdgKVxuXG4gIGNvbnN0IGV4cGVjdGVkU2lnbmF0dXJlID0gYXdhaXQgaG1hY1NoYTI1NkhleCh7XG4gICAgbWVzc2FnZTogb2ZmbGluZUdyYW50U2lnbmF0dXJlSW5wdXQobm9ybWFsaXplZFNpZ25lZEdyYW50KSxcbiAgICBzZWNyZXQ6IHNpZ25pbmdLZXkuc2VjcmV0XG4gIH0pXG5cbiAgaWYgKGV4cGVjdGVkU2lnbmF0dXJlICE9PSBub3JtYWxpemVkU2lnbmVkR3JhbnQuc2lnbmF0dXJlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiT2ZmbGluZSBncmFudCBzaWduYXR1cmUgZGlkIG5vdCBtYXRjaFwiKVxuICB9XG5cbiAgaWYgKE51bWJlci5pc05hTihub3cuZ2V0VGltZSgpKSkgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBvZmZsaW5lIGdyYW50IHZlcmlmaWNhdGlvbiB0aW1lXCIpXG4gIGlmIChuZXcgRGF0ZShub3JtYWxpemVkU2lnbmVkR3JhbnQuZ3JhbnQuZXhwaXJlc0F0KS5nZXRUaW1lKCkgPD0gbm93LmdldFRpbWUoKSkgdGhyb3cgbmV3IEVycm9yKFwiT2ZmbGluZSBncmFudCBleHBpcmVkXCIpXG5cbiAgcmV0dXJuIG5vcm1hbGl6ZWRTaWduZWRHcmFudC5ncmFudFxufVxuXG4vKipcbiAqIEJ1aWxkcyBhIHNpZ25lZCBncmFudCBmcm9tIGJvb3RzdHJhcCByZXF1ZXN0IGlucHV0cy5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQXJndW1lbnRzLlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MuZGV2aWNlSWQgLSBEZXZpY2UgaWQuXG4gKiBAcGFyYW0ge3N0cmluZyB8IHVuZGVmaW5lZH0gW2FyZ3MuZ3JhbnRJZF0gLSBPcHRpb25hbCBkZXRlcm1pbmlzdGljIGdyYW50IGlkIGZvciB0ZXN0cy9jdXN0b20gY2FsbGVycy5cbiAqIEBwYXJhbSB7bnVtYmVyIHwgdW5kZWZpbmVkfSBbYXJncy5ncmFudFR0bE1zXSAtIEdyYW50IFRUTCBpbiBtaWxsaXNlY29uZHMuXG4gKiBAcGFyYW0ge0RhdGV9IGFyZ3Mubm93IC0gSXNzdWUgdGltZS5cbiAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59IGFyZ3MucmVzb3VyY2VzIC0gUmVzb3VyY2Ugc3luYyBtYW5pZmVzdC5cbiAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59IGFyZ3Muc2NvcGVzIC0gR3JhbnQgc2NvcGVzLlxuICogQHBhcmFtIHtPZmZsaW5lR3JhbnRTaWduaW5nS2V5fSBhcmdzLnNpZ25pbmdLZXkgLSBDdXJyZW50IHNpZ25pbmcga2V5LlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MudXNlcklkIC0gQWN0b3IgdXNlciBpZC5cbiAqIEByZXR1cm5zIHtQcm9taXNlPFNpZ25lZE9mZmxpbmVHcmFudD59IC0gU2lnbmVkIGdyYW50LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlT2ZmbGluZUdyYW50RnJvbUJvb3RzdHJhcCh7ZGV2aWNlSWQsIGdyYW50SWQsIGdyYW50VHRsTXMsIG5vdywgcmVzb3VyY2VzLCBzY29wZXMsIHNpZ25pbmdLZXksIHVzZXJJZH0pIHtcbiAgY29uc3QgaXNzdWVkQXQgPSBpc29EYXRlU3RyaW5nKG5vdywgXCJpc3N1ZWRBdFwiKVxuICBjb25zdCB0dGxNcyA9IGdyYW50VHRsTXMgPT09IHVuZGVmaW5lZCA/IDI0ICogNjAgKiA2MCAqIDEwMDAgOiBncmFudFR0bE1zXG5cbiAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHR0bE1zKSB8fCB0dGxNcyA8PSAwKSB0aHJvdyBuZXcgRXJyb3IoXCJPZmZsaW5lIGdyYW50IFRUTCBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlciBudW1iZXIgb2YgbWlsbGlzZWNvbmRzXCIpXG5cbiAgcmV0dXJuIGF3YWl0IGNyZWF0ZU9mZmxpbmVHcmFudCh7XG4gICAgZ3JhbnQ6IHtcbiAgICAgIGRldmljZUlkLFxuICAgICAgZXhwaXJlc0F0OiBuZXcgRGF0ZShub3cuZ2V0VGltZSgpICsgdHRsTXMpLnRvSVNPU3RyaW5nKCksXG4gICAgICBncmFudElkOiBncmFudElkIHx8IHJhbmRvbUdyYW50SWQoKSxcbiAgICAgIGlzc3VlZEF0LFxuICAgICAgcmVzb3VyY2VzLFxuICAgICAgc2NvcGVzLFxuICAgICAgdXNlcklkXG4gICAgfSxcbiAgICBzaWduaW5nS2V5XG4gIH0pXG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBzaWduZWQgZ3JhbnQgc2lnbmF0dXJlIGlucHV0LlxuICogQHBhcmFtIHt7YWxnb3JpdGhtOiBcIkhTMjU2XCIsIGdyYW50OiBPZmZsaW5lR3JhbnQsIGtleUlkOiBzdHJpbmd9fSBzaWduZWRHcmFudCAtIEdyYW50IHNpZ25hdHVyZSBmaWVsZHMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFN0YWJsZSBzaWduYXR1cmUgaW5wdXQuXG4gKi9cbmZ1bmN0aW9uIG9mZmxpbmVHcmFudFNpZ25hdHVyZUlucHV0KHNpZ25lZEdyYW50KSB7XG4gIHJldHVybiBzdGFibGVKc29uU3RyaW5naWZ5KHtcbiAgICBhbGdvcml0aG06IHNpZ25lZEdyYW50LmFsZ29yaXRobSxcbiAgICBncmFudDogc2lnbmVkR3JhbnQuZ3JhbnQsXG4gICAga2V5SWQ6IHNpZ25lZEdyYW50LmtleUlkXG4gIH0pXG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBhIHNpZ25lZCBvZmZsaW5lIGdyYW50IGVudmVsb3BlLlxuICogQHBhcmFtIHtTaWduZWRPZmZsaW5lR3JhbnR9IHNpZ25lZEdyYW50IC0gU2lnbmVkIGdyYW50LlxuICogQHJldHVybnMge1NpZ25lZE9mZmxpbmVHcmFudH0gLSBOb3JtYWxpemVkIHNpZ25lZCBncmFudC5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplU2lnbmVkT2ZmbGluZUdyYW50KHNpZ25lZEdyYW50KSB7XG4gIGlmICghc2lnbmVkR3JhbnQgfHwgdHlwZW9mIHNpZ25lZEdyYW50ICE9PSBcIm9iamVjdFwiIHx8IEFycmF5LmlzQXJyYXkoc2lnbmVkR3JhbnQpKSB0aHJvdyBuZXcgRXJyb3IoXCJFeHBlY3RlZCBzaWduZWQgb2ZmbGluZSBncmFudCBvYmplY3RcIilcbiAgaWYgKHNpZ25lZEdyYW50LmFsZ29yaXRobSAhPT0gT0ZGTElORV9HUkFOVF9TSUdOQVRVUkVfQUxHT1JJVEhNKSB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIG9mZmxpbmUgZ3JhbnQgc2lnbmF0dXJlIGFsZ29yaXRobSAnJHtTdHJpbmcoc2lnbmVkR3JhbnQuYWxnb3JpdGhtKX0nYClcbiAgaWYgKHR5cGVvZiBzaWduZWRHcmFudC5rZXlJZCAhPT0gXCJzdHJpbmdcIiB8fCBzaWduZWRHcmFudC5rZXlJZC5sZW5ndGggPCAxKSB0aHJvdyBuZXcgRXJyb3IoXCJFeHBlY3RlZCBvZmZsaW5lIGdyYW50IGtleSBpZFwiKVxuICBpZiAodHlwZW9mIHNpZ25lZEdyYW50LnNpZ25hdHVyZSAhPT0gXCJzdHJpbmdcIiB8fCAhc2lnbmVkR3JhbnQuc2lnbmF0dXJlLm1hdGNoKC9eaG1hYy1zaGEyNTYtW2EtZjAtOV17NjR9JC8pKSB0aHJvdyBuZXcgRXJyb3IoXCJFeHBlY3RlZCBvZmZsaW5lIGdyYW50IHNpZ25hdHVyZVwiKVxuXG4gIHJldHVybiB7XG4gICAgYWxnb3JpdGhtOiBzaWduZWRHcmFudC5hbGdvcml0aG0sXG4gICAgZ3JhbnQ6IG5vcm1hbGl6ZU9mZmxpbmVHcmFudChzaWduZWRHcmFudC5ncmFudCksXG4gICAga2V5SWQ6IHNpZ25lZEdyYW50LmtleUlkLFxuICAgIHNpZ25hdHVyZTogc2lnbmVkR3JhbnQuc2lnbmF0dXJlXG4gIH1cbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGFuIG9mZmxpbmUgZ3JhbnQgcGF5bG9hZC5cbiAqIEBwYXJhbSB7T2ZmbGluZUdyYW50fSBncmFudCAtIEdyYW50IHBheWxvYWQuXG4gKiBAcmV0dXJucyB7T2ZmbGluZUdyYW50fSAtIE5vcm1hbGl6ZWQgZ3JhbnQgcGF5bG9hZC5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplT2ZmbGluZUdyYW50KGdyYW50KSB7XG4gIGlmICghZ3JhbnQgfHwgdHlwZW9mIGdyYW50ICE9PSBcIm9iamVjdFwiIHx8IEFycmF5LmlzQXJyYXkoZ3JhbnQpKSB0aHJvdyBuZXcgRXJyb3IoXCJFeHBlY3RlZCBvZmZsaW5lIGdyYW50IG9iamVjdFwiKVxuXG4gIHJldHVybiB7XG4gICAgZGV2aWNlSWQ6IHJlcXVpcmVkU3RyaW5nKGdyYW50LmRldmljZUlkLCBcImRldmljZUlkXCIpLFxuICAgIGV4cGlyZXNBdDogaXNvRGF0ZVN0cmluZyhuZXcgRGF0ZShyZXF1aXJlZFN0cmluZyhncmFudC5leHBpcmVzQXQsIFwiZXhwaXJlc0F0XCIpKSwgXCJleHBpcmVzQXRcIiksXG4gICAgZ3JhbnRJZDogcmVxdWlyZWRTdHJpbmcoZ3JhbnQuZ3JhbnRJZCwgXCJncmFudElkXCIpLFxuICAgIGlzc3VlZEF0OiBpc29EYXRlU3RyaW5nKG5ldyBEYXRlKHJlcXVpcmVkU3RyaW5nKGdyYW50Lmlzc3VlZEF0LCBcImlzc3VlZEF0XCIpKSwgXCJpc3N1ZWRBdFwiKSxcbiAgICByZXNvdXJjZXM6IGRldGVybWluaXN0aWNKc29uT2JqZWN0KHtsYWJlbDogXCJyZXNvdXJjZXNcIiwgdmFsdWU6IGdyYW50LnJlc291cmNlc30pLFxuICAgIHNjb3BlczogZGV0ZXJtaW5pc3RpY0pzb25PYmplY3Qoe2xhYmVsOiBcInNjb3Blc1wiLCB2YWx1ZTogZ3JhbnQuc2NvcGVzfSksXG4gICAgdXNlcklkOiByZXF1aXJlZFN0cmluZyhncmFudC51c2VySWQsIFwidXNlcklkXCIpXG4gIH1cbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGFuIG9mZmxpbmUgZ3JhbnQgc2lnbmluZyBrZXkuXG4gKiBAcGFyYW0ge09mZmxpbmVHcmFudFNpZ25pbmdLZXl9IHNpZ25pbmdLZXkgLSBTaWduaW5nIGtleS5cbiAqIEByZXR1cm5zIHtPZmZsaW5lR3JhbnRTaWduaW5nS2V5fSAtIE5vcm1hbGl6ZWQgc2lnbmluZyBrZXkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVPZmZsaW5lR3JhbnRTaWduaW5nS2V5KHNpZ25pbmdLZXkpIHtcbiAgaWYgKCFzaWduaW5nS2V5IHx8IHR5cGVvZiBzaWduaW5nS2V5ICE9PSBcIm9iamVjdFwiIHx8IEFycmF5LmlzQXJyYXkoc2lnbmluZ0tleSkpIHRocm93IG5ldyBFcnJvcihcIkV4cGVjdGVkIG9mZmxpbmUgZ3JhbnQgc2lnbmluZyBrZXkgb2JqZWN0XCIpXG5cbiAgcmV0dXJuIHtcbiAgICBjdXJyZW50OiBzaWduaW5nS2V5LmN1cnJlbnQgPT09IHRydWUsXG4gICAgaWQ6IHJlcXVpcmVkU3RyaW5nKHNpZ25pbmdLZXkuaWQsIFwic2lnbmluZ0tleS5pZFwiKSxcbiAgICBzZWNyZXQ6IHJlcXVpcmVkU3RyaW5nKHNpZ25pbmdLZXkuc2VjcmV0LCBcInNpZ25pbmdLZXkuc2VjcmV0XCIpXG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBjdXJyZW50IGtleSB1c2VkIHRvIHNpZ24gbmV3IGdyYW50cy5cbiAqIEBwYXJhbSB7T2ZmbGluZUdyYW50U2lnbmluZ0tleVtdfSBzaWduaW5nS2V5cyAtIENvbmZpZ3VyZWQgc2lnbmluZyBrZXlzLlxuICogQHJldHVybnMge09mZmxpbmVHcmFudFNpZ25pbmdLZXl9IC0gQ3VycmVudCBzaWduaW5nIGtleS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGN1cnJlbnRPZmZsaW5lR3JhbnRTaWduaW5nS2V5KHNpZ25pbmdLZXlzKSB7XG4gIGNvbnN0IG5vcm1hbGl6ZWRLZXlzID0gc2lnbmluZ0tleXMubWFwKChrZXkpID0+IG5vcm1hbGl6ZU9mZmxpbmVHcmFudFNpZ25pbmdLZXkoa2V5KSlcbiAgY29uc3QgY3VycmVudEtleXMgPSBub3JtYWxpemVkS2V5cy5maWx0ZXIoKGtleSkgPT4ga2V5LmN1cnJlbnQgPT09IHRydWUpXG5cbiAgaWYgKG5vcm1hbGl6ZWRLZXlzLmxlbmd0aCA8IDEpIHRocm93IG5ldyBFcnJvcihcIkF0IGxlYXN0IG9uZSBvZmZsaW5lIGdyYW50IHNpZ25pbmcga2V5IGlzIHJlcXVpcmVkXCIpXG4gIGlmIChjdXJyZW50S2V5cy5sZW5ndGggPiAxKSB0aHJvdyBuZXcgRXJyb3IoXCJPbmx5IG9uZSBvZmZsaW5lIGdyYW50IHNpZ25pbmcga2V5IGNhbiBiZSBjdXJyZW50XCIpXG5cbiAgcmV0dXJuIGN1cnJlbnRLZXlzWzBdIHx8IG5vcm1hbGl6ZWRLZXlzWzBdXG59XG5cbi8qKlxuICogU2lnbnMgYSBtZXNzYWdlIHVzaW5nIEhNQUMtU0hBMjU2IGFuZCByZXR1cm5zIGEgcHJlZml4ZWQgaGV4IHNpZ25hdHVyZS5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQXJndW1lbnRzLlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MubWVzc2FnZSAtIE1lc3NhZ2UgdG8gc2lnbi5cbiAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLnNlY3JldCAtIEhNQUMgc2VjcmV0LlxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gLSBQcmVmaXhlZCBoZXggc2lnbmF0dXJlLlxuICovXG5hc3luYyBmdW5jdGlvbiBobWFjU2hhMjU2SGV4KHttZXNzYWdlLCBzZWNyZXR9KSB7XG4gIGNvbnN0IGNyeXB0b1Byb3ZpZGVyID0gZ2xvYmFsVGhpcy5jcnlwdG9cblxuICBpZiAoIWNyeXB0b1Byb3ZpZGVyPy5zdWJ0bGUpIHRocm93IG5ldyBFcnJvcihcIldlYkNyeXB0byBzdWJ0bGUgQVBJIGlzIHJlcXVpcmVkIGZvciBvZmZsaW5lIGdyYW50IHNpZ25pbmdcIilcblxuICBjb25zdCBrZXkgPSBhd2FpdCBjcnlwdG9Qcm92aWRlci5zdWJ0bGUuaW1wb3J0S2V5KFxuICAgIFwicmF3XCIsXG4gICAgbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKHNlY3JldCksXG4gICAge2hhc2g6IFwiU0hBLTI1NlwiLCBuYW1lOiBcIkhNQUNcIn0sXG4gICAgZmFsc2UsXG4gICAgW1wic2lnblwiXVxuICApXG4gIGNvbnN0IHNpZ25hdHVyZSA9IGF3YWl0IGNyeXB0b1Byb3ZpZGVyLnN1YnRsZS5zaWduKFwiSE1BQ1wiLCBrZXksIG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShtZXNzYWdlKSlcblxuICByZXR1cm4gYCR7T0ZGTElORV9HUkFOVF9TSUdOQVRVUkVfUFJFRklYfSR7aGV4KG5ldyBVaW50OEFycmF5KHNpZ25hdHVyZSkpfWBcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBieXRlcyB0byBsb3dlci1jYXNlIGhleC5cbiAqIEBwYXJhbSB7VWludDhBcnJheX0gYnl0ZXMgLSBCeXRlcy5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gSGV4IHN0cmluZy5cbiAqL1xuZnVuY3Rpb24gaGV4KGJ5dGVzKSB7XG4gIHJldHVybiBBcnJheS5mcm9tKGJ5dGVzKS5tYXAoKGJ5dGUpID0+IGJ5dGUudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsIFwiMFwiKSkuam9pbihcIlwiKVxufVxuXG4vKipcbiAqIFJlcXVpcmVzIGEgbm9uLWVtcHR5IHN0cmluZyBmaWVsZC5cbiAqIEBwYXJhbSB7dW5rbm93bn0gdmFsdWUgLSBWYWx1ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gRmllbGQgbmFtZS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gU3RyaW5nIHZhbHVlLlxuICovXG5mdW5jdGlvbiByZXF1aXJlZFN0cmluZyh2YWx1ZSwgbmFtZSkge1xuICBpZiAodHlwZW9mIHZhbHVlICE9PSBcInN0cmluZ1wiIHx8IHZhbHVlLmxlbmd0aCA8IDEpIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgb2ZmbGluZSBncmFudCAke25hbWV9YClcblxuICByZXR1cm4gdmFsdWVcbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGEgRGF0ZSB0byBhbiBJU08gdGltZXN0YW1wLlxuICogQHBhcmFtIHtEYXRlfSBkYXRlIC0gRGF0ZSB2YWx1ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBsYWJlbCAtIEZpZWxkIGxhYmVsLlxuICogQHJldHVybnMge3N0cmluZ30gLSBJU08gdGltZXN0YW1wLlxuICovXG5mdW5jdGlvbiBpc29EYXRlU3RyaW5nKGRhdGUsIGxhYmVsKSB7XG4gIGlmIChOdW1iZXIuaXNOYU4oZGF0ZS5nZXRUaW1lKCkpKSB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgb2ZmbGluZSBncmFudCAke2xhYmVsfWApXG5cbiAgcmV0dXJuIGRhdGUudG9JU09TdHJpbmcoKVxufVxuXG4vKipcbiAqIEdlbmVyYXRlcyBhIGZhbGxiYWNrIHJhbmRvbSBncmFudCBpZC5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gR3JhbnQgaWQuXG4gKi9cbmZ1bmN0aW9uIHJhbmRvbUdyYW50SWQoKSB7XG4gIHJldHVybiBnbG9iYWxUaGlzLmNyeXB0bz8ucmFuZG9tVVVJRCA/IGdsb2JhbFRoaXMuY3J5cHRvLnJhbmRvbVVVSUQoKSA6IGBncmFudC0ke0RhdGUubm93KCl9LSR7TWF0aC5yYW5kb20oKS50b1N0cmluZygxNikuc2xpY2UoMil9YFxufVxuXG4vKipcbiAqIFN0YWJsZSBKU09OIHN0cmluZ2lmaWVyIHdpdGggc29ydGVkIG9iamVjdCBrZXlzLlxuICogQHBhcmFtIHt1bmtub3dufSB2YWx1ZSAtIFZhbHVlLlxuICogQHJldHVybnMge3N0cmluZ30gLSBKU09OIHN0cmluZy5cbiAqL1xuZnVuY3Rpb24gc3RhYmxlSnNvblN0cmluZ2lmeSh2YWx1ZSkge1xuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoZGV0ZXJtaW5pc3RpY0pzb24oe2xhYmVsOiBcInJvb3RcIiwgdmFsdWV9KSlcbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGEgdmFsdWUgYXMgYSBKU09OIG9iamVjdC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQXJndW1lbnRzLlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MubGFiZWwgLSBEaWFnbm9zdGljIGxhYmVsLlxuICogQHBhcmFtIHt1bmtub3dufSBhcmdzLnZhbHVlIC0gVmFsdWUuXG4gKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59IC0gSlNPTiBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIGRldGVybWluaXN0aWNKc29uT2JqZWN0KHtsYWJlbCwgdmFsdWV9KSB7XG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBkZXRlcm1pbmlzdGljSnNvbih7bGFiZWwsIHZhbHVlfSlcblxuICBpZiAoIW5vcm1hbGl6ZWQgfHwgdHlwZW9mIG5vcm1hbGl6ZWQgIT09IFwib2JqZWN0XCIgfHwgQXJyYXkuaXNBcnJheShub3JtYWxpemVkKSkgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBvZmZsaW5lIGdyYW50ICR7bGFiZWx9IG9iamVjdGApXG5cbiAgcmV0dXJuIC8qKiBAdHlwZSB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59ICovIChub3JtYWxpemVkKVxufVxuXG4vKipcbiAqIE5vcm1hbGl6ZXMgZGV0ZXJtaW5pc3RpYyBKU09OIHdpdGggc29ydGVkIG9iamVjdCBrZXlzLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBBcmd1bWVudHMuXG4gKiBAcGFyYW0ge3N0cmluZ30gYXJncy5sYWJlbCAtIERpYWdub3N0aWMgbGFiZWwuXG4gKiBAcGFyYW0ge3Vua25vd259IGFyZ3MudmFsdWUgLSBWYWx1ZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkZyb250ZW5kTW9kZWxTeW5jSnNvblZhbHVlfSAtIE5vcm1hbGl6ZWQgSlNPTiB2YWx1ZS5cbiAqL1xuZnVuY3Rpb24gZGV0ZXJtaW5pc3RpY0pzb24oe2xhYmVsLCB2YWx1ZX0pIHtcbiAgaWYgKHZhbHVlID09PSBudWxsIHx8IHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiB8fCB0eXBlb2YgdmFsdWUgPT09IFwibnVtYmVyXCIgfHwgdHlwZW9mIHZhbHVlID09PSBcImJvb2xlYW5cIikgcmV0dXJuIHZhbHVlXG5cbiAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgcmV0dXJuIHZhbHVlLm1hcCgoZW50cnksIGluZGV4KSA9PiBkZXRlcm1pbmlzdGljSnNvbih7bGFiZWw6IGAke2xhYmVsfS8ke2luZGV4fWAsIHZhbHVlOiBlbnRyeX0pKVxuICB9XG5cbiAgaWYgKHZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIiAmJiBPYmplY3QuZ2V0UHJvdG90eXBlT2YodmFsdWUpID09PSBPYmplY3QucHJvdG90eXBlKSB7XG4gICAgLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkZyb250ZW5kTW9kZWxTeW5jSnNvblZhbHVlPn0gKi9cbiAgICBjb25zdCBub3JtYWxpemVkID0ge31cblxuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHZhbHVlKS5zb3J0KCkpIHtcbiAgICAgIGNvbnN0IGNoaWxkVmFsdWUgPSAvKiogQHR5cGUge1JlY29yZDxzdHJpbmcsIHVua25vd24+fSAqLyAodmFsdWUpW2tleV1cblxuICAgICAgaWYgKGNoaWxkVmFsdWUgPT09IHVuZGVmaW5lZCkgY29udGludWVcbiAgICAgIG5vcm1hbGl6ZWRba2V5XSA9IGRldGVybWluaXN0aWNKc29uKHtsYWJlbDogYCR7bGFiZWx9LyR7a2V5fWAsIHZhbHVlOiBjaGlsZFZhbHVlfSlcbiAgICB9XG5cbiAgICByZXR1cm4gbm9ybWFsaXplZFxuICB9XG5cbiAgdGhyb3cgbmV3IEVycm9yKGBPZmZsaW5lIGdyYW50ICR7bGFiZWx9IG11c3QgYmUgZGV0ZXJtaW5pc3RpYyBKU09OYClcbn1cbiJdfQ==