bruh 1.13.1 → 2.0.0-beta.1
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/browser/jsx-runtime.mjs +2 -0
- package/dist/browser/jsx-runtime.mjs.map +1 -0
- package/dist/browser.mjs +174 -0
- package/dist/browser.mjs.map +1 -0
- package/dist/cli/node.mjs +16 -0
- package/dist/cli/node.mjs.map +1 -0
- package/dist/components/aside-toc.mjs +162 -0
- package/dist/components/aside-toc.mjs.map +1 -0
- package/dist/components/custom-elements.mjs +52 -0
- package/dist/components/custom-elements.mjs.map +1 -0
- package/dist/components/intl/date-time.mjs +219 -0
- package/dist/components/intl/date-time.mjs.map +1 -0
- package/dist/components/intl/display-name.mjs +71 -0
- package/dist/components/intl/display-name.mjs.map +1 -0
- package/dist/components/intl/language-picker.mjs +102 -0
- package/dist/components/intl/language-picker.mjs.map +1 -0
- package/dist/components/intl/list.mjs +80 -0
- package/dist/components/intl/list.mjs.map +1 -0
- package/dist/components/intl/number.mjs +118 -0
- package/dist/components/intl/number.mjs.map +1 -0
- package/dist/components/intl/plural.mjs +82 -0
- package/dist/components/intl/plural.mjs.map +1 -0
- package/dist/components/intl/utils.mjs +197 -0
- package/dist/components/intl/utils.mjs.map +1 -0
- package/dist/components/optimized-picture/hydrate.mjs +10 -0
- package/dist/components/optimized-picture/hydrate.mjs.map +1 -0
- package/dist/components/optimized-picture/server.mjs +28 -0
- package/dist/components/optimized-picture/server.mjs.map +1 -0
- package/dist/components/utils.mjs +4 -0
- package/dist/components/utils.mjs.map +1 -0
- package/dist/media/images/node.mjs +41 -0
- package/dist/media/images/node.mjs.map +1 -0
- package/dist/polyfills/weakref.mjs +16 -0
- package/dist/polyfills/weakref.mjs.map +1 -0
- package/dist/reactive/sync/transport/websocket/browser.mjs +52 -0
- package/dist/reactive/sync/transport/websocket/browser.mjs.map +1 -0
- package/dist/reactive.mjs +160 -0
- package/dist/reactive.mjs.map +1 -0
- package/dist/server/jsx-runtime.mjs +2 -0
- package/dist/server/jsx-runtime.mjs.map +1 -0
- package/dist/server.mjs +346 -0
- package/dist/server.mjs.map +1 -0
- package/dist/types/cli/index.d.mts +2 -0
- package/dist/types/components/aside-toc/index.d.ts +45 -0
- package/dist/types/components/custom-elements.d.mts +83 -0
- package/dist/types/components/intl/date-time.d.ts +138 -0
- package/dist/types/components/intl/display-name.d.ts +45 -0
- package/dist/types/components/intl/language-picker.d.ts +35 -0
- package/dist/types/components/intl/list.d.ts +41 -0
- package/dist/types/components/intl/number.d.ts +81 -0
- package/dist/types/components/intl/plural.d.ts +60 -0
- package/dist/types/components/intl/utils.d.mts +30 -0
- package/dist/types/components/optimized-picture/hydrate.d.mts +2 -0
- package/dist/types/components/optimized-picture/server.d.ts +8 -0
- package/dist/types/components/utils.d.mts +5 -0
- package/dist/types/dom/browser/jsx-runtime.d.mts +3 -0
- package/dist/types/dom/index.browser.d.mts +127 -0
- package/dist/types/dom/index.server.d.mts +174 -0
- package/dist/types/dom/server/jsx-runtime.d.mts +3 -0
- package/dist/types/dom/types.d.mts +9 -0
- package/dist/types/media/images.node.d.mts +1 -0
- package/dist/types/polyfills/weakref.d.mts +4 -0
- package/dist/types/reactive/index.d.mts +91 -0
- package/dist/types/reactive/sync/transport/websocket/browser.d.mts +11 -0
- package/dist/types/utils/browser.d.mts +2 -0
- package/dist/types/utils/index.d.mts +122 -0
- package/dist/utils/browser.mjs +27 -0
- package/dist/utils/browser.mjs.map +1 -0
- package/dist/utils.mjs +287 -0
- package/dist/utils.mjs.map +1 -0
- package/package.json +122 -19
- package/dist/bruh.es.js +0 -226
- package/dist/bruh.es.js.map +0 -1
- package/dist/bruh.umd.js +0 -2
- package/dist/bruh.umd.js.map +0 -1
- package/src/cli/index.mjs +0 -19
- package/src/components/optimized-picture/hydrate.mjs +0 -10
- package/src/components/optimized-picture/render.mjs +0 -26
- package/src/dom/index.browser.mjs +0 -270
- package/src/dom/index.server.mjs +0 -280
- package/src/index.browser.mjs +0 -3
- package/src/media/images.node.mjs +0 -70
- package/src/reactive/index.mjs +0 -160
- package/src/util/index.mjs +0 -42
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { r, reactiveDo } from '../../../../reactive.mjs';
|
|
2
|
+
|
|
3
|
+
const resolveWebSocketURL = (url = "") => {
|
|
4
|
+
const resolvedURL = new URL(url, location.href);
|
|
5
|
+
if (resolvedURL.protocol !== "ws:" && resolvedURL.protocol !== "wss:")
|
|
6
|
+
resolvedURL.protocol = isSecureContext && resolvedURL.protocol !== "http:" ? "wss:" : "ws:";
|
|
7
|
+
resolvedURL.hash = "";
|
|
8
|
+
return resolvedURL;
|
|
9
|
+
};
|
|
10
|
+
const connectToWebSocket = (url, initialReconnectDelay = 2 ** -2 * 1e3, reconnectDelayCeiling = 2 ** 4 * 1e3) => {
|
|
11
|
+
const resolvedURL = resolveWebSocketURL(url);
|
|
12
|
+
const reactiveSocket = r();
|
|
13
|
+
const attemptConnection = (delay = initialReconnectDelay) => {
|
|
14
|
+
const socket = new WebSocket(resolvedURL);
|
|
15
|
+
socket.addEventListener("open", () => {
|
|
16
|
+
reactiveSocket.value = socket;
|
|
17
|
+
delay = initialReconnectDelay;
|
|
18
|
+
});
|
|
19
|
+
socket.addEventListener("close", ({ wasClean }) => {
|
|
20
|
+
if (wasClean) return;
|
|
21
|
+
setTimeout(() => {
|
|
22
|
+
attemptConnection(Math.min(2 * delay, reconnectDelayCeiling));
|
|
23
|
+
}, delay);
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
attemptConnection();
|
|
27
|
+
return reactiveSocket;
|
|
28
|
+
};
|
|
29
|
+
const handleWebSocket = (maybeReactiveWebSocket, handlers) => {
|
|
30
|
+
let currentSocket;
|
|
31
|
+
reactiveDo(maybeReactiveWebSocket, (socket) => {
|
|
32
|
+
if (!socket) return;
|
|
33
|
+
currentSocket = socket;
|
|
34
|
+
socket.addEventListener("message", ({ data }) => {
|
|
35
|
+
if (typeof data !== "string")
|
|
36
|
+
handlers.raw?.(data);
|
|
37
|
+
else {
|
|
38
|
+
const parsed = JSON.parse(data);
|
|
39
|
+
if (handlers.byType?.hasOwnProperty(parsed.type))
|
|
40
|
+
handlers.byType[parsed.type](parsed);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
return (data) => {
|
|
45
|
+
currentSocket?.send(
|
|
46
|
+
data instanceof Blob || data instanceof ArrayBuffer || ArrayBuffer.isView(data) ? data : JSON.stringify(data)
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export { connectToWebSocket, handleWebSocket, resolveWebSocketURL };
|
|
52
|
+
//# sourceMappingURL=browser.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.mjs","sources":["../../../../../src/reactive/sync/transport/websocket/browser.mts"],"sourcesContent":["import { r, reactiveDo, type MaybeReactive } from \"../../../../reactive/index.mts\"\n\n// Intuitive websocket url resolution\nexport const resolveWebSocketURL = (url: URL | string = \"\") => {\n // Base off of the current location\n const resolvedURL = new URL(url, location.href)\n // Handle implicitly selection of ws: or wss: based on the context\n if (resolvedURL.protocol !== \"ws:\" && resolvedURL.protocol !== \"wss:\")\n resolvedURL.protocol =\n isSecureContext && resolvedURL.protocol !== \"http:\"\n ? \"wss:\"\n : \"ws:\"\n // Fragments aren't allowed in websocket urls\n resolvedURL.hash = \"\"\n return resolvedURL\n}\n\n// websocket connection with automatic reconnection\n// Returned as a promise to a reactive socket because the underlying socket\n// changes every reconnection\nexport const connectToWebSocket = (\n url: URL | string,\n initialReconnectDelay = 2 ** -2 * 1000, // 1/4 second\n reconnectDelayCeiling = 2 ** 4 * 1000 // 16 seconds\n) => {\n const resolvedURL = resolveWebSocketURL(url)\n const reactiveSocket = r<WebSocket>()\n\n // Every attempt makes a new socket, reattempting after a delay\n const attemptConnection = (delay = initialReconnectDelay) => {\n const socket = new WebSocket(resolvedURL)\n\n // The reactive value is updated and the delay reset on success\n socket.addEventListener(\"open\", () => {\n reactiveSocket.value = socket\n delay = initialReconnectDelay\n })\n\n // Whether it fails to connect or the connection is lost later\n socket.addEventListener(\"close\", ({ wasClean }) => {\n // Don't automatically reconnect an intentionally closed websocket\n if (wasClean) return\n\n setTimeout(() => {\n attemptConnection(Math.min(2 * delay, reconnectDelayCeiling))\n }, delay)\n })\n }\n\n // kickoff\n attemptConnection()\n\n return reactiveSocket\n}\n\nexport type WebSocketHandlers = {\n raw?: (data: Blob | ArrayBuffer) => void\n byType?: {\n [type: string]: (data: any) => void\n }\n}\n\n// Handle automatic JSON over websockets, where the websocket can be reactive\nexport const handleWebSocket = (maybeReactiveWebSocket: MaybeReactive<WebSocket | undefined>, handlers: WebSocketHandlers) => {\n let currentSocket: WebSocket | undefined\n\n // Account for a potentially reactive socket\n reactiveDo(maybeReactiveWebSocket, socket => {\n if (!socket) return\n\n currentSocket = socket\n\n // Handle messages, parsing strings as JSON\n socket.addEventListener(\"message\", ({ data }) => {\n // Raw blob/arraybuffer (socket.binaryType, defaults to blob)\n if (typeof data !== \"string\")\n handlers.raw?.(data)\n // assume strings are JSON with {\"type\":\"messageType\"}\n else {\n const parsed = JSON.parse(data)\n if (handlers.byType?.hasOwnProperty(parsed.type))\n handlers.byType[parsed.type](parsed)\n }\n })\n })\n\n // A send function that automatically converts objects to JSON\n return (data: unknown) => {\n currentSocket?.send(\n data instanceof Blob || data instanceof ArrayBuffer || ArrayBuffer.isView(data)\n ? data\n : JSON.stringify(data)\n )\n }\n}\n"],"names":[],"mappings":";;AAGa,MAAA,mBAAA,GAAsB,CAAC,GAAA,GAAoB,EAAO,KAAA;AAE7D,EAAA,MAAM,WAAc,GAAA,IAAI,GAAI,CAAA,GAAA,EAAK,SAAS,IAAI,CAAA;AAE9C,EAAA,IAAI,WAAY,CAAA,QAAA,KAAa,KAAS,IAAA,WAAA,CAAY,QAAa,KAAA,MAAA;AAC7D,IAAA,WAAA,CAAY,QACV,GAAA,eAAA,IAAmB,WAAY,CAAA,QAAA,KAAa,UACxC,MACA,GAAA,KAAA;AAER,EAAA,WAAA,CAAY,IAAO,GAAA,EAAA;AACnB,EAAO,OAAA,WAAA;AACT;AAKa,MAAA,kBAAA,GAAqB,CAChC,GAAA,EACA,qBAAwB,GAAA,CAAA,IAAK,KAAK,GAClC,EAAA,qBAAA,GAAwB,CAAM,IAAA,CAAA,GAAI,GAC/B,KAAA;AACH,EAAM,MAAA,WAAA,GAAc,oBAAoB,GAAG,CAAA;AAC3C,EAAA,MAAM,iBAAiB,CAAa,EAAA;AAGpC,EAAM,MAAA,iBAAA,GAAoB,CAAC,KAAA,GAAQ,qBAA0B,KAAA;AAC3D,IAAM,MAAA,MAAA,GAAS,IAAI,SAAA,CAAU,WAAW,CAAA;AAGxC,IAAO,MAAA,CAAA,gBAAA,CAAiB,QAAQ,MAAM;AACpC,MAAA,cAAA,CAAe,KAAQ,GAAA,MAAA;AACvB,MAAQ,KAAA,GAAA,qBAAA;AAAA,KACT,CAAA;AAGD,IAAA,MAAA,CAAO,gBAAiB,CAAA,OAAA,EAAS,CAAC,EAAE,UAAe,KAAA;AAEjD,MAAA,IAAI,QAAU,EAAA;AAEd,MAAA,UAAA,CAAW,MAAM;AACf,QAAA,iBAAA,CAAkB,IAAK,CAAA,GAAA,CAAI,CAAI,GAAA,KAAA,EAAO,qBAAqB,CAAC,CAAA;AAAA,SAC3D,KAAK,CAAA;AAAA,KACT,CAAA;AAAA,GACH;AAGA,EAAkB,iBAAA,EAAA;AAElB,EAAO,OAAA,cAAA;AACT;AAUa,MAAA,eAAA,GAAkB,CAAC,sBAAA,EAA8D,QAAgC,KAAA;AAC5H,EAAI,IAAA,aAAA;AAGJ,EAAA,UAAA,CAAW,wBAAwB,CAAU,MAAA,KAAA;AAC3C,IAAA,IAAI,CAAC,MAAQ,EAAA;AAEb,IAAgB,aAAA,GAAA,MAAA;AAGhB,IAAA,MAAA,CAAO,gBAAiB,CAAA,SAAA,EAAW,CAAC,EAAE,MAAW,KAAA;AAE/C,MAAA,IAAI,OAAO,IAAS,KAAA,QAAA;AAClB,QAAA,QAAA,CAAS,MAAM,IAAI,CAAA;AAAA,WAEhB;AACH,QAAM,MAAA,MAAA,GAAS,IAAK,CAAA,KAAA,CAAM,IAAI,CAAA;AAC9B,QAAA,IAAI,QAAS,CAAA,MAAA,EAAQ,cAAe,CAAA,MAAA,CAAO,IAAI,CAAA;AAC7C,UAAA,QAAA,CAAS,MAAO,CAAA,MAAA,CAAO,IAAI,CAAA,CAAE,MAAM,CAAA;AAAA;AACvC,KACD,CAAA;AAAA,GACF,CAAA;AAGD,EAAA,OAAO,CAAC,IAAkB,KAAA;AACxB,IAAe,aAAA,EAAA,IAAA;AAAA,MACb,IAAA,YAAgB,IAAQ,IAAA,IAAA,YAAgB,WAAe,IAAA,WAAA,CAAY,MAAO,CAAA,IAAI,CAC1E,GAAA,IAAA,GACA,IAAK,CAAA,SAAA,CAAU,IAAI;AAAA,KACzB;AAAA,GACF;AACF;;;;"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
const isReactiveSymbol = /* @__PURE__ */ Symbol.for("bruh reactive");
|
|
2
|
+
const isReactive = (x) => (
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
x?.[isReactiveSymbol] === true
|
|
5
|
+
);
|
|
6
|
+
class SimpleReactive {
|
|
7
|
+
[isReactiveSymbol] = true;
|
|
8
|
+
#value;
|
|
9
|
+
#reactions = /* @__PURE__ */ new Set();
|
|
10
|
+
constructor(value) {
|
|
11
|
+
this.#value = value;
|
|
12
|
+
}
|
|
13
|
+
get value() {
|
|
14
|
+
return this.#value;
|
|
15
|
+
}
|
|
16
|
+
set value(newValue) {
|
|
17
|
+
if (newValue === this.#value)
|
|
18
|
+
return;
|
|
19
|
+
this.#value = newValue;
|
|
20
|
+
for (const reaction of this.#reactions)
|
|
21
|
+
try {
|
|
22
|
+
reaction();
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* @param reaction called every time that the value changes
|
|
28
|
+
* @returns a function that stops the reactions
|
|
29
|
+
*/
|
|
30
|
+
addReaction(reaction) {
|
|
31
|
+
this.#reactions.add(reaction);
|
|
32
|
+
return () => this.#reactions.delete(reaction);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
class FunctionalReactive {
|
|
36
|
+
[isReactiveSymbol] = true;
|
|
37
|
+
#weakRef = new WeakRef(this);
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
#value;
|
|
40
|
+
#reactions = /* @__PURE__ */ new Set();
|
|
41
|
+
// For derived nodes, this is the derivation function
|
|
42
|
+
// @ts-ignore
|
|
43
|
+
#f;
|
|
44
|
+
// Source nodes are 0 deep in the derivation graph
|
|
45
|
+
// This is for topological sort
|
|
46
|
+
#depth = 0;
|
|
47
|
+
// All nodes have a set of derivatives that update when the node changes
|
|
48
|
+
#derivatives = /* @__PURE__ */ new Set();
|
|
49
|
+
// Keep track of all the pending changes from the value setter
|
|
50
|
+
static #settersQueue = /* @__PURE__ */ new Map();
|
|
51
|
+
// A queue of derivatives to potentially update, sorted into sets by depth
|
|
52
|
+
// This starts with depth 1 and can potentially have holes
|
|
53
|
+
static #derivativesQueue = [];
|
|
54
|
+
// A queue of reactions to run after the graph is fully updated
|
|
55
|
+
static #reactionsQueue = [];
|
|
56
|
+
constructor(x, f) {
|
|
57
|
+
if (!f) {
|
|
58
|
+
const this_2 = this;
|
|
59
|
+
const value = x;
|
|
60
|
+
this_2.#value = value;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const this_ = this;
|
|
64
|
+
const dependencies = x;
|
|
65
|
+
try {
|
|
66
|
+
this_.#value = f();
|
|
67
|
+
} catch (e) {
|
|
68
|
+
this_.#value = e;
|
|
69
|
+
}
|
|
70
|
+
this_.#f = f;
|
|
71
|
+
this_.#depth = Math.max(0, ...dependencies.map((dependency) => dependency.#depth)) + 1;
|
|
72
|
+
dependencies.forEach((dependency) => dependency.#derivatives.add(this_.#weakRef));
|
|
73
|
+
}
|
|
74
|
+
get value() {
|
|
75
|
+
if (FunctionalReactive.#settersQueue.size) {
|
|
76
|
+
if (this.#depth === 0) {
|
|
77
|
+
const this_ = this;
|
|
78
|
+
if (FunctionalReactive.#settersQueue.has(this_))
|
|
79
|
+
return FunctionalReactive.#settersQueue.get(this_);
|
|
80
|
+
} else {
|
|
81
|
+
FunctionalReactive.applyUpdates();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return this.#value;
|
|
85
|
+
}
|
|
86
|
+
set value(newValue) {
|
|
87
|
+
if (this.#depth !== 0)
|
|
88
|
+
return;
|
|
89
|
+
const this_ = this;
|
|
90
|
+
if (newValue === this.#value) {
|
|
91
|
+
FunctionalReactive.#settersQueue.delete(this_);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (!FunctionalReactive.#settersQueue.size)
|
|
95
|
+
queueMicrotask(FunctionalReactive.applyUpdates);
|
|
96
|
+
FunctionalReactive.#settersQueue.set(this_, newValue);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* @param reaction called every time that the value changes
|
|
100
|
+
* @returns a function that stops the reactions
|
|
101
|
+
*/
|
|
102
|
+
addReaction(reaction) {
|
|
103
|
+
this.#reactions.add(reaction);
|
|
104
|
+
return () => this.#reactions.delete(reaction);
|
|
105
|
+
}
|
|
106
|
+
// Apply an update for a node and queue its derivatives if it actually changed
|
|
107
|
+
#applyUpdate(newValue) {
|
|
108
|
+
if (newValue === this.#value)
|
|
109
|
+
return;
|
|
110
|
+
this.#value = newValue;
|
|
111
|
+
FunctionalReactive.#reactionsQueue.push(...this.#reactions);
|
|
112
|
+
this.#derivatives.forEach((weakRef) => {
|
|
113
|
+
const derivative = weakRef.deref();
|
|
114
|
+
if (!derivative) {
|
|
115
|
+
this.#derivatives.delete(weakRef);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const depthSet = FunctionalReactive.#derivativesQueue[derivative.#depth] ??= /* @__PURE__ */ new Set();
|
|
119
|
+
depthSet.add(derivative);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Apply pending updates from actually changed source nodes
|
|
124
|
+
*/
|
|
125
|
+
static applyUpdates() {
|
|
126
|
+
if (!FunctionalReactive.#settersQueue.size)
|
|
127
|
+
return;
|
|
128
|
+
for (const [sourceNode, newValue] of FunctionalReactive.#settersQueue.entries())
|
|
129
|
+
sourceNode.#applyUpdate(newValue);
|
|
130
|
+
FunctionalReactive.#settersQueue.clear();
|
|
131
|
+
for (const depthSet of FunctionalReactive.#derivativesQueue) if (depthSet)
|
|
132
|
+
for (const derivative of depthSet)
|
|
133
|
+
try {
|
|
134
|
+
derivative.#applyUpdate(derivative.#f());
|
|
135
|
+
} catch (e) {
|
|
136
|
+
derivative.#applyUpdate(e);
|
|
137
|
+
}
|
|
138
|
+
FunctionalReactive.#derivativesQueue.length = 0;
|
|
139
|
+
for (const reaction of FunctionalReactive.#reactionsQueue)
|
|
140
|
+
try {
|
|
141
|
+
reaction();
|
|
142
|
+
} catch {
|
|
143
|
+
}
|
|
144
|
+
FunctionalReactive.#reactionsQueue.length = 0;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const r = (x, f) => (
|
|
148
|
+
// @ts-ignore
|
|
149
|
+
new FunctionalReactive(x, f)
|
|
150
|
+
);
|
|
151
|
+
const reactiveDo = (x, f) => {
|
|
152
|
+
if (isReactive(x)) {
|
|
153
|
+
f(x.value);
|
|
154
|
+
return x.addReaction(() => f(x.value));
|
|
155
|
+
}
|
|
156
|
+
f(x);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export { FunctionalReactive, SimpleReactive, isReactive, isReactiveSymbol, r, reactiveDo };
|
|
160
|
+
//# sourceMappingURL=reactive.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactive.mjs","sources":["../src/reactive/index.mts"],"sourcesContent":["export const isReactiveSymbol = Symbol.for(\"bruh reactive\")\n\nexport const isReactive = (x: unknown): x is Reactive<unknown> =>\n // @ts-ignore\n x?.[isReactiveSymbol] === true\n\ntype Reaction = () => void\ntype StopReacting = () => void\n\nexport interface Reactive<T> {\n [isReactiveSymbol]: true\n\n value: T\n\n addReaction(reaction: Reaction): StopReacting\n}\n\nexport type Unreactive<T> = Exclude<T, { [isReactiveSymbol]: true }>\n\nexport type MaybeReactive<T> = Reactive<T> | Unreactive<T>\n\n/**\n * A super simple and performant reactive value implementation\n */\nexport class SimpleReactive<T> implements Reactive<T> {\n [isReactiveSymbol] = true as const\n\n #value: T\n #reactions = new Set<Reaction>()\n\n constructor(value: T) {\n this.#value = value\n }\n\n get value() {\n return this.#value\n }\n\n set value(newValue) {\n if (newValue === this.#value)\n return\n\n this.#value = newValue\n for (const reaction of this.#reactions)\n try { reaction() } catch {}\n }\n\n /**\n * @param reaction called every time that the value changes\n * @returns a function that stops the reactions\n */\n addReaction(reaction: Reaction) {\n this.#reactions.add(reaction)\n\n return () =>\n this.#reactions.delete(reaction)\n }\n}\n\nexport type SourceNode<T> = FunctionalReactive<T, \"source\">\nexport type DerivativeNode<T> = FunctionalReactive<T, \"derivative\">\n\n/**\n * A reactive implementation for building functional reactive graphs.\n * Ensures state consistency, minimal node updates, and transparent update batching.\n */\nexport class FunctionalReactive<T, U extends \"source\" | \"derivative\" = any> implements Reactive<T> {\n [isReactiveSymbol] = true as const\n\n #weakRef = new WeakRef(this)\n\n // @ts-ignore\n #value: T\n #reactions = new Set<Reaction>()\n\n // For derived nodes, this is the derivation function\n // @ts-ignore\n #f:\n U extends \"derivative\"\n ? () => T\n : never\n\n // Source nodes are 0 deep in the derivation graph\n // This is for topological sort\n #depth:\n U extends \"source\"\n ? 0\n : number // natural, > 0\n = 0\n\n // All nodes have a set of derivatives that update when the node changes\n #derivatives = new Set<WeakRef<DerivativeNode<unknown>>>()\n\n // Keep track of all the pending changes from the value setter\n static #settersQueue = new Map<SourceNode<unknown>, unknown>()\n\n // A queue of derivatives to potentially update, sorted into sets by depth\n // This starts with depth 1 and can potentially have holes\n static #derivativesQueue: Array<Set<DerivativeNode<unknown>> | undefined> = []\n\n // A queue of reactions to run after the graph is fully updated\n static #reactionsQueue: Array<Reaction> = []\n\n constructor(value: T)\n constructor(\n dependencies: ReadonlyArray<FunctionalReactive<unknown>>,\n f: () => T\n )\n constructor(\n x: T | ReadonlyArray<FunctionalReactive<unknown>>,\n f?: undefined | (() => T)\n ) {\n // No derivation function means this is a source node\n if (!f) {\n const this_ = this as SourceNode<T>\n const value = x as T\n\n this_.#value = value\n return\n }\n\n // Derived node\n const this_ = this as DerivativeNode<T>\n const dependencies = x as ReadonlyArray<FunctionalReactive<unknown>>\n\n try {\n this_.#value = f()\n }\n catch (e: any) {\n this_.#value = e\n }\n this_.#f = f\n\n this_.#depth = Math.max(0, ...dependencies.map(dependency => dependency.#depth)) + 1\n\n dependencies.forEach(dependency => dependency.#derivatives.add(this_.#weakRef))\n }\n\n get value(): T {\n // If there are any pending updates\n if (FunctionalReactive.#settersQueue.size) {\n // If this is a source node that was updated, just return that\n // new value without actually updating any derived nodes yet\n if (this.#depth === 0) {\n const this_ = this as SourceNode<T>\n if (FunctionalReactive.#settersQueue.has(this_))\n return FunctionalReactive.#settersQueue.get(this_) as T\n }\n // Heuristic quick invalidation for derived nodes\n // Apply updates now, it's ok that there's already a microtask queued for this\n else {\n FunctionalReactive.applyUpdates()\n }\n }\n\n return this.#value\n }\n\n set value(newValue) {\n // Only allow source nodes to be directly updated\n if (this.#depth !== 0)\n return\n\n const this_ = this as SourceNode<T>\n\n if (newValue === this.#value) {\n FunctionalReactive.#settersQueue.delete(this_)\n return\n }\n\n // Unless asked for earlier, these updates are just queued up until the microtasks run\n if (!FunctionalReactive.#settersQueue.size)\n queueMicrotask(FunctionalReactive.applyUpdates)\n\n FunctionalReactive.#settersQueue.set(this_, newValue)\n }\n\n /**\n * @param reaction called every time that the value changes\n * @returns a function that stops the reactions\n */\n addReaction(reaction: Reaction) {\n this.#reactions.add(reaction)\n\n return () =>\n this.#reactions.delete(reaction)\n }\n\n // Apply an update for a node and queue its derivatives if it actually changed\n #applyUpdate(newValue: T) {\n if (newValue === this.#value)\n return\n\n this.#value = newValue\n FunctionalReactive.#reactionsQueue.push(...this.#reactions)\n\n this.#derivatives.forEach(weakRef => {\n const derivative = weakRef.deref()\n if (!derivative) {\n this.#derivatives.delete(weakRef)\n return\n }\n\n const depthSet = FunctionalReactive.#derivativesQueue[derivative.#depth] ??= new Set()\n depthSet.add(derivative)\n })\n }\n\n /**\n * Apply pending updates from actually changed source nodes\n */\n static applyUpdates() {\n if (!FunctionalReactive.#settersQueue.size)\n return\n\n // Bootstrap by applying the updates from the pending setters\n for (const [sourceNode, newValue] of FunctionalReactive.#settersQueue.entries())\n sourceNode.#applyUpdate(newValue)\n FunctionalReactive.#settersQueue.clear()\n\n // Iterate down the depths, ignoring holes\n // Note that both the queue (Array) and each depth Set iterators update as items are added\n for (const depthSet of FunctionalReactive.#derivativesQueue) if (depthSet)\n for (const derivative of depthSet)\n try {\n derivative.#applyUpdate(derivative.#f())\n }\n catch (e) {\n derivative.#applyUpdate(e)\n }\n FunctionalReactive.#derivativesQueue.length = 0\n\n // Call all reactions now that the graph has a fully consistent state\n for (const reaction of FunctionalReactive.#reactionsQueue)\n try { reaction() } catch {}\n FunctionalReactive.#reactionsQueue.length = 0\n }\n}\n\ntype R = {\n /**\n * An initially undefined source node\n */\n <T>(): SourceNode<T | undefined>\n\n /**\n * A source node\n */\n <T>(value: T): SourceNode<T>\n\n /**\n * A derived node\n */\n <T>(\n dependencies: ReadonlyArray<FunctionalReactive<unknown>>,\n f: () => T\n ): DerivativeNode<T>\n}\n/**\n * A convenient wrapper for FunctionalReactive\n */\nexport const r: R = <T extends unknown>(\n x?: T | ReadonlyArray<FunctionalReactive<unknown>>,\n f?: undefined | (() => T)\n) =>\n // @ts-ignore\n new FunctionalReactive(x, f)\n\ntype ReactiveDo = {\n /**\n * Calls the given function with the reactive's value whenever it changes\n * @returns a function that stops the reactions\n */\n <T>(\n reactive: Reactive<T>,\n f: (value: T) => unknown\n ): StopReacting\n\n /**\n * Calls the given function with the value once\n */\n <T>(\n value: Unreactive<T>,\n f: (value: Unreactive<T>) => unknown\n ): undefined\n\n /**\n * If the value is not reactive, it calls the given function with that value once.\n * If it is a reactive value, it calls the given function with the reactive's value whenever it changes.\n * @returns a function that stops the reactions, if the value is reactive\n */\n <T>(\n x: MaybeReactive<T>,\n f: (value: T) => unknown\n ): StopReacting | undefined\n}\n/**\n * Do something with a value, updating if it is reactive\n */\nexport const reactiveDo: ReactiveDo = <T extends unknown>(\n x: MaybeReactive<T>,\n f: (value: T) => unknown\n): any => {\n if (isReactive(x)) {\n f(x.value)\n return x.addReaction(() => f(x.value))\n }\n\n f(x)\n}\n"],"names":["this_"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx-runtime.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/dist/server.mjs
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { makePromiseQueue } from './utils.mjs';
|
|
2
|
+
|
|
3
|
+
const isMetaNode = /* @__PURE__ */ Symbol.for("bruh meta node");
|
|
4
|
+
const isMetaTextNode = /* @__PURE__ */ Symbol.for("bruh meta text node");
|
|
5
|
+
const isMetaElement = /* @__PURE__ */ Symbol.for("bruh meta element");
|
|
6
|
+
const isMetaRawString = /* @__PURE__ */ Symbol.for("bruh meta raw string");
|
|
7
|
+
const voidElements = /* @__PURE__ */ new Set([
|
|
8
|
+
"base",
|
|
9
|
+
"link",
|
|
10
|
+
"meta",
|
|
11
|
+
"hr",
|
|
12
|
+
"br",
|
|
13
|
+
"wbr",
|
|
14
|
+
"area",
|
|
15
|
+
"img",
|
|
16
|
+
"track",
|
|
17
|
+
"embed",
|
|
18
|
+
"param",
|
|
19
|
+
"source",
|
|
20
|
+
"col",
|
|
21
|
+
"input"
|
|
22
|
+
]);
|
|
23
|
+
const isVoidElement = (element) => voidElements.has(element);
|
|
24
|
+
const escapeForElementReplacer = (match) => match === "&" ? "&" : "<";
|
|
25
|
+
const escapeForElement = (x) => (x + "").replace(/[&<]/g, escapeForElementReplacer);
|
|
26
|
+
const escapeForScript = (x) => (x + "").replace(/<!--/g, "\\x3C!--").replace(/<script/g, "\\x3Cscript").replace(/<\/script/g, "\\x3C/script");
|
|
27
|
+
const escapeForStyle = (x) => (x + "").replace(/<!--/g, "\\x3C!--").replace(/<style/g, "\\x3Cstyle").replace(/<\/style/g, "\\x3C/style");
|
|
28
|
+
const escapeForDoubleQuotedAttributeReplacer = (match) => match === "&" ? "&" : """;
|
|
29
|
+
const escapeForDoubleQuotedAttribute = (x) => (x + "").replace(/[&"]/g, escapeForDoubleQuotedAttributeReplacer);
|
|
30
|
+
function* attributesToIterator(attributes) {
|
|
31
|
+
for (const name in attributes) {
|
|
32
|
+
const value = attributes[name];
|
|
33
|
+
if (value == null || value === false || value instanceof Promise)
|
|
34
|
+
continue;
|
|
35
|
+
yield ` ${name}`;
|
|
36
|
+
if (value === true || value === "")
|
|
37
|
+
continue;
|
|
38
|
+
yield `="${escapeForDoubleQuotedAttribute(value)}"`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function* attributesToAsyncIterator(attributes) {
|
|
42
|
+
for (const name in attributes) {
|
|
43
|
+
try {
|
|
44
|
+
const value = await attributes[name];
|
|
45
|
+
if (value == null || value === false)
|
|
46
|
+
continue;
|
|
47
|
+
yield ` ${name}`;
|
|
48
|
+
if (value === true || value === "")
|
|
49
|
+
continue;
|
|
50
|
+
yield `="${escapeForDoubleQuotedAttribute(value)}"`;
|
|
51
|
+
} catch (e) {
|
|
52
|
+
console.error(e);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
class MetaTextNode {
|
|
58
|
+
[isMetaNode] = true;
|
|
59
|
+
[isMetaTextNode] = true;
|
|
60
|
+
textContent;
|
|
61
|
+
tag;
|
|
62
|
+
constructor(textContent) {
|
|
63
|
+
this.textContent = textContent;
|
|
64
|
+
}
|
|
65
|
+
*[Symbol.iterator]() {
|
|
66
|
+
yield `<bruh-text style="all:unset;display:inline"`;
|
|
67
|
+
if (this.tag)
|
|
68
|
+
yield* attributesToIterator({ tag: this.tag });
|
|
69
|
+
yield ">";
|
|
70
|
+
if (this.textContent instanceof Promise)
|
|
71
|
+
yield "<!--Promise-->";
|
|
72
|
+
else
|
|
73
|
+
yield escapeForElement(this.textContent);
|
|
74
|
+
yield "</bruh-text>";
|
|
75
|
+
}
|
|
76
|
+
async *[Symbol.asyncIterator]() {
|
|
77
|
+
yield `<bruh-text style="all:unset;display:inline"`;
|
|
78
|
+
if (this.tag)
|
|
79
|
+
yield* attributesToAsyncIterator({ tag: this.tag });
|
|
80
|
+
yield ">";
|
|
81
|
+
try {
|
|
82
|
+
yield escapeForElement(await this.textContent);
|
|
83
|
+
} catch (e) {
|
|
84
|
+
console.error(e);
|
|
85
|
+
}
|
|
86
|
+
yield "</bruh-text>";
|
|
87
|
+
}
|
|
88
|
+
toString() {
|
|
89
|
+
let result = "";
|
|
90
|
+
for (const chunk of this)
|
|
91
|
+
result += chunk;
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
async toStringPromise() {
|
|
95
|
+
let result = "";
|
|
96
|
+
for await (const chunk of this)
|
|
97
|
+
result += chunk;
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
setTag(tag) {
|
|
101
|
+
this.tag = tag;
|
|
102
|
+
return this;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
class MetaElement {
|
|
106
|
+
[isMetaNode] = true;
|
|
107
|
+
[isMetaElement] = true;
|
|
108
|
+
name;
|
|
109
|
+
attributes = {};
|
|
110
|
+
children = [];
|
|
111
|
+
#isRawTextOnly;
|
|
112
|
+
#escape;
|
|
113
|
+
constructor(name) {
|
|
114
|
+
this.name = name;
|
|
115
|
+
this.#isRawTextOnly = name === "script" || name === "style";
|
|
116
|
+
this.#escape = name === "script" ? escapeForScript : name === "style" ? escapeForStyle : escapeForElement;
|
|
117
|
+
}
|
|
118
|
+
*#childChunks(children) {
|
|
119
|
+
const partiallyFlattened = Array.isArray(children) ? children.flat(Infinity) : children;
|
|
120
|
+
for (const child of partiallyFlattened) {
|
|
121
|
+
if (child == null || typeof child === "boolean") {
|
|
122
|
+
if (this.#isRawTextOnly)
|
|
123
|
+
continue;
|
|
124
|
+
else
|
|
125
|
+
yield `<!--${child}-->`;
|
|
126
|
+
} else if (typeof child === "object") {
|
|
127
|
+
if (!this.#isRawTextOnly && isMetaNode in child)
|
|
128
|
+
yield* child;
|
|
129
|
+
else if (!this.#isRawTextOnly && child instanceof Promise)
|
|
130
|
+
yield "<!--Promise-->";
|
|
131
|
+
else if (!this.#isRawTextOnly && Symbol.asyncIterator in child)
|
|
132
|
+
yield "<!--asyncIterator-->";
|
|
133
|
+
else if (isMetaRawString in child)
|
|
134
|
+
yield child;
|
|
135
|
+
else if (Symbol.iterator in child)
|
|
136
|
+
yield* this.#childChunks(child);
|
|
137
|
+
} else
|
|
138
|
+
yield this.#escape(child);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async *#asyncChildChunks(children) {
|
|
142
|
+
const partiallyFlattened = Array.isArray(children) ? children.flat(Infinity) : children;
|
|
143
|
+
for await (const child of partiallyFlattened) {
|
|
144
|
+
if (child == null || typeof child === "boolean") {
|
|
145
|
+
if (this.#isRawTextOnly)
|
|
146
|
+
continue;
|
|
147
|
+
else
|
|
148
|
+
yield `<!--${child}-->`;
|
|
149
|
+
} else if (typeof child === "object") {
|
|
150
|
+
if (!this.#isRawTextOnly && isMetaNode in child)
|
|
151
|
+
yield* child;
|
|
152
|
+
else if (isMetaRawString in child)
|
|
153
|
+
yield child;
|
|
154
|
+
else if (Symbol.iterator in child || Symbol.asyncIterator in child)
|
|
155
|
+
yield* this.#asyncChildChunks(child);
|
|
156
|
+
} else
|
|
157
|
+
yield this.#escape(child);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
*[Symbol.iterator]() {
|
|
161
|
+
yield `<${this.name}`;
|
|
162
|
+
yield* attributesToIterator(this.attributes);
|
|
163
|
+
yield ">";
|
|
164
|
+
if (isVoidElement(this.name))
|
|
165
|
+
return;
|
|
166
|
+
yield* this.#childChunks(this.children);
|
|
167
|
+
yield `</${this.name}>`;
|
|
168
|
+
}
|
|
169
|
+
async *[Symbol.asyncIterator]() {
|
|
170
|
+
yield `<${this.name}`;
|
|
171
|
+
yield* attributesToAsyncIterator(this.attributes);
|
|
172
|
+
yield ">";
|
|
173
|
+
if (isVoidElement(this.name))
|
|
174
|
+
return;
|
|
175
|
+
yield* this.#asyncChildChunks(this.children);
|
|
176
|
+
yield `</${this.name}>`;
|
|
177
|
+
}
|
|
178
|
+
toString() {
|
|
179
|
+
let result = "";
|
|
180
|
+
for (const chunk of this)
|
|
181
|
+
result += chunk;
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
async toStringPromise() {
|
|
185
|
+
let result = "";
|
|
186
|
+
for await (const chunk of this)
|
|
187
|
+
result += chunk;
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
class MetaRawString extends String {
|
|
192
|
+
[isMetaRawString] = true;
|
|
193
|
+
constructor(string) {
|
|
194
|
+
super(string);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const applyStyles = (element, styles) => {
|
|
198
|
+
const currentStyles = typeof element.attributes.style === "string" ? Object.fromEntries(
|
|
199
|
+
element.attributes.style.split(";").filter((s) => s.length).map((declaration) => declaration.split(":").map((s) => s.trim()))
|
|
200
|
+
) : {};
|
|
201
|
+
Object.entries(styles).forEach(([property, value]) => {
|
|
202
|
+
if (value != null && typeof value !== "boolean")
|
|
203
|
+
currentStyles[property] = value;
|
|
204
|
+
else
|
|
205
|
+
delete currentStyles[property];
|
|
206
|
+
});
|
|
207
|
+
element.attributes.style = Object.entries(currentStyles).map(([property, value]) => `${property}:${value}`).join(";");
|
|
208
|
+
};
|
|
209
|
+
const applyClasses = (element, classes) => {
|
|
210
|
+
const currentClasses = new Set(
|
|
211
|
+
typeof element.attributes.class === "string" ? element.attributes.class.split(/\s+/).filter((s) => s.length) : void 0
|
|
212
|
+
);
|
|
213
|
+
Object.entries(classes).forEach(([name, value]) => {
|
|
214
|
+
if (value)
|
|
215
|
+
currentClasses.add(name);
|
|
216
|
+
else
|
|
217
|
+
currentClasses.delete(name);
|
|
218
|
+
});
|
|
219
|
+
element.attributes.class = [...currentClasses].join(" ");
|
|
220
|
+
};
|
|
221
|
+
const applyAttributes = (element, attributes) => {
|
|
222
|
+
Object.assign(element.attributes, attributes);
|
|
223
|
+
};
|
|
224
|
+
const rawString = (string) => new MetaRawString(string);
|
|
225
|
+
const t = (textContent) => new MetaTextNode(textContent);
|
|
226
|
+
const jsx = (nameOrComponent, props_, key) => {
|
|
227
|
+
if (key !== void 0)
|
|
228
|
+
props_.key = key;
|
|
229
|
+
if (typeof nameOrComponent !== "string") {
|
|
230
|
+
const component = nameOrComponent;
|
|
231
|
+
const props2 = props_;
|
|
232
|
+
return component(props2);
|
|
233
|
+
}
|
|
234
|
+
const name = nameOrComponent;
|
|
235
|
+
const props = props_;
|
|
236
|
+
if (typeof props.bruh === "object" && !(props.bruh instanceof Promise)) {
|
|
237
|
+
props.bruh;
|
|
238
|
+
delete props.bruh;
|
|
239
|
+
}
|
|
240
|
+
const element = new MetaElement(name);
|
|
241
|
+
if ("children" in props) {
|
|
242
|
+
if (Array.isArray(props.children))
|
|
243
|
+
element.children.push(...props.children);
|
|
244
|
+
else
|
|
245
|
+
element.children.push(props.children);
|
|
246
|
+
delete props.children;
|
|
247
|
+
}
|
|
248
|
+
if ("style" in props && props.style != null && typeof props.style === "object" && !(props.style instanceof Promise)) {
|
|
249
|
+
applyStyles(element, props.style);
|
|
250
|
+
delete props.style;
|
|
251
|
+
}
|
|
252
|
+
if ("class" in props && props.class != null && typeof props.class === "object" && !(props.class instanceof Promise)) {
|
|
253
|
+
applyClasses(element, props.class);
|
|
254
|
+
delete props.class;
|
|
255
|
+
}
|
|
256
|
+
applyAttributes(element, props);
|
|
257
|
+
return element;
|
|
258
|
+
};
|
|
259
|
+
const Fragment = (props) => props.children;
|
|
260
|
+
const replaceDeferredScriptContent = `"use strict";customElements.define("bruh-deferred",class extends HTMLElement{connectedCallback(){const t=this.previousElementSibling;document.getElementById(this.dataset.replace).replaceWith(t.content);t.remove();this.remove()}})`;
|
|
261
|
+
const replaceDeferredHash = "sha512-+xpsela6B2jMNhk2cPpAgB4Z89EeB6yltQ208+kvcbUKlkg11dBjAlj2FbNFxeE0kqOuZhdVVldl3hz1yZD38Q==";
|
|
262
|
+
class MetaDocument {
|
|
263
|
+
#metaElementOrFunction;
|
|
264
|
+
constructor(metaElementOrFunction) {
|
|
265
|
+
this.#metaElementOrFunction = metaElementOrFunction;
|
|
266
|
+
}
|
|
267
|
+
*[Symbol.iterator]() {
|
|
268
|
+
if (!(isMetaElement in this.#metaElementOrFunction))
|
|
269
|
+
throw new Error("Not a meta element");
|
|
270
|
+
const metaElement = this.#metaElementOrFunction;
|
|
271
|
+
yield "<!doctype html>";
|
|
272
|
+
yield* metaElement;
|
|
273
|
+
}
|
|
274
|
+
async *[Symbol.asyncIterator]({ deferred: allowDefer = true } = {}) {
|
|
275
|
+
yield "<!doctype html>";
|
|
276
|
+
if (isMetaElement in this.#metaElementOrFunction) {
|
|
277
|
+
const metaElement = this.#metaElementOrFunction;
|
|
278
|
+
yield* metaElement;
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const documentFunction = this.#metaElementOrFunction;
|
|
282
|
+
if (!allowDefer) {
|
|
283
|
+
const defer2 = ({ content }) => content;
|
|
284
|
+
yield* documentFunction({ defer: defer2 });
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const deferQueue = makePromiseQueue();
|
|
288
|
+
let deferCount = 0;
|
|
289
|
+
const defer = ({ placeholder, content }) => {
|
|
290
|
+
const id = `bruh-deferred-${deferCount++}`;
|
|
291
|
+
deferQueue.enqueue(content.then((content2) => ({ id, content: content2 })));
|
|
292
|
+
return placeholder(id);
|
|
293
|
+
};
|
|
294
|
+
const deferred = (async function* () {
|
|
295
|
+
for await (const settled of deferQueue) {
|
|
296
|
+
if (settled.status === "rejected") {
|
|
297
|
+
console.error(settled.reason);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
const { id, content } = settled.value;
|
|
301
|
+
yield jsx("template", { children: content });
|
|
302
|
+
yield jsx("bruh-deferred", { "data-replace": id });
|
|
303
|
+
}
|
|
304
|
+
})();
|
|
305
|
+
const replaceDeferredScript = jsx("script", { children: replaceDeferredScriptContent });
|
|
306
|
+
yield* documentFunction({ defer, deferred, replaceDeferredScript });
|
|
307
|
+
}
|
|
308
|
+
toStream({ deferred = true } = {}) {
|
|
309
|
+
const encoder = new TextEncoder();
|
|
310
|
+
const asyncIterator = this[Symbol.asyncIterator]({ deferred });
|
|
311
|
+
return new ReadableStream({
|
|
312
|
+
async pull(controller) {
|
|
313
|
+
const { value, done } = await asyncIterator.next();
|
|
314
|
+
if (done) {
|
|
315
|
+
controller.close();
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
controller.enqueue(
|
|
319
|
+
encoder.encode(value)
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
toResponse({ deferred = true } = {}) {
|
|
325
|
+
return new Response(this.toStream({ deferred }), {
|
|
326
|
+
headers: {
|
|
327
|
+
"Content-Type": "text/html; charset=utf-8"
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
toString() {
|
|
332
|
+
let result = "";
|
|
333
|
+
for (const chunk of this)
|
|
334
|
+
result += chunk;
|
|
335
|
+
return result;
|
|
336
|
+
}
|
|
337
|
+
async toStringPromise({ deferred = false } = {}) {
|
|
338
|
+
let result = "";
|
|
339
|
+
for await (const chunk of this[Symbol.asyncIterator]({ deferred }))
|
|
340
|
+
result += chunk;
|
|
341
|
+
return result;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export { Fragment, MetaDocument, MetaElement, MetaRawString, MetaTextNode, applyAttributes, applyClasses, applyStyles, jsx, rawString, replaceDeferredHash, replaceDeferredScriptContent, t };
|
|
346
|
+
//# sourceMappingURL=server.mjs.map
|