@prisma/composer 0.2.0-dev.17 → 0.2.0-dev.19

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.
@@ -5,7 +5,7 @@ import { Input, StackServices } from "alchemy";
5
5
  import * as Effect from "effect/Effect";
6
6
  import * as Layer from "effect/Layer";
7
7
  import { State } from "alchemy/State/State";
8
- //#region ../../0-framework/1-core/core/dist/app-config-B-mHQL-a.d.mts
8
+ //#region ../../0-framework/1-core/core/dist/app-config-Dw3r7sUa.d.mts
9
9
  //#region src/container-transport.d.ts
10
10
  /**
11
11
  * Carries resolved containers from the CLI process into the alchemy process
@@ -445,8 +445,10 @@ interface LocalTargetAttachment {
445
445
  readonly address: string;
446
446
  readonly url: string;
447
447
  }[]>;
448
- /** Merged, line-oriented log stream across the app's services (including services that appear after later converges). Ends when `signal` aborts. */
449
- logs(signal: AbortSignal): AsyncIterable<{
448
+ /** Merged, line-oriented log stream across the app's services (including services that appear after later converges). `opts.tail` is how many trailing lines of existing history to emit before live output (default 0 — live only). Ends when `signal` aborts. */
449
+ logs(signal: AbortSignal, opts?: {
450
+ readonly tail?: number;
451
+ }): AsyncIterable<{
450
452
  readonly service: string;
451
453
  readonly line: string;
452
454
  }>;
@@ -490,4 +492,4 @@ interface PrismaAppConfig {
490
492
  declare function defineConfig(config: PrismaAppConfig): PrismaAppConfig;
491
493
  //#endregion
492
494
  export { ProvisionerDescriptor as A, joinDeployment as B, Lowering as C, PreflightInput as D, PackageInput as E, containerEnv as F, lowering as H, containerEnvVarName as I, defineConfig as L, StateDescriptor as M, TeardownInput as N, PrismaAppConfig as O, buildConfig as P, deserializeContainers as R, LoweredResult as S, Outputs as T, mergedProviders as U, lower as V, resolveStateLayer as W, LocalTargetProvidersInput as _, Bundle as a, LowerError as b, DEV_DIR as c, DeploymentResult as d, ExtensionDescriptor as f, LocalTargetEmulatorsInput as g, LocalTargetDescriptor as h, AssembleInput as i, ServiceLowering as j, ProvisionEdge as k, DeployedEntity as l, LocalTargetAttachment as m, ApplicationDescriptor as n, ContainerDescriptor as o, LocalTargetAttachInput as p, Artifact as r, ContainerInstance as s, AlchemyStateLayer as t, DeployedNode as u, LocateContainerInput as v, NodeDescriptor as w, LowerOptions as x, LowerContext as y, isBuildOnlyExtension as z };
493
- //# sourceMappingURL=app-config-B-mHQL-a-CPD39ljh.d.mts.map
495
+ //# sourceMappingURL=app-config-Dw3r7sUa-D3dr8rg2.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-config-B-mHQL-a-CPD39ljh.d.mts","names":[],"sources":["../../../0-framework/1-core/core/dist/app-config-B-mHQL-a.d.mts"],"mappings":"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"}
1
+ {"version":3,"file":"app-config-Dw3r7sUa-D3dr8rg2.d.mts","names":[],"sources":["../../../0-framework/1-core/core/dist/app-config-Dw3r7sUa.d.mts"],"mappings":"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"}
package/dist/bin.mjs CHANGED
@@ -2220,7 +2220,7 @@ var esm_default = {
2220
2220
  FSWatcher
2221
2221
  };
2222
2222
  //#endregion
2223
- //#region ../../0-framework/3-tooling/cli/dist/cli-B3LcFQLH.mjs
2223
+ //#region ../../0-framework/3-tooling/cli/dist/cli-CH8Ewf_a.mjs
2224
2224
  /**
2225
2225
  * A user-facing failure with a message that already names the fix (deploy-cli.md
2226
2226
  * § Error surface). `bin.ts` catches this — and any other Error, including
@@ -2395,6 +2395,27 @@ function validateRegistryCoverage(graph, config) {
2395
2395
  * cannot drift.
2396
2396
  */
2397
2397
  /**
2398
+ * The pipeline's front — config discovery/load, entry load, name resolution —
2399
+ * WITHOUT Load, coverage, or assemble. `log` needs only who the app is (its
2400
+ * config and resolved name) to reach the already-running local instance; it
2401
+ * neither builds nor provisions, so it must not require the user's built
2402
+ * output the way the full pipeline does.
2403
+ */
2404
+ async function resolveAppIdentity(entry, overrideName, cwd, deps = {}) {
2405
+ const resolvedEntryPath = path.resolve(cwd, entry);
2406
+ const configPath = findConfigPathForEntry(resolvedEntryPath);
2407
+ if (configPath === void 0) throw missingConfigError(resolvedEntryPath);
2408
+ const config = deps.config ?? (await loadAppConfig(configPath)).config;
2409
+ const entryModule = await loadEntry(entry, cwd);
2410
+ const name = overrideName ?? entryModule.root.name;
2411
+ if (name.length === 0) throw new CliError("The root node has no name — name it at authoring, or pass --name.");
2412
+ return {
2413
+ configPath,
2414
+ config,
2415
+ name
2416
+ };
2417
+ }
2418
+ /**
2398
2419
  * Runs config discovery/load, entry load, Load, registry coverage, name
2399
2420
  * resolution, and assemble — steps 1–6 of `run()`. `onAssembleError`, when
2400
2421
  * given, lets a caller decorate an assemble failure with command-specific
@@ -2656,7 +2677,7 @@ function startWatch(targets, onChange) {
2656
2677
  * against a generated dev stack file, attach (front door + merged logs),
2657
2678
  * watch loop until interrupted.
2658
2679
  */
2659
- function toCliError(error) {
2680
+ function toCliError$1(error) {
2660
2681
  return error instanceof CliError ? error : new CliError(error instanceof Error ? error.message : String(error));
2661
2682
  }
2662
2683
  /** `[dev] ready:` then one line per endpoint, ordered by address depth (fewest dots first) then lexicographic. Exported for tests. */
@@ -2687,19 +2708,6 @@ async function withEmulatorRetry(call) {
2687
2708
  async function mergedEndpoints(attachments) {
2688
2709
  return (await Promise.all(attachments.map((a) => withEmulatorRetry(() => a.endpoints())))).flat();
2689
2710
  }
2690
- /** Pumps every attachment's merged log stream to stdout, each line prefixed `[<service>] `, until `signal` aborts. */
2691
- function pumpLogs(attachments, signal) {
2692
- for (const attachment of attachments) (async () => {
2693
- try {
2694
- for await (const { service, line } of attachment.logs(signal)) {
2695
- if (signal.aborted) return;
2696
- console.log(`[${service}] ${line}`);
2697
- }
2698
- } catch (error) {
2699
- if (!signal.aborted) console.error(`[dev] log stream failed: ${error instanceof Error ? error.message : String(error)}`);
2700
- }
2701
- })();
2702
- }
2703
2711
  /** Runs the full dev pipeline; returns the process exit code. */
2704
2712
  async function runDev(args, deps = {}) {
2705
2713
  if (process.platform === "win32") throw new CliError("local dev is not supported on Windows yet.");
@@ -2714,7 +2722,7 @@ async function runDev(args, deps = {}) {
2714
2722
  try {
2715
2723
  resolved = await resolveLocalTargets(config);
2716
2724
  } catch (error) {
2717
- throw toCliError(error);
2725
+ throw toCliError$1(error);
2718
2726
  }
2719
2727
  const containers = /* @__PURE__ */ new Map();
2720
2728
  for (const [id, dev] of resolved) try {
@@ -2723,7 +2731,7 @@ async function runDev(args, deps = {}) {
2723
2731
  stage: void 0
2724
2732
  }));
2725
2733
  } catch (error) {
2726
- throw toCliError(error);
2734
+ throw toCliError$1(error);
2727
2735
  }
2728
2736
  if (args.fresh) for (const [id, dev] of resolved) {
2729
2737
  if (dev.teardown === void 0) continue;
@@ -2733,7 +2741,7 @@ async function runDev(args, deps = {}) {
2733
2741
  stage: void 0
2734
2742
  });
2735
2743
  } catch (error) {
2736
- throw toCliError(error);
2744
+ throw toCliError$1(error);
2737
2745
  }
2738
2746
  }
2739
2747
  for (const [id, dev] of resolved) {
@@ -2745,7 +2753,7 @@ async function runDev(args, deps = {}) {
2745
2753
  stage: void 0
2746
2754
  });
2747
2755
  } catch (error) {
2748
- throw toCliError(error);
2756
+ throw toCliError$1(error);
2749
2757
  }
2750
2758
  }
