@4ort/cli 0.8.3 → 0.8.5

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/README.md CHANGED
@@ -409,8 +409,31 @@ automatically (no `FORT_FACTORY_KEY` needed).
409
409
 
410
410
  `render` sends a single HTML composition (or a directory, tarred) to the
411
411
  video factory, polls to completion, downloads the mp4 — and with
412
- `--publish` it lands on 4ort.mov directly. Full guide: `docs/MOV.md` in
413
- the repo.
412
+ `--publish` it lands on 4ort.mov directly.
413
+
414
+ **Start from the shipped template** — a known-good composition that passes
415
+ the factory's lint and renders a 12s vertical fact-card short:
416
+
417
+ ```bash
418
+ cp "$(npm root -g)/@4ort/cli/examples/fact-short.html" my-short.html
419
+ # edit the text/colors, then:
420
+ 4ort mov render my-short.html -q draft
421
+ ```
422
+
423
+ The factory lints compositions strictly. The contract, in short:
424
+
425
+ - The root is a plain `<div>` with `data-composition-id`, `data-width`,
426
+ `data-height`, `data-start="0"`, and `data-duration` — directly in
427
+ `<body>`, **no `<template>` wrapper**.
428
+ - Exactly one GSAP timeline, created `{ paused: true }`, registered
429
+ **synchronously** on `window.__timelines` under the **same id** as the
430
+ root div. Never build it inside async/setTimeout.
431
+ - Deterministic only: no `Math.random()`, no `Date.now()`, no
432
+ `repeat: -1` (use finite repeat counts), never call `.play()` on media.
433
+ - Video length comes from `data-duration`, not the GSAP timeline length.
434
+ - Scope GSAP selectors to your composition root so they can't leak.
435
+ - Don't write attribute-like literals in HTML comments — the linter scans
436
+ raw source and will misparse them as code.
414
437
 
415
438
  ### `4ort vault` + `4ort run` — secrets without plaintext
416
439
 
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ const program = new Command();
34
34
  program
35
35
  .name("4ort")
36
36
  .description("Unified CLI for the 4ort ecosystem — hosting, knowledge graph, and more")
37
- .version("0.8.3");
37
+ .version("0.8.5");
38
38
  // ─────────────────────────────────────────────────────────────────────
39
39
  // 4ort.net subdomain hosting
40
40
  // ─────────────────────────────────────────────────────────────────────
@@ -62,19 +62,46 @@ export async function getToken(server, client, username, password) {
62
62
  return { accessToken: j.access_token, refreshToken: j.refresh_token };
63
63
  }
64
64
  async function refresh(cfg) {
65
- const body = new URLSearchParams({
66
- client_id: cfg.clientId,
67
- client_secret: cfg.clientSecret,
68
- grant_type: "refresh_token",
69
- refresh_token: cfg.refreshToken,
70
- });
71
- const j = await asJson(await fetch(`${base(cfg.server)}/api/v1/users/token`, {
72
- method: "POST",
73
- headers: { "content-type": "application/x-www-form-urlencoded" },
74
- body,
75
- }));
76
- const next = { ...cfg, accessToken: j.access_token, refreshToken: j.refresh_token };
77
- saveMovConfig(next);
65
+ let next;
66
+ try {
67
+ const body = new URLSearchParams({
68
+ client_id: cfg.clientId,
69
+ client_secret: cfg.clientSecret,
70
+ grant_type: "refresh_token",
71
+ refresh_token: cfg.refreshToken,
72
+ });
73
+ const j = await asJson(await fetch(`${base(cfg.server)}/api/v1/users/token`, {
74
+ method: "POST",
75
+ headers: { "content-type": "application/x-www-form-urlencoded" },
76
+ body,
77
+ }));
78
+ next = { ...cfg, accessToken: j.access_token, refreshToken: j.refresh_token };
79
+ }
80
+ catch (err) {
81
+ // Refresh tokens are single-use: if a rotated token is ever lost (e.g. a
82
+ // read-only config in a container), refresh dies with invalid_grant
83
+ // forever. Recover with a full password grant when env creds exist.
84
+ const username = process.env.FORT_MOV_USERNAME || cfg.username;
85
+ const password = process.env.FORT_MOV_PASSWORD;
86
+ if (!username || !password)
87
+ throw err;
88
+ const client = await getOAuthClient(cfg.server);
89
+ const tok = await getToken(cfg.server, client, username, password);
90
+ next = {
91
+ ...cfg,
92
+ clientId: client.clientId,
93
+ clientSecret: client.clientSecret,
94
+ accessToken: tok.accessToken,
95
+ refreshToken: tok.refreshToken,
96
+ username,
97
+ };
98
+ }
99
+ try {
100
+ saveMovConfig(next);
101
+ }
102
+ catch {
103
+ // Read-only config (containerized factory) — keep going with in-memory tokens.
104
+ }
78
105
  return next;
79
106
  }
