@hs-x/cli 0.3.0 → 0.3.6
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/commands/account.d.ts +6 -6
- package/dist/commands/api.js +1 -1
- package/dist/commands/control-plane-read.d.ts +8 -8
- package/dist/commands/deploy-promote.d.ts +1 -1
- package/dist/commands/deploy.d.ts +3 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +180 -22
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/flags.d.ts +1 -1
- package/dist/commands/init.d.ts +2 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +29 -5
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/link.d.ts +1 -1
- package/dist/commands/migrate.d.ts +1 -1
- package/dist/commands/rollback.d.ts +1 -1
- package/dist/commands/secrets.d.ts +2 -2
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/validate.d.ts +2 -2
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/init/templates.d.ts +1 -1
- package/dist/init/templates.d.ts.map +1 -1
- package/dist/init/templates.js +71 -1
- package/dist/init/templates.js.map +1 -1
- package/dist/services/live.d.ts +1 -1
- package/package.json +8 -8
- package/dist/cloudflare-worker-versions.d.ts +0 -184
- package/dist/cloudflare-worker-versions.d.ts.map +0 -1
- package/dist/cloudflare-worker-versions.js +0 -360
- package/dist/cloudflare-worker-versions.js.map +0 -1
- package/dist/rollback-traffic.d.ts +0 -85
- package/dist/rollback-traffic.d.ts.map +0 -1
- package/dist/rollback-traffic.js +0 -204
- package/dist/rollback-traffic.js.map +0 -1
|
@@ -17,7 +17,7 @@ export declare function removeAccountBody(commandName: string, target: Option.Op
|
|
|
17
17
|
declare const whoamiCmd: Command.Command<"whoami", AccountStore, CliError, {
|
|
18
18
|
readonly json: boolean;
|
|
19
19
|
}>;
|
|
20
|
-
export declare const accountCmd: Command.Command<"account",
|
|
20
|
+
export declare const accountCmd: Command.Command<"account", AccountStore | Cwd, CliError, {
|
|
21
21
|
readonly subcommand: Option.Option<{
|
|
22
22
|
readonly cwd: Option.Option<string>;
|
|
23
23
|
readonly json: boolean;
|
|
@@ -42,20 +42,20 @@ export declare const accountCmd: Command.Command<"account", Cwd | AccountStore,
|
|
|
42
42
|
readonly yes: boolean;
|
|
43
43
|
}>;
|
|
44
44
|
}>;
|
|
45
|
-
export declare const accountsCmd: Command.Command<"accounts",
|
|
45
|
+
export declare const accountsCmd: Command.Command<"accounts", AccountStore | Cwd, CliError, {
|
|
46
46
|
readonly subcommand: Option.Option<{
|
|
47
|
+
readonly cwd: Option.Option<string>;
|
|
47
48
|
readonly json: boolean;
|
|
48
49
|
} | {
|
|
49
|
-
readonly
|
|
50
|
+
readonly cwd: Option.Option<string>;
|
|
50
51
|
readonly json: boolean;
|
|
51
52
|
} | {
|
|
52
|
-
readonly 'account-id': Option.Option<string>;
|
|
53
53
|
readonly json: boolean;
|
|
54
54
|
} | {
|
|
55
|
-
readonly
|
|
55
|
+
readonly 'account-id': Option.Option<string>;
|
|
56
56
|
readonly json: boolean;
|
|
57
57
|
} | {
|
|
58
|
-
readonly
|
|
58
|
+
readonly 'account-id': Option.Option<string>;
|
|
59
59
|
readonly json: boolean;
|
|
60
60
|
} | {
|
|
61
61
|
readonly 'account-id': Option.Option<string>;
|
package/dist/commands/api.js
CHANGED
|
@@ -521,7 +521,7 @@ Examples:
|
|
|
521
521
|
hs-x api v1/accounts/me
|
|
522
522
|
hs-x api v1/deploys --json
|
|
523
523
|
hs-x api hubspot crm-dev-applications/v3/apps
|
|
524
|
-
hs-x api hubspot feature-flags/
|
|
524
|
+
hs-x api hubspot feature-flags/2026-03/<appId>/flags/hs-release-mcp-server
|
|
525
525
|
hs-x api hubspot crm-dev-platform/v3/projects/<projectId>/builds
|
|
526
526
|
`;
|
|
527
527
|
}
|
|
@@ -40,7 +40,7 @@ export declare function resolveOperationProjectForRead(opts: CpReadOptions, inpu
|
|
|
40
40
|
readonly message: string;
|
|
41
41
|
readonly emptyMessage: string;
|
|
42
42
|
}): Effect.Effect<OperationProjectSelection | undefined, CliError, AccountStore | ControlPlaneClient | Cwd | Reporter>;
|
|
43
|
-
export declare const auditCmd: Command.Command<"audit",
|
|
43
|
+
export declare const auditCmd: Command.Command<"audit", AccountStore | Cwd | ControlPlaneClient, CliError, {
|
|
44
44
|
readonly limit: number;
|
|
45
45
|
readonly since: Option.Option<string>;
|
|
46
46
|
readonly action: Option.Option<string>;
|
|
@@ -53,7 +53,7 @@ export declare const auditCmd: Command.Command<"audit", Cwd | AccountStore | Con
|
|
|
53
53
|
readonly projectId: Option.Option<string>;
|
|
54
54
|
readonly userId: Option.Option<string>;
|
|
55
55
|
}>;
|
|
56
|
-
export declare const auditListCmd: Command.Command<"list",
|
|
56
|
+
export declare const auditListCmd: Command.Command<"list", AccountStore | Cwd | ControlPlaneClient, CliError, {
|
|
57
57
|
readonly limit: number;
|
|
58
58
|
readonly since: Option.Option<string>;
|
|
59
59
|
readonly action: Option.Option<string>;
|
|
@@ -73,7 +73,7 @@ export declare function parseAuditSince(value: string | undefined, now?: number)
|
|
|
73
73
|
readonly ok: false;
|
|
74
74
|
readonly message: string;
|
|
75
75
|
};
|
|
76
|
-
export declare const driftCmd: Command.Command<"drift",
|
|
76
|
+
export declare const driftCmd: Command.Command<"drift", AccountStore | Cwd | ControlPlaneClient, CliError, {
|
|
77
77
|
readonly json: boolean;
|
|
78
78
|
readonly controlPlaneUrl: Option.Option<string>;
|
|
79
79
|
readonly accountId: Option.Option<string>;
|
|
@@ -120,14 +120,14 @@ export declare function remoteStatusBody(opts: RemoteStatusOptions, projectId: s
|
|
|
120
120
|
export declare function renderRemoteStatus(input: RemoteProjectStatus & {
|
|
121
121
|
readonly projectId: string;
|
|
122
122
|
}): string;
|
|
123
|
-
export declare const checkpointCmd: Command.Command<"checkpoint",
|
|
123
|
+
export declare const checkpointCmd: Command.Command<"checkpoint", AccountStore | Cwd | ControlPlaneClient, CliError, {
|
|
124
124
|
readonly json: boolean;
|
|
125
125
|
readonly controlPlaneUrl: Option.Option<string>;
|
|
126
126
|
readonly accountId: Option.Option<string>;
|
|
127
127
|
readonly projectId: Option.Option<string>;
|
|
128
128
|
readonly userId: Option.Option<string>;
|
|
129
129
|
}>;
|
|
130
|
-
export declare const logsCmd: Command.Command<"logs",
|
|
130
|
+
export declare const logsCmd: Command.Command<"logs", AccountStore | Cwd | ControlPlaneClient, CliError, {
|
|
131
131
|
readonly limit: number;
|
|
132
132
|
readonly sinceMinutes: number;
|
|
133
133
|
readonly trace: Option.Option<string>;
|
|
@@ -152,21 +152,21 @@ export declare function logsBodyForCheckpoint(opts: CpReadOptions, selection: Op
|
|
|
152
152
|
export declare function logsBodyForStatus(opts: RemoteStatusOptions, selection: OperationProjectSelection): Effect.Effect<void, CliError, AccountStore | ControlPlaneClient | Cwd | Reporter>;
|
|
153
153
|
export declare function routesBodyForStatus(opts: RemoteStatusOptions, selection: OperationProjectSelection): Effect.Effect<void, CliError, AccountStore | ControlPlaneClient | Cwd | Reporter>;
|
|
154
154
|
export declare function driftBodyForStatus(opts: RemoteStatusOptions, selection: OperationProjectSelection): Effect.Effect<void, CliError, AccountStore | ControlPlaneClient | Cwd | Reporter>;
|
|
155
|
-
export declare const routingCmd: Command.Command<"
|
|
155
|
+
export declare const routingCmd: Command.Command<"routes" | "routing" | "route", AccountStore | Cwd | ControlPlaneClient, CliError, {
|
|
156
156
|
readonly json: boolean;
|
|
157
157
|
readonly controlPlaneUrl: Option.Option<string>;
|
|
158
158
|
readonly accountId: Option.Option<string>;
|
|
159
159
|
readonly projectId: Option.Option<string>;
|
|
160
160
|
readonly userId: Option.Option<string>;
|
|
161
161
|
}>;
|
|
162
|
-
export declare const routeCmd: Command.Command<"
|
|
162
|
+
export declare const routeCmd: Command.Command<"routes" | "routing" | "route", AccountStore | Cwd | ControlPlaneClient, CliError, {
|
|
163
163
|
readonly json: boolean;
|
|
164
164
|
readonly controlPlaneUrl: Option.Option<string>;
|
|
165
165
|
readonly accountId: Option.Option<string>;
|
|
166
166
|
readonly projectId: Option.Option<string>;
|
|
167
167
|
readonly userId: Option.Option<string>;
|
|
168
168
|
}>;
|
|
169
|
-
export declare const routesCmd: Command.Command<"
|
|
169
|
+
export declare const routesCmd: Command.Command<"routes" | "routing" | "route", AccountStore | Cwd | ControlPlaneClient, CliError, {
|
|
170
170
|
readonly json: boolean;
|
|
171
171
|
readonly controlPlaneUrl: Option.Option<string>;
|
|
172
172
|
readonly accountId: Option.Option<string>;
|
|
@@ -8,7 +8,7 @@ import { AccountStore } from '../services/account-store.js';
|
|
|
8
8
|
import { ControlPlaneClient } from '../services/control-plane.js';
|
|
9
9
|
import { Cwd } from '../services/cwd.js';
|
|
10
10
|
import { CliHttp } from '../services/http.js';
|
|
11
|
-
export declare const promoteCmd: Command.Command<"promote",
|
|
11
|
+
export declare const promoteCmd: Command.Command<"promote", AccountStore | Cwd | CliHttp | ControlPlaneClient, CliError, {
|
|
12
12
|
readonly cwd: Option.Option<string>;
|
|
13
13
|
readonly json: boolean;
|
|
14
14
|
readonly deployId: Option.Option<string>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Command from '@effect/cli/Command';
|
|
2
2
|
import { type WorkerManifest } from '@hs-x/codegen';
|
|
3
|
-
import type { AppAlertsConfiguration, AppEventBatchingConfiguration, AppEventDeclaration, AppObjectAssociationDeclaration, AppObjectDeclaration, AppRedactionConfiguration, CardDefinition, HubSpotRateLimitConfiguration } from '@hs-x/types';
|
|
3
|
+
import type { AppAlertsConfiguration, AppEventBatchingConfiguration, AppEventDeclaration, AppObjectAssociationDeclaration, AppObjectDeclaration, AppRedactionConfiguration, CardDefinition, HubSpotRateLimitConfiguration, McpServerDefinition } from '@hs-x/types';
|
|
4
4
|
import { Schema, schemas } from '@hs-x/types';
|
|
5
5
|
import type { AppBillingDeclaration } from '@hs-x/types';
|
|
6
6
|
import { Option } from 'effect';
|
|
@@ -132,8 +132,10 @@ interface HsxAppConfig {
|
|
|
132
132
|
readonly alerts?: AppAlertsConfiguration;
|
|
133
133
|
readonly redaction?: AppRedactionConfiguration;
|
|
134
134
|
readonly cards: readonly CardDefinition[];
|
|
135
|
+
readonly mcpServers: readonly McpServerDefinition[];
|
|
135
136
|
readonly billing?: AppBillingDeclaration;
|
|
136
137
|
}
|
|
138
|
+
export declare function readHsxAppConfig(root: string): Promise<HsxAppConfig>;
|
|
137
139
|
export declare const deployCmd: Command.Command<"deploy", Cwd, import("../cli-error.js").CliError, {
|
|
138
140
|
readonly json: boolean;
|
|
139
141
|
readonly cwd: Option.Option<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { createHash, randomBytes } from 'node:crypto';
|
|
3
|
-
import { cp, mkdir, mkdtemp, readFile, readdir, stat, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { cp, lstat, mkdir, mkdtemp, readFile, readdir, realpath, rename, rmdir, stat, unlink, writeFile, } from 'node:fs/promises';
|
|
4
4
|
import { createServer } from 'node:http';
|
|
5
5
|
import { tmpdir } from 'node:os';
|
|
6
|
-
import { basename, dirname, join, relative, resolve } from 'node:path';
|
|
6
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
7
7
|
import { pathToFileURL } from 'node:url';
|
|
8
8
|
import * as Command from '@effect/cli/Command';
|
|
9
9
|
import * as Options from '@effect/cli/Options';
|
|
@@ -646,6 +646,7 @@ export async function deployCommand({ argv, root, json, }) {
|
|
|
646
646
|
projectId = await readHsxConfigProjectId(root);
|
|
647
647
|
}
|
|
648
648
|
const needsRuntime = workers.some((worker) => worker.capabilities.some((capability) => capability.runtimeNeeds.some((need) => need !== 'hubspot-only')));
|
|
649
|
+
const needsHubSpotBundle = needsRuntime || app.mcpServers.length > 0;
|
|
649
650
|
const cloudflareDeployRequested = !buildOnly &&
|
|
650
651
|
(explicitCloudflareDeployRequested || (!planOnly && needsRuntime && !explicitHubspotUpload));
|
|
651
652
|
const hubspotUploadRequested = !buildOnly && (explicitHubspotUpload || (!planOnly && !cloudflareDryRun && Boolean(projectId)));
|
|
@@ -1135,7 +1136,7 @@ export async function deployCommand({ argv, root, json, }) {
|
|
|
1135
1136
|
// Default order (skipped when we already uploaded first above): generate the
|
|
1136
1137
|
// HubSpot bundle from the deployed Worker URL, then upload.
|
|
1137
1138
|
if (!uploadFirstOrigin && hubspotUploadRequested && validation.ok) {
|
|
1138
|
-
const bundleStep =
|
|
1139
|
+
const bundleStep = needsHubSpotBundle ? progress?.step('Generating HubSpot bundle') : undefined;
|
|
1139
1140
|
try {
|
|
1140
1141
|
await ensureHubSpotRuntimeProjectArtifacts({
|
|
1141
1142
|
argv,
|
|
@@ -3121,8 +3122,161 @@ async function resolveUploadFirstRuntimeOrigin(input) {
|
|
|
3121
3122
|
return undefined;
|
|
3122
3123
|
}
|
|
3123
3124
|
}
|
|
3125
|
+
const HUBSPOT_GENERATED_LEDGER = '.hs-x/hubspot-generated-files.json';
|
|
3126
|
+
const USER_OWNED_GENERATED_PATHS = new Set(['src/app/cards/package.json']);
|
|
3127
|
+
function generatedFileHash(contents) {
|
|
3128
|
+
return createHash('sha256').update(contents).digest('hex');
|
|
3129
|
+
}
|
|
3130
|
+
function isKnownGeneratedHubSpotPath(file) {
|
|
3131
|
+
return (file === 'hsproject.json' ||
|
|
3132
|
+
file === 'src/app/app-hsmeta.json' ||
|
|
3133
|
+
file === 'src/app/cards/package.json' ||
|
|
3134
|
+
file === 'src/app/cards/_hsx-backend.ts' ||
|
|
3135
|
+
/^src\/app\/(?:workflow-actions|app-objects|app-object-associations|app-events|mcp-server|cards)\/[^/]+-hsmeta\.json$/.test(file));
|
|
3136
|
+
}
|
|
3137
|
+
/** Resolve a ledger path only when it is a known, normalized root-relative artifact. */
|
|
3138
|
+
function resolveGeneratedFilePath(root, file) {
|
|
3139
|
+
if (!isKnownGeneratedHubSpotPath(file) || isAbsolute(file) || file.includes('\\')) {
|
|
3140
|
+
return undefined;
|
|
3141
|
+
}
|
|
3142
|
+
const segments = file.split('/');
|
|
3143
|
+
if (segments.some((segment) => segment === '' || segment === '.' || segment === '..')) {
|
|
3144
|
+
return undefined;
|
|
3145
|
+
}
|
|
3146
|
+
const rootPath = resolve(root);
|
|
3147
|
+
const resolved = resolve(rootPath, file);
|
|
3148
|
+
return resolved.startsWith(`${rootPath}/`) ? resolved : undefined;
|
|
3149
|
+
}
|
|
3150
|
+
async function assertGeneratedPathIsContained(root, path) {
|
|
3151
|
+
const rootRealPath = await realpath(root);
|
|
3152
|
+
let existingAncestor = dirname(path);
|
|
3153
|
+
while (true) {
|
|
3154
|
+
try {
|
|
3155
|
+
const ancestorRealPath = await realpath(existingAncestor);
|
|
3156
|
+
const fromRoot = relative(rootRealPath, ancestorRealPath);
|
|
3157
|
+
if (fromRoot.startsWith('..') || isAbsolute(fromRoot)) {
|
|
3158
|
+
throw new Error(`Generated HubSpot artifact parent escapes the project root: ${path}`);
|
|
3159
|
+
}
|
|
3160
|
+
break;
|
|
3161
|
+
}
|
|
3162
|
+
catch (error) {
|
|
3163
|
+
if (error.code !== 'ENOENT')
|
|
3164
|
+
throw error;
|
|
3165
|
+
const parent = dirname(existingAncestor);
|
|
3166
|
+
if (parent === existingAncestor)
|
|
3167
|
+
throw error;
|
|
3168
|
+
existingAncestor = parent;
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
const target = await lstat(path).catch((error) => {
|
|
3172
|
+
if (error.code === 'ENOENT')
|
|
3173
|
+
return undefined;
|
|
3174
|
+
throw error;
|
|
3175
|
+
});
|
|
3176
|
+
if (target?.isSymbolicLink()) {
|
|
3177
|
+
throw new Error(`Generated HubSpot artifact path must not be a symbolic link: ${path}`);
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
async function readGeneratedFileLedger(root) {
|
|
3181
|
+
try {
|
|
3182
|
+
const parsed = JSON.parse(await readFile(join(root, HUBSPOT_GENERATED_LEDGER), 'utf8'));
|
|
3183
|
+
if (typeof parsed !== 'object' ||
|
|
3184
|
+
parsed === null ||
|
|
3185
|
+
parsed.version !== 1 ||
|
|
3186
|
+
typeof parsed.files !== 'object' ||
|
|
3187
|
+
parsed.files === null) {
|
|
3188
|
+
return { version: 1, files: {} };
|
|
3189
|
+
}
|
|
3190
|
+
const files = {};
|
|
3191
|
+
for (const [file, hash] of Object.entries(parsed.files)) {
|
|
3192
|
+
if (resolveGeneratedFilePath(root, file) && /^[a-f0-9]{64}$/.test(String(hash))) {
|
|
3193
|
+
files[file] = String(hash);
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3196
|
+
return { version: 1, files };
|
|
3197
|
+
}
|
|
3198
|
+
catch {
|
|
3199
|
+
// No heuristic cleanup for projects that predate the ledger, or for a
|
|
3200
|
+
// malformed ledger. Generation can safely establish a fresh ledger.
|
|
3201
|
+
return { version: 1, files: {} };
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
async function pruneEmptyGeneratedDirectories(root, from) {
|
|
3205
|
+
const rootPath = resolve(root);
|
|
3206
|
+
let directory = resolve(from);
|
|
3207
|
+
while (directory !== rootPath && directory.startsWith(`${rootPath}/`)) {
|
|
3208
|
+
try {
|
|
3209
|
+
if ((await readdir(directory)).length > 0)
|
|
3210
|
+
return;
|
|
3211
|
+
await rmdir(directory);
|
|
3212
|
+
}
|
|
3213
|
+
catch {
|
|
3214
|
+
return;
|
|
3215
|
+
}
|
|
3216
|
+
directory = dirname(directory);
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
async function reconcileHubSpotRuntimeProjectFiles(root, generatedFiles, options = {}) {
|
|
3220
|
+
const previous = await readGeneratedFileLedger(root);
|
|
3221
|
+
const generatedPaths = new Set(Object.keys(generatedFiles));
|
|
3222
|
+
const nextFiles = {};
|
|
3223
|
+
for (const [file, expectedHash] of Object.entries(previous.files)) {
|
|
3224
|
+
if (generatedPaths.has(file) || USER_OWNED_GENERATED_PATHS.has(file))
|
|
3225
|
+
continue;
|
|
3226
|
+
if (options.preservePrevious?.(file)) {
|
|
3227
|
+
nextFiles[file] = expectedHash;
|
|
3228
|
+
continue;
|
|
3229
|
+
}
|
|
3230
|
+
const path = resolveGeneratedFilePath(root, file);
|
|
3231
|
+
if (!path)
|
|
3232
|
+
continue;
|
|
3233
|
+
try {
|
|
3234
|
+
await assertGeneratedPathIsContained(root, path);
|
|
3235
|
+
const current = await readFile(path);
|
|
3236
|
+
if (generatedFileHash(current) !== expectedHash)
|
|
3237
|
+
continue;
|
|
3238
|
+
await unlink(path);
|
|
3239
|
+
await pruneEmptyGeneratedDirectories(root, dirname(path));
|
|
3240
|
+
}
|
|
3241
|
+
catch {
|
|
3242
|
+
// Missing and non-file paths are preserved; only a byte-for-byte owned
|
|
3243
|
+
// regular file is eligible for removal.
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
for (const [file, contents] of Object.entries(generatedFiles)) {
|
|
3247
|
+
const path = resolveGeneratedFilePath(root, file);
|
|
3248
|
+
if (!path)
|
|
3249
|
+
throw new Error(`Generated HubSpot artifact has an unsafe path: ${file}`);
|
|
3250
|
+
await assertGeneratedPathIsContained(root, path);
|
|
3251
|
+
// HubSpot tells card authors to add dependencies here. Once created, this
|
|
3252
|
+
// file is user-owned and is deliberately never entered in the ledger.
|
|
3253
|
+
if (USER_OWNED_GENERATED_PATHS.has(file)) {
|
|
3254
|
+
if (!(await stat(path).catch(() => undefined))) {
|
|
3255
|
+
await mkdir(dirname(path), { recursive: true });
|
|
3256
|
+
await writeFile(path, contents);
|
|
3257
|
+
}
|
|
3258
|
+
continue;
|
|
3259
|
+
}
|
|
3260
|
+
await mkdir(dirname(path), { recursive: true });
|
|
3261
|
+
await writeFile(path, contents);
|
|
3262
|
+
nextFiles[file] = generatedFileHash(contents);
|
|
3263
|
+
}
|
|
3264
|
+
const ledgerPath = join(root, HUBSPOT_GENERATED_LEDGER);
|
|
3265
|
+
await assertGeneratedPathIsContained(root, ledgerPath);
|
|
3266
|
+
await mkdir(dirname(ledgerPath), { recursive: true });
|
|
3267
|
+
const temporaryLedgerPath = `${ledgerPath}.${process.pid}.${randomBytes(6).toString('hex')}.tmp`;
|
|
3268
|
+
await writeFile(temporaryLedgerPath, `${JSON.stringify({ version: 1, files: nextFiles }, null, 2)}\n`);
|
|
3269
|
+
await rename(temporaryLedgerPath, ledgerPath);
|
|
3270
|
+
}
|
|
3124
3271
|
export async function ensureHubSpotRuntimeProjectArtifacts({ argv, root, app, workers, cloudflareDeployResult, needsRuntime, controlPlanePlan, runtimeOrigin, }) {
|
|
3125
|
-
|
|
3272
|
+
const hasMcpServers = app.mcpServers.length > 0;
|
|
3273
|
+
if (!needsRuntime && !hasMcpServers) {
|
|
3274
|
+
// A prior MCP-only generation may have left ledger-owned MCP files. Remove
|
|
3275
|
+
// those declarations, but retain other generated metadata: a display-only
|
|
3276
|
+
// card or schema declaration remains valid when its runtime worker is gone.
|
|
3277
|
+
await reconcileHubSpotRuntimeProjectFiles(root, {}, {
|
|
3278
|
+
preservePrevious: (file) => !file.startsWith('src/app/mcp-server/'),
|
|
3279
|
+
});
|
|
3126
3280
|
return;
|
|
3127
3281
|
}
|
|
3128
3282
|
const runtimeBaseUrl = runtimeOrigin ??
|
|
@@ -3135,26 +3289,17 @@ export async function ensureHubSpotRuntimeProjectArtifacts({ argv, root, app, wo
|
|
|
3135
3289
|
const redirectUrls = app.auth === 'oauth' && oauthCallbackPath
|
|
3136
3290
|
? [`${runtimeBaseUrl.replace(/\/$/, '')}${oauthCallbackPath}`]
|
|
3137
3291
|
: [];
|
|
3292
|
+
const platformVersion = resolveFlag(argv, '--platform-version') ?? app.platformVersion;
|
|
3138
3293
|
const generated = generateHubSpotRuntimeProject({
|
|
3139
3294
|
...app,
|
|
3295
|
+
platformVersion,
|
|
3140
3296
|
workers,
|
|
3141
3297
|
runtimeBaseUrl,
|
|
3142
3298
|
redirectUrls,
|
|
3143
3299
|
});
|
|
3144
|
-
|
|
3145
|
-
const path = join(root, file);
|
|
3146
|
-
// src/app/cards/package.json is user-owned once it exists: HubSpot's own
|
|
3147
|
-
// build errors instruct users to add card dependencies (e.g. hs-uix) to
|
|
3148
|
-
// it, and regenerating the fixed-dep version here silently dropped those
|
|
3149
|
-
// deps so the card never built (cold-stranger run #2 blocker B). Keep the
|
|
3150
|
-
// user's file verbatim; only generate one when absent.
|
|
3151
|
-
if (file === 'src/app/cards/package.json' && (await stat(path).catch(() => undefined))) {
|
|
3152
|
-
continue;
|
|
3153
|
-
}
|
|
3154
|
-
await mkdir(dirname(path), { recursive: true });
|
|
3155
|
-
await writeFile(path, contents);
|
|
3156
|
-
}
|
|
3300
|
+
await reconcileHubSpotRuntimeProjectFiles(root, generated.files);
|
|
3157
3301
|
const migratedShimPath = join(root, 'src', 'app', 'cards', '_hsx-migration-run-serverless.ts');
|
|
3302
|
+
await assertGeneratedPathIsContained(root, migratedShimPath);
|
|
3158
3303
|
if (await stat(migratedShimPath).catch(() => undefined)) {
|
|
3159
3304
|
const migratedShim = await readFile(migratedShimPath, 'utf8');
|
|
3160
3305
|
await writeFile(migratedShimPath, stampMigratedRunServerlessShimOrigin(migratedShim, runtimeBaseUrl));
|
|
@@ -3169,9 +3314,19 @@ async function readHsxAppScopesForDeploy(root) {
|
|
|
3169
3314
|
return [];
|
|
3170
3315
|
}
|
|
3171
3316
|
}
|
|
3172
|
-
async function readHsxAppConfig(root) {
|
|
3317
|
+
export async function readHsxAppConfig(root) {
|
|
3173
3318
|
const raw = await readFile(join(root, 'hsx.config.ts'), 'utf8');
|
|
3174
|
-
|
|
3319
|
+
let loaded = parseHsxAppConfigLiteral(raw);
|
|
3320
|
+
if (!loaded) {
|
|
3321
|
+
try {
|
|
3322
|
+
loaded = await loadHsxAppConfigModule(root);
|
|
3323
|
+
}
|
|
3324
|
+
catch (error) {
|
|
3325
|
+
if (/\bmcpServer\s*\(|\bmcpServers\b/.test(raw)) {
|
|
3326
|
+
throw new Error('Could not evaluate helper-based MCP declarations in hsx.config.ts; refusing to treat the declaration set as empty because that could remove generated MCP metadata.', { cause: error });
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3175
3330
|
return {
|
|
3176
3331
|
appName: loaded?.name ?? /name\s*:\s*["'`]([^"'`]+)["'`]/.exec(raw)?.[1] ?? basename(root),
|
|
3177
3332
|
// No regex fallback for description: a raw-text match could pick up a
|
|
@@ -3193,9 +3348,10 @@ async function readHsxAppConfig(root) {
|
|
|
3193
3348
|
...(loaded?.rateLimits !== undefined ? { rateLimits: loaded.rateLimits } : {}),
|
|
3194
3349
|
...(loaded?.alerts !== undefined ? { alerts: loaded.alerts } : {}),
|
|
3195
3350
|
...(loaded?.redaction !== undefined ? { redaction: loaded.redaction } : {}),
|
|
3196
|
-
//
|
|
3197
|
-
//
|
|
3351
|
+
// Helper-based declarations are only recoverable from the loaded module
|
|
3352
|
+
// (the literal parser cannot evaluate card(...) or mcpServer(...) calls).
|
|
3198
3353
|
cards: loaded?.cards ?? [],
|
|
3354
|
+
mcpServers: loaded?.mcpServers ?? [],
|
|
3199
3355
|
...(loaded?.billing ? { billing: loaded.billing } : {}),
|
|
3200
3356
|
};
|
|
3201
3357
|
}
|
|
@@ -3527,11 +3683,13 @@ async function executeHubSpotOnlyUpload({ argv, root, local, uploadOnly, }) {
|
|
|
3527
3683
|
cwd: root,
|
|
3528
3684
|
});
|
|
3529
3685
|
await client.projects.ensureProject({ projectName });
|
|
3686
|
+
const hsproject = await readHubSpotProjectConfig(root);
|
|
3687
|
+
const configuredPlatformVersion = typeof hsproject.platformVersion === 'string' ? hsproject.platformVersion : undefined;
|
|
3530
3688
|
const upload = await client.projects.upload({
|
|
3531
3689
|
projectName,
|
|
3532
3690
|
archivePath,
|
|
3533
3691
|
message: resolveFlag(argv, '--message') ?? 'HS-X HubSpot-only deploy',
|
|
3534
|
-
platformVersion: resolveFlag(argv, '--platform-version') ?? '2026.03',
|
|
3692
|
+
platformVersion: resolveFlag(argv, '--platform-version') ?? configuredPlatformVersion ?? '2026.03',
|
|
3535
3693
|
intermediateRepresentation,
|
|
3536
3694
|
});
|
|
3537
3695
|
const buildStatus = await waitForHubSpotBuildStatus({
|