@facetlayer/prism-framework 0.4.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.
Files changed (42) hide show
  1. package/.claude/settings.local.json +20 -0
  2. package/CHANGELOG +28 -0
  3. package/CLAUDE.md +44 -0
  4. package/README.md +47 -0
  5. package/build.mts +8 -0
  6. package/dist/call-command.d.ts +13 -0
  7. package/dist/call-command.d.ts.map +1 -0
  8. package/dist/cli.d.ts +3 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +475 -0
  11. package/dist/config/ConfigFile.d.ts +7 -0
  12. package/dist/config/ConfigFile.d.ts.map +1 -0
  13. package/dist/config/index.d.ts +4 -0
  14. package/dist/config/index.d.ts.map +1 -0
  15. package/dist/config/loadConfig.d.ts +11 -0
  16. package/dist/config/loadConfig.d.ts.map +1 -0
  17. package/dist/generate-api-clients.d.ts +6 -0
  18. package/dist/generate-api-clients.d.ts.map +1 -0
  19. package/dist/getPorts.d.ts +10 -0
  20. package/dist/getPorts.d.ts.map +1 -0
  21. package/dist/list-endpoints-command.d.ts +5 -0
  22. package/dist/list-endpoints-command.d.ts.map +1 -0
  23. package/dist/loadEnv.d.ts +12 -0
  24. package/dist/loadEnv.d.ts.map +1 -0
  25. package/docs/endpoint-tools.md +116 -0
  26. package/docs/env-files.md +64 -0
  27. package/docs/generate-api-clients-config.md +84 -0
  28. package/docs/getting-started.md +86 -0
  29. package/package.json +43 -0
  30. package/src/call-command.ts +147 -0
  31. package/src/cli.ts +163 -0
  32. package/src/config/ConfigFile.ts +7 -0
  33. package/src/config/index.ts +3 -0
  34. package/src/config/loadConfig.ts +58 -0
  35. package/src/generate-api-clients.ts +203 -0
  36. package/src/getPorts.ts +39 -0
  37. package/src/list-endpoints-command.ts +34 -0
  38. package/src/loadEnv.ts +59 -0
  39. package/test/call-command.test.ts +96 -0
  40. package/test/generate-api-clients.test.ts +33 -0
  41. package/test/generate-api-clients.test.ts.disabled +75 -0
  42. package/tsconfig.json +21 -0
