@powerhousedao/shared 6.0.0-dev.182 → 6.0.0-dev.184

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.
@@ -3,8 +3,9 @@ import { array, boolean, command, flag, multioption, number, oneOf, option, opti
3
3
  import { AGENTS, detect, resolveCommand } from "package-manager-detector";
4
4
  import { homedir } from "node:os";
5
5
  import path, { join } from "node:path";
6
- import { readFileSync } from "node:fs";
6
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
7
7
  import "@sindresorhus/fnv1a";
8
+ import { esmExternalRequirePlugin } from "rolldown/plugins";
8
9
  import chalk from "chalk";
9
10
  import fsPromises, { stat } from "node:fs/promises";
10
11
  import { fileURLToPath } from "node:url";
@@ -565,6 +566,11 @@ const installArgs = {
565
566
  long: "registry",
566
567
  description: "Registry URL to install from (overrides config and environment)"
567
568
  }),
569
+ local: flag({
570
+ type: optional(boolean),
571
+ long: "local",
572
+ description: "Also install packages into node_modules (marks them as provider: \"local\" so they get bundled into ph connect build)"
573
+ }),
568
574
  ...packageManagerArgs,
569
575
  ...debugArgs
570
576
  };
@@ -931,6 +937,12 @@ const entry = [
931
937
  "processors/*/index.ts"
932
938
  ];
933
939
  const alwaysBundle = ["**"];
