@farm.js/create-app 0.1.0-beta.57 → 0.1.0-beta.59

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/dist/index.mjs CHANGED
@@ -7,6 +7,8 @@ import { existsSync } from "node:fs";
7
7
  import { chmod, mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
8
8
  import path$1 from "node:path";
9
9
  import { randomUUID } from "node:crypto";
10
+ import { request } from "node:http";
11
+ import { request as request$1 } from "node:https";
10
12
  import os from "node:os";
11
13
  //#region ../farm-cli/src/ui-feature-registry.ts
12
14
  async function installUIFeature(input) {
@@ -2522,13 +2524,9 @@ function escapeRegExp(input) {
2522
2524
  return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2523
2525
  }
2524
2526
  //#endregion
2525
- //#region ../farm-cli/src/telemetry.ts
2526
- const TELEMETRY_SCHEMA_VERSION = 1;
2527
- const DEFAULT_TELEMETRY_ENDPOINT = "https://farmjs.dev/api/telemetry/v1/events";
2528
- const TELEMETRY_NOTICE_URL = "https://farmjs.dev/docs/telemetry";
2529
- const REQUEST_TIMEOUT_MS = 750;
2530
- const CREATE_APP_COMMANDS = ["create", "list-templates"];
2531
- const FARM_TEMPLATES = [
2527
+ //#region ../farm-cli/src/telemetry-contract.ts
2528
+ const FARM_CREATE_APP_TELEMETRY_COMMANDS = ["create", "list-templates"];
2529
+ const FARM_TELEMETRY_TEMPLATES = [
2532
2530
  "basic",
2533
2531
  "react-compiler",
2534
2532
  "auth",
@@ -2547,19 +2545,28 @@ const FARM_TEMPLATES = [
2547
2545
  "unkey",
2548
2546
  "workos"
2549
2547
  ];
2550
- const RENDERERS = [
2548
+ const FARM_TELEMETRY_RENDERERS = [
2551
2549
  "react",
2552
2550
  "preact",
2553
2551
  "solid",
2554
2552
  "vue",
2555
2553
  "svelte"
2556
2554
  ];
2557
- const PACKAGE_MANAGERS = [
2555
+ const FARM_TELEMETRY_PACKAGE_MANAGERS = [
2558
2556
  "npm",
2559
2557
  "pnpm",
2560
2558
  "yarn",
2561
2559
  "bun"
2562
2560
  ];
2561
+ //#endregion
2562
+ //#region ../farm-cli/src/telemetry.ts
2563
+ const TELEMETRY_SCHEMA_VERSION = 1;
2564
+ const DEFAULT_TELEMETRY_ENDPOINT = "https://farmjs.dev/api/telemetry/v1/events";
2565
+ const TELEMETRY_NOTICE_URL = "https://farmjs.dev/docs/telemetry";
2566
+ const REQUEST_TIMEOUT_MS = 3e3;
2567
+ const RETRY_DELAYS_MS = [250, 750];
2568
+ const pendingDeliveries = /* @__PURE__ */ new Set();
2569
+ const retryTimers = /* @__PURE__ */ new Set();
2563
2570
  function defaultConfig() {
2564
2571
  return {
2565
2572
  version: TELEMETRY_SCHEMA_VERSION,
@@ -2728,33 +2735,44 @@ async function showFarmTelemetryNotice() {
2728
2735
  noticeShown: true
2729
2736
  });
2730
2737
  }
2731
- async function trackFarmCreateAppCommand(input) {
2732
- const command = allowlisted(input.command, CREATE_APP_COMMANDS);
2733
- if (!command) return;
2734
- await track({
2735
- eventType: "command_invoked",
2736
- source: "create-app",
2737
- packageName: "@farm.js/create-app",
2738
- packageVersion: sanitizeVersion(input.packageVersion),
2739
- command
2738
+ function trackFarmCreateAppCommand(input) {
2739
+ return schedule(async () => {
2740
+ await showFarmTelemetryNotice();
2741
+ const command = allowlisted(input.command, FARM_CREATE_APP_TELEMETRY_COMMANDS);
2742
+ if (!command) return;
2743
+ await track({
2744
+ eventType: "command_invoked",
2745
+ source: "create-app",
2746
+ packageName: "@farm.js/create-app",
2747
+ packageVersion: sanitizeVersion(input.packageVersion),
2748
+ command
2749
+ });
2740
2750
  });
2741
2751
  }
2742
- async function trackFarmProjectCreated(input) {
2743
- const template = allowlisted(input.template, FARM_TEMPLATES);
2744
- const renderer = allowlisted(input.renderer, RENDERERS);
2745
- const packageManager = allowlisted(input.packageManager, PACKAGE_MANAGERS);
2746
- await track({
2747
- eventType: "project_created",
2748
- source: "create-app",
2749
- packageName: "@farm.js/create-app",
2750
- packageVersion: sanitizeVersion(input.packageVersion),
2751
- ...template ? { template } : {},
2752
- ...renderer ? { renderer } : {},
2753
- ...packageManager ? { packageManager } : {},
2754
- ...typeof input.typescript === "boolean" ? { typescript: input.typescript } : {},
2755
- ...typeof input.installedDependencies === "boolean" ? { installedDependencies: input.installedDependencies } : {}
2752
+ function trackFarmProjectCreated(input) {
2753
+ return schedule(async () => {
2754
+ const template = allowlisted(input.template, FARM_TELEMETRY_TEMPLATES);
2755
+ const renderer = allowlisted(input.renderer, FARM_TELEMETRY_RENDERERS);
2756
+ const packageManager = allowlisted(input.packageManager, FARM_TELEMETRY_PACKAGE_MANAGERS);
2757
+ await track({
2758
+ eventType: "project_created",
2759
+ source: "create-app",
2760
+ packageName: "@farm.js/create-app",
2761
+ packageVersion: sanitizeVersion(input.packageVersion),
2762
+ ...template ? { template } : {},
2763
+ ...renderer ? { renderer } : {},
2764
+ ...packageManager ? { packageManager } : {},
2765
+ ...typeof input.typescript === "boolean" ? { typescript: input.typescript } : {},
2766
+ ...typeof input.installedDependencies === "boolean" ? { installedDependencies: input.installedDependencies } : {}
2767
+ });
2756
2768
  });
2757
2769
  }
2770
+ function schedule(delivery) {
2771
+ const pending = Promise.resolve().then(delivery).catch(() => {});
2772
+ pendingDeliveries.add(pending);
2773
+ pending.finally(() => pendingDeliveries.delete(pending));
2774
+ return Promise.resolve();
2775
+ }
2758
2776
  async function track(event) {
2759
2777
  try {
2760
2778
  const state = await resolveState();
@@ -2776,20 +2794,85 @@ async function track(event) {
2776
2794
  } catch {}
2777
2795
  }
2778
2796
  async function send(payload) {
2779
- const controller = new AbortController();
2780
- const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
2781
- timeout.unref?.();
2797
+ for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt += 1) {
2798
+ const result = await sendOnce(payload);
2799
+ if (result === "delivered" || result === "rejected") return;
2800
+ const delay = RETRY_DELAYS_MS[attempt];
2801
+ if (delay !== void 0) await wait(delay);
2802
+ }
2803
+ debug("delivery failed after retries");
2804
+ }
2805
+ async function sendOnce(payload) {
2806
+ let endpoint;
2782
2807
  try {
2783
- await fetch(getEndpoint(), {
2808
+ endpoint = new URL(getEndpoint());
2809
+ } catch {
2810
+ debug("invalid endpoint URL");
2811
+ return "rejected";
2812
+ }
2813
+ const requestTransport = endpoint.protocol === "http:" ? request : request$1;
2814
+ if (endpoint.protocol !== "http:" && endpoint.protocol !== "https:") {
2815
+ debug(`unsupported endpoint protocol ${endpoint.protocol}`);
2816
+ return "rejected";
2817
+ }
2818
+ const body = JSON.stringify(payload);
2819
+ return new Promise((resolve) => {
2820
+ let settled = false;
2821
+ const finish = (result) => {
2822
+ if (settled) return;
2823
+ settled = true;
2824
+ clearTimeout(timeout);
2825
+ resolve(result);
2826
+ };
2827
+ const request = requestTransport(endpoint, {
2784
2828
  method: "POST",
2785
- headers: { "content-type": "application/json" },
2786
- body: JSON.stringify(payload),
2787
- signal: controller.signal,
2788
- keepalive: true
2829
+ headers: {
2830
+ "content-type": "application/json",
2831
+ "content-length": Buffer.byteLength(body)
2832
+ }
2833
+ }, (response) => {
2834
+ response.on("error", () => {});
2835
+ response.resume();
2836
+ const status = response.statusCode ?? 0;
2837
+ if (status >= 200 && status < 300) return finish("delivered");
2838
+ if (status === 408 || status === 425 || status === 429) {
2839
+ debug(`temporary HTTP ${status}; retrying`);
2840
+ return finish("retry");
2841
+ }
2842
+ if (status >= 500) {
2843
+ debug(`server HTTP ${status}; retrying`);
2844
+ return finish("retry");
2845
+ }
2846
+ debug(`event rejected with HTTP ${status}`);
2847
+ return finish("rejected");
2789
2848
  });
2790
- } catch {} finally {
2791
- clearTimeout(timeout);
2792
- }
2849
+ const timeout = setTimeout(() => {
2850
+ request.destroy();
2851
+ debug("network request timed out; retrying");
2852
+ finish("retry");
2853
+ }, REQUEST_TIMEOUT_MS);
2854
+ timeout.unref?.();
2855
+ request.once("socket", (socket) => socket.unref());
2856
+ request.once("error", () => {
2857
+ debug("network request failed; retrying");
2858
+ finish("retry");
2859
+ });
2860
+ request.end(body);
2861
+ });
2862
+ }
2863
+ function wait(delay) {
2864
+ return new Promise((resolve) => {
2865
+ const timeout = setTimeout(() => {
2866
+ retryTimers.delete(timeout);
2867
+ resolve();
2868
+ }, delay);
2869
+ retryTimers.add(timeout);
2870
+ timeout.unref?.();
2871
+ });
2872
+ }
2873
+ function debug(message) {
2874
+ if (!isTrue(process.env.FARM_TELEMETRY_DEBUG)) return;
2875
+ process.stderr.write(`[farm.telemetry] ${message}\n`);
2793
2876
  }
2794
2877
  function sanitizeVersion(value) {
2795
2878
  return /^[0-9A-Za-z.+_-]{1,64}$/.test(value) ? value : "unknown";
@@ -2948,8 +3031,7 @@ function integrationTemplate(input) {
2948
3031
  }
2949
3032
  async function createApp(projectName, options = {}) {
2950
3033
  showBanner();
2951
- await showFarmTelemetryNotice();
2952
- await trackFarmCreateAppCommand({
3034
+ trackFarmCreateAppCommand({
2953
3035
  command: options.listTemplates ? "list-templates" : "create",
2954
3036
  packageVersion: options.telemetryPackageVersion ?? "unknown"
2955
3037
  });
@@ -3111,7 +3193,7 @@ async function createApp(projectName, options = {}) {
3111
3193
  if (integrationResult.env.length) logger.info("Copy .env.example to .env.local and add your provider credentials.");
3112
3194
  for (const note of integrationResult.notes) logger.info(note);
3113
3195
  }
3114
- await trackFarmProjectCreated({
3196
+ trackFarmProjectCreated({
3115
3197
  packageVersion: options.telemetryPackageVersion ?? "unknown",
3116
3198
  template,
3117
3199
  renderer,
@@ -3350,7 +3432,7 @@ async function updatePackageJson(projectPath, projectName, packageManager) {
3350
3432
  try {
3351
3433
  const content = await fs.readFile(packageJsonPath, "utf-8");
3352
3434
  const packageJson = JSON.parse(content);
3353
- packageJson.name = projectName;
3435
+ packageJson.name = path.basename(projectName.replace(/[\\/]+$/, "")) || projectName;
3354
3436
  if (packageManager.version) packageJson.packageManager = `${packageManager.name}@${packageManager.version}`;
3355
3437
  await fs.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`);
3356
3438
  } catch {