@theholocron/holocron-plugin-postman 2.0.0-alpha.8 → 2.0.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/README.md CHANGED
@@ -5,8 +5,10 @@ Postman plugin for [Holocron](../cli). Implements the **multi-cardinality**
5
5
 
6
6
  ## Install
7
7
 
8
+ <!-- prettier-ignore -->
8
9
  ```bash
9
10
  pnpm add -D @theholocron/holocron-plugin-postman@alpha
11
+
10
12
  ```
11
13
 
12
14
  ## Why REST, not the CLI
@@ -29,24 +31,26 @@ Generate the key at <https://web.postman.co/settings/me/api-keys>.
29
31
 
30
32
  ## Config
31
33
 
34
+ <!-- prettier-ignore -->
32
35
  ```jsonc
33
36
  {
34
- "providers": {
35
- "tooling": [
36
- [
37
- "postman",
38
- {
39
- "workspaceId": "00000000-0000-0000-0000-000000000000",
40
- "specFile": "apps/api/openapi.json",
41
- "specName": "Rando API",
42
- "collectionName": "Rando API",
43
- "envFiles": ["apps/api/postman-env-staging.json"],
44
- },
45
- ],
46
- "storybook",
47
- ],
48
- },
37
+ "providers": {
38
+ "tooling": [
39
+ [
40
+ "postman",
41
+ {
42
+ "workspaceId": "00000000-0000-0000-0000-000000000000",
43
+ "specFile": "apps/api/openapi.json",
44
+ "specName": "Rando API",
45
+ "collectionName": "Rando API",
46
+ "envFiles": ["apps/api/postman-env-staging.json"],
47
+ },
48
+ ],
49
+ "storybook",
50
+ ],
51
+ },
49
52
  }
53
+
50
54
  ```
51
55
 
52
56
  - `workspaceId` (required) — Postman workspace id. Find via `holocron tooling postman workspaces`.
package/dist/index.d.mts CHANGED
@@ -1,56 +1,8 @@
1
- import { Tooling, ToolingDoctorReport } from "@theholocron/cli";
1
+ import { AuthError, ResolveTokenInput, Tooling, ToolingDoctorReport } from "@theholocron/cli";
2
+ import { PostmanClient, PostmanClient as PostmanClient$1, PostmanCollection, PostmanEnvironment, PostmanPlanLimitError, PostmanSpec, PostmanUser, PostmanWorkspace, createPostmanClient, detectPlanLimit } from "@theholocron/postman-client";
2
3
 
3
4
  //#region src/auth.d.ts
4
- /**
5
- * Token resolution for the Postman plugin.
6
- *
7
- * Resolution order (matches the standard 4-step precedence set by
8
- * `.notes/tech-auth-bootstrap.spec.md`):
9
- * 1. explicit `cliToken` argument (from `--token` flag)
10
- * 2. HOLOCRON_POSTMAN_API_KEY env var (preferred — explicit intent)
11
- * 3. POSTMAN_API_KEY env var (Postman's own default)
12
- * 4. keyring (com.theholocron.cli / "postman")
13
- * 5. AuthError naming all four options + the bootstrap hint
14
- */
15
- declare class AuthError extends Error {
16
- name: string;
17
- }
18
- interface ResolveTokenInput {
19
- /** From `--token` CLI flag. */
20
- cliToken?: string;
21
- /** Env vars; passed in for testability. Defaults to `process.env`. */
22
- env?: NodeJS.ProcessEnv;
23
- /** Keyring lookup fn; passed in for testability. Defaults to `getToken(provider)`. */
24
- keyring?: (provider: string) => string | null;
25
- }
26
- declare function resolveToken(input?: ResolveTokenInput): string;
27
- //#endregion
28
- //#region src/rest.d.ts
29
- /**
30
- * Thin REST wrapper around api.getpostman.com.
31
- *
32
- * Same pattern as the github / vercel / neon / clerk REST clients —
33
- * the Postman API uses `x-api-key` (not bearer) for auth, but
34
- * otherwise the shape's identical: JSON only, transport-failure
35
- * wrapping with `status: 0`.
36
- */
37
- interface RestClientOptions {
38
- token: string;
39
- fetch?: typeof fetch;
40
- baseUrl?: string;
41
- }
42
- interface RequestOptions {
43
- method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
44
- body?: unknown;
45
- query?: Record<string, string>;
46
- }
47
- declare class PostmanRestClient {
48
- private readonly token;
49
- private readonly fetchImpl;
50
- readonly baseUrl: string;
51
- constructor(opts: RestClientOptions);
52
- request<T>(path: string, opts?: RequestOptions): Promise<T>;
53
- }
5
+ declare const resolveToken: (input?: import("@theholocron/http-client").ResolveTokenInput) => string;
54
6
  //#endregion
