@theholocron/cli 5.0.0-alpha.110 → 5.0.0-alpha.112

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/dist/cli.mjs CHANGED
@@ -2167,14 +2167,16 @@ describe("resolveToken", () => {
2167
2167
  });
2168
2168
 
2169
2169
  it("throws AuthError with a helpful message when nothing is set", () => {
2170
- try {
2171
- resolveToken({ env: {}, keyring: noKeyring });
2172
- throw new Error("should have thrown");
2173
- } catch (err) {
2174
- expect(err).toBeInstanceOf(AuthError);
2175
- expect((err as Error).message).toMatch(/${inputs.tokenEnv}/);
2176
- expect((err as Error).message).toMatch(/holocron auth set ${inputs.slug}/);
2177
- }
2170
+ const err = (() => {
2171
+ try {
2172
+ resolveToken({ env: {}, keyring: noKeyring });
2173
+ } catch (e) {
2174
+ return e;
2175
+ }
2176
+ })();
2177
+ expect(err).toBeInstanceOf(AuthError);
2178
+ expect((err as Error).message).toMatch(/${inputs.tokenEnv}/);
2179
+ expect((err as Error).message).toMatch(/holocron auth set ${inputs.slug}/);
2178
2180
  });
2179
2181
  });
2180
2182
  `;
@@ -2218,24 +2220,24 @@ export class ${inputs.capabilityClass} {
2218
2220
  //#endregion
2219
2221
  //#region src/commands/plugin-create/templates/capability-test.ts
2220
2222
  function render$14(inputs) {
2221
- const clientClass = `${inputs.vendorName}RestClient`;
2222
- return `import { describe, it } from "vitest";
2223
+ const factoryName = `create${inputs.vendorName}RestClient`;
2224
+ return `import { describe, expect, it } from "vitest";
2223
2225
 
2224
2226
  import { ${inputs.capabilityClass} } from "../capabilities/${inputs.capability}.js";
2225
- import { ${clientClass} } from "../rest.js";
2227
+ import { ${factoryName} } from "../rest.js";
2226
2228
  import { stubFetch } from "./helpers.js";
2227
2229
 
2228
2230
  // Stub client used by the constructor smoke test. Real capability
2229
2231
  // tests replace this with per-method stubs once implementations land.
2230
2232
  function makeCapability() {
2231
2233
  const stub = stubFetch([]);
2232
- const rest = new ${clientClass}({ token: "t", fetch: stub.fetch });
2234
+ const rest = ${factoryName}({ token: "t", fetch: stub.fetch });
2233
2235
  return new ${inputs.capabilityClass}(() => rest);
2234
2236
  }
2235
2237
 
2236
2238
  describe("${inputs.capabilityClass}", () => {
2237
2239
  it("constructs with a REST client", () => {
2238
- makeCapability();
2240
+ expect(makeCapability().key).toBe("${inputs.capability}");
2239
2241
  });
2240
2242
 
2241
2243
  // TODO: implement one test per ${inputs.capability} capability method
@@ -2251,14 +2253,11 @@ describe("${inputs.capabilityClass}", () => {
2251
2253
  //#endregion
2252
2254
  //#region src/commands/plugin-create/templates/eslint-config.ts
2253
2255
  function render$13(_inputs) {
2254
- return `import root from "../../eslint.config.js";
2256
+ return `import type { Linter } from "eslint";
2255
2257
 
2256
- export default [
2257
- ...root,
2258
- {
2259
- ignores: ["dist/**", "coverage/**"],
2260
- },
2261
- ];
2258
+ import root from "../../eslint.config.js";
2259
+
2260
+ export default [...root, { ignores: ["dist/**", "coverage/**"] }] satisfies Linter.Config[];
2262
2261
  `;
2263
2262
  }
2264
2263
  //#endregion
