@wenathlan/cobaia 0.0.0-stage → 2.0.158
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/App.tsx +52 -0
- package/Dockerfile +48 -0
- package/_headers +4 -0
- package/_redirects +1 -0
- package/adsconfig.ts +59 -0
- package/biome.jsonc +134 -0
- package/bun.lock +2451 -0
- package/capacitor.config.ts +51 -0
- package/checkoutlinks.ts +80 -0
- package/cli.ts +114 -0
- package/cobaia.csproj +22 -0
- package/cobaia.gemspec +14 -0
- package/cobaia.java +16 -0
- package/content.ts +425 -0
- package/db.ts +219 -0
- package/devthink.toml +5 -0
- package/docs/features.md +58 -0
- package/docs/monetization.md +61 -0
- package/familyurl.ts +22 -0
- package/favicon.svg +1 -0
- package/icon.svg +1 -0
- package/index.html +26 -0
- package/labels.ts +291 -0
- package/manifest.webmanifest +56 -0
- package/mime.types +12 -0
- package/netlify.toml +2 -0
- package/package.json +207 -4
- package/pnpm-workspace.yaml +101 -0
- package/pnpmboot.package-lock.json +157 -0
- package/pnpmboot.package.json +6 -0
- package/pom.xml +29 -0
- package/posts.ts +54 -0
- package/robots.txt +90 -0
- package/roster.ts +29 -0
- package/sandboxmodality.ts +138 -0
- package/schema.prisma +31 -0
- package/sitemap.xml +42 -0
- package/sol/Sol.tsx +91 -0
- package/sol/apps/apps.tsx +66 -0
- package/sol/blog/blog.tsx +86 -0
- package/sol/home/home.tsx +140 -0
- package/sol/intro/intro.tsx +187 -0
- package/sol/legal/legal.tsx +76 -0
- package/sol/notfound/notfound.tsx +32 -0
- package/sol/pricing/pricing.tsx +98 -0
- package/sol/shell/Shell.tsx +161 -0
- package/sol/sol.css +1951 -0
- package/sol/support/support.tsx +102 -0
- package/sol/wingets/IntroFooter.tsx +69 -0
- package/sol/wingets/IntroPlans.tsx +93 -0
- package/sol/wingets/IntroSplash.tsx +105 -0
- package/sol/wingets/ShellAdsslot.tsx +47 -0
- package/sol/wingets/ShellBrand.tsx +86 -0
- package/sol/wingets/index.ts +18 -0
- package/tests/adsconfig.test.ts +51 -0
- package/tests/checkoutlinks.test.ts +73 -0
- package/tests/familyurl.test.ts +40 -0
- package/tests/posts.test.ts +76 -0
- package/tests/sandboxmodality.test.ts +77 -0
- package/tsconfig.json +22 -0
- package/tsconfig.node.json +22 -0
- package/vercel.json +3 -0
- package/vite.config.ts +44 -0
- package/vitest.config.ts +42 -0
- package/wrangler.toml +7 -0
- package/README.md +0 -3
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* the one conversion config of the app, living at the app root so the
|
|
3
|
+
* capacitor cli resolves it from its working directory: the mobile lane runs
|
|
4
|
+
* `npx cap add`/`npx cap sync` from the app root and every path below — webDir
|
|
5
|
+
* above all — resolves relative to that cwd.
|
|
6
|
+
*
|
|
7
|
+
* the theme build (hashed bundles emitted by vite straight into the app root,
|
|
8
|
+
* publish = ".") is the single application
|
|
9
|
+
* source of every platform: the browser, github pages, vercel, netlify, the tv
|
|
10
|
+
* and the android wrapper all render the same web bundle. the native shells
|
|
11
|
+
* stay runner-side toolchain output (generated on the mobile workflow into
|
|
12
|
+
* android/ and ios/, never committed).
|
|
13
|
+
*
|
|
14
|
+
* the shape follows the capacitor-cli config contract; the type import stays
|
|
15
|
+
* out so the web typecheck never requires the optional capacitor toolchain.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** the structural contract of the capacitor config the cli reads (the subset this repository declares). */
|
|
19
|
+
type CapacitorConfigShape = {
|
|
20
|
+
appId: string;
|
|
21
|
+
appName: string;
|
|
22
|
+
webDir: string;
|
|
23
|
+
bundledWebRuntime?: boolean;
|
|
24
|
+
server?: { androidScheme?: string };
|
|
25
|
+
android?: { allowMixedContent?: boolean; path?: string };
|
|
26
|
+
ios?: { path?: string };
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const config: CapacitorConfigShape = {
|
|
30
|
+
/** the cobaia mobile identity — the id the mobile lane stamps onto the generated shells. */
|
|
31
|
+
appId: "im.cobaia.app",
|
|
32
|
+
appName: "Cobaia",
|
|
33
|
+
/** the vite build of the theme: pnpm build emits the hashed bundles at the app root. */
|
|
34
|
+
webDir: ".",
|
|
35
|
+
bundledWebRuntime: false,
|
|
36
|
+
server: {
|
|
37
|
+
androidScheme: "https",
|
|
38
|
+
},
|
|
39
|
+
/** the build paths the mobile lane answers: the android wrapper and the ios
|
|
40
|
+
* shell materialize beside this config (family-mobile.yml) and the cli
|
|
41
|
+
* reads them from these declared folders. */
|
|
42
|
+
android: {
|
|
43
|
+
allowMixedContent: false,
|
|
44
|
+
path: "android",
|
|
45
|
+
},
|
|
46
|
+
ios: {
|
|
47
|
+
path: "ios",
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default config;
|
package/checkoutlinks.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* checkoutlinks.ts — the typed accessor of the billing configuration of
|
|
3
|
+
* the family site: the thin door the pricing page, the support page and
|
|
4
|
+
* the intro plans zone import, answering the plan table and the support
|
|
5
|
+
* channels of the content lane (content.ts — the manifest; db.ts — the
|
|
6
|
+
* content_rows table; the platform gateway — GET /api/v1/ui/content). The
|
|
7
|
+
* data never lives here anymore: checkoutlinks() and supportlinks() answer
|
|
8
|
+
* the live rows the platform served, the manifest seed otherwise (the
|
|
9
|
+
* uistore chain). The payment links themselves are configuration, never
|
|
10
|
+
* code: the owner pins the checkout hrefs (Stripe Payment Links or Paddle
|
|
11
|
+
* overlays) into the store once billing goes live. Until then every href
|
|
12
|
+
* ships empty and the interface renders the honest empty state — "checkout
|
|
13
|
+
* not configured yet" — instead of pretending.
|
|
14
|
+
*
|
|
15
|
+
* The words never ride here: every plan sentence (name, billing period,
|
|
16
|
+
* blurb, features) answers from the label store (labels.ts — the manifest
|
|
17
|
+
* the seed carries into the site database), so the pricing cards and the
|
|
18
|
+
* intro plans zone read their prose through the typed accessor and this
|
|
19
|
+
* lane keeps only the billing values — ids, prices and links.
|
|
20
|
+
*
|
|
21
|
+
* No network call ever happens here: the links are plain hrefs the visitor
|
|
22
|
+
* chooses to follow, no key is committed (not even a placeholder that looks
|
|
23
|
+
* real) and no script is loaded. The prices are placeholders (US$0 / 5 / 19
|
|
24
|
+
* per month) until the billing platform decision lands.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import {
|
|
28
|
+
type checkoutplan,
|
|
29
|
+
contenttable,
|
|
30
|
+
contentvalue,
|
|
31
|
+
seedPlans,
|
|
32
|
+
seedSupportLinks,
|
|
33
|
+
type supportlinks as supportlinkstable,
|
|
34
|
+
} from "./content.ts";
|
|
35
|
+
|
|
36
|
+
export type { checkoutplan, supportlinkstable as supportlinks };
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The typed accessor of the pricing table: the live db rows when the
|
|
40
|
+
* platform answered, the manifest seed otherwise — in display order (the
|
|
41
|
+
* prose answers from the label store; only the billing values ride this
|
|
42
|
+
* lane).
|
|
43
|
+
*
|
|
44
|
+
* @returns the plans of the /pricing page.
|
|
45
|
+
*/
|
|
46
|
+
export function checkoutlinks(): readonly checkoutplan[] {
|
|
47
|
+
return contenttable("plans", seedPlans);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The typed accessor of the support channels: the live db row when the
|
|
52
|
+
* platform answered, the manifest seed otherwise — the same rule as the
|
|
53
|
+
* plans: hrefs stay empty until the owner configures them.
|
|
54
|
+
*
|
|
55
|
+
* @returns the support channels of the /support page.
|
|
56
|
+
*/
|
|
57
|
+
export function supportlinks(): Readonly<supportlinkstable> {
|
|
58
|
+
return contentvalue("supportlinks", seedSupportLinks);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Answers whether a configured link is live. An empty (or whitespace) href
|
|
63
|
+
* means the feature is not configured yet and the interface must say so.
|
|
64
|
+
*
|
|
65
|
+
* @param href the configured link href.
|
|
66
|
+
* @returns true only when the href carries a real target.
|
|
67
|
+
*/
|
|
68
|
+
export function isconfigured(href: string): boolean {
|
|
69
|
+
return href.trim().length > 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Finds one plan of the table by its stable id.
|
|
74
|
+
*
|
|
75
|
+
* @param id the plan id (free, pro, studio).
|
|
76
|
+
* @returns the plan, or undefined when no plan carries the id.
|
|
77
|
+
*/
|
|
78
|
+
export function planbyid(id: string): checkoutplan | undefined {
|
|
79
|
+
return checkoutlinks().find((plan) => plan.id === id);
|
|
80
|
+
}
|
package/cli.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @file cli.ts — the cobaia binary seat of the clibin wave (PR13 — CLI
|
|
4
|
+
* binário mesmo design): the same Windows 11 chat console as the web and
|
|
5
|
+
* desktop surfaces, rendered inside the terminal as a subapp — the only
|
|
6
|
+
* difference is responsiveness / DPI (the 28px top rule becomes one line
|
|
7
|
+
* and the accent falls back to the ANSI 256 palette).
|
|
8
|
+
* @module cobaia/cli
|
|
9
|
+
* @family wave/clibin
|
|
10
|
+
* @law same design as web / desktop, difference only responsiveness / DPI
|
|
11
|
+
* @seat 2026 · rung 2.0.157 · hierarchical JSDoc, tokens/flags, no hardcoded
|
|
12
|
+
* data — the version is read from package.json at runtime and the engine
|
|
13
|
+
* one-liner is quoted from the app docs.
|
|
14
|
+
* @runtime node strips the types; the shebang hands the file to the runtime
|
|
15
|
+
* (the saddle law).
|
|
16
|
+
* @deps zero — node builtins only (readline/promises, process, fs/promises).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { createInterface } from "node:readline/promises";
|
|
20
|
+
import { argv, exit, stdin, stdout } from "node:process";
|
|
21
|
+
import { readFile } from "node:fs/promises";
|
|
22
|
+
|
|
23
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
24
|
+
/* Section 1: the chrome tokens — the windows 11 palette folded to the DPI of the terminal (the accent #a3d7e6 lands on ansi 117, the focus #4cc2ff on 75, the hover red rgb(232,17,35) on 203; the 28px top rule becomes one line). */
|
|
25
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
26
|
+
|
|
27
|
+
/** the chat accent of the prompt and the titlebar name. */
|
|
28
|
+
const ACCENT = "\x1b[38;5;117m" as const; // #a3d7e6
|
|
29
|
+
/** the focus ink of the active top rule. */
|
|
30
|
+
const FOCUS = "\x1b[38;5;75m" as const; // #4cc2ff
|
|
31
|
+
/** the hover red of the unknown-command rows. */
|
|
32
|
+
const HOVER = "\x1b[38;5;203m" as const; // rgb(232, 17, 35)
|
|
33
|
+
/** the dim ink of the description rows (the minimal text law). */
|
|
34
|
+
const INK = "\x1b[2m" as const;
|
|
35
|
+
/** the reset token that closes every colored run. */
|
|
36
|
+
const RESET = "\x1b[0m" as const;
|
|
37
|
+
/** the single glyph of the rules and the rails. */
|
|
38
|
+
const BAR = "─" as const;
|
|
39
|
+
|
|
40
|
+
/** the app name of this binary seat — the titlebar text. */
|
|
41
|
+
const APP = "cobaia" as const;
|
|
42
|
+
/** the engine ownership one-liner, quoted from the app docs. */
|
|
43
|
+
const ENGINE =
|
|
44
|
+
"owns no engine file — the content site is the monetization surface: static plans, support rails and honest ad slots, no backend no tracking (docs/features.md)" as const;
|
|
45
|
+
|
|
46
|
+
/** the titlebar bar: the app name on the left rail, the window controls on the right — the windows 11 chrome inside the terminal. */
|
|
47
|
+
function titlebar(): string {
|
|
48
|
+
return `${ACCENT}┌ ${APP} ─ cli${RESET} ${INK}${BAR.repeat(24)} ─ ❐ ✕${RESET}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** the top rule: the 28px divider of the web surface folded to one terminal line. */
|
|
52
|
+
function toprule(): string {
|
|
53
|
+
return `${FOCUS}${BAR.repeat(3)} ${APP} ${BAR.repeat(3)}${RESET}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
57
|
+
/* Section 2: the runtime reads — no hardcoded data; the version comes from package.json at runtime. */
|
|
58
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
59
|
+
|
|
60
|
+
/** reads the version of this seat from the sibling package.json — never a literal. */
|
|
61
|
+
async function readversion(): Promise<string> {
|
|
62
|
+
try {
|
|
63
|
+
const manifest = JSON.parse(await readFile(new URL("./package.json", import.meta.url), "utf8")) as { version?: string };
|
|
64
|
+
return manifest.version ?? "0.0.0";
|
|
65
|
+
} catch {
|
|
66
|
+
return "0.0.0";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
71
|
+
/* Section 3: the chat console — the REPL with the ❯ prompt, the command dispatch and the same chat look as the web surface. */
|
|
72
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
73
|
+
|
|
74
|
+
/** the command help of the console — minimal text law: title + description only. */
|
|
75
|
+
function help(): string[] {
|
|
76
|
+
return [
|
|
77
|
+
`${INK}commands${RESET}`,
|
|
78
|
+
` help ${INK}this list${RESET}`,
|
|
79
|
+
` version ${INK}the package version, read from package.json at runtime${RESET}`,
|
|
80
|
+
` engine ${INK}the engine ownership one-liner of the app${RESET}`,
|
|
81
|
+
` exit ${INK}close the console${RESET}`,
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** runs the chat console: the titlebar, the top rule, the ❯ prompt and the dispatch (help, version, engine, exit); an eof on stdin closes the console the same way exit does. */
|
|
86
|
+
export async function main(): Promise<void> {
|
|
87
|
+
/* the version read happens before the interface exists, so a piped stdin never races the readline open (node buffers the pipe until the reader resumes it). */
|
|
88
|
+
const version = await readversion();
|
|
89
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
90
|
+
let eof = false;
|
|
91
|
+
rl.on("close", () => { eof = true; });
|
|
92
|
+
console.log(titlebar());
|
|
93
|
+
console.log(toprule());
|
|
94
|
+
console.log(`${ACCENT}${APP}${RESET} ${INK}v${version}${RESET}`);
|
|
95
|
+
console.log(`${INK}the ${APP} console — same design as web / desktop, only the DPI differs. type help.${RESET}`);
|
|
96
|
+
rl.setPrompt(`${ACCENT}❯${RESET} `);
|
|
97
|
+
rl.prompt();
|
|
98
|
+
for await (const raw of rl) {
|
|
99
|
+
const line = raw.trim();
|
|
100
|
+
const command = line.length > 0 ? line.split(/\s+/)[0]!.toLowerCase() : "";
|
|
101
|
+
if (command === "exit") rl.close();
|
|
102
|
+
else if (command === "help") for (const row of help()) console.log(row);
|
|
103
|
+
else if (command === "version") console.log(`${ACCENT}${APP}${RESET} ${version}`);
|
|
104
|
+
else if (command === "engine") console.log(`${INK}${ENGINE}${RESET}`);
|
|
105
|
+
else if (command.length > 0) console.log(`${HOVER}✕${RESET} ${INK}unknown command: ${command} — type help${RESET}`);
|
|
106
|
+
if (command === "exit") break;
|
|
107
|
+
/* the prompt is cosmetic chrome: a piped stdin that already reached eof skips it, the buffered lines still answer. */
|
|
108
|
+
if (!eof) rl.prompt();
|
|
109
|
+
}
|
|
110
|
+
console.log(`${INK}${APP} console closed.${RESET}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* the autorun guard (the saddle law): only a direct `node cli.ts` (or a bun run) boots the console here — an import stays quiet. */
|
|
114
|
+
if (import.meta.url === `file://${argv[1]}`) main().catch((error) => { console.error(error); exit(1); });
|
package/cobaia.csproj
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
|
2
|
+
<PropertyGroup>
|
|
3
|
+
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
|
|
4
|
+
<AssemblyName>cobaia</AssemblyName>
|
|
5
|
+
<RootNamespace>cobaia</RootNamespace>
|
|
6
|
+
<PackageId>cobaia</PackageId>
|
|
7
|
+
<Version>2.0.158</Version>
|
|
8
|
+
<Authors>wenathlan</Authors>
|
|
9
|
+
<Description>Distribution package containing the cobaia documentation set and the tests directory. cobaia is the monetization surface — the plans, the support rails and the honest advertisement slots.</Description>
|
|
10
|
+
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
|
11
|
+
<PackageProjectUrl>https://github.com/wenathlan/devthink</PackageProjectUrl>
|
|
12
|
+
<RepositoryUrl>https://github.com/wenathlan/devthink</RepositoryUrl>
|
|
13
|
+
<PackageReadmeFile>README.md</PackageReadmeFile>
|
|
14
|
+
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
|
15
|
+
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
|
16
|
+
</PropertyGroup>
|
|
17
|
+
<ItemGroup>
|
|
18
|
+
<None Include="README.md" Pack="true" PackagePath="/" />
|
|
19
|
+
<None Include="docs/**/*" Pack="true" PackagePath="contentFiles/any/any/docs/" />
|
|
20
|
+
<None Include="tests/**/*" Pack="true" PackagePath="contentFiles/any/any/tests/" />
|
|
21
|
+
</ItemGroup>
|
|
22
|
+
</Project>
|
package/cobaia.gemspec
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Gem::Specification.new do |spec|
|
|
2
|
+
spec.name = "cobaia"
|
|
3
|
+
spec.version = ENV.fetch("COBAIA_VERSION", "2.0.158")
|
|
4
|
+
spec.authors = ["wenathlan"]
|
|
5
|
+
spec.email = ["support@users.noreply.github.com"]
|
|
6
|
+
spec.summary = "The cobaia documentation and tests envelope (the monetization surface — the plans, the support rails and the honest advertisement slots)."
|
|
7
|
+
spec.description = "Distributes the cobaia documentation set and the tests directory as one Ruby gem. cobaia is the monetization surface — the plans, the support rails and the honest advertisement slots."
|
|
8
|
+
spec.homepage = "https://github.com/wenathlan/devthink"
|
|
9
|
+
spec.license = "GPL-3.0-only"
|
|
10
|
+
spec.required_ruby_version = ">= 3.1"
|
|
11
|
+
spec.files = Dir["README.md", "docs/**/*", "tests/**/*"]
|
|
12
|
+
spec.metadata["source_code_uri"] = "https://github.com/wenathlan/devthink"
|
|
13
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
14
|
+
end
|
package/cobaia.java
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package io.github.wenathlan.cobaia;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The cobaia version envelope carrier.
|
|
5
|
+
*
|
|
6
|
+
* <p>The carrier answers the lowercase file name doctrine (the technical name {@code cobaia}
|
|
7
|
+
* while the class keeps the presentation name {@code Cobaia}); the class drops the public
|
|
8
|
+
* modifier so the java file name rule holds — the envelope carries the version constant the
|
|
9
|
+
* metadata lockstep stamps, the registry lanes never compile it.
|
|
10
|
+
*/
|
|
11
|
+
final class Cobaia {
|
|
12
|
+
/** The version of the cobaia envelope (the six-distribution completeness wave). */
|
|
13
|
+
public static final String VERSION = "2.0.158";
|
|
14
|
+
private Cobaia() {
|
|
15
|
+
}
|
|
16
|
+
}
|