@azure-utils/storybooks
Version:
Utils to upload and manage Storybooks via Azure Functions and storage.
1,113 lines (1,072 loc) • 36 kB
JavaScript
const require_chunk = require('./chunk-DWy1uDak.cjs');
const require_constants = require('./constants-94H7Co6A.cjs');
const require_error_utils = require('./error-utils-DFTvM-wv.cjs');
const require_url_utils = require('./url-utils-Dy7KiQmB.cjs');
const node_async_hooks = require_chunk.__toESM(require("node:async_hooks"));
//#region ../../node_modules/@kitajs/html/index.js
var require_html = require_chunk.__commonJS({ "../../node_modules/@kitajs/html/index.js"(exports) {
const ESCAPED_REGEX = /[<"'&]/;
const CAMEL_REGEX = /[a-z][A-Z]/;
/** @type {import('.').isUpper} */
function isUpper(input, index) {
const code = input.charCodeAt(index);
return code >= 65 && code <= 90;
}
/** @type {import('.').toKebabCase} */
function toKebabCase(camel) {
if (!CAMEL_REGEX.test(camel)) return camel;
const length = camel.length;
let start = 0, end = 0, kebab = "", prev = true, curr = isUpper(camel, 0), next;
for (; end < length; end++) {
next = isUpper(camel, end + 1);
if (!prev && curr && !next) {
kebab += camel.slice(start, end) + "-" + camel[end].toLowerCase();
start = end + 1;
}
prev = curr;
curr = next;
}
kebab += camel.slice(start, end);
return kebab;
}
/** @type {import('.').escape} */
function escape(strings, ...values) {
const stringsLength = strings.length, valuesLength = values.length;
let index = 0, result = "";
for (; index < stringsLength; index++) {
result += strings[index];
if (index < valuesLength) result += values[index];
}
return escapeHtml(result);
}
/** @type {import('.').escapeHtml} */
let escapeHtml = function(value) {
if (typeof value !== "string") value = value.toString();
if (!ESCAPED_REGEX.test(value)) return value;
const length = value.length;
let escaped = "", start = 0, end = 0;
for (; end < length; end++) switch (value[end]) {
case "&":
escaped += value.slice(start, end) + "&";
start = end + 1;
continue;
case "<":
escaped += value.slice(start, end) + "<";
start = end + 1;
continue;
case "\"":
escaped += value.slice(start, end) + """;
start = end + 1;
continue;
case "'":
escaped += value.slice(start, end) + "'";
start = end + 1;
continue;
}
escaped += value.slice(start, end);
return escaped;
};
/* c8 ignore next 2 */
if (typeof Bun !== "undefined") escapeHtml = Bun.escapeHTML;
/** @type {import('.').isVoidElement} */
function isVoidElement$1(tag) {
return tag === "meta" || tag === "link" || tag === "img" || tag === "br" || tag === "input" || tag === "hr" || tag === "area" || tag === "base" || tag === "col" || tag === "command" || tag === "embed" || tag === "keygen" || tag === "param" || tag === "source" || tag === "track" || tag === "wbr";
}
/** @type {import('.').styleToString} */
function styleToString(style) {
if (typeof style === "string") {
let end$1 = style.indexOf("\"");
if (end$1 === -1) return style;
const length$1 = style.length;
let escaped = "", start$1 = 0;
for (; end$1 < length$1; end$1++) if (style[end$1] === "\"") {
escaped += style.slice(start$1, end$1) + """;
start$1 = end$1 + 1;
}
escaped += style.slice(start$1, end$1);
return escaped;
}
const keys = Object.keys(style), length = keys.length;
let key, value, end, start, index = 0, result = "";
for (; index < length; index++) {
key = keys[index];
value = style[key];
if (value === null || value === void 0) continue;
result += toKebabCase(key) + ":";
if (typeof value !== "string") {
result += value.toString() + ";";
continue;
}
end = value.indexOf("\"");
if (end === -1) {
result += value + ";";
continue;
}
const length$1 = value.length;
start = 0;
for (; end < length$1; end++) if (value[end] === "\"") {
result += value.slice(start, end) + """;
start = end + 1;
}
result += value.slice(start, end) + ";";
}
return result;
}
/** @type {import('.').attributesToString} */
function attributesToString$1(attributes) {
const keys = Object.keys(attributes);
const length = keys.length;
let key, value, type, end, start, classItems, valueLength, result = "", index = 0;
for (; index < length; index++) {
key = keys[index];
if (key === "children" || key === "safe" || key === "of") continue;
value = attributes[key];
if (value === null || value === void 0) continue;
if (key === "className") {
if (attributes.class !== void 0) continue;
key = "class";
} else if (key === "class" && Array.isArray(value)) {
classItems = value;
valueLength = value.length;
value = "";
for (let i = 0; i < valueLength; i++) if (classItems[i] && classItems[i].length > 0) if (value) value += " " + classItems[i].trim();
else value += classItems[i].trim();
if (value.length === 0) continue;
} else if (key === "style") {
result += " style=\"" + styleToString(value) + "\"";
continue;
} else if (key === "attrs") {
if (typeof value === "string") result += " " + value;
else result += attributesToString$1(value);
continue;
}
type = typeof value;
if (type === "boolean") {
if (value) result += " " + key;
continue;
}
result += " " + key;
if (type !== "string") {
if (type !== "object") {
result += "=\"" + value.toString() + "\"";
continue;
}
if (value instanceof Date) {
result += "=\"" + value.toISOString() + "\"";
continue;
}
value = value.toString();
}
end = value.indexOf("\"");
if (end === -1) {
result += "=\"" + value + "\"";
continue;
}
result += "=\"";
valueLength = value.length;
start = 0;
for (; end < valueLength; end++) if (value[end] === "\"") {
result += value.slice(start, end) + """;
start = end + 1;
}
result += value.slice(start, end) + "\"";
}
return result;
}
/**
* @type {import('.').contentsToString}
* @returns {any}
*/
function contentsToString$2(contents, escape$1) {
let length = contents.length;
let result = "";
for (let index = 0; index < length; index++) {
const content = contents[index];
switch (typeof content) {
case "string":
case "number":
case "bigint":
result += content;
continue;
case "boolean": continue;
}
if (!content) continue;
if (Array.isArray(content)) {
contents.splice(index--, 1, ...content);
length += content.length - 1;
continue;
}
if (typeof content.then === "function") return Promise.all(contents.slice(index)).then(function resolveContents(resolved) {
resolved.unshift(result);
return contentsToString$2(resolved, escape$1);
});
throw new Error("Objects are not valid as a KitaJSX child");
}
if (escape$1 === true) return escapeHtml(result);
return result;
}
/**
* @param {import('./index').Children} content
* @param {boolean} safe
* @returns {JSX.Element}
*/
function contentToString$2(content, safe) {
switch (typeof content) {
case "string": return safe ? escapeHtml(content) : content;
case "number":
case "bigint": return content.toString();
case "boolean": return "";
}
if (!content) return "";
if (Array.isArray(content)) return contentsToString$2(content, safe);
if (typeof content.then === "function") return content.then(function resolveContent(resolved) {
return contentToString$2(resolved, safe);
});
throw new Error("Objects are not valid as a KitaJSX child");
}
/**
* Just to stop TS from complaining about the type.
*
* @type {import('.').createElement}
* @param {any} name
* @returns {any}
*/
function createElement(name, attrs, ...children) {
const hasAttrs = attrs !== null;
if (typeof name === "function") {
if (!hasAttrs) return name({ children: children.length > 1 ? children : children[0] });
attrs.children = children.length > 1 ? children : children[0];
return name(attrs);
}
if (hasAttrs && name === "tag") name = attrs.of;
const attributes = hasAttrs ? attributesToString$1(attrs) : "";
if (children.length === 0) return isVoidElement$1(name) ? "<" + name + attributes + "/>" : "<" + name + attributes + "></" + name + ">";
const contents = contentsToString$2(children, hasAttrs && attrs.safe);
if (typeof contents === "string") return "<" + name + attributes + ">" + contents + "</" + name + ">";
return contents.then(function resolveContents(contents$1) {
return "<" + name + attributes + ">" + contents$1 + "</" + name + ">";
});
}
/** @type {import('.').Fragment} */
function Fragment$1(props) {
return contentsToString$2([props.children]);
}
exports.escape = escape;
exports.e = escape;
exports.escapeHtml = escapeHtml;
exports.isVoidElement = isVoidElement$1;
exports.attributesToString = attributesToString$1;
exports.toKebabCase = toKebabCase;
exports.isUpper = isUpper;
exports.styleToString = styleToString;
exports.createElement = createElement;
exports.h = createElement;
exports.contentsToString = contentsToString$2;
exports.contentToString = contentToString$2;
exports.Fragment = Fragment$1;
exports.Html = { ...exports };
} });
//#endregion
//#region ../../node_modules/@kitajs/html/suspense.js
var require_suspense = require_chunk.__commonJS({ "../../node_modules/@kitajs/html/suspense.js"(exports) {
const { contentsToString: contentsToString$1, contentToString: contentToString$1 } = require_html();
const { Readable, PassThrough } = require("node:stream");
if (!globalThis.SUSPENSE_ROOT) globalThis.SUSPENSE_ROOT = {
requests: /* @__PURE__ */ new Map(),
requestCounter: 1,
autoScript: true
};
function noop() {}
/**
* Simple IE11 compatible replace child scripts to replace the template streamed by the
* server.
*
* As this script is the only residue of this package that is actually sent to the client,
* it's important to keep it as small as possible and also include the license to avoid
* legal issues.
*/
const SuspenseScript = `
<script id="kita-html-suspense">
/*! MIT License https://kita.js.org */
function $KITA_RC(i){
// simple aliases
var d=document,q=d.querySelector.bind(d),
// div sent as the fallback wrapper
v=q('div[id="B:'+i+'"][data-sf]'),
// template and script sent after promise finishes
t=q('template[id="N:'+i+'"][data-sr]'),s=q('script[id="S:'+i+'"][data-ss]'),
// fragment created to avoid inserting element one by one
f=d.createDocumentFragment(),
// used by iterators
c,j,
// all pending hydrations
r;
// if div or template is not found, let this hydration as pending
if(t&&v&&s){
// appends into the fragment
while(c=t.content.firstChild)
f.appendChild(c);
// replaces the div and removes the script and template
v.parentNode.replaceChild(f,v);
t.remove();
s.remove();
// looks for pending templates
r=d.querySelectorAll('template[id][data-sr]');
do{
// resets j & c from previous loop
c=j=0;
// loops over every found pending template and
for(;c<r.length;c++)
if(r[c]!=t)
// let j as true while at least on $KITA_RC call returns true
j=$KITA_RC(r[c].id.slice(2))?!0:j;
}while(j)
// we know at least the original template was substituted
return!0;
}
}
<\/script>
`.replace(/^\s*\/\/.*/gm, "").replace(/\n\s*/g, "");
/** @type {import('./suspense').Suspense} */
function Suspense(props) {
const children = Array.isArray(props.children) ? contentsToString$1(props.children) : contentToString$1(props.children);
if (typeof children === "string") return children;
if (!props.rid) throw new Error("Suspense requires a `rid` to be specified.");
let data = SUSPENSE_ROOT.requests.get(props.rid);
if (!data) {
data = {
stream: new Readable({ read: noop }),
running: 0,
sent: false
};
SUSPENSE_ROOT.requests.set(props.rid, data);
}
const run = ++data.running;
children.then(writeStreamTemplate).catch(function errorRecover(error) {
if (!props.catch) throw error;
let html;
if (typeof props.catch === "function") html = props.catch(error);
else html = props.catch;
if (typeof html === "string") return writeStreamTemplate(html);
return html.then(writeStreamTemplate);
}).catch(function writeFatalError(error) {
data.stream.emit("error", error);
}).finally(function clearRequestData() {
if (data && data.running > 1) {
data.running -= 1;
return;
}
if (data && !data.stream.closed) data.stream.push(null);
SUSPENSE_ROOT.requests.delete(props.rid);
});
const fallback = contentToString$1(props.fallback);
if (typeof fallback === "string") return "<div id=\"B:" + run + "\" data-sf>" + fallback + "</div>";
return fallback.then(function resolveCallback(resolved) {
return "<div id=\"B:" + run + "\" data-sf>" + resolved + "</div>";
});
/**
* This function may be called by the catch handler in case the error could be handled.
*
* @param {string} result
*/
function writeStreamTemplate(result) {
if (!SUSPENSE_ROOT.requests.has(props.rid) || !data || data.stream.closed) return;
if (SUSPENSE_ROOT.autoScript && data.sent === false) {
data.stream.push(SuspenseScript);
data.sent = true;
}
data.stream.push(`<template id="N:${run}" data-sr>${result}</template><script id="S:${run}" data-ss>$KITA_RC(${run})<\/script>`);
}
}
/** @type {import('./suspense').renderToStream} */
function renderToStream$1(html, rid) {
if (!rid) rid = SUSPENSE_ROOT.requestCounter++;
else if (SUSPENSE_ROOT.requests.has(rid)) {
const error = /* @__PURE__ */ new Error(`The provided Request Id is already in use: ${rid}.`);
return new Readable({ read() {
this.emit("error", error);
this.push(null);
} });
}
if (typeof html === "function") try {
html = html(rid);
} catch (error) {
SUSPENSE_ROOT.requests.delete(rid);
return new Readable({ read() {
this.emit("error", error);
this.push(null);
} });
}
const requestData = SUSPENSE_ROOT.requests.get(rid);
if (!requestData) {
if (typeof html === "string") return Readable.from([html]);
return new Readable({ read() {
html.then((result) => {
this.push(result);
this.push(null);
}).catch((error) => {
this.emit("error", error);
});
} });
}
return resolveHtmlStream(html, requestData);
}
/** @type {import('./suspense').resolveHtmlStream} */
function resolveHtmlStream(template, requestData) {
if (typeof template === "string") {
requestData.stream.push(template);
return requestData.stream;
}
const prepended = new PassThrough();
template.then((result) => {
prepended.push(result);
requestData.stream.pipe(prepended);
}, (error) => {
prepended.emit("error", error);
});
return prepended;
}
exports.Suspense = Suspense;
exports.renderToStream = renderToStream$1;
exports.resolveHtmlStream = resolveHtmlStream;
exports.SuspenseScript = SuspenseScript;
} });
//#endregion
//#region src/utils/url-builder.ts
/**
* URL builder for the Storybooks router.
* @private
*/
const urlBuilder = {
root: (...pathnames) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, ...pathnames), base);
return url.toString();
},
staticFile: (filepath) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, filepath), base);
return url.toString();
},
allProjects: () => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "projects"), base);
return url.toString();
},
projectCreate: () => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "projects"), base);
url.searchParams.set(require_constants.QUERY_PARAMS.mode, require_constants.QUERY_PARAMS.newResource);
return url.toString();
},
projectId: (projectId) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "projects", projectId), base);
return url.toString();
},
projectIdEdit: (projectId) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "projects", projectId), base);
url.searchParams.set(require_constants.QUERY_PARAMS.mode, require_constants.QUERY_PARAMS.editResource);
return url.toString();
},
allBuilds: (projectId) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "projects", projectId, "builds"), base);
return url.toString();
},
buildSHA: (projectId, sha, labelSlug) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "projects", projectId, "builds", sha), base);
if (labelSlug) url.searchParams.set(require_constants.QUERY_PARAMS.labelSlug, labelSlug);
return url.toString();
},
buildUpload: (projectId) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "projects", projectId, "builds"), base);
url.searchParams.set(require_constants.QUERY_PARAMS.mode, require_constants.QUERY_PARAMS.newResource);
return url.toString();
},
allLabels: (projectId) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "projects", projectId, "labels"), base);
return url.toString();
},
labelCreate: (projectId) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "projects", projectId, "labels"), base);
url.searchParams.set(require_constants.QUERY_PARAMS.mode, require_constants.QUERY_PARAMS.newResource);
return url.toString();
},
labelSlug: (projectId, labelSlug) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "projects", projectId, "labels", labelSlug), base);
return url.toString();
},
labelSlugEdit: (projectId, labelSlug) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "projects", projectId, "labels", labelSlug), base);
url.searchParams.set(require_constants.QUERY_PARAMS.mode, require_constants.QUERY_PARAMS.editResource);
return url.toString();
},
labelSlugLatest: (projectId, labelSlug) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "projects", projectId, "labels", labelSlug, "latest"), base);
return url.toString();
},
storybookIndexHtml: (projectId, sha) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "_", projectId, sha, "index.html"), base);
return url.toString();
},
storybookTestReport: (projectId, sha) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "_", projectId, sha, "report", "index.html"), base);
return url.toString();
},
storybookCoverage: (projectId, sha) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "_", projectId, sha, "coverage", "index.html"), base);
return url.toString();
},
storybookZip: (projectId, sha) => {
const { baseRoute, url: base } = getStore();
const url = new URL(require_url_utils.joinUrl(baseRoute, "_", projectId, sha, "storybook.zip"), base);
return url.toString();
},
gitHub: (gitHubRepo, ...pathnames) => {
const url = new URL(require_url_utils.joinUrl(gitHubRepo, ...pathnames), "https://github.com");
return url.toString();
}
};
//#endregion
//#region ../../node_modules/@kitajs/html/jsx-runtime.js
var require_jsx_runtime = require_chunk.__commonJS({ "../../node_modules/@kitajs/html/jsx-runtime.js"(exports) {
const { Fragment, attributesToString, isVoidElement, contentsToString, contentToString } = require_html();
/** @type {import('./jsx-runtime').jsx} */
function jsx(name, attrs) {
if (typeof name === "function") return name(attrs);
if (name === "tag") name = attrs.of;
const attributes = attributesToString(attrs);
if (attrs.children === void 0) return isVoidElement(name) ? "<" + name + attributes + "/>" : "<" + name + attributes + "></" + name + ">";
const contents = contentToString(attrs.children, attrs.safe);
if (contents instanceof Promise) return contents.then(function resolveContents(child) {
return "<" + name + attributes + ">" + child + "</" + name + ">";
});
return "<" + name + attributes + ">" + contents + "</" + name + ">";
}
/** @type {import('./jsx-runtime').jsxs} */
function jsxs(name, attrs) {
if (typeof name === "function") return name(attrs);
if (name === "tag") name = attrs.of;
const attributes = attributesToString(attrs);
if (attrs.children.length === 0) return isVoidElement(name) ? "<" + name + attributes + "/>" : "<" + name + attributes + "></" + name + ">";
const contents = contentsToString(attrs.children, attrs.safe);
if (contents instanceof Promise) return contents.then(function resolveContents(child) {
return "<" + name + attributes + ">" + child + "</" + name + ">";
});
return "<" + name + attributes + ">" + contents + "</" + name + ">";
}
exports.jsx = jsx;
exports.jsxs = jsxs;
exports.Fragment = Fragment;
} });
//#endregion
//#region src/components/layout.tsx
var import_jsx_runtime$2 = require_chunk.__toESM(require_jsx_runtime());
function DocumentLayout({ title, breadcrumbs = [], children, footer, toolbar }) {
const safeStylesheet = globalStyleSheet();
const store$1 = getStore();
return /* @__PURE__ */ (0, import_jsx_runtime$2.jsxs)(import_jsx_runtime$2.Fragment, { children: ["<!DOCTYPE html>", /* @__PURE__ */ (0, import_jsx_runtime$2.jsxs)("html", {
lang: "en",
children: [/* @__PURE__ */ (0, import_jsx_runtime$2.jsxs)("head", { children: [
/* @__PURE__ */ (0, import_jsx_runtime$2.jsxs)("title", {
safe: true,
children: [
title,
" |",
" ",
store$1.serviceName === require_constants.DEFAULT_SERVICE_NAME ? "StoryBooks" : store$1.serviceName
]
}),
/* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("style", { children: safeStylesheet }),
/* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("script", {
src: "https://cdn.jsdelivr.net/npm/htmx.org@2.0.6/dist/htmx.min.js",
crossorigin: "anonymous"
}),
/* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("script", {
src: "https://cdn.jsdelivr.net/npm/htmx-ext-response-targets@2.0.2",
crossorigin: "anonymous"
})
] }), /* @__PURE__ */ (0, import_jsx_runtime$2.jsxs)("body", { children: [
/* @__PURE__ */ (0, import_jsx_runtime$2.jsxs)("header", { children: [
/* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("div", {
style: {
borderRight: "1px solid var(--color-border)",
paddingRight: "1rem"
},
children: /* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("a", {
href: urlBuilder.root(),
title: "Home",
children: store$1.serviceName === require_constants.DEFAULT_SERVICE_NAME ? /* @__PURE__ */ (0, import_jsx_runtime$2.jsxs)("strong", {
style: {
fontFamily: "monospace",
display: "block",
textAlign: "center",
color: "var(--color-text-primary)"
},
children: [
"STORY",
/* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("br", {}),
"BOOKS"
]
}) : /* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("strong", {
safe: true,
children: store$1.serviceName
})
})
}),
/* @__PURE__ */ (0, import_jsx_runtime$2.jsxs)("div", {
class: "page-heading",
style: { flex: 1 },
children: [breadcrumbs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("ul", { children: breadcrumbs.map((crumb, i, arr) => {
const href = (typeof crumb === "object" ? crumb.href : "") || require_url_utils.joinUrl(store$1.url, ...Array.from({ length: arr.length - i }).map(() => ".."));
return /* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("a", {
safe: true,
href,
children: typeof crumb === "object" ? crumb.label : crumb
}) });
}) }) : null, /* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("div", {
safe: true,
children: title
})]
}),
toolbar ? /* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("div", { children: toolbar }) : null
] }),
/* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("main", { children }),
footer ? /* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("footer", { children: footer }) : null,
/* @__PURE__ */ (0, import_jsx_runtime$2.jsx)("script", {
defer: true,
src: "https://unpkg.com/htmx-toaster/dist/htmx-toaster.min.js"
})
] })]
})] });
}
function globalStyleSheet() {
return `
:root {
--color-bg-base: #f2f2f2;
--color-bg-card: #ffffff;
--color-text-primary: #09090b;
--color-text-secondary: #71717b;
--color-text-accent: #2b7fff;
--color-border: #e4e4e7;
}
@media (prefers-color-scheme: dark) {
:root {
--color-bg-base: #09090b;
--color-bg-card: #18181b;
--color-text-primary: #fafafa;
--color-text-secondary: #9f9fa9;
--color-text-accent: #2b7fff;
--color-border: #ffffff1a;
}
}
* {
box-sizing: border-box;
color-scheme: light dark;
font-family: system-ui;
border-color: var(--color-border);
}
body {
font-size: 1rem;
padding: 0px;
margin: 0px;
display: flex;
flex-direction: column;
gap: 1rem;
min-height: 100vh;
overflow-y: auto;
overflow-x: hidden;
background-color: var(--color-bg-base);
color: var(--color-text-secondary);
}
body > header,
body > footer,
body > main,
body > aside {
margin: 0 1rem;
background-color: var(--color-bg-card);
color: var(--color-text-primary);
border-radius: 0.5rem;
overflow: hidden;
padding: 1rem;
}
body > header {
margin-top: 1rem;
display: flex;
align-items: center;
gap: 1rem;
}
body > main {
flex: 1;
display: flex;
flex-direction: column;
gap: 1rem;
overflow: auto;
}
body > footer {
margin-bottom: 1rem;
}
hr {
color: var(--color-border);
background: var(--color-border);
border-color: var(--color-border);
}
table {
height: 100%;
width: 100%;
border-radius: 0.25rem;
overflow: hidden;
}
table caption {
font-weight: bold;
font-size: 1.25rem;
padding: 0.5rem 1rem;
text-align: start;
}
thead {
background-color: var(--color-bg-base);
color: var(--color-text-secondary);
}
th {
color: var(--color-text-secondary);
font-weight: medium;
font-size: 0.9rem;
text-align: start;
padding: 0.25rem 1rem;
}
td {
text-align: start;
height: max-content;
padding: 0.5rem 1rem;
color: var(--color-text-primary);
}
time {
font-family: monospace;
font-size: 0.9rem;
color: var(--color-text-secondary);
}
a,
a:visited {
color: var(--color-text-accent);
text-decoration: none;
}
a:hover {
color: var(--color-text-accent);
text-decoration: underline;
}
.raw-data {
margin: 0;
background-color: #00000010;
border: 1px solid var(--color-border);
border-radius: 0.25rem;
font-family: monospace;
font-size: 0.9rem;
white-space: pre-wrap;
padding: 0.5rem;
}
.raw-data:empty{
display: none;
}
.page-heading {
display: flex;
flex-direction: column;
gap: 0.25rem;
font-weight: bold;
}
.page-heading > ul {
display: flex;
align-items: center;
padding: 0;
margin: 0;
list-style: none;
}
.page-heading > ul > li {
font-weight: normal;
list-style: none;
font-size: 0.9em;
}
.page-heading > ul > li::after {
content: \"/\";
color: inherit;
margin: 0 0.5rem;
opacity: 0.5;
}
.description {
color: var(--color-text-secondary);
font-size: 0.9rem;
}
form {
display: flex;
flex-direction: column;
gap: 1rem;
}
form fieldset {
display: flex;
flex-direction:column;
gap: 1rem;
border-radius: 0.5rem;
}
form legend {
font-size:0.9rem;
}
form .field {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
form label {
font-size:0.9rem;
font-weight:600;
}
form input,
form select,
form textarea,
form button
{
border-radius: 0.25rem;
padding: 0.25rem 0.5rem;
color: inherit;
}
form button[type="submit"] {
font-weight:bold;
}
form .description {
font-size: 0.8rem;
color: var(--color-text-secondary);
}
`.replace(/\s+/g, " ");
}
//#endregion
//#region src/components/error-message.tsx
var import_jsx_runtime$1 = require_chunk.__toESM(require_jsx_runtime());
function ErrorMessage({ children = "", id }) {
return /* @__PURE__ */ (0, import_jsx_runtime$1.jsx)("pre", {
id,
class: "error-message raw-data",
style: { background: "#ff000020" },
safe: true,
children: children.includes("{") ? JSON.stringify(JSON.parse(children), null, 2) : children
});
}
//#endregion
//#region src/utils/request-utils.ts
function checkIsHXRequest(request) {
const req = request || getStore().request;
return req.headers.get("hx-request") === "true";
}
function checkIsHTMLRequest(request) {
const req = request || getStore().request;
const accept = req.headers.get("accept");
return !!accept?.includes(require_constants.CONTENT_TYPES.HTML);
}
function checkIsNewMode(request) {
const req = request || getStore().request;
return req.query.get(require_constants.QUERY_PARAMS.mode) === require_constants.QUERY_PARAMS.newResource;
}
function checkIsEditMode(request) {
const req = request || getStore().request;
return req.query.get(require_constants.QUERY_PARAMS.mode) === require_constants.QUERY_PARAMS.editResource;
}
//#endregion
//#region src/utils/response-utils.tsx
var import_suspense = require_chunk.__toESM(require_suspense());
var import_jsx_runtime = require_chunk.__toESM(require_jsx_runtime());
function responseHTML(html) {
return {
status: 200,
headers: { "Content-Type": require_constants.CONTENT_TYPES.HTML },
body: (0, import_suspense.renderToStream)(html)
};
}
function responseError(error, context, init) {
try {
const { errorMessage, errorStatus, errorType } = require_error_utils.parseErrorMessage(error);
context.error(`[${errorType}]`, errorMessage, error instanceof Error ? error.stack : "");
const status = errorStatus ?? (typeof init === "number" ? init : init?.status ?? 500);
const headers = new Headers(typeof init === "number" ? {} : init?.headers);
if (checkIsHXRequest()) {
try {
headers.set("HXToaster-Type", "error");
headers.set("HXToaster-Body", errorMessage);
} catch {}
return {
status,
headers,
body: errorMessage
};
}
if (checkIsHTMLRequest()) {
headers.set("Content-Type", require_constants.CONTENT_TYPES.HTML);
return {
status,
headers,
body: (0, import_suspense.renderToStream)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DocumentLayout, {
title: `Error ${status}`,
breadcrumbs: [{
label: "< Back",
href: "javascript:history.back()"
}],
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorMessage, { children: errorMessage })
}))
};
}
headers.set("Content-Type", "application/json");
const jsonBody = { errorMessage };
return {
jsonBody,
status,
headers
};
} catch (err) {
context.error(`[ErrOnErr]`, err);
return {
status: 500,
body: typeof err === "string" ? err : void 0,
jsonBody: typeof err === "string" ? void 0 : err
};
}
}
function responseRedirect(location, init) {
const status = typeof init === "number" ? init : init?.status ?? 303;
const headers = new Headers(typeof init === "number" ? {} : init?.headers);
if (checkIsHXRequest()) headers.set("HX-redirect", location);
else headers.set("Location", location);
return {
status,
headers
};
}
//#endregion
//#region src/utils/store.ts
const store = new node_async_hooks.AsyncLocalStorage();
function getStore(throwError) {
const value = store.getStore();
if (!value && throwError !== false) throw new Error("Request store not found.");
return value;
}
function wrapHttpHandlerWithStore(options, handler, permissions) {
return function(request, context) {
const locale = request.headers.get("accept-language")?.split(",")[0];
const accept = request.headers.get("accept");
const storeValue = {
...options,
accept,
locale,
url: request.url,
request,
context
};
return store.run(storeValue, async () => {
if (!permissions || permissions.length === 0) return handler(request, context);
const { checkPermissions } = options;
const { projectId } = request.params;
const permitted = await checkPermissions(permissions.map((p) => ({
projectId,
...p
})), context, request);
if (permitted === true) return handler(request, context);
const message = `Permission denied [${permissions.map((p) => `'${p.resource}:${p.action}'`).join(", ")}] (project: ${projectId})`;
if (permitted === false) return responseError(message, context, 403);
if (typeof permitted === "object" && "status" in permitted) {
context.warn(message);
return permitted;
}
if (permitted instanceof Response) {
context.warn(message);
return permitted;
}
return handler(request, context);
});
};
}
//#endregion
Object.defineProperty(exports, 'DocumentLayout', {
enumerable: true,
get: function () {
return DocumentLayout;
}
});
Object.defineProperty(exports, 'ErrorMessage', {
enumerable: true,
get: function () {
return ErrorMessage;
}
});
Object.defineProperty(exports, 'checkIsEditMode', {
enumerable: true,
get: function () {
return checkIsEditMode;
}
});
Object.defineProperty(exports, 'checkIsHTMLRequest', {
enumerable: true,
get: function () {
return checkIsHTMLRequest;
}
});
Object.defineProperty(exports, 'checkIsHXRequest', {
enumerable: true,
get: function () {
return checkIsHXRequest;
}
});
Object.defineProperty(exports, 'checkIsNewMode', {
enumerable: true,
get: function () {
return checkIsNewMode;
}
});
Object.defineProperty(exports, 'getStore', {
enumerable: true,
get: function () {
return getStore;
}
});
Object.defineProperty(exports, 'require_jsx_runtime', {
enumerable: true,
get: function () {
return require_jsx_runtime;
}
});
Object.defineProperty(exports, 'responseError', {
enumerable: true,
get: function () {
return responseError;
}
});
Object.defineProperty(exports, 'responseHTML', {
enumerable: true,
get: function () {
return responseHTML;
}
});
Object.defineProperty(exports, 'responseRedirect', {
enumerable: true,
get: function () {
return responseRedirect;
}
});
Object.defineProperty(exports, 'urlBuilder', {
enumerable: true,
get: function () {
return urlBuilder;
}
});
Object.defineProperty(exports, 'wrapHttpHandlerWithStore', {
enumerable: true,
get: function () {
return wrapHttpHandlerWithStore;
}
});