react-mnemonic 1.2.0-beta1 → 1.3.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 +42 -0
- package/dist/core.cjs +1645 -1027
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +3 -2
- package/dist/core.d.ts +3 -2
- package/dist/core.js +1646 -1028
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +1635 -1383
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1636 -1384
- package/dist/index.js.map +1 -1
- package/dist/key-Bad1hAKN.d.cts +47 -0
- package/dist/key-QIDPiubI.d.ts +47 -0
- package/dist/optional.cjs +166 -0
- package/dist/optional.cjs.map +1 -0
- package/dist/optional.d.cts +13 -0
- package/dist/optional.d.ts +13 -0
- package/dist/optional.js +162 -0
- package/dist/optional.js.map +1 -0
- package/dist/schema.cjs +1635 -1383
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +3 -2
- package/dist/schema.d.ts +3 -2
- package/dist/schema.js +1636 -1384
- package/dist/schema.js.map +1 -1
- package/dist/{key-BvFvcKiR.d.cts → types-DcdXbmVl.d.cts} +88 -45
- package/dist/{key-BvFvcKiR.d.ts → types-DcdXbmVl.d.ts} +88 -45
- package/package.json +13 -1
package/dist/core.js
CHANGED
|
@@ -1,8 +1,417 @@
|
|
|
1
|
-
import { createContext, useMemo, useCallback, useEffect, useContext, useState, useSyncExternalStore, useRef } from 'react';
|
|
1
|
+
import { createContext, useMemo, useCallback, useEffect, createElement, useContext, useState, useSyncExternalStore, useRef } from 'react';
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
4
|
// src/Mnemonic/provider.tsx
|
|
5
5
|
|
|
6
|
+
// src/Mnemonic/codecs.ts
|
|
7
|
+
var CodecError = class extends Error {
|
|
8
|
+
/**
|
|
9
|
+
* Creates a new CodecError.
|
|
10
|
+
*
|
|
11
|
+
* @param message - Human-readable error description
|
|
12
|
+
* @param cause - Optional underlying error that caused this failure
|
|
13
|
+
*/
|
|
14
|
+
constructor(message, cause) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "CodecError";
|
|
17
|
+
this.cause = cause;
|
|
18
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var JSONCodec = {
|
|
22
|
+
encode: (value) => JSON.stringify(value),
|
|
23
|
+
decode: (encoded) => JSON.parse(encoded)
|
|
24
|
+
};
|
|
25
|
+
function createCodec(encode, decode) {
|
|
26
|
+
return { encode, decode };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/Mnemonic/json-schema.ts
|
|
30
|
+
function matchesType(value, type) {
|
|
31
|
+
switch (type) {
|
|
32
|
+
case "string":
|
|
33
|
+
return typeof value === "string";
|
|
34
|
+
case "number":
|
|
35
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
36
|
+
case "integer":
|
|
37
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
38
|
+
case "boolean":
|
|
39
|
+
return typeof value === "boolean";
|
|
40
|
+
case "null":
|
|
41
|
+
return value === null;
|
|
42
|
+
case "object":
|
|
43
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
44
|
+
case "array":
|
|
45
|
+
return Array.isArray(value);
|
|
46
|
+
default:
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function jsonDeepEqualArray(a, b) {
|
|
51
|
+
if (a.length !== b.length) return false;
|
|
52
|
+
for (let i = 0; i < a.length; i++) {
|
|
53
|
+
if (!jsonDeepEqual(a[i], b[i])) return false;
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
function jsonDeepEqualObject(a, b) {
|
|
58
|
+
const aKeys = Object.keys(a);
|
|
59
|
+
const bKeys = Object.keys(b);
|
|
60
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
61
|
+
for (const key of aKeys) {
|
|
62
|
+
if (!objectHasOwn(b, key)) return false;
|
|
63
|
+
if (!jsonDeepEqual(a[key], b[key])) return false;
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
function jsonDeepEqual(a, b) {
|
|
68
|
+
if (a === b) return true;
|
|
69
|
+
if (a === null || b === null) return false;
|
|
70
|
+
if (typeof a !== typeof b) return false;
|
|
71
|
+
if (Array.isArray(a)) {
|
|
72
|
+
if (!Array.isArray(b)) return false;
|
|
73
|
+
return jsonDeepEqualArray(a, b);
|
|
74
|
+
}
|
|
75
|
+
if (typeof a === "object") {
|
|
76
|
+
if (Array.isArray(b)) return false;
|
|
77
|
+
return jsonDeepEqualObject(a, b);
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
var compiledCache = /* @__PURE__ */ new WeakMap();
|
|
82
|
+
function compileSchema(schema) {
|
|
83
|
+
const cached = compiledCache.get(schema);
|
|
84
|
+
if (cached) return cached;
|
|
85
|
+
const compiled = buildValidator(schema);
|
|
86
|
+
compiledCache.set(schema, compiled);
|
|
87
|
+
return compiled;
|
|
88
|
+
}
|
|
89
|
+
function isJsonPrimitive(value) {
|
|
90
|
+
return value === null || typeof value !== "object";
|
|
91
|
+
}
|
|
92
|
+
function isJsonObjectRecord(value) {
|
|
93
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
94
|
+
}
|
|
95
|
+
function objectHasOwn(value, property) {
|
|
96
|
+
const hasOwn = Object.hasOwn;
|
|
97
|
+
if (typeof hasOwn === "function") {
|
|
98
|
+
return hasOwn(value, property);
|
|
99
|
+
}
|
|
100
|
+
return Object.getOwnPropertyDescriptor(value, property) !== void 0;
|
|
101
|
+
}
|
|
102
|
+
function buildValidator(schema) {
|
|
103
|
+
const typeStep = buildTypeValidationStep(schema);
|
|
104
|
+
const validationSteps = [
|
|
105
|
+
buildEnumValidationStep(schema),
|
|
106
|
+
buildConstValidationStep(schema),
|
|
107
|
+
buildNumberValidationStep(schema),
|
|
108
|
+
buildStringValidationStep(schema),
|
|
109
|
+
buildObjectValidationStep(schema),
|
|
110
|
+
buildArrayValidationStep(schema)
|
|
111
|
+
].filter((step) => step !== null);
|
|
112
|
+
if (typeStep === null && validationSteps.length === 0) {
|
|
113
|
+
return (_value, _path) => [];
|
|
114
|
+
}
|
|
115
|
+
return (value, path = "") => {
|
|
116
|
+
const errors = [];
|
|
117
|
+
if (typeStep && !typeStep(value, path, errors)) {
|
|
118
|
+
return errors;
|
|
119
|
+
}
|
|
120
|
+
for (const step of validationSteps) {
|
|
121
|
+
step(value, path, errors);
|
|
122
|
+
}
|
|
123
|
+
return errors;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function buildTypeValidationStep(schema) {
|
|
127
|
+
if (schema.type === void 0) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
const resolvedTypes = Array.isArray(schema.type) ? schema.type : [schema.type];
|
|
131
|
+
const typeLabel = JSON.stringify(schema.type);
|
|
132
|
+
return (value, path, errors) => {
|
|
133
|
+
if (resolvedTypes.some((type) => matchesType(value, type))) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
errors.push({
|
|
137
|
+
path,
|
|
138
|
+
message: `Expected type ${typeLabel}, got ${jsonTypeLabel(value)}`,
|
|
139
|
+
keyword: "type"
|
|
140
|
+
});
|
|
141
|
+
return false;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function buildEnumValidationStep(schema) {
|
|
145
|
+
if (schema.enum === void 0) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
const enumPrimitiveSet = new Set(schema.enum.filter((member) => isJsonPrimitive(member)));
|
|
149
|
+
const enumComplexMembers = schema.enum.filter((member) => !isJsonPrimitive(member));
|
|
150
|
+
return (value, path, errors) => {
|
|
151
|
+
const primitiveMatch = isJsonPrimitive(value) && enumPrimitiveSet.has(value);
|
|
152
|
+
const complexMatch = !primitiveMatch && enumComplexMembers.some((entry) => jsonDeepEqual(value, entry));
|
|
153
|
+
if (primitiveMatch || complexMatch) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
errors.push({
|
|
157
|
+
path,
|
|
158
|
+
message: `Value does not match any enum member`,
|
|
159
|
+
keyword: "enum"
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function buildConstValidationStep(schema) {
|
|
164
|
+
if (!("const" in schema)) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
return (value, path, errors) => {
|
|
168
|
+
if (jsonDeepEqual(value, schema.const)) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
errors.push({
|
|
172
|
+
path,
|
|
173
|
+
message: `Value does not match const`,
|
|
174
|
+
keyword: "const"
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function buildNumberValidationStep(schema) {
|
|
179
|
+
const hasMinimum = schema.minimum !== void 0;
|
|
180
|
+
const hasMaximum = schema.maximum !== void 0;
|
|
181
|
+
const hasExMin = schema.exclusiveMinimum !== void 0;
|
|
182
|
+
const hasExMax = schema.exclusiveMaximum !== void 0;
|
|
183
|
+
if (!hasMinimum && !hasMaximum && !hasExMin && !hasExMax) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
const minimum = schema.minimum;
|
|
187
|
+
const maximum = schema.maximum;
|
|
188
|
+
const exMin = schema.exclusiveMinimum;
|
|
189
|
+
const exMax = schema.exclusiveMaximum;
|
|
190
|
+
return (value, path, errors) => {
|
|
191
|
+
if (typeof value !== "number") {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (hasMinimum && value < minimum) {
|
|
195
|
+
errors.push({
|
|
196
|
+
path,
|
|
197
|
+
message: `Value ${value} is less than minimum ${minimum}`,
|
|
198
|
+
keyword: "minimum"
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
if (hasMaximum && value > maximum) {
|
|
202
|
+
errors.push({
|
|
203
|
+
path,
|
|
204
|
+
message: `Value ${value} is greater than maximum ${maximum}`,
|
|
205
|
+
keyword: "maximum"
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
if (hasExMin && value <= exMin) {
|
|
209
|
+
errors.push({
|
|
210
|
+
path,
|
|
211
|
+
message: `Value ${value} is not greater than exclusiveMinimum ${exMin}`,
|
|
212
|
+
keyword: "exclusiveMinimum"
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
if (hasExMax && value >= exMax) {
|
|
216
|
+
errors.push({
|
|
217
|
+
path,
|
|
218
|
+
message: `Value ${value} is not less than exclusiveMaximum ${exMax}`,
|
|
219
|
+
keyword: "exclusiveMaximum"
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function buildStringValidationStep(schema) {
|
|
225
|
+
const hasMinLength = schema.minLength !== void 0;
|
|
226
|
+
const hasMaxLength = schema.maxLength !== void 0;
|
|
227
|
+
if (!hasMinLength && !hasMaxLength) {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
const minLength = schema.minLength;
|
|
231
|
+
const maxLength = schema.maxLength;
|
|
232
|
+
return (value, path, errors) => {
|
|
233
|
+
if (typeof value !== "string") {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (hasMinLength && value.length < minLength) {
|
|
237
|
+
errors.push({
|
|
238
|
+
path,
|
|
239
|
+
message: `String length ${value.length} is less than minLength ${minLength}`,
|
|
240
|
+
keyword: "minLength"
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
if (hasMaxLength && value.length > maxLength) {
|
|
244
|
+
errors.push({
|
|
245
|
+
path,
|
|
246
|
+
message: `String length ${value.length} is greater than maxLength ${maxLength}`,
|
|
247
|
+
keyword: "maxLength"
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function buildObjectValidationStep(schema) {
|
|
253
|
+
const requiredKeys = schema.required ?? [];
|
|
254
|
+
const propertyValidators = schema.properties ? Object.entries(schema.properties).map(([name, propertySchema]) => [
|
|
255
|
+
name,
|
|
256
|
+
compileSchema(propertySchema)
|
|
257
|
+
]) : null;
|
|
258
|
+
const checkAdditional = schema.additionalProperties !== void 0 && schema.additionalProperties !== true;
|
|
259
|
+
const additionalIsFalse = schema.additionalProperties === false;
|
|
260
|
+
const additionalValidator = checkAdditional && !additionalIsFalse ? compileSchema(schema.additionalProperties) : null;
|
|
261
|
+
const definedPropKeys = checkAdditional ? new Set(Object.keys(schema.properties ?? {})) : null;
|
|
262
|
+
const objectValidationSteps = [];
|
|
263
|
+
if (requiredKeys.length > 0) {
|
|
264
|
+
objectValidationSteps.push(createRequiredPropertyStep(requiredKeys));
|
|
265
|
+
}
|
|
266
|
+
if (propertyValidators !== null) {
|
|
267
|
+
objectValidationSteps.push(createDeclaredPropertyStep(propertyValidators));
|
|
268
|
+
}
|
|
269
|
+
if (checkAdditional) {
|
|
270
|
+
objectValidationSteps.push(
|
|
271
|
+
createAdditionalPropertyStep({
|
|
272
|
+
additionalIsFalse,
|
|
273
|
+
additionalValidator,
|
|
274
|
+
definedPropKeys: definedPropKeys ?? /* @__PURE__ */ new Set()
|
|
275
|
+
})
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
if (objectValidationSteps.length === 0) {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
return (value, path, errors) => {
|
|
282
|
+
if (!isJsonObjectRecord(value)) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
for (const step of objectValidationSteps) {
|
|
286
|
+
step(value, path, errors);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function createRequiredPropertyStep(requiredKeys) {
|
|
291
|
+
return (value, path, errors) => {
|
|
292
|
+
for (const requiredKey of requiredKeys) {
|
|
293
|
+
if (objectHasOwn(value, requiredKey)) {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
errors.push({
|
|
297
|
+
path,
|
|
298
|
+
message: `Missing required property "${requiredKey}"`,
|
|
299
|
+
keyword: "required"
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function createDeclaredPropertyStep(propertyValidators) {
|
|
305
|
+
return (value, path, errors) => {
|
|
306
|
+
for (const [propertyName, validator] of propertyValidators) {
|
|
307
|
+
if (!objectHasOwn(value, propertyName)) {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
errors.push(...validator(value[propertyName], `${path}/${propertyName}`));
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
function createAdditionalPropertyStep({
|
|
315
|
+
additionalIsFalse,
|
|
316
|
+
additionalValidator,
|
|
317
|
+
definedPropKeys
|
|
318
|
+
}) {
|
|
319
|
+
return (value, path, errors) => {
|
|
320
|
+
for (const objectKey of Object.keys(value)) {
|
|
321
|
+
if (definedPropKeys.has(objectKey)) {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (additionalIsFalse) {
|
|
325
|
+
errors.push({
|
|
326
|
+
path,
|
|
327
|
+
message: `Additional property "${objectKey}" is not allowed`,
|
|
328
|
+
keyword: "additionalProperties"
|
|
329
|
+
});
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
errors.push(...additionalValidator(value[objectKey], `${path}/${objectKey}`));
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
function buildArrayValidationStep(schema) {
|
|
337
|
+
const hasMinItems = schema.minItems !== void 0;
|
|
338
|
+
const hasMaxItems = schema.maxItems !== void 0;
|
|
339
|
+
const itemsValidator = schema.items ? compileSchema(schema.items) : null;
|
|
340
|
+
if (!hasMinItems && !hasMaxItems && itemsValidator === null) {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
const minItems = schema.minItems;
|
|
344
|
+
const maxItems = schema.maxItems;
|
|
345
|
+
return (value, path, errors) => {
|
|
346
|
+
if (!Array.isArray(value)) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (hasMinItems && value.length < minItems) {
|
|
350
|
+
errors.push({
|
|
351
|
+
path,
|
|
352
|
+
message: `Array length ${value.length} is less than minItems ${minItems}`,
|
|
353
|
+
keyword: "minItems"
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
if (hasMaxItems && value.length > maxItems) {
|
|
357
|
+
errors.push({
|
|
358
|
+
path,
|
|
359
|
+
message: `Array length ${value.length} is greater than maxItems ${maxItems}`,
|
|
360
|
+
keyword: "maxItems"
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
if (itemsValidator === null) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
for (const [index, item] of value.entries()) {
|
|
367
|
+
errors.push(...itemsValidator(item, `${path}/${index}`));
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function validateJsonSchema(value, schema, path = "") {
|
|
372
|
+
const compiled = compileSchema(schema);
|
|
373
|
+
return compiled(value, path);
|
|
374
|
+
}
|
|
375
|
+
function jsonTypeLabel(value) {
|
|
376
|
+
if (value === null) return "null";
|
|
377
|
+
if (Array.isArray(value)) return "array";
|
|
378
|
+
return typeof value;
|
|
379
|
+
}
|
|
380
|
+
function inferJsonSchema(sample) {
|
|
381
|
+
if (sample === null) return { type: "null" };
|
|
382
|
+
if (Array.isArray(sample)) return { type: "array" };
|
|
383
|
+
switch (typeof sample) {
|
|
384
|
+
case "string":
|
|
385
|
+
return { type: "string" };
|
|
386
|
+
case "number":
|
|
387
|
+
return { type: "number" };
|
|
388
|
+
case "boolean":
|
|
389
|
+
return { type: "boolean" };
|
|
390
|
+
case "object":
|
|
391
|
+
return { type: "object" };
|
|
392
|
+
default:
|
|
393
|
+
return {};
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// src/Mnemonic/schema.ts
|
|
398
|
+
var SchemaError = class extends Error {
|
|
399
|
+
/**
|
|
400
|
+
* Creates a new SchemaError.
|
|
401
|
+
*
|
|
402
|
+
* @param code - Machine-readable failure category
|
|
403
|
+
* @param message - Human-readable error description
|
|
404
|
+
* @param cause - Optional underlying error
|
|
405
|
+
*/
|
|
406
|
+
constructor(code, message, cause) {
|
|
407
|
+
super(message);
|
|
408
|
+
this.name = "SchemaError";
|
|
409
|
+
this.code = code;
|
|
410
|
+
this.cause = cause;
|
|
411
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
|
|
6
415
|
// src/Mnemonic/runtime.ts
|
|
7
416
|
function getGlobalProcess() {
|
|
8
417
|
return globalThis.process;
|
|
@@ -28,1120 +437,1316 @@ function getNativeBrowserStorages() {
|
|
|
28
437
|
addStorage(() => globalWindow.sessionStorage);
|
|
29
438
|
return storages;
|
|
30
439
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
440
|
+
|
|
441
|
+
// src/Mnemonic/use-shared.ts
|
|
442
|
+
var SSR_SNAPSHOT_TOKEN = /* @__PURE__ */ Symbol("mnemonic:ssr-snapshot");
|
|
443
|
+
var diagnosticContractRegistry = /* @__PURE__ */ new WeakMap();
|
|
444
|
+
var diagnosticWarningRegistry = /* @__PURE__ */ new WeakMap();
|
|
445
|
+
var diagnosticObjectIds = /* @__PURE__ */ new WeakMap();
|
|
446
|
+
var nextDiagnosticObjectId = 1;
|
|
447
|
+
function serializeEnvelope(version, payload) {
|
|
448
|
+
return JSON.stringify({
|
|
449
|
+
version,
|
|
450
|
+
payload
|
|
451
|
+
});
|
|
38
452
|
}
|
|
39
|
-
function
|
|
40
|
-
const
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
return globalWindow.localStorage;
|
|
44
|
-
} catch {
|
|
45
|
-
return void 0;
|
|
453
|
+
function withReadMetadata(value, rewriteRaw, extra) {
|
|
454
|
+
const result = { value };
|
|
455
|
+
if (extra !== void 0) {
|
|
456
|
+
Object.assign(result, extra);
|
|
46
457
|
}
|
|
458
|
+
if (rewriteRaw !== void 0) result.rewriteRaw = rewriteRaw;
|
|
459
|
+
return result;
|
|
47
460
|
}
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
return typeof storage.length === "number" && typeof storage.key === "function";
|
|
52
|
-
} catch {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
461
|
+
function isDevelopmentRuntime() {
|
|
462
|
+
return getRuntimeNodeEnv() === "development";
|
|
55
463
|
}
|
|
56
|
-
function
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
|
|
464
|
+
function getDiagnosticWarnings(api) {
|
|
465
|
+
let warnings = diagnosticWarningRegistry.get(api);
|
|
466
|
+
if (!warnings) {
|
|
467
|
+
warnings = /* @__PURE__ */ new Set();
|
|
468
|
+
diagnosticWarningRegistry.set(api, warnings);
|
|
60
469
|
}
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
function weakRefConstructor() {
|
|
64
|
-
const ctor = globalThis.WeakRef;
|
|
65
|
-
return typeof ctor === "function" ? ctor : null;
|
|
66
|
-
}
|
|
67
|
-
function hasFinalizationRegistry() {
|
|
68
|
-
return typeof globalThis.FinalizationRegistry === "function";
|
|
470
|
+
return warnings;
|
|
69
471
|
}
|
|
70
|
-
function
|
|
71
|
-
|
|
72
|
-
if (
|
|
73
|
-
|
|
472
|
+
function warnOnce(api, id, message) {
|
|
473
|
+
const warnings = getDiagnosticWarnings(api);
|
|
474
|
+
if (warnings.has(id)) return;
|
|
475
|
+
warnings.add(id);
|
|
476
|
+
console.warn(message);
|
|
74
477
|
}
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
478
|
+
function stableDiagnosticValue(value) {
|
|
479
|
+
if (typeof value === "function") {
|
|
480
|
+
const source = Function.prototype.toString.call(value).split(/\s+/).join(" ").trim();
|
|
481
|
+
const name = value.name || "anonymous";
|
|
482
|
+
return `[factory:${name}/${value.length}:${source}]`;
|
|
79
483
|
}
|
|
80
|
-
if (typeof
|
|
81
|
-
|
|
484
|
+
if (typeof value === "bigint") return `${value.toString()}n`;
|
|
485
|
+
if (typeof value === "symbol") return value.toString();
|
|
486
|
+
if (value === void 0) return "undefined";
|
|
487
|
+
try {
|
|
488
|
+
return JSON.stringify(value);
|
|
489
|
+
} catch {
|
|
490
|
+
const tag = Object.prototype.toString.call(value);
|
|
491
|
+
if (value !== null && (typeof value === "object" || typeof value === "function")) {
|
|
492
|
+
return `${tag}#${getDiagnosticObjectId(value)}`;
|
|
493
|
+
}
|
|
494
|
+
return tag;
|
|
82
495
|
}
|
|
83
|
-
return "none";
|
|
84
496
|
}
|
|
85
|
-
function
|
|
86
|
-
return
|
|
497
|
+
function isObjectLike(value) {
|
|
498
|
+
return value !== null && (typeof value === "object" || typeof value === "function");
|
|
87
499
|
}
|
|
88
|
-
function
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const descriptor = Object.getOwnPropertyDescriptor(root, key);
|
|
93
|
-
if (descriptor && !descriptor.configurable) continue;
|
|
94
|
-
try {
|
|
95
|
-
delete root[key];
|
|
96
|
-
} catch {
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
function ensureDevToolsRoot(enableDevTools) {
|
|
101
|
-
if (!enableDevTools) return null;
|
|
102
|
-
const globalWindow = getDevToolsWindow();
|
|
103
|
-
if (!globalWindow) return null;
|
|
104
|
-
const weakRefSupported = weakRefConstructor() !== null;
|
|
105
|
-
const finalizationRegistrySupported = hasFinalizationRegistry();
|
|
106
|
-
const existing = globalWindow.__REACT_MNEMONIC_DEVTOOLS__;
|
|
107
|
-
const root = existing && typeof existing === "object" ? existing : {};
|
|
108
|
-
sanitizeDevToolsRoot(root);
|
|
109
|
-
if (!root.providers || typeof root.providers !== "object") {
|
|
110
|
-
root.providers = {};
|
|
111
|
-
}
|
|
112
|
-
if (!root.capabilities || typeof root.capabilities !== "object") {
|
|
113
|
-
root.capabilities = {};
|
|
114
|
-
}
|
|
115
|
-
const capabilities = root.capabilities;
|
|
116
|
-
capabilities.weakRef = weakRefSupported;
|
|
117
|
-
capabilities.finalizationRegistry = finalizationRegistrySupported;
|
|
118
|
-
if (!root.__meta || typeof root.__meta !== "object") {
|
|
119
|
-
root.__meta = {
|
|
120
|
-
version: 0,
|
|
121
|
-
lastUpdated: Date.now(),
|
|
122
|
-
lastChange: ""
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
const meta = root.__meta;
|
|
126
|
-
if (typeof meta.version !== "number" || !Number.isFinite(meta.version)) {
|
|
127
|
-
meta.version = 0;
|
|
128
|
-
}
|
|
129
|
-
if (typeof meta.lastUpdated !== "number" || !Number.isFinite(meta.lastUpdated)) {
|
|
130
|
-
meta.lastUpdated = Date.now();
|
|
131
|
-
}
|
|
132
|
-
if (typeof meta.lastChange !== "string") {
|
|
133
|
-
meta.lastChange = "";
|
|
134
|
-
}
|
|
135
|
-
const providers = root.providers;
|
|
136
|
-
if (typeof root.resolve !== "function") {
|
|
137
|
-
root.resolve = (namespace) => {
|
|
138
|
-
const entry = providers[namespace];
|
|
139
|
-
if (!entry || typeof entry.weakRef?.deref !== "function") return null;
|
|
140
|
-
const live = entry.weakRef.deref();
|
|
141
|
-
if (live) {
|
|
142
|
-
entry.lastSeenAt = Date.now();
|
|
143
|
-
entry.staleSince = null;
|
|
144
|
-
return live;
|
|
145
|
-
}
|
|
146
|
-
entry.staleSince ?? (entry.staleSince = Date.now());
|
|
147
|
-
return null;
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
if (typeof root.list !== "function") {
|
|
151
|
-
root.list = () => Object.entries(providers).map(([namespace, entry]) => {
|
|
152
|
-
const live = typeof entry.weakRef?.deref === "function" ? entry.weakRef.deref() : void 0;
|
|
153
|
-
const available = Boolean(live);
|
|
154
|
-
if (available) {
|
|
155
|
-
entry.lastSeenAt = Date.now();
|
|
156
|
-
entry.staleSince = null;
|
|
157
|
-
} else {
|
|
158
|
-
entry.staleSince ?? (entry.staleSince = Date.now());
|
|
159
|
-
}
|
|
160
|
-
return {
|
|
161
|
-
namespace,
|
|
162
|
-
available,
|
|
163
|
-
registeredAt: entry.registeredAt,
|
|
164
|
-
lastSeenAt: entry.lastSeenAt,
|
|
165
|
-
staleSince: entry.staleSince
|
|
166
|
-
};
|
|
167
|
-
}).sort((left, right) => left.namespace.localeCompare(right.namespace));
|
|
168
|
-
}
|
|
169
|
-
globalWindow.__REACT_MNEMONIC_DEVTOOLS__ = root;
|
|
170
|
-
return root;
|
|
171
|
-
}
|
|
172
|
-
function bumpDevToolsVersion(root, namespace, reason) {
|
|
173
|
-
if (!root) return;
|
|
174
|
-
root.__meta.version += 1;
|
|
175
|
-
root.__meta.lastUpdated = Date.now();
|
|
176
|
-
root.__meta.lastChange = `${namespace}.${reason}`;
|
|
177
|
-
}
|
|
178
|
-
function decodeDevToolsValue(raw) {
|
|
179
|
-
try {
|
|
180
|
-
return JSON.parse(raw);
|
|
181
|
-
} catch {
|
|
182
|
-
return raw;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
function readStorageRaw(storage, storageKey, callbacks) {
|
|
186
|
-
if (!storage) return null;
|
|
187
|
-
try {
|
|
188
|
-
const raw = storage.getItem(storageKey);
|
|
189
|
-
if (isPromiseLike(raw)) {
|
|
190
|
-
callbacks.onAsyncViolation("getItem", raw);
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
callbacks.onAccessSuccess();
|
|
194
|
-
return raw;
|
|
195
|
-
} catch (error) {
|
|
196
|
-
callbacks.onAccessError(error);
|
|
197
|
-
return null;
|
|
500
|
+
function objectHasOwn2(value, property) {
|
|
501
|
+
const hasOwn = Object.hasOwn;
|
|
502
|
+
if (typeof hasOwn === "function") {
|
|
503
|
+
return hasOwn(value, property);
|
|
198
504
|
}
|
|
505
|
+
return Object.getOwnPropertyDescriptor(value, property) !== void 0;
|
|
199
506
|
}
|
|
200
|
-
function
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const storageLength = storage.length;
|
|
207
|
-
const getStorageKey = storage.key;
|
|
208
|
-
if (typeof storageLength !== "number" || typeof getStorageKey !== "function") {
|
|
209
|
-
return [];
|
|
210
|
-
}
|
|
211
|
-
for (let index = 0; index < storageLength; index++) {
|
|
212
|
-
const fullKey = getStorageKey.call(storage, index);
|
|
213
|
-
if (!fullKey?.startsWith(prefix)) continue;
|
|
214
|
-
keys.push(fullKey.slice(prefix.length));
|
|
215
|
-
}
|
|
216
|
-
callbacks.onAccessSuccess();
|
|
217
|
-
} catch (error) {
|
|
218
|
-
callbacks.onAccessError(error);
|
|
219
|
-
}
|
|
220
|
-
return keys;
|
|
507
|
+
function getDiagnosticObjectId(value) {
|
|
508
|
+
const existing = diagnosticObjectIds.get(value);
|
|
509
|
+
if (existing !== void 0) return existing;
|
|
510
|
+
const id = nextDiagnosticObjectId++;
|
|
511
|
+
diagnosticObjectIds.set(value, id);
|
|
512
|
+
return id;
|
|
221
513
|
}
|
|
222
|
-
function
|
|
514
|
+
function buildContractFingerprint({
|
|
515
|
+
api,
|
|
223
516
|
key,
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const fresh = readStorageRaw(storage, storageKey, callbacks);
|
|
231
|
-
const cached = cache.get(key) ?? null;
|
|
232
|
-
if (fresh === cached) {
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
|
-
cache.set(key, fresh);
|
|
236
|
-
emit(key);
|
|
237
|
-
return true;
|
|
238
|
-
}
|
|
239
|
-
function reloadNamedKeysFromStorage({
|
|
240
|
-
changedKeys,
|
|
241
|
-
prefix,
|
|
242
|
-
storage,
|
|
243
|
-
listeners,
|
|
244
|
-
cache,
|
|
245
|
-
emit,
|
|
246
|
-
callbacks
|
|
517
|
+
defaultValue,
|
|
518
|
+
codecOpt,
|
|
519
|
+
schemaVersion,
|
|
520
|
+
reconcile,
|
|
521
|
+
listenCrossTab,
|
|
522
|
+
ssrOptions
|
|
247
523
|
}) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}) || changed;
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
if (cache.has(key)) {
|
|
265
|
-
cache.delete(key);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
return changed;
|
|
524
|
+
const codecSignature = codecOpt == null || !isObjectLike(codecOpt) ? "default-json-codec" : `codec:${stableDiagnosticValue(codecOpt.encode)}:${stableDiagnosticValue(codecOpt.decode)}`;
|
|
525
|
+
const reconcileSignature = reconcile == null || !isObjectLike(reconcile) ? "no-reconcile" : `reconcile:${stableDiagnosticValue(reconcile)}`;
|
|
526
|
+
return JSON.stringify({
|
|
527
|
+
key,
|
|
528
|
+
defaultValue: stableDiagnosticValue(defaultValue),
|
|
529
|
+
codec: codecSignature,
|
|
530
|
+
schemaVersion: schemaVersion ?? null,
|
|
531
|
+
listenCrossTab: Boolean(listenCrossTab),
|
|
532
|
+
reconcile: reconcileSignature,
|
|
533
|
+
ssrHydration: ssrOptions?.hydration ?? null,
|
|
534
|
+
hasServerValue: ssrOptions?.serverValue !== void 0,
|
|
535
|
+
providerHydration: api.ssrHydration ?? null
|
|
536
|
+
});
|
|
269
537
|
}
|
|
270
|
-
function
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
listeners,
|
|
274
|
-
cache,
|
|
275
|
-
emit,
|
|
276
|
-
callbacks
|
|
277
|
-
}) {
|
|
278
|
-
let changed = false;
|
|
279
|
-
for (const [key, listenerSet] of listeners) {
|
|
280
|
-
if (listenerSet.size === 0) continue;
|
|
281
|
-
changed = syncCacheEntryFromStorage({
|
|
282
|
-
key,
|
|
283
|
-
storageKey: `${prefix}${key}`,
|
|
284
|
-
storage,
|
|
285
|
-
cache,
|
|
286
|
-
emit,
|
|
287
|
-
callbacks
|
|
288
|
-
}) || changed;
|
|
538
|
+
function resolveMnemonicKeyArgs(keyOrDescriptor, options) {
|
|
539
|
+
if (typeof keyOrDescriptor !== "string") {
|
|
540
|
+
return keyOrDescriptor;
|
|
289
541
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
if (listenerSet && listenerSet.size > 0) continue;
|
|
293
|
-
cache.delete(key);
|
|
542
|
+
if (!options) {
|
|
543
|
+
throw new Error("useMnemonicKey requires options when called with a string key");
|
|
294
544
|
}
|
|
295
|
-
return changed;
|
|
296
|
-
}
|
|
297
|
-
function createDevToolsProviderApi({
|
|
298
|
-
store,
|
|
299
|
-
dump,
|
|
300
|
-
keys,
|
|
301
|
-
readThrough,
|
|
302
|
-
writeRaw,
|
|
303
|
-
removeRaw
|
|
304
|
-
}) {
|
|
305
545
|
return {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
546
|
+
key: keyOrDescriptor,
|
|
547
|
+
options
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
function useMnemonicKeySharedFromApi(api, keyOrDescriptor, options, schemaVersion) {
|
|
551
|
+
const descriptor = resolveMnemonicKeyArgs(keyOrDescriptor, options);
|
|
552
|
+
const key = descriptor.key;
|
|
553
|
+
const resolvedOptions = descriptor.options;
|
|
554
|
+
const {
|
|
555
|
+
defaultValue,
|
|
556
|
+
onMount,
|
|
557
|
+
onChange,
|
|
558
|
+
listenCrossTab,
|
|
559
|
+
codec: codecOpt,
|
|
560
|
+
schema,
|
|
561
|
+
reconcile,
|
|
562
|
+
ssr: ssrOptions
|
|
563
|
+
} = resolvedOptions;
|
|
564
|
+
const codec = codecOpt ?? JSONCodec;
|
|
565
|
+
const hydrationMode = ssrOptions?.hydration ?? api.ssrHydration;
|
|
566
|
+
const [hasMounted, setHasMounted] = useState(hydrationMode !== "client-only");
|
|
567
|
+
const developmentRuntime = isDevelopmentRuntime();
|
|
568
|
+
const contractFingerprint = useMemo(
|
|
569
|
+
() => developmentRuntime ? buildContractFingerprint({
|
|
570
|
+
api,
|
|
571
|
+
key,
|
|
572
|
+
defaultValue,
|
|
573
|
+
codecOpt,
|
|
574
|
+
...{} ,
|
|
575
|
+
reconcile,
|
|
576
|
+
listenCrossTab,
|
|
577
|
+
ssrOptions
|
|
578
|
+
}) : null,
|
|
579
|
+
[
|
|
580
|
+
developmentRuntime,
|
|
581
|
+
api,
|
|
582
|
+
key,
|
|
583
|
+
defaultValue,
|
|
584
|
+
codecOpt,
|
|
585
|
+
schemaVersion,
|
|
586
|
+
reconcile,
|
|
587
|
+
listenCrossTab,
|
|
588
|
+
ssrOptions?.hydration,
|
|
589
|
+
ssrOptions?.serverValue
|
|
590
|
+
]
|
|
591
|
+
);
|
|
592
|
+
const getFallback = useCallback(
|
|
593
|
+
(error) => typeof defaultValue === "function" ? defaultValue(error) : defaultValue,
|
|
594
|
+
[defaultValue]
|
|
595
|
+
);
|
|
596
|
+
const getServerValue = useCallback(() => {
|
|
597
|
+
const serverValue = ssrOptions?.serverValue;
|
|
598
|
+
if (serverValue === void 0) {
|
|
599
|
+
return getFallback();
|
|
600
|
+
}
|
|
601
|
+
return typeof serverValue === "function" ? serverValue() : serverValue;
|
|
602
|
+
}, [getFallback, ssrOptions?.serverValue]);
|
|
603
|
+
const parseEnvelope2 = useCallback(
|
|
604
|
+
(rawText) => {
|
|
605
|
+
try {
|
|
606
|
+
const parsed = JSON.parse(rawText);
|
|
607
|
+
if (typeof parsed !== "object" || parsed == null || !Number.isInteger(parsed.version) || parsed.version < 0 || !objectHasOwn2(parsed, "payload")) {
|
|
608
|
+
return {
|
|
609
|
+
ok: false,
|
|
610
|
+
error: new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`)
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
return { ok: true, envelope: parsed };
|
|
614
|
+
} catch (err) {
|
|
615
|
+
return {
|
|
616
|
+
ok: false,
|
|
617
|
+
error: new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`, err)
|
|
618
|
+
};
|
|
619
|
+
}
|
|
325
620
|
},
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
621
|
+
[key]
|
|
622
|
+
);
|
|
623
|
+
const decodeStringPayload2 = useCallback(
|
|
624
|
+
(payload, activeCodec) => {
|
|
625
|
+
try {
|
|
626
|
+
return activeCodec.decode(payload);
|
|
627
|
+
} catch (err) {
|
|
628
|
+
throw err instanceof CodecError ? err : new CodecError(`Codec decode failed for key "${key}"`, err);
|
|
330
629
|
}
|
|
331
630
|
},
|
|
332
|
-
|
|
631
|
+
[key]
|
|
632
|
+
);
|
|
633
|
+
const buildFallbackResult2 = useCallback(
|
|
634
|
+
(error, extra) => {
|
|
635
|
+
return withReadMetadata(getFallback(error), void 0, extra);
|
|
636
|
+
},
|
|
637
|
+
[getFallback]
|
|
638
|
+
);
|
|
639
|
+
return {
|
|
640
|
+
api,
|
|
641
|
+
key,
|
|
642
|
+
codec,
|
|
643
|
+
codecOpt,
|
|
644
|
+
schema,
|
|
645
|
+
reconcile,
|
|
646
|
+
onMount,
|
|
647
|
+
onChange,
|
|
648
|
+
listenCrossTab,
|
|
649
|
+
getFallback,
|
|
650
|
+
getServerValue,
|
|
651
|
+
parseEnvelope: parseEnvelope2,
|
|
652
|
+
decodeStringPayload: decodeStringPayload2,
|
|
653
|
+
buildFallbackResult: buildFallbackResult2,
|
|
654
|
+
developmentRuntime,
|
|
655
|
+
contractFingerprint,
|
|
656
|
+
hasMounted,
|
|
657
|
+
setHasMounted,
|
|
658
|
+
hydrationMode,
|
|
659
|
+
ssrOptions
|
|
333
660
|
};
|
|
334
661
|
}
|
|
335
|
-
function
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
listeners,
|
|
340
|
-
cache,
|
|
341
|
-
emit,
|
|
342
|
-
callbacks,
|
|
343
|
-
devToolsRoot,
|
|
344
|
-
namespace
|
|
662
|
+
function useApplyReconcile({
|
|
663
|
+
key,
|
|
664
|
+
reconcile,
|
|
665
|
+
buildFallbackResult: buildFallbackResult2
|
|
345
666
|
}) {
|
|
346
|
-
return (
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
667
|
+
return useCallback(
|
|
668
|
+
({
|
|
669
|
+
value,
|
|
670
|
+
rewriteRaw,
|
|
671
|
+
extra,
|
|
672
|
+
persistedVersion,
|
|
673
|
+
latestVersion,
|
|
674
|
+
serializeForPersist,
|
|
675
|
+
deriveExtra
|
|
676
|
+
}) => {
|
|
677
|
+
if (!reconcile) {
|
|
678
|
+
return withReadMetadata(value, rewriteRaw, extra);
|
|
679
|
+
}
|
|
680
|
+
const context = {
|
|
681
|
+
key,
|
|
682
|
+
persistedVersion
|
|
683
|
+
};
|
|
684
|
+
if (latestVersion !== void 0) {
|
|
685
|
+
context.latestVersion = latestVersion;
|
|
686
|
+
}
|
|
687
|
+
const baselineSerialized = (() => {
|
|
688
|
+
try {
|
|
689
|
+
return serializeForPersist(value);
|
|
690
|
+
} catch {
|
|
691
|
+
return rewriteRaw;
|
|
692
|
+
}
|
|
693
|
+
})();
|
|
694
|
+
try {
|
|
695
|
+
const reconciled = reconcile(value, context);
|
|
696
|
+
const nextExtra = deriveExtra ? deriveExtra(reconciled, extra) : extra;
|
|
697
|
+
const nextSerialized = serializeForPersist(reconciled);
|
|
698
|
+
const nextRewriteRaw = baselineSerialized === void 0 || nextSerialized !== baselineSerialized ? nextSerialized : rewriteRaw;
|
|
699
|
+
return withReadMetadata(reconciled, nextRewriteRaw, nextExtra);
|
|
700
|
+
} catch (err) {
|
|
701
|
+
const typedErr = err instanceof SchemaError ? err : new SchemaError("RECONCILE_FAILED", `Reconciliation failed for key "${key}"`, err);
|
|
702
|
+
return buildFallbackResult2(typedErr, extra);
|
|
703
|
+
}
|
|
704
|
+
},
|
|
705
|
+
[buildFallbackResult2, key, reconcile]
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
function useMnemonicKeyState(shared, config) {
|
|
709
|
+
const {
|
|
710
|
+
api,
|
|
711
|
+
key,
|
|
712
|
+
codecOpt,
|
|
713
|
+
schema,
|
|
714
|
+
onMount,
|
|
715
|
+
onChange,
|
|
716
|
+
listenCrossTab,
|
|
717
|
+
getFallback,
|
|
718
|
+
getServerValue,
|
|
719
|
+
developmentRuntime,
|
|
720
|
+
contractFingerprint,
|
|
721
|
+
hasMounted,
|
|
722
|
+
setHasMounted,
|
|
723
|
+
hydrationMode,
|
|
724
|
+
ssrOptions
|
|
725
|
+
} = shared;
|
|
726
|
+
const { decodeForRead, encodeForWrite, active = true, additionalDevWarnings, onDecodedEffect } = config;
|
|
727
|
+
const getServerRawSnapshot = useCallback(
|
|
728
|
+
() => ssrOptions?.serverValue === void 0 ? null : SSR_SNAPSHOT_TOKEN,
|
|
729
|
+
[ssrOptions?.serverValue]
|
|
730
|
+
);
|
|
731
|
+
const deferStorageRead = hydrationMode === "client-only" && !hasMounted;
|
|
732
|
+
const subscribe = useCallback(
|
|
733
|
+
(listener) => {
|
|
734
|
+
if (!active) {
|
|
735
|
+
return () => void 0;
|
|
736
|
+
}
|
|
737
|
+
if (deferStorageRead) {
|
|
738
|
+
return () => void 0;
|
|
739
|
+
}
|
|
740
|
+
return api.subscribeRaw(key, listener);
|
|
741
|
+
},
|
|
742
|
+
[active, api, deferStorageRead, key]
|
|
743
|
+
);
|
|
744
|
+
const raw = useSyncExternalStore(
|
|
745
|
+
subscribe,
|
|
746
|
+
() => active && !deferStorageRead ? api.getRawSnapshot(key) : getServerRawSnapshot(),
|
|
747
|
+
getServerRawSnapshot
|
|
748
|
+
);
|
|
749
|
+
const decoded = useMemo(() => {
|
|
750
|
+
if (raw === SSR_SNAPSHOT_TOKEN) {
|
|
751
|
+
return withReadMetadata(getServerValue());
|
|
752
|
+
}
|
|
753
|
+
return decodeForRead(raw);
|
|
754
|
+
}, [decodeForRead, getServerValue, raw]);
|
|
755
|
+
const value = decoded.value;
|
|
756
|
+
useEffect(() => {
|
|
757
|
+
if (!active) return;
|
|
758
|
+
if (!developmentRuntime) return;
|
|
759
|
+
const globalWindow = globalThis.window;
|
|
760
|
+
if (listenCrossTab && (api.crossTabSyncMode ?? "none") === "none" && globalWindow !== void 0) {
|
|
761
|
+
warnOnce(
|
|
762
|
+
api,
|
|
763
|
+
`listenCrossTab:${key}`,
|
|
764
|
+
`[Mnemonic] useMnemonicKey("${key}") enabled listenCrossTab, but the active storage backend may not be able to notify external changes. If you're using a custom Storage-like wrapper around localStorage, ensure it forwards browser "storage" events or implements storage.onExternalChange(...); otherwise, use localStorage or implement storage.onExternalChange(...) on your custom backend.`
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
additionalDevWarnings?.({
|
|
768
|
+
api,
|
|
769
|
+
key,
|
|
770
|
+
listenCrossTab,
|
|
771
|
+
codecOpt,
|
|
772
|
+
schema,
|
|
773
|
+
warnOnce: (id, message) => warnOnce(api, id, message)
|
|
365
774
|
});
|
|
366
|
-
|
|
367
|
-
|
|
775
|
+
let keyContracts = diagnosticContractRegistry.get(api);
|
|
776
|
+
if (!keyContracts) {
|
|
777
|
+
keyContracts = /* @__PURE__ */ new Map();
|
|
778
|
+
diagnosticContractRegistry.set(api, keyContracts);
|
|
368
779
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
function registerDevToolsProvider({
|
|
372
|
-
devToolsRoot,
|
|
373
|
-
namespace,
|
|
374
|
-
store,
|
|
375
|
-
dump,
|
|
376
|
-
keys,
|
|
377
|
-
readThrough,
|
|
378
|
-
writeRaw,
|
|
379
|
-
removeRaw
|
|
380
|
-
}) {
|
|
381
|
-
let infoMessage = `[Mnemonic DevTools] Namespace "${namespace}" available via window.__REACT_MNEMONIC_DEVTOOLS__.resolve("${namespace}")`;
|
|
382
|
-
if (!devToolsRoot.capabilities.weakRef) {
|
|
383
|
-
console.info(
|
|
384
|
-
`[Mnemonic DevTools] WeakRef is not available; registry provider "${namespace}" was not registered.`
|
|
385
|
-
);
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
const existingLive = devToolsRoot.resolve(namespace);
|
|
389
|
-
if (existingLive) {
|
|
390
|
-
const duplicateMessage = `[Mnemonic DevTools] Duplicate provider namespace "${namespace}" detected. Each window must have at most one live MnemonicProvider per namespace.`;
|
|
391
|
-
if (!isProductionRuntime()) {
|
|
392
|
-
throw new Error(duplicateMessage);
|
|
780
|
+
if (contractFingerprint === null) {
|
|
781
|
+
return;
|
|
393
782
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
783
|
+
const previousContract = keyContracts.get(key);
|
|
784
|
+
if (previousContract === void 0) {
|
|
785
|
+
keyContracts.set(key, contractFingerprint);
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
if (previousContract === contractFingerprint) {
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
warnOnce(
|
|
792
|
+
api,
|
|
793
|
+
`contract-conflict:${key}`,
|
|
794
|
+
`[Mnemonic] Conflicting useMnemonicKey contracts detected for key "${key}" in namespace "${api.prefix.slice(0, -1)}". Reuse a shared descriptor with defineMnemonicKey(...) or align defaultValue/codec/schema/reconcile options so every consumer describes the same persisted contract.`
|
|
397
795
|
);
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
return;
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
const
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
let accessErrorLogged = false;
|
|
451
|
-
let asyncContractViolationDetected = false;
|
|
452
|
-
const storageAccessCallbacks = {
|
|
453
|
-
onAccessError: (err) => logAccessError(err),
|
|
454
|
-
onAccessSuccess: () => {
|
|
455
|
-
accessErrorLogged = false;
|
|
456
|
-
},
|
|
457
|
-
onAsyncViolation: (method, thenable) => handleAsyncStorageContractViolation(method, thenable)
|
|
458
|
-
};
|
|
459
|
-
const fullKey = (key) => prefix + key;
|
|
460
|
-
const emit = (key) => {
|
|
461
|
-
const set = listeners.get(key);
|
|
462
|
-
if (!set) return;
|
|
463
|
-
for (const fn of set) fn();
|
|
464
|
-
};
|
|
465
|
-
const logAccessError = (err) => {
|
|
466
|
-
if (!accessErrorLogged && err instanceof DOMException && err.name !== "QuotaExceededError") {
|
|
467
|
-
console.error(
|
|
468
|
-
`[Mnemonic] Storage access error (${err.name}): ${err.message}. Data is cached in memory but may not persist.`
|
|
469
|
-
);
|
|
470
|
-
accessErrorLogged = true;
|
|
796
|
+
}, [
|
|
797
|
+
active,
|
|
798
|
+
additionalDevWarnings,
|
|
799
|
+
api,
|
|
800
|
+
key,
|
|
801
|
+
developmentRuntime,
|
|
802
|
+
contractFingerprint,
|
|
803
|
+
listenCrossTab,
|
|
804
|
+
codecOpt,
|
|
805
|
+
schema,
|
|
806
|
+
api.crossTabSyncMode
|
|
807
|
+
]);
|
|
808
|
+
useEffect(() => {
|
|
809
|
+
if (hasMounted) return;
|
|
810
|
+
setHasMounted(true);
|
|
811
|
+
}, [hasMounted, setHasMounted]);
|
|
812
|
+
useEffect(() => {
|
|
813
|
+
if (!active) return;
|
|
814
|
+
if (decoded.rewriteRaw && decoded.rewriteRaw !== raw) {
|
|
815
|
+
api.setRaw(key, decoded.rewriteRaw);
|
|
816
|
+
}
|
|
817
|
+
}, [active, api, decoded.rewriteRaw, key, raw]);
|
|
818
|
+
useEffect(() => {
|
|
819
|
+
if (!active) return;
|
|
820
|
+
onDecodedEffect?.(decoded);
|
|
821
|
+
}, [active, decoded, onDecodedEffect]);
|
|
822
|
+
const prevRef = useRef(value);
|
|
823
|
+
const mounted = useRef(false);
|
|
824
|
+
useEffect(() => {
|
|
825
|
+
if (!active) return;
|
|
826
|
+
if (mounted.current) return;
|
|
827
|
+
mounted.current = true;
|
|
828
|
+
onMount?.(value);
|
|
829
|
+
prevRef.current = value;
|
|
830
|
+
}, [active]);
|
|
831
|
+
useEffect(() => {
|
|
832
|
+
if (!active) return;
|
|
833
|
+
const prev = prevRef.current;
|
|
834
|
+
if (Object.is(prev, value)) return;
|
|
835
|
+
prevRef.current = value;
|
|
836
|
+
onChange?.(value, prev);
|
|
837
|
+
}, [active, value, onChange]);
|
|
838
|
+
useEffect(() => {
|
|
839
|
+
if (!active) return;
|
|
840
|
+
if (!listenCrossTab) return;
|
|
841
|
+
const globalWindow = globalThis.window;
|
|
842
|
+
if (globalWindow === void 0) return;
|
|
843
|
+
const storageKey = api.prefix + key;
|
|
844
|
+
const handler = (e) => {
|
|
845
|
+
if (e.key === null) {
|
|
846
|
+
api.removeRaw(key);
|
|
847
|
+
return;
|
|
471
848
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
if (accessErrorLogged) return;
|
|
477
|
-
console.error(
|
|
478
|
-
`[Mnemonic] StorageLike.${method} returned a Promise. StorageLike must remain synchronous for react-mnemonic v1. Wrap async persistence behind a synchronous cache facade instead.`
|
|
479
|
-
);
|
|
480
|
-
accessErrorLogged = true;
|
|
481
|
-
};
|
|
482
|
-
const readThrough = (key) => {
|
|
483
|
-
if (cache.has(key)) return cache.get(key) ?? null;
|
|
484
|
-
if (!st || asyncContractViolationDetected) {
|
|
485
|
-
cache.set(key, null);
|
|
486
|
-
return null;
|
|
849
|
+
if (e.key !== storageKey) return;
|
|
850
|
+
if (e.newValue == null) {
|
|
851
|
+
api.removeRaw(key);
|
|
852
|
+
return;
|
|
487
853
|
}
|
|
488
|
-
|
|
489
|
-
cache.set(key, raw);
|
|
490
|
-
return raw;
|
|
854
|
+
api.setRaw(key, e.newValue);
|
|
491
855
|
};
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
quotaErrorLogged = true;
|
|
509
|
-
}
|
|
510
|
-
logAccessError(err);
|
|
856
|
+
globalWindow.addEventListener("storage", handler);
|
|
857
|
+
return () => globalWindow.removeEventListener("storage", handler);
|
|
858
|
+
}, [active, listenCrossTab, api, key]);
|
|
859
|
+
const set = useMemo(() => {
|
|
860
|
+
if (!active) {
|
|
861
|
+
return () => void 0;
|
|
862
|
+
}
|
|
863
|
+
return (next) => {
|
|
864
|
+
const nextVal = typeof next === "function" ? next(decodeForRead(api.getRawSnapshot(key)).value) : next;
|
|
865
|
+
try {
|
|
866
|
+
const encoded = encodeForWrite(nextVal);
|
|
867
|
+
api.setRaw(key, encoded);
|
|
868
|
+
} catch (err) {
|
|
869
|
+
if (err instanceof SchemaError) {
|
|
870
|
+
console.error(`[Mnemonic] Schema error for key "${key}" (${err.code}):`, err.message);
|
|
871
|
+
return;
|
|
511
872
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
};
|
|
516
|
-
const removeRaw = (key) => {
|
|
517
|
-
cache.set(key, null);
|
|
518
|
-
if (st && !asyncContractViolationDetected) {
|
|
519
|
-
try {
|
|
520
|
-
const result = st.removeItem(fullKey(key));
|
|
521
|
-
if (isPromiseLike(result)) {
|
|
522
|
-
handleAsyncStorageContractViolation("removeItem", result);
|
|
523
|
-
} else {
|
|
524
|
-
accessErrorLogged = false;
|
|
525
|
-
}
|
|
526
|
-
} catch (err) {
|
|
527
|
-
logAccessError(err);
|
|
873
|
+
if (err instanceof CodecError) {
|
|
874
|
+
console.error(`[Mnemonic] Codec encode error for key "${key}":`, err.message);
|
|
875
|
+
return;
|
|
528
876
|
}
|
|
877
|
+
console.error(`[Mnemonic] Failed to persist key "${key}":`, err);
|
|
529
878
|
}
|
|
530
|
-
emit(key);
|
|
531
|
-
bumpDevToolsVersion(devToolsRoot, namespace, `remove:${key}`);
|
|
532
|
-
};
|
|
533
|
-
const subscribeRaw = (key, listener) => {
|
|
534
|
-
let set = listeners.get(key);
|
|
535
|
-
if (!set) {
|
|
536
|
-
set = /* @__PURE__ */ new Set();
|
|
537
|
-
listeners.set(key, set);
|
|
538
|
-
}
|
|
539
|
-
set.add(listener);
|
|
540
|
-
readThrough(key);
|
|
541
|
-
return () => {
|
|
542
|
-
const s = listeners.get(key);
|
|
543
|
-
if (!s) return;
|
|
544
|
-
s.delete(listener);
|
|
545
|
-
if (s.size === 0) listeners.delete(key);
|
|
546
|
-
};
|
|
547
|
-
};
|
|
548
|
-
const getRawSnapshot = (key) => readThrough(key);
|
|
549
|
-
const keys = () => {
|
|
550
|
-
if (asyncContractViolationDetected) {
|
|
551
|
-
return Array.from(cache.entries()).filter(([, value]) => value != null).map(([key]) => key);
|
|
552
|
-
}
|
|
553
|
-
if (!canEnumerateKeys) return [];
|
|
554
|
-
return enumerateNamespaceKeys(st, prefix, storageAccessCallbacks);
|
|
555
879
|
};
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
880
|
+
}, [active, api, key, decodeForRead, encodeForWrite]);
|
|
881
|
+
const reset = useMemo(() => {
|
|
882
|
+
if (!active) {
|
|
883
|
+
return () => void 0;
|
|
884
|
+
}
|
|
885
|
+
return () => {
|
|
886
|
+
const v = getFallback();
|
|
887
|
+
try {
|
|
888
|
+
const encoded = encodeForWrite(v);
|
|
889
|
+
api.setRaw(key, encoded);
|
|
890
|
+
} catch (err) {
|
|
891
|
+
if (err instanceof SchemaError) {
|
|
892
|
+
console.error(`[Mnemonic] Schema error for key "${key}" (${err.code}):`, err.message);
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
if (err instanceof CodecError) {
|
|
896
|
+
console.error(`[Mnemonic] Codec encode error for key "${key}":`, err.message);
|
|
897
|
+
}
|
|
898
|
+
return;
|
|
561
899
|
}
|
|
562
|
-
return out;
|
|
563
|
-
};
|
|
564
|
-
const reloadFromStorage = createReloadFromStorage({
|
|
565
|
-
storage: st,
|
|
566
|
-
hasAsyncContractViolation: () => asyncContractViolationDetected,
|
|
567
|
-
prefix,
|
|
568
|
-
listeners,
|
|
569
|
-
cache,
|
|
570
|
-
emit,
|
|
571
|
-
callbacks: storageAccessCallbacks,
|
|
572
|
-
devToolsRoot,
|
|
573
|
-
namespace
|
|
574
|
-
});
|
|
575
|
-
const store2 = {
|
|
576
|
-
prefix,
|
|
577
|
-
canEnumerateKeys,
|
|
578
|
-
subscribeRaw,
|
|
579
|
-
getRawSnapshot,
|
|
580
|
-
setRaw: writeRaw,
|
|
581
|
-
removeRaw,
|
|
582
|
-
keys,
|
|
583
|
-
dump,
|
|
584
|
-
reloadFromStorage,
|
|
585
|
-
schemaMode,
|
|
586
|
-
ssrHydration,
|
|
587
|
-
crossTabSyncMode,
|
|
588
|
-
...schemaRegistry ? { schemaRegistry } : {}
|
|
589
900
|
};
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
store: store2,
|
|
595
|
-
dump,
|
|
596
|
-
keys,
|
|
597
|
-
readThrough,
|
|
598
|
-
writeRaw,
|
|
599
|
-
removeRaw
|
|
600
|
-
});
|
|
901
|
+
}, [active, api, key, getFallback, encodeForWrite]);
|
|
902
|
+
const remove = useMemo(() => {
|
|
903
|
+
if (!active) {
|
|
904
|
+
return () => void 0;
|
|
601
905
|
}
|
|
602
|
-
return
|
|
603
|
-
}, [
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
`[Mnemonic] MnemonicProvider from react-mnemonic/core does not support ${propName}. Import MnemonicProvider from "react-mnemonic/schema" or "react-mnemonic" for schema validation, autoschema, and migration support.`
|
|
906
|
+
return () => api.removeRaw(key);
|
|
907
|
+
}, [active, api, key]);
|
|
908
|
+
return useMemo(
|
|
909
|
+
() => ({
|
|
910
|
+
value,
|
|
911
|
+
set,
|
|
912
|
+
reset,
|
|
913
|
+
remove
|
|
914
|
+
}),
|
|
915
|
+
[value, set, reset, remove]
|
|
613
916
|
);
|
|
614
917
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
918
|
+
|
|
919
|
+
// src/Mnemonic/optional-bridge-adapter.ts
|
|
920
|
+
function resolveOptionalDefaultValue(defaultValue) {
|
|
921
|
+
return typeof defaultValue === "function" ? defaultValue() : defaultValue;
|
|
922
|
+
}
|
|
923
|
+
function objectHasOwn3(value, property) {
|
|
924
|
+
const hasOwn = Object.hasOwn;
|
|
925
|
+
if (typeof hasOwn === "function") {
|
|
926
|
+
return hasOwn(value, property);
|
|
927
|
+
}
|
|
928
|
+
return Object.getOwnPropertyDescriptor(value, property) !== void 0;
|
|
929
|
+
}
|
|
930
|
+
function parseEnvelope(key, rawText) {
|
|
931
|
+
try {
|
|
932
|
+
const parsed = JSON.parse(rawText);
|
|
933
|
+
if (typeof parsed !== "object" || parsed == null || !Number.isInteger(parsed.version) || parsed.version < 0 || !objectHasOwn3(parsed, "payload")) {
|
|
934
|
+
throw new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`);
|
|
935
|
+
}
|
|
936
|
+
return parsed;
|
|
937
|
+
} catch (error) {
|
|
938
|
+
if (error instanceof SchemaError) {
|
|
939
|
+
throw error;
|
|
940
|
+
}
|
|
941
|
+
throw new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`, error);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
function decodeStringPayload(key, payload, options) {
|
|
945
|
+
const codec = options.codec ?? JSONCodec;
|
|
946
|
+
try {
|
|
947
|
+
return codec.decode(payload);
|
|
948
|
+
} catch (error) {
|
|
949
|
+
throw error instanceof CodecError ? error : new CodecError(`Codec decode failed for key "${key}"`, error);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
function validateAgainstSchema(key, value, jsonSchema) {
|
|
953
|
+
const errors = validateJsonSchema(value, jsonSchema);
|
|
954
|
+
if (errors.length === 0) {
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
const message = errors.map((entry) => `${entry.path || "/"}: ${entry.message}`).join("; ");
|
|
958
|
+
throw new SchemaError("TYPE_MISMATCH", `Schema validation failed for key "${key}": ${message}`);
|
|
959
|
+
}
|
|
960
|
+
function getSchemaCapabilities(schemaRegistry) {
|
|
961
|
+
return schemaRegistry !== void 0;
|
|
962
|
+
}
|
|
963
|
+
function buildFallbackResult(options) {
|
|
964
|
+
return {
|
|
965
|
+
value: resolveOptionalDefaultValue(options.defaultValue)
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
function getLatestSchema(schemaRegistry, key) {
|
|
969
|
+
return schemaRegistry?.getLatestSchema(key);
|
|
970
|
+
}
|
|
971
|
+
function getSchemaForVersion(schemaRegistry, key, version) {
|
|
972
|
+
return schemaRegistry?.getSchema(key, version);
|
|
973
|
+
}
|
|
974
|
+
function getMigrationPath(schemaRegistry, key, fromVersion, toVersion) {
|
|
975
|
+
return schemaRegistry?.getMigrationPath(key, fromVersion, toVersion) ?? null;
|
|
976
|
+
}
|
|
977
|
+
function encodeValueForWrite(key, nextValue, options, schemaRegistry) {
|
|
978
|
+
const explicitVersion = options.schema?.version;
|
|
979
|
+
const latestSchema = getLatestSchema(schemaRegistry, key);
|
|
980
|
+
const targetSchema = explicitVersion === void 0 ? latestSchema : getSchemaForVersion(schemaRegistry, key, explicitVersion) ?? latestSchema;
|
|
981
|
+
if (!targetSchema) {
|
|
982
|
+
const codec = options.codec ?? JSONCodec;
|
|
983
|
+
return serializeEnvelope(0, codec.encode(nextValue));
|
|
984
|
+
}
|
|
985
|
+
let valueToStore = nextValue;
|
|
986
|
+
const writeMigration = schemaRegistry?.getWriteMigration?.(key, targetSchema.version);
|
|
987
|
+
if (writeMigration) {
|
|
988
|
+
try {
|
|
989
|
+
valueToStore = writeMigration.migrate(valueToStore);
|
|
990
|
+
} catch (error) {
|
|
991
|
+
throw error instanceof SchemaError ? error : new SchemaError("MIGRATION_FAILED", `Write-time migration failed for key "${key}"`, error);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
validateAgainstSchema(key, valueToStore, targetSchema.schema);
|
|
995
|
+
return serializeEnvelope(targetSchema.version, valueToStore);
|
|
996
|
+
}
|
|
997
|
+
function decodeCodecManagedEnvelope(key, envelope, options) {
|
|
998
|
+
if (typeof envelope.payload !== "string") {
|
|
999
|
+
return {
|
|
1000
|
+
value: envelope.payload
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
return {
|
|
1004
|
+
value: decodeStringPayload(key, envelope.payload, options)
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
function decodeAutoschemaEnvelope(key, envelope, options, schemaRegistry) {
|
|
1008
|
+
if (!schemaRegistry?.registerSchema) {
|
|
1009
|
+
throw new SchemaError(
|
|
1010
|
+
"MODE_CONFIGURATION_INVALID",
|
|
1011
|
+
`Autoschema mode requires schema registry registration for key "${key}"`
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
const decoded = typeof envelope.payload === "string" ? decodeStringPayload(key, envelope.payload, options) : envelope.payload;
|
|
1015
|
+
const pendingSchema = {
|
|
1016
|
+
key,
|
|
1017
|
+
version: 1,
|
|
1018
|
+
schema: inferJsonSchema(decoded)
|
|
1019
|
+
};
|
|
1020
|
+
return {
|
|
1021
|
+
value: decoded,
|
|
1022
|
+
rewriteRaw: serializeEnvelope(pendingSchema.version, decoded),
|
|
1023
|
+
pendingSchema
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
function decodeSchemaManagedEnvelope(key, envelope, schemaForVersion, latestSchema, schemaRegistry) {
|
|
1027
|
+
let current = envelope.payload;
|
|
1028
|
+
validateAgainstSchema(key, current, schemaForVersion.schema);
|
|
1029
|
+
if (!latestSchema || envelope.version >= latestSchema.version) {
|
|
1030
|
+
return {
|
|
1031
|
+
value: current
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
const path = getMigrationPath(schemaRegistry, key, envelope.version, latestSchema.version);
|
|
1035
|
+
if (!path) {
|
|
1036
|
+
throw new SchemaError(
|
|
1037
|
+
"MIGRATION_PATH_NOT_FOUND",
|
|
1038
|
+
`No migration path for key "${key}" from v${envelope.version} to v${latestSchema.version}`
|
|
1039
|
+
);
|
|
1040
|
+
}
|
|
1041
|
+
for (const step of path) {
|
|
1042
|
+
current = step.migrate(current);
|
|
1043
|
+
}
|
|
1044
|
+
validateAgainstSchema(key, current, latestSchema.schema);
|
|
1045
|
+
return {
|
|
1046
|
+
value: current,
|
|
1047
|
+
rewriteRaw: serializeEnvelope(latestSchema.version, current)
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
function decodePersistedValue(key, raw, options, api, schemaRegistry) {
|
|
1051
|
+
if (raw == null) {
|
|
1052
|
+
return buildFallbackResult(options);
|
|
618
1053
|
}
|
|
619
|
-
|
|
620
|
-
|
|
1054
|
+
const envelope = parseEnvelope(key, raw);
|
|
1055
|
+
const latestSchema = getLatestSchema(schemaRegistry, key);
|
|
1056
|
+
const schemaForVersion = getSchemaForVersion(schemaRegistry, key, envelope.version);
|
|
1057
|
+
if (api.schemaMode === "strict" && !schemaForVersion) {
|
|
1058
|
+
throw new SchemaError("SCHEMA_NOT_FOUND", `No schema for key "${key}" v${envelope.version}`);
|
|
1059
|
+
}
|
|
1060
|
+
if (api.schemaMode === "autoschema" && !schemaForVersion) {
|
|
1061
|
+
return decodeAutoschemaEnvelope(key, envelope, options, schemaRegistry);
|
|
1062
|
+
}
|
|
1063
|
+
if (!schemaForVersion) {
|
|
1064
|
+
return decodeCodecManagedEnvelope(key, envelope, options);
|
|
621
1065
|
}
|
|
1066
|
+
return decodeSchemaManagedEnvelope(key, envelope, schemaForVersion, latestSchema, schemaRegistry);
|
|
622
1067
|
}
|
|
623
|
-
function
|
|
624
|
-
|
|
625
|
-
|
|
1068
|
+
function createMnemonicOptionalBridge({
|
|
1069
|
+
api,
|
|
1070
|
+
schemaRegistry
|
|
1071
|
+
}) {
|
|
1072
|
+
return {
|
|
1073
|
+
namespace: api.prefix.endsWith(".") ? api.prefix.slice(0, -1) : api.prefix,
|
|
1074
|
+
capabilities: {
|
|
1075
|
+
persistence: true,
|
|
1076
|
+
schema: getSchemaCapabilities(schemaRegistry)
|
|
1077
|
+
},
|
|
1078
|
+
subscribeRaw: (key, listener) => api.subscribeRaw(key, listener),
|
|
1079
|
+
getRawSnapshot: (key) => api.getRawSnapshot(key),
|
|
1080
|
+
decodeSnapshot: (key, raw, options) => {
|
|
1081
|
+
try {
|
|
1082
|
+
return decodePersistedValue(key, raw, options, api, schemaRegistry);
|
|
1083
|
+
} catch {
|
|
1084
|
+
return buildFallbackResult(options);
|
|
1085
|
+
}
|
|
1086
|
+
},
|
|
1087
|
+
setValue: (key, nextValue, options) => {
|
|
1088
|
+
try {
|
|
1089
|
+
api.setRaw(key, encodeValueForWrite(key, nextValue, options, schemaRegistry));
|
|
1090
|
+
} catch (error) {
|
|
1091
|
+
if (error instanceof SchemaError) {
|
|
1092
|
+
console.error(`[Mnemonic] Schema error for key "${key}" (${error.code}):`, error.message);
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
if (error instanceof CodecError) {
|
|
1096
|
+
console.error(`[Mnemonic] Codec error for key "${key}":`, error.message);
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
throw error;
|
|
1100
|
+
}
|
|
1101
|
+
},
|
|
1102
|
+
removeValue: (key) => {
|
|
1103
|
+
api.removeRaw(key);
|
|
1104
|
+
},
|
|
1105
|
+
commitSnapshot: (key, raw, snapshot) => {
|
|
1106
|
+
if (snapshot.pendingSchema && schemaRegistry?.registerSchema) {
|
|
1107
|
+
if (!schemaRegistry.getSchema(snapshot.pendingSchema.key, snapshot.pendingSchema.version)) {
|
|
1108
|
+
try {
|
|
1109
|
+
schemaRegistry.registerSchema(snapshot.pendingSchema);
|
|
1110
|
+
} catch {
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
if (snapshot.rewriteRaw !== void 0 && snapshot.rewriteRaw !== raw) {
|
|
1115
|
+
api.setRaw(key, snapshot.rewriteRaw);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
626
1119
|
}
|
|
1120
|
+
var MnemonicOptionalBridgeContext = createContext(null);
|
|
627
1121
|
|
|
628
|
-
// src/Mnemonic/
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
1122
|
+
// src/Mnemonic/optional-bridge-provider.tsx
|
|
1123
|
+
function MnemonicOptionalBridgeProvider({
|
|
1124
|
+
bridge,
|
|
1125
|
+
children
|
|
1126
|
+
}) {
|
|
1127
|
+
return createElement(MnemonicOptionalBridgeContext.Provider, { value: bridge }, children);
|
|
1128
|
+
}
|
|
1129
|
+
var MnemonicContext = createContext(null);
|
|
1130
|
+
function useMnemonic() {
|
|
1131
|
+
const context = useMnemonicOptional();
|
|
1132
|
+
if (!context) {
|
|
1133
|
+
throw new Error("useMnemonic must be used within a MnemonicProvider");
|
|
641
1134
|
}
|
|
642
|
-
|
|
643
|
-
var JSONCodec = {
|
|
644
|
-
encode: (value) => JSON.stringify(value),
|
|
645
|
-
decode: (encoded) => JSON.parse(encoded)
|
|
646
|
-
};
|
|
647
|
-
function createCodec(encode, decode) {
|
|
648
|
-
return { encode, decode };
|
|
1135
|
+
return context;
|
|
649
1136
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
constructor(code, message, cause) {
|
|
661
|
-
super(message);
|
|
662
|
-
this.name = "SchemaError";
|
|
663
|
-
this.code = code;
|
|
664
|
-
this.cause = cause;
|
|
665
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
1137
|
+
function useMnemonicOptional() {
|
|
1138
|
+
return useContext(MnemonicContext);
|
|
1139
|
+
}
|
|
1140
|
+
function defaultBrowserStorage() {
|
|
1141
|
+
const globalWindow = globalThis.window;
|
|
1142
|
+
if (globalWindow === void 0) return void 0;
|
|
1143
|
+
try {
|
|
1144
|
+
return globalWindow.localStorage;
|
|
1145
|
+
} catch {
|
|
1146
|
+
return void 0;
|
|
666
1147
|
}
|
|
667
|
-
};
|
|
668
|
-
|
|
669
|
-
// src/Mnemonic/use-shared.ts
|
|
670
|
-
var SSR_SNAPSHOT_TOKEN = /* @__PURE__ */ Symbol("mnemonic:ssr-snapshot");
|
|
671
|
-
var diagnosticContractRegistry = /* @__PURE__ */ new WeakMap();
|
|
672
|
-
var diagnosticWarningRegistry = /* @__PURE__ */ new WeakMap();
|
|
673
|
-
var diagnosticObjectIds = /* @__PURE__ */ new WeakMap();
|
|
674
|
-
var nextDiagnosticObjectId = 1;
|
|
675
|
-
function serializeEnvelope(version, payload) {
|
|
676
|
-
return JSON.stringify({
|
|
677
|
-
version,
|
|
678
|
-
payload
|
|
679
|
-
});
|
|
680
1148
|
}
|
|
681
|
-
function
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
1149
|
+
function detectEnumerableStorage(storage) {
|
|
1150
|
+
if (!storage) return false;
|
|
1151
|
+
try {
|
|
1152
|
+
return typeof storage.length === "number" && typeof storage.key === "function";
|
|
1153
|
+
} catch {
|
|
1154
|
+
return false;
|
|
685
1155
|
}
|
|
686
|
-
if (rewriteRaw !== void 0) result.rewriteRaw = rewriteRaw;
|
|
687
|
-
return result;
|
|
688
1156
|
}
|
|
689
|
-
function
|
|
690
|
-
|
|
1157
|
+
function isProductionRuntime() {
|
|
1158
|
+
const env = getRuntimeNodeEnv();
|
|
1159
|
+
if (env === void 0) {
|
|
1160
|
+
return true;
|
|
1161
|
+
}
|
|
1162
|
+
return env === "production";
|
|
691
1163
|
}
|
|
692
|
-
function
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
1164
|
+
function weakRefConstructor() {
|
|
1165
|
+
const ctor = globalThis.WeakRef;
|
|
1166
|
+
return typeof ctor === "function" ? ctor : null;
|
|
1167
|
+
}
|
|
1168
|
+
function hasFinalizationRegistry() {
|
|
1169
|
+
return typeof globalThis.FinalizationRegistry === "function";
|
|
1170
|
+
}
|
|
1171
|
+
function isPromiseLike(value) {
|
|
1172
|
+
if (value == null) return false;
|
|
1173
|
+
if (typeof value !== "object" && typeof value !== "function") return false;
|
|
1174
|
+
return typeof value.then === "function";
|
|
1175
|
+
}
|
|
1176
|
+
function getCrossTabSyncMode(requestedStorage, activeStorage) {
|
|
1177
|
+
const isExplicitNativeBrowserStorage = activeStorage !== void 0 && requestedStorage !== void 0 && getNativeBrowserStorages().includes(activeStorage);
|
|
1178
|
+
if (requestedStorage === void 0 && activeStorage !== void 0 || isExplicitNativeBrowserStorage) {
|
|
1179
|
+
return "browser-storage-event";
|
|
697
1180
|
}
|
|
698
|
-
|
|
1181
|
+
if (typeof activeStorage?.onExternalChange === "function") {
|
|
1182
|
+
return "custom-external-change";
|
|
1183
|
+
}
|
|
1184
|
+
return "none";
|
|
699
1185
|
}
|
|
700
|
-
function
|
|
701
|
-
|
|
702
|
-
if (warnings.has(id)) return;
|
|
703
|
-
warnings.add(id);
|
|
704
|
-
console.warn(message);
|
|
1186
|
+
function getDevToolsWindow() {
|
|
1187
|
+
return globalThis.window;
|
|
705
1188
|
}
|
|
706
|
-
function
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
1189
|
+
function sanitizeDevToolsRoot(root) {
|
|
1190
|
+
const reserved = /* @__PURE__ */ new Set(["providers", "resolve", "list", "capabilities", "__meta"]);
|
|
1191
|
+
for (const key of Object.keys(root)) {
|
|
1192
|
+
if (reserved.has(key)) continue;
|
|
1193
|
+
const descriptor = Object.getOwnPropertyDescriptor(root, key);
|
|
1194
|
+
if (descriptor && !descriptor.configurable) continue;
|
|
1195
|
+
try {
|
|
1196
|
+
delete root[key];
|
|
1197
|
+
} catch {
|
|
1198
|
+
}
|
|
711
1199
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
if (
|
|
1200
|
+
}
|
|
1201
|
+
function ensureDevToolsRoot(enableDevTools) {
|
|
1202
|
+
if (!enableDevTools) return null;
|
|
1203
|
+
const globalWindow = getDevToolsWindow();
|
|
1204
|
+
if (!globalWindow) return null;
|
|
1205
|
+
const weakRefSupported = weakRefConstructor() !== null;
|
|
1206
|
+
const finalizationRegistrySupported = hasFinalizationRegistry();
|
|
1207
|
+
const existing = globalWindow.__REACT_MNEMONIC_DEVTOOLS__;
|
|
1208
|
+
const root = existing && typeof existing === "object" ? existing : {};
|
|
1209
|
+
sanitizeDevToolsRoot(root);
|
|
1210
|
+
if (!root.providers || typeof root.providers !== "object") {
|
|
1211
|
+
root.providers = {};
|
|
1212
|
+
}
|
|
1213
|
+
if (!root.capabilities || typeof root.capabilities !== "object") {
|
|
1214
|
+
root.capabilities = {};
|
|
1215
|
+
}
|
|
1216
|
+
const capabilities = root.capabilities;
|
|
1217
|
+
capabilities.weakRef = weakRefSupported;
|
|
1218
|
+
capabilities.finalizationRegistry = finalizationRegistrySupported;
|
|
1219
|
+
if (!root.__meta || typeof root.__meta !== "object") {
|
|
1220
|
+
root.__meta = {
|
|
1221
|
+
version: 0,
|
|
1222
|
+
lastUpdated: Date.now(),
|
|
1223
|
+
lastChange: ""
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
const meta = root.__meta;
|
|
1227
|
+
if (typeof meta.version !== "number" || !Number.isFinite(meta.version)) {
|
|
1228
|
+
meta.version = 0;
|
|
1229
|
+
}
|
|
1230
|
+
if (typeof meta.lastUpdated !== "number" || !Number.isFinite(meta.lastUpdated)) {
|
|
1231
|
+
meta.lastUpdated = Date.now();
|
|
1232
|
+
}
|
|
1233
|
+
if (typeof meta.lastChange !== "string") {
|
|
1234
|
+
meta.lastChange = "";
|
|
1235
|
+
}
|
|
1236
|
+
const providers = root.providers;
|
|
1237
|
+
if (typeof root.resolve !== "function") {
|
|
1238
|
+
root.resolve = (namespace) => {
|
|
1239
|
+
const entry = providers[namespace];
|
|
1240
|
+
if (!entry || typeof entry.weakRef?.deref !== "function") return null;
|
|
1241
|
+
const live = entry.weakRef.deref();
|
|
1242
|
+
if (live) {
|
|
1243
|
+
entry.lastSeenAt = Date.now();
|
|
1244
|
+
entry.staleSince = null;
|
|
1245
|
+
return live;
|
|
1246
|
+
}
|
|
1247
|
+
entry.staleSince ?? (entry.staleSince = Date.now());
|
|
1248
|
+
return null;
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
if (typeof root.list !== "function") {
|
|
1252
|
+
root.list = () => Object.entries(providers).map(([namespace, entry]) => {
|
|
1253
|
+
const live = typeof entry.weakRef?.deref === "function" ? entry.weakRef.deref() : void 0;
|
|
1254
|
+
const available = Boolean(live);
|
|
1255
|
+
if (available) {
|
|
1256
|
+
entry.lastSeenAt = Date.now();
|
|
1257
|
+
entry.staleSince = null;
|
|
1258
|
+
} else {
|
|
1259
|
+
entry.staleSince ?? (entry.staleSince = Date.now());
|
|
1260
|
+
}
|
|
1261
|
+
return {
|
|
1262
|
+
namespace,
|
|
1263
|
+
available,
|
|
1264
|
+
registeredAt: entry.registeredAt,
|
|
1265
|
+
lastSeenAt: entry.lastSeenAt,
|
|
1266
|
+
staleSince: entry.staleSince
|
|
1267
|
+
};
|
|
1268
|
+
}).sort((left, right) => left.namespace.localeCompare(right.namespace));
|
|
1269
|
+
}
|
|
1270
|
+
globalWindow.__REACT_MNEMONIC_DEVTOOLS__ = root;
|
|
1271
|
+
return root;
|
|
1272
|
+
}
|
|
1273
|
+
function bumpDevToolsVersion(root, namespace, reason) {
|
|
1274
|
+
if (!root) return;
|
|
1275
|
+
root.__meta.version += 1;
|
|
1276
|
+
root.__meta.lastUpdated = Date.now();
|
|
1277
|
+
root.__meta.lastChange = `${namespace}.${reason}`;
|
|
1278
|
+
}
|
|
1279
|
+
function decodeDevToolsValue(raw) {
|
|
715
1280
|
try {
|
|
716
|
-
return JSON.
|
|
1281
|
+
return JSON.parse(raw);
|
|
717
1282
|
} catch {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
1283
|
+
return raw;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
function readStorageRaw(storage, storageKey, callbacks) {
|
|
1287
|
+
if (!storage) return null;
|
|
1288
|
+
try {
|
|
1289
|
+
const raw = storage.getItem(storageKey);
|
|
1290
|
+
if (isPromiseLike(raw)) {
|
|
1291
|
+
callbacks.onAsyncViolation("getItem", raw);
|
|
1292
|
+
return null;
|
|
721
1293
|
}
|
|
722
|
-
|
|
1294
|
+
callbacks.onAccessSuccess();
|
|
1295
|
+
return raw;
|
|
1296
|
+
} catch (error) {
|
|
1297
|
+
callbacks.onAccessError(error);
|
|
1298
|
+
return null;
|
|
723
1299
|
}
|
|
724
1300
|
}
|
|
725
|
-
function
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
function objectHasOwn(value, property) {
|
|
729
|
-
const hasOwn = Object.hasOwn;
|
|
730
|
-
if (typeof hasOwn === "function") {
|
|
731
|
-
return hasOwn(value, property);
|
|
1301
|
+
function enumerateNamespaceKeys(storage, prefix, callbacks) {
|
|
1302
|
+
if (!storage) {
|
|
1303
|
+
return [];
|
|
732
1304
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
1305
|
+
const keys = [];
|
|
1306
|
+
try {
|
|
1307
|
+
const storageLength = storage.length;
|
|
1308
|
+
const getStorageKey = storage.key;
|
|
1309
|
+
if (typeof storageLength !== "number" || typeof getStorageKey !== "function") {
|
|
1310
|
+
return [];
|
|
1311
|
+
}
|
|
1312
|
+
for (let index = 0; index < storageLength; index++) {
|
|
1313
|
+
const fullKey = getStorageKey.call(storage, index);
|
|
1314
|
+
if (!fullKey?.startsWith(prefix)) continue;
|
|
1315
|
+
keys.push(fullKey.slice(prefix.length));
|
|
1316
|
+
}
|
|
1317
|
+
callbacks.onAccessSuccess();
|
|
1318
|
+
} catch (error) {
|
|
1319
|
+
callbacks.onAccessError(error);
|
|
1320
|
+
}
|
|
1321
|
+
return keys;
|
|
741
1322
|
}
|
|
742
|
-
function
|
|
743
|
-
api,
|
|
1323
|
+
function syncCacheEntryFromStorage({
|
|
744
1324
|
key,
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
ssrOptions
|
|
1325
|
+
storageKey,
|
|
1326
|
+
storage,
|
|
1327
|
+
cache,
|
|
1328
|
+
emit,
|
|
1329
|
+
callbacks
|
|
751
1330
|
}) {
|
|
752
|
-
const
|
|
753
|
-
const
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
defaultValue: stableDiagnosticValue(defaultValue),
|
|
757
|
-
codec: codecSignature,
|
|
758
|
-
schemaVersion: schemaVersion ?? null,
|
|
759
|
-
listenCrossTab: Boolean(listenCrossTab),
|
|
760
|
-
reconcile: reconcileSignature,
|
|
761
|
-
ssrHydration: ssrOptions?.hydration ?? null,
|
|
762
|
-
hasServerValue: ssrOptions?.serverValue !== void 0,
|
|
763
|
-
providerHydration: api.ssrHydration ?? null
|
|
764
|
-
});
|
|
765
|
-
}
|
|
766
|
-
function resolveMnemonicKeyArgs(keyOrDescriptor, options) {
|
|
767
|
-
if (typeof keyOrDescriptor !== "string") {
|
|
768
|
-
return keyOrDescriptor;
|
|
1331
|
+
const fresh = readStorageRaw(storage, storageKey, callbacks);
|
|
1332
|
+
const cached = cache.get(key) ?? null;
|
|
1333
|
+
if (fresh === cached) {
|
|
1334
|
+
return false;
|
|
769
1335
|
}
|
|
770
|
-
|
|
771
|
-
|
|
1336
|
+
cache.set(key, fresh);
|
|
1337
|
+
emit(key);
|
|
1338
|
+
return true;
|
|
1339
|
+
}
|
|
1340
|
+
function reloadNamedKeysFromStorage({
|
|
1341
|
+
changedKeys,
|
|
1342
|
+
prefix,
|
|
1343
|
+
storage,
|
|
1344
|
+
listeners,
|
|
1345
|
+
cache,
|
|
1346
|
+
emit,
|
|
1347
|
+
callbacks
|
|
1348
|
+
}) {
|
|
1349
|
+
let changed = false;
|
|
1350
|
+
for (const fullStorageKey of changedKeys) {
|
|
1351
|
+
if (!fullStorageKey.startsWith(prefix)) continue;
|
|
1352
|
+
const key = fullStorageKey.slice(prefix.length);
|
|
1353
|
+
const listenerSet = listeners.get(key);
|
|
1354
|
+
if (listenerSet && listenerSet.size > 0) {
|
|
1355
|
+
changed = syncCacheEntryFromStorage({
|
|
1356
|
+
key,
|
|
1357
|
+
storageKey: fullStorageKey,
|
|
1358
|
+
storage,
|
|
1359
|
+
cache,
|
|
1360
|
+
emit,
|
|
1361
|
+
callbacks
|
|
1362
|
+
}) || changed;
|
|
1363
|
+
continue;
|
|
1364
|
+
}
|
|
1365
|
+
if (cache.has(key)) {
|
|
1366
|
+
cache.delete(key);
|
|
1367
|
+
}
|
|
772
1368
|
}
|
|
773
|
-
return
|
|
774
|
-
key: keyOrDescriptor,
|
|
775
|
-
options
|
|
776
|
-
};
|
|
1369
|
+
return changed;
|
|
777
1370
|
}
|
|
778
|
-
function
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
reconcile,
|
|
791
|
-
ssr: ssrOptions
|
|
792
|
-
} = resolvedOptions;
|
|
793
|
-
const codec = codecOpt ?? JSONCodec;
|
|
794
|
-
const hydrationMode = ssrOptions?.hydration ?? api.ssrHydration;
|
|
795
|
-
const [hasMounted, setHasMounted] = useState(hydrationMode !== "client-only");
|
|
796
|
-
const developmentRuntime = isDevelopmentRuntime();
|
|
797
|
-
const contractFingerprint = useMemo(
|
|
798
|
-
() => developmentRuntime ? buildContractFingerprint({
|
|
799
|
-
api,
|
|
800
|
-
key,
|
|
801
|
-
defaultValue,
|
|
802
|
-
codecOpt,
|
|
803
|
-
...{} ,
|
|
804
|
-
reconcile,
|
|
805
|
-
listenCrossTab,
|
|
806
|
-
ssrOptions
|
|
807
|
-
}) : null,
|
|
808
|
-
[
|
|
809
|
-
developmentRuntime,
|
|
810
|
-
api,
|
|
1371
|
+
function reloadSubscribedKeysFromStorage({
|
|
1372
|
+
prefix,
|
|
1373
|
+
storage,
|
|
1374
|
+
listeners,
|
|
1375
|
+
cache,
|
|
1376
|
+
emit,
|
|
1377
|
+
callbacks
|
|
1378
|
+
}) {
|
|
1379
|
+
let changed = false;
|
|
1380
|
+
for (const [key, listenerSet] of listeners) {
|
|
1381
|
+
if (listenerSet.size === 0) continue;
|
|
1382
|
+
changed = syncCacheEntryFromStorage({
|
|
811
1383
|
key,
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
(
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
const getServerValue = useCallback(() => {
|
|
826
|
-
const serverValue = ssrOptions?.serverValue;
|
|
827
|
-
if (serverValue === void 0) {
|
|
828
|
-
return getFallback();
|
|
829
|
-
}
|
|
830
|
-
return typeof serverValue === "function" ? serverValue() : serverValue;
|
|
831
|
-
}, [getFallback, ssrOptions?.serverValue]);
|
|
832
|
-
const parseEnvelope = useCallback(
|
|
833
|
-
(rawText) => {
|
|
834
|
-
try {
|
|
835
|
-
const parsed = JSON.parse(rawText);
|
|
836
|
-
if (typeof parsed !== "object" || parsed == null || !Number.isInteger(parsed.version) || parsed.version < 0 || !objectHasOwn(parsed, "payload")) {
|
|
837
|
-
return {
|
|
838
|
-
ok: false,
|
|
839
|
-
error: new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`)
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
return { ok: true, envelope: parsed };
|
|
843
|
-
} catch (err) {
|
|
844
|
-
return {
|
|
845
|
-
ok: false,
|
|
846
|
-
error: new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`, err)
|
|
847
|
-
};
|
|
848
|
-
}
|
|
849
|
-
},
|
|
850
|
-
[key]
|
|
851
|
-
);
|
|
852
|
-
const decodeStringPayload = useCallback(
|
|
853
|
-
(payload, activeCodec) => {
|
|
854
|
-
try {
|
|
855
|
-
return activeCodec.decode(payload);
|
|
856
|
-
} catch (err) {
|
|
857
|
-
throw err instanceof CodecError ? err : new CodecError(`Codec decode failed for key "${key}"`, err);
|
|
858
|
-
}
|
|
859
|
-
},
|
|
860
|
-
[key]
|
|
861
|
-
);
|
|
862
|
-
const buildFallbackResult = useCallback(
|
|
863
|
-
(error, extra) => {
|
|
864
|
-
return withReadMetadata(getFallback(error), void 0, extra);
|
|
865
|
-
},
|
|
866
|
-
[getFallback]
|
|
867
|
-
);
|
|
868
|
-
return {
|
|
869
|
-
api,
|
|
870
|
-
key,
|
|
871
|
-
codec,
|
|
872
|
-
codecOpt,
|
|
873
|
-
schema,
|
|
874
|
-
reconcile,
|
|
875
|
-
onMount,
|
|
876
|
-
onChange,
|
|
877
|
-
listenCrossTab,
|
|
878
|
-
getFallback,
|
|
879
|
-
getServerValue,
|
|
880
|
-
parseEnvelope,
|
|
881
|
-
decodeStringPayload,
|
|
882
|
-
buildFallbackResult,
|
|
883
|
-
developmentRuntime,
|
|
884
|
-
contractFingerprint,
|
|
885
|
-
hasMounted,
|
|
886
|
-
setHasMounted,
|
|
887
|
-
hydrationMode,
|
|
888
|
-
ssrOptions
|
|
889
|
-
};
|
|
1384
|
+
storageKey: `${prefix}${key}`,
|
|
1385
|
+
storage,
|
|
1386
|
+
cache,
|
|
1387
|
+
emit,
|
|
1388
|
+
callbacks
|
|
1389
|
+
}) || changed;
|
|
1390
|
+
}
|
|
1391
|
+
for (const key of cache.keys()) {
|
|
1392
|
+
const listenerSet = listeners.get(key);
|
|
1393
|
+
if (listenerSet && listenerSet.size > 0) continue;
|
|
1394
|
+
cache.delete(key);
|
|
1395
|
+
}
|
|
1396
|
+
return changed;
|
|
890
1397
|
}
|
|
891
|
-
function
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
1398
|
+
function createDevToolsProviderApi({
|
|
1399
|
+
store,
|
|
1400
|
+
dump,
|
|
1401
|
+
keys,
|
|
1402
|
+
readThrough,
|
|
1403
|
+
writeRaw,
|
|
1404
|
+
removeRaw
|
|
895
1405
|
}) {
|
|
896
|
-
return
|
|
897
|
-
(
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
}
|
|
909
|
-
const context = {
|
|
910
|
-
key,
|
|
911
|
-
persistedVersion
|
|
912
|
-
};
|
|
913
|
-
if (latestVersion !== void 0) {
|
|
914
|
-
context.latestVersion = latestVersion;
|
|
915
|
-
}
|
|
916
|
-
const baselineSerialized = (() => {
|
|
917
|
-
try {
|
|
918
|
-
return serializeForPersist(value);
|
|
919
|
-
} catch {
|
|
920
|
-
return rewriteRaw;
|
|
921
|
-
}
|
|
922
|
-
})();
|
|
923
|
-
try {
|
|
924
|
-
const reconciled = reconcile(value, context);
|
|
925
|
-
const nextExtra = deriveExtra ? deriveExtra(reconciled, extra) : extra;
|
|
926
|
-
const nextSerialized = serializeForPersist(reconciled);
|
|
927
|
-
const nextRewriteRaw = baselineSerialized === void 0 || nextSerialized !== baselineSerialized ? nextSerialized : rewriteRaw;
|
|
928
|
-
return withReadMetadata(reconciled, nextRewriteRaw, nextExtra);
|
|
929
|
-
} catch (err) {
|
|
930
|
-
const typedErr = err instanceof SchemaError ? err : new SchemaError("RECONCILE_FAILED", `Reconciliation failed for key "${key}"`, err);
|
|
931
|
-
return buildFallbackResult(typedErr, extra);
|
|
932
|
-
}
|
|
1406
|
+
return {
|
|
1407
|
+
getStore: () => store,
|
|
1408
|
+
dump: () => {
|
|
1409
|
+
const data = dump();
|
|
1410
|
+
console.table(
|
|
1411
|
+
Object.entries(data).map(([key, value]) => ({
|
|
1412
|
+
key,
|
|
1413
|
+
value,
|
|
1414
|
+
decoded: decodeDevToolsValue(value)
|
|
1415
|
+
}))
|
|
1416
|
+
);
|
|
1417
|
+
return data;
|
|
933
1418
|
},
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
getFallback,
|
|
947
|
-
getServerValue,
|
|
948
|
-
developmentRuntime,
|
|
949
|
-
contractFingerprint,
|
|
950
|
-
hasMounted,
|
|
951
|
-
setHasMounted,
|
|
952
|
-
hydrationMode,
|
|
953
|
-
ssrOptions
|
|
954
|
-
} = shared;
|
|
955
|
-
const { decodeForRead, encodeForWrite, additionalDevWarnings, onDecodedEffect } = config;
|
|
956
|
-
const getServerRawSnapshot = useCallback(
|
|
957
|
-
() => ssrOptions?.serverValue === void 0 ? null : SSR_SNAPSHOT_TOKEN,
|
|
958
|
-
[ssrOptions?.serverValue]
|
|
959
|
-
);
|
|
960
|
-
const deferStorageRead = hydrationMode === "client-only" && !hasMounted;
|
|
961
|
-
const subscribe = useCallback(
|
|
962
|
-
(listener) => {
|
|
963
|
-
if (deferStorageRead) {
|
|
964
|
-
return () => void 0;
|
|
1419
|
+
get: (key) => {
|
|
1420
|
+
const raw = readThrough(key);
|
|
1421
|
+
if (raw == null) return void 0;
|
|
1422
|
+
return decodeDevToolsValue(raw);
|
|
1423
|
+
},
|
|
1424
|
+
set: (key, value) => {
|
|
1425
|
+
writeRaw(key, JSON.stringify(value));
|
|
1426
|
+
},
|
|
1427
|
+
remove: (key) => removeRaw(key),
|
|
1428
|
+
clear: () => {
|
|
1429
|
+
for (const key of keys()) {
|
|
1430
|
+
removeRaw(key);
|
|
965
1431
|
}
|
|
966
|
-
return api.subscribeRaw(key, listener);
|
|
967
1432
|
},
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
if (!
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1433
|
+
keys
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
function createReloadFromStorage({
|
|
1437
|
+
storage,
|
|
1438
|
+
hasAsyncContractViolation,
|
|
1439
|
+
prefix,
|
|
1440
|
+
listeners,
|
|
1441
|
+
cache,
|
|
1442
|
+
emit,
|
|
1443
|
+
callbacks,
|
|
1444
|
+
devToolsRoot,
|
|
1445
|
+
namespace
|
|
1446
|
+
}) {
|
|
1447
|
+
return (changedKeys) => {
|
|
1448
|
+
if (!storage || hasAsyncContractViolation()) return;
|
|
1449
|
+
if (changedKeys?.length === 0) return;
|
|
1450
|
+
const isFullReload = changedKeys === void 0;
|
|
1451
|
+
const changed = isFullReload ? reloadSubscribedKeysFromStorage({
|
|
1452
|
+
prefix,
|
|
1453
|
+
storage,
|
|
1454
|
+
listeners,
|
|
1455
|
+
cache,
|
|
1456
|
+
emit,
|
|
1457
|
+
callbacks
|
|
1458
|
+
}) : reloadNamedKeysFromStorage({
|
|
1459
|
+
changedKeys,
|
|
1460
|
+
prefix,
|
|
1461
|
+
storage,
|
|
1462
|
+
listeners,
|
|
1463
|
+
cache,
|
|
1464
|
+
emit,
|
|
1465
|
+
callbacks
|
|
999
1466
|
});
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
keyContracts = /* @__PURE__ */ new Map();
|
|
1003
|
-
diagnosticContractRegistry.set(api, keyContracts);
|
|
1004
|
-
}
|
|
1005
|
-
if (contractFingerprint === null) {
|
|
1006
|
-
return;
|
|
1007
|
-
}
|
|
1008
|
-
const previousContract = keyContracts.get(key);
|
|
1009
|
-
if (previousContract === void 0) {
|
|
1010
|
-
keyContracts.set(key, contractFingerprint);
|
|
1011
|
-
return;
|
|
1012
|
-
}
|
|
1013
|
-
if (previousContract === contractFingerprint) {
|
|
1014
|
-
return;
|
|
1467
|
+
if (changed) {
|
|
1468
|
+
bumpDevToolsVersion(devToolsRoot, namespace, isFullReload ? "reload:full" : "reload:granular");
|
|
1015
1469
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1472
|
+
function registerDevToolsProvider({
|
|
1473
|
+
devToolsRoot,
|
|
1474
|
+
namespace,
|
|
1475
|
+
store,
|
|
1476
|
+
dump,
|
|
1477
|
+
keys,
|
|
1478
|
+
readThrough,
|
|
1479
|
+
writeRaw,
|
|
1480
|
+
removeRaw
|
|
1481
|
+
}) {
|
|
1482
|
+
let infoMessage = `[Mnemonic DevTools] Namespace "${namespace}" available via window.__REACT_MNEMONIC_DEVTOOLS__.resolve("${namespace}")`;
|
|
1483
|
+
if (!devToolsRoot.capabilities.weakRef) {
|
|
1484
|
+
console.info(
|
|
1485
|
+
`[Mnemonic DevTools] WeakRef is not available; registry provider "${namespace}" was not registered.`
|
|
1020
1486
|
);
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
codecOpt,
|
|
1029
|
-
schema,
|
|
1030
|
-
api.crossTabSyncMode
|
|
1031
|
-
]);
|
|
1032
|
-
useEffect(() => {
|
|
1033
|
-
if (hasMounted) return;
|
|
1034
|
-
setHasMounted(true);
|
|
1035
|
-
}, [hasMounted, setHasMounted]);
|
|
1036
|
-
useEffect(() => {
|
|
1037
|
-
if (decoded.rewriteRaw && decoded.rewriteRaw !== raw) {
|
|
1038
|
-
api.setRaw(key, decoded.rewriteRaw);
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
const existingLive = devToolsRoot.resolve(namespace);
|
|
1490
|
+
if (existingLive) {
|
|
1491
|
+
const duplicateMessage = `[Mnemonic DevTools] Duplicate provider namespace "${namespace}" detected. Each window must have at most one live MnemonicProvider per namespace.`;
|
|
1492
|
+
if (!isProductionRuntime()) {
|
|
1493
|
+
throw new Error(duplicateMessage);
|
|
1039
1494
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1495
|
+
console.warn(`${duplicateMessage} Keeping the first provider and ignoring the duplicate.`);
|
|
1496
|
+
console.info(
|
|
1497
|
+
`[Mnemonic DevTools] Namespace "${namespace}" already registered. Keeping existing provider reference.`
|
|
1498
|
+
);
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
const providerApi = createDevToolsProviderApi({
|
|
1502
|
+
store,
|
|
1503
|
+
dump,
|
|
1504
|
+
keys,
|
|
1505
|
+
readThrough,
|
|
1506
|
+
writeRaw,
|
|
1507
|
+
removeRaw
|
|
1508
|
+
});
|
|
1509
|
+
const WeakRefCtor = weakRefConstructor();
|
|
1510
|
+
if (!WeakRefCtor) {
|
|
1511
|
+
console.info(`[Mnemonic DevTools] WeakRef became unavailable while registering "${namespace}".`);
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1514
|
+
store.__devToolsProviderApiHold = providerApi;
|
|
1515
|
+
const now = Date.now();
|
|
1516
|
+
devToolsRoot.providers[namespace] = {
|
|
1517
|
+
namespace,
|
|
1518
|
+
weakRef: new WeakRefCtor(providerApi),
|
|
1519
|
+
registeredAt: now,
|
|
1520
|
+
lastSeenAt: now,
|
|
1521
|
+
staleSince: null
|
|
1522
|
+
};
|
|
1523
|
+
bumpDevToolsVersion(devToolsRoot, namespace, "registry:namespace-registered");
|
|
1524
|
+
console.info(infoMessage);
|
|
1525
|
+
}
|
|
1526
|
+
function MnemonicProvider({
|
|
1527
|
+
children,
|
|
1528
|
+
namespace,
|
|
1529
|
+
storage,
|
|
1530
|
+
enableDevTools = false,
|
|
1531
|
+
schemaMode = "default",
|
|
1532
|
+
schemaRegistry,
|
|
1533
|
+
ssr
|
|
1534
|
+
}) {
|
|
1535
|
+
if (schemaMode === "strict" && !schemaRegistry) {
|
|
1536
|
+
throw new Error("MnemonicProvider strict mode requires schemaRegistry");
|
|
1537
|
+
}
|
|
1538
|
+
if (schemaMode === "autoschema" && typeof schemaRegistry?.registerSchema !== "function") {
|
|
1539
|
+
throw new Error("MnemonicProvider autoschema mode requires schemaRegistry.registerSchema");
|
|
1540
|
+
}
|
|
1541
|
+
const store = useMemo(() => {
|
|
1542
|
+
const prefix = `${namespace}.`;
|
|
1543
|
+
const st = storage ?? defaultBrowserStorage();
|
|
1544
|
+
const ssrHydration = ssr?.hydration ?? "immediate";
|
|
1545
|
+
const devToolsRoot = ensureDevToolsRoot(enableDevTools);
|
|
1546
|
+
const canEnumerateKeys = detectEnumerableStorage(st);
|
|
1547
|
+
const crossTabSyncMode = getCrossTabSyncMode(storage, st);
|
|
1548
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1549
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
1550
|
+
let quotaErrorLogged = false;
|
|
1551
|
+
let accessErrorLogged = false;
|
|
1552
|
+
let asyncContractViolationDetected = false;
|
|
1553
|
+
const storageAccessCallbacks = {
|
|
1554
|
+
onAccessError: (err) => logAccessError(err),
|
|
1555
|
+
onAccessSuccess: () => {
|
|
1556
|
+
accessErrorLogged = false;
|
|
1557
|
+
},
|
|
1558
|
+
onAsyncViolation: (method, thenable) => handleAsyncStorageContractViolation(method, thenable)
|
|
1559
|
+
};
|
|
1560
|
+
const fullKey = (key) => prefix + key;
|
|
1561
|
+
const emit = (key) => {
|
|
1562
|
+
const set = listeners.get(key);
|
|
1563
|
+
if (!set) return;
|
|
1564
|
+
for (const fn of set) fn();
|
|
1565
|
+
};
|
|
1566
|
+
const logAccessError = (err) => {
|
|
1567
|
+
if (!accessErrorLogged && err instanceof DOMException && err.name !== "QuotaExceededError") {
|
|
1568
|
+
console.error(
|
|
1569
|
+
`[Mnemonic] Storage access error (${err.name}): ${err.message}. Data is cached in memory but may not persist.`
|
|
1570
|
+
);
|
|
1571
|
+
accessErrorLogged = true;
|
|
1067
1572
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1573
|
+
};
|
|
1574
|
+
const handleAsyncStorageContractViolation = (method, thenable) => {
|
|
1575
|
+
asyncContractViolationDetected = true;
|
|
1576
|
+
void Promise.resolve(thenable).catch(() => void 0);
|
|
1577
|
+
if (accessErrorLogged) return;
|
|
1578
|
+
console.error(
|
|
1579
|
+
`[Mnemonic] StorageLike.${method} returned a Promise. StorageLike must remain synchronous for react-mnemonic v1. Wrap async persistence behind a synchronous cache facade instead.`
|
|
1580
|
+
);
|
|
1581
|
+
accessErrorLogged = true;
|
|
1582
|
+
};
|
|
1583
|
+
const readThrough = (key) => {
|
|
1584
|
+
if (cache.has(key)) return cache.get(key) ?? null;
|
|
1585
|
+
if (!st || asyncContractViolationDetected) {
|
|
1586
|
+
cache.set(key, null);
|
|
1587
|
+
return null;
|
|
1072
1588
|
}
|
|
1073
|
-
|
|
1589
|
+
const raw = readStorageRaw(st, fullKey(key), storageAccessCallbacks);
|
|
1590
|
+
cache.set(key, raw);
|
|
1591
|
+
return raw;
|
|
1074
1592
|
};
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1593
|
+
const writeRaw = (key, raw) => {
|
|
1594
|
+
cache.set(key, raw);
|
|
1595
|
+
if (st && !asyncContractViolationDetected) {
|
|
1596
|
+
try {
|
|
1597
|
+
const result = st.setItem(fullKey(key), raw);
|
|
1598
|
+
if (isPromiseLike(result)) {
|
|
1599
|
+
handleAsyncStorageContractViolation("setItem", result);
|
|
1600
|
+
} else {
|
|
1601
|
+
quotaErrorLogged = false;
|
|
1602
|
+
accessErrorLogged = false;
|
|
1603
|
+
}
|
|
1604
|
+
} catch (err) {
|
|
1605
|
+
if (!quotaErrorLogged && err instanceof DOMException && err.name === "QuotaExceededError") {
|
|
1606
|
+
console.error(
|
|
1607
|
+
`[Mnemonic] Storage quota exceeded writing key "${key}". Data is cached in memory but will not persist.`
|
|
1608
|
+
);
|
|
1609
|
+
quotaErrorLogged = true;
|
|
1610
|
+
}
|
|
1611
|
+
logAccessError(err);
|
|
1092
1612
|
}
|
|
1093
|
-
console.error(`[Mnemonic] Failed to persist key "${key}":`, err);
|
|
1094
1613
|
}
|
|
1614
|
+
emit(key);
|
|
1615
|
+
bumpDevToolsVersion(devToolsRoot, namespace, `set:${key}`);
|
|
1095
1616
|
};
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
if (err instanceof CodecError) {
|
|
1109
|
-
console.error(`[Mnemonic] Codec encode error for key "${key}":`, err.message);
|
|
1617
|
+
const removeRaw = (key) => {
|
|
1618
|
+
cache.set(key, null);
|
|
1619
|
+
if (st && !asyncContractViolationDetected) {
|
|
1620
|
+
try {
|
|
1621
|
+
const result = st.removeItem(fullKey(key));
|
|
1622
|
+
if (isPromiseLike(result)) {
|
|
1623
|
+
handleAsyncStorageContractViolation("removeItem", result);
|
|
1624
|
+
} else {
|
|
1625
|
+
accessErrorLogged = false;
|
|
1626
|
+
}
|
|
1627
|
+
} catch (err) {
|
|
1628
|
+
logAccessError(err);
|
|
1110
1629
|
}
|
|
1111
|
-
return;
|
|
1112
1630
|
}
|
|
1631
|
+
emit(key);
|
|
1632
|
+
bumpDevToolsVersion(devToolsRoot, namespace, `remove:${key}`);
|
|
1113
1633
|
};
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1634
|
+
const subscribeRaw = (key, listener) => {
|
|
1635
|
+
let set = listeners.get(key);
|
|
1636
|
+
if (!set) {
|
|
1637
|
+
set = /* @__PURE__ */ new Set();
|
|
1638
|
+
listeners.set(key, set);
|
|
1639
|
+
}
|
|
1640
|
+
set.add(listener);
|
|
1641
|
+
readThrough(key);
|
|
1642
|
+
return () => {
|
|
1643
|
+
const s = listeners.get(key);
|
|
1644
|
+
if (!s) return;
|
|
1645
|
+
s.delete(listener);
|
|
1646
|
+
if (s.size === 0) listeners.delete(key);
|
|
1647
|
+
};
|
|
1648
|
+
};
|
|
1649
|
+
const getRawSnapshot = (key) => readThrough(key);
|
|
1650
|
+
const keys = () => {
|
|
1651
|
+
if (asyncContractViolationDetected) {
|
|
1652
|
+
return Array.from(cache.entries()).filter(([, value]) => value != null).map(([key]) => key);
|
|
1653
|
+
}
|
|
1654
|
+
if (!canEnumerateKeys) return [];
|
|
1655
|
+
return enumerateNamespaceKeys(st, prefix, storageAccessCallbacks);
|
|
1656
|
+
};
|
|
1657
|
+
const dump = () => {
|
|
1658
|
+
const out = {};
|
|
1659
|
+
for (const k of keys()) {
|
|
1660
|
+
const raw = readThrough(k);
|
|
1661
|
+
if (raw != null) out[k] = raw;
|
|
1662
|
+
}
|
|
1663
|
+
return out;
|
|
1664
|
+
};
|
|
1665
|
+
const reloadFromStorage = createReloadFromStorage({
|
|
1666
|
+
storage: st,
|
|
1667
|
+
hasAsyncContractViolation: () => asyncContractViolationDetected,
|
|
1668
|
+
prefix,
|
|
1669
|
+
listeners,
|
|
1670
|
+
cache,
|
|
1671
|
+
emit,
|
|
1672
|
+
callbacks: storageAccessCallbacks,
|
|
1673
|
+
devToolsRoot,
|
|
1674
|
+
namespace
|
|
1675
|
+
});
|
|
1676
|
+
const store2 = {
|
|
1677
|
+
prefix,
|
|
1678
|
+
canEnumerateKeys,
|
|
1679
|
+
subscribeRaw,
|
|
1680
|
+
getRawSnapshot,
|
|
1681
|
+
setRaw: writeRaw,
|
|
1682
|
+
removeRaw,
|
|
1683
|
+
keys,
|
|
1684
|
+
dump,
|
|
1685
|
+
reloadFromStorage,
|
|
1686
|
+
schemaMode,
|
|
1687
|
+
ssrHydration,
|
|
1688
|
+
crossTabSyncMode,
|
|
1689
|
+
...schemaRegistry ? { schemaRegistry } : {}
|
|
1690
|
+
};
|
|
1691
|
+
if (devToolsRoot) {
|
|
1692
|
+
registerDevToolsProvider({
|
|
1693
|
+
devToolsRoot,
|
|
1694
|
+
namespace,
|
|
1695
|
+
store: store2,
|
|
1696
|
+
dump,
|
|
1697
|
+
keys,
|
|
1698
|
+
readThrough,
|
|
1699
|
+
writeRaw,
|
|
1700
|
+
removeRaw
|
|
1701
|
+
});
|
|
1702
|
+
}
|
|
1703
|
+
return store2;
|
|
1704
|
+
}, [namespace, storage, enableDevTools, schemaMode, schemaRegistry, ssr?.hydration]);
|
|
1705
|
+
const optionalBridge = useMemo(
|
|
1706
|
+
() => createMnemonicOptionalBridge({
|
|
1707
|
+
api: store,
|
|
1708
|
+
...schemaRegistry ? { schemaRegistry } : {}
|
|
1124
1709
|
}),
|
|
1125
|
-
[
|
|
1710
|
+
[schemaRegistry, store]
|
|
1711
|
+
);
|
|
1712
|
+
useEffect(() => {
|
|
1713
|
+
if (!storage?.onExternalChange) return;
|
|
1714
|
+
return storage.onExternalChange((changedKeys) => store.reloadFromStorage(changedKeys));
|
|
1715
|
+
}, [storage, store]);
|
|
1716
|
+
return /* @__PURE__ */ jsx(MnemonicContext.Provider, { value: store, children: /* @__PURE__ */ jsx(MnemonicOptionalBridgeProvider, { bridge: optionalBridge, children }) });
|
|
1717
|
+
}
|
|
1718
|
+
function throwCoreProviderSchemaImportError(propName) {
|
|
1719
|
+
throw new Error(
|
|
1720
|
+
`[Mnemonic] MnemonicProvider from react-mnemonic/core does not support ${propName}. Import MnemonicProvider from "react-mnemonic/schema" or "react-mnemonic" for schema validation, autoschema, and migration support.`
|
|
1126
1721
|
);
|
|
1127
1722
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1723
|
+
function assertNoSchemaProps(props) {
|
|
1724
|
+
if (props.schemaMode !== void 0) {
|
|
1725
|
+
throwCoreProviderSchemaImportError("schemaMode");
|
|
1726
|
+
}
|
|
1727
|
+
if (props.schemaRegistry !== void 0) {
|
|
1728
|
+
throwCoreProviderSchemaImportError("schemaRegistry");
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
function MnemonicProvider2(props) {
|
|
1732
|
+
assertNoSchemaProps(props);
|
|
1733
|
+
return /* @__PURE__ */ jsx(MnemonicProvider, { ...props });
|
|
1734
|
+
}
|
|
1130
1735
|
function throwCoreSchemaImportError(key) {
|
|
1131
1736
|
throw new Error(
|
|
1132
1737
|
`[Mnemonic] useMnemonicKey("${key}") requested schema features from react-mnemonic/core. Import useMnemonicKey from "react-mnemonic/schema" or "react-mnemonic" for schema validation, autoschema, and migration support.`
|
|
1133
1738
|
);
|
|
1134
1739
|
}
|
|
1135
|
-
function
|
|
1136
|
-
const shared =
|
|
1137
|
-
const {
|
|
1138
|
-
if (schema?.version !== void 0 || api.schemaMode !== "default") {
|
|
1740
|
+
function useCoreRuntimeFromApi(api, keyOrDescriptor, options, active = true) {
|
|
1741
|
+
const shared = useMnemonicKeySharedFromApi(api, keyOrDescriptor, options);
|
|
1742
|
+
const { key, codec, schema, reconcile, parseEnvelope: parseEnvelope2, decodeStringPayload: decodeStringPayload2, buildFallbackResult: buildFallbackResult2 } = shared;
|
|
1743
|
+
if (active && (schema?.version !== void 0 || api.schemaMode !== "default")) {
|
|
1139
1744
|
throwCoreSchemaImportError(key);
|
|
1140
1745
|
}
|
|
1141
1746
|
const applyReconcile = useApplyReconcile({
|
|
1142
1747
|
key,
|
|
1143
1748
|
reconcile,
|
|
1144
|
-
buildFallbackResult
|
|
1749
|
+
buildFallbackResult: buildFallbackResult2
|
|
1145
1750
|
});
|
|
1146
1751
|
const encodeForWrite = useCallback(
|
|
1147
1752
|
(nextValue) => {
|
|
@@ -1151,9 +1756,9 @@ function useCoreRuntime(keyOrDescriptor, options) {
|
|
|
1151
1756
|
);
|
|
1152
1757
|
const decodeForRead = useCallback(
|
|
1153
1758
|
(rawText) => {
|
|
1154
|
-
if (rawText == null) return
|
|
1155
|
-
const parsed =
|
|
1156
|
-
if (!parsed.ok) return
|
|
1759
|
+
if (rawText == null) return buildFallbackResult2();
|
|
1760
|
+
const parsed = parseEnvelope2(rawText);
|
|
1761
|
+
if (!parsed.ok) return buildFallbackResult2(parsed.error);
|
|
1157
1762
|
const envelope = parsed.envelope;
|
|
1158
1763
|
if (typeof envelope.payload !== "string") {
|
|
1159
1764
|
return applyReconcile({
|
|
@@ -1163,17 +1768,17 @@ function useCoreRuntime(keyOrDescriptor, options) {
|
|
|
1163
1768
|
});
|
|
1164
1769
|
}
|
|
1165
1770
|
try {
|
|
1166
|
-
const decoded =
|
|
1771
|
+
const decoded = decodeStringPayload2(envelope.payload, codec);
|
|
1167
1772
|
return applyReconcile({
|
|
1168
1773
|
value: decoded,
|
|
1169
1774
|
persistedVersion: envelope.version,
|
|
1170
1775
|
serializeForPersist: encodeForWrite
|
|
1171
1776
|
});
|
|
1172
1777
|
} catch (err) {
|
|
1173
|
-
return
|
|
1778
|
+
return buildFallbackResult2(err);
|
|
1174
1779
|
}
|
|
1175
1780
|
},
|
|
1176
|
-
[applyReconcile,
|
|
1781
|
+
[applyReconcile, buildFallbackResult2, codec, decodeStringPayload2, encodeForWrite, parseEnvelope2]
|
|
1177
1782
|
);
|
|
1178
1783
|
const additionalDevWarnings = useCallback(
|
|
1179
1784
|
({ warnOnce: warnOnce2 }) => {
|
|
@@ -1186,11 +1791,15 @@ function useCoreRuntime(keyOrDescriptor, options) {
|
|
|
1186
1791
|
[api.schemaRegistry, key]
|
|
1187
1792
|
);
|
|
1188
1793
|
return useMnemonicKeyState(shared, {
|
|
1794
|
+
active,
|
|
1189
1795
|
decodeForRead,
|
|
1190
1796
|
encodeForWrite,
|
|
1191
1797
|
additionalDevWarnings
|
|
1192
1798
|
});
|
|
1193
1799
|
}
|
|
1800
|
+
function useCoreRuntime(keyOrDescriptor, options) {
|
|
1801
|
+
return useCoreRuntimeFromApi(useMnemonic(), keyOrDescriptor, options);
|
|
1802
|
+
}
|
|
1194
1803
|
function useMnemonicKey(keyOrDescriptor, options) {
|
|
1195
1804
|
return useCoreRuntime(keyOrDescriptor, options);
|
|
1196
1805
|
}
|
|
@@ -1212,11 +1821,17 @@ function warnRecoveryOnce(api, id, message) {
|
|
|
1212
1821
|
console.warn(message);
|
|
1213
1822
|
}
|
|
1214
1823
|
function useMnemonicRecovery(options = {}) {
|
|
1215
|
-
|
|
1824
|
+
return useMnemonicRecoveryFromApi(useMnemonic(), options);
|
|
1825
|
+
}
|
|
1826
|
+
function useMnemonicRecoveryFromApi(api, options = {}, active = true) {
|
|
1216
1827
|
const { onRecover } = options;
|
|
1217
|
-
const namespace = useMemo(() =>
|
|
1828
|
+
const namespace = useMemo(() => {
|
|
1829
|
+
if (!active) return "";
|
|
1830
|
+
return api.prefix.endsWith(".") ? api.prefix.slice(0, -1) : api.prefix;
|
|
1831
|
+
}, [active, api.prefix]);
|
|
1218
1832
|
const emitRecovery = useCallback(
|
|
1219
1833
|
(action, clearedKeys) => {
|
|
1834
|
+
if (!active) return;
|
|
1220
1835
|
const event = {
|
|
1221
1836
|
action,
|
|
1222
1837
|
namespace,
|
|
@@ -1224,11 +1839,12 @@ function useMnemonicRecovery(options = {}) {
|
|
|
1224
1839
|
};
|
|
1225
1840
|
onRecover?.(event);
|
|
1226
1841
|
},
|
|
1227
|
-
[namespace, onRecover]
|
|
1842
|
+
[active, namespace, onRecover]
|
|
1228
1843
|
);
|
|
1229
|
-
const listKeys = useCallback(() => api.keys(), [api]);
|
|
1844
|
+
const listKeys = useCallback(() => active ? api.keys() : [], [active, api]);
|
|
1230
1845
|
const clearResolvedKeys = useCallback(
|
|
1231
1846
|
(action, keys) => {
|
|
1847
|
+
if (!active) return [];
|
|
1232
1848
|
const clearedKeys = uniqueKeys(keys);
|
|
1233
1849
|
for (const key of clearedKeys) {
|
|
1234
1850
|
api.removeRaw(key);
|
|
@@ -1236,13 +1852,14 @@ function useMnemonicRecovery(options = {}) {
|
|
|
1236
1852
|
emitRecovery(action, clearedKeys);
|
|
1237
1853
|
return clearedKeys;
|
|
1238
1854
|
},
|
|
1239
|
-
[api, emitRecovery]
|
|
1855
|
+
[active, api, emitRecovery]
|
|
1240
1856
|
);
|
|
1241
1857
|
const clearKeys = useCallback(
|
|
1242
1858
|
(keys) => clearResolvedKeys("clear-keys", keys),
|
|
1243
1859
|
[clearResolvedKeys]
|
|
1244
1860
|
);
|
|
1245
1861
|
const clearAll = useCallback(() => {
|
|
1862
|
+
if (!active) return [];
|
|
1246
1863
|
if (!api.canEnumerateKeys) {
|
|
1247
1864
|
if (isDevelopmentRuntime2()) {
|
|
1248
1865
|
warnRecoveryOnce(
|
|
@@ -1256,9 +1873,10 @@ function useMnemonicRecovery(options = {}) {
|
|
|
1256
1873
|
);
|
|
1257
1874
|
}
|
|
1258
1875
|
return clearResolvedKeys("clear-all", api.keys());
|
|
1259
|
-
}, [api, clearResolvedKeys, namespace]);
|
|
1876
|
+
}, [active, api, clearResolvedKeys, namespace]);
|
|
1260
1877
|
const clearMatching = useCallback(
|
|
1261
1878
|
(predicate) => {
|
|
1879
|
+
if (!active) return [];
|
|
1262
1880
|
if (!api.canEnumerateKeys) {
|
|
1263
1881
|
if (isDevelopmentRuntime2()) {
|
|
1264
1882
|
warnRecoveryOnce(
|
|
@@ -1276,18 +1894,18 @@ function useMnemonicRecovery(options = {}) {
|
|
|
1276
1894
|
api.keys().filter((key) => predicate(key))
|
|
1277
1895
|
);
|
|
1278
1896
|
},
|
|
1279
|
-
[api, clearResolvedKeys, namespace]
|
|
1897
|
+
[active, api, clearResolvedKeys, namespace]
|
|
1280
1898
|
);
|
|
1281
1899
|
return useMemo(
|
|
1282
1900
|
() => ({
|
|
1283
1901
|
namespace,
|
|
1284
|
-
canEnumerateKeys: api.canEnumerateKeys,
|
|
1902
|
+
canEnumerateKeys: active ? api.canEnumerateKeys : false,
|
|
1285
1903
|
listKeys,
|
|
1286
1904
|
clearAll,
|
|
1287
1905
|
clearKeys,
|
|
1288
1906
|
clearMatching
|
|
1289
1907
|
}),
|
|
1290
|
-
[namespace, api.canEnumerateKeys, listKeys, clearAll, clearKeys, clearMatching]
|
|
1908
|
+
[namespace, active, api.canEnumerateKeys, listKeys, clearAll, clearKeys, clearMatching]
|
|
1291
1909
|
);
|
|
1292
1910
|
}
|
|
1293
1911
|
|