zotero-plugin-scaffold 0.0.4

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.
@@ -0,0 +1,22 @@
1
+ import { Config } from "../types.js";
2
+ import { LibBase } from "../utils/libBase.js";
3
+ export default class Serve extends LibBase {
4
+ private builder;
5
+ constructor(config: Config);
6
+ run(): Promise<void>;
7
+ /**
8
+ * watch source dir and build when file changed
9
+ */
10
+ watch(): Promise<void>;
11
+ startZotero(): void;
12
+ /**
13
+ * start zotero with plugin installed and reload when dist changed
14
+ */
15
+ startZoteroWebExt(): Promise<void>;
16
+ prepareDevEnv(): void;
17
+ reload(): void;
18
+ openDevTool(): void;
19
+ private get zoteroBinPath();
20
+ private get profilePath();
21
+ private get dataDir();
22
+ }
@@ -0,0 +1,233 @@
1
+ import { LibBase } from "../utils/libBase.js";
2
+ import Build from "./build.js";
3
+ import { execSync, spawn } from "child_process";
4
+ import chokidar from "chokidar";
5
+ import fs from "fs-extra";
6
+ import _ from "lodash";
7
+ import path from "path";
8
+ import { exit } from "process";
9
+ import webext from "web-ext";
10
+ export default class Serve extends LibBase {
11
+ builder;
12
+ constructor(config) {
13
+ super(config);
14
+ this.builder = new Build(config);
15
+ }
16
+ async run() {
17
+ // build
18
+ this.builder.run();
19
+ // start Zotero
20
+ // this.startZotero();
21
+ this.startZoteroWebExt();
22
+ // watch
23
+ await this.config.extraServer(this.config);
24
+ await this.watch();
25
+ }
26
+ /**
27
+ * watch source dir and build when file changed
28
+ */
29
+ async watch() {
30
+ const watcher = chokidar.watch(this.config.source, {
31
+ ignored: /(^|[/\\])\../, // ignore dotfiles
32
+ persistent: true,
33
+ });
34
+ const onChange = _.debounce((path) => {
35
+ try {
36
+ if (path.endsWith(".ts")) {
37
+ this.builder.esbuild();
38
+ }
39
+ else {
40
+ this.builder.run();
41
+ }
42
+ }
43
+ catch (err) {
44
+ // Do not abort the watcher when errors occur
45
+ // in builds triggered by the watcher.
46
+ this.logger.error(err);
47
+ }
48
+ }, 500);
49
+ watcher
50
+ .on("ready", () => {
51
+ this.logger.log("");
52
+ this.logger.info("Server Ready! \n");
53
+ })
54
+ .on("change", async (path) => {
55
+ this.logger.info(`${path} changed at ${new Date().toLocaleTimeString()}`);
56
+ onChange.cancel();
57
+ onChange(path);
58
+ this.reload();
59
+ this.logger.info("Reloaded done.");
60
+ })
61
+ .on("error", (err) => {
62
+ this.logger.error("Server start failed!", err);
63
+ });
64
+ }
65
+ startZotero() {
66
+ if (!fs.existsSync(this.zoteroBinPath)) {
67
+ throw new Error("Zotero binary does not exist.");
68
+ }
69
+ if (!fs.existsSync(this.profilePath)) {
70
+ throw new Error("The given Zotero profile does not exist.");
71
+ }
72
+ const zoteroProcess = spawn(this.zoteroBinPath, [
73
+ "--debugger",
74
+ "--purgecaches",
75
+ "-profile",
76
+ this.profilePath,
77
+ ]);
78
+ zoteroProcess.on("close", (code) => {
79
+ this.logger.info(`Zotero terminated with code ${code}.`);
80
+ exit(0);
81
+ });
82
+ process.on("SIGINT", () => {
83
+ // Handle interrupt signal (Ctrl+C) to gracefully terminate Zotero process
84
+ zoteroProcess.kill();
85
+ exit();
86
+ });
87
+ }
88
+ /**
89
+ * start zotero with plugin installed and reload when dist changed
90
+ */
91
+ async startZoteroWebExt() {
92
+ await webext.cmd.run({
93
+ firefox: this.config.cmd.zoteroBinPath,
94
+ firefoxProfile: this.config.cmd.profilePath,
95
+ sourceDir: path.resolve(`${this.config.dist}/addon`),
96
+ keepProfileChanges: true,
97
+ args: ["--debugger", "--purgecaches"],
98
+ // browserConsole: true,
99
+ // openDevTool: true, // need Zotero upgrade to firefox 115
100
+ }, {
101
+ // These are non CLI related options for each function.
102
+ // You need to specify this one so that your NodeJS application
103
+ // can continue running after web-ext is finished.
104
+ shouldExitProgram: false,
105
+ });
106
+ }
107
+ prepareDevEnv() {
108
+ const addonProxyFilePath = path.join(this.profilePath, `extensions/${this.addonID}`);
109
+ const buildPath = path.resolve("build/addon");
110
+ if (!fs.existsSync(addonProxyFilePath) ||
111
+ fs.readFileSync(addonProxyFilePath, "utf-8") !== buildPath) {
112
+ fs.writeFileSync(addonProxyFilePath, buildPath);
113
+ this.logger.debug(`Addon proxy file has been updated.
114
+ File path: ${addonProxyFilePath}
115
+ Addon path: ${buildPath} `);
116
+ }
117
+ const addonXpiFilePath = path.join(this.profilePath, `extensions/${this.addonID}.xpi`);
118
+ if (fs.existsSync(addonXpiFilePath)) {
119
+ fs.rmSync(addonXpiFilePath);
120
+ }
121
+ const prefsPath = path.join(this.profilePath, "prefs.js");
122
+ if (fs.existsSync(prefsPath)) {
123
+ const PrefsLines = fs.readFileSync(prefsPath, "utf-8").split("\n");
124
+ const filteredLines = PrefsLines.map((line) => {
125
+ if (line.includes("extensions.lastAppBuildId") ||
126
+ line.includes("extensions.lastAppVersion")) {
127
+ return;
128
+ }
129
+ if (line.includes("extensions.zotero.dataDir") && this.dataDir !== "") {
130
+ return `user_pref("extensions.zotero.dataDir", "${this.dataDir}");`;
131
+ }
132
+ return line;
133
+ });
134
+ const updatedPrefs = filteredLines.join("\n");
135
+ fs.writeFileSync(prefsPath, updatedPrefs, "utf-8");
136
+ this.logger.debug("The <profile>/prefs.js has been modified.");
137
+ }
138
+ }
139
+ reload() {
140
+ this.logger.debug("Reloading...");
141
+ const reloadScript = `
142
+ (async () => {
143
+ Services.obs.notifyObservers(null, "startupcache-invalidate", null);
144
+ const { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
145
+ const addon = await AddonManager.getAddonByID("${this.addonID}");
146
+ await addon.reload();
147
+ const progressWindow = new Zotero.ProgressWindow({ closeOnClick: true });
148
+ progressWindow.changeHeadline("${this.addonName} Hot Reload");
149
+ progressWindow.progress = new progressWindow.ItemProgress(
150
+ "chrome://zotero/skin/tick.png",
151
+ "VERSION=${this.version}, BUILD=${new Date().toLocaleString()}. By zotero-plugin-toolkit"
152
+ );
153
+ progressWindow.progress.setProgress(100);
154
+ progressWindow.show();
155
+ progressWindow.startCloseTimer(5000);
156
+ })()`;
157
+ const url = `zotero://ztoolkit-debug/?run=${encodeURIComponent(reloadScript)}`;
158
+ const startZoteroCmd = `"${this.zoteroBinPath}" --debugger --purgecaches -profile "${this.profilePath}"`;
159
+ const command = `${startZoteroCmd} -url "${url}"`;
160
+ execSync(command);
161
+ }
162
+ openDevTool() {
163
+ this.logger.debug("Open dev tools...");
164
+ const openDevToolScript = `
165
+ (async () => {
166
+
167
+ // const { BrowserToolboxLauncher } = ChromeUtils.import(
168
+ // "resource://devtools/client/framework/browser-toolbox/Launcher.jsm",
169
+ // );
170
+ // BrowserToolboxLauncher.init();
171
+ // TODO: Use the above code to open the devtool after https://github.com/zotero/zotero/pull/3387
172
+
173
+ Zotero.Prefs.set("devtools.debugger.remote-enabled", true, true);
174
+ Zotero.Prefs.set("devtools.debugger.remote-port", 6100, true);
175
+ Zotero.Prefs.set("devtools.debugger.prompt-connection", false, true);
176
+ Zotero.Prefs.set("devtools.debugger.chrome-debugging-websocket", false, true);
177
+
178
+ env =
179
+ Services.env ||
180
+ Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
181
+
182
+ env.set("MOZ_BROWSER_TOOLBOX_PORT", 6100);
183
+ Zotero.openInViewer(
184
+ "chrome://devtools/content/framework/browser-toolbox/window.html",
185
+ {
186
+ onLoad: (doc) => {
187
+ doc.querySelector("#status-message-container").style.visibility =
188
+ "collapse";
189
+ let toolboxBody;
190
+ waitUntil(
191
+ () => {
192
+ toolboxBody = doc
193
+ .querySelector(".devtools-toolbox-browsertoolbox-iframe")
194
+ ?.contentDocument?.querySelector(".theme-body");
195
+ return toolboxBody;
196
+ },
197
+ () => {
198
+ toolboxBody.style = "pointer-events: all !important";
199
+ }
200
+ );
201
+ },
202
+ }
203
+ );
204
+
205
+ function waitUntil(condition, callback, interval = 100, timeout = 10000) {
206
+ const start = Date.now();
207
+ const intervalId = setInterval(() => {
208
+ if (condition()) {
209
+ clearInterval(intervalId);
210
+ callback();
211
+ } else if (Date.now() - start > timeout) {
212
+ clearInterval(intervalId);
213
+ }
214
+ }, interval);
215
+ }
216
+ })()`;
217
+ const url = `zotero://ztoolkit-debug/?run=${encodeURIComponent(openDevToolScript)}`;
218
+ const startZoteroCmd = `"${this.zoteroBinPath}" --debugger --purgecaches -profile "${this.profilePath}"`;
219
+ const command = `${startZoteroCmd} -url "${url}"`;
220
+ execSync(command);
221
+ }
222
+ get zoteroBinPath() {
223
+ this.logger.debug("zoteroBinPath", process.env.zoteroBinPath);
224
+ return process.env.zoteroBinPath ?? "";
225
+ }
226
+ get profilePath() {
227
+ this.logger.debug("profilePath", process.env.profilePath);
228
+ return process.env.profilePath ?? "";
229
+ }
230
+ get dataDir() {
231
+ return process.env.dataDir ?? "";
232
+ }
233
+ }
@@ -0,0 +1,346 @@
1
+ import { type VersionBumpOptions } from "bumpp";
2
+ import { BuildOptions } from "esbuild";
3
+ type RecursivePartial<T> = {
4
+ [P in keyof T]?: T[P] extends object ? RecursivePartial<T[P]> : T[P];
5
+ };
6
+ export interface UserConfig extends RecursivePartial<ConfigBase> {
7
+ }
8
+ export interface ConfigBase {
9
+ /**
10
+ * The source code directories.
11
+ *
12
+ * Can be multiple directories, and changes to these directories will be watched when `server` is running.
13
+ *
14
+ * 源码目录。
15
+ *
16
+ * 可以是多个目录,将在 `server` 运行时监听这些目录的变更。
17
+ *
18
+ * @default ["src"]
19
+ */
20
+ source: string[];
21
+ /**
22
+ * The build directories.
23
+ *
24
+ * Scaffold will store the code before packaging after the build at `${dist}/addon`.
25
+ * Store the packaging results at `${dist}/${package_json.name}.xpi`.
26
+ *
27
+ * 构建目录。
28
+ *
29
+ * 脚手架将在 `${dist}/addon` 存放构建后打包前的代码。
30
+ * 在 `${dist}/${package_json.name}.xpi` 存放打包结果。
31
+ *
32
+ * @default "build"
33
+ */
34
+ dist: string;
35
+ /**
36
+ * glob list of static assets
37
+ *
38
+ * 静态资源文件。
39
+ *
40
+ * - 通常包括图标、ftl 文件、第三方 JavaScript 文件、CSS 文件、XHTML 文件等。
41
+ * - 是一个 `glob` 模式数组,支持否定模式。
42
+ * - 除非一个目录没有需要排除的文件,否则不要添加整个目录。
43
+ *
44
+ * @see {@link https://github.com/mrmlnc/fast-glob?tab=readme-ov-file#pattern-syntax | Pattern syntax | 语法说明 }
45
+ *
46
+ * @default `["src/**\/*.*", "!src/**\/*.ts"]` (no `\`)
47
+ */
48
+ assets: string[];
49
+ /**
50
+ * placeholders to replace in static assets
51
+ *
52
+ * 静态资源文本占位符。
53
+ *
54
+ * - 在构建时,脚手架使用占位符的 key 建立正则模式 `/__${key}__/g`,并将匹配到的内容替换为 `value`。
55
+ * - 以下是一些预置的占位符,你可以在这里覆盖它们:
56
+ * - `name`, `description`, `version`, `homepage`, `author` 从 `package.json` 读取。
57
+ * - `__buildTime__` 为 `build.run` 调用时间。
58
+ * - 出于兼容性考虑,`addonName`, `addonID`, `addonRef`, `addonInstense`, `prefsPrefix`, `releasePage` 也可以在 `package.json` 中的 `config` 属性中读取。
59
+ * - 优先级:此处 > package.json > default
60
+ * - 替换发生在 `assets` 下的所有文件。
61
+ */
62
+ define: {
63
+ [key: string]: string | unknown;
64
+ /**
65
+ * The name of plugin
66
+ *
67
+ * 插件名
68
+ *
69
+ * @default _.startCase(pkg.name)
70
+ */
71
+ addonName: string;
72
+ /**
73
+ * 插件 ID
74
+ */
75
+ addonID: string;
76
+ author: string;
77
+ description: string;
78
+ homepage: string;
79
+ ghOwner: string;
80
+ ghRepo: string;
81
+ /**
82
+ * namespace of plugin
83
+ *
84
+ * 插件命名空间
85
+ *
86
+ * @default _.kebabCase(addonName)
87
+ */
88
+ addonRef: string;
89
+ /**
90
+ * 插件注册在 Zotero 下的实例
91
+ *
92
+ * @default _.camelCase(addonName)
93
+ */
94
+ addonInstance: string;
95
+ /**
96
+ * 插件首选项前缀
97
+ *
98
+ * @default `extensions.zotero.${addonRef}`
99
+ */
100
+ prefsPrefix: string;
101
+ /**
102
+ * @default pkg.version
103
+ */
104
+ buildVersion: string;
105
+ /**
106
+ * 打包 XPI 的文件名,不需要加后缀名
107
+ *
108
+ * @default pkg.name || _.kebabCase(addonName)
109
+ */
110
+ xpiName: string;
111
+ /**
112
+ * 插件发布页面
113
+ *
114
+ * 脚手架根据这个地址生成 update.json 地址和 xpi 地址
115
+ *
116
+ * @default `https://github.com/${owner}/${repo}/release`
117
+ */
118
+ releasePage: string;
119
+ /**
120
+ * XPI 文件的地址
121
+ *
122
+ * @default `${releasePage}/download/v${pkg.version}/${xpiName}.xpi`
123
+ */
124
+ updateLink: string;
125
+ /**
126
+ * update.json 文件的地址
127
+ *
128
+ * @default `${releasePage}/download/release/update.json`
129
+ */
130
+ updateURL: string;
131
+ };
132
+ fluent: {
133
+ /**
134
+ * 为所有 FTL 文件添加插件前缀以避免冲突
135
+ *
136
+ * 默认前缀为 `${addonRef}-`
137
+ *
138
+ * @default true
139
+ */
140
+ prefixLocaleFiles: boolean;
141
+ /**
142
+ * 为所有 FTL message 添加插件前缀以避免冲突
143
+ *
144
+ * 默认前缀为 `${addonRef}-`
145
+ *
146
+ * @default true
147
+ */
148
+ prefixFluentMessages: boolean;
149
+ };
150
+ /**
151
+ * The config of esbuild
152
+ *
153
+ * esbuild 配置
154
+ *
155
+ * 注意:
156
+ * - 默认配置中 `source` 和 `dist` 会跟随用户配置.
157
+ * - 此项配置会覆盖默认配置而不是在默认配置列表上新增.
158
+ *
159
+ * @default
160
+ *
161
+ * ```js
162
+ * {
163
+ * entryPoints: [`${source}/index.ts`],
164
+ * define: {
165
+ * __env__: `"${env.NODE_ENV}"`,
166
+ * },
167
+ * bundle: true,
168
+ * target: "firefox102",
169
+ * outfile: `build/addon/${addonRef}.js`,
170
+ * minify: env.NODE_ENV === "production",
171
+ * };
172
+ * ```
173
+ */
174
+ esbuildOptions: BuildOptions[];
175
+ /**
176
+ * Make manifest.json
177
+ *
178
+ */
179
+ makeManifest: {
180
+ /**
181
+ * 是否使用内置的模板 manifest.json。
182
+ * 如果此项为 false,则开发者应自行准备 manifest.json
183
+ *
184
+ * @default true
185
+ */
186
+ enable: boolean;
187
+ /**
188
+ * template of manifest
189
+ *
190
+ * @default
191
+ *
192
+ * ```json
193
+ * {
194
+ * manifest_version: 2,
195
+ * name: "__addonName__",
196
+ * version: "__buildVersion__",
197
+ * description: "__description__",
198
+ * homepage_url: "__homepage__",
199
+ * author: "__author__",
200
+ * icons: {
201
+ * "48": "content/icons/favicon@0.5x.png",
202
+ * "96": "content/icons/favicon.png",
203
+ * },
204
+ * applications: {
205
+ * zotero: {
206
+ * id: "__addonID__",
207
+ * update_url: "__updateURL__",
208
+ * strict_min_version: "6.999",
209
+ * strict_max_version: "7.0.*",
210
+ * },
211
+ * gecko: {
212
+ * id: "__addonID__",
213
+ * update_url: "__updateURL__",
214
+ * strict_min_version: "102",
215
+ * };
216
+ * };
217
+ * };
218
+ * ```
219
+ */
220
+ template: Manifest;
221
+ };
222
+ /**
223
+ * 是否使用内置的模板 bootstrap。
224
+ * 如果此项为 false,则开发者应自行准备 bootstrap.js。
225
+ *
226
+ * @default true
227
+ */
228
+ makeBootstrap: boolean;
229
+ /**
230
+ * 是否使用内置的模板 update.json。
231
+ * 如果此项为 false,则开发者应自行准备 update.json。
232
+ *
233
+ * @default true
234
+ */
235
+ makeUpdateJson: {
236
+ enable: boolean | "only-production";
237
+ template: UpdateJSON;
238
+ tagName: "release" | "updater" | string;
239
+ };
240
+ /**
241
+ * The function called when build-in build resolved.
242
+ *
243
+ * Usually some extra build process.
244
+ * All configurations will be parameterized to this function.
245
+ *
246
+ * 在默认构建步骤执行结束后执行的函数.
247
+ *
248
+ * 通常是一些额外的构建流程.
249
+ * 所有的配置将作为参数传入此函数.
250
+ *
251
+ * @default ()=>{}
252
+ */
253
+ extraBuilder: (options: Config) => any | Promise<any>;
254
+ /**
255
+ * The function called after Zotero started, before build-in watcher ready.
256
+ *
257
+ * @default ()=>{}
258
+ */
259
+ extraServer: (options: Config) => any | Promise<any>;
260
+ /**
261
+ * TODO: 使用 addonLint 检查 XPI
262
+ */
263
+ addonLint: object;
264
+ /**
265
+ * .dotenv 文件路径
266
+ *
267
+ * @default `.env`
268
+ */
269
+ dotEnvPath: string;
270
+ /**
271
+ * 发布相关配置
272
+ */
273
+ release: {
274
+ releaseIt: Partial<ReleaseItConfig>;
275
+ bumpp: VersionBumpOptions;
276
+ };
277
+ /**
278
+ * 日志级别
279
+ *
280
+ * @default "info"
281
+ */
282
+ logLevel: "trace" | "debug" | "info" | "warn" | "error";
283
+ }
284
+ export interface Config extends ConfigBase {
285
+ cmd: {
286
+ zoteroBinPath: string;
287
+ profilePath: string;
288
+ dataDir: string;
289
+ };
290
+ pkgUser: any;
291
+ pkgAbsolute: string;
292
+ }
293
+ interface Manifest {
294
+ [key: string]: any;
295
+ manifest_version: number;
296
+ name: string;
297
+ version: string;
298
+ description?: string;
299
+ homepage_url?: string;
300
+ author?: string;
301
+ icons?: Record<string, string>;
302
+ applications: {
303
+ zotero: {
304
+ id: string;
305
+ update_url: string;
306
+ strict_min_version: string;
307
+ strict_max_version?: string;
308
+ };
309
+ gecko: {
310
+ id: string;
311
+ update_url: string;
312
+ strict_min_version: string;
313
+ };
314
+ };
315
+ }
316
+ /**
317
+ * Update json
318
+ * @see https://extensionworkshop.com/documentation/manage/updating-your-extension/
319
+ */
320
+ interface UpdateJSON {
321
+ addons: {
322
+ [addonID: string]: {
323
+ updates: Array<{
324
+ version: string;
325
+ update_link?: string;
326
+ /**
327
+ * A cryptographic hash of the file pointed to by `update_link`.
328
+ * This must be provided if `update_link` is not a secure URL.
329
+ * If present, this must be a string beginning with either `sha256:` or `sha512:`,
330
+ * followed by the hexadecimal-encoded hash of the matching type.
331
+ */
332
+ update_hash?: string;
333
+ applications: {
334
+ zotero: {
335
+ strict_min_version: string;
336
+ };
337
+ [application: string]: {
338
+ strict_min_version?: string;
339
+ strict_max_version?: string;
340
+ };
341
+ };
342
+ }>;
343
+ };
344
+ };
345
+ }
346
+ export {};
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare function generateHash(filePath: string, algorithm: "sha256" | "sha512" | string): Promise<string>;
2
+ export declare function generateHashSync(filePath: string, algorithm: "sha256" | "sha512" | string): string;
@@ -0,0 +1,23 @@
1
+ import * as crypto from "crypto";
2
+ import * as fs from "fs";
3
+ export function generateHash(filePath, algorithm) {
4
+ return new Promise((resolve, reject) => {
5
+ const hash = crypto.createHash(algorithm);
6
+ const stream = fs.createReadStream(filePath);
7
+ stream.on("data", (data) => {
8
+ hash.update(data);
9
+ });
10
+ stream.on("end", () => {
11
+ const fileHash = hash.digest("hex");
12
+ resolve(`${algorithm}:${fileHash}`);
13
+ });
14
+ stream.on("error", (error) => {
15
+ reject(error);
16
+ });
17
+ });
18
+ }
19
+ export function generateHashSync(filePath, algorithm) {
20
+ const data = fs.readFileSync(filePath);
21
+ const hash = crypto.createHash(algorithm).update(data).digest("hex");
22
+ return `${algorithm}:${hash}`;
23
+ }
@@ -0,0 +1,15 @@
1
+ import { Config } from "../types.js";
2
+ import Log from "./log.js";
3
+ export declare abstract class LibBase {
4
+ config: Config;
5
+ logger: InstanceType<typeof Log>;
6
+ constructor(config: Config);
7
+ get version(): string;
8
+ get addonName(): string;
9
+ get addonID(): string;
10
+ get addonRef(): string;
11
+ get addonInstence(): string;
12
+ get updateLink(): string;
13
+ get updateURL(): string;
14
+ get xpiName(): string;
15
+ }
@@ -0,0 +1,33 @@
1
+ import Log from "./log.js";
2
+ export class LibBase {
3
+ config;
4
+ logger;
5
+ constructor(config) {
6
+ this.config = config;
7
+ this.logger = new Log(config);
8
+ }
9
+ get version() {
10
+ return this.config.define.buildVersion;
11
+ }
12
+ get addonName() {
13
+ return this.config.define.addonName;
14
+ }
15
+ get addonID() {
16
+ return this.config.define.addonID;
17
+ }
18
+ get addonRef() {
19
+ return this.config.define.addonRef;
20
+ }
21
+ get addonInstence() {
22
+ return this.config.define.addonInstance;
23
+ }
24
+ get updateLink() {
25
+ return this.config.define.updateLink;
26
+ }
27
+ get updateURL() {
28
+ return this.config.define.updateURL;
29
+ }
30
+ get xpiName() {
31
+ return this.config.define.xpiName;
32
+ }
33
+ }
@@ -0,0 +1,11 @@
1
+ import { Config } from "../types";
2
+ export default class Log {
3
+ private logLevel;
4
+ constructor(config?: Config);
5
+ log(...args: any[]): void;
6
+ error(...args: any[]): void;
7
+ warn(...args: any[]): void;
8
+ info(...args: any[]): void;
9
+ debug(...args: any[]): void;
10
+ trace(...args: any[]): void;
11
+ }