@backifydev/cli 0.3.5 → 0.3.7

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.
Files changed (2) hide show
  1. package/dist/index.js +55 -9
  2. package/package.json +1 -1
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);
@@ -17854,8 +17876,8 @@ function manifestDiagnostics(manifest, used) {
17854
17876
  // ../platform/dist/delivery.js
17855
17877
  var deliveryInstructions = `# Backify application delivery and prompt history
17856
17878
 
17857
- Instruction version: 4
17858
- Versioned guide: https://agent.backify.dev/v4/delivery.md
17879
+ Instruction version: 5
17880
+ Versioned guide: https://agent.backify.dev/v5/delivery.md
17859
17881
 
17860
17882
  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
17883
 
@@ -17873,7 +17895,7 @@ Initialize using App Id from the copied prompt and the current tool selection:
17873
17895
 
17874
17896
  npx @backifydev/cli@latest init --app <app-id> --agent <current-tool>
17875
17897
 
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/v4 for instruction version 4; 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.
17898
+ 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
17899
 
17878
17900
  Run the following to discover the connected hosting target, repository, branch, reports, releases, and deployment failures:
17879
17901
 
@@ -17907,6 +17929,12 @@ For Backify Cloud, build a static application with a build script and index.html
17907
17929
 
17908
17930
  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
17931
 
17932
+ ## Local development before delivery
17933
+
17934
+ 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.
17935
+
17936
+ 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.
17937
+
17910
17938
  ## Verify, push, and publish
17911
17939
 
17912
17940
  Run:
@@ -17925,6 +17953,8 @@ If testing or approval is required, return the preview URL and explain the remai
17925
17953
 
17926
17954
  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
17955
 
17956
+ 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.
17957
+
17928
17958
  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
17959
 
17930
17960
  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 +17965,7 @@ These instructions are an explicit agent workflow, not a universal chat intercep
17935
17965
  `;
17936
17966
 
17937
17967
  // ../platform/dist/index.js
17938
- var INSTRUCTION_VERSION = 4;
17968
+ var INSTRUCTION_VERSION = 5;
17939
17969
  var SDK_PACKAGE = "@backifydev/sdk";
17940
17970
  var DOCS_URL = "https://docs.backify.dev";
17941
17971
  var MAIL_LIMITS = Object.freeze({
@@ -18005,6 +18035,7 @@ Require explicit confirmation before destructive data operations or removing sta
18005
18035
  ## Implementation workflow
18006
18036
 
18007
18037
  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.
18038
+ 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
18039
  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
18040
 
18010
18041
  ## Connected application delivery
@@ -22776,6 +22807,21 @@ function localReport(runChecks, root = process.cwd()) {
22776
22807
  function matchesSource(release, commit) {
22777
22808
  return release?.commitSha === commit || release?.sourceCommitSha === commit;
22778
22809
  }
22810
+ function pushSource(appId, commit, branch, destination, root, environment) {
22811
+ const remoteHead = git2(["ls-remote", "--", destination, "refs/heads/" + branch], root, environment).split(/\s+/)[0];
22812
+ if (remoteHead === commit) return true;
22813
+ if (remoteHead) {
22814
+ git2(["fetch", "--no-tags", "--", destination, "refs/heads/" + branch], root, environment);
22815
+ const fetchedHead = git2(["rev-parse", "FETCH_HEAD"], root);
22816
+ if (fetchedHead === commit) return true;
22817
+ const parent = git2(["show", "-s", "--format=%P", fetchedHead], root);
22818
+ const message = git2(["show", "-s", "--format=%B", fetchedHead], root);
22819
+ if (parent === commit && message === "Backify build " + applicationGuid(appId).replaceAll("-", "") + ": " + commit) return true;
22820
+ if (git2(["merge-base", commit, fetchedHead], root) !== fetchedHead) throw new Error("Remote history contains other changes. Run backify pull and reconcile them before shipping; nothing was pushed or overwritten.");
22821
+ }
22822
+ git2(["push", "--", destination, commit + ":refs/heads/" + branch], root, environment);
22823
+ return false;
22824
+ }
22779
22825
  async function waitForPreview(call2, prefix, commit, options = {}) {
22780
22826
  const deadline = Date.now() + (options.timeoutMs ?? 20 * 6e4);
22781
22827
  const sleep = options.sleep ?? ((delay) => new Promise((resolve24) => setTimeout(resolve24, delay)));
@@ -22817,10 +22863,10 @@ async function ship(call2, appId, options = {}) {
22817
22863
  if (credential.repository.toLowerCase() !== status.repository.toLowerCase()) throw new Error("Repository changed; reconnect before shipping.");
22818
22864
  const environment = gitEnvironment(status.repository, credential.token);
22819
22865
  const destination = "https://github.com/" + status.repository + ".git";
22820
- const remoteHead = git2(["ls-remote", "--", destination, "refs/heads/" + status.branch], root, environment).split(/\s+/)[0];
22821
- git2(["push", "--", destination, commit + ":refs/heads/" + status.branch], root, environment);
22822
- if (remoteHead === commit && !(matchesSource(status.releases.preview, commit) && status.releases.preview?.status === "succeeded")) await call2(prefix + "/deployments/preview", { method: "POST", body: JSON.stringify({ sourceRevision: "latest" }) });
22823
- const overview = await waitForPreview(call2, prefix, commit, { timeoutMs: options.timeoutMs, previousDeploymentIds: previousDeployments.map((deployment) => deployment.id), previousBuildRunId: previousBuild.runId ?? null });
22866
+ const alreadyPushed = pushSource(appId, commit, status.branch, destination, root, environment);
22867
+ const currentPreview = previousDeployments.find((release) => release.kind === "preview" && matchesSource(release, commit));
22868
+ 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" }) });
22869
+ 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 });
22824
22870
  if (overview.preview.commitSha !== commit) {
22825
22871
  if (git2(["status", "--porcelain"], root) || git2(["rev-parse", "HEAD"], root) !== commit) throw new Error("Local work changed while the preview built. Review it before synchronizing the build commit.");
22826
22872
  const refreshed = await call2(prefix + "/developer/git-credential", { method: "POST" });
@@ -23055,7 +23101,7 @@ async function main() {
23055
23101
  const environmentId = option("--environment");
23056
23102
  const packagePath = option("--package");
23057
23103
  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.");
23058
- await call("/apps/" + appId + "/functions/environments/" + applicationGuid(environmentId) + "/deploy?confirm=true", { method: "POST", headers: { "content-type": "application/zip" }, body: new Uint8Array(readFileSync24(packagePath)) });
23104
+ await deployFunctions(call, appId, applicationGuid(environmentId), new Uint8Array(readFileSync24(packagePath)), { progress: (message) => console.log(message) });
23059
23105
  console.log("Functions deployed.");
23060
23106
  } else throw new Error("Use backify functions package or backify functions deploy");
23061
23107
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backifydev/cli",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "Command-line setup and diagnostics for Backify applications",
5
5
  "type": "module",
6
6
  "bin": {