@prospera/eprospera-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.
- package/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +140 -0
- package/bin/eprospera.js +3 -0
- package/cli.ocs.yaml +406 -0
- package/dist/bundle/eprospera.mjs +28349 -0
- package/dist/completions/eprospera.bash +7 -0
- package/dist/completions/eprospera.fish +2 -0
- package/dist/completions/eprospera.ps1 +7 -0
- package/dist/completions/eprospera.zsh +4 -0
- package/dist/src/api/client.d.ts +29 -0
- package/dist/src/api/client.js +131 -0
- package/dist/src/api/errors.d.ts +11 -0
- package/dist/src/api/errors.js +125 -0
- package/dist/src/api/generated.d.ts +1159 -0
- package/dist/src/api/generated.js +6 -0
- package/dist/src/commands/application/create.d.ts +5 -0
- package/dist/src/commands/application/create.js +62 -0
- package/dist/src/commands/application/get.d.ts +2 -0
- package/dist/src/commands/application/get.js +11 -0
- package/dist/src/commands/application/list.d.ts +2 -0
- package/dist/src/commands/application/list.js +8 -0
- package/dist/src/commands/application/pay.d.ts +5 -0
- package/dist/src/commands/application/pay.js +27 -0
- package/dist/src/commands/application/watch.d.ts +7 -0
- package/dist/src/commands/application/watch.js +42 -0
- package/dist/src/commands/auth/login.d.ts +7 -0
- package/dist/src/commands/auth/login.js +60 -0
- package/dist/src/commands/auth/logout.d.ts +2 -0
- package/dist/src/commands/auth/logout.js +14 -0
- package/dist/src/commands/auth/whoami.d.ts +2 -0
- package/dist/src/commands/auth/whoami.js +19 -0
- package/dist/src/commands/completion.d.ts +3 -0
- package/dist/src/commands/completion.js +80 -0
- package/dist/src/commands/config/get.d.ts +2 -0
- package/dist/src/commands/config/get.js +9 -0
- package/dist/src/commands/config/list.d.ts +2 -0
- package/dist/src/commands/config/list.js +7 -0
- package/dist/src/commands/config/set.d.ts +2 -0
- package/dist/src/commands/config/set.js +9 -0
- package/dist/src/commands/config/unset.d.ts +2 -0
- package/dist/src/commands/config/unset.js +9 -0
- package/dist/src/commands/entity/documents.d.ts +2 -0
- package/dist/src/commands/entity/documents.js +11 -0
- package/dist/src/commands/entity/get.d.ts +2 -0
- package/dist/src/commands/entity/get.js +11 -0
- package/dist/src/commands/entity/search.d.ts +2 -0
- package/dist/src/commands/entity/search.js +17 -0
- package/dist/src/commands/entity/verify.d.ts +2 -0
- package/dist/src/commands/entity/verify.js +9 -0
- package/dist/src/commands/files.d.ts +2 -0
- package/dist/src/commands/files.js +24 -0
- package/dist/src/commands/me/id-verification.d.ts +2 -0
- package/dist/src/commands/me/id-verification.js +8 -0
- package/dist/src/commands/me/profile.d.ts +2 -0
- package/dist/src/commands/me/profile.js +8 -0
- package/dist/src/commands/me/residency.d.ts +2 -0
- package/dist/src/commands/me/residency.js +8 -0
- package/dist/src/commands/runtime.d.ts +56 -0
- package/dist/src/commands/runtime.js +101 -0
- package/dist/src/commands/schema.d.ts +2 -0
- package/dist/src/commands/schema.js +13 -0
- package/dist/src/config/store.d.ts +14 -0
- package/dist/src/config/store.js +99 -0
- package/dist/src/credentials/resolve.d.ts +15 -0
- package/dist/src/credentials/resolve.js +63 -0
- package/dist/src/credentials/store.d.ts +22 -0
- package/dist/src/credentials/store.js +184 -0
- package/dist/src/credentials/types.d.ts +15 -0
- package/dist/src/credentials/types.js +5 -0
- package/dist/src/errors.d.ts +39 -0
- package/dist/src/errors.js +38 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.js +244 -0
- package/dist/src/output/format.d.ts +27 -0
- package/dist/src/output/format.js +126 -0
- package/dist/src/output/table.d.ts +5 -0
- package/dist/src/output/table.js +124 -0
- package/dist/src/output/tty.d.ts +26 -0
- package/dist/src/output/tty.js +41 -0
- package/dist/src/polling/watch.d.ts +19 -0
- package/dist/src/polling/watch.js +86 -0
- package/dist/src/prompts/confirm.d.ts +2 -0
- package/dist/src/prompts/confirm.js +19 -0
- package/dist/src/scopes/check.d.ts +17 -0
- package/dist/src/scopes/check.js +64 -0
- package/dist/src/scopes/map.d.ts +81 -0
- package/dist/src/scopes/map.js +76 -0
- package/dist/src/version.d.ts +1 -0
- package/dist/src/version.js +35 -0
- package/package.json +70 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Generated by scripts/gen-completions.ts.
|
|
2
|
+
_eprospera_completions() {
|
|
3
|
+
local cur
|
|
4
|
+
cur="${COMP_WORDS[COMP_CWORD]}"
|
|
5
|
+
COMPREPLY=( $(compgen -W 'eprospera entity verify search get documents application list create pay watch me profile residency id-verification auth login whoami logout config set unset completion bash zsh fish powershell schema --json --raw --fields --quiet --yes -y --api-key --dry-run --help -h --version --no-auto-json --skip-scope-check --file --coupon --timeout --initial-interval --max-interval --agent-key --standard-key --scopes' -- "$cur") )
|
|
6
|
+
}
|
|
7
|
+
complete -F _eprospera_completions eprospera
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
# Generated by scripts/gen-completions.ts.
|
|
2
|
+
complete -c eprospera -f -a 'eprospera entity verify search get documents application list create pay watch me profile residency id-verification auth login whoami logout config set unset completion bash zsh fish powershell schema --json --raw --fields --quiet --yes -y --api-key --dry-run --help -h --version --no-auto-json --skip-scope-check --file --coupon --timeout --initial-interval --max-interval --agent-key --standard-key --scopes'
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Generated by scripts/gen-completions.ts.
|
|
2
|
+
Register-ArgumentCompleter -Native -CommandName eprospera -ScriptBlock {
|
|
3
|
+
param($wordToComplete)
|
|
4
|
+
'eprospera', 'entity', 'verify', 'search', 'get', 'documents', 'application', 'list', 'create', 'pay', 'watch', 'me', 'profile', 'residency', 'id-verification', 'auth', 'login', 'whoami', 'logout', 'config', 'set', 'unset', 'completion', 'bash', 'zsh', 'fish', 'powershell', 'schema', '--json', '--raw', '--fields', '--quiet', '--yes', '-y', '--api-key', '--dry-run', '--help', '-h', '--version', '--no-auto-json', '--skip-scope-check', '--file', '--coupon', '--timeout', '--initial-interval', '--max-interval', '--agent-key', '--standard-key', '--scopes' | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
|
|
5
|
+
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
|
6
|
+
}
|
|
7
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
#compdef eprospera
|
|
2
|
+
# Generated by scripts/gen-completions.ts.
|
|
3
|
+
local -a commands=("eprospera" "entity" "verify" "search" "get" "documents" "application" "list" "create" "pay" "watch" "me" "profile" "residency" "id-verification" "auth" "login" "whoami" "logout" "config" "set" "unset" "completion" "bash" "zsh" "fish" "powershell" "schema" "--json" "--raw" "--fields" "--quiet" "--yes" "-y" "--api-key" "--dry-run" "--help" "-h" "--version" "--no-auto-json" "--skip-scope-check" "--file" "--coupon" "--timeout" "--initial-interval" "--max-interval" "--agent-key" "--standard-key" "--scopes")
|
|
4
|
+
_describe 'eprospera command' commands
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type Client } from "openapi-fetch";
|
|
2
|
+
import type { paths } from "./generated.js";
|
|
3
|
+
export declare const PRODUCTION_BASE_URL = "https://portal.eprospera.com";
|
|
4
|
+
export declare const STAGING_BASE_URL = "https://staging-portal.eprospera.com";
|
|
5
|
+
export declare const DEFAULT_MAX_RETRIES = 3;
|
|
6
|
+
export type TokenProvider = string | (() => string | Promise<string | undefined>) | undefined;
|
|
7
|
+
export type RetryOptions = {
|
|
8
|
+
maxRetries?: number;
|
|
9
|
+
baseDelayMs?: number;
|
|
10
|
+
maxDelayMs?: number;
|
|
11
|
+
random?: () => number;
|
|
12
|
+
sleep?: (ms: number) => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
export type ApiClientOptions = {
|
|
15
|
+
baseUrl?: string;
|
|
16
|
+
env?: NodeJS.ProcessEnv;
|
|
17
|
+
token?: TokenProvider;
|
|
18
|
+
fetch?: (input: Request) => Promise<Response>;
|
|
19
|
+
idempotencyKey?: () => string;
|
|
20
|
+
retry?: RetryOptions;
|
|
21
|
+
};
|
|
22
|
+
export type EProsperaApiClient = {
|
|
23
|
+
baseUrl: string;
|
|
24
|
+
raw: Client<paths>;
|
|
25
|
+
};
|
|
26
|
+
export declare function resolveBaseUrl(env?: NodeJS.ProcessEnv): string;
|
|
27
|
+
export declare function createApiClient(options?: ApiClientOptions): EProsperaApiClient;
|
|
28
|
+
export declare function parseRetryAfter(value: string | null): number | undefined;
|
|
29
|
+
export declare function computeRetryDelayMs(attempt: number, response: Response, options: Required<Pick<RetryOptions, "baseDelayMs" | "maxDelayMs" | "random">>): number;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import createClient from "openapi-fetch";
|
|
3
|
+
import { apiErrorFromResponse, networkErrorFromCause } from "./errors.js";
|
|
4
|
+
export const PRODUCTION_BASE_URL = "https://portal.eprospera.com";
|
|
5
|
+
export const STAGING_BASE_URL = "https://staging-portal.eprospera.com";
|
|
6
|
+
export const DEFAULT_MAX_RETRIES = 3;
|
|
7
|
+
export function resolveBaseUrl(env = process.env) {
|
|
8
|
+
const explicitBaseUrl = env.EPROSPERA_BASE_URL?.trim();
|
|
9
|
+
if (explicitBaseUrl) {
|
|
10
|
+
return trimTrailingSlash(explicitBaseUrl);
|
|
11
|
+
}
|
|
12
|
+
if (env.EPROSPERA_ENV === "staging") {
|
|
13
|
+
return STAGING_BASE_URL;
|
|
14
|
+
}
|
|
15
|
+
return PRODUCTION_BASE_URL;
|
|
16
|
+
}
|
|
17
|
+
export function createApiClient(options = {}) {
|
|
18
|
+
const baseUrl = trimTrailingSlash(options.baseUrl ?? resolveBaseUrl(options.env));
|
|
19
|
+
const fetchWithRetry = createRetryingFetch(options.fetch ?? globalThis.fetch, options.retry);
|
|
20
|
+
const raw = createClient({
|
|
21
|
+
baseUrl,
|
|
22
|
+
fetch: fetchWithRetry,
|
|
23
|
+
});
|
|
24
|
+
raw.use(createAuthAndIdempotencyMiddleware({
|
|
25
|
+
token: options.token,
|
|
26
|
+
idempotencyKey: options.idempotencyKey ?? randomUUID,
|
|
27
|
+
}), createErrorMiddleware());
|
|
28
|
+
return { baseUrl, raw };
|
|
29
|
+
}
|
|
30
|
+
export function parseRetryAfter(value) {
|
|
31
|
+
if (!value) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
const seconds = Number(value);
|
|
35
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
36
|
+
return seconds * 1000;
|
|
37
|
+
}
|
|
38
|
+
const date = Date.parse(value);
|
|
39
|
+
if (!Number.isNaN(date)) {
|
|
40
|
+
return Math.max(0, date - Date.now());
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
export function computeRetryDelayMs(attempt, response, options) {
|
|
45
|
+
const retryAfterMs = parseRetryAfter(response.headers.get("Retry-After"));
|
|
46
|
+
if (retryAfterMs !== undefined) {
|
|
47
|
+
return retryAfterMs;
|
|
48
|
+
}
|
|
49
|
+
const cap = Math.min(options.maxDelayMs, options.baseDelayMs * 2 ** attempt);
|
|
50
|
+
return Math.floor(options.random() * cap);
|
|
51
|
+
}
|
|
52
|
+
function createAuthAndIdempotencyMiddleware(options) {
|
|
53
|
+
return {
|
|
54
|
+
async onRequest({ request }) {
|
|
55
|
+
const headers = new Headers(request.headers);
|
|
56
|
+
const token = await resolveToken(options.token);
|
|
57
|
+
if (token) {
|
|
58
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
59
|
+
}
|
|
60
|
+
if (requiresIdempotencyKey(request) && !headers.has("Idempotency-Key")) {
|
|
61
|
+
headers.set("Idempotency-Key", options.idempotencyKey());
|
|
62
|
+
}
|
|
63
|
+
return new Request(request, { headers });
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function createErrorMiddleware() {
|
|
68
|
+
return {
|
|
69
|
+
async onResponse({ response }) {
|
|
70
|
+
if (response.ok) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
throw apiErrorFromResponse(response, await readResponseBody(response.clone()));
|
|
74
|
+
},
|
|
75
|
+
onError({ error }) {
|
|
76
|
+
return networkErrorFromCause(error);
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function createRetryingFetch(fetchImpl, retry = {}) {
|
|
81
|
+
const retryOptions = {
|
|
82
|
+
maxRetries: retry.maxRetries ?? DEFAULT_MAX_RETRIES,
|
|
83
|
+
baseDelayMs: retry.baseDelayMs ?? 250,
|
|
84
|
+
maxDelayMs: retry.maxDelayMs ?? 4_000,
|
|
85
|
+
random: retry.random ?? Math.random,
|
|
86
|
+
sleep: retry.sleep ?? sleep,
|
|
87
|
+
};
|
|
88
|
+
return async (request) => {
|
|
89
|
+
for (let attempt = 0;; attempt += 1) {
|
|
90
|
+
const response = await fetchImpl(request.clone());
|
|
91
|
+
if (!shouldRetry(response) || attempt >= retryOptions.maxRetries) {
|
|
92
|
+
return response;
|
|
93
|
+
}
|
|
94
|
+
await retryOptions.sleep(computeRetryDelayMs(attempt, response, retryOptions));
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async function readResponseBody(response) {
|
|
99
|
+
const text = await response.text();
|
|
100
|
+
if (!text) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
return JSON.parse(text);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return text;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async function resolveToken(provider) {
|
|
111
|
+
if (typeof provider === "function") {
|
|
112
|
+
return provider();
|
|
113
|
+
}
|
|
114
|
+
return provider;
|
|
115
|
+
}
|
|
116
|
+
function shouldRetry(response) {
|
|
117
|
+
return response.status === 429 || response.status >= 500;
|
|
118
|
+
}
|
|
119
|
+
function requiresIdempotencyKey(request) {
|
|
120
|
+
if (request.method !== "POST") {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
return new URL(request.url).pathname.startsWith("/api/v1/legal_entity_applications");
|
|
124
|
+
}
|
|
125
|
+
function trimTrailingSlash(value) {
|
|
126
|
+
return value.replace(/\/+$/, "");
|
|
127
|
+
}
|
|
128
|
+
function sleep(ms) {
|
|
129
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ExitCode, ExitError } from "../errors.js";
|
|
2
|
+
export type UpstreamErrorBody = {
|
|
3
|
+
error?: unknown;
|
|
4
|
+
error_description?: string;
|
|
5
|
+
errorDescription?: string;
|
|
6
|
+
message?: string;
|
|
7
|
+
details?: unknown;
|
|
8
|
+
};
|
|
9
|
+
export declare function mapHttpStatusToExitCode(status: number): ExitCode;
|
|
10
|
+
export declare function apiErrorFromResponse(response: Response, body: unknown): ExitError;
|
|
11
|
+
export declare function networkErrorFromCause(error: unknown): ExitError;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { ExitCodes, ExitError } from "../errors.js";
|
|
2
|
+
export function mapHttpStatusToExitCode(status) {
|
|
3
|
+
if (status === 400 || status === 422) {
|
|
4
|
+
return ExitCodes.Validation;
|
|
5
|
+
}
|
|
6
|
+
if (status === 401) {
|
|
7
|
+
return ExitCodes.Authentication;
|
|
8
|
+
}
|
|
9
|
+
if (status === 403) {
|
|
10
|
+
return ExitCodes.Authorization;
|
|
11
|
+
}
|
|
12
|
+
if (status === 404) {
|
|
13
|
+
return ExitCodes.NotFound;
|
|
14
|
+
}
|
|
15
|
+
if (status === 409) {
|
|
16
|
+
return ExitCodes.Conflict;
|
|
17
|
+
}
|
|
18
|
+
if (status === 408 || status === 504) {
|
|
19
|
+
return ExitCodes.Timeout;
|
|
20
|
+
}
|
|
21
|
+
if (status === 429) {
|
|
22
|
+
return ExitCodes.RateLimit;
|
|
23
|
+
}
|
|
24
|
+
return ExitCodes.Generic;
|
|
25
|
+
}
|
|
26
|
+
export function apiErrorFromResponse(response, body) {
|
|
27
|
+
const upstream = normalizeUpstreamError(body);
|
|
28
|
+
return new ExitError({
|
|
29
|
+
code: upstream.code ?? defaultCodeForStatus(response.status),
|
|
30
|
+
message: upstream.message ?? defaultMessageForStatus(response.status),
|
|
31
|
+
exitCode: mapHttpStatusToExitCode(response.status),
|
|
32
|
+
httpStatus: response.status,
|
|
33
|
+
details: upstream.details ?? null,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export function networkErrorFromCause(error) {
|
|
37
|
+
const message = error instanceof Error ? error.message : "Network request failed";
|
|
38
|
+
const isTimeout = error instanceof DOMException
|
|
39
|
+
? error.name === "AbortError" || error.name === "TimeoutError"
|
|
40
|
+
: error instanceof Error && error.name === "AbortError";
|
|
41
|
+
return new ExitError({
|
|
42
|
+
code: isTimeout ? "TIMEOUT" : "NETWORK_ERROR",
|
|
43
|
+
message,
|
|
44
|
+
exitCode: isTimeout ? ExitCodes.Timeout : ExitCodes.Generic,
|
|
45
|
+
cause: error,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function normalizeUpstreamError(body) {
|
|
49
|
+
if (!isRecord(body)) {
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
52
|
+
const { error } = body;
|
|
53
|
+
if (isRecord(error)) {
|
|
54
|
+
return {
|
|
55
|
+
code: stringValue(error.code) ?? stringValue(error.error),
|
|
56
|
+
message: stringValue(error.message) ??
|
|
57
|
+
stringValue(error.error_description) ??
|
|
58
|
+
stringValue(error.errorDescription),
|
|
59
|
+
details: "details" in error ? error.details : body.details,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
code: stringValue(error),
|
|
64
|
+
message: stringValue(body.error_description) ??
|
|
65
|
+
stringValue(body.errorDescription) ??
|
|
66
|
+
stringValue(body.message) ??
|
|
67
|
+
stringValue(error),
|
|
68
|
+
details: body.details,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function defaultCodeForStatus(status) {
|
|
72
|
+
if (status === 400 || status === 422) {
|
|
73
|
+
return "VALIDATION_ERROR";
|
|
74
|
+
}
|
|
75
|
+
if (status === 401) {
|
|
76
|
+
return "UNAUTHENTICATED";
|
|
77
|
+
}
|
|
78
|
+
if (status === 403) {
|
|
79
|
+
return "FORBIDDEN";
|
|
80
|
+
}
|
|
81
|
+
if (status === 404) {
|
|
82
|
+
return "NOT_FOUND";
|
|
83
|
+
}
|
|
84
|
+
if (status === 409) {
|
|
85
|
+
return "CONFLICT";
|
|
86
|
+
}
|
|
87
|
+
if (status === 429) {
|
|
88
|
+
return "RATE_LIMITED";
|
|
89
|
+
}
|
|
90
|
+
if (status === 408 || status === 504) {
|
|
91
|
+
return "TIMEOUT";
|
|
92
|
+
}
|
|
93
|
+
return "API_ERROR";
|
|
94
|
+
}
|
|
95
|
+
function defaultMessageForStatus(status) {
|
|
96
|
+
if (status === 400 || status === 422) {
|
|
97
|
+
return "The API rejected the request as invalid.";
|
|
98
|
+
}
|
|
99
|
+
if (status === 401) {
|
|
100
|
+
return "Authentication failed.";
|
|
101
|
+
}
|
|
102
|
+
if (status === 403) {
|
|
103
|
+
return "The credential is not authorized for this operation.";
|
|
104
|
+
}
|
|
105
|
+
if (status === 404) {
|
|
106
|
+
return "The requested resource was not found.";
|
|
107
|
+
}
|
|
108
|
+
if (status === 409) {
|
|
109
|
+
return "The request conflicts with the current resource state.";
|
|
110
|
+
}
|
|
111
|
+
if (status === 429) {
|
|
112
|
+
return "The API rate limit was exceeded.";
|
|
113
|
+
}
|
|
114
|
+
if (status === 408 || status === 504) {
|
|
115
|
+
return "The request timed out.";
|
|
116
|
+
}
|
|
117
|
+
return `The API returned HTTP ${status}.`;
|
|
118
|
+
}
|
|
119
|
+
function stringValue(value) {
|
|
120
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
121
|
+
}
|
|
122
|
+
function isRecord(value) {
|
|
123
|
+
return typeof value === "object" && value !== null;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=errors.js.map
|