@arcote.tech/arc-cli 0.7.8 → 0.7.9

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.js CHANGED
@@ -25818,6 +25818,7 @@ __export(exports_init_server, {
25818
25818
  wrapDbAdapter: () => wrapDbAdapter,
25819
25819
  initServerTelemetry: () => initServerTelemetry
25820
25820
  });
25821
+ import { diag, DiagConsoleLogger, DiagLogLevel } from "@opentelemetry/api";
25821
25822
  import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
25822
25823
  import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
25823
25824
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
@@ -26131,6 +26132,9 @@ function wrapDbAdapter(adapter, telemetry, dbSystem) {
26131
26132
  }
26132
26133
  function initServerTelemetry(config) {
26133
26134
  const telemetry = new ArcTelemetry({ ...config, environment: "server" });
26135
+ if (telemetry.config.debug) {
26136
+ diag.setLogger(new DiagConsoleLogger, DiagLogLevel.ALL);
26137
+ }
26134
26138
  if (!telemetry.config.enabled) {
26135
26139
  return { telemetry, shutdown: async () => {} };
26136
26140
  }
@@ -26179,7 +26183,8 @@ function initServerTelemetry(config) {
26179
26183
  serviceName: config.serviceName,
26180
26184
  endpoint,
26181
26185
  sampleRate: telemetry.config.sampleRate,
26182
- mode: telemetry.config.mode
26186
+ mode: telemetry.config.mode,
26187
+ active: telemetry.active
26183
26188
  });
26184
26189
  }
