@checkstack/scripts 0.2.0 → 0.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/scripts",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Checkstack tooling: plugin scaffolding, codegen, and the plugin-pack CLI used by external plugin authors.",
5
5
  "license": "Elastic-2.0",
6
6
  "type": "module",
@@ -22,19 +22,13 @@
22
22
  "typecheck": "tsgo -b"
23
23
  },
24
24
  "dependencies": {
25
- "@checkstack/common": "0.7.0",
26
- "@checkstack/backend": "0.8.2",
27
- "@checkstack/frontend": "0.4.2",
28
- "@checkstack/frontend-api": "0.4.1",
29
- "@checkstack/ui": "1.7.0",
30
- "@vitejs/plugin-react": "^4.3.4",
25
+ "@checkstack/common": "0.8.0",
31
26
  "inquirer": "^13.4.1",
32
27
  "handlebars": "^4.7.8",
33
- "tar": "^7.4.3",
34
- "vite": "^5.4.0"
28
+ "tar": "^7.4.3"
35
29
  },
36
30
  "devDependencies": {
37
- "@checkstack/tsconfig": "0.0.6",
31
+ "@checkstack/tsconfig": "0.0.7",
38
32
  "@types/inquirer": "^8.2.10",
39
33
  "@types/handlebars": "^4.1.0",
40
34
  "typescript": "^5.0.0"
package/src/cli.ts CHANGED
@@ -11,7 +11,6 @@ if (!command) {
11
11
  console.log(" sync - Synchronize package configurations");
12
12
  console.log(" generate - Generate migrations and strip public schema");
13
13
  console.log(" plugin-pack - Pack a plugin (or bundle) into a .tgz for distribution");
14
- console.log(" dev - Run a local Checkstack dev server with the current directory's plugin loaded");
15
14
  console.log(" typecheck - Run TypeScript type checking");
16
15
  console.log(" lint - Run linting checks");
17
16
  process.exit(1);
@@ -67,16 +66,6 @@ if (command === "plugin-pack") {
67
66
  process.exit(result.status ?? 0);
68
67
  }
69
68
 
70
- if (command === "dev") {
71
- const scriptPath = path.resolve(
72
- new URL("commands/dev-server.ts", import.meta.url).pathname,
73
- );
74
- const result = spawnSync("bun", ["run", scriptPath, ...process.argv.slice(3)], {
75
- stdio: "inherit",
76
- });
77
- process.exit(result.status ?? 0);
78
- }
79
-
80
69
  // Fallback for other scripts if we want to centralize their execution logic
81
70
  console.error(`Unknown command: ${command}`);
82
71
  process.exit(1);
@@ -14,7 +14,7 @@
14
14
  "pluginId": "{{pluginBaseName}}"
15
15
  },
16
16
  "scripts": {
17
- "dev": "bunx @checkstack/scripts dev",
17
+ "dev": "checkstack-dev",
18
18
  "pack": "bunx @checkstack/scripts plugin-pack",
19
19
  "typecheck": "tsgo -b",
20
20
  "lint": "bun run lint:code",
@@ -30,6 +30,8 @@
30
30
  },
31
31
  "devDependencies": {
32
32
  "@checkstack/scripts": "workspace:*",
33
+ "@checkstack/dev-server": "workspace:*",
34
+ "@checkstack/backend": "workspace:*",
33
35
  "@checkstack/tsconfig": "workspace:*",
34
36
  "@checkstack/drizzle-helper": "workspace:*",
35
37
  "@checkstack/test-utils-backend": "workspace:*",
@@ -14,7 +14,7 @@
14
14
  "pluginId": "{{pluginBaseName}}"
15
15
  },
16
16
  "scripts": {
17
- "dev": "bunx @checkstack/scripts dev",
17
+ "dev": "checkstack-dev",
18
18
  "pack": "bunx @checkstack/scripts plugin-pack",
19
19
  "typecheck": "tsgo -b",
20
20
  "lint": "bun run lint:code",
@@ -32,6 +32,8 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "@checkstack/scripts": "workspace:*",
35
+ "@checkstack/dev-server": "workspace:*",
36
+ "@checkstack/frontend": "workspace:*",
35
37
  "@checkstack/tsconfig": "workspace:*",
36
38
  "@checkstack/test-utils-frontend": "workspace:*",
37
39
  "@types/react": "^18.3.1",
@@ -4,7 +4,7 @@ import {
4
4
  prepareTemplateData,
5
5
  registerHelpers,
6
6
  } from "./utils/template";
7
- import { validatePluginPackageJson } from "./commands/dev-internals";
7
+ import { installPackageMetadataSchema } from "@checkstack/common";
8
8
  import { execSync } from "node:child_process";
9
9
  import { rmSync, existsSync, mkdirSync, readFileSync } from "node:fs";
10
10
  import path from "node:path";
@@ -138,42 +138,60 @@ describe("CLI Template Scaffolding", () => {
138
138
  // because they only inspect static metadata.
139
139
  // ────────────────────────────────────────────────────────────
140
140
 
141
- it("renders a package.json that the dev-server's validator accepts", () => {
142
- const result = validatePluginPackageJson({ cwd: targetDir });
143
- if (!result.ok) {
141
+ it("renders a package.json that the install-time validator accepts", () => {
142
+ // Validate against the same schema dev-server and the runtime
143
+ // plugin installer use. Inlined here (rather than imported from
144
+ // dev-server) so `@checkstack/scripts` doesn't take a dep on
145
+ // `@checkstack/dev-server`.
146
+ const pkgJsonPath = path.join(targetDir, "package.json");
147
+ const raw = JSON.parse(readFileSync(pkgJsonPath, "utf8")) as unknown;
148
+ const result = installPackageMetadataSchema.safeParse(raw);
149
+ if (!result.success) {
144
150
  throw new Error(
145
- `Generated package.json fails dev-server validation:\n${
146
- "issues" in result
147
- ? result.issues.join("\n")
148
- : "package.json missing"
149
- }`,
151
+ `Generated package.json fails install-time validation:\n${result.error.issues
152
+ .map((issue) => `${issue.path.join(".")}: ${issue.message}`)
153
+ .join("\n")}`,
150
154
  );
151
155
  }
152
156
  // Sanity-check the metadata shape so a later schema change
153
157
  // surfaces here too.
154
- expect(result.metadata.name).toBe(`@checkstack/${pluginName}`);
155
- expect(result.metadata.checkstack.type).toBe(pluginType);
156
- expect(result.metadata.checkstack.pluginId).toBe(TEST_BASE_NAME);
157
- expect(result.metadata.author).toBeDefined();
158
- expect(result.metadata.license).toBe("Elastic-2.0");
158
+ expect(result.data.name).toBe(`@checkstack/${pluginName}`);
159
+ expect(result.data.checkstack.type).toBe(pluginType);
160
+ expect(result.data.checkstack.pluginId).toBe(TEST_BASE_NAME);
161
+ expect(result.data.author).toBeDefined();
162
+ expect(result.data.license).toBe("Elastic-2.0");
159
163
  });
160
164
 
161
- it("includes the @checkstack/scripts devDependency so bunx resolves the dev/pack commands", () => {
165
+ it("includes the @checkstack/scripts devDependency so `bunx @checkstack/scripts plugin-pack` resolves", () => {
162
166
  const pkg = JSON.parse(
163
167
  readFileSync(path.join(targetDir, "package.json"), "utf8"),
164
168
  ) as { devDependencies?: Record<string, string> };
165
169
  expect(pkg.devDependencies?.["@checkstack/scripts"]).toBeDefined();
166
170
  });
167
171
 
172
+ it("includes @checkstack/dev-server (backend/frontend only) so the local dev loop is one-click", () => {
173
+ const pkg = JSON.parse(
174
+ readFileSync(path.join(targetDir, "package.json"), "utf8"),
175
+ ) as { devDependencies?: Record<string, string> };
176
+ if (pluginType === "common") {
177
+ // Common packages have no runtime, so the dev server makes no
178
+ // sense for them.
179
+ expect(pkg.devDependencies?.["@checkstack/dev-server"]).toBeUndefined();
180
+ } else {
181
+ expect(pkg.devDependencies?.["@checkstack/dev-server"]).toBeDefined();
182
+ }
183
+ });
184
+
168
185
  it("includes the `pack` script (and the `dev` script for backend/frontend)", () => {
169
186
  const pkg = JSON.parse(
170
187
  readFileSync(path.join(targetDir, "package.json"), "utf8"),
171
188
  ) as { scripts?: Record<string, string> };
172
189
  expect(pkg.scripts?.pack).toBe("bunx @checkstack/scripts plugin-pack");
173
190
  if (pluginType !== "common") {
174
- // Common packages have no runtime, so a dev server makes no
175
- // sense for them but backend/frontend must be one-click.
176
- expect(pkg.scripts?.dev).toBe("bunx @checkstack/scripts dev");
191
+ // Backend/frontend templates pin the dev script to the
192
+ // `checkstack-dev` bin (provided by `@checkstack/dev-server`,
193
+ // which the template adds as a devDependency).
194
+ expect(pkg.scripts?.dev).toBe("checkstack-dev");
177
195
  }
178
196
  });
179
197
  });
@@ -1,411 +0,0 @@
1
- import { describe, it, expect } from "bun:test";
2
- import path from "node:path";
3
- import { resolveCorePluginDeps } from "./dev-deps-resolver";
4
-
5
- /**
6
- * In-memory fixture for a virtual node_modules tree. Maps a fully
7
- * qualified file path to its file contents (typically package.json
8
- * stringified JSON).
9
- */
10
- type Fs = Record<string, string>;
11
-
12
- const ROOT = "/plugin-author/repo";
13
- const NM = `${ROOT}/node_modules`;
14
-
15
- function makeFs(packages: Record<string, unknown>): Fs {
16
- const out: Fs = {};
17
- for (const [name, pkg] of Object.entries(packages)) {
18
- out[`${NM}/${name}/package.json`] = JSON.stringify(pkg);
19
- }
20
- return out;
21
- }
22
-
23
- function makeResolver(fs: Fs) {
24
- return (_from: string, request: string): string | undefined => {
25
- // Only handle requests of the form `<pkg>/package.json` — that's all
26
- // resolveCorePluginDeps issues. A real `createRequire` resolves any
27
- // entry, but we don't need that fidelity here.
28
- if (!request.endsWith("/package.json")) return undefined;
29
- const pkgName = request.replace(/\/package\.json$/, "");
30
- const candidate = `${NM}/${pkgName}/package.json`;
31
- return fs[candidate] === undefined ? undefined : candidate;
32
- };
33
- }
34
-
35
- function readFileFromFs(fs: Fs) {
36
- return (p: string): string => {
37
- const text = fs[p];
38
- if (text === undefined) throw new Error(`ENOENT: ${p}`);
39
- return text;
40
- };
41
- }
42
-
43
- describe("resolveCorePluginDeps", () => {
44
- it("returns only the auto-included providers for a plugin with no @checkstack/* backend deps", () => {
45
- const fs: Fs = {
46
- [`${ROOT}/package.json`]: JSON.stringify({
47
- name: "@my-org/widget-backend",
48
- dependencies: {
49
- "@checkstack/backend-api": "^1.0.0",
50
- lodash: "^4.0.0",
51
- },
52
- checkstack: { type: "backend", pluginId: "widget" },
53
- }),
54
- ...makeFs({
55
- "@checkstack/backend-api": {
56
- name: "@checkstack/backend-api",
57
- checkstack: { type: "common" },
58
- },
59
- "@checkstack/queue-memory-backend": {
60
- name: "@checkstack/queue-memory-backend",
61
- main: "src/index.ts",
62
- checkstack: { type: "backend", pluginId: "queue-memory" },
63
- },
64
- "@checkstack/cache-memory-backend": {
65
- name: "@checkstack/cache-memory-backend",
66
- main: "src/index.ts",
67
- checkstack: { type: "backend", pluginId: "cache-memory" },
68
- },
69
- }),
70
- };
71
-
72
- const resolved = resolveCorePluginDeps({
73
- pluginDir: ROOT,
74
- readFile: readFileFromFs(fs),
75
- resolveFrom: makeResolver(fs),
76
- });
77
-
78
- const names = resolved.map((r) => r.name).toSorted();
79
- expect(names).toEqual([
80
- "@checkstack/cache-memory-backend",
81
- "@checkstack/queue-memory-backend",
82
- ]);
83
- });
84
-
85
- it("includes a single backend dep declared in dependencies", () => {
86
- const fs: Fs = {
87
- [`${ROOT}/package.json`]: JSON.stringify({
88
- name: "@my-org/healthcheck-rcon-backend",
89
- dependencies: {
90
- "@checkstack/healthcheck-backend": "^1.0.0",
91
- },
92
- checkstack: { type: "backend", pluginId: "healthcheck-rcon" },
93
- }),
94
- ...makeFs({
95
- "@checkstack/healthcheck-backend": {
96
- name: "@checkstack/healthcheck-backend",
97
- main: "src/index.ts",
98
- checkstack: { type: "backend", pluginId: "healthcheck" },
99
- dependencies: {},
100
- },
101
- "@checkstack/queue-memory-backend": {
102
- name: "@checkstack/queue-memory-backend",
103
- main: "src/index.ts",
104
- checkstack: { type: "backend", pluginId: "queue-memory" },
105
- },
106
- "@checkstack/cache-memory-backend": {
107
- name: "@checkstack/cache-memory-backend",
108
- main: "src/index.ts",
109
- checkstack: { type: "backend", pluginId: "cache-memory" },
110
- },
111
- }),
112
- };
113
-
114
- const resolved = resolveCorePluginDeps({
115
- pluginDir: ROOT,
116
- readFile: readFileFromFs(fs),
117
- resolveFrom: makeResolver(fs),
118
- });
119
-
120
- expect(resolved.map((r) => r.name).toSorted()).toEqual([
121
- "@checkstack/cache-memory-backend",
122
- "@checkstack/healthcheck-backend",
123
- "@checkstack/queue-memory-backend",
124
- ]);
125
-
126
- const hc = resolved.find((r) => r.name === "@checkstack/healthcheck-backend");
127
- expect(hc?.modulePath).toBe(
128
- path.resolve(`${NM}/@checkstack/healthcheck-backend/src/index.ts`),
129
- );
130
- });
131
-
132
- it("walks transitive @checkstack/* backend deps", () => {
133
- // Plugin → notification-discord-backend → notification-backend → catalog-backend
134
- const fs: Fs = {
135
- [`${ROOT}/package.json`]: JSON.stringify({
136
- name: "@my-org/widget-backend",
137
- dependencies: {
138
- "@checkstack/notification-discord-backend": "^1.0.0",
139
- },
140
- checkstack: { type: "backend", pluginId: "widget" },
141
- }),
142
- ...makeFs({
143
- "@checkstack/notification-discord-backend": {
144
- name: "@checkstack/notification-discord-backend",
145
- main: "src/index.ts",
146
- checkstack: { type: "backend", pluginId: "notification-discord" },
147
- dependencies: {
148
- "@checkstack/notification-backend": "^1.0.0",
149
- },
150
- },
151
- "@checkstack/notification-backend": {
152
- name: "@checkstack/notification-backend",
153
- main: "src/index.ts",
154
- checkstack: { type: "backend", pluginId: "notification" },
155
- dependencies: {
156
- "@checkstack/catalog-backend": "^1.0.0",
157
- },
158
- },
159
- "@checkstack/catalog-backend": {
160
- name: "@checkstack/catalog-backend",
161
- main: "src/index.ts",
162
- checkstack: { type: "backend", pluginId: "catalog" },
163
- },
164
- "@checkstack/queue-memory-backend": {
165
- name: "@checkstack/queue-memory-backend",
166
- main: "src/index.ts",
167
- checkstack: { type: "backend", pluginId: "queue-memory" },
168
- },
169
- "@checkstack/cache-memory-backend": {
170
- name: "@checkstack/cache-memory-backend",
171
- main: "src/index.ts",
172
- checkstack: { type: "backend", pluginId: "cache-memory" },
173
- },
174
- }),
175
- };
176
-
177
- const resolved = resolveCorePluginDeps({
178
- pluginDir: ROOT,
179
- readFile: readFileFromFs(fs),
180
- resolveFrom: makeResolver(fs),
181
- });
182
-
183
- expect(resolved.map((r) => r.name).toSorted()).toEqual([
184
- "@checkstack/cache-memory-backend",
185
- "@checkstack/catalog-backend",
186
- "@checkstack/notification-backend",
187
- "@checkstack/notification-discord-backend",
188
- "@checkstack/queue-memory-backend",
189
- ]);
190
- });
191
-
192
- it("walks through common-type packages to find transitive backend deps", () => {
193
- // Plugin → my-shared-common (type: common) → healthcheck-backend
194
- // (Unusual but possible; common packages can list runtime deps.)
195
- const fs: Fs = {
196
- [`${ROOT}/package.json`]: JSON.stringify({
197
- name: "@my-org/widget-backend",
198
- dependencies: {
199
- "@checkstack/widget-common": "^1.0.0",
200
- },
201
- checkstack: { type: "backend", pluginId: "widget" },
202
- }),
203
- ...makeFs({
204
- "@checkstack/widget-common": {
205
- name: "@checkstack/widget-common",
206
- checkstack: { type: "common" },
207
- dependencies: {
208
- "@checkstack/healthcheck-backend": "^1.0.0",
209
- },
210
- },
211
- "@checkstack/healthcheck-backend": {
212
- name: "@checkstack/healthcheck-backend",
213
- main: "src/index.ts",
214
- checkstack: { type: "backend", pluginId: "healthcheck" },
215
- },
216
- "@checkstack/queue-memory-backend": {
217
- name: "@checkstack/queue-memory-backend",
218
- main: "src/index.ts",
219
- checkstack: { type: "backend", pluginId: "queue-memory" },
220
- },
221
- "@checkstack/cache-memory-backend": {
222
- name: "@checkstack/cache-memory-backend",
223
- main: "src/index.ts",
224
- checkstack: { type: "backend", pluginId: "cache-memory" },
225
- },
226
- }),
227
- };
228
-
229
- const resolved = resolveCorePluginDeps({
230
- pluginDir: ROOT,
231
- readFile: readFileFromFs(fs),
232
- resolveFrom: makeResolver(fs),
233
- });
234
-
235
- expect(resolved.map((r) => r.name)).toContain(
236
- "@checkstack/healthcheck-backend",
237
- );
238
- // The common pkg itself isn't loaded as a plugin
239
- expect(resolved.map((r) => r.name)).not.toContain(
240
- "@checkstack/widget-common",
241
- );
242
- });
243
-
244
- it("excludes the plugin under dev itself even when listed transitively", () => {
245
- const fs: Fs = {
246
- [`${ROOT}/package.json`]: JSON.stringify({
247
- name: "@my-org/widget-backend",
248
- dependencies: {
249
- "@checkstack/healthcheck-backend": "^1.0.0",
250
- },
251
- checkstack: { type: "backend", pluginId: "widget" },
252
- }),
253
- ...makeFs({
254
- "@checkstack/healthcheck-backend": {
255
- name: "@checkstack/healthcheck-backend",
256
- main: "src/index.ts",
257
- checkstack: { type: "backend", pluginId: "healthcheck" },
258
- // Pretend the platform plugin pulls back into the user's plugin
259
- // (this would never happen in practice, but the resolver must
260
- // never try to load the plugin under dev as a sibling).
261
- dependencies: {
262
- "@my-org/widget-backend": "^1.0.0",
263
- },
264
- },
265
- "@checkstack/queue-memory-backend": {
266
- name: "@checkstack/queue-memory-backend",
267
- main: "src/index.ts",
268
- checkstack: { type: "backend", pluginId: "queue-memory" },
269
- },
270
- "@checkstack/cache-memory-backend": {
271
- name: "@checkstack/cache-memory-backend",
272
- main: "src/index.ts",
273
- checkstack: { type: "backend", pluginId: "cache-memory" },
274
- },
275
- }),
276
- };
277
-
278
- const resolved = resolveCorePluginDeps({
279
- pluginDir: ROOT,
280
- readFile: readFileFromFs(fs),
281
- resolveFrom: makeResolver(fs),
282
- });
283
- expect(resolved.map((r) => r.name)).not.toContain("@my-org/widget-backend");
284
- });
285
-
286
- it("skips queue-memory auto-include when bullmq is already in the dep graph", () => {
287
- const fs: Fs = {
288
- [`${ROOT}/package.json`]: JSON.stringify({
289
- name: "@my-org/widget-backend",
290
- dependencies: {
291
- "@checkstack/queue-bullmq-backend": "^1.0.0",
292
- },
293
- checkstack: { type: "backend", pluginId: "widget" },
294
- }),
295
- ...makeFs({
296
- "@checkstack/queue-bullmq-backend": {
297
- name: "@checkstack/queue-bullmq-backend",
298
- main: "src/index.ts",
299
- checkstack: { type: "backend", pluginId: "queue-bullmq" },
300
- },
301
- "@checkstack/queue-memory-backend": {
302
- name: "@checkstack/queue-memory-backend",
303
- main: "src/index.ts",
304
- checkstack: { type: "backend", pluginId: "queue-memory" },
305
- },
306
- "@checkstack/cache-memory-backend": {
307
- name: "@checkstack/cache-memory-backend",
308
- main: "src/index.ts",
309
- checkstack: { type: "backend", pluginId: "cache-memory" },
310
- },
311
- }),
312
- };
313
-
314
- const resolved = resolveCorePluginDeps({
315
- pluginDir: ROOT,
316
- readFile: readFileFromFs(fs),
317
- resolveFrom: makeResolver(fs),
318
- });
319
- const names = resolved.map((r) => r.name);
320
- expect(names).toContain("@checkstack/queue-bullmq-backend");
321
- expect(names).not.toContain("@checkstack/queue-memory-backend");
322
- });
323
-
324
- it("does not include @checkstack/* frontend or tooling packages", () => {
325
- const fs: Fs = {
326
- [`${ROOT}/package.json`]: JSON.stringify({
327
- name: "@my-org/widget-backend",
328
- dependencies: {
329
- "@checkstack/healthcheck-backend": "^1.0.0",
330
- "@checkstack/healthcheck-frontend": "^1.0.0",
331
- "@checkstack/scripts": "^0.1.0",
332
- },
333
- checkstack: { type: "backend", pluginId: "widget" },
334
- }),
335
- ...makeFs({
336
- "@checkstack/healthcheck-backend": {
337
- name: "@checkstack/healthcheck-backend",
338
- main: "src/index.ts",
339
- checkstack: { type: "backend", pluginId: "healthcheck" },
340
- },
341
- "@checkstack/healthcheck-frontend": {
342
- name: "@checkstack/healthcheck-frontend",
343
- main: "src/index.tsx",
344
- checkstack: { type: "frontend", pluginId: "healthcheck" },
345
- },
346
- "@checkstack/scripts": {
347
- name: "@checkstack/scripts",
348
- checkstack: { type: "tooling" },
349
- },
350
- "@checkstack/queue-memory-backend": {
351
- name: "@checkstack/queue-memory-backend",
352
- main: "src/index.ts",
353
- checkstack: { type: "backend", pluginId: "queue-memory" },
354
- },
355
- "@checkstack/cache-memory-backend": {
356
- name: "@checkstack/cache-memory-backend",
357
- main: "src/index.ts",
358
- checkstack: { type: "backend", pluginId: "cache-memory" },
359
- },
360
- }),
361
- };
362
-
363
- const resolved = resolveCorePluginDeps({
364
- pluginDir: ROOT,
365
- readFile: readFileFromFs(fs),
366
- resolveFrom: makeResolver(fs),
367
- });
368
- const names = resolved.map((r) => r.name);
369
- expect(names).toContain("@checkstack/healthcheck-backend");
370
- expect(names).not.toContain("@checkstack/healthcheck-frontend");
371
- expect(names).not.toContain("@checkstack/scripts");
372
- });
373
-
374
- it("silently skips a declared dep that isn't actually installed", () => {
375
- const fs: Fs = {
376
- [`${ROOT}/package.json`]: JSON.stringify({
377
- name: "@my-org/widget-backend",
378
- dependencies: {
379
- "@checkstack/missing-backend": "^1.0.0",
380
- },
381
- checkstack: { type: "backend", pluginId: "widget" },
382
- }),
383
- ...makeFs({
384
- "@checkstack/queue-memory-backend": {
385
- name: "@checkstack/queue-memory-backend",
386
- main: "src/index.ts",
387
- checkstack: { type: "backend", pluginId: "queue-memory" },
388
- },
389
- "@checkstack/cache-memory-backend": {
390
- name: "@checkstack/cache-memory-backend",
391
- main: "src/index.ts",
392
- checkstack: { type: "backend", pluginId: "cache-memory" },
393
- },
394
- }),
395
- };
396
-
397
- const resolved = resolveCorePluginDeps({
398
- pluginDir: ROOT,
399
- readFile: readFileFromFs(fs),
400
- resolveFrom: makeResolver(fs),
401
- });
402
- expect(resolved.map((r) => r.name)).not.toContain(
403
- "@checkstack/missing-backend",
404
- );
405
- // Auto-included providers still present — boot needs them.
406
- expect(resolved.map((r) => r.name).toSorted()).toEqual([
407
- "@checkstack/cache-memory-backend",
408
- "@checkstack/queue-memory-backend",
409
- ]);
410
- });
411
- });