@hypequery/cli 1.20.0 → 1.21.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/README.md CHANGED
@@ -18,8 +18,29 @@ For a semantic layer:
18
18
 
19
19
  ```bash
20
20
  npx hypequery init --style datasets
21
+ npx hypequery login
22
+ npx hypequery deploy analytics/cloud.ts
21
23
  ```
22
24
 
25
+ The dataset scaffold writes `analytics/cloud.ts` alongside the local
26
+ `analytics/api.ts`. Its Cloud publication is explicit:
27
+
28
+ ```ts
29
+ import { publishToCloud } from '@hypequery/datasets';
30
+ import { datasets } from './datasets.js';
31
+
32
+ export const cloud = publishToCloud({
33
+ datasets,
34
+ access: { roles: [], scopes: [] },
35
+ });
36
+ ```
37
+
38
+ `api.ts` remains the local Serve entrypoint. Cloud deployment builds from
39
+ `cloud.ts` and does not load Serve configuration. This first Cloud publisher
40
+ accepts datasets only; it rejects named metrics rather than dropping them.
41
+ The required access policy makes the authenticated roles and scopes visible
42
+ before an existing project moves away from Serve-based publishing.
43
+
23
44
  For embedded analytics without a ClickHouse server:
24
45
 
25
46
  ```bash
@@ -38,7 +59,7 @@ npx hypequery init \
38
59
  | `hypequery generate:datasets` | Dataset definitions scaffolded from tables |
39
60
  | `hypequery generate:manifest` | A browser-safe route manifest for React hooks |
40
61
  | `hypequery login` | An authenticated Cloud target |
41
- | `hypequery deploy` | A verified deployment of the analytics API |
62
+ | `hypequery deploy analytics/cloud.ts` | A verified dataset-only Cloud deployment |
42
63
  | `hypequery pull` / `diff` | Live source inspection and comparison |
43
64
 
44
65
  Non-interactive ClickHouse commands read `CLICKHOUSE_URL`, `CLICKHOUSE_DATABASE`, `CLICKHOUSE_USERNAME`, and `CLICKHOUSE_PASSWORD`.
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiCpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAa9B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAKpE;AA6QD,OAAO,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiCpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAa9B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAKpE;AAqQD,OAAO,EAAE,OAAO,EAAE,CAAC"}
package/dist/cli.js CHANGED
@@ -167,13 +167,12 @@ program
167
167
  await generateManifestCommand(api, options);
168
168
  }));
169
169
  program
170
- .command('deployment:build <api>')
171
- .description('Build a verified deployment bundle')
170
+ .command('deployment:build <cloud>')
171
+ .description('Build a verified dataset-only Cloud deployment bundle')
172
172
  .option('--bundle-output <directory>', 'Bundle directory (default: analytics/hypequery-deployment)')
173
173
  .option('--no-source', 'Exclude project source files from the deployment bundle')
174
- .option('--allow-unsupported-config', 'Deploy even though some Serve config will not be honoured in Cloud')
175
- .action(runCommand(async (api, options) => {
176
- await buildDeploymentCommand(api, options);
174
+ .action(runCommand(async (cloud, options) => {
175
+ await buildDeploymentCommand(cloud, options);
177
176
  }));
178
177
  program
179
178
  .command('deployment:validate <artifact>')
@@ -201,7 +200,7 @@ program
201
200
  }));
202
201
  program
203
202
  .command('deploy <source>')
204
- .description('Build, prepare, and deploy a Hypequery API module')
203
+ .description('Build, prepare, and deploy a dataset-only Cloud publication')
205
204
  .option('--bundle-output <directory>', 'Bundle directory (default: analytics/hypequery-deployment)')
206
205
  .option('--release-output <path>', 'Release JSON path (default: beside the bundle)')
207
206
  .option('--project <project>', 'Target project identifier (advanced override)')
@@ -209,7 +208,6 @@ program
209
208
  .option('--no-source', 'Exclude project source files from the deployment bundle')
210
209
  .option('--endpoint <url>', 'HTTPS submission endpoint; requires HYPEQUERY_API_TOKEN')
211
210
  .option('--replace-restored', 'Intentionally replace a restored live release')
212
- .option('--allow-unsupported-config', 'Deploy even though some Serve config will not be honoured in Cloud')
213
211
  .action(runCommand(async (source, options) => {
214
212
  await deployCommand(source, options);
215
213
  }));
@@ -245,9 +243,9 @@ program.on('--help', () => {
245
243
  console.log(' hypequery generate:types --output analytics/schema.ts');
246
244
  console.log(' hypequery generate:datasets');
247
245
  console.log(' hypequery generate:manifest analytics/api.ts --output analytics/hypequery-manifest.json');
248
- console.log(' hypequery deploy analytics/api.ts');
249
- console.log(' hypequery deploy analytics/api.ts --project my-project --environment production');
250
- console.log(' hypequery deployment:build analytics/api.ts');
246
+ console.log(' hypequery deploy analytics/cloud.ts');
247
+ console.log(' hypequery deploy analytics/cloud.ts --project my-project --environment production');
248
+ console.log(' hypequery deployment:build analytics/cloud.ts');
251
249
  console.log(' hypequery deployment:validate analytics/hypequery-deployment');
252
250
  console.log(' hypequery deployment:release analytics/hypequery-deployment --project my-project --environment production');
253
251
  console.log(' hypequery deployment:submit analytics/hypequery-deployment --release analytics/hypequery-deployment.release.json');
@@ -15,7 +15,6 @@ export interface DeployOptions {
15
15
  bundleOutput?: string;
16
16
  releaseOutput?: string;
17
17
  source?: boolean;
18
- allowUnsupportedConfig?: boolean;
19
18
  }
20
19
  export interface SubmitDeploymentDependencies {
21
20
  readonly env?: Readonly<Record<string, string | undefined>>;
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AASA,OAAO,EACL,mCAAmC,EAEnC,KAAK,4BAA4B,EAElC,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,KAAK,qBAAqB,EAC3B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAChC,MAAM,iBAAiB,CAAC;AAMzB,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC5D,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,mCAAmC,CAAC;IACtE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,mBAAmB,CAAC;CACjD;AAED,MAAM,WAAW,kBAAmB,SAAQ,4BAA4B;IACtE,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,sBAAsB,CAAC;IACzD,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,+BAA+B,CAAC;IAC3E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,uBAAuB,CAAC;CAC5D;AA4DD,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,uBAA4B,EACrC,YAAY,GAAE,4BAAiC,GAC9C,OAAO,CAAC,4BAA4B,CAAC,CA0EvC;AAsBD,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,aAAkB,EAC3B,YAAY,GAAE,kBAAuB,GACpC,OAAO,CAAC,4BAA4B,CAAC,CAwCvC"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AASA,OAAO,EACL,mCAAmC,EAEnC,KAAK,4BAA4B,EAElC,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,KAAK,qBAAqB,EAC3B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAChC,MAAM,iBAAiB,CAAC;AAMzB,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC5D,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,mCAAmC,CAAC;IACtE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,mBAAmB,CAAC;CACjD;AAED,MAAM,WAAW,kBAAmB,SAAQ,4BAA4B;IACtE,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,sBAAsB,CAAC;IACzD,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,+BAA+B,CAAC;IAC3E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,uBAAuB,CAAC;CAC5D;AA4DD,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,uBAA4B,EACrC,YAAY,GAAE,4BAAiC,GAC9C,OAAO,CAAC,4BAA4B,CAAC,CA0EvC;AAsBD,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,aAAkB,EAC3B,YAAY,GAAE,kBAAuB,GACpC,OAAO,CAAC,4BAA4B,CAAC,CAuCvC"}
@@ -123,7 +123,7 @@ export async function submitDeploymentCommand(bundlePath, options = {}, dependen
123
123
  return result;
124
124
  }
125
125
  /**
126
- * `deploy` takes an API module, but the deprecated form took a bundle
126
+ * `deploy` takes a Cloud publication module, but the deprecated form took a bundle
127
127
  * directory. Dropping `--release` from an existing script would otherwise hand
128
128
  * a bundle to the module loader and fail inside esbuild.
129
129
  */
@@ -135,15 +135,15 @@ async function rejectBundleDirectorySource(sourcePath) {
135
135
  return;
136
136
  }
137
137
  throw new Error(`Cannot deploy a prebuilt bundle directory: ${sourcePath}\n\n`
138
- + '`hypequery deploy` takes the API module to build, for example '
139
- + '`hypequery deploy analytics/api.ts`.\n'
138
+ + '`hypequery deploy` takes a Cloud publication module, for example '
139
+ + '`hypequery deploy analytics/cloud.ts`.\n'
140
140
  + 'To upload this bundle, use `hypequery deployment:submit '
