@backifydev/cli 0.3.6 → 0.3.8
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 +2 -0
- package/dist/index.js +125 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -276,3 +276,5 @@ Copy the application AI prompt in Backify to receive the application ID, organiz
|
|
|
276
276
|
`ship` runs configured checks, verifies the repository/branch, and pushes already-committed source using a short-lived repository-scoped GitHub App credential. It never stages, commits, force-pushes, or fabricates preview testing. It waits for the exact healthy preview, then publishes when policy and permissions allow. Required testing/approval returns a pending state and preview URL, not a false successful production deployment. Use `--preview-only` to stop at preview, or `--timeout <seconds>` to change the default 1200-second wait. Applications must currently be at the repository root; Backify Cloud needs static index.html output, and customer Azure needs a Dockerfile serving port 8080.
|
|
277
277
|
|
|
278
278
|
`disconnect` revokes that user's application CLI sessions. `logout` removes local credentials only. Prompt histories and local reports remain subject to application permissions. Deploy the matching API and publish CLI 0.3.0 before enabling this flow in production.
|
|
279
|
+
|
|
280
|
+
Connections now report the device hostname, operating system, architecture, and installed CLI version. Browser-based `connect` exchanges a general sign-in token for an application-scoped device session. Application **People & access → CLI access** shows these sessions and lets access managers revoke individual devices; source managers can revoke their own. Existing connections may need reconnecting to record device details. See [CLI access and country lookup configuration](../../docs/cli-access.md) for privacy, permissions and deployment requirements.
|
package/dist/index.js
CHANGED
|
@@ -17593,6 +17593,28 @@ function unzipSync(data, opts) {
|
|
|
17593
17593
|
import { createRequire as createRequire2 } from "node:module";
|
|
17594
17594
|
import { dirname, resolve } from "node:path";
|
|
17595
17595
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
17596
|
+
async function deployFunctions(call2, appId, environmentId, packageBytes, options = {}) {
|
|
17597
|
+
const result = await call2("/apps/" + appId + "/functions/environments/" + environmentId + "/deploy?confirm=true", { method: "POST", headers: { "content-type": "application/zip" }, body: packageBytes });
|
|
17598
|
+
if (result.status === "succeeded") return;
|
|
17599
|
+
if (!result.operationId) throw new Error("Function deployment did not return a tracking operation. Success has not been verified.");
|
|
17600
|
+
const now = options.now ?? Date.now;
|
|
17601
|
+
const deadline = now() + (options.timeoutMs ?? 20 * 6e4);
|
|
17602
|
+
const sleep = options.sleep ?? ((milliseconds) => new Promise((resolve24) => setTimeout(resolve24, milliseconds)));
|
|
17603
|
+
options.progress?.("Function deployment queued. Waiting for operation " + result.operationId + ".");
|
|
17604
|
+
while (now() < deadline) {
|
|
17605
|
+
let operation;
|
|
17606
|
+
try {
|
|
17607
|
+
operation = await call2("/operations/" + result.operationId);
|
|
17608
|
+
} catch (cause) {
|
|
17609
|
+
throw new Error("Could not read function deployment operation " + result.operationId + ". Check its status before uploading again: " + String(cause));
|
|
17610
|
+
}
|
|
17611
|
+
if (operation.status === "succeeded") return;
|
|
17612
|
+
if (operation.status === "failed" || operation.status === "cancelled") throw new Error("Function deployment " + operation.status + ": " + (operation.errorMessage ?? result.operationId));
|
|
17613
|
+
if (operation.status !== "pending" && operation.status !== "running") throw new Error("Unknown function deployment status: " + operation.status);
|
|
17614
|
+
await sleep(Math.min(options.intervalMs ?? 2e3, Math.max(0, deadline - now())));
|
|
17615
|
+
}
|
|
17616
|
+
throw new Error("Stopped waiting for function deployment. Operation " + result.operationId + " continues on Backify; check its status before uploading again.");
|
|
17617
|
+
}
|
|
17596
17618
|
async function packageFunctions(entry, output) {
|
|
17597
17619
|
const entryPath = resolve(entry);
|
|
17598
17620
|
if (!existsSync(entryPath)) throw new Error("Function entrypoint does not exist: " + entryPath);
|
|
@@ -17638,6 +17660,71 @@ async function packageFunctions(entry, output) {
|
|
|
17638
17660
|
return outputPath;
|
|
17639
17661
|
}
|
|
17640
17662
|
|
|
17663
|
+
// src/cli-session.ts
|
|
17664
|
+
import { hostname, platform, release, arch } from "node:os";
|
|
17665
|
+
|
|
17666
|
+
// package.json
|
|
17667
|
+
var package_default = {
|
|
17668
|
+
name: "@backifydev/cli",
|
|
17669
|
+
version: "0.3.8",
|
|
17670
|
+
description: "Command-line setup and diagnostics for Backify applications",
|
|
17671
|
+
type: "module",
|
|
17672
|
+
bin: {
|
|
17673
|
+
backify: "dist/index.js"
|
|
17674
|
+
},
|
|
17675
|
+
files: [
|
|
17676
|
+
"dist/index.js",
|
|
17677
|
+
"README.md"
|
|
17678
|
+
],
|
|
17679
|
+
scripts: {
|
|
17680
|
+
prebuild: "npm run build -w @backify/platform && npm run build -w @backifydev/sdk && npm run build -w @backify/analyzer",
|
|
17681
|
+
build: `esbuild src/index.ts --bundle --platform=node --format=esm --external:esbuild --external:typescript --outfile=dist/index.js --banner:js="import { createRequire as __backifyCreateRequire } from 'node:module'; var require = __backifyCreateRequire(import.meta.url);"`,
|
|
17682
|
+
prepack: "npm run build",
|
|
17683
|
+
pretypecheck: "npm run build -w @backify/platform && npm run build -w @backifydev/sdk && npm run build -w @backify/analyzer",
|
|
17684
|
+
typecheck: "tsc --noEmit",
|
|
17685
|
+
pretest: "npm run build -w @backify/platform && npm run build -w @backifydev/sdk && npm run build -w @backify/analyzer",
|
|
17686
|
+
test: "vitest run"
|
|
17687
|
+
},
|
|
17688
|
+
publishConfig: {
|
|
17689
|
+
access: "public"
|
|
17690
|
+
},
|
|
17691
|
+
repository: {
|
|
17692
|
+
type: "git",
|
|
17693
|
+
url: "git+https://github.com/frejnorling/backify.git",
|
|
17694
|
+
directory: "packages/cli"
|
|
17695
|
+
},
|
|
17696
|
+
homepage: "https://agent.backify.dev/",
|
|
17697
|
+
license: "MIT",
|
|
17698
|
+
engines: {
|
|
17699
|
+
node: ">=20"
|
|
17700
|
+
},
|
|
17701
|
+
dependencies: {
|
|
17702
|
+
"@azure/functions": "^4.7.2",
|
|
17703
|
+
"@backifydev/sdk": "^0.1.1",
|
|
17704
|
+
esbuild: "^0.25.10",
|
|
17705
|
+
fflate: "^0.8.2",
|
|
17706
|
+
typescript: "^5.9.2"
|
|
17707
|
+
},
|
|
17708
|
+
devDependencies: {
|
|
17709
|
+
"@backify/analyzer": "*",
|
|
17710
|
+
"@backify/platform": "*",
|
|
17711
|
+
"@hono/node-server": "2.1.3",
|
|
17712
|
+
"@types/node": "^24.3.1",
|
|
17713
|
+
hono: "4.13.12",
|
|
17714
|
+
vitest: "^4.1.11"
|
|
17715
|
+
}
|
|
17716
|
+
};
|
|
17717
|
+
|
|
17718
|
+
// src/cli-session.ts
|
|
17719
|
+
function cliDevice() {
|
|
17720
|
+
return { deviceName: hostname(), operatingSystem: platform() + " " + release(), architecture: arch(), cliVersion: package_default.version };
|
|
17721
|
+
}
|
|
17722
|
+
var cliUserAgent = "BackifyCLI/" + package_default.version;
|
|
17723
|
+
async function registerCliSession(client, applicationId, apiUrl) {
|
|
17724
|
+
const session = await client("/apps/" + applicationId + "/developer/session", { method: "POST", body: JSON.stringify(cliDevice()) });
|
|
17725
|
+
return { ...session, apiUrl };
|
|
17726
|
+
}
|
|
17727
|
+
|
|
17641
17728
|
// src/local-runtime.ts
|
|
17642
17729
|
import { createHash, randomUUID } from "node:crypto";
|
|
17643
17730
|
import { chmodSync, existsSync as existsSync2, lstatSync, mkdirSync as mkdirSync2, readFileSync, readdirSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
@@ -17647,13 +17734,13 @@ import { spawnSync } from "node:child_process";
|
|
|
17647
17734
|
|
|
17648
17735
|
// src/local-state.ts
|
|
17649
17736
|
import { renameSync } from "node:fs";
|
|
17650
|
-
function replaceLocalFile(source, destination, rename,
|
|
17737
|
+
function replaceLocalFile(source, destination, rename, platform2, wait) {
|
|
17651
17738
|
for (let attempt = 0; ; attempt++) {
|
|
17652
17739
|
try {
|
|
17653
17740
|
rename(source, destination);
|
|
17654
17741
|
return;
|
|
17655
17742
|
} catch (error) {
|
|
17656
|
-
if (
|
|
17743
|
+
if (platform2 !== "win32" || attempt >= 4 || !(error instanceof Error) || !("code" in error) || !["EPERM", "EACCES", "EBUSY"].includes(String(error.code))) throw error;
|
|
17657
17744
|
wait(10 * 2 ** attempt);
|
|
17658
17745
|
}
|
|
17659
17746
|
}
|
|
@@ -17666,8 +17753,8 @@ function renameLocalFile(source, destination) {
|
|
|
17666
17753
|
var maxArchiveBytes = 256 * 1024 * 1024;
|
|
17667
17754
|
var maxExpandedBytes = 512 * 1024 * 1024;
|
|
17668
17755
|
var hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
17669
|
-
function runtimeIdentifier(
|
|
17670
|
-
const system = { win32: "win", darwin: "osx", linux: "linux" }[
|
|
17756
|
+
function runtimeIdentifier(platform2 = process.platform, architecture = process.arch) {
|
|
17757
|
+
const system = { win32: "win", darwin: "osx", linux: "linux" }[platform2];
|
|
17671
17758
|
if (!system || !["x64", "arm64"].includes(architecture)) throw new Error("Local runtime supports Windows, macOS and Linux on x64/arm64");
|
|
17672
17759
|
return system + "-" + architecture;
|
|
17673
17760
|
}
|
|
@@ -17825,7 +17912,7 @@ function parseApplicationManifest(source) {
|
|
|
17825
17912
|
if (name2 === "database" && settings.migrations !== void 0 && !portablePath(settings.migrations))
|
|
17826
17913
|
throw new Error("Migrations must be repository-relative");
|
|
17827
17914
|
if (name2 === "storage" && settings.buckets !== void 0) {
|
|
17828
|
-
if (!Array.isArray(settings.buckets) || settings.buckets.length > 50 || settings.buckets.some((bucket) => !object(bucket) || typeof bucket.name !== "string" || !/^[A-Za-z0-9_-]{1,100}$/.test(bucket.name) || bucket.access !== void 0 && bucket.access !== "private" || Object.keys(bucket).some((key) => !["name", "access"].includes(key))) || new Set(settings.buckets.map((bucket) => bucket.name)).size !== settings.buckets.length)
|
|
17915
|
+
if (!Array.isArray(settings.buckets) || settings.buckets.length > 50 || settings.buckets.some((bucket) => !object(bucket) || typeof bucket.name !== "string" || !/^[A-Za-z0-9_-]{1,100}$/.test(bucket.name) || bucket.access !== void 0 && bucket.access !== "private" || bucket.isolation !== void 0 && !["private", "user", "tenant", "authenticated", "public", "selected"].includes(String(bucket.isolation)) || bucket.allowSignedUrls !== void 0 && typeof bucket.allowSignedUrls !== "boolean" || Object.keys(bucket).some((key) => !["name", "access", "isolation", "allowSignedUrls"].includes(key))) || new Set(settings.buckets.map((bucket) => bucket.name)).size !== settings.buckets.length)
|
|
17829
17916
|
throw new Error("Storage requires at most 50 distinct private logical buckets");
|
|
17830
17917
|
}
|
|
17831
17918
|
capabilities[name2] = structuredClone(settings);
|
|
@@ -17854,8 +17941,8 @@ function manifestDiagnostics(manifest, used) {
|
|
|
17854
17941
|
// ../platform/dist/delivery.js
|
|
17855
17942
|
var deliveryInstructions = `# Backify application delivery and prompt history
|
|
17856
17943
|
|
|
17857
|
-
Instruction version:
|
|
17858
|
-
Versioned guide: https://agent.backify.dev/
|
|
17944
|
+
Instruction version: 5
|
|
17945
|
+
Versioned guide: https://agent.backify.dev/v5/delivery.md
|
|
17859
17946
|
|
|
17860
17947
|
These instructions are for AI coding tools building applications on Backify, not the Backify platform implementation. Complete the application and deliver a verified deployment, not just SDK setup. Respect the coding tool's own permissions and confirmation settings; preserve unrelated work and applicable repository instructions.
|
|
17861
17948
|
|
|
@@ -17873,7 +17960,7 @@ Initialize using App Id from the copied prompt and the current tool selection:
|
|
|
17873
17960
|
|
|
17874
17961
|
npx @backifydev/cli@latest init --app <app-id> --agent <current-tool>
|
|
17875
17962
|
|
|
17876
|
-
For a tool without a built-in preset, replace --agent <current-tool> with --instruction-file <relative-path>. Read BACKIFY.md and the instruction file used by the current AI coding tool before changing application code. Create or update only instruction files used by that tool; never create files for other coding tools. Use --agent for a built-in tool preset or --instruction-file <relative-path> for the current tool's native instruction file, as described in the setup guide. Initialization installs this workflow alongside the persistent SDK instructions. Follow https://agent.backify.dev/
|
|
17963
|
+
For a tool without a built-in preset, replace --agent <current-tool> with --instruction-file <relative-path>. Read BACKIFY.md and the instruction file used by the current AI coding tool before changing application code. Create or update only instruction files used by that tool; never create files for other coding tools. Use --agent for a built-in tool preset or --instruction-file <relative-path> for the current tool's native instruction file, as described in the setup guide. Initialization installs this workflow alongside the persistent SDK instructions. Follow https://agent.backify.dev/v5 for instruction version 5; use the guide matching backify.json in an existing application. Do not silently upgrade its managed instruction version or overwrite instructions outside the managed block.
|
|
17877
17964
|
|
|
17878
17965
|
Run the following to discover the connected hosting target, repository, branch, reports, releases, and deployment failures:
|
|
17879
17966
|
|
|
@@ -17907,6 +17994,12 @@ For Backify Cloud, build a static application with a build script and index.html
|
|
|
17907
17994
|
|
|
17908
17995
|
Do not claim unsupported hosted server functions or SDK execution paths work. Report unsupported runtime requirements instead of substituting another platform. Keep secrets server-side and out of browser code, project files, and Git.
|
|
17909
17996
|
|
|
17997
|
+
## Local development before delivery
|
|
17998
|
+
|
|
17999
|
+
From the first setup, make every new application runnable and testable locally without a cloud deployment. Follow the matching setup guide's local development steps: preserve the framework, provide a package-manager dev script and README, use @backifydev/sdk/local for platform capabilities and tests, and keep local state and credentials out of Git. Use a native framework dev server for frontend-only apps; for Backify server capabilities, configure backify.yaml and npx @backifydev/cli@latest dev --mode lightweight --json with the supported frontend adapter when needed. Disclose emulator limits and any full-runtime prerequisites.
|
|
18000
|
+
|
|
18001
|
+
Start the application, wait for readiness, request the actual local application URL, and verify a representative user flow before shipping. Document safe seed data and local test identities where needed. Cloud connection, preview approval, or deployment failure must not prevent safe local testing; report those blockers separately without bypassing authorization. If requirements are missing, verify a minimal runnable shell before asking the required final question. Never claim local readiness from a build or management-dashboard response alone.
|
|
18002
|
+
|
|
17910
18003
|
## Verify, push, and publish
|
|
17911
18004
|
|
|
17912
18005
|
Run:
|
|
@@ -17925,6 +18018,8 @@ If testing or approval is required, return the preview URL and explain the remai
|
|
|
17925
18018
|
|
|
17926
18019
|
After setup or a delivery attempt, give the user concise instructions: explain what is ready, how to open and use the application, and any sign-in, testing, approval, or other next steps. Summarize actual checks and blockers without exposing credentials or asking the user to perform routine deployment work the coding tool can complete.
|
|
17927
18020
|
|
|
18021
|
+
Include the verified Local URL, exact start command, and local testing/sign-in steps even when cloud delivery is blocked. If local startup was not verified, say unavailable and explain the blocker.
|
|
18022
|
+
|
|
17928
18023
|
Include separate Preview URL and Production URL lines, using the actual URLs returned by CLI status or deployment results. Include both URLs when available. If either is unavailable, say not deployed or unavailable and explain why; never invent a URL or claim an unverified deployment is live. When production still serves an earlier release, label it as the existing production version and explain that the new changes are preview-only or awaiting approval.
|
|
17929
18024
|
|
|
17930
18025
|
If application requirements are missing after setup, finish the response with this exact question as its final line, without any text after it:
|
|
@@ -17935,7 +18030,7 @@ These instructions are an explicit agent workflow, not a universal chat intercep
|
|
|
17935
18030
|
`;
|
|
17936
18031
|
|
|
17937
18032
|
// ../platform/dist/index.js
|
|
17938
|
-
var INSTRUCTION_VERSION =
|
|
18033
|
+
var INSTRUCTION_VERSION = 5;
|
|
17939
18034
|
var SDK_PACKAGE = "@backifydev/sdk";
|
|
17940
18035
|
var DOCS_URL = "https://docs.backify.dev";
|
|
17941
18036
|
var MAIL_LIMITS = Object.freeze({
|
|
@@ -18005,6 +18100,7 @@ Require explicit confirmation before destructive data operations or removing sta
|
|
|
18005
18100
|
## Implementation workflow
|
|
18006
18101
|
|
|
18007
18102
|
Inspect the framework, lockfile, scripts, configuration, and applicable repository instructions before editing. Preserve the existing framework and unrelated work. Implement the requested application rather than stopping at SDK setup; ask what to build if requirements are missing.
|
|
18103
|
+
From the first setup, make every new application runnable and testable locally without a cloud deployment. Provide a package-manager start script, document prerequisites and local test identities, start the application, and verify its local URL and a representative user flow. Use \`@backifydev/sdk/local\` for local platform capabilities, keep local state and credentials out of Git, and clearly disclose emulation limits. Include the actual Local URL, start command, checks, and any blockers in the user handoff; never claim an unstarted application is ready. Follow the matching setup guide for framework-specific local commands.
|
|
18008
18104
|
Run relevant tests, typechecking, lint, and builds using the repository's scripts when available. Report changes, checks, and remaining blockers accurately; do not claim unverified success.
|
|
18009
18105
|
|
|
18010
18106
|
## Connected application delivery
|
|
@@ -19794,7 +19890,7 @@ async function startLocalServices(root, manifest, options = {}) {
|
|
|
19794
19890
|
if (databasePort === hcrPort) throw new Error("HCR and PostgreSQL require separate ports");
|
|
19795
19891
|
const cluster = join4(directory2, "postgres");
|
|
19796
19892
|
assertLocalStatePath(root, cluster);
|
|
19797
|
-
const
|
|
19893
|
+
const release2 = acquireLocalLease(root, ".backify/dev/services/lifecycle.lock");
|
|
19798
19894
|
let postgresStarted = false;
|
|
19799
19895
|
let hcr;
|
|
19800
19896
|
let timer;
|
|
@@ -19831,7 +19927,7 @@ async function startLocalServices(root, manifest, options = {}) {
|
|
|
19831
19927
|
if (postgresStarted) notify("postgres", "stopped");
|
|
19832
19928
|
if (existsSync5(tokenPath)) unlinkSync3(tokenPath);
|
|
19833
19929
|
} finally {
|
|
19834
|
-
|
|
19930
|
+
release2();
|
|
19835
19931
|
}
|
|
19836
19932
|
})();
|
|
19837
19933
|
const applied = [];
|
|
@@ -21211,7 +21307,7 @@ function initializeLocalSecrets(root, application, keyFile) {
|
|
|
21211
21307
|
if (dirname8(current) === current) break;
|
|
21212
21308
|
}
|
|
21213
21309
|
ensureIgnored(root);
|
|
21214
|
-
const
|
|
21310
|
+
const release2 = acquireLocalLease(root, ".backify/dev/secrets.lock");
|
|
21215
21311
|
const key = randomBytes4(32);
|
|
21216
21312
|
try {
|
|
21217
21313
|
if (existsSync7(filename2)) throw failure();
|
|
@@ -21220,7 +21316,7 @@ function initializeLocalSecrets(root, application, keyFile) {
|
|
|
21220
21316
|
writePrivate2(filename2, encrypt(root, application, key, {}));
|
|
21221
21317
|
} finally {
|
|
21222
21318
|
key.fill(0);
|
|
21223
|
-
|
|
21319
|
+
release2();
|
|
21224
21320
|
}
|
|
21225
21321
|
return { schemaVersion: 1, status: "initialized", keyFile: external, names: [] };
|
|
21226
21322
|
}
|
|
@@ -21228,7 +21324,7 @@ function setLocalSecret(root, application, keyFile, name2, value) {
|
|
|
21228
21324
|
if (!secretName.test(name2) || Buffer.byteLength(value) < 1 || Buffer.byteLength(value) > 65536) throw new Error("Local secrets require an uppercase logical name and 1-65536 UTF-8 bytes from stdin");
|
|
21229
21325
|
const filename2 = vaultPath(root);
|
|
21230
21326
|
assertLocalStatePath(root, filename2);
|
|
21231
|
-
const
|
|
21327
|
+
const release2 = acquireLocalLease(root, ".backify/dev/secrets.lock");
|
|
21232
21328
|
let key;
|
|
21233
21329
|
try {
|
|
21234
21330
|
const secrets = readLocalSecrets(root, application, keyFile);
|
|
@@ -21240,7 +21336,7 @@ function setLocalSecret(root, application, keyFile, name2, value) {
|
|
|
21240
21336
|
renameLocalFile(temporary, filename2);
|
|
21241
21337
|
} finally {
|
|
21242
21338
|
key?.fill(0);
|
|
21243
|
-
|
|
21339
|
+
release2();
|
|
21244
21340
|
}
|
|
21245
21341
|
return { schemaVersion: 1, status: "stored", name: name2 };
|
|
21246
21342
|
}
|
|
@@ -22635,7 +22731,7 @@ function apiClient(session, transport = fetch) {
|
|
|
22635
22731
|
return async (path, init) => {
|
|
22636
22732
|
if (!path.startsWith("/") || path.startsWith("//")) throw new Error("Invalid API path.");
|
|
22637
22733
|
if (session.expiresAt && Date.parse(session.expiresAt) <= Date.now()) throw new Error("CLI session expired. Copy a new setup prompt or run backify login.");
|
|
22638
|
-
const response = await transport(base + path, { ...init, redirect: "error", signal: AbortSignal.timeout(3e4), headers: { "content-type": "application/json", "X-Organization-ID": session.organizationId, ...session.token ? { authorization: "Bearer " + session.token } : {}, ...init?.headers } });
|
|
22734
|
+
const response = await transport(base + path, { ...init, redirect: "error", signal: AbortSignal.timeout(3e4), headers: { "content-type": "application/json", "user-agent": cliUserAgent, "X-Organization-ID": session.organizationId, ...session.token ? { authorization: "Bearer " + session.token } : {}, ...init?.headers } });
|
|
22639
22735
|
if (!response.ok) {
|
|
22640
22736
|
let message = "Backify request failed (" + response.status + ").";
|
|
22641
22737
|
try {
|
|
@@ -22773,8 +22869,8 @@ function localReport(runChecks, root = process.cwd()) {
|
|
|
22773
22869
|
const outputDirectory = ["dist", "build", "out", "."].find((directory2) => existsSync14(join16(root, directory2, "index.html"))) ?? null;
|
|
22774
22870
|
return { framework, sdkVersion: dependencies["@backifydev/sdk"] ?? null, branch, commitSha, dirty, buildCommand: pkg.scripts?.build ? manager + " run build" : null, outputDirectory, hasDockerfile: existsSync14(join16(root, "Dockerfile")), checks };
|
|
22775
22871
|
}
|
|
22776
|
-
function matchesSource(
|
|
22777
|
-
return
|
|
22872
|
+
function matchesSource(release2, commit) {
|
|
22873
|
+
return release2?.commitSha === commit || release2?.sourceCommitSha === commit;
|
|
22778
22874
|
}
|
|
22779
22875
|
function pushSource(appId, commit, branch, destination, root, environment) {
|
|
22780
22876
|
const remoteHead = git2(["ls-remote", "--", destination, "refs/heads/" + branch], root, environment).split(/\s+/)[0];
|
|
@@ -22796,7 +22892,7 @@ async function waitForPreview(call2, prefix, commit, options = {}) {
|
|
|
22796
22892
|
const sleep = options.sleep ?? ((delay) => new Promise((resolve24) => setTimeout(resolve24, delay)));
|
|
22797
22893
|
do {
|
|
22798
22894
|
const deployments = await call2(prefix + "/deployments");
|
|
22799
|
-
const matching = deployments.find((
|
|
22895
|
+
const matching = deployments.find((release2) => release2.kind === "preview" && matchesSource(release2, commit) && !options.previousDeploymentIds?.includes(release2.id));
|
|
22800
22896
|
if (matching?.status === "failed") throw new Error("Deployment of this source failed. Run backify status and inspect its deployment steps.");
|
|
22801
22897
|
const overview = await call2(prefix + "/releases");
|
|
22802
22898
|
if (matchesSource(overview.preview, commit) && overview.preview?.status === "succeeded" && overview.preview.healthResult === "healthy") return overview;
|
|
@@ -22833,7 +22929,7 @@ async function ship(call2, appId, options = {}) {
|
|
|
22833
22929
|
const environment = gitEnvironment(status.repository, credential.token);
|
|
22834
22930
|
const destination = "https://github.com/" + status.repository + ".git";
|
|
22835
22931
|
const alreadyPushed = pushSource(appId, commit, status.branch, destination, root, environment);
|
|
22836
|
-
const currentPreview = previousDeployments.find((
|
|
22932
|
+
const currentPreview = previousDeployments.find((release2) => release2.kind === "preview" && matchesSource(release2, commit));
|
|
22837
22933
|
if (alreadyPushed && (!currentPreview || currentPreview.status === "failed") && !(matchesSource(status.releases.preview, commit) && status.releases.preview?.status === "succeeded")) await call2(prefix + "/deployments/preview", { method: "POST", body: JSON.stringify({ sourceRevision: "latest" }) });
|
|
22838
22934
|
const overview = await waitForPreview(call2, prefix, commit, { timeoutMs: options.timeoutMs, previousDeploymentIds: previousDeployments.filter((deployment) => deployment.status === "failed").map((deployment) => deployment.id), previousBuildRunId: previousBuild.runId ?? null });
|
|
22839
22935
|
if (overview.preview.commitSha !== commit) {
|
|
@@ -23070,7 +23166,7 @@ async function main() {
|
|
|
23070
23166
|
const environmentId = option("--environment");
|
|
23071
23167
|
const packagePath = option("--package");
|
|
23072
23168
|
if (!environmentId || !packagePath || !args.includes("--confirm")) throw new Error("Use backify functions deploy --environment <environment-id> --package <functions.zip> --confirm. This replaces the complete function project.");
|
|
23073
|
-
await call
|
|
23169
|
+
await deployFunctions(call, appId, applicationGuid(environmentId), new Uint8Array(readFileSync24(packagePath)), { progress: (message) => console.log(message) });
|
|
23074
23170
|
console.log("Functions deployed.");
|
|
23075
23171
|
} else throw new Error("Use backify functions package or backify functions deploy");
|
|
23076
23172
|
break;
|
|
@@ -23113,14 +23209,20 @@ async function main() {
|
|
|
23113
23209
|
if (code) {
|
|
23114
23210
|
if (!organizationId) throw new Error("The setup prompt must supply the organization.");
|
|
23115
23211
|
const redeem = apiClient({ token: "", organizationId, apiUrl: address });
|
|
23116
|
-
const paired = await redeem("/apps/" + applicationGuid(appId) + "/developer/pair", { method: "POST", body: JSON.stringify({ code }) });
|
|
23212
|
+
const paired = await redeem("/apps/" + applicationGuid(appId) + "/developer/pair", { method: "POST", body: JSON.stringify({ code, device: cliDevice() }) });
|
|
23117
23213
|
userConfig.sessions ??= {};
|
|
23118
23214
|
userConfig.sessions[key] = { ...paired, apiUrl: address };
|
|
23119
23215
|
saveUserConfig(configPath, userConfig);
|
|
23120
23216
|
} else if (!userConfig.sessions?.[key] && !userConfig.token) {
|
|
23121
23217
|
await browserLogin();
|
|
23122
23218
|
}
|
|
23123
|
-
|
|
23219
|
+
let session = userConfig.sessions?.[key] ?? { token: userConfig.token ?? "", organizationId: organizationId ?? userConfig.organizationId ?? "", apiUrl: address };
|
|
23220
|
+
if (!session.token.startsWith("bfcli_")) {
|
|
23221
|
+
session = await registerCliSession(apiClient(session), applicationGuid(appId), session.apiUrl);
|
|
23222
|
+
userConfig.sessions ??= {};
|
|
23223
|
+
userConfig.sessions[key] = session;
|
|
23224
|
+
saveUserConfig(configPath, userConfig);
|
|
23225
|
+
}
|
|
23124
23226
|
const client = apiClient(session);
|
|
23125
23227
|
await client("/apps/" + applicationGuid(appId) + "/developer");
|
|
23126
23228
|
userConfig.sessions ??= {};
|