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