@theholocron/holocron-plugin-postman 2.0.0-alpha.51 → 2.0.0-alpha.53
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/index.d.mts +6 -65
- package/dist/index.mjs +33 -151
- package/package.json +10 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { AuthError, ResolveTokenInput,
|
|
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
|
declare const resolveToken: (input?: import("@theholocron/http-client").ResolveTokenInput) => string;
|
|
@@ -17,38 +18,13 @@ interface PostmanToolingOptions {
|
|
|
17
18
|
/** Working repo root. Defaults to process.cwd(). */
|
|
18
19
|
repoRoot?: string;
|
|
19
20
|
}
|
|
20
|
-
interface PostmanUser {
|
|
21
|
-
id: number;
|
|
22
|
-
username: string;
|
|
23
|
-
fullName: string;
|
|
24
|
-
}
|
|
25
|
-
interface PostmanWorkspace {
|
|
26
|
-
id: string;
|
|
27
|
-
name: string;
|
|
28
|
-
type: string;
|
|
29
|
-
}
|
|
30
|
-
interface PostmanCollection {
|
|
31
|
-
id: string;
|
|
32
|
-
uid: string;
|
|
33
|
-
name: string;
|
|
34
|
-
}
|
|
35
|
-
interface PostmanEnvironment {
|
|
36
|
-
id: string;
|
|
37
|
-
uid: string;
|
|
38
|
-
name: string;
|
|
39
|
-
}
|
|
40
|
-
interface PostmanSpec {
|
|
41
|
-
id: string;
|
|
42
|
-
name: string;
|
|
43
|
-
type: string;
|
|
44
|
-
}
|
|
45
21
|
declare class PostmanTooling implements Tooling {
|
|
46
|
-
private readonly
|
|
22
|
+
private readonly client;
|
|
47
23
|
readonly key: "tooling";
|
|
48
24
|
readonly providerName = "postman";
|
|
49
25
|
private readonly opts;
|
|
50
26
|
private readonly repoRoot;
|
|
51
|
-
constructor(
|
|
27
|
+
constructor(client: PostmanClient$1, opts: PostmanToolingOptions);
|
|
52
28
|
sync(): Promise<void>;
|
|
53
29
|
doctor(): Promise<ToolingDoctorReport>;
|
|
54
30
|
getMyself(): Promise<PostmanUser>;
|
|
@@ -95,41 +71,6 @@ declare class PostmanTooling implements Tooling {
|
|
|
95
71
|
}): Promise<void>;
|
|
96
72
|
}
|
|
97
73
|
//#endregion
|
|
98
|
-
//#region src/errors.d.ts
|
|
99
|
-
/**
|
|
100
|
-
* Postman-specific errors that callers might want to discriminate.
|
|
101
|
-
*/
|
|
102
|
-
/**
|
|
103
|
-
* Thrown when Postman returns a `limitReachedError` (e.g., a Free-tier
|
|
104
|
-
* account hitting the "0 APIs" cap). Callers can render "upgrade
|
|
105
|
-
* required" instead of dumping the raw API body.
|
|
106
|
-
*/
|
|
107
|
-
declare class PostmanPlanLimitError extends Error {
|
|
108
|
-
/** Human-readable plan-limit message from Postman. */
|
|
109
|
-
readonly limitMessage: string;
|
|
110
|
-
/** Original response body (JSON or text). */
|
|
111
|
-
readonly body: string;
|
|
112
|
-
name: string;
|
|
113
|
-
constructor(/** Human-readable plan-limit message from Postman. */
|
|
114
|
-
|
|
115
|
-
limitMessage: string, /** Original response body (JSON or text). */
|
|
116
|
-
|
|
117
|
-
body: string);
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Inspect a Postman error body for the plan-limit shape. Returns the
|
|
121
|
-
* limit message when matched; null otherwise (caller throws a generic
|
|
122
|
-
* `ProviderApiError`).
|
|
123
|
-
*/
|
|
124
|
-
declare function detectPlanLimit(body: string): string | null;
|
|
125
|
-
//#endregion
|
|
126
|
-
//#region src/rest.d.ts
|
|
127
|
-
declare function createPostmanRestClient(opts: {
|
|
128
|
-
token: string;
|
|
129
|
-
baseUrl?: string;
|
|
130
|
-
fetch?: typeof fetch;
|
|
131
|
-
}): RestClient$1;
|
|
132
|
-
//#endregion
|
|
133
74
|
//#region src/verify-token.d.ts
|
|
134
75
|
/**
|
|
135
76
|
* `verifyToken` — plugin-level export used by `holocron auth set` +
|
|
@@ -162,7 +103,7 @@ interface PostmanPluginOptions extends ResolveTokenInput, PostmanToolingOptions
|
|
|
162
103
|
}
|
|
163
104
|
interface PluginContext {
|
|
164
105
|
options: PostmanPluginOptions;
|
|
165
|
-
|
|
106
|
+
client: PostmanClient;
|
|
166
107
|
}
|
|
167
108
|
declare function createContext(options: PostmanPluginOptions): PluginContext;
|
|
168
109
|
declare function tooling(ctx: PluginContext): Tooling;
|
|
@@ -178,4 +119,4 @@ declare function createPlugin(options: PostmanPluginOptions): {
|
|
|
178
119
|
*/
|
|
179
120
|
declare const AUTH_HINT: string;
|
|
180
121
|
//#endregion
|
|
181
|
-
export { AUTH_HINT, AuthError, PluginContext, PostmanPlanLimitError, PostmanPluginOptions, PostmanTooling, type ResolveTokenInput, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, createContext, createPlugin,
|
|
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,6 +1,7 @@
|
|
|
1
|
-
import { AuthError, ProviderApiError, createResolveToken
|
|
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
|
const resolveToken = createResolveToken({
|
|
6
7
|
envName: "HOLOCRON_POSTMAN_API_KEY",
|
|
@@ -33,13 +34,13 @@ const resolveToken = createResolveToken({
|
|
|
33
34
|
* reachability and returns a `ToolingDoctorReport`.
|
|
34
35
|
*/
|
|
35
36
|
var PostmanTooling = class {
|
|
36
|
-
|
|
37
|
+
client;
|
|
37
38
|
key = "tooling";
|
|
38
39
|
providerName = "postman";
|
|
39
40
|
opts;
|
|
40
41
|
repoRoot;
|
|
41
|
-
constructor(
|
|
42
|
-
this.
|
|
42
|
+
constructor(client, opts) {
|
|
43
|
+
this.client = client;
|
|
43
44
|
if (!opts.workspaceId) throw new Error("PostmanTooling requires `workspaceId` in options");
|
|
44
45
|
this.opts = opts;
|
|
45
46
|
this.repoRoot = opts.repoRoot ?? process.cwd();
|
|
@@ -113,176 +114,57 @@ var PostmanTooling = class {
|
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
async getMyself() {
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
id: raw.user.id,
|
|
119
|
-
username: raw.user.username,
|
|
120
|
-
fullName: raw.user.fullName
|
|
121
|
-
};
|
|
117
|
+
return (await this.client.me.get()).user ?? {};
|
|
122
118
|
}
|
|
123
119
|
async listWorkspaces() {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
name: w.name,
|
|
127
|
-
type: w.type
|
|
128
|
-
}));
|
|
120
|
+
const { workspaces } = await this.client.workspaces.list();
|
|
121
|
+
return workspaces;
|
|
129
122
|
}
|
|
130
123
|
async findCollectionByName(input) {
|
|
131
|
-
const
|
|
132
|
-
return
|
|
133
|
-
id: match.id,
|
|
134
|
-
uid: match.uid,
|
|
135
|
-
name: match.name
|
|
136
|
-
} : null;
|
|
124
|
+
const { collections } = await this.client.collections.list(input.workspaceId);
|
|
125
|
+
return collections.find((c) => c.name === input.name) ?? null;
|
|
137
126
|
}
|
|
138
127
|
async deleteCollection(uid) {
|
|
139
|
-
await this.
|
|
128
|
+
await this.client.collections.delete(uid);
|
|
140
129
|
}
|
|
141
130
|
async importOpenApi(input) {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
query: { workspace: input.workspaceId },
|
|
145
|
-
body: {
|
|
146
|
-
type: "string",
|
|
147
|
-
input: typeof input.spec === "string" ? input.spec : JSON.stringify(input.spec)
|
|
148
|
-
}
|
|
149
|
-
})).collections[0];
|
|
131
|
+
const { collections } = await this.client.import.openapi(input.workspaceId, input.spec);
|
|
132
|
+
const created = collections[0];
|
|
150
133
|
if (!created) throw new ProviderApiError("Postman returned no collection on import — check the OpenAPI spec is well-formed", 500, void 0);
|
|
151
|
-
return
|
|
152
|
-
id: created.id,
|
|
153
|
-
uid: created.uid,
|
|
154
|
-
name: created.name
|
|
155
|
-
};
|
|
134
|
+
return created;
|
|
156
135
|
}
|
|
157
136
|
async listEnvironments(input) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
uid: e.uid,
|
|
161
|
-
name: e.name
|
|
162
|
-
}));
|
|
137
|
+
const { environments } = await this.client.environments.list(input.workspaceId);
|
|
138
|
+
return environments;
|
|
163
139
|
}
|
|
164
140
|
async findEnvironmentByName(input) {
|
|
165
141
|
return (await this.listEnvironments(input)).find((e) => e.name === input.name) ?? null;
|
|
166
142
|
}
|
|
167
143
|
async createEnvironment(input) {
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
query: { workspace: input.workspaceId },
|
|
171
|
-
body: { environment: input.environment }
|
|
172
|
-
});
|
|
173
|
-
return {
|
|
174
|
-
id: raw.environment.id,
|
|
175
|
-
uid: raw.environment.uid,
|
|
176
|
-
name: raw.environment.name
|
|
177
|
-
};
|
|
144
|
+
const { environment } = await this.client.environments.create(input.workspaceId, input.environment);
|
|
145
|
+
return environment;
|
|
178
146
|
}
|
|
179
147
|
async updateEnvironment(input) {
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
body: { environment: input.environment }
|
|
183
|
-
});
|
|
184
|
-
return {
|
|
185
|
-
id: raw.environment.id,
|
|
186
|
-
uid: raw.environment.uid,
|
|
187
|
-
name: raw.environment.name
|
|
188
|
-
};
|
|
148
|
+
const { environment } = await this.client.environments.update(input.uid, input.environment);
|
|
149
|
+
return environment;
|
|
189
150
|
}
|
|
190
151
|
async findSpecByName(input) {
|
|
191
|
-
const
|
|
192
|
-
return
|
|
193
|
-
id: match.id,
|
|
194
|
-
name: match.name,
|
|
195
|
-
type: match.type
|
|
196
|
-
} : null;
|
|
152
|
+
const { specs } = await this.client.specs.list(input.workspaceId);
|
|
153
|
+
return specs.find((s) => s.name === input.name) ?? null;
|
|
197
154
|
}
|
|
198
155
|
async createSpec(input) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
type: input.type ?? "OPENAPI:3.0",
|
|
205
|
-
files: [{
|
|
206
|
-
path: input.filePath ?? "index.json",
|
|
207
|
-
content: input.fileContent
|
|
208
|
-
}]
|
|
209
|
-
}
|
|
156
|
+
return this.client.specs.create(input.workspaceId, {
|
|
157
|
+
name: input.name,
|
|
158
|
+
type: input.type,
|
|
159
|
+
filePath: input.filePath,
|
|
160
|
+
fileContent: input.fileContent
|
|
210
161
|
});
|
|
211
|
-
return {
|
|
212
|
-
id: raw.id,
|
|
213
|
-
name: raw.name,
|
|
214
|
-
type: raw.type
|
|
215
|
-
};
|
|
216
162
|
}
|
|
217
163
|
async upsertSpecFile(input) {
|
|
218
|
-
await this.
|
|
219
|
-
method: "PATCH",
|
|
220
|
-
body: { content: input.content }
|
|
221
|
-
});
|
|
164
|
+
await this.client.specs.updateFile(input.specId, input.filePath, input.content);
|
|
222
165
|
}
|
|
223
166
|
};
|
|
224
167
|
//#endregion
|
|
225
|
-
//#region src/errors.ts
|
|
226
|
-
/**
|
|
227
|
-
* Postman-specific errors that callers might want to discriminate.
|
|
228
|
-
*/
|
|
229
|
-
/**
|
|
230
|
-
* Thrown when Postman returns a `limitReachedError` (e.g., a Free-tier
|
|
231
|
-
* account hitting the "0 APIs" cap). Callers can render "upgrade
|
|
232
|
-
* required" instead of dumping the raw API body.
|
|
233
|
-
*/
|
|
234
|
-
var PostmanPlanLimitError = class extends Error {
|
|
235
|
-
limitMessage;
|
|
236
|
-
body;
|
|
237
|
-
name = "PostmanPlanLimitError";
|
|
238
|
-
constructor(limitMessage, body) {
|
|
239
|
-
super(limitMessage);
|
|
240
|
-
this.limitMessage = limitMessage;
|
|
241
|
-
this.body = body;
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
/**
|
|
245
|
-
* Inspect a Postman error body for the plan-limit shape. Returns the
|
|
246
|
-
* limit message when matched; null otherwise (caller throws a generic
|
|
247
|
-
* `ProviderApiError`).
|
|
248
|
-
*/
|
|
249
|
-
function detectPlanLimit(body) {
|
|
250
|
-
try {
|
|
251
|
-
const parsed = JSON.parse(body);
|
|
252
|
-
if (parsed.error?.name === "limitReachedError" && parsed.error.message) return parsed.error.message;
|
|
253
|
-
} catch {}
|
|
254
|
-
return null;
|
|
255
|
-
}
|
|
256
|
-
//#endregion
|
|
257
|
-
//#region src/rest.ts
|
|
258
|
-
function createPostmanRestClient(opts) {
|
|
259
|
-
const base = createRestClient({
|
|
260
|
-
baseUrl: opts.baseUrl ?? "https://api.getpostman.com",
|
|
261
|
-
token: opts.token,
|
|
262
|
-
tokenScheme: "apikey",
|
|
263
|
-
apiKeyHeader: "x-api-key",
|
|
264
|
-
vendor: "Postman",
|
|
265
|
-
fetch: opts.fetch
|
|
266
|
-
});
|
|
267
|
-
return {
|
|
268
|
-
baseUrl: base.baseUrl,
|
|
269
|
-
async request(path, reqOpts) {
|
|
270
|
-
let res;
|
|
271
|
-
try {
|
|
272
|
-
res = await base.request(path, reqOpts);
|
|
273
|
-
} catch (err) {
|
|
274
|
-
const details = err.details;
|
|
275
|
-
if (typeof details === "string") {
|
|
276
|
-
const limit = detectPlanLimit(details);
|
|
277
|
-
if (limit) throw new PostmanPlanLimitError(limit, details);
|
|
278
|
-
}
|
|
279
|
-
throw err;
|
|
280
|
-
}
|
|
281
|
-
return res;
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
//#endregion
|
|
286
168
|
//#region src/verify-token.ts
|
|
287
169
|
/**
|
|
288
170
|
* `verifyToken` — plugin-level export used by `holocron auth set` +
|
|
@@ -290,13 +172,13 @@ function createPostmanRestClient(opts) {
|
|
|
290
172
|
* authenticated user).
|
|
291
173
|
*/
|
|
292
174
|
async function verifyToken(token, opts = {}) {
|
|
293
|
-
const
|
|
175
|
+
const client = createPostmanClient({
|
|
294
176
|
token,
|
|
295
177
|
baseUrl: opts.baseUrl,
|
|
296
178
|
fetch: opts.fetch
|
|
297
179
|
});
|
|
298
180
|
try {
|
|
299
|
-
const res = await
|
|
181
|
+
const res = await client.me.get();
|
|
300
182
|
return {
|
|
301
183
|
ok: true,
|
|
302
184
|
subject: `user @ ${res?.user?.email ?? res?.user?.username ?? res?.user?.fullName ?? String(res?.user?.id ?? "unknown")}`
|
|
@@ -314,7 +196,7 @@ function createContext(options) {
|
|
|
314
196
|
if (!options.workspaceId) throw new Error("@theholocron/holocron-plugin-postman requires `workspaceId` in options");
|
|
315
197
|
return {
|
|
316
198
|
options,
|
|
317
|
-
|
|
199
|
+
client: createPostmanClient({
|
|
318
200
|
token: resolveToken(options),
|
|
319
201
|
baseUrl: options.baseUrl,
|
|
320
202
|
fetch: options.fetch
|
|
@@ -328,7 +210,7 @@ function tooling(ctx) {
|
|
|
328
210
|
if (ctx.options.collectionName !== void 0) opts.collectionName = ctx.options.collectionName;
|
|
329
211
|
if (ctx.options.envFiles !== void 0) opts.envFiles = ctx.options.envFiles;
|
|
330
212
|
if (ctx.options.repoRoot !== void 0) opts.repoRoot = ctx.options.repoRoot;
|
|
331
|
-
return new PostmanTooling(ctx.
|
|
213
|
+
return new PostmanTooling(ctx.client, opts);
|
|
332
214
|
}
|
|
333
215
|
function createPlugin(options) {
|
|
334
216
|
const ctx = createContext(options);
|
|
@@ -343,4 +225,4 @@ function createPlugin(options) {
|
|
|
343
225
|
*/
|
|
344
226
|
const AUTH_HINT = "generate a Postman API key at https://postman.co/settings/me/api-keys, then run: holocron auth set postman <KEY>";
|
|
345
227
|
//#endregion
|
|
346
|
-
export { AUTH_HINT, AuthError, PostmanPlanLimitError, PostmanTooling, createContext, createPlugin,
|
|
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.
|
|
3
|
+
"version": "2.0.0-alpha.53",
|
|
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,9 +21,16 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"@theholocron/
|
|
24
|
+
"@theholocron/postman-client": "^0.10.0",
|
|
25
|
+
"@theholocron/cli": "2.0.0-alpha.53"
|
|
26
|
+
},
|
|
27
|
+
"peerDependenciesMeta": {
|
|
28
|
+
"@theholocron/postman-client": {
|
|
29
|
+
"optional": false
|
|
30
|
+
}
|
|
25
31
|
},
|
|
26
32
|
"devDependencies": {
|
|
33
|
+
"@theholocron/postman-client": "^0.10.0",
|
|
27
34
|
"@types/node": "^26",
|
|
28
35
|
"@theholocron/eslint-config": "^7.0.0",
|
|
29
36
|
"@theholocron/tsconfig": "^7.0.0",
|
|
@@ -37,7 +44,7 @@
|
|
|
37
44
|
"tsx": "^4.22.4",
|
|
38
45
|
"typescript": "^5.9.3",
|
|
39
46
|
"vitest": "^4.1.10",
|
|
40
|
-
"@theholocron/cli": "2.0.0-alpha.
|
|
47
|
+
"@theholocron/cli": "2.0.0-alpha.53"
|
|
41
48
|
},
|
|
42
49
|
"publishConfig": {
|
|
43
50
|
"access": "public"
|