apiblaze 0.19.17 → 0.19.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/index.js +49 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,6 +33,10 @@ npx apiblaze apichat --openapi https://apiblaze.com/pokeapi_openapi.yaml
|
|
|
33
33
|
# Make an API in one line — no account needed (prints a claim URL)
|
|
34
34
|
npx apiblaze create --target https://api.example.com
|
|
35
35
|
|
|
36
|
+
# Or build it straight from an OpenAPI spec — a URL or a local file.
|
|
37
|
+
# The routes, the API version and one environment per `servers` entry all come from the spec.
|
|
38
|
+
npx apiblaze create --openapi https://petstore3.swagger.io/api/v3/openapi.json
|
|
39
|
+
|
|
36
40
|
# Configure how your backend is accessed through the proxy
|
|
37
41
|
npx apiblaze config
|
|
38
42
|
|
|
@@ -114,6 +118,7 @@ Every chat turn shows its cost.
|
|
|
114
118
|
| Command | What it does |
|
|
115
119
|
|---|---|
|
|
116
120
|
| `apiblaze create --target <url>` | Make an API from a backend (no account needed) |
|
|
121
|
+
| `apiblaze create --openapi <file\|url>` | Make an API from an OpenAPI spec — a local file or a spec URL (`--openapispec` is the same flag) |
|
|
117
122
|
| `apiblaze sidecar` | Route a Next.js app's external `fetch()` calls through APIblaze (one command) |
|
|
118
123
|
| `apiblaze dev [port]` | Put your localhost behind a public URL |
|
|
119
124
|
| `apiblaze login` / `logout` | Sign in / out (logout asks producer or consumer) |
|
package/dist/index.js
CHANGED
|
@@ -932,7 +932,7 @@ var import_commander = require("commander");
|
|
|
932
932
|
var import_chalk44 = __toESM(require("chalk"));
|
|
933
933
|
|
|
934
934
|
// package.json
|
|
935
|
-
var version = "0.19.
|
|
935
|
+
var version = "0.19.19";
|
|
936
936
|
|
|
937
937
|
// src/index.ts
|
|
938
938
|
init_types();
|
|
@@ -1689,6 +1689,9 @@ async function probeLocalServer(port) {
|
|
|
1689
1689
|
}
|
|
1690
1690
|
}
|
|
1691
1691
|
async function runDev(options) {
|
|
1692
|
+
if (options.newSession && !(loadCredentials() && Date.now() < loadCredentials().expiresAt)) {
|
|
1693
|
+
clearAnonCred();
|
|
1694
|
+
}
|
|
1692
1695
|
let auth = resolveDevAuth();
|
|
1693
1696
|
let keyAuth = auth.mode === "key" ? { apiKey: auth.apiKey } : void 0;
|
|
1694
1697
|
let teamId = "";
|
|
@@ -1933,6 +1936,7 @@ ${projects.length} project${projects.length === 1 ? "" : "s"}`));
|
|
|
1933
1936
|
|
|
1934
1937
|
// src/commands/create.ts
|
|
1935
1938
|
var import_fs2 = __toESM(require("fs"));
|
|
1939
|
+
var import_yaml = require("yaml");
|
|
1936
1940
|
var import_chalk10 = __toESM(require("chalk"));
|
|
1937
1941
|
var import_ora5 = __toESM(require("ora"));
|
|
1938
1942
|
init_auth();
|
|
@@ -1948,6 +1952,41 @@ function isHttpUrl(s) {
|
|
|
1948
1952
|
return false;
|
|
1949
1953
|
}
|
|
1950
1954
|
}
|
|
1955
|
+
async function loadOpenapiSource(ref) {
|
|
1956
|
+
let text;
|
|
1957
|
+
if (isHttpUrl(ref)) {
|
|
1958
|
+
const res = await fetch(ref.trim(), {
|
|
1959
|
+
headers: { accept: "application/json, application/yaml, text/yaml, */*" }
|
|
1960
|
+
}).catch((err) => fail(`Could not fetch the OpenAPI spec at ${ref} \u2014 ${err.message}`));
|
|
1961
|
+
if (!res.ok) fail(`Could not fetch the OpenAPI spec at ${ref} (HTTP ${res.status}).`);
|
|
1962
|
+
text = await res.text();
|
|
1963
|
+
} else {
|
|
1964
|
+
try {
|
|
1965
|
+
text = import_fs2.default.readFileSync(ref, "utf8");
|
|
1966
|
+
} catch {
|
|
1967
|
+
fail(`Cannot read the OpenAPI spec "${ref}" \u2014 it is not a readable file, and not an http(s) URL.`);
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
if (!text.trim()) fail(`The OpenAPI spec is empty: ${ref}`);
|
|
1971
|
+
let parsed;
|
|
1972
|
+
try {
|
|
1973
|
+
parsed = text.trimStart().startsWith("{") ? JSON.parse(text) : (0, import_yaml.parse)(text);
|
|
1974
|
+
} catch (err) {
|
|
1975
|
+
fail(`Could not parse the OpenAPI spec at ${ref} as JSON or YAML \u2014 ${err.message}`);
|
|
1976
|
+
}
|
|
1977
|
+
const doc = parsed;
|
|
1978
|
+
if (!doc || typeof doc !== "object") {
|
|
1979
|
+
fail(`${ref} is not an OpenAPI/Swagger document.
|
|
1980
|
+
If that link opens a web page, use the raw file URL instead.`);
|
|
1981
|
+
}
|
|
1982
|
+
if (typeof doc.openapi !== "string" && typeof doc.swagger !== "string") {
|
|
1983
|
+
fail(
|
|
1984
|
+
`${ref} has no "openapi" or "swagger" version field, so it is not a usable API description.
|
|
1985
|
+
If the file looks right otherwise, check its first line \u2014 the copy at that URL may be damaged.`
|
|
1986
|
+
);
|
|
1987
|
+
}
|
|
1988
|
+
return text;
|
|
1989
|
+
}
|
|
1951
1990
|
function stripTenantFromPortal(devPortal) {
|
|
1952
1991
|
try {
|
|
1953
1992
|
const u = new URL(devPortal);
|
|
@@ -2056,12 +2095,7 @@ async function runCreate(opts = {}) {
|
|
|
2056
2095
|
let openapiContent = null;
|
|
2057
2096
|
if (opts.openapi !== void 0) {
|
|
2058
2097
|
if (opts.target !== void 0) fail("Provide only one of --target or --openapi.");
|
|
2059
|
-
|
|
2060
|
-
openapiContent = import_fs2.default.readFileSync(opts.openapi, "utf8");
|
|
2061
|
-
} catch {
|
|
2062
|
-
fail(`Cannot read --openapi file: ${opts.openapi}`);
|
|
2063
|
-
}
|
|
2064
|
-
if (!openapiContent || !openapiContent.trim()) fail(`--openapi file is empty: ${opts.openapi}`);
|
|
2098
|
+
openapiContent = await loadOpenapiSource(opts.openapi);
|
|
2065
2099
|
}
|
|
2066
2100
|
let targetUrl = "";
|
|
2067
2101
|
if (openapiContent) {
|
|
@@ -2186,11 +2220,7 @@ async function runAnonymousCreate(opts) {
|
|
|
2186
2220
|
fail("Proxy name must be at least 3 characters (letters and digits only).");
|
|
2187
2221
|
}
|
|
2188
2222
|
if (opts.openapi !== void 0) {
|
|
2189
|
-
|
|
2190
|
-
body.openapi = import_fs2.default.readFileSync(opts.openapi, "utf8");
|
|
2191
|
-
} catch {
|
|
2192
|
-
fail(`Cannot read --openapi file: ${opts.openapi}`);
|
|
2193
|
-
}
|
|
2223
|
+
body.openapi = await loadOpenapiSource(opts.openapi);
|
|
2194
2224
|
}
|
|
2195
2225
|
if (opts.target && !isHttpUrl(opts.target)) fail("--target must be a valid http(s) URL.");
|
|
2196
2226
|
let target = opts.target?.trim() || (typeof body.target === "string" ? body.target : "") || (typeof body.target_url === "string" ? body.target_url : "");
|
|
@@ -5740,7 +5770,7 @@ var path6 = __toESM(require("path"));
|
|
|
5740
5770
|
var crypto2 = __toESM(require("crypto"));
|
|
5741
5771
|
var import_chalk39 = __toESM(require("chalk"));
|
|
5742
5772
|
var import_ora21 = __toESM(require("ora"));
|
|
5743
|
-
var
|
|
5773
|
+
var import_yaml2 = require("yaml");
|
|
5744
5774
|
init_auth();
|
|
5745
5775
|
init_anon_cred();
|
|
5746
5776
|
init_api();
|
|
@@ -5843,7 +5873,7 @@ function parseSpec(text) {
|
|
|
5843
5873
|
parsed = JSON.parse(text);
|
|
5844
5874
|
} catch {
|
|
5845
5875
|
try {
|
|
5846
|
-
parsed = (0,
|
|
5876
|
+
parsed = (0, import_yaml2.parse)(text);
|
|
5847
5877
|
} catch {
|
|
5848
5878
|
fail4("Could not parse the spec as JSON or YAML.");
|
|
5849
5879
|
}
|
|
@@ -7467,9 +7497,9 @@ program.command("login").description("Authenticate with APIblaze").option("--tea
|
|
|
7467
7497
|
process.exit(1);
|
|
7468
7498
|
}
|
|
7469
7499
|
});
|
|
7470
|
-
program.command("create").description("Create a new API proxy (no login needed \u2014 without auth it creates an anonymous proxy and prints a claim URL)").option("--name <name>", "Proxy name (becomes <name>.abz.run)").option("--target <url>", "Target URL to forward requests to").option("--openapi <file>", "Create FROM an OpenAPI
|
|
7500
|
+
program.command("create").description("Create a new API proxy (no login needed \u2014 without auth it creates an anonymous proxy and prints a claim URL)").option("--name <name>", "Proxy name (becomes <name>.abz.run)").option("--target <url>", "Target URL to forward requests to").option("--openapi <file|url>", "Create FROM an OpenAPI spec instead of --target \u2014 a local file or a URL (e.g. https://pokeapi.co/openapi.yaml). Routes, API version and environments (one per `servers` entry) all come from the spec").option("--openapispec <file|url>", "Alias for --openapi").option("--team <id|name>", "Team to create under (defaults to your active team)").option("--auth <type>", "Auth type: api_key | none | oauth", "api_key").option("--identified", "Require every call to identify its end user (X-End-User-Id or a login token); unattributed calls are rejected").option("--iam", "Turn IAM on for the proxy's tenant so users & groups apply to identified calls").option("--apiversion <version>", "API version to create (e.g. 2.0.0). Creating a new version of a proxy you own adds a version to the existing project.").option("--tenant <slug>", "Tenant to attach the proxy to (created if new). Omitted \u2192 your team's most-recently-used tenant.").option("--product <slug>", "Product tag to group this project under in the portal (team-scoped; anonymous create). Defaults to your team's existing/placeholder tag.").option("--display-name <name>", "Human-friendly display name").option("--subdomain <slug>", "Explicit subdomain (defaults to --name)").option("--config <file>", "JSON file with the full request body (anonymous create): requests_auth, login providers + client/server token types, scopes, callback URLs, etc. See apiblaze_anonymous.yaml. Flags override its fields.").option("-y, --yes", "Skip the confirmation prompt").option("--new-session", "Start a fresh anonymous session (do not group with prior anonymous creates)").option("--json", "Output machine-readable JSON (non-interactive)").action(async (opts) => {
|
|
7471
7501
|
try {
|
|
7472
|
-
await runCreate(opts);
|
|
7502
|
+
await runCreate({ ...opts, openapi: opts.openapi ?? opts.openapispec });
|
|
7473
7503
|
} catch (err) {
|
|
7474
7504
|
await printError(err);
|
|
7475
7505
|
process.exit(1);
|
|
@@ -7493,14 +7523,14 @@ withSetupOptions(sidecar.command("setup").description("Wire a Next.js app to rou
|
|
|
7493
7523
|
sidecar.command("approve").description("Route an origin through APIblaze (creates its proxy)").argument("<origin>", "Origin, e.g. api.stripe.com").option("--team <id|name>", "Team (defaults to active team)").option("--json", "Machine-readable output").action(action((origin, opts) => runOriginsApprove(origin, opts)));
|
|
7494
7524
|
sidecar.command("deny").description("Dismiss a candidate origin so it stops being suggested").argument("<origin>", "Origin, e.g. sentry.io").option("--team <id|name>", "Team (defaults to active team)").action(action((origin, opts) => runOriginsDeny(origin, opts)));
|
|
7495
7525
|
sidecar.command("remove").description("Un-route an approved origin (deletes its proxy; the app goes direct again)").argument("<origin>", "Origin, e.g. api.stripe.com").option("--team <id|name>", "Team (defaults to active team)").action(action((origin, opts) => runOriginsRemove(origin, opts)));
|
|
7496
|
-
program.command("dev").description("Put your localhost behind a public URL (dev tunnel)").argument("[port]", "Local port to tunnel (positional; overrides --port)").option("-p, --port <number>", "Local port to tunnel", "3000").option("--project <nameOrId>", "Tunnel this specific project (skips the picker \u2014 for scripts)").option("-y, --yes", "Skip confirmation prompts (non-interactive)").option("-o, --capture-file <path>", "Stream full request/response traffic to a file (JSON lines)").action(async (port, opts) => {
|
|
7526
|
+
program.command("dev").description("Put your localhost behind a public URL (dev tunnel)").argument("[port]", "Local port to tunnel (positional; overrides --port)").option("-p, --port <number>", "Local port to tunnel", "3000").option("--project <nameOrId>", "Tunnel this specific project (skips the picker \u2014 for scripts)").option("-y, --yes", "Skip confirmation prompts (non-interactive)").option("-o, --capture-file <path>", "Stream full request/response traffic to a file (JSON lines)").option("--new-session", "Logged-out only: start a fresh anonymous workspace instead of reusing this machine's (each run = a throwaway proxy)").action(async (port, opts) => {
|
|
7497
7527
|
try {
|
|
7498
7528
|
const resolved = parseInt(port ?? opts.port, 10);
|
|
7499
7529
|
if (Number.isNaN(resolved)) {
|
|
7500
7530
|
console.error(import_chalk44.default.red(`Invalid port: ${port ?? opts.port}`));
|
|
7501
7531
|
process.exit(1);
|
|
7502
7532
|
}
|
|
7503
|
-
await runDev({ port: resolved, project: opts.project, yes: opts.yes, captureFile: opts.captureFile });
|
|
7533
|
+
await runDev({ port: resolved, project: opts.project, yes: opts.yes, captureFile: opts.captureFile, newSession: opts.newSession });
|
|
7504
7534
|
} catch (err) {
|
|
7505
7535
|
await printError(err);
|
|
7506
7536
|
process.exit(1);
|
|
@@ -7639,6 +7669,7 @@ Examples:
|
|
|
7639
7669
|
$ npx apiblaze apichat --openapi https://pokeapi.co/openapi.yaml # chat with any API
|
|
7640
7670
|
$ npx apiblaze agent # just chat
|
|
7641
7671
|
$ npx apiblaze create --target https://api.example.com # one-line API
|
|
7672
|
+
$ npx apiblaze create --openapi https://pokeapi.co/openapi.yaml # build it from a spec URL
|
|
7642
7673
|
$ npx apiblaze dev 3000 # localhost \u2192 public URL
|
|
7643
7674
|
$ npx apiblaze throttle myapi --rate 50 --verbose # configure + show the API call
|
|
7644
7675
|
$ npx apiblaze consumer login # act as a consumer of your API
|