@@ -2341,10 +2340,17 @@ describe("AUTH_HINT", () => {
2341
2340
  //#endregion
2342
2341
  //#region src/commands/plugin-create/templates/package-json.ts
2343
2342
  function render$10(inputs) {
2343
+ const keywords = [
2344
+ inputs.capability,
2345
+ "holocron",
2346
+ "plugin",
2347
+ inputs.slug
2348
+ ].sort((a, b) => a.localeCompare(b));
2344
2349
  return JSON.stringify({
2345
2350
  name: `@theholocron/holocron-plugin-${inputs.slug}`,
2346
2351
  version: "2.0.0-alpha.1",
2347
2352
  description: `Holocron plugin for ${inputs.vendorName}. Implements the ${inputs.capability} capability against ${inputs.vendorName}'s REST API, plus exports verifyToken + AUTH_HINT for \`holocron auth\`.`,
2353
+ keywords,
2348
2354
  homepage: `https://github.com/theholocron/holocron/tree/main/packages/holocron-plugin-${inputs.slug}#readme`,
2349
2355
  bugs: "https://github.com/theholocron/holocron/issues",
2350
2356
  repository: {
@@ -2354,9 +2360,13 @@ function render$10(inputs) {
2354
2360
  },
2355
2361
  license: "MIT",
2356
2362
  author: "Newton Koumantzelis",
2363
+ sideEffects: false,
2357
2364
  type: "module",
2358
- main: "./src/index.ts",
2359
- exports: { ".": "./src/index.ts" },
2365
+ exports: { ".": {
2366
+ types: "./dist/index.d.mts",
2367
+ import: "./dist/index.mjs",
2368
+ default: "./dist/index.mjs"
2369
+ } },
2360
2370
  scripts: {
2361
2371
  "delivery.build": "tsdown",
2362
2372
  "sourceQuality.staticAnalysis": "holocron run sourceQuality.staticAnalysis --",
@@ -2368,33 +2378,26 @@ function render$10(inputs) {
2368
2378
  peerDependencies: { "@theholocron/cli": "workspace:*" },
2369
2379
  devDependencies: {
2370
2380
  "@theholocron/cli": "workspace:*",
2371
- "@theholocron/tsconfig": "catalog:",
2372
- "@tsconfig/node-lts": "catalog:",
2381
+ "@theholocron/tsconfig": "catalog:configs",
2382
+ "@types/node": "catalog:",
2373
2383
  "@vitest/coverage-v8": "catalog:",
2374
2384
  eslint: "catalog:",
2375
2385
  globals: "catalog:",
2376
- typescript: "catalog:",
2377
- vitest: "catalog:",
2378
2386
  tsdown: "catalog:",
2379
- tsx: "catalog:"
2380
- },
2381
- publishConfig: {
2382
- access: "public",
2383
- main: "./dist/index.mjs",
2384
- types: "./dist/index.d.mts",
2385
- exports: { ".": {
2386
- types: "./dist/index.d.mts",
2387
- import: "./dist/index.mjs",
2388
- default: "./dist/index.mjs"
2389
- } }
2387
+ tsx: "catalog:",
2388
+ typescript: "catalog:",
2389
+ vitest: "catalog:"
2390
2390
  },
2391
- files: ["dist", "README.md"]
2392
- }, null, " ") + "\n";
2391
+ engines: { node: ">=22" },
2392
+ publishConfig: { access: "public" },
2393
+ files: ["dist"]
2394
+ }, null, 2) + "\n";
2393
2395
  }
2394
2396
  //#endregion
2395
2397
  //#region src/commands/plugin-create/templates/plugin-index.ts
2396
2398
  function render$9(inputs) {
2397
2399
  const clientClass = `${inputs.vendorName}RestClient`;
2400
+ const factoryName = `create${inputs.vendorName}RestClient`;
2398
2401
  const capabilityInterface = inputs.capability.charAt(0).toUpperCase() + inputs.capability.slice(1);
2399
2402
  return `/**
2400
2403
  * \`@theholocron/holocron-plugin-${inputs.slug}\` — entrypoint.
@@ -2411,7 +2414,7 @@ function render$9(inputs) {
2411
2414
 
2412
2415
  import { resolveToken, type ResolveTokenInput } from "./auth.js";
2413
2416
  import { ${inputs.capabilityClass} } from "./capabilities/${inputs.capability}.js";
2414
- import { ${clientClass} } from "./rest.js";
2417
+ import { ${factoryName}, type ${clientClass} } from "./rest.js";
2415
2418
 
2416
2419
  export interface ${inputs.vendorName}PluginOptions extends ResolveTokenInput {
2417
2420
  /** Override base URL for tests. */
@@ -2432,10 +2435,12 @@ export function createContext(options: ${inputs.vendorName}PluginOptions): Plugi
2432
2435
  options,
2433
2436
  rest: () => {
2434
2437
  if (rest) return rest;
2435
- const restOpts: ConstructorParameters<typeof ${clientClass}>[0] = { token: resolveToken(options) };
2438
+ const restOpts: { token: string; baseUrl?: string; fetch?: typeof fetch } = {
2439
+ token: resolveToken(options),
2440
+ };
2436
2441
  if (options.baseUrl !== undefined) restOpts.baseUrl = options.baseUrl;
2437
2442
  if (options.fetch !== undefined) restOpts.fetch = options.fetch;
2438
- return (rest = new ${clientClass}(restOpts));
2443
+ return (rest = ${factoryName}(restOpts));
2439
2444
  },
2440
2445
  };
2441
2446
  }
@@ -2469,7 +2474,7 @@ export const AUTH_HINT =
2469
2474
  // ── Public re-exports ────────────────────────────────────────────────
2470
2475
 
2471
2476
  export * from "./auth.js";
2472
- export { ${clientClass} } from "./rest.js";
2477
+ export { type ${clientClass}, ${factoryName} } from "./rest.js";
2473
2478
  export { ${inputs.capabilityClass} } from "./capabilities/${inputs.capability}.js";
2474
2479
  export { verifyToken } from "./verify-token.js";
2475
2480
  export type { VerifyTokenResult, VerifyTokenSuccess, VerifyTokenFailure } from "./verify-token.js";
@@ -2546,15 +2551,26 @@ Not yet published; capability methods are stubs.
2546
2551
  //#endregion
2547
2552
  //#region src/commands/plugin-create/templates/rest.ts
2548
2553
  function render$7(inputs) {
2549
- return `import { createRestClient, type RequestOptions, type RestClient } from "@theholocron/cli";
2554
+ const factoryName = `create${inputs.vendorName}RestClient`;
2555
+ const clientType = `${inputs.vendorName}RestClient`;
2556
+ return `import { createRestClient, type RestClient } from "@theholocron/cli";
2550
2557
 
2551
- export type { RequestOptions, RestClient };
2558
+ export type { RestClient };
2552
2559
 
2553
- export function ${`create${inputs.vendorName}RestClient`}(opts: {
2560
+ /**
2561
+ * TODO: narrow this to the specific ${inputs.vendorName} endpoints this
2562
+ * plugin's capability needs (see \`@theholocron/holocron-plugin-axiom\`'s
2563
+ * \`rest.ts\` for the pattern: an interface with one method per endpoint,
2564
+ * built internally via \`createRestClient\`). Starts as an alias for the
2565
+ * generic client so the scaffold compiles end to end immediately.
2566
+ */
2567
+ export type ${clientType} = RestClient;
2568
+
2569
+ export function ${factoryName}(opts: {
2554
2570
  \ttoken: string;
2555
2571
  \tbaseUrl?: string;
2556
2572
  \tfetch?: typeof fetch;
2557
- }): RestClient {
2573
+ }): ${clientType} {
2558
2574
  \treturn createRestClient({
2559
2575
  \t\tbaseUrl: opts.baseUrl ?? "${inputs.baseUrl}",
2560
2576
  \t\ttoken: opts.token,
@@ -2627,7 +2643,7 @@ describe("${factoryName}", () => {
2627
2643
  function render$5(inputs) {
2628
2644
  return JSON.stringify({
2629
2645
  display: `Holocron Plugin: ${inputs.vendorName}`,
2630
- extends: "@tsconfig/node-lts/tsconfig.json",
2646
+ extends: "@theholocron/tsconfig/node-lts",
2631
2647
  compilerOptions: {
2632
2648
  baseUrl: "./",
2633
2649
  outDir: "./dist",
@@ -2635,7 +2651,7 @@ function render$5(inputs) {
2635
2651
  },
2636
2652
  include: ["src/**/*.ts"],
2637
2653
  exclude: ["node_modules", "dist"]
2638
- }, null, " ") + "\n";
2654
+ }, null, 2) + "\n";
2639
2655
  }
2640
2656
  //#endregion
2641
2657
  //#region src/commands/plugin-create/templates/tsdown-config.ts
@@ -2751,6 +2767,7 @@ console.log("Done. Fill in capability method calls above before shipping.");
2751
2767
  // ── helpers ────────────────────────────────────────────────────────
2752
2768
 
2753
2769
  /** Wrap a capability call, print ERROR + hint on failure. */
2770
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- called once a real capability check replaces the TODO example above
2754
2771
  async function runStep(body) {
2755
2772
  try {
2756
2773
  await body();
@@ -2790,7 +2807,7 @@ function hintFor(message) {
2790
2807
  //#endregion
2791
2808
  //#region src/commands/plugin-create/templates/verify-token.ts
2792
2809
  function render$2(inputs) {
2793
- const clientClass = `${inputs.vendorName}RestClient`;
2810
+ const factoryName = `create${inputs.vendorName}RestClient`;
2794
2811
  return `/**
2795
2812
  * \`verifyToken\` — plugin-level export used by \`holocron auth set\` +
2796
2813
  * \`holocron auth check\`. Hits a lightweight whoami-style endpoint
@@ -2807,7 +2824,7 @@ function render$2(inputs) {
2807
2824
  * \`/me\`, \`/account\`.
2808
2825
  */
2809
2826
 
2810
- import { ${clientClass} } from "./rest.js";
2827
+ import { ${factoryName} } from "./rest.js";
2811
2828
 
2812
2829
  export interface VerifyTokenSuccess {
2813
2830
  ok: true;
@@ -2834,10 +2851,10 @@ export interface VerifyTokenOptions {
2834
2851
  }
2835
2852
 
2836
2853
  export async function verifyToken(token: string, opts: VerifyTokenOptions = {}): Promise<VerifyTokenResult> {
2837
- const restOpts: ConstructorParameters<typeof ${clientClass}>[0] = { token };
2854
+ const restOpts: { token: string; baseUrl?: string; fetch?: typeof fetch } = { token };
2838
2855
  if (opts.baseUrl !== undefined) restOpts.baseUrl = opts.baseUrl;
2839
2856
  if (opts.fetch !== undefined) restOpts.fetch = opts.fetch;
2840
- const rest = new ${clientClass}(restOpts);
2857
+ const rest = ${factoryName}(restOpts);
2841
2858
  try {
2842
2859
  const me = await rest.request<MeResponse>("/me");
2843
2860
  // Optional chaining because \`me\` is \`undefined\` on 204 / empty body.
@@ -2863,18 +2880,14 @@ describe("verifyToken", () => {
2863
2880
  const stub = stubFetch([{ status: 200, body: { email: "user@example.com" } }]);
2864
2881
  const result = await verifyToken("token", { fetch: stub.fetch });
2865
2882
  expect(result.ok).toBe(true);
2866
- if (result.ok) {
2867
- expect(result.subject).toMatch(/user@example.com/);
2868
- }
2883
+ expect((result as { ok: boolean; subject?: string }).subject).toMatch(/user@example.com/);
2869
2884
  });
2870
2885
 
2871
2886
  it("returns ok:false with the error message on 401", async () => {
2872
2887
  const stub = stubFetch([{ status: 401, body: { messages: ["Invalid token"] } }]);
2873
2888
  const result = await verifyToken("bad", { fetch: stub.fetch });
2874
2889
  expect(result.ok).toBe(false);
2875
- if (!result.ok) {
2876
- expect(result.message).toMatch(/→ 401/);
2877
- }
2890
+ expect((result as { ok: boolean; message?: string }).message).toMatch(/→ 401/);
2878
2891
  });
2879
2892
 
2880
2893
  it("returns ok:false when the network layer throws", async () => {
@@ -2883,9 +2896,7 @@ describe("verifyToken", () => {
2883
2896
  };
2884
2897
  const result = await verifyToken("t", { fetch: throwing });
2885
2898
  expect(result.ok).toBe(false);
2886
- if (!result.ok) {
2887
- expect(result.message).toMatch(/network down/);
2888
- }
2899
+ expect((result as { ok: boolean; message?: string }).message).toMatch(/network down/);
2889
2900
  });
2890
2901
  });
2891
2902
  `;
@@ -2959,7 +2970,7 @@ const TEMPLATES = [
2959
2970
  render
2960
2971
  },
2961
2972
  {
2962
- path: "eslint.config.js",
2973
+ path: "eslint.config.ts",
2963
2974
  render: render$13
2964
2975
  },
2965
2976
  {