@bnbagent/deploy-provider-bnb 0.3.1 → 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.
- package/package.json +3 -3
- package/src/client.ts +15 -1
- package/src/index.ts +38 -8
- package/src/init.ts +4 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bnbagent/deploy-provider-bnb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "BNB Chain trial-platform provider for @bnbagent/deploy — deploys agents to the managed free-trial runtime (bnbagent-api) over plain HTTPS: GitHub device-flow login, zip artifact upload, deploy + poll. No cloud credentials of your own.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
"typecheck": "tsc --noEmit"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"@bnbagent/deploy-core": "
|
|
20
|
+
"@bnbagent/deploy-core": "^0.4.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@bnbagent/deploy-core": "^0.
|
|
23
|
+
"@bnbagent/deploy-core": "^0.4.0",
|
|
24
24
|
"@types/bun": "^1.3.0",
|
|
25
25
|
"typescript": "^5.7.0"
|
|
26
26
|
}
|
package/src/client.ts
CHANGED
|
@@ -16,7 +16,21 @@ import { loadSession, saveSession, withSessionLock, type Session } from "./sessi
|
|
|
16
16
|
*/
|
|
17
17
|
export function apiUrl(ctx: Context): string {
|
|
18
18
|
const fromSpec = ctx.overrides?.bnb?.apiUrl;
|
|
19
|
-
const
|
|
19
|
+
const fromEnv = process.env.BNBAGENT_API_URL?.trim();
|
|
20
|
+
const hasApiToken = Boolean(process.env.BNBAGENT_API_TOKEN?.trim());
|
|
21
|
+
// An API token is normally injected by CI while the TOML comes from the
|
|
22
|
+
// checked-out repository. Bind that credential to the trusted environment
|
|
23
|
+
// endpoint so repository config cannot redirect it to another HTTPS origin.
|
|
24
|
+
if (hasApiToken && !fromEnv) {
|
|
25
|
+
throw new BnbApiError(
|
|
26
|
+
0,
|
|
27
|
+
"config.token_api_url_missing",
|
|
28
|
+
"BNBAGENT_API_TOKEN requires BNBAGENT_API_URL so the CI credential is bound to a trusted origin.",
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
const url = hasApiToken
|
|
32
|
+
? fromEnv
|
|
33
|
+
: (typeof fromSpec === "string" && fromSpec.trim()) || fromEnv;
|
|
20
34
|
if (!url) {
|
|
21
35
|
throw new BnbApiError(
|
|
22
36
|
0,
|
package/src/index.ts
CHANGED
|
@@ -93,6 +93,10 @@ function slugPath(id: string): string {
|
|
|
93
93
|
return encodeURIComponent(id);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
export function isFreshSlugError(error: unknown): boolean {
|
|
97
|
+
return error instanceof BnbApiError && error.status === 404;
|
|
98
|
+
}
|
|
99
|
+
|
|
96
100
|
/**
|
|
97
101
|
* The HARD spec contract for bnb/trial. validate() reports these early;
|
|
98
102
|
* deploy() re-asserts UNCONDITIONALLY — --force / skipValidation only skip the
|
|
@@ -153,7 +157,8 @@ async function slugRetiredIssue(name: string, ctx: Context): Promise<string | un
|
|
|
153
157
|
if (agent.state === "deleted" || agent.state === "reclaiming") return retired;
|
|
154
158
|
} catch (e) {
|
|
155
159
|
if (e instanceof BnbApiError && (e.status === 410 || e.code === "agent.deleted")) return retired;
|
|
156
|
-
|
|
160
|
+
if (isFreshSlugError(e)) return undefined;
|
|
161
|
+
throw e;
|
|
157
162
|
}
|
|
158
163
|
return undefined;
|
|
159
164
|
}
|
|
@@ -346,6 +351,23 @@ const bnbProvider: CloudProvider = {
|
|
|
346
351
|
"Run: bnbagent-deploy login --provider bnb (against the current apiUrl), or fix [bnb] apiUrl / BNBAGENT_API_URL.",
|
|
347
352
|
});
|
|
348
353
|
}
|
|
354
|
+
let authReady = false;
|
|
355
|
+
if ((apiToken || session) && base && !issues.some((i) => i.code === "auth.host_mismatch")) {
|
|
356
|
+
try {
|
|
357
|
+
await authedRequest(ctx, "GET", "/v1/account");
|
|
358
|
+
authReady = true;
|
|
359
|
+
} catch (e) {
|
|
360
|
+
const err = e instanceof BnbApiError ? e : undefined;
|
|
361
|
+
issues.push({
|
|
362
|
+
level: "error",
|
|
363
|
+
code: err?.code ?? "auth.unavailable",
|
|
364
|
+
message: `Trial-platform authentication failed: ${(e as Error).message}`,
|
|
365
|
+
...(err?.status === 401
|
|
366
|
+
? { hint: "Re-run login, or replace the revoked/expired BNBAGENT_API_TOKEN." }
|
|
367
|
+
: {}),
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
349
371
|
try {
|
|
350
372
|
if (!base) throw new Error("no endpoint");
|
|
351
373
|
const campaign: CampaignStatus = await publicRequest(base, "GET", "/v1/campaign");
|
|
@@ -365,14 +387,22 @@ const bnbProvider: CloudProvider = {
|
|
|
365
387
|
}
|
|
366
388
|
// Doomed-deploy precheck (needs working auth): a deleted slug is
|
|
367
389
|
// retired forever — deploy would fail AFTER uploading the artifact.
|
|
368
|
-
if (
|
|
369
|
-
|
|
370
|
-
|
|
390
|
+
if (authReady && base) {
|
|
391
|
+
try {
|
|
392
|
+
const retired = await slugRetiredIssue(spec.name, ctx);
|
|
393
|
+
if (retired) {
|
|
394
|
+
issues.push({
|
|
395
|
+
level: "error",
|
|
396
|
+
code: "agent.retired",
|
|
397
|
+
message: retired,
|
|
398
|
+
hint: "Pick a new agent name (slug) in agent-deploy.toml.",
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
} catch (e) {
|
|
371
402
|
issues.push({
|
|
372
403
|
level: "error",
|
|
373
|
-
code: "agent.
|
|
374
|
-
message:
|
|
375
|
-
hint: "Pick a new agent name (slug) in agent-deploy.toml.",
|
|
404
|
+
code: e instanceof BnbApiError ? e.code : "agent.precheck_failed",
|
|
405
|
+
message: `Could not verify the agent slug: ${(e as Error).message}`,
|
|
376
406
|
});
|
|
377
407
|
}
|
|
378
408
|
}
|
|
@@ -419,7 +449,7 @@ const bnbProvider: CloudProvider = {
|
|
|
419
449
|
);
|
|
420
450
|
}
|
|
421
451
|
if (!(e instanceof BnbApiError)) throw e; // the retired-slug Error above
|
|
422
|
-
|
|
452
|
+
if (!isFreshSlugError(e)) throw e;
|
|
423
453
|
}
|
|
424
454
|
|
|
425
455
|
const shipped = spec.type === "zip" ? await shipZipArtifact(spec, ctx) : await shipImageArtifact(spec, ctx);
|
package/src/init.ts
CHANGED
|
@@ -26,6 +26,9 @@ export async function initCmd(ctx: Context): Promise<void> {
|
|
|
26
26
|
const defaultName = slugify(basename(ctx.baseDir));
|
|
27
27
|
const name = process.stdin.isTTY ? slugify(ask(`Agent name (slug) [${defaultName}]: `) || defaultName) : defaultName;
|
|
28
28
|
const apiUrl = process.stdin.isTTY ? ask("Trial platform URL (https://…): ") : "";
|
|
29
|
+
const apiUrlLine = apiUrl
|
|
30
|
+
? `apiUrl = ${JSON.stringify(apiUrl)}`
|
|
31
|
+
: '# apiUrl = "https://<the-trial-platform-host>" # Or set BNBAGENT_API_URL';
|
|
29
32
|
|
|
30
33
|
const toml = `name = "${name}"
|
|
31
34
|
|
|
@@ -37,7 +40,7 @@ entrypoint = "main.py" # .py → Python · .js/.mjs/.cjs → Node (zip
|
|
|
37
40
|
# protocol = "A2A" # or "MCP" — buyers then authenticate via the platform token plane
|
|
38
41
|
|
|
39
42
|
[bnb]
|
|
40
|
-
|
|
43
|
+
${apiUrlLine}
|
|
41
44
|
|
|
42
45
|
# [env] # non-sensitive runtime config (plaintext)
|
|
43
46
|
# MY_FLAG = "1"
|