2751
2759
  for (const [id, dev] of resolved) {
@@ -2757,7 +2765,7 @@ async function runDev(args, deps = {}) {
2757
2765
  devDir
2758
2766
  });
2759
2767
  } catch (error) {
2760
- throw toCliError(error);
2768
+ throw toCliError$1(error);
2761
2769
  }
2762
2770
  }
2763
2771
  const converge = () => {
@@ -2794,11 +2802,10 @@ async function runDev(args, deps = {}) {
2794
2802
  started.push(attachment);
2795
2803
  } catch (error) {
2796
2804
  await Promise.all(started.map((a) => a.stopServices().catch(() => void 0)));
2797
- throw toCliError(error);
2805
+ throw toCliError$1(error);
2798
2806
  }
2799
2807
  printFrontDoor(await mergedEndpoints(attachments));
2800
- const logsController = new AbortController();
2801
- pumpLogs(attachments, logsController.signal);
2808
+ console.log(`[dev] logs: prisma-composer log ${args.entry}`);
2802
2809
  const { targets, unwatchable } = watchTargetsFrom(assembled.bundles);
2803
2810
  for (const address of unwatchable) console.log(`[dev] ${address} has no watchable inputs`);
2804
2811
  const watch = startWatch(targets, () => {
@@ -2837,7 +2844,6 @@ async function runDev(args, deps = {}) {
2837
2844
  console.log("[dev] stopping — the app's services are stopping; emulators and data stay up.");
2838
2845
  watch.stop();
2839
2846
  (async () => {
2840
- logsController.abort();
2841
2847
  for (const attachment of attachments) await attachment.stopServices().catch(() => void 0);
2842
2848
  console.log("[dev] stopped.");
2843
2849
  resolve();
@@ -2903,6 +2909,70 @@ function writeStackFile(input) {
2903
2909
  return filePath;
2904
2910
  }
2905
2911
  const GENERATED_STACK_RELATIVE_PATH = path.join(GENERATED_DIR, GENERATED_FILE);
2912
+ /**
2913
+ * `prisma-composer log <entry> [address]` — tail the merged logs of an
2914
+ * already-running local app. It resolves the app the way `dev` does (config →
2915
+ * localTarget → container → attach) but calls only the attachment's `logs()`
2916
+ * view: it neither builds, provisions, starts, nor stops anything. `dev` no
2917
+ * longer streams logs inline (that drowned the front door once it supervises
2918
+ * more than one service); this is where logs live.
2919
+ */
2920
+ function toCliError(error) {
2921
+ return error instanceof CliError ? error : new CliError(error instanceof Error ? error.message : String(error));
2922
+ }
2923
+ /** Runs the log tail until interrupted; returns the process exit code. */
2924
+ async function runLog(args, deps = {}) {
2925
+ if (process.platform === "win32") throw new CliError("local dev is not supported on Windows yet.");
2926
+ const cwd = process.cwd();
2927
+ const devDir = path.join(cwd, DEV_DIR);
2928
+ const { config, name } = deps.identity ?? await resolveAppIdentity(args.entry, args.name, cwd, { config: deps.config });
2929
+ let resolved;
2930
+ try {
2931
+ resolved = await resolveLocalTargets(config);
2932
+ } catch (error) {
2933
+ throw toCliError(error);
2934
+ }
2935
+ const attachments = [];
2936
+ for (const target of resolved.values()) try {
2937
+ const container = await target.container.ensure({
2938
+ appName: name,
2939
+ stage: void 0
2940
+ });
2941
+ attachments.push(await target.attach({
2942
+ container,
2943
+ devDir
2944
+ }));
2945
+ } catch (error) {
2946
+ throw toCliError(error);
2947
+ }
2948
+ const services = (await Promise.all(attachments.map((a) => a.endpoints()))).flat();
2949
+ if (services.length === 0) {
2950
+ console.error(`[log] no running services for "${name}" — start it first with \`prisma-composer dev ${args.entry}\`.`);
2951
+ return 0;
2952
+ }
2953
+ if (args.address !== void 0 && !services.some((s) => s.address === args.address)) throw new CliError(`no service "${args.address}" in "${name}" — running services: ${services.map((s) => s.address).join(", ")}.`);
2954
+ const controller = new AbortController();
2955
+ const finish = () => controller.abort();
2956
+ process.on("SIGINT", finish);
2957
+ process.on("SIGTERM", finish);
2958
+ try {
2959
+ await Promise.all(attachments.map(async (attachment) => {
2960
+ try {
2961
+ for await (const { service, line } of attachment.logs(controller.signal, { tail: args.tail })) {
2962
+ if (controller.signal.aborted) return;
2963
+ if (args.address !== void 0 && service !== args.address) continue;
2964
+ console.log(`[${service}] ${line}`);
2965
+ }
2966
+ } catch (error) {
2967
+ if (!controller.signal.aborted) console.error(`[log] stream failed: ${error instanceof Error ? error.message : String(error)}`);
2968
+ }
2969
+ }));
2970
+ } finally {
2971
+ process.off("SIGINT", finish);
2972
+ process.off("SIGTERM", finish);
2973
+ }
2974
+ return 0;
2975
+ }
2906
2976
  /** A stage name must be a valid git ref (deploy-cli.md) — checked via `git check-ref-format`, never silently normalized. Runs before anything platform-specific. */
2907
2977
  function validateStageName(stage) {
2908
2978
  const result = spawnSync("git", ["check-ref-format", `refs/heads/${stage}`], { stdio: "ignore" });
@@ -2955,11 +3025,29 @@ var DevCommand = class extends Command {
2955
3025
  return 0;
2956
3026
  }
2957
3027
  };
3028
+ var LogCommand = class extends Command {
3029
+ static paths = [["log"]];
3030
+ static usage = Command.Usage({
3031
+ description: "Tail the merged logs of the locally-running application whose root node is <entry>'s default export.",
3032
+ examples: [["Tail every service", "$0 log src/service.ts"], ["Tail one service", "$0 log src/service.ts catalog.service"]]
3033
+ });
3034
+ entry = Option.String({ name: "entry" });
3035
+ address = Option.String({
3036
+ name: "address",
3037
+ required: false
3038
+ });
3039
+ name = Option.String("--name", { description: "Override the root node's name — the dev instance's application name." });
3040
+ tail = Option.String("--tail", { description: `How many trailing history lines to show before live output (default ${String(DEFAULT_LOG_TAIL)}).` });
3041
+ async execute() {
3042
+ return 0;
3043
+ }
3044
+ };
2958
3045
  function buildCli() {
2959
3046
  return Cli.from([
2960
3047
  DeployCommand,
2961
3048
  DestroyCommand,
2962
- DevCommand
3049
+ DevCommand,
3050
+ LogCommand
2963
3051
  ], {
2964
3052
  binaryName: BINARY_NAME,
2965
3053
  binaryLabel: "The prisma-composer deploy CLI"
@@ -2973,6 +3061,8 @@ function isUnknownSyntaxError(error) {
2973
3061
  const meta = error.clipanion;
2974
3062
  return typeof meta === "object" && meta !== null && meta.type === "none";
2975
3063
  }
3064
+ /** `log`'s default backlog: an empty screen reads as broken, so show a little recent history before going live. */
3065
+ const DEFAULT_LOG_TAIL = 20;
2976
3066
  /** Exported for direct testing (main.test.ts) — not part of the package's public barrel (see index.ts). */
2977
3067
  function parseArgs(argv) {
2978
3068
  const cli = buildCli();
@@ -2999,6 +3089,20 @@ function parseArgs(argv) {
2999
3089
  production: false,
3000
3090
  fresh: command.fresh
3001
3091
  };
3092
+ if (command instanceof LogCommand) {
3093
+ const tail = command.tail === void 0 ? DEFAULT_LOG_TAIL : Number.parseInt(command.tail, 10);
3094
+ if (Number.isNaN(tail) || tail < 0) throw new UsageError("`--tail` must be a non-negative integer.");
3095
+ return {
3096
+ command: "log",
3097
+ entry: command.entry,
3098
+ name: command.name,
3099
+ stage: void 0,
3100
+ production: false,
3101
+ fresh: false,
3102
+ address: command.address,
3103
+ tail
3104
+ };
3105
+ }
3002
3106
  if (argv.includes("--help") || argv.includes("-h")) throw new HelpRequested(cli.usage(null, { detailed: true }));
3003
3107
  throw new UsageError(cli.usage(null, { detailed: true }));
3004
3108
  }
@@ -3031,6 +3135,12 @@ async function run(argv, deps = {}) {
3031
3135
  throw error;
3032
3136
  }
3033
3137
  if (args.command === "dev") return runDev(args, deps);
3138
+ if (args.command === "log") return runLog({
3139
+ entry: args.entry,
3140
+ name: args.name,
3141
+ address: args.address,
3142
+ tail: args.tail ?? DEFAULT_LOG_TAIL
3143
+ }, { config: deps.config });
3034
3144
  const stage = effectiveStage(args);
3035
3145
  if (stage !== void 0) validateStageName(stage);
3036
3146
  const cwd = process.cwd();