@dataparade/cli 0.0.2 → 0.0.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.
- package/README.md +25 -0
- package/dist/package.json +85 -0
- package/dist/src/ai-enrichment/agent-orchestrator.d.ts +2 -0
- package/dist/src/ai-enrichment/agent-orchestrator.js +8 -5
- package/dist/src/ai-enrichment/providers/hosted-worker-infer-provider.d.ts +10 -0
- package/dist/src/ai-enrichment/providers/hosted-worker-infer-provider.js +47 -0
- package/dist/src/cli.js +85 -1
- package/dist/src/config/env.js +2 -0
- package/dist/src/config/resolve.js +3 -0
- package/dist/src/config/scan-env.d.ts +1 -0
- package/dist/src/config/scan-env.js +5 -0
- package/dist/src/config/types.d.ts +1 -0
- package/dist/src/config/upload-env.d.ts +1 -0
- package/dist/src/config/upload-env.js +10 -0
- package/dist/src/config/validate-scan-ai.d.ts +1 -1
- package/dist/src/config/validate-scan-ai.js +5 -0
- package/dist/src/core/pipeline/ai-orchestrator-options.js +5 -0
- package/dist/src/core/pipeline/graph-mapping.js +5 -0
- package/dist/src/core/pipeline/infer-data-flow-protocol.d.ts +7 -0
- package/dist/src/core/pipeline/infer-data-flow-protocol.js +39 -0
- package/dist/src/core/schema/scan-config.schema.d.ts +2 -0
- package/dist/src/core/schema/scan-config.schema.js +2 -1
- package/dist/src/core/types/config.d.ts +3 -1
- package/dist/src/observability/scan-sentry.d.ts +1 -1
- package/dist/src/platform-api/dataparade-app-base-url.d.ts +7 -0
- package/dist/src/platform-api/dataparade-app-base-url.js +14 -0
- package/dist/src/platform-api/upload-client.d.ts +3 -0
- package/dist/src/platform-api/upload-client.js +38 -0
- package/dist/src/platform-api/upload.types.d.ts +10 -0
- package/dist/src/platform-api/upload.types.js +2 -0
- package/dist/src/upload/build-preview-url.d.ts +1 -0
- package/dist/src/upload/build-preview-url.js +10 -0
- package/dist/src/upload/run-upload.d.ts +2 -0
- package/dist/src/upload/run-upload.js +18 -0
- package/dist/src/upload/types.d.ts +11 -0
- package/dist/src/upload/types.js +2 -0
- package/dist/tests/unit/analyzers/typescript/property-detection.spec.js +22 -0
- package/dist/tests/unit/cli/scan-quota-flow.spec.js +2 -0
- package/dist/tests/unit/config/upload-env.spec.d.ts +1 -0
- package/dist/tests/unit/config/upload-env.spec.js +12 -0
- package/dist/tests/unit/config/validate-scan-ai.spec.js +8 -0
- package/dist/tests/unit/core/graph-mapping.spec.js +52 -0
- package/dist/tests/unit/core/infer-data-flow-protocol.spec.d.ts +1 -0
- package/dist/tests/unit/core/infer-data-flow-protocol.spec.js +37 -0
- package/dist/tests/unit/platform-api/dataparade-app-base-url.spec.d.ts +1 -0
- package/dist/tests/unit/platform-api/dataparade-app-base-url.spec.js +13 -0
- package/dist/tests/unit/platform-api/upload-client.spec.d.ts +1 -0
- package/dist/tests/unit/platform-api/upload-client.spec.js +40 -0
- package/dist/tests/unit/publish-manifest.spec.d.ts +1 -0
- package/dist/tests/unit/publish-manifest.spec.js +18 -0
- package/dist/tests/unit/upload/build-preview-url.spec.d.ts +1 -0
- package/dist/tests/unit/upload/build-preview-url.spec.js +19 -0
- package/package.json +4 -3
- package/patterns/README.md +322 -0
- package/patterns/actor.patterns.yaml +51 -0
- package/patterns/aws-terraform-catalog.snapshot.json +1760 -0
- package/patterns/aws-terraform-service-hints.generated.json +1446 -0
- package/patterns/azure-terraform-catalog.snapshot.json +1195 -0
- package/patterns/azure-terraform-service-hints.generated.json +864 -0
- package/patterns/classifier/actors.classifier.yaml +17 -0
- package/patterns/classifier/components.classifier.yaml +110 -0
- package/patterns/classifier/third-party.classifier.yaml +169 -0
- package/patterns/kubernetes-terraform-catalog.snapshot.json +94 -0
- package/patterns/kubernetes-terraform-service-hints.generated.json +258 -0
- package/patterns/non-pii-signals.rules.yaml +84 -0
- package/patterns/pii-signals.rules.yaml +115 -0
- package/patterns/property.patterns.yaml +431 -0
- package/patterns/provider-topology.rules.yaml +765 -0
- package/patterns/python.md +211 -0
- package/patterns/python.patterns.yaml +160 -0
- package/patterns/terraform.md +37 -0
- package/patterns/terraform.patterns.yaml +495 -0
- package/patterns/third-party.patterns.yaml +167 -0
- package/patterns/typescript.patterns.yaml +139 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function buildImportPreviewUrl(draftId: string): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildImportPreviewUrl = buildImportPreviewUrl;
|
|
4
|
+
const dataparade_app_base_url_1 = require("../platform-api/dataparade-app-base-url");
|
|
5
|
+
function buildImportPreviewUrl(draftId) {
|
|
6
|
+
const base = (0, dataparade_app_base_url_1.getDataparadeAppBaseUrl)();
|
|
7
|
+
const url = new URL("/dashboard", `${base}/`);
|
|
8
|
+
url.searchParams.set("importDraft", draftId);
|
|
9
|
+
return url.toString();
|
|
10
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runDataflowUpload = runDataflowUpload;
|
|
4
|
+
const upload_client_1 = require("../platform-api/upload-client");
|
|
5
|
+
const build_preview_url_1 = require("./build-preview-url");
|
|
6
|
+
async function runDataflowUpload(input) {
|
|
7
|
+
const prefix = input.logPrefix ?? "[upload]";
|
|
8
|
+
const result = await (0, upload_client_1.cliUploadPreview)({
|
|
9
|
+
apiKey: input.apiKey,
|
|
10
|
+
dataflow: input.dataflow,
|
|
11
|
+
projectName: input.projectName,
|
|
12
|
+
scanJobId: input.scanJobId,
|
|
13
|
+
});
|
|
14
|
+
const previewUrl = (0, build_preview_url_1.buildImportPreviewUrl)(result.draftId);
|
|
15
|
+
// eslint-disable-next-line no-console
|
|
16
|
+
console.log(`${prefix} Preview ready: ${previewUrl}`);
|
|
17
|
+
return { draftId: result.draftId, previewUrl };
|
|
18
|
+
}
|
|
@@ -122,6 +122,18 @@ describe("property-detection", () => {
|
|
|
122
122
|
expect(out.integration_method).toBe("api");
|
|
123
123
|
expect(out.authentication_method).toBe("api_key");
|
|
124
124
|
});
|
|
125
|
+
it("sets api_type graphql when url path is GraphQL", () => {
|
|
126
|
+
const finding = makeFinding({
|
|
127
|
+
pattern: "external_api_call",
|
|
128
|
+
name: "Graph API",
|
|
129
|
+
properties: {
|
|
130
|
+
serviceName: "internal",
|
|
131
|
+
url: "https://api.example.com/graphql",
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
const out = (0, property_inference_1.getPropertiesFromFinding)(finding);
|
|
135
|
+
expect(out.api_type).toBe("graphql");
|
|
136
|
+
});
|
|
125
137
|
});
|
|
126
138
|
describe("express_route", () => {
|
|
127
139
|
it("sets request_validation and connection_encryption", () => {
|
|
@@ -133,6 +145,16 @@ describe("property-detection", () => {
|
|
|
133
145
|
const out = (0, property_inference_1.getPropertiesFromFinding)(finding);
|
|
134
146
|
expect(out.request_validation).toBe(true);
|
|
135
147
|
expect(out.connection_encryption).toBe(true);
|
|
148
|
+
expect(out.api_type).toBe("rest");
|
|
149
|
+
});
|
|
150
|
+
it("sets api_type graphql for GraphQL route path", () => {
|
|
151
|
+
const finding = makeFinding({
|
|
152
|
+
pattern: "express_route",
|
|
153
|
+
name: "POST /graphql",
|
|
154
|
+
properties: { httpMethods: ["POST"], path: "/graphql" },
|
|
155
|
+
});
|
|
156
|
+
const out = (0, property_inference_1.getPropertiesFromFinding)(finding);
|
|
157
|
+
expect(out.api_type).toBe("graphql");
|
|
136
158
|
});
|
|
137
159
|
});
|
|
138
160
|
});
|
|
@@ -27,10 +27,12 @@ describe("scan quota flow", () => {
|
|
|
27
27
|
afterEach(() => {
|
|
28
28
|
fs_1.default.rmSync(tempRoot, { recursive: true, force: true });
|
|
29
29
|
delete process.env.DATAPARADE_WORKSPACE_API_KEY;
|
|
30
|
+
delete process.env.DATAPARADE_SKIP_AUTO_UPLOAD;
|
|
30
31
|
process.exitCode = 0;
|
|
31
32
|
});
|
|
32
33
|
it("skips quota API when workspace key is present but AI is disabled", async () => {
|
|
33
34
|
process.env.DATAPARADE_WORKSPACE_API_KEY = "dp_live_test";
|
|
35
|
+
process.env.DATAPARADE_SKIP_AUTO_UPLOAD = "true";
|
|
34
36
|
await (0, cli_1.run)(["node", "cli", "scan", tempRoot]);
|
|
35
37
|
expect(fetchMock).not.toHaveBeenCalled();
|
|
36
38
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const upload_env_1 = require("../../../src/config/upload-env");
|
|
4
|
+
describe("resolveSkipAutoUpload", () => {
|
|
5
|
+
it("is false when unset", () => {
|
|
6
|
+
expect((0, upload_env_1.resolveSkipAutoUpload)({})).toBe(false);
|
|
7
|
+
});
|
|
8
|
+
it("is true for truthy env values", () => {
|
|
9
|
+
expect((0, upload_env_1.resolveSkipAutoUpload)({ DATAPARADE_SKIP_AUTO_UPLOAD: "true" })).toBe(true);
|
|
10
|
+
expect((0, upload_env_1.resolveSkipAutoUpload)({ DATAPARADE_SKIP_AUTO_UPLOAD: "1" })).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -39,6 +39,14 @@ describe("validate-scan-ai", () => {
|
|
|
39
39
|
expect((0, validate_scan_ai_1.validateAiInferenceCredentials)(config)).toEqual([]);
|
|
40
40
|
expect((0, validate_scan_ai_1.resolveAiMode)(config)).toBe("platform");
|
|
41
41
|
});
|
|
42
|
+
it("accepts hosted worker infer proxy without BYOK or workspace key", () => {
|
|
43
|
+
const config = baseConfig({
|
|
44
|
+
enableAiInference: true,
|
|
45
|
+
hostedInferProxyUrl: "http://127.0.0.1:4567/infer",
|
|
46
|
+
});
|
|
47
|
+
expect((0, validate_scan_ai_1.validateAiInferenceCredentials)(config)).toEqual([]);
|
|
48
|
+
expect((0, validate_scan_ai_1.resolveAiMode)(config)).toBe("hosted_worker");
|
|
49
|
+
});
|
|
42
50
|
it("allows workspace key with AI disabled", () => {
|
|
43
51
|
const errors = (0, validate_scan_ai_1.validateAiInferenceCredentials)(baseConfig({
|
|
44
52
|
enableAiInference: false,
|
|
@@ -106,6 +106,7 @@ describe("core/pipeline/graph-mapping - DP-P0-CLI-402", () => {
|
|
|
106
106
|
return;
|
|
107
107
|
const properties = edge.data.properties;
|
|
108
108
|
expect(properties.engineering.transferType).toBe("api_call");
|
|
109
|
+
expect(properties.engineering.protocol).toBe("rest");
|
|
109
110
|
expect(properties.engineering.name).toContain("Test Application");
|
|
110
111
|
expect(properties.engineering.actions).toEqual(["read"]);
|
|
111
112
|
expect(properties.privacy.dataCategories).toEqual([
|
|
@@ -122,6 +123,57 @@ describe("core/pipeline/graph-mapping - DP-P0-CLI-402", () => {
|
|
|
122
123
|
expect(properties.targetScopeConfidence).toBe("high");
|
|
123
124
|
expect(properties.targetScopeReason).toBe("same-section-id");
|
|
124
125
|
});
|
|
126
|
+
it("sets engineering.protocol to graphql when flow endpoint is a GraphQL URL", () => {
|
|
127
|
+
const scanResult = {
|
|
128
|
+
components: [
|
|
129
|
+
{
|
|
130
|
+
id: "component-1",
|
|
131
|
+
name: "API Service",
|
|
132
|
+
type: "asset",
|
|
133
|
+
subType: "api",
|
|
134
|
+
confidence: 0.9,
|
|
135
|
+
detectedFrom: [{ pattern: "express_route" }],
|
|
136
|
+
sourceLocations: [
|
|
137
|
+
{ filePath: "src/api.ts", startLine: 1, endLine: 10 },
|
|
138
|
+
],
|
|
139
|
+
properties: {},
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: "component-2",
|
|
143
|
+
name: "External API",
|
|
144
|
+
type: "third_party",
|
|
145
|
+
subType: "saas_service",
|
|
146
|
+
confidence: 0.9,
|
|
147
|
+
detectedFrom: [{ pattern: "external_api_call" }],
|
|
148
|
+
sourceLocations: [
|
|
149
|
+
{ filePath: "src/api.ts", startLine: 20, endLine: 30 },
|
|
150
|
+
],
|
|
151
|
+
properties: {},
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
dataFlows: [
|
|
155
|
+
{
|
|
156
|
+
id: "flow-gql",
|
|
157
|
+
sourceComponentId: "component-1",
|
|
158
|
+
targetComponentId: "component-2",
|
|
159
|
+
type: "api_call",
|
|
160
|
+
confidence: 0.9,
|
|
161
|
+
endpoint: "https://api.example.com/graphql",
|
|
162
|
+
method: "POST",
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
filesScanned: 1,
|
|
166
|
+
filesSkipped: 0,
|
|
167
|
+
totalLines: 50,
|
|
168
|
+
scanDurationMs: 5,
|
|
169
|
+
warnings: [],
|
|
170
|
+
errors: [],
|
|
171
|
+
};
|
|
172
|
+
const graph = (0, graph_mapping_1.buildDiagramGraphFromScanResult)(scanResult);
|
|
173
|
+
const properties = graph.edges[0]?.data
|
|
174
|
+
?.properties;
|
|
175
|
+
expect(properties?.engineering?.protocol).toBe("graphql");
|
|
176
|
+
});
|
|
125
177
|
it("places managed provider service nodes after provider in layout", () => {
|
|
126
178
|
const scanResult = {
|
|
127
179
|
components: [
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const infer_data_flow_protocol_1 = require("../../../src/core/pipeline/infer-data-flow-protocol");
|
|
4
|
+
function baseFlow(overrides = {}) {
|
|
5
|
+
return {
|
|
6
|
+
id: "flow-1",
|
|
7
|
+
sourceComponentId: "a",
|
|
8
|
+
targetComponentId: "b",
|
|
9
|
+
type: "api_call",
|
|
10
|
+
confidence: 0.9,
|
|
11
|
+
...overrides,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
describe("inferDataFlowProtocol", () => {
|
|
15
|
+
it("returns graphql for /graphql endpoint", () => {
|
|
16
|
+
expect((0, infer_data_flow_protocol_1.inferDataFlowProtocol)(baseFlow({ endpoint: "https://api.example.com/graphql" }))).toBe("graphql");
|
|
17
|
+
});
|
|
18
|
+
it("returns graphql when source code mentions graphql", () => {
|
|
19
|
+
expect((0, infer_data_flow_protocol_1.inferDataFlowProtocol)(baseFlow({
|
|
20
|
+
sourceLocation: {
|
|
21
|
+
filePath: "src/client.ts",
|
|
22
|
+
startLine: 1,
|
|
23
|
+
endLine: 2,
|
|
24
|
+
code: "client.query({ query: GET_USERS }) // graphql",
|
|
25
|
+
},
|
|
26
|
+
}))).toBe("graphql");
|
|
27
|
+
});
|
|
28
|
+
it("returns rest for api_call with HTTP endpoint", () => {
|
|
29
|
+
expect((0, infer_data_flow_protocol_1.inferDataFlowProtocol)(baseFlow({ endpoint: "/api/users", method: "GET" }))).toBe("rest");
|
|
30
|
+
});
|
|
31
|
+
it("returns undefined for database_query", () => {
|
|
32
|
+
expect((0, infer_data_flow_protocol_1.inferDataFlowProtocol)(baseFlow({ type: "database_query", endpoint: "postgres://..." }))).toBeUndefined();
|
|
33
|
+
});
|
|
34
|
+
it("returns undefined for api_call without endpoint or method", () => {
|
|
35
|
+
expect((0, infer_data_flow_protocol_1.inferDataFlowProtocol)(baseFlow())).toBeUndefined();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const dataparade_app_base_url_1 = require("../../../src/platform-api/dataparade-app-base-url");
|
|
4
|
+
describe("getDataparadeAppBaseUrl", () => {
|
|
5
|
+
it("defaults to production frontend URL", () => {
|
|
6
|
+
expect((0, dataparade_app_base_url_1.getDataparadeAppBaseUrl)({})).toBe(dataparade_app_base_url_1.DEFAULT_DATAPARADE_APP_URL);
|
|
7
|
+
});
|
|
8
|
+
it("strips trailing slash from DATAPARADE_APP_URL", () => {
|
|
9
|
+
expect((0, dataparade_app_base_url_1.getDataparadeAppBaseUrl)({
|
|
10
|
+
DATAPARADE_APP_URL: "http://localhost:3001/",
|
|
11
|
+
})).toBe("http://localhost:3001");
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const upload_client_1 = require("../../../src/platform-api/upload-client");
|
|
4
|
+
describe("cliUploadPreview", () => {
|
|
5
|
+
const originalFetch = global.fetch;
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
global.fetch = originalFetch;
|
|
8
|
+
jest.restoreAllMocks();
|
|
9
|
+
});
|
|
10
|
+
it("posts dataflow to upload endpoint", async () => {
|
|
11
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
12
|
+
ok: true,
|
|
13
|
+
json: async () => ({ draftId: "draft-1", projectName: "proj" }),
|
|
14
|
+
});
|
|
15
|
+
const result = await (0, upload_client_1.cliUploadPreview)({
|
|
16
|
+
apiKey: "dp_live_testkey123456",
|
|
17
|
+
dataflow: { schemaVersion: "1.0", graph: { nodes: [], edges: [] } },
|
|
18
|
+
projectName: "proj",
|
|
19
|
+
scanJobId: "job-1",
|
|
20
|
+
});
|
|
21
|
+
expect(result.draftId).toBe("draft-1");
|
|
22
|
+
expect(global.fetch).toHaveBeenCalledWith(expect.stringContaining("/api/scans/cli/upload"), expect.objectContaining({
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: expect.objectContaining({
|
|
25
|
+
Authorization: "Bearer dp_live_testkey123456",
|
|
26
|
+
}),
|
|
27
|
+
}));
|
|
28
|
+
});
|
|
29
|
+
it("throws with API error message", async () => {
|
|
30
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
31
|
+
ok: false,
|
|
32
|
+
status: 400,
|
|
33
|
+
json: async () => ({ message: "Invalid dataflow" }),
|
|
34
|
+
});
|
|
35
|
+
await expect((0, upload_client_1.cliUploadPreview)({
|
|
36
|
+
apiKey: "dp_live_testkey123456",
|
|
37
|
+
dataflow: {},
|
|
38
|
+
})).rejects.toThrow("Invalid dataflow");
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
describe("npm publish manifest", () => {
|
|
9
|
+
const pkgPath = path_1.default.resolve(__dirname, "../../package.json");
|
|
10
|
+
const pkg = JSON.parse(fs_1.default.readFileSync(pkgPath, "utf8"));
|
|
11
|
+
it("lists typescript as a runtime dependency (required by TS analyzer)", () => {
|
|
12
|
+
expect(pkg.dependencies?.typescript).toBeDefined();
|
|
13
|
+
expect(pkg.devDependencies?.typescript).toBeUndefined();
|
|
14
|
+
});
|
|
15
|
+
it("includes patterns/ in published files (runtime YAML configs)", () => {
|
|
16
|
+
expect(pkg.files).toContain("patterns");
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const build_preview_url_1 = require("../../../src/upload/build-preview-url");
|
|
4
|
+
describe("buildImportPreviewUrl", () => {
|
|
5
|
+
const original = process.env.DATAPARADE_APP_URL;
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
if (original === undefined) {
|
|
8
|
+
delete process.env.DATAPARADE_APP_URL;
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
process.env.DATAPARADE_APP_URL = original;
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
it("builds dashboard deep link with importDraft query param", () => {
|
|
15
|
+
process.env.DATAPARADE_APP_URL = "http://localhost:3001";
|
|
16
|
+
const url = (0, build_preview_url_1.buildImportPreviewUrl)("draft-abc");
|
|
17
|
+
expect(url).toBe("http://localhost:3001/dashboard?importDraft=draft-abc");
|
|
18
|
+
});
|
|
19
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dataparade/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "dataPARADE CLI — scan codebases for privacy and security data flows",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -58,9 +58,10 @@
|
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@sentry/node": "^10.38.0",
|
|
61
|
+
"commander": "^12.1.0",
|
|
61
62
|
"dotenv": "^16.4.7",
|
|
62
63
|
"langsmith": "^0.3.14",
|
|
63
|
-
"
|
|
64
|
+
"typescript": "^5.7.3",
|
|
64
65
|
"yaml": "^2.8.2",
|
|
65
66
|
"zod": "^4.3.5"
|
|
66
67
|
},
|
|
@@ -72,11 +73,11 @@
|
|
|
72
73
|
"globals": "^15.14.0",
|
|
73
74
|
"jest": "^29.7.0",
|
|
74
75
|
"ts-jest": "^29.2.5",
|
|
75
|
-
"typescript": "^5.7.3",
|
|
76
76
|
"typescript-eslint": "^8.20.0"
|
|
77
77
|
},
|
|
78
78
|
"files": [
|
|
79
79
|
"dist",
|
|
80
|
+
"patterns",
|
|
80
81
|
"LICENSE",
|
|
81
82
|
"README.md",
|
|
82
83
|
"package.json"
|