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