55
7
  //#region src/capabilities/tooling.d.ts
56
8
  interface PostmanToolingOptions {
@@ -66,38 +18,13 @@ interface PostmanToolingOptions {
66
18
  /** Working repo root. Defaults to process.cwd(). */
67
19
  repoRoot?: string;
68
20
  }
69
- interface PostmanUser {
70
- id: number;
71
- username: string;
72
- fullName: string;
73
- }
74
- interface PostmanWorkspace {
75
- id: string;
76
- name: string;
77
- type: string;
78
- }
79
- interface PostmanCollection {
80
- id: string;
81
- uid: string;
82
- name: string;
83
- }
84
- interface PostmanEnvironment {
85
- id: string;
86
- uid: string;
87
- name: string;
88
- }
89
- interface PostmanSpec {
90
- id: string;
91
- name: string;
92
- type: string;
93
- }
94
21
  declare class PostmanTooling implements Tooling {
95
- private readonly rest;
22
+ private readonly client;
96
23
  readonly key: "tooling";
97
24
  readonly providerName = "postman";
98
25
  private readonly opts;
99
26
  private readonly repoRoot;
100
- constructor(rest: PostmanRestClient, opts: PostmanToolingOptions);
27
+ constructor(client: PostmanClient$1, opts: PostmanToolingOptions);
101
28
  sync(): Promise<void>;
102
29
  doctor(): Promise<ToolingDoctorReport>;
103
30
  getMyself(): Promise<PostmanUser>;
@@ -144,34 +71,6 @@ declare class PostmanTooling implements Tooling {
144
71
  }): Promise<void>;
145
72
  }
146
73
  //#endregion
147
- //#region src/errors.d.ts
148
- /**
149
- * Postman-specific errors that callers might want to discriminate.
150
- */
151
- /**
152
- * Thrown when Postman returns a `limitReachedError` (e.g., a Free-tier
153
- * account hitting the "0 APIs" cap). Callers can render "upgrade
154
- * required" instead of dumping the raw API body.
155
- */
156
- declare class PostmanPlanLimitError extends Error {
157
- /** Human-readable plan-limit message from Postman. */
158
- readonly limitMessage: string;
159
- /** Original response body (JSON or text). */
160
- readonly body: string;
161
- name: string;
162
- constructor(/** Human-readable plan-limit message from Postman. */
163
-
164
- limitMessage: string, /** Original response body (JSON or text). */
165
-
166
- body: string);
167
- }
168
- /**
169
- * Inspect a Postman error body for the plan-limit shape. Returns the
170
- * limit message when matched; null otherwise (caller throws a generic
171
- * `ProviderApiError`).
172
- */
173
- declare function detectPlanLimit(body: string): string | null;
174
- //#endregion
175
74
  //#region src/verify-token.d.ts
176
75
  /**
177
76
  * `verifyToken` — plugin-level export used by `holocron auth set` +
@@ -204,7 +103,7 @@ interface PostmanPluginOptions extends ResolveTokenInput, PostmanToolingOptions
204
103
  }
205
104
  interface PluginContext {
206
105
  options: PostmanPluginOptions;
207
- rest: PostmanRestClient;
106
+ client: PostmanClient;
208
107
  }
209
108
  declare function createContext(options: PostmanPluginOptions): PluginContext;
210
109
  declare function tooling(ctx: PluginContext): Tooling;
@@ -220,4 +119,4 @@ declare function createPlugin(options: PostmanPluginOptions): {
220
119
  */
221
120
  declare const AUTH_HINT: string;
222
121
  //#endregion
