blodemd 0.0.4 → 0.0.6
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 +12 -1
- package/dev-server/app/[[...slug]]/page.tsx +139 -0
- package/dev-server/app/blodemd-dev/invalidate/route.ts +12 -0
- package/dev-server/app/blodemd-dev/static/[...path]/route.ts +32 -0
- package/dev-server/app/blodemd-dev/version/route.ts +14 -0
- package/dev-server/app/blodemd-internal/proxy/route.ts +86 -0
- package/dev-server/app/error.tsx +24 -0
- package/dev-server/app/globals.css +4 -0
- package/dev-server/app/layout.tsx +38 -0
- package/dev-server/app/not-found.tsx +18 -0
- package/dev-server/app/search/route.ts +17 -0
- package/dev-server/components/dev-reload-script.tsx +86 -0
- package/dev-server/components/providers.tsx +15 -0
- package/dev-server/lib/dev-state.ts +8 -0
- package/dev-server/lib/local-content-source.ts +103 -0
- package/dev-server/lib/local-runtime.tsx +558 -0
- package/dev-server/next.config.js +46 -0
- package/dev-server/package.json +57 -0
- package/dev-server/postcss.config.mjs +7 -0
- package/dev-server/public/glide-variable.woff2 +0 -0
- package/dev-server/tsconfig.json +49 -0
- package/dist/cli.mjs +299 -26
- package/dist/cli.mjs.map +1 -1
- package/docs/app/globals.css +455 -0
- package/docs/components/api/api-playground.tsx +295 -0
- package/docs/components/api/api-reference.tsx +121 -0
- package/docs/components/content/collection-index.tsx +114 -0
- package/docs/components/docs/contextual-menu.tsx +406 -0
- package/docs/components/docs/copy-page-menu.tsx +255 -0
- package/docs/components/docs/doc-header.tsx +192 -0
- package/docs/components/docs/doc-shell.tsx +289 -0
- package/docs/components/docs/doc-sidebar.tsx +206 -0
- package/docs/components/docs/doc-toc.tsx +45 -0
- package/docs/components/docs/mobile-nav.tsx +207 -0
- package/docs/components/mdx/accordion.tsx +83 -0
- package/docs/components/mdx/badge.tsx +79 -0
- package/docs/components/mdx/callout.tsx +88 -0
- package/docs/components/mdx/card.tsx +104 -0
- package/docs/components/mdx/code-block.tsx +75 -0
- package/docs/components/mdx/code-group.tsx +94 -0
- package/docs/components/mdx/color.tsx +87 -0
- package/docs/components/mdx/columns.tsx +25 -0
- package/docs/components/mdx/expandable.tsx +45 -0
- package/docs/components/mdx/field-layout.tsx +77 -0
- package/docs/components/mdx/frame.tsx +23 -0
- package/docs/components/mdx/get-text-content.ts +18 -0
- package/docs/components/mdx/icon.tsx +56 -0
- package/docs/components/mdx/index.tsx +96 -0
- package/docs/components/mdx/installer.tsx +20 -0
- package/docs/components/mdx/panel.tsx +11 -0
- package/docs/components/mdx/param-field.tsx +56 -0
- package/docs/components/mdx/preview.tsx +36 -0
- package/docs/components/mdx/prompt.tsx +63 -0
- package/docs/components/mdx/request-example.tsx +27 -0
- package/docs/components/mdx/response-field.tsx +42 -0
- package/docs/components/mdx/steps.tsx +92 -0
- package/docs/components/mdx/tabs.tsx +88 -0
- package/docs/components/mdx/tile.tsx +43 -0
- package/docs/components/mdx/tooltip.tsx +71 -0
- package/docs/components/mdx/tree.tsx +120 -0
- package/docs/components/mdx/type-table.tsx +71 -0
- package/docs/components/mdx/update.tsx +44 -0
- package/docs/components/mdx/video.tsx +12 -0
- package/docs/components/mdx/view.tsx +66 -0
- package/docs/components/providers.tsx +15 -0
- package/docs/components/ui/breadcrumb.tsx +92 -0
- package/docs/components/ui/button.tsx +90 -0
- package/docs/components/ui/card.tsx +92 -0
- package/docs/components/ui/command.tsx +139 -0
- package/docs/components/ui/dialog.tsx +97 -0
- package/docs/components/ui/field.tsx +237 -0
- package/docs/components/ui/input.tsx +105 -0
- package/docs/components/ui/label.tsx +22 -0
- package/docs/components/ui/popover.tsx +72 -0
- package/docs/components/ui/search.tsx +380 -0
- package/docs/components/ui/separator.tsx +26 -0
- package/docs/components/ui/sheet.tsx +104 -0
- package/docs/components/ui/sidebar.tsx +433 -0
- package/docs/components/ui/theme-toggle.tsx +62 -0
- package/docs/components/ui/tooltip.tsx +53 -0
- package/docs/lib/contextual-options.ts +193 -0
- package/docs/lib/docs-collection.ts +22 -0
- package/docs/lib/mdx.ts +90 -0
- package/docs/lib/navigation.ts +288 -0
- package/docs/lib/openapi.ts +158 -0
- package/docs/lib/routes.ts +10 -0
- package/docs/lib/server-cache.ts +83 -0
- package/docs/lib/shiki.ts +35 -0
- package/docs/lib/theme.ts +29 -0
- package/docs/lib/toc.ts +2 -0
- package/docs/lib/utils.ts +5 -0
- package/package.json +34 -3
- package/packages/@repo/common/dist/index.d.ts +9 -0
- package/packages/@repo/common/dist/index.d.ts.map +1 -0
- package/packages/@repo/common/dist/index.js +42 -0
- package/packages/@repo/common/package.json +34 -0
- package/packages/@repo/common/src/common.unit.test.ts +55 -0
- package/packages/@repo/common/src/index.ts +51 -0
- package/packages/@repo/contracts/dist/api-key.d.ts +30 -0
- package/packages/@repo/contracts/dist/api-key.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/api-key.js +20 -0
- package/packages/@repo/contracts/dist/dates.d.ts +4 -0
- package/packages/@repo/contracts/dist/dates.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/dates.js +2 -0
- package/packages/@repo/contracts/dist/deployment.d.ts +71 -0
- package/packages/@repo/contracts/dist/deployment.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/deployment.js +46 -0
- package/packages/@repo/contracts/dist/domain.d.ts +94 -0
- package/packages/@repo/contracts/dist/domain.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/domain.js +36 -0
- package/packages/@repo/contracts/dist/ids.d.ts +14 -0
- package/packages/@repo/contracts/dist/ids.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/ids.js +10 -0
- package/packages/@repo/contracts/dist/index.d.ts +10 -0
- package/packages/@repo/contracts/dist/index.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/index.js +11 -0
- package/packages/@repo/contracts/dist/pagination.d.ts +23 -0
- package/packages/@repo/contracts/dist/pagination.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/pagination.js +15 -0
- package/packages/@repo/contracts/dist/project.d.ts +25 -0
- package/packages/@repo/contracts/dist/project.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/project.js +23 -0
- package/packages/@repo/contracts/dist/tenant.d.ts +99 -0
- package/packages/@repo/contracts/dist/tenant.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/tenant.js +36 -0
- package/packages/@repo/contracts/dist/user.d.ts +9 -0
- package/packages/@repo/contracts/dist/user.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/user.js +9 -0
- package/packages/@repo/contracts/package.json +37 -0
- package/packages/@repo/contracts/src/api-key.ts +27 -0
- package/packages/@repo/contracts/src/dates.ts +4 -0
- package/packages/@repo/contracts/src/deployment.ts +73 -0
- package/packages/@repo/contracts/src/domain.ts +51 -0
- package/packages/@repo/contracts/src/ids.ts +22 -0
- package/packages/@repo/contracts/src/index.ts +11 -0
- package/packages/@repo/contracts/src/pagination.ts +21 -0
- package/packages/@repo/contracts/src/project.ts +30 -0
- package/packages/@repo/contracts/src/tenant.ts +54 -0
- package/packages/@repo/contracts/src/user.ts +12 -0
- package/packages/@repo/models/dist/docs-config.d.ts +985 -0
- package/packages/@repo/models/dist/docs-config.d.ts.map +1 -0
- package/packages/@repo/models/dist/docs-config.js +548 -0
- package/packages/@repo/models/dist/index.d.ts +3 -0
- package/packages/@repo/models/dist/index.d.ts.map +1 -0
- package/packages/@repo/models/dist/index.js +3 -0
- package/packages/@repo/models/dist/tenant.d.ts +25 -0
- package/packages/@repo/models/dist/tenant.d.ts.map +1 -0
- package/packages/@repo/models/dist/tenant.js +1 -0
- package/packages/@repo/models/package.json +37 -0
- package/packages/@repo/models/src/docs-config.ts +648 -0
- package/packages/@repo/models/src/index.ts +3 -0
- package/packages/@repo/models/src/tenant.ts +29 -0
- package/packages/@repo/prebuild/dist/index.d.ts +2 -0
- package/packages/@repo/prebuild/dist/index.d.ts.map +1 -0
- package/packages/@repo/prebuild/dist/index.js +2 -0
- package/packages/@repo/prebuild/dist/openapi.d.ts +43 -0
- package/packages/@repo/prebuild/dist/openapi.d.ts.map +1 -0
- package/packages/@repo/prebuild/dist/openapi.js +58 -0
- package/packages/@repo/prebuild/package.json +39 -0
- package/packages/@repo/prebuild/src/index.ts +2 -0
- package/packages/@repo/prebuild/src/openapi.ts +116 -0
- package/packages/@repo/previewing/dist/blob-source.d.ts +16 -0
- package/packages/@repo/previewing/dist/blob-source.d.ts.map +1 -0
- package/packages/@repo/previewing/dist/blob-source.js +110 -0
- package/packages/@repo/previewing/dist/content-source.d.ts +12 -0
- package/packages/@repo/previewing/dist/content-source.d.ts.map +1 -0
- package/packages/@repo/previewing/dist/content-source.js +1 -0
- package/packages/@repo/previewing/dist/fs-source.d.ts +11 -0
- package/packages/@repo/previewing/dist/fs-source.d.ts.map +1 -0
- package/packages/@repo/previewing/dist/fs-source.js +79 -0
- package/packages/@repo/previewing/dist/index.d.ts +120 -0
- package/packages/@repo/previewing/dist/index.d.ts.map +1 -0
- package/packages/@repo/previewing/dist/index.js +984 -0
- package/packages/@repo/previewing/package.json +41 -0
- package/packages/@repo/previewing/src/blob-source.ts +167 -0
- package/packages/@repo/previewing/src/content-source.ts +12 -0
- package/packages/@repo/previewing/src/fs-source.ts +111 -0
- package/packages/@repo/previewing/src/index.ts +1490 -0
- package/packages/@repo/previewing/src/index.unit.test.ts +290 -0
- package/packages/@repo/validation/dist/index.d.ts +12 -0
- package/packages/@repo/validation/dist/index.d.ts.map +1 -0
- package/packages/@repo/validation/dist/index.js +30 -0
- package/packages/@repo/validation/package.json +37 -0
- package/packages/@repo/validation/src/index.ts +59 -0
- package/packages/@repo/validation/src/mintlify-docs-schema.json +5016 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"allowJs": true,
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"declarationMap": true,
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"incremental": false,
|
|
8
|
+
"isolatedModules": true,
|
|
9
|
+
"jsx": "preserve",
|
|
10
|
+
"lib": [
|
|
11
|
+
"es2022",
|
|
12
|
+
"DOM",
|
|
13
|
+
"DOM.Iterable"
|
|
14
|
+
],
|
|
15
|
+
"module": "ESNext",
|
|
16
|
+
"moduleDetection": "force",
|
|
17
|
+
"moduleResolution": "Bundler",
|
|
18
|
+
"noEmit": true,
|
|
19
|
+
"noUncheckedIndexedAccess": true,
|
|
20
|
+
"paths": {
|
|
21
|
+
"@/*": [
|
|
22
|
+
"../docs/*"
|
|
23
|
+
],
|
|
24
|
+
"@dev/*": [
|
|
25
|
+
"./*"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"plugins": [
|
|
29
|
+
{
|
|
30
|
+
"name": "next"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"resolveJsonModule": true,
|
|
34
|
+
"skipLibCheck": true,
|
|
35
|
+
"strict": true,
|
|
36
|
+
"strictNullChecks": true,
|
|
37
|
+
"target": "ES2022"
|
|
38
|
+
},
|
|
39
|
+
"exclude": [
|
|
40
|
+
"node_modules"
|
|
41
|
+
],
|
|
42
|
+
"include": [
|
|
43
|
+
"**/*.ts",
|
|
44
|
+
"**/*.tsx",
|
|
45
|
+
"next-env.d.ts",
|
|
46
|
+
"next.config.js",
|
|
47
|
+
".next/types/**/*.ts"
|
|
48
|
+
]
|
|
49
|
+
}
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
3
4
|
import fs, { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
5
|
import path, { join } from "node:path";
|
|
5
6
|
import { confirm, intro, isCancel, log, password, spinner } from "@clack/prompts";
|
|
@@ -7,6 +8,11 @@ import chalk from "chalk";
|
|
|
7
8
|
import { Command } from "commander";
|
|
8
9
|
import open from "open";
|
|
9
10
|
import { homedir } from "node:os";
|
|
11
|
+
import { once } from "node:events";
|
|
12
|
+
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
import { createFsSource, loadSiteConfig } from "@repo/previewing";
|
|
15
|
+
import { watch } from "chokidar";
|
|
10
16
|
import { createServer } from "node:http";
|
|
11
17
|
import { createHash, randomBytes } from "node:crypto";
|
|
12
18
|
//#region src/constants.ts
|
|
@@ -283,6 +289,257 @@ const resolveTokenStatus = (token) => {
|
|
|
283
289
|
};
|
|
284
290
|
};
|
|
285
291
|
//#endregion
|
|
292
|
+
//#region src/dev/resolve-root.ts
|
|
293
|
+
const CONFIG_FILE$1 = "docs.json";
|
|
294
|
+
const fileExists$2 = async (filePath) => {
|
|
295
|
+
try {
|
|
296
|
+
await fs.access(filePath);
|
|
297
|
+
return true;
|
|
298
|
+
} catch {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
const resolveDocsRoot$1 = async (dir) => {
|
|
303
|
+
if (dir) return path.resolve(process.cwd(), dir);
|
|
304
|
+
const candidates = [
|
|
305
|
+
process.cwd(),
|
|
306
|
+
path.join(process.cwd(), "docs"),
|
|
307
|
+
path.join(process.cwd(), "apps/docs")
|
|
308
|
+
];
|
|
309
|
+
for (const candidate of candidates) if (await fileExists$2(path.join(candidate, CONFIG_FILE$1))) return candidate;
|
|
310
|
+
return process.cwd();
|
|
311
|
+
};
|
|
312
|
+
const validateDocsRoot = async (root) => {
|
|
313
|
+
const result = await loadSiteConfig(createFsSource(root));
|
|
314
|
+
if (!result.ok) throw new CliError(result.errors.join("\n"), EXIT_CODES.VALIDATION, `Make sure ${CONFIG_FILE$1} exists and is valid JSON.`);
|
|
315
|
+
return result;
|
|
316
|
+
};
|
|
317
|
+
//#endregion
|
|
318
|
+
//#region src/dev/watcher.ts
|
|
319
|
+
const INVALIDATE_ENDPOINT = "/blodemd-dev/invalidate";
|
|
320
|
+
const WATCH_DEBOUNCE_MS = 100;
|
|
321
|
+
const normalizeRelativePath$1 = (root, filePath) => path.relative(root, filePath).split(path.sep).join("/");
|
|
322
|
+
const isDirectoryEvent = (event) => event === "addDir" || event === "unlinkDir";
|
|
323
|
+
const createDevWatcher = ({ port, root }) => {
|
|
324
|
+
const watcher = watch(root, {
|
|
325
|
+
ignoreInitial: true,
|
|
326
|
+
ignored: [
|
|
327
|
+
"**/.git/**",
|
|
328
|
+
"**/.next/**",
|
|
329
|
+
"**/dist/**",
|
|
330
|
+
"**/node_modules/**"
|
|
331
|
+
]
|
|
332
|
+
});
|
|
333
|
+
let flushTimer = null;
|
|
334
|
+
let pendingKind = "content";
|
|
335
|
+
const pendingPaths = /* @__PURE__ */ new Set();
|
|
336
|
+
const flush = async () => {
|
|
337
|
+
flushTimer = null;
|
|
338
|
+
const paths = [...pendingPaths];
|
|
339
|
+
const kind = pendingKind;
|
|
340
|
+
pendingPaths.clear();
|
|
341
|
+
pendingKind = "content";
|
|
342
|
+
if (!paths.length) return;
|
|
343
|
+
try {
|
|
344
|
+
const response = await fetch(`http://127.0.0.1:${port}${INVALIDATE_ENDPOINT}`, {
|
|
345
|
+
body: JSON.stringify({
|
|
346
|
+
kind,
|
|
347
|
+
paths
|
|
348
|
+
}),
|
|
349
|
+
headers: { "Content-Type": "application/json" },
|
|
350
|
+
method: "POST"
|
|
351
|
+
});
|
|
352
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
353
|
+
} catch (error) {
|
|
354
|
+
log.error(`Failed to invalidate preview cache: ${error instanceof Error ? error.message : "unknown error"}`);
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
watcher.on("all", (event, changedPath) => {
|
|
358
|
+
if (isDirectoryEvent(event)) return;
|
|
359
|
+
const relativePath = normalizeRelativePath$1(root, changedPath);
|
|
360
|
+
pendingPaths.add(relativePath);
|
|
361
|
+
if (path.basename(changedPath) === "docs.json") pendingKind = "config";
|
|
362
|
+
if (flushTimer) clearTimeout(flushTimer);
|
|
363
|
+
flushTimer = setTimeout(() => {
|
|
364
|
+
flush();
|
|
365
|
+
}, WATCH_DEBOUNCE_MS);
|
|
366
|
+
});
|
|
367
|
+
return { async close() {
|
|
368
|
+
if (flushTimer) {
|
|
369
|
+
clearTimeout(flushTimer);
|
|
370
|
+
await flush();
|
|
371
|
+
}
|
|
372
|
+
await watcher.close();
|
|
373
|
+
} };
|
|
374
|
+
};
|
|
375
|
+
//#endregion
|
|
376
|
+
//#region src/dev/command.ts
|
|
377
|
+
const DEV_READY_ENDPOINT = "/blodemd-dev/version";
|
|
378
|
+
const DEV_READY_TIMEOUT_MS = 45e3;
|
|
379
|
+
const parsePositiveInteger$1 = (value, label) => {
|
|
380
|
+
const parsed = Number.parseInt(value, 10);
|
|
381
|
+
if (!Number.isInteger(parsed) || parsed <= 0) throw new CliError(`${label} must be a positive integer.`, EXIT_CODES.VALIDATION);
|
|
382
|
+
return parsed;
|
|
383
|
+
};
|
|
384
|
+
const fileExists$1 = async (filePath) => {
|
|
385
|
+
try {
|
|
386
|
+
await fs.access(filePath);
|
|
387
|
+
return true;
|
|
388
|
+
} catch {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
/**
|
|
393
|
+
* Derive the CLI npm package root from the running script path.
|
|
394
|
+
* The CLI entry point is at `<pkg-root>/dist/cli.mjs`.
|
|
395
|
+
*/
|
|
396
|
+
const resolveCliPackageRoot = (cliFilePath) => path.dirname(path.dirname(cliFilePath));
|
|
397
|
+
/**
|
|
398
|
+
* Check if a shipped dev-server exists alongside the CLI (npm-installed mode).
|
|
399
|
+
* Verifies both the dev-server directory AND that `next` is resolvable
|
|
400
|
+
* (it's a dependency when npm-installed, but not in the monorepo).
|
|
401
|
+
*/
|
|
402
|
+
const findStandaloneDevServer = async (cliPackageRoot) => {
|
|
403
|
+
const devServerDir = path.join(cliPackageRoot, "dev-server");
|
|
404
|
+
if (!await fileExists$1(path.join(devServerDir, "next.config.js"))) return null;
|
|
405
|
+
try {
|
|
406
|
+
createRequire(path.join(cliPackageRoot, "package.json")).resolve("next/package.json");
|
|
407
|
+
} catch {
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
return {
|
|
411
|
+
devServerDir,
|
|
412
|
+
mode: "standalone",
|
|
413
|
+
packagesDir: path.join(cliPackageRoot, "packages")
|
|
414
|
+
};
|
|
415
|
+
};
|
|
416
|
+
/**
|
|
417
|
+
* Resolve the `next` CLI binary from the blodemd package's own dependencies.
|
|
418
|
+
*/
|
|
419
|
+
const resolveNextBin = (cliPackageRoot) => {
|
|
420
|
+
const nextPkgPath = createRequire(path.join(cliPackageRoot, "package.json")).resolve("next/package.json");
|
|
421
|
+
return path.join(path.dirname(nextPkgPath), "dist", "bin", "next");
|
|
422
|
+
};
|
|
423
|
+
const findMonorepoRoot = async (start) => {
|
|
424
|
+
let current = start;
|
|
425
|
+
while (true) {
|
|
426
|
+
const packageJsonPath = path.join(current, "package.json");
|
|
427
|
+
if (await fileExists$1(packageJsonPath)) {
|
|
428
|
+
const raw = await fs.readFile(packageJsonPath, "utf8");
|
|
429
|
+
const workspaces = JSON.parse(raw).workspaces ?? [];
|
|
430
|
+
if (workspaces.includes("apps/*") && workspaces.includes("packages/*")) return current;
|
|
431
|
+
}
|
|
432
|
+
const parent = path.dirname(current);
|
|
433
|
+
if (parent === current) break;
|
|
434
|
+
current = parent;
|
|
435
|
+
}
|
|
436
|
+
throw new CliError("Could not locate the blodemd dev server.", EXIT_CODES.ERROR, "Make sure blodemd is installed correctly (npm i blodemd).");
|
|
437
|
+
};
|
|
438
|
+
const resolveDevServer = async (cliFilePath) => {
|
|
439
|
+
const standalone = await findStandaloneDevServer(resolveCliPackageRoot(cliFilePath));
|
|
440
|
+
if (standalone) return standalone;
|
|
441
|
+
return {
|
|
442
|
+
mode: "monorepo",
|
|
443
|
+
repoRoot: await findMonorepoRoot(path.dirname(cliFilePath))
|
|
444
|
+
};
|
|
445
|
+
};
|
|
446
|
+
const spawnDevServer = (server, { root, port }) => {
|
|
447
|
+
if (server.mode === "standalone") {
|
|
448
|
+
const nextBin = resolveNextBin(path.dirname(server.devServerDir));
|
|
449
|
+
return spawn(process.execPath, [nextBin, "dev"], {
|
|
450
|
+
cwd: server.devServerDir,
|
|
451
|
+
env: {
|
|
452
|
+
...process.env,
|
|
453
|
+
BLODEMD_PACKAGES_DIR: server.packagesDir,
|
|
454
|
+
DOCS_ROOT: root,
|
|
455
|
+
NODE_PATH: [server.packagesDir, process.env.NODE_PATH].filter(Boolean).join(path.delimiter),
|
|
456
|
+
PORT: String(port)
|
|
457
|
+
},
|
|
458
|
+
stdio: "inherit"
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
return spawn(process.platform === "win32" ? "npm.cmd" : "npm", [
|
|
462
|
+
"run",
|
|
463
|
+
"dev",
|
|
464
|
+
"--workspace=dev-server"
|
|
465
|
+
], {
|
|
466
|
+
cwd: server.repoRoot,
|
|
467
|
+
env: {
|
|
468
|
+
...process.env,
|
|
469
|
+
DOCS_ROOT: root,
|
|
470
|
+
PORT: String(port)
|
|
471
|
+
},
|
|
472
|
+
stdio: "inherit"
|
|
473
|
+
});
|
|
474
|
+
};
|
|
475
|
+
const waitForServer = async ({ child, port }) => {
|
|
476
|
+
const url = `http://localhost:${port}${DEV_READY_ENDPOINT}`;
|
|
477
|
+
const startedAt = Date.now();
|
|
478
|
+
while (Date.now() - startedAt < DEV_READY_TIMEOUT_MS) {
|
|
479
|
+
if (child.exitCode !== null) throw new CliError("The local dev server exited before it became ready.", EXIT_CODES.ERROR);
|
|
480
|
+
try {
|
|
481
|
+
if ((await fetch(url, {
|
|
482
|
+
cache: "no-store",
|
|
483
|
+
headers: { accept: "application/json" }
|
|
484
|
+
})).ok) return;
|
|
485
|
+
} catch {}
|
|
486
|
+
await setTimeout$1(500);
|
|
487
|
+
}
|
|
488
|
+
throw new CliError("Timed out waiting for the local dev server to start.", EXIT_CODES.ERROR);
|
|
489
|
+
};
|
|
490
|
+
const devCommand = async ({ dir, openBrowser, port: portValue }) => {
|
|
491
|
+
intro(chalk.bold("blodemd dev"));
|
|
492
|
+
try {
|
|
493
|
+
const port = parsePositiveInteger$1(portValue, "Port");
|
|
494
|
+
const root = await resolveDocsRoot$1(dir);
|
|
495
|
+
await validateDocsRoot(root);
|
|
496
|
+
const server = await resolveDevServer(fileURLToPath(import.meta.url));
|
|
497
|
+
const localUrl = `http://localhost:${port}`;
|
|
498
|
+
log.info(`Docs root: ${chalk.cyan(root)}`);
|
|
499
|
+
const child = spawnDevServer(server, {
|
|
500
|
+
port,
|
|
501
|
+
root
|
|
502
|
+
});
|
|
503
|
+
let watcher = null;
|
|
504
|
+
let shuttingDown = false;
|
|
505
|
+
const closeAll = async () => {
|
|
506
|
+
if (shuttingDown) return;
|
|
507
|
+
shuttingDown = true;
|
|
508
|
+
if (watcher) {
|
|
509
|
+
await watcher.close();
|
|
510
|
+
watcher = null;
|
|
511
|
+
}
|
|
512
|
+
if (child.exitCode === null && !child.killed) child.kill("SIGTERM");
|
|
513
|
+
};
|
|
514
|
+
process.once("SIGINT", closeAll);
|
|
515
|
+
process.once("SIGTERM", closeAll);
|
|
516
|
+
try {
|
|
517
|
+
await waitForServer({
|
|
518
|
+
child,
|
|
519
|
+
port
|
|
520
|
+
});
|
|
521
|
+
watcher = await createDevWatcher({
|
|
522
|
+
port,
|
|
523
|
+
root
|
|
524
|
+
});
|
|
525
|
+
log.success(`Dev server running at ${chalk.cyan(localUrl)}`);
|
|
526
|
+
if (openBrowser) await open(localUrl);
|
|
527
|
+
const [code, signal] = await once(child, "exit");
|
|
528
|
+
if (shuttingDown || signal === "SIGINT" || signal === "SIGTERM") return;
|
|
529
|
+
if (code !== 0) throw new CliError(`The local dev server exited with code ${code ?? "unknown"}.`, EXIT_CODES.ERROR);
|
|
530
|
+
} finally {
|
|
531
|
+
await closeAll();
|
|
532
|
+
process.removeListener("SIGINT", closeAll);
|
|
533
|
+
process.removeListener("SIGTERM", closeAll);
|
|
534
|
+
}
|
|
535
|
+
} catch (error) {
|
|
536
|
+
const cliError = toCliError(error);
|
|
537
|
+
log.error(cliError.message);
|
|
538
|
+
if (cliError.hint) log.info(cliError.hint);
|
|
539
|
+
process.exitCode = cliError.exitCode;
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
//#endregion
|
|
286
543
|
//#region src/oauth-callback.ts
|
|
287
544
|
const SUCCESS_HTML = "<!doctype html><html><head><meta charset=\"utf-8\"/><title>Blode.md CLI</title></head><body><h2>Logged in! You can close this tab.</h2></body></html>";
|
|
288
545
|
const escapeHtml = (text) => text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """);
|
|
@@ -294,6 +551,7 @@ const waitForOAuthCode = (options) => {
|
|
|
294
551
|
if (!Number.isInteger(port) || port <= 0) return Promise.reject(new CliError("OAuth redirect URL requires an explicit port", EXIT_CODES.ERROR));
|
|
295
552
|
return new Promise((resolve, reject) => {
|
|
296
553
|
let settled = false;
|
|
554
|
+
const sockets = /* @__PURE__ */ new Set();
|
|
297
555
|
const settle = (ok, value) => {
|
|
298
556
|
if (settled) return;
|
|
299
557
|
settled = true;
|
|
@@ -302,6 +560,7 @@ const waitForOAuthCode = (options) => {
|
|
|
302
560
|
if (ok) resolve(value);
|
|
303
561
|
else reject(value);
|
|
304
562
|
});
|
|
563
|
+
for (const socket of sockets) socket.destroy();
|
|
305
564
|
};
|
|
306
565
|
const httpServer = createServer((request, response) => {
|
|
307
566
|
if (!request.url) {
|
|
@@ -341,6 +600,10 @@ const waitForOAuthCode = (options) => {
|
|
|
341
600
|
response.end(SUCCESS_HTML);
|
|
342
601
|
settle(true, code);
|
|
343
602
|
});
|
|
603
|
+
httpServer.on("connection", (socket) => {
|
|
604
|
+
sockets.add(socket);
|
|
605
|
+
socket.once("close", () => sockets.delete(socket));
|
|
606
|
+
});
|
|
344
607
|
httpServer.on("error", (error) => {
|
|
345
608
|
settle(false, new CliError(`Failed to start callback server on ${host}:${port}: ${error.message}`, EXIT_CODES.ERROR));
|
|
346
609
|
});
|
|
@@ -506,21 +769,39 @@ const autoCreateProject = async (project, apiUrl, headers) => {
|
|
|
506
769
|
log.info(`API key for CI: ${chalk.dim(createResult.token)}`);
|
|
507
770
|
return true;
|
|
508
771
|
};
|
|
772
|
+
const MAX_BATCH_BYTES = 4 * 1024 * 1024;
|
|
509
773
|
const uploadFiles = async (files, root, apiPath, deploymentId, headers, s) => {
|
|
510
774
|
s.start(`Uploading ${files.length} files`);
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
775
|
+
const items = await Promise.all(files.map(async (filePath) => {
|
|
776
|
+
return {
|
|
777
|
+
contentBase64: (await fs.readFile(filePath)).toString("base64"),
|
|
778
|
+
contentType: getContentType(filePath),
|
|
779
|
+
path: normalizeRelativePath(root, filePath)
|
|
780
|
+
};
|
|
781
|
+
}));
|
|
782
|
+
const batches = [];
|
|
783
|
+
let current = [];
|
|
784
|
+
let currentBytes = 0;
|
|
785
|
+
for (const item of items) {
|
|
786
|
+
const itemBytes = item.contentBase64.length + item.path.length + 64;
|
|
787
|
+
if (current.length > 0 && currentBytes + itemBytes > MAX_BATCH_BYTES) {
|
|
788
|
+
batches.push(current);
|
|
789
|
+
current = [];
|
|
790
|
+
currentBytes = 0;
|
|
791
|
+
}
|
|
792
|
+
current.push(item);
|
|
793
|
+
currentBytes += itemBytes;
|
|
794
|
+
}
|
|
795
|
+
if (current.length > 0) batches.push(current);
|
|
796
|
+
let uploaded = 0;
|
|
797
|
+
for (const batch of batches) {
|
|
798
|
+
await requestJson(apiPath(`/${deploymentId}/files/batch`), {
|
|
799
|
+
body: JSON.stringify({ files: batch }),
|
|
520
800
|
headers,
|
|
521
801
|
method: "POST"
|
|
522
|
-
},
|
|
523
|
-
|
|
802
|
+
}, "Failed to upload files");
|
|
803
|
+
uploaded += batch.length;
|
|
804
|
+
s.message(`Uploading files (${uploaded}/${files.length})`);
|
|
524
805
|
}
|
|
525
806
|
s.stop(`Uploaded ${chalk.cyan(String(files.length))} files`);
|
|
526
807
|
};
|
|
@@ -624,14 +905,7 @@ program.command("whoami").description("Show current authentication").action(asyn
|
|
|
624
905
|
const email = resolved.user?.email ?? await fetchUserEmail(process.env["BLODEMD_API_URL"] ?? "https://api.blode.md", resolved.token);
|
|
625
906
|
if (email) log.info(`Logged in as ${chalk.cyan(email)}`);
|
|
626
907
|
else log.info("Logged in (could not fetch user details).");
|
|
627
|
-
if (resolved.expiresAt)
|
|
628
|
-
if (status.expired) log.warn("Session has expired. Run \"blodemd login\" to re-authenticate.");
|
|
629
|
-
else if (status.expiresInSeconds !== null) {
|
|
630
|
-
const hours = Math.floor(status.expiresInSeconds / 3600);
|
|
631
|
-
const minutes = Math.floor(status.expiresInSeconds % 3600 / 60);
|
|
632
|
-
log.info(`Session expires in ${hours}h ${minutes}m`);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
908
|
+
if (resolved.expiresAt && status.expired) log.warn("Session has expired. Run \"blodemd login\" to re-authenticate.");
|
|
635
909
|
} catch (error) {
|
|
636
910
|
reportCommandError("Whoami failed", error);
|
|
637
911
|
}
|
|
@@ -731,12 +1005,11 @@ program.command("push").description("Deploy docs").argument("[dir]", "docs direc
|
|
|
731
1005
|
reportCommandError("Push failed", error);
|
|
732
1006
|
}
|
|
733
1007
|
});
|
|
734
|
-
program.command("dev").description("Start the docs dev server").action(() => {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
});
|
|
1008
|
+
program.command("dev").description("Start the local docs dev server").option("-p, --port <port>", "Port number", "3030").option("-d, --dir <dir>", "Docs directory").option("--no-open", "Don't open browser").action(async (options) => await devCommand({
|
|
1009
|
+
dir: options.dir,
|
|
1010
|
+
openBrowser: options.open ?? true,
|
|
1011
|
+
port: options.port
|
|
1012
|
+
}));
|
|
740
1013
|
program.parse();
|
|
741
1014
|
//#endregion
|
|
742
1015
|
export {};
|