@c-time/frelio-cli 1.3.0 → 1.3.11

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.
@@ -6,7 +6,7 @@ import fs from 'node:fs';
6
6
  import path from 'node:path';
7
7
  import os from 'node:os';
8
8
  import { exec, commandExists, log, logStep, logSuccess, logError } from '../lib/shell.js';
9
- import { getLatestRelease, downloadTarball } from '../lib/github-release.js';
9
+ import { getLatestRelease, downloadTarball, extractNpmTarball } from '../lib/npm-registry.js';
10
10
  import { generateInitialContent } from '../lib/initial-content.js';
11
11
  import { generateConfigJson, generateWranglerToml, generateUsersIndex, generateVersionJson, generateRedirects, generateRoutesJson, generateStorageFunction, generateViteConfig, generatePackageJson, generateTsConfig, generateTsConfigNode, generateStagingDomain, writeFile, ensureDir, } from '../lib/templates.js';
12
12
  import { validateContentRepo, validateR2PublicUrl, validateRequired } from '../lib/validators.js';
@@ -559,35 +559,31 @@ jobs:
559
559
  async function extractBundle(projectDir) {
560
560
  const release = await getLatestRelease();
561
561
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'frelio-'));
562
- const tarPath = await downloadTarball(release, tmpDir);
563
- // tar で展開
564
- const { extract } = await import('tar');
565
- await extract({ file: tarPath, cwd: tmpDir });
566
- // 展開されたディレクトリを特定
567
- const entries = fs.readdirSync(tmpDir).filter((e) => e.startsWith('frelio-cms-'));
568
- const bundleDir = entries.find((e) => fs.statSync(path.join(tmpDir, e)).isDirectory());
569
- if (!bundleDir) {
570
- throw new Error('Bundle directory not found in tarball');
571
- }
572
- const srcDir = path.join(tmpDir, bundleDir);
573
- // admin/ をコピー
574
- if (fs.existsSync(path.join(srcDir, 'admin'))) {
575
- copyDir(path.join(srcDir, 'admin'), path.join(projectDir, 'admin'));
576
- }
577
- // functions/ をコピー
578
- if (fs.existsSync(path.join(srcDir, 'functions'))) {
579
- copyDir(path.join(srcDir, 'functions'), path.join(projectDir, 'functions'));
562
+ try {
563
+ const tarPath = await downloadTarball(release, tmpDir);
564
+ const { adminDir, functionsDir, workersDir } = await extractNpmTarball(tarPath, tmpDir);
565
+ // admin/ をコピー(dist/ の中身から functions/ を除く)
566
+ if (fs.existsSync(adminDir)) {
567
+ copyDir(adminDir, path.join(projectDir, 'admin'), ['functions']);
568
+ }
569
+ // functions/ をコピー(dist/functions/ → functions/)
570
+ if (fs.existsSync(functionsDir)) {
571
+ copyDir(functionsDir, path.join(projectDir, 'functions'));
572
+ }
573
+ // workers/ をコピー(Pages Functions が import する)
574
+ if (fs.existsSync(workersDir)) {
575
+ copyDir(workersDir, path.join(projectDir, 'workers'));
576
+ }
580
577
  }
581
- // workers/ をコピー(Pages Functions が import する)
582
- if (fs.existsSync(path.join(srcDir, 'workers'))) {
583
- copyDir(path.join(srcDir, 'workers'), path.join(projectDir, 'workers'));
578
+ finally {
579
+ fs.rmSync(tmpDir, { recursive: true, force: true });
584
580
  }
585
- // クリーンアップ
586
- fs.rmSync(tmpDir, { recursive: true, force: true });
587
581
  }
588
- function copyDir(src, dest) {
582
+ function copyDir(src, dest, exclude = []) {
589
583
  fs.mkdirSync(dest, { recursive: true });
590
584
  for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
585
+ if (exclude.includes(entry.name))
586
+ continue;
591
587
  const srcPath = path.join(src, entry.name);
592
588
  const destPath = path.join(dest, entry.name);
593
589
  if (entry.isDirectory()) {
@@ -4,7 +4,7 @@
4
4
  import fs from 'node:fs';
5
5
  import path from 'node:path';
6
6
  import os from 'node:os';
7
- import { getLatestRelease, getRelease, downloadTarball } from '../lib/github-release.js';
7
+ import { getLatestRelease, getRelease, downloadTarball, extractNpmTarball } from '../lib/npm-registry.js';
8
8
  import { log, logSuccess, logError } from '../lib/shell.js';
9
9
  export async function updateCommand(options) {
10
10
  log('');
@@ -34,37 +34,29 @@ export async function updateCommand(options) {
34
34
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'frelio-update-'));
35
35
  try {
36
36
  const tarPath = await downloadTarball(release, tmpDir);
37
- const { extract } = await import('tar');
38
- await extract({ file: tarPath, cwd: tmpDir });
39
- // 展開されたディレクトリを特定
40
- const entries = fs.readdirSync(tmpDir).filter((e) => e.startsWith('frelio-cms-'));
41
- const bundleDir = entries.find((e) => fs.statSync(path.join(tmpDir, e)).isDirectory());
42
- if (!bundleDir) {
43
- throw new Error('Bundle directory not found in tarball');
44
- }
45
- const srcDir = path.join(tmpDir, bundleDir);
46
- // admin/ を置き換え
47
- if (fs.existsSync(path.join(srcDir, 'admin'))) {
37
+ const { adminDir: srcAdminDir, functionsDir: srcFunctionsDir, workersDir: srcWorkersDir } = await extractNpmTarball(tarPath, tmpDir);
38
+ // admin/ を置き換え(dist/ の中身から functions/ を除く)
39
+ if (fs.existsSync(srcAdminDir)) {
48
40
  fs.rmSync(adminDir, { recursive: true, force: true });
49
- copyDir(path.join(srcDir, 'admin'), adminDir);
41
+ copyDir(srcAdminDir, adminDir, ['functions']);
50
42
  logSuccess('admin/ を更新しました');
51
43
  }
52
44
  // functions/api/ を置き換え(functions/storage/ はユーザー管理なので保持)
53
45
  const functionsApiDir = path.join(projectDir, 'functions', 'api');
54
- if (fs.existsSync(path.join(srcDir, 'functions', 'api'))) {
46
+ if (fs.existsSync(path.join(srcFunctionsDir, 'api'))) {
55
47
  if (fs.existsSync(functionsApiDir)) {
56
48
  fs.rmSync(functionsApiDir, { recursive: true, force: true });
57
49
  }
58
- copyDir(path.join(srcDir, 'functions', 'api'), functionsApiDir);
50
+ copyDir(path.join(srcFunctionsDir, 'api'), functionsApiDir);
59
51
  logSuccess('functions/api/ を更新しました');
60
52
  }
61
53
  // workers/ を置き換え(Pages Functions が import する)
62
- const workersDir = path.join(projectDir, 'workers');
63
- if (fs.existsSync(path.join(srcDir, 'workers'))) {
64
- if (fs.existsSync(workersDir)) {
65
- fs.rmSync(workersDir, { recursive: true, force: true });
54
+ const workersDestDir = path.join(projectDir, 'workers');
55
+ if (fs.existsSync(srcWorkersDir)) {
56
+ if (fs.existsSync(workersDestDir)) {
57
+ fs.rmSync(workersDestDir, { recursive: true, force: true });
66
58
  }
67
- copyDir(path.join(srcDir, 'workers'), workersDir);
59
+ copyDir(srcWorkersDir, workersDestDir);
68
60
  logSuccess('workers/ を更新しました');
69
61
  }
70
62
  // config.json を復元
@@ -80,9 +72,11 @@ export async function updateCommand(options) {
80
72
  fs.rmSync(tmpDir, { recursive: true, force: true });
81
73
  }
82
74
  }
83
- function copyDir(src, dest) {
75
+ function copyDir(src, dest, exclude = []) {
84
76
  fs.mkdirSync(dest, { recursive: true });
85
77
  for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
78
+ if (exclude.includes(entry.name))
79
+ continue;
86
80
  const srcPath = path.join(src, entry.name);
87
81
  const destPath = path.join(dest, entry.name);
88
82
  if (entry.isDirectory()) {
@@ -0,0 +1,26 @@
1
+ /**
2
+ * npm registry からの CMS バンドル取得
3
+ */
4
+ export type Release = {
5
+ tag_name: string;
6
+ tarballUrl: string;
7
+ };
8
+ export declare function getLatestRelease(): Promise<Release>;
9
+ export declare function getRelease(version: string): Promise<Release>;
10
+ export declare function downloadTarball(release: Release, destDir: string): Promise<string>;
11
+ /**
12
+ * npm tarball を展開し、バンドルディレクトリのパスを返す。
13
+ *
14
+ * npm tarball は `package/` ディレクトリに展開される。
15
+ * 中身は:
16
+ * package/dist/ — SPA (index.html, assets/) + bundled functions (functions/)
17
+ * package/workers/ — Worker ソース
18
+ */
19
+ export declare function extractNpmTarball(tarPath: string, tmpDir: string): Promise<{
20
+ /** SPA ファイル (functions/ を除く dist/ の中身) */
21
+ adminDir: string;
22
+ /** バンドル済み Pages Functions */
23
+ functionsDir: string;
24
+ /** Worker ソース */
25
+ workersDir: string;
26
+ }>;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * npm registry からの CMS バンドル取得
3
+ */
4
+ import { createWriteStream } from 'node:fs';
5
+ import { pipeline } from 'node:stream/promises';
6
+ import { Readable } from 'node:stream';
7
+ import path from 'node:path';
8
+ const PACKAGE_NAME = '@c-time/frelio-cms';
9
+ const REGISTRY = 'https://registry.npmjs.org';
10
+ export async function getLatestRelease() {
11
+ const res = await fetch(`${REGISTRY}/${PACKAGE_NAME}/latest`);
12
+ if (!res.ok) {
13
+ throw new Error(`Failed to fetch latest version from npm: ${res.status} ${res.statusText}`);
14
+ }
15
+ const info = (await res.json());
16
+ return {
17
+ tag_name: `v${info.version}`,
18
+ tarballUrl: info.dist.tarball,
19
+ };
20
+ }
21
+ export async function getRelease(version) {
22
+ const ver = version.startsWith('v') ? version.slice(1) : version;
23
+ const res = await fetch(`${REGISTRY}/${PACKAGE_NAME}/${ver}`);
24
+ if (!res.ok) {
25
+ throw new Error(`Version ${ver} not found on npm: ${res.status}`);
26
+ }
27
+ const info = (await res.json());
28
+ return {
29
+ tag_name: `v${info.version}`,
30
+ tarballUrl: info.dist.tarball,
31
+ };
32
+ }
33
+ export async function downloadTarball(release, destDir) {
34
+ const destPath = path.join(destDir, `frelio-cms-${release.tag_name}.tgz`);
35
+ const res = await fetch(release.tarballUrl);
36
+ if (!res.ok || !res.body) {
37
+ throw new Error(`Failed to download tarball: ${res.status}`);
38
+ }
39
+ const readable = Readable.fromWeb(res.body);
40
+ await pipeline(readable, createWriteStream(destPath));
41
+ return destPath;
42
+ }
43
+ /**
44
+ * npm tarball を展開し、バンドルディレクトリのパスを返す。
45
+ *
46
+ * npm tarball は `package/` ディレクトリに展開される。
47
+ * 中身は:
48
+ * package/dist/ — SPA (index.html, assets/) + bundled functions (functions/)
49
+ * package/workers/ — Worker ソース
50
+ */
51
+ export async function extractNpmTarball(tarPath, tmpDir) {
52
+ const { extract } = await import('tar');
53
+ await extract({ file: tarPath, cwd: tmpDir });
54
+ return {
55
+ /** SPA ファイル (functions/ を除く dist/ の中身) */
56
+ adminDir: path.join(tmpDir, 'package', 'dist'),
57
+ /** バンドル済み Pages Functions */
58
+ functionsDir: path.join(tmpDir, 'package', 'dist', 'functions'),
59
+ /** Worker ソース */
60
+ workersDir: path.join(tmpDir, 'package', 'workers'),
61
+ };
62
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c-time/frelio-cli",
3
- "version": "1.3.0",
3
+ "version": "1.3.11",
4
4
  "description": "Frelio CMS setup CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,15 +0,0 @@
1
- /**
2
- * GitHub Release からの tarball ダウンロード
3
- */
4
- type ReleaseAsset = {
5
- name: string;
6
- browser_download_url: string;
7
- };
8
- type Release = {
9
- tag_name: string;
10
- assets: ReleaseAsset[];
11
- };
12
- export declare function getLatestRelease(): Promise<Release>;
13
- export declare function getRelease(version: string): Promise<Release>;
14
- export declare function downloadTarball(release: Release, destDir: string): Promise<string>;
15
- export {};
@@ -1,41 +0,0 @@
1
- /**
2
- * GitHub Release からの tarball ダウンロード
3
- */
4
- import { createWriteStream } from 'node:fs';
5
- import { pipeline } from 'node:stream/promises';
6
- import { Readable } from 'node:stream';
7
- import path from 'node:path';
8
- const REPO = 'ctime-projects/frelio';
9
- export async function getLatestRelease() {
10
- const res = await fetch(`https://api.github.com/repos/${REPO}/releases/latest`, {
11
- headers: { Accept: 'application/vnd.github.v3+json' },
12
- });
13
- if (!res.ok) {
14
- throw new Error(`Failed to fetch latest release: ${res.status} ${res.statusText}`);
15
- }
16
- return res.json();
17
- }
18
- export async function getRelease(version) {
19
- const tag = version.startsWith('v') ? version : `v${version}`;
20
- const res = await fetch(`https://api.github.com/repos/${REPO}/releases/tags/${tag}`, {
21
- headers: { Accept: 'application/vnd.github.v3+json' },
22
- });
23
- if (!res.ok) {
24
- throw new Error(`Release ${tag} not found: ${res.status}`);
25
- }
26
- return res.json();
27
- }
28
- export async function downloadTarball(release, destDir) {
29
- const asset = release.assets.find((a) => a.name.endsWith('.tar.gz'));
30
- if (!asset) {
31
- throw new Error('No tarball found in release assets');
32
- }
33
- const destPath = path.join(destDir, asset.name);
34
- const res = await fetch(asset.browser_download_url);
35
- if (!res.ok || !res.body) {
36
- throw new Error(`Failed to download: ${res.status}`);
37
- }
38
- const readable = Readable.fromWeb(res.body);
39
- await pipeline(readable, createWriteStream(destPath));
40
- return destPath;
41
- }