@forumulate/cli 0.2.0 → 0.3.0

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/dist/cli.js CHANGED
@@ -1,14 +1,46 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
+ const node_readline_1 = require("node:readline");
4
5
  const sdk_1 = require("@forumulate/sdk");
6
+ const credentials_1 = require("./credentials");
5
7
  const run_1 = require("./run");
8
+ /**
9
+ * Read one line the user types, without echoing it.
10
+ *
11
+ * A token pasted into a terminal that echoes it is a token in the scrollback,
12
+ * and on a shared screen that is the whole secret. Falls back to a plain read
13
+ * when stdin is not a TTY (a pipe, CI), where there is nothing to hide it from.
14
+ */
15
+ function askSecret(question) {
16
+ const rl = (0, node_readline_1.createInterface)({ input: process.stdin, output: process.stdout, terminal: true });
17
+ return new Promise((resolve) => {
18
+ const stdout = process.stdout;
19
+ if (stdout.isTTY) {
20
+ const write = rl._writeToOutput;
21
+ rl._writeToOutput = (s) => {
22
+ if (s.includes(question))
23
+ write?.call(rl, s);
24
+ };
25
+ }
26
+ rl.question(question, (answer) => {
27
+ rl.close();
28
+ if (stdout.isTTY)
29
+ process.stdout.write('\n');
30
+ resolve(answer);
31
+ });
32
+ });
33
+ }
6
34
  async function main() {
7
35
  const baseUrl = process.env.FORUMULATE_URL ?? 'http://localhost:4000';
8
- const token = process.env.FORUMULATE_TOKEN;
36
+ // The environment first, then what `login` stored for THIS API — see
37
+ // `credentials.ts` for why the env var still wins.
38
+ const token = (0, credentials_1.resolveToken)(baseUrl);
9
39
  const client = new sdk_1.ForumulateClient({ baseUrl, token });
10
40
  const code = await (0, run_1.run)(process.argv.slice(2), {
11
41
  client,
42
+ baseUrl,
43
+ prompt: askSecret,
12
44
  out: (l) => process.stdout.write(l + '\n'),
13
45
  err: (l) => process.stderr.write(l + '\n'),
14
46
  });
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AACA,yCAAmD;AACnD,+BAA4B;AAE5B,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,uBAAuB,CAAC;IACtE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,sBAAgB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,MAAM,IAAA,SAAG,EAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QAC5C,MAAM;QACN,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC;QAC1C,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC;KAC3C,CAAC,CAAC;IACH,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,KAAK,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AACA,iDAAgD;AAChD,yCAAmD;AACnD,+CAA6C;AAC7C,+BAA4B;AAE5B;;;;;;GAMG;AACH,SAAS,SAAS,CAAC,QAAgB;IACjC,MAAM,EAAE,GAAG,IAAA,+BAAe,EAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7F,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAkD,CAAC;QAC1E,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,MAAM,KAAK,GAAI,EAA0D,CAAC,cAAc,CAAC;YACxF,EAAyD,CAAC,cAAc,GAAG,CAAC,CAAS,EAAE,EAAE;gBACxF,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBAAE,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YAC/C,CAAC,CAAC;QACJ,CAAC;QACD,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;YAC/B,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,MAAM,CAAC,KAAK;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC7C,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,uBAAuB,CAAC;IACtE,qEAAqE;IACrE,mDAAmD;IACnD,MAAM,KAAK,GAAG,IAAA,0BAAY,EAAC,OAAO,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,sBAAgB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,MAAM,IAAA,SAAG,EAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QAC5C,MAAM;QACN,OAAO;QACP,MAAM,EAAE,SAAS;QACjB,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC;QAC1C,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC;KAC3C,CAAC,CAAC;IACH,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,KAAK,IAAI,EAAE,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Where a token lives between invocations.
3
+ *
4
+ * The CLI had no `login`: every command needed `FORUMULATE_TOKEN` exported in
5
+ * the shell, which means the token is in the environment of everything else
6
+ * that shell runs, and in the history file of whoever typed it (Crossly DX-2).
7
+ * A file read by this process alone, mode 0600, is the smaller exposure — and
8
+ * it is what every other CLI a developer already has does.
9
+ *
10
+ * Keyed by API base URL, so a token for staging cannot be sent to production by
11
+ * forgetting to change one variable.
12
+ *
13
+ * `FORUMULATE_TOKEN` still wins when it is set. CI sets it, and a file on disk
14
+ * silently overriding what a pipeline passed in would be the worse surprise.
15
+ */
16
+ export interface Credentials {
17
+ /** baseUrl → token. */
18
+ tokens: Record<string, string>;
19
+ }
20
+ export declare function credentialsPath(env?: NodeJS.ProcessEnv): string;
21
+ export declare function readCredentials(env?: NodeJS.ProcessEnv): Credentials;
22
+ /** The token for a base URL: the environment first, then what `login` stored. */
23
+ export declare function resolveToken(baseUrl: string, env?: NodeJS.ProcessEnv): string | undefined;
24
+ export declare function storeToken(baseUrl: string, token: string, env?: NodeJS.ProcessEnv): string;
25
+ export declare function forgetToken(baseUrl: string, env?: NodeJS.ProcessEnv): boolean;
26
+ /** One spelling per host: a trailing slash is not a different server. */
27
+ export declare function normalizeBase(baseUrl: string): string;
28
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,WAAW;IAC1B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAK5E;AAED,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,WAAW,CASjF;AAED,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAGtG;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAUvG;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAiB1F;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD"}
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.credentialsPath = credentialsPath;
4
+ exports.readCredentials = readCredentials;
5
+ exports.resolveToken = resolveToken;
6
+ exports.storeToken = storeToken;
7
+ exports.forgetToken = forgetToken;
8
+ exports.normalizeBase = normalizeBase;
9
+ const node_fs_1 = require("node:fs");
10
+ const node_os_1 = require("node:os");
11
+ const node_path_1 = require("node:path");
12
+ function credentialsPath(env = process.env) {
13
+ const base = env.FORUMULATE_CONFIG_DIR ??
14
+ (env.XDG_CONFIG_HOME ? (0, node_path_1.join)(env.XDG_CONFIG_HOME, 'forumulate') : (0, node_path_1.join)((0, node_os_1.homedir)(), '.config', 'forumulate'));
15
+ return (0, node_path_1.join)(base, 'credentials.json');
16
+ }
17
+ function readCredentials(env = process.env) {
18
+ try {
19
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)(credentialsPath(env), 'utf8'));
20
+ return { tokens: parsed.tokens ?? {} };
21
+ }
22
+ catch {
23
+ // No file, unreadable, or not ours to parse: there is no stored token, which
24
+ // is a state and not an error.
25
+ return { tokens: {} };
26
+ }
27
+ }
28
+ /** The token for a base URL: the environment first, then what `login` stored. */
29
+ function resolveToken(baseUrl, env = process.env) {
30
+ if (env.FORUMULATE_TOKEN)
31
+ return env.FORUMULATE_TOKEN;
32
+ return readCredentials(env).tokens[normalizeBase(baseUrl)];
33
+ }
34
+ function storeToken(baseUrl, token, env = process.env) {
35
+ const path = credentialsPath(env);
36
+ const creds = readCredentials(env);
37
+ creds.tokens[normalizeBase(baseUrl)] = token;
38
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(path), { recursive: true, mode: 0o700 });
39
+ (0, node_fs_1.writeFileSync)(path, `${JSON.stringify(creds, null, 2)}\n`, { mode: 0o600 });
40
+ // Explicit, because `writeFileSync`'s mode is ignored for a file that already
41
+ // exists — and the one that already exists is the one with a token in it.
42
+ (0, node_fs_1.chmodSync)(path, 0o600);
43
+ return path;
44
+ }
45
+ function forgetToken(baseUrl, env = process.env) {
46
+ const creds = readCredentials(env);
47
+ const key = normalizeBase(baseUrl);
48
+ if (!(key in creds.tokens))
49
+ return false;
50
+ delete creds.tokens[key];
51
+ const path = credentialsPath(env);
52
+ if (Object.keys(creds.tokens).length === 0) {
53
+ try {
54
+ (0, node_fs_1.rmSync)(path);
55
+ }
56
+ catch {
57
+ /* already gone */
58
+ }
59
+ return true;
60
+ }
61
+ (0, node_fs_1.writeFileSync)(path, `${JSON.stringify(creds, null, 2)}\n`, { mode: 0o600 });
62
+ (0, node_fs_1.chmodSync)(path, 0o600);
63
+ return true;
64
+ }
65
+ /** One spelling per host: a trailing slash is not a different server. */
66
+ function normalizeBase(baseUrl) {
67
+ return baseUrl.replace(/\/+$/, '').toLowerCase();
68
+ }
69
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAKD,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA2JzE"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAKD,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA2NzE"}
package/dist/doctor.js CHANGED
@@ -20,11 +20,36 @@ async function runDoctor(input) {
20
20
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
21
21
  }
