tego 1.3.48 → 1.3.50

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.
@@ -2,3 +2,5 @@ export declare const DEFAULT_DEV_PLUGINS_PATH: string;
2
2
  export declare const DEFAULT_REMOTE_PLUGINS_PATH: string;
3
3
  export declare const DEFAULT_BUILTIN_PLUGINS_PATH: string;
4
4
  export declare const DEFAULT_WEB_PACKAGE_NAME = "@tego/web";
5
+ export declare const INDEX_TEGO_URL = "https://tachybase.org/index.tego.json";
6
+ export declare const LAST_UPDATE_FILE_SUFFIX = ".last-update-at";
package/lib/constants.js CHANGED
@@ -30,7 +30,9 @@ __export(constants_exports, {
30
30
  DEFAULT_BUILTIN_PLUGINS_PATH: () => DEFAULT_BUILTIN_PLUGINS_PATH,
31
31
  DEFAULT_DEV_PLUGINS_PATH: () => DEFAULT_DEV_PLUGINS_PATH,
32
32
  DEFAULT_REMOTE_PLUGINS_PATH: () => DEFAULT_REMOTE_PLUGINS_PATH,
33
- DEFAULT_WEB_PACKAGE_NAME: () => DEFAULT_WEB_PACKAGE_NAME
33
+ DEFAULT_WEB_PACKAGE_NAME: () => DEFAULT_WEB_PACKAGE_NAME,
34
+ INDEX_TEGO_URL: () => INDEX_TEGO_URL,
35
+ LAST_UPDATE_FILE_SUFFIX: () => LAST_UPDATE_FILE_SUFFIX
34
36
  });
35
37
  module.exports = __toCommonJS(constants_exports);
36
38
  var import_node_path = __toESM(require("node:path"));
