@hypequery/cli 1.26.0 → 1.28.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 +14 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +9 -2
- package/dist/commands/deploy.d.ts +6 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +48 -2
- package/dist/commands/deployment.d.ts.map +1 -1
- package/dist/commands/deployment.js +11 -0
- package/dist/commands/generate-client.d.ts +13 -1
- package/dist/commands/generate-client.d.ts.map +1 -1
- package/dist/commands/generate-client.js +41 -7
- package/dist/generators/client-contract/render.d.ts +7 -1
- package/dist/generators/client-contract/render.d.ts.map +1 -1
- package/dist/generators/client-contract/render.js +5 -3
- package/dist/generators/dataset-generator.d.ts.map +1 -1
- package/dist/generators/dataset-generator.js +77 -68
- package/dist/templates/cloud.d.ts.map +1 -1
- package/dist/templates/cloud.js +3 -0
- package/dist/utils/clickhouse-dimension-type.d.ts +27 -0
- package/dist/utils/clickhouse-dimension-type.d.ts.map +1 -0
- package/dist/utils/clickhouse-dimension-type.js +61 -0
- package/dist/utils/clickhouse-type-utils.d.ts.map +1 -1
- package/dist/utils/clickhouse-type-utils.js +9 -1
- package/dist/utils/client-contract-file.d.ts +5 -0
- package/dist/utils/client-contract-file.d.ts.map +1 -1
- package/dist/utils/client-contract-file.js +49 -5
- package/dist/utils/cloud-client-contract.d.ts +20 -0
- package/dist/utils/cloud-client-contract.d.ts.map +1 -0
- package/dist/utils/cloud-client-contract.js +52 -0
- package/dist/utils/deployment-upload.d.ts +6 -2
- package/dist/utils/deployment-upload.d.ts.map +1 -1
- package/dist/utils/deployment-upload.js +12 -2
- package/dist/utils/draft-deployment.d.ts +16 -0
- package/dist/utils/draft-deployment.d.ts.map +1 -0
- package/dist/utils/draft-deployment.js +35 -0
- package/dist/utils/field-namer.d.ts +10 -0
- package/dist/utils/field-namer.d.ts.map +1 -0
- package/dist/utils/field-namer.js +20 -0
- package/dist/utils/json-pointer.d.ts +3 -0
- package/dist/utils/json-pointer.d.ts.map +1 -0
- package/dist/utils/json-pointer.js +4 -0
- package/dist/utils/live-deployment.d.ts +1 -1
- package/dist/utils/live-deployment.d.ts.map +1 -1
- package/dist/utils/read-capped.d.ts +6 -0
- package/dist/utils/read-capped.d.ts.map +1 -0
- package/dist/utils/read-capped.js +36 -0
- package/dist/utils/shell-quote.d.ts +6 -0
- package/dist/utils/shell-quote.d.ts.map +1 -0
- package/dist/utils/shell-quote.js +7 -0
- package/dist/utils/telemetry/catalog.d.ts +1 -1
- package/dist/utils/telemetry/domains.d.ts +6 -6
- package/dist/utils/telemetry/domains.js +6 -6
- package/dist/utils/tenant-key-candidates.d.ts +19 -0
- package/dist/utils/tenant-key-candidates.d.ts.map +1 -0
- package/dist/utils/tenant-key-candidates.js +63 -0
- package/package.json +7 -7
|
@@ -15,14 +15,14 @@ export declare const COMMAND_FLAGS: {
|
|
|
15
15
|
readonly 'generate:types': readonly ["--output", "--path", "--tables", "--database", "--chdb-path"];
|
|
16
16
|
readonly 'generate:datasets': readonly ["--output", "--path", "--tables", "--exclude-tables", "--tenant-column", "--force", "--check", "--diff"];
|
|
17
17
|
readonly 'generate:manifest': readonly ["--output"];
|
|
18
|
-
readonly 'generate:client': readonly ["--output", "--check", "--force"];
|
|
18
|
+
readonly 'generate:client': readonly ["--output", "--check", "--force", "--cloud", "--project", "--environment", "--endpoint"];
|
|
19
19
|
readonly login: readonly ["--cloud-url", "--environment"];
|
|
20
20
|
readonly logout: readonly [];
|
|
21
|
-
readonly deploy: readonly ["--bundle-output", "--release-output", "--project", "--environment", "--no-source", "--endpoint", "--replace-restored", "--mcp-config"];
|
|
21
|
+
readonly deploy: readonly ["--bundle-output", "--release-output", "--project", "--environment", "--no-source", "--endpoint", "--replace-restored", "--mcp-config", "--draft", "--client"];
|
|
22
22
|
readonly 'deployment:build': readonly ["--bundle-output", "--no-source"];
|
|
23
23
|
readonly 'deployment:validate': readonly [];
|
|
24
24
|
readonly 'deployment:release': readonly ["--project", "--environment", "--output"];
|
|
25
|
-
readonly 'deployment:submit': readonly ["--release", "--endpoint", "--replace-restored"];
|
|
25
|
+
readonly 'deployment:submit': readonly ["--release", "--endpoint", "--replace-restored", "--draft"];
|
|
26
26
|
readonly 'deployment:status': readonly ["--project", "--environment", "--endpoint", "--mcp-config"];
|
|
27
27
|
readonly pull: readonly ["--output", "--project", "--environment", "--endpoint"];
|
|
28
28
|
readonly diff: readonly ["--project", "--environment", "--endpoint"];
|
|
@@ -41,14 +41,14 @@ export declare const VALUE_FLAGS: {
|
|
|
41
41
|
readonly 'generate:types': readonly ["--output", "--path", "--tables", "--database", "--chdb-path"];
|
|
42
42
|
readonly 'generate:datasets': readonly ["--output", "--path", "--tables", "--exclude-tables", "--tenant-column"];
|
|
43
43
|
readonly 'generate:manifest': readonly ["--output"];
|
|
44
|
-
readonly 'generate:client': readonly ["--output"];
|
|
44
|
+
readonly 'generate:client': readonly ["--output", "--project", "--environment", "--endpoint"];
|
|
45
45
|
readonly login: readonly ["--cloud-url", "--environment"];
|
|
46
46
|
readonly logout: readonly [];
|
|
47
|
-
readonly deploy: readonly ["--bundle-output", "--release-output", "--project", "--environment", "--endpoint"];
|
|
47
|
+
readonly deploy: readonly ["--bundle-output", "--release-output", "--project", "--environment", "--endpoint", "--draft", "--client"];
|
|
48
48
|
readonly 'deployment:build': readonly ["--bundle-output"];
|
|
49
49
|
readonly 'deployment:validate': readonly [];
|
|
50
50
|
readonly 'deployment:release': readonly ["--project", "--environment", "--output"];
|
|
51
|
-
readonly 'deployment:submit': readonly ["--release", "--endpoint"];
|
|
51
|
+
readonly 'deployment:submit': readonly ["--release", "--endpoint", "--draft"];
|
|
52
52
|
readonly 'deployment:status': readonly ["--project", "--environment", "--endpoint"];
|
|
53
53
|
readonly pull: readonly ["--output", "--project", "--environment", "--endpoint"];
|
|
54
54
|
readonly diff: readonly ["--project", "--environment", "--endpoint"];
|
|
@@ -24,14 +24,14 @@ export const COMMAND_FLAGS = {
|
|
|
24
24
|
'generate:types': ['--output', '--path', '--tables', '--database', '--chdb-path'],
|
|
25
25
|
'generate:datasets': ['--output', '--path', '--tables', '--exclude-tables', '--tenant-column', '--force', '--check', '--diff'],
|
|
26
26
|
'generate:manifest': ['--output'],
|
|
27
|
-
'generate:client': ['--output', '--check', '--force'],
|
|
27
|
+
'generate:client': ['--output', '--check', '--force', '--cloud', '--project', '--environment', '--endpoint'],
|
|
28
28
|
login: ['--cloud-url', '--environment'],
|
|
29
29
|
logout: [],
|
|
30
|
-
deploy: ['--bundle-output', '--release-output', '--project', '--environment', '--no-source', '--endpoint', '--replace-restored', '--mcp-config'],
|
|
30
|
+
deploy: ['--bundle-output', '--release-output', '--project', '--environment', '--no-source', '--endpoint', '--replace-restored', '--mcp-config', '--draft', '--client'],
|
|
31
31
|
'deployment:build': ['--bundle-output', '--no-source'],
|
|
32
32
|
'deployment:validate': [],
|
|
33
33
|
'deployment:release': ['--project', '--environment', '--output'],
|
|
34
|
-
'deployment:submit': ['--release', '--endpoint', '--replace-restored'],
|
|
34
|
+
'deployment:submit': ['--release', '--endpoint', '--replace-restored', '--draft'],
|
|
35
35
|
'deployment:status': ['--project', '--environment', '--endpoint', '--mcp-config'],
|
|
36
36
|
pull: ['--output', '--project', '--environment', '--endpoint'],
|
|
37
37
|
diff: ['--project', '--environment', '--endpoint'],
|
|
@@ -47,14 +47,14 @@ export const VALUE_FLAGS = {
|
|
|
47
47
|
'generate:types': ['--output', '--path', '--tables', '--database', '--chdb-path'],
|
|
48
48
|
'generate:datasets': ['--output', '--path', '--tables', '--exclude-tables', '--tenant-column'],
|
|
49
49
|
'generate:manifest': ['--output'],
|
|
50
|
-
'generate:client': ['--output'],
|
|
50
|
+
'generate:client': ['--output', '--project', '--environment', '--endpoint'],
|
|
51
51
|
login: ['--cloud-url', '--environment'],
|
|
52
52
|
logout: [],
|
|
53
|
-
deploy: ['--bundle-output', '--release-output', '--project', '--environment', '--endpoint'],
|
|
53
|
+
deploy: ['--bundle-output', '--release-output', '--project', '--environment', '--endpoint', '--draft', '--client'],
|
|
54
54
|
'deployment:build': ['--bundle-output'],
|
|
55
55
|
'deployment:validate': [],
|
|
56
56
|
'deployment:release': ['--project', '--environment', '--output'],
|
|
57
|
-
'deployment:submit': ['--release', '--endpoint'],
|
|
57
|
+
'deployment:submit': ['--release', '--endpoint', '--draft'],
|
|
58
58
|
'deployment:status': ['--project', '--environment', '--endpoint'],
|
|
59
59
|
pull: ['--output', '--project', '--environment', '--endpoint'],
|
|
60
60
|
diff: ['--project', '--environment', '--endpoint'],
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ProtocolDeploymentContract } from '@hypequery/protocol';
|
|
2
|
+
/**
|
|
3
|
+
* Whether a column name is worth presenting as a possible tenant key.
|
|
4
|
+
*
|
|
5
|
+
* A naming match is never enough to activate tenant enforcement. `tenantKey`
|
|
6
|
+
* is a security boundary that must be chosen explicitly by the application.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isTenantKeyCandidateName(name: string): boolean;
|
|
9
|
+
export interface UnscopedTenantCandidate {
|
|
10
|
+
readonly dataset: string;
|
|
11
|
+
readonly columns: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Served datasets about to be published with a customer-like column that
|
|
15
|
+
* neither the dataset nor its endpoint scopes by tenant. Datasets without an
|
|
16
|
+
* endpoint are not callable, so they are skipped.
|
|
17
|
+
*/
|
|
18
|
+
export declare function unscopedTenantCandidates(contract: ProtocolDeploymentContract): UnscopedTenantCandidate[];
|
|
19
|
+
//# sourceMappingURL=tenant-key-candidates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-key-candidates.d.ts","sourceRoot":"","sources":["../../src/utils/tenant-key-candidates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AActE;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAoCD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,0BAA0B,GAAG,uBAAuB,EAAE,CAMxG"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Kept in step with Cloud's customer-scope review, so the CLI and onboarding flag the same columns.
|
|
2
|
+
const CANDIDATE_NAMES = new Set([
|
|
3
|
+
'tenant_id',
|
|
4
|
+
'org_id',
|
|
5
|
+
'organization_id',
|
|
6
|
+
'organisation_id',
|
|
7
|
+
'account_id',
|
|
8
|
+
'customer_id',
|
|
9
|
+
'workspace_id',
|
|
10
|
+
'company_id',
|
|
11
|
+
]);
|
|
12
|
+
/**
|
|
13
|
+
* Whether a column name is worth presenting as a possible tenant key.
|
|
14
|
+
*
|
|
15
|
+
* A naming match is never enough to activate tenant enforcement. `tenantKey`
|
|
16
|
+
* is a security boundary that must be chosen explicitly by the application.
|
|
17
|
+
*/
|
|
18
|
+
export function isTenantKeyCandidateName(name) {
|
|
19
|
+
return CANDIDATE_NAMES.has(name.toLowerCase());
|
|
20
|
+
}
|
|
21
|
+
const lastSegment = (name) => name.slice(name.lastIndexOf('.') + 1);
|
|
22
|
+
/**
|
|
23
|
+
* The physical columns a dataset reads from its own table, which are the only
|
|
24
|
+
* values `tenantKey` accepts. Dimension sources may be table-qualified or SQL
|
|
25
|
+
* with declared dependencies; measure and filter fields may name a dimension,
|
|
26
|
+
* which resolves to its source. Fields reached through a relationship belong
|
|
27
|
+
* to another table and are skipped.
|
|
28
|
+
*/
|
|
29
|
+
function ownColumns(dataset) {
|
|
30
|
+
const related = new Set((dataset.relationships ?? []).map((relationship) => String(relationship.name)));
|
|
31
|
+
const own = (reference) => {
|
|
32
|
+
const dot = reference.lastIndexOf('.');
|
|
33
|
+
return dot < 0 || !related.has(reference.slice(0, dot));
|
|
34
|
+
};
|
|
35
|
+
const sourceColumns = (dimension) => (dimension.source.kind === 'column' ? [dimension.source.column] : dimension.source.dependencies.map(String))
|
|
36
|
+
.filter(own)
|
|
37
|
+
.map(lastSegment);
|
|
38
|
+
const dimensions = new Map(dataset.dimensions.map((dimension) => [String(dimension.name), dimension]));
|
|
39
|
+
const resolve = (field) => {
|
|
40
|
+
if (!own(field))
|
|
41
|
+
return [];
|
|
42
|
+
const dimension = dimensions.get(lastSegment(field));
|
|
43
|
+
return dimension ? sourceColumns(dimension) : [lastSegment(field)];
|
|
44
|
+
};
|
|
45
|
+
return [
|
|
46
|
+
...dataset.dimensions.flatMap(sourceColumns),
|
|
47
|
+
...dataset.measures.flatMap((measure) => 'field' in measure ? resolve(String(measure.field)) : []),
|
|
48
|
+
...dataset.filters.flatMap((filter) => resolve(String(filter.field))),
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Served datasets about to be published with a customer-like column that
|
|
53
|
+
* neither the dataset nor its endpoint scopes by tenant. Datasets without an
|
|
54
|
+
* endpoint are not callable, so they are skipped.
|
|
55
|
+
*/
|
|
56
|
+
export function unscopedTenantCandidates(contract) {
|
|
57
|
+
return contract.datasets.flatMap((dataset) => {
|
|
58
|
+
if (!dataset.endpoint || dataset.tenant.kind === 'required' || dataset.endpoint.tenant.kind === 'required')
|
|
59
|
+
return [];
|
|
60
|
+
const columns = [...new Set(ownColumns(dataset).filter(isTenantKeyCandidateName))];
|
|
61
|
+
return columns.length ? [{ dataset: dataset.name, columns }] : [];
|
|
62
|
+
});
|
|
63
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hypequery/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0",
|
|
4
4
|
"description": "CLI for scaffolding type-safe ClickHouse analytics, semantic datasets, React manifests, and deployments",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"clickhouse",
|
|
@@ -23,15 +23,15 @@
|
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@clickhouse/client": "^1.24.1",
|
|
26
|
-
"chalk": "^
|
|
26
|
+
"chalk": "^6.0.1",
|
|
27
27
|
"commander": "^15.0.0",
|
|
28
28
|
"dotenv": "^18.0.8",
|
|
29
29
|
"esbuild": "^0.28.2",
|
|
30
30
|
"open": "^11.0.4",
|
|
31
|
-
"ora": "^
|
|
31
|
+
"ora": "^9.4.1",
|
|
32
32
|
"prompts": "^2.4.2",
|
|
33
|
-
"@hypequery/deployment": "0.11.
|
|
34
|
-
"@hypequery/protocol": "0.24.
|
|
33
|
+
"@hypequery/deployment": "0.11.2",
|
|
34
|
+
"@hypequery/protocol": "0.24.2"
|
|
35
35
|
},
|
|
36
36
|
"optionalDependencies": {
|
|
37
37
|
"@napi-rs/keyring": "2.1.2"
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"@vitest/coverage-v8": "^5.0.5",
|
|
55
55
|
"typescript": "^6.0.3",
|
|
56
56
|
"vitest": "^5.0.5",
|
|
57
|
-
"@hypequery/mcp": "0.11.
|
|
58
|
-
"@hypequery/serve": "0.24.
|
|
57
|
+
"@hypequery/mcp": "0.11.2",
|
|
58
|
+
"@hypequery/serve": "0.24.2"
|
|
59
59
|
},
|
|
60
60
|
"repository": {
|
|
61
61
|
"type": "git",
|