80
107
  /** Authenticated JSON request with one transparent refresh-on-401 retry. */
@@ -1 +1 @@
1
- {"version":3,"file":"peertube-client.js","sourceRoot":"","sources":["../src/peertube-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"peertube-client.js","sourceRoot":"","sources":["../src/peertube-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,95 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { createServer } from "node:http";
4
+ import fs from "node:fs";
5
+ import os from "node:os";
6
+ import path from "node:path";
7
+ // Sandbox the config file BEFORE importing anything that touches config.ts.
8
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "fort-refresh-"));
9
+ process.env.HOME = tmp; // CONFIG_DIR derives from os.homedir()
10
+ const { ptRequest } = await import("./peertube-client.js");
11
+ function listen(handler) {
12
+ return new Promise((resolve) => {
13
+ const srv = createServer(handler);
14
+ srv.listen(0, "127.0.0.1", () => {
15
+ const a = srv.address();
16
+ resolve({ url: `http://127.0.0.1:${a.port}`, close: () => srv.close() });
17
+ });
18
+ });
19
+ }
20
+ test("dead refresh token recovers via password grant when env creds exist", async () => {
21
+ const grants = [];
22
+ const m = await listen(async (req, res) => {
23
+ res.setHeader("content-type", "application/json");
24
+ if (req.url === "/api/v1/users/token" && req.method === "POST") {
25
+ const chunks = [];
26
+ for await (const c of req)
27
+ chunks.push(c);
28
+ const body = new URLSearchParams(Buffer.concat(chunks).toString());
29
+ grants.push(body.get("grant_type"));
30
+ if (body.get("grant_type") === "refresh_token") {
31
+ res.statusCode = 400;
32
+ return res.end(JSON.stringify({ code: "invalid_grant" }));
33
+ }
34
+ return res.end(JSON.stringify({ access_token: "fresh-atok", refresh_token: "fresh-rtok" }));
35
+ }
36
+ if (req.url === "/api/v1/oauth-clients/local") {
37
+ return res.end(JSON.stringify({ client_id: "cid2", client_secret: "csec2" }));
38
+ }
39
+ if (req.url === "/api/v1/users/me") {
40
+ const auth = req.headers.authorization ?? "";
41
+ if (auth !== "Bearer fresh-atok") {
42
+ res.statusCode = 401;
43
+ return res.end("{}");
44
+ }
45
+ return res.end(JSON.stringify({ ok: true }));
46
+ }
47
+ res.statusCode = 404;
48
+ res.end("{}");
49
+ });
50
+ process.env.FORT_MOV_USERNAME = "video-factory";
51
+ process.env.FORT_MOV_PASSWORD = "pw123";
52
+ try {
53
+ const cfg = {
54
+ server: m.url,
55
+ accessToken: "stale-atok",
56
+ refreshToken: "dead-rtok",
57
+ clientId: "cid",
58
+ clientSecret: "csec",
59
+ };
60
+ const out = await ptRequest(cfg, "/api/v1/users/me");
61
+ assert.equal(out.ok, true);
62
+ // It tried the refresh grant first, then fell back to the password grant.
63
+ assert.deepEqual(grants, ["refresh_token", "password"]);
64
+ }
65
+ finally {
66
+ delete process.env.FORT_MOV_USERNAME;
67
+ delete process.env.FORT_MOV_PASSWORD;
68
+ m.close();
69
+ }
70
+ });
71
+ test("dead refresh token with no env creds still throws", async () => {
72
+ const m = await listen((req, res) => {
73
+ res.setHeader("content-type", "application/json");
74
+ if (req.url === "/api/v1/users/token") {
75
+ res.statusCode = 400;
76
+ return res.end(JSON.stringify({ code: "invalid_grant" }));
77
+ }
78
+ res.statusCode = 401;
79
+ res.end("{}");
80
+ });
81
+ try {
82
+ const cfg = {
83
+ server: m.url,
84
+ accessToken: "stale",
85
+ refreshToken: "dead",
86
+ clientId: "c",
87
+ clientSecret: "s",
88
+ };
89
+ await assert.rejects(ptRequest(cfg, "/api/v1/users/me"), /400/);
90
+ }
91
+ finally {
92
+ m.close();
93
+ }
94
+ });
95
+ //# sourceMappingURL=peertube-refresh.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peertube-refresh.test.js","sourceRoot":"","sources":["../src/peertube-refresh.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,160 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>fact-short — 4ort mov render starter template</title>
6
+ <!--
7
+ Minimal KNOWN-GOOD HyperFrames composition for `4ort mov render`.
8
+ Vertical 1080x1920 (a "short"). For landscape swap the width/height attrs to 1920/1080.
9
+
10
+ The lint contract (violate any of these and the factory rejects the job):
11
+ 1. The root element is a plain div with a composition id attribute, DIRECTLY
12
+ in the body - no template-tag wrapper on a standalone file.
13
+ 2. The root div needs numeric width + height attrs, start "0", and a duration.
14
+ 3. Exactly one GSAP timeline, created paused, registered synchronously on the
15
+ global timelines object under the SAME id as the root div (see the script
16
+ at the bottom of this file - copy that shape exactly).
17
+ 4. No randomness or clock reads, no infinite repeats (use finite counts),
18
+ never call play() on media - the renderer owns the clock.
19
+ 5. Total video length comes from the duration attr, not the GSAP timeline.
20
+ 6. Keep GSAP selectors scoped (prefix them with the composition root) so they
21
+ never leak into other compositions when bundled.
22
+
23
+ NOTE: do not write attribute-like literals (the id/width/timeline patterns) in
24
+ comments - the linter scans raw source and will misparse them as code.
25
+
26
+ Edit the text, colors, and facts. Render with:
27
+ 4ort mov render fact-short.html -q draft # test render
28
+ 4ort mov render fact-short.html --publish -t "Title" # render + publish to 4ort.mov
29
+ -->
30
+ <style>
31
+ * { margin: 0; box-sizing: border-box; }
32
+ body { background: #000; }
33
+
34
+ [data-composition-id="fact-short"] {
35
+ position: relative;
36
+ overflow: hidden;
37
+ background: #0d0d14;
38
+ font-family: "Inter", "Helvetica Neue", Arial, sans-serif;
39
+ color: #e8e8f0;
40
+ }
41
+
42
+ /* soft radial glow — radial (not linear) avoids H.264 banding on dark bg */
43
+ .glow {
44
+ position: absolute;
45
+ top: -20%; left: 50%;
46
+ width: 1400px; height: 1400px;
47
+ transform: translateX(-50%);
48
+ background: radial-gradient(circle, rgba(167, 139, 250, 0.16) 0%, rgba(13, 13, 20, 0) 60%);
49
+ }
50
+
51
+ .scene-content {
52
+ display: flex;
53
+ flex-direction: column;
54
+ justify-content: center;
55
+ width: 100%;
56
+ height: 100%;
57
+ padding: 160px 96px;
58
+ gap: 44px;
59
+ }
60
+
61
+ .kicker {
62
+ font-size: 34px;
63
+ font-weight: 700;
64
+ letter-spacing: 0.22em;
65
+ text-transform: uppercase;
66
+ color: #a78bfa;
67
+ }
68
+
69
+ .headline {
70
+ font-size: 110px;
71
+ font-weight: 800;
72
+ line-height: 1.05;
73
+ max-width: 880px;
74
+ }
75
+
76
+ .accent-bar {
77
+ width: 140px;
78
+ height: 8px;
79
+ border-radius: 4px;
80
+ background: #a78bfa;
81
+ }
82
+
83
+ .fact {
84
+ display: flex;
85
+ align-items: baseline;
86
+ gap: 24px;
87
+ }
88
+ .fact-number {
89
+ font-size: 64px;
90
+ font-weight: 800;
91
+ color: #a78bfa;
92
+ font-variant-numeric: tabular-nums;
93
+ min-width: 90px;
94
+ }
95
+ .fact-text {
96
+ font-size: 40px;
97
+ line-height: 1.3;
98
+ color: #c9c9da;
99
+ max-width: 740px;
100
+ }
101
+
102
+ .footer {
103
+ margin-top: 28px;
104
+ font-size: 30px;
105
+ font-weight: 600;
106
+ color: #8d8da4;
107
+ letter-spacing: 0.04em;
108
+ }
109
+ </style>
110
+ </head>
111
+ <body>
112
+
113
+ <div data-composition-id="fact-short" data-width="1080" data-height="1920" data-start="0" data-duration="12">
114
+ <div class="glow"></div>
115
+ <div class="scene-content">
116
+ <div class="kicker">📡 Did you know</div>
117
+ <h1 class="headline">Sagittarius&nbsp;A* weighs 4.3 million suns</h1>
118
+ <div class="accent-bar"></div>
119
+ <div class="fact fact-1">
120
+ <span class="fact-number">01</span>
121
+ <span class="fact-text">It sits 26,000 light-years away at the center of our galaxy.</span>
122
+ </div>
123
+ <div class="fact fact-2">
124
+ <span class="fact-number">02</span>
125
+ <span class="fact-text">First photographed in 2022 by the Event Horizon Telescope.</span>
126
+ </div>
127
+ <div class="fact fact-3">
128
+ <span class="fact-number">03</span>
129
+ <span class="fact-text">The star S2 orbits it at 3% of the speed of light.</span>
130
+ </div>
131
+ <div class="footer">yourname.4ort.net</div>
132
+ </div>
133
+ </div>
134
+
135
+ <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
136
+ <script>
137
+ // Built synchronously, paused, registered — the renderer drives it.
138
+ window.__timelines = window.__timelines || {};
139
+ const tl = gsap.timeline({ paused: true });
140
+
141
+ // Entrances — varied eases, first tween offset past t=0.
142
+ tl.from(".kicker", { y: -30, opacity: 0, duration: 0.5, ease: "power2.out" }, 0.2);
143
+ tl.from(".headline", { y: 60, opacity: 0, duration: 0.8, ease: "power3.out" }, 0.4);
144
+ tl.from(".accent-bar", { scaleX: 0, transformOrigin: "left center", duration: 0.6, ease: "expo.out" }, 0.9);
145
+ tl.from(".fact-1", { x: -50, opacity: 0, duration: 0.6, ease: "back.out(1.4)" }, 1.2);
146
+ tl.from(".fact-2", { x: -50, opacity: 0, duration: 0.6, ease: "back.out(1.4)" }, 1.5);
147
+ tl.from(".fact-3", { x: -50, opacity: 0, duration: 0.6, ease: "back.out(1.4)" }, 1.8);
148
+ tl.from(".footer", { opacity: 0, duration: 0.6, ease: "power1.out" }, 2.4);
149
+
150
+ // Ambient pulse on the accent bar — FINITE repeats sized to the 12s duration.
151
+ tl.to(".accent-bar", { opacity: 0.55, duration: 1.0, ease: "sine.inOut", repeat: 7, yoyo: true }, 3.0);
152
+
153
+ // Final-scene fade out (allowed only on the last scene — this is a one-scene short).
154
+ tl.to('[data-composition-id="fact-short"] .scene-content, [data-composition-id="fact-short"] .glow', { opacity: 0, duration: 0.8, ease: "power2.in" }, 11.0);
155
+
156
+ window.__timelines["fact-short"] = tl;
157
+ </script>
158
+
159
+ </body>
160
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4ort/cli",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "Unified CLI for the 4ort ecosystem — 4ort.net hosting, knowledge graph, and more",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,7 +8,8 @@
8
8
  },
9
9
  "files": [
10
10
  "dist",
11
- "README.md"
11
+ "README.md",
12
+ "examples"
12
13
  ],
13
14
  "scripts": {
14
15
  "dev": "tsx src/index.ts",