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