@@ -40,10 +42,14 @@ const DEFAULT_DEV_PLUGINS_PATH = import_node_path.default.join(process.env.TEGO_
40
42
  const DEFAULT_REMOTE_PLUGINS_PATH = import_node_path.default.join(process.env.TEGO_RUNTIME_HOME, "plugins", "remote");
41
43
  const DEFAULT_BUILTIN_PLUGINS_PATH = import_node_path.default.join(process.env.TEGO_RUNTIME_HOME, "plugins", "builtin");
42
44
  const DEFAULT_WEB_PACKAGE_NAME = "@tego/web";
45
+ const INDEX_TEGO_URL = "https://tachybase.org/index.tego.json";
46
+ const LAST_UPDATE_FILE_SUFFIX = ".last-update-at";
43
47
  // Annotate the CommonJS export names for ESM import in node:
44
48
  0 && (module.exports = {
45
49
  DEFAULT_BUILTIN_PLUGINS_PATH,
46
50
  DEFAULT_DEV_PLUGINS_PATH,
47
51
  DEFAULT_REMOTE_PLUGINS_PATH,
48
- DEFAULT_WEB_PACKAGE_NAME
52
+ DEFAULT_WEB_PACKAGE_NAME,
53
+ INDEX_TEGO_URL,
54
+ LAST_UPDATE_FILE_SUFFIX
49
55
  });
package/lib/prepare.js CHANGED
@@ -38,12 +38,10 @@ var import_node_process = __toESM(require("node:process"));
38
38
  var import_yocto_spinner = __toESM(require("@socketregistry/yocto-spinner/index.cjs"));
39
39
  var import_execa = __toESM(require("execa"));
40
40
  var import_constants = require("./constants");
41
- var import_default_modules = require("./default-modules");
42
- var import_default_plugins = require("./default-plugins");
43
41
  var import_utils = require("./utils");
44
42
  async function prepare({
45
43
  name,
46
- plugins = import_default_plugins.defaultPlugins,
44
+ plugins = [],
47
45
  init = false
48
46
  }) {
49
47
  if (init) {
@@ -67,21 +65,14 @@ async function prepare({
67
65
  await (0, import_utils.downloadTar)(import_constants.DEFAULT_WEB_PACKAGE_NAME, `${import_constants.DEFAULT_BUILTIN_PLUGINS_PATH}/${import_constants.DEFAULT_WEB_PACKAGE_NAME}`);
68
66
  spinner.success();
69
67
  console.log();
70
- console.log("\u{1F680} ~ start download ~ required modules");
71
- const moduleNames = import_default_modules.defaultModules.map((moduleName) => `@tachybase/module-${moduleName}`);
72
- let index = 1;
73
- for (const moduleName of moduleNames) {
74
- const spinner2 = (0, import_yocto_spinner.default)({ text: `[${index++}/${moduleNames.length}] Loading ${moduleName}` }).start();
75
- await (0, import_utils.downloadTar)(moduleName, `${import_constants.DEFAULT_BUILTIN_PLUGINS_PATH}/${moduleName}`);
76
- if (npmExist) {
77
- await npmInstall(`${import_constants.DEFAULT_BUILTIN_PLUGINS_PATH}/${moduleName}`, spinner2);
78
- }
79
- spinner2.success();
80
- }
81
- console.log();
82
68
  console.log("\u{1F680} ~ start download ~ plugins");
83
- index = 1;
84
- const pluginNames = plugins.map((pluginName) => `@tachybase/plugin-${pluginName}`);
69
+ const manager = new import_utils.TegoIndexManager({
70
+ indexUrl: import_constants.INDEX_TEGO_URL,
71
+ baseDir: import_node_process.default.env.TEGO_HOME
72
+ });
73
+ const pluginIndex = await manager.getIndex();
74
+ const pluginNames = plugins.length > 0 ? plugins : pluginIndex.plugins.map((plugin) => plugin.name);
75
+ let index = 1;
85
76
  for (const pluginName of pluginNames) {
86
77
  const spinner2 = (0, import_yocto_spinner.default)({ text: `[${index++}/${pluginNames.length}] Loading ${pluginName}` }).start();
87
78
  await (0, import_utils.downloadTar)(pluginName, `${import_constants.DEFAULT_BUILTIN_PLUGINS_PATH}/${pluginName}`);
package/lib/utils.d.ts CHANGED
@@ -2,3 +2,16 @@ export declare function initEnvFile(name: string): void;
2
2
  export declare function parseEnvironment(): void;
3
3
  export declare function guessServePath(): string | false;
4
4
  export declare function downloadTar(packageName: string, target: string): Promise<void>;
5
+ export declare class TegoIndexManager {
6
+ private indexUrl;
7
+ private indexFile;
8
+ private lastUpdateFile;
9
+ constructor({ indexUrl, baseDir, lastUpdateSuffix, }: {
10
+ indexUrl: string;
11
+ baseDir: string;
12
+ lastUpdateSuffix?: string;
13
+ });
14
+ private readLastUpdateTime;
15
+ private fetchIndexFile;
16
+ getIndex(): Promise<any>;
17
+ }
package/lib/utils.js CHANGED
@@ -28,6 +28,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var utils_exports = {};
30
30
  __export(utils_exports, {
31
+ TegoIndexManager: () => TegoIndexManager,
31
32
  downloadTar: () => downloadTar,
32
33
  guessServePath: () => guessServePath,
33
34
  initEnvFile: () => initEnvFile,
@@ -49,9 +50,9 @@ function initEnvFile(name) {
49
50
  const envPath = (0, import_node_path.resolve)(name, ".env");
50
51
  if (!import_node_fs.default.existsSync(envPath)) {
51
52
  import_node_fs.default.copyFileSync((0, import_node_path.resolve)(__dirname, "../presets/.env.example"), envPath);
52
- console.log(".env file created.");
53
+ console.info(".env file created.");
53
54
  } else {
54
- console.log(".env file already exists.");
55
+ console.info(".env file already exists.");
55
56
  }
56
57
  }
57
58
  __name(initEnvFile, "initEnvFile");
@@ -100,7 +101,7 @@ function parseEnvironment() {
100
101
  path: (0, import_node_path.resolve)(process.cwd(), process.env.APP_ENV_PATH || ".env")
101
102
  });
102
103
  if (!process.env.TEGO_RUNTIME_HOME && !process.env.TEGO_RUNTIME_NAME && import_node_fs.default.existsSync((0, import_node_path.resolve)(process.cwd(), "storage"))) {
103
- process.env.TEGO_RUNTIME_HOME = (0, import_node_path.resolve)(process.cwd(), "storage");
104
+ process.env.TEGO_RUNTIME_HOME = process.cwd();
104
105
  }
105
106
  for (const key in env) {
106
107
  if (!process.env[key]) {
@@ -141,36 +142,109 @@ function guessServePath() {
141
142
  return false;
142
143
  }
143
144
  __name(guessServePath, "guessServePath");
144
- async function getTarballUrl(pkgName, version = "latest") {
145
+ async function getTarballMeta(pkgName, version = "latest") {
145
146
  const info = await import_npm_registry_fetch.default.json(`/${pkgName}/${version}`, {
146
- query: { fullMetadata: true }
147
+ query: { fullMetadata: true },
148
+ registry: process.env.NPM_CONFIG_REGISTRY ?? "https://registry.npmjs.org"
147
149
  });
148
- return info.dist.tarball;
150
+ return { url: info.dist.tarball, shasum: info.dist.shasum };
149
151
  }
150
- __name(getTarballUrl, "getTarballUrl");
152
+ __name(getTarballMeta, "getTarballMeta");
153
+ function sha1(buffer) {
154
+ return (0, import_node_crypto.createHash)("sha1").update(buffer).digest("hex");
155
+ }
156
+ __name(sha1, "sha1");
157
+ async function getFileSha1(filePath) {
158
+ const buffer = await (0, import_promises.readFile)(filePath);
159
+ return sha1(buffer);
160
+ }
161
+ __name(getFileSha1, "getFileSha1");
162
+ async function fileExists(path) {
163
+ try {
164
+ await (0, import_promises.access)(path);
165
+ return true;
166
+ } catch {
167
+ return false;
168
+ }
169
+ }
170
+ __name(fileExists, "fileExists");
151
171
  async function downloadTar(packageName, target) {
152
- const url = await getTarballUrl(packageName);
153
- const tarballFile = (0, import_node_path.join)(target, "..", `${(0, import_node_crypto.createHash)("md5").update(packageName).digest("hex")}-tarball.gz`);
154
- await (0, import_promises.mkdir)((0, import_node_path.dirname)(tarballFile), { recursive: true });
155
- const writer = (0, import_node_fs.createWriteStream)(tarballFile);
156
- const response = await fetch(url);
157
- if (!response.ok || !response.body) {
158
- throw new Error(`Failed to fetch tarball: ${response.statusText}`);
159
- }
160
- await (0, import_promises2.pipeline)(response.body, writer);
172
+ const { url, shasum } = await getTarballMeta(packageName);
173
+ const baseName = `${packageName.replace("/", "__")}@${shasum}`;
174
+ const cachedTar = (0, import_node_path.join)(process.env.TEGO_HOME, "plugins", `${baseName}.tar.gz`);
175
+ const cachedSha = (0, import_node_path.join)(process.env.TEGO_HOME, "plugins", `${baseName}.sha1`);
176
+ const exists = await fileExists(cachedTar);
177
+ const shaMatches = exists ? await getFileSha1(cachedTar) === shasum : false;
178
+ if (!exists || !shaMatches) {
179
+ await (0, import_promises.mkdir)((0, import_node_path.dirname)(cachedTar), { recursive: true });
180
+ const res = await fetch(url);
181
+ if (!res.ok || !res.body) {
182
+ throw new Error(`Failed to fetch tarball: ${res.statusText}`);
183
+ }
184
+ const writer = (0, import_node_fs.createWriteStream)(cachedTar);
185
+ await (0, import_promises2.pipeline)(res.body, writer);
186
+ const actualSha = await getFileSha1(cachedTar);
187
+ if (actualSha !== shasum) {
188
+ await (0, import_promises.unlink)(cachedTar);
189
+ throw new Error(`Downloaded tarball hash mismatch for ${packageName}`);
190
+ }
191
+ await (0, import_promises.writeFile)(cachedSha, shasum, "utf-8");
192
+ }
193
+ await (0, import_promises.rm)(target, { recursive: true, force: true });
161
194
  await (0, import_promises.mkdir)(target, { recursive: true });
162
195
  await tar.x({
163
- file: tarballFile,
196
+ file: cachedTar,
164
197
  gzip: true,
165
198
  cwd: target,
166
199
  strip: 1,
167
200
  k: true
168
201
  });
169
- await (0, import_promises.unlink)(tarballFile);
170
202
  }
171
203
  __name(downloadTar, "downloadTar");
204
+ const ONE_DAY_MS = 24 * 60 * 60 * 1e3;
205
+ const _TegoIndexManager = class _TegoIndexManager {
206
+ constructor({
207
+ indexUrl,
208
+ baseDir,
209
+ lastUpdateSuffix = ".last-update-at"
210
+ }) {
211
+ this.indexUrl = indexUrl;
212
+ this.indexFile = (0, import_node_path.join)(baseDir, "index.tego.json");
213
+ this.lastUpdateFile = (0, import_node_path.join)(baseDir, "index.tego.json" + lastUpdateSuffix);
214
+ }
215
+ async readLastUpdateTime() {
216
+ try {
217
+ const content = await (0, import_promises.readFile)(this.lastUpdateFile, "utf-8");
218
+ return new Date(content.trim());
219
+ } catch {
220
+ return null;
221
+ }
222
+ }
223
+ async fetchIndexFile() {
224
+ const res = await fetch(this.indexUrl);
225
+ if (!res.ok) {
226
+ throw new Error(`Failed to fetch ${this.indexUrl}: ${res.statusText}`);
227
+ }
228
+ const json = await res.json();
229
+ await (0, import_promises.writeFile)(this.indexFile, JSON.stringify(json, null, 2), "utf-8");
230
+ await (0, import_promises.writeFile)(this.lastUpdateFile, (/* @__PURE__ */ new Date()).toISOString(), "utf-8");
231
+ return json;
232
+ }
233
+ async getIndex() {
234
+ const lastUpdated = await this.readLastUpdateTime();
235
+ if (lastUpdated && Date.now() - lastUpdated.getTime() < ONE_DAY_MS) {
236
+ console.info(`\u{1F552} index.tego.json was updated within 1 day, skipping download.`);
237
+ const content = await (0, import_promises.readFile)(this.indexFile, "utf-8");
238
+ return JSON.parse(content);
239
+ }
240
+ return await this.fetchIndexFile();
241
+ }
242
+ };
243
+ __name(_TegoIndexManager, "TegoIndexManager");
244
+ let TegoIndexManager = _TegoIndexManager;
172
245
  // Annotate the CommonJS export names for ESM import in node:
173
246
  0 && (module.exports = {
247
+ TegoIndexManager,
174
248
  downloadTar,
175
249
  guessServePath,
176
250
  initEnvFile,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tego",
3
- "version": "1.3.48",
3
+ "version": "1.3.50",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "tego",
@@ -49,20 +49,20 @@
49
49
  "umzug": "3.8.2",
50
50
  "winston": "3.17.0",
51
51
  "winston-daily-rotate-file": "^5.0.0",
52
- "@tachybase/acl": "1.3.48",
53
- "@tachybase/actions": "1.3.48",
54
- "@tachybase/auth": "1.3.48",
55
- "@tachybase/data-source": "1.3.48",
56
- "@tachybase/cache": "1.3.48",
57
- "@tachybase/database": "1.3.48",
58
- "@tachybase/evaluators": "1.3.48",
59
- "@tachybase/globals": "1.3.48",
60
- "@tachybase/loader": "1.3.48",
61
- "@tachybase/logger": "1.3.48",
62
- "@tachybase/resourcer": "1.3.48",
63
- "@tachybase/utils": "1.3.48",
64
- "@tachybase/schema": "1.3.48",
65
- "@tego/core": "1.3.48"
52
+ "@tachybase/acl": "1.3.50",
53
+ "@tachybase/auth": "1.3.50",
54
+ "@tachybase/cache": "1.3.50",
55
+ "@tachybase/actions": "1.3.50",
56
+ "@tachybase/data-source": "1.3.50",
57
+ "@tachybase/database": "1.3.50",
58
+ "@tachybase/evaluators": "1.3.50",
59
+ "@tachybase/loader": "1.3.50",
60
+ "@tachybase/globals": "1.3.50",
61
+ "@tachybase/logger": "1.3.50",
62
+ "@tachybase/schema": "1.3.50",
63
+ "@tego/core": "1.3.50",
64
+ "@tachybase/utils": "1.3.50",
65
+ "@tachybase/resourcer": "1.3.50"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@types/lodash": "4.17.20",
package/src/constants.ts CHANGED
@@ -9,3 +9,5 @@ export const DEFAULT_DEV_PLUGINS_PATH = path.join(process.env.TEGO_RUNTIME_HOME,
9
9
  export const DEFAULT_REMOTE_PLUGINS_PATH = path.join(process.env.TEGO_RUNTIME_HOME, 'plugins', 'remote');
10
10
  export const DEFAULT_BUILTIN_PLUGINS_PATH = path.join(process.env.TEGO_RUNTIME_HOME, 'plugins', 'builtin');
11
11
  export const DEFAULT_WEB_PACKAGE_NAME = '@tego/web';
12
+ export const INDEX_TEGO_URL = 'https://tachybase.org/index.tego.json';
13
+ export const LAST_UPDATE_FILE_SUFFIX = '.last-update-at';
package/src/prepare.ts CHANGED
@@ -5,14 +5,17 @@ import process from 'node:process';
5
5
  import yoctoSpinner from '@socketregistry/yocto-spinner/index.cjs';
6
6
  import execa from 'execa';
7
7
 
8
- import { DEFAULT_BUILTIN_PLUGINS_PATH, DEFAULT_WEB_PACKAGE_NAME } from './constants';
9
- import { defaultModules } from './default-modules';
10
- import { defaultPlugins } from './default-plugins';
11
- import { downloadTar, initEnvFile } from './utils';
8
+ import {
9
+ DEFAULT_BUILTIN_PLUGINS_PATH,
10
+ DEFAULT_WEB_PACKAGE_NAME,
11
+ INDEX_TEGO_URL,
12
+ LAST_UPDATE_FILE_SUFFIX,
13
+ } from './constants';
14
+ import { downloadTar, initEnvFile, TegoIndexManager } from './utils';
12
15
 
13
16
  export async function prepare({
14
17
  name,
15
- plugins = defaultPlugins,
18
+ plugins = [],
16
19
  init = false,
17
20
  }: {
18
21
  name?: string;
@@ -45,24 +48,15 @@ export async function prepare({
45
48
  spinner.success();
46
49
  console.log();
47
50
 
48
- console.log('🚀 ~ start download ~ required modules');
49
- // 安装必须得模块
50
- const moduleNames = defaultModules.map((moduleName) => `@tachybase/module-${moduleName}`);
51
- let index = 1;
52
- for (const moduleName of moduleNames) {
53
- const spinner = yoctoSpinner({ text: `[${index++}/${moduleNames.length}] Loading ${moduleName}` }).start();
54
- await downloadTar(moduleName, `${DEFAULT_BUILTIN_PLUGINS_PATH}/${moduleName}`);
55
- if (npmExist) {
56
- await npmInstall(`${DEFAULT_BUILTIN_PLUGINS_PATH}/${moduleName}`, spinner);
57
- }
58
- spinner.success();
59
- }
60
- console.log();
61
-
62
51
  console.log('🚀 ~ start download ~ plugins');
63
- // 安装可选的模块,由参数指定
64
- index = 1;
65
- const pluginNames = plugins.map((pluginName: string) => `@tachybase/plugin-${pluginName}`);
52
+ const manager = new TegoIndexManager({
53
+ indexUrl: INDEX_TEGO_URL,
54
+ baseDir: process.env.TEGO_HOME!,
55
+ });
56
+ const pluginIndex = await manager.getIndex();
57
+ // download plugins
58
+ const pluginNames = plugins.length > 0 ? plugins : pluginIndex.plugins.map((plugin: { name: string }) => plugin.name);
59
+ let index = 1;
66
60
  for (const pluginName of pluginNames) {
67
61
  const spinner = yoctoSpinner({ text: `[${index++}/${pluginNames.length}] Loading ${pluginName}` }).start();
68
62
  await downloadTar(pluginName, `${DEFAULT_BUILTIN_PLUGINS_PATH}/${pluginName}`);
package/src/utils.ts CHANGED
@@ -5,7 +5,7 @@ import fs, {
5
5
  writeFileSync as _writeFileSync,
6
6
  createWriteStream,
7
7
  } from 'node:fs';
8
- import { mkdir, unlink } from 'node:fs/promises';
8
+ import { access, mkdir, readFile, rm, unlink, writeFile } from 'node:fs/promises';
9
9
  import os from 'node:os';
10
10
  import { dirname, join, resolve } from 'node:path';
11
11
  import { pipeline } from 'node:stream/promises';
@@ -15,15 +15,15 @@ import { config } from 'dotenv';
15
15
  import npmRegistryFetch from 'npm-registry-fetch';
16
16
  import * as tar from 'tar';
17
17
 
18
- import { DEFAULT_WEB_PACKAGE_NAME } from './constants';
18
+ import { DEFAULT_WEB_PACKAGE_NAME, INDEX_TEGO_URL, LAST_UPDATE_FILE_SUFFIX } from './constants';
19
19
 
20
20
  export function initEnvFile(name: string) {
21
21
  const envPath = resolve(name, '.env');
22
22
  if (!fs.existsSync(envPath)) {
23
23
  fs.copyFileSync(resolve(__dirname, '../presets/.env.example'), envPath);
24
- console.log('.env file created.');
24
+ console.info('.env file created.');
25
25
  } else {
26
- console.log('.env file already exists.');
26
+ console.info('.env file already exists.');
27
27
  }
28
28
  }
29
29
 
@@ -78,7 +78,7 @@ export function parseEnvironment() {
78
78
  !process.env.TEGO_RUNTIME_NAME &&
79
79
  fs.existsSync(resolve(process.cwd(), 'storage'))
80
80
  ) {
81
- process.env.TEGO_RUNTIME_HOME = resolve(process.cwd(), 'storage');
81
+ process.env.TEGO_RUNTIME_HOME = process.cwd();
82
82
  }
83
83
 
84
84
  for (const key in env) {
@@ -126,34 +126,125 @@ export function guessServePath() {
126
126
  return false;
127
127
  }
128
128
 
129
- async function getTarballUrl(pkgName, version = 'latest') {
129
+ async function getTarballMeta(pkgName, version = 'latest') {
130
130
  const info = await npmRegistryFetch.json(`/${pkgName}/${version}`, {
131
131
  query: { fullMetadata: true },
132
+ registry: process.env.NPM_CONFIG_REGISTRY ?? 'https://registry.npmjs.org',
132
133
  });
133
- return info.dist.tarball;
134
+ return { url: info.dist.tarball, shasum: info.dist.shasum };
134
135
  }
135
136
 
136
- export async function downloadTar(packageName: string, target: string) {
137
- const url = await getTarballUrl(packageName);
138
- const tarballFile = join(target, '..', `${createHash('md5').update(packageName).digest('hex')}-tarball.gz`);
139
- await mkdir(dirname(tarballFile), { recursive: true });
140
- const writer = createWriteStream(tarballFile);
141
- const response = await fetch(url);
142
- if (!response.ok || !response.body) {
143
- throw new Error(`Failed to fetch tarball: ${response.statusText}`);
137
+ function sha1(buffer: Buffer | string) {
138
+ return createHash('sha1').update(buffer).digest('hex');
139
+ }
140
+
141
+ async function getFileSha1(filePath: string): Promise<string> {
142
+ const buffer = await readFile(filePath);
143
+ return sha1(buffer);
144
+ }
145
+
146
+ async function fileExists(path: string): Promise<boolean> {
147
+ try {
148
+ await access(path);
149
+ return true;
150
+ } catch {
151
+ return false;
144
152
  }
153
+ }
154
+
155
+ // 下载并缓存 tgz 到 ~/.tego/plugins
156
+ export async function downloadTar(packageName: string, target: string) {
157
+ const { url, shasum } = await getTarballMeta(packageName);
145
158
 
146
- // 使用 pipeline 将 response.body 写入文件
147
- await pipeline(response.body as any, writer);
159
+ const baseName = `${packageName.replace('/', '__')}@${shasum}`;
160
+ const cachedTar = join(process.env.TEGO_HOME!, 'plugins', `${baseName}.tar.gz`);
161
+ const cachedSha = join(process.env.TEGO_HOME!, 'plugins', `${baseName}.sha1`);
148
162
 
163
+ const exists = await fileExists(cachedTar);
164
+ const shaMatches = exists ? (await getFileSha1(cachedTar)) === shasum : false;
165
+
166
+ if (!exists || !shaMatches) {
167
+ await mkdir(dirname(cachedTar), { recursive: true });
168
+
169
+ const res = await fetch(url);
170
+ if (!res.ok || !res.body) {
171
+ throw new Error(`Failed to fetch tarball: ${res.statusText}`);
172
+ }
173
+
174
+ const writer = createWriteStream(cachedTar);
175
+ await pipeline(res.body as any, writer);
176
+
177
+ const actualSha = await getFileSha1(cachedTar);
178
+ if (actualSha !== shasum) {
179
+ await unlink(cachedTar);
180
+ throw new Error(`Downloaded tarball hash mismatch for ${packageName}`);
181
+ }
182
+
183
+ await writeFile(cachedSha, shasum, 'utf-8');
184
+ }
185
+
186
+ await rm(target, { recursive: true, force: true });
149
187
  await mkdir(target, { recursive: true });
188
+
150
189
  await tar.x({
151
- file: tarballFile,
190
+ file: cachedTar,
152
191
  gzip: true,
153
192
  cwd: target,
154
193
  strip: 1,
155
194
  k: true,
156
195
  });
196
+ }
197
+
198
+ const ONE_DAY_MS = 24 * 60 * 60 * 1000;
199
+
200
+ export class TegoIndexManager {
201
+ private indexUrl: string;
202
+ private indexFile: string;
203
+ private lastUpdateFile: string;
204
+
205
+ constructor({
206
+ indexUrl,
207
+ baseDir,
208
+ lastUpdateSuffix = '.last-update-at',
209
+ }: {
210
+ indexUrl: string;
211
+ baseDir: string;
212
+ lastUpdateSuffix?: string;
213
+ }) {
214
+ this.indexUrl = indexUrl;
215
+ this.indexFile = join(baseDir, 'index.tego.json');
216
+ this.lastUpdateFile = join(baseDir, 'index.tego.json' + lastUpdateSuffix);
217
+ }
218
+
219
+ private async readLastUpdateTime(): Promise<Date | null> {
220
+ try {
221
+ const content = await readFile(this.lastUpdateFile, 'utf-8');
222
+ return new Date(content.trim());
223
+ } catch {
224
+ return null;
225
+ }
226
+ }
157
227
 
158
- await unlink(tarballFile);
228
+ private async fetchIndexFile(): Promise<any> {
229
+ const res = await fetch(this.indexUrl);
230
+ if (!res.ok) {
231
+ throw new Error(`Failed to fetch ${this.indexUrl}: ${res.statusText}`);
232
+ }
233
+
234
+ const json = await res.json();
235
+ await writeFile(this.indexFile, JSON.stringify(json, null, 2), 'utf-8');
236
+ await writeFile(this.lastUpdateFile, new Date().toISOString(), 'utf-8');
237
+ return json;
238
+ }
239
+
240
+ async getIndex(): Promise<any> {
241
+ const lastUpdated = await this.readLastUpdateTime();
242
+ if (lastUpdated && Date.now() - lastUpdated.getTime() < ONE_DAY_MS) {
243
+ console.info(`🕒 index.tego.json was updated within 1 day, skipping download.`);
244
+ const content = await readFile(this.indexFile, 'utf-8');
245
+ return JSON.parse(content);
246
+ }
247
+
248
+ return await this.fetchIndexFile();
249
+ }
159
250
  }
@@ -1 +0,0 @@
1
- export declare const defaultModules: string[];
@@ -1,51 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __export = (target, all) => {
6
- for (var name in all)
7
- __defProp(target, name, { get: all[name], enumerable: true });
8
- };
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") {
11
- for (let key of __getOwnPropNames(from))
12
- if (!__hasOwnProp.call(to, key) && key !== except)
13
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
- }
15
- return to;
16
- };
17
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
- var default_modules_exports = {};
19
- __export(default_modules_exports, {
20
- defaultModules: () => defaultModules
21
- });
22
- module.exports = __toCommonJS(default_modules_exports);
23
- const defaultModules = [
24
- "acl",
25
- "app-info",
26
- "auth",
27
- "backup",
28
- "cloud-component",
29
- "collection",
30
- "cron",
31
- "data-source",
32
- "error-handler",
33
- "event-source",
34
- "file",
35
- "message",
36
- "pdf",
37
- "ui-schema",
38
- "user",
39
- "web",
40
- "worker-thread",
41
- "instrumentation",
42
- "workflow",
43
- "env-secrets",
44
- "hera",
45
- // FIXME: refactor later
46
- "multi-app"
47
- ];
48
- // Annotate the CommonJS export names for ESM import in node:
49
- 0 && (module.exports = {
50
- defaultModules
51
- });
@@ -1 +0,0 @@
1
- export declare const defaultPlugins: string[];
@@ -1,51 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __export = (target, all) => {
6
- for (var name in all)
7
- __defProp(target, name, { get: all[name], enumerable: true });
8
- };
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") {
11
- for (let key of __getOwnPropNames(from))
12
- if (!__hasOwnProp.call(to, key) && key !== except)
13
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
- }
15
- return to;
16
- };
17
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
- var default_plugins_exports = {};
19
- __export(default_plugins_exports, {
20
- defaultPlugins: () => defaultPlugins
21
- });
22
- module.exports = __toCommonJS(default_plugins_exports);
23
- const defaultPlugins = [
24
- "action-bulk-edit",
25
- "action-bulk-update",
26
- "action-custom-request",
27
- "action-duplicate",
28
- "action-export",
29
- "action-import",
30
- "action-print",
31
- "block-calendar",
32
- "block-charts",
33
- "block-gantt",
34
- "block-kanban",
35
- "block-presentation",
36
- "field-china-region",
37
- "field-formula",
38
- "field-sequence",
39
- "field-encryption",
40
- "log-viewer",
41
- "otp",
42
- "full-text-search",
43
- "password-policy",
44
- "auth-pages",
45
- "manual-notification",
46
- "auth-main-app"
47
- ];
48
- // Annotate the CommonJS export names for ESM import in node:
49
- 0 && (module.exports = {
50
- defaultPlugins
51
- });
@@ -1,24 +0,0 @@
1
- export const defaultModules = [
2
- 'acl',
3
- 'app-info',
4
- 'auth',
5
- 'backup',
6
- 'cloud-component',
7
- 'collection',
8
- 'cron',
9
- 'data-source',
10
- 'error-handler',
11
- 'event-source',
12
- 'file',
13
- 'message',
14
- 'pdf',
15
- 'ui-schema',
16
- 'user',
17
- 'web',
18
- 'worker-thread',
19
- 'instrumentation',
20
- 'workflow',
21
- 'env-secrets',
22
- 'hera', // FIXME: refactor later
23
- 'multi-app',
24
- ];
@@ -1,25 +0,0 @@
1
- export const defaultPlugins = [
2
- 'action-bulk-edit',
3
- 'action-bulk-update',
4
- 'action-custom-request',
5
- 'action-duplicate',
6
- 'action-export',
7
- 'action-import',
8
- 'action-print',
9
- 'block-calendar',
10
- 'block-charts',
11
- 'block-gantt',
12
- 'block-kanban',
13
- 'block-presentation',
14
- 'field-china-region',
15
- 'field-formula',
16
- 'field-sequence',
17
- 'field-encryption',
18
- 'log-viewer',
19
- 'otp',
20
- 'full-text-search',
21
- 'password-policy',
22
- 'auth-pages',
23
- 'manual-notification',
24
- 'auth-main-app',
25
- ];