vitral 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +250 -217
- package/dist/angular.d.ts +15 -4
- package/dist/angular.js +25 -5
- package/dist/auto.d.ts +2 -0
- package/dist/auto.js +12 -0
- package/dist/chunk-2XF5BKV3.js +190 -0
- package/dist/chunk-6Y3VMWHH.js +181 -0
- package/dist/chunk-DXORSF4X.js +42 -0
- package/dist/chunk-GNPFWISJ.js +80 -0
- package/dist/chunk-HP6QWU6K.js +51 -0
- package/dist/chunk-NCONW6WS.js +606 -0
- package/dist/chunk-PX7PBCCT.js +89 -0
- package/dist/chunk-S5MZT5IT.js +20 -0
- package/dist/chunk-SFL6LTP3.js +56 -0
- package/dist/chunk-UTYAX6MU.js +152 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +88 -0
- package/dist/dedupe-IWFIXRWG.js +81 -0
- package/dist/devtools.d.ts +12 -0
- package/dist/devtools.js +86 -0
- package/dist/element.d.ts +60 -2
- package/dist/element.js +9 -2
- package/dist/errors-KKB8FGCz.d.ts +11 -0
- package/dist/events-DUdjhfps.d.ts +6 -0
- package/dist/expose-53BEJB34.js +14 -0
- package/dist/host-slot-Cz6EiGsB.d.ts +6 -0
- package/dist/iframe.d.ts +28 -0
- package/dist/iframe.js +236 -0
- package/dist/index.d.ts +142 -147
- package/dist/index.js +39 -10
- package/dist/navigate-BRG1WJUM.d.ts +9 -0
- package/dist/overrides-NZAIUGK5.js +15 -0
- package/dist/preact.d.ts +30 -7
- package/dist/preact.js +37 -9
- package/dist/react.d.ts +38 -7
- package/dist/react.js +92 -42
- package/dist/routes.d.ts +56 -0
- package/dist/routes.js +143 -0
- package/dist/shadow-MYRJQLLY.js +72 -0
- package/dist/slot-pB276oPt.d.ts +36 -0
- package/dist/solid.d.ts +29 -6
- package/dist/solid.js +31 -8
- package/dist/sri-BVKZNX5Q.js +114 -0
- package/dist/state-BDdCwc21.d.ts +4 -0
- package/dist/svelte.d.ts +19 -3
- package/dist/svelte.js +10 -4
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +8 -3
- package/dist/types-BV-hUrms.d.ts +265 -0
- package/dist/vite.d.ts +58 -4
- package/dist/vite.js +714 -24
- package/dist/vue.d.ts +79 -7
- package/dist/vue.js +69 -46
- package/package.json +144 -8
- package/dist/chunk-IZK6ITIJ.js +0 -96
- package/dist/chunk-TTL52BF2.js +0 -547
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
import {
|
|
2
|
+
load,
|
|
3
|
+
loadFile,
|
|
4
|
+
registerSrc,
|
|
5
|
+
resolveEntry
|
|
6
|
+
} from "./chunk-2XF5BKV3.js";
|
|
7
|
+
import {
|
|
8
|
+
injectStyles
|
|
9
|
+
} from "./chunk-SFL6LTP3.js";
|
|
10
|
+
import {
|
|
11
|
+
RemoteError,
|
|
12
|
+
isRemoteError,
|
|
13
|
+
metric
|
|
14
|
+
} from "./chunk-PX7PBCCT.js";
|
|
15
|
+
import {
|
|
16
|
+
protocol
|
|
17
|
+
} from "./chunk-GNPFWISJ.js";
|
|
18
|
+
|
|
19
|
+
// src/core/events.ts
|
|
20
|
+
var events = {
|
|
21
|
+
emit: (t, p) => protocol().events.emit(t, p),
|
|
22
|
+
on: (t, h) => protocol().events.on(t, h),
|
|
23
|
+
last: (t) => protocol().events.last(t)
|
|
24
|
+
};
|
|
25
|
+
function scopedEvents() {
|
|
26
|
+
const offs = /* @__PURE__ */ new Set();
|
|
27
|
+
const track2 = (off) => {
|
|
28
|
+
const wrapped = () => (offs.delete(wrapped), off());
|
|
29
|
+
offs.add(wrapped);
|
|
30
|
+
return wrapped;
|
|
31
|
+
};
|
|
32
|
+
return {
|
|
33
|
+
bus: {
|
|
34
|
+
emit: (t, p) => events.emit(t, p),
|
|
35
|
+
last: (t) => events.last(t),
|
|
36
|
+
on: (t, h) => track2(events.on(t, h))
|
|
37
|
+
},
|
|
38
|
+
track: track2,
|
|
39
|
+
dispose() {
|
|
40
|
+
for (const off of [...offs]) off();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/core/hooks.ts
|
|
46
|
+
var ctxHooks = {};
|
|
47
|
+
|
|
48
|
+
// src/core/navigate.ts
|
|
49
|
+
function navigate(url, options = {}) {
|
|
50
|
+
const target = new URL(url, location.href);
|
|
51
|
+
if (target.origin !== location.origin) {
|
|
52
|
+
location.assign(target.href);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (options.replace) history.replaceState(history.state, "", target.href);
|
|
56
|
+
else history.pushState(history.state, "", target.href);
|
|
57
|
+
dispatchEvent(new PopStateEvent("popstate", { state: history.state }));
|
|
58
|
+
events.emit("vitral:navigate", target.pathname + target.search + target.hash);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/core/updates.ts
|
|
62
|
+
var versions = /* @__PURE__ */ new Map();
|
|
63
|
+
function track(name, entry) {
|
|
64
|
+
versions.set(name, entry);
|
|
65
|
+
}
|
|
66
|
+
async function refresh(name) {
|
|
67
|
+
const p = protocol();
|
|
68
|
+
await p.pending();
|
|
69
|
+
const entry = p.entry(name);
|
|
70
|
+
if (entry) p.register(name, entry);
|
|
71
|
+
await loadFile(name);
|
|
72
|
+
events.emit("vitral:refresh", name);
|
|
73
|
+
}
|
|
74
|
+
function refreshable(current, name, props, remount) {
|
|
75
|
+
const off = events.on("vitral:refresh", (n) => {
|
|
76
|
+
if (n === name || name.startsWith(n + "/")) {
|
|
77
|
+
remount(props).then((next) => {
|
|
78
|
+
const old = current;
|
|
79
|
+
if (old.unmount === noop) return next.unmount();
|
|
80
|
+
current = next;
|
|
81
|
+
old.unmount();
|
|
82
|
+
}, console.error);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
update(next) {
|
|
87
|
+
props = next;
|
|
88
|
+
current.update?.(next);
|
|
89
|
+
},
|
|
90
|
+
unmount() {
|
|
91
|
+
off();
|
|
92
|
+
current.unmount();
|
|
93
|
+
current = { unmount: noop };
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
var noop = () => {
|
|
98
|
+
};
|
|
99
|
+
async function checkUpdates() {
|
|
100
|
+
const p = protocol();
|
|
101
|
+
const found = [];
|
|
102
|
+
const { splitName } = await import("./expose-53BEJB34.js");
|
|
103
|
+
const remotes = /* @__PURE__ */ new Map();
|
|
104
|
+
for (const [name, entry] of versions) remotes.set(splitName(name)[0], entry);
|
|
105
|
+
versions.clear();
|
|
106
|
+
for (const [name, entry] of remotes) versions.set(name, entry);
|
|
107
|
+
await Promise.all(
|
|
108
|
+
[...remotes].map(
|
|
109
|
+
([name, current]) => resolveEntry(name, p.entry(name)).then(({ entry }) => {
|
|
110
|
+
if (entry !== current) {
|
|
111
|
+
versions.set(name, entry);
|
|
112
|
+
found.push(name);
|
|
113
|
+
events.emit("vitral:update-available", { name, entry });
|
|
114
|
+
}
|
|
115
|
+
}, noop)
|
|
116
|
+
)
|
|
117
|
+
);
|
|
118
|
+
return found;
|
|
119
|
+
}
|
|
120
|
+
function watchUpdates() {
|
|
121
|
+
let busy = null;
|
|
122
|
+
const run = () => busy ??= checkUpdates().finally(() => busy = null);
|
|
123
|
+
const nav = globalThis.navigation;
|
|
124
|
+
addEventListener("popstate", run);
|
|
125
|
+
nav?.addEventListener("navigatesuccess", run);
|
|
126
|
+
return () => {
|
|
127
|
+
removeEventListener("popstate", run);
|
|
128
|
+
nav?.removeEventListener("navigatesuccess", run);
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// src/core/mount.ts
|
|
133
|
+
async function mountRemote(target, name, props, options = {}) {
|
|
134
|
+
return refreshable(await mountOnce(target, name, props, options), name, props, (latest) => mountOnce(target, name, latest, options));
|
|
135
|
+
}
|
|
136
|
+
var frames;
|
|
137
|
+
function setFrameMounter(mounter) {
|
|
138
|
+
frames = mounter;
|
|
139
|
+
}
|
|
140
|
+
async function mountOnce(target, name, props, options) {
|
|
141
|
+
const p = protocol();
|
|
142
|
+
await p.pending();
|
|
143
|
+
if ((options.isolate ?? registered(name)?.isolate ?? p.settings().isolate) === "iframe") {
|
|
144
|
+
if (!frames) throw new RemoteError("MOUNT_FAILED", name, 'isolate="iframe" precisa de enableIframe(), de vitral/iframe');
|
|
145
|
+
return frames(target, name, props, options);
|
|
146
|
+
}
|
|
147
|
+
const { module: mod, ...resolved } = await load(name, options.isolate, options.priority);
|
|
148
|
+
track(name, resolved.entry);
|
|
149
|
+
const isolate = options.isolate ?? resolved.isolate ?? protocol().settings().isolate;
|
|
150
|
+
const label = resolved.name ?? name;
|
|
151
|
+
let shadowRoot = null;
|
|
152
|
+
const el = document.createElement("div");
|
|
153
|
+
el.setAttribute("data-vitral-root", label);
|
|
154
|
+
if (resolved.scope) el.setAttribute("data-vitral-scope", resolved.scope);
|
|
155
|
+
el.style.display = "contents";
|
|
156
|
+
if (isolate === "shadow") {
|
|
157
|
+
shadowRoot = target.shadowRoot ?? target.attachShadow({ mode: "open" });
|
|
158
|
+
shadowRoot.appendChild(el);
|
|
159
|
+
} else {
|
|
160
|
+
target.appendChild(el);
|
|
161
|
+
}
|
|
162
|
+
let t = performance.now();
|
|
163
|
+
const release = await injectStyles(resolved.css, shadowRoot, el, options.styles, resolved.sri);
|
|
164
|
+
metric(name, "css", t);
|
|
165
|
+
t = performance.now();
|
|
166
|
+
const scoped = scopedEvents();
|
|
167
|
+
const on = (type) => (fn) => (el.addEventListener(type, fn), () => el.removeEventListener(type, fn));
|
|
168
|
+
const ctx = {
|
|
169
|
+
name: label,
|
|
170
|
+
baseUrl: new URL(".", resolved.entry).href,
|
|
171
|
+
events: scoped.bus,
|
|
172
|
+
shadowRoot,
|
|
173
|
+
reportError(e) {
|
|
174
|
+
const err = isRemoteError(e) ? e : new RemoteError("RENDER_FAILED", label, String(e?.message ?? e), e);
|
|
175
|
+
if (options.onError) options.onError(err);
|
|
176
|
+
else console.error(err);
|
|
177
|
+
},
|
|
178
|
+
navigate,
|
|
179
|
+
protocol: protocol().protocol,
|
|
180
|
+
onActivate: on("vitral:activate"),
|
|
181
|
+
onDeactivate: on("vitral:deactivate")
|
|
182
|
+
};
|
|
183
|
+
if (ctxHooks.shared) ctx.shared = ctxHooks.shared(name, scoped.track);
|
|
184
|
+
let mounted;
|
|
185
|
+
try {
|
|
186
|
+
mounted = await mod.mount(el, props, ctx);
|
|
187
|
+
metric(name, "mount", t);
|
|
188
|
+
} catch (e) {
|
|
189
|
+
scoped.dispose();
|
|
190
|
+
release();
|
|
191
|
+
el.remove();
|
|
192
|
+
throw new RemoteError("MOUNT_FAILED", label, "erro ao montar", e);
|
|
193
|
+
}
|
|
194
|
+
let alive = true;
|
|
195
|
+
return {
|
|
196
|
+
update(next) {
|
|
197
|
+
if (alive) mounted.update?.(next);
|
|
198
|
+
},
|
|
199
|
+
unmount() {
|
|
200
|
+
if (!alive) return;
|
|
201
|
+
alive = false;
|
|
202
|
+
try {
|
|
203
|
+
mounted.unmount();
|
|
204
|
+
} finally {
|
|
205
|
+
scoped.dispose();
|
|
206
|
+
release();
|
|
207
|
+
el.remove();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function registered(name) {
|
|
213
|
+
const p = protocol();
|
|
214
|
+
let n = name;
|
|
215
|
+
while (n && !p.entry(n)) n = n.slice(0, Math.max(0, n.lastIndexOf("/")));
|
|
216
|
+
return n ? p.entry(n) : void 0;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// src/core/slot.ts
|
|
220
|
+
function createSlot(target, options) {
|
|
221
|
+
let { isolate } = options;
|
|
222
|
+
const key = (o) => o.src ? registerSrc(o.src, o.name) : o.name ?? "";
|
|
223
|
+
let name = key(options);
|
|
224
|
+
let props = options.props ?? {};
|
|
225
|
+
let handle2 = null;
|
|
226
|
+
let holder = null;
|
|
227
|
+
let token = 0;
|
|
228
|
+
let status = "loading";
|
|
229
|
+
const setStatus = (s, e = null) => {
|
|
230
|
+
status = s;
|
|
231
|
+
if (holder) holder.style.display = s === "error" ? "none" : "";
|
|
232
|
+
options.onStatus?.(s, e);
|
|
233
|
+
};
|
|
234
|
+
const teardown = () => {
|
|
235
|
+
handle2?.unmount();
|
|
236
|
+
handle2 = null;
|
|
237
|
+
holder?.remove();
|
|
238
|
+
holder = null;
|
|
239
|
+
};
|
|
240
|
+
const mount = () => {
|
|
241
|
+
const my = ++token;
|
|
242
|
+
teardown();
|
|
243
|
+
holder = document.createElement("div");
|
|
244
|
+
holder.setAttribute("data-vitral-slot", name);
|
|
245
|
+
target.appendChild(holder);
|
|
246
|
+
setStatus("loading");
|
|
247
|
+
const fail = (e) => {
|
|
248
|
+
if (my !== token) return;
|
|
249
|
+
setStatus("error", isRemoteError(e) ? e : new RemoteError("MOUNT_FAILED", name, String(e), e));
|
|
250
|
+
};
|
|
251
|
+
const initial = props;
|
|
252
|
+
mountRemote(holder, name, props, { isolate, priority: options.priority, styles: options.styles, onError: fail }).then((h) => {
|
|
253
|
+
if (my !== token) return h.unmount();
|
|
254
|
+
handle2 = h;
|
|
255
|
+
if (props !== initial) h.update?.(props);
|
|
256
|
+
setStatus("ready");
|
|
257
|
+
}, fail);
|
|
258
|
+
};
|
|
259
|
+
mount();
|
|
260
|
+
return {
|
|
261
|
+
update(next) {
|
|
262
|
+
props = next;
|
|
263
|
+
handle2?.update?.(next);
|
|
264
|
+
},
|
|
265
|
+
set(next) {
|
|
266
|
+
const nextName = next.src || next.name !== void 0 ? key(next) : name;
|
|
267
|
+
const changed = nextName !== name || "isolate" in next && next.isolate !== isolate;
|
|
268
|
+
name = nextName;
|
|
269
|
+
if ("isolate" in next) isolate = next.isolate;
|
|
270
|
+
if (changed) mount();
|
|
271
|
+
},
|
|
272
|
+
retry: mount,
|
|
273
|
+
destroy() {
|
|
274
|
+
token++;
|
|
275
|
+
teardown();
|
|
276
|
+
},
|
|
277
|
+
get status() {
|
|
278
|
+
return status;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/core/remote.ts
|
|
284
|
+
function defineRemote(remote) {
|
|
285
|
+
return remote;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// src/component.ts
|
|
289
|
+
var TEMPLATE = /* @__PURE__ */ Symbol("vitral.html");
|
|
290
|
+
function html(strings, ...values) {
|
|
291
|
+
return { [TEMPLATE]: true, strings, values };
|
|
292
|
+
}
|
|
293
|
+
function unsafeHTML(markup) {
|
|
294
|
+
return html(Object.assign([markup], { raw: [markup] }));
|
|
295
|
+
}
|
|
296
|
+
var isTemplate = (v) => typeof v === "object" && v !== null && TEMPLATE in v;
|
|
297
|
+
var escape = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
298
|
+
var EVENT_ATTR = /\s+on([a-z][\w:-]*)=(["']?)$/i;
|
|
299
|
+
var HANDLER_PREFIX = "data-vitral-h";
|
|
300
|
+
function toMarkup(value, handlers) {
|
|
301
|
+
if (value == null || value === false) return "";
|
|
302
|
+
if (Array.isArray(value)) return value.map((v) => toMarkup(v, handlers)).join("");
|
|
303
|
+
if (!isTemplate(value)) return escape(String(value));
|
|
304
|
+
const strings = [...value.strings];
|
|
305
|
+
let out = "";
|
|
306
|
+
for (let i = 0; i < strings.length; i++) {
|
|
307
|
+
let s = strings[i];
|
|
308
|
+
if (i < value.values.length) {
|
|
309
|
+
const v = value.values[i];
|
|
310
|
+
const event = typeof v === "function" ? EVENT_ATTR.exec(s) : null;
|
|
311
|
+
if (event) {
|
|
312
|
+
s = s.slice(0, s.length - event[0].length) + ` ${HANDLER_PREFIX}${handlers.length}="${event[1].toLowerCase()}"`;
|
|
313
|
+
handlers.push(v);
|
|
314
|
+
if (event[2] && strings[i + 1]?.startsWith(event[2])) strings[i + 1] = strings[i + 1].slice(1);
|
|
315
|
+
out += s;
|
|
316
|
+
} else {
|
|
317
|
+
out += s + toMarkup(v, handlers);
|
|
318
|
+
}
|
|
319
|
+
} else {
|
|
320
|
+
out += s;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return out;
|
|
324
|
+
}
|
|
325
|
+
function render(view, el) {
|
|
326
|
+
if (typeof Node !== "undefined" && view instanceof Node) {
|
|
327
|
+
el.replaceChildren(view);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const handlers = [];
|
|
331
|
+
el.innerHTML = toMarkup(view, handlers);
|
|
332
|
+
if (!handlers.length) return;
|
|
333
|
+
for (const node of el.querySelectorAll("*")) {
|
|
334
|
+
for (const attr of [...node.attributes]) {
|
|
335
|
+
if (!attr.name.startsWith(HANDLER_PREFIX)) continue;
|
|
336
|
+
node.addEventListener(attr.value, handlers[Number(attr.name.slice(HANDLER_PREFIX.length))]);
|
|
337
|
+
node.removeAttribute(attr.name);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
function component(options) {
|
|
342
|
+
const opts = typeof options === "function" ? { render: options } : options;
|
|
343
|
+
return defineRemote({
|
|
344
|
+
mount(el, props, ctx) {
|
|
345
|
+
let current = props;
|
|
346
|
+
let queued = false;
|
|
347
|
+
let alive = true;
|
|
348
|
+
const draw = () => {
|
|
349
|
+
queued = false;
|
|
350
|
+
if (alive) render(opts.render(current, state, ctx) ?? "", el);
|
|
351
|
+
};
|
|
352
|
+
const initial = typeof opts.state === "function" ? opts.state() : { ...opts.state ?? {} };
|
|
353
|
+
const state = new Proxy(initial, {
|
|
354
|
+
set(target, key, value) {
|
|
355
|
+
if (!Object.is(Reflect.get(target, key), value)) {
|
|
356
|
+
Reflect.set(target, key, value);
|
|
357
|
+
if (!queued) {
|
|
358
|
+
queued = true;
|
|
359
|
+
queueMicrotask(draw);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
draw();
|
|
366
|
+
const cleanup = opts.mounted?.(el, state, ctx);
|
|
367
|
+
return {
|
|
368
|
+
update(next) {
|
|
369
|
+
current = next;
|
|
370
|
+
draw();
|
|
371
|
+
},
|
|
372
|
+
unmount() {
|
|
373
|
+
alive = false;
|
|
374
|
+
cleanup?.();
|
|
375
|
+
el.replaceChildren();
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// src/core/store.ts
|
|
383
|
+
function createStore(seed = {}) {
|
|
384
|
+
const slots = /* @__PURE__ */ new Map();
|
|
385
|
+
const changed = /* @__PURE__ */ new Map();
|
|
386
|
+
let depth = 0;
|
|
387
|
+
const slot = (key) => {
|
|
388
|
+
let x = slots.get(key);
|
|
389
|
+
if (!x) slots.set(key, x = { s: /* @__PURE__ */ new Set() });
|
|
390
|
+
return x;
|
|
391
|
+
};
|
|
392
|
+
const flush = () => {
|
|
393
|
+
if (depth) return;
|
|
394
|
+
const list = [...changed];
|
|
395
|
+
changed.clear();
|
|
396
|
+
for (const [x, before] of list) {
|
|
397
|
+
if (Object.is(x.v, before)) continue;
|
|
398
|
+
for (const fn of [...x.s]) {
|
|
399
|
+
try {
|
|
400
|
+
fn(x.v);
|
|
401
|
+
} catch (e) {
|
|
402
|
+
console.error(e);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
const write = (x, value, by) => {
|
|
408
|
+
if ("v" in x && Object.is(x.v, value)) return;
|
|
409
|
+
if (!changed.has(x)) changed.set(x, x.v);
|
|
410
|
+
x.v = value;
|
|
411
|
+
x.b = by;
|
|
412
|
+
flush();
|
|
413
|
+
};
|
|
414
|
+
for (const key in seed) slots.set(key, { v: seed[key], s: /* @__PURE__ */ new Set(), d: true });
|
|
415
|
+
return {
|
|
416
|
+
get: (key) => slots.get(key)?.v,
|
|
417
|
+
set(key, value, token, by) {
|
|
418
|
+
const x = slot(key);
|
|
419
|
+
if (x.r && token !== x.t) return false;
|
|
420
|
+
write(x, value, by);
|
|
421
|
+
return true;
|
|
422
|
+
},
|
|
423
|
+
subscribe(key, fn) {
|
|
424
|
+
const subs = slot(key).s;
|
|
425
|
+
const f = (v) => fn(v);
|
|
426
|
+
subs.add(f);
|
|
427
|
+
return () => void subs.delete(f);
|
|
428
|
+
},
|
|
429
|
+
own(key, value, writable, by) {
|
|
430
|
+
const x = slot(key);
|
|
431
|
+
if (x.t) return;
|
|
432
|
+
if (!x.d) write(x, value, by);
|
|
433
|
+
x.d = false;
|
|
434
|
+
x.r = !writable;
|
|
435
|
+
x.o = by;
|
|
436
|
+
return x.t = {};
|
|
437
|
+
},
|
|
438
|
+
release(key, token) {
|
|
439
|
+
const x = slots.get(key);
|
|
440
|
+
if (x && x.t === token) x.t = x.r = x.o = void 0;
|
|
441
|
+
},
|
|
442
|
+
batch(fn) {
|
|
443
|
+
depth++;
|
|
444
|
+
try {
|
|
445
|
+
return fn();
|
|
446
|
+
} finally {
|
|
447
|
+
depth--;
|
|
448
|
+
flush();
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
list: () => [...slots].filter(([, x]) => "v" in x).map(([key, x]) => ({ key, value: x.v, writable: !x.r, owner: x.o, by: x.b, subscribers: x.s.size }))
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
function hydrate() {
|
|
455
|
+
try {
|
|
456
|
+
return JSON.parse(document.querySelector("script[data-vitral-shared]")?.textContent || "{}");
|
|
457
|
+
} catch (e) {
|
|
458
|
+
console.error(e);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
function pageStore() {
|
|
462
|
+
if (typeof document === "undefined") return createStore();
|
|
463
|
+
const p = protocol();
|
|
464
|
+
if (!p.shared) {
|
|
465
|
+
const store = createStore(hydrate());
|
|
466
|
+
p.shared = () => store;
|
|
467
|
+
}
|
|
468
|
+
return p.shared();
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// src/core/shared.ts
|
|
472
|
+
function isDev() {
|
|
473
|
+
try {
|
|
474
|
+
return process.env.NODE_ENV !== "production";
|
|
475
|
+
} catch {
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
function pageStore2() {
|
|
480
|
+
ctxHooks.shared ??= scopedShared;
|
|
481
|
+
return pageStore();
|
|
482
|
+
}
|
|
483
|
+
function handle(store, key, by, track2 = (off) => off, token) {
|
|
484
|
+
const get = () => store.get(key);
|
|
485
|
+
const set = (value) => {
|
|
486
|
+
if (store.set(key, value, token, by)) return;
|
|
487
|
+
const e = new RemoteError("SHARED_READONLY", by || "shared", `s\xF3 o dono altera "${key}"`);
|
|
488
|
+
if (isDev()) throw e;
|
|
489
|
+
console.warn(e.message);
|
|
490
|
+
};
|
|
491
|
+
return {
|
|
492
|
+
key,
|
|
493
|
+
get,
|
|
494
|
+
set,
|
|
495
|
+
update: (fn) => set(fn(get())),
|
|
496
|
+
subscribe(fn) {
|
|
497
|
+
fn(get());
|
|
498
|
+
return track2(store.subscribe(key, fn));
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
function own(key, value, options = {}, by, track2) {
|
|
503
|
+
const store = pageStore2();
|
|
504
|
+
const token = store.own(key, value, options.writable !== false, by);
|
|
505
|
+
if (token) track2?.(() => store.release(key, token));
|
|
506
|
+
return handle(store, key, by, track2, token);
|
|
507
|
+
}
|
|
508
|
+
function shared(key) {
|
|
509
|
+
return handle(pageStore2(), key);
|
|
510
|
+
}
|
|
511
|
+
function provide(key, value, options) {
|
|
512
|
+
return own(key, value, options);
|
|
513
|
+
}
|
|
514
|
+
function batch(fn) {
|
|
515
|
+
return pageStore2().batch(fn);
|
|
516
|
+
}
|
|
517
|
+
function scopedShared(by, track2) {
|
|
518
|
+
const api = ((key) => handle(pageStore2(), key, by, track2));
|
|
519
|
+
api.provide = (key, value, options) => own(key, value, options, by, track2);
|
|
520
|
+
api.batch = batch;
|
|
521
|
+
return api;
|
|
522
|
+
}
|
|
523
|
+
function memoSelect() {
|
|
524
|
+
let last;
|
|
525
|
+
return (value, select) => {
|
|
526
|
+
if (!last || !Object.is(last[0], value) || last[1] !== select) {
|
|
527
|
+
const out = select(value);
|
|
528
|
+
last = [value, select, last && Object.is(last[2], out) ? last[2] : out];
|
|
529
|
+
}
|
|
530
|
+
return last[2];
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
var same = (value) => value;
|
|
534
|
+
|
|
535
|
+
// src/core/persist.ts
|
|
536
|
+
function persist(value, options = {}) {
|
|
537
|
+
const key = `vitral:${value.key}:${options.version ?? 1}`;
|
|
538
|
+
let storage;
|
|
539
|
+
try {
|
|
540
|
+
storage = options.storage === "session" ? sessionStorage : localStorage;
|
|
541
|
+
const saved = storage.getItem(key);
|
|
542
|
+
if (saved !== null) value.set(JSON.parse(saved));
|
|
543
|
+
} catch {
|
|
544
|
+
return value;
|
|
545
|
+
}
|
|
546
|
+
value.subscribe((v) => {
|
|
547
|
+
try {
|
|
548
|
+
storage.setItem(key, JSON.stringify(v));
|
|
549
|
+
} catch (e) {
|
|
550
|
+
console.warn(`[vitral] n\xE3o foi poss\xEDvel guardar "${value.key}"`, e);
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
return value;
|
|
554
|
+
}
|
|
555
|
+
function syncTabs(value) {
|
|
556
|
+
if (typeof BroadcastChannel === "undefined") return value;
|
|
557
|
+
const channel = new BroadcastChannel(`vitral:${value.key}`);
|
|
558
|
+
let receiving = false;
|
|
559
|
+
let first = true;
|
|
560
|
+
channel.onmessage = (e) => {
|
|
561
|
+
receiving = true;
|
|
562
|
+
try {
|
|
563
|
+
value.set(e.data);
|
|
564
|
+
} finally {
|
|
565
|
+
receiving = false;
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
value.subscribe((v) => {
|
|
569
|
+
if (first) return void (first = false);
|
|
570
|
+
if (receiving) return;
|
|
571
|
+
try {
|
|
572
|
+
channel.postMessage(v);
|
|
573
|
+
} catch (e) {
|
|
574
|
+
console.warn(`[vitral] "${value.key}" n\xE3o pode ser enviado a outras abas`, e);
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
return value;
|
|
578
|
+
}
|
|
579
|
+
function serializeShared(values) {
|
|
580
|
+
return JSON.stringify(values).replace(/</g, "\\u003c");
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
export {
|
|
584
|
+
events,
|
|
585
|
+
navigate,
|
|
586
|
+
track,
|
|
587
|
+
refresh,
|
|
588
|
+
checkUpdates,
|
|
589
|
+
watchUpdates,
|
|
590
|
+
mountRemote,
|
|
591
|
+
setFrameMounter,
|
|
592
|
+
createSlot,
|
|
593
|
+
defineRemote,
|
|
594
|
+
html,
|
|
595
|
+
unsafeHTML,
|
|
596
|
+
render,
|
|
597
|
+
component,
|
|
598
|
+
shared,
|
|
599
|
+
provide,
|
|
600
|
+
batch,
|
|
601
|
+
memoSelect,
|
|
602
|
+
same,
|
|
603
|
+
persist,
|
|
604
|
+
syncTabs,
|
|
605
|
+
serializeShared
|
|
606
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {
|
|
2
|
+
protocol
|
|
3
|
+
} from "./chunk-GNPFWISJ.js";
|
|
4
|
+
|
|
5
|
+
// src/core/errors.ts
|
|
6
|
+
var ERROR_DOCS = "https://joaogabriel15.github.io/vitral/erros/";
|
|
7
|
+
var RemoteError = class extends Error {
|
|
8
|
+
constructor(code, remote, message, cause) {
|
|
9
|
+
super(`[vitral] ${remote}: ${message} (${ERROR_DOCS}${code})`);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.remote = remote;
|
|
12
|
+
this.cause = cause;
|
|
13
|
+
this.name = "RemoteError";
|
|
14
|
+
this.docs = `${ERROR_DOCS}${code}`;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var isRemoteError = (e) => e?.name === "RemoteError";
|
|
18
|
+
|
|
19
|
+
// src/core/util.ts
|
|
20
|
+
function pageOrigin() {
|
|
21
|
+
return typeof location !== "undefined" ? location.origin : null;
|
|
22
|
+
}
|
|
23
|
+
function absolute(url, base) {
|
|
24
|
+
return new URL(url, base ?? (typeof location !== "undefined" ? location.href : void 0)).href;
|
|
25
|
+
}
|
|
26
|
+
async function withRetry(retries, fn) {
|
|
27
|
+
for (let i = 0; ; i++) {
|
|
28
|
+
try {
|
|
29
|
+
return await fn();
|
|
30
|
+
} catch (e) {
|
|
31
|
+
const retryable = isRemoteError(e) && (e.code === "LOAD_FAILED" || e.code === "TIMEOUT");
|
|
32
|
+
if (!retryable || i >= retries) throw e;
|
|
33
|
+
await new Promise((r) => setTimeout(r, 200 * 2 ** i));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function withTimeout(ms, name, p) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const t = setTimeout(() => reject(new RemoteError("TIMEOUT", name, `n\xE3o respondeu em ${ms}ms`)), ms);
|
|
40
|
+
p.then(resolve, reject).finally(() => clearTimeout(t));
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function fetchBytes(url, timeout, name, init) {
|
|
44
|
+
const ctrl = new AbortController();
|
|
45
|
+
const got = fetch(url, { signal: ctrl.signal, credentials: "omit", ...init }).then(
|
|
46
|
+
(res) => {
|
|
47
|
+
if (!res.ok) throw new RemoteError("LOAD_FAILED", name, `HTTP ${res.status} em ${url}`);
|
|
48
|
+
return res.arrayBuffer();
|
|
49
|
+
},
|
|
50
|
+
(e) => {
|
|
51
|
+
throw new RemoteError("LOAD_FAILED", name, `falha ao baixar ${url}`, e);
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
return withTimeout(timeout, name, got).catch((e) => {
|
|
55
|
+
ctrl.abort();
|
|
56
|
+
throw e;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async function fetchJson(url, timeout, name, init) {
|
|
60
|
+
const text = new TextDecoder().decode(await fetchBytes(url, timeout, name, init));
|
|
61
|
+
try {
|
|
62
|
+
return JSON.parse(text);
|
|
63
|
+
} catch (e) {
|
|
64
|
+
throw new RemoteError("INVALID_MODULE", name, `JSON inv\xE1lido em ${url}`, e);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function addLink(rel, href, props = {}, parent = document.head) {
|
|
68
|
+
return parent.appendChild(Object.assign(document.createElement("link"), { rel, crossOrigin: "anonymous", href }, props));
|
|
69
|
+
}
|
|
70
|
+
function metric(name, stage, start) {
|
|
71
|
+
try {
|
|
72
|
+
performance.measure(`vitral:${name}:${stage}`, { start });
|
|
73
|
+
protocol().settings().onMetric?.({ name, stage, start, duration: performance.now() - start });
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export {
|
|
79
|
+
RemoteError,
|
|
80
|
+
isRemoteError,
|
|
81
|
+
pageOrigin,
|
|
82
|
+
absolute,
|
|
83
|
+
withRetry,
|
|
84
|
+
withTimeout,
|
|
85
|
+
fetchBytes,
|
|
86
|
+
fetchJson,
|
|
87
|
+
addLink,
|
|
88
|
+
metric
|
|
89
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RemoteError
|
|
3
|
+
} from "./chunk-PX7PBCCT.js";
|
|
4
|
+
|
|
5
|
+
// src/core/integrity.ts
|
|
6
|
+
var clean = (b64) => b64.replace(/-/g, "+").replace(/_/g, "/").replace(/=/g, "");
|
|
7
|
+
async function verifyIntegrity(name, bytes, integrity) {
|
|
8
|
+
const hashes = integrity.split(/\s+/).map((token) => /^sha(256|384|512)-([\w+/=-]+)/.exec(token)).filter((m) => !!m);
|
|
9
|
+
if (!hashes.length) throw new RemoteError("INTEGRITY", name, `formato de integrity inv\xE1lido: ${integrity}`);
|
|
10
|
+
const bits = Math.max(...hashes.map((m) => +m[1]));
|
|
11
|
+
const actual = btoa(String.fromCharCode(...new Uint8Array(await crypto.subtle.digest("SHA-" + bits, bytes))));
|
|
12
|
+
const expected = hashes.filter((m) => +m[1] === bits).map((m) => m[2]);
|
|
13
|
+
if (!expected.some((h) => clean(h) === clean(actual))) {
|
|
14
|
+
throw new RemoteError("INTEGRITY", name, `o hash n\xE3o confere: esperado sha${bits}-${expected.join(" ou ")}, obtido sha${bits}-${actual}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
verifyIntegrity
|
|
20
|
+
};
|