@@ -0,0 +1,20 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(git mv:*)",
5
+ "Bash(prism-endpoint:*)",
6
+ "Bash(pnpm build:*)",
7
+ "Bash(pnpm install:*)",
8
+ "Bash(pnpm typecheck:*)",
9
+ "Skill(vibe-code-cleanup)",
10
+ "Bash(node build.mts:*)",
11
+ "Bash(pnpm test:*)",
12
+ "Bash(node dist/cli.js:*)",
13
+ "Bash(mkdir:*)",
14
+ "Bash(node /Users/andy/node-libraries/prism-framework-tools/dist/cli.js generate-api-clients:*)",
15
+ "Bash(pnpm local:install:*)"
16
+ ],
17
+ "deny": [],
18
+ "ask": []
19
+ }
20
+ }
package/CHANGELOG ADDED
@@ -0,0 +1,28 @@
1
+
2
+ 0.4.0
3
+ - Renamed from @facetlayer/prism-framework-tools to @facetlayer/prism-framework
4
+
5
+ 0.3.0
6
+ - Add config file support (.prism.qc) with parent directory search
7
+ - Fix API client type generation issues
8
+ - Add generate-api-clients-config documentation
9
+ - Add endpoint-tools and env-files documentation
10
+ - Safety checks for Zod schemas incompatible with OpenAPI
11
+ - Improve getting-started docs
12
+
13
+ 0.2.5
14
+ - Add list-docs and get-doc (with doc-files-helper)
15
+
16
+ 0.2.4
17
+ - Handle JSONish params in 'call' command
18
+ - generate-api-clients now uses --out param
19
+
20
+ 0.2.3
21
+ - Fix for list-endpoints
22
+
23
+ 0.2.1
24
+ - Add list-endpoints command
25
+ - Call endpoint - don't fail on response schema failure
26
+
27
+ 0.1.0
28
+ - initial version
package/CLAUDE.md ADDED
@@ -0,0 +1,44 @@
1
+ # prism-framework
2
+
3
+ Base library and CLI tools for the Prism app framework ecosystem.
4
+
5
+ ## Important Files and Directories
6
+
7
+ ### Source Code (`src/`)
8
+ - `cli.ts` - Main CLI entry point, uses yargs for argument parsing
9
+ - `call-command.ts` - Logic for calling endpoints, handles JSON parsing of arguments
10
+ - `generate-api-clients.ts` - Generates TypeScript types from OpenAPI schema
11
+ - `list-endpoints-command.ts` - Lists available endpoints from the API server
12
+ - `loadEnv.ts` - Environment variable loading and validation
13
+ - `getPorts.ts` - Port number utilities
14
+
15
+ ### Documentation (`docs/`)
16
+
17
+ Markdown files for documentation.
18
+
19
+ Run `doc-files list-docs` to understand the format.
20
+
21
+ - `getting-started.md` - Setup guide for Prism Framework projects
22
+ - `run-endpoint-tool.md` - Detailed CLI usage documentation
23
+ - `env-files.md` - Environment configuration strategy
24
+
25
+ ### Tests (`test/`)
26
+ - `call-command.test.ts` - Unit tests for argument parsing logic
27
+
28
+ ### Build Output
29
+ - `dist/cli.js` - Compiled CLI executable (ES modules)
30
+
31
+ ## Build Commands
32
+
33
+ ```bash
34
+ pnpm build # Build the project
35
+ pnpm test # Run tests with Vitest
36
+ pnpm typecheck # TypeScript type checking
37
+ ```
38
+
39
+ ## Key Dependencies
40
+
41
+ - `yargs` - CLI argument parsing
42
+ - `dotenv` - Environment variable loading
43
+ - `@facetlayer/doc-files-helper` - Documentation file management
44
+ - `@facetlayer/prism-framework-api` - Prism API framework types
package/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # @facetlayer/prism-framework
2
+
3
+ Base library and CLI tools for the Prism app framework.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @facetlayer/prism-framework
9
+ ```
10
+
11
+ ## CLI Commands
12
+
13
+ | Command | Description |
14
+ |---------|-------------|
15
+ | `prism list-endpoints` | List all available endpoints from the API server |
16
+ | `prism call [METHOD] [PATH] [--args]` | Call an endpoint on the running API server |
17
+ | `prism generate-api-clients --out <file>` | Generate TypeScript types from OpenAPI schema |
18
+ | `prism list-docs` | List available documentation |
19
+ | `prism get-doc <name>` | Display a specific documentation file |
20
+
21
+ ### Examples
22
+
23
+ ```bash
24
+ # List all endpoints
25
+ prism list-endpoints
26
+
27
+ # Call endpoints
28
+ prism call /api/users # GET request
29
+ prism call POST /api/users --name "John" # POST with body
30
+ prism call POST /api/data --config '{"timeout":30}' # JSON arguments
31
+
32
+ # Generate TypeScript types
33
+ prism generate-api-clients --out ./src/api-types.ts
34
+
35
+ # Access documentation
36
+ prism list-docs
37
+ prism get-doc getting-started
38
+ ```
39
+
40
+ ## Documentation
41
+
42
+ Once installed, the CLI has `prism list-docs` and `prism get-doc ...` commands to browse through the documentation files.
43
+
44
+ Run `prism list-docs` to see available documentation topics, including:
45
+ - `getting-started` - Setup guide for Prism Framework projects
46
+ - `run-endpoint-tool` - Detailed CLI usage documentation
47
+ - `env-files` - Environment configuration strategy
package/build.mts ADDED
@@ -0,0 +1,8 @@
1
+ #! /usr/bin/env node
2
+
3
+ import { runBuildTool } from '@facetlayer/build-config-nodejs';
4
+ import { cpSync } from 'fs';
5
+
6
+ await runBuildTool({
7
+ entryPoints: ['src/cli.ts'],
8
+ });
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ export interface CallEndpointLooseOptions {
3
+ baseUrl: string;
4
+ positionalArgs: string[];
5
+ namedArgs: Record<string, any>;
6
+ quiet?: boolean;
7
+ }
8
+ export declare function parseNamedArgs(namedArgs: Record<string, any>): Record<string, any>;
9
+ /**
10
+ * Make an HTTP request to the local Prism API server
11
+ */
12
+ export declare function callEndpoint(looseOptions: CallEndpointLooseOptions): Promise<any>;
13
+ //# sourceMappingURL=call-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call-command.d.ts","sourceRoot":"","sources":["../src/call-command.ts"],"names":[],"mappings":";AAIA,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAA;IACf,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAC,GAAG,CAAC,CAAA;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAmCD,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAMlF;AAkCD;;GAEG;AACH,wBAAsB,YAAY,CAAC,YAAY,EAAE,wBAAwB,gBA2DxE"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,475 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import yargs from "yargs";
5
+ import { hideBin } from "yargs/helpers";
6
+ import { readFileSync as readFileSync2 } from "fs";
7
+ import { join as join2, dirname as dirname3 } from "path";
8
+ import { fileURLToPath } from "url";
9
+
10
+ // src/loadEnv.ts
11
+ import * as path from "path";
12
+ import * as fs from "fs";
13
+ import { config } from "dotenv";
14
+ function loadEnv(cwd) {
15
+ const envPath = path.resolve(cwd, ".env");
16
+ if (!fs.existsSync(envPath)) {
17
+ throw new Error(
18
+ `No .env file found at ${envPath}
19
+
20
+ Please create a .env file with PRISM_API_PORT defined.
21
+ Example:
22
+ PRISM_API_PORT=3000`
23
+ );
24
+ }
25
+ const result = config({ path: envPath });
26
+ if (result.error) {
27
+ throw new Error(`Failed to load .env file: ${result.error.message}`);
28
+ }
29
+ const port = process.env.PRISM_API_PORT;
30
+ if (!port) {
31
+ throw new Error(
32
+ "PRISM_API_PORT is not defined in .env file\n\nPlease add PRISM_API_PORT to your .env file.\nExample:\n PRISM_API_PORT=3000"
33
+ );
34
+ }
35
+ const portNumber = parseInt(port, 10);
36
+ if (isNaN(portNumber) || portNumber <= 0 || portNumber > 65535) {
37
+ throw new Error(
38
+ `Invalid PRISM_API_PORT value: ${port}
39
+
40
+ Port must be a number between 1 and 65535`
41
+ );
42
+ }
43
+ return {
44
+ port: portNumber,
45
+ baseUrl: `http://localhost:${portNumber}`
46
+ };
47
+ }
48
+
49
+ // src/call-command.ts
50
+ var EVERY_METHOD = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE"]);
51
+ function parseValue(value) {
52
+ if (typeof value === "string") {
53
+ const trimmed = value.trim();
54
+ if (trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]")) {
55
+ try {
56
+ return JSON.parse(trimmed);
57
+ } catch {
58
+ return value;
59
+ }
60
+ }
61
+ } else if (typeof value === "object" && value !== null && !Array.isArray(value)) {
62
+ const result = {};
63
+ for (const [k, v] of Object.entries(value)) {
64
+ result[k] = parseValue(v);
65
+ }
66
+ return result;
67
+ }
68
+ return value;
69
+ }
70
+ function parseNamedArgs(namedArgs) {
71
+ const result = {};
72
+ for (const [key, value] of Object.entries(namedArgs)) {
73
+ result[key] = parseValue(value);
74
+ }
75
+ return result;
76
+ }
77
+ function parseOptions(looseOptions) {
78
+ const result = {
79
+ baseUrl: looseOptions.baseUrl,
80
+ method: "GET",
81
+ path: "/",
82
+ requestBody: parseNamedArgs(looseOptions.namedArgs)
83
+ };
84
+ for (const positional of looseOptions.positionalArgs) {
85
+ if (positional.startsWith("/")) {
86
+ result.path = positional;
87
+ continue;
88
+ }
89
+ if (EVERY_METHOD.has(positional.toUpperCase())) {
90
+ result.method = positional.toUpperCase();
91
+ continue;
92
+ }
93
+ if (positional.startsWith("http:") || positional.startsWith("https:")) {
94
+ result.baseUrl = positional;
95
+ continue;
96
+ }
97
+ throw new Error("unrecognized positional arg:" + positional);
98
+ }
99
+ return result;
100
+ }
101
+ async function callEndpoint(looseOptions) {
102
+ const options = parseOptions(looseOptions);
103
+ const url = `${options.baseUrl}${options.path}`;
104
+ const requestOptions = {
105
+ method: options.method,
106
+ headers: {
107
+ "Content-Type": "application/json"
108
+ }
109
+ };
110
+ if (["POST", "PUT", "PATCH", "DELETE"].includes(options.method) && options.requestBody && Object.keys(options.requestBody).length > 0) {
111
+ requestOptions.body = JSON.stringify(options.requestBody);
112
+ }
113
+ try {
114
+ const response = await fetch(url, requestOptions);
115
+ if (!looseOptions.quiet)
116
+ console.log("Response status: " + response.status);
117
+ const responseText = await response.text();
118
+ if (!looseOptions.quiet)
119
+ console.log("Response: ", responseText);
120
+ let responseData;
121
+ try {
122
+ responseData = responseText ? JSON.parse(responseText) : null;
123
+ } catch {
124
+ responseData = responseText;
125
+ }
126
+ if (!response.ok) {
127
+ throw new Error(
128
+ `HTTP ${response.status} ${response.statusText}
129
+ Response: ${JSON.stringify(responseData, null, 2)}`
130
+ );
131
+ }
132
+ return responseData;
133
+ } catch (error) {
134
+ if (error instanceof Error) {
135
+ if (error.message.includes("fetch failed") || error.message.includes("ECONNREFUSED")) {
136
+ throw new Error(
137
+ `Failed to connect to ${url}
138
+
139
+ Make sure your Prism API server is running.
140
+ The server should be listening on the port specified in .env (PRISM_API_PORT)`
141
+ );
142
+ }
143
+ }
144
+ throw error;
145
+ }
146
+ }
147
+
148
+ // src/list-endpoints-command.ts
149
+ async function listEndpoints(baseUrl) {
150
+ try {
151
+ const response = await callEndpoint({
152
+ baseUrl,
153
+ positionalArgs: ["GET", "/endpoints.json"],
154
+ namedArgs: {},
155
+ quiet: true
156
+ });
157
+ const endpoints = response.endpoints;
158
+ console.log("Available endpoints:\n");
159
+ if (Array.isArray(endpoints)) {
160
+ for (const endpoint of endpoints) {
161
+ const fullPath = `${endpoint.method} ${endpoint.path}`;
162
+ console.log(` ${fullPath}`);
163
+ if (endpoint.description) {
164
+ console.log(` ${endpoint.description}`);
165
+ }
166
+ }
167
+ } else {
168
+ console.log(JSON.stringify(endpoints, null, 2));
169
+ }
170
+ } catch (error) {
171
+ console.error("Could not list endpoints. The server may not support the /api/endpoints introspection endpoint.");
172
+ console.error(error instanceof Error ? error.message : String(error));
173
+ process.exit(1);
174
+ }
175
+ }
176
+
177
+ // src/generate-api-clients.ts
178
+ import { mkdirSync, writeFileSync } from "fs";
179
+ import { dirname, resolve as resolve2 } from "path";
180
+ function capitalizeFirst(str) {
181
+ return str.charAt(0).toUpperCase() + str.slice(1);
182
+ }
183
+ function convertToExpressPath(openApiPath) {
184
+ return openApiPath.replace(/\{([^}]+)\}/g, ":$1");
185
+ }
186
+ function schemaToTypeScript(schema, components, indent = 0) {
187
+ if (!schema) {
188
+ return "unknown";
189
+ }
190
+ const indentStr = " ".repeat(indent);
191
+ if (schema.$ref) {
192
+ const refName = schema.$ref.split("/").pop();
193
+ return refName;
194
+ }
195
+ if (schema.type === "array") {
196
+ const itemType = schemaToTypeScript(schema.items, components, indent);
197
+ return `Array<${itemType}>`;
198
+ }
199
+ if (schema.type === "object" || schema.properties) {
200
+ const properties = schema.properties || {};
201
+ const required = schema.required || [];
202
+ if (Object.keys(properties).length === 0) {
203
+ return "Record<string, unknown>";
204
+ }
205
+ const props = Object.entries(properties).map(([key, value]) => {
206
+ const isRequired = required.includes(key);
207
+ const propType = schemaToTypeScript(value, components, indent + 1);
208
+ const optional = isRequired ? "" : "?";
209
+ return `${indentStr} ${key}${optional}: ${propType};`;
210
+ });
211
+ return `{
212
+ ${props.join("\n")}
213
+ ${indentStr}}`;
214
+ }
215
+ switch (schema.type) {
216
+ case "string":
217
+ return "string";
218
+ case "number":
219
+ case "integer":
220
+ return "number";
221
+ case "boolean":
222
+ return "boolean";
223
+ case "null":
224
+ return "null";
225
+ default:
226
+ return "unknown";
227
+ }
228
+ }
229
+ async function generateApiClients(baseUrl, outputFiles) {
230
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
231
+ if (outputFiles.length === 0) {
232
+ throw new Error("At least one --out file must be specified");
233
+ }
234
+ try {
235
+ const response = await fetch(`${baseUrl}/openapi.json`);
236
+ if (!response.ok) {
237
+ throw new Error(
238
+ `Failed to fetch OpenAPI schema: ${response.status} ${response.statusText}
239
+ Make sure the Prism API server is running at ${baseUrl}`
240
+ );
241
+ }
242
+ const schema = await response.json();
243
+ const lines = [];
244
+ const endpointMap = [];
245
+ if ((_a = schema.components) == null ? void 0 : _a.schemas) {
246
+ lines.push("// Component Schemas");
247
+ for (const [name, componentSchema] of Object.entries(schema.components.schemas)) {
248
+ const typeStr = schemaToTypeScript(componentSchema, schema.components.schemas);
249
+ lines.push(`export type ${name} = ${typeStr};
250
+ `);
251
+ }
252
+ lines.push("");
253
+ }
254
+ lines.push("// Endpoint Types");
255
+ for (const [pathStr, pathItem] of Object.entries(schema.paths)) {
256
+ for (const [method, operation] of Object.entries(pathItem)) {
257
+ if (!operation.operationId) continue;
258
+ const typeName = capitalizeFirst(operation.operationId);
259
+ const expressPath = convertToExpressPath(pathStr);
260
+ endpointMap.push({ method: method.toLowerCase(), path: expressPath, operationId: operation.operationId });
261
+ const requestSchema = (_d = (_c = (_b = operation.requestBody) == null ? void 0 : _b.content) == null ? void 0 : _c["application/json"]) == null ? void 0 : _d.schema;
262
+ const requestType = requestSchema ? schemaToTypeScript(requestSchema, (_e = schema.components) == null ? void 0 : _e.schemas) : "void";
263
+ lines.push(`export type ${typeName}Request = ${requestType};
264
+ `);
265
+ const responseSchema = (_i = (_h = (_g = (_f = operation.responses) == null ? void 0 : _f["200"]) == null ? void 0 : _g.content) == null ? void 0 : _h["application/json"]) == null ? void 0 : _i.schema;
266
+ const responseType = responseSchema ? schemaToTypeScript(responseSchema, (_j = schema.components) == null ? void 0 : _j.schemas) : "void";
267
+ lines.push(`export type ${typeName}Response = ${responseType};
268
+ `);
269
+ }
270
+ }
271
+ lines.push("// Union type of all valid endpoints");
272
+ lines.push("export type ApiEndpoint =");
273
+ const endpointStrings = endpointMap.map(({ method, path: path2 }) => ` | "${method} ${path2}"`);
274
+ lines.push(endpointStrings.join("\n"));
275
+ lines.push(";\n");
276
+ lines.push("// Generic Request/Response Types by Endpoint");
277
+ lines.push("export type RequestType<T extends ApiEndpoint> =");
278
+ const requestCases = endpointMap.map(
279
+ ({ method, path: path2, operationId }) => ` T extends "${method} ${path2}" ? ${capitalizeFirst(operationId)}Request :`
280
+ );
281
+ lines.push(requestCases.join("\n"));
282
+ lines.push(" never;\n");
283
+ lines.push("export type ResponseType<T extends ApiEndpoint> =");
284
+ const responseCases = endpointMap.map(
285
+ ({ method, path: path2, operationId }) => ` T extends "${method} ${path2}" ? ${capitalizeFirst(operationId)}Response :`
286
+ );
287
+ lines.push(responseCases.join("\n"));
288
+ lines.push(" never;\n");
289
+ const output = lines.join("\n");
290
+ const header = `// Generated API client types
291
+ // Auto-generated from OpenAPI schema - do not edit manually
292
+
293
+ `;
294
+ const content = header + output;
295
+ for (const outputFile of outputFiles) {
296
+ const resolvedPath = resolve2(outputFile);
297
+ mkdirSync(dirname(resolvedPath), { recursive: true });
298
+ writeFileSync(resolvedPath, content, "utf-8");
299
+ console.log(`Written: ${resolvedPath}`);
300
+ }
301
+ } catch (error) {
302
+ console.error("\u274C Error generating client:", error);
303
+ throw error;
304
+ }
305
+ }
306
+
307
+ // src/config/loadConfig.ts
308
+ import { existsSync as existsSync2, readFileSync } from "fs";
309
+ import { dirname as dirname2, join, resolve as resolve3 } from "path";
310
+ import { parseFile } from "@facetlayer/qc";
311
+ var CONFIG_FILENAME = ".prism.qc";
312
+ function loadConfig(cwd) {
313
+ let currentDir = resolve3(cwd);
314
+ while (true) {
315
+ const configPath = join(currentDir, CONFIG_FILENAME);
316
+ if (existsSync2(configPath)) {
317
+ const config2 = parseConfigFile(configPath);
318
+ return { config: config2, configDir: currentDir };
319
+ }
320
+ const parentDir = dirname2(currentDir);
321
+ if (parentDir === currentDir) {
322
+ return null;
323
+ }
324
+ currentDir = parentDir;
325
+ }
326
+ }
327
+ function parseConfigFile(configPath) {
328
+ const content = readFileSync(configPath, "utf-8");
329
+ const queries = parseFile(content);
330
+ const generateApiClientTargets = [];
331
+ for (const query of queries) {
332
+ switch (query.command) {
333
+ case "generate-api-client": {
334
+ const outputFile = query.getStringValue("output-file");
335
+ generateApiClientTargets.push({ outputFile });
336
+ break;
337
+ }
338
+ default:
339
+ throw new Error(`Unknown command "${query.command}" in ${CONFIG_FILENAME}`);
340
+ }
341
+ }
342
+ return {
343
+ generateApiClientTargets
344
+ };
345
+ }
346
+
347
+ // src/cli.ts
348
+ import { DocFilesHelper } from "@facetlayer/doc-files-helper";
349
+ var __filename = fileURLToPath(import.meta.url);
350
+ var __dirname = dirname3(__filename);
351
+ var __packageRoot = join2(__dirname, "..");
352
+ var packageJson = JSON.parse(
353
+ readFileSync2(join2(__packageRoot, "package.json"), "utf-8")
354
+ );
355
+ var docFiles = new DocFilesHelper({
356
+ dirs: [join2(__packageRoot, "docs")],
357
+ files: [join2(__packageRoot, "README.md")]
358
+ });
359
+ async function main() {
360
+ const args = yargs(hideBin(process.argv)).command(
361
+ "list-endpoints",
362
+ "List all available endpoints",
363
+ {},
364
+ async () => {
365
+ try {
366
+ const cwd = process.cwd();
367
+ const config2 = loadEnv(cwd);
368
+ console.log(`Using API server at: ${config2.baseUrl}
369
+ `);
370
+ await listEndpoints(config2.baseUrl);
371
+ } catch (error) {
372
+ if (error instanceof Error && error.stack) {
373
+ console.error(error.stack);
374
+ } else {
375
+ console.error("Error:", error instanceof Error ? error.message : String(error));
376
+ }
377
+ process.exit(1);
378
+ }
379
+ }
380
+ ).command(
381
+ "call <positionals...>",
382
+ "Call an endpoint. Named args starting with { } or [ ] are parsed as JSON.",
383
+ (yargs2) => {
384
+ return yargs2;
385
+ },
386
+ async (argv) => {
387
+ try {
388
+ const cwd = process.cwd();
389
+ const config2 = loadEnv(cwd);
390
+ const requestData = {};
391
+ for (const [key, value] of Object.entries(argv)) {
392
+ if (["positionals", "_", "$0"].includes(key)) {
393
+ continue;
394
+ }
395
+ requestData[key] = value;
396
+ }
397
+ try {
398
+ const result = await callEndpoint({
399
+ baseUrl: config2.baseUrl,
400
+ positionalArgs: argv.positionals,
401
+ namedArgs: requestData
402
+ });
403
+ } catch (error) {
404
+ console.error("Error calling endpoint:");
405
+ if (error instanceof Error) {
406
+ console.error(error.message);
407
+ if (error.stack) {
408
+ console.error("\nStack trace:");
409
+ console.error(error.stack);
410
+ }
411
+ } else {
412
+ console.error(String(error));
413
+ }
414
+ process.exit(1);
415
+ }
416
+ } catch (error) {
417
+ if (error instanceof Error && error.stack) {
418
+ console.error(error.stack);
419
+ } else {
420
+ console.error("Error:", error instanceof Error ? error.message : String(error));
421
+ }
422
+ process.exit(1);
423
+ }
424
+ }
425
+ ).command(
426
+ "generate-api-clients",
427
+ "Generate TypeScript API client types from OpenAPI schema",
428
+ (yargs2) => {
429
+ return yargs2.option("out", {
430
+ type: "string",
431
+ array: true,
432
+ describe: "Output file path(s) to write generated types to"
433
+ });
434
+ },
435
+ async (argv) => {
436
+ try {
437
+ const cwd = process.cwd();
438
+ const envConfig = loadEnv(cwd);
439
+ console.log(`Using API server at: ${envConfig.baseUrl}
440
+ `);
441
+ let outputFiles = [];
442
+ if (argv.out && argv.out.length > 0) {
443
+ outputFiles = argv.out;
444
+ } else {
445
+ const result = loadConfig(cwd);
446
+ if (!result || result.config.generateApiClientTargets.length === 0) {
447
+ console.error("Error: No output files specified.");
448
+ console.error("Either use --out to specify output files, or configure targets in .prism.qc:");
449
+ console.error(" generate-api-client-target out=./src/api-types.ts");
450
+ process.exit(1);
451
+ }
452
+ outputFiles = result.config.generateApiClientTargets.map((t) => t.outputFile);
453
+ }
454
+ await generateApiClients(envConfig.baseUrl, outputFiles);
455
+ } catch (error) {
456
+ if (error instanceof Error && error.stack) {
457
+ console.error(error.stack);
458
+ } else {
459
+ console.error("Error:", error instanceof Error ? error.message : String(error));
460
+ }
461
+ process.exit(1);
462
+ }
463
+ }
464
+ );
465
+ docFiles.yargsSetup(args);
466
+ args.strictCommands().demandCommand(1, "You must specify a command").help().alias("help", "h").version(packageJson.version).alias("version", "v").example([
467
+ ["$0 list-endpoints", "List all available endpoints"],
468
+ ["$0 call /api/users", "Call GET /api/users"],
469
+ ['$0 call POST /api/users --name "John" --email "john@example.com"', "call POST with data"],
470
+ [`$0 call POST /api/users --config '{"timeout":30}'`, "pass JSON objects as args"],
471
+ ["$0 generate-api-clients --out ./api-types.ts", "Generate API client types to a file"],
472
+ ["$0 generate-api-clients --out ./types.ts --out ./backup/types.ts", "Write to multiple files"]
473
+ ]).parse();
474
+ }
475
+ main();
@@ -0,0 +1,7 @@
1
+ export interface GenerateApiClientTarget {
2
+ outputFile: string;
3
+ }
4
+ export interface ConfigFile {
5
+ generateApiClientTargets: GenerateApiClientTarget[];
6
+ }
7
+ //# sourceMappingURL=ConfigFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigFile.d.ts","sourceRoot":"","sources":["../../src/config/ConfigFile.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,wBAAwB,EAAE,uBAAuB,EAAE,CAAC;CACrD"}
@@ -0,0 +1,4 @@
1
+ export type { ConfigFile, GenerateApiClientTarget } from './ConfigFile.ts';
2
+ export type { LoadConfigResult } from './loadConfig.ts';
3
+ export { loadConfig } from './loadConfig.ts';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC3E,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { ConfigFile } from './ConfigFile.ts';
2
+ export interface LoadConfigResult {
3
+ config: ConfigFile;
4
+ configDir: string;
5
+ }
6
+ /**
7
+ * Find and load the .prism.qc config file.
8
+ * Searches in the provided directory and parent directories until found or root is reached.
9
+ */
10
+ export declare function loadConfig(cwd: string): LoadConfigResult | null;
11
+ //# sourceMappingURL=loadConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadConfig.d.ts","sourceRoot":"","sources":["../../src/config/loadConfig.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,iBAAiB,CAAC;AAI3E,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAkB/D"}