223
- export { AUTH_HINT, AuthError, PluginContext, PostmanPlanLimitError, PostmanPluginOptions, PostmanRestClient, PostmanTooling, ResolveTokenInput, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, createContext, createPlugin, detectPlanLimit, resolveToken, tooling, verifyToken };
122
+ export { AUTH_HINT, AuthError, PluginContext, type PostmanClient, PostmanPlanLimitError, PostmanPluginOptions, PostmanTooling, type ResolveTokenInput, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, createContext, createPlugin, createPostmanClient, detectPlanLimit, resolveToken, tooling, verifyToken };
package/dist/index.mjs CHANGED
@@ -1,28 +1,14 @@
1
- import { ProviderApiError, getToken } from "@theholocron/cli";
1
+ import { AuthError, ProviderApiError, createResolveToken } from "@theholocron/cli";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import { basename, resolve } from "node:path";
4
+ import { PostmanPlanLimitError, createPostmanClient, detectPlanLimit } from "@theholocron/postman-client";
4
5
  //#region src/auth.ts
5
- /**
6
- * Token resolution for the Postman plugin.
7
- *
8
- * Resolution order (matches the standard 4-step precedence set by
9
- * `.notes/tech-auth-bootstrap.spec.md`):
10
- * 1. explicit `cliToken` argument (from `--token` flag)
11
- * 2. HOLOCRON_POSTMAN_API_KEY env var (preferred — explicit intent)
12
- * 3. POSTMAN_API_KEY env var (Postman's own default)
13
- * 4. keyring (com.theholocron.cli / "postman")
14
- * 5. AuthError naming all four options + the bootstrap hint
15
- */
16
- var AuthError = class extends Error {
17
- name = "AuthError";
18
- };
19
- function resolveToken(input = {}) {
20
- const env = input.env ?? process.env;
21
- const keyring = input.keyring ?? getToken;
22
- const token = input.cliToken || env["HOLOCRON_POSTMAN_API_KEY"] || env["POSTMAN_API_KEY"] || keyring("postman");
23
- if (!token) throw new AuthError("no Postman API key found. Pass --token <KEY>, set HOLOCRON_POSTMAN_API_KEY / POSTMAN_API_KEY, or run: holocron auth set postman <KEY>");
24
- return token;
25
- }
6
+ const resolveToken = createResolveToken({
7
+ envName: "HOLOCRON_POSTMAN_API_KEY",
8
+ vendorEnvName: "POSTMAN_API_KEY",
9
+ keyringService: "postman",
10
+ errorMessage: "no Postman API key found. Pass --token <KEY>, set HOLOCRON_POSTMAN_API_KEY / POSTMAN_API_KEY, or run: holocron auth set postman <KEY>"
11
+ });
26
12
  //#endregion
27
13
  //#region src/capabilities/tooling.ts
28
14
  /**
@@ -48,13 +34,13 @@ function resolveToken(input = {}) {
48
34
  * reachability and returns a `ToolingDoctorReport`.
49
35
  */
