diff --git a/lib/maoka-components/src/common/button.css b/lib/maoka-components/src/common/button.css
deleted file mode 100644
index e64c38ccd..000000000
--- a/lib/maoka-components/src/common/button.css
+++ /dev/null
@@ -1,22 +0,0 @@
-.button {
- @apply flex flex-wrap items-center justify-center space-x-2 rounded-md px-4 py-1 text-sm outline-none transition-all duration-300;
- @apply focus:!opacity-100 focus:ring-2 focus:ring-pink-600 focus:dark:ring-pink-400;
- @apply active:!opacity-100 active:ring-2 active:ring-pink-600 active:dark:ring-pink-400;
- @apply target:!opacity-100 target:ring-2 target:ring-pink-600 target:dark:ring-pink-400;
-}
-
-.button:disabled {
- @apply animate-none cursor-not-allowed !bg-neutral-400 ring-0 hover:!scale-100 hover:!bg-neutral-400 dark:!bg-neutral-600 hover:dark:!bg-neutral-600;
-}
-
-.button.neutral {
- @apply opacity-50 hover:opacity-100;
-}
-
-.button.success {
- @apply bg-emerald-300 shadow-md hover:scale-110 hover:shadow-lg dark:bg-emerald-700;
-}
-
-.button.primary {
- @apply bg-neutral-800 text-neutral-200 shadow-md hover:scale-110 hover:bg-pink-600 hover:shadow-lg dark:bg-neutral-200 dark:text-neutral-900 hover:dark:bg-pink-400;
-}
diff --git a/lib/maoka-components/src/common/checkbox.component.ts b/lib/maoka-components/src/common/checkbox.component.ts
index 8d0e73a10..640f5a757 100644
--- a/lib/maoka-components/src/common/checkbox.component.ts
+++ b/lib/maoka-components/src/common/checkbox.component.ts
@@ -22,7 +22,7 @@
import { Maoka } from "@ordo-pink/maoka"
import { MaokaJabs } from "@ordo-pink/maoka-jabs"
-import "./checkbox.css"
+import "../../maoka-components.css"
export type TCheckboxParams = {
on_change: (event: Event) => void
diff --git a/lib/maoka-components/src/common/checkbox.css b/lib/maoka-components/src/common/checkbox.css
deleted file mode 100644
index bad1a0d66..000000000
--- a/lib/maoka-components/src/common/checkbox.css
+++ /dev/null
@@ -1,11 +0,0 @@
-.checkbox {
- @apply size-5 shrink-0 cursor-pointer accent-pink-400;
-}
-
-.checkbox-label {
- @apply flex w-full items-start gap-x-1;
-}
-
-.checkbox-label > .checkbox {
- @apply mt-1 size-4;
-}
diff --git a/lib/maoka-components/src/common/dialog.component.ts b/lib/maoka-components/src/common/dialog.component.ts
index 7eacf6bd1..69d974f25 100644
--- a/lib/maoka-components/src/common/dialog.component.ts
+++ b/lib/maoka-components/src/common/dialog.component.ts
@@ -23,7 +23,7 @@ import { Maoka, type TMaokaChildren } from "@ordo-pink/maoka"
import { Button } from "@ordo-pink/maoka-components"
import { MaokaJabs } from "@ordo-pink/maoka-jabs"
-import "./dialog.css"
+import "../../maoka-components.css"
type TDialogParams = {
title: string
diff --git a/lib/maoka-components/src/common/dialog.css b/lib/maoka-components/src/common/dialog.css
deleted file mode 100644
index e1a44c673..000000000
--- a/lib/maoka-components/src/common/dialog.css
+++ /dev/null
@@ -1,15 +0,0 @@
-.dialog {
- @apply flex w-full flex-col gap-y-2 p-4 sm:w-96;
-}
-
-.dialog_header {
- @apply flex items-center gap-x-2;
-}
-
-.dialog_title {
- @apply text-lg;
-}
-
-.dialog_footer {
- @apply flex items-center justify-end gap-x-2;
-}
diff --git a/lib/maoka-components/src/common/hotkey.component.ts b/lib/maoka-components/src/common/hotkey.component.ts
index a9a02e942..de2002f9e 100644
--- a/lib/maoka-components/src/common/hotkey.component.ts
+++ b/lib/maoka-components/src/common/hotkey.component.ts
@@ -26,7 +26,7 @@ import { Switch } from "@ordo-pink/switch"
import { create_hotkey_from_event } from "@ordo-pink/hotkey-from-event"
import { title_case } from "@ordo-pink/tau"
-import "./hotkey.css"
+import "../../maoka-components.css"
export type THotkeyOptions = {
prevent_in_inputs?: boolean
diff --git a/lib/maoka-components/src/common/hotkey.css b/lib/maoka-components/src/common/hotkey.css
deleted file mode 100644
index a53e84040..000000000
--- a/lib/maoka-components/src/common/hotkey.css
+++ /dev/null
@@ -1,15 +0,0 @@
-.hotkey {
- @apply hidden shrink-0 items-center justify-center space-x-1 rounded-md px-2 py-0.5 text-center text-xs text-current sm:flex;
-}
-
-.hotkey.mobile {
- @apply flex;
-}
-
-.hotkey.smol {
- @apply px-1 py-0.5;
-}
-
-.key-container {
- @apply min-w-8 rounded-md border border-b-2 border-r-2 border-current px-1 py-0.5 text-current;
-}
diff --git a/lib/maoka-components/src/common/input.component.ts b/lib/maoka-components/src/common/input.component.ts
index ea4ac9dbf..079a246c3 100644
--- a/lib/maoka-components/src/common/input.component.ts
+++ b/lib/maoka-components/src/common/input.component.ts
@@ -27,7 +27,7 @@ import { ZAGS } from "@ordo-pink/zags"
const is_valid$ = ZAGS.Of({ value: true })
-import "./input.css"
+import "../../maoka-components.css"
type TInputProps = {
initial_value?: string
diff --git a/lib/maoka-components/src/common/input.css b/lib/maoka-components/src/common/input.css
deleted file mode 100644
index 126784f5a..000000000
--- a/lib/maoka-components/src/common/input.css
+++ /dev/null
@@ -1,19 +0,0 @@
-.input-wrapper {
- @apply relative w-full;
-}
-
-.input_label {
- @apply w-full text-sm font-bold;
-}
-
-.input_text {
- @apply w-full rounded-md border-0 bg-transparent px-2 py-1 shadow-inner outline-none placeholder:text-neutral-500;
-}
-
-.input_text.non-transparent {
- @apply bg-gradient-to-br from-neutral-100 to-stone-100 hover:from-neutral-100 hover:to-stone-100 dark:from-neutral-600 dark:to-stone-600 hover:dark:from-neutral-600 hover:dark:to-stone-600;
-}
-
-.input_text-error {
- @apply absolute top-0 w-full text-right text-sm font-bold text-rose-500;
-}
diff --git a/lib/maoka-components/src/common/label.component.ts b/lib/maoka-components/src/common/label.component.ts
index 5a95506a4..20aa4a9b2 100644
--- a/lib/maoka-components/src/common/label.component.ts
+++ b/lib/maoka-components/src/common/label.component.ts
@@ -25,7 +25,7 @@ import { Maoka } from "@ordo-pink/maoka"
import { MaokaJabs } from "@ordo-pink/maoka-jabs"
import { is_string } from "@ordo-pink/tau"
-import "./label.css"
+import "../../maoka-components.css"
export const Label = (label: Ordo.Metadata.Label, emit: Ordo.Command.EmitFn, metadata?: Ordo.Metadata.Instance) =>
Maoka.create("div", ({ use }) => {
diff --git a/lib/maoka-components/src/common/label.css b/lib/maoka-components/src/common/label.css
deleted file mode 100644
index 9dc21a6f7..000000000
--- a/lib/maoka-components/src/common/label.css
+++ /dev/null
@@ -1,81 +0,0 @@
-.label {
- @apply cursor-pointer rounded-sm px-1 py-0.5 text-xs shadow-sm;
- @apply hover:scale-105 hover:transition-all;
- @apply flex items-center gap-x-1;
-}
-
-.label_remove {
- @apply rounded-lg opacity-0 transition-all hover:bg-neutral-500/50 hover:opacity-100;
-}
-
-.label.default {
- @apply bg-neutral-200 dark:bg-neutral-600/75;
-}
-
-.label.red {
- @apply bg-red-200 dark:bg-red-600/75;
-}
-
-.label.orange {
- @apply bg-orange-200 dark:bg-orange-600/75;
-}
-
-.label.amber {
- @apply bg-amber-200 dark:bg-amber-600/75;
-}
-
-.label.yellow {
- @apply bg-yellow-200 dark:bg-yellow-600/75;
-}
-
-.label.lime {
- @apply bg-lime-200 dark:bg-lime-600/75;
-}
-
-.label.green {
- @apply bg-green-200 dark:bg-green-600/75;
-}
-
-.label.emerald {
- @apply bg-emerald-200 dark:bg-emerald-600/75;
-}
-
-.label.teal {
- @apply bg-teal-200 dark:bg-teal-600/75;
-}
-
-.label.cyan {
- @apply bg-cyan-200 dark:bg-cyan-600/75;
-}
-
-.label.sky {
- @apply bg-sky-200 dark:bg-sky-600/75;
-}
-
-.label.blue {
- @apply bg-blue-200 dark:bg-blue-600/75;
-}
-
-.label.indigo {
- @apply bg-indigo-200 dark:bg-indigo-600/75;
-}
-
-.label.violet {
- @apply bg-violet-200 dark:bg-violet-600/75;
-}
-
-.label.purple {
- @apply bg-purple-200 dark:bg-purple-600/75;
-}
-
-.label.fuchsia {
- @apply bg-fuchsia-200 dark:bg-fuchsia-600/75;
-}
-
-.label.pink {
- @apply bg-pink-200 dark:bg-pink-600/75;
-}
-
-.label.rose {
- @apply bg-rose-200 dark:bg-rose-600/75;
-}
diff --git a/lib/maoka-components/src/common/link.component.ts b/lib/maoka-components/src/common/link.component.ts
index 8a8a62e9a..751b6b108 100644
--- a/lib/maoka-components/src/common/link.component.ts
+++ b/lib/maoka-components/src/common/link.component.ts
@@ -26,7 +26,11 @@ import { is_string } from "@ordo-pink/tau"
import { MetadataIcon } from "../metadata/metadata-icon.component"
-type P = { href: `/${string}`; children?: TMaokaChildren; custom_class?: string; show_visited?: boolean; title?: string }
+import "../../maoka-components.css"
+import { MaokaStr } from "@ordo-pink/maoka-render-string"
+import { ordo_app_state } from "@ordo-pink/frontend-app/app.state"
+
+type P = { href: string; children?: TMaokaChildren; custom_class?: string; show_visited?: boolean; title?: string }
export const Link = ({ href, children, custom_class, show_visited, title }: P) =>
Maoka.create("a", ({ use }) => {
const { emit } = use(MaokaOrdo.Jabs.get_commands)
@@ -34,48 +38,57 @@ export const Link = ({ href, children, custom_class, show_visited, title }: P) =
use(MaokaJabs.listen("onclick", click_listener(emit, href)))
use(MaokaJabs.set_attribute("href", href))
use(MaokaJabs.set_attribute("title", title))
- use(MaokaJabs.set_class(default_class))
+ use(MaokaJabs.set_class("link"))
if (custom_class) use(MaokaJabs.add_class(custom_class))
- if (!show_visited) use(MaokaJabs.add_class(ignore_history_highlighting_class))
+ if (!show_visited) use(MaokaJabs.add_class("link_no-history"))
if (is_string(children)) use(MaokaJabs.set_attribute("title", children))
return () => children
})
export const MetadataLink = ({
- href,
children,
custom_class,
show_visited,
metadata,
title,
-}: P & { metadata: Ordo.Metadata.Instance }) =>
- Link({
- children: MetadataLinkWrapper(() => [
- MetadataIcon({ metadata, show_emoji_picker: false }),
- MetadataLinkTextWrapper(() => children),
- ]),
- custom_class: `no-underline ${custom_class}`,
- href,
- show_visited,
- title,
+}: Omit & { metadata: Ordo.Metadata.Instance }) =>
+ Maoka.create("span", ({ element }) => {
+ let href = `/editor/${metadata.get_fsid()}`
+
+ const user_query = ordo_app_state.zags.select("auth.user")
+ const pb_host = ordo_app_state.zags.select("hosts.pb")
+
+ if (user_query && MaokaStr.is_maoka_str_element(element)) {
+ const name = metadata.get_property("public_name")
+ href = `${pb_host}/${user_query.get_handle()}/${name}`
+ }
+
+ return () =>
+ Link({
+ children: MetadataLinkWrapper(() => [
+ MetadataIcon({ metadata, show_emoji_picker: false }),
+ MetadataLinkTextWrapper(() => children),
+ ]),
+ custom_class: `no-underline ${custom_class}`,
+ href,
+ show_visited,
+ title,
+ })
})
// --- Internal ---
-const default_class =
- "underline transition-all hover:text-rose-600 dark:hover:text-rose-300 rounded-sm cursor-pointer decoration-neutral-500/50 hover:decoration-rose-500/50 decoration-1 underline-offset-2"
-
-const MetadataLinkWrapper = Maoka.styled("div", { class: "w-fit flex items-center gap-x-1" })
+const MetadataLinkWrapper = Maoka.styled("div", { class: "link_wrapper" })
-const MetadataLinkTextWrapper = Maoka.styled("div", { class: `${default_class} text-ellipsis line-clamp-1` })
+const MetadataLinkTextWrapper = Maoka.styled("div", { class: "link link_text-wrapper" })
-const click_listener = (emit: Ordo.Command.Commands["emit"], url: `/${string}`) => (event: MouseEvent) => {
+const click_listener = (emit: Ordo.Command.Commands["emit"], url: string) => (event: MouseEvent) => {
event.preventDefault()
event.stopPropagation()
- emit("cmd.application.router.navigate", { url })
+ url.startsWith("/")
+ ? emit("cmd.application.router.navigate", { url: url as `/${string}` })
+ : emit("cmd.application.router.open_external", { url, new_tab: true })
}
-
-const ignore_history_highlighting_class = "text-inherit visited:text-inherit"
diff --git a/lib/maoka-components/src/common/select.component.ts b/lib/maoka-components/src/common/select.component.ts
index ac26f5385..a00de2182 100644
--- a/lib/maoka-components/src/common/select.component.ts
+++ b/lib/maoka-components/src/common/select.component.ts
@@ -20,12 +20,12 @@
*/
import { Maoka, type TMaokaChildren } from "@ordo-pink/maoka"
+import { BsChevronDown } from "@ordo-pink/frontend-icons"
import { MaokaJabs } from "@ordo-pink/maoka-jabs"
import { ActionListItem } from "./action-list-item.component"
-import "./select.css"
-import { BsChevronDown } from "@ordo-pink/frontend-icons"
+import "../../maoka-components.css"
export type TSelectOption<$TValue> = {
title: string
diff --git a/lib/maoka-components/src/common/select.css b/lib/maoka-components/src/common/select.css
deleted file mode 100644
index 48a4845a6..000000000
--- a/lib/maoka-components/src/common/select.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.select_color-picker_options-wrapper {
- @apply absolute left-0 right-0 top-7 max-h-48 overflow-auto rounded-sm bg-neutral-50 shadow-lg backdrop-blur-md dark:bg-neutral-800/90;
-}
diff --git a/lib/maoka-ordo-jabs/index.ts b/lib/maoka-ordo-jabs/index.ts
index 66a0a1396..1ad69e39a 100644
--- a/lib/maoka-ordo-jabs/index.ts
+++ b/lib/maoka-ordo-jabs/index.ts
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: Unlicense
*/
-import { Maoka, type TMaokaChildren } from "@ordo-pink/maoka"
+import { Maoka, type TMaokaComponent } from "@ordo-pink/maoka"
import {
get_commands,
@@ -52,12 +52,12 @@ export const MaokaOrdo = {
},
Context: ordo_context,
Components: {
- WithState: (ctx: Ordo.CreateFunction.State, children: () => TMaokaChildren) =>
+ WithState: (ctx: Ordo.CreateFunction.State, children: () => TMaokaComponent | Promise) =>
Maoka.create("div", ({ use }) => {
use(MaokaOrdo.Context.provide(ctx))
- return children
+ return async () => children()
}),
- WithStateCurry: (ctx: Ordo.CreateFunction.State) => (children: () => TMaokaChildren) =>
+ WithStateCurry: (ctx: Ordo.CreateFunction.State) => (children: () => TMaokaComponent | Promise) =>
MaokaOrdo.Components.WithState(ctx, children),
},
}
diff --git a/lib/maoka-render-string/index.ts b/lib/maoka-render-string/index.ts
new file mode 100644
index 000000000..10d01c24b
--- /dev/null
+++ b/lib/maoka-render-string/index.ts
@@ -0,0 +1,10 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2025, 谢尔盖 ||↓ and the Ordo.pink contributors
+ * SPDX-License-Identifier: Unlicense
+ */
+
+import { create_element, is_maoka_str_element, render } from "./src/maoka-render-string.impl"
+
+export * from "./src/maoka-render-string.types"
+
+export const MaokaStr = { create_element, is_maoka_str_element, render }
diff --git a/lib/maoka-render-string/license b/lib/maoka-render-string/license
new file mode 100644
index 000000000..f43bdf2be
--- /dev/null
+++ b/lib/maoka-render-string/license
@@ -0,0 +1,19 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in
+source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any
+and all copyright interest in the software to the public domain. We make this dedication for the
+benefit of the public at large and to the detriment of our heirs and successors. We intend this
+dedication to be an overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to
diff --git a/lib/maoka-render-string/readme.md b/lib/maoka-render-string/readme.md
new file mode 100644
index 000000000..bcf67a028
--- /dev/null
+++ b/lib/maoka-render-string/readme.md
@@ -0,0 +1 @@
+# Maoka Render String
diff --git a/lib/maoka-render-string/src/maoka-render-string.impl.ts b/lib/maoka-render-string/src/maoka-render-string.impl.ts
new file mode 100644
index 000000000..7ec5c9d8d
--- /dev/null
+++ b/lib/maoka-render-string/src/maoka-render-string.impl.ts
@@ -0,0 +1,69 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2025, 谢尔盖 ||↓ and the Ordo.pink contributors
+ * SPDX-License-Identifier: Unlicense
+ */
+
+import { type TMaokaChild } from "@ordo-pink/maoka"
+
+import { type TMaokaRenderStringFn, type TMaokaStrElement } from "./maoka-render-string.types"
+
+export const render: TMaokaRenderStringFn = async (root, component) => {
+ const root_id = crypto.randomUUID()
+ const Component = await component(create_element, root, root_id)
+
+ root.appendChild(Component)
+
+ return root.str()
+}
+
+export const create_element = (tag: string): TMaokaStrElement => {
+ const attributes = {} as Record
+ let children = [] as TMaokaChild[]
+
+ return {
+ setAttribute: (qualified_name: string, value: string) => {
+ attributes[qualified_name] = value
+ },
+ getAttribute: (qualified_name: string) => qualified_name,
+ removeAttribute: (qualified_name: string) => {
+ delete attributes[qualified_name]
+ },
+ appendChild: child => {
+ children.push(child)
+ return child
+ },
+ replaceChildren: (...new_children) => {
+ children = new_children
+ },
+ get children() {
+ return children
+ },
+ dispatchEvent: () => false,
+ str: async (depth = 0) => {
+ const result = "<"
+ .concat(tag)
+ .concat(Object.keys(attributes).length ? " " : "")
+ .concat(Object.keys(attributes).reduce((acc, key) => acc.concat(`${key}="${attributes[key]}" `), ""))
+ .concat(">")
+
+ const child_strings = [] as string[]
+
+ for (const child of children) {
+ if (!child) {
+ continue
+ } else if (is_maoka_str_element(child)) {
+ child_strings.push(await child.str(depth + 1))
+ } else if (typeof child === "string") {
+ child_strings.push(child)
+ } else if (typeof child === "number") {
+ child_strings.push(String(child))
+ }
+ }
+
+ return result.concat(child_strings.join("")).concat("").concat(tag).concat(">")
+ },
+ }
+}
+
+export const is_maoka_str_element = (x: any): x is TMaokaStrElement =>
+ !!x && typeof x === "object" && x.str && typeof x.str === "function"
diff --git a/lib/maoka-render-string/src/maoka-render-string.test.ts b/lib/maoka-render-string/src/maoka-render-string.test.ts
new file mode 100644
index 000000000..a4aa56c14
--- /dev/null
+++ b/lib/maoka-render-string/src/maoka-render-string.test.ts
@@ -0,0 +1,11 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2025, 谢尔盖 ||↓ and the Ordo.pink contributors
+ * SPDX-License-Identifier: Unlicense
+ */
+
+import { expect, test } from "bun:test"
+import { maoka_render_string } from "./maoka-render-string.impl"
+
+test("maoka-render-string should pass", () => {
+ expect(maoka_render_string).toEqual("maoka-render-string")
+})
diff --git a/lib/maoka-render-string/src/maoka-render-string.types.ts b/lib/maoka-render-string/src/maoka-render-string.types.ts
new file mode 100644
index 000000000..c4c4d9b4b
--- /dev/null
+++ b/lib/maoka-render-string/src/maoka-render-string.types.ts
@@ -0,0 +1,9 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2025, 谢尔盖 ||↓ and the Ordo.pink contributors
+ * SPDX-License-Identifier: Unlicense
+ */
+
+import type { TMaokaComponent, TMaokaElement } from "@ordo-pink/maoka"
+
+export type TMaokaRenderStringFn = (root: TMaokaStrElement, component: TMaokaComponent) => Promise
+export type TMaokaStrElement = TMaokaElement & { str: (depth?: number) => Promise }
diff --git a/lib/maoka/src/maoka.impl.ts b/lib/maoka/src/maoka.impl.ts
index e9f3c35fb..f40ae54aa 100644
--- a/lib/maoka/src/maoka.impl.ts
+++ b/lib/maoka/src/maoka.impl.ts
@@ -75,7 +75,8 @@ export const styled =
export const html = (tag: string, html: string): T.TMaokaComponent =>
create(tag, ({ element }) => {
- element.innerHTML = html
+ if (element instanceof Element) return void (element.innerHTML = html)
+ return () => html
})
export const dom: T.TMaokaRenderDOMFn = async (root, component) => {
@@ -86,22 +87,27 @@ export const dom: T.TMaokaRenderDOMFn = async (root, component) => {
const Component = await component(create_element, root_element, root_id)
const refresh_queue = new Map Promise }>()
- root.appendChild(Component as HTMLElement)
+ root.appendChild(Component as unknown as HTMLElement)
root.addEventListener("refresh", event => {
event.stopPropagation()
- const [id, element, get_children] = (event as any).detail as [string, T.TMaokaElement, () => T.TMaokaComponent]
+ const [id, element, get_children] = (event as any).detail as [string, T.TMaokaDOMElement, () => T.TMaokaComponent]
- const refresh_elements = refresh_queue.keys().toArray()
+ const refresh_nodes = refresh_queue.keys().toArray()
if (refresh_queue.has(id)) return
- for (let i = 0; i < refresh_elements.length; i++) {
- const e = refresh_queue.get(refresh_elements[i])?.element as HTMLElement
+ for (let i = 0; i < refresh_nodes.length; i++) {
+ const refresh_element = refresh_queue.get(refresh_nodes[i])?.element
- if (e && element.contains?.(e)) {
- refresh_queue.delete(refresh_elements[i])
+ if (
+ refresh_element &&
+ refresh_element instanceof HTMLElement &&
+ element instanceof HTMLElement &&
+ element.contains?.(refresh_element)
+ ) {
+ refresh_queue.delete(refresh_nodes[i])
break
}
}
@@ -124,30 +130,22 @@ export const dom: T.TMaokaRenderDOMFn = async (root, component) => {
).then(() => request_idle_callback(() => void render_loop()))
: request_idle_callback(() => void render_loop())
- // const render_loop = () => {
- // const next = refresh_queue.entries().next()
-
- // if (next.value) {
- // console.log(next.value[0])
- // refresh_queue.delete(next.value[0])
- // return void next.value[1]().then(() => request_idle_callback(render_loop))
- // }
-
- // request_idle_callback(render_loop)
- // }
-
request_idle_callback(() => void render_loop())
const unmount_element = (element: T.TMaokaElement) => {
if (element.onunmount) element.onunmount()
- element.childNodes.forEach(child => unmount_element(child as any))
+ for (let i = 0; i < element.children.length; i++) {
+ unmount_element(element.children[i] as T.TMaokaElement)
+ }
}
const mount_element = (element: T.TMaokaElement) => {
if (element.onmount) element.onmount()
- element.childNodes.forEach(child => mount_element(child as any))
+ for (let i = 0; i < element.children.length; i++) {
+ mount_element(element.children[i] as T.TMaokaElement)
+ }
}
mount_element(Component)
@@ -169,11 +167,7 @@ export const dom: T.TMaokaRenderDOMFn = async (root, component) => {
}
})
- observer.observe(root as HTMLElement, {
- childList: true,
- subtree: true,
- attributeFilter: ["onmount", "onunmount"],
- })
+ observer.observe(root, { childList: true, subtree: true, attributeFilter: ["onmount", "onunmount"] })
}
// --- Internal ---
@@ -186,7 +180,7 @@ const render_children = async (
element: T.TMaokaElement,
) => {
if (!get_children) return element
- element.innerHTML = ""
+ if (element instanceof HTMLElement) element.innerHTML = ""
let children = await get_children()
if (!children) return element
diff --git a/lib/maoka/src/maoka.types.ts b/lib/maoka/src/maoka.types.ts
index fbf3bf17a..eabaec70b 100644
--- a/lib/maoka/src/maoka.types.ts
+++ b/lib/maoka/src/maoka.types.ts
@@ -5,28 +5,31 @@
// TODO: Comments
// TODO: Full types
-export type TMaokaElement = { [$TKey in keyof HTMLElement]: HTMLElement[$TKey] | undefined } & {
- setAttribute: (qualified_name: string, value: string) => void
- getAttribute: (qualified_name: string) => string
+export type TMaokaElement = {
+ setAttribute: (qualifiedName: string, value: string) => void
+ getAttribute: (qualifiedName: string) => string
+ removeAttribute: (qualifiedName: string) => void
appendChild: (child: TMaokaChild) => TMaokaChild
replaceChildren: (...children: TMaokaChild[]) => void
- childNodes: HTMLElement["childNodes"]
dispatchEvent: (event: Event) => void
- onunmount: (() => void) | undefined
- onmount: (() => void) | undefined
+ children: TMaokaChild[]
+
+ // TODO Move to render_dom
+ onunmount?: (() => void) | undefined
+ onmount?: (() => void) | undefined
}
export type TMaokaTextElement = Partial<{ [$TKey in keyof Text]: Text[$TKey] }> | string
-export type TMaokaCreateMaokaElementFn<$TElement extends TMaokaElement = TMaokaElement> = (name: string) => $TElement
+export type TMaokaCreateMaokaElementFn = (name: string) => TMaokaElement
export type TMaokaCreateComponentFn = (name: string, callback: TMaokaCallback) => TMaokaComponent
-export type TMaokaComponent<$TElement extends TMaokaElement = TMaokaElement> = {
- (create_element: TMaokaCreateMaokaElementFn<$TElement>, root_element: TMaokaElement, root_id: string): Promise
+export type TMaokaComponent = {
+ (create_element: TMaokaCreateMaokaElementFn, root_element: TMaokaElement, root_id: string): Promise
id?: string
rid?: string
- element?: $TElement
+ element?: TMaokaElement
refresh?: () => void
}
@@ -51,7 +54,7 @@ export type TMaokaChildren = TMaokaChild | TMaokaChild[]
/**
* A record of jabs that are provided by Maoka directly.
*/
-export type TMaokaProps<$TElement extends TMaokaElement = TMaokaElement> = {
+export type TMaokaProps = {
/**
* Get UUID of current Maoka component. This would probably only be useful for creating custom
* jabs that accumulate a set of components to apply batch refresh calls. You would hardly ever
@@ -62,7 +65,7 @@ export type TMaokaProps<$TElement extends TMaokaElement = TMaokaElement> = {
/**
* Returns reference to the current element.
*/
- get element(): $TElement
+ get element(): TMaokaElement
/**
* Root id.
@@ -104,7 +107,9 @@ export type TMaokaCallback = (
| Promise<(() => TMaokaChildren) | undefined | void>
| Promise<(() => Promise) | undefined | void>
-export type TMaokaRenderDOMFn = <$TElement extends HTMLElement = HTMLElement>(
- root: $TElement,
- component: TMaokaComponent,
-) => Promise
+export type TMaokaDOMElement = TMaokaElement & {
+ onunmount: (() => void) | undefined
+ onmount: (() => void) | undefined
+}
+
+export type TMaokaRenderDOMFn = (root: HTMLElement, component: TMaokaComponent) => Promise
diff --git a/lib/oath-indexeddb/index.ts b/lib/oath-indexeddb/index.ts
new file mode 100644
index 000000000..607d1c249
--- /dev/null
+++ b/lib/oath-indexeddb/index.ts
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2025, 谢尔盖 ||↓ and the Ordo.pink contributors
+ * SPDX-License-Identifier: Unlicense
+ */
+
+export * from "./src/oath-indexeddb.impl"
+export * from "./src/oath-indexeddb.types"
diff --git a/lib/oath-indexeddb/license b/lib/oath-indexeddb/license
new file mode 100644
index 000000000..f43bdf2be
--- /dev/null
+++ b/lib/oath-indexeddb/license
@@ -0,0 +1,19 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in
+source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any
+and all copyright interest in the software to the public domain. We make this dedication for the
+benefit of the public at large and to the detriment of our heirs and successors. We intend this
+dedication to be an overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to
diff --git a/lib/oath-indexeddb/readme.md b/lib/oath-indexeddb/readme.md
new file mode 100644
index 000000000..7a6acca60
--- /dev/null
+++ b/lib/oath-indexeddb/readme.md
@@ -0,0 +1 @@
+# Oath Indexeddb
diff --git a/lib/oath-indexeddb/src/oath-indexeddb.impl.ts b/lib/oath-indexeddb/src/oath-indexeddb.impl.ts
new file mode 100644
index 000000000..972ec2e55
--- /dev/null
+++ b/lib/oath-indexeddb/src/oath-indexeddb.impl.ts
@@ -0,0 +1,34 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2025, 谢尔盖 ||↓ and the Ordo.pink contributors
+ * SPDX-License-Identifier: Unlicense
+ */
+
+import type { TIndexedDBObjectStorePromiseStatic } from "./oath-indexeddb.types"
+
+export const IndexedDBStorePromise: TIndexedDBObjectStorePromiseStatic = {
+ Of: store => ({
+ add: (value, key) => promisify_idb_request(store.add(value, key)),
+ clear: () => promisify_idb_request(store.clear()),
+ count: query => promisify_idb_request(store.count(query)),
+ delete: query => promisify_idb_request(store.delete(query)),
+ get: query => promisify_idb_request(store.get(query)),
+ get_all: (query, count) => promisify_idb_request(store.getAll(query, count)),
+ get_all_keys: (query, count) => promisify_idb_request(store.getAllKeys(query, count)),
+ get_key: query => promisify_idb_request(store.getKey(query)),
+ put: (value, key) => promisify_idb_request(store.put(value, key)),
+ }),
+}
+
+const promisify_idb_request = (req: IDBRequest) =>
+ new Promise((resolve, reject) => {
+ if (req.transaction) {
+ req.transaction.oncomplete = () => resolve(req.result)
+ req.transaction.onerror = () => reject(req.error)
+ req.transaction.onabort = () => reject(new Error("Transaction aborted"))
+
+ return
+ }
+
+ req.onsuccess = () => resolve(req.result)
+ req.onerror = () => reject(req.error)
+ })
diff --git a/lib/oath-indexeddb/src/oath-indexeddb.test.ts b/lib/oath-indexeddb/src/oath-indexeddb.test.ts
new file mode 100644
index 000000000..caf855a58
--- /dev/null
+++ b/lib/oath-indexeddb/src/oath-indexeddb.test.ts
@@ -0,0 +1,11 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2025, 谢尔盖 ||↓ and the Ordo.pink contributors
+ * SPDX-License-Identifier: Unlicense
+ */
+
+import { expect, test } from "bun:test"
+import { oath_indexeddb } from "./oath-indexeddb.impl"
+
+test("oath-indexeddb should pass", () => {
+ expect(oath_indexeddb).toEqual("oath-indexeddb")
+})
diff --git a/lib/oath-indexeddb/src/oath-indexeddb.types.ts b/lib/oath-indexeddb/src/oath-indexeddb.types.ts
new file mode 100644
index 000000000..a9fba5cca
--- /dev/null
+++ b/lib/oath-indexeddb/src/oath-indexeddb.types.ts
@@ -0,0 +1,30 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2025, 谢尔盖 ||↓ and the Ordo.pink contributors
+ * SPDX-License-Identifier: Unlicense
+ */
+
+export type IDBCursorWithValue = IDBCursor & { value: T }
+
+export type TIndexedDBObjectStorePromise = {
+ add: (value: T, key: IDBValidKey) => Promise
+ clear: () => Promise
+ count: (query?: IDBValidKey | IDBKeyRange) => Promise
+ delete: (query: IDBValidKey | IDBKeyRange) => Promise
+ get: (query: IDBValidKey | IDBKeyRange) => Promise
+ get_all: (query?: IDBValidKey | IDBKeyRange | null, count?: number) => Promise
+ get_all_keys: (query?: IDBValidKey | IDBKeyRange | null, count?: number) => Promise
+ get_key: (query: IDBValidKey | IDBKeyRange) => Promise
+ put: (value: T, key?: IDBValidKey) => Promise
+ // create_index: (name: string, keyPath: string | string[], options?: IDBIndexParameters) => Promise
+ // delete_index: (name: string) => void
+ // index: (name: string) => IDBIndex
+ // open_cursor: (
+ // query?: IDBValidKey | IDBKeyRange | null,
+ // direction?: IDBCursorDirection,
+ // ) => Promise | null>
+ // open_key_cursor: (query?: IDBValidKey | IDBKeyRange | null, direction?: IDBCursorDirection) => Promise
+}
+
+export type TIndexedDBObjectStorePromiseStatic = {
+ Of: (store: IDBObjectStore) => TIndexedDBObjectStorePromise
+}
diff --git a/lib/oath/src/oath.impl.ts b/lib/oath/src/oath.impl.ts
index cab92c3ba..cde95f1b3 100644
--- a/lib/oath/src/oath.impl.ts
+++ b/lib/oath/src/oath.impl.ts
@@ -240,7 +240,7 @@ export class Oath<$TResolve, $TReject = never> {
*
* @optional
*/
- on_error = (error: unknown) => (error instanceof Error ? error : (new Error(String(error as any)) as any)),
+ on_error: (error: Error) => $TReject = (error: Error) => error as any,
/**
* Optional abort controller for cases when Oath was cancelled when it already
@@ -250,12 +250,14 @@ export class Oath<$TResolve, $TReject = never> {
*/
abort_controller: AbortController = new AbortController(),
): Oath, $TReject> => {
+ const to_error = (error: any) => (error instanceof Error ? error : new Error(String(error)))
+
return new Oath(async (resolve, reject) => {
try {
// eslint-disable-next-line @typescript-eslint/await-thenable
resolve(await thunk())
} catch (error) {
- reject(on_error(error))
+ reject(on_error(to_error(error)))
}
}, abort_controller)
}
diff --git a/lib/oath/src/oath.types.ts b/lib/oath/src/oath.types.ts
index be28fdc9f..ca7287d59 100644
--- a/lib/oath/src/oath.types.ts
+++ b/lib/oath/src/oath.types.ts
@@ -25,7 +25,7 @@ export type TUnderOathRejected = T extends object & {
fix(on_reject: infer F): any
}
? F extends (value: infer V) => any
- ? TUnderOathRejected
+ ? V
: never
: never
diff --git a/lib/routary-cors/src/routary-cors.impl.ts b/lib/routary-cors/src/routary-cors.impl.ts
index 7f0e914b1..626cc61db 100644
--- a/lib/routary-cors/src/routary-cors.impl.ts
+++ b/lib/routary-cors/src/routary-cors.impl.ts
@@ -15,7 +15,7 @@ export const routary_cors: TRoutaryCORS =
Object.keys(shaft).forEach(bearing => {
if (bearing === "OPTIONS") return
- Object.keys(shaft[bearing as TBearing] as Record>>).forEach(gasket => {
+ Object.keys(shaft[bearing as TBearing] as Record>).forEach(gasket => {
if (!options[gasket]) options[gasket] = ["OPTIONS"]
options[gasket].push(bearing)
@@ -25,17 +25,15 @@ export const routary_cors: TRoutaryCORS =
if (typeof allow_origin === "string") allow_origin = [allow_origin]
const origin = intake.req.headers.get("origin")
- if (!origin || !allow_origin.includes(origin)) return new Response("", { status: 404 })
+ if (!origin || !allow_origin.includes(origin)) return gear(intake)
- const headers = {
- "Access-Control-Allow-Origin": origin,
- "Access-Control-Allow-Methods": options[gasket].join(", "),
- } as Record
+ if (!intake.headers) intake.headers = new Headers()
- if (max_age) headers["Access-Control-Max-Age"] = String(max_age)
- if (allow_headers.length) headers["Access-Control-Allow-Headers"] = allow_headers.join(", ")
+ intake.headers.set("Access-Control-Allow-Origin", origin)
+ intake.headers.set("Access-Control-Allow-Methods", options[gasket].join(", "))
- intake.headers = headers
+ if (max_age) intake.headers.set("Access-Control-Max-Age", String(max_age))
+ if (allow_headers.length) intake.headers.set("Access-Control-Allow-Headers", allow_headers.join(", "))
return gear(intake)
}
@@ -51,13 +49,13 @@ export const routary_cors: TRoutaryCORS =
if (!origin || !allow_origin.includes(origin)) return new Response("", { status: 404 })
- const headers = {
- "Access-Control-Allow-Origin": origin,
- "Access-Control-Allow-Methods": options[gasket].join(", "),
- } as Record
+ const headers = new Headers()
- if (max_age) headers["Access-Control-Max-Age"] = String(max_age)
- if (allow_headers.length) headers["Access-Control-Allow-Headers"] = allow_headers.join(", ")
+ headers.set("Access-Control-Allow-Origin", origin)
+ headers.set("Access-Control-Allow-Methods", options[gasket].join(", "))
+
+ if (max_age) headers.set("Access-Control-Max-Age", String(max_age))
+ if (allow_headers.length) headers.set("Access-Control-Allow-Headers", allow_headers.join(", "))
return new Response("", { status: success_status, headers })
}
diff --git a/lib/routary-cors/src/routary-cors.types.ts b/lib/routary-cors/src/routary-cors.types.ts
index 00eb7db4a..10194bd55 100644
--- a/lib/routary-cors/src/routary-cors.types.ts
+++ b/lib/routary-cors/src/routary-cors.types.ts
@@ -12,6 +12,6 @@ export type TRoutaryCORSParams = {
allow_headers?: string[]
}
-export type TRoutaryCORS = <$TChamber extends Record & { headers: Record }>(
+export type TRoutaryCORS = <$TChamber extends Record & { headers: Headers }>(
params: TRoutaryCORSParams,
) => Parameters["use"]>[0]
diff --git a/lib/routary/src/routary.types.ts b/lib/routary/src/routary.types.ts
index 1cd1b8658..36c2a1a9c 100644
--- a/lib/routary/src/routary.types.ts
+++ b/lib/routary/src/routary.types.ts
@@ -33,5 +33,5 @@ export type TRoutary<$TChamber> = {
head: (gasket: TGasket, gear: TGear<$TChamber>) => TRoutary<$TChamber>
options: (gasket: TGasket, gear: TGear<$TChamber>) => TRoutary<$TChamber>
each: (gasket: TGasket, bearings: TBearing[], gear: TGear<$TChamber>) => TRoutary<$TChamber>
- start: (chown_gear: TGear<$TChamber>) => (req: Request, server: Server) => Response | Promise
+ start: (crown_gear: TGear<$TChamber>) => (req: Request, server: Server) => Response | Promise
}
diff --git a/lib/tau/src/impl.ts b/lib/tau/src/impl.ts
index e242addff..d9a6608da 100644
--- a/lib/tau/src/impl.ts
+++ b/lib/tau/src/impl.ts
@@ -147,9 +147,9 @@ export const first_matched =
(xs: T[]) =>
xs.find(i => f(i))
-type TProp = <$Key extends PropertyKey>(
- prop: $Key,
-) => <$Record extends { [_Property in $Key]: unknown }>(obj: $Record) => $Record[$Key]
+type TProp = <$TRecord extends Record | any[], $TKey extends keyof $TRecord>(
+ prop: $TKey,
+) => (obj: $TRecord) => $TRecord[$TKey]
export const prop: TProp = key => obj => obj[key]
export const thunk =
diff --git a/package.json b/package.json
index fc9105b38..aa7debde6 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,7 @@
},
"name": "@ordo-pink/ordo",
"devDependencies": {
- "@types/bun": "^1.1.11",
+ "@types/bun": "^1.2.2",
"@types/eslint": "^8.56.2",
"@types/koa-bodyparser": "^4.3.10",
"@types/koa-cors": "^0.0.2",
diff --git a/root/bruno/DT/Create File Content.bru b/root/bruno/DT/Create File Content.bru
new file mode 100644
index 000000000..f56099e45
--- /dev/null
+++ b/root/bruno/DT/Create File Content.bru
@@ -0,0 +1,28 @@
+meta {
+ name: Create File Content
+ type: http
+ seq: 1
+}
+
+post {
+ url: {{DT_HOST}}/:uid/:fsid
+ body: text
+ auth: bearer
+}
+
+params:path {
+ uid: {{CURRENT_ID}}
+ fsid: {{CURRENT_ID}}
+}
+
+headers {
+ Origin: {{ORIGIN}}
+}
+
+auth:bearer {
+ token: {{CURRENT_TOKEN}}
+}
+
+body:text {
+ Hello world
+}
diff --git a/root/bruno/DT/Delete File Content.bru b/root/bruno/DT/Delete File Content.bru
new file mode 100644
index 000000000..8733d6325
--- /dev/null
+++ b/root/bruno/DT/Delete File Content.bru
@@ -0,0 +1,24 @@
+meta {
+ name: Delete File Content
+ type: http
+ seq: 5
+}
+
+delete {
+ url: {{DT_HOST}}/:uid/:fsid
+ body: none
+ auth: bearer
+}
+
+params:path {
+ uid: {{CURRENT_ID}}
+ fsid: {{CURRENT_ID}}
+}
+
+headers {
+ Origin: {{ORIGIN}}
+}
+
+auth:bearer {
+ token: {{CURRENT_TOKEN}}
+}
diff --git a/root/bruno/DT/Get File Content.bru b/root/bruno/DT/Get File Content.bru
new file mode 100644
index 000000000..5bc6604be
--- /dev/null
+++ b/root/bruno/DT/Get File Content.bru
@@ -0,0 +1,24 @@
+meta {
+ name: Get File Content
+ type: http
+ seq: 3
+}
+
+get {
+ url: {{DT_HOST}}/:uid/:fsid
+ body: none
+ auth: bearer
+}
+
+params:path {
+ uid: {{CURRENT_ID}}
+ fsid: {{CURRENT_ID}}
+}
+
+headers {
+ Origin: {{ORIGIN}}
+}
+
+auth:bearer {
+ token: {{CURRENT_TOKEN}}
+}
diff --git a/root/bruno/DT/Get File Modification Time.bru b/root/bruno/DT/Get File Modification Time.bru
new file mode 100644
index 000000000..df2b0e160
--- /dev/null
+++ b/root/bruno/DT/Get File Modification Time.bru
@@ -0,0 +1,24 @@
+meta {
+ name: Get File Modification Time
+ type: http
+ seq: 2
+}
+
+head {
+ url: {{DT_HOST}}/:uid/:fsid
+ body: none
+ auth: bearer
+}
+
+params:path {
+ uid: {{CURRENT_ID}}
+ fsid: "b68678af-6776-47c0-a0b8-4b6535664b8c"
+}
+
+headers {
+ Origin: {{ORIGIN}}
+}
+
+auth:bearer {
+ token: {{CURRENT_TOKEN}}
+}
diff --git a/root/bruno/DT/Update File Content.bru b/root/bruno/DT/Update File Content.bru
new file mode 100644
index 000000000..332457c2d
--- /dev/null
+++ b/root/bruno/DT/Update File Content.bru
@@ -0,0 +1,28 @@
+meta {
+ name: Update File Content
+ type: http
+ seq: 4
+}
+
+put {
+ url: {{DT_HOST}}/:uid/:fsid
+ body: text
+ auth: bearer
+}
+
+params:path {
+ uid: {{CURRENT_ID}}
+ fsid: {{CURRENT_ID}}
+}
+
+headers {
+ Origin: {{ORIGIN}}
+}
+
+auth:bearer {
+ token: {{CURRENT_TOKEN}}
+}
+
+body:text {
+ Hello world!
+}
diff --git a/root/bruno/DT/[pub] Healthcheck.bru b/root/bruno/DT/[pub] Healthcheck.bru
new file mode 100644
index 000000000..5d26aa4fe
--- /dev/null
+++ b/root/bruno/DT/[pub] Healthcheck.bru
@@ -0,0 +1,15 @@
+meta {
+ name: [pub] Healthcheck
+ type: http
+ seq: 6
+}
+
+get {
+ url: {{DT_HOST}}/healthcheck
+ body: none
+ auth: none
+}
+
+headers {
+ Origin: {{ORIGIN}}
+}
diff --git a/root/bruno/ID/codes/[pub] Validate Code.bru b/root/bruno/ID/codes/[pub] Validate Code.bru
index e7f6adab2..3dad4af8f 100644
--- a/root/bruno/ID/codes/[pub] Validate Code.bru
+++ b/root/bruno/ID/codes/[pub] Validate Code.bru
@@ -21,7 +21,7 @@ headers {
body:json {
{
"email": "{{USER_EMAIL}}",
- "code": "143948"
+ "code": "{{CURRENT_CODE}}"
}
}
diff --git a/root/bruno/collection.bru b/root/bruno/collection.bru
index 0d53de500..5f2795e4d 100644
--- a/root/bruno/collection.bru
+++ b/root/bruno/collection.bru
@@ -4,4 +4,7 @@ vars:pre-request {
ORIGIN: http://localhost:3004
USER_EMAIL: test@test.com
USER_HANDLE: @test
+ DT_PORT: 3002
+ DT_HOST: http://localhost:{{DT_PORT}}
+ CURRENT_CODE: 199515
}
diff --git a/srv/data/Dockerfile b/srv/data/Dockerfile
deleted file mode 100644
index c5a17cdf6..000000000
--- a/srv/data/Dockerfile
+++ /dev/null
@@ -1,17 +0,0 @@
-FROM ubuntu:latest
-
-ARG ORDO_DT_DOCKER_PORT
-ARG ORDO_DT_DOCKER_ENV
-ARG ORDO_DT_DOCKER_REGION
-
-MAINTAINER 谢尔盖||↓ and the Ordo.pink contributors
-LABEL pink.ordo.service="DT"
-LABEL pink.ordo.description="Docker image for Ordo DT service"
-LABEL pink.ordo.env=${ORDO_DT_DOCKER_ENV}
-LABEL pink.ordo.region=${ORDO_DT_DOCKER_REGION}
-
-EXPOSE ${ORDO_DT_DOCKER_PORT:-3002}
-
-COPY ./var/out/dt /dt
-
-ENTRYPOINT ["/dt"]
diff --git a/srv/data/bin/compile.ts b/srv/data/bin/compile.ts
deleted file mode 100644
index 9885ec979..000000000
--- a/srv/data/bin/compile.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SPDX-FileCopyrightText: Copyright 2024, 谢尔盖 ||↓ and the Ordo.pink contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- *
- * Ordo.pink is an all-in-one team workspace.
- * Copyright (C) 2024 谢尔盖 ||↓ and the Ordo.pink contributors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import { create_dir_if_not_exists0, mv0 } from "@ordo-pink/fs"
-import { die, run_bun_command } from "@ordo-pink/binutil"
-import { getc } from "@ordo-pink/getc"
-import { keys_of } from "@ordo-pink/tau"
-
-const env = getc()
-
-const defineEnv = (env: Record) =>
- keys_of(env).reduce((acc, key) => acc.concat(`--define Bun.env.${key}='${env[key]}' `), "")
-const createOutDirectoryIfNotExists0 = () => create_dir_if_not_exists0("var/out")
-const moveCompiledFileToOutDirectory0 = () => mv0("dt", "var/out/dt")
-
-const command = "build srv/data/index.ts --outfile=dt --target=bun --minify --compile "
-const envDefinitions = defineEnv(env)
-
-void run_bun_command(command.concat(envDefinitions))
- .chain(createOutDirectoryIfNotExists0)
- .chain(moveCompiledFileToOutDirectory0)
- .orElse(die())
diff --git a/srv/data/bin/init.ts b/srv/data/bin/init.ts
deleted file mode 100644
index 2f10af4a7..000000000
--- a/srv/data/bin/init.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SPDX-FileCopyrightText: Copyright 2024, 谢尔盖 ||↓ and the Ordo.pink contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- *
- * Ordo.pink is an all-in-one team workspace.
- * Copyright (C) 2024 谢尔盖 ||↓ and the Ordo.pink contributors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import { Oath, invokers0 } from "@ordo-pink/oath"
-import { create_dir_if_not_exists0 } from "@ordo-pink/fs"
-import { die } from "@ordo-pink/binutil"
-import { getc } from "@ordo-pink/getc"
-
-const { ORDO_DT_DATA_PATH, ORDO_DT_CONTENT_PATH } = getc(["ORDO_DT_DATA_PATH", "ORDO_DT_CONTENT_PATH"])
-
-void Oath.Merge([create_dir_if_not_exists0(ORDO_DT_DATA_PATH), create_dir_if_not_exists0(ORDO_DT_CONTENT_PATH)]).invoke(
- invokers0.or_else(die()),
-)
diff --git a/srv/data/bin/publish.ts b/srv/data/bin/publish.ts
deleted file mode 100644
index 91563ca26..000000000
--- a/srv/data/bin/publish.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SPDX-FileCopyrightText: Copyright 2024, 谢尔盖 ||↓ and the Ordo.pink contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- *
- * Ordo.pink is an all-in-one team workspace.
- * Copyright (C) 2024 谢尔盖 ||↓ and the Ordo.pink contributors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import { die, run_command } from "@ordo-pink/binutil"
-import { getc } from "@ordo-pink/getc"
-
-const {
- ORDO_DT_ENV,
- ORDO_DT_PORT,
- ORDO_DT_REGION,
- ORDO_DT_DOCKER_REGISTRY,
- ORDO_DT_DOCKER_REGISTRY_SCOPE,
- ORDO_DT_DOCKER_REGISTRY_USERNAME,
- ORDO_DT_DOCKER_REGISTRY_PASSWORD,
- ORDO_DT_VERSION,
-} = getc([
- "ORDO_DT_PORT",
- "ORDO_DT_ENV",
- "ORDO_DT_REGION",
- "ORDO_DT_DOCKER_REGISTRY",
- "ORDO_DT_DOCKER_REGISTRY_SCOPE",
- "ORDO_DT_DOCKER_REGISTRY_USERNAME",
- "ORDO_DT_DOCKER_REGISTRY_PASSWORD",
- "ORDO_DT_VERSION",
-])
-
-const build = `docker build --build-arg ORDO_DT_DOCKER_PORT=${ORDO_DT_PORT} --build-arg ORDO_DT_DOCKER_ENV=${ORDO_DT_ENV} --build-arg ORDO_DT_DOCKER_REGION=${ORDO_DT_REGION} -t ${ORDO_DT_DOCKER_REGISTRY}/${ORDO_DT_DOCKER_REGISTRY_SCOPE}/dt:${ORDO_DT_VERSION} -f ./srv/data/Dockerfile .`
-const login = `docker login --username ${ORDO_DT_DOCKER_REGISTRY_USERNAME} --password ${ORDO_DT_DOCKER_REGISTRY_PASSWORD} ${ORDO_DT_DOCKER_REGISTRY}`
-const publish = `docker push ${ORDO_DT_DOCKER_REGISTRY}/${ORDO_DT_DOCKER_REGISTRY_SCOPE}/dt:${ORDO_DT_VERSION}`
-
-void run_command(build)
- .chain(() => run_command(login))
- .chain(() => run_command(publish))
- .orElse(die())
diff --git a/srv/data/index.ts b/srv/data/index.ts
deleted file mode 100644
index c845c55a0..000000000
--- a/srv/data/index.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SPDX-FileCopyrightText: Copyright 2024, 谢尔盖 ||↓ and the Ordo.pink contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- *
- * Ordo.pink is an all-in-one team workspace.
- * Copyright (C) 2024 谢尔盖 ||↓ and the Ordo.pink contributors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import chalk from "chalk"
-
-import { ConsoleLogger } from "@ordo-pink/logger"
-import { ContentPersistenceStrategyFS } from "@ordo-pink/backend-persistence-strategy-content-fs"
-import { ContentPersistenceStrategyS3 } from "@ordo-pink/backend-persistence-strategy-content-s3"
-import { DataCommands } from "@ordo-pink/managers"
-import { DataPersistenceStrategyFS } from "@ordo-pink/backend-persistence-strategy-data-fs"
-import { DataPersistenceStrategyS3 } from "@ordo-pink/backend-persistence-strategy-data-s3"
-import { Switch } from "@ordo-pink/switch"
-import { createDataServer } from "@ordo-pink/backend-server-data"
-
-const port = Bun.env.ORDO_DT_PORT!
-const idHost = Bun.env.ORDO_ID_HOST!
-const origin = [Bun.env.ORDO_WORKSPACE_HOST!, Bun.env.ORDO_WEB_HOST!]
-const logger = ConsoleLogger
-const contentPersistenceStrategyType = Bun.env.ORDO_DT_CONTENT_PERSISTENCE_STRATEGY!
-
-const dataPersistenceStrategyType = Bun.env.ORDO_DT_DATA_PERSISTENCE_STRATEGY!
-
-const dataPersistenceStrategyFSParams = {
- root: Bun.env.ORDO_DT_DATA_PATH!,
-}
-
-const dataPersistenceStrategyS3Params = {
- accessKeyId: Bun.env.ORDO_DT_DATA_S3_ACCESS_KEY!,
- secretAccessKey: Bun.env.ORDO_DT_DATA_S3_SECRET_KEY!,
- region: Bun.env.ORDO_DT_DATA_S3_REGION!,
- endpoint: Bun.env.ORDO_DT_DATA_S3_ENDPOINT!,
- bucketName: Bun.env.ORDO_DT_DATA_S3_BUCKET_NAME!,
-}
-
-const contentPersistenceStrategyFSParams = {
- root: Bun.env.ORDO_DT_CONTENT_PATH!,
-}
-
-const contentPersistenceStrategyS3Params = {
- accessKeyId: Bun.env.ORDO_DT_CONTENT_S3_ACCESS_KEY!,
- secretAccessKey: Bun.env.ORDO_DT_CONTENT_S3_SECRET_KEY!,
- region: Bun.env.ORDO_DT_CONTENT_S3_REGION!,
- endpoint: Bun.env.ORDO_DT_CONTENT_S3_ENDPOINT!,
- bucketName: Bun.env.ORDO_DT_CONTENT_S3_BUCKET_NAME!,
-}
-
-const main = () => {
- const dataPersistenceStrategy = Switch.of(dataPersistenceStrategyType)
- .case("s3", () => DataPersistenceStrategyS3.of(dataPersistenceStrategyS3Params))
- .default(() => DataPersistenceStrategyFS.of(dataPersistenceStrategyFSParams))
-
- const contentPersistenceStrategy = Switch.of(contentPersistenceStrategyType)
- .case("s3", () => ContentPersistenceStrategyS3.of(contentPersistenceStrategyS3Params))
- .default(() => ContentPersistenceStrategyFS.of(contentPersistenceStrategyFSParams))
-
- const dataService = DataCommands.of({ dataPersistenceStrategy, contentPersistenceStrategy })
-
- createDataServer({ dataService, idHost, origin, logger }).listen({ port: Number(port) }, () =>
- ConsoleLogger.info(`DT running on http://localhost:${chalk.blue(port)}`),
- )
-}
-
-main()
diff --git a/srv/data/license b/srv/data/license
deleted file mode 100644
index 3a64ee5fe..000000000
--- a/srv/data/license
+++ /dev/null
@@ -1,504 +0,0 @@
- GNU AFFERO GENERAL PUBLIC LICENSE
- Version 3, 19 November 2007
-
-Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy
-and distribute verbatim copies of this license document, but changing it is not allowed.
-
- Preamble
-
-The GNU Affero General Public License is a free, copyleft license for software and other kinds of
-works, specifically designed to ensure cooperation with the community in the case of network server
-software.
-
-The licenses for most software and other practical works are designed to take away your freedom to
-share and change the works. By contrast, our General Public Licenses are intended to guarantee your
-freedom to share and change all versions of a program--to make sure it remains free software for all
-its users.
-
-When we speak of free software, we are referring to freedom, not price. Our General Public Licenses
-are designed to make sure that you have the freedom to distribute copies of free software (and
-charge for them if you wish), that you receive source code or can get it if you want it, that you
-can change the software or use pieces of it in new free programs, and that you know you can do these
-things.
-
-Developers that use our General Public Licenses protect your rights with two steps: (1) assert
-copyright on the software, and (2) offer you this License which gives you legal permission to copy,
-distribute and/or modify the software.
-
-A secondary benefit of defending all users' freedom is that improvements made in alternate versions
-of the program, if they receive widespread use, become available for other developers to
-incorporate. Many developers of free software are heartened and encouraged by the resulting
-cooperation. However, in the case of software used on network servers, this result may fail to come
-about. The GNU General Public License permits making a modified version and letting the public
-access it on a server without ever releasing its source code to the public.
-
-The GNU Affero General Public License is designed specifically to ensure that, in such cases, the
-modified source code becomes available to the community. It requires the operator of a network
-server to provide the source code of the modified version running there to the users of that server.
-Therefore, public use of a modified version, on a publicly accessible server, gives the public
-access to the source code of the modified version.
-
-An older license, called the Affero General Public License and published by Affero, was designed to
-accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero
-has released a new version of the Affero GPL which permits relicensing under this license.
-
-The precise terms and conditions for copying, distribution and modification follow.
-
- TERMS AND CONDITIONS
-
-0. Definitions.
-
-"This License" refers to version 3 of the GNU Affero General Public License.
-
-"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor
-masks.
-
-"The Program" refers to any copyrightable work licensed under this License. Each licensee is
-addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
-
-To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring
-copyright permission, other than the making of an exact copy. The resulting work is called a
-"modified version" of the earlier work or a work "based on" the earlier work.
-
-A "covered work" means either the unmodified Program or a work based on the Program.
-
-To "propagate" a work means to do anything with it that, without permission, would make you directly
-or secondarily liable for infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying, distribution (with or without
-modification), making available to the public, and in some countries other activities as well.
-
-To "convey" a work means any kind of propagation that enables other parties to make or receive
-copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not
-conveying.
-
-An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a
-convenient and prominently visible feature that (1) displays an appropriate copyright notice, and
-(2) tells the user that there is no warranty for the work (except to the extent that warranties are
-provided), that licensees may convey the work under this License, and how to view a copy of this
-License. If the interface presents a list of user commands or options, such as a menu, a prominent
-item in the list meets this criterion.
-
-1. Source Code.
-
-The "source code" for a work means the preferred form of the work for making modifications to it.
-"Object code" means any non-source form of a work.
-
-A "Standard Interface" means an interface that either is an official standard defined by a
-recognized standards body, or, in the case of interfaces specified for a particular programming
-language, one that is widely used among developers working in that language.
-
-The "System Libraries" of an executable work include anything, other than the work as a whole, that
-(a) is included in the normal form of packaging a Major Component, but which is not part of that
-Major Component, and (b) serves only to enable use of the work with that Major Component, or to
-implement a Standard Interface for which an implementation is available to the public in source code
-form. A "Major Component", in this context, means a major essential component (kernel, window
-system, and so on) of the specific operating system (if any) on which the executable work runs, or a
-compiler used to produce the work, or an object code interpreter used to run it.
-
-The "Corresponding Source" for a work in object code form means all the source code needed to
-generate, install, and (for an executable work) run the object code and to modify the work,
-including scripts to control those activities. However, it does not include the work's System
-Libraries, or general-purpose tools or generally available free programs which are used unmodified
-in performing those activities but which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for the work, and the source code
-for shared libraries and dynamically linked subprograms that the work is specifically designed to
-require, such as by intimate data communication or control flow between those subprograms and other
-parts of the work.
-
-The Corresponding Source need not include anything that users can regenerate automatically from
-other parts of the Corresponding Source.
-
-The Corresponding Source for a work in source code form is that same work.
-
-2. Basic Permissions.
-
-All rights granted under this License are granted for the term of copyright on the Program, and are
-irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a covered work is covered by this
-License only if the output, given its content, constitutes a covered work. This License acknowledges
-your rights of fair use or other equivalent, as provided by copyright law.
-
-You may make, run and propagate covered works that you do not convey, without conditions so long as
-your license otherwise remains in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you with facilities for running
-those works, provided that you comply with the terms of this License in conveying all material for
-which you do not control copyright. Those thus making or running the covered works for you must do
-so exclusively on your behalf, under your direction and control, on terms that prohibit them from
-making any copies of your copyrighted material outside their relationship with you.
-
-Conveying under any other circumstances is permitted solely under the conditions stated below.
-Sublicensing is not allowed; section 10 makes it unnecessary.
-
-3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-No covered work shall be deemed part of an effective technological measure under any applicable law
-fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such measures.
-
-When you convey a covered work, you waive any legal power to forbid circumvention of technological
-measures to the extent such circumvention is effected by exercising rights under this License with
-respect to the covered work, and you disclaim any intention to limit operation or modification of
-the work as a means of enforcing, against the work's users, your or third parties' legal rights to
-forbid circumvention of technological measures.
-
-4. Conveying Verbatim Copies.
-
-You may convey verbatim copies of the Program's source code as you receive it, in any medium,
-provided that you conspicuously and appropriately publish on each copy an appropriate copyright
-notice; keep intact all notices stating that this License and any non-permissive terms added in
-accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and
-give all recipients a copy of this License along with the Program.
-
-You may charge any price or no price for each copy that you convey, and you may offer support or
-warranty protection for a fee.
-
-5. Conveying Modified Source Versions.
-
-You may convey a work based on the Program, or the modifications to produce it from the Program, in
-the form of source code under the terms of section 4, provided that you also meet all of these
-conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
-A compilation of a covered work with other separate and independent works, which are not by their
-nature extensions of the covered work, and which are not combined with it such as to form a larger
-program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the
-compilation and its resulting copyright are not used to limit the access or legal rights of the
-compilation's users beyond what the individual works permit. Inclusion of a covered work in an
-aggregate does not cause this License to apply to the other parts of the aggregate.
-
-6. Conveying Non-Source Forms.
-
-You may convey a covered work in object code form under the terms of sections 4 and 5, provided that
-you also convey the machine-readable Corresponding Source under the terms of this License, in one of
-these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
-A separable portion of the object code, whose source code is excluded from the Corresponding Source
-as a System Library, need not be included in conveying the object code work.
-
-A "User Product" is either (1) a "consumer product", which means any tangible personal property
-which is normally used for personal, family, or household purposes, or (2) anything designed or sold
-for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful
-cases shall be resolved in favor of coverage. For a particular product received by a particular
-user, "normally used" refers to a typical or common use of that class of product, regardless of the
-status of the particular user or of the way in which the particular user actually uses, or expects
-or is expected to use, the product. A product is a consumer product regardless of whether the
-product has substantial commercial, industrial or non-consumer uses, unless such uses represent the
-only significant mode of use of the product.
-
-"Installation Information" for a User Product means any methods, procedures, authorization keys, or
-other information required to install and execute modified versions of a covered work in that User
-Product from a modified version of its Corresponding Source. The information must suffice to ensure
-that the continued functioning of the modified object code is in no case prevented or interfered
-with solely because modification has been made.
-
-If you convey an object code work under this section in, or with, or specifically for use in, a User
-Product, and the conveying occurs as part of a transaction in which the right of possession and use
-of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of
-how the transaction is characterized), the Corresponding Source conveyed under this section must be
-accompanied by the Installation Information. But this requirement does not apply if neither you nor
-any third party retains the ability to install modified object code on the User Product (for
-example, the work has been installed in ROM).
-
-The requirement to provide Installation Information does not include a requirement to continue to
-provide support service, warranty, or updates for a work that has been modified or installed by the
-recipient, or for the User Product in which it has been modified or installed. Access to a network
-may be denied when the modification itself materially and adversely affects the operation of the
-network or violates the rules and protocols for communication across the network.
-
-Corresponding Source conveyed, and Installation Information provided, in accord with this section
-must be in a format that is publicly documented (and with an implementation available to the public
-in source code form), and must require no special password or key for unpacking, reading or copying.
-
-7. Additional Terms.
-
-"Additional permissions" are terms that supplement the terms of this License by making exceptions
-from one or more of its conditions. Additional permissions that are applicable to the entire Program
-shall be treated as though they were included in this License, to the extent that they are valid
-under applicable law. If additional permissions apply only to part of the Program, that part may be
-used separately under those permissions, but the entire Program remains governed by this License
-without regard to the additional permissions.
-
-When you convey a copy of a covered work, you may at your option remove any additional permissions
-from that copy, or from any part of it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place additional permissions on
-material, added by you to a covered work, for which you have or can give appropriate copyright
-permission.
-
-Notwithstanding any other provision of this License, for material you add to a covered work, you may
-(if authorized by the copyright holders of that material) supplement the terms of this License with
-terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
-All other non-permissive additional terms are considered "further restrictions" within the meaning
-of section 10. If the Program as you received it, or any part of it, contains a notice stating that
-it is governed by this License along with a term that is a further restriction, you may remove that
-term. If a license document contains a further restriction but permits relicensing or conveying
-under this License, you may add to a covered work material governed by the terms of that license
-document, provided that the further restriction does not survive such relicensing or conveying.
-
-If you add terms to a covered work in accord with this section, you must place, in the relevant
-source files, a statement of the additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
-Additional terms, permissive or non-permissive, may be stated in the form of a separately written
-license, or stated as exceptions; the above requirements apply either way.
-
-8. Termination.
-
-You may not propagate or modify a covered work except as expressly provided under this License. Any
-attempt otherwise to propagate or modify it is void, and will automatically terminate your rights
-under this License (including any patent licenses granted under the third paragraph of section 11).
-
-However, if you cease all violation of this License, then your license from a particular copyright
-holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally
-terminates your license, and (b) permanently, if the copyright holder fails to notify you of the
-violation by some reasonable means prior to 60 days after the cessation.
-
-Moreover, your license from a particular copyright holder is reinstated permanently if the copyright
-holder notifies you of the violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that copyright holder, and you cure
-the violation prior to 30 days after your receipt of the notice.
-
-Termination of your rights under this section does not terminate the licenses of parties who have
-received copies or rights from you under this License. If your rights have been terminated and not
-permanently reinstated, you do not qualify to receive new licenses for the same material under
-section 10.
-
-9. Acceptance Not Required for Having Copies.
-
-You are not required to accept this License in order to receive or run a copy of the Program.
-Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer
-transmission to receive a copy likewise does not require acceptance. However, nothing other than
-this License grants you permission to propagate or modify any covered work. These actions infringe
-copyright if you do not accept this License. Therefore, by modifying or propagating a covered work,
-you indicate your acceptance of this License to do so.
-
-10. Automatic Licensing of Downstream Recipients.
-
-Each time you convey a covered work, the recipient automatically receives a license from the
-original licensors, to run, modify and propagate that work, subject to this License. You are not
-responsible for enforcing compliance by third parties with this License.
-
-An "entity transaction" is a transaction transferring control of an organization, or substantially
-all assets of one, or subdividing an organization, or merging organizations. If propagation of a
-covered work results from an entity transaction, each party to that transaction who receives a copy
-of the work also receives whatever licenses to the work the party's predecessor in interest had or
-could give under the previous paragraph, plus a right to possession of the Corresponding Source of
-the work from the predecessor in interest, if the predecessor has it or can get it with reasonable
-efforts.
-
-You may not impose any further restrictions on the exercise of the rights granted or affirmed under
-this License. For example, you may not impose a license fee, royalty, or other charge for exercise
-of rights granted under this License, and you may not initiate litigation (including a cross-claim
-or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling,
-offering for sale, or importing the Program or any portion of it.
-
-11. Patents.
-
-A "contributor" is a copyright holder who authorizes use under this License of the Program or a work
-on which the Program is based. The work thus licensed is called the contributor's "contributor
-version".
-
-A contributor's "essential patent claims" are all patent claims owned or controlled by the
-contributor, whether already acquired or hereafter acquired, that would be infringed by some manner,
-permitted by this License, of making, using, or selling its contributor version, but do not include
-claims that would be infringed only as a consequence of further modification of the contributor
-version. For purposes of this definition, "control" includes the right to grant patent sublicenses
-in a manner consistent with the requirements of this License.
-
-Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the
-contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run,
-modify and propagate the contents of its contributor version.
-
-In the following three paragraphs, a "patent license" is any express agreement or commitment,
-however denominated, not to enforce a patent (such as an express permission to practice a patent or
-covenant not to sue for patent infringement). To "grant" such a patent license to a party means to
-make such an agreement or commitment not to enforce a patent against the party.
-
-If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of
-the work is not available for anyone to copy, free of charge and under the terms of this License,
-through a publicly available network server or other readily accessible means, then you must either
-(1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the
-benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with
-the requirements of this License, to extend the patent license to downstream recipients. "Knowingly
-relying" means you have actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work in a country, would infringe
-one or more identifiable patents in that country that you have reason to believe are valid.
-
-If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate
-by procuring conveyance of, a covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of
-the covered work, then the patent license you grant is automatically extended to all recipients of
-the covered work and works based on it.
-
-A patent license is "discriminatory" if it does not include within the scope of its coverage,
-prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that
-are specifically granted under this License. You may not convey a covered work if you are a party to
-an arrangement with a third party that is in the business of distributing software, under which you
-make payment to the third party based on the extent of your activity of conveying the work, and
-under which the third party grants, to any of the parties who would receive the covered work from
-you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by
-you (or copies made from those copies), or (b) primarily for and in connection with specific
-products or compilations that contain the covered work, unless you entered into that arrangement, or
-that patent license was granted, prior to 28 March 2007.
-
-Nothing in this License shall be construed as excluding or limiting any implied license or other
-defenses to infringement that may otherwise be available to you under applicable patent law.
-
-12. No Surrender of Others' Freedom.
-
-If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict
-the conditions of this License, they do not excuse you from the conditions of this License. If you
-cannot convey a covered work so as to satisfy simultaneously your obligations under this License and
-any other pertinent obligations, then as a consequence you may not convey it at all. For example, if
-you agree to terms that obligate you to collect a royalty for further conveying from those to whom
-you convey the Program, the only way you could satisfy both those terms and this License would be to
-refrain entirely from conveying the Program.
-
-13. Remote Network Interaction; Use with the GNU General Public License.
-
-Notwithstanding any other provision of this License, if you modify the Program, your modified
-version must prominently offer all users interacting with it remotely through a computer network (if
-your version supports such interaction) an opportunity to receive the Corresponding Source of your
-version by providing access to the Corresponding Source from a network server at no charge, through
-some standard or customary means of facilitating copying of software. This Corresponding Source
-shall include the Corresponding Source for any work covered by version 3 of the GNU General Public
-License that is incorporated pursuant to the following paragraph.
-
-Notwithstanding any other provision of this License, you have permission to link or combine any
-covered work with a work licensed under version 3 of the GNU General Public License into a single
-combined work, and to convey the resulting work. The terms of this License will continue to apply to
-the part which is the covered work, but the work with which it is combined will remain governed by
-version 3 of the GNU General Public License.
-
-14. Revised Versions of this License.
-
-The Free Software Foundation may publish revised and/or new versions of the GNU Affero General
-Public License from time to time. Such new versions will be similar in spirit to the present
-version, but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program specifies that a certain
-numbered version of the GNU Affero General Public License "or any later version" applies to it, you
-have the option of following the terms and conditions either of that numbered version or of any
-later version published by the Free Software Foundation. If the Program does not specify a version
-number of the GNU Affero General Public License, you may choose any version ever published by the
-Free Software Foundation.
-
-If the Program specifies that a proxy can decide which future versions of the GNU Affero General
-Public License can be used, that proxy's public statement of acceptance of a version permanently
-authorizes you to choose that version for the Program.
-
-Later license versions may give you additional or different permissions. However, no additional
-obligations are imposed on any author or copyright holder as a result of your choosing to follow a
-later version.
-
-15. Disclaimer of Warranty.
-
-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO
-THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU
-ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-16. Limitation of Liability.
-
-IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
-ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
-DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE
-OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
-INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH
-ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
-17. Interpretation of Sections 15 and 16.
-
-If the disclaimer of warranty and limitation of liability provided above cannot be given local legal
-effect according to their terms, reviewing courts shall apply local law that most closely
-approximates an absolute waiver of all civil liability in connection with the Program, unless a
-warranty or assumption of liability accompanies a copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
diff --git a/srv/data/readme.md b/srv/data/readme.md
deleted file mode 100644
index 599c41b4d..000000000
--- a/srv/data/readme.md
+++ /dev/null
@@ -1 +0,0 @@
-# Data
diff --git a/srv/data/bin/run.ts b/srv/dt/bin/run.ts
similarity index 94%
rename from srv/data/bin/run.ts
rename to srv/dt/bin/run.ts
index bc6e9efe3..9d8972e33 100644
--- a/srv/data/bin/run.ts
+++ b/srv/dt/bin/run.ts
@@ -22,7 +22,7 @@
import { die, run_async_command } from "@ordo-pink/binutil"
import { invokers0 } from "@ordo-pink/oath"
-void run_async_command("opt/bun run --watch srv/data/index.ts", {
+void run_async_command("opt/bun run --watch srv/dt/index.ts", {
stdout: "pipe",
stderr: "pipe",
env: { ...process.env, FORCE_COLOR: "1" },
diff --git a/srv/dt/index.ts b/srv/dt/index.ts
new file mode 100644
index 000000000..81c4432be
--- /dev/null
+++ b/srv/dt/index.ts
@@ -0,0 +1,82 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2024, 谢尔盖 ||↓ and the Ordo.pink contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ *
+ * Ordo.pink is an all-in-one team workspace.
+ * Copyright (C) 2024 谢尔盖 ||↓ and the Ordo.pink contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { ConsoleLogger, type TLogger } from "@ordo-pink/logger"
+import { Oath, invokers0, ops0 } from "@ordo-pink/oath"
+import { type TDTChamber, create_backend_dt } from "@ordo-pink/backend-dt"
+import { PersistenceStrategyDataFS } from "@ordo-pink/backend-persistence-strategy-data-fs"
+import { is_port } from "@ordo-pink/tau"
+
+const env_rrr = (env_var: string) => (value?: any) =>
+ value != null ? `Invalid value for ${env_var}: "${value}"` : `Missing value for ${env_var}`
+
+const get_env = () =>
+ Oath.Merge({
+ port: Oath.FromNullable(Bun.env.ORDO_DT_PORT)
+ .and(n => Oath.If(is_port(n), { T: () => n }))
+ .pipe(ops0.rejected_map(env_rrr("ORDO_DT_PORT"))),
+
+ allow_origin: Oath.FromNullable(Bun.env.ORDO_DT_ALLOW_ORIGIN)
+ .and(s => s.split(", "))
+ .pipe(ops0.rejected_map(env_rrr("ORDO_DT_ALLOW_ORIGIN"))),
+
+ data_path: Oath.FromNullable(Bun.env.ORDO_DT_DATA_PATH, env_rrr("ORDO_DT_DATA_PATH")),
+
+ id_host: Oath.FromNullable(Bun.env.ORDO_ID_HOST, env_rrr("ORDO_ID_HOST")),
+
+ dt_host: Oath.FromNullable(Bun.env.ORDO_DT_HOST, env_rrr("ORDO_DT_HOST")),
+ })
+
+const main = () =>
+ get_env()
+ .and(({ allow_origin, port, data_path, id_host, dt_host }) =>
+ Oath.Merge({
+ allow_origin,
+ logger,
+ data_persistence_strategy: PersistenceStrategyDataFS.Of(data_path),
+ id_host,
+ dt_host,
+ } satisfies TDTChamber)
+ .and(create_backend_dt)
+ .and(fetch => Bun.serve({ fetch, port })),
+ )
+ .pipe(ops0.tap(server => logger.info(`server running on http://${server.hostname}:${server.port}`)))
+ .invoke(
+ invokers0.or_else(e => {
+ logger.panic(e)
+ process.exit(1)
+ }),
+ )
+
+void main()
+
+// --- Internal ---
+
+const logger: TLogger = {
+ alert: (...message) => ConsoleLogger.alert("[DT]", ...message),
+ crit: (...message) => ConsoleLogger.crit("[DT]", ...message),
+ debug: (...message) => ConsoleLogger.debug("[DT]", ...message),
+ error: (...message) => ConsoleLogger.error("[DT]", ...message),
+ info: (...message) => ConsoleLogger.info("[DT]", ...message),
+ notice: (...message) => ConsoleLogger.notice("[DT]", ...message),
+ panic: (...message) => ConsoleLogger.panic("[DT]", ...message),
+ warn: (...message) => ConsoleLogger.warn("[DT]", ...message),
+}
diff --git a/lib/backend-email-strategy-rusender/license b/srv/dt/license
similarity index 100%
rename from lib/backend-email-strategy-rusender/license
rename to srv/dt/license
diff --git a/srv/dt/readme.md b/srv/dt/readme.md
new file mode 100644
index 000000000..990436c5c
--- /dev/null
+++ b/srv/dt/readme.md
@@ -0,0 +1,3 @@
+# DT
+
+This is a data service instance used for local development.
diff --git a/srv/id/index.ts b/srv/id/index.ts
index 4d9f49c9b..d369c2dfb 100644
--- a/srv/id/index.ts
+++ b/srv/id/index.ts
@@ -88,6 +88,8 @@ const get_env = () =>
.pipe(ops0.rejected_map(env_rrr("ORDO_ID_PERSISTED_TOKEN_LIFETIME"))),
user_db_path: Oath.FromNullable(Bun.env.ORDO_ID_USER_DB_PATH, env_rrr("ORDO_ID_USER_DB_PATH")),
+ web_host: Oath.FromNullable(Bun.env.ORDO_WEB_HOST, env_rrr("ORDO_WEB_HOST")),
+ dt_host: Oath.FromNullable(Bun.env.ORDO_DT_HOST, env_rrr("ORDO_DT_HOST")),
token_db_path: Oath.FromNullable(Bun.env.ORDO_ID_TOKEN_DB_PATH, env_rrr("ORDO_ID_TOKEN_DB_PATH")),
})
@@ -108,6 +110,7 @@ const main = () =>
token_db_path,
token_lifetime,
user_db_path,
+ web_host,
}) =>
Oath.Merge({
allow_origin,
@@ -118,8 +121,7 @@ const main = () =>
token_persistence_strategy: PersistenceStrategyTokenFS.Of(token_db_path), // TODO
user_persistence_strategy: PersistenceStategyUserFS.Of(user_db_path),
wjwt: WJWT({ aud, alg, private_key, public_key, iss, token_lifetime }),
- status: 200,
- headers: {},
+ web_host,
} satisfies TIDChamber)
.and(create_backend_id)
.and(fetch => Bun.serve({ fetch, port })),
diff --git a/lib/backend-persistence-strategy-content-fs/src/backend-persistence-strategy-content-fs.types.ts b/srv/pb/bin/run.ts
similarity index 76%
rename from lib/backend-persistence-strategy-content-fs/src/backend-persistence-strategy-content-fs.types.ts
rename to srv/pb/bin/run.ts
index f66df0310..f4db07ed7 100644
--- a/lib/backend-persistence-strategy-content-fs/src/backend-persistence-strategy-content-fs.types.ts
+++ b/srv/pb/bin/run.ts
@@ -19,4 +19,11 @@
* along with this program. If not, see .
*/
-export type TPersistenceStrategyContentFSParams = { root: string }
+import { die, run_async_command } from "@ordo-pink/binutil"
+import { invokers0 } from "@ordo-pink/oath"
+
+void run_async_command("opt/bun run --watch srv/pb/index.ts", {
+ stdout: "pipe",
+ stderr: "pipe",
+ env: { ...process.env, FORCE_COLOR: "1" },
+}).invoke(invokers0.or_else(die()))
diff --git a/srv/pb/index.ts b/srv/pb/index.ts
new file mode 100644
index 000000000..d976af68b
--- /dev/null
+++ b/srv/pb/index.ts
@@ -0,0 +1,72 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2024, 谢尔盖 ||↓ and the Ordo.pink contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ *
+ * Ordo.pink is an all-in-one team workspace.
+ * Copyright (C) 2024 谢尔盖 ||↓ and the Ordo.pink contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { ConsoleLogger, type TLogger } from "@ordo-pink/logger"
+import { Oath, invokers0, ops0 } from "@ordo-pink/oath"
+import { PersistenceStrategyDataFS } from "@ordo-pink/backend-persistence-strategy-data-fs"
+import { create_backend_pb } from "@ordo-pink/backend-pb"
+import { is_port } from "@ordo-pink/tau"
+
+const env_rrr = (env_var: string) => (value?: any) =>
+ value != null ? `Invalid value for ${env_var}: "${value}"` : `Missing value for ${env_var}`
+
+const get_env = () =>
+ Oath.Merge({
+ port: Oath.FromNullable(Bun.env.ORDO_PB_PORT)
+ .and(n => Oath.If(is_port(n), { T: () => n }))
+ .pipe(ops0.rejected_map(env_rrr("ORDO_PB_PORT"))),
+
+ data_path: Oath.FromNullable(Bun.env.ORDO_PB_DATA_PATH, env_rrr("ORDO_PB_DATA_PATH")),
+
+ allow_origin: Oath.FromNullable(Bun.env.ORDO_DT_ALLOW_ORIGIN)
+ .and(s => s.split(", "))
+ .pipe(ops0.rejected_map(env_rrr("ORDO_DT_ALLOW_ORIGIN"))),
+ })
+
+const main = () =>
+ get_env()
+ .and(({ port, data_path, allow_origin }) =>
+ Oath.Merge({ logger, data_persistence_strategy: PersistenceStrategyDataFS.Of(data_path), allow_origin })
+ .and(create_backend_pb)
+ .and(fetch => Bun.serve({ fetch, port })),
+ )
+ .pipe(ops0.tap(server => logger.info(`server running on http://${server.hostname}:${server.port}`)))
+ .invoke(
+ invokers0.or_else(e => {
+ logger.panic(e)
+ process.exit(1)
+ }),
+ )
+
+void main()
+
+// --- Internal ---
+
+const logger: TLogger = {
+ alert: (...message) => ConsoleLogger.alert("[PB]", ...message),
+ crit: (...message) => ConsoleLogger.crit("[PB]", ...message),
+ debug: (...message) => ConsoleLogger.debug("[PB]", ...message),
+ error: (...message) => ConsoleLogger.error("[PB]", ...message),
+ info: (...message) => ConsoleLogger.info("[PB]", ...message),
+ notice: (...message) => ConsoleLogger.notice("[PB]", ...message),
+ panic: (...message) => ConsoleLogger.panic("[PB]", ...message),
+ warn: (...message) => ConsoleLogger.warn("[PB]", ...message),
+}
diff --git a/lib/backend-persistence-strategy-content-fs/license b/srv/pb/license
similarity index 100%
rename from lib/backend-persistence-strategy-content-fs/license
rename to srv/pb/license
diff --git a/srv/pb/readme.md b/srv/pb/readme.md
new file mode 100644
index 000000000..990436c5c
--- /dev/null
+++ b/srv/pb/readme.md
@@ -0,0 +1,3 @@
+# DT
+
+This is a data service instance used for local development.
diff --git a/srv/web/bin/run.ts b/srv/web/bin/run.ts
index e9af471aa..2eb5e6f0d 100644
--- a/srv/web/bin/run.ts
+++ b/srv/web/bin/run.ts
@@ -23,13 +23,7 @@ import { die, run_command } from "@ordo-pink/binutil"
import { getc } from "@ordo-pink/getc"
import { invokers0 } from "@ordo-pink/oath"
-const { ORDO_STATIC_HOST, ORDO_ID_HOST, ORDO_WEB_HOST, ORDO_DT_HOST, ORDO_WORKSPACE_HOST } = getc([
- "ORDO_STATIC_HOST",
- "ORDO_ID_HOST",
- "ORDO_WEB_HOST",
- "ORDO_DT_HOST",
- "ORDO_WORKSPACE_HOST",
-])
+const { ORDO_ID_HOST, ORDO_DT_HOST, ORDO_PB_HOST } = getc(["ORDO_ID_HOST", "ORDO_DT_HOST", "ORDO_PB_HOST"])
void run_command("npm run dev", {
cwd: "./srv/web",
@@ -37,11 +31,9 @@ void run_command("npm run dev", {
stdout: "inherit",
env: {
...process.env,
- VITE_ORDO_STATIC_HOST: ORDO_STATIC_HOST,
VITE_ORDO_ID_HOST: ORDO_ID_HOST,
- VITE_ORDO_WEBSITE_HOST: ORDO_WEB_HOST,
+ VITE_ORDO_PB_HOST: ORDO_PB_HOST,
VITE_ORDO_DT_HOST: ORDO_DT_HOST,
- VITE_ORDO_WORKSPACE_HOST: ORDO_WORKSPACE_HOST,
FORCE_COLOR: "1",
},
}).invoke(invokers0.or_else(die()))
diff --git a/srv/web/src/index.ts b/srv/web/src/index.ts
index 431308a03..1c53d43da 100644
--- a/srv/web/src/index.ts
+++ b/srv/web/src/index.ts
@@ -24,4 +24,8 @@ import { Maoka } from "@ordo-pink/maoka"
const app = document.getElementById("app")!
-void Maoka.dom(app, App)
+const id_host = import.meta.env.VITE_ORDO_ID_HOST
+const dt_host = import.meta.env.VITE_ORDO_DT_HOST
+const pb_host = import.meta.env.VITE_ORDO_PB_HOST
+
+void Maoka.dom(app, App({ id_host, dt_host, pb_host }))
diff --git a/srv/web/src/vite-env.d.ts b/srv/web/src/vite-env.d.ts
index e20eb5751..e921669d8 100644
--- a/srv/web/src/vite-env.d.ts
+++ b/srv/web/src/vite-env.d.ts
@@ -35,5 +35,5 @@ interface ImportMetaEnv {
/**
* Function Store server host.
*/
- readonly VITE_ORDO_FS_HOST: string
+ readonly VITE_ORDO_PB_HOST: string
}
diff --git a/srv/web/vite.config.ts b/srv/web/vite.config.ts
index b666f2aea..53ed42452 100644
--- a/srv/web/vite.config.ts
+++ b/srv/web/vite.config.ts
@@ -28,7 +28,9 @@ import tsconfigPaths from "vite-tsconfig-paths"
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
+ // @ts-ignore
tsconfigPaths(),
+ // @ts-ignore
ViteImageOptimizer({
png: { quality: 80 },
jpeg: { quality: 75 },