26185
26190
  const shutdown = async () => {
@@ -35013,8 +35018,11 @@ var TAILWIND_INPUT_TEMPLATE = (rootRel) => `@import "tailwindcss";
35013
35018
 
35014
35019
  @source "${rootRel}/packages/*/*.{ts,tsx}";
35015
35020
  @source "${rootRel}/packages/*/src/**/*.{ts,tsx}";
35016
- @source "${rootRel}/node_modules/@arcote.tech/platform/src/**/*.{ts,tsx}";
35017
- @source "${rootRel}/node_modules/@arcote.tech/arc-ds/src/**/*.{ts,tsx}";
35021
+ /* Skanuj wszystkie framework packages \u2014 fragmenty (arc-chat, arc-ai-voice\u2026)
35022
+ wnosz\u0105 w\u0142asne komponenty React z klasami Tailwind, kt\xF3re musz\u0105 trafi\u0107 do
35023
+ CSS. Bez tego absolute positioning, color/border klasy w nowych fragmentach
35024
+ s\u0105 ignorowane \u2014 komponent renderuje si\u0119 bez styl\xF3w. */
35025
+ @source "${rootRel}/node_modules/@arcote.tech/*/src/**/*.{ts,tsx}";
35018
35026
 
35019
35027
  @custom-variant dark (&:is(.dark *));
35020
35028
 
@@ -35281,11 +35289,21 @@ function collectFrameworkDeps(arcDir, rootDir, packages, sharedDeps = []) {
35281
35289
  } catch (e) {
35282
35290
  console.warn(`[arc-otel] could not resolve @arcote.tech/arc-otel \u2014 image will run without telemetry deps: ${e.message}`);
35283
35291
  }
35292
+ let rootArc;
35293
+ const rootPkgPath = join10(rootDir, "package.json");
35294
+ if (existsSync9(rootPkgPath)) {
35295
+ try {
35296
+ const rootPkg = JSON.parse(readFileSync9(rootPkgPath, "utf-8"));
35297
+ if (rootPkg.arc && typeof rootPkg.arc === "object")
35298
+ rootArc = rootPkg.arc;
35299
+ } catch {}
35300
+ }
35284
35301
  const manifest = {
35285
35302
  name: "arc-platform-framework",
35286
35303
  private: true,
35287
35304
  type: "module",
35288
- dependencies: versions
35305
+ dependencies: versions,
35306
+ ...rootArc ? { arc: rootArc } : {}
35289
35307
  };
35290
35308
  const manifestPath = join10(arcDir, "package.json");
35291
35309
  writeFileSync8(manifestPath, JSON.stringify(manifest, null, 2) + `
@@ -36114,6 +36132,10 @@ function generateCompose({ cfg }) {
36114
36132
  lines.push(" retries: 20");
36115
36133
  lines.push(" networks:");
36116
36134
  lines.push(" - arc-net");
36135
+ if (env2.db.exposeOnLoopback !== undefined) {
36136
+ lines.push(" ports:");
36137
+ lines.push(` - "127.0.0.1:${env2.db.exposeOnLoopback}:5432"`);
36138
+ }
36117
36139
  lines.push("");
36118
36140
  }
36119
36141
  if (cfg.observability?.enabled) {
@@ -36303,7 +36325,10 @@ processors:
36303
36325
  send_batch_max_size: 1024
36304
36326
 
36305
36327
  # Tail-based sampling \u2014 applied after a full trace has been assembled.
36306
- # Errors and slow traces are kept 100%, everything else at 10%.
36328
+ # Errors + slow traces zachowywane w 100%, normalne traces r\xF3wnie\u017C 100%
36329
+ # przy obecnej skali (boostrap produkcji). Tail sampling matchuje OR po
36330
+ # policies \u2014 bez "always" policy WSZYSTKIE OK traces by\u0142yby droppowane.
36331
+ # Obni\u017C 'random_100pct' do np. 10% gdy ruch eksploduje.
36307
36332
  tail_sampling:
36308
36333
  decision_wait: 10s
36309
36334
  num_traces: 50000
@@ -36315,9 +36340,9 @@ processors:
36315
36340
  - name: slow
36316
36341
  type: latency
36317
36342
  latency: { threshold_ms: 500 }
36318
- - name: random_10pct
36343
+ - name: random_100pct
36319
36344
  type: probabilistic
36320
- probabilistic: { sampling_percentage: 10 }
36345
+ probabilistic: { sampling_percentage: 100 }
36321
36346
 
36322
36347
  # Drop high-cardinality / PII attributes that might slip past app-side
36323
36348
  # sanitization. Belt-and-suspenders before they hit long-term storage.
@@ -37236,7 +37261,8 @@ function validateDeployConfig(input) {
37236
37261
  } else if (dbType === "postgres") {
37237
37262
  db = {
37238
37263
  type: "postgres",
37239
- image: optionalString(dbRaw, `envs.${name}.db.image`)
37264
+ image: optionalString(dbRaw, `envs.${name}.db.image`),
37265
+ exposeOnLoopback: optionalNumber(dbRaw, `envs.${name}.db.exposeOnLoopback`)
37240
37266
  };
37241
37267
  } else {
37242
37268
  throw new Error(`deploy.arc.json: envs.${name}.db.type must be "sqlite" or "postgres" (got "${dbType}")`);
@@ -40636,7 +40662,7 @@ function staticFilesHandler(ws, devMode, getManifest) {
40636
40662
  return null;
40637
40663
  };
40638
40664
  }
40639
- function apiEndpointsHandler(ws, getManifest, cm, moduleAccessMap) {
40665
+ function apiEndpointsHandler(ws, getManifest, cm, moduleAccessMap, telemetry) {
40640
40666
  return (req, url, ctx) => {
40641
40667
  if (url.pathname === "/api/modules") {
40642
40668
  const arcTokensHeader = req.headers.get("X-Arc-Tokens");
@@ -40656,7 +40682,11 @@ function apiEndpointsHandler(ws, getManifest, cm, moduleAccessMap) {
40656
40682
  return Response.json({
40657
40683
  status: "ok",
40658
40684
  groups: Object.keys(getManifest().groups).length,
40659
- clients: cm?.clientCount ?? 0
40685
+ clients: cm?.clientCount ?? 0,
40686
+ otel: {
40687
+ enabled: telemetry?.config.enabled ?? false,
40688
+ active: telemetry?.active ?? false
40689
+ }
40660
40690
  }, { headers: ctx.corsHeaders });
40661
40691
  }
40662
40692
  return null;
@@ -40707,7 +40737,8 @@ async function startPlatformServer(opts) {
40707
40737
  environment: "server",
40708
40738
  endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
40709
40739
  mode: devMode ? "development" : "production",
40710
- sampleRate: devMode ? 1 : 1
40740
+ sampleRate: devMode ? 1 : 1,
40741
+ debug: process.env.ARC_OTEL_DEBUG === "true"
40711
40742
  });
40712
40743
  telemetry = init2.telemetry;
40713
40744
  telemetryShutdown = init2.shutdown;
@@ -40757,7 +40788,7 @@ async function startPlatformServer(opts) {
40757
40788
  corsHeaders: cors
40758
40789
  };
40759
40790
  const handlers = [
40760
- apiEndpointsHandler(ws, getManifest, null, moduleAccessMap),
40791
+ apiEndpointsHandler(ws, getManifest, null, moduleAccessMap, telemetry),
40761
40792
  devReloadHandler(sseClients),
40762
40793
  staticFilesHandler(ws, !!devMode, getManifest),
40763
40794
  spaFallbackHandler(getShellHtml)
@@ -40795,7 +40826,7 @@ async function startPlatformServer(opts) {
40795
40826
  dbAdapterFactory,
40796
40827
  port,
40797
40828
  httpHandlers: [
40798
- apiEndpointsHandler(ws, getManifest, null, moduleAccessMap),
40829
+ apiEndpointsHandler(ws, getManifest, null, moduleAccessMap, telemetry),
40799
40830
  devReloadHandler(sseClients),
40800
40831
  staticFilesHandler(ws, !!devMode, getManifest),
40801
40832
  spaFallbackHandler(getShellHtml)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcote.tech/arc-cli",
3
- "version": "0.7.8",
3
+ "version": "0.7.9",
4
4
  "description": "CLI tool for Arc framework",
5
5
  "module": "index.ts",
6
6
  "main": "dist/index.js",
@@ -12,13 +12,13 @@
12
12
  "build": "bun build --target=bun ./src/index.ts --outdir=dist --external @arcote.tech/arc --external @arcote.tech/arc-ds --external @arcote.tech/arc-react --external @arcote.tech/platform --external '@opentelemetry/*' && chmod +x dist/index.js"
13
13
  },
14
14
  "dependencies": {
15
- "@arcote.tech/arc": "^0.7.8",
16
- "@arcote.tech/arc-ds": "^0.7.8",
17
- "@arcote.tech/arc-react": "^0.7.8",
18
- "@arcote.tech/arc-host": "^0.7.8",
19
- "@arcote.tech/arc-adapter-db-sqlite": "^0.7.8",
20
- "@arcote.tech/arc-adapter-db-postgres": "^0.7.8",
21
- "@arcote.tech/arc-otel": "^0.7.8",
15
+ "@arcote.tech/arc": "^0.7.9",
16
+ "@arcote.tech/arc-ds": "^0.7.9",
17
+ "@arcote.tech/arc-react": "^0.7.9",
18
+ "@arcote.tech/arc-host": "^0.7.9",
19
+ "@arcote.tech/arc-adapter-db-sqlite": "^0.7.9",
20
+ "@arcote.tech/arc-adapter-db-postgres": "^0.7.9",
21
+ "@arcote.tech/arc-otel": "^0.7.9",
22
22
  "@opentelemetry/api": "^1.9.0",
23
23
  "@opentelemetry/api-logs": "^0.57.0",
24
24
  "@opentelemetry/core": "^1.30.0",
@@ -31,7 +31,7 @@
31
31
  "@opentelemetry/sdk-trace-base": "^1.30.0",
32
32
  "@opentelemetry/sdk-trace-node": "^1.30.0",
33
33
  "@opentelemetry/semantic-conventions": "^1.27.0",
34
- "@arcote.tech/platform": "^0.7.8",
34
+ "@arcote.tech/platform": "^0.7.9",
35
35
  "@clack/prompts": "^0.9.0",
36
36
  "commander": "^11.1.0",
37
37
  "chokidar": "^3.5.3",
@@ -79,11 +79,27 @@ export function collectFrameworkDeps(
79
79
  `[arc-otel] could not resolve @arcote.tech/arc-otel — image will run without telemetry deps: ${(e as Error).message}`,
80
80
  );
81
81
  }
82
+ // Pole `arc` z root package.json (translations, theme, manifest...) musi
83
+ // trafić do obrazu runtime — `readTranslationsConfig` w server.ts czyta je
84
+ // z `ws.rootDir/package.json` (czyli /app/package.json w obrazie). Bez
85
+ // przepisania `/api/translations` zwraca pustą listę locale, `useI18nConfig`
86
+ // w PlatformApp nie ustawia stanu, `I18nProvider` nie zostaje mountowany
87
+ // i każde `useI18n()` wyrzuca błąd na produkcji.
88
+ let rootArc: unknown;
89
+ const rootPkgPath = join(rootDir, "package.json");
90
+ if (existsSync(rootPkgPath)) {
91
+ try {
92
+ const rootPkg = JSON.parse(readFileSync(rootPkgPath, "utf-8")) as Record<string, unknown>;
93
+ if (rootPkg.arc && typeof rootPkg.arc === "object") rootArc = rootPkg.arc;
94
+ } catch {}
95
+ }
96
+
82
97
  const manifest = {
83
98
  name: "arc-platform-framework",
84
99
  private: true,
85
100
  type: "module" as const,
86
101
  dependencies: versions,
102
+ ...(rootArc ? { arc: rootArc } : {}),
87
103
  };
88
104
  const manifestPath = join(arcDir, "package.json");
89
105
  writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
@@ -722,8 +722,11 @@ const TAILWIND_INPUT_TEMPLATE = (rootRel: string) => `@import "tailwindcss";
722
722
 
723
723
  @source "${rootRel}/packages/*/*.{ts,tsx}";
724
724
  @source "${rootRel}/packages/*/src/**/*.{ts,tsx}";
725
- @source "${rootRel}/node_modules/@arcote.tech/platform/src/**/*.{ts,tsx}";
726
- @source "${rootRel}/node_modules/@arcote.tech/arc-ds/src/**/*.{ts,tsx}";
725
+ /* Skanuj wszystkie framework packages — fragmenty (arc-chat, arc-ai-voice…)
726
+ wnoszą własne komponenty React z klasami Tailwind, które muszą trafić do
727
+ CSS. Bez tego absolute positioning, color/border klasy w nowych fragmentach
728
+ są ignorowane — komponent renderuje się bez stylów. */
729
+ @source "${rootRel}/node_modules/@arcote.tech/*/src/**/*.{ts,tsx}";
727
730
 
728
731
  @custom-variant dark (&:is(.dark *));
729
732
 
@@ -164,8 +164,15 @@ export function generateCompose({ cfg }: ComposeOptions): string {
164
164
  lines.push(" retries: 20");
165
165
  lines.push(" networks:");
166
166
  lines.push(" - arc-net");
167
- // No `ports:` — the database is only reachable from other containers
168
- // on `arc-net`. Exposing 5432 to the host would defeat the isolation.
167
+ // `ports:` is omitted by default — the database is only reachable from
168
+ // other containers on `arc-net`. When `exposeOnLoopback` is set in
169
+ // deploy.arc.json, bind to `127.0.0.1:<n>:5432` on the host so SSH
170
+ // tunneling (DBeaver/psql via `ssh -L`) works without exposing the
171
+ // port to the public internet (ufw only opens 22/80/443).
172
+ if (env.db.exposeOnLoopback !== undefined) {
173
+ lines.push(" ports:");
174
+ lines.push(` - "127.0.0.1:${env.db.exposeOnLoopback}:5432"`);
175
+ }
169
176
  lines.push("");
170
177
  }
171
178
 
@@ -31,7 +31,21 @@ export interface DeployTarget {
31
31
  */
32
32
  export type DeployEnvDb =
33
33
  | { type: "sqlite" }
34
- | { type: "postgres"; image?: string };
34
+ | {
35
+ type: "postgres";
36
+ image?: string;
37
+ /**
38
+ * Bind the postgres port to `127.0.0.1:<n>` on the host. Container
39
+ * pozostaje niewystawiony do internetu (ufw przepuszcza tylko
40
+ * 22/80/443), ale staje się dostępny przez SSH tunnel
41
+ * (`ssh -L <n>:localhost:<n> deploy@host`) np. dla DBeavera.
42
+ *
43
+ * Per-env różne porty unikają kolizji gdy kilka środowisk dzieli
44
+ * jeden VPS. Pomiń pole żeby zachować pełną izolację (tylko docker
45
+ * network).
46
+ */
47
+ exposeOnLoopback?: number;
48
+ };
35
49
 
36
50
  export interface DeployEnv {
37
51
  /** Subdomain or full domain routed by Caddy. */
@@ -301,6 +315,10 @@ export function validateDeployConfig(input: unknown): DeployConfig {
301
315
  db = {
302
316
  type: "postgres",
303
317
  image: optionalString(dbRaw, `envs.${name}.db.image`),
318
+ exposeOnLoopback: optionalNumber(
319
+ dbRaw,
320
+ `envs.${name}.db.exposeOnLoopback`,
321
+ ),
304
322
  };
305
323
  } else {
306
324
  throw new Error(
@@ -13,9 +13,11 @@ import type { DeployConfig, DeployObservability } from "./config";
13
13
  // - logs: 7d retention (Loki chunks on local disk)
14
14
  // - metrics: 30d retention (Prometheus TSDB on local disk)
15
15
  //
16
- // Tail sampling: every error + every span >500ms + 10% random. Decided in
17
- // the collector so per-service SDKs can be left at always-on without
18
- // flooding the backend.
16
+ // Tail sampling: every error + every span >500ms + 100% random przy obecnej
17
+ // skali. Tail_sampling matchuje OR po policies bez "always" policy WSZYSTKIE
18
+ // OK traces byłyby droppowane (errors + slow nie obejmują happy path).
19
+ // Obniż `random_100pct` w `tail_sampling.policies` gdy backend zacznie się
20
+ // zatkać; do tego momentu lepiej widzieć wszystko.
19
21
  // ---------------------------------------------------------------------------
20
22
 
21
23
  const DEFAULT_RETENTION = {
@@ -60,7 +62,10 @@ processors:
60
62
  send_batch_max_size: 1024
61
63
 
62
64
  # Tail-based sampling — applied after a full trace has been assembled.
63
- # Errors and slow traces are kept 100%, everything else at 10%.
65
+ # Errors + slow traces zachowywane w 100%, normalne traces również 100%
66
+ # przy obecnej skali (boostrap produkcji). Tail sampling matchuje OR po
67
+ # policies — bez "always" policy WSZYSTKIE OK traces byłyby droppowane.
68
+ # Obniż 'random_100pct' do np. 10% gdy ruch eksploduje.
64
69
  tail_sampling:
65
70
  decision_wait: 10s
66
71
  num_traces: 50000
@@ -72,9 +77,9 @@ processors:
72
77
  - name: slow
73
78
  type: latency
74
79
  latency: { threshold_ms: 500 }
75
- - name: random_10pct
80
+ - name: random_100pct
76
81
  type: probabilistic
77
- probabilistic: { sampling_percentage: 10 }
82
+ probabilistic: { sampling_percentage: 100 }
78
83
 
79
84
  # Drop high-cardinality / PII attributes that might slip past app-side
80
85
  # sanitization. Belt-and-suspenders before they hit long-term storage.
@@ -415,6 +415,7 @@ function apiEndpointsHandler(
415
415
  getManifest: () => BuildManifest,
416
416
  cm: ConnectionManager | null,
417
417
  moduleAccessMap: Map<string, ModuleAccess>,
418
+ telemetry?: import("@arcote.tech/arc-otel").ArcTelemetry,
418
419
  ): ArcHttpHandler {
419
420
  return (req, url, ctx) => {
420
421
  if (url.pathname === "/api/modules") {
@@ -442,6 +443,16 @@ function apiEndpointsHandler(
442
443
  status: "ok",
443
444
  groups: Object.keys(getManifest().groups).length,
444
445
  clients: cm?.clientCount ?? 0,
446
+ otel: {
447
+ // `enabled` — `ARC_OTEL_ENABLED` w env i init przeszedł
448
+ // (telemetry obiekt istnieje, config.enabled === true).
449
+ // `active` — to samo + `attach()` wywołane (tracer ustawiony).
450
+ // Rozjazd między tymi flagami zwykle oznacza że
451
+ // `initServerTelemetry` przeszło na wczesny return z
452
+ // `config.enabled === false`.
453
+ enabled: telemetry?.config.enabled ?? false,
454
+ active: telemetry?.active ?? false,
455
+ },
445
456
  },
446
457
  { headers: ctx.corsHeaders },
447
458
  );
@@ -510,6 +521,7 @@ export async function startPlatformServer(
510
521
  endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
511
522
  mode: devMode ? "development" : "production",
512
523
  sampleRate: devMode ? 1.0 : 1.0, // head-based 100%, collector tail-samples
524
+ debug: process.env.ARC_OTEL_DEBUG === "true",
513
525
  });
514
526
  telemetry = init.telemetry;
515
527
  telemetryShutdown = init.shutdown;
@@ -572,7 +584,7 @@ export async function startPlatformServer(
572
584
 
573
585
  // Platform handlers only
574
586
  const handlers: ArcHttpHandler[] = [
575
- apiEndpointsHandler(ws, getManifest, null, moduleAccessMap),
587
+ apiEndpointsHandler(ws, getManifest, null, moduleAccessMap, telemetry),
576
588
  devReloadHandler(sseClients),
577
589
  staticFilesHandler(ws, !!devMode, getManifest),
578
590
  spaFallbackHandler(getShellHtml),
@@ -626,7 +638,7 @@ export async function startPlatformServer(
626
638
  port,
627
639
  httpHandlers: [
628
640
  // Platform-specific handlers (checked AFTER arc handlers)
629
- apiEndpointsHandler(ws, getManifest, null, moduleAccessMap),
641
+ apiEndpointsHandler(ws, getManifest, null, moduleAccessMap, telemetry),
630
642
  devReloadHandler(sseClients),
631
643
  staticFilesHandler(ws, !!devMode, getManifest),
632
644
  spaFallbackHandler(getShellHtml),