@wenathlan/cobaia 2.0.166 → 2.0.167

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.
@@ -1,7 +1,7 @@
1
1
  // # entryflow.test — the construction-flow contract of the cobaia: the
2
2
  // standardized family law (intro → onboarding → entrada) the owner ordered
3
3
  // and the db-backed content law behind it. Run: pnpm vitest run
4
- // tests/entryflow.test.ts
4
+ // test/entryflow.test.ts
5
5
  //
6
6
  // The suite watches three promises:
7
7
  // 1. the flow — the intro mounts before the onboarding, the onboarding
@@ -115,7 +115,7 @@ describe("the content law (the rows live in the db, the manifest is the seed)",
115
115
  });
116
116
 
117
117
  it("keeps the faces reading through the typed doors — no hardcoded row in a page", () => {
118
- expect(HOME).toMatch(/from "\.\.\/\.\.\/roster\.ts"/);
118
+ expect(HOME).toMatch(/from "\.\.\/\.\.\/monetization\.ts"/);
119
119
  expect(HOME).not.toMatch(/const ROSTER/);
120
120
  expect(read("../sol/apps/apps.tsx")).not.toMatch(/const ROSTER/);
121
121
  expect(read("../sol/pricing/pricing.tsx")).not.toMatch(/const PLANS/);
@@ -1,5 +1,5 @@
1
1
  // # familyurl.test — the address book contract of the family deploy units.
2
- // Run: pnpm vitest run tests/familyurl.test.ts
2
+ // Run: pnpm vitest run test/familyurl.test.ts
3
3
  // The suite watches the promise the directory and the footer make: every
4
4
  // family member resolves one level above this application, always with the
5
5
  // trailing slash, and pasted segments or stray slashes land on the same
@@ -1,12 +1,12 @@
1
1
  // # posts.test — the seed blog of the family site.
2
- // Run: pnpm vitest run tests/posts.test.ts
2
+ // Run: pnpm vitest run test/posts.test.ts
3
3
  // The suite watches the promise the blog page makes: the index is sorted
4
4
  // newest first no matter the array order, the slugs are unique and url-safe,
5
5
  // every seed post carries a real ~300 word body (the ad networks approve
6
6
  // content, not containers) and the honest word counter agrees with itself.
7
7
  import assert from "node:assert/strict";
8
8
  import { describe, expect, it } from "vitest";
9
- import { postindex, posts, postwords } from "../posts.ts";
9
+ import { postindex, posts, postwords } from "../monetization.ts";
10
10
 
11
11
  // the content lane answers the same rows the seed carries (wave of the
12
12
  // content law): the const retired, the accessor serves the identical data
@@ -9,7 +9,7 @@
9
9
  // modality id pins the seat for the platform's join to validate at
10
10
  // dispatch — this module never judges engine vocabulary). runnable with
11
11
  // vitest:
12
- // pnpm vitest run tests/sandboxmodality.test.ts
12
+ // pnpm vitest run test/sandboxmodality.test.ts
13
13
  import assert from "node:assert/strict";
14
14
  import { lanesof } from "@wenathlan/saddle/workloadlaw";
15
15
  import { describe, it } from "vitest";
package/vitest.config.ts CHANGED
@@ -32,7 +32,7 @@ export default defineConfig({
32
32
  },
33
33
  },
34
34
  test: {
35
- include: ["tests/*.test.ts"],
35
+ include: ["test/*.test.ts"],
36
36
  environment: "node",
37
37
  /* the timeout stays five seconds on every native runner and scales through the env the emulated arm64 container leg sets (a qemu-interpreted second answers the same green suite many times slower), so an emulated runner never fails a test a native runner passed */
38
38
  testTimeout: Number(process.env.COBAIA_TEST_TIMEOUT_MS ?? 5000),
package/adsconfig.ts DELETED
@@ -1,59 +0,0 @@
1
- /**
2
- * adsconfig.ts — the honest ad slot registry of the family site, pure data
3
- * at the app root. The family site carries ONE reserved ad container per
4
- * content page (home, the app directory, the blog index), always at the end
5
- * of the content, always labeled "advertisement", always a fixed aspect
6
- * ratio so the page never shifts when a real unit arrives.
7
- *
8
- * THE SCRIPT RULE: no ad network script lives in this repository. The
9
- * AdSense (or equivalent) loader is injected AFTER the network approves the
10
- * site, through the deploy environment only. Until then the slot ids stay
11
- * empty and the container renders the honest empty note. No network call,
12
- * no click encouragement, no automated traffic ever touches an ad surface —
13
- * invalid traffic is the one thing that kills both the ad account and the
14
- * domain reputation, so the family does not do it.
15
- */
16
-
17
- /** one reserved ad slot: the config id and the reserved shape. */
18
- export type adsslot = {
19
- /** the ad network slot id — empty until the owner configures it after approval */
20
- slotid: string;
21
- /** the display format the reserved box mimics */
22
- format: string;
23
- /** the css aspect-ratio value the container reserves (never shifts layout) */
24
- ratio: string;
25
- };
26
-
27
- /** the fixed label every ad container renders, visible and honest. */
28
- export const ADS_LABEL = "advertisement";
29
-
30
- /** the honest note the container renders while no slot id is configured. */
31
- export const ADS_EMPTY = "ad slot not configured yet";
32
-
33
- /** the reserved slots per content page, keyed by the page folder name. */
34
- export const ADSSLOTS: Readonly<Record<string, adsslot>> = {
35
- home: { slotid: "", format: "display", ratio: "728 / 90" },
36
- apps: { slotid: "", format: "in-feed", ratio: "3 / 1" },
37
- blog: { slotid: "", format: "in-article", ratio: "3 / 1" },
38
- };
39
-
40
- /**
41
- * Reads the reserved slot of one content page.
42
- *
43
- * @param page the page folder name (home, apps, blog).
44
- * @returns the slot, or undefined when the page carries no slot.
45
- */
46
- export function adsslotfor(page: string): adsslot | undefined {
47
- return ADSSLOTS[page];
48
- }
49
-
50
- /**
51
- * Answers whether a slot is configured with a real network id. An empty
52
- * (or whitespace) slot id means the container stays an honest placeholder.
53
- *
54
- * @param slot the reserved slot entry.
55
- * @returns true only when the slot id carries a value.
56
- */
57
- export function adsslotlive(slot: adsslot | undefined): boolean {
58
- return slot !== undefined && slot.slotid.trim().length > 0;
59
- }
package/checkoutlinks.ts DELETED
@@ -1,80 +0,0 @@
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/posts.ts DELETED
@@ -1,54 +0,0 @@
1
- /**
2
- * posts.ts — the typed accessor of the seed blog: the thin door the blog
3
- * page and the tests import, answering the posts of the content lane
4
- * (content.ts — the manifest; db.ts — the content_rows table; the platform
5
- * gateway — GET /api/v1/ui/content). The data never lives here anymore:
6
- * posts() answers the live rows the platform served, the manifest seed
7
- * otherwise (the uistore chain), the index sort and the honest word count
8
- * stay exactly where they rode, and the blog index (/blog) renders the
9
- * sorted index and the full bodies through this door — real, written
10
- * content about how the family is built, so the site is useful on its own
11
- * merits (the ad networks approve content, not containers). New posts
12
- * append to the manifest; the index sorts by date, so the manifest order
13
- * never matters.
14
- */
15
-
16
- import { type blogpost, contenttable, seedPosts } from "./content.ts";
17
-
18
- export type { blogpost };
19
-
20
- /**
21
- * The typed accessor of the blog: the live db rows when the platform
22
- * answered, the manifest seed otherwise.
23
- *
24
- * @returns the posts of the blog.
25
- */
26
- export function posts(): readonly blogpost[] {
27
- return contenttable("posts", seedPosts);
28
- }
29
-
30
- /**
31
- * Builds the blog index: the posts sorted by date, newest first. The ISO
32
- * date sort is lexicographic and stable, so the index order never depends
33
- * on the row order the store answers.
34
- *
35
- * @returns the posts of the blog, newest first.
36
- */
37
- export function postindex(): readonly blogpost[] {
38
- return [...posts()].sort((a, b) => {
39
- if (a.date < b.date) return 1;
40
- if (a.date > b.date) return -1;
41
- return 0;
42
- });
43
- }
44
-
45
- /**
46
- * Counts the words of one post's body — the honest length measure the tests
47
- * and the page footer can both read.
48
- *
49
- * @param post the post to measure.
50
- * @returns the total word count across the body paragraphs.
51
- */
52
- export function postwords(post: blogpost): number {
53
- return post.body.join(" ").split(/\s+/).filter(Boolean).length;
54
- }
package/roster.ts DELETED
@@ -1,29 +0,0 @@
1
- /**
2
- * roster.ts — the typed accessor of the family directory data: the thin
3
- * door the /apps page, the shell footer, the home preview and the intro
4
- * footer import, answering the roster of the content lane (content.ts —
5
- * the manifest; db.ts — the content_rows table; the platform gateway — GET
6
- * /api/v1/ui/content). The data never lives here anymore: roster() answers
7
- * the live rows the platform served, the manifest seed otherwise (the
8
- * uistore chain). Every deploy unit beside the cobaia, with the one accent
9
- * each carries (the spec §12 table, mirrored from the argan contract; the
10
- * devthink OS rides the family sun) and the honest role each app declares
11
- * in its own devthink.toml — condensed to one line, nothing embellished:
12
- * the page and the tests read the same table through this door, so the
13
- * directory can never drift from the family.
14
- */
15
-
16
- import { contenttable, type familymember, seedRoster } from "./content.ts";
17
-
18
- export type { familymember };
19
-
20
- /**
21
- * The typed accessor of the directory: the live db rows when the platform
22
- * answered, the manifest seed otherwise — rail order, the OS first, then
23
- * the applications.
24
- *
25
- * @returns the directory roster.
26
- */
27
- export function roster(): readonly familymember[] {
28
- return contenttable("roster", seedRoster);
29
- }