@epoch32/visage 1.1.3 → 1.1.4
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/dist/api/index.js +55 -4085
- package/dist/charts/index.js +48 -2806
- package/dist/devtools/index.js +18 -4771
- package/dist/dom/index.js +32 -1639
- package/dist/form/index.js +13 -1498
- package/dist/index-061jf06a.js +848 -0
- package/dist/index-0madxn60.js +442 -0
- package/dist/index-1xtrtz1t.js +256 -0
- package/dist/index-2zz0g2n2.js +212 -0
- package/dist/index-5s255b3w.js +303 -0
- package/dist/index-6kfe1nr4.js +1179 -0
- package/dist/index-8czhpea8.js +338 -0
- package/dist/index-8x8xz80v.js +727 -0
- package/dist/index-921pn75b.js +0 -0
- package/dist/index-965ryh36.js +537 -0
- package/dist/index-9fvarkrx.js +98 -0
- package/dist/index-a4xns6cc.js +219 -0
- package/dist/index-b5wc752a.js +1696 -0
- package/dist/index-df5e614s.js +334 -0
- package/dist/index-dyvgtp43.js +1094 -0
- package/dist/index-grhdtcb5.js +234 -0
- package/dist/index-h6tjqk6e.js +158 -0
- package/dist/index-js199er4.js +101 -0
- package/dist/index-x2rs3vab.js +124 -0
- package/dist/index-y9bq7h9g.js +1162 -0
- package/dist/index-zr6cvset.js +2092 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +458 -11920
- package/dist/jsx-runtime/index.js +13 -1719
- package/dist/query/index.js +47 -2505
- package/dist/router/index.js +25 -1945
- package/dist/rpc/index.js +39 -3567
- package/dist/server/index.js +11 -1256
- package/dist/signals/index.js +52 -1160
- package/dist/style/index.js +77 -2429
- package/dist/template/index.js +7 -1232
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +150 -4249
- package/dist/ui/tabs.d.ts +23 -1
- package/dist/virtual/index.js +12 -2044
- package/dist/vite/index.js +5 -744
- package/package.json +2 -2
- package/src/dom/render.ts +20 -7
- package/src/index.ts +2 -0
- package/src/signals/computed.ts +19 -12
- package/src/signals/effect.ts +7 -7
- package/src/signals/signal.ts +16 -12
- package/src/signals/system.ts +50 -21
- package/src/ui/index.ts +2 -0
- package/src/ui/tabs.tsx +211 -10
- package/src/ui/utils.ts +1 -3
package/dist/rpc/index.js
CHANGED
|
@@ -1,3569 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
_regex;
|
|
26
|
-
_isOptional = false;
|
|
27
|
-
min(length, message) {
|
|
28
|
-
this._min = { val: length, msg: message };
|
|
29
|
-
return this;
|
|
30
|
-
}
|
|
31
|
-
max(length, message) {
|
|
32
|
-
this._max = { val: length, msg: message };
|
|
33
|
-
return this;
|
|
34
|
-
}
|
|
35
|
-
email(message) {
|
|
36
|
-
this._emailMsg = message ?? "Invalid email address";
|
|
37
|
-
return this;
|
|
38
|
-
}
|
|
39
|
-
regex(pattern, message) {
|
|
40
|
-
this._regex = { pattern, msg: message };
|
|
41
|
-
return this;
|
|
42
|
-
}
|
|
43
|
-
optional() {
|
|
44
|
-
this._isOptional = true;
|
|
45
|
-
return this;
|
|
46
|
-
}
|
|
47
|
-
validate(value, path = "") {
|
|
48
|
-
if (value === undefined || value === null || value === "") {
|
|
49
|
-
if (this._isOptional)
|
|
50
|
-
return { success: true, data: undefined };
|
|
51
|
-
return { success: false, issues: [{ path, message: "This field is required" }] };
|
|
52
|
-
}
|
|
53
|
-
if (typeof value !== "string") {
|
|
54
|
-
return { success: false, issues: [{ path, message: "Must be a string" }] };
|
|
55
|
-
}
|
|
56
|
-
if (this._min && value.length < this._min.val) {
|
|
57
|
-
return {
|
|
58
|
-
success: false,
|
|
59
|
-
issues: [{ path, message: this._min.msg ?? `Must be at least ${this._min.val} characters` }]
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
if (this._max && value.length > this._max.val) {
|
|
63
|
-
return {
|
|
64
|
-
success: false,
|
|
65
|
-
issues: [{ path, message: this._max.msg ?? `Must be at most ${this._max.val} characters` }]
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
if (this._emailMsg) {
|
|
69
|
-
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
70
|
-
if (!emailRegex.test(value)) {
|
|
71
|
-
return { success: false, issues: [{ path, message: this._emailMsg }] };
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (this._regex && !this._regex.pattern.test(value)) {
|
|
75
|
-
return {
|
|
76
|
-
success: false,
|
|
77
|
-
issues: [{ path, message: this._regex.msg ?? "Invalid format" }]
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
return { success: true, data: value };
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
class NumberSchema extends Schema {
|
|
85
|
-
_min;
|
|
86
|
-
_max;
|
|
87
|
-
_integer;
|
|
88
|
-
_isOptional = false;
|
|
89
|
-
min(value, message) {
|
|
90
|
-
this._min = { val: value, msg: message };
|
|
91
|
-
return this;
|
|
92
|
-
}
|
|
93
|
-
max(value, message) {
|
|
94
|
-
this._max = { val: value, msg: message };
|
|
95
|
-
return this;
|
|
96
|
-
}
|
|
97
|
-
integer(message) {
|
|
98
|
-
this._integer = { msg: message };
|
|
99
|
-
return this;
|
|
100
|
-
}
|
|
101
|
-
optional() {
|
|
102
|
-
this._isOptional = true;
|
|
103
|
-
return this;
|
|
104
|
-
}
|
|
105
|
-
validate(value, path = "") {
|
|
106
|
-
if (value === undefined || value === null || value === "") {
|
|
107
|
-
if (this._isOptional)
|
|
108
|
-
return { success: true, data: undefined };
|
|
109
|
-
return { success: false, issues: [{ path, message: "This field is required" }] };
|
|
110
|
-
}
|
|
111
|
-
const num = Number(value);
|
|
112
|
-
if (Number.isNaN(num) || typeof value === "boolean") {
|
|
113
|
-
return { success: false, issues: [{ path, message: "Must be a valid number" }] };
|
|
114
|
-
}
|
|
115
|
-
if (this._integer && !Number.isInteger(num)) {
|
|
116
|
-
return {
|
|
117
|
-
success: false,
|
|
118
|
-
issues: [{ path, message: this._integer.msg ?? "Must be an integer" }]
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
if (this._min && num < this._min.val) {
|
|
122
|
-
return {
|
|
123
|
-
success: false,
|
|
124
|
-
issues: [{ path, message: this._min.msg ?? `Must be at least ${this._min.val}` }]
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
if (this._max && num > this._max.val) {
|
|
128
|
-
return {
|
|
129
|
-
success: false,
|
|
130
|
-
issues: [{ path, message: this._max.msg ?? `Must be at most ${this._max.val}` }]
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
return { success: true, data: num };
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
class BooleanSchema extends Schema {
|
|
138
|
-
validate(value, _path = "") {
|
|
139
|
-
return { success: true, data: Boolean(value) };
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
class ObjectSchema extends Schema {
|
|
144
|
-
shape;
|
|
145
|
-
constructor(shape) {
|
|
146
|
-
super();
|
|
147
|
-
this.shape = shape;
|
|
148
|
-
}
|
|
149
|
-
validate(value, basePath = "") {
|
|
150
|
-
if (typeof value !== "object" || value === null) {
|
|
151
|
-
return { success: false, issues: [{ path: basePath, message: "Must be an object" }] };
|
|
152
|
-
}
|
|
153
|
-
const issues = [];
|
|
154
|
-
const data = {};
|
|
155
|
-
for (const key in this.shape) {
|
|
156
|
-
const fieldSchema = this.shape[key];
|
|
157
|
-
const fieldVal = value[key];
|
|
158
|
-
const fieldPath = basePath ? `${basePath}.${key}` : key;
|
|
159
|
-
const res = validateWithSchema(fieldSchema, fieldVal, fieldPath);
|
|
160
|
-
if (res.success) {
|
|
161
|
-
data[key] = res.data;
|
|
162
|
-
} else if (res.issues) {
|
|
163
|
-
issues.push(...res.issues);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
if (issues.length > 0) {
|
|
167
|
-
return { success: false, issues };
|
|
168
|
-
}
|
|
169
|
-
return { success: true, data };
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
function validateWithSchema(schema, value, path = "") {
|
|
173
|
-
if (!schema)
|
|
174
|
-
return { success: true, data: value };
|
|
175
|
-
if (schema instanceof Schema) {
|
|
176
|
-
return schema.validate(value, path);
|
|
177
|
-
}
|
|
178
|
-
if (typeof schema === "object" && "~standard" in schema) {
|
|
179
|
-
const res = schema["~standard"].validate(value);
|
|
180
|
-
if ("value" in res) {
|
|
181
|
-
return { success: true, data: res.value };
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
184
|
-
success: false,
|
|
185
|
-
issues: res.issues.map((i) => ({
|
|
186
|
-
path: i.path ? i.path.join(".") : path,
|
|
187
|
-
message: i.message
|
|
188
|
-
}))
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
if (typeof schema === "function") {
|
|
192
|
-
const res = schema(value);
|
|
193
|
-
if (res === true || res === null || res === undefined) {
|
|
194
|
-
return { success: true, data: value };
|
|
195
|
-
}
|
|
196
|
-
if (typeof res === "string") {
|
|
197
|
-
return { success: false, issues: [{ path, message: res }] };
|
|
198
|
-
}
|
|
199
|
-
if (typeof res === "object") {
|
|
200
|
-
return res;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
return { success: true, data: value };
|
|
204
|
-
}
|
|
205
|
-
var v = {
|
|
206
|
-
string: () => new StringSchema,
|
|
207
|
-
number: () => new NumberSchema,
|
|
208
|
-
boolean: () => new BooleanSchema,
|
|
209
|
-
object: (shape) => new ObjectSchema(shape)
|
|
210
|
-
};
|
|
211
|
-
// src/signals/types.ts
|
|
212
|
-
var SubscriberState;
|
|
213
|
-
((SubscriberState) => {
|
|
214
|
-
SubscriberState[SubscriberState["CLEAN"] = 0] = "CLEAN";
|
|
215
|
-
SubscriberState[SubscriberState["CHECK_DIRTY"] = 1] = "CHECK_DIRTY";
|
|
216
|
-
SubscriberState[SubscriberState["DIRTY"] = 2] = "DIRTY";
|
|
217
|
-
SubscriberState[SubscriberState["DISPOSED"] = 3] = "DISPOSED";
|
|
218
|
-
})(SubscriberState ||= {});
|
|
219
|
-
var SIGNAL_BRAND = Symbol("visage.signal");
|
|
220
|
-
var COMPUTED_BRAND = Symbol("visage.computed");
|
|
221
|
-
function isSignal(value) {
|
|
222
|
-
return typeof value === "function" && ((SIGNAL_BRAND in value) || (COMPUTED_BRAND in value));
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// src/signals/system.ts
|
|
226
|
-
var currentSubscriber = null;
|
|
227
|
-
var currentScope = null;
|
|
228
|
-
var batchDepth = 0;
|
|
229
|
-
var pendingEffects = new Set;
|
|
230
|
-
var warnedCyclicSubscribers = new WeakSet;
|
|
231
|
-
var isFlushing = false;
|
|
232
|
-
function setCurrentSubscriber(sub) {
|
|
233
|
-
currentSubscriber = sub;
|
|
234
|
-
}
|
|
235
|
-
function setCurrentScope(scope) {
|
|
236
|
-
currentScope = scope;
|
|
237
|
-
}
|
|
238
|
-
function getCurrentScope() {
|
|
239
|
-
return currentScope;
|
|
240
|
-
}
|
|
241
|
-
function addPendingEffect(eff) {
|
|
242
|
-
pendingEffects.add(eff);
|
|
243
|
-
}
|
|
244
|
-
function removePendingEffect(eff) {
|
|
245
|
-
pendingEffects.delete(eff);
|
|
246
|
-
}
|
|
247
|
-
var MAX_FLUSH_COUNT = 100;
|
|
248
|
-
function flushEffects() {
|
|
249
|
-
if (isFlushing || batchDepth > 0)
|
|
250
|
-
return;
|
|
251
|
-
isFlushing = true;
|
|
252
|
-
let iterations = 0;
|
|
253
|
-
try {
|
|
254
|
-
while (pendingEffects.size > 0) {
|
|
255
|
-
if (++iterations > MAX_FLUSH_COUNT) {
|
|
256
|
-
pendingEffects.clear();
|
|
257
|
-
throw new Error(`[Visage Reactivity] Maximum update depth exceeded (${MAX_FLUSH_COUNT} cycles). ` + `An effect continuously triggered state mutations (infinite loop detected). ` + `Ensure effects that modify signals do not unconditionally depend on them, or use untrack() to read state.`);
|
|
258
|
-
}
|
|
259
|
-
const effectsToRun = Array.from(pendingEffects);
|
|
260
|
-
pendingEffects.clear();
|
|
261
|
-
for (const eff of effectsToRun) {
|
|
262
|
-
if (eff.state === 2 /* DIRTY */ || eff.state === 1 /* CHECK_DIRTY */) {
|
|
263
|
-
eff.run();
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
} finally {
|
|
268
|
-
isFlushing = false;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
function batch(fn) {
|
|
272
|
-
batchDepth++;
|
|
273
|
-
try {
|
|
274
|
-
return fn();
|
|
275
|
-
} finally {
|
|
276
|
-
batchDepth--;
|
|
277
|
-
if (batchDepth === 0) {
|
|
278
|
-
flushEffects();
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
function untrack(fn) {
|
|
283
|
-
const prev = currentSubscriber;
|
|
284
|
-
currentSubscriber = null;
|
|
285
|
-
try {
|
|
286
|
-
return fn();
|
|
287
|
-
} finally {
|
|
288
|
-
currentSubscriber = prev;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// src/signals/computed.ts
|
|
293
|
-
class Computed {
|
|
294
|
-
[COMPUTED_BRAND] = true;
|
|
295
|
-
_fn;
|
|
296
|
-
_value;
|
|
297
|
-
_subscribers = new Set;
|
|
298
|
-
sources = new Set;
|
|
299
|
-
sourceVersions = new Map;
|
|
300
|
-
state = 2 /* DIRTY */;
|
|
301
|
-
scope;
|
|
302
|
-
version = 0;
|
|
303
|
-
constructor(fn) {
|
|
304
|
-
this._fn = fn;
|
|
305
|
-
this.scope = currentScope;
|
|
306
|
-
if (currentScope) {
|
|
307
|
-
currentScope.addSubscriber(this);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
get() {
|
|
311
|
-
if (this.state === 3 /* DISPOSED */) {
|
|
312
|
-
return this._fn();
|
|
313
|
-
}
|
|
314
|
-
if (currentSubscriber !== null && currentSubscriber.state !== 3 /* DISPOSED */) {
|
|
315
|
-
this._subscribers.add(currentSubscriber);
|
|
316
|
-
currentSubscriber.sources.add(this);
|
|
317
|
-
currentSubscriber.sourceVersions.set(this, this.version);
|
|
318
|
-
}
|
|
319
|
-
if (this.state === 2 /* DIRTY */ || this.state === 1 /* CHECK_DIRTY */) {
|
|
320
|
-
this.updateIfNecessary();
|
|
321
|
-
}
|
|
322
|
-
return this._value;
|
|
323
|
-
}
|
|
324
|
-
get value() {
|
|
325
|
-
return this.get();
|
|
326
|
-
}
|
|
327
|
-
removeSubscriber(sub) {
|
|
328
|
-
this._subscribers.delete(sub);
|
|
329
|
-
}
|
|
330
|
-
markDirty(targetState = 1 /* CHECK_DIRTY */) {
|
|
331
|
-
if (this.state >= targetState || this.state === 3 /* DISPOSED */) {
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
this.state = targetState;
|
|
335
|
-
for (const sub of this._subscribers) {
|
|
336
|
-
sub.markDirty(1 /* CHECK_DIRTY */);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
updateIfNecessary() {
|
|
340
|
-
if (this.state === 2 /* DIRTY */) {
|
|
341
|
-
const prev = this._value;
|
|
342
|
-
this.recompute();
|
|
343
|
-
return !Object.is(prev, this._value);
|
|
344
|
-
}
|
|
345
|
-
if (this.state === 1 /* CHECK_DIRTY */) {
|
|
346
|
-
let anyChanged = false;
|
|
347
|
-
for (const source of this.sources) {
|
|
348
|
-
if (source instanceof Computed) {
|
|
349
|
-
source.updateIfNecessary();
|
|
350
|
-
}
|
|
351
|
-
const lastVersion = this.sourceVersions.get(source);
|
|
352
|
-
if (lastVersion !== undefined && lastVersion !== source.version) {
|
|
353
|
-
anyChanged = true;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
if (anyChanged) {
|
|
357
|
-
const prev = this._value;
|
|
358
|
-
this.recompute();
|
|
359
|
-
return !Object.is(prev, this._value);
|
|
360
|
-
}
|
|
361
|
-
this.state = 0 /* CLEAN */;
|
|
362
|
-
return false;
|
|
363
|
-
}
|
|
364
|
-
return false;
|
|
365
|
-
}
|
|
366
|
-
recompute() {
|
|
367
|
-
this.cleanupSources();
|
|
368
|
-
const prevSubscriber = currentSubscriber;
|
|
369
|
-
setCurrentSubscriber(this);
|
|
370
|
-
const prevScope = currentScope;
|
|
371
|
-
setCurrentScope(this.scope);
|
|
372
|
-
try {
|
|
373
|
-
const next = this._fn();
|
|
374
|
-
if (!Object.is(this._value, next)) {
|
|
375
|
-
this._value = next;
|
|
376
|
-
this.version++;
|
|
377
|
-
}
|
|
378
|
-
this.state = 0 /* CLEAN */;
|
|
379
|
-
} finally {
|
|
380
|
-
setCurrentSubscriber(prevSubscriber);
|
|
381
|
-
setCurrentScope(prevScope);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
cleanupSources() {
|
|
385
|
-
for (const source of this.sources) {
|
|
386
|
-
source.removeSubscriber(this);
|
|
387
|
-
}
|
|
388
|
-
this.sources.clear();
|
|
389
|
-
this.sourceVersions.clear();
|
|
390
|
-
}
|
|
391
|
-
dispose() {
|
|
392
|
-
if (this.state === 3 /* DISPOSED */)
|
|
393
|
-
return;
|
|
394
|
-
this.state = 3 /* DISPOSED */;
|
|
395
|
-
this.cleanupSources();
|
|
396
|
-
this._subscribers.clear();
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
function computed(fn, options) {
|
|
400
|
-
const isInternal = options?.internal ?? false;
|
|
401
|
-
const customName = options?.name;
|
|
402
|
-
const c = new Computed(fn);
|
|
403
|
-
const accessor = () => c.get();
|
|
404
|
-
Object.defineProperties(accessor, {
|
|
405
|
-
[COMPUTED_BRAND]: { value: true },
|
|
406
|
-
get: { value: () => c.get() },
|
|
407
|
-
value: { get: () => c.get() }
|
|
408
|
-
});
|
|
409
|
-
if (!isInternal && typeof window !== "undefined" && window.__VISAGE_DEVTOOLS__) {
|
|
410
|
-
const devtools = window.__VISAGE_DEVTOOLS__;
|
|
411
|
-
const sigId = devtools.registerSignal({
|
|
412
|
-
name: customName,
|
|
413
|
-
type: "computed",
|
|
414
|
-
getValue: () => c.get(),
|
|
415
|
-
version: () => c.version,
|
|
416
|
-
subscribersCount: () => c._subscribers?.size ?? 0,
|
|
417
|
-
dependencies: () => Array.from(c.sources ?? []).map((src) => src._devId).filter(Boolean),
|
|
418
|
-
dependents: () => Array.from(c._subscribers ?? []).map((sub) => sub._devId).filter(Boolean)
|
|
419
|
-
});
|
|
420
|
-
c._devId = sigId;
|
|
421
|
-
if (currentScope) {
|
|
422
|
-
currentScope.addCleanup(() => {
|
|
423
|
-
devtools.unregisterSignal(sigId);
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
return accessor;
|
|
428
|
-
}
|
|
429
|
-
var createMemo = computed;
|
|
430
|
-
// src/style/cx.ts
|
|
431
|
-
function hasReactiveClass(val) {
|
|
432
|
-
if (typeof val === "function")
|
|
433
|
-
return true;
|
|
434
|
-
if (Array.isArray(val)) {
|
|
435
|
-
for (let i = 0;i < val.length; i++) {
|
|
436
|
-
if (hasReactiveClass(val[i]))
|
|
437
|
-
return true;
|
|
438
|
-
}
|
|
439
|
-
return false;
|
|
440
|
-
}
|
|
441
|
-
if (typeof val === "object" && val !== null) {
|
|
442
|
-
for (const k in val) {
|
|
443
|
-
if (typeof val[k] === "function")
|
|
444
|
-
return true;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
return false;
|
|
448
|
-
}
|
|
449
|
-
function normalizeClass(val) {
|
|
450
|
-
if (!val)
|
|
451
|
-
return "";
|
|
452
|
-
if (typeof val === "function")
|
|
453
|
-
return normalizeClass(val());
|
|
454
|
-
if (typeof val === "string")
|
|
455
|
-
return val.trim();
|
|
456
|
-
if (typeof val === "number")
|
|
457
|
-
return String(val);
|
|
458
|
-
if (Array.isArray(val)) {
|
|
459
|
-
let res = "";
|
|
460
|
-
for (let i = 0;i < val.length; i++) {
|
|
461
|
-
const item = typeof val[i] === "function" ? val[i]() : val[i];
|
|
462
|
-
const itemStr = normalizeClass(item);
|
|
463
|
-
if (itemStr) {
|
|
464
|
-
res = res ? `${res} ${itemStr}` : itemStr;
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
return res;
|
|
468
|
-
}
|
|
469
|
-
if (typeof val === "object") {
|
|
470
|
-
let res = "";
|
|
471
|
-
for (const key in val) {
|
|
472
|
-
const condition = typeof val[key] === "function" ? val[key]() : val[key];
|
|
473
|
-
if (condition) {
|
|
474
|
-
res = res ? `${res} ${key}` : key;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
return res;
|
|
478
|
-
}
|
|
479
|
-
return "";
|
|
480
|
-
}
|
|
481
|
-
function cx(...args) {
|
|
482
|
-
return normalizeClass(args);
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
// src/style/scale.ts
|
|
486
|
-
var UNITLESS_PROPERTIES = new Set([
|
|
487
|
-
"animationIterationCount",
|
|
488
|
-
"aspectRatio",
|
|
489
|
-
"borderImageSlice",
|
|
490
|
-
"columnCount",
|
|
491
|
-
"columns",
|
|
492
|
-
"flex",
|
|
493
|
-
"flexGrow",
|
|
494
|
-
"flexShrink",
|
|
495
|
-
"flexOrder",
|
|
496
|
-
"fontWeight",
|
|
497
|
-
"lineHeight",
|
|
498
|
-
"opacity",
|
|
499
|
-
"order",
|
|
500
|
-
"orphans",
|
|
501
|
-
"scale",
|
|
502
|
-
"tabSize",
|
|
503
|
-
"widows",
|
|
504
|
-
"zIndex",
|
|
505
|
-
"zoom",
|
|
506
|
-
"fillOpacity",
|
|
507
|
-
"strokeOpacity"
|
|
508
|
-
]);
|
|
509
|
-
var DIMENSION_KEYWORDS = {
|
|
510
|
-
screen: "100dvh",
|
|
511
|
-
"screen-h": "100dvh",
|
|
512
|
-
"screen-w": "100dvw",
|
|
513
|
-
full: "100%",
|
|
514
|
-
half: "50%",
|
|
515
|
-
third: "33.333333%",
|
|
516
|
-
"two-thirds": "66.666667%",
|
|
517
|
-
quarter: "25%",
|
|
518
|
-
"three-quarters": "75%",
|
|
519
|
-
auto: "auto",
|
|
520
|
-
min: "min-content",
|
|
521
|
-
max: "max-content",
|
|
522
|
-
fit: "fit-content"
|
|
523
|
-
};
|
|
524
|
-
function space(val) {
|
|
525
|
-
if (val === undefined || val === null || val === "")
|
|
526
|
-
return "";
|
|
527
|
-
if (typeof val === "number") {
|
|
528
|
-
if (val === 0)
|
|
529
|
-
return "0px";
|
|
530
|
-
return `${val * 4}px`;
|
|
531
|
-
}
|
|
532
|
-
const str = String(val).trim();
|
|
533
|
-
if (str in DIMENSION_KEYWORDS) {
|
|
534
|
-
return DIMENSION_KEYWORDS[str];
|
|
535
|
-
}
|
|
536
|
-
return str;
|
|
537
|
-
}
|
|
538
|
-
function resolveDimension(val) {
|
|
539
|
-
if (val === undefined || val === null || val === "")
|
|
540
|
-
return "";
|
|
541
|
-
if (typeof val === "number") {
|
|
542
|
-
if (val === 0)
|
|
543
|
-
return "0px";
|
|
544
|
-
if (val > 48)
|
|
545
|
-
return `${val}px`;
|
|
546
|
-
return `${val * 4}px`;
|
|
547
|
-
}
|
|
548
|
-
const str = String(val).trim();
|
|
549
|
-
if (str in DIMENSION_KEYWORDS) {
|
|
550
|
-
return DIMENSION_KEYWORDS[str];
|
|
551
|
-
}
|
|
552
|
-
return str;
|
|
553
|
-
}
|
|
554
|
-
function px(val) {
|
|
555
|
-
return `${val}px`;
|
|
556
|
-
}
|
|
557
|
-
function rem(val) {
|
|
558
|
-
return `${val}rem`;
|
|
559
|
-
}
|
|
560
|
-
function em(val) {
|
|
561
|
-
return `${val}em`;
|
|
562
|
-
}
|
|
563
|
-
function fluid(minPx, maxPx, options) {
|
|
564
|
-
const minVw = options?.minVw ?? 375;
|
|
565
|
-
const maxVw = options?.maxVw ?? 1280;
|
|
566
|
-
const slope = (maxPx - minPx) / (maxVw - minVw);
|
|
567
|
-
const yIntercept = -minVw * slope + minPx;
|
|
568
|
-
const slopeVw = slope * 100;
|
|
569
|
-
const preferred = `${yIntercept.toFixed(2)}px + ${slopeVw.toFixed(2)}vw`;
|
|
570
|
-
const min = Math.min(minPx, maxPx);
|
|
571
|
-
const max = Math.max(minPx, maxPx);
|
|
572
|
-
return `clamp(${min}px, ${preferred}, ${max}px)`;
|
|
573
|
-
}
|
|
574
|
-
var SHADOW_PRESETS = {
|
|
575
|
-
none: "none",
|
|
576
|
-
sm: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
|
|
577
|
-
md: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
|
|
578
|
-
lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)",
|
|
579
|
-
xl: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)",
|
|
580
|
-
soft: "0 8px 30px rgba(0, 0, 0, 0.06)",
|
|
581
|
-
glow: "0 0 24px rgba(168, 85, 247, 0.35)",
|
|
582
|
-
inner: "inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)"
|
|
583
|
-
};
|
|
584
|
-
function shadow(variant) {
|
|
585
|
-
if (variant in SHADOW_PRESETS) {
|
|
586
|
-
return SHADOW_PRESETS[variant];
|
|
587
|
-
}
|
|
588
|
-
return variant;
|
|
589
|
-
}
|
|
590
|
-
var RADIUS_PRESETS = {
|
|
591
|
-
none: "0px",
|
|
592
|
-
sm: "4px",
|
|
593
|
-
md: "8px",
|
|
594
|
-
lg: "12px",
|
|
595
|
-
xl: "16px",
|
|
596
|
-
"2xl": "20px",
|
|
597
|
-
"3xl": "24px",
|
|
598
|
-
full: "9999px"
|
|
599
|
-
};
|
|
600
|
-
function radius(variant) {
|
|
601
|
-
if (typeof variant === "number") {
|
|
602
|
-
return `${variant}px`;
|
|
603
|
-
}
|
|
604
|
-
if (variant in RADIUS_PRESETS) {
|
|
605
|
-
return RADIUS_PRESETS[variant];
|
|
606
|
-
}
|
|
607
|
-
return String(variant);
|
|
608
|
-
}
|
|
609
|
-
function glass(options = {}) {
|
|
610
|
-
const blurVal = typeof options.blur === "number" ? `${options.blur}px` : options.blur ?? "20px";
|
|
611
|
-
const tintVal = options.tint ?? "rgba(255, 255, 255, 0.65)";
|
|
612
|
-
const borderVal = options.border ?? "1px solid rgba(255, 255, 255, 0.75)";
|
|
613
|
-
return {
|
|
614
|
-
backdropFilter: `blur(${blurVal})`,
|
|
615
|
-
WebkitBackdropFilter: `blur(${blurVal})`,
|
|
616
|
-
backgroundColor: tintVal,
|
|
617
|
-
border: borderVal
|
|
618
|
-
};
|
|
619
|
-
}
|
|
620
|
-
function formatStyleProp(prop, val) {
|
|
621
|
-
if (val === null || val === undefined || val === "")
|
|
622
|
-
return "";
|
|
623
|
-
if (typeof val === "number") {
|
|
624
|
-
if (val === 0 || UNITLESS_PROPERTIES.has(prop)) {
|
|
625
|
-
return String(val);
|
|
626
|
-
}
|
|
627
|
-
return `${val}px`;
|
|
628
|
-
}
|
|
629
|
-
const str = String(val).trim();
|
|
630
|
-
if (str in DIMENSION_KEYWORDS) {
|
|
631
|
-
const lowerProp = prop.toLowerCase();
|
|
632
|
-
if (str === "screen") {
|
|
633
|
-
if (lowerProp.includes("width"))
|
|
634
|
-
return "100dvw";
|
|
635
|
-
return "100dvh";
|
|
636
|
-
}
|
|
637
|
-
return DIMENSION_KEYWORDS[str];
|
|
638
|
-
}
|
|
639
|
-
return str;
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
// src/dom/render.ts
|
|
643
|
-
function isReactive(value) {
|
|
644
|
-
return isSignal(value) || typeof value === "function";
|
|
645
|
-
}
|
|
646
|
-
function resolveValue(val) {
|
|
647
|
-
if (typeof val === "function") {
|
|
648
|
-
return val();
|
|
649
|
-
}
|
|
650
|
-
return val;
|
|
651
|
-
}
|
|
652
|
-
function render(fn, container) {
|
|
653
|
-
return createRoot((dispose) => {
|
|
654
|
-
container.textContent = "";
|
|
655
|
-
const node = insertChild(container, fn());
|
|
656
|
-
onCleanup(() => {
|
|
657
|
-
if (node && node instanceof Node && node.parentNode === container) {
|
|
658
|
-
container.removeChild(node);
|
|
659
|
-
}
|
|
660
|
-
});
|
|
661
|
-
return dispose;
|
|
662
|
-
});
|
|
663
|
-
}
|
|
664
|
-
function setAttribute(el, key, value) {
|
|
665
|
-
if (key.startsWith("on") && typeof value === "function") {
|
|
666
|
-
const eventName = key.startsWith("onCapture") ? key.slice(9).toLowerCase() : key.slice(2).toLowerCase();
|
|
667
|
-
const useCapture = key.startsWith("onCapture");
|
|
668
|
-
el.addEventListener(eventName, value, useCapture);
|
|
669
|
-
onCleanup(() => {
|
|
670
|
-
el.removeEventListener(eventName, value, useCapture);
|
|
671
|
-
});
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
if (key === "ref" && typeof value === "function") {
|
|
675
|
-
value(el);
|
|
676
|
-
return;
|
|
677
|
-
}
|
|
678
|
-
if (key === "class" || key === "className") {
|
|
679
|
-
if (hasReactiveClass(value)) {
|
|
680
|
-
effect(() => {
|
|
681
|
-
const cls = normalizeClass(value);
|
|
682
|
-
if (cls)
|
|
683
|
-
el.setAttribute("class", cls);
|
|
684
|
-
else
|
|
685
|
-
el.removeAttribute("class");
|
|
686
|
-
});
|
|
687
|
-
} else {
|
|
688
|
-
const cls = normalizeClass(value);
|
|
689
|
-
if (cls)
|
|
690
|
-
el.setAttribute("class", cls);
|
|
691
|
-
else
|
|
692
|
-
el.removeAttribute("class");
|
|
693
|
-
}
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
if (isReactive(value)) {
|
|
697
|
-
effect(() => {
|
|
698
|
-
const resolved = resolveValue(value);
|
|
699
|
-
applyProp(el, key, resolved);
|
|
700
|
-
});
|
|
701
|
-
} else {
|
|
702
|
-
applyProp(el, key, value);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
function setStyleProperty(el, prop, val) {
|
|
706
|
-
const formatted = formatStyleProp(prop, val);
|
|
707
|
-
if (prop.startsWith("--") || prop.includes("-")) {
|
|
708
|
-
if (formatted === "") {
|
|
709
|
-
el.style.removeProperty(prop);
|
|
710
|
-
} else {
|
|
711
|
-
el.style.setProperty(prop, formatted);
|
|
712
|
-
}
|
|
713
|
-
} else {
|
|
714
|
-
el.style[prop] = formatted;
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
function applyProp(el, key, value) {
|
|
718
|
-
if (value === null || value === undefined || value === false && !key.startsWith("aria-") && !key.startsWith("data-")) {
|
|
719
|
-
if (key === "className" || key === "class") {
|
|
720
|
-
el.removeAttribute("class");
|
|
721
|
-
} else if (key === "style" && typeof value === "string") {
|
|
722
|
-
el.removeAttribute("style");
|
|
723
|
-
} else if (key in el && !(el instanceof SVGElement)) {
|
|
724
|
-
try {
|
|
725
|
-
el[key] = typeof el[key] === "boolean" ? false : "";
|
|
726
|
-
} catch {
|
|
727
|
-
el.removeAttribute(key);
|
|
728
|
-
}
|
|
729
|
-
} else {
|
|
730
|
-
el.removeAttribute(key);
|
|
731
|
-
}
|
|
732
|
-
return;
|
|
733
|
-
}
|
|
734
|
-
if (key === "className" || key === "class") {
|
|
735
|
-
const cls = normalizeClass(value);
|
|
736
|
-
if (cls) {
|
|
737
|
-
el.setAttribute("class", cls);
|
|
738
|
-
} else {
|
|
739
|
-
el.removeAttribute("class");
|
|
740
|
-
}
|
|
741
|
-
} else if (key === "style") {
|
|
742
|
-
if (typeof value === "string") {
|
|
743
|
-
el.setAttribute("style", value);
|
|
744
|
-
} else if (typeof value === "object" && value !== null) {
|
|
745
|
-
for (const styleKey in value) {
|
|
746
|
-
const styleVal = value[styleKey];
|
|
747
|
-
if (isReactive(styleVal)) {
|
|
748
|
-
effect(() => {
|
|
749
|
-
setStyleProperty(el, styleKey, resolveValue(styleVal));
|
|
750
|
-
});
|
|
751
|
-
} else {
|
|
752
|
-
setStyleProperty(el, styleKey, styleVal);
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
} else if (key === "dangerouslySetInnerHTML" && value && typeof value.__html === "string") {
|
|
757
|
-
el.innerHTML = value.__html;
|
|
758
|
-
} else if (key in el && !(el instanceof SVGElement) && key !== "list" && key !== "form") {
|
|
759
|
-
try {
|
|
760
|
-
el[key] = value;
|
|
761
|
-
} catch {
|
|
762
|
-
el.setAttribute(key, String(value));
|
|
763
|
-
}
|
|
764
|
-
} else {
|
|
765
|
-
if (key.startsWith("aria-") || key.startsWith("data-")) {
|
|
766
|
-
el.setAttribute(key, String(value));
|
|
767
|
-
} else if (value === true) {
|
|
768
|
-
el.setAttribute(key, "");
|
|
769
|
-
} else {
|
|
770
|
-
el.setAttribute(key, String(value));
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
function insertChild(parent, child, before = null) {
|
|
775
|
-
if (child === null || child === undefined || child === false || child === true) {
|
|
776
|
-
return null;
|
|
777
|
-
}
|
|
778
|
-
if (child instanceof Node) {
|
|
779
|
-
parent.insertBefore(child, before);
|
|
780
|
-
return child;
|
|
781
|
-
}
|
|
782
|
-
if (Array.isArray(child)) {
|
|
783
|
-
const fragment = document.createDocumentFragment();
|
|
784
|
-
for (const item of child) {
|
|
785
|
-
insertChild(fragment, item);
|
|
786
|
-
}
|
|
787
|
-
parent.insertBefore(fragment, before);
|
|
788
|
-
return fragment;
|
|
789
|
-
}
|
|
790
|
-
if (isReactive(child)) {
|
|
791
|
-
const marker = document.createTextNode("");
|
|
792
|
-
parent.insertBefore(marker, before);
|
|
793
|
-
let childScope = null;
|
|
794
|
-
let currentNodes = [];
|
|
795
|
-
effect(() => {
|
|
796
|
-
const resolved = resolveValue(child);
|
|
797
|
-
if ((typeof resolved === "string" || typeof resolved === "number") && currentNodes.length === 1 && currentNodes[0].nodeType === Node.TEXT_NODE) {
|
|
798
|
-
currentNodes[0].data = String(resolved);
|
|
799
|
-
return;
|
|
800
|
-
}
|
|
801
|
-
if (childScope) {
|
|
802
|
-
childScope.dispose();
|
|
803
|
-
}
|
|
804
|
-
childScope = new Scope(getActiveScope());
|
|
805
|
-
runInScope(childScope, () => {
|
|
806
|
-
for (const node of currentNodes) {
|
|
807
|
-
if (node.parentNode) {
|
|
808
|
-
node.parentNode.removeChild(node);
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
currentNodes = [];
|
|
812
|
-
if (resolved === null || resolved === undefined || resolved === false) {
|
|
813
|
-
return;
|
|
814
|
-
}
|
|
815
|
-
const frag = document.createDocumentFragment();
|
|
816
|
-
if (typeof resolved === "string" || typeof resolved === "number" || typeof resolved === "boolean") {
|
|
817
|
-
frag.appendChild(document.createTextNode(String(resolved)));
|
|
818
|
-
} else {
|
|
819
|
-
insertChild(frag, resolved);
|
|
820
|
-
}
|
|
821
|
-
currentNodes = Array.from(frag.childNodes);
|
|
822
|
-
if (marker.parentNode) {
|
|
823
|
-
marker.parentNode.insertBefore(frag, marker);
|
|
824
|
-
}
|
|
825
|
-
});
|
|
826
|
-
});
|
|
827
|
-
onCleanup(() => {
|
|
828
|
-
if (childScope) {
|
|
829
|
-
childScope.dispose();
|
|
830
|
-
}
|
|
831
|
-
for (const node of currentNodes) {
|
|
832
|
-
if (node.parentNode) {
|
|
833
|
-
node.parentNode.removeChild(node);
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
if (marker.parentNode) {
|
|
837
|
-
marker.parentNode.removeChild(marker);
|
|
838
|
-
}
|
|
839
|
-
});
|
|
840
|
-
return marker;
|
|
841
|
-
}
|
|
842
|
-
const textNode = document.createTextNode(String(child));
|
|
843
|
-
parent.insertBefore(textNode, before);
|
|
844
|
-
return textNode;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
// src/signals/scope.ts
|
|
848
|
-
class Scope {
|
|
849
|
-
subscribers = new Set;
|
|
850
|
-
cleanups = [];
|
|
851
|
-
parent = null;
|
|
852
|
-
isDisposed = false;
|
|
853
|
-
context;
|
|
854
|
-
constructor(parent = currentScope) {
|
|
855
|
-
this.parent = parent;
|
|
856
|
-
if (parent && !parent.isDisposed) {
|
|
857
|
-
parent.cleanups.push(() => this.dispose());
|
|
858
|
-
if (parent.context) {
|
|
859
|
-
this.context = new Map(parent.context);
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
addSubscriber(sub) {
|
|
864
|
-
if (this.isDisposed)
|
|
865
|
-
return;
|
|
866
|
-
this.subscribers.add(sub);
|
|
867
|
-
}
|
|
868
|
-
addCleanup(fn) {
|
|
869
|
-
if (this.isDisposed) {
|
|
870
|
-
fn();
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
this.cleanups.push(fn);
|
|
874
|
-
}
|
|
875
|
-
dispose() {
|
|
876
|
-
if (this.isDisposed)
|
|
877
|
-
return;
|
|
878
|
-
this.isDisposed = true;
|
|
879
|
-
for (const sub of this.subscribers) {
|
|
880
|
-
sub.dispose();
|
|
881
|
-
}
|
|
882
|
-
this.subscribers.clear();
|
|
883
|
-
for (let i = this.cleanups.length - 1;i >= 0; i--) {
|
|
884
|
-
try {
|
|
885
|
-
this.cleanups[i]();
|
|
886
|
-
} catch (err) {
|
|
887
|
-
console.error("Error during cleanup:", err);
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
this.cleanups = [];
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
function onCleanup(fn) {
|
|
894
|
-
if (currentSubscriber && "addCleanup" in currentSubscriber) {
|
|
895
|
-
currentSubscriber.addCleanup(fn);
|
|
896
|
-
} else if (currentScope) {
|
|
897
|
-
currentScope.addCleanup(fn);
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
function createRoot(fn) {
|
|
901
|
-
const prevScope = currentScope;
|
|
902
|
-
const scope = new Scope(null);
|
|
903
|
-
setCurrentScope(scope);
|
|
904
|
-
try {
|
|
905
|
-
return fn(() => scope.dispose());
|
|
906
|
-
} finally {
|
|
907
|
-
setCurrentScope(prevScope);
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
function runInScope(scope, fn) {
|
|
911
|
-
const prevScope = currentScope;
|
|
912
|
-
setCurrentScope(scope);
|
|
913
|
-
try {
|
|
914
|
-
return fn();
|
|
915
|
-
} finally {
|
|
916
|
-
setCurrentScope(prevScope);
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
function getActiveScope() {
|
|
920
|
-
return getCurrentScope();
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
// src/signals/context.ts
|
|
924
|
-
function createContext(defaultValue) {
|
|
925
|
-
const id = Symbol("visage.context");
|
|
926
|
-
const context = {
|
|
927
|
-
id,
|
|
928
|
-
defaultValue,
|
|
929
|
-
Provider: (props) => {
|
|
930
|
-
const parentScope = getActiveScope();
|
|
931
|
-
const scope = new Scope(parentScope);
|
|
932
|
-
if (!scope.context) {
|
|
933
|
-
scope.context = new Map(parentScope?.context);
|
|
934
|
-
}
|
|
935
|
-
scope.context.set(id, props.value);
|
|
936
|
-
return runInScope(scope, () => {
|
|
937
|
-
const content = typeof props.children === "function" ? props.children() : props.children;
|
|
938
|
-
if (typeof document !== "undefined") {
|
|
939
|
-
const frag = document.createDocumentFragment();
|
|
940
|
-
insertChild(frag, content);
|
|
941
|
-
return frag;
|
|
942
|
-
}
|
|
943
|
-
return content;
|
|
944
|
-
});
|
|
945
|
-
}
|
|
946
|
-
};
|
|
947
|
-
return context;
|
|
948
|
-
}
|
|
949
|
-
function useContext(context) {
|
|
950
|
-
let scope = getActiveScope();
|
|
951
|
-
while (scope) {
|
|
952
|
-
if (scope.context?.has(context.id)) {
|
|
953
|
-
return scope.context.get(context.id);
|
|
954
|
-
}
|
|
955
|
-
scope = scope.parent;
|
|
956
|
-
}
|
|
957
|
-
return context.defaultValue;
|
|
958
|
-
}
|
|
959
|
-
// src/signals/effect.ts
|
|
960
|
-
class Effect {
|
|
961
|
-
_fn;
|
|
962
|
-
sources = new Set;
|
|
963
|
-
sourceVersions = new Map;
|
|
964
|
-
cleanups = [];
|
|
965
|
-
state = 2 /* DIRTY */;
|
|
966
|
-
scope;
|
|
967
|
-
constructor(fn) {
|
|
968
|
-
this._fn = fn;
|
|
969
|
-
this.scope = currentScope;
|
|
970
|
-
if (currentScope) {
|
|
971
|
-
currentScope.addSubscriber(this);
|
|
972
|
-
}
|
|
973
|
-
this.run();
|
|
974
|
-
}
|
|
975
|
-
addCleanup(fn) {
|
|
976
|
-
this.cleanups.push(fn);
|
|
977
|
-
}
|
|
978
|
-
runCleanups() {
|
|
979
|
-
for (let i = this.cleanups.length - 1;i >= 0; i--) {
|
|
980
|
-
try {
|
|
981
|
-
this.cleanups[i]();
|
|
982
|
-
} catch (e) {
|
|
983
|
-
console.error("Error in effect cleanup:", e);
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
this.cleanups = [];
|
|
987
|
-
}
|
|
988
|
-
markDirty(targetState = 2 /* DIRTY */) {
|
|
989
|
-
if (this.state >= targetState || this.state === 3 /* DISPOSED */) {
|
|
990
|
-
return;
|
|
991
|
-
}
|
|
992
|
-
this.state = targetState;
|
|
993
|
-
addPendingEffect(this);
|
|
994
|
-
if (batchDepth === 0) {
|
|
995
|
-
flushEffects();
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
run() {
|
|
999
|
-
if (this.state === 3 /* DISPOSED */)
|
|
1000
|
-
return;
|
|
1001
|
-
if (this.state === 1 /* CHECK_DIRTY */) {
|
|
1002
|
-
let isDirty = false;
|
|
1003
|
-
for (const source of this.sources) {
|
|
1004
|
-
if (source instanceof Computed) {
|
|
1005
|
-
source.updateIfNecessary();
|
|
1006
|
-
}
|
|
1007
|
-
const lastVersion = this.sourceVersions.get(source);
|
|
1008
|
-
if (lastVersion !== undefined && lastVersion !== source.version) {
|
|
1009
|
-
isDirty = true;
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
if (!isDirty) {
|
|
1013
|
-
this.state = 0 /* CLEAN */;
|
|
1014
|
-
return;
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
this.runCleanups();
|
|
1018
|
-
this.cleanupSources();
|
|
1019
|
-
const prevSubscriber = currentSubscriber;
|
|
1020
|
-
setCurrentSubscriber(this);
|
|
1021
|
-
const prevScope = currentScope;
|
|
1022
|
-
setCurrentScope(this.scope);
|
|
1023
|
-
try {
|
|
1024
|
-
this.state = 0 /* CLEAN */;
|
|
1025
|
-
const res = this._fn();
|
|
1026
|
-
if (typeof res === "function") {
|
|
1027
|
-
this.cleanups.push(res);
|
|
1028
|
-
}
|
|
1029
|
-
} finally {
|
|
1030
|
-
setCurrentSubscriber(prevSubscriber);
|
|
1031
|
-
setCurrentScope(prevScope);
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
cleanupSources() {
|
|
1035
|
-
for (const source of this.sources) {
|
|
1036
|
-
source.removeSubscriber(this);
|
|
1037
|
-
}
|
|
1038
|
-
this.sources.clear();
|
|
1039
|
-
this.sourceVersions.clear();
|
|
1040
|
-
}
|
|
1041
|
-
dispose() {
|
|
1042
|
-
if (this.state === 3 /* DISPOSED */)
|
|
1043
|
-
return;
|
|
1044
|
-
this.state = 3 /* DISPOSED */;
|
|
1045
|
-
this.runCleanups();
|
|
1046
|
-
this.cleanupSources();
|
|
1047
|
-
removePendingEffect(this);
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
function effect(fn) {
|
|
1051
|
-
const eff = new Effect(fn);
|
|
1052
|
-
return () => eff.dispose();
|
|
1053
|
-
}
|
|
1054
|
-
var createEffect = effect;
|
|
1055
|
-
// src/signals/signal.ts
|
|
1056
|
-
class Signal {
|
|
1057
|
-
[SIGNAL_BRAND] = true;
|
|
1058
|
-
_value;
|
|
1059
|
-
_subscribers = new Set;
|
|
1060
|
-
_equals;
|
|
1061
|
-
_onSet;
|
|
1062
|
-
version = 0;
|
|
1063
|
-
constructor(initialValue, equals, onSet) {
|
|
1064
|
-
this._value = initialValue;
|
|
1065
|
-
this._equals = equals ?? Object.is;
|
|
1066
|
-
this._onSet = onSet;
|
|
1067
|
-
}
|
|
1068
|
-
get() {
|
|
1069
|
-
if (currentSubscriber !== null && currentSubscriber.state !== 3 /* DISPOSED */) {
|
|
1070
|
-
this._subscribers.add(currentSubscriber);
|
|
1071
|
-
currentSubscriber.sources.add(this);
|
|
1072
|
-
currentSubscriber.sourceVersions.set(this, this.version);
|
|
1073
|
-
}
|
|
1074
|
-
return this._value;
|
|
1075
|
-
}
|
|
1076
|
-
set(newValue) {
|
|
1077
|
-
if (this._equals(this._value, newValue)) {
|
|
1078
|
-
return;
|
|
1079
|
-
}
|
|
1080
|
-
if (currentSubscriber !== null && this._subscribers.has(currentSubscriber)) {
|
|
1081
|
-
if (!warnedCyclicSubscribers.has(currentSubscriber)) {
|
|
1082
|
-
warnedCyclicSubscribers.add(currentSubscriber);
|
|
1083
|
-
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1084
|
-
console.warn(`[Visage Reactivity] Cyclic update detected: An active subscriber modified a signal that it depends on. ` + `To read a signal inside an effect/computed without creating a circular dependency, wrap the read in untrack():
|
|
1085
|
-
` + ` untrack(() => signal())`);
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
this._value = newValue;
|
|
1090
|
-
this.version++;
|
|
1091
|
-
if (this._onSet) {
|
|
1092
|
-
this._onSet(newValue);
|
|
1093
|
-
}
|
|
1094
|
-
batch(() => {
|
|
1095
|
-
this.notify();
|
|
1096
|
-
});
|
|
1097
|
-
}
|
|
1098
|
-
update(fn) {
|
|
1099
|
-
this.set(fn(this._value));
|
|
1100
|
-
}
|
|
1101
|
-
get value() {
|
|
1102
|
-
return this.get();
|
|
1103
|
-
}
|
|
1104
|
-
set value(val) {
|
|
1105
|
-
this.set(val);
|
|
1106
|
-
}
|
|
1107
|
-
removeSubscriber(sub) {
|
|
1108
|
-
this._subscribers.delete(sub);
|
|
1109
|
-
}
|
|
1110
|
-
notify() {
|
|
1111
|
-
if (this._subscribers.size === 0)
|
|
1112
|
-
return;
|
|
1113
|
-
const subs = Array.from(this._subscribers);
|
|
1114
|
-
for (const sub of subs) {
|
|
1115
|
-
sub.markDirty(2 /* DIRTY */);
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
function resolveStorage(storageOption) {
|
|
1120
|
-
if (storageOption && typeof storageOption === "object") {
|
|
1121
|
-
return storageOption;
|
|
1122
|
-
}
|
|
1123
|
-
if (storageOption === "session") {
|
|
1124
|
-
try {
|
|
1125
|
-
if (typeof sessionStorage !== "undefined")
|
|
1126
|
-
return sessionStorage;
|
|
1127
|
-
} catch {}
|
|
1128
|
-
try {
|
|
1129
|
-
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
1130
|
-
return window.sessionStorage;
|
|
1131
|
-
}
|
|
1132
|
-
} catch {}
|
|
1133
|
-
try {
|
|
1134
|
-
if (typeof globalThis !== "undefined" && globalThis.sessionStorage) {
|
|
1135
|
-
return globalThis.sessionStorage;
|
|
1136
|
-
}
|
|
1137
|
-
} catch {}
|
|
1138
|
-
return null;
|
|
1139
|
-
}
|
|
1140
|
-
try {
|
|
1141
|
-
if (typeof localStorage !== "undefined")
|
|
1142
|
-
return localStorage;
|
|
1143
|
-
} catch {}
|
|
1144
|
-
try {
|
|
1145
|
-
if (typeof window !== "undefined" && window.localStorage) {
|
|
1146
|
-
return window.localStorage;
|
|
1147
|
-
}
|
|
1148
|
-
} catch {}
|
|
1149
|
-
try {
|
|
1150
|
-
if (typeof globalThis !== "undefined" && globalThis.localStorage) {
|
|
1151
|
-
return globalThis.localStorage;
|
|
1152
|
-
}
|
|
1153
|
-
} catch {}
|
|
1154
|
-
return null;
|
|
1155
|
-
}
|
|
1156
|
-
function signal(initialValue, optionsOrEquals) {
|
|
1157
|
-
const equals = typeof optionsOrEquals === "function" ? optionsOrEquals : optionsOrEquals?.equals;
|
|
1158
|
-
const isInternal = typeof optionsOrEquals === "object" ? optionsOrEquals?.internal : false;
|
|
1159
|
-
const customName = typeof optionsOrEquals === "object" ? optionsOrEquals?.name : undefined;
|
|
1160
|
-
const persistOption = typeof optionsOrEquals === "object" ? optionsOrEquals?.persist : undefined;
|
|
1161
|
-
const persistConfig = persistOption ? typeof persistOption === "string" ? { key: persistOption } : persistOption : undefined;
|
|
1162
|
-
let effectiveInitial = initialValue;
|
|
1163
|
-
const storage = persistConfig ? resolveStorage(persistConfig.storage) : null;
|
|
1164
|
-
const serialize = persistConfig?.serialize ?? JSON.stringify;
|
|
1165
|
-
const deserialize = persistConfig?.deserialize ?? JSON.parse;
|
|
1166
|
-
if (persistConfig && storage) {
|
|
1167
|
-
try {
|
|
1168
|
-
const stored = storage.getItem(persistConfig.key);
|
|
1169
|
-
if (stored !== null) {
|
|
1170
|
-
effectiveInitial = deserialize(stored);
|
|
1171
|
-
}
|
|
1172
|
-
} catch {}
|
|
1173
|
-
}
|
|
1174
|
-
let isSyncing = false;
|
|
1175
|
-
const onSet = persistConfig && storage ? (val) => {
|
|
1176
|
-
if (isSyncing)
|
|
1177
|
-
return;
|
|
1178
|
-
try {
|
|
1179
|
-
storage.setItem(persistConfig.key, serialize(val));
|
|
1180
|
-
} catch {}
|
|
1181
|
-
} : undefined;
|
|
1182
|
-
const s = new Signal(effectiveInitial, equals, onSet);
|
|
1183
|
-
if (persistConfig && storage && (persistConfig.syncTabs ?? true) && typeof window !== "undefined" && typeof window.addEventListener === "function") {
|
|
1184
|
-
const onStorage = (e) => {
|
|
1185
|
-
if (e.key === persistConfig.key) {
|
|
1186
|
-
try {
|
|
1187
|
-
const nextVal = e.newValue !== null ? deserialize(e.newValue) : initialValue;
|
|
1188
|
-
isSyncing = true;
|
|
1189
|
-
try {
|
|
1190
|
-
s.set(nextVal);
|
|
1191
|
-
} finally {
|
|
1192
|
-
isSyncing = false;
|
|
1193
|
-
}
|
|
1194
|
-
} catch {}
|
|
1195
|
-
}
|
|
1196
|
-
};
|
|
1197
|
-
window.addEventListener("storage", onStorage);
|
|
1198
|
-
if (currentScope) {
|
|
1199
|
-
currentScope.addCleanup(() => {
|
|
1200
|
-
window.removeEventListener("storage", onStorage);
|
|
1201
|
-
});
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
const accessor = (...args) => {
|
|
1205
|
-
if (args.length === 0) {
|
|
1206
|
-
return s.get();
|
|
1207
|
-
}
|
|
1208
|
-
s.set(args[0]);
|
|
1209
|
-
return args[0];
|
|
1210
|
-
};
|
|
1211
|
-
Object.defineProperties(accessor, {
|
|
1212
|
-
[SIGNAL_BRAND]: { value: true },
|
|
1213
|
-
get: { value: () => s.get() },
|
|
1214
|
-
set: { value: (v) => s.set(v) },
|
|
1215
|
-
update: { value: (fn) => s.update(fn) },
|
|
1216
|
-
value: {
|
|
1217
|
-
get: () => s.get(),
|
|
1218
|
-
set: (v) => s.set(v)
|
|
1219
|
-
}
|
|
1220
|
-
});
|
|
1221
|
-
if (!isInternal && typeof window !== "undefined" && window.__VISAGE_DEVTOOLS__) {
|
|
1222
|
-
const devtools = window.__VISAGE_DEVTOOLS__;
|
|
1223
|
-
const sigId = devtools.registerSignal({
|
|
1224
|
-
name: customName,
|
|
1225
|
-
type: "signal",
|
|
1226
|
-
getValue: () => s.get(),
|
|
1227
|
-
version: () => s.version,
|
|
1228
|
-
subscribersCount: () => s._subscribers?.size ?? 0,
|
|
1229
|
-
dependents: () => Array.from(s._subscribers ?? []).map((sub) => sub._devId).filter(Boolean)
|
|
1230
|
-
});
|
|
1231
|
-
s._devId = sigId;
|
|
1232
|
-
if (currentScope) {
|
|
1233
|
-
currentScope.addCleanup(() => {
|
|
1234
|
-
devtools.unregisterSignal(sigId);
|
|
1235
|
-
});
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
return accessor;
|
|
1239
|
-
}
|
|
1240
|
-
function createSignal(initialValue, optionsOrEquals) {
|
|
1241
|
-
const s = signal(initialValue, optionsOrEquals);
|
|
1242
|
-
const setter = (value) => {
|
|
1243
|
-
if (typeof value === "function") {
|
|
1244
|
-
s.update(value);
|
|
1245
|
-
} else {
|
|
1246
|
-
s.set(value);
|
|
1247
|
-
}
|
|
1248
|
-
};
|
|
1249
|
-
return [s, setter];
|
|
1250
|
-
}
|
|
1251
|
-
// src/signals/store.ts
|
|
1252
|
-
var STORE_RAW = Symbol("visage.store.raw");
|
|
1253
|
-
var STORE_SIGNALS = Symbol("visage.store.signals");
|
|
1254
|
-
var STORE_PROXY = Symbol("visage.store.proxy");
|
|
1255
|
-
function isObject(val) {
|
|
1256
|
-
return typeof val === "object" && val !== null && (typeof Node === "undefined" || !(val instanceof Node)) && !isSignal(val);
|
|
1257
|
-
}
|
|
1258
|
-
function getOrCreatePropertySignal(target, prop) {
|
|
1259
|
-
let signalsMap = target[STORE_SIGNALS];
|
|
1260
|
-
if (!signalsMap) {
|
|
1261
|
-
signalsMap = new Map;
|
|
1262
|
-
Object.defineProperty(target, STORE_SIGNALS, {
|
|
1263
|
-
value: signalsMap,
|
|
1264
|
-
enumerable: false,
|
|
1265
|
-
writable: true
|
|
1266
|
-
});
|
|
1267
|
-
}
|
|
1268
|
-
let sig = signalsMap.get(prop);
|
|
1269
|
-
if (!sig) {
|
|
1270
|
-
sig = new Signal(target[prop]);
|
|
1271
|
-
signalsMap.set(prop, sig);
|
|
1272
|
-
}
|
|
1273
|
-
return sig;
|
|
1274
|
-
}
|
|
1275
|
-
function createStoreProxy(target) {
|
|
1276
|
-
if (!isObject(target))
|
|
1277
|
-
return target;
|
|
1278
|
-
if (target[STORE_PROXY])
|
|
1279
|
-
return target[STORE_PROXY];
|
|
1280
|
-
const proxy = new Proxy(target, {
|
|
1281
|
-
get(target, prop, receiver) {
|
|
1282
|
-
if (prop === STORE_RAW)
|
|
1283
|
-
return target;
|
|
1284
|
-
if (prop === STORE_PROXY)
|
|
1285
|
-
return proxy;
|
|
1286
|
-
if (typeof prop === "string" || typeof prop === "symbol") {
|
|
1287
|
-
const sig = getOrCreatePropertySignal(target, prop);
|
|
1288
|
-
sig.get();
|
|
1289
|
-
}
|
|
1290
|
-
const value = Reflect.get(target, prop, receiver);
|
|
1291
|
-
if (isObject(value)) {
|
|
1292
|
-
return createStoreProxy(value);
|
|
1293
|
-
}
|
|
1294
|
-
return value;
|
|
1295
|
-
},
|
|
1296
|
-
set(target, prop, value, receiver) {
|
|
1297
|
-
const prevValue = Reflect.get(target, prop, receiver);
|
|
1298
|
-
if (Object.is(prevValue, value)) {
|
|
1299
|
-
return true;
|
|
1300
|
-
}
|
|
1301
|
-
const success = Reflect.set(target, prop, value, receiver);
|
|
1302
|
-
if (success) {
|
|
1303
|
-
const sig = getOrCreatePropertySignal(target, prop);
|
|
1304
|
-
sig.set(value);
|
|
1305
|
-
if (Array.isArray(target) && prop !== "length") {
|
|
1306
|
-
const lenSig = getOrCreatePropertySignal(target, "length");
|
|
1307
|
-
lenSig.set(target.length);
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
return success;
|
|
1311
|
-
},
|
|
1312
|
-
deleteProperty(target, prop) {
|
|
1313
|
-
const hadProp = Reflect.has(target, prop);
|
|
1314
|
-
const success = Reflect.deleteProperty(target, prop);
|
|
1315
|
-
if (hadProp && success) {
|
|
1316
|
-
const sig = getOrCreatePropertySignal(target, prop);
|
|
1317
|
-
sig.set(undefined);
|
|
1318
|
-
}
|
|
1319
|
-
return success;
|
|
1320
|
-
}
|
|
1321
|
-
});
|
|
1322
|
-
Object.defineProperty(target, STORE_PROXY, {
|
|
1323
|
-
value: proxy,
|
|
1324
|
-
enumerable: false,
|
|
1325
|
-
writable: true
|
|
1326
|
-
});
|
|
1327
|
-
return proxy;
|
|
1328
|
-
}
|
|
1329
|
-
function createStore(initialState) {
|
|
1330
|
-
if (!isObject(initialState)) {
|
|
1331
|
-
throw new Error("createStore requires an object or array as initial state");
|
|
1332
|
-
}
|
|
1333
|
-
return createStoreProxy(initialState);
|
|
1334
|
-
}
|
|
1335
|
-
function mutateStore(store, mutator) {
|
|
1336
|
-
batch(() => {
|
|
1337
|
-
mutator(store);
|
|
1338
|
-
});
|
|
1339
|
-
}
|
|
1340
|
-
function unwrapStore(store) {
|
|
1341
|
-
if (isObject(store) && store[STORE_RAW]) {
|
|
1342
|
-
return store[STORE_RAW];
|
|
1343
|
-
}
|
|
1344
|
-
return store;
|
|
1345
|
-
}
|
|
1346
|
-
// src/query/focus-manager.ts
|
|
1347
|
-
class FocusManager {
|
|
1348
|
-
_focused;
|
|
1349
|
-
_listeners = new Set;
|
|
1350
|
-
_cleanup;
|
|
1351
|
-
constructor() {
|
|
1352
|
-
this.setupEventListener();
|
|
1353
|
-
}
|
|
1354
|
-
setupEventListener() {
|
|
1355
|
-
if (typeof window === "undefined" || typeof window.addEventListener === "undefined") {
|
|
1356
|
-
return;
|
|
1357
|
-
}
|
|
1358
|
-
const listener = () => {
|
|
1359
|
-
this.notify(this.isFocused());
|
|
1360
|
-
};
|
|
1361
|
-
window.addEventListener("visibilitychange", listener, false);
|
|
1362
|
-
window.addEventListener("focus", listener, false);
|
|
1363
|
-
this._cleanup = () => {
|
|
1364
|
-
window.removeEventListener("visibilitychange", listener);
|
|
1365
|
-
window.removeEventListener("focus", listener);
|
|
1366
|
-
};
|
|
1367
|
-
}
|
|
1368
|
-
setFocused(focused) {
|
|
1369
|
-
this._focused = focused;
|
|
1370
|
-
this.notify(this.isFocused());
|
|
1371
|
-
}
|
|
1372
|
-
isFocused() {
|
|
1373
|
-
if (typeof this._focused === "boolean") {
|
|
1374
|
-
return this._focused;
|
|
1375
|
-
}
|
|
1376
|
-
if (typeof document !== "undefined" && typeof document.visibilityState === "string") {
|
|
1377
|
-
return document.visibilityState !== "hidden";
|
|
1378
|
-
}
|
|
1379
|
-
return true;
|
|
1380
|
-
}
|
|
1381
|
-
subscribe(listener) {
|
|
1382
|
-
this._listeners.add(listener);
|
|
1383
|
-
return () => {
|
|
1384
|
-
this._listeners.delete(listener);
|
|
1385
|
-
};
|
|
1386
|
-
}
|
|
1387
|
-
notify(focused) {
|
|
1388
|
-
for (const listener of this._listeners) {
|
|
1389
|
-
try {
|
|
1390
|
-
listener(focused);
|
|
1391
|
-
} catch (err) {
|
|
1392
|
-
console.error("Error in focus listener:", err);
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
}
|
|
1396
|
-
cleanup() {
|
|
1397
|
-
this._cleanup?.();
|
|
1398
|
-
this._listeners.clear();
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
var focusManager = new FocusManager;
|
|
1402
|
-
|
|
1403
|
-
// src/query/mutation-cache.ts
|
|
1404
|
-
class Mutation {
|
|
1405
|
-
options;
|
|
1406
|
-
data;
|
|
1407
|
-
error;
|
|
1408
|
-
status;
|
|
1409
|
-
submittedAt;
|
|
1410
|
-
variables;
|
|
1411
|
-
isIdle;
|
|
1412
|
-
isPending;
|
|
1413
|
-
isLoading;
|
|
1414
|
-
isSuccess;
|
|
1415
|
-
isError;
|
|
1416
|
-
constructor(options) {
|
|
1417
|
-
this.options = options;
|
|
1418
|
-
this.data = signal(undefined);
|
|
1419
|
-
this.error = signal(null);
|
|
1420
|
-
this.status = signal("idle");
|
|
1421
|
-
this.submittedAt = signal(0);
|
|
1422
|
-
this.variables = signal(undefined);
|
|
1423
|
-
this.isIdle = computed(() => this.status() === "idle");
|
|
1424
|
-
this.isPending = computed(() => this.status() === "pending");
|
|
1425
|
-
this.isLoading = this.isPending;
|
|
1426
|
-
this.isSuccess = computed(() => this.status() === "success");
|
|
1427
|
-
this.isError = computed(() => this.status() === "error");
|
|
1428
|
-
}
|
|
1429
|
-
async execute(variables, mutateOptions) {
|
|
1430
|
-
this.status.set("pending");
|
|
1431
|
-
this.error.set(null);
|
|
1432
|
-
this.variables.set(variables);
|
|
1433
|
-
this.submittedAt.set(Date.now());
|
|
1434
|
-
let context;
|
|
1435
|
-
try {
|
|
1436
|
-
if (this.options.onMutate) {
|
|
1437
|
-
const res = await this.options.onMutate(variables);
|
|
1438
|
-
if (res !== undefined) {
|
|
1439
|
-
context = res;
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
const result = await this.options.mutationFn(variables);
|
|
1443
|
-
this.data.set(result);
|
|
1444
|
-
this.status.set("success");
|
|
1445
|
-
try {
|
|
1446
|
-
await this.options.onSuccess?.(result, variables, context);
|
|
1447
|
-
} catch (err) {
|
|
1448
|
-
console.error("Error in mutation onSuccess:", err);
|
|
1449
|
-
}
|
|
1450
|
-
try {
|
|
1451
|
-
mutateOptions?.onSuccess?.(result, variables, context);
|
|
1452
|
-
} catch (err) {
|
|
1453
|
-
console.error("Error in mutateOptions onSuccess:", err);
|
|
1454
|
-
}
|
|
1455
|
-
try {
|
|
1456
|
-
await this.options.onSettled?.(result, null, variables, context);
|
|
1457
|
-
} catch (err) {
|
|
1458
|
-
console.error("Error in mutation onSettled:", err);
|
|
1459
|
-
}
|
|
1460
|
-
try {
|
|
1461
|
-
mutateOptions?.onSettled?.(result, null, variables, context);
|
|
1462
|
-
} catch (err) {
|
|
1463
|
-
console.error("Error in mutateOptions onSettled:", err);
|
|
1464
|
-
}
|
|
1465
|
-
return result;
|
|
1466
|
-
} catch (err) {
|
|
1467
|
-
this.error.set(err);
|
|
1468
|
-
this.status.set("error");
|
|
1469
|
-
try {
|
|
1470
|
-
await this.options.onError?.(err, variables, context);
|
|
1471
|
-
} catch (e) {
|
|
1472
|
-
console.error("Error in mutation onError:", e);
|
|
1473
|
-
}
|
|
1474
|
-
try {
|
|
1475
|
-
mutateOptions?.onError?.(err, variables, context);
|
|
1476
|
-
} catch (e) {
|
|
1477
|
-
console.error("Error in mutateOptions onError:", e);
|
|
1478
|
-
}
|
|
1479
|
-
try {
|
|
1480
|
-
await this.options.onSettled?.(undefined, err, variables, context);
|
|
1481
|
-
} catch (e) {
|
|
1482
|
-
console.error("Error in mutation onSettled:", e);
|
|
1483
|
-
}
|
|
1484
|
-
try {
|
|
1485
|
-
mutateOptions?.onSettled?.(undefined, err, variables, context);
|
|
1486
|
-
} catch (e) {
|
|
1487
|
-
console.error("Error in mutateOptions onSettled:", e);
|
|
1488
|
-
}
|
|
1489
|
-
throw err;
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
reset() {
|
|
1493
|
-
this.data.set(undefined);
|
|
1494
|
-
this.error.set(null);
|
|
1495
|
-
this.status.set("idle");
|
|
1496
|
-
this.submittedAt.set(0);
|
|
1497
|
-
this.variables.set(undefined);
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
|
|
1501
|
-
class MutationCache {
|
|
1502
|
-
mutations = new Set;
|
|
1503
|
-
build(options) {
|
|
1504
|
-
const mutation = new Mutation(options);
|
|
1505
|
-
this.mutations.add(mutation);
|
|
1506
|
-
return mutation;
|
|
1507
|
-
}
|
|
1508
|
-
remove(mutation) {
|
|
1509
|
-
this.mutations.delete(mutation);
|
|
1510
|
-
}
|
|
1511
|
-
clear() {
|
|
1512
|
-
this.mutations.clear();
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
// src/query/online-manager.ts
|
|
1517
|
-
class OnlineManager {
|
|
1518
|
-
_online;
|
|
1519
|
-
_listeners = new Set;
|
|
1520
|
-
_cleanup;
|
|
1521
|
-
constructor() {
|
|
1522
|
-
this.setupEventListener();
|
|
1523
|
-
}
|
|
1524
|
-
setupEventListener() {
|
|
1525
|
-
if (typeof window === "undefined" || typeof window.addEventListener === "undefined") {
|
|
1526
|
-
return;
|
|
1527
|
-
}
|
|
1528
|
-
const onlineListener = () => this.notify(true);
|
|
1529
|
-
const offlineListener = () => this.notify(false);
|
|
1530
|
-
window.addEventListener("online", onlineListener, false);
|
|
1531
|
-
window.addEventListener("offline", offlineListener, false);
|
|
1532
|
-
this._cleanup = () => {
|
|
1533
|
-
window.removeEventListener("online", onlineListener);
|
|
1534
|
-
window.removeEventListener("offline", offlineListener);
|
|
1535
|
-
};
|
|
1536
|
-
}
|
|
1537
|
-
setOnline(online) {
|
|
1538
|
-
this._online = online;
|
|
1539
|
-
this.notify(this.isOnline());
|
|
1540
|
-
}
|
|
1541
|
-
isOnline() {
|
|
1542
|
-
if (typeof this._online === "boolean") {
|
|
1543
|
-
return this._online;
|
|
1544
|
-
}
|
|
1545
|
-
if (typeof navigator !== "undefined" && typeof navigator.onLine === "boolean") {
|
|
1546
|
-
return navigator.onLine;
|
|
1547
|
-
}
|
|
1548
|
-
return true;
|
|
1549
|
-
}
|
|
1550
|
-
subscribe(listener) {
|
|
1551
|
-
this._listeners.add(listener);
|
|
1552
|
-
return () => {
|
|
1553
|
-
this._listeners.delete(listener);
|
|
1554
|
-
};
|
|
1555
|
-
}
|
|
1556
|
-
notify(online) {
|
|
1557
|
-
for (const listener of this._listeners) {
|
|
1558
|
-
try {
|
|
1559
|
-
listener(online);
|
|
1560
|
-
} catch (err) {
|
|
1561
|
-
console.error("Error in online listener:", err);
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
cleanup() {
|
|
1566
|
-
this._cleanup?.();
|
|
1567
|
-
this._listeners.clear();
|
|
1568
|
-
}
|
|
1569
|
-
}
|
|
1570
|
-
var onlineManager = new OnlineManager;
|
|
1571
|
-
|
|
1572
|
-
// src/query/utils.ts
|
|
1573
|
-
function isPlainObject(value) {
|
|
1574
|
-
if (value === null || typeof value !== "object")
|
|
1575
|
-
return false;
|
|
1576
|
-
const proto = Object.getPrototypeOf(value);
|
|
1577
|
-
return proto === null || proto === Object.prototype;
|
|
1578
|
-
}
|
|
1579
|
-
function hashKey(queryKey) {
|
|
1580
|
-
return JSON.stringify(queryKey, (_key, val) => {
|
|
1581
|
-
if (isPlainObject(val)) {
|
|
1582
|
-
return Object.keys(val).sort().reduce((result, k) => {
|
|
1583
|
-
result[k] = val[k];
|
|
1584
|
-
return result;
|
|
1585
|
-
}, {});
|
|
1586
|
-
}
|
|
1587
|
-
return val;
|
|
1588
|
-
});
|
|
1589
|
-
}
|
|
1590
|
-
function deepEqual(a, b) {
|
|
1591
|
-
if (Object.is(a, b))
|
|
1592
|
-
return true;
|
|
1593
|
-
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
|
|
1594
|
-
return false;
|
|
1595
|
-
}
|
|
1596
|
-
if (Array.isArray(a) !== Array.isArray(b))
|
|
1597
|
-
return false;
|
|
1598
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
1599
|
-
if (a.length !== b.length)
|
|
1600
|
-
return false;
|
|
1601
|
-
for (let i = 0;i < a.length; i++) {
|
|
1602
|
-
if (!deepEqual(a[i], b[i]))
|
|
1603
|
-
return false;
|
|
1604
|
-
}
|
|
1605
|
-
return true;
|
|
1606
|
-
}
|
|
1607
|
-
const keysA = Object.keys(a);
|
|
1608
|
-
const keysB = Object.keys(b);
|
|
1609
|
-
if (keysA.length !== keysB.length)
|
|
1610
|
-
return false;
|
|
1611
|
-
for (const key of keysA) {
|
|
1612
|
-
if (!Object.hasOwn(b, key))
|
|
1613
|
-
return false;
|
|
1614
|
-
if (!deepEqual(a[key], b[key])) {
|
|
1615
|
-
return false;
|
|
1616
|
-
}
|
|
1617
|
-
}
|
|
1618
|
-
return true;
|
|
1619
|
-
}
|
|
1620
|
-
function partialDeepEqual(a, b) {
|
|
1621
|
-
if (Object.is(a, b))
|
|
1622
|
-
return true;
|
|
1623
|
-
if (a === undefined || a === null || b === undefined || b === null) {
|
|
1624
|
-
return a === b;
|
|
1625
|
-
}
|
|
1626
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
1627
|
-
if (a.length > b.length)
|
|
1628
|
-
return false;
|
|
1629
|
-
for (let i = 0;i < a.length; i++) {
|
|
1630
|
-
if (!partialDeepEqual(a[i], b[i]))
|
|
1631
|
-
return false;
|
|
1632
|
-
}
|
|
1633
|
-
return true;
|
|
1634
|
-
}
|
|
1635
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
1636
|
-
for (const key of Object.keys(a)) {
|
|
1637
|
-
if (!(key in b))
|
|
1638
|
-
return false;
|
|
1639
|
-
if (!partialDeepEqual(a[key], b[key]))
|
|
1640
|
-
return false;
|
|
1641
|
-
}
|
|
1642
|
-
return true;
|
|
1643
|
-
}
|
|
1644
|
-
return false;
|
|
1645
|
-
}
|
|
1646
|
-
function matchQuery(filters, query) {
|
|
1647
|
-
if (!filters)
|
|
1648
|
-
return true;
|
|
1649
|
-
if (filters.queryKey !== undefined) {
|
|
1650
|
-
const filterKey = Array.isArray(filters.queryKey) ? filters.queryKey : [filters.queryKey];
|
|
1651
|
-
const queryKey = Array.isArray(query.queryKey) ? query.queryKey : [query.queryKey];
|
|
1652
|
-
if (filters.exact) {
|
|
1653
|
-
if (filterKey.length !== queryKey.length)
|
|
1654
|
-
return false;
|
|
1655
|
-
if (!deepEqual(filterKey, queryKey))
|
|
1656
|
-
return false;
|
|
1657
|
-
} else {
|
|
1658
|
-
if (filterKey.length > queryKey.length)
|
|
1659
|
-
return false;
|
|
1660
|
-
for (let i = 0;i < filterKey.length; i++) {
|
|
1661
|
-
if (!partialDeepEqual(filterKey[i], queryKey[i])) {
|
|
1662
|
-
return false;
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
if (filters.type === "active" && query.observers.size === 0) {
|
|
1668
|
-
return false;
|
|
1669
|
-
}
|
|
1670
|
-
if (filters.type === "inactive" && query.observers.size > 0) {
|
|
1671
|
-
return false;
|
|
1672
|
-
}
|
|
1673
|
-
if (filters.stale !== undefined && query.isStale() !== filters.stale) {
|
|
1674
|
-
return false;
|
|
1675
|
-
}
|
|
1676
|
-
if (filters.fetchStatus !== undefined && query.fetchStatus() !== filters.fetchStatus) {
|
|
1677
|
-
return false;
|
|
1678
|
-
}
|
|
1679
|
-
if (filters.predicate && !filters.predicate(query)) {
|
|
1680
|
-
return false;
|
|
1681
|
-
}
|
|
1682
|
-
return true;
|
|
1683
|
-
}
|
|
1684
|
-
function sleep(ms) {
|
|
1685
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1686
|
-
}
|
|
1687
|
-
|
|
1688
|
-
// src/query/query-cache.ts
|
|
1689
|
-
function shouldRetry(failureCount, error, retry) {
|
|
1690
|
-
if (retry === false)
|
|
1691
|
-
return false;
|
|
1692
|
-
if (retry === true)
|
|
1693
|
-
return true;
|
|
1694
|
-
if (typeof retry === "number")
|
|
1695
|
-
return failureCount <= retry;
|
|
1696
|
-
if (typeof retry === "function")
|
|
1697
|
-
return retry(failureCount, error);
|
|
1698
|
-
return failureCount < 3;
|
|
1699
|
-
}
|
|
1700
|
-
function getRetryDelay(attempt, error, retryDelay) {
|
|
1701
|
-
if (typeof retryDelay === "function")
|
|
1702
|
-
return retryDelay(attempt, error);
|
|
1703
|
-
if (typeof retryDelay === "number")
|
|
1704
|
-
return retryDelay;
|
|
1705
|
-
return Math.min(1000 * 2 ** attempt, 30000);
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
class Query {
|
|
1709
|
-
queryKey;
|
|
1710
|
-
queryHash;
|
|
1711
|
-
cache;
|
|
1712
|
-
data;
|
|
1713
|
-
error;
|
|
1714
|
-
status;
|
|
1715
|
-
fetchStatus;
|
|
1716
|
-
dataUpdatedAt;
|
|
1717
|
-
errorUpdatedAt;
|
|
1718
|
-
failureCount;
|
|
1719
|
-
isInvalidated;
|
|
1720
|
-
observers = new Set;
|
|
1721
|
-
_gcTimeout = null;
|
|
1722
|
-
_abortController = null;
|
|
1723
|
-
promise = null;
|
|
1724
|
-
defaultGcTime = 5 * 60 * 1000;
|
|
1725
|
-
constructor(options) {
|
|
1726
|
-
this.queryKey = options.queryKey;
|
|
1727
|
-
this.queryHash = options.queryHash;
|
|
1728
|
-
this.cache = options.cache;
|
|
1729
|
-
const initialData = typeof options.initialData === "function" ? options.initialData() : options.initialData;
|
|
1730
|
-
const initialUpdatedAt = initialData !== undefined ? typeof options.initialDataUpdatedAt === "function" ? options.initialDataUpdatedAt() : options.initialDataUpdatedAt ?? Date.now() : 0;
|
|
1731
|
-
this.data = signal(initialData);
|
|
1732
|
-
this.error = signal(null);
|
|
1733
|
-
this.status = signal(initialData !== undefined ? "success" : "pending");
|
|
1734
|
-
this.fetchStatus = signal("idle");
|
|
1735
|
-
this.dataUpdatedAt = signal(initialUpdatedAt);
|
|
1736
|
-
this.errorUpdatedAt = signal(0);
|
|
1737
|
-
this.failureCount = signal(0);
|
|
1738
|
-
this.isInvalidated = signal(false);
|
|
1739
|
-
}
|
|
1740
|
-
get state() {
|
|
1741
|
-
return {
|
|
1742
|
-
data: this.data(),
|
|
1743
|
-
error: this.error(),
|
|
1744
|
-
status: this.status(),
|
|
1745
|
-
fetchStatus: this.fetchStatus(),
|
|
1746
|
-
dataUpdatedAt: this.dataUpdatedAt(),
|
|
1747
|
-
errorUpdatedAt: this.errorUpdatedAt(),
|
|
1748
|
-
failureCount: this.failureCount(),
|
|
1749
|
-
isInvalidated: this.isInvalidated()
|
|
1750
|
-
};
|
|
1751
|
-
}
|
|
1752
|
-
isStale(staleTime = 0) {
|
|
1753
|
-
if (this.isInvalidated())
|
|
1754
|
-
return true;
|
|
1755
|
-
if (this.dataUpdatedAt() === 0)
|
|
1756
|
-
return true;
|
|
1757
|
-
if (staleTime === Number.POSITIVE_INFINITY)
|
|
1758
|
-
return false;
|
|
1759
|
-
return Date.now() - this.dataUpdatedAt() >= staleTime;
|
|
1760
|
-
}
|
|
1761
|
-
addObserver(observer) {
|
|
1762
|
-
this.observers.add(observer);
|
|
1763
|
-
this.clearGcTimeout();
|
|
1764
|
-
}
|
|
1765
|
-
removeObserver(observer) {
|
|
1766
|
-
this.observers.delete(observer);
|
|
1767
|
-
if (this.observers.size === 0) {
|
|
1768
|
-
this.scheduleGc(observer.options.gcTime);
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
scheduleGc(gcTime) {
|
|
1772
|
-
this.clearGcTimeout();
|
|
1773
|
-
const duration = gcTime !== undefined ? gcTime : this.defaultGcTime;
|
|
1774
|
-
if (duration === Number.POSITIVE_INFINITY)
|
|
1775
|
-
return;
|
|
1776
|
-
if (duration <= 0) {
|
|
1777
|
-
this.cache.remove(this);
|
|
1778
|
-
return;
|
|
1779
|
-
}
|
|
1780
|
-
this._gcTimeout = setTimeout(() => {
|
|
1781
|
-
if (this.observers.size === 0) {
|
|
1782
|
-
this.cache.remove(this);
|
|
1783
|
-
}
|
|
1784
|
-
}, duration);
|
|
1785
|
-
}
|
|
1786
|
-
clearGcTimeout() {
|
|
1787
|
-
if (this._gcTimeout !== null) {
|
|
1788
|
-
clearTimeout(this._gcTimeout);
|
|
1789
|
-
this._gcTimeout = null;
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
setData(updater, options) {
|
|
1793
|
-
const prev = this.data();
|
|
1794
|
-
const nextData = typeof updater === "function" ? updater(prev) : updater;
|
|
1795
|
-
this.data.set(nextData);
|
|
1796
|
-
this.error.set(null);
|
|
1797
|
-
this.status.set("success");
|
|
1798
|
-
this.isInvalidated.set(false);
|
|
1799
|
-
this.dataUpdatedAt.set(options?.updatedAt ?? Date.now());
|
|
1800
|
-
this.notifyObservers();
|
|
1801
|
-
this.cache.notify({ type: "updated", query: this });
|
|
1802
|
-
return nextData;
|
|
1803
|
-
}
|
|
1804
|
-
invalidate() {
|
|
1805
|
-
this.isInvalidated.set(true);
|
|
1806
|
-
if (this.observers.size > 0) {
|
|
1807
|
-
for (const observer of this.observers) {
|
|
1808
|
-
observer.onQueryUpdate();
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1811
|
-
}
|
|
1812
|
-
cancel() {
|
|
1813
|
-
if (this._abortController) {
|
|
1814
|
-
this._abortController.abort();
|
|
1815
|
-
this._abortController = null;
|
|
1816
|
-
}
|
|
1817
|
-
this.fetchStatus.set("idle");
|
|
1818
|
-
this.promise = null;
|
|
1819
|
-
}
|
|
1820
|
-
reset() {
|
|
1821
|
-
this.cancel();
|
|
1822
|
-
this.data.set(undefined);
|
|
1823
|
-
this.error.set(null);
|
|
1824
|
-
this.status.set("pending");
|
|
1825
|
-
this.fetchStatus.set("idle");
|
|
1826
|
-
this.dataUpdatedAt.set(0);
|
|
1827
|
-
this.errorUpdatedAt.set(0);
|
|
1828
|
-
this.failureCount.set(0);
|
|
1829
|
-
this.isInvalidated.set(false);
|
|
1830
|
-
this.notifyObservers();
|
|
1831
|
-
}
|
|
1832
|
-
async fetch(options, fetchOptions) {
|
|
1833
|
-
if (this.promise && !fetchOptions?.cancelRefetch) {
|
|
1834
|
-
return this.promise;
|
|
1835
|
-
}
|
|
1836
|
-
if (this._abortController && fetchOptions?.cancelRefetch) {
|
|
1837
|
-
this.cancel();
|
|
1838
|
-
}
|
|
1839
|
-
const controller = new AbortController;
|
|
1840
|
-
this._abortController = controller;
|
|
1841
|
-
this.fetchStatus.set("fetching");
|
|
1842
|
-
const queryFn = options?.queryFn;
|
|
1843
|
-
if (!queryFn) {
|
|
1844
|
-
this.fetchStatus.set("idle");
|
|
1845
|
-
throw new Error(`Missing queryFn for queryKey: ${JSON.stringify(this.queryKey)}`);
|
|
1846
|
-
}
|
|
1847
|
-
const execFetch = async () => {
|
|
1848
|
-
let attempt = 0;
|
|
1849
|
-
while (true) {
|
|
1850
|
-
if (controller.signal.aborted) {
|
|
1851
|
-
this.fetchStatus.set("idle");
|
|
1852
|
-
this.promise = null;
|
|
1853
|
-
throw new Error("Query was cancelled");
|
|
1854
|
-
}
|
|
1855
|
-
try {
|
|
1856
|
-
const result = await queryFn({
|
|
1857
|
-
queryKey: this.queryKey,
|
|
1858
|
-
signal: controller.signal,
|
|
1859
|
-
meta: options?.meta
|
|
1860
|
-
});
|
|
1861
|
-
if (controller.signal.aborted) {
|
|
1862
|
-
throw new Error("Query was cancelled");
|
|
1863
|
-
}
|
|
1864
|
-
this.setData(result);
|
|
1865
|
-
this.failureCount.set(0);
|
|
1866
|
-
this.fetchStatus.set("idle");
|
|
1867
|
-
this.promise = null;
|
|
1868
|
-
return result;
|
|
1869
|
-
} catch (err) {
|
|
1870
|
-
if (controller.signal.aborted) {
|
|
1871
|
-
this.fetchStatus.set("idle");
|
|
1872
|
-
this.promise = null;
|
|
1873
|
-
throw err;
|
|
1874
|
-
}
|
|
1875
|
-
attempt++;
|
|
1876
|
-
this.failureCount.set(attempt);
|
|
1877
|
-
const canRetry = shouldRetry(attempt, err, options?.retry);
|
|
1878
|
-
if (canRetry) {
|
|
1879
|
-
const delay = getRetryDelay(attempt, err, options?.retryDelay);
|
|
1880
|
-
if (delay > 0) {
|
|
1881
|
-
await sleep(delay);
|
|
1882
|
-
}
|
|
1883
|
-
continue;
|
|
1884
|
-
}
|
|
1885
|
-
this.error.set(err);
|
|
1886
|
-
this.errorUpdatedAt.set(Date.now());
|
|
1887
|
-
this.status.set("error");
|
|
1888
|
-
this.fetchStatus.set("idle");
|
|
1889
|
-
this.promise = null;
|
|
1890
|
-
this.notifyObservers();
|
|
1891
|
-
throw err;
|
|
1892
|
-
}
|
|
1893
|
-
}
|
|
1894
|
-
};
|
|
1895
|
-
this.promise = execFetch();
|
|
1896
|
-
return this.promise;
|
|
1897
|
-
}
|
|
1898
|
-
notifyObservers() {
|
|
1899
|
-
for (const observer of this.observers) {
|
|
1900
|
-
observer.onQueryUpdate();
|
|
1901
|
-
}
|
|
1902
|
-
}
|
|
1903
|
-
destroy() {
|
|
1904
|
-
this.cancel();
|
|
1905
|
-
this.clearGcTimeout();
|
|
1906
|
-
this.observers.clear();
|
|
1907
|
-
}
|
|
1908
|
-
}
|
|
1909
|
-
|
|
1910
|
-
class QueryCache {
|
|
1911
|
-
queries = new Map;
|
|
1912
|
-
_subscribers = new Set;
|
|
1913
|
-
subscribe(listener) {
|
|
1914
|
-
this._subscribers.add(listener);
|
|
1915
|
-
return () => this._subscribers.delete(listener);
|
|
1916
|
-
}
|
|
1917
|
-
notify(event) {
|
|
1918
|
-
for (const sub of this._subscribers) {
|
|
1919
|
-
sub(event);
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
|
-
getAll() {
|
|
1923
|
-
return Array.from(this.queries.values());
|
|
1924
|
-
}
|
|
1925
|
-
build(_client, options) {
|
|
1926
|
-
const queryHash = hashKey(options.queryKey);
|
|
1927
|
-
let query = this.queries.get(queryHash);
|
|
1928
|
-
if (!query) {
|
|
1929
|
-
query = new Query({
|
|
1930
|
-
queryKey: options.queryKey,
|
|
1931
|
-
queryHash,
|
|
1932
|
-
cache: this,
|
|
1933
|
-
initialData: options.initialData,
|
|
1934
|
-
initialDataUpdatedAt: options.initialDataUpdatedAt
|
|
1935
|
-
});
|
|
1936
|
-
this.add(query);
|
|
1937
|
-
}
|
|
1938
|
-
return query;
|
|
1939
|
-
}
|
|
1940
|
-
get(queryHash) {
|
|
1941
|
-
return this.queries.get(queryHash);
|
|
1942
|
-
}
|
|
1943
|
-
add(query) {
|
|
1944
|
-
this.queries.set(query.queryHash, query);
|
|
1945
|
-
this.notify({ type: "added", query });
|
|
1946
|
-
}
|
|
1947
|
-
remove(query) {
|
|
1948
|
-
const existing = this.queries.get(query.queryHash);
|
|
1949
|
-
if (existing) {
|
|
1950
|
-
existing.destroy();
|
|
1951
|
-
this.queries.delete(query.queryHash);
|
|
1952
|
-
this.notify({ type: "removed", query: existing });
|
|
1953
|
-
}
|
|
1954
|
-
}
|
|
1955
|
-
find(filters) {
|
|
1956
|
-
return this.findAll(filters)[0];
|
|
1957
|
-
}
|
|
1958
|
-
findAll(filters) {
|
|
1959
|
-
const results = [];
|
|
1960
|
-
for (const query of this.queries.values()) {
|
|
1961
|
-
if (matchQuery(filters, query)) {
|
|
1962
|
-
results.push(query);
|
|
1963
|
-
}
|
|
1964
|
-
}
|
|
1965
|
-
return results;
|
|
1966
|
-
}
|
|
1967
|
-
clear() {
|
|
1968
|
-
for (const query of this.queries.values()) {
|
|
1969
|
-
query.destroy();
|
|
1970
|
-
}
|
|
1971
|
-
this.queries.clear();
|
|
1972
|
-
this.notify({ type: "cleared" });
|
|
1973
|
-
}
|
|
1974
|
-
}
|
|
1975
|
-
|
|
1976
|
-
// src/query/query-client.ts
|
|
1977
|
-
class QueryClient {
|
|
1978
|
-
queryCache;
|
|
1979
|
-
mutationCache;
|
|
1980
|
-
defaultOptions;
|
|
1981
|
-
_unsubscribeFocus;
|
|
1982
|
-
_unsubscribeOnline;
|
|
1983
|
-
_isMounted = false;
|
|
1984
|
-
constructor(config = {}) {
|
|
1985
|
-
this.defaultOptions = config.defaultOptions ?? {};
|
|
1986
|
-
this.queryCache = config.queryCache ?? new QueryCache;
|
|
1987
|
-
this.mutationCache = config.mutationCache ?? new MutationCache;
|
|
1988
|
-
this.mount();
|
|
1989
|
-
if (typeof window !== "undefined" && window.__VISAGE_DEVTOOLS__) {
|
|
1990
|
-
window.__VISAGE_DEVTOOLS__.attachQueryClient(this);
|
|
1991
|
-
}
|
|
1992
|
-
}
|
|
1993
|
-
mount() {
|
|
1994
|
-
if (this._isMounted)
|
|
1995
|
-
return;
|
|
1996
|
-
this._isMounted = true;
|
|
1997
|
-
this._unsubscribeFocus = focusManager.subscribe((focused) => {
|
|
1998
|
-
if (focused) {
|
|
1999
|
-
this.onWindowFocus();
|
|
2000
|
-
}
|
|
2001
|
-
});
|
|
2002
|
-
this._unsubscribeOnline = onlineManager.subscribe((online) => {
|
|
2003
|
-
if (online) {
|
|
2004
|
-
this.onOnline();
|
|
2005
|
-
}
|
|
2006
|
-
});
|
|
2007
|
-
}
|
|
2008
|
-
unmount() {
|
|
2009
|
-
this._isMounted = false;
|
|
2010
|
-
this._unsubscribeFocus?.();
|
|
2011
|
-
this._unsubscribeOnline?.();
|
|
2012
|
-
}
|
|
2013
|
-
onWindowFocus() {
|
|
2014
|
-
const activeQueries = this.queryCache.findAll({ type: "active" });
|
|
2015
|
-
for (const query of activeQueries) {
|
|
2016
|
-
const observer = Array.from(query.observers)[0];
|
|
2017
|
-
const options = observer?.options ?? this.defaultOptions.queries ?? {};
|
|
2018
|
-
const refetchOnFocus = options.refetchOnWindowFocus ?? true;
|
|
2019
|
-
if (refetchOnFocus === "always" || refetchOnFocus && query.isStale(options.staleTime)) {
|
|
2020
|
-
query.fetch(options).catch(() => {});
|
|
2021
|
-
}
|
|
2022
|
-
}
|
|
2023
|
-
}
|
|
2024
|
-
onOnline() {
|
|
2025
|
-
const activeQueries = this.queryCache.findAll({ type: "active" });
|
|
2026
|
-
for (const query of activeQueries) {
|
|
2027
|
-
const observer = Array.from(query.observers)[0];
|
|
2028
|
-
const options = observer?.options ?? this.defaultOptions.queries ?? {};
|
|
2029
|
-
const refetchOnReconnect = options.refetchOnReconnect ?? true;
|
|
2030
|
-
if (refetchOnReconnect === "always" || refetchOnReconnect && query.isStale(options.staleTime)) {
|
|
2031
|
-
query.fetch(options).catch(() => {});
|
|
2032
|
-
}
|
|
2033
|
-
}
|
|
2034
|
-
}
|
|
2035
|
-
getDefaultOptions() {
|
|
2036
|
-
return this.defaultOptions;
|
|
2037
|
-
}
|
|
2038
|
-
setDefaultOptions(options) {
|
|
2039
|
-
this.defaultOptions = options;
|
|
2040
|
-
}
|
|
2041
|
-
getQueryCache() {
|
|
2042
|
-
return this.queryCache;
|
|
2043
|
-
}
|
|
2044
|
-
getMutationCache() {
|
|
2045
|
-
return this.mutationCache;
|
|
2046
|
-
}
|
|
2047
|
-
getQueryData(queryKey) {
|
|
2048
|
-
const queryHash = hashKey(queryKey);
|
|
2049
|
-
const query = this.queryCache.get(queryHash);
|
|
2050
|
-
return query?.data();
|
|
2051
|
-
}
|
|
2052
|
-
setQueryData(queryKey, updater, options) {
|
|
2053
|
-
const query = this.queryCache.build(this, {
|
|
2054
|
-
queryKey,
|
|
2055
|
-
...this.defaultOptions.queries
|
|
2056
|
-
});
|
|
2057
|
-
return query.setData(updater, options);
|
|
2058
|
-
}
|
|
2059
|
-
getQueryState(queryKey) {
|
|
2060
|
-
const queryHash = hashKey(queryKey);
|
|
2061
|
-
const query = this.queryCache.get(queryHash);
|
|
2062
|
-
return query?.state;
|
|
2063
|
-
}
|
|
2064
|
-
async fetchQuery(options) {
|
|
2065
|
-
const mergedOptions = {
|
|
2066
|
-
...this.defaultOptions.queries,
|
|
2067
|
-
...options
|
|
2068
|
-
};
|
|
2069
|
-
const query = this.queryCache.build(this, mergedOptions);
|
|
2070
|
-
if (!query.isStale(mergedOptions.staleTime) && query.data() !== undefined) {
|
|
2071
|
-
return query.data();
|
|
2072
|
-
}
|
|
2073
|
-
return query.fetch(mergedOptions);
|
|
2074
|
-
}
|
|
2075
|
-
async prefetchQuery(options) {
|
|
2076
|
-
try {
|
|
2077
|
-
await this.fetchQuery(options);
|
|
2078
|
-
} catch {}
|
|
2079
|
-
}
|
|
2080
|
-
async invalidateQueries(filters) {
|
|
2081
|
-
const queries = this.queryCache.findAll(filters);
|
|
2082
|
-
const promises = [];
|
|
2083
|
-
for (const query of queries) {
|
|
2084
|
-
query.invalidate();
|
|
2085
|
-
if (query.observers.size > 0) {
|
|
2086
|
-
const observer = Array.from(query.observers)[0];
|
|
2087
|
-
const options = observer?.options ?? this.defaultOptions.queries ?? {};
|
|
2088
|
-
promises.push(query.fetch(options).catch(() => {}));
|
|
2089
|
-
}
|
|
2090
|
-
}
|
|
2091
|
-
await Promise.all(promises);
|
|
2092
|
-
}
|
|
2093
|
-
async refetchQueries(filters) {
|
|
2094
|
-
const queries = this.queryCache.findAll(filters);
|
|
2095
|
-
const promises = [];
|
|
2096
|
-
for (const query of queries) {
|
|
2097
|
-
if (query.observers.size > 0) {
|
|
2098
|
-
const observer = Array.from(query.observers)[0];
|
|
2099
|
-
const options = observer?.options ?? this.defaultOptions.queries ?? {};
|
|
2100
|
-
promises.push(query.fetch(options, { cancelRefetch: true }).catch(() => {}));
|
|
2101
|
-
}
|
|
2102
|
-
}
|
|
2103
|
-
await Promise.all(promises);
|
|
2104
|
-
}
|
|
2105
|
-
cancelQueries(filters) {
|
|
2106
|
-
const queries = this.queryCache.findAll(filters);
|
|
2107
|
-
for (const query of queries) {
|
|
2108
|
-
query.cancel();
|
|
2109
|
-
}
|
|
2110
|
-
}
|
|
2111
|
-
removeQueries(filters) {
|
|
2112
|
-
const queries = this.queryCache.findAll(filters);
|
|
2113
|
-
for (const query of queries) {
|
|
2114
|
-
this.queryCache.remove(query);
|
|
2115
|
-
}
|
|
2116
|
-
}
|
|
2117
|
-
async resetQueries(filters) {
|
|
2118
|
-
const queries = this.queryCache.findAll(filters);
|
|
2119
|
-
const promises = [];
|
|
2120
|
-
for (const query of queries) {
|
|
2121
|
-
query.reset();
|
|
2122
|
-
if (query.observers.size > 0) {
|
|
2123
|
-
const observer = Array.from(query.observers)[0];
|
|
2124
|
-
const options = observer?.options ?? this.defaultOptions.queries ?? {};
|
|
2125
|
-
promises.push(query.fetch(options).catch(() => {}));
|
|
2126
|
-
}
|
|
2127
|
-
}
|
|
2128
|
-
await Promise.all(promises);
|
|
2129
|
-
}
|
|
2130
|
-
clear() {
|
|
2131
|
-
this.queryCache.clear();
|
|
2132
|
-
this.mutationCache.clear();
|
|
2133
|
-
}
|
|
2134
|
-
}
|
|
2135
|
-
var QueryClientContext = createContext(null);
|
|
2136
|
-
var defaultGlobalClient = null;
|
|
2137
|
-
function getDefaultGlobalClient() {
|
|
2138
|
-
if (!defaultGlobalClient) {
|
|
2139
|
-
defaultGlobalClient = new QueryClient;
|
|
2140
|
-
}
|
|
2141
|
-
return defaultGlobalClient;
|
|
2142
|
-
}
|
|
2143
|
-
function QueryClientProvider(props) {
|
|
2144
|
-
return QueryClientContext.Provider({
|
|
2145
|
-
value: props.client,
|
|
2146
|
-
children: props.children
|
|
2147
|
-
});
|
|
2148
|
-
}
|
|
2149
|
-
function useQueryClient(client) {
|
|
2150
|
-
if (client)
|
|
2151
|
-
return client;
|
|
2152
|
-
const ctxClient = useContext(QueryClientContext);
|
|
2153
|
-
return ctxClient ?? getDefaultGlobalClient();
|
|
2154
|
-
}
|
|
2155
|
-
|
|
2156
|
-
// src/query/create-mutation.ts
|
|
2157
|
-
function createMutation(options, client) {
|
|
2158
|
-
const queryClient = useQueryClient(client);
|
|
2159
|
-
const resolveOptions = () => typeof options === "function" ? options() : options;
|
|
2160
|
-
const defaults = queryClient.getDefaultOptions().mutations ?? {};
|
|
2161
|
-
const mergedOpts = { ...defaults, ...resolveOptions() };
|
|
2162
|
-
const mutation = queryClient.mutationCache.build(mergedOpts);
|
|
2163
|
-
const mutate = (variables, mutateOptions) => {
|
|
2164
|
-
mutation.execute(variables, mutateOptions).catch(() => {});
|
|
2165
|
-
};
|
|
2166
|
-
const mutateAsync = (variables, mutateOptions) => {
|
|
2167
|
-
return mutation.execute(variables, mutateOptions);
|
|
2168
|
-
};
|
|
2169
|
-
const accessor = () => {
|
|
2170
|
-
return mutation.data();
|
|
2171
|
-
};
|
|
2172
|
-
Object.defineProperties(accessor, {
|
|
2173
|
-
[SIGNAL_BRAND]: { value: true },
|
|
2174
|
-
[COMPUTED_BRAND]: { value: true },
|
|
2175
|
-
value: { get: () => mutation.data() },
|
|
2176
|
-
mutate: { value: mutate },
|
|
2177
|
-
mutateAsync: { value: mutateAsync },
|
|
2178
|
-
data: { get: () => mutation.data },
|
|
2179
|
-
error: { get: () => mutation.error },
|
|
2180
|
-
status: { get: () => mutation.status },
|
|
2181
|
-
isIdle: { get: () => mutation.isIdle },
|
|
2182
|
-
isPending: { get: () => mutation.isPending },
|
|
2183
|
-
isLoading: { get: () => mutation.isLoading },
|
|
2184
|
-
isSuccess: { get: () => mutation.isSuccess },
|
|
2185
|
-
isError: { get: () => mutation.isError },
|
|
2186
|
-
reset: { value: () => mutation.reset() },
|
|
2187
|
-
variables: { get: () => mutation.variables },
|
|
2188
|
-
submittedAt: { get: () => mutation.submittedAt }
|
|
2189
|
-
});
|
|
2190
|
-
return accessor;
|
|
2191
|
-
}
|
|
2192
|
-
|
|
2193
|
-
// src/dom/resource.ts
|
|
2194
|
-
var SuspenseContext = createContext(null);
|
|
2195
|
-
function createResource(sourceOrFetcher, maybeFetcher) {
|
|
2196
|
-
const isDirect = typeof maybeFetcher !== "function";
|
|
2197
|
-
const fetcher = isDirect ? sourceOrFetcher : maybeFetcher;
|
|
2198
|
-
const source = isDirect ? null : sourceOrFetcher;
|
|
2199
|
-
const data = signal(undefined);
|
|
2200
|
-
const loading = signal(true);
|
|
2201
|
-
const error = signal(null);
|
|
2202
|
-
let currentPromise = null;
|
|
2203
|
-
let requestId = 0;
|
|
2204
|
-
const load = async (arg) => {
|
|
2205
|
-
const currentReq = ++requestId;
|
|
2206
|
-
loading.set(true);
|
|
2207
|
-
error.set(null);
|
|
2208
|
-
const promise = isDirect ? fetcher() : fetcher(arg);
|
|
2209
|
-
currentPromise = promise;
|
|
2210
|
-
const suspense = useContext(SuspenseContext);
|
|
2211
|
-
if (suspense) {
|
|
2212
|
-
suspense.registerPromise(promise);
|
|
2213
|
-
}
|
|
2214
|
-
try {
|
|
2215
|
-
const res = await promise;
|
|
2216
|
-
if (currentReq === requestId) {
|
|
2217
|
-
data.set(res);
|
|
2218
|
-
loading.set(false);
|
|
2219
|
-
currentPromise = null;
|
|
2220
|
-
}
|
|
2221
|
-
return res;
|
|
2222
|
-
} catch (err) {
|
|
2223
|
-
if (currentReq === requestId) {
|
|
2224
|
-
error.set(err);
|
|
2225
|
-
loading.set(false);
|
|
2226
|
-
currentPromise = null;
|
|
2227
|
-
}
|
|
2228
|
-
throw err;
|
|
2229
|
-
}
|
|
2230
|
-
};
|
|
2231
|
-
if (source) {
|
|
2232
|
-
effect(() => {
|
|
2233
|
-
const sourceVal = resolveValue(source);
|
|
2234
|
-
if (sourceVal !== false && sourceVal !== null && sourceVal !== undefined) {
|
|
2235
|
-
load(sourceVal).catch(() => {});
|
|
2236
|
-
}
|
|
2237
|
-
});
|
|
2238
|
-
} else {
|
|
2239
|
-
load().catch(() => {});
|
|
2240
|
-
}
|
|
2241
|
-
const accessor = () => {
|
|
2242
|
-
if (loading() && currentPromise) {
|
|
2243
|
-
const suspense = useContext(SuspenseContext);
|
|
2244
|
-
if (suspense) {
|
|
2245
|
-
suspense.registerPromise(currentPromise);
|
|
2246
|
-
}
|
|
2247
|
-
}
|
|
2248
|
-
return data();
|
|
2249
|
-
};
|
|
2250
|
-
Object.defineProperties(accessor, {
|
|
2251
|
-
loading: { get: () => loading },
|
|
2252
|
-
error: { get: () => error },
|
|
2253
|
-
mutate: { value: (val) => data.set(val) },
|
|
2254
|
-
refetch: { value: () => source ? load(resolveValue(source)) : load() }
|
|
2255
|
-
});
|
|
2256
|
-
return accessor;
|
|
2257
|
-
}
|
|
2258
|
-
// src/dom/async.ts
|
|
2259
|
-
function Suspense(props) {
|
|
2260
|
-
if (typeof document === "undefined") {
|
|
2261
|
-
return typeof props.children === "function" ? props.children() : props.children;
|
|
2262
|
-
}
|
|
2263
|
-
const marker = document.createTextNode("");
|
|
2264
|
-
const initialFrag = document.createDocumentFragment();
|
|
2265
|
-
const pendingCount = signal(0);
|
|
2266
|
-
let currentScope = null;
|
|
2267
|
-
let currentNodes = [];
|
|
2268
|
-
let isMounted = false;
|
|
2269
|
-
const suspenseValue = {
|
|
2270
|
-
registerPromise(p) {
|
|
2271
|
-
pendingCount.update((c) => c + 1);
|
|
2272
|
-
p.finally(() => {
|
|
2273
|
-
pendingCount.update((c) => Math.max(0, c - 1));
|
|
2274
|
-
});
|
|
2275
|
-
}
|
|
2276
|
-
};
|
|
2277
|
-
const renderContent = (content) => {
|
|
2278
|
-
const parent = marker.parentNode ?? (!isMounted ? initialFrag : null);
|
|
2279
|
-
if (!parent)
|
|
2280
|
-
return;
|
|
2281
|
-
for (const n of currentNodes) {
|
|
2282
|
-
if (n.parentNode)
|
|
2283
|
-
n.parentNode.removeChild(n);
|
|
2284
|
-
}
|
|
2285
|
-
currentNodes = [];
|
|
2286
|
-
const frag = document.createDocumentFragment();
|
|
2287
|
-
insertChild(frag, content);
|
|
2288
|
-
currentNodes = Array.from(frag.childNodes);
|
|
2289
|
-
if (marker.parentNode) {
|
|
2290
|
-
marker.parentNode.insertBefore(frag, marker);
|
|
2291
|
-
} else if (!isMounted) {
|
|
2292
|
-
initialFrag.appendChild(frag);
|
|
2293
|
-
}
|
|
2294
|
-
};
|
|
2295
|
-
effect(() => {
|
|
2296
|
-
if (currentScope) {
|
|
2297
|
-
currentScope.dispose();
|
|
2298
|
-
currentScope = null;
|
|
2299
|
-
}
|
|
2300
|
-
currentScope = new Scope(getActiveScope());
|
|
2301
|
-
runInScope(currentScope, () => {
|
|
2302
|
-
let threwPromise = null;
|
|
2303
|
-
let rendered = null;
|
|
2304
|
-
try {
|
|
2305
|
-
const SuspenseProvider = SuspenseContext.Provider;
|
|
2306
|
-
rendered = SuspenseProvider({
|
|
2307
|
-
value: suspenseValue,
|
|
2308
|
-
children: props.children
|
|
2309
|
-
});
|
|
2310
|
-
} catch (err) {
|
|
2311
|
-
if (err && typeof err.then === "function") {
|
|
2312
|
-
threwPromise = err;
|
|
2313
|
-
suspenseValue.registerPromise(err);
|
|
2314
|
-
} else {
|
|
2315
|
-
throw err;
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2318
|
-
if (pendingCount() > 0 || threwPromise) {
|
|
2319
|
-
renderContent(props.fallback);
|
|
2320
|
-
} else {
|
|
2321
|
-
renderContent(rendered);
|
|
2322
|
-
}
|
|
2323
|
-
});
|
|
2324
|
-
});
|
|
2325
|
-
isMounted = true;
|
|
2326
|
-
initialFrag.appendChild(marker);
|
|
2327
|
-
onCleanup(() => {
|
|
2328
|
-
if (currentScope)
|
|
2329
|
-
currentScope.dispose();
|
|
2330
|
-
});
|
|
2331
|
-
return initialFrag;
|
|
2332
|
-
}
|
|
2333
|
-
function ErrorBoundary(props) {
|
|
2334
|
-
if (typeof document === "undefined") {
|
|
2335
|
-
try {
|
|
2336
|
-
return typeof props.children === "function" ? props.children() : props.children;
|
|
2337
|
-
} catch (err) {
|
|
2338
|
-
return typeof props.fallback === "function" ? props.fallback(err, () => {}) : props.fallback;
|
|
2339
|
-
}
|
|
2340
|
-
}
|
|
2341
|
-
const marker = document.createTextNode("");
|
|
2342
|
-
const initialFrag = document.createDocumentFragment();
|
|
2343
|
-
const currentError = signal(null);
|
|
2344
|
-
let currentScope = null;
|
|
2345
|
-
let currentNodes = [];
|
|
2346
|
-
let isMounted = false;
|
|
2347
|
-
const reset = () => {
|
|
2348
|
-
currentError.set(null);
|
|
2349
|
-
};
|
|
2350
|
-
const renderNodes = (child) => {
|
|
2351
|
-
const parent = marker.parentNode ?? (!isMounted ? initialFrag : null);
|
|
2352
|
-
if (!parent)
|
|
2353
|
-
return;
|
|
2354
|
-
for (const n of currentNodes) {
|
|
2355
|
-
if (n.parentNode)
|
|
2356
|
-
n.parentNode.removeChild(n);
|
|
2357
|
-
}
|
|
2358
|
-
currentNodes = [];
|
|
2359
|
-
const frag = document.createDocumentFragment();
|
|
2360
|
-
insertChild(frag, child);
|
|
2361
|
-
currentNodes = Array.from(frag.childNodes);
|
|
2362
|
-
if (marker.parentNode) {
|
|
2363
|
-
marker.parentNode.insertBefore(frag, marker);
|
|
2364
|
-
} else if (!isMounted) {
|
|
2365
|
-
initialFrag.appendChild(frag);
|
|
2366
|
-
}
|
|
2367
|
-
};
|
|
2368
|
-
effect(() => {
|
|
2369
|
-
const err = currentError();
|
|
2370
|
-
if (currentScope) {
|
|
2371
|
-
currentScope.dispose();
|
|
2372
|
-
currentScope = null;
|
|
2373
|
-
}
|
|
2374
|
-
currentScope = new Scope(getActiveScope());
|
|
2375
|
-
runInScope(currentScope, () => {
|
|
2376
|
-
if (err !== null) {
|
|
2377
|
-
const fallbackNode = typeof props.fallback === "function" ? props.fallback(err, reset) : props.fallback;
|
|
2378
|
-
renderNodes(fallbackNode);
|
|
2379
|
-
} else {
|
|
2380
|
-
try {
|
|
2381
|
-
const content = typeof props.children === "function" ? props.children() : props.children;
|
|
2382
|
-
renderNodes(content);
|
|
2383
|
-
} catch (catchedErr) {
|
|
2384
|
-
currentError.set(catchedErr);
|
|
2385
|
-
}
|
|
2386
|
-
}
|
|
2387
|
-
});
|
|
2388
|
-
});
|
|
2389
|
-
isMounted = true;
|
|
2390
|
-
initialFrag.appendChild(marker);
|
|
2391
|
-
onCleanup(() => {
|
|
2392
|
-
if (currentScope)
|
|
2393
|
-
currentScope.dispose();
|
|
2394
|
-
});
|
|
2395
|
-
return initialFrag;
|
|
2396
|
-
}
|
|
2397
|
-
|
|
2398
|
-
// src/query/create-query.ts
|
|
2399
|
-
function createQuery(options, client) {
|
|
2400
|
-
const queryClient = useQueryClient(client);
|
|
2401
|
-
const resolveOptions = () => typeof options === "function" ? options() : options;
|
|
2402
|
-
const currentQuery = signal(null);
|
|
2403
|
-
const version = signal(0);
|
|
2404
|
-
let activeObserver = null;
|
|
2405
|
-
let intervalTimer = null;
|
|
2406
|
-
const clearIntervalTimer = () => {
|
|
2407
|
-
if (intervalTimer !== null) {
|
|
2408
|
-
clearInterval(intervalTimer);
|
|
2409
|
-
intervalTimer = null;
|
|
2410
|
-
}
|
|
2411
|
-
};
|
|
2412
|
-
effect(() => {
|
|
2413
|
-
const rawOpts = resolveOptions();
|
|
2414
|
-
const defaults = queryClient.getDefaultOptions().queries ?? {};
|
|
2415
|
-
const mergedOpts = {
|
|
2416
|
-
...defaults,
|
|
2417
|
-
...rawOpts
|
|
2418
|
-
};
|
|
2419
|
-
const isEnabled = typeof mergedOpts.enabled === "function" ? mergedOpts.enabled() : mergedOpts.enabled !== false;
|
|
2420
|
-
const targetQuery = queryClient.queryCache.build(queryClient, mergedOpts);
|
|
2421
|
-
if (untrack(currentQuery) !== targetQuery || !activeObserver) {
|
|
2422
|
-
const prevQ = untrack(currentQuery);
|
|
2423
|
-
if (prevQ && activeObserver) {
|
|
2424
|
-
prevQ.removeObserver(activeObserver);
|
|
2425
|
-
}
|
|
2426
|
-
const observer = {
|
|
2427
|
-
options: mergedOpts,
|
|
2428
|
-
onQueryUpdate: () => {
|
|
2429
|
-
version.update((v) => v + 1);
|
|
2430
|
-
}
|
|
2431
|
-
};
|
|
2432
|
-
targetQuery.addObserver(observer);
|
|
2433
|
-
activeObserver = observer;
|
|
2434
|
-
currentQuery.set(targetQuery);
|
|
2435
|
-
} else if (activeObserver) {
|
|
2436
|
-
activeObserver.options = mergedOpts;
|
|
2437
|
-
}
|
|
2438
|
-
clearIntervalTimer();
|
|
2439
|
-
const refetchInterval = typeof mergedOpts.refetchInterval === "function" ? mergedOpts.refetchInterval() : mergedOpts.refetchInterval;
|
|
2440
|
-
if (refetchInterval && refetchInterval > 0) {
|
|
2441
|
-
intervalTimer = setInterval(() => {
|
|
2442
|
-
if (focusManager.isFocused() || mergedOpts.refetchIntervalInBackground) {
|
|
2443
|
-
targetQuery.fetch(mergedOpts).catch(() => {});
|
|
2444
|
-
}
|
|
2445
|
-
}, refetchInterval);
|
|
2446
|
-
}
|
|
2447
|
-
if (isEnabled) {
|
|
2448
|
-
untrack(() => {
|
|
2449
|
-
if (targetQuery.isStale(mergedOpts.staleTime) && targetQuery.fetchStatus() === "idle") {
|
|
2450
|
-
const fetchPromise = targetQuery.fetch(mergedOpts);
|
|
2451
|
-
fetchPromise.catch(() => {});
|
|
2452
|
-
const suspense = useContext(SuspenseContext);
|
|
2453
|
-
if (suspense) {
|
|
2454
|
-
suspense.registerPromise(fetchPromise);
|
|
2455
|
-
}
|
|
2456
|
-
}
|
|
2457
|
-
});
|
|
2458
|
-
}
|
|
2459
|
-
});
|
|
2460
|
-
onCleanup(() => {
|
|
2461
|
-
clearIntervalTimer();
|
|
2462
|
-
if (currentQuery() && activeObserver) {
|
|
2463
|
-
currentQuery().removeObserver(activeObserver);
|
|
2464
|
-
}
|
|
2465
|
-
});
|
|
2466
|
-
const data = computed(() => {
|
|
2467
|
-
version();
|
|
2468
|
-
const q = currentQuery();
|
|
2469
|
-
const rawOpts = resolveOptions();
|
|
2470
|
-
const rawData = q?.data();
|
|
2471
|
-
if (rawData !== undefined) {
|
|
2472
|
-
if (rawOpts.select) {
|
|
2473
|
-
return rawOpts.select(rawData);
|
|
2474
|
-
}
|
|
2475
|
-
return rawData;
|
|
2476
|
-
}
|
|
2477
|
-
if (rawOpts.placeholderData !== undefined) {
|
|
2478
|
-
return typeof rawOpts.placeholderData === "function" ? rawOpts.placeholderData(undefined) : rawOpts.placeholderData;
|
|
2479
|
-
}
|
|
2480
|
-
return;
|
|
2481
|
-
});
|
|
2482
|
-
const error = computed(() => {
|
|
2483
|
-
version();
|
|
2484
|
-
return currentQuery()?.error() ?? null;
|
|
2485
|
-
});
|
|
2486
|
-
const status = computed(() => {
|
|
2487
|
-
version();
|
|
2488
|
-
return currentQuery()?.status() ?? "pending";
|
|
2489
|
-
});
|
|
2490
|
-
const fetchStatus = computed(() => {
|
|
2491
|
-
version();
|
|
2492
|
-
return currentQuery()?.fetchStatus() ?? "idle";
|
|
2493
|
-
});
|
|
2494
|
-
const isLoading = computed(() => {
|
|
2495
|
-
return status() === "pending" && fetchStatus() === "fetching";
|
|
2496
|
-
});
|
|
2497
|
-
const isFetching = computed(() => {
|
|
2498
|
-
return fetchStatus() === "fetching";
|
|
2499
|
-
});
|
|
2500
|
-
const isSuccess = computed(() => {
|
|
2501
|
-
return status() === "success";
|
|
2502
|
-
});
|
|
2503
|
-
const isError = computed(() => {
|
|
2504
|
-
return status() === "error";
|
|
2505
|
-
});
|
|
2506
|
-
const isStale = computed(() => {
|
|
2507
|
-
version();
|
|
2508
|
-
const q = currentQuery();
|
|
2509
|
-
const rawOpts = resolveOptions();
|
|
2510
|
-
return q?.isStale(rawOpts.staleTime) ?? true;
|
|
2511
|
-
});
|
|
2512
|
-
const dataUpdatedAt = computed(() => {
|
|
2513
|
-
version();
|
|
2514
|
-
return currentQuery()?.dataUpdatedAt() ?? 0;
|
|
2515
|
-
});
|
|
2516
|
-
const errorUpdatedAt = computed(() => {
|
|
2517
|
-
version();
|
|
2518
|
-
return currentQuery()?.errorUpdatedAt() ?? 0;
|
|
2519
|
-
});
|
|
2520
|
-
const refetch = async (refetchOpts) => {
|
|
2521
|
-
const q = untrack(() => currentQuery());
|
|
2522
|
-
if (!q)
|
|
2523
|
-
return;
|
|
2524
|
-
const rawOpts = resolveOptions();
|
|
2525
|
-
const defaults = queryClient.getDefaultOptions().queries ?? {};
|
|
2526
|
-
const mergedOpts = { ...defaults, ...rawOpts };
|
|
2527
|
-
const rawResult = await q.fetch(mergedOpts, { cancelRefetch: refetchOpts?.cancelRefetch });
|
|
2528
|
-
if (rawOpts.select) {
|
|
2529
|
-
return rawOpts.select(rawResult);
|
|
2530
|
-
}
|
|
2531
|
-
return rawResult;
|
|
2532
|
-
};
|
|
2533
|
-
const accessor = () => {
|
|
2534
|
-
const q = currentQuery();
|
|
2535
|
-
const rawOpts = resolveOptions();
|
|
2536
|
-
if ((rawOpts.suspense || status() === "pending") && q?.promise) {
|
|
2537
|
-
const suspense = useContext(SuspenseContext);
|
|
2538
|
-
if (suspense) {
|
|
2539
|
-
suspense.registerPromise(q.promise);
|
|
2540
|
-
}
|
|
2541
|
-
}
|
|
2542
|
-
return data();
|
|
2543
|
-
};
|
|
2544
|
-
Object.defineProperties(accessor, {
|
|
2545
|
-
[SIGNAL_BRAND]: { value: true },
|
|
2546
|
-
[COMPUTED_BRAND]: { value: true },
|
|
2547
|
-
value: { get: () => data() },
|
|
2548
|
-
data: { get: () => data },
|
|
2549
|
-
error: { get: () => error },
|
|
2550
|
-
status: { get: () => status },
|
|
2551
|
-
fetchStatus: { get: () => fetchStatus },
|
|
2552
|
-
isLoading: { get: () => isLoading },
|
|
2553
|
-
isFetching: { get: () => isFetching },
|
|
2554
|
-
isSuccess: { get: () => isSuccess },
|
|
2555
|
-
isError: { get: () => isError },
|
|
2556
|
-
isStale: { get: () => isStale },
|
|
2557
|
-
dataUpdatedAt: { get: () => dataUpdatedAt },
|
|
2558
|
-
errorUpdatedAt: { get: () => errorUpdatedAt },
|
|
2559
|
-
refetch: { value: refetch }
|
|
2560
|
-
});
|
|
2561
|
-
return accessor;
|
|
2562
|
-
}
|
|
2563
|
-
function createInfiniteQuery(options, client) {
|
|
2564
|
-
const queryClient = useQueryClient(client);
|
|
2565
|
-
const resolveOptions = () => typeof options === "function" ? options() : options;
|
|
2566
|
-
const isFetchingNextPage = signal(false);
|
|
2567
|
-
const isFetchingPreviousPage = signal(false);
|
|
2568
|
-
const baseQuery = createQuery(() => {
|
|
2569
|
-
const rawOpts = resolveOptions();
|
|
2570
|
-
return {
|
|
2571
|
-
...rawOpts,
|
|
2572
|
-
queryFn: async (ctx) => {
|
|
2573
|
-
const pageParam = ctx.pageParam ?? rawOpts.initialPageParam;
|
|
2574
|
-
const page = await rawOpts.queryFn({
|
|
2575
|
-
...ctx,
|
|
2576
|
-
pageParam
|
|
2577
|
-
});
|
|
2578
|
-
return {
|
|
2579
|
-
pages: [page],
|
|
2580
|
-
pageParams: [pageParam]
|
|
2581
|
-
};
|
|
2582
|
-
},
|
|
2583
|
-
select: undefined
|
|
2584
|
-
};
|
|
2585
|
-
}, queryClient);
|
|
2586
|
-
const hasNextPage = computed(() => {
|
|
2587
|
-
const current = baseQuery.data();
|
|
2588
|
-
if (!current || current.pages.length === 0)
|
|
2589
|
-
return false;
|
|
2590
|
-
const rawOpts = resolveOptions();
|
|
2591
|
-
const lastPage = current.pages[current.pages.length - 1];
|
|
2592
|
-
const lastParam = current.pageParams[current.pageParams.length - 1];
|
|
2593
|
-
const nextParam = rawOpts.getNextPageParam(lastPage, current.pages, lastParam, current.pageParams);
|
|
2594
|
-
return nextParam !== undefined && nextParam !== null;
|
|
2595
|
-
});
|
|
2596
|
-
const hasPreviousPage = computed(() => {
|
|
2597
|
-
const current = baseQuery.data();
|
|
2598
|
-
if (!current || current.pages.length === 0)
|
|
2599
|
-
return false;
|
|
2600
|
-
const rawOpts = resolveOptions();
|
|
2601
|
-
if (!rawOpts.getPreviousPageParam)
|
|
2602
|
-
return false;
|
|
2603
|
-
const firstPage = current.pages[0];
|
|
2604
|
-
const firstParam = current.pageParams[0];
|
|
2605
|
-
const prevParam = rawOpts.getPreviousPageParam(firstPage, current.pages, firstParam, current.pageParams);
|
|
2606
|
-
return prevParam !== undefined && prevParam !== null;
|
|
2607
|
-
});
|
|
2608
|
-
const fetchNextPage = async () => {
|
|
2609
|
-
const current = baseQuery.data();
|
|
2610
|
-
if (!current || current.pages.length === 0)
|
|
2611
|
-
return;
|
|
2612
|
-
const rawOpts = resolveOptions();
|
|
2613
|
-
const lastPage = current.pages[current.pages.length - 1];
|
|
2614
|
-
const lastParam = current.pageParams[current.pageParams.length - 1];
|
|
2615
|
-
const nextParam = rawOpts.getNextPageParam(lastPage, current.pages, lastParam, current.pageParams);
|
|
2616
|
-
if (nextParam === undefined || nextParam === null) {
|
|
2617
|
-
return current;
|
|
2618
|
-
}
|
|
2619
|
-
isFetchingNextPage.set(true);
|
|
2620
|
-
try {
|
|
2621
|
-
const newPage = await rawOpts.queryFn({
|
|
2622
|
-
queryKey: rawOpts.queryKey,
|
|
2623
|
-
signal: new AbortController().signal,
|
|
2624
|
-
pageParam: nextParam,
|
|
2625
|
-
meta: rawOpts.meta
|
|
2626
|
-
});
|
|
2627
|
-
const nextData = {
|
|
2628
|
-
pages: [...current.pages, newPage],
|
|
2629
|
-
pageParams: [...current.pageParams, nextParam]
|
|
2630
|
-
};
|
|
2631
|
-
queryClient.setQueryData(rawOpts.queryKey, nextData);
|
|
2632
|
-
return nextData;
|
|
2633
|
-
} finally {
|
|
2634
|
-
isFetchingNextPage.set(false);
|
|
2635
|
-
}
|
|
2636
|
-
};
|
|
2637
|
-
const fetchPreviousPage = async () => {
|
|
2638
|
-
const current = baseQuery.data();
|
|
2639
|
-
if (!current || current.pages.length === 0)
|
|
2640
|
-
return;
|
|
2641
|
-
const rawOpts = resolveOptions();
|
|
2642
|
-
if (!rawOpts.getPreviousPageParam)
|
|
2643
|
-
return current;
|
|
2644
|
-
const firstPage = current.pages[0];
|
|
2645
|
-
const firstParam = current.pageParams[0];
|
|
2646
|
-
const prevParam = rawOpts.getPreviousPageParam(firstPage, current.pages, firstParam, current.pageParams);
|
|
2647
|
-
if (prevParam === undefined || prevParam === null) {
|
|
2648
|
-
return current;
|
|
2649
|
-
}
|
|
2650
|
-
isFetchingPreviousPage.set(true);
|
|
2651
|
-
try {
|
|
2652
|
-
const newPage = await rawOpts.queryFn({
|
|
2653
|
-
queryKey: rawOpts.queryKey,
|
|
2654
|
-
signal: new AbortController().signal,
|
|
2655
|
-
pageParam: prevParam,
|
|
2656
|
-
meta: rawOpts.meta
|
|
2657
|
-
});
|
|
2658
|
-
const nextData = {
|
|
2659
|
-
pages: [newPage, ...current.pages],
|
|
2660
|
-
pageParams: [prevParam, ...current.pageParams]
|
|
2661
|
-
};
|
|
2662
|
-
queryClient.setQueryData(rawOpts.queryKey, nextData);
|
|
2663
|
-
return nextData;
|
|
2664
|
-
} finally {
|
|
2665
|
-
isFetchingPreviousPage.set(false);
|
|
2666
|
-
}
|
|
2667
|
-
};
|
|
2668
|
-
const accessor = () => {
|
|
2669
|
-
return baseQuery();
|
|
2670
|
-
};
|
|
2671
|
-
Object.defineProperties(accessor, {
|
|
2672
|
-
[SIGNAL_BRAND]: { value: true },
|
|
2673
|
-
[COMPUTED_BRAND]: { value: true },
|
|
2674
|
-
value: { get: () => baseQuery.data() },
|
|
2675
|
-
data: { get: () => baseQuery.data },
|
|
2676
|
-
error: { get: () => baseQuery.error },
|
|
2677
|
-
status: { get: () => baseQuery.status },
|
|
2678
|
-
fetchStatus: { get: () => baseQuery.fetchStatus },
|
|
2679
|
-
isLoading: { get: () => baseQuery.isLoading },
|
|
2680
|
-
isFetching: { get: () => baseQuery.isFetching },
|
|
2681
|
-
isSuccess: { get: () => baseQuery.isSuccess },
|
|
2682
|
-
isError: { get: () => baseQuery.isError },
|
|
2683
|
-
isStale: { get: () => baseQuery.isStale },
|
|
2684
|
-
dataUpdatedAt: { get: () => baseQuery.dataUpdatedAt },
|
|
2685
|
-
errorUpdatedAt: { get: () => baseQuery.errorUpdatedAt },
|
|
2686
|
-
refetch: { value: baseQuery.refetch },
|
|
2687
|
-
fetchNextPage: { value: fetchNextPage },
|
|
2688
|
-
fetchPreviousPage: { value: fetchPreviousPage },
|
|
2689
|
-
hasNextPage: { get: () => hasNextPage },
|
|
2690
|
-
hasPreviousPage: { get: () => hasPreviousPage },
|
|
2691
|
-
isFetchingNextPage: { get: () => isFetchingNextPage },
|
|
2692
|
-
isFetchingPreviousPage: { get: () => isFetchingPreviousPage }
|
|
2693
|
-
});
|
|
2694
|
-
return accessor;
|
|
2695
|
-
}
|
|
2696
|
-
|
|
2697
|
-
// src/rpc/error.ts
|
|
2698
|
-
var ERROR_CODE_TO_STATUS = {
|
|
2699
|
-
BAD_REQUEST: 400,
|
|
2700
|
-
UNAUTHORIZED: 401,
|
|
2701
|
-
FORBIDDEN: 403,
|
|
2702
|
-
NOT_FOUND: 404,
|
|
2703
|
-
METHOD_NOT_ALLOWED: 405,
|
|
2704
|
-
TIMEOUT: 408,
|
|
2705
|
-
CONFLICT: 409,
|
|
2706
|
-
UNPROCESSABLE_CONTENT: 422,
|
|
2707
|
-
INTERNAL_SERVER_ERROR: 500
|
|
2708
|
-
};
|
|
2709
|
-
var STATUS_TO_ERROR_CODE = {
|
|
2710
|
-
400: "BAD_REQUEST",
|
|
2711
|
-
401: "UNAUTHORIZED",
|
|
2712
|
-
403: "FORBIDDEN",
|
|
2713
|
-
404: "NOT_FOUND",
|
|
2714
|
-
405: "METHOD_NOT_ALLOWED",
|
|
2715
|
-
408: "TIMEOUT",
|
|
2716
|
-
409: "CONFLICT",
|
|
2717
|
-
422: "UNPROCESSABLE_CONTENT",
|
|
2718
|
-
500: "INTERNAL_SERVER_ERROR"
|
|
2719
|
-
};
|
|
2720
|
-
|
|
2721
|
-
class RPCError extends Error {
|
|
2722
|
-
code;
|
|
2723
|
-
status;
|
|
2724
|
-
issues;
|
|
2725
|
-
constructor(codeOrStatusOrOptions, message) {
|
|
2726
|
-
if (typeof codeOrStatusOrOptions === "number") {
|
|
2727
|
-
const code = STATUS_TO_ERROR_CODE[codeOrStatusOrOptions] || "INTERNAL_SERVER_ERROR";
|
|
2728
|
-
super(message || code);
|
|
2729
|
-
this.name = "RPCError";
|
|
2730
|
-
this.code = code;
|
|
2731
|
-
this.status = codeOrStatusOrOptions;
|
|
2732
|
-
} else if (typeof codeOrStatusOrOptions === "string") {
|
|
2733
|
-
super(message || codeOrStatusOrOptions);
|
|
2734
|
-
this.name = "RPCError";
|
|
2735
|
-
this.code = codeOrStatusOrOptions;
|
|
2736
|
-
this.status = ERROR_CODE_TO_STATUS[codeOrStatusOrOptions] || 500;
|
|
2737
|
-
} else {
|
|
2738
|
-
super(codeOrStatusOrOptions.message ?? codeOrStatusOrOptions.code, {
|
|
2739
|
-
cause: codeOrStatusOrOptions.cause
|
|
2740
|
-
});
|
|
2741
|
-
this.name = "RPCError";
|
|
2742
|
-
this.code = codeOrStatusOrOptions.code;
|
|
2743
|
-
this.status = ERROR_CODE_TO_STATUS[codeOrStatusOrOptions.code] ?? 500;
|
|
2744
|
-
this.issues = codeOrStatusOrOptions.issues;
|
|
2745
|
-
}
|
|
2746
|
-
}
|
|
2747
|
-
get statusCode() {
|
|
2748
|
-
return this.status;
|
|
2749
|
-
}
|
|
2750
|
-
}
|
|
2751
|
-
|
|
2752
|
-
// src/rpc/procedure.ts
|
|
2753
|
-
function createProcedure(type, options, middlewares = []) {
|
|
2754
|
-
return {
|
|
2755
|
-
type,
|
|
2756
|
-
inputSchema: options.input,
|
|
2757
|
-
outputSchema: options.output,
|
|
2758
|
-
middlewares: [...middlewares],
|
|
2759
|
-
resolve: options.resolve
|
|
2760
|
-
};
|
|
2761
|
-
}
|
|
2762
|
-
async function executeProcedure(procedure, opts) {
|
|
2763
|
-
let input = opts.rawInput;
|
|
2764
|
-
if (procedure.inputSchema) {
|
|
2765
|
-
const res = validateWithSchema(procedure.inputSchema, opts.rawInput);
|
|
2766
|
-
if (!res.success) {
|
|
2767
|
-
throw new RPCError({
|
|
2768
|
-
code: "BAD_REQUEST",
|
|
2769
|
-
message: "Invalid procedure input",
|
|
2770
|
-
issues: res.issues
|
|
2771
|
-
});
|
|
2772
|
-
}
|
|
2773
|
-
input = res.data;
|
|
2774
|
-
}
|
|
2775
|
-
let currentIndex = 0;
|
|
2776
|
-
let currentContext = opts.ctx;
|
|
2777
|
-
const runPipeline = async (ctx) => {
|
|
2778
|
-
currentContext = ctx;
|
|
2779
|
-
if (currentIndex < procedure.middlewares.length) {
|
|
2780
|
-
const mw = procedure.middlewares[currentIndex++];
|
|
2781
|
-
return mw({
|
|
2782
|
-
ctx: currentContext,
|
|
2783
|
-
req: opts.req,
|
|
2784
|
-
signal: opts.signal,
|
|
2785
|
-
next: async (nextOpts) => {
|
|
2786
|
-
return runPipeline(nextOpts?.ctx ?? currentContext);
|
|
2787
|
-
}
|
|
2788
|
-
});
|
|
2789
|
-
}
|
|
2790
|
-
return procedure.resolve({
|
|
2791
|
-
input,
|
|
2792
|
-
ctx: currentContext,
|
|
2793
|
-
req: opts.req,
|
|
2794
|
-
signal: opts.signal
|
|
2795
|
-
});
|
|
2796
|
-
};
|
|
2797
|
-
const output = await runPipeline(currentContext);
|
|
2798
|
-
if (procedure.outputSchema && procedure.type !== "subscription") {
|
|
2799
|
-
const res = validateWithSchema(procedure.outputSchema, output);
|
|
2800
|
-
if (!res.success) {
|
|
2801
|
-
throw new RPCError({
|
|
2802
|
-
code: "INTERNAL_SERVER_ERROR",
|
|
2803
|
-
message: "Invalid procedure output",
|
|
2804
|
-
issues: res.issues
|
|
2805
|
-
});
|
|
2806
|
-
}
|
|
2807
|
-
return res.data;
|
|
2808
|
-
}
|
|
2809
|
-
return output;
|
|
2810
|
-
}
|
|
2811
|
-
|
|
2812
|
-
// src/rpc/server.ts
|
|
2813
|
-
function getCORSHeaders(cors, req) {
|
|
2814
|
-
const headers = new Headers;
|
|
2815
|
-
if (!cors)
|
|
2816
|
-
return headers;
|
|
2817
|
-
const opts = typeof cors === "object" ? cors : {};
|
|
2818
|
-
const originHeader = req.headers.get("origin") ?? "*";
|
|
2819
|
-
let allowOrigin = "*";
|
|
2820
|
-
if (typeof opts.origin === "function") {
|
|
2821
|
-
const res = opts.origin(originHeader);
|
|
2822
|
-
if (typeof res === "string")
|
|
2823
|
-
allowOrigin = res;
|
|
2824
|
-
else if (res)
|
|
2825
|
-
allowOrigin = originHeader;
|
|
2826
|
-
} else if (typeof opts.origin === "string") {
|
|
2827
|
-
allowOrigin = opts.origin;
|
|
2828
|
-
} else if (Array.isArray(opts.origin)) {
|
|
2829
|
-
if (opts.origin.includes(originHeader))
|
|
2830
|
-
allowOrigin = originHeader;
|
|
2831
|
-
} else {
|
|
2832
|
-
allowOrigin = originHeader || "*";
|
|
2833
|
-
}
|
|
2834
|
-
headers.set("Access-Control-Allow-Origin", allowOrigin);
|
|
2835
|
-
headers.set("Access-Control-Allow-Methods", (opts.methods ?? ["GET", "POST", "OPTIONS", "HEAD"]).join(", "));
|
|
2836
|
-
headers.set("Access-Control-Allow-Headers", (opts.allowedHeaders ?? ["Content-Type", "Authorization", "X-Requested-With"]).join(", "));
|
|
2837
|
-
if (opts.exposedHeaders) {
|
|
2838
|
-
headers.set("Access-Control-Expose-Headers", opts.exposedHeaders.join(", "));
|
|
2839
|
-
}
|
|
2840
|
-
if (opts.credentials) {
|
|
2841
|
-
headers.set("Access-Control-Allow-Credentials", "true");
|
|
2842
|
-
}
|
|
2843
|
-
if (opts.maxAge !== undefined) {
|
|
2844
|
-
headers.set("Access-Control-Max-Age", opts.maxAge.toString());
|
|
2845
|
-
}
|
|
2846
|
-
return headers;
|
|
2847
|
-
}
|
|
2848
|
-
function resolveProcedureFromPath(router, path) {
|
|
2849
|
-
const parts = path.split(/[./]/).filter(Boolean);
|
|
2850
|
-
let current = router._def.record;
|
|
2851
|
-
for (let i = 0;i < parts.length; i++) {
|
|
2852
|
-
const part = parts[i];
|
|
2853
|
-
if (!current || typeof current !== "object") {
|
|
2854
|
-
throw new RPCError({
|
|
2855
|
-
code: "NOT_FOUND",
|
|
2856
|
-
message: `Procedure '${path}' not found`
|
|
2857
|
-
});
|
|
2858
|
-
}
|
|
2859
|
-
if (i === parts.length - 1) {
|
|
2860
|
-
if (part in current && "type" in current[part]) {
|
|
2861
|
-
return current[part];
|
|
2862
|
-
}
|
|
2863
|
-
throw new RPCError({
|
|
2864
|
-
code: "NOT_FOUND",
|
|
2865
|
-
message: `Procedure '${path}' not found`
|
|
2866
|
-
});
|
|
2867
|
-
}
|
|
2868
|
-
if (part in current && "_def" in current[part]) {
|
|
2869
|
-
current = current[part]._def.record;
|
|
2870
|
-
} else if (part in current && typeof current[part] === "object") {
|
|
2871
|
-
current = current[part];
|
|
2872
|
-
} else {
|
|
2873
|
-
throw new RPCError({
|
|
2874
|
-
code: "NOT_FOUND",
|
|
2875
|
-
message: `Procedure '${path}' not found`
|
|
2876
|
-
});
|
|
2877
|
-
}
|
|
2878
|
-
}
|
|
2879
|
-
throw new RPCError({
|
|
2880
|
-
code: "NOT_FOUND",
|
|
2881
|
-
message: `Procedure '${path}' not found`
|
|
2882
|
-
});
|
|
2883
|
-
}
|
|
2884
|
-
function matchesRulePattern(pattern, urlPath, procedurePath) {
|
|
2885
|
-
if (pattern === "*")
|
|
2886
|
-
return true;
|
|
2887
|
-
const cleanUrl = urlPath.replace(/^\/+|\/+$/g, "");
|
|
2888
|
-
const cleanPattern = pattern.replace(/^\/+|\/+$/g, "");
|
|
2889
|
-
const cleanProc = procedurePath.replace(/^\/+|\/+$/g, "");
|
|
2890
|
-
if (cleanUrl === cleanPattern || cleanProc === cleanPattern || cleanProc === cleanPattern.replace(/\//g, ".")) {
|
|
2891
|
-
return true;
|
|
2892
|
-
}
|
|
2893
|
-
if (cleanPattern.endsWith("*")) {
|
|
2894
|
-
const prefix = cleanPattern.slice(0, -1);
|
|
2895
|
-
if (cleanUrl.startsWith(prefix) || cleanProc.startsWith(prefix)) {
|
|
2896
|
-
return true;
|
|
2897
|
-
}
|
|
2898
|
-
const dotPrefix = prefix.replace(/\//g, ".");
|
|
2899
|
-
if (cleanProc.startsWith(dotPrefix)) {
|
|
2900
|
-
return true;
|
|
2901
|
-
}
|
|
2902
|
-
}
|
|
2903
|
-
try {
|
|
2904
|
-
const regexStr = cleanPattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
2905
|
-
const regex = new RegExp(`^${regexStr}$`);
|
|
2906
|
-
return regex.test(cleanUrl) || regex.test(cleanProc);
|
|
2907
|
-
} catch {
|
|
2908
|
-
return false;
|
|
2909
|
-
}
|
|
2910
|
-
}
|
|
2911
|
-
function createFetchHandler(options) {
|
|
2912
|
-
const {
|
|
2913
|
-
router,
|
|
2914
|
-
endpoint = "",
|
|
2915
|
-
createContext,
|
|
2916
|
-
onError,
|
|
2917
|
-
cors = true,
|
|
2918
|
-
securityHeaders = true,
|
|
2919
|
-
rules
|
|
2920
|
-
} = options;
|
|
2921
|
-
return async (request, ...extra) => {
|
|
2922
|
-
const corsHeaders = getCORSHeaders(cors, request);
|
|
2923
|
-
if (request.method === "OPTIONS") {
|
|
2924
|
-
return new Response(null, {
|
|
2925
|
-
status: 204,
|
|
2926
|
-
headers: corsHeaders
|
|
2927
|
-
});
|
|
2928
|
-
}
|
|
2929
|
-
const baseHeaders = new Headers(corsHeaders);
|
|
2930
|
-
if (securityHeaders) {
|
|
2931
|
-
if (typeof securityHeaders === "object") {
|
|
2932
|
-
for (const [k, v] of Object.entries(securityHeaders)) {
|
|
2933
|
-
baseHeaders.set(k, v);
|
|
2934
|
-
}
|
|
2935
|
-
} else {
|
|
2936
|
-
baseHeaders.set("X-Content-Type-Options", "nosniff");
|
|
2937
|
-
}
|
|
2938
|
-
}
|
|
2939
|
-
const url = new URL(request.url);
|
|
2940
|
-
let pathname = url.pathname;
|
|
2941
|
-
if (endpoint && pathname.startsWith(endpoint)) {
|
|
2942
|
-
pathname = pathname.slice(endpoint.length);
|
|
2943
|
-
}
|
|
2944
|
-
pathname = pathname.replace(/^\/+|\/+$/g, "");
|
|
2945
|
-
const procedurePath = pathname || url.searchParams.get("procedure") || "";
|
|
2946
|
-
let ctx = {};
|
|
2947
|
-
try {
|
|
2948
|
-
if (createContext) {
|
|
2949
|
-
ctx = await createContext({ req: request, extra });
|
|
2950
|
-
}
|
|
2951
|
-
} catch (err) {
|
|
2952
|
-
const error = err instanceof RPCError ? err : new RPCError({
|
|
2953
|
-
code: "UNAUTHORIZED",
|
|
2954
|
-
message: err.message ?? "Context initialization failed",
|
|
2955
|
-
cause: err
|
|
2956
|
-
});
|
|
2957
|
-
onError?.({ error, req: request });
|
|
2958
|
-
baseHeaders.set("Content-Type", "application/json");
|
|
2959
|
-
return new Response(JSON.stringify({
|
|
2960
|
-
error: {
|
|
2961
|
-
code: error.code,
|
|
2962
|
-
message: error.message,
|
|
2963
|
-
issues: error.issues
|
|
2964
|
-
}
|
|
2965
|
-
}), {
|
|
2966
|
-
status: error.status,
|
|
2967
|
-
headers: baseHeaders
|
|
2968
|
-
});
|
|
2969
|
-
}
|
|
2970
|
-
const rulesList = [];
|
|
2971
|
-
if (rules) {
|
|
2972
|
-
if (Array.isArray(rules)) {
|
|
2973
|
-
rulesList.push(...rules);
|
|
2974
|
-
} else {
|
|
2975
|
-
for (const [match, rule] of Object.entries(rules)) {
|
|
2976
|
-
rulesList.push({ match, ...rule });
|
|
2977
|
-
}
|
|
2978
|
-
}
|
|
2979
|
-
}
|
|
2980
|
-
const matchingRules = rulesList.filter((r) => matchesRulePattern(r.match, url.pathname, procedurePath));
|
|
2981
|
-
for (const rule of matchingRules) {
|
|
2982
|
-
if (rule.requireHeaders) {
|
|
2983
|
-
for (const headerName of rule.requireHeaders) {
|
|
2984
|
-
if (!request.headers.get(headerName)) {
|
|
2985
|
-
const error = new RPCError({
|
|
2986
|
-
code: "UNAUTHORIZED",
|
|
2987
|
-
message: `Missing required header '${headerName}' for rule '${rule.match}'`
|
|
2988
|
-
});
|
|
2989
|
-
onError?.({ error, path: procedurePath, req: request });
|
|
2990
|
-
baseHeaders.set("Content-Type", "application/json");
|
|
2991
|
-
return new Response(JSON.stringify({
|
|
2992
|
-
error: {
|
|
2993
|
-
code: error.code,
|
|
2994
|
-
message: error.message
|
|
2995
|
-
}
|
|
2996
|
-
}), {
|
|
2997
|
-
status: 401,
|
|
2998
|
-
headers: baseHeaders
|
|
2999
|
-
});
|
|
3000
|
-
}
|
|
3001
|
-
}
|
|
3002
|
-
}
|
|
3003
|
-
if (rule.requireParams) {
|
|
3004
|
-
for (const paramName of rule.requireParams) {
|
|
3005
|
-
if (!url.searchParams.has(paramName)) {
|
|
3006
|
-
const error = new RPCError({
|
|
3007
|
-
code: "BAD_REQUEST",
|
|
3008
|
-
message: `Missing required query parameter '${paramName}' for rule '${rule.match}'`
|
|
3009
|
-
});
|
|
3010
|
-
onError?.({ error, path: procedurePath, req: request });
|
|
3011
|
-
baseHeaders.set("Content-Type", "application/json");
|
|
3012
|
-
return new Response(JSON.stringify({
|
|
3013
|
-
error: {
|
|
3014
|
-
code: error.code,
|
|
3015
|
-
message: error.message
|
|
3016
|
-
}
|
|
3017
|
-
}), {
|
|
3018
|
-
status: 400,
|
|
3019
|
-
headers: baseHeaders
|
|
3020
|
-
});
|
|
3021
|
-
}
|
|
3022
|
-
}
|
|
3023
|
-
}
|
|
3024
|
-
if (rule.guard) {
|
|
3025
|
-
try {
|
|
3026
|
-
const guardResult = await rule.guard({ req: request, ctx, path: procedurePath });
|
|
3027
|
-
if (guardResult === false) {
|
|
3028
|
-
throw new RPCError({
|
|
3029
|
-
code: "UNAUTHORIZED",
|
|
3030
|
-
message: `Access denied by route rule guard for '${rule.match}'`
|
|
3031
|
-
});
|
|
3032
|
-
}
|
|
3033
|
-
} catch (err) {
|
|
3034
|
-
const error = err instanceof RPCError ? err : new RPCError({
|
|
3035
|
-
code: "UNAUTHORIZED",
|
|
3036
|
-
message: err.message ?? "Unauthorized",
|
|
3037
|
-
cause: err
|
|
3038
|
-
});
|
|
3039
|
-
onError?.({ error, path: procedurePath, req: request });
|
|
3040
|
-
baseHeaders.set("Content-Type", "application/json");
|
|
3041
|
-
return new Response(JSON.stringify({
|
|
3042
|
-
error: {
|
|
3043
|
-
code: error.code,
|
|
3044
|
-
message: error.message
|
|
3045
|
-
}
|
|
3046
|
-
}), {
|
|
3047
|
-
status: error.status,
|
|
3048
|
-
headers: baseHeaders
|
|
3049
|
-
});
|
|
3050
|
-
}
|
|
3051
|
-
}
|
|
3052
|
-
if (rule.headers) {
|
|
3053
|
-
const resHeaders = typeof rule.headers === "function" ? await rule.headers(request, ctx) : rule.headers;
|
|
3054
|
-
for (const [k, v] of Object.entries(resHeaders)) {
|
|
3055
|
-
baseHeaders.set(k, v);
|
|
3056
|
-
}
|
|
3057
|
-
}
|
|
3058
|
-
}
|
|
3059
|
-
if (request.method === "POST" && (!pathname || pathname === "batch")) {
|
|
3060
|
-
try {
|
|
3061
|
-
const body = await request.json();
|
|
3062
|
-
if (Array.isArray(body)) {
|
|
3063
|
-
const batchResults = await Promise.all(body.map(async (item) => {
|
|
3064
|
-
try {
|
|
3065
|
-
const proc = resolveProcedureFromPath(router, item.path);
|
|
3066
|
-
const data = await executeProcedure(proc, {
|
|
3067
|
-
rawInput: item.input,
|
|
3068
|
-
ctx,
|
|
3069
|
-
req: request,
|
|
3070
|
-
signal: request.signal
|
|
3071
|
-
});
|
|
3072
|
-
return {
|
|
3073
|
-
id: item.id,
|
|
3074
|
-
result: { data }
|
|
3075
|
-
};
|
|
3076
|
-
} catch (err) {
|
|
3077
|
-
const error = err instanceof RPCError ? err : new RPCError({
|
|
3078
|
-
code: "INTERNAL_SERVER_ERROR",
|
|
3079
|
-
message: err.message ?? "Internal Server Error",
|
|
3080
|
-
cause: err
|
|
3081
|
-
});
|
|
3082
|
-
onError?.({ error, path: item.path, req: request });
|
|
3083
|
-
return {
|
|
3084
|
-
id: item.id,
|
|
3085
|
-
error: {
|
|
3086
|
-
code: error.code,
|
|
3087
|
-
message: error.message,
|
|
3088
|
-
issues: error.issues
|
|
3089
|
-
}
|
|
3090
|
-
};
|
|
3091
|
-
}
|
|
3092
|
-
}));
|
|
3093
|
-
baseHeaders.set("Content-Type", "application/json");
|
|
3094
|
-
return new Response(JSON.stringify(batchResults), {
|
|
3095
|
-
status: 200,
|
|
3096
|
-
headers: baseHeaders
|
|
3097
|
-
});
|
|
3098
|
-
}
|
|
3099
|
-
} catch (err) {
|
|
3100
|
-
const error = new RPCError({
|
|
3101
|
-
code: "BAD_REQUEST",
|
|
3102
|
-
message: "Malformed batch request body",
|
|
3103
|
-
cause: err
|
|
3104
|
-
});
|
|
3105
|
-
baseHeaders.set("Content-Type", "application/json");
|
|
3106
|
-
return new Response(JSON.stringify({
|
|
3107
|
-
error: {
|
|
3108
|
-
code: error.code,
|
|
3109
|
-
message: error.message
|
|
3110
|
-
}
|
|
3111
|
-
}), {
|
|
3112
|
-
status: 400,
|
|
3113
|
-
headers: baseHeaders
|
|
3114
|
-
});
|
|
3115
|
-
}
|
|
3116
|
-
}
|
|
3117
|
-
try {
|
|
3118
|
-
const procedure = resolveProcedureFromPath(router, procedurePath);
|
|
3119
|
-
if (procedure.type === "mutation" && request.method !== "POST") {
|
|
3120
|
-
throw new RPCError({
|
|
3121
|
-
code: "METHOD_NOT_ALLOWED",
|
|
3122
|
-
message: "Mutations must use POST method"
|
|
3123
|
-
});
|
|
3124
|
-
}
|
|
3125
|
-
let rawInput;
|
|
3126
|
-
if (request.method === "GET") {
|
|
3127
|
-
const inputParam = url.searchParams.get("input");
|
|
3128
|
-
if (inputParam !== null) {
|
|
3129
|
-
try {
|
|
3130
|
-
rawInput = JSON.parse(inputParam);
|
|
3131
|
-
} catch {
|
|
3132
|
-
rawInput = inputParam;
|
|
3133
|
-
}
|
|
3134
|
-
}
|
|
3135
|
-
} else if (request.method === "POST") {
|
|
3136
|
-
try {
|
|
3137
|
-
const body = await request.json();
|
|
3138
|
-
rawInput = body && typeof body === "object" && "input" in body ? body.input : body;
|
|
3139
|
-
} catch {
|
|
3140
|
-
rawInput = undefined;
|
|
3141
|
-
}
|
|
3142
|
-
}
|
|
3143
|
-
if (procedure.type === "subscription") {
|
|
3144
|
-
const iterable = await executeProcedure(procedure, {
|
|
3145
|
-
rawInput,
|
|
3146
|
-
ctx,
|
|
3147
|
-
req: request,
|
|
3148
|
-
signal: request.signal
|
|
3149
|
-
});
|
|
3150
|
-
if (!iterable || typeof iterable[Symbol.asyncIterator] !== "function") {
|
|
3151
|
-
throw new RPCError({
|
|
3152
|
-
code: "INTERNAL_SERVER_ERROR",
|
|
3153
|
-
message: "Subscription procedure must return an AsyncIterable"
|
|
3154
|
-
});
|
|
3155
|
-
}
|
|
3156
|
-
const encoder = new TextEncoder;
|
|
3157
|
-
const stream = new ReadableStream({
|
|
3158
|
-
async start(controller) {
|
|
3159
|
-
try {
|
|
3160
|
-
for await (const chunk of iterable) {
|
|
3161
|
-
if (request.signal.aborted)
|
|
3162
|
-
break;
|
|
3163
|
-
const message = `data: ${JSON.stringify(chunk)}
|
|
3164
|
-
|
|
3165
|
-
`;
|
|
3166
|
-
controller.enqueue(encoder.encode(message));
|
|
3167
|
-
}
|
|
3168
|
-
controller.close();
|
|
3169
|
-
} catch (err) {
|
|
3170
|
-
const errorMessage = `event: error
|
|
3171
|
-
data: ${JSON.stringify({ message: err.message ?? "Stream error" })}
|
|
3172
|
-
|
|
3173
|
-
`;
|
|
3174
|
-
controller.enqueue(encoder.encode(errorMessage));
|
|
3175
|
-
controller.close();
|
|
3176
|
-
}
|
|
3177
|
-
},
|
|
3178
|
-
cancel() {
|
|
3179
|
-
if (typeof iterable.return === "function") {
|
|
3180
|
-
iterable.return();
|
|
3181
|
-
}
|
|
3182
|
-
}
|
|
3183
|
-
});
|
|
3184
|
-
baseHeaders.set("Content-Type", "text/event-stream; charset=utf-8");
|
|
3185
|
-
baseHeaders.set("Cache-Control", "no-cache, no-transform");
|
|
3186
|
-
baseHeaders.set("Connection", "keep-alive");
|
|
3187
|
-
return new Response(stream, {
|
|
3188
|
-
status: 200,
|
|
3189
|
-
headers: baseHeaders
|
|
3190
|
-
});
|
|
3191
|
-
}
|
|
3192
|
-
const data = await executeProcedure(procedure, {
|
|
3193
|
-
rawInput,
|
|
3194
|
-
ctx,
|
|
3195
|
-
req: request,
|
|
3196
|
-
signal: request.signal
|
|
3197
|
-
});
|
|
3198
|
-
const responsePayload = {
|
|
3199
|
-
result: { data }
|
|
3200
|
-
};
|
|
3201
|
-
baseHeaders.set("Content-Type", "application/json");
|
|
3202
|
-
return new Response(JSON.stringify(responsePayload), {
|
|
3203
|
-
status: 200,
|
|
3204
|
-
headers: baseHeaders
|
|
3205
|
-
});
|
|
3206
|
-
} catch (err) {
|
|
3207
|
-
const error = err instanceof RPCError ? err : new RPCError({
|
|
3208
|
-
code: "INTERNAL_SERVER_ERROR",
|
|
3209
|
-
message: err.message ?? "Internal Server Error",
|
|
3210
|
-
cause: err
|
|
3211
|
-
});
|
|
3212
|
-
onError?.({ error, path: procedurePath, req: request });
|
|
3213
|
-
const responsePayload = {
|
|
3214
|
-
error: {
|
|
3215
|
-
code: error.code,
|
|
3216
|
-
message: error.message,
|
|
3217
|
-
issues: error.issues
|
|
3218
|
-
}
|
|
3219
|
-
};
|
|
3220
|
-
baseHeaders.set("Content-Type", "application/json");
|
|
3221
|
-
return new Response(JSON.stringify(responsePayload), {
|
|
3222
|
-
status: ERROR_CODE_TO_STATUS[error.code] ?? 500,
|
|
3223
|
-
headers: baseHeaders
|
|
3224
|
-
});
|
|
3225
|
-
}
|
|
3226
|
-
};
|
|
3227
|
-
}
|
|
3228
|
-
|
|
3229
|
-
// src/rpc/client.ts
|
|
3230
|
-
async function resolveHeaders(headers, fullPath = "") {
|
|
3231
|
-
if (!headers)
|
|
3232
|
-
return {};
|
|
3233
|
-
if (typeof headers === "function") {
|
|
3234
|
-
return await headers();
|
|
3235
|
-
}
|
|
3236
|
-
const result = {};
|
|
3237
|
-
for (const [key, val] of Object.entries(headers)) {
|
|
3238
|
-
if (typeof val === "object" || typeof val === "function") {
|
|
3239
|
-
if (matchesRulePattern(key, fullPath, fullPath)) {
|
|
3240
|
-
const resolved = typeof val === "function" ? await val() : val;
|
|
3241
|
-
if (resolved && typeof resolved === "object") {
|
|
3242
|
-
Object.assign(result, resolved);
|
|
3243
|
-
}
|
|
3244
|
-
}
|
|
3245
|
-
} else if (typeof val === "string") {
|
|
3246
|
-
result[key] = val;
|
|
3247
|
-
}
|
|
3248
|
-
}
|
|
3249
|
-
return result;
|
|
3250
|
-
}
|
|
3251
|
-
function createProxyPath(options, path = []) {
|
|
3252
|
-
return new Proxy({}, {
|
|
3253
|
-
get(_target, prop) {
|
|
3254
|
-
if (prop === "then")
|
|
3255
|
-
return;
|
|
3256
|
-
if (prop === "query") {
|
|
3257
|
-
return async (input, callOpts) => {
|
|
3258
|
-
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
3259
|
-
const baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
3260
|
-
const fullPath = path.join(".");
|
|
3261
|
-
let url = `${baseUrl}/${fullPath}`;
|
|
3262
|
-
if (input !== undefined) {
|
|
3263
|
-
const serialized = JSON.stringify(input);
|
|
3264
|
-
url += `${url.includes("?") ? "&" : "?"}input=${encodeURIComponent(serialized)}`;
|
|
3265
|
-
}
|
|
3266
|
-
const dynamicHeaders = await resolveHeaders(options.headers, fullPath);
|
|
3267
|
-
const headers = {
|
|
3268
|
-
Accept: "application/json",
|
|
3269
|
-
...dynamicHeaders,
|
|
3270
|
-
...callOpts?.headers
|
|
3271
|
-
};
|
|
3272
|
-
const devtools = typeof window !== "undefined" ? window.__VISAGE_DEVTOOLS__ : null;
|
|
3273
|
-
const logId = devtools?.logRpcCall({
|
|
3274
|
-
id: `rpc_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
|
|
3275
|
-
path: fullPath,
|
|
3276
|
-
type: "query",
|
|
3277
|
-
input
|
|
3278
|
-
});
|
|
3279
|
-
try {
|
|
3280
|
-
const res = await fetchFn(url, {
|
|
3281
|
-
method: "GET",
|
|
3282
|
-
headers,
|
|
3283
|
-
signal: callOpts?.signal
|
|
3284
|
-
});
|
|
3285
|
-
const body = await res.json();
|
|
3286
|
-
if ("error" in body) {
|
|
3287
|
-
devtools?.updateRpcCall(logId, { status: "error", error: body.error });
|
|
3288
|
-
throw new RPCError({
|
|
3289
|
-
code: body.error.code,
|
|
3290
|
-
message: body.error.message,
|
|
3291
|
-
issues: body.error.issues
|
|
3292
|
-
});
|
|
3293
|
-
}
|
|
3294
|
-
devtools?.updateRpcCall(logId, { status: "success", response: body.result.data });
|
|
3295
|
-
return body.result.data;
|
|
3296
|
-
} catch (err) {
|
|
3297
|
-
devtools?.updateRpcCall(logId, { status: "error", error: err });
|
|
3298
|
-
throw err;
|
|
3299
|
-
}
|
|
3300
|
-
};
|
|
3301
|
-
}
|
|
3302
|
-
if (prop === "mutate") {
|
|
3303
|
-
return async (input, callOpts) => {
|
|
3304
|
-
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
3305
|
-
const baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
3306
|
-
const fullPath = path.join(".");
|
|
3307
|
-
const url = `${baseUrl}/${fullPath}`;
|
|
3308
|
-
const dynamicHeaders = await resolveHeaders(options.headers, fullPath);
|
|
3309
|
-
const headers = {
|
|
3310
|
-
"Content-Type": "application/json",
|
|
3311
|
-
Accept: "application/json",
|
|
3312
|
-
...dynamicHeaders,
|
|
3313
|
-
...callOpts?.headers
|
|
3314
|
-
};
|
|
3315
|
-
const devtools = typeof window !== "undefined" ? window.__VISAGE_DEVTOOLS__ : null;
|
|
3316
|
-
const logId = devtools?.logRpcCall({
|
|
3317
|
-
id: `rpc_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
|
|
3318
|
-
path: fullPath,
|
|
3319
|
-
type: "mutation",
|
|
3320
|
-
input
|
|
3321
|
-
});
|
|
3322
|
-
try {
|
|
3323
|
-
const res = await fetchFn(url, {
|
|
3324
|
-
method: "POST",
|
|
3325
|
-
headers,
|
|
3326
|
-
body: JSON.stringify({ input }),
|
|
3327
|
-
signal: callOpts?.signal
|
|
3328
|
-
});
|
|
3329
|
-
const body = await res.json();
|
|
3330
|
-
if ("error" in body) {
|
|
3331
|
-
devtools?.updateRpcCall(logId, { status: "error", error: body.error });
|
|
3332
|
-
throw new RPCError({
|
|
3333
|
-
code: body.error.code,
|
|
3334
|
-
message: body.error.message,
|
|
3335
|
-
issues: body.error.issues
|
|
3336
|
-
});
|
|
3337
|
-
}
|
|
3338
|
-
devtools?.updateRpcCall(logId, { status: "success", response: body.result.data });
|
|
3339
|
-
return body.result.data;
|
|
3340
|
-
} catch (err) {
|
|
3341
|
-
devtools?.updateRpcCall(logId, { status: "error", error: err });
|
|
3342
|
-
throw err;
|
|
3343
|
-
}
|
|
3344
|
-
};
|
|
3345
|
-
}
|
|
3346
|
-
if (prop === "subscribe") {
|
|
3347
|
-
return (input, callbacks) => {
|
|
3348
|
-
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
3349
|
-
const baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
3350
|
-
const fullPath = path.join(".");
|
|
3351
|
-
let url = `${baseUrl}/${fullPath}`;
|
|
3352
|
-
if (input !== undefined) {
|
|
3353
|
-
const serialized = JSON.stringify(input);
|
|
3354
|
-
url += `${url.includes("?") ? "&" : "?"}input=${encodeURIComponent(serialized)}`;
|
|
3355
|
-
}
|
|
3356
|
-
const controller = new AbortController;
|
|
3357
|
-
const devtools = typeof window !== "undefined" ? window.__VISAGE_DEVTOOLS__ : null;
|
|
3358
|
-
const logId = devtools?.logRpcCall({
|
|
3359
|
-
id: `rpc_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
|
|
3360
|
-
path: fullPath,
|
|
3361
|
-
type: "subscription",
|
|
3362
|
-
input
|
|
3363
|
-
});
|
|
3364
|
-
(async () => {
|
|
3365
|
-
try {
|
|
3366
|
-
const dynamicHeaders = await resolveHeaders(options.headers, fullPath);
|
|
3367
|
-
const headers = {
|
|
3368
|
-
Accept: "text/event-stream",
|
|
3369
|
-
...dynamicHeaders
|
|
3370
|
-
};
|
|
3371
|
-
const res = await fetchFn(url, {
|
|
3372
|
-
method: "GET",
|
|
3373
|
-
headers,
|
|
3374
|
-
signal: controller.signal
|
|
3375
|
-
});
|
|
3376
|
-
if (!res.ok || !res.body) {
|
|
3377
|
-
throw new Error(`Subscription connection failed with status ${res.status}`);
|
|
3378
|
-
}
|
|
3379
|
-
const reader = res.body.getReader();
|
|
3380
|
-
const decoder = new TextDecoder;
|
|
3381
|
-
let buffer = "";
|
|
3382
|
-
while (true) {
|
|
3383
|
-
const { done, value } = await reader.read();
|
|
3384
|
-
if (done)
|
|
3385
|
-
break;
|
|
3386
|
-
buffer += decoder.decode(value, { stream: true });
|
|
3387
|
-
const lines = buffer.split(`
|
|
3388
|
-
|
|
3389
|
-
`);
|
|
3390
|
-
buffer = lines.pop() ?? "";
|
|
3391
|
-
for (const line of lines) {
|
|
3392
|
-
const trimmed = line.trim();
|
|
3393
|
-
if (trimmed.startsWith("data:")) {
|
|
3394
|
-
const jsonStr = trimmed.slice(5).trim();
|
|
3395
|
-
try {
|
|
3396
|
-
const parsed = JSON.parse(jsonStr);
|
|
3397
|
-
devtools?.logRpcEvent(logId, parsed);
|
|
3398
|
-
callbacks.onData(parsed);
|
|
3399
|
-
} catch (parseErr) {
|
|
3400
|
-
devtools?.updateRpcCall(logId, { status: "error", error: parseErr });
|
|
3401
|
-
callbacks.onError?.(parseErr);
|
|
3402
|
-
}
|
|
3403
|
-
} else if (trimmed.startsWith("event: error")) {
|
|
3404
|
-
devtools?.updateRpcCall(logId, { status: "error" });
|
|
3405
|
-
callbacks.onError?.(new Error("Server event stream error"));
|
|
3406
|
-
}
|
|
3407
|
-
}
|
|
3408
|
-
}
|
|
3409
|
-
callbacks.onComplete?.();
|
|
3410
|
-
} catch (err) {
|
|
3411
|
-
if (!controller.signal.aborted) {
|
|
3412
|
-
callbacks.onError?.(err);
|
|
3413
|
-
}
|
|
3414
|
-
}
|
|
3415
|
-
})();
|
|
3416
|
-
return {
|
|
3417
|
-
unsubscribe: () => {
|
|
3418
|
-
controller.abort();
|
|
3419
|
-
}
|
|
3420
|
-
};
|
|
3421
|
-
};
|
|
3422
|
-
}
|
|
3423
|
-
if (prop === "queryKey") {
|
|
3424
|
-
return (input) => {
|
|
3425
|
-
const resolvedInput = typeof input === "function" ? input() : input;
|
|
3426
|
-
const key = [...path];
|
|
3427
|
-
if (resolvedInput !== undefined) {
|
|
3428
|
-
key.push(resolvedInput);
|
|
3429
|
-
}
|
|
3430
|
-
return key;
|
|
3431
|
-
};
|
|
3432
|
-
}
|
|
3433
|
-
if (prop === "queryOptions") {
|
|
3434
|
-
return (input, extra) => {
|
|
3435
|
-
const resolvedInput = typeof input === "function" ? input() : input;
|
|
3436
|
-
const key = [...path];
|
|
3437
|
-
if (resolvedInput !== undefined) {
|
|
3438
|
-
key.push(resolvedInput);
|
|
3439
|
-
}
|
|
3440
|
-
return {
|
|
3441
|
-
queryKey: key,
|
|
3442
|
-
queryFn: ({ signal }) => {
|
|
3443
|
-
const queryFn = createProxyPath(options, path).query;
|
|
3444
|
-
return queryFn(resolvedInput, { signal });
|
|
3445
|
-
},
|
|
3446
|
-
...extra
|
|
3447
|
-
};
|
|
3448
|
-
};
|
|
3449
|
-
}
|
|
3450
|
-
if (prop === "createQuery" || prop === "useQuery") {
|
|
3451
|
-
return (input, extra) => {
|
|
3452
|
-
const proxy = createProxyPath(options, path);
|
|
3453
|
-
return createQuery(() => proxy.queryOptions(input, extra));
|
|
3454
|
-
};
|
|
3455
|
-
}
|
|
3456
|
-
if (prop === "mutationKey") {
|
|
3457
|
-
return () => [...path];
|
|
3458
|
-
}
|
|
3459
|
-
if (prop === "mutationOptions") {
|
|
3460
|
-
return (extra) => {
|
|
3461
|
-
return {
|
|
3462
|
-
mutationKey: [...path],
|
|
3463
|
-
mutationFn: (input) => {
|
|
3464
|
-
const mutateFn = createProxyPath(options, path).mutate;
|
|
3465
|
-
return mutateFn(input);
|
|
3466
|
-
},
|
|
3467
|
-
...extra
|
|
3468
|
-
};
|
|
3469
|
-
};
|
|
3470
|
-
}
|
|
3471
|
-
if (prop === "createMutation" || prop === "useMutation") {
|
|
3472
|
-
return (extra) => {
|
|
3473
|
-
const proxy = createProxyPath(options, path);
|
|
3474
|
-
return createMutation(proxy.mutationOptions(extra));
|
|
3475
|
-
};
|
|
3476
|
-
}
|
|
3477
|
-
return createProxyPath(options, [...path, prop]);
|
|
3478
|
-
}
|
|
3479
|
-
});
|
|
3480
|
-
}
|
|
3481
|
-
function createClient(options) {
|
|
3482
|
-
return createProxyPath(options, []);
|
|
3483
|
-
}
|
|
3484
|
-
// src/rpc/router.ts
|
|
3485
|
-
class RouterImpl {
|
|
3486
|
-
_def;
|
|
3487
|
-
constructor(record = {}, middlewares = []) {
|
|
3488
|
-
this._def = {
|
|
3489
|
-
record: { ...record },
|
|
3490
|
-
middlewares: [...middlewares]
|
|
3491
|
-
};
|
|
3492
|
-
}
|
|
3493
|
-
query(name, options) {
|
|
3494
|
-
const proc = createProcedure("query", options, this._def.middlewares);
|
|
3495
|
-
const newRecord = {
|
|
3496
|
-
...this._def.record,
|
|
3497
|
-
[name]: proc
|
|
3498
|
-
};
|
|
3499
|
-
return new RouterImpl(newRecord, this._def.middlewares);
|
|
3500
|
-
}
|
|
3501
|
-
mutation(name, options) {
|
|
3502
|
-
const proc = createProcedure("mutation", options, this._def.middlewares);
|
|
3503
|
-
const newRecord = {
|
|
3504
|
-
...this._def.record,
|
|
3505
|
-
[name]: proc
|
|
3506
|
-
};
|
|
3507
|
-
return new RouterImpl(newRecord, this._def.middlewares);
|
|
3508
|
-
}
|
|
3509
|
-
subscription(name, options) {
|
|
3510
|
-
const proc = createProcedure("subscription", options, this._def.middlewares);
|
|
3511
|
-
const newRecord = {
|
|
3512
|
-
...this._def.record,
|
|
3513
|
-
[name]: proc
|
|
3514
|
-
};
|
|
3515
|
-
return new RouterImpl(newRecord, this._def.middlewares);
|
|
3516
|
-
}
|
|
3517
|
-
use(middleware) {
|
|
3518
|
-
const updatedMiddlewares = [...this._def.middlewares, middleware];
|
|
3519
|
-
const updatedRecord = {};
|
|
3520
|
-
for (const key in this._def.record) {
|
|
3521
|
-
const item = this._def.record[key];
|
|
3522
|
-
if ("type" in item) {
|
|
3523
|
-
updatedRecord[key] = {
|
|
3524
|
-
...item,
|
|
3525
|
-
middlewares: [...updatedMiddlewares]
|
|
3526
|
-
};
|
|
3527
|
-
} else {
|
|
3528
|
-
updatedRecord[key] = item;
|
|
3529
|
-
}
|
|
3530
|
-
}
|
|
3531
|
-
return new RouterImpl(updatedRecord, updatedMiddlewares);
|
|
3532
|
-
}
|
|
3533
|
-
merge(prefix, router) {
|
|
3534
|
-
const newRecord = {
|
|
3535
|
-
...this._def.record,
|
|
3536
|
-
[prefix]: router
|
|
3537
|
-
};
|
|
3538
|
-
return new RouterImpl(newRecord, this._def.middlewares);
|
|
3539
|
-
}
|
|
3540
|
-
}
|
|
3541
|
-
function createRouter(record) {
|
|
3542
|
-
return new RouterImpl(record ?? {});
|
|
3543
|
-
}
|
|
3544
|
-
function query(options) {
|
|
3545
|
-
return createProcedure("query", options);
|
|
3546
|
-
}
|
|
3547
|
-
function mutation(options) {
|
|
3548
|
-
return createProcedure("mutation", options);
|
|
3549
|
-
}
|
|
3550
|
-
function subscription(options) {
|
|
3551
|
-
return createProcedure("subscription", options);
|
|
3552
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
createClient2,
|
|
3
|
+
RouterImpl2,
|
|
4
|
+
createRouter2,
|
|
5
|
+
query3,
|
|
6
|
+
mutation3,
|
|
7
|
+
subscription3
|
|
8
|
+
} from "../index-df5e614s.js";
|
|
9
|
+
import {
|
|
10
|
+
ERROR_CODE_TO_STATUS2,
|
|
11
|
+
STATUS_TO_ERROR_CODE2,
|
|
12
|
+
RPCError2,
|
|
13
|
+
createProcedure2,
|
|
14
|
+
executeProcedure2,
|
|
15
|
+
createFetchHandler2
|
|
16
|
+
} from "../index-965ryh36.js";
|
|
17
|
+
import {
|
|
18
|
+
Schema2,
|
|
19
|
+
validateWithSchema2,
|
|
20
|
+
v2
|
|
21
|
+
} from "../index-2zz0g2n2.js";
|
|
22
|
+
import"../index-y9bq7h9g.js";
|
|
23
|
+
import"../index-a4xns6cc.js";
|
|
24
|
+
import"../index-6kfe1nr4.js";
|
|
3553
25
|
export {
|
|
3554
|
-
ERROR_CODE_TO_STATUS,
|
|
3555
|
-
RPCError,
|
|
3556
|
-
RouterImpl,
|
|
3557
|
-
STATUS_TO_ERROR_CODE,
|
|
3558
|
-
Schema,
|
|
3559
|
-
createClient,
|
|
3560
|
-
createFetchHandler,
|
|
3561
|
-
createProcedure,
|
|
3562
|
-
createRouter,
|
|
3563
|
-
executeProcedure,
|
|
3564
|
-
mutation,
|
|
3565
|
-
query,
|
|
3566
|
-
subscription,
|
|
3567
|
-
v,
|
|
3568
|
-
validateWithSchema
|
|
26
|
+
ERROR_CODE_TO_STATUS2 as ERROR_CODE_TO_STATUS,
|
|
27
|
+
RPCError2 as RPCError,
|
|
28
|
+
RouterImpl2 as RouterImpl,
|
|
29
|
+
STATUS_TO_ERROR_CODE2 as STATUS_TO_ERROR_CODE,
|
|
30
|
+
Schema2 as Schema,
|
|
31
|
+
createClient2 as createClient,
|
|
32
|
+
createFetchHandler2 as createFetchHandler,
|
|
33
|
+
createProcedure2 as createProcedure,
|
|
34
|
+
createRouter2 as createRouter,
|
|
35
|
+
executeProcedure2 as executeProcedure,
|
|
36
|
+
mutation3 as mutation,
|
|
37
|
+
query3 as query,
|
|
38
|
+
subscription3 as subscription,
|
|
39
|
+
v2 as v,
|
|
40
|
+
validateWithSchema2 as validateWithSchema
|
|
3569
41
|
};
|