@fluid-app/fluid-cli 0.1.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.
@@ -0,0 +1,210 @@
1
+ import { Command } from "commander";
2
+
3
+ //#region src/config/types.d.ts
4
+ /**
5
+ * Configuration types for the Fluid CLI
6
+ */
7
+ interface FluidProfile {
8
+ readonly name: string;
9
+ readonly token: string;
10
+ readonly companyName: string;
11
+ readonly storedAt: string;
12
+ }
13
+ interface FluidConfig {
14
+ activeProfile: string | null;
15
+ profiles: Record<string, FluidProfile>;
16
+ plugins: Record<string, unknown>;
17
+ /**
18
+ * Allow-list of plugin package names.
19
+ *
20
+ * - `null` (default) — auto-discover and load all `@fluid-app/fluid-cli-*`
21
+ * and `*-cli-commands` packages found in `node_modules` or the pnpm
22
+ * workspace. Only `@fluid-app`-scoped packages matching the naming
23
+ * convention are eligible; no third-party code is loaded.
24
+ * - `string[]` — only load plugins whose names appear in the array.
25
+ * Set to `[]` to disable all plugins.
26
+ */
27
+ enabledPlugins: string[] | null;
28
+ }
29
+ declare function createDefaultConfig(): FluidConfig;
30
+ //#endregion
31
+ //#region src/config/paths.d.ts
32
+ /**
33
+ * XDG-compliant config directory resolution
34
+ *
35
+ * Priority:
36
+ * 1. FLUID_CONFIG_DIR env var (explicit override)
37
+ * 2. ~/.fluid/ on macOS (convention for CLI tools)
38
+ * 3. %APPDATA%/fluid/ on Windows
39
+ * 4. $XDG_CONFIG_HOME/fluid/ on Linux (XDG spec)
40
+ * 5. ~/.config/fluid/ fallback on Linux
41
+ */
42
+ declare function getConfigDir(): string;
43
+ declare function getConfigFilePath(): string;
44
+ //#endregion
45
+ //#region src/config/config.d.ts
46
+ declare function readConfig(): FluidConfig;
47
+ declare function writeConfig(config: FluidConfig): void;
48
+ declare function updateConfig(updater: (config: FluidConfig) => FluidConfig): FluidConfig;
49
+ //#endregion
50
+ //#region src/utils/errors.d.ts
51
+ /**
52
+ * Base error interface for CLI domain errors.
53
+ * All domain-specific error types should extend this.
54
+ */
55
+ interface CliError {
56
+ readonly code: string;
57
+ readonly message: string;
58
+ readonly details?: string;
59
+ }
60
+ //#endregion
61
+ //#region src/utils/result.d.ts
62
+ /**
63
+ * Result type utilities for type-safe error handling
64
+ *
65
+ * The Result<T, E> pattern provides a discriminated union for fallible operations,
66
+ * enabling exhaustive handling without try/catch blocks.
67
+ */
68
+ interface Success<T> {
69
+ readonly success: true;
70
+ readonly value: T;
71
+ }
72
+ interface Failure<E> {
73
+ readonly success: false;
74
+ readonly error: E;
75
+ }
76
+ type Result<T, E = Error> = Success<T> | Failure<E>;
77
+ declare function success<T>(value: T): Success<T>;
78
+ declare function failure<E>(error: E): Failure<E>;
79
+ declare function isSuccess<T, E>(result: Result<T, E>): result is Success<T>;
80
+ declare function isFailure<T, E>(result: Result<T, E>): result is Failure<E>;
81
+ declare function tryCatch<T>(fn: () => T): Result<T, Error>;
82
+ declare function tryCatchAsync<T>(fn: () => Promise<T>): Promise<Result<T, Error>>;
83
+ declare function unwrap<T, E>(result: Result<T, E>): T;
84
+ declare function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T;
85
+ declare function mapResult<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;
86
+ declare function mapError<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F>;
87
+ declare function isError(value: unknown): value is Error;
88
+ declare function isNodeError(value: unknown): value is NodeJS.ErrnoException;
89
+ declare function getErrorMessage(error: unknown): string;
90
+ //#endregion
91
+ //#region src/auth/fluid-api.d.ts
92
+ interface FluidApiError extends CliError {
93
+ readonly code: string;
94
+ readonly message: string;
95
+ readonly details?: string;
96
+ }
97
+ interface CompanyInfo {
98
+ readonly name: string;
99
+ }
100
+ interface MfaResponse {
101
+ readonly uuid: string;
102
+ readonly expiresAt: string;
103
+ }
104
+ interface CompanyChoice {
105
+ readonly id: number;
106
+ readonly name: string;
107
+ readonly shopName: string;
108
+ readonly jwt: string;
109
+ }
110
+ interface ConfirmMfaResponse {
111
+ readonly authType: string;
112
+ readonly companies: CompanyChoice[];
113
+ }
114
+ /**
115
+ * Validate a token against the Fluid API and return company info
116
+ */
117
+ declare function validateToken(token: string): Promise<Result<CompanyInfo, FluidApiError>>;
118
+ /**
119
+ * Send a multi-factor authentication code to the given email address.
120
+ * Always returns 201 from the API (anti-enumeration).
121
+ */
122
+ declare function sendMfa(email: string): Promise<Result<MfaResponse, FluidApiError>>;
123
+ /**
124
+ * Confirm a multi-factor authentication code and retrieve company JWTs.
125
+ */
126
+ declare function confirmMfa(uuid: string, code: string): Promise<Result<ConfirmMfaResponse, FluidApiError>>;
127
+ //#endregion
128
+ //#region src/auth/token.d.ts
129
+ /**
130
+ * Get the auth token for a named profile, or the active profile when omitted.
131
+ */
132
+ declare function getAuthToken(profileName?: string): string | null;
133
+ /**
134
+ * Get the active profile, or null if not logged in
135
+ */
136
+ declare function getActiveProfile(): FluidProfile | null;
137
+ /**
138
+ * List all stored profile names
139
+ */
140
+ declare function listProfileNames(): string[];
141
+ //#endregion
142
+ //#region src/plugins/types.d.ts
143
+ interface PluginContext {
144
+ /** Commander program instance — plugins add subcommands here */
145
+ readonly program: Command;
146
+ /** Read the stored auth token for the active profile */
147
+ readonly getAuthToken: () => string | null;
148
+ /** Path to the config directory (~/.fluid/) */
149
+ readonly configDir: string;
150
+ }
151
+ interface FluidPlugin {
152
+ readonly name: string;
153
+ readonly version: string;
154
+ register(ctx: PluginContext): void | Promise<void>;
155
+ }
156
+ //#endregion
157
+ //#region ../../platform/api-client-core/src/fetch-client.d.ts
158
+ interface RequestOptions {
159
+ method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
160
+ headers?: Record<string, string>;
161
+ params?: Record<string, unknown>;
162
+ body?: unknown;
163
+ signal?: AbortSignal;
164
+ }
165
+ interface FetchClientInstance {
166
+ request: <TResponse = unknown>(endpoint: string, options?: RequestOptions) => Promise<TResponse>;
167
+ requestWithFormData: <TResponse = unknown>(endpoint: string, formData: FormData, options?: Omit<RequestOptions, "body" | "params"> & {
168
+ method?: "POST" | "PUT" | "PATCH";
169
+ }) => Promise<TResponse>;
170
+ get: <TResponse = unknown>(endpoint: string, params?: Record<string, unknown>, options?: Omit<RequestOptions, "method" | "params">) => Promise<TResponse>;
171
+ post: <TResponse = unknown>(endpoint: string, body?: unknown, options?: Omit<RequestOptions, "method" | "body">) => Promise<TResponse>;
172
+ put: <TResponse = unknown>(endpoint: string, body?: unknown, options?: Omit<RequestOptions, "method" | "body">) => Promise<TResponse>;
173
+ patch: <TResponse = unknown>(endpoint: string, body?: unknown, options?: Omit<RequestOptions, "method" | "body">) => Promise<TResponse>;
174
+ delete: <TResponse = unknown>(endpoint: string, options?: Omit<RequestOptions, "method">) => Promise<TResponse>;
175
+ }
176
+ type FetchClient = FetchClientInstance;
177
+ //#endregion
178
+ //#region src/domain/types.d.ts
179
+ interface OutputOptions {
180
+ format: "json" | "table";
181
+ compact: boolean;
182
+ jq?: string;
183
+ }
184
+ interface CommandContext {
185
+ getClient(): Promise<FetchClient>;
186
+ output(data: unknown): void;
187
+ parseBody(raw: string): unknown;
188
+ verbose: boolean;
189
+ }
190
+ //#endregion
191
+ //#region src/domain/command.d.ts
192
+ type RegisterFn = (parent: Command, ctx: CommandContext) => void;
193
+ declare function createDomainCommand(name: string, description: string, register: RegisterFn): Command;
194
+ //#endregion
195
+ //#region src/domain/context.d.ts
196
+ declare function createCommandContext(opts: {
197
+ token?: string;
198
+ baseUrl?: string;
199
+ profile?: string;
200
+ format: "json" | "table";
201
+ compact: boolean;
202
+ jq?: string;
203
+ verbose: boolean;
204
+ }): CommandContext;
205
+ //#endregion
206
+ //#region src/domain/output.d.ts
207
+ declare function formatOutput(data: unknown, options: OutputOptions): string;
208
+ //#endregion
209
+ export { type CliError, type CommandContext, type CompanyChoice, type CompanyInfo, type ConfirmMfaResponse, type Failure, type FetchClient, type FluidApiError, type FluidConfig, type FluidPlugin, type FluidProfile, type MfaResponse, type OutputOptions, type PluginContext, type Result, type Success, confirmMfa, createCommandContext, createDefaultConfig, createDomainCommand, failure, formatOutput, getActiveProfile, getAuthToken, getConfigDir, getConfigFilePath, getErrorMessage, isError, isFailure, isNodeError, isSuccess, listProfileNames, mapError, mapResult, readConfig, sendMfa, success, tryCatch, tryCatchAsync, unwrap, unwrapOr, updateConfig, validateToken, writeConfig };
210
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/config/types.ts","../src/config/paths.ts","../src/config/config.ts","../src/utils/errors.ts","../src/utils/result.ts","../src/auth/fluid-api.ts","../src/auth/token.ts","../src/plugins/types.ts","../../../platform/api-client-core/src/fetch-client.ts","../src/domain/types.ts","../src/domain/command.ts","../src/domain/context.ts","../src/domain/output.ts"],"mappings":"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"}
package/dist/index.mjs ADDED
@@ -0,0 +1,301 @@
1
+ import { C as tryCatchAsync, S as tryCatch, T as unwrapOr, _ as isNodeError, a as updateConfig, b as mapResult, c as getConfigFilePath, d as sendMfa, f as validateToken, g as isFailure, h as isError, i as readConfig, l as createDefaultConfig, m as getErrorMessage, n as getAuthToken, o as writeConfig, p as failure, r as listProfileNames, s as getConfigDir, t as getActiveProfile, u as confirmMfa, v as isSuccess, w as unwrap, x as success, y as mapError } from "./token-DCpSVmEk.mjs";
2
+ import { Command } from "commander";
3
+ //#region ../../platform/api-client-core/src/fetch-client.ts
4
+ /**
5
+ * API Error class compatible with fluid-admin's ApiError
6
+ */
7
+ var ApiError = class ApiError extends Error {
8
+ status;
9
+ data;
10
+ constructor(message, status, data) {
11
+ super(message);
12
+ this.name = "ApiError";
13
+ this.status = status;
14
+ this.data = data;
15
+ if ("captureStackTrace" in Error) Error.captureStackTrace(this, ApiError);
16
+ }
17
+ toJSON() {
18
+ return {
19
+ name: this.name,
20
+ message: this.message,
21
+ status: this.status,
22
+ data: this.data
23
+ };
24
+ }
25
+ };
26
+ /**
27
+ * Creates a configured fetch client instance
28
+ */
29
+ function createFetchClient(config) {
30
+ const { baseUrl, getAuthToken, onAuthError, defaultHeaders = {} } = config;
31
+ /**
32
+ * Build headers for a request
33
+ */
34
+ async function buildHeaders(customHeaders) {
35
+ const headers = {
36
+ Accept: "application/json",
37
+ "Content-Type": "application/json",
38
+ ...defaultHeaders,
39
+ ...customHeaders
40
+ };
41
+ if (getAuthToken) {
42
+ const token = await getAuthToken();
43
+ if (token) headers.Authorization = `Bearer ${token}`;
44
+ }
45
+ return headers;
46
+ }
47
+ /**
48
+ * Join baseUrl + endpoint via string concatenation (matches fetchApi).
49
+ * Using `new URL(endpoint, baseUrl)` would strip any path prefix from
50
+ * baseUrl (e.g. "/api") when the endpoint starts with "/".
51
+ */
52
+ function joinUrl(endpoint) {
53
+ return `${baseUrl}${endpoint}`;
54
+ }
55
+ /**
56
+ * Build URL with query parameters for GET requests
57
+ * Compatible with fluid-admin's query param handling
58
+ */
59
+ function buildUrl(endpoint, params) {
60
+ const fullUrl = joinUrl(endpoint);
61
+ if (!params || Object.keys(params).length === 0) return fullUrl;
62
+ const queryString = new URLSearchParams();
63
+ Object.entries(params).forEach(([key, value]) => {
64
+ if (value === void 0 || value === null) return;
65
+ if (Array.isArray(value)) value.forEach((item) => queryString.append(`${key}[]`, String(item)));
66
+ else if (typeof value === "object") Object.entries(value).forEach(([subKey, subValue]) => {
67
+ if (subValue === void 0 || subValue === null) return;
68
+ if (Array.isArray(subValue)) subValue.forEach((item) => queryString.append(`${key}[${subKey}][]`, String(item)));
69
+ else queryString.append(`${key}[${subKey}]`, String(subValue));
70
+ });
71
+ else queryString.append(key, String(value));
72
+ });
73
+ const qs = queryString.toString();
74
+ return qs ? `${fullUrl}?${qs}` : fullUrl;
75
+ }
76
+ /**
77
+ * Shared response handler for both JSON and FormData requests.
78
+ * Handles auth errors, non-OK responses, 204 No Content, and JSON parsing.
79
+ */
80
+ async function handleResponse(response, method, _url) {
81
+ if (response.status === 401 && onAuthError) onAuthError();
82
+ if (!response.ok) {
83
+ const errorText = await response.text().catch(() => "");
84
+ if (response.headers.get("content-type")?.includes("application/json")) {
85
+ let data;
86
+ try {
87
+ data = JSON.parse(errorText);
88
+ } catch {
89
+ throw new ApiError(errorText.slice(0, 200) || `${method} request failed with status ${response.status}`, response.status, null);
90
+ }
91
+ throw new ApiError(data.message || data.error_message || `${method} request failed`, response.status, data.errors || data);
92
+ } else throw new ApiError(`${method} request failed with status ${response.status}`, response.status, null);
93
+ }
94
+ if (response.status === 204 || response.headers.get("content-length") === "0") return null;
95
+ if (response.headers.get("content-type")?.includes("application/json")) try {
96
+ return await response.json();
97
+ } catch {
98
+ try {
99
+ return await response.text();
100
+ } catch {
101
+ return null;
102
+ }
103
+ }
104
+ return null;
105
+ }
106
+ /**
107
+ * Main request function
108
+ */
109
+ async function request(endpoint, options = {}) {
110
+ const { method = "GET", headers: customHeaders, params, body, signal } = options;
111
+ const url = params ? buildUrl(endpoint, params) : joinUrl(endpoint);
112
+ const headers = await buildHeaders(customHeaders);
113
+ let response;
114
+ try {
115
+ const fetchOptions = {
116
+ method,
117
+ headers
118
+ };
119
+ const serializedBody = body && method !== "GET" ? JSON.stringify(body) : null;
120
+ if (serializedBody) fetchOptions.body = serializedBody;
121
+ if (signal) fetchOptions.signal = signal;
122
+ response = await fetch(url, fetchOptions);
123
+ } catch (networkError) {
124
+ throw new ApiError(`Network error: ${networkError instanceof Error ? networkError.message : "Unknown network error"}`, 0, null);
125
+ }
126
+ return handleResponse(response, method, url);
127
+ }
128
+ /**
129
+ * Request with FormData (for file uploads)
130
+ */
131
+ async function requestWithFormData(endpoint, formData, options = {}) {
132
+ const { method = "POST", headers: customHeaders, signal } = options;
133
+ const url = joinUrl(endpoint);
134
+ const headers = await buildHeaders(customHeaders);
135
+ delete headers["Content-Type"];
136
+ let response;
137
+ try {
138
+ const fetchOptions = {
139
+ method,
140
+ headers,
141
+ body: formData
142
+ };
143
+ if (signal) fetchOptions.signal = signal;
144
+ response = await fetch(url, fetchOptions);
145
+ } catch (networkError) {
146
+ throw new ApiError(`Network error: ${networkError instanceof Error ? networkError.message : "Unknown network error"}`, 0, null);
147
+ }
148
+ return handleResponse(response, method, url);
149
+ }
150
+ return {
151
+ request,
152
+ requestWithFormData,
153
+ get: (endpoint, params, options) => request(endpoint, {
154
+ ...options,
155
+ method: "GET",
156
+ ...params && { params }
157
+ }),
158
+ post: (endpoint, body, options) => request(endpoint, {
159
+ ...options,
160
+ method: "POST",
161
+ body
162
+ }),
163
+ put: (endpoint, body, options) => request(endpoint, {
164
+ ...options,
165
+ method: "PUT",
166
+ body
167
+ }),
168
+ patch: (endpoint, body, options) => request(endpoint, {
169
+ ...options,
170
+ method: "PATCH",
171
+ body
172
+ }),
173
+ delete: (endpoint, options) => request(endpoint, {
174
+ ...options,
175
+ method: "DELETE"
176
+ })
177
+ };
178
+ }
179
+ //#endregion
180
+ //#region src/domain/output.ts
181
+ function formatOutput(data, options) {
182
+ let result = data;
183
+ if (options.jq) result = extractPath(result, options.jq);
184
+ if (options.format === "table") return formatTable(result);
185
+ if (options.compact) return JSON.stringify(result);
186
+ return JSON.stringify(result, null, 2);
187
+ }
188
+ function extractPath(data, path) {
189
+ const parts = path.replace(/^\.*/, "").split(/\.|\[/).filter(Boolean).map((p) => p.replace(/\]$/, ""));
190
+ let current = data;
191
+ for (const part of parts) {
192
+ if (current == null) return void 0;
193
+ current = current[part];
194
+ }
195
+ return current;
196
+ }
197
+ function formatTable(data) {
198
+ if (Array.isArray(data)) {
199
+ if (data.length === 0) return "(empty)";
200
+ if (typeof data[0] === "object" && data[0] !== null) {
201
+ const keys = Object.keys(data[0]);
202
+ const widths = keys.map((k) => Math.max(k.length, ...data.map((row) => String(row[k] ?? "").length)));
203
+ return [
204
+ keys.map((k, i) => k.toUpperCase().padEnd(widths[i])).join(" "),
205
+ widths.map((w) => "-".repeat(w)).join(" "),
206
+ ...data.map((row) => keys.map((k, i) => String(row[k] ?? "").padEnd(widths[i])).join(" "))
207
+ ].join("\n");
208
+ }
209
+ return data.map(String).join("\n");
210
+ }
211
+ if (typeof data === "object" && data !== null) {
212
+ const entries = Object.entries(data);
213
+ const maxKeyLen = Math.max(...entries.map(([k]) => k.length));
214
+ return entries.map(([k, v]) => `${k.padEnd(maxKeyLen)} ${JSON.stringify(v)}`).join("\n");
215
+ }
216
+ return String(data);
217
+ }
218
+ //#endregion
219
+ //#region src/domain/context.ts
220
+ function createCommandContext(opts) {
221
+ let clientInstance = null;
222
+ const outputOptions = {
223
+ format: opts.format,
224
+ compact: opts.compact,
225
+ jq: opts.jq
226
+ };
227
+ return {
228
+ verbose: opts.verbose,
229
+ async getClient() {
230
+ if (clientInstance) return clientInstance;
231
+ const token = resolveToken(opts);
232
+ if (!token) {
233
+ if (opts.profile) throw new Error(`No API token found for profile "${opts.profile}". Run \`fluid login\` for that profile or provide --token <token>`);
234
+ throw new Error("No API token found. Run `fluid login` or provide --token <token>");
235
+ }
236
+ clientInstance = createFetchClient({
237
+ baseUrl: opts.baseUrl ?? process.env["FLUID_API_BASE"] ?? "https://api.fluid.app",
238
+ getAuthToken: () => token
239
+ });
240
+ return clientInstance;
241
+ },
242
+ output(data) {
243
+ const formatted = formatOutput(data, outputOptions);
244
+ process.stdout.write(formatted + "\n");
245
+ },
246
+ parseBody(raw) {
247
+ try {
248
+ return JSON.parse(raw);
249
+ } catch {
250
+ throw new Error(`Invalid JSON body: ${raw}`);
251
+ }
252
+ }
253
+ };
254
+ }
255
+ function resolveToken(opts) {
256
+ if (opts.token) return opts.token;
257
+ if (opts.profile) return getAuthToken(opts.profile);
258
+ const envToken = process.env["FLUID_TOKEN"] ?? process.env["FLUID_API_TOKEN"];
259
+ if (envToken) return envToken;
260
+ return getAuthToken();
261
+ }
262
+ //#endregion
263
+ //#region src/domain/command.ts
264
+ function createDomainCommand(name, description, register) {
265
+ const cmd = new Command(name).description(description).enablePositionalOptions(false).option("--token <token>", "API authentication token").option("--base-url <url>", "API base URL").option("--profile <name>", "Config profile name").option("--format <format>", "Output format (json|table)", "json").option("--compact", "Compact JSON output", false).option("--jq <path>", "Extract value at JSON path").option("--verbose", "Print request details to stderr", false);
266
+ let resolvedCtx = null;
267
+ function getCtx() {
268
+ if (!resolvedCtx) {
269
+ const opts = cmd.opts();
270
+ resolvedCtx = createCommandContext({
271
+ token: opts.token,
272
+ baseUrl: opts.baseUrl,
273
+ profile: opts.profile,
274
+ format: opts.format,
275
+ compact: opts.compact,
276
+ jq: opts.jq,
277
+ verbose: opts.verbose
278
+ });
279
+ }
280
+ return resolvedCtx;
281
+ }
282
+ register(cmd, {
283
+ get verbose() {
284
+ return getCtx().verbose;
285
+ },
286
+ getClient() {
287
+ return getCtx().getClient();
288
+ },
289
+ output(data) {
290
+ return getCtx().output(data);
291
+ },
292
+ parseBody(raw) {
293
+ return getCtx().parseBody(raw);
294
+ }
295
+ });
296
+ return cmd;
297
+ }
298
+ //#endregion
299
+ export { confirmMfa, createCommandContext, createDefaultConfig, createDomainCommand, failure, formatOutput, getActiveProfile, getAuthToken, getConfigDir, getConfigFilePath, getErrorMessage, isError, isFailure, isNodeError, isSuccess, listProfileNames, mapError, mapResult, readConfig, sendMfa, success, tryCatch, tryCatchAsync, unwrap, unwrapOr, updateConfig, validateToken, writeConfig };
300
+
301
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../platform/api-client-core/src/fetch-client.ts","../src/domain/output.ts","../src/domain/context.ts","../src/domain/command.ts"],"sourcesContent":["/**\n * Minimal, framework-agnostic fetch client for Fluid APIs\n * Compatible with fluid-admin patterns but usable standalone\n */\n\nexport interface FetchClientConfig {\n /**\n * Base URL for all requests (e.g., \"https://api.fluid.app/api\")\n */\n baseUrl: string;\n\n /**\n * Optional function to get auth token\n * Return null/undefined if no token available\n */\n getAuthToken?: () => string | null | Promise<string | null>;\n\n /**\n * Optional callback when 401 auth error occurs\n */\n onAuthError?: () => void;\n\n /**\n * Default headers to include in all requests\n * Example: { \"x-fluid-client\": \"admin\" }\n */\n defaultHeaders?: Record<string, string>;\n}\n\nexport interface RequestOptions {\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n headers?: Record<string, string>;\n params?: Record<string, unknown>;\n body?: unknown;\n signal?: AbortSignal;\n}\n\n/**\n * API Error class compatible with fluid-admin's ApiError\n */\nexport class ApiError extends Error {\n public readonly status: number;\n public readonly data: unknown;\n\n constructor(message: string, status: number, data?: unknown) {\n super(message);\n this.name = \"ApiError\";\n this.status = status;\n this.data = data;\n\n if (\"captureStackTrace\" in Error) {\n (\n Error as {\n captureStackTrace: (\n target: Error,\n constructor: NewableFunction,\n ) => void;\n }\n ).captureStackTrace(this, ApiError);\n }\n }\n\n toJSON(): { name: string; message: string; status: number; data: unknown } {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n data: this.data,\n };\n }\n}\n\n/**\n * Type guard for ApiError\n */\nexport function isApiError(error: unknown): error is ApiError {\n return error instanceof ApiError;\n}\n\nexport interface FetchClientInstance {\n request: <TResponse = unknown>(\n endpoint: string,\n options?: RequestOptions,\n ) => Promise<TResponse>;\n requestWithFormData: <TResponse = unknown>(\n endpoint: string,\n formData: FormData,\n options?: Omit<RequestOptions, \"body\" | \"params\"> & {\n method?: \"POST\" | \"PUT\" | \"PATCH\";\n },\n ) => Promise<TResponse>;\n get: <TResponse = unknown>(\n endpoint: string,\n params?: Record<string, unknown>,\n options?: Omit<RequestOptions, \"method\" | \"params\">,\n ) => Promise<TResponse>;\n post: <TResponse = unknown>(\n endpoint: string,\n body?: unknown,\n options?: Omit<RequestOptions, \"method\" | \"body\">,\n ) => Promise<TResponse>;\n put: <TResponse = unknown>(\n endpoint: string,\n body?: unknown,\n options?: Omit<RequestOptions, \"method\" | \"body\">,\n ) => Promise<TResponse>;\n patch: <TResponse = unknown>(\n endpoint: string,\n body?: unknown,\n options?: Omit<RequestOptions, \"method\" | \"body\">,\n ) => Promise<TResponse>;\n delete: <TResponse = unknown>(\n endpoint: string,\n options?: Omit<RequestOptions, \"method\">,\n ) => Promise<TResponse>;\n}\n\n/**\n * Creates a configured fetch client instance\n */\nexport function createFetchClient(\n config: FetchClientConfig,\n): FetchClientInstance {\n const { baseUrl, getAuthToken, onAuthError, defaultHeaders = {} } = config;\n\n /**\n * Build headers for a request\n */\n async function buildHeaders(\n customHeaders?: Record<string, string>,\n ): Promise<Record<string, string>> {\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n ...defaultHeaders,\n ...customHeaders,\n };\n\n // Add auth token if available\n if (getAuthToken) {\n const token = await getAuthToken();\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n }\n\n return headers;\n }\n\n /**\n * Join baseUrl + endpoint via string concatenation (matches fetchApi).\n * Using `new URL(endpoint, baseUrl)` would strip any path prefix from\n * baseUrl (e.g. \"/api\") when the endpoint starts with \"/\".\n */\n function joinUrl(endpoint: string): string {\n return `${baseUrl}${endpoint}`;\n }\n\n /**\n * Build URL with query parameters for GET requests\n * Compatible with fluid-admin's query param handling\n */\n function buildUrl(\n endpoint: string,\n params?: Record<string, unknown>,\n ): string {\n const fullUrl = joinUrl(endpoint);\n\n if (!params || Object.keys(params).length === 0) {\n return fullUrl;\n }\n\n const queryString = new URLSearchParams();\n\n Object.entries(params).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return; // Skip undefined/null values\n }\n\n if (Array.isArray(value)) {\n // Handle arrays like Rails expects: key[]\n value.forEach((item) => queryString.append(`${key}[]`, String(item)));\n } else if (typeof value === \"object\") {\n // Handle nested objects: key[subkey]\n Object.entries(value).forEach(([subKey, subValue]) => {\n if (subValue === undefined || subValue === null) {\n return;\n }\n\n if (Array.isArray(subValue)) {\n subValue.forEach((item) =>\n queryString.append(`${key}[${subKey}][]`, String(item)),\n );\n } else {\n queryString.append(`${key}[${subKey}]`, String(subValue));\n }\n });\n } else {\n queryString.append(key, String(value));\n }\n });\n\n const qs = queryString.toString();\n return qs ? `${fullUrl}?${qs}` : fullUrl;\n }\n\n /**\n * Shared response handler for both JSON and FormData requests.\n * Handles auth errors, non-OK responses, 204 No Content, and JSON parsing.\n */\n async function handleResponse<TResponse>(\n response: Response,\n method: string,\n _url: string,\n ): Promise<TResponse> {\n if (response.status === 401 && onAuthError) {\n onAuthError();\n }\n\n if (!response.ok) {\n // Read body as text first to avoid SyntaxError from response.json()\n // when server returns non-JSON bodies with application/json content-type.\n const errorText = await response.text().catch(() => \"\");\n const contentType = response.headers.get(\"content-type\");\n\n if (contentType?.includes(\"application/json\")) {\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(errorText);\n } catch {\n throw new ApiError(\n errorText.slice(0, 200) ||\n `${method} request failed with status ${response.status}`,\n response.status,\n null,\n );\n }\n const msg = (data.message || data.error_message) as string | undefined;\n throw new ApiError(\n msg || `${method} request failed`,\n response.status,\n data.errors || data,\n );\n } else {\n throw new ApiError(\n `${method} request failed with status ${response.status}`,\n response.status,\n null,\n );\n }\n }\n\n if (\n response.status === 204 ||\n response.headers.get(\"content-length\") === \"0\"\n ) {\n return null as TResponse;\n }\n\n const contentType = response.headers.get(\"content-type\");\n\n if (contentType?.includes(\"application/json\")) {\n try {\n const data = await response.json();\n return data as TResponse;\n } catch {\n try {\n // API declared JSON content-type but body isn't valid JSON\n const text = await response.text();\n return text as TResponse;\n } catch {\n return null as TResponse;\n }\n }\n }\n\n // Non-JSON response (text/plain, text/html, etc.)\n return null as TResponse;\n }\n\n /**\n * Main request function\n */\n async function request<TResponse = unknown>(\n endpoint: string,\n options: RequestOptions = {},\n ): Promise<TResponse> {\n const {\n method = \"GET\",\n headers: customHeaders,\n params,\n body,\n signal,\n } = options;\n\n const url = params ? buildUrl(endpoint, params) : joinUrl(endpoint);\n\n const headers = await buildHeaders(customHeaders);\n\n let response: Response;\n\n try {\n const fetchOptions: RequestInit = { method, headers };\n const serializedBody =\n body && method !== \"GET\" ? JSON.stringify(body) : null;\n if (serializedBody) fetchOptions.body = serializedBody;\n if (signal) fetchOptions.signal = signal;\n response = await fetch(url, fetchOptions);\n } catch (networkError) {\n throw new ApiError(\n `Network error: ${networkError instanceof Error ? networkError.message : \"Unknown network error\"}`,\n 0,\n null,\n );\n }\n\n return handleResponse<TResponse>(response, method, url);\n }\n\n /**\n * Request with FormData (for file uploads)\n */\n async function requestWithFormData<TResponse = unknown>(\n endpoint: string,\n formData: FormData,\n options: Omit<RequestOptions, \"body\" | \"params\"> & {\n method?: \"POST\" | \"PUT\" | \"PATCH\";\n } = {},\n ): Promise<TResponse> {\n const { method = \"POST\", headers: customHeaders, signal } = options;\n\n const url = joinUrl(endpoint);\n const headers = await buildHeaders(customHeaders);\n\n // Remove Content-Type to let browser set it with boundary\n delete headers[\"Content-Type\"];\n\n let response: Response;\n\n try {\n const fetchOptions: RequestInit = { method, headers, body: formData };\n if (signal) fetchOptions.signal = signal;\n response = await fetch(url, fetchOptions);\n } catch (networkError) {\n throw new ApiError(\n `Network error: ${networkError instanceof Error ? networkError.message : \"Unknown network error\"}`,\n 0,\n null,\n );\n }\n\n return handleResponse<TResponse>(response, method, url);\n }\n\n // Return client with convenience methods\n return {\n request: request,\n requestWithFormData: requestWithFormData,\n\n // Convenience methods for common HTTP verbs\n get: <TResponse = unknown>(\n endpoint: string,\n params?: Record<string, unknown>,\n options?: Omit<RequestOptions, \"method\" | \"params\">,\n ): Promise<TResponse> =>\n request<TResponse>(endpoint, {\n ...options,\n method: \"GET\" as const,\n ...(params && { params }),\n }),\n\n post: <TResponse = unknown>(\n endpoint: string,\n body?: unknown,\n options?: Omit<RequestOptions, \"method\" | \"body\">,\n ): Promise<TResponse> =>\n request<TResponse>(endpoint, {\n ...options,\n method: \"POST\",\n body,\n }),\n\n put: <TResponse = unknown>(\n endpoint: string,\n body?: unknown,\n options?: Omit<RequestOptions, \"method\" | \"body\">,\n ): Promise<TResponse> =>\n request<TResponse>(endpoint, {\n ...options,\n method: \"PUT\",\n body,\n }),\n\n patch: <TResponse = unknown>(\n endpoint: string,\n body?: unknown,\n options?: Omit<RequestOptions, \"method\" | \"body\">,\n ): Promise<TResponse> =>\n request<TResponse>(endpoint, {\n ...options,\n method: \"PATCH\",\n body,\n }),\n\n delete: <TResponse = unknown>(\n endpoint: string,\n options?: Omit<RequestOptions, \"method\">,\n ): Promise<TResponse> =>\n request<TResponse>(endpoint, {\n ...options,\n method: \"DELETE\",\n }),\n };\n}\n\nexport type FetchClient = FetchClientInstance;\n","import type { OutputOptions } from \"./types.js\";\n\nexport function formatOutput(data: unknown, options: OutputOptions): string {\n let result = data;\n\n if (options.jq) {\n result = extractPath(result, options.jq);\n }\n\n if (options.format === \"table\") {\n return formatTable(result);\n }\n\n if (options.compact) {\n return JSON.stringify(result);\n }\n return JSON.stringify(result, null, 2);\n}\n\nfunction extractPath(data: unknown, path: string): unknown {\n const parts = path\n .replace(/^\\.*/, \"\")\n .split(/\\.|\\[/)\n .filter(Boolean)\n .map((p) => p.replace(/\\]$/, \"\"));\n\n let current: any = data;\n for (const part of parts) {\n if (current == null) return undefined;\n current = current[part];\n }\n return current;\n}\n\nfunction formatTable(data: unknown): string {\n if (Array.isArray(data)) {\n if (data.length === 0) return \"(empty)\";\n\n if (typeof data[0] === \"object\" && data[0] !== null) {\n const keys = Object.keys(data[0]);\n const widths = keys.map((k) =>\n Math.max(k.length, ...data.map((row) => String(row[k] ?? \"\").length)),\n );\n\n const header = keys\n .map((k, i) => k.toUpperCase().padEnd(widths[i]!))\n .join(\" \");\n const separator = widths.map((w) => \"-\".repeat(w)).join(\" \");\n const rows = data.map((row) =>\n keys.map((k, i) => String(row[k] ?? \"\").padEnd(widths[i]!)).join(\" \"),\n );\n\n return [header, separator, ...rows].join(\"\\n\");\n }\n\n return data.map(String).join(\"\\n\");\n }\n\n if (typeof data === \"object\" && data !== null) {\n const entries = Object.entries(data);\n const maxKeyLen = Math.max(...entries.map(([k]) => k.length));\n return entries\n .map(([k, v]) => `${k.padEnd(maxKeyLen)} ${JSON.stringify(v)}`)\n .join(\"\\n\");\n }\n\n return String(data);\n}\n","import { createFetchClient } from \"@fluid-app/api-client-core\";\nimport type { FetchClient } from \"@fluid-app/api-client-core\";\n\nimport { getAuthToken } from \"../auth/token.js\";\nimport { formatOutput } from \"./output.js\";\nimport type { CommandContext, OutputOptions } from \"./types.js\";\n\nexport function createCommandContext(opts: {\n token?: string;\n baseUrl?: string;\n profile?: string;\n format: \"json\" | \"table\";\n compact: boolean;\n jq?: string;\n verbose: boolean;\n}): CommandContext {\n let clientInstance: FetchClient | null = null;\n\n const outputOptions: OutputOptions = {\n format: opts.format,\n compact: opts.compact,\n jq: opts.jq,\n };\n\n return {\n verbose: opts.verbose,\n\n async getClient(): Promise<FetchClient> {\n if (clientInstance) return clientInstance;\n\n const token = resolveToken(opts);\n if (!token) {\n if (opts.profile) {\n throw new Error(\n `No API token found for profile \"${opts.profile}\". Run \\`fluid login\\` for that profile or provide --token <token>`,\n );\n }\n\n throw new Error(\n \"No API token found. Run `fluid login` or provide --token <token>\",\n );\n }\n\n const baseUrl =\n opts.baseUrl ??\n process.env[\"FLUID_API_BASE\"] ??\n \"https://api.fluid.app\";\n\n clientInstance = createFetchClient({\n baseUrl,\n getAuthToken: () => token,\n });\n\n return clientInstance;\n },\n\n output(data: unknown): void {\n const formatted = formatOutput(data, outputOptions);\n process.stdout.write(formatted + \"\\n\");\n },\n\n parseBody(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n throw new Error(`Invalid JSON body: ${raw}`);\n }\n },\n };\n}\n\nfunction resolveToken(opts: {\n token?: string;\n profile?: string;\n}): string | null {\n if (opts.token) return opts.token;\n\n if (opts.profile) return getAuthToken(opts.profile);\n\n const envToken = process.env[\"FLUID_TOKEN\"] ?? process.env[\"FLUID_API_TOKEN\"];\n if (envToken) return envToken;\n\n return getAuthToken();\n}\n","import { Command } from \"commander\";\n\nimport { createCommandContext } from \"./context.js\";\nimport type { CommandContext } from \"./types.js\";\n\ntype RegisterFn = (parent: Command, ctx: CommandContext) => void;\n\nexport function createDomainCommand(\n name: string,\n description: string,\n register: RegisterFn,\n): Command {\n const cmd = new Command(name)\n .description(description)\n // Keep global domain flags usable before or after nested subcommands.\n .enablePositionalOptions(false)\n .option(\"--token <token>\", \"API authentication token\")\n .option(\"--base-url <url>\", \"API base URL\")\n .option(\"--profile <name>\", \"Config profile name\")\n .option(\"--format <format>\", \"Output format (json|table)\", \"json\")\n .option(\"--compact\", \"Compact JSON output\", false)\n .option(\"--jq <path>\", \"Extract value at JSON path\")\n .option(\"--verbose\", \"Print request details to stderr\", false);\n\n let resolvedCtx: CommandContext | null = null;\n\n function getCtx(): CommandContext {\n if (!resolvedCtx) {\n const opts = cmd.opts();\n resolvedCtx = createCommandContext({\n token: opts.token,\n baseUrl: opts.baseUrl,\n profile: opts.profile,\n format: opts.format as \"json\" | \"table\",\n compact: opts.compact,\n jq: opts.jq,\n verbose: opts.verbose,\n });\n }\n return resolvedCtx;\n }\n\n const lazyCtx: CommandContext = {\n get verbose() {\n return getCtx().verbose;\n },\n getClient() {\n return getCtx().getClient();\n },\n output(data: unknown) {\n return getCtx().output(data);\n },\n parseBody(raw: string) {\n return getCtx().parseBody(raw);\n },\n };\n\n register(cmd, lazyCtx);\n\n return cmd;\n}\n"],"mappings":"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"}