partial-content 1.0.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/CHANGELOG.md +31 -0
- package/LICENSE +21 -0
- package/README.md +601 -0
- package/SECURITY.md +92 -0
- package/dist/azure.d.ts +79 -0
- package/dist/azure.d.ts.map +1 -0
- package/dist/azure.js +251 -0
- package/dist/azure.js.map +1 -0
- package/dist/content-disposition.d.ts +74 -0
- package/dist/content-disposition.d.ts.map +1 -0
- package/dist/content-disposition.js +253 -0
- package/dist/content-disposition.js.map +1 -0
- package/dist/fs.d.ts +86 -0
- package/dist/fs.d.ts.map +1 -0
- package/dist/fs.js +375 -0
- package/dist/fs.js.map +1 -0
- package/dist/gcs.d.ts +72 -0
- package/dist/gcs.d.ts.map +1 -0
- package/dist/gcs.js +202 -0
- package/dist/gcs.js.map +1 -0
- package/dist/hono.d.ts +92 -0
- package/dist/hono.d.ts.map +1 -0
- package/dist/hono.js +61 -0
- package/dist/hono.js.map +1 -0
- package/dist/http.d.ts +70 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +281 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel.d.ts +541 -0
- package/dist/kernel.d.ts.map +1 -0
- package/dist/kernel.js +1218 -0
- package/dist/kernel.js.map +1 -0
- package/dist/memory.d.ts +55 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +107 -0
- package/dist/memory.js.map +1 -0
- package/dist/mime.d.ts +49 -0
- package/dist/mime.d.ts.map +1 -0
- package/dist/mime.js +150 -0
- package/dist/mime.js.map +1 -0
- package/dist/node.d.ts +84 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +215 -0
- package/dist/node.js.map +1 -0
- package/dist/object-store.d.ts +472 -0
- package/dist/object-store.d.ts.map +1 -0
- package/dist/object-store.js +335 -0
- package/dist/object-store.js.map +1 -0
- package/dist/r2.d.ts +94 -0
- package/dist/r2.d.ts.map +1 -0
- package/dist/r2.js +150 -0
- package/dist/r2.js.map +1 -0
- package/dist/s3.d.ts +49 -0
- package/dist/s3.d.ts.map +1 -0
- package/dist/s3.js +263 -0
- package/dist/s3.js.map +1 -0
- package/dist/web.d.ts +336 -0
- package/dist/web.d.ts.map +1 -0
- package/dist/web.js +1094 -0
- package/dist/web.js.map +1 -0
- package/docs/DESIGN.md +426 -0
- package/package.json +182 -0
- package/src/azure.ts +329 -0
- package/src/content-disposition.ts +300 -0
- package/src/fs.ts +469 -0
- package/src/gcs.ts +290 -0
- package/src/hono.ts +123 -0
- package/src/http.ts +351 -0
- package/src/index.ts +85 -0
- package/src/kernel.ts +1498 -0
- package/src/memory.ts +148 -0
- package/src/mime.ts +160 -0
- package/src/node.ts +261 -0
- package/src/object-store.ts +665 -0
- package/src/r2.ts +232 -0
- package/src/s3.ts +324 -0
- package/src/web.ts +1603 -0
package/dist/node.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js HTTP adapter for partial-content.
|
|
3
|
+
*
|
|
4
|
+
* Bridges the gap between Node.js `IncomingMessage`/`ServerResponse` and the
|
|
5
|
+
* Fetch-based `partial-content/web` handler. Works with Express, Fastify
|
|
6
|
+
* (in compatibility mode), Koa, raw `http.createServer`, and any Node.js
|
|
7
|
+
* HTTP framework that exposes the standard request/response objects.
|
|
8
|
+
*
|
|
9
|
+
* @example Express
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import express from "express";
|
|
12
|
+
* import { serveObject } from "partial-content/node";
|
|
13
|
+
* import { fsStore } from "partial-content/fs";
|
|
14
|
+
*
|
|
15
|
+
* const store = fsStore({ root: "./uploads" });
|
|
16
|
+
* const app = express();
|
|
17
|
+
*
|
|
18
|
+
* app.get("/files/:key", serveObject(store, {
|
|
19
|
+
* key: (req) => req.params.key,
|
|
20
|
+
* disposition: "inline",
|
|
21
|
+
* }));
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example raw http.createServer
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { createServer } from "node:http";
|
|
27
|
+
* import { serveObject } from "partial-content/node";
|
|
28
|
+
* import { s3Store } from "partial-content/s3";
|
|
29
|
+
*
|
|
30
|
+
* const store = s3Store({ client, bucket: "docs" });
|
|
31
|
+
* const handler = serveObject(store, {
|
|
32
|
+
* key: (req) => new URL(req.url!, `http://${req.headers.host}`).pathname.slice(1),
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* createServer((req, res) => handler(req, res)).listen(3000);
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @packageDocumentation
|
|
39
|
+
*/
|
|
40
|
+
import { serveObjectRaw } from "./web.js";
|
|
41
|
+
/** Default backpressure stall bound: 60s of zero drain is a stalled reader. */
|
|
42
|
+
const DEFAULT_WRITE_STALL_MS = 60_000;
|
|
43
|
+
// ─── Factory ────────────────────────────────────────────────────────────────
|
|
44
|
+
/**
|
|
45
|
+
* Create a Node.js request handler that serves files from an {@link ObjectStore}.
|
|
46
|
+
*
|
|
47
|
+
* Converts Node.js `IncomingMessage` to a Fetch `Request`, delegates to the
|
|
48
|
+
* web adapter's `serveObject`, then writes the Fetch `Response` back to the
|
|
49
|
+
* Node.js `ServerResponse`.
|
|
50
|
+
*/
|
|
51
|
+
export function serveObject(store, opts) {
|
|
52
|
+
const { key: keyFn, mime: mimeFn, filename: filenameFn, writeStallTimeoutMs, ...serveOpts } = opts;
|
|
53
|
+
const handler = serveObjectRaw(store, serveOpts);
|
|
54
|
+
const stallMs = writeStallTimeoutMs ?? DEFAULT_WRITE_STALL_MS;
|
|
55
|
+
return async function handleNodeServe(req, res) {
|
|
56
|
+
// Wire up client-disconnect detection: when the Node.js request closes
|
|
57
|
+
// (client navigates away, connection drops), signal the web adapter to
|
|
58
|
+
// cancel the storage stream and stop transferring bytes.
|
|
59
|
+
//
|
|
60
|
+
// The listener MUST be detached once the response is fully written:
|
|
61
|
+
// IncomingMessage emits "close" after every NORMAL completion too, and
|
|
62
|
+
// an abort() there constructs a DOMException and notifies the store's
|
|
63
|
+
// abort listener on every request -- measured at ~8% of serve CPU.
|
|
64
|
+
const ac = new AbortController();
|
|
65
|
+
const onClientGone = () => ac.abort();
|
|
66
|
+
req.once("close", onClientGone);
|
|
67
|
+
// Lightweight ServableRequest view: the orchestrator only reads method,
|
|
68
|
+
// headers.get, and signal, so constructing real fetch primitives
|
|
69
|
+
// (undici Request + Headers) per request would be pure overhead. Node
|
|
70
|
+
// already lower-cases incoming header names, so reads go straight to
|
|
71
|
+
// req.headers with no per-request copy; join() matches how Node folds
|
|
72
|
+
// repeated headers (request headers are never Set-Cookie).
|
|
73
|
+
const nodeHeaders = req.headers;
|
|
74
|
+
const fetchRequest = {
|
|
75
|
+
method: req.method ?? "GET",
|
|
76
|
+
headers: {
|
|
77
|
+
get(name) {
|
|
78
|
+
const value = nodeHeaders[name.toLowerCase()];
|
|
79
|
+
if (value === undefined)
|
|
80
|
+
return null;
|
|
81
|
+
return Array.isArray(value) ? value.join(", ") : value;
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
signal: ac.signal,
|
|
85
|
+
};
|
|
86
|
+
// Resolve context and delegate to the web adapter. Guarded: a throwing
|
|
87
|
+
// key/mime/filename extractor (caller code) must become a 500 response,
|
|
88
|
+
// not a rejected handler -- in Express 4 an async handler rejection is
|
|
89
|
+
// an unhandled promise rejection, which kills the process.
|
|
90
|
+
let parts;
|
|
91
|
+
try {
|
|
92
|
+
const key = await keyFn(req);
|
|
93
|
+
const ctx = {
|
|
94
|
+
key,
|
|
95
|
+
mime: mimeFn?.(req),
|
|
96
|
+
filename: filenameFn?.(req),
|
|
97
|
+
};
|
|
98
|
+
parts = await handler(fetchRequest, ctx);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
if (!res.headersSent) {
|
|
102
|
+
const body = "Internal Server Error";
|
|
103
|
+
res.writeHead(500, {
|
|
104
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
105
|
+
"Content-Length": String(body.length),
|
|
106
|
+
"X-Content-Type-Options": "nosniff",
|
|
107
|
+
});
|
|
108
|
+
res.end(body);
|
|
109
|
+
}
|
|
110
|
+
else if (!res.destroyed) {
|
|
111
|
+
res.destroy();
|
|
112
|
+
}
|
|
113
|
+
req.off("close", onClientGone);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// Write the raw parts straight to the ServerResponse: no fetch
|
|
117
|
+
// primitives were constructed anywhere on this path. Preserves custom
|
|
118
|
+
// reason phrases (e.g. 499 Client Closed Request). The outer try/finally
|
|
119
|
+
// is load-bearing: writeHead and end can throw SYNCHRONOUSLY (socket
|
|
120
|
+
// destroyed in the await window, a header value the runtime rejects),
|
|
121
|
+
// and that throw must not leak the storage stream, leave the disconnect
|
|
122
|
+
// listener attached, or escape as an unhandled rejection (which kills
|
|
123
|
+
// Express 4 processes).
|
|
124
|
+
try {
|
|
125
|
+
res.writeHead(parts.status, parts.statusText || undefined, parts.headers);
|
|
126
|
+
if (!parts.body) {
|
|
127
|
+
res.end();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// Byte bodies (in-memory stores, fs small-transfer fast path, error
|
|
131
|
+
// pages): a single write, no reader machinery.
|
|
132
|
+
if (parts.body instanceof Uint8Array) {
|
|
133
|
+
res.end(parts.body);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
// Stream the response body with backpressure. Client disconnects abort
|
|
137
|
+
// the storage stream (via the signal above), which rejects reader.read();
|
|
138
|
+
// that rejection must be contained here, not escape the handler.
|
|
139
|
+
const reader = parts.body.getReader();
|
|
140
|
+
try {
|
|
141
|
+
while (true) {
|
|
142
|
+
const { done, value } = await reader.read();
|
|
143
|
+
if (done)
|
|
144
|
+
break;
|
|
145
|
+
if (res.destroyed) {
|
|
146
|
+
// Client is gone; stop pulling and release the storage stream.
|
|
147
|
+
await reader.cancel();
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
const canContinue = res.write(value);
|
|
151
|
+
if (!canContinue) {
|
|
152
|
+
// Backpressure: wait for drain, or for the response to close
|
|
153
|
+
// (client disconnect) so a stalled socket cannot hang this loop.
|
|
154
|
+
// A stall timeout bounds a reader that stops consuming but holds
|
|
155
|
+
// the socket open: it rejects into the catch below, which cancels
|
|
156
|
+
// the storage reader and destroys the response.
|
|
157
|
+
await new Promise((resolve, reject) => {
|
|
158
|
+
let timer;
|
|
159
|
+
const cleanup = () => {
|
|
160
|
+
if (timer !== undefined)
|
|
161
|
+
clearTimeout(timer);
|
|
162
|
+
res.off("drain", onDone);
|
|
163
|
+
res.off("close", onDone);
|
|
164
|
+
};
|
|
165
|
+
const onDone = () => {
|
|
166
|
+
cleanup();
|
|
167
|
+
resolve();
|
|
168
|
+
};
|
|
169
|
+
if (stallMs > 0) {
|
|
170
|
+
timer = setTimeout(() => {
|
|
171
|
+
cleanup();
|
|
172
|
+
reject(new Error("partial-content: response write stalled"));
|
|
173
|
+
}, stallMs);
|
|
174
|
+
// Do not keep the event loop alive solely for this timer.
|
|
175
|
+
timer.unref?.();
|
|
176
|
+
}
|
|
177
|
+
res.once("drain", onDone);
|
|
178
|
+
res.once("close", onDone);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
res.end();
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
// Transfer failed mid-stream (disconnect or storage error). Headers are
|
|
186
|
+
// already sent, so no error response is possible; tear the socket down
|
|
187
|
+
// so the client sees a truncated transfer instead of a hang.
|
|
188
|
+
await reader.cancel().catch(() => {
|
|
189
|
+
// Stream may already be errored; cancel is best-effort
|
|
190
|
+
});
|
|
191
|
+
if (!res.destroyed)
|
|
192
|
+
res.destroy();
|
|
193
|
+
}
|
|
194
|
+
finally {
|
|
195
|
+
reader.releaseLock();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
// writeHead/end threw synchronously. The pump above never rethrows, so
|
|
200
|
+
// this only catches pre-stream failures: release an unconsumed stream
|
|
201
|
+
// body (fs handle / backend socket) and tear the connection down.
|
|
202
|
+
if (parts.body instanceof ReadableStream) {
|
|
203
|
+
await parts.body.cancel().catch(() => {
|
|
204
|
+
// Already locked or errored; best-effort release
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
if (!res.destroyed)
|
|
208
|
+
res.destroy();
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
req.off("close", onClientGone);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=node.js.map
|
package/dist/node.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,OAAO,EAAE,cAAc,EAAqE,MAAM,UAAU,CAAC;AA0C7G,+EAA+E;AAC/E,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAEtC,+EAA+E;AAE/E;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,KAAkB,EAClB,IAAsB;IAEtB,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,mBAAmB,EAAE,GAAG,SAAS,EAAE,GAAG,IAAI,CAAC;IACnG,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,mBAAmB,IAAI,sBAAsB,CAAC;IAE9D,OAAO,KAAK,UAAU,eAAe,CACnC,GAAoB,EACpB,GAAmB;QAEnB,uEAAuE;QACvE,uEAAuE;QACvE,yDAAyD;QACzD,EAAE;QACF,oEAAoE;QACpE,uEAAuE;QACvE,sEAAsE;QACtE,mEAAmE;QACnE,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC;QACjC,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;QACtC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QAEhC,wEAAwE;QACxE,iEAAiE;QACjE,sEAAsE;QACtE,qEAAqE;QACrE,sEAAsE;QACtE,2DAA2D;QAC3D,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC;QAChC,MAAM,YAAY,GAAG;YACnB,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,KAAK;YAC3B,OAAO,EAAE;gBACP,GAAG,CAAC,IAAY;oBACd,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;oBAC9C,IAAI,KAAK,KAAK,SAAS;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;gBACzD,CAAC;aACF;YACD,MAAM,EAAE,EAAE,CAAC,MAAM;SAClB,CAAC;QAEF,uEAAuE;QACvE,wEAAwE;QACxE,uEAAuE;QACvE,2DAA2D;QAC3D,IAAI,KAAuB,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7B,MAAM,GAAG,GAAiB;gBACxB,GAAG;gBACH,IAAI,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC;gBACnB,QAAQ,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC;aAC5B,CAAC;YACF,KAAK,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;gBACrB,MAAM,IAAI,GAAG,uBAAuB,CAAC;gBACrC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;oBACjB,cAAc,EAAE,2BAA2B;oBAC3C,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;oBACrC,wBAAwB,EAAE,SAAS;iBACpC,CAAC,CAAC;gBACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC;iBAAM,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;gBAC1B,GAAG,CAAC,OAAO,EAAE,CAAC;YAChB,CAAC;YACD,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YAC/B,OAAO;QACT,CAAC;QAED,+DAA+D;QAC/D,sEAAsE;QACtE,yEAAyE;QACzE,qEAAqE;QACrE,sEAAsE;QACtE,wEAAwE;QACxE,sEAAsE;QACtE,wBAAwB;QACxB,IAAI,CAAC;YACH,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,IAAI,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAE1E,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;gBAChB,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,oEAAoE;YACpE,+CAA+C;YAC/C,IAAI,KAAK,CAAC,IAAI,YAAY,UAAU,EAAE,CAAC;gBACrC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACpB,OAAO;YACT,CAAC;YAED,uEAAuE;YACvE,0EAA0E;YAC1E,iEAAiE;YACjE,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,IAAI,CAAC;gBACH,OAAO,IAAI,EAAE,CAAC;oBACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;oBAC5C,IAAI,IAAI;wBAAE,MAAM;oBAChB,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;wBAClB,+DAA+D;wBAC/D,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;wBACtB,MAAM;oBACR,CAAC;oBACD,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;oBACrC,IAAI,CAAC,WAAW,EAAE,CAAC;wBACjB,6DAA6D;wBAC7D,iEAAiE;wBACjE,iEAAiE;wBACjE,kEAAkE;wBAClE,gDAAgD;wBAChD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;4BAC1C,IAAI,KAAgD,CAAC;4BACrD,MAAM,OAAO,GAAG,GAAG,EAAE;gCACnB,IAAI,KAAK,KAAK,SAAS;oCAAE,YAAY,CAAC,KAAK,CAAC,CAAC;gCAC7C,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gCACzB,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;4BAC3B,CAAC,CAAC;4BACF,MAAM,MAAM,GAAG,GAAG,EAAE;gCAClB,OAAO,EAAE,CAAC;gCACV,OAAO,EAAE,CAAC;4BACZ,CAAC,CAAC;4BACF,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;gCAChB,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;oCACtB,OAAO,EAAE,CAAC;oCACV,MAAM,CAAC,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC,CAAC;gCAC/D,CAAC,EAAE,OAAO,CAAC,CAAC;gCACZ,0DAA0D;gCAC1D,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;4BAClB,CAAC;4BACD,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;4BAC1B,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;wBAC5B,CAAC,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;gBACD,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC;YAAC,MAAM,CAAC;gBACP,wEAAwE;gBACxE,uEAAuE;gBACvE,6DAA6D;gBAC7D,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;oBAC/B,uDAAuD;gBACzD,CAAC,CAAC,CAAC;gBACH,IAAI,CAAC,GAAG,CAAC,SAAS;oBAAE,GAAG,CAAC,OAAO,EAAE,CAAC;YACpC,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,WAAW,EAAE,CAAC;YACvB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;YACvE,sEAAsE;YACtE,kEAAkE;YAClE,IAAI,KAAK,CAAC,IAAI,YAAY,cAAc,EAAE,CAAC;gBACzC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;oBACnC,iDAAiD;gBACnD,CAAC,CAAC,CAAC;YACL,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,SAAS;gBAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QACpC,CAAC;gBAAS,CAAC;YACT,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|