forge-remote 0.1.9 → 0.1.11
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 +1 -1
- package/src/init.js +38 -9
package/package.json
CHANGED
package/src/init.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright (c) 2025-2026 Iron Forge Apps
|
|
3
3
|
// Created by Daniel Wendel, CEO/Founder of Iron Forge Apps
|
|
4
4
|
|
|
5
|
-
import { execSync, execFileSync } from "child_process";
|
|
5
|
+
import { execSync, execFileSync, spawn } from "child_process";
|
|
6
6
|
import { createInterface } from "readline";
|
|
7
7
|
import { hostname, platform, homedir } from "os";
|
|
8
8
|
import { existsSync, mkdirSync, writeFileSync, readFileSync, rmSync } from "fs";
|
|
@@ -119,14 +119,24 @@ function waitForEnter(message) {
|
|
|
119
119
|
|
|
120
120
|
/**
|
|
121
121
|
* Open a URL in the default browser (best-effort, no throw).
|
|
122
|
+
* Uses spawn + detach to avoid blocking or suspending the terminal.
|
|
122
123
|
*/
|
|
123
124
|
function openBrowser(url) {
|
|
124
125
|
const p = platform();
|
|
125
126
|
try {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
let cmd, args;
|
|
128
|
+
if (p === "darwin") {
|
|
129
|
+
cmd = "open";
|
|
130
|
+
args = [url];
|
|
131
|
+
} else if (p === "win32") {
|
|
132
|
+
cmd = "cmd";
|
|
133
|
+
args = ["/c", "start", "", url];
|
|
134
|
+
} else {
|
|
135
|
+
cmd = "xdg-open";
|
|
136
|
+
args = [url];
|
|
137
|
+
}
|
|
138
|
+
const child = spawn(cmd, args, { detached: true, stdio: "ignore" });
|
|
139
|
+
child.unref();
|
|
130
140
|
} catch {
|
|
131
141
|
// Silently fail — URL is always printed for manual opening.
|
|
132
142
|
}
|
|
@@ -576,7 +586,8 @@ export async function runInit({ projectId: overrideProjectId } = {}) {
|
|
|
576
586
|
console.log(chalk.yellow(" ⚠ Firestore already enabled — continuing."));
|
|
577
587
|
results.firestoreEnabled = true;
|
|
578
588
|
} else {
|
|
579
|
-
const maxFirestoreRetries =
|
|
589
|
+
const maxFirestoreRetries = 4;
|
|
590
|
+
let billingPromptShown = false;
|
|
580
591
|
|
|
581
592
|
for (let attempt = 0; attempt < maxFirestoreRetries; attempt++) {
|
|
582
593
|
try {
|
|
@@ -614,13 +625,31 @@ export async function runInit({ projectId: overrideProjectId } = {}) {
|
|
|
614
625
|
break;
|
|
615
626
|
}
|
|
616
627
|
|
|
628
|
+
// Detect API propagation delay — retry automatically with a wait.
|
|
629
|
+
if (
|
|
630
|
+
fullOutput.includes("has not been used in project") ||
|
|
631
|
+
fullOutput.includes("it is disabled")
|
|
632
|
+
) {
|
|
633
|
+
if (attempt < maxFirestoreRetries - 1) {
|
|
634
|
+
console.log(
|
|
635
|
+
chalk.yellow(
|
|
636
|
+
` ⚠ Firestore API still propagating (attempt ${attempt + 1}/${maxFirestoreRetries}). Waiting 15s...`,
|
|
637
|
+
),
|
|
638
|
+
);
|
|
639
|
+
await new Promise((r) => setTimeout(r, 15000));
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
617
644
|
if (
|
|
645
|
+
!billingPromptShown &&
|
|
618
646
|
(fullOutput.includes("billing") ||
|
|
619
647
|
fullOutput.includes("FAILED_PRECONDITION") ||
|
|
620
|
-
fullOutput.includes("403")
|
|
621
|
-
|
|
648
|
+
(fullOutput.includes("403") &&
|
|
649
|
+
!fullOutput.includes("has not been used")))
|
|
622
650
|
) {
|
|
623
|
-
//
|
|
651
|
+
// Failed due to billing — guide the user through upgrading.
|
|
652
|
+
billingPromptShown = true;
|
|
624
653
|
console.log(
|
|
625
654
|
chalk.yellow(
|
|
626
655
|
"\n Firestore requires the Blaze (pay-as-you-go) plan.",
|