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