@pagepocket/cli 0.10.1 → 0.11.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.
@@ -1,20 +1,99 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
+ const node_module_1 = require("node:module");
40
+ const node_url_1 = require("node:url");
6
41
  const core_1 = require("@oclif/core");
7
42
  const lib_1 = require("@pagepocket/lib");
8
43
  const chalk_1 = __importDefault(require("chalk"));
9
44
  const load_configured_plugins_1 = require("../services/load-configured-plugins");
10
45
  const config_service_1 = require("../services/config-service");
11
- const read_installed_package_version_1 = require("../services/strategy/read-installed-package-version");
46
+ const builtin_strategy_registry_1 = require("../services/strategy/builtin-strategy-registry");
12
47
  const strategy_service_1 = require("../services/strategy/strategy-service");
13
48
  const strategy_normalize_1 = require("../services/strategy/strategy-normalize");
14
49
  const parse_pinned_spec_1 = require("../services/user-packages/parse-pinned-spec");
50
+ const unit_validate_1 = require("../services/units/unit-validate");
15
51
  const unit_store_1 = require("../services/units/unit-store");
52
+ const array_1 = require("../utils/array");
16
53
  const with_spinner_1 = require("../utils/with-spinner");
17
- const loadStrategyUnits = async (input) => {
54
+ const buildMissingStrategyError = (input) => {
55
+ const available = (0, array_1.uniq)([...input.installedNames, ...(0, builtin_strategy_registry_1.listBuiltinStrategyNames)()])
56
+ .filter((name) => name.trim().length > 0)
57
+ .sort((left, right) => left.localeCompare(right));
58
+ const suffix = available.length > 0 ? ` Available strategies: ${available.join(", ")}` : " No strategies found.";
59
+ return new Error(`Strategy not found: ${input.strategyName}.${suffix}`);
60
+ };
61
+ const resolveStrategy = (input) => {
62
+ const installedNames = input.strategyService.listInstalledStrategyNames();
63
+ if (installedNames.includes(input.strategyName)) {
64
+ return {
65
+ name: input.strategyName,
66
+ strategyFile: input.strategyService.readStrategy(input.strategyName),
67
+ source: "installed"
68
+ };
69
+ }
70
+ const builtin = (0, builtin_strategy_registry_1.readBuiltinStrategy)(input.strategyName);
71
+ if (builtin) {
72
+ return {
73
+ name: input.strategyName,
74
+ strategyFile: builtin,
75
+ source: "builtin"
76
+ };
77
+ }
78
+ throw buildMissingStrategyError({
79
+ strategyName: input.strategyName,
80
+ installedNames
81
+ });
82
+ };
83
+ const assertNoDuplicateUnitIds = (input) => {
84
+ const seen = new Set();
85
+ const dup = input.units.find((u) => {
86
+ if (seen.has(u.id)) {
87
+ return true;
88
+ }
89
+ seen.add(u.id);
90
+ return false;
91
+ });
92
+ if (dup) {
93
+ throw new Error(`Duplicate unit id detected in strategy ${input.strategyName}: ${dup.id}`);
94
+ }
95
+ };
96
+ const loadInstalledStrategyUnits = async (input) => {
18
97
  const strategyService = new strategy_service_1.StrategyService(input.configService);
19
98
  const unitStore = new unit_store_1.UnitStore(input.configService);
20
99
  strategyService.ensureConfigFileExists();
@@ -45,19 +124,52 @@ const loadStrategyUnits = async (input) => {
45
124
  throw new Error(`Strategy drift detected (${input.strategyName}). ${details}. ` +
46
125
  `Fix: pp strategy update ${input.strategyName} OR pp strategy pin ${input.strategyName}`);
47
126
  }
48
- const loadedUnits = await Promise.all(normalized.map(async (u) => unitStore.instantiateFromRef(u.ref, u.args)));
49
- const seen = new Set();
50
- const dup = loadedUnits.find((u) => {
51
- if (seen.has(u.id)) {
52
- return true;
53
- }
54
- seen.add(u.id);
55
- return false;
127
+ const units = await Promise.all(normalized.map(async (u) => unitStore.instantiateFromRef(u.ref, u.args)));
128
+ assertNoDuplicateUnitIds({
129
+ strategyName: input.strategyName,
130
+ units
56
131
  });
57
- if (dup) {
58
- throw new Error(`Duplicate unit id detected in strategy ${input.strategyName}: ${dup.id}`);
132
+ return units;
133
+ };
134
+ const instantiateBuiltinUnit = async (input) => {
135
+ const req = (0, node_module_1.createRequire)(__filename);
136
+ const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(input.ref);
137
+ const resolved = req.resolve(pinned.name);
138
+ const mod = (await Promise.resolve(`${(0, node_url_1.pathToFileURL)(resolved).href}`).then(s => __importStar(require(s))));
139
+ const def = mod.default;
140
+ if (typeof def !== "function") {
141
+ throw new Error(`Unit ${pinned.name} must default export a constructor.`);
59
142
  }
60
- return loadedUnits;
143
+ const ctor = def;
144
+ const instance = new ctor(...input.args);
145
+ if (!(0, unit_validate_1.isUnitLike)(instance)) {
146
+ throw new Error(`Unit ${pinned.name} default export did not construct a Unit.`);
147
+ }
148
+ return instance;
149
+ };
150
+ const loadBuiltinStrategyUnits = async (input) => {
151
+ const normalized = (0, strategy_normalize_1.normalizeStrategyUnits)(input.strategyFile);
152
+ const units = await Promise.all(normalized.map(async (u) => instantiateBuiltinUnit({
153
+ ref: u.ref,
154
+ args: u.args
155
+ })));
156
+ assertNoDuplicateUnitIds({
157
+ strategyName: input.strategyName,
158
+ units
159
+ });
160
+ return units;
161
+ };
162
+ const loadStrategyUnits = async (input) => {
163
+ if (input.strategy.source === "installed") {
164
+ return loadInstalledStrategyUnits({
165
+ strategyName: input.strategy.name,
166
+ configService: input.configService
167
+ });
168
+ }
169
+ return loadBuiltinStrategyUnits({
170
+ strategyName: input.strategy.name,
171
+ strategyFile: input.strategy.strategyFile
172
+ });
61
173
  };
62
174
  class ArchiveCommand extends core_1.Command {
63
175
  async run() {
@@ -73,20 +185,16 @@ class ArchiveCommand extends core_1.Command {
73
185
  const name = strategyName && strategyName.length > 0 ? strategyName : "default";
74
186
  const strategyService = new strategy_service_1.StrategyService(configService);
75
187
  strategyService.ensureConfigFileExists();
76
- const installedNames = strategyService.listInstalledStrategyNames();
77
- if (installedNames.length === 0) {
78
- const v = (0, read_installed_package_version_1.readInstalledPackageVersion)("@pagepocket/builtin-strategy");
79
- await strategyService.addStrategy({
80
- source: `@pagepocket/builtin-strategy@${v}`,
81
- force: false
82
- });
83
- }
84
- const units = await loadStrategyUnits({
188
+ const strategy = resolveStrategy({
85
189
  strategyName: name,
190
+ strategyService
191
+ });
192
+ const units = await loadStrategyUnits({
193
+ strategy,
86
194
  configService
87
195
  });
88
196
  const entryTarget = pagepocket;
89
- const strategyFile = strategyService.readStrategy(name);
197
+ const strategyFile = strategy.strategyFile;
90
198
  const captureOptions = strategyFile.pipeline.captureOptions;
91
199
  const effectiveTimeoutMs = typeof timeoutMs === "number" ? timeoutMs : captureOptions?.timeoutMs;
92
200
  const effectiveMaxDurationMs = typeof maxDurationMs === "number" ? maxDurationMs : captureOptions?.maxDurationMs;
@@ -133,7 +241,7 @@ ArchiveCommand.flags = {
133
241
  required: false
134
242
  }),
135
243
  strategy: core_1.Flags.string({
136
- description: "Run an installed strategy (unit pipeline) by name"
244
+ description: "Run an installed or built-in strategy (unit pipeline) by name"
137
245
  })
138
246
  };
139
247
  exports.default = ArchiveCommand;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const builtin_strategy_registry_1 = require("../../services/strategy/builtin-strategy-registry");
5
+ const strategy_service_1 = require("../../services/strategy/strategy-service");
6
+ const array_1 = require("../../utils/array");
7
+ class StrategyLsCommand extends core_1.Command {
8
+ async run() {
9
+ const service = new strategy_service_1.StrategyService();
10
+ service.ensureConfigFileExists();
11
+ const builtin = (0, builtin_strategy_registry_1.listBuiltinStrategyNames)();
12
+ const installed = service.listInstalledStrategyNames();
13
+ const names = (0, array_1.uniq)([...builtin, ...installed])
14
+ .map((n) => n.trim())
15
+ .filter((n) => n.length > 0)
16
+ .sort((a, b) => a.localeCompare(b));
17
+ if (names.length === 0) {
18
+ this.log("No strategies available.");
19
+ return;
20
+ }
21
+ names.forEach((n) => this.log(n));
22
+ }
23
+ }
24
+ StrategyLsCommand.description = "List available strategies.";
25
+ exports.default = StrategyLsCommand;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.readBuiltinStrategy = exports.listBuiltinStrategyNames = exports.readBuiltinStrategies = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const node_module_1 = require("node:module");
9
+ const strategy_pack_read_1 = require("./strategy-pack-read");
10
+ const readBuiltinStrategiesUnsafe = () => {
11
+ const req = (0, node_module_1.createRequire)(__filename);
12
+ const pkgJsonPath = req.resolve("@pagepocket/builtin-strategy/package.json");
13
+ const packRoot = node_path_1.default.dirname(pkgJsonPath);
14
+ return (0, strategy_pack_read_1.readStrategiesFromPackRoot)(packRoot);
15
+ };
16
+ const readBuiltinStrategies = () => {
17
+ try {
18
+ return readBuiltinStrategiesUnsafe();
19
+ }
20
+ catch {
21
+ return [];
22
+ }
23
+ };
24
+ exports.readBuiltinStrategies = readBuiltinStrategies;
25
+ const listBuiltinStrategyNames = () => {
26
+ return (0, exports.readBuiltinStrategies)().map((strategy) => strategy.name);
27
+ };
28
+ exports.listBuiltinStrategyNames = listBuiltinStrategyNames;
29
+ const readBuiltinStrategy = (name) => {
30
+ return (0, exports.readBuiltinStrategies)().find((strategy) => strategy.name === name);
31
+ };
32
+ exports.readBuiltinStrategy = readBuiltinStrategy;
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ensureNoInstalledVersionConflicts = exports.computeDrift = exports.computeConflicts = exports.collectWantedVersions = exports.uniq = void 0;
3
+ exports.ensureNoInstalledVersionConflicts = exports.computeDrift = exports.computeConflicts = exports.collectWantedVersions = void 0;
4
4
  const parse_pinned_spec_1 = require("../user-packages/parse-pinned-spec");
5
- const uniq = (xs) => [...new Set(xs)];
6
- exports.uniq = uniq;
7
5
  const collectWantedVersions = (strategies) => {
8
6
  var _a, _b, _c;
9
7
  const wanted = {};
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.withoutStrategyInConfig = exports.withStrategyInConfig = exports.requireStrategyInstalled = exports.listStrategyNamesFromConfig = void 0;
4
- const uniq = (xs) => [...new Set(xs)];
4
+ const array_1 = require("../../utils/array");
5
5
  const listStrategyNamesFromConfig = (config) => {
6
- return uniq((config.strategies ?? []).map((s) => s.trim()).filter((s) => s.length > 0));
6
+ return (0, array_1.uniq)((config.strategies ?? []).map((s) => s.trim()).filter((s) => s.length > 0));
7
7
  };
8
8
  exports.listStrategyNamesFromConfig = listStrategyNamesFromConfig;
9
9
  const requireStrategyInstalled = (config, name) => {
@@ -14,7 +14,7 @@ const requireStrategyInstalled = (config, name) => {
14
14
  };
15
15
  exports.requireStrategyInstalled = requireStrategyInstalled;
16
16
  const withStrategyInConfig = (config, name) => {
17
- const strategies = uniq([...(config.strategies ?? []), name]);
17
+ const strategies = (0, array_1.uniq)([...(config.strategies ?? []), name]);
18
18
  return { ...config, strategies };
19
19
  };
20
20
  exports.withStrategyInConfig = withStrategyInConfig;
@@ -8,6 +8,7 @@ const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const config_service_1 = require("../config-service");
9
9
  const parse_pinned_spec_1 = require("../user-packages/parse-pinned-spec");
10
10
  const unit_store_1 = require("../units/unit-store");
11
+ const array_1 = require("../../utils/array");
11
12
  const strategy_analyze_1 = require("./strategy-analyze");
12
13
  const strategy_config_1 = require("./strategy-config");
13
14
  const strategy_fetch_1 = require("./strategy-fetch");
@@ -58,7 +59,7 @@ class StrategyService {
58
59
  throw new Error(`No *.strategy.json found in package: ${pinned.spec}`);
59
60
  }
60
61
  const allUnits = strategies.flatMap((s) => (0, strategy_normalize_1.normalizeStrategyUnits)(s));
61
- const refs = (0, strategy_analyze_1.uniq)(allUnits.map((u) => u.ref));
62
+ const refs = (0, array_1.uniq)(allUnits.map((u) => u.ref));
62
63
  (0, strategy_analyze_1.ensureNoInstalledVersionConflicts)(this.unitStore.readInstalledDependencyVersions(), refs);
63
64
  refs.forEach((ref) => this.unitStore.installPinned(ref));
64
65
  const installedStrategies = [];
@@ -95,7 +96,7 @@ class StrategyService {
95
96
  }
96
97
  const { strategy, source } = await (0, strategy_fetch_1.fetchStrategyFile)(sourceTrimmed);
97
98
  const normalizedUnits = (0, strategy_normalize_1.normalizeStrategyUnits)(strategy);
98
- const refs = (0, strategy_analyze_1.uniq)(normalizedUnits.map((u) => u.ref));
99
+ const refs = (0, array_1.uniq)(normalizedUnits.map((u) => u.ref));
99
100
  const strategyPath = this.getStrategyPath(strategy.name);
100
101
  if (!input.force && node_fs_1.default.existsSync(strategyPath)) {
101
102
  throw new Error(`Strategy already exists: ${strategy.name}`);
@@ -129,7 +130,7 @@ class StrategyService {
129
130
  }
130
131
  const installed = this.unitStore.readInstalledDependencyVersions();
131
132
  if (opts?.packageOnly) {
132
- const packageNames = (0, strategy_analyze_1.uniq)(names
133
+ const packageNames = (0, array_1.uniq)(names
133
134
  .flatMap((n) => (0, strategy_normalize_1.normalizeStrategyUnits)(this.readStrategy(n)).map((u) => (0, parse_pinned_spec_1.parsePinnedSpec)(u.ref).name))
134
135
  .filter((x) => x.trim().length > 0));
135
136
  packageNames.forEach((pkg) => {
@@ -232,7 +233,7 @@ class StrategyService {
232
233
  if (conflicts.length > 0) {
233
234
  throw new Error(`Strategy version conflicts detected (${conflicts.length}). Run 'pp strategy doctor' for details.`);
234
235
  }
235
- const refs = (0, strategy_analyze_1.uniq)(nextStrategies.flatMap((s) => s.units.map((u) => u.ref)));
236
+ const refs = (0, array_1.uniq)(nextStrategies.flatMap((s) => s.units.map((u) => u.ref)));
236
237
  (0, strategy_analyze_1.ensureNoInstalledVersionConflicts)(installed, refs);
237
238
  refs.forEach((ref) => {
238
239
  this.unitStore.installPinned(ref);
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.parsePinnedSpec = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const node_module_1 = require("node:module");
4
9
  const isRecord = (value) => {
5
10
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
6
11
  };
@@ -12,7 +17,8 @@ const parsePinnedSpec = (input) => {
12
17
  if (!trimmed) {
13
18
  throw new Error("package spec is empty");
14
19
  }
15
- const npa = require("npm-package-arg");
20
+ const req = (0, node_module_1.createRequire)(typeof __filename === "string" ? __filename : node_path_1.default.join(process.cwd(), "package.json"));
21
+ const npa = req("npm-package-arg");
16
22
  const parsed = npa(trimmed);
17
23
  if (!isRecord(parsed)) {
18
24
  throw new Error(`Invalid package spec: ${trimmed}`);
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uniq = void 0;
4
+ const uniq = (items) => {
5
+ return [...new Set(items)];
6
+ };
7
+ exports.uniq = uniq;
@@ -1,12 +1,18 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.parsePluginSpec = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const node_module_1 = require("node:module");
4
9
  const parsePluginSpec = (spec) => {
5
10
  const trimmed = spec.trim();
6
11
  if (!trimmed) {
7
12
  throw new Error("plugin spec is empty");
8
13
  }
9
- const npa = require("npm-package-arg");
14
+ const req = (0, node_module_1.createRequire)(typeof __filename === "string" ? __filename : node_path_1.default.join(process.cwd(), "package.json"));
15
+ const npa = req("npm-package-arg");
10
16
  const parsed = npa(trimmed);
11
17
  if (!parsed || typeof parsed.name !== "string" || !parsed.name) {
12
18
  throw new Error(`Invalid plugin spec: ${trimmed}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagepocket/cli",
3
- "version": "0.10.1",
3
+ "version": "0.11.0",
4
4
  "description": "CLI for capturing offline snapshots of web pages.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -21,16 +21,16 @@
21
21
  "koa-static": "^5.0.0",
22
22
  "npm-package-arg": "^13.0.2",
23
23
  "ora": "^9.0.0",
24
- "@pagepocket/build-snapshot-unit": "0.10.1",
25
- "@pagepocket/capture-http-puppeteer-unit": "0.10.1",
26
- "@pagepocket/contracts": "0.10.1",
27
- "@pagepocket/capture-http-lighterceptor-unit": "0.10.1",
28
- "@pagepocket/capture-http-cdp-unit": "0.10.1",
29
- "@pagepocket/lib": "0.10.1",
30
- "@pagepocket/builtin-strategy": "0.10.1",
31
- "@pagepocket/plugin-yt-dlp": "0.10.1",
32
- "@pagepocket/single-file-unit": "0.10.1",
33
- "@pagepocket/write-down-unit": "0.10.1"
24
+ "@pagepocket/build-snapshot-unit": "0.11.0",
25
+ "@pagepocket/capture-http-lighterceptor-unit": "0.11.0",
26
+ "@pagepocket/capture-http-cdp-unit": "0.11.0",
27
+ "@pagepocket/capture-http-puppeteer-unit": "0.11.0",
28
+ "@pagepocket/contracts": "0.11.0",
29
+ "@pagepocket/lib": "0.11.0",
30
+ "@pagepocket/builtin-strategy": "0.11.0",
31
+ "@pagepocket/plugin-yt-dlp": "0.11.0",
32
+ "@pagepocket/single-file-unit": "0.11.0",
33
+ "@pagepocket/write-down-unit": "0.11.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/koa": "^2.15.0",
@@ -1,28 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.readInstalledPackageVersion = void 0;
7
- const node_fs_1 = __importDefault(require("node:fs"));
8
- const parse_json_1 = require("../../utils/parse-json");
9
- const isRecord = (value) => {
10
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
11
- };
12
- const readInstalledPackageVersion = (packageName) => {
13
- const req = globalThis.require;
14
- if (!req) {
15
- throw new Error("require is not available in this runtime");
16
- }
17
- const pkgJsonPath = req.resolve(`${packageName}/package.json`);
18
- const text = node_fs_1.default.readFileSync(pkgJsonPath, "utf8");
19
- const parsed = (0, parse_json_1.parseJson)(text);
20
- if (!parsed.ok) {
21
- throw parsed.error;
22
- }
23
- if (!isRecord(parsed.value) || typeof parsed.value.version !== "string") {
24
- throw new Error(`Failed to read package version: ${packageName}`);
25
- }
26
- return parsed.value.version;
27
- };
28
- exports.readInstalledPackageVersion = readInstalledPackageVersion;