@hs-x/cli 0.2.3 → 0.2.4

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.
@@ -1,3 +1,6 @@
1
+ import { type WorkerManifest } from '@hs-x/codegen';
2
+ import type { AppEventDeclaration, AppObjectAssociationDeclaration, AppObjectDeclaration, CardDefinition } from '@hs-x/types';
3
+ import type { AppBillingDeclaration } from '@hs-x/types';
1
4
  import * as Command from '@effect/cli/Command';
2
5
  import { Option } from 'effect';
3
6
  import { Cwd } from '../services/cwd.js';
@@ -7,6 +10,21 @@ export declare function deployCommand({ argv, root, json, }: {
7
10
  readonly root: string;
8
11
  readonly json: boolean;
9
12
  }): Promise<CliResult>;
13
+ interface CloudflareWorkerDeployResult {
14
+ readonly workerName: string;
15
+ readonly workerSourcePath: string;
16
+ readonly entrypointPath: string;
17
+ readonly configPath?: string;
18
+ readonly url: string | undefined;
19
+ readonly command: readonly string[];
20
+ readonly dryRun: boolean;
21
+ readonly stdout: string;
22
+ readonly stderr: string;
23
+ }
24
+ interface CloudflareDeployResult {
25
+ readonly deployId: string;
26
+ readonly workers: readonly CloudflareWorkerDeployResult[];
27
+ }
10
28
  export declare function renderWranglerConfig(input: {
11
29
  readonly workerName: string;
12
30
  readonly entrypointPath: string;
@@ -22,6 +40,32 @@ export declare function renderWranglerConfig(input: {
22
40
  /** Enable Workers Logs ingestion (linked deploys; read by the dashboard tail). */
23
41
  readonly observability?: boolean;
24
42
  }): string;
43
+ export declare function ensureHubSpotRuntimeProjectArtifacts({ argv, root, app, workers, cloudflareDeployResult, needsRuntime, controlPlanePlan, }: {
44
+ readonly argv: readonly string[];
45
+ readonly root: string;
46
+ readonly app: HsxAppConfig;
47
+ readonly workers: readonly WorkerManifest[];
48
+ readonly cloudflareDeployResult: CloudflareDeployResult | undefined;
49
+ readonly needsRuntime: boolean;
50
+ readonly controlPlanePlan?: {
51
+ readonly runtimeBindings?: {
52
+ readonly oauthCallbackPath: string;
53
+ };
54
+ };
55
+ }): Promise<void>;
56
+ interface HsxAppConfig {
57
+ readonly appName: string;
58
+ readonly description?: string;
59
+ readonly distribution: string;
60
+ readonly auth: string;
61
+ readonly platformVersion: string;
62
+ readonly scopes: readonly string[];
63
+ readonly appObjects: readonly AppObjectDeclaration[];
64
+ readonly appObjectAssociations: readonly AppObjectAssociationDeclaration[];
65
+ readonly appEvents: readonly AppEventDeclaration[];
66
+ readonly cards: readonly CardDefinition[];
67
+ readonly billing?: AppBillingDeclaration;
68
+ }
25
69
  export declare const deployCmd: Command.Command<"deploy", Cwd, import("../cli-error.js").CliError, {
26
70
  readonly json: boolean;
27
71
  readonly cwd: Option.Option<string>;
@@ -76,4 +120,5 @@ export declare const deployCmd: Command.Command<"deploy", Cwd, import("../cli-er
76
120
  readonly yes: boolean;
77
121
  }>;
78
122
  }>;
123
+ export {};
79
124
  //# sourceMappingURL=deploy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAE/C,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;AAgBxC,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAyBzC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AA+a9C,wBAAsB,aAAa,CAAC,EAClC,IAAI,EACJ,IAAI,EACJ,IAAI,GACL,EAAE;IACD,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB,GAAG,OAAO,CAAC,SAAS,CAAC,CAoarB;AAslDD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACvC,wFAAwF;IACxF,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,kFAAkF;IAClF,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;CAClC,GAAG,MAAM,CAoDT;AAqpDD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAqE,CAAC"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"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"}
@@ -1367,6 +1367,37 @@ async function executeCloudflareWorkerDeploy({ argv, root, worker, index, source
1367
1367
  tenantDataPlane?.flagsKvNamespaceName,
1368
1368
  tenantDataPlane?.tenantD1DatabaseName,
1369
1369
  ].filter((name) => typeof name === 'string' && name.toLowerCase().startsWith(accountResourcePrefix));
1370
+ // wrangler does NOT auto-apply D1 migrations on deploy (found live:
1371
+ // tenant DBs had zero tables across every real deploy since ADR-014) —
1372
+ // apply them explicitly before the worker code that expects them lands.
1373
+ const migrationsDirExists = await stat(join(root, 'node_modules', '@hs-x', 'runtime', 'migrations'))
1374
+ .then((entry) => entry.isDirectory())
1375
+ .catch(() => false);
1376
+ if (tenantDataPlane?.tenantD1DatabaseName && !dryRun && !migrationsDirExists) {
1377
+ process.stderr.write('warning: @hs-x/runtime did not ship its tenant migrations (pre-0.2.4 package) — tenant D1 tables were NOT applied; upgrade @hs-x/runtime.\n');
1378
+ }
1379
+ if (tenantDataPlane?.tenantD1DatabaseName && !dryRun && migrationsDirExists) {
1380
+ try {
1381
+ await runCloudflareCommand([
1382
+ 'bun',
1383
+ 'x',
1384
+ 'wrangler',
1385
+ 'd1',
1386
+ 'migrations',
1387
+ 'apply',
1388
+ tenantDataPlane.tenantD1DatabaseName,
1389
+ '--remote',
1390
+ '--config',
1391
+ relative(root, configPath),
1392
+ ], { cwd: root, env: cloudflareDeployEnv(argv) });
1393
+ }
1394
+ catch (error) {
1395
+ const message = error instanceof Error ? error.message : String(error);
1396
+ if (!/No migrations to apply/i.test(message)) {
1397
+ throw new Error(`Tenant D1 migrations failed: ${message.slice(-300)}`);
1398
+ }
1399
+ }
1400
+ }
1370
1401
  const command = [
1371
1402
  'bun',
1372
1403
  'x',
@@ -1470,7 +1501,19 @@ async function executeCloudflareWorkerDeploy({ argv, root, worker, index, source
1470
1501
  installKvNamespaceName: installRuntimeBinding.installKvNamespaceName,
1471
1502
  tokenKeySecretName: installRuntimeBinding.tokenKeySecretName,
1472
1503
  runtimeBaseUrl: resolvedRuntimeUrl,
1473
- ...(tenantDataPlane ? { syncGrantSecretName: tenantDataPlane.syncGrantSecretName } : {}),
1504
+ ...(tenantDataPlane
1505
+ ? {
1506
+ syncGrantSecretName: tenantDataPlane.syncGrantSecretName,
1507
+ // Read-through legs need these registered: exemplars read the
1508
+ // tenant D1; flag tooling reads the flags KV.
1509
+ tenantD1DatabaseId: tenantDataPlane.tenantD1DatabaseId,
1510
+ tenantD1DatabaseName: tenantDataPlane.tenantD1DatabaseName,
1511
+ flagsKvNamespaceId: tenantDataPlane.flagsKvNamespaceId,
1512
+ ...(tenantDataPlane.flagsKvNamespaceName
1513
+ ? { flagsKvNamespaceName: tenantDataPlane.flagsKvNamespaceName }
1514
+ : {}),
1515
+ }
1516
+ : {}),
1474
1517
  });
1475
1518
  }
1476
1519
  catch (error) {
@@ -1655,6 +1698,10 @@ async function putDeployInstallRuntimeBinding(input) {
1655
1698
  tokenKeySecretName: input.tokenKeySecretName,
1656
1699
  ...(input.runtimeBaseUrl ? { runtimeBaseUrl: input.runtimeBaseUrl } : {}),
1657
1700
  ...(input.syncGrantSecretName ? { syncGrantSecretName: input.syncGrantSecretName } : {}),
1701
+ ...(input.tenantD1DatabaseId ? { tenantD1DatabaseId: input.tenantD1DatabaseId } : {}),
1702
+ ...(input.tenantD1DatabaseName ? { tenantD1DatabaseName: input.tenantD1DatabaseName } : {}),
1703
+ ...(input.flagsKvNamespaceId ? { flagsKvNamespaceId: input.flagsKvNamespaceId } : {}),
1704
+ ...(input.flagsKvNamespaceName ? { flagsKvNamespaceName: input.flagsKvNamespaceName } : {}),
1658
1705
  },
1659
1706
  });
1660
1707
  const body = await response.json();
@@ -1836,6 +1883,14 @@ export function renderWranglerConfig(input) {
1836
1883
  `name = "${tomlString(input.workerName)}"`,
1837
1884
  `main = "${tomlString(input.entrypointPath)}"`,
1838
1885
  `compatibility_date = "${tomlString(input.compatibilityDate)}"`,
1886
+ // nodejs_compat: guide + scaffold code reads `process.env.X` at module
1887
+ // scope (e.g. defineSource hmac secrets); without it the Worker fails
1888
+ // validation with "process is not defined" (Cloudflare error 10021,
1889
+ // cold-stranger run #2 blocker A). With nodejs_compat and a
1890
+ // compatibility_date >= 2025-04-01, Workers auto-populate process.env
1891
+ // from bindings/secrets; the explicit populate flag keeps that true even
1892
+ // when --compatibility-date is set to an older date.
1893
+ 'compatibility_flags = [ "nodejs_compat", "nodejs_compat_populate_process_env" ]',
1839
1894
  ];
1840
1895
  if (input.installKvNamespaceId) {
1841
1896
  lines.push('', '[[kv_namespaces]]', 'binding = "INSTALL_KV"', `id = "${tomlString(input.installKvNamespaceId)}"`);
@@ -1891,7 +1946,7 @@ async function readDeployHubSpotOAuthSecret(input) {
1891
1946
  function extractWorkerUrl(output) {
1892
1947
  return /https:\/\/[a-zA-Z0-9.-]+\.workers\.dev\b/.exec(output)?.[0];
1893
1948
  }
1894
- async function ensureHubSpotRuntimeProjectArtifacts({ argv, root, app, workers, cloudflareDeployResult, needsRuntime, controlPlanePlan, }) {
1949
+ export async function ensureHubSpotRuntimeProjectArtifacts({ argv, root, app, workers, cloudflareDeployResult, needsRuntime, controlPlanePlan, }) {
1895
1950
  if (!needsRuntime) {
1896
1951
  return;
1897
1952
  }
@@ -1912,6 +1967,14 @@ async function ensureHubSpotRuntimeProjectArtifacts({ argv, root, app, workers,
1912
1967
  });
1913
1968
  for (const [file, contents] of Object.entries(generated.files)) {
1914
1969
  const path = join(root, file);
1970
+ // src/app/cards/package.json is user-owned once it exists: HubSpot's own
1971
+ // build errors instruct users to add card dependencies (e.g. hs-uix) to
1972
+ // it, and regenerating the fixed-dep version here silently dropped those
1973
+ // deps so the card never built (cold-stranger run #2 blocker B). Keep the
1974
+ // user's file verbatim; only generate one when absent.
1975
+ if (file === 'src/app/cards/package.json' && (await stat(path).catch(() => undefined))) {
1976
+ continue;
1977
+ }
1915
1978
  await mkdir(dirname(path), { recursive: true });
1916
1979
  await writeFile(path, contents);
1917
1980
  }
@@ -2716,6 +2779,7 @@ async function requestHostedControlPlaneDeployRecordAndMaybePromote({ request, p
2716
2779
  signedManifest: request.manifest,
2717
2780
  signature: `sig_${plan.deployId}`,
2718
2781
  bundleKey: deployBundleKey({ projectId: request.projectId, deployId: plan.deployId }),
2782
+ ...(await collectDeployProvenance(userId)),
2719
2783
  },
2720
2784
  });
2721
2785
  const body = await response.json();
@@ -2854,14 +2918,59 @@ function stringProperty(source, propertyName) {
2854
2918
  return match ? { [propertyName]: match } : {};
2855
2919
  }
2856
2920
  function schemaProperty(source) {
2857
- const body = /schema\s*:\s*\{([\s\S]*?)\}\s*(?:,|$)/.exec(source)?.[1];
2921
+ // Balanced-brace extraction. The previous non-greedy regex stopped at the
2922
+ // first `}` inside an object-form field (`score: { type: "number", … }`),
2923
+ // truncating the schema and mis-reading nested keys (`type`) as property
2924
+ // names — which made portal-schema plans wrong for any schema that mixes
2925
+ // shorthand strings with object declarations.
2926
+ const body = objectLiteralBody(source, 'schema');
2858
2927
  if (!body) {
2859
2928
  return {};
2860
2929
  }
2861
2930
  const schema = {};
2862
- for (const match of body.matchAll(/([A-Za-z_$][\w$]*)\s*:\s*["'`]([^"'`]+)["'`]/g)) {
2863
- if (match[1] && match[2]) {
2864
- schema[match[1]] = match[2];
2931
+ let index = 0;
2932
+ while (index < body.length) {
2933
+ const entry = /^[\s,]*([A-Za-z_$][\w$]*)\s*:\s*/.exec(body.slice(index));
2934
+ if (!entry || !entry[1])
2935
+ break;
2936
+ const name = entry[1];
2937
+ const valueStart = index + entry[0].length;
2938
+ const char = body[valueStart];
2939
+ if (char === '"' || char === "'" || char === '`') {
2940
+ const close = body.indexOf(char, valueStart + 1);
2941
+ if (close === -1)
2942
+ break;
2943
+ schema[name] = body.slice(valueStart + 1, close);
2944
+ index = close + 1;
2945
+ }
2946
+ else if (char === '{') {
2947
+ let depth = 0;
2948
+ let end = -1;
2949
+ for (let i = valueStart; i < body.length; i += 1) {
2950
+ if (body[i] === '{')
2951
+ depth += 1;
2952
+ else if (body[i] === '}') {
2953
+ depth -= 1;
2954
+ if (depth === 0) {
2955
+ end = i;
2956
+ break;
2957
+ }
2958
+ }
2959
+ }
2960
+ if (end === -1)
2961
+ break;
2962
+ const inner = body.slice(valueStart + 1, end);
2963
+ const type = /type\s*:\s*["'`]([^"'`]+)["'`]/.exec(inner)?.[1];
2964
+ const property = /property\s*:\s*["'`]([^"'`]+)["'`]/.exec(inner)?.[1];
2965
+ schema[name] = { ...(type ? { type } : {}), ...(property ? { property } : {}) };
2966
+ index = end + 1;
2967
+ }
2968
+ else {
2969
+ // Unsupported value shape (identifier, number); skip to the next entry.
2970
+ const nextComma = body.indexOf(',', valueStart);
2971
+ if (nextComma === -1)
2972
+ break;
2973
+ index = nextComma + 1;
2865
2974
  }
2866
2975
  }
2867
2976
  return Object.keys(schema).length > 0 ? { schema } : {};
@@ -3169,4 +3278,40 @@ const deployPromoteSubCmd = Command.make('promote', {
3169
3278
  yield* runQuarantined(opts.json, () => deployCommand({ argv, root, json: opts.json }));
3170
3279
  })));
3171
3280
  export const deployCmd = deployBaseCmd.pipe(Command.withSubcommands([deployPromoteSubCmd]));
3281
+ /**
3282
+ * Provenance for the active-deploy card, collected where it's cheapest: the
3283
+ * CLI knows its own version, the git state of the tree it deployed, and the
3284
+ * session identity. Everything best-effort — a non-git tree stamps nothing.
3285
+ */
3286
+ async function collectDeployProvenance(userId) {
3287
+ const git = async (args) => {
3288
+ try {
3289
+ const proc = Bun.spawn({ cmd: ['git', ...args], stdout: 'pipe', stderr: 'ignore' });
3290
+ const [out, code] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
3291
+ const trimmed = out.trim();
3292
+ return code === 0 && trimmed ? trimmed : undefined;
3293
+ }
3294
+ catch {
3295
+ return undefined;
3296
+ }
3297
+ };
3298
+ const [gitCommit, gitBranch] = await Promise.all([
3299
+ git(['rev-parse', '--short', 'HEAD']),
3300
+ git(['rev-parse', '--abbrev-ref', 'HEAD']),
3301
+ ]);
3302
+ let deployedBy;
3303
+ try {
3304
+ const { loadStore, activeSession } = await import('../account-store.js');
3305
+ deployedBy = activeSession(await loadStore())?.email ?? userId;
3306
+ }
3307
+ catch {
3308
+ deployedBy = userId;
3309
+ }
3310
+ return {
3311
+ cliVersion: `hs-x@${CLI_VERSION}`,
3312
+ ...(gitCommit ? { gitCommit } : {}),
3313
+ ...(gitBranch ? { gitBranch } : {}),
3314
+ ...(deployedBy ? { deployedBy } : {}),
3315
+ };
3316
+ }
3172
3317
  //# sourceMappingURL=deploy.js.map