@farm.js/create-app 0.1.0-beta.36 → 0.1.0-beta.38
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/bin/create-farm-app.js +1 -1
- package/dist/index.js +277 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +275 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/_renderers/preact/package.json +2 -2
- package/templates/_renderers/solid/package.json +2 -2
- package/templates/_renderers/svelte/package.json +2 -2
- package/templates/_renderers/vue/package.json +2 -2
- package/templates/auth/package.json +3 -3
- package/templates/basic/package.json +2 -2
- package/templates/better-auth/package.json +3 -3
- package/templates/react-compiler/package.json +2 -2
package/bin/create-farm-app.js
CHANGED
|
@@ -19,7 +19,7 @@ program
|
|
|
19
19
|
.option("--skip-install", "Skip installing dependencies")
|
|
20
20
|
.action(async (projectName, options) => {
|
|
21
21
|
try {
|
|
22
|
-
await createApp(projectName, options);
|
|
22
|
+
await createApp(projectName, { ...options, telemetryPackageVersion: version });
|
|
23
23
|
} catch (error) {
|
|
24
24
|
console.error("Failed to create app:", error);
|
|
25
25
|
process.exit(1);
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,9 @@ let node_fs = require("node:fs");
|
|
|
12
12
|
let node_fs_promises = require("node:fs/promises");
|
|
13
13
|
let node_path = require("node:path");
|
|
14
14
|
node_path = require_rolldown_runtime.__toESM(node_path);
|
|
15
|
+
let node_crypto = require("node:crypto");
|
|
16
|
+
let node_os = require("node:os");
|
|
17
|
+
node_os = require_rolldown_runtime.__toESM(node_os);
|
|
15
18
|
//#region ../farm-cli/src/ui-feature-registry.ts
|
|
16
19
|
async function installUIFeature(input) {
|
|
17
20
|
const feature = input.definition.ui;
|
|
@@ -2526,6 +2529,269 @@ function escapeRegExp(input) {
|
|
|
2526
2529
|
return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2527
2530
|
}
|
|
2528
2531
|
//#endregion
|
|
2532
|
+
//#region ../farm-cli/src/telemetry.ts
|
|
2533
|
+
const TELEMETRY_SCHEMA_VERSION = 1;
|
|
2534
|
+
const DEFAULT_TELEMETRY_ENDPOINT = "https://farmjs.dev/api/telemetry/v1/events";
|
|
2535
|
+
const TELEMETRY_NOTICE_URL = "https://farmjs.dev/docs/telemetry";
|
|
2536
|
+
const REQUEST_TIMEOUT_MS = 750;
|
|
2537
|
+
const FARM_TEMPLATES = [
|
|
2538
|
+
"basic",
|
|
2539
|
+
"react-compiler",
|
|
2540
|
+
"auth",
|
|
2541
|
+
"better-auth",
|
|
2542
|
+
"ai",
|
|
2543
|
+
"auth0",
|
|
2544
|
+
"authjs",
|
|
2545
|
+
"autumn",
|
|
2546
|
+
"clerk",
|
|
2547
|
+
"jobs-inngest",
|
|
2548
|
+
"jobs-trigger",
|
|
2549
|
+
"polar",
|
|
2550
|
+
"resend",
|
|
2551
|
+
"stripe",
|
|
2552
|
+
"supabase",
|
|
2553
|
+
"unkey",
|
|
2554
|
+
"workos"
|
|
2555
|
+
];
|
|
2556
|
+
const RENDERERS = [
|
|
2557
|
+
"react",
|
|
2558
|
+
"preact",
|
|
2559
|
+
"solid",
|
|
2560
|
+
"vue",
|
|
2561
|
+
"svelte"
|
|
2562
|
+
];
|
|
2563
|
+
const PACKAGE_MANAGERS = [
|
|
2564
|
+
"npm",
|
|
2565
|
+
"pnpm",
|
|
2566
|
+
"yarn",
|
|
2567
|
+
"bun"
|
|
2568
|
+
];
|
|
2569
|
+
function defaultConfig() {
|
|
2570
|
+
return {
|
|
2571
|
+
version: TELEMETRY_SCHEMA_VERSION,
|
|
2572
|
+
enabled: false,
|
|
2573
|
+
noticeShown: false
|
|
2574
|
+
};
|
|
2575
|
+
}
|
|
2576
|
+
function configDirectory() {
|
|
2577
|
+
if (process.env.FARM_TELEMETRY_CONFIG_DIR) return node_path.default.resolve(process.env.FARM_TELEMETRY_CONFIG_DIR);
|
|
2578
|
+
if (process.platform === "win32") return node_path.default.join(process.env.APPDATA || node_path.default.join(node_os.default.homedir(), "AppData", "Roaming"), "farmjs");
|
|
2579
|
+
if (process.platform === "darwin") return node_path.default.join(node_os.default.homedir(), "Library", "Application Support", "farmjs");
|
|
2580
|
+
return node_path.default.join(process.env.XDG_CONFIG_HOME || node_path.default.join(node_os.default.homedir(), ".config"), "farmjs");
|
|
2581
|
+
}
|
|
2582
|
+
function getFarmTelemetryConfigFile() {
|
|
2583
|
+
return node_path.default.join(configDirectory(), "telemetry.json");
|
|
2584
|
+
}
|
|
2585
|
+
async function readConfig() {
|
|
2586
|
+
try {
|
|
2587
|
+
const parsed = JSON.parse(await (0, node_fs_promises.readFile)(getFarmTelemetryConfigFile(), "utf8"));
|
|
2588
|
+
if (parsed.version !== TELEMETRY_SCHEMA_VERSION) return defaultConfig();
|
|
2589
|
+
return {
|
|
2590
|
+
version: TELEMETRY_SCHEMA_VERSION,
|
|
2591
|
+
enabled: parsed.enabled === true,
|
|
2592
|
+
noticeShown: parsed.noticeShown === true,
|
|
2593
|
+
anonymousId: isUuid(parsed.anonymousId) ? parsed.anonymousId : void 0
|
|
2594
|
+
};
|
|
2595
|
+
} catch {
|
|
2596
|
+
return defaultConfig();
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
async function writeConfig(config) {
|
|
2600
|
+
const file = getFarmTelemetryConfigFile();
|
|
2601
|
+
const directory = node_path.default.dirname(file);
|
|
2602
|
+
const temporaryFile = `${file}.${process.pid}.${(0, node_crypto.randomUUID)()}.tmp`;
|
|
2603
|
+
try {
|
|
2604
|
+
await (0, node_fs_promises.mkdir)(directory, {
|
|
2605
|
+
recursive: true,
|
|
2606
|
+
mode: 448
|
|
2607
|
+
});
|
|
2608
|
+
await (0, node_fs_promises.writeFile)(temporaryFile, `${JSON.stringify(config, null, 2)}\n`, { mode: 384 });
|
|
2609
|
+
await (0, node_fs_promises.rename)(temporaryFile, file);
|
|
2610
|
+
await (0, node_fs_promises.chmod)(file, 384).catch(() => void 0);
|
|
2611
|
+
} catch {
|
|
2612
|
+
await (0, node_fs_promises.unlink)(temporaryFile).catch(() => void 0);
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
function isUuid(value) {
|
|
2616
|
+
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
2617
|
+
}
|
|
2618
|
+
function isTrue(value) {
|
|
2619
|
+
return value !== void 0 && [
|
|
2620
|
+
"1",
|
|
2621
|
+
"true",
|
|
2622
|
+
"yes",
|
|
2623
|
+
"on"
|
|
2624
|
+
].includes(value.toLowerCase());
|
|
2625
|
+
}
|
|
2626
|
+
function isFalse(value) {
|
|
2627
|
+
return value !== void 0 && [
|
|
2628
|
+
"0",
|
|
2629
|
+
"false",
|
|
2630
|
+
"no",
|
|
2631
|
+
"off"
|
|
2632
|
+
].includes(value.toLowerCase());
|
|
2633
|
+
}
|
|
2634
|
+
function environmentDecision() {
|
|
2635
|
+
if (process.env.DO_NOT_TRACK !== void 0 && !isFalse(process.env.DO_NOT_TRACK)) return {
|
|
2636
|
+
enabled: false,
|
|
2637
|
+
reason: "DO_NOT_TRACK is set"
|
|
2638
|
+
};
|
|
2639
|
+
if (isTrue(process.env.FARM_TELEMETRY_DISABLED)) return {
|
|
2640
|
+
enabled: false,
|
|
2641
|
+
reason: "FARM_TELEMETRY_DISABLED is set"
|
|
2642
|
+
};
|
|
2643
|
+
if (isTrue(process.env.FARM_TELEMETRY)) return { enabled: true };
|
|
2644
|
+
if (isFalse(process.env.FARM_TELEMETRY)) return {
|
|
2645
|
+
enabled: false,
|
|
2646
|
+
reason: "FARM_TELEMETRY disables collection"
|
|
2647
|
+
};
|
|
2648
|
+
return {};
|
|
2649
|
+
}
|
|
2650
|
+
function isContinuousIntegration() {
|
|
2651
|
+
return isTrue(process.env.CI) || isTrue(process.env.GITHUB_ACTIONS) || isTrue(process.env.BUILDKITE) || isTrue(process.env.CIRCLECI);
|
|
2652
|
+
}
|
|
2653
|
+
function isInteractive() {
|
|
2654
|
+
return process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
2655
|
+
}
|
|
2656
|
+
function getEndpoint() {
|
|
2657
|
+
const candidate = process.env.FARM_TELEMETRY_ENDPOINT || DEFAULT_TELEMETRY_ENDPOINT;
|
|
2658
|
+
try {
|
|
2659
|
+
const url = new URL(candidate);
|
|
2660
|
+
const isLocal = [
|
|
2661
|
+
"localhost",
|
|
2662
|
+
"127.0.0.1",
|
|
2663
|
+
"::1"
|
|
2664
|
+
].includes(url.hostname);
|
|
2665
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && isLocal)) return DEFAULT_TELEMETRY_ENDPOINT;
|
|
2666
|
+
return url.toString();
|
|
2667
|
+
} catch {
|
|
2668
|
+
return DEFAULT_TELEMETRY_ENDPOINT;
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
async function resolveState() {
|
|
2672
|
+
const config = await readConfig();
|
|
2673
|
+
const environment = environmentDecision();
|
|
2674
|
+
const enabled = environment.enabled ?? config.enabled;
|
|
2675
|
+
const source = environment.enabled !== void 0 ? "environment" : config.enabled ? "configuration" : "default";
|
|
2676
|
+
if (!enabled) return {
|
|
2677
|
+
config,
|
|
2678
|
+
enabled,
|
|
2679
|
+
active: false,
|
|
2680
|
+
source,
|
|
2681
|
+
reason: environment.reason
|
|
2682
|
+
};
|
|
2683
|
+
if (environment.enabled === true) return {
|
|
2684
|
+
config,
|
|
2685
|
+
enabled,
|
|
2686
|
+
active: true,
|
|
2687
|
+
source
|
|
2688
|
+
};
|
|
2689
|
+
if (process.env.NODE_ENV === "test") return {
|
|
2690
|
+
config,
|
|
2691
|
+
enabled,
|
|
2692
|
+
active: false,
|
|
2693
|
+
source,
|
|
2694
|
+
reason: "test environments are skipped"
|
|
2695
|
+
};
|
|
2696
|
+
if (isContinuousIntegration()) return {
|
|
2697
|
+
config,
|
|
2698
|
+
enabled,
|
|
2699
|
+
active: false,
|
|
2700
|
+
source,
|
|
2701
|
+
reason: "CI environments are skipped"
|
|
2702
|
+
};
|
|
2703
|
+
if (!isInteractive()) return {
|
|
2704
|
+
config,
|
|
2705
|
+
enabled,
|
|
2706
|
+
active: false,
|
|
2707
|
+
source,
|
|
2708
|
+
reason: "non-interactive commands are skipped"
|
|
2709
|
+
};
|
|
2710
|
+
return {
|
|
2711
|
+
config,
|
|
2712
|
+
enabled,
|
|
2713
|
+
active: true,
|
|
2714
|
+
source
|
|
2715
|
+
};
|
|
2716
|
+
}
|
|
2717
|
+
async function showFarmTelemetryNotice() {
|
|
2718
|
+
if (!isInteractive() || isContinuousIntegration() || process.env.NODE_ENV === "test") return;
|
|
2719
|
+
if (environmentDecision().enabled !== void 0) return;
|
|
2720
|
+
const config = await readConfig();
|
|
2721
|
+
if (config.noticeShown) return;
|
|
2722
|
+
process.stderr.write(`Farm.js anonymous telemetry is off during beta. Run "farm telemetry enable" to opt in.\nLearn more: ${TELEMETRY_NOTICE_URL}\n`);
|
|
2723
|
+
await writeConfig({
|
|
2724
|
+
...config,
|
|
2725
|
+
noticeShown: true
|
|
2726
|
+
});
|
|
2727
|
+
}
|
|
2728
|
+
async function trackFarmProjectCreated(input) {
|
|
2729
|
+
const template = allowlisted(input.template, FARM_TEMPLATES);
|
|
2730
|
+
const renderer = allowlisted(input.renderer, RENDERERS);
|
|
2731
|
+
const packageManager = allowlisted(input.packageManager, PACKAGE_MANAGERS);
|
|
2732
|
+
await track({
|
|
2733
|
+
eventType: "project_created",
|
|
2734
|
+
source: "create-app",
|
|
2735
|
+
packageName: "@farm.js/create-app",
|
|
2736
|
+
packageVersion: sanitizeVersion(input.packageVersion),
|
|
2737
|
+
...template ? { template } : {},
|
|
2738
|
+
...renderer ? { renderer } : {},
|
|
2739
|
+
...packageManager ? { packageManager } : {},
|
|
2740
|
+
...typeof input.typescript === "boolean" ? { typescript: input.typescript } : {},
|
|
2741
|
+
...typeof input.installedDependencies === "boolean" ? { installedDependencies: input.installedDependencies } : {}
|
|
2742
|
+
});
|
|
2743
|
+
}
|
|
2744
|
+
async function track(event) {
|
|
2745
|
+
try {
|
|
2746
|
+
const state = await resolveState();
|
|
2747
|
+
if (!state.active) return;
|
|
2748
|
+
const anonymousId = state.config.anonymousId || (0, node_crypto.randomUUID)();
|
|
2749
|
+
if (!state.config.anonymousId) await writeConfig({
|
|
2750
|
+
...state.config,
|
|
2751
|
+
anonymousId
|
|
2752
|
+
});
|
|
2753
|
+
await send({
|
|
2754
|
+
schemaVersion: TELEMETRY_SCHEMA_VERSION,
|
|
2755
|
+
eventId: (0, node_crypto.randomUUID)(),
|
|
2756
|
+
anonymousId,
|
|
2757
|
+
nodeMajor: Number.parseInt(process.versions.node.split(".")[0] || "0", 10),
|
|
2758
|
+
platform: normalizePlatform(process.platform),
|
|
2759
|
+
architecture: normalizeArchitecture(process.arch),
|
|
2760
|
+
...event
|
|
2761
|
+
});
|
|
2762
|
+
} catch {}
|
|
2763
|
+
}
|
|
2764
|
+
async function send(payload) {
|
|
2765
|
+
const controller = new AbortController();
|
|
2766
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
2767
|
+
timeout.unref?.();
|
|
2768
|
+
try {
|
|
2769
|
+
await fetch(getEndpoint(), {
|
|
2770
|
+
method: "POST",
|
|
2771
|
+
headers: { "content-type": "application/json" },
|
|
2772
|
+
body: JSON.stringify(payload),
|
|
2773
|
+
signal: controller.signal,
|
|
2774
|
+
keepalive: true
|
|
2775
|
+
});
|
|
2776
|
+
} catch {} finally {
|
|
2777
|
+
clearTimeout(timeout);
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
function sanitizeVersion(value) {
|
|
2781
|
+
return /^[0-9A-Za-z.+_-]{1,64}$/.test(value) ? value : "unknown";
|
|
2782
|
+
}
|
|
2783
|
+
function allowlisted(value, values) {
|
|
2784
|
+
return value && values.includes(value) ? value : void 0;
|
|
2785
|
+
}
|
|
2786
|
+
function normalizePlatform(value) {
|
|
2787
|
+
if (value === "darwin" || value === "linux") return value;
|
|
2788
|
+
if (value === "win32") return "windows";
|
|
2789
|
+
return "other";
|
|
2790
|
+
}
|
|
2791
|
+
function normalizeArchitecture(value) {
|
|
2792
|
+
return value === "arm64" || value === "x64" ? value : "other";
|
|
2793
|
+
}
|
|
2794
|
+
//#endregion
|
|
2529
2795
|
//#region src/index.ts
|
|
2530
2796
|
const templateDetails = {
|
|
2531
2797
|
basic: {
|
|
@@ -2668,6 +2934,7 @@ function integrationTemplate(input) {
|
|
|
2668
2934
|
}
|
|
2669
2935
|
async function createApp(projectName, options = {}) {
|
|
2670
2936
|
require_utils.showBanner();
|
|
2937
|
+
await showFarmTelemetryNotice();
|
|
2671
2938
|
const templates = await getAvailableTemplates();
|
|
2672
2939
|
if (templates.length === 0) {
|
|
2673
2940
|
require_utils.logger.error("No templates are available in this package.");
|
|
@@ -2826,6 +3093,14 @@ async function createApp(projectName, options = {}) {
|
|
|
2826
3093
|
if (integrationResult.env.length) require_utils.logger.info("Copy .env.example to .env.local and add your provider credentials.");
|
|
2827
3094
|
for (const note of integrationResult.notes) require_utils.logger.info(note);
|
|
2828
3095
|
}
|
|
3096
|
+
await trackFarmProjectCreated({
|
|
3097
|
+
packageVersion: options.telemetryPackageVersion ?? "unknown",
|
|
3098
|
+
template,
|
|
3099
|
+
renderer,
|
|
3100
|
+
packageManager: packageManager.name,
|
|
3101
|
+
typescript: useTypeScript,
|
|
3102
|
+
installedDependencies: !options.skipInstall
|
|
3103
|
+
});
|
|
2829
3104
|
}
|
|
2830
3105
|
async function copyTemplate(template, projectPath, useTypeScript, renderer) {
|
|
2831
3106
|
const details = templateDetails[template];
|
|
@@ -3011,9 +3286,9 @@ async function copyDir(src, dest) {
|
|
|
3011
3286
|
else await fs_promises.default.copyFile(srcPath, destPath);
|
|
3012
3287
|
}
|
|
3013
3288
|
}
|
|
3014
|
-
async function dirExists(path$
|
|
3289
|
+
async function dirExists(path$5) {
|
|
3015
3290
|
try {
|
|
3016
|
-
return (await fs_promises.default.stat(path$
|
|
3291
|
+
return (await fs_promises.default.stat(path$5)).isDirectory();
|
|
3017
3292
|
} catch {
|
|
3018
3293
|
return false;
|
|
3019
3294
|
}
|