22
22
  };
23
- // 1. Health answers JSON, in every state.
23
+ /*
24
+ * 1. Health answers JSON, in every state.
25
+ *
26
+ * This check could not fail, and a customer caught it. `get()` reports
27
+ * `ok: true` whenever the FETCH resolved — it says nothing about the status —
28
+ * and the body test was only `parsed && typeof parsed === 'object'`. Our API
29
+ * answers its errors as JSON, so a 404 and a 500 both parsed to an object and
30
+ * both were reported as a pass. On their domain `/api/health` is not routed
31
+ * at all: a 404 with a JSON error envelope, reported green. A health check
32
+ * that passes while the thing it checks is absent is worse than no check,
33
+ * because it is the one line in the report somebody trusts.
34
+ *
35
+ * Two things follow. The status has to be read. And on a reader URL the
36
+ * default probe is the WRONG origin to ask: a customer's host serves their
37
+ * docs, not our API, and `/api` there is theirs — so an absent route is a
38
+ * skip that says where the real endpoint is, never a pass and never a scary
39
+ * failure for something they do not operate. Reachability of the platform is
40
+ * already proven by the page fetch below; this check is about the API.
41
+ */
42
+ const defaultedApiBase = input.apiBase === undefined;
24
43
  const health = await get(`${apiBase}/api/health`, { accept: 'application/json' });