940
+ const reactExternals = [
941
+ "react",
942
+ "react-dom",
943
+ "react/jsx-runtime",
944
+ "react-dom/client"
945
+ ];
934
946
  const nodeNeverBundle = [
935
947
  "@powerhousedao/connect",
936
948
  "@powerhousedao/ph-cli",
@@ -950,7 +962,7 @@ const nodeNeverBundle = [
950
962
  "@types/react",
951
963
  "@types/react-dom"
952
964
  ];
953
- const browserNeverBundle = [...nodeNeverBundle, "@powerhousedao/reactor-api"];
965
+ const browserNeverBundle = [...nodeNeverBundle.filter((m) => !reactExternals.includes(m)), "@powerhousedao/reactor-api"];
954
966
  const copy = [{
955
967
  from: "powerhouse.manifest.json",
956
968
  to: "dist"
@@ -970,7 +982,9 @@ const browserBuildConfig = {
970
982
  config,
971
983
  clean: clean$1,
972
984
  dts,
973
- sourcemap
985
+ sourcemap,
986
+ plugins: esmExternalRequirePlugin({ external: reactExternals }),
987
+ inputOptions: { experimental: { resolveNewUrlToAsset: true } }
974
988
  };
975
989
  const nodeBuildConfig = {
976
990
  entry,
@@ -6886,6 +6900,183 @@ PH CLI package manager: ${packageManager}
6886
6900
  `.trim();
6887
6901
  }
6888
6902
  //#endregion
6903
+ //#region clis/services/telemetry.ts
6904
+ /**
6905
+ * CLI telemetry (error reporting via Sentry).
6906
+ *
6907
+ * Design:
6908
+ * - Opt-out by default, asked once on first interactive run.
6909
+ * - Stores consent in ~/.ph/telemetry.json so we never ask twice.
6910
+ * - Respects PH_NO_TELEMETRY=1 and DO_NOT_TRACK=1 as immediate kill switches.
6911
+ * - Non-interactive (TTY missing, CI, piped) defaults to DISABLED — we don't
6912
+ * want to hang a CI pipeline on an unanswered prompt, and we don't want to
6913
+ * capture errors without informed consent.
6914
+ * - DSN is published in the CLI binary; Sentry DSNs accept events but grant
6915
+ * no read access, so this is safe. Hardcoded so users can't accidentally
6916
+ * misroute events.
6917
+ *
6918
+ * PII scrubbing in beforeSend hook:
6919
+ * - Home-directory paths collapsed to ~
6920
+ * - Flag/arg values that look like secrets (tokens, keys) stripped
6921
+ * - No source-context from user files
6922
+ */
6923
+ const SENTRY_DSN = "https://0e7793802288589b4923896118374462@sentry.monitoring.vetra.io/3";
6924
+ const TELEMETRY_FILE = join(homedir(), ".ph", "telemetry.json");
6925
+ function isExplicitlyDisabled() {
6926
+ return process.env.PH_NO_TELEMETRY === "1" || process.env.PH_NO_TELEMETRY === "true" || process.env.DO_NOT_TRACK === "1" || process.env.DO_NOT_TRACK === "true";
6927
+ }
6928
+ function isExplicitlyEnabled() {
6929
+ return process.env.PH_TELEMETRY === "1" || process.env.PH_TELEMETRY === "true";
6930
+ }
6931
+ function isInteractive() {
6932
+ return Boolean(process.stdin.isTTY) && !process.env.CI;
6933
+ }
6934
+ function readConfig() {
6935
+ try {
6936
+ if (!existsSync(TELEMETRY_FILE)) return null;
6937
+ return JSON.parse(readFileSync(TELEMETRY_FILE, "utf8"));
6938
+ } catch {
6939
+ return null;
6940
+ }
6941
+ }
6942
+ function writeConfig(cfg) {
6943
+ try {
6944
+ mkdirSync(join(homedir(), ".ph"), { recursive: true });
6945
+ writeFileSync(TELEMETRY_FILE, JSON.stringify(cfg, null, 2));
6946
+ } catch {}
6947
+ }
6948
+ /**
6949
+ * Prompts the user once, caches the answer. Must be called before init.
6950
+ * Returns `true` if telemetry should be enabled, `false` otherwise.
6951
+ */
6952
+ async function resolveTelemetryConsent() {
6953
+ if (isExplicitlyDisabled()) return false;
6954
+ if (isExplicitlyEnabled()) return true;
6955
+ const cached = readConfig();
6956
+ if (cached) return cached.enabled;
6957
+ if (!isInteractive()) return false;
6958
+ const enquirer = await import("enquirer");
6959
+ try {
6960
+ const { enabled } = await enquirer.default.prompt({
6961
+ type: "confirm",
6962
+ name: "enabled",
6963
+ message: "Help improve Powerhouse by sending anonymous error reports? (stack traces only, paths and secrets are scrubbed)",
6964
+ initial: true
6965
+ });
6966
+ writeConfig({
6967
+ enabled,
6968
+ askedAt: (/* @__PURE__ */ new Date()).toISOString()
6969
+ });
6970
+ return enabled;
6971
+ } catch {
6972
+ return false;
6973
+ }
6974
+ }
6975
+ function scrubString(input) {
6976
+ if (!input) return input;
6977
+ const home = homedir();
6978
+ let out = input;
6979
+ if (home && out.includes(home)) out = out.split(home).join("~");
6980
+ out = out.replace(/(--?(?:token|api[-_]?key|password|secret|auth)[=\s])([^\s]+)/gi, "$1<redacted>");
6981
+ return out;
6982
+ }
6983
+ function scrubEvent(event) {
6984
+ try {
6985
+ if (event.message) event.message = scrubString(event.message);
6986
+ if (event.logentry?.message) event.logentry.message = scrubString(event.logentry.message);
6987
+ if (Array.isArray(event.exception?.values)) for (const ex of event.exception.values) {
6988
+ if (ex.value) ex.value = scrubString(ex.value);
6989
+ if (Array.isArray(ex.stacktrace?.frames)) for (const f of ex.stacktrace.frames) {
6990
+ if (f.filename) f.filename = scrubString(f.filename);
6991
+ if (f.abs_path) f.abs_path = scrubString(f.abs_path);
6992
+ delete f.pre_context;
6993
+ delete f.context_line;
6994
+ delete f.post_context;
6995
+ delete f.vars;
6996
+ }
6997
+ }
6998
+ delete event.server_name;
6999
+ if (event.extra) {
7000
+ delete event.extra.argv;
7001
+ delete event.extra.env;
7002
+ }
7003
+ } catch {}
7004
+ return event;
7005
+ }
7006
+ let initialized = false;
7007
+ /**
7008
+ * Initializes Sentry for CLI error reporting if telemetry is enabled.
7009
+ * Safe to call multiple times; only the first call takes effect.
7010
+ */
7011
+ async function initCliTelemetry(opts) {
7012
+ if (initialized) return;
7013
+ if (!await resolveTelemetryConsent()) return;
7014
+ const Sentry = await import("@sentry/node");
7015
+ Sentry.init({
7016
+ dsn: SENTRY_DSN,
7017
+ release: opts.release,
7018
+ environment: process.env.NODE_ENV || "production",
7019
+ sendDefaultPii: false,
7020
+ autoSessionTracking: false,
7021
+ defaultIntegrations: false,
7022
+ integrations: [],
7023
+ beforeSend(event) {
7024
+ return scrubEvent(event);
7025
+ },
7026
+ beforeBreadcrumb(breadcrumb) {
7027
+ if (breadcrumb.message) breadcrumb.message = scrubString(breadcrumb.message);
7028
+ return breadcrumb;
7029
+ }
7030
+ });
7031
+ Sentry.setTag("cli_name", opts.cliName);
7032
+ if (opts.release) Sentry.setTag("cli_version", opts.release);
7033
+ initialized = true;
7034
+ }
7035
+ /**
7036
+ * Captures an error (if telemetry is initialized) and flushes before the
7037
+ * caller calls process.exit(). Safe no-op when telemetry is disabled.
7038
+ */
7039
+ async function captureCliError(err) {
7040
+ if (!initialized) return;
7041
+ try {
7042
+ const Sentry = await import("@sentry/node");
7043
+ Sentry.captureException(err);
7044
+ await Sentry.flush(2e3);
7045
+ } catch {}
7046
+ }
7047
+ /**
7048
+ * Explicitly set telemetry consent (used by `ph telemetry on|off`).
7049
+ */
7050
+ function setTelemetryConsent(enabled) {
7051
+ writeConfig({
7052
+ enabled,
7053
+ askedAt: (/* @__PURE__ */ new Date()).toISOString()
7054
+ });
7055
+ }
7056
+ /**
7057
+ * Returns the current telemetry state — useful for `ph telemetry status`.
7058
+ */
7059
+ function getTelemetryStatus() {
7060
+ if (isExplicitlyDisabled()) return {
7061
+ source: "env",
7062
+ enabled: false
7063
+ };
7064
+ if (isExplicitlyEnabled()) return {
7065
+ source: "env",
7066
+ enabled: true
7067
+ };
7068
+ const cached = readConfig();
7069
+ if (cached) return {
7070
+ source: "config",
7071
+ enabled: cached.enabled,
7072
+ askedAt: cached.askedAt
7073
+ };
7074
+ return {
7075
+ source: "default",
7076
+ enabled: false
7077
+ };
7078
+ }
7079
+ //#endregion
6889
7080
  //#region constants.ts
6890
7081
  const PACKAGES_DEPENDENCIES = [
6891
7082
  "@powerhousedao/builder-tools",
@@ -7002,6 +7193,6 @@ function assertNodeVersion(nodeVersion = process.versions.node) {
7002
7193
  if ((0, import_semver.lt)(nodeVersion, "24.0.0")) throw new NodeVersionError(nodeVersion, MINIMUM_NODE_VERSION);
7003
7194
  }
7004
7195
  //#endregion
7005
- export { DEFAULT_CONFIG, DEFAULT_CONNECT_OUTDIR, DEFAULT_CONNECT_PREVIEW_PORT, DEFAULT_CONNECT_STUDIO_PORT, DEFAULT_EXPIRY_DAYS, DEFAULT_EXPIRY_SECONDS, DEFAULT_REGISTRY_URL, DEFAULT_RENOWN_URL, DEFAULT_SWITCHBOARD_PORT, DEFAULT_TIMEOUT, DEFAULT_VETRA_CONNECT_PORT, DEFAULT_VETRA_DRIVE_ID, DRIVES_PRESERVE_STRATEGIES, HOME_DIR, LOG_LEVELS, MINIMUM_NODE_VERSION, NodeVersionError, PH_BIN, PH_GLOBAL_DIR_NAME, PH_GLOBAL_PROJECT_NAME, POWERHOUSE_CONFIG_FILE, POWERHOUSE_GLOBAL_DIR, SECONDS_IN_DAY, SERVICE_ACTIONS, VERSIONED_DEPENDENCIES, VERSIONED_DEV_DEPENDENCIES, accessTokenArgs, assertNodeVersion, browserBuildConfig, buildArgs, commonArgs, commonServerArgs, connectArgs, connectBasePath, connectBuildArgs, connectPreviewArgs, connectStudioArgs, debugArgs, defaultDrivesUrl, directoryExists, disableLocalPackages, drivesPreserveStrategy, fetchNpmVersionFromRegistryForTag, fetchPackageVersionFromNpmRegistry, fileExists, force, generateArgs, getConfig, getGlobalPowerhouseProjectDirPath, getLocalPowerhouseProjectDirPath, getPackageManagerAtPowerhouseProjectDirPath, getPackageManagerCommand, getPackageVersionFromPackageJson, getPhCliVersionInfo, getPhCmdVersionInfo, getPowerhouseProjectInfo, getPowerhouseProjectInstallCommand, getPowerhouseProjectUninstallCommand, getTagFromVersion, handleMutuallyExclusiveOptions, https, httpsCertFile, httpsKeyFile, initArgs, inspectArgs, installArgs, isPowerhouseProject, listArgs, localPackage, logLevel, logVersionUpdate, loginArgs, makeDependenciesWithVersions, makeVersionedDependencies, migrateArgs, nodeBuildConfig, packageManagerArgs, packages, parsePackageManager, parsePackageVersion, parseTag, phCliCommandNames, phCliHelpCommands, publishArgs, runCmd, runUseLocal, serviceArgs, spawnAsync, switchboardArgs, uninstallArgs, vetraArgs, vetraSwitchboardArgs };
7196
+ export { DEFAULT_CONFIG, DEFAULT_CONNECT_OUTDIR, DEFAULT_CONNECT_PREVIEW_PORT, DEFAULT_CONNECT_STUDIO_PORT, DEFAULT_EXPIRY_DAYS, DEFAULT_EXPIRY_SECONDS, DEFAULT_REGISTRY_URL, DEFAULT_RENOWN_URL, DEFAULT_SWITCHBOARD_PORT, DEFAULT_TIMEOUT, DEFAULT_VETRA_CONNECT_PORT, DEFAULT_VETRA_DRIVE_ID, DRIVES_PRESERVE_STRATEGIES, HOME_DIR, LOG_LEVELS, MINIMUM_NODE_VERSION, NodeVersionError, PH_BIN, PH_GLOBAL_DIR_NAME, PH_GLOBAL_PROJECT_NAME, POWERHOUSE_CONFIG_FILE, POWERHOUSE_GLOBAL_DIR, SECONDS_IN_DAY, SERVICE_ACTIONS, VERSIONED_DEPENDENCIES, VERSIONED_DEV_DEPENDENCIES, accessTokenArgs, assertNodeVersion, browserBuildConfig, buildArgs, captureCliError, commonArgs, commonServerArgs, connectArgs, connectBasePath, connectBuildArgs, connectPreviewArgs, connectStudioArgs, debugArgs, defaultDrivesUrl, directoryExists, disableLocalPackages, drivesPreserveStrategy, fetchNpmVersionFromRegistryForTag, fetchPackageVersionFromNpmRegistry, fileExists, force, generateArgs, getConfig, getGlobalPowerhouseProjectDirPath, getLocalPowerhouseProjectDirPath, getPackageManagerAtPowerhouseProjectDirPath, getPackageManagerCommand, getPackageVersionFromPackageJson, getPhCliVersionInfo, getPhCmdVersionInfo, getPowerhouseProjectInfo, getPowerhouseProjectInstallCommand, getPowerhouseProjectUninstallCommand, getTagFromVersion, getTelemetryStatus, handleMutuallyExclusiveOptions, https, httpsCertFile, httpsKeyFile, initArgs, initCliTelemetry, inspectArgs, installArgs, isPowerhouseProject, listArgs, localPackage, logLevel, logVersionUpdate, loginArgs, makeDependenciesWithVersions, makeVersionedDependencies, migrateArgs, nodeBuildConfig, packageManagerArgs, packages, parsePackageManager, parsePackageVersion, parseTag, phCliCommandNames, phCliHelpCommands, publishArgs, resolveTelemetryConsent, runCmd, runUseLocal, serviceArgs, setTelemetryConsent, spawnAsync, switchboardArgs, uninstallArgs, vetraArgs, vetraSwitchboardArgs };
7006
7197
 
7007
7198
  //# sourceMappingURL=index.mjs.map