141
141
  + `${sourcePath} --release <file>\`.`);
142
142
  }
143
143
  export async function deployCommand(sourcePath, options = {}, dependencies = {}) {
144
144
  if (!sourcePath) {
145
- throw new Error('Missing API module path.\n\n'
146
- + 'Usage: hypequery deploy analytics/api.ts');
145
+ throw new Error('Missing Cloud publication module path.\n\n'
146
+ + 'Usage: hypequery deploy analytics/cloud.ts');
147
147
  }
148
148
  await rejectBundleDirectorySource(sourcePath);
149
149
  const bundlePath = options.bundleOutput ?? DEFAULT_BUNDLE_PATH;
@@ -159,7 +159,6 @@ export async function deployCommand(sourcePath, options = {}, dependencies = {})
159
159
  await build(sourcePath, {
160
160
  bundleOutput: bundlePath,
161
161
  source: options.source,
162
- allowUnsupportedConfig: options.allowUnsupportedConfig,
163
162
  });
164
163
  await prepareRelease(bundlePath, {
165
164
  project: options.project,
@@ -3,7 +3,6 @@ import { type StoredCloudCredential } from '../utils/cloud-credential-store.js';
3
3
  export interface BuildDeploymentOptions {
4
4
  bundleOutput?: string;
5
5
  source?: boolean;
6
- allowUnsupportedConfig?: boolean;
7
6
  }
8
7
  export interface PrepareDeploymentReleaseOptions {
9
8
  project?: string;
@@ -18,7 +17,7 @@ export interface PrepareDeploymentReleaseDependencies {
18
17
  */
19
18
  outputFlagLabel?: string;
20
19
  }
21
- export declare function buildDeploymentCommand(apiPath: string | undefined, options?: BuildDeploymentOptions): Promise<ProtocolDeploymentContract>;
20
+ export declare function buildDeploymentCommand(sourcePath: string | undefined, options?: BuildDeploymentOptions): Promise<ProtocolDeploymentContract>;
22
21
  export declare function validateDeploymentCommand(artifactPath: string | undefined): Promise<ProtocolDeploymentContract>;
23
22
  export declare function prepareDeploymentReleaseCommand(bundlePath: string | undefined, options?: PrepareDeploymentReleaseOptions, dependencies?: PrepareDeploymentReleaseDependencies): Promise<ProtocolDeploymentReleaseEnvelope>;
24
23
  //# sourceMappingURL=deployment.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../../src/commands/deployment.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,iCAAiC,EACvC,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,oCAAoC,CAAC;AAE5C,MAAM,WAAW,sBAAsB;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,+BAA+B;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oCAAoC;IACnD,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;IAC7D;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAYD,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,0BAA0B,CAAC,CAyCrC;AAUD,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,OAAO,CAAC,0BAA0B,CAAC,CAqErC;AAiED,wBAAsB,+BAA+B,CACnD,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,+BAAoC,EAC7C,YAAY,GAAE,oCAAyC,GACtD,OAAO,CAAC,iCAAiC,CAAC,CAkE5C"}
1
+ {"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../../src/commands/deployment.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,iCAAiC,EACvC,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,oCAAoC,CAAC;AAE5C,MAAM,WAAW,sBAAsB;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,+BAA+B;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oCAAoC;IACnD,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;IAC7D;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAID,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,0BAA0B,CAAC,CAkCrC;AAUD,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,OAAO,CAAC,0BAA0B,CAAC,CAqErC;AAiED,wBAAsB,+BAA+B,CACnD,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,+BAAoC,EAC7C,YAAY,GAAE,oCAAyC,GACtD,OAAO,CAAC,iCAAiC,CAAC,CAkE5C"}
@@ -3,31 +3,26 @@ import path from 'node:path';
3
3
  import { prepareProtocolDeploymentReleaseEnvelope, prepareProtocolDeploymentContract, } from '@hypequery/protocol';
4
4
  import { writeDeploymentBundle, verifyDeploymentBundle, } from '../utils/deployment-bundle.js';
5
5
  import { captureDeploymentSourceSnapshot } from '../utils/deployment-source-snapshot.js';
6
- import { loadApiModule } from '../utils/load-api.js';
6
+ import { loadCloudPublication } from '../utils/load-cloud-publication.js';
7
7
  import { logger } from '../utils/logger.js';
8
- import { reportCloudDiagnostic } from '../utils/cloud-diagnostic.js';
9
8
  import { loadCloudCredential, } from '../utils/cloud-credential-store.js';
10
9
  const DEFAULT_BUNDLE_OUTPUT = 'analytics/hypequery-deployment';
11
- export async function buildDeploymentCommand(apiPath, options = {}) {
12
- if (!apiPath) {
13
- throw new Error('Missing API module path.\n\n'
14
- + 'Usage: hypequery deployment:build analytics/api.ts');
10
+ export async function buildDeploymentCommand(sourcePath, options = {}) {
11
+ if (!sourcePath) {
12
+ throw new Error('Missing Cloud publication module path.\n\n'
13
+ + 'Usage: hypequery deployment:build analytics/cloud.ts');
15
14
  }
16
15
  const bundleOutput = options.bundleOutput ?? DEFAULT_BUNDLE_OUTPUT;
17
- const api = await loadApiModule(apiPath);
18
- if (typeof api.deploymentContract !== 'function') {
19
- throw new Error(`Invalid API module: ${apiPath}\n\n`
20
- + 'The exported API must provide deploymentContract(). '
21
- + 'Upgrade @hypequery/serve and export the value returned by createAPI() or serve().');
22
- }
23
- const contract = api.deploymentContract({
24
- ...(options.allowUnsupportedConfig ? { allowUnsupportedConfig: true } : {}),
25
- onCloudDiagnostic: diagnostic => reportCloudDiagnostic(diagnostic, options.allowUnsupportedConfig === true),
26
- });
16
+ const contract = await loadCloudPublication(sourcePath);
17
+ const candidate = contract;
18
+ if ((Array.isArray(candidate.queries) && candidate.queries.length > 0)
19
+ || (Array.isArray(candidate.artifacts) && candidate.artifacts.length > 0)) {
20
+ throw new Error('Cloud publication modules may publish datasets only.');
21
+ }
27
22
  const prepared = prepareProtocolDeploymentContract(contract);
28
23
  const sourceSnapshot = options.source === false
29
24
  ? undefined
30
- : await captureDeploymentSourceSnapshot(apiPath);
25
+ : await captureDeploymentSourceSnapshot(sourcePath);
31
26
  const bundle = await writeDeploymentBundle(bundleOutput, prepared, sourceSnapshot);
32
27
  logger.success(`Deployment bundle written to ${bundle.directory}`);
33
28
  if (bundle.manifest.source) {
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAIA,OAAO,EAcL,KAAK,SAAS,EACf,MAAM,qBAAqB,CAAC;AAe7B,OAAO,EAA2B,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAWzF,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAqKD,wBAAsB,WAAW,CAAC,OAAO,GAAE,WAAgB,iBAkb1D"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAIA,OAAO,EAcL,KAAK,SAAS,EACf,MAAM,qBAAqB,CAAC;AAe7B,OAAO,EAA2B,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAYzF,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAqKD,wBAAsB,WAAW,CAAC,OAAO,GAAE,WAAgB,iBAsb1D"}
@@ -10,6 +10,7 @@ import { generateEnvTemplate, appendToEnv } from '../templates/env.js';
10
10
  import { generateClientTemplate } from '../templates/client.js';
11
11
  import { generateQueriesTemplate } from '../templates/queries.js';
12
12
  import { generateApiTemplate } from '../templates/api.js';
13
+ import { generateCloudTemplate } from '../templates/cloud.js';
13
14
  import { CONTEXT_AUTH_TENANT_COLUMN } from '../templates/auth-scaffold.js';
14
15
  import { generateDatasetsPlaceholderTemplate } from '../templates/datasets.js';
15
16
  import { appendToGitignore } from '../templates/gitignore.js';
@@ -234,6 +235,7 @@ export async function initCommand(options = {}) {
234
235
  ? [
235
236
  path.join(resolvedOutputDir, 'datasets.ts'),
236
237
  path.join(resolvedOutputDir, 'api.ts'),
238
+ path.join(resolvedOutputDir, 'cloud.ts'),
237
239
  ]
238
240
  : [
239
241
  path.join(resolvedOutputDir, 'queries.ts'),
@@ -421,6 +423,9 @@ export interface IntrospectedSchema {
421
423
  apiPath = path.join(resolvedOutputDir, 'api.ts');
422
424
  await writeFile(apiPath, generateApiTemplate({ auth }));
423
425
  logger.success(`Created API file (${path.relative(process.cwd(), apiPath)})`);
426
+ const cloudPath = path.join(resolvedOutputDir, 'cloud.ts');
427
+ await writeFile(cloudPath, generateCloudTemplate());
428
+ logger.success(`Created Cloud publication (${path.relative(process.cwd(), cloudPath)})`);
424
429
  }
425
430
  else {
426
431
  apiPath = path.join(resolvedOutputDir, 'queries.ts');
@@ -0,0 +1,3 @@
1
+ /** Generate the explicit Cloud publication entrypoint for dataset projects. */
2
+ export declare function generateCloudTemplate(): string;
3
+ //# sourceMappingURL=cloud.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../../src/templates/cloud.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,wBAAgB,qBAAqB,IAAI,MAAM,CAS9C"}
@@ -0,0 +1,11 @@
1
+ /** Generate the explicit Cloud publication entrypoint for dataset projects. */
2
+ export function generateCloudTemplate() {
3
+ return `import { publishToCloud } from '@hypequery/datasets';
4
+ import { datasets } from './datasets.js';
5
+
6
+ export const cloud = publishToCloud({
7
+ datasets,
8
+ access: { roles: [], scopes: [] },
9
+ });
10
+ `;
11
+ }
@@ -0,0 +1,4 @@
1
+ import type { ProtocolDeploymentContract } from '@hypequery/protocol';
2
+ /** Load the explicit dataset contract exported by a Cloud publication module. */
3
+ export declare function loadCloudPublication(sourcePath: string): Promise<ProtocolDeploymentContract>;
4
+ //# sourceMappingURL=load-cloud-publication.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-cloud-publication.d.ts","sourceRoot":"","sources":["../../src/utils/load-cloud-publication.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAGtE,iFAAiF;AACjF,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAYlG"}
@@ -0,0 +1,13 @@
1
+ import { loadModule } from './load-api.js';
2
+ /** Load the explicit dataset contract exported by a Cloud publication module. */
3
+ export async function loadCloudPublication(sourcePath) {
4
+ const module = await loadModule(sourcePath);
5
+ const cloud = module.cloud ?? module.default;
6
+ if (typeof cloud !== 'object' || cloud === null
7
+ || !('kind' in cloud) || cloud.kind !== 'hypequery-deployment') {
8
+ throw new Error(`Invalid Cloud publication: ${sourcePath}\n\n`
9
+ + 'Export `cloud = publishToCloud({ datasets, access })` from @hypequery/datasets. '
10
+ + 'A Serve API is not a Cloud publication.');
11
+ }
12
+ return cloud;
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypequery/cli",
3
- "version": "1.20.0",
3
+ "version": "1.21.0",
4
4
  "description": "CLI for scaffolding type-safe ClickHouse analytics, semantic datasets, React manifests, and deployments",
5
5
  "keywords": [
6
6
  "clickhouse",
@@ -30,8 +30,8 @@
30
30
  "open": "^10.0.0",
31
31
  "ora": "^8.0.1",
32
32
  "prompts": "^2.4.2",
33
- "@hypequery/deployment": "0.9.0",
34
- "@hypequery/protocol": "0.14.0"
33
+ "@hypequery/deployment": "0.9.1",
34
+ "@hypequery/protocol": "0.15.0"
35
35
  },
36
36
  "optionalDependencies": {
37
37
  "@napi-rs/keyring": "1.3.0"
@@ -51,8 +51,8 @@
51
51
  "@vitest/coverage-v8": "^3.2.6",
52
52
  "typescript": "^5.7.3",
53
53
  "vitest": "^3.2.6",
54
- "@hypequery/mcp": "0.8.1",
55
- "@hypequery/serve": "0.18.0"
54
+ "@hypequery/mcp": "0.8.2",
55
+ "@hypequery/serve": "0.19.0"
56
56
  },
57
57
  "repository": {
58
58
  "type": "git",
@@ -1,10 +0,0 @@
1
- export interface CloudCompatibilityDiagnosticLike {
2
- readonly severity: 'error' | 'warning';
3
- readonly code: string;
4
- readonly subject: string;
5
- readonly message: string;
6
- readonly remedy: string;
7
- }
8
- /** Report warnings and explicitly overridden errors before submitting a release. */
9
- export declare function reportCloudDiagnostic(diagnostic: CloudCompatibilityDiagnosticLike, allowUnsupportedConfig: boolean): void;
10
- //# sourceMappingURL=cloud-diagnostic.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cloud-diagnostic.d.ts","sourceRoot":"","sources":["../../src/utils/cloud-diagnostic.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,oFAAoF;AACpF,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,gCAAgC,EAC5C,sBAAsB,EAAE,OAAO,GAC9B,IAAI,CAMN"}
@@ -1,10 +0,0 @@
1
- import { logger } from './logger.js';
2
- /** Report warnings and explicitly overridden errors before submitting a release. */
3
- export function reportCloudDiagnostic(diagnostic, allowUnsupportedConfig) {
4
- // Blocking errors are reported by the contract builder's exception.
5
- if (diagnostic.severity === 'error' && !allowUnsupportedConfig)
6
- return;
7
- logger.warn(`${diagnostic.code} (${diagnostic.subject})`);
8
- logger.indent(diagnostic.message);
9
- logger.indent(`→ ${diagnostic.remedy}`);
10
- }