@signstack/cli 0.1.1
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 +458 -0
- package/bin/run.js +12 -0
- package/dist/apps/signstack-cli/schemas/asset.schema.json +220 -0
- package/dist/apps/signstack-cli/schemas/blueprint.schema.json +485 -0
- package/dist/apps/signstack-cli/schemas/jsonata-function.schema.json +185 -0
- package/dist/apps/signstack-cli/schemas/schema.schema.json +97 -0
- package/dist/apps/signstack-cli/schemas/template.schema.json +295 -0
- package/dist/apps/signstack-cli/src/commands/auth/login.d.ts +25 -0
- package/dist/apps/signstack-cli/src/commands/auth/login.js +229 -0
- package/dist/apps/signstack-cli/src/commands/auth/login.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/auth/logout.d.ts +10 -0
- package/dist/apps/signstack-cli/src/commands/auth/logout.js +59 -0
- package/dist/apps/signstack-cli/src/commands/auth/logout.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/auth/whoami.d.ts +9 -0
- package/dist/apps/signstack-cli/src/commands/auth/whoami.js +85 -0
- package/dist/apps/signstack-cli/src/commands/auth/whoami.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/generate.d.ts +51 -0
- package/dist/apps/signstack-cli/src/commands/generate.js +479 -0
- package/dist/apps/signstack-cli/src/commands/generate.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/preview.d.ts +24 -0
- package/dist/apps/signstack-cli/src/commands/preview.js +162 -0
- package/dist/apps/signstack-cli/src/commands/preview.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/pull.d.ts +28 -0
- package/dist/apps/signstack-cli/src/commands/pull.js +244 -0
- package/dist/apps/signstack-cli/src/commands/pull.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/push.d.ts +46 -0
- package/dist/apps/signstack-cli/src/commands/push.js +460 -0
- package/dist/apps/signstack-cli/src/commands/push.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/run.d.ts +22 -0
- package/dist/apps/signstack-cli/src/commands/run.js +126 -0
- package/dist/apps/signstack-cli/src/commands/run.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/test.d.ts +6 -0
- package/dist/apps/signstack-cli/src/commands/test.js +25 -0
- package/dist/apps/signstack-cli/src/commands/test.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/validate.d.ts +59 -0
- package/dist/apps/signstack-cli/src/commands/validate.js +558 -0
- package/dist/apps/signstack-cli/src/commands/validate.js.map +1 -0
- package/dist/apps/signstack-cli/src/index.d.ts +1 -0
- package/dist/apps/signstack-cli/src/index.js +2 -0
- package/dist/apps/signstack-cli/src/index.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/api-client.d.ts +77 -0
- package/dist/apps/signstack-cli/src/lib/api-client.js +269 -0
- package/dist/apps/signstack-cli/src/lib/api-client.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/base-command.d.ts +38 -0
- package/dist/apps/signstack-cli/src/lib/base-command.js +135 -0
- package/dist/apps/signstack-cli/src/lib/base-command.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/config.d.ts +47 -0
- package/dist/apps/signstack-cli/src/lib/config.js +106 -0
- package/dist/apps/signstack-cli/src/lib/config.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/entity-data-resolver.d.ts +31 -0
- package/dist/apps/signstack-cli/src/lib/entity-data-resolver.js +107 -0
- package/dist/apps/signstack-cli/src/lib/entity-data-resolver.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/local-resource-loader.d.ts +72 -0
- package/dist/apps/signstack-cli/src/lib/local-resource-loader.js +238 -0
- package/dist/apps/signstack-cli/src/lib/local-resource-loader.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/path-utils.d.ts +4 -0
- package/dist/apps/signstack-cli/src/lib/path-utils.js +7 -0
- package/dist/apps/signstack-cli/src/lib/path-utils.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/payload-builder.d.ts +127 -0
- package/dist/apps/signstack-cli/src/lib/payload-builder.js +545 -0
- package/dist/apps/signstack-cli/src/lib/payload-builder.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/preview-handler.d.ts +95 -0
- package/dist/apps/signstack-cli/src/lib/preview-handler.js +611 -0
- package/dist/apps/signstack-cli/src/lib/preview-handler.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/preview-output-formatter.d.ts +63 -0
- package/dist/apps/signstack-cli/src/lib/preview-output-formatter.js +198 -0
- package/dist/apps/signstack-cli/src/lib/preview-output-formatter.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/public-api-client.d.ts +13 -0
- package/dist/apps/signstack-cli/src/lib/public-api-client.js +39 -0
- package/dist/apps/signstack-cli/src/lib/public-api-client.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/resource-puller.d.ts +131 -0
- package/dist/apps/signstack-cli/src/lib/resource-puller.js +800 -0
- package/dist/apps/signstack-cli/src/lib/resource-puller.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/resource-pusher.d.ts +87 -0
- package/dist/apps/signstack-cli/src/lib/resource-pusher.js +361 -0
- package/dist/apps/signstack-cli/src/lib/resource-pusher.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/resource-scanner.d.ts +29 -0
- package/dist/apps/signstack-cli/src/lib/resource-scanner.js +101 -0
- package/dist/apps/signstack-cli/src/lib/resource-scanner.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/resource-validator.d.ts +44 -0
- package/dist/apps/signstack-cli/src/lib/resource-validator.js +158 -0
- package/dist/apps/signstack-cli/src/lib/resource-validator.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/run-handler.d.ts +47 -0
- package/dist/apps/signstack-cli/src/lib/run-handler.js +266 -0
- package/dist/apps/signstack-cli/src/lib/run-handler.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/safe-path.d.ts +28 -0
- package/dist/apps/signstack-cli/src/lib/safe-path.js +44 -0
- package/dist/apps/signstack-cli/src/lib/safe-path.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/scenario-file.d.ts +35 -0
- package/dist/apps/signstack-cli/src/lib/scenario-file.js +80 -0
- package/dist/apps/signstack-cli/src/lib/scenario-file.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/schema-validator.d.ts +8 -0
- package/dist/apps/signstack-cli/src/lib/schema-validator.js +39 -0
- package/dist/apps/signstack-cli/src/lib/schema-validator.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/url-validator.d.ts +17 -0
- package/dist/apps/signstack-cli/src/lib/url-validator.js +61 -0
- package/dist/apps/signstack-cli/src/lib/url-validator.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/yaml-document-parser.d.ts +25 -0
- package/dist/apps/signstack-cli/src/lib/yaml-document-parser.js +133 -0
- package/dist/apps/signstack-cli/src/lib/yaml-document-parser.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/yaml-transforms.d.ts +3 -0
- package/dist/apps/signstack-cli/src/lib/yaml-transforms.js +32 -0
- package/dist/apps/signstack-cli/src/lib/yaml-transforms.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/yaml-writer.d.ts +47 -0
- package/dist/apps/signstack-cli/src/lib/yaml-writer.js +160 -0
- package/dist/apps/signstack-cli/src/lib/yaml-writer.js.map +1 -0
- package/dist/apps/signstack-cli/src/types/auth.types.d.ts +48 -0
- package/dist/apps/signstack-cli/src/types/auth.types.js +31 -0
- package/dist/apps/signstack-cli/src/types/auth.types.js.map +1 -0
- package/dist/apps/signstack-cli/src/types/schema.types.d.ts +14 -0
- package/dist/apps/signstack-cli/src/types/schema.types.js +16 -0
- package/dist/apps/signstack-cli/src/types/schema.types.js.map +1 -0
- package/dist/apps/signstack-cli/src/types/yaml.types.d.ts +144 -0
- package/dist/apps/signstack-cli/src/types/yaml.types.js +2 -0
- package/dist/apps/signstack-cli/src/types/yaml.types.js.map +1 -0
- package/dist/libs/common/base/src/index.d.ts +14 -0
- package/dist/libs/common/base/src/index.js +44 -0
- package/dist/libs/common/base/src/index.js.map +1 -0
- package/dist/libs/common/base/src/lib/address.util.d.ts +12 -0
- package/dist/libs/common/base/src/lib/address.util.js +55 -0
- package/dist/libs/common/base/src/lib/address.util.js.map +1 -0
- package/dist/libs/common/base/src/lib/country-code-data.d.ts +5 -0
- package/dist/libs/common/base/src/lib/country-code-data.js +1256 -0
- package/dist/libs/common/base/src/lib/country-code-data.js.map +1 -0
- package/dist/libs/common/base/src/lib/date.util.d.ts +13 -0
- package/dist/libs/common/base/src/lib/date.util.js +135 -0
- package/dist/libs/common/base/src/lib/date.util.js.map +1 -0
- package/dist/libs/common/base/src/lib/headers.d.ts +1 -0
- package/dist/libs/common/base/src/lib/headers.js +5 -0
- package/dist/libs/common/base/src/lib/headers.js.map +1 -0
- package/dist/libs/common/base/src/lib/jsonata.service.d.ts +32 -0
- package/dist/libs/common/base/src/lib/jsonata.service.js +207 -0
- package/dist/libs/common/base/src/lib/jsonata.service.js.map +1 -0
- package/dist/libs/common/base/src/lib/key-validation.constants.d.ts +37 -0
- package/dist/libs/common/base/src/lib/key-validation.constants.js +144 -0
- package/dist/libs/common/base/src/lib/key-validation.constants.js.map +1 -0
- package/dist/libs/common/base/src/lib/phone-util.d.ts +16 -0
- package/dist/libs/common/base/src/lib/phone-util.js +61 -0
- package/dist/libs/common/base/src/lib/phone-util.js.map +1 -0
- package/dist/libs/common/base/src/lib/schema-validation.util.d.ts +24 -0
- package/dist/libs/common/base/src/lib/schema-validation.util.js +155 -0
- package/dist/libs/common/base/src/lib/schema-validation.util.js.map +1 -0
- package/dist/libs/common/base/src/lib/string-builder.d.ts +48 -0
- package/dist/libs/common/base/src/lib/string-builder.js +90 -0
- package/dist/libs/common/base/src/lib/string-builder.js.map +1 -0
- package/dist/libs/common/base/src/lib/util.d.ts +20 -0
- package/dist/libs/common/base/src/lib/util.js +110 -0
- package/dist/libs/common/base/src/lib/util.js.map +1 -0
- package/dist/libs/signstack/base/schemas/asset.schema.json +220 -0
- package/dist/libs/signstack/base/schemas/blueprint.schema.json +485 -0
- package/dist/libs/signstack/base/schemas/jsonata-function.schema.json +185 -0
- package/dist/libs/signstack/base/schemas/schema.schema.json +97 -0
- package/dist/libs/signstack/base/schemas/template.schema.json +295 -0
- package/dist/libs/signstack/base/src/index.d.ts +28 -0
- package/dist/libs/signstack/base/src/index.js +32 -0
- package/dist/libs/signstack/base/src/index.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/constants.d.ts +123 -0
- package/dist/libs/signstack/base/src/lib/constants.js +131 -0
- package/dist/libs/signstack/base/src/lib/constants.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/hash.util.d.ts +58 -0
- package/dist/libs/signstack/base/src/lib/hash.util.js +90 -0
- package/dist/libs/signstack/base/src/lib/hash.util.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/is-schema-renderable.util.d.ts +29 -0
- package/dist/libs/signstack/base/src/lib/is-schema-renderable.util.js +93 -0
- package/dist/libs/signstack/base/src/lib/is-schema-renderable.util.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/ai-chat.d.ts +41 -0
- package/dist/libs/signstack/base/src/lib/models/ai-chat.js +3 -0
- package/dist/libs/signstack/base/src/lib/models/ai-chat.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/api-key.d.ts +54 -0
- package/dist/libs/signstack/base/src/lib/models/api-key.js +18 -0
- package/dist/libs/signstack/base/src/lib/models/api-key.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/asset.d.ts +101 -0
- package/dist/libs/signstack/base/src/lib/models/asset.js +11 -0
- package/dist/libs/signstack/base/src/lib/models/asset.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/auth.d.ts +142 -0
- package/dist/libs/signstack/base/src/lib/models/auth.js +35 -0
- package/dist/libs/signstack/base/src/lib/models/auth.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/base.d.ts +134 -0
- package/dist/libs/signstack/base/src/lib/models/base.js +71 -0
- package/dist/libs/signstack/base/src/lib/models/base.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/blueprint.d.ts +311 -0
- package/dist/libs/signstack/base/src/lib/models/blueprint.js +9 -0
- package/dist/libs/signstack/base/src/lib/models/blueprint.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/file.d.ts +75 -0
- package/dist/libs/signstack/base/src/lib/models/file.js +9 -0
- package/dist/libs/signstack/base/src/lib/models/file.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/jsonata-function.d.ts +111 -0
- package/dist/libs/signstack/base/src/lib/models/jsonata-function.js +19 -0
- package/dist/libs/signstack/base/src/lib/models/jsonata-function.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/marketplace-listing.d.ts +132 -0
- package/dist/libs/signstack/base/src/lib/models/marketplace-listing.js +22 -0
- package/dist/libs/signstack/base/src/lib/models/marketplace-listing.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/membership.d.ts +127 -0
- package/dist/libs/signstack/base/src/lib/models/membership.js +22 -0
- package/dist/libs/signstack/base/src/lib/models/membership.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/namespace.d.ts +87 -0
- package/dist/libs/signstack/base/src/lib/models/namespace.js +57 -0
- package/dist/libs/signstack/base/src/lib/models/namespace.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/organization.d.ts +79 -0
- package/dist/libs/signstack/base/src/lib/models/organization.js +41 -0
- package/dist/libs/signstack/base/src/lib/models/organization.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/render-job.d.ts +88 -0
- package/dist/libs/signstack/base/src/lib/models/render-job.js +3 -0
- package/dist/libs/signstack/base/src/lib/models/render-job.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/resource-edge.d.ts +60 -0
- package/dist/libs/signstack/base/src/lib/models/resource-edge.js +202 -0
- package/dist/libs/signstack/base/src/lib/models/resource-edge.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/scenario.d.ts +138 -0
- package/dist/libs/signstack/base/src/lib/models/scenario.js +14 -0
- package/dist/libs/signstack/base/src/lib/models/scenario.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/schema.d.ts +131 -0
- package/dist/libs/signstack/base/src/lib/models/schema.js +44 -0
- package/dist/libs/signstack/base/src/lib/models/schema.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/shareable-link.d.ts +215 -0
- package/dist/libs/signstack/base/src/lib/models/shareable-link.js +27 -0
- package/dist/libs/signstack/base/src/lib/models/shareable-link.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/subscription.d.ts +279 -0
- package/dist/libs/signstack/base/src/lib/models/subscription.js +105 -0
- package/dist/libs/signstack/base/src/lib/models/subscription.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/template.d.ts +248 -0
- package/dist/libs/signstack/base/src/lib/models/template.js +32 -0
- package/dist/libs/signstack/base/src/lib/models/template.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/user.d.ts +30 -0
- package/dist/libs/signstack/base/src/lib/models/user.js +3 -0
- package/dist/libs/signstack/base/src/lib/models/user.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/webhook.d.ts +223 -0
- package/dist/libs/signstack/base/src/lib/models/webhook.js +62 -0
- package/dist/libs/signstack/base/src/lib/models/webhook.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/workflow.d.ts +917 -0
- package/dist/libs/signstack/base/src/lib/models/workflow.js +152 -0
- package/dist/libs/signstack/base/src/lib/models/workflow.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/util.d.ts +92 -0
- package/dist/libs/signstack/base/src/lib/util.js +406 -0
- package/dist/libs/signstack/base/src/lib/util.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/dependency-graph.d.ts +94 -0
- package/dist/libs/signstack/base/src/lib/validation/dependency-graph.js +446 -0
- package/dist/libs/signstack/base/src/lib/validation/dependency-graph.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/graph.types.d.ts +57 -0
- package/dist/libs/signstack/base/src/lib/validation/graph.types.js +8 -0
- package/dist/libs/signstack/base/src/lib/validation/graph.types.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/index.d.ts +9 -0
- package/dist/libs/signstack/base/src/lib/validation/index.js +23 -0
- package/dist/libs/signstack/base/src/lib/validation/index.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/resource-schemas.d.ts +3 -0
- package/dist/libs/signstack/base/src/lib/validation/resource-schemas.js +27 -0
- package/dist/libs/signstack/base/src/lib/validation/resource-schemas.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/schema-validation.types.d.ts +57 -0
- package/dist/libs/signstack/base/src/lib/validation/schema-validation.types.js +57 -0
- package/dist/libs/signstack/base/src/lib/validation/schema-validation.types.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/schema-validator.d.ts +38 -0
- package/dist/libs/signstack/base/src/lib/validation/schema-validator.js +146 -0
- package/dist/libs/signstack/base/src/lib/validation/schema-validator.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-dependencies.d.ts +22 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-dependencies.js +69 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-dependencies.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-resource-tree.d.ts +37 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-resource-tree.js +250 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-resource-tree.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-template-inputs.d.ts +24 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-template-inputs.js +98 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-template-inputs.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/yaml-document-utils.d.ts +12 -0
- package/dist/libs/signstack/base/src/lib/validation/yaml-document-utils.js +50 -0
- package/dist/libs/signstack/base/src/lib/validation/yaml-document-utils.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/yaml-spec-converter.d.ts +101 -0
- package/dist/libs/signstack/base/src/lib/yaml-spec-converter.js +998 -0
- package/dist/libs/signstack/base/src/lib/yaml-spec-converter.js.map +1 -0
- package/oclif.manifest.json +822 -0
- package/package.json +101 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { DependencyGraph, type ParsedDocument, type ResourceId } from '@signstack/base';
|
|
2
|
+
import { type ValidationSummary } from '../types/schema.types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extended validation summary with graph stats
|
|
5
|
+
*/
|
|
6
|
+
export interface ExtendedValidationSummary extends ValidationSummary {
|
|
7
|
+
graphStats?: {
|
|
8
|
+
totalNodes: number;
|
|
9
|
+
totalEdges: number;
|
|
10
|
+
leafNodes: number;
|
|
11
|
+
rootNodes: number;
|
|
12
|
+
};
|
|
13
|
+
hasCycles: boolean;
|
|
14
|
+
cycles?: ResourceId[][];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* ResourceValidator - Shared validation logic for YAML resources
|
|
18
|
+
*
|
|
19
|
+
* Used by both the validate and preview commands
|
|
20
|
+
*/
|
|
21
|
+
export declare class ResourceValidator {
|
|
22
|
+
private validator;
|
|
23
|
+
/**
|
|
24
|
+
* Validate all YAML files in a folder
|
|
25
|
+
* Returns parsed documents if valid, throws if validation fails
|
|
26
|
+
*/
|
|
27
|
+
validateFolder(folderPath: string): Promise<{
|
|
28
|
+
documents: ParsedDocument[];
|
|
29
|
+
graph: DependencyGraph;
|
|
30
|
+
summary: ExtendedValidationSummary;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* Validate that all dependencies exist in the graph
|
|
34
|
+
*/
|
|
35
|
+
private validateDependencies;
|
|
36
|
+
/**
|
|
37
|
+
* Validate that spec.file references exist
|
|
38
|
+
*/
|
|
39
|
+
private validateFileReferences;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get the shared ResourceValidator instance
|
|
43
|
+
*/
|
|
44
|
+
export declare function getResourceValidator(): ResourceValidator;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { DependencyGraph } from '@signstack/base';
|
|
4
|
+
import { getSchemaValidator } from './schema-validator.js';
|
|
5
|
+
import { discoverYamlFiles, parseAllYamlFiles, } from './yaml-document-parser.js';
|
|
6
|
+
import { SchemaKind, ValidationErrorKeyword, } from '../types/schema.types.js';
|
|
7
|
+
/**
|
|
8
|
+
* ResourceValidator - Shared validation logic for YAML resources
|
|
9
|
+
*
|
|
10
|
+
* Used by both the validate and preview commands
|
|
11
|
+
*/
|
|
12
|
+
export class ResourceValidator {
|
|
13
|
+
validator = getSchemaValidator();
|
|
14
|
+
/**
|
|
15
|
+
* Validate all YAML files in a folder
|
|
16
|
+
* Returns parsed documents if valid, throws if validation fails
|
|
17
|
+
*/
|
|
18
|
+
async validateFolder(folderPath) {
|
|
19
|
+
// Discover all YAML files
|
|
20
|
+
const filePaths = await discoverYamlFiles(folderPath);
|
|
21
|
+
if (filePaths.length === 0) {
|
|
22
|
+
throw new Error(`No YAML files found in: ${folderPath}`);
|
|
23
|
+
}
|
|
24
|
+
// Parse all documents
|
|
25
|
+
const { documents, parseErrors } = parseAllYamlFiles(filePaths);
|
|
26
|
+
if (documents.length === 0 && parseErrors.length > 0) {
|
|
27
|
+
return {
|
|
28
|
+
documents: [],
|
|
29
|
+
graph: new DependencyGraph(),
|
|
30
|
+
summary: {
|
|
31
|
+
total: parseErrors.length,
|
|
32
|
+
passed: 0,
|
|
33
|
+
failed: parseErrors.length,
|
|
34
|
+
results: parseErrors,
|
|
35
|
+
hasCycles: false,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// Build dependency graph
|
|
40
|
+
const graph = DependencyGraph.fromDocuments(documents);
|
|
41
|
+
// Determine validation order via topological sort
|
|
42
|
+
const sortResult = graph.topologicalSort();
|
|
43
|
+
const validationOrder = sortResult.order;
|
|
44
|
+
// Add any nodes not in sort result (cycle members)
|
|
45
|
+
const orderedSet = new Set(validationOrder);
|
|
46
|
+
for (const id of graph.nodes.keys()) {
|
|
47
|
+
if (!orderedSet.has(id)) {
|
|
48
|
+
validationOrder.push(id);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Run validations
|
|
52
|
+
const results = [...parseErrors];
|
|
53
|
+
// Schema validation in topological order
|
|
54
|
+
for (const resourceId of validationOrder) {
|
|
55
|
+
const doc = graph.nodes.get(resourceId);
|
|
56
|
+
if (!doc)
|
|
57
|
+
continue;
|
|
58
|
+
const result = this.validator.validate(doc.content, doc.filePath, doc.kind, doc.documentIndex);
|
|
59
|
+
results.push(result);
|
|
60
|
+
}
|
|
61
|
+
// Dependency validation
|
|
62
|
+
const depErrors = this.validateDependencies(graph);
|
|
63
|
+
results.push(...depErrors);
|
|
64
|
+
// File reference validation
|
|
65
|
+
const fileRefErrors = this.validateFileReferences(graph);
|
|
66
|
+
results.push(...fileRefErrors);
|
|
67
|
+
// Build summary
|
|
68
|
+
const summary = {
|
|
69
|
+
total: results.length,
|
|
70
|
+
passed: results.filter((r) => r.valid).length,
|
|
71
|
+
failed: results.filter((r) => !r.valid).length,
|
|
72
|
+
results,
|
|
73
|
+
graphStats: graph.getStats(),
|
|
74
|
+
hasCycles: !sortResult.isAcyclic,
|
|
75
|
+
cycles: sortResult.cycles,
|
|
76
|
+
};
|
|
77
|
+
return { documents, graph, summary };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Validate that all dependencies exist in the graph
|
|
81
|
+
*/
|
|
82
|
+
validateDependencies(graph) {
|
|
83
|
+
const errors = [];
|
|
84
|
+
const missing = graph.getMissingDependencies();
|
|
85
|
+
for (const [sourceId, missingDeps] of missing) {
|
|
86
|
+
const sourceDoc = graph.nodes.get(sourceId);
|
|
87
|
+
if (!sourceDoc)
|
|
88
|
+
continue;
|
|
89
|
+
for (const missingId of missingDeps) {
|
|
90
|
+
const { kind, key, version } = DependencyGraph.parseId(missingId);
|
|
91
|
+
const ref = sourceDoc.references.find((r) => r.key === key && r.version === version && r.targetKind === kind);
|
|
92
|
+
errors.push({
|
|
93
|
+
valid: false,
|
|
94
|
+
errors: [
|
|
95
|
+
{
|
|
96
|
+
path: ref?.sourcePath ?? '/',
|
|
97
|
+
message: `Referenced ${kind} '${key}@${version}' not found in project`,
|
|
98
|
+
keyword: ValidationErrorKeyword.DependencyMissing,
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
schemaKind: sourceDoc.kind,
|
|
102
|
+
filePath: sourceDoc.filePath,
|
|
103
|
+
documentIndex: sourceDoc.documentIndex,
|
|
104
|
+
resourceKey: sourceDoc.key,
|
|
105
|
+
resourceVersion: sourceDoc.version,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return errors;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Validate that spec.file references exist
|
|
113
|
+
*/
|
|
114
|
+
validateFileReferences(graph) {
|
|
115
|
+
const errors = [];
|
|
116
|
+
for (const doc of graph.nodes.values()) {
|
|
117
|
+
if (doc.kind !== SchemaKind.Schema && doc.kind !== SchemaKind.Asset) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const spec = doc.content['spec'];
|
|
121
|
+
const filePath = spec?.['file'];
|
|
122
|
+
if (!filePath)
|
|
123
|
+
continue;
|
|
124
|
+
const baseDir = dirname(doc.filePath);
|
|
125
|
+
const resolvedPath = resolve(baseDir, filePath);
|
|
126
|
+
if (!existsSync(resolvedPath)) {
|
|
127
|
+
errors.push({
|
|
128
|
+
valid: false,
|
|
129
|
+
errors: [
|
|
130
|
+
{
|
|
131
|
+
path: 'spec.file',
|
|
132
|
+
message: `Referenced file '${filePath}' not found (resolved: ${resolvedPath})`,
|
|
133
|
+
keyword: ValidationErrorKeyword.FileReferenceMissing,
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
schemaKind: doc.kind,
|
|
137
|
+
filePath: doc.filePath,
|
|
138
|
+
documentIndex: doc.documentIndex,
|
|
139
|
+
resourceKey: doc.key,
|
|
140
|
+
resourceVersion: doc.version,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return errors;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** Singleton instance */
|
|
148
|
+
let validatorInstance = null;
|
|
149
|
+
/**
|
|
150
|
+
* Get the shared ResourceValidator instance
|
|
151
|
+
*/
|
|
152
|
+
export function getResourceValidator() {
|
|
153
|
+
if (!validatorInstance) {
|
|
154
|
+
validatorInstance = new ResourceValidator();
|
|
155
|
+
}
|
|
156
|
+
return validatorInstance;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=resource-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-validator.js","sourceRoot":"","sources":["../../../../../src/lib/resource-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { CreateWorkflowMode } from '@signstack/base';
|
|
2
|
+
import { ApiClient } from './api-client.js';
|
|
3
|
+
export interface RunConfig {
|
|
4
|
+
orgId: string;
|
|
5
|
+
namespaceKey: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Handler for the `run` command — kicks off a workflow from a blueprint.
|
|
9
|
+
*
|
|
10
|
+
* Supports three modes:
|
|
11
|
+
* - Remote: Blueprint is resolved entirely from the SignStack API (key + optional version)
|
|
12
|
+
* - Local (--path --local): All resources from local YAML files
|
|
13
|
+
* - Hybrid (--path): Local files + fetch missing deps from API
|
|
14
|
+
*/
|
|
15
|
+
export declare class RunHandler {
|
|
16
|
+
private readonly apiClient;
|
|
17
|
+
private readonly config;
|
|
18
|
+
private readonly log;
|
|
19
|
+
private readonly error;
|
|
20
|
+
private readonly payloadBuilder;
|
|
21
|
+
private readonly localLoader;
|
|
22
|
+
constructor(apiClient: ApiClient, config: RunConfig, log: (message: string) => void, error: (message: string, options?: {
|
|
23
|
+
exit?: number;
|
|
24
|
+
}) => never);
|
|
25
|
+
/**
|
|
26
|
+
* Run a workflow from a deployed blueprint.
|
|
27
|
+
* The API resolves all dependencies from blueprintKey/version.
|
|
28
|
+
*/
|
|
29
|
+
runRemote(blueprintKey: string, version: string | undefined, scenarioKey: string | undefined, mode: CreateWorkflowMode | undefined, jsonOutput: boolean): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Run a workflow from local YAML files.
|
|
32
|
+
* @param inlineOnly - When true (--local), fail on missing deps. When false (hybrid), API resolves missing.
|
|
33
|
+
*/
|
|
34
|
+
runLocal(pathArg: string, blueprintRef: string, scenarioKey: string | undefined, mode: CreateWorkflowMode | undefined, jsonOutput: boolean, inlineOnly?: boolean): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Load blueprint metadata from SignStack API.
|
|
37
|
+
*/
|
|
38
|
+
private loadBlueprintFromApi;
|
|
39
|
+
/**
|
|
40
|
+
* Call POST /v1/orgs/:orgId/workflows to create and start a workflow.
|
|
41
|
+
*/
|
|
42
|
+
private createWorkflow;
|
|
43
|
+
/**
|
|
44
|
+
* Print the run results to the console.
|
|
45
|
+
*/
|
|
46
|
+
private printRunResults;
|
|
47
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import { resolveEntityData, } from './entity-data-resolver.js';
|
|
4
|
+
import { LocalResourceLoader } from './local-resource-loader.js';
|
|
5
|
+
import { PayloadBuilder } from './payload-builder.js';
|
|
6
|
+
import { isScenarioFilePath, loadDefaultScenario, loadScenario, loadScenarioFromPath, } from './scenario-file.js';
|
|
7
|
+
import { SchemaKind } from '../types/schema.types.js';
|
|
8
|
+
const DEFAULT_WEB_APP_URL = 'https://signstack-test.web.app';
|
|
9
|
+
/**
|
|
10
|
+
* Handler for the `run` command — kicks off a workflow from a blueprint.
|
|
11
|
+
*
|
|
12
|
+
* Supports three modes:
|
|
13
|
+
* - Remote: Blueprint is resolved entirely from the SignStack API (key + optional version)
|
|
14
|
+
* - Local (--path --local): All resources from local YAML files
|
|
15
|
+
* - Hybrid (--path): Local files + fetch missing deps from API
|
|
16
|
+
*/
|
|
17
|
+
export class RunHandler {
|
|
18
|
+
apiClient;
|
|
19
|
+
config;
|
|
20
|
+
log;
|
|
21
|
+
error;
|
|
22
|
+
payloadBuilder;
|
|
23
|
+
localLoader;
|
|
24
|
+
constructor(apiClient, config, log, error) {
|
|
25
|
+
this.apiClient = apiClient;
|
|
26
|
+
this.config = config;
|
|
27
|
+
this.log = log;
|
|
28
|
+
this.error = error;
|
|
29
|
+
this.payloadBuilder = new PayloadBuilder();
|
|
30
|
+
this.localLoader = new LocalResourceLoader(apiClient, config.orgId, this.payloadBuilder, log, error);
|
|
31
|
+
}
|
|
32
|
+
// ── Remote mode ──────────────────────────────────────────────────
|
|
33
|
+
/**
|
|
34
|
+
* Run a workflow from a deployed blueprint.
|
|
35
|
+
* The API resolves all dependencies from blueprintKey/version.
|
|
36
|
+
*/
|
|
37
|
+
async runRemote(blueprintKey, version, scenarioKey, mode, jsonOutput) {
|
|
38
|
+
// Step 1: Load blueprint from API (need inputs for entity data generation)
|
|
39
|
+
const blueprintData = await this.loadBlueprintFromApi(blueprintKey, version, jsonOutput);
|
|
40
|
+
// Step 2: Resolve entity data (from scenario or generate via API)
|
|
41
|
+
const entityData = await resolveEntityData({
|
|
42
|
+
entitySlots: blueprintData.inputs,
|
|
43
|
+
scenarioKey,
|
|
44
|
+
jsonOutput,
|
|
45
|
+
fetchScenario: (key) => this.apiClient.get(`/v1/orgs/${this.config.orgId}/namespaces/${this.config.namespaceKey}/scenarios/${encodeURIComponent(key)}`),
|
|
46
|
+
generateFromApi: (schemaKeys) => this.apiClient.post(`/v1/orgs/${this.config.orgId}/namespaces/${this.config.namespaceKey}/schemas/examples`, { schemaKeys }),
|
|
47
|
+
log: this.log,
|
|
48
|
+
});
|
|
49
|
+
// Step 3: Create workflow via API
|
|
50
|
+
const data = entityData.entities.length > 0
|
|
51
|
+
? Object.fromEntries(entityData.entities.map((e) => [e.key, e.data]))
|
|
52
|
+
: undefined;
|
|
53
|
+
const result = await this.createWorkflow({
|
|
54
|
+
blueprintKey: blueprintData.key,
|
|
55
|
+
blueprintVersion: blueprintData.version,
|
|
56
|
+
...(data ? { data } : {}),
|
|
57
|
+
options: mode ? { mode } : undefined,
|
|
58
|
+
}, jsonOutput);
|
|
59
|
+
// Step 4: Output results
|
|
60
|
+
this.printRunResults(result, jsonOutput, entityData, {
|
|
61
|
+
key: blueprintData.key,
|
|
62
|
+
version: blueprintData.version,
|
|
63
|
+
name: blueprintData.name,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// ── Local / Hybrid mode ──────────────────────────────────────────
|
|
67
|
+
/**
|
|
68
|
+
* Run a workflow from local YAML files.
|
|
69
|
+
* @param inlineOnly - When true (--local), fail on missing deps. When false (hybrid), API resolves missing.
|
|
70
|
+
*/
|
|
71
|
+
async runLocal(pathArg, blueprintRef, scenarioKey, mode, jsonOutput, inlineOnly = false) {
|
|
72
|
+
// Step 1-4: Validate, find blueprint, collect deps, upload assets
|
|
73
|
+
const { missingDeps, targetDoc: blueprintDoc, relevantDocs, fileIdMap, } = await this.localLoader.prepareLocalResources({
|
|
74
|
+
pathArg,
|
|
75
|
+
resourceRef: blueprintRef,
|
|
76
|
+
resourceKind: SchemaKind.Blueprint,
|
|
77
|
+
resourceType: 'blueprint',
|
|
78
|
+
jsonOutput,
|
|
79
|
+
inlineOnly,
|
|
80
|
+
});
|
|
81
|
+
// Step 5: Build blueprint resource (for entity slots)
|
|
82
|
+
const blueprint = this.payloadBuilder.buildBlueprintPayload(blueprintDoc);
|
|
83
|
+
// Step 6: Collect local resource docs by type
|
|
84
|
+
const templateDocs = relevantDocs.filter((d) => d.kind === SchemaKind.Template);
|
|
85
|
+
const assetDocs = relevantDocs.filter((d) => d.kind === SchemaKind.Asset);
|
|
86
|
+
const functionDocs = relevantDocs.filter((d) => d.kind === SchemaKind.JsonataFunction);
|
|
87
|
+
// Step 7: Log missing deps info (backend resolves them in hybrid mode)
|
|
88
|
+
if (missingDeps.size > 0 && !jsonOutput) {
|
|
89
|
+
const allMissing = new Set();
|
|
90
|
+
for (const deps of missingDeps.values()) {
|
|
91
|
+
for (const dep of deps)
|
|
92
|
+
allMissing.add(dep);
|
|
93
|
+
}
|
|
94
|
+
this.log(`\n${pc.dim(`${allMissing.size} missing local dependency(ies) will be resolved from deployed resources.`)}`);
|
|
95
|
+
}
|
|
96
|
+
// Step 8: Resolve entity data — load local scenario files or generate
|
|
97
|
+
const schemaDocs = relevantDocs
|
|
98
|
+
.filter((d) => d.kind === SchemaKind.Schema)
|
|
99
|
+
.map((d) => this.payloadBuilder.buildSchemaPayload(d));
|
|
100
|
+
const { resolve: resolvePath } = await import('node:path');
|
|
101
|
+
const contractDir = resolvePath(pathArg);
|
|
102
|
+
// Try loading scenario from local files first
|
|
103
|
+
let entityData;
|
|
104
|
+
if (scenarioKey && isScenarioFilePath(scenarioKey)) {
|
|
105
|
+
const scenarioEntities = loadScenarioFromPath(resolvePath(scenarioKey));
|
|
106
|
+
if (!jsonOutput)
|
|
107
|
+
this.log(`Loaded scenario from file: ${scenarioKey}`);
|
|
108
|
+
entityData = { entities: scenarioEntities, isAutoGenerated: false };
|
|
109
|
+
}
|
|
110
|
+
else if (scenarioKey) {
|
|
111
|
+
const scenarioEntities = loadScenario(contractDir, scenarioKey);
|
|
112
|
+
if (scenarioEntities) {
|
|
113
|
+
if (!jsonOutput)
|
|
114
|
+
this.log(`Using scenario: ${scenarioKey}`);
|
|
115
|
+
entityData = { entities: scenarioEntities, isAutoGenerated: false };
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
// Fall back to remote scenario resolution
|
|
119
|
+
entityData = await resolveEntityData({
|
|
120
|
+
entitySlots: blueprint.spec.inputs ?? [],
|
|
121
|
+
scenarioKey,
|
|
122
|
+
jsonOutput,
|
|
123
|
+
fetchScenario: (key) => this.apiClient.get(`/v1/orgs/${this.config.orgId}/namespaces/${this.config.namespaceKey}/scenarios/${encodeURIComponent(key)}`),
|
|
124
|
+
log: this.log,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// Try loading default scenario from scenarios/ folder first
|
|
130
|
+
const defaultScenario = loadDefaultScenario(contractDir);
|
|
131
|
+
if (defaultScenario) {
|
|
132
|
+
if (!jsonOutput)
|
|
133
|
+
this.log(`Using scenario: ${defaultScenario.key}`);
|
|
134
|
+
entityData = {
|
|
135
|
+
entities: defaultScenario.entities,
|
|
136
|
+
isAutoGenerated: false,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
entityData = await resolveEntityData({
|
|
141
|
+
entitySlots: blueprint.spec.inputs ?? [],
|
|
142
|
+
scenarioKey: undefined,
|
|
143
|
+
jsonOutput,
|
|
144
|
+
generateFromApi: (schemaKeys) => this.apiClient.post(`/v1/orgs/${this.config.orgId}/namespaces/${this.config.namespaceKey}/schemas/examples`, { schemaKeys }),
|
|
145
|
+
log: this.log,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Step 9: Build CreateWorkflowReq with inline resources
|
|
150
|
+
const entities = entityData.entities.length > 0
|
|
151
|
+
? entityData.entities.map((e) => ({
|
|
152
|
+
key: e.key,
|
|
153
|
+
data: e.data,
|
|
154
|
+
}))
|
|
155
|
+
: undefined;
|
|
156
|
+
const req = this.payloadBuilder.buildCreateWorkflowReq({
|
|
157
|
+
blueprintDoc,
|
|
158
|
+
templateDocs,
|
|
159
|
+
assetDocs,
|
|
160
|
+
functionDocs,
|
|
161
|
+
schemaDocs,
|
|
162
|
+
fileIdMap,
|
|
163
|
+
entities,
|
|
164
|
+
inlineOnly,
|
|
165
|
+
mode,
|
|
166
|
+
});
|
|
167
|
+
// Step 10: Create workflow via API
|
|
168
|
+
const result = await this.createWorkflow(req, jsonOutput);
|
|
169
|
+
// Step 11: Print results
|
|
170
|
+
const meta = blueprintDoc.content['metadata'];
|
|
171
|
+
this.printRunResults(result, jsonOutput, entityData, {
|
|
172
|
+
key: blueprintDoc.key,
|
|
173
|
+
version: blueprintDoc.version,
|
|
174
|
+
name: meta?.name ?? blueprintDoc.key,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// ── Private methods ───────────────────────────────────────────────
|
|
178
|
+
/**
|
|
179
|
+
* Load blueprint metadata from SignStack API.
|
|
180
|
+
*/
|
|
181
|
+
async loadBlueprintFromApi(blueprintKey, version, jsonOutput) {
|
|
182
|
+
const spinner = jsonOutput
|
|
183
|
+
? null
|
|
184
|
+
: ora({
|
|
185
|
+
text: 'Fetching blueprint from SignStack...',
|
|
186
|
+
color: 'cyan',
|
|
187
|
+
}).start();
|
|
188
|
+
try {
|
|
189
|
+
const baseUrl = `/v1/orgs/${this.config.orgId}/namespaces/${this.config.namespaceKey}/blueprints/${encodeURIComponent(blueprintKey)}`;
|
|
190
|
+
const url = version
|
|
191
|
+
? `${baseUrl}?version=${encodeURIComponent(version)}`
|
|
192
|
+
: baseUrl;
|
|
193
|
+
const blueprint = await this.apiClient.get(url);
|
|
194
|
+
spinner?.succeed(`Found blueprint: ${pc.cyan(blueprint.metadata.name)} (v${blueprint.metadata.version})`);
|
|
195
|
+
return {
|
|
196
|
+
key: blueprintKey,
|
|
197
|
+
version: blueprint.metadata.version,
|
|
198
|
+
name: blueprint.metadata.name || blueprintKey,
|
|
199
|
+
inputs: blueprint.spec.inputs || [],
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
spinner?.fail('Failed to fetch blueprint from SignStack');
|
|
204
|
+
throw error;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Call POST /v1/orgs/:orgId/workflows to create and start a workflow.
|
|
209
|
+
*/
|
|
210
|
+
async createWorkflow(req, jsonOutput) {
|
|
211
|
+
const spinner = jsonOutput
|
|
212
|
+
? null
|
|
213
|
+
: ora({
|
|
214
|
+
text: 'Creating workflow...',
|
|
215
|
+
color: 'cyan',
|
|
216
|
+
}).start();
|
|
217
|
+
try {
|
|
218
|
+
const result = await this.apiClient.post(`/v1/orgs/${this.config.orgId}/namespaces/${this.config.namespaceKey}/workflows`, req);
|
|
219
|
+
spinner?.succeed('Workflow created successfully');
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
spinner?.fail('Failed to create workflow');
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Print the run results to the console.
|
|
229
|
+
*/
|
|
230
|
+
printRunResults(result, jsonOutput, entityData, blueprint) {
|
|
231
|
+
const workflowUrl = `${DEFAULT_WEB_APP_URL}/workflows/${result.id}`;
|
|
232
|
+
if (jsonOutput) {
|
|
233
|
+
this.log(JSON.stringify({
|
|
234
|
+
blueprint: {
|
|
235
|
+
key: blueprint.key,
|
|
236
|
+
version: blueprint.version,
|
|
237
|
+
name: blueprint.name,
|
|
238
|
+
},
|
|
239
|
+
entityData: {
|
|
240
|
+
source: entityData.isAutoGenerated
|
|
241
|
+
? 'generated'
|
|
242
|
+
: entityData.entities.length > 0
|
|
243
|
+
? 'scenario'
|
|
244
|
+
: 'none',
|
|
245
|
+
},
|
|
246
|
+
workflowId: result.id,
|
|
247
|
+
status: result.status,
|
|
248
|
+
workflowUrl,
|
|
249
|
+
}, null, 2));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
this.log('');
|
|
253
|
+
this.log(pc.bold(pc.green('Workflow Created Successfully')));
|
|
254
|
+
this.log('');
|
|
255
|
+
this.log(` ${pc.dim('Blueprint:')} ${blueprint.name} (v${blueprint.version})`);
|
|
256
|
+
this.log(` ${pc.dim('Workflow ID:')} ${pc.cyan(result.id)}`);
|
|
257
|
+
this.log(` ${pc.dim('Status:')} ${result.status}`);
|
|
258
|
+
if (entityData.isAutoGenerated) {
|
|
259
|
+
this.log(pc.dim(' (with generated sample data)'));
|
|
260
|
+
}
|
|
261
|
+
this.log('');
|
|
262
|
+
this.log(` ${pc.dim('View status:')} ${pc.underline(workflowUrl)}`);
|
|
263
|
+
this.log('');
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=run-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-handler.js","sourceRoot":"","sources":["../../../../../src/lib/run-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Reason why a path resolution was rejected */
|
|
2
|
+
export type SafePathFailureReason = 'traversal' | 'not_found' | 'symlink_escape' | 'resolve_error';
|
|
3
|
+
export interface SafePathSuccess {
|
|
4
|
+
valid: true;
|
|
5
|
+
realPath: string;
|
|
6
|
+
}
|
|
7
|
+
export interface SafePathFailure {
|
|
8
|
+
valid: false;
|
|
9
|
+
reason: SafePathFailureReason;
|
|
10
|
+
/** Underlying error message when reason is 'resolve_error'. */
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
export type SafePathResult = SafePathSuccess | SafePathFailure;
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a relative file path and verify it stays within the base directory.
|
|
16
|
+
*
|
|
17
|
+
* Performs three security checks:
|
|
18
|
+
* 1. String-based containment — catches `../..` traversal before touching the filesystem.
|
|
19
|
+
* 2. File existence — the file must actually exist.
|
|
20
|
+
* 3. Symlink resolution — `realpathSync` resolves symlinks, then the real path is
|
|
21
|
+
* re-checked against the real base directory to prevent symlink-based traversal.
|
|
22
|
+
*
|
|
23
|
+
* @param baseDir Absolute path to the allowed base directory (should end with `sep`).
|
|
24
|
+
* @param relativePath The (potentially untrusted) relative path to resolve.
|
|
25
|
+
* @returns A discriminated union indicating success (with the real path) or
|
|
26
|
+
* failure (with a reason code).
|
|
27
|
+
*/
|
|
28
|
+
export declare function safeResolvePath(baseDir: string, relativePath: string): SafePathResult;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { resolve, sep } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a relative file path and verify it stays within the base directory.
|
|
5
|
+
*
|
|
6
|
+
* Performs three security checks:
|
|
7
|
+
* 1. String-based containment — catches `../..` traversal before touching the filesystem.
|
|
8
|
+
* 2. File existence — the file must actually exist.
|
|
9
|
+
* 3. Symlink resolution — `realpathSync` resolves symlinks, then the real path is
|
|
10
|
+
* re-checked against the real base directory to prevent symlink-based traversal.
|
|
11
|
+
*
|
|
12
|
+
* @param baseDir Absolute path to the allowed base directory (should end with `sep`).
|
|
13
|
+
* @param relativePath The (potentially untrusted) relative path to resolve.
|
|
14
|
+
* @returns A discriminated union indicating success (with the real path) or
|
|
15
|
+
* failure (with a reason code).
|
|
16
|
+
*/
|
|
17
|
+
export function safeResolvePath(baseDir, relativePath) {
|
|
18
|
+
const resolvedPath = resolve(baseDir, relativePath);
|
|
19
|
+
// Check 1: string-based containment (catches ../.. traversal)
|
|
20
|
+
if (!resolvedPath.startsWith(baseDir)) {
|
|
21
|
+
return { valid: false, reason: 'traversal' };
|
|
22
|
+
}
|
|
23
|
+
// Check 2: file must exist to resolve symlinks
|
|
24
|
+
if (!existsSync(resolvedPath)) {
|
|
25
|
+
return { valid: false, reason: 'not_found' };
|
|
26
|
+
}
|
|
27
|
+
// Check 3: resolve symlinks and verify the real path is still contained
|
|
28
|
+
try {
|
|
29
|
+
const realPath = realpathSync(resolvedPath);
|
|
30
|
+
const normalizedBase = baseDir.endsWith(sep)
|
|
31
|
+
? baseDir.slice(0, -1)
|
|
32
|
+
: baseDir;
|
|
33
|
+
const realBaseDir = realpathSync(normalizedBase) + sep;
|
|
34
|
+
if (!realPath.startsWith(realBaseDir)) {
|
|
35
|
+
return { valid: false, reason: 'symlink_escape' };
|
|
36
|
+
}
|
|
37
|
+
return { valid: true, realPath };
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
41
|
+
return { valid: false, reason: 'resolve_error', error: message };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=safe-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-path.js","sourceRoot":"","sources":["../../../../../src/lib/safe-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAuBzC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,YAAoB;IAEpB,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAEpD,8DAA8D;IAC9D,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAC/C,CAAC;IAED,+CAA+C;IAC/C,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAC/C,CAAC;IAED,wEAAwE;IACxE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;QAC5C,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;YAC1C,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACtB,CAAC,CAAC,OAAO,CAAC;QACZ,MAAM,WAAW,GAAG,YAAY,CAAC,cAAc,CAAC,GAAG,GAAG,CAAC;QAEvD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YACtC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;QACpD,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IACnE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ScenarioEntity } from '@signstack/base';
|
|
2
|
+
/**
|
|
3
|
+
* Load a specific scenario by key from the contract's scenarios/ folder.
|
|
4
|
+
* Returns null if the file doesn't exist.
|
|
5
|
+
*/
|
|
6
|
+
export declare function loadScenario(contractDir: string, scenarioKey: string): ScenarioEntity[] | null;
|
|
7
|
+
/**
|
|
8
|
+
* Load the default scenario (first alphabetically) from the contract's scenarios/ folder.
|
|
9
|
+
* Returns null if no scenarios/ folder or no .json files exist.
|
|
10
|
+
*/
|
|
11
|
+
export declare function loadDefaultScenario(contractDir: string): {
|
|
12
|
+
key: string;
|
|
13
|
+
entities: ScenarioEntity[];
|
|
14
|
+
} | null;
|
|
15
|
+
/**
|
|
16
|
+
* Save multiple scenarios to the contract's scenarios/ folder.
|
|
17
|
+
* Each scenario is written as <snake_case_name>.json.
|
|
18
|
+
*/
|
|
19
|
+
export declare function saveScenarios(contractDir: string, scenarios: Array<{
|
|
20
|
+
name: string;
|
|
21
|
+
entities: ScenarioEntity[];
|
|
22
|
+
}>): void;
|
|
23
|
+
/**
|
|
24
|
+
* List available scenario keys (filenames without .json) in the contract's scenarios/ folder.
|
|
25
|
+
*/
|
|
26
|
+
export declare function listScenarioKeys(contractDir: string): string[];
|
|
27
|
+
/**
|
|
28
|
+
* Check if a scenario value looks like a file path (vs a key).
|
|
29
|
+
*/
|
|
30
|
+
export declare function isScenarioFilePath(value: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Load scenario entities from a direct file path.
|
|
33
|
+
*/
|
|
34
|
+
export declare function loadScenarioFromPath(filePath: string): ScenarioEntity[];
|
|
35
|
+
export declare function toSnakeCase(str: string): string;
|