@mesh-tech/mesh-cli 0.19.0 → 0.20.0

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/bin/mesh.js CHANGED
@@ -767,22 +767,35 @@ async function seedLocalPlatform() {
767
767
  );
768
768
  await registerTenantEnv(LOCAL_TENANT, { tier: "hub" });
769
769
  logSuccess(`Registered tenant '${LOCAL_TENANT}' env '${LOCAL_ENV}' \u2192 ${APP_TENANTS_PARAM}`);
770
- const { S3Client, CreateBucketCommand } = await import("@aws-sdk/client-s3");
770
+ const { S3Client, CreateBucketCommand, PutObjectCommand } = await import("@aws-sdk/client-s3");
771
771
  const s3 = new S3Client({ ...AWS_CONFIG, forcePathStyle: true });
772
- try {
773
- await s3.send(new CreateBucketCommand({ Bucket: ARTIFACTS_BUCKET }));
774
- logSuccess(`Created artifacts bucket s3://${ARTIFACTS_BUCKET}`);
775
- } catch (err) {
776
- if (err?.name === "BucketAlreadyOwnedByYou" || err?.name === "BucketAlreadyExists") {
777
- logInfo(`Artifacts bucket s3://${ARTIFACTS_BUCKET} already exists`);
778
- } else {
779
- throw err;
772
+ for (const bucket of [ARTIFACTS_BUCKET, DATA_BUCKET]) {
773
+ try {
774
+ await s3.send(new CreateBucketCommand({ Bucket: bucket }));
775
+ logSuccess(`Created bucket s3://${bucket}`);
776
+ } catch (err) {
777
+ if (err?.name === "BucketAlreadyOwnedByYou" || err?.name === "BucketAlreadyExists") {
778
+ logInfo(`Bucket s3://${bucket} already exists`);
779
+ } else {
780
+ throw err;
781
+ }
780
782
  }
781
783
  }
784
+ for (const seed of DATA_BUCKET_SEEDS) {
785
+ await s3.send(
786
+ new PutObjectCommand({
787
+ Bucket: DATA_BUCKET,
788
+ Key: seed.key,
789
+ Body: seed.body,
790
+ ContentType: "application/json"
791
+ })
792
+ );
793
+ }
794
+ logSuccess(`Seeded s3://${DATA_BUCKET} with ${DATA_BUCKET_SEEDS.length} sample object(s)`);
782
795
  await seedTemporalNamespace();
783
796
  return { parameter: APP_TENANTS_PARAM, bucket: ARTIFACTS_BUCKET };
784
797
  }
785
- var LOCAL_TENANT, LOCAL_ENV, LOCAL_AWS_ENDPOINT, LOCAL_AWS_REGION, ARTIFACTS_BUCKET, APP_TENANTS_PARAM, LOCAL_AWS_CONFIG, AWS_CONFIG, FABRIC_CHECK_PATH, TEMPORAL_NAMESPACE, TEMPORAL_ADDRESS;
798
+ var LOCAL_TENANT, LOCAL_ENV, LOCAL_AWS_ENDPOINT, LOCAL_AWS_REGION, ARTIFACTS_BUCKET, DATA_BUCKET, APP_TENANTS_PARAM, DATA_BUCKET_SEEDS, LOCAL_AWS_CONFIG, AWS_CONFIG, FABRIC_CHECK_PATH, TEMPORAL_NAMESPACE, TEMPORAL_ADDRESS;
786
799
  var init_seed = __esm({
787
800
  "libs/mesh-cli/src/commands/local/seed.ts"() {
788
801
  "use strict";
@@ -793,7 +806,24 @@ var init_seed = __esm({
793
806
  LOCAL_AWS_ENDPOINT = "http://localhost:4566";
794
807
  LOCAL_AWS_REGION = "us-east-2";
795
808
  ARTIFACTS_BUCKET = "mesh-local-artifacts";
809
+ DATA_BUCKET = "mesh-local-data";
796
810
  APP_TENANTS_PARAM = `/mesh-platform/${LOCAL_TENANT}/${LOCAL_ENV}/app-tenants`;
811
+ DATA_BUCKET_SEEDS = [
812
+ {
813
+ key: "samples/pipes/fragment-0001.json",
814
+ body: JSON.stringify(
815
+ {
816
+ id: "sample-0001",
817
+ kind: "pipes-fragment",
818
+ account: "0001",
819
+ asOf: "2026-01-01",
820
+ lines: [{ amount: "125.00", currency: "USD", description: "Sample credit" }]
821
+ },
822
+ null,
823
+ 2
824
+ )
825
+ }
826
+ ];
797
827
  LOCAL_AWS_CONFIG = {
798
828
  endpoint: LOCAL_AWS_ENDPOINT,
799
829
  region: LOCAL_AWS_REGION,
@@ -6808,6 +6838,20 @@ async function registerLocalApp(args) {
6808
6838
  `Local service registration (${service})`
6809
6839
  );
6810
6840
  }
6841
+ for (const service of args.services) {
6842
+ if (args.kinds?.[service] !== "dagster") continue;
6843
+ const port = args.ports?.[service];
6844
+ if (!port) continue;
6845
+ await put2(
6846
+ `${base}/dagster`,
6847
+ {
6848
+ kind: "dagster",
6849
+ graphqlUrl: `http://host.docker.internal:${port}/graphql`,
6850
+ uiUrl: `http://localhost:${port}`
6851
+ },
6852
+ `Local Dagster discovery record (${service})`
6853
+ );
6854
+ }
6811
6855
  for (const service of args.services) {
6812
6856
  if (!/worker/i.test(service)) continue;
6813
6857
  await put2(
@@ -7127,6 +7171,22 @@ function localPlatformEnv(tenant, appName, serviceName) {
7127
7171
  }
7128
7172
  return env;
7129
7173
  }
7174
+ function isDagsterWorkspaceRoot(appRoot) {
7175
+ if (fs17.existsSync(path17.join(appRoot, "dg.toml"))) return true;
7176
+ const pyproject = path17.join(appRoot, "pyproject.toml");
7177
+ if (!fs17.existsSync(pyproject)) return false;
7178
+ try {
7179
+ return /^\s*\[tool\.dg[\].]/m.test(fs17.readFileSync(pyproject, "utf-8"));
7180
+ } catch {
7181
+ return false;
7182
+ }
7183
+ }
7184
+ function resolveDgBinary(appRoot) {
7185
+ for (const candidate of ["deployments/local/.venv/bin/dg", ".venv/bin/dg"]) {
7186
+ if (fs17.existsSync(path17.join(appRoot, candidate))) return candidate;
7187
+ }
7188
+ return "dg";
7189
+ }
7130
7190
  function hasDevScript(dir) {
7131
7191
  const pkgPath = path17.join(dir, "package.json");
7132
7192
  if (!fs17.existsSync(pkgPath)) return false;
@@ -7153,9 +7213,10 @@ function detectLocalServices(appRoot) {
7153
7213
  function buildLocalDevOutput(appRoot, tenant, opts = {}) {
7154
7214
  const detected = detectLocalServices(appRoot);
7155
7215
  const names = Object.keys(detected);
7156
- if (names.length === 0) {
7216
+ const isDagsterWorkspace = isDagsterWorkspaceRoot(appRoot);
7217
+ if (names.length === 0 && !isDagsterWorkspace) {
7157
7218
  throw new MeshCliError(
7158
- `No runnable services found under ${appRoot} \u2014 expected subdirectories (api/, worker/, \u2026) with a package.json 'dev' script.`,
7219
+ `No runnable services found under ${appRoot} \u2014 expected subdirectories (api/, worker/, \u2026) with a package.json 'dev' script, or a Dagster workspace (dg.toml, or [tool.dg] in pyproject.toml).`,
7159
7220
  { remediation: { command: "mesh create-app" } }
7160
7221
  );
7161
7222
  }
@@ -7203,6 +7264,25 @@ function buildLocalDevOutput(appRoot, tenant, opts = {}) {
7203
7264
  services[other].env[key] = { value: url };
7204
7265
  }
7205
7266
  }
7267
+ if (isDagsterWorkspace) {
7268
+ const port = BASE_PORT + names.length + mockNames.length;
7269
+ services["dagster"] = {
7270
+ // Absolute on purpose: a relative src is MONOREPO-ROOT-relative by the
7271
+ // ServiceDevOutput contract (rebaseServiceSrc), which for an app nested
7272
+ // in the monorepo would cd the launch shell to the repo root — where
7273
+ // neither dg.toml nor the venv path resolves. The absolute app root
7274
+ // survives rebasing in both the monorepo and standalone-repo shapes.
7275
+ src: appRoot,
7276
+ kind: "dagster",
7277
+ port,
7278
+ command: [resolveDgBinary(appRoot), "dev", "-h", "127.0.0.1", "-p", '"$PORT"'],
7279
+ env: {
7280
+ PORT: { value: String(port) },
7281
+ DAGSTER_HOME: { value: path17.join(appRoot, ".dagster") },
7282
+ ...localPlatformEnv(tenant, appName, "dagster")
7283
+ }
7284
+ };
7285
+ }
7206
7286
  mockNames.forEach((name, i) => {
7207
7287
  const decl = mocks[name];
7208
7288
  const serviceName = `mock-${name}`;
@@ -9349,6 +9429,11 @@ function registerDevCommand(program2) {
9349
9429
  ports: Object.fromEntries(
9350
9430
  Object.entries(devOutput2.services).map(([name, svc]) => [name, svc.port])
9351
9431
  ),
9432
+ kinds: Object.fromEntries(
9433
+ Object.entries(devOutput2.services).flatMap(
9434
+ ([name, svc]) => svc.kind ? [[name, svc.kind]] : []
9435
+ )
9436
+ ),
9352
9437
  // ExternalService.link() parity: consuming services carry the
9353
9438
  // external names, so the Hub shows consumers + per-app uptime.
9354
9439
  links: Object.values(selectedMocks).map((decl) => decl.external).filter((n) => !!n)
@@ -15922,7 +16007,12 @@ var init_hub = __esm({
15922
16007
  TEMPORAL_UI_URL: "http://localhost:8233",
15923
16008
  // The stack's namespace. Absent, the Hub's compliance schedules fail to
15924
16009
  // register with "Temporal namespace is required".
15925
- TEMPORAL_NAMESPACE: "local-dev"
16010
+ TEMPORAL_NAMESPACE: "local-dev",
16011
+ // Dagster discovery records written by `mesh dev --local` carry
16012
+ // `host.docker.internal` (for the containerized `mesh start` hub). This hub
16013
+ // runs on the host, where that name does not resolve — tell the Data
16014
+ // section's resolver to swap it for localhost.
16015
+ MESH_DAGSTER_LOCAL_HOST: "localhost"
15926
16016
  });
15927
16017
  SENSITIVE_RE = /TOKEN|SECRET|KEY|PASSWORD/i;
15928
16018
  }