@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,800 @@
|
|
|
1
|
+
import { AssetType, parseResourceId, ResourceKind, } from '@signstack/base';
|
|
2
|
+
import { SchemaKind } from '../types/schema.types.js';
|
|
3
|
+
import { YamlWriter } from './yaml-writer.js';
|
|
4
|
+
/** Org-scoped pull source — uses authenticated org/namespace endpoints. */
|
|
5
|
+
export class OrgPullSource {
|
|
6
|
+
orgId;
|
|
7
|
+
nsKey;
|
|
8
|
+
constructor(orgId, nsKey) {
|
|
9
|
+
this.orgId = orgId;
|
|
10
|
+
this.nsKey = nsKey;
|
|
11
|
+
}
|
|
12
|
+
buildDependencyTreeUrl(kind, key, version) {
|
|
13
|
+
return `/v1/orgs/${this.orgId}/namespaces/${this.nsKey}/resource-edges/${encodeURIComponent(kind)}/${encodeURIComponent(key)}/${encodeURIComponent(version)}/depends-on?transitive=true`;
|
|
14
|
+
}
|
|
15
|
+
buildResourceUrl(kind, key, version) {
|
|
16
|
+
const endpoint = KIND_TO_ENDPOINT[kind];
|
|
17
|
+
return `/v1/orgs/${this.orgId}/namespaces/${this.nsKey}/${endpoint}/${key}?version=${version}`;
|
|
18
|
+
}
|
|
19
|
+
async fetchFileDownloadUrl(client, fileId) {
|
|
20
|
+
const file = await client.get(`/v1/orgs/${this.orgId}/files/${fileId}`);
|
|
21
|
+
return file.downloadUrl;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Public library pull source — scoped by the listing that's being pulled. All
|
|
26
|
+
* URLs are keyed by the listing (`listingKey@listingVersion`), not the
|
|
27
|
+
* underlying resource. Sub-resources are fetched through the listing so the
|
|
28
|
+
* backend can authorize access once at the listing level. No auth required.
|
|
29
|
+
*/
|
|
30
|
+
export class LibraryPullSource {
|
|
31
|
+
listingKey;
|
|
32
|
+
listingVersion;
|
|
33
|
+
constructor(listingKey, listingVersion) {
|
|
34
|
+
this.listingKey = listingKey;
|
|
35
|
+
this.listingVersion = listingVersion;
|
|
36
|
+
}
|
|
37
|
+
get _prefix() {
|
|
38
|
+
return `/v1/library/listings/by-key/${encodeURIComponent(this.listingKey)}/${encodeURIComponent(this.listingVersion)}`;
|
|
39
|
+
}
|
|
40
|
+
// The dependency tree is per-listing (the listing knows its root resource
|
|
41
|
+
// and transitive deps), so the `kind`/`key`/`version` args are ignored.
|
|
42
|
+
buildDependencyTreeUrl() {
|
|
43
|
+
return `${this._prefix}/dependencies`;
|
|
44
|
+
}
|
|
45
|
+
buildResourceUrl(kind, key, version) {
|
|
46
|
+
const endpoint = KIND_TO_ENDPOINT[kind];
|
|
47
|
+
return `${this._prefix}/${endpoint}/${encodeURIComponent(key)}?resourceVersion=${encodeURIComponent(version)}`;
|
|
48
|
+
}
|
|
49
|
+
async fetchFileDownloadUrl(client, fileId) {
|
|
50
|
+
const resp = await client.get(`${this._prefix}/files/${encodeURIComponent(fileId)}/signed-url`);
|
|
51
|
+
return resp.url;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Map backend ResourceKind to CLI SchemaKind */
|
|
55
|
+
const BACKEND_TO_SCHEMA_KIND = {
|
|
56
|
+
[ResourceKind.Blueprint]: SchemaKind.Blueprint,
|
|
57
|
+
[ResourceKind.Template]: SchemaKind.Template,
|
|
58
|
+
[ResourceKind.Schema]: SchemaKind.Schema,
|
|
59
|
+
[ResourceKind.Asset]: SchemaKind.Asset,
|
|
60
|
+
[ResourceKind.JsonataFunction]: SchemaKind.JsonataFunction,
|
|
61
|
+
};
|
|
62
|
+
/** Map CLI SchemaKind to backend ResourceKind */
|
|
63
|
+
export const SCHEMA_KIND_TO_BACKEND = {
|
|
64
|
+
[SchemaKind.Blueprint]: ResourceKind.Blueprint,
|
|
65
|
+
[SchemaKind.Template]: ResourceKind.Template,
|
|
66
|
+
[SchemaKind.Schema]: ResourceKind.Schema,
|
|
67
|
+
[SchemaKind.Asset]: ResourceKind.Asset,
|
|
68
|
+
[SchemaKind.JsonataFunction]: ResourceKind.JsonataFunction,
|
|
69
|
+
};
|
|
70
|
+
/** Map backend ResourceKind to API endpoint path segment */
|
|
71
|
+
export const KIND_TO_ENDPOINT = {
|
|
72
|
+
[ResourceKind.Blueprint]: 'blueprints',
|
|
73
|
+
[ResourceKind.Template]: 'templates',
|
|
74
|
+
[ResourceKind.Schema]: 'schemas',
|
|
75
|
+
[ResourceKind.Asset]: 'assets',
|
|
76
|
+
[ResourceKind.JsonataFunction]: 'jsonata-functions',
|
|
77
|
+
};
|
|
78
|
+
/** Default file extensions by asset type */
|
|
79
|
+
const ASSET_TYPE_EXT = {
|
|
80
|
+
[AssetType.Pdf]: '.pdf',
|
|
81
|
+
[AssetType.Image]: '.png',
|
|
82
|
+
[AssetType.Html]: '.hbs',
|
|
83
|
+
[AssetType.Css]: '.css',
|
|
84
|
+
};
|
|
85
|
+
/** Content-Type to file extension reverse map */
|
|
86
|
+
const CONTENT_TYPE_TO_EXT = {
|
|
87
|
+
'image/png': '.png',
|
|
88
|
+
'image/jpeg': '.jpg',
|
|
89
|
+
'image/gif': '.gif',
|
|
90
|
+
'image/svg+xml': '.svg',
|
|
91
|
+
'image/webp': '.webp',
|
|
92
|
+
'application/pdf': '.pdf',
|
|
93
|
+
};
|
|
94
|
+
const CONCURRENCY_LIMIT = 5;
|
|
95
|
+
const API_VERSION = 'signstack/v1beta2';
|
|
96
|
+
/**
|
|
97
|
+
* ResourcePuller — Fetches SignStack resources from the API and converts them to YAML files.
|
|
98
|
+
*
|
|
99
|
+
* This is the inverse of ResourcePusher. It:
|
|
100
|
+
* 1. Fetches the dependency tree for a resource
|
|
101
|
+
* 2. Downloads each dependent resource
|
|
102
|
+
* 3. Converts API responses to YAML format
|
|
103
|
+
* 4. Downloads binary files for assets with fileIds
|
|
104
|
+
* 5. Writes everything to a local folder structure
|
|
105
|
+
*/
|
|
106
|
+
export class ResourcePuller {
|
|
107
|
+
client;
|
|
108
|
+
source;
|
|
109
|
+
log;
|
|
110
|
+
constructor(client, source, log) {
|
|
111
|
+
this.client = client;
|
|
112
|
+
this.source = source;
|
|
113
|
+
this.log = log;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Pull a resource and all its dependencies from the API.
|
|
117
|
+
*/
|
|
118
|
+
async pull(params) {
|
|
119
|
+
const { kind, key, version, outputDir, verbose } = params;
|
|
120
|
+
// Step 1: Fetch dependency tree
|
|
121
|
+
if (verbose) {
|
|
122
|
+
this.log(`Fetching dependency tree for ${kind}:${key}@${version}...`);
|
|
123
|
+
}
|
|
124
|
+
const resourceIds = await this.fetchAllDependencyIds(kind, key, version);
|
|
125
|
+
this.log(`Found ${resourceIds.size} dependencies (including root)`);
|
|
126
|
+
// Build a lookup map from "kind:key" -> version, so converters can resolve
|
|
127
|
+
// missing schemaVersion fields that the API sometimes omits.
|
|
128
|
+
const versionByKindAndKey = new Map();
|
|
129
|
+
for (const id of resourceIds) {
|
|
130
|
+
const { kind: k, key: rk, version: rv } = parseResourceId(id);
|
|
131
|
+
versionByKindAndKey.set(`${k}:${rk}`, rv);
|
|
132
|
+
}
|
|
133
|
+
// Step 2: Create output directory structure
|
|
134
|
+
const writer = new YamlWriter(outputDir);
|
|
135
|
+
writer.ensureDirectories();
|
|
136
|
+
// Step 3: Fetch and convert each resource
|
|
137
|
+
const results = [];
|
|
138
|
+
const byKind = {};
|
|
139
|
+
const resourceIdArray = Array.from(resourceIds);
|
|
140
|
+
// Process in batches for concurrency
|
|
141
|
+
for (let i = 0; i < resourceIdArray.length; i += CONCURRENCY_LIMIT) {
|
|
142
|
+
const batch = resourceIdArray.slice(i, i + CONCURRENCY_LIMIT);
|
|
143
|
+
const batchResults = await Promise.all(batch.map((id) => this.pullSingleResource(id, writer, verbose, versionByKindAndKey)));
|
|
144
|
+
for (const result of batchResults) {
|
|
145
|
+
results.push(result);
|
|
146
|
+
if (result.success) {
|
|
147
|
+
byKind[result.kind] = (byKind[result.kind] ?? 0) + 1;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const succeeded = results.filter((r) => r.success).length;
|
|
152
|
+
const failed = results.filter((r) => !r.success).length;
|
|
153
|
+
return {
|
|
154
|
+
outputDir,
|
|
155
|
+
total: results.length,
|
|
156
|
+
succeeded,
|
|
157
|
+
failed,
|
|
158
|
+
results,
|
|
159
|
+
byKind,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Fetch the transitive dependency tree and collect all unique resource IDs.
|
|
164
|
+
* Also includes the root resource itself.
|
|
165
|
+
*/
|
|
166
|
+
async fetchAllDependencyIds(kind, key, version) {
|
|
167
|
+
const rootId = `${kind}:${key}@${version}`;
|
|
168
|
+
const ids = new Set();
|
|
169
|
+
ids.add(rootId);
|
|
170
|
+
try {
|
|
171
|
+
const url = this.source.buildDependencyTreeUrl(kind, key, version);
|
|
172
|
+
const resp = await this.client.get(url);
|
|
173
|
+
if (resp.tree) {
|
|
174
|
+
this.flattenTree(resp.tree, ids);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
this.log(`Warning: Could not fetch dependency tree for ${rootId}: ${error.message}`);
|
|
179
|
+
}
|
|
180
|
+
return ids;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Recursively flatten a dependency tree into a set of resource IDs.
|
|
184
|
+
* Handles both org format ({ resourceId }) and library format ({ kind, key, version }).
|
|
185
|
+
*/
|
|
186
|
+
flattenTree(node, ids) {
|
|
187
|
+
if ('resourceId' in node) {
|
|
188
|
+
ids.add(node.resourceId);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
ids.add(`${node.kind}:${node.key}@${node.version}`);
|
|
192
|
+
}
|
|
193
|
+
for (const child of node.children ?? []) {
|
|
194
|
+
this.flattenTree(child, ids);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Pull a single resource: fetch from API, convert to YAML, write files.
|
|
199
|
+
*/
|
|
200
|
+
async pullSingleResource(resourceId, writer, verbose, versionByKindAndKey) {
|
|
201
|
+
const { kind: backendKind, key, version } = parseResourceId(resourceId);
|
|
202
|
+
const schemaKind = BACKEND_TO_SCHEMA_KIND[backendKind];
|
|
203
|
+
if (!schemaKind) {
|
|
204
|
+
return {
|
|
205
|
+
resourceId,
|
|
206
|
+
kind: SchemaKind.Schema, // fallback
|
|
207
|
+
key,
|
|
208
|
+
version,
|
|
209
|
+
success: false,
|
|
210
|
+
error: `Unknown resource kind: ${backendKind}`,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
const baseResult = {
|
|
214
|
+
resourceId,
|
|
215
|
+
kind: schemaKind,
|
|
216
|
+
key,
|
|
217
|
+
version,
|
|
218
|
+
success: false,
|
|
219
|
+
};
|
|
220
|
+
try {
|
|
221
|
+
const path = this.source.buildResourceUrl(backendKind, key, version);
|
|
222
|
+
const resp = await this.client.get(path);
|
|
223
|
+
const { yamlDoc, additionalFiles } = await this.convertResource(schemaKind, key, version, resp, writer, versionByKindAndKey);
|
|
224
|
+
const yamlPath = writer.writeYaml(schemaKind, key, yamlDoc);
|
|
225
|
+
if (verbose) {
|
|
226
|
+
this.log(` ${schemaKind}:${key}@${version} -> ${yamlPath}`);
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
...baseResult,
|
|
230
|
+
success: true,
|
|
231
|
+
yamlPath,
|
|
232
|
+
additionalFiles,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
const errMsg = error.message;
|
|
237
|
+
if (verbose) {
|
|
238
|
+
this.log(` Failed: ${schemaKind}:${key}@${version} - ${errMsg}`);
|
|
239
|
+
}
|
|
240
|
+
return { ...baseResult, error: errMsg };
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Convert an API response to a YAML document object.
|
|
245
|
+
* Also writes any additional files (JSON definitions, HTML/CSS content, binary files).
|
|
246
|
+
*/
|
|
247
|
+
async convertResource(kind, key, version, resp, writer, versionByKindAndKey) {
|
|
248
|
+
switch (kind) {
|
|
249
|
+
case SchemaKind.Schema:
|
|
250
|
+
return this.convertSchema(key, resp, writer);
|
|
251
|
+
case SchemaKind.Asset:
|
|
252
|
+
return this.convertAsset(key, resp, writer);
|
|
253
|
+
case SchemaKind.Template:
|
|
254
|
+
return this.convertTemplateWithAssetStub(key, version, resp, writer, versionByKindAndKey);
|
|
255
|
+
case SchemaKind.Blueprint:
|
|
256
|
+
return {
|
|
257
|
+
yamlDoc: this.convertBlueprint(resp, versionByKindAndKey),
|
|
258
|
+
additionalFiles: [],
|
|
259
|
+
};
|
|
260
|
+
case SchemaKind.JsonataFunction:
|
|
261
|
+
return {
|
|
262
|
+
yamlDoc: this.convertJsonataFunction(resp, versionByKindAndKey),
|
|
263
|
+
additionalFiles: [],
|
|
264
|
+
};
|
|
265
|
+
default:
|
|
266
|
+
throw new Error(`Unknown resource kind: ${kind}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// ─── Schema Conversion ────────────────────────────────────────
|
|
270
|
+
convertSchema(key, resp, writer) {
|
|
271
|
+
const additionalFiles = [];
|
|
272
|
+
// Write JSON schema definition to file
|
|
273
|
+
const filePath = writer.writeJsonDefinition(key, resp.spec.schemaDefinition);
|
|
274
|
+
additionalFiles.push(filePath);
|
|
275
|
+
const yamlDoc = {
|
|
276
|
+
apiVersion: API_VERSION,
|
|
277
|
+
kind: 'Schema',
|
|
278
|
+
metadata: buildMetadata(resp.metadata),
|
|
279
|
+
spec: {
|
|
280
|
+
jsonSchemaDraft: resp.spec.jsonSchemaDraft,
|
|
281
|
+
file: filePath,
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
return { yamlDoc, additionalFiles };
|
|
285
|
+
}
|
|
286
|
+
// ─── Asset Conversion ─────────────────────────────────────────
|
|
287
|
+
async convertAsset(key, resp, writer) {
|
|
288
|
+
const additionalFiles = [];
|
|
289
|
+
const spec = {
|
|
290
|
+
type: resp.spec.type,
|
|
291
|
+
};
|
|
292
|
+
// Handle file content based on asset type
|
|
293
|
+
if (resp.spec.type === AssetType.Html || resp.spec.type === AssetType.Css) {
|
|
294
|
+
// Text assets: write content to file
|
|
295
|
+
if (resp.spec.content) {
|
|
296
|
+
const subdir = resp.spec.type === AssetType.Html ? 'html' : 'css';
|
|
297
|
+
const ext = ASSET_TYPE_EXT[resp.spec.type] ?? '.txt';
|
|
298
|
+
const filename = `${key}${ext}`;
|
|
299
|
+
const filePath = writer.writeTextContent(subdir, filename, resp.spec.content);
|
|
300
|
+
spec.file = filePath;
|
|
301
|
+
additionalFiles.push(filePath);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
else if (resp.spec.type === AssetType.Pdf ||
|
|
305
|
+
resp.spec.type === AssetType.Image) {
|
|
306
|
+
// Binary assets: download via signed URL
|
|
307
|
+
if (resp.spec.fileId) {
|
|
308
|
+
try {
|
|
309
|
+
const signedUrl = await this.getSignedUrl(resp.spec.fileId);
|
|
310
|
+
const ext = await this.getFileExtension(resp.spec.type, signedUrl);
|
|
311
|
+
const filePath = await writer.downloadBinaryFile(key, ext, signedUrl);
|
|
312
|
+
spec.file = filePath;
|
|
313
|
+
additionalFiles.push(filePath);
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
// Log but don't fail the entire resource
|
|
317
|
+
this.log(` Warning: Could not download file for asset ${key} (fileId: ${resp.spec.fileId}): ${error.message}`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// Handle HTML config references
|
|
322
|
+
if (resp.spec.htmlConfig) {
|
|
323
|
+
this.convertHtmlConfig(resp.spec.htmlConfig, spec);
|
|
324
|
+
}
|
|
325
|
+
const yamlDoc = {
|
|
326
|
+
apiVersion: API_VERSION,
|
|
327
|
+
kind: 'Asset',
|
|
328
|
+
metadata: buildMetadata(resp.metadata),
|
|
329
|
+
spec,
|
|
330
|
+
};
|
|
331
|
+
return { yamlDoc, additionalFiles };
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Convert API htmlConfig refs back to YAML format.
|
|
335
|
+
*/
|
|
336
|
+
convertHtmlConfig(config, spec) {
|
|
337
|
+
// Partials: [{key, version, alias}] -> { alias: "key@version" }
|
|
338
|
+
if (config.partials && config.partials.length > 0) {
|
|
339
|
+
const partials = {};
|
|
340
|
+
for (const p of config.partials) {
|
|
341
|
+
partials[p.alias] = `${p.key}@${p.version}`;
|
|
342
|
+
}
|
|
343
|
+
spec.partials = partials;
|
|
344
|
+
}
|
|
345
|
+
// Styles: [{key, version}] -> ["key@version"]
|
|
346
|
+
if (config.styles && config.styles.length > 0) {
|
|
347
|
+
spec.styles = config.styles.map((s) => `${s.key}@${s.version}`);
|
|
348
|
+
}
|
|
349
|
+
// Images: [{key, version, alias}] -> { alias: "key@version" }
|
|
350
|
+
if (config.images && config.images.length > 0) {
|
|
351
|
+
const images = {};
|
|
352
|
+
for (const img of config.images) {
|
|
353
|
+
images[img.alias] = `${img.key}@${img.version}`;
|
|
354
|
+
}
|
|
355
|
+
spec.images = images;
|
|
356
|
+
}
|
|
357
|
+
// ViewModel schema
|
|
358
|
+
if (config.data?.schemaKey) {
|
|
359
|
+
spec.data = {
|
|
360
|
+
schema: toRef(config.data.schemaKey, config.data.schemaVersion),
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
// PDF settings
|
|
364
|
+
if (config.pdfSettings) {
|
|
365
|
+
spec.pdfSettings = config.pdfSettings;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// ─── Template Conversion ──────────────────────────────────────
|
|
369
|
+
/**
|
|
370
|
+
* Convert a template and, when contentKey was absent from the API response
|
|
371
|
+
* (supplement templates like exhibit_a_nwmls), also write a stub asset YAML
|
|
372
|
+
* so that --resolve local preview can find the content dependency.
|
|
373
|
+
*/
|
|
374
|
+
convertTemplateWithAssetStub(key, version, resp, writer, versionByKindAndKey) {
|
|
375
|
+
const additionalFiles = [];
|
|
376
|
+
const yamlDoc = this.convertTemplate(resp, versionByKindAndKey);
|
|
377
|
+
// When contentKey was absent from the API, write a stub asset so that
|
|
378
|
+
// --resolve local preview can resolve the content reference.
|
|
379
|
+
if (!resp.spec.contentKey && resp.spec.type === 'pdf') {
|
|
380
|
+
const assetVersion = resp.metadata.version;
|
|
381
|
+
const stubAsset = {
|
|
382
|
+
apiVersion: API_VERSION,
|
|
383
|
+
kind: 'Asset',
|
|
384
|
+
metadata: {
|
|
385
|
+
key,
|
|
386
|
+
version: assetVersion,
|
|
387
|
+
name: key,
|
|
388
|
+
},
|
|
389
|
+
spec: {
|
|
390
|
+
type: 'pdf',
|
|
391
|
+
file: `./${key}.pdf`,
|
|
392
|
+
},
|
|
393
|
+
};
|
|
394
|
+
const assetPath = writer.writeYaml(SchemaKind.Asset, key, stubAsset);
|
|
395
|
+
writer.writePlaceholderPdf(key);
|
|
396
|
+
this.log(` Warning: template ${key}@${version} had no contentKey — wrote stub asset at ${assetPath}`);
|
|
397
|
+
additionalFiles.push(assetPath);
|
|
398
|
+
}
|
|
399
|
+
return { yamlDoc, additionalFiles };
|
|
400
|
+
}
|
|
401
|
+
convertTemplate(resp, versionByKindAndKey) {
|
|
402
|
+
const spec = {
|
|
403
|
+
type: resp.spec.type,
|
|
404
|
+
};
|
|
405
|
+
// Content reference — required for pdf templates.
|
|
406
|
+
// Fall back to the template's own key/version when the API omits contentKey
|
|
407
|
+
// or contentVersion (observed for supplement templates like exhibit_a_nwmls).
|
|
408
|
+
const contentKey = resp.spec.contentKey ||
|
|
409
|
+
(resp.spec.type === 'pdf' ? resp.metadata.key : undefined);
|
|
410
|
+
const contentVersion = resp.spec.contentVersion || resp.metadata.version;
|
|
411
|
+
if (contentKey) {
|
|
412
|
+
spec.content = toRef(contentKey, contentVersion);
|
|
413
|
+
}
|
|
414
|
+
// Inputs
|
|
415
|
+
if (resp.spec.inputs && resp.spec.inputs.length > 0) {
|
|
416
|
+
spec.inputs = resp.spec.inputs.map((i) => convertInputToYaml(i, versionByKindAndKey));
|
|
417
|
+
}
|
|
418
|
+
// Roles
|
|
419
|
+
if (resp.spec.roles && resp.spec.roles.length > 0) {
|
|
420
|
+
spec.roles = resp.spec.roles.map(convertRoleToYaml);
|
|
421
|
+
}
|
|
422
|
+
// Fields
|
|
423
|
+
if (resp.spec.fields && resp.spec.fields.length > 0) {
|
|
424
|
+
spec.fields = resp.spec.fields.map(convertFieldToYaml);
|
|
425
|
+
}
|
|
426
|
+
// Data transform
|
|
427
|
+
if (resp.spec.data?.transform) {
|
|
428
|
+
spec.data = { transform: resp.spec.data.transform };
|
|
429
|
+
}
|
|
430
|
+
if (resp.spec.functions && resp.spec.functions.length > 0) {
|
|
431
|
+
spec.functions = convertFunctionsToYaml(resp.spec.functions);
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
apiVersion: API_VERSION,
|
|
435
|
+
kind: 'Template',
|
|
436
|
+
metadata: buildMetadata(resp.metadata),
|
|
437
|
+
spec,
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
// ─── Blueprint Conversion ─────────────────────────────────────
|
|
441
|
+
convertBlueprint(resp, versionByKindAndKey) {
|
|
442
|
+
const spec = {};
|
|
443
|
+
// Inputs
|
|
444
|
+
if (resp.spec.inputs && resp.spec.inputs.length > 0) {
|
|
445
|
+
spec.inputs = resp.spec.inputs.map((i) => convertInputToYaml(i, versionByKindAndKey));
|
|
446
|
+
}
|
|
447
|
+
// Participants
|
|
448
|
+
if (resp.spec.participants && resp.spec.participants.length > 0) {
|
|
449
|
+
spec.participants = resp.spec.participants.map(convertParticipantToYaml);
|
|
450
|
+
}
|
|
451
|
+
// Envelopes
|
|
452
|
+
if (resp.spec.envelopes && resp.spec.envelopes.length > 0) {
|
|
453
|
+
spec.envelopes = resp.spec.envelopes.map(convertEnvelopeToYaml);
|
|
454
|
+
}
|
|
455
|
+
if (resp.spec.functions && resp.spec.functions.length > 0) {
|
|
456
|
+
spec.functions = convertFunctionsToYaml(resp.spec.functions);
|
|
457
|
+
}
|
|
458
|
+
// Orchestration
|
|
459
|
+
if (resp.spec.orchestration) {
|
|
460
|
+
spec.orchestration = convertOrchestrationToYaml(resp.spec.orchestration);
|
|
461
|
+
}
|
|
462
|
+
return {
|
|
463
|
+
apiVersion: API_VERSION,
|
|
464
|
+
kind: 'Blueprint',
|
|
465
|
+
metadata: buildMetadata(resp.metadata),
|
|
466
|
+
spec,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
// ─── JsonataFunction Conversion ───────────────────────────────
|
|
470
|
+
convertJsonataFunction(resp, versionByKindAndKey) {
|
|
471
|
+
const spec = {};
|
|
472
|
+
if (resp.spec.params && resp.spec.params.length > 0) {
|
|
473
|
+
spec.params = resp.spec.params.map((p) => {
|
|
474
|
+
const param = {
|
|
475
|
+
name: p.name,
|
|
476
|
+
type: p.type,
|
|
477
|
+
};
|
|
478
|
+
if (p.schemaKey) {
|
|
479
|
+
param.schema = toRef(p.schemaKey, resolveVersion(ResourceKind.Schema, p.schemaKey, p.schemaVersion, versionByKindAndKey));
|
|
480
|
+
}
|
|
481
|
+
return param;
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
if (resp.spec.returnType) {
|
|
485
|
+
const rt = {
|
|
486
|
+
type: resp.spec.returnType.type,
|
|
487
|
+
};
|
|
488
|
+
if (resp.spec.returnType.schemaKey) {
|
|
489
|
+
rt.schema = toRef(resp.spec.returnType.schemaKey, resolveVersion(ResourceKind.Schema, resp.spec.returnType.schemaKey, resp.spec.returnType.schemaVersion, versionByKindAndKey));
|
|
490
|
+
}
|
|
491
|
+
spec.returnType = rt;
|
|
492
|
+
}
|
|
493
|
+
if (resp.spec.body) {
|
|
494
|
+
spec.body = resp.spec.body;
|
|
495
|
+
}
|
|
496
|
+
return {
|
|
497
|
+
apiVersion: API_VERSION,
|
|
498
|
+
kind: 'JsonataFunction',
|
|
499
|
+
metadata: buildMetadata(resp.metadata),
|
|
500
|
+
spec,
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
// ─── File Download Helpers ────────────────────────────────────
|
|
504
|
+
/**
|
|
505
|
+
* Get a signed download URL for a file.
|
|
506
|
+
*/
|
|
507
|
+
async getSignedUrl(fileId) {
|
|
508
|
+
return this.source.fetchFileDownloadUrl(this.client, fileId);
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Determine file extension by making a HEAD request to the signed URL.
|
|
512
|
+
* Falls back to the default extension for the asset type if the Content-Type
|
|
513
|
+
* is unrecognized or the request fails.
|
|
514
|
+
*/
|
|
515
|
+
async getFileExtension(assetType, signedUrl) {
|
|
516
|
+
try {
|
|
517
|
+
const response = await fetch(signedUrl, { method: 'HEAD' });
|
|
518
|
+
if (response.ok) {
|
|
519
|
+
const contentType = response.headers.get('content-type');
|
|
520
|
+
// Strip parameters like "; charset=utf-8" before lookup
|
|
521
|
+
const mimeType = contentType?.split(';')[0].trim();
|
|
522
|
+
if (mimeType && CONTENT_TYPE_TO_EXT[mimeType]) {
|
|
523
|
+
return CONTENT_TYPE_TO_EXT[mimeType];
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
catch {
|
|
528
|
+
// Fall through to default
|
|
529
|
+
}
|
|
530
|
+
return ASSET_TYPE_EXT[assetType] ?? '.bin';
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
// ─── Shared Conversion Helpers ────────────────────────────────
|
|
534
|
+
/**
|
|
535
|
+
* Resolve a version for a resource, falling back to the dependency map when
|
|
536
|
+
* the API omits schemaVersion (it's an optional field on Input).
|
|
537
|
+
*/
|
|
538
|
+
function resolveVersion(kind, key, version, versionByKindAndKey) {
|
|
539
|
+
return version || versionByKindAndKey.get(`${kind}:${key}`);
|
|
540
|
+
}
|
|
541
|
+
/** Combine key and version into "key@version" reference */
|
|
542
|
+
function toRef(key, version) {
|
|
543
|
+
if (!key)
|
|
544
|
+
return undefined;
|
|
545
|
+
if (!version)
|
|
546
|
+
return key;
|
|
547
|
+
return `${key}@${version}`;
|
|
548
|
+
}
|
|
549
|
+
/** Build the YAML metadata block, omitting undefined fields */
|
|
550
|
+
function buildMetadata(metadata) {
|
|
551
|
+
const result = {
|
|
552
|
+
key: metadata.key,
|
|
553
|
+
version: metadata.version,
|
|
554
|
+
};
|
|
555
|
+
if (metadata.name)
|
|
556
|
+
result.name = metadata.name;
|
|
557
|
+
if (metadata.description)
|
|
558
|
+
result.description = metadata.description;
|
|
559
|
+
if (metadata.labels && Object.keys(metadata.labels).length > 0) {
|
|
560
|
+
// Label keys must match ^[a-z][a-z0-9]*(_[a-z0-9]+)*$ — sanitize by
|
|
561
|
+
// converting camelCase and any invalid chars to snake_case.
|
|
562
|
+
const sanitized = {};
|
|
563
|
+
for (const [k, v] of Object.entries(metadata.labels)) {
|
|
564
|
+
const safe = k
|
|
565
|
+
.replace(/([A-Z])/g, '_$1')
|
|
566
|
+
.toLowerCase()
|
|
567
|
+
.replace(/[^a-z0-9_]/g, '_')
|
|
568
|
+
.replace(/^[^a-z]+/, '')
|
|
569
|
+
.replace(/_+/g, '_')
|
|
570
|
+
.replace(/_$/, '');
|
|
571
|
+
if (safe)
|
|
572
|
+
sanitized[safe] = v;
|
|
573
|
+
}
|
|
574
|
+
if (Object.keys(sanitized).length > 0)
|
|
575
|
+
result.labels = sanitized;
|
|
576
|
+
}
|
|
577
|
+
return result;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Converts a spec.functions array to YAML form.
|
|
581
|
+
* Emits object-map when any entry has a distinct alias, otherwise a plain array.
|
|
582
|
+
*/
|
|
583
|
+
function convertFunctionsToYaml(functions) {
|
|
584
|
+
const hasDistinctAlias = functions.some((f) => f.alias);
|
|
585
|
+
if (hasDistinctAlias) {
|
|
586
|
+
return functions.reduce((acc, f) => {
|
|
587
|
+
acc[f.alias ?? f.functionKey] = `${f.functionKey}@${f.functionVersion}`;
|
|
588
|
+
return acc;
|
|
589
|
+
}, {});
|
|
590
|
+
}
|
|
591
|
+
return functions.map((f) => `${f.functionKey}@${f.functionVersion}`);
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Convert API LiteralOrExpression to YAML expression format.
|
|
595
|
+
* Both sides use { expression: "..." }, so this is effectively a passthrough
|
|
596
|
+
* that strips undefined/null.
|
|
597
|
+
*/
|
|
598
|
+
function passthroughExpression(value) {
|
|
599
|
+
if (value === undefined || value === null)
|
|
600
|
+
return undefined;
|
|
601
|
+
return value;
|
|
602
|
+
}
|
|
603
|
+
/** Convert API Input to YAML input format */
|
|
604
|
+
function convertInputToYaml(input, versionByKindAndKey) {
|
|
605
|
+
const result = {
|
|
606
|
+
key: input.key,
|
|
607
|
+
};
|
|
608
|
+
if (input.name)
|
|
609
|
+
result.name = input.name;
|
|
610
|
+
if (input.description)
|
|
611
|
+
result.description = input.description;
|
|
612
|
+
if (input.schemaKey) {
|
|
613
|
+
result.schema = toRef(input.schemaKey, resolveVersion(ResourceKind.Schema, input.schemaKey, input.schemaVersion, versionByKindAndKey));
|
|
614
|
+
}
|
|
615
|
+
if (typeof input.required === 'boolean') {
|
|
616
|
+
result.required = input.required;
|
|
617
|
+
}
|
|
618
|
+
else if (input.required &&
|
|
619
|
+
typeof input.required === 'object' &&
|
|
620
|
+
'expression' in input.required) {
|
|
621
|
+
result.required = input.required.expression;
|
|
622
|
+
}
|
|
623
|
+
return result;
|
|
624
|
+
}
|
|
625
|
+
/** Convert API TemplateRole to YAML role format */
|
|
626
|
+
function convertRoleToYaml(role) {
|
|
627
|
+
const result = {
|
|
628
|
+
key: role.key,
|
|
629
|
+
};
|
|
630
|
+
if (role.name)
|
|
631
|
+
result.name = role.name;
|
|
632
|
+
if (role.roleCategory)
|
|
633
|
+
result.roleCategory = role.roleCategory;
|
|
634
|
+
if (role.output) {
|
|
635
|
+
result.output = {
|
|
636
|
+
schema: toRef(role.output.schemaKey, role.output.schemaVersion),
|
|
637
|
+
transform: role.output.transform,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
return result;
|
|
641
|
+
}
|
|
642
|
+
/** Convert API TemplateFieldInfo to YAML field format */
|
|
643
|
+
function convertFieldToYaml(field) {
|
|
644
|
+
const result = {
|
|
645
|
+
key: field.key,
|
|
646
|
+
type: field.type,
|
|
647
|
+
};
|
|
648
|
+
// Value (LiteralOrExpression)
|
|
649
|
+
const yamlValue = passthroughExpression(field.value);
|
|
650
|
+
if (yamlValue !== undefined)
|
|
651
|
+
result.value = yamlValue;
|
|
652
|
+
// Role
|
|
653
|
+
if (field.role)
|
|
654
|
+
result.role = field.role;
|
|
655
|
+
// includeIf
|
|
656
|
+
if (field.includeIf)
|
|
657
|
+
result.includeIf = field.includeIf;
|
|
658
|
+
// Widget (flatten from widgets[0])
|
|
659
|
+
if (field.widgets && field.widgets.length > 0) {
|
|
660
|
+
const w = field.widgets[0];
|
|
661
|
+
const widget = {};
|
|
662
|
+
if (w.position) {
|
|
663
|
+
widget.page = w.position.pageNumber;
|
|
664
|
+
widget.x = w.position.x;
|
|
665
|
+
widget.y = w.position.y;
|
|
666
|
+
}
|
|
667
|
+
if (w.dimensions) {
|
|
668
|
+
widget.width = w.dimensions.width;
|
|
669
|
+
widget.height = w.dimensions.height;
|
|
670
|
+
}
|
|
671
|
+
if (w.style) {
|
|
672
|
+
const style = {};
|
|
673
|
+
if (w.style.fontSizePx !== undefined)
|
|
674
|
+
style.fontSize = w.style.fontSizePx;
|
|
675
|
+
if (w.style.fontColor)
|
|
676
|
+
style.fontColor = w.style.fontColor;
|
|
677
|
+
if (w.style.fontFamily)
|
|
678
|
+
style.fontFamily = w.style.fontFamily;
|
|
679
|
+
if (w.style.strokeWidth !== undefined)
|
|
680
|
+
style.strokeWidth = w.style.strokeWidth;
|
|
681
|
+
if (w.style.strokeColor)
|
|
682
|
+
style.strokeColor = w.style.strokeColor;
|
|
683
|
+
if (Object.keys(style).length > 0)
|
|
684
|
+
widget.style = style;
|
|
685
|
+
}
|
|
686
|
+
if (Object.keys(widget).length > 0)
|
|
687
|
+
result.widget = widget;
|
|
688
|
+
}
|
|
689
|
+
return result;
|
|
690
|
+
}
|
|
691
|
+
/** Convert API BlueprintParticipant to YAML format */
|
|
692
|
+
function convertParticipantToYaml(participant) {
|
|
693
|
+
// Schema requires `name` and `email`; fall back to key-derived placeholders
|
|
694
|
+
// if the API didn't store LiteralOrExpression values for them.
|
|
695
|
+
const name = passthroughExpression(participant.participantName) ??
|
|
696
|
+
participant.name ??
|
|
697
|
+
participant.key;
|
|
698
|
+
// email must be a valid address or an { expression } object — never a freeform
|
|
699
|
+
// string. Use an expression placeholder when no expression was stored on the API.
|
|
700
|
+
const email = passthroughExpression(participant.participantEmail) ?? {
|
|
701
|
+
expression: `$.${participant.key}.email`,
|
|
702
|
+
};
|
|
703
|
+
const result = {
|
|
704
|
+
key: participant.key,
|
|
705
|
+
name,
|
|
706
|
+
email,
|
|
707
|
+
};
|
|
708
|
+
if (participant.roleCategory)
|
|
709
|
+
result.roleCategory = participant.roleCategory;
|
|
710
|
+
return result;
|
|
711
|
+
}
|
|
712
|
+
/** Convert API BlueprintEnvelope to YAML format */
|
|
713
|
+
function convertEnvelopeToYaml(envelope) {
|
|
714
|
+
const result = {
|
|
715
|
+
key: envelope.key,
|
|
716
|
+
};
|
|
717
|
+
if (envelope.subject && envelope.subject !== envelope.key) {
|
|
718
|
+
result.name = envelope.subject;
|
|
719
|
+
}
|
|
720
|
+
if (envelope.documents && envelope.documents.length > 0) {
|
|
721
|
+
result.documents = envelope.documents.map((doc) => {
|
|
722
|
+
const d = {
|
|
723
|
+
key: doc.key,
|
|
724
|
+
};
|
|
725
|
+
if (doc.templateKey) {
|
|
726
|
+
d.template = toRef(doc.templateKey, doc.templateVersion);
|
|
727
|
+
}
|
|
728
|
+
if (doc.inputMap && doc.inputMap.length > 0) {
|
|
729
|
+
const inputMap = {};
|
|
730
|
+
for (const m of doc.inputMap) {
|
|
731
|
+
inputMap[m.templateInputKey] = m.blueprintInputKey
|
|
732
|
+
? `$.${m.blueprintInputKey}`
|
|
733
|
+
: m.blueprintInputKey;
|
|
734
|
+
}
|
|
735
|
+
d.inputMap = inputMap;
|
|
736
|
+
}
|
|
737
|
+
if (doc.includeIf)
|
|
738
|
+
d.includeIf = doc.includeIf;
|
|
739
|
+
if (doc.iterator)
|
|
740
|
+
d.iterator = doc.iterator;
|
|
741
|
+
const fileIdYaml = passthroughExpression(doc.fileId);
|
|
742
|
+
if (fileIdYaml !== undefined)
|
|
743
|
+
d.fileId = fileIdYaml;
|
|
744
|
+
return d;
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
return result;
|
|
748
|
+
}
|
|
749
|
+
/** Recursively convert API BlueprintStep to YAML orchestration format */
|
|
750
|
+
function convertOrchestrationToYaml(step) {
|
|
751
|
+
const result = {
|
|
752
|
+
key: step.key,
|
|
753
|
+
type: step.type,
|
|
754
|
+
};
|
|
755
|
+
if (step.name)
|
|
756
|
+
result.name = step.name;
|
|
757
|
+
if (step.includeIf)
|
|
758
|
+
result.includeIf = step.includeIf;
|
|
759
|
+
if (step.onComplete)
|
|
760
|
+
result.onComplete = step.onComplete;
|
|
761
|
+
if (step.type === 'group') {
|
|
762
|
+
const group = step;
|
|
763
|
+
if (group.execution)
|
|
764
|
+
result.execution = group.execution;
|
|
765
|
+
if (group.completion)
|
|
766
|
+
result.completion = group.completion;
|
|
767
|
+
if (group.quorum)
|
|
768
|
+
result.quorum = group.quorum;
|
|
769
|
+
if (group.children && group.children.length > 0) {
|
|
770
|
+
// Filter out participant steps whose action has no assignments — they
|
|
771
|
+
// are unrepresentable in the YAML schema (sign action requires minItems:1).
|
|
772
|
+
result.children = group.children
|
|
773
|
+
.filter((child) => {
|
|
774
|
+
if (child.type !== 'participant')
|
|
775
|
+
return true;
|
|
776
|
+
const p = child;
|
|
777
|
+
return !p.action || p.action.assignments?.length > 0;
|
|
778
|
+
})
|
|
779
|
+
.map(convertOrchestrationToYaml);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
else {
|
|
783
|
+
const participant = step;
|
|
784
|
+
if (participant.participantKey) {
|
|
785
|
+
result.participant = participant.participantKey;
|
|
786
|
+
}
|
|
787
|
+
if (participant.action && participant.action.assignments?.length > 0) {
|
|
788
|
+
result.action = {
|
|
789
|
+
type: participant.action.type,
|
|
790
|
+
envelope: participant.action.envelopeKey,
|
|
791
|
+
assignments: participant.action.assignments.map((a) => ({
|
|
792
|
+
document: a.documentKey,
|
|
793
|
+
role: a.roleKey,
|
|
794
|
+
})),
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
return result;
|
|
799
|
+
}
|
|
800
|
+
//# sourceMappingURL=resource-puller.js.map
|