25
44
  if (!health.ok) {
26
45
  add('health', 'Health endpoint answers', 'fail', health.error, 'A caller cannot tell an outage from a bug.');
27
46
  }
47
+ else if (health.res.status === 404 && defaultedApiBase) {
48
+ add('health', 'Health endpoint answers JSON', 'skip', `404 — ${apiBase} does not route /api/health. This host serves the reader; the API it is served by has its own origin.`, 'Re-run with --api-base <origin> to check the API that serves this site.');
49
+ }
50
+ else if (health.res.status < 200 || health.res.status >= 300) {
51
+ add('health', 'Health endpoint answers JSON', 'fail', `${health.res.status} from ${apiBase}/api/health: ${health.text.slice(0, 80)}`, 'A health endpoint that does not answer 2xx is down, whatever its body parses as.');
52
+ }
28
53
  else {
29
54
  let parsed = null;
30
55
  try {
@@ -96,10 +121,35 @@ async function runDoctor(input) {
96
121
  if (asBot.ok) {
97
122
  add('crawler-access', 'A crawler gets the same answer as a reader', asBot.res.status === (anon.ok ? anon.res.status : 200) ? 'pass' : 'fail', `reader ${anon.ok ? anon.res.status : '?'}, crawler ${asBot.res.status}`, 'A WAF rule or bot challenge that answers crawlers differently removes the site from search without telling anybody.');
98
123
  }
99
- // 8. The feeds exist where a reader will look for them.
100
- const feed = await get(`${origin}${site.pathname.replace(/\/$/, '')}/rss.xml`, { accept: 'application/rss+xml' });
101
- if (feed.ok) {
102
- add('feeds', 'A feed is served under this path', feed.res.status === 200 ? 'pass' : 'skip', `${feed.res.status} for ${site.pathname.replace(/\/$/, '')}/rss.xml`, 'Readers and aggregators look beside the page, not at an API URL.');
124
+ /*
125
+ * 8. The feed a reader will look for is the one the page ADVERTISES.
126
+ *
127
+ * This probed `<path>/rss.xml` unconditionally and called a 404 a skip — so on
128
+ * a docs section, which has no feed and is not supposed to have one, the
129
+ * report carried a warning that read like a defect and the detail said only
130
+ * "404". The customer asked, reasonably, why their docs were being marked
131
+ * down for missing a thing docs do not have.
132
+ *
133
+ * The page's own `<link rel="alternate">` is the contract: if a surface names
134
+ * a feed, that feed must answer, and if it names none there is nothing to
135
+ * check. That is both the honest report and the stricter one — it now catches
136
+ * an ADVERTISED feed that 404s, which the blanket probe could not distinguish
137
+ * from a surface that simply has no feed.
138
+ */
139
+ const advertised = feedHref(html, origin);
140
+ if (advertised) {
141
+ const feed = await get(advertised, { accept: 'application/rss+xml' });
142
+ if (!feed.ok) {
143
+ add('feeds', 'The feed this page advertises is served', 'fail', feed.error, 'A feed link that does not resolve breaks every aggregator that followed it.');
144
+ }
145
+ else {
146
+ add('feeds', 'The feed this page advertises is served', feed.res.status === 200 ? 'pass' : 'fail', `${feed.res.status} for ${advertised}`, feed.res.status === 200
147
+ ? ''
148
+ : 'The page tells readers and aggregators this URL is its feed, so a non-200 is a broken promise, not a missing feature.');
149
+ }
150
+ }
151
+ else if (html) {
152
+ add('feeds', 'The feed this page advertises is served', 'skip', 'This page advertises no feed. Docs surfaces do not publish one; blogs, changelogs, forums and status pages do.', '');
103
153
  }
104
154
  return {
105
155
  url: input.url,
@@ -109,6 +159,32 @@ async function runDoctor(input) {
109
159
  warnings: checks.filter((c) => c.state === 'skip').length,
110
160
  };
111
161
  }
162
+ /**
163
+ * The feed this document declares, absolute, or null when it declares none.
164
+ *
165
+ * Matched on the `<link rel="alternate">` whose type is an RSS/Atom/JSON-feed
166
+ * media type, rather than on a filename — a surface is free to serve its feed
167
+ * at any address, and the point of reading the markup is to check the address
168
+ * the page actually publishes.
169
+ */
170
+ function feedHref(html, origin) {
171
+ for (const tag of html.match(/<link\b[^>]*>/gi) ?? []) {
172
+ if (!/\brel\s*=\s*["']?alternate\b/i.test(tag))
173
+ continue;
174
+ if (!/type\s*=\s*["'](?:application\/(?:rss\+xml|atom\+xml|feed\+json))["']/i.test(tag))
175
+ continue;
176
+ const href = tag.match(/\bhref\s*=\s*["']([^"']+)["']/i)?.[1];
177
+ if (!href)
178
+ continue;
179
+ try {
180
+ return new URL(href, origin).toString();
181
+ }
182
+ catch {
183
+ return null;
184
+ }
185
+ }
186
+ return null;
187
+ }
112
188
  function safeHost(href) {
113
189
  try {
114
190
  return new URL(href).host;
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /** One markdown file, as the publisher sees it. */
2
+ export interface LocalDoc {
3
+ /** Path as given on the command line, for the plan a person reads. */
4
+ path: string;
5
+ /** The slug this file publishes at. */
6
+ slug: string;
7
+ title: string;
8
+ markdown: string;
9
+ }
10
+ /** What a directory publish would do, before it does any of it. */
11
+ export interface PublishPlan {
12
+ create: LocalDoc[];
13
+ update: (LocalDoc & {
14
+ itemId: string;
15
+ })[];
16
+ /** Published pieces with no file — never touched, only reported. */
17
+ orphans: {
18
+ slug: string;
19
+ title: string;
20
+ }[];
21
+ }
22
+ /**
23
+ * A file's own front matter, in the small form every static-site generator
24
+ * writes: `key: value` lines, no nesting, no arrays. Anything richer belongs in
25
+ * the page itself, and guessing at YAML we do not support would publish a
26
+ * document whose first paragraph is a parse error.
27
+ */
28
+ export declare function parseFrontMatter(text: string): {
29
+ data: Record<string, string>;
30
+ body: string;
31
+ };
32
+ /** `01-getting-started.md` → `getting-started`; `a/b/c.md` → `a-b-c`. */
33
+ export declare function slugFor(file: string, root: string, front: Record<string, string>): string;
34
+ /** The first `# heading`, else the front matter's title, else the slug. */
35
+ export declare function titleFor(body: string, front: Record<string, string>, slug: string): string;
36
+ /** Every `.md`/`.mdx` under a directory, depth-first, in a stable order. */
37
+ export declare function readDocs(root: string): LocalDoc[];
38
+ /**
39
+ * What publishing this directory would change, decided against what the space
40
+ * already holds.
41
+ *
42
+ * A file whose slug the space already has is an UPDATE; one it does not is a
43
+ * CREATE; a published piece with no file is an orphan — reported and left
44
+ * alone, because a directory is a source of truth for what it contains and not
45
+ * a statement about what should be deleted.
46
+ */
47
+ export declare function planPublish(docs: LocalDoc[], existing: {
48
+ id: string;
49
+ slug?: string;
50
+ title: string;
51
+ }[]): PublishPlan;
52
+ /** The plan as a person reads it — the whole point of `--dry-run`. */
53
+ export declare function describePlan(plan: PublishPlan, root: string): string[];
54
+ //# sourceMappingURL=publish-dir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish-dir.d.ts","sourceRoot":"","sources":["../src/publish-dir.ts"],"names":[],"mappings":"AAGA,mDAAmD;AACnD,MAAM,WAAW,QAAQ;IACvB,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,mEAAmE;AACnE,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,MAAM,EAAE,CAAC,QAAQ,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAC1C,oEAAoE;IACpE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5C;AAID;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAe7F;AAED,yEAAyE;AACzE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAUzF;AAED,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1F;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAmBjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,WAAW,CAcnH;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAOtE"}
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseFrontMatter = parseFrontMatter;
4
+ exports.slugFor = slugFor;
5
+ exports.titleFor = titleFor;
6
+ exports.readDocs = readDocs;
7
+ exports.planPublish = planPublish;
8
+ exports.describePlan = describePlan;
9
+ const node_fs_1 = require("node:fs");
10
+ const node_path_1 = require("node:path");
11
+ const FRONT_MATTER = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
12
+ /**
13
+ * A file's own front matter, in the small form every static-site generator
14
+ * writes: `key: value` lines, no nesting, no arrays. Anything richer belongs in
15
+ * the page itself, and guessing at YAML we do not support would publish a
16
+ * document whose first paragraph is a parse error.
17
+ */
18
+ function parseFrontMatter(text) {
19
+ const m = FRONT_MATTER.exec(text);
20
+ if (!m)
21
+ return { data: {}, body: text };
22
+ const data = {};
23
+ for (const line of (m[1] ?? '').split(/\r?\n/)) {
24
+ const at = line.indexOf(':');
25
+ if (at <= 0)
26
+ continue;
27
+ const key = line.slice(0, at).trim();
28
+ const value = line
29
+ .slice(at + 1)
30
+ .trim()
31
+ .replace(/^["']|["']$/g, '');
32
+ if (key)
33
+ data[key] = value;
34
+ }
35
+ return { data, body: text.slice(m[0].length) };
36
+ }
37
+ /** `01-getting-started.md` → `getting-started`; `a/b/c.md` → `a-b-c`. */
38
+ function slugFor(file, root, front) {
39
+ if (front.slug)
40
+ return front.slug.trim();
41
+ const rel = (0, node_path_1.relative)(root, file).replace(/\.mdx?$/i, '');
42
+ return rel
43
+ .split(node_path_1.sep)
44
+ .map((part) => part.replace(/^\d+[-_]/, ''))
45
+ .join('-')
46
+ .toLowerCase()
47
+ .replace(/[^a-z0-9]+/g, '-')
48
+ .replace(/^-+|-+$/g, '');
49
+ }
50
+ /** The first `# heading`, else the front matter's title, else the slug. */
51
+ function titleFor(body, front, slug) {
52
+ if (front.title)
53
+ return front.title.trim();
54
+ const heading = /^#\s+(.+)$/m.exec(body);
55
+ return heading?.[1]?.trim() || slug;
56
+ }
57
+ /** Every `.md`/`.mdx` under a directory, depth-first, in a stable order. */
58
+ function readDocs(root) {
59
+ const out = [];
60
+ const walk = (dir) => {
61
+ for (const entry of (0, node_fs_1.readdirSync)(dir).sort()) {
62
+ if (entry.startsWith('.'))
63
+ continue;
64
+ const path = (0, node_path_1.join)(dir, entry);
65
+ if ((0, node_fs_1.statSync)(path).isDirectory()) {
66
+ walk(path);
67
+ continue;
68
+ }
69
+ if (!/\.mdx?$/i.test(entry))
70
+ continue;
71
+ const raw = (0, node_fs_1.readFileSync)(path, 'utf8');
72
+ const { data, body } = parseFrontMatter(raw);
73
+ const slug = slugFor(path, root, data);
74
+ out.push({ path, slug, title: titleFor(body, data, slug), markdown: body.trim() });
75
+ }
76
+ };
77
+ walk(root);
78
+ return out;
79
+ }
80
+ /**
81
+ * What publishing this directory would change, decided against what the space
82
+ * already holds.
83
+ *
84
+ * A file whose slug the space already has is an UPDATE; one it does not is a
85
+ * CREATE; a published piece with no file is an orphan — reported and left
86
+ * alone, because a directory is a source of truth for what it contains and not
87
+ * a statement about what should be deleted.
88
+ */
89
+ function planPublish(docs, existing) {
90
+ const bySlug = new Map(existing.filter((e) => e.slug).map((e) => [e.slug, e]));
91
+ const create = [];
92
+ const update = [];
93
+ for (const doc of docs) {
94
+ const match = bySlug.get(doc.slug);
95
+ if (match)
96
+ update.push({ ...doc, itemId: match.id });
97
+ else
98
+ create.push(doc);
99
+ }
100
+ const named = new Set(docs.map((d) => d.slug));
101
+ const orphans = existing
102
+ .filter((e) => e.slug && !named.has(e.slug))
103
+ .map((e) => ({ slug: e.slug, title: e.title }));
104
+ return { create, update, orphans };
105
+ }
106
+ /** The plan as a person reads it — the whole point of `--dry-run`. */
107
+ function describePlan(plan, root) {
108
+ const lines = [];
109
+ for (const d of plan.create)
110
+ lines.push(` create ${d.slug} ← ${(0, node_path_1.relative)(root, d.path) || d.path}`);
111
+ for (const d of plan.update)
112
+ lines.push(` update ${d.slug} ← ${(0, node_path_1.relative)(root, d.path) || d.path}`);
113
+ for (const o of plan.orphans)
114
+ lines.push(` (left) ${o.slug} — published here, no file in this directory`);
115
+ if (lines.length === 0)
116
+ lines.push(' nothing to do — no .md files found');
117
+ return lines;
118
+ }
119
+ //# sourceMappingURL=publish-dir.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish-dir.js","sourceRoot":"","sources":["../src/publish-dir.ts"],"names":[],"mappings":"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"}
package/dist/run.d.ts CHANGED
@@ -1,10 +1,22 @@
1
1
  import type { ForumulateClient } from '@forumulate/sdk';
2
- export declare const VERSION = "0.1.0";
2
+ /**
3
+ * Kept in step with package.json by `cli-version.test.ts` — they had drifted to
4
+ * 0.1.0 and 0.2.1, so `--version` reported a release that was never published.
5
+ */
6
+ export declare const VERSION = "0.3.0";
3
7
  export interface RunDeps {
4
8
  /** The API client. Injected so the CLI is testable without a live server. */
5
9
  client: ForumulateClient;
6
10
  out: (line: string) => void;
7
11
  err: (line: string) => void;
12
+ /**
13
+ * The API this invocation is talking to, and how it reads a secret the user
14
+ * types. Both injected for the same reason the client is: `login` writes a
15
+ * file and reads a terminal, and a test must be able to do neither.
16
+ */
17
+ baseUrl?: string;
18
+ prompt?: (question: string) => Promise<string>;
19
+ env?: NodeJS.ProcessEnv;
8
20
  }
9
21
  /**
10
22
  * Parse and execute a CLI invocation. Pure w.r.t. I/O (uses the injected deps),
package/dist/run.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAIxD,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,MAAM,WAAW,OAAO;IACtB,6EAA6E;IAC7E,MAAM,EAAE,gBAAgB,CAAC;IACzB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAgCD;;;GAGG;AACH,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAwKxE"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAMxD;;;GAGG;AACH,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,MAAM,WAAW,OAAO;IACtB,6EAA6E;IAC7E,MAAM,EAAE,gBAAgB,CAAC;IACzB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AA2CD;;;GAGG;AACH,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAkSxE"}
package/dist/run.js CHANGED
@@ -2,15 +2,26 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  exports.run = run;
5
+ const node_fs_1 = require("node:fs");
5
6
  const conformance_1 = require("./conformance");
6
7
  const doctor_1 = require("./doctor");
7
- exports.VERSION = '0.1.0';
8
+ const credentials_1 = require("./credentials");
9
+ const publish_dir_1 = require("./publish-dir");
10
+ /**
11
+ * Kept in step with package.json by `cli-version.test.ts` — they had drifted to
12
+ * 0.1.0 and 0.2.1, so `--version` reported a release that was never published.
13
+ */
14
+ exports.VERSION = '0.3.0';
8
15
  const HELP = `forumulate — Forumulate command-line interface
9
16
 
10
17
  Usage:
11
18
  forumulate <command> [args]
12
19
 
13
20
  Commands:
21
+ login [--token <pat>] Store a token for this API, so every other
22
+ command stops needing FORUMULATE_TOKEN in
23
+ the environment
24
+ logout Forget the stored token
14
25
  whoami Show the authenticated user
15
26
  orgs List your organizations
16
27
  spaces <orgId> List spaces in an org
@@ -18,6 +29,11 @@ Commands:
18
29
  piece's content lives
19
30
  search <orgId> <query...> Unified search across docs/forum/blog
20
31
  publish <orgId> <spaceId> <pageId> Publish a page
32
+ publish <orgId> <spaceId> <dir> Publish every .md in a directory — add
33
+ --dry-run to see the plan and write nothing
34
+ domains <orgId> <spaceId> List this space's domains and their state
35
+ domains verify <orgId> <spaceId> <hostname>
36
+ Re-run verification and say what is missing
21
37
  snapshot <orgId> <spaceId> <label> Create a space version snapshot
22
38
  conformance <collectionUrl> Run the Content Sync Protocol suite against
23
39
  any platform's collection endpoint
@@ -28,10 +44,12 @@ Commands:
28
44
 
29
45
  Environment:
30
46
  FORUMULATE_URL API base URL (default http://localhost:4000)
31
- FORUMULATE_TOKEN Personal Access Token (Bearer)
47
+ FORUMULATE_TOKEN Personal Access Token (Bearer). Overrides a stored one, so
48
+ CI keeps working exactly as it did.
32
49
 
33
50
  Flags:
34
51
  --json Emit raw JSON instead of a formatted summary
52
+ --dry-run Plan the work and write nothing (publish of a directory)
35
53
  --version Print the CLI version
36
54
  `;
37
55
  /**
@@ -40,7 +58,15 @@ Flags:
40
58
  */
41
59
  async function run(argv, deps) {
42
60
  const args = argv.filter((a) => !a.startsWith('--'));
43
- const flags = new Set(argv.filter((a) => a.startsWith('--')));
61
+ const flags = new Set(argv.filter((a) => a.startsWith('--')).map((a) => a.split('=')[0]));
62
+ /** `--token=abc` or `--token abc`, for the flags that carry a value. */
63
+ const flagValue = (name) => {
64
+ const inline = argv.find((a) => a.startsWith(`${name}=`));
65
+ if (inline)
66
+ return inline.slice(name.length + 1);
67
+ const at = argv.indexOf(name);
68
+ return at >= 0 ? argv[at + 1] : undefined;
69
+ };
44
70
  const json = flags.has('--json');
45
71
  const [cmd, ...rest] = args;
46
72
  if (flags.has('--version')) {
@@ -132,11 +158,57 @@ async function run(argv, deps) {
132
158
  return 0;
133
159
  }
134
160
  case 'publish': {
135
- const [orgId, spaceId, pageId] = rest;
136
- if (!orgId || !spaceId || !pageId)
137
- return usage(deps, 'publish <orgId> <spaceId> <pageId>');
138
- await deps.client.spaces.publishPage(orgId, spaceId, pageId);
139
- deps.out(`Published ${pageId}.`);
161
+ const [orgId, spaceId, target] = rest;
162
+ if (!orgId || !spaceId || !target)
163
+ return usage(deps, 'publish <orgId> <spaceId> <pageId|directory> [--dry-run]');
164
+ /*
165
+ * One verb, two objects. `publish <pageId>` published exactly one page
166
+ * by id, which is the thing a person doing docs-as-code never has:
167
+ * they have a directory (Crossly DX-2). A path that exists on disk is a
168
+ * directory publish; anything else is the id form, unchanged.
169
+ */
170
+ const isDir = (() => {
171
+ try {
172
+ return (0, node_fs_1.statSync)(target).isDirectory();
173
+ }
174
+ catch {
175
+ return false;
176
+ }
177
+ })();
178
+ if (!isDir) {
179
+ await deps.client.spaces.publishPage(orgId, spaceId, target);
180
+ deps.out(`Published ${target}.`);
181
+ return 0;
182
+ }
183
+ const docs = (0, publish_dir_1.readDocs)(target);
184
+ const { items } = await deps.client.items.list(orgId, spaceId, { limit: 200 });
185
+ const plan = (0, publish_dir_1.planPublish)(docs, items);
186
+ if (json)
187
+ dump(plan);
188
+ else {
189
+ deps.out(`${docs.length} file(s) in ${target}:`);
190
+ for (const line of (0, publish_dir_1.describePlan)(plan, target))
191
+ deps.out(line);
192
+ }
193
+ if (flags.has('--dry-run')) {
194
+ if (!json)
195
+ deps.out('--dry-run: nothing was written.');
196
+ return 0;
197
+ }
198
+ for (const doc of plan.create) {
199
+ const { item } = await deps.client.items.create(orgId, spaceId, {
200
+ title: doc.title,
201
+ slug: doc.slug,
202
+ body: doc.markdown,
203
+ });
204
+ await deps.client.items.publish(orgId, spaceId, item.id);
205
+ }
206
+ for (const doc of plan.update) {
207
+ await deps.client.items.setContent(orgId, spaceId, doc.itemId, { body: doc.markdown });
208
+ await deps.client.items.publish(orgId, spaceId, doc.itemId);
209
+ }
210
+ if (!json)
211
+ deps.out(`Published ${plan.create.length} new and ${plan.update.length} updated piece(s).`);
140
212
  return 0;
141
213
  }
142
214
  case 'snapshot': {
@@ -215,6 +287,86 @@ async function run(argv, deps) {
215
287
  }
216
288
  return report.failed > 0 ? 1 : 0;
217
289
  }
290
+ /*
291
+ * A token, stored for this API.
292
+ *
293
+ * Everything here needed `FORUMULATE_TOKEN` exported in the shell, which
294
+ * puts the token in the environment of every other process that shell
295
+ * runs and in somebody's history file (Crossly DX-2). It is verified
296
+ * before it is written — storing a token that does not work is a worse
297
+ * state than storing none, because the next failure is reported
298
+ * somewhere else entirely.
299
+ */
300
+ case 'login': {
301
+ const base = deps.baseUrl ?? process.env.FORUMULATE_URL ?? 'http://localhost:4000';
302
+ let token = flagValue('--token') ?? rest[0];
303
+ if (!token && deps.prompt) {
304
+ deps.out(`Create a token at ${base.replace(/\/api$/, '')}/o/<orgId>/settings/tokens`);
305
+ token = (await deps.prompt('Token: ')).trim();
306
+ }
307
+ if (!token)
308
+ return usage(deps, 'login --token <pat>');
309
+ const probe = new deps.client.constructor({
310
+ baseUrl: base,
311
+ token,
312
+ });
313
+ const { user } = await probe.auth.me();
314
+ const path = (0, credentials_1.storeToken)(base, token, deps.env);
315
+ deps.out(`Signed in as ${user.name} <${user.email}> for ${base}`);
316
+ deps.out(`Token stored in ${path} (readable only by you).`);
317
+ return 0;
318
+ }
319
+ case 'logout': {
320
+ const base = deps.baseUrl ?? process.env.FORUMULATE_URL ?? 'http://localhost:4000';
321
+ const had = (0, credentials_1.forgetToken)(base, deps.env);
322
+ deps.out(had ? `Forgot the token for ${base}.` : `No stored token for ${base}.`);
323
+ if (deps.env?.FORUMULATE_TOKEN ?? process.env.FORUMULATE_TOKEN)
324
+ deps.err('FORUMULATE_TOKEN is still set in this environment and still wins.');
325
+ return 0;
326
+ }
327
+ /*
328
+ * The domains a space answers at, and what a half-finished one is waiting
329
+ * for. `verify` re-runs the check and prints the DNS the customer has not
330
+ * added yet — the question "why is my domain not live" asked in the one
331
+ * place that can answer it (DX-2).
332
+ */
333
+ case 'domains': {
334
+ const [maybeVerb, ...tail] = rest;
335
+ const verifying = maybeVerb === 'verify';
336
+ const [orgId, spaceId, hostname] = verifying ? tail : rest;
337
+ if (!orgId || !spaceId)
338
+ return usage(deps, 'domains [verify] <orgId> <spaceId> [hostname]');
339
+ const { domains } = await deps.client.domains.list(orgId, spaceId);
340
+ if (!verifying) {
341
+ if (json)
342
+ dump(domains);
343
+ else if (domains.length === 0)
344
+ deps.out('No domains on this space.');
345
+ else
346
+ for (const d of domains)
347
+ deps.out(` ${stateOf(d)} ${d.hostname}${d.basePath || ''}`);
348
+ return 0;
349
+ }
350
+ const target = hostname
351
+ ? domains.find((d) => d.hostname.toLowerCase() === hostname.toLowerCase())
352
+ : domains[0];
353
+ if (!target) {
354
+ deps.err(hostname ? `No domain ${hostname} on this space.` : 'No domains on this space.');
355
+ return 1;
356
+ }
357
+ const { domain } = await deps.client.domains.verify(orgId, spaceId, target.id);
358
+ const setup = await deps.client.domains.setup(orgId, spaceId, target.id).catch(() => null);
359
+ if (json)
360
+ dump({ domain, setup });
361
+ else {
362
+ deps.out(`${stateOf(domain)} ${domain.hostname}${domain.basePath || ''}`);
363
+ for (const line of setupLines(domain, setup))
364
+ deps.out(` ${line}`);
365
+ }
366
+ // A failed verification is a 200 with `verified: false` — the exit code
367
+ // is what a script reads, so it has to say which happened.
368
+ return domain.verified ? 0 : 1;
369
+ }
218
370
  default:
219
371
  deps.err(`Unknown command: ${cmd}`);
220
372
  deps.out(HELP);
@@ -231,4 +383,38 @@ function usage(deps, form) {
231
383
  deps.err(`Usage: forumulate ${form}`);
232
384
  return 1;
233
385
  }
386
+ /** `live`, `verified (not serving yet)`, `unverified` — one word a person can scan. */
387
+ function stateOf(d) {
388
+ if (!d.verified)
389
+ return 'unverified';
390
+ return d.active === false ? 'verified (not serving)' : 'live';
391
+ }
392
+ /**
393
+ * What a half-finished domain is still waiting for, in the words the API uses.
394
+ *
395
+ * `mode` is the state machine (`unverified` → `dns`/`path` → `pending` →
396
+ * `verified`), `served` is whether traffic reaches us, and the verification
397
+ * record is the thing somebody has to go and add. Printing all three is the
398
+ * whole point: "not live" with no next step is the complaint this closes.
399
+ */
400
+ function setupLines(domain, setup) {
401
+ const out = [];
402
+ if (setup?.mode)
403
+ out.push(`state: ${setup.mode}${setup.served === false ? ' (not serving yet)' : ''}`);
404
+ if (setup?.message)
405
+ out.push(setup.message);
406
+ const record = domain.verificationRecord;
407
+ if (record)
408
+ out.push(`TXT ${record.name} → ${record.value}`);
409
+ if (setup?.dns?.expected) {
410
+ const found = setup.dns.found?.length ? setup.dns.found.join(', ') : 'nothing';
411
+ out.push(`DNS expected ${setup.dns.expected}, found ${found}`);
412
+ }
413
+ if (setup?.forward)
414
+ out.push(`forward ${setup.forward.path} → ${setup.forward.origin}`);
415
+ // Theirs to change, not ours — but invisible unless somebody says it.
416
+ if (setup?.crawlerBlocked)
417
+ out.push('a CDN in front of this domain is blocking AI crawlers');
418
+ return out;
419
+ }
234
420
  //# sourceMappingURL=run.js.map
package/dist/run.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@forumulate/cli",
3
- "version": "0.2.0",
4
- "description": "Command-line interface for Forumulate — manage orgs, spaces, docs, and search from your terminal.",
3
+ "version": "0.3.0",
4
+ "description": "Command-line interface for Forumulate \u2014 manage orgs, spaces, docs, and search from your terminal.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://forumulate.com/guides",
7
7
  "bugs": {
@@ -28,18 +28,19 @@
28
28
  "publishConfig": {
29
29
  "access": "public"
30
30
  },
31
+ "scripts": {
32
+ "build": "tsc -p tsconfig.json",
33
+ "typecheck": "tsc -p tsconfig.json --noEmit",
34
+ "test": "vitest run",
35
+ "prepublishOnly": "npm run build"
36
+ },
31
37
  "dependencies": {
32
- "@forumulate/sdk": "0.2.0"
38
+ "@forumulate/sdk": "workspace:*"
33
39
  },
34
40
  "devDependencies": {
35
41
  "@types/node": "^22.9.0",
36
42
  "typescript": "^5.6.3",
37
43
  "vitest": "^2.1.4"
38
44
  },
39
- "author": "Forumulate",
40
- "scripts": {
41
- "build": "tsc -p tsconfig.json",
42
- "typecheck": "tsc -p tsconfig.json --noEmit",
43
- "test": "vitest run"
44
- }
45
- }
45
+ "author": "Forumulate"
46
+ }