apps 0.0.1-beta.79 → 0.0.1-beta.80
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/js/ui/serving.js
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
} from "../chunk-KLYSEHUD.js";
|
|
4
4
|
import "../chunk-JPEUKEV4.js";
|
|
5
5
|
import {
|
|
6
|
+
UiFailed,
|
|
6
7
|
UiForbidden
|
|
7
8
|
} from "../chunk-CDXQDN7W.js";
|
|
8
9
|
import {
|
|
@@ -17,7 +18,9 @@ import {
|
|
|
17
18
|
HttpServerResponse_exports
|
|
18
19
|
} from "../chunk-EOPQ727L.js";
|
|
19
20
|
import {
|
|
20
|
-
Effect_exports
|
|
21
|
+
Effect_exports,
|
|
22
|
+
Option_exports,
|
|
23
|
+
Stream_exports
|
|
21
24
|
} from "../chunk-IFJU5SYQ.js";
|
|
22
25
|
import "../chunk-CZ7CSFO4.js";
|
|
23
26
|
|
|
@@ -8526,12 +8529,14 @@ var appDocument = (options) => Effect_exports.gen(function* () {
|
|
|
8526
8529
|
const pathname = yield* Effect_exports.try(() => new URL(request.url, options.origin).pathname).pipe(
|
|
8527
8530
|
Effect_exports.mapError(() => new UiForbidden())
|
|
8528
8531
|
);
|
|
8529
|
-
const
|
|
8530
|
-
|
|
8532
|
+
const path = Option_exports.getOrUndefined(assetPath(pathname.slice(1)));
|
|
8533
|
+
const file = pathname === "/" || path === void 0 || path === "index.html" ? void 0 : yield* options.asset(path);
|
|
8534
|
+
if (file !== void 0 && "body" in file)
|
|
8531
8535
|
return HttpServerResponse_exports.uint8Array(file.body, {
|
|
8532
8536
|
contentType: file.contentType,
|
|
8533
8537
|
headers: appPrivateHeaders
|
|
8534
8538
|
});
|
|
8539
|
+
if (file !== void 0) return yield* storedFile(file, "private, no-cache");
|
|
8535
8540
|
if (pathname.includes(".") && pathname !== "/index.html")
|
|
8536
8541
|
return HttpServerResponse_exports.empty({ status: 404 });
|
|
8537
8542
|
const notice = options.accounts;
|
|
@@ -8542,7 +8547,7 @@ var appDocument = (options) => Effect_exports.gen(function* () {
|
|
|
8542
8547
|
headers: appPrivateHeaders
|
|
8543
8548
|
});
|
|
8544
8549
|
const document = yield* options.asset("index.html");
|
|
8545
|
-
if (document === void 0)
|
|
8550
|
+
if (document === void 0 || !("body" in document))
|
|
8546
8551
|
return HttpServerResponse_exports.text("This app has no UI.", {
|
|
8547
8552
|
status: 404,
|
|
8548
8553
|
headers: appPrivateHeaders
|
|
@@ -8564,21 +8569,92 @@ var appDocument = (options) => Effect_exports.gen(function* () {
|
|
|
8564
8569
|
{ contentType: "text/html", headers: appPrivateHeaders }
|
|
8565
8570
|
);
|
|
8566
8571
|
});
|
|
8572
|
+
var storedAppFile = (stored, read) => {
|
|
8573
|
+
const unavailable = () => new UiFailed({ reason: "unavailable" });
|
|
8574
|
+
return {
|
|
8575
|
+
contentType: stored.contentType,
|
|
8576
|
+
size: stored.size,
|
|
8577
|
+
etag: stored.etag,
|
|
8578
|
+
read: (range) => read(range).pipe(
|
|
8579
|
+
Effect_exports.mapError(unavailable),
|
|
8580
|
+
Effect_exports.flatMap(
|
|
8581
|
+
Option_exports.match({
|
|
8582
|
+
onNone: () => Effect_exports.fail(unavailable()),
|
|
8583
|
+
onSome: (found) => Effect_exports.succeed(found.body.pipe(Stream_exports.mapError(unavailable)))
|
|
8584
|
+
})
|
|
8585
|
+
)
|
|
8586
|
+
)
|
|
8587
|
+
};
|
|
8588
|
+
};
|
|
8589
|
+
var assetPath = (path) => Option_exports.liftThrowable(() => path.split("/").map(decodeURIComponent).join("/"))();
|
|
8590
|
+
var etagMatches = (header, etag) => header?.split(",").some(
|
|
8591
|
+
(candidate) => candidate.trim() === "*" || candidate.trim().replace(/^W\//, "") === etag.replace(/^W\//, "")
|
|
8592
|
+
) === true;
|
|
8593
|
+
var requestedRange = (header, ifRange, etag, size) => {
|
|
8594
|
+
if (header === void 0 || ifRange !== void 0 && ifRange.trim() !== etag) return void 0;
|
|
8595
|
+
const match = /^bytes=(\d*)-(\d*)$/u.exec(header.trim());
|
|
8596
|
+
if (match === null) return void 0;
|
|
8597
|
+
const [, first = "", last = ""] = match;
|
|
8598
|
+
if (first === "" && last === "") return void 0;
|
|
8599
|
+
if (first === "") {
|
|
8600
|
+
const suffix = Number(last);
|
|
8601
|
+
if (suffix === 0) return "unsatisfiable";
|
|
8602
|
+
return { start: Math.max(0, size - suffix), end: size - 1 };
|
|
8603
|
+
}
|
|
8604
|
+
const start = Number(first);
|
|
8605
|
+
const end = last === "" ? size - 1 : Math.min(Number(last), size - 1);
|
|
8606
|
+
if (start >= size) return "unsatisfiable";
|
|
8607
|
+
if (end < start) return void 0;
|
|
8608
|
+
return { start, end };
|
|
8609
|
+
};
|
|
8610
|
+
var storedFile = (file, cacheControl) => Effect_exports.gen(function* () {
|
|
8611
|
+
const request = yield* HttpServerRequest_exports.HttpServerRequest;
|
|
8612
|
+
const etag = `"${file.etag}"`;
|
|
8613
|
+
const headers = {
|
|
8614
|
+
...appPrivateHeaders,
|
|
8615
|
+
"cache-control": cacheControl,
|
|
8616
|
+
vary: "Cookie",
|
|
8617
|
+
etag,
|
|
8618
|
+
"accept-ranges": "bytes"
|
|
8619
|
+
};
|
|
8620
|
+
if (etagMatches(request.headers["if-none-match"], etag))
|
|
8621
|
+
return HttpServerResponse_exports.empty({ status: 304, headers });
|
|
8622
|
+
const range = requestedRange(
|
|
8623
|
+
request.headers.range,
|
|
8624
|
+
request.headers["if-range"],
|
|
8625
|
+
etag,
|
|
8626
|
+
file.size
|
|
8627
|
+
);
|
|
8628
|
+
if (range === "unsatisfiable")
|
|
8629
|
+
return HttpServerResponse_exports.empty({
|
|
8630
|
+
status: 416,
|
|
8631
|
+
headers: { ...headers, "content-range": `bytes */${file.size}` }
|
|
8632
|
+
});
|
|
8633
|
+
const length = range === void 0 ? file.size : range.end - range.start + 1;
|
|
8634
|
+
const body = yield* file.read(
|
|
8635
|
+
range === void 0 ? void 0 : { offset: range.start, length }
|
|
8636
|
+
);
|
|
8637
|
+
return HttpServerResponse_exports.stream(body, {
|
|
8638
|
+
status: range === void 0 ? 200 : 206,
|
|
8639
|
+
contentType: file.contentType,
|
|
8640
|
+
contentLength: length,
|
|
8641
|
+
headers: range === void 0 ? headers : { ...headers, "content-range": `bytes ${range.start}-${range.end}/${file.size}` }
|
|
8642
|
+
});
|
|
8643
|
+
});
|
|
8567
8644
|
var appAsset = (asset, build, path) => Effect_exports.gen(function* () {
|
|
8568
|
-
if (asset === void 0 ||
|
|
8645
|
+
if (asset === void 0 || path === "index.html")
|
|
8569
8646
|
return HttpServerResponse_exports.empty({ status: 404, headers: appPrivateHeaders });
|
|
8647
|
+
const immutable = "private, max-age=31536000, immutable";
|
|
8648
|
+
if (!("body" in asset)) return yield* storedFile(asset, immutable);
|
|
8570
8649
|
const request = yield* HttpServerRequest_exports.HttpServerRequest;
|
|
8571
8650
|
const etag = `W/"${encodeURIComponent(build)}/${encodeURIComponent(path)}"`;
|
|
8572
8651
|
const headers = {
|
|
8573
8652
|
...appPrivateHeaders,
|
|
8574
|
-
"cache-control":
|
|
8653
|
+
"cache-control": immutable,
|
|
8575
8654
|
vary: "Cookie",
|
|
8576
8655
|
etag
|
|
8577
8656
|
};
|
|
8578
|
-
|
|
8579
|
-
(candidate) => candidate.trim() === "*" || candidate.trim().replace(/^W\//, "") === etag.slice(2)
|
|
8580
|
-
);
|
|
8581
|
-
return matches ? HttpServerResponse_exports.empty({ status: 304, headers }) : HttpServerResponse_exports.uint8Array(asset.body, { contentType: asset.contentType, headers });
|
|
8657
|
+
return etagMatches(request.headers["if-none-match"], etag) ? HttpServerResponse_exports.empty({ status: 304, headers }) : HttpServerResponse_exports.uint8Array(asset.body, { contentType: asset.contentType, headers });
|
|
8582
8658
|
});
|
|
8583
8659
|
|
|
8584
8660
|
// src/implementation/ui-watch.ts
|
|
@@ -8586,5 +8662,7 @@ var appWatchScript = appWatchSource;
|
|
|
8586
8662
|
export {
|
|
8587
8663
|
appAsset,
|
|
8588
8664
|
appDocument,
|
|
8589
|
-
appWatchScript
|
|
8665
|
+
appWatchScript,
|
|
8666
|
+
assetPath,
|
|
8667
|
+
storedAppFile
|
|
8590
8668
|
};
|