50
36
  var PostmanTooling = class {
51
- rest;
37
+ client;
52
38
  key = "tooling";
53
39
  providerName = "postman";
54
40
  opts;
55
41
  repoRoot;
56
- constructor(rest, opts) {
57
- this.rest = rest;
42
+ constructor(client, opts) {
43
+ this.client = client;
58
44
  if (!opts.workspaceId) throw new Error("PostmanTooling requires `workspaceId` in options");
59
45
  this.opts = opts;
60
46
  this.repoRoot = opts.repoRoot ?? process.cwd();
@@ -128,200 +114,54 @@ var PostmanTooling = class {
128
114
  }
129
115
  }
130
116
  async getMyself() {
131
- const raw = await this.rest.request("/me");
132
- return {
133
- id: raw.user.id,
134
- username: raw.user.username,
135
- fullName: raw.user.fullName
136
- };
117
+ return (await this.client.me.get()).user ?? {};
137
118
  }
138
119
  async listWorkspaces() {
139
- return (await this.rest.request("/workspaces")).workspaces.map((w) => ({
140
- id: w.id,
141
- name: w.name,
142
- type: w.type
143
- }));
120
+ const { workspaces } = await this.client.workspaces.list();
121
+ return workspaces;
144
122
  }
145
123
  async findCollectionByName(input) {
146
- const match = (await this.rest.request("/collections", { query: { workspace: input.workspaceId } })).collections.find((c) => c.name === input.name);
147
- return match ? {
148
- id: match.id,
149
- uid: match.uid,
150
- name: match.name
151
- } : null;
124
+ const { collections } = await this.client.collections.list(input.workspaceId);
125
+ return collections.find((c) => c.name === input.name) ?? null;
152
126
  }
153
127
  async deleteCollection(uid) {
154
- await this.rest.request(`/collections/${encodeURIComponent(uid)}`, { method: "DELETE" });
128
+ await this.client.collections.delete(uid);
155
129
  }
156
130
  async importOpenApi(input) {
157
- const created = (await this.rest.request("/import/openapi", {
158
- method: "POST",
159
- query: { workspace: input.workspaceId },
160
- body: {
161
- type: "string",
162
- input: typeof input.spec === "string" ? input.spec : JSON.stringify(input.spec)
163
- }
164
- })).collections[0];
131
+ const { collections } = await this.client.import.openapi(input.workspaceId, input.spec);
132
+ const created = collections[0];
165
133
  if (!created) throw new ProviderApiError("Postman returned no collection on import — check the OpenAPI spec is well-formed", 500, void 0);
166
- return {
167
- id: created.id,
168
- uid: created.uid,
169
- name: created.name
170
- };
134
+ return created;
171
135
  }
172
136
  async listEnvironments(input) {
173
- return (await this.rest.request("/environments", { query: { workspace: input.workspaceId } })).environments.map((e) => ({
174
- id: e.id,
175
- uid: e.uid,
176
- name: e.name
177
- }));
137
+ const { environments } = await this.client.environments.list(input.workspaceId);
138
+ return environments;
178
139
  }
179
140
  async findEnvironmentByName(input) {
180
141
  return (await this.listEnvironments(input)).find((e) => e.name === input.name) ?? null;
181
142
  }
182
143
  async createEnvironment(input) {
183
- const raw = await this.rest.request("/environments", {
184
- method: "POST",
185
- query: { workspace: input.workspaceId },
186
- body: { environment: input.environment }
187
- });
188
- return {
189
- id: raw.environment.id,
190
- uid: raw.environment.uid,
191
- name: raw.environment.name
192
- };
144
+ const { environment } = await this.client.environments.create(input.workspaceId, input.environment);
145
+ return environment;
193
146
  }
194
147
  async updateEnvironment(input) {
195
- const raw = await this.rest.request(`/environments/${encodeURIComponent(input.uid)}`, {
196
- method: "PUT",
197
- body: { environment: input.environment }
198
- });
199
- return {
200
- id: raw.environment.id,
201
- uid: raw.environment.uid,
202
- name: raw.environment.name
203
- };
148
+ const { environment } = await this.client.environments.update(input.uid, input.environment);
149
+ return environment;
204
150
  }
205
151
  async findSpecByName(input) {
206
- const match = (await this.rest.request("/specs", { query: { workspaceId: input.workspaceId } })).specs.find((s) => s.name === input.name);
207
- return match ? {
208
- id: match.id,
209
- name: match.name,
210
- type: match.type
211
- } : null;
152
+ const { specs } = await this.client.specs.list(input.workspaceId);
153
+ return specs.find((s) => s.name === input.name) ?? null;
212
154
  }
213
155
  async createSpec(input) {
214
- const raw = await this.rest.request("/specs", {
215
- method: "POST",
216
- query: { workspaceId: input.workspaceId },
217
- body: {
218
- name: input.name,
219
- type: input.type ?? "OPENAPI:3.0",
220
- files: [{
221
- path: input.filePath ?? "index.json",
222
- content: input.fileContent
223
- }]
224
- }
156
+ return this.client.specs.create(input.workspaceId, {
157
+ name: input.name,
158
+ type: input.type,
159
+ filePath: input.filePath,
160
+ fileContent: input.fileContent
225
161
  });
226
- return {
227
- id: raw.id,
228
- name: raw.name,
229
- type: raw.type
230
- };
231
162
  }
232
163
  async upsertSpecFile(input) {
233
- await this.rest.request(`/specs/${encodeURIComponent(input.specId)}/files/${encodeURIComponent(input.filePath)}`, {
234
- method: "PATCH",
235
- body: { content: input.content }
236
- });
237
- }
238
- };
239
- //#endregion
240
- //#region src/errors.ts
241
- /**
242
- * Postman-specific errors that callers might want to discriminate.
243
- */
244
- /**
245
- * Thrown when Postman returns a `limitReachedError` (e.g., a Free-tier
246
- * account hitting the "0 APIs" cap). Callers can render "upgrade
247
- * required" instead of dumping the raw API body.
248
- */
249
- var PostmanPlanLimitError = class extends Error {
250
- limitMessage;
251
- body;
252
- name = "PostmanPlanLimitError";
253
- constructor(limitMessage, body) {
254
- super(limitMessage);
255
- this.limitMessage = limitMessage;
256
- this.body = body;
257
- }
258
- };
259
- /**
260
- * Inspect a Postman error body for the plan-limit shape. Returns the
261
- * limit message when matched; null otherwise (caller throws a generic
262
- * `ProviderApiError`).
263
- */
264
- function detectPlanLimit(body) {
265
- try {
266
- const parsed = JSON.parse(body);
267
- if (parsed.error?.name === "limitReachedError" && parsed.error.message) return parsed.error.message;
268
- } catch {}
269
- return null;
270
- }
271
- //#endregion
272
- //#region src/rest.ts
273
- /**
274
- * Thin REST wrapper around api.getpostman.com.
275
- *
276
- * Same pattern as the github / vercel / neon / clerk REST clients —
277
- * the Postman API uses `x-api-key` (not bearer) for auth, but
278
- * otherwise the shape's identical: JSON only, transport-failure
279
- * wrapping with `status: 0`.
280
- */
281
- var PostmanRestClient = class {
282
- token;
283
- fetchImpl;
284
- baseUrl;
285
- constructor(opts) {
286
- this.token = opts.token;
287
- this.fetchImpl = opts.fetch ?? globalThis.fetch;
288
- let url = opts.baseUrl ?? "https://api.getpostman.com";
289
- while (url.endsWith("/")) url = url.slice(0, -1);
290
- this.baseUrl = url;
291
- }
292
- async request(path, opts = {}) {
293
- const url = new URL(`${this.baseUrl}${path.startsWith("/") ? path : "/" + path}`);
294
- for (const [k, v] of Object.entries(opts.query ?? {})) url.searchParams.set(k, v);
295
- const fullUrl = url.toString();
296
- const headers = {
297
- "x-api-key": this.token,
298
- accept: "application/json"
299
- };
300
- const init = {
301
- method: opts.method ?? "GET",
302
- headers
303
- };
304
- if (opts.body !== void 0) {
305
- headers["content-type"] = "application/json";
306
- init.body = JSON.stringify(opts.body);
307
- }
308
- let res;
309
- try {
310
- res = await this.fetchImpl(fullUrl, init);
311
- } catch (err) {
312
- const detail = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
313
- throw new ProviderApiError(`Postman ${init.method} ${path} failed: ${detail}`, 0, void 0);
314
- }
315
- if (!res.ok) {
316
- const body = await res.text().catch(() => "");
317
- const limit = detectPlanLimit(body);
318
- if (limit) throw new PostmanPlanLimitError(limit, body);
319
- throw new ProviderApiError(`Postman ${init.method} ${path} → ${res.status}`, res.status, body);
320
- }
321
- if (res.status === 204) return void 0;
322
- const text = await res.text();
323
- if (!text) return void 0;
324
- return JSON.parse(text);
164
+ await this.client.specs.updateFile(input.specId, input.filePath, input.content);
325
165
  }
326
166
  };
327
167
  //#endregion
@@ -332,12 +172,13 @@ var PostmanRestClient = class {
332
172
  * authenticated user).
333
173
  */
334
174
  async function verifyToken(token, opts = {}) {
335
- const restOpts = { token };
336
- if (opts.baseUrl !== void 0) restOpts.baseUrl = opts.baseUrl;
337
- if (opts.fetch !== void 0) restOpts.fetch = opts.fetch;
338
- const rest = new PostmanRestClient(restOpts);
175
+ const client = createPostmanClient({
176
+ token,
177
+ baseUrl: opts.baseUrl,
178
+ fetch: opts.fetch
179
+ });
339
180
  try {
340
- const res = await rest.request("/me");
181
+ const res = await client.me.get();
341
182
  return {
342
183
  ok: true,
343
184
  subject: `user @ ${res?.user?.email ?? res?.user?.username ?? res?.user?.fullName ?? String(res?.user?.id ?? "unknown")}`
@@ -353,12 +194,13 @@ async function verifyToken(token, opts = {}) {
353
194
  //#region src/index.ts
354
195
  function createContext(options) {
355
196
  if (!options.workspaceId) throw new Error("@theholocron/holocron-plugin-postman requires `workspaceId` in options");
356
- const restOpts = { token: resolveToken(options) };
357
- if (options.baseUrl !== void 0) restOpts.baseUrl = options.baseUrl;
358
- if (options.fetch !== void 0) restOpts.fetch = options.fetch;
359
197
  return {
360
198
  options,
361
- rest: new PostmanRestClient(restOpts)
199
+ client: createPostmanClient({
200
+ token: resolveToken(options),
201
+ baseUrl: options.baseUrl,
202
+ fetch: options.fetch
203
+ })
362
204
  };
363
205
  }
364
206
  function tooling(ctx) {
@@ -368,7 +210,7 @@ function tooling(ctx) {
368
210
  if (ctx.options.collectionName !== void 0) opts.collectionName = ctx.options.collectionName;
369
211
  if (ctx.options.envFiles !== void 0) opts.envFiles = ctx.options.envFiles;
370
212
  if (ctx.options.repoRoot !== void 0) opts.repoRoot = ctx.options.repoRoot;
371
- return new PostmanTooling(ctx.rest, opts);
213
+ return new PostmanTooling(ctx.client, opts);
372
214
  }
373
215
  function createPlugin(options) {
374
216
  const ctx = createContext(options);
@@ -383,4 +225,4 @@ function createPlugin(options) {
383
225
  */
384
226
  const AUTH_HINT = "generate a Postman API key at https://postman.co/settings/me/api-keys, then run: holocron auth set postman <KEY>";
385
227
  //#endregion
386
- export { AUTH_HINT, AuthError, PostmanPlanLimitError, PostmanRestClient, PostmanTooling, createContext, createPlugin, detectPlanLimit, resolveToken, tooling, verifyToken };
228
+ export { AUTH_HINT, AuthError, PostmanPlanLimitError, PostmanTooling, createContext, createPlugin, createPostmanClient, detectPlanLimit, resolveToken, tooling, verifyToken };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theholocron/holocron-plugin-postman",
3
- "version": "2.0.0-alpha.8",
3
+ "version": "2.0.0",
4
4
  "description": "Holocron plugin for Postman. Implements the tooling capability against Postman's REST API — workspace + collection + spec + environment sync.",
5
5
  "homepage": "https://github.com/theholocron/holocron/tree/main/packages/holocron-plugin-postman#readme",
6
6
  "bugs": "https://github.com/theholocron/holocron/issues",
@@ -21,19 +21,31 @@
21
21
  }
22
22
  },
23
23
  "peerDependencies": {
24
- "@theholocron/cli": "2.0.0-alpha.8"
24
+ "@theholocron/postman-client": "^1.1.0",
25
+ "@theholocron/cli": "2.0.0"
26
+ },
27
+ "peerDependenciesMeta": {
28
+ "@theholocron/postman-client": {
29
+ "optional": false
30
+ }
25
31
  },
26
32
  "devDependencies": {
27
- "@theholocron/tsconfig": "^4.1.0",
28
- "@tsconfig/node-lts": "^24.0.0",
29
- "@vitest/coverage-v8": "^3.2.6",
30
- "eslint": "^9.36.0",
31
- "globals": "^16.5.0",
32
- "typescript": "^5.9.3",
33
- "vitest": "^3.2.6",
33
+ "@theholocron/eslint-config": "^7.3.0",
34
+ "@theholocron/postman-client": "^1.1.0",
35
+ "@theholocron/tsconfig": "^7.3.0",
36
+ "@theholocron/tsdown-config": "^7.3.0",
37
+ "@theholocron/vitest-config": "^7.3.0",
38
+ "@types/node": "^26",
39
+ "@vitest/coverage-v8": "^4.1.10",
40
+ "@vitest/eslint-plugin": "^1.6.23",
41
+ "eslint": "^10.7.0",
42
+ "eslint-plugin-n": "^18.2.2",
43
+ "globals": "^17.7.0",
34
44
  "tsdown": "^0.22.3",
35
45
  "tsx": "^4.22.4",
36
- "@theholocron/cli": "2.0.0-alpha.8"
46
+ "typescript": "^5.9.3",
47
+ "vitest": "^4.1.10",
48
+ "@theholocron/cli": "2.0.0"
37
49
  },
38
50
  "publishConfig": {
39
51
  "access": "public"